From e44a7e37b6c7b5961adaffc62b9042b8d442938e Mon Sep 17 00:00:00 2001 From: mensonge Date: Thu, 13 Nov 2008 09:49:11 +0000 Subject: New feature: basic Ajax suggestion for tags and implementation of Dojo toolkit git-svn-id: https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/trunk@151 b3834d28-1941-0410-a4f8-b48e95affb8f --- includes/js/dojox/LICENSE | 195 + includes/js/dojox/_sql/LICENSE | 9 + includes/js/dojox/_sql/_crypto.js | 443 ++ includes/js/dojox/_sql/common.js | 538 ++ .../js/dojox/_sql/demos/customers/customers.html | 292 + includes/js/dojox/analytics.js | 16 + includes/js/dojox/analytics/README | 134 + includes/js/dojox/analytics/_base.js | 127 + includes/js/dojox/analytics/logger/JSON.php | 724 ++ .../js/dojox/analytics/logger/dojoxAnalytics.php | 31 + .../js/dojox/analytics/plugins/consoleMessages.js | 24 + includes/js/dojox/analytics/plugins/dojo.js | 22 + includes/js/dojox/analytics/plugins/idle.js | 34 + includes/js/dojox/analytics/plugins/mouseClick.js | 49 + includes/js/dojox/analytics/plugins/mouseOver.js | 90 + includes/js/dojox/analytics/plugins/window.js | 34 + .../dojox/analytics/profiles/analytics.profile.js | 21 + .../analytics/profiles/analyticsInBase.profile.js | 22 + .../js/dojox/analytics/tests/test_analytics.html | 93 + includes/js/dojox/av.js | 7 + includes/js/dojox/av/README | 40 + includes/js/dojox/av/_base.js | 8 + includes/js/dojox/av/_base/_ieFlash.js | 17 + includes/js/dojox/av/_base/flash.js | 186 + includes/js/dojox/av/_base/quicktime.js | 161 + includes/js/dojox/av/resources/version.mov | Bin 0 -> 1667 bytes includes/js/dojox/av/tests/flash.html | 39 + includes/js/dojox/av/tests/quicktime.html | 24 + includes/js/dojox/av/tests/resources/hfp.swf | Bin 0 -> 13671 bytes includes/js/dojox/charting/Chart2D.js | 341 + includes/js/dojox/charting/Chart3D.js | 86 + includes/js/dojox/charting/Element.js | 49 + includes/js/dojox/charting/README | 31 + includes/js/dojox/charting/Series.js | 20 + includes/js/dojox/charting/Theme.js | 256 + includes/js/dojox/charting/_color.js | 62 + includes/js/dojox/charting/axis2d/Base.js | 31 + includes/js/dojox/charting/axis2d/Default.js | 323 + includes/js/dojox/charting/axis2d/common.js | 75 + includes/js/dojox/charting/plot2d/Areas.js | 14 + includes/js/dojox/charting/plot2d/Bars.js | 89 + includes/js/dojox/charting/plot2d/Base.js | 60 + includes/js/dojox/charting/plot2d/ClusteredBars.js | 63 + .../js/dojox/charting/plot2d/ClusteredColumns.js | 63 + includes/js/dojox/charting/plot2d/Columns.js | 88 + includes/js/dojox/charting/plot2d/Default.js | 173 + includes/js/dojox/charting/plot2d/Grid.js | 116 + includes/js/dojox/charting/plot2d/Lines.js | 13 + includes/js/dojox/charting/plot2d/Markers.js | 13 + includes/js/dojox/charting/plot2d/MarkersOnly.js | 14 + includes/js/dojox/charting/plot2d/Pie.js | 199 + includes/js/dojox/charting/plot2d/Scatter.js | 14 + includes/js/dojox/charting/plot2d/Stacked.js | 160 + includes/js/dojox/charting/plot2d/StackedAreas.js | 14 + includes/js/dojox/charting/plot2d/StackedBars.js | 85 + .../js/dojox/charting/plot2d/StackedColumns.js | 83 + includes/js/dojox/charting/plot2d/StackedLines.js | 13 + includes/js/dojox/charting/plot2d/common.js | 113 + includes/js/dojox/charting/plot3d/Bars.js | 66 + includes/js/dojox/charting/plot3d/Base.js | 23 + includes/js/dojox/charting/plot3d/Cylinders.js | 69 + includes/js/dojox/charting/scaler.js | 161 + includes/js/dojox/charting/tests/Theme.js | 71 + includes/js/dojox/charting/tests/_color.js | 82 + includes/js/dojox/charting/tests/charting.js | 12 + .../js/dojox/charting/tests/data/goog_prices.csv | 796 +++ .../js/dojox/charting/tests/data/msft_prices.csv | 796 +++ .../js/dojox/charting/tests/data/yahoo_prices.csv | 796 +++ includes/js/dojox/charting/tests/runTests.html | 9 + includes/js/dojox/charting/tests/test_bars.html | 65 + includes/js/dojox/charting/tests/test_chart2d.html | 353 + .../charting/tests/test_chart2d_updating.html | 80 + .../js/dojox/charting/tests/test_cylinders.html | 65 + .../js/dojox/charting/tests/test_labels2d.html | 90 + includes/js/dojox/charting/tests/test_pie2d.html | 128 + includes/js/dojox/charting/tests/test_scaler.html | 97 + .../js/dojox/charting/tests/test_sparklines.html | 180 + .../js/dojox/charting/tests/test_widget2d.html | 98 + includes/js/dojox/charting/themes/ET/greys.js | 63 + includes/js/dojox/charting/themes/GreySkies.js | 11 + includes/js/dojox/charting/themes/PlotKit/README | 11 + includes/js/dojox/charting/themes/PlotKit/blue.js | 43 + includes/js/dojox/charting/themes/PlotKit/cyan.js | 43 + includes/js/dojox/charting/themes/PlotKit/green.js | 43 + .../js/dojox/charting/themes/PlotKit/orange.js | 43 + .../js/dojox/charting/themes/PlotKit/purple.js | 43 + includes/js/dojox/charting/themes/PlotKit/red.js | 43 + includes/js/dojox/charting/widget/Chart2D.js | 215 + includes/js/dojox/collections.js | 6 + includes/js/dojox/collections/ArrayList.js | 133 + includes/js/dojox/collections/BinaryTree.js | 211 + includes/js/dojox/collections/Dictionary.js | 116 + includes/js/dojox/collections/Queue.js | 74 + includes/js/dojox/collections/README | 39 + includes/js/dojox/collections/Set.js | 89 + includes/js/dojox/collections/SortedList.js | 198 + includes/js/dojox/collections/Stack.js | 72 + includes/js/dojox/collections/_base.js | 100 + includes/js/dojox/collections/tests/ArrayList.js | 83 + includes/js/dojox/collections/tests/BinaryTree.js | 83 + includes/js/dojox/collections/tests/Dictionary.js | 82 + includes/js/dojox/collections/tests/Queue.js | 49 + includes/js/dojox/collections/tests/Set.js | 35 + includes/js/dojox/collections/tests/SortedList.js | 168 + includes/js/dojox/collections/tests/Stack.js | 49 + includes/js/dojox/collections/tests/_base.js | 84 + includes/js/dojox/collections/tests/collections.js | 19 + includes/js/dojox/collections/tests/runTests.html | 9 + includes/js/dojox/color.js | 6 + includes/js/dojox/color/Colorspace.js | 556 ++ includes/js/dojox/color/Generator.js | 261 + includes/js/dojox/color/README | 41 + includes/js/dojox/color/_base.js | 197 + includes/js/dojox/color/tests/Generator.js | 128 + includes/js/dojox/color/tests/_base.js | 82 + includes/js/dojox/color/tests/color.js | 14 + includes/js/dojox/color/tests/runTests.html | 9 + includes/js/dojox/cometd.js | 7 + includes/js/dojox/cometd/README | 29 + includes/js/dojox/cometd/_base.js | 950 +++ includes/js/dojox/cometd/timestamp.js | 9 + includes/js/dojox/cometd/timesync.js | 126 + includes/js/dojox/crypto.js | 6 + includes/js/dojox/crypto/Blowfish.js | 10 + includes/js/dojox/crypto/MD5.js | 10 + includes/js/dojox/crypto/README | 12 + includes/js/dojox/crypto/_base.js | 14 + includes/js/dojox/data/AtomReadStore.js | 543 ++ includes/js/dojox/data/CsvStore.js | 561 ++ includes/js/dojox/data/FlickrRestStore.js | 471 ++ includes/js/dojox/data/FlickrStore.js | 257 + includes/js/dojox/data/HtmlStore.js | 531 ++ includes/js/dojox/data/HtmlTableStore.js | 469 ++ includes/js/dojox/data/KeyValueStore.js | 381 ++ includes/js/dojox/data/OpmlStore.js | 515 ++ includes/js/dojox/data/PicasaStore.js | 254 + includes/js/dojox/data/QueryReadStore.js | 513 ++ includes/js/dojox/data/README | 89 + includes/js/dojox/data/SnapLogicStore.js | 332 + includes/js/dojox/data/XmlStore.js | 1141 ++++ .../js/dojox/data/demos/demo_DataDemoTable.html | 130 + .../js/dojox/data/demos/demo_FlickrRestStore.html | 275 + includes/js/dojox/data/demos/demo_FlickrStore.html | 199 + includes/js/dojox/data/demos/demo_LazyLoad.html | 66 + includes/js/dojox/data/demos/demo_MultiStores.html | 72 + includes/js/dojox/data/demos/demo_PicasaStore.html | 188 + .../data/demos/demo_QueryReadStore_ComboBox.html | 56 + .../demos/demo_QueryReadStore_FilteringSelect.html | 56 + .../dojox/data/demos/demo_QueryReadStore_grid.html | 129 + includes/js/dojox/data/demos/flickrDemo.css | 29 + .../dojox/data/demos/flickrDemo.css.commented.css | 35 + includes/js/dojox/data/demos/geography.json | 45 + includes/js/dojox/data/demos/geography.xml | 51 + .../dojox/data/demos/geography/Argentina/data.json | 5 + .../js/dojox/data/demos/geography/Brazil/data.json | 5 + .../data/demos/geography/Canada/Ottawa/data.json | 6 + .../data/demos/geography/Canada/Toronto/data.json | 6 + .../js/dojox/data/demos/geography/Canada/data.json | 10 + .../js/dojox/data/demos/geography/China/data.json | 4 + .../geography/Commonwealth of Australia/data.json | 5 + .../js/dojox/data/demos/geography/Egypt/data.json | 5 + .../js/dojox/data/demos/geography/France/data.json | 4 + .../dojox/data/demos/geography/Germany/data.json | 4 + .../js/dojox/data/demos/geography/India/data.json | 4 + .../js/dojox/data/demos/geography/Italy/data.json | 4 + .../data/demos/geography/Kenya/Mombasa/data.json | 5 + .../data/demos/geography/Kenya/Nairobi/data.json | 5 + .../js/dojox/data/demos/geography/Kenya/data.json | 9 + .../demos/geography/Mexico/Guadalajara/data.json | 7 + .../demos/geography/Mexico/Mexico City/data.json | 6 + .../js/dojox/data/demos/geography/Mexico/data.json | 10 + .../dojox/data/demos/geography/Mongolia/data.json | 4 + .../js/dojox/data/demos/geography/Russia/data.json | 4 + .../js/dojox/data/demos/geography/Spain/data.json | 4 + .../data/demos/geography/Sudan/Khartoum/data.json | 5 + .../js/dojox/data/demos/geography/Sudan/data.json | 6 + .../geography/United States of America/data.json | 4 + includes/js/dojox/data/demos/geography/root.json | 39 + includes/js/dojox/data/demos/picasaDemo.css | 37 + .../dojox/data/demos/picasaDemo.css.commented.css | 44 + .../js/dojox/data/demos/stores/LazyLoadJSIStore.js | 142 + includes/js/dojox/data/demos/widgets/FlickrView.js | 36 + .../js/dojox/data/demos/widgets/FlickrViewList.js | 37 + includes/js/dojox/data/demos/widgets/PicasaView.js | 37 + .../js/dojox/data/demos/widgets/PicasaViewList.js | 37 + .../data/demos/widgets/templates/FlickrView.html | 34 + .../demos/widgets/templates/FlickrViewList.html | 2 + .../data/demos/widgets/templates/PicasaView.html | 35 + .../demos/widgets/templates/PicasaViewList.html | 2 + includes/js/dojox/data/dom.js | 187 + includes/js/dojox/data/jsonPathStore.js | 1191 ++++ includes/js/dojox/data/tests/QueryReadStore.html | 220 + includes/js/dojox/data/tests/dom.js | 133 + includes/js/dojox/data/tests/ml/divList.html | 14 + includes/js/dojox/data/tests/ml/orderedList.html | 16 + includes/js/dojox/data/tests/ml/table.html | 46 + .../tests/ml/test_HtmlStore_declaratively.html | 172 + .../dojox/data/tests/ml/test_HtmlStore_remote.html | 115 + .../ml/test_HtmlTableStore_declaratively.html | 120 + includes/js/dojox/data/tests/ml/unorderedList.html | 17 + includes/js/dojox/data/tests/module.js | 30 + includes/js/dojox/data/tests/runTests.html | 9 + .../js/dojox/data/tests/stores/AtomReadStore.js | 641 ++ includes/js/dojox/data/tests/stores/CsvStore.js | 1127 ++++ .../js/dojox/data/tests/stores/FlickrRestStore.js | 476 ++ includes/js/dojox/data/tests/stores/FlickrStore.js | 410 ++ includes/js/dojox/data/tests/stores/HtmlStore.js | 804 +++ .../js/dojox/data/tests/stores/HtmlTableStore.js | 702 ++ .../js/dojox/data/tests/stores/KeyValueStore.js | 1002 +++ includes/js/dojox/data/tests/stores/OpmlStore.js | 1075 +++ .../js/dojox/data/tests/stores/QueryReadStore.js | 442 ++ .../js/dojox/data/tests/stores/QueryReadStore.php | 114 + .../js/dojox/data/tests/stores/SnapLogicStore.js | 438 ++ includes/js/dojox/data/tests/stores/XmlStore.js | 881 +++ includes/js/dojox/data/tests/stores/atom1.xml | 848 +++ includes/js/dojox/data/tests/stores/books.html | 118 + includes/js/dojox/data/tests/stores/books.xml | 103 + includes/js/dojox/data/tests/stores/books2.html | 43 + includes/js/dojox/data/tests/stores/books2.xml | 28 + includes/js/dojox/data/tests/stores/books3.html | 14 + includes/js/dojox/data/tests/stores/books3.xml | 31 + .../js/dojox/data/tests/stores/books_isbnAttr.xml | 23 + .../js/dojox/data/tests/stores/books_isbnAttr2.xml | 23 + includes/js/dojox/data/tests/stores/geography.xml | 51 + .../tests/stores/geography_withspeciallabel.xml | 51 + .../js/dojox/data/tests/stores/jsonPathStore.js | 604 ++ includes/js/dojox/data/tests/stores/movies.csv | 9 + includes/js/dojox/data/tests/stores/movies2.csv | 9 + includes/js/dojox/data/tests/stores/patterns.csv | 11 + includes/js/dojox/data/tests/stores/properties.js | 10 + .../js/dojox/data/tests/stores/snap_pipeline.php | 72 + .../data/tests/test_Tree_vs_jsonPathStore.html | 105 + includes/js/dojox/data/tests/treeTest.json | 10 + includes/js/dojox/date/README | 36 + includes/js/dojox/date/php.js | 312 + includes/js/dojox/date/posix.js | 293 + includes/js/dojox/date/tests/module.js | 12 + includes/js/dojox/date/tests/posix.js | 236 + includes/js/dojox/date/tests/runTests.html | 9 + includes/js/dojox/dtl.js | 6 + includes/js/dojox/dtl/Context.js | 87 + includes/js/dojox/dtl/README | 207 + includes/js/dojox/dtl/_HtmlTemplated.js | 72 + includes/js/dojox/dtl/_Templated.js | 93 + includes/js/dojox/dtl/_base.js | 570 ++ includes/js/dojox/dtl/contrib/data.js | 89 + includes/js/dojox/dtl/contrib/dijit.js | 220 + includes/js/dojox/dtl/contrib/html.js | 107 + includes/js/dojox/dtl/contrib/objects.js | 15 + includes/js/dojox/dtl/demos/demo_Animation.html | 45 + includes/js/dojox/dtl/demos/demo_Blog.html | 96 + includes/js/dojox/dtl/demos/demo_Data.html | 58 + includes/js/dojox/dtl/demos/demo_Dijitless.html | 50 + includes/js/dojox/dtl/demos/demo_Events.html | 46 + .../js/dojox/dtl/demos/demo_HtmlTemplated.html | 40 + includes/js/dojox/dtl/demos/demo_Inline.html | 48 + includes/js/dojox/dtl/demos/demo_NodeList.html | 37 + includes/js/dojox/dtl/demos/demo_Table.html | 4072 +++++++++++ includes/js/dojox/dtl/demos/demo_Templated.html | 36 + includes/js/dojox/dtl/demos/demo_Tree.html | 33 + .../js/dojox/dtl/demos/json/blog/get_blog_1.json | 1 + .../js/dojox/dtl/demos/json/blog/get_blog_3.json | 1 + .../dojox/dtl/demos/json/blog/get_blog_list.json | 1 + .../dojox/dtl/demos/json/blog/get_page_about.json | 1 + includes/js/dojox/dtl/demos/json/fruit.json | 1 + includes/js/dojox/dtl/demos/json/morefruit.json | 1 + .../js/dojox/dtl/demos/templates/animation.html | 5 + .../js/dojox/dtl/demos/templates/blog_base.html | 8 + .../js/dojox/dtl/demos/templates/blog_detail.html | 10 + .../js/dojox/dtl/demos/templates/blog_list.html | 9 + .../js/dojox/dtl/demos/templates/blog_page.html | 7 + .../dojox/dtl/demos/templates/countrychildren.html | 1 + includes/js/dojox/dtl/demos/templates/gallery.html | 16 + .../js/dojox/dtl/demos/templates/nodelist.html | 5 + includes/js/dojox/dtl/ext-dojo/NodeList.js | 33 + includes/js/dojox/dtl/filter/dates.js | 54 + includes/js/dojox/dtl/filter/htmlstrings.js | 59 + includes/js/dojox/dtl/filter/integers.js | 32 + includes/js/dojox/dtl/filter/lists.js | 137 + includes/js/dojox/dtl/filter/logic.js | 34 + includes/js/dojox/dtl/filter/misc.js | 59 + includes/js/dojox/dtl/filter/strings.js | 327 + includes/js/dojox/dtl/html.js | 818 +++ includes/js/dojox/dtl/render/html.js | 76 + includes/js/dojox/dtl/tag/date.js | 29 + includes/js/dojox/dtl/tag/loader.js | 277 + includes/js/dojox/dtl/tag/logic.js | 272 + includes/js/dojox/dtl/tag/loop.js | 196 + includes/js/dojox/dtl/tag/misc.js | 291 + includes/js/dojox/dtl/tests/context.js | 79 + .../js/dojox/dtl/tests/demo_Templated_Jaxer.html | 87 + includes/js/dojox/dtl/tests/html/buffer.js | 35 + includes/js/dojox/dtl/tests/html/tag.js | 233 + includes/js/dojox/dtl/tests/html/util.js | 160 + includes/js/dojox/dtl/tests/module.js | 15 + includes/js/dojox/dtl/tests/runTests.html | 9 + includes/js/dojox/dtl/tests/templates/hello.html | 1 + includes/js/dojox/dtl/tests/templates/pocket.html | 1 + includes/js/dojox/dtl/tests/templates/pocket2.html | 1 + includes/js/dojox/dtl/tests/text/filter.js | 740 ++ includes/js/dojox/dtl/tests/text/load.js | 6 + includes/js/dojox/dtl/tests/text/tag.js | 480 ++ includes/js/dojox/dtl/utils/date.js | 72 + includes/js/dojox/encoding/LICENSE | 9 + includes/js/dojox/encoding/README | 35 + includes/js/dojox/encoding/_base.js | 7 + includes/js/dojox/encoding/ascii85.js | 63 + includes/js/dojox/encoding/base64.js | 66 + includes/js/dojox/encoding/bits.js | 68 + includes/js/dojox/encoding/compression/lzw.js | 91 + includes/js/dojox/encoding/compression/splay.js | 64 + includes/js/dojox/encoding/crypto/Blowfish.js | 481 ++ includes/js/dojox/encoding/crypto/_base.js | 19 + includes/js/dojox/encoding/digests/MD5.js | 177 + includes/js/dojox/encoding/digests/_base.js | 78 + includes/js/dojox/encoding/easy64.js | 50 + includes/js/dojox/encoding/tests/ascii85.js | 35 + includes/js/dojox/encoding/tests/bits.js | 74 + .../js/dojox/encoding/tests/compression/_base.js | 12 + .../js/dojox/encoding/tests/compression/colors.js | 156 + .../dojox/encoding/tests/compression/colors2.html | 104 + .../js/dojox/encoding/tests/compression/colors2.js | 64 + .../dojox/encoding/tests/compression/colors3.html | 104 + .../js/dojox/encoding/tests/compression/colors3.js | 53 + .../js/dojox/encoding/tests/compression/lzw.js | 54 + .../dojox/encoding/tests/compression/runTests.html | 9 + .../js/dojox/encoding/tests/compression/splay.js | 49 + .../js/dojox/encoding/tests/compression/test.html | 61 + .../js/dojox/encoding/tests/compression/vq.html | 185 + .../js/dojox/encoding/tests/crypto/Blowfish.js | 35 + includes/js/dojox/encoding/tests/crypto/_base.js | 12 + .../js/dojox/encoding/tests/crypto/runTests.html | 9 + includes/js/dojox/encoding/tests/digests/MD5.js | 26 + includes/js/dojox/encoding/tests/digests/_base.js | 12 + .../js/dojox/encoding/tests/digests/runTests.html | 9 + includes/js/dojox/encoding/tests/easy64.js | 35 + includes/js/dojox/encoding/tests/encoding.js | 13 + includes/js/dojox/encoding/tests/runTests.html | 9 + includes/js/dojox/flash.js | 6 + includes/js/dojox/flash/DojoExternalInterface.as | 168 + includes/js/dojox/flash/ExpressInstall.as | 71 + includes/js/dojox/flash/README | 31 + includes/js/dojox/flash/_base.js | 762 +++ includes/js/dojox/flash/tests/TestFlash.as | 36 + includes/js/dojox/flash/tests/TestFlash.swf | Bin 0 -> 1863 bytes includes/js/dojox/flash/tests/buildFlashTest.sh | 4 + includes/js/dojox/flash/tests/test_flash.html | 15 + includes/js/dojox/flash/tests/test_flash.js | 155 + includes/js/dojox/form/CheckedMultiSelect.js | 223 + includes/js/dojox/form/DropDownSelect.js | 267 + includes/js/dojox/form/PasswordValidator.js | 280 + includes/js/dojox/form/README | 39 + includes/js/dojox/form/nls/PasswordValidator.js | 1 + .../js/dojox/form/resources/CheckedMultiSelect.css | 65 + .../resources/CheckedMultiSelect.css.commented.css | 99 + .../dojox/form/resources/CheckedMultiSelect.html | 4 + .../js/dojox/form/resources/DropDownSelect.css | 137 + .../resources/DropDownSelect.css.commented.css | 209 + .../js/dojox/form/resources/PasswordValidator.html | 3 + .../form/resources/_CheckedMultiSelectItem.html | 4 + .../dojox/form/tests/test_CheckedMultiSelect.html | 91 + .../js/dojox/form/tests/test_DropDownSelect.html | 128 + .../dojox/form/tests/test_PasswordValidator.html | 216 + includes/js/dojox/fx.js | 7 + includes/js/dojox/fx/README | 77 + includes/js/dojox/fx/Shadow.js | 151 + includes/js/dojox/fx/_arg.js | 27 + includes/js/dojox/fx/_base.js | 240 + includes/js/dojox/fx/_core.js | 60 + includes/js/dojox/fx/easing.js | 223 + includes/js/dojox/fx/ext-dojo/NodeList.js | 66 + includes/js/dojox/fx/resources/shadowB.png | Bin 0 -> 470 bytes includes/js/dojox/fx/resources/shadowBL.png | Bin 0 -> 272 bytes includes/js/dojox/fx/resources/shadowBR.png | Bin 0 -> 271 bytes includes/js/dojox/fx/resources/shadowL.png | Bin 0 -> 148 bytes includes/js/dojox/fx/resources/shadowR.png | Bin 0 -> 149 bytes includes/js/dojox/fx/resources/shadowT.png | Bin 0 -> 152 bytes includes/js/dojox/fx/resources/shadowTL.png | Bin 0 -> 271 bytes includes/js/dojox/fx/resources/shadowTR.png | Bin 0 -> 287 bytes includes/js/dojox/fx/scroll.js | 40 + includes/js/dojox/fx/style.js | 219 + includes/js/dojox/fx/tests/_animation.css | 97 + .../js/dojox/fx/tests/_animation.css.commented.css | 113 + includes/js/dojox/fx/tests/example_Line.html | 80 + .../dojox/fx/tests/example_backgroundPosition.html | 59 + .../js/dojox/fx/tests/example_dojoAnimations.html | 442 ++ .../js/dojox/fx/tests/example_easingChart2D.html | 147 + includes/js/dojox/fx/tests/images/averycutedog.jpg | Bin 0 -> 40879 bytes includes/js/dojox/fx/tests/images/dot.png | Bin 0 -> 4064 bytes includes/js/dojox/fx/tests/images/longBg.png | Bin 0 -> 12217 bytes includes/js/dojox/fx/tests/test_Nodelist-fx.html | 282 + includes/js/dojox/fx/tests/test_Shadow.html | 93 + includes/js/dojox/fx/tests/test_animateClass.html | 222 + includes/js/dojox/fx/tests/test_crossFade.html | 145 + includes/js/dojox/fx/tests/test_easing.html | 142 + includes/js/dojox/fx/tests/test_highlight.html | 45 + includes/js/dojox/fx/tests/test_scroll.html | 98 + includes/js/dojox/fx/tests/test_sizeTo.html | 142 + includes/js/dojox/fx/tests/test_slideBy.html | 75 + includes/js/dojox/fx/tests/test_wipeTo.html | 109 + includes/js/dojox/gfx.js | 40 + includes/js/dojox/gfx/Moveable.js | 101 + includes/js/dojox/gfx/Mover.js | 62 + includes/js/dojox/gfx/README | 102 + includes/js/dojox/gfx/_base.js | 288 + includes/js/dojox/gfx/arc.js | 122 + includes/js/dojox/gfx/attach.js | 7 + includes/js/dojox/gfx/canvas.js | 687 ++ includes/js/dojox/gfx/canvas_attach.js | 8 + includes/js/dojox/gfx/decompose.js | 139 + includes/js/dojox/gfx/demos/beautify.html | 48 + includes/js/dojox/gfx/demos/butterfly.html | 88 + includes/js/dojox/gfx/demos/career_test.html | 467 ++ includes/js/dojox/gfx/demos/circles.html | 90 + includes/js/dojox/gfx/demos/clock.html | 253 + includes/js/dojox/gfx/demos/clockWidget.html | 332 + includes/js/dojox/gfx/demos/clock_black.html | 253 + includes/js/dojox/gfx/demos/creator.html | 123 + includes/js/dojox/gfx/demos/data/Lars.json | 1823 +++++ includes/js/dojox/gfx/demos/data/Lars.svg | 531 ++ includes/js/dojox/gfx/demos/data/LarsDreaming.json | 1823 +++++ includes/js/dojox/gfx/demos/data/LarsDreaming.svg | 536 ++ includes/js/dojox/gfx/demos/data/Nils.json | 717 ++ includes/js/dojox/gfx/demos/data/Nils.svg | 188 + includes/js/dojox/gfx/demos/data/buratino-bg.png | Bin 0 -> 27507 bytes includes/js/dojox/gfx/demos/data/buratino-head.png | Bin 0 -> 30696 bytes .../js/dojox/gfx/demos/data/buratino-left-arm.png | Bin 0 -> 9631 bytes .../js/dojox/gfx/demos/data/buratino-left-leg.png | Bin 0 -> 21682 bytes .../js/dojox/gfx/demos/data/buratino-lollipop.png | Bin 0 -> 21976 bytes .../dojox/gfx/demos/data/buratino-nose-large.png | Bin 0 -> 4182 bytes .../dojox/gfx/demos/data/buratino-nose-medium.png | Bin 0 -> 2587 bytes .../js/dojox/gfx/demos/data/buratino-right-arm.png | Bin 0 -> 13033 bytes .../js/dojox/gfx/demos/data/buratino-right-leg.png | Bin 0 -> 23025 bytes .../js/dojox/gfx/demos/data/buratino-torso.png | Bin 0 -> 23405 bytes includes/js/dojox/gfx/demos/data/buratino.jpg | Bin 0 -> 33344 bytes includes/js/dojox/gfx/demos/data/buratino.json | 12 + includes/js/dojox/gfx/demos/data/svg2gfx.xsl | 72 + includes/js/dojox/gfx/demos/data/transform.json | 1567 +++++ includes/js/dojox/gfx/demos/images/clock_face.jpg | Bin 0 -> 31088 bytes .../js/dojox/gfx/demos/images/clock_face_black.jpg | Bin 0 -> 17347 bytes includes/js/dojox/gfx/demos/inspector.html | 165 + includes/js/dojox/gfx/demos/lion.html | 235 + includes/js/dojox/gfx/demos/roundedPane.html | 191 + includes/js/dojox/gfx/demos/tiger.html | 566 ++ includes/js/dojox/gfx/demos/tooltip.html | 238 + includes/js/dojox/gfx/fx.js | 281 + includes/js/dojox/gfx/matrix.js | 444 ++ includes/js/dojox/gfx/move.js | 8 + includes/js/dojox/gfx/path.js | 361 + includes/js/dojox/gfx/shape.js | 691 ++ includes/js/dojox/gfx/silverlight.js | 693 ++ includes/js/dojox/gfx/silverlight_attach.js | 87 + includes/js/dojox/gfx/svg.js | 638 ++ includes/js/dojox/gfx/svg_attach.js | 224 + includes/js/dojox/gfx/tests/decompose.js | 114 + includes/js/dojox/gfx/tests/matrix.js | 228 + includes/js/dojox/gfx/tests/module.js | 13 + includes/js/dojox/gfx/tests/runTests.html | 9 + includes/js/dojox/gfx/tests/test_arc.html | 71 + includes/js/dojox/gfx/tests/test_bezier.html | 85 + includes/js/dojox/gfx/tests/test_decompose.html | 54 + includes/js/dojox/gfx/tests/test_fill.html | 47 + includes/js/dojox/gfx/tests/test_fx.html | 113 + includes/js/dojox/gfx/tests/test_gfx.html | 489 ++ includes/js/dojox/gfx/tests/test_gradient.html | 70 + includes/js/dojox/gfx/tests/test_group.html | 73 + includes/js/dojox/gfx/tests/test_image1.html | 74 + includes/js/dojox/gfx/tests/test_image2.html | 50 + .../js/dojox/gfx/tests/test_linearGradient.html | 80 + includes/js/dojox/gfx/tests/test_linestyle.html | 45 + includes/js/dojox/gfx/tests/test_pattern.html | 44 + includes/js/dojox/gfx/tests/test_poly.html | 53 + includes/js/dojox/gfx/tests/test_resize.html | 61 + includes/js/dojox/gfx/tests/test_setPath.html | 76 + includes/js/dojox/gfx/tests/test_tbbox.html | 117 + includes/js/dojox/gfx/tests/test_text.html | 88 + includes/js/dojox/gfx/tests/test_textpath.html | 76 + includes/js/dojox/gfx/tests/test_transform.html | 98 + includes/js/dojox/gfx/utils.js | 87 + includes/js/dojox/gfx/vml.js | 1165 ++++ includes/js/dojox/gfx/vml_attach.js | 362 + includes/js/dojox/gfx3d.js | 11 + includes/js/dojox/gfx3d/README | 36 + includes/js/dojox/gfx3d/_base.js | 19 + includes/js/dojox/gfx3d/gradient.js | 41 + includes/js/dojox/gfx3d/lighting.js | 241 + includes/js/dojox/gfx3d/matrix.js | 339 + includes/js/dojox/gfx3d/object.js | 1092 +++ includes/js/dojox/gfx3d/scheduler.js | 126 + .../js/dojox/gfx3d/tests/test_camerarotate.html | 93 + .../gfx3d/tests/test_camerarotate_shaded.html | 97 + includes/js/dojox/gfx3d/tests/test_cube.html | 50 + includes/js/dojox/gfx3d/tests/test_cylinder.html | 66 + includes/js/dojox/gfx3d/tests/test_drawer.html | 92 + includes/js/dojox/gfx3d/tests/test_edges.html | 73 + includes/js/dojox/gfx3d/tests/test_matrix.html | 89 + includes/js/dojox/gfx3d/tests/test_orbit.html | 50 + includes/js/dojox/gfx3d/tests/test_overlap.html | 69 + includes/js/dojox/gfx3d/tests/test_polygon.html | 44 + includes/js/dojox/gfx3d/tests/test_quads.html | 78 + includes/js/dojox/gfx3d/tests/test_rotate.html | 123 + includes/js/dojox/gfx3d/tests/test_scene.html | 66 + includes/js/dojox/gfx3d/tests/test_triangles.html | 82 + includes/js/dojox/gfx3d/tests/test_vector.html | 59 + includes/js/dojox/gfx3d/vector.js | 110 + includes/js/dojox/grid/Grid.js | 363 + includes/js/dojox/grid/README | 39 + includes/js/dojox/grid/VirtualGrid.js | 779 +++ includes/js/dojox/grid/_data/dijitEditors.js | 170 + includes/js/dojox/grid/_data/editors.js | 239 + includes/js/dojox/grid/_data/fields.js | 104 + includes/js/dojox/grid/_data/model.js | 762 +++ includes/js/dojox/grid/_grid/Grid.css | 201 + .../js/dojox/grid/_grid/Grid.css.commented.css | 258 + includes/js/dojox/grid/_grid/Grid_rtl.css | 8 + .../js/dojox/grid/_grid/Grid_rtl.css.commented.css | 10 + includes/js/dojox/grid/_grid/builder.js | 522 ++ includes/js/dojox/grid/_grid/cell.js | 66 + includes/js/dojox/grid/_grid/drag.js | 113 + includes/js/dojox/grid/_grid/edit.js | 238 + includes/js/dojox/grid/_grid/focus.js | 207 + .../dojox/grid/_grid/images/grid_dx_gradient.gif | Bin 0 -> 267 bytes .../js/dojox/grid/_grid/images/grid_sort_down.gif | Bin 0 -> 49 bytes .../js/dojox/grid/_grid/images/grid_sort_up.gif | Bin 0 -> 48 bytes .../dojox/grid/_grid/images/tabEnabled_rotated.png | Bin 0 -> 94 bytes .../dojox/grid/_grid/images/tabHover_rotated.png | Bin 0 -> 106 bytes includes/js/dojox/grid/_grid/layout.js | 75 + includes/js/dojox/grid/_grid/lib.js | 254 + includes/js/dojox/grid/_grid/nihiloGrid.css | 211 + .../dojox/grid/_grid/nihiloGrid.css.commented.css | 275 + includes/js/dojox/grid/_grid/publicEvents.js | 451 ++ includes/js/dojox/grid/_grid/rowbar.js | 53 + includes/js/dojox/grid/_grid/rows.js | 66 + includes/js/dojox/grid/_grid/scroller.js | 489 ++ includes/js/dojox/grid/_grid/selection.js | 215 + includes/js/dojox/grid/_grid/soriaGrid.css | 212 + .../dojox/grid/_grid/soriaGrid.css.commented.css | 276 + includes/js/dojox/grid/_grid/tundraGrid.css | 215 + .../dojox/grid/_grid/tundraGrid.css.commented.css | 281 + includes/js/dojox/grid/_grid/view.js | 336 + includes/js/dojox/grid/_grid/views.js | 277 + includes/js/dojox/grid/resources/GridView.html | 12 + includes/js/dojox/grid/resources/VirtualGrid.html | 5 + includes/js/dojox/grid/tests/databaseModel.js | 337 + includes/js/dojox/grid/tests/images/closed.gif | Bin 0 -> 907 bytes includes/js/dojox/grid/tests/images/flatScreen.gif | Bin 0 -> 824 bytes includes/js/dojox/grid/tests/images/open.gif | Bin 0 -> 907 bytes includes/js/dojox/grid/tests/support/books.xml | 103 + includes/js/dojox/grid/tests/support/data.php | 379 ++ includes/js/dojox/grid/tests/support/geography.xml | 51 + includes/js/dojox/grid/tests/support/json.php | 794 +++ includes/js/dojox/grid/tests/support/movies.csv | 9 + includes/js/dojox/grid/tests/support/test_data.js | 30 + .../dojox/grid/tests/support/test_data_objects.js | 31 + includes/js/dojox/grid/tests/support/testtbl.sql | 944 +++ .../js/dojox/grid/tests/support/yahoo_search.js | 131 + .../js/dojox/grid/tests/test_change_structure.html | 124 + includes/js/dojox/grid/tests/test_custom_sort.html | 86 + .../js/dojox/grid/tests/test_dojo_data_edit.html | 124 + .../js/dojox/grid/tests/test_dojo_data_empty.html | 63 + .../js/dojox/grid/tests/test_dojo_data_model.html | 84 + .../tests/test_dojo_data_model_EmptyResultSet.html | 57 + .../tests/test_dojo_data_model_multiStores.html | 291 + .../tests/test_dojo_data_model_processError.html | 65 + .../grid/tests/test_dojo_data_notification.html | 114 + includes/js/dojox/grid/tests/test_edit.html | 149 + .../js/dojox/grid/tests/test_edit_canEdit.html | 156 + includes/js/dojox/grid/tests/test_edit_dijit.html | 137 + includes/js/dojox/grid/tests/test_events.html | 174 + includes/js/dojox/grid/tests/test_expand.html | 107 + includes/js/dojox/grid/tests/test_grid.html | 69 + includes/js/dojox/grid/tests/test_grid_dlg.html | 88 + .../dojox/grid/tests/test_grid_headerHeight.html | 84 + includes/js/dojox/grid/tests/test_grid_layout.html | 112 + .../tests/test_grid_layout_LayoutContainer.html | 87 + .../tests/test_grid_layout_borderContainer.html | 98 + .../grid/tests/test_grid_object_model_change.html | 86 + .../dojox/grid/tests/test_grid_programmatic.html | 65 + .../grid/tests/test_grid_programmatic_layout.html | 74 + includes/js/dojox/grid/tests/test_grid_rtl.html | 71 + includes/js/dojox/grid/tests/test_grid_themes.html | 118 + .../dojox/grid/tests/test_grid_tooltip_menu.html | 161 + includes/js/dojox/grid/tests/test_keyboard.html | 90 + includes/js/dojox/grid/tests/test_markup.html | 112 + includes/js/dojox/grid/tests/test_mysql_edit.html | 155 + includes/js/dojox/grid/tests/test_sizing.html | 175 + .../js/dojox/grid/tests/test_sizing_100rows.html | 168 + .../dojox/grid/tests/test_sizing_ResizeHandle.html | 113 + includes/js/dojox/grid/tests/test_styling.html | 131 + includes/js/dojox/grid/tests/test_subgrid.html | 179 + includes/js/dojox/grid/tests/test_tundra_edit.html | 139 + .../js/dojox/grid/tests/test_yahoo_images.html | 148 + .../js/dojox/grid/tests/test_yahoo_search.html | 141 + includes/js/dojox/grid/tests/yahooSearch.js | 137 + includes/js/dojox/help/README | 35 + includes/js/dojox/help/_base.js | 473 ++ includes/js/dojox/help/console.js | 80 + includes/js/dojox/help/demos/demo_Console.html | 33 + includes/js/dojox/highlight.js | 6 + includes/js/dojox/highlight/README | 31 + includes/js/dojox/highlight/_base.js | 406 ++ includes/js/dojox/highlight/languages/_all.js | 11 + includes/js/dojox/highlight/languages/_dynamic.js | 11 + includes/js/dojox/highlight/languages/_static.js | 10 + includes/js/dojox/highlight/languages/_www.js | 12 + includes/js/dojox/highlight/languages/cpp.js | 53 + includes/js/dojox/highlight/languages/css.js | 96 + includes/js/dojox/highlight/languages/delphi.js | 122 + includes/js/dojox/highlight/languages/django.js | 97 + includes/js/dojox/highlight/languages/html.js | 70 + .../js/dojox/highlight/languages/javascript.js | 55 + .../js/dojox/highlight/languages/pygments/_html.js | 25 + .../js/dojox/highlight/languages/pygments/_www.js | 12 + .../js/dojox/highlight/languages/pygments/css.js | 211 + .../js/dojox/highlight/languages/pygments/html.js | 101 + .../highlight/languages/pygments/javascript.js | 152 + .../js/dojox/highlight/languages/pygments/xml.js | 79 + includes/js/dojox/highlight/languages/python.js | 102 + includes/js/dojox/highlight/languages/sql.js | 101 + includes/js/dojox/highlight/languages/xml.js | 69 + .../js/dojox/highlight/resources/highlight.css | 51 + .../resources/highlight.css.commented.css | 58 + .../dojox/highlight/resources/pygments/autumn.css | 22 + .../resources/pygments/autumn.css.commented.css | 28 + .../dojox/highlight/resources/pygments/borland.css | 11 + .../resources/pygments/borland.css.commented.css | 17 + .../highlight/resources/pygments/colorful.css | 37 + .../resources/pygments/colorful.css.commented.css | 43 + .../dojox/highlight/resources/pygments/default.css | 28 + .../resources/pygments/default.css.commented.css | 35 + .../dojox/highlight/resources/pygments/emacs.css | 29 + .../resources/pygments/emacs.css.commented.css | 36 + .../highlight/resources/pygments/friendly.css | 29 + .../resources/pygments/friendly.css.commented.css | 36 + .../dojox/highlight/resources/pygments/fruity.css | 14 + .../resources/pygments/fruity.css.commented.css | 20 + .../dojox/highlight/resources/pygments/manni.css | 30 + .../resources/pygments/manni.css.commented.css | 37 + .../dojox/highlight/resources/pygments/murphy.css | 37 + .../resources/pygments/murphy.css.commented.css | 43 + .../dojox/highlight/resources/pygments/native.css | 21 + .../resources/pygments/native.css.commented.css | 28 + .../dojox/highlight/resources/pygments/pastie.css | 30 + .../resources/pygments/pastie.css.commented.css | 36 + .../dojox/highlight/resources/pygments/perldoc.css | 23 + .../resources/pygments/perldoc.css.commented.css | 30 + .../js/dojox/highlight/resources/pygments/trac.css | 20 + .../resources/pygments/trac.css.commented.css | 26 + .../js/dojox/highlight/tests/test_highlight.html | 327 + .../js/dojox/highlight/tests/test_pygments.html | 142 + includes/js/dojox/image/Gallery.js | 182 + includes/js/dojox/image/Lightbox.js | 451 ++ includes/js/dojox/image/Magnifier.js | 75 + includes/js/dojox/image/MagnifierLite.js | 126 + includes/js/dojox/image/README | 66 + includes/js/dojox/image/SlideShow.js | 598 ++ includes/js/dojox/image/ThumbnailPicker.js | 535 ++ includes/js/dojox/image/resources/Gallery.html | 4 + includes/js/dojox/image/resources/Lightbox.html | 15 + includes/js/dojox/image/resources/Magnifier.css | 5 + .../image/resources/Magnifier.css.commented.css | 5 + includes/js/dojox/image/resources/SlideShow.html | 14 + .../js/dojox/image/resources/ThumbnailPicker.html | 11 + includes/js/dojox/image/resources/image.css | 283 + .../dojox/image/resources/image.css.commented.css | 345 + .../js/dojox/image/resources/images/buttons.gif | Bin 0 -> 4620 bytes .../js/dojox/image/resources/images/buttons.png | Bin 0 -> 9259 bytes includes/js/dojox/image/resources/images/close.png | Bin 0 -> 675 bytes .../js/dojox/image/resources/images/close_dark.png | Bin 0 -> 711 bytes includes/js/dojox/image/resources/images/left.png | Bin 0 -> 626 bytes .../js/dojox/image/resources/images/loading.gif | Bin 0 -> 4178 bytes includes/js/dojox/image/resources/images/right.png | Bin 0 -> 621 bytes .../js/dojox/image/resources/images/warning.png | Bin 0 -> 995 bytes includes/js/dojox/image/tests/images.json | 32 + includes/js/dojox/image/tests/images/extraWide.jpg | Bin 0 -> 49250 bytes includes/js/dojox/image/tests/images/huuuge.png | Bin 0 -> 37958 bytes .../js/dojox/image/tests/images/imageHoriz.jpg | Bin 0 -> 47693 bytes .../js/dojox/image/tests/images/imageHoriz2.jpg | Bin 0 -> 77176 bytes includes/js/dojox/image/tests/images/imageVert.jpg | Bin 0 -> 71533 bytes includes/js/dojox/image/tests/images/spanke.jpg | Bin 0 -> 302741 bytes includes/js/dojox/image/tests/images/square.jpg | Bin 0 -> 82010 bytes includes/js/dojox/image/tests/test_Gallery.html | 67 + includes/js/dojox/image/tests/test_Lightbox.html | 105 + includes/js/dojox/image/tests/test_Magnifier.html | 98 + .../js/dojox/image/tests/test_MagnifierLite.html | 91 + includes/js/dojox/image/tests/test_SlideShow.html | 68 + .../js/dojox/image/tests/test_ThumbnailPicker.html | 134 + includes/js/dojox/io/README | 45 + includes/js/dojox/io/proxy/README | 82 + includes/js/dojox/io/proxy/tests/frag.xml | 4 + includes/js/dojox/io/proxy/tests/xip.html | 62 + includes/js/dojox/io/proxy/xip.js | 441 ++ includes/js/dojox/io/proxy/xip_client.html | 102 + includes/js/dojox/io/proxy/xip_server.html | 382 ++ includes/js/dojox/io/xhrMultiPart.js | 81 + includes/js/dojox/jsonPath.js | 6 + includes/js/dojox/jsonPath/README | 125 + includes/js/dojox/jsonPath/query.js | 163 + includes/js/dojox/jsonPath/tests/jsonPath.js | 211 + includes/js/dojox/jsonPath/tests/module.js | 12 + includes/js/dojox/jsonPath/tests/runTests.html | 9 + includes/js/dojox/lang/LICENSE | 21 + includes/js/dojox/lang/README | 37 + includes/js/dojox/lang/functional.js | 9 + includes/js/dojox/lang/functional/array.js | 113 + includes/js/dojox/lang/functional/curry.js | 96 + includes/js/dojox/lang/functional/fold.js | 87 + includes/js/dojox/lang/functional/lambda.js | 110 + includes/js/dojox/lang/functional/listcomp.js | 54 + includes/js/dojox/lang/functional/object.js | 48 + includes/js/dojox/lang/functional/reversed.js | 79 + includes/js/dojox/lang/functional/scan.js | 84 + includes/js/dojox/lang/functional/sequence.js | 38 + includes/js/dojox/lang/functional/zip.js | 45 + includes/js/dojox/lang/tests/array.js | 84 + includes/js/dojox/lang/tests/curry.js | 31 + includes/js/dojox/lang/tests/fold.js | 64 + includes/js/dojox/lang/tests/fun_perf.html | 176 + includes/js/dojox/lang/tests/lambda.js | 24 + includes/js/dojox/lang/tests/listcomp.js | 28 + includes/js/dojox/lang/tests/main.js | 17 + includes/js/dojox/lang/tests/misc.js | 31 + includes/js/dojox/lang/tests/runTests.html | 9 + includes/js/dojox/lang/utils.js | 54 + includes/js/dojox/layout/BorderContainer.js | 7 + includes/js/dojox/layout/ContentPane.js | 479 ++ includes/js/dojox/layout/DragPane.js | 65 + includes/js/dojox/layout/ExpandoPane.js | 208 + includes/js/dojox/layout/FloatingPane.js | 394 ++ includes/js/dojox/layout/README | 75 + includes/js/dojox/layout/RadioGroup.js | 233 + includes/js/dojox/layout/ResizeHandle.js | 271 + includes/js/dojox/layout/ScrollPane.js | 114 + includes/js/dojox/layout/resources/ExpandoPane.css | 99 + .../layout/resources/ExpandoPane.css.commented.css | 116 + .../js/dojox/layout/resources/ExpandoPane.html | 9 + .../js/dojox/layout/resources/FloatingPane.css | 152 + .../resources/FloatingPane.css.commented.css | 183 + .../js/dojox/layout/resources/FloatingPane.html | 14 + includes/js/dojox/layout/resources/RadioGroup.css | 40 + .../layout/resources/RadioGroup.css.commented.css | 45 + .../js/dojox/layout/resources/ResizeHandle.css | 28 + .../resources/ResizeHandle.css.commented.css | 34 + includes/js/dojox/layout/resources/ScrollPane.css | 21 + .../layout/resources/ScrollPane.css.commented.css | 24 + includes/js/dojox/layout/resources/ScrollPane.html | 6 + .../js/dojox/layout/resources/icons/resize.png | Bin 0 -> 319 bytes includes/js/dojox/layout/tests/ContentPane.html | 1059 +++ includes/js/dojox/layout/tests/_bottomPane.html | 53 + includes/js/dojox/layout/tests/_expando.css | 477 ++ .../dojox/layout/tests/_expando.css.commented.css | 64 + includes/js/dojox/layout/tests/_floating.html | 48 + includes/js/dojox/layout/tests/_lorem.html | 11 + includes/js/dojox/layout/tests/_script.html | 9 + includes/js/dojox/layout/tests/doc0.html | 14 + includes/js/dojox/layout/tests/images/blank.gif | Bin 0 -> 43 bytes includes/js/dojox/layout/tests/images/dojoLogo.png | Bin 0 -> 14712 bytes .../js/dojox/layout/tests/images/gridUnderlay.png | Bin 0 -> 915 bytes .../js/dojox/layout/tests/images/testImage.gif | Bin 0 -> 14171 bytes .../js/dojox/layout/tests/remote/getResponse.php | 108 + includes/js/dojox/layout/tests/test_DragPane.html | 93 + .../js/dojox/layout/tests/test_ExpandoPane.html | 307 + .../dojox/layout/tests/test_ExpandoPane_code.html | 98 + .../dojox/layout/tests/test_ExpandoPane_more.html | 114 + .../js/dojox/layout/tests/test_FloatingPane.html | 167 + .../js/dojox/layout/tests/test_RadioGroup.html | 61 + .../js/dojox/layout/tests/test_ResizeHandle.html | 134 + .../js/dojox/layout/tests/test_ScrollPane.html | 129 + .../dojox/layout/tests/test_ScrollPaneSingle.html | 71 + .../js/dojox/layout/tests/test_SizingPane.html | 170 + includes/js/dojox/math.js | 6 + includes/js/dojox/math/README | 38 + includes/js/dojox/math/_base.js | 122 + includes/js/dojox/math/curves.js | 193 + includes/js/dojox/math/matrix.js | 294 + includes/js/dojox/off.js | 6 + includes/js/dojox/off/README | 28 + includes/js/dojox/off/_common.js | 559 ++ includes/js/dojox/off/docs/bookmarklets.html | 10 + includes/js/dojox/off/files.js | 454 ++ includes/js/dojox/off/network_check.txt | 1 + includes/js/dojox/off/offline.js | 20 + includes/js/dojox/off/offline.js.uncompressed.js | 5910 ++++++++++++++++ includes/js/dojox/off/resources/checkmark.png | Bin 0 -> 27329 bytes includes/js/dojox/off/resources/greenball.png | Bin 0 -> 27414 bytes includes/js/dojox/off/resources/learnhow.html | 43 + includes/js/dojox/off/resources/learnhow.js | 43 + includes/js/dojox/off/resources/offline-widget.css | 88 + .../off/resources/offline-widget.css.commented.css | 112 + .../js/dojox/off/resources/offline-widget.html | 40 + includes/js/dojox/off/resources/redball.png | Bin 0 -> 27409 bytes includes/js/dojox/off/resources/roller.gif | Bin 0 -> 7462 bytes includes/js/dojox/off/sync.js | 690 ++ includes/js/dojox/off/ui.js | 622 ++ includes/js/dojox/presentation.js | 6 + includes/js/dojox/presentation/README | 72 + includes/js/dojox/presentation/_base.js | 557 ++ includes/js/dojox/presentation/resources/Show.css | 100 + .../presentation/resources/Show.css.commented.css | 110 + includes/js/dojox/presentation/resources/Show.html | 12 + .../js/dojox/presentation/resources/Slide.html | 4 + .../js/dojox/presentation/resources/icons/down.png | Bin 0 -> 469 bytes .../js/dojox/presentation/resources/icons/next.png | Bin 0 -> 470 bytes .../js/dojox/presentation/resources/icons/prev.png | Bin 0 -> 460 bytes .../js/dojox/presentation/resources/icons/up.png | Bin 0 -> 464 bytes includes/js/dojox/presentation/tests/_ext1.html | 21 + .../presentation/tests/test_presentation.html | 162 + includes/js/dojox/resources/README.template | 36 + includes/js/dojox/resources/_modules.js | 204 + includes/js/dojox/resources/manualTests.html | 12 + includes/js/dojox/resources/manualTests.js | 211 + includes/js/dojox/rpc/CouchDBRestStore.js | 87 + includes/js/dojox/rpc/JsonRPC.js | 58 + includes/js/dojox/rpc/JsonReferencing.js | 265 + includes/js/dojox/rpc/JsonRestStore.js | 661 ++ includes/js/dojox/rpc/PersevereRestStore.js | 39 + includes/js/dojox/rpc/README | 52 + includes/js/dojox/rpc/Rest.js | 90 + includes/js/dojox/rpc/SMDLibrary/yahoo.smd | 493 ++ includes/js/dojox/rpc/Service.js | 293 + .../rpc/demos/demo_JsonRestStore_CouchDB.html | 125 + .../rpc/demos/demo_JsonRestStore_Persevere.html | 65 + includes/js/dojox/rpc/demos/documentation.html | 33 + .../dojox/rpc/demos/templates/documentation.html | 8 + includes/js/dojox/rpc/demos/templates/yahoo.html | 31 + includes/js/dojox/rpc/demos/yahoo.html | 39 + includes/js/dojox/rpc/documentation.smd | 30 + includes/js/dojox/rpc/test.txt | 0 includes/js/dojox/rpc/tests/JsonReferencing.js | 30 + includes/js/dojox/rpc/tests/Service.js | 702 ++ includes/js/dojox/rpc/tests/Yahoo.js | 317 + includes/js/dojox/rpc/tests/libraryTests.js | 12 + includes/js/dojox/rpc/tests/module.js | 13 + includes/js/dojox/rpc/tests/resources/JSON.php | 724 ++ includes/js/dojox/rpc/tests/resources/bigQuery | 1 + includes/js/dojox/rpc/tests/resources/bigQuery5 | 1 + includes/js/dojox/rpc/tests/resources/echo.php | 7 + includes/js/dojox/rpc/tests/resources/echoJson.php | 8 + .../js/dojox/rpc/tests/resources/fakestore.php | 36 + .../js/dojox/rpc/tests/resources/jsonRpc10.php | 47 + .../js/dojox/rpc/tests/resources/jsonRpc11.php | 52 + .../js/dojox/rpc/tests/resources/jsonRpc12.php | 53 + .../rpc/tests/resources/jsonRpcPostGetEcho.php | 38 + .../js/dojox/rpc/tests/resources/jsonpEcho.php | 23 + .../js/dojox/rpc/tests/resources/jsonpEcho.phps | 23 + .../dojox/rpc/tests/resources/jsonpJsonRpcEcho.php | 37 + includes/js/dojox/rpc/tests/resources/obj1 | 1 + .../js/dojox/rpc/tests/resources/obj1testArray | 1 + includes/js/dojox/rpc/tests/resources/obj3 | 1 + includes/js/dojox/rpc/tests/resources/obj4 | 1 + includes/js/dojox/rpc/tests/resources/query | 6 + includes/js/dojox/rpc/tests/resources/rawEcho.php | 5 + includes/js/dojox/rpc/tests/resources/res | 1 + includes/js/dojox/rpc/tests/resources/store.php | 24 + includes/js/dojox/rpc/tests/resources/test.smd | 189 + includes/js/dojox/rpc/tests/runLibraryTests.html | 9 + includes/js/dojox/rpc/tests/runTests.html | 9 + .../js/dojox/rpc/tests/stores/JsonRestStore.js | 237 + .../rpc/tests/test_dojo_data_model_persevere.html | 146 + includes/js/dojox/sketch.js | 13 + includes/js/dojox/sketch/Anchor.js | 61 + includes/js/dojox/sketch/Annotation.js | 223 + includes/js/dojox/sketch/DoubleArrowAnnotation.js | 200 + includes/js/dojox/sketch/Figure.js | 493 ++ includes/js/dojox/sketch/LeadAnnotation.js | 141 + includes/js/dojox/sketch/PreexistingAnnotation.js | 121 + includes/js/dojox/sketch/README | 58 + includes/js/dojox/sketch/SingleArrowAnnotation.js | 183 + includes/js/dojox/sketch/Slider.js | 31 + includes/js/dojox/sketch/Toolbar.js | 96 + includes/js/dojox/sketch/UnderlineAnnotation.js | 82 + includes/js/dojox/sketch/UndoStack.js | 104 + includes/js/dojox/sketch/_Plugin.js | 83 + .../js/dojox/sketch/resources/images/icons.gif | Bin 0 -> 600 bytes includes/js/dojox/sketch/resources/sketch.css | 17 + .../sketch/resources/sketch.css.commented.css | 17 + includes/js/dojox/sketch/tests/annotation.svg | 1 + includes/js/dojox/sketch/tests/images/figure2.gif | Bin 0 -> 40349 bytes .../js/dojox/sketch/tests/images/testsBodyBg.gif | Bin 0 -> 753 bytes includes/js/dojox/sketch/tests/test_full.html | 66 + includes/js/dojox/sql.js | 6 + includes/js/dojox/storage.js | 6 + includes/js/dojox/storage/AirDBStorageProvider.js | 252 + .../storage/AirEncryptedLocalStorageProvider.js | 221 + .../js/dojox/storage/AirFileStorageProvider.js | 232 + includes/js/dojox/storage/FlashStorageProvider.js | 346 + includes/js/dojox/storage/GearsStorageProvider.js | 320 + includes/js/dojox/storage/Provider.js | 331 + includes/js/dojox/storage/README | 76 + includes/js/dojox/storage/Storage.as | 399 ++ includes/js/dojox/storage/Storage.swf | Bin 0 -> 3256 bytes includes/js/dojox/storage/WhatWGStorageProvider.js | 278 + includes/js/dojox/storage/_common.js | 20 + includes/js/dojox/storage/buildFlashStorage.sh | 4 + includes/js/dojox/storage/demos/helloworld.html | 90 + includes/js/dojox/storage/manager.js | 261 + includes/js/dojox/storage/storage_dialog.fla | Bin 0 -> 344064 bytes .../js/dojox/storage/tests/resources/testBook.txt | 7104 ++++++++++++++++++++ .../js/dojox/storage/tests/resources/testXML.xml | 203 + includes/js/dojox/storage/tests/test_storage.html | 189 + includes/js/dojox/storage/tests/test_storage.js | 493 ++ includes/js/dojox/string/Builder.js | 101 + includes/js/dojox/string/README | 39 + includes/js/dojox/string/sprintf.js | 406 ++ includes/js/dojox/string/tests/Builder.js | 91 + includes/js/dojox/string/tests/BuilderPerf.html | 403 ++ includes/js/dojox/string/tests/PerfFun.html | 260 + includes/js/dojox/string/tests/lipsum.js | 133 + includes/js/dojox/string/tests/notes.txt | 153 + includes/js/dojox/string/tests/peller.html | 78 + includes/js/dojox/string/tests/runTests.html | 9 + includes/js/dojox/string/tests/sprintf.js | 277 + includes/js/dojox/string/tests/string.js | 10 + includes/js/dojox/string/tokenize.js | 42 + includes/js/dojox/timing.js | 6 + includes/js/dojox/timing/README | 58 + includes/js/dojox/timing/Sequence.js | 145 + includes/js/dojox/timing/Streamer.js | 94 + includes/js/dojox/timing/ThreadPool.js | 157 + includes/js/dojox/timing/_base.js | 58 + includes/js/dojox/timing/tests/test_Sequence.html | 80 + .../js/dojox/timing/tests/test_ThreadPool.html | 16 + includes/js/dojox/uuid.js | 6 + includes/js/dojox/uuid/README | 43 + includes/js/dojox/uuid/Uuid.js | 200 + includes/js/dojox/uuid/_base.js | 245 + includes/js/dojox/uuid/generateRandomUuid.js | 56 + includes/js/dojox/uuid/generateTimeBasedUuid.js | 290 + includes/js/dojox/uuid/tests/runTests.html | 10 + includes/js/dojox/uuid/tests/uuid.js | 377 ++ includes/js/dojox/validate.js | 6 + includes/js/dojox/validate/README | 37 + includes/js/dojox/validate/_base.js | 183 + includes/js/dojox/validate/ca.js | 44 + includes/js/dojox/validate/check.js | 261 + includes/js/dojox/validate/creditCard.js | 92 + includes/js/dojox/validate/isbn.js | 37 + includes/js/dojox/validate/regexp.js | 331 + includes/js/dojox/validate/tests/creditcard.js | 119 + includes/js/dojox/validate/tests/module.js | 14 + includes/js/dojox/validate/tests/runTests.html | 9 + includes/js/dojox/validate/tests/validate.js | 316 + includes/js/dojox/validate/us.js | 67 + includes/js/dojox/validate/web.js | 89 + includes/js/dojox/widget/ColorPicker.js | 284 + .../js/dojox/widget/ColorPicker/ColorPicker.css | 78 + .../ColorPicker/ColorPicker.css.commented.css | 89 + .../js/dojox/widget/ColorPicker/ColorPicker.html | 31 + .../js/dojox/widget/ColorPicker/images/hue.png | Bin 0 -> 1991 bytes .../dojox/widget/ColorPicker/images/hueHandle.png | Bin 0 -> 280 bytes .../widget/ColorPicker/images/pickerPointer.png | Bin 0 -> 228 bytes .../dojox/widget/ColorPicker/images/underlay.png | Bin 0 -> 10788 bytes includes/js/dojox/widget/FileInput.js | 75 + includes/js/dojox/widget/FileInput/FileInput.css | 70 + .../widget/FileInput/FileInput.css.commented.css | 79 + includes/js/dojox/widget/FileInput/FileInput.html | 9 + .../js/dojox/widget/FileInput/FileInputAuto.html | 9 + includes/js/dojox/widget/FileInput/ReceiveFile.php | 37 + includes/js/dojox/widget/FileInputAuto.js | 185 + includes/js/dojox/widget/FisheyeList.js | 708 ++ .../js/dojox/widget/FisheyeList/FisheyeList.css | 24 + .../FisheyeList/FisheyeList.css.commented.css | 28 + includes/js/dojox/widget/FisheyeLite.js | 135 + includes/js/dojox/widget/Iterator.js | 177 + includes/js/dojox/widget/Loader.js | 103 + includes/js/dojox/widget/Loader/Loader.css | 24 + .../dojox/widget/Loader/Loader.css.commented.css | 27 + includes/js/dojox/widget/Loader/README | 39 + includes/js/dojox/widget/Loader/honey.php | 27 + includes/js/dojox/widget/Loader/icons/loading.gif | Bin 0 -> 751 bytes includes/js/dojox/widget/MultiComboBox.js | 61 + includes/js/dojox/widget/README | 84 + includes/js/dojox/widget/Rating.js | 90 + includes/js/dojox/widget/Rating/Rating.css | 20 + .../dojox/widget/Rating/Rating.css.commented.css | 24 + includes/js/dojox/widget/Rating/rating_empty.gif | Bin 0 -> 934 bytes includes/js/dojox/widget/Rating/rating_empty.png | Bin 0 -> 482 bytes includes/js/dojox/widget/Rating/rating_full.gif | Bin 0 -> 936 bytes includes/js/dojox/widget/Rating/rating_full.png | Bin 0 -> 483 bytes includes/js/dojox/widget/Rating/rating_half.png | Bin 0 -> 541 bytes includes/js/dojox/widget/SortList.js | 151 + includes/js/dojox/widget/SortList/SortList.css | 57 + .../widget/SortList/SortList.css.commented.css | 64 + includes/js/dojox/widget/SortList/SortList.html | 9 + includes/js/dojox/widget/TimeSpinner.js | 48 + includes/js/dojox/widget/Toaster.js | 268 + includes/js/dojox/widget/Toaster/Toaster.css | 39 + .../dojox/widget/Toaster/Toaster.css.commented.css | 47 + includes/js/dojox/widget/Wizard.js | 192 + includes/js/dojox/widget/Wizard/Wizard.css | 19 + .../dojox/widget/Wizard/Wizard.css.commented.css | 22 + includes/js/dojox/widget/Wizard/Wizard.html | 9 + includes/js/dojox/widget/nls/Wizard.js | 1 + includes/js/dojox/widget/nls/ar/Wizard.js | 1 + includes/js/dojox/widget/nls/cs/Wizard.js | 1 + includes/js/dojox/widget/nls/da/Wizard.js | 1 + includes/js/dojox/widget/nls/de/Wizard.js | 1 + includes/js/dojox/widget/nls/el/Wizard.js | 1 + includes/js/dojox/widget/nls/es/Wizard.js | 1 + includes/js/dojox/widget/nls/fi/Wizard.js | 1 + includes/js/dojox/widget/nls/fr/Wizard.js | 1 + includes/js/dojox/widget/nls/he/Wizard.js | 1 + includes/js/dojox/widget/nls/hu/Wizard.js | 1 + includes/js/dojox/widget/nls/it/Wizard.js | 1 + includes/js/dojox/widget/nls/ja/Wizard.js | 1 + includes/js/dojox/widget/nls/ko/Wizard.js | 1 + includes/js/dojox/widget/nls/nb/Wizard.js | 1 + includes/js/dojox/widget/nls/nl/Wizard.js | 1 + includes/js/dojox/widget/nls/pl/Wizard.js | 1 + includes/js/dojox/widget/nls/pt-pt/Wizard.js | 1 + includes/js/dojox/widget/nls/pt/Wizard.js | 1 + includes/js/dojox/widget/nls/ru/Wizard.js | 1 + includes/js/dojox/widget/nls/sv/Wizard.js | 1 + includes/js/dojox/widget/nls/tr/Wizard.js | 1 + includes/js/dojox/widget/nls/zh-tw/Wizard.js | 1 + includes/js/dojox/widget/nls/zh/Wizard.js | 1 + includes/js/dojox/widget/tests/_tags.json | 100 + .../dojox/widget/tests/demo_FisheyeList-orig.html | 111 + .../js/dojox/widget/tests/demo_FisheyeList.html | 117 + .../js/dojox/widget/tests/demo_FisheyeLite.html | 175 + .../js/dojox/widget/tests/images/fisheye_1.png | Bin 0 -> 3799 bytes .../js/dojox/widget/tests/images/fisheye_2.png | Bin 0 -> 4479 bytes .../js/dojox/widget/tests/images/fisheye_3.png | Bin 0 -> 4321 bytes .../js/dojox/widget/tests/images/fisheye_4.png | Bin 0 -> 4389 bytes .../js/dojox/widget/tests/images/icon_browser.png | Bin 0 -> 18619 bytes .../js/dojox/widget/tests/images/icon_calendar.png | Bin 0 -> 10822 bytes .../js/dojox/widget/tests/images/icon_email.png | Bin 0 -> 17133 bytes .../dojox/widget/tests/images/icon_texteditor.png | Bin 0 -> 25271 bytes .../js/dojox/widget/tests/images/icon_update.png | Bin 0 -> 21984 bytes .../js/dojox/widget/tests/images/icon_users.png | Bin 0 -> 24802 bytes .../js/dojox/widget/tests/images/rating_empty.gif | Bin 0 -> 1277 bytes .../js/dojox/widget/tests/images/rating_empty.png | Bin 0 -> 2031 bytes .../js/dojox/widget/tests/images/rating_full.gif | Bin 0 -> 1314 bytes .../js/dojox/widget/tests/images/rating_full.png | Bin 0 -> 2241 bytes .../js/dojox/widget/tests/test_ColorPicker.html | 41 + includes/js/dojox/widget/tests/test_FileInput.html | 115 + .../js/dojox/widget/tests/test_FisheyeList.html | 144 + .../js/dojox/widget/tests/test_FisheyeLite.html | 257 + includes/js/dojox/widget/tests/test_Iterator.html | 73 + includes/js/dojox/widget/tests/test_Loader.html | 81 + .../js/dojox/widget/tests/test_MultiComboBox.html | 70 + includes/js/dojox/widget/tests/test_Rating.html | 91 + includes/js/dojox/widget/tests/test_SortList.html | 74 + .../js/dojox/widget/tests/test_TimeSpinner.html | 87 + includes/js/dojox/widget/tests/test_Toaster.html | 147 + includes/js/dojox/widget/tests/test_Wizard.html | 118 + includes/js/dojox/wire.js | 7 + includes/js/dojox/wire/CompositeWire.js | 103 + includes/js/dojox/wire/DataWire.js | 179 + includes/js/dojox/wire/README | 53 + includes/js/dojox/wire/TableAdapter.js | 88 + includes/js/dojox/wire/TextAdapter.js | 88 + includes/js/dojox/wire/TreeAdapter.js | 188 + includes/js/dojox/wire/Wire.js | 336 + includes/js/dojox/wire/XmlWire.js | 244 + includes/js/dojox/wire/_base.js | 195 + includes/js/dojox/wire/demos/TableContainer.css | 25 + .../wire/demos/TableContainer.css.commented.css | 30 + includes/js/dojox/wire/demos/TableContainer.js | 68 + includes/js/dojox/wire/demos/WidgetRepeater.js | 33 + includes/js/dojox/wire/demos/markup/countries.json | 43 + .../wire/demos/markup/demo_ActionChaining.html | 108 + .../dojox/wire/demos/markup/demo_ActionWiring.html | 142 + .../wire/demos/markup/demo_BasicChildWire.html | 78 + .../wire/demos/markup/demo_BasicColumnWiring.html | 90 + .../wire/demos/markup/demo_ConditionalActions.html | 221 + .../wire/demos/markup/demo_FlickrStoreWire.html | 281 + .../dojox/wire/demos/markup/demo_TopicWiring.html | 78 + includes/js/dojox/wire/demos/markup/flickrDemo.css | 29 + .../wire/demos/markup/flickrDemo.css.commented.css | 35 + includes/js/dojox/wire/demos/markup/states.json | 56 + includes/js/dojox/wire/ml/Action.js | 225 + includes/js/dojox/wire/ml/Data.js | 143 + includes/js/dojox/wire/ml/DataStore.js | 116 + includes/js/dojox/wire/ml/Invocation.js | 171 + includes/js/dojox/wire/ml/Service.js | 340 + includes/js/dojox/wire/ml/Transfer.js | 359 + includes/js/dojox/wire/ml/util.js | 295 + includes/js/dojox/wire/tests/markup/Action.html | 147 + includes/js/dojox/wire/tests/markup/Data.html | 105 + includes/js/dojox/wire/tests/markup/DataStore.html | 66 + includes/js/dojox/wire/tests/markup/DataStore.xml | 18 + .../js/dojox/wire/tests/markup/Invocation.html | 53 + includes/js/dojox/wire/tests/markup/Service.html | 84 + .../js/dojox/wire/tests/markup/Service/JSON.smd | 11 + .../js/dojox/wire/tests/markup/Service/XML.smd | 11 + includes/js/dojox/wire/tests/markup/Service/a.json | 5 + includes/js/dojox/wire/tests/markup/Service/a.xml | 5 + includes/js/dojox/wire/tests/markup/Transfer.html | 157 + includes/js/dojox/wire/tests/module.js | 13 + .../dojox/wire/tests/programmatic/CompositeWire.js | 51 + .../wire/tests/programmatic/ConverterDynamic.js | 12 + .../js/dojox/wire/tests/programmatic/DataWire.js | 25 + .../dojox/wire/tests/programmatic/TableAdapter.js | 24 + .../dojox/wire/tests/programmatic/TextAdapter.js | 25 + .../dojox/wire/tests/programmatic/TreeAdapter.js | 29 + includes/js/dojox/wire/tests/programmatic/Wire.js | 123 + .../js/dojox/wire/tests/programmatic/XmlWire.js | 32 + includes/js/dojox/wire/tests/programmatic/_base.js | 111 + includes/js/dojox/wire/tests/runTests.html | 9 + includes/js/dojox/wire/tests/wire.js | 18 + includes/js/dojox/wire/tests/wireml.js | 18 + includes/js/dojox/xml/DomParser.js | 379 ++ includes/js/dojox/xml/README | 40 + 1104 files changed, 154526 insertions(+) create mode 100644 includes/js/dojox/LICENSE create mode 100644 includes/js/dojox/_sql/LICENSE create mode 100644 includes/js/dojox/_sql/_crypto.js create mode 100644 includes/js/dojox/_sql/common.js create mode 100644 includes/js/dojox/_sql/demos/customers/customers.html create mode 100644 includes/js/dojox/analytics.js create mode 100644 includes/js/dojox/analytics/README create mode 100644 includes/js/dojox/analytics/_base.js create mode 100644 includes/js/dojox/analytics/logger/JSON.php create mode 100644 includes/js/dojox/analytics/logger/dojoxAnalytics.php create mode 100644 includes/js/dojox/analytics/plugins/consoleMessages.js create mode 100644 includes/js/dojox/analytics/plugins/dojo.js create mode 100644 includes/js/dojox/analytics/plugins/idle.js create mode 100644 includes/js/dojox/analytics/plugins/mouseClick.js create mode 100644 includes/js/dojox/analytics/plugins/mouseOver.js create mode 100644 includes/js/dojox/analytics/plugins/window.js create mode 100644 includes/js/dojox/analytics/profiles/analytics.profile.js create mode 100644 includes/js/dojox/analytics/profiles/analyticsInBase.profile.js create mode 100644 includes/js/dojox/analytics/tests/test_analytics.html create mode 100644 includes/js/dojox/av.js create mode 100644 includes/js/dojox/av/README create mode 100644 includes/js/dojox/av/_base.js create mode 100644 includes/js/dojox/av/_base/_ieFlash.js create mode 100644 includes/js/dojox/av/_base/flash.js create mode 100644 includes/js/dojox/av/_base/quicktime.js create mode 100644 includes/js/dojox/av/resources/version.mov create mode 100644 includes/js/dojox/av/tests/flash.html create mode 100644 includes/js/dojox/av/tests/quicktime.html create mode 100644 includes/js/dojox/av/tests/resources/hfp.swf create mode 100644 includes/js/dojox/charting/Chart2D.js create mode 100644 includes/js/dojox/charting/Chart3D.js create mode 100644 includes/js/dojox/charting/Element.js create mode 100644 includes/js/dojox/charting/README create mode 100644 includes/js/dojox/charting/Series.js create mode 100644 includes/js/dojox/charting/Theme.js create mode 100644 includes/js/dojox/charting/_color.js create mode 100644 includes/js/dojox/charting/axis2d/Base.js create mode 100644 includes/js/dojox/charting/axis2d/Default.js create mode 100644 includes/js/dojox/charting/axis2d/common.js create mode 100644 includes/js/dojox/charting/plot2d/Areas.js create mode 100644 includes/js/dojox/charting/plot2d/Bars.js create mode 100644 includes/js/dojox/charting/plot2d/Base.js create mode 100644 includes/js/dojox/charting/plot2d/ClusteredBars.js create mode 100644 includes/js/dojox/charting/plot2d/ClusteredColumns.js create mode 100644 includes/js/dojox/charting/plot2d/Columns.js create mode 100644 includes/js/dojox/charting/plot2d/Default.js create mode 100644 includes/js/dojox/charting/plot2d/Grid.js create mode 100644 includes/js/dojox/charting/plot2d/Lines.js create mode 100644 includes/js/dojox/charting/plot2d/Markers.js create mode 100644 includes/js/dojox/charting/plot2d/MarkersOnly.js create mode 100644 includes/js/dojox/charting/plot2d/Pie.js create mode 100644 includes/js/dojox/charting/plot2d/Scatter.js create mode 100644 includes/js/dojox/charting/plot2d/Stacked.js create mode 100644 includes/js/dojox/charting/plot2d/StackedAreas.js create mode 100644 includes/js/dojox/charting/plot2d/StackedBars.js create mode 100644 includes/js/dojox/charting/plot2d/StackedColumns.js create mode 100644 includes/js/dojox/charting/plot2d/StackedLines.js create mode 100644 includes/js/dojox/charting/plot2d/common.js create mode 100644 includes/js/dojox/charting/plot3d/Bars.js create mode 100644 includes/js/dojox/charting/plot3d/Base.js create mode 100644 includes/js/dojox/charting/plot3d/Cylinders.js create mode 100644 includes/js/dojox/charting/scaler.js create mode 100644 includes/js/dojox/charting/tests/Theme.js create mode 100644 includes/js/dojox/charting/tests/_color.js create mode 100644 includes/js/dojox/charting/tests/charting.js create mode 100644 includes/js/dojox/charting/tests/data/goog_prices.csv create mode 100644 includes/js/dojox/charting/tests/data/msft_prices.csv create mode 100644 includes/js/dojox/charting/tests/data/yahoo_prices.csv create mode 100644 includes/js/dojox/charting/tests/runTests.html create mode 100644 includes/js/dojox/charting/tests/test_bars.html create mode 100644 includes/js/dojox/charting/tests/test_chart2d.html create mode 100644 includes/js/dojox/charting/tests/test_chart2d_updating.html create mode 100644 includes/js/dojox/charting/tests/test_cylinders.html create mode 100644 includes/js/dojox/charting/tests/test_labels2d.html create mode 100644 includes/js/dojox/charting/tests/test_pie2d.html create mode 100644 includes/js/dojox/charting/tests/test_scaler.html create mode 100644 includes/js/dojox/charting/tests/test_sparklines.html create mode 100644 includes/js/dojox/charting/tests/test_widget2d.html create mode 100644 includes/js/dojox/charting/themes/ET/greys.js create mode 100644 includes/js/dojox/charting/themes/GreySkies.js create mode 100644 includes/js/dojox/charting/themes/PlotKit/README create mode 100644 includes/js/dojox/charting/themes/PlotKit/blue.js create mode 100644 includes/js/dojox/charting/themes/PlotKit/cyan.js create mode 100644 includes/js/dojox/charting/themes/PlotKit/green.js create mode 100644 includes/js/dojox/charting/themes/PlotKit/orange.js create mode 100644 includes/js/dojox/charting/themes/PlotKit/purple.js create mode 100644 includes/js/dojox/charting/themes/PlotKit/red.js create mode 100644 includes/js/dojox/charting/widget/Chart2D.js create mode 100644 includes/js/dojox/collections.js create mode 100644 includes/js/dojox/collections/ArrayList.js create mode 100644 includes/js/dojox/collections/BinaryTree.js create mode 100644 includes/js/dojox/collections/Dictionary.js create mode 100644 includes/js/dojox/collections/Queue.js create mode 100644 includes/js/dojox/collections/README create mode 100644 includes/js/dojox/collections/Set.js create mode 100644 includes/js/dojox/collections/SortedList.js create mode 100644 includes/js/dojox/collections/Stack.js create mode 100644 includes/js/dojox/collections/_base.js create mode 100644 includes/js/dojox/collections/tests/ArrayList.js create mode 100644 includes/js/dojox/collections/tests/BinaryTree.js create mode 100644 includes/js/dojox/collections/tests/Dictionary.js create mode 100644 includes/js/dojox/collections/tests/Queue.js create mode 100644 includes/js/dojox/collections/tests/Set.js create mode 100644 includes/js/dojox/collections/tests/SortedList.js create mode 100644 includes/js/dojox/collections/tests/Stack.js create mode 100644 includes/js/dojox/collections/tests/_base.js create mode 100644 includes/js/dojox/collections/tests/collections.js create mode 100644 includes/js/dojox/collections/tests/runTests.html create mode 100644 includes/js/dojox/color.js create mode 100644 includes/js/dojox/color/Colorspace.js create mode 100644 includes/js/dojox/color/Generator.js create mode 100644 includes/js/dojox/color/README create mode 100644 includes/js/dojox/color/_base.js create mode 100644 includes/js/dojox/color/tests/Generator.js create mode 100644 includes/js/dojox/color/tests/_base.js create mode 100644 includes/js/dojox/color/tests/color.js create mode 100644 includes/js/dojox/color/tests/runTests.html create mode 100644 includes/js/dojox/cometd.js create mode 100644 includes/js/dojox/cometd/README create mode 100644 includes/js/dojox/cometd/_base.js create mode 100644 includes/js/dojox/cometd/timestamp.js create mode 100644 includes/js/dojox/cometd/timesync.js create mode 100644 includes/js/dojox/crypto.js create mode 100644 includes/js/dojox/crypto/Blowfish.js create mode 100644 includes/js/dojox/crypto/MD5.js create mode 100644 includes/js/dojox/crypto/README create mode 100644 includes/js/dojox/crypto/_base.js create mode 100644 includes/js/dojox/data/AtomReadStore.js create mode 100644 includes/js/dojox/data/CsvStore.js create mode 100644 includes/js/dojox/data/FlickrRestStore.js create mode 100644 includes/js/dojox/data/FlickrStore.js create mode 100644 includes/js/dojox/data/HtmlStore.js create mode 100644 includes/js/dojox/data/HtmlTableStore.js create mode 100644 includes/js/dojox/data/KeyValueStore.js create mode 100644 includes/js/dojox/data/OpmlStore.js create mode 100644 includes/js/dojox/data/PicasaStore.js create mode 100644 includes/js/dojox/data/QueryReadStore.js create mode 100644 includes/js/dojox/data/README create mode 100644 includes/js/dojox/data/SnapLogicStore.js create mode 100644 includes/js/dojox/data/XmlStore.js create mode 100644 includes/js/dojox/data/demos/demo_DataDemoTable.html create mode 100644 includes/js/dojox/data/demos/demo_FlickrRestStore.html create mode 100644 includes/js/dojox/data/demos/demo_FlickrStore.html create mode 100644 includes/js/dojox/data/demos/demo_LazyLoad.html create mode 100644 includes/js/dojox/data/demos/demo_MultiStores.html create mode 100644 includes/js/dojox/data/demos/demo_PicasaStore.html create mode 100644 includes/js/dojox/data/demos/demo_QueryReadStore_ComboBox.html create mode 100644 includes/js/dojox/data/demos/demo_QueryReadStore_FilteringSelect.html create mode 100644 includes/js/dojox/data/demos/demo_QueryReadStore_grid.html create mode 100644 includes/js/dojox/data/demos/flickrDemo.css create mode 100644 includes/js/dojox/data/demos/flickrDemo.css.commented.css create mode 100644 includes/js/dojox/data/demos/geography.json create mode 100644 includes/js/dojox/data/demos/geography.xml create mode 100644 includes/js/dojox/data/demos/geography/Argentina/data.json create mode 100644 includes/js/dojox/data/demos/geography/Brazil/data.json create mode 100644 includes/js/dojox/data/demos/geography/Canada/Ottawa/data.json create mode 100644 includes/js/dojox/data/demos/geography/Canada/Toronto/data.json create mode 100644 includes/js/dojox/data/demos/geography/Canada/data.json create mode 100644 includes/js/dojox/data/demos/geography/China/data.json create mode 100644 includes/js/dojox/data/demos/geography/Commonwealth of Australia/data.json create mode 100644 includes/js/dojox/data/demos/geography/Egypt/data.json create mode 100644 includes/js/dojox/data/demos/geography/France/data.json create mode 100644 includes/js/dojox/data/demos/geography/Germany/data.json create mode 100644 includes/js/dojox/data/demos/geography/India/data.json create mode 100644 includes/js/dojox/data/demos/geography/Italy/data.json create mode 100644 includes/js/dojox/data/demos/geography/Kenya/Mombasa/data.json create mode 100644 includes/js/dojox/data/demos/geography/Kenya/Nairobi/data.json create mode 100644 includes/js/dojox/data/demos/geography/Kenya/data.json create mode 100644 includes/js/dojox/data/demos/geography/Mexico/Guadalajara/data.json create mode 100644 includes/js/dojox/data/demos/geography/Mexico/Mexico City/data.json create mode 100644 includes/js/dojox/data/demos/geography/Mexico/data.json create mode 100644 includes/js/dojox/data/demos/geography/Mongolia/data.json create mode 100644 includes/js/dojox/data/demos/geography/Russia/data.json create mode 100644 includes/js/dojox/data/demos/geography/Spain/data.json create mode 100644 includes/js/dojox/data/demos/geography/Sudan/Khartoum/data.json create mode 100644 includes/js/dojox/data/demos/geography/Sudan/data.json create mode 100644 includes/js/dojox/data/demos/geography/United States of America/data.json create mode 100644 includes/js/dojox/data/demos/geography/root.json create mode 100644 includes/js/dojox/data/demos/picasaDemo.css create mode 100644 includes/js/dojox/data/demos/picasaDemo.css.commented.css create mode 100644 includes/js/dojox/data/demos/stores/LazyLoadJSIStore.js create mode 100644 includes/js/dojox/data/demos/widgets/FlickrView.js create mode 100644 includes/js/dojox/data/demos/widgets/FlickrViewList.js create mode 100644 includes/js/dojox/data/demos/widgets/PicasaView.js create mode 100644 includes/js/dojox/data/demos/widgets/PicasaViewList.js create mode 100644 includes/js/dojox/data/demos/widgets/templates/FlickrView.html create mode 100644 includes/js/dojox/data/demos/widgets/templates/FlickrViewList.html create mode 100644 includes/js/dojox/data/demos/widgets/templates/PicasaView.html create mode 100644 includes/js/dojox/data/demos/widgets/templates/PicasaViewList.html create mode 100644 includes/js/dojox/data/dom.js create mode 100644 includes/js/dojox/data/jsonPathStore.js create mode 100644 includes/js/dojox/data/tests/QueryReadStore.html create mode 100644 includes/js/dojox/data/tests/dom.js create mode 100644 includes/js/dojox/data/tests/ml/divList.html create mode 100644 includes/js/dojox/data/tests/ml/orderedList.html create mode 100644 includes/js/dojox/data/tests/ml/table.html create mode 100644 includes/js/dojox/data/tests/ml/test_HtmlStore_declaratively.html create mode 100644 includes/js/dojox/data/tests/ml/test_HtmlStore_remote.html create mode 100644 includes/js/dojox/data/tests/ml/test_HtmlTableStore_declaratively.html create mode 100644 includes/js/dojox/data/tests/ml/unorderedList.html create mode 100644 includes/js/dojox/data/tests/module.js create mode 100644 includes/js/dojox/data/tests/runTests.html create mode 100644 includes/js/dojox/data/tests/stores/AtomReadStore.js create mode 100644 includes/js/dojox/data/tests/stores/CsvStore.js create mode 100644 includes/js/dojox/data/tests/stores/FlickrRestStore.js create mode 100644 includes/js/dojox/data/tests/stores/FlickrStore.js create mode 100644 includes/js/dojox/data/tests/stores/HtmlStore.js create mode 100644 includes/js/dojox/data/tests/stores/HtmlTableStore.js create mode 100644 includes/js/dojox/data/tests/stores/KeyValueStore.js create mode 100644 includes/js/dojox/data/tests/stores/OpmlStore.js create mode 100644 includes/js/dojox/data/tests/stores/QueryReadStore.js create mode 100644 includes/js/dojox/data/tests/stores/QueryReadStore.php create mode 100644 includes/js/dojox/data/tests/stores/SnapLogicStore.js create mode 100644 includes/js/dojox/data/tests/stores/XmlStore.js create mode 100644 includes/js/dojox/data/tests/stores/atom1.xml create mode 100644 includes/js/dojox/data/tests/stores/books.html create mode 100644 includes/js/dojox/data/tests/stores/books.xml create mode 100644 includes/js/dojox/data/tests/stores/books2.html create mode 100644 includes/js/dojox/data/tests/stores/books2.xml create mode 100644 includes/js/dojox/data/tests/stores/books3.html create mode 100644 includes/js/dojox/data/tests/stores/books3.xml create mode 100644 includes/js/dojox/data/tests/stores/books_isbnAttr.xml create mode 100644 includes/js/dojox/data/tests/stores/books_isbnAttr2.xml create mode 100644 includes/js/dojox/data/tests/stores/geography.xml create mode 100644 includes/js/dojox/data/tests/stores/geography_withspeciallabel.xml create mode 100644 includes/js/dojox/data/tests/stores/jsonPathStore.js create mode 100644 includes/js/dojox/data/tests/stores/movies.csv create mode 100644 includes/js/dojox/data/tests/stores/movies2.csv create mode 100644 includes/js/dojox/data/tests/stores/patterns.csv create mode 100644 includes/js/dojox/data/tests/stores/properties.js create mode 100644 includes/js/dojox/data/tests/stores/snap_pipeline.php create mode 100644 includes/js/dojox/data/tests/test_Tree_vs_jsonPathStore.html create mode 100644 includes/js/dojox/data/tests/treeTest.json create mode 100644 includes/js/dojox/date/README create mode 100644 includes/js/dojox/date/php.js create mode 100644 includes/js/dojox/date/posix.js create mode 100644 includes/js/dojox/date/tests/module.js create mode 100644 includes/js/dojox/date/tests/posix.js create mode 100644 includes/js/dojox/date/tests/runTests.html create mode 100644 includes/js/dojox/dtl.js create mode 100644 includes/js/dojox/dtl/Context.js create mode 100644 includes/js/dojox/dtl/README create mode 100644 includes/js/dojox/dtl/_HtmlTemplated.js create mode 100644 includes/js/dojox/dtl/_Templated.js create mode 100644 includes/js/dojox/dtl/_base.js create mode 100644 includes/js/dojox/dtl/contrib/data.js create mode 100644 includes/js/dojox/dtl/contrib/dijit.js create mode 100644 includes/js/dojox/dtl/contrib/html.js create mode 100644 includes/js/dojox/dtl/contrib/objects.js create mode 100644 includes/js/dojox/dtl/demos/demo_Animation.html create mode 100644 includes/js/dojox/dtl/demos/demo_Blog.html create mode 100644 includes/js/dojox/dtl/demos/demo_Data.html create mode 100644 includes/js/dojox/dtl/demos/demo_Dijitless.html create mode 100644 includes/js/dojox/dtl/demos/demo_Events.html create mode 100644 includes/js/dojox/dtl/demos/demo_HtmlTemplated.html create mode 100644 includes/js/dojox/dtl/demos/demo_Inline.html create mode 100644 includes/js/dojox/dtl/demos/demo_NodeList.html create mode 100644 includes/js/dojox/dtl/demos/demo_Table.html create mode 100644 includes/js/dojox/dtl/demos/demo_Templated.html create mode 100644 includes/js/dojox/dtl/demos/demo_Tree.html create mode 100644 includes/js/dojox/dtl/demos/json/blog/get_blog_1.json create mode 100644 includes/js/dojox/dtl/demos/json/blog/get_blog_3.json create mode 100644 includes/js/dojox/dtl/demos/json/blog/get_blog_list.json create mode 100644 includes/js/dojox/dtl/demos/json/blog/get_page_about.json create mode 100644 includes/js/dojox/dtl/demos/json/fruit.json create mode 100644 includes/js/dojox/dtl/demos/json/morefruit.json create mode 100644 includes/js/dojox/dtl/demos/templates/animation.html create mode 100644 includes/js/dojox/dtl/demos/templates/blog_base.html create mode 100644 includes/js/dojox/dtl/demos/templates/blog_detail.html create mode 100644 includes/js/dojox/dtl/demos/templates/blog_list.html create mode 100644 includes/js/dojox/dtl/demos/templates/blog_page.html create mode 100644 includes/js/dojox/dtl/demos/templates/countrychildren.html create mode 100644 includes/js/dojox/dtl/demos/templates/gallery.html create mode 100644 includes/js/dojox/dtl/demos/templates/nodelist.html create mode 100644 includes/js/dojox/dtl/ext-dojo/NodeList.js create mode 100644 includes/js/dojox/dtl/filter/dates.js create mode 100644 includes/js/dojox/dtl/filter/htmlstrings.js create mode 100644 includes/js/dojox/dtl/filter/integers.js create mode 100644 includes/js/dojox/dtl/filter/lists.js create mode 100644 includes/js/dojox/dtl/filter/logic.js create mode 100644 includes/js/dojox/dtl/filter/misc.js create mode 100644 includes/js/dojox/dtl/filter/strings.js create mode 100644 includes/js/dojox/dtl/html.js create mode 100644 includes/js/dojox/dtl/render/html.js create mode 100644 includes/js/dojox/dtl/tag/date.js create mode 100644 includes/js/dojox/dtl/tag/loader.js create mode 100644 includes/js/dojox/dtl/tag/logic.js create mode 100644 includes/js/dojox/dtl/tag/loop.js create mode 100644 includes/js/dojox/dtl/tag/misc.js create mode 100644 includes/js/dojox/dtl/tests/context.js create mode 100644 includes/js/dojox/dtl/tests/demo_Templated_Jaxer.html create mode 100644 includes/js/dojox/dtl/tests/html/buffer.js create mode 100644 includes/js/dojox/dtl/tests/html/tag.js create mode 100644 includes/js/dojox/dtl/tests/html/util.js create mode 100644 includes/js/dojox/dtl/tests/module.js create mode 100644 includes/js/dojox/dtl/tests/runTests.html create mode 100644 includes/js/dojox/dtl/tests/templates/hello.html create mode 100644 includes/js/dojox/dtl/tests/templates/pocket.html create mode 100644 includes/js/dojox/dtl/tests/templates/pocket2.html create mode 100644 includes/js/dojox/dtl/tests/text/filter.js create mode 100644 includes/js/dojox/dtl/tests/text/load.js create mode 100644 includes/js/dojox/dtl/tests/text/tag.js create mode 100644 includes/js/dojox/dtl/utils/date.js create mode 100644 includes/js/dojox/encoding/LICENSE create mode 100644 includes/js/dojox/encoding/README create mode 100644 includes/js/dojox/encoding/_base.js create mode 100644 includes/js/dojox/encoding/ascii85.js create mode 100644 includes/js/dojox/encoding/base64.js create mode 100644 includes/js/dojox/encoding/bits.js create mode 100644 includes/js/dojox/encoding/compression/lzw.js create mode 100644 includes/js/dojox/encoding/compression/splay.js create mode 100644 includes/js/dojox/encoding/crypto/Blowfish.js create mode 100644 includes/js/dojox/encoding/crypto/_base.js create mode 100644 includes/js/dojox/encoding/digests/MD5.js create mode 100644 includes/js/dojox/encoding/digests/_base.js create mode 100644 includes/js/dojox/encoding/easy64.js create mode 100644 includes/js/dojox/encoding/tests/ascii85.js create mode 100644 includes/js/dojox/encoding/tests/bits.js create mode 100644 includes/js/dojox/encoding/tests/compression/_base.js create mode 100644 includes/js/dojox/encoding/tests/compression/colors.js create mode 100644 includes/js/dojox/encoding/tests/compression/colors2.html create mode 100644 includes/js/dojox/encoding/tests/compression/colors2.js create mode 100644 includes/js/dojox/encoding/tests/compression/colors3.html create mode 100644 includes/js/dojox/encoding/tests/compression/colors3.js create mode 100644 includes/js/dojox/encoding/tests/compression/lzw.js create mode 100644 includes/js/dojox/encoding/tests/compression/runTests.html create mode 100644 includes/js/dojox/encoding/tests/compression/splay.js create mode 100644 includes/js/dojox/encoding/tests/compression/test.html create mode 100644 includes/js/dojox/encoding/tests/compression/vq.html create mode 100644 includes/js/dojox/encoding/tests/crypto/Blowfish.js create mode 100644 includes/js/dojox/encoding/tests/crypto/_base.js create mode 100644 includes/js/dojox/encoding/tests/crypto/runTests.html create mode 100644 includes/js/dojox/encoding/tests/digests/MD5.js create mode 100644 includes/js/dojox/encoding/tests/digests/_base.js create mode 100644 includes/js/dojox/encoding/tests/digests/runTests.html create mode 100644 includes/js/dojox/encoding/tests/easy64.js create mode 100644 includes/js/dojox/encoding/tests/encoding.js create mode 100644 includes/js/dojox/encoding/tests/runTests.html create mode 100644 includes/js/dojox/flash.js create mode 100644 includes/js/dojox/flash/DojoExternalInterface.as create mode 100644 includes/js/dojox/flash/ExpressInstall.as create mode 100644 includes/js/dojox/flash/README create mode 100644 includes/js/dojox/flash/_base.js create mode 100644 includes/js/dojox/flash/tests/TestFlash.as create mode 100644 includes/js/dojox/flash/tests/TestFlash.swf create mode 100644 includes/js/dojox/flash/tests/buildFlashTest.sh create mode 100644 includes/js/dojox/flash/tests/test_flash.html create mode 100644 includes/js/dojox/flash/tests/test_flash.js create mode 100644 includes/js/dojox/form/CheckedMultiSelect.js create mode 100644 includes/js/dojox/form/DropDownSelect.js create mode 100644 includes/js/dojox/form/PasswordValidator.js create mode 100644 includes/js/dojox/form/README create mode 100644 includes/js/dojox/form/nls/PasswordValidator.js create mode 100644 includes/js/dojox/form/resources/CheckedMultiSelect.css create mode 100644 includes/js/dojox/form/resources/CheckedMultiSelect.css.commented.css create mode 100644 includes/js/dojox/form/resources/CheckedMultiSelect.html create mode 100644 includes/js/dojox/form/resources/DropDownSelect.css create mode 100644 includes/js/dojox/form/resources/DropDownSelect.css.commented.css create mode 100644 includes/js/dojox/form/resources/PasswordValidator.html create mode 100644 includes/js/dojox/form/resources/_CheckedMultiSelectItem.html create mode 100644 includes/js/dojox/form/tests/test_CheckedMultiSelect.html create mode 100644 includes/js/dojox/form/tests/test_DropDownSelect.html create mode 100644 includes/js/dojox/form/tests/test_PasswordValidator.html create mode 100644 includes/js/dojox/fx.js create mode 100644 includes/js/dojox/fx/README create mode 100644 includes/js/dojox/fx/Shadow.js create mode 100644 includes/js/dojox/fx/_arg.js create mode 100644 includes/js/dojox/fx/_base.js create mode 100644 includes/js/dojox/fx/_core.js create mode 100644 includes/js/dojox/fx/easing.js create mode 100644 includes/js/dojox/fx/ext-dojo/NodeList.js create mode 100644 includes/js/dojox/fx/resources/shadowB.png create mode 100644 includes/js/dojox/fx/resources/shadowBL.png create mode 100644 includes/js/dojox/fx/resources/shadowBR.png create mode 100644 includes/js/dojox/fx/resources/shadowL.png create mode 100644 includes/js/dojox/fx/resources/shadowR.png create mode 100644 includes/js/dojox/fx/resources/shadowT.png create mode 100644 includes/js/dojox/fx/resources/shadowTL.png create mode 100644 includes/js/dojox/fx/resources/shadowTR.png create mode 100644 includes/js/dojox/fx/scroll.js create mode 100644 includes/js/dojox/fx/style.js create mode 100644 includes/js/dojox/fx/tests/_animation.css create mode 100644 includes/js/dojox/fx/tests/_animation.css.commented.css create mode 100644 includes/js/dojox/fx/tests/example_Line.html create mode 100644 includes/js/dojox/fx/tests/example_backgroundPosition.html create mode 100644 includes/js/dojox/fx/tests/example_dojoAnimations.html create mode 100644 includes/js/dojox/fx/tests/example_easingChart2D.html create mode 100644 includes/js/dojox/fx/tests/images/averycutedog.jpg create mode 100644 includes/js/dojox/fx/tests/images/dot.png create mode 100644 includes/js/dojox/fx/tests/images/longBg.png create mode 100644 includes/js/dojox/fx/tests/test_Nodelist-fx.html create mode 100644 includes/js/dojox/fx/tests/test_Shadow.html create mode 100644 includes/js/dojox/fx/tests/test_animateClass.html create mode 100644 includes/js/dojox/fx/tests/test_crossFade.html create mode 100644 includes/js/dojox/fx/tests/test_easing.html create mode 100644 includes/js/dojox/fx/tests/test_highlight.html create mode 100644 includes/js/dojox/fx/tests/test_scroll.html create mode 100644 includes/js/dojox/fx/tests/test_sizeTo.html create mode 100644 includes/js/dojox/fx/tests/test_slideBy.html create mode 100644 includes/js/dojox/fx/tests/test_wipeTo.html create mode 100644 includes/js/dojox/gfx.js create mode 100644 includes/js/dojox/gfx/Moveable.js create mode 100644 includes/js/dojox/gfx/Mover.js create mode 100644 includes/js/dojox/gfx/README create mode 100644 includes/js/dojox/gfx/_base.js create mode 100644 includes/js/dojox/gfx/arc.js create mode 100644 includes/js/dojox/gfx/attach.js create mode 100644 includes/js/dojox/gfx/canvas.js create mode 100644 includes/js/dojox/gfx/canvas_attach.js create mode 100644 includes/js/dojox/gfx/decompose.js create mode 100644 includes/js/dojox/gfx/demos/beautify.html create mode 100644 includes/js/dojox/gfx/demos/butterfly.html create mode 100644 includes/js/dojox/gfx/demos/career_test.html create mode 100644 includes/js/dojox/gfx/demos/circles.html create mode 100644 includes/js/dojox/gfx/demos/clock.html create mode 100644 includes/js/dojox/gfx/demos/clockWidget.html create mode 100644 includes/js/dojox/gfx/demos/clock_black.html create mode 100644 includes/js/dojox/gfx/demos/creator.html create mode 100644 includes/js/dojox/gfx/demos/data/Lars.json create mode 100644 includes/js/dojox/gfx/demos/data/Lars.svg create mode 100644 includes/js/dojox/gfx/demos/data/LarsDreaming.json create mode 100644 includes/js/dojox/gfx/demos/data/LarsDreaming.svg create mode 100644 includes/js/dojox/gfx/demos/data/Nils.json create mode 100644 includes/js/dojox/gfx/demos/data/Nils.svg create mode 100644 includes/js/dojox/gfx/demos/data/buratino-bg.png create mode 100644 includes/js/dojox/gfx/demos/data/buratino-head.png create mode 100644 includes/js/dojox/gfx/demos/data/buratino-left-arm.png create mode 100644 includes/js/dojox/gfx/demos/data/buratino-left-leg.png create mode 100644 includes/js/dojox/gfx/demos/data/buratino-lollipop.png create mode 100644 includes/js/dojox/gfx/demos/data/buratino-nose-large.png create mode 100644 includes/js/dojox/gfx/demos/data/buratino-nose-medium.png create mode 100644 includes/js/dojox/gfx/demos/data/buratino-right-arm.png create mode 100644 includes/js/dojox/gfx/demos/data/buratino-right-leg.png create mode 100644 includes/js/dojox/gfx/demos/data/buratino-torso.png create mode 100644 includes/js/dojox/gfx/demos/data/buratino.jpg create mode 100644 includes/js/dojox/gfx/demos/data/buratino.json create mode 100644 includes/js/dojox/gfx/demos/data/svg2gfx.xsl create mode 100644 includes/js/dojox/gfx/demos/data/transform.json create mode 100644 includes/js/dojox/gfx/demos/images/clock_face.jpg create mode 100644 includes/js/dojox/gfx/demos/images/clock_face_black.jpg create mode 100644 includes/js/dojox/gfx/demos/inspector.html create mode 100644 includes/js/dojox/gfx/demos/lion.html create mode 100644 includes/js/dojox/gfx/demos/roundedPane.html create mode 100644 includes/js/dojox/gfx/demos/tiger.html create mode 100644 includes/js/dojox/gfx/demos/tooltip.html create mode 100644 includes/js/dojox/gfx/fx.js create mode 100644 includes/js/dojox/gfx/matrix.js create mode 100644 includes/js/dojox/gfx/move.js create mode 100644 includes/js/dojox/gfx/path.js create mode 100644 includes/js/dojox/gfx/shape.js create mode 100644 includes/js/dojox/gfx/silverlight.js create mode 100644 includes/js/dojox/gfx/silverlight_attach.js create mode 100644 includes/js/dojox/gfx/svg.js create mode 100644 includes/js/dojox/gfx/svg_attach.js create mode 100644 includes/js/dojox/gfx/tests/decompose.js create mode 100644 includes/js/dojox/gfx/tests/matrix.js create mode 100644 includes/js/dojox/gfx/tests/module.js create mode 100644 includes/js/dojox/gfx/tests/runTests.html create mode 100644 includes/js/dojox/gfx/tests/test_arc.html create mode 100644 includes/js/dojox/gfx/tests/test_bezier.html create mode 100644 includes/js/dojox/gfx/tests/test_decompose.html create mode 100644 includes/js/dojox/gfx/tests/test_fill.html create mode 100644 includes/js/dojox/gfx/tests/test_fx.html create mode 100644 includes/js/dojox/gfx/tests/test_gfx.html create mode 100644 includes/js/dojox/gfx/tests/test_gradient.html create mode 100644 includes/js/dojox/gfx/tests/test_group.html create mode 100644 includes/js/dojox/gfx/tests/test_image1.html create mode 100644 includes/js/dojox/gfx/tests/test_image2.html create mode 100644 includes/js/dojox/gfx/tests/test_linearGradient.html create mode 100644 includes/js/dojox/gfx/tests/test_linestyle.html create mode 100644 includes/js/dojox/gfx/tests/test_pattern.html create mode 100644 includes/js/dojox/gfx/tests/test_poly.html create mode 100644 includes/js/dojox/gfx/tests/test_resize.html create mode 100644 includes/js/dojox/gfx/tests/test_setPath.html create mode 100644 includes/js/dojox/gfx/tests/test_tbbox.html create mode 100644 includes/js/dojox/gfx/tests/test_text.html create mode 100644 includes/js/dojox/gfx/tests/test_textpath.html create mode 100644 includes/js/dojox/gfx/tests/test_transform.html create mode 100644 includes/js/dojox/gfx/utils.js create mode 100644 includes/js/dojox/gfx/vml.js create mode 100644 includes/js/dojox/gfx/vml_attach.js create mode 100644 includes/js/dojox/gfx3d.js create mode 100644 includes/js/dojox/gfx3d/README create mode 100644 includes/js/dojox/gfx3d/_base.js create mode 100644 includes/js/dojox/gfx3d/gradient.js create mode 100644 includes/js/dojox/gfx3d/lighting.js create mode 100644 includes/js/dojox/gfx3d/matrix.js create mode 100644 includes/js/dojox/gfx3d/object.js create mode 100644 includes/js/dojox/gfx3d/scheduler.js create mode 100644 includes/js/dojox/gfx3d/tests/test_camerarotate.html create mode 100644 includes/js/dojox/gfx3d/tests/test_camerarotate_shaded.html create mode 100644 includes/js/dojox/gfx3d/tests/test_cube.html create mode 100644 includes/js/dojox/gfx3d/tests/test_cylinder.html create mode 100644 includes/js/dojox/gfx3d/tests/test_drawer.html create mode 100644 includes/js/dojox/gfx3d/tests/test_edges.html create mode 100644 includes/js/dojox/gfx3d/tests/test_matrix.html create mode 100644 includes/js/dojox/gfx3d/tests/test_orbit.html create mode 100644 includes/js/dojox/gfx3d/tests/test_overlap.html create mode 100644 includes/js/dojox/gfx3d/tests/test_polygon.html create mode 100644 includes/js/dojox/gfx3d/tests/test_quads.html create mode 100644 includes/js/dojox/gfx3d/tests/test_rotate.html create mode 100644 includes/js/dojox/gfx3d/tests/test_scene.html create mode 100644 includes/js/dojox/gfx3d/tests/test_triangles.html create mode 100644 includes/js/dojox/gfx3d/tests/test_vector.html create mode 100644 includes/js/dojox/gfx3d/vector.js create mode 100644 includes/js/dojox/grid/Grid.js create mode 100644 includes/js/dojox/grid/README create mode 100644 includes/js/dojox/grid/VirtualGrid.js create mode 100644 includes/js/dojox/grid/_data/dijitEditors.js create mode 100644 includes/js/dojox/grid/_data/editors.js create mode 100644 includes/js/dojox/grid/_data/fields.js create mode 100644 includes/js/dojox/grid/_data/model.js create mode 100644 includes/js/dojox/grid/_grid/Grid.css create mode 100644 includes/js/dojox/grid/_grid/Grid.css.commented.css create mode 100644 includes/js/dojox/grid/_grid/Grid_rtl.css create mode 100644 includes/js/dojox/grid/_grid/Grid_rtl.css.commented.css create mode 100644 includes/js/dojox/grid/_grid/builder.js create mode 100644 includes/js/dojox/grid/_grid/cell.js create mode 100644 includes/js/dojox/grid/_grid/drag.js create mode 100644 includes/js/dojox/grid/_grid/edit.js create mode 100644 includes/js/dojox/grid/_grid/focus.js create mode 100644 includes/js/dojox/grid/_grid/images/grid_dx_gradient.gif create mode 100644 includes/js/dojox/grid/_grid/images/grid_sort_down.gif create mode 100644 includes/js/dojox/grid/_grid/images/grid_sort_up.gif create mode 100644 includes/js/dojox/grid/_grid/images/tabEnabled_rotated.png create mode 100644 includes/js/dojox/grid/_grid/images/tabHover_rotated.png create mode 100644 includes/js/dojox/grid/_grid/layout.js create mode 100644 includes/js/dojox/grid/_grid/lib.js create mode 100644 includes/js/dojox/grid/_grid/nihiloGrid.css create mode 100644 includes/js/dojox/grid/_grid/nihiloGrid.css.commented.css create mode 100644 includes/js/dojox/grid/_grid/publicEvents.js create mode 100644 includes/js/dojox/grid/_grid/rowbar.js create mode 100644 includes/js/dojox/grid/_grid/rows.js create mode 100644 includes/js/dojox/grid/_grid/scroller.js create mode 100644 includes/js/dojox/grid/_grid/selection.js create mode 100644 includes/js/dojox/grid/_grid/soriaGrid.css create mode 100644 includes/js/dojox/grid/_grid/soriaGrid.css.commented.css create mode 100644 includes/js/dojox/grid/_grid/tundraGrid.css create mode 100644 includes/js/dojox/grid/_grid/tundraGrid.css.commented.css create mode 100644 includes/js/dojox/grid/_grid/view.js create mode 100644 includes/js/dojox/grid/_grid/views.js create mode 100644 includes/js/dojox/grid/resources/GridView.html create mode 100644 includes/js/dojox/grid/resources/VirtualGrid.html create mode 100644 includes/js/dojox/grid/tests/databaseModel.js create mode 100644 includes/js/dojox/grid/tests/images/closed.gif create mode 100644 includes/js/dojox/grid/tests/images/flatScreen.gif create mode 100644 includes/js/dojox/grid/tests/images/open.gif create mode 100644 includes/js/dojox/grid/tests/support/books.xml create mode 100644 includes/js/dojox/grid/tests/support/data.php create mode 100644 includes/js/dojox/grid/tests/support/geography.xml create mode 100644 includes/js/dojox/grid/tests/support/json.php create mode 100644 includes/js/dojox/grid/tests/support/movies.csv create mode 100644 includes/js/dojox/grid/tests/support/test_data.js create mode 100644 includes/js/dojox/grid/tests/support/test_data_objects.js create mode 100644 includes/js/dojox/grid/tests/support/testtbl.sql create mode 100644 includes/js/dojox/grid/tests/support/yahoo_search.js create mode 100644 includes/js/dojox/grid/tests/test_change_structure.html create mode 100644 includes/js/dojox/grid/tests/test_custom_sort.html create mode 100644 includes/js/dojox/grid/tests/test_dojo_data_edit.html create mode 100644 includes/js/dojox/grid/tests/test_dojo_data_empty.html create mode 100644 includes/js/dojox/grid/tests/test_dojo_data_model.html create mode 100644 includes/js/dojox/grid/tests/test_dojo_data_model_EmptyResultSet.html create mode 100644 includes/js/dojox/grid/tests/test_dojo_data_model_multiStores.html create mode 100644 includes/js/dojox/grid/tests/test_dojo_data_model_processError.html create mode 100644 includes/js/dojox/grid/tests/test_dojo_data_notification.html create mode 100644 includes/js/dojox/grid/tests/test_edit.html create mode 100644 includes/js/dojox/grid/tests/test_edit_canEdit.html create mode 100644 includes/js/dojox/grid/tests/test_edit_dijit.html create mode 100644 includes/js/dojox/grid/tests/test_events.html create mode 100644 includes/js/dojox/grid/tests/test_expand.html create mode 100644 includes/js/dojox/grid/tests/test_grid.html create mode 100644 includes/js/dojox/grid/tests/test_grid_dlg.html create mode 100644 includes/js/dojox/grid/tests/test_grid_headerHeight.html create mode 100644 includes/js/dojox/grid/tests/test_grid_layout.html create mode 100644 includes/js/dojox/grid/tests/test_grid_layout_LayoutContainer.html create mode 100644 includes/js/dojox/grid/tests/test_grid_layout_borderContainer.html create mode 100644 includes/js/dojox/grid/tests/test_grid_object_model_change.html create mode 100644 includes/js/dojox/grid/tests/test_grid_programmatic.html create mode 100644 includes/js/dojox/grid/tests/test_grid_programmatic_layout.html create mode 100644 includes/js/dojox/grid/tests/test_grid_rtl.html create mode 100644 includes/js/dojox/grid/tests/test_grid_themes.html create mode 100644 includes/js/dojox/grid/tests/test_grid_tooltip_menu.html create mode 100644 includes/js/dojox/grid/tests/test_keyboard.html create mode 100644 includes/js/dojox/grid/tests/test_markup.html create mode 100644 includes/js/dojox/grid/tests/test_mysql_edit.html create mode 100644 includes/js/dojox/grid/tests/test_sizing.html create mode 100644 includes/js/dojox/grid/tests/test_sizing_100rows.html create mode 100644 includes/js/dojox/grid/tests/test_sizing_ResizeHandle.html create mode 100644 includes/js/dojox/grid/tests/test_styling.html create mode 100644 includes/js/dojox/grid/tests/test_subgrid.html create mode 100644 includes/js/dojox/grid/tests/test_tundra_edit.html create mode 100644 includes/js/dojox/grid/tests/test_yahoo_images.html create mode 100644 includes/js/dojox/grid/tests/test_yahoo_search.html create mode 100644 includes/js/dojox/grid/tests/yahooSearch.js create mode 100644 includes/js/dojox/help/README create mode 100644 includes/js/dojox/help/_base.js create mode 100644 includes/js/dojox/help/console.js create mode 100644 includes/js/dojox/help/demos/demo_Console.html create mode 100644 includes/js/dojox/highlight.js create mode 100644 includes/js/dojox/highlight/README create mode 100644 includes/js/dojox/highlight/_base.js create mode 100644 includes/js/dojox/highlight/languages/_all.js create mode 100644 includes/js/dojox/highlight/languages/_dynamic.js create mode 100644 includes/js/dojox/highlight/languages/_static.js create mode 100644 includes/js/dojox/highlight/languages/_www.js create mode 100644 includes/js/dojox/highlight/languages/cpp.js create mode 100644 includes/js/dojox/highlight/languages/css.js create mode 100644 includes/js/dojox/highlight/languages/delphi.js create mode 100644 includes/js/dojox/highlight/languages/django.js create mode 100644 includes/js/dojox/highlight/languages/html.js create mode 100644 includes/js/dojox/highlight/languages/javascript.js create mode 100644 includes/js/dojox/highlight/languages/pygments/_html.js create mode 100644 includes/js/dojox/highlight/languages/pygments/_www.js create mode 100644 includes/js/dojox/highlight/languages/pygments/css.js create mode 100644 includes/js/dojox/highlight/languages/pygments/html.js create mode 100644 includes/js/dojox/highlight/languages/pygments/javascript.js create mode 100644 includes/js/dojox/highlight/languages/pygments/xml.js create mode 100644 includes/js/dojox/highlight/languages/python.js create mode 100644 includes/js/dojox/highlight/languages/sql.js create mode 100644 includes/js/dojox/highlight/languages/xml.js create mode 100644 includes/js/dojox/highlight/resources/highlight.css create mode 100644 includes/js/dojox/highlight/resources/highlight.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/autumn.css create mode 100644 includes/js/dojox/highlight/resources/pygments/autumn.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/borland.css create mode 100644 includes/js/dojox/highlight/resources/pygments/borland.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/colorful.css create mode 100644 includes/js/dojox/highlight/resources/pygments/colorful.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/default.css create mode 100644 includes/js/dojox/highlight/resources/pygments/default.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/emacs.css create mode 100644 includes/js/dojox/highlight/resources/pygments/emacs.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/friendly.css create mode 100644 includes/js/dojox/highlight/resources/pygments/friendly.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/fruity.css create mode 100644 includes/js/dojox/highlight/resources/pygments/fruity.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/manni.css create mode 100644 includes/js/dojox/highlight/resources/pygments/manni.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/murphy.css create mode 100644 includes/js/dojox/highlight/resources/pygments/murphy.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/native.css create mode 100644 includes/js/dojox/highlight/resources/pygments/native.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/pastie.css create mode 100644 includes/js/dojox/highlight/resources/pygments/pastie.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/perldoc.css create mode 100644 includes/js/dojox/highlight/resources/pygments/perldoc.css.commented.css create mode 100644 includes/js/dojox/highlight/resources/pygments/trac.css create mode 100644 includes/js/dojox/highlight/resources/pygments/trac.css.commented.css create mode 100644 includes/js/dojox/highlight/tests/test_highlight.html create mode 100644 includes/js/dojox/highlight/tests/test_pygments.html create mode 100644 includes/js/dojox/image/Gallery.js create mode 100644 includes/js/dojox/image/Lightbox.js create mode 100644 includes/js/dojox/image/Magnifier.js create mode 100644 includes/js/dojox/image/MagnifierLite.js create mode 100644 includes/js/dojox/image/README create mode 100644 includes/js/dojox/image/SlideShow.js create mode 100644 includes/js/dojox/image/ThumbnailPicker.js create mode 100644 includes/js/dojox/image/resources/Gallery.html create mode 100644 includes/js/dojox/image/resources/Lightbox.html create mode 100644 includes/js/dojox/image/resources/Magnifier.css create mode 100644 includes/js/dojox/image/resources/Magnifier.css.commented.css create mode 100644 includes/js/dojox/image/resources/SlideShow.html create mode 100644 includes/js/dojox/image/resources/ThumbnailPicker.html create mode 100644 includes/js/dojox/image/resources/image.css create mode 100644 includes/js/dojox/image/resources/image.css.commented.css create mode 100644 includes/js/dojox/image/resources/images/buttons.gif create mode 100644 includes/js/dojox/image/resources/images/buttons.png create mode 100644 includes/js/dojox/image/resources/images/close.png create mode 100644 includes/js/dojox/image/resources/images/close_dark.png create mode 100644 includes/js/dojox/image/resources/images/left.png create mode 100644 includes/js/dojox/image/resources/images/loading.gif create mode 100644 includes/js/dojox/image/resources/images/right.png create mode 100644 includes/js/dojox/image/resources/images/warning.png create mode 100644 includes/js/dojox/image/tests/images.json create mode 100644 includes/js/dojox/image/tests/images/extraWide.jpg create mode 100644 includes/js/dojox/image/tests/images/huuuge.png create mode 100644 includes/js/dojox/image/tests/images/imageHoriz.jpg create mode 100644 includes/js/dojox/image/tests/images/imageHoriz2.jpg create mode 100644 includes/js/dojox/image/tests/images/imageVert.jpg create mode 100644 includes/js/dojox/image/tests/images/spanke.jpg create mode 100644 includes/js/dojox/image/tests/images/square.jpg create mode 100644 includes/js/dojox/image/tests/test_Gallery.html create mode 100644 includes/js/dojox/image/tests/test_Lightbox.html create mode 100644 includes/js/dojox/image/tests/test_Magnifier.html create mode 100644 includes/js/dojox/image/tests/test_MagnifierLite.html create mode 100644 includes/js/dojox/image/tests/test_SlideShow.html create mode 100644 includes/js/dojox/image/tests/test_ThumbnailPicker.html create mode 100644 includes/js/dojox/io/README create mode 100644 includes/js/dojox/io/proxy/README create mode 100644 includes/js/dojox/io/proxy/tests/frag.xml create mode 100644 includes/js/dojox/io/proxy/tests/xip.html create mode 100644 includes/js/dojox/io/proxy/xip.js create mode 100644 includes/js/dojox/io/proxy/xip_client.html create mode 100644 includes/js/dojox/io/proxy/xip_server.html create mode 100644 includes/js/dojox/io/xhrMultiPart.js create mode 100644 includes/js/dojox/jsonPath.js create mode 100644 includes/js/dojox/jsonPath/README create mode 100644 includes/js/dojox/jsonPath/query.js create mode 100644 includes/js/dojox/jsonPath/tests/jsonPath.js create mode 100644 includes/js/dojox/jsonPath/tests/module.js create mode 100644 includes/js/dojox/jsonPath/tests/runTests.html create mode 100644 includes/js/dojox/lang/LICENSE create mode 100644 includes/js/dojox/lang/README create mode 100644 includes/js/dojox/lang/functional.js create mode 100644 includes/js/dojox/lang/functional/array.js create mode 100644 includes/js/dojox/lang/functional/curry.js create mode 100644 includes/js/dojox/lang/functional/fold.js create mode 100644 includes/js/dojox/lang/functional/lambda.js create mode 100644 includes/js/dojox/lang/functional/listcomp.js create mode 100644 includes/js/dojox/lang/functional/object.js create mode 100644 includes/js/dojox/lang/functional/reversed.js create mode 100644 includes/js/dojox/lang/functional/scan.js create mode 100644 includes/js/dojox/lang/functional/sequence.js create mode 100644 includes/js/dojox/lang/functional/zip.js create mode 100644 includes/js/dojox/lang/tests/array.js create mode 100644 includes/js/dojox/lang/tests/curry.js create mode 100644 includes/js/dojox/lang/tests/fold.js create mode 100644 includes/js/dojox/lang/tests/fun_perf.html create mode 100644 includes/js/dojox/lang/tests/lambda.js create mode 100644 includes/js/dojox/lang/tests/listcomp.js create mode 100644 includes/js/dojox/lang/tests/main.js create mode 100644 includes/js/dojox/lang/tests/misc.js create mode 100644 includes/js/dojox/lang/tests/runTests.html create mode 100644 includes/js/dojox/lang/utils.js create mode 100644 includes/js/dojox/layout/BorderContainer.js create mode 100644 includes/js/dojox/layout/ContentPane.js create mode 100644 includes/js/dojox/layout/DragPane.js create mode 100644 includes/js/dojox/layout/ExpandoPane.js create mode 100644 includes/js/dojox/layout/FloatingPane.js create mode 100644 includes/js/dojox/layout/README create mode 100644 includes/js/dojox/layout/RadioGroup.js create mode 100644 includes/js/dojox/layout/ResizeHandle.js create mode 100644 includes/js/dojox/layout/ScrollPane.js create mode 100644 includes/js/dojox/layout/resources/ExpandoPane.css create mode 100644 includes/js/dojox/layout/resources/ExpandoPane.css.commented.css create mode 100644 includes/js/dojox/layout/resources/ExpandoPane.html create mode 100644 includes/js/dojox/layout/resources/FloatingPane.css create mode 100644 includes/js/dojox/layout/resources/FloatingPane.css.commented.css create mode 100644 includes/js/dojox/layout/resources/FloatingPane.html create mode 100644 includes/js/dojox/layout/resources/RadioGroup.css create mode 100644 includes/js/dojox/layout/resources/RadioGroup.css.commented.css create mode 100644 includes/js/dojox/layout/resources/ResizeHandle.css create mode 100644 includes/js/dojox/layout/resources/ResizeHandle.css.commented.css create mode 100644 includes/js/dojox/layout/resources/ScrollPane.css create mode 100644 includes/js/dojox/layout/resources/ScrollPane.css.commented.css create mode 100644 includes/js/dojox/layout/resources/ScrollPane.html create mode 100644 includes/js/dojox/layout/resources/icons/resize.png create mode 100644 includes/js/dojox/layout/tests/ContentPane.html create mode 100644 includes/js/dojox/layout/tests/_bottomPane.html create mode 100644 includes/js/dojox/layout/tests/_expando.css create mode 100644 includes/js/dojox/layout/tests/_expando.css.commented.css create mode 100644 includes/js/dojox/layout/tests/_floating.html create mode 100644 includes/js/dojox/layout/tests/_lorem.html create mode 100644 includes/js/dojox/layout/tests/_script.html create mode 100644 includes/js/dojox/layout/tests/doc0.html create mode 100644 includes/js/dojox/layout/tests/images/blank.gif create mode 100644 includes/js/dojox/layout/tests/images/dojoLogo.png create mode 100644 includes/js/dojox/layout/tests/images/gridUnderlay.png create mode 100644 includes/js/dojox/layout/tests/images/testImage.gif create mode 100644 includes/js/dojox/layout/tests/remote/getResponse.php create mode 100644 includes/js/dojox/layout/tests/test_DragPane.html create mode 100644 includes/js/dojox/layout/tests/test_ExpandoPane.html create mode 100644 includes/js/dojox/layout/tests/test_ExpandoPane_code.html create mode 100644 includes/js/dojox/layout/tests/test_ExpandoPane_more.html create mode 100644 includes/js/dojox/layout/tests/test_FloatingPane.html create mode 100644 includes/js/dojox/layout/tests/test_RadioGroup.html create mode 100644 includes/js/dojox/layout/tests/test_ResizeHandle.html create mode 100644 includes/js/dojox/layout/tests/test_ScrollPane.html create mode 100644 includes/js/dojox/layout/tests/test_ScrollPaneSingle.html create mode 100644 includes/js/dojox/layout/tests/test_SizingPane.html create mode 100644 includes/js/dojox/math.js create mode 100644 includes/js/dojox/math/README create mode 100644 includes/js/dojox/math/_base.js create mode 100644 includes/js/dojox/math/curves.js create mode 100644 includes/js/dojox/math/matrix.js create mode 100644 includes/js/dojox/off.js create mode 100644 includes/js/dojox/off/README create mode 100644 includes/js/dojox/off/_common.js create mode 100644 includes/js/dojox/off/docs/bookmarklets.html create mode 100644 includes/js/dojox/off/files.js create mode 100644 includes/js/dojox/off/network_check.txt create mode 100644 includes/js/dojox/off/offline.js create mode 100644 includes/js/dojox/off/offline.js.uncompressed.js create mode 100644 includes/js/dojox/off/resources/checkmark.png create mode 100644 includes/js/dojox/off/resources/greenball.png create mode 100644 includes/js/dojox/off/resources/learnhow.html create mode 100644 includes/js/dojox/off/resources/learnhow.js create mode 100644 includes/js/dojox/off/resources/offline-widget.css create mode 100644 includes/js/dojox/off/resources/offline-widget.css.commented.css create mode 100644 includes/js/dojox/off/resources/offline-widget.html create mode 100644 includes/js/dojox/off/resources/redball.png create mode 100644 includes/js/dojox/off/resources/roller.gif create mode 100644 includes/js/dojox/off/sync.js create mode 100644 includes/js/dojox/off/ui.js create mode 100644 includes/js/dojox/presentation.js create mode 100644 includes/js/dojox/presentation/README create mode 100644 includes/js/dojox/presentation/_base.js create mode 100644 includes/js/dojox/presentation/resources/Show.css create mode 100644 includes/js/dojox/presentation/resources/Show.css.commented.css create mode 100644 includes/js/dojox/presentation/resources/Show.html create mode 100644 includes/js/dojox/presentation/resources/Slide.html create mode 100644 includes/js/dojox/presentation/resources/icons/down.png create mode 100644 includes/js/dojox/presentation/resources/icons/next.png create mode 100644 includes/js/dojox/presentation/resources/icons/prev.png create mode 100644 includes/js/dojox/presentation/resources/icons/up.png create mode 100644 includes/js/dojox/presentation/tests/_ext1.html create mode 100644 includes/js/dojox/presentation/tests/test_presentation.html create mode 100644 includes/js/dojox/resources/README.template create mode 100644 includes/js/dojox/resources/_modules.js create mode 100644 includes/js/dojox/resources/manualTests.html create mode 100644 includes/js/dojox/resources/manualTests.js create mode 100644 includes/js/dojox/rpc/CouchDBRestStore.js create mode 100644 includes/js/dojox/rpc/JsonRPC.js create mode 100644 includes/js/dojox/rpc/JsonReferencing.js create mode 100644 includes/js/dojox/rpc/JsonRestStore.js create mode 100644 includes/js/dojox/rpc/PersevereRestStore.js create mode 100644 includes/js/dojox/rpc/README create mode 100644 includes/js/dojox/rpc/Rest.js create mode 100644 includes/js/dojox/rpc/SMDLibrary/yahoo.smd create mode 100644 includes/js/dojox/rpc/Service.js create mode 100644 includes/js/dojox/rpc/demos/demo_JsonRestStore_CouchDB.html create mode 100644 includes/js/dojox/rpc/demos/demo_JsonRestStore_Persevere.html create mode 100644 includes/js/dojox/rpc/demos/documentation.html create mode 100644 includes/js/dojox/rpc/demos/templates/documentation.html create mode 100644 includes/js/dojox/rpc/demos/templates/yahoo.html create mode 100644 includes/js/dojox/rpc/demos/yahoo.html create mode 100644 includes/js/dojox/rpc/documentation.smd create mode 100644 includes/js/dojox/rpc/test.txt create mode 100644 includes/js/dojox/rpc/tests/JsonReferencing.js create mode 100644 includes/js/dojox/rpc/tests/Service.js create mode 100644 includes/js/dojox/rpc/tests/Yahoo.js create mode 100644 includes/js/dojox/rpc/tests/libraryTests.js create mode 100644 includes/js/dojox/rpc/tests/module.js create mode 100644 includes/js/dojox/rpc/tests/resources/JSON.php create mode 100644 includes/js/dojox/rpc/tests/resources/bigQuery create mode 100644 includes/js/dojox/rpc/tests/resources/bigQuery5 create mode 100644 includes/js/dojox/rpc/tests/resources/echo.php create mode 100644 includes/js/dojox/rpc/tests/resources/echoJson.php create mode 100644 includes/js/dojox/rpc/tests/resources/fakestore.php create mode 100644 includes/js/dojox/rpc/tests/resources/jsonRpc10.php create mode 100644 includes/js/dojox/rpc/tests/resources/jsonRpc11.php create mode 100644 includes/js/dojox/rpc/tests/resources/jsonRpc12.php create mode 100644 includes/js/dojox/rpc/tests/resources/jsonRpcPostGetEcho.php create mode 100644 includes/js/dojox/rpc/tests/resources/jsonpEcho.php create mode 100644 includes/js/dojox/rpc/tests/resources/jsonpEcho.phps create mode 100644 includes/js/dojox/rpc/tests/resources/jsonpJsonRpcEcho.php create mode 100644 includes/js/dojox/rpc/tests/resources/obj1 create mode 100644 includes/js/dojox/rpc/tests/resources/obj1testArray create mode 100644 includes/js/dojox/rpc/tests/resources/obj3 create mode 100644 includes/js/dojox/rpc/tests/resources/obj4 create mode 100644 includes/js/dojox/rpc/tests/resources/query create mode 100644 includes/js/dojox/rpc/tests/resources/rawEcho.php create mode 100644 includes/js/dojox/rpc/tests/resources/res create mode 100644 includes/js/dojox/rpc/tests/resources/store.php create mode 100644 includes/js/dojox/rpc/tests/resources/test.smd create mode 100644 includes/js/dojox/rpc/tests/runLibraryTests.html create mode 100644 includes/js/dojox/rpc/tests/runTests.html create mode 100644 includes/js/dojox/rpc/tests/stores/JsonRestStore.js create mode 100644 includes/js/dojox/rpc/tests/test_dojo_data_model_persevere.html create mode 100644 includes/js/dojox/sketch.js create mode 100644 includes/js/dojox/sketch/Anchor.js create mode 100644 includes/js/dojox/sketch/Annotation.js create mode 100644 includes/js/dojox/sketch/DoubleArrowAnnotation.js create mode 100644 includes/js/dojox/sketch/Figure.js create mode 100644 includes/js/dojox/sketch/LeadAnnotation.js create mode 100644 includes/js/dojox/sketch/PreexistingAnnotation.js create mode 100644 includes/js/dojox/sketch/README create mode 100644 includes/js/dojox/sketch/SingleArrowAnnotation.js create mode 100644 includes/js/dojox/sketch/Slider.js create mode 100644 includes/js/dojox/sketch/Toolbar.js create mode 100644 includes/js/dojox/sketch/UnderlineAnnotation.js create mode 100644 includes/js/dojox/sketch/UndoStack.js create mode 100644 includes/js/dojox/sketch/_Plugin.js create mode 100644 includes/js/dojox/sketch/resources/images/icons.gif create mode 100644 includes/js/dojox/sketch/resources/sketch.css create mode 100644 includes/js/dojox/sketch/resources/sketch.css.commented.css create mode 100644 includes/js/dojox/sketch/tests/annotation.svg create mode 100644 includes/js/dojox/sketch/tests/images/figure2.gif create mode 100644 includes/js/dojox/sketch/tests/images/testsBodyBg.gif create mode 100644 includes/js/dojox/sketch/tests/test_full.html create mode 100644 includes/js/dojox/sql.js create mode 100644 includes/js/dojox/storage.js create mode 100644 includes/js/dojox/storage/AirDBStorageProvider.js create mode 100644 includes/js/dojox/storage/AirEncryptedLocalStorageProvider.js create mode 100644 includes/js/dojox/storage/AirFileStorageProvider.js create mode 100644 includes/js/dojox/storage/FlashStorageProvider.js create mode 100644 includes/js/dojox/storage/GearsStorageProvider.js create mode 100644 includes/js/dojox/storage/Provider.js create mode 100644 includes/js/dojox/storage/README create mode 100644 includes/js/dojox/storage/Storage.as create mode 100644 includes/js/dojox/storage/Storage.swf create mode 100644 includes/js/dojox/storage/WhatWGStorageProvider.js create mode 100644 includes/js/dojox/storage/_common.js create mode 100644 includes/js/dojox/storage/buildFlashStorage.sh create mode 100644 includes/js/dojox/storage/demos/helloworld.html create mode 100644 includes/js/dojox/storage/manager.js create mode 100644 includes/js/dojox/storage/storage_dialog.fla create mode 100644 includes/js/dojox/storage/tests/resources/testBook.txt create mode 100644 includes/js/dojox/storage/tests/resources/testXML.xml create mode 100644 includes/js/dojox/storage/tests/test_storage.html create mode 100644 includes/js/dojox/storage/tests/test_storage.js create mode 100644 includes/js/dojox/string/Builder.js create mode 100644 includes/js/dojox/string/README create mode 100644 includes/js/dojox/string/sprintf.js create mode 100644 includes/js/dojox/string/tests/Builder.js create mode 100644 includes/js/dojox/string/tests/BuilderPerf.html create mode 100644 includes/js/dojox/string/tests/PerfFun.html create mode 100644 includes/js/dojox/string/tests/lipsum.js create mode 100644 includes/js/dojox/string/tests/notes.txt create mode 100644 includes/js/dojox/string/tests/peller.html create mode 100644 includes/js/dojox/string/tests/runTests.html create mode 100644 includes/js/dojox/string/tests/sprintf.js create mode 100644 includes/js/dojox/string/tests/string.js create mode 100644 includes/js/dojox/string/tokenize.js create mode 100644 includes/js/dojox/timing.js create mode 100644 includes/js/dojox/timing/README create mode 100644 includes/js/dojox/timing/Sequence.js create mode 100644 includes/js/dojox/timing/Streamer.js create mode 100644 includes/js/dojox/timing/ThreadPool.js create mode 100644 includes/js/dojox/timing/_base.js create mode 100644 includes/js/dojox/timing/tests/test_Sequence.html create mode 100644 includes/js/dojox/timing/tests/test_ThreadPool.html create mode 100644 includes/js/dojox/uuid.js create mode 100644 includes/js/dojox/uuid/README create mode 100644 includes/js/dojox/uuid/Uuid.js create mode 100644 includes/js/dojox/uuid/_base.js create mode 100644 includes/js/dojox/uuid/generateRandomUuid.js create mode 100644 includes/js/dojox/uuid/generateTimeBasedUuid.js create mode 100644 includes/js/dojox/uuid/tests/runTests.html create mode 100644 includes/js/dojox/uuid/tests/uuid.js create mode 100644 includes/js/dojox/validate.js create mode 100644 includes/js/dojox/validate/README create mode 100644 includes/js/dojox/validate/_base.js create mode 100644 includes/js/dojox/validate/ca.js create mode 100644 includes/js/dojox/validate/check.js create mode 100644 includes/js/dojox/validate/creditCard.js create mode 100644 includes/js/dojox/validate/isbn.js create mode 100644 includes/js/dojox/validate/regexp.js create mode 100644 includes/js/dojox/validate/tests/creditcard.js create mode 100644 includes/js/dojox/validate/tests/module.js create mode 100644 includes/js/dojox/validate/tests/runTests.html create mode 100644 includes/js/dojox/validate/tests/validate.js create mode 100644 includes/js/dojox/validate/us.js create mode 100644 includes/js/dojox/validate/web.js create mode 100644 includes/js/dojox/widget/ColorPicker.js create mode 100644 includes/js/dojox/widget/ColorPicker/ColorPicker.css create mode 100644 includes/js/dojox/widget/ColorPicker/ColorPicker.css.commented.css create mode 100644 includes/js/dojox/widget/ColorPicker/ColorPicker.html create mode 100644 includes/js/dojox/widget/ColorPicker/images/hue.png create mode 100644 includes/js/dojox/widget/ColorPicker/images/hueHandle.png create mode 100644 includes/js/dojox/widget/ColorPicker/images/pickerPointer.png create mode 100644 includes/js/dojox/widget/ColorPicker/images/underlay.png create mode 100644 includes/js/dojox/widget/FileInput.js create mode 100644 includes/js/dojox/widget/FileInput/FileInput.css create mode 100644 includes/js/dojox/widget/FileInput/FileInput.css.commented.css create mode 100644 includes/js/dojox/widget/FileInput/FileInput.html create mode 100644 includes/js/dojox/widget/FileInput/FileInputAuto.html create mode 100644 includes/js/dojox/widget/FileInput/ReceiveFile.php create mode 100644 includes/js/dojox/widget/FileInputAuto.js create mode 100644 includes/js/dojox/widget/FisheyeList.js create mode 100644 includes/js/dojox/widget/FisheyeList/FisheyeList.css create mode 100644 includes/js/dojox/widget/FisheyeList/FisheyeList.css.commented.css create mode 100644 includes/js/dojox/widget/FisheyeLite.js create mode 100644 includes/js/dojox/widget/Iterator.js create mode 100644 includes/js/dojox/widget/Loader.js create mode 100644 includes/js/dojox/widget/Loader/Loader.css create mode 100644 includes/js/dojox/widget/Loader/Loader.css.commented.css create mode 100644 includes/js/dojox/widget/Loader/README create mode 100644 includes/js/dojox/widget/Loader/honey.php create mode 100644 includes/js/dojox/widget/Loader/icons/loading.gif create mode 100644 includes/js/dojox/widget/MultiComboBox.js create mode 100644 includes/js/dojox/widget/README create mode 100644 includes/js/dojox/widget/Rating.js create mode 100644 includes/js/dojox/widget/Rating/Rating.css create mode 100644 includes/js/dojox/widget/Rating/Rating.css.commented.css create mode 100644 includes/js/dojox/widget/Rating/rating_empty.gif create mode 100644 includes/js/dojox/widget/Rating/rating_empty.png create mode 100644 includes/js/dojox/widget/Rating/rating_full.gif create mode 100644 includes/js/dojox/widget/Rating/rating_full.png create mode 100644 includes/js/dojox/widget/Rating/rating_half.png create mode 100644 includes/js/dojox/widget/SortList.js create mode 100644 includes/js/dojox/widget/SortList/SortList.css create mode 100644 includes/js/dojox/widget/SortList/SortList.css.commented.css create mode 100644 includes/js/dojox/widget/SortList/SortList.html create mode 100644 includes/js/dojox/widget/TimeSpinner.js create mode 100644 includes/js/dojox/widget/Toaster.js create mode 100644 includes/js/dojox/widget/Toaster/Toaster.css create mode 100644 includes/js/dojox/widget/Toaster/Toaster.css.commented.css create mode 100644 includes/js/dojox/widget/Wizard.js create mode 100644 includes/js/dojox/widget/Wizard/Wizard.css create mode 100644 includes/js/dojox/widget/Wizard/Wizard.css.commented.css create mode 100644 includes/js/dojox/widget/Wizard/Wizard.html create mode 100644 includes/js/dojox/widget/nls/Wizard.js create mode 100644 includes/js/dojox/widget/nls/ar/Wizard.js create mode 100644 includes/js/dojox/widget/nls/cs/Wizard.js create mode 100644 includes/js/dojox/widget/nls/da/Wizard.js create mode 100644 includes/js/dojox/widget/nls/de/Wizard.js create mode 100644 includes/js/dojox/widget/nls/el/Wizard.js create mode 100644 includes/js/dojox/widget/nls/es/Wizard.js create mode 100644 includes/js/dojox/widget/nls/fi/Wizard.js create mode 100644 includes/js/dojox/widget/nls/fr/Wizard.js create mode 100644 includes/js/dojox/widget/nls/he/Wizard.js create mode 100644 includes/js/dojox/widget/nls/hu/Wizard.js create mode 100644 includes/js/dojox/widget/nls/it/Wizard.js create mode 100644 includes/js/dojox/widget/nls/ja/Wizard.js create mode 100644 includes/js/dojox/widget/nls/ko/Wizard.js create mode 100644 includes/js/dojox/widget/nls/nb/Wizard.js create mode 100644 includes/js/dojox/widget/nls/nl/Wizard.js create mode 100644 includes/js/dojox/widget/nls/pl/Wizard.js create mode 100644 includes/js/dojox/widget/nls/pt-pt/Wizard.js create mode 100644 includes/js/dojox/widget/nls/pt/Wizard.js create mode 100644 includes/js/dojox/widget/nls/ru/Wizard.js create mode 100644 includes/js/dojox/widget/nls/sv/Wizard.js create mode 100644 includes/js/dojox/widget/nls/tr/Wizard.js create mode 100644 includes/js/dojox/widget/nls/zh-tw/Wizard.js create mode 100644 includes/js/dojox/widget/nls/zh/Wizard.js create mode 100644 includes/js/dojox/widget/tests/_tags.json create mode 100644 includes/js/dojox/widget/tests/demo_FisheyeList-orig.html create mode 100644 includes/js/dojox/widget/tests/demo_FisheyeList.html create mode 100644 includes/js/dojox/widget/tests/demo_FisheyeLite.html create mode 100644 includes/js/dojox/widget/tests/images/fisheye_1.png create mode 100644 includes/js/dojox/widget/tests/images/fisheye_2.png create mode 100644 includes/js/dojox/widget/tests/images/fisheye_3.png create mode 100644 includes/js/dojox/widget/tests/images/fisheye_4.png create mode 100644 includes/js/dojox/widget/tests/images/icon_browser.png create mode 100644 includes/js/dojox/widget/tests/images/icon_calendar.png create mode 100644 includes/js/dojox/widget/tests/images/icon_email.png create mode 100644 includes/js/dojox/widget/tests/images/icon_texteditor.png create mode 100644 includes/js/dojox/widget/tests/images/icon_update.png create mode 100644 includes/js/dojox/widget/tests/images/icon_users.png create mode 100644 includes/js/dojox/widget/tests/images/rating_empty.gif create mode 100644 includes/js/dojox/widget/tests/images/rating_empty.png create mode 100644 includes/js/dojox/widget/tests/images/rating_full.gif create mode 100644 includes/js/dojox/widget/tests/images/rating_full.png create mode 100644 includes/js/dojox/widget/tests/test_ColorPicker.html create mode 100644 includes/js/dojox/widget/tests/test_FileInput.html create mode 100644 includes/js/dojox/widget/tests/test_FisheyeList.html create mode 100644 includes/js/dojox/widget/tests/test_FisheyeLite.html create mode 100644 includes/js/dojox/widget/tests/test_Iterator.html create mode 100644 includes/js/dojox/widget/tests/test_Loader.html create mode 100644 includes/js/dojox/widget/tests/test_MultiComboBox.html create mode 100644 includes/js/dojox/widget/tests/test_Rating.html create mode 100644 includes/js/dojox/widget/tests/test_SortList.html create mode 100644 includes/js/dojox/widget/tests/test_TimeSpinner.html create mode 100644 includes/js/dojox/widget/tests/test_Toaster.html create mode 100644 includes/js/dojox/widget/tests/test_Wizard.html create mode 100644 includes/js/dojox/wire.js create mode 100644 includes/js/dojox/wire/CompositeWire.js create mode 100644 includes/js/dojox/wire/DataWire.js create mode 100644 includes/js/dojox/wire/README create mode 100644 includes/js/dojox/wire/TableAdapter.js create mode 100644 includes/js/dojox/wire/TextAdapter.js create mode 100644 includes/js/dojox/wire/TreeAdapter.js create mode 100644 includes/js/dojox/wire/Wire.js create mode 100644 includes/js/dojox/wire/XmlWire.js create mode 100644 includes/js/dojox/wire/_base.js create mode 100644 includes/js/dojox/wire/demos/TableContainer.css create mode 100644 includes/js/dojox/wire/demos/TableContainer.css.commented.css create mode 100644 includes/js/dojox/wire/demos/TableContainer.js create mode 100644 includes/js/dojox/wire/demos/WidgetRepeater.js create mode 100644 includes/js/dojox/wire/demos/markup/countries.json create mode 100644 includes/js/dojox/wire/demos/markup/demo_ActionChaining.html create mode 100644 includes/js/dojox/wire/demos/markup/demo_ActionWiring.html create mode 100644 includes/js/dojox/wire/demos/markup/demo_BasicChildWire.html create mode 100644 includes/js/dojox/wire/demos/markup/demo_BasicColumnWiring.html create mode 100644 includes/js/dojox/wire/demos/markup/demo_ConditionalActions.html create mode 100644 includes/js/dojox/wire/demos/markup/demo_FlickrStoreWire.html create mode 100644 includes/js/dojox/wire/demos/markup/demo_TopicWiring.html create mode 100644 includes/js/dojox/wire/demos/markup/flickrDemo.css create mode 100644 includes/js/dojox/wire/demos/markup/flickrDemo.css.commented.css create mode 100644 includes/js/dojox/wire/demos/markup/states.json create mode 100644 includes/js/dojox/wire/ml/Action.js create mode 100644 includes/js/dojox/wire/ml/Data.js create mode 100644 includes/js/dojox/wire/ml/DataStore.js create mode 100644 includes/js/dojox/wire/ml/Invocation.js create mode 100644 includes/js/dojox/wire/ml/Service.js create mode 100644 includes/js/dojox/wire/ml/Transfer.js create mode 100644 includes/js/dojox/wire/ml/util.js create mode 100644 includes/js/dojox/wire/tests/markup/Action.html create mode 100644 includes/js/dojox/wire/tests/markup/Data.html create mode 100644 includes/js/dojox/wire/tests/markup/DataStore.html create mode 100644 includes/js/dojox/wire/tests/markup/DataStore.xml create mode 100644 includes/js/dojox/wire/tests/markup/Invocation.html create mode 100644 includes/js/dojox/wire/tests/markup/Service.html create mode 100644 includes/js/dojox/wire/tests/markup/Service/JSON.smd create mode 100644 includes/js/dojox/wire/tests/markup/Service/XML.smd create mode 100644 includes/js/dojox/wire/tests/markup/Service/a.json create mode 100644 includes/js/dojox/wire/tests/markup/Service/a.xml create mode 100644 includes/js/dojox/wire/tests/markup/Transfer.html create mode 100644 includes/js/dojox/wire/tests/module.js create mode 100644 includes/js/dojox/wire/tests/programmatic/CompositeWire.js create mode 100644 includes/js/dojox/wire/tests/programmatic/ConverterDynamic.js create mode 100644 includes/js/dojox/wire/tests/programmatic/DataWire.js create mode 100644 includes/js/dojox/wire/tests/programmatic/TableAdapter.js create mode 100644 includes/js/dojox/wire/tests/programmatic/TextAdapter.js create mode 100644 includes/js/dojox/wire/tests/programmatic/TreeAdapter.js create mode 100644 includes/js/dojox/wire/tests/programmatic/Wire.js create mode 100644 includes/js/dojox/wire/tests/programmatic/XmlWire.js create mode 100644 includes/js/dojox/wire/tests/programmatic/_base.js create mode 100644 includes/js/dojox/wire/tests/runTests.html create mode 100644 includes/js/dojox/wire/tests/wire.js create mode 100644 includes/js/dojox/wire/tests/wireml.js create mode 100644 includes/js/dojox/xml/DomParser.js create mode 100644 includes/js/dojox/xml/README (limited to 'includes/js/dojox') diff --git a/includes/js/dojox/LICENSE b/includes/js/dojox/LICENSE new file mode 100644 index 0000000..3fa2720 --- /dev/null +++ b/includes/js/dojox/LICENSE @@ -0,0 +1,195 @@ +Dojo is available under *either* the terms of the modified BSD license *or* the +Academic Free License version 2.1. As a recipient of Dojo, you may choose which +license to receive this code under (except as noted in per-module LICENSE +files). Some modules may not be the copyright of the Dojo Foundation. These +modules contain explicit declarations of copyright in both the LICENSE files in +the directories in which they reside and in the code itself. No external +contributions are allowed under licenses which are fundamentally incompatible +with the AFL or BSD licenses that Dojo is distributed under. + +The text of the AFL and BSD licenses is reproduced below. + +------------------------------------------------------------------------------- +The "New" BSD License: +********************** + +Copyright (c) 2005-2008, The Dojo Foundation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the Dojo Foundation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- +The Academic Free License, v. 2.1: +********************************** + +This Academic Free License (the "License") applies to any original work of +authorship (the "Original Work") whose owner (the "Licensor") has placed the +following notice immediately following the copyright notice for the Original +Work: + +Licensed under the Academic Free License version 2.1 + +1) Grant of Copyright License. Licensor hereby grants You a world-wide, +royalty-free, non-exclusive, perpetual, sublicenseable license to do the +following: + +a) to reproduce the Original Work in copies; + +b) to prepare derivative works ("Derivative Works") based upon the Original +Work; + +c) to distribute copies of the Original Work and Derivative Works to the +public; + +d) to perform the Original Work publicly; and + +e) to display the Original Work publicly. + +2) Grant of Patent License. Licensor hereby grants You a world-wide, +royalty-free, non-exclusive, perpetual, sublicenseable license, under patent +claims owned or controlled by the Licensor that are embodied in the Original +Work as furnished by the Licensor, to make, use, sell and offer for sale the +Original Work and Derivative Works. + +3) Grant of Source Code License. The term "Source Code" means the preferred +form of the Original Work for making modifications to it and all available +documentation describing how to modify the Original Work. Licensor hereby +agrees to provide a machine-readable copy of the Source Code of the Original +Work along with each copy of the Original Work that Licensor distributes. +Licensor reserves the right to satisfy this obligation by placing a +machine-readable copy of the Source Code in an information repository +reasonably calculated to permit inexpensive and convenient access by You for as +long as Licensor continues to distribute the Original Work, and by publishing +the address of that information repository in a notice immediately following +the copyright notice that applies to the Original Work. + +4) Exclusions From License Grant. Neither the names of Licensor, nor the names +of any contributors to the Original Work, nor any of their trademarks or +service marks, may be used to endorse or promote products derived from this +Original Work without express prior written permission of the Licensor. Nothing +in this License shall be deemed to grant any rights to trademarks, copyrights, +patents, trade secrets or any other intellectual property of Licensor except as +expressly stated herein. No patent license is granted to make, use, sell or +offer to sell embodiments of any patent claims other than the licensed claims +defined in Section 2. No right is granted to the trademarks of Licensor even if +such marks are included in the Original Work. Nothing in this License shall be +interpreted to prohibit Licensor from licensing under different terms from this +License any Original Work that Licensor otherwise would have a right to +license. + +5) This section intentionally omitted. + +6) Attribution Rights. You must retain, in the Source Code of any Derivative +Works that You create, all copyright, patent or trademark notices from the +Source Code of the Original Work, as well as any notices of licensing and any +descriptive text identified therein as an "Attribution Notice." You must cause +the Source Code for any Derivative Works that You create to carry a prominent +Attribution Notice reasonably calculated to inform recipients that You have +modified the Original Work. + +7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that +the copyright in and to the Original Work and the patent rights granted herein +by Licensor are owned by the Licensor or are sublicensed to You under the terms +of this License with the permission of the contributor(s) of those copyrights +and patent rights. Except as expressly stated in the immediately proceeding +sentence, the Original Work is provided under this License on an "AS IS" BASIS +and WITHOUT WARRANTY, either express or implied, including, without limitation, +the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. +This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No +license to Original Work is granted hereunder except under this disclaimer. + +8) Limitation of Liability. Under no circumstances and under no legal theory, +whether in tort (including negligence), contract, or otherwise, shall the +Licensor be liable to any person for any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License +or the use of the Original Work including, without limitation, damages for loss +of goodwill, work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses. This limitation of liability shall not +apply to liability for death or personal injury resulting from Licensor's +negligence to the extent applicable law prohibits such limitation. Some +jurisdictions do not allow the exclusion or limitation of incidental or +consequential damages, so this exclusion and limitation may not apply to You. + +9) Acceptance and Termination. If You distribute copies of the Original Work or +a Derivative Work, You must make a reasonable effort under the circumstances to +obtain the express assent of recipients to the terms of this License. Nothing +else but this License (or another written agreement between Licensor and You) +grants You permission to create Derivative Works based upon the Original Work +or to exercise any of the rights granted in Section 1 herein, and any attempt +to do so except under the terms of this License (or another written agreement +between Licensor and You) is expressly prohibited by U.S. copyright law, the +equivalent laws of other countries, and by international treaty. Therefore, by +exercising any of the rights granted to You in Section 1 herein, You indicate +Your acceptance of this License and all of its terms and conditions. + +10) Termination for Patent Action. This License shall terminate automatically +and You may no longer exercise any of the rights granted to You by this License +as of the date You commence an action, including a cross-claim or counterclaim, +against Licensor or any licensee alleging that the Original Work infringes a +patent. This termination provision shall not apply for an action alleging +patent infringement by combinations of the Original Work with other software or +hardware. + +11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this +License may be brought only in the courts of a jurisdiction wherein the +Licensor resides or in which Licensor conducts its primary business, and under +the laws of that jurisdiction excluding its conflict-of-law provisions. The +application of the United Nations Convention on Contracts for the International +Sale of Goods is expressly excluded. Any use of the Original Work outside the +scope of this License or after its termination shall be subject to the +requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et +seq., the equivalent laws of other countries, and international treaty. This +section shall survive the termination of this License. + +12) Attorneys Fees. In any action to enforce the terms of this License or +seeking damages relating thereto, the prevailing party shall be entitled to +recover its costs and expenses, including, without limitation, reasonable +attorneys' fees and costs incurred in connection with such action, including +any appeal of such action. This section shall survive the termination of this +License. + +13) Miscellaneous. This License represents the complete agreement concerning +the subject matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent necessary to +make it enforceable. + +14) Definition of "You" in This License. "You" throughout this License, whether +in upper or lower case, means an individual or a legal entity exercising rights +under, and complying with all of the terms of, this License. For legal +entities, "You" includes any entity that controls, is controlled by, or is +under common control with you. For purposes of this definition, "control" means +(i) the power, direct or indirect, to cause the direction or management of such +entity, whether by contract or otherwise, or (ii) ownership of fifty percent +(50%) or more of the outstanding shares, or (iii) beneficial ownership of such +entity. + +15) Right to Use. You may use the Original Work in all ways not otherwise +restricted or conditioned by this License or by law, and Licensor promises not +to interfere with or be responsible for such uses by You. + +This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved. +Permission is hereby granted to copy and distribute this license without +modification. This license may not be modified without the express written +permission of its copyright owner. diff --git a/includes/js/dojox/_sql/LICENSE b/includes/js/dojox/_sql/LICENSE new file mode 100644 index 0000000..5c277ec --- /dev/null +++ b/includes/js/dojox/_sql/LICENSE @@ -0,0 +1,9 @@ +License Disclaimer: + +All contents of this directory are Copyright (c) the Dojo Foundation, with the +following exceptions: +------------------------------------------------------------------------------- + +_crypto.js - internally uses AES algorithm + * AES algorithm copyright Chris Veness (CLA signed and permission given to use code under BSD license) + Taken from http://www.movable-type.co.uk/scripts/aes.html diff --git a/includes/js/dojox/_sql/_crypto.js b/includes/js/dojox/_sql/_crypto.js new file mode 100644 index 0000000..e8a9214 --- /dev/null +++ b/includes/js/dojox/_sql/_crypto.js @@ -0,0 +1,443 @@ +if(!dojo._hasResource["dojox._sql._crypto"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox._sql._crypto"] = true; +// Taken from http://www.movable-type.co.uk/scripts/aes.html by +// Chris Veness (CLA signed); adapted for Dojo and Google Gears Worker Pool +// by Brad Neuberg, bkn3@columbia.edu + +dojo.provide("dojox._sql._crypto"); + +dojo.mixin(dojox._sql._crypto,{ + // _POOL_SIZE: + // Size of worker pool to create to help with crypto + _POOL_SIZE: 100, + + encrypt: function(plaintext, password, callback){ + // summary: + // Use Corrected Block TEA to encrypt plaintext using password + // (note plaintext & password must be strings not string objects). + // Results will be returned to the 'callback' asychronously. + this._initWorkerPool(); + + var msg ={plaintext: plaintext, password: password}; + msg = dojo.toJson(msg); + msg = "encr:" + String(msg); + + this._assignWork(msg, callback); + }, + + decrypt: function(ciphertext, password, callback){ + // summary: + // Use Corrected Block TEA to decrypt ciphertext using password + // (note ciphertext & password must be strings not string objects). + // Results will be returned to the 'callback' asychronously. + this._initWorkerPool(); + + var msg ={ciphertext: ciphertext, password: password}; + msg = dojo.toJson(msg); + msg = "decr:" + String(msg); + + this._assignWork(msg, callback); + }, + + _initWorkerPool: function(){ + // bugs in Google Gears prevents us from dynamically creating + // and destroying workers as we need them -- the worker + // pool functionality stops working after a number of crypto + // cycles (probably related to a memory leak in Google Gears). + // this is too bad, since it results in much simpler code. + + // instead, we have to create a pool of workers and reuse them. we + // keep a stack of 'unemployed' Worker IDs that are currently not working. + // if a work request comes in, we pop off the 'unemployed' stack + // and put them to work, storing them in an 'employed' hashtable, + // keyed by their Worker ID with the value being the callback function + // that wants the result. when an employed worker is done, we get + // a message in our 'manager' which adds this worker back to the + // unemployed stack and routes the result to the callback that + // wanted it. if all the workers were employed in the past but + // more work needed to be done (i.e. it's a tight labor pool ;) + // then the work messages are pushed onto + // a 'handleMessage' queue as an object tuple{msg: msg, callback: callback} + + if(!this._manager){ + try{ + this._manager = google.gears.factory.create("beta.workerpool", "1.0"); + this._unemployed = []; + this._employed ={}; + this._handleMessage = []; + + var self = this; + this._manager.onmessage = function(msg, sender){ + // get the callback necessary to serve this result + var callback = self._employed["_" + sender]; + + // make this worker unemployed + self._employed["_" + sender] = undefined; + self._unemployed.push("_" + sender); + + // see if we need to assign new work + // that was queued up needing to be done + if(self._handleMessage.length){ + var handleMe = self._handleMessage.shift(); + self._assignWork(handleMe.msg, handleMe.callback); + } + + // return results + callback(msg); + } + + var workerInit = "function _workerInit(){" + + "gearsWorkerPool.onmessage = " + + String(this._workerHandler) + + ";" + + "}"; + + var code = workerInit + " _workerInit();"; + + // create our worker pool + for(var i = 0; i < this._POOL_SIZE; i++){ + this._unemployed.push("_" + this._manager.createWorker(code)); + } + }catch(exp){ + throw exp.message||exp; + } + } + }, + + _assignWork: function(msg, callback){ + // can we immediately assign this work? + if(!this._handleMessage.length && this._unemployed.length){ + // get an unemployed worker + var workerID = this._unemployed.shift().substring(1); // remove _ + + // list this worker as employed + this._employed["_" + workerID] = callback; + + // do the worke + this._manager.sendMessage(msg, workerID); + }else{ + // we have to queue it up + this._handleMessage ={msg: msg, callback: callback}; + } + }, + + _workerHandler: function(msg, sender){ + + /* Begin AES Implementation */ + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + // Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [§5.1.1] + var Sbox = [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16]; + + // Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [§5.2] + var Rcon = [ [0x00, 0x00, 0x00, 0x00], + [0x01, 0x00, 0x00, 0x00], + [0x02, 0x00, 0x00, 0x00], + [0x04, 0x00, 0x00, 0x00], + [0x08, 0x00, 0x00, 0x00], + [0x10, 0x00, 0x00, 0x00], + [0x20, 0x00, 0x00, 0x00], + [0x40, 0x00, 0x00, 0x00], + [0x80, 0x00, 0x00, 0x00], + [0x1b, 0x00, 0x00, 0x00], + [0x36, 0x00, 0x00, 0x00] ]; + + /* + * AES Cipher function: encrypt 'input' with Rijndael algorithm + * + * takes byte-array 'input' (16 bytes) + * 2D byte-array key schedule 'w' (Nr+1 x Nb bytes) + * + * applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage + * + * returns byte-array encrypted value (16 bytes) + */ + function Cipher(input, w) { // main Cipher function [§5.1] + var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES) + var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys + + var state = [[],[],[],[]]; // initialise 4xNb byte-array 'state' with input [§3.4] + for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i]; + + state = AddRoundKey(state, w, 0, Nb); + + for (var round=1; round 6 && i%Nk == 4) { + temp = SubWord(temp); + } + for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t]; + } + + return w; + } + + function SubWord(w) { // apply SBox to 4-byte word w + for (var i=0; i<4; i++) w[i] = Sbox[w[i]]; + return w; + } + + function RotWord(w) { // rotate 4-byte word w left by one byte + w[4] = w[0]; + for (var i=0; i<4; i++) w[i] = w[i+1]; + return w; + } + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + /* + * Use AES to encrypt 'plaintext' with 'password' using 'nBits' key, in 'Counter' mode of operation + * - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + * for each block + * - outputblock = cipher(counter, key) + * - cipherblock = plaintext xor outputblock + */ + function AESEncryptCtr(plaintext, password, nBits) { + if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys + + // for this example script, generate the key by applying Cipher to 1st 16/24/32 chars of password; + // for real-world applications, a more secure approach would be to hash the password e.g. with SHA-1 + var nBytes = nBits/8; // no bytes in key + var pwBytes = new Array(nBytes); + for (var i=0; i>> i*8) & 0xff; + for (var i=0; i<4; i++) counterBlock[i+4] = (nonce/0x100000000 >>> i*8) & 0xff; + + // generate key schedule - an expansion of the key into distinct Key Rounds for each round + var keySchedule = KeyExpansion(key); + + var blockCount = Math.ceil(plaintext.length/blockSize); + var ciphertext = new Array(blockCount); // ciphertext as array of strings + + for (var b=0; b>> c*8) & 0xff; + for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8) + + var cipherCntr = Cipher(counterBlock, keySchedule); // -- encrypt counter block -- + + // calculate length of final block: + var blockLength = b>> c*8) & 0xff; + for (var c=0; c<4; c++) counterBlock[15-c-4] = ((b/0x100000000-1) >>> c*8) & 0xff; + + var cipherCntr = Cipher(counterBlock, keySchedule); // encrypt counter block + + ciphertext[b] = unescCtrlChars(ciphertext[b]); + + var pt = ''; + for (var i=0; i 63){ + this.dbName = this.dbName.substring(0, 63); + } + } + + if(!dbName){ + dbName = this.dbName; + } + + try{ + this._initDb(); + this.db.open(dbName); + this._dbOpen = true; + }catch(exp){ + throw exp.message||exp; + } + }, + + close: function(dbName){ + // on Internet Explorer, Google Gears throws an exception + // "Object not a collection", when we try to close the + // database -- just don't close it on this platform + // since we are running into a Gears bug; the Gears team + // said it's ok to not close a database connection + if(dojo.isIE){ return; } + + if(!this._dbOpen && (!dbName || dbName == this.dbName)){ + return; + } + + if(!dbName){ + dbName = this.dbName; + } + + try{ + this.db.close(dbName); + this._dbOpen = false; + }catch(exp){ + throw exp.message||exp; + } + }, + + _exec: function(params){ + try{ + // get the Gears Database object + this._initDb(); + + // see if we need to open the db; if programmer + // manually called dojox.sql.open() let them handle + // it; otherwise we open and close automatically on + // each SQL execution + if(!this._dbOpen){ + this.open(); + this._autoClose = true; + } + + // determine our parameters + var sql = null; + var callback = null; + var password = null; + + var args = dojo._toArray(params); + + sql = args.splice(0, 1)[0]; + + // does this SQL statement use the ENCRYPT or DECRYPT + // keywords? if so, extract our callback and crypto + // password + if(this._needsEncrypt(sql) || this._needsDecrypt(sql)){ + callback = args.splice(args.length - 1, 1)[0]; + password = args.splice(args.length - 1, 1)[0]; + } + + // 'args' now just has the SQL parameters + + // print out debug SQL output if the developer wants that + if(this.debug){ + this._printDebugSQL(sql, args); + } + + // handle SQL that needs encryption/decryption differently + // do we have an ENCRYPT SQL statement? if so, handle that first + if(this._needsEncrypt(sql)){ + var crypto = new dojox.sql._SQLCrypto("encrypt", sql, + password, args, + callback); + return; // encrypted results will arrive asynchronously + }else if(this._needsDecrypt(sql)){ // otherwise we have a DECRYPT statement + var crypto = new dojox.sql._SQLCrypto("decrypt", sql, + password, args, + callback); + return; // decrypted results will arrive asynchronously + } + + // execute the SQL and get the results + var rs = this.db.execute(sql, args); + + // Gears ResultSet object's are ugly -- normalize + // these into something JavaScript programmers know + // how to work with, basically an array of + // JavaScript objects where each property name is + // simply the field name for a column of data + rs = this._normalizeResults(rs); + + if(this._autoClose){ + this.close(); + } + + return rs; + }catch(exp){ + exp = exp.message||exp; + + console.debug("SQL Exception: " + exp); + + if(this._autoClose){ + try{ + this.close(); + }catch(e){ + console.debug("Error closing database: " + + e.message||e); + } + } + + throw exp; + } + }, + + _initDb: function(){ + if(!this.db){ + try{ + this.db = google.gears.factory.create('beta.database', '1.0'); + }catch(exp){ + dojo.setObject("google.gears.denied", true); + dojox.off.onFrameworkEvent("coreOperationFailed"); + throw "Google Gears must be allowed to run"; + } + } + }, + + _printDebugSQL: function(sql, args){ + var msg = "dojox.sql(\"" + sql + "\""; + for(var i = 0; i < args.length; i++){ + if(typeof args[i] == "string"){ + msg += ", \"" + args[i] + "\""; + }else{ + msg += ", " + args[i]; + } + } + msg += ")"; + + console.debug(msg); + }, + + _normalizeResults: function(rs){ + var results = []; + if(!rs){ return []; } + + while(rs.isValidRow()){ + var row = {}; + + for(var i = 0; i < rs.fieldCount(); i++){ + var fieldName = rs.fieldName(i); + var fieldValue = rs.field(i); + row[fieldName] = fieldValue; + } + + results.push(row); + + rs.next(); + } + + rs.close(); + + return results; + }, + + _needsEncrypt: function(sql){ + return /encrypt\([^\)]*\)/i.test(sql); + }, + + _needsDecrypt: function(sql){ + return /decrypt\([^\)]*\)/i.test(sql); + } +}); + +// summary: +// A private class encapsulating any cryptography that must be done +// on a SQL statement. We instantiate this class and have it hold +// it's state so that we can potentially have several encryption +// operations happening at the same time by different SQL statements. +dojo.declare("dojox.sql._SQLCrypto", null, { + constructor: function(action, sql, password, args, callback){ + if(action == "encrypt"){ + this._execEncryptSQL(sql, password, args, callback); + }else{ + this._execDecryptSQL(sql, password, args, callback); + } + }, + + _execEncryptSQL: function(sql, password, args, callback){ + // strip the ENCRYPT/DECRYPT keywords from the SQL + var strippedSQL = this._stripCryptoSQL(sql); + + // determine what arguments need encryption + var encryptColumns = this._flagEncryptedArgs(sql, args); + + // asynchronously encrypt each argument that needs it + var self = this; + this._encrypt(strippedSQL, password, args, encryptColumns, function(finalArgs){ + // execute the SQL + var error = false; + var resultSet = []; + var exp = null; + try{ + resultSet = dojox.sql.db.execute(strippedSQL, finalArgs); + }catch(execError){ + error = true; + exp = execError.message||execError; + } + + // was there an error during SQL execution? + if(exp != null){ + if(dojox.sql._autoClose){ + try{ dojox.sql.close(); }catch(e){} + } + + callback(null, true, exp.toString()); + return; + } + + // normalize SQL results into a JavaScript object + // we can work with + resultSet = dojox.sql._normalizeResults(resultSet); + + if(dojox.sql._autoClose){ + dojox.sql.close(); + } + + // are any decryptions necessary on the result set? + if(dojox.sql._needsDecrypt(sql)){ + // determine which of the result set columns needs decryption + var needsDecrypt = self._determineDecryptedColumns(sql); + + // now decrypt columns asynchronously + // decrypt columns that need it + self._decrypt(resultSet, needsDecrypt, password, function(finalResultSet){ + callback(finalResultSet, false, null); + }); + }else{ + callback(resultSet, false, null); + } + }); + }, + + _execDecryptSQL: function(sql, password, args, callback){ + // strip the ENCRYPT/DECRYPT keywords from the SQL + var strippedSQL = this._stripCryptoSQL(sql); + + // determine which columns needs decryption; this either + // returns the value *, which means all result set columns will + // be decrypted, or it will return the column names that need + // decryption set on a hashtable so we can quickly test a given + // column name; the key is the column name that needs + // decryption and the value is 'true' (i.e. needsDecrypt["someColumn"] + // would return 'true' if it needs decryption, and would be 'undefined' + // or false otherwise) + var needsDecrypt = this._determineDecryptedColumns(sql); + + // execute the SQL + var error = false; + var resultSet = []; + var exp = null; + try{ + resultSet = dojox.sql.db.execute(strippedSQL, args); + }catch(execError){ + error = true; + exp = execError.message||execError; + } + + // was there an error during SQL execution? + if(exp != null){ + if(dojox.sql._autoClose){ + try{ dojox.sql.close(); }catch(e){} + } + + callback(resultSet, true, exp.toString()); + return; + } + + // normalize SQL results into a JavaScript object + // we can work with + resultSet = dojox.sql._normalizeResults(resultSet); + + if(dojox.sql._autoClose){ + dojox.sql.close(); + } + + // decrypt columns that need it + this._decrypt(resultSet, needsDecrypt, password, function(finalResultSet){ + callback(finalResultSet, false, null); + }); + }, + + _encrypt: function(sql, password, args, encryptColumns, callback){ + //console.debug("_encrypt, sql="+sql+", password="+password+", encryptColumns="+encryptColumns+", args="+args); + + this._totalCrypto = 0; + this._finishedCrypto = 0; + this._finishedSpawningCrypto = false; + this._finalArgs = args; + + for(var i = 0; i < args.length; i++){ + if(encryptColumns[i]){ + // we have an encrypt() keyword -- get just the value inside + // the encrypt() parantheses -- for now this must be a ? + var sqlParam = args[i]; + var paramIndex = i; + + // update the total number of encryptions we know must be done asynchronously + this._totalCrypto++; + + // FIXME: This currently uses DES as a proof-of-concept since the + // DES code used is quite fast and was easy to work with. Modify dojox.sql + // to be able to specify a different encryption provider through a + // a SQL-like syntax, such as dojox.sql("SET ENCRYPTION BLOWFISH"), + // and modify the dojox.crypto.Blowfish code to be able to work using + // a Google Gears Worker Pool + + // do the actual encryption now, asychronously on a Gears worker thread + dojox._sql._crypto.encrypt(sqlParam, password, dojo.hitch(this, function(results){ + // set the new encrypted value + this._finalArgs[paramIndex] = results; + this._finishedCrypto++; + // are we done with all encryption? + if(this._finishedCrypto >= this._totalCrypto + && this._finishedSpawningCrypto){ + callback(this._finalArgs); + } + })); + } + } + + this._finishedSpawningCrypto = true; + }, + + _decrypt: function(resultSet, needsDecrypt, password, callback){ + //console.debug("decrypt, resultSet="+resultSet+", needsDecrypt="+needsDecrypt+", password="+password); + + this._totalCrypto = 0; + this._finishedCrypto = 0; + this._finishedSpawningCrypto = false; + this._finalResultSet = resultSet; + + for(var i = 0; i < resultSet.length; i++){ + var row = resultSet[i]; + + // go through each of the column names in row, + // seeing if they need decryption + for(var columnName in row){ + if(needsDecrypt == "*" || needsDecrypt[columnName]){ + this._totalCrypto++; + var columnValue = row[columnName]; + + // forming a closure here can cause issues, with values not cleanly + // saved on Firefox/Mac OS X for some of the values above that + // are needed in the callback below; call a subroutine that will form + // a closure inside of itself instead + this._decryptSingleColumn(columnName, columnValue, password, i, + function(finalResultSet){ + callback(finalResultSet); + }); + } + } + } + + this._finishedSpawningCrypto = true; + }, + + _stripCryptoSQL: function(sql){ + // replace all DECRYPT(*) occurrences with a * + sql = sql.replace(/DECRYPT\(\*\)/ig, "*"); + + // match any ENCRYPT(?, ?, ?, etc) occurrences, + // then replace with just the question marks in the + // middle + var matches = sql.match(/ENCRYPT\([^\)]*\)/ig); + if(matches != null){ + for(var i = 0; i < matches.length; i++){ + var encryptStatement = matches[i]; + var encryptValue = encryptStatement.match(/ENCRYPT\(([^\)]*)\)/i)[1]; + sql = sql.replace(encryptStatement, encryptValue); + } + } + + // match any DECRYPT(COL1, COL2, etc) occurrences, + // then replace with just the column names + // in the middle + matches = sql.match(/DECRYPT\([^\)]*\)/ig); + if(matches != null){ + for(var i = 0; i < matches.length; i++){ + var decryptStatement = matches[i]; + var decryptValue = decryptStatement.match(/DECRYPT\(([^\)]*)\)/i)[1]; + sql = sql.replace(decryptStatement, decryptValue); + } + } + + return sql; + }, + + _flagEncryptedArgs: function(sql, args){ + // capture literal strings that have question marks in them, + // and also capture question marks that stand alone + var tester = new RegExp(/([\"][^\"]*\?[^\"]*[\"])|([\'][^\']*\?[^\']*[\'])|(\?)/ig); + var matches; + var currentParam = 0; + var results = []; + while((matches = tester.exec(sql)) != null){ + var currentMatch = RegExp.lastMatch+""; + + // are we a literal string? then ignore it + if(/^[\"\']/.test(currentMatch)){ + continue; + } + + // do we have an encrypt keyword to our left? + var needsEncrypt = false; + if(/ENCRYPT\([^\)]*$/i.test(RegExp.leftContext)){ + needsEncrypt = true; + } + + // set the encrypted flag + results[currentParam] = needsEncrypt; + + currentParam++; + } + + return results; + }, + + _determineDecryptedColumns: function(sql){ + var results = {}; + + if(/DECRYPT\(\*\)/i.test(sql)){ + results = "*"; + }else{ + var tester = /DECRYPT\((?:\s*\w*\s*\,?)*\)/ig; + var matches; + while(matches = tester.exec(sql)){ + var lastMatch = new String(RegExp.lastMatch); + var columnNames = lastMatch.replace(/DECRYPT\(/i, ""); + columnNames = columnNames.replace(/\)/, ""); + columnNames = columnNames.split(/\s*,\s*/); + dojo.forEach(columnNames, function(column){ + if(/\s*\w* AS (\w*)/i.test(column)){ + column = column.match(/\s*\w* AS (\w*)/i)[1]; + } + results[column] = true; + }); + } + } + + return results; + }, + + _decryptSingleColumn: function(columnName, columnValue, password, currentRowIndex, + callback){ + //console.debug("decryptSingleColumn, columnName="+columnName+", columnValue="+columnValue+", currentRowIndex="+currentRowIndex) + dojox._sql._crypto.decrypt(columnValue, password, dojo.hitch(this, function(results){ + // set the new decrypted value + this._finalResultSet[currentRowIndex][columnName] = results; + this._finishedCrypto++; + + // are we done with all encryption? + if(this._finishedCrypto >= this._totalCrypto + && this._finishedSpawningCrypto){ + //console.debug("done with all decrypts"); + callback(this._finalResultSet); + } + })); + } +}); + +} diff --git a/includes/js/dojox/_sql/demos/customers/customers.html b/includes/js/dojox/_sql/demos/customers/customers.html new file mode 100644 index 0000000..a4c0c03 --- /dev/null +++ b/includes/js/dojox/_sql/demos/customers/customers.html @@ -0,0 +1,292 @@ + + + + + + + + + + + + + +

Dojo SQL Cryptography

+ +

Instructions

+ +

This demo shows Dojo Offline's SQL encryption technologies. In the table below, we have a + sample SQL table that has three columns of data: a last name, a first name, and + a social security number. We don't want to store the social security numbers + in the clear, just in case they are downloaded for offline use to a laptop and the + laptop is stolen.

+ +

To use this demo, enter a password and press the ENCRYPT button to see the Social Security column encrypt. Enter + the same password and press DECRYPT to see it decrypt. If you enter an incorrect password and + press DECRYPT, the Social Security column will remain encrypted and only show gibberish.

+ +

Under the covers we use 256-bit AES encryption and your password to derive the crypto key; we use + a facility in Google Gears to do the cryptography in such a way that the browser does not lock up + during processing. Dojo Offline ties this cryptography into Dojo SQL, providing convenient ENCRYPT() + and DECRYPT() SQL keywords you can use to easily have this functionality in your + own offline applications. To learn how you can use this feature + see here.

+ +
+ + + + + + + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/includes/js/dojox/analytics.js b/includes/js/dojox/analytics.js new file mode 100644 index 0000000..3a07f42 --- /dev/null +++ b/includes/js/dojox/analytics.js @@ -0,0 +1,16 @@ +if(!dojo._hasResource["dojox.analytics"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.analytics"] = true; +dojo.provide("dojox.analytics"); +dojo.require("dojox.analytics._base"); +dojo.require("dojo._base.connect"); +dojo.require("dojo._base.Deferred"); +dojo.require("dojo._base.json"); +dojo.require("dojo._base.array"); +dojo.requireIf(dojo.isBrowser, "dojo._base.window"); +dojo.requireIf(dojo.isBrowser, "dojo._base.event"); +dojo.requireIf(dojo.isBrowser, "dojo._base.html"); +dojo.requireIf(dojo.isBrowser, "dojo._base.NodeList"); +dojo.requireIf(dojo.isBrowser, "dojo._base.query"); +dojo.requireIf(dojo.isBrowser, "dojo._base.xhr"); + +} diff --git a/includes/js/dojox/analytics/README b/includes/js/dojox/analytics/README new file mode 100644 index 0000000..c41cc19 --- /dev/null +++ b/includes/js/dojox/analytics/README @@ -0,0 +1,134 @@ +------------------------------------------------------------------------------- +dojox.analytics +------------------------------------------------------------------------------- +Version 1.0 +Release date: 12/17/2007 +------------------------------------------------------------------------------- +Project state: beta +------------------------------------------------------------------------------- +Project authors + Dustin Machi +------------------------------------------------------------------------------- +Project description + analytics and client monitoring system. Including the base analytics +system and any number of plugins enables logging of different system data +back to the server. Plugins included at this time: + + dojo - reports dojo startup collected information + window - reports available window information to the server + mouseOver - allows periodic sampling of mouseOver + mouseClick - reports any mouse clicks to the server + idle - reports idle/activity + consoleMessages - reports console.* messages to the server + + +------------------------------------------------------------------------------- +Dependencies: + +Dojo Core (package loader). +------------------------------------------------------------------------------- +Documentation + +Usage: + +The primary intended usage will be to create a custom build layer that includes +the particular plugins you need for your project. However in practice you +can use the system as such: + + + + + +When done using a build, none of the dojo.require() statement will be requires +would already be in the build. + +Most of the plugins and the base itself have a number of configurable params +that are passed in via the djConfig variable set. This approach is taken so that +the parameters can be easily provided in the case of a build or for a custom +dojo.js build with analytics built in. Examples for different build profiles +are in the profiles directory. + +Available Configuration Parameters: + + Base Configs + sendInterval - Normal send interval. Default 5000 + sendMethod - "script" || "xhrPost" + inTransitRetry - Delay before retrying an a send if it was in transit + or if there is still data to be sent after a post. + Default 1000 + analyticsUrl - url to send logging data to. defaults to the test php + file for now + maxRequestSize - Maximum size of GET style requests. Capped at 2000 for + IE, and 4000 otherwise + + consoleMessages Config: + + consoleLogFuncs - functions from the console object that you will log to + the server. If the console object doesn't exist + or a particuarl method doesn't exist it will be + created as a remote logging only method. This provides + a quick and convient way to automatically define + a remote logging funciton that includes the functions + name in the log. The 'rlog' in the default paramerters + is an example of this. Defaults to ["error", "warn", "info", "rlog"] + + idle Config: + + idleTime - Number of ms to be idle before being reported to the server as idle + + mouseOver config: + targetProps - the properties whose values will be reported for each target from + a mouse over sample. defaults to ["id","className","localName","href", "spellcheck", "lang", "textContent", "value" ] + + sampleDelay - the delay in ms between mouseover samples. Defaults to 2500 + + window config: + windowConnects - methods on the window objec that will be attached to + have its data passed to the server when called. + + +Note that the basic usage of this system simply serializes json with toJson() when passed +to the analytics addData() method. If data is passed that has circular references +it will die. Take care not to do that or be surprised when it doens't work +in those cases. + + +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/analytics + +Install into the following directory structure: +/dojox/analytics/ + +...which should be at the same level as your Dojo checkout. diff --git a/includes/js/dojox/analytics/_base.js b/includes/js/dojox/analytics/_base.js new file mode 100644 index 0000000..8d6bd66 --- /dev/null +++ b/includes/js/dojox/analytics/_base.js @@ -0,0 +1,127 @@ +if(!dojo._hasResource["dojox.analytics._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.analytics._base"] = true; +dojo.provide("dojox.analytics._base"); + +dojox.analytics = function(){ + //where we store data until we're ready to send it off. + + //the data queue; + this._data = [] ; + + //id of messages for this session/page + this._id=1; + + //some default values + this.sendInterval=dojo.config["sendInterval"] || 5000; + this.inTransitRetry=dojo.config["inTransitRetry"] || 200; + this.dataUrl=dojo.config["analyticsUrl"] || dojo.moduleUrl("dojox.analytics.logger", "dojoxAnalytics.php"); + this.sendMethod = dojo.config["sendMethod"] || "xhrPost"; + if (dojo.isIE){ + this.maxRequestSize = 2000; + }else{ + this.maxRequestSize = dojo.config["maxRequestSize"] || 4000; + } + + //while we can go ahead and being logging as soon as this constructor is completed + //we're not going to schedule pushing data to the server until after the page + //has completed loading + dojo.addOnLoad(this, "schedulePusher"); + dojo.addOnUnload(this, "pushData", true); +}; + +dojo.extend(dojox.analytics, { + schedulePusher: function(interval){ + // summary: + // schedule the data pushing routines to happen in interval ms + setTimeout(dojo.hitch(this, "checkData"), interval||this.sendInterval); + }, + + addData: function(dataType, data){ + // summary: + // add data to the queue. Will be pusshed to the server on the next + // data push + + if (arguments.length>2){ + var d = []; + for(var i=1;i0){ + //clear the queue + this._inTransit=this._data; + this._data=[]; + var def; + switch(this.sendMethod){ + case "script": + def = dojo.io.script.get({url: this.getQueryPacket(), preventCache: 1, callbackParamName: "callback"}); + break; + case "xhrPost": + default: + console.info("post send: ", this._inTransit); + def = dojo.xhrPost({url:this.dataUrl, content: {id: this._id++, data: dojo.toJson(this._inTransit)}}); + break; + } + def.addCallback(this, "onPushComplete"); + return def; + } + return false; + }, + + getQueryPacket: function(){ + while(true){ + var content = {id: this._id++, data: dojo.toJson(this._inTransit)}; + + //FIXME would like a much better way to get the query down to lenght + var query = this.dataUrl + '?' + dojo.objectToQuery(content); + if (query.length>this.maxRequestSize){ + this._data.unshift(this._inTransit.pop()); + this._split=1; + }else{ + //console.log("script send: ", this._inTransit, " Remaining in queue: ", this._data.length); + return query; + } + } + }, + + onPushComplete: function(results){ + // summary + // if our data push was successfully, remove the _inTransit data and schedule the next + // parser run. + if (this._inTransit){ + delete this._inTransit; + } + + if (this._data.length>0){ + this.schedulePusher(this.inTransitRetry); + } else { + this.schedulePusher(); + } + } +}); + +//create the analytics singleton +dojox.analytics = new dojox.analytics(); + +} diff --git a/includes/js/dojox/analytics/logger/JSON.php b/includes/js/dojox/analytics/logger/JSON.php new file mode 100644 index 0000000..4a21ce7 --- /dev/null +++ b/includes/js/dojox/analytics/logger/JSON.php @@ -0,0 +1,724 @@ + + * @author Matt Knapp + * @author Brett Stimmerman + * @copyright 2005 Michal Migurski + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_SLICE', 1); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_STR', 2); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_ARR', 4); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_OBJ', 8); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_CMT', 16); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_LOOSE_TYPE', 10); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_STRICT_TYPE', 11); + +/** + * Converts to and from JSON format. + * + * Brief example of use: + * + * + * // create a new instance of Services_JSON + * $json = new Services_JSON(); + * + * // convert a complexe value to JSON notation, and send it to the browser + * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); + * $output = $json->encode($value); + * + * print($output); + * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] + * + * // accept incoming POST data, assumed to be in JSON notation + * $input = file_get_contents('php://input', 1000000); + * $value = $json->decode($input); + * + */ +class Services_JSON +{ + /** + * constructs a new JSON instance + * + * @param int $use object behavior: when encoding or decoding, + * be loose or strict about object/array usage + * + * possible values: + * - SERVICES_JSON_STRICT_TYPE: strict typing, default. + * "{...}" syntax creates objects in decode(). + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays in decode(). + */ + function Services_JSON($use = SERVICES_JSON_STRICT_TYPE) + { + $this->use = $use; + } + + /** + * convert a string from one UTF-16 char to one UTF-8 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch(true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + function utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $ut8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return string JSON string representation of input var + * @access public + */ + function encode($var) + { + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + return '{' . + join(',', array_map(array($this, 'name_value'), + array_keys($var), + array_values($var))) + . '}'; + } + + // treat it like a regular array + return '[' . join(',', array_map(array($this, 'encode'), $var)) . ']'; + + case 'object': + $vars = get_object_vars($var); + return '{' . + join(',', array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars))) + . '}'; + + default: + return ''; + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + function name_value($name, $value) + { + return $this->encode(strval($name)) . ':' . $this->encode($value); + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) + . chr(hexdec(substr($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + + if ($str{0} == '[') { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, + 'where' => 0, + 'delim' => false)); + + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } + + } + + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + } elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == SERVICES_JSON_IN_STR) && + (($chrs{$c - 1} != '\\') || + ($chrs{$c - 1} == '\\' && $chrs{$c - 2} == '\\'))) { + // found a quote, we're in a string, and it's not escaped + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); + + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + return $obj; + + } + + } + } + } + +} + +?> \ No newline at end of file diff --git a/includes/js/dojox/analytics/logger/dojoxAnalytics.php b/includes/js/dojox/analytics/logger/dojoxAnalytics.php new file mode 100644 index 0000000..0f7f849 --- /dev/null +++ b/includes/js/dojox/analytics/logger/dojoxAnalytics.php @@ -0,0 +1,31 @@ +decode($_REQUEST["data"]); + + if (!$handle = fopen($filename, 'a+')) { + print '{error: "server error"}'; + exit; + } + + foreach($items as $i=>$item){ + $item->_analyticsId = $id; + $item->_analyticsTimeStamp = time(); + $log = $json->encode($item) . "\n"; + fwrite($handle, $log); + } + + fclose($handle); + + $response = "{'eventsRecieved': '" . sizeof($items) . "', 'id': '" . $id . "'}"; + if ($_REQUEST["callback"]){ + print $_REQUEST["callback"] . "(" . $response . ");"; + }else{ + print $response; + } + +?> diff --git a/includes/js/dojox/analytics/plugins/consoleMessages.js b/includes/js/dojox/analytics/plugins/consoleMessages.js new file mode 100644 index 0000000..6b8e0f0 --- /dev/null +++ b/includes/js/dojox/analytics/plugins/consoleMessages.js @@ -0,0 +1,24 @@ +if(!dojo._hasResource["dojox.analytics.plugins.consoleMessages"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.analytics.plugins.consoleMessages"] = true; +dojo.provide("dojox.analytics.plugins.consoleMessages"); + +dojox.analytics.plugins.consoleMessages = new (function(){ + // summary: + // plugin to have analyitcs return the base info dojo collects + this.addData = dojo.hitch(dojox.analytics, "addData", "consoleMessages"); + + var lvls = dojo.config["consoleLogFuncs"] || ["error", "warn", "info", "rlog"]; + if(!console){ + console={}; + } + + for(var i=0; i + + + Dojox Analytics Test + + + + + + + + + + + + + + + + + + +
+

Dijit TitlePane Test

+
+
+ Lorem Ipsum Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Quisque + iaculis, nulla id semper faucibus, pede tellus nonummy magna, vitae adipiscing + orci arcu ut augue. Nunc condimentum, magna a vestibulum convallis, libero purus + pulvinar orci, sed vestibulum urna sem ut pede. More Ipsum... + Sed sollicitudin suscipit risus. Nam ullamcorper. Sed nisl lectus, pellentesque + nec, malesuada eget, ornare a, libero. Lorem ipsum dolor sit amet, + consectetuer adipiscing elit. + + cometdaily.com +
+ +
+ Lorem Ipsum Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Quisque + iaculis, nulla id semper faucibus, pede tellus nonummy magna, vitae adipiscing + orci arcu ut augue. Nunc condimentum, magna a vestibulum convallis, libero purus + pulvinar orci, sed vestibulum urna sem ut pede. More Ipsum... + Sed sollicitudin suscipit risus. Nam ullamcorper. Sed nisl lectus, pellentesque + nec, malesuada eget, ornare a, libero. Lorem ipsum dolor sit amet, + consectetuer adipiscing elit. + + dojotoolkit.org +
+
+ + diff --git a/includes/js/dojox/av.js b/includes/js/dojox/av.js new file mode 100644 index 0000000..268a6b3 --- /dev/null +++ b/includes/js/dojox/av.js @@ -0,0 +1,7 @@ +if(!dojo._hasResource["dojox.av"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.av"] = true; +dojo.provide("dojox.av"); + +dojo.require("dojox.av._base"); + +} diff --git a/includes/js/dojox/av/README b/includes/js/dojox/av/README new file mode 100644 index 0000000..828aa40 --- /dev/null +++ b/includes/js/dojox/av/README @@ -0,0 +1,40 @@ +------------------------------------------------------------------------------- +DojoX Audio/Video +------------------------------------------------------------------------------- +Version 0.1 +Release date: 01/15/2008 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + Tom Trenka (ttrenka AT gmail.com) +------------------------------------------------------------------------------- +Project description + +DojoX A/V aims to bring audio and video capabilities to the Open Web, first +by wrapping common media types (Flash and Quicktime) and then by providing +easy to use objects to accomplish basic A/V tasks. As of version 0.1, only +the base is included (Flash and Quicktime embedding mechanisms); in the near +future, usable objects will appear, both in raw programmatic form and also with +Dijit-compatible wrappers. +------------------------------------------------------------------------------- +Dependencies: + +DojoX A/V has no dependencies outside of the Dojo Base. +------------------------------------------------------------------------------- +Documentation + +TBD. +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/av.js +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/av/* + +Install into the following directory structure: +/dojox/av/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- diff --git a/includes/js/dojox/av/_base.js b/includes/js/dojox/av/_base.js new file mode 100644 index 0000000..540a751 --- /dev/null +++ b/includes/js/dojox/av/_base.js @@ -0,0 +1,8 @@ +if(!dojo._hasResource["dojox.av._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.av._base"] = true; +dojo.provide("dojox.av._base"); + +dojo.require("dojox.av._base.flash"); +dojo.require("dojox.av._base.quicktime"); + +} diff --git a/includes/js/dojox/av/_base/_ieFlash.js b/includes/js/dojox/av/_base/_ieFlash.js new file mode 100644 index 0000000..80869fd --- /dev/null +++ b/includes/js/dojox/av/_base/_ieFlash.js @@ -0,0 +1,17 @@ +// *** Fricking Eolas. This is here to get around the Eolas issue. Sigh. *************** +dojox.av.flash.place = function(node, kwArgs){ + node=dojo.byId(node); + var o = dojox.av.flash.__ie_markup__(kwArgs); + if(o){ + node.innerHTML = o.markup; + return window[o.id]; + } + return null; +} +if(dojo._initFired){ + dojox.av.flash.onInitialize(); +} else { + dojo.addOnLoad(function(){ + dojox.av.flash.onInitialize(); + }); +} diff --git a/includes/js/dojox/av/_base/flash.js b/includes/js/dojox/av/_base/flash.js new file mode 100644 index 0000000..f1eb27c --- /dev/null +++ b/includes/js/dojox/av/_base/flash.js @@ -0,0 +1,186 @@ +if(!dojo._hasResource["dojox.av._base.flash"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.av._base.flash"] = true; +dojo.provide("dojox.av._base.flash"); + +(function(){ + /******************************************************* + dojox.av.flash + + Base functionality to insert a flash movie into + a document on the fly. + + Support for Flash 6 is dropped in favor of Flash 8; + multiple movies are supported. + ******************************************************/ + + // TODO: solve the Eolas problem, the function that actually pushes + // Flash movie into the doc must be loaded from an external script. + + // TODO: add Brad's ExpressInstall for automated installation. + + var fMarkup, fVersion, __def__={ + expressInstall: false, + width: 320, + height: 240, + style: null, + redirect: null, + params: [] + }; + var keyBase="dojox-av-flash-", keyCount=0; + function prep(kwArgs){ + kwArgs=dojo.mixin(dojo.clone(__def__), kwArgs || {}); + if(!("path" in kwArgs)){ + console.error("dojox.av._base.flash(ctor):: no path reference to a Flash movie was provided."); + return null; + } + if(!("id" in kwArgs)){ + kwArgs.id=(keyBase + keyCount++); + } + return kwArgs; + } + + if(dojo.isIE){ + // *** Internet Explorer branch ****************************************************************** + fMarkup=function(kwArgs){ + kwArgs=prep(kwArgs); + if(!kwArgs){ return null; } + var s='' + + ''; + for(var i=0, l=kwArgs.params.length; i'; + } + s += ''; + return { id: kwArgs.id, markup: s }; + }; + + fVersion=(function(){ + var testVersion=10, testObj=null; + while(!testObj && testVersion > 7){ + try { + testObj = new ActiveXObject("ShockwaveFlash.ShockwaveFlash." + testVersion--); + } catch(e){ } + } + if(testObj){ + var v = testObj.GetVariable("$version").split(" ")[1].split(","); + return { + major: (v[0]!=null)?parseInt(v[0]):0, + minor: (v[1]!=null)?parseInt(v[1]):0, + rev: (v[2]!=null)?parseInt(v[2]):0 + }; + } + return { major: 0, minor: 0, rev: 0 }; + })(); + + // attach some cleanup for IE, thanks to deconcept :) + dojo.addOnUnload(function(){ + var objs=dojo.query("object"); + for(var i=objs.length-1; i>=0; i--){ + objs[i].style.display="none"; + for(var p in objs[i]){ + if(p!="FlashVars" && dojo.isFunction(objs[i][p])){ + objs[i][p]=function(){ }; + } + } + } + }); + + // TODO: ...and double check this fix; is IE really firing onbeforeunload with any kind of href="#" link? + var beforeUnloadHandle = dojo.connect(dojo.global, "onbeforeunload", function(){ + try{ + if(__flash_unloadHandler){ __flash_unloadHandler=function(){ }; } + if(__flash_savedUnloadHandler){ __flash_savedUnloadHandler=function(){ }; } + } catch(e){ } + dojo.disconnect(beforeUnloadHandle); + }); + } else { + // *** Sane browsers branch ****************************************************************** + fMarkup=function(kwArgs){ + kwArgs=prep(kwArgs); + if(!kwArgs){ return null; } + var s = '= 8), + version: fVersion, + initialized: false, + onInitialize: function(){ + dojox.av.flash.initialized=true; + }, + __ie_markup__: function(kwArgs){ + return fMarkup(kwArgs); + } + }; + + if(dojo.isIE){ + // Ugh! + if(dojo._initFired){ + var e=document.createElement("script"); + e.type="text/javascript"; + e.src=dojo.moduleUrl("dojox", "av/_base/_ieFlash.js"); + e.defer=true; + document.getElementsByTagName("head")[0].appendChild(e); + } else { + // we can use document.write. What a kludge. + document.write('' + + ''); + } + } else { + dojox.av.flash.place = function(node, kwArgs){ + node=dojo.byId(node); + var o = fMarkup(kwArgs); + if(o){ + node.innerHTML = o.markup; + return document[o.id]; + } + return null; + } + + if(dojo._initFired){ + dojox.av.flash.onInitialize(); + } else { + dojo.addOnLoad(function(){ + console.log("firing off dojox.av.flash.onInitialize() for sane browsers."); + dojox.av.flash.onInitialize(); + }); + } + } +})(); + +} diff --git a/includes/js/dojox/av/_base/quicktime.js b/includes/js/dojox/av/_base/quicktime.js new file mode 100644 index 0000000..0c23a9e --- /dev/null +++ b/includes/js/dojox/av/_base/quicktime.js @@ -0,0 +1,161 @@ +if(!dojo._hasResource["dojox.av._base.quicktime"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.av._base.quicktime"] = true; +dojo.provide("dojox.av._base.quicktime"); + +(function(){ + /******************************************************* + dojox.av.quicktime + + Base functionality to insert a QuickTime movie + into a document on the fly. + ******************************************************/ + + var qtMarkup, qtVersion, installed, __def__={ + width: 320, + height: 240, + redirect: null, + params: [] + }; + var keyBase="dojox-av-quicktime-", keyCount=0; + + // reference to the test movie we will use for getting QT info from the browser. + var testMovieUrl=dojo.moduleUrl("dojox", "av/resources/version.mov"); + + // *** private methods ********************************************************* + function prep(kwArgs){ + kwArgs = dojo.mixin(dojo.clone(__def__), kwArgs || {}); + if(!("path" in kwArgs)){ + console.error("dojox.av._base.quicktime(ctor):: no path reference to a QuickTime movie was provided."); + return null; + } + if(!("id" in kwArgs)){ + kwArgs.id=(keyBase + keyCount++); + } + return kwArgs; + } + + var getQTMarkup = 'This content requires the QuickTime plugin.'; + if(dojo.isIE){ + installed = (function(){ + try{ + var o = new ActiveXObject("QuickTimeCheckObject.QuickTimeCheck.1"); + if(o!==undefined){ + return o.IsQuickTimeAvailable(0); + } + } catch(e){ } + return false; + })(); + + qtMarkup = function(kwArgs){ + if(!installed){ return { id: null, markup: getQTMarkup }; } + + kwArgs = prep(kwArgs); + if(!kwArgs){ return null; } + var s = '' + + ''; + for(var i=0, l=kwArgs.params.length; i'; + } + s += ''; + return { id: kwArgs.id, markup: s }; + } + } else { + installed = (function(){ + for(var i=0, l=navigator.plugins.length; i-1){ + return true; + } + } + return false; + })(); + + qtMarkup = function(kwArgs){ + if(!installed){ return { id: null, markup: getQTMarkup }; } + + kwArgs = prep(kwArgs); + if(!kwArgs){ return null; } + var s = ' + + DojoX A/V Flash Detection Test + + + + + + +

DojoX A/V: Flash detection tests.

+

+ This page is testing the base Flash movie generator. +

+

Installed Flash version: .

+
+ A movie will be inserted here on load. +
+ + diff --git a/includes/js/dojox/av/tests/quicktime.html b/includes/js/dojox/av/tests/quicktime.html new file mode 100644 index 0000000..48e1426 --- /dev/null +++ b/includes/js/dojox/av/tests/quicktime.html @@ -0,0 +1,24 @@ + + + DojoX A/V QuickTime Detection Test + + + + + + +

DojoX A/V: QuickTime detection tests.

+

+ This page is testing the base QuickTime movie generator. See the Firebug log for details. +

+

Installed QuickTime version: .

+ + diff --git a/includes/js/dojox/av/tests/resources/hfp.swf b/includes/js/dojox/av/tests/resources/hfp.swf new file mode 100644 index 0000000..b878f69 Binary files /dev/null and b/includes/js/dojox/av/tests/resources/hfp.swf differ diff --git a/includes/js/dojox/charting/Chart2D.js b/includes/js/dojox/charting/Chart2D.js new file mode 100644 index 0000000..27be653 --- /dev/null +++ b/includes/js/dojox/charting/Chart2D.js @@ -0,0 +1,341 @@ +if(!dojo._hasResource["dojox.charting.Chart2D"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.Chart2D"] = true; +dojo.provide("dojox.charting.Chart2D"); + +dojo.require("dojox.gfx"); +dojo.require("dojox.lang.functional"); +dojo.require("dojox.lang.functional.fold"); +dojo.require("dojox.lang.functional.reversed"); + +dojo.require("dojox.charting.Theme"); +dojo.require("dojox.charting.Series"); + +dojo.require("dojox.charting.axis2d.Default"); + +dojo.require("dojox.charting.plot2d.Default"); +dojo.require("dojox.charting.plot2d.Lines"); +dojo.require("dojox.charting.plot2d.Areas"); +dojo.require("dojox.charting.plot2d.Markers"); +dojo.require("dojox.charting.plot2d.MarkersOnly"); +dojo.require("dojox.charting.plot2d.Scatter"); +dojo.require("dojox.charting.plot2d.Stacked"); +dojo.require("dojox.charting.plot2d.StackedLines"); +dojo.require("dojox.charting.plot2d.StackedAreas"); +dojo.require("dojox.charting.plot2d.Columns"); +dojo.require("dojox.charting.plot2d.StackedColumns"); +dojo.require("dojox.charting.plot2d.ClusteredColumns"); +dojo.require("dojox.charting.plot2d.Bars"); +dojo.require("dojox.charting.plot2d.StackedBars"); +dojo.require("dojox.charting.plot2d.ClusteredBars"); +dojo.require("dojox.charting.plot2d.Grid"); +dojo.require("dojox.charting.plot2d.Pie"); + +(function(){ + var df = dojox.lang.functional, dc = dojox.charting, + clear = df.lambda("item.clear()"), + purge = df.lambda("item.purgeGroup()"), + destroy = df.lambda("item.destroy()"), + makeClean = df.lambda("item.dirty = false"), + makeDirty = df.lambda("item.dirty = true"); + + dojo.declare("dojox.charting.Chart2D", null, { + constructor: function(node, kwArgs){ + // initialize parameters + if(!kwArgs){ kwArgs = {}; } + this.margins = kwArgs.margins ? kwArgs.margins : {l: 10, t: 10, r: 10, b: 10}; + this.stroke = kwArgs.stroke; + this.fill = kwArgs.fill; + + // default initialization + this.theme = null; + this.axes = {}; // map of axes + this.stack = []; // stack of plotters + this.plots = {}; // map of plotter indices + this.series = []; // stack of data runs + this.runs = {}; // map of data run indices + this.dirty = true; + this.coords = null; + + // create a surface + this.node = dojo.byId(node); + var box = dojo.marginBox(node); + this.surface = dojox.gfx.createSurface(this.node, box.w, box.h); + }, + destroy: function(){ + dojo.forEach(this.series, destroy); + dojo.forEach(this.stack, destroy); + df.forIn(this.axes, destroy); + }, + getCoords: function(){ + if(!this.coords){ + this.coords = dojo.coords(this.node, true); + } + return this.coords; + }, + setTheme: function(theme){ + this.theme = theme; + this.dirty = true; + return this; + }, + addAxis: function(name, kwArgs){ + var axis; + if(!kwArgs || !("type" in kwArgs)){ + axis = new dc.axis2d.Default(this, kwArgs); + }else{ + axis = typeof kwArgs.type == "string" ? + new dc.axis2d[kwArgs.type](this, kwArgs) : + new kwArgs.type(this, kwArgs); + } + axis.name = name; + axis.dirty = true; + if(name in this.axes){ + this.axes[name].destroy(); + } + this.axes[name] = axis; + this.dirty = true; + return this; + }, + addPlot: function(name, kwArgs){ + var plot; + if(!kwArgs || !("type" in kwArgs)){ + plot = new dc.plot2d.Default(this, kwArgs); + }else{ + plot = typeof kwArgs.type == "string" ? + new dc.plot2d[kwArgs.type](this, kwArgs) : + new kwArgs.type(this, kwArgs); + } + plot.name = name; + plot.dirty = true; + if(name in this.plots){ + this.stack[this.plots[name]].destroy(); + this.stack[this.plots[name]] = plot; + }else{ + this.plots[name] = this.stack.length; + this.stack.push(plot); + } + this.dirty = true; + return this; + }, + addSeries: function(name, data, kwArgs){ + var run = new dc.Series(this, data, kwArgs); + if(name in this.runs){ + this.series[this.runs[name]].destroy(); + this.series[this.runs[name]] = run; + }else{ + this.runs[name] = this.series.length; + this.series.push(run); + } + this.dirty = true; + // fix min/max + if(!("ymin" in run) && "min" in run){ run.ymin = run.min; } + if(!("ymax" in run) && "max" in run){ run.ymax = run.max; } + return this; + }, + updateSeries: function(name, data){ + if(name in this.runs){ + var run = this.series[this.runs[name]], + plot = this.stack[this.plots[run.plot]], axis; + run.data = data; + run.dirty = true; + // check to see if axes and plot should be updated + if(plot.hAxis){ + axis = this.axes[plot.hAxis]; + if(axis.dependOnData()){ + axis.dirty = true; + // find all plots and mark them dirty + dojo.forEach(this.stack, function(p){ + if(p.hAxis && p.hAxis == plot.hAxis){ + p.dirty = true; + } + }); + } + }else{ + plot.dirty = true; + } + if(plot.vAxis){ + axis = this.axes[plot.vAxis]; + if(axis.dependOnData()){ + axis.dirty = true; + // find all plots and mark them dirty + dojo.forEach(this.stack, function(p){ + if(p.vAxis && p.vAxis == plot.vAxis){ + p.dirty = true; + } + }); + } + }else{ + plot.dirty = true; + } + } + return this; + }, + resize: function(width, height){ + var box; + switch(arguments.length){ + case 0: + box = dojo.marginBox(this.node); + break; + case 1: + box = width; + break; + default: + box = {w: width, h: height}; + break; + } + dojo.marginBox(this.node, box); + this.surface.setDimensions(box.w, box.h); + this.dirty = true; + this.coords = null; + return this.render(); + }, + render: function(){ + if(this.dirty){ + return this.fullRender(); + } + + // calculate geometry + dojo.forEach(this.stack, function(plot){ + if(plot.dirty || (plot.hAxis && this.axes[plot.hAxis].dirty) || + (plot.vAxis && this.axes[plot.vAxis].dirty)){ + plot.calculateAxes(this.plotArea); + } + }, this); + + // go over the stack backwards + df.forEachRev(this.stack, function(plot){ plot.render(this.dim, this.offsets); }, this); + + // go over axes + df.forIn(this.axes, function(axis){ axis.render(this.dim, this.offsets); }, this); + + this._makeClean(); + + // BEGIN FOR HTML CANVAS + if(this.surface.render){ this.surface.render(); }; + // END FOR HTML CANVAS + + return this; + }, + fullRender: function(){ + this._makeDirty(); + + // clear old values + dojo.forEach(this.stack, clear); + dojo.forEach(this.series, purge); + df.forIn(this.axes, purge); + dojo.forEach(this.stack, purge); + this.surface.clear(); + + // rebuild new connections, and add defaults + + // assign series + dojo.forEach(this.series, function(run){ + if(!(run.plot in this.plots)){ + var plot = new dc.plot2d.Default(this, {}); + plot.name = run.plot; + this.plots[run.plot] = this.stack.length; + this.stack.push(plot); + } + this.stack[this.plots[run.plot]].addSeries(run); + }, this); + // assign axes + dojo.forEach(this.stack, function(plot){ + if(plot.hAxis){ + plot.setAxis(this.axes[plot.hAxis]); + } + if(plot.vAxis){ + plot.setAxis(this.axes[plot.vAxis]); + } + }, this); + // set up a theme + if(!this.theme){ + this.theme = new dojox.charting.Theme(dojox.charting._def); + } + var requiredColors = df.foldl(this.stack, "z + plot.getRequiredColors()", 0); + this.theme.defineColors({num: requiredColors, cache: false}); + + // calculate geometry + + // 1st pass + var dim = this.dim = this.surface.getDimensions(); + dim.width = dojox.gfx.normalizedLength(dim.width); + dim.height = dojox.gfx.normalizedLength(dim.height); + df.forIn(this.axes, clear); + dojo.forEach(this.stack, function(plot){ plot.calculateAxes(dim); }); + + // assumption: we don't have stacked axes yet + var offsets = this.offsets = {l: 0, r: 0, t: 0, b: 0}; + df.forIn(this.axes, function(axis){ + df.forIn(axis.getOffsets(), function(o, i){ offsets[i] += o; }); + }); + // add margins + df.forIn(this.margins, function(o, i){ offsets[i] += o; }); + + // 2nd pass with realistic dimensions + this.plotArea = {width: dim.width - offsets.l - offsets.r, height: dim.height - offsets.t - offsets.b}; + df.forIn(this.axes, clear); + dojo.forEach(this.stack, function(plot){ plot.calculateAxes(this.plotArea); }, this); + + // generate shapes + + // draw a chart background + var t = this.theme, + fill = this.fill ? this.fill : (t.chart && t.chart.fill), + stroke = this.stroke ? this.stroke : (t.chart && t.chart.stroke); + if(fill){ + this.surface.createRect({ + width: dim.width, + height: dim.height + }).setFill(fill); + } + if(stroke){ + this.surface.createRect({ + width: dim.width - 1, + height: dim.height - 1 + }).setStroke(stroke); + } + // draw a plot background + fill = t.plotarea && t.plotarea.fill; + stroke = t.plotarea && t.plotarea.stroke; + if(fill){ + this.surface.createRect({ + x: offsets.l, y: offsets.t, + width: dim.width - offsets.l - offsets.r, + height: dim.height - offsets.t - offsets.b + }).setFill(fill); + } + if(stroke){ + this.surface.createRect({ + x: offsets.l, y: offsets.t, + width: dim.width - offsets.l - offsets.r - 1, + height: dim.height - offsets.t - offsets.b - 1 + }).setStroke(stroke); + } + + // go over the stack backwards + df.foldr(this.stack, function(z, plot){ return plot.render(dim, offsets), 0; }, 0); + + // go over axes + df.forIn(this.axes, function(axis){ axis.render(dim, offsets); }); + + this._makeClean(); + + return this; + }, + _makeClean: function(){ + // reset dirty flags + dojo.forEach(this.axes, makeClean); + dojo.forEach(this.stack, makeClean); + dojo.forEach(this.series, makeClean); + this.dirty = false; + }, + _makeDirty: function(){ + // reset dirty flags + dojo.forEach(this.axes, makeDirty); + dojo.forEach(this.stack, makeDirty); + dojo.forEach(this.series, makeDirty); + this.dirty = true; + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/Chart3D.js b/includes/js/dojox/charting/Chart3D.js new file mode 100644 index 0000000..86dfd59 --- /dev/null +++ b/includes/js/dojox/charting/Chart3D.js @@ -0,0 +1,86 @@ +if(!dojo._hasResource["dojox.charting.Chart3D"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.Chart3D"] = true; +dojo.provide("dojox.charting.Chart3D"); + +dojo.require("dojox.gfx3d"); + +(function(){ + var observerVector = {x: 0, y: 0, z: 1}, v = dojox.gfx3d.vector, n = dojox.gfx.normalizedLength; + + dojo.declare("dojox.charting.Chart3D", null, { + constructor: function(node, lights, camera, theme){ + // setup a view + this.node = dojo.byId(node); + this.surface = dojox.gfx.createSurface(this.node, n(this.node.style.width), n(this.node.style.height)); + this.view = this.surface.createViewport(); + this.view.setLights(lights.lights, lights.ambient, lights.specular); + this.view.setCameraTransform(camera); + this.theme = theme; + + // initialize internal variables + this.walls = []; + this.plots = []; + }, + + // public API + generate: function(){ + return this._generateWalls()._generatePlots(); + }, + invalidate: function(){ + this.view.invalidate(); + return this; + }, + render: function(){ + this.view.render(); + return this; + }, + addPlot: function(plot){ + return this._add(this.plots, plot); + }, + removePlot: function(plot){ + return this._remove(this.plots, plot); + }, + addWall: function(wall){ + return this._add(this.walls, wall); + }, + removeWall: function(wall){ + return this._remove(this.walls, wall); + }, + + // internal API + _add: function(array, item){ + if(!dojo.some(array, function(i){ return i == item; })){ + array.push(item); + this.view.invalidate(); + } + return this; + }, + _remove: function(array, item){ + var a = dojo.filter(array, function(i){ return i != item; }); + return a.length < array.length ? (array = a, this.invalidate()) : this; + }, + _generateWalls: function(){ + for(var i = 0; i < this.walls.length; ++i){ + if(v.dotProduct(observerVector, this.walls[i].normal) > 0){ + this.walls[i].generate(this); + } + } + return this; + }, + _generatePlots: function(){ + var depth = 0, m = dojox.gfx3d.matrix, i = 0; + for(; i < this.plots.length; ++i){ + depth += this.plots[i].getDepth(); + } + for(--i; i >= 0; --i){ + var scene = this.view.createScene(); + scene.setTransform(m.translate(0, 0, -depth)); + this.plots[i].generate(this, scene); + depth -= this.plots[i].getDepth(); + } + return this; + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/Element.js b/includes/js/dojox/charting/Element.js new file mode 100644 index 0000000..f6bdc5d --- /dev/null +++ b/includes/js/dojox/charting/Element.js @@ -0,0 +1,49 @@ +if(!dojo._hasResource["dojox.charting.Element"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.Element"] = true; +dojo.provide("dojox.charting.Element"); + +dojo.declare("dojox.charting.Element", null, { + constructor: function(chart){ + this.chart = chart; + this.group = null; + this.htmlElements = []; + this.dirty = true; + }, + createGroup: function(creator){ + if(!creator){ creator = this.chart.surface; } + if(!this.group){ + this.group = creator.createGroup(); + } + return this; + }, + purgeGroup: function(){ + this.destroyHtmlElements(); + if(this.group){ + this.group.clear(); + this.group.removeShape(); + this.group = null; + } + this.dirty = true; + return this; + }, + cleanGroup: function(creator){ + this.destroyHtmlElements(); + if(!creator){ creator = this.chart.surface; } + if(this.group){ + this.group.clear(); + }else{ + this.group = creator.createGroup(); + } + this.dirty = true; + return this; + }, + destroyHtmlElements: function(){ + dojo.forEach(this.htmlElements, dojo._destroyElement); + this.htmlElements = []; + }, + destroy: function(){ + this.purgeGroup(); + } +}); + +} diff --git a/includes/js/dojox/charting/README b/includes/js/dojox/charting/README new file mode 100644 index 0000000..0858f3a --- /dev/null +++ b/includes/js/dojox/charting/README @@ -0,0 +1,31 @@ +------------------------------------------------------------------------------- +dojox.charting +------------------------------------------------------------------------------- +Version 0.800 +Release date: 10/31/2007 +------------------------------------------------------------------------------- +Project state: +beta +------------------------------------------------------------------------------- +Credits + Tom Trenka (ttrenka@gmail.com) + Eugene Lazutkin (eugene.lazutkin@gmail.com) +------------------------------------------------------------------------------- +Project description + +Implementation of simple charting library based on dojox.gfx/dojox.gfx3d. +------------------------------------------------------------------------------- +Dependencies: + +Dojo Core, dojox.gfx, dojox.gfx3d, dojox.lang. +------------------------------------------------------------------------------- +Documentation + +Not ready yet. +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/ +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/ +------------------------------------------------------------------------------- diff --git a/includes/js/dojox/charting/Series.js b/includes/js/dojox/charting/Series.js new file mode 100644 index 0000000..06115ec --- /dev/null +++ b/includes/js/dojox/charting/Series.js @@ -0,0 +1,20 @@ +if(!dojo._hasResource["dojox.charting.Series"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.Series"] = true; +dojo.provide("dojox.charting.Series"); + +dojo.require("dojox.charting.Element"); + +dojo.declare("dojox.charting.Series", dojox.charting.Element, { + constructor: function(chart, data, kwArgs){ + dojo.mixin(this, kwArgs); + if(typeof this.plot != "string"){ this.plot = "default"; } + this.data = data; + this.dirty = true; + this.clear(); + }, + clear: function(){ + this.dyn = {}; + } +}); + +} diff --git a/includes/js/dojox/charting/Theme.js b/includes/js/dojox/charting/Theme.js new file mode 100644 index 0000000..c7e3a6a --- /dev/null +++ b/includes/js/dojox/charting/Theme.js @@ -0,0 +1,256 @@ +if(!dojo._hasResource["dojox.charting.Theme"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.Theme"] = true; +dojo.provide("dojox.charting.Theme"); +dojo.require("dojox.charting._color"); + +(function(){ + var dxc=dojox.charting; + // TODO: Legend information + + dxc.Theme = function(/*Object?*/ kwArgs){ + kwArgs=kwArgs||{}; + var def = dxc.Theme._def; + dojo.forEach(["chart", "plotarea", "axis", "series", "marker"], function(n){ + this[n] = dojo.mixin(dojo.clone(def[n]), kwArgs[n]||{}); + }, this); + this.markers = dojo.mixin(dojo.clone(dxc.Theme.Markers), kwArgs.markers||{}); + this.colors = []; + this.antiAlias = ("antiAlias" in kwArgs)?kwArgs.antiAlias:true; + this.assignColors = ("assignColors" in kwArgs)?kwArgs.assignColors:true; + this.assignMarkers = ("assignMarkers" in kwArgs)?kwArgs.assignMarkers:true; + this._colorCache = null; + + // push the colors, use _def colors if none passed. + kwArgs.colors = kwArgs.colors||def.colors; + dojo.forEach(kwArgs.colors, function(item){ + this.colors.push(item); + }, this); + + // private variables for color and marker indexing + this._current = { color:0, marker: 0 }; + this._markers = []; + this._buildMarkerArray(); + }; + + // "static" fields + // default markers. + // A marker is defined by an SVG path segment; it should be defined as + // relative motion, and with the assumption that the path segment + // will be moved to the value point (i.e prepend Mx,y) + dxc.Theme.Markers={ + CIRCLE: "m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0", + SQUARE: "m-3,-3 l0,6 6,0 0,-6 z", + DIAMOND: "m0,-3 l3,3 -3,3 -3,-3 z", + CROSS: "m0,-3 l0,6 m-3,-3 l6,0", + X: "m-3,-3 l6,6 m0,-6 l-6,6", + TRIANGLE: "m-3,3 l3,-6 3,6 z", + TRIANGLE_INVERTED:"m-3,-3 l3,6 3,-6 z" + }; + dxc.Theme._def={ + // all objects are structs used directly in dojox.gfx + chart:{ + stroke:null, + fill: "white" + }, + plotarea:{ + stroke:null, + fill: "white" + }, + // TODO: label rotation on axis + axis:{ + stroke: { // the axis itself + color:"#333", + width:1 + }, + line: { // gridlines + color:"#ccc", + width:1, + style:"Dot", + cap:"round" + }, + majorTick: { // major ticks on axis + color:"#666", + width:1, + length:6, + position:"center" + }, + minorTick: { // minor ticks on axis + color:"#666", + width:0.8, + length:3, + position:"center" + }, + font: "normal normal normal 7pt Tahoma", // labels on axis + fontColor:"#333" // color of labels + }, + series:{ + outline: {width: 0.1, color: "#ccc"}, // line or outline + stroke: {width: 1.5, color: "#333"}, // line or outline + fill: "#ccc", // fill, if appropriate + font: "normal normal normal 7pt Tahoma", // if there's a label + fontColor: "#000" // color of labels + }, + marker:{ // any markers on a series. + stroke: {width:1}, // stroke or outline + fill: "#333", // fill if needed + font: "normal normal normal 7pt Tahoma", // label + fontColor: "#000" + }, + colors:[ + "#000","#111","#222","#333", + "#444","#555","#666","#777", + "#888","#999","#aaa","#bbb", + "#ccc" + ] + }; + + // prototype methods + dojo.extend(dxc.Theme, { + defineColors: function(obj){ + // summary: + // Generate a set of colors for the theme based on keyword + // arguments + var kwArgs=obj||{}; + + // deal with caching + var cache = false; + if(kwArgs.cache === undefined){ cache = true; } + if(kwArgs.cache == true){ cache = true; } + + if(cache){ + this._colorCache=kwArgs; + } else { + var mix=this._colorCache||{}; + kwArgs=dojo.mixin(dojo.clone(mix), kwArgs); + } + + var c=[], n=kwArgs.num||32; // the number of colors to generate + if(kwArgs.colors){ + // we have an array of colors predefined, so fix for the number of series. + var l=kwArgs.colors.length; + for(var i=0; i 0){ min = 0; } + if(max < 0){ max = 0; } + } + var minMinorStep = 0, ta = this.chart.theme.axis, + taFont = "font" in this.opt ? this.opt.font : ta.font, + size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0; + if(this.vertical){ + if(size){ + minMinorStep = size + labelGap; + } + }else{ + if(size){ + var labelWidth, i; + if(this.labels){ + labelWidth = df.foldl(df.map(this.labels, function(label){ + return dojox.gfx._base._getTextBox(label.text, {font: taFont}).w; + }), "Math.max(a, b)", 0); + }else{ + var labelLength = Math.ceil(Math.log(Math.max(Math.abs(min), Math.abs(max))) / Math.LN10), t = []; + if(min < 0 || max < 0){ t.push("-"); } + for(i = 0; i < labelLength; ++i){ t.push("9"); } + var precision = Math.floor(Math.log(max - min) / Math.LN10); + if(precision > 0){ + t.push("."); + for(i = 0; i < precision; ++i){ t.push("9"); } + } + labelWidth = dojox.gfx._base._getTextBox(t.join(""), {font: taFont}).w; + } + minMinorStep = labelWidth + labelGap; + } + } + var kwArgs = { + fixUpper: this.opt.fixUpper, + fixLower: this.opt.fixLower, + natural: this.opt.natural + }; + if("majorTickStep" in this.opt){ kwArgs.majorTick = this.opt.majorTickStep; } + if("minorTickStep" in this.opt){ kwArgs.minorTick = this.opt.minorTickStep; } + if("microTickStep" in this.opt){ kwArgs.microTick = this.opt.microTickStep; } + this.scaler = dojox.charting.scaler(min, max, span, kwArgs); + this.scaler.minMinorStep = minMinorStep; + return this; + }, + getScaler: function(){ + return this.scaler; + }, + getOffsets: function(){ + var offsets = {l: 0, r: 0, t: 0, b: 0}, s, labelWidth, gtb, a, b, c, d; + var offset = 0, ta = this.chart.theme.axis, + taFont = "font" in this.opt ? this.opt.font : ta.font, + taMajorTick = "majorTick" in this.opt ? this.opt.majorTick : ta.majorTick, + taMinorTick = "minorTick" in this.opt ? this.opt.minorTick : ta.minorTick, + size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0; + if(this.vertical){ + if(size){ + s = this.scaler; + if(this.labels){ + labelWidth = df.foldl(df.map(this.labels, function(label){ + return dojox.gfx._base._getTextBox(label.text, {font: taFont}).w; + }), "Math.max(a, b)", 0); + }else{ + gtb = dojox.gfx._base._getTextBox; + a = gtb(this._getLabel(s.major.start, s.major.prec), {font: taFont}).w; + b = gtb(this._getLabel(s.major.start + s.major.count * s.major.tick, s.major.prec), {font: taFont}).w; + c = gtb(this._getLabel(s.minor.start, s.minor.prec), {font: taFont}).w; + d = gtb(this._getLabel(s.minor.start + s.minor.count * s.minor.tick, s.minor.prec), {font: taFont}).w; + labelWidth = Math.max(a, b, c, d); + } + offset = labelWidth + labelGap; + } + offset += labelGap + Math.max(taMajorTick.length, taMinorTick.length); + offsets[this.opt.leftBottom ? "l" : "r"] = offset; + offsets.t = offsets.b = size / 2; + }else{ + if(size){ + offset = size + labelGap; + } + offset += labelGap + Math.max(taMajorTick.length, taMinorTick.length); + offsets[this.opt.leftBottom ? "b" : "t"] = offset; + if(size){ + s = this.scaler; + if(this.labels){ + labelWidth = df.foldl(df.map(this.labels, function(label){ + return dojox.gfx._base._getTextBox(label.text, {font: taFont}).w; + }), "Math.max(a, b)", 0); + }else{ + gtb = dojox.gfx._base._getTextBox; + a = gtb(this._getLabel(s.major.start, s.major.prec), {font: taFont}).w; + b = gtb(this._getLabel(s.major.start + s.major.count * s.major.tick, s.major.prec), {font: taFont}).w; + c = gtb(this._getLabel(s.minor.start, s.minor.prec), {font: taFont}).w; + d = gtb(this._getLabel(s.minor.start + s.minor.count * s.minor.tick, s.minor.prec), {font: taFont}).w; + labelWidth = Math.max(a, b, c, d); + } + offsets.l = offsets.r = labelWidth / 2; + } + } + return offsets; + }, + render: function(dim, offsets){ + if(!this.dirty){ return this; } + // prepare variable + var start, stop, axisVector, tickVector, labelOffset, labelAlign, + ta = this.chart.theme.axis, + taStroke = "stroke" in this.opt ? this.opt.stroke : ta.stroke, + taMajorTick = "majorTick" in this.opt ? this.opt.majorTick : ta.majorTick, + taMinorTick = "minorTick" in this.opt ? this.opt.minorTick : ta.minorTick, + taFont = "font" in this.opt ? this.opt.font : ta.font, + taFontColor = "fontColor" in this.opt ? this.opt.fontColor : ta.fontColor, + tickSize = Math.max(taMajorTick.length, taMinorTick.length), + size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0; + if(this.vertical){ + start = {y: dim.height - offsets.b}; + stop = {y: offsets.t}; + axisVector = {x: 0, y: -1}; + if(this.opt.leftBottom){ + start.x = stop.x = offsets.l; + tickVector = {x: -1, y: 0}; + labelAlign = "end"; + }else{ + start.x = stop.x = dim.width - offsets.r; + tickVector = {x: 1, y: 0}; + labelAlign = "start"; + } + labelOffset = {x: tickVector.x * (tickSize + labelGap), y: size * 0.4}; + }else{ + start = {x: offsets.l}; + stop = {x: dim.width - offsets.r}; + axisVector = {x: 1, y: 0}; + labelAlign = "middle"; + if(this.opt.leftBottom){ + start.y = stop.y = dim.height - offsets.b; + tickVector = {x: 0, y: 1}; + labelOffset = {y: tickSize + labelGap + size}; + }else{ + start.y = stop.y = offsets.t; + tickVector = {x: 0, y: -1}; + labelOffset = {y: -tickSize - labelGap}; + } + labelOffset.x = 0; + } + + // render shapes + this.cleanGroup(); + var s = this.group, c = this.scaler, step, next, + nextMajor = c.major.start, nextMinor = c.minor.start, nextMicro = c.micro.start; + s.createLine({x1: start.x, y1: start.y, x2: stop.x, y2: stop.y}).setStroke(taStroke); + if(this.opt.microTicks && c.micro.tick){ + step = c.micro.tick, next = nextMicro; + }else if(this.opt.minorTicks && c.minor.tick){ + step = c.minor.tick, next = nextMinor; + }else if(c.major.tick){ + step = c.major.tick, next = nextMajor; + }else{ + // don't draw anything + return this; + } + while(next <= c.bounds.upper + 1/c.scale){ + var offset = (next - c.bounds.lower) * c.scale, + x = start.x + axisVector.x * offset, + y = start.y + axisVector.y * offset, elem; + if(Math.abs(nextMajor - next) < step / 2){ + // major tick + s.createLine({ + x1: x, y1: y, + x2: x + tickVector.x * taMajorTick.length, + y2: y + tickVector.y * taMajorTick.length + }).setStroke(taMajorTick); + if(this.opt.majorLabels){ + elem = dc.axis2d.common.createText[this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx"] + (this.chart, s, x + labelOffset.x, y + labelOffset.y, labelAlign, + this._getLabel(nextMajor, c.major.prec), taFont, taFontColor); + if(this.opt.htmlLabels){ this.htmlElements.push(elem); } + } + nextMajor += c.major.tick; + nextMinor += c.minor.tick; + nextMicro += c.micro.tick; + }else if(Math.abs(nextMinor - next) < step / 2){ + // minor tick + if(this.opt.minorTicks){ + s.createLine({ + x1: x, y1: y, + x2: x + tickVector.x * taMinorTick.length, + y2: y + tickVector.y * taMinorTick.length + }).setStroke(taMinorTick); + if(this.opt.minorLabels && (c.minMinorStep <= c.minor.tick * c.scale)){ + elem = dc.axis2d.common.createText[this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx"] + (this.chart, s, x + labelOffset.x, y + labelOffset.y, labelAlign, + this._getLabel(nextMinor, c.minor.prec), taFont, taFontColor); + if(this.opt.htmlLabels){ this.htmlElements.push(elem); } + } + } + nextMinor += c.minor.tick; + nextMicro += c.micro.tick; + }else{ + // micro tick + if(this.opt.microTicks){ + s.createLine({ + x1: x, y1: y, + // use minor ticks for now + x2: x + tickVector.x * taMinorTick.length, + y2: y + tickVector.y * taMinorTick.length + }).setStroke(taMinorTick); + } + nextMicro += c.micro.tick; + } + next += step; + } + this.dirty = false; + return this; + }, + + // utilities + _getLabel: function(number, precision){ + if(this.opt.labels){ + // classic binary search + var l = this.opt.labels, lo = 0, hi = l.length; + while(lo < hi){ + var mid = Math.floor((lo + hi) / 2), val = l[mid].value; + if(val < number){ + lo = mid + 1; + }else{ + hi = mid; + } + } + // lets take into account FP errors + if(lo < l.length && eq(l[lo].value, number)){ + return l[lo].text; + } + --lo; + if(lo < l.length && eq(l[lo].value, number)){ + return l[lo].text; + } + lo += 2; + if(lo < l.length && eq(l[lo].value, number)){ + return l[lo].text; + } + // otherwise we will produce a number + } + return this.opt.fixed ? number.toFixed(precision < 0 ? -precision : 0) : number.toString(); + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/axis2d/common.js b/includes/js/dojox/charting/axis2d/common.js new file mode 100644 index 0000000..dd8ceb3 --- /dev/null +++ b/includes/js/dojox/charting/axis2d/common.js @@ -0,0 +1,75 @@ +if(!dojo._hasResource["dojox.charting.axis2d.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.axis2d.common"] = true; +dojo.provide("dojox.charting.axis2d.common"); + +dojo.require("dojox.gfx"); + +(function(){ + var g = dojox.gfx; + + function clearNode(s){ + s.marginLeft = "0px"; + s.marginTop = "0px"; + s.marginRight = "0px"; + s.marginBottom = "0px"; + s.paddingLeft = "0px"; + s.paddingTop = "0px"; + s.paddingRight = "0px"; + s.paddingBottom = "0px"; + s.borderLeftWidth = "0px"; + s.borderTopWidth = "0px"; + s.borderRightWidth = "0px"; + s.borderBottomWidth = "0px"; + } + + dojo.mixin(dojox.charting.axis2d.common, { + createText: { + gfx: function(chart, creator, x, y, align, text, font, fontColor){ + return creator.createText({ + x: x, y: y, text: text, align: align + }).setFont(font).setFill(fontColor); + }, + html: function(chart, creator, x, y, align, text, font, fontColor){ + // setup the text node + var p = dojo.doc.createElement("div"), s = p.style; + clearNode(s); + s.font = font; + p.innerHTML = text; + s.color = fontColor; + // measure the size + s.position = "absolute"; + s.left = "-10000px"; + dojo.body().appendChild(p); + var size = g.normalizedLength(g.splitFontString(font).size), + box = dojo.marginBox(p); + // new settings for the text node + dojo.body().removeChild(p); + s.position = "relative"; + switch(align){ + case "middle": + s.left = Math.floor(x - box.w / 2) + "px"; + break; + case "end": + s.left = Math.floor(x - box.w) + "px"; + break; + //case "start": + default: + s.left = Math.floor(x) + "px"; + break; + } + s.top = Math.floor(y - size) + "px"; + // setup the wrapper node + var wrap = dojo.doc.createElement("div"), w = wrap.style; + clearNode(w); + w.width = "0px"; + w.height = "0px"; + // insert nodes + wrap.appendChild(p) + chart.node.insertBefore(wrap, chart.node.firstChild); + return p; + } + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot2d/Areas.js b/includes/js/dojox/charting/plot2d/Areas.js new file mode 100644 index 0000000..35d859f --- /dev/null +++ b/includes/js/dojox/charting/plot2d/Areas.js @@ -0,0 +1,14 @@ +if(!dojo._hasResource["dojox.charting.plot2d.Areas"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.Areas"] = true; +dojo.provide("dojox.charting.plot2d.Areas"); + +dojo.require("dojox.charting.plot2d.Default"); + +dojo.declare("dojox.charting.plot2d.Areas", dojox.charting.plot2d.Default, { + constructor: function(){ + this.opt.lines = true; + this.opt.areas = true; + } +}); + +} diff --git a/includes/js/dojox/charting/plot2d/Bars.js b/includes/js/dojox/charting/plot2d/Bars.js new file mode 100644 index 0000000..dd82b64 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/Bars.js @@ -0,0 +1,89 @@ +if(!dojo._hasResource["dojox.charting.plot2d.Bars"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.Bars"] = true; +dojo.provide("dojox.charting.plot2d.Bars"); + +dojo.require("dojox.charting.plot2d.common"); +dojo.require("dojox.charting.plot2d.Base"); + +dojo.require("dojox.lang.utils"); +dojo.require("dojox.lang.functional"); +dojo.require("dojox.lang.functional.reversed"); + +(function(){ + var df = dojox.lang.functional, du = dojox.lang.utils, + dc = dojox.charting.plot2d.common, + purgeGroup = df.lambda("item.purgeGroup()"); + + dojo.declare("dojox.charting.plot2d.Bars", dojox.charting.plot2d.Base, { + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + gap: 0, // gap between columns in pixels + shadows: null // draw shadows + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, kwArgs){ + this.opt = dojo.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + }, + + calculateAxes: function(dim){ + var stats = dc.collectSimpleStats(this.series), t; + stats.hmin -= 0.5; + stats.hmax += 0.5; + t = stats.hmin, stats.hmin = stats.vmin, stats.vmin = t; + t = stats.hmax, stats.hmax = stats.vmax, stats.vmax = t; + this._calc(dim, stats); + return this; + }, + render: function(dim, offsets){ + if(this.dirty){ + dojo.forEach(this.series, purgeGroup); + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, color, stroke, fill, f, + gap = this.opt.gap < this._vScaler.scale / 3 ? this.opt.gap : 0; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ continue; } + run.cleanGroup(); + var s = run.group; + if(!run.fill || !run.stroke){ + // need autogenerated color + color = run.dyn.color = new dojo.Color(t.next("color")); + } + stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); + fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); + var baseline = Math.max(0, this._hScaler.bounds.lower), + xoff = offsets.l + this._hScaler.scale * (baseline - this._hScaler.bounds.lower), + yoff = dim.height - offsets.b - this._vScaler.scale * (1.5 - this._vScaler.bounds.lower) + gap; + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j], + width = this._hScaler.scale * (v - baseline), + height = this._vScaler.scale - 2 * gap, + w = Math.abs(width); + if(w >= 1 && height >= 1){ + var shape = s.createRect({ + x: xoff + (width < 0 ? width : 0), + y: yoff - this._vScaler.scale * j, + width: w, height: height + }).setFill(fill).setStroke(stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + } + } + run.dirty = false; + } + this.dirty = false; + return this; + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot2d/Base.js b/includes/js/dojox/charting/plot2d/Base.js new file mode 100644 index 0000000..c894ce3 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/Base.js @@ -0,0 +1,60 @@ +if(!dojo._hasResource["dojox.charting.plot2d.Base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.Base"] = true; +dojo.provide("dojox.charting.plot2d.Base"); + +dojo.require("dojox.charting.Element"); +dojo.require("dojox.charting.plot2d.common"); + +dojo.declare("dojox.charting.plot2d.Base", dojox.charting.Element, { + clear: function(){ + this.series = []; + this._hAxis = null; + this._vAxis = null; + this.dirty = true; + return this; + }, + setAxis: function(axis){ + if(axis){ + this[axis.vertical ? "_vAxis" : "_hAxis"] = axis; + } + return this; + }, + addSeries: function(run){ + this.series.push(run); + return this; + }, + calculateAxes: function(dim){ + return this; + }, + render: function(dim, offsets){ + return this; + }, + getRequiredColors: function(){ + return this.series.length; + }, + + // utilities + _calc: function(dim, stats){ + // calculate scaler + if(this._hAxis){ + if(!this._hAxis.initialized()){ + this._hAxis.calculate(stats.hmin, stats.hmax, dim.width); + } + this._hScaler = this._hAxis.getScaler(); + }else{ + this._hScaler = {bounds: {lower: stats.hmin, upper: stats.hmax}, + scale: dim.width / (stats.hmax - stats.hmin)}; + } + if(this._vAxis){ + if(!this._vAxis.initialized()){ + this._vAxis.calculate(stats.vmin, stats.vmax, dim.height); + } + this._vScaler = this._vAxis.getScaler(); + }else{ + this._vScaler = {bounds: {lower: stats.vmin, upper: stats.vmax}, + scale: dim.height / (stats.vmax - stats.vmin)}; + } + } +}); + +} diff --git a/includes/js/dojox/charting/plot2d/ClusteredBars.js b/includes/js/dojox/charting/plot2d/ClusteredBars.js new file mode 100644 index 0000000..9d64bb2 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/ClusteredBars.js @@ -0,0 +1,63 @@ +if(!dojo._hasResource["dojox.charting.plot2d.ClusteredBars"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.ClusteredBars"] = true; +dojo.provide("dojox.charting.plot2d.ClusteredBars"); + +dojo.require("dojox.charting.plot2d.common"); +dojo.require("dojox.charting.plot2d.Bars"); + +dojo.require("dojox.lang.functional"); +dojo.require("dojox.lang.functional.reversed"); + +(function(){ + var df = dojox.lang.functional, dc = dojox.charting.plot2d.common, + purgeGroup = df.lambda("item.purgeGroup()"); + + dojo.declare("dojox.charting.plot2d.ClusteredBars", dojox.charting.plot2d.Bars, { + render: function(dim, offsets){ + if(this.dirty){ + dojo.forEach(this.series, purgeGroup); + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, color, stroke, fill, f, + gap = this.opt.gap < this._vScaler.scale / 3 ? this.opt.gap : 0, + thickness = (this._vScaler.scale - 2 * gap) / this.series.length; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ continue; } + run.cleanGroup(); + var s = run.group; + if(!run.fill || !run.stroke){ + // need autogenerated color + color = run.dyn.color = new dojo.Color(t.next("color")); + } + stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); + fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); + var baseline = Math.max(0, this._hScaler.bounds.lower), + xoff = offsets.l + this._hScaler.scale * (baseline - this._hScaler.bounds.lower), + yoff = dim.height - offsets.b - this._vScaler.scale * (1.5 - this._vScaler.bounds.lower) + + gap + thickness * (this.series.length - i - 1); + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j], + width = this._hScaler.scale * (v - baseline), + height = thickness, w = Math.abs(width); + if(w >= 1 && height >= 1){ + var shape = s.createRect({ + x: xoff + (width < 0 ? width : 0), + y: yoff - this._vScaler.scale * j, + width: w, height: height + }).setFill(fill).setStroke(stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + } + } + run.dirty = false; + } + this.dirty = false; + return this; + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot2d/ClusteredColumns.js b/includes/js/dojox/charting/plot2d/ClusteredColumns.js new file mode 100644 index 0000000..9a4170a --- /dev/null +++ b/includes/js/dojox/charting/plot2d/ClusteredColumns.js @@ -0,0 +1,63 @@ +if(!dojo._hasResource["dojox.charting.plot2d.ClusteredColumns"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.ClusteredColumns"] = true; +dojo.provide("dojox.charting.plot2d.ClusteredColumns"); + +dojo.require("dojox.charting.plot2d.common"); +dojo.require("dojox.charting.plot2d.Columns"); + +dojo.require("dojox.lang.functional"); +dojo.require("dojox.lang.functional.reversed"); + +(function(){ + var df = dojox.lang.functional, dc = dojox.charting.plot2d.common, + purgeGroup = df.lambda("item.purgeGroup()"); + + dojo.declare("dojox.charting.plot2d.ClusteredColumns", dojox.charting.plot2d.Columns, { + render: function(dim, offsets){ + if(this.dirty){ + dojo.forEach(this.series, purgeGroup); + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, color, stroke, fill, f, + gap = this.opt.gap < this._hScaler.scale / 3 ? this.opt.gap : 0, + thickness = (this._hScaler.scale - 2 * gap) / this.series.length; + for(var i = 0; i < this.series.length; ++i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ continue; } + run.cleanGroup(); + var s = run.group; + if(!run.fill || !run.stroke){ + // need autogenerated color + color = run.dyn.color = new dojo.Color(t.next("color")); + } + stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); + fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); + var baseline = Math.max(0, this._vScaler.bounds.lower), + xoff = offsets.l + this._hScaler.scale * (0.5 - this._hScaler.bounds.lower) + gap + thickness * i, + yoff = dim.height - offsets.b - this._vScaler.scale * (baseline - this._vScaler.bounds.lower); + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j], + width = thickness, + height = this._vScaler.scale * (v - baseline), + h = Math.abs(height); + if(width >= 1 && h >= 1){ + var shape = s.createRect({ + x: xoff + this._hScaler.scale * j, + y: yoff - (height < 0 ? 0 : height), + width: width, height: h + }).setFill(fill).setStroke(stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + } + } + run.dirty = false; + } + this.dirty = false; + return this; + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot2d/Columns.js b/includes/js/dojox/charting/plot2d/Columns.js new file mode 100644 index 0000000..ff97393 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/Columns.js @@ -0,0 +1,88 @@ +if(!dojo._hasResource["dojox.charting.plot2d.Columns"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.Columns"] = true; +dojo.provide("dojox.charting.plot2d.Columns"); + +dojo.require("dojox.charting.plot2d.common"); +dojo.require("dojox.charting.plot2d.Base"); + +dojo.require("dojox.lang.utils"); +dojo.require("dojox.lang.functional"); +dojo.require("dojox.lang.functional.reversed"); + +(function(){ + var df = dojox.lang.functional, du = dojox.lang.utils, + dc = dojox.charting.plot2d.common, + purgeGroup = df.lambda("item.purgeGroup()"); + + dojo.declare("dojox.charting.plot2d.Columns", dojox.charting.plot2d.Base, { + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + gap: 0, // gap between columns in pixels + shadows: null // draw shadows + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, kwArgs){ + this.opt = dojo.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + }, + + calculateAxes: function(dim){ + var stats = dc.collectSimpleStats(this.series); + stats.hmin -= 0.5; + stats.hmax += 0.5; + this._calc(dim, stats); + return this; + }, + render: function(dim, offsets){ + if(this.dirty){ + dojo.forEach(this.series, purgeGroup); + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, color, stroke, fill, f, + gap = this.opt.gap < this._hScaler.scale / 3 ? this.opt.gap : 0; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ continue; } + run.cleanGroup(); + var s = run.group; + if(!run.fill || !run.stroke){ + // need autogenerated color + color = run.dyn.color = new dojo.Color(t.next("color")); + } + stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); + fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); + var baseline = Math.max(0, this._vScaler.bounds.lower), + xoff = offsets.l + this._hScaler.scale * (0.5 - this._hScaler.bounds.lower) + gap, + yoff = dim.height - offsets.b - this._vScaler.scale * (baseline - this._vScaler.bounds.lower); + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j], + width = this._hScaler.scale - 2 * gap, + height = this._vScaler.scale * (v - baseline), + h = Math.abs(height); + if(width >= 1 && h >= 1){ + var rect = { + x: xoff + this._hScaler.scale * j, + y: yoff - (height < 0 ? 0 : height), + width: width, height: h + }, + shape = s.createRect(rect).setFill(fill).setStroke(stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + } + } + run.dirty = false; + } + this.dirty = false; + return this; + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot2d/Default.js b/includes/js/dojox/charting/plot2d/Default.js new file mode 100644 index 0000000..a8ca8a5 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/Default.js @@ -0,0 +1,173 @@ +if(!dojo._hasResource["dojox.charting.plot2d.Default"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.Default"] = true; +dojo.provide("dojox.charting.plot2d.Default"); + +dojo.require("dojox.charting.plot2d.common"); +dojo.require("dojox.charting.plot2d.Base"); + +dojo.require("dojox.lang.utils"); +dojo.require("dojox.lang.functional"); +dojo.require("dojox.lang.functional.reversed"); + +(function(){ + var df = dojox.lang.functional, du = dojox.lang.utils, + dc = dojox.charting.plot2d.common, + purgeGroup = df.lambda("item.purgeGroup()"); + + dojo.declare("dojox.charting.plot2d.Default", dojox.charting.plot2d.Base, { + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + lines: true, // draw lines + areas: false, // draw areas + markers: false, // draw markers + shadows: 0, // draw shadows + tension: 0 // draw curved lines (tension>0) + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, kwArgs){ + this.opt = dojo.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + }, + + calculateAxes: function(dim){ + this._calc(dim, dc.collectSimpleStats(this.series)); + return this; + }, + render: function(dim, offsets){ + if(this.dirty){ + dojo.forEach(this.series, purgeGroup); + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, stroke, outline, color, marker; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ continue; } + run.cleanGroup(); + if(!run.data.length){ + run.dirty = false; + continue; + } + + // inner function for translating polylines to curves with tension + function curve(arr, tension){ + var p=dojo.map(arr, function(item, i){ + if(i==0){ return "M" + item.x + "," + item.y; } + var dx=item.x-arr[i-1].x, dy=arr[i-1].y; + return "C"+(item.x-(tension-1)*(dx/tension))+","+dy+" "+(item.x-(dx/tension))+","+item.y+" "+item.x+","+item.y; + }); + return p.join(" "); + } + + var s = run.group, lpoly; + if(typeof run.data[0] == "number"){ + lpoly = dojo.map(run.data, function(v, i){ + return { + x: this._hScaler.scale * (i + 1 - this._hScaler.bounds.lower) + offsets.l, + y: dim.height - offsets.b - this._vScaler.scale * (v - this._vScaler.bounds.lower) + }; + }, this); + }else{ + lpoly = dojo.map(run.data, function(v, i){ + return { + x: this._hScaler.scale * (v.x - this._hScaler.bounds.lower) + offsets.l, + y: dim.height - offsets.b - this._vScaler.scale * (v.y - this._vScaler.bounds.lower) + }; + }, this); + } + if(!run.fill || !run.stroke){ + // need autogenerated color + color = run.dyn.color = new dojo.Color(t.next("color")); + } + + var lpath=""; + if(this.opt.tension){ + var lpath=curve(lpoly, this.opt.tension); + } + + if(this.opt.areas){ + var fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); + var apoly = dojo.clone(lpoly); + if(this.opt.tension){ + var apath="L" + (apoly[apoly.length-1].x) + "," + (dim.height-offsets.b) + " " + + "L"+apoly[0].x+","+(dim.height-offsets.b)+" " + + "L"+apoly[0].x+","+apoly[0].y; + run.dyn.fill = s.createPath(lpath+" "+apath).setFill(fill).getFill(); + } else { + apoly.push({x: lpoly[lpoly.length - 1].x, y: dim.height - offsets.b}); + apoly.push({x: lpoly[0].x, y: dim.height - offsets.b}); + apoly.push(lpoly[0]); + run.dyn.fill = s.createPolyline(apoly).setFill(fill).getFill(); + } + } + if(this.opt.lines || this.opt.markers){ + // need a stroke + stroke = run.stroke ? dc.makeStroke(run.stroke) : dc.augmentStroke(t.series.stroke, color); + if(run.outline || t.series.outline){ + outline = dc.makeStroke(run.outline ? run.outline : t.series.outline); + outline.width = 2 * outline.width + stroke.width; + } + } + if(this.opt.markers){ + // need a marker + marker = run.dyn.marker = run.marker ? run.marker : t.next("marker"); + } + if(this.opt.shadows && stroke){ + var sh = this.opt.shadows, shadowColor = new dojo.Color([0, 0, 0, 0.3]), + spoly = dojo.map(lpoly, function(c){ + return {x: c.x + sh.dx, y: c.y + sh.dy}; + }), + shadowStroke = dojo.clone(outline ? outline : stroke); + shadowStroke.color = shadowColor; + shadowStroke.width += sh.dw ? sh.dw : 0; + if(this.opt.lines){ + if(this.opt.tension){ + s.createPath(curve(spoly, this.opt.tension)).setStroke(shadowStroke); + } else { + s.createPolyline(spoly).setStroke(shadowStroke); + } + } + if(this.opt.markers){ + dojo.forEach(spoly, function(c){ + s.createPath("M" + c.x + " " + c.y + " " + marker).setStroke(shadowStroke).setFill(shadowColor); + }, this); + } + } + if(this.opt.lines){ + if(outline){ + if(this.opt.tension){ + run.dyn.outline = s.createPath(lpath).setStroke(outline).getStroke(); + } else { + run.dyn.outline = s.createPolyline(lpoly).setStroke(outline).getStroke(); + } + } + if(this.opt.tension){ + run.dyn.stroke = s.createPath(lpath).setStroke(stroke).getStroke(); + } else { + run.dyn.stroke = s.createPolyline(lpoly).setStroke(stroke).getStroke(); + } + } + if(this.opt.markers){ + dojo.forEach(lpoly, function(c){ + var path = "M" + c.x + " " + c.y + " " + marker; + if(outline){ + s.createPath(path).setStroke(outline); + } + s.createPath(path).setStroke(stroke).setFill(stroke.color); + }, this); + } + run.dirty = false; + } + this.dirty = false; + return this; + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot2d/Grid.js b/includes/js/dojox/charting/plot2d/Grid.js new file mode 100644 index 0000000..52cb348 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/Grid.js @@ -0,0 +1,116 @@ +if(!dojo._hasResource["dojox.charting.plot2d.Grid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.Grid"] = true; +dojo.provide("dojox.charting.plot2d.Grid"); + +dojo.require("dojox.charting.Element"); +dojo.require("dojox.charting.plot2d.common"); +dojo.require("dojox.lang.functional"); + +(function(){ + var du = dojox.lang.utils; + + dojo.declare("dojox.charting.plot2d.Grid", dojox.charting.Element, { + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + hMajorLines: true, // draw horizontal major lines + hMinorLines: false, // draw horizontal minor lines + vMajorLines: true, // draw vertical major lines + vMinorLines: false, // draw vertical minor lines + hStripes: "none", // TBD + vStripes: "none" // TBD + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, kwArgs){ + this.opt = dojo.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + }, + clear: function(){ + this._hAxis = null; + this._vAxis = null; + this.dirty = true; + return this; + }, + setAxis: function(axis){ + if(axis){ + this[axis.vertical ? "_vAxis" : "_hAxis"] = axis; + } + return this; + }, + addSeries: function(run){ + // nothing + return this; + }, + calculateAxes: function(dim){ + // nothing + return this; + }, + getRequiredColors: function(){ + return 0; + }, + render: function(dim, offsets){ + // draw horizontal stripes and lines + if(!this.dirty){ return this; } + this.cleanGroup(); + var s = this.group, ta = this.chart.theme.axis, + scaler = this._vAxis.getScaler(); + if(this.opt.hMinorLines && scaler.minor.tick){ + for(var i = 0; i < scaler.minor.count; ++i){ + var y = dim.height - offsets.b - scaler.scale * + (scaler.minor.start - scaler.bounds.lower + i * scaler.minor.tick); + s.createLine({ + x1: offsets.l, + y1: y, + x2: dim.width - offsets.r, + y2: y + }).setStroke(ta.minorTick); + } + } + if(this.opt.hMajorLines && scaler.major.tick){ + for(var i = 0; i < scaler.major.count; ++i){ + var y = dim.height - offsets.b - scaler.scale * + (scaler.major.start - scaler.bounds.lower + i * scaler.major.tick); + s.createLine({ + x1: offsets.l, + y1: y, + x2: dim.width - offsets.r, + y2: y + }).setStroke(ta.majorTick); + } + } + // draw vertical stripes and lines + scaler = this._hAxis.getScaler(); + if(this.opt.vMinorLines && scaler.minor.tick){ + for(var i = 0; i < scaler.minor.count; ++i){ + var x = offsets.l + scaler.scale * + (scaler.minor.start - scaler.bounds.lower + i * scaler.minor.tick); + s.createLine({ + x1: x, + y1: offsets.t, + x2: x, + y2: dim.height - offsets.b + }).setStroke(ta.minorTick); + } + } + if(this.opt.vMajorLines && scaler.major.tick){ + for(var i = 0; i < scaler.major.count; ++i){ + var x = offsets.l + scaler.scale * + (scaler.major.start - scaler.bounds.lower + i * scaler.major.tick); + s.createLine({ + x1: x, + y1: offsets.t, + x2: x, + y2: dim.height - offsets.b + }).setStroke(ta.majorTick); + } + } + this.dirty = false; + return this; + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot2d/Lines.js b/includes/js/dojox/charting/plot2d/Lines.js new file mode 100644 index 0000000..34e6897 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/Lines.js @@ -0,0 +1,13 @@ +if(!dojo._hasResource["dojox.charting.plot2d.Lines"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.Lines"] = true; +dojo.provide("dojox.charting.plot2d.Lines"); + +dojo.require("dojox.charting.plot2d.Default"); + +dojo.declare("dojox.charting.plot2d.Lines", dojox.charting.plot2d.Default, { + constructor: function(){ + this.opt.lines = true; + } +}); + +} diff --git a/includes/js/dojox/charting/plot2d/Markers.js b/includes/js/dojox/charting/plot2d/Markers.js new file mode 100644 index 0000000..177aafb --- /dev/null +++ b/includes/js/dojox/charting/plot2d/Markers.js @@ -0,0 +1,13 @@ +if(!dojo._hasResource["dojox.charting.plot2d.Markers"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.Markers"] = true; +dojo.provide("dojox.charting.plot2d.Markers"); + +dojo.require("dojox.charting.plot2d.Default"); + +dojo.declare("dojox.charting.plot2d.Markers", dojox.charting.plot2d.Default, { + constructor: function(){ + this.opt.markers = true; + } +}); + +} diff --git a/includes/js/dojox/charting/plot2d/MarkersOnly.js b/includes/js/dojox/charting/plot2d/MarkersOnly.js new file mode 100644 index 0000000..48cd663 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/MarkersOnly.js @@ -0,0 +1,14 @@ +if(!dojo._hasResource["dojox.charting.plot2d.MarkersOnly"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.MarkersOnly"] = true; +dojo.provide("dojox.charting.plot2d.MarkersOnly"); + +dojo.require("dojox.charting.plot2d.Default"); + +dojo.declare("dojox.charting.plot2d.MarkersOnly", dojox.charting.plot2d.Default, { + constructor: function(){ + this.opt.lines = false; + this.opt.markers = true; + } +}); + +} diff --git a/includes/js/dojox/charting/plot2d/Pie.js b/includes/js/dojox/charting/plot2d/Pie.js new file mode 100644 index 0000000..2d0f55e --- /dev/null +++ b/includes/js/dojox/charting/plot2d/Pie.js @@ -0,0 +1,199 @@ +if(!dojo._hasResource["dojox.charting.plot2d.Pie"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.Pie"] = true; +dojo.provide("dojox.charting.plot2d.Pie"); + +dojo.require("dojox.charting.Element"); +dojo.require("dojox.charting.axis2d.common"); +dojo.require("dojox.charting.plot2d.common"); + +dojo.require("dojox.lang.functional"); +dojo.require("dojox.gfx"); + +(function(){ + var df = dojox.lang.functional, du = dojox.lang.utils, + dc = dojox.charting.plot2d.common, + da = dojox.charting.axis2d.common, + g = dojox.gfx; + + dojo.declare("dojox.charting.plot2d.Pie", dojox.charting.Element, { + defaultParams: { + labels: true, + ticks: false, + fixed: true, + precision: 1, + labelOffset: 20, + labelStyle: "default", // default/rows/auto + htmlLabels: true // use HTML to draw labels + }, + optionalParams: { + font: "", + fontColor: "", + radius: 0 + }, + + constructor: function(chart, kwArgs){ + this.opt = dojo.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.run = null; + this.dyn = []; + }, + clear: function(){ + this.dirty = true; + this.dyn = []; + return this; + }, + setAxis: function(axis){ + // nothing + return this; + }, + addSeries: function(run){ + this.run = run; + return this; + }, + calculateAxes: function(dim){ + // nothing + return this; + }, + getRequiredColors: function(){ + return this.run ? this.run.data.length : 0; + }, + render: function(dim, offsets){ + if(!this.dirty){ return this; } + this.dirty = false; + this.cleanGroup(); + var s = this.group, color, t = this.chart.theme; + + // calculate the geometry + var rx = (dim.width - offsets.l - offsets.r) / 2, + ry = (dim.height - offsets.t - offsets.b) / 2, + r = Math.min(rx, ry), + taFont = "font" in this.opt ? this.opt.font : t.axis.font, + size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0, + taFontColor = "fontColor" in this.opt ? this.opt.fontColor : t.axis.fontColor, + start = 0, step, sum, slices, labels, shift, labelR, + run = this.run.data; + if(typeof run[0] == "number"){ + sum = df.foldl1(run, "+"); + slices = dojo.map(run, function(x){ return x / sum; }); + if(this.opt.labels){ + labels = dojo.map(slices, function(x){ + return this._getLabel(x * 100) + "%"; + }, this); + } + }else{ + sum = df.foldl1(run, function(a, b){ return {y: a.y + b.y}; }).y; + slices = df.map(run, function(x){ return x.y / sum; }); + if(this.opt.labels){ + labels = dojo.map(slices, function(x, i){ + var v = run[i]; + return "text" in v ? v.text : this._getLabel(x * 100) + "%"; + }, this); + } + } + if(this.opt.labels){ + shift = df.foldl1(df.map(labels, function(label){ + return dojox.gfx._base._getTextBox(label, {font: taFont}).w; + }, this), "Math.max(a, b)") / 2; + if(this.opt.labelOffset < 0){ + r = Math.min(rx - 2 * shift, ry - size) + this.opt.labelOffset; + } + labelR = r - this.opt.labelOffset; + } + if("radius" in this.opt){ + r = this.opt.radius; + labelR = r - this.opt.labelOffset; + } + var circle = { + cx: offsets.l + rx, + cy: offsets.t + ry, + r: r + }; + + this.dyn = []; + if(!this.run || !run.length){ + return this; + } + if(run.length == 1){ + // need autogenerated color + color = new dojo.Color(t.next("color")); + var shape = s.createCircle(circle). + setFill(dc.augmentFill(t.run.fill, color)). + setStroke(dc.augmentStroke(t.series.stroke, color)); + this.dyn.push({color: color, fill: shape.getFill(), stroke: shape.getStroke()}); + if(this.opt.labels){ + // draw the label + var elem = da.createText[this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx"] + (this.chart, s, circle.cx, circle.cy + size / 2, "middle", + "100%", taFont, taFontColor); + if(this.opt.htmlLabels){ this.htmlElements.push(elem); } + } + return this; + } + // draw slices + dojo.forEach(slices, function(x, i){ + // calculate the geometry of the slice + var end = start + x * 2 * Math.PI, v = run[i]; + if(i + 1 == slices.length){ + end = 2 * Math.PI; + } + var step = end - start, + x1 = circle.cx + r * Math.cos(start), + y1 = circle.cy + r * Math.sin(start), + x2 = circle.cx + r * Math.cos(end), + y2 = circle.cy + r * Math.sin(end); + // draw the slice + var color, fill, stroke; + if(typeof v == "object"){ + color = "color" in v ? v.color : new dojo.Color(t.next("color")); + fill = "fill" in v ? v.fill : dc.augmentFill(t.series.fill, color); + stroke = "stroke" in v ? v.stroke : dc.augmentStroke(t.series.stroke, color); + }else{ + color = new dojo.Color(t.next("color")); + fill = dc.augmentFill(t.series.fill, color); + stroke = dc.augmentStroke(t.series.stroke, color); + } + var shape = s.createPath({}). + moveTo(circle.cx, circle.cy). + lineTo(x1, y1). + arcTo(r, r, 0, step > Math.PI, true, x2, y2). + lineTo(circle.cx, circle.cy). + closePath(). + setFill(fill). + setStroke(stroke); + this.dyn.push({color: color, fill: fill, stroke: stroke}); + start = end; + }, this); + // draw labels + if(this.opt.labels){ + start = 0; + dojo.forEach(slices, function(slice, i){ + // calculate the geometry of the slice + var end = start + slice * 2 * Math.PI, v = run[i]; + if(i + 1 == slices.length){ + end = 2 * Math.PI; + } + var labelAngle = (start + end) / 2, + x = circle.cx + labelR * Math.cos(labelAngle), + y = circle.cy + labelR * Math.sin(labelAngle) + size / 2; + // draw the label + var elem = da.createText[this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx"] + (this.chart, s, x, y, "middle", + labels[i], taFont, + (typeof v == "object" && "fontColor" in v) + ? v.fontColor : taFontColor); + if(this.opt.htmlLabels){ this.htmlElements.push(elem); } + start = end; + }, this); + } + return this; + }, + + // utilities + _getLabel: function(number){ + return this.opt.fixed ? number.toFixed(this.opt.precision) : number.toString(); + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot2d/Scatter.js b/includes/js/dojox/charting/plot2d/Scatter.js new file mode 100644 index 0000000..d307cb1 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/Scatter.js @@ -0,0 +1,14 @@ +if(!dojo._hasResource["dojox.charting.plot2d.Scatter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.Scatter"] = true; +dojo.provide("dojox.charting.plot2d.Scatter"); + +dojo.require("dojox.charting.plot2d.Default"); + +dojo.declare("dojox.charting.plot2d.Scatter", dojox.charting.plot2d.Default, { + constructor: function(){ + this.opt.lines = false; + this.opt.markers = true; + } +}); + +} diff --git a/includes/js/dojox/charting/plot2d/Stacked.js b/includes/js/dojox/charting/plot2d/Stacked.js new file mode 100644 index 0000000..0e26a75 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/Stacked.js @@ -0,0 +1,160 @@ +if(!dojo._hasResource["dojox.charting.plot2d.Stacked"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.Stacked"] = true; +dojo.provide("dojox.charting.plot2d.Stacked"); + +dojo.require("dojox.charting.plot2d.common"); +dojo.require("dojox.charting.plot2d.Default"); + +dojo.require("dojox.lang.functional"); +dojo.require("dojox.lang.functional.sequence"); +dojo.require("dojox.lang.functional.reversed"); + +(function(){ + var df = dojox.lang.functional, dc = dojox.charting.plot2d.common, + purgeGroup = df.lambda("item.purgeGroup()"); + + dojo.declare("dojox.charting.plot2d.Stacked", dojox.charting.plot2d.Default, { + calculateAxes: function(dim){ + var stats = dc.collectStackedStats(this.series); + this._maxRunLength = stats.hmax; + this._calc(dim, stats); + return this; + }, + render: function(dim, offsets){ + // stack all values + var acc = df.repeat(this._maxRunLength, "-> 0", 0); + for(var i = 0; i < this.series.length; ++i){ + var run = this.series[i]; + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(isNaN(v)){ v = 0; } + acc[j] += v; + } + } + // draw runs in backwards + if(this.dirty){ + dojo.forEach(this.series, purgeGroup); + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + + // inner function for translating polylines to curves with tension + function curve(arr, tension){ + var p=dojo.map(arr, function(item, i){ + if(i==0){ return "M" + item.x + "," + item.y; } + var dx=item.x-arr[i-1].x, dy=arr[i-1].y; + return "C"+(item.x-(tension-1)*(dx/tension))+","+dy+" "+(item.x-(dx/tension))+","+item.y+" "+item.x+","+item.y; + }); + return p.join(" "); + } + + var t = this.chart.theme, stroke, outline, color, marker; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ continue; } + run.cleanGroup(); + var s = run.group, + lpoly = dojo.map(acc, function(v, i){ + return { + x: this._hScaler.scale * (i + 1 - this._hScaler.bounds.lower) + offsets.l, + y: dim.height - offsets.b - this._vScaler.scale * (v - this._vScaler.bounds.lower) + }; + }, this); + if(!run.fill || !run.stroke){ + // need autogenerated color + color = new dojo.Color(t.next("color")); + } + + var lpath=""; + if(this.opt.tension){ + lpath=curve(lpoly, this.opt.tension); + } + + if(this.opt.areas){ + var apoly = dojo.clone(lpoly); + var fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); + if(this.opt.tension){ + var p=curve(apoly, this.opt.tension); + p += " L" + lpoly[lpoly.length-1].x + "," + (dim.height - offsets.b) + " " + + "L" + lpoly[0].x + "," + (dim.height - offsets.b) + " " + + "L" + lpoly[0].x + "," + lpoly[0].y; + s.createPath(p).setFill(fill); + } else { + apoly.push({x: lpoly[lpoly.length - 1].x, y: dim.height - offsets.b}); + apoly.push({x: lpoly[0].x, y: dim.height - offsets.b}); + apoly.push(lpoly[0]); + s.createPolyline(apoly).setFill(fill); + } + } + if(this.opt.lines || this.opt.markers){ + // need a stroke + stroke = run.stroke ? dc.makeStroke(run.stroke) : dc.augmentStroke(t.series.stroke, color); + if(run.outline || t.series.outline){ + outline = dc.makeStroke(run.outline ? run.outline : t.series.outline); + outline.width = 2 * outline.width + stroke.width; + } + } + if(this.opt.markers){ + // need a marker + marker = run.marker ? run.marker : t.next("marker"); + } + if(this.opt.shadows && stroke){ + var sh = this.opt.shadows, shadowColor = new dojo.Color([0, 0, 0, 0.3]), + spoly = dojo.map(lpoly, function(c){ + return {x: c.x + sh.dx, y: c.y + sh.dy}; + }), + shadowStroke = dojo.clone(outline ? outline : stroke); + shadowStroke.color = shadowColor; + shadowStroke.width += sh.dw ? sh.dw : 0; + if(this.opt.lines){ + if(this.opt.tension){ + s.createPath(curve(spoly, this.opt.tension)).setStroke(shadowStroke); + } else { + s.createPolyline(spoly).setStroke(shadowStroke); + } + } + if(this.opt.markers){ + dojo.forEach(spoly, function(c){ + s.createPath("M" + c.x + " " + c.y + " " + marker).setStroke(shadowStroke).setFill(shadowColor); + }, this); + } + } + if(this.opt.lines){ + if(outline){ + if(this.opt.tension){ + s.createPath(lpath).setStroke(outline); + } else { + s.createPolyline(lpoly).setStroke(outline); + } + } + if(this.opt.tension){ + s.createPath(lpath).setStroke(stroke); + } else { + s.createPolyline(lpoly).setStroke(stroke); + } + } + if(this.opt.markers){ + dojo.forEach(lpoly, function(c){ + var path = "M" + c.x + " " + c.y + " " + marker; + if(outline){ + s.createPath(path).setStroke(outline); + } + s.createPath(path).setStroke(stroke).setFill(stroke.color); + }, this); + } + run.dirty = false; + // update the accumulator + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(isNaN(v)){ v = 0; } + acc[j] -= v; + } + } + this.dirty = false; + return this; + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot2d/StackedAreas.js b/includes/js/dojox/charting/plot2d/StackedAreas.js new file mode 100644 index 0000000..7bfd255 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/StackedAreas.js @@ -0,0 +1,14 @@ +if(!dojo._hasResource["dojox.charting.plot2d.StackedAreas"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.StackedAreas"] = true; +dojo.provide("dojox.charting.plot2d.StackedAreas"); + +dojo.require("dojox.charting.plot2d.Stacked"); + +dojo.declare("dojox.charting.plot2d.StackedAreas", dojox.charting.plot2d.Stacked, { + constructor: function(){ + this.opt.lines = true; + this.opt.areas = true; + } +}); + +} diff --git a/includes/js/dojox/charting/plot2d/StackedBars.js b/includes/js/dojox/charting/plot2d/StackedBars.js new file mode 100644 index 0000000..e5c9c22 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/StackedBars.js @@ -0,0 +1,85 @@ +if(!dojo._hasResource["dojox.charting.plot2d.StackedBars"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.StackedBars"] = true; +dojo.provide("dojox.charting.plot2d.StackedBars"); + +dojo.require("dojox.charting.plot2d.common"); +dojo.require("dojox.charting.plot2d.Bars"); + +dojo.require("dojox.lang.functional"); +dojo.require("dojox.lang.functional.reversed"); + +(function(){ + var df = dojox.lang.functional, dc = dojox.charting.plot2d.common, + purgeGroup = df.lambda("item.purgeGroup()"); + + dojo.declare("dojox.charting.plot2d.StackedBars", dojox.charting.plot2d.Bars, { + calculateAxes: function(dim){ + var stats = dc.collectStackedStats(this.series), t; + this._maxRunLength = stats.hmax; + stats.hmin -= 0.5; + stats.hmax += 0.5; + t = stats.hmin, stats.hmin = stats.vmin, stats.vmin = t; + t = stats.hmax, stats.hmax = stats.vmax, stats.vmax = t; + this._calc(dim, stats); + return this; + }, + render: function(dim, offsets){ + // stack all values + var acc = df.repeat(this._maxRunLength, "-> 0", 0); + for(var i = 0; i < this.series.length; ++i){ + var run = this.series[i]; + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(isNaN(v)){ v = 0; } + acc[j] += v; + } + } + // draw runs in backwards + if(this.dirty){ + dojo.forEach(this.series, purgeGroup); + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, color, stroke, fill, f, + gap = this.opt.gap < this._vScaler.scale / 3 ? this.opt.gap : 0; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ continue; } + run.cleanGroup(); + var s = run.group; + if(!run.fill || !run.stroke){ + // need autogenerated color + color = run.dyn.color = new dojo.Color(t.next("color")); + } + stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); + fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); + for(var j = 0; j < acc.length; ++j){ + var v = acc[j], + width = this._hScaler.scale * (v - this._hScaler.bounds.lower), + height = this._vScaler.scale - 2 * gap; + if(width >= 1 && height >= 1){ + var shape = s.createRect({ + x: offsets.l, + y: dim.height - offsets.b - this._vScaler.scale * (j + 1.5 - this._vScaler.bounds.lower) + gap, + width: width, height: height + }).setFill(fill).setStroke(stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + } + } + run.dirty = false; + // update the accumulator + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(isNaN(v)){ v = 0; } + acc[j] -= v; + } + } + this.dirty = false; + return this; + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot2d/StackedColumns.js b/includes/js/dojox/charting/plot2d/StackedColumns.js new file mode 100644 index 0000000..15fd141 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/StackedColumns.js @@ -0,0 +1,83 @@ +if(!dojo._hasResource["dojox.charting.plot2d.StackedColumns"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.StackedColumns"] = true; +dojo.provide("dojox.charting.plot2d.StackedColumns"); + +dojo.require("dojox.charting.plot2d.common"); +dojo.require("dojox.charting.plot2d.Columns"); + +dojo.require("dojox.lang.functional"); +dojo.require("dojox.lang.functional.reversed"); + +(function(){ + var df = dojox.lang.functional, dc = dojox.charting.plot2d.common, + purgeGroup = df.lambda("item.purgeGroup()"); + + dojo.declare("dojox.charting.plot2d.StackedColumns", dojox.charting.plot2d.Columns, { + calculateAxes: function(dim){ + var stats = dc.collectStackedStats(this.series); + this._maxRunLength = stats.hmax; + stats.hmin -= 0.5; + stats.hmax += 0.5; + this._calc(dim, stats); + return this; + }, + render: function(dim, offsets){ + // stack all values + var acc = df.repeat(this._maxRunLength, "-> 0", 0); + for(var i = 0; i < this.series.length; ++i){ + var run = this.series[i]; + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(isNaN(v)){ v = 0; } + acc[j] += v; + } + } + // draw runs in backwards + if(this.dirty){ + dojo.forEach(this.series, purgeGroup); + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, color, stroke, fill, f, + gap = this.opt.gap < this._hScaler.scale / 3 ? this.opt.gap : 0; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ continue; } + run.cleanGroup(); + var s = run.group; + if(!run.fill || !run.stroke){ + // need autogenerated color + color = run.dyn.color = new dojo.Color(t.next("color")); + } + stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); + fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); + for(var j = 0; j < acc.length; ++j){ + var v = acc[j], + width = this._hScaler.scale - 2 * gap, + height = this._vScaler.scale * (v - this._vScaler.bounds.lower); + if(width >= 1 && height >= 1){ + var shape = s.createRect({ + x: offsets.l + this._hScaler.scale * (j + 0.5 - this._hScaler.bounds.lower) + gap, + y: dim.height - offsets.b - this._vScaler.scale * (v - this._vScaler.bounds.lower), + width: width, height: height + }).setFill(fill).setStroke(stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + } + } + run.dirty = false; + // update the accumulator + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(isNaN(v)){ v = 0; } + acc[j] -= v; + } + } + this.dirty = false; + return this; + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot2d/StackedLines.js b/includes/js/dojox/charting/plot2d/StackedLines.js new file mode 100644 index 0000000..2581b85 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/StackedLines.js @@ -0,0 +1,13 @@ +if(!dojo._hasResource["dojox.charting.plot2d.StackedLines"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.StackedLines"] = true; +dojo.provide("dojox.charting.plot2d.StackedLines"); + +dojo.require("dojox.charting.plot2d.Stacked"); + +dojo.declare("dojox.charting.plot2d.StackedLines", dojox.charting.plot2d.Stacked, { + constructor: function(){ + this.opt.lines = true; + } +}); + +} diff --git a/includes/js/dojox/charting/plot2d/common.js b/includes/js/dojox/charting/plot2d/common.js new file mode 100644 index 0000000..de60020 --- /dev/null +++ b/includes/js/dojox/charting/plot2d/common.js @@ -0,0 +1,113 @@ +if(!dojo._hasResource["dojox.charting.plot2d.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot2d.common"] = true; +dojo.provide("dojox.charting.plot2d.common"); + +dojo.require("dojo.colors"); +dojo.require("dojox.gfx"); +dojo.require("dojox.lang.functional"); + +(function(){ + var df = dojox.lang.functional, dc = dojox.charting.plot2d.common; + + dojo.mixin(dojox.charting.plot2d.common, { + makeStroke: function(stroke){ + if(!stroke){ return stroke; } + if(typeof stroke == "string" || stroke instanceof dojo.Color){ + stroke = {color: stroke}; + } + return dojox.gfx.makeParameters(dojox.gfx.defaultStroke, stroke); + }, + augmentColor: function(target, color){ + var t = new dojo.Color(target), + c = new dojo.Color(color); + c.a = t.a; + return c; + }, + augmentStroke: function(stroke, color){ + var s = dc.makeStroke(stroke); + if(s){ + s.color = dc.augmentColor(s.color, color); + } + return s; + }, + augmentFill: function(fill, color){ + var fc, c = new dojo.Color(color); + if(typeof fill == "string" || fill instanceof dojo.Color){ + return dc.augmentColor(fill, color); + } + return fill; + }, + + defaultStats: {hmin: Number.POSITIVE_INFINITY, hmax: Number.NEGATIVE_INFINITY, + vmin: Number.POSITIVE_INFINITY, vmax: Number.NEGATIVE_INFINITY}, + + collectSimpleStats: function(series){ + var stats = dojo.clone(dc.defaultStats); + for(var i = 0; i < series.length; ++i){ + var run = series[i]; + if(!run.data.length){ continue; } + if(typeof run.data[0] == "number"){ + // 1D case + var old_vmin = stats.vmin, old_vmax = stats.vmax; + if(!("ymin" in run) || !("ymax" in run)){ + dojo.forEach(run.data, function(val, i){ + var x = i + 1, y = val; + if(isNaN(y)){ y = 0; } + stats.hmin = Math.min(stats.hmin, x); + stats.hmax = Math.max(stats.hmax, x); + stats.vmin = Math.min(stats.vmin, y); + stats.vmax = Math.max(stats.vmax, y); + }); + } + if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } + if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } + }else{ + // 2D case + var old_hmin = stats.hmin, old_hmax = stats.hmax, + old_vmin = stats.vmin, old_vmax = stats.vmax; + if(!("xmin" in run) || !("xmax" in run) || !("ymin" in run) || !("ymax" in run)){ + dojo.forEach(run.data, function(val, i){ + var x = val.x, y = val.y; + if(isNaN(x)){ x = 0; } + if(isNaN(y)){ y = 0; } + stats.hmin = Math.min(stats.hmin, x); + stats.hmax = Math.max(stats.hmax, x); + stats.vmin = Math.min(stats.vmin, y); + stats.vmax = Math.max(stats.vmax, y); + }); + } + if("xmin" in run){ stats.hmin = Math.min(old_hmin, run.xmin); } + if("xmax" in run){ stats.hmax = Math.max(old_hmax, run.xmax); } + if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } + if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } + } + } + return stats; + }, + + collectStackedStats: function(series){ + // collect statistics + var stats = dojo.clone(dc.defaultStats); + if(series.length){ + // 1st pass: find the maximal length of runs + stats.hmin = Math.min(stats.hmin, 1); + stats.hmax = df.foldl(series, "seed, run -> Math.max(seed, run.data.length)", stats.hmax); + // 2nd pass: stack values + for(var i = 0; i < stats.hmax; ++i){ + var v = series[0].data[i]; + if(isNaN(v)){ v = 0; } + stats.vmin = Math.min(stats.vmin, v); + for(var j = 1; j < series.length; ++j){ + var t = series[j].data[i]; + if(isNaN(t)){ t = 0; } + v += t; + } + stats.vmax = Math.max(stats.vmax, v); + } + } + return stats; + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot3d/Bars.js b/includes/js/dojox/charting/plot3d/Bars.js new file mode 100644 index 0000000..8fbe67c --- /dev/null +++ b/includes/js/dojox/charting/plot3d/Bars.js @@ -0,0 +1,66 @@ +if(!dojo._hasResource["dojox.charting.plot3d.Bars"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot3d.Bars"] = true; +dojo.provide("dojox.charting.plot3d.Bars"); + +dojo.require("dojox.charting.plot3d.Base"); + +(function(){ + + // reduce function borrowed from dojox.fun + var reduce = function(/*Array*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from left + // to right; returns the final value. + a = typeof a == "string" ? a.split("") : a; o = o || dojo.global; + var z = a[0]; + for(var i = 1; i < a.length; z = f.call(o, z, a[i++])); + return z; // Object + }; + + dojo.declare("dojox.charting.plot3d.Bars", dojox.charting.plot3d.Base, { + constructor: function(width, height, kwArgs){ + this.depth = "auto"; + this.gap = 0; + this.data = []; + this.material = {type: "plastic", finish: "dull", color: "lime"}; + if(kwArgs){ + if("depth" in kwArgs){ this.depth = kwArgs.depth; } + if("gap" in kwArgs){ this.gap = kwArgs.gap; } + if("material" in kwArgs){ + var m = kwArgs.material; + if(typeof m == "string" || m instanceof dojo.Color){ + this.material.color = m; + }else{ + this.material = m; + } + } + } + }, + getDepth: function(){ + if(this.depth == "auto"){ + var w = this.width; + if(this.data && this.data.length){ + w = w / this.data.length; + } + return w - 2 * this.gap; + } + return this.depth; + }, + generate: function(chart, creator){ + if(!this.data){ return this; } + var step = this.width / this.data.length, org = 0, + depth = this.depth == "auto" ? step - 2 * this.gap : this.depth, + scale = this.height / reduce(this.data, Math.max); + if(!creator){ creator = chart.view; } + for(var i = 0; i < this.data.length; ++i, org += step){ + creator + .createCube({ + bottom: {x: org + this.gap, y: 0, z: 0}, + top: {x: org + step - this.gap, y: this.data[i] * scale, z: depth} + }) + .setFill(this.material); + } + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/plot3d/Base.js b/includes/js/dojox/charting/plot3d/Base.js new file mode 100644 index 0000000..5ba5dc4 --- /dev/null +++ b/includes/js/dojox/charting/plot3d/Base.js @@ -0,0 +1,23 @@ +if(!dojo._hasResource["dojox.charting.plot3d.Base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot3d.Base"] = true; +dojo.provide("dojox.charting.plot3d.Base"); + +dojo.require("dojox.charting.Chart3D"); + +dojo.declare("dojox.charting.plot3d.Base", null, { + constructor: function(width, height, kwArgs){ + this.width = width; + this.height = height; + }, + setData: function(data){ + this.data = data ? data : []; + return this; + }, + getDepth: function(){ + return this.depth; + }, + generate: function(chart, creator){ + } +}); + +} diff --git a/includes/js/dojox/charting/plot3d/Cylinders.js b/includes/js/dojox/charting/plot3d/Cylinders.js new file mode 100644 index 0000000..96433d4 --- /dev/null +++ b/includes/js/dojox/charting/plot3d/Cylinders.js @@ -0,0 +1,69 @@ +if(!dojo._hasResource["dojox.charting.plot3d.Cylinders"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.plot3d.Cylinders"] = true; +dojo.provide("dojox.charting.plot3d.Cylinders"); + +dojo.require("dojox.charting.plot3d.Base"); + +(function(){ + + // reduce function borrowed from dojox.fun + var reduce = function(/*Array*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from left + // to right; returns the final value. + a = typeof a == "string" ? a.split("") : a; o = o || dojo.global; + var z = a[0]; + for(var i = 1; i < a.length; z = f.call(o, z, a[i++])); + return z; // Object + }; + + dojo.declare("dojox.charting.plot3d.Cylinders", dojox.charting.plot3d.Base, { + constructor: function(width, height, kwArgs){ + this.depth = "auto"; + this.gap = 0; + this.data = []; + this.material = {type: "plastic", finish: "shiny", color: "lime"}; + this.outline = null; + if(kwArgs){ + if("depth" in kwArgs){ this.depth = kwArgs.depth; } + if("gap" in kwArgs){ this.gap = kwArgs.gap; } + if("material" in kwArgs){ + var m = kwArgs.material; + if(typeof m == "string" || m instanceof dojo.Color){ + this.material.color = m; + }else{ + this.material = m; + } + } + if("outline" in kwArgs){ this.outline = kwArgs.outline; } + } + }, + getDepth: function(){ + if(this.depth == "auto"){ + var w = this.width; + if(this.data && this.data.length){ + w = w / this.data.length; + } + return w - 2 * this.gap; + } + return this.depth; + }, + generate: function(chart, creator){ + if(!this.data){ return this; } + var step = this.width / this.data.length, org = 0, + scale = this.height / reduce(this.data, Math.max); + if(!creator){ creator = chart.view; } + for(var i = 0; i < this.data.length; ++i, org += step){ + creator + .createCylinder({ + center: {x: org + step / 2, y: 0, z: 0}, + radius: step / 2 - this.gap, + height: this.data[i] * scale + }) + .setTransform(dojox.gfx3d.matrix.rotateXg(-90)) + .setFill(this.material).setStroke(this.outline); + } + } + }); +})(); + +} diff --git a/includes/js/dojox/charting/scaler.js b/includes/js/dojox/charting/scaler.js new file mode 100644 index 0000000..8a3d091 --- /dev/null +++ b/includes/js/dojox/charting/scaler.js @@ -0,0 +1,161 @@ +if(!dojo._hasResource["dojox.charting.scaler"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.scaler"] = true; +dojo.provide("dojox.charting.scaler"); + +(function(){ + var deltaLimit = 3; // pixels + + var isText = function(val, text){ + val = val.toLowerCase(); + for(var i = 0; i < text.length; ++i){ + if(val == text[i]){ return true; } + } + return false; + }; + + var calcTicks = function(min, max, kwArgs, majorTick, minorTick, microTick, span){ + kwArgs = dojo.clone(kwArgs); + if(!majorTick){ + if(kwArgs.fixUpper == "major"){ kwArgs.fixUpper = "minor"; } + if(kwArgs.fixLower == "major"){ kwArgs.fixLower = "minor"; } + } + if(!minorTick){ + if(kwArgs.fixUpper == "minor"){ kwArgs.fixUpper = "micro"; } + if(kwArgs.fixLower == "minor"){ kwArgs.fixLower = "micro"; } + } + if(!microTick){ + if(kwArgs.fixUpper == "micro"){ kwArgs.fixUpper = "none"; } + if(kwArgs.fixLower == "micro"){ kwArgs.fixLower = "none"; } + } + var lowerBound = isText(kwArgs.fixLower, ["major"]) ? + Math.floor(min / majorTick) * majorTick : + isText(kwArgs.fixLower, ["minor"]) ? + Math.floor(min / minorTick) * minorTick : + isText(kwArgs.fixLower, ["micro"]) ? + Math.floor(min / microTick) * unit : min, + upperBound = isText(kwArgs.fixUpper, ["major"]) ? + Math.ceil(max / majorTick) * majorTick : + isText(kwArgs.fixUpper, ["minor"]) ? + Math.ceil(max / minorTick) * minorTick : + isText(kwArgs.fixUpper, ["unit"]) ? + Math.ceil(max / unit) * unit : max, + majorStart = (isText(kwArgs.fixLower, ["major"]) || !majorTick) ? + lowerBound : Math.ceil(lowerBound / majorTick) * majorTick, + minorStart = (isText(kwArgs.fixLower, ["major", "minor"]) || !minorTick) ? + lowerBound : Math.ceil(lowerBound / minorTick) * minorTick, + microStart = (isText(kwArgs.fixLower, ["major", "minor", "micro"]) || ! microTick) ? + lowerBound : Math.ceil(lowerBound / microTick) * microTick, + majorCount = !majorTick ? 0 : (isText(kwArgs.fixUpper, ["major"]) ? + Math.round((upperBound - majorStart) / majorTick) : + Math.floor((upperBound - majorStart) / majorTick)) + 1, + minorCount = !minorTick ? 0 : (isText(kwArgs.fixUpper, ["major", "minor"]) ? + Math.round((upperBound - minorStart) / minorTick) : + Math.floor((upperBound - minorStart) / minorTick)) + 1, + microCount = !microTick ? 0 : (isText(kwArgs.fixUpper, ["major", "minor", "micro"]) ? + Math.round((upperBound - microStart) / microTick) : + Math.floor((upperBound - microStart) / microTick)) + 1, + minorPerMajor = minorTick ? Math.round(majorTick / minorTick) : 0, + microPerMinor = microTick ? Math.round(minorTick / microTick) : 0, + majorPrecision = majorTick ? Math.floor(Math.log(majorTick) / Math.LN10) : 0, + minorPrecision = minorTick ? Math.floor(Math.log(minorTick) / Math.LN10) : 0, + scale = span / (upperBound - lowerBound); + if(!isFinite(scale)){ scale = 1; } + return { + bounds: { + lower: lowerBound, + upper: upperBound + }, + major: { + tick: majorTick, + start: majorStart, + count: majorCount, + prec: majorPrecision + }, + minor: { + tick: minorTick, + start: minorStart, + count: minorCount, + prec: minorPrecision + }, + micro: { + tick: microTick, + start: microStart, + count: microCount, + prec: 0 + }, + minorPerMajor: minorPerMajor, + microPerMinor: microPerMinor, + scale: scale + }; + }; + + dojox.charting.scaler = function(min, max, span, kwArgs){ + var h = {fixUpper: "none", fixLower: "none", natural: false}; + if(kwArgs){ + if("fixUpper" in kwArgs){ h.fixUpper = String(kwArgs.fixUpper); } + if("fixLower" in kwArgs){ h.fixLower = String(kwArgs.fixLower); } + if("natural" in kwArgs){ h.natural = Boolean(kwArgs.natural); } + } + + if(max <= min){ + return calcTicks(min, max, h, 0, 0, 0, span); // Object + } + + var mag = Math.floor(Math.log(max - min) / Math.LN10), + major = kwArgs && ("majorTick" in kwArgs) ? kwArgs.majorTick : Math.pow(10, mag), + minor = 0, micro = 0, ticks; + + // calculate minor ticks + if(kwArgs && ("minorTick" in kwArgs)){ + minor = kwArgs.minorTick; + }else{ + do{ + minor = major / 10; + if(!h.natural || minor > 0.9){ + ticks = calcTicks(min, max, h, major, minor, 0, span); + if(ticks.scale * ticks.minor.tick > deltaLimit){ break; } + } + minor = major / 5; + if(!h.natural || minor > 0.9){ + ticks = calcTicks(min, max, h, major, minor, 0, span); + if(ticks.scale * ticks.minor.tick > deltaLimit){ break; } + } + minor = major / 2; + if(!h.natural || minor > 0.9){ + ticks = calcTicks(min, max, h, major, minor, 0, span); + if(ticks.scale * ticks.minor.tick > deltaLimit){ break; } + } + return calcTicks(min, max, h, major, 0, 0, span); // Object + }while(false); + } + + // calculate micro ticks + if(kwArgs && ("microTick" in kwArgs)){ + micro = kwArgs.microTick; + ticks = calcTicks(min, max, h, major, minor, micro, span); + }else{ + do{ + micro = minor / 10; + if(!h.natural || micro > 0.9){ + ticks = calcTicks(min, max, h, major, minor, micro, span); + if(ticks.scale * ticks.micro.tick > deltaLimit){ break; } + } + micro = minor / 5; + if(!h.natural || micro > 0.9){ + ticks = calcTicks(min, max, h, major, minor, micro, span); + if(ticks.scale * ticks.micro.tick > deltaLimit){ break; } + } + micro = minor / 2; + if(!h.natural || micro > 0.9){ + ticks = calcTicks(min, max, h, major, minor, micro, span); + if(ticks.scale * ticks.micro.tick > deltaLimit){ break; } + } + micro = 0; + }while(false); + } + + return micro ? ticks : calcTicks(min, max, h, major, minor, 0, span); // Object + }; +})(); + +} diff --git a/includes/js/dojox/charting/tests/Theme.js b/includes/js/dojox/charting/tests/Theme.js new file mode 100644 index 0000000..c30635c --- /dev/null +++ b/includes/js/dojox/charting/tests/Theme.js @@ -0,0 +1,71 @@ +if(!dojo._hasResource["dojox.charting.tests.Theme"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.tests.Theme"] = true; +dojo.provide("dojox.charting.tests.Theme"); +dojo.require("dojox.charting.Theme"); +dojo.require("dojox.charting.themes.PlotKit.blue"); + +(function(){ + var dxc=dojox.charting; + var blue=dxc.themes.PlotKit.blue; + tests.register("dojox.charting.tests.Theme", [ + function testDefineColor(t){ + var args={ num:16, cache:false }; + blue.defineColors(args); + var a=blue.colors; + var s=""; + for(var i=0; i0) s+=""; + s+=""; + } + s+=''; + } + s+="
 
"; + doh.debug(s); + + var args={ num:32, cache: false }; + blue.defineColors(args); + var a=blue.colors; + var s=""; + for(var i=0; i0) s+=""; + s+=""; + } + s+=''; + } + s+="
 
"; + doh.debug(s); + + var args={ saturation:20, num:32, cache:false }; + blue.defineColors(args); + var a=blue.colors; + var s=""; + for(var i=0; i0) s+=""; + s+=""; + } + s+=''; + } + s+="
 
"; + doh.debug(s); + + var args={ low:10, high:90, num:32, cache: false }; + blue.defineColors(args); + var a=blue.colors; + var s=""; + for(var i=0; i0) s+=""; + s+=""; + } + s+=''; + } + s+="
 
"; + doh.debug(s); + } + ]); +})(); + +} diff --git a/includes/js/dojox/charting/tests/_color.js b/includes/js/dojox/charting/tests/_color.js new file mode 100644 index 0000000..df263df --- /dev/null +++ b/includes/js/dojox/charting/tests/_color.js @@ -0,0 +1,82 @@ +if(!dojo._hasResource["dojox.charting.tests._color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.tests._color"] = true; +dojo.provide("dojox.charting.tests._color"); +dojo.require("dojox.charting._color"); + +/* + Note that there are some minor inaccuracies that + can be introduced for comparison purposes; the + formulae used in Photoshop may produce *slightly* + different numbers. But numbers will be off by + 1, if at all. + */ +(function(){ + var dxc=dojox.charting; + var rgb=[ + { r:0x4f, g:0xc8, b:0xd6 }, + { r:0x40, g:0x9e, b:0x02 }, + { r:0xff, g:0xfb, b:0x85 }, + { r:0x7b, g:0x5a, b:0x7d } + ]; + var hsb=[ + { h:186, s:63, b: 84 }, + { h: 96, s:99, b: 62 }, + { h: 58, s:48, b:100 }, + { h:297, s:28, b: 49 } + ]; + tests.register("dojox.charting.tests._util", [ + function testToHsb(t){ + var c=rgb[0]; + var oHsb=dxc._color.toHsb(c.r, c.g, c.b); + t.assertEqual(hsb[0].h, oHsb.h); + t.assertEqual(hsb[0].s, oHsb.s); + t.assertEqual(hsb[0].b, oHsb.b); + + var c=rgb[1]; + var oHsb=dxc._color.toHsb(c.r, c.g, c.b); + t.assertEqual(hsb[1].h, oHsb.h); + t.assertEqual(hsb[1].s, oHsb.s); + t.assertEqual(hsb[1].b, oHsb.b); + + var c=rgb[2]; + var oHsb=dxc._color.toHsb(c.r, c.g, c.b); + t.assertEqual(hsb[2].h, oHsb.h); + t.assertEqual(hsb[2].s, oHsb.s); + t.assertEqual(hsb[2].b, oHsb.b); + + var c=rgb[3]; + var oHsb=dxc._color.toHsb(c.r, c.g, c.b); + t.assertEqual(hsb[3].h, oHsb.h); + t.assertEqual(hsb[3].s, oHsb.s); + t.assertEqual(hsb[3].b, oHsb.b); + }, + + function testFromHsb(t){ + var c1=dxc._color.fromHsb(hsb[0].h, hsb[0].s, hsb[0].b); + var c2=rgb[0]; + t.assertEqual(c1.r, c2.r); + t.assertEqual(c1.g, c2.g); + t.assertEqual(c1.b, c2.b); + + var c1=dxc._color.fromHsb(hsb[1].h, hsb[1].s, hsb[1].b); + var c2=rgb[1]; + t.assertEqual(c1.r, c2.r); + t.assertEqual(c1.g, c2.g); + t.assertEqual(c1.b, c2.b); + + var c1=dxc._color.fromHsb(hsb[2].h, hsb[2].s, hsb[2].b); + var c2=rgb[2]; + t.assertEqual(c1.r, c2.r); + t.assertEqual(c1.g, c2.g); + t.assertEqual(c1.b, c2.b); + + var c1=dxc._color.fromHsb(hsb[3].h, hsb[3].s, hsb[3].b); + var c2=rgb[3]; + t.assertEqual(c1.r, c2.r); + t.assertEqual(c1.g, c2.g); + t.assertEqual(c1.b, c2.b); + } + ]); +})(); + +} diff --git a/includes/js/dojox/charting/tests/charting.js b/includes/js/dojox/charting/tests/charting.js new file mode 100644 index 0000000..500f354 --- /dev/null +++ b/includes/js/dojox/charting/tests/charting.js @@ -0,0 +1,12 @@ +if(!dojo._hasResource["dojox.charting.tests.charting"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.tests.charting"] = true; +dojo.provide("dojox.charting.tests.charting"); + +try{ + dojo.require("dojox.charting.tests._color"); + dojo.require("dojox.charting.tests.Theme"); +}catch(e){ + doh.debug(e); +} + +} diff --git a/includes/js/dojox/charting/tests/data/goog_prices.csv b/includes/js/dojox/charting/tests/data/goog_prices.csv new file mode 100644 index 0000000..901a6d2 --- /dev/null +++ b/includes/js/dojox/charting/tests/data/goog_prices.csv @@ -0,0 +1,796 @@ +Date,Open,High,Low,Close,Volume,Adj Close +2008-02-29,471.87,479.74,464.65,471.18,9425400,471.18 +2008-02-28,470.50,479.09,467.36,475.39,6586900,475.39 +2008-02-27,460.13,475.49,459.64,472.86,10121900,472.86 +2008-02-26,461.20,466.47,446.85,464.19,23287300,464.19 +2008-02-25,505.95,506.50,485.74,486.44,8350800,486.44 +2008-02-22,502.06,509.00,497.55,507.80,5515900,507.80 +2008-02-21,512.85,513.21,499.50,502.86,5677800,502.86 +2008-02-20,503.51,511.01,498.82,509.00,6662200,509.00 +2008-02-19,534.94,535.06,506.50,508.95,6350400,508.95 +2008-02-15,528.31,532.66,524.33,529.64,5240100,529.64 +2008-02-14,538.35,541.04,531.00,532.25,6476700,532.25 +2008-02-13,522.50,534.99,518.69,534.62,6624700,534.62 +2008-02-12,523.39,530.60,513.03,518.09,6662300,518.09 +2008-02-11,520.52,523.71,513.40,521.16,5826000,521.16 +2008-02-08,509.41,517.73,508.70,516.69,6828900,516.69 +2008-02-07,496.86,514.19,494.76,504.95,7928900,504.95 +2008-02-06,511.14,511.17,497.93,501.71,7636400,501.71 +2008-02-05,489.43,509.00,488.52,506.80,11203300,506.80 +2008-02-04,509.07,512.78,492.55,495.43,13157100,495.43 +2008-02-01,528.67,536.67,510.00,515.90,17600500,515.90 +2008-01-31,539.01,573.00,534.29,564.30,14871300,564.30 +2008-01-30,549.19,560.43,543.51,548.27,7939600,548.27 +2008-01-29,560.47,561.33,540.67,550.52,6283000,550.52 +2008-01-28,570.97,572.24,548.60,555.98,5816700,555.98 +2008-01-25,591.81,595.00,566.18,566.40,6966000,566.40 +2008-01-24,558.80,579.69,554.14,574.49,9400900,574.49 +2008-01-23,560.71,568.00,519.00,548.62,16965700,548.62 +2008-01-22,562.03,597.50,561.20,584.35,9501500,584.35 +2008-01-18,608.36,609.99,598.45,600.25,8539600,600.25 +2008-01-17,620.76,625.74,598.01,600.79,8216800,600.79 +2008-01-16,628.97,639.99,601.93,615.95,10560000,615.95 +2008-01-15,645.90,649.05,635.38,637.65,5568200,637.65 +2008-01-14,651.14,657.40,645.25,653.82,4447500,653.82 +2008-01-11,642.70,649.47,630.11,638.25,4977000,638.25 +2008-01-10,645.01,657.20,640.11,646.73,6334200,646.73 +2008-01-09,630.04,653.34,622.51,653.20,6739700,653.20 +2008-01-08,653.00,659.96,631.00,631.68,5339100,631.68 +2008-01-07,653.94,662.28,637.35,649.25,6403400,649.25 +2008-01-04,679.69,680.96,655.00,657.00,5359800,657.00 +2008-01-03,685.26,686.85,676.52,685.33,3252500,685.33 +2008-01-02,692.87,697.37,677.73,685.19,4306900,685.19 +2007-12-31,698.57,702.49,690.58,691.48,2376200,691.48 +2007-12-28,704.93,707.95,696.54,702.53,2562700,702.53 +2007-12-27,707.07,716.00,700.74,700.74,2942500,700.74 +2007-12-26,698.99,713.22,698.21,710.84,2530000,710.84 +2007-12-24,694.99,700.73,693.06,700.73,1628400,700.73 +2007-12-21,697.88,699.26,693.24,696.69,5382000,696.69 +2007-12-20,685.83,691.00,680.61,689.69,4422200,689.69 +2007-12-19,674.21,679.50,669.00,677.37,4421100,677.37 +2007-12-18,674.16,676.71,652.50,673.35,7166700,673.35 +2007-12-17,688.00,695.42,663.67,669.23,5486000,669.23 +2007-12-14,687.51,699.70,687.26,689.96,3673500,689.96 +2007-12-13,696.31,697.62,681.21,694.05,5040800,694.05 +2007-12-12,714.00,714.32,688.50,699.35,6159100,699.35 +2007-12-11,719.94,720.99,698.78,699.20,6139100,699.20 +2007-12-10,715.99,724.80,714.00,718.42,3856200,718.42 +2007-12-07,714.99,718.00,710.50,714.87,3852100,714.87 +2007-12-06,697.80,716.56,697.01,715.26,4909000,715.26 +2007-12-05,692.73,698.93,687.50,698.51,4209600,698.51 +2007-12-04,678.31,692.00,677.12,684.16,4231800,684.16 +2007-12-03,691.01,695.00,681.14,681.53,4325100,681.53 +2007-11-30,711.00,711.06,682.11,693.00,7895500,693.00 +2007-11-29,690.75,702.79,687.77,697.00,6208000,697.00 +2007-11-28,682.11,694.30,672.14,692.26,7916500,692.26 +2007-11-27,674.80,676.43,650.26,673.57,8904500,673.57 +2007-11-26,680.20,693.40,665.00,666.00,6790100,666.00 +2007-11-23,670.00,678.28,668.11,676.70,2738700,676.70 +2007-11-21,643.77,669.97,642.08,660.52,7013500,660.52 +2007-11-20,636.48,659.10,632.87,648.54,9840600,648.54 +2007-11-19,629.59,636.77,618.50,625.85,5527400,625.85 +2007-11-16,633.94,635.49,616.02,633.63,9042800,633.63 +2007-11-15,638.57,647.50,624.00,629.65,6967700,629.65 +2007-11-14,673.28,675.49,636.27,641.68,8094700,641.68 +2007-11-13,644.99,660.92,632.07,660.55,8426100,660.55 +2007-11-12,657.74,669.93,626.21,632.07,10227300,632.07 +2007-11-09,675.78,681.88,661.21,663.97,11388100,663.97 +2007-11-08,734.60,734.89,677.18,693.84,16512200,693.84 +2007-11-07,741.13,747.24,723.14,732.94,8252900,732.94 +2007-11-06,737.56,741.79,725.00,741.79,8436300,741.79 +2007-11-05,706.99,730.23,706.07,725.65,8883700,725.65 +2007-11-02,710.51,713.58,697.34,711.25,5841500,711.25 +2007-11-01,702.79,713.72,701.78,703.21,6527200,703.21 +2007-10-31,700.69,707.00,696.04,707.00,6876800,707.00 +2007-10-30,677.51,699.91,677.51,694.77,6900600,694.77 +2007-10-29,677.77,680.00,672.09,679.23,3066300,679.23 +2007-10-26,674.03,676.54,668.06,674.60,3353900,674.60 +2007-10-25,678.68,678.97,663.55,668.51,5795500,668.51 +2007-10-24,672.71,677.47,659.56,675.82,7404200,675.82 +2007-10-23,661.25,677.60,660.00,675.77,6793700,675.77 +2007-10-22,638.67,655.00,636.28,650.75,6664400,650.75 +2007-10-19,654.56,658.49,643.23,644.71,15789000,644.71 +2007-10-18,635.41,641.37,628.50,639.62,12289200,639.62 +2007-10-17,630.45,634.00,621.59,633.48,6030500,633.48 +2007-10-16,618.49,625.92,611.99,616.00,6025300,616.00 +2007-10-15,638.47,639.86,615.55,620.11,6943800,620.11 +2007-10-12,623.98,638.40,618.24,637.39,6823700,637.39 +2007-10-11,633.64,641.41,609.00,622.00,11799000,622.00 +2007-10-10,621.36,625.68,616.80,625.39,5385600,625.39 +2007-10-09,615.11,623.78,608.39,615.18,8767800,615.18 +2007-10-08,595.00,610.26,593.95,609.62,5028000,609.62 +2007-10-05,587.11,596.00,587.01,594.05,5068700,594.05 +2007-10-04,585.09,585.09,577.06,579.03,2986700,579.03 +2007-10-03,586.25,588.99,580.36,584.02,3879500,584.02 +2007-10-02,583.38,596.81,580.01,584.39,7067500,584.39 +2007-10-01,569.97,584.35,569.61,582.55,4711300,582.55 +2007-09-28,567.00,569.55,564.12,567.27,2639500,567.27 +2007-09-27,571.73,571.74,565.78,567.50,2056300,567.50 +2007-09-26,570.40,571.79,563.81,568.16,3346100,568.16 +2007-09-25,564.00,569.56,562.86,569.00,2730600,569.00 +2007-09-24,561.00,571.46,560.00,568.02,5297000,568.02 +2007-09-21,556.34,560.79,552.83,560.10,8011700,560.10 +2007-09-20,547.00,556.80,546.03,552.83,5525000,552.83 +2007-09-19,539.27,549.45,538.86,546.85,5526900,546.85 +2007-09-18,526.52,537.25,524.27,535.27,4215700,535.27 +2007-09-17,526.53,529.28,524.07,525.30,2197500,525.30 +2007-09-14,523.20,530.27,522.22,528.75,2764900,528.75 +2007-09-13,524.06,527.21,523.22,524.78,1891100,524.78 +2007-09-12,520.53,527.98,519.00,522.65,2986000,522.65 +2007-09-11,516.99,521.65,515.73,521.33,2703600,521.33 +2007-09-10,521.28,522.07,510.88,514.48,3225800,514.48 +2007-09-07,517.86,521.24,516.80,519.35,3663600,519.35 +2007-09-06,529.36,529.83,518.24,523.52,3625900,523.52 +2007-09-05,523.40,529.48,522.25,527.80,3312900,527.80 +2007-09-04,515.02,528.00,514.62,525.15,3693700,525.15 +2007-08-31,513.10,516.50,511.47,515.25,2977600,515.25 +2007-08-30,512.36,515.40,510.58,511.40,2651700,511.40 +2007-08-29,507.84,513.30,507.23,512.88,2549300,512.88 +2007-08-28,511.53,514.98,505.79,506.40,3273900,506.40 +2007-08-27,514.43,517.45,511.40,513.26,2325100,513.26 +2007-08-24,512.61,515.55,508.50,515.00,2472700,515.00 +2007-08-23,516.00,516.13,507.00,512.19,3076700,512.19 +2007-08-22,509.96,516.25,509.25,512.75,3252700,512.75 +2007-08-21,498.94,508.16,497.77,506.61,3610600,506.61 +2007-08-20,502.46,502.56,496.00,497.92,2697300,497.92 +2007-08-17,497.44,501.00,491.65,500.04,5479400,500.04 +2007-08-16,492.02,496.43,480.46,491.52,8645600,491.52 +2007-08-15,509.00,511.69,496.71,497.55,5409500,497.55 +2007-08-14,515.72,517.40,508.00,508.60,3633700,508.60 +2007-08-13,519.54,519.75,513.03,515.50,3179300,515.50 +2007-08-10,510.18,518.72,505.63,515.75,5875200,515.75 +2007-08-09,520.80,526.82,514.63,514.73,4846500,514.73 +2007-08-08,519.34,525.78,517.09,525.78,4068800,525.78 +2007-08-07,509.75,519.88,509.04,516.02,4264300,516.02 +2007-08-06,503.00,510.15,502.50,510.00,3651500,510.00 +2007-08-03,510.05,513.20,503.00,503.00,3176200,503.00 +2007-08-02,513.72,514.99,509.00,511.01,3154900,511.01 +2007-08-01,510.50,516.51,508.14,512.94,4421500,512.94 +2007-07-31,520.23,520.44,510.00,510.00,4270500,510.00 +2007-07-30,512.92,519.34,510.50,516.11,3963300,516.11 +2007-07-27,508.53,516.62,505.50,511.89,5509100,511.89 +2007-07-26,508.74,512.59,498.88,508.00,6883400,508.00 +2007-07-25,516.98,517.02,505.56,509.76,5545000,509.76 +2007-07-24,509.30,518.69,507.11,514.00,5572100,514.00 +2007-07-23,519.01,520.00,512.15,512.51,6356700,512.51 +2007-07-20,511.90,523.18,509.50,520.12,17772300,520.12 +2007-07-19,553.46,553.52,542.24,548.59,11127200,548.59 +2007-07-18,553.89,554.50,543.81,549.50,6080000,549.50 +2007-07-17,555.04,557.73,552.38,555.00,4328600,555.00 +2007-07-16,550.30,558.58,549.31,552.99,6599500,552.99 +2007-07-13,547.91,552.67,547.25,552.16,5237100,552.16 +2007-07-12,545.86,547.32,540.22,545.33,3441600,545.33 +2007-07-11,543.61,546.50,540.01,544.47,3309300,544.47 +2007-07-10,543.79,547.00,541.65,543.34,3856000,543.34 +2007-07-09,543.00,548.74,540.26,542.56,3729800,542.56 +2007-07-06,541.25,543.87,538.73,539.40,2747000,539.40 +2007-07-05,535.56,544.40,532.15,541.63,4942900,541.63 +2007-07-03,531.06,534.40,527.50,534.34,1871800,534.34 +2007-07-02,525.49,531.85,524.20,530.38,3487600,530.38 +2007-06-29,526.02,527.40,519.46,522.70,3880600,522.70 +2007-06-28,524.88,529.50,523.80,525.01,4168400,525.01 +2007-06-27,525.00,527.99,519.56,526.29,6123100,526.29 +2007-06-26,532.73,533.20,526.24,530.26,5689500,530.26 +2007-06-25,528.98,534.99,523.38,527.42,7925000,527.42 +2007-06-22,516.42,524.99,516.10,524.98,7203700,524.98 +2007-06-21,510.98,515.29,506.28,514.11,4409700,514.11 +2007-06-20,516.96,518.75,509.06,509.97,4338200,509.97 +2007-06-19,514.01,517.25,511.54,514.31,4355300,514.31 +2007-06-18,506.18,516.00,504.24,515.20,4835900,515.20 +2007-06-15,508.19,509.00,501.23,505.89,6174100,505.89 +2007-06-14,505.38,505.88,501.70,502.84,4621200,502.84 +2007-06-13,507.09,508.54,498.69,505.24,7034000,505.24 +2007-06-12,508.71,511.67,503.17,504.77,6419500,504.77 +2007-06-11,514.02,518.25,510.00,511.34,4647700,511.34 +2007-06-08,516.20,519.64,509.46,515.49,6358200,515.49 +2007-06-07,519.75,526.50,512.51,515.06,10630500,515.06 +2007-06-06,516.75,520.78,515.26,518.25,7886700,518.25 +2007-06-05,509.75,519.00,506.61,518.84,10447100,518.84 +2007-06-04,497.91,510.51,497.59,507.07,7101000,507.07 +2007-06-01,501.00,505.02,497.93,500.40,4799000,500.40 +2007-05-31,500.56,508.78,497.06,497.91,8924300,497.91 +2007-05-30,484.50,498.84,483.00,498.60,7245800,498.60 +2007-05-29,485.00,491.80,484.00,487.11,5218000,487.11 +2007-05-25,479.70,484.95,477.27,483.52,5348500,483.52 +2007-05-24,475.15,479.20,471.50,474.33,4173600,474.33 +2007-05-23,480.82,483.41,473.75,473.97,5060200,473.97 +2007-05-22,473.00,479.01,473.00,475.86,3839000,475.86 +2007-05-21,469.53,479.20,466.72,470.60,6159300,470.60 +2007-05-18,472.03,472.70,469.75,470.32,3695900,470.32 +2007-05-17,472.46,475.22,470.81,470.96,4660600,470.96 +2007-05-16,462.00,473.14,459.02,472.61,6554200,472.61 +2007-05-15,461.96,462.54,457.41,458.00,4119000,458.00 +2007-05-14,465.48,467.51,460.00,461.78,3872700,461.78 +2007-05-11,461.83,467.00,461.00,466.74,2944100,466.74 +2007-05-10,467.04,469.49,461.02,461.47,3686300,461.47 +2007-05-09,466.15,471.73,463.88,469.25,3889900,469.25 +2007-05-08,466.13,468.17,464.73,466.81,2905100,466.81 +2007-05-07,472.14,472.82,466.47,467.27,3020100,467.27 +2007-05-04,470.12,474.84,465.88,471.12,3950000,471.12 +2007-05-03,466.22,474.07,465.29,473.23,3594200,473.23 +2007-05-02,468.65,471.08,465.73,465.78,3062700,465.78 +2007-05-01,472.19,472.81,464.17,469.00,3658200,469.00 +2007-04-30,479.15,481.35,471.38,471.38,3641200,471.38 +2007-04-27,480.07,482.40,478.33,479.01,2925700,479.01 +2007-04-26,478.10,484.45,477.11,481.18,4124900,481.18 +2007-04-25,480.00,481.37,476.11,477.99,3966800,477.99 +2007-04-24,478.61,479.98,475.55,477.53,3694700,477.53 +2007-04-23,480.10,485.00,478.26,479.08,5674600,479.08 +2007-04-20,490.52,492.50,482.02,482.48,12161500,482.48 +2007-04-19,474.50,481.95,469.59,471.65,11009600,471.65 +2007-04-18,471.26,479.90,469.53,476.01,5670500,476.01 +2007-04-17,473.80,476.39,471.60,472.80,3210100,472.80 +2007-04-16,468.46,476.99,468.15,474.27,5077900,474.27 +2007-04-13,468.45,468.77,463.36,466.29,2794800,466.29 +2007-04-12,464.00,468.00,462.24,467.39,2707900,467.39 +2007-04-11,466.06,469.40,462.61,464.53,3812000,464.53 +2007-04-10,467.09,470.79,465.16,466.50,2979300,466.50 +2007-04-09,472.98,473.00,465.59,468.21,3062100,468.21 +2007-04-05,471.30,472.09,469.62,471.51,2715800,471.51 +2007-04-04,472.14,473.00,469.58,471.02,3778800,471.02 +2007-04-03,464.05,474.25,464.00,472.60,6501800,472.60 +2007-04-02,457.76,458.53,452.12,458.53,3448500,458.53 +2007-03-30,462.10,463.40,456.14,458.16,3380200,458.16 +2007-03-29,464.55,466.00,455.00,460.92,3988500,460.92 +2007-03-28,461.87,465.44,460.15,461.88,4591600,461.88 +2007-03-27,463.55,465.23,460.34,463.62,3741200,463.62 +2007-03-26,460.55,465.00,455.62,465.00,4710300,465.00 +2007-03-23,461.45,463.39,457.08,461.83,4111300,461.83 +2007-03-22,455.61,462.17,452.53,462.04,5680700,462.04 +2007-03-21,445.30,456.57,445.21,456.55,5798300,456.55 +2007-03-20,445.79,447.60,443.60,445.28,3421500,445.28 +2007-03-19,443.25,448.50,440.63,447.23,5197700,447.23 +2007-03-16,445.65,446.70,439.89,440.85,5659100,440.85 +2007-03-15,447.86,449.82,443.94,446.19,3944200,446.19 +2007-03-14,443.23,448.66,439.00,448.00,8016900,448.00 +2007-03-13,450.11,451.93,442.83,443.03,6377300,443.03 +2007-03-12,452.57,455.25,451.11,454.75,3465400,454.75 +2007-03-09,458.00,458.40,450.10,452.96,4977700,452.96 +2007-03-08,459.22,465.50,454.10,454.72,5362800,454.72 +2007-03-07,462.69,463.14,454.29,455.64,6534100,455.64 +2007-03-06,447.47,459.00,447.38,457.55,7533700,457.55 +2007-03-05,437.02,445.50,437.00,440.95,6355100,440.95 +2007-03-02,445.11,448.70,438.68,438.68,6583600,438.68 +2007-03-01,442.67,452.42,440.00,448.23,8685200,448.23 +2007-02-28,450.41,453.67,443.04,449.45,8032300,449.45 +2007-02-27,455.00,459.80,447.17,448.77,9312800,448.77 +2007-02-26,472.83,475.25,463.75,464.93,3969900,464.93 +2007-02-23,475.75,476.95,467.80,470.62,3882600,470.62 +2007-02-22,478.69,484.24,474.39,475.85,5743900,475.85 +2007-02-21,469.84,478.68,467.74,475.86,5640600,475.86 +2007-02-20,468.47,472.75,464.71,472.10,4067600,472.10 +2007-02-16,462.80,470.15,462.06,469.94,6177000,469.94 +2007-02-15,466.00,466.13,460.72,461.47,4042400,461.47 +2007-02-14,460.00,469.13,459.22,465.93,5698800,465.93 +2007-02-13,459.15,462.78,457.26,459.10,4062600,459.10 +2007-02-12,460.68,462.39,455.02,458.29,5754500,458.29 +2007-02-09,471.65,472.68,461.50,461.89,4858600,461.89 +2007-02-08,468.05,473.75,465.15,471.03,4076700,471.03 +2007-02-07,473.82,474.35,468.78,470.01,4119800,470.01 +2007-02-06,468.10,473.30,467.26,471.48,5321900,471.48 +2007-02-05,477.50,478.00,466.19,467.16,7206900,467.16 +2007-02-02,482.61,485.00,477.81,481.50,6286500,481.50 +2007-02-01,506.00,506.01,481.53,481.75,15658700,481.75 +2007-01-31,496.49,505.00,495.51,501.50,12206100,501.50 +2007-01-30,494.00,498.00,491.22,494.32,4180500,494.32 +2007-01-29,498.00,498.75,490.50,492.47,4775700,492.47 +2007-01-26,490.93,497.90,487.03,495.84,5496500,495.84 +2007-01-25,501.00,504.50,485.66,488.09,6368500,488.09 +2007-01-24,484.45,499.54,483.29,499.07,6059300,499.07 +2007-01-23,480.79,484.75,477.29,479.05,4665500,479.05 +2007-01-22,492.50,492.65,478.50,480.84,5404300,480.84 +2007-01-19,487.98,490.76,486.74,489.75,4978300,489.75 +2007-01-18,494.52,496.48,487.43,487.83,5932000,487.83 +2007-01-17,503.39,507.77,494.38,497.28,6699100,497.28 +2007-01-16,507.55,513.00,503.30,504.28,7568900,504.28 +2007-01-12,501.99,505.00,500.00,505.00,4473700,505.00 +2007-01-11,497.20,501.75,496.18,499.72,7208200,499.72 +2007-01-10,484.43,493.55,482.04,489.46,5968500,489.46 +2007-01-09,485.45,488.25,481.20,485.50,5381400,485.50 +2007-01-08,487.69,489.87,482.20,483.58,4754400,483.58 +2007-01-05,482.50,487.50,478.11,487.19,6872100,487.19 +2007-01-04,469.00,483.95,468.35,483.26,7887600,483.26 +2007-01-03,466.00,476.66,461.11,467.59,7706500,467.59 +2006-12-29,462.10,464.47,459.86,460.48,2559200,460.48 +2006-12-28,467.12,468.58,462.25,462.56,3116200,462.56 +2006-12-27,460.00,468.08,459.10,468.03,4231500,468.03 +2006-12-26,456.52,459.47,454.59,457.53,2074300,457.53 +2006-12-22,457.50,458.64,452.73,455.58,3988300,455.58 +2006-12-21,464.18,465.25,452.34,456.20,6953300,456.20 +2006-12-20,470.00,471.50,462.33,462.90,4367800,462.90 +2006-12-19,461.72,469.31,458.50,468.63,6587000,468.63 +2006-12-18,482.51,482.74,460.72,462.80,8016600,462.80 +2006-12-15,482.64,484.11,479.84,480.30,5190800,480.30 +2006-12-14,480.25,483.75,477.26,482.12,4748900,482.12 +2006-12-13,484.69,485.50,477.02,478.99,4662100,478.99 +2006-12-12,483.85,486.36,480.28,481.78,4181000,481.78 +2006-12-11,484.92,488.90,483.80,483.93,3263400,483.93 +2006-12-08,481.94,488.60,480.00,484.11,3974900,484.11 +2006-12-07,490.23,491.80,482.42,482.64,4664300,482.64 +2006-12-06,486.96,492.40,484.52,488.71,4450300,488.71 +2006-12-05,487.40,489.44,484.89,487.00,4103000,487.00 +2006-12-04,483.00,487.43,479.35,484.85,4899900,484.85 +2006-12-01,485.98,488.39,478.50,480.80,5631400,480.80 +2006-11-30,484.19,490.40,481.55,484.81,5577500,484.81 +2006-11-29,494.24,494.74,482.25,484.65,6315300,484.65 +2006-11-28,481.13,489.86,477.03,489.50,7797600,489.50 +2006-11-27,501.37,501.78,484.75,484.75,7324700,484.75 +2006-11-24,504.50,507.50,504.00,505.00,1732700,505.00 +2006-11-22,510.97,513.00,505.78,508.01,4500700,508.01 +2006-11-21,496.54,510.00,495.83,509.65,8427500,509.65 +2006-11-20,498.40,498.40,492.65,495.05,5124500,495.05 +2006-11-17,493.25,499.66,493.00,498.79,5511000,498.79 +2006-11-16,495.00,497.68,492.56,495.90,5092600,495.90 +2006-11-15,493.43,499.85,491.93,491.93,8370700,491.93 +2006-11-14,480.70,489.95,480.50,489.30,7223400,489.30 +2006-11-13,474.90,481.17,474.14,481.03,4341900,481.03 +2006-11-10,473.78,474.72,470.29,473.55,2796700,473.55 +2006-11-09,476.50,479.49,471.86,472.63,4879200,472.63 +2006-11-08,470.35,481.74,468.60,475.00,7965000,475.00 +2006-11-07,476.95,479.02,471.77,472.57,4897100,472.57 +2006-11-06,473.77,479.66,472.33,476.95,4991500,476.95 +2006-11-03,472.23,473.75,465.06,471.80,4907700,471.80 +2006-11-02,467.50,473.73,466.38,469.91,5236700,469.91 +2006-11-01,478.76,479.13,465.26,467.50,5426300,467.50 +2006-10-31,478.06,482.16,473.84,476.39,6285400,476.39 +2006-10-30,474.82,480.46,470.01,476.57,6563100,476.57 +2006-10-27,483.90,485.24,472.49,475.20,6604000,475.20 +2006-10-26,487.68,491.96,484.20,485.10,7031700,485.10 +2006-10-25,477.49,488.50,475.11,486.60,9187500,486.60 +2006-10-24,476.28,477.86,471.41,473.31,8660200,473.31 +2006-10-23,462.28,484.64,460.37,480.78,15104500,480.78 +2006-10-20,458.99,460.10,453.59,459.67,11647900,459.67 +2006-10-19,420.23,429.50,419.57,426.06,11503500,426.06 +2006-10-18,422.99,424.75,417.50,419.31,6017300,419.31 +2006-10-17,420.30,423.75,416.70,420.64,5211000,420.64 +2006-10-16,427.70,429.20,421.34,421.75,4319400,421.75 +2006-10-13,427.76,429.50,425.56,427.30,3622500,427.30 +2006-10-12,428.56,429.68,424.00,427.44,4844000,427.44 +2006-10-11,425.02,429.91,423.76,426.50,5635400,426.50 +2006-10-10,431.56,437.85,422.39,426.65,9788600,426.65 +2006-10-09,424.80,431.95,423.42,429.00,7583300,429.00 +2006-10-06,410.22,421.91,409.75,420.50,7336500,420.50 +2006-10-05,414.70,418.24,410.86,411.81,5789800,411.81 +2006-10-04,404.97,415.77,403.05,415.70,6661800,415.70 +2006-10-03,401.29,406.46,398.19,404.04,5464700,404.04 +2006-10-02,401.90,406.00,400.80,401.44,3651900,401.44 +2006-09-29,405.13,405.62,401.41,401.90,3310900,401.90 +2006-09-28,404.08,406.98,400.54,403.58,5107400,403.58 +2006-09-27,406.30,411.22,402.37,402.92,5876700,402.92 +2006-09-26,405.50,407.68,401.77,406.87,5289400,406.87 +2006-09-25,405.58,409.45,402.50,403.98,5737300,403.98 +2006-09-22,404.98,407.45,401.36,403.78,4649600,403.78 +2006-09-21,400.30,408.45,399.86,406.85,10692100,406.85 +2006-09-20,407.10,407.39,394.62,397.00,9147800,397.00 +2006-09-19,415.46,415.49,392.74,403.81,14292900,403.81 +2006-09-18,410.00,418.69,409.47,414.69,7106700,414.69 +2006-09-15,407.48,410.05,406.74,409.88,7838200,409.88 +2006-09-14,404.30,406.28,401.93,403.98,5366100,403.98 +2006-09-13,395.15,406.76,395.10,406.57,9768200,406.57 +2006-09-12,385.00,392.73,384.88,391.90,5442200,391.90 +2006-09-11,378.26,384.69,377.77,384.09,4529200,384.09 +2006-09-08,376.72,380.79,376.72,377.85,3083400,377.85 +2006-09-07,379.39,381.75,377.40,378.49,3842000,378.49 +2006-09-06,382.10,383.19,379.66,380.14,3724100,380.14 +2006-09-05,379.87,385.40,377.44,384.36,4074300,384.36 +2006-09-01,380.99,381.28,377.19,378.60,2672900,378.60 +2006-08-31,381.49,382.15,378.20,378.53,2959900,378.53 +2006-08-30,379.21,384.65,378.51,380.75,4044400,380.75 +2006-08-29,380.78,382.32,377.20,378.95,4460000,378.95 +2006-08-28,375.61,380.95,375.00,380.95,4164000,380.95 +2006-08-25,373.08,375.32,372.50,373.26,2466700,373.26 +2006-08-24,374.44,376.40,372.26,373.73,3482500,373.73 +2006-08-23,377.64,378.27,372.66,373.43,3642300,373.43 +2006-08-22,377.73,379.26,374.84,378.29,4164100,378.29 +2006-08-21,378.10,379.00,375.22,377.30,4023300,377.30 +2006-08-18,386.31,387.09,380.75,383.36,4952200,383.36 +2006-08-17,386.39,390.00,383.92,385.80,5080200,385.80 +2006-08-16,383.48,388.45,382.12,387.72,5853200,387.72 +2006-08-15,374.11,381.67,372.60,380.97,6698200,380.97 +2006-08-14,371.50,375.13,368.67,369.43,4968300,369.43 +2006-08-11,374.40,375.28,368.00,368.50,3766500,368.50 +2006-08-10,373.88,377.67,372.46,374.20,4261900,374.20 +2006-08-09,382.80,384.68,376.36,376.94,4311000,376.94 +2006-08-08,382.82,384.50,379.09,381.00,5743200,381.00 +2006-08-07,371.50,379.73,371.15,377.95,3946900,377.95 +2006-08-04,379.56,380.68,371.75,373.85,5095200,373.85 +2006-08-03,364.98,377.91,363.36,375.39,6327000,375.39 +2006-08-02,375.60,377.17,365.20,367.23,7097800,367.23 +2006-08-01,385.11,385.77,375.51,375.51,5463200,375.51 +2006-07-31,388.00,389.17,383.31,386.60,4595300,386.60 +2006-07-28,382.00,389.56,381.73,388.12,4083600,388.12 +2006-07-27,387.37,387.49,377.95,382.40,5641100,382.40 +2006-07-26,388.20,391.91,383.00,385.50,5531900,385.50 +2006-07-25,385.02,391.31,383.80,389.36,5761100,389.36 +2006-07-24,392.82,393.89,381.21,390.90,8086100,390.90 +2006-07-21,386.14,391.75,377.69,390.11,11754600,390.11 +2006-07-20,404.28,404.44,385.66,387.12,12538700,387.12 +2006-07-19,395.01,401.14,394.66,399.00,8518500,399.00 +2006-07-18,409.75,410.57,397.74,403.05,8536800,403.05 +2006-07-17,404.63,411.00,403.72,407.89,5811900,407.89 +2006-07-14,410.33,411.49,398.61,403.50,7552100,403.50 +2006-07-13,414.00,418.34,406.83,408.83,6924500,408.83 +2006-07-12,422.09,422.74,416.73,417.25,4906700,417.25 +2006-07-11,418.51,425.05,413.03,424.56,5971300,424.56 +2006-07-10,423.44,425.23,416.38,418.20,4436400,418.20 +2006-07-07,426.05,427.89,415.88,420.45,6041900,420.45 +2006-07-06,423.38,425.38,421.98,423.19,3687100,423.19 +2006-07-05,421.52,422.80,415.64,421.46,4985600,421.46 +2006-07-03,420.04,423.77,419.45,423.20,2156700,423.20 +2006-06-30,415.60,419.33,412.33,419.33,6258000,419.33 +2006-06-29,407.99,418.20,405.82,417.81,6658200,417.81 +2006-06-28,404.01,406.48,401.13,406.11,3710500,406.11 +2006-06-27,405.71,408.00,401.01,402.32,4107100,402.32 +2006-06-26,406.75,408.30,403.25,404.22,3551200,404.22 +2006-06-23,402.76,409.75,400.74,404.86,5314800,404.86 +2006-06-22,401.58,406.00,388.00,399.95,5911900,399.95 +2006-06-21,391.06,404.00,389.75,402.13,8744400,402.13 +2006-06-20,388.03,391.87,386.51,387.17,4039900,387.17 +2006-06-19,390.85,394.80,386.98,388.14,7633100,388.14 +2006-06-16,389.10,390.93,388.00,390.70,5304600,390.70 +2006-06-15,386.62,392.25,383.00,391.00,6785700,391.00 +2006-06-14,389.83,391.10,378.52,384.39,7772000,384.39 +2006-06-13,380.90,387.00,378.12,386.52,7659100,386.52 +2006-06-12,388.34,390.49,381.00,381.54,5019100,381.54 +2006-06-09,392.19,395.43,385.35,386.57,6157500,386.57 +2006-06-08,387.75,394.27,378.59,393.30,10359500,393.30 +2006-06-07,393.24,394.86,386.50,386.51,8911300,386.51 +2006-06-06,376.58,390.00,376.30,389.99,10259800,389.99 +2006-06-05,376.18,381.45,374.15,374.44,5558500,374.44 +2006-06-02,386.84,387.08,377.45,379.44,6386400,379.44 +2006-06-01,373.54,382.99,371.60,382.62,6278000,382.62 +2006-05-31,373.80,378.25,366.78,371.82,7981300,371.82 +2006-05-30,378.28,381.00,371.45,371.94,4316000,371.94 +2006-05-26,384.55,385.88,380.03,381.35,3667000,381.35 +2006-05-25,379.08,383.00,372.31,382.99,8194600,382.99 +2006-05-24,377.35,383.44,371.61,381.25,9553800,381.25 +2006-05-23,374.21,383.88,373.56,375.58,8983000,375.58 +2006-05-22,367.85,373.03,365.25,370.95,8604400,370.95 +2006-05-19,373.28,374.50,360.57,370.02,11398200,370.02 +2006-05-18,378.78,381.81,370.71,370.99,5835000,370.99 +2006-05-17,370.61,379.84,370.22,374.50,10643800,374.50 +2006-05-16,375.99,376.86,369.89,371.30,6491100,371.30 +2006-05-15,375.93,380.15,368.25,376.20,8590100,376.20 +2006-05-12,383.54,384.87,373.55,374.13,10087600,374.13 +2006-05-11,403.42,404.71,384.98,387.00,8892800,387.00 +2006-05-10,408.31,411.71,401.86,402.98,6187200,402.98 +2006-05-09,395.70,409.00,393.75,408.80,9140600,408.80 +2006-05-08,395.11,397.12,390.05,394.78,5118600,394.78 +2006-05-05,397.60,400.68,391.78,394.30,6065000,394.30 +2006-05-04,395.03,398.87,392.21,394.75,4652000,394.75 +2006-05-03,396.35,401.50,390.88,394.17,8072200,394.17 +2006-05-02,401.08,402.49,388.40,394.80,13104300,394.80 +2006-05-01,418.47,419.44,398.55,398.90,10361200,398.90 +2006-04-28,418.63,425.73,416.30,417.94,7421300,417.94 +2006-04-27,422.91,426.91,419.39,420.03,8337900,420.03 +2006-04-26,427.74,430.04,423.53,425.97,7277800,425.97 +2006-04-25,439.63,441.04,426.00,427.16,9569000,427.16 +2006-04-24,439.40,444.70,436.52,440.50,8836400,440.50 +2006-04-21,448.90,450.72,436.17,437.10,22551300,437.10 +2006-04-20,411.01,416.00,408.20,415.00,12271500,415.00 +2006-04-19,412.57,413.64,406.73,410.50,6781700,410.50 +2006-04-18,407.93,409.83,401.50,404.24,8137600,404.24 +2006-04-17,403.45,412.50,400.84,406.82,8259500,406.82 +2006-04-13,408.63,409.76,400.50,402.16,6552900,402.16 +2006-04-12,409.00,411.33,405.19,408.95,6017000,408.95 +2006-04-11,416.42,419.10,406.22,409.66,11107200,409.66 +2006-04-10,407.08,417.17,405.25,416.38,9320100,416.38 +2006-04-07,412.41,412.85,404.02,406.16,7025900,406.16 +2006-04-06,406.49,413.89,405.43,411.18,8598500,411.18 +2006-04-05,408.20,414.57,402.82,407.99,13410500,407.99 +2006-04-04,389.90,404.90,388.14,404.34,15715700,404.34 +2006-04-03,389.53,392.47,387.93,389.70,8122700,389.70 +2006-03-31,388.74,391.87,384.03,390.00,36521400,390.00 +2006-03-30,389.19,393.50,383.61,388.44,14711700,388.44 +2006-03-29,379.94,399.00,379.51,394.98,19027500,394.98 +2006-03-28,371.71,377.86,371.17,377.20,8945800,377.20 +2006-03-27,367.09,371.71,365.00,369.69,7023700,369.69 +2006-03-24,368.62,370.09,362.51,365.80,15180600,365.80 +2006-03-23,342.35,345.75,340.20,341.89,7434700,341.89 +2006-03-22,339.75,344.10,337.50,340.22,7596000,340.22 +2006-03-21,350.01,351.66,339.08,339.92,9831100,339.92 +2006-03-20,342.34,350.09,341.54,348.19,10407600,348.19 +2006-03-17,338.80,341.78,334.93,339.79,8551700,339.79 +2006-03-16,348.61,348.75,337.90,338.77,10016700,338.77 +2006-03-15,350.77,352.30,340.53,344.50,12768800,344.50 +2006-03-14,337.14,352.37,332.62,351.16,18450700,351.16 +2006-03-13,340.93,346.10,335.45,337.06,13642400,337.06 +2006-03-10,343.50,344.50,331.55,337.50,19325600,337.50 +2006-03-09,355.39,358.53,341.50,343.00,13910400,343.00 +2006-03-08,353.93,360.03,350.54,353.88,11745600,353.88 +2006-03-07,365.02,368.45,358.15,364.45,10378800,364.45 +2006-03-06,380.91,383.40,367.14,368.10,8939700,368.10 +2006-03-03,384.30,387.24,375.76,378.18,11962000,378.18 +2006-03-02,364.28,381.10,362.20,376.45,18330300,376.45 +2006-03-01,368.56,369.45,361.30,364.80,12061200,364.80 +2006-02-28,393.20,397.54,338.51,362.62,39437600,362.62 +2006-02-27,381.27,391.70,380.28,390.38,10212200,390.38 +2006-02-24,377.30,380.07,373.49,377.40,6484300,377.40 +2006-02-23,365.61,381.24,365.39,378.07,12551600,378.07 +2006-02-22,367.15,368.95,363.86,365.49,6476200,365.49 +2006-02-21,366.44,373.54,365.11,366.59,8686000,366.59 +2006-02-17,369.86,372.14,363.62,368.75,14320200,368.75 +2006-02-16,345.67,367.00,344.49,366.46,21315500,366.46 +2006-02-15,341.27,346.00,337.83,342.38,12947000,342.38 +2006-02-14,345.33,351.69,342.40,343.32,14654000,343.32 +2006-02-13,346.64,350.60,341.89,345.70,19717800,345.70 +2006-02-10,361.95,364.50,353.14,362.61,15223500,362.61 +2006-02-09,371.20,374.40,356.11,358.77,11912400,358.77 +2006-02-08,368.48,370.69,354.67,369.08,20804100,369.08 +2006-02-07,382.99,383.70,363.35,367.92,16630200,367.92 +2006-02-06,385.31,389.90,379.56,385.10,8940400,385.10 +2006-02-03,393.62,393.90,372.57,381.55,18281800,381.55 +2006-02-02,403.82,406.50,395.98,396.04,11807700,396.04 +2006-02-01,389.03,402.00,387.52,401.78,27122500,401.78 +2006-01-31,430.57,439.60,423.97,432.66,22066000,432.66 +2006-01-30,429.23,433.28,425.00,426.82,8588900,426.82 +2006-01-27,435.00,438.22,428.98,433.49,8452200,433.49 +2006-01-26,439.54,439.99,423.56,434.27,12926100,434.27 +2006-01-25,451.26,454.23,429.22,433.00,18739800,433.00 +2006-01-24,436.03,444.95,434.48,443.03,15464600,443.03 +2006-01-23,407.38,428.39,405.73,427.50,22741400,427.50 +2006-01-20,438.70,440.03,394.74,399.46,41116700,399.46 +2006-01-19,451.17,453.49,433.00,436.45,14537300,436.45 +2006-01-18,447.30,457.36,443.25,444.91,20485700,444.91 +2006-01-17,463.06,469.90,462.53,467.11,8270300,467.11 +2006-01-13,464.31,466.89,461.61,466.25,7656600,466.25 +2006-01-12,473.72,474.99,461.50,463.63,10125300,463.63 +2006-01-11,471.27,475.11,469.18,471.63,9007400,471.63 +2006-01-10,464.42,470.25,462.04,469.76,9097100,469.76 +2006-01-09,466.41,473.40,460.94,466.90,12791900,466.90 +2006-01-06,456.87,470.50,453.24,465.66,17756900,465.66 +2006-01-05,446.00,451.55,441.50,451.24,10808300,451.24 +2006-01-04,443.90,448.96,439.75,445.24,15286400,445.24 +2006-01-03,422.52,435.67,418.22,435.23,13121200,435.23 +2005-12-30,417.27,418.21,413.74,414.86,7587100,414.86 +2005-12-29,427.98,428.73,419.17,420.15,6945800,420.15 +2005-12-28,424.34,427.78,421.26,426.69,7117900,426.69 +2005-12-27,431.86,431.86,422.76,424.64,6702800,424.64 +2005-12-23,432.15,432.50,428.78,430.93,4595100,430.93 +2005-12-22,431.77,432.86,425.93,432.04,7546600,432.04 +2005-12-21,433.55,436.86,420.71,426.33,11221900,426.33 +2005-12-20,427.86,432.20,424.67,429.74,10084700,429.74 +2005-12-19,432.20,446.21,420.11,424.60,21936800,424.60 +2005-12-16,425.34,432.50,422.75,430.15,16330500,430.15 +2005-12-15,419.11,423.14,416.50,422.55,6045800,422.55 +2005-12-14,417.04,419.73,415.49,418.96,6630400,418.96 +2005-12-13,412.50,418.00,411.64,417.49,8157000,417.49 +2005-12-12,414.63,415.21,409.95,412.61,6950100,412.61 +2005-12-09,415.00,415.78,408.56,409.20,7643400,409.20 +2005-12-08,405.30,410.65,402.64,410.65,8910100,410.65 +2005-12-07,406.16,406.70,399.01,404.22,11665900,404.22 +2005-12-06,408.70,416.41,401.70,404.54,15114700,404.54 +2005-12-05,417.00,417.50,404.28,405.85,10289400,405.85 +2005-12-02,416.94,419.53,413.86,417.70,7543500,417.70 +2005-12-01,409.20,415.44,408.29,414.09,9744900,414.09 +2005-11-30,404.26,408.45,395.56,404.91,15596600,404.91 +2005-11-29,424.46,426.40,402.14,403.54,21495800,403.54 +2005-11-28,429.82,431.24,422.44,423.48,11008400,423.48 +2005-11-25,425.78,428.75,425.30,428.62,4840100,428.62 +2005-11-23,417.04,424.72,415.78,422.86,10085000,422.86 +2005-11-22,408.65,417.31,406.23,416.47,9596000,416.47 +2005-11-21,399.17,409.98,393.49,409.36,10335100,409.36 +2005-11-18,403.49,404.50,399.85,400.21,7025700,400.21 +2005-11-17,401.80,403.81,399.53,403.45,9212200,403.45 +2005-11-16,396.20,398.85,394.11,398.15,8695200,398.15 +2005-11-15,394.38,397.00,390.95,392.80,8624900,392.80 +2005-11-14,392.12,398.22,391.53,396.97,7807900,396.97 +2005-11-11,395.12,396.90,388.85,390.40,7063900,390.40 +2005-11-10,378.36,391.35,377.43,391.10,9128700,391.10 +2005-11-09,386.67,388.29,378.03,379.15,10466900,379.15 +2005-11-08,394.25,395.59,388.58,389.90,7897500,389.90 +2005-11-07,395.10,397.47,392.15,395.03,9591500,395.03 +2005-11-04,389.98,391.79,385.45,390.43,8824900,390.43 +2005-11-03,382.41,386.58,381.38,385.95,7448400,385.95 +2005-11-02,381.70,385.00,377.17,379.68,10565400,379.68 +2005-11-01,371.86,383.90,369.01,379.38,16356100,379.38 +2005-10-31,360.24,374.75,359.51,372.14,14342900,372.14 +2005-10-28,355.27,358.95,355.02,358.17,5903500,358.17 +2005-10-27,356.60,357.09,351.68,353.06,5134400,353.06 +2005-10-26,346.28,356.00,346.19,355.44,8907500,355.44 +2005-10-25,345.78,347.40,342.86,346.91,6878300,346.91 +2005-10-24,343.37,349.30,342.19,348.65,9431700,348.65 +2005-10-21,345.80,346.43,333.00,339.90,22892400,339.90 +2005-10-20,309.99,311.13,301.21,303.20,13911700,303.20 +2005-10-19,304.00,309.87,303.96,308.70,7010700,308.70 +2005-10-18,304.96,307.96,302.74,303.28,7077800,303.28 +2005-10-17,297.50,305.20,294.56,305.00,7566700,305.00 +2005-10-14,299.90,300.23,292.54,296.14,8519100,296.14 +2005-10-13,302.00,302.00,290.68,297.44,10567700,297.44 +2005-10-12,305.20,307.19,299.00,300.97,9306200,300.97 +2005-10-11,310.61,312.65,304.86,306.10,8542600,306.10 +2005-10-10,313.31,314.82,309.15,310.65,5572200,310.65 +2005-10-07,314.79,316.67,310.54,312.99,6770300,312.99 +2005-10-06,314.14,314.48,310.09,312.75,7993800,312.75 +2005-10-05,312.69,314.90,308.00,310.71,8328400,310.71 +2005-10-04,319.95,321.28,310.74,311.00,9144300,311.00 +2005-10-03,313.63,320.11,312.79,318.68,9160300,318.68 +2005-09-30,314.22,317.50,312.29,316.46,9151300,316.46 +2005-09-29,306.68,310.72,306.08,309.62,5613800,309.62 +2005-09-28,314.22,315.10,305.60,306.00,7997400,306.00 +2005-09-27,314.95,318.41,313.38,313.94,6873100,313.94 +2005-09-26,319.50,320.95,312.56,314.28,9894400,314.28 +2005-09-23,313.00,317.21,312.59,315.36,8483800,315.36 +2005-09-22,311.50,319.22,310.17,311.37,13006400,311.37 +2005-09-21,308.41,313.76,305.96,311.90,10119700,311.90 +2005-09-20,306.15,311.30,305.23,307.91,9351000,307.91 +2005-09-19,301.00,306.00,300.71,303.79,5761900,303.79 +2005-09-16,304.02,304.50,299.87,300.20,7579800,300.20 +2005-09-15,299.52,306.75,297.91,302.62,15466200,302.62 +2005-09-14,308.73,313.28,300.30,303.00,11275800,303.00 +2005-09-13,309.00,315.53,306.17,311.68,10299900,311.68 +2005-09-12,301.75,311.42,301.00,309.74,10386500,309.74 +2005-09-09,297.28,299.10,296.56,299.09,4390500,299.09 +2005-09-08,294.83,299.28,293.36,295.39,6613300,295.39 +2005-09-07,285.89,295.50,285.28,294.87,7499500,294.87 +2005-09-06,289.00,289.39,286.80,287.11,4212300,287.11 +2005-09-02,286.51,289.99,286.44,288.45,3434500,288.45 +2005-09-01,285.91,287.50,285.00,286.25,2742100,286.25 +2005-08-31,288.23,288.50,284.36,286.00,5034000,286.00 +2005-08-30,287.39,289.51,285.88,287.27,4792000,287.27 +2005-08-29,282.24,289.12,282.24,288.45,5903000,288.45 +2005-08-26,283.48,285.02,282.66,283.58,3755300,283.58 +2005-08-25,282.55,284.00,279.97,282.59,4376600,282.59 +2005-08-24,277.57,284.75,276.45,282.57,8593100,282.57 +2005-08-23,276.16,279.74,274.12,279.58,5821700,279.58 +2005-08-22,281.24,281.47,273.35,274.01,6813000,274.01 +2005-08-19,280.99,281.45,279.62,280.00,5542900,280.00 +2005-08-18,275.91,280.50,275.00,279.99,11872800,279.99 +2005-08-17,285.51,286.57,284.00,285.10,3883300,285.10 +2005-08-16,284.88,287.79,283.34,285.65,7109200,285.65 +2005-08-15,289.80,292.77,283.77,284.00,8174700,284.00 +2005-08-12,283.36,290.20,281.64,289.72,6585900,289.72 +2005-08-11,285.89,286.58,280.62,284.05,7514900,284.05 +2005-08-10,291.30,292.33,284.88,285.68,6879000,285.68 +2005-08-09,291.96,292.68,288.51,291.57,5779300,291.57 +2005-08-08,293.60,295.65,290.49,291.25,4481800,291.25 +2005-08-05,297.50,298.51,291.31,292.35,5939700,292.35 +2005-08-04,295.55,299.00,295.25,297.73,5236500,297.73 +2005-08-03,298.00,299.72,295.60,297.30,5930600,297.30 +2005-08-02,291.60,299.52,291.12,299.19,7290200,299.19 +2005-08-01,288.12,292.50,288.10,291.61,5662400,291.61 +2005-07-29,292.14,292.84,286.99,287.76,8363300,287.76 +2005-07-28,297.41,297.41,293.28,293.50,5925600,293.50 +2005-07-27,297.74,298.23,292.40,296.93,7217900,296.93 +2005-07-26,295.01,298.00,292.09,296.09,9816900,296.09 +2005-07-25,302.39,303.29,294.96,295.85,9658800,295.85 +2005-07-22,306.37,309.25,296.33,302.40,23386800,302.40 +2005-07-21,314.05,317.80,311.21,313.94,19789400,313.94 +2005-07-20,305.57,312.61,301.80,312.00,14310400,312.00 +2005-07-19,302.10,310.35,301.80,309.90,12621400,309.90 +2005-07-18,300.00,301.90,297.75,299.54,6207800,299.54 +2005-07-15,301.24,303.40,299.78,301.19,8438400,301.19 +2005-07-14,305.34,306.75,300.07,300.89,10667700,300.89 +2005-07-13,292.51,299.24,292.10,298.86,11437900,298.86 +2005-07-12,293.39,294.40,290.93,291.78,5864900,291.78 +2005-07-11,296.40,296.60,291.02,293.35,8390300,293.35 +2005-07-08,296.25,297.50,294.05,296.23,7457600,296.23 +2005-07-07,289.39,295.80,288.51,295.54,10672100,295.54 +2005-07-06,297.30,297.60,291.38,291.52,8000300,291.52 +2005-07-05,292.10,295.98,290.23,295.71,7494000,295.71 +2005-07-01,295.04,296.24,289.22,291.25,9227600,291.25 +2005-06-30,294.34,298.93,291.04,294.15,15094400,294.15 +2005-06-29,302.50,304.38,292.15,292.72,18298700,292.72 +2005-06-28,306.28,309.25,302.00,302.00,19036500,302.00 +2005-06-27,298.90,304.47,293.86,304.10,17802900,304.10 +2005-06-24,290.90,298.00,289.58,297.25,17771200,297.25 +2005-06-23,288.00,294.81,286.50,289.71,14056400,289.71 +2005-06-22,289.67,292.32,288.67,289.30,10474000,289.30 +2005-06-21,288.07,290.30,284.97,287.84,15132300,287.84 +2005-06-20,276.09,287.67,271.73,286.70,21024700,286.70 +2005-06-17,279.00,280.30,275.90,280.30,10434400,280.30 +2005-06-16,274.26,278.30,273.07,277.44,12462400,277.44 +2005-06-15,275.00,277.30,267.43,274.80,20883100,274.80 +2005-06-14,278.59,281.24,277.75,278.35,10091900,278.35 +2005-06-13,279.82,284.19,276.52,282.75,12803200,282.75 +2005-06-10,286.99,287.28,280.02,282.50,12696600,282.50 +2005-06-09,284.72,288.50,280.56,286.31,16441100,286.31 +2005-06-08,292.85,293.19,278.00,279.56,25700900,279.56 +2005-06-07,297.10,299.59,290.30,293.12,24323000,293.12 +2005-06-06,282.39,293.75,281.83,290.94,22525900,290.94 +2005-06-03,286.79,289.30,277.41,280.26,18782300,280.26 +2005-06-02,288.73,289.78,284.60,287.90,17974100,287.90 +2005-06-01,283.20,292.89,282.02,288.00,35191700,288.00 +2005-05-31,269.43,278.40,269.37,277.27,22236800,277.27 +2005-05-27,260.46,266.05,259.25,266.00,12184100,266.00 +2005-05-26,260.96,263.76,258.30,259.20,13546600,259.20 +2005-05-25,252.73,260.98,250.63,260.81,18057900,260.81 +2005-05-24,256.96,265.44,253.50,256.00,29043100,256.00 +2005-05-23,243.16,258.10,242.71,255.45,21388300,255.45 +2005-05-20,241.21,241.67,239.65,241.61,8163500,241.61 +2005-05-19,240.34,241.17,238.27,239.18,9716500,239.18 +2005-05-18,233.61,239.97,233.52,239.16,12312000,239.16 +2005-05-17,230.56,233.45,230.20,233.13,7808900,233.13 +2005-05-16,229.68,231.62,228.57,231.05,5681400,231.05 +2005-05-13,229.18,231.09,227.32,229.24,7415500,229.24 +2005-05-12,230.81,232.23,228.20,228.72,8948200,228.72 +2005-05-11,228.97,231.98,227.93,231.29,11478800,231.29 +2005-05-10,225.47,227.80,224.72,227.80,6345800,227.80 +2005-05-09,228.00,228.50,225.43,226.02,5536800,226.02 +2005-05-06,228.40,229.25,226.47,228.02,6763900,228.02 +2005-05-05,228.62,228.62,225.88,226.98,7509600,226.98 +2005-05-04,227.23,229.88,227.00,228.50,12083500,228.50 +2005-05-03,221.85,228.15,221.32,226.19,17780200,226.19 +2005-05-02,222.05,223.70,220.21,222.29,9767400,222.29 +2005-04-29,221.91,222.25,217.82,220.00,9170200,220.00 +2005-04-28,219.50,222.08,217.71,219.45,8682800,219.45 +2005-04-27,217.99,220.85,216.74,219.78,10264800,219.78 +2005-04-26,220.22,222.00,218.29,218.75,17272000,218.75 +2005-04-25,217.82,224.74,217.52,223.53,19840000,223.53 +2005-04-22,222.90,224.00,214.26,215.81,33205100,215.81 +2005-04-21,200.42,205.00,199.32,204.22,17751900,204.22 +2005-04-20,198.58,200.50,195.91,198.10,15451500,198.10 +2005-04-19,189.33,192.00,188.03,191.40,8430000,191.40 +2005-04-18,184.58,187.88,183.49,186.97,6550300,186.97 +2005-04-15,190.10,190.34,184.66,185.00,11577400,185.00 +2005-04-14,193.27,194.36,190.10,191.45,6152700,191.45 +2005-04-13,193.47,194.32,189.73,192.93,6555800,192.93 +2005-04-12,193.00,194.42,189.41,193.96,7319600,193.96 +2005-04-11,193.09,194.80,192.32,193.23,5410500,193.23 +2005-04-08,193.69,195.10,191.45,192.05,5116600,192.05 +2005-04-07,188.78,194.62,188.64,193.76,9692200,193.76 +2005-04-06,189.24,189.65,187.58,189.22,5252600,189.22 +2005-04-05,187.73,190.26,187.57,188.57,8736700,188.57 +2005-04-04,179.95,185.32,179.84,185.29,8076400,185.29 +2005-04-01,181.76,182.95,179.99,180.04,6182000,180.04 +2005-03-31,177.95,181.39,177.64,180.51,6768600,180.51 +2005-03-30,180.64,181.45,179.60,180.45,6236100,180.45 +2005-03-29,181.05,183.28,178.07,179.57,6473000,179.57 +2005-03-28,181.68,184.80,180.95,181.42,8738000,181.42 +2005-03-24,180.70,180.86,179.20,179.25,3705200,179.25 +2005-03-23,177.97,180.24,177.97,178.98,4845000,178.98 +2005-03-22,181.18,181.94,177.85,178.60,5631700,178.60 +2005-03-21,179.27,182.17,177.25,180.88,7483700,180.88 +2005-03-18,178.81,180.40,178.31,180.04,7090000,180.04 +2005-03-17,177.13,179.64,175.80,179.29,8260600,179.29 +2005-03-16,176.70,178.61,175.01,175.60,7106300,175.60 +2005-03-15,175.30,180.00,174.21,178.61,10422100,178.61 +2005-03-14,178.33,178.40,172.57,174.99,11146600,174.99 +2005-03-11,180.44,180.95,177.15,177.80,8028300,177.80 +2005-03-10,181.01,181.20,177.40,179.98,10960500,179.98 +2005-03-09,184.21,184.65,180.16,181.35,11360400,181.35 +2005-03-08,189.10,189.85,184.97,185.20,8046100,185.20 +2005-03-07,187.78,189.60,187.03,188.81,8667400,188.81 +2005-03-04,186.70,187.25,185.07,185.90,6774100,185.90 +2005-03-03,186.13,187.75,184.31,187.01,7608600,187.01 +2005-03-02,185.95,187.67,184.36,185.18,7285500,185.18 +2005-03-01,189.29,189.75,182.00,186.06,9311200,186.06 +2005-02-28,186.00,189.87,185.85,187.99,7818400,187.99 +2005-02-25,189.15,189.92,185.51,185.87,9973500,185.87 +2005-02-24,183.37,189.85,182.23,188.89,25814300,188.89 +2005-02-23,193.30,194.48,188.66,193.95,15586000,193.95 +2005-02-22,196.50,198.90,190.39,191.37,13483700,191.37 +2005-02-18,198.51,198.84,196.66,197.95,8485900,197.95 +2005-02-17,197.83,199.75,196.81,197.90,10414400,197.90 +2005-02-16,194.70,199.33,194.30,198.41,16532300,198.41 +2005-02-15,193.60,199.84,193.08,195.23,25782800,195.23 +2005-02-14,182.85,193.08,181.00,192.99,38562200,192.99 +2005-02-11,186.66,192.32,186.07,187.40,13116000,187.40 +2005-02-10,191.97,192.21,185.25,187.98,18982700,187.98 +2005-02-09,200.76,201.60,189.46,191.58,17171500,191.58 +2005-02-08,196.96,200.02,194.53,198.64,11480000,198.64 +2005-02-07,205.26,206.40,195.51,196.03,12960400,196.03 +2005-02-04,206.47,207.75,202.60,204.36,14819300,204.36 +2005-02-03,205.99,213.37,205.81,210.86,12988100,210.86 +2005-02-02,215.55,216.80,203.66,205.96,32799300,205.96 +2005-02-01,194.38,196.66,190.63,191.90,18839000,191.90 +2005-01-31,193.69,196.36,191.72,195.62,9596700,195.62 +2005-01-28,190.02,194.70,186.34,190.34,12208200,190.34 +2005-01-27,188.76,188.86,185.20,188.08,6627400,188.08 +2005-01-26,179.27,189.41,179.15,189.24,12307900,189.24 +2005-01-25,181.94,182.24,176.29,177.12,10659200,177.12 +2005-01-24,188.69,189.33,180.32,180.72,14022700,180.72 +2005-01-21,194.54,195.36,188.12,188.28,9258400,188.28 +2005-01-20,192.50,196.25,192.00,193.92,9001600,193.92 +2005-01-19,204.65,205.30,196.71,197.30,11257700,197.30 +2005-01-18,200.97,205.02,198.66,203.90,13172600,203.90 +2005-01-14,196.00,200.01,194.13,199.97,9640300,199.97 +2005-01-13,195.38,197.39,194.05,195.33,6849400,195.33 +2005-01-12,194.33,195.93,190.50,195.38,8177800,195.38 +2005-01-11,195.62,197.71,193.18,193.54,6958700,193.54 +2005-01-10,194.50,198.10,191.83,195.06,7539600,195.06 +2005-01-07,190.64,194.25,188.78,193.85,9662900,193.85 +2005-01-06,195.08,195.90,187.72,188.55,10387100,188.55 +2005-01-05,193.45,196.90,192.23,193.51,8236600,193.51 +2005-01-04,201.40,202.93,193.48,194.50,13755900,194.50 +2005-01-03,197.40,203.64,195.46,202.71,15844200,202.71 diff --git a/includes/js/dojox/charting/tests/data/msft_prices.csv b/includes/js/dojox/charting/tests/data/msft_prices.csv new file mode 100644 index 0000000..a0c1e90 --- /dev/null +++ b/includes/js/dojox/charting/tests/data/msft_prices.csv @@ -0,0 +1,796 @@ +Date,Open,High,Low,Close,Volume,Adj Close +2008-02-29,27.69,27.83,27.02,27.20,117394000,27.20 +2008-02-28,28.02,28.27,27.80,27.93,83002900,27.93 +2008-02-27,28.19,28.68,28.10,28.26,75187200,28.26 +2008-02-26,27.74,28.86,27.67,28.38,108923500,28.38 +2008-02-25,27.65,28.24,27.48,27.84,109945200,27.84 +2008-02-22,28.24,28.39,27.20,27.68,125705400,27.68 +2008-02-21,28.62,28.96,27.96,28.10,98776500,28.10 +2008-02-20,28.15,28.26,27.92,28.22,92830000,28.22 +2008-02-19,28.80,28.84,28.07,28.17,68261200,28.17 +2008-02-15,28.31,28.64,28.25,28.42,68166100,28.31 +2008-02-14,28.88,29.04,28.46,28.50,68191600,28.39 +2008-02-13,28.62,29.05,28.53,28.96,88986200,28.85 +2008-02-12,28.43,28.62,28.11,28.34,84365900,28.23 +2008-02-11,28.52,28.61,27.91,28.21,156814100,28.10 +2008-02-08,28.29,29.08,28.24,28.56,124872000,28.45 +2008-02-07,28.34,28.78,27.90,28.12,164964900,28.01 +2008-02-06,29.28,29.35,28.29,28.52,138315600,28.41 +2008-02-05,29.91,29.94,28.89,29.07,137534100,28.96 +2008-02-04,30.49,30.72,30.11,30.19,119998600,30.07 +2008-02-01,31.06,33.25,30.25,30.45,291138900,30.33 +2008-01-31,31.91,32.74,31.72,32.60,103642200,32.47 +2008-01-30,32.56,32.80,32.05,32.20,106432600,32.08 +2008-01-29,32.85,32.89,32.35,32.60,68023000,32.47 +2008-01-28,33.02,33.10,32.42,32.72,81019000,32.59 +2008-01-25,34.90,35.00,32.87,32.94,196992300,32.81 +2008-01-24,32.35,33.36,32.12,33.25,155640400,33.12 +2008-01-23,31.48,32.05,31.04,31.93,137597400,31.81 +2008-01-22,31.54,32.53,31.50,31.96,108521400,31.84 +2008-01-18,33.16,34.00,32.97,33.01,117062000,32.88 +2008-01-17,33.54,33.80,32.97,33.11,94247800,32.98 +2008-01-16,33.42,33.65,32.51,33.23,120778500,33.10 +2008-01-15,34.03,34.38,34.00,34.00,61606200,33.87 +2008-01-14,34.46,34.57,34.08,34.39,52792200,34.26 +2008-01-11,34.14,34.24,33.72,33.91,55187900,33.78 +2008-01-10,34.35,34.50,33.78,34.33,72446000,34.20 +2008-01-09,33.36,34.54,33.35,34.44,74305500,34.31 +2008-01-08,34.71,34.71,33.40,33.45,79148300,33.32 +2008-01-07,34.55,34.80,34.25,34.61,80164300,34.48 +2008-01-04,35.19,35.20,34.09,34.38,72090800,34.25 +2008-01-03,35.22,35.65,34.86,35.37,49599600,35.23 +2008-01-02,35.79,35.96,35.00,35.22,63004200,35.08 +2007-12-31,35.90,35.99,35.52,35.60,35229700,35.46 +2007-12-28,36.10,36.23,35.67,36.12,33447200,35.98 +2007-12-27,36.35,36.55,35.94,35.97,33311100,35.83 +2007-12-26,36.41,36.64,36.26,36.61,30252400,36.47 +2007-12-24,36.13,36.72,36.05,36.58,29622600,36.44 +2007-12-21,35.90,36.06,35.75,36.06,83240500,35.92 +2007-12-20,35.29,35.79,35.08,35.52,59345000,35.38 +2007-12-19,34.69,35.14,34.38,34.79,58469100,34.66 +2007-12-18,34.64,35.00,34.21,34.74,52791800,34.61 +2007-12-17,35.03,35.13,34.36,34.39,58121200,34.26 +2007-12-14,35.05,35.84,35.01,35.31,71126200,35.17 +2007-12-13,34.48,35.45,34.28,35.22,73913200,35.08 +2007-12-12,34.61,35.09,33.93,34.47,63345400,34.34 +2007-12-11,34.73,34.99,33.93,34.10,55070700,33.97 +2007-12-10,34.64,34.95,34.47,34.76,36083500,34.63 +2007-12-07,34.61,34.70,34.22,34.53,40771000,34.40 +2007-12-06,34.26,34.61,33.87,34.55,49209700,34.42 +2007-12-05,33.14,34.52,33.03,34.15,84894700,34.02 +2007-12-04,32.74,33.24,32.63,32.77,54801500,32.64 +2007-12-03,33.50,33.64,32.68,32.92,61770600,32.79 +2007-11-30,33.92,34.12,33.19,33.60,71027800,33.47 +2007-11-29,33.58,33.93,33.31,33.59,53633600,33.46 +2007-11-28,33.38,33.89,32.90,33.70,88585000,33.57 +2007-11-27,33.27,33.60,32.68,33.06,84178400,32.93 +2007-11-26,34.09,34.37,32.93,32.97,80335000,32.84 +2007-11-23,34.36,34.44,33.71,34.11,33467200,33.98 +2007-11-21,34.40,34.73,34.18,34.23,89518700,34.10 +2007-11-20,34.23,34.97,34.10,34.58,100009400,34.45 +2007-11-19,33.96,34.24,33.87,33.96,63000300,33.83 +2007-11-16,33.86,34.26,33.71,34.09,71113800,33.96 +2007-11-15,33.76,34.10,33.55,33.76,63111200,33.63 +2007-11-14,34.62,34.75,33.75,33.93,83840100,33.80 +2007-11-13,33.54,34.67,33.38,34.46,104261100,34.33 +2007-11-12,33.32,33.71,33.02,33.38,84719000,33.14 +2007-11-09,34.18,34.54,33.65,33.73,125111400,33.49 +2007-11-08,35.60,35.90,34.40,34.74,133742400,34.49 +2007-11-07,36.04,36.16,35.45,35.52,74873600,35.27 +2007-11-06,36.59,36.66,35.87,36.41,100966700,36.15 +2007-11-05,36.76,37.10,36.63,36.73,75485400,36.47 +2007-11-02,37.22,37.50,36.42,37.06,96389800,36.79 +2007-11-01,36.53,37.49,36.36,37.06,152078800,36.79 +2007-10-31,35.52,37.00,35.51,36.81,185635800,36.55 +2007-10-30,34.37,35.59,34.35,35.57,107297300,35.32 +2007-10-29,34.85,35.29,34.45,34.57,114655600,34.32 +2007-10-26,36.01,36.03,34.56,35.03,287270900,34.78 +2007-10-25,31.57,32.22,31.49,31.99,169588700,31.76 +2007-10-24,30.85,31.30,30.50,31.25,77979200,31.03 +2007-10-23,30.71,31.12,30.71,30.90,49956200,30.68 +2007-10-22,30.12,30.70,30.12,30.51,58785100,30.29 +2007-10-19,31.09,31.09,30.11,30.17,75200200,29.95 +2007-10-18,31.22,31.23,30.63,31.16,49208600,30.94 +2007-10-17,30.75,31.23,30.65,31.08,86092400,30.86 +2007-10-16,30.24,30.58,30.23,30.32,56286200,30.10 +2007-10-15,30.10,30.33,30.00,30.04,47150500,29.83 +2007-10-12,30.03,30.40,29.95,30.17,31121100,29.95 +2007-10-11,30.30,30.63,29.79,29.91,50788400,29.70 +2007-10-10,30.04,30.37,30.03,30.23,32251500,30.01 +2007-10-09,30.03,30.39,30.00,30.10,63603100,29.88 +2007-10-08,29.66,29.85,29.60,29.84,30265400,29.63 +2007-10-05,29.89,29.99,29.73,29.84,45012300,29.63 +2007-10-04,29.56,29.77,29.44,29.71,37868000,29.50 +2007-10-03,29.71,29.85,29.29,29.45,37633900,29.24 +2007-10-02,29.70,29.85,29.57,29.70,33700900,29.49 +2007-10-01,29.46,29.79,29.41,29.77,43875100,29.56 +2007-09-28,29.49,29.69,29.23,29.46,45819100,29.25 +2007-09-27,29.70,29.72,29.44,29.49,43407100,29.28 +2007-09-26,29.68,29.85,29.48,29.50,60337000,29.29 +2007-09-25,29.14,29.56,29.11,29.56,75621000,29.35 +2007-09-24,28.81,29.61,28.80,29.08,104459800,28.87 +2007-09-21,28.69,28.81,28.44,28.65,135636100,28.45 +2007-09-20,28.48,28.58,28.34,28.42,67168900,28.22 +2007-09-19,28.87,28.91,28.30,28.67,94242200,28.46 +2007-09-18,28.70,28.97,28.27,28.93,77462400,28.72 +2007-09-17,28.79,28.88,28.62,28.73,39536500,28.52 +2007-09-14,28.98,29.11,28.88,29.04,33496600,28.83 +2007-09-13,29.12,29.26,28.96,29.16,35288600,28.95 +2007-09-12,28.81,29.17,28.80,28.93,42364700,28.72 +2007-09-11,28.63,28.95,28.58,28.93,34380800,28.72 +2007-09-10,28.67,28.75,28.41,28.48,37247600,28.28 +2007-09-07,28.62,28.83,28.32,28.44,52160900,28.24 +2007-09-06,28.56,29.01,28.55,28.91,45430800,28.70 +2007-09-05,28.65,28.73,28.42,28.48,47669800,28.28 +2007-09-04,28.50,29.10,28.48,28.81,45689600,28.60 +2007-08-31,28.70,28.92,28.36,28.73,42511900,28.52 +2007-08-30,28.42,28.93,28.32,28.45,33690700,28.25 +2007-08-29,28.13,28.61,27.82,28.59,45753700,28.39 +2007-08-28,28.30,28.49,27.91,27.93,43924400,27.73 +2007-08-27,28.61,28.77,28.40,28.49,32789500,28.29 +2007-08-24,28.21,28.84,28.07,28.81,45158900,28.60 +2007-08-23,28.28,28.33,28.10,28.30,33886600,28.10 +2007-08-22,28.27,28.32,28.01,28.22,44763500,28.02 +2007-08-21,28.10,28.32,27.87,28.07,50786200,27.87 +2007-08-20,28.18,28.49,28.08,28.26,49952000,28.06 +2007-08-17,28.09,28.25,27.82,28.25,76747700,28.05 +2007-08-16,27.88,28.35,27.51,27.81,81447400,27.61 +2007-08-15,28.24,28.99,28.05,28.10,48117700,27.90 +2007-08-14,28.77,28.89,28.20,28.27,42944100,28.07 +2007-08-13,28.94,28.99,28.44,28.63,55492300,28.33 +2007-08-10,28.90,29.05,28.26,28.71,76576200,28.41 +2007-08-09,29.64,30.10,28.92,29.30,72964500,28.99 +2007-08-08,29.72,30.01,29.21,30.00,52898600,29.68 +2007-08-07,29.33,29.79,29.05,29.55,49163000,29.24 +2007-08-06,29.05,29.54,28.75,29.54,59530500,29.23 +2007-08-03,29.45,29.78,28.90,28.96,61535500,28.65 +2007-08-02,29.19,29.79,29.02,29.52,47938300,29.21 +2007-08-01,28.95,29.55,28.82,29.30,80006300,28.99 +2007-07-31,29.71,29.72,28.98,28.99,66554000,28.68 +2007-07-30,29.41,29.49,28.95,29.40,67499600,29.09 +2007-07-27,29.93,30.00,29.36,29.39,69214600,29.08 +2007-07-26,30.24,30.53,29.51,29.98,87025300,29.66 +2007-07-25,30.99,31.30,30.37,30.71,54950100,30.38 +2007-07-24,31.01,31.48,30.71,30.80,59729300,30.47 +2007-07-23,31.36,31.52,31.12,31.19,48910600,30.86 +2007-07-20,31.15,31.20,30.79,31.16,98292600,30.83 +2007-07-19,31.05,31.84,30.93,31.51,121159300,31.18 +2007-07-18,30.51,30.97,30.50,30.92,64414400,30.59 +2007-07-17,30.02,30.88,30.01,30.78,77539600,30.45 +2007-07-16,29.76,30.24,29.72,30.03,48023200,29.71 +2007-07-13,29.94,30.02,29.66,29.82,42173000,29.50 +2007-07-12,29.56,30.11,29.44,30.07,54302400,29.75 +2007-07-11,29.24,29.65,29.21,29.49,48017000,29.18 +2007-07-10,29.70,29.99,29.18,29.33,66013500,29.02 +2007-07-09,29.86,29.95,29.81,29.87,33831400,29.55 +2007-07-06,29.91,30.04,29.66,29.97,57541000,29.65 +2007-07-05,30.05,30.22,29.83,29.99,47838500,29.67 +2007-07-03,29.79,30.22,29.78,30.02,35202600,29.70 +2007-07-02,29.67,29.80,29.49,29.74,47316000,29.42 +2007-06-29,29.87,29.93,29.04,29.47,71193900,29.16 +2007-06-28,29.86,29.97,29.68,29.83,46055200,29.51 +2007-06-27,29.36,29.95,29.36,29.87,53468600,29.55 +2007-06-26,29.55,29.80,29.50,29.52,48340300,29.21 +2007-06-25,29.47,29.77,29.38,29.49,53905800,29.18 +2007-06-22,30.00,30.10,29.45,29.49,86219900,29.18 +2007-06-21,29.98,30.30,29.91,30.22,56564800,29.90 +2007-06-20,30.44,30.51,29.96,30.01,46861600,29.69 +2007-06-19,30.48,30.66,30.38,30.46,46802600,30.14 +2007-06-18,30.69,30.72,30.42,30.51,45412600,30.19 +2007-06-15,30.86,30.88,30.43,30.49,100933000,30.17 +2007-06-14,30.35,30.71,30.30,30.52,59065700,30.20 +2007-06-13,29.97,30.41,29.85,30.39,64435600,30.07 +2007-06-12,29.96,30.24,29.77,29.85,56981800,29.53 +2007-06-11,29.94,30.25,29.93,30.02,48467400,29.70 +2007-06-08,29.58,30.06,29.41,30.05,61346200,29.73 +2007-06-07,30.02,30.29,29.59,29.62,71971400,29.31 +2007-06-06,30.37,30.53,30.25,30.29,38217500,29.97 +2007-06-05,30.62,30.63,30.33,30.58,44265000,30.26 +2007-06-04,30.42,30.76,30.40,30.72,41434500,30.39 +2007-06-01,30.79,30.90,30.55,30.59,39469400,30.27 +2007-05-31,31.12,31.16,30.61,30.69,85290500,30.36 +2007-05-30,30.55,31.13,30.51,31.11,57376800,30.78 +2007-05-29,30.49,30.83,30.39,30.79,42373100,30.46 +2007-05-25,30.28,30.66,30.18,30.48,47726500,30.16 +2007-05-24,30.54,30.80,29.96,30.17,64046400,29.85 +2007-05-23,30.84,30.84,30.57,30.58,46322500,30.26 +2007-05-22,30.90,30.93,30.66,30.69,39999500,30.36 +2007-05-21,30.73,31.16,30.73,31.05,41836400,30.72 +2007-05-18,30.97,30.99,30.58,30.83,58453000,30.50 +2007-05-17,31.03,31.14,30.96,30.98,41045600,30.65 +2007-05-16,31.00,31.09,30.81,31.07,45833600,30.74 +2007-05-15,30.90,31.09,30.84,30.90,75013900,30.57 +2007-05-14,30.84,30.99,30.81,30.97,70188500,30.54 +2007-05-11,30.57,30.98,30.55,30.89,43425300,30.46 +2007-05-10,30.68,30.93,30.53,30.58,55398600,30.16 +2007-05-09,30.70,30.93,30.57,30.78,51735000,30.35 +2007-05-08,30.68,30.94,30.58,30.75,60551700,30.33 +2007-05-07,30.52,30.76,30.48,30.71,59889100,30.29 +2007-05-04,30.68,30.70,30.29,30.56,104385900,30.14 +2007-05-03,30.60,31.00,30.53,30.97,82036800,30.54 +2007-05-02,30.39,30.69,30.30,30.61,80686700,30.19 +2007-05-01,29.94,30.42,29.90,30.40,73539300,29.98 +2007-04-30,30.13,30.37,29.94,29.94,67788800,29.53 +2007-04-27,30.17,30.74,30.00,30.12,128298800,29.70 +2007-04-26,29.09,29.35,28.91,29.10,68760300,28.70 +2007-04-25,28.86,29.00,28.69,28.99,39475000,28.59 +2007-04-24,28.79,28.96,28.59,28.79,34236700,28.39 +2007-04-23,28.96,28.99,28.67,28.78,41739100,28.38 +2007-04-20,28.98,29.10,28.70,29.02,60311500,28.62 +2007-04-19,28.34,28.89,28.26,28.69,43648800,28.29 +2007-04-18,28.61,28.67,28.36,28.60,41778400,28.20 +2007-04-17,28.63,28.89,28.56,28.85,33170200,28.45 +2007-04-16,28.60,28.75,28.21,28.73,30740100,28.33 +2007-04-13,28.43,28.70,28.10,28.61,36002900,28.21 +2007-04-12,28.06,28.62,28.04,28.54,43762100,28.15 +2007-04-11,28.30,28.57,27.99,28.11,44050200,27.72 +2007-04-10,28.50,28.64,28.22,28.40,38643100,28.01 +2007-04-09,28.58,28.72,28.39,28.57,31384600,28.18 +2007-04-05,28.32,28.65,28.30,28.55,30131200,28.16 +2007-04-04,28.01,28.78,27.90,28.50,63244200,28.11 +2007-04-03,27.86,28.06,27.75,27.87,39821300,27.48 +2007-04-02,27.89,27.93,27.56,27.74,41977600,27.36 +2007-03-30,27.75,27.95,27.50,27.87,47061000,27.48 +2007-03-29,27.84,27.85,27.49,27.75,42629900,27.37 +2007-03-28,27.58,28.00,27.40,27.64,46947000,27.26 +2007-03-27,28.04,28.16,27.65,27.72,58979800,27.34 +2007-03-26,27.94,28.22,27.70,28.22,47491500,27.83 +2007-03-23,28.22,28.27,27.80,28.02,50519800,27.63 +2007-03-22,28.52,28.55,28.01,28.27,47934900,27.88 +2007-03-21,27.90,28.52,27.56,28.52,72808200,28.13 +2007-03-20,27.93,28.16,27.76,27.84,47902400,27.46 +2007-03-19,27.34,27.83,27.20,27.83,49412000,27.45 +2007-03-16,27.35,27.48,27.20,27.33,65055300,26.95 +2007-03-15,27.32,27.47,27.20,27.28,51757100,26.90 +2007-03-14,26.82,27.40,26.73,27.40,75730300,27.02 +2007-03-13,27.25,27.40,26.71,26.72,75169500,26.35 +2007-03-12,27.18,27.48,27.13,27.44,36516400,27.06 +2007-03-09,27.42,27.48,27.03,27.29,80125000,26.91 +2007-03-08,27.72,27.85,26.60,27.32,72175200,26.94 +2007-03-07,27.76,27.90,27.55,27.61,52044700,27.23 +2007-03-06,27.80,27.94,27.65,27.83,49361800,27.45 +2007-03-05,27.49,27.91,27.41,27.55,56454300,27.17 +2007-03-02,28.02,28.16,27.76,27.76,63254700,27.38 +2007-03-01,27.82,28.33,27.73,28.09,80175700,27.70 +2007-02-28,27.95,28.25,27.92,28.17,86333300,27.78 +2007-02-27,28.71,28.97,27.79,27.87,87143300,27.48 +2007-02-26,28.96,29.09,28.82,29.07,63481900,28.67 +2007-02-23,29.22,29.28,28.89,28.90,63787100,28.50 +2007-02-22,29.31,29.54,29.16,29.39,57754400,28.98 +2007-02-21,28.75,29.39,28.74,29.35,68604900,28.94 +2007-02-20,28.63,28.86,28.47,28.83,53978200,28.43 +2007-02-16,28.91,28.94,28.65,28.74,109340300,28.34 +2007-02-15,29.58,29.65,29.22,29.46,63858100,29.05 +2007-02-14,29.17,29.69,29.15,29.40,55588600,28.99 +2007-02-13,29.04,29.20,28.96,29.01,50348100,28.61 +2007-02-12,28.89,29.09,28.83,28.94,52774400,28.44 +2007-02-09,29.35,29.40,28.93,28.98,69823100,28.48 +2007-02-08,29.24,29.80,29.20,29.26,48749000,28.76 +2007-02-07,29.64,29.70,29.25,29.37,65145500,28.86 +2007-02-06,29.59,29.75,29.22,29.51,79281100,29.00 +2007-02-05,29.97,30.02,29.41,29.61,99102100,29.10 +2007-02-02,30.82,30.84,30.13,30.19,60401700,29.67 +2007-02-01,30.84,30.94,30.37,30.56,55355800,30.03 +2007-01-31,30.41,31.10,30.35,30.86,73968400,30.33 +2007-01-30,30.57,30.64,30.14,30.48,61900400,29.96 +2007-01-29,30.65,30.78,30.34,30.53,57605900,30.00 +2007-01-26,31.22,31.23,30.60,30.60,96103700,30.07 +2007-01-25,31.08,31.48,30.45,30.45,97378700,29.93 +2007-01-24,30.78,31.30,30.65,31.09,58527800,30.55 +2007-01-23,30.63,30.96,30.52,30.74,49171200,30.21 +2007-01-22,31.06,31.12,30.51,30.72,56143900,30.19 +2007-01-19,30.73,31.11,30.69,31.11,75826900,30.57 +2007-01-18,31.15,31.37,30.80,31.00,56364300,30.47 +2007-01-17,31.26,31.44,31.01,31.10,58519600,30.56 +2007-01-16,31.26,31.45,31.03,31.16,62379600,30.62 +2007-01-12,30.65,31.39,30.64,31.21,103972500,30.67 +2007-01-11,29.76,30.75,29.65,30.70,99464300,30.17 +2007-01-10,29.80,29.89,29.43,29.66,55017400,29.15 +2007-01-09,30.00,30.18,29.73,29.96,44636600,29.44 +2007-01-08,29.65,30.10,29.53,29.93,50220200,29.41 +2007-01-05,29.63,29.75,29.45,29.64,44607200,29.13 +2007-01-04,29.70,29.97,29.44,29.81,45774500,29.30 +2007-01-03,29.91,30.25,29.40,29.86,76935100,29.35 +2006-12-29,29.86,30.15,29.83,29.86,41739800,29.35 +2006-12-28,29.86,30.03,29.81,29.98,26690600,29.46 +2006-12-27,29.99,30.13,29.91,30.02,31248400,29.50 +2006-12-26,29.53,30.00,29.40,29.99,37098300,29.47 +2006-12-22,29.83,29.86,29.62,29.64,37971700,29.13 +2006-12-21,30.13,30.14,29.89,29.98,32270500,29.46 +2006-12-20,29.99,30.24,29.97,30.09,31202100,29.57 +2006-12-19,29.71,30.17,29.53,29.99,53822100,29.47 +2006-12-18,30.19,30.26,29.78,29.89,56986800,29.38 +2006-12-15,30.14,30.23,30.03,30.19,102783700,29.67 +2006-12-14,29.54,30.08,29.52,30.07,85866500,29.55 +2006-12-13,29.60,29.60,29.32,29.55,46002500,29.04 +2006-12-12,29.56,29.63,29.22,29.43,68529400,28.92 +2006-12-11,29.19,29.75,29.11,29.54,107712000,29.03 +2006-12-08,28.82,29.40,28.80,29.40,108854900,28.89 +2006-12-07,28.96,29.07,28.81,28.85,46831100,28.35 +2006-12-06,29.10,29.13,28.87,28.99,48564100,28.49 +2006-12-05,29.36,29.40,29.03,29.13,45606000,28.63 +2006-12-04,29.23,29.52,29.17,29.33,55123400,28.82 +2006-12-01,29.23,29.30,28.90,29.12,72257000,28.62 +2006-11-30,29.42,29.57,29.33,29.36,53297400,28.85 +2006-11-29,29.44,29.78,29.43,29.57,58775100,29.06 +2006-11-28,29.34,29.42,29.13,29.39,52602300,28.88 +2006-11-27,29.69,29.74,29.33,29.48,72722100,28.97 +2006-11-24,29.66,29.84,29.64,29.76,20456700,29.25 +2006-11-22,29.97,30.00,29.82,29.92,43907200,29.40 +2006-11-21,29.91,30.00,29.79,29.92,66446600,29.40 +2006-11-20,29.52,30.00,29.50,29.89,85703800,29.38 +2006-11-17,29.31,29.54,29.28,29.40,49356700,28.89 +2006-11-16,29.14,29.64,29.13,29.47,64328500,28.96 +2006-11-15,29.13,29.36,29.11,29.12,63943200,28.62 +2006-11-14,29.28,29.42,29.07,29.23,63012500,28.73 +2006-11-13,29.19,29.46,29.16,29.35,47271800,28.75 +2006-11-10,29.17,29.29,29.15,29.24,37855100,28.64 +2006-11-09,29.11,29.40,29.00,29.26,89407500,28.66 +2006-11-08,28.78,29.23,28.66,28.98,77403300,28.38 +2006-11-07,28.86,29.07,28.80,28.95,56511200,28.35 +2006-11-06,28.77,29.05,28.76,28.84,60446200,28.25 +2006-11-03,28.85,28.93,28.61,28.73,41124500,28.14 +2006-11-02,28.71,28.86,28.58,28.77,58674400,28.18 +2006-11-01,28.78,28.99,28.70,28.81,75895900,28.22 +2006-10-31,28.66,28.85,28.56,28.71,61861700,28.12 +2006-10-30,28.35,28.84,28.32,28.53,47296800,27.94 +2006-10-27,28.49,28.79,28.25,28.34,89060100,27.76 +2006-10-26,28.33,28.41,28.04,28.35,69964200,27.77 +2006-10-25,28.28,28.46,28.14,28.31,40717100,27.73 +2006-10-24,28.43,28.43,28.13,28.28,61409600,27.70 +2006-10-23,28.30,28.69,28.18,28.45,48525000,27.86 +2006-10-20,28.48,28.49,28.17,28.43,48887800,27.85 +2006-10-19,28.35,28.45,28.12,28.29,44730800,27.71 +2006-10-18,28.50,28.70,28.26,28.52,40630800,27.93 +2006-10-17,28.24,28.51,28.17,28.44,40122600,27.85 +2006-10-16,28.48,28.60,28.33,28.45,49744800,27.86 +2006-10-13,28.34,28.69,28.31,28.37,129751900,27.79 +2006-10-12,27.58,28.29,27.54,28.22,120174900,27.64 +2006-10-11,27.46,27.67,27.42,27.54,37219600,26.97 +2006-10-10,27.69,27.75,27.44,27.69,34598500,27.12 +2006-10-09,27.80,27.93,27.62,27.72,33366300,27.15 +2006-10-06,27.76,28.00,27.65,27.87,36452200,27.30 +2006-10-05,27.92,28.11,27.78,27.92,81967200,27.35 +2006-10-04,27.39,27.96,27.37,27.94,82191200,27.37 +2006-10-03,27.37,27.48,27.21,27.37,39386200,26.81 +2006-10-02,27.32,27.49,27.15,27.36,52908100,26.80 +2006-09-29,27.35,27.42,27.21,27.35,34283500,26.79 +2006-09-28,27.47,27.52,27.26,27.40,44179700,26.84 +2006-09-27,27.18,27.47,27.12,27.44,66233900,26.88 +2006-09-26,26.91,27.32,26.88,27.20,54766500,26.64 +2006-09-25,26.81,27.19,26.79,26.95,67903900,26.40 +2006-09-22,26.83,26.85,26.48,26.66,47712500,26.11 +2006-09-21,27.24,27.25,26.85,26.90,58495100,26.35 +2006-09-20,27.01,27.23,26.99,27.18,71676400,26.62 +2006-09-19,26.74,26.94,26.72,26.86,43039100,26.31 +2006-09-18,26.74,27.04,26.67,26.79,49135000,26.24 +2006-09-15,26.58,26.94,26.49,26.85,126057700,26.30 +2006-09-14,25.99,26.50,25.98,26.33,74324500,25.79 +2006-09-13,25.82,26.10,25.82,25.98,37706700,25.45 +2006-09-12,25.90,25.98,25.72,25.93,52248800,25.40 +2006-09-11,25.43,25.95,25.42,25.91,55608200,25.38 +2006-09-08,25.53,25.79,25.46,25.60,36866800,25.07 +2006-09-07,25.48,25.70,25.39,25.43,51266900,24.91 +2006-09-06,25.51,25.72,25.51,25.61,50160400,25.08 +2006-09-05,25.69,25.96,25.56,25.61,44222400,25.08 +2006-09-01,25.89,25.97,25.64,25.84,31594600,25.31 +2006-08-31,25.87,25.98,25.68,25.70,26380500,25.17 +2006-08-30,25.85,25.89,25.64,25.80,30283100,25.27 +2006-08-29,25.92,25.98,25.63,25.84,42711200,25.31 +2006-08-28,25.84,26.00,25.69,25.95,34190900,25.42 +2006-08-25,25.71,26.00,25.69,25.85,33115900,25.32 +2006-08-24,25.82,25.86,25.50,25.74,35933300,25.21 +2006-08-23,25.65,25.95,25.52,25.67,44648500,25.14 +2006-08-22,26.01,26.25,25.62,25.62,89312400,25.09 +2006-08-21,25.66,26.13,25.56,26.12,88398300,25.58 +2006-08-18,25.05,25.80,24.98,25.79,128414800,25.26 +2006-08-17,24.70,24.75,24.61,24.70,45674800,24.19 +2006-08-16,24.61,24.73,24.47,24.70,52373600,24.19 +2006-08-15,24.55,24.65,24.44,24.62,48994500,24.11 +2006-08-14,24.52,24.60,24.35,24.53,47831900,23.94 +2006-08-11,24.43,24.45,24.20,24.43,30255500,23.84 +2006-08-10,24.37,24.60,24.34,24.46,31753400,23.87 +2006-08-09,24.49,24.64,24.34,24.44,44405700,23.85 +2006-08-08,24.39,24.52,24.20,24.34,58171300,23.75 +2006-08-07,24.28,24.48,24.19,24.22,36862400,23.63 +2006-08-04,24.40,24.49,24.15,24.29,45690400,23.70 +2006-08-03,24.19,24.48,24.15,24.21,43155300,23.62 +2006-08-02,24.12,24.40,24.03,24.30,46462000,23.71 +2006-08-01,24.02,24.20,23.85,23.99,49168700,23.41 +2006-07-31,24.07,24.42,24.01,24.06,40254400,23.48 +2006-07-28,24.08,24.28,24.06,24.25,51705800,23.66 +2006-07-27,24.58,24.60,23.77,23.87,85386800,23.29 +2006-07-26,24.12,24.53,24.10,24.37,54942100,23.78 +2006-07-25,24.00,24.29,23.90,24.22,60075800,23.63 +2006-07-24,24.01,24.11,23.79,24.00,59586700,23.42 +2006-07-21,24.08,24.15,23.00,23.87,175483800,23.29 +2006-07-20,23.44,23.45,22.78,22.85,76605200,22.30 +2006-07-19,22.82,23.46,22.72,23.40,82188200,22.83 +2006-07-18,22.59,22.76,22.48,22.74,65047300,22.19 +2006-07-17,22.29,22.61,22.26,22.48,37053500,21.94 +2006-07-14,22.28,22.55,22.23,22.29,67499400,21.75 +2006-07-13,22.37,22.61,22.25,22.26,73099500,21.72 +2006-07-12,22.79,22.88,22.62,22.64,77379300,22.09 +2006-07-11,23.37,23.37,22.74,23.10,88676300,22.54 +2006-07-10,23.43,23.66,23.38,23.50,50565100,22.93 +2006-07-07,23.39,23.55,23.30,23.30,63168800,22.74 +2006-07-06,23.45,23.61,23.42,23.48,44775200,22.91 +2006-07-05,23.48,23.52,23.30,23.35,53093500,22.79 +2006-07-03,23.53,23.72,23.45,23.70,25711400,23.13 +2006-06-30,23.54,23.65,23.30,23.30,73048800,22.74 +2006-06-29,23.32,23.63,23.22,23.47,121395500,22.90 +2006-06-28,22.96,23.25,22.91,23.16,71906500,22.60 +2006-06-27,22.89,23.16,22.84,22.86,84759100,22.31 +2006-06-26,22.65,22.89,22.63,22.82,53644100,22.27 +2006-06-23,22.85,22.87,22.50,22.50,60532600,21.96 +2006-06-22,23.06,23.17,22.78,22.88,76590600,22.33 +2006-06-21,22.61,23.15,22.53,23.08,91660300,22.52 +2006-06-20,22.54,22.76,22.50,22.56,90598500,22.01 +2006-06-19,22.14,22.60,22.12,22.55,129640900,22.01 +2006-06-16,21.97,22.28,21.79,22.10,147506500,21.57 +2006-06-15,22.01,22.13,21.80,22.07,121577300,21.54 +2006-06-14,21.59,21.94,21.55,21.88,86081500,21.35 +2006-06-13,21.73,22.03,21.46,21.51,113175300,20.99 +2006-06-12,21.96,22.10,21.70,21.71,74309700,21.19 +2006-06-09,22.15,22.19,21.89,21.92,52573800,21.39 +2006-06-08,22.03,22.21,21.97,22.11,104126900,21.58 +2006-06-07,22.15,22.39,22.01,22.04,73827500,21.51 +2006-06-06,22.55,22.56,21.98,22.13,126601300,21.60 +2006-06-05,22.72,22.73,22.49,22.50,63914100,21.96 +2006-06-02,22.87,22.99,22.67,22.76,73935600,22.21 +2006-06-01,22.74,22.84,22.62,22.82,80230800,22.27 +2006-05-31,23.26,23.35,22.65,22.65,120202000,22.10 +2006-05-30,23.55,23.76,23.14,23.15,52497500,22.59 +2006-05-26,23.77,23.88,23.56,23.72,46861600,23.15 +2006-05-25,23.57,23.92,23.54,23.74,83052700,23.17 +2006-05-24,22.99,23.54,22.98,23.50,107356700,22.93 +2006-05-23,23.11,23.38,22.77,22.79,79986300,22.24 +2006-05-22,22.48,23.02,22.45,22.88,87322300,22.33 +2006-05-19,22.79,22.90,22.52,22.56,100071200,22.01 +2006-05-18,22.84,23.14,22.76,22.83,95476400,22.28 +2006-05-17,22.89,23.08,22.73,22.73,98598300,22.18 +2006-05-16,23.16,24.00,22.91,23.01,82095100,22.45 +2006-05-15,23.10,23.23,23.03,23.15,67314800,22.59 +2006-05-12,23.14,23.37,23.05,23.17,83115900,22.52 +2006-05-11,23.71,23.79,23.15,23.22,92916700,22.57 +2006-05-10,23.67,23.79,23.59,23.77,76563300,23.11 +2006-05-09,23.75,24.00,23.49,23.62,75345900,22.96 +2006-05-08,23.85,25.00,23.51,23.73,80693500,23.07 +2006-05-05,23.66,23.95,23.52,23.80,131604300,23.13 +2006-05-04,23.35,23.67,23.14,23.44,171257400,22.78 +2006-05-03,23.99,24.02,23.15,23.17,211527100,22.52 +2006-05-02,24.49,25.00,23.90,24.01,190533500,23.34 +2006-05-01,24.32,25.00,24.09,24.29,174800900,23.61 +2006-04-28,24.23,24.50,24.00,24.15,591052200,23.47 +2006-04-27,26.97,27.63,26.94,27.25,96509600,26.49 +2006-04-26,27.08,27.23,27.00,27.10,39190000,26.34 +2006-04-25,27.09,27.21,27.02,27.11,49222500,26.35 +2006-04-24,27.07,27.25,26.98,27.11,42318400,26.35 +2006-04-21,27.05,27.39,27.00,27.15,58528000,26.39 +2006-04-20,27.05,27.19,26.70,27.03,45648300,26.27 +2006-04-19,27.11,27.19,26.96,27.03,45111100,26.27 +2006-04-18,26.94,27.50,26.82,27.22,56272700,26.46 +2006-04-17,27.03,27.05,26.73,26.84,35796200,26.09 +2006-04-13,27.08,27.20,27.00,27.07,28160000,26.31 +2006-04-12,27.10,27.20,26.97,27.20,32183000,26.44 +2006-04-11,27.29,27.32,27.00,27.13,42953400,26.37 +2006-04-10,27.23,27.44,27.20,27.29,39432000,26.53 +2006-04-07,27.61,27.72,27.23,27.25,47249400,26.49 +2006-04-06,27.66,27.72,27.37,27.56,51885500,26.79 +2006-04-05,27.88,27.94,27.64,27.74,41539300,26.96 +2006-04-04,27.60,27.80,27.47,27.64,45470000,26.87 +2006-04-03,27.67,27.73,27.44,27.56,57605300,26.79 +2006-03-31,27.30,27.54,27.21,27.21,62190500,26.45 +2006-03-30,27.03,27.39,27.00,27.23,54612000,26.47 +2006-03-29,26.95,27.20,26.92,27.02,53150300,26.26 +2006-03-28,27.01,27.21,26.81,26.90,58520500,26.15 +2006-03-27,27.01,27.30,27.00,27.01,59908600,26.25 +2006-03-24,26.71,27.21,26.62,27.01,69157600,26.25 +2006-03-23,27.08,27.10,26.66,26.85,73682900,26.10 +2006-03-22,27.08,27.50,26.80,27.15,145696100,26.39 +2006-03-21,27.74,28.22,27.68,27.74,73199600,26.96 +2006-03-20,27.70,27.99,27.67,27.89,67094100,27.11 +2006-03-17,27.35,27.66,27.27,27.50,120615000,26.73 +2006-03-16,27.34,27.48,27.22,27.27,73793700,26.51 +2006-03-15,27.20,27.45,27.01,27.36,57152000,26.60 +2006-03-14,27.04,27.38,26.99,27.23,39821800,26.47 +2006-03-13,27.18,27.29,26.94,27.11,40342600,26.35 +2006-03-10,27.06,27.22,26.88,27.17,41297200,26.41 +2006-03-09,27.27,27.42,27.00,27.00,45360700,26.25 +2006-03-08,26.99,27.50,26.97,27.25,57547400,26.49 +2006-03-07,26.90,27.10,26.81,27.06,51613900,26.30 +2006-03-06,26.92,27.15,26.83,26.91,53054100,26.16 +2006-03-03,26.81,27.16,26.74,26.93,45218800,26.18 +2006-03-02,27.02,27.10,26.90,26.97,41850300,26.22 +2006-03-01,26.98,27.20,26.95,27.14,53061200,26.38 +2006-02-28,26.95,27.30,26.87,26.87,65036100,26.12 +2006-02-27,26.75,27.26,26.67,27.05,51301500,26.29 +2006-02-24,26.59,26.74,26.52,26.63,44753800,25.89 +2006-02-23,26.73,26.89,26.54,26.66,47359100,25.91 +2006-02-22,26.53,26.86,26.47,26.72,43043100,25.97 +2006-02-21,26.72,26.72,26.34,26.54,50216100,25.80 +2006-02-17,26.67,26.81,26.56,26.70,41513200,25.95 +2006-02-16,26.85,26.90,26.57,26.81,48868500,26.06 +2006-02-15,26.60,26.93,26.50,26.88,62808900,26.13 +2006-02-14,26.41,26.68,26.35,26.65,58432900,25.82 +2006-02-13,26.63,26.70,26.34,26.39,46707000,25.57 +2006-02-10,26.62,26.89,26.51,26.69,52127000,25.86 +2006-02-09,26.96,27.03,26.65,26.66,52861700,25.83 +2006-02-08,27.01,27.08,26.71,26.91,51795200,26.07 +2006-02-07,26.95,27.15,26.81,26.94,72159500,26.10 +2006-02-06,27.51,27.54,27.09,27.17,60170500,26.32 +2006-02-03,27.48,27.70,27.34,27.54,75022700,26.68 +2006-02-02,27.97,27.99,27.55,27.68,55073400,26.82 +2006-02-01,27.96,28.07,27.76,28.04,68448800,27.16 +2006-01-31,27.91,28.38,27.87,28.15,94841300,27.27 +2006-01-30,27.82,28.18,27.78,28.00,103999200,27.13 +2006-01-27,27.23,27.95,27.19,27.79,134520700,26.92 +2006-01-26,26.56,26.72,26.31,26.50,69509300,25.67 +2006-01-25,26.41,26.57,26.23,26.40,59072100,25.58 +2006-01-24,26.34,26.45,26.22,26.28,63040700,25.46 +2006-01-23,26.41,26.53,26.30,26.35,47925600,25.53 +2006-01-20,27.01,27.01,26.26,26.41,79165900,25.58 +2006-01-19,26.87,27.24,26.85,27.02,60367600,26.18 +2006-01-18,26.74,26.98,26.70,26.83,52376200,25.99 +2006-01-17,26.90,27.19,26.90,26.99,58566600,26.15 +2006-01-13,27.03,27.25,27.01,27.19,41418000,26.34 +2006-01-12,27.25,27.26,26.97,27.14,45994800,26.29 +2006-01-11,27.01,27.39,26.90,27.29,70120700,26.44 +2006-01-10,26.65,27.02,26.59,27.00,64921900,26.16 +2006-01-09,26.93,27.07,26.76,26.86,55625000,26.02 +2006-01-06,26.89,27.00,26.49,26.91,100963000,26.07 +2006-01-05,26.96,27.13,26.91,26.99,48245500,26.15 +2006-01-04,26.77,27.08,26.77,26.97,57975600,26.13 +2006-01-03,26.25,27.00,26.10,26.84,79973000,26.00 +2005-12-30,26.15,26.31,26.10,26.15,49044600,25.33 +2005-12-29,26.41,26.50,26.26,26.27,34495500,25.45 +2005-12-28,26.51,26.66,26.35,26.39,35444400,25.57 +2005-12-27,26.68,26.85,26.45,26.46,37819000,25.63 +2005-12-23,26.52,26.67,26.44,26.64,30689200,25.81 +2005-12-22,26.71,26.78,26.42,26.59,91276900,25.76 +2005-12-21,26.87,26.91,26.71,26.73,75800900,25.89 +2005-12-20,26.76,26.88,26.67,26.86,62960600,26.02 +2005-12-19,26.82,26.87,26.65,26.83,68680100,25.99 +2005-12-16,26.88,27.08,26.81,26.90,88542500,26.06 +2005-12-15,27.08,27.11,26.81,26.92,79018100,26.08 +2005-12-14,27.00,27.24,26.85,27.09,65076200,26.24 +2005-12-13,27.29,27.43,27.00,27.13,104285500,26.28 +2005-12-12,27.70,27.75,27.33,27.45,63757200,26.59 +2005-12-09,27.71,27.83,27.64,27.71,48467000,26.84 +2005-12-08,27.71,27.81,27.60,27.69,63931600,26.83 +2005-12-07,27.67,27.75,27.55,27.75,55583200,26.88 +2005-12-06,27.90,27.92,27.68,27.69,65980000,26.83 +2005-12-05,27.93,28.02,27.71,27.85,47517300,26.98 +2005-12-02,27.82,28.10,27.79,28.01,42319600,27.14 +2005-12-01,27.73,28.10,27.73,27.89,61006100,27.02 +2005-11-30,27.68,27.77,27.63,27.68,55904700,26.82 +2005-11-29,27.79,27.79,27.60,27.68,62220400,26.82 +2005-11-28,27.79,27.85,27.53,27.75,57517200,26.88 +2005-11-25,27.80,27.94,27.47,27.76,44082500,26.89 +2005-11-23,27.92,28.09,27.74,27.92,70541300,27.05 +2005-11-22,28.06,28.08,27.86,27.91,104253300,27.04 +2005-11-21,28.07,28.24,27.84,28.16,65794400,27.28 +2005-11-18,28.12,28.25,27.90,28.07,75431200,27.19 +2005-11-17,27.85,28.00,27.76,27.97,91351000,27.10 +2005-11-16,27.48,27.88,27.44,27.74,86277000,26.87 +2005-11-15,27.33,27.54,27.25,27.50,65081000,26.64 +2005-11-14,27.36,27.44,27.20,27.37,67152200,26.44 +2005-11-11,27.15,27.39,27.13,27.28,51945600,26.35 +2005-11-10,26.94,27.15,26.64,27.09,73314800,26.17 +2005-11-09,26.98,27.15,26.94,26.96,59562100,26.04 +2005-11-08,26.94,27.18,26.77,27.05,60091700,26.13 +2005-11-07,26.72,27.08,26.70,27.01,77104800,26.09 +2005-11-04,26.53,26.71,26.45,26.66,57464000,25.75 +2005-11-03,26.60,26.64,26.25,26.44,73421600,25.54 +2005-11-02,25.93,26.50,25.93,26.46,75067100,25.56 +2005-11-01,25.61,26.10,25.61,25.96,71370400,25.08 +2005-10-31,25.61,25.80,25.50,25.70,75122100,24.82 +2005-10-28,25.10,25.60,25.10,25.53,106559300,24.66 +2005-10-27,25.22,25.27,24.85,24.85,61566100,24.00 +2005-10-26,24.97,25.33,24.93,25.11,58178100,24.25 +2005-10-25,24.95,25.13,24.83,25.03,41310500,24.18 +2005-10-24,24.89,25.10,24.68,25.10,51868000,24.24 +2005-10-21,24.91,25.00,24.57,24.78,69431200,23.94 +2005-10-20,25.05,25.13,24.74,24.79,58830600,23.95 +2005-10-19,24.56,25.09,24.50,25.09,66574500,24.24 +2005-10-18,24.49,24.83,24.45,24.57,69328200,23.73 +2005-10-17,24.68,24.69,24.44,24.53,46924400,23.69 +2005-10-14,24.71,24.73,24.50,24.67,53846700,23.83 +2005-10-13,24.31,24.73,24.27,24.59,70192000,23.75 +2005-10-12,24.49,24.70,24.27,24.30,71294400,23.47 +2005-10-11,24.51,24.55,24.25,24.41,76567300,23.58 +2005-10-10,24.67,24.68,24.35,24.46,48880900,23.63 +2005-10-07,24.77,24.84,24.52,24.59,50768700,23.75 +2005-10-06,24.66,24.95,24.53,24.73,81724600,23.89 +2005-10-05,25.04,25.05,24.67,24.67,73684700,23.83 +2005-10-04,25.36,25.39,24.75,24.98,151666300,24.13 +2005-10-03,25.71,25.73,25.44,25.50,55341300,24.63 +2005-09-30,25.91,25.95,25.61,25.73,57644500,24.85 +2005-09-29,25.61,26.00,25.50,25.94,66807100,25.06 +2005-09-28,25.39,25.87,25.38,25.67,71019400,24.80 +2005-09-27,25.37,25.45,25.30,25.34,48797900,24.48 +2005-09-26,25.40,25.49,25.21,25.27,56203700,24.41 +2005-09-23,25.31,25.54,25.12,25.27,66396800,24.41 +2005-09-22,25.49,25.60,25.15,25.34,71314900,24.48 +2005-09-21,25.80,25.90,25.43,25.49,68281800,24.62 +2005-09-20,26.07,26.22,25.69,25.84,61043400,24.96 +2005-09-19,26.09,26.27,25.86,26.00,61832300,25.11 +2005-09-16,26.34,26.40,25.97,26.07,187384300,25.18 +2005-09-15,26.37,26.43,26.22,26.27,60357200,25.37 +2005-09-14,26.52,26.64,26.30,26.31,54969600,25.41 +2005-09-13,26.54,26.76,26.37,26.48,63422900,25.58 +2005-09-12,26.62,26.75,26.52,26.61,40550500,25.70 +2005-09-09,26.62,26.82,26.53,26.58,41515800,25.67 +2005-09-08,26.80,26.88,26.52,26.61,52552300,25.70 +2005-09-07,26.94,27.11,26.82,26.85,44656100,25.94 +2005-09-06,27.06,27.29,26.98,27.00,46089000,26.08 +2005-09-02,27.21,27.27,26.97,27.02,52047500,26.10 +2005-09-01,27.38,27.39,27.15,27.20,75974500,26.27 +2005-08-31,27.17,27.44,27.04,27.38,65210200,26.45 +2005-08-30,27.06,27.23,26.96,27.18,55163200,26.25 +2005-08-29,26.81,27.23,26.81,27.15,52307700,26.22 +2005-08-26,27.06,27.08,26.87,26.97,36774600,26.05 +2005-08-25,26.90,27.09,26.85,27.03,39306300,26.11 +2005-08-24,26.84,27.16,26.78,26.81,63645000,25.90 +2005-08-23,26.84,27.07,26.74,26.87,48296700,25.95 +2005-08-22,26.79,27.17,26.77,26.91,41691700,25.99 +2005-08-19,26.85,26.91,26.70,26.72,36043500,25.81 +2005-08-18,26.89,27.08,26.80,26.82,40861900,25.91 +2005-08-17,26.82,27.15,26.66,26.95,52413100,26.03 +2005-08-16,27.03,27.14,26.70,26.74,46894600,25.83 +2005-08-15,26.98,27.30,26.69,27.13,45976600,26.21 +2005-08-12,27.08,27.14,26.90,27.05,52006500,26.05 +2005-08-11,26.98,27.30,26.89,27.27,48646800,26.26 +2005-08-10,27.41,27.50,26.85,26.95,62818800,25.95 +2005-08-09,27.22,27.51,27.01,27.35,64761800,26.34 +2005-08-08,27.80,27.84,27.08,27.13,77207200,26.13 +2005-08-05,27.29,27.94,27.25,27.76,82212400,26.73 +2005-08-04,27.16,27.50,27.05,27.32,91461400,26.31 +2005-08-03,26.76,27.43,26.73,27.25,139422400,26.24 +2005-08-02,25.90,26.90,25.87,26.81,137510100,25.82 +2005-08-01,25.81,26.05,25.76,25.92,61346800,24.96 +2005-07-29,25.78,26.00,25.59,25.61,59524400,24.66 +2005-07-28,25.75,25.85,25.66,25.75,44738700,24.80 +2005-07-27,25.61,25.80,25.53,25.72,57977300,24.77 +2005-07-26,25.72,25.74,25.53,25.54,51476400,24.60 +2005-07-25,25.69,25.90,25.65,25.69,45174600,24.74 +2005-07-22,25.99,26.34,25.63,25.68,97558900,24.73 +2005-07-21,26.30,26.48,26.00,26.44,112932100,25.46 +2005-07-20,26.00,26.23,25.88,26.19,71424800,25.22 +2005-07-19,25.79,26.25,25.75,26.16,113290100,25.19 +2005-07-18,25.71,25.79,25.55,25.55,39668000,24.61 +2005-07-15,26.04,26.10,25.75,25.79,56472800,24.84 +2005-07-14,25.79,26.10,25.79,25.97,69506800,25.01 +2005-07-13,25.53,25.75,25.48,25.66,44749200,24.71 +2005-07-12,25.24,25.62,25.20,25.61,63384800,24.66 +2005-07-11,25.15,25.38,25.11,25.29,61525400,24.36 +2005-07-08,24.64,25.12,24.63,25.09,56104000,24.16 +2005-07-07,24.58,24.71,24.50,24.65,80082900,23.74 +2005-07-06,24.97,25.08,24.69,24.70,64214600,23.79 +2005-07-05,24.66,25.19,24.62,24.98,61883500,24.06 +2005-07-01,24.85,24.99,24.67,24.71,69718400,23.80 +2005-06-30,25.06,25.14,24.82,24.84,82018200,23.92 +2005-06-29,25.22,25.32,25.00,25.09,55859900,24.16 +2005-06-28,25.09,25.20,25.03,25.07,53058100,24.14 +2005-06-27,25.07,25.25,25.03,25.05,61636200,24.12 +2005-06-24,25.22,25.40,25.04,25.04,57970700,24.12 +2005-06-23,25.17,25.62,25.15,25.31,105159800,24.38 +2005-06-22,25.11,25.26,25.03,25.07,60492700,24.14 +2005-06-21,25.08,25.19,25.04,25.15,81084000,24.22 +2005-06-20,24.98,25.28,24.93,25.11,50538900,24.18 +2005-06-17,25.27,25.29,24.92,25.04,90821300,24.12 +2005-06-16,25.22,25.23,24.95,25.04,65918800,24.12 +2005-06-15,25.40,25.41,25.11,25.26,50764800,24.33 +2005-06-14,25.31,25.44,25.24,25.36,44243300,24.42 +2005-06-13,25.36,25.49,25.26,25.31,49104100,24.38 +2005-06-10,25.49,25.52,25.34,25.43,39459800,24.49 +2005-06-09,25.40,25.61,25.35,25.51,52767900,24.57 +2005-06-08,25.55,25.62,25.34,25.40,45369700,24.46 +2005-06-07,25.33,25.83,25.31,25.51,54511400,24.57 +2005-06-06,25.38,25.50,25.31,25.37,40756900,24.43 +2005-06-03,25.70,25.81,25.34,25.43,79659500,24.49 +2005-06-02,25.71,25.86,25.64,25.79,27212500,24.84 +2005-06-01,25.73,26.00,25.61,25.81,54621000,24.86 +2005-05-31,25.99,26.03,25.75,25.80,46131100,24.85 +2005-05-27,25.83,26.09,25.81,26.07,54978000,25.11 +2005-05-26,25.75,26.00,25.73,25.90,50579200,24.94 +2005-05-25,25.68,25.77,25.50,25.71,35749000,24.76 +2005-05-24,25.80,25.88,25.72,25.75,61287700,24.80 +2005-05-23,25.74,26.07,25.74,25.85,75421100,24.90 +2005-05-20,25.88,25.92,25.73,25.74,64444500,24.79 +2005-05-19,25.75,26.05,25.70,25.92,52120800,24.96 +2005-05-18,25.50,25.84,25.42,25.70,71182400,24.75 +2005-05-17,25.31,25.50,25.25,25.46,39983200,24.52 +2005-05-16,25.23,25.50,25.19,25.49,50577300,24.55 +2005-05-13,25.03,25.38,24.99,25.30,77204300,24.29 +2005-05-12,24.84,25.11,24.83,25.00,74540700,24.00 +2005-05-11,24.89,24.97,24.64,24.91,59463300,23.91 +2005-05-10,25.04,25.08,24.82,24.90,62235100,23.90 +2005-05-09,25.23,25.33,25.05,25.11,61872400,24.11 +2005-05-06,25.33,25.48,25.19,25.22,64322600,24.21 +2005-05-05,25.20,25.33,25.08,25.23,59362300,24.22 +2005-05-04,25.34,25.40,25.11,25.21,86864200,24.20 +2005-05-03,25.13,25.40,25.09,25.36,67867800,24.35 +2005-05-02,25.23,25.36,24.95,25.23,54376700,24.22 +2005-04-29,24.88,25.30,24.79,25.30,98641200,24.29 +2005-04-28,24.82,24.92,24.44,24.45,83623100,23.47 +2005-04-27,24.66,25.15,24.63,24.99,47732800,23.99 +2005-04-26,24.95,25.25,24.74,24.76,60464300,23.77 +2005-04-25,25.07,25.28,24.86,24.99,75457900,23.99 +2005-04-22,25.05,25.25,24.78,24.98,80087500,23.98 +2005-04-21,24.48,25.39,24.47,25.28,93562300,24.27 +2005-04-20,24.66,24.70,24.30,24.32,91923500,23.35 +2005-04-19,24.71,24.80,24.45,24.63,65956200,23.65 +2005-04-18,24.45,24.84,24.40,24.65,75766400,23.66 +2005-04-15,24.58,24.90,24.41,24.46,100251600,23.48 +2005-04-14,25.01,25.14,24.83,24.84,66754400,23.85 +2005-04-13,25.23,25.45,24.99,25.04,60929300,24.04 +2005-04-12,24.92,25.35,24.80,25.32,67517800,24.31 +2005-04-11,25.03,25.11,24.86,24.97,47791800,23.97 +2005-04-08,25.07,25.25,24.91,24.94,47956300,23.94 +2005-04-07,24.66,25.13,24.63,25.10,77451500,24.10 +2005-04-06,24.47,24.94,24.45,24.67,78020200,23.68 +2005-04-05,24.22,24.50,24.12,24.47,73549600,23.49 +2005-04-04,24.11,24.26,23.94,24.23,62196400,23.26 +2005-04-01,24.24,24.35,24.10,24.12,64619600,23.16 +2005-03-31,24.25,24.31,24.12,24.17,62382300,23.20 +2005-03-30,24.04,24.19,24.00,24.16,59585700,23.19 +2005-03-29,24.14,24.24,23.82,23.92,74231700,22.96 +2005-03-28,24.40,24.47,24.18,24.20,49802000,23.23 +2005-03-24,24.24,24.47,24.20,24.28,78820900,23.31 +2005-03-23,23.99,24.39,23.96,24.18,79293300,23.21 +2005-03-22,24.19,24.27,23.96,23.99,102113300,23.03 +2005-03-21,24.35,24.36,24.15,24.20,71446200,23.23 +2005-03-18,24.53,24.91,24.28,24.31,135904000,23.34 +2005-03-17,24.64,24.68,24.53,24.54,60573200,23.56 +2005-03-16,24.82,24.97,24.56,24.63,74841400,23.65 +2005-03-15,25.10,25.24,24.89,24.91,71469400,23.91 +2005-03-14,25.08,25.15,24.96,25.11,65550500,24.11 +2005-03-11,25.45,25.48,25.06,25.09,60617900,24.09 +2005-03-10,25.43,25.48,25.25,25.43,59132900,24.41 +2005-03-09,25.39,25.57,25.28,25.31,62991800,24.30 +2005-03-08,25.40,25.62,25.34,25.40,52871800,24.38 +2005-03-07,25.17,25.79,25.16,25.47,80407400,24.45 +2005-03-04,25.21,25.30,25.13,25.17,63058200,24.16 +2005-03-03,25.30,25.31,25.14,25.17,52183600,24.16 +2005-03-02,25.19,25.48,25.16,25.26,67739000,24.25 +2005-03-01,25.19,25.41,25.13,25.28,56394800,24.27 +2005-02-28,25.22,25.37,25.13,25.16,82728000,24.15 +2005-02-25,25.33,25.38,25.15,25.25,62467700,24.24 +2005-02-24,25.18,25.44,25.15,25.37,85236300,24.36 +2005-02-23,25.24,25.35,25.17,25.20,83689400,24.19 +2005-02-22,25.25,25.49,25.20,25.23,96419200,24.22 +2005-02-18,25.64,25.65,25.40,25.48,77091100,24.46 +2005-02-17,25.71,25.86,25.60,25.65,67024800,24.62 +2005-02-16,25.87,25.93,25.67,25.79,57506600,24.76 +2005-02-15,26.00,26.08,25.86,25.93,76551600,24.89 +2005-02-14,25.93,26.12,25.91,26.01,58694000,24.89 +2005-02-11,26.03,26.12,25.81,25.97,83835900,24.86 +2005-02-10,26.10,26.13,26.00,26.06,71796400,24.94 +2005-02-09,26.25,26.31,26.04,26.07,77874800,24.95 +2005-02-08,26.19,26.34,26.16,26.24,61343700,25.11 +2005-02-07,26.27,26.30,26.06,26.16,57763400,25.04 +2005-02-04,26.17,26.37,26.14,26.32,61246500,25.19 +2005-02-03,26.37,26.40,26.10,26.18,62545400,25.06 +2005-02-02,26.42,26.50,26.28,26.46,79329500,25.32 +2005-02-01,26.25,26.43,26.22,26.39,57981700,25.26 +2005-01-31,26.35,26.52,26.16,26.28,71442100,25.15 +2005-01-28,26.54,26.65,25.96,26.18,110466500,25.06 +2005-01-27,25.95,26.16,25.85,26.11,93204100,24.99 +2005-01-26,26.07,26.17,25.90,26.01,64974500,24.89 +2005-01-25,25.76,26.19,25.75,26.02,67580700,24.90 +2005-01-24,25.76,26.00,25.64,25.67,69010900,24.57 +2005-01-21,25.95,26.13,25.64,25.65,76501000,24.55 +2005-01-20,25.84,26.10,25.74,25.86,58380100,24.75 +2005-01-19,26.21,26.26,25.92,25.98,58114100,24.86 +2005-01-18,26.03,26.35,25.84,26.32,69146400,25.19 +2005-01-14,26.40,26.45,26.04,26.12,92180800,25.00 +2005-01-13,26.68,26.80,26.16,26.27,89861600,25.14 +2005-01-12,26.77,26.85,26.62,26.78,72940600,25.63 +2005-01-11,26.69,26.82,26.61,26.73,64712000,25.58 +2005-01-10,26.60,26.86,26.54,26.80,70376600,25.65 +2005-01-07,26.82,26.89,26.62,26.67,68723300,25.53 +2005-01-06,26.85,27.06,26.64,26.75,76890500,25.60 +2005-01-05,26.84,27.10,26.76,26.78,72463500,25.63 +2005-01-04,26.87,27.10,26.66,26.84,109442100,25.69 +2005-01-03,26.80,26.95,26.65,26.74,65002900,25.59 diff --git a/includes/js/dojox/charting/tests/data/yahoo_prices.csv b/includes/js/dojox/charting/tests/data/yahoo_prices.csv new file mode 100644 index 0000000..261889b --- /dev/null +++ b/includes/js/dojox/charting/tests/data/yahoo_prices.csv @@ -0,0 +1,796 @@ +Date,Open,High,Low,Close,Volume,Adj Close +2008-02-29,27.94,28.41,27.50,27.78,23860500,27.78 +2008-02-28,27.98,28.82,27.96,28.15,30113200,28.15 +2008-02-27,28.33,28.49,27.75,28.37,27664100,28.37 +2008-02-26,27.93,28.55,27.81,28.22,26013000,28.22 +2008-02-25,28.42,28.57,27.75,28.13,32470600,28.13 +2008-02-22,28.36,28.64,27.98,28.42,26157800,28.42 +2008-02-21,28.76,29.17,28.25,28.42,34494000,28.42 +2008-02-20,28.71,29.04,28.39,28.83,29274700,28.83 +2008-02-19,29.34,29.42,28.75,29.01,38679600,29.01 +2008-02-15,29.95,30.15,29.43,29.66,40125200,29.66 +2008-02-14,29.98,30.25,29.75,29.98,38045600,29.98 +2008-02-13,29.78,30.07,29.60,29.88,57047700,29.88 +2008-02-12,29.81,29.84,29.40,29.57,42445600,29.57 +2008-02-11,29.89,30.05,29.32,29.87,67253700,29.87 +2008-02-08,28.98,29.22,28.71,29.20,55618900,29.20 +2008-02-07,28.63,29.19,28.60,29.04,44248800,29.04 +2008-02-06,29.11,29.33,28.53,28.57,55648800,28.57 +2008-02-05,28.78,29.57,28.75,28.98,68583700,28.98 +2008-02-04,28.33,29.50,28.33,29.33,144814000,29.33 +2008-02-01,28.68,29.83,27.34,28.38,438248800,28.38 +2008-01-31,18.87,19.35,18.72,19.18,41449800,19.18 +2008-01-30,18.62,20.81,18.58,19.05,115993300,19.05 +2008-01-29,20.87,20.90,20.05,20.81,79230000,20.81 +2008-01-28,21.56,21.90,20.42,20.78,32473100,20.78 +2008-01-25,22.24,22.37,21.32,21.94,28386800,21.94 +2008-01-24,20.44,21.75,20.42,21.69,39823300,21.69 +2008-01-23,19.25,20.34,18.72,20.01,42064200,20.01 +2008-01-22,19.29,21.03,19.26,19.86,38126200,19.86 +2008-01-18,21.27,21.61,20.07,20.78,41239300,20.78 +2008-01-17,22.00,22.17,21.14,21.22,28812600,21.22 +2008-01-16,22.20,22.75,21.73,21.95,38155300,21.95 +2008-01-15,23.00,23.49,22.57,22.91,31911000,22.91 +2008-01-14,23.51,23.76,23.18,23.70,18552900,23.70 +2008-01-11,23.81,24.13,22.98,23.36,27297400,23.36 +2008-01-10,23.19,24.57,22.83,24.09,52342100,24.09 +2008-01-09,22.47,22.80,21.37,22.56,46662700,22.56 +2008-01-08,23.28,23.65,22.50,22.61,22974000,22.61 +2008-01-07,23.12,23.56,22.73,23.18,24769400,23.18 +2008-01-04,23.81,23.81,23.10,23.16,20745800,23.16 +2008-01-03,23.86,24.19,23.70,23.84,20179700,23.84 +2008-01-02,23.80,24.15,23.60,23.72,25671700,23.72 +2007-12-31,23.22,23.43,23.11,23.26,14782600,23.26 +2007-12-28,23.66,23.71,23.21,23.45,13773000,23.45 +2007-12-27,23.60,24.15,23.57,23.71,16041500,23.71 +2007-12-26,23.85,24.25,23.85,23.96,9821600,23.96 +2007-12-24,24.01,24.19,23.94,24.05,24861800,24.05 +2007-12-21,23.88,24.10,23.74,24.01,24094600,24.01 +2007-12-20,23.50,23.80,23.24,23.64,21030700,23.64 +2007-12-19,22.92,23.69,22.92,23.31,26547300,23.31 +2007-12-18,23.22,23.35,22.80,23.02,27735600,23.02 +2007-12-17,23.80,24.03,22.94,23.04,37877100,23.04 +2007-12-14,24.13,24.47,24.00,24.06,15125500,24.06 +2007-12-13,24.39,24.75,24.19,24.38,23787400,24.38 +2007-12-12,24.82,25.00,24.11,24.54,20241200,24.54 +2007-12-11,25.15,25.65,24.36,24.47,28579100,24.47 +2007-12-10,25.51,25.57,24.92,25.20,26074900,25.20 +2007-12-07,25.86,26.11,25.50,25.63,11443200,25.63 +2007-12-06,25.88,26.02,25.39,25.96,19236500,25.96 +2007-12-05,26.63,26.73,25.73,25.98,21170900,25.98 +2007-12-04,26.14,26.73,26.11,26.42,14668800,26.42 +2007-12-03,26.64,27.20,26.56,26.61,15250100,26.61 +2007-11-30,26.96,27.33,26.51,26.81,23994000,26.81 +2007-11-29,26.01,26.71,25.91,26.63,17929700,26.63 +2007-11-28,26.03,26.70,25.93,26.20,23239300,26.20 +2007-11-27,25.18,26.00,25.17,25.59,19484500,25.59 +2007-11-26,26.08,26.25,25.20,25.22,24174600,25.22 +2007-11-23,25.98,26.40,25.76,26.13,9249400,26.13 +2007-11-21,26.11,26.58,25.52,25.71,23320100,25.71 +2007-11-20,26.93,27.25,25.98,26.72,25672500,26.72 +2007-11-19,27.11,27.35,26.35,26.76,33066200,26.76 +2007-11-16,25.66,27.13,25.10,26.82,53013100,26.82 +2007-11-15,24.94,25.75,24.90,25.42,27920800,25.42 +2007-11-14,26.42,26.44,25.00,25.07,38154800,25.07 +2007-11-13,25.53,26.24,25.30,26.10,34123300,26.10 +2007-11-12,25.80,26.20,24.69,24.78,31264200,24.78 +2007-11-09,26.13,26.38,25.40,25.79,45199700,25.79 +2007-11-08,28.11,28.24,25.82,26.70,58160600,26.70 +2007-11-07,29.27,29.30,27.56,27.63,57069800,27.63 +2007-11-06,31.76,31.79,29.00,29.93,63664400,29.93 +2007-11-05,30.71,32.37,30.35,31.36,43520300,31.36 +2007-11-02,30.54,31.21,29.64,31.11,34090300,31.11 +2007-11-01,30.86,31.10,30.04,30.22,26913300,30.22 +2007-10-31,31.50,31.75,30.50,31.10,34762000,31.10 +2007-10-30,31.55,31.64,30.12,30.83,52417300,30.83 +2007-10-29,34.07,34.08,31.18,31.79,83685800,31.79 +2007-10-26,32.43,33.99,31.61,33.63,66018100,33.63 +2007-10-25,30.75,31.62,30.50,31.34,38706600,31.34 +2007-10-24,30.68,30.98,30.00,30.68,33603100,30.68 +2007-10-23,30.12,30.88,30.03,30.64,45406200,30.64 +2007-10-22,28.93,30.00,28.80,29.85,27750100,29.85 +2007-10-19,29.36,29.96,28.85,29.03,41933000,29.03 +2007-10-18,28.59,29.60,28.47,29.35,28152200,29.35 +2007-10-17,29.10,29.20,28.00,28.82,75067700,28.82 +2007-10-16,27.37,27.48,26.55,26.69,56275300,26.69 +2007-10-15,28.32,28.40,27.46,27.86,22994100,27.86 +2007-10-12,27.76,28.51,27.65,28.48,22130500,28.48 +2007-10-11,28.44,28.68,27.50,27.65,25298300,27.65 +2007-10-10,28.43,28.70,27.90,28.36,14847100,28.36 +2007-10-09,28.35,28.76,27.94,28.37,19539500,28.37 +2007-10-08,28.01,28.17,27.75,28.05,15060700,28.05 +2007-10-05,27.78,28.16,27.75,27.88,28389600,27.88 +2007-10-04,27.19,27.29,26.90,27.15,19203600,27.15 +2007-10-03,27.16,27.38,26.82,27.17,18052500,27.17 +2007-10-02,27.20,27.24,26.62,26.95,15133400,26.95 +2007-10-01,26.76,27.10,26.73,27.04,16938700,27.04 +2007-09-28,26.49,26.89,26.20,26.84,22155600,26.84 +2007-09-27,26.95,26.95,26.17,26.27,21365200,26.27 +2007-09-26,26.70,27.07,26.50,26.70,18692400,26.70 +2007-09-25,25.70,26.65,25.63,26.51,33721300,26.51 +2007-09-24,26.13,26.40,25.51,25.73,27597800,25.73 +2007-09-21,25.54,26.21,25.29,26.05,53074900,26.05 +2007-09-20,25.28,25.61,25.16,25.29,17312000,25.29 +2007-09-19,25.09,25.37,24.81,25.29,25867900,25.29 +2007-09-18,25.06,25.21,24.53,25.06,28121000,25.06 +2007-09-17,24.50,25.10,24.38,24.95,20594000,24.95 +2007-09-14,23.69,25.00,23.65,24.73,28868600,24.73 +2007-09-13,23.60,23.96,23.60,23.72,10309000,23.72 +2007-09-12,23.64,23.94,23.53,23.56,16553700,23.56 +2007-09-11,23.31,23.84,23.31,23.71,17207500,23.71 +2007-09-10,23.85,23.85,23.10,23.30,15246000,23.30 +2007-09-07,23.76,24.05,23.60,23.76,12591900,23.76 +2007-09-06,24.22,24.32,23.62,24.15,13922100,24.15 +2007-09-05,24.10,24.40,23.91,24.10,23071000,24.10 +2007-09-04,23.30,24.50,23.20,23.97,43598600,23.97 +2007-08-31,22.81,22.83,22.51,22.73,13052500,22.73 +2007-08-30,22.49,22.91,22.38,22.61,18172500,22.61 +2007-08-29,22.60,22.69,22.27,22.55,24599900,22.55 +2007-08-28,22.95,23.10,22.50,22.52,18030600,22.52 +2007-08-27,23.59,23.76,23.01,23.03,16523800,23.03 +2007-08-24,23.03,23.73,23.03,23.59,11191100,23.59 +2007-08-23,23.35,23.36,22.95,23.13,15603000,23.13 +2007-08-22,23.22,23.52,23.18,23.23,18763700,23.23 +2007-08-21,23.25,23.48,22.91,23.04,25962900,23.04 +2007-08-20,23.64,23.74,23.18,23.34,13338900,23.34 +2007-08-17,23.26,23.63,22.76,23.54,19528200,23.54 +2007-08-16,23.00,23.15,22.50,22.76,29652200,22.76 +2007-08-15,23.56,24.00,23.25,23.32,18767700,23.32 +2007-08-14,24.69,24.70,23.69,23.72,18707100,23.72 +2007-08-13,24.21,24.74,24.01,24.57,21317600,24.57 +2007-08-10,23.93,24.22,23.52,23.94,22939800,23.94 +2007-08-09,23.67,24.45,23.51,23.80,24052500,23.80 +2007-08-08,23.46,23.87,23.43,23.87,17198000,23.87 +2007-08-07,22.75,23.70,22.69,23.44,20075300,23.44 +2007-08-06,23.03,23.15,22.44,22.97,28948000,22.97 +2007-08-03,23.20,23.39,22.87,22.92,19702100,22.92 +2007-08-02,22.65,23.70,22.65,23.36,21098900,23.36 +2007-08-01,23.17,23.40,22.85,23.25,22030400,23.25 +2007-07-31,23.88,23.93,23.24,23.25,21575800,23.25 +2007-07-30,23.55,23.88,23.38,23.62,20976600,23.62 +2007-07-27,23.98,24.49,23.47,23.49,35783800,23.49 +2007-07-26,24.40,24.49,23.62,24.03,33373300,24.03 +2007-07-25,25.01,25.32,24.59,24.68,21882400,24.68 +2007-07-24,24.80,25.34,24.73,24.84,28981000,24.84 +2007-07-23,25.43,25.46,24.98,24.99,26631500,24.99 +2007-07-20,25.70,25.89,25.20,25.35,38056100,25.35 +2007-07-19,26.32,26.34,25.92,26.03,29537900,26.03 +2007-07-18,26.07,26.72,26.02,26.20,65125900,26.20 +2007-07-17,26.74,27.80,26.70,27.53,53656100,27.53 +2007-07-16,26.48,26.74,26.13,26.70,30804500,26.70 +2007-07-13,26.87,26.97,26.50,26.58,18522700,26.58 +2007-07-12,26.70,26.97,26.34,26.96,20082300,26.96 +2007-07-11,27.03,27.05,26.55,26.69,21970700,26.69 +2007-07-10,27.09,27.57,26.96,26.97,24635500,26.97 +2007-07-09,26.92,27.33,26.82,27.20,17515800,27.20 +2007-07-06,27.01,27.14,26.93,27.10,12284500,27.10 +2007-07-05,26.92,27.14,26.90,26.99,16071900,26.99 +2007-07-03,26.95,27.25,26.90,27.00,11643400,27.00 +2007-07-02,27.19,27.27,26.76,26.86,21011000,26.86 +2007-06-29,27.21,27.38,26.93,27.13,13842500,27.13 +2007-06-28,27.44,27.49,27.12,27.25,17124500,27.25 +2007-06-27,27.51,27.66,27.40,27.58,13997000,27.58 +2007-06-26,27.73,28.18,27.36,27.71,25324000,27.71 +2007-06-25,27.60,27.77,27.34,27.64,21232200,27.64 +2007-06-22,27.68,27.79,27.31,27.38,33796900,27.38 +2007-06-21,27.69,27.94,27.55,27.67,17885800,27.67 +2007-06-20,27.89,28.17,27.66,27.66,33496400,27.66 +2007-06-19,29.40,29.40,27.54,27.63,65967500,27.63 +2007-06-18,27.72,28.34,27.50,28.12,70919400,28.12 +2007-06-15,27.49,27.52,27.19,27.31,23816900,27.31 +2007-06-14,27.38,27.64,27.15,27.30,18919400,27.30 +2007-06-13,27.12,27.41,26.61,27.38,31210700,27.38 +2007-06-12,27.30,27.66,26.98,27.05,22203600,27.05 +2007-06-11,27.27,27.52,27.15,27.35,14856500,27.35 +2007-06-08,27.02,27.45,26.96,27.39,18618500,27.39 +2007-06-07,27.34,27.73,26.98,26.98,34232300,26.98 +2007-06-06,28.05,28.11,27.30,27.44,33508200,27.44 +2007-06-05,28.40,28.59,28.10,28.23,20494800,28.23 +2007-06-04,28.60,28.78,28.40,28.59,13428800,28.59 +2007-06-01,28.90,29.13,28.61,28.78,12398800,28.78 +2007-05-31,28.76,28.85,28.49,28.70,15859100,28.70 +2007-05-30,28.19,28.38,28.00,28.38,16046800,28.38 +2007-05-29,28.36,28.73,28.20,28.40,13981500,28.40 +2007-05-25,28.44,28.73,28.34,28.58,10334600,28.58 +2007-05-24,28.65,28.88,28.25,28.41,19122900,28.41 +2007-05-23,29.10,29.37,28.53,28.61,27964400,28.61 +2007-05-22,29.33,29.35,28.78,28.92,19131300,28.92 +2007-05-21,29.62,29.86,29.32,29.35,18955900,29.35 +2007-05-18,28.90,29.80,28.78,29.75,35487200,29.75 +2007-05-17,28.99,29.13,28.49,28.57,23535000,28.57 +2007-05-16,28.89,29.37,28.25,29.21,32944800,29.21 +2007-05-15,29.16,29.42,28.75,28.81,22226800,28.81 +2007-05-14,29.79,30.00,29.08,29.31,20895900,29.31 +2007-05-11,29.62,30.08,29.53,30.05,13838800,30.05 +2007-05-10,30.52,30.69,29.61,29.70,26570200,29.70 +2007-05-09,30.17,30.44,29.95,30.22,23533100,30.22 +2007-05-08,30.24,31.10,30.21,30.41,28018200,30.41 +2007-05-07,30.13,30.98,29.86,30.38,41243900,30.38 +2007-05-04,33.27,33.61,29.58,30.98,245611400,30.98 +2007-05-03,28.25,28.50,28.01,28.18,20119500,28.18 +2007-05-02,27.72,28.26,27.72,28.12,16911800,28.12 +2007-05-01,28.25,28.35,27.53,27.73,18310900,27.73 +2007-04-30,28.32,28.50,28.00,28.04,17596300,28.04 +2007-04-27,28.35,28.86,28.17,28.34,21097000,28.34 +2007-04-26,27.98,28.65,27.73,28.49,32331000,28.49 +2007-04-25,28.22,28.27,27.68,28.06,35568600,28.06 +2007-04-24,28.03,28.26,27.69,28.02,25964000,28.02 +2007-04-23,27.53,28.14,27.37,27.88,27262400,27.88 +2007-04-20,27.86,27.86,27.37,27.46,39123300,27.46 +2007-04-19,28.10,28.23,27.46,27.51,45664700,27.51 +2007-04-18,28.42,28.90,27.89,28.31,127875300,28.31 +2007-04-17,31.98,32.14,31.71,32.09,43223800,32.09 +2007-04-16,31.68,31.79,31.24,31.61,14359100,31.61 +2007-04-13,31.15,31.50,30.96,31.41,12006300,31.41 +2007-04-12,31.26,31.42,31.10,31.21,13904800,31.21 +2007-04-11,31.65,31.73,30.90,31.17,16141100,31.17 +2007-04-10,31.64,32.02,31.60,31.69,12797600,31.69 +2007-04-09,32.01,32.24,31.60,31.64,12408000,31.64 +2007-04-05,32.00,32.09,31.72,31.96,13878100,31.96 +2007-04-04,31.61,31.87,31.48,31.62,7836200,31.62 +2007-04-03,31.41,32.00,31.41,31.72,12324600,31.72 +2007-04-02,31.22,31.40,30.93,31.28,8668800,31.28 +2007-03-30,31.21,31.60,31.02,31.29,9425000,31.29 +2007-03-29,31.71,31.73,30.83,31.34,13815000,31.34 +2007-03-28,31.45,31.70,31.25,31.41,13162500,31.41 +2007-03-27,31.56,31.66,31.24,31.55,9403100,31.55 +2007-03-26,31.25,31.74,31.24,31.66,12907000,31.66 +2007-03-23,31.33,31.70,31.16,31.36,12727900,31.36 +2007-03-22,31.36,31.44,30.85,31.26,12989800,31.26 +2007-03-21,30.33,31.39,30.21,31.29,26667300,31.29 +2007-03-20,30.00,30.35,29.94,30.33,12203800,30.33 +2007-03-19,30.00,30.19,29.92,30.03,9983800,30.03 +2007-03-16,30.02,30.11,29.72,29.88,19799300,29.88 +2007-03-15,29.81,30.07,29.78,30.06,15440900,30.06 +2007-03-14,29.63,30.04,29.26,29.86,23604900,29.86 +2007-03-13,29.77,30.24,29.42,29.56,18263800,29.56 +2007-03-12,29.30,30.11,29.29,29.99,35991600,29.99 +2007-03-09,29.85,30.15,28.79,29.12,72749900,29.12 +2007-03-08,30.82,31.04,30.58,30.71,13715100,30.71 +2007-03-07,30.95,31.03,30.33,30.39,16014300,30.39 +2007-03-06,30.89,31.06,30.52,30.80,33472600,30.80 +2007-03-05,30.18,31.90,30.14,30.31,21469000,30.31 +2007-03-02,30.54,30.89,30.28,30.42,18136600,30.42 +2007-03-01,30.13,31.23,30.00,30.86,24012900,30.86 +2007-02-28,30.86,31.47,30.09,30.86,30487800,30.86 +2007-02-27,31.38,31.64,30.24,30.95,31505200,30.95 +2007-02-26,32.80,32.84,30.85,32.11,28295200,32.11 +2007-02-23,31.60,32.18,31.41,32.10,21533500,32.10 +2007-02-22,31.60,32.08,31.32,31.60,15485100,31.60 +2007-02-21,31.74,31.77,31.22,31.65,27999200,31.65 +2007-02-20,31.80,32.21,31.39,32.01,20026500,32.01 +2007-02-16,31.00,32.00,31.00,31.91,36774800,31.91 +2007-02-15,30.82,31.65,30.69,31.25,28160300,31.25 +2007-02-14,29.69,30.86,29.64,30.66,30821100,30.66 +2007-02-13,29.37,29.68,29.26,29.56,12802300,29.56 +2007-02-12,29.29,29.77,29.05,29.17,18316200,29.17 +2007-02-09,30.07,30.16,29.51,29.74,18172200,29.74 +2007-02-08,29.75,30.24,29.73,30.08,15561700,30.08 +2007-02-07,29.35,30.15,29.12,29.89,29162600,29.89 +2007-02-06,28.61,29.56,28.60,29.35,24506800,29.35 +2007-02-05,28.67,28.80,28.36,28.56,11163300,28.56 +2007-02-02,28.57,28.92,28.45,28.77,16483100,28.77 +2007-02-01,28.68,28.71,28.15,28.35,17905200,28.35 +2007-01-31,28.04,28.48,27.82,28.31,14100300,28.31 +2007-01-30,27.87,28.39,27.61,28.04,13576600,28.04 +2007-01-29,28.05,28.21,27.73,27.87,16859000,27.87 +2007-01-26,28.33,28.52,27.96,28.04,21334800,28.04 +2007-01-25,28.68,29.05,28.13,28.21,28356200,28.21 +2007-01-24,28.34,29.20,28.22,28.94,81017500,28.94 +2007-01-23,27.42,27.54,26.88,26.96,43728100,26.96 +2007-01-22,27.85,27.90,27.18,27.42,23199800,27.42 +2007-01-19,27.93,28.34,27.55,27.64,24757700,27.64 +2007-01-18,28.92,28.99,27.82,28.12,23869400,28.12 +2007-01-17,29.40,29.40,28.81,29.05,17796100,29.05 +2007-01-16,29.88,29.88,28.79,29.29,24448400,29.29 +2007-01-12,28.98,29.50,28.49,29.45,20971100,29.45 +2007-01-11,28.76,29.37,28.70,29.20,28457500,29.20 +2007-01-10,27.48,28.92,27.44,28.70,40240000,28.70 +2007-01-09,28.00,28.05,27.41,27.58,25621500,27.58 +2007-01-08,27.70,28.04,27.43,27.92,25713700,27.92 +2007-01-05,26.70,27.87,26.66,27.74,64264600,27.74 +2007-01-04,25.64,26.92,25.52,26.85,32512200,26.85 +2007-01-03,25.85,26.26,25.26,25.61,26352700,25.61 +2006-12-29,25.42,25.82,25.33,25.54,16297800,25.54 +2006-12-28,25.62,25.72,25.30,25.36,11908400,25.36 +2006-12-27,25.47,25.88,25.45,25.75,12421800,25.75 +2006-12-26,25.49,25.61,25.34,25.45,8400500,25.45 +2006-12-22,25.67,25.88,25.45,25.55,14666100,25.55 +2006-12-21,25.71,25.75,25.13,25.48,27050600,25.48 +2006-12-20,26.24,26.31,25.54,25.59,24905600,25.59 +2006-12-19,26.05,26.50,25.91,26.41,18973800,26.41 +2006-12-18,26.89,26.97,26.07,26.30,19431200,26.30 +2006-12-15,27.00,27.22,26.76,26.90,27227300,26.90 +2006-12-14,26.63,26.97,26.50,26.87,14400300,26.87 +2006-12-13,27.05,27.23,26.51,26.60,20428600,26.60 +2006-12-12,26.63,27.38,26.60,26.75,31971600,26.75 +2006-12-11,26.37,26.70,26.12,26.49,12916900,26.49 +2006-12-08,26.65,26.78,26.27,26.34,19262200,26.34 +2006-12-07,26.95,27.16,26.60,26.63,22407000,26.63 +2006-12-06,27.25,27.45,26.60,26.86,35202800,26.86 +2006-12-05,26.87,27.61,26.86,27.43,27118200,27.43 +2006-12-04,26.49,27.30,26.49,26.89,28012700,26.89 +2006-12-01,27.00,27.25,26.00,26.49,20055800,26.49 +2006-11-30,27.00,27.15,26.73,27.01,14916300,27.01 +2006-11-29,27.40,27.40,26.71,27.04,19375100,27.04 +2006-11-28,27.03,27.24,26.85,27.00,14940800,27.00 +2006-11-27,27.50,28.50,27.17,27.27,19922300,27.27 +2006-11-24,28.22,28.49,27.70,28.03,9384400,28.03 +2006-11-22,27.51,28.56,27.29,28.49,32055800,28.49 +2006-11-21,26.50,27.34,26.50,27.14,21138300,27.14 +2006-11-20,26.96,27.04,26.63,26.72,20272000,26.72 +2006-11-17,26.68,27.05,26.63,26.91,17955200,26.91 +2006-11-16,27.31,27.33,26.20,26.64,38508500,26.64 +2006-11-15,27.18,27.50,27.03,27.15,22112700,27.15 +2006-11-14,27.40,27.50,27.11,27.24,20145700,27.24 +2006-11-13,27.17,27.62,27.15,27.40,16876500,27.40 +2006-11-10,27.40,27.50,27.03,27.39,21366600,27.39 +2006-11-09,27.18,27.65,26.96,27.45,27428600,27.45 +2006-11-08,26.36,27.25,26.31,26.90,23384800,26.90 +2006-11-07,26.69,27.15,26.58,26.61,28442700,26.61 +2006-11-06,26.34,26.70,26.10,26.59,22563600,26.59 +2006-11-03,26.63,26.70,26.04,26.18,15313800,26.18 +2006-11-02,25.94,26.60,25.77,26.53,34824500,26.53 +2006-11-01,26.50,26.62,25.82,25.99,26300200,25.99 +2006-10-31,26.44,26.70,26.10,26.34,33492800,26.34 +2006-10-30,25.87,26.40,25.66,25.95,35295800,25.95 +2006-10-27,25.23,25.60,24.90,25.34,29647200,25.34 +2006-10-26,24.70,25.33,24.36,25.28,38435800,25.28 +2006-10-25,23.73,24.64,23.69,24.49,40110600,24.49 +2006-10-24,23.35,23.64,23.15,23.53,31704000,23.53 +2006-10-23,23.14,23.50,23.10,23.37,26301200,23.37 +2006-10-20,23.22,23.27,22.65,23.21,49795600,23.21 +2006-10-19,23.02,23.59,23.00,23.14,42280400,23.14 +2006-10-18,24.57,24.75,22.88,22.99,111660900,22.99 +2006-10-17,23.74,24.35,23.68,24.15,67417200,24.15 +2006-10-16,24.34,24.52,23.75,24.18,36496400,24.18 +2006-10-13,23.90,24.50,23.57,24.42,51338900,24.42 +2006-10-12,24.32,24.38,24.10,24.12,25824500,24.12 +2006-10-11,24.29,24.64,23.80,24.24,39356300,24.24 +2006-10-10,24.94,25.03,24.32,24.47,30371900,24.47 +2006-10-09,25.45,25.72,25.00,25.03,15729500,25.03 +2006-10-06,25.09,25.50,25.01,25.47,20847000,25.47 +2006-10-05,25.16,25.25,24.88,25.18,17634000,25.18 +2006-10-04,24.89,25.26,24.74,25.21,21717900,25.21 +2006-10-03,24.81,25.00,24.70,24.84,21148300,24.84 +2006-10-02,25.45,25.46,24.75,24.88,19641300,24.88 +2006-09-29,25.50,25.59,25.24,25.28,18982600,25.28 +2006-09-28,24.87,25.50,24.84,25.33,35331200,25.33 +2006-09-27,25.00,25.01,24.60,24.65,29835900,24.65 +2006-09-26,25.44,25.48,24.81,25.05,34950100,25.05 +2006-09-25,25.64,25.87,25.20,25.29,19992400,25.29 +2006-09-22,25.34,25.69,25.18,25.52,20667400,25.52 +2006-09-21,25.53,25.95,25.21,25.34,28584500,25.34 +2006-09-20,26.04,26.09,25.38,25.64,55636600,25.64 +2006-09-19,29.09,29.13,25.10,25.75,127718600,25.75 +2006-09-18,29.37,29.39,28.58,29.00,15685000,29.00 +2006-09-15,29.30,29.57,29.22,29.32,19550300,29.32 +2006-09-14,29.10,29.24,28.89,29.03,9565500,29.03 +2006-09-13,29.06,29.37,28.80,29.17,15248400,29.17 +2006-09-12,28.55,29.22,28.46,29.09,10005000,29.09 +2006-09-11,28.05,28.73,27.67,28.61,12936000,28.61 +2006-09-08,28.04,28.32,27.97,28.14,9781800,28.14 +2006-09-07,28.40,28.51,27.82,27.86,18434400,27.86 +2006-09-06,28.94,29.01,28.49,28.50,12800600,28.50 +2006-09-05,29.45,29.48,28.95,29.07,11425600,29.07 +2006-09-01,28.91,29.53,28.91,29.49,11573600,29.49 +2006-08-31,28.99,29.02,28.59,28.83,8879300,28.83 +2006-08-30,29.00,29.14,28.71,29.02,13119300,29.02 +2006-08-29,28.86,29.01,28.51,28.96,9888800,28.96 +2006-08-28,28.75,29.25,28.70,28.91,10404700,28.91 +2006-08-25,28.95,29.28,28.74,28.77,6203800,28.77 +2006-08-24,28.75,29.13,28.70,28.99,8983600,28.99 +2006-08-23,29.34,29.47,28.68,28.70,8837400,28.70 +2006-08-22,28.84,29.65,28.80,29.26,10891800,29.26 +2006-08-21,29.22,29.52,28.83,28.90,11575200,28.90 +2006-08-18,28.90,29.97,28.77,29.78,19611300,29.78 +2006-08-17,28.38,29.32,28.34,28.91,17251600,28.91 +2006-08-16,28.35,28.46,27.97,28.39,12589400,28.39 +2006-08-15,27.58,28.20,27.48,28.17,15298500,28.17 +2006-08-14,27.71,27.80,27.00,27.26,10640100,27.26 +2006-08-11,27.52,27.72,27.40,27.50,9252200,27.50 +2006-08-10,26.95,27.80,26.85,27.49,12597900,27.49 +2006-08-09,27.75,27.85,27.00,27.22,14736100,27.22 +2006-08-08,26.95,27.70,26.63,27.44,19332800,27.44 +2006-08-07,26.92,27.11,26.58,27.08,12847200,27.08 +2006-08-04,27.20,27.58,26.83,26.99,11607900,26.99 +2006-08-03,26.50,27.05,26.40,26.90,15468500,26.90 +2006-08-02,27.01,27.10,26.45,26.63,18116200,26.63 +2006-08-01,27.06,27.12,26.74,26.94,18613100,26.94 +2006-07-31,27.46,27.55,26.99,27.14,16492600,27.14 +2006-07-28,26.90,27.50,26.33,27.47,21584800,27.47 +2006-07-27,27.35,27.50,26.64,26.70,25153000,26.70 +2006-07-26,26.78,27.51,26.57,27.08,20073800,27.08 +2006-07-25,26.75,27.19,26.57,26.95,21388800,26.95 +2006-07-24,26.24,27.23,25.89,26.94,42631300,26.94 +2006-07-21,24.99,26.06,24.91,25.89,36187100,25.89 +2006-07-20,25.55,26.21,24.91,25.27,54659700,25.27 +2006-07-19,26.41,26.70,25.04,25.20,204339000,25.20 +2006-07-18,32.08,32.26,31.25,32.24,39767700,32.24 +2006-07-17,31.98,32.40,31.69,31.84,16369600,31.84 +2006-07-14,32.34,32.48,31.85,32.08,12484700,32.08 +2006-07-13,32.85,33.16,32.07,32.23,19463500,32.23 +2006-07-12,33.03,33.74,32.99,33.38,18708400,33.38 +2006-07-11,32.79,33.35,32.32,33.17,11285900,33.17 +2006-07-10,32.91,33.14,32.73,32.85,15317600,32.85 +2006-07-07,32.94,33.05,32.37,32.50,12372500,32.50 +2006-07-06,32.77,33.22,32.70,33.11,13801500,33.11 +2006-07-05,32.85,32.99,32.33,32.47,13453900,32.47 +2006-07-03,32.90,33.44,32.90,33.30,8067100,33.30 +2006-06-30,33.01,33.12,32.54,33.00,22566600,33.00 +2006-06-29,32.26,33.00,32.20,32.97,15745900,32.97 +2006-06-28,31.75,32.17,31.70,31.92,14032800,31.92 +2006-06-27,31.85,32.22,31.32,31.51,16589400,31.51 +2006-06-26,31.45,31.70,31.16,31.55,11457000,31.55 +2006-06-23,31.08,31.76,30.82,31.37,17378500,31.37 +2006-06-22,30.85,31.16,30.44,30.68,11500300,30.68 +2006-06-21,30.77,31.54,30.65,31.06,18252900,31.06 +2006-06-20,30.42,30.65,30.10,30.60,12613200,30.60 +2006-06-19,30.51,30.75,30.06,30.35,12236700,30.35 +2006-06-16,30.70,30.86,30.15,30.36,12951700,30.36 +2006-06-15,29.98,30.96,29.72,30.79,22375000,30.79 +2006-06-14,29.81,30.00,29.25,29.62,19257500,29.62 +2006-06-13,29.77,30.20,29.51,29.65,16435700,29.65 +2006-06-12,30.37,30.65,29.66,29.78,14344600,29.78 +2006-06-09,30.70,30.80,30.23,30.37,10044700,30.37 +2006-06-08,30.43,30.99,29.83,30.45,20538600,30.45 +2006-06-07,30.80,31.25,30.36,30.54,17470100,30.54 +2006-06-06,30.83,30.97,30.35,30.70,15615600,30.70 +2006-06-05,31.19,31.43,30.79,30.82,17188500,30.82 +2006-06-02,32.11,32.19,31.30,31.52,16470900,31.52 +2006-06-01,31.83,32.00,31.49,31.99,16652400,31.99 +2006-05-31,32.19,32.32,31.11,31.59,21306700,31.59 +2006-05-30,32.73,32.89,31.79,32.00,16247600,32.00 +2006-05-26,32.86,33.02,32.35,33.02,13842600,33.02 +2006-05-25,32.94,33.50,32.50,32.92,34732700,32.92 +2006-05-24,30.95,32.02,30.71,31.79,27286300,31.79 +2006-05-23,31.04,31.63,30.76,30.76,28583400,30.76 +2006-05-22,30.42,30.98,29.89,30.46,35089300,30.46 +2006-05-19,29.05,29.75,28.60,29.53,33121900,29.53 +2006-05-18,30.10,30.36,28.93,29.00,38254000,29.00 +2006-05-17,30.61,31.26,30.04,30.11,39847500,30.11 +2006-05-16,31.10,31.22,30.63,30.97,15333700,30.97 +2006-05-15,30.85,31.25,30.60,31.03,13350700,31.03 +2006-05-12,30.71,31.18,30.38,30.81,16745600,30.81 +2006-05-11,31.96,32.17,30.87,30.99,24277000,30.99 +2006-05-10,32.48,32.56,32.00,32.09,13797500,32.09 +2006-05-09,32.68,34.00,32.35,32.49,13396400,32.49 +2006-05-08,33.09,33.43,32.63,32.87,18188200,32.87 +2006-05-05,32.63,32.75,32.22,32.66,14689200,32.66 +2006-05-04,32.40,32.56,32.08,32.19,10402300,32.19 +2006-05-03,32.40,33.00,31.75,32.17,23292600,32.17 +2006-05-02,32.20,32.91,31.72,31.85,16276000,31.85 +2006-05-01,32.99,33.10,31.86,32.08,19752200,32.08 +2006-04-28,32.88,33.45,32.78,32.78,13283500,32.78 +2006-04-27,32.79,33.50,32.40,33.20,19635700,33.20 +2006-04-26,32.30,33.09,32.10,33.00,24426400,33.00 +2006-04-25,32.99,33.06,31.88,31.99,22363200,31.99 +2006-04-24,33.01,33.45,32.90,33.01,15441600,33.01 +2006-04-21,33.36,34.09,32.70,32.89,25215000,32.89 +2006-04-20,33.48,33.70,32.93,33.37,23403900,33.37 +2006-04-19,33.47,33.98,32.76,33.54,77253600,33.54 +2006-04-18,31.17,31.38,30.53,31.30,38604500,31.30 +2006-04-17,31.16,31.79,30.66,30.97,18239900,30.97 +2006-04-13,31.14,31.40,30.85,31.13,15609800,31.13 +2006-04-12,31.44,31.50,30.89,31.10,14926900,31.10 +2006-04-11,32.45,32.60,31.15,31.39,22105600,31.39 +2006-04-10,32.28,32.63,32.12,32.55,9618000,32.55 +2006-04-07,32.85,32.97,32.21,32.27,12980200,32.27 +2006-04-06,32.12,33.14,32.11,32.79,21572600,32.79 +2006-04-05,32.30,32.50,31.96,32.11,11982500,32.11 +2006-04-04,31.69,32.25,31.66,32.10,16232700,32.10 +2006-04-03,32.41,32.53,31.79,31.89,14887900,31.89 +2006-03-31,32.45,32.63,32.01,32.26,12677300,32.26 +2006-03-30,32.75,32.83,32.09,32.42,14314000,32.42 +2006-03-29,32.44,32.91,32.14,32.56,25508200,32.56 +2006-03-28,31.45,32.50,31.41,32.39,25981500,32.39 +2006-03-27,31.84,32.08,31.30,31.45,14858500,31.45 +2006-03-24,32.28,32.31,31.53,31.77,17816500,31.77 +2006-03-23,31.52,31.95,31.48,31.83,33834000,31.83 +2006-03-22,30.33,30.91,30.31,30.75,23147400,30.75 +2006-03-21,30.11,30.78,30.02,30.11,18876400,30.11 +2006-03-20,30.38,30.93,30.20,30.44,21455200,30.44 +2006-03-17,30.35,30.36,29.83,30.07,23629700,30.07 +2006-03-16,30.77,30.88,30.10,30.13,17108000,30.13 +2006-03-15,31.25,31.28,30.47,30.53,20758000,30.53 +2006-03-14,30.10,31.00,30.10,30.99,19294700,30.99 +2006-03-13,30.72,30.97,30.12,30.15,18437700,30.15 +2006-03-10,30.40,31.10,29.75,30.58,28991400,30.58 +2006-03-09,31.05,31.32,30.25,30.28,18277000,30.28 +2006-03-08,31.31,31.55,30.82,30.99,20910200,30.99 +2006-03-07,31.42,32.20,31.31,31.43,23365100,31.43 +2006-03-06,31.53,31.94,31.45,31.57,17211200,31.57 +2006-03-03,31.70,32.07,31.38,31.45,23196000,31.45 +2006-03-02,32.01,32.11,31.58,31.70,23487300,31.70 +2006-03-01,32.21,32.42,31.72,32.18,18466100,32.18 +2006-02-28,32.63,32.98,31.34,32.06,39926200,32.06 +2006-02-27,33.11,33.21,32.57,32.74,11821900,32.74 +2006-02-24,33.20,33.34,32.92,33.01,10136400,33.01 +2006-02-23,33.01,33.66,32.88,33.15,14947600,33.15 +2006-02-22,32.49,33.34,32.40,33.16,18433500,33.16 +2006-02-21,32.90,33.07,32.38,32.39,14328100,32.39 +2006-02-17,32.88,33.14,32.71,32.76,12620200,32.76 +2006-02-16,33.30,33.40,32.60,32.75,19500100,32.75 +2006-02-15,32.62,33.33,32.55,33.02,19542100,33.02 +2006-02-14,32.14,32.83,32.05,32.72,26198600,32.72 +2006-02-13,32.21,32.44,31.70,32.04,26139300,32.04 +2006-02-10,32.58,32.60,32.10,32.51,19628600,32.51 +2006-02-09,33.01,33.36,32.40,32.50,25335200,32.50 +2006-02-08,33.24,33.40,32.51,33.00,28112900,33.00 +2006-02-07,33.01,33.10,32.32,33.02,37236800,33.02 +2006-02-06,33.90,33.95,32.78,32.92,23523100,32.92 +2006-02-03,34.00,34.05,33.26,33.54,32639600,33.54 +2006-02-02,35.01,35.10,34.10,34.25,18323500,34.25 +2006-02-01,34.45,35.00,34.35,35.00,43600400,35.00 +2006-01-31,35.20,35.20,34.31,34.38,36538000,34.38 +2006-01-30,35.09,35.23,34.88,35.05,29030600,35.05 +2006-01-27,35.26,35.27,34.66,35.09,24317400,35.09 +2006-01-26,34.94,35.25,34.49,35.17,28471400,35.17 +2006-01-25,35.43,35.48,34.38,34.49,23779200,34.49 +2006-01-24,34.55,35.20,34.51,34.87,31667800,34.87 +2006-01-23,34.22,34.40,33.98,34.17,30887600,34.17 +2006-01-20,34.44,34.66,33.21,33.74,57644600,33.74 +2006-01-19,35.82,35.84,34.24,34.33,60913000,34.33 +2006-01-18,35.01,36.16,34.74,35.18,118556100,35.18 +2006-01-17,39.09,40.39,38.96,40.11,41797000,40.11 +2006-01-13,41.00,41.08,39.62,39.90,30960800,39.90 +2006-01-12,41.92,41.99,40.76,40.89,18921700,40.89 +2006-01-11,42.19,42.31,41.72,41.87,26191400,41.87 +2006-01-10,42.96,43.34,42.34,42.98,16287200,42.98 +2006-01-09,43.10,43.66,42.82,43.42,16266900,43.42 +2006-01-06,42.88,43.57,42.80,43.21,29418400,43.21 +2006-01-05,40.93,41.73,40.85,41.53,12829100,41.53 +2006-01-04,41.22,41.90,40.77,40.97,20549000,40.97 +2006-01-03,39.69,41.22,38.79,40.91,24227700,40.91 +2005-12-30,39.40,39.56,39.05,39.18,12233000,39.18 +2005-12-29,40.25,40.35,39.41,39.56,10116600,39.56 +2005-12-28,40.10,40.48,39.77,40.25,11567900,40.25 +2005-12-27,40.65,40.94,39.85,39.94,11672900,39.94 +2005-12-23,41.09,41.10,40.45,40.63,5070200,40.63 +2005-12-22,40.69,41.68,40.55,40.83,9548300,40.83 +2005-12-21,40.52,41.05,40.35,40.47,11626900,40.47 +2005-12-20,41.26,41.36,40.48,40.68,15269500,40.68 +2005-12-19,42.16,42.89,40.88,41.05,18563700,41.05 +2005-12-16,41.86,42.67,41.75,42.32,21805000,42.32 +2005-12-15,41.23,41.84,41.14,41.75,20900800,41.75 +2005-12-14,41.12,41.68,40.84,41.30,23034200,41.30 +2005-12-13,40.01,41.40,40.00,41.20,17264700,41.20 +2005-12-12,40.41,40.54,39.81,40.08,9776300,40.08 +2005-12-09,40.50,40.87,40.20,40.31,11116900,40.31 +2005-12-08,40.25,40.54,39.95,40.35,12851600,40.35 +2005-12-07,40.31,40.63,39.57,40.11,15644900,40.11 +2005-12-06,40.78,41.18,40.12,40.19,16356800,40.19 +2005-12-05,40.88,41.03,40.37,40.47,15389400,40.47 +2005-12-02,41.22,41.85,40.89,41.21,14411400,41.21 +2005-12-01,40.74,41.25,40.54,41.07,20069600,41.07 +2005-11-30,39.38,40.84,39.09,40.23,31608700,40.23 +2005-11-29,41.01,41.59,39.82,40.19,28698200,40.19 +2005-11-28,41.63,41.77,40.66,41.11,23190900,41.11 +2005-11-25,42.71,42.84,41.94,42.13,8253000,42.13 +2005-11-23,42.21,43.45,42.17,42.50,21471000,42.50 +2005-11-22,41.73,42.65,41.65,42.36,26389500,42.36 +2005-11-21,41.26,42.98,41.21,42.27,27915500,42.27 +2005-11-18,42.04,42.41,41.29,41.54,30747600,41.54 +2005-11-17,40.32,42.50,40.03,42.23,44796000,42.23 +2005-11-16,37.90,40.07,37.86,40.04,39464600,40.04 +2005-11-15,38.26,38.61,37.54,37.65,11981600,37.65 +2005-11-14,38.43,38.72,37.96,38.45,10112500,38.45 +2005-11-11,38.69,39.05,38.34,38.49,12234400,38.49 +2005-11-10,37.52,38.75,37.52,38.69,13722400,38.69 +2005-11-09,37.76,38.04,37.43,37.75,12217600,37.75 +2005-11-08,37.75,38.50,37.60,37.97,14434400,37.97 +2005-11-07,37.69,38.18,37.41,37.90,11652700,37.90 +2005-11-04,37.59,37.99,37.37,37.87,11656100,37.87 +2005-11-03,38.26,38.28,37.33,37.45,16880800,37.45 +2005-11-02,37.49,38.04,37.43,37.99,17886200,37.99 +2005-11-01,36.62,38.71,36.59,37.72,41932100,37.72 +2005-10-31,35.60,37.27,35.60,36.97,24867100,36.97 +2005-10-28,35.62,35.92,35.25,35.58,14123800,35.58 +2005-10-27,35.34,35.66,35.30,35.45,11605000,35.45 +2005-10-26,35.06,35.75,34.97,35.46,17125600,35.46 +2005-10-25,35.19,35.38,34.89,35.12,14441100,35.12 +2005-10-24,35.30,35.49,34.94,35.28,19591900,35.28 +2005-10-21,35.99,36.33,35.19,35.29,28423400,35.29 +2005-10-20,35.90,36.94,35.05,35.26,29267000,35.26 +2005-10-19,34.62,35.94,34.59,35.91,63254000,35.91 +2005-10-18,34.40,34.76,33.64,33.70,35010300,33.70 +2005-10-17,33.85,34.30,33.80,34.16,21994600,34.16 +2005-10-14,33.62,33.62,32.77,33.52,17425200,33.52 +2005-10-13,33.80,33.85,32.97,33.37,16254600,33.37 +2005-10-12,33.99,34.71,33.91,33.93,16089600,33.93 +2005-10-11,34.55,34.84,33.66,34.10,16504700,34.10 +2005-10-10,34.20,34.90,34.12,34.53,15227800,34.53 +2005-10-07,34.03,34.29,33.97,34.16,12253200,34.16 +2005-10-06,33.95,34.30,33.54,33.80,21836100,33.80 +2005-10-05,33.79,33.93,33.36,33.49,14642000,33.49 +2005-10-04,33.75,34.37,33.51,33.57,14331000,33.57 +2005-10-03,33.80,34.12,33.71,33.77,13184500,33.77 +2005-09-30,33.59,34.10,33.56,33.84,15697000,33.84 +2005-09-29,32.40,33.70,32.12,33.46,22209100,33.46 +2005-09-28,32.67,32.80,32.27,32.35,11622800,32.35 +2005-09-27,32.17,32.61,32.17,32.48,12246900,32.48 +2005-09-26,32.48,32.55,31.99,32.18,13548200,32.18 +2005-09-23,32.12,32.25,31.75,32.13,14903700,32.13 +2005-09-22,32.09,32.41,31.76,32.04,18259400,32.04 +2005-09-21,32.53,33.10,31.60,31.97,21896000,31.97 +2005-09-20,32.88,33.11,32.36,32.64,14578900,32.64 +2005-09-19,33.27,33.47,32.25,32.75,15429900,32.75 +2005-09-16,33.74,33.77,33.05,33.17,20858300,33.17 +2005-09-15,33.95,33.99,33.50,33.57,10404800,33.57 +2005-09-14,34.30,34.50,33.64,33.80,15017400,33.80 +2005-09-13,33.93,34.71,33.73,34.30,19346600,34.30 +2005-09-12,33.42,34.34,33.41,33.91,18580300,33.91 +2005-09-09,33.35,33.60,33.02,33.46,15247900,33.46 +2005-09-08,33.74,33.93,33.20,33.34,17464400,33.34 +2005-09-07,33.50,34.26,33.30,34.06,12545300,34.06 +2005-09-06,33.18,33.78,33.18,33.68,12513300,33.68 +2005-09-02,33.20,33.37,33.10,33.17,6849000,33.17 +2005-09-01,33.28,33.51,33.04,33.24,11848500,33.24 +2005-08-31,33.23,33.39,32.99,33.32,13035500,33.32 +2005-08-30,33.50,33.67,33.00,33.18,13496000,33.18 +2005-08-29,33.40,33.78,33.31,33.68,11427600,33.68 +2005-08-26,33.51,33.81,33.38,33.57,9833400,33.57 +2005-08-25,33.54,33.62,33.20,33.48,12564900,33.48 +2005-08-24,32.92,33.68,32.88,33.47,23249500,33.47 +2005-08-23,33.29,33.33,32.65,33.11,16912700,33.11 +2005-08-22,34.07,34.10,33.07,33.20,21054400,33.20 +2005-08-19,34.39,34.47,33.98,34.00,12810400,34.00 +2005-08-18,34.13,34.73,34.12,34.36,12154200,34.36 +2005-08-17,34.30,34.73,34.23,34.39,10443700,34.39 +2005-08-16,34.57,34.66,34.21,34.23,11867100,34.23 +2005-08-15,34.80,34.87,34.49,34.60,11244500,34.60 +2005-08-12,34.86,34.88,34.45,34.60,13306100,34.60 +2005-08-11,34.54,35.00,34.32,34.94,22391900,34.94 +2005-08-10,34.28,34.77,34.00,34.19,18047900,34.19 +2005-08-09,34.15,34.32,33.91,34.06,9987400,34.06 +2005-08-08,33.86,34.18,33.66,33.94,13066200,33.94 +2005-08-05,34.09,34.28,33.49,33.52,11873800,33.52 +2005-08-04,34.26,34.60,34.00,34.06,11143400,34.06 +2005-08-03,33.75,34.68,33.73,34.51,18240600,34.51 +2005-08-02,33.46,34.20,33.39,33.88,17581900,33.88 +2005-08-01,33.63,33.69,33.31,33.33,12637100,33.33 +2005-07-29,34.01,34.06,33.34,33.34,16236100,33.34 +2005-07-28,34.23,34.31,33.98,34.01,11871600,34.01 +2005-07-27,34.22,34.37,33.95,34.29,20497500,34.29 +2005-07-26,34.05,34.30,33.91,34.15,16819200,34.15 +2005-07-25,33.88,34.08,33.59,33.85,23252600,33.85 +2005-07-22,33.35,33.77,33.17,33.53,27561500,33.53 +2005-07-21,33.75,33.76,32.75,32.94,37778500,32.94 +2005-07-20,34.21,34.35,33.31,33.40,82623300,33.40 +2005-07-19,37.02,38.02,36.56,37.73,32685500,37.73 +2005-07-18,36.45,36.78,36.37,36.58,11019300,36.58 +2005-07-15,37.05,37.16,36.50,36.58,12372200,36.58 +2005-07-14,37.40,37.50,36.77,36.86,14722200,36.86 +2005-07-13,36.42,36.98,36.41,36.73,16897500,36.73 +2005-07-12,36.20,36.49,35.94,36.23,19665800,36.23 +2005-07-11,34.90,35.81,34.78,35.76,20233000,35.76 +2005-07-08,34.77,34.87,34.25,34.62,15515400,34.62 +2005-07-07,33.87,34.77,33.72,34.63,16354300,34.63 +2005-07-06,34.64,34.97,34.03,34.12,13585700,34.12 +2005-07-05,34.25,35.08,34.20,34.60,16086700,34.60 +2005-07-01,34.76,34.85,34.22,34.44,9861600,34.44 +2005-06-30,34.84,35.17,34.44,34.65,16699500,34.65 +2005-06-29,35.80,35.94,34.88,34.94,16481900,34.94 +2005-06-28,35.95,36.24,35.51,35.80,13346200,35.80 +2005-06-27,35.88,36.11,35.20,35.68,12044700,35.68 +2005-06-24,36.26,36.40,35.60,36.09,13468200,36.09 +2005-06-23,36.85,37.31,36.20,36.20,15547700,36.20 +2005-06-22,36.91,37.32,36.84,36.90,12148100,36.90 +2005-06-21,36.37,37.31,36.36,36.95,16219200,36.95 +2005-06-20,35.96,36.84,35.79,36.45,12753200,36.45 +2005-06-17,36.76,36.98,36.12,36.30,15952800,36.30 +2005-06-16,36.46,36.74,36.22,36.40,12228700,36.40 +2005-06-15,36.97,37.11,35.91,36.32,22753900,36.32 +2005-06-14,36.56,37.05,36.43,36.80,12781200,36.80 +2005-06-13,36.66,37.51,36.53,36.90,11586300,36.90 +2005-06-10,37.48,37.50,36.32,36.81,14216900,36.81 +2005-06-09,36.81,37.48,36.38,37.45,18455100,37.45 +2005-06-08,37.42,37.45,36.32,36.63,20121100,36.63 +2005-06-07,38.72,38.95,37.32,37.44,22848300,37.44 +2005-06-06,37.79,38.74,37.75,38.52,12416000,38.52 +2005-06-03,38.24,38.79,37.60,37.92,12813300,37.92 +2005-06-02,38.20,38.71,38.13,38.50,13150700,38.50 +2005-06-01,37.31,38.90,37.17,38.42,28153800,38.42 +2005-05-31,37.03,37.35,36.85,37.20,12498300,37.20 +2005-05-27,36.98,37.47,36.95,37.27,10256600,37.27 +2005-05-26,36.45,37.19,36.35,37.14,15547700,37.14 +2005-05-25,36.25,36.42,36.06,36.27,14995100,36.27 +2005-05-24,36.87,37.10,36.45,36.63,17421300,36.63 +2005-05-23,36.10,37.10,36.04,36.80,21616200,36.80 +2005-05-20,36.60,36.64,36.13,36.33,13771900,36.33 +2005-05-19,36.13,36.99,36.11,36.75,21267100,36.75 +2005-05-18,35.79,36.58,35.69,35.95,23769000,35.95 +2005-05-17,35.20,35.80,35.14,35.68,13178400,35.68 +2005-05-16,34.78,35.50,34.74,35.45,15473900,35.45 +2005-05-13,34.71,35.35,34.35,34.82,15855900,34.82 +2005-05-12,34.95,35.37,34.54,34.71,18906700,34.71 +2005-05-11,34.09,34.88,33.69,34.88,19537100,34.88 +2005-05-10,34.30,34.37,33.86,34.06,13227000,34.06 +2005-05-09,34.48,34.65,34.25,34.59,9991700,34.59 +2005-05-06,35.00,35.08,34.45,34.52,14202200,34.52 +2005-05-05,35.10,35.29,34.43,34.71,16926300,34.71 +2005-05-04,34.43,35.50,34.38,35.18,23410900,35.18 +2005-05-03,34.05,34.60,33.90,34.28,22042800,34.28 +2005-05-02,34.44,34.85,34.03,34.38,13231500,34.38 +2005-04-29,34.60,34.75,33.92,34.50,15666100,34.50 +2005-04-28,34.70,34.93,34.02,34.33,16159300,34.33 +2005-04-27,34.70,35.14,34.59,34.95,14861300,34.95 +2005-04-26,35.12,35.42,34.80,35.00,17921200,35.00 +2005-04-25,34.58,35.59,34.58,35.49,23883600,35.49 +2005-04-22,35.21,35.88,34.50,34.87,31869800,34.87 +2005-04-21,35.12,35.91,34.71,35.87,27731600,35.87 +2005-04-20,34.96,35.25,34.36,34.65,50104400,34.65 +2005-04-19,32.96,33.33,32.42,33.22,34158500,33.22 +2005-04-18,32.43,33.09,32.40,32.55,19201200,32.55 +2005-04-15,32.96,33.41,32.29,32.46,27008500,32.46 +2005-04-14,33.63,34.20,33.40,33.46,19855300,33.46 +2005-04-13,34.16,34.46,33.40,33.60,16886100,33.60 +2005-04-12,34.35,34.50,33.74,34.28,22681900,34.28 +2005-04-11,34.97,35.09,34.54,34.60,11758500,34.60 +2005-04-08,35.04,35.14,34.65,34.76,11106300,34.76 +2005-04-07,34.45,35.25,34.45,35.07,20575000,35.07 +2005-04-06,35.14,35.42,34.12,34.49,23574000,34.49 +2005-04-05,35.15,35.40,34.84,35.15,20275900,35.15 +2005-04-04,34.34,35.27,33.75,35.07,27853300,35.07 +2005-04-01,34.18,34.77,34.15,34.28,27955400,34.28 +2005-03-31,33.55,34.20,33.20,33.90,25390000,33.90 +2005-03-30,32.31,33.60,32.27,33.48,28267900,33.48 +2005-03-29,32.18,32.84,31.79,32.16,23544700,32.16 +2005-03-28,32.21,32.50,32.10,32.25,20624400,32.25 +2005-03-24,31.94,32.09,31.41,31.41,23162000,31.41 +2005-03-23,30.91,31.33,30.85,30.87,13917100,30.87 +2005-03-22,31.70,31.98,30.86,30.99,19570600,30.99 +2005-03-21,31.29,31.77,30.98,31.62,18449400,31.62 +2005-03-18,31.53,31.73,30.91,31.11,20796400,31.11 +2005-03-17,31.80,31.98,31.54,31.61,13760200,31.61 +2005-03-16,31.87,32.35,31.40,31.58,17952000,31.58 +2005-03-15,31.61,32.28,31.53,31.94,20880800,31.94 +2005-03-14,31.74,31.83,30.65,31.32,19762000,31.32 +2005-03-11,31.86,32.21,31.65,31.65,13364800,31.65 +2005-03-10,32.43,32.56,31.60,31.91,19381200,31.91 +2005-03-09,33.01,33.15,32.01,32.32,21824400,32.32 +2005-03-08,33.55,33.73,33.14,33.16,17839300,33.16 +2005-03-07,32.40,33.31,32.36,33.09,17679200,33.09 +2005-03-04,32.36,32.57,31.76,32.36,17499800,32.36 +2005-03-03,32.25,32.48,31.80,32.31,17896100,32.31 +2005-03-02,32.07,32.60,31.75,32.23,15357200,32.23 +2005-03-01,32.37,32.67,32.05,32.30,20222500,32.30 +2005-02-28,31.74,33.77,31.62,32.27,25266400,32.27 +2005-02-25,31.53,31.96,31.43,31.73,20114900,31.73 +2005-02-24,30.43,31.49,30.30,31.48,55457300,31.48 +2005-02-23,32.82,32.92,31.40,32.12,34757100,32.12 +2005-02-22,33.25,33.82,32.66,32.79,18142600,32.79 +2005-02-18,33.84,33.98,33.38,33.60,12436100,33.60 +2005-02-17,34.42,34.79,33.76,33.82,16203500,33.82 +2005-02-16,33.81,34.82,33.75,34.42,22176200,34.42 +2005-02-15,34.34,34.92,33.81,33.98,20391900,33.98 +2005-02-14,34.01,34.41,33.78,34.33,20065300,34.33 +2005-02-11,33.45,34.70,33.31,34.15,20005800,34.15 +2005-02-10,33.72,33.72,32.47,33.44,32637400,33.44 +2005-02-09,34.60,34.66,33.45,33.59,18285100,33.59 +2005-02-08,34.64,34.91,34.32,34.36,17321500,34.36 +2005-02-07,35.07,35.19,34.36,34.47,14588900,34.47 +2005-02-04,34.71,35.30,34.71,35.02,16850200,35.02 +2005-02-03,35.27,35.67,35.00,35.09,16742400,35.09 +2005-02-02,36.02,36.34,35.29,35.54,33495200,35.54 +2005-02-01,35.13,35.28,34.46,34.75,18633600,34.75 +2005-01-31,35.04,35.44,34.53,35.21,20712200,35.21 +2005-01-28,34.90,35.24,34.12,34.62,17853700,34.62 +2005-01-27,35.38,35.49,34.35,34.73,21450800,34.73 +2005-01-26,34.71,35.74,34.39,35.47,25767500,35.47 +2005-01-25,34.55,34.76,33.94,34.04,26521400,34.04 +2005-01-24,35.48,35.52,33.75,33.93,31477400,33.93 +2005-01-21,36.07,36.11,35.29,35.30,26608000,35.30 +2005-01-20,35.39,36.42,35.05,35.78,30239100,35.78 +2005-01-19,38.08,38.20,36.42,36.45,44303200,36.45 +2005-01-18,37.10,37.46,36.60,37.18,42709600,37.18 +2005-01-14,35.86,36.70,35.83,36.70,27697700,36.70 +2005-01-13,36.12,36.32,35.26,35.33,18526500,35.33 +2005-01-12,35.88,36.18,34.80,36.14,23274700,36.14 +2005-01-11,36.31,36.58,35.39,35.66,19711900,35.66 +2005-01-10,36.00,36.76,35.51,36.32,17482800,36.32 +2005-01-07,35.99,36.46,35.41,35.96,18596300,35.96 +2005-01-06,36.32,36.50,35.21,35.43,20835300,35.43 +2005-01-05,36.69,36.98,36.06,36.13,18469100,36.13 +2005-01-04,38.45,38.54,36.46,36.58,26625300,36.58 +2005-01-03,38.36,38.90,37.65,38.18,25482800,38.18 diff --git a/includes/js/dojox/charting/tests/runTests.html b/includes/js/dojox/charting/tests/runTests.html new file mode 100644 index 0000000..6e13c2a --- /dev/null +++ b/includes/js/dojox/charting/tests/runTests.html @@ -0,0 +1,9 @@ + + + + Dojox.wire Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/charting/tests/test_bars.html b/includes/js/dojox/charting/tests/test_bars.html new file mode 100644 index 0000000..f39c7b1 --- /dev/null +++ b/includes/js/dojox/charting/tests/test_bars.html @@ -0,0 +1,65 @@ + + +Bar chart + + + + + + + + + + +

Bar chart

+
+ +

That's all Folks!

+ + diff --git a/includes/js/dojox/charting/tests/test_chart2d.html b/includes/js/dojox/charting/tests/test_chart2d.html new file mode 100644 index 0000000..2480730 --- /dev/null +++ b/includes/js/dojox/charting/tests/test_chart2d.html @@ -0,0 +1,353 @@ + + +Chart 2D + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Chart 2D

+ +

1: Defaults: lines, no axes.

+
+

2: Defaults: lines, no axes, and custom strokes.

+
+

3: Areas, orange theme, no axes.

+
+

4: Areas, no axes, custom strokes and fills.

+
+

5: Lines, axes, blue theme.

+
+

6: Lines, axes (aligned on minor ticks), cyan theme.

+
+

7: Lines, axes (aligned on major ticks), green theme.

+
+

8: Lines and markers, no axes, purple theme, custom min/max.

+
+

9: Markers only, no axes, custom theme, custom markers, custom min/max.

+
+

10: Lines and markers, shadows, no axes, custom theme, custom markers, custom min/max.

+
+

11: Stacked lines, markers, shadows, no axes, custom strokes, fills, and markers.

+
+

12: Stacked areas, axes (aligned on major ticks), custom strokes and fills.

+
+

13: Columns, no axes, custom strokes and fills.

+
+

14: Columns with gaps beetwen them, vertical axis aligned on major ticks, custom strokes, fills.

+
+

15: Stacked columns, no axes, custom strokes and fills.

+
+

16: Bars, axes aligned on major ticks, no minor ticks, custom strokes and fills.

+
+

17: Stacked bars, no axes, custom strokes and fills.

+
+

18: Clustered columns, custom axes, custom strokes, fills, and gap.

+
+

19: Clustered bars, custom axes, custom strokes, fills, and gap.

+
+

20: Columns with gaps beetwen them, grids, custom strokes, fills, axes.

+
+

21: Columns with gaps beetwen them, grids, custom strokes, fills, axes, with min=0, max=8, and manually specified ticks on the vertical axis.

+
+

22: Columns with positive and negative values, axes, and grid.

+
+

23: Clustered columns with positive and negative values, axes, and grid.

+
+

24: Bars with positive and negative values, axes, and grid.

+
+

25: Clustered bars with positive and negative values, axes, and grid.

+
+

26: Default lines with 2D data, custom axis, red theme.

+
+

27: Scatter chart, custom axis, purple theme.

+
+

28: Markers, lines, 2D data, custom axis, blue theme.

+
+

29: Clustered columns with positive and negative values, readable theme.

+
+

That's all Folks!

+ + diff --git a/includes/js/dojox/charting/tests/test_chart2d_updating.html b/includes/js/dojox/charting/tests/test_chart2d_updating.html new file mode 100644 index 0000000..6a7641b --- /dev/null +++ b/includes/js/dojox/charting/tests/test_chart2d_updating.html @@ -0,0 +1,80 @@ + + +Chart 2D + + + + + + + + + + + +

Chart 2D Updating Data

+

Areas, orange theme, axes, grid. Very crude example to show a chart with updating values.

+
+ + diff --git a/includes/js/dojox/charting/tests/test_cylinders.html b/includes/js/dojox/charting/tests/test_cylinders.html new file mode 100644 index 0000000..9a3cc66 --- /dev/null +++ b/includes/js/dojox/charting/tests/test_cylinders.html @@ -0,0 +1,65 @@ + + +Cylinder chart + + + + + + + + + + +

Cylinder chart

+
+ +

That's all Folks!

+ + diff --git a/includes/js/dojox/charting/tests/test_labels2d.html b/includes/js/dojox/charting/tests/test_labels2d.html new file mode 100644 index 0000000..299385e --- /dev/null +++ b/includes/js/dojox/charting/tests/test_labels2d.html @@ -0,0 +1,90 @@ + + +Chart 2D + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Chart 2D

+ +

1: Bars, axes aligned on major ticks, no minor ticks, custom strokes and fills.

+
+

2: Bars, axes aligned on major ticks, no minor ticks, custom strokes and fills, custom labels.

+
+

That's all Folks!

+ + diff --git a/includes/js/dojox/charting/tests/test_pie2d.html b/includes/js/dojox/charting/tests/test_pie2d.html new file mode 100644 index 0000000..9fe6827 --- /dev/null +++ b/includes/js/dojox/charting/tests/test_pie2d.html @@ -0,0 +1,128 @@ + + +Pie 2D + + + + + + + + + + + + + + + +

Pie 2D

+ +

1: Pie with internal labels.

+
+

2: Pie with external labels and precision=0.

+
+

3/4: Two pies with internal and external labels with a constant radius.

+ + + +
+

5/6: Pie with internal custom labels and custom colors.

+ + + +
+

That's all Folks!

+ + diff --git a/includes/js/dojox/charting/tests/test_scaler.html b/includes/js/dojox/charting/tests/test_scaler.html new file mode 100644 index 0000000..f717f83 --- /dev/null +++ b/includes/js/dojox/charting/tests/test_scaler.html @@ -0,0 +1,97 @@ + + +Scaler/tick generator + + + + + + + + +

Scaler/tick generator

+

Input

+ + + + + + + + +
NameValue
min
max
span
natural
fixLower
fixUpper
+

+

Output

+ + + + + + + + + + + + + + + + + + + + + + +
NameValue
lowerBound 
upperBound 
major.tick 
major.start 
major.count 
major.prec 
minor.tick 
minor.start 
minor.count 
minor.prec 
micro.tick 
micro.start 
micro.count 
micro.prec 
scale 
+ + diff --git a/includes/js/dojox/charting/tests/test_sparklines.html b/includes/js/dojox/charting/tests/test_sparklines.html new file mode 100644 index 0000000..2d3a36f --- /dev/null +++ b/includes/js/dojox/charting/tests/test_sparklines.html @@ -0,0 +1,180 @@ + + + Chart 2D -- Sparklines Edition + + + + + + +

Chart 2D

+

Sparkline-style charts using dojox.charting

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Simple Sparkline: + +
+
+
+
+
+ 7 arbitrary data points +
+ Google Closing Price & Volume: + + +
+
+
+
+
+
+
+ +
+ ~1400 data points, all trading days since Jan '05 +
+ Yahoo Closing Price & Volume: + + +
+
+
+
+
+
+
+ +
+
+ Microsoft Closing Price & Volume: + +
+
+
+
+
+
+
+ +
+
+ + diff --git a/includes/js/dojox/charting/tests/test_widget2d.html b/includes/js/dojox/charting/tests/test_widget2d.html new file mode 100644 index 0000000..f97719f --- /dev/null +++ b/includes/js/dojox/charting/tests/test_widget2d.html @@ -0,0 +1,98 @@ + + +Chart 2D + + + + + + + + + + + + + + +

Chart 2D

+

Examples of charts using widgets.

+
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

That's all Folks!

+ + diff --git a/includes/js/dojox/charting/themes/ET/greys.js b/includes/js/dojox/charting/themes/ET/greys.js new file mode 100644 index 0000000..de5e805 --- /dev/null +++ b/includes/js/dojox/charting/themes/ET/greys.js @@ -0,0 +1,63 @@ +if(!dojo._hasResource["dojox.charting.themes.ET.greys"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.themes.ET.greys"] = true; +dojo.provide("dojox.charting.themes.ET.greys"); +dojo.require("dojox.charting.Theme"); + +(function(){ + var dxc=dojox.charting; + dxc.themes.ET.greys = new dxc.Theme({ + antiAlias: false, + chart: { + stroke: null, + fill: "transparent" + }, + plotarea: { + // stroke: { width: 0.2, color: "#666666" }, + stroke: null, + fill: "transparent" + }, + axis:{ + stroke:{ width: 0 }, + line:{ width: 0 }, + majorTick:{ + color: "#666666", + width: 1, + length: 5 + }, + minorTick: { + color: "black", + width: 0.5, + length: 2 + }, + font:"normal normal normal 8pt Tahoma", + fontColor:"#999999" + }, + series:{ + outline:{ width: 0, color: "black" }, + stroke: { width: 1, color: "black" }, + fill: dojo.colorFromHex("#3b444b"), + font: "normal normal normal 7pt Tahoma", // label + fontColor: "#717171" + }, + marker:{ // any markers on a series. + stroke:{ width:1 }, + fill:"#333", + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + colors:[] + }); + dxc.themes.ET.greys.defineColors({ + colors: [ + // dojo.colorFromHex("#c3c3c3"), + dojo.colorFromHex("#8a8c8f"), + dojo.colorFromHex("#4b4b4b"), + dojo.colorFromHex("#3b444b"), + dojo.colorFromHex("#2e2d30"), + dojo.colorFromHex("#000000") + ] + }); +})(); + + +} diff --git a/includes/js/dojox/charting/themes/GreySkies.js b/includes/js/dojox/charting/themes/GreySkies.js new file mode 100644 index 0000000..da96edc --- /dev/null +++ b/includes/js/dojox/charting/themes/GreySkies.js @@ -0,0 +1,11 @@ +if(!dojo._hasResource["dojox.charting.themes.GreySkies"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.themes.GreySkies"] = true; +dojo.provide("dojox.charting.themes.GreySkies"); +dojo.require("dojox.charting.Theme"); + +(function(){ + var dxc=dojox.charting; + dxc.themes.GreySkies=new dxc.Theme(dxc.Theme._def); +})(); + +} diff --git a/includes/js/dojox/charting/themes/PlotKit/README b/includes/js/dojox/charting/themes/PlotKit/README new file mode 100644 index 0000000..dbf4c81 --- /dev/null +++ b/includes/js/dojox/charting/themes/PlotKit/README @@ -0,0 +1,11 @@ +This directory contains a set of themes for the DojoX Charting +engine that are based on the visual stylings of the PlotKit +chart kit, created by Alastair Tse: + +http://www.liquidx.net/plotkit/ + +...whose work we admire. Consider these themes to not be a +ripoff of his fine work, but instead a true homage: his charts +are beautiful, and we stand in awe. + +--trt, 2007-06-08 diff --git a/includes/js/dojox/charting/themes/PlotKit/blue.js b/includes/js/dojox/charting/themes/PlotKit/blue.js new file mode 100644 index 0000000..5ba63bc --- /dev/null +++ b/includes/js/dojox/charting/themes/PlotKit/blue.js @@ -0,0 +1,43 @@ +if(!dojo._hasResource["dojox.charting.themes.PlotKit.blue"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.themes.PlotKit.blue"] = true; +dojo.provide("dojox.charting.themes.PlotKit.blue"); +dojo.require("dojox.charting.Theme"); + +(function(){ + var dxc=dojox.charting; + dxc.themes.PlotKit.blue=new dxc.Theme({ + chart:{ + stroke:null, + fill: "white" + }, + plotarea:{ + stroke:null, + fill: "#e7eef6" + }, + axis:{ + stroke:{ color:"#fff",width:2 }, + line:{ color:"#fff",width:1 }, + majorTick:{ color:"#fff", width:2, length:12 }, + minorTick:{ color:"#fff", width:1, length:8 }, + font:"normal normal normal 8pt Tahoma", + fontColor:"#999" + }, + series:{ + outline:{ width: 0.1, color:"#fff" }, + stroke:{ width: 1.5, color:"#666" }, + fill:new dojo.Color([0x66, 0x66, 0x66, 0.8]), + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + marker:{ // any markers on a series. + stroke:{ width:2 }, + fill:"#333", + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + colors:[] + }); + dxc.themes.PlotKit.blue.defineColors({ hue:217, saturation:60, low:40, high:88 }); +})(); + +} diff --git a/includes/js/dojox/charting/themes/PlotKit/cyan.js b/includes/js/dojox/charting/themes/PlotKit/cyan.js new file mode 100644 index 0000000..0f05638 --- /dev/null +++ b/includes/js/dojox/charting/themes/PlotKit/cyan.js @@ -0,0 +1,43 @@ +if(!dojo._hasResource["dojox.charting.themes.PlotKit.cyan"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.themes.PlotKit.cyan"] = true; +dojo.provide("dojox.charting.themes.PlotKit.cyan"); +dojo.require("dojox.charting.Theme"); + +(function(){ + var dxc=dojox.charting; + dxc.themes.PlotKit.cyan=new dxc.Theme({ + chart:{ + stroke:null, + fill: "white" + }, + plotarea:{ + stroke:null, + fill: "#e6f1f5" + }, + axis:{ + stroke:{ color:"#fff",width:2 }, + line:{ color:"#fff",width:1 }, + majorTick:{ color:"#fff", width:2, length:12 }, + minorTick:{ color:"#fff", width:1, length:8 }, + font:"normal normal normal 8pt Tahoma", + fontColor:"#999" + }, + series:{ + outline:{ width:1, color:"#fff" }, + stroke:{ width:2, color:"#666" }, + fill:new dojo.Color([0x66, 0x66, 0x66, 0.8]), + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + marker:{ // any markers on a series. + stroke:{ width:2 }, + fill:"#333", + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + colors:[] + }); + dxc.themes.PlotKit.cyan.defineColors({ hue:194, saturation:60, low:40, high:88 }); +})(); + +} diff --git a/includes/js/dojox/charting/themes/PlotKit/green.js b/includes/js/dojox/charting/themes/PlotKit/green.js new file mode 100644 index 0000000..7581a5a --- /dev/null +++ b/includes/js/dojox/charting/themes/PlotKit/green.js @@ -0,0 +1,43 @@ +if(!dojo._hasResource["dojox.charting.themes.PlotKit.green"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.themes.PlotKit.green"] = true; +dojo.provide("dojox.charting.themes.PlotKit.green"); +dojo.require("dojox.charting.Theme"); + +(function(){ + var dxc=dojox.charting; + dxc.themes.PlotKit.green=new dxc.Theme({ + chart:{ + stroke:null, + fill: "white" + }, + plotarea:{ + stroke:null, + fill: "#eff5e6" + }, + axis:{ + stroke:{ color:"#fff",width:2 }, + line:{ color:"#fff",width:1 }, + majorTick:{ color:"#fff", width:2, length:12 }, + minorTick:{ color:"#fff", width:1, length:8 }, + font:"normal normal normal 8pt Tahoma", + fontColor:"#999" + }, + series:{ + outline:{ width:1, color:"#fff" }, + stroke:{ width:2, color:"#666" }, + fill:new dojo.Color([0x66, 0x66, 0x66, 0.8]), + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + marker:{ // any markers on a series. + stroke:{ width:2 }, + fill:"#333", + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + colors:[] + }); + dxc.themes.PlotKit.green.defineColors({ hue:82, saturation:60, low:40, high:88 }); +})(); + +} diff --git a/includes/js/dojox/charting/themes/PlotKit/orange.js b/includes/js/dojox/charting/themes/PlotKit/orange.js new file mode 100644 index 0000000..1693610 --- /dev/null +++ b/includes/js/dojox/charting/themes/PlotKit/orange.js @@ -0,0 +1,43 @@ +if(!dojo._hasResource["dojox.charting.themes.PlotKit.orange"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.themes.PlotKit.orange"] = true; +dojo.provide("dojox.charting.themes.PlotKit.orange"); +dojo.require("dojox.charting.Theme"); + +(function(){ + var dxc=dojox.charting; + dxc.themes.PlotKit.orange=new dxc.Theme({ + chart:{ + stroke:null, + fill: "white" + }, + plotarea:{ + stroke:null, + fill: "#f5eee6" + }, + axis:{ + stroke:{ color:"#fff",width:2 }, + line:{ color:"#fff",width:1 }, + majorTick:{ color:"#fff", width:2, length:12 }, + minorTick:{ color:"#fff", width:1, length:8 }, + font:"normal normal normal 8pt Tahoma", + fontColor:"#999" + }, + series:{ + outline:{ width:0.15, color: "#fff" }, + stroke:{ width:1.5, color: "#666" }, + fill:new dojo.Color([0x66, 0x66, 0x66, 0.8]), + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + marker:{ // any markers on a series. + stroke:{ width:2 }, + fill:"#333", + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + colors:[] + }); + dxc.themes.PlotKit.orange.defineColors({ hue:31, saturation:60, low:40, high:88 }); +})(); + +} diff --git a/includes/js/dojox/charting/themes/PlotKit/purple.js b/includes/js/dojox/charting/themes/PlotKit/purple.js new file mode 100644 index 0000000..a54d0cc --- /dev/null +++ b/includes/js/dojox/charting/themes/PlotKit/purple.js @@ -0,0 +1,43 @@ +if(!dojo._hasResource["dojox.charting.themes.PlotKit.purple"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.themes.PlotKit.purple"] = true; +dojo.provide("dojox.charting.themes.PlotKit.purple"); +dojo.require("dojox.charting.Theme"); + +(function(){ + var dxc=dojox.charting; + dxc.themes.PlotKit.purple=new dxc.Theme({ + chart:{ + stroke:null, + fill: "white" + }, + plotarea:{ + stroke:null, + fill: "#eee6f5" + }, + axis:{ + stroke:{ color:"#fff",width:2 }, + line:{ color:"#fff",width:1 }, + majorTick:{ color:"#fff", width:2, length:12 }, + minorTick:{ color:"#fff", width:1, length:8 }, + font:"normal normal normal 8pt Tahoma", + fontColor:"#999" + }, + series:{ + outline:{ width:1, color:"#fff" }, + stroke:{ width:2, color:"#666" }, + fill:new dojo.Color([0x66, 0x66, 0x66, 0.8]), + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + marker:{ // any markers on a series. + stroke:{ width:2 }, + fill:"#333", + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + colors:[] + }); + dxc.themes.PlotKit.purple.defineColors({ hue:271, saturation:60, low:40, high:88 }); +})(); + +} diff --git a/includes/js/dojox/charting/themes/PlotKit/red.js b/includes/js/dojox/charting/themes/PlotKit/red.js new file mode 100644 index 0000000..607090b --- /dev/null +++ b/includes/js/dojox/charting/themes/PlotKit/red.js @@ -0,0 +1,43 @@ +if(!dojo._hasResource["dojox.charting.themes.PlotKit.red"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.themes.PlotKit.red"] = true; +dojo.provide("dojox.charting.themes.PlotKit.red"); +dojo.require("dojox.charting.Theme"); + +(function(){ + var dxc=dojox.charting; + dxc.themes.PlotKit.red=new dxc.Theme({ + chart:{ + stroke:null, + fill: "white" + }, + plotarea:{ + stroke:null, + fill: "#f5e6e6" + }, + axis:{ + stroke:{ color:"#fff",width:2 }, + line:{ color:"#fff",width:1 }, + majorTick:{ color:"#fff", width:2, length:12 }, + minorTick:{ color:"#fff", width:1, length:8 }, + font:"normal normal normal 8pt Tahoma", + fontColor:"#999" + }, + series:{ + outline:{ width:1, color:"#fff" }, + stroke:{ width:2, color:"#666" }, + fill:new dojo.Color([0x66, 0x66, 0x66, 0.8]), + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + marker:{ // any markers on a series. + stroke:{ width:2 }, + fill:"#333", + font:"normal normal normal 7pt Tahoma", // label + fontColor:"#000" + }, + colors:[] + }); + dxc.themes.PlotKit.red.defineColors({ hue:1, saturation:60, low:40, high:88 }); +})(); + +} diff --git a/includes/js/dojox/charting/widget/Chart2D.js b/includes/js/dojox/charting/widget/Chart2D.js new file mode 100644 index 0000000..08def5e --- /dev/null +++ b/includes/js/dojox/charting/widget/Chart2D.js @@ -0,0 +1,215 @@ +if(!dojo._hasResource["dojox.charting.widget.Chart2D"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.charting.widget.Chart2D"] = true; +dojo.provide("dojox.charting.widget.Chart2D"); + +dojo.require("dijit._Widget"); +dojo.require("dojox.charting.Chart2D"); +dojo.require("dojox.lang.functional"); + +(function(){ + var collectAxisParams, collectPlotParams, collectDataParams, + notNull = function(o){ return o; }, + df = dojox.lang.functional, + du = dojox.lang.utils; + + dojo.declare("dojox.charting.widget.Chart2D", dijit._Widget, { + // parameters for the markup + + // theme for the chart + theme: null, + + // margins for the chart: {l: 10, r: 10, t: 10, b: 10} + margins: null, + + // chart area + stroke: null, + fill: null, + + // methods + + buildRendering: function(){ + var n = this.domNode = this.srcNodeRef; + + // collect chart parameters + var axes = dojo.filter(dojo.query("> .axis", n).map(collectAxisParams), notNull); + var plots = dojo.filter(dojo.query("> .plot", n).map(collectPlotParams), notNull); + var series = dojo.filter(dojo.query("> .series", n).map(collectDataParams), notNull); + + // build the chart + n.innerHTML = ""; + var c = this.chart = new dojox.charting.Chart2D(n, { + margins: this.margins, + stroke: this.stroke, + fill: this.fill + }); + + // add collected parameters + if(this.theme){ + c.setTheme(this.theme); + } + dojo.forEach(axes, function(axis){ + c.addAxis(axis.name, axis.kwArgs); + }); + dojo.forEach(plots, function(plot){ + c.addPlot(plot.name, plot.kwArgs); + }); + var render = df.foldl(series, function(render, series){ + if(series.type == "data"){ + c.addSeries(series.name, series.data, series.kwArgs); + render = true; + }else{ + c.addSeries(series.name, [0], series.kwArgs); + var kw = {}; + du.updateWithPattern( + kw, + series.kwArgs, + { + "query": "", + "queryOptions": null, + "start": 0, + "count": 1 //, + // "sort": [] + }, + true + ); + if(series.kwArgs.sort){ + // sort is a complex object type and doesn't survive coercian + kw.sort = dojo.clone(series.kwArgs.sort); + } + dojo.mixin(kw, { + onComplete: function(data){ + var values; + if("valueFn" in series.kwArgs){ + var fn = series.kwArgs.valueFn; + values = dojo.map(data, function(x){ + return fn(series.data.getValue(x, series.field, 0)); + }); + }else{ + values = dojo.map(data, function(x){ + return series.data.getValue(x, series.field, 0); + }); + } + c.addSeries(series.name, values, series.kwArgs).render(); + } + }); + series.data.fetch(kw); + } + return render; + }, false); + if(render){ c.render(); } + }, + resize: function(box){ + dojo.marginBox(this.domNode, box); + this.chart.resize(); + } + }); + + collectAxisParams = function(node){ + var name = node.getAttribute("name"), type = node.getAttribute("type"); + if(!name){ return null; } + var o = {name: name, kwArgs: {}}, kw = o.kwArgs; + if(type){ + if(dojox.charting.axis2d[type]){ + type = dojox._scopeName + ".charting.axis2d." + type; + } + var axis = eval("(" + type + ")"); + if(axis){ kw.type = axis; } + }else{ + type = dojox._scopeName + ".charting.axis2d.Default"; + } + var dp = eval("(" + type + ".prototype.defaultParams)"); + for(var x in dp){ + if(x in kw){ continue; } + var attr = node.getAttribute(x); + kw[x] = du.coerceType(dp[x], attr == null ? dp[x] : attr); + } + var op = eval("(" + type + ".prototype.optionalParams)"); + for(var x in op){ + if(x in kw){ continue; } + var attr = node.getAttribute(x); + if(attr != null){ + kw[x] = du.coerceType(op[x], attr); + } + } + return o; + }; + + collectPlotParams = function(node){ + var name = node.getAttribute("name"), type = node.getAttribute("type"); + if(!name){ return null; } + var o = {name: name, kwArgs: {}}, kw = o.kwArgs; + if(type){ + if(dojox.charting.plot2d[type]){ + type = dojox._scopeName + ".charting.plot2d." + type; + } + var plot = eval("(" + type + ")"); + if(plot){ kw.type = plot; } + }else{ + type = dojox._scopeName + ".charting.plot2d.Default"; + } + var dp = eval("(" + type + ".prototype.defaultParams)"); + for(var x in dp){ + if(x in kw){ continue; } + var attr = node.getAttribute(x); + kw[x] = du.coerceType(dp[x], attr == null ? dp[x] : attr); + } + var op = eval("(" + type + ".prototype.optionalParams)"); + for(var x in op){ + if(x in kw){ continue; } + var attr = node.getAttribute(x); + if(attr != null){ + kw[x] = du.coerceType(op[x], attr); + } + } + return o; + }; + + collectDataParams = function(node){ + var name = node.getAttribute("name"); + if(!name){ return null; } + var o = {name: name, kwArgs: {}}, kw = o.kwArgs, t; + t = node.getAttribute("plot"); + if(t != null){ kw.plot = t; } + t = node.getAttribute("marker"); + if(t != null){ kw.marker = t; } + t = node.getAttribute("stroke"); + if(t != null){ kw.stroke = eval("(" + t + ")"); } + t = node.getAttribute("fill"); + if(t != null){ kw.fill = eval("(" + t + ")"); } + t = node.getAttribute("data"); + if(t != null){ + o.type = "data"; + o.data = dojo.map(String(t).split(','), Number); + return o; + } + t = node.getAttribute("array"); + if(t != null){ + o.type = "data"; + o.data = eval("(" + t + ")"); + return o; + } + t = node.getAttribute("store"); + if(t != null){ + o.type = "store"; + o.data = eval("(" + t + ")"); + t = node.getAttribute("field"); + o.field = t != null ? t : "value"; + t = node.getAttribute("query"); + if(!!t){ kw.query = t; } + t = node.getAttribute("queryOptions"); + if(!!t){ kw.queryOptions = eval("(" + t + ")"); } + t = node.getAttribute("start"); + if(!!t){ kw.start = Number(t); } + t = node.getAttribute("count"); + if(!!t){ kw.count = Number(t); } + t = node.getAttribute("sort"); + if(!!t){ kw.sort = eval("("+t+")"); } + t = node.getAttribute("valueFn"); + if(!!t){ kw.valueFn = df.lambda(t); } + return o; + } + return null; + }; +})(); + +} diff --git a/includes/js/dojox/collections.js b/includes/js/dojox/collections.js new file mode 100644 index 0000000..bb76034 --- /dev/null +++ b/includes/js/dojox/collections.js @@ -0,0 +1,6 @@ +if(!dojo._hasResource["dojox.collections"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections"] = true; +dojo.provide("dojox.collections"); +dojo.require("dojox.collections._base"); + +} diff --git a/includes/js/dojox/collections/ArrayList.js b/includes/js/dojox/collections/ArrayList.js new file mode 100644 index 0000000..d57f6e7 --- /dev/null +++ b/includes/js/dojox/collections/ArrayList.js @@ -0,0 +1,133 @@ +if(!dojo._hasResource["dojox.collections.ArrayList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.ArrayList"] = true; +dojo.provide("dojox.collections.ArrayList"); +dojo.require("dojox.collections._base"); + +dojox.collections.ArrayList=function(/* array? */arr){ + // summary + // Returns a new object of type dojox.collections.ArrayList + var items=[]; + if(arr) items=items.concat(arr); + this.count=items.length; + this.add=function(/* object */obj){ + // summary + // Add an element to the collection. + items.push(obj); + this.count=items.length; + }; + this.addRange=function(/* array */a){ + // summary + // Add a range of objects to the ArrayList + if(a.getIterator){ + var e=a.getIterator(); + while(!e.atEnd()){ + this.add(e.get()); + } + this.count=items.length; + }else{ + for(var i=0; i=0) { + items.splice(i,1); + } + this.count=items.length; + }; + this.removeAt=function(/* int */ i){ + // summary + // return an array with function applied to all elements + items.splice(i,1); + this.count=items.length; + }; + this.reverse=function(){ + // summary + // Reverse the internal array + items.reverse(); + }; + this.sort=function(/* function? */ fn){ + // summary + // sort the internal array + if(fn){ + items.sort(fn); + }else{ + items.sort(); + } + }; + this.setByIndex=function(/* int */ i, /* object */ obj){ + // summary + // Set an element in the array by the passed index. + items[i]=obj; + this.count=items.length; + }; + this.toArray=function(){ + // summary + // Return a new array with all of the items of the internal array concatenated. + return [].concat(items); + } + this.toString=function(/* string */ delim){ + // summary + // implementation of toString, follows [].toString(); + return items.join((delim||",")); + }; +}; + +} diff --git a/includes/js/dojox/collections/BinaryTree.js b/includes/js/dojox/collections/BinaryTree.js new file mode 100644 index 0000000..edd9fbf --- /dev/null +++ b/includes/js/dojox/collections/BinaryTree.js @@ -0,0 +1,211 @@ +if(!dojo._hasResource["dojox.collections.BinaryTree"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.BinaryTree"] = true; +dojo.provide("dojox.collections.BinaryTree"); +dojo.require("dojox.collections._base"); + +dojox.collections.BinaryTree=function(data){ + function node(data, rnode, lnode){ + this.value=data||null; + this.right=rnode||null; + this.left=lnode||null; + this.clone=function(){ + var c=new node(); + if(this.value.value){ + c.value=this.value.clone(); + }else{ + c.value=this.value; + } + if(this.left!=null){ + c.left=this.left.clone(); + } + if(this.right!=null){ + c.right=this.right.clone(); + } + return c; + } + this.compare=function(n){ + if(this.value>n.value){ return 1; } + if(this.valued){ return 1; } + if(this.value0){ return searchHelper(current.left, data); } + else{ return searchHelper(current.right, data); } + } + + this.add=function(data){ + var n=new node(data); + var i; + var current=root; + var parent=null; + while(current){ + i=current.compare(n); + if(i==0){ return; } + parent=current; + if(i>0){ current=current.left; } + else{ current=current.right; } + } + this.count++; + if(!parent){ + root=n; + }else{ + i=parent.compare(n); + if(i>0){ + parent.left=n; + }else{ + parent.right=n; + } + } + }; + this.clear=function(){ + root=null; + this.count=0; + }; + this.clone=function(){ + var c=new dojox.collections.BinaryTree(); + var itr=this.getIterator(); + while(!itr.atEnd()){ + c.add(itr.get()); + } + return c; + }; + this.contains=function(data){ + return this.search(data) != null; + }; + this.deleteData=function(data){ + var current=root; + var parent=null; + var i=current.compareData(data); + while(i!=0&¤t!=null){ + if(i>0){ + parent=current; + current=current.left; + }else if(i<0){ + parent=current; + current=current.right; + } + i=current.compareData(data); + } + if(!current){ return; } + this.count--; + if(!current.right){ + if(!parent){ + root=current.left; + }else{ + i=parent.compare(current); + if(i>0){ parent.left=current.left; } + else if(i<0){ parent.right=current.left; } + } + } + else if(!current.right.left){ + if(!parent){ + root=current.right; + }else{ + i=parent.compare(current); + if(i>0){ parent.left=current.right; } + else if(i<0){ parent.right=current.right; } + } + } + else{ + var leftmost=current.right.left; + var lmParent=current.right; + while(leftmost.left!=null){ + lmParent=leftmost; + leftmost=leftmost.left; + } + lmParent.left=leftmost.right; + leftmost.left=current.left; + leftmost.right=current.right; + if(!parent){ + root=leftmost; + }else{ + i=parent.compare(current); + if(i>0){ parent.left=leftmost; } + else if(i<0){ parent.right=leftmost; } + } + } + }; + this.getIterator=function(){ + var a=[]; + inorderTraversalBuildup(root, a); + return new dojox.collections.Iterator(a); + }; + this.search=function(data){ + return searchHelper(root, data); + }; + this.toString=function(order, sep){ + if(!order){ order=dojox.collections.BinaryTree.TraversalMethods.Inorder; } + if(!sep){ sep=","; } + var s=""; + switch(order){ + case dojox.collections.BinaryTree.TraversalMethods.Preorder: + s=preorderTraversal(root, sep); + break; + case dojox.collections.BinaryTree.TraversalMethods.Inorder: + s=inorderTraversal(root, sep); + break; + case dojox.collections.BinaryTree.TraversalMethods.Postorder: + s=postorderTraversal(root, sep); + break; + }; + if(s.length==0){ return ""; } + else{ return s.substring(0, s.length - sep.length); } + }; + + this.count=0; + var root=this.root=null; + if(data){ + this.add(data); + } +} +dojox.collections.BinaryTree.TraversalMethods={ + Preorder: 1, Inorder: 2, Postorder: 3 +}; + +} diff --git a/includes/js/dojox/collections/Dictionary.js b/includes/js/dojox/collections/Dictionary.js new file mode 100644 index 0000000..8213790 --- /dev/null +++ b/includes/js/dojox/collections/Dictionary.js @@ -0,0 +1,116 @@ +if(!dojo._hasResource["dojox.collections.Dictionary"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.Dictionary"] = true; +dojo.provide("dojox.collections.Dictionary"); +dojo.require("dojox.collections._base"); + +dojox.collections.Dictionary=function(/* dojox.collections.Dictionary? */dictionary){ + // summary + // Returns an object of type dojox.collections.Dictionary + var items={}; + this.count=0; + + // comparator for property addition and access. + var testObject={}; + + this.add=function(/* string */k, /* object */v){ + // summary + // Add a new item to the Dictionary. + var b=(k in items); + items[k]=new dojox.collections.DictionaryEntry(k,v); + if(!b){ + this.count++; + } + }; + this.clear=function(){ + // summary + // Clears the internal dictionary. + items={}; + this.count=0; + }; + this.clone=function(){ + // summary + // Returns a new instance of dojox.collections.Dictionary; note the the dictionary is a clone but items might not be. + return new dojox.collections.Dictionary(this); // dojox.collections.Dictionary + }; + this.contains=this.containsKey=function(/* string */k){ + // summary + // Check to see if the dictionary has an entry at key "k". + if(testObject[k]){ + return false; // bool + } + return (items[k]!=null); // bool + }; + this.containsValue=function(/* object */v){ + // summary + // Check to see if the dictionary has an entry with value "v". + var e=this.getIterator(); + while(e.get()){ + if(e.element.value==v){ + return true; // bool + } + } + return false; // bool + }; + this.entry=function(/* string */k){ + // summary + // Accessor method; similar to dojox.collections.Dictionary.item but returns the actual Entry object. + return items[k]; // dojox.collections.DictionaryEntry + }; + this.forEach=function(/* function */ fn, /* object? */ scope){ + // summary + // functional iterator, following the mozilla spec. + var a=[]; // Create an indexing array + for(var p in items) { + if(!testObject[p]){ + a.push(items[p]); // fill it up + } + } + dojo.forEach(a, fn, scope); + }; + this.getKeyList=function(){ + // summary + // Returns an array of the keys in the dictionary. + return (this.getIterator()).map(function(entry){ + return entry.key; + }); // array + }; + this.getValueList=function(){ + // summary + // Returns an array of the values in the dictionary. + return (this.getIterator()).map(function(entry){ + return entry.value; + }); // array + }; + this.item=function(/* string */k){ + // summary + // Accessor method. + if(k in items){ + return items[k].valueOf(); // object + } + return undefined; // object + }; + this.getIterator=function(){ + // summary + // Gets a dojox.collections.DictionaryIterator for iteration purposes. + return new dojox.collections.DictionaryIterator(items); // dojox.collections.DictionaryIterator + }; + this.remove=function(/* string */k){ + // summary + // Removes the item at k from the internal collection. + if(k in items && !testObject[k]){ + delete items[k]; + this.count--; + return true; // bool + } + return false; // bool + }; + + if (dictionary){ + var e=dictionary.getIterator(); + while(e.get()) { + this.add(e.element.key, e.element.value); + } + } +}; + +} diff --git a/includes/js/dojox/collections/Queue.js b/includes/js/dojox/collections/Queue.js new file mode 100644 index 0000000..5fa4a5d --- /dev/null +++ b/includes/js/dojox/collections/Queue.js @@ -0,0 +1,74 @@ +if(!dojo._hasResource["dojox.collections.Queue"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.Queue"] = true; +dojo.provide("dojox.collections.Queue"); +dojo.require("dojox.collections._base"); + +dojox.collections.Queue=function(/* array? */arr){ + // summary + // return an object of type dojox.collections.Queue + var q=[]; + if (arr){ + q=q.concat(arr); + } + this.count=q.length; + this.clear=function(){ + // summary + // clears the internal collection + q=[]; + this.count=q.length; + }; + this.clone=function(){ + // summary + // creates a new Queue based on this one + return new dojox.collections.Queue(q); // dojox.collections.Queue + }; + this.contains=function(/* object */ o){ + // summary + // Check to see if the passed object is an element in this queue + for(var i=0; i b.key) return 1; + if (a.key < b.key) return -1; + return 0; + }; + var build=function(){ + q=[]; + var e=_this.getIterator(); + while (!e.atEnd()){ + q.push(e.get()); + } + q.sort(sorter); + }; + var testObject={}; + + this.count=q.length; + this.add=function(/* string */ k,/* object */v){ + // summary + // add the passed value to the dictionary at location k + if (!items[k]) { + items[k]=new dojox.collections.DictionaryEntry(k,v); + this.count=q.push(items[k]); + q.sort(sorter); + } + }; + this.clear=function(){ + // summary + // clear the internal collections + items={}; + q=[]; + this.count=q.length; + }; + this.clone=function(){ + // summary + // create a clone of this sorted list + return new dojox.collections.SortedList(this); // dojox.collections.SortedList + }; + this.contains=this.containsKey=function(/* string */ k){ + // summary + // Check to see if the list has a location k + if(testObject[k]){ + return false; // bool + } + return (items[k]!=null); // bool + }; + this.containsValue=function(/* object */ o){ + // summary + // Check to see if this list contains the passed object + var e=this.getIterator(); + while (!e.atEnd()){ + var item=e.get(); + if(item.value==o){ + return true; // bool + } + } + return false; // bool + }; + this.copyTo=function(/* array */ arr, /* int */ i){ + // summary + // copy the contents of the list into array arr at index i + var e=this.getIterator(); + var idx=i; + while(!e.atEnd()){ + arr.splice(idx,0,e.get()); + idx++; + } + }; + this.entry=function(/* string */ k){ + // summary + // return the object at location k + return items[k]; // dojox.collections.DictionaryEntry + }; + this.forEach=function(/* function */ fn, /* object? */ scope){ + // summary + // functional iterator, following the mozilla spec. + dojo.forEach(q, fn, scope); + }; + this.getByIndex=function(/* int */ i){ + // summary + // return the item at index i + return q[i].valueOf(); // object + }; + this.getIterator=function(){ + // summary + // get an iterator for this object + return new dojox.collections.DictionaryIterator(items); // dojox.collections.DictionaryIterator + }; + this.getKey=function(/* int */ i){ + // summary + // return the key of the item at index i + return q[i].key; + }; + this.getKeyList=function(){ + // summary + // return an array of the keys set in this list + var arr=[]; + var e=this.getIterator(); + while (!e.atEnd()){ + arr.push(e.get().key); + } + return arr; // array + }; + this.getValueList=function(){ + // summary + // return an array of values in this list + var arr=[]; + var e=this.getIterator(); + while (!e.atEnd()){ + arr.push(e.get().value); + } + return arr; // array + }; + this.indexOfKey=function(/* string */ k){ + // summary + // return the index of the passed key. + for (var i=0; i=a.length); // bool + }; + this.get=function(){ + // summary + // Get the next member in the collection. + if(this.atEnd()){ + return null; // object + } + this.element=a[position++]; + return this.element; // object + }; + this.map=function(/* function */fn, /* object? */scope){ + // summary + // Functional iteration with optional scope. + return dojo.map(a, fn, scope); + }; + this.reset=function(){ + // summary + // reset the internal cursor. + position=0; + this.element=a[position]; + }; +} + +/* Notes: + * The DictionaryIterator no longer supports a key and value property; + * the reality is that you can use this to iterate over a JS object + * being used as a hashtable. + */ +dojox.collections.DictionaryIterator=function(/* object */obj){ + // summary + // return an object of type dojox.collections.DictionaryIterator + var a=[]; // Create an indexing array + var testObject={}; + for(var p in obj){ + if(!testObject[p]){ + a.push(obj[p]); // fill it up + } + } + var position=0; + this.element=a[position]||null; + this.atEnd=function(){ + // summary + // Test to see if the internal cursor has reached the end of the internal collection. + return (position>=a.length); // bool + }; + this.get=function(){ + // summary + // Get the next member in the collection. + if(this.atEnd()){ + return null; // object + } + this.element=a[position++]; + return this.element; // object + }; + this.map=function(/* function */fn, /* object? */scope){ + // summary + // Functional iteration with optional scope. + return dojo.map(a, fn, scope); + }; + this.reset=function() { + // summary + // reset the internal cursor. + position=0; + this.element=a[position]; + }; +}; + +} diff --git a/includes/js/dojox/collections/tests/ArrayList.js b/includes/js/dojox/collections/tests/ArrayList.js new file mode 100644 index 0000000..2645238 --- /dev/null +++ b/includes/js/dojox/collections/tests/ArrayList.js @@ -0,0 +1,83 @@ +if(!dojo._hasResource["dojox.collections.tests.ArrayList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.tests.ArrayList"] = true; +dojo.provide("dojox.collections.tests.ArrayList"); +dojo.require("dojox.collections.ArrayList"); + +tests.register("dojox.collections.tests.ArrayList", [ + function testCtor(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + t.assertEqual(4, al.count); + }, + function testAdd(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + al.add("carp"); + t.assertEqual("foo,bar,test,bull,carp", al.toString()); + al.addRange(["oof","rab"]); + t.assertEqual("foo,bar,test,bull,carp,oof,rab", al.toString()); + }, + function testClear(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + al.clear(); + t.assertEqual(0, al.count); + }, + function testClone(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + var cloned=al.clone(); + t.assertEqual(al.toString(), cloned.toString()); + }, + function testContains(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + t.assertTrue(al.contains("bar")); + t.assertFalse(al.contains("faz")); + }, + function testGetIterator(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + var itr=al.getIterator(); + while(!itr.atEnd()){ + itr.get(); + } + t.assertEqual("bull", itr.element); + }, + function testIndexOf(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + t.assertEqual(1, al.indexOf("bar")); + }, + function testInsert(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + al.insert(2, "baz"); + t.assertEqual(2, al.indexOf("baz")); + }, + function testItem(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + t.assertEqual("test", al.item(2)); + }, + function testRemove(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + al.remove("bar"); + t.assertEqual("foo,test,bull", al.toString()); + t.assertEqual(3, al.count); + }, + function testRemoveAt(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + al.removeAt(3); + t.assertEqual("foo,bar,test", al.toString()); + t.assertEqual(3, al.count); + }, + function testReverse(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + al.reverse(); + t.assertEqual("bull,test,bar,foo", al.toString()); + }, + function testSort(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + al.sort(); + t.assertEqual("bar,bull,foo,test", al.toString()); + }, + function testToArray(t){ + var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]); + var a=al.toArray(); + t.assertEqual(a.join(","), al.toString()); + } +]); + +} diff --git a/includes/js/dojox/collections/tests/BinaryTree.js b/includes/js/dojox/collections/tests/BinaryTree.js new file mode 100644 index 0000000..48acaa4 --- /dev/null +++ b/includes/js/dojox/collections/tests/BinaryTree.js @@ -0,0 +1,83 @@ +if(!dojo._hasResource["dojox.collections.tests.BinaryTree"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.tests.BinaryTree"] = true; +dojo.provide("dojox.collections.tests.BinaryTree"); +dojo.require("dojox.collections.BinaryTree"); + +tests.register("dojox.collections.tests.BinaryTree", [ + function testCtor(t){ + var bt=new dojox.collections.BinaryTree("foo"); + t.assertTrue(bt instanceof dojox.collections.BinaryTree); + }, + function testAdd(t){ + var bt=new dojox.collections.BinaryTree("foo"); + bt.add("bar"); + bt.add("baz"); + bt.add("buck"); + bt.add("shot"); + bt.add("apple"); + t.assertEqual("apple,bar,baz,buck,foo,shot",bt.toString()); + }, + function testClear(t){ + var bt=new dojox.collections.BinaryTree("foo"); + bt.add("bar"); + bt.add("baz"); + bt.add("buck"); + bt.add("shot"); + bt.add("apple"); + bt.clear(); + t.assertEqual(bt.count, 0); + }, + function testClone(t){ + var bt=new dojox.collections.BinaryTree("foo"); + bt.add("bar"); + bt.add("baz"); + bt.add("buck"); + bt.add("shot"); + bt.add("apple"); + var bt2=bt.clone(); + t.assertEqual(bt2.count, 6); + t.assertEqual(bt.toString(), bt2.toString()); + }, + function testContains(t){ + var bt=new dojox.collections.BinaryTree("foo"); + bt.add("bar"); + bt.add("baz"); + bt.add("buck"); + bt.add("shot"); + bt.add("apple"); + t.assertTrue(bt.contains("buck")); + t.assertFalse(bt.contains("duck")); + }, + function testDeleteData(t){ + var bt=new dojox.collections.BinaryTree("foo"); + bt.add("bar"); + bt.add("baz"); + bt.add("buck"); + bt.add("shot"); + bt.add("apple"); + bt.deleteData("buck"); + t.assertEqual("apple,bar,baz,foo,shot",bt.toString()); + }, + function testGetIterator(t){ + var bt=new dojox.collections.BinaryTree("foo"); + bt.add("bar"); + bt.add("baz"); + bt.add("buck"); + bt.add("shot"); + bt.add("apple"); + var itr=bt.getIterator(); + while(!itr.atEnd()){ itr.get(); } + t.assertEqual("shot", itr.element); + }, + function testSearch(t){ + var bt=new dojox.collections.BinaryTree("foo"); + bt.add("bar"); + bt.add("baz"); + bt.add("buck"); + bt.add("shot"); + bt.add("apple"); + t.assertEqual("buck", bt.search("buck").value); + } +]); + +} diff --git a/includes/js/dojox/collections/tests/Dictionary.js b/includes/js/dojox/collections/tests/Dictionary.js new file mode 100644 index 0000000..7bde6ee --- /dev/null +++ b/includes/js/dojox/collections/tests/Dictionary.js @@ -0,0 +1,82 @@ +if(!dojo._hasResource["dojox.collections.tests.Dictionary"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.tests.Dictionary"] = true; +dojo.provide("dojox.collections.tests.Dictionary"); +dojo.require("dojox.collections.Dictionary"); + +tests.register("dojox.collections.tests.Dictionary", [ + function testCtor(t){ + var d=new dojox.collections.Dictionary(); + t.assertTrue(d instanceof dojox.collections.Dictionary); + }, + function testAdd(t){ + var d=new dojox.collections.Dictionary(); + d.add("foo","bar"); + t.assertEqual("bar", d.item("foo").valueOf()); + }, + function testClear(t){ + var d=new dojox.collections.Dictionary(); + d.add("foo","bar"); + d.clear() + t.assertEqual(0, d.count); + }, + function testClone(t){ + var d=new dojox.collections.Dictionary(); + d.add("baz","fab"); + d.add("buck","shot"); + d.add("apple","orange"); + var d2 = d.clone(); + t.assertTrue(d2.contains("baz")); + }, + function testContains(t){ + var d=new dojox.collections.Dictionary(); + d.add("foo","bar"); + d.add("baz","fab"); + d.add("buck","shot"); + d.add("apple","orange"); + t.assertTrue(d.contains("baz")); + }, + function testContainsKey(t){ + var d=new dojox.collections.Dictionary(); + d.add("foo","bar"); + d.add("baz","fab"); + d.add("buck","shot"); + d.add("apple","orange"); + t.assertTrue(d.containsKey("buck")); + }, + function testContainsValue(t){ + var d=new dojox.collections.Dictionary(); + d.add("foo","bar"); + d.add("baz","fab"); + d.add("buck","shot"); + d.add("apple","orange"); + t.assertTrue(d.containsValue("shot")); + }, + function testGetKeyList(t){ + var d=new dojox.collections.Dictionary(); + d.add("foo","bar"); + d.add("baz","fab"); + d.add("buck","shot"); + d.add("apple","orange"); + t.assertEqual("foo,baz,buck,apple", d.getKeyList().join(",")); + }, + function testGetValueList(t){ + var d=new dojox.collections.Dictionary(); + d.add("foo","bar"); + d.add("baz","fab"); + d.add("buck","shot"); + d.add("apple","orange"); + t.assertEqual("bar,fab,shot,orange", d.getValueList().join(",")); + }, + function testRemove(t){ + var d=new dojox.collections.Dictionary(); + d.add("foo","bar"); + d.add("baz","fab"); + d.add("buck","shot"); + d.add("apple","orange"); + d.remove("baz"); + t.assertEqual(3, d.count); + t.assertEqual(undefined, d.item("baz")); + } +]); + +} diff --git a/includes/js/dojox/collections/tests/Queue.js b/includes/js/dojox/collections/tests/Queue.js new file mode 100644 index 0000000..5ac61bc --- /dev/null +++ b/includes/js/dojox/collections/tests/Queue.js @@ -0,0 +1,49 @@ +if(!dojo._hasResource["dojox.collections.tests.Queue"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.tests.Queue"] = true; +dojo.provide("dojox.collections.tests.Queue"); +dojo.require("dojox.collections.Queue"); + +tests.register("dojox.collections.tests.Queue", [ + function testCtor(t){ + var q=new dojox.collections.Queue(["foo","bar","test","bull"]); + t.assertEqual(4, q.count); + }, + function testClear(t){ + var q=new dojox.collections.Queue(["foo","bar","test","bull"]); + q.clear(); + t.assertEqual(0, q.count); + }, + function testClone(t){ + var q=new dojox.collections.Queue(["foo","bar","test","bull"]); + var cloned=q.clone(); + t.assertEqual(q.count, cloned.count); + t.assertEqual(q.toArray().join(), cloned.toArray().join()); + }, + function testContains(t){ + var q=new dojox.collections.Queue(["foo","bar","test","bull"]); + t.assertTrue(q.contains("bar")); + t.assertFalse(q.contains("faz")); + }, + function testGetIterator(t){ + var q=new dojox.collections.Queue(["foo","bar","test","bull"]); + var itr=q.getIterator(); + while(!itr.atEnd()){ itr.get(); } + t.assertEqual("bull", itr.element); + }, + function testPeek(t){ + var q=new dojox.collections.Queue(["foo","bar","test","bull"]); + t.assertEqual("foo", q.peek()); + }, + function testDequeue(t){ + var q=new dojox.collections.Queue(["foo","bar","test","bull"]); + t.assertEqual("foo", q.dequeue()); + t.assertEqual("bar,test,bull", q.toArray().join(",")); + }, + function testEnqueue(t){ + var q=new dojox.collections.Queue(["foo","bar","test","bull"]); + q.enqueue("bull"); + t.assertEqual("bull", q.toArray().pop()); + } +]); + +} diff --git a/includes/js/dojox/collections/tests/Set.js b/includes/js/dojox/collections/tests/Set.js new file mode 100644 index 0000000..d548223 --- /dev/null +++ b/includes/js/dojox/collections/tests/Set.js @@ -0,0 +1,35 @@ +if(!dojo._hasResource["dojox.collections.tests.Set"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.tests.Set"] = true; +dojo.provide("dojox.collections.tests.Set"); +dojo.require("dojox.collections.Set"); + +(function(){ + var dxcs=dojox.collections.Set; + var a = ["apple","bear","candy","donut","epiphite","frank"]; + var b = ["bear","epiphite","google","happy","joy"]; + tests.register("dojox.collections.tests.Set", [ + function testUnion(t){ + var union=dxcs.union(a,b); + t.assertEqual("apple,bear,candy,donut,epiphite,frank,google,happy,joy", union.toArray().join(',')); + }, + function testIntersection(t){ + var itsn=dxcs.intersection(a,b); + t.assertEqual("bear,epiphite", itsn.toArray().join(",")); + t.assertEqual("bear", dxcs.intersection(["bear","apple"], ["bear"])); + }, + function testDifference(t){ + var d=dxcs.difference(a,b); + t.assertEqual("apple,candy,donut,frank",d.toArray().join(',')); + }, + function testIsSubSet(t){ + t.assertFalse(dxcs.isSubSet(a,["bear","candy"])); + t.assertTrue(dxcs.isSubSet(["bear","candy"],a)); + }, + function testIsSuperSet(t){ + t.assertTrue(dxcs.isSuperSet(a,["bear","candy"])); + t.assertFalse(dxcs.isSuperSet(["bear","candy"],a)); + } + ]); +})(); + +} diff --git a/includes/js/dojox/collections/tests/SortedList.js b/includes/js/dojox/collections/tests/SortedList.js new file mode 100644 index 0000000..dfb4ffa --- /dev/null +++ b/includes/js/dojox/collections/tests/SortedList.js @@ -0,0 +1,168 @@ +if(!dojo._hasResource["dojox.collections.tests.SortedList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.tests.SortedList"] = true; +dojo.provide("dojox.collections.tests.SortedList"); +dojo.require("dojox.collections.SortedList"); + +tests.register("dojox.collections.tests.SortedList", [ + function testCtor(t){ + var sl=new dojox.collections.SortedList(); + t.assertTrue(sl instanceof dojox.collections.SortedList); + }, + function testAdd(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + t.assertEqual("bar", sl.item("foo").valueOf()); + }, + function testClear(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.clear(); + t.assertEqual(0, sl.count); + }, + function testClone(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + var sl2=sl.clone(); + t.assertTrue(sl2.contains("baz")); + }, + function testContains(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + t.assertTrue(sl.contains("baz")); + t.assertFalse(sl.contains("faz")); + }, + function testContainsKey(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + t.assertTrue(sl.containsKey("buck")); + t.assertFalse(sl.containsKey("faz")); + }, + function testContainsValue(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + t.assertTrue(sl.containsValue("shot")); + t.assertFalse(sl.containsValue("faz")); + }, + function testGetKeyList(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + t.assertEqual("foo,baz,buck,apple",sl.getKeyList().join(',')); + }, + function testGetValueList(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + t.assertEqual("bar,fab,shot,orange",sl.getValueList().join(',')); + }, + function testCopyTo(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + var arr=["bek"]; + sl.copyTo(arr,0); + t.assertEqual("bar,fab,shot,orange,bek", arr.join(',')); + }, + function testGetByIndex(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + t.assertEqual("shot", sl.getByIndex(2)); + }, + function testGetKey(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + t.assertEqual("apple", sl.getKey(0)); + }, + function testIndexOfKey(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + t.assertEqual(0, sl.indexOfKey("apple")); + }, + function testIndexOfValue(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + t.assertEqual(3, sl.indexOfValue("bar")); + }, + function testRemove(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + sl.remove("baz"); + t.assertEqual(3, sl.count); + t.assertEqual(undefined, sl.item("baz")); + }, + function testRemoveAt(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + sl.removeAt(2); + t.assertEqual(undefined, sl.item("buck")); + }, + function testReplace(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + sl.replace("buck","dollar"); + t.assertEqual(sl.item("buck").valueOf(), "dollar"); + }, + function testSetByIndex(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + sl.setByIndex(0, "bar"); + t.assertEqual("bar", sl.getByIndex(0)); + }, + function testSorting(t){ + var sl=new dojox.collections.SortedList(); + sl.add("foo","bar"); + sl.add("baz","fab"); + sl.add("buck","shot"); + sl.add("apple","orange"); + + var a=[]; + sl.forEach(function(item){ + a.push(item); + }); + t.assertEqual("orange,fab,shot,bar", a.join()); + } +]); + +} diff --git a/includes/js/dojox/collections/tests/Stack.js b/includes/js/dojox/collections/tests/Stack.js new file mode 100644 index 0000000..7bf4e79 --- /dev/null +++ b/includes/js/dojox/collections/tests/Stack.js @@ -0,0 +1,49 @@ +if(!dojo._hasResource["dojox.collections.tests.Stack"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.tests.Stack"] = true; +dojo.provide("dojox.collections.tests.Stack"); +dojo.require("dojox.collections.Stack"); + +tests.register("dojox.collections.tests.Stack", [ + function testCtor(t){ + var s=new dojox.collections.Stack(["foo","bar","test","bull"]); + t.assertEqual(4, s.count); + }, + function testClear(t){ + var s=new dojox.collections.Stack(["foo","bar","test","bull"]); + s.clear(); + t.assertEqual(0, s.count); + }, + function testClone(t){ + var s=new dojox.collections.Stack(["foo","bar","test","bull"]); + var cloned=s.clone(); + t.assertEqual(s.count, cloned.count); + t.assertEqual(s.toArray().join(), cloned.toArray().join()); + }, + function testContains(t){ + var s=new dojox.collections.Stack(["foo","bar","test","bull"]); + t.assertTrue(s.contains("bar")); + t.assertFalse(s.contains("faz")); + }, + function testGetIterator(t){ + var s=new dojox.collections.Stack(["foo","bar","test","bull"]); + var itr=s.getIterator(); + while(!itr.atEnd()){ itr.get(); } + t.assertEqual("bull", itr.element); + }, + function testPeek(t){ + var s=new dojox.collections.Stack(["foo","bar","test","bull"]); + t.assertEqual("bull", s.peek()); + }, + function testPop(t){ + var s=new dojox.collections.Stack(["foo","bar","test","bull"]); + t.assertEqual("bull", s.pop()); + t.assertEqual("test", s.pop()); + }, + function testPush(t){ + var s=new dojox.collections.Stack(["foo","bar","test","bull"]); + s.push("bug"); + t.assertEqual("bug", s.peek()); + } +]); + +} diff --git a/includes/js/dojox/collections/tests/_base.js b/includes/js/dojox/collections/tests/_base.js new file mode 100644 index 0000000..f58a82c --- /dev/null +++ b/includes/js/dojox/collections/tests/_base.js @@ -0,0 +1,84 @@ +if(!dojo._hasResource["dojox.collections.tests._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.tests._base"] = true; +dojo.provide("dojox.collections.tests._base"); +dojo.require("dojox.collections"); + +tests.register("dojox.collections.tests._base", [ + function testDictionaryEntry(t){ + var d=new dojox.collections.DictionaryEntry("foo","bar"); + t.assertEqual("bar", d.valueOf()); + t.assertEqual("bar", d.toString()); + }, + + function testIterator(t){ + var itr=new dojox.collections.Iterator(["foo","bar","baz","zoo"]); + t.assertEqual("foo", itr.element); // test initialization + t.assertTrue(!itr.atEnd()); + t.assertEqual("foo", itr.get()); // make sure the first get doesn't advance. + t.assertEqual("bar", itr.get()); + t.assertEqual("baz", itr.get()); + t.assertEqual("zoo", itr.get()); + t.assertTrue(itr.atEnd()); + t.assertEqual(null, itr.get()); + + itr.reset(); + t.assertTrue(!itr.atEnd()); + t.assertEqual("foo", itr.element); + + // test map + var a=itr.map(function(elm){ + return elm+"-mapped"; + }); + itr=new dojox.collections.Iterator(a); + t.assertEqual("foo-mapped", itr.element); // test initialization + t.assertTrue(!itr.atEnd()); + t.assertEqual("foo-mapped", itr.get()); // make sure the first get doesn't advance. + t.assertEqual("bar-mapped", itr.get()); + t.assertEqual("baz-mapped", itr.get()); + t.assertEqual("zoo-mapped", itr.get()); + t.assertTrue(itr.atEnd()); + t.assertEqual(null, itr.get()); + }, + + function testDictionaryIterator(t){ + /* + in the context of any of the Dictionary-based collections, the + element would normally return a DictionaryEntry. However, since + the DictionaryIterator is really an iterator of pure objects, + we will just test with an object here. This means all property + names are lost in the translation, but...that's why there's a + DictionaryEntry object :) + */ + var itr=new dojox.collections.DictionaryIterator({ + first:"foo", second:"bar", third:"baz", fourth:"zoo" + }); + t.assertEqual("foo", itr.element); // test initialization + t.assertTrue(!itr.atEnd()); + t.assertEqual("foo", itr.get()); // make sure the first get doesn't advance. + t.assertEqual("bar", itr.get()); + t.assertEqual("baz", itr.get()); + t.assertEqual("zoo", itr.get()); + t.assertTrue(itr.atEnd()); + t.assertEqual(null, itr.get()); + + itr.reset(); + t.assertTrue(!itr.atEnd()); + t.assertEqual("foo", itr.element); + + // test map + var a=itr.map(function(elm){ + return elm+"-mapped"; + }); + itr=new dojox.collections.Iterator(a); + t.assertEqual("foo-mapped", itr.element); // test initialization + t.assertTrue(!itr.atEnd()); + t.assertEqual("foo-mapped", itr.get()); // make sure the first get doesn't advance. + t.assertEqual("bar-mapped", itr.get()); + t.assertEqual("baz-mapped", itr.get()); + t.assertEqual("zoo-mapped", itr.get()); + t.assertTrue(itr.atEnd()); + t.assertEqual(null, itr.get()); + } +]); + +} diff --git a/includes/js/dojox/collections/tests/collections.js b/includes/js/dojox/collections/tests/collections.js new file mode 100644 index 0000000..4fb2634 --- /dev/null +++ b/includes/js/dojox/collections/tests/collections.js @@ -0,0 +1,19 @@ +if(!dojo._hasResource["dojox.collections.tests.collections"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.collections.tests.collections"] = true; +dojo.provide("dojox.collections.tests.collections"); +dojo.require("dojox.collections"); + +try{ + dojo.require("dojox.collections.tests._base"); + dojo.require("dojox.collections.tests.ArrayList"); + dojo.require("dojox.collections.tests.BinaryTree"); + dojo.require("dojox.collections.tests.Dictionary"); + dojo.require("dojox.collections.tests.Queue"); + dojo.require("dojox.collections.tests.Set"); + dojo.require("dojox.collections.tests.SortedList"); + dojo.require("dojox.collections.tests.Stack"); +}catch(e){ + doh.debug(e); +} + +} diff --git a/includes/js/dojox/collections/tests/runTests.html b/includes/js/dojox/collections/tests/runTests.html new file mode 100644 index 0000000..37f26a6 --- /dev/null +++ b/includes/js/dojox/collections/tests/runTests.html @@ -0,0 +1,9 @@ + + + + Dojox.wire Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/color.js b/includes/js/dojox/color.js new file mode 100644 index 0000000..c44cd1c --- /dev/null +++ b/includes/js/dojox/color.js @@ -0,0 +1,6 @@ +if(!dojo._hasResource["dojox.color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.color"] = true; +dojo.provide("dojox.color"); +dojo.require("dojox.color._base"); + +} diff --git a/includes/js/dojox/color/Colorspace.js b/includes/js/dojox/color/Colorspace.js new file mode 100644 index 0000000..b40b06d --- /dev/null +++ b/includes/js/dojox/color/Colorspace.js @@ -0,0 +1,556 @@ +if(!dojo._hasResource["dojox.color.Colorspace"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.color.Colorspace"] = true; +dojo.provide("dojox.color.Colorspace"); +dojo.require("dojox.math.matrix"); + +dojox.color.Colorspace=new (function(){ + var dxc=dojox.color; + var dxm=dojox.math.matrix; + var self=this; + var wpMap={ + "2":{ + "E": { x:1/3, y:1/3, t:5400 }, + "D50": { x:0.34567, y:0.3585, t:5000 }, + "D55": { x:0.33242, y:0.34743, t:5500 }, + "D65": { x:0.31271, y:0.32902, t:6500 }, + "D75": { x:0.29902, y:0.31485, t:7500 }, + "A": { x:0.44757, y:0.40745, t:2856 }, + "B": { x:0.34842, y:0.35161, t:4874 }, + "C": { x:0.31006, y:0.31616, t:6774 }, + "9300": { x:0.2848, y:0.2932, t:9300 }, + "F2": { x:0.37207, y:0.37512, t:4200 }, + "F7": { x:0.31285, y:0.32918, t:6500 }, + "F11": { x:0.38054, y:0.37691, t:4000 } + }, + "10":{ + "E": { x:1/3, y:1/3, t:5400 }, + "D50": { x:0.34773, y:0.35952, t:5000 }, + "D55": { x:0.33411, y:0.34877, t:5500 }, + "D65": { x:0.31382, y:0.331, t:6500 }, + "D75": { x:0.29968, y:0.3174, t:7500 }, + "A": { x:0.45117, y:0.40594, t:2856 }, + "B": { x:0.3498, y:0.3527, t:4874 }, + "C": { x:0.31039, y:0.31905, t:6774 }, + "F2": { x:0.37928, y:0.36723, t:4200 }, + "F7": { x:0.31565, y:0.32951, t:6500 }, + "F11": { x:0.38543, y:0.3711, t:4000 } + } + }; + + var profiles={ + "Adobe RGB 98":[2.2, "D65", 0.64, 0.33, 0.297361, 0.21, 0.71, 0.627355, 0.15, 0.06, 0.075285], + "Apple RGB":[1.8, "D65", 0.625, 0.34, 0.244634, 0.28, 0.595, 0.672034, 0.155, 0.07, 0.083332], + "Best RGB":[2.2, "D50", 0.7347, 0.2653, 0.228457, 0.215, 0.775, 0.737352, 0.13, 0.035, 0.034191], + "Beta RGB":[2.2, "D50", 0.6888, 0.3112, 0.303273, 0.1986, 0.7551, 0.663786, 0.1265, 0.0352, 0.032941], + "Bruce RGB":[2.2, "D65", 0.64, 0.33, 0.240995, 0.28, 0.65, 0.683554, 0.15, 0.06, 0.075452], + "CIE RGB":[2.2, "E", 0.735, 0.265, 0.176204, 0.274, 0.717, 0.812985, 0.167, 0.009, 0.010811], + "ColorMatch RGB":[1.8, "D50", 0.63, 0.34, 0.274884, 0.295, 0.605, 0.658132, 0.15, 0.075, 0.066985], + "DON RGB 4":[2.2, "D50", 0.696, 0.3, 0.27835, 0.215, 0.765, 0.68797, 0.13, 0.035, 0.03368], + "ECI RGB":[1.8, "D50", 0.67, 0.33, 0.32025, 0.21, 0.71, 0.602071, 0.14, 0.08, 0.077679], + "EktaSpace PS5":[2.2, "D50", 0.695, 0.305, 0.260629, 0.26, 0.7, 0.734946, 0.11, 0.005, 0.004425], + "NTSC RGB":[2.2, "C", 0.67, 0.33, 0.298839, 0.21, 0.71, 0.586811, 0.14, 0.08, 0.11435], + "PAL/SECAM RGB":[2.2, "D65", 0.64, 0.33, 0.222021, 0.29, 0.6, 0.706645, 0.15, 0.06, 0.071334], + "Pro Photo RGB":[1.8, "D50", 0.7347, 0.2653, 0.28804, 0.1596, 0.8404, 0.711874, 0.0366, 0.0001, 0.000086], + "SMPTE/C RGB":[2.2, "D65", 0.63, 0.34, 0.212395, 0.31, 0.595, 0.701049, 0.155, 0.07, 0.086556], + "sRGB":[2.2, "D65", 0.64, 0.33, 0.212656, 0.3, 0.6, 0.715158, 0.15, 0.06, 0.072186], + "Wide Gamut RGB":[2.2, "D50", 0.735, 0.265, 0.258187, 0.115, 0.826, 0.724938, 0.157, 0.018, 0.016875] + }; + + var adaptors={ + "XYZ scaling":{ + ma: [[1,0,0], [0,1,0], [0,0,1]], + mai: [[1,0,0], [0,1,0], [0,0,1]] + }, + "Bradford":{ + ma: [[0.8951, -0.7502, 0.0389], [0.2664, 1.7135, -0.0685], [-0.1614, 0.0367, 1.0296]], + mai: [[0.986993, 0.432305, -0.008529], [-0.147054, 0.51836, 0.040043], [0.159963, 0.049291, 0.968487]] + }, + "Von Kries":{ + ma: [[0.40024, -0.2263, 0], [0.7076, 1.16532, 0], [-0.08081, 0.0457, 0.91822]], + mai: [[1.859936, 0.361191, 0], [-1.129382, 0.638812, 0], [0.219897, -0.000006, 1.089064]] + } + }; + + var cMaps={ + "XYZ":{ + "xyY":function(xyz, kwArgs){ + kwArgs=dojo.mixin({ + whitepoint:"D65", + observer:"10", + useApproximation:true + }, kwArgs||{}); + var wp=self.whitepoint(kwArgs.whitepoint, kwArgs.observer); + var sum=xyz.X+xyz.Y+xyz.Z; + if(sum==0){ var x=wp.x, y=wp.y; } + else{ var x=xyz.X/sum, y=xyz.Y/sum; } + return { x:x, y:y, Y:xyz.Y }; + }, + "Lab":function(xyz, kwArgs){ + kwArgs=dojo.mixin({ + whitepoint:"D65", + observer:"10", + useApproximation:true + }, kwArgs||{}); + + var kappa=self.kappa(kwArgs.useApproximation), epsilon=self.epsilon(kwArgs.useApproximation); + var wp=self.whitepoint(kwArgs.whitepoint, kwArgs.observer); + var xr=xyz.X/wp.x, yr=xyz.Y/wp.y, zr=xyz.z/wp.z; + var fx=(xr>epsilon)?Math.pow(xr,1/3):(kappa*xr+16)/116; + var fy=(yr>epsilon)?Math.pow(yr,1/3):(kappa*yr+16)/116; + var fz=(zr>epsilon)?Math.pow(zr,1/3):(kappa*zr+16)/116; + var L=116*fy-16, a=500*(fx-fy), b=200*(fy-fz); + return { L:L, a:a, b:b }; + }, + "Luv": function(xyz, kwArgs){ + kwArgs=dojo.mixin({ + whitepoint:"D65", + observer:"10", + useApproximation:true + }, kwArgs||{}); + + var kappa=self.kappa(kwArgs.useApproximation), epsilon=self.epsilon(kwArgs.useApproximation); + var wp=self.whitepoint(kwArgs.whitepoint, kwArgs.observer); + var ud=(4*xyz.X)/(xyz.X+15*xyz.Y+3*xyz.Z); + var vd=(9*xyz.Y)/(xyz.X+15*xyz.Y+3*xyz.Z); + var udr=(4*wp.x)/(wp.x+15*wp.y+3*wp.z); + var vdr=(9*wp.y)/(wp.x+15*wp.y+3*wp.z); + var yr=xyz.Y/wp.y; + var L=(yr>epsilon)?116*Math.pow(yr, 1/3)-16:kappa*yr; + var u=13*L*(ud-udr); + var v=13*L*(vd-vdr); + return { L:L, u:u, v:v }; + } + }, + "xyY":{ + "XYZ":function(xyY){ + if(xyY.y==0){ var X=0, Y=0, Z=0; } + else{ + var X=(xyY.x*xyY.Y)/xyY.y; + var Y=xyY.Y; + var Z=((1-xyY.x-xyY.y)*xyY.Y)/xyY.y; + } + return { X:X, Y:Y, Z:Z }; + } + }, + "Lab":{ + "XYZ": function(lab, kwArgs){ + kwArgs=dojo.mixin({ + whitepoint:"D65", + observer:"10", + useApproximation:true + }, kwArgs||{}); + + var b=kwArgs.useApproximation, kappa=self.kappa(b), epsilon=self.epsilon(b); + var wp=self.whitepoint(kwArgs.whitepoint, kwArgs.observer); + var yr=(lab.L>(kappa*epsilon))?Math.pow((lab.L+16)/116, 3):lab.L/kappa; + var fy=(yr>epsilon)?(lab.L+16)/116:(kappa*yr+16)/116; + var fx=(lab.a/500)+fy; + var fz=fy-(lab.b/200); + var fxcube=Math.pow(fx, 3), fzcube=Math.pow(fz, 3); + var xr=(fxcube>epsilon)?fxcube:(116*fx-16)/kappa; + var zr=(fzcube>epsilon)?fzcube:(116*fz-16)/kappa; + return { X: xr*wp.x, Y: yr*wp.y, Z: zr*wp.z }; + }, + "LCHab": function(lab){ + var L=lab.L, C=Math.pow(lab.a*lab.a+lab.b*lab.b, 0.5), H=Math.atan(lab.b, lab.a)*(180/Math.PI); + if(H<0){ H+=360; } + if(H<360){ H-=360; } + return { L:L, C:C, H:H }; + } + }, + "LCHab":{ + "Lab":function(lch){ + var hRad=lch.H*(Math.PI/180), L=lch.L, a=lch.C/Math.pow(Math.pow(Math.tan(hRad),2)+1, 0.5); + if(90180){ b = -b; } + return { L: L, a:a, b:b }; + } + }, + "Luv":{ + "XYZ": function(Luv, kwArgs){ + kwArgs=dojo.mixin({ + whitepoint:"D65", + observer:"10", + useApproximation:true + }, kwArgs||{}); + + var b=kwArgs.useApproximation, kappa=self.kappa(b), epsilon=self.epsilon(b); + var wp=self.whitepoint(kwArgs.whitepoint, kwArgs.observer); + var uz=(4*wp.x)/(wp.x+15*wp.y+3*wp.z); + var vz=(9*wp.y)/(wp.x+15*wp.y+3*wp.z); + var Y=(Luv.L>kappa*epsilon)?Math.pow((Luv.L+16)/116, 3):Luv.L/kappa; + var a=(1/3)*(((52*Luv.L)/(Luv.u+13*Luv.L*uz))-1); + var b=-5*Y, c=-(1/3), d=Y*(((39*Luv.L)/(Luv.v+13*Luv.L*vz))-5); + var X=(d-b)/(a-c), Z=X*a+b; + return { X:X, Y:Y, Z:Z }; + }, + "LCHuv": function(Luv){ + var L=Luv.L, C=Math.pow(Luv.u*Luv.u+Luv.v*Luv*v, 0.5), H=Math.atan(Luv.v, Luv.u)*(180/Math.PI); + if(H<0){ H+=360; } + if(H>360){ H-=360; } + return { L:L, C:C, H:H }; + } + }, + "LCHuv":{ + "Luv": function(LCH){ + var hRad=LCH.H*(Math.PI/180); + var L=LCH.L, u=LCH.C/Math.pow(Math.pow(Math.tan(hRad),2)+1, 0.5); + var v=Math.pow(LCH.C*LCH.C-u*u, 0.5); + if(90270){ u*=-1; } + if(LCH.H>180){ v*=-1; } + return { L:L, u:u, v:v }; + } + } + }; + var converters={ + "CMY":{ + "CMYK":function(obj, kwArgs){ return dxc.fromCmy(obj).toCmyk(); }, + "HSL":function(obj, kwArgs){ return dxc.fromCmy(obj).toHsl(); }, + "HSV":function(obj, kwArgs){ return dxc.fromCmy(obj).toHsv(); }, + "Lab":function(obj, kwArgs){ return cMaps["XYZ"]["Lab"](dxc.fromCmy(obj).toXYZ(kwArgs)); }, + "LCHab":function(obj, kwArgs){ return cMaps["Lab"]["LCHab"](converters["CMY"]["Lab"](obj)); }, + "LCHuv":function(obj, kwArgs){ return cMaps["LCHuv"]["Luv"](cMaps["Luv"]["XYZ"](dxc.fromCmy(obj).toXYZ(kwArgs))); }, + "Luv":function(obj, kwArgs){ return cMaps["Luv"]["XYZ"](dxc.fromCmy(obj).toXYZ(kwArgs)); }, + "RGB":function(obj, kwArgs){ return dxc.fromCmy(obj); }, + "XYZ":function(obj, kwArgs){ return dxc.fromCmy(obj).toXYZ(kwArgs); }, + "xyY":function(obj, kwArgs){ return cMaps["XYZ"]["xyY"](dxc.fromCmy(obj).toXYZ(kwArgs)); } + }, + "CMYK":{ + "CMY":function(obj, kwArgs){ return dxc.fromCmyk(obj).toCmy(); }, + "HSL":function(obj, kwArgs){ return dxc.fromCmyk(obj).toHsl(); }, + "HSV":function(obj, kwArgs){ return dxc.fromCmyk(obj).toHsv(); }, + "Lab":function(obj, kwArgs){ return cMaps["XYZ"]["Lab"](dxc.fromCmyk(obj).toXYZ(kwArgs)); }, + "LCHab":function(obj, kwArgs){ return cMaps["Lab"]["LCHab"](converters["CMYK"]["Lab"](obj)); }, + "LCHuv":function(obj, kwArgs){ return cMaps["LCHuv"]["Luv"](cMaps["Luv"]["XYZ"](dxc.fromCmyk(obj).toXYZ(kwArgs))); }, + "Luv":function(obj, kwArgs){ return cMaps["Luv"]["XYZ"](dxc.fromCmyk(obj).toXYZ(kwArgs)); }, + "RGB":function(obj, kwArgs){ return dxc.fromCmyk(obj); }, + "XYZ":function(obj, kwArgs){ return dxc.fromCmyk(obj).toXYZ(kwArgs); }, + "xyY":function(obj, kwArgs){ return cMaps["XYZ"]["xyY"](dxc.fromCmyk(obj).toXYZ(kwArgs)); } + }, + "HSL":{ + "CMY":function(obj, kwArgs){ return dxc.fromHsl(obj).toCmy(); }, + "CMYK":function(obj, kwArgs){ return dxc.fromHsl(obj).toCmyk(); }, + "HSV":function(obj, kwArgs){ return dxc.fromHsl(obj).toHsv(); }, + "Lab":function(obj, kwArgs){ return cMaps["XYZ"]["Lab"](dxc.fromHsl(obj).toXYZ(kwArgs)); }, + "LCHab":function(obj, kwArgs){ return cMaps["Lab"]["LCHab"](converters["CMYK"]["Lab"](obj)); }, + "LCHuv":function(obj, kwArgs){ return cMaps["LCHuv"]["Luv"](cMaps["Luv"]["XYZ"](dxc.fromHsl(obj).toXYZ(kwArgs))); }, + "Luv":function(obj, kwArgs){ return cMaps["Luv"]["XYZ"](dxc.fromHsl(obj).toXYZ(kwArgs)); }, + "RGB":function(obj, kwArgs){ return dxc.fromHsl(obj); }, + "XYZ":function(obj, kwArgs){ return dxc.fromHsl(obj).toXYZ(kwArgs); }, + "xyY":function(obj, kwArgs){ return cMaps["XYZ"]["xyY"](dxc.fromHsl(obj).toXYZ(kwArgs)); } + }, + "HSV":{ + "CMY":function(obj, kwArgs){ return dxc.fromHsv(obj).toCmy(); }, + "CMYK":function(obj, kwArgs){ return dxc.fromHsv(obj).toCmyk(); }, + "HSL":function(obj, kwArgs){ return dxc.fromHsv(obj).toHsl(); }, + "Lab":function(obj, kwArgs){ return cMaps["XYZ"]["Lab"](dxc.fromHsv(obj).toXYZ(kwArgs)); }, + "LCHab":function(obj, kwArgs){ return cMaps["Lab"]["LCHab"](converters["CMYK"]["Lab"](obj)); }, + "LCHuv":function(obj, kwArgs){ return cMaps["LCHuv"]["Luv"](cMaps["Luv"]["XYZ"](dxc.fromHsv(obj).toXYZ(kwArgs))); }, + "Luv":function(obj, kwArgs){ return cMaps["Luv"]["XYZ"](dxc.fromHsv(obj).toXYZ(kwArgs)); }, + "RGB":function(obj, kwArgs){ return dxc.fromHsv(obj); }, + "XYZ":function(obj, kwArgs){ return dxc.fromHsv(obj).toXYZ(kwArgs); }, + "xyY":function(obj, kwArgs){ return cMaps["XYZ"]["xyY"](dxc.fromHsv(obj).toXYZ(kwArgs)); } + }, + "Lab":{ + "CMY":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Lab"]["XYZ"](obj, kwArgs)).toCmy(); }, + "CMYK":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Lab"]["XYZ"](obj, kwArgs)).toCmyk(); }, + "HSL":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Lab"]["XYZ"](obj, kwArgs)).toHsl(); }, + "HSV":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Lab"]["XYZ"](obj, kwArgs)).toHsv(); }, + "LCHab":function(obj, kwArgs){ return cMaps["Lab"]["LCHab"](obj, kwArgs); }, + "LCHuv":function(obj, kwArgs){ return cMaps["Luv"]["LCHuv"](cMaps["Lab"]["XYZ"](obj, kwArgs), kwArgs); }, + "Luv":function(obj, kwArgs){ return cMaps["XYZ"]["Luv"](cMaps["Lab"]["XYZ"](obj, kwArgs), kwArgs); }, + "RGB":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Lab"]["XYZ"](obj, kwArgs)); }, + "XYZ":function(obj, kwArgs){ return cMaps["Lab"]["XYZ"](obj, kwArgs); }, + "xyY":function(obj, kwArgs){ return cMaps["XYZ"]["xyY"](cMaps["Lab"]["XYZ"](obj, kwArgs), kwArgs); } + }, + "LCHab":{ + "CMY":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Lab"]["XYZ"](cMaps["LCHab"]["Lab"](obj), kwArgs), kwArgs).toCmy(); }, + "CMYK":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Lab"]["XYZ"](cMaps["LCHab"]["Lab"](obj), kwArgs), kwArgs).toCmyk(); }, + "HSL":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Lab"]["XYZ"](cMaps["LCHab"]["Lab"](obj), kwArgs), kwArgs).toHsl(); }, + "HSV":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Lab"]["XYZ"](cMaps["LCHab"]["Lab"](obj), kwArgs), kwArgs).toHsv(); }, + "Lab":function(obj, kwArgs){ return cMaps["Lab"]["LCHab"](obj, kwArgs); }, + "LCHuv":function(obj, kwArgs){ return cMaps["Luv"]["LCHuv"](cMaps["XYZ"]["Luv"](cMaps["Lab"]["XYZ"](cMaps["LCHab"]["Lab"](obj), kwArgs), kwArgs), kwArgs);}, + "Luv":function(obj, kwArgs){ return cMaps["XYZ"]["Luv"](cMaps["Lab"]["XYZ"](cMaps["LCHab"]["Lab"](obj), kwArgs), kwArgs);}, + "RGB":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Lab"]["XYZ"](cMaps["LCHab"]["Lab"](obj), kwArgs), kwArgs); }, + "XYZ":function(obj, kwArgs){ return cMaps["Lab"]["XYZ"](cMaps["LCHab"]["Lab"](obj, kwArgs), kwArgs); }, + "xyY":function(obj, kwArgs){ return cMaps["XYZ"]["xyY"](cMaps["Lab"]["XYZ"](cMaps["LCHab"]["Lab"](obj), kwArgs), kwArgs); } + }, + "LCHuv":{ + "CMY":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Luv"]["XYZ"](cMaps["LCHuv"]["Luv"](obj), kwArgs), kwArgs).toCmy(); }, + "CMYK":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Luv"]["XYZ"](cMaps["LCHuv"]["Luv"](obj), kwArgs), kwArgs).toCmyk(); }, + "HSL":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Luv"]["XYZ"](cMaps["LCHuv"]["Luv"](obj), kwArgs), kwArgs).toHsl(); }, + "HSV":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Luv"]["XYZ"](cMaps["LCHuv"]["Luv"](obj), kwArgs), kwArgs).toHsv(); }, + "Lab":function(obj, kwArgs){ return cMaps["XYZ"]["Lab"](cMaps["Luv"]["XYZ"](cMaps["LCHuv"]["Luv"](obj), kwArgs), kwArgs); }, + "LCHab":function(obj, kwArgs){ return cMaps["Lab"]["LCHab"](cMaps["XYZ"]["Lab"](cMaps["Luv"]["XYZ"](cMaps["LCHuv"]["Luv"](obj), kwArgs), kwArgs), kwArgs); }, + "Luv":function(obj, kwArgs){ return cMaps["LCHuv"]["Luv"](obj, kwArgs); }, + "RGB":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Luv"]["XYZ"](cMaps["LCHuv"]["Luv"](obj), kwArgs), kwArgs); }, + "XYZ":function(obj, kwArgs){ return cMaps["Luv"]["XYZ"](cMaps["LCHuv"]["Luv"](obj), kwArgs); }, + "xyY":function(obj, kwArgs){ return cMaps["XYZ"]["xyY"](cMaps["Luv"]["XYZ"](cMaps["LCHuv"]["Luv"](obj), kwArgs), kwArgs); }, + }, + "Luv":{ + "CMY":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Luv"]["XYZ"](obj, kwArgs), kwArgs).toCmy(); }, + "CMYK":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Luv"]["XYZ"](obj, kwArgs), kwArgs).toCmyk(); }, + "HSL":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Luv"]["XYZ"](obj, kwArgs), kwArgs).toHsl(); }, + "HSV":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Luv"]["XYZ"](obj, kwArgs), kwArgs).toHsv(); }, + "Lab":function(obj, kwArgs){ return cMaps["XYZ"]["Lab"](cMaps["Luv"]["XYZ"](obj, kwArgs), kwArgs); }, + "LCHab":function(obj, kwArgs){ return cMaps["Lab"]["LCHab"](cMaps["XYZ"]["Lab"](cMaps["Luv"]["XYZ"](obj, kwArgs), kwArgs), kwArgs); }, + "LCHuv":function(obj, kwArgs){ return cMaps["Luv"]["LCHuv"](obj, kwArgs); }, + "RGB":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["Luv"]["XYZ"](obj, kwArgs), kwArgs); }, + "XYZ":function(obj, kwArgs){ return cMaps["Luv"]["XYZ"](obj, kwArgs); }, + "xyY":function(obj, kwArgs){ return cMaps["XYZ"]["xyY"](cMaps["Luv"]["XYZ"](obj, kwArgs), kwArgs); }, + }, + "RGB":{ + "CMY":function(obj, kwArgs){ return obj.toCmy(); }, + "CMYK":function(obj, kwArgs){ return obj.toCmyk(); }, + "HSL":function(obj, kwArgs){ return obj.toHsl(); }, + "HSV":function(obj, kwArgs){ return obj.toHsv(); }, + "Lab":function(obj, kwArgs){ return cMaps["XYZ"]["Lab"](obj.toXYZ(kwArgs), kwArgs); }, + "LCHab":function(obj, kwArgs){ return cMaps["LCHab"]["Lab"](cMaps["XYZ"]["Lab"](obj.toXYZ(kwArgs), kwArgs), kwArgs);}, + "LCHuv":function(obj, kwArgs){ return cMaps["LCHuv"]["Luv"](cMaps["XYZ"]["Luv"](obj.toXYZ(kwArgs), kwArgs), kwArgs);}, + "Luv":function(obj, kwArgs){ return cMaps["XYZ"]["Luv"](obj.toXYZ(kwArgs), kwArgs); }, + "XYZ":function(obj, kwArgs){ return obj.toXYZ(kwArgs); }, + "xyY":function(obj, kwArgs){ return cMaps["XYZ"]["xyY"](obj.toXYZ(kwArgs), kwArgs); } + }, + "XYZ":{ + "CMY":function(obj, kwArgs){ return dxc.fromXYZ(obj, kwArgs).toCmy(); }, + "CMYK":function(obj, kwArgs){ return dxc.fromXYZ(obj, kwArgs).toCmyk(); }, + "HSL":function(obj, kwArgs){ return dxc.fromXYZ(obj, kwArgs).toHsl(); }, + "HSV":function(obj, kwArgs){ return dxc.fromXYZ(obj, kwArgs).toHsv(); }, + "Lab":function(obj, kwArgs){ return cMaps["XYZ"]["Lab"](obj, kwArgs); }, + "LCHab":function(obj, kwArgs){ return cMaps["Lab"]["LCHab"](cMaps["XYZ"]["Lab"](obj, kwArgs), kwArgs); }, + "LCHuv":function(obj, kwArgs){ return cMaps["Luv"]["LCHuv"](cMaps["XYZ"]["Luv"](obj, kwArgs), kwArgs); }, + "Luv":function(obj, kwArgs){ return cMaps["XYZ"]["Luv"](obj, kwArgs); }, + "RGB":function(obj, kwArgs){ return dxc.fromXYZ(obj, kwArgs); }, + "xyY":function(obj, kwArgs){ return cMaps["XYZ"]["xyY"](dxc.fromXYZ(obj, kwArgs), kwArgs); } + }, + // TODO: revisit this. xyY represents a single color, not a spectrum of colors. + "xyY":{ + "CMY":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["xyY"]["XYZ"](obj, kwArgs), kwArgs).toCmy(); }, + "CMYK":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["xyY"]["XYZ"](obj, kwArgs), kwArgs).toCmyk(); }, + "HSL":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["xyY"]["XYZ"](obj, kwArgs), kwArgs).toHsl(); }, + "HSV":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["xyY"]["XYZ"](obj, kwArgs), kwArgs).toHsv(); }, + "Lab":function(obj, kwArgs){ return cMaps["Lab"]["XYZ"](cMaps["xyY"]["XYZ"](obj, kwArgs), kwArgs); }, + "LCHab":function(obj, kwArgs){ return cMaps["LCHab"]["Lab"](cMaps["Lab"]["XYZ"](cMaps["xyY"]["XYZ"](obj, kwArgs), kwArgs), kwArgs); }, + "LCHuv":function(obj, kwArgs){ return cMaps["LCHuv"]["Luv"](cMaps["Luv"]["XYZ"](cMaps["xyY"]["XYZ"](obj, kwArgs), kwArgs), kwArgs); }, + "Luv":function(obj, kwArgs){ return cMaps["Luv"]["XYZ"](cMaps["xyY"]["XYZ"](obj, kwArgs), kwArgs); }, + "RGB":function(obj, kwArgs){ return dxc.fromXYZ(cMaps["xyY"]["XYZ"](obj, kwArgs), kwArgs); }, + "XYZ":function(obj, kwArgs){ return cMaps["xyY"]["XYZ"](obj, kwArgs); } + } + }; + + this.whitepoint=function(/* String */wpName, /* String? */observer){ + observer=observer||"10"; + var x=0, y=0, t=0; + if(wpMap[observer] && wpMap[observer][wpName]){ + x=wpMap[observer][wpName].x; + y=wpMap[observer][wpName].y; + t=wpMap[observer][wpName].t; + } else { + console.warn( + "dojox.color.Colorspace::whitepoint: either the observer or the whitepoint name was not found. ", + observer, wpName + ); + } + var wp={ x:x, y:y, z:(1-x-y), t:t, Y:1 }; + return this.convert(wp, "xyY", "XYZ"); + }; + + this.tempToWhitepoint=function(/* Number */t){ + if(t<4000){ + console.warn("dojox.color.Colorspace::tempToWhitepoint: can't find a white point for temperatures less than 4000K. (Passed ", t, ")."); + return { x:0, y:0 }; + } + if(t>25000){ + console.warn("dojox.color.Colorspace::tempToWhitepoint: can't find a white point for temperatures greater than 25000K. (Passed ", t, ")."); + return { x:0, y:0 }; + } + var t1=t, t2=t*t, t3=t2*t; + var ten9=Math.pow(10, 9), ten6=Math.pow(10, 6), ten3=Math.pow(10,3); + if(t<=7000){ + var x=(-4.607*ten9/t3)+(2.9678*ten6/t2)+(0.09911*ten3/t)+0.2444063; + } else { + var x=(-2.0064*ten9/t3)+(1.9018*ten6/t2)+(0.24748*ten3/t)+0.23704; + } + var y=-3*x*x+2.87*x-0.275; + return { x:x, y:y }; + }; + + this.primaries=function(/* Object */kwArgs){ + // mix in the defaults. + kwArgs=dojo.mixin({ + profile:"sRGB", + whitepoint:"D65", + observer:"10", + adaptor:"Bradford" + }, kwArgs||{}); + + var m=[]; + if(profiles[kwArgs.profile]){ + m=profiles[kwArgs.profile].slice(0); + } else { + console.warn( + "dojox.color.Colorspace::primaries: the passed profile was not found. ", + "Available profiles include: ", profiles, + ". The profile passed was ", kwArgs.profile + ); + } + var primary={ + name:kwArgs.profile, + gamma:m[0], whitepoint:m[1], + xr:m[2], yr:m[3], Yr:m[4], + xg:m[5], yg:m[6], Yg:m[7], + xb:m[8], yb:m[9], Yb:m[10] + }; + + // convert for the whitepoint + if(kwArgs.whitepoint!=primary.whitepoint){ + var r=this.convert( + this.adapt({ + color:this.convert({ x:xr, y:yr, Y:Yr }, "xyY", "XYZ"), + adaptor:kwArgs.adaptor, + source:primary.whitepoint, + destination:kwArgs.whitepoint + }), + "XYZ", + "xyY" + ); + var g=this.convert( + this.adapt({ + color:this.convert({ x:xg, y:yg, Y:Yg }, "xyY", "XYZ"), + adaptor:kwArgs.adaptor, + source:primary.whitepoint, + destination:kwArgs.whitepoint + }), + "XYZ", + "xyY" + ); + var b=this.convert( + this.adapt({ + color:this.convert({ x:xb, y:yb, Y:Yb }, "xyY", "XYZ"), + adaptor:kwArgs.adaptor, + source:primary.whitepoint, + destination:kwArgs.whitepoint + }), + "XYZ", + "xyY" + ); + primary=dojo.mixin(primary, { + xr: r.x, yr: r.y, Yr: r.Y, + xg: g.x, yg: g.y, Yg: g.Y, + xb: b.x, yb: b.y, Yb: b.Y, + whitepoint: kwArgs.whitepoint + }); + } + return dojo.mixin(primary, { + zr: 1-primary.xr-primary.yr, + zg: 1-primary.xg-primary.yg, + zb: 1-primary.xb-primary.yb + }); // Object + }; + + this.adapt=function(/* Object */kwArgs){ + // color is required in the form of XYZ, source whitepoint name is required. + if(!kwArgs.color || !kwArgs.source){ + console.error("dojox.color.Colorspace::adapt: color and source arguments are required. ", kwArgs); + } + + // defaults + kwArgs=dojo.mixin({ + adaptor:"Bradford", + destination:"D65" + }, kwArgs); + + // adapt + var swp = this.whitepoint(kwArgs.source); + var dwp = this.whitepoint(kwArgs.destination); + if(adaptors[kwArgs.adaptor]){ + var ma=adaptors[kwArgs.adaptor].ma; + var mai=adaptors[kwArgs.adaptor].mai; + }else{ + console.warn("dojox.color.Colorspace::adapt: the passed adaptor '", kwArgs.adaptor, "' was not found."); + } + var dSrc=dxm.multiply([[swp.x, swp.y, swp.z]], ma); + var dDest=dxm.multiply([[dwp.x, dwp.y, dwp.z]], ma); + var center=[ + [dDest[0][0]/dSrc[0][0], 0, 0], + [0, dDest[0][1]/dSrc[0][1], 0], + [0, 0, dDest[0][2]/dSrc[0][2]] + ]; + var m=dxm.multiply(dxm.multiply(ma, center), mai); + var r=dxm.multiply([[ kwArgs.color.X, kwArgs.color.Y, kwArgs.color.Z ]], m)[0]; + return { X:r[0], Y:r[1], Z:r[2] }; + }; + + this.matrix=function(/* String */to, /* Object */primary){ + var wp=this.whitepoint(primary.whitepoint); + var Xr = p.xr/p.yr, Yr = 1, Zr = (1-p.xr-p.yr)/p.yr; + var Xg = p.xg/p.yg, Yg = 1, Zg = (1-p.xg-p.yg)/p.yg; + var Xb = p.xb/p.yb, Yb = 1, Zr = (1-p.xb-p.yb)/p.yb; + + var m1 = [[ Xr, Yr, Zr ], [ Xg, Yg, Zg ], [ Xb, Yb, Zb ]]; + var m2 = [[ wp.X, wp.Y, wp.Z ]]; + var sm = dojox.math.matrix.multiply(m2, dojox.math.matrix.inverse(m1)); + var Sr = sm[0][0], Sg = sm[0][1], Sb = sm[0][2]; + var result=[ + [Sr*Xr, Sr*Yr, Sr*Zr], + [Sg*Xg, Sg*Yg, Sg*Zg], + [Sb*Xb, Sb*Yb, Sb*Zb] + ]; + if(to=="RGB"){ return dojox.math.inverse(result); } + return result; + }; + + this.epsilon=function(/* bool? */useApprox){ + return (useApprox || typeof(useApprox)=="undefined")? 0.008856: 216/24289; + }; + this.kappa=function(/* bool? */useApprox){ + return (useApprox || typeof(useApprox)=="undefined")? 903.3: 24389/27; + }; + + this.convert=function(/* Object */color, /* string */from, /* string */to, /* Object? */kwArgs){ + if(converters[from] && converters[from][to]){ + return converters[from][to](obj, kwArgs); + } + console.warn("dojox.color.Colorspace::convert: Can't convert ", color, " from ", from, " to ", to, "."); + }; +})(); + +// More dojox.color and dojox.color.Color extensions +dojo.mixin(dojox.color, { + fromXYZ: function(/* Object */xyz, /* Object?*/kwArgs){ + kwArgs=kwArgs||{}; + var p=dojox.color.Colorspace.primaries(kwArgs); + var m=dojox.color.Colorspace.matrix("RGB", p); + var rgb=dojox.math.matrix.mutliply([[ xyz.X, xyz.Y, xyz.Z ]], m); + var r=rgb[0][0], g=rgb[0][1], b=rgb[0][2]; + if(p.profile=="sRGB"){ + var R = (r>0.0031308)?(1.055*Math.pow(r, 1/2.4))-0.055: 12.92*r; + var G = (g>0.0031308)?(1.055*Math.pow(g, 1/2.4))-0.055: 12.92*g; + var B = (b>0.0031308)?(1.055*Math.pow(b, 1/2.4))-0.055: 12.92*b; + }else{ + var R=Math.pow(r, 1/p.gamma), G=Math.pow(g, 1/p.gamma), B=Math.pow(b, 1/p.gamma); + } + return new dojox.color.Color({ r:Math.floor(R*255), g:Math.floor(G*255), b:Math.floor(B*255) }); + } +}); + +dojo.extend(dojox.color.Color, { + toXYZ: function(/* Object */kwArgs){ + kwArgs=kwArgs||{}; + var p=dojox.color.Colorspace.primaries(kwArgs); + var m=dojox.color.Colorspace.matrix("XYZ", p); + var _r=this.r/255, _g=this.g/255, _b=this.b/255; + if(p.profile=="sRGB"){ + var r=(_r>0.04045) ? Math.pow(((_r+0.055)/1.055), 2.4):_r/12.92; + var g=(_g>0.04045) ? Math.pow(((_g+0.055)/1.055), 2.4):_g/12.92; + var b=(_b>0.04045) ? Math.pow(((_b+0.055)/1.055), 2.4):_b/12.92; + } else { + var r=Math.pow(_r, p.gamma), g=Math.pow(_g, p.gamma), b=Math.pow(_b, p.gamma); + } + var xyz=dojox.math.matrix([[ r, g, b ]], m); + return { X: xyz[0][0], Y: xyz[0][1], Z: xyz[0][2] }; // Object + } +}); + +} diff --git a/includes/js/dojox/color/Generator.js b/includes/js/dojox/color/Generator.js new file mode 100644 index 0000000..4baaf07 --- /dev/null +++ b/includes/js/dojox/color/Generator.js @@ -0,0 +1,261 @@ +if(!dojo._hasResource["dojox.color.Generator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.color.Generator"] = true; +dojo.provide("dojox.color.Generator"); + +dojox.color.Generator = new (function(){ + var dxc=dojox.color; + + // common helper functions + var prep=function(obj){ + if(!obj){ + console.warn("dojox.color.Generator:: no base color was passed. ", obj); + return null; + } + if(!obj.toHsv){ + // either a raw string or object, return a Color. + obj=new dxc.Color(obj); + } + return obj; + }; + + var factors=function(n, high, low){ + var ret=[], i, step=(high-low)/n, cur=high; + for(i=0; i=360){ a-=360; } + ang.push(a); + } + ang.push(0); + for(i=1; i<=gen; i++){ + a=hsv.h-(kwArgs.angleHigh*i); + if(a<0){ a+=360; } + ang.push(a); + } + + var m=[], cur=0; + for(i=0; i360){ h1-=360; } + if(h2<0){ h2+=360; } + + // sat calculations + var s1=(hsv.s>=20) ? hsv.s-10 : hsv.s+10; + var s2=(hsv.s>=95) ? hsv.s-5 : hsv.s+5; + + // value calcs + var v2=(hsv.v>=70) ? hsv.v-30 : hsv.v+30; + + m.push(fill(dojox.color.fromHsv({ h:h1, s:s1, v:hsv.v }), cols, fs)); + m.push(fill(base, cols, fs)); + m.push(fill(dojox.color.fromHsv({ h:h2, s:s2, v:v2 }), cols, fs)); + return flatten(m, num); // Array + }; + + this.complementary = function(/* Object */kwArgs){ + // summary + // generates n colors from a base color, using complimentary rules. + kwArgs=dojo.mixin({ + num:32, // number of colors to derive + high:0.5, // high factor to generate tints and shades + low:0.15 // low factor to generate tints and shades + }, kwArgs||{}); + + var base=prep(kwArgs.base, "complimentary"); + if(!base){ return []; } + + var num=kwArgs.num, rows=2, cols=Math.ceil(num/rows), fs=factors(Math.floor(cols/2), kwArgs.high, kwArgs.low); + var m=[], hsv=base.toHsv(); + var compliment=(hsv.h+120)%360; + m.push(fill(base, cols, fs)); + m.push(fill(dojox.color.fromHsv({ h:compliment, s:hsv.s, v:hsv.v }), cols, fs)); + return flatten(m, num); // Array + }; + + this.splitComplementary = function(/* Object */kwArgs){ + // summary + // generates n colors from a base color, using split complimentary rules. + kwArgs=dojo.mixin({ + num:32, // number of colors to derive + angle:30, // the angle of difference to use + high:0.5, // high factor to generate tints and shades + low:0.15 // low factor to generate tints and shades + }, kwArgs||{}); + + var base=prep(kwArgs.base, "splitComplementary"); + if(!base){ return []; } + + var num=kwArgs.num, rows=3, cols=Math.ceil(num/rows), fs=factors(Math.floor(cols/2), kwArgs.high, kwArgs.low); + var m=[], hsv=base.toHsv(); + var compliment=(hsv.h+120)%360; + var comp1=compliment-kwArgs.angle, comp2=(compliment+kwArgs.angle)%360; + if(comp1<0){ comp1+=360; } + + m.push(fill(base, cols, fs)); + m.push(fill(dojox.color.fromHsv({ h:comp1, s:hsv.s, v:hsv.v }), cols, fs)); + m.push(fill(dojox.color.fromHsv({ h:comp2, s:hsv.s, v:hsv.v }), cols, fs)); + return flatten(m, num); // Array + }; + + this.compound = function(/* Object */kwArgs){ + // summary + // generates n colors from a base color, using a *very* rough approximation + // of the Compound rules at http://kuler.adobe.com + kwArgs=dojo.mixin({ + num:32, // number of colors to derive + angle:30, // the angle of difference to use + high:0.5, // high factor to generate tints and shades + low:0.15 // low factor to generate tints and shades + }, kwArgs||{}); + + var base=prep(kwArgs.base, "compound"); + if(!base){ return []; } + + var num=kwArgs.num, rows=4, cols=Math.ceil(num/rows), fs=factors(Math.floor(cols/2), kwArgs.high, kwArgs.low); + var m=[], hsv=base.toHsv(); + var comp=(hsv.h+120)%360; // other base angle. + + // hue calculations + var h1=(hsv.h+kwArgs.angle)%360, h2=comp-kwArgs.angle, h3=comp-(kwArgs.angle/2); + if(h2<0){ h2+=360; } + if(h3<0){ h3+=360; } + + // saturation calculations + var s1=(hsv.s>=90 && hsv.s<=100)? hsv.s-10 : hsv.s+10; + var s2=(hsv.s<=35) ? hsv.s+25 : hsv.s-25; + + // value calculations + var v1=hsv.v-20; + var v2=hsv.v; + + m.push(fill(base, cols, fs)); + m.push(fill(dojox.color.fromHsv({ h:h1, s:s1, v:v1 }), cols, fs)); + m.push(fill(dojox.color.fromHsv({ h:h2, s:s1, v:v1 }), cols, fs)); + m.push(fill(dojox.color.fromHsv({ h:h3, s:s2, v:v2 }), cols, fs)); + return flatten(m, num); // Array + }; + + this.shades = function(/* Object */kwArgs){ + // summary + // generates n colors based on a base color using only changes + // in value. Similar to monochromatic but a bit more linear. + kwArgs=dojo.mixin({ + num:32, // number of colors to derive + high:1.5, // high factor to generate tints and shades + low:0.5 // low factor to generate tints and shades + }, kwArgs||{}); + + var base=prep(kwArgs.base, "shades"); + if(!base){ return []; } + + var num=kwArgs.num, hsv=base.toHsv(); + var step=(kwArgs.high-kwArgs.low)/num, cur=kwArgs.low; + var a=[]; + for(var i=0; i=360){ hue-=360; } + + var r, g, b; + if(hue<120){ + r=(120-hue)/60, g=hue/60, b=0; + } else if (hue<240){ + r=0, g=(240-hue)/60, b=(hue-120)/60; + } else { + r=(hue-240)/60, g=0, b=(360-hue)/60; + } + + r=2*saturation*Math.min(r, 1)+(1-saturation); + g=2*saturation*Math.min(g, 1)+(1-saturation); + b=2*saturation*Math.min(b, 1)+(1-saturation); + if(luminosity<0.5){ + r*=luminosity, g*=luminosity, b*=luminosity; + }else{ + r=(1-luminosity)*r+2*luminosity-1; + g=(1-luminosity)*g+2*luminosity-1; + b=(1-luminosity)*b+2*luminosity-1; + } + return new dojox.color.Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color + }, + + fromHsv: function(/* Object|Array|int */hue, /* int */saturation, /* int */value){ + // summary + // Create a dojox.color.Color from an HSV defined color. + // hue from 0-359 (degrees), saturation and value 0-100. + + if(dojo.isArray(hue)){ + saturation=hue[1], value=hue[2], hue=hue[0]; + } else if (dojo.isObject(hue)){ + saturation=hue.s, value=hue.v, hue=hue.h; + } + + if(hue==360){ hue=0; } + saturation/=100; + value/=100; + + var r, g, b; + if(saturation==0){ + r=value, b=value, g=value; + }else{ + var hTemp=hue/60, i=Math.floor(hTemp), f=hTemp-i; + var p=value*(1-saturation); + var q=value*(1-(saturation*f)); + var t=value*(1-(saturation*(1-f))); + switch(i){ + case 0:{ r=value, g=t, b=p; break; } + case 1:{ r=q, g=value, b=p; break; } + case 2:{ r=p, g=value, b=t; break; } + case 3:{ r=p, g=q, b=value; break; } + case 4:{ r=t, g=p, b=value; break; } + case 5:{ r=value, g=p, b=q; break; } + } + } + return new dojox.color.Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color + } +}); + +// Conversions directly on dojox.color.Color +dojo.extend(dojox.color.Color, { + toCmy: function(){ + // summary + // Convert this Color to a CMY definition. + var cyan=1-(this.r/255), magenta=1-(this.g/255), yellow=1-(this.b/255); + return { c:Math.round(cyan*100), m:Math.round(magenta*100), y:Math.round(yellow*100) }; // Object + }, + + toCmyk: function(){ + // summary + // Convert this Color to a CMYK definition. + var cyan, magenta, yellow, black; + var r=this.r/255, g=this.g/255, b=this.b/255; + black = Math.min(1-r, 1-g, 1-b); + cyan = (1-r-black)/(1-black); + magenta = (1-g-black)/(1-black); + yellow = (1-b-black)/(1-black); + return { c:Math.round(cyan*100), m:Math.round(magenta*100), y:Math.round(yellow*100), b:Math.round(black*100) }; // Object + }, + + toHsl: function(){ + // summary + // Convert this Color to an HSL definition. + var r=this.r/255, g=this.g/255, b=this.b/255; + var min = Math.min(r, b, g), max = Math.max(r, g, b); + var delta = max-min; + var h=0, s=0, l=(min+max)/2; + if(l>0 && l<1){ + s = delta/((l<0.5)?(2*l):(2-2*l)); + } + if(delta>0){ + if(max==r && max!=g){ + h+=(g-b)/delta; + } + if(max==g && max!=b){ + h+=(2+(b-r)/delta); + } + if(max==b && max!=r){ + h+=(4+(r-g)/delta); + } + h*=60; + } + return { h:h, s:Math.round(s*100), l:Math.round(l*100) }; // Object + }, + + toHsv: function(){ + // summary + // Convert this Color to an HSV definition. + var r=this.r/255, g=this.g/255, b=this.b/255; + var min = Math.min(r, b, g), max = Math.max(r, g, b); + var delta = max-min; + var h = null, s = (max==0)?0:(delta/max); + if(s==0){ + h = 0; + }else{ + if(r==max){ + h = 60*(g-b)/delta; + }else if(g==max){ + h = 120 + 60*(b-r)/delta; + }else{ + h = 240 + 60*(r-g)/delta; + } + + if(h<0){ h+=360; } + } + return { h:h, s:Math.round(s*100), v:Math.round(max*100) }; // Object + } +}); + +} diff --git a/includes/js/dojox/color/tests/Generator.js b/includes/js/dojox/color/tests/Generator.js new file mode 100644 index 0000000..6232cc7 --- /dev/null +++ b/includes/js/dojox/color/tests/Generator.js @@ -0,0 +1,128 @@ +if(!dojo._hasResource["dojox.color.tests.Generator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.color.tests.Generator"] = true; +dojo.provide("dojox.color.tests.Generator"); +dojo.require("dojox.color.Generator"); + +tests.register("dojox.color.tests.Generator", [ + function testAnalogous(t){ + // test the defaults + var args={ base: new dojox.color.Color({ r:128, g:0, b:0 }) }; + var a=dojox.color.Generator.analogous(args); + var s='

dojox.color.Generator.analogous

'; + var cols=5, c=0; + dojo.forEach(a, function(item){ + if(c++%cols==0){ s+=""; } + s+=''; + }); + if(c
 
'); + }, + + function testMonochromatic(t){ + // test the defaults + var a=dojox.color.Generator.monochromatic({ base:new dojox.color.Color({r:128, g:0, b:0}) }); + var s='

dojox.color.Generator.monochromatic

'; + var cols=8, c=0; + dojo.forEach(a, function(item){ + if(c++%cols==0){ s+=""; } + s+=''; + }); + if(c
 
'); + }, + + function testTriadic(t){ + // test the defaults + var a=dojox.color.Generator.triadic({ base:new dojox.color.Color({r:128, g:0, b:0}) }); + var s='

dojox.color.Generator.triadic

'; + var cols=3, c=0; + dojo.forEach(a, function(item){ + if(c++%cols==0){ s+=""; } + s+=''; + }); + if(c
 
'); + }, + + function testComplementary(t){ + // test the defaults + var a=dojox.color.Generator.complementary({ base:new dojox.color.Color({r:128, g:0, b:0}) }); + var s='

dojox.color.Generator.complementary

'; + var cols=2, c=0; + dojo.forEach(a, function(item){ + if(c++%cols==0){ s+=""; } + s+=''; + }); + if(c
 
'); + }, + + function testSplitComplementary(t){ + // test the defaults + var a=dojox.color.Generator.splitComplementary({ base:new dojox.color.Color({r:128, g:0, b:0}) }); + var s='

dojox.color.Generator.splitComplementary

'; + var cols=3, c=0; + dojo.forEach(a, function(item){ + if(c++%cols==0){ s+=""; } + s+=''; + }); + if(c
 
'); + }, + + function testCompound(t){ + // test the defaults + var a=dojox.color.Generator.compound({ base:new dojox.color.Color({r:128, g:0, b:0}) }); + var s='

dojox.color.Generator.compound

'; + var cols=4, c=0; + dojo.forEach(a, function(item){ + if(c++%cols==0){ s+=""; } + s+=''; + }); + if(c
 
'); + }, + + function testShades(t){ + // test the defaults + var a=dojox.color.Generator.shades({ base:new dojox.color.Color({r:128, g:0, b:0}) }); + var s=''; + var cols=8, c=0; + dojo.forEach(a, function(item){ + if(c++%cols==0){ s+=""; } + s+=''; + }); + if(c
 
'); + } +]); + +} diff --git a/includes/js/dojox/color/tests/_base.js b/includes/js/dojox/color/tests/_base.js new file mode 100644 index 0000000..cb96223 --- /dev/null +++ b/includes/js/dojox/color/tests/_base.js @@ -0,0 +1,82 @@ +if(!dojo._hasResource["dojox.color.tests._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.color.tests._base"] = true; +dojo.provide("dojox.color.tests._base"); +dojo.require("dojox.color"); + +/************************************************************ + * Note that some color translations are not exact, + * due to the need to round calculations in translation. + * + * These tests work with grey, the primary colors and + * one secondary color to ensure that extreme calculation + * is correct. + ************************************************************/ + +tests.register("dojox.color.tests._base", [ + function testStaticMethods(t){ + // fromCmy + t.assertEqual(dojox.color.fromCmy({ c:50, m:50, y:50}), new dojo.Color({ r:128, g:128, b:128 })); + t.assertEqual(dojox.color.fromCmy({ c:0, m:100, y:100}), new dojo.Color({ r:255, g:0, b:0 })); + t.assertEqual(dojox.color.fromCmy({ c:100, m:0, y:100}), new dojo.Color({ r:0, g:255, b:0 })); + t.assertEqual(dojox.color.fromCmy({ c:100, m:100, y:0}), new dojo.Color({ r:0, g:0, b:255 })); + t.assertEqual(dojox.color.fromCmy({ c:0, m:0, y:100}), new dojo.Color({ r:255, g:255, b:0 })); + + // fromCmyk + t.assertEqual(dojox.color.fromCmyk({ c:0, m:0, y:0, b:50}), new dojo.Color({ r:128, g:128, b:128 })); + t.assertEqual(dojox.color.fromCmyk({ c:0, m:100, y:100, b:0}), new dojo.Color({ r:255, g:0, b:0 })); + t.assertEqual(dojox.color.fromCmyk({ c:100, m:0, y:100, b:0}), new dojo.Color({ r:0, g:255, b:0 })); + t.assertEqual(dojox.color.fromCmyk({ c:100, m:100, y:0, b:0}), new dojo.Color({ r:0, g:0, b:255 })); + t.assertEqual(dojox.color.fromCmyk({ c:0, m:0, y:100, b:0}), new dojo.Color({ r:255, g:255, b:0 })); + + // fromHsl + t.assertEqual(dojox.color.fromHsl({ h:0, s:0, l:50}), new dojo.Color({ r:128, g:128, b:128 })); + t.assertEqual(dojox.color.fromHsl({ h:0, s:100, l:50}), new dojo.Color({ r:255, g:0, b:0 })); + t.assertEqual(dojox.color.fromHsl({ h:120, s:100, l:50}), new dojo.Color({ r:0, g:255, b:0 })); + t.assertEqual(dojox.color.fromHsl({ h:240, s:100, l:50}), new dojo.Color({ r:0, g:0, b:255 })); + t.assertEqual(dojox.color.fromHsl({ h:60, s:100, l:50}), new dojo.Color({ r:255, g:255, b:0 })); + + // fromHsv + t.assertEqual(dojox.color.fromHsv({ h:0, s:0, v:50}), new dojo.Color({ r:128, g:128, b:128 })); + t.assertEqual(dojox.color.fromHsv({ h:0, s:100, v:100}), new dojo.Color({ r:255, g:0, b:0 })); + t.assertEqual(dojox.color.fromHsv({ h:120, s:100, v:100}), new dojo.Color({ r:0, g:255, b:0 })); + t.assertEqual(dojox.color.fromHsv({ h:240, s:100, v:100}), new dojo.Color({ r:0, g:0, b:255 })); + t.assertEqual(dojox.color.fromHsv({ h:60, s:100, v:100}), new dojo.Color({ r:255, g:255, b:0 })); + }, + function testColorExtensions(t){ + var grey=new dojox.color.Color({ r:128, g:128, b:128 }); + var red=new dojox.color.Color({ r:255, g:0, b:0 }); + var green=new dojox.color.Color({ r:0, g:255, b:0 }); + var blue=new dojox.color.Color({ r:0, g:0, b:255 }); + var yellow=new dojox.color.Color({ r:255, g:255, b:0 }); + + // toCmy + t.assertEqual(grey.toCmy(), { c:50, m:50, y:50 }); + t.assertEqual(red.toCmy(), { c:0, m:100, y:100 }); + t.assertEqual(green.toCmy(), { c:100, m:0, y:100 }); + t.assertEqual(blue.toCmy(), { c:100, m:100, y:0 }); + t.assertEqual(yellow.toCmy(), { c:0, m:0, y:100 }); + + // toCmyk + t.assertEqual(grey.toCmyk(), { c:0, m:0, y:0, b:50 }); + t.assertEqual(red.toCmyk(), { c:0, m:100, y:100, b:0 }); + t.assertEqual(green.toCmyk(), { c:100, m:0, y:100, b:0 }); + t.assertEqual(blue.toCmyk(), { c:100, m:100, y:0, b:0 }); + t.assertEqual(yellow.toCmyk(), { c:0, m:0, y:100, b:0 }); + + // toHsl + t.assertEqual(grey.toHsl(), { h:0, s:0, l:50 }); + t.assertEqual(red.toHsl(), { h:0, s:100, l:50 }); + t.assertEqual(green.toHsl(), { h:120, s:100, l:50 }); + t.assertEqual(blue.toHsl(), { h:240, s:100, l:50 }); + t.assertEqual(yellow.toHsl(), { h:60, s:100, l:50 }); + + // toHsv + t.assertEqual(grey.toHsv(), { h:0, s:0, v:50 }); + t.assertEqual(red.toHsv(), { h:0, s:100, v:100 }); + t.assertEqual(green.toHsv(), { h:120, s:100, v:100 }); + t.assertEqual(blue.toHsv(), { h:240, s:100, v:100 }); + t.assertEqual(yellow.toHsv(), { h:60, s:100, v:100 }); + } +]); + +} diff --git a/includes/js/dojox/color/tests/color.js b/includes/js/dojox/color/tests/color.js new file mode 100644 index 0000000..74438f6 --- /dev/null +++ b/includes/js/dojox/color/tests/color.js @@ -0,0 +1,14 @@ +if(!dojo._hasResource["dojox.color.tests.color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.color.tests.color"] = true; +dojo.provide("dojox.color.tests.color"); +dojo.require("dojox.color"); + +try{ + dojo.require("dojox.color.tests._base"); +// dojo.require("dojox.color.tests.Colorspace"); + dojo.require("dojox.color.tests.Generator"); +}catch(e){ + doh.debug(e); +} + +} diff --git a/includes/js/dojox/color/tests/runTests.html b/includes/js/dojox/color/tests/runTests.html new file mode 100644 index 0000000..9376e20 --- /dev/null +++ b/includes/js/dojox/color/tests/runTests.html @@ -0,0 +1,9 @@ + + + + Dojox.wire Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/cometd.js b/includes/js/dojox/cometd.js new file mode 100644 index 0000000..0a02a9f --- /dev/null +++ b/includes/js/dojox/cometd.js @@ -0,0 +1,7 @@ +if(!dojo._hasResource["dojox.cometd"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.cometd"] = true; +// stub loader for the cometd module since no implementation code is allowed to live in top-level files +dojo.provide("dojox.cometd"); +dojo.require("dojox.cometd._base"); + +} diff --git a/includes/js/dojox/cometd/README b/includes/js/dojox/cometd/README new file mode 100644 index 0000000..05a42a2 --- /dev/null +++ b/includes/js/dojox/cometd/README @@ -0,0 +1,29 @@ +------------------------------------------------------------------------------- +Cometd (client) +------------------------------------------------------------------------------- +Version 0.4 +Release date: May 29, 2007 +------------------------------------------------------------------------------- +Project state: beta +------------------------------------------------------------------------------- +Project authors + Alex Russell (alex@dojotoolkit.org) + Greg Wilkins +------------------------------------------------------------------------------- +Project description + +Low-latency data transfer from servers to clients. dojox.cometd implements a +Bayeux protocol client for use with most Bayeux servers. See cometd.com for +details on Cometd or on the Bayeux protocol. +------------------------------------------------------------------------------- +Dependencies: + +Needs a cooperating Bayeux server +------------------------------------------------------------------------------- +Documentation + +See http://cometd.com +------------------------------------------------------------------------------- +Installation instructions + +Use this library with (preferably through) an existing Cometd server. diff --git a/includes/js/dojox/cometd/_base.js b/includes/js/dojox/cometd/_base.js new file mode 100644 index 0000000..eb129ee --- /dev/null +++ b/includes/js/dojox/cometd/_base.js @@ -0,0 +1,950 @@ +if(!dojo._hasResource["dojox.cometd._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.cometd._base"] = true; +dojo.provide("dojox.cometd._base"); +dojo.require("dojo.AdapterRegistry"); +dojo.require("dojo.io.script"); + + +/* + * this file defines Comet protocol client. Actual message transport is + * deferred to one of several connection type implementations. The default is a + * long-polling implementation. A single global object named "dojox.cometd" is + * used to mediate for these connection types in order to provide a stable + * interface. + * + * extensions modules may be loaded (eg "dojox.cometd.timestamp", that use + * the cometd._extendInList and cometd._extendOutList fields to provide functions + * that extend and handling incoming and outgoing messages. + */ + +dojox.cometd = new function(){ + + // cometd states: + + // alex; OMG, these "constants" need to die. Java truly is a degenerative disease. + this.DISCONNECTED = "DISCONNECTED"; // _initialized==false && _connected==false + this.CONNECTING = "CONNECTING"; // _initialized==true && _connected==false (handshake sent) + this.CONNECTED = "CONNECTED"; // _initialized==true && _connected==true (first successful connect) + this.DISCONNECTING = "DISCONNECING"; // _initialized==false && _connected==true (disconnect sent) + + this._initialized = false; + this._connected = false; + this._polling = false; + + this.expectedNetworkDelay = 5000; // expected max network delay + this.connectTimeout = 0; // If set, used as ms to wait for a connect response and sent as the advised timeout + + this.connectionTypes = new dojo.AdapterRegistry(true); + + this.version = "1.0"; + this.minimumVersion = "0.9"; + this.clientId = null; + this.messageId = 0; + this.batch = 0; + + this._isXD = false; + this.handshakeReturn = null; + this.currentTransport = null; + this.url = null; + this.lastMessage = null; + this._messageQ = []; + this.handleAs = "json-comment-optional"; + this._advice = {}; + this._backoffInterval = 0; + this._backoffIncrement = 1000; + this._backoffMax = 60000; + this._deferredSubscribes = {}; + this._deferredUnsubscribes = {}; + this._subscriptions = []; + this._extendInList = []; // List of functions invoked before delivering messages + this._extendOutList = []; // List of functions invoked before sending messages + + this.state = function() { + return this._initialized ? + (this._connected ? "CONNECTED" : "CONNECTING") : + ( this._connected ? "DISCONNECTING" : "DISCONNECTED"); + } + + this.init = function( /*String*/ root, + /*Object?*/ props, + /*Object?*/ bargs){ // return: dojo.Deferred + // summary: + // Initialize the cometd implementation of the Bayeux protocol + // description: + // Initialize the cometd implementation of the Bayeux protocol by + // sending a handshake message. The cometd state will be changed to CONNECTING + // until a handshake response is received and the first successful connect message + // has returned. + // The protocol state changes may be monitored + // by subscribing to the dojo topic "/cometd/meta" where events are + // published in the form {cometd:this,action:"handshake",successful:true,state:this.state()} + // root: + // The URL of the cometd server. If the root is absolute, the host + // is examined to determine if xd transport is needed. Otherwise the + // same domain is assumed. + // props: + // An optional object that is used as the basis of the handshake message + // bargs: + // An optional object of bind args mixed in with the send of the handshake + // example: + // | dojox.cometd.init("/cometd"); + // | dojox.cometd.init("http://xdHost/cometd",{ext:{user:"fred",pwd:"secret"}}); + + + // FIXME: if the root isn't from the same host, we should automatically + // try to select an XD-capable transport + props = props||{}; + // go ask the short bus server what we can support + props.version = this.version; + props.minimumVersion = this.minimumVersion; + props.channel = "/meta/handshake"; + props.id = ""+this.messageId++; + + this.url = root||dojo.config["cometdRoot"]; + if(!this.url){ + console.debug("no cometd root specified in djConfig and no root passed"); + return null; + } + + // Are we x-domain? borrowed from dojo.uri.Uri in lieu of fixed host and port properties + var regexp = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$"; + var parts = (""+window.location).match(new RegExp(regexp)); + if(parts[4]){ + var tmp = parts[4].split(":"); + var thisHost = tmp[0]; + var thisPort = tmp[1]||"80"; // FIXME: match 443 + + parts = this.url.match(new RegExp(regexp)); + if(parts[4]){ + tmp = parts[4].split(":"); + var urlHost = tmp[0]; + var urlPort = tmp[1]||"80"; + this._isXD = ((urlHost != thisHost)||(urlPort != thisPort)); + } + } + + if(!this._isXD){ + if(props.ext){ + if(props.ext["json-comment-filtered"]!==true && props.ext["json-comment-filtered"]!==false){ + props.ext["json-comment-filtered"] = true; + } + }else{ + props.ext = { "json-comment-filtered": true }; + } + props.supportedConnectionTypes = dojo.map(this.connectionTypes.pairs, "return item[0]"); + } + + props = this._extendOut(props); + + var bindArgs = { + url: this.url, + handleAs: this.handleAs, + content: { "message": dojo.toJson([props]) }, + load: dojo.hitch(this,function(msg){ + this._backon(); + this._finishInit(msg); + }), + error: dojo.hitch(this,function(e){ + console.debug("handshake error!:",e); + this._backoff(); + this._finishInit([{}]); + }) + }; + + if(bargs){ + dojo.mixin(bindArgs, bargs); + } + this._props = props; + for(var tname in this._subscriptions){ + for(var sub in this._subscriptions[tname]){ + if(this._subscriptions[tname][sub].topic){ + dojo.unsubscribe(this._subscriptions[tname][sub].topic); + } + } + } + this._messageQ = []; + this._subscriptions = []; + this._initialized = true; + this.batch = 0; + this.startBatch(); + + var r; + // if xdomain, then we assume jsonp for handshake + if(this._isXD){ + bindArgs.callbackParamName = "jsonp"; + r = dojo.io.script.get(bindArgs); + }else{ + r = dojo.xhrPost(bindArgs); + } + dojo.publish("/cometd/meta", [ + { + cometd: this, + action: "handshake", + successful: true, + state: this.state() + } + ]); + return r; + } + + + this.publish = function(/*String*/ channel, /*Object*/ data, /*Object?*/ props){ + // summary: + // publishes the passed message to the cometd server for delivery + // on the specified topic + // channel: + // the destination channel for the message + // data: + // a JSON object containing the message "payload" + // properties: + // Optional. Other meta-data to be mixed into the top-level of the + // message + var message = { + data: data, + channel: channel + }; + if(props){ + dojo.mixin(message, props); + } + this._sendMessage(message); + } + + + this.subscribe = function( /*String */ channel, + /*Object */ objOrFunc, + /*String */ funcName, + /*Object?*/ props){ // return: dojo.Deferred + // summary: + // inform the server of this client's interest in channel + // description: + // `dojox.cometd.subscribe()` handles all the hard work of telling + // the server that we want to be notified when events are + // published on a particular topic. `subscribe` accepts a function + // to handle messages and returns a `dojo.Deferred` object which + // has an extra property added to it which makes it suitable for + // passing to `dojox.cometd.unsubscribe()` as a "subscription + // handle" (much like the handle object that `dojo.connect()` + // produces and which `dojo.disconnect()` expects). + // + // Note that of a subscription is registered before a connection + // with the server is established, events sent before the + // connection is established will not be delivered to this client. + // The deferred object which `subscribe` returns will callback + // when the server successfuly acknolwedges receipt of our + // "subscribe" request. + // channel: + // name of the cometd channel to subscribe to + // objOrFunc: + // an object scope for funcName or the name or reference to a + // function to be called when messages are delivered to the + // channel + // funcName: + // the second half of the objOrFunc/funcName pair for identifying + // a callback function to notifiy upon channel message delivery + // example: + // Simple subscribe use-case + // | dojox.cometd.init("http://myserver.com:8080/cometd"); + // | // log out all incoming messages on /foo/bar + // | dojox.cometd.subscribe("/foo/bar", console, "debug"); + // example: + // Subscribe before connection is initialized + // | dojox.cometd.subscribe("/foo/bar", console, "debug"); + // | dojox.cometd.init("http://myserver.com:8080/cometd"); + // example: + // Subscribe an unsubscribe + // | dojox.cometd.init("http://myserver.com:8080/cometd"); + // | var h = dojox.cometd.subscribe("/foo/bar", console, "debug"); + // | dojox.cometd.unsubscribe(h); + // example: + // Listen for successful subscription: + // | dojox.cometd.init("http://myserver.com:8080/cometd"); + // | var h = dojox.cometd.subscribe("/foo/bar", console, "debug"); + // | h.addCallback(function(){ + // | console.debug("subscription to /foo/bar established"); + // | }); + + props = props||{}; + if(objOrFunc){ + var tname = "/cometd"+channel; + var subs = this._subscriptions[tname]; + if(!subs || subs.length==0){ + subs = []; + props.channel = "/meta/subscribe"; + props.subscription = channel; + this._sendMessage(props); + + var _ds = this._deferredSubscribes; + if(_ds[channel]){ + _ds[channel].cancel(); + delete _ds[channel]; + } + _ds[channel] = new dojo.Deferred(); + } + + for(var i in subs){ + if( subs[i].objOrFunc === objOrFunc && (!subs[i].funcName&&!funcName||subs[i].funcName==funcName) ){ + return null; + } + } + + var topic = dojo.subscribe(tname, objOrFunc, funcName); + subs.push({ + topic: topic, + objOrFunc: objOrFunc, + funcName: funcName + }); + this._subscriptions[tname] = subs; + } + var ret = this._deferredSubscribes[channel]||{}; + ret.args = dojo._toArray(arguments); + return ret; // dojo.Deferred + } + + + + this.unsubscribe = function( /*String*/ channel, + /*Object?*/ objOrFunc, + /*String?*/ funcName, + /*Object?*/ props){ + // summary: + // inform the server of this client's disinterest in channel + // channel: + // name of the cometd channel to unsubscribe from + // objOrFunc: + // an object scope for funcName or the name or reference to a + // function to be called when messages are delivered to the + // channel. If null then all subscribers to the channel are unsubscribed. + // funcName: + // the second half of the objOrFunc/funcName pair for identifying + // a callback function to notifiy upon channel message delivery + + if( + (arguments.length == 1) && + (!dojo.isString(channel)) && + (channel.args) + ){ + // it's a subscription handle, unroll + return this.unsubscribe.apply(this, channel.args); + } + + var tname = "/cometd"+channel; + var subs = this._subscriptions[tname]; + if(!subs || subs.length==0){ + return null; + } + + var s=0; + for(var i in subs){ + var sb = subs[i]; + if( (!objOrFunc) || + ( + sb.objOrFunc===objOrFunc && + (!sb.funcName && !funcName || sb.funcName==funcName) + ) + ){ + dojo.unsubscribe(subs[i].topic); + delete subs[i]; + }else{ + s++; + } + } + + if(s==0){ + props = props||{}; + props.channel = "/meta/unsubscribe"; + props.subscription = channel; + delete this._subscriptions[tname]; + this._sendMessage(props); + this._deferredUnsubscribes[channel] = new dojo.Deferred(); + if (this._deferredSubscribes[channel]){ + this._deferredSubscribes[channel].cancel(); + delete this._deferredSubscribes[channel]; + } + } + return this._deferredUnsubscribes[channel]; // dojo.Deferred + } + + + this.disconnect = function(){ + // summary: + // Disconnect from the server. + // description: + // Disconnect from the server by sending a disconnect message + // example: + // | dojox.cometd.disconnect(); + + for(var tname in this._subscriptions){ + for(var sub in this._subscriptions[tname]){ + if(this._subscriptions[tname][sub].topic){ + dojo.unsubscribe(this._subscriptions[tname][sub].topic); + } + } + } + this._subscriptions = []; + this._messageQ = []; + if(this._initialized && this.currentTransport){ + this._initialized=false; + this.currentTransport.disconnect(); + } + if(!this._polling) { + this._connected=false; + dojo.publish("/cometd/meta", [{cometd:this,action:"connect",successful:false,state:this.state()}]); + } + this._initialized=false; + dojo.publish("/cometd/meta", [{cometd:this,action:"disconnect",successful:true,state:this.state()}]); + } + + + // public extension points + + this.subscribed = function( /*String*/channel, /*Object*/message){ } + + this.unsubscribed = function(/*String*/channel, /*Object*/message){ } + + + // private methods (TODO name all with leading _) + + this.tunnelInit = function(childLocation, childDomain){ + // placeholder - replaced by _finishInit + } + + this.tunnelCollapse = function(){ + // placeholder - replaced by _finishInit + } + + this._backoff = function(){ + if(!this._advice){ + this._advice={reconnect:"retry",interval:0}; + } + else if(!this._advice.interval){ + this._advice.interval=0; + } + if(this._backoffInterval0) + console.debug("Retry in interval+backoff="+this._advice.interval+"+"+this._backoffInterval+"="+i+"ms"); + return i; + } + + this._finishInit = function(data){ + // summary: + // Handle the handshake return from the server and initialize + // connection if all is OK + data = data[0]; + this.handshakeReturn = data; + + // remember any advice + if(data["advice"]){ + this._advice = data.advice; + } + + var successful=data.successful?data.successful:false; + + // check version + if(data.version < this.minimumVersion){ + console.debug("cometd protocol version mismatch. We wanted", this.minimumVersion, "but got", data.version); + successful=false; + this._advice.reconnect="none"; + } + + // If all OK + if(successful){ + // pick a transport + this.currentTransport = this.connectionTypes.match( + data.supportedConnectionTypes, + data.version, + this._isXD + ); + // initialize the transport + this.currentTransport._cometd = this; + this.currentTransport.version = data.version; + this.clientId = data.clientId; + this.tunnelInit = dojo.hitch(this.currentTransport, "tunnelInit"); + this.tunnelCollapse = dojo.hitch(this.currentTransport, "tunnelCollapse"); + this.currentTransport.startup(data); + } + + dojo.publish("/cometd/meta", [{cometd:this,action:"handshook",successful:successful,state:this.state()}]); + + // If there is a problem + if(!successful){ + console.debug("cometd init failed"); + // follow advice + if(this._advice && this._advice["reconnect"]=="none"){ + console.debug("cometd reconnect: none"); + }else{ + setTimeout(dojo.hitch(this, "init", this.url, this._props),this._interval()); + } + } + } + + // fixme: lots of repeated code...why? + + this._extendIn = function(message){ + // Handle extensions for inbound messages + dojo.forEach(dojox.cometd._extendInList, function(f){ + message = f(message)||message; + }); + return message; + } + + this._extendOut = function(message){ + // Handle extensions for inbound messages + dojo.forEach(dojox.cometd._extendOutList, function(f){ + message = f(message)||message; + }); + return message; + } + + + this.deliver = function(messages){ + dojo.forEach(messages, this._deliver, this); + return messages; + } + + this._deliver = function(message){ + // dipatch events along the specified path + + message=this._extendIn(message); + + if(!message["channel"]){ + if(message["success"] !== true){ + console.debug("cometd error: no channel for message!", message); + return; + } + } + this.lastMessage = message; + + if(message.advice){ + this._advice = message.advice; // TODO maybe merge? + } + + // check to see if we got a /meta channel message that we care about + var deferred=null; + if( (message["channel"]) && + (message.channel.length > 5)&& + (message.channel.substr(0, 5) == "/meta")){ + // check for various meta topic actions that we need to respond to + switch(message.channel){ + case "/meta/connect": + if(message.successful && !this._connected){ + this._connected = this._initialized; + this.endBatch(); + }else if(!this._initialized){ + this._connected = false; // finish disconnect + } + dojo.publish("/cometd/meta",[{cometd:this,action:"connect",successful:message.successful,state:this.state()}]); + break; + case "/meta/subscribe": + deferred = this._deferredSubscribes[message.subscription]; + if(!message.successful){ + if(deferred){ + deferred.errback(new Error(message.error)); + } + this.currentTransport.cancelConnect(); + return; + } + dojox.cometd.subscribed(message.subscription, message); + if(deferred){ + deferred.callback(true); + } + break; + case "/meta/unsubscribe": + deferred = this._deferredUnsubscribes[message.subscription]; + if(!message.successful){ + if(deferred){ + deferred.errback(new Error(message.error)); + } + this.currentTransport.cancelConnect(); + return; + } + this.unsubscribed(message.subscription, message); + if(deferred){ + deferred.callback(true); + } + break; + default: + if(message.successful && !message.successful){ + this.currentTransport.cancelConnect(); + return; + } + } + } + + // send the message down for processing by the transport + this.currentTransport.deliver(message); + + if(message.data){ + // dispatch the message to any locally subscribed listeners + try { + var messages=[message]; + + // Determine target topic + var tname="/cometd"+message.channel; + + // Deliver to globs that apply to target topic + var tnameParts=message.channel.split("/"); + var tnameGlob="/cometd"; + for (var i=1;i0){ + this.currentTransport.sendMessages(messages); + } + } + } + + this._onUnload = function(){ + // make this the last of the onUnload method + dojo.addOnUnload(dojox.cometd,"disconnect"); + } + + this._connectTimeout = function(){ + // return the connect timeout in ms, calculated as the minimum of the advised timeout + // and the configured timeout. Else 0 to indicate no client side timeout + var _advised=0; + if (this._advice && this._advice.timeout && this.expectedNetworkDelay>0) + _advised=this._advice.timeout + this.expectedNetworkDelay; + + if (this.connectTimeout>0 && this.connectTimeout<_advised) + return this.connectTimeout; + + return 0; + } +} + +/* +transport objects MUST expose the following methods: + - check + - startup + - sendMessages + - deliver + - disconnect +optional, standard but transport dependent methods are: + - tunnelCollapse + - tunnelInit + +Transports SHOULD be namespaced under the cometd object and transports MUST +register themselves with cometd.connectionTypes + +here's a stub transport defintion: + +cometd.blahTransport = new function(){ + this._connectionType="my-polling"; + this._cometd=null; + this.lastTimestamp = null; + + this.check = function(types, version, xdomain){ + // summary: + // determines whether or not this transport is suitable given a + // list of transport types that the server supports + return dojo.lang.inArray(types, "blah"); + } + + this.startup = function(){ + if(dojox.cometd._polling){ return; } + // FIXME: fill in startup routine here + dojox.cometd._polling = true; + } + + this.sendMessages = function(message){ + // FIXME: fill in message array sending logic + } + + this.deliver = function(message){ + } + + this.disconnect = function(){ + // send orderly disconnect message + } + + this.cancelConnect = function(){ + // cancel the current connection + } +} +cometd.connectionTypes.register("blah", cometd.blahTransport.check, cometd.blahTransport); +*/ + +dojox.cometd.longPollTransport = new function(){ + this._connectionType="long-polling"; + this._cometd=null; + + this.check = function(types, version, xdomain){ + return ((!xdomain)&&(dojo.indexOf(types, "long-polling") >= 0)); + } + + this.tunnelInit = function(){ + var message = { + channel: "/meta/connect", + clientId: this._cometd.clientId, + connectionType: this._connectionType, + id: ""+this._cometd.messageId++ + }; + message=this._cometd._extendOut(message); + this.openTunnelWith({message: dojo.toJson([message])}); + } + + this.tunnelCollapse = function(){ + // TODO handle transport specific advice + + if(!this._cometd._initialized){ return; } + + if(this._cometd._advice && this._cometd._advice["reconnect"]=="none"){ + console.debug("cometd reconnect: none"); + return; + } + setTimeout(dojo.hitch(this,function(){ this._connect(); }),this._cometd._interval()); + } + + this._connect = function(){ + if(!this._cometd._initialized){ return; } + if(this._cometd._polling) { + console.debug("wait for poll to complete or fail"); + return; + } + + if((this._cometd._advice) && (this._cometd._advice["reconnect"]=="handshake")){ + this._cometd._connected=false; + this._initialized = false; + this._cometd.init(this._cometd.url,this._cometd._props); + }else if(this._cometd._connected){ + var message={ + channel: "/meta/connect", + connectionType: this._connectionType, + clientId: this._cometd.clientId, + id: ""+this._cometd.messageId++ + }; + if (this._cometd.connectTimeout>this._cometd.expectedNetworkDelay) + message.advice={timeout:(this._cometd.connectTimeout-this._cometd.expectedNetworkDelay)}; + + message=this._cometd._extendOut(message); + this.openTunnelWith({message: dojo.toJson([message])}); + } + } + + this.deliver = function(message){ + // Nothing to do + } + + this.openTunnelWith = function(content, url){ + this._cometd._polling = true; + var post = { + url: (url||this._cometd.url), + content: content, + handleAs: this._cometd.handleAs, + load: dojo.hitch(this, function(data){ + this._cometd._polling=false; + this._cometd.deliver(data); + this._cometd._backon(); + this.tunnelCollapse(); + }), + error: dojo.hitch(this, function(err){ + this._cometd._polling=false; + console.debug("tunnel opening failed:", err); + dojo.publish("/cometd/meta", [{cometd:this._cometd,action:"connect",successful:false,state:this._cometd.state()}]); + this._cometd._backoff(); + this.tunnelCollapse(); + }) + }; + + var connectTimeout=this._cometd._connectTimeout(); + if (connectTimeout>0) + post.timeout=connectTimeout; + + this._poll = dojo.xhrPost(post); + } + + this.sendMessages = function(messages){ + for(var i=0; i= 0); + } + + this.tunnelInit = function(){ + var message = { + channel: "/meta/connect", + clientId: this._cometd.clientId, + connectionType: this._connectionType, + id: ""+this._cometd.messageId++ + }; + message = this._cometd._extendOut(message); + this.openTunnelWith({ + message: dojo.toJson([message]) + }); + } + + this.tunnelCollapse = dojox.cometd.longPollTransport.tunnelCollapse; + this._connect = dojox.cometd.longPollTransport._connect; + this.deliver = dojox.cometd.longPollTransport.deliver; + + this.openTunnelWith = function(content, url){ + this._cometd._polling = true; + var script = { + load: dojo.hitch(this, function(data){ + this._cometd._polling=false; + this._cometd.deliver(data); + this._cometd._backon(); + this.tunnelCollapse(); + }), + error: dojo.hitch(this, function(err){ + this._cometd._polling=false; + console.debug("tunnel opening failed:", err); + dojo.publish("/cometd/meta", [{cometd:this._cometd,action:"connect",successful:false,state:this._cometd.state()}]); + this._cometd._backoff(); + this.tunnelCollapse(); + }), + url: (url||this._cometd.url), + content: content, + callbackParamName: "jsonp" + }; + var connectTimeout=this._cometd._connectTimeout(); + if (connectTimeout>0) + script.timeout=connectTimeout; + dojo.io.script.get(script); + } + + this.sendMessages = function(/*array*/ messages){ + for(var i=0; ithis._window) + this._offsets.shift(); + this.samples++; + var total=0; + for (var i in this._offsets) + total+=this._offsets[i]; + this.offset=parseInt((total/this._offsets.length).toFixed()); + + if (this.samples]+)>)/g", "i"); + var text = content.text.replace(regexp,""); + retVal = { + text: text.substring(0, Math.min(400, text.length)), + type: "text" + }; + item._attribs[attribute] = retVal; + } + + if(retVal && this.unescapeHTML){ + if ((attribute == "content" || attribute == "summary" || attribute == "subtitle") && !item["_"+attribute+"Escaped"]) { + retVal.text = this._unescapeHTML(retVal.text); + item["_"+attribute+"Escaped"] = true; + } + } + return retVal ? dojo.isArray(retVal) ? retVal[0]: retVal : undefined; + }, + + getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute){ + // summary: + // Return an attribute value + // description: + // 'item' must be an instance of an object created by the AtomReadStore instance. + // Accepted attributes are id, subtitle, title, summary, content, author, updated, + // published, category, link and alternate + // item: + // An item returned by a call to the 'fetch' method. + // attribute: + // A attribute of the Atom Entry + // defaultValue: + // A default value + // returns: + // An array of values for the attribute value found, otherwise 'defaultValue' + this._assertIsItem(item); + this._assertIsAttribute(attribute); + this._initItem(item); + attribute = attribute.toLowerCase(); + //If the attribute has previously been retrieved, then return it + if(!item._attribs[attribute]){ + this._parseItem(item); + } + var retVal = item._attribs[attribute]; + return retVal ? ((retVal.length !== undefined && typeof(retVal) !== "string") ? retVal : [retVal]) : undefined; + }, + + getAttributes: function(/* item */ item) { + // summary: + // Return an array of attribute names + // description: + // 'item' must be have been created by the AtomReadStore instance. + // tag names of child elements and XML attribute names of attributes + // specified to the element are returned along with special attribute + // names applicable to the element including "tagName", "childNodes" + // if the element has child elements, "text()" if the element has + // child text nodes, and attribute names in '_attributeMap' that match + // the tag name of the element. + // item: + // An XML element + // returns: + // An array of attributes found + this._assertIsItem(item); + if(!item._attribs){ + this._initItem(item); + this._parseItem(item); + } + var attrNames = []; + for(var x in item._attribs){ + attrNames.push(x); + } + return attrNames; //array + }, + + hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute){ + // summary: + // Check whether an element has the attribute + // item: + // 'item' must be created by the AtomReadStore instance. + // attribute: + // An attribute of an Atom Entry item. + // returns: + // True if the element has the attribute, otherwise false + return (this.getValue(item, attribute) !== undefined); //boolean + }, + + containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value){ + // summary: + // Check whether the attribute values contain the value + // item: + // 'item' must be an instance of a dojox.data.XmlItem from the store instance. + // attribute: + // A tag name of a child element, An XML attribute name or one of + // special names + // returns: + // True if the attribute values contain the value, otherwise false + var values = this.getValues(item, attribute); + for(var i = 0; i < values.length; i++){ + if((typeof value === "string")){ + if(values[i].toString && values[i].toString() === value){ + return true; + } + }else if (values[i] === value){ + return true; //boolean + } + } + return false;//boolean + }, + + isItem: function(/* anything */ something){ + // summary: + // Check whether the object is an item (XML element) + // item: + // An object to check + // returns: + // True if the object is an XML element, otherwise false + if(something && something.element && something.store && something.store === this){ + return true; //boolean + } + return false; //boolran + }, + + isItemLoaded: function(/* anything */ something){ + // summary: + // Check whether the object is an item (XML element) and loaded + // item: + // An object to check + // returns: + // True if the object is an XML element, otherwise false + return this.isItem(something); //boolean + }, + + loadItem: function(/* object */ keywordArgs){ + // summary: + // Load an item (XML element) + // keywordArgs: + // object containing the args for loadItem. See dojo.data.api.Read.loadItem() + }, + + getFeatures: function() { + // summary: + // Return supported data APIs + // returns: + // "dojo.data.api.Read" and "dojo.data.api.Write" + var features = { + "dojo.data.api.Read": true + }; + return features; //array + }, + + getLabel: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabel() + if((this.label !== "") && this.isItem(item)){ + var label = this.getValue(item,this.label); + if(label && label.text){ + return label.text; + }else if (label){ + return label.toString(); + }else{ + return undefined; + } + } + return undefined; //undefined + }, + + getLabelAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabelAttributes() + if(this.label !== ""){ + return [this.label]; //array + } + return null; //null + }, + + getFeedValue: function(attribute, defaultValue){ + // summary: + // Non-API method for retrieving values regarding the Atom feed, + // rather than the Atom entries. + var values = this.getFeedValues(attribute, defaultValue); + if(dojo.isArray(values)){ + return values[0]; + } + return values; + }, + + getFeedValues: function(attribute, defaultValue){ + // summary: + // Non-API method for retrieving values regarding the Atom feed, + // rather than the Atom entries. + if(!this.doc){ + return defaultValue; + } + if(!this._feedMetaData){ + this._feedMetaData = { + element: this.doc.getElementsByTagName("feed")[0], + store: this, + _attribs: {} + }; + this._parseItem(this._feedMetaData); + } + return this._feedMetaData._attribs[attribute] || defaultValue; + }, + + _initItem: function(item){ + // summary: + // Initializes an item before it can be parsed. + if(!item._attribs){ + item._attribs = {}; + } + }, + + _fetchItems: function(request, fetchHandler, errorHandler) { + // summary: + // Retrieves the items from the Atom XML document. + var url = this._getFetchUrl(request); + if(!url){ + errorHandler(new Error("No URL specified.")); + return; + } + var localRequest = (!this.sendQuery ? request : null); // use request for _getItems() + + var _this = this; + var docHandler = function(data){ + _this.doc = data; + var items = _this._getItems(data, localRequest); + var query = request.query; + if(query) { + if(query.id) { + items = dojo.filter(items, function(item){ + return (_this.getValue(item, "id") == query.id); + }); + } else if(query.category){ + items = dojo.filter(items, function(entry) { + var cats = _this.getValues(entry, "category"); + if(!cats){ + return false; + } + return dojo.some(cats, "return item.term=='"+query.category+"'"); + }); + } + } + + if (items && items.length > 0) { + fetchHandler(items, request); + } + else { + fetchHandler([], request); + } + }; + + if (this.doc) { + docHandler(this.doc); + }else{ + var getArgs = { + url: url, + handleAs: "xml"//, + // preventCache: true + }; + var getHandler = dojo.xhrGet(getArgs); + getHandler.addCallback(docHandler); + + getHandler.addErrback(function(data){ + errorHandler(data, request); + }); + } + }, + + _getFetchUrl: function(request){ + if(!this.sendQuery){ + return this.url; + } + var query = request.query; + if(!query){ + return this.url; + } + if(dojo.isString(query)){ + return this.url + query; + } + var queryString = ""; + for(var name in query){ + var value = query[name]; + if(value){ + if(queryString){ + queryString += "&"; + } + queryString += (name + "=" + value); + } + } + if(!queryString){ + return this.url; + } + //Check to see if the URL already has query params or not. + var fullUrl = this.url; + if(fullUrl.indexOf("?") < 0){ + fullUrl += "?"; + }else{ + fullUrl += "&"; + } + return fullUrl + queryString; + }, + + _getItems: function(document, request) { + // summary: + // Parses the document in a first pass + if(this._items){ + return this._items; + } + var items = []; + var nodes = []; + + if(document.childNodes.length < 1){ + this._items = items; + console.log("dojox.data.AtomReadStore: Received an invalid Atom document. Check the content type header"); + return items; + } + + var feedNodes = dojo.filter(document.childNodes, "return item.tagName && item.tagName.toLowerCase() == 'feed'"); + + var query = request.query; + + if(!feedNodes || feedNodes.length != 1){ + console.log("dojox.data.AtomReadStore: Received an invalid Atom document, number of feed tags = " + (feedNodes? feedNodes.length : 0)); + return items; + } + + nodes = dojo.filter(feedNodes[0].childNodes, "return item.tagName && item.tagName.toLowerCase() == 'entry'"); + + if(request.onBegin){ + request.onBegin(nodes.length); + } + + for(var i = 0; i < nodes.length; i++){ + var node = nodes[i]; + if(node.nodeType != 1 /*ELEMENT_NODE*/){ + continue; + } + items.push(this._getItem(node)); + } + this._items = items; + return items; + }, + + close: function(/*dojo.data.api.Request || keywordArgs || null */ request){ + // summary: + // See dojo.data.api.Read.close() + }, + +/* internal API */ + + _getItem: function(element){ + return { + element: element, + store: this + }; + }, + + _parseItem: function(item) { + var attribs = item._attribs; + var _this = this; + var text, type; + + function getNodeText(node){ + var txt = node.textContent || node.innerHTML || node.innerXML; + if(!txt && node.childNodes[0]){ + var child = node.childNodes[0]; + if (child && (child.nodeType == 3 || child.nodeType == 4)) { + txt = node.childNodes[0].nodeValue; + } + } + return txt; + } + function parseTextAndType(node) { + return {text: getNodeText(node),type: node.getAttribute("type")}; + } + dojo.forEach(item.element.childNodes, function(node){ + var tagName = node.tagName ? node.tagName.toLowerCase() : ""; + switch(tagName){ + case "title": + attribs[tagName] = { + text: getNodeText(node), + type: node.getAttribute("type") + }; break; + case "subtitle": + case "summary": + case "content": + attribs[tagName] = parseTextAndType(node); + break; + case "author": + var nameNode ,uriNode; + dojo.forEach(node.childNodes, function(child){ + if(!child.tagName){ + return; + } + switch(child.tagName.toLowerCase()){ + case "name":nameNode = child;break; + case "uri": uriNode = child; break; + } + }); + var author = {}; + if(nameNode && nameNode.length == 1){ + author.name = getNodeText(nameNode[0]); + } + if(uriNode && uriNode.length == 1){ + author.uri = getNodeText(uriNode[0]); + } + attribs[tagName] = author; + break; + case "id": attribs[tagName] = getNodeText(node); break; + case "updated": attribs[tagName] = dojo.date.stamp.fromISOString(getNodeText(node) );break; + case "published": attribs[tagName] = dojo.date.stamp.fromISOString(getNodeText(node));break; + case "category": + if(!attribs[tagName]){ + attribs[tagName] = []; + } + attribs[tagName].push({scheme:node.getAttribute("scheme"), term: node.getAttribute("term")}); + break; + case "link": + if(!attribs[tagName]){ + attribs[tagName] = []; + } + var link = { + rel: node.getAttribute("rel"), + href: node.getAttribute("href"), + type: node.getAttribute("type")}; + attribs[tagName].push(link); + + if(link.rel == "alternate") { + attribs["alternate"] = link; + } + break; + default: + break; + } + }); + }, + + _unescapeHTML : function(text) { + //Replace HTML character codes with their unencoded equivalents, e.g. ’ with ' + text = text.replace(/’/m , "'").replace(/″/m , "\"").replace(/</m,">").replace(/>/m,"<").replace(/&/m,"&"); + return text; + }, + + _assertIsItem: function(/* item */ item){ + // summary: + // This function tests whether the item passed in is indeed an item in the store. + // item: + // The item to test for being contained by the store. + if(!this.isItem(item)){ + throw new Error("dojox.data.AtomReadStore: Invalid item argument."); + } + }, + + _assertIsAttribute: function(/* attribute-name-string */ attribute){ + // summary: + // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store. + // attribute: + // The attribute to test for being contained by the store. + if(typeof attribute !== "string"){ + throw new Error("dojox.data.AtomReadStore: Invalid attribute argument."); + } + } +}); +dojo.extend(dojox.data.AtomReadStore,dojo.data.util.simpleFetch); + +} diff --git a/includes/js/dojox/data/CsvStore.js b/includes/js/dojox/data/CsvStore.js new file mode 100644 index 0000000..87f7466 --- /dev/null +++ b/includes/js/dojox/data/CsvStore.js @@ -0,0 +1,561 @@ +if(!dojo._hasResource["dojox.data.CsvStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.CsvStore"] = true; +dojo.provide("dojox.data.CsvStore"); + +dojo.require("dojo.data.util.filter"); +dojo.require("dojo.data.util.simpleFetch"); + +dojo.declare("dojox.data.CsvStore", null, { + // summary: + // The CsvStore implements the dojo.data.api.Read API and reads + // data from files in CSV (Comma Separated Values) format. + // All values are simple string values. References to other items + // are not supported as attribute values in this datastore. + // + // Example data file: + // name, color, age, tagline + // Kermit, green, 12, "Hi, I'm Kermit the Frog." + // Fozzie Bear, orange, 10, "Wakka Wakka Wakka!" + // Miss Piggy, pink, 11, "Kermie!" + // + // Note that values containing a comma must be enclosed with quotes ("") + // Also note that values containing quotes must be escaped with two consecutive quotes (""quoted"") + + /* examples: + * var csvStore = new dojox.data.CsvStore({url:"movies.csv"); + * var csvStore = new dojox.data.CsvStore({url:"http://example.com/movies.csv"); + */ + + constructor: function(/* Object */ keywordParameters){ + // summary: initializer + // keywordParameters: {url: String} + // keywordParameters: {data: String} + // keywordParameters: {label: String} The column label for the column to use for the label returned by getLabel. + + this._attributes = []; // e.g. ["Title", "Year", "Producer"] + this._attributeIndexes = {}; // e.g. {Title: 0, Year: 1, Producer: 2} + this._dataArray = []; // e.g. [[],[],[]] + this._arrayOfAllItems = []; // e.g. [{_csvId:0,_csvStore:store},...] + this._loadFinished = false; + if(keywordParameters.url){ + this.url = keywordParameters.url; + } + this._csvData = keywordParameters.data; + if(keywordParameters.label){ + this.label = keywordParameters.label; + }else if(this.label === ""){ + this.label = undefined; + } + this._storeProp = "_csvStore"; // Property name for the store reference on every item. + this._idProp = "_csvId"; // Property name for the Item Id on every item. + this._features = { + 'dojo.data.api.Read': true, + 'dojo.data.api.Identity': true + }; + this._loadInProgress = false; //Got to track the initial load to prevent duelling loads of the dataset. + this._queuedFetches = []; + }, + + url: "", //Declarative hook for setting Csv source url. + + label: "", //Declarative hook for setting the label attribute. + + _assertIsItem: function(/* item */ item){ + // summary: + // This function tests whether the item passed in is indeed an item in the store. + // item: + // The item to test for being contained by the store. + if(!this.isItem(item)){ + throw new Error("dojox.data.CsvStore: a function was passed an item argument that was not an item"); + } + }, + + _assertIsAttribute: function(/* item || String */ attribute){ + // summary: + // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store. + // attribute: + // The attribute to test for being contained by the store. + if(!dojo.isString(attribute)){ + throw new Error("dojox.data.CsvStore: a function was passed an attribute argument that was not an attribute object nor an attribute name string"); + } + }, + +/*************************************** + dojo.data.api.Read API +***************************************/ + getValue: function( /* item */ item, + /* attribute || attribute-name-string */ attribute, + /* value? */ defaultValue){ + // summary: + // See dojo.data.api.Read.getValue() + // Note that for the CsvStore, an empty string value is the same as no value, + // so the defaultValue would be returned instead of an empty string. + this._assertIsItem(item); + this._assertIsAttribute(attribute); + var itemValue = defaultValue; + if(this.hasAttribute(item, attribute)){ + var itemData = this._dataArray[this.getIdentity(item)]; + itemValue = itemData[this._attributeIndexes[attribute]]; + } + return itemValue; //String + }, + + getValues: function(/* item */ item, + /* attribute || attribute-name-string */ attribute){ + // summary: + // See dojo.data.api.Read.getValues() + // CSV syntax does not support multi-valued attributes, so this is just a + // wrapper function for getValue(). + var value = this.getValue(item, attribute); + return (value ? [value] : []); //Array + }, + + getAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getAttributes() + this._assertIsItem(item); + var attributes = []; + var itemData = this._dataArray[this.getIdentity(item)]; + for(var i=0; i= 0 && identity < this._dataArray.length){ + return true; //Boolean + } + } + return false; //Boolean + }, + + isItemLoaded: function(/* anything */ something){ + // summary: + // See dojo.data.api.Read.isItemLoaded() + // The CsvStore always loads all items, so if it's an item, then it's loaded. + return this.isItem(something); //Boolean + }, + + loadItem: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.loadItem() + // description: + // The CsvStore always loads all items, so if it's an item, then it's loaded. + // From the dojo.data.api.Read.loadItem docs: + // If a call to isItemLoaded() returns true before loadItem() is even called, + // then loadItem() need not do any work at all and will not even invoke + // the callback handlers. + }, + + getFeatures: function(){ + // summary: + // See dojo.data.api.Read.getFeatures() + return this._features; //Object + }, + + getLabel: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabel() + if(this.label && this.isItem(item)){ + return this.getValue(item,this.label); //String + } + return undefined; //undefined + }, + + getLabelAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabelAttributes() + if(this.label){ + return [this.label]; //array + } + return null; //null + }, + + + // The dojo.data.api.Read.fetch() function is implemented as + // a mixin from dojo.data.util.simpleFetch. + // That mixin requires us to define _fetchItems(). + _fetchItems: function( /* Object */ keywordArgs, + /* Function */ findCallback, + /* Function */ errorCallback){ + // summary: + // See dojo.data.util.simpleFetch.fetch() + + var self = this; + + var filter = function(requestArgs, arrayOfAllItems){ + var items = null; + if(requestArgs.query){ + items = []; + var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false; + + //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the + //same value for each item examined. Much more efficient. + var regexpList = {}; + for(var key in requestArgs.query){ + var value = requestArgs.query[key]; + if(typeof value === "string"){ + regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase); + } + } + + for(var i = 0; i < arrayOfAllItems.length; ++i){ + var match = true; + var candidateItem = arrayOfAllItems[i]; + for(var key in requestArgs.query){ + var value = requestArgs.query[key]; + if(!self._containsValue(candidateItem, key, value, regexpList[key])){ + match = false; + } + } + if(match){ + items.push(candidateItem); + } + } + }else{ + // We want a copy to pass back in case the parent wishes to sort the array. We shouldn't allow resort + // of the internal list so that multiple callers can get lists and sort without affecting each other. + if(arrayOfAllItems.length> 0){ + items = arrayOfAllItems.slice(0,arrayOfAllItems.length); + } + } + findCallback(items, requestArgs); + }; + + if(this._loadFinished){ + filter(keywordArgs, this._arrayOfAllItems); + }else{ + if(this.url !== ""){ + //If fetches come in before the loading has finished, but while + //a load is in progress, we have to defer the fetching to be + //invoked in the callback. + if(this._loadInProgress){ + this._queuedFetches.push({args: keywordArgs, filter: filter}); + }else{ + this._loadInProgress = true; + var getArgs = { + url: self.url, + handleAs: "text" + }; + var getHandler = dojo.xhrGet(getArgs); + getHandler.addCallback(function(data){ + self._processData(data); + filter(keywordArgs, self._arrayOfAllItems); + self._handleQueuedFetches(); + }); + getHandler.addErrback(function(error){ + self._loadInProgress = false; + if(errorCallback){ + errorCallback(error, keywordArgs); + }else{ + throw error; + } + }); + } + }else if(this._csvData){ + this._processData(this._csvData); + this._csvData = null; + filter(keywordArgs, this._arrayOfAllItems); + }else{ + var error = new Error("dojox.data.CsvStore: No CSV source data was provided as either URL or String data input."); + if(errorCallback){ + errorCallback(error, keywordArgs); + }else{ + throw error; + } + } + } + }, + + close: function(/*dojo.data.api.Request || keywordArgs || null */ request){ + // summary: + // See dojo.data.api.Read.close() + }, + + + // ------------------------------------------------------------------- + // Private methods + _getArrayOfArraysFromCsvFileContents: function(/* string */ csvFileContents){ + /* summary: + * Parses a string of CSV records into a nested array structure. + * description: + * Given a string containing CSV records, this method parses + * the string and returns a data structure containing the parsed + * content. The data structure we return is an array of length + * R, where R is the number of rows (lines) in the CSV data. The + * return array contains one sub-array for each CSV line, and each + * sub-array contains C string values, where C is the number of + * columns in the CSV data. + */ + + /* example: + * For example, given this CSV string as input: + * "Title, Year, Producer \n Alien, 1979, Ridley Scott \n Blade Runner, 1982, Ridley Scott" + * this._dataArray will be set to: + * [["Alien", "1979", "Ridley Scott"], + * ["Blade Runner", "1982", "Ridley Scott"]] + * And this._attributes will be set to: + * ["Title", "Year", "Producer"] + * And this._attributeIndexes will be set to: + * { "Title":0, "Year":1, "Producer":2 } + */ + if(dojo.isString(csvFileContents)){ + var lineEndingCharacters = new RegExp("\r\n|\n|\r"); + var leadingWhiteSpaceCharacters = new RegExp("^\\s+",'g'); + var trailingWhiteSpaceCharacters = new RegExp("\\s+$",'g'); + var doubleQuotes = new RegExp('""','g'); + var arrayOfOutputRecords = []; + + var arrayOfInputLines = csvFileContents.split(lineEndingCharacters); + for(var i = 0; i < arrayOfInputLines.length; ++i){ + var singleLine = arrayOfInputLines[i]; + if(singleLine.length > 0){ + var listOfFields = singleLine.split(','); + var j = 0; + while(j < listOfFields.length){ + var space_field_space = listOfFields[j]; + var field_space = space_field_space.replace(leadingWhiteSpaceCharacters, ''); // trim leading whitespace + var field = field_space.replace(trailingWhiteSpaceCharacters, ''); // trim trailing whitespace + var firstChar = field.charAt(0); + var lastChar = field.charAt(field.length - 1); + var secondToLastChar = field.charAt(field.length - 2); + var thirdToLastChar = field.charAt(field.length - 3); + if(field.length === 2 && field == "\"\""){ + listOfFields[j] = ""; //Special case empty string field. + }else if((firstChar == '"') && + ((lastChar != '"') || + ((lastChar == '"') && (secondToLastChar == '"') && (thirdToLastChar != '"')))){ + if(j+1 === listOfFields.length){ + // alert("The last field in record " + i + " is corrupted:\n" + field); + return null; //null + } + var nextField = listOfFields[j+1]; + listOfFields[j] = field_space + ',' + nextField; + listOfFields.splice(j+1, 1); // delete element [j+1] from the list + }else{ + if((firstChar == '"') && (lastChar == '"')){ + field = field.slice(1, (field.length - 1)); // trim the " characters off the ends + field = field.replace(doubleQuotes, '"'); // replace "" with " + } + listOfFields[j] = field; + j += 1; + } + } + arrayOfOutputRecords.push(listOfFields); + } + } + + // The first item of the array must be the header row with attribute names. + this._attributes = arrayOfOutputRecords.shift(); + for(var i=0; i 0) { + for(var i = 0; i < this._queuedFetches.length; i++){ + var fData = this._queuedFetches[i]; + var delayedFilter = fData.filter; + var delayedQuery = fData.args; + if(delayedFilter){ + delayedFilter(delayedQuery, this._arrayOfAllItems); + }else{ + this.fetchItemByIdentity(fData.args); + } + } + this._queuedFetches = []; + } + } +}); +//Mix in the simple fetch implementation to this class. +dojo.extend(dojox.data.CsvStore,dojo.data.util.simpleFetch); + +} diff --git a/includes/js/dojox/data/FlickrRestStore.js b/includes/js/dojox/data/FlickrRestStore.js new file mode 100644 index 0000000..466d6df --- /dev/null +++ b/includes/js/dojox/data/FlickrRestStore.js @@ -0,0 +1,471 @@ +if(!dojo._hasResource["dojox.data.FlickrRestStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.FlickrRestStore"] = true; +dojo.provide("dojox.data.FlickrRestStore"); + +dojo.require("dojox.data.FlickrStore"); + +dojo.declare("dojox.data.FlickrRestStore", + dojox.data.FlickrStore, { + constructor: function(/*Object*/args){ + // summary: + // Initializer for the FlickrRestStore store. + // description: + // The FlickrRestStore is a Datastore interface to one of the basic services + // of the Flickr service, the public photo feed. This does not provide + // access to all the services of Flickr. + // This store cannot do * and ? filtering as the flickr service + // provides no interface for wildcards. + if(args && args.label){ + if(args.label) { + this.label = args.label; + } + if(args.apikey) { + this._apikey = args.apikey; + } + } + this._cache = []; + this._prevRequests = {}; + this._handlers = {}; + this._prevRequestRanges = []; + this._maxPhotosPerUser = {}; + this._id = dojox.data.FlickrRestStore.prototype._id++; + }, + + // _id: Integer + // A unique identifier for this store. + _id: 0, + + // _requestCount: Integer + // A counter for the number of requests made. This is used to define + // the callback function that Flickr will use. + _requestCount: 0, + + // _flickrRestUrl: String + // The URL to the Flickr REST services. + _flickrRestUrl: "http://www.flickr.com/services/rest/", + + // _apikey: String + // The users API key to be used when accessing Flickr REST services. + _apikey: null, + + // _storeRef: String + // A key used to mark an data store item as belonging to this store. + _storeRef: "_S", + + // _cache: Array + // An Array of all previously downloaded picture info. + _cache: null, + + // _prevRequests: Object + // A HashMap used to record the signature of a request to prevent duplicate + // request being made. + _prevRequests: null, + + // _handlers: Object + // A HashMap used to record the handlers registered for a single remote request. Multiple + // requests may be made for the same information before the first request has finished. + // Each element of this Object is an array of handlers to call back when the request finishes. + // This prevents multiple requests being made for the same information. + _handlers: null, + + // _sortAttributes: Object + // A quick lookup of valid attribute names in a sort query. + _sortAttributes: { + "date-posted": true, + "date-taken": true, + "interestingness": true + }, + + _fetchItems: function(request, fetchHandler, errorHandler){ + // summary: Fetch flickr items that match to a query + // request: + // A request object + // fetchHandler: + // A function to call for fetched items + // errorHandler: + // A function to call on error + var query = {}; + if(!request.query){ + request.query = query = {}; + } else { + dojo.mixin(query, request.query); + } + + var primaryKey = []; + var secondaryKey = []; + + //Generate a unique function to be called back + var callbackFn = "FlickrRestStoreCallback_" + this._id + "_" + (++this._requestCount); + //Build up the content to send the request for. + var content = { + format: "json", + method: "flickr.photos.search", + api_key: this._apikey, + extras: "owner_name,date_upload,date_taken", + jsoncallback: callbackFn + }; + var isRest = false; + if(query.userid){ + isRest = true; + content.user_id = request.query.userid; + primaryKey.push("userid"+request.query.userid); + } + if(query.apikey){ + isRest = true; + content.api_key = request.query.apikey; + secondaryKey.push("api"+request.query.apikey); + } else{ + throw Error("dojox.data.FlickrRestStore: An API key must be specified."); + } + request._curCount = request.count; + if(query.page){ + content.page = request.query.page; + secondaryKey.push("page" + content.page); + }else if(typeof(request.start) != "undefined" && request.start != null) { + if(!request.count){ + request.count = 20; + } + var diff = request.start % request.count; + var start = request.start, count = request.count; + //If the count does not divide cleanly into the start number, + //more work has to be done to figure out the best page to request + if(diff != 0) { + if(start < count / 2) { + //If the first record requested is less than half the amount requested, + //then request from 0 to the count record + count = start + count; + start = 0; + } else { + var divLimit = 20, div = 2; + for(var i = divLimit; i > 0; i--) { + if(start % i == 0 && (start/i) >= count){ + div = i; + break; + } + } + count = start/div; + } + request._realStart = request.start; + request._realCount = request.count; + request._curStart = start; + request._curCount = count; + } else { + request._realStart = request._realCount = null; + request._curStart = request.start; + request._curCount = request.count; + } + + content.page = (start / count) + 1; + secondaryKey.push("page" + content.page); + } + if(request._curCount){ + content.per_page = request._curCount; + secondaryKey.push("count" + request._curCount); + } + + if(query.lang){ + content.lang = request.query.lang; + primaryKey.push("lang" + request.lang); + } + var url = this._flickrRestUrl; + + if(query.setid){ + content.method = "flickr.photosets.getPhotos"; + content.photoset_id = request.query.set; + primaryKey.push("set" + request.query.set); + } + + if(query.tags){ + if(query.tags instanceof Array){ + content.tags = query.tags.join(","); + } else { + content.tags=query.tags; + } + primaryKey.push("tags" + content.tags); + + if(query["tag_mode"] && (query.tag_mode.toLowerCase() == "any" + || query.tag_mode.toLowerCase() == "all")){ + content.tag_mode = query.tag_mode; + } + } + if(query.text){ + content.text=query.text; + primaryKey.push("text:"+query.text); + } + + //The store only supports a single sort attribute, even though the + //Read API technically allows multiple sort attributes + if(query.sort && query.sort.length > 0){ + //The default sort attribute is 'date-posted' + if(!query.sort[0].attribute){ + query.sort[0].attribute = "date-posted"; + } + + //If the sort attribute is valid, check if it is ascending or + //descending. + if(this._sortAttributes[query.sort[0].attribute]) { + if(query.sort[0].descending){ + content.sort = query.sort[0].attribute + "-desc"; + } else { + content.sort = query.sort[0].attribute + "-asc"; + } + } + } else { + //The default sort in the Dojo Data API is ascending. + content.sort = "date-posted-asc"; + } + primaryKey.push("sort:"+content.sort); + + //Generate a unique key for this request, so the store can + //detect duplicate requests. + primaryKey = primaryKey.join("."); + secondaryKey = secondaryKey.length > 0 ? "." + secondaryKey.join(".") : ""; + var requestKey = primaryKey + secondaryKey; + + //Make a copy of the request, in case the source object is modified + //before the request completes + request = { + query: query, + count: request._curCount, + start: request._curStart, + _realCount: request._realCount, + _realStart: request._realStart, + onBegin: request.onBegin, + onComplete: request.onComplete, + onItem: request.onItem + }; + + var thisHandler = { + request: request, + fetchHandler: fetchHandler, + errorHandler: errorHandler + }; + + //If the request has already been made, but not yet completed, + //then add the callback handler to the list of handlers + //for this request, and finish. + if(this._handlers[requestKey]){ + this._handlers[requestKey].push(thisHandler); + return; + } + + this._handlers[requestKey] = [thisHandler]; + + //Linking this up to Flickr is a PAIN! + var self = this; + var handle = null; + var getArgs = { + url: this._flickrRestUrl, + preventCache: true, + content: content + }; + + var doHandle = function(processedData, data, handler){ + var onBegin = handler.request.onBegin; + handler.request.onBegin = null; + var maxPhotos; + var req = handler.request; + + if(typeof(req._realStart) != undefined && req._realStart != null) { + req.start = req._realStart; + req.count = req._realCount; + req._realStart = req._realCount = null; + } + + //If the request contains an onBegin method, the total number + //of photos must be calculated. + if(onBegin){ + if(data && typeof(data.photos.perpage) != "undefined" && typeof(data.photos.pages) != "undefined"){ + if(data.photos.perpage * data.photos.pages <= handler.request.start + handler.request.count){ + //If the final page of results has been received, it is possible to + //know exactly how many photos there are + maxPhotos = handler.request.start + data.photos.photo.length; + }else{ + //If the final page of results has not yet been received, + //it is not possible to tell exactly how many photos exist, so + //return the number of pages multiplied by the number of photos per page. + maxPhotos = data.photos.perpage * data.photos.pages; + } + self._maxPhotosPerUser[primaryKey] = maxPhotos; + onBegin(maxPhotos, handler.request); + } else if(self._maxPhotosPerUser[primaryKey]) { + onBegin(self._maxPhotosPerUser[primaryKey], handler.request); + } + } + //Call whatever functions the caller has defined on the request object, except for onBegin + handler.fetchHandler(processedData, handler.request); + if(onBegin){ + //Replace the onBegin function, if it existed. + handler.request.onBegin = onBegin; + } + }; + + //Define a callback for the script that iterates through a list of + //handlers for this piece of data. Multiple requests can come into + //the store for the same data. + var myHandler = function(data){ + //The handler should not be called more than once, so disconnect it. + //if(handle !== null){ dojo.disconnect(handle); } + if(data.stat != "ok"){ + errorHandler(null, request); + }else{ //Process the items... + var handlers = self._handlers[requestKey]; + if(!handlers){ + console.log("FlickrRestStore: no handlers for data", data); + return; + } + + self._handlers[requestKey] = null; + self._prevRequests[requestKey] = data; + + //Process the data once. + var processedData = self._processFlickrData(data, request, primaryKey); + if(!self._prevRequestRanges[primaryKey]) { + self._prevRequestRanges[primaryKey] = []; + } + self._prevRequestRanges[primaryKey].push({ + start: request.start, + end: request.start + data.photos.photo.length + }); + + //Iterate through the array of handlers, calling each one. + for(var i = 0; i < handlers.length; i++ ){ + doHandle(processedData, data, handlers[i]); + } + } + }; + + var data = this._prevRequests[requestKey]; + + //If the data was previously retrieved, there is no need to fetch it again. + if(data){ + this._handlers[requestKey] = null; + doHandle(this._cache[primaryKey], data, thisHandler); + return; + } else if(this._checkPrevRanges(primaryKey, request.start, request.count)) { + //If this range of data has already been retrieved, reuse it. + this._handlers[requestKey] = null; + doHandle(this._cache[primaryKey], null, thisHandler); + return; + } + + dojo.global[callbackFn] = function(data){ + myHandler(data); + //Clean up the function, it should never be called again + dojo.global[callbackFn] = null; + }; + + var deferred = dojo.io.script.get(getArgs); + + //We only set up the errback, because the callback isn't ever really used because we have + //to link to the jsonFlickrFeed function.... + deferred.addErrback(function(error){ + dojo.disconnect(handle); + errorHandler(error, request); + }); + }, + + getAttributes: function(item){ + // summary: + // See dojo.data.api.Read.getAttributes() + return ["title", "author", "imageUrl", "imageUrlSmall", + "imageUrlMedium", "imageUrlThumb", "link", + "dateTaken", "datePublished"]; + }, + + getValues: function(item, attribute){ + // summary: + // See dojo.data.api.Read.getValue() + this._assertIsItem(item); + this._assertIsAttribute(attribute); + if(attribute === "title"){ + return [this._unescapeHtml(item.title)]; // String + }else if(attribute === "author"){ + return [item.ownername]; // String + }else if(attribute === "imageUrlSmall"){ + return [item.media.s]; // String + }else if(attribute === "imageUrl"){ + return [item.media.l]; // String + }else if(attribute === "imageUrlMedium"){ + return [item.media.m]; // String + }else if(attribute === "imageUrlThumb"){ + return [item.media.t]; // String + }else if(attribute === "link"){ + return ["http://www.flickr.com/photos/" + item.owner + "/" + item.id]; // String + }else if(attribute === "dateTaken"){ + return item.datetaken; + }else if(attribute === "datePublished"){ + return item.datepublished; + } + + return undefined; + }, + + _processFlickrData: function(/* Object */data, /* Object */request, /* String */ cacheKey){ + // summary: Processes the raw data from Flickr and updates the internal cache. + // data: + // Data returned from Flickr + // request: + // The original dojo.data.Request object passed in by the user. + + //If the data contains an 'item' object, it has not come from the REST services, + //so process it using the FlickrStore. + if(data.items){ + return dojox.data.FlickrStore.prototype._processFlickrData.apply(this,arguments); + } + + var template = ["http://farm", null, ".static.flickr.com/", null, "/", null, "_", null]; + + var items = []; + if(data.stat == "ok" && data.photos && data.photos.photo){ + items = data.photos.photo; + + //Add on the store ref so that isItem can work. + for(var i = 0; i < items.length; i++){ + var item = items[i]; + item[this._storeRef] = this; + + template[1] = item.farm; + template[3] = item.server; + template[5] = item.id; + template[7] = item.secret; + + var base = template.join(""); + item.media = { + s: base + "_s.jpg", + m: base + "_m.jpg", + l: base + ".jpg", + t: base + "_t.jpg" + }; + } + } + var start = request.start ? request.start : 0; + var arr = this._cache[cacheKey]; + if(!arr) { + this._cache[cacheKey] = arr = []; + } + for(var count = 0; count < items.length; count++){ + arr[count + start] = items[count]; + } + + return arr; // Array + }, + + _checkPrevRanges: function(primaryKey, start, count) { + var end = start + count; + var arr = this._prevRequestRanges[primaryKey]; + if(!arr) { + return false; + } + for(var i = 0; i< arr.length; i++) { + if(start >= arr[i].start && + end <= arr[i].end) { + return true; + } + } + return false; + } +}); + + +} diff --git a/includes/js/dojox/data/FlickrStore.js b/includes/js/dojox/data/FlickrStore.js new file mode 100644 index 0000000..4f282df --- /dev/null +++ b/includes/js/dojox/data/FlickrStore.js @@ -0,0 +1,257 @@ +if(!dojo._hasResource["dojox.data.FlickrStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.FlickrStore"] = true; +dojo.provide("dojox.data.FlickrStore"); + +dojo.require("dojo.data.util.simpleFetch"); +dojo.require("dojo.io.script"); +dojo.require("dojo.date.stamp"); + +dojo.declare("dojox.data.FlickrStore", null, { + constructor: function(/*Object*/args){ + // summary: + // Initializer for the FlickrStore store. + // description: + // The FlickrStore is a Datastore interface to one of the basic services + // of the Flickr service, the public photo feed. This does not provide + // access to all the services of Flickr. + // This store cannot do * and ? filtering as the flickr service + // provides no interface for wildcards. + if(args && args.label){ + this.label = args.label; + } + }, + + _flickrUrl: "http://api.flickr.com/services/feeds/photos_public.gne", + + _storeRef: "_S", + + label: "title", + + _assertIsItem: function(/* item */ item){ + // summary: + // This function tests whether the item passed in is indeed an item in the store. + // item: + // The item to test for being contained by the store. + if(!this.isItem(item)){ + throw new Error("dojox.data.FlickrStore: a function was passed an item argument that was not an item"); + } + }, + + _assertIsAttribute: function(/* attribute-name-string */ attribute){ + // summary: + // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store. + // attribute: + // The attribute to test for being contained by the store. + if(typeof attribute !== "string"){ + throw new Error("dojox.data.FlickrStore: a function was passed an attribute argument that was not an attribute name string"); + } + }, + + getFeatures: function(){ + // summary: + // See dojo.data.api.Read.getFeatures() + return { + 'dojo.data.api.Read': true + }; + }, + + getValue: function(item, attribute){ + // summary: + // See dojo.data.api.Read.getValue() + var values = this.getValues(item, attribute); + if(values){ + return values[0]; + } + return undefined; + }, + + getAttributes: function(item){ + // summary: + // See dojo.data.api.Read.getAttributes() + return ["title", "description", "author", "datePublished", "dateTaken", "imageUrl", "imageUrlSmall", "imageUrlMedium", "tags", "link"]; + }, + + hasAttribute: function(item, attribute){ + // summary: + // See dojo.data.api.Read.hasAttributes() + if(this.getValue(item,attribute)){ + return true; + } + return false; + }, + + isItemLoaded: function(item){ + // summary: + // See dojo.data.api.Read.isItemLoaded() + return this.isItem(item); + }, + + loadItem: function(keywordArgs){ + // summary: + // See dojo.data.api.Read.loadItem() + }, + + getLabel: function(item){ + // summary: + // See dojo.data.api.Read.getLabel() + return this.getValue(item,this.label); + }, + + getLabelAttributes: function(item){ + // summary: + // See dojo.data.api.Read.getLabelAttributes() + return [this.label]; + }, + + containsValue: function(item, attribute, value){ + // summary: + // See dojo.data.api.Read.containsValue() + var values = this.getValues(item,attribute); + for(var i = 0; i < values.length; i++){ + if(values[i] === value){ + return true; + } + } + return false; + }, + + getValues: function(item, attribute){ + // summary: + // See dojo.data.api.Read.getValue() + + this._assertIsItem(item); + this._assertIsAttribute(attribute); + if(attribute === "title"){ + return [this._unescapeHtml(item.title)]; + }else if(attribute === "author"){ + return [this._unescapeHtml(item.author)]; + }else if(attribute === "datePublished"){ + return [dojo.date.stamp.fromISOString(item.published)]; + }else if(attribute === "dateTaken"){ + return [dojo.date.stamp.fromISOString(item.date_taken)]; + }else if(attribute === "imageUrlSmall"){ + return [item.media.m.replace(/_m\./, "_s.")]; + }else if(attribute === "imageUrl"){ + return [item.media.m.replace(/_m\./, ".")]; + }else if(attribute === "imageUrlMedium"){ + return [item.media.m]; + }else if(attribute === "link"){ + return [item.link]; + }else if(attribute === "tags"){ + return item.tags.split(" "); + }else if(attribute === "description"){ + return [this._unescapeHtml(item.description)]; + } + return undefined; + }, + + isItem: function(item){ + // summary: + // See dojo.data.api.Read.isItem() + if(item && item[this._storeRef] === this){ + return true; + } + return false; + }, + + close: function(request){ + // summary: + // See dojo.data.api.Read.close() + }, + + _fetchItems: function(request, fetchHandler, errorHandler){ + // summary: + // Fetch flickr items that match to a query + // request: + // A request object + // fetchHandler: + // A function to call for fetched items + // errorHandler: + // A function to call on error + + if(!request.query){ + request.query={}; + } + + //Build up the content to send the request for. + var content = {format: "json", tagmode:"any"}; + if (request.query.tags) { + content.tags = request.query.tags; + } + if (request.query.tagmode) { + content.tagmode = request.query.tagmode; + } + if (request.query.userid) { + content.id = request.query.userid; + } + if (request.query.userids) { + content.ids = request.query.userids; + } + if (request.query.lang) { + content.lang = request.query.lang; + } + + //Linking this up to Flickr is a PAIN! + var self = this; + var handle = null; + var getArgs = { + url: this._flickrUrl, + preventCache: true, + content: content + }; + var myHandler = function(data){ + if(handle !== null){ + dojo.disconnect(handle); + } + + //Process the items... + fetchHandler(self._processFlickrData(data), request); + }; + handle = dojo.connect("jsonFlickrFeed", myHandler); + var deferred = dojo.io.script.get(getArgs); + + //We only set up the errback, because the callback isn't ever really used because we have + //to link to the jsonFlickrFeed function.... + deferred.addErrback(function(error){ + dojo.disconnect(handle); + errorHandler(error, request); + }); + }, + + _processFlickrData: function(data){ + var items = []; + if(data.items){ + items = data.items; + //Add on the store ref so that isItem can work. + for(var i = 0; i < data.items.length; i++){ + var item = data.items[i]; + item[this._storeRef] = this; + } + } + return items; + }, + + _unescapeHtml: function(str){ + // summary: Utility function to un-escape XML special characters in an HTML string. + // description: Utility function to un-escape XML special characters in an HTML string. + // + // str: String. + // The string to un-escape + // returns: HTML String converted back to the normal text (unescaped) characters (<,>,&, ", etc,). + // + //TODO: Check to see if theres already compatible escape() in dojo.string or dojo.html + str = str.replace(/&/gm, "&").replace(/</gm, "<").replace(/>/gm, ">").replace(/"/gm, "\""); + str = str.replace(/'/gm, "'"); + return str; + } +}); +dojo.extend(dojox.data.FlickrStore,dojo.data.util.simpleFetch); + +//We have to define this because of how the Flickr API works. +//This somewhat stinks, but what can you do? +if (!jsonFlickrFeed) { + var jsonFlickrFeed = function(data){}; +} + + +} diff --git a/includes/js/dojox/data/HtmlStore.js b/includes/js/dojox/data/HtmlStore.js new file mode 100644 index 0000000..188aac6 --- /dev/null +++ b/includes/js/dojox/data/HtmlStore.js @@ -0,0 +1,531 @@ +if(!dojo._hasResource["dojox.data.HtmlStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.HtmlStore"] = true; +dojo.provide("dojox.data.HtmlStore"); + +dojo.require("dojox.data.dom"); +dojo.require("dojo.data.util.simpleFetch"); +dojo.require("dojo.data.util.filter"); + +dojo.declare("dojox.data.HtmlStore", null, { + constructor: function(/*Object*/args){ + // summary: + // Initializer for the HTML table store. + // description: + // The HtmlStore can be created in one of two ways: a) by parsing an existing + // table or list DOM node on the current page or b) by referencing an external url and giving + // the id of the table or listin that page. The remote url will be parsed as an html page. + // + // The HTML table or list should be of the following form: + // + // | + // | + // | + // | + // | + // | + // | + // | + // | + // | + // | + // | + // | + // | + // | + // | + // | + // |
Attribute1Attribute2
Value1.1Value1.2
Value2.1Value2.2
+ // + // -or- + // + // |
    + // |
  • Value.1
  • + // |
  • Value.2
  • + // |
+ // + // -or- + // + // |
    + // |
  1. Value.1
  2. + // |
  3. Value.2
  4. + // |
+ // + // args: + // An anonymous object to initialize properties. It expects the following values: + // dataId: The id of the HTML table to use. + // OR + // url: The url of the remote page to load + // dataId: The id of the table element in the remote page + + if(args.url){ + if(!args.dataId) + throw new Error("dojo.data.HtmlStore: Cannot instantiate using url without an id!"); + this.url = args.url; + this.dataId = args.dataId; + }else{ + if(args.dataId){ + this._rootNode = dojo.byId(args.dataId); + this.dataId = this._rootNode.id; + }else{ + this._rootNode = dojo.byId(this.dataId); + } + this._indexItems(); + } + }, + + url: "", // So the parser can instantiate the store via markup. + dataId: "", // So the parser can instantiate the store via markup. + + _indexItems: function(){ + this._getHeadings(); + if (this._rootNode.rows){//tables + if(this._rootNode.tBodies && this._rootNode.tBodies.length > 0) { + this._rootNode = this._rootNode.tBodies[0]; + } + var i; + for(i=0; i 0)?values[0]:defaultValue; //Object || int || Boolean + }, + + getValues: function(/* item */ item, + /* attribute-name-string */ attribute){ + // summary: + // See dojo.data.api.Read.getValues() + + this._assertIsItem(item); + var index = this._assertIsAttribute(attribute); + + if(index>-1){ + if (item.cells){ + return [dojox.data.dom.textContent(item.cells[index])]; + }else{//return Value for lists + return [dojox.data.dom.textContent(item)]; + } + } + return []; //Array + }, + + getAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getAttributes() + this._assertIsItem(item); + var attributes = []; + for(var i=0; i 0; + }, + + containsValue: function(/* item */ item, + /* attribute-name-string */ attribute, + /* anything */ value){ + // summary: + // See dojo.data.api.Read.containsValue() + var regexp = undefined; + if(typeof value === "string"){ + regexp = dojo.data.util.filter.patternToRegExp(value, false); + } + return this._containsValue(item, attribute, value, regexp); //boolean. + }, + + _containsValue: function( /* item */ item, + /* attribute-name-string */ attribute, + /* anything */ value, + /* RegExp?*/ regexp){ + // summary: + // Internal function for looking at the values contained by the item. + // description: + // Internal function for looking at the values contained by the item. This + // function allows for denoting if the comparison should be case sensitive for + // strings or not (for handling filtering cases where string case should not matter) + // + // item: + // The data item to examine for attribute values. + // attribute: + // The attribute to inspect. + // value: + // The value to match. + // regexp: + // Optional regular expression generated off value if value was of string type to handle wildcarding. + // If present and attribute values are string, then it can be used for comparison instead of 'value' + var values = this.getValues(item, attribute); + for(var i = 0; i < values.length; ++i){ + var possibleValue = values[i]; + if(typeof possibleValue === "string" && regexp){ + return (possibleValue.match(regexp) !== null); + }else{ + //Non-string matching. + if(value === possibleValue){ + return true; // Boolean + } + } + } + return false; // Boolean + }, + + isItem: function(/* anything */ something){ + // summary: + // See dojo.data.api.Read.isItem() + if(something && something.store && something.store === this){ + return true; //boolean + } + return false; //boolean + }, + + isItemLoaded: function(/* anything */ something){ + // summary: + // See dojo.data.api.Read.isItemLoaded() + return this.isItem(something); + }, + + loadItem: function(/* Object */ keywordArgs){ + // summary: + // See dojo.data.api.Read.loadItem() + this._assertIsItem(keywordArgs.item); + }, + + _fetchItems: function(request, fetchHandler, errorHandler){ + // summary: + // Fetch items (XML elements) that match to a query + // description: + // If '_fetchUrl' is specified, it is used to load an XML document + // with a query string. + // Otherwise and if 'url' is specified, the XML document is + // loaded and list XML elements that match to a query (set of element + // names and their text attribute values that the items to contain). + // A wildcard, "*" can be used to query values to match all + // occurrences. + // If '_rootItem' is specified, it is used to fetch items. + // request: + // A request object + // fetchHandler: + // A function to call for fetched items + // errorHandler: + // A function to call on error + + if(this._rootNode){ + this._finishFetchItems(request, fetchHandler, errorHandler); + }else{ + if(!this.url){ + this._rootNode = dojo.byId(this.dataId); + }else{ + var getArgs = { + url: this.url, + handleAs: "text" + }; + var self = this; + var getHandler = dojo.xhrGet(getArgs); + getHandler.addCallback(function(data){ + var findNode = function(node, id){ + if(node.id == id){ + return node; //object + } + if(node.childNodes){ + for(var i=0; i 0){ + items = arrayOfAllItems.slice(0,arrayOfAllItems.length); + } + fetchHandler(items, request); + } + }, + + getFeatures: function(){ + // summary: + // See dojo.data.api.Read.getFeatures() + return { + 'dojo.data.api.Read': true, + 'dojo.data.api.Identity': true + }; + }, + + close: function(/*dojo.data.api.Request || keywordArgs || null */ request){ + // summary: + // See dojo.data.api.Read.close() + // nothing to do here! + }, + + getLabel: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabel() + if(this.isItem(item)){ + if(item.cells){ + return "Item #" + this.getIdentity(item); + }else{ + return this.getValue(item,"name"); + } + } + return undefined; + }, + + getLabelAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabelAttributes() + if(item.cells){ + return null; + }else{ + return ["name"]; + } + }, + +/*************************************** + dojo.data.api.Identity API +***************************************/ + + getIdentity: function(/* item */ item){ + // summary: + // See dojo.data.api.Identity.getIdentity() + this._assertIsItem(item); + if(this.hasAttribute(item, "name")){ + return this.getValue(item,"name"); + }else{ + return item._ident; + } + }, + + getIdentityAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Identity.getIdentityAttributes() + //Identity isn't taken from a public attribute. + return null; + }, + + fetchItemByIdentity: function(keywordArgs){ + // summary: + // See dojo.data.api.Identity.fetchItemByIdentity() + var identity = keywordArgs.identity; + var self = this; + var item = null; + var scope = null; + + if(!this._rootNode){ + if(!this.url){ + this._rootNode = dojo.byId(this.dataId); + this._indexItems(); + if(self._rootNode.rows){ //Table + item = this._rootNode.rows[identity + 1]; + }else{ //Lists + for(var i = 0; i < self._rootNode.childNodes.length; i++){ + if(self._rootNode.childNodes[i].nodeType === 1 && identity === dojox.data.dom.textContent(self._rootNode.childNodes[i])) { + item = self._rootNode.childNodes[i]; + } + } + } + if(keywordArgs.onItem){ + scope = keywordArgs.scope?keywordArgs.scope:dojo.global; + keywordArgs.onItem.call(scope, item); + } + + }else{ + var getArgs = { + url: this.url, + handleAs: "text" + }; + var getHandler = dojo.xhrGet(getArgs); + getHandler.addCallback(function(data){ + var findNode = function(node, id){ + if(node.id == id){ + return node; //object + } + if(node.childNodes){ + for(var i=0; i + // + // + // Attribute1 + // Attribute2 + // + // + // + // + // Value1.1 + // Value1.2 + // + // + // Value2.1 + // Value2.2 + // + // + // + // + // args: + // An anonymous object to initialize properties. It expects the following values: + // tableId: The id of the HTML table to use. + // OR + // url: The url of the remote page to load + // tableId: The id of the table element in the remote page + + if(args.url){ + if(!args.tableId) + throw new Error("dojo.data.HtmlTableStore: Cannot instantiate using url without an id!"); + this.url = args.url; + this.tableId = args.tableId; + }else{ + if(args.tableId){ + this._rootNode = dojo.byId(args.tableId); + this.tableId = this._rootNode.id; + }else{ + this._rootNode = dojo.byId(this.tableId); + } + this._getHeadings(); + for(var i=0; i 0)?values[0]:defaultValue; //Object || int || Boolean + }, + + getValues: function(/* item */ item, + /* attribute-name-string */ attribute){ + // summary: + // See dojo.data.api.Read.getValues() + + this._assertIsItem(item); + var index = this._assertIsAttribute(attribute); + + if(index>-1){ + return [dojox.data.dom.textContent(item.cells[index])] ; + } + return []; //Array + }, + + getAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getAttributes() + this._assertIsItem(item); + var attributes = []; + for(var i=0; i 0; + }, + + containsValue: function(/* item */ item, + /* attribute-name-string */ attribute, + /* anything */ value){ + // summary: + // See dojo.data.api.Read.containsValue() + var regexp = undefined; + if(typeof value === "string"){ + regexp = dojo.data.util.filter.patternToRegExp(value, false); + } + return this._containsValue(item, attribute, value, regexp); //boolean. + }, + + _containsValue: function( /* item */ item, + /* attribute-name-string */ attribute, + /* anything */ value, + /* RegExp?*/ regexp){ + // summary: + // Internal function for looking at the values contained by the item. + // description: + // Internal function for looking at the values contained by the item. This + // function allows for denoting if the comparison should be case sensitive for + // strings or not (for handling filtering cases where string case should not matter) + // + // item: + // The data item to examine for attribute values. + // attribute: + // The attribute to inspect. + // value: + // The value to match. + // regexp: + // Optional regular expression generated off value if value was of string type to handle wildcarding. + // If present and attribute values are string, then it can be used for comparison instead of 'value' + var values = this.getValues(item, attribute); + for(var i = 0; i < values.length; ++i){ + var possibleValue = values[i]; + if(typeof possibleValue === "string" && regexp){ + return (possibleValue.match(regexp) !== null); + }else{ + //Non-string matching. + if(value === possibleValue){ + return true; // Boolean + } + } + } + return false; // Boolean + }, + + isItem: function(/* anything */ something){ + // summary: + // See dojo.data.api.Read.isItem() + if(something && something.store && something.store === this){ + return true; //boolean + } + return false; //boolean + }, + + isItemLoaded: function(/* anything */ something){ + // summary: + // See dojo.data.api.Read.isItemLoaded() + return this.isItem(something); + }, + + loadItem: function(/* Object */ keywordArgs){ + // summary: + // See dojo.data.api.Read.loadItem() + this._assertIsItem(keywordArgs.item); + }, + + _fetchItems: function(request, fetchHandler, errorHandler) { + // summary: + // Fetch items (XML elements) that match to a query + // description: + // If '_fetchUrl' is specified, it is used to load an XML document + // with a query string. + // Otherwise and if 'url' is specified, the XML document is + // loaded and list XML elements that match to a query (set of element + // names and their text attribute values that the items to contain). + // A wildcard, "*" can be used to query values to match all + // occurrences. + // If '_rootItem' is specified, it is used to fetch items. + // request: + // A request object + // fetchHandler: + // A function to call for fetched items + // errorHandler: + // A function to call on error + + if(this._rootNode){ + this._finishFetchItems(request, fetchHandler, errorHandler); + }else{ + if(!this.url){ + this._rootNode = dojo.byId(this.tableId); + this._getHeadings(); + for(var i=0; i 0){ + items = arrayOfAllItems.slice(0,arrayOfAllItems.length); + } + fetchHandler(items, request); + } + }, + + getFeatures: function(){ + // summary: + // See dojo.data.api.Read.getFeatures() + return { + 'dojo.data.api.Read': true, + 'dojo.data.api.Identity': true + }; + }, + + close: function(/*dojo.data.api.Request || keywordArgs || null */ request){ + // summary: + // See dojo.data.api.Read.close() + // nothing to do here! + }, + + getLabel: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabel() + if(this.isItem(item)) + return "Table Row #" + this.getIdentity(item); + return undefined; + }, + + getLabelAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabelAttributes() + return null; + }, + +/*************************************** + dojo.data.api.Identity API +***************************************/ + + getIdentity: function(/* item */ item){ + // summary: + // See dojo.data.api.Identity.getIdentity() + this._assertIsItem(item); + //Opera doesn't support the sectionRowIndex, + //So, have to call the indexOf to locate it. + //Blah. + if(!dojo.isOpera){ + return item.sectionRowIndex; // int + }else{ + return (dojo.indexOf(this._rootNode.rows, item) - 1) // int + } + }, + + getIdentityAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Identity.getIdentityAttributes() + //Identity isn't taken from a public attribute. + return null; + }, + + fetchItemByIdentity: function(keywordArgs){ + // summary: + // See dojo.data.api.Identity.fetchItemByIdentity() + var identity = keywordArgs.identity; + var self = this; + var item = null; + var scope = null; + + if(!this._rootNode){ + if(!this.url){ + this._rootNode = dojo.byId(this.tableId); + this._getHeadings(); + for(var i=0; i 0){ + items = arrayOfAllItems.slice(0,arrayOfAllItems.length); + } + } + findCallback(items, requestArgs); + }; + + if(this._loadFinished){ + filter(keywordArgs, this._arrayOfAllItems); + }else{ + if(this.url !== ""){ + //If fetches come in before the loading has finished, but while + //a load is in progress, we have to defer the fetching to be + //invoked in the callback. + if(this._loadInProgress){ + this._queuedFetches.push({args: keywordArgs, filter: filter}); + }else{ + this._loadInProgress = true; + var getArgs = { + url: self.url, + handleAs: "json-comment-filtered" + }; + var getHandler = dojo.xhrGet(getArgs); + getHandler.addCallback(function(data){ + self._processData(data); + filter(keywordArgs, self._arrayOfAllItems); + self._handleQueuedFetches(); + }); + getHandler.addErrback(function(error){ + self._loadInProgress = false; + throw error; + }); + } + }else if(this._keyValueString){ + this._processData(eval(this._keyValueString)); + this._keyValueString = null; + filter(keywordArgs, this._arrayOfAllItems); + }else if(this._keyValueVar){ + this._processData(this._keyValueVar); + this._keyValueVar = null; + filter(keywordArgs, this._arrayOfAllItems); + }else{ + throw new Error("dojox.data.KeyValueStore: No source data was provided as either URL, String, or Javascript variable data input."); + } + } + + }, + + _handleQueuedFetches: function(){ + // summary: + // Internal function to execute delayed request in the store. + //Execute any deferred fetches now. + if(this._queuedFetches.length > 0){ + for(var i = 0; i < this._queuedFetches.length; i++){ + var fData = this._queuedFetches[i]; + var delayedFilter = fData.filter; + var delayedQuery = fData.args; + if(delayedFilter){ + delayedFilter(delayedQuery, this._arrayOfAllItems); + }else{ + this.fetchItemByIdentity(fData.args); + } + } + this._queuedFetches = []; + } + }, + + _processData: function(/* Array */ data){ + this._arrayOfAllItems = []; + for(var i=0; i 0){ + attributes.push('children'); + } + return attributes; //Array + }, + + hasAttribute: function( /* item */ item, + /* attribute || attribute-name-string */ attribute){ + // summary: + // See dojo.data.api.Read.hasAttribute() + return (this.getValues(item, attribute).length > 0); //Boolean + }, + + containsValue: function(/* item */ item, + /* attribute || attribute-name-string */ attribute, + /* anything */ value){ + // summary: + // See dojo.data.api.Read.containsValue() + var regexp = undefined; + if(typeof value === "string"){ + regexp = dojo.data.util.filter.patternToRegExp(value, false); + } + return this._containsValue(item, attribute, value, regexp); //boolean. + }, + + _containsValue: function( /* item */ item, + /* attribute || attribute-name-string */ attribute, + /* anything */ value, + /* RegExp?*/ regexp){ + // summary: + // Internal function for looking at the values contained by the item. + // description: + // Internal function for looking at the values contained by the item. This + // function allows for denoting if the comparison should be case sensitive for + // strings or not (for handling filtering cases where string case should not matter) + // + // item: + // The data item to examine for attribute values. + // attribute: + // The attribute to inspect. + // value: + // The value to match. + // regexp: + // Optional regular expression generated off value if value was of string type to handle wildcarding. + // If present and attribute values are string, then it can be used for comparison instead of 'value' + var values = this.getValues(item, attribute); + for(var i = 0; i < values.length; ++i){ + var possibleValue = values[i]; + if(typeof possibleValue === "string" && regexp){ + return (possibleValue.match(regexp) !== null); + }else{ + //Non-string matching. + if(value === possibleValue){ + return true; // Boolean + } + } + } + return false; // Boolean + }, + + isItem: function(/* anything */ something){ + // summary: + // See dojo.data.api.Read.isItem() + // description: + // Four things are verified to ensure that "something" is an item: + // something can not be null, the nodeType must be an XML Element, + // the tagName must be "outline", and the node must be a member of + // XML document for this datastore. + return (something && + something.nodeType == 1 && + something.tagName == 'outline' && + something.ownerDocument === this._xmlData); //Boolean + }, + + isItemLoaded: function(/* anything */ something){ + // summary: + // See dojo.data.api.Read.isItemLoaded() + // OpmlStore loads every item, so if it's an item, then it's loaded. + return this.isItem(something); //Boolean + }, + + loadItem: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.loadItem() + // description: + // The OpmlStore always loads all items, so if it's an item, then it's loaded. + // From the dojo.data.api.Read.loadItem docs: + // If a call to isItemLoaded() returns true before loadItem() is even called, + // then loadItem() need not do any work at all and will not even invoke the callback handlers. + }, + + getLabel: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabel() + if(this.isItem(item)){ + return this.getValue(item,this.label); //String + } + return undefined; //undefined + }, + + getLabelAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabelAttributes() + return [this.label]; //array + }, + + // The dojo.data.api.Read.fetch() function is implemented as + // a mixin from dojo.data.util.simpleFetch. + // That mixin requires us to define _fetchItems(). + _fetchItems: function( /* Object */ keywordArgs, + /* Function */ findCallback, + /* Function */ errorCallback){ + // summary: + // See dojo.data.util.simpleFetch.fetch() + + var self = this; + var filter = function(requestArgs, arrayOfItems){ + var items = null; + if(requestArgs.query){ + items = []; + var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false; + + //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the + //same value for each item examined. Much more efficient. + var regexpList = {}; + for(var key in requestArgs.query){ + var value = requestArgs.query[key]; + if(typeof value === "string"){ + regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase); + } + } + + for(var i = 0; i < arrayOfItems.length; ++i){ + var match = true; + var candidateItem = arrayOfItems[i]; + for(var key in requestArgs.query){ + var value = requestArgs.query[key]; + if(!self._containsValue(candidateItem, key, value, regexpList[key])){ + match = false; + } + } + if(match){ + items.push(candidateItem); + } + } + }else{ + // We want a copy to pass back in case the parent wishes to sort the array. We shouldn't allow resort + // of the internal list so that multiple callers can get lists and sort without affecting each other. + if(arrayOfItems.length> 0){ + items = arrayOfItems.slice(0,arrayOfItems.length); + } + } + findCallback(items, requestArgs); + }; + + if(this._loadFinished){ + filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions)); + }else{ + + //If fetches come in before the loading has finished, but while + //a load is in progress, we have to defer the fetching to be + //invoked in the callback. + if(this._loadInProgress){ + this._queuedFetches.push({args: keywordArgs, filter: filter}); + }else{ + if(this.url !== ""){ + this._loadInProgress = true; + var getArgs = { + url: self.url, + handleAs: "xml" + }; + var getHandler = dojo.xhrGet(getArgs); + getHandler.addCallback(function(data){ + self._processRawXmlTree(data); + filter(keywordArgs, self._getItemsArray(keywordArgs.queryOptions)); + self._handleQueuedFetches(); + }); + getHandler.addErrback(function(error){ + throw error; + }); + }else if(this._opmlData){ + this._processRawXmlTree(this._opmlData); + this._opmlData = null; + filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions)); + }else{ + throw new Error("dojox.data.OpmlStore: No OPML source data was provided as either URL or XML data input."); + } + } + } + }, + + getFeatures: function(){ + // summary: See dojo.data.api.Read.getFeatures() + var features = { + 'dojo.data.api.Read': true, + 'dojo.data.api.Identity': true + }; + return features; //Object + }, + +/*************************************** + dojo.data.api.Identity API +***************************************/ + getIdentity: function(/* item */ item){ + // summary: + // See dojo.data.api.Identity.getIdentity() + if(this.isItem(item)){ + //No ther way to do this other than O(n) without + //complete rework of how the tree stores nodes. + for(var i in this._identityMap){ + if(this._identityMap[i] === item){ + return i; + } + } + } + return null; //null + }, + + fetchItemByIdentity: function(/* Object */ keywordArgs){ + // summary: + // See dojo.data.api.Identity.fetchItemByIdentity() + + //Hasn't loaded yet, we have to trigger the load. + if(!this._loadFinished){ + var self = this; + if(this.url !== ""){ + //If fetches come in before the loading has finished, but while + //a load is in progress, we have to defer the fetching to be + //invoked in the callback. + if(this._loadInProgress){ + this._queuedFetches.push({args: keywordArgs}); + }else{ + this._loadInProgress = true; + var getArgs = { + url: self.url, + handleAs: "xml" + }; + var getHandler = dojo.xhrGet(getArgs); + getHandler.addCallback(function(data){ + var scope = keywordArgs.scope?keywordArgs.scope:dojo.global; + try{ + self._processRawXmlTree(data); + var item = self._identityMap[keywordArgs.identity]; + if(!self.isItem(item)){ + item = null; + } + if(keywordArgs.onItem){ + keywordArgs.onItem.call(scope, item); + } + self._handleQueuedFetches(); + }catch(error){ + if(keywordArgs.onError){ + keywordArgs.onError.call(scope, error); + } + } + }); + getHandler.addErrback(function(error){ + this._loadInProgress = false; + if(keywordArgs.onError){ + var scope = keywordArgs.scope?keywordArgs.scope:dojo.global; + keywordArgs.onError.call(scope, error); + } + }); + } + }else if(this._opmlData){ + this._processRawXmlTree(this._opmlData); + this._opmlData = null; + var item = this._identityMap[keywordArgs.identity]; + if(!self.isItem(item)){ + item = null; + } + if(keywordArgs.onItem){ + var scope = keywordArgs.scope?keywordArgs.scope:dojo.global; + keywordArgs.onItem.call(scope, item); + } + } + }else{ + //Already loaded. We can just look it up and call back. + var item = this._identityMap[keywordArgs.identity]; + if(!this.isItem(item)){ + item = null; + } + if(keywordArgs.onItem){ + var scope = keywordArgs.scope?keywordArgs.scope:dojo.global; + keywordArgs.onItem.call(scope, item); + } + } + }, + + getIdentityAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Identity.getIdentifierAttributes() + + //Identity isn't a public attribute in the item, it's the node count. + //So, return null. + return null; + }, + + _handleQueuedFetches: function(){ + // summary: + // Internal function to execute delayed request in the store. + //Execute any deferred fetches now. + if (this._queuedFetches.length > 0) { + for(var i = 0; i < this._queuedFetches.length; i++){ + var fData = this._queuedFetches[i]; + var delayedQuery = fData.args; + var delayedFilter = fData.filter; + if(delayedFilter){ + delayedFilter(delayedQuery, this._getItemsArray(delayedQuery.queryOptions)); + }else{ + this.fetchItemByIdentity(delayedQuery); + } + } + this._queuedFetches = []; + } + }, + + close: function(/*dojo.data.api.Request || keywordArgs || null */ request){ + // summary: + // See dojo.data.api.Read.close() + } +}); +//Mix in the simple fetch implementation to this class. +dojo.extend(dojox.data.OpmlStore,dojo.data.util.simpleFetch); + + +} diff --git a/includes/js/dojox/data/PicasaStore.js b/includes/js/dojox/data/PicasaStore.js new file mode 100644 index 0000000..e1b96b0 --- /dev/null +++ b/includes/js/dojox/data/PicasaStore.js @@ -0,0 +1,254 @@ +if(!dojo._hasResource["dojox.data.PicasaStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.PicasaStore"] = true; +dojo.provide("dojox.data.PicasaStore"); + +dojo.require("dojo.data.util.simpleFetch"); +dojo.require("dojo.io.script"); +dojo.require("dojo.date.stamp"); + +dojo.declare("dojox.data.PicasaStore", null, { + constructor: function(/*Object*/args){ + // summary: + // Initializer for the PicasaStore store. + // description: + // The PicasaStore is a Datastore interface to one of the basic services + // of the Picasa service, the public photo feed. This does not provide + // access to all the services of Picasa. + // This store cannot do * and ? filtering as the picasa service + // provides no interface for wildcards. + if(args && args.label){ + this.label = args.label; + } + }, + + _picasaUrl: "http://picasaweb.google.com/data/feed/api/all", + + _storeRef: "_S", + + label: "title", + + _assertIsItem: function(/* item */ item){ + // summary: + // This function tests whether the item passed in is indeed an item in the store. + // item: + // The item to test for being contained by the store. + if(!this.isItem(item)){ + throw new Error("dojox.data.PicasaStore: a function was passed an item argument that was not an item"); + } + }, + + _assertIsAttribute: function(/* attribute-name-string */ attribute){ + // summary: + // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store. + // attribute: + // The attribute to test for being contained by the store. + if(typeof attribute !== "string"){ + throw new Error("dojox.data.PicasaStore: a function was passed an attribute argument that was not an attribute name string"); + } + }, + + getFeatures: function(){ + // summary: + // See dojo.data.api.Read.getFeatures() + return { + 'dojo.data.api.Read': true + }; + }, + + getValue: function(item, attribute){ + // summary: + // See dojo.data.api.Read.getValue() + var values = this.getValues(item, attribute); + if(values){ + return values[0]; + } + return undefined; + }, + + getAttributes: function(item){ + // summary: + // See dojo.data.api.Read.getAttributes() + return ["id", "published", "updated", "category", "title$type", "title", "summary$type", "summary", "rights$type", "rights", "link", "author", "gphoto$id", "gphoto$name", "location"]; + }, + + hasAttribute: function(item, attribute){ + // summary: + // See dojo.data.api.Read.hasAttributes() + if(this.getValue(item,attribute)){ + return true; + } + return false; + }, + + isItemLoaded: function(item){ + // summary: + // See dojo.data.api.Read.isItemLoaded() + return this.isItem(item); + }, + + loadItem: function(keywordArgs){ + // summary: + // See dojo.data.api.Read.loadItem() + }, + + getLabel: function(item){ + // summary: + // See dojo.data.api.Read.getLabel() + return this.getValue(item,this.label); + }, + + getLabelAttributes: function(item){ + // summary: + // See dojo.data.api.Read.getLabelAttributes() + return [this.label]; + }, + + containsValue: function(item, attribute, value){ + // summary: + // See dojo.data.api.Read.containsValue() + var values = this.getValues(item,attribute); + for(var i = 0; i < values.length; i++){ + if(values[i] === value){ + return true; + } + } + return false; + }, + + getValues: function(item, attribute){ + // summary: + // See dojo.data.api.Read.getValue() + + this._assertIsItem(item); + this._assertIsAttribute(attribute); + if(attribute === "title"){ + return [this._unescapeHtml(item.title)]; + }else if(attribute === "author"){ + return [this._unescapeHtml(item.author[0].name)]; + }else if(attribute === "datePublished"){ + return [dojo.date.stamp.fromISOString(item.published)]; + }else if(attribute === "dateTaken"){ + return [dojo.date.stamp.fromISOString(item.date_taken)]; + }else if(attribute === "imageUrlSmall"){ + return [item.media.thumbnail[1].url]; + }else if(attribute === "imageUrl"){ + return [item.content$src]; + }else if(attribute === "imageUrlMedium"){ + return [item.media.thumbnail[2].url]; + }else if(attribute === "link"){ + return [item.link[1]]; + }else if(attribute === "tags"){ + return item.tags.split(" "); + }else if(attribute === "description"){ + return [this._unescapeHtml(item.summary)]; + } + return undefined; + }, + + isItem: function(item){ + // summary: + // See dojo.data.api.Read.isItem() + if(item && item[this._storeRef] === this){ + return true; + } + return false; + }, + + close: function(request){ + // summary: + // See dojo.data.api.Read.close() + }, + + _fetchItems: function(request, fetchHandler, errorHandler){ + // summary: + // Fetch picasa items that match to a query + // request: + // A request object + // fetchHandler: + // A function to call for fetched items + // errorHandler: + // A function to call on error + + if(!request.query){ + request.query={}; + } + + //Build up the content to send the request for. + var content = {alt: "jsonm", pp: "1", psc: "G"}; + content['start-index'] = "1"; + if(request.query.start){ + content['start-index'] = request.query.start; + } + if(request.query.tags){ + content.q = request.query.tags; + } + if(request.query.userid){ + content.uname = request.query.userid; + } + if(request.query.userids){ + content.ids = request.query.userids; + } + if(request.query.lang){ + content.hl = request.query.lang; + } + if(request.count){ + content['max-results'] = request.count; + }else{ + content['max-results'] = "20"; + } + + //Linking this up to Picasa is a JOY! + var self = this; + var handle = null; + var myHandler = function(data){ + if(handle !== null){ + dojo.disconnect(handle); + } + + //Process the items... + fetchHandler(self._processPicasaData(data), request); + }; + var getArgs = { + url: this._picasaUrl, + // preventCache: true, + content: content, + callbackParamName: 'callback', + handle: myHandler + }; + var deferred = dojo.io.script.get(getArgs); + + deferred.addErrback(function(error){ + dojo.disconnect(handle); + errorHandler(error, request); + }); + }, + + _processPicasaData: function(data){ + var items = []; + if(data.feed){ + items = data.feed.entry; + //Add on the store ref so that isItem can work. + for(var i = 0; i < items.length; i++){ + var item = items[i]; + item[this._storeRef] = this; + } + } + return items; + }, + + _unescapeHtml: function(str){ + // summary: Utility function to un-escape XML special characters in an HTML string. + // description: Utility function to un-escape XML special characters in an HTML string. + // str: String. + // The string to un-escape + // returns: HTML String converted back to the normal text (unescaped) characters (<,>,&, ", etc,). + // + //TODO: Check to see if theres already compatible escape() in dojo.string or dojo.html + str = str.replace(/&/gm, "&").replace(/</gm, "<").replace(/>/gm, ">").replace(/"/gm, "\""); + str = str.replace(/'/gm, "'"); + return str; + } +}); +dojo.extend(dojox.data.PicasaStore,dojo.data.util.simpleFetch); + +} diff --git a/includes/js/dojox/data/QueryReadStore.js b/includes/js/dojox/data/QueryReadStore.js new file mode 100644 index 0000000..95af166 --- /dev/null +++ b/includes/js/dojox/data/QueryReadStore.js @@ -0,0 +1,513 @@ +if(!dojo._hasResource["dojox.data.QueryReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.QueryReadStore"] = true; +dojo.provide("dojox.data.QueryReadStore"); + +dojo.require("dojo.string"); + +dojo.declare("dojox.data.QueryReadStore", + null, + { + // summary: + // This class provides a store that is mainly intended to be used + // for loading data dynamically from the server, used i.e. for + // retreiving chunks of data from huge data stores on the server (by server-side filtering!). + // Upon calling the fetch() method of this store the data are requested from + // the server if they are not yet loaded for paging (or cached). + // + // For example used for a combobox which works on lots of data. It + // can be used to retreive the data partially upon entering the + // letters "ac" it returns only items like "action", "acting", etc. + // + // note: + // The field name "id" in a query is reserved for looking up data + // by id. This is necessary as before the first fetch, the store + // has no way of knowing which field the server will declare as + // identifier. + // + // examples: + // | // The parameter "query" contains the data that are sent to the server. + // | var store = new dojox.data.QueryReadStore({url:'/search.php'}); + // | store.fetch({query:{name:'a'}, queryOptions:{ignoreCase:false}}); + // + // | // Since "serverQuery" is given, it overrules and those data are + // | // sent to the server. + // | var store = new dojox.data.QueryReadStore({url:'/search.php'}); + // | store.fetch({serverQuery:{name:'a'}, queryOptions:{ignoreCase:false}}); + // + // |
+ // |
+ // |
+ + // + // todo: + // - there is a bug in the paging, when i set start:2, count:5 after an initial fetch() and doClientPaging:true + // it returns 6 elemetns, though count=5, try it in QueryReadStore.html + // - add optional caching + // - when the first query searched for "a" and the next for a subset of + // the first, i.e. "ab" then we actually dont need a server request, if + // we have client paging, we just need to filter the items we already have + // that might also be tooo much logic + + url:"", + requestMethod:"get", + //useCache:false, + + // We use the name in the errors, once the name is fixed hardcode it, may be. + _className:"dojox.data.QueryReadStore", + + // This will contain the items we have loaded from the server. + // The contents of this array is optimized to satisfy all read-api requirements + // and for using lesser storage, so the keys and their content need some explaination: + // this._items[0].i - the item itself + // this._items[0].r - a reference to the store, so we can identify the item + // securly. We set this reference right after receiving the item from the + // server. + _items:[], + + // Store the last query that triggered xhr request to the server. + // So we can compare if the request changed and if we shall reload + // (this also depends on other factors, such as is caching used, etc). + _lastServerQuery:null, + + + // Store a hash of the last server request. Actually I introduced this + // for testing, so I can check if no unnecessary requests were issued for + // client-side-paging. + lastRequestHash:null, + + // summary: + // By default every request for paging is sent to the server. + doClientPaging:false, + + // summary: + // By default all the sorting is done serverside before the data is returned + // which is the proper place to be doing it for really large datasets. + doClientSorting:false, + + // Items by identify for Identify API + _itemsByIdentity:null, + + // Identifier used + _identifier:null, + + _features: {'dojo.data.api.Read':true, 'dojo.data.api.Identity':true}, + + _labelAttr: "label", + + constructor: function(/* Object */ params){ + dojo.mixin(this,params); + }, + + getValue: function(/* item */ item, /* attribute-name-string */ attribute, /* value? */ defaultValue){ + // According to the Read API comments in getValue() and exception is + // thrown when an item is not an item or the attribute not a string! + this._assertIsItem(item); + if (!dojo.isString(attribute)) { + throw new Error(this._className+".getValue(): Invalid attribute, string expected!"); + } + if(!this.hasAttribute(item, attribute)){ + // read api says: return defaultValue "only if *item* does not have a value for *attribute*." + // Is this the case here? The attribute doesn't exist, but a defaultValue, sounds reasonable. + if(defaultValue){ + return defaultValue; + } + console.log(this._className+".getValue(): Item does not have the attribute '"+attribute+"'."); + } + return item.i[attribute]; + }, + + getValues: function(/* item */ item, /* attribute-name-string */ attribute){ + this._assertIsItem(item); + var ret = []; + if(this.hasAttribute(item, attribute)){ + ret.push(item.i[attribute]); + } + return ret; + }, + + getAttributes: function(/* item */ item){ + this._assertIsItem(item); + var ret = []; + for(var i in item.i){ + ret.push(i); + } + return ret; + }, + + hasAttribute: function(/* item */ item, /* attribute-name-string */ attribute) { + // summary: + // See dojo.data.api.Read.hasAttribute() + return this.isItem(item) && typeof item.i[attribute]!="undefined"; + }, + + containsValue: function(/* item */ item, /* attribute-name-string */ attribute, /* anything */ value){ + var values = this.getValues(item, attribute); + var len = values.length; + for(var i=0; i>> var store = new dojox.data.QueryReadStore({}); + // >>> store.isItem(""); + // false + // + // >>> var store = new dojox.data.QueryReadStore({}); + // >>> store.isItem({}); + // false + // + // >>> var store = new dojox.data.QueryReadStore({}); + // >>> store.isItem(0); + // false + // + // >>> var store = new dojox.data.QueryReadStore({}); + // >>> store.isItem({name:"me", label:"me too"}); + // false + // + if(something){ + return typeof something.r!="undefined" && something.r==this; + } + return false; + }, + + isItemLoaded: function(/* anything */ something) { + // Currently we dont have any state that tells if an item is loaded or not + // if the item exists its also loaded. + // This might change when we start working with refs inside items ... + return this.isItem(something); + }, + + loadItem: function(/* object */ args){ + if(this.isItemLoaded(args.item)){ + return; + } + // Actually we have nothing to do here, or at least I dont know what to do here ... + }, + + fetch:function(/* Object? */ request){ + // summary: + // See dojo.data.util.simpleFetch.fetch() this is just a copy and I adjusted + // only the paging, since it happens on the server if doClientPaging is + // false, thx to http://trac.dojotoolkit.org/ticket/4761 reporting this. + // Would be nice to be able to use simpleFetch() to reduce copied code, + // but i dont know how yet. Ideas please! + request = request || {}; + if(!request.store){ + request.store = this; + } + var self = this; + + var _errorHandler = function(errorData, requestObject){ + if(requestObject.onError){ + var scope = requestObject.scope || dojo.global; + requestObject.onError.call(scope, errorData, requestObject); + } + }; + + var _fetchHandler = function(items, requestObject, numRows){ + var oldAbortFunction = requestObject.abort || null; + var aborted = false; + + var startIndex = requestObject.start?requestObject.start:0; + if (self.doClientPaging==false) { + // For client paging we dont need no slicing of the result. + startIndex = 0; + } + var endIndex = requestObject.count?(startIndex + requestObject.count):items.length; + + requestObject.abort = function(){ + aborted = true; + if(oldAbortFunction){ + oldAbortFunction.call(requestObject); + } + }; + + var scope = requestObject.scope || dojo.global; + if(!requestObject.store){ + requestObject.store = self; + } + if(requestObject.onBegin){ + requestObject.onBegin.call(scope, numRows, requestObject); + } + if(requestObject.sort && this.doClientSorting){ + items.sort(dojo.data.util.sorter.createSortFunction(requestObject.sort, self)); + } + if(requestObject.onItem){ + for(var i = startIndex; (i < items.length) && (i < endIndex); ++i){ + var item = items[i]; + if(!aborted){ + requestObject.onItem.call(scope, item, requestObject); + } + } + } + if(requestObject.onComplete && !aborted){ + var subset = null; + if (!requestObject.onItem) { + subset = items.slice(startIndex, endIndex); + } + requestObject.onComplete.call(scope, subset, requestObject); + } + }; + this._fetchItems(request, _fetchHandler, _errorHandler); + return request; // Object + }, + + getFeatures: function(){ + return this._features; + }, + + close: function(/*dojo.data.api.Request || keywordArgs || null */ request){ + // I have no idea if this is really needed ... + }, + + getLabel: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabel() + if(this._labelAttr && this.isItem(item)){ + return this.getValue(item, this._labelAttr); //String + } + return undefined; //undefined + }, + + getLabelAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabelAttributes() + if(this._labelAttr){ + return [this._labelAttr]; //array + } + return null; //null + }, + + _fetchItems: function(request, fetchHandler, errorHandler){ + // summary: + // The request contains the data as defined in the Read-API. + // Additionally there is following keyword "serverQuery". + // + // The *serverQuery* parameter, optional. + // This parameter contains the data that will be sent to the server. + // If this parameter is not given the parameter "query"'s + // data are sent to the server. This is done for some reasons: + // - to specify explicitly which data are sent to the server, they + // might also be a mix of what is contained in "query", "queryOptions" + // and the paging parameters "start" and "count" or may be even + // completely different things. + // - don't modify the request.query data, so the interface using this + // store can rely on unmodified data, as the combobox dijit currently + // does it, it compares if the query has changed + // - request.query is required by the Read-API + // + // I.e. the following examples might be sent via GET: + // fetch({query:{name:"abc"}, queryOptions:{ignoreCase:true}}) + // the URL will become: /url.php?name=abc + // + // fetch({serverQuery:{q:"abc", c:true}, query:{name:"abc"}, queryOptions:{ignoreCase:true}}) + // the URL will become: /url.php?q=abc&c=true + // // The serverQuery-parameter has overruled the query-parameter + // // but the query parameter stays untouched, but is not sent to the server! + // // The serverQuery contains more data than the query, so they might differ! + // + + var serverQuery = request.serverQuery || request.query || {}; + //Need to add start and count + if(!this.doClientPaging){ + serverQuery.start = request.start || 0; + // Count might not be sent if not given. + if (request.count) { + serverQuery.count = request.count; + } + } + if(!this.doClientSorting){ + if(request.sort){ + var sort = request.sort[0]; + if(sort && sort.attribute){ + var sortStr = sort.attribute; + if(sort.descending){ + sortStr = "-" + sortStr; + } + serverQuery.sort = sortStr; + } + } + } + // Compare the last query and the current query by simply json-encoding them, + // so we dont have to do any deep object compare ... is there some dojo.areObjectsEqual()??? + if(this.doClientPaging && this._lastServerQuery!==null && + dojo.toJson(serverQuery)==dojo.toJson(this._lastServerQuery) + ){ + fetchHandler(this._items, request); + }else{ + var xhrFunc = this.requestMethod.toLowerCase()=="post" ? dojo.xhrPost : dojo.xhrGet; + var xhrHandler = xhrFunc({url:this.url, handleAs:"json-comment-optional", content:serverQuery}); + xhrHandler.addCallback(dojo.hitch(this, function(data){ + data = this._filterResponse(data); + if (data.label){ + this._labelAttr = data.label; + } + var numRows = data.numRows || -1; + + this._items = []; + // Store a ref to "this" in each item, so we can simply check if an item + // really origins form here (idea is from ItemFileReadStore, I just don't know + // how efficient the real storage use, garbage collection effort, etc. is). + dojo.forEach(data.items,function(e){ + this._items.push({i:e, r:this}); + },this); + + var identifier = data.identifier; + this._itemsByIdentity = {}; + if(identifier){ + this._identifier = identifier; + for(i = 0; i < this._items.length; ++i){ + var item = this._items[i].i; + var identity = item[identifier]; + if(!this._itemsByIdentity[identity]){ + this._itemsByIdentity[identity] = item; + }else{ + throw new Error(this._className+": The json data as specified by: [" + this.url + "] is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]"); + } + } + }else{ + this._identifier = Number; + for(i = 0; i < this._items.length; ++i){ + this._items[i].n = i; + } + } + + // TODO actually we should do the same as dojo.data.ItemFileReadStore._getItemsFromLoadedData() to sanitize + // (does it really sanititze them) and store the data optimal. should we? for security reasons??? + numRows = (numRows === -1) ? this._items.length : numRows; + fetchHandler(this._items, request, numRows); + })); + xhrHandler.addErrback(function(error){ + errorHandler(error, request); + }); + // Generate the hash using the time in milliseconds and a randon number. + // Since Math.randon() returns something like: 0.23453463, we just remove the "0." + // probably just for esthetic reasons :-). + this.lastRequestHash = new Date().getTime()+"-"+String(Math.random()).substring(2); + this._lastServerQuery = dojo.mixin({}, serverQuery); + } + }, + + _filterResponse: function(data){ + // summary: + // If the data from servers needs to be processed before it can be processed by this + // store, then this function should be re-implemented in subclass. This default + // implementation just return the data unchanged. + // data: + // The data received from server + return data; + }, + + _assertIsItem: function(/* item */ item){ + // summary: + // It throws an error if item is not valid, so you can call it in every method that needs to + // throw an error when item is invalid. + // item: + // The item to test for being contained by the store. + if(!this.isItem(item)){ + throw new Error(this._className+": Invalid item argument."); + } + }, + + _assertIsAttribute: function(/* attribute-name-string */ attribute){ + // summary: + // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store. + // attribute: + // The attribute to test for being contained by the store. + if(typeof attribute !== "string"){ + throw new Error(this._className+": Invalid attribute argument ('"+attribute+"')."); + } + }, + + fetchItemByIdentity: function(/* Object */ keywordArgs){ + // summary: + // See dojo.data.api.Identity.fetchItemByIdentity() + + // See if we have already loaded the item with that id + // In case there hasn't been a fetch yet, _itemsByIdentity is null + // and thus a fetch will be triggered below. + if(this._itemsByIdentity){ + var item = this._itemsByIdentity[keywordArgs.identity]; + if(!(item === undefined)){ + if(keywordArgs.onItem){ + var scope = keywordArgs.scope?keywordArgs.scope:dojo.global; + keywordArgs.onItem.call(scope, {i:item, r:this}); + } + return; + } + } + + // Otherwise we need to go remote + // Set up error handler + var _errorHandler = function(errorData, requestObject){ + var scope = keywordArgs.scope?keywordArgs.scope:dojo.global; + if(keywordArgs.onError){ + keywordArgs.onError.call(scope, error); + } + }; + + // Set up fetch handler + var _fetchHandler = function(items, requestObject){ + var scope = keywordArgs.scope?keywordArgs.scope:dojo.global; + try{ + // There is supposed to be only one result + var item = null; + if(items && items.length == 1){ + item = items[0]; + } + + // If no item was found, item is still null and we'll + // fire the onItem event with the null here + if(keywordArgs.onItem){ + keywordArgs.onItem.call(scope, item); + } + }catch(error){ + if(keywordArgs.onError){ + keywordArgs.onError.call(scope, error); + } + } + }; + + // Construct query + var request = {serverQuery:{id:keywordArgs.identity}}; + + // Dispatch query + this._fetchItems(request, _fetchHandler, _errorHandler); + }, + + getIdentity: function(/* item */ item){ + // summary: + // See dojo.data.api.Identity.getIdentity() + var identifier = null; + if(this._identifier === Number){ + identifier = item.n; // Number + }else{ + identifier = item.i[this._identifier]; + } + return identifier; + }, + + getIdentityAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Identity.getIdentityAttributes() + return [this._identifier]; + } + } +); + +} diff --git a/includes/js/dojox/data/README b/includes/js/dojox/data/README new file mode 100644 index 0000000..94565f9 --- /dev/null +++ b/includes/js/dojox/data/README @@ -0,0 +1,89 @@ +------------------------------------------------------------------------------- +DojoX Data +------------------------------------------------------------------------------- +Version 1.1 +Release date: 03/18/2008 +------------------------------------------------------------------------------- +Project state: stable +------------------------------------------------------------------------------- +Project authors + Jared Jurkiewicz (jared.jurkiewicz@gmail.com) + Shane O'Sullivan (shaneosullivan1@gmail.com) (FlickrRestStore, AtomReadStore) + Wolfram Kriesing (wolfram@kriesing.de) (QueryReadStore) + Dustin Machi (dmachi@dojotolkit.org) (jsonPathStore); + Russell Jones (KeyValueStore) (CLA) + Benjamin Schell (KeyValueStore) (Corporate CLA) + Kurt Stutsman (kurt@snaplogic.org) (SnapLogicStore) + +------------------------------------------------------------------------------- +Project description + +The DojoX Data project is a container for extensions and extra example stores +that implement the dojo.data APIs. It may also contain utility functions for +working with specific types of data. + +------------------------------------------------------------------------------- +Dependencies: + +DojoX Data has dependencies on core dojo (dojo.data) and the D.O.H. unit test +framework. +------------------------------------------------------------------------------- +Documentation: + +See the Dojo API tool (http://dojotoolkit.org/api) +------------------------------------------------------------------------------- +Contributions: + +For contributions to be committed into the dojox repository, the datastore +should have basic unit tests that exercise the API's that the store declares it +implements. Documentation and demos are a plus, but unit tests are required +to be committed into this sub-package. This is necessary to help keep the +provided datastores as stable as possible. + +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/data/* + +Install into the following directory structure: +/dojox/data/ + +...which should be at the same level as your Dojo checkout. + +/dojox/data/* + +Require in the dojox.data stores you wish to use. +------------------------------------------------------------------------------- +Additional Notes: + dojox.data.AtomReadStore - Reads Atom XML documents. + + dojox.data.CvsStore - comma-separated (spreadsheet output) + datastore implementation + + dojox.data.FlickrRestStore - advanced version of: dojox.data.FlickrStore + (Caching + user key support) + + dojox.data.FlickrStore - data store driven by Flickr.com public API. + + dojox.data.HtmlTableStore - Implementation of an HTML Table reading + datastore + + dojox.data.HtmlStore - Implementation of an HTML reading datastore. Can + handle tables, ordered and un-ordered lists, and lists of divs. + + dojox.data.OpmlStore - Store for reading OMPL formatted data + + dojox.data.XmlStore - datastore for XML based services or + documents. + + dojox.data.QueryReadStore - datastore to provide serverside URL query + matching. Similar to the 0.4.X ComboBox dataUrl parameter. + + dojox.data.jsonPathStore - datastore that takes an arbitrary js object + and uses it as the store. Pre-Alpha at the moment. + + dojox.data.KeyValueStore - datastore that mimics a key/value property + file format. + + dojox.data.SnapLogicStore - Store to interface to SnapLogic data services. diff --git a/includes/js/dojox/data/SnapLogicStore.js b/includes/js/dojox/data/SnapLogicStore.js new file mode 100644 index 0000000..101ab91 --- /dev/null +++ b/includes/js/dojox/data/SnapLogicStore.js @@ -0,0 +1,332 @@ +if(!dojo._hasResource["dojox.data.SnapLogicStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.SnapLogicStore"] = true; +dojo.provide("dojox.data.SnapLogicStore"); + +dojo.require("dojo.io.script"); +dojo.require("dojo.data.util.sorter"); + +dojo.declare("dojox.data.SnapLogicStore", null, { + Parts: { + DATA: "data", + COUNT: "count" + }, + + url: "", + + constructor: function(/* Object */args){ + // summary: + // Initialize a SnapLogicStore object. + // args: + // An object that contains properties for initializing the new data store object. The + // following properties are understood: + // url: + // A URL to the SnapLogic pipeline's output routed through PipeToHttp. Typically, this + // will look like "http://:/pipe//". + // parameters: + // An object whose properties define parameters to the pipeline. The values of these + // properties will be sent to the pipeline as parameters when it run. + // + if(args.url){ + this.url = args.url; + } + this._parameters = args.parameters; + }, + + _assertIsItem: function(/* item */item){ + // summary: + // This function tests whether the item passed in is indeed an item in the store. + // item: + // The item to test for being contained by the store. + if(!this.isItem(item)){ + throw new Error("dojox.data.SnapLogicStore: a function was passed an item argument that was not an item"); + } + }, + + _assertIsAttribute: function(/* attribute-name-string */ attribute){ + // summary: + // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store. + // attribute: + // The attribute to test for being contained by the store. + if(typeof attribute !== "string"){ + throw new Error("dojox.data.SnapLogicStore: a function was passed an attribute argument that was not an attribute name string"); + } + }, + + getFeatures: function(){ + // summary: + // See dojo.data.api.Read.getFeatures() + return { + 'dojo.data.api.Read': true + }; + }, + + getValue: function(item, attribute){ + // summary: + // See dojo.data.api.Read.getValue() + this._assertIsItem(item); + this._assertIsAttribute(attribute); + i = dojo.indexOf(item.attributes, attribute); + if(i !== -1){ + return item.values[i]; + } + return undefined; + }, + + getAttributes: function(item){ + // summary: + // See dojo.data.api.Read.getAttributes() + this._assertIsItem(item); + return item.attributes; + }, + + hasAttribute: function(item, attribute){ + // summary: + // See dojo.data.api.Read.hasAttributes() + this._assertIsItem(item); + this._assertIsAttribute(attribute); + for(var i = 0; i < item.attributes.length; ++i){ + if(attribute == item.attributes[i]){ + return true; + } + } + return false; + }, + + isItemLoaded: function(item){ + // summary: + // See dojo.data.api.Read.isItemLoaded() + return this.isItem(item); // Boolean + }, + + loadItem: function(keywordArgs){ + // summary: + // See dojo.data.api.Read.loadItem() + }, + + getLabel: function(item){ + // summary: + // See dojo.data.api.Read.getLabel() + return undefined; + }, + + getLabelAttributes: function(item){ + // summary: + // See dojo.data.api.Read.getLabelAttributes() + return null; + }, + + containsValue: function(item, attribute, value){ + // summary: + // See dojo.data.api.Read.containsValue() + return this.getValue(item, attribute) === value; // Boolean + }, + + getValues: function(item, attribute){ + // summary: + // See dojo.data.api.Read.getValue() + this._assertIsItem(item); + this._assertIsAttribute(attribute); + i = dojo.indexOf(item.attributes, attribute); + if(i !== -1){ + return [item.values[i]]; // Array + } + return undefined; + }, + + isItem: function(item){ + // summary: + // See dojo.data.api.Read.isItem() + if(item && item._store === this){ + return true; + } + return false; + }, + + close: function(request){ + // summary: + // See dojo.data.api.Read.close() + }, + + _fetchHandler: function(/* Object */request){ + // summary: + // Process data retrieved via fetch and send it back to requester. + // response: + // The data returend from the I/O transport. In the normal case, it will be an array of result rows + // from the pipeline. In the special case for record count optimization, response will be an array + // with a single element containing the total pipeline result row count. See fetch() for details + // on this optimization. + + var scope = request.scope || dojo.global; + + if(request.onBegin){ + // Check for the record count optimization + request.onBegin.call(scope, request._countResponse[0], request); + } + + if(request.onItem || request.onComplete){ + response = request._dataResponse; + + if (!response.length){ + request.onError.call(scope, + new Error("dojox.data.SnapLogicStore: invalid response of length 0"), + request); + return; + }else if(request.query != 'record count'){ + //If this was not a record count request, the first element returned will contain + //the field names. + field_names = response.shift(); + + var items = []; + for(var i = 0; i < response.length; ++i){ + if(request._aborted){ + break; + } + + items.push({attributes: field_names, values: response[i], _store: this}); + } + + if(request.sort && !request._aborted){ + items.sort(dojo.data.util.sorter.createSortFunction(request.sort, self)); + } + }else{ + //This is a record count request, so manually set the field names. + items = [({attributes: ['count'], values: response, _store: this})]; + } + + if(request.onItem){ + for(var i = 0; i < items.length; ++i){ + if (request._aborted) { + break; + } + request.onItem.call(scope, items[i], request); + } + items = null; + } + + if(request.onComplete && !request._aborted){ + request.onComplete.call(scope, items, request); + } + } + }, + + _partHandler: function(/* Object */request, /* String */part, /* Object */response){ + // summary: + // Handle the individual replies for both data and length requests. + // request: + // The request/handle object used with the original fetch() call. + // part: + // A value indicating which request this handler call is for (this.Parts). + // response: + // Response received from the underlying IO transport. + + if(response instanceof Error){ + if(part == this.Parts.DATA){ + request._dataHandle = null; + }else{ + request._countHandle = null; + } + request._aborted = true; + if(request.onError){ + request.onError.call(request.scope, response, request); + } + }else{ + if(request._aborted){ + return; + } + if(part == this.Parts.DATA){ + request._dataResponse = response; + }else{ + request._countResponse = response; + } + if((!request._dataHandle || request._dataResponse !== null) && + (!request._countHandle || request._countResponse !== null)){ + this._fetchHandler(request); + } + } + }, + + fetch: function(/* Object */request){ + // summary: + // See dojo.data.api.Read.close() + // request: + // See dojo.data.api.Read.close() for generic interface. + // + // In addition to the standard Read API fetch support, this store supports an optimization for + // for retrieving the total count of records in the Pipeline without retrieving the data. To + // use this optimization, simply provide an onBegin handler without an onItem or onComplete handler. + + request._countResponse = null; + request._dataResponse = null; + request._aborted = false; + request.abort = function(){ + if(!request._aborted){ + request._aborted = true; + if(request._dataHandle && request._dataHandle.cancel){ + request._dataHandle.cancel(); + } + if(request._countHandle && request._countHandle.cancel){ + request._countHandle.cancel(); + } + } + }; + + // Only make the call for data if onItem or onComplete is used. Otherwise, onBegin will only + // require the total row count. + if(request.onItem || request.onComplete){ + var content = this._parameters || {}; + if(request.start){ + if(request.start < 0){ + throw new Error("dojox.data.SnapLogicStore: request start value must be 0 or greater"); + } + content['sn.start'] = request.start + 1; + } + if(request.count){ + if(request.count < 0){ + throw new Error("dojox.data.SnapLogicStore: request count value 0 or greater"); + } + content['sn.limit'] = request.count; + } + + content['sn.content_type'] = 'application/javascript'; + + var store = this; + var handler = function(response, ioArgs){ + if(response instanceof Error){ + store._fetchHandler(response, request); + } + }; + + var getArgs = { + url: this.url, + content: content, + // preventCache: true, + timeout: 60000, //Starting a pipeline can take a long time. + callbackParamName: "sn.stream_header", + handle: dojo.hitch(this, "_partHandler", request, this.Parts.DATA) + }; + + request._dataHandle = dojo.io.script.get(getArgs); + } + + if(request.onBegin){ + var content = {}; + content['sn.count'] = 'records'; + content['sn.content_type'] = 'application/javascript'; + + var getArgs = { + url: this.url, + content: content, + timeout: 60000, + callbackParamName: "sn.stream_header", + handle: dojo.hitch(this, "_partHandler", request, this.Parts.COUNT) + }; + + request._countHandle = dojo.io.script.get(getArgs); + } + + return request; // Object + } +}); + + +} diff --git a/includes/js/dojox/data/XmlStore.js b/includes/js/dojox/data/XmlStore.js new file mode 100644 index 0000000..90b26a9 --- /dev/null +++ b/includes/js/dojox/data/XmlStore.js @@ -0,0 +1,1141 @@ +if(!dojo._hasResource["dojox.data.XmlStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.XmlStore"] = true; +dojo.provide("dojox.data.XmlStore"); +dojo.provide("dojox.data.XmlItem"); + +dojo.require("dojo.data.util.simpleFetch"); +dojo.require("dojo.data.util.filter"); +dojo.require("dojox.data.dom"); + +dojo.declare("dojox.data.XmlStore", null, { + // summary: + // A data store for XML based services or documents + // description: + // A data store for XML based services or documents + + constructor: function(/* object */ args) { + // summary: + // Constructor for the XML store. + // args: + // An anonymous object to initialize properties. It expects the following values: + // url: The url to a service or an XML document that represents the store + // rootItem: A tag name for root items + // keyAttribute: An attribute name for a key or an indentify + // attributeMap: An anonymous object contains properties for attribute mapping, + // {"tag_name.item_attribute_name": "@xml_attribute_name", ...} + // sendQuery: A boolean indicate to add a query string to the service URL + console.log("XmlStore()"); + if(args){ + this.url = args.url; + this.rootItem = (args.rootItem || args.rootitem || this.rootItem); + this.keyAttribute = (args.keyAttribute || args.keyattribute || this.keyAttribute); + this._attributeMap = (args.attributeMap || args.attributemap); + this.label = args.label || this.label; + this.sendQuery = (args.sendQuery || args.sendquery || this.sendQuery); + } + this._newItems = []; + this._deletedItems = []; + this._modifiedItems = []; + }, + + //Values that may be set by the parser. + //Ergo, have to be instantiated to something + //So the parser knows how to set them. + url: "", + + rootItem: "", + + keyAttribute: "", + + label: "", + + sendQuery: false, + +/* dojo.data.api.Read */ + + getValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue){ + // summary: + // Return an attribute value + // description: + // 'item' must be an instance of a dojox.data.XmlItem from the store instance. + // If 'attribute' specifies "tagName", the tag name of the element is + // returned. + // If 'attribute' specifies "childNodes", the first element child is + // returned. + // If 'attribute' specifies "text()", the value of the first text + // child is returned. + // For generic attributes, if '_attributeMap' is specified, + // an actual attribute name is looked up with the tag name of + // the element and 'attribute' (concatenated with '.'). + // Then, if 'attribute' starts with "@", the value of the XML + // attribute is returned. + // Otherwise, the first child element of the tag name specified with + // 'attribute' is returned. + // item: + // An XML element that holds the attribute + // attribute: + // A tag name of a child element, An XML attribute name or one of + // special names + // defaultValue: + // A default value + // returns: + // An attribute value found, otherwise 'defaultValue' + var element = item.element; + if(attribute === "tagName"){ + return element.nodeName; + }else if (attribute === "childNodes"){ + for (var i = 0; i < element.childNodes.length; i++) { + var node = element.childNodes[i]; + if (node.nodeType === 1 /*ELEMENT_NODE*/) { + return this._getItem(node); //object + } + } + return defaultValue; + }else if(attribute === "text()"){ + for(var i = 0; i < element.childNodes.length; i++){ + var node = element.childNodes[i]; + if(node.nodeType === 3 /*TEXT_NODE*/ || + node.nodeType === 4 /*CDATA_SECTION_NODE*/){ + return node.nodeValue; //string + } + } + return defaultValue; + }else{ + attribute = this._getAttribute(element.nodeName, attribute); + if(attribute.charAt(0) === '@'){ + var name = attribute.substring(1); + var value = element.getAttribute(name); + return (value !== undefined) ? value : defaultValue; //object + }else{ + for(var i = 0; i < element.childNodes.length; i++){ + var node = element.childNodes[i]; + if( node.nodeType === 1 /*ELEMENT_NODE*/ && + node.nodeName === attribute){ + return this._getItem(node); //object + } + } + return defaultValue; //object + } + } + }, + + getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute){ + // summary: + // Return an array of attribute values + // description: + // 'item' must be an instance of a dojox.data.XmlItem from the store instance. + // If 'attribute' specifies "tagName", the tag name of the element is + // returned. + // If 'attribute' specifies "childNodes", child elements are returned. + // If 'attribute' specifies "text()", the values of child text nodes + // are returned. + // For generic attributes, if '_attributeMap' is specified, + // an actual attribute name is looked up with the tag name of + // the element and 'attribute' (concatenated with '.'). + // Then, if 'attribute' starts with "@", the value of the XML + // attribute is returned. + // Otherwise, child elements of the tag name specified with + // 'attribute' are returned. + // item: + // An XML element that holds the attribute + // attribute: + // A tag name of child elements, An XML attribute name or one of + // special names + // returns: + // An array of attribute values found, otherwise an empty array + var element = item.element; + if(attribute === "tagName"){ + return [element.nodeName]; + }else if(attribute === "childNodes"){ + var values = []; + for(var i = 0; i < element.childNodes.length; i++){ + var node = element.childNodes[i]; + if(node.nodeType === 1 /*ELEMENT_NODE*/){ + values.push(this._getItem(node)); + } + } + return values; //array + }else if(attribute === "text()"){ + var values = []; + for(var i = 0; i < element.childNodes.length; i++){ + var node = childNodes[i]; + if(node.nodeType === 3){ + values.push(node.nodeValue); + } + } + return values; //array + }else{ + attribute = this._getAttribute(element.nodeName, attribute); + if(attribute.charAt(0) === '@'){ + var name = attribute.substring(1); + var value = element.getAttribute(name); + return (value !== undefined) ? [value] : []; //array + }else{ + var values = []; + for(var i = 0; i < element.childNodes.length; i++){ + var node = element.childNodes[i]; + if( node.nodeType === 1 /*ELEMENT_NODE*/ && + node.nodeName === attribute){ + values.push(this._getItem(node)); + } + } + return values; //array + } + } + }, + + getAttributes: function(/* item */ item) { + // summary: + // Return an array of attribute names + // description: + // 'item' must be an instance of a dojox.data.XmlItem from the store instance. + // tag names of child elements and XML attribute names of attributes + // specified to the element are returned along with special attribute + // names applicable to the element including "tagName", "childNodes" + // if the element has child elements, "text()" if the element has + // child text nodes, and attribute names in '_attributeMap' that match + // the tag name of the element. + // item: + // An XML element + // returns: + // An array of attributes found + var element = item.element; + var attributes = []; + attributes.push("tagName"); + if(element.childNodes.length > 0){ + var names = {}; + var childNodes = true; + var text = false; + for(var i = 0; i < element.childNodes.length; i++){ + var node = element.childNodes[i]; + if (node.nodeType === 1 /*ELEMENT_NODE*/) { + var name = node.nodeName; + if(!names[name]){ + attributes.push(name); + names[name] = name; + } + childNodes = true; + }else if(node.nodeType === 3){ + text = true; + } + } + if(childNodes){ + attributes.push("childNodes"); + } + if(text){ + attributes.push("text()"); + } + } + for(var i = 0; i < element.attributes.length; i++){ + attributes.push("@" + element.attributes[i].nodeName); + } + if(this._attributeMap){ + for (var key in this._attributeMap){ + var i = key.indexOf('.'); + if(i > 0){ + var tagName = key.substring(0, i); + if (tagName === element.nodeName){ + attributes.push(key.substring(i + 1)); + } + }else{ // global attribute + attributes.push(key); + } + } + } + return attributes; //array + }, + + hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute){ + // summary: + // Check whether an element has the attribute + // item: + // 'item' must be an instance of a dojox.data.XmlItem from the store instance. + // attribute: + // A tag name of a child element, An XML attribute name or one of + // special names + // returns: + // True if the element has the attribute, otherwise false + return (this.getValue(item, attribute) !== undefined); //boolean + }, + + containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value){ + // summary: + // Check whether the attribute values contain the value + // item: + // 'item' must be an instance of a dojox.data.XmlItem from the store instance. + // attribute: + // A tag name of a child element, An XML attribute name or one of + // special names + // returns: + // True if the attribute values contain the value, otherwise false + var values = this.getValues(item, attribute); + for(var i = 0; i < values.length; i++){ + if((typeof value === "string")){ + if(values[i].toString && values[i].toString() === value){ + return true; + } + }else if (values[i] === value){ + return true; //boolean + } + } + return false;//boolean + }, + + isItem: function(/* anything */ something){ + // summary: + // Check whether the object is an item (XML element) + // item: + // An object to check + // returns: + // True if the object is an XML element, otherwise false + if(something && something.element && something.store && something.store === this){ + return true; //boolean + } + return false; //boolran + }, + + isItemLoaded: function(/* anything */ something){ + // summary: + // Check whether the object is an item (XML element) and loaded + // item: + // An object to check + // returns: + // True if the object is an XML element, otherwise false + return this.isItem(something); //boolean + }, + + loadItem: function(/* object */ keywordArgs){ + // summary: + // Load an item (XML element) + // keywordArgs: + // object containing the args for loadItem. See dojo.data.api.Read.loadItem() + }, + + getFeatures: function() { + // summary: + // Return supported data APIs + // returns: + // "dojo.data.api.Read" and "dojo.data.api.Write" + var features = { + "dojo.data.api.Read": true, + "dojo.data.api.Write": true + }; + return features; //array + }, + + getLabel: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabel() + if((this.label !== "") && this.isItem(item)){ + var label = this.getValue(item,this.label); + if(label){ + return label.toString(); + } + } + return undefined; //undefined + }, + + getLabelAttributes: function(/* item */ item){ + // summary: + // See dojo.data.api.Read.getLabelAttributes() + if(this.label !== ""){ + return [this.label]; //array + } + return null; //null + }, + + _fetchItems: function(request, fetchHandler, errorHandler) { + // summary: + // Fetch items (XML elements) that match to a query + // description: + // If 'sendQuery' is true, an XML document is loaded from + // 'url' with a query string. + // Otherwise, an XML document is loaded and list XML elements that + // match to a query (set of element names and their text attribute + // values that the items to contain). + // A wildcard, "*" can be used to query values to match all + // occurrences. + // If 'rootItem' is specified, it is used to fetch items. + // request: + // A request object + // fetchHandler: + // A function to call for fetched items + // errorHandler: + // A function to call on error + var url = this._getFetchUrl(request); + console.log("XmlStore._fetchItems(): url=" + url); + if(!url){ + errorHandler(new Error("No URL specified.")); + return; + } + var localRequest = (!this.sendQuery ? request : null); // use request for _getItems() + + var self = this; + var getArgs = { + url: url, + handleAs: "xml", + preventCache: true + }; + var getHandler = dojo.xhrGet(getArgs); + getHandler.addCallback(function(data){ + var items = self._getItems(data, localRequest); + console.log("XmlStore._fetchItems(): length=" + (items ? items.length : 0)); + if (items && items.length > 0) { + fetchHandler(items, request); + } + else { + fetchHandler([], request); + } + }); + getHandler.addErrback(function(data){ + errorHandler(data, request); + }); + }, + + _getFetchUrl: function(request){ + // summary: + // Generate a URL for fetch + // description: + // This default implementation generates a query string in the form of + // "?name1=value1&name2=value2..." off properties of 'query' object + // specified in 'request' and appends it to 'url', if 'sendQuery' + // is set to false. + // Otherwise, 'url' is returned as is. + // Sub-classes may override this method for the custom URL generation. + // request: + // A request object + // returns: + // A fetch URL + if(!this.sendQuery){ + return this.url; + } + var query = request.query; + if(!query){ + return this.url; + } + if(dojo.isString(query)){ + return this.url + query; + } + var queryString = ""; + for(var name in query){ + var value = query[name]; + if(value){ + if(queryString){ + queryString += "&"; + } + queryString += (name + "=" + value); + } + } + if(!queryString){ + return this.url; + } + //Check to see if the URL already has query params or not. + var fullUrl = this.url; + if(fullUrl.indexOf("?") < 0){ + fullUrl += "?"; + }else{ + fullUrl += "&"; + } + return fullUrl + queryString; + }, + + _getItems: function(document, request) { + // summary: + // Fetch items (XML elements) in an XML document based on a request + // description: + // This default implementation walks through child elements of + // the document element to see if all properties of 'query' object + // match corresponding attributes of the element (item). + // If 'request' is not specified, all child elements are returned. + // Sub-classes may override this method for the custom search in + // an XML document. + // document: + // An XML document + // request: + // A request object + // returns: + // An array of items + var query = null; + if(request){ + query = request.query; + } + var items = []; + var nodes = null; + + console.log("Looking up root item: " + this.rootItem); + if(this.rootItem !== ""){ + + nodes = document.getElementsByTagName(this.rootItem); + } + else{ + nodes = document.documentElement.childNodes; + } + for(var i = 0; i < nodes.length; i++){ + var node = nodes[i]; + if(node.nodeType != 1 /*ELEMENT_NODE*/){ + continue; + } + var item = this._getItem(node); + if(query){ + var found = true; + var ignoreCase = request.queryOptions ? request.queryOptions.ignoreCase : false; + + //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the + //same value for each item examined. Much more efficient. + var regexpList = {}; + for(var key in query){ + var value = query[key]; + if(typeof value === "string"){ + regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase); + } + } + + for(var attribute in query){ + var value = this.getValue(item, attribute); + if(value){ + var queryValue = query[attribute]; + if ((typeof value) === "string" && + (regexpList[attribute])){ + if((value.match(regexpList[attribute])) !== null){ + continue; + } + }else if((typeof value) === "object"){ + if( value.toString && + (regexpList[attribute])){ + var stringValue = value.toString(); + if((stringValue.match(regexpList[attribute])) !== null){ + continue; + } + }else{ + if(queryValue === "*" || queryValue === value){ + continue; + } + } + } + } + found = false; + break; + } + if(!found){ + continue; + } + } + items.push(item); + } + dojo.forEach(items,function(item){ + item.element.parentNode.removeChild(item.element); // make it root + },this); + return items; + }, + + close: function(/*dojo.data.api.Request || keywordArgs || null */ request){ + // summary: + // See dojo.data.api.Read.close() + }, + +/* dojo.data.api.Write */ + + newItem: function(/* object? */ keywordArgs){ + // summary: + // Return a new dojox.data.XmlItem + // description: + // At least, 'keywordArgs' must contain "tagName" to be used for + // the new element. + // Other attributes in 'keywordArgs' are set to the new element, + // including "text()", but excluding "childNodes". + // keywordArgs: + // An object containing initial attributes + // returns: + // An XML element + console.log("XmlStore.newItem()"); + keywordArgs = (keywordArgs || {}); + var tagName = keywordArgs.tagName; + if(!tagName){ + tagName = this.rootItem; + if(tagName === ""){ + return null; + } + } + + var document = this._getDocument(); + var element = document.createElement(tagName); + for(var attribute in keywordArgs){ + if(attribute === "tagName"){ + continue; + }else if(attribute === "text()"){ + var text = document.createTextNode(keywordArgs[attribute]); + element.appendChild(text); + }else{ + attribute = this._getAttribute(tagName, attribute); + if(attribute.charAt(0) === '@'){ + var name = attribute.substring(1); + element.setAttribute(name, keywordArgs[attribute]); + }else{ + var child = document.createElement(attribute); + var text = document.createTextNode(keywordArgs[attribute]); + child.appendChild(text); + element.appendChild(child); + } + } + } + + var item = this._getItem(element); + this._newItems.push(item); + return item; //object + }, + + deleteItem: function(/* item */ item){ + // summary: + // Delete an dojox.data.XmlItem (wrapper to a XML element). + // item: + // An XML element to delete + // returns: + // True + console.log("XmlStore.deleteItem()"); + var element = item.element; + if(element.parentNode){ + this._backupItem(item); + element.parentNode.removeChild(element); + return true; + } + this._forgetItem(item); + this._deletedItems.push(item); + return true; //boolean + }, + + setValue: function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value){ + // summary: + // Set an attribute value + // description: + // 'item' must be an instance of a dojox.data.XmlItem from the store instance. + // If 'attribute' specifies "tagName", nothing is set and false is + // returned. + // If 'attribute' specifies "childNodes", the value (XML element) is + // added to the element. + // If 'attribute' specifies "text()", a text node is created with + // the value and set it to the element as a child. + // For generic attributes, if '_attributeMap' is specified, + // an actual attribute name is looked up with the tag name of + // the element and 'attribute' (concatenated with '.'). + // Then, if 'attribute' starts with "@", the value is set to the XML + // attribute. + // Otherwise, a text node is created with the value and set it to + // the first child element of the tag name specified with 'attribute'. + // If the child element does not exist, it is created. + // item: + // An XML element that holds the attribute + // attribute: + // A tag name of a child element, An XML attribute name or one of + // special names + // value: + // A attribute value to set + // returns: + // False for "tagName", otherwise true + if(attribute === "tagName"){ + return false; //boolean + } + + this._backupItem(item); + + var element = item.element; + if(attribute === "childNodes"){ + var child = value.element; + element.appendChild(child); + }else if(attribute === "text()"){ + while (element.firstChild){ + element.removeChild(element.firstChild); + } + var text = this._getDocument(element).createTextNode(value); + element.appendChild(text); + }else{ + attribute = this._getAttribute(element.nodeName, attribute); + if(attribute.charAt(0) === '@'){ + var name = attribute.substring(1); + element.setAttribute(name, value); + }else{ + var child = null; + for(var i = 0; i < element.childNodes.length; i++){ + var node = element.childNodes[i]; + if( node.nodeType === 1 /*ELEMENT_NODE*/&& + node.nodeName === attribute){ + child = node; + break; + } + } + var document = this._getDocument(element); + if(child){ + while(child.firstChild){ + child.removeChild(child.firstChild); + } + }else{ + child = document.createElement(attribute); + element.appendChild(child); + } + var text = document.createTextNode(value); + child.appendChild(text); + } + } + return true; //boolean + }, + + setValues: function(/* item */ item, /* attribute || string */ attribute, /* array */ values){ + // summary: + // Set attribute values + // description: + // 'item' must be an instance of a dojox.data.XmlItem from the store instance. + // If 'attribute' specifies "tagName", nothing is set and false is + // returned. + // If 'attribute' specifies "childNodes", the value (array of XML + // elements) is set to the element's childNodes. + // If 'attribute' specifies "text()", a text node is created with + // the values and set it to the element as a child. + // For generic attributes, if '_attributeMap' is specified, + // an actual attribute name is looked up with the tag name of + // the element and 'attribute' (concatenated with '.'). + // Then, if 'attribute' starts with "@", the first value is set to + // the XML attribute. + // Otherwise, child elements of the tag name specified with + // 'attribute' are replaced with new child elements and their + // child text nodes of values. + // item: + // An XML element that holds the attribute + // attribute: + // A tag name of child elements, an XML attribute name or one of + // special names + // value: + // A attribute value to set + // returns: + // False for "tagName", otherwise true + if(attribute === "tagName"){ + return false; //boolean + } + + this._backupItem(item); + + var element = item.element; + if(attribute === "childNodes"){ + while(element.firstChild){ + element.removeChild(element.firstChild); + } + for(var i = 0; i < values.length; i++){ + var child = values[i].element; + element.appendChild(child); + } + }else if(attribute === "text()"){ + while (element.firstChild){ + element.removeChild(element.firstChild); + } + var value = ""; + for(var i = 0; i < values.length; i++){ + value += values[i]; + } + var text = this._getDocument(element).createTextNode(value); + element.appendChild(text); + }else{ + attribute = this._getAttribute(element.nodeName, attribute); + if(attribute.charAt(0) === '@'){ + var name = attribute.substring(1); + element.setAttribute(name, values[0]); + }else{ + for(var i = element.childNodes.length - 1; i >= 0; i--){ + var node = element.childNodes[i]; + if( node.nodeType === 1 /*ELEMENT_NODE*/ && + node.nodeName === attribute){ + element.removeChild(node); + } + } + var document = this._getDocument(element); + for(var i = 0; i < values.length; i++){ + var child = document.createElement(attribute); + var text = document.createTextNode(values[i]); + child.appendChild(text); + element.appendChild(child); + } + } + } + return true; //boolean + }, + + unsetAttribute: function(/* item */ item, /* attribute || string */ attribute){ + // summary: + // Remove an attribute + // description: + // 'item' must be an instance of a dojox.data.XmlItem from the store instance. + // 'attribute' can be an XML attribute name of the element or one of + // special names described below. + // If 'attribute' specifies "tagName", nothing is removed and false is + // returned. + // If 'attribute' specifies "childNodes" or "text()", all child nodes + // are removed. + // For generic attributes, if '_attributeMap' is specified, + // an actual attribute name is looked up with the tag name of + // the element and 'attribute' (concatenated with '.'). + // Then, if 'attribute' starts with "@", the XML attribute is removed. + // Otherwise, child elements of the tag name specified with + // 'attribute' are removed. + // item: + // An XML element that holds the attribute + // attribute: + // A tag name of child elements, an XML attribute name or one of + // special names + // returns: + // False for "tagName", otherwise true + if(attribute === "tagName"){ + return false; //boolean + } + + this._backupItem(item); + + var element = item.element; + if(attribute === "childNodes" || attribute === "text()"){ + while(element.firstChild){ + element.removeChild(element.firstChild); + } + }else{ + attribute = this._getAttribute(element.nodeName, attribute); + if(attribute.charAt(0) === '@'){ + var name = attribute.substring(1); + element.removeAttribute(name); + }else{ + for(var i = element.childNodes.length - 1; i >= 0; i--){ + var node = element.childNodes[i]; + if( node.nodeType === 1 /*ELEMENT_NODE*/ && + node.nodeName === attribute){ + element.removeChild(node); + } + } + } + } + return true; //boolean + }, + + save: function(/* object */ keywordArgs){ + // summary: + // Save new and/or modified items (XML elements) + // description: + // 'url' is used to save XML documents for new, modified and/or + // deleted XML elements. + // keywordArgs: + // An object for callbacks + if(!keywordArgs){ + keywordArgs = {}; + } + for(var i = 0; i < this._modifiedItems.length; i++){ + this._saveItem(this._modifiedItems[i], keywordArgs, "PUT"); + } + for(var i = 0; i < this._newItems.length; i++){ + var item = this._newItems[i]; + if(item.element.parentNode){ // reparented + this._newItems.splice(i, 1); + i--; + continue; + } + this._saveItem(this._newItems[i], keywordArgs, "POST"); + } + for(var i = 0; i < this._deletedItems.length; i++){ + this._saveItem(this._deletedItems[i], keywordArgs, "DELETE"); + } + }, + + revert: function(){ + // summary: + // Invalidate changes (new and/or modified elements) + // returns: + // True + console.log("XmlStore.revert() _newItems=" + this._newItems.length); + console.log("XmlStore.revert() _deletedItems=" + this._deletedItems.length); + console.log("XmlStore.revert() _modifiedItems=" + this._modifiedItems.length); + this._newItems = []; + this._restoreItems(this._deletedItems); + this._deletedItems = []; + this._restoreItems(this._modifiedItems); + this._modifiedItems = []; + return true; //boolean + }, + + isDirty: function(/* item? */ item){ + // summary: + // Check whether an item is new, modified or deleted + // description: + // If 'item' is specified, true is returned if the item is new, + // modified or deleted. + // Otherwise, true is returned if there are any new, modified + // or deleted items. + // item: + // An item (XML element) to check + // returns: + // True if an item or items are new, modified or deleted, otherwise + // false + if (item) { + var element = this._getRootElement(item.element); + return (this._getItemIndex(this._newItems, element) >= 0 || + this._getItemIndex(this._deletedItems, element) >= 0 || + this._getItemIndex(this._modifiedItems, element) >= 0); //boolean + } + else { + return (this._newItems.length > 0 || + this._deletedItems.length > 0 || + this._modifiedItems.length > 0); //boolean + } + }, + + _saveItem: function(item, keywordArgs, method){ + if(method === "PUT"){ + url = this._getPutUrl(item); + }else if(method === "DELETE"){ + url = this._getDeleteUrl(item); + }else{ // POST + url = this._getPostUrl(item); + } + if(!url){ + if(keywordArgs.onError){ + keywordArgs.onError.call(scope, new Error("No URL for saving content: " + postContent)); + } + return; + } + + var saveArgs = { + url: url, + method: (method || "POST"), + contentType: "text/xml", + handleAs: "xml" + }; + var saveHander; + if(method === "PUT"){ + saveArgs.putData = this._getPutContent(item); + saveHandler = dojo.rawXhrPut(saveArgs); + }else if(method === "DELETE"){ + saveHandler = dojo.xhrDelete(saveArgs); + }else{ // POST + saveArgs.postData = this._getPostContent(item); + saveHandler = dojo.rawXhrPost(saveArgs); + } + var scope = (keywordArgs.scope || dojo.global); + var self = this; + saveHandler.addCallback(function(data){ + self._forgetItem(item); + if(keywordArgs.onComplete){ + keywordArgs.onComplete.call(scope); + } + }); + saveHandler.addErrback(function(error){ + if(keywordArgs.onError){ + keywordArgs.onError.call(scope, error); + } + }); + }, + + _getPostUrl: function(item){ + // summary: + // Generate a URL for post + // description: + // This default implementation just returns 'url'. + // Sub-classes may override this method for the custom URL. + // item: + // An item to save + // returns: + // A post URL + return this.url; //string + }, + + _getPutUrl: function(item){ + // summary: + // Generate a URL for put + // description: + // This default implementation just returns 'url'. + // Sub-classes may override this method for the custom URL. + // item: + // An item to save + // returns: + // A put URL + return this.url; //string + }, + + _getDeleteUrl: function(item){ + // summary: + // Generate a URL for delete + // description: + // This default implementation returns 'url' with 'keyAttribute' + // as a query string. + // Sub-classes may override this method for the custom URL based on + // changes (new, deleted, or modified). + // item: + // An item to delete + // returns: + // A delete URL + var url = this.url; + if (item && this.keyAttribute !== "") { + var value = this.getValue(item, this.keyAttribute); + if (value) { + var key = this.keyAttribute.charAt(0) ==='@' ? this.keyAttribute.substring(1): this.keyAttribute; + url += url.indexOf('?') < 0 ? '?' : '&'; + url += key + '=' + value; + } + } + return url; //string + }, + + _getPostContent: function(item){ + // summary: + // Generate a content to post + // description: + // This default implementation generates an XML document for one + // (the first only) new or modified element. + // Sub-classes may override this method for the custom post content + // generation. + // item: + // An item to save + // returns: + // A post content + var element = item.element; + var declaration = ""; // FIXME: encoding? + return declaration + dojox.data.dom.innerXML(element); //XML string + }, + + _getPutContent: function(item){ + // summary: + // Generate a content to put + // description: + // This default implementation generates an XML document for one + // (the first only) new or modified element. + // Sub-classes may override this method for the custom put content + // generation. + // item: + // An item to save + // returns: + // A post content + var element = item.element; + var declaration = ""; // FIXME: encoding? + return declaration + dojox.data.dom.innerXML(element); //XML string + }, + +/* internal API */ + + _getAttribute: function(tagName, attribute){ + if(this._attributeMap){ + var key = tagName + "." + attribute; + var value = this._attributeMap[key]; + if(value){ + attribute = value; + }else{ // look for global attribute + value = this._attributeMap[attribute]; + if(value){ + attribute = value; + } + } + } + return attribute; //object + }, + + _getItem: function(element){ + return new dojox.data.XmlItem(element, this); //object + }, + + _getItemIndex: function(items, element){ + for(var i = 0; i < items.length; i++){ + if(items[i].element === element){ + return i; //int + } + } + return -1; //int + }, + + _backupItem: function(item){ + var element = this._getRootElement(item.element); + if( this._getItemIndex(this._newItems, element) >= 0 || + this._getItemIndex(this._modifiedItems, element) >= 0){ + return; // new or already modified + } + if(element != item.element){ + item = this._getItem(element); + } + item._backup = element.cloneNode(true); + this._modifiedItems.push(item); + }, + + _restoreItems: function(items){ + + dojo.forEach(items,function(item){ + if(item._backup){ + item.element = item._backup; + item._backup = null; + } + },this); + }, + + _forgetItem: function(item){ + var element = item.element; + var index = this._getItemIndex(this._newItems, element); + if(index >= 0){ + this._newItems.splice(index, 1); + } + index = this._getItemIndex(this._deletedItems, element); + if(index >= 0){ + this._deletedItems.splice(index, 1); + } + index = this._getItemIndex(this._modifiedItems, element); + if(index >= 0){ + this._modifiedItems.splice(index, 1); + } + }, + + _getDocument: function(element){ + if(element){ + return element.ownerDocument; //DOMDocument + }else if(!this._document){ + return dojox.data.dom.createDocument(); // DOMDocument + } + }, + + _getRootElement: function(element){ + while(element.parentNode){ + element = element.parentNode; + } + return element; //DOMElement + } + +}); + +//FIXME: Is a full class here really needed for containment of the item or would +//an anon object work fine? +dojo.declare("dojox.data.XmlItem", null, { + constructor: function(element, store) { + // summary: + // Initialize with an XML element + // element: + // An XML element + // store: + // The containing store, if any. + this.element = element; + this.store = store; + }, + // summary: + // A data item of 'XmlStore' + // description: + // This class represents an item of 'XmlStore' holding an XML element. + // 'element' + // element: + // An XML element + + toString: function() { + // summary: + // Return a value of the first text child of the element + // returns: + // a value of the first text child of the element + var str = ""; + if (this.element) { + for (var i = 0; i < this.element.childNodes.length; i++) { + var node = this.element.childNodes[i]; + if (node.nodeType === 3) { + str = node.nodeValue; + break; + } + } + } + return str; //String + } + +}); +dojo.extend(dojox.data.XmlStore,dojo.data.util.simpleFetch); + +} diff --git a/includes/js/dojox/data/demos/demo_DataDemoTable.html b/includes/js/dojox/data/demos/demo_DataDemoTable.html new file mode 100644 index 0000000..09761b9 --- /dev/null +++ b/includes/js/dojox/data/demos/demo_DataDemoTable.html @@ -0,0 +1,130 @@ + + + + Dojo Visual Loader Test + + + + + + + + + + +

Dojox Data Demo Table

+ + + + + + + + + + + + + + +
+ + + + + + + + + + diff --git a/includes/js/dojox/data/demos/demo_FlickrRestStore.html b/includes/js/dojox/data/demos/demo_FlickrRestStore.html new file mode 100644 index 0000000..a094bc6 --- /dev/null +++ b/includes/js/dojox/data/demos/demo_FlickrRestStore.html @@ -0,0 +1,275 @@ + + + + Demo of FlickrRestStore + + + + + + + +

+ DEMO: FlickrRestStore Search +

+
+

+ Description: +

+

+ This simple demo shows how services, such as Flickr, can be wrapped by the datastore API. + In this demo, you can search public Flickr images through a FlickrRestStore by specifying + a series of tags (separated by spaces) to search on. The results will be displayed below the search box. +

+

+ For fun, search on the 3dny tag! +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Status: + +
+
+ User ID: + +
+
+ Set ID + +
+
+ Tags: + +
+
+ Full Text + +
+
+ Tagmode: + + + + Sort + + + +
+ Number of Pictures: + +
+
+ Page: + +
+
+ +
+
+
+
+
+ + + diff --git a/includes/js/dojox/data/demos/demo_FlickrStore.html b/includes/js/dojox/data/demos/demo_FlickrStore.html new file mode 100644 index 0000000..5ca48cf --- /dev/null +++ b/includes/js/dojox/data/demos/demo_FlickrStore.html @@ -0,0 +1,199 @@ + + + + Demo of FlickrStore + + + + + + + +

+ DEMO: FlickrStore Search +

+
+

+ Description: +

+

+ This simple demo shows how services, such as Flickr, can be wrapped by the datastore API. In this demo, you can search public Flickr images through a simple FlickrStore by specifying a series of tags (separated by spaces) to search on. The results will be displayed below the search box. +

+

+ For fun, search on the 3dny tag! +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Status: + +
+
+ ID: + +
+
+ Tags: + +
+
+ Tagmode: + + +
+ Number of Pictures: + +
+
+ +
+
+
+
+
+ + + diff --git a/includes/js/dojox/data/demos/demo_LazyLoad.html b/includes/js/dojox/data/demos/demo_LazyLoad.html new file mode 100644 index 0000000..358ce84 --- /dev/null +++ b/includes/js/dojox/data/demos/demo_LazyLoad.html @@ -0,0 +1,66 @@ + + + + Demo of Lazy Loading Datastore + + + + + + + +

+ DEMO: Lazy Loading Datastore used by dijit.Tree +

+
+

+ Description: +

+

+ This simple demo shows how the dijit.Tree widget can work with a Datastore that does lazy-loading of values into the tree. + In this demo, the Datastore is an extension of ItemFileReadStore that overrides the isItemLoaded() and loadItem() functions of + with ones that can detect 'stub' items and use the data in the stub item to load the real data for that item when it + is required. In this demo, the real data is required when one of the tree nodes is expanded. +

+

+ The key thing to note is that all the lazy-loading logic (how to locate the data from the backend and so forth) is encapsulated + into the store functions. The dijit.Tree widget only knows about and uses the dojo.data.Read API interfaces to call to the store to + get items, test if child items are fully loaded or not, and to invoke the loadItem() function on items that are not yet fully + loaded but have been requested to be expanded into view. It has no knowledge of how the store actually goes and gets the data. +

+ +
+ + +
+ + + Continents +
+
+ + + diff --git a/includes/js/dojox/data/demos/demo_MultiStores.html b/includes/js/dojox/data/demos/demo_MultiStores.html new file mode 100644 index 0000000..9faa8be --- /dev/null +++ b/includes/js/dojox/data/demos/demo_MultiStores.html @@ -0,0 +1,72 @@ + + + + Demo of Multiple Widgets using different Datastores + + + + + + + +

+ DEMO: Multiple DataStore implementations with dojo.data aware Widgets +

+
+

+ Description: +

+

+ This simple demo shows how widgets which know only the dojo.data interfaces can work with data sources of varying formats. In this case an OpmlStore + and a ItemFileReadStore are used to house the same data in different formats. +

+ +
+ + +
+
+ +

+ Widgets using OpmlStore: +

+
+ ComboBox:
+ +
+
+ + Tree:
+
+
+ +

+ Widgets using ItemFileReadStore: +

+
+ ComboBox:
+ +
+
+ + Tree:
+
+
+ + diff --git a/includes/js/dojox/data/demos/demo_PicasaStore.html b/includes/js/dojox/data/demos/demo_PicasaStore.html new file mode 100644 index 0000000..78bc961 --- /dev/null +++ b/includes/js/dojox/data/demos/demo_PicasaStore.html @@ -0,0 +1,188 @@ + + + + Demo of PicasaStore + + + + + + + +

+ DEMO: PicasaStore Search +

+
+

+ Description: +

+

+ This simple demo shows how services, such as Flickr, can be wrapped by the datastore API. In this demo, you can search public Flickr images through a simple FlickrStore by specifying a series of tags (separated by spaces) to search on. The results will be displayed below the search box. +

+

+ For fun, search on the 3dny tag! +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ Status: + +
+
+ ID: + +
+
+ Query: + +
+
+ Number of Pictures: + +
+
+
+ +
+
+
+
+
+ + + diff --git a/includes/js/dojox/data/demos/demo_QueryReadStore_ComboBox.html b/includes/js/dojox/data/demos/demo_QueryReadStore_ComboBox.html new file mode 100644 index 0000000..f6d187f --- /dev/null +++ b/includes/js/dojox/data/demos/demo_QueryReadStore_ComboBox.html @@ -0,0 +1,56 @@ + + + + Dojox QueryReadStore+ComboBox Demo + + + + + + +

Dojox QueryReadStore + ComboBox demo

+ +

Everything is created ONLY in markup

+
+
+
+ +
+
+ var w = dijit.byId("cb1"); +
= w.value +
= w.item ? w.store.getValue(w.item, "id") : "-" +
= w.getDisplayedValue() +
= w.isValid() +
+
+ + + + diff --git a/includes/js/dojox/data/demos/demo_QueryReadStore_FilteringSelect.html b/includes/js/dojox/data/demos/demo_QueryReadStore_FilteringSelect.html new file mode 100644 index 0000000..addaeca --- /dev/null +++ b/includes/js/dojox/data/demos/demo_QueryReadStore_FilteringSelect.html @@ -0,0 +1,56 @@ + + + + Dojox QueryReadStore+FilteringSelect Demo + + + + + + +

Dojox QueryReadStore + FilteringSelect demo

+ +

Everything is created ONLY in markup

+
+
+
+ +
+
+ var w = dijit.byId("fs1"); +
= w.value +
= w.item ? w.store.getValue(w.item, "id") : "-" +
= w.getDisplayedValue() +
= w.isValid() +
+
+ + + + diff --git a/includes/js/dojox/data/demos/demo_QueryReadStore_grid.html b/includes/js/dojox/data/demos/demo_QueryReadStore_grid.html new file mode 100644 index 0000000..3f7db7e --- /dev/null +++ b/includes/js/dojox/data/demos/demo_QueryReadStore_grid.html @@ -0,0 +1,129 @@ + + + + Dojox QueryReadStore+grid Demo + + + + + + +

Dojox QueryReadStore + Grid demo - paging, sortable and filterable all server-side

+ +

The grid is in HTML, store, model, etc. are JS, sorting is added by extending the model class

+ Capabilities: load data from server, show data, paging (30 rows at a time), sort, filter
+ You can see that data are loaded upon demand by scrolling down in the grid below line #30, + open FireBug and you see a server request being issued, to retreive another 30 rows/items.
+

+ +
+ +

The store and grid are "generated" and connected in HTML, filtering is done via JS

+ This store is by default sorted descending by name (not as the one above, which is ascending). +
+
+
+ + + + + + diff --git a/includes/js/dojox/data/demos/flickrDemo.css b/includes/js/dojox/data/demos/flickrDemo.css new file mode 100644 index 0000000..793d1c6 --- /dev/null +++ b/includes/js/dojox/data/demos/flickrDemo.css @@ -0,0 +1,29 @@ +.flickrView { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; + border-collapse: separate; + width: 100%; +} +.flickrView th { + text-align: left; +} +.flickrView tr { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} +.flickrView tr td { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} +.flickrView { + background-color: #EFEFEF; +} +.flickrTitle { + background-color: #CCCCCC; +} diff --git a/includes/js/dojox/data/demos/flickrDemo.css.commented.css b/includes/js/dojox/data/demos/flickrDemo.css.commented.css new file mode 100644 index 0000000..7e75a5d --- /dev/null +++ b/includes/js/dojox/data/demos/flickrDemo.css.commented.css @@ -0,0 +1,35 @@ +.flickrView { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; + border-collapse: separate; + width: 100%; +} + +.flickrView th { + text-align: left; +} + +.flickrView tr { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} + +.flickrView tr td { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} + +.flickrView { + background-color: #EFEFEF; +} + +.flickrTitle { + background-color: #CCCCCC; +} + diff --git a/includes/js/dojox/data/demos/geography.json b/includes/js/dojox/data/demos/geography.json new file mode 100644 index 0000000..c2f01bb --- /dev/null +++ b/includes/js/dojox/data/demos/geography.json @@ -0,0 +1,45 @@ +{ identifier: 'name', + label: 'name', + items: [ + { name:'Africa', type:'continent', children:[ + { name:'Egypt', type:'country' }, + { name:'Kenya', type:'country', children:[ + { name:'Nairobi', type:'city' }, + { name:'Mombasa', type:'city' } ] + }, + { name:'Sudan', type:'country', children: + { name:'Khartoum', type:'city' } + } ] + }, + { name:'Asia', type:'continent', children:[ + { name:'China', type:'country' }, + { name:'India', type:'country' }, + { name:'Russia', type:'country' }, + { name:'Mongolia', type:'country' } ] + }, + { name:'Australia', type:'continent', population:'21 million', children: + { name:'Commonwealth of Australia', type:'country', population:'21 million'} + }, + { name:'Europe', type:'continent', children:[ + { name:'Germany', type:'country' }, + { name:'France', type:'country' }, + { name:'Spain', type:'country' }, + { name:'Italy', type:'country' } ] + }, + { name:'North America', type:'continent', children:[ + { name:'Mexico', type:'country', population:'108 million', area:'1,972,550 sq km', children:[ + { name:'Mexico City', type:'city', population:'19 million', timezone:'-6 UTC'}, + { name:'Guadalajara', type:'city', population:'4 million', timezone:'-6 UTC' } ] + }, + { name:'Canada', type:'country', population:'33 million', area:'9,984,670 sq km', children:[ + { name:'Ottawa', type:'city', population:'0.9 million', timezone:'-5 UTC'}, + { name:'Toronto', type:'city', population:'2.5 million', timezone:'-5 UTC' }] + }, + { name:'United States of America', type:'country' } ] + }, + { name:'South America', type:'continent', children:[ + { name:'Brazil', type:'country', population:'186 million' }, + { name:'Argentina', type:'country', population:'40 million' } ] + } ] +} + diff --git a/includes/js/dojox/data/demos/geography.xml b/includes/js/dojox/data/demos/geography.xml new file mode 100644 index 0000000..070a8c1 --- /dev/null +++ b/includes/js/dojox/data/demos/geography.xml @@ -0,0 +1,51 @@ + + + + geography.opml + 2006-11-10 + 2006-11-13 + Magellan, Ferdinand + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/includes/js/dojox/data/demos/geography/Argentina/data.json b/includes/js/dojox/data/demos/geography/Argentina/data.json new file mode 100644 index 0000000..17ba291 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Argentina/data.json @@ -0,0 +1,5 @@ +{ + name:'Argentina', + type:'country', + population:'40 million' +} diff --git a/includes/js/dojox/data/demos/geography/Brazil/data.json b/includes/js/dojox/data/demos/geography/Brazil/data.json new file mode 100644 index 0000000..a326c24 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Brazil/data.json @@ -0,0 +1,5 @@ +{ + name:'Brazil', + type:'country', + population:'186 million' +} diff --git a/includes/js/dojox/data/demos/geography/Canada/Ottawa/data.json b/includes/js/dojox/data/demos/geography/Canada/Ottawa/data.json new file mode 100644 index 0000000..df3bbc8 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Canada/Ottawa/data.json @@ -0,0 +1,6 @@ +{ + name:'Ottawa', + type:'city', + population:'0.9 million', + timezone:'-5 UTC' +} diff --git a/includes/js/dojox/data/demos/geography/Canada/Toronto/data.json b/includes/js/dojox/data/demos/geography/Canada/Toronto/data.json new file mode 100644 index 0000000..534409b --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Canada/Toronto/data.json @@ -0,0 +1,6 @@ +{ + name:'Toronto', + type:'city', + population:'2.5 million', + timezone:'-5 UTC' +} diff --git a/includes/js/dojox/data/demos/geography/Canada/data.json b/includes/js/dojox/data/demos/geography/Canada/data.json new file mode 100644 index 0000000..6ef34ed --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Canada/data.json @@ -0,0 +1,10 @@ +{ + name:'Canada', + type:'country', + population:'33 million', area:'9,984,670 sq km', + children:[ + {stub:'Ottawa'}, + {stub:'Toronto'} + ] +} + diff --git a/includes/js/dojox/data/demos/geography/China/data.json b/includes/js/dojox/data/demos/geography/China/data.json new file mode 100644 index 0000000..72c29cc --- /dev/null +++ b/includes/js/dojox/data/demos/geography/China/data.json @@ -0,0 +1,4 @@ +{ + name:'China', + type:'country' +} diff --git a/includes/js/dojox/data/demos/geography/Commonwealth of Australia/data.json b/includes/js/dojox/data/demos/geography/Commonwealth of Australia/data.json new file mode 100644 index 0000000..e093295 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Commonwealth of Australia/data.json @@ -0,0 +1,5 @@ +{ + name:'Commonwealth of Australia', + type:'country', + population:'21 million' +} diff --git a/includes/js/dojox/data/demos/geography/Egypt/data.json b/includes/js/dojox/data/demos/geography/Egypt/data.json new file mode 100644 index 0000000..d355537 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Egypt/data.json @@ -0,0 +1,5 @@ +{ + name:'Egypt', + type:'country' +} + diff --git a/includes/js/dojox/data/demos/geography/France/data.json b/includes/js/dojox/data/demos/geography/France/data.json new file mode 100644 index 0000000..5b5f3c3 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/France/data.json @@ -0,0 +1,4 @@ +{ + name:'France', + type:'country' +} diff --git a/includes/js/dojox/data/demos/geography/Germany/data.json b/includes/js/dojox/data/demos/geography/Germany/data.json new file mode 100644 index 0000000..1656257 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Germany/data.json @@ -0,0 +1,4 @@ +{ + name:'Germany', + type:'country' +} diff --git a/includes/js/dojox/data/demos/geography/India/data.json b/includes/js/dojox/data/demos/geography/India/data.json new file mode 100644 index 0000000..3103f89 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/India/data.json @@ -0,0 +1,4 @@ +{ + name:'India', + type:'country' +} diff --git a/includes/js/dojox/data/demos/geography/Italy/data.json b/includes/js/dojox/data/demos/geography/Italy/data.json new file mode 100644 index 0000000..6e6b076 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Italy/data.json @@ -0,0 +1,4 @@ +{ + name:'Italy', + type:'country' +} diff --git a/includes/js/dojox/data/demos/geography/Kenya/Mombasa/data.json b/includes/js/dojox/data/demos/geography/Kenya/Mombasa/data.json new file mode 100644 index 0000000..28aa849 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Kenya/Mombasa/data.json @@ -0,0 +1,5 @@ +{ + name:'Mombasa', + type:'city', + population: "Unknown" +} diff --git a/includes/js/dojox/data/demos/geography/Kenya/Nairobi/data.json b/includes/js/dojox/data/demos/geography/Kenya/Nairobi/data.json new file mode 100644 index 0000000..f5658ec --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Kenya/Nairobi/data.json @@ -0,0 +1,5 @@ +{ + name:'Nairobi', + type:'city', + population: "Unknown" +} diff --git a/includes/js/dojox/data/demos/geography/Kenya/data.json b/includes/js/dojox/data/demos/geography/Kenya/data.json new file mode 100644 index 0000000..9253c25 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Kenya/data.json @@ -0,0 +1,9 @@ +{ + name:'Kenya', + type:'country', + children:[ + {stub:'Nairobi'}, + {stub:'Mombasa'} + ] +} + diff --git a/includes/js/dojox/data/demos/geography/Mexico/Guadalajara/data.json b/includes/js/dojox/data/demos/geography/Mexico/Guadalajara/data.json new file mode 100644 index 0000000..059fc82 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Mexico/Guadalajara/data.json @@ -0,0 +1,7 @@ +{ + name:'Guadalajara', + type:'city', + population:'4 million', + timezone:'-6 UTC' +} + diff --git a/includes/js/dojox/data/demos/geography/Mexico/Mexico City/data.json b/includes/js/dojox/data/demos/geography/Mexico/Mexico City/data.json new file mode 100644 index 0000000..8c67622 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Mexico/Mexico City/data.json @@ -0,0 +1,6 @@ +{ + name:'Mexico City', + type:'city', + population:'19 million', + timezone:'-6 UTC' +} diff --git a/includes/js/dojox/data/demos/geography/Mexico/data.json b/includes/js/dojox/data/demos/geography/Mexico/data.json new file mode 100644 index 0000000..aa381e4 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Mexico/data.json @@ -0,0 +1,10 @@ +{ + name:'Mexico', + type:'country', + population:'108 million', + area:'1,972,550 sq km', + children:[ + {stub:'Mexico City'}, + {stub:'Guadalajara'} + ] +} diff --git a/includes/js/dojox/data/demos/geography/Mongolia/data.json b/includes/js/dojox/data/demos/geography/Mongolia/data.json new file mode 100644 index 0000000..4c60b22 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Mongolia/data.json @@ -0,0 +1,4 @@ +{ + name:'Mongolia', + type:'country' +} diff --git a/includes/js/dojox/data/demos/geography/Russia/data.json b/includes/js/dojox/data/demos/geography/Russia/data.json new file mode 100644 index 0000000..5d9a6ba --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Russia/data.json @@ -0,0 +1,4 @@ +{ + name:'Russia', + type:'country' +} diff --git a/includes/js/dojox/data/demos/geography/Spain/data.json b/includes/js/dojox/data/demos/geography/Spain/data.json new file mode 100644 index 0000000..d9a1210 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Spain/data.json @@ -0,0 +1,4 @@ +{ + name:'Spain', + type:'country' +} diff --git a/includes/js/dojox/data/demos/geography/Sudan/Khartoum/data.json b/includes/js/dojox/data/demos/geography/Sudan/Khartoum/data.json new file mode 100644 index 0000000..befa3c7 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Sudan/Khartoum/data.json @@ -0,0 +1,5 @@ +{ + name:'Khartoum', + type:'city' +} + diff --git a/includes/js/dojox/data/demos/geography/Sudan/data.json b/includes/js/dojox/data/demos/geography/Sudan/data.json new file mode 100644 index 0000000..fe7585b --- /dev/null +++ b/includes/js/dojox/data/demos/geography/Sudan/data.json @@ -0,0 +1,6 @@ +{ + name:'Sudan', + type:'country', + children:{stub:'Khartoum'} +} + diff --git a/includes/js/dojox/data/demos/geography/United States of America/data.json b/includes/js/dojox/data/demos/geography/United States of America/data.json new file mode 100644 index 0000000..7dbdd61 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/United States of America/data.json @@ -0,0 +1,4 @@ +{ + name:'United States of America', + type:'country' +} diff --git a/includes/js/dojox/data/demos/geography/root.json b/includes/js/dojox/data/demos/geography/root.json new file mode 100644 index 0000000..dda74f5 --- /dev/null +++ b/includes/js/dojox/data/demos/geography/root.json @@ -0,0 +1,39 @@ +{ + identifier: 'name', + label: 'name', + items: [ + { name:'Africa', type:'continent', + children:[{_reference:'Egypt'}, {_reference:'Kenya'}, {_reference:'Sudan'}] }, + { name:'Egypt', type:'stub', parent: 'geography'}, + { name:'Kenya', type:'stub', parent: 'geography'}, + { name:'Sudan', type:'stub', parent: 'geography'}, + + { name:'Asia', type:'continent', + children:[{_reference:'China'}, {_reference:'India'}, {_reference:'Russia'}, {_reference:'Mongolia'}] }, + { name:'China', type:'stub', parent: 'geography'}, + { name:'India', type:'stub', parent: 'geography'}, + { name:'Russia', type:'stub', parent: 'geography'}, + { name:'Mongolia', type:'stub', parent: 'geography'}, + + { name:'Australia', type:'continent', population:'21 million', + children:{_reference:'Commonwealth of Australia'}}, + { name:'Commonwealth of Australia', type:'stub', parent:'geography'}, + + { name:'Europe', type:'continent', + children:[{_reference:'Germany'}, {_reference:'France'}, {_reference:'Spain'}, {_reference:'Italy'}] }, + { name:'Germany', type:'stub', parent: 'geography'}, + { name:'France', type:'stub', parent: 'geography'}, + { name:'Spain', type:'stub', parent: 'geography'}, + { name:'Italy', type:'stub', parent: 'geography'}, + + { name:'North America', type:'continent', + children:[{_reference:'Mexico'}, {_reference:'Canada'}, {_reference:'United States of America'}] }, + { name:'Mexico', type:'stub', parent: 'geography'}, + { name:'Canada', type:'stub', parent: 'geography'}, + { name:'United States of America', type:'stub', parent: 'geography'}, + + { name:'South America', type:'continent', + children:[{_reference:'Brazil'}, {_reference:'Argentina'}] }, + { name:'Brazil', type:'stub', parent: 'geography'}, + { name:'Argentina', type:'stub', parent: 'geography'} +]} diff --git a/includes/js/dojox/data/demos/picasaDemo.css b/includes/js/dojox/data/demos/picasaDemo.css new file mode 100644 index 0000000..9163d40 --- /dev/null +++ b/includes/js/dojox/data/demos/picasaDemo.css @@ -0,0 +1,37 @@ +.picasaView { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; + border-collapse: separate; + width: 100%; +} +.picasaView th { + text-align: left; +} +.picasaView tr { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} +.picasaView tr td { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} +.picasaView { + background-color: #EFEFEF; + float: left; + width: 250px; + height: 250px; +} +.picasaSummary { + width: 250px; + height: 30px; + overflow: hidden; + } +.picasaTitle { + background-color: #CCCCCC; +} diff --git a/includes/js/dojox/data/demos/picasaDemo.css.commented.css b/includes/js/dojox/data/demos/picasaDemo.css.commented.css new file mode 100644 index 0000000..e274f87 --- /dev/null +++ b/includes/js/dojox/data/demos/picasaDemo.css.commented.css @@ -0,0 +1,44 @@ +.picasaView { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; + border-collapse: separate; + width: 100%; +} + +.picasaView th { + text-align: left; +} + +.picasaView tr { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} + +.picasaView tr td { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} + +.picasaView { + background-color: #EFEFEF; + float: left; + width: 250px; + height: 250px; +} + +.picasaSummary { + width: 250px; + height: 30px; + overflow: hidden; + } + +.picasaTitle { + background-color: #CCCCCC; +} + diff --git a/includes/js/dojox/data/demos/stores/LazyLoadJSIStore.js b/includes/js/dojox/data/demos/stores/LazyLoadJSIStore.js new file mode 100644 index 0000000..e7acff7 --- /dev/null +++ b/includes/js/dojox/data/demos/stores/LazyLoadJSIStore.js @@ -0,0 +1,142 @@ +if(!dojo._hasResource["dojox.data.demos.stores.LazyLoadJSIStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.demos.stores.LazyLoadJSIStore"] = true; +dojo.provide("dojox.data.demos.stores.LazyLoadJSIStore"); +dojo.require("dojo.data.ItemFileReadStore"); + +dojo.declare("dojox.data.demos.stores.LazyLoadJSIStore", dojo.data.ItemFileReadStore, { + constructor: function(/* object */ keywordParameters){ + // LazyLoadJSIStore extends ItemFileReadStore to implement an + // example of lazy-loading/faulting in items on-demand. + // Note this is certianly not a perfect implementation, it is + // an example. + }, + + isItemLoaded: function(/*object*/ item) { + // summary: + // Overload of the isItemLoaded function to look for items of type 'stub', which indicate + // the data hasn't been loaded in yet. + // + // item: + // The item to examine. + + //For this store, if it has the value of stub for its type attribute, + //then the item basn't been fully loaded yet. It's just a placeholder. + if(this.getValue(item, "type") === "stub"){ + return false; + } + return true; + }, + + loadItem: function(keywordArgs){ + // summary: + // Overload of the loadItem function to fault in items. This assumes the data for an item is laid out + // in a RESTful sort of pattern name0/name1/data.json and so on and uses that to load the data. + // It will also detect stub items in the newly loaded item and insert the stubs into the ItemFileReadStore + // list so they can also be loaded in on-demand. + // + // item: + // The item to examine. + + var item = keywordArgs.item; + this._assertIsItem(item); + + //Build the path to the data.json for this item + //The path consists of where its parent was loaded from + //plus the item name. + var itemName = this.getValue(item, "name"); + var parent = this.getValue(item, "parent"); + var dataUrl = ""; + if (parent){ + dataUrl += (parent + "/"); + } + + //For this store, all child input data is loaded from a url that ends with data.json + dataUrl += itemName + "/data.json"; + + //Need a reference to the store to call back to its structures. + var self = this; + + // Callback for handling a successful load. + var gotData = function(data){ + //Now we need to modify the existing item a bit to take it out of stub state + //Since we extend the store and have knowledge of the internal + //structure, this can be done here. Now, is we extended + //a write store, we could call the write APIs to do this too + //But for a simple demo the diretc modification in the store function + //is sufficient. + + //Clear off the stub indicators. + delete item.type; + delete item.parent; + + //Set up the loaded values in the format ItemFileReadStore uses for attributes. + for (i in data) { + if (dojo.isArray(data[i])) { + item[i] = data[i]; + }else{ + item[i] = [data[i]]; + } + } + + //Reset the item in the reference. + self._arrayOfAllItems[item[self._itemNumPropName]] = item; + + //Scan the new values in the item for extra stub items we need to + //add to the items array of the store so they can be lazy-loaded later... + var attributes = self.getAttributes(item); + for(i in attributes){ + var values = self.getValues(item, attributes[i]); + for (var j = 0; j < values.length; j++) { + var value = values[j]; + + if(typeof value === "object"){ + if(value["stub"] ){ + //We have a stub reference here, we need to create the stub item + var stub = { + type: ["stub"], + name: [value["stub"]], // + parent: [itemName] //The child stub item is parented by this item name... + }; + if (parent) { + //Add in any parents to your parent so URL construstruction is accurate. + stub.parent[0] = parent + "/" + stub.parent[0]; + } + //Finalize the addition of the new stub item into the ItemFileReadStore list. + self._arrayOfAllItems.push(stub); + stub[self._storeRefPropName] = self; + stub[self._itemNumPropName] = (self._arrayOfAllItems.length - 1); //Last one pushed in should be the item + values[j] = stub; //Set the stub item back in its place and replace the stub notation. + } + } + } + } + + //Done processing! Call the onItem, if any. + if(keywordArgs.onItem){ + var scope = keywordArgs.scope ? keywordArgs.scope : dojo.global; + keywordArgs.onItem.call(scope, item); + } + }; + + //Callback for any errors that occur during load. + var gotError = function(error){ + //Call the onComplete, if any + if(keywordArgs.onError){ + var scope = keywordArgs.scope ? keywordArgs.scope : dojo.global; + keywordArgs.onError.call(scope, error); + } + }; + + //Fire the get and pass the proper callbacks to the deferred. + var xhrArgs = { + url: dataUrl, + handleAs: "json-comment-optional" + }; + var d = dojo.xhrGet(xhrArgs); + d.addCallback(gotData); + d.addErrback(gotError); + } +}); + + +} diff --git a/includes/js/dojox/data/demos/widgets/FlickrView.js b/includes/js/dojox/data/demos/widgets/FlickrView.js new file mode 100644 index 0000000..cacb127 --- /dev/null +++ b/includes/js/dojox/data/demos/widgets/FlickrView.js @@ -0,0 +1,36 @@ +if(!dojo._hasResource["dojox.data.demos.widgets.FlickrView"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.demos.widgets.FlickrView"] = true; +dojo.provide("dojox.data.demos.widgets.FlickrView"); +dojo.require("dijit._Templated"); +dojo.require("dijit._Widget"); + +dojo.declare("dojox.data.demos.widgets.FlickrView", [dijit._Widget, dijit._Templated], { + //Simple demo widget for representing a view of a Flickr Item. + + templateString:"\n\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\n\t\n
\n\t\t\t\t\n\t\t\t\t\tTitle:\n\t\t\t\t\n\t\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\tAuthor:\n\t\t\t\t\n\t\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\tImage:\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\n", + + //Attach points for reference. + titleNode: null, + descriptionNode: null, + imageNode: null, + authorNode: null, + + title: "", + author: "", + imageUrl: "", + iconUrl: "", + + postCreate: function(){ + this.titleNode.appendChild(document.createTextNode(this.title)); + this.authorNode.appendChild(document.createTextNode(this.author)); + var href = document.createElement("a"); + href.setAttribute("href", this.imageUrl); + href.setAttribute("target", "_blank"); + var imageTag = document.createElement("img"); + imageTag.setAttribute("src", this.iconUrl); + href.appendChild(imageTag); + this.imageNode.appendChild(href); + } +}); + +} diff --git a/includes/js/dojox/data/demos/widgets/FlickrViewList.js b/includes/js/dojox/data/demos/widgets/FlickrViewList.js new file mode 100644 index 0000000..2c3c881 --- /dev/null +++ b/includes/js/dojox/data/demos/widgets/FlickrViewList.js @@ -0,0 +1,37 @@ +if(!dojo._hasResource["dojox.data.demos.widgets.FlickrViewList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.demos.widgets.FlickrViewList"] = true; +dojo.provide("dojox.data.demos.widgets.FlickrViewList"); +dojo.require("dijit._Templated"); +dojo.require("dijit._Widget"); +dojo.require("dojox.data.demos.widgets.FlickrView"); + +dojo.declare("dojox.data.demos.widgets.FlickrViewList", [dijit._Widget, dijit._Templated], { + //Simple demo widget that is just a list of FlickrView Widgets. + + templateString:"
\n\n", + + //Attach points for reference. + listNode: null, + + postCreate: function(){ + this.fViewWidgets = []; + }, + + clearList: function(){ + while(this.list.firstChild){ + this.list.removeChild(this.list.firstChild); + } + for(var i = 0; i < this.fViewWidgets.length; i++){ + this.fViewWidgets[i].destroy(); + } + this.fViewWidgets = []; + }, + + addView: function(viewData){ + var newView = new dojox.data.demos.widgets.FlickrView(viewData); + this.fViewWidgets.push(newView); + this.list.appendChild(newView.domNode); + } +}); + +} diff --git a/includes/js/dojox/data/demos/widgets/PicasaView.js b/includes/js/dojox/data/demos/widgets/PicasaView.js new file mode 100644 index 0000000..6b100ac --- /dev/null +++ b/includes/js/dojox/data/demos/widgets/PicasaView.js @@ -0,0 +1,37 @@ +if(!dojo._hasResource["dojox.data.demos.widgets.PicasaView"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.demos.widgets.PicasaView"] = true; +dojo.provide("dojox.data.demos.widgets.PicasaView"); +dojo.require("dijit._Templated"); +dojo.require("dijit._Widget"); + +dojo.declare("dojox.data.demos.widgets.PicasaView", [dijit._Widget, dijit._Templated], { + //Simple demo widget for representing a view of a Picasa Item. + + templateString:"\n\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\n\t\n
\n\t\t\t\t\n\t\t\t\t\tTitle:\n\t\t\t\t\n\t\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\tAuthor:\n\t\t\t\t\n\t\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\tSummary:\n\t\t\t\t\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\n", + + //Attach points for reference. + titleNode: null, + descriptionNode: null, + imageNode: null, + authorNode: null, + + title: "", + author: "", + imageUrl: "", + iconUrl: "", + + postCreate: function(){ + this.titleNode.appendChild(document.createTextNode(this.title)); + this.authorNode.appendChild(document.createTextNode(this.author)); + this.descriptionNode.appendChild(document.createTextNode(this.description)); + var href = document.createElement("a"); + href.setAttribute("href", this.imageUrl); + href.setAttribute("target", "_blank"); + var imageTag = document.createElement("img"); + imageTag.setAttribute("src", this.iconUrl); + href.appendChild(imageTag); + this.imageNode.appendChild(href); + } +}); + +} diff --git a/includes/js/dojox/data/demos/widgets/PicasaViewList.js b/includes/js/dojox/data/demos/widgets/PicasaViewList.js new file mode 100644 index 0000000..45371cd --- /dev/null +++ b/includes/js/dojox/data/demos/widgets/PicasaViewList.js @@ -0,0 +1,37 @@ +if(!dojo._hasResource["dojox.data.demos.widgets.PicasaViewList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.demos.widgets.PicasaViewList"] = true; +dojo.provide("dojox.data.demos.widgets.PicasaViewList"); +dojo.require("dijit._Templated"); +dojo.require("dijit._Widget"); +dojo.require("dojox.data.demos.widgets.PicasaView"); + +dojo.declare("dojox.data.demos.widgets.PicasaViewList", [dijit._Widget, dijit._Templated], { + //Simple demo widget that is just a list of PicasaView Widgets. + + templateString:"
\n\n", + + //Attach points for reference. + listNode: null, + + postCreate: function(){ + this.fViewWidgets = []; + }, + + clearList: function(){ + while(this.list.firstChild){ + this.list.removeChild(this.list.firstChild); + } + for(var i = 0; i < this.fViewWidgets.length; i++){ + this.fViewWidgets[i].destroy(); + } + this.fViewWidgets = []; + }, + + addView: function(viewData){ + var newView = new dojox.data.demos.widgets.PicasaView(viewData); + this.fViewWidgets.push(newView); + this.list.appendChild(newView.domNode); + } +}); + +} diff --git a/includes/js/dojox/data/demos/widgets/templates/FlickrView.html b/includes/js/dojox/data/demos/widgets/templates/FlickrView.html new file mode 100644 index 0000000..b9d3bf9 --- /dev/null +++ b/includes/js/dojox/data/demos/widgets/templates/FlickrView.html @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + +
+ + Title: + + +
+ + Author: + + +
+ + Image: + +
+
+ diff --git a/includes/js/dojox/data/demos/widgets/templates/FlickrViewList.html b/includes/js/dojox/data/demos/widgets/templates/FlickrViewList.html new file mode 100644 index 0000000..3a9f565 --- /dev/null +++ b/includes/js/dojox/data/demos/widgets/templates/FlickrViewList.html @@ -0,0 +1,2 @@ +
+ diff --git a/includes/js/dojox/data/demos/widgets/templates/PicasaView.html b/includes/js/dojox/data/demos/widgets/templates/PicasaView.html new file mode 100644 index 0000000..88dbb31 --- /dev/null +++ b/includes/js/dojox/data/demos/widgets/templates/PicasaView.html @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + +
+ + Title: + + +
+ + Author: + + +
+ + Summary: + + +
+
+ diff --git a/includes/js/dojox/data/demos/widgets/templates/PicasaViewList.html b/includes/js/dojox/data/demos/widgets/templates/PicasaViewList.html new file mode 100644 index 0000000..3a9f565 --- /dev/null +++ b/includes/js/dojox/data/demos/widgets/templates/PicasaViewList.html @@ -0,0 +1,2 @@ +
+ diff --git a/includes/js/dojox/data/dom.js b/includes/js/dojox/data/dom.js new file mode 100644 index 0000000..8911bc3 --- /dev/null +++ b/includes/js/dojox/data/dom.js @@ -0,0 +1,187 @@ +if(!dojo._hasResource["dojox.data.dom"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.dom"] = true; +dojo.provide("dojox.data.dom"); + +//DOM type to int value for reference. +//Ints make for more compact code than full constant names. +//ELEMENT_NODE = 1; +//ATTRIBUTE_NODE = 2; +//TEXT_NODE = 3; +//CDATA_SECTION_NODE = 4; +//ENTITY_REFERENCE_NODE = 5; +//ENTITY_NODE = 6; +//PROCESSING_INSTRUCTION_NODE = 7; +//COMMENT_NODE = 8; +//DOCUMENT_NODE = 9; +//DOCUMENT_TYPE_NODE = 10; +//DOCUMENT_FRAGMENT_NODE = 11; +//NOTATION_NODE = 12; + +//FIXME: Remove this file when possible. +//This file contains internal/helper APIs as holders until the true DOM apis of Dojo 0.9 are finalized. +//Therefore, these should not be generally used, they are present only for the use by XmlStore and the +//wires project until proper dojo replacements are available. When such exist, XmlStore and the like +//will be ported off these and this file will be deleted. +dojo.experimental("dojox.data.dom"); + +dojox.data.dom.createDocument = function(/*string?*/ str, /*string?*/ mimetype){ + // summary: + // cross-browser implementation of creating an XML document object. + // + // str: + // Optional text to create the document from. If not provided, an empty XML document will be created. + // mimetype: + // Optional mimetype of the text. Typically, this is text/xml. Will be defaulted to text/xml if not provided. + var _document = dojo.doc; + + if(!mimetype){ mimetype = "text/xml"; } + if(str && (typeof dojo.global["DOMParser"]) !== "undefined"){ + var parser = new DOMParser(); + return parser.parseFromString(str, mimetype); // DOMDocument + }else if((typeof dojo.global["ActiveXObject"]) !== "undefined"){ + var prefixes = [ "MSXML2", "Microsoft", "MSXML", "MSXML3" ]; + for(var i = 0; i1){ + var _document = node.ownerDocument || dojo.doc; //Preference is to get the node owning doc first or it may fail + dojox.data.dom.replaceChildren(node, _document.createTextNode(text)); + return text; // string + } else { + if(node.textContent !== undefined){ //FF 1.5 + return node.textContent; // string + } + var _result = ""; + if(node == null){ + return _result; //empty string. + } + for(var i = 0; i < node.childNodes.length; i++){ + switch(node.childNodes[i].nodeType){ + case 1: // ELEMENT_NODE + case 5: // ENTITY_REFERENCE_NODE + _result += dojox.data.dom.textContent(node.childNodes[i]); + break; + case 3: // TEXT_NODE + case 2: // ATTRIBUTE_NODE + case 4: // CDATA_SECTION_NODE + _result += node.childNodes[i].nodeValue; + break; + default: + break; + } + } + return _result; // string + } +} + +dojox.data.dom.replaceChildren = function(/*Element*/node, /*Node || array*/ newChildren){ + // summary: + // Removes all children of node and appends newChild. All the existing + // children will be destroyed. + // description: + // Removes all children of node and appends newChild. All the existing + // children will be destroyed. + // node: + // The node to modify the children on + // newChildren: + // The children to add to the node. It can either be a single Node or an + // array of Nodes. + var nodes = []; + + if(dojo.isIE){ + for(var i=0;i0){ + var req = this._fetchQueue.shift(); + this.fetch(req); + } + + }, + + setData: function(data){ + // summary: + // set the stores' data to the supplied object and then + // load and/or setup that data with the required meta info + this._loadData(data); + }, + + buildIndex: function(path, item){ + //summary: + // parse the object structure, and turn any objects into + // jsonPathStore items. Basically this just does a recursive + // series of fetches which itself already examines any items + // as they are retrieved and setups up the required meta information. + // + // path: /* string */ + // jsonPath Query for the starting point of this index construction. + + if (!this.idAttribute){ + throw new Error("buildIndex requires idAttribute for the store"); + } + + item = item || this._data; + var origPath = path; + path = path||"$"; + path += "[*]"; + var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE}); + for(var i=0; i= args.count)) { continue; } + + var item = results[i]["value"]; + var path = results[i]["path"]; + if (!dojo.isObject(item)){continue;} + if(this.metaRegex.exec(path)){continue;} + + //this automatically records the objects path + this._updateMeta(item,{path: results[i].path}); + + //if autoIdentity and no id, generate one and add it to the item + if(this.autoIdentity && !item[this.idAttribute]){ + var newId = this.autoIdPrefix + this._autoId++; + item[this.idAttribute]=newId; + item[this.metaLabel]["autoId"]=true; + } + + //add item to the item index if appropriate + if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item} + count++; + tmp.push(item); + } + results = tmp; + var scope = args.scope || dojo.global; + + if ("sort" in args){ + console.log("TODO::add support for sorting in the fetch"); + } + + if (args.mode==dojox.data.SYNC_MODE){ + return results; + }; + + if (args.onBegin){ + args["onBegin"].call(scope, results.length, args); + } + + if (args.onItem){ + for (var i=0; i0) { label+=" ";} + label += item[this.labelAttribute[i]]; + } + return label; + }else{ + return item[this.labelAttribute]; + } + } + return item.toString(); + }, + + getLabelAttributes: function(item){ + // summary: + // returns an array of attributes that are used to create the label of an item + item = this._correctReference(item); + return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute]; + }, + + sort: function(a,b){ + console.log("TODO::implement default sort algo"); + }, + + //Identity API Support + + getIdentity: function(item){ + // summary + // returns the identity of an item or throws + // a not found error. + + if (this.isItem(item)){ + return item[this.idAttribute]; + } + throw new Error("Id not found for item"); + }, + + getIdentityAttributes: function(item){ + // summary: + // returns the attributes which are used to make up the + // identity of an item. Basically returns this.idAttribute + + return [this.idAttribute]; + }, + + fetchItemByIdentity: function(args){ + // summary: + // fetch an item by its identity. This store also provides + // a much more finger friendly alias, 'byId' which does the + // same thing as this function. If provided a string + // this call will be treated as a SYNC request and will + // return the identified item immediatly. Alternatively it + // takes a object as a set of keywordArgs: + // + // identity: /* string */ + // the id of the item you want to retrieve + // + // mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE + // overrides the default store fetch mode + // + // onItem: /* function */ + // Result call back. Passed the fetched item. + // + // onError: /* function */ + // error callback. + var id; + if (dojo.isString(args)){ + id = args; + args = {identity: id, mode: dojox.data.SYNC_MODE} + }else{ + if (args){ + id = args["identity"]; + } + if (!args.mode){args.mode = this.mode} + } + + if (this.index && (this.index[id] || this.index["identity"])){ + + if (args.mode==dojox.data.SYNC_MODE){ + return this.index[id]; + } + + if (args.onItem){ + args["onItem"].call(args.scope || dojo.global, this.index[id], args); + } + + return args; + }else{ + if (args.mode==dojox.data.SYNC_MODE){ + return false; + } + } + + + if(args.onError){ + args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args); + } + + return args; + }, + + //Write API Support + newItem: function(data, options){ + // summary: + // adds a new item to the store at the specified point. + // Takes two parameters, data, and options. + // + // data: /* object */ + // The data to be added in as an item. This could be a + // new javascript object, or it could be an item that + // already exists in the store. If it already exists in the + // store, then this will be added as a reference. + // + // options: /* object */ + // + // item: /* item */ + // reference to an existing store item + // + // attribute: /* string */ + // attribute to add the item at. If this is + // not provided, the item's id will be used as the + // attribute name. If specified attribute is an + // array, the new item will be push()d on to the + // end of it. + // oldValue: /* old value of item[attribute] + // newValue: new value item[attribute] + + var meta={}; + + //default parent to the store root; + var pInfo ={item:this._data}; + + if (options){ + if (options.parent){ + options.item = options.parent; + } + + dojo.mixin(pInfo, options); + } + + if (this.idAttribute && !data[this.idAttribute]){ + if (this.requireId){throw new Error("requireId is enabled, new items must have an id defined to be added");} + if (this.autoIdentity){ + var newId = this.autoIdPrefix + this._autoId++; + data[this.idAttribute]=newId; + meta["autoId"]=true; + } + } + + if (!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){ + throw new Error("Adding a new item requires, at a minumum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute"); + } + + //pInfo.parent = this._correctReference(pInfo.parent); + //if there is no parent info supplied, default to the store root + //and add to the pInfo.attribute or if that doestn' exist create an + //attribute with the same name as the new items ID + if(!pInfo.attribute){pInfo.attribute = data[this.idAttribute]} + + pInfo.oldValue = this._trimItem(pInfo.item[pInfo.attribute]); + if (dojo.isArray(pInfo.item[pInfo.attribute])){ + this._setDirty(pInfo.item); + pInfo.item[pInfo.attribute].push(data); + }else{ + this._setDirty(pInfo.item); + pInfo.item[pInfo.attribute]=data; + } + + pInfo.newValue = pInfo.item[pInfo.attribute]; + + //add this item to the index + if(data[this.idAttribute]){this.index[data[this.idAttribute]]=data} + + this._updateMeta(data, meta) + + //keep track of all references in the store so we can delete them as necessary + this._addReference(data, pInfo); + + //mark this new item as dirty + this._setDirty(data); + + //Notification API + this.onNew(data, pInfo); + + //returns the original item, now decorated with some meta info + return data; + }, + + _addReference: function(item, pInfo){ + // summary + // adds meta information to an item containing a reference id + // so that references can be deleted as necessary, when passed + // only a string, the string for parent info, it will only + // it will be treated as a string reference + + //console.log("_addReference: ", item, pInfo); + var rid = '_ref_' + this._referenceId++; + if (!item[this.metaLabel]["referenceIds"]){ + item[this.metaLabel]["referenceIds"]=[]; + } + + item[this.metaLabel]["referenceIds"].push(rid); + this._references[rid] = pInfo; + }, + + deleteItem: function(item){ + // summary + // deletes item and any references to that item from the store. + // If the desire is to delete only one reference, unsetAttribute or + // setValue is the way to go. + + item = this._correctReference(item); + console.log("Item: ", item); + if (this.isItem(item)){ + while(item[this.metaLabel]["referenceIds"].length>0){ + console.log("refs map: " , this._references); + console.log("item to delete: ", item); + var rid = item[this.metaLabel]["referenceIds"].pop(); + var pInfo = this._references[rid]; + + console.log("deleteItem(): ", pInfo, pInfo.parent); + parentItem = pInfo.parent; + var attribute = pInfo.attribute; + if(parentItem && parentItem[attribute] && !dojo.isArray(parentItem[attribute])){ + this._setDirty(parentItem); + this.unsetAttribute(parentItem, attribute); + delete parentItem[attribute]; + } + + if (dojo.isArray(parentItem[attribute])){ + console.log("Parent is array"); + var oldValue = this._trimItem(parentItem[attribute]); + var found=false; + for (var i=0; i 0){ + var item = this._dirtyItems.pop()["item"]; + var t = this._trimItem(item); + var d; + switch(kwArgs.format){ + case "json": + d = dojo.toJson(t); + break; + case "raw": + default: + d = t; + } + data.push(d); + this._markClean(item); + } + + this.onSave(data); + }, + + _markClean: function(item){ + // summary + // remove this meta information marking an item as "dirty" + + if (item && item[this.metaLabel] && item[this.metaLabel]["isDirty"]){ + delete item[this.metaLabel]["isDirty"]; + } + }, + + revert: function(){ + // summary + // returns any modified data to its original state prior to a save(); + + while (this._dirtyItems.length>0){ + var d = this._dirtyItems.pop(); + this._mixin(d.item, d.old); + } + this.onRevert(); + }, + + _mixin: function(target, data){ + // summary: + // specialized mixin that hooks up objects in the store where references are identified. + + if (dojo.isObject(data)){ + if (dojo.isArray(data)){ + while(target.length>0){target.pop();} + for (var i=0; i + + + + + Query read store + + + + + + + +
+ This is a ComboBox: +


+ + This is a FilteringSelect: +
+
+ + +
+ +


+ + This ComboBox uses a customized QueryReadStore, it prepares the query-string for the URL that + way that the paging parameters "start" and "count" are also send.
+
+ +
+ Click here to see the code! + +

+ +
+ + +
+
+ requestMethod + get + post +
+ +
+ queryOptions + +
+ ignoreCase +
+ true + false +
+
+
+ deep +
+ true + false +
+
+
+
+ paging + start: + count: +

+ do client paging: +
+ + +

+ + +
+
+ + diff --git a/includes/js/dojox/data/tests/dom.js b/includes/js/dojox/data/tests/dom.js new file mode 100644 index 0000000..a6eb621 --- /dev/null +++ b/includes/js/dojox/data/tests/dom.js @@ -0,0 +1,133 @@ +if(!dojo._hasResource["dojox.data.tests.dom"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.dom"] = true; +dojo.provide("dojox.data.tests.dom"); +dojo.require("dojox.data.dom"); + +tests.register("dojox.data.tests.dom", + [ + function testCreateDocument(t){ + var document = dojox.data.dom.createDocument(); + t.assertTrue(document !== null); + }, + function testCreateDocumentFromText(t){ + var simpleXml = ""; + var document = dojox.data.dom.createDocument(simpleXml, "text/xml"); + + var parent = document.firstChild; + t.assertTrue(parent !== null); + t.assertTrue(parent.tagName === "parentNode"); + t.assertTrue(parent.childNodes.length == 2); + + var firstChild = parent.firstChild; + t.assertTrue(firstChild !== null); + t.assertTrue(firstChild.tagName === "childNode"); + t.assertTrue(firstChild.childNodes.length == 1); + + var secondChild = firstChild.nextSibling; + t.assertTrue(secondChild !== null); + t.assertTrue(secondChild.tagName === "childNode"); + + var grandChild = firstChild.firstChild; + t.assertTrue(grandChild !== null); + t.assertTrue(grandChild.tagName === "grandchildNode"); + + }, + function testReadTextContent(t){ + var text = "This is a bunch of child text on the node"; + var simpleXml = "" + text + ""; + var document = dojox.data.dom.createDocument(simpleXml, "text/xml"); + + var topNode = document.firstChild; + t.assertTrue(topNode !== null); + t.assertTrue(topNode.tagName === "parentNode"); + t.assertTrue(text === dojox.data.dom.textContent(topNode)); + dojo._destroyElement(topNode); + t.assertTrue(document.firstChild === null); + }, + function testSetTextContent(t){ + var text = "This is a bunch of child text on the node"; + var text2 = "This is the new text"; + var simpleXml = "" + text + ""; + var document = dojox.data.dom.createDocument(simpleXml, "text/xml"); + + var topNode = document.firstChild; + t.assertTrue(topNode !== null); + t.assertTrue(topNode.tagName === "parentNode"); + t.assertTrue(text === dojox.data.dom.textContent(topNode)); + dojox.data.dom.textContent(topNode, text2); + t.assertTrue(text2 === dojox.data.dom.textContent(topNode)); + dojo._destroyElement(topNode); + t.assertTrue(document.firstChild === null); + + }, + function testReplaceChildrenArray(t){ + var simpleXml1 = ""; + var simpleXml2 = ""; + var doc1 = dojox.data.dom.createDocument(simpleXml1, "text/xml"); + var doc2 = dojox.data.dom.createDocument(simpleXml2, "text/xml"); + + var topNode1 = doc1.firstChild; + var topNode2 = doc2.firstChild; + t.assertTrue(topNode1 !== null); + t.assertTrue(topNode1.tagName === "parentNode"); + t.assertTrue(topNode2 !== null); + t.assertTrue(topNode2.tagName === "parentNode"); + dojox.data.dom.removeChildren(topNode1); + var newChildren=[]; + for(var i=0;i + + + + HTML Div List for HtmlStore + + +
+
bold
+
italic
+
normal
+
+ + diff --git a/includes/js/dojox/data/tests/ml/orderedList.html b/includes/js/dojox/data/tests/ml/orderedList.html new file mode 100644 index 0000000..e995377 --- /dev/null +++ b/includes/js/dojox/data/tests/ml/orderedList.html @@ -0,0 +1,16 @@ + + + + + HTML Ordered List for HtmlStore + + +
    +
  1. Every
  2. +
  3. Good
  4. +
  5. Boy
  6. +
  7. Does
  8. +
  9. Fine
  10. +
+ + diff --git a/includes/js/dojox/data/tests/ml/table.html b/includes/js/dojox/data/tests/ml/table.html new file mode 100644 index 0000000..0c556d0 --- /dev/null +++ b/includes/js/dojox/data/tests/ml/table.html @@ -0,0 +1,46 @@ + + + + + HTML Ordered List for HtmlStore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XYAB
238
1357
4922777
32313535747
+ + diff --git a/includes/js/dojox/data/tests/ml/test_HtmlStore_declaratively.html b/includes/js/dojox/data/tests/ml/test_HtmlStore_declaratively.html new file mode 100644 index 0000000..ea36c8a --- /dev/null +++ b/includes/js/dojox/data/tests/ml/test_HtmlStore_declaratively.html @@ -0,0 +1,172 @@ + + + +Dojox HtmlDataStore Widget + + + + + + + + + +

Dojox HtmlDataStore Widget

+
+
+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XYAB
238
1357
4922777
32313535747
+ +
+
+
+ Table Rows:
(Just to show that the tree can determine that the tableStore works like a store).
Should have three branches, where the row had attr Y value of 3.
+
+
+ +
    +
  • Red
  • +
  • Orange
  • +
  • Yellow
  • +
  • Green
  • +
  • Blue
  • +
  • Violet
  • +
+ + + + +
+ Unordered List in Tree:
+
+
+ +
    +
  1. Every
  2. +
  3. Good
  4. +
  5. Boy
  6. +
  7. Does
  8. +
  9. Fine
  10. +
+ + + + +
+ Ordered List in Tree:
+
+
+ + +
+
bold
+
italic
+
normal
+
+ + + + +
+ Div list in tree:
+
+
+ + + diff --git a/includes/js/dojox/data/tests/ml/test_HtmlStore_remote.html b/includes/js/dojox/data/tests/ml/test_HtmlStore_remote.html new file mode 100644 index 0000000..f9d9eff --- /dev/null +++ b/includes/js/dojox/data/tests/ml/test_HtmlStore_remote.html @@ -0,0 +1,115 @@ + + + +Dojox HtmlDataStore Widget + + + + + + + + + +

Dojox HtmlDataStore Widget

+
+
+
+ + +
+
+
+
+ +
+ Table Rows:
(Just to show that the tree can determine that the tableStore works like a store).
Should have three branches, where the row had attr Y value of 3.
+
+
+ + + + +
+ Unordered List in Tree:
+
+
+ + + + +
+ Ordered List in Tree:
+
+
+ + +
+
bold
+
italic
+
normal
+
+ + + + +
+ Div list in tree:
+
+
+ + + diff --git a/includes/js/dojox/data/tests/ml/test_HtmlTableStore_declaratively.html b/includes/js/dojox/data/tests/ml/test_HtmlTableStore_declaratively.html new file mode 100644 index 0000000..f69ba68 --- /dev/null +++ b/includes/js/dojox/data/tests/ml/test_HtmlTableStore_declaratively.html @@ -0,0 +1,120 @@ + + + +Dojox HtmlDataStore Widget + + + + + + + + + +

Dojox HtmlDataStore Widget

+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XYAB
238
1357
4922777
32313535747
+ +
+
+
+ Table Rows:
(Just to show that the tree can determine that the tableStore works like a store).
Should have three branches, where the row had attr Y value of 3.
+
+
+ + diff --git a/includes/js/dojox/data/tests/ml/unorderedList.html b/includes/js/dojox/data/tests/ml/unorderedList.html new file mode 100644 index 0000000..a19149a --- /dev/null +++ b/includes/js/dojox/data/tests/ml/unorderedList.html @@ -0,0 +1,17 @@ + + + + + HTML Unorderd List for HtmlStore + + +
    +
  • Red
  • +
  • Orange
  • +
  • Yellow
  • +
  • Green
  • +
  • Blue
  • +
  • Violet
  • +
+ + diff --git a/includes/js/dojox/data/tests/module.js b/includes/js/dojox/data/tests/module.js new file mode 100644 index 0000000..8474eb4 --- /dev/null +++ b/includes/js/dojox/data/tests/module.js @@ -0,0 +1,30 @@ +if(!dojo._hasResource["dojox.data.tests.module"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.module"] = true; +dojo.provide("dojox.data.tests.module"); + +try{ + dojo.require("dojox.data.tests.stores.CsvStore"); + dojo.require("dojox.data.tests.stores.KeyValueStore"); + dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.HtmlTableStore"); + dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.HtmlStore"); + dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.OpmlStore"); + dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.XmlStore"); + dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.FlickrStore"); + dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.FlickrRestStore"); + dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.AtomReadStore"); + dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.jsonPathStore"); + //Load only if in a browser AND if the location is remote (not file. As it needs a PHP server to work). + if(dojo.isBrowser){ + if(window.location.protocol !== "file:"){ + dojo.require("dojox.data.tests.stores.QueryReadStore"); + dojo.require("dojox.data.tests.stores.SnapLogicStore"); + } + } + dojo.requireIf(dojo.isBrowser, "dojox.data.tests.dom"); +}catch(e){ + doh.debug(e); +} + + + +} diff --git a/includes/js/dojox/data/tests/runTests.html b/includes/js/dojox/data/tests/runTests.html new file mode 100644 index 0000000..49f065c --- /dev/null +++ b/includes/js/dojox/data/tests/runTests.html @@ -0,0 +1,9 @@ + + + + Dojox Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/data/tests/stores/AtomReadStore.js b/includes/js/dojox/data/tests/stores/AtomReadStore.js new file mode 100644 index 0000000..1df9493 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/AtomReadStore.js @@ -0,0 +1,641 @@ +if(!dojo._hasResource["dojox.data.tests.stores.AtomReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.stores.AtomReadStore"] = true; +dojo.provide("dojox.data.tests.stores.AtomReadStore"); +dojo.require("dojox.data.AtomReadStore"); +dojo.require("dojo.data.api.Read"); + +dojox.data.tests.stores.AtomReadStore.getBlog1Store = function(){ + return new dojox.data.AtomReadStore({url: dojo.moduleUrl("dojox.data.tests", "stores/atom1.xml").toString()}); + //return new dojox.data.AtomReadStore({url: "/sos/feeds/blog.php"}); +}; +/* +dojox.data.tests.stores.AtomReadStore.getBlog2Store = function(){ + return new dojox.data.AtomReadStore({url: dojo.moduleUrl("dojox.data.tests", "stores/atom2.xml").toString()}); +}; +*/ +dojox.data.tests.stores.AtomReadStore.error = function(t, d, errData){ + // summary: + // The error callback function to be used for all of the tests. + //console.log("In here."); + //console.trace(); + d.errback(errData); +} + +doh.register("dojox.data.tests.stores.AtomReadStore", + [ + { + name: "ReadAPI: Fetch_One", + timeout: 5000, //1 second + runTest: function(t) { + // summary: + // Simple test of a basic fetch on AtomReadStore of a single item. + // description: + // Simple test of a basic fetch on AtomReadStore of a single item. + + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.is(1, items.length); + d.callback(true); + } + atomStore.fetch({ + query: { + }, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, doh, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: Fetch_5_Streaming", + timeout: 5000, //1 second. + runTest: function(t) { + // summary: + // Simple test of a basic fetch on AtomReadStore. + // description: + // Simple test of a basic fetch on AtomReadStore. + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + var count = 0; + + function onItem(item, requestObj){ + t.assertTrue(atomStore.isItem(item)); + count++; + } + function onComplete(items, request){ + t.is(5, count); + + t.is(null, items); + d.callback(true); + } + //Get everything... + atomStore.fetch({ + query: { + }, + onBegin: null, + count: 5, + onItem: onItem, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: Fetch_Paging", + timeout: 5000, //1 second. + runTest: function(t) { + // summary: + // Test of multiple fetches on a single result. Paging, if you will. + // description: + // Test of multiple fetches on a single result. Paging, if you will. + + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + var d = new doh.Deferred(); + + function dumpFirstFetch(items, request){ + t.is(5, items.length); + request.start = 3; + request.count = 1; + request.onComplete = dumpSecondFetch; + atomStore.fetch(request); + } + + function dumpSecondFetch(items, request){ + console.log("dumpSecondFetch: got "+items.length); + t.is(1, items.length); + request.start = 0; + request.count = 5; + request.onComplete = dumpThirdFetch; + atomStore.fetch(request); + } + + function dumpThirdFetch(items, request){ + console.log("dumpThirdFetch: got "+items.length); + t.is(5, items.length); + request.start = 2; + request.count = 18; + request.onComplete = dumpFourthFetch; + atomStore.fetch(request); + } + + function dumpFourthFetch(items, request){ + console.log("dumpFourthFetch: got "+items.length); + t.is(18, items.length); + request.start = 5; + request.count = 11; + request.onComplete = dumpFifthFetch; + atomStore.fetch(request); + } + + function dumpFifthFetch(items, request){ + console.log("dumpFifthFetch: got "+items.length); + t.is(11, items.length); + request.start = 4; + request.count = 16; + request.onComplete = dumpSixthFetch; + atomStore.fetch(request); + } + + function dumpSixthFetch(items, request){ + console.log("dumpSixthFetch: got "+items.length); + t.is(16, items.length); + d.callback(true); + } + + function completed(items, request){ + t.is(7, items.length); + request.start = 1; + request.count = 5; + request.onComplete = dumpFirstFetch; + atomStore.fetch(request); + } + atomStore.fetch({ + query: { + }, + count: 7, + onComplete: completed, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: getLabel", + timeout: 5000, //1 second. + runTest: function(t) { + // summary: + // Simple test of the getLabel function against a store set that has a label defined. + // description: + // Simple test of the getLabel function against a store set that has a label defined. + + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var label = atomStore.getLabel(items[0]); + t.assertTrue(label !== null); + d.callback(true); + } + atomStore.fetch({ + query: { + }, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d) + }); + return d; + } + }, + { + name: "ReadAPI: getLabelAttributes", + timeout: 5000, //1 second + runTest: function(t) { + // summary: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + // description: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var labelList = atomStore.getLabelAttributes(items[0]); + t.assertTrue(dojo.isArray(labelList)); + t.assertEqual("title", labelList[0]); + d.callback(true); + } + atomStore.fetch({ + query: { + }, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d) + }); + return d; + + } + }, + { + name: "ReadAPI: getValue", + timeout: 5000, //1 second + runTest: function(t) { + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + function completedAll(items){ + t.is(1, items.length); + t.assertTrue(atomStore.getValue(items[0], "summary") !== null); + t.assertTrue(atomStore.getValue(items[0], "content") !== null); + t.assertTrue(atomStore.getValue(items[0], "published") !== null); + t.assertTrue(atomStore.getValue(items[0], "updated") !== null); + console.log("typeof updated = "+typeof(atomStore.getValue(items[0], "updated"))); + t.assertTrue(atomStore.getValue(items[0], "updated").getFullYear); + d.callback(true); + } + + //Get one item and look at it. + atomStore.fetch({ + query: { + }, + count: 1, + onComplete: completedAll, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d)}); + return d; //Object + } + }, + { + name: "ReadAPI: getValue_Failure", + timeout: 5000, //1 second + runTest: function(t) { + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + var passed = false; + try{ + var value = store.getValue("NotAnItem", foo); + }catch(e){ + passed = true; + } + t.assertTrue(passed); + } + }, + { + name: "ReadAPI: getValues", + timeout: 5000, //1 second + runTest: function(t) { + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + function completedAll(items){ + t.is(1, items.length); + var summary = atomStore.getValues(items[0], "summary"); + t.assertTrue(dojo.isArray(summary)); + + var content = atomStore.getValues(items[0], "content"); + t.assertTrue(dojo.isArray(content)); + + var published = atomStore.getValues(items[0], "published"); + t.assertTrue(dojo.isArray(published)); + + var updated = atomStore.getValues(items[0], "updated"); + t.assertTrue(dojo.isArray(updated)); + d.callback(true); + } + //Get one item and look at it. + atomStore.fetch({ + query: { + }, + count: 1, + onComplete: completedAll, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, + t, + d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: getValues_Failure", + timeout: 5000, //1 second + runTest: function(t) { + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + var passed = false; + try{ + var value = store.getValues("NotAnItem", foo); + }catch(e){ + passed = true; + } + t.assertTrue(passed); + } + }, + { + name: "ReadAPI: isItem", + timeout: 5000, //1 second + runTest: function(t) { + // summary: + // Simple test of the isItem function of the store + // description: + // Simple test of the isItem function of the store + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + function completedAll(items){ + t.is(5, items.length); + for(var i=0; i < items.length; i++){ + t.assertTrue(atomStore.isItem(items[i])); + } + d.callback(true); + } + + //Get everything... + atomStore.fetch({ + query: { + }, + count: 5, + onComplete: completedAll, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: hasAttribute", + timeout: 5000, //1 second + runTest: function(t) { + // summary: + // Simple test of the hasAttribute function of the store + // description: + // Simple test of the hasAttribute function of the store + + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + function onComplete(items){ + t.is(1, items.length); + t.assertTrue(items[0] !== null); + var count = 0; + console.log("hasAttribute"); + t.assertTrue(atomStore.hasAttribute(items[0], "author")); + t.assertTrue(atomStore.hasAttribute(items[0], "published")); + t.assertTrue(atomStore.hasAttribute(items[0], "updated")); + t.assertTrue(atomStore.hasAttribute(items[0], "category")); + t.assertTrue(atomStore.hasAttribute(items[0], "id")); + t.assertTrue(!atomStore.hasAttribute(items[0], "foo")); + t.assertTrue(!atomStore.hasAttribute(items[0], "bar")); + + + t.assertTrue(atomStore.hasAttribute(items[0], "summary")); + t.assertTrue(atomStore.hasAttribute(items[0], "content")); + t.assertTrue(atomStore.hasAttribute(items[0], "title")); + + + var summary = atomStore.getValue(items[0], "summary"); + var content = atomStore.getValue(items[0], "content"); + var title = atomStore.getValue(items[0], "title"); + + t.assertTrue(summary && summary.text && summary.type == "html"); + t.assertTrue(content && content.text && content.type == "html"); + t.assertTrue(title && title.text && title.type == "html"); + + //Test that null attributes throw an exception + try{ + atomStore.hasAttribute(items[0], null); + t.assertTrue(false); + }catch (e){ + + } + d.callback(true); + } + + //Get one item... + atomStore.fetch({ + query: { + }, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: containsValue", + timeout: 5000, //1 second + runTest: function(t) { + // summary: + // Simple test of the containsValue function of the store + // description: + // Simple test of the containsValue function of the store + + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + function onComplete(items){ + t.is(1, items.length); + + t.assertTrue(atomStore.containsValue(items[0], "id","http://shaneosullivan.wordpress.com/2008/01/22/using-aol-hosted-dojo-with-your-custom-code/")); + + d.callback(true); + } + + //Get one item... + atomStore.fetch({ + query: { + }, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: getAttributes", + timeout: 5000, //1 second + runTest: function(t) { + // summary: + // Simple test of the getAttributes function of the store + // description: + // Simple test of the getAttributes function of the store + + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + function onComplete(items){ + t.is(1, items.length); + t.assertTrue(atomStore.isItem(items[0])); + + var attributes = atomStore.getAttributes(items[0]); + console.log("getAttributes 4: "+attributes.length); + t.is(10, attributes.length); + d.callback(true); + } + + //Get everything... + atomStore.fetch({ + query: { + }, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: fetch_Category", + timeout: 5000, //1 second. + runTest: function(t) { + // summary: + // Retrieve items from the store by category + // description: + // Simple test of the getAttributes function of the store + + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + function onComplete(items){ + t.is(2, items.length); + t.assertTrue(atomStore.isItem(items[0])); + t.assertTrue(atomStore.isItem(items[1])); + + var categories = atomStore.getValues(items[0], "category"); + t.assertTrue(dojo.some(categories, function(category){ + return category.term == "aol"; + })); + categories = atomStore.getValues(items[1], "category"); + t.assertTrue(dojo.some(categories, function(category){ + return category.term == "aol"; + })); + + d.callback(true); + } + + //Get everything... + atomStore.fetch({ + query: { + category: "aol" + }, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: fetch_byID", + timeout: 5000, //1 second. + runTest: function(t) { + // summary: + // Retrieve items from the store by category + // description: + // Simple test of the getAttributes function of the store + + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + function onComplete(items){ + console.log("getById: items.length="+items.length) + t.is(1, items.length); + t.assertTrue(atomStore.isItem(items[0])); + + var title = atomStore.getValue(items[0], "title"); + console.log("getById: title.text="+title.text) + t.assertTrue(title.text == "Dojo Grid has landed"); + + d.callback(true); + } + + //Get everything... + atomStore.fetch({ + query: { + id: "http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed/" + }, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: fetch_alternate", + timeout: 5000, //1 second. + runTest: function(t) { + // summary: + // Retrieve items from the store by category + // description: + // Simple test of the getAttributes function of the store + + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var d = new doh.Deferred(); + function onComplete(items){ + t.is(1, items.length); + t.assertTrue(atomStore.isItem(items[0])); + + var alternate = atomStore.getValue(items[0], "alternate"); + t.assertEqual(alternate.href, "http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed/"); + + d.callback(true); + } + + //Get everything... + atomStore.fetch({ + query: { + id: "http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed/" + }, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.AtomReadStore.error, t, d) + }); + return d; //Object + } + }, + function testReadAPI_getFeatures(t){ + // summary: + // Simple test of the getFeatures function of the store + // description: + // Simple test of the getFeatures function of the store + + var atomStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + + var features = atomStore.getFeatures(); + var count = 0; + for(i in features){ + t.assertTrue((i === "dojo.data.api.Read")); + count++; + } + t.assertTrue(count === 1); + }, + function testReadAPI_functionConformance(t){ + // summary: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + + var testStore = dojox.data.tests.stores.AtomReadStore.getBlog1Store(); + var readApi = new dojo.data.api.Read(); + var passed = true; + + for(i in readApi){ + if(i.toString().charAt(0) !== '_') + { + var member = readApi[i]; + //Check that all the 'Read' defined functions exist on the test store. + if(typeof member === "function"){ + console.log("Looking at function: [" + i + "]"); + var testStoreMember = testStore[i]; + if(!(typeof testStoreMember === "function")){ + console.log("Problem with function: [" + i + "]. Got value: " + testStoreMember); + passed = false; + break; + } + } + } + } + t.assertTrue(passed); + } + ] +); + +} diff --git a/includes/js/dojox/data/tests/stores/CsvStore.js b/includes/js/dojox/data/tests/stores/CsvStore.js new file mode 100644 index 0000000..c1bad11 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/CsvStore.js @@ -0,0 +1,1127 @@ +if(!dojo._hasResource["dojox.data.tests.stores.CsvStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.stores.CsvStore"] = true; +dojo.provide("dojox.data.tests.stores.CsvStore"); +dojo.require("dojox.data.CsvStore"); +dojo.require("dojo.data.api.Read"); +dojo.require("dojo.data.api.Identity"); + +dojox.data.tests.stores.CsvStore.getDatasource = function(filepath){ + // summary: + // A simple helper function for getting the sample data used in each of the tests. + // description: + // A simple helper function for getting the sample data used in each of the tests. + + var dataSource = {}; + if(dojo.isBrowser){ + dataSource.url = dojo.moduleUrl("dojox.data.tests", filepath).toString(); + }else{ + // When running tests in Rhino, xhrGet is not available, + // so we have the file data in the code below. + switch(filepath){ + case "stores/movies.csv": + var csvData = ""; + csvData += "Title, Year, Producer\n"; + csvData += "City of God, 2002, Katia Lund\n"; + csvData += "Rain,, Christine Jeffs\n"; + csvData += "2001: A Space Odyssey, 1968, Stanley Kubrick\n"; + csvData += '"This is a ""fake"" movie title", 1957, Sidney Lumet\n'; + csvData += "Alien, 1979 , Ridley Scott\n"; + csvData += '"The Sequel to ""Dances With Wolves.""", 1982, Ridley Scott\n'; + csvData += '"Caine Mutiny, The", 1954, "Dymtryk ""the King"", Edward"\n'; + break; + case "stores/movies2.csv": + var csvData = ""; + csvData += "Title, Year, Producer\n"; + csvData += "City of God, 2002, Katia Lund\n"; + csvData += "Rain,\"\", Christine Jeffs\n"; + csvData += "2001: A Space Odyssey, 1968, Stanley Kubrick\n"; + csvData += '"This is a ""fake"" movie title", 1957, Sidney Lumet\n'; + csvData += "Alien, 1979 , Ridley Scott\n"; + csvData += '"The Sequel to ""Dances With Wolves.""", 1982, Ridley Scott\n'; + csvData += '"Caine Mutiny, The", 1954, "Dymtryk ""the King"", Edward"\n'; + break; + case "stores/books.csv": + var csvData = ""; + csvData += "Title, Author\n"; + csvData += "The Transparent Society, David Brin\n"; + csvData += "The First Measured Century, Theodore Caplow\n"; + csvData += "Maps in a Mirror, Orson Scott Card\n"; + csvData += "Princess Smartypants, Babette Cole\n"; + csvData += "Carfree Cities, Crawford J.H.\n"; + csvData += "Down and Out in the Magic Kingdom, Cory Doctorow\n"; + csvData += "Tax Shift, Alan Thein Durning\n"; + csvData += "The Sneetches and other stories, Dr. Seuss\n"; + csvData += "News from Tartary, Peter Fleming\n"; + break; + case "stores/patterns.csv": + var csvData = ""; + csvData += "uniqueId, value\n"; + csvData += "9, jfq4@#!$!@Rf14r14i5u\n"; + csvData += "6, BaBaMaSaRa***Foo\n"; + csvData += "2, bar*foo\n"; + csvData += "8, 123abc\n"; + csvData += "4, bit$Bite\n"; + csvData += "3, 123abc\n"; + csvData += "10, 123abcdefg\n"; + csvData += "1, foo*bar\n"; + csvData += "7, \n"; + csvData += "5, 123abc\n" + break; + } + dataSource.data = csvData; + } + return dataSource; //Object +} + +dojox.data.tests.stores.CsvStore.verifyItems = function(csvStore, items, attribute, compareArray){ + // summary: + // A helper function for validating that the items array is ordered + // the same as the compareArray + if(items.length != compareArray.length){ return false; } + for(var i = 0; i < items.length; i++){ + if(!(csvStore.getValue(items[i], attribute) === compareArray[i])){ + return false; //Boolean + } + } + return true; //Boolean +} + +dojox.data.tests.stores.CsvStore.error = function(t, d, errData){ + // summary: + // The error callback function to be used for all of the tests. + for (i in errData) { + console.log(errData[i]); + } + d.errback(errData); +} + +doh.register("dojox.data.tests.stores.CsvStore", + [ + function testReadAPI_fetch_all(t){ + // summary: + // Simple test of a basic fetch on CsvStore. + // description: + // Simple test of a basic fetch on CsvStore. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completedAll(items){ + t.assertTrue((items.length === 7)); + d.callback(true); + } + + //Get everything... + csvStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_all_withEmptyStringField(t){ + // summary: + // Simple test of a basic fetch on CsvStore. + // description: + // Simple test of a basic fetch on CsvStore. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies2.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completedAll(items){ + t.assertTrue((items.length === 7)); + d.callback(true); + } + + //Get everything... + csvStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_one(t){ + // summary: + // Simple test of a basic fetch on CsvStore of a single item. + // description: + // Simple test of a basic fetch on CsvStore of a single item. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.is(1, items.length); + d.callback(true); + } + csvStore.fetch({ query: {Title: "*Sequel*"}, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d) + }); + return d; //Object + }, + function testReadAPI_fetch_Multiple(t){ + // summary: + // Simple test of a basic fetch on CsvStore of a single item. + // description: + // Simple test of a basic fetch on CsvStore of a single item. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + + var done = [false, false]; + + function onCompleteOne(items, request){ + done[0] = true; + t.is(1, items.length); + if(done[0] && done[1]){ + d.callback(true); + } + } + + function onCompleteTwo(items, request){ + done[1] = true; + t.is(1, items.length); + if(done[0] && done[1]){ + d.callback(true); + } + } + + try + { + csvStore.fetch({ query: {Title: "*Sequel*"}, + onComplete: onCompleteOne, + onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d) + }); + csvStore.fetch({ query: {Title: "2001:*"}, + onComplete: onCompleteTwo, + onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d) + }); + } + catch(e) + { + for (i in e) { + console.log(e[i]); + } + } + + return d; //Object + }, + function testReadAPI_fetch_MultipleMixed(t){ + // summary: + // Simple test of a basic fetch on CsvStore of a single item. + // description: + // Simple test of a basic fetch on CsvStore of a single item. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + + var done = [false, false]; + function onComplete(items, request){ + done[0] = true; + t.is(1, items.length); + if(done[0] && done[1]){ + d.callback(true); + } + } + + function onItem(item){ + done[1] = true; + t.assertTrue(item !== null); + t.is('Dymtryk "the King", Edward', csvStore.getValue(item,"Producer")); + t.is('Caine Mutiny, The', csvStore.getValue(item,"Title")); + if(done[0] && done[1]){ + d.callback(true); + } + } + + csvStore.fetch({ query: {Title: "*Sequel*"}, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d) + }); + + csvStore.fetchItemByIdentity({identity: "6", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_all_streaming(t){ + // summary: + // Simple test of a basic fetch on CsvStore. + // description: + // Simple test of a basic fetch on CsvStore. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + count = 0; + + function onBegin(size, requestObj){ + t.assertTrue(size === 7); + } + function onItem(item, requestObj){ + t.assertTrue(csvStore.isItem(item)); + count++; + } + function onComplete(items, request){ + t.is(7, count); + t.is(null, items); + d.callback(true); + } + + //Get everything... + csvStore.fetch({ onBegin: onBegin, + onItem: onItem, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d) + }); + return d; //Object + }, + function testReadAPI_fetch_paging(t){ + // summary: + // Test of multiple fetches on a single result. Paging, if you will. + // description: + // Test of multiple fetches on a single result. Paging, if you will. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function dumpFirstFetch(items, request){ + t.is(5, items.length); + request.start = 3; + request.count = 1; + request.onComplete = dumpSecondFetch; + csvStore.fetch(request); + } + + function dumpSecondFetch(items, request){ + t.is(1, items.length); + request.start = 0; + request.count = 5; + request.onComplete = dumpThirdFetch; + csvStore.fetch(request); + } + + function dumpThirdFetch(items, request){ + t.is(5, items.length); + request.start = 2; + request.count = 20; + request.onComplete = dumpFourthFetch; + csvStore.fetch(request); + } + + function dumpFourthFetch(items, request){ + t.is(5, items.length); + request.start = 9; + request.count = 100; + request.onComplete = dumpFifthFetch; + csvStore.fetch(request); + } + + function dumpFifthFetch(items, request){ + t.is(0, items.length); + request.start = 2; + request.count = 20; + request.onComplete = dumpSixthFetch; + csvStore.fetch(request); + } + + function dumpSixthFetch(items, request){ + t.is(5, items.length); + d.callback(true); + } + + function completed(items, request){ + t.is(7, items.length); + request.start = 1; + request.count = 5; + request.onComplete = dumpFirstFetch; + csvStore.fetch(request); + } + + csvStore.fetch({onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + + }, + + function testReadAPI_getLabel(t){ + // summary: + // Simple test of the getLabel function against a store set that has a label defined. + // description: + // Simple test of the getLabel function against a store set that has a label defined. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + args.label = "Title"; + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var label = csvStore.getLabel(items[0]); + t.assertTrue(label !== null); + t.assertEqual("The Sequel to \"Dances With Wolves.\"", label); + d.callback(true); + } + csvStore.fetch({ query: {Title: "*Sequel*"}, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d) + }); + return d; + }, + function testReadAPI_getLabelAttributes(t){ + // summary: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + // description: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + args.label = "Title"; + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var labelList = csvStore.getLabelAttributes(items[0]); + t.assertTrue(dojo.isArray(labelList)); + t.assertEqual("Title", labelList[0]); + d.callback(true); + } + csvStore.fetch({ query: {Title: "*Sequel*"}, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d) + }); + return d; + }, + function testReadAPI_getValue(t){ + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(item !== null); + t.is('Dymtryk "the King", Edward', csvStore.getValue(item,"Producer")); + t.is('Caine Mutiny, The', csvStore.getValue(item,"Title")); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "6", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + function testReadAPI_getValue_2(t){ + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(item !== null); + t.is("City of God", csvStore.getValue(item,"Title")); + t.is("2002", csvStore.getValue(item,"Year")); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "0", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + function testReadAPI_getValue_3(t){ + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(item !== null); + t.is("1979", csvStore.getValue(item,"Year")); + t.is("Alien", csvStore.getValue(item,"Title")); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "4", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + function testReadAPI_getValue_4(t){ + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(item !== null); + t.is("2001: A Space Odyssey", csvStore.getValue(item,"Title")); + t.is("Stanley Kubrick", csvStore.getValue(item,"Producer")); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "2", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + + function testReadAPI_getValues(t){ + // summary: + // Simple test of the getValues function of the store. + // description: + // Simple test of the getValues function of the store. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(item !== null); + var names = csvStore.getValues(item,"Title"); + t.assertTrue(dojo.isArray(names)); + t.is(1, names.length); + t.is("Rain", names[0]); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + function testIdentityAPI_fetchItemByIdentity(t){ + // summary: + // Simple test of the fetchItemByIdentity function of the store. + // description: + // Simple test of the fetchItemByIdentity function of the store. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(item !== null); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + + function testIdentityAPI_fetchItemByIdentity_bad1(t){ + // summary: + // Simple test of the fetchItemByIdentity function of the store. + // description: + // Simple test of the fetchItemByIdentity function of the store. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(item === null); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "7", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + function testIdentityAPI_fetchItemByIdentity_bad2(t){ + // summary: + // Simple test of the fetchItemByIdentity function of the store. + // description: + // Simple test of the fetchItemByIdentity function of the store. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(item === null); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "-1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + function testIdentityAPI_fetchItemByIdentity_bad3(t){ + // summary: + // Simple test of the fetchItemByIdentity function of the store. + // description: + // Simple test of the fetchItemByIdentity function of the store. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(item === null); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "999999", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + function testIdentityAPI_getIdentity(t){ + // summary: + // Simple test of the fetchItemByIdentity function of the store. + // description: + // Simple test of the fetchItemByIdentity function of the store. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completed(items, request){ + t.is(7, items.length); + var passed = true; + for(var i = 0; i < items.length; i++){ + if(!(csvStore.getIdentity(items[i]) === i)){ + passed=false; + break; + } + } + t.assertTrue(passed); + d.callback(true); + } + + //Get everything... + csvStore.fetch({ onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testIdentityAPI_getIdentityAttributes(t){ + // summary: + // Simple test of the getIdentityAttributes + // description: + // Simple test of the fetchItemByIdentity function of the store. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(csvStore.isItem(item)); + t.assertEqual(null, csvStore.getIdentityAttributes(item)); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + function testReadAPI_isItem(t){ + // summary: + // Simple test of the isItem function of the store + // description: + // Simple test of the isItem function of the store + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(csvStore.isItem(item)); + t.assertTrue(!csvStore.isItem({})); + t.assertTrue(!csvStore.isItem({ item: "not an item" })); + t.assertTrue(!csvStore.isItem("not an item")); + t.assertTrue(!csvStore.isItem(["not an item"])); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + function testReadAPI_hasAttribute(t){ + // summary: + // Simple test of the hasAttribute function of the store + // description: + // Simple test of the hasAttribute function of the store + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(item !== null); + t.assertTrue(csvStore.hasAttribute(item, "Title")); + t.assertTrue(csvStore.hasAttribute(item, "Producer")); + t.assertTrue(!csvStore.hasAttribute(item, "Year")); + t.assertTrue(!csvStore.hasAttribute(item, "Nothing")); + t.assertTrue(!csvStore.hasAttribute(item, "title")); + + //Test that null attributes throw an exception + var passed = false; + try{ + csvStore.hasAttribute(item, null); + }catch (e){ + passed = true; + } + t.assertTrue(passed); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + function testReadAPI_containsValue(t){ + // summary: + // Simple test of the containsValue function of the store + // description: + // Simple test of the containsValue function of the store + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(item !== null); + t.assertTrue(csvStore.containsValue(item, "Title", "Alien")); + t.assertTrue(csvStore.containsValue(item, "Year", "1979")); + t.assertTrue(csvStore.containsValue(item, "Producer", "Ridley Scott")); + t.assertTrue(!csvStore.containsValue(item, "Title", "Alien2")); + t.assertTrue(!csvStore.containsValue(item, "Year", "1979 ")); + t.assertTrue(!csvStore.containsValue(item, "Title", null)); + + //Test that null attributes throw an exception + var passed = false; + try{ + csvStore.containsValue(item, null, "foo"); + }catch (e){ + passed = true; + } + t.assertTrue(passed); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "4", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + function testReadAPI_getAttributes(t){ + // summary: + // Simple test of the getAttributes function of the store + // description: + // Simple test of the getAttributes function of the store + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + t.assertTrue(item !== null); + t.assertTrue(csvStore.isItem(item)); + + var attributes = csvStore.getAttributes(item); + t.is(3, attributes.length); + for(var i = 0; i < attributes.length; i++){ + t.assertTrue((attributes[i] === "Title" || attributes[i] === "Year" || attributes[i] === "Producer")); + } + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "4", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + + function testReadAPI_getAttributes_onlyTwo(t){ + // summary: + // Simple test of the getAttributes function of the store + // description: + // Simple test of the getAttributes function of the store + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function onItem(item){ + // Test an item that does not have all of the attributes + t.assertTrue(item !== null); + t.assertTrue(csvStore.isItem(item)); + + var attributes = csvStore.getAttributes(item); + t.assertTrue(attributes.length === 2); + t.assertTrue(attributes[0] === "Title"); + t.assertTrue(attributes[1] === "Producer"); + d.callback(true); + } + csvStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; + }, + + function testReadAPI_getFeatures(t){ + // summary: + // Simple test of the getFeatures function of the store + // description: + // Simple test of the getFeatures function of the store + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var features = csvStore.getFeatures(); + var count = 0; + for(i in features){ + t.assertTrue((i === "dojo.data.api.Read" || i === "dojo.data.api.Identity")); + count++; + } + t.assertTrue(count === 2); + }, + function testReadAPI_fetch_patternMatch0(t){ + // summary: + // Function to test pattern matching of everything starting with lowercase e + // description: + // Function to test pattern matching of everything starting with lowercase e + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completed(items, request){ + t.is(2, items.length); + var valueArray = [ "Alien", "The Sequel to \"Dances With Wolves.\""]; + t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "Title", valueArray)); + d.callback(true); + } + + csvStore.fetch({query: {Producer: "* Scott"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_patternMatch1(t){ + // summary: + // Function to test pattern matching of everything with $ in it. + // description: + // Function to test pattern matching of everything with $ in it. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completed(items, request){ + t.assertTrue(items.length === 2); + var valueArray = [ "jfq4@#!$!@Rf14r14i5u", "bit$Bite"]; + t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "value", valueArray)); + d.callback(true); + } + + csvStore.fetch({query: {value: "*$*"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_patternMatch2(t){ + // summary: + // Function to test exact pattern match + // description: + // Function to test exact pattern match + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completed(items, request){ + t.is(1, items.length); + t.assertTrue(csvStore.getValue(items[0], "value") === "bar*foo"); + d.callback(true); + } + + csvStore.fetch({query: {value: "bar\*foo"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_patternMatch_caseInsensitive(t){ + // summary: + // Function to test exact pattern match with case insensitivity set. + // description: + // Function to test exact pattern match with case insensitivity set. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completed(items, request){ + t.is(1, items.length); + t.assertTrue(csvStore.getValue(items[0], "value") === "bar*foo"); + d.callback(true); + } + + csvStore.fetch({query: {value: "BAR\\*foo"}, queryOptions: {ignoreCase: true}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_patternMatch_caseSensitive(t){ + // summary: + // Function to test exact pattern match with case insensitivity set. + // description: + // Function to test exact pattern match with case insensitivity set. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completed(items, request){ + t.is(0, items.length); + d.callback(true); + } + + csvStore.fetch({query: {value: "BAR\\*foo"}, queryOptions: {ignoreCase: false}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_sortNumeric(t){ + // summary: + // Function to test sorting numerically. + // description: + // Function to test sorting numerically. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completed(items, request){ + t.assertTrue(items.length === 10); + // TODO: CsvStore treats everything like a string, so these numbers will be sorted lexicographically. + var orderedArray = [ "1", "10", "2", "3", "4", "5", "6", "7", "8", "9" ]; + t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "uniqueId", orderedArray)); + d.callback(true); + } + + var sortAttributes = [{attribute: "uniqueId"}]; + csvStore.fetch({onComplete: completed, + onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d), + sort: sortAttributes}); + return d; //Object + }, + function testReadAPI_fetch_sortNumericDescending(t){ + // summary: + // Function to test sorting numerically. + // description: + // Function to test sorting numerically. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completed(items, request){ + t.is(10, items.length); + // TODO: CsvStore treats everything like a string, so these numbers will be sorted lexicographically. + var orderedArray = [ "9", "8", "7", "6", "5", "4", "3", "2", "10", "1" ]; + t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "uniqueId", orderedArray)); + d.callback(true); + } + + var sortAttributes = [{attribute: "uniqueId", descending: true}]; + csvStore.fetch({ sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_sortNumericWithCount(t){ + // summary: + // Function to test sorting numerically in descending order, returning only a specified number of them. + // description: + // Function to test sorting numerically in descending order, returning only a specified number of them. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completed(items, request){ + t.is(5, items.length); + // TODO: CsvStore treats everything like a string, so these numbers will be sorted lexicographically. + var orderedArray = [ "9", "8", "7", "6", "5" ]; + t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "uniqueId", orderedArray)); + d.callback(true); + } + + var sortAttributes = [{attribute: "uniqueId", descending: true}]; + csvStore.fetch({sort: sortAttributes, + count: 5, + onComplete: completed, + onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_sortAlphabetic(t){ + // summary: + // Function to test sorting alphabetic ordering. + // description: + // Function to test sorting alphabetic ordering. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completed(items, request){ + //Output should be in this order... + var orderedArray = [ "123abc", + "123abc", + "123abc", + "123abcdefg", + "BaBaMaSaRa***Foo", + "bar*foo", + "bit$Bite", + "foo*bar", + "jfq4@#!$!@Rf14r14i5u", + undefined + ]; + t.is(10, items.length); + t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "value", orderedArray)); + d.callback(true); + } + + var sortAttributes = [{attribute: "value"}]; + csvStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_sortAlphabeticDescending(t){ + // summary: + // Function to test sorting alphabetic ordering in descending mode. + // description: + // Function to test sorting alphabetic ordering in descending mode. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completed(items, request){ + //Output should be in this order... + var orderedArray = [ undefined, + "jfq4@#!$!@Rf14r14i5u", + "foo*bar", + "bit$Bite", + "bar*foo", + "BaBaMaSaRa***Foo", + "123abcdefg", + "123abc", + "123abc", + "123abc" + ]; + t.is(10, items.length); + t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "value", orderedArray)); + d.callback(true); + } + + var sortAttributes = [{attribute: "value", descending: true}]; + csvStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_sortMultiple(t){ + // summary: + // Function to test sorting on multiple attributes. + // description: + // Function to test sorting on multiple attributes. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv"); + var csvStore = new dojox.data.CsvStore(args); + + var d = new doh.Deferred(); + function completed(items, request){ + var orderedArray0 = [ "8", "5", "3", "10", "6", "2", "4", "1", "9", "7" ]; + var orderedArray1 = [ "123abc", + "123abc", + "123abc", + "123abcdefg", + "BaBaMaSaRa***Foo", + "bar*foo", + "bit$Bite", + "foo*bar", + "jfq4@#!$!@Rf14r14i5u", + undefined + ]; + t.is(10, items.length); + t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "uniqueId", orderedArray0)); + t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "value", orderedArray1)); + d.callback(true); + } + + var sortAttributes = [{ attribute: "value"}, { attribute: "uniqueId", descending: true}]; + csvStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_sortMultipleSpecialComparator(t){ + // summary: + // Function to test sorting on multiple attributes with a custom comparator. + // description: + // Function to test sorting on multiple attributes with a custom comparator. + + var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"); + var csvStore = new dojox.data.CsvStore(args); + + csvStore.comparatorMap = {}; + csvStore.comparatorMap["Producer"] = function(a,b){ + var ret = 0; + // We want to sort authors alphabetical by their last name + function lastName(name){ + if(typeof name === "undefined"){ return undefined; } + + var matches = name.match(/\s*(\S+)$/); // Grab the last word in the string. + return matches ? matches[1] : name; // Strings with only whitespace will not match. + } + var lastNameA = lastName(a); + var lastNameB = lastName(b); + if(lastNameA > lastNameB || typeof lastNameA === "undefined"){ + ret = 1; + }else if(lastNameA < lastNameB || typeof lastNameB === "undefined"){ + ret = -1; + } + return ret; + }; + + var sortAttributes = [{attribute: "Producer", descending: true}, { attribute: "Title", descending: true}]; + + var d = new doh.Deferred(); + function completed(items, findResult){ + var orderedArray = [5,4,0,3,2,1,6]; + t.assertTrue(items.length === 7); + var passed = true; + for(var i = 0; i < items.length; i++){ + if(!(csvStore.getIdentity(items[i]) === orderedArray[i])){ + passed=false; + break; + } + } + t.assertTrue(passed); + d.callback(true); + } + + csvStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_functionConformance(t){ + // summary: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + + var testStore = new dojox.data.CsvStore(dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv")); + var readApi = new dojo.data.api.Read(); + var passed = true; + + for(i in readApi){ + if(i.toString().charAt(0) !== '_') + { + var member = readApi[i]; + //Check that all the 'Read' defined functions exist on the test store. + if(typeof member === "function"){ + console.log("Looking at function: [" + i + "]"); + var testStoreMember = testStore[i]; + if(!(typeof testStoreMember === "function")){ + console.log("Problem with function: [" + i + "]. Got value: " + testStoreMember); + passed = false; + break; + } + } + } + } + t.assertTrue(passed); + }, + function testIdentityAPI_functionConformance(t){ + // summary: + // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances. + + var testStore = new dojox.data.CsvStore(dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv")); + var identityApi = new dojo.data.api.Identity(); + var passed = true; + + for(i in identityApi){ + if(i.toString().charAt(0) !== '_') + { + var member = identityApi[i]; + //Check that all the 'Read' defined functions exist on the test store. + if(typeof member === "function"){ + console.log("Looking at function: [" + i + "]"); + var testStoreMember = testStore[i]; + if(!(typeof testStoreMember === "function")){ + passed = false; + break; + } + } + } + } + t.assertTrue(passed); + } + ] +); + + +} diff --git a/includes/js/dojox/data/tests/stores/FlickrRestStore.js b/includes/js/dojox/data/tests/stores/FlickrRestStore.js new file mode 100644 index 0000000..23320ec --- /dev/null +++ b/includes/js/dojox/data/tests/stores/FlickrRestStore.js @@ -0,0 +1,476 @@ +if(!dojo._hasResource["dojox.data.tests.stores.FlickrRestStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.stores.FlickrRestStore"] = true; +dojo.provide("dojox.data.tests.stores.FlickrRestStore"); +dojo.require("dojox.data.FlickrRestStore"); +dojo.require("dojo.data.api.Read"); + + +dojox.data.tests.stores.FlickrRestStore.error = function(t, d, errData){ + // summary: + // The error callback function to be used for all of the tests. + d.errback(errData); +} + +doh.register("dojox.data.tests.stores.FlickrRestStore", + [ + { + name: "ReadAPI: Fetch_One", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of a basic fetch on FlickrRestStore of a single item. + // description: + // Simple test of a basic fetch on FlickrRestStore of a single item. + + var flickrStore = new dojox.data.FlickrRestStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.is(1, items.length); + d.callback(true); + } + flickrStore.fetch({ + query: { + userid: "44153025@N00", + apikey: "8c6803164dbc395fb7131c9d54843627" + }, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, doh, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: Fetch_20_Streaming", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of a basic fetch on FlickrRestStore. + // description: + // Simple test of a basic fetch on FlickrRestStore. + var flickrStore = new dojox.data.FlickrRestStore(); + + var d = new doh.Deferred(); + var count = 0; + + function onItem(item, requestObj){ + t.assertTrue(flickrStore.isItem(item)); + count++; + } + function onComplete(items, request){ + t.is(5, count); + + t.is(null, items); + d.callback(true); + } + //Get everything... + flickrStore.fetch({ + query: { + userid: "44153025@N00", + apikey: "8c6803164dbc395fb7131c9d54843627" + }, + onBegin: null, + count: 5, + onItem: onItem, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: Fetch_Paging", + timeout: 30000, //30 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Test of multiple fetches on a single result. Paging, if you will. + // description: + // Test of multiple fetches on a single result. Paging, if you will. + + var flickrStore = new dojox.data.FlickrRestStore(); + + var d = new doh.Deferred(); + function dumpFirstFetch(items, request){ + t.is(5, items.length); + request.start = 3; + request.count = 1; + request.onComplete = dumpSecondFetch; + flickrStore.fetch(request); + } + + function dumpSecondFetch(items, request){ + t.is(1, items.length); + request.start = 0; + request.count = 5; + request.onComplete = dumpThirdFetch; + flickrStore.fetch(request); + } + + function dumpThirdFetch(items, request){ + t.is(5, items.length); + request.start = 2; + request.count = 18; + request.onComplete = dumpFourthFetch; + flickrStore.fetch(request); + } + + function dumpFourthFetch(items, request){ + t.is(18, items.length); + request.start = 9; + request.count = 11; + request.onComplete = dumpFifthFetch; + flickrStore.fetch(request); + } + + function dumpFifthFetch(items, request){ + t.is(11, items.length); + request.start = 4; + request.count = 16; + request.onComplete = dumpSixthFetch; + flickrStore.fetch(request); + } + + function dumpSixthFetch(items, request){ + t.is(16, items.length); + d.callback(true); + } + + function completed(items, request){ + t.is(7, items.length); + request.start = 1; + request.count = 5; + request.onComplete = dumpFirstFetch; + flickrStore.fetch(request); + } + flickrStore.fetch({ + query: { + userid: "44153025@N00", + apikey: "8c6803164dbc395fb7131c9d54843627" + }, + count: 7, + onComplete: completed, + onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: getLabel", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the getLabel function against a store set that has a label defined. + // description: + // Simple test of the getLabel function against a store set that has a label defined. + + var flickrStore = new dojox.data.FlickrRestStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var label = flickrStore.getLabel(items[0]); + t.assertTrue(label !== null); + d.callback(true); + } + flickrStore.fetch({ + query: { + userid: "44153025@N00", + apikey: "8c6803164dbc395fb7131c9d54843627" + }, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d) + }); + return d; + } + }, + { + name: "ReadAPI: getLabelAttributes", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + // description: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + + var flickrStore = new dojox.data.FlickrRestStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var labelList = flickrStore.getLabelAttributes(items[0]); + t.assertTrue(dojo.isArray(labelList)); + t.assertEqual("title", labelList[0]); + d.callback(true); + } + flickrStore.fetch({ + query: { + userid: "44153025@N00", + apikey: "8c6803164dbc395fb7131c9d54843627" + }, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d) + }); + return d; + } + }, + { + name: "ReadAPI: getValue", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + var flickrStore = new dojox.data.FlickrRestStore(); + + var d = new doh.Deferred(); + function completedAll(items){ + t.is(1, items.length); + t.assertTrue(flickrStore.getValue(items[0], "title") !== null); + t.assertTrue(flickrStore.getValue(items[0], "imageUrl") !== null); + t.assertTrue(flickrStore.getValue(items[0], "imageUrlSmall") !== null); + t.assertTrue(flickrStore.getValue(items[0], "imageUrlMedium") !== null); + d.callback(true); + } + + //Get one item and look at it. + flickrStore.fetch({ + query: { + userid: "44153025@N00", + apikey: "8c6803164dbc395fb7131c9d54843627" + }, + count: 1, + onComplete: completedAll, + onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d)}); + return d; //Object + } + }, + { + name: "ReadAPI: getValues", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + var flickrStore = new dojox.data.FlickrRestStore(); + + var d = new doh.Deferred(); + function completedAll(items){ + t.is(1, items.length); + var title = flickrStore.getValues(items[0], "title"); + t.assertTrue(title instanceof Array); + + var imgUrl = flickrStore.getValues(items[0], "imageUrl"); + t.assertTrue(imgUrl instanceof Array); + + var imgUrlSmall = flickrStore.getValues(items[0], "imageUrlSmall"); + t.assertTrue(imgUrlSmall instanceof Array); + + var imgUrlMedium = flickrStore.getValues(items[0], "imageUrlMedium"); + t.assertTrue(imgUrlMedium instanceof Array); + d.callback(true); + } + //Get one item and look at it. + flickrStore.fetch({ + query: { + userid: "44153025@N00", + apikey: "8c6803164dbc395fb7131c9d54843627" + }, + count: 1, + onComplete: completedAll, + onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, + t, + d)}); + return d; //Object + } + }, + { + name: "ReadAPI: isItem", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the isItem function of the store + // description: + // Simple test of the isItem function of the store + var flickrStore = new dojox.data.FlickrRestStore(); + + var d = new doh.Deferred(); + function completedAll(items){ + t.is(5, items.length); + for(var i=0; i < items.length; i++){ + t.assertTrue(flickrStore.isItem(items[i])); + } + d.callback(true); + } + + //Get everything... + flickrStore.fetch({ + query: { + userid: "44153025@N00", + apikey: "8c6803164dbc395fb7131c9d54843627" + }, + count: 5, + onComplete: completedAll, + onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: hasAttribute", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the hasAttribute function of the store + // description: + // Simple test of the hasAttribute function of the store + + var flickrStore = new dojox.data.FlickrRestStore(); + + var d = new doh.Deferred(); + function onComplete(items){ + t.is(1, items.length); + t.assertTrue(items[0] !== null); + t.assertTrue(flickrStore.hasAttribute(items[0], "title")); + t.assertTrue(flickrStore.hasAttribute(items[0], "author")); + t.assertTrue(!flickrStore.hasAttribute(items[0], "Nothing")); + t.assertTrue(!flickrStore.hasAttribute(items[0], "Text")); + + //Test that null attributes throw an exception + var passed = false; + try{ + flickrStore.hasAttribute(items[0], null); + }catch (e){ + passed = true; + } + t.assertTrue(passed); + d.callback(true); + } + + //Get one item... + flickrStore.fetch({ + query: { + userid: "44153025@N00", + apikey: "8c6803164dbc395fb7131c9d54843627" + }, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: containsValue", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the containsValue function of the store + // description: + // Simple test of the containsValue function of the store + + var flickrStore = new dojox.data.FlickrRestStore(); + + var d = new doh.Deferred(); + function onComplete(items){ + t.is(1, items.length); + d.callback(true); + } + + //Get one item... + flickrStore.fetch({ + query: { + userid: "44153025@N00", + apikey: "8c6803164dbc395fb7131c9d54843627" + }, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: getAttributes", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the getAttributes function of the store + // description: + // Simple test of the getAttributes function of the store + + var flickrStore = new dojox.data.FlickrRestStore(); + + var d = new doh.Deferred(); + function onComplete(items){ + t.is(1, items.length); + t.assertTrue(flickrStore.isItem(items[0])); + + var attributes = flickrStore.getAttributes(items[0]); + t.is(9, attributes.length); + d.callback(true); + } + + //Get everything... + flickrStore.fetch({ + query: { + userid: "44153025@N00", + apikey: "8c6803164dbc395fb7131c9d54843627" + }, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrRestStore.error, t, d) + }); + return d; //Object + } + }, + function testReadAPI_getFeatures(t){ + // summary: + // Simple test of the getFeatures function of the store + // description: + // Simple test of the getFeatures function of the store + + var flickrStore = new dojox.data.FlickrRestStore(); + + var features = flickrStore.getFeatures(); + var count = 0; + for(i in features){ + t.assertTrue((i === "dojo.data.api.Read")); + count++; + } + t.assertTrue(count === 1); + }, + function testReadAPI_functionConformance(t){ + // summary: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + + var testStore = new dojox.data.FlickrRestStore(); + var readApi = new dojo.data.api.Read(); + var passed = true; + + for(i in readApi){ + if(i.toString().charAt(0) !== '_') + { + var member = readApi[i]; + //Check that all the 'Read' defined functions exist on the test store. + if(typeof member === "function"){ + var testStoreMember = testStore[i]; + if(!(typeof testStoreMember === "function")){ + passed = false; + break; + } + } + } + } + } + ] +); + + +} diff --git a/includes/js/dojox/data/tests/stores/FlickrStore.js b/includes/js/dojox/data/tests/stores/FlickrStore.js new file mode 100644 index 0000000..3ed8c6c --- /dev/null +++ b/includes/js/dojox/data/tests/stores/FlickrStore.js @@ -0,0 +1,410 @@ +if(!dojo._hasResource["dojox.data.tests.stores.FlickrStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.stores.FlickrStore"] = true; +dojo.provide("dojox.data.tests.stores.FlickrStore"); +dojo.require("dojox.data.FlickrStore"); +dojo.require("dojo.data.api.Read"); + + +dojox.data.tests.stores.FlickrStore.error = function(t, d, errData){ + // summary: + // The error callback function to be used for all of the tests. + d.errback(errData); +} + +doh.register("dojox.data.tests.stores.FlickrStore", + [ + { + name: "ReadAPI: Fetch_One", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of a basic fetch on FlickrStore of a single item. + // description: + // Simple test of a basic fetch on FlickrStore of a single item. + + var flickrStore = new dojox.data.FlickrStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.is(1, items.length); + d.callback(true); + } + flickrStore.fetch({ query: {tags: "animals"}, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, doh, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: Fetch_20_Streaming", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of a basic fetch on FlickrStore. + // description: + // Simple test of a basic fetch on FlickrStore. + var flickrStore = new dojox.data.FlickrStore(); + + var d = new doh.Deferred(); + count = 0; + + function onBegin(size, requestObj){ + t.is(20, size); + } + function onItem(item, requestObj){ + t.assertTrue(flickrStore.isItem(item)); + count++; + } + function onComplete(items, request){ + t.is(20, count); + t.is(null, items); + d.callback(true); + } + + //Get everything... + flickrStore.fetch({ onBegin: onBegin, + count: 20, + onItem: onItem, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: Fetch_Paging", + timeout: 30000, //30 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Test of multiple fetches on a single result. Paging, if you will. + // description: + // Test of multiple fetches on a single result. Paging, if you will. + + var flickrStore = new dojox.data.FlickrStore(); + + var d = new doh.Deferred(); + function dumpFirstFetch(items, request){ + t.is(5, items.length); + request.start = 3; + request.count = 1; + request.onComplete = dumpSecondFetch; + flickrStore.fetch(request); + } + + function dumpSecondFetch(items, request){ + t.is(1, items.length); + request.start = 0; + request.count = 5; + request.onComplete = dumpThirdFetch; + flickrStore.fetch(request); + } + + function dumpThirdFetch(items, request){ + t.is(5, items.length); + request.start = 2; + request.count = 20; + request.onComplete = dumpFourthFetch; + flickrStore.fetch(request); + } + + function dumpFourthFetch(items, request){ + t.is(18, items.length); + request.start = 9; + request.count = 100; + request.onComplete = dumpFifthFetch; + flickrStore.fetch(request); + } + + function dumpFifthFetch(items, request){ + t.is(11, items.length); + request.start = 2; + request.count = 20; + request.onComplete = dumpSixthFetch; + flickrStore.fetch(request); + } + + function dumpSixthFetch(items, request){ + t.is(18, items.length); + d.callback(true); + } + + function completed(items, request){ + t.is(7, items.length); + request.start = 1; + request.count = 5; + request.onComplete = dumpFirstFetch; + flickrStore.fetch(request); + } + flickrStore.fetch({count: 7, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)}); + return d; //Object + } + }, + { + name: "ReadAPI: getLabel", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the getLabel function against a store set that has a label defined. + // description: + // Simple test of the getLabel function against a store set that has a label defined. + + var flickrStore = new dojox.data.FlickrStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var label = flickrStore.getLabel(items[0]); + t.assertTrue(label !== null); + d.callback(true); + } + flickrStore.fetch({ query: {tags: "animals"}, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d) + }); + return d; + } + }, + { + name: "ReadAPI: getLabelAttributes", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + // description: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + + var flickrStore = new dojox.data.FlickrStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var labelList = flickrStore.getLabelAttributes(items[0]); + t.assertTrue(dojo.isArray(labelList)); + t.assertEqual("title", labelList[0]); + d.callback(true); + } + flickrStore.fetch({ query: {tags: "animals"}, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d) + }); + return d; + } + }, + { + name: "ReadAPI: getValue", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + var flickrStore = new dojox.data.FlickrStore(); + + var d = new doh.Deferred(); + function completedAll(items){ + t.is(1, items.length); + t.assertTrue(flickrStore.getValue(items[0], "title") !== null); + t.assertTrue(flickrStore.getValue(items[0], "imageUrl") !== null); + t.assertTrue(flickrStore.getValue(items[0], "imageUrlSmall") !== null); + t.assertTrue(flickrStore.getValue(items[0], "imageUrlMedium") !== null); + d.callback(true); + } + + //Get one item and look at it. + flickrStore.fetch({ count: 1, onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)}); + return d; //Object + } + }, + { + name: "ReadAPI: getValues", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + var flickrStore = new dojox.data.FlickrStore(); + + var d = new doh.Deferred(); + function completedAll(items){ + t.is(1, items.length); + t.assertTrue(flickrStore.getValues(items[0], "title") instanceof Array); + t.assertTrue(flickrStore.getValues(items[0], "description") instanceof Array); + t.assertTrue(flickrStore.getValues(items[0], "imageUrl") instanceof Array); + t.assertTrue(flickrStore.getValues(items[0], "imageUrlSmall") instanceof Array); + t.assertTrue(flickrStore.getValues(items[0], "imageUrlMedium") instanceof Array); + d.callback(true); + } + //Get one item and look at it. + flickrStore.fetch({ count: 1, onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)}); + return d; //Object + } + }, + { + name: "ReadAPI: isItem", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the isItem function of the store + // description: + // Simple test of the isItem function of the store + var flickrStore = new dojox.data.FlickrStore(); + + var d = new doh.Deferred(); + function completedAll(items){ + t.is(5, items.length); + for(var i=0; i < items.length; i++){ + t.assertTrue(flickrStore.isItem(items[i])); + } + d.callback(true); + } + + //Get everything... + flickrStore.fetch({ count: 5, onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)}); + return d; //Object + } + }, + { + name: "ReadAPI: hasAttribute", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the hasAttribute function of the store + // description: + // Simple test of the hasAttribute function of the store + + var flickrStore = new dojox.data.FlickrStore(); + + var d = new doh.Deferred(); + function onComplete(items){ + t.is(1, items.length); + t.assertTrue(items[0] !== null); + t.assertTrue(flickrStore.hasAttribute(items[0], "title")); + t.assertTrue(flickrStore.hasAttribute(items[0], "description")); + t.assertTrue(flickrStore.hasAttribute(items[0], "author")); + t.assertTrue(!flickrStore.hasAttribute(items[0], "Nothing")); + t.assertTrue(!flickrStore.hasAttribute(items[0], "Text")); + + //Test that null attributes throw an exception + var passed = false; + try{ + flickrStore.hasAttribute(items[0], null); + }catch (e){ + passed = true; + } + t.assertTrue(passed); + d.callback(true); + } + + //Get one item... + flickrStore.fetch({ query: {tags: "animals"}, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: containsValue", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the containsValue function of the store + // description: + // Simple test of the containsValue function of the store + + var flickrStore = new dojox.data.FlickrStore(); + + var d = new doh.Deferred(); + function onComplete(items){ + t.is(1, items.length); + d.callback(true); + } + + //Get one item... + flickrStore.fetch({ query: {tags: "animals"}, + count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: getAttributes", + timeout: 10000, //10 seconds. Flickr can sometimes be slow. + runTest: function(t) { + // summary: + // Simple test of the getAttributes function of the store + // description: + // Simple test of the getAttributes function of the store + + var flickrStore = new dojox.data.FlickrStore(); + + var d = new doh.Deferred(); + function onComplete(items){ + t.is(1, items.length); + t.assertTrue(flickrStore.isItem(items[0])); + + var attributes = flickrStore.getAttributes(items[0]); + t.is(10, attributes.length); + d.callback(true); + } + + //Get everything... + flickrStore.fetch({ count: 1, onComplete: onComplete, onError: dojo.partial(dojox.data.tests.stores.FlickrStore.error, t, d)}); + return d; //Object + } + }, + function testReadAPI_getFeatures(t){ + // summary: + // Simple test of the getFeatures function of the store + // description: + // Simple test of the getFeatures function of the store + + var flickrStore = new dojox.data.FlickrStore(); + + var features = flickrStore.getFeatures(); + var count = 0; + for(i in features){ + t.assertTrue((i === "dojo.data.api.Read")); + count++; + } + t.assertTrue(count === 1); + }, + function testReadAPI_functionConformance(t){ + // summary: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + + var testStore = new dojox.data.FlickrStore(); + var readApi = new dojo.data.api.Read(); + var passed = true; + + for(i in readApi){ + if(i.toString().charAt(0) !== '_') + { + var member = readApi[i]; + //Check that all the 'Read' defined functions exist on the test store. + if(typeof member === "function"){ + var testStoreMember = testStore[i]; + if(!(typeof testStoreMember === "function")){ + passed = false; + break; + } + } + } + } + t.assertTrue(passed); + } + ] +); + + +} diff --git a/includes/js/dojox/data/tests/stores/HtmlStore.js b/includes/js/dojox/data/tests/stores/HtmlStore.js new file mode 100644 index 0000000..648dd06 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/HtmlStore.js @@ -0,0 +1,804 @@ +if(!dojo._hasResource["dojox.data.tests.stores.HtmlStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.stores.HtmlStore"] = true; +dojo.provide("dojox.data.tests.stores.HtmlStore"); +dojo.require("dojox.data.HtmlStore"); +dojo.require("dojo.data.api.Read"); +dojo.require("dojo.data.api.Identity"); + + +dojox.data.tests.stores.HtmlStore.getBooks3Store = function(){ + return new dojox.data.HtmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books3.html").toString(), dataId: "books3"}); +}; + +dojox.data.tests.stores.HtmlStore.getBooks2Store = function(){ + return new dojox.data.HtmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books2.html").toString(), dataId: "books2"}); +}; + +dojox.data.tests.stores.HtmlStore.getBooksStore = function(){ + return new dojox.data.HtmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books.html").toString(), dataId: "books"}); +}; + +doh.register("dojox.data.tests.stores.HtmlStore", + [ +/*************************************** + dojo.data.api.Read API +***************************************/ + function testReadAPI_fetch_all_table(t){ + // summary: + // Simple test of fetching all xml items through an XML element called isbn + // description: + // Simple test of fetching all xml items through an XML element called isbn + var store = dojox.data.tests.stores.HtmlStore.getBooksStore(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(20, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"*"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_all_list(t){ + // summary: + // Simple test of fetching all xml items through an XML element called isbn + // description: + // Simple test of fetching all xml items through an XML element called isbn + var store = dojox.data.tests.stores.HtmlStore.getBooks3Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(5, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{name:"*"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_one_table(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn + // description: + // Simple test of fetching one xml items through an XML element called isbn + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_one_list(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn + // description: + // Simple test of fetching one xml items through an XML element called isbn + var store = dojox.data.tests.stores.HtmlStore.getBooks3Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{name:"A9B57C - Title of 1 - Author of 1"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_paging(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn + // description: + // Simple test of fetching one xml items through an XML element called isbn + var store = dojox.data.tests.stores.HtmlStore.getBooksStore(); + + var d = new doh.Deferred(); + function dumpFirstFetch(items, request){ + t.assertEqual(5, items.length); + request.start = 3; + request.count = 1; + request.onComplete = dumpSecondFetch; + store.fetch(request); + } + + function dumpSecondFetch(items, request){ + t.assertEqual(1, items.length); + request.start = 0; + request.count = 5; + request.onComplete = dumpThirdFetch; + store.fetch(request); + } + + function dumpThirdFetch(items, request){ + t.assertEqual(5, items.length); + request.start = 2; + request.count = 20; + request.onComplete = dumpFourthFetch; + store.fetch(request); + } + + function dumpFourthFetch(items, request){ + t.assertEqual(18, items.length); + request.start = 9; + request.count = 100; + request.onComplete = dumpFifthFetch; + store.fetch(request); + } + + function dumpFifthFetch(items, request){ + t.assertEqual(11, items.length); + request.start = 2; + request.count = 20; + request.onComplete = dumpSixthFetch; + store.fetch(request); + } + + function dumpSixthFetch(items, request){ + t.assertEqual(18, items.length); + d.callback(true); + } + + function completed(items, request){ + t.assertEqual(20, items.length); + request.start = 1; + request.count = 5; + request.onComplete = dumpFirstFetch; + store.fetch(request); + } + + function error(errData, request){ + d.errback(errData); + } + + store.fetch({onComplete: completed, onError: error}); + return d; //Object + }, + function testReadAPI_fetch_pattern0(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + // description: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"?9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_pattern1(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + // description: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(4, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B57?"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_pattern2(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with * pattern match + // description: + // Simple test of fetching one xml items through an XML element called isbn with * pattern match + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(5, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9*"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_pattern_caseInsensitive(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case insensitive mode. + // description: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case insensitive mode. + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"?9b574"}, queryOptions: {ignoreCase: true}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_pattern_caseSensitive(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case sensitive mode. + // description: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case sensitive mode. + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"?9B574"}, queryOptions: {ignoreCase: false}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_getLabel_table(t){ + // summary: + // Simple test of the getLabel function against a store set that has a label defined. + // description: + // Simple test of the getLabel function against a store set that has a label defined. + + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var label = store.getLabel(items[0]); + t.assertTrue(label !== null); + t.assertEqual("Item #4", label); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; + }, + function testReadAPI_getLabel_list(t){ + // summary: + // Simple test of the getLabel function against a store set that has a label defined. + // description: + // Simple test of the getLabel function against a store set that has a label defined. + + var store = dojox.data.tests.stores.HtmlStore.getBooks3Store(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var label = store.getLabel(items[0]); + t.assertTrue(label !== null); + t.assertEqual("A9B57C - Title of 1 - Author of 1", label); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{name:"A9B57C - Title of 1 - Author of 1"}, onComplete: onComplete, onError: onError}); + return d; + }, + function testReadAPI_getLabelAttributes(t){ + // summary: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + // description: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var labelList = store.getLabelAttributes(items[0]); + t.assertTrue(labelList === null); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; + }, + + function testReadAPI_getValue(t){ + // summary: + // Simple test of the getValue API + // description: + // Simple test of the getValue API + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.hasAttribute(item,"isbn")); + t.assertEqual(store.getValue(item,"isbn"), "A9B574"); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_getValues(t){ + // summary: + // Simple test of the getValues API + // description: + // Simple test of the getValues API + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.hasAttribute(item,"isbn")); + var values = store.getValues(item,"isbn"); + t.assertEqual(1,values.length); + t.assertEqual("A9B574", values[0]); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_isItem(t){ + // summary: + // Simple test of the isItem API + // description: + // Simple test of the isItem API + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.isItem(item)); + t.assertTrue(!store.isItem({})); + t.assertTrue(!store.isItem("Foo")); + t.assertTrue(!store.isItem(1)); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_isItem_multistore(t){ + // summary: + // Simple test of the isItem API across multiple store instances. + // description: + // Simple test of the isItem API across multiple store instances. + var store1 = dojox.data.tests.stores.HtmlStore.getBooksStore(); + var store2 = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete1(items, request) { + t.assertEqual(1, items.length); + var item1 = items[0]; + t.assertTrue(store1.isItem(item1)); + + function onComplete2(items, request) { + t.assertEqual(1, items.length); + var item2 = items[0]; + t.assertTrue(store2.isItem(item2)); + t.assertTrue(!store1.isItem(item2)); + t.assertTrue(!store2.isItem(item1)); + d.callback(true); + } + store2.fetch({query:{isbn:"A9B574"}, onComplete: onComplete2, onError: onError}); + } + function onError(error, request) { + d.errback(error); + } + store1.fetch({query:{isbn:"1"}, onComplete: onComplete1, onError: onError}); + return d; //Object + }, + function testReadAPI_hasAttribute(t){ + // summary: + // Simple test of the hasAttribute API + // description: + // Simple test of the hasAttribute API + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.hasAttribute(item,"isbn")); + t.assertTrue(!store.hasAttribute(item,"bob")); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_containsValue(t){ + // summary: + // Simple test of the containsValue API + // description: + // Simple test of the containsValue API + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.containsValue(item,"isbn", "A9B574")); + t.assertTrue(!store.containsValue(item,"isbn", "bob")); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_sortDescending(t){ + // summary: + // Simple test of the sorting API in descending order. + // description: + // Simple test of the sorting API in descending order. + var store = dojox.data.tests.stores.HtmlStore.getBooksStore(); + + //Comparison is done as a string type (toString comparison), so the order won't be numeric + //So have to compare in 'alphabetic' order. + var order = [9,8,7,6,5,4,3,20,2,19,18,17,16,15,14,13,12,11,10,1]; + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(20, items.length); + + for(var i = 0; i < items.length; i++){ + t.assertEqual(order[i], store.getValue(items[i],"isbn").toString()); + } + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + + var sortAttributes = [{attribute: "isbn", descending: true}]; + store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_sortAscending(t){ + // summary: + // Simple test of the sorting API in ascending order. + // description: + // Simple test of the sorting API in ascending order. + var store = dojox.data.tests.stores.HtmlStore.getBooksStore(); + + //Comparison is done as a string type (toString comparison), so the order won't be numeric + //So have to compare in 'alphabetic' order. + var order = [1,10,11,12,13,14,15,16,17,18,19,2,20,3,4,5,6,7,8,9]; + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(20, items.length); + var itemId = 1; + for(var i = 0; i < items.length; i++){ + t.assertEqual(order[i], store.getValue(items[i],"isbn").toString()); + } + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + + var sortAttributes = [{attribute: "isbn"}]; + store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_sortDescendingNumeric(t){ + // summary: + // Simple test of the sorting API in descending order using a numeric comparator. + // description: + // Simple test of the sorting API in descending order using a numeric comparator. + var store = dojox.data.tests.stores.HtmlStore.getBooksStore(); + + //isbn should be treated as a numeric, not as a string comparison + store.comparatorMap = {}; + store.comparatorMap["isbn"] = function(a, b){ + var ret = 0; + if(parseInt(a.toString()) > parseInt(b.toString())){ + ret = 1; + }else if(parseInt(a.toString()) < parseInt(b.toString())){ + ret = -1; + } + return ret; //int, {-1,0,1} + }; + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(20, items.length); + var itemId = 20; + for(var i = 0; i < items.length; i++){ + t.assertEqual(itemId, store.getValue(items[i],"isbn").toString()); + itemId--; + } + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + + var sortAttributes = [{attribute: "isbn", descending: true}]; + store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_sortAscendingNumeric(t){ + // summary: + // Simple test of the sorting API in ascending order using a numeric comparator. + // description: + // Simple test of the sorting API in ascending order using a numeric comparator. + var store = dojox.data.tests.stores.HtmlStore.getBooksStore(); + + //isbn should be treated as a numeric, not as a string comparison + store.comparatorMap = {}; + store.comparatorMap["isbn"] = function(a, b){ + var ret = 0; + if(parseInt(a.toString()) > parseInt(b.toString())){ + ret = 1; + }else if(parseInt(a.toString()) < parseInt(b.toString())){ + ret = -1; + } + return ret; //int, {-1,0,1} + }; + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(20, items.length); + var itemId = 1; + for(var i = 0; i < items.length; i++){ + t.assertEqual(itemId, store.getValue(items[i],"isbn").toString()); + itemId++; + } + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + + var sortAttributes = [{attribute: "isbn"}]; + store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_isItemLoaded(t){ + // summary: + // Simple test of the isItemLoaded API + // description: + // Simple test of the isItemLoaded API + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.isItemLoaded(item)); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_getFeatures(t){ + // summary: + // Simple test of the getFeatures function of the store + // description: + // Simple test of the getFeatures function of the store + + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + var features = store.getFeatures(); + var count = 0; + for(i in features){ + t.assertTrue((i === "dojo.data.api.Read" || i === "dojo.data.api.Identity")); + count++; + } + t.assertEqual(2, count); + }, + function testReadAPI_getAttributes(t){ + // summary: + // Simple test of the getAttributes API + // description: + // Simple test of the getAttributes API + var store = dojox.data.tests.stores.HtmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + var attributes = store.getAttributes(item); + t.assertEqual(3,attributes.length); + for(var i=0; i parseInt(b.toString())){ + ret = 1; + }else if(parseInt(a.toString()) < parseInt(b.toString())){ + ret = -1; + } + return ret; //int, {-1,0,1} + }; + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(20, items.length); + var itemId = 20; + for(var i = 0; i < items.length; i++){ + t.assertEqual(itemId, store.getValue(items[i],"isbn").toString()); + itemId--; + } + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + + var sortAttributes = [{attribute: "isbn", descending: true}]; + store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_sortAscendingNumeric(t){ + // summary: + // Simple test of the sorting API in ascending order using a numeric comparator. + // description: + // Simple test of the sorting API in ascending order using a numeric comparator. + var store = dojox.data.tests.stores.HtmlTableStore.getBooksStore(); + + //isbn should be treated as a numeric, not as a string comparison + store.comparatorMap = {}; + store.comparatorMap["isbn"] = function(a, b){ + var ret = 0; + if(parseInt(a.toString()) > parseInt(b.toString())){ + ret = 1; + }else if(parseInt(a.toString()) < parseInt(b.toString())){ + ret = -1; + } + return ret; //int, {-1,0,1} + }; + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(20, items.length); + var itemId = 1; + for(var i = 0; i < items.length; i++){ + t.assertEqual(itemId, store.getValue(items[i],"isbn").toString()); + itemId++; + } + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + + var sortAttributes = [{attribute: "isbn"}]; + store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_isItemLoaded(t){ + // summary: + // Simple test of the isItemLoaded API + // description: + // Simple test of the isItemLoaded API + var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.isItemLoaded(item)); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_getFeatures(t){ + // summary: + // Simple test of the getFeatures function of the store + // description: + // Simple test of the getFeatures function of the store + + var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store(); + var features = store.getFeatures(); + var count = 0; + for(i in features){ + t.assertTrue((i === "dojo.data.api.Read" || i === "dojo.data.api.Identity")); + count++; + } + t.assertEqual(2, count); + }, + function testReadAPI_getAttributes(t){ + // summary: + // Simple test of the getAttributes API + // description: + // Simple test of the getAttributes API + var store = dojox.data.tests.stores.HtmlTableStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + var attributes = store.getAttributes(item); + t.assertEqual(3,attributes.length); + for(var i=0; i lastCharB || typeof lastCharA === "undefined"){ + ret = 1; + }else if(lastCharA < lastCharB || typeof lastCharB === "undefined"){ + ret = -1; + } + return ret; + }; + + var sortAttributes = [{attribute: "key", descending: true}, { attribute: "value", descending: true}]; + + var d = new doh.Deferred(); + function completed(items, findResult){ + var orderedArray = [5,4,0,3,2,1,6]; + var orderedArray = [ "day", "nday", "weekOfYear", "dayOfYear", "year", "month", "nmonth" ]; + t.assertTrue(items.length === 7); + var passed = true; + for(var i = 0; i < items.length; i++){ + if(!(keyStore.getIdentity(items[i]) === orderedArray[i])){ + passed=false; + break; + } + } + t.assertTrue(passed); + d.callback(true); + } + + keyStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.KeyValueStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_functionConformance(t){ + // summary: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + + var testStore = new dojox.data.KeyValueStore(dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv")); + var readApi = new dojo.data.api.Read(); + var passed = true; + + for(i in readApi){ + if(i.toString().charAt(0) !== '_') + { + var member = readApi[i]; + //Check that all the 'Read' defined functions exist on the test store. + if(typeof member === "function"){ + console.log("Looking at function: [" + i + "]"); + var testStoreMember = testStore[i]; + if(!(typeof testStoreMember === "function")){ + console.log("Problem with function: [" + i + "]. Got value: " + testStoreMember); + passed = false; + break; + } + } + } + } + t.assertTrue(passed); + }, + function testIdentityAPI_functionConformance(t){ + // summary: + // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test identity API conformance. Checks to see all declared functions are actual functions on the instances. + + var testStore = new dojox.data.KeyValueStore(dojox.data.tests.stores.KeyValueStore.getDatasource("stores/movies.csv")); + var identityApi = new dojo.data.api.Identity(); + var passed = true; + + for(i in identityApi){ + if(i.toString().charAt(0) !== '_') + { + var member = identityApi[i]; + //Check that all the 'Read' defined functions exist on the test store. + if(typeof member === "function"){ + console.log("Looking at function: [" + i + "]"); + var testStoreMember = testStore[i]; + if(!(typeof testStoreMember === "function")){ + passed = false; + break; + } + } + } + } + t.assertTrue(passed); + } + ] +); + + +} diff --git a/includes/js/dojox/data/tests/stores/OpmlStore.js b/includes/js/dojox/data/tests/stores/OpmlStore.js new file mode 100644 index 0000000..4fe7be4 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/OpmlStore.js @@ -0,0 +1,1075 @@ +if(!dojo._hasResource["dojox.data.tests.stores.OpmlStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.stores.OpmlStore"] = true; +dojo.provide("dojox.data.tests.stores.OpmlStore"); +dojo.require("dojox.data.OpmlStore"); +dojo.require("dojo.data.api.Read"); + +dojox.data.tests.stores.OpmlStore.getDatasource = function(filepath){ + // summary: + // A simple helper function for getting the sample data used in each of the tests. + // description: + // A simple helper function for getting the sample data used in each of the tests. + + var dataSource = {}; + if(dojo.isBrowser){ + dataSource.url = dojo.moduleUrl("dojox.data.tests", filepath).toString(); + }else{ + // When running tests in Rhino, xhrGet is not available, + // so we have the file data in the code below. + switch(filepath){ + case "stores/geography.xml": + var opmlData = ""; + opmlData += '\n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' geography.opml\n'; + opmlData += ' 2006-11-10\n'; + opmlData += ' 2006-11-13\n'; + opmlData += ' Magellan, Ferdinand\n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + break; + case "stores/geography_withspeciallabel.xml": + var opmlData = ""; + opmlData += '\n'; + opmlData += '\n'; + opmlData += ' \n'; + opmlData += ' geography.opml\n'; + opmlData += ' 2006-11-10\n'; + opmlData += ' 2006-11-13\n'; + opmlData += ' Magellan, Ferdinand\n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += ' \n'; + opmlData += '\n'; + break; + } + dataSource.data = opmlData; + } + return dataSource; //Object +} + +dojox.data.tests.stores.OpmlStore.verifyItems = function(opmlStore, items, attribute, compareArray){ + // summary: + // A helper function for validating that the items array is ordered + // the same as the compareArray + if(items.length != compareArray.length){ return false; } + for(var i = 0; i < items.length; i++){ + if(!(opmlStore.getValue(items[i], attribute) === compareArray[i])){ + return false; //Boolean + } + } + return true; //Boolean +} + +dojox.data.tests.stores.OpmlStore.error = function(t, d, errData){ + // summary: + // The error callback function to be used for all of the tests. + d.errback(errData); +} + +doh.register("dojox.data.tests.stores.OpmlStore", + [ + function testReadAPI_fetch_all(t){ + // summary: + // Simple test of a basic fetch on OpmlStore. + // description: + // Simple test of a basic fetch on OpmlStore. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"); + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + function completedAll(items){ + t.is(6, items.length); + d.callback(true); + } + + //Get everything... + opmlStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_fetch_one(t){ + // summary: + // Simple test of a basic fetch on OpmlStore of a single item. + // description: + // Simple test of a basic fetch on OpmlStore of a single item. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"); + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.is(1, items.length); + d.callback(true); + } + opmlStore.fetch({ query: {text: "Asia"}, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d) + }); + return d; //Object + }, + + function testReadAPI_fetch_one_Multiple(t){ + // summary: + // Simple test of a basic fetch on OpmlStore of a single item. + // description: + // Simple test of a basic fetch on OpmlStore of a single item. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"); + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + var done = [false,false]; + function onCompleteOne(items, request){ + done[0] = true; + t.is(1, items.length); + if(done[0] && done[1]){ + d.callback(true); + } + } + function onCompleteTwo(items, request){ + done[1] = true; + t.is(1, items.length); + if(done[0] && done[1]){ + d.callback(true); + } + } + + opmlStore.fetch({ query: {text: "Asia"}, + onComplete: onCompleteOne, + onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d) + }); + + opmlStore.fetch({ query: {text: "North America"}, + onComplete: onCompleteTwo, + onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d) + }); + + return d; //Object + }, + + function testReadAPI_fetch_one_MultipleMixed(t){ + // summary: + // Simple test of a basic fetch on OpmlStore of a single item mixing two fetch types. + // description: + // Simple test of a basic fetch on Cpmltore of a single item mixing two fetch types. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"); + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + + var done = [false, false]; + function onComplete(items, request){ + done[0] = true; + t.is(1, items.length); + console.log("Found item: " + opmlStore.getValue(items[0],"text") + " with identity: " + opmlStore.getIdentity(items[0])); + t.is(0, opmlStore.getIdentity(items[0])); + if(done[0] && done[1]){ + d.callback(true); + } + } + + function onItem(item){ + done[1] = true; + t.assertTrue(item !== null); + console.log("Found item: " + opmlStore.getValue(item,"text")); + t.is('Egypt', opmlStore.getValue(item,"text")); //Should be the second node parsed, ergo id 1, first node is id 0. + t.is(1, opmlStore.getIdentity(item)); + if(done[0] && done[1]){ + d.callback(true); + } + } + + opmlStore.fetch({ query: {text: "Africa"}, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d) + }); + + opmlStore.fetchItemByIdentity({identity: "1", onItem: onItem, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)}); + + return d; //Object + }, + + function testReadAPI_fetch_one_deep(t){ + // summary: + // Simple test of a basic fetch on OpmlStore of a single item that's nested down as a child item. + // description: + // Simple test of a basic fetch on OpmlStore of a single item that's nested down as a child item. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"); + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.is(1, items.length); + d.callback(true); + } + opmlStore.fetch({ query: {text: "Mexico City"}, + queryOptions: {deep:true}, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d) + }); + return d; //Object + }, + + function testReadAPI_fetch_one_deep_off(t){ + // summary: + // Simple test of a basic fetch on OpmlStore of a single item that's nested down as a child item. + // description: + // Simple test of a basic fetch on OpmlStore of a single item that's nested down as a child item. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"); + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + function onComplete(items, request){ + //Nothing should be found. + t.is(0, items.length); + d.callback(true); + } + opmlStore.fetch({ query: {text: "Mexico City"}, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d) + }); + return d; //Object + }, + + function testReadAPI_fetch_all_streaming(t){ + // summary: + // Simple test of a basic fetch on OpmlStore. + // description: + // Simple test of a basic fetch on OpmlStore. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"); + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + count = 0; + + function onBegin(size, requestObj){ + t.is(6, size); + } + function onItem(item, requestObj){ + t.assertTrue(opmlStore.isItem(item)); + count++; + } + function onComplete(items, request){ + t.is(6, count); + t.is(null, items); + d.callback(true); + } + + //Get everything... + opmlStore.fetch({ onBegin: onBegin, + onItem: onItem, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d) + }); + return d; //Object + }, + function testReadAPI_fetch_paging(t){ + // summary: + // Test of multiple fetches on a single result. Paging, if you will. + // description: + // Test of multiple fetches on a single result. Paging, if you will. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"); + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + function dumpFirstFetch(items, request){ + t.is(5, items.length); + request.start = 3; + request.count = 1; + request.onComplete = dumpSecondFetch; + opmlStore.fetch(request); + } + + function dumpSecondFetch(items, request){ + t.is(1, items.length); + request.start = 0; + request.count = 5; + request.onComplete = dumpThirdFetch; + opmlStore.fetch(request); + } + + function dumpThirdFetch(items, request){ + t.is(5, items.length); + request.start = 2; + request.count = 20; + request.onComplete = dumpFourthFetch; + opmlStore.fetch(request); + } + + function dumpFourthFetch(items, request){ + t.is(4, items.length); + request.start = 9; + request.count = 100; + request.onComplete = dumpFifthFetch; + opmlStore.fetch(request); + } + + function dumpFifthFetch(items, request){ + t.is(0, items.length); + request.start = 2; + request.count = 20; + request.onComplete = dumpSixthFetch; + opmlStore.fetch(request); + } + + function dumpSixthFetch(items, request){ + t.is(4, items.length); + d.callback(true); + } + + function completed(items, request){ + t.is(6, items.length); + request.start = 1; + request.count = 5; + request.onComplete = dumpFirstFetch; + opmlStore.fetch(request); + } + + opmlStore.fetch({onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)}); + return d; //Object + + }, + function testReadAPI_getLabel(t){ + // summary: + // Simple test of the getLabel function against a store set that has a label defined. + // description: + // Simple test of the getLabel function against a store set that has a label defined. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"); + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var label = opmlStore.getLabel(items[0]); + t.assertTrue(label !== null); + t.assertEqual("Asia", label); + d.callback(true); + } + opmlStore.fetch({ query: {text: "Asia"}, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d) + }); + return d; + }, + function testReadAPI_getLabelAttributes(t){ + // summary: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + // description: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"); + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var labelList = opmlStore.getLabelAttributes(items[0]); + t.assertTrue(dojo.isArray(labelList)); + t.assertEqual("text", labelList[0]); + d.callback(true); + } + opmlStore.fetch({ query: {text: "Asia"}, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d) + }); + return d; + }, + + function testReadAPI_getLabel_nondefault(t){ + // summary: + // Simple test of the getLabel function against a store set that has a label defined. + // description: + // Simple test of the getLabel function against a store set that has a label defined. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography_withspeciallabel.xml"); + args.label="label"; + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var label = opmlStore.getLabel(items[0]); + t.assertTrue(label !== null); + t.assertEqual("Continent/Asia", label); + d.callback(true); + } + opmlStore.fetch({ query: {text: "Asia"}, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d) + }); + return d; + }, + function testReadAPI_getLabelAttributes_nondefault(t){ + // summary: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + // description: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography_withspeciallabel.xml"); + args.label="label"; + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var labelList = opmlStore.getLabelAttributes(items[0]); + t.assertTrue(dojo.isArray(labelList)); + t.assertEqual("label", labelList[0]); + d.callback(true); + } + opmlStore.fetch({ query: {text: "Asia"}, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d) + }); + return d; + }, + + function testReadAPI_getValue(t){ + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"); + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + function completedAll(items){ + t.is(6, items.length); + + t.is("Africa", opmlStore.getValue(items[0],"text")); + t.is("Asia", opmlStore.getValue(items[1],"text")); + t.is("Australia", opmlStore.getValue(items[2],"text")); + t.is("Europe", opmlStore.getValue(items[3],"text")); + t.is("North America", opmlStore.getValue(items[4],"text")); + t.is("South America", opmlStore.getValue(items[5],"text")); + + t.is("continent", opmlStore.getValue(items[1],"type")); + t.is("21 million", opmlStore.getValue(items[2],"population")); + + var firstChild = opmlStore.getValue(items[4],"children"); + t.assertTrue(opmlStore.isItem(firstChild)); + t.is("Mexico", opmlStore.getValue(firstChild,"text")); + t.is("country", opmlStore.getValue(firstChild,"type")); + t.is("108 million", opmlStore.getValue(firstChild,"population")); + t.is("1,972,550 sq km", opmlStore.getValue(firstChild,"area")); + + firstChild = opmlStore.getValue(firstChild,"children"); + t.assertTrue(opmlStore.isItem(firstChild)); + t.is("Mexico City", opmlStore.getValue(firstChild,"text")); + t.is("city", opmlStore.getValue(firstChild,"type")); + t.is("19 million", opmlStore.getValue(firstChild,"population")); + t.is("-6 UTC", opmlStore.getValue(firstChild,"timezone")); + + d.callback(true); + } + + //Get everything... + opmlStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)}); + return d; //Object + }, + function testReadAPI_getValues(t){ + // summary: + // Simple test of the getValues function of the store. + // description: + // Simple test of the getValues function of the store. + + var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"); + var opmlStore = new dojox.data.OpmlStore(args); + + var d = new doh.Deferred(); + function completed(items){ + t.is(1, items.length); + + var children = opmlStore.getValues(items[0],"children"); + t.is(3, children.length); + for(var i=0; iAlabama", store.getValue(item, "label")); + t.assertEqual("AL", store.getValue(item, "abbreviation")); + // Test the defaultValue cases (the third paramter). + t.assertEqual("default value", store.getValue(item, "NAME", "default value")); + // TODO Test for null somehow ... + // Read api says: Returns null if and only if null was explicitly set as the attribute value. + + // According to Read-API getValue() an exception is thrown when + // the item is not an item or when the attribute is not a string. + t.assertError(Error, store, "getValue", ["not an item", "NOT THERE"]); + t.assertError(Error, store, "getValue", [item, {}]); + + d.callback(true); + } + store.fetch({query:{q:"Alabama"}, onComplete: onComplete}); + return d; //Object + }, + + function testReadApi_getValues(t){ + // summary: + // description: + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + var item = items[0]; + // The good cases. + t.assertEqual(["Alabama"], store.getValues(item, "name")); + t.assertEqual(["Alabama"], store.getValues(item, "label")); + t.assertEqual(["AL"], store.getValues(item, "abbreviation")); + // TODO Test for null somehow ... + // Read api says: Returns null if and only if null was explicitly set as the attribute value. + + // Test for not-existing attributes without defaultValues and invalid items. + // TODO + t.assertEqual([], store.getValues(item, "NOT THERE")); + var errThrown = false; + try{ + //Should throw an exception. + var values = store.getValues("not an item", "NOT THERE"); + }catch (e){ + errThrown = true; + } + t.assertTrue(errThrown); + d.callback(true); + } + store.fetch({query:{q:"Alabama"}, onComplete: onComplete}); + return d; //Object + }, + + function testReadApi_getAttributes(t){ + // summary: + // description: + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + var item = items[0]; + // The good case(s). + t.assertEqual(['id', 'name', 'label', 'abbreviation', 'capital'], store.getAttributes(item)); + t.assertError(Error, store, "getAttributes", [{}]); + + d.callback(true); + } + store.fetch({query:{q:"Alabama"}, onComplete: onComplete}); + return d; //Object + }, + + function testReadApi_getLabel(t){ + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + var d = new doh.Deferred(); + function onComplete(items, request){ + var item = items[0]; + // The good cases. + t.assertEqual(["Alabama"], store.getLabel(item)); + d.callback(true); + } + store.fetch({query:{q:"Alabama"}, onComplete: onComplete}); + return d; //Object + }, + + function testReadApi_hasAttribute(t){ + // summary: + // description: + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + var item = items[0]; + // The positive cases. + t.assertEqual(true, store.hasAttribute(item, "name")); + t.assertEqual(true, store.hasAttribute(item, "label")); + t.assertEqual(true, store.hasAttribute(item, "abbreviation")); + // Make sure attribute case doesnt matter. + t.assertEqual(false, store.hasAttribute(item, "NAME")); + t.assertEqual(false, store.hasAttribute(item, "Name")); + t.assertEqual(false, store.hasAttribute(item, "Label")); + // Pass in an invalid item. + t.assertEqual(false, store.hasAttribute({}, "abbreviation")); + // pass in something that looks like the item with the attribute. + t.assertEqual(false, store.hasAttribute({name:"yo"}, "name")); + + d.callback(true); + } + store.fetch({query:{q:"Alaska"}, onComplete: onComplete}); + return d; //Object + }, + + function testReadApi_containsValue(t){ + // summary: + // description: + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + var item = items[0]; + t.assertTrue(store.containsValue(item, "name", "Alaska")); + d.callback(true); + } + store.fetch({query:{q:"Alaska"}, onComplete: onComplete}); + return d; //Object + }, + + function testReadApi_isItem(t){ + // summary: + // description: + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + // The good case. + t.assertEqual(true, store.isItem(items[0])); + // Try a pure object. + t.assertEqual(false, store.isItem({})); + // Try to look like an item. + t.assertEqual(false, store.isItem({name:"Alaska", label:"Alaska", abbreviation:"AK"})); + d.callback(true); + } + store.fetch({query:{q:"Alaska"}, onComplete: onComplete}); + return d; //Object + }, + + function testReadApi_isItemLoaded(t){ + // summary: + // description: + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + var item = items[0]; + // The good case(s). + t.assertTrue(store.isItemLoaded(item)); + + d.callback(true); + } + store.fetch({query:{q:"Alabama"}, onComplete: onComplete}); + return d; //Object + }, + + //function testReadApi_loadItem(t){ + // // summary: + // // description: + // t.assertTrue(false); + //}, + + function testReadApi_fetch_all(t){ + // summary: + // Simple test of fetching all items. + // description: + // Simple test of fetching all items. + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(8, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{q:"m"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + + function testReadApi_fetch_onBegin(t){ + // summary: + // Simple test of fetching items, checking that onBegin size is all items matched, and page is just the items asked for. + // description: + // Simple test of fetching items, checking that onBegin size is all items matched, and page is just the items asked for. + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + + var d = new doh.Deferred(); + var passed = false; + function onBegin(size, request){ + t.assertEqual(8, size); + passed = true; + } + function onComplete(items, request) { + t.assertEqual(5, items.length); + if(passed){ + d.callback(true); + }else{ + d.errback(new Error("Store did not return proper number of rows, regardless of page size")); + } + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{q:"m"}, start: 0, count: 5, onBegin: onBegin, onComplete: onComplete, onError: onError}); + return d; //Object + }, + + function testReadApi_fetch_onBegin_ServersidePaging(t){ + // summary: + // Simple test of fetching items, checking that onBegin size is all items matched, and page is just the items asked for. + // description: + // Simple test of fetching items, checking that onBegin size is all items matched, and page is just the items asked for. + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + + var d = new doh.Deferred(); + var passed = false; + function onBegin(size, request){ + t.assertEqual(8, size); + passed = true; + } + function onComplete(items, request) { + t.assertEqual(3, items.length); + if(passed){ + d.callback(true); + }else{ + d.errback(new Error("Store did not return proper number of rows, regardless of page size")); + } + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{q:"m"}, start: 5, count: 5, onBegin: onBegin, onComplete: onComplete, onError: onError}); + return d; //Object + }, + + function testReadApi_fetch_onBegin_ClientsidePaging(t){ + // summary: + // Simple test of fetching items, checking that onBegin size is all items matched, and page is just the items asked for. + // description: + // Simple test of fetching items, checking that onBegin size is all items matched, and page is just the items asked for. + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + store.doClientPaging = true; + + var d = new doh.Deferred(); + var passed = false; + function onBegin(size, request){ + t.assertEqual(8, size); + passed = true; + } + function onComplete(items, request) { + t.assertEqual(5, items.length); + if(passed){ + d.callback(true); + }else{ + d.errback(new Error("Store did not return proper number of rows, regardless of page size")); + } + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{q:"m"}, start: 0, count: 5, onBegin: onBegin, onComplete: onComplete, onError: onError}); + return d; //Object + }, + + function testReadApi_fetch_one(t){ + // summary: + // description: + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(1, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{q:"Alaska"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + + function testReadApi_fetch_client_paging(t){ + // summary: + // Lets test that paging on the same request does not trigger + // server requests. + // description: + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + store.doClientPaging = true; + + var lastRequestHash = null; + var firstItems = []; + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(5, items.length); + lastRequestHash = store.lastRequestHash; + firstItems = items; + + // Do the next request AFTER the previous one, so we are sure its sequential. + // We need to be sure so we can compare to the data from the first request. + function onComplete1(items, request) { + t.assertEqual(5, items.length); + t.assertEqual(lastRequestHash, store.lastRequestHash); + t.assertEqual(firstItems[1], items[0]); + d.callback(true); + } + req.start = 1; + req.onComplete = onComplete1; + store.fetch(req); + } + function onError(error, request) { + d.errback(error); + } + var req = {query:{q:"m"}, start:0, count:5, + onComplete: onComplete, onError: onError}; + store.fetch(req); + return d; //Object + }, + + function testReadApi_fetch_server_paging(t) { + // Verify that the paging on the server side does work. + // This is the test for http://trac.dojotoolkit.org/ticket/4761 + // + // How? We request 10 items from the server, start=0, count=10. + // The second request requests 5 items: start=5, count=5 and those + // 5 items should have the same values as the last 5 of the first + // request. + // This tests if the server side paging does work. + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + + var lastRequestHash = null; + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(10, items.length); + lastRequestHash = store.lastRequestHash; + firstItems = items; + + // Do the next request AFTER the previous one, so we are sure its sequential. + // We need to be sure so we can compare to the data from the first request. + function onComplete1(items, request) { + t.assertEqual(5, items.length); + // Compare the hash of the last request, they must be different, + // since another server request was issued. + t.assertTrue(lastRequestHash!=store.lastRequestHash); + t.assertEqual(store.getValue(firstItems[5], "name"), store.getValue(items[0], "name")); + t.assertEqual(store.getValue(firstItems[6], "name"), store.getValue(items[1], "name")); + t.assertEqual(store.getValue(firstItems[7], "name"), store.getValue(items[2], "name")); + t.assertEqual(store.getValue(firstItems[8], "name"), store.getValue(items[3], "name")); + t.assertEqual(store.getValue(firstItems[9], "name"), store.getValue(items[4], "name")); + d.callback(true); + } + // Init a new store, or it will use the old data, since the query has not changed. + store.doClientPaging = false; + store.fetch({start:5, count:5, onComplete: onComplete1, onError: onError}); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{}, start:0, count:10, onComplete: onComplete, onError: onError}); + return d; //Object + }, + + function testReadApi_getFeatures(t) { + var store = dojox.data.tests.stores.QueryReadStore.getStore(); + var features = store.getFeatures(); + t.assertTrue(features["dojo.data.api.Read"]); + t.assertTrue(features["dojo.data.api.Identity"]); + var count = 0; + for (i in features){ + count++; + } + t.assertEqual(2, count); + }, + function testReadAPI_functionConformance(t){ + // summary: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + + var testStore = dojox.data.tests.stores.QueryReadStore.getStore(); + var readApi = new dojo.data.api.Read(); + var passed = true; + + for(i in readApi){ + var member = readApi[i]; + //Check that all the 'Read' defined functions exist on the test store. + if(typeof member === "function"){ + var testStoreMember = testStore[i]; + if(!(typeof testStoreMember === "function")){ + console.log("Problem with function: [" + i + "]"); + passed = false; + break; + } + } + } + t.assertTrue(passed); + } + ] +); + +} diff --git a/includes/js/dojox/data/tests/stores/QueryReadStore.php b/includes/js/dojox/data/tests/stores/QueryReadStore.php new file mode 100644 index 0000000..26fbcde --- /dev/null +++ b/includes/js/dojox/data/tests/stores/QueryReadStore.php @@ -0,0 +1,114 @@ +0, 'name'=>"Alabama", 'label'=>"Alabama", 'abbreviation'=>"AL", 'capital'=>'Montgomery'), + array('id'=>1, 'name'=>"Alaska", 'label'=>"Alaska", 'abbreviation'=>"AK", 'capital'=>'Juneau'), + //array('id'=>2, 'name'=>"American Samoa", 'label'=>"American Samoa", 'abbreviation'=>"AS", 'capital'=>''), + array('id'=>3, 'name'=>"Arizona", 'label'=>"Arizona", 'abbreviation'=>"AZ", 'capital'=>'Phoenix'), + array('id'=>4, 'name'=>"Arkansas", 'label'=>"Arkansas", 'abbreviation'=>"AR", 'capital'=>'Little Rock'), + //array('id'=>5, 'name'=>"Armed Forces Europe", 'label'=>"Armed Forces Europe", 'abbreviation'=>"AE", 'capital'=>''), + //array('id'=>6, 'name'=>"Armed Forces Pacific", 'label'=>"Armed Forces Pacific", 'abbreviation'=>"AP", 'capital'=>''), + //array('id'=>7, 'name'=>"Armed Forces the Americas", 'label'=>"Armed Forces the Americas", 'abbreviation'=>"AA", 'capital'=>''), + array('id'=>8, 'name'=>"California", 'label'=>"California", 'abbreviation'=>"CA", 'capital'=>'Sacramento'), + array('id'=>9, 'name'=>"Colorado", 'label'=>"Colorado", 'abbreviation'=>"CO", 'capital'=>'Denver'), + array('id'=>10, 'name'=>"Connecticut", 'label'=>"Connecticut", 'abbreviation'=>"CT", 'capital'=>'Hartford'), + array('id'=>11, 'name'=>"Delaware", 'label'=>"Delaware", 'abbreviation'=>"DE", 'capital'=>'Dover'), + //array('id'=>12, 'name'=>"District of Columbia", 'label'=>"District of Columbia", 'abbreviation'=>"DC", 'capital'=>''), + //array('id'=>13, 'name'=>"Federated States of Micronesia", 'label'=>"Federated States of Micronesia", 'abbreviation'=>"FM", 'capital'=>''), + array('id'=>14, 'name'=>"Florida", 'label'=>"Florida", 'abbreviation'=>"FL", 'capital'=>'Tallahassee'), + array('id'=>15, 'name'=>"Georgia", 'label'=>"Georgia", 'abbreviation'=>"GA", 'capital'=>'Atlanta'), + //array('id'=>16, 'name'=>"Guam", 'label'=>"Guam", 'abbreviation'=>"GU", 'capital'=>''), + array('id'=>17, 'name'=>"Hawaii", 'label'=>"Hawaii", 'abbreviation'=>"HI", 'capital'=>'Honolulu'), + array('id'=>18, 'name'=>"Idaho", 'label'=>"Idaho", 'abbreviation'=>"ID", 'capital'=>'Boise'), + array('id'=>19, 'name'=>"Illinois", 'label'=>"Illinois", 'abbreviation'=>"IL", 'capital'=>'Springfield'), + array('id'=>20, 'name'=>"Indiana", 'label'=>"Indiana", 'abbreviation'=>"IN", 'capital'=>'Indianapolis'), + array('id'=>21, 'name'=>"Iowa", 'label'=>"Iowa", 'abbreviation'=>"IA", 'capital'=>'Des Moines'), + array('id'=>22, 'name'=>"Kansas", 'label'=>"Kansas", 'abbreviation'=>"KS", 'capital'=>'Topeka'), + array('id'=>23, 'name'=>"Kentucky", 'label'=>"Kentucky", 'abbreviation'=>"KY", 'capital'=>'Frankfort'), + array('id'=>24, 'name'=>"Louisiana", 'label'=>"Louisiana", 'abbreviation'=>"LA", 'capital'=>'Baton Rouge'), + array('id'=>25, 'name'=>"Maine", 'label'=>"Maine", 'abbreviation'=>"ME", 'capital'=>'Augusta'), + //array('id'=>26, 'name'=>"Marshall Islands", 'label'=>"Marshall Islands", 'abbreviation'=>"MH", 'capital'=>''), + array('id'=>27, 'name'=>"Maryland", 'label'=>"Maryland", 'abbreviation'=>"MD", 'capital'=>'Annapolis'), + array('id'=>28, 'name'=>"Massachusetts", 'label'=>"Massachusetts", 'abbreviation'=>"MA", 'capital'=>'Boston'), + array('id'=>29, 'name'=>"Michigan", 'label'=>"Michigan", 'abbreviation'=>"MI", 'capital'=>'Lansing'), + array('id'=>30, 'name'=>"Minnesota", 'label'=>"Minnesota", 'abbreviation'=>"MN", 'capital'=>'Saint Paul'), + array('id'=>31, 'name'=>"Mississippi", 'label'=>"Mississippi", 'abbreviation'=>"MS", 'capital'=>'Jackson'), + array('id'=>32, 'name'=>"Missouri", 'label'=>"Missouri", 'abbreviation'=>"MO", 'capital'=>'Jefferson City'), + array('id'=>33, 'name'=>"Montana", 'label'=>"Montana", 'abbreviation'=>"MT", 'capital'=>'Helena'), + array('id'=>34, 'name'=>"Nebraska", 'label'=>"Nebraska", 'abbreviation'=>"NE", 'capital'=>'Lincoln'), + array('id'=>35, 'name'=>"Nevada", 'label'=>"Nevada", 'abbreviation'=>"NV", 'capital'=>'Carson City'), + array('id'=>36, 'name'=>"New Hampshire", 'label'=>"New Hampshire", 'abbreviation'=>"NH", 'capital'=>'Concord'), + array('id'=>37, 'name'=>"New Jersey", 'label'=>"New Jersey", 'abbreviation'=>"NJ", 'capital'=>'Trenton'), + array('id'=>38, 'name'=>"New Mexico", 'label'=>"New Mexico", 'abbreviation'=>"NM", 'capital'=>'Santa Fe'), + array('id'=>39, 'name'=>"New York", 'label'=>"New York", 'abbreviation'=>"NY", 'capital'=>'Albany'), + array('id'=>40, 'name'=>"North Carolina", 'label'=>"North Carolina", 'abbreviation'=>"NC", 'capital'=>'Raleigh'), + array('id'=>41, 'name'=>"North Dakota", 'label'=>"North Dakota", 'abbreviation'=>"ND", 'capital'=>'Bismarck'), + //array('id'=>42, 'name'=>"Northern Mariana Islands", 'label'=>"Northern Mariana Islands", 'abbreviation'=>"MP", 'capital'=>''), + array('id'=>43, 'name'=>"Ohio", 'label'=>"Ohio", 'abbreviation'=>"OH", 'capital'=>'Columbus'), + array('id'=>44, 'name'=>"Oklahoma", 'label'=>"Oklahoma", 'abbreviation'=>"OK", 'capital'=>'Oklahoma City'), + array('id'=>45, 'name'=>"Oregon", 'label'=>"Oregon", 'abbreviation'=>"OR", 'capital'=>'Salem'), + array('id'=>46, 'name'=>"Pennsylvania", 'label'=>"Pennsylvania", 'abbreviation'=>"PA", 'capital'=>'Harrisburg'), + //array('id'=>47, 'name'=>"Puerto Rico", 'label'=>"Puerto Rico", 'abbreviation'=>"PR", 'capital'=>''), + array('id'=>48, 'name'=>"Rhode Island", 'label'=>"Rhode Island", 'abbreviation'=>"RI", 'capital'=>'Providence'), + array('id'=>49, 'name'=>"South Carolina", 'label'=>"South Carolina", 'abbreviation'=>"SC", 'capital'=>'Columbia'), + array('id'=>50, 'name'=>"South Dakota", 'label'=>"South Dakota", 'abbreviation'=>"SD", 'capital'=>'Pierre'), + array('id'=>51, 'name'=>"Tennessee", 'label'=>"Tennessee", 'abbreviation'=>"TN", 'capital'=>'Nashville'), + array('id'=>52, 'name'=>"Texas", 'label'=>"Texas", 'abbreviation'=>"TX", 'capital'=>'Austin'), + array('id'=>53, 'name'=>"Utah", 'label'=>"Utah", 'abbreviation'=>"UT", 'capital'=>'Salt Lake City'), + array('id'=>54, 'name'=>"Vermont", 'label'=>"Vermont", 'abbreviation'=>"VT", 'capital'=>'Montpelier'), + //array('id'=>55, 'name'=> "Virgin Islands, U.S.", 'label'=>"Virgin Islands, U.S.", 'abbreviation'=>"VI", 'capital'=>''), + array('id'=>56, 'name'=>"Virginia", 'label'=>"Virginia", 'abbreviation'=>"VA", 'capital'=>'Richmond'), + array('id'=>57, 'name'=>"Washington", 'label'=>"Washington", 'abbreviation'=>"WA", 'capital'=>'Olympia'), + array('id'=>58, 'name'=>"West Virginia", 'label'=>"West Virginia", 'abbreviation'=>"WV", 'capital'=>'Charleston'), + array('id'=>59, 'name'=>"Wisconsin", 'label'=>"Wisconsin", 'abbreviation'=>"WI", 'capital'=>'Madison'), + array('id'=>60, 'name'=>"Wyoming", 'label'=>"Wyoming", 'abbreviation'=>"WY", 'capital'=>'Cheyenne'), +); + +$q = ""; +if (array_key_exists("q", $_REQUEST)) { + $q = $_REQUEST['q']; +}else if (array_key_exists("name", $_REQUEST)) { + $q = $_REQUEST['name']; +} + +if (strlen($q) && $q[strlen($q)-1]=="*") { + $q = substr($q, 0, strlen($q)-1); +} +$ret = array(); +foreach ($allItems as $item) { + if (!$q || strpos(strtolower($item['name']), strtolower($q))===0) { + $ret[] = $item; + } +} + +// Handle sorting +if (array_key_exists("sort", $_REQUEST)) { + $sort = $_REQUEST['sort']; + // Check if $sort starts with "-" then we have a DESC sort. + $desc = strpos($sort, '-')===0 ? true : false; + $sort = strpos($sort, '-')===0 ? substr($sort, 1) : $sort; + if (in_array($sort, array_keys($ret[0]))) { + $toSort = array(); + foreach ($ret as $i) $toSort[$i[$sort]] = $i; + if ($desc) krsort($toSort); else ksort($toSort); + $newRet = array(); + foreach ($toSort as $i) $newRet[] = $i; + $ret = $newRet; + } +} + + +// Handle total number of matches as a return, regardless of page size, but taking the filtering into account (if taken place). +$numRows = count($ret); + +// Handle paging, if given. +if (array_key_exists("start", $_REQUEST)) { + $ret = array_slice($ret, $_REQUEST['start']); +} +if (array_key_exists("count", $_REQUEST)) { + $ret = array_slice($ret, 0, $_REQUEST['count']); +} + +print '/*'.json_encode(array('numRows'=>$numRows, 'items'=>$ret, 'identity'=>'id')).'*/'; diff --git a/includes/js/dojox/data/tests/stores/SnapLogicStore.js b/includes/js/dojox/data/tests/stores/SnapLogicStore.js new file mode 100644 index 0000000..d544799 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/SnapLogicStore.js @@ -0,0 +1,438 @@ +if(!dojo._hasResource["dojox.data.tests.stores.SnapLogicStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.stores.SnapLogicStore"] = true; +dojo.provide("dojox.data.tests.stores.SnapLogicStore"); +dojo.require("dojox.data.SnapLogicStore"); +dojo.require("dojo.data.api.Read"); + +dojox.data.tests.stores.SnapLogicStore.pipelineUrl = dojo.moduleUrl("dojox.data.tests", "stores/snap_pipeline.php").toString(); +dojox.data.tests.stores.SnapLogicStore.pipelineSize = 14; +dojox.data.tests.stores.SnapLogicStore.attributes = ["empno", "ename", "job", "hiredate", "sal", "comm", "deptno"]; + +dojox.data.tests.stores.SnapLogicStore.error = function(t, d, errData){ + // summary: + // The error callback function to be used for all of the tests. + d.errback(errData); +} + +doh.register("dojox.data.tests.stores.SnapLogicStore", + [ + { + name: "ReadAPI: Fetch One", + timeout: 3000, //3 seconds. + runTest: function(t) { + // summary: + // Simple test of a basic fetch from a SnapLogic pipeline + // description: + // Simple test of a basic fetch from a SnapLogic pipeline + + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(1, items.length); + d.callback(true); + } + store.fetch({ count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, doh, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: Fetch_10_Streaming", + timeout: 3000, //3 seconds. + runTest: function(t) { + // summary: + // Simple test of a basic fetch on SnapLogic pipeline. + // description: + // Simple test of a basic fetch on SnapLogic pipeline. + + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var d = new doh.Deferred(); + count = 0; + + function onBegin(size, requestObj){ + t.assertEqual(dojox.data.tests.stores.SnapLogicStore.pipelineSize, size); + } + function onItem(item, requestObj){ + t.assertTrue(store.isItem(item)); + count++; + } + function onComplete(items, request){ + t.assertEqual(10, count); + t.assertTrue(items === null); + d.callback(true); + } + + //Get everything... + store.fetch({ onBegin: onBegin, + count: 10, + onItem: onItem, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: Fetch Zero", + timeout: 3000, //3 seconds. + runTest: function(t) { + // summary: + // Try fetching 0 records. A count of the items in the pipeline should be returned. + // description: + // Try fetching 0 records. A count of the items in the pipeline should be returned. + + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var d = new doh.Deferred(); + function onBegin(count, request){ + t.assertEqual(dojox.data.tests.stores.SnapLogicStore.pipelineSize, count); + d.callback(true); + } + store.fetch({ count: 0, + onBegin: onBegin, + onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, doh, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: Fetch_Paging", + timeout: 3000, //3 seconds. + runTest: function(t) { + // summary: + // Test of multiple fetches on a single result. Paging, if you will. + // description: + // Test of multiple fetches on a single result. Paging, if you will. + + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var d = new doh.Deferred(); + function dumpFirstFetch(items, request){ + t.assertEqual(request.count, items.length); + request.start = dojox.data.tests.stores.SnapLogicStore.pipelineSize / 3; + request.count = 1; + request.onComplete = dumpSecondFetch; + store.fetch(request); + } + + function dumpSecondFetch(items, request){ + t.assertEqual(1, items.length); + request.start = 0; + request.count = dojox.data.tests.stores.SnapLogicStore.pipelineSize / 2; + request.onComplete = dumpThirdFetch; + store.fetch(request); + } + + function dumpThirdFetch(items, request){ + t.assertEqual(request.count, items.length); + request.count = dojox.data.tests.stores.SnapLogicStore.pipelineSize * 2; + request.onComplete = dumpFourthFetch; + store.fetch(request); + } + + function dumpFourthFetch(items, request){ + t.assertEqual(dojox.data.tests.stores.SnapLogicStore.pipelineSize, items.length); + request.start = Math.floor(3 * dojox.data.tests.stores.SnapLogicStore.pipelineSize / 4); + request.count = dojox.data.tests.stores.SnapLogicStore.pipelineSize; + request.onComplete = dumpFifthFetch; + store.fetch(request); + } + + function dumpFifthFetch(items, request){ + t.assertEqual(dojox.data.tests.stores.SnapLogicStore.pipelineSize - request.start, items.length); + request.start = 2; + request.count = dojox.data.tests.stores.SnapLogicStore.pipelineSize * 10; + request.onComplete = dumpSixthFetch; + store.fetch(request); + } + + function dumpSixthFetch(items, request){ + t.assertEqual(dojox.data.tests.stores.SnapLogicStore.pipelineSize - request.start, items.length); + d.callback(true); + } + + store.fetch({ count: 5, + onComplete: dumpFirstFetch, + onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)}); + return d; //Object + } + }, + { + name: "ReadAPI: getLabel", + timeout: 3000, //3 seconds + runTest: function(t) { + // summary: + // Test that the label function returns undefined since it's not supported. + // description: + // Test that the label function returns undefined since it's not supported. + + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var label = store.getLabel(items[0]); + t.assertTrue(label === undefined); + d.callback(true); + } + store.fetch({ count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d) + }); + return d; + } + }, + { + name: "ReadAPI: getLabelAttributes", + timeout: 3000, //3 seconds. + runTest: function(t) { + // summary: + // Simple test of the getLabelAttributes returns null since it's not supported. + // description: + // Simple test of the getLabelAttributes returns null since it's not supported. + + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var labelList = store.getLabelAttributes(items[0]); + t.assertTrue(labelList === null); + d.callback(true); + } + store.fetch({ count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d) + }); + return d; + } + }, + { + name: "ReadAPI: getValue", + timeout: 3000, //3 seconds. + runTest: function(t) { + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var d = new doh.Deferred(); + function completedAll(items){ + t.assertEqual(1, items.length); + console.debug(items[0]); + t.assertTrue(store.getValue(items[0], "empno") === 7369); + t.assertTrue(store.getValue(items[0], "ename") === "SMITH,CLERK"); + console.debug(store.getValue(items[0], "sal")); + t.assertTrue(store.getValue(items[0], "sal") == 800.00); + console.debug(1); + t.assertTrue(store.getValue(items[0], "deptno") === 20); + d.callback(true); + } + + store.fetch({ count: 1, + onComplete: completedAll, + onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)}); + return d; + } + }, + { + name: "ReadAPI: getValues", + timeout: 3000, //3 seconds. + runTest: function(t) { + // summary: + // Simple test of the getValue function of the store. + // description: + // Simple test of the getValue function of the store. + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var d = new doh.Deferred(); + function completedAll(items){ + t.assertEqual(1, items.length); + for(var i = 0; i < dojox.data.tests.stores.SnapLogicStore.attributes.length; ++i){ + var values = store.getValues(items[0], dojox.data.tests.stores.SnapLogicStore.attributes[i]); + t.assertTrue(dojo.isArray(values)); + t.assertTrue(values[0] === store.getValue(items[0], dojox.data.tests.stores.SnapLogicStore.attributes[i])); + } + d.callback(true); + } + + store.fetch({ count: 1, + onComplete: completedAll, + onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)}); + return d; + } + }, + { + name: "ReadAPI: isItem", + timeout: 3000, //3 seconds. + runTest: function(t) { + // summary: + // Simple test of the isItem function of the store + // description: + // Simple test of the isItem function of the store + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var d = new doh.Deferred(); + function completedAll(items){ + t.assertEqual(5, items.length); + for(var i=0; i < items.length; i++){ + t.assertTrue(store.isItem(items[i])); + } + d.callback(true); + } + + //Get everything... + store.fetch({ count: 5, + onComplete: completedAll, + onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)}); + return d; //Object + } + }, + { + name: "ReadAPI: hasAttribute", + timeout: 3000, //3 seconds. + runTest: function(t) { + // summary: + // Simple test of the hasAttribute function of the store + // description: + // Simple test of the hasAttribute function of the store + + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var d = new doh.Deferred(); + function onComplete(items){ + t.assertEqual(1, items.length); + t.assertTrue(items[0] !== null); + for(var i = 0; i < dojox.data.tests.stores.SnapLogicStore.attributes.length; ++i){ + t.assertTrue(store.hasAttribute(items[0], dojox.data.tests.stores.SnapLogicStore.attributes[i])); + } + t.assertTrue(!store.hasAttribute(items[0], "Nothing")); + t.assertTrue(!store.hasAttribute(items[0], "Text")); + + //Test that null attributes throw an exception + var passed = false; + try{ + store.hasAttribute(items[0], null); + }catch (e){ + passed = true; + } + t.assertTrue(passed); + d.callback(true); + } + + //Get one item... + store.fetch({ count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: containsValue", + timeout: 3000, //3 seconds. + runTest: function(t) { + // summary: + // Simple test of the containsValue function of the store + // description: + // Simple test of the containsValue function of the store + + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var d = new doh.Deferred(); + function onComplete(items){ + t.assertEqual(1, items.length); + var value = store.getValue(items[0], "LastName"); + t.assertTrue(store.containsValue(items[0], "LastName", value)); + d.callback(true); + } + + //Get one item... + store.fetch({ count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d) + }); + return d; //Object + } + }, + { + name: "ReadAPI: getAttributes", + timeout: 3000, //3 seconds. + runTest: function(t) { + // summary: + // Simple test of the getAttributes function of the store + // description: + // Simple test of the getAttributes function of the store + + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var d = new doh.Deferred(); + function onComplete(items){ + t.assertEqual(1, items.length); + + var itemAttributes = store.getAttributes(items[0]); + t.assertEqual(dojox.data.tests.stores.SnapLogicStore.attributes.length, itemAttributes.length); + for(var i = 0; i < dojox.data.tests.stores.SnapLogicStore.attributes.length; ++i){ + t.assertTrue(dojo.indexOf(itemAttributes, dojox.data.tests.stores.SnapLogicStore.attributes[i]) !== -1); + } + d.callback(true); + } + + //Get everything... + store.fetch({ count: 1, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.SnapLogicStore.error, t, d)}); + return d; //Object + } + }, + function testReadAPI_getFeatures(t){ + // summary: + // Simple test of the getFeatures function of the store + // description: + // Simple test of the getFeatures function of the store + + var store = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + + var features = store.getFeatures(); + var count = 0; + for(var i in features){ + t.assertEqual(i, "dojo.data.api.Read"); + count++; + } + + t.assertEqual(count, 1); + }, + function testReadAPI_functionConformance(t){ + // summary: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + + var testStore = new dojox.data.SnapLogicStore({url: dojox.data.tests.stores.SnapLogicStore.pipelineUrl}); + var readApi = new dojo.data.api.Read(); + var passed = true; + + for(var i in readApi){ + if(i.toString().charAt(0) !== '_'){ + var member = readApi[i]; + //Check that all the 'Read' defined functions exist on the test store. + if(typeof member === "function"){ + var testStoreMember = testStore[i]; + if(!(typeof testStoreMember === "function")){ + passed = false; + break; + } + } + } + } + t.assertTrue(passed); + } + ] +); + +} diff --git a/includes/js/dojox/data/tests/stores/XmlStore.js b/includes/js/dojox/data/tests/stores/XmlStore.js new file mode 100644 index 0000000..0c99732 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/XmlStore.js @@ -0,0 +1,881 @@ +if(!dojo._hasResource["dojox.data.tests.stores.XmlStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.stores.XmlStore"] = true; +dojo.provide("dojox.data.tests.stores.XmlStore"); +dojo.require("dojox.data.XmlStore"); +dojo.require("dojo.data.api.Read"); +dojo.require("dojo.data.api.Write"); + + +dojox.data.tests.stores.XmlStore.getBooks2Store = function(){ + return new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books2.xml").toString(), label: "title"}); +}; + +dojox.data.tests.stores.XmlStore.getBooksStore = function(){ + return new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books.xml").toString(), label: "title"}); +}; + +doh.register("dojox.data.tests.stores.XmlStore", + [ + function testReadAPI_fetch_all(t){ + // summary: + // Simple test of fetching all xml items through an XML element called isbn + // description: + // Simple test of fetching all xml items through an XML element called isbn + var store = dojox.data.tests.stores.XmlStore.getBooksStore(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(20, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"*"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_one(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn + // description: + // Simple test of fetching one xml items through an XML element called isbn + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + { + name: "testReadAPI_fetch_paging", + timeout: 10000, + runTest: function(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn + // description: + // Simple test of fetching one xml items through an XML element called isbn + var store = dojox.data.tests.stores.XmlStore.getBooksStore(); + var d = new doh.Deferred(); + function dumpFirstFetch(items, request){ + t.assertEqual(5, items.length); + request.start = 3; + request.count = 1; + request.onComplete = dumpSecondFetch; + store.fetch(request); + } + + function dumpSecondFetch(items, request){ + t.assertEqual(1, items.length); + request.start = 0; + request.count = 5; + request.onComplete = dumpThirdFetch; + store.fetch(request); + } + + function dumpThirdFetch(items, request){ + t.assertEqual(5, items.length); + request.start = 2; + request.count = 20; + request.onComplete = dumpFourthFetch; + store.fetch(request); + } + + function dumpFourthFetch(items, request){ + t.assertEqual(18, items.length); + request.start = 9; + request.count = 100; + request.onComplete = dumpFifthFetch; + store.fetch(request); + } + + function dumpFifthFetch(items, request){ + t.assertEqual(11, items.length); + request.start = 2; + request.count = 20; + request.onComplete = dumpSixthFetch; + store.fetch(request); + } + + function dumpSixthFetch(items, request){ + t.assertEqual(18, items.length); + d.callback(true); + } + + function completed(items, request){ + t.assertEqual(20, items.length); + request.start = 1; + request.count = 5; + request.onComplete = dumpFirstFetch; + store.fetch(request); + } + + function error(errData, request){ + d.errback(errData); + } + + store.fetch({onComplete: completed, onError: error}); + return d; //Object + } + }, + function testReadAPI_fetch_pattern0(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + // description: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"?9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_pattern1(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + // description: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(4, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B57?"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_pattern2(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with * pattern match + // description: + // Simple test of fetching one xml items through an XML element called isbn with * pattern match + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(5, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9*"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_pattern_caseInsensitive(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case insensitive mode. + // description: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case insensitive mode. + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"?9b574"}, queryOptions: {ignoreCase: true}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_pattern_caseSensitive(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case sensitive mode. + // description: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case sensitive mode. + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"?9B574"}, queryOptions: {ignoreCase: false}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_all_rootItem(t){ + // summary: + // Simple test of fetching all xml items through an XML element called isbn + // description: + // Simple test of fetching all xml items through an XML element called isbn + var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books3.xml").toString(), + rootItem:"book"}); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(5, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"*"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_withAttrMap_all(t){ + var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr.xml").toString(), + attributeMap: {"book.isbn": "@isbn"}}); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(5, items.length); + d.callback(true); + } + function onError(error, request) { + console.debug(error); + d.errback(error); + } + store.fetch({query:{isbn:"*"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_withAttrMap_one(t){ + var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr.xml").toString(), + attributeMap: {"book.isbn": "@isbn"}}); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + d.callback(true); + } + function onError(error, request) { + console.debug(error); + d.errback(error); + } + store.fetch({query:{isbn:"2"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_withAttrMap_pattern0(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + // description: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr2.xml").toString(), + attributeMap: {"book.isbn": "@isbn"}}); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(3, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"ABC?"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_withAttrMap_pattern1(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + // description: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr2.xml").toString(), + attributeMap: {"book.isbn": "@isbn"}}); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(5, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A*"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_fetch_withAttrMap_pattern2(t){ + // summary: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + // description: + // Simple test of fetching one xml items through an XML element called isbn with ? pattern match + var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr2.xml").toString(), + attributeMap: {"book.isbn": "@isbn"}}); + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(2, items.length); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"?C*"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + + function testReadAPI_getLabel(t){ + // summary: + // Simple test of the getLabel function against a store set that has a label defined. + // description: + // Simple test of the getLabel function against a store set that has a label defined. + + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var label = store.getLabel(items[0]); + t.assertTrue(label !== null); + t.assertEqual("Title of 4", label); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; + }, + function testReadAPI_getLabelAttributes(t){ + // summary: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + // description: + // Simple test of the getLabelAttributes function against a store set that has a label defined. + + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request){ + t.assertEqual(items.length, 1); + var labelList = store.getLabelAttributes(items[0]); + t.assertTrue(dojo.isArray(labelList)); + t.assertEqual("title", labelList[0]); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; + }, + + function testReadAPI_getValue(t){ + // summary: + // Simple test of the getValue API + // description: + // Simple test of the getValue API + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.hasAttribute(item,"isbn")); + t.assertEqual(store.getValue(item,"isbn"), "A9B574"); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_getValues(t){ + // summary: + // Simple test of the getValues API + // description: + // Simple test of the getValues API + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.hasAttribute(item,"isbn")); + var values = store.getValues(item,"isbn"); + t.assertEqual(1,values.length); + t.assertEqual("A9B574", values[0]); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_isItem(t){ + // summary: + // Simple test of the isItem API + // description: + // Simple test of the isItem API + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.isItem(item)); + t.assertTrue(!store.isItem({})); + t.assertTrue(!store.isItem("Foo")); + t.assertTrue(!store.isItem(1)); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_isItem_multistore(t){ + // summary: + // Simple test of the isItem API across multiple store instances. + // description: + // Simple test of the isItem API across multiple store instances. + var store1 = dojox.data.tests.stores.XmlStore.getBooks2Store(); + var store2 = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete1(items, request) { + t.assertEqual(1, items.length); + var item1 = items[0]; + t.assertTrue(store1.isItem(item1)); + + function onComplete2(items, request) { + t.assertEqual(1, items.length); + var item2 = items[0]; + t.assertTrue(store2.isItem(item2)); + t.assertTrue(!store1.isItem(item2)); + t.assertTrue(!store2.isItem(item1)); + d.callback(true); + } + store2.fetch({query:{isbn:"A9B574"}, onComplete: onComplete2, onError: onError}); + } + function onError(error, request) { + d.errback(error); + } + store1.fetch({query:{isbn:"A9B574"}, onComplete: onComplete1, onError: onError}); + return d; //Object + }, + function testReadAPI_hasAttribute(t){ + // summary: + // Simple test of the hasAttribute API + // description: + // Simple test of the hasAttribute API + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.hasAttribute(item,"isbn")); + t.assertTrue(!store.hasAttribute(item,"bob")); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_containsValue(t){ + // summary: + // Simple test of the containsValue API + // description: + // Simple test of the containsValue API + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.containsValue(item,"isbn", "A9B574")); + t.assertTrue(!store.containsValue(item,"isbn", "bob")); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_sortDescending(t){ + // summary: + // Simple test of the sorting API in descending order. + // description: + // Simple test of the sorting API in descending order. + var store = dojox.data.tests.stores.XmlStore.getBooksStore(); + + //Comparison is done as a string type (toString comparison), so the order won't be numeric + //So have to compare in 'alphabetic' order. + var order = [9,8,7,6,5,4,3,20,2,19,18,17,16,15,14,13,12,11,10,1]; + + var d = new doh.Deferred(); + function onComplete(items, request) { + console.log("Number of items: " + items.length); + t.assertEqual(20, items.length); + + for(var i = 0; i < items.length; i++){ + t.assertEqual(order[i], store.getValue(items[i],"isbn").toString()); + } + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + + var sortAttributes = [{attribute: "isbn", descending: true}]; + store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_sortAscending(t){ + // summary: + // Simple test of the sorting API in ascending order. + // description: + // Simple test of the sorting API in ascending order. + var store = dojox.data.tests.stores.XmlStore.getBooksStore(); + + //Comparison is done as a string type (toString comparison), so the order won't be numeric + //So have to compare in 'alphabetic' order. + var order = [1,10,11,12,13,14,15,16,17,18,19,2,20,3,4,5,6,7,8,9]; + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(20, items.length); + var itemId = 1; + for(var i = 0; i < items.length; i++){ + t.assertEqual(order[i], store.getValue(items[i],"isbn").toString()); + } + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + + var sortAttributes = [{attribute: "isbn"}]; + store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_sortDescendingNumeric(t){ + // summary: + // Simple test of the sorting API in descending order using a numeric comparator. + // description: + // Simple test of the sorting API in descending order using a numeric comparator. + var store = dojox.data.tests.stores.XmlStore.getBooksStore(); + + //isbn should be treated as a numeric, not as a string comparison + store.comparatorMap = {}; + store.comparatorMap["isbn"] = function(a, b){ + var ret = 0; + if(parseInt(a.toString()) > parseInt(b.toString())){ + ret = 1; + }else if(parseInt(a.toString()) < parseInt(b.toString())){ + ret = -1; + } + return ret; //int, {-1,0,1} + }; + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(20, items.length); + var itemId = 20; + for(var i = 0; i < items.length; i++){ + t.assertEqual(itemId, store.getValue(items[i],"isbn").toString()); + itemId--; + } + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + + var sortAttributes = [{attribute: "isbn", descending: true}]; + store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_sortAscendingNumeric(t){ + // summary: + // Simple test of the sorting API in ascending order using a numeric comparator. + // description: + // Simple test of the sorting API in ascending order using a numeric comparator. + var store = dojox.data.tests.stores.XmlStore.getBooksStore(); + + //isbn should be treated as a numeric, not as a string comparison + store.comparatorMap = {}; + store.comparatorMap["isbn"] = function(a, b){ + var ret = 0; + if(parseInt(a.toString()) > parseInt(b.toString())){ + ret = 1; + }else if(parseInt(a.toString()) < parseInt(b.toString())){ + ret = -1; + } + return ret; //int, {-1,0,1} + }; + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(20, items.length); + var itemId = 1; + for(var i = 0; i < items.length; i++){ + t.assertEqual(itemId, store.getValue(items[i],"isbn").toString()); + itemId++; + } + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + + var sortAttributes = [{attribute: "isbn"}]; + store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_isItemLoaded(t){ + // summary: + // Simple test of the isItemLoaded API + // description: + // Simple test of the isItemLoaded API + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.isItemLoaded(item)); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_getFeatures(t){ + // summary: + // Simple test of the getFeatures function of the store + // description: + // Simple test of the getFeatures function of the store + + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + var features = store.getFeatures(); + var count = 0; + for(i in features){ + t.assertTrue((i === "dojo.data.api.Read" || i === "dojo.data.api.Write")); + count++; + } + t.assertEqual(2, count); + }, + function testReadAPI_getAttributes(t){ + // summary: + // Simple test of the getAttributes API + // description: + // Simple test of the getAttributes API + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + var attributes = store.getAttributes(item); + + //Should be six, as all items should have tagName, childNodes, and text() special attributes + //in addition to any doc defined ones, which in this case are author, title, and isbn + //FIXME: Figure out why IE returns 5! Need to get firebug lite working in IE for that. + //Suspect it's childNodes, may not be defined if there are no child nodes. + for(var i = 0; i < attributes.length; i++){ + console.log("attribute found: " + attributes[i]); + } + if(dojo.isIE){ + t.assertEqual(5,attributes.length); + }else{ + t.assertEqual(6,attributes.length); + } + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testWriteAPI_setValue(t){ + // summary: + // Simple test of the setValue API + // description: + // Simple test of the setValue API + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.containsValue(item,"isbn", "A9B574")); + store.setValue(item, "isbn", "A9B574-new"); + t.assertEqual(store.getValue(item,"isbn").toString(), "A9B574-new"); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testWriteAPI_setValues(t){ + // summary: + // Simple test of the setValues API + // description: + // Simple test of the setValues API + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.containsValue(item,"isbn", "A9B574")); + store.setValues(item, "isbn", ["A9B574-new1", "A9B574-new2"]); + var values = store.getValues(item,"isbn"); + t.assertEqual(values[0].toString(), "A9B574-new1"); + t.assertEqual(values[1].toString(), "A9B574-new2"); + store.setValues(values[0], "text()", ["A9B574", "-new3"]); + t.assertEqual(store.getValue(values[0],"text()").toString(), "A9B574-new3"); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testWriteAPI_unsetAttribute(t){ + // summary: + // Simple test of the unsetAttribute API + // description: + // Simple test of the unsetAttribute API + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.containsValue(item,"isbn", "A9B574")); + store.unsetAttribute(item,"isbn"); + t.assertTrue(!store.hasAttribute(item,"isbn")); + t.assertTrue(store.isDirty(item)); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testWriteAPI_isDirty(t){ + // summary: + // Simple test of the isDirty API + // description: + // Simple test of the isDirty API + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.containsValue(item,"isbn", "A9B574")); + store.setValue(item, "isbn", "A9B574-new"); + t.assertEqual(store.getValue(item,"isbn").toString(), "A9B574-new"); + t.assertTrue(store.isDirty(item)); + d.callback(true); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testWriteAPI_revert(t){ + // summary: + // Simple test of the isDirty API + // description: + // Simple test of the isDirty API + var store = dojox.data.tests.stores.XmlStore.getBooks2Store(); + + var d = new doh.Deferred(); + function onComplete(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.containsValue(item,"isbn", "A9B574")); + t.assertTrue(!store.isDirty(item)); + store.setValue(item, "isbn", "A9B574-new"); + t.assertEqual(store.getValue(item,"isbn").toString(), "A9B574-new"); + t.assertTrue(store.isDirty(item)); + store.revert(); + + //Fetch again to see if it reset the state. + function onComplete1(items, request) { + t.assertEqual(1, items.length); + var item = items[0]; + t.assertTrue(store.containsValue(item,"isbn", "A9B574")); + d.callback(true); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete1, onError: onError}); + } + function onError(error, request) { + d.errback(error); + } + store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError}); + return d; //Object + }, + function testReadAPI_functionConformance(t){ + // summary: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + + var testStore = dojox.data.tests.stores.XmlStore.getBooksStore(); + var readApi = new dojo.data.api.Read(); + var passed = true; + + for(i in readApi){ + var member = readApi[i]; + //Check that all the 'Read' defined functions exist on the test store. + if(typeof member === "function"){ + var testStoreMember = testStore[i]; + if(!(typeof testStoreMember === "function")){ + console.log("Problem with function: [" + i + "]"); + passed = false; + break; + } + } + } + t.assertTrue(passed); + }, + function testWriteAPI_functionConformance(t){ + // summary: + // Simple test write API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test write API conformance. Checks to see all declared functions are actual functions on the instances. + + var testStore = dojox.data.tests.stores.XmlStore.getBooksStore(); + var writeApi = new dojo.data.api.Write(); + var passed = true; + + for(i in writeApi){ + var member = writeApi[i]; + //Check that all the 'Write' defined functions exist on the test store. + if(typeof member === "function"){ + var testStoreMember = testStore[i]; + if(!(typeof testStoreMember === "function")){ + passed = false; + break; + } + } + } + t.assertTrue(passed); + } + ] +); + + + + + +} diff --git a/includes/js/dojox/data/tests/stores/atom1.xml b/includes/js/dojox/data/tests/stores/atom1.xml new file mode 100644 index 0000000..faff9aa --- /dev/null +++ b/includes/js/dojox/data/tests/stores/atom1.xml @@ -0,0 +1,848 @@ + + SOS + ..where the wave finally broke, and rolled back.. Shane O'Sullivan's technical blog + + 2008-01-22T14:32:09Z + WordPress + + + http://shaneosullivan.wordpress.com/feed/atom/ + + + + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Using AOL hosted Dojo with your custom code]]> + + http://shaneosullivan.wordpress.com/2008/01/22/using-aol-hosted-dojo-with-your-custom-code/ + 2008-01-22T14:32:09Z + 2008-01-22T14:32:09Z + + + + + + + + +

The Dojo Ajax Toolkit is kindly hosted by AOL for the consumption of anyone at all. This has the advantage of

+ +
    +
  • Reducing the load on your own server
  • +
  • Speeding up the delivery, as a Content Delivery Network (CDN) is used to ensure that the server is as close as possible to the client, and
  • +
  • The more people who use this the better, as the same Dojo files will be cached when users move from site to site, as they’ll all be downloading the AOL hosted files.
  • +
  • Gzip compression as standard, so the files are as small as possible
  • +
+

Additionally, since release 0.9 onwards, the main Dojo JavaScript file, dojo.js, is always exactly the same, whereas in previous released it changed for every developer who built it.

+

However, the problem comes in where you want to use your own custom code with the hosted Dojo code. This is because the hosted code uses Dojo’s loading system to dynamically load the resources needed on the page, and this will read the files from AOL, not your server (as you would expect - it knows nothing about your server). If you want to build custom layers to improve performance, the remotely hosted Dojo will not be able to find them.

+ +

So, the solution I generally tend to use is to put the AOL dojo.js on every page, and tell Dojo to load any other required files from my own server. To do this, set the baseUrl parameter on the djConfig attribute for the JavaScript file to the folder where Dojo is stored on your server. E.g.

+

<script type=”text/javascript” src=”http://o.aolcdn.com/dojo/1.0.2/dojo/dojo.js” djConfig=”{baseUrl:’/js/dojo/’}”></script>

+ +

Notice here that the file I load is dojo.js, the normal version, not dojo.xd.js, which is the cross domain version capable of loading files from AOL.

+

After doing this, you can then include whatever custom built layers you like onto an particular page. For example, if you have a layer built for the dojox.image.Gallery widget called /js/dojo/dojox/image/Gallery-layer.js, you can load it either dynamically:

+

<script type=”text/javascript”>dojo.require(”dojox.image.Gallery-layer.js”);</script>

+ +

or include it via a script tag:

+

<script type=”text/javascript” src=”js/dojo/dojox/image/Gallery-layer.js”></script>

+

and it should work just as if you were using Dojo from your own server. Only of course you are not - AOL is serving up that file, and in many cases users will already have cached that file, speeding up your site quite nicely.

+

Another approach is to create a custom namespace, register it with Dojo, and put all your layers in there…. but that’s for another post :-)
+ +Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 1 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Dojo Demo Engine Update]]> + + http://shaneosullivan.wordpress.com/2008/01/07/dojo-demo-engine-update/ + 2008-01-12T13:22:38Z + 2008-01-07T01:02:43Z + +

A short while ago I posted about the demo engine I’m writing for the Dojo Ajax Toolkit. Click here to read that post or go to http://www.skynet.ie/~sos/js/demo/dojo/dojoc/demos/featureexplorer.html to see it in action.

+ +

Features

+

Since that post, quite a lot of work has gone into both the features and the content of the demo engine, and the development process has solidified nicely. Some of the features include:

+
    +
  • Tree navigation. A dijit.Tree widget, reading from a remote JSON data store is used to navigate the various demos.
  • +
  • Search feature. A dijit.form.ComboBox widget, reading from the same JSON data store as the tree, can be used to dynamically search for demos by matching any part of their name.
  • + +
  • Theme switcher. A dijit.form.ComboBox widget is used to switch between the CSS styles that Dojo provides.
  • +
  • URL addressability. Using a hash identifier (e.g. #Dojo_Query_By%20Class) in the URL of the demo engine causes it to open that demo when it has finished loading. For example, if you click this link, it will open the dojo.query demo showing you how to select nodes by class name. Opening any demo changes the URL in the browser to the URL for that demo, for easy bookmarking.
  • + +
  • Integrated build process. A simple build script is integrated with the Dojo build process. It builds a JSON data file listing all the existing demos and their respective files. It also builds files with URL links for each demo.
  • +
+

Content

+

To date, a lot of content has been added. Many, many widgets in Dijit and DojoX
+
have have been added, including the majority of the Form Controls.

+ +

The latest, pretty cool additions have been the IO and dojo.query demos. These cover things such as:

+
    +
  • Performing a XMLHttpRequest request
  • +
  • Using an iFrame transport
  • +
  • Submitting a form asynchronously
  • +
  • Loading remote JavaScript files from another domain
  • +
  • Selecting nodes using CSS selectors with dojo.query
  • + +
  • Performing operations on the NodeList returned from dojo.query
  • +
  • Attaching events to the NodeList returned from dojo.query
  • +
+

File Naming Scheme
+A simple file naming scheme is used to add content to the demo framework. Each folder beneath the root folder represents a demo. Each file in a folder must be named the same as the folder, with five possible extensions. For example, given a folder with the name ‘Button‘, the possible files are:

+
    + +
  • Button.html - this contains the demo to be displayed. Any JavaScript code inside <script> tags is executed, and any <link type=”text/css”> and <style> tags have their CSS loaded. The executed code is shown in the View tab, and and the source code is shown in the XML tab. The <html>, <head> and <body> tags are not required.
  • + +
  • Button.js - this contains pure JavaScript code that performs the same operations as Button.html, if applicable. It is not executed however. It is shown in the JS tab.
  • +
  • Button.txt - this contains the text description of the demo. It is loaded above the tabs.
  • +
  • Button.links - this contains a JSON array of URL links. The build script transforms these links into HTML, and the result is loaded into the Links tab. One neat feature of this is that all links from sub folders are integrated with the parent folder and displayed in a nested structure. Do, for example, clicking on Dijit will show all the links for all widgets in the Dijit project.
  • + +
  • Button.full.html - this is standalone demo, that is designed to run outside the demo engine. The View tab provides a link to the external file.
  • +
  • sort.txt - this contains a comma separated list of the child folders contained in this folder. It specifies the order in which to display the child demos in the tree. If this file is not specified, then an alphabetical ordering is used.
  • +
+

All of these files are optional. If a file in a folder does not match this naming scheme, it is assumed to be some kind of resource that the demo needs, such as an image or a JSON data file. In this case, the file can be named whatever you like.

+

The tree structure in the demo engine mirrors the folder layout.

+ +

Still To Do

+

There remains quite a lot of work ahead. There are a few bugs remaining, some more cross browser testing is needed, and of course more content is required, particularly the base Dojo package.

+

In the relatively near future this should be opened up to the public for development. The Dojo folks are setting up a source control server for community additions, and this demo engine should be part of that. Once that is done, people can start adding all sorts of cool stuff!
+Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 3 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Navigating in an IE Modal Dialog]]> + + http://shaneosullivan.wordpress.com/2007/12/31/navigating-in-an-ie-modal-dialog/ + 2007-12-31T16:36:21Z + 2007-12-31T16:36:21Z + +

Internet Explorer has a nice feature where a new window can be opened modally using the window.showModalDialog function, meaning that the page that opened it cannot be accessed until the new window is closed. This can be useful in many situations.

+ +

However, the main limitation of IE Modal Dialogs (other than being non-standard), is that any hyperlink clicked in a modal dialog causes another, non modal, dialog to be opened, rather than opening the page linked to in the same window, as would happen in a normal pop up window.

+

The key to solving this problem is to note that a modal dialog only opens another window when a GET request is made, not when a POST request is made. However, an anchor tag automatically causes a GET request, so the solution is to:

+
    +
  1. Catch the click on each anchor tag, cancel it,
  2. +
  3. Submit a dynamically created FORM element, with it’s method set to ‘POST’ and it’s action set to the URL of the link clicked.
  4. + +
+

While it is possible to put a listener on each anchor tag to achieve this, such an approach will not scale well. Instead, place a listener on the body tag. The example below is done using methods from the Dojo Ajax Toolkit, since that the toolkit I use the most, but you can of course use whatever methods you like to achieve the same result:

+

<script type="text/javascript">
+dojo.addOnLoad(function(){
+dojo.connect(dojo.body(), “onclick”, function(evt) {
+if(evt.target.tagName != “A”) {return true;}
+dojo.stopEvent(evt);
+var form = document.createElement(”form”);
+form.setAttribute(”target”, window.name ? window.name : “SrPopUp”);
+form.setAttribute(”action”, url);
+form.setAttribute(”method”,”POST”);
+document.appendChild(form);
+form.submit();
+return false;
+});
+});
+ +</script>

+

This method assumes that you have control over the content of the page being shown in the modal dialog. It would also make sense to add a similar listener to the body tag for key events, as a user can trigger an anchor tag by tabbing to it and hitting enter.

+

Thanks to Danny Goodman and Steiner Overbeck Cook for coming up with this solution.
+Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 1 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[A new Demo engine for Dojo]]> + + http://shaneosullivan.wordpress.com/2007/12/04/a-new-demo-engine-for-dojo/ + 2008-01-12T13:23:15Z + 2007-12-04T09:29:16Z + +

A couple of weeks ago I saw a cool demo framework for an Ajax toolkit just released as open source. It’s a very slick implementation, with a tree listing all the various demos, and a tabbed area showing the implementation, and the widget in practice.

+ +

So, I think to myself, this is exactly what the Dojo Ajax Toolkit is missing! Cut to today, and I’ve put the first rough cut at the demo framework on the web for people’s perusal. Check it out at http://www.skynet.ie/~sos/js/demo/dojo/dojoc/demos/featureexplorer.html .

+

Note: I have written a follow up post here.

+

Some of the features include:

+
    + +
  • Tree navigation for the demos. Demos can be nested as deep as required.
  • +
  • View tab. This shows the widgets in action.
  • +
  • HTML tab. This shows how to instantiate the widget using HTML markup.
  • +
  • JS tab. This shows how to instantiate the widget using JavaScript code.
  • +
  • Links tab. This shows various hyperlinks to alternate content for that demo, e.g. the Dojo Book.
  • +
  • Demo description. Gives a text description of the demo.
  • +
  • Theme selector. This allows you to change from one CSS theme to another
  • +
  • Ability to link to standalone demos that open in a new page. This is useful for large demos that show the integration of many widgets together, and may not fit well within the demo framework itself. See the Dijit/Mail demo for an example of this.
  • + +
  • A build system that takes a very simple naming scheme for the demos, and creates a JSON data store that the framework runs off of. So, whenever a user adds a new demo, they simply have to re-run the build step, and that’s it! No need for a server side script, so you can run this right off your hard drive.
  • +
+

This is still very much beta code, and there are a couple of errors floating around, but those will of course be hunted down. There are also some Internet Explorer issues that I’ll get to soon, so try this in Firefox for now (update Dec 05 2007 - most of these have been solved, with one or two small bugs remaining). I’m in discussions to get this into the Dojo toolkit, so that the community at large can start adding in demos. I’ve put in quite a few already, but it’s so easy to do that this could become a huge resource for the Dojo community.

+

If you have any suggestions, please let me know.

+

Demo Framework
+ +Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 3 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Upgrading Ubuntu Feisty Fawn (7.04) to Gutsy Gibbon (7.10)]]> + + http://shaneosullivan.wordpress.com/2007/10/18/upgrading-ubuntu-feisty-fawn-704-to-gutsy-gibbon-710/ + 2008-01-12T10:26:42Z + 2007-10-18T16:11:37Z + +

Today I’ve begun the process of upgrading my Ubuntu installation of version 7.04 to version 7.10. To see my previous tutorial of getting Ubuntu installed on my IBM Thinkpad X41, see http://shaneosullivan.wordpress.com/2007/02/16/installing-ubuntu-edgy-on-a-thinkpad-x41-tablet/.

+ +

This post lists whatever issues I found when upgrading, and my solutions to them. For the official instructions, see https://help.ubuntu.com/community/GutsyUpgrades.

+

Third Party software sources cause problems

+

My first problem was caused by having links to third party software distribution sites. When running the “update-manager -d” command, I received an error, saying the dbus couldn’t run.

+

This was caused by having third party software sources enabled that no longer existed, for whatever reason.

+ +

To fix this:

+
    +
  1. click “System/Administration/Software Sources”
  2. +
  3. Click the “Third-Party Software” tab
  4. +
  5. Deselect any non-Ubuntu software sources. You can always reselect them after the upgrade
  6. + +
+

Modifying the software channels gets stuck

+

When the second step in the “Distribution Upgrade” application is running, that is, the “Modifying the software channels” step, it got stuck downloading files. It would say

+

Downloading file 36 of 97

+

and stay at that number for a long time. This was not a bandwidth issue, it simply stopped. To fix this

+
    +
  1. Click the “Cancel” button.
  2. + +
  3. Run the “update-manager -d” command again.
  4. +
  5. Repeat this each time it gets stuck downloading files. I had to do this four times for it to work completely.
  6. +
+

Dual monitors didn’t work correctly

+

When booted up with an external monitor plugged in, the desktop was fixed at 640 * 480 pixels resolution. I found someone else with a similar issue at http://ubuntuforums.org/showthread.php?t=566947 , but their solution didn’t work for me. I solved this by:

+ +
    +
  1. Unplugging the monitor.
  2. +
  3. Restart the machine, and log in.
  4. +
  5. Click “System/Administration/Screens and Graphics
  6. +
  7. Click the “Graphics Card” tab.
  8. + +
  9. Click the “Driver” button
  10. +
  11. From the “Driver” dropdown list, choose “i810 - Intel Integrated Graphics Chipsets
  12. +
  13. Restart the machine.
  14. + +
+

Compiz has problems with dual monitors

+

Compiz (the 3D graphics stuff) causes problems and refuses to work at all if I am using dual monitors. Still working on this one.

+

Some Eclipse plug-ins no longer work

+

As a Java developer, I often use the Eclipse development platform. I include some non-standard plugins in the application, like plugins for Subversion support. However, when Ubuntu is upgraded to 7.10, the base Eclipse platform in upgraded, but not the non-standard plugins, which stops some of them from working.

+

Update: actually, this didn’t fix my Eclipse problems, please ignore :-)

+ +

The solution is to upgrade the plugins in the usual Eclipse manner:

+
    +
  1. Open Eclipse
  2. +
  3. Click Help/Software Updates/Find and Install
  4. +
  5. Click Finish
  6. +
  7. Wait a while…
  8. +
+ +

Running low on disk space after upgrade

+

My laptop was running out of disk space after the install, as it downloaded quite a few packages. I found a very good blog post on how to clean up your Ubuntu install at http://www.ubuntugeek.com/cleaning-up-all-unnecessary-junk-files-in-ubuntu.html.

+

Make sure to read comment #7 also, that alone saved me 1GB.

+

Some Thinkpad features no longer work

+

I found that some things didn’t work that did work before, for example the stylus pen and the middle ’scroller’ button of the mouse. If this happens, just reapply the settings I describe here, as the upgrade removed them. This solved the problems for me.

+ +

Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 25 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Introducing the new Dojo Image Widgets]]> + + http://shaneosullivan.wordpress.com/2007/10/13/introducing-the-new-dojo-image-widgets/ + 2008-01-08T11:23:13Z + 2007-10-13T11:09:13Z + + + + + + + + + + + + + + + + +

In previous posts (here for the Dojo 0.4.3 version, here and here), I wrote how I wrote an image gallery for version 0.4.3 of the Dojo Ajax Toolkit, and how I was translating it for the latest version of the toolkit, version 1.0.

+ +

Well, that work is now, finally, complete, and I have to say, I’m pretty damn happy with the results. The code is now part of the dojox.image project (dojox is the Dojo extensions project, for cool new code that may in the future make it into the core code base if enough people like/want it).

+

If you’d like to just see the gallery in action, have a look at the Photos page on my personal website, or see the links at the bottom of the post, otherwise, read on!

+

Update: changes have been made to the widgets since this post was written, resulting in some badly aligned images. This will be fixed in the next few days. (Oct 25th 2007)

+

Update: issue above has been fixed (Oct 29th 2007)

+ +

All For One….

+

The gallery is composed of three widgets:

+
    +
  • dojox.image.ThumbnailPicker - a widget to list many small images in either a horizontal or vertical orientation, scroll through them, and attach click events that other widgets can listen to
  • +
  • dojox.image.SlideShow - a widget that displays one image at a time, and can run a slideshow, changing the images every ‘x’ seconds.
  • +
  • dojox.image.Gallery - A wrapper around the ThumbnailPicker, and SlideShow widgets.
  • + +
+

Both the ThumbnailPicker and Slideshow widgets can also be used on their own, and have no dependencies on each other.
+

+

Dojo Data Is Too Cool for School

+

One of the coolest features of all of these widgets is that they all feed off image data provided by the dojo.data API. What this basically means is that each widget can display images from any source, with no modification whatsoever. You simply pass it a Dojo data store, and is shows the pictures. Some of the data stores currently in the Dojo toolkit include:

+
    +
  • dojo.data.ItemFileReadStore - pull in simple JSON data in an array. You could use this if you simply have a directory of images on your own web server you would like to display
  • +
  • dojox.data.FlickrRestStore (demo) - query the Flickr photo sharing website for images. This is all done on the browser, with no need for any server-side redirects. This is another of my additions to the Dojo toolkit - I love Flickr, feel free to check out my photo stream here. I previously wrote another blog post on this data store here.
  • + +
  • dojox.data.PicasaStore (demo) - query Google’s Picasa image sharing website for images. As with the Flickr data store, this is done on the browser, with no need for server side support.
  • +
+

and many more….. You can also write your own data store if you so desire, but the ones included in the toolkit should cover almost everything you might need.

+

Gimme, Gimme, Gimme!

+

So, how can I get this, you ask! Well, you can:

+ +

Update: Dojo 1.0 is now released. Get it at http://www.dojotoolkit.org/downloads
+As always, any and all feedback is welcome. Also, a big thanks to Peter Higgins, owner of the dojox.image project, and Jared Jurkiewicz, owner of the dojo.data project, for all their helpful ideas, and for reviewing/committing my code to the Dojo project.
+Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 46 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Dojo Grid has landed]]> + + http://shaneosullivan.wordpress.com/2007/10/05/dojo-grid-has-landed/ + 2007-10-14T21:46:03Z + 2007-10-05T13:23:17Z + +

The previously announced Dojo Grid has landed in source control, and is in the nightly builds. It has all sorts of fancy functionality, like support for lazy loading huge data sets, individual styling of rows and columns, inline editing etc.

+ +

Check it out at http://archive.dojotoolkit.org/nightly/checkout/dojox/grid/tests/

+

Very cool stuff!

+

Update: The Sitepen guys have recently blogged about the grid at http://www.sitepen.com/blog/2007/10/13/dojo-grid-update/

+

Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 0 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[A TortoiseSVN replacement for Ubuntu]]> + + http://shaneosullivan.wordpress.com/2007/10/04/a-tortoisesvn-replacement-for-ubuntu/ + 2007-10-04T15:50:50Z + 2007-10-04T15:50:50Z + +

I work on a number of open source projects, and many of them use the Subversion version control system to manage their code. Before my switch from Windows XP to Ubuntu Linux (which I am still ecstatically happy with btw), I became a big fan of TortoiseSVN, an extremely useful Subversion client that integrates itself directly into Windows Explorer.

+ +

TortoiseSVN is simple to use, very intuitive, and does everything I need from it. You simply right click on a folder you want to store your checked out files in, give it the URL of the Subversion server, and it checks out the code, updates it, checks it back in (if you have permission), performs file diffs ….. basically everything you need to do is integrated right in with your file browser.

+

So, I miss this in Ubuntu, as TortoiseSVN is Windows only. However, I recently found a replacement, which integrates nicely with Nautilus, the Ubuntu file browser. While it is not as slick as TortoiseSVN, it works in a very similar way. You right click on a folder, and have a selection of SVN operations you can perform.

+

See http://marius.scurtescu.com/2005/08/24/nautilus_scripts_for_subversion for details.

+

Nautilus Subversion Menu

+

Nautilus Subversion Dialog

+

One thing that is missing from this is the display of icons in the file browser (Nautilus) to inform you of the state of a file - checked out, modified, not added to source control etc. Another person has developed a solution to this, which unfortunately I have not, yet, been able to get working, but perhaps you will have more luck.

+ +

See http://www.kryogenix.org/days/2006/09/12/extremely-noddy-tortoisesvn-for-the-gnome-desktop for details on this.
+Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 3 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Querying Flickr with Dojo!]]> + + http://shaneosullivan.wordpress.com/2007/09/22/querying-flickr-with-dojo/ + 2007-09-22T18:26:51Z + 2007-09-22T16:10:05Z + +

I’ve recently submitted a new data store for the Dojo Ajax Toolkit that makes it very simple to query Flickr for your and other peoples images. For those not familiar with Flickr, it is a photo sharing website, one of the most popular on the net. However, what makes it quite special is the comprehensive public APIs that it exposes.

+ +

While these APIs are extremely useful, however, they are also very complex, with a steep learning curve before you can even get started. In steps Dojo and their new Data API specification, whose stated aim is to have a single unified interface to all data sources, so that users of a data store won’t have to care if they’re reading from a database, from a XML or JSON file, or from some remote service like Flickr.

+

So, long story short, I’ve written an implementation of the Dojo Data APIs to query data from Flickr. It is part of the DojoX project, and is called dojox.data.FlickrRestStore. It provides quite a few methods of querying for photos:

+
    +
  • By one or more tags, matchine any or all of them
  • +
  • By user id
  • + +
  • By set id
  • +
  • Full text search
  • +
  • Sorting on date taken, date published or ‘interestingness’
  • +
+

FlickrRestStore also performs caching of image data, so if you request the data twice it won’t make a second remote request.

+

The store is also designed to be accessed by multiple clients simultaneously. If two clients request the same data, only one request is made, with both clients being notified of the identical results.

+

Examples

+ +

I’ve put a fairly comprehensive set of examples in the Dojo book at http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo
+/using-dojo-data/available-stores/flickr-rest-s#examples
.

+

You can see a Demo of it running at http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/data/demos/demo_FlickrRestStore.html .

+

The unit tests cover quite a few cases also, and you can see them at http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/data/tests/stores/FlickrRestStore.js

+

To get the code, you can:

+ + +

Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 3 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Specifying the callback function with the Flickr JSON APIs]]> + + http://shaneosullivan.wordpress.com/2007/09/13/specifying-the-callback-function-with-the-flickr-json-apis/ + 2007-09-13T09:54:53Z + 2007-09-13T09:31:30Z + +

Flickr is a photo sharing website that has a very flexible set of APIs that other applications and websites can use to access the photos it stores. This post shows you how to specify a callback function that Flickr can call to pass your web application information on photos it stores.

+ +

Quite a while ago I looked into the Flickr APIs for a website I was writing. Looking at the service that returns photo data in JSON (Javascript Object Notation), I noticed that it did so by calling a predefined function, jsonFlickrApi, passing in the data to that function. This seemed to be an obvious weak spot, since if more than one widget on a page were accessing the Flickr REST services, they would clash with each other, possibly receiving each others data. Obviously not a good thing.

+

Cut to today. I’ve been working on a JavaScript data store that operates against the Flickr REST services for the Dojo Ajax Toolkit, and had another look at the Flickr APIs. Now, whether I missed it before (doubtful, as I looked specifically for it), or the fine Flickr folk have listened to complaints (very likely), but there is now a parameter that can be passed to the Flickr API that specifies the callback function to use when the data is retrieved from Flickr.

+

All you have to do is pass a parameter jsoncallback to Flickr, with the name of the function you want to be called with the data, and thats it.

+ +

E.g. if I had a function:

+

function myCallbackFunction(data) {

+

alert(”I received ” + data.photos.photo.length +” photos”);

+

}

+

I could then specify a <script> element in my HTML page to retrieve the data in a cross site manner (since you can’t make cross site XmlHttpRequest calls), like so:

+ +

<SCRIPT type=”text/javascript” src=”http://www.flickr.com/services/rest/?format=json&jsoncallback=myCallbackFunction
+&method=flickr.people.getPublicPhotos
+&api_key=8c6803164dbc395fb7131c9d54843627
+&user_id=44153025%40N00&per_page=1″>

+ +

</SCRIPT>

+

Note the jsoncallback parameter in the src attribute. This results in JavaScript similar to:

+

myCallbackFunction({”photos”:{”page”:1, “pages”:489, “perpage”:1, “total”:”489″, “photo”:[{”id”:”1352049918″, “owner”:”44153025@N00″, “secret”:”5636009306″, “server”:”1111″, “farm”:2, “title”:”The Liffey Panorama”, “ispublic”:1, “isfriend”:0, “isfamily”:0}]}, “stat”:”ok”});

+ +

being called.

+

Thanks Flickr! Nice to see them listening, and continually improving. This will make web applications built on Flickr much more robust, without the need of ridiculous hackery to get around unnecessarily difficult APIs. See http://www.flickr.com/services/api/response.json.html for the offical info on JSON responses.

+

Keep an eye out for my dojox.data.FlickrRestStore being release some day soon!!
+Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 0 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Image Gallery, Slideshow, and Flickr data source for Dojo 0.9]]> + + http://shaneosullivan.wordpress.com/2007/09/04/image-gallery-slideshow-and-flickr-data-source-for-dojo-09/ + 2007-09-05T08:32:22Z + 2007-09-04T23:32:51Z + +

In a previous post (see here) I spoke about how I’d written an Image Gallery widget that worked with Dojo Ajax Toolkit version 0.4.2 and 0.4.3. I contacted the good folks at Dojo about updating it for the latest release, 0.9, and adding it to the toolkit.

+ +

They were very receptive to the idea, with a few suggestions. Firstly, rather than having its own method of storing information, it should run off the dojo.data API, and secondly, it should go into the newly created dojox.image project.

+

Both of these suggestions were perfectly reasonable, so, cut to a few weeks later and I’ve finished my first pass at converting over the code from 0.4.3 to 0.9. As the Dojo APIs have changed drastically recently, this was no simple matter, but thats the subject of another blog post.

+

The code is not finished (or even checked in) yet, but you can see some examples of it running from test pages. There are two separate widgets:

+
    +
  • dojox.image.SlideShow - a simple widget that runs a slide show of images, with urls loaded from a dojo.data store.
  • +
  • dojox.image.ImageGallery - this wraps the SlideShow widget, adding thumbnail views. This is also loaded from a dojo.data store.
  • +
+

Finally, I’ve implemented a dojo.data store that reads from the Flickr REST APIs, to pull down lists of photos. This store is more complex than the existing Flickr store, as it does caching of results, as well as going against a much more flexible API, meaning that expanding its capabilities later is possible.

+ +

Whether or not this goes into dojox or not is still undecided. However, you can see the widgets running using this data store.

+

See the test files at http://www.skynet.ie/~sos/js2/dojox/image/tests for examples of this working.

+

Note that this is NOT the final code. It may still be buggy, may look different in the future (it’s pretty basic now), and the code will be cleaned up. However, if you have any suggestions, please feel free to leave comments on this post.

+

Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 1 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Dojo event performance tip]]> + + http://shaneosullivan.wordpress.com/2007/08/23/dojo-event-performance-tip/ + 2007-08-23T12:38:36Z + 2007-08-23T12:29:08Z + +

When working with the Dojo Ajax Toolkit and using it’s dojo.event package to listen to DOM and custom events, the two most common approaches are:

+ +
    +
  1. Listen for an event (or function call) to be triggered on an object, and when it is to run a custom function, e.g.
    + var alertFn = function() {alert(”widget is showing”);};
    +dojo.event.connect(myWidget, “onShow”, alertFn);
  2. +

    This basically says that when the “onShow” function is called on some widget, called myWidget, run a function that does a simple alert. Of course you can do whatever you like inside this function.

    + +
  3. Listen for an event (or function call) to be triggered on an object, and when it is to run a custom function defined in the scope of an object, e.g.
    + var myObj = {
    +alertFn: function() {alert(”widget is showing”);}
    +};
    +dojo.event.connect(myWidget, “onShow”,myObj, “alertFn”);

    +

    This is saying that I have an object called “myObj“, which has a function called “alertFn“, and when the “onShow” method on “myWidget” is called, call the “alertFn” function on “myObj“.

  4. + +
+

I’ve found that when working with Dojo version 0.4.2 and 0.4.3, using the second approach is far far quicker. It turns out that internally, if you simply pass an anonymous function to Dojo, it will add that function to an internal structure and do a brute force search on that internal structure to make sure that this function is unique. This can result in a very significant performance hit - I’ve seen it take up over 50% of the startup time of a page on one of our more JavaScript heavy applications.

+

So, the conclusion is that if you are dojo.event.connect, which is one of the most useful functions in the toolkit, make sure to use four arguments to the function (approach #2 above), rather than just three (approach #1 above). If necessary, place a simple wrapper around the function as I have shown.
+Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 0 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Dojo 0.9 released]]> + + http://shaneosullivan.wordpress.com/2007/08/22/dojo-09-released/ + 2007-09-04T15:23:50Z + 2007-08-22T10:24:51Z + +

The latest version of the Dojo Ajax Toolkit has just been released into the wild. Version 0.9 is a very streamlined progression of the toolkit, with many of the less essential features pushed out to another project, DojoX, and the Dojo widgets given their own project, Dijit.

+ +

Another big change is the the main JavaScript file in Dojo, dojo.js, is no longer customisable. It now contains the most common features required by most web developers, and nothing more. As a result, it is far smaller than previous incarnations, down to ~24k when gzipped.

+

Some resources:

+

James Burke has written up a very informative post about what exactly is baked into the default build of dojo.js, which you can find at http://dojotoolkit.org/2007/08/22/dissecting-0-9s-dojo-js . Well worth a read.

+

Bill Keese wrote up a guided tour of 0.9 at http://dojotoolkit.org/2007/08/20/dijit-0-9-guided-tour.

+

The Dojo book for version 0.9 can be found at http://dojotoolkit.org/book/dojo-book-0-9-0. It’s almost finished (almost!) as of today, Aug 22 2007.

+ +

The Ajaxian post on Dojo 0.9 can be read at http://ajaxian.com/archives/dojo-09-final-version-released.

+

Download the toolkit from http://build.dojotoolkit.org/0.9.0. This page gives some information on how you can use Dojo from AOL’s hosting servers, so you never have to download it at all.
+Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 2 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Dojo theme browser shows off Dijit widgets]]> + + http://shaneosullivan.wordpress.com/2007/08/17/dojo-theme-browser-shows-off-dijit-widgets/ + 2007-11-05T13:45:45Z + 2007-08-17T12:18:57Z + +

The Dojo/Dijit (Dojo’s widget project) toolkit has created a page where you can view many of their widgets using the four CSS themes written so far for Dojo. This is cool for a couple of reasons.

+ +

Firstly, it showcases the excellent work the Dijit developers have put into new themeing skins. There are four themes completed so far, and changing the look of Dojo is now as simple as including a different CSS file on your web page. All Dijit widgets now run off a single CSS file, rather than each having their own CSS file.

+

Secondly, it shows the usage of many of Dijit’s widgets (say that five times in a row! :-) ). Many of the demos from the 0.4.* days are gone now, and this is about as comprehensive a demo of Dojo’s widgets as you’re likely to see for a while. And yes, they are very nice indeed.

+

Go to http://archive.dojotoolkit.org/nightly/dojotoolkit/dijit/themes/themeTester.html to see the default theme (tundra) in use. Click on the “Alternate Themes” tab at the bottom of the page to switch themes to one of the alternate themes.

+ +

Enjoy!

+

Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 2 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Why is my web page slow? YSlow for Firebug can tell you.]]> + + http://shaneosullivan.wordpress.com/2007/07/25/why-is-my-web-page-slow-yslow-for-firebug-can-tell-you/ + 2007-07-26T08:28:03Z + 2007-07-25T15:08:30Z + +

Yahoo have released a very useful extension for Firebug, which is itself an extension for Firefox, which can be used to analyze a web page’s performance. The extension, called YSlow, appears as a separate pane in Firebug, and gives you a whole load of statistics about your page.

+ +

However, in addition to the bare numbers, it also gives your page a ranking, from zero to a hundred, and offers tips in plain English on you can improve the performance of your page.

+

All in all, a very handy little addition to a web developer’s toolkit.

+

One caveat is that it is of course not perfect - I tried to use it on Gmail, and it gave the site a 98% mark (practically impossible to achieve in reality), as the initial page of the Gmail application simply loads a single JavaScript page and not much else. Therefore, YSlow seems to only analyze content sent down the wire to browser upon page load, and ignores generated content. However, this does not take away from the fact that it is perfectly suitable for the vast majority of websites out there.

+

More information available here, or read Ajaxian’s post here.
+Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 1 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Flickr and Dojo Image Gallery]]> + + http://shaneosullivan.wordpress.com/2007/07/03/flickr-and-dojo-image-gallery/ + 2007-07-19T10:44:19Z + 2007-07-03T15:53:33Z + +

I have created an Image Gallery widget built on Dojo 0.4.3 that integrates nicely with Flickr. The widget it written entirely using JavaScript and CSS as a standalone Dojo widget, and is released under the same open source license as Dojo, the Academic Free License.

+ +

For more information, including the code and examples, see http://www.skynet.ie/~sos/ajax/imagegallery.php.

+

Some of the features of the widget include:

+
    +
  • Pages of thumbnails.
  • +
  • Intelligent pre-loading of images so the images you are looking at are loaded first.
  • +
  • Fade effects for transitioning of images
  • +
  • Populated using JSON data - any JSON data, not just Flickr.
  • +
  • Flickr integration - remotely load your Flickr images.
  • + +
  • Paging through a Flickr collection.
  • +
  • Slideshow
  • +
+

The widget can be instantiated from both HTML markup and programmatically in JavaScript.

+

To view your own Flickr pictures on the widget, without installing it on your own site, go to http://www.skynet.ie/~sos/ajax/yourpics.php .

+

There is a discussion thread in the Flickr API group at http://www.flickr.com/groups/api/discuss/72157600624623643.

+

So, why create this widget? Well, firstly I wanted a JavaScript image gallery that would list thumbnails and allow me to page through Flickr photos. Also, a slide show would have been nice. I was surprised to discover that I couldn’t find one that I liked in the twenty or so minutes I spent looking for one. I found a handy Flash based one, but I wanted a HTML and JavaScript only widget. So I grabbed Dojo 0.4.3 (my JavaScript library of choice right now) and wrote one.

+ +

Here is a screen shot:

+


+Screenshot

+

The widget has all the features that I personally require at the moment, but will probably evolve as I think of new things to add. If you have any suggestions/bug reports, please comment on this post.

+

Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 7 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Is Dojo being ignored by developers?]]> + + http://shaneosullivan.wordpress.com/2007/06/19/is-dojo-being-ignored-by-developers/ + 2007-06-26T10:18:09Z + 2007-06-19T10:36:49Z + +

The two main areas of interest for me over the last year or two, blog-wise that is, have been the Dojo Ajax toolkit, one of the more popular open source JavaScript toolkits, and Ubuntu Linux, the very popular operating system that is seen by many as the best chance Linux has of succeeding on the desktop.

+ +

Due to the fact that my blog is hosted on Wordpress.com, I am provided with very detailed statistics on which blog posts are more popular, what days they are accessed on etc. Looking at these, a very definite trend has become apparent

+

While the number of hits received by the Ubuntu blogs remains more or less steady, hits on Dojo blog posts falls dramatically on the weekend.

+

While this is not an exact measurement by any means, it points to a worrying possibility. People are obviously working with Ubuntu on their spare time, installing it, upgrading, adding applications and window managers etc, and need help doing this. They are personally interested in Ubuntu, not just professionally. This is one of the main reasons for Ubuntu’s success - people are excited and motivated by it. They want to work and play with it on their own time.

+ +

This does not seem to be the case for Dojo.

+

Dojo has the backing of many large and small companies, including two I have worked for, my previous employer IBM, and my current employer Curam. Both of these are attracted to Dojo for a number of reasons, chief among them being it’s good design and wide range of features. The very large size of the toolkit is not a problem for them (and corporations in general) because it will be included in websites that employees will use to do their everyday work tasks (e.g. using a corporate installation of IBM WebSphere Portal), so the JavaScript is cached and the performance hit is avoided.

+

However, for hobbyists, this is not the case. A person might only visit a single page on their website, and a ~200KB overhead for perhaps something simple like a collapsible menu and some fading effects is simply not feasible. I’ve experienced this recently when writing a simple website for myself - all I wanted was some fading/sliding effects, but the huge overhead just wasn’t worth it. And I am a very big supporter of Dojo (I’ve contributed code even - here and here), and use it every day at work.

+ +

The Dojo team are working hard on the 0.9 release, which is addressing many of these issues, bringing the base size down to a more manageable size (at time of writing dojo.js is down to 68KB). I look forward to the day when my site statistics change, when Dojo can stand on the shoulders of many thousands of enthusiastic hackers rather than being held up by a few big corporations. I really do.

+

However, this does not seem to be the case today. Version 0.9 has a lot of work to do.
+Share this post: digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 5 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Dojo Charting example to show website statistics]]> + + http://shaneosullivan.wordpress.com/2007/06/15/dojo-charting-example-to-show-website-statistics-2/ + 2007-06-15T12:38:24Z + 2007-06-15T12:35:35Z + +

I’ve created an example usage of the Dojo Charting engine, which you can find at http://www.skynet.ie/~sos/pageStats.php. View the source to see how it works.
+It’s a modified version of the unit test available with the Dojo toolkit, but used in a specific scenario - in this case, to graph the page impressions for my personal website . The JSON data on the page is dynamically generated by PHP, however all other processing is done in JavaScript.

+ +

You can filter the data to show info on any combination of pages, and also use a number of different chart types.

+

The code is well documented, so should be easy to follow.
+Some other good examples of using the Dojo Charting engine can be found here and here.
+Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 4 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[GreaseMonkey script to add Digg-like links to posts]]> + + http://shaneosullivan.wordpress.com/2007/05/22/greasemonkey-script-to-add-digg-like-links-to-posts/ + 2007-05-23T14:56:07Z + 2007-05-22T16:57:02Z + +

I decided today that I wanted to put links at the bottom of each of my blog posts that would allow people to perform actions on the post, e.g:

+ + +

My blog is on Wordpress.com which doesn’t seem to have a plugin that will allow me to do this. So, I got off my ass and wrote a GreaseMonkey Firefox script that’ll do it for me. You can download this script by going to http://userscripts.org/scripts/show/9421 and clicking the “Install This Script” button.

+ +

The links that are inserted are at the bottom of this post. The script is open source (GPL license), so take it, play with it, whatever. If you find any bugs, please let me know by commenting on this post.
+Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

+ + ]]>
+ + + 8 +
+ + + Shane O'Sullivan + http://shaneosullivan.wordpress.com/ + + <![CDATA[Article on the square pegs and round holes of desktop and web applications]]> + + http://shaneosullivan.wordpress.com/2007/05/22/article-on-the-square-pegs-and-round-holes-of-desktop-and-web-applications/ + 2007-05-22T08:57:59Z + 2007-05-22T08:49:00Z + +

Bill Higgins of IBM has written a very well thought out article of why web applications should look and act like web applications, and not the desktop variety. Well worth a read - http://billhiggins.us/weblog/2007/05/17/the-uncanny-valley-of-user-interface-design

+ + ]]>
+ + + 0 +
+
+ diff --git a/includes/js/dojox/data/tests/stores/books.html b/includes/js/dojox/data/tests/stores/books.html new file mode 100644 index 0000000..8535cec --- /dev/null +++ b/includes/js/dojox/data/tests/stores/books.html @@ -0,0 +1,118 @@ + + + Books.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
isbntitleauthor
1Title of 1Author of 1
2Title of 2Author of 2
3Title of 3Author of 3
4Title of 4Author of 4
5Title of 5Author of 5
6Title of 6Author of 6
7Title of 7Author of 7
8Title of 8Author of 8
9Title of 9Author of 9
10Title of 10Author of 10
11Title of 11Author of 11
12Title of 12Author of 12
13Title of 13Author of 13
14Title of 14Author of 14
15Title of 15Author of 15
16Title of 16Author of 16
17Title of 17Author of 17
18Title of 18Author of 18
19Title of 19Author of 19
20Title of 20Author of 20
+ + diff --git a/includes/js/dojox/data/tests/stores/books.xml b/includes/js/dojox/data/tests/stores/books.xml new file mode 100644 index 0000000..4c330e6 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/books.xml @@ -0,0 +1,103 @@ + + + + 1 + Title of 1 + Author of 1 + + + 2 + Title of 2 + Author of 2 + + + 3 + Title of 3 + Author of 3 + + + 4 + Title of 4 + Author of 4 + + + 5 + Title of 5 + Author of 5 + + + 6 + Title of 6 + Author of 6 + + + 7 + Title of 7 + Author of 7 + + + 8 + Title of 8 + Author of 8 + + + 9 + Title of 9 + Author of 9 + + + 10 + Title of 10 + Author of 10 + + + 11 + Title of 11 + Author of 11 + + + 12 + Title of 12 + Author of 12 + + + 13 + Title of 13 + Author of 13 + + + 14 + Title of 14 + Author of 14 + + + 15 + Title of 15 + Author of 15 + + + 16 + Title of 16 + Author of 16 + + + 17 + Title of 17 + Author of 17 + + + 18 + Title of 18 + Author of 18 + + + 19 + Title of 19 + Author of 19 + + + 20 + Title of 20 + Author of 20 + + diff --git a/includes/js/dojox/data/tests/stores/books2.html b/includes/js/dojox/data/tests/stores/books2.html new file mode 100644 index 0000000..c0b3550 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/books2.html @@ -0,0 +1,43 @@ + + + Books2.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
isbntitleauthor
A9B57CTitle of 1Author of 1
A9B57FTitle of 2Author of 2
A9B577Title of 3Author of 3
A9B574Title of 4Author of 4
A9B5CCTitle of 5Author of 5
+ + \ No newline at end of file diff --git a/includes/js/dojox/data/tests/stores/books2.xml b/includes/js/dojox/data/tests/stores/books2.xml new file mode 100644 index 0000000..d1fa494 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/books2.xml @@ -0,0 +1,28 @@ + + + + A9B57C + Title of 1 + Author of 1 + + + A9B57F + Title of 2 + Author of 2 + + + A9B577 + Title of 3 + Author of 3 + + + A9B574 + Title of 4 + Author of 4 + + + A9B5CC + Title of 5 + Author of 5 + + diff --git a/includes/js/dojox/data/tests/stores/books3.html b/includes/js/dojox/data/tests/stores/books3.html new file mode 100644 index 0000000..7d0f81d --- /dev/null +++ b/includes/js/dojox/data/tests/stores/books3.html @@ -0,0 +1,14 @@ + + + Books2.html + + +
    +
  • A9B57C - Title of 1 - Author of 1
  • +
  • A9B57F - Title of 2 - Author of 2
  • +
  • A9B577 - Title of 3 - Author of 3
  • +
  • A9B574 - Title of 4 - Author of 4
  • +
  • A9B5CC - Title of 5 - Author of 5
  • +
+ + \ No newline at end of file diff --git a/includes/js/dojox/data/tests/stores/books3.xml b/includes/js/dojox/data/tests/stores/books3.xml new file mode 100644 index 0000000..c44b4c3 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/books3.xml @@ -0,0 +1,31 @@ + + + + Category 1 + + 1 + Title of 1 + Author of 1 + + + 2 + Title of 2 + Author of 2 + + + 3 + Title of 3 + Author of 3 + + + 4 + Title of 4 + Author of 4 + + + 5 + Title of 5 + Author of 5 + + + diff --git a/includes/js/dojox/data/tests/stores/books_isbnAttr.xml b/includes/js/dojox/data/tests/stores/books_isbnAttr.xml new file mode 100644 index 0000000..b9f3d27 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/books_isbnAttr.xml @@ -0,0 +1,23 @@ + + + + Title of 1 + Author of 1 + + + Title of 2 + Author of 2 + + + Title of 3 + Author of 3 + + + Title of 4 + Author of 4 + + + Title of 5 + Author of 5 + + diff --git a/includes/js/dojox/data/tests/stores/books_isbnAttr2.xml b/includes/js/dojox/data/tests/stores/books_isbnAttr2.xml new file mode 100644 index 0000000..a6ce005 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/books_isbnAttr2.xml @@ -0,0 +1,23 @@ + + + + Title of 1 + Author of 1 + + + Title of 2 + Author of 2 + + + Title of 3 + Author of 3 + + + Title of 4 + Author of 4 + + + Title of 5 + Author of 5 + + diff --git a/includes/js/dojox/data/tests/stores/geography.xml b/includes/js/dojox/data/tests/stores/geography.xml new file mode 100644 index 0000000..070a8c1 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/geography.xml @@ -0,0 +1,51 @@ + + + + geography.opml + 2006-11-10 + 2006-11-13 + Magellan, Ferdinand + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/includes/js/dojox/data/tests/stores/geography_withspeciallabel.xml b/includes/js/dojox/data/tests/stores/geography_withspeciallabel.xml new file mode 100644 index 0000000..597c164 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/geography_withspeciallabel.xml @@ -0,0 +1,51 @@ + + + + geography.opml + 2006-11-10 + 2006-11-13 + Magellan, Ferdinand + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/includes/js/dojox/data/tests/stores/jsonPathStore.js b/includes/js/dojox/data/tests/stores/jsonPathStore.js new file mode 100644 index 0000000..9a42a18 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/jsonPathStore.js @@ -0,0 +1,604 @@ +if(!dojo._hasResource["dojox.data.tests.stores.jsonPathStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.stores.jsonPathStore"] = true; +dojo.provide("dojox.data.tests.stores.jsonPathStore"); +dojo.require("dojox.data.jsonPathStore"); + +dojox.data.tests.stores.jsonPathStore.error = function(t, d, errData){ + // summary: + // The error callback function to be used for all of the tests. + d.errback(errData); +} + +dojox.data.tests.testData=dojo.toJson({"store": {"book": [{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99}], "bicycle": {"color": "red", "price": 19.95}}}); + +dojox.data.tests.test_ID_Data=dojo.toJson({"gadgetList": {"myId": "product", "1000": {"name": "Gadget", "type": "Junk", "myId": "1000", "price": "19.99"}, "1001": {"name": "Gadget2", "type": "Junk", "myId": "1010", "price": "17.99"}, "1003": {"name": "Gadget3", "type": "Junk", "myId": "1009", "price": "15.99"}, "1004": {"name": "Gadget4", "type": "Junk", "myId": "1008", "price": "13.99"}, "1005": {"name": "Gadget5", "type": "Junk", "myId": "1007", "price": "11.99"}, "1006": {"name": "Gadget6", "type": "Junk", "myId": "1006", "price": "9.99"}}, "testList": {"a": {"name": "test", "type": "Junk", "myId": "3000", "price": "19.99"}, "b": {"name": "test2", "type": "Junk", "myId": "3010", "price": "17.99"}, "c": {"name": "test3", "type": "Junk", "myId": "3009", "price": "15.99"}, "d": {"name": "test4", "type": "Junk", "myId": "3008", "price": "13.99"}, "e": {"name": "test5", "type": "Junk", "myId": "3007", "price": "11.99"}, "f": {"name": "test6", "type": "Junk", "myId": "3006", "price": "9.99"}}, "bricknbrack": [{"name": "BrickNBrack", "type": "Junk", "myId": "2000", "price": "19.99"}, {"name": "BrickNBrack2", "type": "Junk", "myId": "2010", "price": "17.99"}, {"name": "BrickNBrack3", "type": "Junk", "myId": "2009", "price": "15.99"}, {"name": "BrickNBrack4", "type": "Junk", "myId": "2008", "price": "13.99"}, {"name": "BrickNBrack5", "type": "Junk", "myId": "2007", "price": "11.99"}, {"name": "BrickNBrack6", "type": "Junk", "myId": "2006", "price": "9.99"}]}); + +doh.register("dojox.data.tests.stores.jsonPathStore", + [ + { + name: "Create, Index, Export: {clone: true, suppressExportMeta: true}", + options: {clone: true, suppressExportMeta: true}, + runTest: function(t) { + var original= dojox.data.tests.test_ID_Data; + var store= new dojox.data.jsonPathStore({ + data: original, + mode: dojox.data.SYNC_MODE, + idAttribute: "myId", + indexOnLoad: true + }); + + //snapshot of the store after creation; + var storeWithMeta = dojo.toJson(store._data); + var result = store.dump(this.options); + doh.assertEqual(storeWithMeta, result); + } + }, + { + name: "Create, Index, Export: {cleanMeta: true, clone: true}", + options: {cleanMeta: true, clone: true, suppressExportMeta: true}, + runTest: function(t) { + var original= dojox.data.tests.test_ID_Data; + var store= new dojox.data.jsonPathStore({ + data: original, + mode: dojox.data.SYNC_MODE, + idAttribute: "myId", + indexOnLoad: true + }); + + var result = store.dump(this.options); + doh.assertEqual(original, result); + } + }, + { + name: "Create, Index, Export: {suppressExportMeta: true}", + options: {suppressExportMeta: true}, + runTest: function(t) { + var original= dojox.data.tests.test_ID_Data; + var store= new dojox.data.jsonPathStore({ + data: original, + mode: dojox.data.SYNC_MODE, + idAttribute: "myId", + indexOnLoad: true + }); + + //snapshot of the store after creation; + var storeWithMeta = dojo.toJson(store._data); + var result = store.dump(this.options); + doh.assertEqual(storeWithMeta, result); + } + }, + { + name: "Create, Index, Export: {clone: true, type: 'raw', suppressExportMeta: true}", + options: {clone: true, type: "raw", suppressExportMeta: true}, + runTest: function(t) { + var original= dojox.data.tests.test_ID_Data; + var store= new dojox.data.jsonPathStore({ + data: original, + mode: dojox.data.SYNC_MODE, + idAttribute: "myId", + indexOnLoad: true + }); + + //snapshot of the store after creation; + var storeWithMeta = dojo.toJson(store._data); + var result = dojo.toJson(store.dump(this.options)); + doh.assertEqual(storeWithMeta, result); + } + }, + { + name: "Create, Index, Export: {clone: true, suppressExportMeta: true}", + options: {cleanMeta: true}, + runTest: function(t) { + var original= dojox.data.tests.test_ID_Data; + var store= new dojox.data.jsonPathStore({ + data: original, + mode: dojox.data.SYNC_MODE, + idAttribute: "myId", + indexOnLoad: true + }); + + //snapshot of the store after creation; + var result = store.dump(this.options); + doh.assertEqual(original, result); + } + }, + { + name: "Create, Index, Export: {type: raw}", + options: {type: "raw"}, + runTest: function(t) { + var original= dojox.data.tests.test_ID_Data; + var store= new dojox.data.jsonPathStore({ + data: original, + mode: dojox.data.SYNC_MODE, + idAttribute: "myId", + indexOnLoad: true + }); + + //snapshot of the store after creation; + var result = dojo.toJson(store.dump(this.options)); + var storeWithMeta = dojo.toJson(store._data); + doh.assertEqual(storeWithMeta, result); + } + }, + { + name: "ReadAPI: fetch() Empty Request Test [SYNC_MODE]", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE}); + var success = dojo.toJson([{"book": [{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "_meta": {"path": "$['store']['book'][0]", "autoId": true, "referenceIds": ["_ref_1"]}, "_id": "_auto_3"}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99, "_meta": {"path": "$['store']['book'][1]", "autoId": true, "referenceIds": ["_ref_2"]}, "_id": "_auto_4"}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "_meta": {"path": "$['store']['book'][2]", "autoId": true, "referenceIds": ["_ref_3"]}, "_id": "_auto_5"}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "_meta": {"path": "$['store']['book'][3]", "autoId": true, "referenceIds": ["_ref_4"]}, "_id": "_auto_6"}], "bicycle": {"color": "red", "price": 19.95, "_meta": {"path": "$['store']['bicycle']", "autoId": true, "referenceIds": ["_ref_5"]}, "_id": "_auto_2"}, "_meta": {"path": "$['store']", "autoId": true, "referenceIds": ["_ref_0"]}, "_id": "_auto_0"}, [{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "_meta": {"path": "$['store']['book'][0]", "autoId": true, "referenceIds": ["_ref_1"]}, "_id": "_auto_3"}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99, "_meta": {"path": "$['store']['book'][1]", "autoId": true, "referenceIds": ["_ref_2"]}, "_id": "_auto_4"}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "_meta": {"path": "$['store']['book'][2]", "autoId": true, "referenceIds": ["_ref_3"]}, "_id": "_auto_5"}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "_meta": {"path": "$['store']['book'][3]", "autoId": true, "referenceIds": ["_ref_4"]}, "_id": "_auto_6"}], {"color": "red", "price": 19.95, "_meta": {"path": "$['store']['bicycle']", "autoId": true, "referenceIds": ["_ref_5"]}, "_id": "_auto_2"}, {"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "_meta": {"path": "$['store']['book'][0]", "autoId": true, "referenceIds": ["_ref_1"]}, "_id": "_auto_3"}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99, "_meta": {"path": "$['store']['book'][1]", "autoId": true, "referenceIds": ["_ref_2"]}, "_id": "_auto_4"}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "_meta": {"path": "$['store']['book'][2]", "autoId": true, "referenceIds": ["_ref_3"]}, "_id": "_auto_5"}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "_meta": {"path": "$['store']['book'][3]", "autoId": true, "referenceIds": ["_ref_4"]}, "_id": "_auto_6"}]); + var result = dojo.toJson(store.fetch()); + doh.assertEqual(success, result); + return true; + } + }, + + { + name: "ReadAPI: fetch('$.store.book[*]') test [SYNC_MODE]", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE}); + var success = dojo.toJson([{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "_meta": {"path": "$['store']['book'][0]", "autoId": true, "referenceIds": ["_ref_1"]}, "_id": "_auto_3"}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99, "_meta": {"path": "$['store']['book'][1]", "autoId": true, "referenceIds": ["_ref_2"]}, "_id": "_auto_4"}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "_meta": {"path": "$['store']['book'][2]", "autoId": true, "referenceIds": ["_ref_3"]}, "_id": "_auto_5"}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "_meta": {"path": "$['store']['book'][3]", "autoId": true, "referenceIds": ["_ref_4"]}, "_id": "_auto_6"}]); + var result = dojo.toJson(store.fetch({query:"$.store.book[*]"})); + doh.assertEqual(success, result); + return true; + } + }, + { + name: "ReadAPI: fetch('$.store.book[*]') test [ASYNC_MODE forced SYNC_MODE by string parameter]", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.ASYNC_MODE}); + var success = dojo.toJson([{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "_meta": {"path": "$['store']['book'][0]", "autoId": true, "referenceIds": ["_ref_1"]}, "_id": "_auto_3"}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99, "_meta": {"path": "$['store']['book'][1]", "autoId": true, "referenceIds": ["_ref_2"]}, "_id": "_auto_4"}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "_meta": {"path": "$['store']['book'][2]", "autoId": true, "referenceIds": ["_ref_3"]}, "_id": "_auto_5"}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "_meta": {"path": "$['store']['book'][3]", "autoId": true, "referenceIds": ["_ref_4"]}, "_id": "_auto_6"}]); + var result = dojo.toJson(store.fetch("$.store.book[*]")); + doh.assertEqual(success, result); + return true; + } + }, + { + name: "ReadAPI: fetch({query: '$.store.book[*]', start: 2})", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE}); + var success = dojo.toJson([{"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "_meta": {"path": "$['store']['book'][2]", "autoId": true, "referenceIds": ["_ref_3"]}, "_id": "_auto_5"}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "_meta": {"path": "$['store']['book'][3]", "autoId": true, "referenceIds": ["_ref_4"]}, "_id": "_auto_6"}]); + var result = dojo.toJson(store.fetch({query: '$.store.book[*]', start: 2})); + doh.assertEqual(success, result); + return true; + } + }, + { + name: "ReadAPI: fetch({query: '$.store.book[*]', start: 2, count: 1})", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE}); + var result = store.fetch({query: "$.store.book[*]", start: 2, count: 1}); + doh.assertEqual(result[0].author, 'Herman Melville'); + return true; + } + }, + + { + name: "ReadAPI: fetch(query: '$.store.book[0]'...callbacks...) [ASYNC_MODE]", + runTest: function(datastore, t){ + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData}); + var d = new doh.Deferred(); + function onBegin(count, args){ + doh.assertEqual(1, count); + } + function onItem(item){ + doh.assertTrue(store.isItem(item)); + } + + function onComplete(results){ + doh.assertEqual(1, results.length); + doh.assertEqual("Nigel Rees", results[0]["author"]); + d.callback(true); + } + + function onError(errData){ + t.assertTrue(false); + d.errback(errData); + } + + store.fetch({query: "$.store.book[0]", onBegin: onBegin, onItem: onItem, onError: onError, onComplete: onComplete}); + return d; // Deferred + } + }, + { + name: "ReadAPI: isItem() test", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE}); + var result = store.fetch("$.store.book[*].author"); + doh.assertFalse(store.isItem(result[0])); + result = store.fetch("$.store.book[*]"); + doh.assertTrue(store.isItem(result[0])); + return true; + } + }, + { + name: "ReadAPI: getValue() test", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE}); + var data = store.fetch("$.store.book[*]"); + var result = store.getValue(data[0], "author"); + doh.assertEqual("Nigel Rees", result); + return true; + } + }, + { + name: "ReadAPI: getValues() test", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE}); + var result = store.fetch("$.store.book[*]"); + doh.assertEqual(dojo.toJson(store.getValues(result[0], "author")),dojo.toJson(["Nigel Rees"])); + return true; + } + }, + { + name: "ReadAPI: getAttributes() test", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE}); + var result = store.fetch("$.store.book[*]"); + doh.assertEqual(dojo.toJson(store.getAttributes(result[0])),'["category","author","title","price","_meta","_id"]'); + return true; + } + }, + { + name: "ReadAPI: getAttributes() test [hideMetaAttributes]", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, hideMetaAttributes: true}); + var result = store.fetch("$.store.book[*]"); + doh.assertEqual('["category","author","title","price","_id"]',dojo.toJson(store.getAttributes(result[0]))); + return true; + } + }, + { + name: "ReadAPI: hasAttribute() test", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE}); + var result = store.fetch("$.store.book[*]"); + doh.assertTrue(store.hasAttribute(result[0], "author")); + doh.assertFalse(store.hasAttribute(result[0],"_im_invalid_fooBar")); + return true; + } + }, + + { + name: "ReadAPI: containsValue() test", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE}); + var result = store.fetch("$.store.book[*]"); + doh.assertTrue(store.containsValue(result[0], "author", "Nigel Rees")); + doh.assertFalse(store.containsValue(result[0], "author", "_im_invalid_fooBar")); + return true; + } + }, + { + name: "ReadAPI: getFeatures() test", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE}); + //doh.debug("Store Features: ", dojo.toJson(store.getFeatures())); + var success='{"dojo.data.api.Read":true,"dojo.data.api.Identity":true,"dojo.data.api.Write":true,"dojo.data.api.Notification":true}'; + doh.assertEqual(success,dojo.toJson(store.getFeatures())); + return true; + } + }, + { + name: "ReadAPI: getLabel(item) test [multiple label attributes]", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, labelAttribute: ["title", "author"]}); + var result = store.fetch("$.store.book[0]")[0]; + doh.assertEqual("Sayings of the Century Nigel Rees",store.getLabel(result)); + return true; + } + }, + { + name: "ReadAPI: getLabelAttributes(item) test [multiple label attributes]", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, labelAttribute: ["title", "author"]}); + var result = store.fetch("$.store.book[0]")[0]; + doh.assertEqual('["title","author"]',dojo.toJson(store.getLabelAttributes(result))); + return true; + } + }, + { + name: "ReadAPI: getLabelAttributes(item) test [single label attribute]", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, labelAttribute: ["title"]}); + var result = store.fetch("$.store.book[0]")[0]; + doh.assertEqual('["title"]',dojo.toJson(store.getLabelAttributes(result))); + return true; + } + }, + { + name: "jsonPathStore Feature: override createLabel", + runTest: function(t) { + var createLabel = function(item){ + return item[this.labelAttribute[0]] + " By " + item[this.labelAttribute[1]]; + }; + + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, labelAttribute: ["title", "author"], createLabel: createLabel}); + var result = store.fetch("$.store.book[0]")[0]; + doh.assertEqual('Sayings of the Century By Nigel Rees',store.getLabel(result)); + return true; + } + }, + { + name: "jsonPathStore Feature: autoIdentity", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, idAttribute: "_id"}); + var result = dojo.toJson(store.fetch("$.store.book[0]")[0]); + var success=dojo.toJson( {"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "_meta": {"path": "$['store']['book'][0]", "autoId": true, "referenceIds": ["_ref_1"]}, "_id": "_auto_3"}); + doh.assertEqual(success,result); + return true; + } + }, + + { + name: "jsonPathStore Feature: autoIdentity [clean export removing added id attributes in addition to meta]", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, idAttribute: "_id"}); + //do a search to popuplate some of the itesm with autoId data + var result = store.fetch("$.store.book[0]"); + result = store.dump({cleanMeta: true}); + doh.assertEqual(dojox.data.tests.testData,result); + return true; + } + }, + + { + name: "IdentityAPI: getIdentity(item)", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, idAttribute: "_id"}); + var data= store.fetch("$.store.book[0]")[0]; + var result= store.getIdentity(data); + var success="_auto_3"; + doh.assertEqual(success,result); + return true; + } + }, + + { + + name: "IdentityAPI: fetchItemByIdentity(item) [SYNC_MODE]", + runTest: function(t){ + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, idAttribute: "_id"}); + + var data= store.fetch("$.store.book[0]")[0]; + var id = store.getIdentity(data); + var result = dojo.toJson(store.fetchItemByIdentity({identity:id})); + var success = dojo.toJson(data); + doh.assertEqual(success,result); + return true; + } + }, + { + + name: "jsonPathStore Feature: byId(item) [fetchItemByIdentity alias] [SYNC_MODE]", + runTest: function(t){ + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, idAttribute: "_id"}); + + var data= store.fetch("$.store.book[0]")[0]; + var id = store.getIdentity(data); + var result = dojo.toJson(store.byId({identity:id})); + var success = dojo.toJson(data); + doh.assertEqual(success,result); + return true; + } + }, + + { + name: "IdentityAPI: fetchItemByIdentity(id) single Item [ASYNC_MODE]", + timeout: 1000, + runTest: function(datastore, t){ + // summary: + // Simple test of the fetchItemByIdentity function of the store. + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, indexOnLoad: true}); + var d = new doh.Deferred(); + var query = {query: "$.store.book[0]", mode: dojox.data.SYNC_MODE}; + var data = store.fetch(query)[0]; + var id = store.getIdentity(data); + + function onItem(item){ + doh.assertTrue(store.isItem(item)); + doh.assertEqual(data["author"], item["author"]); + d.callback(true); + } + + function onError(errData){ + + t.assertTrue(false); + d.errback(errData); + } + + store.fetchItemByIdentity({identity: id, onItem: onItem, onError: onError}); + + return d; // Deferred + } + }, + { + name: "IdentityAPI: getIdentityAttributes(item) ", + runTest: function(t) { + var store= new dojox.data.jsonPathStore({data:dojox.data.tests.testData, mode: dojox.data.SYNC_MODE, idAttribute: "_id"}); + var data= store.fetch("$.store.book[0]")[0]; + var result = dojo.toJson(store.getIdentityAttributes(data)); + var success = '["_id"]'; + doh.assertEqual(success,result); + return true; + } + }, + { + name: "WriteAPI: newItem(item) add to store root.", + runTest: function(t) { + var original = dojox.data.tests.testData; + var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, idAttribute: "_id"}); + + var testObject = { + propA: "foo", + propB: "bar" + } + + var testObject2 = { + propA: "foo", + propB: "bar" + } + + var newItem = store.newItem(testObject); + doh.assertTrue(store.isItem(newItem)); + + newItem = store.newItem(testObject2); + doh.assertTrue(store.isItem(newItem)); + + return true; + } + }, + { + name: "WriteAPI: newItem(item) no idAttribute on data item, added only with pInfo", + runTest: function(t) { + var original = dojox.data.tests.testData; + var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE}); + + var parentItem = store.fetch("$.store.book[0]")[0]; + + var testObject = { + propA: "foo", + propB: "bar" + } + + var newItem = store.newItem(testObject,{parent: parentItem, attribute: "TEST_PROPERTY"}); + doh.assertTrue(store.isItem(newItem)); + return true; + } + }, + { + name: "WriteAPI: newItem(item) given id, no parent Attribute", + runTest: function(t) { + var original = dojox.data.tests.testData; + var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, idAttribute: "_id"}); + + var parentItem = store.fetch("$.store.book[0]")[0]; + + var testObject = { + _id: "99999", + propA: "foo", + propB: "bar" + } + + var newItem = store.newItem(testObject,{parent: parentItem}); + doh.assertTrue(store.isItem(newItem)); + return true; + } + }, + { + name: "WriteAPI: newItem(item) given id and parent Attribute", + runTest: function(t) { + var original = dojox.data.tests.testData; + var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, idAttribute: "_id"}); + + var parentItem = store.fetch("$.store.book[0]")[0]; + + var testObject = { + _id: "99999", + propA: "foo", + propB: "bar" + } + + var newItem = store.newItem(testObject,{parent: parentItem, attribute: "TEST"}); + doh.assertTrue(store.isItem(newItem)); + return true; + } + }, + { + name: "WriteAPI: newItem(item) adding to an array", + runTest: function(t) { + var original = dojox.data.tests.testData; + var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, idAttribute: "_id"}); + + var parentItem = store.fetch("$.store")[0]; + + var testObject = { + _id: "99999", + propA: "foo", + propB: "bar" + } + + var newItem = store.newItem(testObject,{parent: parentItem, attribute: "book"}); + doh.assertTrue(store.isItem(newItem)); + return true; + } + }, + { + name: "WriteAPI: setValue(item, value)", + runTest: function(t) { + var original = dojox.data.tests.testData; + var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, indexOnLoad: true, idAttribute: "_id"}); + var item = store.fetch("$.store")[0]; + + var snapshot = store.dump({clone:true, cleanMeta: false, suppressExportMeta: true}); + + store.setValue(item, "Foo", "Bar"); + doh.assertEqual(store._data.store.Foo, "Bar"); + doh.assertTrue(store._data.store._meta.isDirty); + store.save(); + doh.assertFalse(store._data.store._meta.isDirty); + return true; + } + }, + { + name: "WriteAPI: setValues(item, value)", + runTest: function(t) { + var original = dojox.data.tests.testData; + var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, indexOnLoad: true, idAttribute: "_id"}); + var item = store.fetch("$.store")[0]; + + var snapshot = store.dump({clone:true, cleanMeta: false, suppressExportMeta: true}); + + store.setValues(item, "Foo", ["Bar", "Diddly", "Ar"]); + doh.assertEqual(store._data.store.Foo[0], "Bar"); + doh.assertEqual(store._data.store.Foo.length, 3); + doh.assertTrue(store._data.store._meta.isDirty); + store.save(); + doh.assertFalse(store._data.store._meta.isDirty); + return true; + } + }, + { + name: "WriteAPI: unsetAttribute(item, attribute)", + runTest: function(t) { + var original = dojox.data.tests.testData; + var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, indexOnLoad: true, idAttribute: "_id"}); + var item = store.fetch("$.store")[0]; + + var snapshot = store.dump({clone:true, cleanMeta: false, suppressExportMeta: true}); + + store.setValues(item, "Foo", ["Bar", "Diddly", "Ar"]); + doh.assertEqual(store._data.store.Foo[0], "Bar"); + doh.assertEqual(store._data.store.Foo.length, 3); + doh.assertTrue(store._data.store._meta.isDirty); + store.save(); + doh.assertFalse(store._data.store._meta.isDirty); + store.unsetAttribute(item,"Foo"); + doh.assertFalse(item.Foo); + doh.assertTrue(store._data.store._meta.isDirty); + store.save(); + doh.assertFalse(store._data.store._meta.isDirty); + return true; + } + }, + { + name: "WriteAPI: revert()", + runTest: function(t) { + var original = dojox.data.tests.testData; + var store= new dojox.data.jsonPathStore({data:original, mode: dojox.data.SYNC_MODE, indexOnLoad: true, idAttribute: "_id"}); + var item = store.fetch("$.store")[0]; + + var snapshot = store.dump({clone:true, cleanMeta: false, suppressExportMeta: true}); + + store.setValues(item, "Foo", ["Bar", "Diddly", "Ar"]); + doh.assertEqual(store._data.store.Foo[0], "Bar"); + doh.assertEqual(store._data.store.Foo.length, 3); + doh.assertTrue(store._data.store._meta.isDirty); + store.revert(); + doh.assertFalse(store._data.store._meta.isDirty); + doh.assertFalse(store._data.store.Foo); + return true; + } + } + ] +); + +} diff --git a/includes/js/dojox/data/tests/stores/movies.csv b/includes/js/dojox/data/tests/stores/movies.csv new file mode 100644 index 0000000..baf71eb --- /dev/null +++ b/includes/js/dojox/data/tests/stores/movies.csv @@ -0,0 +1,9 @@ +Title, Year, Producer +City of God, 2002, Katia Lund +Rain,, Christine Jeffs +2001: A Space Odyssey, , Stanley Kubrick +"This is a ""fake"" movie title", 1957, Sidney Lumet +Alien, 1979 , Ridley Scott +"The Sequel to ""Dances With Wolves.""", 1982, Ridley Scott +"Caine Mutiny, The", 1954, "Dymtryk ""the King"", Edward" + diff --git a/includes/js/dojox/data/tests/stores/movies2.csv b/includes/js/dojox/data/tests/stores/movies2.csv new file mode 100644 index 0000000..401bcfc --- /dev/null +++ b/includes/js/dojox/data/tests/stores/movies2.csv @@ -0,0 +1,9 @@ +Title, Year, Producer +City of God, 2002, Katia Lund +Rain,"", Christine Jeffs +2001: A Space Odyssey, , Stanley Kubrick +"This is a ""fake"" movie title", 1957, Sidney Lumet +Alien, 1979 , Ridley Scott +"The Sequel to ""Dances With Wolves.""", 1982, Ridley Scott +"Caine Mutiny, The", 1954, "Dymtryk ""the King"", Edward" + diff --git a/includes/js/dojox/data/tests/stores/patterns.csv b/includes/js/dojox/data/tests/stores/patterns.csv new file mode 100644 index 0000000..a9bee64 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/patterns.csv @@ -0,0 +1,11 @@ +uniqueId, value +9, jfq4@#!$!@Rf14r14i5u +6, BaBaMaSaRa***Foo +2, bar*foo +8, 123abc +4, bit$Bite +3, 123abc +10, 123abcdefg +1, foo*bar +7, +5, 123abc diff --git a/includes/js/dojox/data/tests/stores/properties.js b/includes/js/dojox/data/tests/stores/properties.js new file mode 100644 index 0000000..bbdd38d --- /dev/null +++ b/includes/js/dojox/data/tests/stores/properties.js @@ -0,0 +1,10 @@ +/*[ + // Properties of December 1, 2007 + { "year": "2007" }, + { "nmonth": "12" }, + { "month": "December" }, + { "nday": "1" }, + { "day": "Saturday" }, + { "dayOfYear": "335" }, + { "weekOfYear": "48" } +]*/ diff --git a/includes/js/dojox/data/tests/stores/snap_pipeline.php b/includes/js/dojox/data/tests/stores/snap_pipeline.php new file mode 100644 index 0000000..a7e6033 --- /dev/null +++ b/includes/js/dojox/data/tests/stores/snap_pipeline.php @@ -0,0 +1,72 @@ += count($rows) || $limit < 0) { + header("HTTP/1.1 400 Bad Request"); + echo "sn.start and/or sn.limit out of range"; + exit(0); + } + + $slice = array_slice($rows, $start, $limit); + + header("Content-type: application/javascript"); + echo $prefix . "(["; + + $out_rows = array("[" . join(", ", $field_names) . "]"); + foreach($slice as $r) { + $out_rows[] = "[" . join(", ", $r) . "]"; + } + + echo join(", ", $out_rows); + echo "])"; + } + +?> + diff --git a/includes/js/dojox/data/tests/test_Tree_vs_jsonPathStore.html b/includes/js/dojox/data/tests/test_Tree_vs_jsonPathStore.html new file mode 100644 index 0000000..f06bafe --- /dev/null +++ b/includes/js/dojox/data/tests/test_Tree_vs_jsonPathStore.html @@ -0,0 +1,105 @@ + + + + Dijit Tree Test + + + + + + + + + + + + +

Dijit Tree Test - dojo.data.Notification API support

+ +
+ +
+ +
+

Current Selection: Tree Root + +

Selected Item:

+ Name:
+ Description:

+
Update Item
+ +

New Item

+

Enter an Id, Name, and optionally a description to be added as a new item to the store. Upon successful addition, the tree will recieve notification of this event and respond accordingly. If you select a node the item will be added to that node, otherwise the item will be added to the tree root. "Id" is the identifer here and as such must be unique for all items in the store.

+ Id:
+ Name:
+ Description:

+ +
Add Item to Store
+
+ + + + + diff --git a/includes/js/dojox/data/tests/treeTest.json b/includes/js/dojox/data/tests/treeTest.json new file mode 100644 index 0000000..70cc7d8 --- /dev/null +++ b/includes/js/dojox/data/tests/treeTest.json @@ -0,0 +1,10 @@ +{ + node1: { id: 'node1', name:'node1', someProperty:'somePropertyA', children:[ + { id: 'node1.1',name:'node1.1', someProperty:'somePropertyA1'}, + { id: 'node1.2',name:'node1.2', someProperty:'somePropertyA2'} + ]}, + node2:{ id: 'node2', name:'node2', someProperty:'somePropertyB'}, + node3:{ id: 'node3', name:'node3', someProperty:'somePropertyC'}, + node4:{ id: 'node4', name:'node4', someProperty:'somePropertyA'}, + node5:{ id: 'node5', name:'node5', someProperty:'somePropertyB'} +} diff --git a/includes/js/dojox/date/README b/includes/js/dojox/date/README new file mode 100644 index 0000000..8ad5aba --- /dev/null +++ b/includes/js/dojox/date/README @@ -0,0 +1,36 @@ +------------------------------------------------------------------------------- +DojoX Date +------------------------------------------------------------------------------- +Version 0.9 +Release date: 5/17/2007 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + Paul Sowden, Adam Peller (dojox.date.posix) + Neil Roberts (dojox.date.php) +------------------------------------------------------------------------------- +Project description + +Placeholder for any kind of date operations, including formatters that are +common to other languages (posix and php). +------------------------------------------------------------------------------- +Dependencies: + +Depends only on the Dojo Core. +------------------------------------------------------------------------------- +Documentation + +See the API documentation for details. +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/date/* + +Install into the following directory structure: +/dojox/date/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- diff --git a/includes/js/dojox/date/php.js b/includes/js/dojox/date/php.js new file mode 100644 index 0000000..3cee1a2 --- /dev/null +++ b/includes/js/dojox/date/php.js @@ -0,0 +1,312 @@ +if(!dojo._hasResource["dojox.date.php"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.date.php"] = true; +dojo.provide("dojox.date.php"); +dojo.require("dojo.date"); +dojo.require("dojox.string.tokenize"); + +dojox.date.php.format = function(/*Date*/ date, /*String*/ format){ + // summary: Get a formatted string for a given date object + var df = new dojox.date.php.DateFormat(format); + return df.format(date); +} + +dojox.date.php.DateFormat = function(/*String*/ format){ + // summary: Format the internal date object + if(!this.regex){ + var keys = []; + for(var key in this.constructor.prototype){ + if(dojo.isString(key) && key.length == 1 && dojo.isFunction(this[key])){ + keys.push(key); + } + } + this.constructor.prototype.regex = new RegExp("(?:(\\\\.)|([" + keys.join("") + "]))", "g"); + } + + var replacements = []; + + this.tokens = dojox.string.tokenize(format, this.regex, function(escape, token, i){ + if(token){ + replacements.push([i, token]); + return token; + } + if(escape){ + return escape.charAt(1); + } + }); + + this.replacements = replacements; +} +dojo.extend(dojox.date.php.DateFormat, { + weekdays: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + weekdays_3: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + months_3: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + monthdays: [31,28,31,30,31,30,31,31,30,31,30,31], + + format: function(/*Date*/ date){ + this.date = date; + for(var i = 0, replacement; replacement = this.replacements[i]; i++){ + this.tokens[replacement[0]] = this[replacement[1]](); + } + return this.tokens.join(""); + }, + + // Day + + d: function(){ + // summary: Day of the month, 2 digits with leading zeros + var j = this.j(); + return (j.length == 1) ? "0" + j : j; + }, + + D: function(){ + // summary: A textual representation of a day, three letters + return this.weekdays_3[this.date.getDay()]; + }, + + j: function(){ + // summary: Day of the month without leading zeros + return this.date.getDate() + ""; + }, + + l: function(){ + // summary: A full textual representation of the day of the week + return this.weekdays[this.date.getDay()]; + }, + + N: function(){ + // summary: ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) + var w = this.w(); + return (!w) ? 7 : w; + }, + + S: function(){ + // summary: English ordinal suffix for the day of the month, 2 characters + switch(this.date.getDate()){ + case 11: case 12: case 13: return "th"; + case 1: case 21: case 31: return "st"; + case 2: case 22: return "nd"; + case 3: case 23: return "rd"; + default: return "th"; + } + }, + + w: function(){ + // summary: Numeric representation of the day of the week + return this.date.getDay() + ""; + }, + + z: function(){ + // summary: The day of the year (starting from 0) + var millis = this.date.getTime() - new Date(this.date.getFullYear(), 0, 1).getTime(); + return Math.floor(millis/86400000) + ""; + }, + + // Week + + W: function(){ + // summary: ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0) + var week; + var jan1_w = new Date(this.date.getFullYear(), 0, 1).getDay() + 1; + var w = this.date.getDay() + 1; + var z = parseInt(this.z()); + + if(z <= (8 - jan1_w) && jan1_w > 4){ + var last_year = new Date(this.date.getFullYear() - 1, this.date.getMonth(), this.date.getDate()); + if(jan1_w == 5 || (jan1_w == 6 && dojo.date.isLeapYear(last_year))){ + week = 53; + }else{ + week = 52; + } + }else{ + var i; + if(Boolean(this.L())){ + i = 366; + }else{ + i = 365; + } + if((i - z) < (4 - w)){ + week = 1; + }else{ + var j = z + (7 - w) + (jan1_w - 1); + week = Math.ceil(j / 7); + if(jan1_w > 4){ + --week; + } + } + } + + return week; + }, + + // Month + + F: function(){ + // summary: A full textual representation of a month, such as January or March + return this.months[this.date.getMonth()]; + }, + + m: function(){ + // summary: Numeric representation of a month, with leading zeros + var n = this.n(); + return (n.length == 1) ? "0" + n : n; + }, + + M: function(){ + // summary: A short textual representation of a month, three letters + return this.months_3[this.date.getMonth()]; + }, + + n: function(){ + // summary: Numeric representation of a month, without leading zeros + return this.date.getMonth() + 1 + ""; + }, + + t: function(){ + // summary: Number of days in the given month + return (Boolean(this.L()) && this.date.getMonth() == 1) ? 29 : this.monthdays[this.getMonth()]; + }, + + // Year + + L: function(){ + // summary: Whether it's a leap year + return (dojo.date.isLeapYear(this.date)) ? "1" : "0"; + }, + + o: function(){ + // summary: + // ISO-8601 year number. This has the same value as Y, except that if + // the ISO week number (W) belongs to the previous or next year, that year is used instead. (added in PHP 5.1.0) + // TODO: Figure out what this means + }, + + Y: function(){ + // summary: A full numeric representation of a year, 4 digits + return this.date.getFullYear() + ""; + }, + + y: function(){ + // summary: A two digit representation of a year + return this.Y().slice(-2); + }, + + // Time + + a: function(){ + // summary: Lowercase Ante meridiem and Post meridiem + return this.date.getHours() >= 12 ? "pm" : "am"; + }, + + b: function(){ + // summary: Uppercase Ante meridiem and Post meridiem + return this.a().toUpperCase(); + }, + + B: function(){ + // summary: + // Swatch Internet time + // A day is 1,000 beats. All time is measured from GMT + 1 + var off = this.date.getTimezoneOffset() + 60; + var secs = (this.date.getHours() * 3600) + (this.date.getMinutes() * 60) + this.getSeconds() + (off * 60); + var beat = Math.abs(Math.floor(secs / 86.4) % 1000) + ""; + while(beat.length < 2) beat = "0" + beat; + return beat; + }, + + g: function(){ + // summary: 12-hour format of an hour without leading zeros + return (this.date.getHours() > 12) ? this.date.getHours() - 12 + "" : this.date.getHours() + ""; + }, + + G: function(){ + // summary: 24-hour format of an hour without leading zeros + return this.date.getHours() + ""; + }, + + h: function(){ + // summary: 12-hour format of an hour with leading zeros + var g = this.g(); + return (g.length == 1) ? "0" + g : g; + }, + + H: function(){ + // summary: 24-hour format of an hour with leading zeros + var G = this.G(); + return (G.length == 1) ? "0" + G : G; + }, + + i: function(){ + // summary: Minutes with leading zeros + var mins = this.date.getMinutes() + ""; + return (mins.length == 1) ? "0" + mins : mins; + }, + + s: function(){ + // summary: Seconds, with leading zeros + var secs = this.date.getSeconds() + ""; + return (secs.length == 1) ? "0" + secs : secs; + }, + + // Timezone + + e: function(){ + // summary: Timezone identifier (added in PHP 5.1.0) + return dojo.date.getTimezoneName(this.date); + }, + + I: function(){ + // summary: Whether or not the date is in daylight saving time + // TODO: Can dojo.date do this? + }, + + O: function(){ + // summary: Difference to Greenwich time (GMT) in hours + var off = Math.abs(this.date.getTimezoneOffset()); + var hours = Math.floor(off / 60) + ""; + var mins = (off % 60) + ""; + if(hours.length == 1) hours = "0" + hours; + if(mins.length == 1) hours = "0" + mins; + return ((this.date.getTimezoneOffset() < 0) ? "+" : "-") + hours + mins; + }, + + P: function(){ + // summary: Difference to Greenwich time (GMT) with colon between hours and minutes (added in PHP 5.1.3) + var O = this.O(); + return O.substring(0, 2) + ":" + O.substring(2, 4); + }, + + T: function(){ + // summary: Timezone abbreviation + + // Guess... + return this.e().substring(0, 3); + }, + + Z: function(){ + // summary: + // Timezone offset in seconds. The offset for timezones west of UTC is always negative, + // and for those east of UTC is always positive. + return this.date.getTimezoneOffset() * -60; + }, + + // Full Date/Time + + c: function(){ + // summary: ISO 8601 date (added in PHP 5) + return this.Y() + "-" + this.m() + "-" + this.d() + "T" + this.h() + ":" + this.i() + ":" + this.s() + this.P(); + }, + + r: function(){ + // summary: RFC 2822 formatted date + return this.D() + ", " + this.d() + " " + this.M() + " " + this.Y() + " " + this.H() + ":" + this.i() + ":" + this.s() + " " + this.O(); + }, + + U: function(){ + // summary: Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) + return Math.floor(this.date.getTime() / 1000); + } + +}); + +} diff --git a/includes/js/dojox/date/posix.js b/includes/js/dojox/date/posix.js new file mode 100644 index 0000000..88e9c47 --- /dev/null +++ b/includes/js/dojox/date/posix.js @@ -0,0 +1,293 @@ +if(!dojo._hasResource["dojox.date.posix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.date.posix"] = true; +dojo.provide("dojox.date.posix"); + +dojo.require("dojo.date"); +dojo.require("dojo.date.locale"); +dojo.require("dojo.string"); + +dojox.date.posix.strftime = function(/*Date*/dateObject, /*String*/format, /*String?*/locale){ +// +// summary: +// Formats the date object using the specifications of the POSIX strftime function +// +// description: +// see http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html + + // zero pad + var padChar = null; + var _ = function(s, n){ + return dojo.string.pad(s, n || 2, padChar || "0"); + }; + + var bundle = dojo.date.locale._getGregorianBundle(locale); + + var $ = function(property){ + switch(property){ + case "a": // abbreviated weekday name according to the current locale + return dojo.date.locale.getNames('days', 'abbr', 'format', locale)[dateObject.getDay()]; + + case "A": // full weekday name according to the current locale + return dojo.date.locale.getNames('days', 'wide', 'format', locale)[dateObject.getDay()]; + + case "b": + case "h": // abbreviated month name according to the current locale + return dojo.date.locale.getNames('months', 'abbr', 'format', locale)[dateObject.getMonth()]; + + case "B": // full month name according to the current locale + return dojo.date.locale.getNames('months', 'wide', 'format', locale)[dateObject.getMonth()]; + + case "c": // preferred date and time representation for the current + // locale + return dojo.date.locale.format(dateObject, {formatLength: 'full', locale: locale}); + + case "C": // century number (the year divided by 100 and truncated + // to an integer, range 00 to 99) + return _(Math.floor(dateObject.getFullYear()/100)); + + case "d": // day of the month as a decimal number (range 01 to 31) + return _(dateObject.getDate()); + + case "D": // same as %m/%d/%y + return $("m") + "/" + $("d") + "/" + $("y"); + + case "e": // day of the month as a decimal number, a single digit is + // preceded by a space (range ' 1' to '31') + if(padChar == null){ padChar = " "; } + return _(dateObject.getDate()); + + case "f": // month as a decimal number, a single digit is + // preceded by a space (range ' 1' to '12') + if(padChar == null){ padChar = " "; } + return _(dateObject.getMonth()+1); + + case "g": // like %G, but without the century. + break; + + case "G": // The 4-digit year corresponding to the ISO week number + // (see %V). This has the same format and value as %Y, + // except that if the ISO week number belongs to the + // previous or next year, that year is used instead. + dojo.unimplemented("unimplemented modifier 'G'"); + break; + + case "F": // same as %Y-%m-%d + return $("Y") + "-" + $("m") + "-" + $("d"); + + case "H": // hour as a decimal number using a 24-hour clock (range + // 00 to 23) + return _(dateObject.getHours()); + + case "I": // hour as a decimal number using a 12-hour clock (range + // 01 to 12) + return _(dateObject.getHours() % 12 || 12); + + case "j": // day of the year as a decimal number (range 001 to 366) + return _(dojo.date.locale._getDayOfYear(dateObject), 3); + + case "k": // Hour as a decimal number using a 24-hour clock (range + // 0 to 23 (space-padded)) + if(padChar == null){ padChar = " "; } + return _(dateObject.getHours()); + + case "l": // Hour as a decimal number using a 12-hour clock (range + // 1 to 12 (space-padded)) + if(padChar == null){ padChar = " "; } + return _(dateObject.getHours() % 12 || 12); + + case "m": // month as a decimal number (range 01 to 12) + return _(dateObject.getMonth() + 1); + + case "M": // minute as a decimal number + return _(dateObject.getMinutes()); + + case "n": + return "\n"; + + case "p": // either `am' or `pm' according to the given time value, + // or the corresponding strings for the current locale + return bundle[dateObject.getHours() < 12 ? "am" : "pm"]; + + case "r": // time in a.m. and p.m. notation + return $("I") + ":" + $("M") + ":" + $("S") + " " + $("p"); + + case "R": // time in 24 hour notation + return $("H") + ":" + $("M"); + + case "S": // second as a decimal number + return _(dateObject.getSeconds()); + + case "t": + return "\t"; + + case "T": // current time, equal to %H:%M:%S + return $("H") + ":" + $("M") + ":" + $("S"); + + case "u": // weekday as a decimal number [1,7], with 1 representing + // Monday + return String(dateObject.getDay() || 7); + + case "U": // week number of the current year as a decimal number, + // starting with the first Sunday as the first day of the + // first week + return _(dojo.date.locale._getWeekOfYear(dateObject)); + + case "V": // week number of the year (Monday as the first day of the + // week) as a decimal number [01,53]. If the week containing + // 1 January has four or more days in the new year, then it + // is considered week 1. Otherwise, it is the last week of + // the previous year, and the next week is week 1. + return _(dojox.date.posix.getIsoWeekOfYear(dateObject)); + + case "W": // week number of the current year as a decimal number, + // starting with the first Monday as the first day of the + // first week + return _(dojo.date.locale._getWeekOfYear(dateObject, 1)); + + case "w": // day of the week as a decimal, Sunday being 0 + return String(dateObject.getDay()); + + case "x": // preferred date representation for the current locale + // without the time + return dojo.date.locale.format(dateObject, {selector:'date', formatLength: 'full', locale:locale}); + + case "X": // preferred time representation for the current locale + // without the date + return dojo.date.locale.format(dateObject, {selector:'time', formatLength: 'full', locale:locale}); + + case "y": // year as a decimal number without a century (range 00 to + // 99) + return _(dateObject.getFullYear()%100); + + case "Y": // year as a decimal number including the century + return String(dateObject.getFullYear()); + + case "z": // time zone or name or abbreviation + var timezoneOffset = dateObject.getTimezoneOffset(); + return (timezoneOffset > 0 ? "-" : "+") + + _(Math.floor(Math.abs(timezoneOffset)/60)) + ":" + + _(Math.abs(timezoneOffset)%60); + + case "Z": // time zone or name or abbreviation + return dojo.date.getTimezoneName(dateObject); + + case "%": + return "%"; + } + }; + + // parse the formatting string and construct the resulting string + var string = ""; + var i = 0; + var index = 0; + var switchCase = null; + while ((index = format.indexOf("%", i)) != -1){ + string += format.substring(i, index++); + + // inspect modifier flag + switch (format.charAt(index++)) { + case "_": // Pad a numeric result string with spaces. + padChar = " "; break; + case "-": // Do not pad a numeric result string. + padChar = ""; break; + case "0": // Pad a numeric result string with zeros. + padChar = "0"; break; + case "^": // Convert characters in result string to uppercase. + switchCase = "upper"; break; + case "*": // Convert characters in result string to lowercase + switchCase = "lower"; break; + case "#": // Swap the case of the result string. + switchCase = "swap"; break; + default: // no modifier flag so decrement the index + padChar = null; index--; break; + } + + // toggle case if a flag is set + var property = $(format.charAt(index++)); + switch (switchCase){ + case "upper": + property = property.toUpperCase(); + break; + case "lower": + property = property.toLowerCase(); + break; + case "swap": // Upper to lower, and versey-vicea + var compareString = property.toLowerCase(); + var swapString = ''; + var ch = ''; + for (var j = 0; j < property.length; j++){ + ch = property.charAt(j); + swapString += (ch == compareString.charAt(j)) ? + ch.toUpperCase() : ch.toLowerCase(); + } + property = swapString; + break; + default: + break; + } + switchCase = null; + + string += property; + i = index; + } + string += format.substring(i); + + return string; // String +}; + +dojox.date.posix.getStartOfWeek = function(/*Date*/dateObject, /*Number*/firstDay){ + // summary: Return a date object representing the first day of the given + // date's week. + if(isNaN(firstDay)){ + firstDay = dojo.cldr.supplemental.getFirstDayOfWeek ? dojo.cldr.supplemental.getFirstDayOfWeek() : 0; + } + var offset = firstDay; + if(dateObject.getDay() >= firstDay){ + offset -= dateObject.getDay(); + }else{ + offset -= (7 - dateObject.getDay()); + } + var date = new Date(dateObject); + date.setHours(0, 0, 0, 0); + return dojo.date.add(date, "day", offset); // Date +} + +dojox.date.posix.setIsoWeekOfYear = function(/*Date*/dateObject, /*Number*/week){ + // summary: Set the ISO8601 week number of the given date. + // The week containing January 4th is the first week of the year. + // week: + // can be positive or negative: -1 is the year's last week. + if(!week){ return dateObject; } + var currentWeek = dojox.date.posix.getIsoWeekOfYear(dateObject); + var offset = week - currentWeek; + if(week < 0){ + var weeks = dojox.date.posix.getIsoWeeksInYear(dateObject); + offset = (weeks + week + 1) - currentWeek; + } + return dojo.date.add(dateObject, "week", offset); // Date +} + +dojox.date.posix.getIsoWeekOfYear = function(/*Date*/dateObject){ + // summary: Get the ISO8601 week number of the given date. + // The week containing January 4th is the first week of the year. + // See http://en.wikipedia.org/wiki/ISO_week_date + var weekStart = dojox.date.posix.getStartOfWeek(dateObject, 1); + var yearStart = new Date(dateObject.getFullYear(), 0, 4); // January 4th + yearStart = dojox.date.posix.getStartOfWeek(yearStart, 1); + var diff = weekStart.getTime() - yearStart.getTime(); + if(diff < 0){ return dojox.date.posix.getIsoWeeksInYear(weekStart); } // Integer + return Math.ceil(diff / 604800000) + 1; // Integer +} + +dojox.date.posix.getIsoWeeksInYear = function(/*Date*/dateObject) { + // summary: Determine the number of ISO8601 weeks in the year of the given + // date. Most years have 52 but some have 53. + // See http://www.phys.uu.nl/~vgent/calendar/isocalendar_text3.htm + function p(y) { + return y + Math.floor(y/4) - Math.floor(y/100) + Math.floor(y/400); + } + var y = dateObject.getFullYear(); + return ( p(y) % 7 == 4 || p(y-1) % 7 == 3 ) ? 53 : 52; // Integer +} + +} diff --git a/includes/js/dojox/date/tests/module.js b/includes/js/dojox/date/tests/module.js new file mode 100644 index 0000000..9e1a297 --- /dev/null +++ b/includes/js/dojox/date/tests/module.js @@ -0,0 +1,12 @@ +if(!dojo._hasResource["dojox.date.tests.module"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.date.tests.module"] = true; +dojo.provide("dojox.date.tests.module"); + +try{ + dojo.require("dojox.date.tests.posix"); +}catch(e){ + doh.debug(e); +} + + +} diff --git a/includes/js/dojox/date/tests/posix.js b/includes/js/dojox/date/tests/posix.js new file mode 100644 index 0000000..84039f9 --- /dev/null +++ b/includes/js/dojox/date/tests/posix.js @@ -0,0 +1,236 @@ +if(!dojo._hasResource["dojox.date.tests.posix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.date.tests.posix"] = true; +dojo.provide("dojox.date.tests.posix"); +dojo.require("dojox.date.posix"); + +tests.register("dojox.date.tests.posix", + [ + + //FIXME: set up by loading 'en' resources +function test_date_strftime(t){ + var date = new Date(2006, 7, 11, 0, 55, 12, 3456); + t.is("06/08/11", dojox.date.posix.strftime(date, "%y/%m/%d")); + + var dt = null; // Date to test + var fmt = ''; // Format to test + var res = ''; // Expected result + + dt = new Date(2006, 0, 1, 18, 23); + fmt = '%a'; + res = 'Sun'; + t.is(res, dojox.date.posix.strftime(dt, fmt, 'en')); + + fmt = '%A'; + res = 'Sunday'; + t.is(res, dojox.date.posix.strftime(dt, fmt, 'en')); + + fmt = '%b'; + res = 'Jan'; + t.is(res, dojox.date.posix.strftime(dt, fmt, 'en')); + + fmt = '%B'; + res = 'January'; + t.is(res, dojox.date.posix.strftime(dt, fmt, 'en')); + + fmt = '%c'; + res = 'Sunday, January 1, 2006 6:23:00 PM'; + t.is(res, dojox.date.posix.strftime(dt, fmt).substring(0, res.length)); + + fmt = '%C'; + res = '20'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%d'; + res = '01'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%D'; + res = '01/01/06'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%e'; + res = ' 1'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%h'; + res = 'Jan'; + t.is(res, dojox.date.posix.strftime(dt, fmt, 'en')); + + fmt = '%H'; + res = '18'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%I'; + res = '06'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%j'; + res = '001'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%k'; + res = '18'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%l'; + res = ' 6'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%m'; + res = '01'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%M'; + res = '23'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%p'; + res = 'PM'; + t.is(res, dojox.date.posix.strftime(dt, fmt, 'en')); + + fmt = '%r'; + res = '06:23:00 PM'; + t.is(res, dojox.date.posix.strftime(dt, fmt, 'en')); + + fmt = '%R'; + res = '18:23'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%S'; + res = '00'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%T'; + res = '18:23:00'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%u'; + res = '7'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%w'; + res = '0'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%x'; + res = 'Sunday, January 1, 2006'; + t.is(res, dojox.date.posix.strftime(dt, fmt, 'en')); + + fmt = '%X'; + res = '6:23:00 PM'; + t.is(res, dojox.date.posix.strftime(dt, fmt, 'en').substring(0,res.length)); + + fmt = '%y'; + res = '06'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%Y'; + res = '2006'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); + + fmt = '%%'; + res = '%'; + t.is(res, dojox.date.posix.strftime(dt, fmt)); +}, +function test_date_getStartOfWeek(t){ + var weekStart; + + // Monday + var date = new Date(2007, 0, 1); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 1), 1); + t.is(date, weekStart); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 2), 1); + t.is(date, weekStart); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 3), 1); + t.is(date, weekStart); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 4), 1); + t.is(date, weekStart); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 5), 1); + t.is(date, weekStart); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 6), 1); + t.is(date, weekStart); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 7), 1); + t.is(date, weekStart); + + // Sunday + date = new Date(2007, 0, 7); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 7), 0); + t.is(date, weekStart); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 8), 0); + t.is(date, weekStart); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 9), 0); + t.is(date, weekStart); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 10), 0); + t.is(date, weekStart); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 11), 0); + t.is(date, weekStart); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 12), 0); + t.is(date, weekStart); + weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 13), 0); + t.is(date, weekStart); +}, + +function test_date_setIsoWeekOfYear(t){ + var date = new Date(2006,10,10); + var result = dojox.date.posix.setIsoWeekOfYear(date, 1); + t.is(new Date(2006,0,6), result); + result = dojox.date.posix.setIsoWeekOfYear(date, 10); + result = dojox.date.posix.setIsoWeekOfYear(date, 2); + t.is(new Date(2006,0,13), result); + result = dojox.date.posix.setIsoWeekOfYear(date, 10); + t.is(new Date(2006,2,10), result); + result = dojox.date.posix.setIsoWeekOfYear(date, 52); + t.is(new Date(2006,11,29), result); + var result = dojox.date.posix.setIsoWeekOfYear(date, -1); + t.is(new Date(2006,11,29), result); + var result = dojox.date.posix.setIsoWeekOfYear(date, -2); + t.is(new Date(2006,11,22), result); + var result = dojox.date.posix.setIsoWeekOfYear(date, -10); + t.is(new Date(2006,9,27), result); + + date = new Date(2004,10,10); + result = dojox.date.posix.setIsoWeekOfYear(date, 1); + t.is(new Date(2003,11,31), result); + result = dojox.date.posix.setIsoWeekOfYear(date, 2); + t.is(new Date(2004,0,7), result); + result = dojox.date.posix.setIsoWeekOfYear(date, -1); + t.is(new Date(2004,11,29), result); +}, + +function test_date_getIsoWeekOfYear(t){ + var week = dojox.date.posix.getIsoWeekOfYear(new Date(2006,0,1)); + t.is(52, week); + week = dojox.date.posix.getIsoWeekOfYear(new Date(2006,0,4)); + t.is(1, week); + week = dojox.date.posix.getIsoWeekOfYear(new Date(2006,11,31)); + t.is(52, week); + week = dojox.date.posix.getIsoWeekOfYear(new Date(2007,0,1)); + t.is(1, week); + week = dojox.date.posix.getIsoWeekOfYear(new Date(2007,11,31)); + t.is(53, week); + week = dojox.date.posix.getIsoWeekOfYear(new Date(2008,0,1)); + t.is(1, week); + week = dojox.date.posix.getIsoWeekOfYear(new Date(2007,11,31)); + t.is(53, week); +}, + +function test_date_getIsoWeeksInYear(t){ + // 44 long years in a 400 year cycle. + var longYears = [4, 9, 15, 20, 26, 32, 37, 43, 48, 54, 60, 65, 71, 76, 82, + 88, 93, 99, 105, 111, 116, 122, 128, 133, 139, 144, 150, 156, 161, 167, + 172, 178, 184, 189, 195, 201, 207, 212, 218, 224, 229, 235, 240, 246, + 252, 257, 263, 268, 274, 280, 285, 291, 296, 303, 308, 314, 320, 325, + 331, 336, 342, 348, 353, 359, 364, 370, 376, 381, 387, 392, 398]; + + var i, j, weeks, result; + for(i=0; i < 400; i++) { + weeks = 52; + if(i == longYears[0]) { weeks = 53; longYears.shift(); } + result = dojox.date.posix.getIsoWeeksInYear(new Date(2000 + i, 0, 1)); + t.is(/*weeks +" weeks in "+ (2000+i), */weeks, result); + } +} + ] +); + +} diff --git a/includes/js/dojox/date/tests/runTests.html b/includes/js/dojox/date/tests/runTests.html new file mode 100644 index 0000000..57f6ba1 --- /dev/null +++ b/includes/js/dojox/date/tests/runTests.html @@ -0,0 +1,9 @@ + + + + Dojox Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/dtl.js b/includes/js/dojox/dtl.js new file mode 100644 index 0000000..2128ab6 --- /dev/null +++ b/includes/js/dojox/dtl.js @@ -0,0 +1,6 @@ +if(!dojo._hasResource["dojox.dtl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl"] = true; +dojo.provide("dojox.dtl"); +dojo.require("dojox.dtl._base"); + +} diff --git a/includes/js/dojox/dtl/Context.js b/includes/js/dojox/dtl/Context.js new file mode 100644 index 0000000..f608506 --- /dev/null +++ b/includes/js/dojox/dtl/Context.js @@ -0,0 +1,87 @@ +if(!dojo._hasResource["dojox.dtl.Context"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.Context"] = true; +dojo.provide("dojox.dtl.Context"); +dojo.require("dojox.dtl._base"); + +dojox.dtl.Context = dojo.extend(function(dict){ + this._this = {}; + dojox.dtl._Context.call(this, dict); +}, dojox.dtl._Context.prototype, +{ + extend: function(/*dojox.dtl.Context|Object*/ obj){ + // summary: Returns a clone of this context object, with the items from the + // passed objecct mixed in. + var context = new dojox.dtl.Context(); + var keys = this.getKeys(); + var i, key; + for(i = 0; key = keys[i]; i++){ + if(typeof obj[key] != "undefined"){ + context[key] = obj[key]; + }else{ + context[key] = this[key]; + } + } + + if(obj instanceof dojox.dtl.Context){ + keys = obj.getKeys(); + }else if(typeof obj == "object"){ + keys = []; + for(key in obj){ + keys.push(key); + } + } + + for(i = 0; key = keys[i]; i++){ + context[key] = obj[key]; + } + + return context; + }, + filter: function(/*dojox.dtl.Context|Object|String...*/ filter){ + // summary: Returns a clone of this context, only containing the items + // defined in the filter. + var context = new dojox.dtl.Context(); + var keys = []; + var i, arg; + if(filter instanceof dojox.dtl.Context){ + keys = filter.getKeys(); + }else if(typeof filter == "object"){ + for(var key in filter){ + keys.push(key); + } + }else{ + for(i = 0; arg = arguments[i]; i++){ + if(typeof arg == "string"){ + keys.push(arg); + } + } + } + + for(i = 0, key; key = keys[i]; i++){ + context[key] = this[key]; + } + + return context; + }, + setThis: function(/*Object*/ _this){ + this._this = _this; + }, + getThis: function(){ + return this._this; + }, + hasKey: function(key){ + if(typeof this[key] != "undefined"){ + return true; + } + + for(var i = 0, dict; dict = this._dicts[i]; i++){ + if(typeof dict[key] != "undefined"){ + return true; + } + } + + return false; + } +}); + +} diff --git a/includes/js/dojox/dtl/README b/includes/js/dojox/dtl/README new file mode 100644 index 0000000..a6cc8c3 --- /dev/null +++ b/includes/js/dojox/dtl/README @@ -0,0 +1,207 @@ +------------------------------------------------------------------------------- +DojoX Django Template Language +------------------------------------------------------------------------------- +Version 0.0 +Release date: 09/20/2007 +------------------------------------------------------------------------------- +Project state: experimental/feature incomplete +------------------------------------------------------------------------------- +Project authors + Neil Roberts (pottedmeat@dojotoolkit.org) +------------------------------------------------------------------------------- +Project description + +The Django Template language uses a system of templates that can be compiled +once and rendered indefinitely afterwards. It uses a simple system of tags +and filters. + +This is a 1:1 match with the Django Template Language as outlined in +http://www.djangoproject.com/documentation/templates/. All applicable tags and +filters have been implemented (see below), along with new filters and tags as +necessary (see below). + +The Django Template Language is intended within Django to only handle text. +Our implementation is able to handle HTML in addition to text. Actually, the +text and HTML portions of dojox.dtl are two separate layers, the HTML layer +sits on top of the text layer (base). It's also been implemented in such a way +that you have little to fear when moving your code from Django to dojox.dtl. +Your existing templates should work, and will benefit from the massive +performance gain of being able to manipulate nodes, rather than having to do +clunky innerHTML swaps you would have to do with a text-only system. It also +allows for new HTML-centric abilities, outlined below. + +Despite having two levels of complexity, if you write your tags correctly, they +will work in both environments. +------------------------------------------------------------------------------- +Dependencies + +Base: +dojox.string.Builder + +Date filters and tags: +dojox.date.php + +Widget: +dijit._Widget +dijit._Container +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/dtl.js +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/dtl/* + +Install into the following directory structure: +/dojox/dtl/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- +What's Been Done + +Note: HTML Unit Tests should only be around for the oddities of HTML, tag/filter +code is the same for each environment with minor exceptions. Cloning of all tags +should be tested inside a for loop. + +| Implemented | Tag | Text Unit Test | HTML Unit Test | +| X | block | X | | +| X | comment | X | | +| X | cycle | X | | +| X | debug | X | | +| X | extends | X | | +| X | filter | X | | +| X | firstof | X | | +| X | for | X | | +| X | if | X | | +| X | ifchanged | X | X | +| X | ifequal | X | | +| X | ifnotequal | X | | +| X | include | X | X | +| X | load | X | | +| X | now | X | | +| X | regroup | X | | +| X | spaceless | X | X | +| X | ssi | X | X | +| X | templatetag | X | | +| N/A | url | | | +| X | widthratio | X | | +| X | with | X | | + +| Implemented | Filter | Text Unit Test | HTML Unit Test | +| X | add | X | | +| X | addslashes | X | | +| X | capfirst | X | | +| X | center | X | | +| X | cut | X | | +| X | date | X | | +| X | default | X | | +| X | default_if_none | X | | +| X | dictsort | X | | +| X | dictsort_reversed | X | | +| X | divisibleby | X | | +| X | escape | X | | +| X | filesizeformat | X | | +| X | first | X | | +| X | fix_ampersands | X | | +| X | floatformat | X | | +| X | get_digit | X | | +| X | iriencode | X | | +| X | join | X | | +| X | length | X | | +| X | length_is | X | | +| X | linebreaks | X | | +| X | linebreaksbr | X | | +| X | linenumbers | X | | +| X | ljust | X | | +| X | lower | X | | +| X | make_list | X | | +| X | phone2numeric | X | | +| X | pluralize | X | | +| X | pprint | X | | +| X | random | X | | +| X | removetags | X | | +| X | rjust | X | | +| X | slice | X | | +| X | slugify | X | | +| X | stringformat | X | | +| X | striptags | X | | +| X | time | X | | +| X | timesince | X | | +| X | timeuntil | X | | +| X | title | X | | +| X | truncatewords | X | | +| X | truncatewords_html | X | | +| X | unordered_list | X | | +| X | upper | X | | +| X | urlencode | X | | +| X | urlize | X | | +| X | urlizetrunc | X | | +| X | wordcount | X | | +| X | wordwrap | X | | +| X | yesno | X | | +------------------------------------------------------------------------------- +HTML-Specific Additions +------------------------------------------------------------------------------- +{%extends "shared:templates/template.html" %} + +When using the {% extends %} tag, we don't always want to replace the parent +node in DOM. For example, if we have a list view and a detail view, but both +share the same base template, we want it to share the parent template. This +basically means that the same nodes will be used in the parent for both views. + +To use this, simply add "shared:" to the beginning of the specified template. +------------------------------------------------------------------------------- + + +Some browsers treat comment nodes as full fledged nodes. If performance is +important to you, you can wrap your markup in comments. The comments will be +automatically stripped for browsers that cannot support this. +------------------------------------------------------------------------------- +Attribute Tags + +If a tag name begins with "attr:" then it will be able to inject an object +into the parsed template. (See dojox.dtl.tag.event.EventNode) + +onclick/onmouseover/etc attributes work by attaching to the rendering object. + +tstyle attribute allows for styles to be changed dynamically. Use them just +like a "style" attribute. + +attach attribute attaches the node to the rendering object. +------------------------------------------------------------------------------- +New Context Functions + +setThis() and getThis() returns the object "in charge" of the current rendering. +This is used so that we can attach events. + +mixin() and filter() clone the current context, and either add to or reduce +the keys in the context. +------------------------------------------------------------------------------- +Buffers + +Both the base and HTML versions of dojox.dtl use buffers. The base version uses +dojox.string.Builder and the HTML version uses dojox.dtl.HtmlBuffer. + +The HTML buffer has several calls important to rendering: + +setParent/getParent/concat/remove: + +setParent and concat are used in order to render our HTML. As we move through +the parsed template, different nodes change the parent or add on to the +current parent. getParent is useful in things like the attribute tags, since +they can use getParent to find the node that they're an attribute on. remove is +used during unrendering. + +setAttribute: + +Sets an attribute on the current parent +------------------------------------------------------------------------------- +Tags Need clone/unrender Functions. + +One of the biggest challenges of getting dojox.dtl to work in an HTML +environment was logic blocks. Nodes and objects inside a for loop need to be +cloned, they can't simply be re-rendered, especially if they involve a Node. +Also, in the case of an if/else block, we need to be able to not just render +one of the blocks, but also unrender the second. + +This is really simple code, a good example is the dojox.dtl.HtmlNode +object. Each function in this object is only one line long. \ No newline at end of file diff --git a/includes/js/dojox/dtl/_HtmlTemplated.js b/includes/js/dojox/dtl/_HtmlTemplated.js new file mode 100644 index 0000000..8947a8d --- /dev/null +++ b/includes/js/dojox/dtl/_HtmlTemplated.js @@ -0,0 +1,72 @@ +if(!dojo._hasResource["dojox.dtl._HtmlTemplated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl._HtmlTemplated"] = true; +dojo.provide("dojox.dtl._HtmlTemplated"); +dojo.require("dijit._Templated"); +dojo.require("dojox.dtl.html"); +dojo.require("dojox.dtl.render.html"); +dojo.require("dojox.dtl.contrib.dijit"); + +dojox.dtl._HtmlTemplated = { + prototype: { + _dijitTemplateCompat: false, + buildRendering: function(){ + this.domNode = this.srcNodeRef; + + if(!this._render){ + var ddcd = dojox.dtl.contrib.dijit; + var old = ddcd.widgetsInTemplate; + ddcd.widgetsInTemplate = this.widgetsInTemplate; + this._template = this._getCachedTemplate(this.templatePath, this.templateString); + this._render = new dojox.dtl.render.html.Render(this.domNode, this._template); + ddcd.widgetsInTemplate = old; + } + + var self = this; + this._rendering = setTimeout(function(){ self.render(); }, 10); + }, + setTemplate: function(/*String|dojo._Url*/ template, /*dojox.dtl.Context?*/ context){ + // summary: + // Quickly switch between templated by location + if(dojox.dtl.text._isTemplate(template)){ + this._template = this._getCachedTemplate(null, template); + }else{ + this._template = this._getCachedTemplate(template); + } + this.render(context); + }, + render: function(/*dojox.dtl.Context?*/ context){ + if(this._rendering){ + clearTimeout(this._rendering); + delete this._rendering; + } + this._render.render(this._getContext(context)); + }, + _getContext: function(context){ + if (!(context instanceof dojox.dtl.Context)) { + context = false; + } + context = context || new dojox.dtl.Context(this); + context.setThis(this); + return context; + }, + _getCachedTemplate: function(templatePath, templateString){ + if(!this._templates){ + this._templates = {}; + } + var key = templateString || templatePath.toString(); + var tmplts = this._templates; + if(tmplts[key]){ + return tmplts[key]; + } + return (tmplts[key] = new dojox.dtl.HtmlTemplate( + dijit._Templated.getCachedTemplate( + templatePath, + templateString, + true + ) + )); + } + } +}; + +} diff --git a/includes/js/dojox/dtl/_Templated.js b/includes/js/dojox/dtl/_Templated.js new file mode 100644 index 0000000..1472fe9 --- /dev/null +++ b/includes/js/dojox/dtl/_Templated.js @@ -0,0 +1,93 @@ +if(!dojo._hasResource["dojox.dtl._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl._Templated"] = true; +dojo.provide("dojox.dtl._Templated"); +dojo.require("dijit._Templated"); +dojo.require("dojox.dtl._base"); + +dojo.declare("dojox.dtl._Templated", dijit._Templated, { + _dijitTemplateCompat: false, + buildRendering: function(){ + var node; + + if(this.domNode && !this._template){ + return; + } + + if(!this._template){ + var t = this.getCachedTemplate( + this.templatePath, + this.templateString, + this._skipNodeCache + ); + if(t instanceof dojox.dtl.Template) { + this._template = t; + }else{ + node = t; + } + } + if(!node){ + var nodes = dijit._Templated._createNodesFromText( + this._template.render(new dojox.dtl._Context(this)) + ); + for(var i = 0; i < nodes.length; i++){ + if(nodes[i].nodeType == 1){ + node = nodes[i]; + break; + } + } + } + + this._attachTemplateNodes(node); + + var source = this.srcNodeRef; + if(source && source.parentNode){ + source.parentNode.replaceChild(node, source); + } + + if(this.widgetsInTemplate){ + var childWidgets = dojo.parser.parse(node); + this._attachTemplateNodes(childWidgets, function(n,p){ + return n[p]; + }); + } + + if(this.domNode){ + dojo.place(node, this.domNode, "before"); + this.destroyDescendants(); + dojo._destroyElement(this.domNode); + } + this.domNode = node; + + this._fillContent(source); + }, + _templateCache: {}, + getCachedTemplate: function(templatePath, templateString, alwaysUseString){ + // summary: + // Layer for dijit._Templated.getCachedTemplate + var tmplts = this._templateCache; + var key = templateString || templatePath; + if(tmplts[key]){ + return tmplts[key]; + } + + templateString = dojo.string.trim(templateString || dijit._Templated._sanitizeTemplateString(dojo._getText(templatePath))); + + if( this._dijitTemplateCompat && + (alwaysUseString || templateString.match(/\$\{([^\}]+)\}/g)) + ){ + templateString = this._stringRepl(templateString); + } + + // If we always use a string, or find no variables, just store it as a node + if(alwaysUseString || !templateString.match(/\{[{%]([^\}]+)[%}]\}/g)){ + return (tmplts[key] = dijit._Templated._createNodesFromText(templateString)[0]); + }else{ + return (tmplts[key] = new dojox.dtl.Template(templateString)); + } + }, + render: function(){ + this.buildRendering(); + } +}); + +} diff --git a/includes/js/dojox/dtl/_base.js b/includes/js/dojox/dtl/_base.js new file mode 100644 index 0000000..f42f245 --- /dev/null +++ b/includes/js/dojox/dtl/_base.js @@ -0,0 +1,570 @@ +if(!dojo._hasResource["dojox.dtl._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl._base"] = true; +dojo.provide("dojox.dtl._base"); + +dojo.require("dojox.string.Builder"); +dojo.require("dojox.string.tokenize"); + +(function(){ + var dd = dojox.dtl; + + dd._Context = dojo.extend(function(dict){ + // summary: Pass one of these when rendering a template to tell the template what values to use. + dojo.mixin(this, dict || {}); + this._dicts = []; + }, + { + push: function(){ + var dict = {}; + var keys = this.getKeys(); + for(var i = 0, key; key = keys[i]; i++){ + dict[key] = this[key]; + delete this[key]; + } + this._dicts.unshift(dict); + }, + pop: function(){ + if(!this._dicts.length){ + throw new Error("pop() called on empty Context"); + } + var dict = this._dicts.shift(); + dojo.mixin(this, dict); + }, + getKeys: function(){ + var keys = []; + for(var key in this){ + if(this.hasOwnProperty(key) && key != "_dicts" && key != "_this"){ + keys.push(key); + } + } + return keys; + }, + get: function(key, otherwise){ + if(typeof this[key] != "undefined"){ + return this._normalize(this[key]); + } + + for(var i = 0, dict; dict = this._dicts[i]; i++){ + if(typeof dict[key] != "undefined"){ + return this._normalize(dict[key]); + } + } + + return otherwise; + }, + _normalize: function(value){ + if(value instanceof Date){ + value.year = value.getFullYear(); + value.month = value.getMonth() + 1; + value.day = value.getDate(); + value.date = value.year + "-" + ("0" + value.month).slice(-2) + "-" + ("0" + value.day).slice(-2); + value.hour = value.getHours(); + value.minute = value.getMinutes(); + value.second = value.getSeconds(); + value.microsecond = value.getMilliseconds(); + } + return value; + }, + update: function(dict){ + this.push(); + if(dict){ + dojo.mixin(this, dict); + } + } + }); + + var ddt = dd.text = { + types: {tag: -1, varr: -2, text: 3}, + pySplit: function(str){ + // summary: Split a string according to Python's split function + str = dojo.trim(str); + return (!str.length) ? [] : str.split(/\s+/g); + }, + _get: function(module, name, errorless){ + // summary: Used to find both tags and filters + var params = dd.register.get(module, name.toLowerCase(), errorless); + if(!params){ + if(!errorless){ + throw new Error("No tag found for " + name); + } + return null; + } + + var fn = params[1]; + var require = params[2]; + + var parts; + if(fn.indexOf(":") != -1){ + parts = fn.split(":"); + fn = parts.pop(); + } + + dojo["require"](require); + + var parent = dojo.getObject(require); + + return parent[fn || name] || parent[name + "_"]; + }, + getTag: function(name, errorless){ + return ddt._get("tag", name, errorless); + }, + getFilter: function(name, errorless){ + return ddt._get("filter", name, errorless); + }, + getTemplate: function(file){ + return new dd.Template(dd.getTemplateString(file)); + }, + getTemplateString: function(file){ + return dojo._getText(file.toString()) || ""; + }, + _resolveLazy: function(location, sync, json){ + if(sync){ + if(json){ + return dojo.fromJson(dojo._getText(location)) || {}; + }else{ + return dd.text.getTemplateString(location); + } + }else{ + return dojo.xhrGet({ + handleAs: (json) ? "json" : "text", + url: location + }); + } + }, + _resolveTemplateArg: function(arg, sync){ + if(ddt._isTemplate(arg)){ + if(!sync){ + var d = new dojo.Deferred(); + d.callback(arg); + return d; + } + return arg; + } + return ddt._resolveLazy(arg, sync); + }, + _isTemplate: function(arg){ + return (typeof arg == "undefined") || (dojo.isString(arg) && (arg.match(/^\s*[<{]/) || arg.indexOf(" ") != -1)); + }, + _resolveContextArg: function(arg, sync){ + if(arg.constructor == Object){ + if(!sync){ + var d = new dojo.Deferred; + d.callback(arg); + return d; + } + return arg; + } + return ddt._resolveLazy(arg, sync, true); + }, + _re: /(?:\{\{\s*(.+?)\s*\}\}|\{%\s*(load\s*)?(.+?)\s*%\})/g, + tokenize: function(str){ + return dojox.string.tokenize(str, ddt._re, ddt._parseDelims); + }, + _parseDelims: function(varr, load, tag){ + var types = ddt.types; + if(varr){ + return [types.varr, varr]; + }else if(load){ + var parts = dd.text.pySplit(tag); + for(var i = 0, part; part = parts[i]; i++){ + dojo["require"](part); + } + }else{ + return [types.tag, tag]; + } + } + } + + dd.Template = dojo.extend(function(/*String|dojo._Url*/ template){ + // template: + // The string or location of the string to + // use as a template + var str = ddt._resolveTemplateArg(template, true) || ""; + var tokens = ddt.tokenize(str); + var parser = new dd._Parser(tokens); + this.nodelist = parser.parse(); + }, + { + update: function(node, context){ + // node: DOMNode|String|dojo.NodeList + // A node reference or set of nodes + // context: dojo._Url|String|Object + // The context object or location + return ddt._resolveContextArg(context).addCallback(this, function(contextObject){ + var content = this.render(new dd._Context(contextObject)); + if(node.forEach){ + node.forEach(function(item){ + item.innerHTML = content; + }); + }else{ + dojo.byId(node).innerHTML = content; + } + return this; + }); + }, + render: function(context, /*concatenatable?*/ buffer){ + buffer = buffer || this.getBuffer(); + context = context || new dd._Context({}); + return this.nodelist.render(context, buffer) + ""; + }, + getBuffer: function(){ + dojo.require("dojox.string.Builder"); + return new dojox.string.Builder(); + } + }); + + dd._Filter = dojo.extend(function(token){ + // summary: Uses a string to find (and manipulate) a variable + if(!token) throw new Error("Filter must be called with variable name"); + this.contents = token; + + var cache = this._cache[token]; + if(cache){ + this.key = cache[0]; + this.filters = cache[1]; + }else{ + this.filters = []; + dojox.string.tokenize(token, this._re, this._tokenize, this); + this._cache[token] = [this.key, this.filters]; + } + }, + { + _cache: {}, + _re: /(?:^_\("([^\\"]*(?:\\.[^\\"])*)"\)|^"([^\\"]*(?:\\.[^\\"]*)*)"|^([a-zA-Z0-9_.]+)|\|(\w+)(?::(?:_\("([^\\"]*(?:\\.[^\\"])*)"\)|"([^\\"]*(?:\\.[^\\"]*)*)"|([a-zA-Z0-9_.]+)|'([^\\']*(?:\\.[^\\']*)*)'))?|^'([^\\']*(?:\\.[^\\']*)*)')/g, + _values: { + 0: '"', // _("text") + 1: '"', // "text" + 2: "", // variable + 8: '"' // 'text' + }, + _args: { + 4: '"', // :_("text") + 5: '"', // :"text" + 6: "", // :variable + 7: "'"// :'text' + }, + _tokenize: function(){ + var pos, arg; + + for(var i = 0, has = []; i < arguments.length; i++){ + has[i] = (typeof arguments[i] != "undefined" && dojo.isString(arguments[i]) && arguments[i]); + } + + if(!this.key){ + for(pos in this._values){ + if(has[pos]){ + this.key = this._values[pos] + arguments[pos] + this._values[pos]; + break; + } + } + }else{ + for(pos in this._args){ + if(has[pos]){ + var value = arguments[pos]; + if(this._args[pos] == "'"){ + value = value.replace(/\\'/g, "'"); + }else if(this._args[pos] == '"'){ + value = value.replace(/\\"/g, '"'); + } + arg = [!this._args[pos], value]; + break; + } + } + // Get a named filter + var fn = ddt.getFilter(arguments[3]); + if(!dojo.isFunction(fn)) throw new Error(arguments[3] + " is not registered as a filter"); + this.filters.push([fn, arg]); + } + }, + getExpression: function(){ + return this.contents; + }, + resolve: function(context){ + var str = this.resolvePath(this.key, context); + for(var i = 0, filter; filter = this.filters[i]; i++){ + // Each filter has the function in [0], a boolean in [1][0] of whether it's a variable or a string + // and [1][1] is either the variable name of the string content. + if(filter[1]){ + if(filter[1][0]){ + str = filter[0](str, this.resolvePath(filter[1][1], context)); + }else{ + str = filter[0](str, filter[1][1]); + } + }else{ + str = filter[0](str); + } + } + return str; + }, + resolvePath: function(path, context){ + var current, parts; + var first = path.charAt(0); + var last = path.slice(-1); + if(!isNaN(parseInt(first))){ + current = (path.indexOf(".") == -1) ? parseInt(path) : parseFloat(path); + }else if(first == '"' && first == last){ + current = path.slice(1, -1); + }else{ + if(path == "true"){ return true; } + if(path == "false"){ return false; } + if(path == "null" || path == "None"){ return null; } + parts = path.split("."); + current = context.get(parts[0]); + for(var i = 1; i < parts.length; i++){ + var part = parts[i]; + if(current){ + if(dojo.isObject(current) && part == "items" && typeof current[part] == "undefined"){ + var items = []; + for(var key in current){ + items.push([key, current[key]]); + } + current = items; + continue; + } + + if(current.get && dojo.isFunction(current.get)){ + current = current.get(part); + }else if(typeof current[part] == "undefined"){ + current = current[part]; + break; + }else{ + current = current[part]; + } + + if(dojo.isFunction(current)){ + if(current.alters_data){ + current = ""; + }else{ + current = current(); + } + } + }else{ + return ""; + } + } + } + return current; + } + }); + + dd._TextNode = dd._Node = dojo.extend(function(/*Object*/ obj){ + // summary: Basic catch-all node + this.contents = obj; + }, + { + set: function(data){ + this.contents = data; + }, + render: function(context, buffer){ + // summary: Adds content onto the buffer + return buffer.concat(this.contents); + } + }); + + dd._NodeList = dojo.extend(function(/*Node[]*/ nodes){ + // summary: Allows us to render a group of nodes + this.contents = nodes || []; + this.last = ""; + }, + { + push: function(node){ + // summary: Add a new node to the list + this.contents.push(node); + }, + render: function(context, buffer){ + // summary: Adds all content onto the buffer + for(var i = 0; i < this.contents.length; i++){ + buffer = this.contents[i].render(context, buffer); + if(!buffer) throw new Error("Template must return buffer"); + } + return buffer; + }, + dummyRender: function(context){ + return this.render(context, dd.Template.prototype.getBuffer()).toString(); + }, + unrender: function(){ return arguments[1]; }, + clone: function(){ return this; } + }); + + dd._VarNode = dojo.extend(function(str){ + // summary: A node to be processed as a variable + this.contents = new dd._Filter(str); + }, + { + render: function(context, buffer){ + var str = this.contents.resolve(context); + return buffer.concat(str); + } + }); + + dd._noOpNode = new function(){ + // summary: Adds a no-op node. Useful in custom tags + this.render = this.unrender = function(){ return arguments[1]; } + this.clone = function(){ return this; } + } + + dd._Parser = dojo.extend(function(tokens){ + // summary: Parser used during initialization and for tag groups. + this.contents = tokens; + }, + { + i: 0, + parse: function(/*Array?*/ stop_at){ + // summary: Turns tokens into nodes + // description: Steps into tags are they're found. Blocks use the parse object + // to find their closing tag (the stop_at array). stop_at is inclusive, it + // returns the node that matched. + var types = ddt.types; + var terminators = {}; + stop_at = stop_at || []; + for(var i = 0; i < stop_at.length; i++){ + terminators[stop_at[i]] = true; + } + + var nodelist = new dd._NodeList(); + while(this.i < this.contents.length){ + token = this.contents[this.i++]; + if(dojo.isString(token)){ + nodelist.push(new dd._TextNode(token)); + }else{ + var type = token[0]; + var text = token[1]; + if(type == types.varr){ + nodelist.push(new dd._VarNode(text)); + }else if(type == types.tag){ + if(terminators[text]){ + --this.i; + return nodelist; + } + var cmd = text.split(/\s+/g); + if(cmd.length){ + cmd = cmd[0]; + var fn = ddt.getTag(cmd); + if(fn){ + nodelist.push(fn(this, text)); + } + } + } + } + } + + if(stop_at.length){ + throw new Error("Could not find closing tag(s): " + stop_at.toString()); + } + + this.contents.length = 0; + return nodelist; + }, + next: function(){ + // summary: Returns the next token in the list. + var token = this.contents[this.i++]; + return {type: token[0], text: token[1]}; + }, + skipPast: function(endtag){ + var types = ddt.types; + while(this.i < this.contents.length){ + var token = this.contents[this.i++]; + if(token[0] == types.tag && token[1] == endtag){ + return; + } + } + throw new Error("Unclosed tag found when looking for " + endtag); + }, + getVarNodeConstructor: function(){ + return dd._VarNode; + }, + getTextNodeConstructor: function(){ + return dd._TextNode; + }, + getTemplate: function(file){ + return new dd.Template(file); + } + }); + + dd.register = { + _registry: { + attributes: [], + tags: [], + filters: [] + }, + get: function(/*String*/ module, /*String*/ name){ + var registry = dd.register._registry[module + "s"]; + for(var i = 0, entry; entry = registry[i]; i++){ + if(dojo.isString(entry[0])){ + if(entry[0] == name){ + return entry; + } + }else if(name.match(entry[0])){ + return entry; + } + } + }, + getAttributeTags: function(){ + var tags = []; + var registry = dd.register._registry.attributes; + for(var i = 0, entry; entry = registry[i]; i++){ + if(entry.length == 3){ + tags.push(entry); + }else{ + var fn = dojo.getObject(entry[1]); + if(fn && dojo.isFunction(fn)){ + entry.push(fn); + tags.push(entry); + } + } + } + return tags; + }, + _any: function(type, base, locations){ + for(var path in locations){ + for(var i = 0, fn; fn = locations[path][i]; i++){ + var key = fn; + if(dojo.isArray(fn)){ + key = fn[0]; + fn = fn[1]; + } + if(dojo.isString(key)){ + if(key.substr(0, 5) == "attr:"){ + var attr = fn; + if(attr.substr(0, 5) == "attr:"){ + attr = attr.slice(5); + } + dd.register._registry.attributes.push([attr, base + "." + path + "." + attr]); + } + key = key.toLowerCase(); + } + dd.register._registry[type].push([ + key, + fn, + base + "." + path + ]); + } + } + }, + tags: function(/*String*/ base, /*Object*/ locations){ + dd.register._any("tags", base, locations); + }, + filters: function(/*String*/ base, /*Object*/ locations){ + dd.register._any("filters", base, locations); + } + } + + dd.register.tags("dojox.dtl.tag", { + "date": ["now"], + "logic": ["if", "for", "ifequal", "ifnotequal"], + "loader": ["extends", "block", "include", "load", "ssi"], + "misc": ["comment", "debug", "filter", "firstof", "spaceless", "templatetag", "widthratio", "with"], + "loop": ["cycle", "ifchanged", "regroup"] + }); + dd.register.filters("dojox.dtl.filter", { + "dates": ["date", "time", "timesince", "timeuntil"], + "htmlstrings": ["escape", "linebreaks", "linebreaksbr", "removetags", "striptags"], + "integers": ["add", "get_digit"], + "lists": ["dictsort", "dictsortreversed", "first", "join", "length", "length_is", "random", "slice", "unordered_list"], + "logic": ["default", "default_if_none", "divisibleby", "yesno"], + "misc": ["filesizeformat", "pluralize", "phone2numeric", "pprint"], + "strings": ["addslashes", "capfirst", "center", "cut", "fix_ampersands", "floatformat", "iriencode", "linenumbers", "ljust", "lower", "make_list", "rjust", "slugify", "stringformat", "title", "truncatewords", "truncatewords_html", "upper", "urlencode", "urlize", "urlizetrunc", "wordcount", "wordwrap"] + }); +})(); + +} diff --git a/includes/js/dojox/dtl/contrib/data.js b/includes/js/dojox/dtl/contrib/data.js new file mode 100644 index 0000000..5ca3aa7 --- /dev/null +++ b/includes/js/dojox/dtl/contrib/data.js @@ -0,0 +1,89 @@ +if(!dojo._hasResource["dojox.dtl.contrib.data"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.contrib.data"] = true; +dojo.provide("dojox.dtl.contrib.data"); +dojo.require("dojox.dtl._base"); + +(function(){ + var dd = dojox.dtl; + var ddcd = dd.contrib.data; + + ddcd._BoundItem = dojo.extend(function(item, store){ + this.item = item; + this.store = store; + }, + { + get: function(key){ + var store = this.store; + var item = this.item; + + if(key == "getLabel"){ + return store.getLabel(item); + }else if(key == "getAttributes"){ + return store.getAttributes(item); + }else if(key == "getIdentity"){ + if(store.getIdentity){ + return store.getIdentity(item); + } + return "Store has no identity API"; + }else{ + if(store.hasAttribute(item, key)){ + var value = store.getValue(item, key); + return (dojo.isObject(value) && store.isItem(value)) ? new ddcd._BoundItem(value, store) : value; + }else if(key.slice(-1) == "s" && store.hasAttribute(item, key.slice(0, -1))){ + return dojo.map(store.getValues(item, key.slice(0, -1)), function(value){ + return (dojo.isObject(value) && store.isItem(value)) ? new ddcd._BoundItem(value, store) : value; + }); + } + } + } + }); + + ddcd.BindDataNode = dojo.extend(function(items, store, alias){ + this.items = new dd._Filter(items); + this.store = new dd._Filter(store); + this.alias = alias; + }, + { + render: function(context, buffer){ + var items = this.items.resolve(context); + var store = this.store.resolve(context); + if(!store){ + throw new Error("data_bind didn't receive a store"); + } + + var list = []; + if(items){ + for(var i = 0, item; item = items[i]; i++){ + list.push(new ddcd._BoundItem(item, store)); + } + } + + context[this.alias] = list; + return buffer; + }, + unrender: function(context, buffer){ + return buffer; + }, + clone: function(){ + return this; + } + }); + + dojo.mixin(ddcd, { + bind_data: function(parser, text){ + var parts = dd.text.pySplit(text); + + if(parts[2] != 'to' || parts[4] != 'as' || !parts[5]){ + throw new Error("data_bind expects the format: 'data_bind items to store as varName'"); + } + + return new ddcd.BindDataNode(parts[1], parts[3], parts[5]); + } + }); + + dd.register.tags("dojox.dtl.contrib", { + "data": ["bind_data"] + }); +})(); + +} diff --git a/includes/js/dojox/dtl/contrib/dijit.js b/includes/js/dojox/dtl/contrib/dijit.js new file mode 100644 index 0000000..41caf33 --- /dev/null +++ b/includes/js/dojox/dtl/contrib/dijit.js @@ -0,0 +1,220 @@ +if(!dojo._hasResource["dojox.dtl.contrib.dijit"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.contrib.dijit"] = true; +dojo.provide("dojox.dtl.contrib.dijit"); + +dojo.require("dojox.dtl.html"); +dojo.require("dojo.parser"); + +(function(){ + var dd = dojox.dtl; + var ddcd = dd.contrib.dijit; + + ddcd.AttachNode = dojo.extend(function(keys, object){ + this._keys = keys; + this._object = object; + }, + { + render: function(context, buffer){ + if(!this._rendered){ + this._rendered = true; + for(var i=0, key; key = this._keys[i]; i++){ + context.getThis()[key] = this._object || buffer.getParent(); + } + } + return buffer; + }, + unrender: function(context, buffer){ + if(this._rendered){ + this._rendered = false; + for(var i=0, key; key = this._keys[i]; i++){ + if(context.getThis()[key] === (this._object || buffer.getParent())){ + delete context.getThis()[key]; + } + } + } + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this._keys, this._object); + } + }); + + ddcd.EventNode = dojo.extend(function(command, obj){ + this._command = command; + + var type, events = command.split(/\s*,\s*/); + var trim = dojo.trim; + var types = []; + var fns = []; + while(type = events.pop()){ + if(type){ + var fn = null; + if(type.indexOf(":") != -1){ + // oh, if only JS had tuple assignment + var funcNameArr = type.split(":"); + type = trim(funcNameArr[0]); + fn = trim(funcNameArr[1]); + }else{ + type = trim(type); + } + if(!fn){ + fn = type; + } + types.push(type); + fns.push(fn); + } + } + + this._types = types; + this._fns = fns; + this._object = obj; + this._rendered = []; + }, + { + // _clear: Boolean + // Make sure we kill the actual tags (onclick problems, etc) + _clear: false, + render: function(context, buffer){ + for(var i = 0, type; type = this._types[i]; i++){ + if(!this._clear && !this._object){ + buffer.getParent()[type] = null; + } + var fn = this._fns[i]; + var args; + if(fn.indexOf(" ") != -1){ + if(this._rendered[i]){ + dojo.disconnect(this._rendered[i]); + this._rendered[i] = false; + } + args = dojo.map(fn.split(" ").slice(1), function(item){ + return new dd._Filter(item).resolve(context); + }); + fn = fn[0]; + } + if(!this._rendered[i]){ + if(!this._object){ + this._rendered[i] = buffer.addEvent(context, type, fn, args); + }else{ + this._rendered[i] = dojo.connect(this._object, type, context.getThis(), fn); + } + } + } + this._clear = true; + + return buffer; + }, + unrender: function(context, buffer){ + while(this._rendered.length){ + dojo.disconnect(this._rendered.pop()); + } + return buffer; + }, + clone: function(){ + return new this.constructor(this._command, this._object); + } + }); + + function cloneNode(n1){ + var n2 = n1.cloneNode(true); + if(dojo.isIE){ + dojo.query("script", n2).forEach("item.text = this[index].text;", dojo.query("script", n1)); + } + return n2; + } + + ddcd.DojoTypeNode = dojo.extend(function(node, parsed){ + this._node = node; + this._parsed = parsed; + + var events = node.getAttribute("dojoAttachEvent"); + if(events){ + this._events = new ddcd.EventNode(dojo.trim(events)); + } + var attach = node.getAttribute("dojoAttachPoint"); + if(attach){ + this._attach = new ddcd.AttachNode(dojo.trim(attach).split(/\s*,\s*/)); + } + + if (!parsed){ + this._dijit = dojo.parser.instantiate([cloneNode(node)])[0]; + }else{ + node = cloneNode(node); + var old = ddcd.widgetsInTemplate; + ddcd.widgetsInTemplate = false; + this._template = new dd.HtmlTemplate(node); + ddcd.widgetsInTemplate = old; + } + }, + { + render: function(context, buffer){ + if(this._parsed){ + var _buffer = new dd.HtmlBuffer(); + this._template.render(context, _buffer); + var root = cloneNode(_buffer.getRootNode()); + var div = document.createElement("div"); + div.appendChild(root); + var rendered = div.innerHTML; + div.removeChild(root); + if(rendered != this._rendered){ + this._rendered = rendered; + if(this._dijit){ + this._dijit.destroyRecursive(); + } + this._dijit = dojo.parser.instantiate([root])[0]; + } + } + + var node = this._dijit.domNode; + + if(this._events){ + this._events._object = this._dijit; + this._events.render(context, buffer); + } + if(this._attach){ + this._attach._object = this._dijit; + this._attach.render(context, buffer); + } + + return buffer.concat(node); + }, + unrender: function(context, buffer){ + return buffer.remove(this._dijit.domNode); + }, + clone: function(){ + return new this.constructor(this._node, this._parsed); + } + }); + + dojo.mixin(ddcd, { + widgetsInTemplate: true, + dojoAttachPoint: function(parser, text){ + return new ddcd.AttachNode(dojo.trim(text).slice(16).split(/\s*,\s*/)); + }, + dojoAttachEvent: function(parser, text){ + return new ddcd.EventNode(text.slice(16)); + }, + dojoType: function(parser, text){ + if(ddcd.widgetsInTemplate){ + var node = parser.swallowNode(); + var parsed = false; + if(text.slice(-7) == " parsed"){ + parsed = true; + node.setAttribute("dojoType", dojo.trim(text).slice(0, -7)); + } + return new ddcd.DojoTypeNode(node, parsed); + } + return dd._noOpNode; + }, + on: function(parser, text){ + // summary: Associates an event type to a function (on the current widget) by name + var parts = text.split(" "); + return new ddcd.EventNode(parts[0] + ":" + parts.slice(1).join(" ")); + } + }); + + dd.register.tags("dojox.dtl.contrib", { + "dijit": ["attr:dojoType", "attr:dojoAttachPoint", ["attr:attach", "dojoAttachPoint"], "attr:dojoAttachEvent", [/(attr:)?on(click|key(up))/i, "on"]] + }); +})(); + +} diff --git a/includes/js/dojox/dtl/contrib/html.js b/includes/js/dojox/dtl/contrib/html.js new file mode 100644 index 0000000..260bbe2 --- /dev/null +++ b/includes/js/dojox/dtl/contrib/html.js @@ -0,0 +1,107 @@ +if(!dojo._hasResource["dojox.dtl.contrib.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.contrib.html"] = true; +dojo.provide("dojox.dtl.contrib.html"); + +dojo.require("dojox.dtl.html"); + +(function(){ + var dd = dojox.dtl; + var ddch = dd.contrib.html; + + ddch.HtmlNode = dojo.extend(function(name){ + this.contents = new dd._Filter(name); + this._div = document.createElement("div"); + this._lasts = []; + }, + { + render: function(context, buffer){ + var text = this.contents.resolve(context); + if(text){ + text = text.replace(/<(\/?script)/ig, '<$1').replace(/\bon[a-z]+\s*=/ig, ''); + if(this._rendered && this._last != text){ + buffer = this.unrender(context, buffer); + } + this._last = text; + + // This can get reset in the above tag + if(!this._rendered){ + this._rendered = true; + var div = this._div; + div.innerHTML = text; + var children = div.childNodes; + while(children.length){ + var removed = div.removeChild(children[0]); + this._lasts.push(removed); + buffer = buffer.concat(removed); + } + } + } + + return buffer; + }, + unrender: function(context, buffer){ + if(this._rendered){ + this._rendered = false; + this._last = ""; + for(var i = 0, node; node = this._lasts[i++];){ + buffer = buffer.remove(node); + dojo._destroyElement(node); + } + this._lasts = []; + } + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this.contents.getExpression()); + } + }); + + ddch.StyleNode = dojo.extend(function(styles){ + this.contents = {}; + this._styles = styles; + for(var key in styles){ + this.contents[key] = new dd.Template(styles[key]); + } + }, + { + render: function(context, buffer){ + for(var key in this.contents){ + dojo.style(buffer.getParent(), key, this.contents[key].render(context)); + } + return buffer; + }, + unrender: function(context, buffer){ + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this._styles); + } + }); + + dojo.mixin(ddch, { + html: function(parser, text){ + var parts = text.split(" ", 2); + return new ddch.HtmlNode(parts[1]); + }, + tstyle: function(parser, text){ + var styles = {}; + text = text.replace(/^tstyle\s+/, ""); + var rules = text.split(/\s*;\s*/g); + for(var i = 0, rule; rule = rules[i]; i++){ + var parts = rule.split(/\s*:\s*/g); + var key = parts[0]; + var value = parts[1]; + if(value.indexOf("{{") == 0){ + styles[key] = value; + } + } + return new ddch.StyleNode(styles); + } + }); + + dd.register.tags("dojox.dtl.contrib", { + "html": ["html", "attr:tstyle"] + }); +})(); + +} diff --git a/includes/js/dojox/dtl/contrib/objects.js b/includes/js/dojox/dtl/contrib/objects.js new file mode 100644 index 0000000..d29c0df --- /dev/null +++ b/includes/js/dojox/dtl/contrib/objects.js @@ -0,0 +1,15 @@ +if(!dojo._hasResource["dojox.dtl.contrib.objects"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.contrib.objects"] = true; +dojo.provide("dojox.dtl.contrib.objects"); + +dojo.mixin(dojox.dtl.contrib.objects, { + key: function(value, arg){ + return value[arg]; + } +}); + +dojox.dtl.register.filters("dojox.dtl.contrib", { + "objects": ["key"] +}); + +} diff --git a/includes/js/dojox/dtl/demos/demo_Animation.html b/includes/js/dojox/dtl/demos/demo_Animation.html new file mode 100644 index 0000000..1a5e278 --- /dev/null +++ b/includes/js/dojox/dtl/demos/demo_Animation.html @@ -0,0 +1,45 @@ + + + Testing dojox.dtl using animation to change attributes + + + + +
+ + \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/demo_Blog.html b/includes/js/dojox/dtl/demos/demo_Blog.html new file mode 100644 index 0000000..c9bd990 --- /dev/null +++ b/includes/js/dojox/dtl/demos/demo_Blog.html @@ -0,0 +1,96 @@ + + + Testing dojox.dtl using a blog example + + + + +
+ + diff --git a/includes/js/dojox/dtl/demos/demo_Data.html b/includes/js/dojox/dtl/demos/demo_Data.html new file mode 100644 index 0000000..93bb76f --- /dev/null +++ b/includes/js/dojox/dtl/demos/demo_Data.html @@ -0,0 +1,58 @@ + + + Demo using the dojo.data bind_data tag + + + + +
+ + + \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/demo_Dijitless.html b/includes/js/dojox/dtl/demos/demo_Dijitless.html new file mode 100644 index 0000000..2aaceaa --- /dev/null +++ b/includes/js/dojox/dtl/demos/demo_Dijitless.html @@ -0,0 +1,50 @@ + + + Demo using dojox.dtl._HtmlTemplated without Dijit + + + + +
+ + diff --git a/includes/js/dojox/dtl/demos/demo_Events.html b/includes/js/dojox/dtl/demos/demo_Events.html new file mode 100644 index 0000000..aa3da46 --- /dev/null +++ b/includes/js/dojox/dtl/demos/demo_Events.html @@ -0,0 +1,46 @@ + + + Demo using dojox.dtl._Templated + + + + + +
+ + + \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/demo_HtmlTemplated.html b/includes/js/dojox/dtl/demos/demo_HtmlTemplated.html new file mode 100644 index 0000000..71dabe4 --- /dev/null +++ b/includes/js/dojox/dtl/demos/demo_HtmlTemplated.html @@ -0,0 +1,40 @@ + + + Demo using dojox.dtl._HtmlTemplated + + + + + +
+ + + \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/demo_Inline.html b/includes/js/dojox/dtl/demos/demo_Inline.html new file mode 100644 index 0000000..6e17d8e --- /dev/null +++ b/includes/js/dojox/dtl/demos/demo_Inline.html @@ -0,0 +1,48 @@ + + + Demo using dojox.dtl._HtmlTemplated inline in DOM + + + + +
    + {% for item in items %} +
  • {{ item }}
  • + {% endfor %} +
+ +
    + {% for item in items reversed %} +
  • {{ item }}
  • + {% endfor %} +
+ + diff --git a/includes/js/dojox/dtl/demos/demo_NodeList.html b/includes/js/dojox/dtl/demos/demo_NodeList.html new file mode 100644 index 0000000..d1ab0a8 --- /dev/null +++ b/includes/js/dojox/dtl/demos/demo_NodeList.html @@ -0,0 +1,37 @@ + + + Demo using dojox.dtl._Templated + + + + +
+
+
+
+ + diff --git a/includes/js/dojox/dtl/demos/demo_Table.html b/includes/js/dojox/dtl/demos/demo_Table.html new file mode 100644 index 0000000..56dc8ac --- /dev/null +++ b/includes/js/dojox/dtl/demos/demo_Table.html @@ -0,0 +1,4072 @@ + + + Demo to show a massive nested for loop to render a table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexNumericTextCurrencyDate
0158.9Bill$22.442008-12-28
1690.4Joe$3.032009-07-03
2843Bob$11.142010-09-30
357.8Matt$70.642009-12-16
4494.6Mark$9.132010-05-11
5766.3Tom$55.342008-03-10
6699.3Jake$26.242008-11-26
7487.8Greg$72.942010-06-23
8786.2Adam$34.642008-09-19
9188.6Steve$6.332009-01-01
10898.4George$22.242009-09-18
11222.2John$91.242009-10-23
12707.9Phil$75.542010-02-28
13585.5Jack$81.342009-03-24
14213.8Paul$30.742009-07-08
15968.5Rob$7.332008-02-06
1639.3Walt$77.342008-12-05
17335.7Nathan$26.142008-01-27
18127.6Dan$4.732009-03-03
19365.3Jeff$23.542009-05-15
20692.9Bill$13.342010-01-26
21244.9Joe$35.642009-10-16
22827Bob$6.332009-01-06
23519.6Matt$64.942008-06-03
24917.8Mark$86.342009-05-24
25407.1Tom$83.142009-08-17
26449.3Jake$87.042008-11-27
27753.5Greg$20.642009-09-25
28787Adam$33.442009-11-18
29166.9Steve$69.942010-08-17
30609.6George$39.242011-01-18
31274John$63.642009-01-02
32850.3Phil$46.342009-03-17
33181.4Jack$98.342008-02-04
34325.3Paul$90.142010-10-30
35776.3Rob$30.842010-04-17
36300.8Walt$75.742009-11-18
37598Nathan$51.042010-07-15
38155.6Dan$29.742008-06-04
39759.8Jeff$46.442010-08-21
40599.2Bill$7.432008-09-16
41571.9Joe$34.842010-09-23
42900.3Bob$19.842009-01-09
43292.2Matt$37.942008-12-21
44333Mark$70.542008-08-28
45236.4Tom$48.142009-08-19
46970.9Jake$78.242008-11-10
47575.8Greg$37.942010-06-24
48386.7Adam$53.542008-04-02
49531.1Steve$29.542009-09-21
50374.3George$89.442009-12-15
51609.1John$46.642011-01-22
52480.3Phil$36.642008-07-07
53814.8Jack$65.842009-09-19
54132.2Paul$99.142008-10-12
55350.1Rob$22.842010-04-22
56875.7Walt$19.842009-08-12
57158.1Nathan$77.442010-10-25
58950.9Dan$16.142009-05-05
5941.1Jeff$69.242010-04-11
60595.4Bill$6.632009-12-09
61223.4Joe$67.542008-03-30
62199.2Bob$15.642009-05-28
63372.8Matt$97.042008-04-28
64925.7Mark$10.242008-04-17
65183.1Tom$45.342009-01-05
66921.2Jake$32.842009-08-23
67440.8Greg$48.642008-12-04
68339.8Adam$43.742009-06-08
69773.7Steve$47.842008-06-17
70502.3George$7.332008-09-01
71124.8John$29.742010-10-22
72213Phil$49.642008-02-18
73667.3Jack$86.942008-01-14
74779.8Paul$79.442008-05-12
75883.3Rob$97.742009-10-17
76214.4Walt$89.942010-11-01
77743.7Nathan$33.942009-03-16
7847Dan$67.942010-08-04
79511Jeff$45.342008-12-08
80666.7Bill$95.542009-03-03
81888.5Joe$8.032010-02-09
82785.4Bob$29.342008-07-06
83837.7Matt$96.042008-02-05
84860.2Mark$74.042010-08-12
85985Tom$62.342010-07-17
86562.3Jake$83.742010-03-21
87467.6Greg$58.142008-02-16
88859Adam$62.842010-04-12
89687.5Steve$13.942008-07-17
90993.9George$80.542008-05-26
91373.8John$69.442008-08-26
9250.4Phil$47.942009-07-30
93222.8Jack$31.742009-06-14
94263.9Paul$17.742008-08-16
9599.2Rob$16.242010-08-07
96911.8Walt$72.442010-01-31
97623Nathan$19.242008-10-03
98673.4Dan$5.032010-09-29
99402.8Jeff$73.842008-01-06
100584.8Bill$73.242010-07-26
101721.7Joe$10.642009-08-06
102938.1Bob$15.642011-02-11
103447.1Matt$37.942008-12-12
104915.9Mark$64.342009-07-05
105124.2Tom$74.242010-01-08
106955.3Jake$65.342009-02-23
107623.6Greg$27.642009-10-02
108872.6Adam$95.042009-11-30
109749.4Steve$35.342009-01-30
110764.7George$93.742008-03-26
111585.4John$65.942008-07-26
11299.8Phil$59.742009-01-23
11393.2Jack$4.432010-04-06
114403.3Paul$96.042009-02-16
115890.2Rob$8.432008-04-23
116538.9Walt$3.932010-05-19
117911.6Nathan$66.342008-02-02
118475.9Dan$53.542011-02-05
11990.7Jeff$28.542009-01-16
120443.3Bill$5.032008-11-05
121527.7Joe$63.542010-12-07
122717.7Bob$73.542009-08-28
12363.5Matt$82.842009-10-18
124788Mark$23.142009-09-02
125155Tom$12.142009-12-08
126263.6Jake$66.042010-01-22
12725.6Greg$57.242008-12-28
12863.9Adam$4.732010-09-09
12952Steve$13.842008-06-03
130392.5George$58.142008-07-31
131670.3John$10.942010-08-04
132607Phil$82.742009-10-01
133140.7Jack$89.042009-03-16
134718.3Paul$67.842009-12-08
135255.9Rob$83.342010-04-27
136877.6Walt$9.732009-03-29
137538.6Nathan$12.242011-01-20
138862.5Dan$18.642008-01-13
139721.9Jeff$23.842008-06-21
140866.2Bill$63.042010-04-25
14159.9Joe$30.142010-08-29
142888.4Bob$90.842010-02-09
143451.5Matt$4.832009-10-05
144842.2Mark$76.742008-09-27
145463.9Tom$2.232008-03-18
146206.6Jake$90.042008-07-08
147609.3Greg$43.842008-11-26
148583.6Adam$30.142009-06-29
149605.2Steve$2.332010-03-31
150764.8George$88.942009-01-27
151505.6John$94.942010-01-10
152355.4Phil$83.742009-09-25
15331.9Jack$28.842009-11-20
154598.4Paul$13.142009-02-23
155842.9Rob$59.442009-03-20
156920.5Walt$80.142008-11-24
15794.5Nathan$41.042010-04-16
158390.6Dan$99.442008-01-28
159872.6Jeff$59.942008-02-23
160592.3Bill$36.442010-12-18
161942.4Joe$86.942010-10-19
162593Bob$22.442010-04-13
163151.1Matt$25.642008-01-11
164757.4Mark$85.542008-06-10
165130Tom$69.842010-04-29
166525Jake$61.842009-09-10
167819.8Greg$71.342010-12-29
168552.9Adam$10.342010-12-22
169586.8Steve$97.542009-09-13
170643.5George$56.842010-11-08
171588.9John$51.042010-06-10
172482.9Phil$10.342007-12-25
173213.9Jack$25.442008-10-17
174233.2Paul$1.132008-05-01
175383Rob$14.242010-07-18
176127.1Walt$66.742009-05-01
177672.2Nathan$48.642008-06-03
178627.4Dan$3.932008-09-30
179576.3Jeff$62.642008-09-01
180124.1Bill$26.942010-06-20
18135.3Joe$85.842008-11-30
182815.7Bob$34.142009-03-30
183820.6Matt$55.542010-01-18
18481.8Mark$78.842010-01-31
185197.5Tom$17.142010-07-14
18610.8Jake$29.842009-06-23
187442Greg$97.042011-01-06
188585.7Adam$59.742007-12-21
189832.2Steve$17.442009-12-14
19054.3George$29.842010-10-22
191844John$33.342010-05-10
192143.9Phil$14.942008-04-07
193546.8Jack$96.942010-01-09
194203.8Paul$5.132009-05-09
195872.3Rob$24.842009-11-22
196682.3Walt$25.942010-11-02
197158.7Nathan$70.142010-09-28
198121.2Dan$28.742009-06-19
199122.6Jeff$11.942010-01-06
200749.8Bill$17.342010-12-17
201646.1Joe$1.732008-11-05
202400.4Bob$16.142009-04-26
203495.5Matt$70.842009-03-21
204145.3Mark$91.242009-05-19
205582.9Tom$78.442010-03-02
206191.3Jake$46.642010-12-27
20797.5Greg$62.542010-01-15
208973.7Adam$74.642010-12-13
209447.2Steve$86.842008-02-27
21094.3George$61.842008-09-15
21139John$26.442008-10-04
212316.7Phil$66.542009-04-09
213743Jack$16.042008-05-05
214138.4Paul$30.542008-01-24
215584.7Rob$88.842010-07-19
216279.3Walt$7.932008-11-08
217233Nathan$17.742010-11-01
218887.8Dan$15.042010-01-11
219829.3Jeff$59.842009-08-12
220889.7Bill$69.242008-05-27
221123.3Joe$73.142009-03-29
222373.9Bob$4.732008-03-06
223785.6Matt$79.042008-09-07
224904.9Mark$92.942009-08-26
225935.8Tom$51.342009-04-19
226750.5Jake$79.342009-07-19
22731.2Greg$2.532010-02-09
228936.7Adam$91.342010-08-02
229588Steve$74.242009-04-23
230107.7George$63.242008-05-01
231245.7John$75.542010-08-25
232647.8Phil$12.942010-10-19
233714.6Jack$91.542010-02-18
234941.3Paul$82.042009-11-28
235473.3Rob$75.542008-05-13
236893.4Walt$50.642010-11-17
237392.7Nathan$53.742010-12-16
23868.8Dan$47.442010-09-06
239895.2Jeff$6.132009-11-12
240319.1Bill$16.942008-09-12
241434.7Joe$41.542011-02-04
242281.1Bob$6.332008-05-02
243174.8Matt$77.742008-01-24
244859Mark$71.842010-08-30
245471.8Tom$19.142009-11-19
246597.9Jake$8.532008-04-26
247516.5Greg$47.842010-01-08
248460.6Adam$54.642008-05-08
249317.8Steve$44.142008-07-18
250917.4George$76.042009-01-30
251149.1John$19.542010-05-25
252136.1Phil$47.642010-08-05
253252.2Jack$65.142009-11-20
254283Paul$51.042008-12-29
255133.3Rob$98.242009-08-08
256739Walt$57.942009-11-14
257850.4Nathan$9.632008-03-19
258498.6Dan$55.642009-12-11
259620.3Jeff$87.442008-03-04
260803.4Bill$79.142010-08-01
261155.5Joe$94.042008-01-13
262922.3Bob$7.632009-07-17
263751.6Matt$32.942008-06-07
264357.9Mark$61.142010-01-18
265682.4Tom$74.542009-12-28
266198.4Jake$48.442008-08-28
267799.1Greg$33.442008-12-17
268877.4Adam$83.342010-09-21
269501.7Steve$45.342010-04-28
270567.4George$25.642009-08-30
271393.4John$41.142009-06-22
272414.4Phil$33.442009-09-18
273911.4Jack$8.532010-10-03
27459.2Paul$44.342009-07-10
275716.7Rob$12.642008-09-18
276355.7Walt$32.442010-04-01
277573.9Nathan$12.342008-02-20
278887.7Dan$0.032010-10-10
279757.8Jeff$50.242009-01-15
280501.7Bill$6.932009-11-07
28136.9Joe$46.342007-12-27
282512.4Bob$87.742009-01-16
28364.3Matt$78.842009-04-25
284944.6Mark$84.742010-09-20
285436.3Tom$56.442011-02-12
286672.6Jake$92.042008-12-21
287392.6Greg$49.442009-05-13
288446.5Adam$38.142009-05-13
289333Steve$13.942010-12-15
290672.1George$64.142008-01-02
291267.3John$67.842009-06-21
292273.9Phil$19.042009-01-29
293614.3Jack$25.442008-05-29
29440Paul$19.942011-02-04
295908.8Rob$63.542009-09-17
296903.1Walt$30.842009-06-17
297221.2Nathan$70.042011-01-09
298662.1Dan$14.742009-01-23
299103.2Jeff$47.942009-07-03
30046.2Bill$15.242008-05-13
30158.3Joe$41.942010-07-06
302533Bob$69.342011-02-10
303884.6Matt$30.742008-09-30
30424.5Mark$34.742009-05-18
30511.7Tom$25.642008-03-22
306563Jake$15.942009-03-12
30734.1Greg$38.042008-03-30
308998.8Adam$4.232008-09-16
309344.7Steve$14.542010-03-25
310829.5George$19.142010-09-16
311955John$24.942008-11-12
312758Phil$78.342011-01-23
313750.8Jack$66.742008-11-11
314997.8Paul$69.142009-12-18
315443.5Rob$70.342010-10-10
316524Walt$26.642008-02-09
317912Nathan$30.042009-04-24
3181000Dan$29.942009-06-11
319234.5Jeff$64.342009-11-26
320948.4Bill$47.342010-07-05
321813.7Joe$42.842008-02-18
32297.7Bob$18.642010-08-11
32374.3Matt$93.742009-07-22
324357.7Mark$93.442008-07-29
325988Tom$37.842010-10-21
326873.8Jake$90.242008-06-24
327918.3Greg$81.442009-06-06
328342.7Adam$81.442010-05-18
329809Steve$4.832009-03-31
330420.4George$99.742010-09-30
331223John$81.042008-12-06
332275Phil$90.842009-07-09
333109.5Jack$98.242009-04-27
334610.9Paul$34.042009-02-10
335803.7Rob$32.842010-04-23
336699.6Walt$20.142009-12-30
337861.4Nathan$12.042009-05-28
338323.4Dan$46.242008-10-25
33984.3Jeff$27.142008-12-19
340488.6Bill$69.242008-12-15
341365.7Joe$91.542008-05-10
342670.8Bob$19.042008-01-24
343161.5Matt$29.942008-01-03
344588.8Mark$91.042009-01-30
345950.3Tom$71.442010-02-13
346689.5Jake$41.342010-10-04
347330.4Greg$27.442007-12-20
348785Adam$59.842009-06-07
34953.2Steve$68.242010-04-17
350369.6George$17.142009-04-25
351682.4John$53.642009-01-17
352805.3Phil$20.742009-08-24
353836Jack$36.942010-08-05
354848.6Paul$95.742010-04-23
355201Rob$90.742009-05-26
356880.9Walt$59.742010-09-16
357762.2Nathan$92.742008-05-29
358763.1Dan$71.242010-04-21
359226.4Jeff$76.542009-04-18
360960.8Bill$13.542009-11-02
361386.9Joe$81.742008-05-14
362727.6Bob$62.342009-01-08
363257.8Matt$45.942010-03-11
36487Mark$30.742010-01-20
365826Tom$50.842009-10-05
366278.6Jake$38.942008-06-25
367144.2Greg$15.142008-04-02
368284.2Adam$91.442010-07-05
36922Steve$14.142009-10-07
370441.8George$10.142010-03-12
37132.2John$48.842009-08-13
372158.8Phil$21.642008-06-02
373492.4Jack$47.342009-11-14
374194.4Paul$56.042010-11-05
375853.5Rob$38.642009-04-14
376420Walt$66.542010-07-09
377583.4Nathan$80.942010-12-30
378674Dan$9.332010-09-22
379476.8Jeff$11.542008-01-01
38044.9Bill$55.742008-04-27
381748Joe$58.942009-11-13
382268.4Bob$74.842010-07-21
383411.3Matt$24.042008-11-18
38412.8Mark$43.442010-08-29
385921.3Tom$28.842008-09-18
386337.8Jake$70.842010-10-27
387143.3Greg$29.142010-03-20
38899.8Adam$96.542010-07-06
389970.4Steve$44.242010-11-16
390981.5George$48.742009-06-21
39193.8John$23.442008-03-02
392694.2Phil$50.342010-07-16
393510.3Jack$91.442008-02-17
394799.7Paul$92.742009-07-04
395649.5Rob$84.842010-06-02
396885.6Walt$18.642009-06-28
397786.6Nathan$32.942010-05-31
398496.7Dan$42.942010-04-21
399299.9Jeff$39.942008-07-13
400218.1Bill$38.142010-01-27
401693.2Joe$47.442010-10-26
402757.2Bob$16.942009-03-29
403568.9Matt$67.942008-12-20
404620.5Mark$47.842008-09-26
405106.4Tom$12.842008-04-04
406880.1Jake$1.332008-11-05
407361.5Greg$80.042009-11-20
408133.8Adam$29.742008-01-29
409871.1Steve$59.642009-05-05
41050George$81.542010-07-20
411715.4John$50.842008-11-18
412615.3Phil$26.542009-06-01
41318.1Jack$83.442008-05-25
414335Paul$45.442009-11-30
415578.7Rob$56.042010-04-27
416670.5Walt$44.042010-05-12
417948.2Nathan$80.242009-09-23
418554.8Dan$93.642010-09-01
419590.3Jeff$80.742009-05-22
42024.8Bill$85.742008-10-19
421839.9Joe$57.242010-05-29
422129.3Bob$18.742008-01-29
423587.2Matt$20.542010-09-20
424723.7Mark$54.042008-12-27
425338.5Tom$11.942010-10-07
42681Jake$78.942008-12-28
427836.9Greg$73.842008-05-13
428392.7Adam$29.242008-02-29
429245Steve$88.342010-09-19
430693.7George$90.742010-04-06
431956.8John$74.742008-11-27
432727.5Phil$87.742009-07-02
433763Jack$46.442010-02-24
434632Paul$18.742008-09-10
435955.1Rob$52.642009-01-26
436838.7Walt$60.742008-05-27
437162.7Nathan$44.442010-09-27
438288.6Dan$83.642008-06-30
439350.1Jeff$8.132008-02-15
440218.4Bill$77.542010-12-31
441943.2Joe$73.142010-03-14
442240Bob$45.942009-10-22
443724Matt$22.242008-02-09
444413.3Mark$85.442008-09-13
445642.8Tom$80.942010-05-14
446991.3Jake$64.842009-02-13
447129.2Greg$81.042010-07-11
4484.6Adam$9.932010-01-02
449172.2Steve$44.942010-04-06
450222.3George$66.742009-07-19
451179.7John$61.042008-09-11
452884.3Phil$85.042010-02-24
453465.3Jack$57.442010-11-08
454510Paul$98.742010-05-22
455741.8Rob$63.042009-10-13
456499.2Walt$62.142008-08-31
457863.3Nathan$75.042008-01-24
458670.7Dan$75.542008-05-17
459314.2Jeff$92.742009-10-19
46038.7Bill$14.942008-09-28
461537.8Joe$32.942010-09-05
462768.2Bob$21.342010-03-15
463457.5Matt$67.942008-11-07
464368.5Mark$18.942008-10-23
465133.3Tom$93.042010-10-22
466706.9Jake$43.042009-08-10
467927.9Greg$29.342008-10-25
468959.1Adam$96.342008-01-16
46988.8Steve$27.842010-12-24
470667.2George$31.642008-04-13
471912.6John$85.442009-04-29
472768.1Phil$62.242010-01-01
473473.8Jack$8.032008-12-25
474753.4Paul$44.842009-07-31
47520.3Rob$58.142009-05-11
476917.3Walt$28.842010-09-20
477435.6Nathan$21.642008-06-24
478704.3Dan$17.542008-05-12
479728.1Jeff$26.442009-03-29
480678.9Bill$93.142010-03-30
481779.1Joe$84.342009-10-12
482208.3Bob$61.142008-07-31
483850.8Matt$8.532008-10-31
484171.8Mark$83.842010-04-03
485681.4Tom$85.942008-12-04
486121.1Jake$77.642009-11-02
487990.2Greg$21.142010-07-10
488152Adam$91.642011-01-28
489277Steve$64.442008-09-28
490679.5George$32.342008-07-10
491398John$10.242008-01-10
492970.4Phil$31.042009-12-18
493164.7Jack$16.142010-03-26
494438.5Paul$33.242009-09-20
495160.2Rob$1.432009-04-10
496463Walt$13.542008-07-24
49753.9Nathan$12.542009-03-26
498860.6Dan$27.742008-12-18
499842.2Jeff$55.442011-01-02
+ + + \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/demo_Templated.html b/includes/js/dojox/dtl/demos/demo_Templated.html new file mode 100644 index 0000000..b538811 --- /dev/null +++ b/includes/js/dojox/dtl/demos/demo_Templated.html @@ -0,0 +1,36 @@ + + + Demo using dojox.dtl._Templated + + + + +
+ + + diff --git a/includes/js/dojox/dtl/demos/demo_Tree.html b/includes/js/dojox/dtl/demos/demo_Tree.html new file mode 100644 index 0000000..692d863 --- /dev/null +++ b/includes/js/dojox/dtl/demos/demo_Tree.html @@ -0,0 +1,33 @@ + + + Demo to show recursion in DTL + + + + +
+ + + \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/json/blog/get_blog_1.json b/includes/js/dojox/dtl/demos/json/blog/get_blog_1.json new file mode 100644 index 0000000..9c7dd9f --- /dev/null +++ b/includes/js/dojox/dtl/demos/json/blog/get_blog_1.json @@ -0,0 +1 @@ +{"teaser":"I'd be able to write a lot faster.","body":"I think I wouldn't be able to think.","date":1189125242601,"author":"jim"} \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/json/blog/get_blog_3.json b/includes/js/dojox/dtl/demos/json/blog/get_blog_3.json new file mode 100644 index 0000000..7c0a937 --- /dev/null +++ b/includes/js/dojox/dtl/demos/json/blog/get_blog_3.json @@ -0,0 +1 @@ +{"teaser":"There was SO much sand","body":"I tried to walk so fast that I wouldn't leave foot prints.","date":1190245842601,"author":"jim"} \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/json/blog/get_blog_list.json b/includes/js/dojox/dtl/demos/json/blog/get_blog_list.json new file mode 100644 index 0000000..40f14a7 --- /dev/null +++ b/includes/js/dojox/dtl/demos/json/blog/get_blog_list.json @@ -0,0 +1 @@ +{"blog_list":{"3":{"title":"My Trip to the Beach"},"1":{"title":"If I Were a Robot"}}} \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/json/blog/get_page_about.json b/includes/js/dojox/dtl/demos/json/blog/get_page_about.json new file mode 100644 index 0000000..05ddb9c --- /dev/null +++ b/includes/js/dojox/dtl/demos/json/blog/get_page_about.json @@ -0,0 +1 @@ +{"title":"About Jim","body":"

Jim is an avid golfer, enjoys long walks on the beach, and eating hot pockets

When he's not scalding his mouth, you'll find him throwing rocks at pigeons.

"} \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/json/fruit.json b/includes/js/dojox/dtl/demos/json/fruit.json new file mode 100644 index 0000000..e7a0bf8 --- /dev/null +++ b/includes/js/dojox/dtl/demos/json/fruit.json @@ -0,0 +1 @@ +{ items: ["apple", "banana", "pear"] } \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/json/morefruit.json b/includes/js/dojox/dtl/demos/json/morefruit.json new file mode 100644 index 0000000..6a8beea --- /dev/null +++ b/includes/js/dojox/dtl/demos/json/morefruit.json @@ -0,0 +1 @@ +{ items: ["pineapple", "orange", "tomato"] } \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/templates/animation.html b/includes/js/dojox/dtl/demos/templates/animation.html new file mode 100644 index 0000000..56c38f3 --- /dev/null +++ b/includes/js/dojox/dtl/demos/templates/animation.html @@ -0,0 +1,5 @@ +{% load dojox.dtl.contrib.dijit dojox.dtl.contrib.html %} +
+
 
+
 
+
\ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/templates/blog_base.html b/includes/js/dojox/dtl/demos/templates/blog_base.html new file mode 100644 index 0000000..1438a6b --- /dev/null +++ b/includes/js/dojox/dtl/demos/templates/blog_base.html @@ -0,0 +1,8 @@ +
+

+ + +
\ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/templates/blog_detail.html b/includes/js/dojox/dtl/demos/templates/blog_detail.html new file mode 100644 index 0000000..2b6146d --- /dev/null +++ b/includes/js/dojox/dtl/demos/templates/blog_detail.html @@ -0,0 +1,10 @@ + + + +
+

+
posted on by
+

+

+
+ \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/templates/blog_list.html b/includes/js/dojox/dtl/demos/templates/blog_list.html new file mode 100644 index 0000000..2413605 --- /dev/null +++ b/includes/js/dojox/dtl/demos/templates/blog_list.html @@ -0,0 +1,9 @@ + + + +
    + +
  • {{ blog.title }}
  • + +
+ \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/templates/blog_page.html b/includes/js/dojox/dtl/demos/templates/blog_page.html new file mode 100644 index 0000000..aeeb762 --- /dev/null +++ b/includes/js/dojox/dtl/demos/templates/blog_page.html @@ -0,0 +1,7 @@ + + + +
+ +
+ \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/templates/countrychildren.html b/includes/js/dojox/dtl/demos/templates/countrychildren.html new file mode 100644 index 0000000..fbdbebe --- /dev/null +++ b/includes/js/dojox/dtl/demos/templates/countrychildren.html @@ -0,0 +1 @@ +
  • {{ country.type }}: {{ country.name }}{% if country.children %}
      {% for country in country.childrens %}{% include countrychildren %}{% endfor %}
    {% endif %}
  • \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/templates/gallery.html b/includes/js/dojox/dtl/demos/templates/gallery.html new file mode 100644 index 0000000..7fe6d8c --- /dev/null +++ b/includes/js/dojox/dtl/demos/templates/gallery.html @@ -0,0 +1,16 @@ +{% load dojox.dtl.contrib.data %} +{% bind_data items to store as flickr %} +
    + + + + {% for item in flickr %}{% endfor %} + + + + + +
    + {% if selected %}{% endif %} +
    +
    \ No newline at end of file diff --git a/includes/js/dojox/dtl/demos/templates/nodelist.html b/includes/js/dojox/dtl/demos/templates/nodelist.html new file mode 100644 index 0000000..ddf7def --- /dev/null +++ b/includes/js/dojox/dtl/demos/templates/nodelist.html @@ -0,0 +1,5 @@ +
    +
      + {% for item in items %}
    • {{ item }}
    • {% endfor %} +
    +
    \ No newline at end of file diff --git a/includes/js/dojox/dtl/ext-dojo/NodeList.js b/includes/js/dojox/dtl/ext-dojo/NodeList.js new file mode 100644 index 0000000..64e9a93 --- /dev/null +++ b/includes/js/dojox/dtl/ext-dojo/NodeList.js @@ -0,0 +1,33 @@ +if(!dojo._hasResource["dojox.dtl.ext-dojo.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.ext-dojo.NodeList"] = true; +dojo.provide("dojox.dtl.ext-dojo.NodeList"); +dojo.require("dojox.dtl._base"); + +dojo.extend(dojo.NodeList, { + dtl: function(template, context){ + // args: dojox.dtl.__StringArgs|String + // The template string or location + // context: dojox.dtl.__ObjectArgs|Object + // The context object or location + var d = dojox.dtl; + + var self = this; + var render = function(data){ + var content = template.render(new d._Context(context)); + self.forEach(function(node){ + node.innerHTML = content; + }); + } + + d.text._resolveTemplateArg(template).addCallback(function(templateString){ + template = new d.Template(templateString); + d.text._resolveContextArg(context).addCallback(function(contextObject){ + render(contextObject); + }); + }); + + return this; + } +}); + +} diff --git a/includes/js/dojox/dtl/filter/dates.js b/includes/js/dojox/dtl/filter/dates.js new file mode 100644 index 0000000..3ca2022 --- /dev/null +++ b/includes/js/dojox/dtl/filter/dates.js @@ -0,0 +1,54 @@ +if(!dojo._hasResource["dojox.dtl.filter.dates"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.filter.dates"] = true; +dojo.provide("dojox.dtl.filter.dates"); + +dojo.require("dojox.dtl.utils.date"); + +(function(){ + var ddfd = dojox.dtl.filter.dates; + + dojo.mixin(ddfd, { + _toDate: function(value){ + if(value instanceof Date){ + return value; + } + value = new Date(value); + if(value.getTime() == new Date(0).getTime()){ + return ""; + } + return value; + }, + date: function(value, arg){ + // summary: Formats a date according to the given format + value = ddfd._toDate(value); + if(!value) return ""; + arg = arg || "N j, Y"; + return dojox.dtl.utils.date.format(value, arg); + }, + time: function(value, arg){ + // summary: Formats a time according to the given format + value = ddfd._toDate(value); + if(!value) return ""; + arg = arg || "P"; + return dojox.dtl.utils.date.format(value, arg); + }, + timesince: function(value, arg){ + // summary: Formats a date as the time since that date (i.e. "4 days, 6 hours") + value = ddfd._toDate(value); + if(!value) return ""; + var timesince = dojox.dtl.utils.date.timesince; + if(arg) return timesince(arg, value); + return timesince(value); + }, + timeuntil: function(value, arg){ + // summary: Formats a date as the time until that date (i.e. "4 days, 6 hours") + value = ddfd._toDate(value); + if(!value) return ""; + var timesince = dojox.dtl.utils.date.timesince; + if(arg) return timesince(arg, value); + return timesince(new Date(), value); + } + }); +})(); + +} diff --git a/includes/js/dojox/dtl/filter/htmlstrings.js b/includes/js/dojox/dtl/filter/htmlstrings.js new file mode 100644 index 0000000..d4feb93 --- /dev/null +++ b/includes/js/dojox/dtl/filter/htmlstrings.js @@ -0,0 +1,59 @@ +if(!dojo._hasResource["dojox.dtl.filter.htmlstrings"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.filter.htmlstrings"] = true; +dojo.provide("dojox.dtl.filter.htmlstrings"); + +dojo.require("dojox.dtl._base"); + +dojo.mixin(dojox.dtl.filter.htmlstrings, { + _escapeamp: /&/g, + _escapelt: //g, + _escapeqt: /'/g, + _escapedblqt: /"/g, + _linebreaksrn: /(\r\n|\n\r)/g, + _linebreaksn: /\n{2,}/g, + _linebreakss: /(^\s+|\s+$)/g, + _linebreaksbr: /\n/g, + _removetagsfind: /[a-z0-9]+/g, + _striptags: /<[^>]*?>/g, + escape: function(value){ + // summary: Escapes a string's HTML + var dh = dojox.dtl.filter.htmlstrings; + return value.replace(dh._escapeamp, '&').replace(dh._escapelt, '<').replace(dh._escapegt, '>').replace(dh._escapedblqt, '"').replace(dh._escapeqt, '''); + }, + linebreaks: function(value){ + // summary: Converts newlines into

    and
    s + var output = []; + var dh = dojox.dtl.filter.htmlstrings; + value = value.replace(dh._linebreaksrn, "\n"); + var parts = value.split(dh._linebreaksn); + for(var i = 0; i < parts.length; i++){ + var part = parts[i].replace(dh._linebreakss, "").replace(dh._linebreaksbr, "
    ") + output.push("

    " + part + "

    "); + } + + return output.join("\n\n"); + }, + linebreaksbr: function(value){ + // summary: Converts newlines into
    s + var dh = dojox.dtl.filter.htmlstrings; + return value.replace(dh._linebreaksrn, "\n").replace(dh._linebreaksbr, "
    "); + }, + removetags: function(value, arg){ + // summary: Removes a space separated list of [X]HTML tags from the output" + var dh = dojox.dtl.filter.htmlstrings; + var tags = []; + var group; + while(group = dh._removetagsfind.exec(arg)){ + tags.push(group[0]); + } + tags = "(" + tags.join("|") + ")"; + return value.replace(new RegExp("]*>", "gi"), ""); + }, + striptags: function(value){ + // summary: Strips all [X]HTML tags + return value.replace(dojox.dtl.filter.htmlstrings._striptags, ""); + } +}); + +} diff --git a/includes/js/dojox/dtl/filter/integers.js b/includes/js/dojox/dtl/filter/integers.js new file mode 100644 index 0000000..0c54a90 --- /dev/null +++ b/includes/js/dojox/dtl/filter/integers.js @@ -0,0 +1,32 @@ +if(!dojo._hasResource["dojox.dtl.filter.integers"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.filter.integers"] = true; +dojo.provide("dojox.dtl.filter.integers"); + +dojo.mixin(dojox.dtl.filter.integers, { + add: function(value, arg){ + value = parseInt(value); + arg = parseInt(arg); + return isNaN(arg) ? value : value + arg; + }, + get_digit: function(value, arg){ + // summary: + // Given a whole number, returns the 1-based requested digit of it + // desciprtion: + // 1 is the right-most digit, 2 is the second-right-most digit, etc. Returns the + // original value for invalid input (if input or argument is not an integer, + // or if argument is less than 1). Otherwise, output is always an integer. + value = parseInt(value); + arg = parseInt(arg) - 1; + if(arg >= 0){ + value += ""; + if(arg < value.length){ + value = parseInt(value.charAt(arg)); + }else{ + value = 0; + } + } + return (isNaN(value) ? 0 : value); + } +}); + +} diff --git a/includes/js/dojox/dtl/filter/lists.js b/includes/js/dojox/dtl/filter/lists.js new file mode 100644 index 0000000..b095242 --- /dev/null +++ b/includes/js/dojox/dtl/filter/lists.js @@ -0,0 +1,137 @@ +if(!dojo._hasResource["dojox.dtl.filter.lists"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.filter.lists"] = true; +dojo.provide("dojox.dtl.filter.lists") + +dojo.require("dojox.dtl._base"); + +dojo.mixin(dojox.dtl.filter.lists, { + _dictsort: function(a, b){ + if(a[0] == b[0]) return 0; + return (a[0] < b[0]) ? -1 : 1; + }, + dictsort: function(value, arg){ + // summary: Takes a list of dicts, returns that list sorted by the property given in the argument. + if(!arg) return value; + + var i, item, items = []; + if(!dojo.isArray(value)){ + var obj = value, value = []; + for(var key in obj){ + value.push(obj[k]); + } + } + for(i = 0; i < value.length; i++){ + items.push([new dojox.dtl._Filter('var.' + arg).resolve(new dojox.dtl._Context({ 'var' : value[i]})), value[i]]); + } + items.sort(dojox.dtl.filter.lists._dictsort); + var output = []; + for(i = 0; item = items[i]; i++){ + output.push(item[1]); + } + return output; + }, + dictsortreversed: function(value, arg){ + // summary: Takes a list of dicts, returns that list sorted in reverse order by the property given in the argument. + if(!arg) return value; + + var dictsort = dojox.dtl.filter.lists.dictsort(value, arg); + return dictsort.reverse(); + }, + first: function(value){ + // summary: Returns the first item in a list + return (value.length) ? value[0] : ""; + }, + join: function(value, arg){ + // summary: Joins a list with a string, like Python's ``str.join(list)`` + // description: + // Django throws a compile error, but JS can't do arg checks + // so we're left with run time errors, which aren't wise for something + // as trivial here as an empty arg. + return value.join(arg || ","); + }, + length: function(value){ + // summary: Returns the length of the value - useful for lists + return (isNaN(value.length)) ? (value + "").length : value.length; + }, + length_is: function(value, arg){ + // summary: Returns a boolean of whether the value's length is the argument + return value.length == parseInt(arg); + }, + random: function(value){ + // summary: Returns a random item from the list + return value[Math.floor(Math.random() * value.length)]; + }, + slice: function(value, arg){ + // summary: Returns a slice of the list. + // description: + // Uses the same syntax as Python's list slicing; see + // http://diveintopython.org/native_data_types/lists.html#odbchelper.list.slice + // for an introduction. + // Also uses the optional third value to denote every X item. + arg = arg || ""; + var parts = arg.split(":"); + var bits = []; + for(var i = 0; i < parts.length; i++){ + if(!parts[i].length){ + bits.push(null); + }else{ + bits.push(parseInt(parts[i])); + } + } + + if(bits[0] === null){ + bits[0] = 0; + } + if(bits[0] < 0){ + bits[0] = value.length + bits[0]; + } + if(bits.length < 2 || bits[1] === null){ + bits[1] = value.length; + } + if(bits[1] < 0){ + bits[1] = value.length + bits[1]; + } + + return value.slice(bits[0], bits[1]); + }, + _unordered_list: function(value, tabs){ + var ddl = dojox.dtl.filter.lists; + var i, indent = ""; + for(i = 0; i < tabs; i++){ + indent += "\t"; + } + if(value[1] && value[1].length){ + var recurse = []; + for(i = 0; i < value[1].length; i++){ + recurse.push(ddl._unordered_list(value[1][i], tabs + 1)) + } + return indent + "
  • " + value[0] + "\n" + indent + "
      \n" + recurse.join("\n") + "\n" + indent + "
    \n" + indent + "
  • "; + }else{ + return indent + "
  • " + value[0] + "
  • "; + } + }, + unordered_list: function(value){ + // summary: + // Recursively takes a self-nested list and returns an HTML unordered list -- + // WITHOUT opening and closing
      tags. + // description: + // The list is assumed to be in the proper format. For example, if ``var`` contains + // ``['States', [['Kansas', [['Lawrence', []], ['Topeka', []]]], ['Illinois', []]]]``, + // then ``{{ var|unordered_list }}`` would return:: + // + // |
    • States + // |
        + // |
      • Kansas + // |
          + // |
        • Lawrence
        • + // |
        • Topeka
        • + // |
        + // |
      • + // |
      • Illinois
      • + // |
      + // |
    • + return dojox.dtl.filter.lists._unordered_list(value, 1); + } +}); + +} diff --git a/includes/js/dojox/dtl/filter/logic.js b/includes/js/dojox/dtl/filter/logic.js new file mode 100644 index 0000000..b69a1a8 --- /dev/null +++ b/includes/js/dojox/dtl/filter/logic.js @@ -0,0 +1,34 @@ +if(!dojo._hasResource["dojox.dtl.filter.logic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.filter.logic"] = true; +dojo.provide("dojox.dtl.filter.logic"); + +dojo.mixin(dojox.dtl.filter.logic, { + default_: function(value, arg){ + // summary: If value is unavailable, use given default + return value || arg || ""; + }, + default_if_none: function(value, arg){ + // summary: If value is null, use given default + return (value === null) ? arg || "" : value || ""; + }, + divisibleby: function(value, arg){ + // summary: Returns true if the value is devisible by the argument" + return (parseInt(value) % parseInt(arg)) == 0; + }, + _yesno: /\s*,\s*/g, + yesno: function(value, arg){ + // summary: + // arg being a comma-delimited string, value of true/false/none + // chooses the appropriate item from the string + if(!arg) arg = 'yes,no,maybe'; + var parts = arg.split(dojox.dtl.filter.logic._yesno); + if(parts.length < 2){ + return value; + } + if(value) return parts[0]; + if((!value && value !== null) || parts.length < 3) return parts[1]; + return parts[2]; + } +}); + +} diff --git a/includes/js/dojox/dtl/filter/misc.js b/includes/js/dojox/dtl/filter/misc.js new file mode 100644 index 0000000..0704d25 --- /dev/null +++ b/includes/js/dojox/dtl/filter/misc.js @@ -0,0 +1,59 @@ +if(!dojo._hasResource["dojox.dtl.filter.misc"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.filter.misc"] = true; +dojo.provide("dojox.dtl.filter.misc"); + +dojo.mixin(dojox.dtl.filter.misc, { + filesizeformat: function(value){ + // summary: Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102bytes, etc). + value = parseFloat(value); + if(value < 1024){ + return (value == 1) ? value + " byte" : value + " bytes"; + }else if(value < 1024 * 1024){ + return (value / 1024).toFixed(1) + " KB"; + }else if(value < 1024 * 1024 * 1024){ + return (value / 1024 / 1024).toFixed(1) + " MB"; + } + return (value / 1024 / 1024 / 1024).toFixed(1) + " GB"; + }, + pluralize: function(value, arg){ + // summary: + // Returns a plural suffix if the value is not 1, for '1 vote' vs. '2 votes' + // description: + // By default, 's' is used as a suffix; if an argument is provided, that string + // is used instead. If the provided argument contains a comma, the text before + // the comma is used for the singular case. + arg = arg || 's'; + if(arg.indexOf(",") == -1){ + arg = "," + arg; + } + var parts = arg.split(","); + if(parts.length > 2){ + return ""; + } + var singular = parts[0]; + var plural = parts[1]; + + if(parseInt(value) != 1){ + return plural; + } + return singular; + }, + _phone2numeric: { a: 2, b: 2, c: 2, d: 3, e: 3, f: 3, g: 4, h: 4, i: 4, j: 5, k: 5, l: 5, m: 6, n: 6, o: 6, p: 7, r: 7, s: 7, t: 8, u: 8, v: 8, w: 9, x: 9, y: 9 }, + phone2numeric: function(value){ + // summary: Takes a phone number and converts it in to its numerical equivalent + var dm = dojox.dtl.filter.misc; + value = value + ""; + var output = ""; + for(var i = 0; i < value.length; i++){ + var chr = value.charAt(i).toLowerCase(); + (dm._phone2numeric[chr]) ? output += dm._phone2numeric[chr] : output += value.charAt(i); + } + return output; + }, + pprint: function(value){ + // summary: A wrapper around toJson unless something better comes along + return dojo.toJson(value); + } +}); + +} diff --git a/includes/js/dojox/dtl/filter/strings.js b/includes/js/dojox/dtl/filter/strings.js new file mode 100644 index 0000000..1270574 --- /dev/null +++ b/includes/js/dojox/dtl/filter/strings.js @@ -0,0 +1,327 @@ +if(!dojo._hasResource["dojox.dtl.filter.strings"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.filter.strings"] = true; +dojo.provide("dojox.dtl.filter.strings"); + +dojo.require("dojox.dtl.filter.htmlstrings"); +dojo.require("dojox.string.sprintf"); +dojo.require("dojox.string.tokenize"); + +dojo.mixin(dojox.dtl.filter.strings, { + _urlquote: function(/*String*/ url, /*String?*/ safe){ + if(!safe){ + safe = "/"; + } + return dojox.string.tokenize(url, /([^\w-_.])/g, function(token){ + if(safe.indexOf(token) == -1){ + if(token == " "){ + return "+"; + }else{ + return "%" + token.charCodeAt(0).toString(16).toUpperCase(); + } + } + return token; + }).join(""); + }, + addslashes: function(value){ + // summary: Adds slashes - useful for passing strings to JavaScript, for example. + return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/'/g, "\\'"); + }, + capfirst: function(value){ + // summary: Capitalizes the first character of the value + value = "" + value; + return value.charAt(0).toUpperCase() + value.substring(1); + }, + center: function(value, arg){ + // summary: Centers the value in a field of a given width + arg = arg || value.length; + value = value + ""; + var diff = arg - value.length; + if(diff % 2){ + value = value + " "; + diff -= 1; + } + for(var i = 0; i < diff; i += 2){ + value = " " + value + " "; + } + return value; + }, + cut: function(value, arg){ + // summary: Removes all values of arg from the given string + arg = arg + "" || ""; + value = value + ""; + return value.replace(new RegExp(arg, "g"), ""); + }, + _fix_ampersands: /&(?!(\w+|#\d+);)/g, + fix_ampersands: function(value){ + // summary: Replaces ampersands with ``&`` entities + return value.replace(dojox.dtl.filter.strings._fix_ampersands, "&"); + }, + floatformat: function(value, arg){ + // summary: Format a number according to arg + // description: + // If called without an argument, displays a floating point + // number as 34.2 -- but only if there's a point to be displayed. + // With a positive numeric argument, it displays that many decimal places + // always. + // With a negative numeric argument, it will display that many decimal + // places -- but only if there's places to be displayed. + arg = parseInt(arg || -1); + value = parseFloat(value); + var m = value - value.toFixed(0); + if(!m && arg < 0){ + return value.toFixed(); + } + value = value.toFixed(Math.abs(arg)); + return (arg < 0) ? parseFloat(value) + "" : value; + }, + iriencode: function(value){ + return dojox.dtl.filter.strings._urlquote(value, "/#%[]=:;$&()+,!"); + }, + linenumbers: function(value){ + // summary: Displays text with line numbers + var df = dojox.dtl.filter; + var lines = value.split("\n"); + var output = []; + var width = (lines.length + "").length; + for(var i = 0, line; i < lines.length; i++){ + line = lines[i]; + output.push(df.strings.ljust(i + 1, width) + ". " + df.htmlstrings.escape(line)); + } + return output.join("\n"); + }, + ljust: function(value, arg){ + value = value + ""; + arg = parseInt(arg); + while(value.length < arg){ + value = value + " "; + } + return value; + }, + lower: function(value){ + // summary: Converts a string into all lowercase + return (value + "").toLowerCase(); + }, + make_list: function(value){ + // summary: + // Returns the value turned into a list. For an integer, it's a list of + // digits. For a string, it's a list of characters. + var output = []; + if(typeof value == "number"){ + value = value + ""; + } + if(value.charAt){ + for(var i = 0; i < value.length; i++){ + output.push(value.charAt(i)); + } + return output; + } + if(typeof value == "object"){ + for(var key in value){ + output.push(value[key]); + } + return output; + } + return []; + }, + rjust: function(value, arg){ + value = value + ""; + arg = parseInt(arg); + while(value.length < arg){ + value = " " + value; + } + return value; + }, + slugify: function(value){ + // summary: Converts to lowercase, removes + // non-alpha chars and converts spaces to hyphens + value = value.replace(/[^\w\s-]/g, "").toLowerCase(); + return value.replace(/[\-\s]+/g, "-"); + }, + _strings: {}, + stringformat: function(value, arg){ + // summary: + // Formats the variable according to the argument, a string formatting specifier. + // This specifier uses Python string formating syntax, with the exception that + // the leading "%" is dropped. + arg = "" + arg; + var strings = dojox.dtl.filter.strings._strings; + if(!strings[arg]){ + strings[arg] = new dojox.string.sprintf.Formatter("%" + arg); + } + return strings[arg].format(value); + }, + title: function(value){ + // summary: Converts a string into titlecase + var last, title = ""; + for(var i = 0, current; i < value.length; i++){ + current = value.charAt(i); + if(last == " " || last == "\n" || last == "\t" || !last){ + title += current.toUpperCase(); + }else{ + title += current.toLowerCase(); + } + last = current; + } + return title; + }, + _truncatewords: /[ \n\r\t]/, + truncatewords: function(value, arg){ + // summary: Truncates a string after a certain number of words + // arg: Integer + // Number of words to truncate after + arg = parseInt(arg); + if(!arg){ + return value; + } + + for(var i = 0, j = value.length, count = 0, current, last; i < value.length; i++){ + current = value.charAt(i); + if(dojox.dtl.filter.strings._truncatewords.test(last)){ + if(!dojox.dtl.filter.strings._truncatewords.test(current)){ + ++count; + if(count == arg){ + return value.substring(0, j + 1); + } + } + }else if(!dojox.dtl.filter.strings._truncatewords.test(current)){ + j = i; + } + last = current; + } + return value; + }, + _truncate_words: /(&.*?;|<.*?>|(\w[\w\-]*))/g, + _truncate_tag: /<(\/)?([^ ]+?)(?: (\/)| .*?)?>/, + _truncate_singlets: { br: true, col: true, link: true, base: true, img: true, param: true, area: true, hr: true, input: true }, + truncatewords_html: function(value, arg){ + arg = parseInt(arg); + + if(arg <= 0){ + return ""; + } + + var strings = dojox.dtl.filter.strings; + var words = 0; + var open = []; + + var output = dojox.string.tokenize(value, strings._truncate_words, function(all, word){ + if(word){ + // It's an actual non-HTML word + ++words; + if(words < arg){ + return word; + }else if(words == arg){ + return word + " ..."; + } + } + // Check for tag + var tag = all.match(strings._truncate_tag); + if(!tag || words >= arg){ + // Don't worry about non tags or tags after our truncate point + return; + } + var closing = tag[1]; + var tagname = tag[2].toLowerCase(); + var selfclosing = tag[3]; + if(closing || strings._truncate_singlets[tagname]){ + }else if(closing){ + var i = dojo.indexOf(open, tagname); + if(i != -1){ + open = open.slice(i + 1); + } + }else{ + open.unshift(tagname); + } + return all; + }).join(""); + + output = output.replace(/\s+$/g, ""); + + for(var i = 0, tag; tag = open[i]; i++){ + output += ""; + } + + return output; + }, + upper: function(value){ + return value.toUpperCase(); + }, + urlencode: function(value){ + return dojox.dtl.filter.strings._urlquote(value); + }, + _urlize: /^((?:[(>]|<)*)(.*?)((?:[.,)>\n]|>)*)$/, + _urlize2: /^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$/, + urlize: function(value){ + return dojox.dtl.filter.strings.urlizetrunc(value); + }, + urlizetrunc: function(value, arg){ + arg = parseInt(arg); + return dojox.string.tokenize(value, /(\S+)/g, function(word){ + var matches = dojox.dtl.filter.strings._urlize.exec(word); + if(!matches){ + return word; + } + var lead = matches[1]; + var middle = matches[2]; + var trail = matches[3]; + + var startsWww = middle.indexOf("www.") == 0; + var hasAt = middle.indexOf("@") != -1; + var hasColon = middle.indexOf(":") != -1; + var startsHttp = middle.indexOf("http://") == 0; + var startsHttps = middle.indexOf("https://") == 0; + var firstAlpha = /[a-zA-Z0-9]/.test(middle.charAt(0)); + var last4 = middle.substring(middle.length - 4); + + var trimmed = middle; + if(arg > 3){ + trimmed = trimmed.substring(0, arg - 3) + "..."; + } + + if(startsWww || (!hasAt && !startsHttp && middle.length && firstAlpha && (last4 == ".org" || last4 == ".net" || last4 == ".com"))){ + return '' + trimmed + ''; + }else if(startsHttp || startsHttps){ + return '' + trimmed + ''; + }else if(hasAt && !startsWww && !hasColon && dojox.dtl.filter.strings._urlize2.test(middle)){ + return '' + middle + ''; + } + return word; + }).join(""); + }, + wordcount: function(value){ + return dojox.dtl.text.pySplit(value).length; + }, + wordwrap: function(value, arg){ + arg = parseInt(arg); + // summary: Wraps words at specified line length + var output = []; + var parts = value.split(/ /g); + if(parts.length){ + var word = parts.shift(); + output.push(word); + var pos = word.length - word.lastIndexOf("\n") - 1; + for(var i = 0; i < parts.length; i++){ + word = parts[i]; + if(word.indexOf("\n") != -1){ + var lines = word.split(/\n/g); + }else{ + var lines = [word]; + } + pos += lines[0].length + 1; + if(arg && pos > arg){ + output.push("\n"); + pos = lines[lines.length - 1].length; + }else{ + output.push(" "); + if(lines.length > 1){ + pos = lines[lines.length - 1].length; + } + } + output.push(word); + } + } + return output.join(""); + } +}); + +} diff --git a/includes/js/dojox/dtl/html.js b/includes/js/dojox/dtl/html.js new file mode 100644 index 0000000..c984157 --- /dev/null +++ b/includes/js/dojox/dtl/html.js @@ -0,0 +1,818 @@ +if(!dojo._hasResource["dojox.dtl.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.html"] = true; +dojo.provide("dojox.dtl.html"); + +dojo.require("dojox.dtl._base"); +dojo.require("dojox.dtl.Context"); + +(function(){ + var dd = dojox.dtl; + + var ddt = dd.text; + var ddh = dd.html = { + types: dojo.mixin({change: -11, attr: -12, custom: -13, elem: 1, text: 3}, ddt.types), + _attributes: {}, + _re4: /^function anonymous\(\)\s*{\s*(.*)\s*}$/, + getTemplate: function(text){ + if(typeof this._commentable == "undefined"){ + // Check to see if the browser can handle comments + this._commentable = false; + var div = document.createElement("div"); + div.innerHTML = ""; + if(div.childNodes.length && div.childNodes[0].nodeType == 8 && div.childNodes[0].data == "comment"){ + this._commentable = true; + } + } + + if(!this._commentable){ + // Strip comments + text = text.replace(//g, "$1"); + } + + var match; + var pairs = [ + [true, "select", "option"], + [dojo.isSafari, "tr", "th"], + [dojo.isSafari, "tr", "td"], + [dojo.isSafari, "thead", "tr", "th"], + [dojo.isSafari, "tbody", "tr", "td"] + ]; + // Some tags can't contain text. So we wrap the text in tags that they can have. + for(var i = 0, pair; pair = pairs[i]; i++){ + if(!pair[0]){ + continue; + } + if(text.indexOf("<" + pair[1]) != -1){ + var selectRe = new RegExp("<" + pair[1] + "[\\s\\S]*?>([\\s\\S]+?)", "ig"); + while(match = selectRe.exec(text)){ + // Do it like this to make sure we don't double-wrap + var found = false; + var tokens = dojox.string.tokenize(match[1], new RegExp("(<" + pair[2] + "[\\s\\S]*?>[\\s\\S]*?)", "ig"), function(child){ found = true; return {data: child}; }); + if(found){ + var replace = []; + for(var j = 0; j < tokens.length; j++) { + if(dojo.isObject(tokens[j])){ + replace.push(tokens[j].data); + }else{ + var close = pair[pair.length - 1]; + var k, replacement = ""; + for(k = 2; k < pair.length - 1; k++){ + replacement += "<" + pair[k] + ">"; + } + replacement += "<" + close + ' iscomment="true">' + dojo.trim(tokens[j]) + ""; + for(k = 2; k < pair.length - 1; k++){ + replacement += ""; + } + replace.push(replacement); + } + } + text = text.replace(match[1], replace.join("")); + } + } + } + } + + var re = /\b([a-zA-Z]+)=['"]/g; + while(match = re.exec(text)){ + this._attributes[match[1].toLowerCase()] = true; + } + var div = document.createElement("div"); + div.innerHTML = text; + var output = {nodes: []}; + while(div.childNodes.length){ + output.nodes.push(div.removeChild(div.childNodes[0])) + } + + return output; + }, + tokenize: function(/*Node*/ nodes){ + var tokens = []; + + for(var i = 0, node; node = nodes[i++];){ + if(node.nodeType != 1){ + this.__tokenize(node, tokens); + }else{ + this._tokenize(node, tokens); + } + } + + return tokens; + }, + _swallowed: [], + _tokenize: function(/*Node*/ node, /*Array*/ tokens){ + var types = this.types; + var first = false; + var swallowed = this._swallowed; + var i, j, tag, child; + + if(!tokens.first){ + // Try to efficiently associate tags that use an attribute to + // remove the node from DOM (eg dojoType) so that we can efficiently + // locate them later in the tokenizing. + first = tokens.first = true; + var tags = dd.register.getAttributeTags(); + for(i = 0; tag = tags[i]; i++){ + try{ + (tag[2])({ swallowNode: function(){ throw 1; }}, ""); + }catch(e){ + swallowed.push(tag); + } + } + } + + + for(i = 0; tag = swallowed[i]; i++){ + var text = node.getAttribute(tag[0]); + if(text){ + var swallowed = false; + var custom = (tag[2])({ swallowNode: function(){ swallowed = true; return node; }}, text); + if(swallowed){ + if(node.parentNode && node.parentNode.removeChild){ + node.parentNode.removeChild(node); + } + tokens.push([types.custom, custom]); + return; + } + } + } + + var children = []; + if(dojo.isIE && node.tagName == "SCRIPT"){ + children.push({ + nodeType: 3, + data: node.text + }); + node.text = ""; + }else{ + for(i = 0; child = node.childNodes[i]; i++){ + children.push(child); + } + } + + tokens.push([types.elem, node]); + + var change = false; + if(children.length){ + // Only do a change request if we need to + tokens.push([types.change, node]); + change = true; + } + + for(var key in this._attributes){ + var value = ""; + if(key == "class"){ + value = node.className || value; + }else if(key == "for"){ + value = node.htmlFor || value; + }else if(key == "value" && node.value == node.innerHTML){ + // Sometimes .value is set the same as the contents of the item (button) + continue; + }else if(node.getAttribute){ + value = node.getAttribute(key, 2) || value; + if(key == "href" || key == "src"){ + if(dojo.isIE){ + var hash = location.href.lastIndexOf(location.hash); + var href = location.href.substring(0, hash).split("/"); + href.pop(); + href = href.join("/") + "/"; + if(value.indexOf(href) == 0){ + value = value.replace(href, ""); + } + value = decodeURIComponent(value); + } + if(value.indexOf("{%") != -1 || value.indexOf("{{") != -1){ + node.setAttribute(key, ""); + } + } + } + if(typeof value == "function"){ + value = value.toString().replace(this._re4, "$1"); + } + + if(!change){ + // Only do a change request if we need to + tokens.push([types.change, node]); + change = true; + } + // We'll have to resolve attributes during parsing + tokens.push([types.attr, node, key, value]); + } + + for(i = 0, child; child = children[i]; i++){ + if(child.nodeType == 1 && child.getAttribute("iscomment")){ + child.parentNode.removeChild(child); + child = { + nodeType: 8, + data: child.innerHTML + }; + } + this.__tokenize(child, tokens); + } + + if(!first && node.parentNode && node.parentNode.tagName){ + if(change){ + tokens.push([types.change, node, true]); + } + tokens.push([types.change, node.parentNode]); + node.parentNode.removeChild(node); + }else{ + // If this node is parentless, it's a base node, so we have to "up" change to itself + // and note that it's a top-level to watch for errors + tokens.push([types.change, node, true, true]); + } + }, + __tokenize: function(child, tokens){ + var types = this.types; + var data = child.data; + switch(child.nodeType){ + case 1: + this._tokenize(child, tokens); + return; + case 3: + if(data.match(/[^\s\n]/) && (data.indexOf("{{") != -1 || data.indexOf("{%") != -1)){ + var texts = ddt.tokenize(data); + for(var j = 0, text; text = texts[j]; j++){ + if(typeof text == "string"){ + tokens.push([types.text, text]); + }else{ + tokens.push(text); + } + } + }else{ + tokens.push([child.nodeType, child]); + } + if(child.parentNode) child.parentNode.removeChild(child); + return; + case 8: + if(data.indexOf("{%") == 0){ + var text = dojo.trim(data.slice(2, -2)); + if(text.substr(0, 5) == "load "){ + var parts = dd.text.pySplit(dojo.trim(text)); + for(var i = 1, part; part = parts[i]; i++){ + dojo["require"](part); + } + } + tokens.push([types.tag, text]); + } + if(data.indexOf("{{") == 0){ + tokens.push([types.varr, dojo.trim(data.slice(2, -2))]); + } + if(child.parentNode) child.parentNode.removeChild(child); + return; + } + } + }; + + dd.HtmlTemplate = dojo.extend(function(/*String|DOMNode|dojo._Url*/ obj){ + // summary: Use this object for HTML templating + if(!obj.nodes){ + var node = dojo.byId(obj); + if(node){ + dojo.forEach(["class", "src", "href", "name", "value"], function(item){ + ddh._attributes[item] = true; + }); + obj = { + nodes: [node] + }; + }else{ + if(typeof obj == "object"){ + obj = ddt.getTemplateString(obj); + } + obj = ddh.getTemplate(obj); + } + } + + var tokens = ddh.tokenize(obj.nodes); + if(dd.tests){ + this.tokens = tokens.slice(0); + } + + var parser = new dd._HtmlParser(tokens); + this.nodelist = parser.parse(); + }, + { + _count: 0, + _re: /\bdojo:([a-zA-Z0-9_]+)\b/g, + setClass: function(str){ + this.getRootNode().className = str; + }, + getRootNode: function(){ + return this.rootNode; + }, + getBuffer: function(){ + return new dd.HtmlBuffer(); + }, + render: function(context, buffer){ + buffer = buffer || this.getBuffer(); + this.rootNode = null; + var output = this.nodelist.render(context || new dd.Context({}), buffer); + this.rootNode = buffer.getRootNode(); + for(var i = 0, node; node = buffer._cache[i]; i++){ + if(node._cache){ + node._cache.length = 0; + } + } + return output; + }, + unrender: function(context, buffer){ + return this.nodelist.unrender(context, buffer); + } + }); + + dd.HtmlBuffer = dojo.extend(function(/*Node*/ parent){ + // summary: Allows the manipulation of DOM + // description: + // Use this to append a child, change the parent, or + // change the attribute of the current node. + this._parent = parent; + this._cache = []; + }, + { + concat: function(/*DOMNode*/ node){ + var parent = this._parent; + if(node.parentNode && node.parentNode.tagName && parent && !parent._dirty){ + return this; + } + + if(node.nodeType == 1 && !this.rootNode){ + this.rootNode = node || true; + } + + if(!parent){ + if(node.nodeType == 3 && dojo.trim(node.data)){ + throw new Error("Text should not exist outside of the root node in template"); + } + return this; + } + if(this._closed && (node.nodeType != 3 || dojo.trim(node.data))){ + throw new Error("Content should not exist outside of the root node in template"); + } + if(parent._dirty){ + if(node._drawn && node.parentNode == parent){ + var caches = parent._cache; + if(caches){ + for(var i = 0, cache; cache = caches[i]; i++){ + this.onAddNode(cache); + parent.insertBefore(cache, node); + this.onAddNodeComplete(cache); + } + caches.length = 0; + } + } + parent._dirty = false; + } + if(!parent._cache){ + parent._cache = []; + this._cache.push(parent); + } + parent._dirty = true; + parent._cache.push(node); + return this; + }, + remove: function(obj){ + if(typeof obj == "string"){ + if(this._parent){ + this._parent.removeAttribute(obj); + } + }else{ + if(obj.nodeType == 1 && !this.getRootNode() && !this._removed){ + this._removed = true; + return this; + } + if(obj.parentNode){ + this.onRemoveNode(); + if(obj.parentNode){ + obj.parentNode.removeChild(obj); + } + } + } + return this; + }, + setAttribute: function(key, value){ + if(key == "class"){ + this._parent.className = value; + }else if(key == "for"){ + this._parent.htmlFor = value; + }else if(this._parent.setAttribute){ + this._parent.setAttribute(key, value); + } + return this; + }, + addEvent: function(context, type, fn, /*Array|Function*/ args){ + if(!context.getThis()){ throw new Error("You must use Context.setObject(instance)"); } + this.onAddEvent(this.getParent(), type, fn); + var resolved = fn; + if(dojo.isArray(args)){ + resolved = function(e){ + this[fn].apply(this, [e].concat(args)); + } + } + return dojo.connect(this.getParent(), type, context.getThis(), resolved); + }, + setParent: function(node, /*Boolean?*/ up, /*Boolean?*/ root){ + if(!this._parent) this._parent = this._first = node; + + if(up && root && node === this._first){ + this._closed = true; + } + + if(up){ + var parent = this._parent; + var script = ""; + var ie = dojo.isIE && parent.tagName == "SCRIPT"; + if(ie){ + parent.text = ""; + } + if(parent._dirty){ + var caches = parent._cache; + for(var i = 0, cache; cache = caches[i]; i++){ + if(cache !== parent){ + this.onAddNode(cache); + if(ie){ + script += cache.data; + }else{ + parent.appendChild(cache); + } + this.onAddNodeComplete(cache); + } + } + caches.length = 0; + parent._dirty = false; + } + if(ie){ + parent.text = script; + } + } + + this.onSetParent(node, up); + this._parent = node; + return this; + }, + getParent: function(){ + return this._parent; + }, + getRootNode: function(){ + return this.rootNode; + }, + onSetParent: function(node, up){ + // summary: Stub called when setParent is used. + }, + onAddNode: function(node){ + // summary: Stub called before new nodes are added + }, + onAddNodeComplete: function(node){ + // summary: Stub called after new nodes are added + }, + onRemoveNode: function(node){ + // summary: Stub called when nodes are removed + }, + onClone: function(/*DOMNode*/ from, /*DOMNode*/ to){ + // summary: Stub called when a node is duplicated + }, + onAddEvent: function(/*DOMNode*/ node, /*String*/ type, /*String*/ description){ + // summary: Stub to call when you're adding an event + } + }); + + dd._HtmlNode = dojo.extend(function(node){ + // summary: Places a node into DOM + this.contents = node; + }, + { + render: function(context, buffer){ + this._rendered = true; + return buffer.concat(this.contents); + }, + unrender: function(context, buffer){ + if(!this._rendered){ + return buffer; + } + this._rendered = false; + return buffer.remove(this.contents); + }, + clone: function(buffer){ + return new this.constructor(this.contents); + } + }); + + dd._HtmlNodeList = dojo.extend(function(/*Node[]*/ nodes){ + // summary: A list of any HTML-specific node object + // description: + // Any object that's used in the constructor or added + // through the push function much implement the + // render, unrender, and clone functions. + this.contents = nodes || []; + }, + { + push: function(node){ + this.contents.push(node); + }, + unshift: function(node){ + this.contents.unshift(node); + }, + render: function(context, buffer, /*Node*/ instance){ + buffer = buffer || dd.HtmlTemplate.prototype.getBuffer(); + + if(instance){ + var parent = buffer.getParent(); + } + for(var i = 0; i < this.contents.length; i++){ + buffer = this.contents[i].render(context, buffer); + if(!buffer) throw new Error("Template node render functions must return their buffer"); + } + if(parent){ + buffer.setParent(parent); + } + return buffer; + }, + dummyRender: function(context, buffer, asNode){ + // summary: A really expensive way of checking to see how a rendering will look. + // Used in the ifchanged tag + var div = document.createElement("div"); + + var parent = buffer.getParent(); + var old = parent._clone; + // Tell the clone system to attach itself to our new div + parent._clone = div; + var nodelist = this.clone(buffer, div); + if(old){ + // Restore state if there was a previous clone + parent._clone = old; + }else{ + // Remove if there was no clone + parent._clone = null; + } + + buffer = dd.HtmlTemplate.prototype.getBuffer(); + nodelist.unshift(new dd.ChangeNode(div)); + nodelist.push(new dd.ChangeNode(div, true)); + nodelist.render(context, buffer); + + if(asNode){ + return buffer.getRootNode(); + } + + var html = div.innerHTML; + return (dojo.isIE) ? html.replace(/\s*_(dirty|clone)="[^"]*"/g, "") : html; + }, + unrender: function(context, buffer){ + for(var i = 0; i < this.contents.length; i++){ + buffer = this.contents[i].unrender(context, buffer); + if(!buffer) throw new Error("Template node render functions must return their buffer"); + } + return buffer; + }, + clone: function(buffer){ + // summary: + // Used to create an identical copy of a NodeList, useful for things like the for tag. + var parent = buffer.getParent(); + var contents = this.contents; + var nodelist = new dd._HtmlNodeList(); + var cloned = []; + for(var i = 0; i < contents.length; i++){ + var clone = contents[i].clone(buffer); + if(clone instanceof dd.ChangeNode || clone instanceof dd._HtmlNode){ + var item = clone.contents._clone; + if(item){ + clone.contents = item; + }else if(parent != clone.contents && clone instanceof dd._HtmlNode){ + var node = clone.contents; + clone.contents = clone.contents.cloneNode(false); + buffer.onClone(node, clone.contents); + cloned.push(node); + node._clone = clone.contents; + } + } + nodelist.push(clone); + } + + for(var i = 0, clone; clone = cloned[i]; i++){ + clone._clone = null; + } + + return nodelist; + } + }); + + dd._HtmlVarNode = dojo.extend(function(str){ + // summary: A node to be processed as a variable + // description: + // Will render an object that supports the render function + // and the getRootNode function + this.contents = new dd._Filter(str); + this._lists = {}; + }, + { + render: function(context, buffer){ + this._rendered = true; + + var str = this.contents.resolve(context); + if(str && str.render && str.getRootNode){ + var root = this._curr = str.getRootNode(); + var lists = this._lists; + var list = lists[root]; + if(!list){ + list = lists[root] = new dd._HtmlNodeList(); + list.push(new dd.ChangeNode(buffer.getParent())); + list.push(new dd._HtmlNode(root)); + list.push(str); + list.push(new dd.ChangeNode(buffer.getParent())); + } + return list.render(context, buffer); + }else{ + if(!this._txt){ + this._txt = document.createTextNode(str); + } + this._txt.data = str; + return buffer.concat(this._txt); + } + }, + unrender: function(context, buffer){ + if(!this._rendered){ + return buffer; + } + this._rendered = false; + if(this._curr){ + return this._lists[this._curr].unrender(context, buffer); + }else if(this._txt){ + return buffer.remove(this._txt); + } + return buffer; + }, + clone: function(){ + return new this.constructor(this.contents.getExpression()); + } + }); + + dd.ChangeNode = dojo.extend(function(node, /*Boolean?*/ up, /*Bookean*/ root){ + // summary: Changes the parent during render/unrender + this.contents = node; + this.up = up; + this.root = root; + }, + { + render: function(context, buffer){ + return buffer.setParent(this.contents, this.up, this.root); + }, + unrender: function(context, buffer){ + if(!this.contents.parentNode){ + return buffer; + } + if(!buffer.getParent()){ + return buffer; + } + return buffer.setParent(this.contents); + }, + clone: function(){ + return new this.constructor(this.contents, this.up, this.root); + } + }); + + dd.AttributeNode = dojo.extend(function(key, value, nodelist){ + // summary: Works on attributes + this.key = key; + this.value = value; + this.nodelist = nodelist || (new dd.Template(value)).nodelist; + + this.contents = ""; + }, + { + render: function(context, buffer){ + var key = this.key; + var value = this.nodelist.dummyRender(context); + if(this._rendered){ + if(value != this.contents){ + this.contents = value; + return buffer.setAttribute(key, value); + } + }else{ + this._rendered = true; + this.contents = value; + return buffer.setAttribute(key, value); + } + return buffer; + }, + unrender: function(context, buffer){ + return buffer.remove(this.key); + }, + clone: function(buffer){ + return new this.constructor(this.key, this.value, this.nodelist.clone(buffer)); + } + }); + + dd._HtmlTextNode = dojo.extend(function(str){ + // summary: Adds a straight text node without any processing + this.contents = document.createTextNode(str); + }, + { + set: function(data){ + this.contents.data = data; + }, + render: function(context, buffer){ + return buffer.concat(this.contents); + }, + unrender: function(context, buffer){ + return buffer.remove(this.contents); + }, + clone: function(){ + return new this.constructor(this.contents.data); + } + }); + + dd._HtmlParser = dojo.extend(function(tokens){ + // summary: Turn a simple array into a set of objects + // description: + // This is also used by all tags to move through + // the list of nodes. + this.contents = tokens; + }, + { + i: 0, + parse: function(/*Array?*/ stop_at){ + var types = ddh.types; + var terminators = {}; + var tokens = this.contents; + if(!stop_at){ + stop_at = []; + } + for(var i = 0; i < stop_at.length; i++){ + terminators[stop_at[i]] = true; + } + var nodelist = new dd._HtmlNodeList(); + while(this.i < tokens.length){ + var token = tokens[this.i++]; + var type = token[0]; + var value = token[1]; + if(type == types.custom){ + nodelist.push(value); + }else if(type == types.change){ + var changeNode = new dd.ChangeNode(value, token[2], token[3]); + value[changeNode.attr] = changeNode; + nodelist.push(changeNode); + }else if(type == types.attr){ + var fn = ddt.getTag("attr:" + token[2], true); + if(fn && token[3]){ + nodelist.push(fn(null, token[2] + " " + token[3])); + }else if(dojo.isString(token[3]) && (token[3].indexOf("{%") != -1 || token[3].indexOf("{{") != -1)){ + nodelist.push(new dd.AttributeNode(token[2], token[3])); + } + }else if(type == types.elem){ + var fn = ddt.getTag("node:" + value.tagName.toLowerCase(), true); + if(fn){ + // TODO: We need to move this to tokenization so that it's before the + // node and the parser can be passed here instead of null + nodelist.push(fn(null, value, value.tagName.toLowerCase())); + } + nodelist.push(new dd._HtmlNode(value)); + }else if(type == types.varr){ + nodelist.push(new dd._HtmlVarNode(value)); + }else if(type == types.text){ + nodelist.push(new dd._HtmlTextNode(value.data || value)); + }else if(type == types.tag){ + if(terminators[value]){ + --this.i; + return nodelist; + } + var cmd = value.split(/\s+/g); + if(cmd.length){ + cmd = cmd[0]; + var fn = ddt.getTag(cmd); + if(typeof fn != "function"){ + throw new Error("Function not found for " + cmd); + } + var tpl = fn(this, value); + if(tpl){ + nodelist.push(tpl); + } + } + } + } + + if(stop_at.length){ + throw new Error("Could not find closing tag(s): " + stop_at.toString()); + } + + return nodelist; + }, + next: function(){ + // summary: Used by tags to discover what token was found + var token = this.contents[this.i++]; + return {type: token[0], text: token[1]}; + }, + skipPast: function(endtag){ + return dd.Parser.prototype.skipPast.call(this, endtag); + }, + getVarNodeConstructor: function(){ + return dd._HtmlVarNode; + }, + getTextNodeConstructor: function(){ + return dd._HtmlTextNode; + }, + getTemplate: function(/*String*/ loc){ + return new dd.HtmlTemplate(ddh.getTemplate(loc)); + } + }); + +})(); + +} diff --git a/includes/js/dojox/dtl/render/html.js b/includes/js/dojox/dtl/render/html.js new file mode 100644 index 0000000..943dfbe --- /dev/null +++ b/includes/js/dojox/dtl/render/html.js @@ -0,0 +1,76 @@ +if(!dojo._hasResource["dojox.dtl.render.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.render.html"] = true; +dojo.provide("dojox.dtl.render.html"); +dojo.require("dojox.dtl.Context"); + +dojox.dtl.render.html.sensitivity = { + // summary: + // Set conditions under which to buffer changes + // description: + // Necessary if you make a lot of changes to your template. + // What happens is that the entire node, from the attached DOM Node + // down gets swapped with a clone, and until the entire rendering + // is complete, we don't replace the clone again. In this way, renders are + // "batched". + // + // But, if we're only changing a small number of nodes, we might no want to buffer at all. + // The higher numbers mean that even small changes will result in buffering. + // Each higher level includes the lower levels. + NODE: 1, // If a node changes, implement buffering + ATTRIBUTE: 2, // If an attribute or node changes, implement buffering + TEXT: 3 // If any text at all changes, implement buffering +} +dojox.dtl.render.html.Render = function(/*DOMNode?*/ attachPoint, /*dojox.dtl.HtmlTemplate?*/ tpl){ + this._tpl = tpl; + this.domNode = attachPoint; + this._swap = dojo.hitch(this, function(){ + // summary: Swaps the node out the first time the DOM is changed + // description: Gets swapped back it at end of render + if(this.domNode === this._tpl.getRootNode()){ + var frag = this.domNode; + this.domNode = this.domNode.cloneNode(true); + frag.parentNode.replaceChild(this.domNode, frag); + } + }); +} +dojo.extend(dojox.dtl.render.html.Render, { + sensitivity: dojox.dtl.render.html.sensitivity, + setAttachPoint: function(/*Node*/ node){ + this.domNode = node; + }, + render: function(/*Object*/ context, /*dojox.dtl.HtmlTemplate?*/ tpl, /*dojox.dtl.HtmlBuffer?*/ buffer){ + if(!this.domNode){ + throw new Error("You cannot use the Render object without specifying where you want to render it"); + } + + tpl = tpl || this._tpl; + buffer = buffer || tpl.getBuffer(); + context = context || new dojox.dtl.Context(); + + if(context.getThis() && context.getThis().buffer == this.sensitivity.NODE){ + var onAddNode = dojo.connect(buffer, "onAddNode", this, "_swap"); + var onRemoveNode = dojo.connect(buffer, "onRemoveNode", this, "_swap"); + } + + if(this._tpl && this._tpl !== tpl){ + this._tpl.unrender(context, buffer); + } + this._tpl = tpl; + + var frag = tpl.render(context, buffer).getParent(); + if(!frag){ + throw new Error("Rendered template does not have a root node"); + } + + dojo.disconnect(onAddNode); + dojo.disconnect(onRemoveNode); + + if(this.domNode !== frag){ + this.domNode.parentNode.replaceChild(frag, this.domNode); + dojo._destroyElement(this.domNode); + this.domNode = frag; + } + } +}); + +} diff --git a/includes/js/dojox/dtl/tag/date.js b/includes/js/dojox/dtl/tag/date.js new file mode 100644 index 0000000..fba4089 --- /dev/null +++ b/includes/js/dojox/dtl/tag/date.js @@ -0,0 +1,29 @@ +if(!dojo._hasResource["dojox.dtl.tag.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tag.date"] = true; +dojo.provide("dojox.dtl.tag.date"); + +dojo.require("dojox.dtl._base"); +dojo.require("dojox.dtl.utils.date"); + +dojox.dtl.tag.date.NowNode = function(format, TextNode){ + this.format = new dojox.dtl.utils.date.DateFormat(format); + this.contents = new TextNode(""); +} +dojo.extend(dojox.dtl.tag.date.NowNode, { + render: function(context, buffer){ + this.contents.set(this.format.format(new Date())); + return this.contents.render(context, buffer); + } +}); + +dojox.dtl.tag.date.now = function(parser, text){ + // Split by either :" or :' + var parts = text.split((text.substring(0, 5) == "now '") ? "'" : '"'); + if(parts.length != 3){ + throw new Error("'now' statement takes one argument"); + } + var format = parts[1]; + return new dojox.dtl.tag.date.NowNode(format, parser.getTextNodeConstructor()); +} + +} diff --git a/includes/js/dojox/dtl/tag/loader.js b/includes/js/dojox/dtl/tag/loader.js new file mode 100644 index 0000000..36c81bc --- /dev/null +++ b/includes/js/dojox/dtl/tag/loader.js @@ -0,0 +1,277 @@ +if(!dojo._hasResource["dojox.dtl.tag.loader"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tag.loader"] = true; +dojo.provide("dojox.dtl.tag.loader"); + +dojo.require("dojox.dtl._base"); + +(function(){ + var dd = dojox.dtl; + var ddtl = dd.tag.loader; + + ddtl.BlockNode = dojo.extend(function(name, nodelist){ + this.name = name; + this.nodelist = nodelist; // Can be overridden + }, + { + render: function(context, buffer){ + var name = this.name; + var nodelist = this.nodelist; + if(buffer.blocks){ + var block = buffer.blocks[name]; + if(block){ + nodelist = block.nodelist; + block.used = true; + } + } + this.rendered = nodelist; + return nodelist.render(context, buffer, this); + }, + unrender: function(context, buffer){ + return this.rendered.unrender(context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this.name, this.nodelist.clone(buffer)); + }, + setOverride: function(nodelist){ + // summary: In a shared parent, we override, not overwrite + if(!this.override){ + this.override = nodelist; + } + }, + toString: function(){ return "dojox.dtl.tag.loader.BlockNode"; } + }); + + ddtl.ExtendsNode = dojo.extend(function(getTemplate, nodelist, shared, parent, key){ + this.getTemplate = getTemplate; + this.nodelist = nodelist; + this.shared = shared; + this.parent = parent; + this.key = key; + }, + { + parents: {}, + getParent: function(context){ + if(!this.parent){ + this.parent = context.get(this.key, false); + if(!this.parent){ + throw new Error("extends tag used a variable that did not resolve"); + } + if(typeof this.parent == "object"){ + if(this.parent.url){ + if(this.parent.shared){ + this.shared = true; + } + this.parent = this.parent.url.toString(); + }else{ + this.parent = this.parent.toString(); + } + } + if(this.parent && this.parent.indexOf("shared:") == 0){ + this.shared = true; + this.parent = this.parent.substring(7, parent.length); + } + } + var parent = this.parent; + if(!parent){ + throw new Error("Invalid template name in 'extends' tag."); + } + if(parent.render){ + return parent; + } + if(this.parents[parent]){ + return this.parents[parent]; + } + this.parent = this.getTemplate(dojox.dtl.text.getTemplateString(parent)); + if(this.shared){ + this.parents[parent] = this.parent; + } + return this.parent; + }, + render: function(context, buffer){ + var parent = this.getParent(context); + + buffer.blocks = buffer.blocks || {}; + + // The parent won't always be in the default parent's nodelist + for(var i = 0, node; node = this.nodelist.contents[i]; i++){ + if(node instanceof dojox.dtl.tag.loader.BlockNode){ + buffer.blocks[node.name] = { + shared: this.shared, + nodelist: node.nodelist, + used: false + } + } + } + + this.rendered = parent; + buffer = parent.nodelist.render(context, buffer, this); + + var rerender = false; + for(var name in buffer.blocks){ + var block = buffer.blocks[name]; + if(!block.used){ + rerender = true; + parent.nodelist[0].nodelist.append(block.nodelist); + } + } + + if(rerender){ + buffer = parent.nodelist.render(context, buffer, this); + } + + return buffer; + }, + unrender: function(context, buffer){ + return this.rendered.unrender(context, buffer, this); + }, + toString: function(){ return "dojox.dtl.block.ExtendsNode"; } + }); + + ddtl.IncludeNode = dojo.extend(function(path, constant, getTemplate, TextNode, parsed){ + this._path = path; + this.constant = constant; + this.path = (constant) ? path : new dd._Filter(path); + this.getTemplate = getTemplate; + this.TextNode = TextNode; + this.parsed = (arguments.length == 5) ? parsed : true; + }, + { + _cache: [{}, {}], + render: function(context, buffer){ + var location = ((this.constant) ? this.path : this.path.resolve(context)).toString(); + var parsed = Number(this.parsed); + var dirty = false; + if(location != this.last){ + dirty = true; + if(this.last){ + buffer = this.unrender(context, buffer); + } + this.last = location; + } + + var cache = this._cache[parsed]; + + if(parsed){ + if(!cache[location]){ + cache[location] = dd.text._resolveTemplateArg(location, true); + } + if(dirty){ + var template = this.getTemplate(cache[location]); + this.rendered = template.nodelist; + } + return this.rendered.render(context, buffer, this); + }else{ + if(this.TextNode == dd._TextNode){ + if(dirty){ + this.rendered = new this.TextNode(""); + this.rendered.set(dd.text._resolveTemplateArg(location, true)); + } + return this.rendered.render(context, buffer); + }else{ + if(!cache[location]){ + var nodelist = []; + var div = document.createElement("div"); + div.innerHTML = dd.text._resolveTemplateArg(location, true); + var children = div.childNodes; + while(children.length){ + var removed = div.removeChild(children[0]); + nodelist.push(removed); + } + cache[location] = nodelist; + } + if(dirty){ + this.nodelist = []; + var exists = true; + for(var i = 0, child; child = cache[location][i]; i++){ + this.nodelist.push(child.cloneNode(true)); + } + } + for(var i = 0, node; node = this.nodelist[i]; i++){ + buffer = buffer.concat(node); + } + } + } + return buffer; + }, + unrender: function(context, buffer){ + if(this.rendered){ + buffer = this.rendered.unrender(context, buffer); + } + if(this.nodelist){ + for(var i = 0, node; node = this.nodelist[i]; i++){ + buffer = buffer.remove(node); + } + } + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this._path, this.constant, this.getTemplate, this.TextNode, this.parsed); + } + }); + + dojo.mixin(ddtl, { + block: function(parser, text){ + var parts = text.split(" "); + var name = parts[1]; + + parser._blocks = parser._blocks || {}; + parser._blocks[name] = parser._blocks[name] || []; + parser._blocks[name].push(name); + + var nodelist = parser.parse(["endblock", "endblock " + name]); + parser.next(); + return new dojox.dtl.tag.loader.BlockNode(name, nodelist); + }, + extends_: function(parser, text){ + var parts = text.split(" "); + var shared = false; + var parent = null; + var key = null; + if(parts[1].charAt(0) == '"' || parts[1].charAt(0) == "'"){ + parent = parts[1].substring(1, parts[1].length - 1); + }else{ + key = parts[1]; + } + if(parent && parent.indexOf("shared:") == 0){ + shared = true; + parent = parent.substring(7, parent.length); + } + var nodelist = parser.parse(); + return new dojox.dtl.tag.loader.ExtendsNode(parser.getTemplate, nodelist, shared, parent, key); + }, + include: function(parser, token){ + var parts = dd.text.pySplit(token); + if(parts.length != 2){ + throw new Error(parts[0] + " tag takes one argument: the name of the template to be included"); + } + var path = parts[1]; + var constant = false; + if((path.charAt(0) == '"' || path.slice(-1) == "'") && path.charAt(0) == path.slice(-1)){ + path = path.slice(1, -1); + constant = true; + } + return new ddtl.IncludeNode(path, constant, parser.getTemplate, parser.getTextNodeConstructor()); + }, + ssi: function(parser, token){ + // We're going to treat things a little differently here. + // First of all, this tag is *not* portable, so I'm not + // concerned about it being a "drop in" replacement. + + // Instead, we'll just replicate the include tag, but with that + // optional "parsed" parameter. + var parts = dd.text.pySplit(token); + var parsed = false; + if(parts.length == 3){ + parsed = (parts.pop() == "parsed"); + if(!parsed){ + throw new Error("Second (optional) argument to ssi tag must be 'parsed'"); + } + } + var node = ddtl.include(parser, parts.join(" ")); + node.parsed = parsed; + return node; + } + }); +})(); + +} diff --git a/includes/js/dojox/dtl/tag/logic.js b/includes/js/dojox/dtl/tag/logic.js new file mode 100644 index 0000000..90909ce --- /dev/null +++ b/includes/js/dojox/dtl/tag/logic.js @@ -0,0 +1,272 @@ +if(!dojo._hasResource["dojox.dtl.tag.logic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tag.logic"] = true; +dojo.provide("dojox.dtl.tag.logic"); + +dojo.require("dojox.dtl._base"); + +(function(){ + var dd = dojox.dtl; + var ddt = dd.text; + var ddtl = dd.tag.logic; + + ddtl.IfNode = dojo.extend(function(bools, trues, falses, type){ + this.bools = bools; + this.trues = trues; + this.falses = falses; + this.type = type; + }, + { + render: function(context, buffer){ + var i, bool, ifnot, filter, value; + if(this.type == "or"){ + for(i = 0; bool = this.bools[i]; i++){ + ifnot = bool[0]; + filter = bool[1]; + value = filter.resolve(context); + if((value && !ifnot) || (ifnot && !value)){ + if(this.falses){ + buffer = this.falses.unrender(context, buffer); + } + return (this.trues) ? this.trues.render(context, buffer, this) : buffer; + } + } + if(this.trues){ + buffer = this.trues.unrender(context, buffer); + } + return (this.falses) ? this.falses.render(context, buffer, this) : buffer; + }else{ + for(i = 0; bool = this.bools[i]; i++){ + ifnot = bool[0]; + filter = bool[1]; + value = filter.resolve(context); + // If we ever encounter a false value + if(value == ifnot){ + if(this.trues){ + buffer = this.trues.unrender(context, buffer); + } + return (this.falses) ? this.falses.render(context, buffer, this) : buffer; + } + } + if(this.falses){ + buffer = this.falses.unrender(context, buffer); + } + return (this.trues) ? this.trues.render(context, buffer, this) : buffer; + } + return buffer; + }, + unrender: function(context, buffer){ + buffer = (this.trues) ? this.trues.unrender(context, buffer) : buffer; + buffer = (this.falses) ? this.falses.unrender(context, buffer) : buffer; + return buffer; + }, + clone: function(buffer){ + var trues = (this.trues) ? this.trues.clone(buffer) : null; + var falses = (this.falses) ? this.falses.clone(buffer) : null; + return new this.constructor(this.bools, trues, falses, this.type); + } + }); + + ddtl.IfEqualNode = dojo.extend(function(var1, var2, trues, falses, negate){ + this.var1 = new dd._Filter(var1); + this.var2 = new dd._Filter(var2); + this.trues = trues; + this.falses = falses; + this.negate = negate; + }, + { + render: function(context, buffer){ + var var1 = this.var1.resolve(context); + var var2 = this.var2.resolve(context); + if((this.negate && var1 != var2) || (!this.negate && var1 == var2)){ + if(this.falses){ + buffer = this.falses.unrender(context, buffer); + } + return (this.trues) ? this.trues.render(context, buffer, this) : buffer; + } + if(this.trues){ + buffer = this.trues.unrender(context, buffer); + } + return (this.falses) ? this.falses.render(context, buffer, this) : buffer; + }, + unrender: function(context, buffer){ + return ddtl.IfNode.prototype.unrender.call(this, context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this.var1.getExpression(), this.var2.getExpression(), this.trues.clone(buffer), this.falses.clone(buffer), this.negate); + } + }); + + ddtl.ForNode = dojo.extend(function(assign, loop, reversed, nodelist){ + this.assign = assign; + this.loop = new dd._Filter(loop); + this.reversed = reversed; + this.nodelist = nodelist; + this.pool = []; + }, + { + render: function(context, buffer){ + var i, j, k; + var dirty = false; + var assign = this.assign; + + for(k = 0; k < assign.length; k++){ + if(typeof context[assign[k]] != "undefined"){ + dirty = true; + context.push(); + break; + } + } + + var items = this.loop.resolve(context) || []; + for(i = items.length; i < this.pool.length; i++){ + this.pool[i].unrender(context, buffer); + } + if(this.reversed){ + items = items.slice(0).reverse(); + } + + var isObject = dojo.isObject(items) && !dojo.isArrayLike(items); + var arred = []; + if(isObject){ + for(var key in items){ + arred.push(items[key]); + } + }else{ + arred = items; + } + + var forloop = context.forloop = { + parentloop: context.forloop || {} + }; + var j = 0; + for(i = 0; i < arred.length; i++){ + var item = arred[i]; + + forloop.counter0 = j; + forloop.counter = j + 1; + forloop.revcounter0 = arred.length - j - 1; + forloop.revcounter = arred.length - j; + forloop.first = !j; + forloop.last = (j == arred.length - 1); + + if(assign.length > 1 && dojo.isArrayLike(item)){ + if(!dirty){ + dirty = true; + context.push(); + } + var zipped = {}; + for(k = 0; k < item.length && k < assign.length; k++){ + zipped[assign[k]] = item[k]; + } + context.update(zipped); + }else{ + context[assign[0]] = item; + } + + if(j + 1 > this.pool.length){ + this.pool.push(this.nodelist.clone(buffer)); + } + buffer = this.pool[j].render(context, buffer, this); + ++j; + } + + delete context.forloop; + for(k = 0; k < assign.length; k++){ + delete context[assign[k]]; + } + if(dirty){ + context.pop(); + } + return buffer; + }, + unrender: function(context, buffer){ + for(var i = 0, pool; pool = this.pool[i]; i++){ + buffer = pool.unrender(context, buffer); + } + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this.assign, this.loop.getExpression(), this.reversed, this.nodelist.clone(buffer)); + } + }); + + dojo.mixin(ddtl, { + if_: function(parser, text){ + var i, part, type, bools = [], parts = ddt.pySplit(text); + parts.shift(); + text = parts.join(" "); + parts = text.split(" and "); + if(parts.length == 1){ + type = "or"; + parts = text.split(" or "); + }else{ + type = "and"; + for(i = 0; i < parts.length; i++){ + if(parts[i].indexOf(" or ") != -1){ + // Note, since we split by and, this is the only place we need to error check + throw new Error("'if' tags can't mix 'and' and 'or'"); + } + } + } + for(i = 0; part = parts[i]; i++){ + var not = false; + if(part.indexOf("not ") == 0){ + part = part.slice(4); + not = true; + } + bools.push([not, new dd._Filter(part)]); + } + var trues = parser.parse(["else", "endif"]); + var falses = false; + var token = parser.next(); + if(token.text == "else"){ + falses = parser.parse(["endif"]); + parser.next(); + } + return new ddtl.IfNode(bools, trues, falses, type); + }, + _ifequal: function(parser, text, negate){ + var parts = ddt.pySplit(text); + if(parts.length != 3){ + throw new Error(parts[0] + " takes two arguments"); + } + var end = 'end' + parts[0]; + var trues = parser.parse(["else", end]); + var falses = false; + var token = parser.next(); + if(token.text == "else"){ + falses = parser.parse([end]); + parser.next(); + } + return new ddtl.IfEqualNode(parts[1], parts[2], trues, falses, negate); + }, + ifequal: function(parser, text){ + return ddtl._ifequal(parser, text); + }, + ifnotequal: function(parser, text){ + return ddtl._ifequal(parser, text, true); + }, + for_: function(parser, text){ + var parts = ddt.pySplit(text); + if(parts.length < 4){ + throw new Error("'for' statements should have at least four words: " + text); + } + var reversed = parts[parts.length - 1] == "reversed"; + var index = (reversed) ? -3 : -2; + if(parts[parts.length + index] != "in"){ + throw new Error("'for' tag received an invalid argument: " + text); + } + var loopvars = parts.slice(1, index).join(" ").split(/ *, */); + for(var i = 0; i < loopvars.length; i++){ + if(!loopvars[i] || loopvars[i].indexOf(" ") != -1){ + throw new Error("'for' tag received an invalid argument: " + text); + } + } + var nodelist = parser.parse(["endfor"]); + parser.next(); + return new ddtl.ForNode(loopvars, parts[parts.length + index + 1], reversed, nodelist); + } + }); +})(); + +} diff --git a/includes/js/dojox/dtl/tag/loop.js b/includes/js/dojox/dtl/tag/loop.js new file mode 100644 index 0000000..3626c52 --- /dev/null +++ b/includes/js/dojox/dtl/tag/loop.js @@ -0,0 +1,196 @@ +if(!dojo._hasResource["dojox.dtl.tag.loop"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tag.loop"] = true; +dojo.provide("dojox.dtl.tag.loop"); + +dojo.require("dojox.dtl._base"); +dojo.require("dojox.string.tokenize"); + +(function(){ + var dd = dojox.dtl; + var ddtl = dd.tag.loop; + + ddtl.CycleNode = dojo.extend(function(cyclevars, name, TextNode, shared){ + this.cyclevars = cyclevars; + this.name = name; + this.TextNode = TextNode; + this.shared = shared || {counter: -1, map: {}}; + }, + { + render: function(context, buffer){ + if(context.forloop && !context.forloop.counter0){ + this.shared.counter = -1; + } + + ++this.shared.counter; + var value = this.cyclevars[this.shared.counter % this.cyclevars.length]; + + var map = this.shared.map; + if(!map[value]){ + map[value] = new dd._Filter(value); + } + value = map[value].resolve(context, buffer); + + if(this.name){ + context[this.name] = value; + } + if(!this.contents){ + this.contents = new this.TextNode(""); + } + this.contents.set(value); + return this.contents.render(context, buffer); + }, + unrender: function(context, buffer){ + return this.contents.unrender(context, buffer); + }, + clone: function(){ + return new this.constructor(this.cyclevars, this.name, this.TextNode, this.shared); + } + }); + + ddtl.IfChangedNode = dojo.extend(function(nodes, vars, shared){ + this.nodes = nodes; + this._vars = vars; + this.shared = shared || {last: null}; + this.vars = dojo.map(vars, function(item){ + return new dojox.dtl._Filter(item); + }); + }, { + render: function(context, buffer){ + if(context.forloop && context.forloop.first){ + this.shared.last = null; + } + + var change; + if(this.vars.length){ + change = dojo.toJson(dojo.map(this.vars, function(item){ + return item.resolve(context); + })); + }else{ + change = this.nodes.dummyRender(context, buffer); + } + + if(change != this.shared.last){ + var firstloop = (this.shared.last === null); + this.shared.last = change; + context.push(); + context.ifchanged = {firstloop: firstloop} + buffer = this.nodes.render(context, buffer); + context.pop(); + } + return buffer; + }, + unrender: function(context, buffer){ + this.nodes.unrender(context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this.nodes.clone(buffer), this._vars, this.shared); + } + }); + + ddtl.RegroupNode = dojo.extend(function(expression, key, alias){ + this._expression = expression; + this.expression = new dd._Filter(expression); + this.key = key; + this.alias = alias; + }, + { + _push: function(container, grouper, stack){ + if(stack.length){ + container.push({ grouper: grouper, list: stack }) + } + }, + render: function(context, buffer){ + context[this.alias] = []; + var list = this.expression.resolve(context); + if(list){ + var last = null; + var stack = []; + for(var i = 0; i < list.length; i++){ + var id = list[i][this.key]; + if(last !== id){ + this._push(context[this.alias], last, stack); + last = id; + stack = [list[i]]; + }else{ + stack.push(list[i]); + } + } + this._push(context[this.alias], last, stack); + } + return buffer; + }, + unrender: function(context, buffer){ + return buffer; + }, + clone: function(context, buffer){ + return this; + } + }); + + dojo.mixin(ddtl, { + cycle: function(parser, text){ + // summary: Cycle among the given strings each time this tag is encountered + var args = text.split(" "); + + if(args.length < 2){ + throw new Error("'cycle' tag requires at least two arguments"); + } + + if(args[1].indexOf(",") != -1){ + var vars = args[1].split(","); + args = [args[0]]; + for(var i = 0; i < vars.length; i++){ + args.push('"' + vars[i] + '"'); + } + } + + if(args.length == 2){ + var name = args[args.length - 1]; + + if(!parser._namedCycleNodes){ + throw new Error("No named cycles in template: '" + name + "' is not defined"); + } + if(!parser._namedCycleNodes[name]){ + throw new Error("Named cycle '" + name + "' does not exist"); + } + + return parser._namedCycleNodes[name]; + } + + if(args.length > 4 && args[args.length - 2] == "as"){ + var name = args[args.length - 1]; + + var node = new ddtl.CycleNode(args.slice(1, args.length - 2), name, parser.getTextNodeConstructor()); + + if(!parser._namedCycleNodes){ + parser._namedCycleNodes = {}; + } + parser._namedCycleNodes[name] = node; + }else{ + node = new ddtl.CycleNode(args.slice(1), null, parser.getTextNodeConstructor()); + } + + return node; + }, + ifchanged: function(parser, text){ + var parts = dojox.dtl.text.pySplit(text); + var nodes = parser.parse(["endifchanged"]); + parser.next(); + return new ddtl.IfChangedNode(nodes, parts.slice(1)); + }, + regroup: function(parser, text){ + var tokens = dojox.string.tokenize(dojo.trim(text), /(\s+)/g, function(spaces){ + return spaces; + }); + if(tokens.length < 11 || tokens[tokens.length - 3] != "as" || tokens[tokens.length - 7] != "by"){ + throw new Error("Expected the format: regroup list by key as newList"); + } + var expression = tokens.slice(2, -8).join(""); + var key = tokens[tokens.length - 5]; + var alias = tokens[tokens.length - 1]; + return new ddtl.RegroupNode(expression, key, alias); + } + }); +})(); + +} diff --git a/includes/js/dojox/dtl/tag/misc.js b/includes/js/dojox/dtl/tag/misc.js new file mode 100644 index 0000000..31610d7 --- /dev/null +++ b/includes/js/dojox/dtl/tag/misc.js @@ -0,0 +1,291 @@ +if(!dojo._hasResource["dojox.dtl.tag.misc"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tag.misc"] = true; +dojo.provide("dojox.dtl.tag.misc"); +dojo.require("dojox.dtl._base"); + +(function(){ + var dd = dojox.dtl; + var ddtm = dd.tag.misc; + + ddtm.DebugNode = dojo.extend(function(TextNode){ + this._TextNode = TextNode; + }, + { + render: function(context, buffer){ + var keys = context.getKeys(); + var debug = ""; + for(var i = 0, key; key = keys[i]; i++){ + console.debug("DEBUG", key, ":", context[key]); + debug += key + ": " + dojo.toJson(context[key]) + "\n\n"; + } + return new this._TextNode(debug).render(context, buffer, this); + }, + unrender: function(context, buffer){ + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this._TextNode); + }, + toString: function(){ return "ddtm.DebugNode"; } + }); + + ddtm.FilterNode = dojo.extend(function(varnode, nodelist){ + this._varnode = varnode; + this._nodelist = nodelist; + }, + { + render: function(context, buffer){ + // Doing this in HTML requires a different buffer with a fake root node + var output = this._nodelist.render(context, new dojox.string.Builder()); + context.update({ "var": output.toString() }); + var filtered = this._varnode.render(context, buffer); + context.pop(); + return buffer; + }, + unrender: function(context, buffer){ + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this._expression, this._nodelist.clone(buffer)); + } + }); + + ddtm.FirstOfNode = dojo.extend(function(vars, TextNode){ + this._vars = vars; + this.vars = dojo.map(vars, function(item){ + return new dojox.dtl._Filter(item); + }); + this.contents = new TextNode(""); + }, + { + render: function(context, buffer){ + for(var i = 0, item; item = this.vars[i]; i++){ + var resolved = item.resolve(context); + if(typeof resolved != "undefined"){ + if(resolved === null){ + resolved = "null"; + } + this.contents.set(resolved); + return this.contents.render(context, buffer); + } + } + return this.contents.unrender(context, buffer); + }, + unrender: function(context, buffer){ + return this.contents.unrender(context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this._vars, this.contents.constructor); + } + }); + + ddtm.SpacelessNode = dojo.extend(function(nodelist, TextNode){ + this.nodelist = nodelist; + this.TextNode = TextNode; + }, + { + render: function(context, buffer){ + if(buffer.onAddNodeComplete){ + // Unfortunately, we have to branch here + var watch = [ + dojo.connect(buffer, "onAddNodeComplete", this, "_watch"), + dojo.connect(buffer, "onSetParent", this, "_watchParent") + ]; + buffer = this.nodelist.render(context, buffer); + dojo.disconnect(watch[0]); + dojo.disconnect(watch[1]); + }else{ + if(!this.contents){ + this.contents = new this.TextNode(""); + } + var value = this.nodelist.dummyRender(context); + this.contents.set(value.replace(/>\s+<')); + buffer = this.contents.render(context, buffer); + } + return buffer; + }, + unrender: function(context, buffer){ + return this.nodelist.unrender(context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this.nodelist.clone(buffer)); + }, + _isEmpty: function(node){ + return (node.nodeType == 3 && !node.data.match(/[^\s\n]/)); + }, + _watch: function(node){ + if(this._isEmpty(node)){ + var remove = false; + if(node.parentNode.firstChild == node){ + node.parentNode.removeChild(node); + } + }else{ + var children = node.parentNode.childNodes; + if(node.nodeType == 1 && children.length > 2){ + for(var i = 2, child; child = children[i]; i++){ + if(children[i - 2].nodeType == 1 && this._isEmpty(children[i - 1])){ + node.parentNode.removeChild(children[i - 1]); + return; + } + } + } + } + }, + _watchParent: function(node){ + var children = node.childNodes; + if(children.length){ + while(node.childNodes.length){ + var last = node.childNodes[node.childNodes.length - 1]; + if(!this._isEmpty(last)){ + return; + } + node.removeChild(last); + } + } + } + }); + + ddtm.TemplateTagNode = dojo.extend(function(tag, TextNode){ + this.tag = tag; + this.contents = new TextNode(""); + }, + { + mapping: { + openblock: "{%", + closeblock: "%}", + openvariable: "{{", + closevariable: "}}", + openbrace: "{", + closebrace: "}", + opencomment: "{#", + closecomment: "#}" + }, + render: function(context, buffer){ + this.contents.set(this.mapping[this.tag]); + return this.contents.render(context, buffer); + }, + unrender: function(context, buffer){ + return this.contents.unrender(context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this.tag, this.contents.constructor); + } + }); + + ddtm.WidthRatioNode = dojo.extend(function(current, max, width, TextNode){ + this.current = new dd._Filter(current); + this.max = new dd._Filter(max); + this.width = width; + this.contents = new TextNode(""); + }, + { + render: function(context, buffer){ + var current = +this.current.resolve(context); + var max = +this.max.resolve(context); + if(typeof current != "number" || typeof max != "number" || !max){ + this.contents.set(""); + }else{ + this.contents.set("" + Math.round((current / max) * this.width)); + } + return this.contents.render(context, buffer); + }, + unrender: function(context, buffer){ + return this.contents.unrender(context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this.current.getExpression(), this.max.getExpression(), this.width, this.contents.constructor); + } + }); + + ddtm.WithNode = dojo.extend(function(target, alias, nodelist){ + this.target = new dd._Filter(target); + this.alias = alias; + this.nodelist = nodelist; + }, + { + render: function(context, buffer){ + var target = this.target.resolve(context); + context.push(); + context[this.alias] = target; + buffer = this.nodelist.render(context, buffer); + context.pop(); + return buffer; + }, + unrender: function(context, buffer){ + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this.target.getExpression(), this.alias, this.nodelist.clone(buffer)); + } + }); + + dojo.mixin(ddtm, { + comment: function(parser, text){ + // summary: Ignore everything between {% comment %} and {% endcomment %} + parser.skipPast("endcomment"); + return dd._noOpNode; + }, + debug: function(parser, text){ + // summary: Output the current context, maybe add more stuff later. + return new ddtm.DebugNode(parser.getTextNodeConstructor()); + }, + filter: function(parser, text){ + // summary: Filter the contents of the blog through variable filters. + var parts = text.split(" ", 2); + var varnode = new (parser.getVarNodeConstructor())("var|" + parts[1]); + var nodelist = parser.parse(["endfilter"]); + parser.next(); + return new ddtm.FilterNode(varnode, nodelist); + }, + firstof: function(parser, text){ + var parts = dojox.dtl.text.pySplit(text).slice(1); + if(!parts.length){ + throw new Error("'firstof' statement requires at least one argument"); + } + return new ddtm.FirstOfNode(parts, parser.getTextNodeConstructor()); + }, + spaceless: function(parser, text){ + var nodelist = parser.parse(["endspaceless"]); + parser.next(); + return new ddtm.SpacelessNode(nodelist, parser.getTextNodeConstructor()); + }, + templatetag: function(parser, text){ + var parts = dd.text.pySplit(text); + if(parts.length != 2){ + throw new Error("'templatetag' statement takes one argument"); + } + var tag = parts[1]; + var mapping = ddtm.TemplateTagNode.prototype.mapping; + if(!mapping[tag]){ + var keys = []; + for(var key in mapping){ + keys.push(key); + } + throw new Error("Invalid templatetag argument: '" + tag + "'. Must be one of: " + keys.join(", ")); + } + return new ddtm.TemplateTagNode(tag, parser.getTextNodeConstructor()); + }, + widthratio: function(parser, text){ + var parts = dd.text.pySplit(text); + if(parts.length != 4){ + throw new Error("widthratio takes three arguments"); + } + var width = +parts[3]; + if(typeof width != "number"){ + throw new Error("widthratio final argument must be an integer"); + } + return new ddtm.WidthRatioNode(parts[1], parts[2], width, parser.getTextNodeConstructor()); + }, + with_: function(parser, text){ + var parts = dd.text.pySplit(text); + if(parts.length != 4 || parts[2] != "as"){ + throw new Error("do_width expected format as 'with value as name'"); + } + var nodelist = parser.parse(["endwith"]); + parser.next(); + return new ddtm.WithNode(parts[1], parts[3], nodelist); + } + }); +})(); + +} diff --git a/includes/js/dojox/dtl/tests/context.js b/includes/js/dojox/dtl/tests/context.js new file mode 100644 index 0000000..a366098 --- /dev/null +++ b/includes/js/dojox/dtl/tests/context.js @@ -0,0 +1,79 @@ +if(!dojo._hasResource["dojox.dtl.tests.context"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tests.context"] = true; +dojo.provide("dojox.dtl.tests.context"); + +dojo.require("dojox.dtl"); +dojo.require("dojox.dtl.Context"); + +doh.register("dojox.dtl.context", + [ + function test_context_creation(t){ + var context = new dojox.dtl.Context({ foo: "foo", bar: "bar" }); + t.is("foo", context.foo); + t.is("bar", context.bar); + }, + function test_context_push(t){ + var context = new dojox.dtl.Context({ foo: "foo", bar: "bar" }); + context.push(); + for(var key in context._dicts[0]){ + t.t(key == "foo" || key == "bar"); + } + }, + function test_context_pop(t){ + var context = new dojox.dtl.Context({ foo: "foo", bar: "bar" }); + context.push(); + t.is("undefined", typeof context.foo); + t.is("undefined", typeof context.bar); + context.pop(); + t.is("foo", context.foo); + t.is("bar", context.bar); + }, + function test_context_overpop(t){ + var context = new dojox.dtl.Context(); + try{ + context.pop(); + t.t(false); + }catch(e){ + t.is("pop() called on empty Context", e.message); + } + }, + function test_context_filter(t){ + var context = new dojox.dtl.Context({ foo: "one", bar: "two", baz: "three" }); + var filtered = context.filter("foo", "bar"); + t.is(filtered.foo, "one"); + t.is(filtered.bar, "two"); + t.f(filtered.baz); + + filtered = context.filter({ bar: true, baz: true }); + t.f(filtered.foo); + t.is(filtered.bar, "two"); + t.is(filtered.baz, "three"); + + filtered = context.filter(new dojox.dtl.Context({ foo: true, baz: true })); + t.is(filtered.foo, "one"); + t.f(filtered.bar); + t.is(filtered.baz, "three"); + }, + function test_context_extend(t){ + var context = new dojox.dtl.Context({ foo: "one" }); + var extended = context.extend({ bar: "two", baz: "three" }); + t.is(extended.foo, "one"); + t.is(extended.bar, "two"); + t.is(extended.baz, "three"); + + extended = context.extend({ barr: "two", bazz: "three" }); + t.is(extended.foo, "one"); + t.f(extended.bar); + t.f(extended.baz); + t.is(extended.barr, "two"); + t.is(extended.bazz, "three"); + + t.f(context.bar) + t.f(context.baz); + t.f(context.barr); + t.f(context.bazz); + } + ] +); + +} diff --git a/includes/js/dojox/dtl/tests/demo_Templated_Jaxer.html b/includes/js/dojox/dtl/tests/demo_Templated_Jaxer.html new file mode 100644 index 0000000..29e5470 --- /dev/null +++ b/includes/js/dojox/dtl/tests/demo_Templated_Jaxer.html @@ -0,0 +1,87 @@ + + + Demo using dojox.dtl._Templated + + + + +

      Using Dojo's Django Template language on Jaxer

      +

      + Aptana's Jaxer is server side JavaScript (SSJS) server. With some modifications to + a web page, Dojo can be run on the server. With Dojo running on the server, you can + utilize the Dojo's Django Template library rendering engine to do templating within + Jaxer. The latest build of Dojo includes some patches to properly work with Jaxer, + so you need a build of Dojo later than 2/18/08 to work with Jaxer. Next, the + following modifications to your page are needed to run Jaxer: +

        +
      • + You must explicitly set the base url of the Dojo library. Jaxer does not provide + the ability for Dojo to auto-detect the base url as it can in other environments. + Therefore you must declare the base url with the djConfig global variable: +
        +	<script runat="server">
        +		djConfig = {baseUrl:"/dojo/", // use the base path of dojo here
        +					usePlainJson: true, parseOnLoad: true};
        +	</script>
        +							
        +
      • +
      • + Next, you must add the runat attribute with a value of "server" to all of the script + tags that you want executed on the server. Your script tags should look like: +
        +	<script runat="server" type="text/javascript" src="../../../dojo/dojo.js"></script>
        +							
        +
      • +
      • + Last, you must dojo.require("dojo.jaxer") with a script tag. This should immediately + follow the declaration of dojo.js: +
        +	<script runat="server" type="text/javascript" src="../../../dojo/dojo.js"></script>
        +	<script runat="server" type="text/javascript">dojo.require("dojo.jaxer");</script>
        +							
        +
      • +
      +

      +

      + Once this is done, Dojo should load in Jaxer, and you can utilize the library capabilities of + Dojo. In particular, you can now use DTL renderer as you would on + the browser. If you are running this in Jaxer, below should be a working demonstration of + a template that is rendered on the server. +

      +
      +

      + It is important to note that Jaxer is not capable of transferring the programmaticaly set + event handlers for widgets, it can only send the static HTML to the browser. This means + you can use DTL as a templating engine to create HTML on the server, but Dojo client side widgets + are still necessary if you want to use interactive widgets on the browser. +

      + + + \ No newline at end of file diff --git a/includes/js/dojox/dtl/tests/html/buffer.js b/includes/js/dojox/dtl/tests/html/buffer.js new file mode 100644 index 0000000..3077d8c --- /dev/null +++ b/includes/js/dojox/dtl/tests/html/buffer.js @@ -0,0 +1,35 @@ +if(!dojo._hasResource["dojox.dtl.tests.html.buffer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tests.html.buffer"] = true; +dojo.provide("dojox.dtl.tests.html.buffer"); + +dojo.require("dojox.dtl.html"); +dojo.require("dojox.dtl.Context"); +dojo.require("dojox.dtl.tests.html.util"); + +doh.register("dojox.dtl.html.buffer", + [ + function test_insertion_order_text(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + first: false, + last: false + }); + + var template = new dd.HtmlTemplate("
      {% if first %}first{% endif %}middle{% if last %}last{% endif %}
      "); + t.is("
      middle
      ", dd.tests.html.util.render(template, context)); + + context.first = true; + t.is("
      firstmiddle
      ", dd.tests.html.util.render(template, context)); + + context.first = false; + context.last = true; + t.is("
      middlelast
      ", dd.tests.html.util.render(template, context)); + + context.first = true; + t.is("
      firstmiddlelast
      ", dd.tests.html.util.render(template, context)); + } + ] +); + +} diff --git a/includes/js/dojox/dtl/tests/html/tag.js b/includes/js/dojox/dtl/tests/html/tag.js new file mode 100644 index 0000000..c964913 --- /dev/null +++ b/includes/js/dojox/dtl/tests/html/tag.js @@ -0,0 +1,233 @@ +if(!dojo._hasResource["dojox.dtl.tests.html.tag"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tests.html.tag"] = true; +dojo.provide("dojox.dtl.tests.html.tag"); + +dojo.require("dojox.dtl.html"); +dojo.require("dojox.dtl.Context"); +dojo.require("dojox.dtl.tests.html.util"); + +doh.register("dojox.dtl.html.tag", + [ + function test_errors(t){ + var dd = dojox.dtl; + var template; + + // No root node after rendering + var found = false; + try { + template = new dd.HtmlTemplate('No div'); + dd.tests.html.util.render(template); + }catch(e){ + t.is("Text should not exist outside of the root node in template", e.message); + found = true; + } + t.t(found); + + var context = new dojox.dtl.Context({test: "Pocket"}); + found = false; + try { + template = new dd.HtmlTemplate('{{ test }}'); + dd.tests.html.util.render(template, context); + }catch(e){ + t.is("Text should not exist outside of the root node in template", e.message); + found = true; + } + t.t(found); + + template = new dd.HtmlTemplate('
      extra content'); + found = false; + try { + dd.tests.html.util.render(template); + }catch(e){ + t.is("Content should not exist outside of the root node in template", e.message); + found = true; + } + t.t(found); + + // More than one top-level node (except for blocks) + template = new dd.HtmlTemplate('
      '); + found = false; + try { + dd.tests.html.util.render(template); + }catch(e){ + t.is("Content should not exist outside of the root node in template", e.message); + found = true; + } + t.t(found); + + // Logic block rules out any root node + template = new dd.HtmlTemplate('{% if missing %}
      {% endif %}'); + found = false; + try { + dd.tests.html.util.render(template); + }catch(e){ + t.is("Rendered template does not have a root node", e.message); + found = true; + } + t.t(found); + }, + function test_structures(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + actions: ["ate", "picked"], + items: [ + { + name: "apple" + }, + { + name: "banana", + date: new Date(2007, 2, 16, 14, 30, 10) + }, + { + name: "orange", + date: new Date(2008, 0, 1, 12, 0, 0) + } + ] + }); + + var template = new dd.HtmlTemplate('
        I {% for action in actions %}{% if not forloop.first %}, {% endif %}{{action}}{% endfor %} the following:
          {% for item in items %}
        • {{ item.name }}{% if item.date %} at {{ item.date|date:"P" }}{% endif %}
        • {% endfor %}
      '); + t.is('
        I ate, picked the following:
        • apple
        • banana at 2:30 pm
        • orange at noon
      ', dd.tests.html.util.render(template, context)); + }, + function test_tag_extend(t){ + // Problems to look for: + // * Content outside of blocks + }, + function test_tag_for(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + items: ["apple", "banana", "lemon"] + }); + var template = new dd.HtmlTemplate('
        {% for item in items %}
      • {{ item }}
      • {% endfor %}
      '); + + t.is('
      • apple
      • banana
      • lemon
      ', dd.tests.html.util.render(template, context)); + + // The line break is there to make sure our regex works + template = new dd.HtmlTemplate('
      '); + + t.is('
      ', dd.tests.html.util.render(template, context)); + }, + function test_tag_if(t){ + var dd = dojox.dtl; + + var context = new dd.Context({key: true}); + var template = new dd.HtmlTemplate('{% if key %}
      has key
      {% else %}
      no key
      {% endif %}'); + t.is("
      has key
      ", dd.tests.html.util.render(template, context)); + context.key = false; + t.is("
      no key
      ", dd.tests.html.util.render(template, context)); + }, + function test_tag_ifchanged(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + year: 2008, + days: [ + new Date(2008, 0, 12), + new Date(2008, 0, 28), + new Date(2008, 1, 1), + new Date(2008, 1, 1), + new Date(2008, 1, 1) + ] + }); + + var template = new dd.HtmlTemplate("

      Archive for {{ year }}

      "+ +"{% for date in days %}"+ +'{% ifchanged %}

      Month:

      {{ date|date:"F" }}

      {% endifchanged %}'+ +'{{ date|date:\'j\' }}'+ +"{% endfor %}
      "); + + t.is('

      Archive for 2008

      '+ +'

      Month:

      January

      '+ +'12'+ +'28'+ +'

      Month:

      February

      '+ +'1'+ +'1'+ +'1
      ', dd.tests.html.util.render(template, context)); + + template = new dd.HtmlTemplate('
      {% for date in days %}'+ +'{% ifchanged date.date %} {{ date.date }} {% endifchanged %}'+ +'{% ifchanged date.hour date.date %}'+ +'{{ date.hour }}'+ +'{% endifchanged %}'+ +'{% endfor %}
      '); + t.is('
      2008-01-12 0 2008-01-28 0 2008-02-01 0
      ', dd.tests.html.util.render(template, context)); + }, + function test_tag_ifequal(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + items: [ + { name: "apple", color: "red" }, + { name: "banana", color: "yellow" }, + { name: "pear", color: "green" }, + { name: "kiwi", color: "brown" } + ], + edit_item: "banana" + }); + + var template = new dd.HtmlTemplate("
        {% for item in items %}
      • {{ item.name }}
      • {% endfor %}
      "); + t.is('
      • apple
      • banana
      • pear
      • kiwi
      ', dd.tests.html.util.render(template, context)); + + template = new dd.HtmlTemplate("
        {% for item in items %}
      • {{ item.name }}

        {{ item.color }}

      • {% endfor %}
      "); + t.is('
      • apple

        red

      • banana

        yellow

      • pear

        green

      • kiwi

        brown

      ', dd.tests.html.util.render(template, context)); + + template = new dd.HtmlTemplate("
        {% for item in items %}
      • {% ifequal item.name edit_item %}
        {% else %}{{ item.name }}

        {{ item.color }}

        {% endifequal %}
      • {% endfor %}
      "); + t.is('
      • apple

        red


      • pear

        green

      • kiwi

        brown

      ', dd.tests.html.util.render(template, context)); + + template = new dd.HtmlTemplate("
        {% for item in items %}
      • {% ifequal item.name edit_item %}

        {% else %}
        {{ item.name }}

        {{ item.color }}

        {% endifequal %}
      • {% endfor %}
      "); + t.is('
      • apple

        red


      • pear

        green

      • kiwi

        brown

      ', dd.tests.html.util.render(template, context)); + + template = new dd.HtmlTemplate("
        {% for item in items %}{% ifequal item.name edit_item %}

      • {% else %}
      • {{ item.name }}

        {{ item.color }}

      • {% endifequal %}{% endfor %}
      "); + t.is('
      • apple

        red


      • pear

        green

      • kiwi

        brown

      ', dd.tests.html.util.render(template, context)); + }, + function test_tag_include(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + hello: dojo.moduleUrl("dojox.dtl.tests.templates", "hello.html"), + person: "Bob", + people: ["Charles", "Ralph", "Julia"] + }); + + var template = new dd.HtmlTemplate("
      {% include hello %}
      "); + t.is("
      Hello, Bob
      ", dd.tests.html.util.render(template, context)); + + template = new dd.HtmlTemplate('
      {% include "../../dojox/dtl/tests/templates/hello.html" %}
      '); + t.is("
      Hello, Bob
      ", dd.tests.html.util.render(template, context)); + + template = new dd.HtmlTemplate('
      {% for person in people %}
      {% include hello %}
      {% endfor %}
      '); + t.is('
      Hello, Charles
      Hello, Ralph
      Hello, Julia
      ', dd.tests.html.util.render(template, context)); + }, + function test_tag_spaceless(t){ + var dd = dojox.dtl; + + var template = new dd.HtmlTemplate("{% spaceless %}
        \n
      • Hot
      • \n\n
      • Pocket
      • \n
      {% endspaceless %}"); + t.is("
      • Hot
      • Pocket
      ", dd.tests.html.util.render(template)); + }, + function test_tag_ssi(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + hello: dojo.moduleUrl("dojox.dtl.tests.templates", "hello.html"), + person: "Bob", + people: ["Charles", "Ralph", "Julia"] + }); + + var template = new dd.HtmlTemplate("
      {% ssi hello parsed %}
      "); + t.is("
      Hello, Bob
      ", dd.tests.html.util.render(template, context)); + + template = new dd.HtmlTemplate("
      {% ssi hello %}
      "); + t.is("
      Hello, {{ person }}
      ", dd.tests.html.util.render(template, context)); + + template = new dd.HtmlTemplate('
      {% ssi "../../dojox/dtl/tests/templates/hello.html" parsed %}
      '); + t.is("
      Hello, Bob
      ", dd.tests.html.util.render(template, context)); + + template = new dd.HtmlTemplate('
      {% for person in people %}{% ssi hello parsed %} {% endfor %}
      '); + t.is("
      Hello, Charles Hello, Ralph Hello, Julia
      ", dd.tests.html.util.render(template, context)); + } + ] +); + +} diff --git a/includes/js/dojox/dtl/tests/html/util.js b/includes/js/dojox/dtl/tests/html/util.js new file mode 100644 index 0000000..b4efe5a --- /dev/null +++ b/includes/js/dojox/dtl/tests/html/util.js @@ -0,0 +1,160 @@ +if(!dojo._hasResource["dojox.dtl.tests.html.util"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tests.html.util"] = true; +dojo.provide("dojox.dtl.tests.html.util"); + +dojo.require("dojox.dtl.html"); +dojo.require("dojox.dtl.render.html"); +dojo.require("dojox.string.Builder"); + +dojox.dtl.HtmlBuffer.prototype.onClone = function(from, to){ + var clones = this._clones = this._clones || []; + + for(var i = 0, group; group = clones[i]; i++){ + for(var j = 0, item; item = group[j]; j++){ + if(item === from){ + group.push(to); + return + }else if(item === to){ + group.push(from); + return; + } + } + } + + clones.push([from, to]); +} +dojox.dtl.HtmlBuffer.prototype.onAddEvent = function(node, type, description){ + var events = this._events = this._events || []; + + var found = false; + for(var i = 0, evt; evt = events[i]; i++){ + if(evt[0] === node){ + found = true; + evt[1] = type; + evt[2] = description; + } + } + + if(!found){ + events.push([node, type, description]); + } +} + +dojox.dtl.tests.html.util.render = function(/*HtmlTemplate*/ template, /*Context*/ context) { + try { + var div = document.createElement("div"); + dojo.style(div, "visibility", "hidden"); + var attach = document.createElement("div"); + div.appendChild(attach); + dojo.body().appendChild(div); + + var buffer = template.getBuffer(); + var canvas = new dojox.dtl.render.html.Render(attach, template); + canvas.render(context, template, buffer); + var clones = buffer._clones; + var events = buffer._events; + + var first = dojox.dtl.tests.html.util.serialize(canvas.domNode, template.tokens, clones, events).toString(); + + buffer = template.getBuffer(); + buffer._clones = clones; + buffer._events = events; + canvas.render(context, template, buffer); + + var second = dojox.dtl.tests.html.util.serialize(canvas.domNode, template.tokens, clones, events).toString(); + + doh.is("Compare re-render: " + first, "Compare re-render: " + second); + return first; + } + catch(e){ + throw e; + }finally{ + div.parentNode.removeChild(div); + } +} + +dojox.dtl.tests.html.util.serialize = function(node, tokens, clones, events, output) { + var types = dojox.dtl.html.types; + clones = clones || []; + events = events || []; + + if (node.nodeType == 3) { + output.append(node.nodeValue); + }else{ + var name = node.nodeName.toLowerCase(); + + if (!output) { + output = new dojox.string.Builder(); + } + output.append("<").append(name); + + var attributes = dojo.filter(tokens, function(token){ + if(token[0] == types.attr){ + for(var i = 0, group; group = clones[i]; i++){ + // group is any set of nodes that were originally the sam + var count = 0; + for(var j = 0, item; item = group[j]; j++){ + if(item === token[1] || item === node){ + if(count++){ + // This is entered when we have 2 hits within a clone group. + // The first would be the original node + // The second would be if our current node is a clone + // of the original + return true; + } + } + } + } + } + }); + + for(var i = 0, attribute; attribute = attributes[i]; i++){ + var value = ""; + if(attribute[2] == "class"){ + value = node.className || value; + }else if(attribute[2] == "for"){ + value = node.htmlFor || value; + }else if(node.getAttribute){ + value = node.getAttribute(attribute[2], 2) || value; + if(dojo.isIE && (attribute[2] == "href" || attribute[2] == "src")){ + if(dojo.isIE){ + var hash = location.href.lastIndexOf(location.hash); + var href = location.href.substring(0, hash).split("/"); + href.pop(); + href = href.join("/") + "/"; + if(value.indexOf(href) == 0){ + value = value.replace(href, ""); + } + value = decodeURIComponent(value); + } + } + } + if(value){ + output.append(" ").append(attribute[2]).append('="').append(value.replace(/"/g, '\\"')).append('"'); + } + } + + // Deal with events + if(events){ + for(var i = 0, evt; evt = events[i]; i++){ + if(evt[0] === node){ + output.append(" ").append(evt[1]).append('="').append(evt[2]).append('"'); + } + } + } + + if(!node.childNodes.length){ + output.append("/>"); + }else{ + output.append(">"); + dojo.forEach(node.childNodes, function(node){ + dojox.dtl.tests.html.util.serialize(node, tokens, clones, events, output); + }); + output.append(""); + } + + return output; + } +} + +} diff --git a/includes/js/dojox/dtl/tests/module.js b/includes/js/dojox/dtl/tests/module.js new file mode 100644 index 0000000..57dcafb --- /dev/null +++ b/includes/js/dojox/dtl/tests/module.js @@ -0,0 +1,15 @@ +if(!dojo._hasResource["dojox.dtl.tests.module"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tests.module"] = true; +dojo.provide("dojox.dtl.tests.module"); + +try{ + dojo.require("dojox.dtl.tests.text.filter"); + dojo.require("dojox.dtl.tests.text.tag"); + dojo.require("dojox.dtl.tests.html.tag"); + dojo.require("dojox.dtl.tests.html.buffer"); + dojo.require("dojox.dtl.tests.context"); +}catch(e){ + doh.debug(e); +} + +} diff --git a/includes/js/dojox/dtl/tests/runTests.html b/includes/js/dojox/dtl/tests/runTests.html new file mode 100644 index 0000000..32338f6 --- /dev/null +++ b/includes/js/dojox/dtl/tests/runTests.html @@ -0,0 +1,9 @@ + + + + Dojox Djanto Template Language D.O.H. Unit Test Runner + + + Redirecting to D.O.H runner. + + \ No newline at end of file diff --git a/includes/js/dojox/dtl/tests/templates/hello.html b/includes/js/dojox/dtl/tests/templates/hello.html new file mode 100644 index 0000000..18e4c1a --- /dev/null +++ b/includes/js/dojox/dtl/tests/templates/hello.html @@ -0,0 +1 @@ +Hello, {{ person }} \ No newline at end of file diff --git a/includes/js/dojox/dtl/tests/templates/pocket.html b/includes/js/dojox/dtl/tests/templates/pocket.html new file mode 100644 index 0000000..f78c520 --- /dev/null +++ b/includes/js/dojox/dtl/tests/templates/pocket.html @@ -0,0 +1 @@ +{% block pocket %}Hot{% endblock %} Pocket \ No newline at end of file diff --git a/includes/js/dojox/dtl/tests/templates/pocket2.html b/includes/js/dojox/dtl/tests/templates/pocket2.html new file mode 100644 index 0000000..547f9a2 --- /dev/null +++ b/includes/js/dojox/dtl/tests/templates/pocket2.html @@ -0,0 +1 @@ +{% for item in items %}({% block pocket %}Hot{% endblock %}) {% endfor %}Pocket \ No newline at end of file diff --git a/includes/js/dojox/dtl/tests/text/filter.js b/includes/js/dojox/dtl/tests/text/filter.js new file mode 100644 index 0000000..d96f931 --- /dev/null +++ b/includes/js/dojox/dtl/tests/text/filter.js @@ -0,0 +1,740 @@ +if(!dojo._hasResource["dojox.dtl.tests.text.filter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tests.text.filter"] = true; +dojo.provide("dojox.dtl.tests.text.filter"); + +dojo.require("dojox.dtl"); +dojo.require("dojox.dtl.Context"); +dojo.require("dojox.dtl.utils.date"); +dojo.require("dojox.date.php"); +dojo.require("dojox.string.sprintf"); + +// If you update something here, update it in the HTML tests +doh.register("dojox.dtl.text.filter", + [ + function test_filter_add(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ four: 4 }); + tpl = new dd.Template('{{ four|add:"6" }}'); + t.is("10", tpl.render(context)); + context.four = "4"; + t.is("10", tpl.render(context)); + tpl = new dd.Template('{{ four|add:"six" }}'); + t.is("4", tpl.render(context)); + tpl = new dd.Template('{{ four|add:"6.6" }}'); + t.is("10", tpl.render(context)); + }, + function test_filter_addslashes(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ unslashed: "Test back slashes \\, double quotes \" and single quotes '" }) + var tpl = new dd.Template('{{ unslashed|addslashes }}'); + t.is("Test back slashes \\\\, double quotes \\\" and single quotes \\'", tpl.render(context)); + }, + function test_filter_capfirst(t){ + var dd = dojox.dtl; + + var tpl = new dd.Template('{{ uncapped|capfirst }}'); + t.is("Cap", tpl.render(new dd.Context({ uncapped: "cap" }))); + }, + function test_filter_center(t){ + var dd = dojox.dtl; + + var context = new dd.Context(); + var tpl = new dd.Template('{{ narrow|center }}'); + context.narrow = "even"; + t.is("even", tpl.render(context)); + context.narrow = "odd"; + t.is("odd", tpl.render(context)); + tpl = new dd.Template('{{ narrow|center:"5" }}'); + context.narrow = "even"; + t.is("even ", tpl.render(context)); + context.narrow = "odd"; + t.is(" odd ", tpl.render(context)); + tpl = new dd.Template('{{ narrow|center:"6" }}'); + context.narrow = "even"; + t.is(" even ", tpl.render(context)); + context.narrow = "odd"; + t.is(" odd ", tpl.render(context)); + tpl = new dd.Template('{{ narrow|center:"12" }}'); + context.narrow = "even"; + t.is(" even ", tpl.render(context)); + context.narrow = "odd"; + t.is(" odd ", tpl.render(context)); + }, + function test_filter_cut(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ uncut: "Apples and oranges" }); + var tpl = new dd.Template('{{ uncut|cut }}'); + t.is("Apples and oranges", tpl.render(context)); + tpl = new dd.Template('{{ uncut|cut:"A" }}'); + t.is("pples and oranges", tpl.render(context)); + tpl = new dd.Template('{{ uncut|cut:" " }}'); + t.is("Applesandoranges", tpl.render(context)); + tpl = new dd.Template('{{ uncut|cut:"e" }}'); + t.is("Appls and orangs", tpl.render(context)); + }, + function test_filter_date(t){ + var dd = dojox.dtl; + var context = new dd.Context({ now: new Date(2007, 0, 1), then: new Date(2007, 1, 1) }); + + var tpl = new dd.Template('{{ now|date }}'); + t.is(dojox.dtl.utils.date.format(context.now, "N j, Y"), tpl.render(context)); + + context.then = new Date(2007, 0, 1); + tpl = new dd.Template('{{ now|date:"d" }}'); + t.is("01", tpl.render(context)); + + tpl = new dd.Template('{{ now|date:"D" }}'); + t.is("Mon", tpl.render(context)); + + tpl = new dd.Template('{{ now|date:"j" }}'); + t.is("1", tpl.render(context)); + + tpl = new dd.Template('{{ now|date:"l" }}'); + t.is("Monday", tpl.render(context)); + + tpl = new dd.Template('{{ now|date:"N" }}'); + t.is("Jan.", tpl.render(context)); + + tpl = new dd.Template('{{ now|date:"S" }}'); + t.is("st", tpl.render(context)); + context.now.setDate(2); + t.is("nd", tpl.render(context)); + context.now.setDate(3); + t.is("rd", tpl.render(context)); + context.now.setDate(4); + t.is("th", tpl.render(context)); + context.now.setDate(5); + t.is("th", tpl.render(context)); + context.now.setDate(6); + t.is("th", tpl.render(context)); + context.now.setDate(7); + t.is("th", tpl.render(context)); + context.now.setDate(8); + t.is("th", tpl.render(context)); + context.now.setDate(9); + t.is("th", tpl.render(context)); + context.now.setDate(10); + t.is("th", tpl.render(context)); + context.now.setDate(11); + t.is("th", tpl.render(context)); + context.now.setDate(12); + t.is("th", tpl.render(context)); + context.now.setDate(13); + t.is("th", tpl.render(context)); + context.now.setDate(14); + t.is("th", tpl.render(context)); + context.now.setDate(15); + t.is("th", tpl.render(context)); + context.now.setDate(16); + t.is("th", tpl.render(context)); + context.now.setDate(17); + t.is("th", tpl.render(context)); + context.now.setDate(18); + t.is("th", tpl.render(context)); + context.now.setDate(19); + t.is("th", tpl.render(context)); + context.now.setDate(20); + t.is("th", tpl.render(context)); + context.now.setDate(21); + t.is("st", tpl.render(context)); + context.now.setDate(22); + t.is("nd", tpl.render(context)); + context.now.setDate(23); + t.is("rd", tpl.render(context)); + context.now.setDate(24); + t.is("th", tpl.render(context)); + context.now.setDate(25); + t.is("th", tpl.render(context)); + context.now.setDate(26); + t.is("th", tpl.render(context)); + context.now.setDate(27); + t.is("th", tpl.render(context)); + context.now.setDate(28); + t.is("th", tpl.render(context)); + context.now.setDate(29); + t.is("th", tpl.render(context)); + context.now.setDate(30); + t.is("th", tpl.render(context)); + context.now.setDate(31); + t.is("st", tpl.render(context)); + context.now.setDate(1); + + tpl = new dd.Template('{{ now|date:"w" }}'); + t.is("1", tpl.render(context)); + + tpl = new dd.Template('{{ now|date:"z" }}'); + t.is("0", tpl.render(context)); + + tpl = new dd.Template('{{ now|date:"W" }}'); + t.is("1", tpl.render(context)); + }, + function test_filter_default(t){ + var dd = dojox.dtl; + + var context = new dd.Context(); + tpl = new dd.Template('{{ empty|default }}'); + t.is("", tpl.render(context)); + tpl = new dd.Template('{{ empty|default:"full" }}'); + t.is("full", tpl.render(context)); + context.empty = "not empty"; + t.is("not empty", tpl.render(context)); + }, + function test_filter_default_if_none(t){ + var dd = dojox.dtl; + + var context = new dd.Context(); + tpl = new dd.Template('{{ empty|default_if_none }}'); + t.is("", tpl.render(context)); + tpl = new dd.Template('{{ empty|default_if_none:"full" }}'); + t.is("", tpl.render(context)); + context.empty = null; + t.is("full", tpl.render(context)); + context.empty = "not empty"; + t.is("not empty", tpl.render(context)); + }, + function test_filter_dictsort(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + fruit: [ + { name: "lemons", toString: function(){ return this.name; } }, + { name: "apples", toString: function(){ return this.name; } }, + { name: "grapes", toString: function(){ return this.name; } } + ] + }); + tpl = new dd.Template('{{ fruit|dictsort|join:"|" }}'); + t.is("lemons|apples|grapes", tpl.render(context)); + tpl = new dd.Template('{{ fruit|dictsort:"name"|join:"|" }}'); + t.is("apples|grapes|lemons", tpl.render(context)); + }, + function test_filter_dictsort_reversed(t){ + var dd = dojox.dtl; + + context = new dd.Context({ + fruit: [ + { name: "lemons", toString: function(){ return this.name; } }, + { name: "apples", toString: function(){ return this.name; } }, + { name: "grapes", toString: function(){ return this.name; } } + ] + }); + tpl = new dd.Template('{{ fruit|dictsortreversed:"name"|join:"|" }}'); + t.is("lemons|grapes|apples", tpl.render(context)); + }, + function test_filter_divisibleby(t){ + var dd = dojox.dtl; + + context = new dd.Context(); + tpl = new dd.Template('{{ 4|divisibleby:"2" }}'); + t.is("true", tpl.render(context)); + context = new dd.Context({ number: 4 }); + tpl = new dd.Template('{{ number|divisibleby:3 }}'); + t.is("false", tpl.render(context)); + }, + function test_filter_escape(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ unescaped: "Try & cover the \"major\" 'situations' at once" }); + tpl = new dd.Template('{{ unescaped|escape }}'); + t.is("Try & cover <all> the "major" 'situations' at once", tpl.render(context)); + }, + function test_filter_filesizeformat(t){ + var dd = dojox.dtl; + + var tpl = new dd.Template('{{ 1|filesizeformat }}'); + t.is("1 byte", tpl.render()); + tpl = new dd.Template('{{ 512|filesizeformat }}'); + t.is("512 bytes", tpl.render()); + tpl = new dd.Template('{{ 1024|filesizeformat }}'); + t.is("1.0 KB", tpl.render()); + tpl = new dd.Template('{{ 2048|filesizeformat }}'); + t.is("2.0 KB", tpl.render()); + tpl = new dd.Template('{{ 1048576|filesizeformat }}'); + t.is("1.0 MB", tpl.render()); + tpl = new dd.Template('{{ 1073741824|filesizeformat }}'); + t.is("1.0 GB", tpl.render()); + }, + function test_filter_first(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + fruit: [ + { name: "lemons", toString: function(){ return this.name; } }, + { name: "apples", toString: function(){ return this.name; } }, + { name: "grapes", toString: function(){ return this.name; } } + ] + }); + tpl = new dd.Template('{{ fruit|first }}'); + t.is("lemons", tpl.render(context)); + }, + function test_filter_fix_ampersands(t){ + var dd = dojox.dtl; + + var tpl = new dd.Template('{{ "One & Two"|fix_ampersands }}'); + t.is("One & Two", tpl.render()); + }, + function test_filter_floatformat(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ num1: 34.23234, num2: 34.00000 }); + var tpl = new dd.Template('{{ num1|floatformat }}'); + t.is("34.2", tpl.render(context)); + tpl = new dd.Template('{{ num2|floatformat }}'); + t.is("34", tpl.render(context)); + tpl = new dd.Template('{{ num1|floatformat:3 }}'); + t.is("34.232", tpl.render(context)); + tpl = new dd.Template('{{ num2|floatformat:3 }}'); + t.is("34.000", tpl.render(context)); + tpl = new dd.Template('{{ num1|floatformat:-3 }}'); + t.is("34.2", tpl.render(context)); + tpl = new dd.Template('{{ num2|floatformat:-3 }}'); + t.is("34", tpl.render(context)); + }, + function test_filter_get_digit(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ pi: 314159265 }); + var tpl = new dd.Template('{{ pi|get_digit:1 }}'); + t.is("3", tpl.render(context)); + tpl = new dd.Template('{{ pi|get_digit:"2" }}'); + t.is("1", tpl.render(context)); + tpl = new dd.Template('{{ pi|get_digit:0 }}'); + t.is("314159265", tpl.render(context)); + tpl = new dd.Template('{{ "nada"|get_digit:1 }}'); + t.is("0", tpl.render(context)); + }, + function test_filter_iriencode(t){ + var dd = dojox.dtl; + + var tpl = new dd.Template('{{ "http://homepage.com/~user"|urlencode|iriencode }}'); + t.is("http%3A//homepage.com/%7Euser", tpl.render()); + tpl = new dd.Template('{{ "pottedmeat@dojotoolkit.org"|iriencode }}'); + t.is("pottedmeat%40dojotoolkit.org", tpl.render()); + }, + function test_filter_join(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ items: ["foo", "bar", "baz" ]}); + var tpl = new dd.Template("{{ items|join }}"); + t.is("foo,bar,baz", tpl.render(context)); + + tpl = new dd.Template('{{ items|join:"mustard" }}'); + t.is("foomustardbarmustardbaz", tpl.render(context)); + }, + function test_filter_length(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + fruit: [ + { name: "lemons", toString: function(){ return this.name; } }, + { name: "apples", toString: function(){ return this.name; } }, + { name: "grapes", toString: function(){ return this.name; } } + ] + }); + tpl = new dd.Template('{{ fruit|length }}'); + t.is("3", tpl.render(context)); + tpl = new dd.Template('{{ fruit|first|length }}'); + t.is("6", tpl.render(context)); + }, + function test_filter_length_is(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + fruit: [ + { name: "lemons", toString: function(){ return this.name; } }, + { name: "apples", toString: function(){ return this.name; } }, + { name: "grapes", toString: function(){ return this.name; } } + ] + }); + tpl = new dd.Template('{{ fruit|length_is:"3" }}'); + t.is("true", tpl.render(context)); + tpl = new dd.Template('{{ fruit|length_is:"4" }}'); + t.is("false", tpl.render(context)); + }, + function test_filter_linebreaks(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ unbroken: "This is just\r\n\n\ra bunch\nof text\n\n\nand such" }); + tpl = new dd.Template('{{ unbroken|linebreaks }}'); + t.is("

      This is just

      \n\n

      a bunch
      of text

      \n\n

      and such

      ", tpl.render(context)); + }, + function test_filter_linebreaksbr(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ unbroken: "This is just\r\n\n\ra bunch\nof text\n\n\nand such" }); + tpl = new dd.Template('{{ unbroken|linebreaksbr }}'); + t.is("This is just

      a bunch
      of text


      and such", tpl.render(context)); + }, + function test_filter_linenumbers(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ lines: "One\nTwo\nThree\nFour\n" }); + var tpl = new dd.Template('{{ lines|linenumbers }}'); + t.is("1. One\n2. Two\n3. Three\n4. Four\n5. ", tpl.render(context)); + }, + function test_filter_ljust(t){ + var dd = dojox.dtl; + + var context = new dd.Context(); + var tpl = new dd.Template('{{ narrow|ljust }}'); + context.narrow = "even"; + t.is("even", tpl.render(context)); + context.narrow = "odd"; + t.is("odd", tpl.render(context)); + tpl = new dd.Template('{{ narrow|ljust:"5" }}'); + context.narrow = "even"; + t.is("even ", tpl.render(context)); + context.narrow = "odd"; + t.is("odd ", tpl.render(context)); + tpl = new dd.Template('{{ narrow|ljust:"6" }}'); + context.narrow = "even"; + t.is("even ", tpl.render(context)); + context.narrow = "odd"; + t.is("odd ", tpl.render(context)); + tpl = new dd.Template('{{ narrow|ljust:"12" }}'); + context.narrow = "even"; + t.is("even ", tpl.render(context)); + context.narrow = "odd"; + t.is("odd ", tpl.render(context)); + }, + function test_filter_lower(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ mixed: "MiXeD" }); + var tpl = new dd.Template('{{ mixed|lower }}'); + t.is("mixed", tpl.render(context)); + }, + function test_filter_make_list(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ word: "foo", number: 314159265, arr: ["first", "second"], obj: {first: "first", second: "second"} }); + var tpl = new dd.Template('{{ word|make_list|join:"|" }} {{ number|make_list|join:"|" }} {{ arr|make_list|join:"|" }} {{ obj|make_list|join:"|" }}'); + t.is("f|o|o 3|1|4|1|5|9|2|6|5 first|second first|second", tpl.render(context)); + }, + function test_filter_phone2numeric(t){ + var dd = dojox.dtl; + + tpl = new dd.Template('{{ "1-800-pottedmeat"|phone2numeric }}'); + t.is("1-800-7688336328", tpl.render()); + }, + function test_filter_pluralize(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ animals: ["bear", "cougar", "aardvark"] }); + var tpl = new dd.Template('{{ animals|length }} animal{{ animals|length|pluralize }}'); + t.is("3 animals", tpl.render(context)); + context.animals = ["bear"]; + t.is("1 animal", tpl.render(context)); + context = new dd.Context({ fairies: ["tinkerbell", "Andy Dick" ]}); + tpl = new dd.Template('{{ fairies|length }} fair{{ fairies|length|pluralize:"y,ies" }}'); + t.is("2 fairies", tpl.render(context)); + context.fairies.pop(); + t.is("1 fairy", tpl.render(context)); + }, + function test_filter_pprint(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ animals: ["bear", "cougar", "aardvark"] }); + tpl = new dd.Template("{{ animals|pprint }}"); + t.is('["bear","cougar","aardvark"]', tpl.render(context)); + }, + function test_filter_random(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + fruit: [ + { name: "lemons", toString: function(){ return this.name; } }, + { name: "apples", toString: function(){ return this.name; } }, + { name: "grapes", toString: function(){ return this.name; } } + ] + }); + tpl = new dd.Template('{{ fruit|random }}'); + result = tpl.render(context); + t.t(result == "lemons" || result == "apples" || result == "grapes"); + var different = false; + for(var i = 0; i < 10; i++){ + // Check to see if it changes + if(result != tpl.render(context) && result == "lemons" || result == "apples" || result == "grapes"){ + different = true; + break; + } + } + t.t(different); + }, + function test_filter_removetags(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ tagged: "I'm gonna do something with the filter" }); + tpl = new dd.Template('{{ tagged|removetags:"script " }}'); + t.is("I'm gonna do something evil with the filter", tpl.render(context)); + }, + function test_filter_rjust(t){ + var dd = dojox.dtl; + + var context = new dd.Context(); + var tpl = new dd.Template('{{ narrow|rjust }}'); + context.narrow = "even"; + t.is("even", tpl.render(context)); + context.narrow = "odd"; + t.is("odd", tpl.render(context)); + tpl = new dd.Template('{{ narrow|rjust:"5" }}'); + context.narrow = "even"; + t.is(" even", tpl.render(context)); + context.narrow = "odd"; + t.is(" odd", tpl.render(context)); + tpl = new dd.Template('{{ narrow|rjust:"6" }}'); + context.narrow = "even"; + t.is(" even", tpl.render(context)); + context.narrow = "odd"; + t.is(" odd", tpl.render(context)); + tpl = new dd.Template('{{ narrow|rjust:"12" }}'); + context.narrow = "even"; + t.is(" even", tpl.render(context)); + context.narrow = "odd"; + t.is(" odd", tpl.render(context)); + }, + function test_filter_slice(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + fruit: [ + { name: "lemons", toString: function(){ return this.name; } }, + { name: "apples", toString: function(){ return this.name; } }, + { name: "grapes", toString: function(){ return this.name; } } + ] + }); + tpl = new dd.Template('{{ fruit|slice:":1"|join:"|" }}'); + t.is("lemons", tpl.render(context)); + tpl = new dd.Template('{{ fruit|slice:"1"|join:"|" }}'); + t.is("apples|grapes", tpl.render(context)); + tpl = new dd.Template('{{ fruit|slice:"1:3"|join:"|" }}'); + t.is("apples|grapes", tpl.render(context)); + tpl = new dd.Template('{{ fruit|slice:""|join:"|" }}'); + t.is("lemons|apples|grapes", tpl.render(context)); + tpl = new dd.Template('{{ fruit|slice:"-1"|join:"|" }}'); + t.is("grapes", tpl.render(context)); + tpl = new dd.Template('{{ fruit|slice:":-1"|join:"|" }}'); + t.is("lemons|apples", tpl.render(context)); + tpl = new dd.Template('{{ fruit|slice:"-2:-1"|join:"|" }}'); + t.is("apples", tpl.render(context)); + }, + function test_filter_slugify(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ unslugged: "Apples and oranges()"}); + tpl = new dd.Template('{{ unslugged|slugify }}'); + t.is("apples-and-oranges", tpl.render(context)); + }, + function test_filter_stringformat(t){ + var dd = dojox.dtl; + + var tpl = new dd.Template('{{ 42|stringformat:"7.3f" }}'); + t.is(" 42.000", tpl.render()); + }, + function test_filter_striptags(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ tagged: "I'm gonna do something with the filter" }); + tpl = new dd.Template('{{ tagged|striptags }}'); + t.is("I'm gonna do something evil with the filter", tpl.render(context)); + }, + function test_filter_time(t){ + var dd = dojox.dtl; + var context = new dd.Context({ now: new Date(2007, 0, 1) }); + + tpl = new dd.Template('{{ now|time }}'); + t.is(dojox.dtl.utils.date.format(context.now, "P"), tpl.render(context)); + }, + function test_filter_timesince(t){ + var dd = dojox.dtl; + var context = new dd.Context({ now: new Date(2007, 0, 1), then: new Date(2007, 1, 1) }); + + tpl = new dd.Template('{{ now|timesince:then }}'); + t.is("1 month", tpl.render(context)); + context.then = new Date(2007, 0, 5); + t.is("4 days", tpl.render(context)); + context.then = new Date(2007, 0, 17); + t.is("2 weeks", tpl.render(context)); + context.then = new Date(2008, 1, 1); + t.is("1 year", tpl.render(context)); + }, + function test_filter_timeuntil(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ now: new Date(2007, 0, 1), then: new Date(2007, 1, 1) }); + var tpl = new dd.Template('{{ now|timeuntil:then }}'); + t.is("1 month", tpl.render(context)); + context.then = new Date(2007, 0, 5); + t.is("4 days", tpl.render(context)); + context.then = new Date(2007, 0, 17); + t.is("2 weeks", tpl.render(context)); + context.then = new Date(2008, 1, 1); + t.is("1 year", tpl.render(context)); + }, + function test_filter_title(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ name: "potted meat" }); + var tpl = new dd.Template("{{ name|title }}"); + t.is("Potted Meat", tpl.render(context)); + + context.name = "What's going on?"; + t.is("What's Going On?", tpl.render(context)); + + context.name = "use\nline\nbREAKs\tand tabs"; + t.is("Use\nLine\nBreaks\tAnd Tabs", tpl.render(context)); + }, + function test_filter_truncatewords(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ word: "potted meat writes a lot of tests" }); + var tpl = new dd.Template("{{ word|truncatewords }}"); + t.is(context.word, tpl.render(context)); + + tpl = new dd.Template('{{ word|truncatewords:"1" }}'); + t.is("potted", tpl.render(context)); + + tpl = new dd.Template('{{ word|truncatewords:"2" }}'); + t.is("potted meat", tpl.render(context)); + + tpl = new dd.Template('{{ word|truncatewords:20" }}'); + t.is(context.word, tpl.render(context)); + + context.word = "potted \nmeat \nwrites a lot of tests"; + tpl = new dd.Template('{{ word|truncatewords:"3" }}'); + t.is("potted \nmeat \nwrites", tpl.render(context)); + }, + function test_filter_truncatewords_html(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + body: "Test a string that ends inside a tag with different args", + size: 2 + }) + var tpl = new dd.Template('{{ body|truncatewords_html:size }}'); + t.is("Test a ...", tpl.render(context)); + context.size = 4; + t.is("Test a string that ...", tpl.render(context)); + context.size = 6; + t.is("Test a string that ends inside ...", tpl.render(context)); + }, + function test_filter_unordered_list(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ states: ["States", [["Kansas", [["Lawrence", []], ["Topeka", []]]], ["Illinois", []]]] }); + tpl = new dd.Template('{{ states|unordered_list }}'); + t.is("\t
    • States\n\t
        \n\t\t
      • Kansas\n\t\t
          \n\t\t\t
        • Lawrence
        • \n\t\t\t
        • Topeka
        • \n\t\t
        \n\t\t
      • \n\t\t
      • Illinois
      • \n\t
      \n\t
    • ", tpl.render(context)); + }, + function test_filter_upper(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ mixed: "MiXeD" }); + var tpl = new dd.Template('{{ mixed|upper }}'); + t.is("MIXED", tpl.render(context)); + }, + function test_filter_urlencode(t){ + var dd = dojox.dtl; + + var tpl = new dd.Template('{{ "http://homepage.com/~user"|urlencode }}'); + t.is("http%3A//homepage.com/%7Euser", tpl.render()); + }, + function test_filter_urlize(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + body: "My favorite websites are www.televisionwithoutpity.com, http://daringfireball.net and you can email me at pottedmeat@sitepen.com" + }); + var tpl = new dd.Template("{{ body|urlize }}"); + t.is('My favorite websites are www.televisionwithoutpity.com http://daringfireball.net and you can email me at pottedmeat@sitepen.com', tpl.render(context)); + }, + function test_filter_urlizetrunc(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + body: "My favorite websites are www.televisionwithoutpity.com, http://daringfireball.net and you can email me at pottedmeat@sitepen.com" + }); + var tpl = new dd.Template("{{ body|urlizetrunc }}"); + t.is('My favorite websites are www.televisionwithoutpity.com http://daringfireball.net and you can email me at pottedmeat@sitepen.com', tpl.render(context)); + tpl = new dd.Template('{{ body|urlizetrunc:"2" }}'); + t.is('My favorite websites are www.televisionwithoutpity.com http://daringfireball.net and you can email me at pottedmeat@sitepen.com', tpl.render(context)); + tpl = new dd.Template('{{ body|urlizetrunc:"10" }}'); + t.is('My favorite websites are www.tel... http://... and you can email me at pottedmeat@sitepen.com', tpl.render(context)); + }, + function test_filter_wordcount(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + food: "Hot Pocket" + }); + var tpl = new dd.Template("{{ food|wordcount }}"); + t.is("2", tpl.render(context)); + context.food = ""; + t.is("0", tpl.render(context)); + context.food = "A nice barbecue, maybe a little grilled veggies, some cole slaw."; + t.is("11", tpl.render(context)); + }, + function test_filter_wordwrap(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + body: "shrimp gumbo, shrimp pie, shrimp scampi, shrimp stew, fried shrimp, baked shrimp, shrimp o grotten, grilled shrimp, shrimp on a stick, shrimp salad, shrimp pop overs, shrimp cake, shrimp legs, shrimp stuffed eggs, shrimp cre oll, shrimp soup, creamed shrimp on toast, shrimp crapes, shrimply good crescent rolls, shrimp pizza, scalloped shrimp, boiled shrimp, shrimp cocktail" + }); + var tpl = new dd.Template("{{ body|wordwrap }}"); + t.is(context.body, tpl.render(context)); + tpl = new dd.Template("{{ body|wordwrap:width }}"); + context.width = 10; + t.is("shrimp\ngumbo,\nshrimp\npie,\nshrimp\nscampi,\nshrimp\nstew,\nfried\nshrimp,\nbaked\nshrimp,\nshrimp o\ngrotten,\ngrilled\nshrimp,\nshrimp on\na stick,\nshrimp\nsalad,\nshrimp pop\novers,\nshrimp\ncake,\nshrimp\nlegs,\nshrimp\nstuffed\neggs,\nshrimp cre\noll,\nshrimp\nsoup,\ncreamed\nshrimp on\ntoast,\nshrimp\ncrapes,\nshrimply\ngood\ncrescent\nrolls,\nshrimp\npizza,\nscalloped\nshrimp,\nboiled\nshrimp,\nshrimp\ncocktail", tpl.render(context)); + tpl = new dd.Template('{{ body|wordwrap:"80" }}'); + t.is("shrimp gumbo, shrimp pie, shrimp scampi, shrimp stew, fried shrimp, baked\nshrimp, shrimp o grotten, grilled shrimp, shrimp on a stick, shrimp salad,\nshrimp pop overs, shrimp cake, shrimp legs, shrimp stuffed eggs, shrimp cre oll,\nshrimp soup, creamed shrimp on toast, shrimp crapes, shrimply good crescent\nrolls, shrimp pizza, scalloped shrimp, boiled shrimp, shrimp cocktail", tpl.render(context)); + }, + function test_filter_yesno(t){ + var dd = dojox.dtl; + + var context = new dd.Context(); + tpl = new dd.Template('{{ true|yesno }}'); + t.is("yes", tpl.render(context)); + context = new dd.Context({ test: "value" }); + tpl = new dd.Template('{{ test|yesno }}'); + t.is("yes", tpl.render(context)); + tpl = new dd.Template('{{ false|yesno }}'); + t.is("no", tpl.render(context)); + tpl = new dd.Template('{{ null|yesno }}'); + t.is("maybe", tpl.render(context)); + tpl = new dd.Template('{{ true|yesno:"bling,whack,soso" }}'); + t.is("bling", tpl.render(context)); + context = new dd.Context({ test: "value" }); + tpl = new dd.Template('{{ test|yesno:"bling,whack,soso" }}'); + t.is("bling", tpl.render(context)); + tpl = new dd.Template('{{ false|yesno:"bling,whack,soso" }}'); + t.is("whack", tpl.render(context)); + tpl = new dd.Template('{{ null|yesno:"bling,whack,soso" }}'); + t.is("soso", tpl.render(context)); + tpl = new dd.Template('{{ null|yesno:"bling,whack" }}'); + t.is("whack", tpl.render(context)); + }, + function test_filter_contrib_key(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + headers: ["action", "type"], + items: [ + { + action: "eat", + type: "apple", + }, + { + action: "mash", + type: "banana" + } + ] + }); + + var tpl = new dd.Template("{% load dojox.dtl.contrib.objects %}
        {% for item in items %}
        • {% for header in headers %}
        • {{ header }}: {{ item|key:header }}
        • {% endfor %}
      • {% endfor %}
      "); + t.is('
        • action: eat
        • type: apple
        • action: mash
        • type: banana
      ', tpl.render(context)); + } + ] +); + +} diff --git a/includes/js/dojox/dtl/tests/text/load.js b/includes/js/dojox/dtl/tests/text/load.js new file mode 100644 index 0000000..b4c7472 --- /dev/null +++ b/includes/js/dojox/dtl/tests/text/load.js @@ -0,0 +1,6 @@ +if(!dojo._hasResource["dojox.dtl.tests.text.load"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tests.text.load"] = true; +dojo.provide("dojox.dtl.tests.text.load"); +// Test for the {% load %} tag + +} diff --git a/includes/js/dojox/dtl/tests/text/tag.js b/includes/js/dojox/dtl/tests/text/tag.js new file mode 100644 index 0000000..7abbc43 --- /dev/null +++ b/includes/js/dojox/dtl/tests/text/tag.js @@ -0,0 +1,480 @@ +if(!dojo._hasResource["dojox.dtl.tests.text.tag"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tests.text.tag"] = true; +dojo.provide("dojox.dtl.tests.text.tag"); + +dojo.require("dojox.dtl"); +dojo.require("dojox.dtl.Context"); + +doh.register("dojox.dtl.text.tag", + [ + function test_tag_block_and_extends(t){ + var dd = dojox.dtl; + + // Simple (messy) string-based extension + var template = new dd.Template('{% extends "../../dojox/dtl/tests/templates/pocket.html" %}{% block pocket %}Simple{% endblock %}'); + t.is("Simple Pocket", template.render()); + + // Variable replacement + var context = new dd.Context({ + parent: "../../dojox/dtl/tests/templates/pocket.html" + }) + template = new dd.Template('{% extends parent %}{% block pocket %}Variabled{% endblock %}'); + t.is("Variabled Pocket", template.render(context)); + + // Nicer dojo.moduleUrl and variable based extension + context.parent = dojo.moduleUrl("dojox.dtl.tests.templates", "pocket.html"); + template = new dd.Template('{% extends parent %}{% block pocket %}Slightly More Advanced{% endblock %}'); + t.is("Slightly More Advanced Pocket", template.render(context)); + + // dojo.moduleUrl with support for more variables. + // This is important for HTML templates where the "shared" flag will be important. + context.parent = { + url: dojo.moduleUrl("dojox.dtl.tests.templates", "pocket.html") + } + template = new dd.Template('{% extends parent %}{% block pocket %}Super{% endblock %}'); + t.is("Super Pocket", template.render(context)); + }, + function test_tag_block(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + parent: dojo.moduleUrl("dojox.dtl.tests.templates", "pocket2.html"), + items: ["apple", "banana", "lemon" ] + }); + + var template = new dd.Template("{% extends parent %}{% block pocket %}My {{ item }}{% endblock %}"); + t.is("(My apple) (My banana) (My lemon) Pocket", template.render(context)); + }, + function test_tag_comment(t){ + var dd = dojox.dtl; + + var template = new dd.Template('Hot{% comment %}Make me disappear{% endcomment %} Pocket'); + t.is("Hot Pocket", template.render()); + + var found = false; + try{ + template = new dd.Template('Hot{% comment %}Make me disappear Pocket'); + }catch(e){ + t.is("Unclosed tag found when looking for endcomment", e.message); + found = true; + } + t.t(found); + }, + function test_tag_cycle(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + items: ["apple", "banana", "lemon"], + unplugged: "Torrey" + }); + var template = new dd.Template("{% for item in items %}{% cycle 'Hot' 'Diarrhea' unplugged 'Extra' %} Pocket. {% endfor %}"); + t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. ", template.render(context)); + // Make sure that it doesn't break on re-render + t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. ", template.render(context)); + + // Test repeating the loop + context.items.push("guava", "mango", "pineapple"); + t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. Extra Pocket. Hot Pocket. Diarrhea Pocket. ", template.render(context)); + + // Repeat the above tests for the old style + // ======================================== + context.items = context.items.slice(0, 3); + template = new dd.Template("{% for item in items %}{% cycle Hot,Diarrhea,Torrey,Extra %} Pocket. {% endfor %}"); + t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. ", template.render(context)); + // Make sure that it doesn't break on re-render + t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. ", template.render(context)); + + // Test repeating the loop + context.items.push("guava", "mango", "pineapple"); + t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. Extra Pocket. Hot Pocket. Diarrhea Pocket. ", template.render(context)); + + // Now test outside of the for loop + // ================================ + context = new dojox.dtl.Context({ unplugged: "Torrey" }); + template = new dd.Template("{% cycle 'Hot' 'Diarrhea' unplugged 'Extra' as steakum %} Pocket. {% cycle steakum %} Pocket. {% cycle steakum %} Pocket."); + t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket.", template.render(context)); + + template = new dd.Template("{% cycle 'Hot' 'Diarrhea' unplugged 'Extra' as steakum %} Pocket. {% cycle steakum %} Pocket. {% cycle steakum %} Pocket. {% cycle steakum %} Pocket. {% cycle steakum %} Pocket. {% cycle steakum %} Pocket."); + t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. Extra Pocket. Hot Pocket. Diarrhea Pocket.", template.render(context)); +//t.t(false) + // Test for nested objects + context.items = { + list: ["apple", "banana", "lemon"] + }; + template = new dd.Template("{% for item in items.list %}{% cycle 'Hot' 'Diarrhea' unplugged 'Extra' %} Pocket. {% endfor %}"); + t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. ", template.render(context)); + // Make sure that it doesn't break on re-render + t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. ", template.render(context)); + }, + function test_tag_debug(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + items: ["apple", "banana", "lemon"], + unplugged: "Torrey" + }); + var template = new dd.Template("{% debug %}"); + t.is('items: ["apple","banana","lemon"]\n\nunplugged: "Torrey"\n\n', template.render(context)); + }, + function test_tag_filter(t){ + var dd = dojox.dtl; + + var template = new dd.Template('{% filter lower|center:"15" %}Hot Pocket{% endfilter %}'); + t.is(" hot pocket ", template.render()); + }, + function test_tag_firstof(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + found: "unicorn" + }); + + var template = new dd.Template("{% firstof one two three four found %}"); + t.is("unicorn", template.render(context)); + + context.four = null; + t.is("null", template.render(context)); + + context.three = false; + t.is("false", template.render(context)); + }, + function test_tag_for(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + items: ["apple", "banana", "lemon"] + }); + var template = new dd.Template("{% for item in items %}
    • {{ item }}
    • {% endfor %}"); + t.is("
    • apple
    • banana
    • lemon
    • ", template.render(context)); + + template = new dd.Template("{% for item in items reversed %}
    • {{ item }}
    • {% endfor %}"); + t.is("
    • lemon
    • banana
    • apple
    • ", template.render(context)); + + context.items = { + apple: "Red Delicious", + banana: "Cavendish", + lemon: "Citrus" + }; + template = new dd.Template("{% for key, value in items.items %}
    • {{ value }} {{ key|title }}
    • {% endfor %}"); + t.is("
    • Red Delicious Apple
    • Cavendish Banana
    • Citrus Lemon
    • ", template.render(context)); + + // The same thing above, but using "zipped" sets + context.items = [ + ["apple", "Red Delicious", 1.99], + ["banana", "Cavendish", 0.49], + ["lemon", "Citrus", 0.29] + ]; + template = new dd.Template("{% for fruit, type, price in items %}
    • {{ type }} {{ fruit|title }} costs ${{ price}}
    • {% endfor %}"); + t.is("
    • Red Delicious Apple costs $1.99
    • Cavendish Banana costs $0.49
    • Citrus Lemon costs $0.29
    • ", template.render(context)); + + template = new dd.Template("{% for fruit, type, price in items reversed %}
    • {{ type }} {{ fruit|title }} costs ${{ price}}
    • {% endfor %}"); + t.is("
    • Citrus Lemon costs $0.29
    • Cavendish Banana costs $0.49
    • Red Delicious Apple costs $1.99
    • ", template.render(context)); + + // Now to create some errors + var found = false; + try { + template = new dd.Template("{% for item initems %}
    • {{ item }}
    • {% endfor %}"); + }catch(e){ + found = true; + t.is("'for' statements should have at least four words: for item initems", e.message); + } + t.t(found); + + found = false; + try { + template = new dd.Template("{% for item ni items %}
    • {{ item }}
    • {% endfor %}"); + }catch(e){ + found = true; + t.is("'for' tag received an invalid argument: for item ni items", e.message); + } + t.t(found); + + found = false; + try { + template = new dd.Template("{% for my item in items %}
    • {{ item }}
    • {% endfor %}"); + }catch(e){ + found = true; + t.is("'for' tag received an invalid argument: for my item in items", e.message); + } + t.t(found); + }, + function test_tag_if(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + jokes: { + hot_pockets: true, + unicycles: true, + bacon: true + } + }); + var template = new dd.Template("Comedian is {% if jokes.hot_pockets and jokes.unicycles and jokes.bacon %}funny{% else %}not funny{% endif %}"); + t.is("Comedian is funny", template.render(context)); + + context.jokes.unicycles = false; + t.is("Comedian is not funny", template.render(context)); + + context.comedians = { + hedberg: true, + gaffigan: true, + cook: true + }; + template = new dd.Template("Show will be {% if comedians.hedberg or comedians.gaffigan %}worth seeing{% else %}not worth seeing{% endif %}"); + t.is("Show will be worth seeing", template.render(context)); + + // NOTE: "and" is implied by nesting. eg {% if sunny %}{% if windy %}It's Sunny and Windy{% endif %}{% endif %} + // Not mixing ands and ors allows for MUCH faster rendering + template = new dd.Template("Show will {% if comedians.hedberg or comedians.gaffigan %}{% if comedians.cook %}not {% endif %}be worth seeing{% else %}not be worth seeing{% endif %}"); + t.is("Show will not be worth seeing", template.render(context)); + + context.comedians.cook = false; + t.is("Show will be worth seeing", template.render(context)); + + template = new dd.Template("Show will be {% if comedians.hedberg and comedians.gaffigan and not comedians.cook %}AWESOME{% else %}almost awesome{% endif %}"); + t.is("Show will be AWESOME", template.render(context)); + + context.comedians.cook = true; + t.is("Show will be almost awesome", template.render(context)); + + // Now we test for errors. + var found = false; + try { + template = new dd.Template("Show will be {% if comedians.hedberg or comedians.gaffigan and not comedians.cook %}worth seeing{% else %}not worth seeing{% endif %}"); + }catch(e){ + found = true; + t.is("'if' tags can't mix 'and' and 'or'", e.message); + } + t.t(found); + }, + function test_tag_ifchanged(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + year: 2008, + days: [ + new Date(2008, 0, 12), + new Date(2008, 0, 28), + new Date(2008, 1, 1), + new Date(2008, 1, 1), + new Date(2008, 1, 1) + ] + }); + + var template = new dd.Template("

      Archive for {{ year }}

      "+ +"{% for date in days %}"+ +'{% ifchanged %}

      {{ date|date:"F" }}

      {% endifchanged %}'+ +'{{ date|date:\'j\' }}'+ +"{% endfor %}"); + t.is('

      Archive for 2008

      '+ +'

      January

      '+ +'12'+ +'28'+ +'

      February

      '+ +'1'+ +'1'+ +'1', template.render(context)); + + template = new dd.Template('{% for date in days %}'+ +'{% ifchanged date.date %} {{ date.date }} {% endifchanged %}'+ +'{% ifchanged date.hour date.date %}'+ +'{{ date.hour }}'+ +'{% endifchanged %}'+ +'{% endfor %}'); + t.is(' 2008-01-12 0 2008-01-28 0 2008-02-01 0', template.render(context)); + }, + function test_tag_ifequal(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + user: { + id: 314 + }, + comment: { + user_id: 314 + } + }); + + var template = new dd.Template("{% ifequal user.id comment.user_id %}You posted this{% endifequal %}"); + t.is("You posted this", template.render(context)); + + context.user.id = 313; + t.is("", template.render(context)); + + // Errors + var found = false; + try { + template = new dd.Template("{% ifequal user.id %}You posted this{% endifequal %}"); + }catch(e){ + found = true; + t.is("ifequal takes two arguments", e.message); + } + t.t(found); + + found = false; + try { + template = new dd.Template("{% ifequal user.id comment.user_id %}You posted this{% endif %}"); + }catch(e){ + found = true; + t.is("No tag found for endif", e.message); + } + t.t(found); + }, + function test_tag_ifnotequal(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + favorite: "hedberg", + comedian: "cook" + }); + + var template = new dd.Template("{% ifnotequal favorite comedian %}Not your favorite{% else %}Your favorite{% endifnotequal %}"); + t.is("Not your favorite", template.render(context)); + + context.comedian = "hedberg"; + t.is("Your favorite", template.render(context)); + }, + function test_tag_include(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + hello: dojo.moduleUrl("dojox.dtl.tests.templates", "hello.html"), + person: "Bob", + people: ["Charles", "Ralph", "Julia"] + }); + + var template = new dd.Template("{% include hello %}"); + t.is("Hello, Bob", template.render(context)); + + template = new dd.Template('{% include "../../dojox/dtl/tests/templates/hello.html" %}'); + t.is("Hello, Bob", template.render(context)); + + template = new dd.Template('{% for person in people %}{% include hello %} {% endfor %}'); + t.is("Hello, Charles Hello, Ralph Hello, Julia ", template.render(context)); + }, + function test_tag_load(t){ + t.f(dojox.dtl.tests.text.load); + new dojox.dtl.Template("{% load dojox.dtl.tests.text.load %}"); + t.t(dojox.dtl.tests.text.load); + }, + function test_tag_now(t){ + var dd = dojox.dtl; + + var template = new dd.Template('It is {% now "jS F Y H:i" %}'); + t.t(template.render().match(/^It is \d{1,2}[a-z]{2} [A-Z][a-z]+ [0-9]{4,} \d{2}:\d{2}$/)); + + template = new dd.Template('It is the {% now "jS \\o\\f F" %}'); + t.t(template.render().match(/^It is the \d{1,2}[a-z]{2} of [A-Z][a-z]+$/)); + + template = new dd.Template("It is the {% now 'jS \\o\\f F' %}"); + t.t(template.render().match(/^It is the \d{1,2}[a-z]{2} of [A-Z][a-z]+$/)); + + var found = false; + try{ + template = new dd.Template("It is the {% now 'jS \\o\\f F %}"); + }catch(e){ + found = true; + t.is("'now' statement takes one argument", e.message); + } + t.t(found); + + found = false; + try{ + template = new dd.Template('It is the {% now "jS \\o\\f F %}'); + }catch(e){ + found = true; + t.is("'now' statement takes one argument", e.message); + } + t.t(found); + }, + function test_tag_regroup(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + people: [ + { firstName: "Bill", lastName: "Clinton", gender: "Male" }, + { firstName: "Margaret", lastName: "Thatcher", gender: "Female" }, + { firstName: "Path", lastName: "Smith", gender: "Unkown" }, + { firstName: "Condoleezza", lastName: "Rice", gender: "Female" }, + { firstName: "George", lastName: "Bush", gender: "Male" } + ] + }); + + var template = new dd.Template("{% regroup people|dictsort:'gender' by gender as grouped %}
        {% for group in grouped %}
      • {{ group.grouper }}
          {% for item in group.list %}
        • {{ item.firstName }} {{ item.lastName }}
        • {% endfor %}
      • {% endfor %}
      "); + t.t(template.render(context).match(new RegExp("^
      • Female
        • (Condoleezza Rice|Margaret Thatcher)
        • (Condoleezza Rice|Margaret Thatcher)
      • Male
        • (Bill Clinton|George Bush)
        • (Bill Clinton|George Bush)
      • Unkown
        • Path Smith
      $"))); + }, + function test_tag_spaceless(t){ + var dd = dojox.dtl; + + var template = new dd.Template("{% spaceless %}
        \n
      • Hot
      • \n\n
      • Pocket
      • \n
      {% endspaceless %}"); + t.is("
      • Hot
      • Pocket
      ", template.render()); + }, + function test_tag_ssi(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + hello: dojo.moduleUrl("dojox.dtl.tests.templates", "hello.html"), + person: "Bob", + people: ["Charles", "Ralph", "Julia"] + }); + + var template = new dd.Template("{% ssi hello parsed %}"); + t.is("Hello, Bob", template.render(context)); + + template = new dd.Template("{% ssi hello %}"); + t.is("Hello, {{ person }}", template.render(context)); + + template = new dd.Template('{% ssi "../../dojox/dtl/tests/templates/hello.html" parsed %}'); + t.is("Hello, Bob", template.render(context)); + + template = new dd.Template('{% for person in people %}{% ssi hello parsed %} {% endfor %}'); + t.is("Hello, Charles Hello, Ralph Hello, Julia ", template.render(context)); + }, + function test_tag_templatetag(t){ + var dd = dojox.dtl; + + var template = new dd.Template("{% templatetag openblock %}"); + t.is("{%", template.render()); + template = new dd.Template("{% templatetag closeblock %}"); + t.is("%}", template.render()); + template = new dd.Template("{% templatetag openvariable %}"); + t.is("{{", template.render()); + template = new dd.Template("{% templatetag closevariable %}"); + t.is("}}", template.render()); + template = new dd.Template("{% templatetag openbrace %}"); + t.is("{", template.render()); + template = new dd.Template("{% templatetag closebrace %}"); + t.is("}", template.render()); + template = new dd.Template("{% templatetag opencomment %}"); + t.is("{#", template.render()); + template = new dd.Template("{% templatetag closecomment %}"); + t.is("#}", template.render()); + }, + function test_tag_widthratio(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + this_value: 175, + max_value: 200 + }); + + var template = new dd.Template(''); + t.is('', template.render(context)); + }, + function test_tag_with(t){ + var dd = dojox.dtl; + + var context = new dd.Context({ + person: { + someSqlMethod: function(){ + return 4815162342; + } + } + }); + + var template = new dd.Template('{% with person.someSqlMethod as total %}{{ total }} object{{ total|pluralize }}{% endwith %}') + t.is("4815162342 objects", template.render(context)); + } + ] +); + +} diff --git a/includes/js/dojox/dtl/utils/date.js b/includes/js/dojox/dtl/utils/date.js new file mode 100644 index 0000000..65f8cb5 --- /dev/null +++ b/includes/js/dojox/dtl/utils/date.js @@ -0,0 +1,72 @@ +if(!dojo._hasResource["dojox.dtl.utils.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.utils.date"] = true; +dojo.provide("dojox.dtl.utils.date"); + +dojo.require("dojox.date.php"); + +dojox.dtl.utils.date.DateFormat = function(/*String*/ format){ + dojox.date.php.DateFormat.call(this, format); +} +dojo.extend(dojox.dtl.utils.date.DateFormat, dojox.date.php.DateFormat.prototype, { + f: function(){ + // summary: + // Time, in 12-hour hours and minutes, with minutes left off if they're zero. + // description: + // Examples: '1', '1:30', '2:05', '2' + // Proprietary extension. + return (!this.date.getMinutes()) ? this.g() : this.g() + ":" + this.i(); + }, + N: function(){ + // summary: Month abbreviation in Associated Press style. Proprietary extension. + return dojox.dtl.utils.date._months_ap[this.date.getMonth()]; + }, + P: function(){ + // summary: + // Time, in 12-hour hours, minutes and 'a.m.'/'p.m.', with minutes left off + // if they're zero and the strings 'midnight' and 'noon' if appropriate. + // description: + // Examples: '1 a.m.', '1:30 p.m.', 'midnight', 'noon', '12:30 p.m.' + // Proprietary extension. + if(!this.date.getMinutes() && !this.date.getHours()) return 'midnight'; + if(!this.date.getMinutes() && this.date.getHours() == 12) return 'noon'; + return this.f() + " " + this.a(); + } +}); + +dojo.mixin(dojox.dtl.utils.date, { + format: function(/*Date*/ date, /*String*/ format){ + var df = new dojox.dtl.utils.date.DateFormat(format); + return df.format(date); + }, + timesince: function(d, now){ + // summary: + // Takes two datetime objects and returns the time between then and now + // as a nicely formatted string, e.g "10 minutes" + // description: + // Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since + if(!(d instanceof Date)){ + d = new Date(d.year, d.month, d.day); + } + if(!now){ + now = new Date(); + } + + var delta = Math.abs(now.getTime() - d.getTime()); + for(var i = 0, chunk; chunk = dojox.dtl.utils.date._chunks[i]; i++){ + var count = Math.floor(delta / chunk[0]); + if(count) break; + } + return count + " " + chunk[1](count); + }, + _chunks: [ + [60 * 60 * 24 * 365 * 1000, function(n){ return (n == 1) ? 'year' : 'years'; }], + [60 * 60 * 24 * 30 * 1000, function(n){ return (n == 1) ? 'month' : 'months'; }], + [60 * 60 * 24 * 7 * 1000, function(n){ return (n == 1) ? 'week' : 'weeks'; }], + [60 * 60 * 24 * 1000, function(n){ return (n == 1) ? 'day' : 'days'; }], + [60 * 60 * 1000, function(n){ return (n == 1) ? 'hour' : 'hours'; }], + [60 * 1000, function(n){ return (n == 1) ? 'minute' : 'minutes'; }] + ], + _months_ap: ["Jan.", "Feb.", "March", "April", "May", "June", "July", "Aug.", "Sept.", "Oct.", "Nov.", "Dec."] +}); + +} diff --git a/includes/js/dojox/encoding/LICENSE b/includes/js/dojox/encoding/LICENSE new file mode 100644 index 0000000..032211b --- /dev/null +++ b/includes/js/dojox/encoding/LICENSE @@ -0,0 +1,9 @@ +License Disclaimer: + +All contents of this directory are Copyright (c) the Dojo Foundation, with the +following exceptions: +------------------------------------------------------------------------------- + +MD5.js, SHA1.js: + * Copyright 1998-2005, Paul Johnstone + Distributed under the terms of the BSD License diff --git a/includes/js/dojox/encoding/README b/includes/js/dojox/encoding/README new file mode 100644 index 0000000..8826008 --- /dev/null +++ b/includes/js/dojox/encoding/README @@ -0,0 +1,35 @@ +------------------------------------------------------------------------------- +DojoX Encoding +------------------------------------------------------------------------------- +Version 0.1.0 +Release date: 7/30/2007 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + Eugene Lazutkin + Tom Trenka +------------------------------------------------------------------------------- +Project description + +DojoX Encoding provides a set of routines for common encoding algorithms. +------------------------------------------------------------------------------- +Dependencies: + +Encoding only depends on the Dojo Core. +------------------------------------------------------------------------------- +Documentation + +See the API documentation for details. +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/encoding/* + +Install into the following directory structure: +/dojox/encoding/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- diff --git a/includes/js/dojox/encoding/_base.js b/includes/js/dojox/encoding/_base.js new file mode 100644 index 0000000..420ab91 --- /dev/null +++ b/includes/js/dojox/encoding/_base.js @@ -0,0 +1,7 @@ +if(!dojo._hasResource["dojox.encoding._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding._base"] = true; +dojo.provide("dojox.encoding._base"); + + + +} diff --git a/includes/js/dojox/encoding/ascii85.js b/includes/js/dojox/encoding/ascii85.js new file mode 100644 index 0000000..c54bb72 --- /dev/null +++ b/includes/js/dojox/encoding/ascii85.js @@ -0,0 +1,63 @@ +if(!dojo._hasResource["dojox.encoding.ascii85"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.ascii85"] = true; +dojo.provide("dojox.encoding.ascii85"); + +(function(){ + var c = function(input, length, result){ + var i, j, n, b = [0, 0, 0, 0, 0]; + for(i = 0; i < length; i += 4){ + n = ((input[i] * 256 + input[i+1]) * 256 + input[i+2]) * 256 + input[i+3]; + if(!n){ + result.push("z"); + }else{ + for(j = 0; j < 5; b[j++] = n % 85 + 33, n = Math.floor(n / 85)); + } + result.push(String.fromCharCode(b[4], b[3], b[2], b[1], b[0])); + } + }; + + dojox.encoding.ascii85.encode = function(input){ + // summary: encodes input data in ascii85 string + // input: Array: an array of numbers (0-255) to encode + var result = [], reminder = input.length % 4, length = input.length - reminder; + c(input, length, result); + if(reminder){ + var t = input.slice(length); + while(t.length < 4){ t.push(0); } + c(t, 4, result); + var x = result.pop(); + if(x == "z"){ x = "!!!!!"; } + result.push(x.substr(0, reminder + 1)); + } + return result.join(""); // String + }; + + dojox.encoding.ascii85.decode = function(input){ + // summary: decodes the input string back to array of numbers + // input: String: the input string to decode + var n = input.length, r = [], b = [0, 0, 0, 0, 0], i, j, t, x, y, d; + for(i = 0; i < n; ++i){ + if(input.charAt(i) == "z"){ + r.push(0, 0, 0, 0); + continue; + } + for(j = 0; j < 5; ++j){ b[j] = input.charCodeAt(i + j) - 33; } + d = n - i; + if(d < 5){ + for(j = d; j < 4; b[++j] = 0); + b[d] = 85; + } + t = (((b[0] * 85 + b[1]) * 85 + b[2]) * 85 + b[3]) * 85 + b[4]; + x = t & 255; + t >>>= 8; + y = t & 255; + t >>>= 8; + r.push(t >>> 8, t & 255, y, x); + for(j = d; j < 5; ++j, r.pop()); + i += 4; + } + return r; + }; +})(); + +} diff --git a/includes/js/dojox/encoding/base64.js b/includes/js/dojox/encoding/base64.js new file mode 100644 index 0000000..916e119 --- /dev/null +++ b/includes/js/dojox/encoding/base64.js @@ -0,0 +1,66 @@ +if(!dojo._hasResource["dojox.encoding.base64"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.base64"] = true; +dojo.provide("dojox.encoding.base64"); + +(function(){ + var p="="; + var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var dxe=dojox.encoding; + + dxe.base64.encode=function(/* byte[] */ba){ + // summary + // Encode an array of bytes as a base64-encoded string + var s=[], l=ba.length; + var rm=l%3; + var x=l-rm; + for (var i=0; i>>18)&0x3f)); + s.push(tab.charAt((t>>>12)&0x3f)); + s.push(tab.charAt((t>>>6)&0x3f)); + s.push(tab.charAt(t&0x3f)); + } + // deal with trailers, based on patch from Peter Wood. + switch(rm){ + case 2:{ + var t=ba[i++]<<16|ba[i++]<<8; + s.push(tab.charAt((t>>>18)&0x3f)); + s.push(tab.charAt((t>>>12)&0x3f)); + s.push(tab.charAt((t>>>6)&0x3f)); + s.push(p); + break; + } + case 1:{ + var t=ba[i++]<<16; + s.push(tab.charAt((t>>>18)&0x3f)); + s.push(tab.charAt((t>>>12)&0x3f)); + s.push(p); + s.push(p); + break; + } + } + return s.join(""); // string + }; + + dxe.base64.decode=function(/* string */str){ + // summary + // Convert a base64-encoded string to an array of bytes + var s=str.split(""), out=[]; + var l=s.length; + while(s[--l]==p){ } // strip off trailing padding + for (var i=0; i>>16)&0xff); + out.push((t>>>8)&0xff); + out.push(t&0xff); + } + // strip off any null bytes + while(out[out.length-1]==0){ out.pop(); } + return out; // byte[] + }; +})(); + +} diff --git a/includes/js/dojox/encoding/bits.js b/includes/js/dojox/encoding/bits.js new file mode 100644 index 0000000..8beb167 --- /dev/null +++ b/includes/js/dojox/encoding/bits.js @@ -0,0 +1,68 @@ +if(!dojo._hasResource["dojox.encoding.bits"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.bits"] = true; +dojo.provide("dojox.encoding.bits"); + +dojox.encoding.bits.OutputStream = function(){ + this.reset(); +}; + +dojo.extend(dojox.encoding.bits.OutputStream, { + reset: function(){ + this.buffer = []; + this.accumulator = 0; + this.available = 8; + }, + putBits: function(value, width){ + while(width){ + var w = Math.min(width, this.available); + var v = (w <= width ? value >>> (width - w) : value) << (this.available - w); + this.accumulator |= v & (255 >>> (8 - this.available)); + this.available -= w; + if(!this.available){ + this.buffer.push(this.accumulator); + this.accumulator = 0; + this.available = 8; + } + width -= w; + } + }, + getWidth: function(){ + return this.buffer.length * 8 + (8 - this.available); + }, + getBuffer: function(){ + var b = this.buffer; + if(this.available < 8){ b.push(this.accumulator & (255 << this.available)); } + this.reset(); + return b; + } +}); + +dojox.encoding.bits.InputStream = function(buffer, width){ + this.buffer = buffer; + this.width = width; + this.bbyte = this.bit = 0; +}; + +dojo.extend(dojox.encoding.bits.InputStream, { + getBits: function(width){ + var r = 0; + while(width){ + var w = Math.min(width, 8 - this.bit); + var v = this.buffer[this.bbyte] >>> (8 - this.bit - w); + r <<= w; + r |= v & ~(~0 << w); + this.bit += w; + if(this.bit == 8){ + ++this.bbyte; + this.bit = 0; + } + width -= w; + } + return r; + }, + getWidth: function(){ + return this.width - this.bbyte * 8 - this.bit; + } +}); + +} diff --git a/includes/js/dojox/encoding/compression/lzw.js b/includes/js/dojox/encoding/compression/lzw.js new file mode 100644 index 0000000..5e0cca7 --- /dev/null +++ b/includes/js/dojox/encoding/compression/lzw.js @@ -0,0 +1,91 @@ +if(!dojo._hasResource["dojox.encoding.compression.lzw"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.compression.lzw"] = true; +dojo.provide("dojox.encoding.compression.lzw"); +dojo.require("dojox.encoding.bits"); + +(function(){ + var _bits = function(x){ + var w = 1; + for(var v = 2; x >= v; v <<= 1, ++w); + return w; + }; + + dojox.encoding.compression.lzw.Encoder = function(n){ + this.size = n; + this.init(); + }; + + dojo.extend(dojox.encoding.compression.lzw.Encoder, { + init: function(){ + this.dict = {}; + for(var i = 0; i < this.size; ++i){ + this.dict[String.fromCharCode(i)] = i; + } + this.width = _bits(this.code = this.size); + this.p = ""; + }, + encode: function(value, stream){ + var c = String.fromCharCode(value), p = this.p + c, r = 0; + // if already in the dictionary + if(p in this.dict){ + this.p = p; + return r; + } + stream.putBits(this.dict[this.p], this.width); + // if we need to increase the code length + if((this.code & (this.code + 1)) == 0){ + stream.putBits(this.code++, r = this.width++); + } + // add new string + this.dict[p] = this.code++; + this.p = c; + return r + this.width; + }, + flush: function(stream){ + if(this.p.length == 0){ + return 0; + } + stream.putBits(this.dict[this.p], this.width); + this.p = ""; + return this.width; + } + }); + + dojox.encoding.compression.lzw.Decoder = function(n){ + this.size = n; + this.init(); + }; + + dojo.extend(dojox.encoding.compression.lzw.Decoder, { + init: function(){ + this.codes = new Array(this.size); + for(var i = 0; i < this.size; ++i){ + this.codes[i] = String.fromCharCode(i); + } + this.width = _bits(this.size); + this.p = -1; + }, + decode: function(stream){ + var c = stream.getBits(this.width), v; + if(c < this.codes.length){ + v = this.codes[c]; + if(this.p >= 0){ + this.codes.push(this.codes[this.p] + v.substr(0, 1)); + } + }else{ + if((c & (c + 1)) == 0){ + this.codes.push(""); + ++this.width; + return ""; + } + var x = this.codes[this.p]; + v = x + x.substr(0, 1); + this.codes.push(v); + } + this.p = c; + return v; + } + }); +})(); + +} diff --git a/includes/js/dojox/encoding/compression/splay.js b/includes/js/dojox/encoding/compression/splay.js new file mode 100644 index 0000000..5902380 --- /dev/null +++ b/includes/js/dojox/encoding/compression/splay.js @@ -0,0 +1,64 @@ +if(!dojo._hasResource["dojox.encoding.compression.splay"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.compression.splay"] = true; +dojo.provide("dojox.encoding.compression.splay"); +dojo.require("dojox.encoding.bits"); + +dojox.encoding.compression.Splay = function(n){ + this.up = new Array(2 * n + 1); + this.left = new Array(n); + this.right = new Array(n); + this.reset(); +}; + +dojo.extend(dojox.encoding.compression.Splay, { + reset: function(){ + for(var i = 1; i < this.up.length; this.up[i] = Math.floor((i - 1) / 2), ++i); + for(var i = 0; i < this.left.length; this.left[i] = 2 * i + 1, this.right[i] = 2 * i + 2, ++i); + }, + splay: function(i){ + var a = i + this.left.length; + do{ + var c = this.up[a]; + if(c){ // root + // rotated pair + var d = this.up[c]; + // swap descendants + var b = this.left[d]; + if(c == b){ + b = this.right[d]; + this.right[d] = a; + } else { + this.left[d] = a; + } + this[a == this.left[c] ? "left" : "right"][c] = b; + this.up[a] = d; + this.up[b] = c; + a = d; + }else{ + a = c; + } + }while(a); // root + }, + encode: function(value, stream){ + var s = [], a = value + this.left.length; + do{ + s.push(this.right[this.up[a]] == a); + a = this.up[a]; + }while(a); // root + this.splay(value); + var l = s.length; + while(s.length){ stream.putBits(s.pop() ? 1 : 0, 1); } + return l; + }, + decode: function(stream){ + var a = 0; // root; + do{ + a = this[stream.getBits(1) ? "right" : "left"][a]; + }while(a < this.left.length); + a -= this.left.length; + this.splay(a); + return a; + } +}); + +} diff --git a/includes/js/dojox/encoding/crypto/Blowfish.js b/includes/js/dojox/encoding/crypto/Blowfish.js new file mode 100644 index 0000000..94f58ca --- /dev/null +++ b/includes/js/dojox/encoding/crypto/Blowfish.js @@ -0,0 +1,481 @@ +if(!dojo._hasResource["dojox.encoding.crypto.Blowfish"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.crypto.Blowfish"] = true; +dojo.provide("dojox.encoding.crypto.Blowfish"); + +dojo.require("dojox.encoding.base64"); +dojo.require("dojox.encoding.crypto._base"); + +/* Blowfish + * Created based on the C# implementation by Marcus Hahn (http://www.hotpixel.net/) + * Unsigned math based on Paul Johnstone and Peter Wood patches. + * 2005-12-08 + */ +dojox.encoding.crypto.Blowfish = new function(){ + // summary + // Object for doing Blowfish encryption/decryption. + var POW2=Math.pow(2,2); + var POW3=Math.pow(2,3); + var POW4=Math.pow(2,4); + var POW8=Math.pow(2,8); + var POW16=Math.pow(2,16); + var POW24=Math.pow(2,24); + var iv=null; // CBC mode initialization vector + var boxes={ + p:[ + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b + ], + s0:[ + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a + ], + s1:[ + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 + ], + s2:[ + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 + ], + s3:[ + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + ] + } +//////////////////////////////////////////////////////////////////////////// +// fixes based on patch submitted by Peter Wood (#5791) + function add(x,y){ + return (((x>>0x10)+(y>>0x10)+(((x&0xffff)+(y&0xffff))>>0x10))<<0x10)|(((x&0xffff)+(y&0xffff))&0xffff); + } + function xor(x,y){ + return (((x>>0x10)^(y>>0x10))<<0x10)|(((x&0xffff)^(y&0xffff))&0xffff); + } + + function $(v, box){ + var d=box.s3[v&0xff]; v>>=8; + var c=box.s2[v&0xff]; v>>=8; + var b=box.s1[v&0xff]; v>>=8; + var a=box.s0[v&0xff]; + + var r = (((a>>0x10)+(b>>0x10)+(((a&0xffff)+(b&0xffff))>>0x10))<<0x10)|(((a&0xffff)+(b&0xffff))&0xffff); + r = (((r>>0x10)^(c>>0x10))<<0x10)|(((r&0xffff)^(c&0xffff))&0xffff); + return (((r>>0x10)+(d>>0x10)+(((r&0xffff)+(d&0xffff))>>0x10))<<0x10)|(((r&0xffff)+(d&0xffff))&0xffff); + } +//////////////////////////////////////////////////////////////////////////// + function eb(o, box){ + // TODO: see if this can't be made more efficient + var l=o.left; + var r=o.right; + l=xor(l,box.p[0]); + r=xor(r,xor($(l,box),box.p[1])); + l=xor(l,xor($(r,box),box.p[2])); + r=xor(r,xor($(l,box),box.p[3])); + l=xor(l,xor($(r,box),box.p[4])); + r=xor(r,xor($(l,box),box.p[5])); + l=xor(l,xor($(r,box),box.p[6])); + r=xor(r,xor($(l,box),box.p[7])); + l=xor(l,xor($(r,box),box.p[8])); + r=xor(r,xor($(l,box),box.p[9])); + l=xor(l,xor($(r,box),box.p[10])); + r=xor(r,xor($(l,box),box.p[11])); + l=xor(l,xor($(r,box),box.p[12])); + r=xor(r,xor($(l,box),box.p[13])); + l=xor(l,xor($(r,box),box.p[14])); + r=xor(r,xor($(l,box),box.p[15])); + l=xor(l,xor($(r,box),box.p[16])); + o.right=l; + o.left=xor(r,box.p[17]); + } + + function db(o, box){ + var l=o.left; + var r=o.right; + l=xor(l,box.p[17]); + r=xor(r,xor($(l,box),box.p[16])); + l=xor(l,xor($(r,box),box.p[15])); + r=xor(r,xor($(l,box),box.p[14])); + l=xor(l,xor($(r,box),box.p[13])); + r=xor(r,xor($(l,box),box.p[12])); + l=xor(l,xor($(r,box),box.p[11])); + r=xor(r,xor($(l,box),box.p[10])); + l=xor(l,xor($(r,box),box.p[9])); + r=xor(r,xor($(l,box),box.p[8])); + l=xor(l,xor($(r,box),box.p[7])); + r=xor(r,xor($(l,box),box.p[6])); + l=xor(l,xor($(r,box),box.p[5])); + r=xor(r,xor($(l,box),box.p[4])); + l=xor(l,xor($(r,box),box.p[3])); + r=xor(r,xor($(l,box),box.p[2])); + l=xor(l,xor($(r,box),box.p[1])); + o.right=l; + o.left=xor(r,box.p[0]); + } + + // Note that we aren't caching contexts here; it might take a little longer + // but we should be more secure this way. + function init(key){ + var k=key; + if(dojo.isString(k)){ + k = dojo.map(k.split(""), function(item){ + return item.charCodeAt(0) & 0xff; + }); + } + + // init the boxes + var pos=0, data=0, res={ left:0, right:0 }, i, j; + var box = { + p: dojo.map(boxes.p.slice(0), function(item){ + var l=k.length, j; + for(j=0; j<4; j++){ data=(data*POW8)|k[pos++ % l]; } + return (((item>>0x10)^(data>>0x10))<<0x10)|(((item&0xffff)^(data&0xffff))&0xffff); + }), + s0:boxes.s0.slice(0), + s1:boxes.s1.slice(0), + s2:boxes.s2.slice(0), + s3:boxes.s3.slice(0) + }; + + // encrypt p and the s boxes + for(i=0, l=box.p.length; i> 3, pos=0, o={}, isCBC=(mode==dojox.encoding.crypto.cipherModes.CBC); + var vector={left:iv.left||null, right:iv.right||null}; + for(var i=0; i>0x10)^(vector.left>>0x10))<<0x10)|(((o.left&0xffff)^(vector.left&0xffff))&0xffff); + o.right=(((o.right>>0x10)^(vector.right>>0x10))<<0x10)|(((o.right&0xffff)^(vector.right&0xffff))&0xffff); + } + + eb(o, bx); // encrypt the block + + if(isCBC){ + vector.left=o.left; + vector.right=o.right; + } + + cipher.push((o.left>>24)&0xff); + cipher.push((o.left>>16)&0xff); + cipher.push((o.left>>8)&0xff); + cipher.push(o.left&0xff); + cipher.push((o.right>>24)&0xff); + cipher.push((o.right>>16)&0xff); + cipher.push((o.right>>8)&0xff); + cipher.push(o.right&0xff); + pos+=8; + } + + switch(out){ + case dojox.encoding.crypto.outputTypes.Hex:{ + return dojo.map(cipher, function(item){ + return item.toString(16); + }).join(""); // string + } + case dojox.encoding.crypto.outputTypes.String:{ + return cipher.join(""); // string + } + case dojox.encoding.crypto.outputTypes.Raw:{ + return cipher; // array + } + default:{ + return dojox.encoding.base64.encode(cipher); // string + } + } + }; + + this.decrypt = function(/* string */ciphertext, /* string */key, /* object? */ao){ + // summary + // decrypts ciphertext using key; allows specification of how ciphertext is encoded via ao. + var ip=dojox.encoding.crypto.outputTypes.Base64; + var mode=dojox.encoding.crypto.cipherModes.EBC; + if (ao){ + if (ao.outputType) ip=ao.outputType; + if (ao.cipherMode) mode=ao.cipherMode; + } + var bx = init(key); + var pt=[]; + + var c=null; + switch(ip){ + case dojox.encoding.crypto.outputTypes.Hex:{ + c = []; + for(var i=0, l=ciphertext.length-1; i> 3, pos=0, o={}, isCBC=(mode==dojox.encoding.crypto.cipherModes.CBC); + var vector={left:iv.left||null, right:iv.right||null}; + for(var i=0; i>0x10)^(vector.left>>0x10))<<0x10)|(((o.left&0xffff)^(vector.left&0xffff))&0xffff); + o.right=(((o.right>>0x10)^(vector.right>>0x10))<<0x10)|(((o.right&0xffff)^(vector.right&0xffff))&0xffff); + vector.left=left; + vector.right=right; + } + + pt.push((o.left>>24)&0xff); + pt.push((o.left>>16)&0xff); + pt.push((o.left>>8)&0xff); + pt.push(o.left&0xff); + pt.push((o.right>>24)&0xff); + pt.push((o.right>>16)&0xff); + pt.push((o.right>>8)&0xff); + pt.push(o.right&0xff); + pos+=8; + } + + // check for padding, and remove. + if(pt[pt.length-1]==pt[pt.length-2]||pt[pt.length-1]==0x01){ + var n=pt[pt.length-1]; + pt.splice(pt.length-n, n); + } + + // convert to string + return dojo.map(pt, function(item){ + return String.fromCharCode(item); + }).join(""); // string + }; + + this.setIV("0000000000000000", dojox.encoding.crypto.outputTypes.Hex); +}(); + +} diff --git a/includes/js/dojox/encoding/crypto/_base.js b/includes/js/dojox/encoding/crypto/_base.js new file mode 100644 index 0000000..174d073 --- /dev/null +++ b/includes/js/dojox/encoding/crypto/_base.js @@ -0,0 +1,19 @@ +if(!dojo._hasResource["dojox.encoding.crypto._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.crypto._base"] = true; +dojo.provide("dojox.encoding.crypto._base"); + +(function(){ + var c=dojox.encoding.crypto; + c.cipherModes={ + // summary + // Enumeration for various cipher modes. + ECB:0, CBC:1, PCBC:2, CFB:3, OFB:4, CTR:5 + }; + c.outputTypes={ + // summary + // Enumeration for input and output encodings. + Base64:0, Hex:1, String:2, Raw:3 + }; +})(); + +} diff --git a/includes/js/dojox/encoding/digests/MD5.js b/includes/js/dojox/encoding/digests/MD5.js new file mode 100644 index 0000000..eb72d59 --- /dev/null +++ b/includes/js/dojox/encoding/digests/MD5.js @@ -0,0 +1,177 @@ +if(!dojo._hasResource["dojox.encoding.digests.MD5"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.digests.MD5"] = true; +dojo.provide("dojox.encoding.digests.MD5"); + +dojo.require("dojox.encoding.digests._base"); + +/* A port of Paul Johnstone's MD5 implementation + * http://pajhome.org.uk/crypt/md5/index.html + * + * Copyright (C) Paul Johnston 1999 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * + * Dojo port by Tom Trenka + */ +(function(){ + var dxd=dojox.encoding.digests; + var chrsz=8; + + // MD5 rounds functions + function R(n,c){ return (n<>>(32-c)); } + function C(q,a,b,x,s,t){ return dxd.addWords(R(dxd.addWords(dxd.addWords(a, q), dxd.addWords(x, t)), s), b); } + function FF(a,b,c,d,x,s,t){ return C((b&c)|((~b)&d),a,b,x,s,t); } + function GG(a,b,c,d,x,s,t){ return C((b&d)|(c&(~d)),a,b,x,s,t); } + function HH(a,b,c,d,x,s,t){ return C(b^c^d,a,b,x,s,t); } + function II(a,b,c,d,x,s,t){ return C(c^(b|(~d)),a,b,x,s,t); } + + // the core MD5 rounds method + function core(x,len){ + x[len>>5]|=0x80<<((len)%32); + x[(((len+64)>>>9)<<4)+14]=len; + var a= 1732584193; + var b=-271733879; + var c=-1732584194; + var d= 271733878; + for(var i=0; i16){ + wa=core(wa, key.length*chrsz); + } + var l=[], r=[]; + for(var i=0; i<16; i++){ + l[i]=wa[i]^0x36363636; + r[i]=wa[i]^0x5c5c5c5c; + } + var h=core(l.concat(dxd.stringToWord(data)), 512+data.length*chrsz); + return core(r.concat(h), 640); + } + + // public function + dxd.MD5=function(/* string */data, /* dojox.encoding.digests.outputTypes? */outputType){ + // summary + // computes the digest of data, and returns the result according to type outputType + var out=outputType || dxd.outputTypes.Base64; + var wa=core(dxd.stringToWord(data), data.length*chrsz); + switch(out){ + case dxd.outputTypes.Raw:{ + return wa; // word[] + } + case dxd.outputTypes.Hex:{ + return dxd.wordToHex(wa); // string + } + case dxd.outputTypes.String:{ + return dxd.wordToString(wa); // string + } + default:{ + return dxd.wordToBase64(wa); // string + } + } + }; + + // make this private, for later use with a generic HMAC calculator. + dxd.MD5._hmac=function(/* string */data, /* string */key, /* dojox.encoding.digests.outputTypes? */outputType){ + // summary + // computes the digest of data, and returns the result according to type outputType + var out=outputType || dxd.outputTypes.Base64; + var wa=hmac(data, key); + switch(out){ + case dxd.outputTypes.Raw:{ + return wa; // word[] + } + case dxd.outputTypes.Hex:{ + return dxd.wordToHex(wa); // string + } + case dxd.outputTypes.String:{ + return dxd.wordToString(wa); // string + } + default:{ + return dxd.wordToBase64(wa); // string + } + } + }; +})(); + +} diff --git a/includes/js/dojox/encoding/digests/_base.js b/includes/js/dojox/encoding/digests/_base.js new file mode 100644 index 0000000..3ebae22 --- /dev/null +++ b/includes/js/dojox/encoding/digests/_base.js @@ -0,0 +1,78 @@ +if(!dojo._hasResource["dojox.encoding.digests._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.digests._base"] = true; +dojo.provide("dojox.encoding.digests._base"); + +(function(){ + //TODO: see if it makes sense to meld this into one with the + // crypto base enums + var d=dojox.encoding.digests; + d.outputTypes={ + // summary + // Enumeration for input and output encodings. + Base64:0, Hex:1, String:2, Raw:3 + }; + + // word-based addition + d.addWords=function(/* word */a, /* word */b){ + // summary + // add a pair of words together with rollover + var l=(a&0xFFFF)+(b&0xFFFF); + var m=(a>>16)+(b>>16)+(l>>16); + return (m<<16)|(l&0xFFFF); // word + }; + + // word-based conversion method, for efficiency sake; + // most digests operate on words, and this should be faster + // than the encoding version (which works on bytes). + var chrsz=8; + var mask=(1<>5]|=(s.charCodeAt(i/chrsz)&mask)<<(i%32); + } + return wa; // word[] + }; + + d.wordToString=function(/* word[] */wa){ + // summary + // convert an array of words to a string + var s=[]; + for(var i=0, l=wa.length*32; i>5]>>>(i%32))&mask)); + } + return s.join(""); // string + } + + d.wordToHex=function(/* word[] */wa){ + // summary + // convert an array of words to a hex tab + var h="0123456789abcdef", s=[]; + for(var i=0, l=wa.length*4; i>2]>>((i%4)*8+4))&0xF)+h.charAt((wa[i>>2]>>((i%4)*8))&0xF)); + } + return s.join(""); // string + } + d.wordToBase64=function(/* word[] */wa){ + // summary + // convert an array of words to base64 encoding, should be more efficient + // than using dojox.encoding.base64 + var p="=", tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", s=[]; + for(var i=0, l=wa.length*4; i>2]>>8*(i%4))&0xFF)<<16)|(((wa[i+1>>2]>>8*((i+1)%4))&0xFF)<<8)|((wa[i+2>>2]>>8*((i+2)%4))&0xFF); + for(var j=0; j<4; j++){ + if(i*8+j*6>wa.length*32){ + s.push(p); + } else { + s.push(tab.charAt((t>>6*(3-j))&0x3F)); + } + } + } + return s.join(""); // string + }; +})(); + +} diff --git a/includes/js/dojox/encoding/easy64.js b/includes/js/dojox/encoding/easy64.js new file mode 100644 index 0000000..824ff3e --- /dev/null +++ b/includes/js/dojox/encoding/easy64.js @@ -0,0 +1,50 @@ +if(!dojo._hasResource["dojox.encoding.easy64"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.easy64"] = true; +dojo.provide("dojox.encoding.easy64"); + +(function(){ + var c = function(input, length, result){ + for(var i = 0; i < length; i += 3){ + result.push( + String.fromCharCode((input[i] >>> 2) + 33), + String.fromCharCode(((input[i] & 3) << 4) + (input[i + 1] >>> 4) + 33), + String.fromCharCode(((input[i + 1] & 15) << 2) + (input[i + 2] >>> 6) + 33), + String.fromCharCode((input[i + 2] & 63) + 33) + ); + } + }; + + dojox.encoding.easy64.encode = function(input){ + // summary: encodes input data in easy64 string + // input: Array: an array of numbers (0-255) to encode + var result = [], reminder = input.length % 3, length = input.length - reminder; + c(input, length, result); + if(reminder){ + var t = input.slice(length); + while(t.length < 3){ t.push(0); } + c(t, 3, result); + for(var i = 3; i > reminder; result.pop(), --i); + } + return result.join(""); // String + }; + + dojox.encoding.easy64.decode = function(input){ + // summary: decodes the input string back to array of numbers + // input: String: the input string to decode + var n = input.length, r = [], b = [0, 0, 0, 0], i, j, d; + for(i = 0; i < n; i += 4){ + for(j = 0; j < 4; ++j){ b[j] = input.charCodeAt(i + j) - 33; } + d = n - i; + for(j = d; j < 4; b[++j] = 0); + r.push( + (b[0] << 2) + (b[1] >>> 4), + ((b[1] & 15) << 4) + (b[2] >>> 2), + ((b[2] & 3) << 6) + b[3] + ); + for(j = d; j < 4; ++j, r.pop()); + } + return r; + }; +})(); + +} diff --git a/includes/js/dojox/encoding/tests/ascii85.js b/includes/js/dojox/encoding/tests/ascii85.js new file mode 100644 index 0000000..d93329c --- /dev/null +++ b/includes/js/dojox/encoding/tests/ascii85.js @@ -0,0 +1,35 @@ +if(!dojo._hasResource["dojox.encoding.tests.ascii85"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.ascii85"] = true; +dojo.provide("dojox.encoding.tests.ascii85"); +dojo.require("dojox.encoding.ascii85"); + +(function(){ + var msg1 = "The rain in Spain falls mainly on the plain."; + var msg2 = "The rain in Spain falls mainly on the plain.1"; + var msg3 = "The rain in Spain falls mainly on the plain.ab"; + var msg4 = "The rain in Spain falls mainly on the plain.!@#"; + var dca = dojox.encoding.ascii85; + + var s2b = function(s){ + var b = []; + for(var i = 0; i < s.length; ++i){ + b.push(s.charCodeAt(i)); + } + return b; + }; + + var b2s = function(b){ + var s = []; + dojo.forEach(b, function(c){ s.push(String.fromCharCode(c)); }); + return s.join(""); + }; + + tests.register("dojox.encoding.tests.ascii85", [ + function testMsg1(t){ t.assertEqual(msg1, b2s(dca.decode(dca.encode(s2b(msg1))))); }, + function testMsg2(t){ t.assertEqual(msg2, b2s(dca.decode(dca.encode(s2b(msg2))))); }, + function testMsg3(t){ t.assertEqual(msg3, b2s(dca.decode(dca.encode(s2b(msg3))))); }, + function testMsg4(t){ t.assertEqual(msg4, b2s(dca.decode(dca.encode(s2b(msg4))))); } + ]); +})(); + +} diff --git a/includes/js/dojox/encoding/tests/bits.js b/includes/js/dojox/encoding/tests/bits.js new file mode 100644 index 0000000..dc7ae66 --- /dev/null +++ b/includes/js/dojox/encoding/tests/bits.js @@ -0,0 +1,74 @@ +if(!dojo._hasResource["dojox.encoding.tests.bits"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.bits"] = true; +dojo.provide("dojox.encoding.tests.bits"); +dojo.require("dojox.encoding.bits"); + +(function(){ + var msg1 = "The rain in Spain falls mainly on the plain."; + var msg2 = "The rain in Spain falls mainly on the plain.1"; + var msg3 = "The rain in Spain falls mainly on the plain.ab"; + var msg4 = "The rain in Spain falls mainly on the plain.!@#"; + var dcb = dojox.encoding.bits; + + var s2b = function(s){ + var b = []; + for(var i = 0; i < s.length; ++i){ + b.push(s.charCodeAt(i)); + } + return b; + }; + + var b2s = function(b){ + var s = []; + dojo.forEach(b, function(c){ s.push(String.fromCharCode(c)); }); + return s.join(""); + }; + + var testOut = function(msg){ + var a = new dojox.encoding.bits.OutputStream(); + for(var i = 0; i < msg.length; ++i){ + var v = msg.charCodeAt(i); + var j = Math.floor(Math.random() * 7) + 1; + a.putBits(v >>> (8 - j), j); + a.putBits(v, 8 - j); + } + return b2s(a.getBuffer()); + }; + + var testIn = function(msg){ + var a = new dojox.encoding.bits.InputStream(s2b(msg), msg.length * 8); + var r = []; + for(var i = 0; i < msg.length; ++i){ + var j = Math.floor(Math.random() * 7) + 1; + r.push((a.getBits(j) << (8 - j)) | a.getBits(8 - j)); + } + return b2s(r); + }; + + var test = function(msg){ + var a = new dojox.encoding.bits.InputStream(s2b(msg), msg.length * 8); + var o = new dojox.encoding.bits.OutputStream(); + while(a.getWidth() > 0){ + var w = Math.min(a.getWidth(), 3); + o.putBits(a.getBits(w), w); + } + return b2s(o.getBuffer()); + }; + + tests.register("dojox.encoding.tests.bits", [ + function testBitsOut1(t){ t.assertEqual(msg1, testOut(msg1)); }, + function testBitsOut2(t){ t.assertEqual(msg2, testOut(msg2)); }, + function testBitsOut3(t){ t.assertEqual(msg3, testOut(msg3)); }, + function testBitsOut4(t){ t.assertEqual(msg4, testOut(msg4)); }, + function testBitsIn1(t){ t.assertEqual(msg1, testIn(msg1)); }, + function testBitsIn2(t){ t.assertEqual(msg2, testIn(msg2)); }, + function testBitsIn3(t){ t.assertEqual(msg3, testIn(msg3)); }, + function testBitsIn4(t){ t.assertEqual(msg4, testIn(msg4)); }, + function testBits1(t){ t.assertEqual(msg1, test(msg1)); }, + function testBits2(t){ t.assertEqual(msg2, test(msg2)); }, + function testBits3(t){ t.assertEqual(msg3, test(msg3)); }, + function testBits4(t){ t.assertEqual(msg4, test(msg4)); } + ]); +})(); + +} diff --git a/includes/js/dojox/encoding/tests/compression/_base.js b/includes/js/dojox/encoding/tests/compression/_base.js new file mode 100644 index 0000000..ec9d560 --- /dev/null +++ b/includes/js/dojox/encoding/tests/compression/_base.js @@ -0,0 +1,12 @@ +if(!dojo._hasResource["dojox.encoding.tests.compression._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.compression._base"] = true; +dojo.provide("dojox.encoding.tests.compression._base"); + +try{ + dojo.require("dojox.encoding.tests.compression.splay"); + dojo.require("dojox.encoding.tests.compression.lzw"); +}catch(e){ + doh.debug(e); +} + +} diff --git a/includes/js/dojox/encoding/tests/compression/colors.js b/includes/js/dojox/encoding/tests/compression/colors.js new file mode 100644 index 0000000..caedbb1 --- /dev/null +++ b/includes/js/dojox/encoding/tests/compression/colors.js @@ -0,0 +1,156 @@ +if(!dojo._hasResource["dojox.encoding.tests.compression.colors"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.compression.colors"] = true; +dojo.provide("dojox.encoding.tests.compression.colors"); + +// all CSS3 colors +dojox.encoding.tests.compression.colors = { +aliceblue: [240,248,255], +antiquewhite: [250,235,215], +aqua: [0,255,255], +aquamarine: [127,255,212], +azure: [240,255,255], +beige: [245,245,220], +bisque: [255,228,196], +black: [0,0,0], +blanchedalmond: [255,235,205], +blue: [0,0,255], +blueviolet: [138,43,226], +brown: [165,42,42], +burlywood: [222,184,135], +cadetblue: [95,158,160], +chartreuse: [127,255,0], +chocolate: [210,105,30], +coral: [255,127,80], +cornflowerblue: [100,149,237], +cornsilk: [255,248,220], +crimson: [220,20,60], +cyan: [0,255,255], +darkblue: [0,0,139], +darkcyan: [0,139,139], +darkgoldenrod: [184,134,11], +darkgray: [169,169,169], +darkgreen: [0,100,0], +darkgrey: [169,169,169], +darkkhaki: [189,183,107], +darkmagenta: [139,0,139], +darkolivegreen: [85,107,47], +darkorange: [255,140,0], +darkorchid: [153,50,204], +darkred: [139,0,0], +darksalmon: [233,150,122], +darkseagreen: [143,188,143], +darkslateblue: [72,61,139], +darkslategray: [47,79,79], +darkslategrey: [47,79,79], +darkturquoise: [0,206,209], +darkviolet: [148,0,211], +deeppink: [255,20,147], +deepskyblue: [0,191,255], +dimgray: [105,105,105], +dimgrey: [105,105,105], +dodgerblue: [30,144,255], +firebrick: [178,34,34], +floralwhite: [255,250,240], +forestgreen: [34,139,34], +fuchsia: [255,0,255], +gainsboro: [220,220,220], +ghostwhite: [248,248,255], +gold: [255,215,0], +goldenrod: [218,165,32], +gray: [128,128,128], +green: [0,128,0], +greenyellow: [173,255,47], +grey: [128,128,128], +honeydew: [240,255,240], +hotpink: [255,105,180], +indianred: [205,92,92], +indigo: [75,0,130], +ivory: [255,255,240], +khaki: [240,230,140], +lavender: [230,230,250], +lavenderblush: [255,240,245], +lawngreen: [124,252,0], +lemonchiffon: [255,250,205], +lightblue: [173,216,230], +lightcoral: [240,128,128], +lightcyan: [224,255,255], +lightgoldenrodyellow: [250,250,210], +lightgray: [211,211,211], +lightgreen: [144,238,144], +lightgrey: [211,211,211], +lightpink: [255,182,193], +lightsalmon: [255,160,122], +lightseagreen: [32,178,170], +lightskyblue: [135,206,250], +lightslategray: [119,136,153], +lightslategrey: [119,136,153], +lightsteelblue: [176,196,222], +lightyellow: [255,255,224], +lime: [0,255,0], +limegreen: [50,205,50], +linen: [250,240,230], +magenta: [255,0,255], +maroon: [128,0,0], +mediumaquamarine: [102,205,170], +mediumblue: [0,0,205], +mediumorchid: [186,85,211], +mediumpurple: [147,112,219], +mediumseagreen: [60,179,113], +mediumslateblue: [123,104,238], +mediumspringgreen: [0,250,154], +mediumturquoise: [72,209,204], +mediumvioletred: [199,21,133], +midnightblue: [25,25,112], +mintcream: [245,255,250], +mistyrose: [255,228,225], +moccasin: [255,228,181], +navajowhite: [255,222,173], +navy: [0,0,128], +oldlace: [253,245,230], +olive: [128,128,0], +olivedrab: [107,142,35], +orange: [255,165,0], +orangered: [255,69,0], +orchid: [218,112,214], +palegoldenrod: [238,232,170], +palegreen: [152,251,152], +paleturquoise: [175,238,238], +palevioletred: [219,112,147], +papayawhip: [255,239,213], +peachpuff: [255,218,185], +peru: [205,133,63], +pink: [255,192,203], +plum: [221,160,221], +powderblue: [176,224,230], +purple: [128,0,128], +red: [255,0,0], +rosybrown: [188,143,143], +royalblue: [65,105,225], +saddlebrown: [139,69,19], +salmon: [250,128,114], +sandybrown: [244,164,96], +seagreen: [46,139,87], +seashell: [255,245,238], +sienna: [160,82,45], +silver: [192,192,192], +skyblue: [135,206,235], +slateblue: [106,90,205], +slategray: [112,128,144], +slategrey: [112,128,144], +snow: [255,250,250], +springgreen: [0,255,127], +steelblue: [70,130,180], +tan: [210,180,140], +teal: [0,128,128], +thistle: [216,191,216], +tomato: [255,99,71], +turquoise: [64,224,208], +violet: [238,130,238], +wheat: [245,222,179], +white: [255,255,255], +whitesmoke: [245,245,245], +yellow: [255,255,0], +yellowgreen: [154,205,50] +}; + +} diff --git a/includes/js/dojox/encoding/tests/compression/colors2.html b/includes/js/dojox/encoding/tests/compression/colors2.html new file mode 100644 index 0000000..24bb9fe --- /dev/null +++ b/includes/js/dojox/encoding/tests/compression/colors2.html @@ -0,0 +1,104 @@ + + + Compress colors + + + + + + +

      Compress colors

      +

      +
      No status yet.
      + + diff --git a/includes/js/dojox/encoding/tests/compression/colors2.js b/includes/js/dojox/encoding/tests/compression/colors2.js new file mode 100644 index 0000000..52f9186 --- /dev/null +++ b/includes/js/dojox/encoding/tests/compression/colors2.js @@ -0,0 +1,64 @@ +if(!dojo._hasResource["dojox.encoding.tests.compression.colors2"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.compression.colors2"] = true; +dojo.provide("dojox.encoding.tests.compression.colors2"); + +// all CSS3 colors +dojox.encoding.tests.compression.colors2 = {}; + +(function(){ + var n = "!mi-='%@Md%8;F\"=E5(:$@nHf!(;HYAOL),#XJKa#UHDMYQ0@q6C8='JBa#m1`YRS;3_\\P=@.(bN\\!)0d:Nar*Fo]]G`\\[X7Cb@r#pc;D3!k*8^\"bS8DAYbu'J5[`7Fh5S1e8`@1^N\"n8R:+ZQt]Ab.S>NP-jkO\"N$oQpbVbYtZl1&rSs%_;'!e8\"ij:*R!%9&P.+o0%cF&0F<\"eWn+rm!a<(02!d\\-J\\O@`K![IaPrqh6H4S!U7CU!\"5jICR2\\X?!FilaO:$aE\"G1NIfMJ<.)1d;?OH9VU%LiGhi9=d?$EjW!BM0)1mGfg@\"os1\\E*A>+>YdjUK:P>T'7tj.UQ?<89]$:\\Li]GF*H8o*Z,o]Q_E]tq?C^%'^cfU9B9sH-^t.-R;J6P9!buNg*%$9#>Y'*n;MPc7=>*]sb&NmgKSZcd2nWt6I@SX7agi3!0)M'T3O@@/>W+I:H9?@A7tjT8':(9PG\\m@_T8Ws\\\".VLCkg7IYKZ7M3.XQqX$4V`bEQF?<#jJ>#4Z#6:ZeYffa.W#0CW3@s2*ESkiD6hN#EAhXBm5F%&U_=k*tFq@rYS/!:$=M9epZ<`=HN:X\"!CRI(`>iqTRe(S@A\"&0!Dib&)1p9P)$NZb^e+i_UHHq\\_8AYC+oiIMLj_TW=u'3Nn?c=#_6Z^s/;EY/3Z(cZ\"CaOq6g>>I+;'H>Nh`>\"-3NDnX+!(g67=pRcf38l7XNQ:_FJ,l2V)C@@A;H1dN#\\$n75qg6-:\".KQkn!?a7e\"J7C0p3Pn`]hKrG_4WG*5qo\\tH,20o2QOZljnj_lZ&C6!.u8Qu:_L$8$4.[V@`&A0J,fQL"; + var c = "nG*%[ldl.:s*t'unGiO]p\"]T._uKc;s6Io0!<7p,ih\\+ShRJ>JStLT5!7GR&s*mjUQ0nVHgtWT+!<<'!!/gi8Mn\"KLWMuisA,rU.WP,cVMZAZ8CG5^H!1>UdMZs7$&&[*;i\\9)sSDs7#O?N99:!s7#]/quHcnc)oX\\n:6&Is8VrldaQ[oORA4Ze'n?*_>g0S+L8#&cMDa@RV#^Na!8;DCmc^[I^5QAOBh4WT.i9#OiJH#TL]T8+>C#Ot='Dd6\"oV>kIMc]rOm\\!H0^qda@cKf4Kc#A2pE.F&MqYC3lIn#$sd^4r5J:Q:ef`,GO5iC#WK'r>>= 8; y = t & 255; t >>>= 8; + r.push(t >>> 8, t & 255, y, x); + } + return r; + }; + var B = function(f){ this.f = f; this.y = this.t = 0; }; + B.prototype.g = function(b){ + var r = 0; + while(b){ + var w = Math.min(b, 8 - this.t), v = this.f[this.y] >>> (8 - this.t - w); + r <<= w; r |= v & ~(~0 << w); + if((this.t += w) == 8){ ++this.y; this.t = 0; } + b -= w; + } + return r; + }; + var D = function(n, w){ + this.c = new Array(n); this.w = w; this.p = -1; + for(var i = 0; i < n; ++i){ this.c[i] = [i + 97]; } + }; + D.prototype.d = function(s){ + var c = s.g(this.w), v; + if(c < this.c.length){ + v = this.c[c]; + if(this.p >= 0){ + this.c.push(this.c[this.p].concat(v[0])); + } + }else{ + this.c.push([]); + ++this.w; + return []; + } + this.p = c; + return v; + }; + var i = new B(a(n)), d = new D(27, 5), t = []; + while(t.length < 1455){ + var v = d.d(i); + dojo.forEach(v, function(x){ t.push(x); }); + } + var n2 = dojo.map(t, function(x){ return String.fromCharCode(x); }).join("").split("{"); + i = a(c); + for(var j = 0, k = 0; j < n2.length; ++j){ + dojox.encoding.tests.compression.colors2[n2[j]] = [i[k++], i[k++], i[k++]]; + } + +})(); + +} diff --git a/includes/js/dojox/encoding/tests/compression/colors3.html b/includes/js/dojox/encoding/tests/compression/colors3.html new file mode 100644 index 0000000..482c75d --- /dev/null +++ b/includes/js/dojox/encoding/tests/compression/colors3.html @@ -0,0 +1,104 @@ + + + Compress colors + + + + + + +

      Compress colors

      +

      +
      No status yet.
      + + diff --git a/includes/js/dojox/encoding/tests/compression/colors3.js b/includes/js/dojox/encoding/tests/compression/colors3.js new file mode 100644 index 0000000..f0a1587 --- /dev/null +++ b/includes/js/dojox/encoding/tests/compression/colors3.js @@ -0,0 +1,53 @@ +if(!dojo._hasResource["dojox.encoding.tests.compression.colors3"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.compression.colors3"] = true; +dojo.provide("dojox.encoding.tests.compression.colors3"); + +// all CSS3 colors +dojox.encoding.tests.compression.colors3 = {}; + +(function(){ + var n = "!N!C@\",5%;!.4)1D7()4E!K!FS-!2).Q:52E`!B\"!;!)*+I!M!#&'E+9%(#!T9Q=.\"TE5F'6%$B91H/)DCQW=^&G#QY>:\"!!?*#D.57Z.]5**+0]/!G!!,X=/%2O'%1U&#W9%%86_BQU3#!N.!DA-%F>X'#9;6\"%+EK)X#A+A;+-+\"G\"T$76:L1;)'+?ENA1%L+C\\O+U+\"Q!+#,E+.E1H-[VA#\"5%O\\X)BS:%V2&2#,3I0NWE%F7?L8U!U\\\\B3C_GZ?P3N]A3\\]$)%TUK$E9EL6ZA`T%IFY$Q?/3;=Q)$QE#AQ\\11$&M!'$$XK!T?2%C7QU\"110A#/#:'U=C!7,\"=*!+BQ)%AG[)W&#CFBG\"A!/1E!5/$AU\"A/$J:*E+LQ77;%M6H/XD,H1'!)#U=&K1\"&R02U'$H5*[%Y+$3;/1'#\"-XQV8C(/GABVQQW+RS5U3QE!V<6[=YS@!0=1!:Z=93M$7W\":3;!Z0!GJM'\"QGAJ*=3(C&5I=0,6AP6H4+=:M:B)CO-D?]<,2^H-`7SEB(B5N5%Z9P!8BM`FK@D!9*!ZQ]]/D1SF[%RG.D+HO(8QI.BK.RS*/C#/GJOTUU/WSTX19$R[$T#'P&L\"]V03\\_Y5_UH!?/!;\"J>YHO%8S_`2]/H`T_'%?B4?AX!.:^X!Z9E0A!!S\"5M\"A:2^?AA2R*9;!.!!&1!!E:AN)7'16,AM\"+\"Y'D0.'*Q=.%!S)!'*S)@5*$7D*9H@#U710\"MUG4,)Z'!F-%15E\"\"J!#+$A0':>#G?1%8G#29I31U:2H\"I:3AK4C&C;ZY\"J[C]HG6!3&*4K!!AP9:IA#T2\"'A%-+9]WWJ*MU3I\"MWY\")$79\"*]QZ@:[ZZ#^43G=Q;!P)E%QN3RZQ4!Y.KP\"J_8\\B/3RD#S6+YB]*&!3M6A+#2Q'9M-&DI!!"; + var c = "]0D`_OP8!0``@``5]0``^@8=`_4%!!!!`_P.!!$`CCPCJ3IKXLC(8Z[A@`]!UGE?`X^1:*8N``D=X\"1]!0``!!#,!)O,O)9,K;GJ!'1!K;GJP<>LCQ#,67MP`YQ!G4,-CQ!![::[D\\S03$W,,U^0,U^0!-\\2F!$4`R34!,``;7FJ;7FJ(J$`MC)C``LQ)IMC`Q$`X.T=_0D``^=!WK5AA)#!!)!!L@]PA)#!]0`Q`WGUT6R=3Q##```Q]/;-ZO<[``$V@0Q!``L.L>DG])#!Y0``_PL3U^04E/[1U^04`\\<\"`[\"[),+KB]\\[>YC:>YC:M-4?```A!0]!-MUS_P$G`Q$`A!!!:MWK!!$.OF84EX$<0,.R?WDO!0K;3.(-RR7&'2FQ^@`[`_4B`_3V`^[N!!#!`@8GA)!!;YYD`[5!`U5!WH$7\\OCKG0O9L_\\OWX#4`_`6`^KZT95``]$,X;$>M/$GA!#!`Q!!P)_017HBCU54_I\"S^+2A,IN8``8OI&)NQ-$!B]\\L;FL.=)#1=)#1``L[!0^`2I+UUL3-!)#!W,`9`W.(1/$1\\I,O^>[T````^@8V``]!GMUS!!!!"; + var B = function(f){ var t = this; t.f = f; t.y = t.t = 0; t.x = f.charCodeAt(0) - 33; }; + B.prototype.g = function(b){ + var r = 0, t = this; + while(b){ + var w = Math.min(b, 6 - t.t), v = t.x >>> (6 - t.t - w); + r <<= w; r |= v & ~(~0 << w); + if((t.t += w) == 6){ t.x = t.f.charCodeAt(++t.y) - 33; t.t = 0; } + b -= w; + } + return r; + }; + var D = function(n, w){ + this.c = new Array(n); this.w = w; this.p = -1; + for(var i = 0; i < n; ++i){ this.c[i] = [i + 97]; } + }; + D.prototype.d = function(s){ + var c = s.g(this.w), t = this, v; + if(c < t.c.length){ + v = t.c[c]; + if(t.p >= 0){ + t.c.push(t.c[t.p].concat(v[0])); + } + }else{ + t.c.push([]); + ++t.w; + return []; + } + t.p = c; + return v; + }; + var i = new B(n), d = new D(27, 5), t = []; + while(t.length < 1455){ + var v = d.d(i); + dojo.forEach(v, function(x){ t.push(x); }); + } + var n2 = dojo.map(t, function(x){ return String.fromCharCode(x); }).join("").split("{"); + i = new B(c); + for(var j = 0; j < n2.length; ++j){ + dojox.encoding.tests.compression.colors3[n2[j]] = [i.g(8), i.g(8), i.g(8)]; + } +})(); + +} diff --git a/includes/js/dojox/encoding/tests/compression/lzw.js b/includes/js/dojox/encoding/tests/compression/lzw.js new file mode 100644 index 0000000..7956a0e --- /dev/null +++ b/includes/js/dojox/encoding/tests/compression/lzw.js @@ -0,0 +1,54 @@ +if(!dojo._hasResource["dojox.encoding.tests.compression.lzw"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.compression.lzw"] = true; +dojo.provide("dojox.encoding.tests.compression.lzw"); +dojo.require("dojox.encoding.compression.lzw"); +dojo.require("dojox.encoding.bits"); + +(function(){ + var msg1 = "The rain in Spain falls mainly on the plain."; + var msg2 = "The rain in Spain falls mainly on the plain.1"; + var msg3 = "The rain in Spain falls mainly on the plain.ab"; + var msg4 = "The rain in Spain falls mainly on the plain.!@#"; + var dc = dojox.encoding.compression, dcb = dojox.encoding.bits, dcl = dc.lzw; + + var s2b = function(s){ + var b = []; + for(var i = 0; i < s.length; ++i){ + b.push(s.charCodeAt(i)); + } + return b; + }; + + var b2s = function(b){ + var s = []; + dojo.forEach(b, function(c){ s.push(String.fromCharCode(c)); }); + return s.join(""); + }; + + var encode = function(msg){ + var x = new dcb.OutputStream(), encoder = new dcl.Encoder(128); + dojo.forEach(s2b(msg), function(v){ encoder.encode(v, x); }); + encoder.flush(x); + console.debug("bits =", x.getWidth()); + return x.getBuffer(); + }; + + var decode = function(n, buf){ + var x = new dcb.InputStream(buf, buf.length * 8), decoder = new dcl.Decoder(128), t = [], w = 0; + while(w < n){ + var v = decoder.decode(x); + t.push(v); + w += v.length; + } + return t.join(""); + }; + + tests.register("dojox.encoding.tests.compression.lzw", [ + function testLzwMsg1(t){ t.assertEqual(msg1, decode(msg1.length, encode(msg1))); }, + function testLzwMsg2(t){ t.assertEqual(msg2, decode(msg2.length, encode(msg2))); }, + function testLzwMsg3(t){ t.assertEqual(msg3, decode(msg3.length, encode(msg3))); }, + function testLzwMsg4(t){ t.assertEqual(msg4, decode(msg4.length, encode(msg4))); } + ]); +})(); + +} diff --git a/includes/js/dojox/encoding/tests/compression/runTests.html b/includes/js/dojox/encoding/tests/compression/runTests.html new file mode 100644 index 0000000..4a24eef --- /dev/null +++ b/includes/js/dojox/encoding/tests/compression/runTests.html @@ -0,0 +1,9 @@ + + + DojoX Compression Unit Test Runner + + + +

      Redirecting to D.O.H runner.

      + + diff --git a/includes/js/dojox/encoding/tests/compression/splay.js b/includes/js/dojox/encoding/tests/compression/splay.js new file mode 100644 index 0000000..44d157c --- /dev/null +++ b/includes/js/dojox/encoding/tests/compression/splay.js @@ -0,0 +1,49 @@ +if(!dojo._hasResource["dojox.encoding.tests.compression.splay"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.compression.splay"] = true; +dojo.provide("dojox.encoding.tests.compression.splay"); +dojo.require("dojox.encoding.compression.splay"); +dojo.require("dojox.encoding.bits"); + +(function(){ + var msg1 = "The rain in Spain falls mainly on the plain."; + var msg2 = "The rain in Spain falls mainly on the plain.1"; + var msg3 = "The rain in Spain falls mainly on the plain.ab"; + var msg4 = "The rain in Spain falls mainly on the plain.!@#"; + var dc = dojox.encoding.compression, dcb = dojox.encoding.bits; + + var s2b = function(s){ + var b = []; + for(var i = 0; i < s.length; ++i){ + b.push(s.charCodeAt(i)); + } + return b; + }; + + var b2s = function(b){ + var s = []; + dojo.forEach(b, function(c){ s.push(String.fromCharCode(c)); }); + return s.join(""); + }; + + var encode = function(msg){ + var x = new dcb.OutputStream(), encoder = new dc.Splay(256); + dojo.forEach(s2b(msg), function(v){ encoder.encode(v, x); }); + console.debug("bits =", x.getWidth()); + return x.getBuffer(); + }; + + var decode = function(n, buf){ + var x = new dcb.InputStream(buf, buf.length * 8), decoder = new dc.Splay(256), t = []; + for(var i = 0; i < n; ++i){ t.push(decoder.decode(x)); } + return b2s(t); + }; + + tests.register("dojox.encoding.tests.compression.splay", [ + function testSplayMsg1(t){ t.assertEqual(msg1, decode(msg1.length, encode(msg1))); }, + function testSplayMsg2(t){ t.assertEqual(msg2, decode(msg2.length, encode(msg2))); }, + function testSplayMsg3(t){ t.assertEqual(msg3, decode(msg3.length, encode(msg3))); }, + function testSplayMsg4(t){ t.assertEqual(msg4, decode(msg4.length, encode(msg4))); } + ]); +})(); + +} diff --git a/includes/js/dojox/encoding/tests/compression/test.html b/includes/js/dojox/encoding/tests/compression/test.html new file mode 100644 index 0000000..8f07c59 --- /dev/null +++ b/includes/js/dojox/encoding/tests/compression/test.html @@ -0,0 +1,61 @@ + + + Test colors + + + + + + + +

      Test colors

      +

      +
      No status yet.
      + + diff --git a/includes/js/dojox/encoding/tests/compression/vq.html b/includes/js/dojox/encoding/tests/compression/vq.html new file mode 100644 index 0000000..7805bd4 --- /dev/null +++ b/includes/js/dojox/encoding/tests/compression/vq.html @@ -0,0 +1,185 @@ + + + Compress colors using VQ + + + + + + +

      Compress colors using VQ

      +

      Select desirable number of clusters:  

      +
      No status yet.
      +
      No results yet.
      + + diff --git a/includes/js/dojox/encoding/tests/crypto/Blowfish.js b/includes/js/dojox/encoding/tests/crypto/Blowfish.js new file mode 100644 index 0000000..3f5ac54 --- /dev/null +++ b/includes/js/dojox/encoding/tests/crypto/Blowfish.js @@ -0,0 +1,35 @@ +if(!dojo._hasResource["dojox.encoding.tests.crypto.Blowfish"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.crypto.Blowfish"] = true; +dojo.provide("dojox.encoding.tests.crypto.Blowfish"); +dojo.require("dojox.encoding.crypto.Blowfish"); + +(function(){ + var message="The rain in Spain falls mainly on the plain."; + var key="foobar"; + var base64Encrypted="WI5J5BPPVBuiTniVcl7KlIyNMmCosmKTU6a/ueyQuoUXyC5dERzwwdzfFsiU4vBw"; + var dxc=dojox.encoding.crypto; + + tests.register("dojox.encoding.crypto.tests.Blowfish", [ + function testEncrypt(t){ + var dt=new Date(); + t.assertEqual(base64Encrypted, dxc.Blowfish.encrypt(message, key)); + doh.debug("testEncrypt: ", new Date()-dt, "ms."); + }, + function testDecrypt(t){ + var dt=new Date(); + t.assertEqual(message, dxc.Blowfish.decrypt(base64Encrypted, key)); + doh.debug("testDecrypt: ", new Date()-dt, "ms."); + }, + function testShortMessage(t){ + var msg="pass"; + var pwd="foobar"; + var dt=new Date(); + var enc=dxc.Blowfish.encrypt(msg, pwd); + var dec=dxc.Blowfish.decrypt(enc, pwd); + t.assertEqual(dec, msg); + doh.debug("testShortMessage: ", new Date()-dt, "ms."); + } + ]); +})(); + +} diff --git a/includes/js/dojox/encoding/tests/crypto/_base.js b/includes/js/dojox/encoding/tests/crypto/_base.js new file mode 100644 index 0000000..24dc044 --- /dev/null +++ b/includes/js/dojox/encoding/tests/crypto/_base.js @@ -0,0 +1,12 @@ +if(!dojo._hasResource["dojox.encoding.tests.crypto._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.crypto._base"] = true; +dojo.provide("dojox.encoding.tests.crypto._base"); +dojo.require("dojox.encoding.crypto.Blowfish"); + +try{ + dojo.require("dojox.encoding.tests.crypto.Blowfish"); +}catch(e){ + doh.debug(e); +} + +} diff --git a/includes/js/dojox/encoding/tests/crypto/runTests.html b/includes/js/dojox/encoding/tests/crypto/runTests.html new file mode 100644 index 0000000..31e54ed --- /dev/null +++ b/includes/js/dojox/encoding/tests/crypto/runTests.html @@ -0,0 +1,9 @@ + + + + Dojox.wire Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/encoding/tests/digests/MD5.js b/includes/js/dojox/encoding/tests/digests/MD5.js new file mode 100644 index 0000000..8bfcfeb --- /dev/null +++ b/includes/js/dojox/encoding/tests/digests/MD5.js @@ -0,0 +1,26 @@ +if(!dojo._hasResource["dojox.encoding.tests.digests.MD5"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.digests.MD5"] = true; +dojo.provide("dojox.encoding.tests.digests.MD5"); +dojo.require("dojox.encoding.digests.MD5"); + +(function(){ + var message="The rain in Spain falls mainly on the plain."; + var base64="OUhxbVZ1Mtmu4zx9LzS5cA=="; + var hex="3948716d567532d9aee33c7d2f34b970"; + var s="9HqmVu2\xD9\xAE\xE3<}/4\xB9p"; + var ded=dojox.encoding.digests; + + tests.register("dojox.encoding.tests.digests.MD5", [ + function testBase64Compute(t){ + t.assertEqual(base64, ded.MD5(message)); + }, + function testHexCompute(t){ + t.assertEqual(hex, ded.MD5(message, ded.outputTypes.Hex)); + }, + function testStringCompute(t){ + t.assertEqual(s, ded.MD5(message, ded.outputTypes.String)); + } + ]); +})(); + +} diff --git a/includes/js/dojox/encoding/tests/digests/_base.js b/includes/js/dojox/encoding/tests/digests/_base.js new file mode 100644 index 0000000..a2bc2fd --- /dev/null +++ b/includes/js/dojox/encoding/tests/digests/_base.js @@ -0,0 +1,12 @@ +if(!dojo._hasResource["dojox.encoding.tests.digests._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.digests._base"] = true; +dojo.provide("dojox.encoding.tests.digests._base"); +dojo.require("dojox.encoding.digests._base"); + +try{ + dojo.require("dojox.encoding.tests.digests.MD5"); +}catch(e){ + doh.debug(e); +} + +} diff --git a/includes/js/dojox/encoding/tests/digests/runTests.html b/includes/js/dojox/encoding/tests/digests/runTests.html new file mode 100644 index 0000000..6c41e6e --- /dev/null +++ b/includes/js/dojox/encoding/tests/digests/runTests.html @@ -0,0 +1,9 @@ + + + + Dojox.wire Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/encoding/tests/easy64.js b/includes/js/dojox/encoding/tests/easy64.js new file mode 100644 index 0000000..93876b1 --- /dev/null +++ b/includes/js/dojox/encoding/tests/easy64.js @@ -0,0 +1,35 @@ +if(!dojo._hasResource["dojox.encoding.tests.easy64"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.easy64"] = true; +dojo.provide("dojox.encoding.tests.easy64"); +dojo.require("dojox.encoding.easy64"); + +(function(){ + var msg1 = "The rain in Spain falls mainly on the plain."; + var msg2 = "The rain in Spain falls mainly on the plain.1"; + var msg3 = "The rain in Spain falls mainly on the plain.ab"; + var msg4 = "The rain in Spain falls mainly on the plain.!@#"; + var dce = dojox.encoding.easy64; + + var s2b = function(s){ + var b = []; + for(var i = 0; i < s.length; ++i){ + b.push(s.charCodeAt(i)); + } + return b; + }; + + var b2s = function(b){ + var s = []; + dojo.forEach(b, function(c){ s.push(String.fromCharCode(c)); }); + return s.join(""); + }; + + tests.register("dojox.encoding.tests.easy64", [ + function testEasyMsg1(t){ t.assertEqual(msg1, b2s(dce.decode(dce.encode(s2b(msg1))))); }, + function testEasyMsg2(t){ t.assertEqual(msg2, b2s(dce.decode(dce.encode(s2b(msg2))))); }, + function testEasyMsg3(t){ t.assertEqual(msg3, b2s(dce.decode(dce.encode(s2b(msg3))))); }, + function testEasyMsg4(t){ t.assertEqual(msg4, b2s(dce.decode(dce.encode(s2b(msg4))))); } + ]); +})(); + +} diff --git a/includes/js/dojox/encoding/tests/encoding.js b/includes/js/dojox/encoding/tests/encoding.js new file mode 100644 index 0000000..9d492cd --- /dev/null +++ b/includes/js/dojox/encoding/tests/encoding.js @@ -0,0 +1,13 @@ +if(!dojo._hasResource["dojox.encoding.tests.encoding"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.encoding.tests.encoding"] = true; +dojo.provide("dojox.encoding.tests.encoding"); + +try{ + dojo.require("dojox.encoding.tests.ascii85"); + dojo.require("dojox.encoding.tests.easy64"); + dojo.require("dojox.encoding.tests.bits"); +}catch(e){ + doh.debug(e); +} + +} diff --git a/includes/js/dojox/encoding/tests/runTests.html b/includes/js/dojox/encoding/tests/runTests.html new file mode 100644 index 0000000..b79c2d9 --- /dev/null +++ b/includes/js/dojox/encoding/tests/runTests.html @@ -0,0 +1,9 @@ + + + DojoX Compression Unit Test Runner + + + +

      Redirecting to D.O.H runner.

      + + diff --git a/includes/js/dojox/flash.js b/includes/js/dojox/flash.js new file mode 100644 index 0000000..75e2752 --- /dev/null +++ b/includes/js/dojox/flash.js @@ -0,0 +1,6 @@ +if(!dojo._hasResource["dojox.flash"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.flash"] = true; +dojo.provide("dojox.flash"); +dojo.require("dojox.flash._base"); + +} diff --git a/includes/js/dojox/flash/DojoExternalInterface.as b/includes/js/dojox/flash/DojoExternalInterface.as new file mode 100644 index 0000000..d857968 --- /dev/null +++ b/includes/js/dojox/flash/DojoExternalInterface.as @@ -0,0 +1,168 @@ +/** + A wrapper around Flash 8's ExternalInterface; this is needed + because ExternalInterface has a number of serialization bugs that we + need to correct for. + + @author Brad Neuberg +*/ + +import flash.external.ExternalInterface; + +class DojoExternalInterface{ + public static var available:Boolean; + public static var dojoPath = ""; + + public static function initialize(){ + //trace("DojoExternalInterface.initialize"); + + // extract the dojo base path + DojoExternalInterface.dojoPath = DojoExternalInterface.getDojoPath(); + + // see if we need to do an express install + var install:ExpressInstall = new ExpressInstall(); + if(install.needsUpdate){ + install.init(); + } + + // set whether communication is available + DojoExternalInterface.available = ExternalInterface.available; + } + + /** Called when we are finished adding methods through addCallback. */ + public static function done(){ + //trace("done"); + DojoExternalInterface.call("dojox.flash.loaded"); + } + + public static function addCallback(methodName:String, instance:Object, + method:Function):Boolean{ + //trace("addCallback"); + ExternalInterface.addCallback(methodName, instance, function(){ + instance = (instance) ? instance : null; + var params = []; + if(arguments && arguments.length){ + for(var i = 0; i < arguments.length; i++){ + params[i] = DojoExternalInterface.decodeData(arguments[i]); + } + } + + var results = method.apply(instance, params); + results = DojoExternalInterface.encodeData(results); + + return results; + }); + + // tell JavaScript about DojoExternalInterface new method so we can create a proxy + ExternalInterface.call("dojox.flash.comm._addExternalInterfaceCallback", + methodName); + + return true; + } + + public static function call(methodName:String):Void{ + // we might have any number of optional arguments, so we have to + // pass them in dynamically; strip out the results callback + var parameters = new Array(); + for(var i = 0; i < arguments.length; i++){ + parameters.push(arguments[i]); + } + + // FIXME: Should we be encoding or decoding the data to get + // around Flash's serialization bugs? + + var results = ExternalInterface.call.apply(ExternalInterface, parameters); + + return results; + } + + /** + Called by Flash to indicate to JavaScript that we are ready to have + our Flash functions called. Calling loaded() + will fire the dojox.flash.loaded() event, so that JavaScript can know that + Flash has finished loading and adding its callbacks, and can begin to + interact with the Flash file. + */ + public static function loaded(){ + DojoExternalInterface.call("dojox.flash.loaded"); + } + + /** + Utility trace implementation that prints out to console.debug. + */ + public static function trace(msg){ + DojoExternalInterface.call("console.debug", "FLASH: " + msg); + } + + private static function decodeData(data):String{ + if(!data || typeof data != "string"){ + return data; + } + + // we have to use custom encodings for certain characters when passing + // them over; for example, passing a backslash over as //// from JavaScript + // to Flash doesn't work + data = replaceStr(data, "&custom_backslash;", "\\"); + + data = replaceStr(data, "\\\'", "\'"); + data = replaceStr(data, "\\\"", "\""); + + return data; + } + + private static function encodeData(data):String{ + if(!data || typeof data != "string"){ + return data; + } + + // certain XMLish characters break Flash's wire serialization for + // ExternalInterface; encode these into a custom encoding, rather than + // the standard entity encoding, because otherwise we won't be able to + // differentiate between our own encoding and any entity characters + // that are being used in the string itself + data = replaceStr(data, '<', '&custom_lt;'); + data = replaceStr(data, '>', '&custom_gt;'); + + // needed for IE + data = replaceStr(data, '\\', '&custom_backslash;'); + + // encode control characters and JavaScript delimiters + data = replaceStr(data, "\n", "\\n"); + data = replaceStr(data, "\r", "\\r"); + data = replaceStr(data, "\f", "\\f"); + data = replaceStr(data, "'", "\\'"); + data = replaceStr(data, '"', '\"'); + + return data; + } + + /** + Flash ActionScript has no String.replace method or support for + Regular Expressions! We roll our own very simple one. + */ + public static function replaceStr(inputStr:String, replaceThis:String, + withThis:String):String{ + var splitStr = inputStr.split(replaceThis); + if(!splitStr){ + return inputStr; + } + + inputStr = splitStr.join(withThis); + return inputStr; + } + + private static function getDojoPath(){ + var url = _root._url; + var start = url.indexOf("baseUrl=") + "baseUrl=".length; + var path = url.substring(start); + var end = path.indexOf("&"); + if(end != -1){ + path = path.substring(0, end); + } + + // some browsers append a junk string at the end: '%20'%20quality= + if(path.indexOf("'%20'%20quality=") != -1){ + path = path.substring(0, path.indexOf("'%20'%20quality=")); + } + return path; + } +} diff --git a/includes/js/dojox/flash/ExpressInstall.as b/includes/js/dojox/flash/ExpressInstall.as new file mode 100644 index 0000000..1801171 --- /dev/null +++ b/includes/js/dojox/flash/ExpressInstall.as @@ -0,0 +1,71 @@ +/** + * Based on the expressinstall.as class created by Geoff Stearns as part + * of the FlashObject library. + * + * Use this file to invoke the Macromedia Flash Player Express Install functionality + * This file is intended for use with the FlashObject embed script. You can download FlashObject + * and this file at the following URL: http://blog.deconcept.com/flashobject/ + * + * Usage: + * var ExpressInstall = new ExpressInstall(); + * + * // test to see if install is needed: + * if (ExpressInstall.needsUpdate) { // returns true if update is needed + * ExpressInstall.init(); // starts the update + * } + * + * NOTE: Your Flash movie must be at least 214px by 137px in order to use ExpressInstall. + * + */ + +class ExpressInstall{ + public var needsUpdate:Boolean; + private var updater:MovieClip; + private var hold:MovieClip; + + public function ExpressInstall(){ + // does the user need to update? + this.needsUpdate = (_root.MMplayerType == undefined) ? false : true; + } + + public function init():Void{ + this.loadUpdater(); + } + + public function loadUpdater():Void{ + System.security.allowDomain("fpdownload.macromedia.com"); + + // hope that nothing is at a depth of 10000000, you can change this depth if needed, but you want + // it to be on top of your content if you have any stuff on the first frame + this.updater = _root.createEmptyMovieClip("expressInstallHolder", 10000000); + + // register the callback so we know if they cancel or there is an error + var _self = this; + this.updater.installStatus = _self.onInstallStatus; + this.hold = this.updater.createEmptyMovieClip("hold", 1); + + // can't use movieClipLoader because it has to work in 6.0.65 + this.updater.onEnterFrame = function():Void { + if(typeof this.hold.startUpdate == 'function'){ + _self.initUpdater(); + this.onEnterFrame = null; + } + } + + var cacheBuster:Number = Math.random(); + + this.hold.loadMovie("http://fpdownload.macromedia.com/pub/flashplayer/" + +"update/current/swf/autoUpdater.swf?"+ cacheBuster); + } + + private function initUpdater():Void{ + this.hold.redirectURL = _root.MMredirectURL; + this.hold.MMplayerType = _root.MMplayerType; + this.hold.MMdoctitle = _root.MMdoctitle; + this.hold.startUpdate(); + } + + public function onInstallStatus(msg):Void{ + getURL("javascript:dojox.flash.install._onInstallStatus('"+msg+"')"); + } +} diff --git a/includes/js/dojox/flash/README b/includes/js/dojox/flash/README new file mode 100644 index 0000000..e01f3be --- /dev/null +++ b/includes/js/dojox/flash/README @@ -0,0 +1,31 @@ +------------------------------------------------------------------------------- +dojox.flash +------------------------------------------------------------------------------- +Version 0.4 +Release date: MM/DD/YYYY +------------------------------------------------------------------------------- +Project state: experimental (currently broken) +------------------------------------------------------------------------------- +Project authors + Brad Neuberg (BradNeuberg@dojotoolkit.org) + Alex Russell (alex@dojotoolkit.org, only handled minor porting issues) +------------------------------------------------------------------------------- +Project description + +Infrastructure for high-performance Flash/JS communication +------------------------------------------------------------------------------- +Dependencies: + +MTASC for creating builds +------------------------------------------------------------------------------- +Documentation + +TODOC +------------------------------------------------------------------------------- +Installation instructions + +Not intended as a stand-alone module. +------------------------------------------------------------------------------- +Additional Notes + +TODOC diff --git a/includes/js/dojox/flash/_base.js b/includes/js/dojox/flash/_base.js new file mode 100644 index 0000000..5a372dd --- /dev/null +++ b/includes/js/dojox/flash/_base.js @@ -0,0 +1,762 @@ +if(!dojo._hasResource["dojox.flash._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.flash._base"] = true; +dojo.provide("dojox.flash._base"); + +// for dijit.getViewport(), needed by dojox.flash.Embed.center() +dojo.require("dijit._base.place"); + +dojox.flash = function(){ + // summary: + // The goal of dojox.flash is to make it easy to extend Flash's capabilities + // into an Ajax/DHTML environment. + // + // dojox.flash provides an easy object for interacting with the Flash plugin. + // This object provides methods to determine the current version of the Flash + // plugin (dojox.flash.info); write out the necessary markup to + // dynamically insert a Flash object into the page (dojox.flash.Embed; and + // do dynamic installation and upgrading of the current Flash plugin in + // use (dojox.flash.Install). If you want to call methods on the Flash object + // embedded into the page it is your responsibility to use Flash's ExternalInterface + // API and get a reference to the Flash object yourself. + // + // To use dojox.flash, you must first wait until Flash is finished loading + // and initializing before you attempt communication or interaction. + // To know when Flash is finished use dojo.connect: + // + // dojo.connect(dojox.flash, "loaded", myInstance, "myCallback"); + // + // Then, while the page is still loading provide the file name: + // + // dojox.flash.setSwf(dojo.moduleUrl("dojox", "_storage/storage.swf")); + // + // If no SWF files are specified, then Flash is not initialized. + // + // Your Flash must use Flash's ExternalInterface to expose Flash methods and + // to call JavaScript. + // + // setSwf can take an optional 'visible' attribute to control whether + // the Flash object is visible or not on the page; the default is visible: + // + // dojox.flash.setSwf(dojo.moduleUrl("dojox", "_storage/storage.swf"), + // false); + // + // Once finished, you can query Flash version information: + // + // dojox.flash.info.version + // + // Or can communicate with Flash methods that were exposed: + // + // var f = dojox.flash.get(); + // var results = f.sayHello("Some Message"); + // + // Your Flash files should use DojoExternalInterface.as to register methods; + // this file wraps Flash's normal ExternalInterface but correct various + // serialization bugs that ExternalInterface has. + // + // Note that dojox.flash is not meant to be a generic Flash embedding + // mechanism; it is as generic as necessary to make Dojo Storage's + // Flash Storage Provider as clean and modular as possible. If you want + // a generic Flash embed mechanism see SWFObject + // (http://blog.deconcept.com/swfobject/). + // + // Notes: + // Note that dojox.flash can currently only work with one Flash object + // on the page; it does not yet support multiple Flash objects on + // the same page. + // + // Your code can detect whether the Flash player is installing or having + // its version revved in two ways. First, if dojox.flash detects that + // Flash installation needs to occur, it sets dojox.flash.info.installing + // to true. Second, you can detect if installation is necessary with the + // following callback: + // + // dojo.connect(dojox.flash, "installing", myInstance, "myCallback"); + // + // You can use this callback to delay further actions that might need Flash; + // when installation is finished the full page will be refreshed and the + // user will be placed back on your page with Flash installed. + // + // ------------------- + // Todo/Known Issues + // ------------------- + // * On Internet Explorer, after doing a basic install, the page is + // not refreshed or does not detect that Flash is now available. The way + // to fix this is to create a custom small Flash file that is pointed to + // during installation; when it is finished loading, it does a callback + // that says that Flash installation is complete on IE, and we can proceed + // to initialize the dojox.flash subsystem. + // * Things aren't super tested for sending complex objects to Flash + // methods, since Dojo Storage only needs strings + // + // Author- Brad Neuberg, http://codinginparadise.org +} + +dojox.flash = { + ready: false, + url: null, + + _visible: true, + _loadedListeners: new Array(), + _installingListeners: new Array(), + + setSwf: function(/* String */ url, /* boolean? */ visible){ + // summary: Sets the SWF files and versions we are using. + // url: String + // The URL to this Flash file. + // visible: boolean? + // Whether the Flash file is visible or not. If it is not visible we hide it off the + // screen. This defaults to true (i.e. the Flash file is visible). + this.url = url; + + if(typeof visible != "undefined"){ + this._visible = visible; + } + + // initialize ourselves + this._initialize(); + }, + + addLoadedListener: function(/* Function */ listener){ + // summary: + // Adds a listener to know when Flash is finished loading. + // Useful if you don't want a dependency on dojo.event. + // listener: Function + // A function that will be called when Flash is done loading. + + this._loadedListeners.push(listener); + }, + + addInstallingListener: function(/* Function */ listener){ + // summary: + // Adds a listener to know if Flash is being installed. + // Useful if you don't want a dependency on dojo.event. + // listener: Function + // A function that will be called if Flash is being + // installed + + this._installingListeners.push(listener); + }, + + loaded: function(){ + // summary: Called back when the Flash subsystem is finished loading. + // description: + // A callback when the Flash subsystem is finished loading and can be + // worked with. To be notified when Flash is finished loading, add a + // loaded listener: + // + // dojox.flash.addLoadedListener(loadedListener); + + dojox.flash.ready = true; + if(dojox.flash._loadedListeners.length > 0){ + for(var i = 0;i < dojox.flash._loadedListeners.length; i++){ + dojox.flash._loadedListeners[i].call(null); + } + } + }, + + installing: function(){ + // summary: Called if Flash is being installed. + // description: + // A callback to know if Flash is currently being installed or + // having its version revved. To be notified if Flash is installing, connect + // your callback to this method using the following: + // + // dojo.event.connect(dojox.flash, "installing", myInstance, "myCallback"); + + if(dojox.flash._installingListeners.length > 0){ + for(var i = 0; i < dojox.flash._installingListeners.length; i++){ + dojox.flash._installingListeners[i].call(null); + } + } + }, + + // Initializes dojox.flash. + _initialize: function(){ + //console.debug("dojox.flash._initialize"); + // see if we need to rev or install Flash on this platform + var installer = new dojox.flash.Install(); + dojox.flash.installer = installer; + + if(installer.needed() == true){ + installer.install(); + }else{ + // write the flash object into the page + dojox.flash.obj = new dojox.flash.Embed(this._visible); + dojox.flash.obj.write(); + + // setup the communicator + dojox.flash.comm = new dojox.flash.Communicator(); + } + } +}; + + +dojox.flash.Info = function(){ + // summary: A class that helps us determine whether Flash is available. + // description: + // A class that helps us determine whether Flash is available, + // it's major and minor versions, and what Flash version features should + // be used for Flash/JavaScript communication. Parts of this code + // are adapted from the automatic Flash plugin detection code autogenerated + // by the Macromedia Flash 8 authoring environment. + // + // An instance of this class can be accessed on dojox.flash.info after + // the page is finished loading. + // + // This constructor must be called before the page is finished loading. + + // Visual basic helper required to detect Flash Player ActiveX control + // version information on Internet Explorer + if(dojo.isIE){ + document.write([ + ' + + + + + +

      Test Dojox Flash

      + +

      For detailed test output see Firebug console (if Firefox). + This test should be run on Firefox, Internet Explorer, and Safari + to confirm that Dojox Flash is working correctly.

      + + \ No newline at end of file diff --git a/includes/js/dojox/flash/tests/test_flash.js b/includes/js/dojox/flash/tests/test_flash.js new file mode 100644 index 0000000..1b26eb2 --- /dev/null +++ b/includes/js/dojox/flash/tests/test_flash.js @@ -0,0 +1,155 @@ +// TODO: FIXME: Refactor this to use D.O.H. instead of its own assertions + +dojo.require("dojox.flash"); + +var flashLoaded = false; +var pageLoaded = false; +var testXML = testBook = null; + +function flashReady(){ + console.debug("flashReady"); + flashLoaded = true; + + if(isReady()){ + run(); + } +} + +function pageReady(){ + console.debug("pageReady"); + pageLoaded = true; + + loadResources(); + + if(isReady()){ + run(); + } +} + +function isReady(){ + return testXML && testBook && pageLoaded && flashLoaded; +} + +function loadResources(){ + console.debug("Trying to load resources"); + + var d = dojo.xhrGet({ + url: "../../storage/tests/resources/testXML.xml", + handleAs: "text" + }); + + d.addCallback(function(results){ + console.debug("testXML loaded"); + testXML = results; + if(isReady()){ + run(); + } + }); + + d.addErrback(function(error){ + console.debug("Unable to load testXML.xml: " + error); + }); + + d = dojo.xhrGet({ + url: "../../storage/tests/resources/testBook.txt", + handleAs: "text" + }); + + d.addCallback(function(results){ + console.debug("testBook loaded"); + testBook = results; + if(isReady()){ + run(); + } + }); + + d.addErrback(function(error){ + console.debug("Unable to load testXML.xml: " + error); + }); +} + +function run(){ + console.debug("run"); + try{ + var correct, actual; + + console.debug("Setting simple message..."); + correct = "hello world"; + dojox.flash.comm.setMessage(correct); + actual = dojox.flash.comm.getMessage(); + assert(correct, actual, "Setting/getting simple message did not work"); + + console.debug("Setting message with evil characters..."); + // our correct and actual values get tricky when we have double back + // slashes; do a trick so that they can be compared easier + var doubleSlash = "\\"; + doubleSlash = doubleSlash.charAt(0); + correct = "hello world\n\n\nasdfasdf!@#$@#%^[]{}&" + doubleSlash + + "
      $%^&%^&*^&()<><><>,./;\0\r\f\'][`~=\"+-]MORE!\n\rLESS"; + dojox.flash.comm.setMessage(correct); + actual = dojox.flash.comm.getMessage(); + assert(correct, actual, "Setting/getting message with evil characters did not work"); + + console.debug("Setting testXML..."); + correct = testXML; + dojox.flash.comm.setMessage(correct); + actual = dojox.flash.comm.getMessage(); + assert(correct, actual, "Setting/getting testXML did not work"); + + console.debug("Setting testBook(~300K)..."); + correct = testBook; + dojox.flash.comm.setMessage(correct); + actual = dojox.flash.comm.getMessage(); + assert(correct, actual, "Setting/getting testBook did not work"); + + console.debug("Setting testBook 3 times (~900K)..."); + correct = testBook + testBook + testBook; + dojox.flash.comm.setMessage(correct); + actual = dojox.flash.comm.getMessage(); + assert(correct, actual, "Setting/getting testBook X 3 did not work"); + + console.debug("Setting JSON..."); + var obj = {type: "car", color: "red", model: "Ford", year: "2008", + features: ["A/C", "automatic", "4-wheel drive"]}; + correct = dojo.toJson(obj, true); + dojox.flash.comm.setMessage(correct); + actual = dojox.flash.comm.getMessage(); + assert(correct, actual, "Setting/getting JSON did not work"); + + console.debug("Calling method that takes multiple values..."); + actual = dojox.flash.comm.multipleValues("key", "value", "namespace"); + assert("namespacekeyvalue", actual, "Setting/getting multiple values did not work"); + + var allPassed = document.createElement("p"); + allPassed.style.backgroundColor = "green"; + allPassed.style.color = "white"; + allPassed.style.fontSize = "24pt"; + allPassed.appendChild(document.createTextNode("All tests passed")); + var body = document.getElementsByTagName("body")[0]; + body.appendChild(allPassed); + }catch(e){ + console.debug(e.message || e); + } +} + +function assert(correct, actual, msg){ + //alert("correct="+correct+",\n\nactual="+actual); + if(correct != actual){ + var failed = document.createElement("p"); + failed.style.backgroundColor = "red"; + failed.style.color = "white"; + failed.style.fontSize = "24pt"; + failed.appendChild(document.createTextNode("Test failed: " + msg)); + var body = document.getElementsByTagName("body")[0]; + body.appendChild(failed); + + throw new Error("ASSERTION FAILED: " + msg); + }else{ + console.debug("Assertion passed"); + } +} + +console.debug("adding listeners..."); +dojox.flash.addLoadedListener(flashReady); +dojox.flash.setSwf("TestFlash.swf", true); +dojo.connect(dojo, "loaded", pageReady); diff --git a/includes/js/dojox/form/CheckedMultiSelect.js b/includes/js/dojox/form/CheckedMultiSelect.js new file mode 100644 index 0000000..eb80c72 --- /dev/null +++ b/includes/js/dojox/form/CheckedMultiSelect.js @@ -0,0 +1,223 @@ +if(!dojo._hasResource["dojox.form.CheckedMultiSelect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.form.CheckedMultiSelect"] = true; +dojo.provide("dojox.form.CheckedMultiSelect"); + +dojo.require("dijit.form.MultiSelect"); +dojo.require("dijit.form.CheckBox"); + +dojo.declare("dojox.form._CheckedMultiSelectItem", + [dijit._Widget, dijit._Templated], + { + // summary: + // The individual items for a CheckedMultiSelect + + widgetsInTemplate: true, + templateString:"
      ${option.innerHTML}
      \n", + + baseClass: "dojoxMultiSelectItem", + + // option: Element + // The option that is associated with this item + option: null, + parent: null, + + // disabled: boolean + // Whether or not this widget is disabled + disabled: false, + + _changeBox: function(){ + // summary: + // Called to force the select to match the state of the check box + // (only on click of the checkbox) + this.option.selected = this.checkBox.getValue() && true; + + // fire the parent's change + this.parent._onChange(); + + // refocus the parent + this.parent.focus(); + }, + + _labelClick: function(){ + // summary: + // Called when the label portion is clicked + dojo.stopEvent(e); + if(this.disabled){ + return; + } + var cb = this.checkBox; + cb.setValue(!cb.getValue()); + this._changeBox(); + }, + + _onMouse: function(e){ + // summary: + // Sets the hover state depending on mouse state (passes through + // to the check box) + this.checkBox._onMouse(e); + }, + + _onClick: function(e){ + // summary: + // Sets the click state (passes through to the check box) + this.checkBox._onClick(e); + }, + + _updateBox: function(){ + // summary: + // Called to force the box to match the state of the select + this.checkBox.setValue(this.option.selected); + }, + + setAttribute: function(attr, value){ + // summary: + // Disables (or enables) all the children as well + this.inherited(arguments); + switch(attr){ + case "disabled": + this.checkBox.setAttribute(attr, value); + break; + default: + break; + } + } +}); + +dojo.declare("dojox.form.CheckedMultiSelect", dijit.form.MultiSelect, { + // summary: + // Extends the core dijit MultiSelect to provide a "checkbox" selector + + templateString: "", + templateString:"
      . + + baseClass: "dojoxDropDownSelect", + + /*===== + dojox.form.__SelectOption = function(){ + // value: String + // The value of the option. Setting to empty (or missing) will + // place a separator at that location + // label: String + // The label for our option. It can contain html tags. + this.value = value; + this.label = label; + } + =====*/ + + // options: dojox.form.__SelectOption[] + // our set of options + options: null, + + // emptyLabel: string + // What to display in an "empty" dropdown + emptyLabel: "", + + // _isPopulated: boolean + // Whether or not we have been populated + _isPopulated: false, + + _addMenuItem: function(/* dojox.form.__SelectOption */ option){ + // summary: + // For the given option, add a menu item to our dropdown + // If the option doesn't have a value, then a separator is added + // in that place. + var menu = this.dropDown; + + if(!option.value){ + // We are a separator (no label set for it) + menu.addChild(new dijit.MenuSeparator()); + }else{ + // Just a regular menu option + var click = dojo.hitch(this, "setAttribute","value",option); + var mi = new dijit.MenuItem({ + id: this.id + "_item_" + option.value, + label: option.label, + onClick: click + }); + menu.addChild(mi); + + } + }, + + _resetButtonState: function(){ + // summary: + // Resets the menu and the length attribute of the button - and + // ensures that the label is appropriately set. + var len = this.options.length; + + // reset the menu to make it "populatable on the next click + var dropDown = this.dropDown; + dojo.forEach(dropDown.getChildren(), function(child){ + child.destroyRecursive(); + }); + this._isPopulated = false; + + // Set our length attribute and our value + this.setAttribute("readOnly", (len === 1)); + this.setAttribute("disabled", (len === 0)); + this.setAttribute("value", this.value); + }, + + _updateSelectedState: function(){ + // summary: + // Sets the "selected" class on the item for styling purposes + var val = this.value; + if(val){ + var testId = this.id + "_item_" + val; + dojo.forEach(this.dropDown.getChildren(), function(child){ + dojo[child.id === testId ? "addClass" : "removeClass"](child.domNode, + this.baseClass + "SelectedOption"); + }, this); + } + }, + + addOption: function(/* dojox.form.__SelectOption or string, optional */ value, /* string? */ label){ + // summary: + // Adds an option to the end of the select. If value is empty or + // missing, a separator is created instead. + + this.options.push(value.value ? value : { value:value, label:label }); + }, + + removeOption: function(/* string, dojox.form.__SelectOption or number */ valueOrIdx){ + // summary: + // Removes the given option + this.options = dojo.filter(this.options, function(node, idx){ + return !((typeof valueOrIdx === "number" && idx === valueOrIdx) || + (typeof valueOrIdx === "string" && node.value === valueOrIdx) || + (valueOrIdx.value && node.value === valueOrIdx.value)); + }); + }, + + setOptionLabel: function(/*string*/ value, /*string*/ label){ + dojo.forEach(this.options, function(node){ + if(node.value === value){ + node.label = label; + } + }); + }, + + destroy: function(){ + // summary: + // Clear out an outstanding hack handle + if(this._labelHackHandle){ + clearTimeout(this._labelHackHandle); + } + this.inherited(arguments); + }, + + setLabel: function(/* string */ content){ + // summary: + // Wraps our label in a div - that way, our rich text can work + // correctly. + + content = '
      ' + + content + + '
      '; + // Because FF2 has a problem with layout, we need to delay this + // call for it. + if(this._labelHackHandle){ + clearTimeout(this._labelHackHandle); + } + if(dojo.isFF === 2){ + this._labelHackHandle = setTimeout(dojo.hitch(this, function(){ + this._labelHackHandle = null; + dijit.form.DropDownButton.prototype.setLabel.call(this, content); + }), 0); + }else{ + this.inherited(arguments); + } + }, + + setAttribute: function(/*string*/ attr, /* anything */ value){ + // summary: sometime we get called to set our value - we need to + // make sure and route those requests through _setValue() + // instead. + if(attr === "value"){ + // If a string is passed, then we set our value from looking it up. + if(typeof value === "string"){ + value = dojo.filter(this.options, function(node){ + return node.value === value; + })[0]; + } + + // If we don't have a value, try to show the first item + if(!value){ + value = this.options[0] || { value: "", label: "" }; + } + this.value = value.value; + if(this._started){ + this.setLabel(value.label || this.emptyLabel || " "); + } + this._handleOnChange(value.value); + value = this.value; + }else{ + this.inherited(arguments); + } + }, + + _fillContent: function(){ + // summary: + // Loads our options and sets up our dropdown correctly. We + // don't want any content, so we don't call any inherit chain + // function. + var opts = this.options; + if(!opts){ + opts = this.options = this.srcNodeRef ? dojo.query(">", + this.srcNodeRef).map(function(node){ + if(node.getAttribute("type") === "separator"){ + return { value: "", label: "" }; + } + return { value: node.getAttribute("value"), + label: String(node.innerHTML) }; + }, this) : []; + } + + // Set the value to be the first, or the selected index + if(opts.length && !this.value){ + var si = this.srcNodeRef.selectedIndex; + this.value = opts[si != -1 ? si : 0].value; + } + + // Create the dropDown widget + this.dropDown = new dijit.Menu(); + }, + + postCreate: function(){ + // summary: sets up our event handling that we need for functioning + // as a select + + this.inherited(arguments); + + // Make our event connections for updating state + var fx = function(){ + dojo[this._opened ? "addClass" : "removeClass"](this.focusNode, + this.baseClass + "ButtonOpened"); + }; + this.connect(this, "_openDropDown", fx); + this.connect(this, "_closeDropDown", fx); + this.connect(this, "onChange", "_updateSelectedState"); + this.connect(this, "addOption", "_resetButtonState"); + this.connect(this, "removeOption", "_resetButtonState"); + this.connect(this, "setOptionLabel", "_resetButtonState"); + }, + + startup: function(){ + // summary: + // FF2 has layout problems if the reset call isn't done on a + // slight delay + this.inherited(arguments); + if(dojo.isFF === 2){ + setTimeout(dojo.hitch(this, this._resetButtonState), 0); + }else{ + this._resetButtonState(); + } + }, + + _populate: function(/* function */ callback){ + // summary: + // populates the menu (and does the callback, if passed) + + var dropDown = this.dropDown; + + // Add each menu item + dojo.forEach(this.options, this._addMenuItem, this); + + // Update states + this._updateSelectedState(); + dojo.addClass(this.dropDown.domNode, this.baseClass + "Menu"); + this._isPopulated = true; + if(callback){ callback.call(this); } + }, + + _toggleDropDown: function(){ + // summary: Overrides DropDownButton's toggle function to make sure + // that the values are correctly populated. + var dropDown = this.dropDown; + if(dropDown && !dropDown.isShowingNow && !this._isPopulated){ + this._populate(dojox.form.DropDownSelect.superclass._toggleDropDown); + }else{ + this.inherited(arguments); + } + } +}); + +} diff --git a/includes/js/dojox/form/PasswordValidator.js b/includes/js/dojox/form/PasswordValidator.js new file mode 100644 index 0000000..e147ddf --- /dev/null +++ b/includes/js/dojox/form/PasswordValidator.js @@ -0,0 +1,280 @@ +if(!dojo._hasResource["dojox.form.PasswordValidator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.form.PasswordValidator"] = true; +dojo.provide("dojox.form.PasswordValidator"); + +dojo.require("dijit.form._FormWidget"); +dojo.require("dijit.form.ValidationTextBox"); + +dojo.requireLocalization("dojox.form", "PasswordValidator", null, "ROOT"); + +dojo.declare("dojox.form._ChildTextBox", dijit.form.ValidationTextBox, { + // summary: + // A class that is shared between all our children - extends + // ValidationTextBox and provides some shared functionality + // + // containerWidget: widget + // Our parent (the PasswordValidator) + containerWidget: null, + + // type: string + // Don't override this - we are all "password" types + type: "password", + + reset: function(){ + // summary: + // Force-set to empty string (we don't save passwords EVER)...and + // since _OldPWBox overrides setValue to check for empty string, + // call our parent class directly (not this.inherited()) + dijit.form.ValidationTextBox.prototype.setValue.call(this, "", true); + this._hasBeenBlurred = false; + } +}); + + + +dojo.declare("dojox.form._OldPWBox", dojox.form._ChildTextBox, { + // summary: + // A class representing our "old password" box. + // + // _isPWValid: boolean + // Whether or not the password is valid + _isPWValid: false, + + setValue: function(/* anything */ newVal, /* boolean? */ priority){ + // summary: + // Updates _isPWValid if this isn't our initial update by calling + // our PasswordValidator's pwCheck function + if(newVal === ""){ + newVal = dojox.form._OldPWBox.superclass.getValue.call(this); + } + if(priority !== null){ + // Priority is passed in as null, explicitly when this is an + // update (not initially set). We want to check our password now. + this._isPWValid = this.containerWidget.pwCheck(newVal); + } + this.inherited("setValue", arguments); + }, + + isValid: function(/* boolean */ isFocused){ + // Take into account the isPWValid setting + return this.inherited("isValid", arguments) && this._isPWValid; + }, + + _update: function(/* event */ e){ + // Only call validate() if we've been blurred or else we get popups + // too early. + if(this._hasBeenBlurred){ this.validate(true); } + this._onMouse(e); + }, + + getValue: function(){ + // summary: + // Only returns a value if our container widget is valid. This + // is to prevent exposure of "oldPW" too early. + if(this.containerWidget.isValid()){ + return this.inherited("getValue", arguments); + }else{ + return ""; + } + } +}); + + +dojo.declare("dojox.form._NewPWBox", dojox.form._ChildTextBox, { + // summary: + // A class representing our new password textbox + + // required: boolean + // Whether or not this widget is required (default: true) + required: true, + + onChange: function(){ + // summary: + // Validates our verify box - to make sure that a change to me is + // reflected there + this.containerWidget._inputWidgets[2].validate(false); + this.inherited(arguments); + } +}); + +dojo.declare("dojox.form._VerifyPWBox", dojox.form._ChildTextBox, { + // summary: + // A class representing our verify textbox + + isValid: function(isFocused){ + // summary: + // Validates that we match the "real" password + return this.inherited("isValid", arguments) && + (this.getValue() == this.containerWidget._inputWidgets[1].getValue()); + } +}); + +dojo.declare("dojox.form.PasswordValidator", dijit.form._FormValueWidget, { + // summary: + // A password validation widget that simplifies the "old/new/verify" + // style of requesting passwords. You will probably want to override + // this class and implement your own pwCheck function. + // + // required: boolean + // Whether or not it is required for form submission + required: true, + + // inputWidgets: TextBox[] + // An array of text boxes that are our components + _inputWidgets: null, + + // oldName: string? + // The name to send our old password as (when form is posted) + oldName: "", + + templateString:"
      \n\t\n
      \n", + + _hasBeenBlurred: false, + + isValid: function(/* boolean */ isFocused){ + // summary: we are valid if ALL our children are valid + return dojo.every(this._inputWidgets, function(i){ + if(i && i._setStateClass){ i._setStateClass(); } + return (!i || i.isValid()); + }); + }, + + validate: function(/* boolean */ isFocused){ + // summary: Validating this widget validates all our children + return dojo.every(dojo.map(this._inputWidgets, function(i){ + if(i && i.validate){ + i._hasBeenBlurred = (i._hasBeenBlurred || this._hasBeenBlurred); + return i.validate(); + } + return true; + }, this), "return item;"); + }, + + reset: function(){ + // summary: Resetting this widget resets all our children + this._hasBeenBlurred = false; + dojo.forEach(this._inputWidgets, function(i){ + if(i && i.reset){ i.reset(); } + }, this); + }, + + _createSubWidgets: function(){ + // summary: + // Turns the inputs inside this widget into "real" validation + // widgets - and sets up the needed connections. + var widgets = this._inputWidgets, + msg = dojo.i18n.getLocalization("dojox.form", "PasswordValidator", + this.lang); + dojo.forEach(widgets, function(i, idx){ + if(i){ + var p = {containerWidget: this}, c; + if(idx === 0){ + p.name = this.oldName; + p.invalidMessage = msg.badPasswordMessage; + c = dojox.form._OldPWBox; + }else if(idx === 1){ + p.required = this.required; + c = dojox.form._NewPWBox; + }else if(idx === 2){ + p.invalidMessage = msg.nomatchMessage; + c = dojox.form._VerifyPWBox; + } + widgets[idx] = new c(p, i); + } + }, this); + }, + + pwCheck: function(/* string */ password){ + // summary: + // Overridable function for validation of the old password box. + // + // This function is called and passed the old password. Return + // true if it's OK to continue, and false if it is not. + // + // IMPORTANT SECURITY NOTE: Do NOT EVER EVER EVER check this in + // HTML or JavaScript!!! + // + // You will probably want to override this function to callback + // to a server to verify the password (the callback will need to + // be syncronous) - and it's probably a good idea to validate + // it again on form submission before actually doing + // anything destructive - that's why the "oldName" value + // is available. + // + // And don't just fetch the password from the server + // either :) Send the test password (probably hashed, for + // security) and return from the server a status instead. + // + // Again - DON'T BE INSECURE!!! Security is left as an exercise + // for the reader :) + return false; + }, + + postCreate: function(){ + // summary: + // Sets up the correct widgets. You *MUST* specify one child + // text box (a simple HTML element) with pwType="new" + // *and* one child text box with pwType="verify". You *MAY* + // specify a third child text box with pwType="old" in order to + // prompt the user to enter in their old password before the + // widget returns that it is valid. + + this.inherited(arguments); + + // Turn my inputs into the correct stuff.... + var widgets = this._inputWidgets = []; + dojo.forEach(["old","new","verify"], function(i){ + widgets.push(dojo.query("input[pwType=" + i + "]", + this.containerNode)[0]); + }, this); + if (!widgets[1] || !widgets[2]){ + throw new Error("Need at least pwType=\"new\" and pwType=\"verify\""); + } + if (this.oldName && !widgets[0]){ + throw new Error("Need to specify pwType=\"old\" if using oldName"); + } + this._createSubWidgets(); + }, + + setAttribute: function(/* string */ attr, /* anything */ value){ + this.inherited(arguments); + + // Disabling (or enabling) the container disables (or enables) all + // the subwidgets as well - same for requiring + switch(attr){ + case "disabled": + case "required": + dojo.forEach(this._inputWidgets, function(i){ + if(i && i.setAttribute){ i.setAttribute(attr, value);} + }); + break; + default: + break; + } + }, + + getValue: function(){ + // summary: overridden to return an empty string if we aren't valid. + if (this.isValid()){ + return this._inputWidgets[1].getValue(); + }else{ + return ""; + } + }, + + focus: function(){ + // summary: + // places focus on the first invalid input widget - if all + // input widgets are valid, the first widget is focused. + var f = false; + dojo.forEach(this._inputWidgets, function(i){ + if(i && !i.isValid() && !f){ + i.focus(); + f = true; + } + }); + if(!f){ this._inputWidgets[1].focus(); } + } +}); + +} diff --git a/includes/js/dojox/form/README b/includes/js/dojox/form/README new file mode 100644 index 0000000..3fc4f7c --- /dev/null +++ b/includes/js/dojox/form/README @@ -0,0 +1,39 @@ +------------------------------------------------------------------------------- +dojox.form Collection +------------------------------------------------------------------------------- +Version 1.0 +Release date: 02/26/2008 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + Nathan Toone (nathan) + +------------------------------------------------------------------------------- +Project description + + This is a collection of additional widgets that can be used in forms. +------------------------------------------------------------------------------- +Dependencies: + + Depends on dojo core and dijit +------------------------------------------------------------------------------- +Documentation + +------------------------------------------------------------------------------- +Installation instructions + + Install into /dojox/form +------------------------------------------------------------------------------- +Additional Notes (Brief widget list): + + * CheckedMultiSelect - an extension to dijit.form.MultiSelect which + uses check boxes instead of ctrl-click + + * PasswordValidator - a widget which simplifies the common "old/new/verify" + mechanism of specifying passwords + + * DropDownSelect - an extension to dijit.form.DropDownButton which is + meant to mirror the html
      \ No newline at end of file diff --git a/includes/js/dojox/form/resources/DropDownSelect.css b/includes/js/dojox/form/resources/DropDownSelect.css new file mode 100644 index 0000000..cbd1971 --- /dev/null +++ b/includes/js/dojox/form/resources/DropDownSelect.css @@ -0,0 +1,137 @@ + +.dojoxDropDownSelect { + margin: 0.2em; +} +.dijit_a11y .dojoxDropDownSelectDisabled .dijitButtonNode { + border-style: dotted !important; + border-color: #999 !important; + color:#999 !important; +} +.dojoxDropDownSelect .dijitButtonNode { + padding: 0px; +} +.dijitButtonNode .dojoxDropDownSelectLabel * +{ + vertical-align: baseline; +} +.dojoxDropDownSelectSelectedOption * { + font-weight: bold; +} +.dojoxDropDownSelectDisabled .dijitArrowButtonInner, +.dojoxDropDownSelectReadOnly .dijitArrowButtonInner { + display: none; +} +.dojoxDropDownSelectMenu .dijitMenuItemIcon { + width: 1px; +} +.tundra .dojoxDropDownSelectDisabled * { + cursor: not-allowed !important; +} +.tundra .dojoxDropDownSelectReadOnly * { + cursor: default !important; +} +.tundra .dojoxDropDownSelectDisabled * { + cursor: not-allowed !important; +} +.tundra .dojoxDropDownSelectReadOnly * { + cursor: default !important; +} +.tundra .dojoxDropDownSelect .dijitButtonNode { + background:#fff url("../../../dijit/themes/tundra/images/validationInputBg.png") repeat-x top left; + #background:#fff url('../../../dijit/themes/tundra/images/validationInputBg.gif') repeat-x top left; + border:1px solid #b3b3b3; + line-height: normal; +} +.tundra .dojoxDropDownSelectDisabled .dijitButtonNode { + + border-color: #d5d5d5 #bdbdbd #bdbdbd #d5d5d5; + + background:#e4e4e4 url("../../../dijit/themes/tundra/images/buttonDisabled.png") top repeat-x; + opacity: 0.60; +} +.dj_ie .tundra .dojoxDropDownSelectDisabled .dijitButtonNode * { + filter: gray() alpha(opacity=50); +} +.tundra .dojoxDropDownSelectHover .dijitButtonNode, +.tundra .dojoxDropDownSelect .dojoxDropDownSelectButtonOpened { + + + border-color:#a5beda; + border-bottom-color:#5c7590; + border-right-color:#5c7590; + color:#000; + background:#fcfdff url("../../../dijit/themes/tundra/images/buttonHover.png") repeat-x bottom; +} +.tundra .dojoxDropDownSelectActive .dijitButtonNode { + + border-color:#366dba; + background: #ededed url("../../../dijit/themes/tundra/images/buttonActive.png") bottom repeat-x; +} +.soria .dojoxDropDownSelectDisabled * { + cursor: not-allowed !important; +} +.soria .dojoxDropDownSelectReadOnly * { + cursor: default !important; +} +.soria .dojoxDropDownSelect .dijitButtonNode { + background:#fff url("../../../dijit/themes/soria/images/validationInputBg.png") repeat-x top left; + #background:#fff url('../../../dijit/themes/soria/images/validationInputBg.gif') repeat-x top left; + border:1px solid #8ba0bd; + line-height: normal; +} +.soria .dojoxDropDownSelectDisabled .dijitButtonNode { + + border-color: #b9bbdd #b9bbdd #b9bbdd #b9bbdd; + + background:#c3d3e5 url("../../../dijit/themes/soria/images/buttonDisabled.png") top repeat-x; + opacity: 0.60; +} +.dj_ie .soria .dojoxDropDownSelectDisabled .dijitButtonNode * { + filter: gray() alpha(opacity=50); +} +.soria .dojoxDropDownSelectHover .dijitButtonNode, +.soria .dojoxDropDownSelect .dojoxDropDownSelectButtonOpened { + + + color:#000; + background:#acc5e2 url("../../../dijit/themes/soria/images/buttonHover.png") repeat-x top left; +} +.soria .dojoxDropDownSelectActive .dijitButtonNode { + + border-color:#657c9c; + background: #91b4e5 url("../../../dijit/themes/soria/images/buttonActive.png") top left repeat-x; +} +.nihilo .dojoxDropDownSelectDisabled * { + cursor: not-allowed !important; +} +.nihilo .dojoxDropDownSelectReadOnly * { + cursor: default !important; +} +.nihilo .dojoxDropDownSelect .dijitButtonNode { + background:#fff url("../../../dijit/themes/nihilo/images/validationInputBg.png") repeat-x top left; + #background:#fff url('../../../dijit/themes/nihilo/images/validationInputBg.gif') repeat-x top left; + border:1px solid #d3d3d3; + line-height: normal; +} +.nihilo .dojoxDropDownSelectDisabled .dijitButtonNode { + + border-color: #dedede; + + background:#fafafa url("../../../dijit/themes/nihilo/images/buttonDisabled.png") top repeat-x; + opacity: 0.60; +} +.dj_ie .nihilo .dojoxDropDownSelectDisabled .dijitButtonNode * { + filter: gray() alpha(opacity=50); +} +.nihilo .dojoxDropDownSelectHover .dijitButtonNode, +.nihilo .dojoxDropDownSelect .dojoxDropDownSelectButtonOpened { + + + color:#000; + background:#fcfcfc url("../../../dijit/themes/nihilo/images/buttonHover.png") repeat-x top left; +} +.nihilo .dojoxDropDownSelectActive .dijitButtonNode { + + border-color:#dedede; + background: #f5f5f5 url("../../../dijit/themes/nihilo/images/buttonActive.png") top left repeat-x; +} diff --git a/includes/js/dojox/form/resources/DropDownSelect.css.commented.css b/includes/js/dojox/form/resources/DropDownSelect.css.commented.css new file mode 100644 index 0000000..a0a0636 --- /dev/null +++ b/includes/js/dojox/form/resources/DropDownSelect.css.commented.css @@ -0,0 +1,209 @@ +/* +**---------------------------------------------------------------------------- +** DropDownSelect +**---------------------------------------------------------------------------- +*/ +/* Mirror dijitDropDownButton a bit */ +.dojoxDropDownSelect { + margin: 0.2em; +} +.dijit_a11y .dojoxDropDownSelectDisabled .dijitButtonNode { + border-style: dotted !important; + border-color: #999 !important; + color:#999 !important; +} + +/* And remove the padding - so it looks a "bit" more like a text box */ +.dojoxDropDownSelect .dijitButtonNode { + padding: 0px; +} + +/* Fix the baseline of our label (for multi-size font elements) */ +.dijitButtonNode .dojoxDropDownSelectLabel * +{ + vertical-align: baseline; +} + +/* Styling for the currently-selected option (rich text can mess this up) */ +.dojoxDropDownSelectSelectedOption * { + font-weight: bold; +} + +/* And remove the arrow when we are read-only or disabled (1 or 0 options) */ +.dojoxDropDownSelectDisabled .dijitArrowButtonInner, +.dojoxDropDownSelectReadOnly .dijitArrowButtonInner { + display: none; +} + +/* And hide (at least, mostly) the menuItemIcon column */ +.dojoxDropDownSelectMenu .dijitMenuItemIcon { + width: 1px; +} + +/* +**---------------------------------------------------------------------------- +** Common stylings +**---------------------------------------------------------------------------- +*/ +/* Cursor States */ +.tundra .dojoxDropDownSelectDisabled * { + cursor: not-allowed !important; +} +.tundra .dojoxDropDownSelectReadOnly * { + cursor: default !important; +} + + +/* +**---------------------------------------------------------------------------- +** Tundra stylings +**---------------------------------------------------------------------------- +*/ +/* Cursor States */ +.tundra .dojoxDropDownSelectDisabled * { + cursor: not-allowed !important; +} +.tundra .dojoxDropDownSelectReadOnly * { + cursor: default !important; +} + +/* Make unselected "look" more like a text box and less like a button */ +.tundra .dojoxDropDownSelect .dijitButtonNode { + background:#fff url("../../../dijit/themes/tundra/images/validationInputBg.png") repeat-x top left; + #background:#fff url('../../../dijit/themes/tundra/images/validationInputBg.gif') repeat-x top left; + border:1px solid #b3b3b3; + line-height: normal; +} + +/* Mirror DropDownButton */ +.tundra .dojoxDropDownSelectDisabled .dijitButtonNode { + /* disabled state - inner */ + border-color: #d5d5d5 #bdbdbd #bdbdbd #d5d5d5; + /*color:#b4b4b4;*/ + background:#e4e4e4 url("../../../dijit/themes/tundra/images/buttonDisabled.png") top repeat-x; + opacity: 0.60; /* Safari, Opera and Mozilla */ +} + +.dj_ie .tundra .dojoxDropDownSelectDisabled .dijitButtonNode * { + filter: gray() alpha(opacity=50); /* IE */ +} + +.tundra .dojoxDropDownSelectHover .dijitButtonNode, +.tundra .dojoxDropDownSelect .dojoxDropDownSelectButtonOpened { + /* hover and opened state - inner */ + /* TODO: change from Hover to Selected so that button is still highlighted while drop down is being used */ + border-color:#a5beda; + border-bottom-color:#5c7590; + border-right-color:#5c7590; + color:#000; + background:#fcfdff url("../../../dijit/themes/tundra/images/buttonHover.png") repeat-x bottom; +} + +.tundra .dojoxDropDownSelectActive .dijitButtonNode { + /* active state - inner (for when you are pressing a normal button, or + * when a toggle button is in a depressed state + */ + border-color:#366dba; + background: #ededed url("../../../dijit/themes/tundra/images/buttonActive.png") bottom repeat-x; +} + + +/* +**---------------------------------------------------------------------------- +** Soria stylings +**---------------------------------------------------------------------------- +*/ +/* Cursor States */ +.soria .dojoxDropDownSelectDisabled * { + cursor: not-allowed !important; +} +.soria .dojoxDropDownSelectReadOnly * { + cursor: default !important; +} + +/* Make unselected "look" more like a text box and less like a button */ +.soria .dojoxDropDownSelect .dijitButtonNode { + background:#fff url("../../../dijit/themes/soria/images/validationInputBg.png") repeat-x top left; + #background:#fff url('../../../dijit/themes/soria/images/validationInputBg.gif') repeat-x top left; + border:1px solid #8ba0bd; + line-height: normal; +} + +/* Mirror DropDownButton */ +.soria .dojoxDropDownSelectDisabled .dijitButtonNode { + /* disabled state - inner */ + border-color: #b9bbdd #b9bbdd #b9bbdd #b9bbdd; + /*color:#b4b4b4;*/ + background:#c3d3e5 url("../../../dijit/themes/soria/images/buttonDisabled.png") top repeat-x; + opacity: 0.60; /* Safari, Opera and Mozilla */ +} + +.dj_ie .soria .dojoxDropDownSelectDisabled .dijitButtonNode * { + filter: gray() alpha(opacity=50); /* IE */ +} + +.soria .dojoxDropDownSelectHover .dijitButtonNode, +.soria .dojoxDropDownSelect .dojoxDropDownSelectButtonOpened { + /* hover state - inner */ + /* TODO: change from Hover to Selected so that button is still highlighted while drop down is being used */ + color:#000; + background:#acc5e2 url("../../../dijit/themes/soria/images/buttonHover.png") repeat-x top left; +} + +.soria .dojoxDropDownSelectActive .dijitButtonNode { + /* active state - inner (for when you are pressing a normal button, or + * when a toggle button is in a depressed state + */ + border-color:#657c9c; + background: #91b4e5 url("../../../dijit/themes/soria/images/buttonActive.png") top left repeat-x; +} + +/* +**---------------------------------------------------------------------------- +** Nihilo stylings +**---------------------------------------------------------------------------- +*/ +/* Cursor States */ +.nihilo .dojoxDropDownSelectDisabled * { + cursor: not-allowed !important; +} +.nihilo .dojoxDropDownSelectReadOnly * { + cursor: default !important; +} + +/* Make unselected "look" more like a text box and less like a button */ +.nihilo .dojoxDropDownSelect .dijitButtonNode { + background:#fff url("../../../dijit/themes/nihilo/images/validationInputBg.png") repeat-x top left; + #background:#fff url('../../../dijit/themes/nihilo/images/validationInputBg.gif') repeat-x top left; + border:1px solid #d3d3d3; + line-height: normal; +} + +/* Mirror DropDownButton */ +.nihilo .dojoxDropDownSelectDisabled .dijitButtonNode { + /* disabled state - inner */ + border-color: #dedede; + /*color:#b4b4b4;*/ + background:#fafafa url("../../../dijit/themes/nihilo/images/buttonDisabled.png") top repeat-x; + opacity: 0.60; /* Safari, Opera and Mozilla */ +} + +.dj_ie .nihilo .dojoxDropDownSelectDisabled .dijitButtonNode * { + filter: gray() alpha(opacity=50); /* IE */ +} + +.nihilo .dojoxDropDownSelectHover .dijitButtonNode, +.nihilo .dojoxDropDownSelect .dojoxDropDownSelectButtonOpened { + /* hover state - inner */ + /* TODO: change from Hover to Selected so that button is still highlighted while drop down is being used */ + color:#000; + background:#fcfcfc url("../../../dijit/themes/nihilo/images/buttonHover.png") repeat-x top left; +} + +.nihilo .dojoxDropDownSelectActive .dijitButtonNode { + /* active state - inner (for when you are pressing a normal button, or + * when a toggle button is in a depressed state + */ + border-color:#dedede; + background: #f5f5f5 url("../../../dijit/themes/nihilo/images/buttonActive.png") top left repeat-x; +} diff --git a/includes/js/dojox/form/resources/PasswordValidator.html b/includes/js/dojox/form/resources/PasswordValidator.html new file mode 100644 index 0000000..80a55ae --- /dev/null +++ b/includes/js/dojox/form/resources/PasswordValidator.html @@ -0,0 +1,3 @@ +
      + +
      \ No newline at end of file diff --git a/includes/js/dojox/form/resources/_CheckedMultiSelectItem.html b/includes/js/dojox/form/resources/_CheckedMultiSelectItem.html new file mode 100644 index 0000000..d9ec863 --- /dev/null +++ b/includes/js/dojox/form/resources/_CheckedMultiSelectItem.html @@ -0,0 +1,4 @@ +
      ${option.innerHTML}
      diff --git a/includes/js/dojox/form/tests/test_CheckedMultiSelect.html b/includes/js/dojox/form/tests/test_CheckedMultiSelect.html new file mode 100644 index 0000000..b8729d2 --- /dev/null +++ b/includes/js/dojox/form/tests/test_CheckedMultiSelect.html @@ -0,0 +1,91 @@ + + + + + + + +

      Test: dojox.form.CheckedMultiSelect

      +

      Automated test

      +
      + +
      + +
      + +
      + + + +
      + + diff --git a/includes/js/dojox/form/tests/test_DropDownSelect.html b/includes/js/dojox/form/tests/test_DropDownSelect.html new file mode 100644 index 0000000..4487e54 --- /dev/null +++ b/includes/js/dojox/form/tests/test_DropDownSelect.html @@ -0,0 +1,128 @@ + + + + + + + + +

      Test: dojox.form.DropDownSelect

      +

      Automated test

      +
      +

      Setting Defaults

      + + + +
      +

      Rich Text (Need to use divs and spans - since browsers hack selects to pieces)

      +
      + Alabama + Alaska + Arizona + Arkansas + California + New
        Mexico
      +
      +
      + Copy + Move + No Copy + No Move +
      +
      +

      Empty

      + +
      +

      Single Item

      + +
      + + + + +
      + + diff --git a/includes/js/dojox/form/tests/test_PasswordValidator.html b/includes/js/dojox/form/tests/test_PasswordValidator.html new file mode 100644 index 0000000..e3b1e63 --- /dev/null +++ b/includes/js/dojox/form/tests/test_PasswordValidator.html @@ -0,0 +1,216 @@ + + + + + + + + +

      Test: dojox.form.PasswordValidator

      +

      Automated test

      +

      No old password

      +
      +
      +
      +
      +
      +
      +
      +

      Old password (hard-coded to "oldpw2") - not passed to getValues

      +
      +
      + +
      +
      +
      +
      +
      +
      +

      Old password (hard-coded to "oldpw3") - passed to getValues

      +
      +
      + +
      +
      +
      +
      +
      +
      +

      In Table, Old password (hard-coded to "oldpw4") - not passed to getValues

      +
      +
      + + + + + + + + + + + + + + +
      +
      +
      +
      +

      In Table, Old password (hard-coded to "oldpw5") - passed to getValues

      +
      +
      + + + + + + + + + + + + + + +
      +
      +
      +
      +

      No old password, not required

      +
      +
      +
      +
      +
      +
      +
      + + + + diff --git a/includes/js/dojox/fx.js b/includes/js/dojox/fx.js new file mode 100644 index 0000000..635a570 --- /dev/null +++ b/includes/js/dojox/fx.js @@ -0,0 +1,7 @@ +if(!dojo._hasResource["dojox.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.fx"] = true; +dojo.provide("dojox.fx"); + +dojo.require("dojox.fx._base"); + +} diff --git a/includes/js/dojox/fx/README b/includes/js/dojox/fx/README new file mode 100644 index 0000000..7eb06a8 --- /dev/null +++ b/includes/js/dojox/fx/README @@ -0,0 +1,77 @@ +------------------------------------------------------------------------------- +dojox.fx +------------------------------------------------------------------------------- +Version 1.0.0 +Release date: 10/31/2007 +------------------------------------------------------------------------------- +Project state: +prototype / experimental +------------------------------------------------------------------------------- +Credits + Peter Higgins (dante) + Jonathan Bond-Caron (jbondc@gmail.com) + Shane O'Sullivan (shaneosullivan1@gmail.com) + Bryan Forbes (bforbes) + +------------------------------------------------------------------------------- +Project description + + dojox.fx provides a class of animation effects to use, and + other animation and Effects additions to dojo base. + +------------------------------------------------------------------------------- +Dependencies: + + dojox.fx requires dojo (core) and the dojo.fx package + dojox.fx.easing requires only dojo core. + dojox.fx.scroll requires dojox.fx._core and dojo.fx + +------------------------------------------------------------------------------- +Documentation + + existing API surface: + + dojox.fx._base: + - dojox.fx.crossFade - crossfade two nodes easily + - dojox.fx.sizeTo - size a node about it's center to a new width/height + - dojox.fx.slideBy - slide a node by a t,l offset + - dojox.fx.highlight - animates the background color of a node, and returns + it to the color it was. + + (all use standard _Animation properties, like duration, easing, node, etc) + + dojox.fx._core: + - dojox.fx._Line - a 2-d _Line implementation, backwards compatible with + dojo._Line ... you might could safely do something akin to + dojo._Line.prototype = dojox.fx._Line.prototype; + and enable this for all dojo _Animations? + + dojox.fx.style: - experimental CSS animation via class definitions + - dojox.fx.addClass - animate the effects of applying a class to a node + - dojox.fx.removeClass - " " " " removing a class from a node + - dojox.fx.toggleClass - wrapper for addClass/removeClass + + dojox.fx.easing: - a collection of easing functions to use + this is a "stand alone" class, and can be used via: + dojo.require("dojox.fx.easing"); + to use in an _Animation easing: property + ported/decoded by Bryan Forbes from Robert Penner's Flash easing + functions, contributed under CLA. + + dojox.fx.ext-dojo.NodeList - extensions to dojo.NodeList-fx wrapping the + relevant dojox.fx animations into dojo.NodeList + + dojox.fx.Shadow - Class to add drop shadows to a node + +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/dojo/dojox/trunk/fx.js +http://svn.dojotoolkit.org/dojo/dojox/trunk/fx/* + +Install into the following directory structure: +/dojox/fx/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- diff --git a/includes/js/dojox/fx/Shadow.js b/includes/js/dojox/fx/Shadow.js new file mode 100644 index 0000000..7ed4c55 --- /dev/null +++ b/includes/js/dojox/fx/Shadow.js @@ -0,0 +1,151 @@ +if(!dojo._hasResource["dojox.fx.Shadow"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.fx.Shadow"] = true; +dojo.provide("dojox.fx.Shadow"); +dojo.experimental("dojox.fx.Shadow"); + +dojo.require("dijit._Widget"); +dojo.require("dojo.NodeList-fx"); + +dojo.declare("dojox.fx.Shadow", + dijit._Widget,{ + // summary: Adds a drop-shadow to a node. + // + // example: + // | // add drop shadows to all nodes with class="hasShadow" + // | dojo.query(".hasShadow").forEach(function(n){ + // | var foo = new dojox.fx.Shadow({ node: n }); + // | foo.startup(); + // | }); + // + // shadowPng: String + // Base location for drop-shadow images + shadowPng: dojo.moduleUrl("dojox.fx", "resources/shadow"), + + // shadowThickness: Integer + // How wide (in px) to make the shadow + shadowThickness: 7, + + // shadowOffset: Integer + // How deep to make the shadow appear to be + shadowOffset: 3, + + // opacity: Float + // Overall opacity of the shadow + opacity: 0.75, + + // animate: Boolean + // A toggle to disable animated transitions + animate: false, + + // node: DomNode + // The node we will be applying this shadow to + node: null, + + startup: function(){ + // summary: Initializes the shadow. + + this.inherited(arguments); + this.node.style.position = "relative"; + // make all the pieces of the shadow, and position/size them as much + // as possible (but a lot of the coordinates are set in sizeShadow + this.pieces={}; + var x1 = -1 * this.shadowThickness; + var y0 = this.shadowOffset; + var y1 = this.shadowOffset + this.shadowThickness; + this._makePiece("tl", "top", y0, "left", x1); + this._makePiece("l", "top", y1, "left", x1, "scale"); + this._makePiece("tr", "top", y0, "left", 0); + this._makePiece("r", "top", y1, "left", 0, "scale"); + this._makePiece("bl", "top", 0, "left", x1); + this._makePiece("b", "top", 0, "left", 0, "crop"); + this._makePiece("br", "top", 0, "left", 0); + + this.nodeList = dojo.query(".shadowPiece",this.node); + + this.setOpacity(this.opacity); + this.resize(); + }, + + _makePiece: function(name, vertAttach, vertCoord, horzAttach, horzCoord, sizing){ + // summary: append a shadow pieces to the node, and position it + var img; + var url = this.shadowPng + name.toUpperCase() + ".png"; + if((dojo.isIE)&&(dojo.isIE<7)){ + img=document.createElement("div"); + img.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+url+"'"+ + (sizing?", sizingMethod='"+sizing+"'":"") + ")"; + }else{ + img=document.createElement("img"); + img.src=url; + } + + img.style.position="absolute"; + img.style[vertAttach]=vertCoord+"px"; + img.style[horzAttach]=horzCoord+"px"; + img.style.width=this.shadowThickness+"px"; + img.style.height=this.shadowThickness+"px"; + dojo.addClass(img,"shadowPiece"); + this.pieces[name]=img; + this.node.appendChild(img); + + }, + + setOpacity: function(/* Float */n,/* Object? */animArgs){ + // summary: set the opacity of the underlay + // note: does not work in IE? FIXME. + if(dojo.isIE){ return; } + if(!animArgs){ animArgs = {}; } + if(this.animate){ + var _anims = []; + this.nodeList.forEach(function(node){ + _anims.push(dojo._fade(dojo.mixin(animArgs,{ node: node, end: n }))); + }); + dojo.fx.combine(_anims).play(); + }else{ + this.nodeList.style("opacity",n); + } + + }, + + setDisabled: function(/* Boolean */disabled){ + // summary: enable / disable the shadow + if(disabled){ + if(this.disabled){ return; } + if(this.animate){ this.nodeList.fadeOut().play(); + }else{ this.nodeList.style("visibility","hidden"); } + this.disabled = true; + }else{ + if(!this.disabled){ return; } + if(this.animate){ this.nodeList.fadeIn().play(); + }else{ this.nodeList.style("visibility","visible"); } + this.disabled = false; + } + }, + + resize: function(/* dojox.fx._arg.ShadowResizeArgs */args){ + // summary: Resizes the shadow based on width and height. + var x; var y; + if(args){ x = args.x; y = args.y; + }else{ + var co = dojo._getBorderBox(this.node); + x = co.w; y = co.h; + } + var sideHeight = y - (this.shadowOffset+this.shadowThickness); + if (sideHeight < 0) { sideHeight = 0; } + if (y < 1) { y = 1; } + if (x < 1) { x = 1; } + with(this.pieces){ + l.style.height = sideHeight+"px"; + r.style.height = sideHeight+"px"; + b.style.width = x+"px"; + bl.style.top = y+"px"; + b.style.top = y+"px"; + br.style.top = y+"px"; + tr.style.left = x+"px"; + r.style.left = x+"px"; + br.style.left = x+"px"; + } + } +}); + +} diff --git a/includes/js/dojox/fx/_arg.js b/includes/js/dojox/fx/_arg.js new file mode 100644 index 0000000..b90f0d9 --- /dev/null +++ b/includes/js/dojox/fx/_arg.js @@ -0,0 +1,27 @@ +if(!dojo._hasResource["dojox.fx._arg"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.fx._arg"] = true; +dojo.provide("dojox.fx._arg"); + +dojox.fx._arg.StyleArgs = function(/*Object*/ args){ + // summary: + // The node and CSS class to use for style manipulations. + // node: DOMNode + // The node to manipulate + // cssClass: String + // The class to use during the manipulation + this.node = args.node; + this.cssClass = args.cssClass; +} + +dojox.fx._arg.ShadowResizeArgs = function(/*Object*/ args){ + // summary: + // The odd way to document object parameters. + // x: Integer + // the width to set + // y: Integer + // the height to set + this.x = args.x; + this.y = args.y; +} + +} diff --git a/includes/js/dojox/fx/_base.js b/includes/js/dojox/fx/_base.js new file mode 100644 index 0000000..61d23a7 --- /dev/null +++ b/includes/js/dojox/fx/_base.js @@ -0,0 +1,240 @@ +if(!dojo._hasResource["dojox.fx._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.fx._base"] = true; +dojo.provide("dojox.fx._base"); +// summary: add-on Animations to dojo.fx + +dojo.require("dojo.fx"); + +dojox.fx.sizeTo = function(/* Object */args){ + // summary: Create an animation that will size a node + // description: + // Returns an animation that will size "node" + // defined in args Object about it's center to + // a width and height defined by (args.width, args.height), + // supporting an optional method: chain||combine mixin + // (defaults to chain). + // + // - works best on absolutely or relatively positioned elements? + // + // example: + // | // size #myNode to 400px x 200px over 1 second + // | dojo.fx.sizeTo({ node:'myNode', + // | duration: 1000, + // | width: 400, + // | height: 200, + // | method: "chain" + // | }).play(); + // + var node = (args.node = dojo.byId(args.node)); + + var method = args.method || "chain"; + if(!args.duration){ args.duration = 500; } // default duration needed + if (method=="chain"){ args.duration = Math.floor(args.duration/2); } + + var top, newTop, left, newLeft, width, height = null; + + var init = (function(n){ + return function(){ + var cs = dojo.getComputedStyle(n); + var pos = cs.position; + top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0); + left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0); + width = parseInt(cs.width); + height = parseInt(cs.height); + + newLeft = left - Math.floor((args.width - width)/2); + newTop = top - Math.floor((args.height - height)/2); + + if(pos != 'absolute' && pos != 'relative'){ + var ret = dojo.coords(n, true); + top = ret.y; + left = ret.x; + n.style.position="absolute"; + n.style.top=top+"px"; + n.style.left=left+"px"; + } + } + })(node); + init(); + + var anim1 = dojo.animateProperty(dojo.mixin({ + properties: { + height: { start: height, end: args.height || 0, unit:"px" }, + top: { start: top, end: newTop } + } + }, args)); + var anim2 = dojo.animateProperty(dojo.mixin({ + properties: { + width: { start: width, end: args.width || 0, unit:"px" }, + left: { start: left, end: newLeft } + } + }, args)); + + var anim = dojo.fx[((args.method == "combine") ? "combine" : "chain")]([anim1,anim2]); + dojo.connect(anim, "beforeBegin", anim, init); + return anim; // dojo._Animation +}; + +dojox.fx.slideBy = function(/* Object */args){ + // summary: Returns an animation to slide a node by a defined offset. + // + // description: + // Returns an animation that will slide a node (args.node) from it's + // current position to it's current posision plus the numbers defined + // in args.top and args.left. standard dojo.fx mixin's apply. + // + // example: + // | // slide domNode 50px down, and 22px left + // | dojox.fx.slideBy({ + // | node: domNode, duration:400, + // | top: 50, left: -22 + // | }).play(); + + var node = (args.node = dojo.byId(args.node)); + var top = null; var left = null; + + var init = (function(n){ + return function(){ + var cs = dojo.getComputedStyle(n); + var pos = cs.position; + top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0); + left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0); + if(pos != 'absolute' && pos != 'relative'){ + var ret = dojo.coords(n, true); + top = ret.y; + left = ret.x; + n.style.position="absolute"; + n.style.top=top+"px"; + n.style.left=left+"px"; + } + } + })(node); + init(); + var _anim = dojo.animateProperty(dojo.mixin({ + properties: { + // FIXME: is there a way to update the _Line after creation? + // null start values allow chaining to work, animateProperty will + // determine them for us (except in ie6? -- ugh) + top: { /* start: top, */ end: top+(args.top||0) }, + left: { /* start: left,*/ end: left+(args.left||0) } + } + }, args)); + dojo.connect(_anim,"beforeBegin",_anim,init); + return _anim; // dojo._Animation +}; + +dojox.fx.crossFade = function(/* Object */args){ + // summary: Returns an animation cross fading two element simultaneously + // + // args: + // args.nodes: Array - two element array of domNodes, or id's + // + // all other standard animation args mixins apply. args.node ignored. + // + if(dojo.isArray(args.nodes)){ + // simple check for which node is visible, maybe too simple? + var node1 = args.nodes[0] = dojo.byId(args.nodes[0]); + var op1 = dojo.style(node1,"opacity"); + var node2 = args.nodes[1] = dojo.byId(args.nodes[1]); + var op2 = dojo.style(node2, "opacity"); + + var _anim = dojo.fx.combine([ + dojo[((op1==0)?"fadeIn":"fadeOut")](dojo.mixin({ + node: node1 + },args)), + dojo[((op1==0)?"fadeOut":"fadeIn")](dojo.mixin({ + node: node2 + },args)) + ]); + return _anim; // dojo._Animation + }else{ + // improper syntax in args, needs Array + return false; // Boolean + } +}; + +dojox.fx.highlight = function(/*Object*/ args){ + // summary: Highlight a node + // description: + // Returns an animation that sets the node background to args.color + // then gradually fades back the original node background color + // + // example: + // dojox.fx.highlight({ node:"foo" }).play(); + + var node = (args.node = dojo.byId(args.node)); + + args.duration = args.duration || 400; + // Assign default color light yellow + var startColor = args.color || '#ffff99'; + var endColor = dojo.style(node, "backgroundColor"); + var wasTransparent = (endColor == "transparent" || endColor == "rgba(0, 0, 0, 0)"); + + var anim = dojo.animateProperty(dojo.mixin({ + properties: { + backgroundColor: { start: startColor, end: endColor } + } + }, args)); + + dojo.connect(anim, "onEnd", anim, function(){ + if(wasTransparent){ + node.style.backgroundColor = "transparent"; + } + }); + + return anim; // dojo._Animation +}; + + +dojox.fx.wipeTo = function(/*Object*/ args){ + // summary: Animate a node wiping to a specific width or height + // + // description: + // Returns an animation that will expand the + // node defined in 'args' object from it's current to + // the height or width value given by the args object. + // + // default to height:, so leave height null and specify width: + // to wipeTo a width. note: this may be deprecated by a + // + // Note that the final value should not include + // units and should be an integer. Thus a valid args object + // would look something like this: + // + // dojox.fx.wipeTo({node: "nodeId", height: 200}).play(); + // + // Node must have no margin/border/padding, so put another + // node inside your target node for additional styling. + + args.node = dojo.byId(args.node); + var node = args.node, s = node.style; + + var dir = (args.width ? "width" : "height"); + var endVal = args[dir]; + + var props = {}; + props[dir] = { + // wrapped in functions so we wait till the last second to query (in case value has changed) + start: function(){ + // start at current [computed] height, but use 1px rather than 0 + // because 0 causes IE to display the whole panel + s.overflow="hidden"; + if(s.visibility=="hidden"||s.display=="none"){ + s[dir] = "1px"; + s.display=""; + s.visibility=""; + return 1; + }else{ + var now = dojo.style(node,dir); + return Math.max(now, 1); + } + }, + end: endVal, + unit: "px" + }; + + var anim = dojo.animateProperty(dojo.mixin({ properties: props },args)); + return anim; // dojo._Animation +} + +} diff --git a/includes/js/dojox/fx/_core.js b/includes/js/dojox/fx/_core.js new file mode 100644 index 0000000..54698ad --- /dev/null +++ b/includes/js/dojox/fx/_core.js @@ -0,0 +1,60 @@ +if(!dojo._hasResource["dojox.fx._core"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.fx._core"] = true; +dojo.provide("dojox.fx._core"); + +dojox.fx._Line = function(start, end){ + // summary: a custom _Line to accomodate multi-dimensional values + // + // description: + // a normal dojo._Line is the curve, and does Line(start,end) + // for propertyAnimation. as we make more complicatied animations, we realize + // some properties can have 2, or 4 values relevant (x,y) or (t,l,r,b) for example + // + // this function provides support for those Lines, and is ported directly from 0.4 + // this is a lot of extra code for something so seldom used, so we'll put it here as + // and optional core addition. you can create a new line, and use it during onAnimate + // as you see fit. + // + // start: Integer|Array + // An Integer (or an Array of integers) to use as a starting point + // end: Integer|Array + // An Integer (or an Array of integers) to use as an ending point + // + // example: see dojox.fx.smoothScroll + // + // example: + // | // this is 10 .. 100 and 50 .. 500 + // | var curve = new dojox.fx._Line([10,50],[100,500]); + // | // dojo._Animation.onAnimate is called at every step of the animation + // | // to define current values. this _Line returns an array + // | // at each step. arguments[0] and [1] in this example. + // + this.start = start; + this.end = end; + if(dojo.isArray(start)){ + // multi-dimensional branch + var diff = []; + dojo.forEach(this.start, function(s,i){ + diff[i] = this.end[i] - s; + }, this); + + this.getValue = function(/*float*/ n){ + var res = []; + dojo.forEach(this.start, function(s, i){ + res[i] = (diff[i] * n) + s; + }, this); + return res; // Array + } + }else{ + // single value branch, document here for both branches: + var diff = end - start; + this.getValue = function(/*float*/ n){ + // summary: Returns the point on the line, or an array of points + // n: a floating point number greater than 0 and less than 1 + // returns: Mixed + return (diff * n) + this.start; // Decimal + } + } +}; + +} diff --git a/includes/js/dojox/fx/easing.js b/includes/js/dojox/fx/easing.js new file mode 100644 index 0000000..444a8e9 --- /dev/null +++ b/includes/js/dojox/fx/easing.js @@ -0,0 +1,223 @@ +if(!dojo._hasResource["dojox.fx.easing"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.fx.easing"] = true; +dojo.provide("dojox.fx.easing"); +/* + dojox.fx.easing is in this little file so you don't need dojox.fx to utilize this. + dojox.fx has a lot of fun animations, but this module is optimized for size ... + +*/ +dojox.fx.easing = { + // summary: Collection of easing functions to use beyond the default dojo._defaultEasing + // + // description: + // Easing functions are used to manipulate the iteration through + // an _Animation's _Line. _Line being the properties of an Animation, + // and the easing function progresses through that Line determing + // how quickly (or slowly) it should go. Or more accurately: modify + // the value of the _Line based on the percentage of animation completed. + // + // example: + // | dojo.require("dojox.fx.easing"); + // | var anim = dojo.fadeOut({ + // | node: 'node', + // | duration: 2000, + // | easing: dojox.fx.easing.quadIn + // | }).play(); + // + + linear: function(/* Decimal? */n){ + // summary: A linear easing function + return n; + }, + + quadIn: function(/* Decimal? */n){ + return Math.pow(n, 2); + }, + + quadOut: function(/* Decimal? */n){ + return n * (n-2) * -1; + }, + + quadInOut: function(/* Decimal? */n){ + n=n*2; + if(n<1){ return Math.pow(n, 2) / 2; } + return -1 * ((--n)*(n-2) - 1) / 2; + }, + + cubicIn: function(/* Decimal? */n){ + return Math.pow(n, 3); + }, + + cubicOut: function(/* Decimal? */n){ + return Math.pow(n-1, 3) + 1; + }, + + cubicInOut: function(/* Decimal? */n){ + n=n*2; + if(n<1){ return Math.pow(n, 3) / 2; } + n-=2; + return (Math.pow(n, 3) + 2) / 2; + }, + + quartIn: function(/* Decimal? */n){ + return Math.pow(n, 4); + }, + + quartOut: function(/* Decimal? */n){ + return -1 * (Math.pow(n-1, 4) - 1); + }, + + quartInOut: function(/* Decimal? */n){ + n=n*2; + if(n<1){ return Math.pow(n, 4) / 2; } + n-=2; + return -1/2 * (Math.pow(n, 4) - 2); + }, + + quintIn: function(/* Decimal? */n){ + return Math.pow(n, 5); + }, + + quintOut: function(/* Decimal? */n){ + return Math.pow(n-1, 5) + 1; + }, + + quintInOut: function(/* Decimal? */n){ + n=n*2; + if(n<1){ return Math.pow(n, 5) / 2; }; + n-=2; + return (Math.pow(n, 5) + 2) / 2; + }, + + sineIn: function(/* Decimal? */n){ + return -1 * Math.cos(n * (Math.PI/2)) + 1; + }, + + sineOut: function(/* Decimal? */n){ + return Math.sin(n * (Math.PI/2)); + }, + + sineInOut: function(/* Decimal? */n){ + return -1 * (Math.cos(Math.PI*n) - 1) / 2; + }, + + expoIn: function(/* Decimal? */n){ + return (n==0) ? 0 : Math.pow(2, 10 * (n - 1)); + }, + + expoOut: function(/* Decimal? */n){ + return (n==1) ? 1 : (-1 * Math.pow(2, -10 * n) + 1); + }, + + expoInOut: function(/* Decimal? */n){ + if(n==0){ return 0; } + if(n==1){ return 1; } + n = n*2; + if(n<1){ return Math.pow(2, 10 * (n-1)) / 2; } + --n; + return (-1 * Math.pow(2, -10 * n) + 2) / 2; + }, + + circIn: function(/* Decimal? */n){ + return -1 * (Math.sqrt(1 - Math.pow(n, 2)) - 1); + }, + + circOut: function(/* Decimal? */n){ + n = n-1; + return Math.sqrt(1 - Math.pow(n, 2)); + }, + + circInOut: function(/* Decimal? */n){ + n = n*2; + if(n<1){ return -1/2 * (Math.sqrt(1 - Math.pow(n, 2)) - 1); } + n-=2; + return 1/2 * (Math.sqrt(1 - Math.pow(n, 2)) + 1); + }, + + backIn: function(/* Decimal? */n){ + var s = 1.70158; + return Math.pow(n, 2) * ((s+1)*n - s); + }, + + backOut: function(/* Decimal? */n){ + // summary: an easing function that pops past the range briefly, and + // slowly comes back. + n = n - 1; + var s = 1.70158; + return Math.pow(n, 2) * ((s + 1) * n + s) + 1; + }, + + backInOut: function(/* Decimal? */n){ + var s = 1.70158 * 1.525; + n = n*2; + if(n < 1){ return (Math.pow(n, 2)*((s+1)*n - s))/2; } + n-=2; + return (Math.pow(n, 2)*((s+1)*n + s) + 2)/2; + }, + + elasticIn: function(/* Decimal? */n){ + if(n==0){ return 0; } + if(n==1){ return 1; } + var p = .3; + var s = p/4; + n = n - 1; + return -1 * Math.pow(2,10*n) * Math.sin((n-s)*(2*Math.PI)/p); + }, + + elasticOut: function(/* Decimal? */n){ + // summary: An easing function that elasticly snaps around the target value, near the end of the Animation + if(n==0) return 0; + if(n==1) return 1; + var p = .3; + var s = p/4; + return Math.pow(2,-10*n) * Math.sin((n-s)*(2*Math.PI)/p) + 1; + }, + + elasticInOut: function(/* Decimal? */n){ + // summary: An easing function that elasticly snaps around the value, near the beginning and end of the Animation + if(n==0) return 0; + n = n*2; + if(n==2) return 1; + var p = .3*1.5; + var s = p/4; + if(n<1){ + n-=1; + return -.5*(Math.pow(2,10*n) * Math.sin((n-s)*(2*Math.PI)/p)); + } + n-=1; + return .5*(Math.pow(2,-10*n) * Math.sin((n-s)*(2*Math.PI)/p)) + 1; + }, + + bounceIn: function(/* Decimal? */n){ + // summary: An easing function that "bounces" near the beginning of an Animation + return (1 - dojox.fx.easing.bounceOut(1-n)); // Decimal + }, + + bounceOut: function(/* Decimal? */n){ + // summary: An easing function that "bounces" near the end of an Animation + var s=7.5625; + var p=2.75; + var l; + if(n < (1 / p)){ + l = s*Math.pow(n, 2); + }else if(n < (2 / p)){ + n -= (1.5 / p); + l = s * Math.pow(n, 2) + .75; + }else if(n < (2.5 / p)){ + n -= (2.25 / p); + l = s * Math.pow(n, 2) + .9375; + }else{ + n -= (2.625 / p); + l = s * Math.pow(n, 2) + .984375; + } + return l; + }, + + bounceInOut: function(/* Decimal? */n){ + // summary: An easing function that "bounces" at the beginning and end of the Animation + if(n<0.5){ return dojox.fx.easing.bounceIn(n*2) / 2; } + return (dojox.fx.easing.bounceOut(n*2-1) / 2) + 0.5; // Decimal + } +}; + +} diff --git a/includes/js/dojox/fx/ext-dojo/NodeList.js b/includes/js/dojox/fx/ext-dojo/NodeList.js new file mode 100644 index 0000000..486b5fe --- /dev/null +++ b/includes/js/dojox/fx/ext-dojo/NodeList.js @@ -0,0 +1,66 @@ +if(!dojo._hasResource["dojox.fx.ext-dojo.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.fx.ext-dojo.NodeList"] = true; +dojo.provide("dojox.fx.ext-dojo.NodeList"); +dojo.experimental("dojox.fx.ext-dojo.NodeList"); +// summary: Core extensions to dojo.NodeList providing addtional fx to dojo.NodeList-fx +// description: +// A Package to extend dojo base NodeList with fx provided by the dojox.fx project. +// These are experimental animations, in an experimental + +dojo.require("dojo.NodeList-fx"); +dojo.require("dojox.fx"); + +dojo.extend(dojo.NodeList, { + + sizeTo: function(args){ + // summary: + // size all elements of this NodeList. Returns an instance of dojo._Animation + // example: + // | // size all divs with class "blah" + // | dojo.query("div.blah").sizeTo({ + // | width:50, + // | height:50 + // | }).play(); + return this._anim(dojox.fx, "sizeTo", args); // dojo._Animation + }, + + slideBy: function(args){ + // summary: + // slide all elements of this NodeList. Returns an instance of dojo._Animation + // + // example: + // | // slide all tables with class "blah" 10 px + // | dojo.query("table.blah").slideBy({ top:10, left:10 }).play(); + return this._anim(dojox.fx, "slideBy", args); // dojo._Animation + }, + + highlight: function(args){ + // summary: + // highlight all elements of the node list. + // Returns an instance of dojo._Animation + // example: + // | // highlight all links with class "foo" + // | dojo.query("a.foo").hightlight().play(); + return this._anim(dojox.fx, "highlight", args); // dojo._Animation + }, + + fadeTo: function(args){ + // summary: + // fade all elements of the node list to a specified opacity + // example: + // | // fade all elements with class "bar" to to 50% opacity + // | dojo.query(".bar").fadeTo({ end: 0.5 }).play(); + return this._anim(dojo,"_fade",args); + }, + + wipeTo: function(args){ + // summary: + // Wipe all elements of the NodeList to a specified width: or height: + // example: + // | dojo.query(".box").wipeTo({ width: 300px }).play(); + return this._anim(dojox.fx, "wipeTo", args); + } + +}); + +} diff --git a/includes/js/dojox/fx/resources/shadowB.png b/includes/js/dojox/fx/resources/shadowB.png new file mode 100644 index 0000000..0da8a2a Binary files /dev/null and b/includes/js/dojox/fx/resources/shadowB.png differ diff --git a/includes/js/dojox/fx/resources/shadowBL.png b/includes/js/dojox/fx/resources/shadowBL.png new file mode 100644 index 0000000..4926283 Binary files /dev/null and b/includes/js/dojox/fx/resources/shadowBL.png differ diff --git a/includes/js/dojox/fx/resources/shadowBR.png b/includes/js/dojox/fx/resources/shadowBR.png new file mode 100644 index 0000000..ee704df Binary files /dev/null and b/includes/js/dojox/fx/resources/shadowBR.png differ diff --git a/includes/js/dojox/fx/resources/shadowL.png b/includes/js/dojox/fx/resources/shadowL.png new file mode 100644 index 0000000..67ebc2e Binary files /dev/null and b/includes/js/dojox/fx/resources/shadowL.png differ diff --git a/includes/js/dojox/fx/resources/shadowR.png b/includes/js/dojox/fx/resources/shadowR.png new file mode 100644 index 0000000..8d0c99d Binary files /dev/null and b/includes/js/dojox/fx/resources/shadowR.png differ diff --git a/includes/js/dojox/fx/resources/shadowT.png b/includes/js/dojox/fx/resources/shadowT.png new file mode 100644 index 0000000..ea99436 Binary files /dev/null and b/includes/js/dojox/fx/resources/shadowT.png differ diff --git a/includes/js/dojox/fx/resources/shadowTL.png b/includes/js/dojox/fx/resources/shadowTL.png new file mode 100644 index 0000000..388742a Binary files /dev/null and b/includes/js/dojox/fx/resources/shadowTL.png differ diff --git a/includes/js/dojox/fx/resources/shadowTR.png b/includes/js/dojox/fx/resources/shadowTR.png new file mode 100644 index 0000000..c9d4f04 Binary files /dev/null and b/includes/js/dojox/fx/resources/shadowTR.png differ diff --git a/includes/js/dojox/fx/scroll.js b/includes/js/dojox/fx/scroll.js new file mode 100644 index 0000000..34111a2 --- /dev/null +++ b/includes/js/dojox/fx/scroll.js @@ -0,0 +1,40 @@ +if(!dojo._hasResource["dojox.fx.scroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.fx.scroll"] = true; +dojo.provide("dojox.fx.scroll"); +dojo.experimental("dojox.fx.scroll"); + +dojo.require("dojox.fx._core"); + +dojox.fx.smoothScroll = function(/* Object */args){ + // summary: Returns an animation that will smooth-scroll to a node (specified in etup()) + // description: This implementation support either horizental or vertical scroll, as well as + // both. In addition, element in iframe can be scrolled to correctly. + // offset: {x: int, y: int} this will be added to the target position + // duration: Duration of the animation in milliseconds. + // win: a node or window object to scroll + + if(!args.target){ args.target = dojo.coords(args.node,true); } + + var isWindow = dojo[(dojo.isIE ? "isObject" : "isFunction")](args["win"].scrollTo); + + var _anim = (isWindow) ? + (function(val){ + args.win.scrollTo(val[0],val[1]); + }) : + (function(val){ + args.win.scrollLeft = val[0]; + args.win.scrollTop = val[1]; + }); + + var anim = new dojo._Animation(dojo.mixin({ + beforeBegin: function(){ + if(this.curve){ delete this.curve; } + var current = isWindow ? dojo._docScroll() : {x: args.win.scrollLeft, y: args.win.scrollTop}; + anim.curve = new dojox.fx._Line([current.x,current.y],[args.target.x,args.target.y]); + }, + onAnimate: _anim + },args)); + return anim; // dojo._Animation +}; + +} diff --git a/includes/js/dojox/fx/style.js b/includes/js/dojox/fx/style.js new file mode 100644 index 0000000..895de9a --- /dev/null +++ b/includes/js/dojox/fx/style.js @@ -0,0 +1,219 @@ +if(!dojo._hasResource["dojox.fx.style"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.fx.style"] = true; +dojo.provide("dojox.fx.style"); +dojo.experimental("dojox.fx.style"); +// +// summary: dojox.fx CSS Class _Animations: +// +// description: a set of functions to animate properties based on +// normalized CSS class definitions. +// +// provides: addClass, removeClass, and toggleClass +// +dojo.require("dojox.fx._base"); + +// FIXME: should the call signatures match dojo.addClass/removeClass/toggleClass and extend +// by having a third (or fourth) param to mix in additional _Animation args for advanced +// usage (delay: curve: repeat: easing: etc ... ) + +dojox.fx.addClass = function(/*dojox.fx._arg.StyleArgs*/ args){ + // summary: Animate the effects of adding a class to a node + // description: + // Creates an animation that will animate + // the properties of a node to the properties + // defined in a standard CSS .class definition. + // (calculating the differences itself) + // + // example: + // | + // | .bar { line-height: 12px; } + // | .foo { line-height: 40px; } + // |
      + // | Multi
      line
      text + // |
      + // | + // | // animate to line-height:40px + // | dojo.fx.addClass({ node:"test", cssClass:"foo" }).play(); + // + var node = (args.node = dojo.byId(args.node)); + + var pushClass = (function(n){ + // summary: onEnd we want to add the class to the node + // (as dojo.addClass naturally would) in case our + // class parsing misses anything the browser would + // otherwise interpret. this may cause some flicker, + // and will only apply the class so children can inherit + // after the animation is done (potentially more flicker) + return function(){ + dojo.addClass(n, args.cssClass); + n.style.cssText = _beforeStyle; + } + })(node); + + // _getCalculatedStleChanges is the core of our style/class animations + var mixedProperties = dojox.fx._getCalculatedStyleChanges(args,true); + var _beforeStyle = node.style.cssText; + var _anim = dojo.animateProperty(dojo.mixin({ + properties: mixedProperties + },args)); + dojo.connect(_anim,"onEnd",_anim,pushClass); + return _anim; // dojo._Animation +}; + +dojox.fx.removeClass = function(/*dojox.fx._arg.StyleArgs*/ args){ + // summary: Animate the effects of removing a class from a node + // description: + // Creates an animation that will animate the properties of a + // node (args.node) to the properties calculated after removing + // a standard CSS className from a that node. + // + // calls dojo.removeClass(args.cssClass) onEnd of animation + // + // standard dojo._Animation object rules apply. + // + // example: + // | // animate the removal of "foo" from a node with id="bar" + // | dojox.fx.removeClass({ + // | node: "bar", + // | cssClass: "foo" + // | }).play(); + + var node = (args.node = dojo.byId(args.node)); + + var pullClass = (function(n){ + // summary: onEnd we want to remove the class from the node + // (as dojo.removeClass naturally would) in case our class + // parsing misses anything the browser would otherwise + // interpret. this may cause some flicker, and will only + // apply the class so children can inherit after the + // animation is done (potentially more flicker) + // + return function(){ + dojo.removeClass(n, args.cssClass); + n.style.cssText = _beforeStyle; + } + })(node); + + var mixedProperties = dojox.fx._getCalculatedStyleChanges(args,false); + var _beforeStyle = node.style.cssText; + var _anim = dojo.animateProperty(dojo.mixin({ + properties: mixedProperties + },args)); + dojo.connect(_anim,"onEnd",_anim,pullClass); + return _anim; // dojo._Animation +}; + +dojox.fx.toggleClass = function(/*DomNode|String*/node, /*String*/cssClass, /*Boolean?*/condition){ + // summary: + // Animate the effects of Toggling a class on a Node + // + // description: + // creates an animation that will animate the effect of + // toggling a class on or off of a node. + // Adds a class to node if not present, or removes if present. + // Pass a boolean condition if you want to explicitly add or remove. + // node: + // The domNode (or string of the id) to toggle + // cssClass: + // String of the classname to add to the node + // condition: + // If passed, true means to add the class, false means to remove. + // + // example: + // | // add the class "sampleClass" to a node id="theNode" + // | dojox.fx.toggleClass("theNode","sampleClass",true).play(); + // example: + // | // toggle the class "sampleClass" on the node id="theNode" + // | dojox.fx.toggleClass("theNode","sampleClass").play(); + + if(typeof condition == "undefined"){ + condition = !dojo.hasClass(node, cssClass); + } + return dojox.fx[(condition ? "addClass" : "removeClass")]({ node: node, cssClass:cssClass }); // dojo._Animation + // TODO: support 4th param animMixin to allow passing of easing and duration and other _Animtion options +}; + +dojox.fx._allowedProperties = [ + // summary: Our pseudo map of properties we will check for. + // description: + // it should be much more intuitive. a way to normalize and + // "predict" intent, or even something more clever ... + // open to suggestions. + + // no-brainers: + "width", + "height", + // only if position = absolute || relative? + "left", "top", // "right", "bottom", + // these need to be filtered through dojo.colors? + // "background", // normalize to: + /* "backgroundImage", */ + // "backgroundPosition", // FIXME: to be effective, this needs "#px #px"? + "backgroundColor", + + "color", + + // "border", + "borderBottomColor", "borderBottomWidth", + "borderTopColor","borderTopWidth", + "borderLeftColor","borderLeftWidth", + "borderRightColor","borderRightWidth", + + // "padding", // normalize to: + "paddingLeft", "paddingRight", "paddingTop", "paddingBottom", + // "margin", // normalize to: + "marginLeft", "marginTop", "marginRight", "marginBottom", + + // unit import/delicate?: + "lineHeight", + "letterSpacing", + "fontSize" +]; + +dojox.fx._getStyleSnapshot = function(/* Object */cache){ + // summary: + // uses a dojo.getComputedStyle(node) cache reference and + // iterates through the 'documented/supported animate-able' + // properties. + // + // returns: Array + // an array of raw, calculcated values (no keys), to be normalized/compared + // elsewhere + return dojo.map(dojox.fx._allowedProperties,function(style){ + return cache[style]; // String + }); // Array +}; + +dojox.fx._getCalculatedStyleChanges = function(/*dojox.fx._arg.StyleArgs*/ args, /*Boolean*/addClass){ + // summary: calclate the difference in style properties between two states + // description: + // calculate and normalize(?) the differences between two states + // of a node (args.node) by quickly adding or removing a class, and + // iterateing over the results of dojox.fx._getStyleSnapshot() + // + // addClass: + // true to calculate what adding a class would do, + // false to calculate what removing the class would do + + var node = (args.node = dojo.byId(args.node)); + var cs = dojo.getComputedStyle(node); + + // take our snapShots + var _before = dojox.fx._getStyleSnapshot(cs); + dojo[(addClass ? "addClass" : "removeClass")](node,args.cssClass); + var _after = dojox.fx._getStyleSnapshot(cs); + dojo[(addClass ? "removeClass" : "addClass")](node,args.cssClass); + + var calculated = {}; + var i = 0; + dojo.forEach(dojox.fx._allowedProperties,function(prop){ + if(_before[i] != _after[i]){ + // FIXME: the static unit: px is not good, either. need to parse unit from computed style? + calculated[prop] = { end: parseInt(_after[i]) /* start: parseInt(_before[i]), unit: 'px' */ }; + } + i++; + }); + return calculated; +}; + +} diff --git a/includes/js/dojox/fx/tests/_animation.css b/includes/js/dojox/fx/tests/_animation.css new file mode 100644 index 0000000..efab455 --- /dev/null +++ b/includes/js/dojox/fx/tests/_animation.css @@ -0,0 +1,97 @@ +.testBox { + border:1px solid #333; + width:75px; + height:75px; +} +.absolutely { position:absolute; + top:0; left:0; +} +.floating { + float:left; +} +.wide { + width:200px; +} +.tall { + height:200px; +} +.tiny { + width:3px; + height:3px; +} +.black { + color:#fff; + background-color:#000; +} +.white { + color:#666; + background-color:#fff; +} +.green { + color:#000; + background-color:#eef; +} +.red { + color:#fff; + background-color:#ffe; +} +.blue { + color:#000; + background-color:#fef !important; +} +.baseFont { + line-height:14px; + font:12px Arial,sans-serif; + letter-spacing:0.1em; +} +.spacedVertical { + line-height:42px; +} +.spacedHorizontal { + letter-spacing:0.42em; +} +.fontSizeTest { + font:20px Arial,sans-serif; +} +.bigMargin { + margin:30px; +} +.noMargin { + margin:0; +} +.mediumMargin { + margin:15px; +} +.bigMarginLeft { + margin-left:150px; +} +.padded { + padding:3px; +} +.noPadding { + padding:0; +} +.topPadding { + padding-top:50px; +} +.bigPadding { + padding:30px; +} +.offsetSome { + top:50px; + left:75px; +} +.topLeft { + top:0; + left:0; +} +.bottomRight { + bottom:0; + right:0; +} +.bothAxis { + top:10px; + left:10px; + right:10px; + bottom:10px; +} diff --git a/includes/js/dojox/fx/tests/_animation.css.commented.css b/includes/js/dojox/fx/tests/_animation.css.commented.css new file mode 100644 index 0000000..ba01d03 --- /dev/null +++ b/includes/js/dojox/fx/tests/_animation.css.commented.css @@ -0,0 +1,113 @@ +.testBox { + border:1px solid #333; + width:75px; + height:75px; +} +.absolutely { position:absolute; + top:0; left:0; +} +.floating { + float:left; +} +.wide { + width:200px; +} +.tall { + height:200px; +} +.tiny { + width:3px; + height:3px; +} + + +.black { + color:#fff; + background-color:#000; +} + +.white { + color:#666; + background-color:#fff; +} + +.green { + color:#000; + background-color:#eef; +} +.red { + color:#fff; + background-color:#ffe; +} +.blue { + color:#000; + background-color:#fef !important; +} + +/* font sizes */ +.baseFont { + line-height:14px; + font:12px Arial,sans-serif; + letter-spacing:0.1em; +} + +.spacedVertical { + line-height:42px; +} +.spacedHorizontal { + letter-spacing:0.42em; +} +.fontSizeTest { + font:20px Arial,sans-serif; +} + +/* margins */ +.bigMargin { + margin:30px; +} +.noMargin { + margin:0; +} +.mediumMargin { + margin:15px; +} +.bigMarginLeft { + margin-left:150px; +} + +/* padding */ +.padded { + padding:3px; +} +.noPadding { + padding:0; +} +.topPadding { + padding-top:50px; +} +.bigPadding { + padding:30px; +} + +/* positioning */ + +.offsetSome { + top:50px; + left:75px; +} + +.topLeft { + top:0; + left:0; +} +.bottomRight { + bottom:0; + right:0; +} + +.bothAxis { + top:10px; + left:10px; + right:10px; + bottom:10px; +} diff --git a/includes/js/dojox/fx/tests/example_Line.html b/includes/js/dojox/fx/tests/example_Line.html new file mode 100644 index 0000000..4177e96 --- /dev/null +++ b/includes/js/dojox/fx/tests/example_Line.html @@ -0,0 +1,80 @@ + + + + using a dojo._Line and dojo._Animation + + + + + + +

      an "animateProperty" for dojox.gfx

      +
      + + + diff --git a/includes/js/dojox/fx/tests/example_backgroundPosition.html b/includes/js/dojox/fx/tests/example_backgroundPosition.html new file mode 100644 index 0000000..5011213 --- /dev/null +++ b/includes/js/dojox/fx/tests/example_backgroundPosition.html @@ -0,0 +1,59 @@ + + + + Animated background position example | The Dojo Toolkit + + + + + + + +

      dojo._Animation test:

      + +

      +

      Test
      +

      + + + diff --git a/includes/js/dojox/fx/tests/example_dojoAnimations.html b/includes/js/dojox/fx/tests/example_dojoAnimations.html new file mode 100644 index 0000000..2365ea1 --- /dev/null +++ b/includes/js/dojox/fx/tests/example_dojoAnimations.html @@ -0,0 +1,442 @@ + + + + + skeleton page | The Dojo Toolkit + + + + + + + + + +
      + +

      Dojo FX: base animations

      + + + + + + + +
      +
      +
       
      +
      +
      + + +

      Animate CSS Properties:

      + + + + + + + +
      +
      +

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. + Nam facilisis enim. Pellentesque in elit et lacus euismod dignissim. + Aliquam dolor pede, convallis eget, dictum a, blandit ac, urna. + Pellentesque sed nunc ut justo volutpat egestas. Class aptent taciti + sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. + In erat. +

      +
      +
      + +

      dojo.fx - Core animations

      + + + + + + + +
      +
      +
      +
      +
      + +

      dojo.query FX

      + + + + + + + + + + + +
      +
        +
      • odd row
      • +
      • even row
      • +
      • odd row
      • +
      • even row
      • +
      • odd row
      • +
      • even row
      • +
      • odd row
      • +
      • even row
      • +
      • odd row
      • +
      +
      +

      (FisheyeLite makes this easy. be creative:)

      +
        +
      • odd row
      • +
      • even row
      • +
      • odd row
      • +
      • even row
      • +
      • odd row
      • +
      • with id
      • +
      • odd row
      • +
      +

      +
      +
      + +
      + + diff --git a/includes/js/dojox/fx/tests/example_easingChart2D.html b/includes/js/dojox/fx/tests/example_easingChart2D.html new file mode 100644 index 0000000..fd0d171 --- /dev/null +++ b/includes/js/dojox/fx/tests/example_easingChart2D.html @@ -0,0 +1,147 @@ + + + + visualising dojo._Animation.easing via dojox.charting + + + + + + + + + + + + + +

      dojox.fx.easing

      + +

      this chart shows time (x axis) vs. position (y axis) for a movement from 0px to 30px modified by easing functions

      + + + +
      +
      +
      + + + diff --git a/includes/js/dojox/fx/tests/images/averycutedog.jpg b/includes/js/dojox/fx/tests/images/averycutedog.jpg new file mode 100644 index 0000000..335855e Binary files /dev/null and b/includes/js/dojox/fx/tests/images/averycutedog.jpg differ diff --git a/includes/js/dojox/fx/tests/images/dot.png b/includes/js/dojox/fx/tests/images/dot.png new file mode 100644 index 0000000..1287a73 Binary files /dev/null and b/includes/js/dojox/fx/tests/images/dot.png differ diff --git a/includes/js/dojox/fx/tests/images/longBg.png b/includes/js/dojox/fx/tests/images/longBg.png new file mode 100644 index 0000000..f89d23a Binary files /dev/null and b/includes/js/dojox/fx/tests/images/longBg.png differ diff --git a/includes/js/dojox/fx/tests/test_Nodelist-fx.html b/includes/js/dojox/fx/tests/test_Nodelist-fx.html new file mode 100644 index 0000000..75c7a94 --- /dev/null +++ b/includes/js/dojox/fx/tests/test_Nodelist-fx.html @@ -0,0 +1,282 @@ + + + + dojo.NodeList-fx and dojox.fx.ext-dojo.Nodelist | fx add-ons to dojo.query() + + + + + + + +

      NodeList and dojo.query "magic"

      + +
      +

      stuff going on:

      +
        +
      • watch the startup cycle
      • +
      • click col 6
      • +
      • click top right box
      • +
      • hover to highlight() node
      • +
      +
      + +
      +

      custom query:

      +
      +

      + dojo.query(""); +
      (dojo:)
      + +
      + + +
      + + +
      + + +
      + + + (x: 0, y:0)
      + +
      (dojox:)
      + + +
      + + +
      + + +
      + + +
      + +

      + + + + +
      +
      + +
      +
      1
      +
      2
      +
      3
      +
      4
      +
      5
      +
      6
      +
      7
      + +
      2
      +
      +
      +
      +
      +
      +
      + +
      3
      +
      +
      +
      +
      +
      +
      + +
      4
      +
      +
      +
      +
      +
      +
      + +
      + +
      + HTML AFTER +
      + +

      classes available to play with:

      + +
      +		.testBox
      +		.noIdHere
      +		each row: .rowOne .rowTwo .rowThree .rowFour
      +		each col: .iOne .iTwo .. iSeven
      +		#randomNode, #node9, #node7, #aNode, #node1, #node2, #node4, #node6
      +	
      + +

      the dojo.query() isn't limited to the testDiv, it parses the body. try: dojo.query("fieldset") and slideBy animation

      + + + diff --git a/includes/js/dojox/fx/tests/test_Shadow.html b/includes/js/dojox/fx/tests/test_Shadow.html new file mode 100644 index 0000000..fd21fd2 --- /dev/null +++ b/includes/js/dojox/fx/tests/test_Shadow.html @@ -0,0 +1,93 @@ + + + + dojox.fx.Shadow - Drop Shadows for DomNodes | The Dojo Toolkit + + + + + + + + +

      dojox.fx.Shadow tests

      + +
      +

      with margin:

      +

      Lorem

      + +

      with padding:

      +

      Lorem

      + +

      no padding:

      +

      Lorem

      + +

      position:absolute

      +

      Lorem

      + +
      +
      + + +

      + + + + diff --git a/includes/js/dojox/fx/tests/test_animateClass.html b/includes/js/dojox/fx/tests/test_animateClass.html new file mode 100644 index 0000000..c963ca1 --- /dev/null +++ b/includes/js/dojox/fx/tests/test_animateClass.html @@ -0,0 +1,222 @@ + + + + dojox.fx.style - animatated CSS functions | The Dojo Toolkit + + + + + + + + +

      dojox.fx.style tests

      + +

      + dojox.fx.style provides a few methods to animate the changes that would occur + when adding or removing a class from a domNode. +

      +
        +
      • dojox.fx.addClass(/* Object */)args); // Returns dojo._Animation
      • +
      • dojox.fx.removeClass(/* Object */args); // Returns dojo._Animation
      • +
      • dojox.fx.toggleClass(/* DomNode */node, /* String */cssClass,/* Boolean */force)
      • +
      + + + + + + + +

      testing sizes

      + + + + + + + +
      +
      +
      +
      +
      + +
      + +

      testing position

      +

      This is a div position:relative with a position:absolute div inside. testing various t/l/b/r combos. + normal css inheritance rules apply, so setting .foo .bar if .foo was defined last in the css text, .bar + will take precedent. the below position test shows the results of this: +

      + + + + + +
      +
      +
      + + + + + +

      Some properties + cannot be modified (fontFace, and so on), so to ensure the results at the end + of the animation are applied correctly and fully, the class name is set on the node + via dojo.add/removeClass(). +

      + + + + diff --git a/includes/js/dojox/fx/tests/test_crossFade.html b/includes/js/dojox/fx/tests/test_crossFade.html new file mode 100644 index 0000000..330a34a --- /dev/null +++ b/includes/js/dojox/fx/tests/test_crossFade.html @@ -0,0 +1,145 @@ + + + + dojox.fx - animation sets to use! + + + + + + + +

      dojox.fx.crossFade test

      + + +

      a simple demonstration of two nodes fading simultaneously

      +
      + +
      + +
      box2
      +
      +
      +
      + +

      two nodes with position:relative in a container with position:absolute, crossfading together.

      + +
      +
      + +
      box two
      +
      +
      +
      + +

      simple looping crossfade

      + +
      +
      +
      box one
      + +
      +
      +
      + + + +

      that's all, folks...

      + + + diff --git a/includes/js/dojox/fx/tests/test_easing.html b/includes/js/dojox/fx/tests/test_easing.html new file mode 100644 index 0000000..fa7bf41 --- /dev/null +++ b/includes/js/dojox/fx/tests/test_easing.html @@ -0,0 +1,142 @@ + + + + dojox.fx.easing functions: + + + + + + + +

      dojox.fx.easing function tests:

      + + (click block to play animation, or here to do all three) + +
      dojox.fx.easing.easeIn
      +

      +
      dojox.fx.easing.easeOut
      +

      +
      dojox.fx.easing.linear
      +

      +
      dojo default easing
      + +

      + dojox.fx.easing is stand-alone, and does not require the dojox.fx base files. to see a chart + of these functions see example_easingChart2D.html +

      + +
      bounce
      + + + diff --git a/includes/js/dojox/fx/tests/test_highlight.html b/includes/js/dojox/fx/tests/test_highlight.html new file mode 100644 index 0000000..1d5947e --- /dev/null +++ b/includes/js/dojox/fx/tests/test_highlight.html @@ -0,0 +1,45 @@ + + + + dojox.fx.highlight + + + + + + +

      dojox.fx.highlight tests

      + +
      +

      This is the default highlight

      +
      + +
      +

      BRING ATTENTION HERE!

      +
      + +
      +

      Highlight me

      +
      + + test #1 (default) +
      + test #2 (default - play twice) +
      + test #3 +
      + test #4 +
      + highlight via dojo.query + + + diff --git a/includes/js/dojox/fx/tests/test_scroll.html b/includes/js/dojox/fx/tests/test_scroll.html new file mode 100644 index 0000000..a3ec9ed --- /dev/null +++ b/includes/js/dojox/fx/tests/test_scroll.html @@ -0,0 +1,98 @@ + + + + dojox.fx.scroll + + + + + + + + +

      dojox.fx.scroll tests

      + +

      YOU FOUND ME!

      +

      neat.

      +
      + +

      dojox.fx.scroll provides:

      +
        +
      • dojox.fx.smoothScroll()
      • +
      +

      + which will create and return a dojo._Animation to scroll + a window to a desired offset. (or a node that has overflow:auto/hidden, if you pass the domNode as the win: argument) +

      + + +

      getScroll

      +

      + Scroll top: 0
      + Scroll left: 0 +

      + + + +
      + +
      + +
      + +

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      + + +

      getElementsByClass

      + +

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      + +

      ContainsAny

      + +

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitaerisus.

      + + + diff --git a/includes/js/dojox/fx/tests/test_sizeTo.html b/includes/js/dojox/fx/tests/test_sizeTo.html new file mode 100644 index 0000000..0c21e9b --- /dev/null +++ b/includes/js/dojox/fx/tests/test_sizeTo.html @@ -0,0 +1,142 @@ + + + + dojox.fx.sizeTo | experimental fx add-ons for the Dojo Toolkit + + + + + + + +

      dojox.fx.sizeTo test

      + +

      quick sizeTo API overview:

      + +
      +        dojox.fx.sizeTo({
      +                // basic requirements:
      +                node: "aDomNodeId", // or a domNode reference        
      +                width: 200, // measured in px
      +                height: 200, // measured in px
      +                method: "chain" // is default, or "combine"               
      +        });
      +        
      +

      + little test blocks (works in FF/win/mac + ie6) dojo.query() test +

      + +
      +
      + mouse down / mouse up +
      +
      + hover / exit +
      + +
      + all of em' +
      +
      +
      + + (click the box labeled "all of em'" again to reset all nodes) + + HTML AFTER +
      + + + diff --git a/includes/js/dojox/fx/tests/test_slideBy.html b/includes/js/dojox/fx/tests/test_slideBy.html new file mode 100644 index 0000000..a1a1960 --- /dev/null +++ b/includes/js/dojox/fx/tests/test_slideBy.html @@ -0,0 +1,75 @@ + + + + dojox.fx - animation sets to use! + + + + + + + +

      dojox.fx.slideBy test

      + + top: 50, left:50 + top:-50, left:50 + top:-50, left:-50 + top:50, left:-50 + dojo.query() + chainTest + +
      + lorem. ipsum. +
      + +
      + +
      +
      a
      b
      c
      +
      + + + HTML AFTER +
      + + + + + diff --git a/includes/js/dojox/fx/tests/test_wipeTo.html b/includes/js/dojox/fx/tests/test_wipeTo.html new file mode 100644 index 0000000..539453b --- /dev/null +++ b/includes/js/dojox/fx/tests/test_wipeTo.html @@ -0,0 +1,109 @@ + + + + dojox.fx.wipeTo | experimental fx add-ons for the Dojo Toolkit + + + + + + + +

      dojox.fx.wipeTo test

      + +

      quick sizeTo API overview:

      + +
      +        dojox.fx.wipeTo({
      +                // basic requirements:
      +                node: "aDomNodeId", // or a domNode reference        
      +                width: 200 // measured in px
      +                // height: 200 // measured in px (only one at a time, see sizeTo)         
      +        });
      +        
      + +

      Some test boxes: (id="box1,box2,box3" etc ...)

      + + + + + + + +
      + I am some small text +
      + +
      + I am some small text +
      + +
      + I am some small text +
      + + +
      + +
      + + + diff --git a/includes/js/dojox/gfx.js b/includes/js/dojox/gfx.js new file mode 100644 index 0000000..85cbc52 --- /dev/null +++ b/includes/js/dojox/gfx.js @@ -0,0 +1,40 @@ +if(!dojo._hasResource["dojox.gfx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx"] = true; +dojo.provide("dojox.gfx"); + +dojo.require("dojox.gfx.matrix"); +dojo.require("dojox.gfx._base"); + +(function(){ + var renderers = (typeof dojo.config["gfxRenderer"] == "string" ? + dojo.config["gfxRenderer"] : "svg,vml,silverlight,canvas").split(","); + for(var i = 0; i < renderers.length; ++i){ + switch(renderers[i]){ + case "svg": + //TODO: need more comprehensive test for SVG + if(!dojo.isIE && (navigator.userAgent.indexOf("iPhone") < 0) && (navigator.userAgent.indexOf("iPod") < 0)){ dojox.gfx.renderer = "svg"; } + break; + case "vml": + if(dojo.isIE != 0){ dojox.gfx.renderer = "vml"; } + break; + case "silverlight": + //TODO: need more comprehensive test for Silverlight + if(window.Silverlight){ dojox.gfx.renderer = "silverlight"; } + break; + case "canvas": + //TODO: need more comprehensive test for Canvas + if(dojo.isIE == 0){ dojox.gfx.renderer = "canvas"; } + break; + } + if(dojox.gfx.renderer){ break; } + } + console.log("gfx renderer = " + dojox.gfx.renderer); +})(); + +// include a renderer conditionally +dojo.requireIf(dojox.gfx.renderer == "svg", "dojox.gfx.svg"); +dojo.requireIf(dojox.gfx.renderer == "vml", "dojox.gfx.vml"); +dojo.requireIf(dojox.gfx.renderer == "silverlight", "dojox.gfx.silverlight"); +dojo.requireIf(dojox.gfx.renderer == "canvas", "dojox.gfx.canvas"); + +} diff --git a/includes/js/dojox/gfx/Moveable.js b/includes/js/dojox/gfx/Moveable.js new file mode 100644 index 0000000..2717043 --- /dev/null +++ b/includes/js/dojox/gfx/Moveable.js @@ -0,0 +1,101 @@ +if(!dojo._hasResource["dojox.gfx.Moveable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.Moveable"] = true; +dojo.provide("dojox.gfx.Moveable"); + +dojo.require("dojox.gfx.Mover"); + +dojo.declare("dojox.gfx.Moveable", null, { + constructor: function(shape, params){ + // summary: an object, which makes a shape moveable + // shape: dojox.gfx.Shape: a shape object to be moved + // params: Object: an optional object with additional parameters; + // following parameters are recognized: + // delay: Number: delay move by this number of pixels + // mover: Object: a constructor of custom Mover + this.shape = shape; + this.delay = (params && params.delay > 0) ? params.delay : 0; + this.mover = (params && params.mover) ? params.mover : dojox.gfx.Mover; + this.events = [ + this.shape.connect("onmousedown", this, "onMouseDown"), + // cancel text selection and text dragging + //dojo.connect(this.handle, "ondragstart", dojo, "stopEvent"), + //dojo.connect(this.handle, "onselectstart", dojo, "stopEvent") + ]; + }, + + // methods + destroy: function(){ + // summary: stops watching for possible move, deletes all references, so the object can be garbage-collected + dojo.forEach(this.events, this.shape.disconnect, this.shape); + this.events = this.shape = null; + }, + + // mouse event processors + onMouseDown: function(e){ + // summary: event processor for onmousedown, creates a Mover for the shape + // e: Event: mouse event + if(this.delay){ + this.events.push(this.shape.connect("onmousemove", this, "onMouseMove")); + this.events.push(this.shape.connect("onmouseup", this, "onMouseUp")); + this._lastX = e.clientX; + this._lastY = e.clientY; + }else{ + new this.mover(this.shape, e, this); + } + dojo.stopEvent(e); + }, + onMouseMove: function(e){ + // summary: event processor for onmousemove, used only for delayed drags + // e: Event: mouse event + if(Math.abs(e.clientX - this._lastX) > this.delay || Math.abs(e.clientY - this._lastY) > this.delay){ + this.onMouseUp(e); + new this.mover(this.shape, e, this); + } + dojo.stopEvent(e); + }, + onMouseUp: function(e){ + // summary: event processor for onmouseup, used only for delayed delayed drags + // e: Event: mouse event + this.shape.disconnect(this.events.pop()); + this.shape.disconnect(this.events.pop()); + }, + + // local events + onMoveStart: function(/* dojox.gfx.Mover */ mover){ + // summary: called before every move operation + dojo.publish("/gfx/move/start", [mover]); + dojo.addClass(dojo.body(), "dojoMove"); + }, + onMoveStop: function(/* dojox.gfx.Mover */ mover){ + // summary: called after every move operation + dojo.publish("/gfx/move/stop", [mover]); + dojo.removeClass(dojo.body(), "dojoMove"); + }, + onFirstMove: function(/* dojox.gfx.Mover */ mover){ + // summary: called during the very first move notification, + // can be used to initialize coordinates, can be overwritten. + + // default implementation does nothing + }, + onMove: function(/* dojox.gfx.Mover */ mover, /* Object */ shift){ + // summary: called during every move notification, + // should actually move the node, can be overwritten. + this.onMoving(mover, shift); + this.shape.applyLeftTransform(shift); + this.onMoved(mover, shift); + }, + onMoving: function(/* dojox.gfx.Mover */ mover, /* Object */ shift){ + // summary: called before every incremental move, + // can be overwritten. + + // default implementation does nothing + }, + onMoved: function(/* dojox.gfx.Mover */ mover, /* Object */ shift){ + // summary: called after every incremental move, + // can be overwritten. + + // default implementation does nothing + } +}); + +} diff --git a/includes/js/dojox/gfx/Mover.js b/includes/js/dojox/gfx/Mover.js new file mode 100644 index 0000000..6a5d456 --- /dev/null +++ b/includes/js/dojox/gfx/Mover.js @@ -0,0 +1,62 @@ +if(!dojo._hasResource["dojox.gfx.Mover"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.Mover"] = true; +dojo.provide("dojox.gfx.Mover"); + +dojo.declare("dojox.gfx.Mover", null, { + constructor: function(shape, e, host){ + // summary: an object, which makes a shape follow the mouse, + // used as a default mover, and as a base class for custom movers + // shape: dojox.gfx.Shape: a shape object to be moved + // e: Event: a mouse event, which started the move; + // only clientX and clientY properties are used + // host: Object?: object which implements the functionality of the move, + // and defines proper events (onMoveStart and onMoveStop) + this.shape = shape; + this.lastX = e.clientX + this.lastY = e.clientY; + var h = this.host = host, d = document, + firstEvent = dojo.connect(d, "onmousemove", this, "onFirstMove"); + this.events = [ + dojo.connect(d, "onmousemove", this, "onMouseMove"), + dojo.connect(d, "onmouseup", this, "destroy"), + // cancel text selection and text dragging + dojo.connect(d, "ondragstart", dojo, "stopEvent"), + dojo.connect(d, "onselectstart", dojo, "stopEvent"), + firstEvent + ]; + // notify that the move has started + if(h && h.onMoveStart){ + h.onMoveStart(this); + } + }, + // mouse event processors + onMouseMove: function(e){ + // summary: event processor for onmousemove + // e: Event: mouse event + var x = e.clientX; + var y = e.clientY; + this.host.onMove(this, {dx: x - this.lastX, dy: y - this.lastY}); + this.lastX = x; + this.lastY = y; + dojo.stopEvent(e); + }, + // utilities + onFirstMove: function(){ + // summary: it is meant to be called only once + this.host.onFirstMove(this); + dojo.disconnect(this.events.pop()); + }, + destroy: function(){ + // summary: stops the move, deletes all references, so the object can be garbage-collected + dojo.forEach(this.events, dojo.disconnect); + // undo global settings + var h = this.host; + if(h && h.onMoveStop){ + h.onMoveStop(this); + } + // destroy objects + this.events = this.shape = null; + } +}); + +} diff --git a/includes/js/dojox/gfx/README b/includes/js/dojox/gfx/README new file mode 100644 index 0000000..c318ddb --- /dev/null +++ b/includes/js/dojox/gfx/README @@ -0,0 +1,102 @@ +------------------------------------------------------------------------------- +dojox.gfx +------------------------------------------------------------------------------- +Version 1.100 +Release date: 08/01/2006 +------------------------------------------------------------------------------- +Project state: +beta +HTMLCanvas renderer: experimental +------------------------------------------------------------------------------- +Credits + Eugene Lazutkin (eugene.lazutkin@gmail.com) + Kun Xi (bookstack@gmail.com) + Chris Mitchell (ccmitchellusa@gmail.com) HTML Canvas +------------------------------------------------------------------------------- +Project description + +Implementation of simple portable 2D graphics library. +------------------------------------------------------------------------------- +Dependencies: + +Dojo Core +------------------------------------------------------------------------------- +Documentation + +Currently it can be found here: http://docs.google.com/Doc?id=d764479_1hnb2tn + +HTMLCanvas Renderer Status + +To use canvas rendering, insert 'canvas' at the beginning of the gfxRenderers list in your +djConfig, for example: + +canvas currently will only render on non-IE browsers (see dojox/gfx.js for where the renderer is loaded); +although it should be possible to use an IE canvas implementation (like Google's); however, it will be very slow. + +The following tests can be made to work with HTML Canvas with minor testcase modification: +dojox/gfx/tests + test_gfx.html-Bugs #1 + test_arc.html + test_bezier.html + test_pattern.html + test_gradient.html + test_linearGradient.html + test_image1.html - Limitation #3 + test_transform.html - Bug #1 + test_poly.html - Bug #1 +dojox/gfx/demos + butterfly.html - Bug #1 + lion.html - Bug #1 + tiger.html - Bug #1 + circles.html - No event processing yet :( + creator.html +dojox/chart + test_pie2d.html - Dojo Charts on iPhone anyone? :) + test_chart2d.html - + + // To make charts work, the following line needs to be added to the end of the + // Chart2D.js render() method (prior to return) + if(this.surface.render){this.surface.render()}; + +Known Limitations: +1) event handling- plan is to capture all events at canvas, perform intersect/hit + tests (not implemented) against scene graph, then propogate event to top-most + intersected shape. HtmlCanvas shape need intersectsStroke and intersectsBounds, + and intersects (region). +2) SVG and VML are "live" scene graphs; eg. any state change to objects in the + scene automatically get rendered in next engine render pass. For canvas, it's + procedural, and current implementation requires application to call surface.render() + whenever scene needs to be updated. Plan is to do dirty region checking based + on bounding boxes (currently not properly computed), and track dirty areas anytime + state changes (invalidate) separate from render phase. + Add the following call where changes to the scene graph are complete and you want to + render: + + if (surface.render){surface.render();} + +4) Text/Text Paths - Text shape is implemented using DIV overlays. Many text styles are not + applied, and outline/fills are not possible. This is due to limitations in Canvas spec. + Firefox 3.0 has proprietary text functions that we could test for and use once FF3 is out. + No luck on Safari. +3) No Image skewing - Limitation of Canvas + +Known Bugs: +1) Matrix xformations (applied from root to shape leaf nodes) not quite right--but very close. + Canvas does not have a built in transformation function that allows skewing. Need to + track skew matrix with Shape, and perform other trans/rot/scale transformations without + using canvas transform functions. + + +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/gfx.js +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/gfx/* + +Install into the following directory structure: +/dojox/gfx/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- diff --git a/includes/js/dojox/gfx/_base.js b/includes/js/dojox/gfx/_base.js new file mode 100644 index 0000000..3b118c2 --- /dev/null +++ b/includes/js/dojox/gfx/_base.js @@ -0,0 +1,288 @@ +if(!dojo._hasResource["dojox.gfx._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx._base"] = true; +dojo.provide("dojox.gfx._base"); + +(function(){ + var g = dojox.gfx, b = g._base; + + // candidates for dojox.style (work on VML and SVG nodes) + g._hasClass = function(/*DomNode*/node, /*String*/classStr){ + // summary: + // Returns whether or not the specified classes are a portion of the + // class list currently applied to the node. + // return (new RegExp('(^|\\s+)'+classStr+'(\\s+|$)')).test(node.className) // Boolean + return ((" "+node.getAttribute("className")+" ").indexOf(" "+classStr+" ") >= 0); // Boolean + } + g._addClass = function(/*DomNode*/node, /*String*/classStr){ + // summary: + // Adds the specified classes to the end of the class list on the + // passed node. + var cls = node.getAttribute("className"); + if((" "+cls+" ").indexOf(" "+classStr+" ") < 0){ + node.setAttribute("className", cls + (cls ? ' ' : '') + classStr); + } + } + g._removeClass = function(/*DomNode*/node, /*String*/classStr){ + // summary: Removes classes from node. + node.setAttribute("className", node.getAttribute("className").replace(new RegExp('(^|\\s+)'+classStr+'(\\s+|$)'), "$1$2")); + } + + + // candidate for dojox.html.metrics (dynamic font resize handler is not implemented here) + + // derived from Morris John's emResized measurer + b._getFontMeasurements = function(){ + // summary + // Returns an object that has pixel equivilents of standard font size values. + var heights = { + '1em':0, '1ex':0, '100%':0, '12pt':0, '16px':0, 'xx-small':0, 'x-small':0, + 'small':0, 'medium':0, 'large':0, 'x-large':0, 'xx-large':0 + }; + + if(dojo.isIE){ + // we do a font-size fix if and only if one isn't applied already. + // NOTE: If someone set the fontSize on the HTML Element, this will kill it. + dojo.doc.documentElement.style.fontSize="100%"; + } + + // set up the measuring node. + var div=dojo.doc.createElement("div"); + div.style.position="absolute"; + div.style.left="-100px"; + div.style.top="0"; + div.style.width="30px"; + div.style.height="1000em"; + div.style.border="0"; + div.style.margin="0"; + div.style.padding="0"; + div.style.outline="0"; + div.style.lineHeight="1"; + div.style.overflow="hidden"; + dojo.body().appendChild(div); + + // do the measurements. + for(var p in heights){ + div.style.fontSize = p; + heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000; + } + + dojo.body().removeChild(div); + div = null; + return heights; // object + }; + + var fontMeasurements = null; + + b._getCachedFontMeasurements = function(recalculate){ + if(recalculate || !fontMeasurements){ + fontMeasurements = b._getFontMeasurements(); + } + return fontMeasurements; + }; + + // candidate for dojox.html.metrics + + var measuringNode = null, empty = {}; + b._getTextBox = function(/* String */ text, /* Object */ style, /* String? */ className){ + var m; + if(!measuringNode){ + m = measuringNode = dojo.doc.createElement("div"); + m.style.position = "absolute"; + m.style.left = "-10000px"; + m.style.top = "0"; + dojo.body().appendChild(m); + }else{ + m = measuringNode; + } + // reset styles + m.className = ""; + m.style.border = "0"; + m.style.margin = "0"; + m.style.padding = "0"; + m.style.outline = "0"; + // set new style + if(arguments.length > 1 && style){ + for(var i in style){ + if(i in empty){ continue; } + m.style[i] = style[i]; + } + } + // set classes + if(arguments.length > 2 && className){ + m.className = className; + } + // take a measure + m.innerHTML = text; + return dojo.marginBox(m); + }; + + // candidate for dojo.dom + + var uniqueId = 0; + b._getUniqueId = function(){ + // summary: returns a unique string for use with any DOM element + var id; + do{ + id = dojo._scopeName + "Unique" + (++uniqueId); + }while(dojo.byId(id)); + return id; + }; +})(); + +dojo.mixin(dojox.gfx, { + // summary: defines constants, prototypes, and utility functions + + // default shapes, which are used to fill in missing parameters + defaultPath: {type: "path", path: ""}, + defaultPolyline: {type: "polyline", points: []}, + defaultRect: {type: "rect", x: 0, y: 0, width: 100, height: 100, r: 0}, + defaultEllipse: {type: "ellipse", cx: 0, cy: 0, rx: 200, ry: 100}, + defaultCircle: {type: "circle", cx: 0, cy: 0, r: 100}, + defaultLine: {type: "line", x1: 0, y1: 0, x2: 100, y2: 100}, + defaultImage: {type: "image", x: 0, y: 0, width: 0, height: 0, src: ""}, + defaultText: {type: "text", x: 0, y: 0, text: "", + align: "start", decoration: "none", rotated: false, kerning: true }, + defaultTextPath: {type: "textpath", text: "", + align: "start", decoration: "none", rotated: false, kerning: true }, + + // default geometric attributes + defaultStroke: {type: "stroke", color: "black", style: "solid", width: 1, cap: "butt", join: 4}, + defaultLinearGradient: {type: "linear", x1: 0, y1: 0, x2: 100, y2: 100, + colors: [{offset: 0, color: "black"}, {offset: 1, color: "white"}]}, + defaultRadialGradient: {type: "radial", cx: 0, cy: 0, r: 100, + colors: [{offset: 0, color: "black"}, {offset: 1, color: "white"}]}, + defaultPattern: {type: "pattern", x: 0, y: 0, width: 0, height: 0, src: ""}, + defaultFont: {type: "font", style: "normal", variant: "normal", weight: "normal", + size: "10pt", family: "serif"}, + + normalizeColor: function(/*Color*/ color){ + // summary: converts any legal color representation to normalized dojo.Color object + return (color instanceof dojo.Color) ? color : new dojo.Color(color); // dojo.Color + }, + normalizeParameters: function(existed, update){ + // summary: updates an existing object with properties from an "update" object + // existed: Object: the "target" object to be updated + // update: Object: the "update" object, whose properties will be used to update the existed object + if(update){ + var empty = {}; + for(var x in existed){ + if(x in update && !(x in empty)){ + existed[x] = update[x]; + } + } + } + return existed; // Object + }, + makeParameters: function(defaults, update){ + // summary: copies the original object, and all copied properties from the "update" object + // defaults: Object: the object to be cloned before updating + // update: Object: the object, which properties are to be cloned during updating + if(!update) return dojo.clone(defaults); + var result = {}; + for(var i in defaults){ + if(!(i in result)){ + result[i] = dojo.clone((i in update) ? update[i] : defaults[i]); + } + } + return result; // Object + }, + formatNumber: function(x, addSpace){ + // summary: converts a number to a string using a fixed notation + // x: Number: number to be converted + // addSpace: Boolean?: if it is true, add a space before a positive number + var val = x.toString(); + if(val.indexOf("e") >= 0){ + val = x.toFixed(4); + }else{ + var point = val.indexOf("."); + if(point >= 0 && val.length - point > 5){ + val = x.toFixed(4); + } + } + if(x < 0){ + return val; // String + } + return addSpace ? " " + val : val; // String + }, + // font operations + makeFontString: function(font){ + // summary: converts a font object to a CSS font string + // font: Object: font object (see dojox.gfx.defaultFont) + return font.style + " " + font.variant + " " + font.weight + " " + font.size + " " + font.family; // Object + }, + splitFontString: function(str){ + // summary: converts a CSS font string to a font object + // str: String: a CSS font string + var font = dojo.clone(dojox.gfx.defaultFont); + var t = str.split(/\s+/); + do{ + if(t.length < 5){ break; } + font.style = t[0]; + font.varian = t[1]; + font.weight = t[2]; + var i = t[3].indexOf("/"); + font.size = i < 0 ? t[3] : t[3].substring(0, i); + var j = 4; + if(i < 0){ + if(t[4] == "/"){ + j = 6; + break; + } + if(t[4].substr(0, 1) == "/"){ + j = 5; + break; + } + } + if(j + 3 > t.length){ break; } + font.size = t[j]; + font.family = t[j + 1]; + }while(false); + return font; // Object + }, + // length operations + cm_in_pt: 72 / 2.54, // Number: centimeters per inch + mm_in_pt: 7.2 / 2.54, // Number: millimeters per inch + px_in_pt: function(){ + // summary: returns a number of pixels per point + return dojox.gfx._base._getCachedFontMeasurements()["12pt"] / 12; // Number + }, + pt2px: function(len){ + // summary: converts points to pixels + // len: Number: a value in points + return len * dojox.gfx.px_in_pt(); // Number + }, + px2pt: function(len){ + // summary: converts pixels to points + // len: Number: a value in pixels + return len / dojox.gfx.px_in_pt(); // Number + }, + normalizedLength: function(len) { + // summary: converts any length value to pixels + // len: String: a length, e.g., "12pc" + if(len.length == 0) return 0; + if(len.length > 2){ + var px_in_pt = dojox.gfx.px_in_pt(); + var val = parseFloat(len); + switch(len.slice(-2)){ + case "px": return val; + case "pt": return val * px_in_pt; + case "in": return val * 72 * px_in_pt; + case "pc": return val * 12 * px_in_pt; + case "mm": return val / dojox.gfx.mm_in_pt * px_in_pt; + case "cm": return val / dojox.gfx.cm_in_pt * px_in_pt; + } + } + return parseFloat(len); // Number + }, + + // a constant used to split a SVG/VML path into primitive components + pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g, + pathSvgRegExp: /([A-Za-z])|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g, + + equalSources: function(a, b){ + // summary: compares event sources, returns true if they are equal + return a && b && a == b; + } +}); + +} diff --git a/includes/js/dojox/gfx/arc.js b/includes/js/dojox/gfx/arc.js new file mode 100644 index 0000000..4a0eade --- /dev/null +++ b/includes/js/dojox/gfx/arc.js @@ -0,0 +1,122 @@ +if(!dojo._hasResource["dojox.gfx.arc"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.arc"] = true; +dojo.provide("dojox.gfx.arc"); + +dojo.require("dojox.gfx.matrix"); + +(function(){ + var m = dojox.gfx.matrix, + unitArcAsBezier = function(alpha){ + // summary: return a start point, 1st and 2nd control points, and an end point of + // a an arc, which is reflected on the x axis + // alpha: Number: angle in radians, the arc will be 2 * angle size + var cosa = Math.cos(alpha), sina = Math.sin(alpha), + p2 = {x: cosa + (4 / 3) * (1 - cosa), y: sina - (4 / 3) * cosa * (1 - cosa) / sina}; + return { // Object + s: {x: cosa, y: -sina}, + c1: {x: p2.x, y: -p2.y}, + c2: p2, + e: {x: cosa, y: sina} + }; + }, + twoPI = 2 * Math.PI, pi4 = Math.PI / 4, pi8 = Math.PI / 8, + pi48 = pi4 + pi8, curvePI4 = unitArcAsBezier(pi8); + + dojo.mixin(dojox.gfx.arc, { + unitArcAsBezier: unitArcAsBezier, + curvePI4: curvePI4, + arcAsBezier: function(last, rx, ry, xRotg, large, sweep, x, y){ + // summary: calculates an arc as a series of Bezier curves + // given the last point and a standard set of SVG arc parameters, + // it returns an array of arrays of parameters to form a series of + // absolute Bezier curves. + // last: Object: a point-like object as a start of the arc + // rx: Number: a horizontal radius for the virtual ellipse + // ry: Number: a vertical radius for the virtual ellipse + // xRotg: Number: a rotation of an x axis of the virtual ellipse in degrees + // large: Boolean: which part of the ellipse will be used (the larger arc if true) + // sweep: Boolean: direction of the arc (CW if true) + // x: Number: the x coordinate of the end point of the arc + // y: Number: the y coordinate of the end point of the arc + + // calculate parameters + large = Boolean(large); + sweep = Boolean(sweep); + var xRot = m._degToRad(xRotg), + rx2 = rx * rx, ry2 = ry * ry, + pa = m.multiplyPoint( + m.rotate(-xRot), + {x: (last.x - x) / 2, y: (last.y - y) / 2} + ), + pax2 = pa.x * pa.x, pay2 = pa.y * pa.y, + c1 = Math.sqrt((rx2 * ry2 - rx2 * pay2 - ry2 * pax2) / (rx2 * pay2 + ry2 * pax2)); + if(isNaN(c1)){ c1 = 0; } + var ca = { + x: c1 * rx * pa.y / ry, + y: -c1 * ry * pa.x / rx + }; + if(large == sweep){ + ca = {x: -ca.x, y: -ca.y}; + } + // the center + var c = m.multiplyPoint( + [ + m.translate( + (last.x + x) / 2, + (last.y + y) / 2 + ), + m.rotate(xRot) + ], + ca + ); + // calculate the elliptic transformation + var elliptic_transform = m.normalize([ + m.translate(c.x, c.y), + m.rotate(xRot), + m.scale(rx, ry) + ]); + // start, end, and size of our arc + var inversed = m.invert(elliptic_transform), + sp = m.multiplyPoint(inversed, last), + ep = m.multiplyPoint(inversed, x, y), + startAngle = Math.atan2(sp.y, sp.x), + endAngle = Math.atan2(ep.y, ep.x), + theta = startAngle - endAngle; // size of our arc in radians + if(sweep){ theta = -theta; } + if(theta < 0){ + theta += twoPI; + }else if(theta > twoPI){ + theta -= twoPI; + } + + // draw curve chunks + var alpha = pi8, curve = curvePI4, step = sweep ? alpha : -alpha, + result = []; + for(var angle = theta; angle > 0; angle -= pi4){ + if(angle < pi48){ + alpha = angle / 2; + curve = unitArcAsBezier(alpha); + step = sweep ? alpha : -alpha; + angle = 0; // stop the loop + } + var c1, c2, e, + M = m.normalize([elliptic_transform, m.rotate(startAngle + step)]); + if(sweep){ + c1 = m.multiplyPoint(M, curve.c1); + c2 = m.multiplyPoint(M, curve.c2); + e = m.multiplyPoint(M, curve.e ); + }else{ + c1 = m.multiplyPoint(M, curve.c2); + c2 = m.multiplyPoint(M, curve.c1); + e = m.multiplyPoint(M, curve.s ); + } + // draw the curve + result.push([c1.x, c1.y, c2.x, c2.y, e.x, e.y]); + startAngle += 2 * step; + } + return result; // Object + } + }); +})(); + +} diff --git a/includes/js/dojox/gfx/attach.js b/includes/js/dojox/gfx/attach.js new file mode 100644 index 0000000..901f66f --- /dev/null +++ b/includes/js/dojox/gfx/attach.js @@ -0,0 +1,7 @@ +dojo.require("dojox.gfx"); + +// include an attacher conditionally +dojo.requireIf(dojox.gfx.renderer == "svg", "dojox.gfx.svg_attach"); +dojo.requireIf(dojox.gfx.renderer == "vml", "dojox.gfx.vml_attach"); +dojo.requireIf(dojox.gfx.renderer == "silverlight", "dojox.gfx.silverlight_attach"); +dojo.requireIf(dojox.gfx.renderer == "canvas", "dojox.gfx.canvas_attach"); diff --git a/includes/js/dojox/gfx/canvas.js b/includes/js/dojox/gfx/canvas.js new file mode 100644 index 0000000..6872b2f --- /dev/null +++ b/includes/js/dojox/gfx/canvas.js @@ -0,0 +1,687 @@ +if(!dojo._hasResource["dojox.gfx.canvas"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.canvas"] = true; +dojo.provide("dojox.gfx.canvas"); + +dojo.require("dojox.gfx._base"); +dojo.require("dojox.gfx.shape"); +dojo.require("dojox.gfx.path"); +dojo.require("dojox.gfx.arc"); +dojo.require("dojox.gfx.decompose"); + +dojo.experimental("dojox.gfx.canvas"); + +(function(){ + var g = dojox.gfx, gs = g.shape, ga = g.arc, + m = g.matrix, mp = m.multiplyPoint, pi = Math.PI, twoPI = 2 * pi, halfPI = pi /2; + + dojo.extend(g.Shape, { + _render: function(/* Object */ ctx){ + // summary: render the shape + ctx.save(); + this._renderTransform(ctx); + this._renderShape(ctx); + this._renderFill(ctx, true); + this._renderStroke(ctx, true); + ctx.restore(); + }, + _renderTransform: function(/* Object */ ctx){ + if("canvasTransform" in this){ + var t = this.canvasTransform; + ctx.translate(t.dx, t.dy); + ctx.rotate(t.angle2); + ctx.scale(t.sx, t.sy); + ctx.rotate(t.angle1); + // The future implementation when vendors catch up with the spec: + // var t = this.matrix; + // ctx.transform(t.xx, t.yx, t.xy, t.yy, t.dx, t.dy); + } + }, + _renderShape: function(/* Object */ ctx){ + // nothing + }, + _renderFill: function(/* Object */ ctx, /* Boolean */ apply){ + if("canvasFill" in this){ + if("canvasFillImage" in this){ + this.canvasFill = ctx.createPattern(this.canvasFillImage, "repeat"); + delete this.canvasFillImage; + } + ctx.fillStyle = this.canvasFill; + if(apply){ ctx.fill(); } + }else{ + ctx.fillStyle = "rgba(0,0,0,0.0)"; + } + }, + _renderStroke: function(/* Object */ ctx, /* Boolean */ apply){ + var s = this.strokeStyle; + if(s){ + ctx.strokeStyle = s.color.toString(); + ctx.lineWidth = s.width; + ctx.lineCap = s.cap; + if(typeof s.join == "number"){ + ctx.lineJoin = "miter"; + ctx.miterLimit = s.join; + }else{ + ctx.lineJoin = s.join; + } + if(apply){ ctx.stroke(); } + }else if(!apply){ + ctx.strokeStyle = "rgba(0,0,0,0.0)"; + } + }, + + // events are not implemented + getEventSource: function(){ return null; }, + connect: function(){}, + disconnect: function(){} + }); + + var modifyMethod = function(shape, method, extra){ + var old = shape.prototype[method]; + shape.prototype[method] = extra ? + function(){ + this.surface.makeDirty(); + old.apply(this, arguments); + extra.call(this); + return this; + } : + function(){ + this.surface.makeDirty(); + return old.apply(this, arguments); + }; + }; + + modifyMethod(g.Shape, "setTransform", + function(){ + // prepare Canvas-specific structures + if(this.matrix){ + this.canvasTransform = g.decompose(this.matrix); + }else{ + delete this.canvasTransform; + } + }); + + modifyMethod(g.Shape, "setFill", + function(){ + // prepare Canvas-specific structures + var fs = this.fillStyle, f; + if(fs){ + if(typeof(fs) == "object" && "type" in fs){ + var ctx = this.surface.rawNode.getContext("2d"); + switch(fs.type){ + case "linear": + case "radial": + f = fs.type == "linear" ? + ctx.createLinearGradient(fs.x1, fs.y1, fs.x2, fs.y2) : + ctx.createRadialGradient(fs.cx, fs.cy, 0, fs.cx, fs.cy, fs.r); + dojo.forEach(fs.colors, function(step){ + f.addColorStop(step.offset, g.normalizeColor(step.color).toString()); + }); + break; + case "pattern": + var img = new Image(fs.width, fs.height); + this.surface.downloadImage(img, fs.src); + this.canvasFillImage = img; + } + }else{ + // Set fill color using CSS RGBA func style + f = fs.toString(); + } + this.canvasFill = f; + }else{ + delete this.canvasFill; + } + }); + + modifyMethod(g.Shape, "setStroke"); + modifyMethod(g.Shape, "setShape"); + + dojo.declare("dojox.gfx.Group", g.Shape, { + // summary: a group shape (Canvas), which can be used + // to logically group shapes (e.g, to propagate matricies) + constructor: function(){ + gs.Container._init.call(this); + }, + _render: function(/* Object */ ctx){ + // summary: render the group + ctx.save(); + this._renderTransform(ctx); + this._renderFill(ctx); + this._renderStroke(ctx); + for(var i = 0; i < this.children.length; ++i){ + this.children[i]._render(ctx); + } + ctx.restore(); + } + }); + + dojo.declare("dojox.gfx.Rect", gs.Rect, { + // summary: a rectangle shape (Canvas) + _renderShape: function(/* Object */ ctx){ + var s = this.shape, r = Math.min(s.r, s.height / 2, s.width / 2), + xl = s.x, xr = xl + s.width, yt = s.y, yb = yt + s.height, + xl2 = xl + r, xr2 = xr - r, yt2 = yt + r, yb2 = yb - r; + ctx.beginPath(); + ctx.moveTo(xl2, yt); + if(r){ + ctx.arc(xr2, yt2, r, -halfPI, 0, false); + ctx.arc(xr2, yb2, r, 0, halfPI, false); + ctx.arc(xl2, yb2, r, halfPI, pi, false); + ctx.arc(xl2, yt2, r, pi, halfPI, false); + }else{ + ctx.lineTo(xr2, yt); + ctx.lineTo(xr, yb2); + ctx.lineTo(xl2, yb); + ctx.lineTo(xl, yt2); + } + ctx.closePath(); + } + }); + + var bezierCircle = []; + (function(){ + var u = ga.curvePI4; + bezierCircle.push(u.s, u.c1, u.c2, u.e); + for(var a = 45; a < 360; a += 45){ + var r = m.rotateg(a); + bezierCircle.push(mp(r, u.c1), mp(r, u.c2), mp(r, u.e)); + } + })(); + + dojo.declare("dojox.gfx.Ellipse", gs.Ellipse, { + // summary: an ellipse shape (Canvas) + setShape: function(){ + g.Ellipse.superclass.setShape.apply(this, arguments); + // prepare Canvas-specific structures + var s = this.shape, t, c1, c2, r = [], + M = m.normalize([m.translate(s.cx, s.cy), m.scale(s.rx, s.ry)]); + t = mp(M, bezierCircle[0]); + r.push([t.x, t.y]); + for(var i = 1; i < bezierCircle.length; i += 3){ + c1 = mp(M, bezierCircle[i]); + c2 = mp(M, bezierCircle[i + 1]); + t = mp(M, bezierCircle[i + 2]); + r.push([c1.x, c1.y, c2.x, c2.y, t.x, t.y]); + } + this.canvasEllipse = r; + return this; + }, + _renderShape: function(/* Object */ ctx){ + var r = this.canvasEllipse; + ctx.beginPath(); + ctx.moveTo.apply(ctx, r[0]); + for(var i = 1; i < r.length; ++i){ + ctx.bezierCurveTo.apply(ctx, r[i]); + } + ctx.closePath(); + } + }); + + dojo.declare("dojox.gfx.Circle", gs.Circle, { + // summary: a circle shape (Canvas) + _renderShape: function(/* Object */ ctx){ + var s = this.shape; + ctx.beginPath(); + ctx.arc(s.cx, s.cy, s.r, 0, twoPI, 1); + } + }); + + dojo.declare("dojox.gfx.Line", gs.Line, { + // summary: a line shape (Canvas) + _renderShape: function(/* Object */ ctx){ + var s = this.shape; + ctx.beginPath(); + ctx.moveTo(s.x1, s.y1); + ctx.lineTo(s.x2, s.y2); + } + }); + + dojo.declare("dojox.gfx.Polyline", gs.Polyline, { + // summary: a polyline/polygon shape (Canvas) + setShape: function(){ + g.Polyline.superclass.setShape.apply(this, arguments); + // dojo.inherited("setShape", arguments); + // prepare Canvas-specific structures + var p = this.shape.points, f = p[0], r = [], c, i; + if(p.length){ + if(typeof f == "number"){ + r.push(f, p[1]); + i = 2; + }else{ + r.push(f.x, f.y); + i = 1; + } + for(; i < p.length; ++i){ + c = p[i]; + if(typeof c == "number"){ + r.push(c, p[++i]); + }else{ + r.push(c.x, c.y); + } + } + } + this.canvasPolyline = r; + return this; + }, + _renderShape: function(/* Object */ ctx){ + // console.debug("Polyline::_renderShape"); + var p = this.canvasPolyline; + if(p.length){ + ctx.beginPath(); + ctx.moveTo(p[0], p[1]); + for(var i = 2; i < p.length; i += 2){ + ctx.lineTo(p[i], p[i + 1]); + } + } + } + }); + + dojo.declare("dojox.gfx.Image", gs.Image, { + // summary: an image shape (Canvas) + setShape: function(){ + g.Image.superclass.setShape.apply(this, arguments); + // prepare Canvas-specific structures + var img = new Image(); + this.surface.downloadImage(img, this.shape.src); + this.canvasImage = img; + return this; + }, + _renderShape: function(/* Object */ ctx){ + var s = this.shape; + ctx.drawImage(this.canvasImage, s.x, s.y, s.width, s.height); + } + }); + + dojo.declare("dojox.gfx.Text", gs.Text, { + // summary: a text shape (Canvas) + _renderShape: function(/* Object */ ctx){ + var s = this.shape; + // nothing for the moment + } + }); + modifyMethod(g.Text, "setFont"); + + var pathRenderers = { + M: "_moveToA", m: "_moveToR", + L: "_lineToA", l: "_lineToR", + H: "_hLineToA", h: "_hLineToR", + V: "_vLineToA", v: "_vLineToR", + C: "_curveToA", c: "_curveToR", + S: "_smoothCurveToA", s: "_smoothCurveToR", + Q: "_qCurveToA", q: "_qCurveToR", + T: "_qSmoothCurveToA", t: "_qSmoothCurveToR", + A: "_arcTo", a: "_arcTo", + Z: "_closePath", z: "_closePath" + }; + + dojo.declare("dojox.gfx.Path", g.path.Path, { + // summary: a path shape (Canvas) + constructor: function(){ + this.last = {}; + this.lastControl = {}; + }, + setShape: function(){ + this.canvasPath = []; + return g.Path.superclass.setShape.apply(this, arguments); + }, + _updateWithSegment: function(segment){ + var last = dojo.clone(this.last); + this[pathRenderers[segment.action]](this.canvasPath, segment.action, segment.args); + this.last = last; + g.Path.superclass._updateWithSegment.apply(this, arguments); + }, + _renderShape: function(/* Object */ ctx){ + var r = this.canvasPath; + ctx.beginPath(); + for(var i = 0; i < r.length; i += 2){ + ctx[r[i]].apply(ctx, r[i + 1]); + } + }, + _moveToA: function(result, action, args){ + result.push("moveTo", [args[0], args[1]]); + for(var i = 2; i < args.length; i += 2){ + result.push("lineTo", [args[i], args[i + 1]]); + } + this.last.x = args[args.length - 2]; + this.last.y = args[args.length - 1]; + this.lastControl = {}; + }, + _moveToR: function(result, action, args){ + if("x" in this.last){ + result.push("moveTo", [this.last.x += args[0], this.last.y += args[1]]); + }else{ + result.push("moveTo", [this.last.x = args[0], this.last.y = args[1]]); + } + for(var i = 2; i < args.length; i += 2){ + result.push("lineTo", [this.last.x += args[i], this.last.y += args[i + 1]]); + } + this.lastControl = {}; + }, + _lineToA: function(result, action, args){ + for(var i = 0; i < args.length; i += 2){ + result.push("lineTo", [args[i], args[i + 1]]); + } + this.last.x = args[args.length - 2]; + this.last.y = args[args.length - 1]; + this.lastControl = {}; + }, + _lineToR: function(result, action, args){ + for(var i = 0; i < args.length; i += 2){ + result.push("lineTo", [this.last.x += args[i], this.last.y += args[i + 1]]); + } + this.lastControl = {}; + }, + _hLineToA: function(result, action, args){ + for(var i = 0; i < args.length; ++i){ + result.push("lineTo", [args[i], this.last.y]); + } + this.last.x = args[args.length - 1]; + this.lastControl = {}; + }, + _hLineToR: function(result, action, args){ + for(var i = 0; i < args.length; ++i){ + result.push("lineTo", [this.last.x += args[i], this.last.y]); + } + this.lastControl = {}; + }, + _vLineToA: function(result, action, args){ + for(var i = 0; i < args.length; ++i){ + result.push("lineTo", [this.last.x, args[i]]); + } + this.last.y = args[args.length - 1]; + this.lastControl = {}; + }, + _vLineToR: function(result, action, args){ + for(var i = 0; i < args.length; ++i){ + result.push("lineTo", [this.last.x, this.last.y += args[i]]); + } + this.lastControl = {}; + }, + _curveToA: function(result, action, args){ + for(var i = 0; i < args.length; i += 6){ + result.push("bezierCurveTo", args.slice(i, i + 6)); + } + this.last.x = args[args.length - 2]; + this.last.y = args[args.length - 1]; + this.lastControl.x = args[args.length - 4]; + this.lastControl.y = args[args.length - 3]; + this.lastControl.type = "C"; + }, + _curveToR: function(result, action, args){ + for(var i = 0; i < args.length; i += 6){ + result.push("bezierCurveTo", [ + this.last.x + args[i], + this.last.y + args[i + 1], + this.lastControl.x = this.last.x + args[i + 2], + this.lastControl.y = this.last.y + args[i + 3], + this.last.x + args[i + 4], + this.last.y + args[i + 5] + ]); + this.last.x += args[i + 4]; + this.last.y += args[i + 5]; + } + this.lastControl.type = "C"; + }, + _smoothCurveToA: function(result, action, args){ + for(var i = 0; i < args.length; i += 4){ + var valid = this.lastControl.type == "C"; + result.push("bezierCurveTo", [ + valid ? 2 * this.last.x - this.lastControl.x : this.last.x, + valid ? 2 * this.last.y - this.lastControl.y : this.last.y, + args[i], + args[i + 1], + args[i + 2], + args[i + 3] + ]); + this.lastControl.x = args[i]; + this.lastControl.y = args[i + 1]; + this.lastControl.type = "C"; + } + this.last.x = args[args.length - 2]; + this.last.y = args[args.length - 1]; + }, + _smoothCurveToR: function(result, action, args){ + for(var i = 0; i < args.length; i += 4){ + var valid = this.lastControl.type == "C"; + result.push("bezierCurveTo", [ + valid ? 2 * this.last.x - this.lastControl.x : this.last.x, + valid ? 2 * this.last.y - this.lastControl.y : this.last.y, + this.last.x + args[i], + this.last.y + args[i + 1], + this.last.x + args[i + 2], + this.last.y + args[i + 3] + ]); + this.lastControl.x = this.last.x + args[i]; + this.lastControl.y = this.last.y + args[i + 1]; + this.lastControl.type = "C"; + this.last.x += args[i + 2]; + this.last.y += args[i + 3]; + } + }, + _qCurveToA: function(result, action, args){ + for(var i = 0; i < args.length; i += 4){ + result.push("quadraticCurveTo", args.slice(i, i + 4)); + } + this.last.x = args[args.length - 2]; + this.last.y = args[args.length - 1]; + this.lastControl.x = args[args.length - 4]; + this.lastControl.y = args[args.length - 3]; + this.lastControl.type = "Q"; + }, + _qCurveToR: function(result, action, args){ + for(var i = 0; i < args.length; i += 4){ + result.push("quadraticCurveTo", [ + this.lastControl.x = this.last.x + args[i], + this.lastControl.y = this.last.y + args[i + 1], + this.last.x + args[i + 2], + this.last.y + args[i + 3] + ]); + this.last.x += args[i + 2]; + this.last.y += args[i + 3]; + } + this.lastControl.type = "Q"; + }, + _qSmoothCurveToA: function(result, action, args){ + for(var i = 0; i < args.length; i += 2){ + var valid = this.lastControl.type == "Q"; + result.push("quadraticCurveTo", [ + this.lastControl.x = valid ? 2 * this.last.x - this.lastControl.x : this.last.x, + this.lastControl.y = valid ? 2 * this.last.y - this.lastControl.y : this.last.y, + args[i], + args[i + 1] + ]); + this.lastControl.type = "Q"; + } + this.last.x = args[args.length - 2]; + this.last.y = args[args.length - 1]; + }, + _qSmoothCurveToR: function(result, action, args){ + for(var i = 0; i < args.length; i += 2){ + var valid = this.lastControl.type == "Q"; + result.push("quadraticCurveTo", [ + this.lastControl.x = valid ? 2 * this.last.x - this.lastControl.x : this.last.x, + this.lastControl.y = valid ? 2 * this.last.y - this.lastControl.y : this.last.y, + this.last.x + args[i], + this.last.y + args[i + 1] + ]); + this.lastControl.type = "Q"; + this.last.x += args[i]; + this.last.y += args[i + 1]; + } + }, + _arcTo: function(result, action, args){ + var relative = action == "a"; + for(var i = 0; i < args.length; i += 7){ + var x1 = args[i + 5], y1 = args[i + 6]; + if(relative){ + x1 += this.last.x; + y1 += this.last.y; + } + var arcs = ga.arcAsBezier( + this.last, args[i], args[i + 1], args[i + 2], + args[i + 3] ? 1 : 0, args[i + 4] ? 1 : 0, + x1, y1 + ); + dojo.forEach(arcs, function(p){ + result.push("bezierCurveTo", p); + }); + this.last.x = x1; + this.last.y = y1; + } + this.lastControl = {}; + }, + _closePath: function(result, action, args){ + result.push("closePath", []); + this.lastControl = {}; + } + }); + dojo.forEach(["moveTo", "lineTo", "hLineTo", "vLineTo", "curveTo", + "smoothCurveTo", "qCurveTo", "qSmoothCurveTo", "arcTo", "closePath"], + function(method){ modifyMethod(g.Path, method); } + ); + + dojo.declare("dojox.gfx.TextPath", g.path.TextPath, { + // summary: a text shape (Canvas) + _renderShape: function(/* Object */ ctx){ + var s = this.shape; + // nothing for the moment + } + }); + + dojo.declare("dojox.gfx.Surface", gs.Surface, { + // summary: a surface object to be used for drawings (Canvas) + constructor: function(){ + gs.Container._init.call(this); + this.pendingImageCount = 0; + this.makeDirty(); + }, + setDimensions: function(width, height){ + // summary: sets the width and height of the rawNode + // width: String: width of surface, e.g., "100px" + // height: String: height of surface, e.g., "100px" + this.width = g.normalizedLength(width); // in pixels + this.height = g.normalizedLength(height); // in pixels + if(!this.rawNode) return this; + this.rawNode.width = width; + this.rawNode.height = height; + this.makeDirty(); + return this; // self + }, + getDimensions: function(){ + // summary: returns an object with properties "width" and "height" + return this.rawNode ? {width: this.rawNode.width, height: this.rawNode.height} : null; // Object + }, + _render: function(){ + // summary: render the all shapes + if(this.pendingImageCount){ return; } + var ctx = this.rawNode.getContext("2d"); + ctx.save(); + ctx.clearRect(0, 0, this.rawNode.width, this.rawNode.height); + for(var i = 0; i < this.children.length; ++i){ + this.children[i]._render(ctx); + } + ctx.restore(); + if("pendingRender" in this){ + clearTimeout(this.pendingRender); + delete this.pendingRender; + } + }, + makeDirty: function(){ + // summary: internal method, which is called when we may need to redraw + if(!this.pendingImagesCount && !("pendingRender" in this)){ + this.pendingRender = setTimeout(dojo.hitch(this, this._render), 0); + } + }, + downloadImage: function(img, url){ + // summary: + // internal method, which starts an image download and renders, when it is ready + // img: Image: + // the image object + // url: String: + // the url of the image + var handler = dojo.hitch(this, this.onImageLoad); + if(!this.pendingImageCount++ && "pendingRender" in this){ + clearTimeout(this.pendingRender); + delete this.pendingRender; + } + img.onload = handler; + img.onerror = handler; + img.onabort = handler; + img.src = url; + }, + onImageLoad: function(){ + if(!--this.pendingImageCount){ this._render(); } + }, + + // events are not implemented + getEventSource: function(){ return null; }, + connect: function(){}, + disconnect: function(){} + }); + + g.createSurface = function(parentNode, width, height){ + // summary: creates a surface (Canvas) + // parentNode: Node: a parent node + // width: String: width of surface, e.g., "100px" + // height: String: height of surface, e.g., "100px" + + if(!width){ width = "100%"; } + if(!height){ height = "100%"; } + var s = new g.Surface(), + p = dojo.byId(parentNode), + c = p.ownerDocument.createElement("canvas"); + c.width = width; + c.height = height; + p.appendChild(c); + s.rawNode = c; + s.surface = s; + return s; // dojox.gfx.Surface + }; + + // Extenders + + var C = gs.Container, Container = { + add: function(shape){ + this.surface.makeDirty(); + return C.add.apply(this, arguments); + }, + remove: function(shape, silently){ + this.surface.makeDirty(); + return C.remove.apply(this, arguments); + }, + clear: function(){ + this.surface.makeDirty(); + return C.clear.apply(this, arguments); + }, + _moveChildToFront: function(shape){ + this.surface.makeDirty(); + return C._moveChildToFront.apply(this, arguments); + }, + _moveChildToBack: function(shape){ + this.surface.makeDirty(); + return C._moveChildToBack.apply(this, arguments); + } + }; + + dojo.mixin(gs.Creator, { + // summary: Canvas shape creators + createObject: function(shapeType, rawShape) { + // summary: creates an instance of the passed shapeType class + // shapeType: Function: a class constructor to create an instance of + // rawShape: Object: properties to be passed in to the classes "setShape" method + // overrideSize: Boolean: set the size explicitly, if true + var shape = new shapeType(); + shape.surface = this.surface; + shape.setShape(rawShape); + this.add(shape); + return shape; // dojox.gfx.Shape + } + }); + + dojo.extend(g.Group, Container); + dojo.extend(g.Group, gs.Creator); + + dojo.extend(g.Surface, Container); + dojo.extend(g.Surface, gs.Creator); +})(); + +} diff --git a/includes/js/dojox/gfx/canvas_attach.js b/includes/js/dojox/gfx/canvas_attach.js new file mode 100644 index 0000000..82ccd13 --- /dev/null +++ b/includes/js/dojox/gfx/canvas_attach.js @@ -0,0 +1,8 @@ +dojo.require("dojox.gfx.canvas"); + +dojo.experimental("dojox.gfx.canvas_attach"); + +// not implemented +dojox.gfx.attachNode = function(){ + return null; // for now +}; diff --git a/includes/js/dojox/gfx/decompose.js b/includes/js/dojox/gfx/decompose.js new file mode 100644 index 0000000..4e34ee6 --- /dev/null +++ b/includes/js/dojox/gfx/decompose.js @@ -0,0 +1,139 @@ +if(!dojo._hasResource["dojox.gfx.decompose"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.decompose"] = true; +dojo.provide("dojox.gfx.decompose"); + +dojo.require("dojox.gfx.matrix"); + +(function(){ + var m = dojox.gfx.matrix; + + var eq = function(/* Number */ a, /* Number */ b){ + // summary: compare two FP numbers for equality + return Math.abs(a - b) <= 1e-6 * (Math.abs(a) + Math.abs(b)); // Boolean + }; + + var calcFromValues = function(/* Number */ r1, /* Number */ m1, /* Number */ r2, /* Number */ m2){ + // summary: uses two close FP ration and their original magnitudes to approximate the result + if(!isFinite(r1)){ + return r2; // Number + }else if(!isFinite(r2)){ + return r1; // Number + } + m1 = Math.abs(m1), m2 = Math.abs(m2); + return (m1 * r1 + m2 * r2) / (m1 + m2); // Number + }; + + var transpose = function(/* dojox.gfx.matrix.Matrix2D */ matrix){ + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object + var M = new m.Matrix2D(matrix); + return dojo.mixin(M, {dx: 0, dy: 0, xy: M.yx, yx: M.xy}); // dojox.gfx.matrix.Matrix2D + }; + + var scaleSign = function(/* dojox.gfx.matrix.Matrix2D */ matrix){ + return (matrix.xx * matrix.yy < 0 || matrix.xy * matrix.yx > 0) ? -1 : 1; // Number + }; + + var eigenvalueDecomposition = function(/* dojox.gfx.matrix.Matrix2D */ matrix){ + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object + var M = m.normalize(matrix), + b = -M.xx - M.yy, + c = M.xx * M.yy - M.xy * M.yx, + d = Math.sqrt(b * b - 4 * c), + l1 = -(b + (b < 0 ? -d : d)) / 2, + l2 = c / l1, + vx1 = M.xy / (l1 - M.xx), vy1 = 1, + vx2 = M.xy / (l2 - M.xx), vy2 = 1; + if(eq(l1, l2)){ + vx1 = 1, vy1 = 0, vx2 = 0, vy2 = 1; + } + if(!isFinite(vx1)){ + vx1 = 1, vy1 = (l1 - M.xx) / M.xy; + if(!isFinite(vy1)){ + vx1 = (l1 - M.yy) / M.yx, vy1 = 1; + if(!isFinite(vx1)){ + vx1 = 1, vy1 = M.yx / (l1 - M.yy); + } + } + } + if(!isFinite(vx2)){ + vx2 = 1, vy2 = (l2 - M.xx) / M.xy; + if(!isFinite(vy2)){ + vx2 = (l2 - M.yy) / M.yx, vy2 = 1; + if(!isFinite(vx2)){ + vx2 = 1, vy2 = M.yx / (l2 - M.yy); + } + } + } + var d1 = Math.sqrt(vx1 * vx1 + vy1 * vy1), + d2 = Math.sqrt(vx2 * vx2 + vy2 * vy2); + if(!isFinite(vx1 /= d1)){ vx1 = 0; } + if(!isFinite(vy1 /= d1)){ vy1 = 0; } + if(!isFinite(vx2 /= d2)){ vx2 = 0; } + if(!isFinite(vy2 /= d2)){ vy2 = 0; } + return { // Object + value1: l1, + value2: l2, + vector1: {x: vx1, y: vy1}, + vector2: {x: vx2, y: vy2} + }; + }; + + var decomposeSR = function(/* dojox.gfx.matrix.Matrix2D */ M, /* Object */ result){ + // summary: decomposes a matrix into [scale, rotate]; no checks are done. + var sign = scaleSign(M), + a = result.angle1 = (Math.atan2(M.yx, M.yy) + Math.atan2(-sign * M.xy, sign * M.xx)) / 2, + cos = Math.cos(a), sin = Math.sin(a); + result.sx = calcFromValues(M.xx / cos, cos, -M.xy / sin, sin); + result.sy = calcFromValues(M.yy / cos, cos, M.yx / sin, sin); + return result; // Object + }; + + var decomposeRS = function(/* dojox.gfx.matrix.Matrix2D */ M, /* Object */ result){ + // summary: decomposes a matrix into [rotate, scale]; no checks are done + var sign = scaleSign(M), + a = result.angle2 = (Math.atan2(sign * M.yx, sign * M.xx) + Math.atan2(-M.xy, M.yy)) / 2, + cos = Math.cos(a), sin = Math.sin(a); + result.sx = calcFromValues(M.xx / cos, cos, M.yx / sin, sin); + result.sy = calcFromValues(M.yy / cos, cos, -M.xy / sin, sin); + return result; // Object + }; + + dojox.gfx.decompose = function(matrix){ + // summary: decompose a 2D matrix into translation, scaling, and rotation components + // description: this function decompose a matrix into four logical components: + // translation, rotation, scaling, and one more rotation using SVD. + // The components should be applied in following order: + // | [translate, rotate(angle2), scale, rotate(angle1)] + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object + var M = m.normalize(matrix), + result = {dx: M.dx, dy: M.dy, sx: 1, sy: 1, angle1: 0, angle2: 0}; + // detect case: [scale] + if(eq(M.xy, 0) && eq(M.yx, 0)){ + return dojo.mixin(result, {sx: M.xx, sy: M.yy}); // Object + } + // detect case: [scale, rotate] + if(eq(M.xx * M.yx, -M.xy * M.yy)){ + return decomposeSR(M, result); // Object + } + // detect case: [rotate, scale] + if(eq(M.xx * M.xy, -M.yx * M.yy)){ + return decomposeRS(M, result); // Object + } + // do SVD + var MT = transpose(M), + u = eigenvalueDecomposition([M, MT]), + v = eigenvalueDecomposition([MT, M]), + U = new m.Matrix2D({xx: u.vector1.x, xy: u.vector2.x, yx: u.vector1.y, yy: u.vector2.y}), + VT = new m.Matrix2D({xx: v.vector1.x, xy: v.vector1.y, yx: v.vector2.x, yy: v.vector2.y}), + S = new m.Matrix2D([m.invert(U), M, m.invert(VT)]); + decomposeSR(VT, result); + S.xx *= result.sx; + S.yy *= result.sy; + decomposeRS(U, result); + S.xx *= result.sx; + S.yy *= result.sy; + return dojo.mixin(result, {sx: S.xx, sy: S.yy}); // Object + }; +})(); + +} diff --git a/includes/js/dojox/gfx/demos/beautify.html b/includes/js/dojox/gfx/demos/beautify.html new file mode 100644 index 0000000..d1f02f5 --- /dev/null +++ b/includes/js/dojox/gfx/demos/beautify.html @@ -0,0 +1,48 @@ + + +Beautify JSON + + + + + + +

      Beautify JSON

      +

      Paste valid JSON in this textarea and receive a pretty-printed version of it. Use Firefox, if you want to be able to read comma-ended sequences (Python style). + Additionally it knows how to remove extra spaces from path elements.

      +

      +

      +     Process "path" elements +     Pretty-print JSON

      +

      This program is a companion for inspector.html.

      + + diff --git a/includes/js/dojox/gfx/demos/butterfly.html b/includes/js/dojox/gfx/demos/butterfly.html new file mode 100644 index 0000000..2b9f188 --- /dev/null +++ b/includes/js/dojox/gfx/demos/butterfly.html @@ -0,0 +1,88 @@ + + +dojox.gfx: Butterfly + + + + + + + + +

      dojox.gfx: Butterfly

      +

      This example was directly converted from SVG file.

      +

      This is a slightly modified version of a sample that shipped with JASC's WebDraw (www.jasc.com). Generated by Jasc WebDraw PR4(tm) on 06/07/01 12:18:39.

      + + + + + +
      Rotation (0)
      +
      +
      +
      +
      +
      +
      Scaling (1.000)
      +
      +
      +
      +
      +
      +
      + + diff --git a/includes/js/dojox/gfx/demos/career_test.html b/includes/js/dojox/gfx/demos/career_test.html new file mode 100644 index 0000000..3958395 --- /dev/null +++ b/includes/js/dojox/gfx/demos/career_test.html @@ -0,0 +1,467 @@ + + +dojox.gfx: Career Aptitude Test + + + + + + + + + + + + + +

      dojox.gfx: Career Aptitude Test

      +

      Warning: Canvas renderer doesn't implement event handling.

      + +
      +

      Thank you for your interest in "I can't believe it's manure" Eateries™ +and for submitting your resume for our review. While this is an automated response, +please be assured that every resume is reviewed by us, and forwarded to the hiring +managers if the skills fit our needs.

      +

      In order order to evaluate your skills we ask you to take a career aptitude test. +You will have an exciting chance to operate one of our state-of-the-art workstations +remotely. Don't forget: +

      +
        +
      1. Fish out a live speciment of dung-42 from the container.
      2. +
      3. Freeze it until you see an orange glow to kill the elements and make it less green.
      4. +
      5. Broil it until you see the orange glow again, and drop it on the table below.
      6. +
      7. You have to process all items without wasting resources and in minimal time.
      8. +
      +

      Warnings: don't overfreeze, don't overheat, don't drop the speciment, don't change the sequence, +don't touch the speciment in heating and freezing chambers until it is's ready.

      +

      Use your head and your mouse!

      +

      Please select the desired position:

      + + + + + + + + + + + + + +
      Workstation Supervisor 
      Shift Director 
      Vice President #49653 
      +
      + + + + + + + diff --git a/includes/js/dojox/gfx/demos/circles.html b/includes/js/dojox/gfx/demos/circles.html new file mode 100644 index 0000000..ce4d0cd --- /dev/null +++ b/includes/js/dojox/gfx/demos/circles.html @@ -0,0 +1,90 @@ + + +dojox.gfx: 100 draggable circles + + + + + + + + + + +

      dojox.gfx: 100 draggable circles

      +

      Warning: Canvas renderer doesn't implement event handling.

      +
      + + diff --git a/includes/js/dojox/gfx/demos/clock.html b/includes/js/dojox/gfx/demos/clock.html new file mode 100644 index 0000000..8d4d8c1 --- /dev/null +++ b/includes/js/dojox/gfx/demos/clock.html @@ -0,0 +1,253 @@ + + +dojox.gfx: interactive analog clock + + + + + + + + +

      dojox.gfx: interactive analog clock

      +

      Grab hands and set your own time.

      +

      Warning: Canvas renderer doesn't implement event handling.

      +
      +

      Current time: .

      +

      + + diff --git a/includes/js/dojox/gfx/demos/clockWidget.html b/includes/js/dojox/gfx/demos/clockWidget.html new file mode 100644 index 0000000..409523c --- /dev/null +++ b/includes/js/dojox/gfx/demos/clockWidget.html @@ -0,0 +1,332 @@ + + +dojox.gfx: interactive analog clock + + + + + + + + +

      dojox.gfx: interactive analog clock

      +

      Grab hands and set your own time.

      +

      Warning: Canvas renderer doesn't implement event handling.

      + + + +
      + +
      +
      +
      +
      + +
      + + + + + + diff --git a/includes/js/dojox/gfx/demos/clock_black.html b/includes/js/dojox/gfx/demos/clock_black.html new file mode 100644 index 0000000..4c72770 --- /dev/null +++ b/includes/js/dojox/gfx/demos/clock_black.html @@ -0,0 +1,253 @@ + + +dojox.gfx: interactive analog clock + + + + + + + + +

      dojox.gfx: interactive analog clock

      +

      Grab hands and set your own time.

      +

      Warning: Canvas renderer doesn't implement event handling.

      +
      +

      Current time: .

      +

      + + diff --git a/includes/js/dojox/gfx/demos/creator.html b/includes/js/dojox/gfx/demos/creator.html new file mode 100644 index 0000000..48ddf5b --- /dev/null +++ b/includes/js/dojox/gfx/demos/creator.html @@ -0,0 +1,123 @@ + + +Create DojoX GFX JSON + + + + + + + +

      Create DojoX GFX JSON

      +

      This is a helper file, which serves as a template to generate static pictures.

      + + + + +
      +
      +
      +
      +

      +

      +     

      + + diff --git a/includes/js/dojox/gfx/demos/data/Lars.json b/includes/js/dojox/gfx/demos/data/Lars.json new file mode 100644 index 0000000..320feb0 --- /dev/null +++ b/includes/js/dojox/gfx/demos/data/Lars.json @@ -0,0 +1,1823 @@ +[ + { + "name": "torso", + "children": [ + { + "name": "leftArm", + "shape": { + "type": "path", + "path": "M156.007,292.674c2.737,1.779,5.563,3.322,8.752,3.947c7.098,1.39,19.25-5.666,23.136-11.699 c1.572-2.441,8.077-21.031,11.177-14.271c1.224,2.67-1.59,4-1.399,6.462c3.108-1.425,5.48-5.242,8.918-2.182 c0.672,4.019-4.472,4.343-3.918,7.669c1.376,0.218,5.394-1.595,6.285-0.535c1.707,2.027-2.933,3.561-4.072,4.018 c-1.852,0.741-4.294,1.233-5.988,2.369c-2.636,1.768-4.766,5.143-7.034,7.4c-11.657,11.604-26.183,10.553-40.646,5.515 c-4.713-1.642-17.399-4.472-18.655-9.427c-1.647-6.502,5.523-7.999,10.184-6.74C147.658,286.528,151.725,289.891,156.007,292.674z" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "leftArmThumb", + "shape": { + "type": "path", + "path": "M188.257,284.902c-1.932-1.391-3.314-4.206-3.506-6.494c-0.149-1.786,0.59-6.522,3.199-3.95c0.792,0.78,0.083,2.155,0.558,2.943 c0.885,1.47,1.071,0.493,2.748,1.002c1.406,0.426,3.827,2.05,4.251,3.499" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "rightArm", + "shape": { + "type": "path", + "path": "M57.05,283.306c-5.502,5.354-13.185,8.541-18.249,14.221c-4.303,4.827-7.721,11.575-11.138,17.112 c-6.752,10.939-10.794,26.076-19.912,35.185c-3.869,3.866-7.637,5.721-7.251,12.032c0.932,0.372,1.548,0.589,2.418,0.683 c0.605-2.746,2.569-4.199,5.362-3.799c-0.14,3.365-3.512,5.941-3.228,9.235c0.364,4.223,3.983,5.968,7.181,2.662 c2.61-2.699,0.192-7.848,3.338-10.179c5.535-4.103,2.889,2.998,4.13,5.514c5.19,10.519,8.634-1.859,7.35-7.996 c-2.336-11.159-3.003-15.126,3.267-24.416c6.358-9.419,12.194-18.708,19.399-27.588c1.116-1.375,2.08-2.728,3.333-4" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "shirt", + "children": [ + { + "name": "tShirt", + "shape": { + "type": "path", + "path": "M96.509,268.264 c-2.301,0.323-4.69,0.205-6.945,0.72c-2.234,0.509-4.5,0.8-6.749,1.249c-4.369,0.872-8.206,3.265-12.3,5.024 c-3.259,1.401-6.644,2.571-9.763,4.26c-1.923,1.041-3.688,2.616-5.487,3.97c-1.543,1.16-3.495,2.11-4.854,3.562 c-2.205,2.354,0.896,7.408,1.854,9.873c0.92,2.368,2.149,4.82,2.749,7.29c0.228,0.937,0.235,2.058,0.875,2.873 c0.644,0.821,0.64,0.735,1.822,0.048c1.513-0.878,2.873-1.993,4.329-2.993c2.431-1.67,5.462-2.848,7.434-5.111 c-3.335,1.652-5.335,4.679-6.931,8.012c-1.398,2.92-4.482,35.854-5.389,38.947c-0.195,0.003-0.775,0.003-0.749,0.013 c20.561,0,41.123-0.07,61.684,0c2.1,0.007,3.607-0.497,5.529-1.252c0.715-0.281,2.257-0.356,2.807-0.745 c1.412-0.998-0.094-3.916-0.646-5.302c-1.425-3.579-2.111-37.767-4.726-40.543c1.842,0.057,4.127,1.311,5.937,1.95 c1.351,0.478,2.633,1.092,3.956,1.66c1.39,0.597,3.667,1.927,5.168,1.858c0.296-1.873,1.045-3.286,1.839-5.02 c0.943-2.061,1.155-4.214,1.528-6.415c0.351-2.07,0.898-3.787,1.939-5.635c0.531-0.942,1.356-1.73,1.693-2.768 c-0.443-0.402-1.043-0.907-1.603-1.125c-0.56-0.219-1.292-0.111-1.908-0.33c-1.237-0.438-2.44-1.089-3.669-1.576 c-3.773-1.499-7.519-2.983-11.319-4.466c-3.575-1.396-6.977-3.239-10.784-3.872c-1.735-0.289-3.467-0.529-5.073-0.906" + }, + "fill": "#4459A5", + "stroke": { + "color": "#000000", + "cap": "round" + } + }, + { + "name": "shirtNeck", + "shape": { + "type": "path", + "path": "M99.759,268.889 c-0.984,0.152-1.746-0.549-2.75-0.5c-1.369,0.066-1.649,0.872-2.153,2c-1.037,2.325-2.442,4.974,0.064,6.946 c2.53,1.991,6.964,1.717,9.829,0.803c1.616-0.516,3.045-1.24,3.825-2.867c0.508-1.061,0.935-2.771,0.149-3.598 c-0.231-0.243-0.562-0.376-0.84-0.534" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round" + } + }, + { + "name": "shirtLogo", + "children": [ + { + "children": [ + { + "shape": { + "type": "path", + "path": "M104.864,296.92c-0.151-0.003,7.101,0.41,7.052,0.404c0.132,0.028-0.172,0.633-0.021,0.632 c-0.226,0.028-7.244-0.454-7.28-0.464C104.657,297.518,104.776,296.904,104.864,296.92z" + }, + "stroke": { + } + } + ] + }, + { + "children": [ + { + "shape": { + "type": "path", + "path": "M90.071,295.919c-0.199,0.004,6.792,0.43,6.79,0.446c0.153,0.005-0.031,0.663,0.012,0.665 c0.272,0.015-6.79-0.471-6.875-0.459C89.881,296.56,89.796,295.899,90.071,295.919z" + }, + "stroke": { + } + } + ] + }, + { + "shape": { + "type": "path", + "path": "M84.407,306.476c0.2-0.159,0.322-1.04,0.254,0.057 c-0.542-0.356-2.02,2.083-4.215,2.001c-1.887-1.706-4.559-3.384-4.302-7.092c0.652-2.599,3.082-4.084,5.213-3.942 c1.889,0.377,2.899,0.716,4,1.318c-0.497,0.957-0.175,0.866-0.459,0.703c0.456-2.398,0.598-5.75,0.312-7.855 c0.594-0.554,0.714,0.125,1.249,0.941c0.502-0.727,0.509-1.425,0.875-0.571c-0.207,1.328-0.809,7.186-0.711,10.174 c-0.126,2.797-0.375,4.354-0.051,4.985c-0.718,0.613-0.667,1.006-0.981,1.381c-0.72-1.33-1.056-0.132-1.339-0.157 C84.632,308.442,84.493,305.791,84.407,306.476z M81.186,307.176c2.403,0.206,3.734-2.164,3.841-4.222 c0.269-2.72-0.896-5.104-3.198-5.04c-1.972,0.437-3.46,2.188-3.331,4.638C78.171,306.265,79.847,306.961,81.186,307.176z" + }, + "stroke": { + } + }, + { + "shape": { + "type": "path", + "path": "M93.321,297.766c2.592,0.148,5.688,2.315,5.696,5.627 c-0.611,4.576-3.69,5.316-6.158,5.581c-2.68-0.76-5.708-1.872-5.413-6.472C88.086,299.394,90.653,297.875,93.321,297.766z M92.939,307.46c2.531,0.735,3.706-1.297,3.666-3.935c0.114-2.219-0.641-4.584-3.389-4.896c-2.29-0.552-3.366,2.188-3.661,4.688 C89.339,305.264,89.934,307.95,92.939,307.46z" + }, + "stroke": { + } + }, + { + "shape": { + "type": "path", + "path": "M99.688,303.916c0.03-1.511,0.055-4.731,0.022-4.646 c0.481-1.355,0.658-0.556,1.034-1.297c0.263,1.473,0.653,0.326,1.186,0.066c-0.386,2.517-0.513,3.347-0.574,4.949 c-0.068-0.47-0.128,2.28-0.238,2.188c-0.055,1.935-0.036,2.201-0.047,4.219c-0.079,0.914-0.28,2.412-1.126,3.831 c-0.61,1.212-1.73,1.146-3.24,1.651c0.073-0.945-0.065-1.242-0.096-1.822c0.098,0.138,0.213,0.604,0.225,0.398 c1.892,0.228,2.209-1.896,2.362-3.366c0.042,0.304,0.512-6.933,0.415-7.061C99.73,302.636,99.75,303.178,99.688,303.916z M100.978,295.564c0.717,0.14,1.11,0.61,1.099,1.156c0.052,0.552-0.595,0.993-1.286,1.015c-0.541-0.074-1.025-0.548-1.022-1.054 C99.813,296.084,100.292,295.643,100.978,295.564z" + }, + "stroke": { + } + }, + { + "shape": { + "type": "path", + "path": "M108.115,298.791c3.028-0.067,5.283,1.359,5.256,5.757 c-0.264,3.479-3.366,4.63-5.883,5.12c-2.429-0.034-5.619-2.241-5.16-5.811C102.322,300.085,105.715,298.845,108.115,298.791z M107.351,309.232c2.675-0.132,3.839-2.333,3.841-4.497c0.246-2.344-0.263-4.833-2.923-5.396 c-2.844,0.299-3.974,1.917-4.053,4.48C104.136,306.655,104.854,308.372,107.351,309.232z" + }, + "stroke": { + } + } + ] + } + ] + } + ] + }, + { + "name": "heads", + "children": [ + { + "name": "head1", + "children": [ + { + "name": "leftEart", + "children": [ + { + "shape": { + "type": "path", + "path": "M201.557,195.474 c7.734-4.547,16.591-5.012,18.405,4.443c2.43,12.659-3.317,13.328-14.598,13.328" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M211.711,203.09 c0.523,0.004,0.946-0.208,1.27-0.635" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M211.076,197.377 c3.062,3.013,5.489,5.624,4.443,10.155" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + } + ] + }, + { + "name": "bgHairTop", + "shape": { + "type": "path", + "path": "M54.384,199.306c-5.253-4.402-7.511-11.061-15.779-10.632c3.449-1.277,7.116-2.397,10.911-2.666 c-2.873-1.397-5.865-2.575-8.231-4.718c3.986-1.119,11.47-1.817,14.864,0.75c-5.183-2.758-8.397-7.816-13.062-10.598 c6.014-0.643,12.377,0.978,18.022,2.265c-2.547-4.486-6.682-10.83-10.523-14.297c5.033,1.052,10.647,4.518,15.062,7.177 c-1.614-4.176-5.634-8.406-7.859-12.513c10.312-1.125,12.522,4.919,19.7,9.932c-0.412-0.127-1.114-0.113-1.527,0.015 c0.875-7.261,3.058-12.8,8.258-18.566c6.771-7.507,17.812-9.131,24.095-15.381c-4.699,1.821-4.518,23.765-4.875,28.955" + }, + "fill": "#FFF471", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "bgHairLeft", + "shape": { + "type": "path", + "path": "M92.384,243.972c-6.334,7.929-12.601,12.241-22.465,15.362c3.65-1.263,7.735-5.86,7.695-9.928 c-2.208,0.218-4.49,0.605-6.498,1.097c1.244-1.097,2.087-3.239,3.198-4.396c-5.77,0.001-12.131,1.133-18.396,1.23 c5.013-2.809,10.665-3.25,12.398-9.246c-3.59,0.313-7.233,1.606-11.033,1.097c1.731-2.022,3.953-3.995,5.049-6.447 c-3.781,0.056-6.665,3.098-10.547,2.465c0.962-2.863,3.187-5.208,4.531-7.766c-5.59-0.273-11.658,2.45-17.732,2.564 c5.494-2.857,8.967-7.819,12.3-12.718c5.233-7.693,10.625-9.96,20.349-9.981c11.059-0.024,15.558,6.714,20.984,16 c2.786,4.767,7.249,14.375,0.832,18" + }, + "fill": "#FFF471", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "bgHair", + "shape": { + "type": "path", + "path": "M142.384,255.306c2.984,6.076,3.567,11.856,10.531,14.6c-0.134-3.114-0.094-6.664,1.619-9.033 c1.605,1.968,3.122,4.211,5.048,5.698c-0.29-1.769,0.412-4.024,0.233-5.828c3.445,0.26,4.979,3.965,8.468,4.479 c0.066-2.78,0.427-5.151,0.868-7.813c2.687,0.2,4.768,1.565,7.132,2.997c0.452-4.921-0.409-10.579-0.667-15.666 c-5.795-0.756-12.291,2.827-17.899,3.899c-4.414,0.844-14.136,0.524-15.333,6" + }, + "fill": "#FFF471", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "neck", + "shape": { + "type": "path", + "path": "M106.989,254.499c-2.932,6.063-4.613,11.997-8.947,17.137c7.288,10.195,16.311-10.9,15.183-17.026 c-1.926-1.138-3.928-1.589-6.236-1.38" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "headShape", + "shape": { + "type": "path", + "path": "M210.941,207.665c-0.843,3.985-2.081,7.982-3.769,11.783c-3.374,7.604-8.543,14.427-16.052,18.899 c-2.94,2.13-5.983,4.167-9.109,6.085c-25.013,15.342-55.353,23.08-82.254,10.57c-3.433-1.557-6.785-3.431-10.053-5.66 c-1.821-1.184-3.592-2.46-5.308-3.832c-1.715-1.373-3.375-2.842-4.972-4.412c-2.352-2.148-4.576-4.425-6.631-6.814 c-6.168-7.169-10.823-15.358-12.87-24.185c-0.649-3.284-0.84-6.634-0.5-9.975c4.48-13.743,14.22-24.364,26.109-32.149 c2.973-1.946,6.079-3.715,9.271-5.309c30.581-15.027,69.581-10.027,95.851,12.209c2.564,2.254,4.988,4.651,7.244,7.178 c4.513,5.054,8.354,10.626,11.312,16.64C210.178,201.505,210.798,204.496,210.941,207.665z" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "rightEar", + "children": [ + { + "shape": { + "type": "path", + "path": "M64.857,195.606 c-6.59-7.181-15.047-10.664-19.467,3.676c-1.235,4.007-1.87,14.468,1.29,17.786c4.223,4.435,13.591,0.529,19.055-0.015" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M52.407,196.743 c-1.702,3.613-1.257,7.505-1.27,11.424" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M51.772,209.437 c-3.39-4.661,0.922-5.769,5.078-6.347" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + } + ] + }, + { + "name": "fgHair", + "shape": { + "type": "path", + "path": "M90.384,154.639c8.453-11.353,15.678-13.458,28.581-15.915c-1.382,3.376-3.89,7.352-5.179,11.16 c5.01-1.816,9.571-6.545,15.218-8.413c11.355-3.755,23.852-1.903,35.671-2.213c-3.004,3.712-4.912,7.88-2.026,11.447 c5.856-2.212,13.37-6.871,19.635-6.646c0.263,4.561-0.024,9.278,0.201,13.841c3.509-1.201,6.015-3.04,8.277-5.148 s3.761-4.049,4.942-5.2c1.063,2.408,2.134,5.334,2.24,8.494c-0.182,3.462-0.866,6.794-2.66,9.291 c3.663,0.65,6.098-2.021,8.35-4.479c-0.655,4.349-3.164,8.604-3.851,13.013c2.178-0.072,4.382,0.216,6.367-0.48 c-1.389,3.093-3.069,7.287-6.616,8.414c-4.475,1.423-4.354-0.992-7.315-4.332c-4.892-5.518-9.774-6.791-15.872-9.464 c-6.585-2.887-10.983-6.47-17.963-8.219c-8.994-2.255-19.864-3.867-28.093-5.196c2.466,1.967,1.138,5.594,0.659,8.625 c-2.729-0.645-4.41-3.813-6.301-5.158c0.953,3.195,0.983,6.953-2.134,8.491c-6.145-5.226-9.199-9.721-17.527-11.647 c1,1.83,1.728,4.208,1.396,6.402c-0.751,4.971-0.289,3.134-3.836,2.466c-5.192-0.977-9.953-3.677-15.815-4.496 c3.292,2.002,5.469,5.017,7.418,8.21c-2.651,0.404-6.238,0.257-8.382,1.671c2.456,0.38,3.44,2.166,3.197,4.714 c-7.45,0.386-13.623,0.731-19.915,5.434" + }, + "fill": "#FFF471", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + } + ] + } + ] + }, + { + "name": "eyes", + "children": [ + { + "name": "eyes1", + "children": [ + { + "shape": { + "type": "path", + "path": "M123.163,176.668 c-5.066,1.17-9.01,7.888-13.666,10.335c-4.238,2.227-8.648,6.636-7.009,12.332c1.971,6.848,12.042,3.991,16.261,1.165 c5.282-3.539,9.59-8.517,12.006-14.524c1.523-3.787,2.568-7.272-1.509-9.391c-2.905-1.51-8.174-1.386-11.417-0.583" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M182.545,179.865 c-3.533,0.169-4.854-1.166-8.408-0.001c-3,0.983-6.24,1.936-8.852,3.743c-3.938,2.725-7.46,5.555-4.73,13.592 c1.973,5.811,8.791,7.571,14.656,6.667c5.537-0.854,9.078-4.977,11.408-10.007c3.666-7.918,0.943-11.639-6.742-13.659" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000", + "cap": "round" + } + }, + { + "shape": { + "type": "path", + "path": "M108.829,183.668c-1.308-1.03-4.557,0.011-5.6-1.733 c-1.056-1.765,1.735-5.409,2.984-6.192c5.684-3.562,15.946-0.39,19.95-6.742" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M163.877,167.198c2.369,1.282,6.539,0.307,9.408,0.815 c3.449,0.612,7.066,2.657,10.592,2.851" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M127.496,192.002c-4.917-2.12-9.188-1.708-8.608,4.942 c3.132,1.734,5.428-2.82,7.275-4.942" + }, + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M174.852,203.143c-0.293,0.12-0.307,0.577-0.943,0.282 c-1.605-3.188-0.404-6.507,2.676-8.192c2.15-1.176,5.67-1.759,7.471,0.359c0.199,0.234,0.412,0.521,0.514,0.813 c0.229,0.649-0.285,0.95-0.285,0.95s-3.988,6.009-3.285,1.934c0.438,1.743-5.537,5.743-2.287,1.653 c-1.955,2.583-2.525,1.977-3.859,2.868" + }, + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "eyes2", + "children": [ + { + "shape": { + "type": "path", + "path": "M98.668,186.108c0.668-8.915,15.545-13.749,22.667-15" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M169.667,178.108 c5.307,3.436,16.928,5.632,19.668,12.333" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M105.334,197.775c8.085-4.283,17.059-2.8,25-6.333" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M164.001,198.775c4.656-0.417,9.664,1.805,14.334,2.017 c3.951,0.18,5.773,0.189,9,2.316" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M124.001,188.108c3.039-0.258,4.594,2.571,5.301,4.983 c-1.096,1.242-2.065,2.646-2.968,4.017" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M168.335,194.108c-1.77,2.293-4.869,3.271-6.299,5.91 c1.377,0.991,3.02,2.122,3.965,3.424" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + } + ] + } + ] + }, + { + "name": "beard", + "children": [ + { + "shape": { + "type": "path", + "path": "M96.05,213.639 c-0.366,0.21-0.783,0.389-1.167,0.5" + }, + "fill": "#AFA8A5", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M102.55,211.972 c0.314-0.01,0.554-0.198,0.667-0.5" + }, + "fill": "#AFA8A5", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M105.717,208.805 c0.164-0.109,0.336-0.224,0.5-0.333" + }, + "fill": "#AFA8A5", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M111.05,207.972 c-0.651-1.81,0.859-2.262,2.333-1.5" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M117.717,209.805 c1.738,0,3.653,0.369,5.333,0.167" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M132.717,214.472 c0.104-0.21,0.162-0.435,0.167-0.667" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M139.551,216.972 c0.215-0.175,0.465-0.426,0.666-0.667" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M144.551,213.305 c0.277-0.056,0.556-0.111,0.833-0.167" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M147.884,216.639 c0.195,0.045,0.369-0.013,0.5-0.167" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M148.384,214.139 c0.112-0.168,0.222-0.332,0.333-0.5" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M98.217,219.305c1.697-1.772,4.233-2.109,5.967-4.046c1.519-1.696,3.812-3.001,4.2-5.454" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M152.717,216.139 c0.611,0,1.223,0,1.834,0" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M160.384,217.472 c0.333,0,0.667,0,1,0" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M163.217,215.972 c0.321-0.042,0.658-0.175,0.834-0.333" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M164.217,218.805 c0.167,0,0.333,0,0.5,0" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M168.384,217.972 c0.056-0.056,0.111-0.111,0.167-0.167" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M169.884,225.805 c0.491-0.397,0.882-0.926,1.167-1.5" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M172.717,221.972 c0.056,0,0.111,0,0.167,0" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M171.717,229.805 c0.334,0.075,0.659,0.025,0.834-0.167" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M190.051,227.805 c0.163-0.242,0.398-0.423,0.666-0.5" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M197.384,221.472 c0.258-0.007,0.485-0.125,0.667-0.333" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M199.384,214.972 c-0.04-0.333,0.075-0.609,0.333-0.833" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M117.884,257.305 c0.056,0,0.111,0,0.167,0" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M142.717,252.472 c0.358,0.069,0.71,0.016,1-0.167" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M137.884,256.472 c0.277,0,0.556,0,0.833,0" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M160.884,252.972 c0.366-0.138,0.765-0.402,1-0.667" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M171.384,250.139 c0.235-0.263,0.475-0.561,0.667-0.834" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M89.384,243.972 c0.537,0.378,1.329,0.876,1.833,1.333" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M79.05,225.472 c0.087,0.272,0.143,0.55,0.167,0.833" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M73.884,222.639 c0,0.167,0,0.333,0,0.5" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M72.55,219.805c0.466-0.325,0.875-0.797,1.167-1.333" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M71.717,211.972c0.422-0.553,0.776-1.305,1-2" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M78.55,214.472c0-0.111,0-0.222,0-0.333" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M79.384,218.805c-0.001-0.137,0.055-0.248,0.167-0.333" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M80.217,221.139c0.111,0,0.222,0,0.333,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M75.55,226.472c0.103-0.5,0.156-0.977,0.167-1.5" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M78.55,230.139c0.111,0,0.222,0,0.333,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M83.384,227.639c0.118-0.059,0.215-0.107,0.333-0.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M81.55,237.139c0.056,0,0.111,0,0.167,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M86.217,233.805c0.056,0,0.111,0,0.167,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M87.884,230.472c0.595-0.181,1.219-0.527,1.833-0.667" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M88.717,222.139 c-0.929,2.359-1.615,4.865-2.667,7.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M89.05,216.139 c0.784-0.736,1.709-1.565,2.833-1.5" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M94.217,210.139 c1.599-0.089,3.199-0.167,4.833-0.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M94.884,224.639 c0.052-0.588-0.004-1.155-0.167-1.667" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M92.384,228.305 c0.585-0.062,1.244-0.132,1.667-0.333" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M88.717,240.139 c0.111,0,0.222,0,0.333,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M95.884,243.305 c0.526,0.1,1.017-0.015,1.333-0.333" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M98.55,248.305 c0.069-0.24,0.265-0.926,0.333-1.166" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M96.55,249.805 c0.125,0.014,0.18-0.042,0.167-0.166" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M104.55,250.139 c0.01-0.238,0.126-0.428,0.333-0.5" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M106.884,251.972 c0.195,0.045,0.37-0.013,0.5-0.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M113.884,254.805 c0.758-0.586,1.595-1.171,2.382-1.774c0.072,0.376,0.418,0.685,0.48,1.079c0.833,0.265,1.624-0.021,1.638-0.971" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M122.217,254.639 c0.063-0.165,0.179-0.288,0.333-0.334" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M125.884,255.805 c1.13-0.745,2.783-0.962,3.667-2" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M132.217,255.972 c0.638-0.492,1.104-1.173,1.141-1.975c-1.11,0.062-1.449-0.888-1.475-1.858" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M129.717,249.305 c-0.045,0.154-0.168,0.271-0.333,0.334" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M136.551,252.305 c0.222,0,0.444,0,0.666,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M110.217,251.305 c0.056-0.056,0.111-0.11,0.167-0.166" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M140.717,251.805 c0.111,0,0.223,0,0.334,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M150.051,249.472 c0.111,0,0.222,0,0.333,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M143.217,255.472 c1.022-0.313,1.724-1.175,2.646-1.654c0.203,0.321,0.44,0.626,0.521,0.987" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M152.217,253.472 c0.165-0.063,0.288-0.179,0.334-0.333" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M155.051,254.639 c0.222,0,0.444,0,0.666,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M157.717,256.472 c0.326-0.027,0.546-0.073,0.834-0.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M163.217,252.639 c0.552-0.891,2.082-1.512,2.341-2.334c0.37-1.177-1.156-3.069-1.007-4.5" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M167.384,235.972 c0.118-0.54,0.353-1.064,0.667-1.5" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M170.717,242.805 c0-0.333,0-0.667,0-1" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M170.217,236.972 c0-0.333,0-0.667,0-1" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M179.051,235.805 c0.378-0.101,0.738-0.35,1-0.667" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M185.051,232.805 c0.379-0.319,0.656-0.702,0.833-1.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M188.051,231.139 c0.063-0.39,0.178-0.792,0.333-1.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M197.884,223.305 c-0.166,0.277-0.334,0.556-0.5,0.833" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + } + ] + }, + { + "name": "mouths", + "children": [ + { + "name": "mouth1", + "children": [ + { + "shape": { + "type": "path", + "path": "M177.122,216.821c-0.515,2.282-5.213,3.21-7.433,3.854 c-3.254,0.945-6.596,1.345-9.895,1.851c-3.26,0.5-6.665,0.671-10.107,0.671c-3.596,0-6.645,0.559-10.107,0.671 c-3.105,0.1-6.898-0.474-9.694-1.3c-3.527-1.043-6.672-1.666-10.096-3.062c-2.823-1.152-5.746-1.876-8.462-3.143 c-2.594-1.209-6.084-1.994-8.221-3.552c-1.068,1.834-5.867,3.748-8.1,4.546c-2.444,0.874-8.881,2.725-7.817,5.512 c0.457,1.195,1.948,2.273,2.63,3.385c0.774,1.261,1.139,2.601,2.057,3.859c1.83,2.5,4.506,4.773,6,7.34 c1.308,2.249,2.096,4.74,4.01,6.67c2.214,2.233,5.792,2.634,9.231,2.399c7.028-0.479,13.982-2.129,20.481-3.983 c3.295-0.941,6.699-1.536,10.087-2.686c3.272-1.111,6.641-3,9.402-4.777c5.248-3.377,10.278-6.409,14.283-10.705 c1.479-1.587,3.429-2.503,5.15-3.859" + }, + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M135.25,241.319 c0.723-4.757-10.487-8.47-14.898-9.526c-3.09-0.74-6.68-1.17-9.858-1.712c-2.758-0.47-6.865-0.836-9.437,0.369 c-1.385,0.649-2.843,1.724-4.141,2.513c2.156,3.964,4.728,8.861,9.468,11.506c3.229,1.801,5.511,0.777,8.859,0.373 c3.045-0.369,6.046-0.703,9.029-1.72c3.479-1.186,7.228-2.385,10.978-2.475" + }, + "fill": "#FFC0C0", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M148.656,225.547c1.267,0.697,1.301,2.838,0.671,3.9 c-0.702,1.182-2.063,1.4-3.306,2.01c-2.271,1.116-4.581,2.624-7.482,2.638c-4.619,0.023-2.143-4.067-0.253-5.869 c2.405-2.292,5.057-2.72,8.72-2.512c0.588,0.034,1.095,0.041,1.65,0.168" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M130.299,223.365 c2.687,0.437,5.619,4.384,3.727,6.422c-1.234,1.33-7.94,1.391-9.915,1.296c-4.896-0.233-2.502-2.445-0.613-4.525 c1.604-1.767,5.088-3.249,7.833-3.36" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M113.178,217.157 c2.56,0.958,4.922,5.057,5.352,7.215c0.377,1.885-0.324,2.106-2.526,2.643c-1.366,0.333-3.636,0.723-5.105,0.385 c-2.506-0.577-5.883-5.051-4.909-7.223c1.03-2.298,5.944-2.923,8.427-2.852" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M99.359,217.661 c2.038,0.432,4.015,4.279,2.468,5.625c-1.083,0.943-5.221,1.795-6.799,1.589c-4.032-0.526-2.265-4.102-0.866-5.872 c0.706-0.894,1.049-1.976,2.514-2.186c1.627-0.233,2.501,0.99,3.921,1.346" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M181.815,222.895c-3.101-2.75-4.764-8.777-9.282-10.403" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "mouth2", + "children": [ + { + "shape": { + "type": "path", + "path": "M87.57,221.951c5.563-1.759,11.066-1.32,16.694-1.782c2.93-0.24,5.228-1.14,8.309-0.927c3.142,0.217,6.085-0.235,9.289,0.176 c7.136,0.914,13.96,0.598,21.112,1.506c3.654,0.464,7.218,0.609,10.81,0.869c4.017,0.291,7.646,1.582,11.433,2.623 c2.948,0.812,6.347,1.618,9.011,2.99c2.521,1.298,6.354,2.856,8.3,4.72c-2.775,0.027-5.601,2.603-8.021,3.769 c-2.93,1.412-5.741,2.949-8.656,4.432c-5.599,2.849-11.885,5.468-18.104,6.53c-6.793,1.161-13.195,2.107-20.067,2.197 c-7.699,0.102-14.313-4.705-20.735-8.396c-2.071-1.19-4.69-2.182-6.504-3.666c-1.792-1.466-3.469-3.386-5.154-4.984 c-2.703-2.564-7.519-5.649-8.13-9.438" + }, + "stroke": { + "color": "#000000", + "width": "3", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M87.785,228.193 c-5.907-3.235-0.344-9.531,3.971-11.424" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2" + } + }, + { + "shape": { + "type": "path", + "path": "M184.679,227.228c-1.534,2.583-2.548,5.334-4.025,7.889" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M106.862,219.528 c-3.071-0.74-5.608,2.166-6.318,4.738c-0.379,1.375-0.494,2.55,0.748,3.337c1.519,0.962,2.905-0.052,4.418-0.332 c2.518-0.467,7.293,0.053,6.461-4.248c-0.568-2.938-3.743-3.682-6.338-3.335c-0.451,0.06-0.758,0.212-1.205,0.229" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M119.764,218.479 c-2.648,1.243-4.657,3.518-5.346,6.377c-0.866,3.594,3.9,3.711,6.356,2.865c2.64-0.91,4.77-3.351,3.299-6.133 c-1.01-1.91-3.979-2.548-6.026-2.823" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M130.388,219.492 c-1.753,1.382-4.069,4.525-4.835,6.61c-1.159,3.156,2.296,3.371,4.868,3.348c3.061-0.028,6.6-1.148,5.022-4.78 c-1.168-2.691-2.552-4.85-5.551-5.241" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M142.954,221.087 c-1.502,0.337-5.418,3.249-5.638,4.997c-0.292,2.311,4.856,4.536,6.854,4.234c2.503-0.377,4.384-3.175,3.167-5.65 c-0.92-1.873-3.36-2.252-4.508-3.932" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M155.354,222.663 c-2.039,0.426-4.212,2.287-4.766,4.444c-0.723,2.821,3.225,3.383,5.458,3.331c2.541-0.059,5.126-1.752,3.249-4.32 c-1.394-1.908-3.707-3.189-5.304-4.636" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M168.367,237.924 c-1.554-1.217-3.302-2.557-5.203-2.976c-2.973-0.654-3.537,2.131-3.377,4.406c0.205,2.913,1.032,3.883,3.901,2.344 c1.988-1.066,4.272-1.997,4.599-4.456" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M151.524,246.202 c-1.912-0.166-4.003-4.491-2.91-6.25c0.771-1.239,5.456-1.688,6.858-1.292c0.271,0.917,0.979,1.841,0.829,2.771 c-0.088,0.54-0.994,1.645-1.296,2.188c-1.08,1.951-2.133,1.866-3.998,2.684" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M145.911,241.457 c-0.209,1.649-0.215,2.702-1.528,3.801c-0.885,0.739-1.773,1.19-2.54,2.1c-0.786,0.933-1.226,2.38-2.792,1.812 c-1.042-0.377-1.959-2.318-2.138-3.311c-0.299-1.676-1.003-5.228,0.783-6.158c1.155-0.603,7.067-0.18,7.43,1.32" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M133.12,238.991 c-1.495-0.087-2.253-1.33-3.918-0.964c-1.42,0.311-2.489,1.354-2.54,2.836c-0.052,1.527,0.99,5.581,1.852,6.956 c2.363,3.771,4.329-1.535,5.516-3.159c1.117-1.526,2.643-2.053,2.271-3.958c-0.318-1.632-1.118-2.047-2.766-2.329 c-0.382-0.065-0.773-0.095-1.158-0.147" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M116.853,237.429 c-1.049,2.211-0.173,5.147,0.047,7.566c0.357,3.929,3.827,2.028,5.831,0.067c1.575-1.541,4.599-4.86,2.209-6.484 c-1.881-1.279-5.727-2.458-7.756-1.107" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M107.455,233.38 c-0.813,2.487-1.704,5.049,0.073,7.364c1.91,2.486,4.009,1.229,5.537-0.939c1.056-1.5,3.316-4.481,1.563-6.017 c-1.347-1.179-6.468-1.518-7.854-0.325" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "mouth3", + "children": [ + { + "shape": { + "type": "path", + "path": "M99.05,218.972 c1.691-0.875,3.313-2.39,4.833-3.537c1.231-0.928,2.782-1.671,3.5-3.072c1.846,3.486,7.661,4.669,11.003,6.067 c3.553,1.486,7.174,3.066,10.784,4.166c4.271,1.301,9.277,1.67,13.721,2.343c4.155,0.629,9.979,1.365,14.162,0.496 c1.181-0.245,2.343-1.024,3.462-1.446c0.162,1.905-3.637,3.023-4.933,3.487c-2.435,0.871-4.18,2.541-6.362,3.871 c-1.623,0.989-2.974,1.669-4.755,2.117c-1.77,0.445-3.353,0.806-4.825,1.878c-5.915,4.311-15.264,3.247-22.424,3.13 c-5.384-0.088-6.719-5.372-9.337-9c-1.437-1.991-2.843-3.854-3.796-6.138c-0.871-2.086-1.119-4.582-2.033-6.528" + }, + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M107.217,227.972 c1.182-2.033,4.375-2.176,6.5-1.963c2.879,0.289,4.124,1.217,6.168,3.167c1.834,1.749,5.906,5.509,5.64,8.271 c-2.808,0.89-7.847,0.402-10.346-1.104c-1.334-0.804-1.151-2.256-2.246-3.588c-0.712-0.866-1.836-2.673-2.855-3.311 c-0.209-0.94-2.106-1.499-3.028-1.805" + }, + "fill": "#F4BDBD", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + } + ] + } + ] + }, + { + "name": "personalProps", + "children": [ + { + "name": "hat", + "children": [ + { + "children": [ + { + "children": [ + { + "shape": { + "type": "path", + "path": "M88.374,173.144c0.474-0.074,16.606,2.725,18.01,5.879 c1.145,2.572,28.184,4.568,28.184,4.568l35.971-5.618l5.025,1.132l7.211,0.315l9.295,0.851l10.188,3.248l5.75,2.935 l1.615-1.832l-0.264-5.27l-3.967-7.087c0,0-22.045-13.031-23.273-13.703c-1.229-0.669-4.941-2.294-6.484-4.542 c-8.584-12.528-8.404-18.05-3.371-6.461c0,0,2.662-7.592,2.52-8.575c-0.143-0.982,0.355-5.031,0.355-5.031l2.396-6.832 c0,0-1.379-5.341-2.738-7.19c-1.357-1.844-15.793-4.078-18.162-4.011c-24.933,0.706-3.783,0.071-25.567,0.724 c-24.317,0.728-0.882-2.591-24.068,3.551c-24.228,6.418-5.35-1.298-23.187,6.142c-18.301,7.633-16.67,7.186-16.704,10.685 c-0.034,3.499-3.057-4.884-0.034,3.499c3.023,8.381,3.037-3.871,3.023,8.381c-0.015,12.252,6.696,4.557,1.678,12.373 c-5.017,7.813-3.831,7.91-0.179,8.543c17.017,2.953,4.157,4.378,17.427,3.175" + }, + "fill": "#FF0000", + "stroke": { + } + }, + { + "shape": { + "type": "path", + "path": "M156.605,114.92l-13.936,0.381l-11.633,0.343c-10.646,0.319-11.973-0.155-12.021-0.175l-0.599-0.238 l-0.577,0.514l0.049-0.047c-0.118,0.09-1.43,0.957-11.145,3.53c-9.989,2.646-12.812,2.931-13.421,2.704 c-0.822-0.306-0.821-0.306-7.791,2.604l-2.104,0.878c-16.037,6.689-17.342,7.324-17.342,10.316c0,0.019,0.001,0.041,0.001,0.06 c-0.224-0.108-0.459-0.199-0.787-0.04c-0.357,0.173-0.565,0.275-0.565,0.672c0,0.557,0.411,1.697,1.399,4.438 c0.924,2.561,1.71,3.671,2.714,3.833c0.083,0.014,0.164,0.02,0.241,0.02c0.007,0.584,0.01,1.339,0.01,2.313 c0,0.561-0.001,1.902-0.001,1.916c0,6.908,2.176,8.105,3.347,8.749c0,0,0.075,0.045,0.151,0.09 c-0.095,0.332-0.47,1.1-1.661,2.955c-2.509,3.908-3.516,5.931-3.516,7.303c0,0.358,0.068,0.671,0.196,0.962 c0.544,1.237,1.926,1.477,3.677,1.78l0.135,0.023c8.138,1.412,9.14,2.422,9.568,2.854c0.923,0.931,1.511,0.928,7.224,0.413 c0.06,0.014,0.102,0.068,0.165,0.071c2.167,0.105,16.131,3.138,17.087,5.288c1.147,2.578,16.416,4.228,29.023,5.159 l0.115,0.009c0,0,35.523-5.548,35.896-5.606c0.345,0.078,4.927,1.11,4.927,1.11l7.3,0.319c0,0,8.927,0.818,9.139,0.837 c0.202,0.064,9.854,3.142,10.006,3.19c0.143,0.073,6.368,3.251,6.368,3.251l2.398-2.719l-0.296-5.911l-4.213-7.526 l-0.232-0.137c-0.9-0.532-22.073-13.047-23.303-13.72c-0.001,0-0.735-0.38-0.735-0.38c-1.48-0.752-4.238-2.151-5.404-3.85 c-1.357-1.982-2.451-3.729-3.355-5.268c0.022-0.064,0.104-0.296,0.104-0.296c1.193-3.402,2.576-7.619,2.576-8.885 c0-0.063-0.004-0.118-0.011-0.165c-0.012-0.083-0.017-0.204-0.017-0.356c0-0.909,0.194-2.911,0.363-4.307 c0.072-0.205,2.46-7.013,2.46-7.013l-0.076-0.294c-0.146-0.566-1.468-5.584-2.9-7.532 C173.721,116.784,158.242,114.874,156.605,114.92z M131.097,117.643l11.614-0.342l13.951-0.382 c2.575-0.073,16.104,2.238,17.336,3.614c0.956,1.3,2.058,4.938,2.49,6.549c-0.188,0.536-2.33,6.642-2.33,6.642l-0.013,0.107 c-0.073,0.592-0.387,3.224-0.387,4.658c0,0.258,0.011,0.477,0.034,0.639c-0.006,0.493-0.768,3.026-1.659,5.709 c-2.14-4.566-2.792-4.606-3.242-4.629l-0.62-0.031l-0.354,0.571c-0.069,0.124-0.102,0.29-0.102,0.492 c0,2.273,4.134,9.172,6.993,13.346c1.456,2.12,4.509,3.669,6.149,4.501l0.682,0.353c1.138,0.622,20.813,12.25,23.011,13.549 c0.239,0.427,3.513,6.275,3.721,6.647c0.02,0.393,0.199,3.971,0.231,4.629c-0.23,0.262-0.472,0.535-0.832,0.944 c-1.07-0.546-5.132-2.619-5.132-2.619l-10.369-3.306l-9.404-0.86c0,0-6.995-0.307-7.169-0.315 c-0.168-0.038-5.124-1.155-5.124-1.155s-35.814,5.594-36.044,5.63c-12.419-0.922-25.993-2.687-27.285-4.058 c-1.366-3.097-13.245-5.574-17.517-6.211c-0.203-0.212-0.479-0.346-0.793-0.318c-3.083,0.28-5.996,0.544-6.4,0.369 c0-0.003-0.12-0.117-0.12-0.117c-0.703-0.708-1.879-1.895-10.646-3.416l-0.135-0.023c-0.827-0.143-2.075-0.359-2.188-0.614 c-0.021-0.048-0.033-0.111-0.033-0.193c0-0.592,0.632-2.179,3.205-6.187c1.488-2.318,2.024-3.388,2.024-4.188 c0-0.15-0.019-0.291-0.054-0.428c-0.181-0.712-0.758-1.03-1.179-1.261c-0.865-0.476-2.311-1.271-2.311-6.993 c0-0.014,0.001-1.098,0.001-1.56c0-4.969-0.065-4.992-0.833-5.258c-0.424-0.146-0.816,0.001-1.178,0.377 c-0.208-0.289-0.558-0.898-1.073-2.324c-0.205-0.568-0.385-1.068-0.542-1.506c0.587-0.423,0.632-1.277,0.636-1.644 l-0.014-0.825c-0.004-0.119-0.007-0.231-0.007-0.338c0-1.702,0.899-2.264,16.109-8.608l2.105-0.878 c4.165-1.739,5.948-2.482,6.375-2.562c0.817,0.296,2.292,0.597,14.579-2.658c8.169-2.164,10.697-3.187,11.58-3.704 C120.451,117.773,124.529,117.84,131.097,117.643z" + }, + "stroke": { + } + } + ] + }, + { + "children": [ + { + "shape": { + "type": "path", + "path": "M155.146,147.929c4.879-9.398-5.344-20.199-12.65-21.176 c-12.05-1.61-13.404,10.426-13.684,21.258c3.73,2.016,8.915,3.425,11.721,6.534" + }, + "fill": "#FFFFFF", + "stroke": { + } + }, + { + "shape": { + "type": "path", + "path": "M133.446,127.979c-4.599,3.921-5.426,11.933-5.635,20.006l-0.017,0.654l4.415,2.067 c2.849,1.244,5.793,2.529,7.581,4.509c0.371,0.41,1.004,0.442,1.412,0.072c0.219-0.197,0.33-0.469,0.33-0.743 c0-0.239-0.084-0.479-0.258-0.67c-2.076-2.299-5.222-3.673-8.266-5.001c0,0-2.377-1.112-3.174-1.486 c0.223-7.385,1.021-14.572,4.909-17.887c1.892-1.614,4.386-2.189,7.621-1.757c4.143,0.554,9.086,4.472,11.5,9.113 c1.348,2.591,2.51,6.535,0.395,10.611c-0.254,0.49-0.064,1.093,0.426,1.348c0.49,0.254,1.094,0.063,1.35-0.427 c1.959-3.775,1.818-8.199-0.395-12.456c-2.732-5.251-8.203-9.53-13.012-10.172C138.853,125.257,135.763,126,133.446,127.979z" + }, + "stroke": { + } + } + ] + }, + { + "children": [ + { + "shape": { + "type": "path", + "path": "M154.077,146.278c-2.156,1.18-4.24,2.619-6.256,4.01c-3.635,2.509-7.068,4.878-10.941,5.924 c-2.991,0.808-6.055,1.058-9.3,1.324c-3.222,0.263-6.553,0.536-9.783,1.406c-2.027,0.546-4.117,1.397-6.137,2.221 c-3.491,1.423-7.102,2.895-10.528,2.866c-0.552-0.005-1.004,0.439-1.009,0.991s0.439,1.004,0.991,1.009 c3.828,0.033,7.627-1.516,11.301-3.014c2.054-0.837,3.994-1.628,5.902-2.142c3.054-0.823,6.292-1.088,9.425-1.344 c3.191-0.261,6.492-0.531,9.659-1.386c4.205-1.135,7.941-3.714,11.557-6.208c1.973-1.362,4.014-2.771,6.08-3.901 c0.484-0.265,0.662-0.873,0.396-1.357S154.562,146.013,154.077,146.278z" + }, + "stroke": { + } + } + ] + }, + { + "children": [ + { + "shape": { + "type": "path", + "path": "M156.458,153.549c-2.619,0.064-5.709,0.812-8.98,1.604c-4.279,1.035-8.701,2.104-11.902,1.536 c-0.543-0.096-1.063,0.267-1.159,0.81c-0.097,0.544,0.267,1.063,0.81,1.16c3.613,0.641,8.24-0.481,12.72-1.562 c3.166-0.766,6.154-1.489,8.561-1.548c5.664-0.141,7.961,0.698,13.508,2.724c0.518,0.189,1.094-0.077,1.281-0.596 c0.189-0.519-0.076-1.091-0.596-1.282C165.069,154.337,162.501,153.399,156.458,153.549z" + }, + "stroke": { + } + } + ] + } + ] + } + ] + }, + { + "name": "textSurface", + "children": [ + { + "name": "spokenBubble", + "children": [ + { + "name": "textContainer", + "shape": { + "type": "path", + "path": "M225.719,45.306c0-6.627,5.373-12,12-12h181.333 c6.627,0,12,5.373,12,12V150.64c0,6.627-5.373,12-12,12H237.719c-6.627,0-12-5.373-12-12V45.306z" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "name": "textArrowBelow", + "shape": { + "type": "path", + "path": "M249.052,160.639 c-0.775,14.251-1.676,18.525-9.1,30.565c9.705-0.79,21.952-21.605,25.1-30.045" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "thoughtBubble", + "children": [ + { + "name": "textContainer_1_", + "shape": { + "type": "path", + "path": "M202.698,21.089 c19.686-26.45,59.686-24.45,79.747-0.084c2.697,1.349,5.571,1.709,7.472,0.781c15.28-13.888,33.272-14.043,49.893-7.839 c2.771,1.034,5.478,2.219,8.031,3.421c28.543-21.729,75.543-10.729,83.166,27.658c0,0-1.324,3.889,1.165,6.603 c18.212,11.011,26.212,32.011,22.212,53.011c-1,5.333-3.223,9.667-6.037,13.52c-2.814,3.854-1.381,0-2.613-0.591 c-1.35-0.929-3.35-0.929-4.35-1.929c16,7,27,22,30,39c2,21-8,41-27,50c-16,7.5-32.5,5.5-45.745-2.556 c-2.532-1.384-4.229-1.856-5.336-1.551c-1.919,0.107-3.919,2.107-5.919,2.107c4-1,6-5,10-6c-15,11-35,12-52,3c-13-7-20-20-24-34 c1,5,3,9,3.299,13.505c-0.397,0.708-3.423,2.219-6.655,3.466c-22.627,8.729-49.423,1.729-65.241-19.971 c-3.453,0-6.263,0.589-8.723,0.879c-17.3,3.2-32.381-7.709-40.771-22.689c-1.678-2.996-3.089-6.153-4.195-9.396 c-15.714-7.795-29.714-18.795-33.714-37.795c-5-25,11-45,29.842-57.667c0.719-2.335,1.697-4.636,3.006-6.896 C201.159,23.306,202.698,21.089,202.698,21.089z" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "children": [ + { + "shape": { + "type": "path", + "path": "M269.719,186.306c0,4.602-4.179,8.333-9.333,8.333c-5.155,0-9.334-3.731-9.334-8.333 c0-4.603,4.179-8.333,9.334-8.333C265.54,177.973,269.719,181.704,269.719,186.306z" + }, + "fill": "#FFFFFF", + "stroke": { + } + }, + { + "children": [ + { + "shape": { + "type": "path", + "path": "M269.719,186.306c0,4.602-4.179,8.333-9.333,8.333c-5.155,0-9.334-3.731-9.334-8.333 c0-4.603,4.179-8.333,9.334-8.333C265.54,177.973,269.719,181.704,269.719,186.306z" + }, + "fill": "none", + "stroke": { + } + }, + { + "shape": { + "type": "path", + "path": "M268.225,186.165c-0.564,8.736-13.982,9.286-15.633,0.853 c-1.785-9.125,15.017-10.254,15.649-0.451c0.125,1.929,3.078,1.388,2.955-0.521c-0.814-12.597-20.828-12.412-21.639,0.119 c-0.827,12.813,20.831,13.028,21.655,0.283C271.337,184.518,268.35,184.235,268.225,186.165z" + }, + "fill": "#FFFFFF", + "stroke": { + } + } + ] + } + ] + }, + { + "shape": { + "type": "path", + "path": "M260.386,188.306c0,3.498-2.985,6.333-6.667,6.333 s-6.667-2.835-6.667-6.333c0-3.498,2.985-6.333,6.667-6.333S260.386,184.808,260.386,188.306z" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M238.386,196.973c0,1.289-1.045,2.333-2.334,2.333 c-1.288,0-2.333-1.045-2.333-2.333s1.045-2.333,2.333-2.333C237.341,194.639,238.386,195.684,238.386,196.973z" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M285.719,179.973c0,4.602-4.253,8.333-9.5,8.333 s-9.5-3.731-9.5-8.333c0-4.603,4.253-8.333,9.5-8.333S285.719,175.371,285.719,179.973z" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "yellBubble", + "children": [ + { + "shape": { + "type": "path", + "path": "M251.156,176.051 l40.228-15.992" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M280.932,149.385 l-40.667,36.42" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "textContainer_2_", + "shape": { + "type": "path", + "path": "M217.778,34.643 c8.609,6.684,9.952,3.684,7.987-5.785c6.308,5.125,9.308,3.782,10.188-4.309c2.433,8.091,5.266,8.091,9.12-1.703 c6.063,9.793,13.146,9.793,24.043,3.878c6.103,5.915,16.02,5.915,20.094-4.64c17.178,10.555,28.511,10.555,45.233-5.505 c5.941,16.06,17.273,16.06,18.835,1.458c19.688,14.603,29.605,14.603,46.749-17.802c-0.144,32.405,6.939,32.405,29.26,16.182 c-12.403,16.223-9.57,16.223,4.813,6.576c-11.07,9.646-8.07,10.99,4.333,9.089c-8.061,6.244-6.717,9.244,2.533,11.068 c-9.25,1.489-9.25,5.703-0.315,13.07c-8.935,6.115-8.935,15.385,7.513,10.932c-16.447,24.677-16.447,35.631,14.938,36.553 c-31.385,19.303-31.385,28.571-4.39,40.526c-26.995,1.528-26.995,5.741-5.942,17.857c-21.053-8.801-22.396-5.802-9.526,11.916 c-17.213-13.374-20.213-12.03-12.048,8.029c-11.479-20.06-14.312-20.06-10.553,3.532c-13.676-23.591-20.759-23.591-29.814-2.664 c-7.944-20.927-17.861-20.927-27.072,12.467c-12.039-33.395-23.373-33.395-23.148-1.581 c-22.89-31.814-34.224-31.814-61.517-8.479c6.042-23.335-3.874-23.335-11.9-9.703c-8.975-13.632-16.058-13.632-23.926,4.361 c-2.049-17.993-4.882-17.993-10.51-1.486c2.314-16.508-0.686-17.851-12.385-5.019c7.356-17.175,6.013-20.176-10.27-7.879 c16.283-15.61,16.283-19.824-9.255-12.972c25.538-20.334,25.538-29.603,1.919-46.578c23.619-3.249,23.619-14.204-0.313-25.522 c23.933-8.905,23.933-18.175,7.798-37.429C226.385,48.854,226.385,44.64,217.778,34.643z" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + } + ] + } + ] + } + ] + } +] \ No newline at end of file diff --git a/includes/js/dojox/gfx/demos/data/Lars.svg b/includes/js/dojox/gfx/demos/data/Lars.svg new file mode 100644 index 0000000..7295501 --- /dev/null +++ b/includes/js/dojox/gfx/demos/data/Lars.svg @@ -0,0 +1,531 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/includes/js/dojox/gfx/demos/data/LarsDreaming.json b/includes/js/dojox/gfx/demos/data/LarsDreaming.json new file mode 100644 index 0000000..d4cd1ad --- /dev/null +++ b/includes/js/dojox/gfx/demos/data/LarsDreaming.json @@ -0,0 +1,1823 @@ +[ + { + "name": "torso", + "children": [ + { + "name": "leftArm", + "shape": { + "type": "path", + "path": "M156.007,292.675c2.737,1.778,5.563,3.321,8.752,3.946c7.099,1.391,19.25-5.666,23.136-11.698 c1.572-2.441,8.077-21.031,11.178-14.271c1.224,2.67-1.59,4-1.399,6.462c3.108-1.425,5.48-5.242,8.918-2.182 c0.672,4.019-4.472,4.343-3.918,7.669c1.376,0.218,5.395-1.595,6.285-0.535c1.707,2.027-2.933,3.561-4.072,4.018 c-1.852,0.741-4.294,1.233-5.988,2.369c-2.636,1.769-4.766,5.144-7.033,7.4c-11.657,11.604-26.184,10.553-40.646,5.515 c-4.713-1.642-17.399-4.472-18.655-9.427c-1.647-6.502,5.523-7.999,10.184-6.74C147.658,286.528,151.725,289.892,156.007,292.675z" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "leftArmThumb", + "shape": { + "type": "path", + "path": "M188.257,284.902c-1.932-1.391-3.313-4.206-3.506-6.494c-0.149-1.786,0.59-6.521,3.199-3.95c0.792,0.78,0.083,2.155,0.558,2.943 c0.885,1.47,1.071,0.493,2.748,1.002c1.406,0.426,3.827,2.05,4.251,3.499" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "rightArm", + "shape": { + "type": "path", + "path": "M57.05,283.307c-5.502,5.354-13.185,8.541-18.249,14.221c-4.303,4.827-7.721,11.575-11.138,17.112 c-6.752,10.938-10.794,26.076-19.912,35.185c-3.869,3.866-7.637,5.722-7.251,12.032c0.932,0.372,1.548,0.589,2.418,0.683 c0.605-2.745,2.569-4.198,5.362-3.799c-0.14,3.365-3.512,5.941-3.228,9.235c0.364,4.223,3.983,5.968,7.181,2.662 c2.61-2.699,0.192-7.849,3.338-10.18c5.535-4.103,2.889,2.998,4.13,5.515c5.19,10.519,8.634-1.859,7.35-7.996 c-2.336-11.159-3.003-15.126,3.267-24.416c6.358-9.419,12.194-18.708,19.399-27.588c1.116-1.375,2.08-2.729,3.333-4" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "shirt", + "children": [ + { + "name": "tShirt", + "shape": { + "type": "path", + "path": "M96.509,268.265 c-2.301,0.323-4.69,0.205-6.945,0.72c-2.234,0.509-4.5,0.8-6.749,1.249c-4.369,0.872-8.206,3.265-12.3,5.024 c-3.259,1.4-6.644,2.57-9.763,4.26c-1.923,1.041-3.688,2.616-5.487,3.97c-1.543,1.16-3.495,2.11-4.854,3.563 c-2.205,2.354,0.896,7.407,1.854,9.873c0.92,2.367,2.149,4.819,2.749,7.29c0.228,0.937,0.235,2.058,0.875,2.872 c0.644,0.821,0.64,0.735,1.822,0.049c1.513-0.878,2.873-1.993,4.329-2.993c2.431-1.67,5.462-2.849,7.434-5.111 c-3.335,1.652-5.335,4.679-6.931,8.012c-1.398,2.921-4.482,35.854-5.389,38.947c-0.195,0.003-0.775,0.003-0.749,0.013 c20.561,0,41.123-0.069,61.684,0c2.1,0.008,3.607-0.496,5.529-1.252c0.715-0.28,2.257-0.355,2.807-0.744 c1.412-0.998-0.094-3.916-0.646-5.303c-1.425-3.579-2.111-37.767-4.726-40.543c1.842,0.058,4.127,1.312,5.938,1.95 c1.351,0.478,2.633,1.092,3.956,1.66c1.39,0.597,3.667,1.927,5.168,1.857c0.296-1.872,1.045-3.285,1.839-5.02 c0.942-2.061,1.155-4.214,1.528-6.415c0.351-2.07,0.897-3.787,1.938-5.635c0.531-0.942,1.356-1.73,1.693-2.769 c-0.443-0.401-1.043-0.906-1.604-1.125c-0.56-0.219-1.292-0.11-1.908-0.33c-1.236-0.438-2.439-1.089-3.668-1.575 c-3.773-1.499-7.519-2.983-11.319-4.467c-3.575-1.396-6.977-3.238-10.784-3.871c-1.735-0.289-3.467-0.529-5.073-0.906" + }, + "fill": "#4459A5", + "stroke": { + "color": "#000000", + "cap": "round" + } + }, + { + "name": "shirtNeck", + "shape": { + "type": "path", + "path": "M99.759,268.89 c-0.984,0.151-1.746-0.549-2.75-0.5c-1.369,0.065-1.649,0.872-2.153,2c-1.037,2.325-2.442,4.974,0.064,6.945 c2.53,1.991,6.964,1.718,9.829,0.804c1.616-0.517,3.045-1.24,3.825-2.867c0.508-1.062,0.935-2.771,0.149-3.598 c-0.231-0.243-0.562-0.376-0.84-0.534" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round" + } + }, + { + "name": "shirtLogo", + "children": [ + { + "children": [ + { + "shape": { + "type": "path", + "path": "M104.864,296.921c-0.151-0.004,7.101,0.409,7.052,0.403c0.132,0.028-0.172,0.633-0.021,0.632 c-0.226,0.028-7.244-0.454-7.28-0.464C104.657,297.519,104.776,296.904,104.864,296.921z" + }, + "stroke": { + } + } + ] + }, + { + "children": [ + { + "shape": { + "type": "path", + "path": "M90.071,295.919c-0.199,0.005,6.792,0.431,6.79,0.446c0.153,0.005-0.031,0.663,0.012,0.665 c0.272,0.016-6.79-0.471-6.875-0.459C89.881,296.561,89.796,295.899,90.071,295.919z" + }, + "stroke": { + } + } + ] + }, + { + "shape": { + "type": "path", + "path": "M84.407,306.477c0.2-0.159,0.322-1.04,0.254,0.057c-0.542-0.355-2.02,2.083-4.215,2.001 c-1.887-1.706-4.559-3.384-4.302-7.092c0.652-2.599,3.082-4.084,5.213-3.942c1.889,0.378,2.899,0.717,4,1.318 c-0.497,0.957-0.175,0.866-0.459,0.703c0.456-2.398,0.598-5.75,0.312-7.855c0.594-0.554,0.714,0.125,1.249,0.941 c0.502-0.727,0.509-1.425,0.875-0.571c-0.207,1.328-0.809,7.187-0.711,10.174c-0.126,2.798-0.375,4.354-0.051,4.985 c-0.718,0.613-0.667,1.006-0.981,1.381c-0.72-1.33-1.056-0.132-1.339-0.157C84.632,308.442,84.493,305.791,84.407,306.477z M81.186,307.177c2.403,0.206,3.734-2.164,3.841-4.223c0.269-2.72-0.896-5.104-3.198-5.04c-1.972,0.438-3.46,2.188-3.331,4.639 C78.171,306.266,79.847,306.962,81.186,307.177z" + }, + "stroke": { + } + }, + { + "shape": { + "type": "path", + "path": "M93.321,297.767c2.592,0.147,5.688,2.314,5.696,5.627c-0.611,4.576-3.69,5.316-6.158,5.581 c-2.68-0.76-5.708-1.872-5.413-6.472C88.086,299.395,90.653,297.875,93.321,297.767z M92.939,307.46 c2.531,0.735,3.706-1.297,3.666-3.935c0.114-2.219-0.641-4.584-3.389-4.896c-2.29-0.553-3.366,2.188-3.661,4.688 C89.339,305.265,89.934,307.95,92.939,307.46z" + }, + "stroke": { + } + }, + { + "shape": { + "type": "path", + "path": "M99.688,303.916c0.03-1.511,0.055-4.73,0.022-4.646c0.481-1.355,0.658-0.556,1.034-1.297 c0.263,1.473,0.653,0.326,1.186,0.065c-0.386,2.518-0.513,3.348-0.574,4.949c-0.068-0.47-0.128,2.28-0.238,2.188 c-0.055,1.935-0.036,2.201-0.047,4.219c-0.079,0.914-0.28,2.412-1.126,3.831c-0.61,1.212-1.73,1.146-3.24,1.651 c0.073-0.945-0.065-1.242-0.096-1.822c0.098,0.138,0.213,0.604,0.225,0.397c1.892,0.229,2.209-1.896,2.362-3.365 c0.042,0.304,0.512-6.934,0.415-7.062C99.73,302.637,99.75,303.179,99.688,303.916z M100.978,295.564 c0.717,0.14,1.11,0.61,1.099,1.156c0.052,0.552-0.595,0.993-1.286,1.015c-0.541-0.074-1.025-0.548-1.022-1.054 C99.813,296.084,100.292,295.644,100.978,295.564z" + }, + "stroke": { + } + }, + { + "shape": { + "type": "path", + "path": "M108.115,298.791c3.028-0.066,5.283,1.359,5.256,5.758c-0.264,3.479-3.366,4.63-5.883,5.119 c-2.429-0.033-5.619-2.24-5.16-5.811C102.322,300.085,105.715,298.846,108.115,298.791z M107.351,309.232 c2.675-0.132,3.839-2.333,3.841-4.497c0.246-2.344-0.263-4.833-2.923-5.396c-2.844,0.299-3.974,1.917-4.053,4.479 C104.136,306.655,104.854,308.372,107.351,309.232z" + }, + "stroke": { + } + } + ] + } + ] + } + ] + }, + { + "name": "heads", + "children": [ + { + "name": "head1", + "children": [ + { + "name": "leftEart", + "children": [ + { + "shape": { + "type": "path", + "path": "M201.557,195.475 c7.734-4.547,16.592-5.012,18.405,4.443c2.43,12.659-3.317,13.328-14.598,13.328" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M211.711,203.09 c0.523,0.004,0.946-0.208,1.271-0.635" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M211.076,197.377 c3.062,3.013,5.489,5.624,4.442,10.155" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + } + ] + }, + { + "name": "bgHairTop", + "shape": { + "type": "path", + "path": "M54.384,199.307c-5.253-4.402-7.511-11.061-15.779-10.632c3.449-1.277,7.116-2.397,10.911-2.666 c-2.873-1.397-5.865-2.575-8.231-4.718c3.986-1.119,11.47-1.817,14.864,0.75c-5.183-2.758-8.397-7.816-13.062-10.598 c6.014-0.643,12.377,0.978,18.022,2.265c-2.547-4.486-6.682-10.83-10.523-14.297c5.033,1.052,10.647,4.518,15.062,7.177 c-1.614-4.176-5.634-8.406-7.859-12.513c10.312-1.125,12.522,4.919,19.7,9.932c-0.412-0.127-1.114-0.113-1.527,0.015 c0.875-7.261,3.058-12.8,8.258-18.566c6.771-7.507,17.813-9.131,24.095-15.381c-4.699,1.821-4.518,23.765-4.875,28.955" + }, + "fill": "#FFF471", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "bgHairLeft", + "shape": { + "type": "path", + "path": "M92.384,243.973c-6.334,7.929-12.601,12.241-22.465,15.361c3.65-1.263,7.735-5.859,7.695-9.928 c-2.208,0.218-4.49,0.605-6.498,1.098c1.244-1.098,2.087-3.239,3.198-4.396c-5.77,0.001-12.131,1.133-18.396,1.23 c5.013-2.81,10.665-3.25,12.398-9.247c-3.59,0.313-7.233,1.606-11.033,1.097c1.731-2.022,3.953-3.995,5.049-6.447 c-3.781,0.056-6.665,3.098-10.547,2.465c0.962-2.863,3.187-5.208,4.531-7.766c-5.59-0.273-11.658,2.45-17.732,2.564 c5.494-2.857,8.967-7.819,12.3-12.718c5.233-7.693,10.625-9.96,20.349-9.981c11.059-0.024,15.558,6.714,20.984,16 c2.786,4.767,7.249,14.375,0.832,18" + }, + "fill": "#FFF471", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "bgHair", + "shape": { + "type": "path", + "path": "M142.384,255.307c2.984,6.076,3.567,11.855,10.531,14.6c-0.134-3.114-0.094-6.664,1.619-9.033 c1.604,1.969,3.122,4.211,5.048,5.698c-0.29-1.769,0.412-4.023,0.233-5.828c3.444,0.261,4.979,3.965,8.468,4.479 c0.065-2.78,0.427-5.151,0.868-7.813c2.687,0.2,4.768,1.565,7.132,2.997c0.452-4.921-0.409-10.579-0.667-15.666 c-5.795-0.756-12.291,2.827-17.899,3.899c-4.414,0.844-14.136,0.523-15.333,6" + }, + "fill": "#FFF471", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "neck", + "shape": { + "type": "path", + "path": "M106.989,254.499c-2.932,6.063-4.613,11.997-8.947,17.138c7.288,10.194,16.311-10.9,15.183-17.026 c-1.926-1.138-3.928-1.589-6.236-1.38" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "headShape", + "shape": { + "type": "path", + "path": "M210.941,207.666c-0.844,3.985-2.081,7.982-3.77,11.783c-3.374,7.604-8.543,14.427-16.052,18.899 c-2.94,2.13-5.983,4.167-9.109,6.085c-25.013,15.342-55.353,23.08-82.254,10.57c-3.433-1.558-6.785-3.432-10.053-5.66 c-1.821-1.185-3.592-2.46-5.308-3.832c-1.715-1.373-3.375-2.842-4.972-4.412c-2.352-2.148-4.576-4.425-6.631-6.814 c-6.168-7.169-10.823-15.358-12.87-24.185c-0.649-3.284-0.84-6.634-0.5-9.975c4.48-13.743,14.22-24.364,26.109-32.149 c2.973-1.946,6.079-3.715,9.271-5.309c30.581-15.027,69.581-10.027,95.852,12.209c2.563,2.254,4.987,4.651,7.244,7.178 c4.513,5.054,8.354,10.626,11.312,16.64C210.178,201.505,210.798,204.497,210.941,207.666z" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "rightEar", + "children": [ + { + "shape": { + "type": "path", + "path": "M64.857,195.606 c-6.59-7.181-15.047-10.664-19.467,3.676c-1.235,4.007-1.87,14.468,1.29,17.786c4.223,4.435,13.591,0.529,19.055-0.015" + }, + "fill": "#FFE8B0", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M52.407,196.744 c-1.702,3.613-1.257,7.505-1.27,11.424" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M51.772,209.438 c-3.39-4.661,0.922-5.769,5.078-6.347" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + } + ] + }, + { + "name": "fgHair", + "shape": { + "type": "path", + "path": "M90.384,154.64c8.453-11.353,15.678-13.458,28.581-15.915c-1.382,3.376-3.89,7.352-5.179,11.16 c5.01-1.816,9.571-6.545,15.218-8.413c11.355-3.755,23.853-1.903,35.671-2.213c-3.004,3.712-4.912,7.88-2.025,11.447 c5.855-2.212,13.369-6.871,19.635-6.646c0.263,4.561-0.024,9.278,0.201,13.841c3.509-1.201,6.015-3.04,8.276-5.148 c2.263-2.108,3.761-4.049,4.942-5.2c1.063,2.408,2.134,5.334,2.24,8.494c-0.183,3.462-0.866,6.794-2.66,9.291 c3.663,0.65,6.098-2.021,8.35-4.479c-0.655,4.349-3.164,8.604-3.851,13.013c2.178-0.072,4.382,0.216,6.367-0.48 c-1.39,3.093-3.069,7.287-6.616,8.414c-4.476,1.423-4.354-0.992-7.315-4.332c-4.892-5.518-9.773-6.791-15.872-9.464 c-6.585-2.887-10.982-6.47-17.963-8.219c-8.994-2.255-19.864-3.867-28.093-5.196c2.466,1.967,1.138,5.594,0.659,8.625 c-2.729-0.646-4.41-3.813-6.301-5.158c0.953,3.195,0.983,6.953-2.134,8.491c-6.145-5.226-9.199-9.721-17.527-11.647 c1,1.83,1.728,4.208,1.396,6.402c-0.751,4.971-0.289,3.134-3.836,2.466c-5.192-0.977-9.953-3.677-15.815-4.496 c3.292,2.002,5.469,5.017,7.418,8.21c-2.651,0.404-6.238,0.257-8.382,1.671c2.456,0.38,3.44,2.166,3.197,4.714 c-7.45,0.386-13.623,0.731-19.915,5.434" + }, + "fill": "#FFF471", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + } + ] + } + ] + }, + { + "name": "eyes", + "children": [ + { + "name": "eyes1", + "children": [ + { + "shape": { + "type": "path", + "path": "M123.163,176.668 c-5.066,1.17-9.01,7.888-13.666,10.335c-4.238,2.227-8.648,6.636-7.009,12.332c1.971,6.848,12.042,3.991,16.261,1.165 c5.282-3.539,9.59-8.517,12.006-14.524c1.523-3.787,2.568-7.272-1.509-9.391c-2.905-1.51-8.174-1.386-11.417-0.583" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M182.545,179.865 c-3.533,0.169-4.854-1.166-8.408-0.001c-3,0.983-6.239,1.936-8.852,3.743c-3.938,2.725-7.46,5.555-4.73,13.592 c1.974,5.811,8.791,7.571,14.656,6.667c5.537-0.854,9.078-4.977,11.408-10.007c3.666-7.918,0.942-11.639-6.742-13.659" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000", + "cap": "round" + } + }, + { + "shape": { + "type": "path", + "path": "M108.829,183.668c-1.308-1.03-4.557,0.011-5.6-1.733 c-1.056-1.765,1.735-5.409,2.984-6.192c5.684-3.562,15.946-0.39,19.95-6.742" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M163.877,167.198c2.369,1.282,6.539,0.307,9.408,0.815 c3.449,0.612,7.065,2.657,10.592,2.851" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M127.496,192.002c-4.917-2.12-9.188-1.708-8.608,4.942 c3.132,1.734,5.428-2.82,7.275-4.942" + }, + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M174.852,203.144c-0.293,0.12-0.307,0.577-0.942,0.282 c-1.605-3.188-0.404-6.507,2.676-8.192c2.15-1.176,5.67-1.759,7.471,0.359c0.199,0.234,0.412,0.521,0.515,0.813 c0.229,0.649-0.285,0.95-0.285,0.95s-3.988,6.009-3.285,1.934c0.438,1.743-5.537,5.743-2.287,1.653 c-1.955,2.583-2.524,1.977-3.859,2.868" + }, + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "eyes2", + "children": [ + { + "shape": { + "type": "path", + "path": "M98.668,186.108c0.668-8.915,15.545-13.749,22.667-15" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M169.667,178.108c5.307,3.436,16.928,5.632,19.668,12.333" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M105.334,197.775c8.085-4.283,17.059-2.8,25-6.333" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M164.001,198.775c4.656-0.417,9.664,1.805,14.334,2.017 c3.951,0.18,5.773,0.189,9,2.316" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M124.001,188.108c3.039-0.258,4.594,2.571,5.301,4.983 c-1.096,1.242-2.065,2.646-2.968,4.017" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M168.335,194.108c-1.77,2.293-4.869,3.271-6.299,5.91 c1.377,0.991,3.02,2.122,3.965,3.424" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + } + ] + } + ] + }, + { + "name": "beard", + "children": [ + { + "shape": { + "type": "path", + "path": "M96.05,213.64 c-0.366,0.21-0.783,0.389-1.167,0.5" + }, + "fill": "#AFA8A5", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M102.55,211.973 c0.314-0.01,0.554-0.198,0.667-0.5" + }, + "fill": "#AFA8A5", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M105.717,208.806 c0.164-0.109,0.336-0.224,0.5-0.333" + }, + "fill": "#AFA8A5", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M111.05,207.973 c-0.651-1.81,0.859-2.262,2.333-1.5" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M117.717,209.806 c1.738,0,3.653,0.369,5.333,0.167" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M132.717,214.473 c0.104-0.21,0.162-0.435,0.167-0.667" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M139.551,216.973 c0.215-0.175,0.465-0.426,0.666-0.667" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M144.551,213.306 c0.277-0.056,0.557-0.111,0.833-0.167" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M147.884,216.64 c0.195,0.045,0.369-0.013,0.5-0.167" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M148.384,214.14 c0.112-0.168,0.223-0.332,0.333-0.5" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M98.217,219.306c1.697-1.772,4.233-2.109,5.967-4.046c1.519-1.696,3.812-3.001,4.2-5.454" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M152.717,216.14 c0.611,0,1.224,0,1.834,0" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M160.384,217.473 c0.333,0,0.667,0,1,0" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M163.217,215.973 c0.321-0.042,0.658-0.175,0.834-0.333" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M164.217,218.806 c0.167,0,0.333,0,0.5,0" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M168.384,217.973 c0.057-0.056,0.111-0.111,0.167-0.167" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M169.884,225.806 c0.491-0.397,0.882-0.926,1.167-1.5" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M172.717,221.973 c0.057,0,0.111,0,0.167,0" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M171.717,229.806 c0.334,0.075,0.659,0.025,0.834-0.167" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M190.051,227.806 c0.163-0.242,0.398-0.423,0.666-0.5" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M197.384,221.473 c0.258-0.007,0.485-0.125,0.667-0.333" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M199.384,214.973 c-0.04-0.333,0.075-0.609,0.333-0.833" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M117.884,257.306 c0.056,0,0.111,0,0.167,0" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M142.717,252.473 c0.358,0.068,0.71,0.016,1-0.167" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M137.884,256.473 c0.277,0,0.557,0,0.833,0" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M160.884,252.973 c0.366-0.139,0.766-0.402,1-0.667" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M171.384,250.14 c0.235-0.264,0.476-0.562,0.667-0.834" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M89.384,243.973 c0.537,0.378,1.329,0.876,1.833,1.333" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M79.05,225.473 c0.087,0.272,0.143,0.55,0.167,0.833" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M73.884,222.64 c0,0.167,0,0.333,0,0.5" + }, + "fill": "none", + "stroke": { + "color": "#AAAAAA", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M72.55,219.806c0.466-0.325,0.875-0.797,1.167-1.333" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M71.717,211.973c0.422-0.553,0.776-1.305,1-2" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M78.55,214.473c0-0.111,0-0.222,0-0.333" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M79.384,218.806c-0.001-0.137,0.055-0.248,0.167-0.333" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M80.217,221.14c0.111,0,0.222,0,0.333,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M75.55,226.473c0.103-0.5,0.156-0.977,0.167-1.5" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M78.55,230.14c0.111,0,0.222,0,0.333,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M83.384,227.64c0.118-0.059,0.215-0.107,0.333-0.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M81.55,237.14c0.056,0,0.111,0,0.167,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M86.217,233.806c0.056,0,0.111,0,0.167,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M87.884,230.473c0.595-0.181,1.219-0.527,1.833-0.667" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M88.717,222.14 c-0.929,2.359-1.615,4.865-2.667,7.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M89.05,216.14 c0.784-0.736,1.709-1.565,2.833-1.5" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M94.217,210.14 c1.599-0.089,3.199-0.167,4.833-0.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M94.884,224.64 c0.052-0.588-0.004-1.155-0.167-1.667" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M92.384,228.306 c0.585-0.062,1.244-0.132,1.667-0.333" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M88.717,240.14 c0.111,0,0.222,0,0.333,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M95.884,243.306 c0.526,0.1,1.017-0.016,1.333-0.333" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M98.55,248.306 c0.069-0.24,0.265-0.926,0.333-1.166" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M96.55,249.806 c0.125,0.014,0.18-0.042,0.167-0.166" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M104.55,250.14 c0.01-0.238,0.126-0.428,0.333-0.5" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M106.884,251.973 c0.195,0.045,0.37-0.014,0.5-0.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M113.884,254.806 c0.758-0.586,1.595-1.171,2.382-1.774c0.072,0.376,0.418,0.686,0.48,1.079c0.833,0.265,1.624-0.021,1.638-0.971" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M122.217,254.64 c0.063-0.165,0.179-0.288,0.333-0.334" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M125.884,255.806 c1.13-0.745,2.783-0.962,3.667-2" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M132.217,255.973 c0.638-0.492,1.104-1.173,1.141-1.976c-1.11,0.063-1.449-0.888-1.475-1.857" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M129.717,249.306 c-0.045,0.153-0.168,0.271-0.333,0.334" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M136.551,252.306 c0.223,0,0.444,0,0.666,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M110.217,251.306 c0.056-0.057,0.111-0.11,0.167-0.166" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M140.717,251.806 c0.111,0,0.224,0,0.334,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M150.051,249.473 c0.111,0,0.223,0,0.333,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M143.217,255.473 c1.022-0.313,1.725-1.175,2.646-1.654c0.203,0.321,0.439,0.626,0.521,0.987" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M152.217,253.473 c0.165-0.063,0.288-0.179,0.334-0.333" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M155.051,254.64 c0.223,0,0.444,0,0.666,0" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M157.717,256.473 c0.326-0.027,0.546-0.073,0.834-0.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M163.217,252.64 c0.552-0.892,2.082-1.512,2.341-2.334c0.37-1.178-1.155-3.069-1.007-4.5" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M167.384,235.973 c0.118-0.54,0.354-1.064,0.667-1.5" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M170.717,242.806 c0-0.333,0-0.667,0-1" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M170.217,236.973 c0-0.333,0-0.667,0-1" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M179.051,235.806 c0.378-0.101,0.738-0.35,1-0.667" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M185.051,232.806 c0.379-0.319,0.656-0.702,0.833-1.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M188.051,231.14 c0.063-0.39,0.178-0.792,0.333-1.167" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M197.884,223.306 c-0.166,0.277-0.334,0.556-0.5,0.833" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + } + ] + }, + { + "name": "mouths", + "children": [ + { + "name": "mouth1", + "children": [ + { + "shape": { + "type": "path", + "path": "M177.122,216.821c-0.515,2.282-5.213,3.21-7.434,3.854 c-3.254,0.945-6.596,1.345-9.895,1.851c-3.26,0.5-6.665,0.671-10.107,0.671c-3.596,0-6.645,0.559-10.106,0.671 c-3.105,0.1-6.898-0.474-9.694-1.3c-3.527-1.043-6.672-1.666-10.096-3.062c-2.823-1.152-5.746-1.876-8.462-3.143 c-2.594-1.209-6.084-1.994-8.221-3.552c-1.068,1.834-5.867,3.748-8.1,4.546c-2.444,0.874-8.881,2.725-7.817,5.512 c0.457,1.195,1.948,2.273,2.63,3.385c0.774,1.261,1.139,2.601,2.057,3.859c1.83,2.5,4.506,4.773,6,7.34 c1.308,2.249,2.096,4.74,4.01,6.669c2.214,2.233,5.792,2.635,9.231,2.399c7.028-0.479,13.982-2.129,20.481-3.983 c3.295-0.941,6.699-1.536,10.086-2.686c3.272-1.111,6.642-3,9.402-4.777c5.248-3.377,10.278-6.409,14.283-10.705 c1.479-1.587,3.429-2.503,5.149-3.859" + }, + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M135.25,241.319 c0.723-4.757-10.487-8.47-14.898-9.526c-3.09-0.74-6.68-1.17-9.858-1.712c-2.758-0.47-6.865-0.836-9.437,0.369 c-1.385,0.649-2.843,1.724-4.141,2.513c2.156,3.964,4.728,8.861,9.468,11.506c3.229,1.801,5.511,0.776,8.859,0.373 c3.045-0.369,6.046-0.703,9.029-1.721c3.479-1.186,7.228-2.385,10.978-2.475" + }, + "fill": "#FFC0C0", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M148.656,225.547c1.267,0.697,1.301,2.838,0.671,3.9 c-0.702,1.182-2.063,1.4-3.307,2.01c-2.271,1.116-4.58,2.624-7.481,2.638c-4.619,0.023-2.144-4.067-0.253-5.869 c2.405-2.292,5.057-2.72,8.72-2.512c0.588,0.034,1.095,0.041,1.65,0.168" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M130.299,223.365 c2.687,0.437,5.619,4.384,3.727,6.422c-1.234,1.33-7.94,1.391-9.915,1.296c-4.896-0.233-2.502-2.445-0.613-4.525 c1.604-1.767,5.088-3.249,7.833-3.36" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M113.178,217.157 c2.56,0.958,4.922,5.057,5.352,7.215c0.377,1.885-0.324,2.106-2.526,2.643c-1.366,0.333-3.636,0.723-5.105,0.385 c-2.506-0.577-5.883-5.051-4.909-7.223c1.03-2.298,5.944-2.923,8.427-2.852" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M99.359,217.662 c2.038,0.432,4.015,4.279,2.468,5.625c-1.083,0.943-5.221,1.795-6.799,1.589c-4.032-0.526-2.265-4.102-0.866-5.872 c0.706-0.894,1.049-1.976,2.514-2.186c1.627-0.233,2.501,0.99,3.921,1.346" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M181.815,222.896c-3.102-2.75-4.765-8.777-9.282-10.403" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "mouth2", + "children": [ + { + "shape": { + "type": "path", + "path": "M87.57,221.951c5.563-1.759,11.066-1.32,16.694-1.782c2.93-0.24,5.228-1.14,8.309-0.927c3.142,0.217,6.085-0.235,9.289,0.176 c7.136,0.914,13.96,0.598,21.112,1.506c3.654,0.464,7.219,0.609,10.811,0.869c4.017,0.291,7.646,1.582,11.433,2.623 c2.948,0.812,6.347,1.618,9.011,2.99c2.521,1.298,6.354,2.856,8.301,4.72c-2.775,0.027-5.602,2.603-8.021,3.769 c-2.93,1.412-5.741,2.949-8.656,4.432c-5.599,2.849-11.885,5.468-18.104,6.53c-6.793,1.161-13.195,2.107-20.067,2.197 c-7.699,0.102-14.313-4.705-20.735-8.396c-2.071-1.19-4.69-2.182-6.504-3.666c-1.792-1.466-3.469-3.386-5.154-4.984 c-2.703-2.564-7.519-5.649-8.13-9.438" + }, + "stroke": { + "color": "#000000", + "width": "3", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M87.785,228.193 c-5.907-3.235-0.344-9.531,3.971-11.424" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2" + } + }, + { + "shape": { + "type": "path", + "path": "M184.679,227.229c-1.534,2.583-2.548,5.334-4.024,7.889" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "width": "2", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M106.862,219.528 c-3.071-0.74-5.608,2.166-6.318,4.738c-0.379,1.375-0.494,2.55,0.748,3.337c1.519,0.962,2.905-0.052,4.418-0.332 c2.518-0.467,7.293,0.053,6.461-4.248c-0.568-2.938-3.743-3.682-6.338-3.335c-0.451,0.06-0.758,0.212-1.205,0.229" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M119.764,218.479 c-2.648,1.243-4.657,3.518-5.346,6.377c-0.866,3.594,3.9,3.711,6.356,2.865c2.64-0.91,4.77-3.351,3.299-6.133 c-1.01-1.91-3.979-2.548-6.026-2.823" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M130.388,219.492 c-1.753,1.382-4.069,4.525-4.835,6.61c-1.159,3.156,2.296,3.371,4.868,3.348c3.061-0.028,6.6-1.148,5.022-4.78 c-1.168-2.691-2.552-4.85-5.551-5.241" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M142.954,221.087 c-1.502,0.337-5.418,3.249-5.638,4.997c-0.292,2.311,4.855,4.536,6.854,4.234c2.503-0.377,4.384-3.175,3.167-5.65 c-0.92-1.873-3.36-2.252-4.508-3.932" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M155.354,222.664 c-2.038,0.426-4.212,2.287-4.766,4.444c-0.723,2.821,3.226,3.383,5.458,3.331c2.541-0.059,5.126-1.752,3.249-4.32 c-1.394-1.908-3.707-3.189-5.304-4.636" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M168.367,237.924 c-1.554-1.217-3.302-2.557-5.203-2.976c-2.973-0.654-3.537,2.131-3.377,4.406c0.205,2.913,1.032,3.883,3.901,2.344 c1.987-1.066,4.271-1.997,4.599-4.456" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M151.524,246.202 c-1.912-0.166-4.004-4.491-2.91-6.25c0.771-1.239,5.456-1.688,6.857-1.292c0.271,0.917,0.979,1.841,0.829,2.771 c-0.088,0.54-0.994,1.645-1.296,2.188c-1.08,1.951-2.133,1.866-3.998,2.685" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M145.911,241.458 c-0.209,1.649-0.215,2.702-1.528,3.801c-0.885,0.738-1.772,1.189-2.54,2.1c-0.786,0.933-1.226,2.38-2.792,1.813 c-1.042-0.377-1.959-2.318-2.138-3.312c-0.299-1.676-1.003-5.228,0.783-6.158c1.154-0.603,7.066-0.18,7.43,1.32" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M133.12,238.991 c-1.495-0.087-2.253-1.33-3.918-0.964c-1.42,0.311-2.489,1.354-2.54,2.836c-0.052,1.527,0.99,5.581,1.852,6.956 c2.363,3.771,4.329-1.535,5.516-3.159c1.117-1.525,2.643-2.053,2.271-3.958c-0.318-1.632-1.118-2.047-2.766-2.329 c-0.382-0.065-0.773-0.095-1.158-0.147" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M116.853,237.43 c-1.049,2.211-0.173,5.147,0.047,7.565c0.357,3.93,3.827,2.028,5.831,0.067c1.575-1.541,4.599-4.86,2.209-6.484 c-1.881-1.279-5.727-2.458-7.756-1.107" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M107.455,233.38 c-0.813,2.487-1.704,5.049,0.073,7.364c1.91,2.486,4.009,1.229,5.537-0.939c1.056-1.5,3.316-4.481,1.563-6.017 c-1.347-1.179-6.468-1.518-7.854-0.325" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "mouth3", + "children": [ + { + "shape": { + "type": "path", + "path": "M99.05,218.973c1.691-0.875,3.313-2.39,4.833-3.537c1.231-0.928,2.782-1.671,3.5-3.072c1.846,3.486,7.661,4.669,11.003,6.067 c3.553,1.486,7.174,3.066,10.784,4.166c4.271,1.301,9.277,1.67,13.721,2.343c4.155,0.629,9.979,1.365,14.162,0.496 c1.182-0.245,2.343-1.024,3.462-1.446c0.162,1.905-3.637,3.023-4.933,3.487c-2.435,0.871-4.18,2.541-6.362,3.871 c-1.623,0.989-2.974,1.669-4.755,2.117c-1.77,0.445-3.353,0.806-4.825,1.878c-5.915,4.311-15.264,3.247-22.424,3.13 c-5.384-0.088-6.719-5.372-9.337-9c-1.437-1.991-2.843-3.854-3.796-6.138c-0.871-2.086-1.119-4.582-2.033-6.528" + }, + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M107.217,227.973c1.182-2.033,4.375-2.176,6.5-1.963c2.879,0.289,4.124,1.217,6.168,3.167c1.834,1.749,5.906,5.509,5.64,8.271 c-2.808,0.89-7.847,0.402-10.346-1.104c-1.334-0.804-1.151-2.256-2.246-3.588c-0.712-0.866-1.836-2.673-2.855-3.311 c-0.209-0.94-2.106-1.499-3.028-1.805" + }, + "fill": "#F4BDBD", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + } + ] + } + ] + }, + { + "name": "personalProps", + "children": [ + { + "name": "hat", + "children": [ + { + "children": [ + { + "children": [ + { + "shape": { + "type": "path", + "path": "M88.374,173.145c0.474-0.074,16.606,2.725,18.01,5.879 c1.145,2.572,28.184,4.568,28.184,4.568l35.971-5.618l5.024,1.132l7.212,0.315l9.295,0.851l10.188,3.248l5.75,2.935 l1.615-1.832l-0.264-5.27l-3.968-7.087c0,0-22.045-13.031-23.272-13.703c-1.229-0.669-4.941-2.294-6.484-4.542 c-8.584-12.528-8.403-18.05-3.371-6.461c0,0,2.662-7.592,2.521-8.575c-0.144-0.982,0.354-5.031,0.354-5.031l2.396-6.832 c0,0-1.379-5.341-2.738-7.19c-1.356-1.844-15.793-4.078-18.162-4.011c-24.933,0.706-3.783,0.071-25.567,0.724 c-24.317,0.728-0.882-2.591-24.068,3.551c-24.228,6.418-5.35-1.298-23.187,6.142c-18.301,7.633-16.67,7.186-16.704,10.685 c-0.034,3.499-3.057-4.884-0.034,3.499c3.023,8.381,3.037-3.871,3.023,8.381c-0.015,12.252,6.696,4.557,1.678,12.373 c-5.017,7.813-3.831,7.91-0.179,8.543c17.017,2.953,4.157,4.378,17.427,3.175" + }, + "fill": "#FF0000", + "stroke": { + } + }, + { + "shape": { + "type": "path", + "path": "M156.604,114.92l-13.936,0.381l-11.633,0.343c-10.646,0.319-11.973-0.155-12.021-0.175l-0.599-0.238 l-0.577,0.514l0.049-0.047c-0.118,0.09-1.43,0.957-11.145,3.53c-9.989,2.646-12.812,2.931-13.421,2.704 c-0.822-0.306-0.821-0.306-7.791,2.604l-2.104,0.878c-16.037,6.689-17.342,7.324-17.342,10.316c0,0.019,0.001,0.041,0.001,0.06 c-0.224-0.108-0.459-0.199-0.787-0.04c-0.357,0.173-0.565,0.275-0.565,0.672c0,0.557,0.411,1.697,1.399,4.438 c0.924,2.561,1.71,3.671,2.714,3.833c0.083,0.014,0.164,0.02,0.241,0.02c0.007,0.584,0.01,1.339,0.01,2.313 c0,0.561-0.001,1.902-0.001,1.916c0,6.908,2.176,8.105,3.347,8.749c0,0,0.075,0.045,0.151,0.09 c-0.095,0.332-0.47,1.1-1.661,2.955c-2.509,3.908-3.516,5.931-3.516,7.303c0,0.358,0.068,0.671,0.196,0.962 c0.544,1.237,1.926,1.477,3.677,1.78l0.135,0.023c8.138,1.412,9.14,2.422,9.568,2.854c0.923,0.931,1.511,0.928,7.224,0.413 c0.06,0.014,0.102,0.068,0.165,0.071c2.167,0.105,16.131,3.138,17.087,5.288c1.147,2.578,16.416,4.228,29.023,5.159 l0.115,0.009c0,0,35.523-5.548,35.896-5.606c0.345,0.078,4.927,1.11,4.927,1.11l7.301,0.319c0,0,8.927,0.818,9.139,0.837 c0.202,0.064,9.854,3.142,10.006,3.19c0.143,0.073,6.368,3.251,6.368,3.251l2.397-2.719l-0.296-5.911l-4.213-7.526 l-0.231-0.137c-0.9-0.532-22.073-13.047-23.304-13.72c-0.001,0-0.734-0.38-0.734-0.38c-1.48-0.752-4.238-2.151-5.404-3.85 c-1.357-1.982-2.451-3.729-3.354-5.268c0.021-0.064,0.104-0.296,0.104-0.296c1.193-3.402,2.576-7.619,2.576-8.885 c0-0.063-0.004-0.118-0.011-0.165c-0.013-0.083-0.018-0.204-0.018-0.356c0-0.909,0.194-2.911,0.363-4.307 c0.072-0.205,2.46-7.013,2.46-7.013l-0.076-0.294c-0.146-0.566-1.468-5.584-2.9-7.532 C173.721,116.784,158.242,114.875,156.604,114.92z M131.097,117.644l11.614-0.342l13.951-0.382 c2.575-0.073,16.104,2.238,17.336,3.614c0.956,1.3,2.058,4.938,2.49,6.549c-0.188,0.536-2.33,6.642-2.33,6.642l-0.014,0.107 c-0.072,0.592-0.387,3.224-0.387,4.658c0,0.258,0.011,0.477,0.034,0.639c-0.006,0.493-0.768,3.026-1.659,5.709 c-2.14-4.566-2.792-4.606-3.242-4.629l-0.62-0.031l-0.354,0.571c-0.069,0.124-0.102,0.29-0.102,0.492 c0,2.273,4.134,9.172,6.992,13.346c1.456,2.12,4.51,3.669,6.149,4.501l0.682,0.353c1.139,0.622,20.813,12.25,23.012,13.549 c0.238,0.427,3.513,6.275,3.721,6.647c0.02,0.393,0.199,3.971,0.23,4.629c-0.229,0.262-0.472,0.535-0.832,0.944 c-1.069-0.546-5.132-2.619-5.132-2.619l-10.369-3.306l-9.403-0.86c0,0-6.995-0.307-7.169-0.315 c-0.168-0.038-5.124-1.155-5.124-1.155s-35.814,5.594-36.044,5.63c-12.419-0.922-25.993-2.687-27.285-4.058 c-1.366-3.097-13.245-5.574-17.517-6.211c-0.203-0.212-0.479-0.346-0.793-0.318c-3.083,0.28-5.996,0.544-6.4,0.369 c0-0.003-0.12-0.117-0.12-0.117c-0.703-0.708-1.879-1.895-10.646-3.416l-0.135-0.023c-0.827-0.143-2.075-0.359-2.188-0.614 c-0.021-0.048-0.033-0.111-0.033-0.193c0-0.592,0.632-2.179,3.205-6.187c1.488-2.318,2.024-3.388,2.024-4.188 c0-0.15-0.019-0.291-0.054-0.428c-0.181-0.712-0.758-1.03-1.179-1.261c-0.865-0.476-2.311-1.271-2.311-6.993 c0-0.014,0.001-1.098,0.001-1.56c0-4.969-0.065-4.992-0.833-5.258c-0.424-0.146-0.816,0.001-1.178,0.377 c-0.208-0.289-0.558-0.898-1.073-2.324c-0.205-0.568-0.385-1.068-0.542-1.506c0.587-0.423,0.632-1.277,0.636-1.644 l-0.014-0.825c-0.004-0.119-0.007-0.231-0.007-0.338c0-1.702,0.899-2.264,16.109-8.608l2.105-0.878 c4.165-1.739,5.948-2.482,6.375-2.562c0.817,0.296,2.292,0.597,14.579-2.658c8.169-2.164,10.697-3.187,11.58-3.704 C120.451,117.773,124.529,117.84,131.097,117.644z" + }, + "stroke": { + } + } + ] + }, + { + "children": [ + { + "shape": { + "type": "path", + "path": "M155.146,147.93c4.88-9.398-5.344-20.199-12.649-21.176 c-12.05-1.61-13.404,10.426-13.684,21.258c3.73,2.016,8.915,3.425,11.721,6.534" + }, + "fill": "#FFFFFF", + "stroke": { + } + }, + { + "shape": { + "type": "path", + "path": "M133.446,127.979c-4.599,3.921-5.426,11.933-5.635,20.006l-0.017,0.654l4.415,2.067 c2.849,1.244,5.793,2.529,7.581,4.509c0.371,0.41,1.004,0.442,1.412,0.072c0.219-0.197,0.33-0.469,0.33-0.743 c0-0.239-0.084-0.479-0.258-0.67c-2.076-2.299-5.223-3.673-8.267-5.001c0,0-2.377-1.112-3.174-1.486 c0.223-7.385,1.021-14.572,4.909-17.887c1.892-1.614,4.386-2.189,7.621-1.757c4.143,0.554,9.086,4.472,11.5,9.113 c1.348,2.591,2.51,6.535,0.395,10.611c-0.254,0.49-0.063,1.093,0.426,1.348c0.49,0.254,1.095,0.063,1.351-0.427 c1.959-3.775,1.817-8.199-0.396-12.456c-2.731-5.251-8.203-9.53-13.012-10.172C138.853,125.257,135.763,126,133.446,127.979z" + }, + "stroke": { + } + } + ] + }, + { + "children": [ + { + "shape": { + "type": "path", + "path": "M154.077,146.278c-2.156,1.18-4.24,2.619-6.256,4.01c-3.636,2.509-7.068,4.878-10.941,5.924 c-2.991,0.808-6.055,1.058-9.3,1.324c-3.222,0.263-6.553,0.536-9.783,1.406c-2.027,0.546-4.117,1.397-6.137,2.221 c-3.491,1.423-7.102,2.895-10.528,2.866c-0.552-0.005-1.004,0.439-1.009,0.991c-0.005,0.552,0.439,1.004,0.991,1.009 c3.828,0.033,7.627-1.516,11.301-3.014c2.054-0.837,3.994-1.628,5.902-2.142c3.054-0.823,6.292-1.088,9.425-1.344 c3.191-0.261,6.492-0.531,9.659-1.386c4.205-1.135,7.94-3.714,11.557-6.208c1.973-1.362,4.014-2.771,6.08-3.901 c0.484-0.265,0.662-0.873,0.396-1.357C155.168,146.193,154.562,146.014,154.077,146.278z" + }, + "stroke": { + } + } + ] + }, + { + "children": [ + { + "shape": { + "type": "path", + "path": "M156.458,153.549c-2.619,0.064-5.709,0.812-8.98,1.604c-4.278,1.035-8.7,2.104-11.901,1.536 c-0.543-0.096-1.063,0.267-1.159,0.81c-0.097,0.544,0.267,1.063,0.81,1.16c3.613,0.641,8.24-0.481,12.72-1.562 c3.166-0.766,6.153-1.489,8.561-1.548c5.664-0.141,7.961,0.698,13.508,2.724c0.519,0.189,1.095-0.077,1.281-0.596 c0.189-0.519-0.076-1.091-0.596-1.282C165.069,154.337,162.501,153.399,156.458,153.549z" + }, + "stroke": { + } + } + ] + } + ] + } + ] + }, + { + "name": "textSurface", + "children": [ + { + "name": "spokenBubble", + "children": [ + { + "name": "textContainer", + "shape": { + "type": "path", + "path": "M225.719,45.307 c0-6.627,5.373-12,12-12h181.333c6.627,0,12,5.373,12,12v105.334c0,6.627-5.373,12-12,12H237.719c-6.627,0-12-5.373-12-12 V45.307z" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "name": "textArrowBelow", + "shape": { + "type": "path", + "path": "M249.052,160.64 c-0.774,14.251-1.676,18.525-9.1,30.565c9.705-0.79,21.952-21.605,25.1-30.045" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "thoughtBubble", + "children": [ + { + "name": "textContainer_1_", + "shape": { + "type": "path", + "path": "M202.698,21.089 c19.686-26.45,59.686-24.45,79.747-0.084c2.696,1.349,5.57,1.709,7.472,0.781c15.28-13.888,33.271-14.043,49.893-7.839 c2.771,1.034,5.479,2.219,8.031,3.421C376.384-4.36,423.384,6.64,431.007,45.026c0,0-1.324,3.889,1.165,6.603 c18.212,11.011,26.212,32.011,22.212,53.011c-1,5.333-3.223,9.667-6.037,13.52c-2.813,3.854-1.381,0-2.612-0.591 c-1.351-0.929-3.351-0.929-4.351-1.929c16,7,27,22,30,39c2,21-8,41-27,50c-16,7.5-32.5,5.5-45.745-2.556 c-2.531-1.384-4.229-1.856-5.336-1.551c-1.919,0.107-3.919,2.107-5.919,2.107c4-1,6-5,10-6c-15,11-35,12-52,3c-13-7-20-20-24-34 c1,5,3,9,3.299,13.505c-0.396,0.708-3.423,2.219-6.654,3.466c-22.627,8.729-49.423,1.729-65.241-19.971 c-3.453,0-6.263,0.589-8.723,0.879c-17.301,3.2-32.382-7.709-40.771-22.689c-1.678-2.996-3.089-6.153-4.195-9.396 c-15.714-7.795-29.714-18.795-33.714-37.795c-5-25,11-45,29.842-57.667c0.72-2.335,1.697-4.636,3.007-6.896 C201.159,23.307,202.698,21.089,202.698,21.089z" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "children": [ + { + "shape": { + "type": "path", + "path": "M269.719,186.307c0,4.602-4.179,8.333-9.333,8.333s-9.334-3.731-9.334-8.333 c0-4.603,4.18-8.333,9.334-8.333S269.719,181.705,269.719,186.307z" + }, + "fill": "#FFFFFF", + "stroke": { + } + }, + { + "children": [ + { + "shape": { + "type": "path", + "path": "M269.719,186.307c0,4.602-4.179,8.333-9.333,8.333s-9.334-3.731-9.334-8.333 c0-4.603,4.18-8.333,9.334-8.333S269.719,181.705,269.719,186.307z" + }, + "fill": "none", + "stroke": { + } + }, + { + "shape": { + "type": "path", + "path": "M268.225,186.166c-0.563,8.736-13.981,9.286-15.633,0.853 c-1.785-9.125,15.018-10.254,15.649-0.451c0.125,1.929,3.078,1.388,2.955-0.521c-0.814-12.597-20.828-12.412-21.64,0.119 c-0.827,12.813,20.831,13.028,21.655,0.283C271.337,184.519,268.35,184.235,268.225,186.166z" + }, + "fill": "#FFFFFF", + "stroke": { + } + } + ] + } + ] + }, + { + "shape": { + "type": "path", + "path": "M260.386,188.307c0,3.498-2.984,6.333-6.667,6.333 c-3.682,0-6.667-2.835-6.667-6.333s2.985-6.333,6.667-6.333C257.401,181.974,260.386,184.809,260.386,188.307z" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M238.386,196.974c0,1.289-1.045,2.333-2.334,2.333 c-1.288,0-2.333-1.045-2.333-2.333c0-1.288,1.045-2.333,2.333-2.333C237.341,194.64,238.386,195.685,238.386,196.974z" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M285.719,179.974c0,4.602-4.253,8.333-9.5,8.333 s-9.5-3.731-9.5-8.333c0-4.603,4.253-8.333,9.5-8.333S285.719,175.372,285.719,179.974z" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "yellBubble", + "children": [ + { + "shape": { + "type": "path", + "path": "M251.156,176.051l40.228-15.992" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "shape": { + "type": "path", + "path": "M280.932,149.385l-40.667,36.42" + }, + "fill": "none", + "stroke": { + "color": "#000000", + "cap": "round", + "join": "bevel" + } + }, + { + "name": "textContainer_2_", + "shape": { + "type": "path", + "path": "M217.778,34.644 c8.608,6.684,9.951,3.684,7.986-5.785c6.309,5.125,9.309,3.782,10.188-4.309c2.433,8.091,5.266,8.091,9.12-1.703 c6.063,9.793,13.146,9.793,24.043,3.878c6.103,5.915,16.02,5.915,20.094-4.64c17.178,10.555,28.511,10.555,45.233-5.505 c5.94,16.06,17.272,16.06,18.835,1.458c19.688,14.603,29.604,14.603,46.749-17.802c-0.145,32.405,6.938,32.405,29.26,16.182 c-12.403,16.223-9.57,16.223,4.813,6.576c-11.069,9.646-8.069,10.99,4.333,9.089c-8.061,6.244-6.717,9.244,2.533,11.068 c-9.25,1.489-9.25,5.703-0.314,13.07c-8.936,6.115-8.936,15.385,7.513,10.932c-16.447,24.677-16.447,35.631,14.938,36.553 c-31.385,19.303-31.385,28.571-4.39,40.526c-26.995,1.528-26.995,5.741-5.942,17.857c-21.053-8.801-22.396-5.802-9.525,11.916 c-17.213-13.374-20.213-12.03-12.048,8.029c-11.479-20.06-14.313-20.06-10.554,3.532c-13.676-23.591-20.759-23.591-29.813-2.664 c-7.944-20.927-17.861-20.927-27.072,12.467c-12.039-33.395-23.373-33.395-23.147-1.581 c-22.891-31.814-34.225-31.814-61.518-8.479c6.042-23.335-3.874-23.335-11.899-9.703c-8.976-13.632-16.059-13.632-23.927,4.361 c-2.049-17.993-4.882-17.993-10.51-1.486c2.314-16.508-0.686-17.851-12.385-5.019c7.355-17.175,6.013-20.176-10.271-7.879 c16.283-15.61,16.283-19.824-9.255-12.972c25.538-20.334,25.538-29.603,1.919-46.578c23.619-3.249,23.619-14.204-0.313-25.522 c23.933-8.905,23.933-18.175,7.798-37.429C226.385,48.854,226.385,44.641,217.778,34.644z" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + } + ] + } + ] + } + ] + } +] \ No newline at end of file diff --git a/includes/js/dojox/gfx/demos/data/LarsDreaming.svg b/includes/js/dojox/gfx/demos/data/LarsDreaming.svg new file mode 100644 index 0000000..3f4b903 --- /dev/null +++ b/includes/js/dojox/gfx/demos/data/LarsDreaming.svg @@ -0,0 +1,536 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/includes/js/dojox/gfx/demos/data/Nils.json b/includes/js/dojox/gfx/demos/data/Nils.json new file mode 100644 index 0000000..59e40cb --- /dev/null +++ b/includes/js/dojox/gfx/demos/data/Nils.json @@ -0,0 +1,717 @@ +[ + { + "name": "nils_1_", + "children": [ + { + "name": "lowerBody", + "children": [ + { + "name": "leftShoe", + "children": [ + { + "shape": { + "type": "path", + "path": "M44.787,442.042c13.536-0.097,28.515-2.647,40.667-8.815 c13.064-6.631,3.188-24.604,0.553-34.404c-5.771-1.73-10.549-4.837-16.568-0.148c-4.371,3.405-6.025,11.462-2.07,15.501 c-3.212,7.339-17.804,1.912-23.732,6.7c-5.825,4.706-7.32,17.966,0.484,21.167" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M133.453,425.375c0.901-2.979,2.793-5.781,4.667-8" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M56.787,426.708c-2.551-2.07-3.97-5.252-5.333-8" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "rightShoe", + "children": [ + { + "shape": { + "type": "path", + "path": "M111.453,402.042c-2.005-0.426-3.947-0.363-5.899-0.566 c-0.104,2.376,0.438,5.478,0.048,7.751c-0.4,2.327-1.597,4.06-2.146,6.817c-0.975,4.9,0.412,10.561,3.813,13.517 c3.718,3.23,8.442,2.56,12.87,3.797c4.256,1.189,7.959,3.502,12.5,4.849c9.169,2.717,20.433,7.657,25.649-4.685 c2.797-6.618-0.894-5.624-6.331-7.982c-4.049-1.757-6.774-4.353-10.32-7.014c-4.123-3.095-8.203-5.957-13.415-6.584 c-0.11-3.353,1.616-5.692,1.132-9.117c-5.299-2.318-13.883-3.984-19.233-0.116" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M62.787,424.708c-1.417-2.271-3.012-5.388-2.667-8.666" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M141.453,428.042c2.076-1.991,4.274-3.745,6-6" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "leftLeft", + "shape": { + "type": "path", + "path": "M111.687,360.891c0.036,4.747,1.844,9.223,1.56,14.078 c-0.24,4.099-1.372,8.075-1.553,12.199c-0.2,4.558-1.141,9.069-1.142,13.648c0,3.48-0.275,5.533,3.084,7.379 c2.301,1.264,4.909,1.163,7.094-0.113c2.993-1.748,2.841-3.747,2.868-6.904c0.025-2.952,0.712-5.943,1.162-8.841 c0.446-2.868,0.401-5.667,0.398-8.578c-0.004-3.788,0.138-7.556,0.003-11.357c-0.118-3.318-1.49-6.782-1.279-10.093" + }, + "fill": "#FFF0A9", + "stroke": { + "color": "#000000" + } + }, + { + "name": "rightLeg", + "shape": { + "type": "path", + "path": "M74.107,353.8c-0.57,1.485-0.055,3.729-0.142,5.357 c-0.076,1.44-0.315,2.774-0.571,4.184c-0.786,4.316-1,8.786-1.732,13.181c-1.158,6.942-0.906,14.193-1.777,21.167 c-0.456,3.648,0.862,8.169,5.499,7.139c2.579-0.572,4.859-3.016,5.846-5.361c2.937-6.981-0.974-13.832-0.457-21.057 c0.331-4.619,2.141-8.637,3.402-13.056c0.769-2.694,1.709-5.131,1.703-7.972c-0.004-1.809,0-3.616,0-5.425" + }, + "fill": "#FFF0A9", + "stroke": { + "color": "#000000" + } + }, + { + "name": "pants", + "children": [ + { + "name": "pants_1_", + "shape": { + "type": "path", + "path": "M72.453,299.375 c1.947,19.47-1.848,38.143-0.849,57.849c3.905,0.681,11.166,0.417,14.849-0.849c7.135-2.453,6.497-2.631,7-11 c0.81-13.479-2.849-20.278,12.845-17.853c-1.125,13.305-9.43,25.115-3.42,38.649c8.404-0.38,20.265,0.661,28.427-1.944 c0.505-10.198-1.523-17.622-2.853-26.853c-1.398-9.708,3.313-18.866-1.174-27.826c-9.218,0.693-18.358,2.747-27.722,0.798 c-9.863-2.054-18.89-8.623-29.104-8.972" + }, + "fill": "#ADA274", + "stroke": { + "color": "#000000" + } + } + ] + } + ] + }, + { + "name": "leftArm_1_", + "children": [ + { + "name": "leftArm", + "shape": { + "type": "path", + "path": "M161.453,199.375c-6.73,0.606-12.711,7.192-9.248,13.248 c3.358,5.87,13.618,5.538,19.021,6.979c4,1.066,16.837,3.192,19.52,5.703c3.974,3.72,5.243,15.844,5.854,20.924 c13.641,4.354,26.949-0.671,33.102-13.826c5.331-11.398-5.783-19.505-17.098-22.174c1.771-8.465,14.167-32.061-0.128-36.899 c-4.761-1.611-15.726,3.346-17.801,7.272c-3.095,5.855-0.055,15.902-0.374,22.623c-13.399,0.68-27.351-3.555-39.849-1.849" + }, + "fill": "#FFF0A9", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M221.453,220.375c-4.604-1.889-17.369-6.456-21.801-1.801 c-4.797,5.039,1.256,14.077,6.027,16.578c4.118,2.159,20.628,4.348,24.575,1c4.999-4.241,2.906-14.993-2.801-17.777" + }, + "fill": "#FFF0A9", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M214.453,253.375c-1.006,3.482-0.767,9-3.174,12.826 c-15.878,0.834-16.244-5.43-25.674-14.571c10.53-5.253,19.583,4.754,29.849,2.745" + }, + "fill": "#FFF0A9", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M226.453,239.375c0.54,16.962-8.377,15.391-21.023,12.023 c-17.34-4.617-11.577-7.176,3.023-13.023" + }, + "fill": "#FFF0A9", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M208.453,188.375c-4.474,0.83-8.972-0.434-11-4" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M203.453,221.375c6.112-0.45,18.967,6.649,8,10" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M195.453,258.375c3.441-0.666,5.408-2.2,4-5" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "rightArm", + "children": [ + { + "shape": { + "type": "path", + "path": "M39.453,187.375c-3.104,7.216-3.137,14.998-7.278,21.997 c-5.137,8.684-9.794,6.9-17.5,12.281c-8.803,6.146-12.141,29.697-14.095,40.548c20.2,3.536,18.779-23.776,21.649-34.524 c0.975,13.012-0.289,26.468,0.374,39.546c2.257,0.582,6.44,0.582,8.697,0c2.04-10.494-3.53-22.034-0.852-33.546 c0.009,7.58-2.598,32.2,10.852,28.546c0.514-10.124-1.899-18.938-4.868-25.972c2.181,8.766,4.798,18.48,15.845,15.949 c6.407-12.781-3.909-15.105-8.048-25.604c-2.531-6.422,0.527-25.44,6.223-31.223" + }, + "fill": "#FFF0A9", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M6.453,248.042c2.111,0,6.324-0.997,6.667,1.666" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M22.453,255.375c2.85-0.37,4.155,0.539,4.999,3.001 c1.085,3.168-0.233,4.173-2.999,5.332" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M31.787,255.042c3.675-0.503,7.077,4.971,3,6" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M48.453,235.708c-5.387-0.935-3.676,10.551,3.667,8.667" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M207.453,241.375c2.63,1.686,2.368,4.909,1.884,7.884 c-0.744,0.175-1.23,0.456-1.884,0.783" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "shirt", + "children": [ + { + "name": "mainShirt", + "shape": { + "type": "path", + "path": "M39.453,189.375 c0.777-3.467,1.211-7.217,1.151-10.849c14.871-1.403,32.372-7.656,46.875-11.125c9.423-2.254,31.959-20.14,39.244-11.079 c3.778,4.7,2.066,16.102,5.456,22.08c2.827,4.986,9.093,12.445,13.003,16.217c5.193,5.009,15.695-3.271,18.271,2.754 c3.024,7.075-0.511,20.739-10.02,18.016c-5.084-1.456-12.238-5.093-15.228-9.769c-4.055-6.341-8.831-13.012-10.53-19.167 c-0.713,10.697,1.173,22.369,2.726,32.92c1.637,11.128,1.886,22.261,3.052,34c2.02,20.336,6.915,42.053,10.845,61.855 c-14.599,4.091-47.868-3.832-47.868-3.832s-14.457-3.595-21.2-5.801c-8.131-2.661-21.777-11.223-13.777-11.223 s-3.063-9.756,2.468-40.878s14.003-39.61,19.806-56.122c1.387-3.946,2.399-8.004,4.375-11.845 c-17.565,1.273-26.117,7.964-40.475,16.742c-2.413-9.11-9.707-14.336-17.174-18.897" + }, + "fill": "#4867FF", + "stroke": { + "color": "#000000", + "width": "2" + } + }, + { + "name": "highlight", + "shape": { + "type": "path", + "path": "M99.453,179.375 c-5.364,2.937-10.603,8.065-17,8" + }, + "fill": "#4867FF", + "stroke": { + "color": "#000000", + "width": "2" + } + }, + { + "name": "logo", + "children": [ + ] + } + ] + }, + { + "name": "heads", + "children": [ + { + "name": "head1", + "children": [ + { + "name": "hair_1_", + "shape": { + "type": "path", + "path": "M60.453,97.375c-3.965-0.012-7.98,0.045-11.897-0.147 c2.645-5.735,10.791-8.417,14.794-13.65c-2.384,0.19-5.083-0.61-7.543-0.154c2.395-1.359,4.008-3.487,6.347-4.846 c-2.993-0.207-6.326-0.467-9.399-0.18c2.893-0.874,5.243-2.063,7.821-3.05c-0.92-0.166-4.625-2.732-6.772-4.221 c5.187-4.255,12.317-5.834,17.573-8.534c-2.844-0.13-5.037-1.713-7.75-2.393c-0.424-7.244-1.302-14.461-1.223-21.475 c2.166,2.761,3.541,5.976,4.849,8.546c-0.996-11.489,4.773-13.594,13.025-18.797c0.403,1.91,1.943,3.845,2.229,5.546 c1.27-13.312,22.924-28.644,34.016-33.272c0.039,6.247-2.955,11.957-5.365,17.475c-0.365,0.375-0.375,0.366-0.028-0.028 c5.849-6.92,14-8.882,22.143-10.721c-1.215,5.635-5.28,10.684-6.698,16.602c6.258-10.069,20.421-4.135,27.949-11.351 c-1.011,3.251-2.028,6.254-3.143,9.276c7.035-8.774,15.902-11.37,25.894-14.499c-0.668,7.995-10.243,18.061-0.822,20.872 c8.889,2.653,17.435-7.31,26.698-6.075c-2.976,1.954-5.822,4.12-8.614,6.345c7.596,2.01,18.243,0.852,26.614,0.658 c-4.125,3.304-9.116,7.352-9.593,12.943c3.896-0.826,8.6-1.318,12.741-0.725c-1.013,1.726-1.479,5.845-2.718,7.678 c3.136-0.265,6.17,1.053,8.519,1.452c-3.019,0.804-5.247,3.16-7.566,4.52c3.765,0.755,7.282,2.001,10.844,3.398 c-3.322,1.78-5.724,5.475-4.776,9.657c0.798,0.374,2.536,0.977,2.995,1.147c-6.481,3.645-21.331-1.522-28.945-2.752 c-13.967-2.257-27.844-4.641-41.913-6.244c-17.039-1.941-37.716-3.446-54.359,1.025C83.983,67.42,68.871,76.651,58.453,98.375" + }, + "fill": "#605542", + "stroke": { + "color": "#000000" + } + }, + { + "name": "neck", + "shape": { + "type": "path", + "path": "M108.453,132.375c0.902,8.412-0.835,20.235-3.849,27.797 c4.164,2.769,15.721,4.339,19.868,0c3.538-3.701,1.964-17.522,1.98-22.797" + }, + "fill": "#FFF0A9", + "stroke": { + "color": "#000000" + } + }, + { + "name": "leftEar_1_", + "children": [ + { + "name": "leftEar", + "shape": { + "type": "path", + "path": "M232.453,76.375c10.186-6.915,21.465,6.994,19.052,17 c-2.781,11.53-20.253,15.518-27.052,5" + }, + "fill": "#FFF0A9", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M245.453,91.375c-0.398-2.267-1.99-4.77-3.171-6.829 c-2.738-0.936-5.713-1.545-8.829-1.171" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M238.453,90.375c1.863-0.367,3.589-1.433,5-3" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "headShape", + "shape": { + "type": "path", + "path": "M116.453,35.375 c-13.417,2.219-31.83,24.639-39.777,35.055c-8.128,10.652-24.737,25.747-20.219,39.945 c5.161,16.221,22.089,14.526,34.025,19.972c15.448,7.047,30.645,11.875,46.749,14.251c18.146,2.676,27.633,0.161,44.223-7.972 c15.701-7.697,29.862-9.589,41.801-24.303c8.182-10.084,15.033-28.733,8.174-38.923c-6.159-9.151-21.79-19.289-31.201-25.75 c-12.144-8.339-26.876-10.032-41-11.274c-15.007-1.32-33.207-3.056-47.774,1" + }, + "fill": "#FFF0A9", + "stroke": { + "color": "#000000" + } + }, + { + "name": "rightEar_1_", + "children": [ + { + "name": "rightEar", + "shape": { + "type": "path", + "path": "M66.453,94.375 c-10.188-4.124-23.701-5.729-27.774,7.226c-4.779,15.198,14.506,23.077,25.774,15.774" + }, + "fill": "#FFF0A9", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M42.453,106.375c4.149-4.954,11.06-7.737,16-10" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M48.453,100.375c1.337,3.541,2.787,6.955,5,10" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "adamsApple", + "shape": { + "type": "path", + "path": "M113.453,152.375c-0.526-2.327,1.546-3.837,5-4" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + } + ] + } + ] + }, + { + "name": "expressions", + "children": [ + { + "name": "confused", + "children": [ + { + "name": "mouth_1_", + "children": [ + { + "name": "mouth", + "shape": { + "type": "path", + "path": "M102.148,120.014c13.398-6.9,33.568-7.688,49-10.026 c12.555-1.903,36.519-2.575,44,9.026" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "name": "tooth_1_", + "shape": { + "type": "path", + "path": "M178.148,109.014 c-0.563-2.655-0.017-6.196,0.151-8.849c4.788-0.944,9.637,0.768,13.675,3.022c0.664,3.187,0.065,6.267-1.826,8.826" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "name": "tooth", + "shape": { + "type": "path", + "path": "M168.148,108.014c-2.021-7.958,5.04-7.752,10.826-6.826 c1.286,2.446,1.752,5.863,1.022,8.675c-3.801,0.292-8.049,0.308-10.849-0.849" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "eyes", + "children": [ + { + "name": "rightEye", + "shape": { + "type": "path", + "path": "M121.148,52.014 c-6.562,8.145-20.057,16.28-21.023,26.977c-1.104,12.227,10.759,15.164,21.02,11.798c18.8-6.168,24.482-40.499,0.004-39.774" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "name": "pupilRight", + "shape": { + "type": "path", + "path": "M112.148,61.014c-7.625,3.067-4.047,12.428,3.826,10.826 C118.354,67.432,118.046,61.261,112.148,61.014" + }, + "stroke": { + "color": "#000000" + } + }, + { + "name": "leftEye", + "shape": { + "type": "path", + "path": "M184.148,55.014c-13.391-8.758-17.664,28.504,5,25.996 c10.862-1.201,14.124-12.581,8.004-19.996c-6.121-7.415-14.988-4.947-22.004-8" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "name": "pupilLeft", + "shape": { + "type": "path", + "path": "M176.148,54.014c-2.04,2.896-2.657,6.347-1.849,9.849 C184.707,66.621,182.108,56.322,176.148,54.014" + }, + "stroke": { + "color": "#000000" + } + } + ] + } + ] + }, + { + "name": "confused2", + "children": [ + { + "name": "rightEye_1_", + "shape": { + "type": "path", + "path": "M121.148,52.014 c-6.562,8.145-20.057,16.28-21.023,26.977c-1.104,12.227,10.759,15.164,21.02,11.798c18.8-6.168,24.482-40.499,0.004-39.774" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "name": "pupilRight_1_", + "shape": { + "type": "path", + "path": "M112.148,61.014 c-7.625,3.067-4.047,12.428,3.826,10.826C118.354,67.432,118.046,61.261,112.148,61.014" + }, + "stroke": { + "color": "#000000" + } + }, + { + "name": "leftEye_1_", + "shape": { + "type": "path", + "path": "M184.148,55.014 c-13.391-8.758-17.664,28.504,5,25.996c10.862-1.201,14.124-12.581,8.004-19.996c-6.121-7.415-14.988-4.947-22.004-8" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "name": "pupilLeft_1_", + "shape": { + "type": "path", + "path": "M176.148,54.014 c-2.04,2.896-2.657,6.347-1.849,9.849C184.707,66.621,182.108,56.322,176.148,54.014" + }, + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M114.934,118.74 c18.933-4.896,31.704-2.456,49.826,1.171c6.734,1.348,17.654,7.566,23.408,0.323c5.436-6.841-0.011-16.179-7.237-17.994" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "talking", + "children": [ + { + "shape": { + "type": "path", + "path": "M150.536,116.479c0.413,18.115,48.746,18.222,37.276-7.278 c-10.396-1.757-28.836,2.451-38.776,5.778" + }, + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M103.453,104.875c-2.277,2.169-1.729,7.324-4.849,8 c8.889,3.074,18.975,7.877,28.849,6.998c6.759-0.602,18.439-1.511,23.5-5.998" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M104.453,64.875 c-6.218-0.224-17.093,9.247-13.875,15.887c2.822,5.825,15.087,4.174,20.375,3.113c4.505-0.904,7.783-1.37,9.889-6.123 c1.107-2.499,2.855-9.088,1.623-11.889c-2.859-6.496-15.374-3.248-19.512,0.012" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M176.953,59.875 c-4.742,8.403,0.46,13.596,6.486,18.376c4.779,3.791,15.903,8.529,19.512,0.622c8.012-17.554-22.026-19.554-32.498-17.887 c-0.345,0.055-1.151,0.291-1.5,0.389" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M98.953,66.875c-6.969-2.545-10.165,5.418-3.002,8.05 c2.178-2.129,5.596-6.88,2.502-9.05" + }, + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M178.453,60.875c-5.534,0.708-5.259,9.173,0.5,7.387 c6.145-1.906,5.217-9.047-1.5-8.387" + }, + "stroke": { + "color": "#000000" + } + } + ] + }, + { + "name": "talking2", + "children": [ + { + "shape": { + "type": "path", + "path": "M102.87,94.503c-2.279,15.037-5.934,27.828,15.027,23.027 c15.334-3.512,25.379-13.239,28.973-28.027" + }, + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M92.87,104.503 c4.248-16.004,34.717-10.765,47.052-11.948c8.414-0.807,15.879-1.97,24.948-1.055c8.295,0.837,19.3,2.941,27-0.997" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M84.87,73.503c2.341-8.752,12.467-12.772,19-18" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M181.87,59.503c8.968-3.27,16.681,2.245,25,3" + }, + "fill": "none", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M98.87,68.503 c-7.218,11.165,3.031,17.234,13.003,17.997c13.201,1.009,21.125-8.677,18.845-21.842c-11.637-0.604-21.219,1.818-31.849,2.845" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M178.87,67.503 c-9.045,2.007-6.264,11.616-1.249,15.249c3.778,2.737,13.479,4.477,18.249,2.528C210.946,79.123,185.327,71.038,178.87,67.503" + }, + "fill": "#FFFFFF", + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M115.87,85.503c2.365-1.63,3.646-3.553,2.826-6.826 c-16.491-8.159-17.436,11.182-1.826,8.826" + }, + "stroke": { + "color": "#000000" + } + }, + { + "shape": { + "type": "path", + "path": "M174.87,80.503c-0.492-1.165-0.677-2.687-0.872-3.826 c3.483-0.285,7.207-0.292,10.698-0.023c3.568,7.301-6.079,7.593-10.826,5.849" + }, + "stroke": { + "color": "#000000" + } + } + ] + } + ] + } + ] + } +] \ No newline at end of file diff --git a/includes/js/dojox/gfx/demos/data/Nils.svg b/includes/js/dojox/gfx/demos/data/Nils.svg new file mode 100644 index 0000000..48908a2 --- /dev/null +++ b/includes/js/dojox/gfx/demos/data/Nils.svg @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/includes/js/dojox/gfx/demos/data/buratino-bg.png b/includes/js/dojox/gfx/demos/data/buratino-bg.png new file mode 100644 index 0000000..ee50a15 Binary files /dev/null and b/includes/js/dojox/gfx/demos/data/buratino-bg.png differ diff --git a/includes/js/dojox/gfx/demos/data/buratino-head.png b/includes/js/dojox/gfx/demos/data/buratino-head.png new file mode 100644 index 0000000..d576873 Binary files /dev/null and b/includes/js/dojox/gfx/demos/data/buratino-head.png differ diff --git a/includes/js/dojox/gfx/demos/data/buratino-left-arm.png b/includes/js/dojox/gfx/demos/data/buratino-left-arm.png new file mode 100644 index 0000000..1e620f3 Binary files /dev/null and b/includes/js/dojox/gfx/demos/data/buratino-left-arm.png differ diff --git a/includes/js/dojox/gfx/demos/data/buratino-left-leg.png b/includes/js/dojox/gfx/demos/data/buratino-left-leg.png new file mode 100644 index 0000000..1ae5600 Binary files /dev/null and b/includes/js/dojox/gfx/demos/data/buratino-left-leg.png differ diff --git a/includes/js/dojox/gfx/demos/data/buratino-lollipop.png b/includes/js/dojox/gfx/demos/data/buratino-lollipop.png new file mode 100644 index 0000000..9a52c1e Binary files /dev/null and b/includes/js/dojox/gfx/demos/data/buratino-lollipop.png differ diff --git a/includes/js/dojox/gfx/demos/data/buratino-nose-large.png b/includes/js/dojox/gfx/demos/data/buratino-nose-large.png new file mode 100644 index 0000000..a0e38fd Binary files /dev/null and b/includes/js/dojox/gfx/demos/data/buratino-nose-large.png differ diff --git a/includes/js/dojox/gfx/demos/data/buratino-nose-medium.png b/includes/js/dojox/gfx/demos/data/buratino-nose-medium.png new file mode 100644 index 0000000..f38e205 Binary files /dev/null and b/includes/js/dojox/gfx/demos/data/buratino-nose-medium.png differ diff --git a/includes/js/dojox/gfx/demos/data/buratino-right-arm.png b/includes/js/dojox/gfx/demos/data/buratino-right-arm.png new file mode 100644 index 0000000..206bdb1 Binary files /dev/null and b/includes/js/dojox/gfx/demos/data/buratino-right-arm.png differ diff --git a/includes/js/dojox/gfx/demos/data/buratino-right-leg.png b/includes/js/dojox/gfx/demos/data/buratino-right-leg.png new file mode 100644 index 0000000..cd0e172 Binary files /dev/null and b/includes/js/dojox/gfx/demos/data/buratino-right-leg.png differ diff --git a/includes/js/dojox/gfx/demos/data/buratino-torso.png b/includes/js/dojox/gfx/demos/data/buratino-torso.png new file mode 100644 index 0000000..64c2336 Binary files /dev/null and b/includes/js/dojox/gfx/demos/data/buratino-torso.png differ diff --git a/includes/js/dojox/gfx/demos/data/buratino.jpg b/includes/js/dojox/gfx/demos/data/buratino.jpg new file mode 100644 index 0000000..95aaf05 Binary files /dev/null and b/includes/js/dojox/gfx/demos/data/buratino.jpg differ diff --git a/includes/js/dojox/gfx/demos/data/buratino.json b/includes/js/dojox/gfx/demos/data/buratino.json new file mode 100644 index 0000000..45ed668 --- /dev/null +++ b/includes/js/dojox/gfx/demos/data/buratino.json @@ -0,0 +1,12 @@ +[ + {name: "bg", shape: {type: "image", width: 321, height: 355, src: "data/buratino-bg.png"}}, + {name: "left-arm", shape: {type: "image", width: 111, height: 40, src: "data/buratino-left-arm.png"}}, + {name: "right-arm", shape: {type: "image", width: 59, height: 130, src: "data/buratino-right-arm.png"}}, + {name: "left-leg", shape: {type: "image", width: 152, height: 99, src: "data/buratino-left-leg.png"}}, + {name: "right-leg", shape: {type: "image", width: 104, height: 158, src: "data/buratino-right-leg.png"}}, + {name: "torso", shape: {type: "image", width: 90, height: 130, src: "data/buratino-torso.png"}}, + {name: "head", shape: {type: "image", width: 116, height: 139, src: "data/buratino-head.png"}}, + {name: "nose-medium", shape: {type: "image", width: 50, height: 43, src: "data/buratino-nose-medium.png"}}, + {name: "nose-large", shape: {type: "image", width: 70, height: 66, src: "data/buratino-nose-large.png"}}, + {name: "lollipop", shape: {type: "image", width: 82, height: 144, src: "data/buratino-lollipop.png"}} +] diff --git a/includes/js/dojox/gfx/demos/data/svg2gfx.xsl b/includes/js/dojox/gfx/demos/data/svg2gfx.xsl new file mode 100644 index 0000000..90a463f --- /dev/null +++ b/includes/js/dojox/gfx/demos/data/svg2gfx.xsl @@ -0,0 +1,72 @@ + + + + + + + + fill: " + + ", + + + + + stroke: { + + color: " + + ", + + + width: " + + ", + + + cap: " + + ", + + + join: " + + ", + + }, + + + { + + name: " + + ", + + children: [ + + ]}, + + + { + + name: " + + ", + + shape: {type: "path", path: " + + "}, + + + + + + + }, + + + [ + + ] + + diff --git a/includes/js/dojox/gfx/demos/data/transform.json b/includes/js/dojox/gfx/demos/data/transform.json new file mode 100644 index 0000000..60bd466 --- /dev/null +++ b/includes/js/dojox/gfx/demos/data/transform.json @@ -0,0 +1,1567 @@ +[ + { + "children": [ + { + "shape": { + "type": "line", + "x1": 0, + "y1": 0, + "x2": 500, + "y2": 0 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 0, + "y1": 0, + "x2": 0, + "y2": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 0, + "y1": 50, + "x2": 500, + "y2": 50 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 50, + "y1": 0, + "x2": 50, + "y2": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 0, + "y1": 100, + "x2": 500, + "y2": 100 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 100, + "y1": 0, + "x2": 100, + "y2": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 0, + "y1": 150, + "x2": 500, + "y2": 150 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 150, + "y1": 0, + "x2": 150, + "y2": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 0, + "y1": 200, + "x2": 500, + "y2": 200 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 200, + "y1": 0, + "x2": 200, + "y2": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 0, + "y1": 250, + "x2": 500, + "y2": 250 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 250, + "y1": 0, + "x2": 250, + "y2": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 0, + "y1": 300, + "x2": 500, + "y2": 300 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 300, + "y1": 0, + "x2": 300, + "y2": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 0, + "y1": 350, + "x2": 500, + "y2": 350 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 350, + "y1": 0, + "x2": 350, + "y2": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 0, + "y1": 400, + "x2": 500, + "y2": 400 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 400, + "y1": 0, + "x2": 400, + "y2": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 0, + "y1": 450, + "x2": 500, + "y2": 450 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 450, + "y1": 0, + "x2": 450, + "y2": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 0, + "y1": 500, + "x2": 500, + "y2": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + }, + { + "shape": { + "type": "line", + "x1": 500, + "y1": 0, + "x2": 500, + "y2": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + } + } + ], + "name": "grid" + }, + { + "children": [ + { + "shape": { + "type": "rect", + "x": 0, + "y": 0, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 0, + "y": 100, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 0, + "y": 200, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 0, + "y": 300, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 0, + "y": 400, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 50, + "y": 50, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 50, + "y": 150, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 50, + "y": 250, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 50, + "y": 350, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 50, + "y": 450, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 100, + "y": 0, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 100, + "y": 100, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 100, + "y": 200, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 100, + "y": 300, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 100, + "y": 400, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 150, + "y": 50, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 150, + "y": 150, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 150, + "y": 250, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 150, + "y": 350, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 150, + "y": 450, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 200, + "y": 0, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 200, + "y": 100, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 200, + "y": 200, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 200, + "y": 300, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 200, + "y": 400, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 250, + "y": 50, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 250, + "y": 150, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 250, + "y": 250, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 250, + "y": 350, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 250, + "y": 450, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 300, + "y": 0, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 300, + "y": 100, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 300, + "y": 200, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 300, + "y": 300, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 300, + "y": 400, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 350, + "y": 50, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 350, + "y": 150, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 350, + "y": 250, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 350, + "y": 350, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 350, + "y": 450, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 400, + "y": 0, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 400, + "y": 100, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 400, + "y": 200, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 400, + "y": 300, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 400, + "y": 400, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 450, + "y": 50, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 450, + "y": 150, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 450, + "y": 250, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 450, + "y": 350, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + }, + { + "shape": { + "type": "rect", + "x": 450, + "y": 450, + "width": 50, + "height": 50, + "r": 0 + }, + "fill": { + "g": 0, + "b": 0, + "a": 0.1, + "r": 255 + } + } + ], + "name": "checkerboard" + }, + { + "shape": { + "type": "rect", + "x": 0, + "y": 0, + "width": 100, + "height": 100, + "r": 0 + }, + "transform": { + "dx": 100, + "dy": 100, + "xx": 1, + "xy": 0, + "yx": 0, + "yy": 1 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + }, + "fill": { + "type": "linear", + "x1": 0, + "y1": 0, + "x2": 100, + "y2": 100, + "colors": [ + { + "offset": 0, + "color": { + "r": 0, + "g": 128, + "b": 0, + "a": 1 + } + }, + { + "offset": 0.5, + "color": { + "g": 0, + "b": 0, + "r": 255, + "a": 1 + } + }, + { + "offset": 1, + "color": { + "r": 0, + "g": 0, + "b": 255, + "a": 1 + } + } + ] + }, + "name": "rect with color gradient" + }, + { + "shape": { + "type": "rect", + "x": 0, + "y": 0, + "width": 100, + "height": 100, + "r": 0 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + }, + "fill": { + "type": "linear", + "x1": 0, + "y1": 0, + "x2": 100, + "y2": 100, + "colors": [ + { + "offset": 0, + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + } + }, + { + "offset": 1, + "color": { + "r": 255, + "g": 255, + "b": 255, + "a": 1 + } + } + ] + }, + "name": "rect with gray gradient" + }, + { + "children": [ + { + "shape": { + "type": "rect", + "x": 200, + "y": 200, + "width": 100, + "height": 100, + "r": 0 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + }, + "fill": { + "r": 0, + "g": 128, + "b": 0, + "a": 1 + }, + name: "green rect" + }, + { + "shape": { + "type": "rect", + "x": 0, + "y": 0, + "width": 100, + "height": 100, + "r": 0 + }, + "transform": { + "xx": 0.8660254037844387, + "xy": 0.49999999999999994, + "yx": -0.49999999999999994, + "yy": 0.8660254037844387, + "dx": 281.69872981077805, + "dy": 231.69872981077808 + }, + "fill": { + "r": 0, + "g": 0, + "b": 255, + "a": 1 + }, + name: "blue rect" + }, + { + "shape": { + "type": "path", + "path": "M 300 100L 400 200L 400 300L 300 400C 400 300 400 200 300 100" + }, + "transform": { + "xx": 1, + "xy": 0, + "yx": 0, + "yy": 1, + "dx": 0, + "dy": 0 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + }, + "style": "solid", + "width": 1, + "cap": "butt", + "join": 4 + }, + name: "black path" + }, + { + "shape": { + "type": "path", + "path": "M 300 100L 400 200L 400 300L 300 400C 400 300 400 200 300 100" + }, + "transform": { + "dx": 100, + "xx": 1, + "xy": 0, + "yx": 0, + "yy": 1, + "dy": 0 + }, + "stroke": { + "type": "stroke", + "color": { + "g": 0, + "b": 0, + "r": 255, + "a": 1 + }, + "style": "solid", + "width": 2, + "cap": "butt", + "join": 4 + }, + name: "red path" + }, + { + "shape": { + "type": "path", + "path": "M 300 100l 100 100l 0 100l-100 100c 100-100 100-200 0-300" + }, + "transform": { + "xx": -1, + "xy": -1.2246063538223773e-16, + "yx": 1.2246063538223773e-16, + "yy": -1, + "dx": 500, + "dy": 500 + }, + "stroke": { + "type": "stroke", + "color": { + "r": 0, + "g": 0, + "b": 255, + "a": 1 + }, + "style": "solid", + "width": 2, + "cap": "butt", + "join": 4 + }, + name: "blue path" + } + ], + "transform": { + "xx": 0.9659258262890683, + "xy": 0.25881904510252074, + "yx": -0.25881904510252074, + "yy": 0.9659258262890683, + "dx": -56.1862178478973, + "dy": 73.22330470336311 + }, + "name": "rotated group" + } +] diff --git a/includes/js/dojox/gfx/demos/images/clock_face.jpg b/includes/js/dojox/gfx/demos/images/clock_face.jpg new file mode 100644 index 0000000..12f1903 Binary files /dev/null and b/includes/js/dojox/gfx/demos/images/clock_face.jpg differ diff --git a/includes/js/dojox/gfx/demos/images/clock_face_black.jpg b/includes/js/dojox/gfx/demos/images/clock_face_black.jpg new file mode 100644 index 0000000..dbef7cd Binary files /dev/null and b/includes/js/dojox/gfx/demos/images/clock_face_black.jpg differ diff --git a/includes/js/dojox/gfx/demos/inspector.html b/includes/js/dojox/gfx/demos/inspector.html new file mode 100644 index 0000000..034fa3b --- /dev/null +++ b/includes/js/dojox/gfx/demos/inspector.html @@ -0,0 +1,165 @@ + + +Inspect DojoX GFX JSON + + + + + + + +

      Inspect DojoX GFX JSON

      +

      Help: load a file, select an object, and add it, move it around, or apply operations to selected items:
      + F — bring to front, B — bring to back, Q — rotate CCW, W — rotate CW, D — delete.
      + (all operations work on currently dragged item).

      +

      VML note: VML doesn't process PNG images with opacity correctly.

      + + + +
      + + + + + + + + + + + + + +
      Source:
       
      +  
      Available sources:
      data/Lars.json — vectors from SVG
      data/Nils.json — vectors from SVG
      data/LarsDreaming.json — vectors from SVG
      data/buratino.json — images
      data/transform.json — from dojox.gfx
       
      Objects:
      Object names are hierarchical and separated by "/". Adding a selected object creates a group for this object. + A higher-level object (a group) always includes lower-level objects as children.
      + + diff --git a/includes/js/dojox/gfx/demos/lion.html b/includes/js/dojox/gfx/demos/lion.html new file mode 100644 index 0000000..445945c --- /dev/null +++ b/includes/js/dojox/gfx/demos/lion.html @@ -0,0 +1,235 @@ + + +dojox.gfx: Lion + + + + + + + + + + + + + +

      dojox.gfx: Lion

      +

      This example was directly converted from SVG file.

      + + + + + +
      Rotation (0)
      +
      +
      +
      +
      +
      +
      Scaling (1.000)
      +
      +
      +
      +
      +
      +
      + + diff --git a/includes/js/dojox/gfx/demos/roundedPane.html b/includes/js/dojox/gfx/demos/roundedPane.html new file mode 100644 index 0000000..4abb775 --- /dev/null +++ b/includes/js/dojox/gfx/demos/roundedPane.html @@ -0,0 +1,191 @@ + + + + + rounded skeleton page | The Dojo Toolkit + + + + + + + + + + +

      Some gfx + ContentPane's

      + +
      +

      YO!

      +

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      lorem

      +
      + +
      + LOREM, ipsum, dollllllllllor: + .roundedContent { + padding: 31px; + font-family: 'Tahoma'; + font-size: 12px; + color:#fff; + }

      .roundedContent { + padding: 31px; + font-family: 'Tahoma'; + font-size: 12px; + color:#fff; + }

      .roundedContent { + padding: 31px; + font-family: 'Tahoma'; + font-size: 12px; + color:#fff; + }

      .roundedContent { + padding: 31px; + font-family: 'Tahoma'; + font-size: 12px; + color:#fff; + }

      .roundedContent { + padding: 31px; + font-family: 'Tahoma'; + font-size: 12px; + color:#fff; + }

      .roundedContent { + padding: 31px; + font-family: 'Tahoma'; + font-size: 12px; + color:#fff; + }

      .roundedContent { + padding: 31px; + font-family: 'Tahoma'; + font-size: 12px; + color:#fff; + }

      .roundedContent { + padding: 31px; + font-family: 'Tahoma'; + font-size: 12px; + color:#fff; + }

      .roundedContent { + padding: 31px; + font-family: 'Tahoma'; + font-size: 12px; + color:#fff; + }

      .roundedContent { + padding: 31px; + font-family: 'Tahoma'; + font-size: 12px; + color:#fff; + }

      .roundedContent { + padding: 31px; + font-family: 'Tahoma'; + font-size: 12px; + color:#fff; + }

      .roundedContent { + padding: 31px; + font-family: 'Tahoma'; + font-size: 12px; + color:#fff; + }

      + +
      + + +
      +

      Moveable Handle

      + LOREM, ipsum, dollllllllllor: +
      + + +
      + lorem ipsum (small moveable) +
      + + + diff --git a/includes/js/dojox/gfx/demos/tiger.html b/includes/js/dojox/gfx/demos/tiger.html new file mode 100644 index 0000000..afb45ef --- /dev/null +++ b/includes/js/dojox/gfx/demos/tiger.html @@ -0,0 +1,566 @@ + + +dojox.gfx: Tiger + + + + + + + + +

      dojox.gfx: Tiger

      +

      This example was directly converted from SVG file.

      + + + + + +
      Rotation (0)
      +
      +
      +
      +
      +
      +
      Scaling (1.000)
      +
      +
      +
      +
      +
      +
      + + diff --git a/includes/js/dojox/gfx/demos/tooltip.html b/includes/js/dojox/gfx/demos/tooltip.html new file mode 100644 index 0000000..96bb694 --- /dev/null +++ b/includes/js/dojox/gfx/demos/tooltip.html @@ -0,0 +1,238 @@ + + + A Sample ToolTip using dijit and dojox.gfx + + + + + + + + + +

      dojox.gfx: A Sample tooltip

      + +
        + + + +
      • + Tooltip + Button +

        Canvas renderer doesn't implement event handling. + +

        +
      • + + +
      • + Hover trigger / persists +
        Canvas renderer doesn't implement event handling.
        +
      • + + +
      • MultiTip trigger 1
      • +
      • I do nothing
      • +
      • Trigger two
      • + +
      • show this way + + +
      • + + +
      • + Parent Attached Tooltip +
        +
        +

        + Name:

        + Pass:
        +

        +
        +
        +
      • + +
      + + +
      Canvas renderer doesn't implement event handling. (shared tooltip)
      + + + diff --git a/includes/js/dojox/gfx/fx.js b/includes/js/dojox/gfx/fx.js new file mode 100644 index 0000000..2b576d6 --- /dev/null +++ b/includes/js/dojox/gfx/fx.js @@ -0,0 +1,281 @@ +if(!dojo._hasResource["dojox.gfx.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.fx"] = true; +dojo.provide("dojox.gfx.fx"); + +dojo.require("dojox.gfx.matrix"); + +(function(){ + var d = dojo, g = dojox.gfx, m = g.matrix; + + // Generic interpolators. Should they be moved to dojox.fx? + + var InterpolNumber = function(start, end){ + this.start = start, this.end = end; + }; + d.extend(InterpolNumber, { + getValue: function(r){ + return (this.end - this.start) * r + this.start; + } + }); + + var InterpolUnit = function(start, end, unit){ + this.start = start, this.end = end; + this.unit = unit; + }; + d.extend(InterpolUnit, { + getValue: function(r){ + return (this.end - this.start) * r + this.start + this.unit; + } + }); + + var InterpolColor = function(start, end){ + this.start = start, this.end = end; + this.temp = new dojo.Color(); + }; + d.extend(InterpolColor, { + getValue: function(r){ + return d.blendColors(this.start, this.end, r, this.temp); + } + }); + + var InterpolValues = function(values){ + this.values = values; + this.length = values.length; + }; + d.extend(InterpolValues, { + getValue: function(r){ + return this.values[Math.min(Math.floor(r * this.length), this.length - 1)]; + } + }); + + var InterpolObject = function(values, def){ + this.values = values; + this.def = def ? def : {}; + }; + d.extend(InterpolObject, { + getValue: function(r){ + var ret = dojo.clone(this.def); + for(var i in this.values){ + ret[i] = this.values[i].getValue(r); + } + return ret; + } + }); + + var InterpolTransform = function(stack, original){ + this.stack = stack; + this.original = original; + }; + d.extend(InterpolTransform, { + getValue: function(r){ + var ret = []; + dojo.forEach(this.stack, function(t){ + if(t instanceof m.Matrix2D){ + ret.push(t); + return; + } + if(t.name == "original" && this.original){ + ret.push(this.original); + return; + } + if(!(t.name in m)){ return; } + var f = m[t.name]; + if(typeof f != "function"){ + // constant + ret.push(f); + return; + } + var val = dojo.map(t.start, function(v, i){ + return (t.end[i] - v) * r + v; + }), + matrix = f.apply(m, val); + if(matrix instanceof m.Matrix2D){ + ret.push(matrix); + } + }, this); + return ret; + } + }); + + var transparent = new d.Color(0, 0, 0, 0); + + var getColorInterpol = function(prop, obj, name, def){ + if(prop.values){ + return new InterpolValues(prop.values); + } + var value, start, end; + if(prop.start){ + start = g.normalizeColor(prop.start); + }else{ + start = value = obj ? (name ? obj[name] : obj) : def; + } + if(prop.end){ + end = g.normalizeColor(prop.end); + }else{ + if(!value){ + value = obj ? (name ? obj[name] : obj) : def; + } + end = value; + } + return new InterpolColor(start, end); + }; + + var getNumberInterpol = function(prop, obj, name, def){ + if(prop.values){ + return new InterpolValues(prop.values); + } + var value, start, end; + if(prop.start){ + start = prop.start; + }else{ + start = value = obj ? obj[name] : def; + } + if(prop.end){ + end = prop.end; + }else{ + if(typeof value != "number"){ + value = obj ? obj[name] : def; + } + end = value; + } + return new InterpolNumber(start, end); + }; + + g.fx.animateStroke = function(/*Object*/ args){ + // summary: + // returns the animation, which will change stroke properties over time + // example: + // | dojox.gfx.fx.animateStroke{{ + // | shape: shape, + // | duration: 500, + // | color: {start: "red", end: "green"}, + // | width: {end: 15}, + // | join: {values: ["miter", "bevel", "round"]} + // | }).play(); + if(!args.easing){ args.easing = d._defaultEasing; } + var anim = new d._Animation(args), shape = args.shape, stroke; + d.connect(anim, "beforeBegin", anim, function(){ + stroke = shape.getStroke(); + var prop = args.color, values = {}, value, start, end; + if(prop){ + values.color = getColorInterpol(prop, stroke, "color", transparent); + } + prop = args.style; + if(prop && prop.values){ + values.style = new InterpolValues(prop.values); + } + prop = args.width; + if(prop){ + values.width = getNumberInterpol(prop, stroke, "width", 1); + } + prop = args.cap; + if(prop && prop.values){ + values.cap = new InterpolValues(prop.values); + } + prop = args.join; + if(prop){ + if(prop.values){ + values.join = new InterpolValues(prop.values); + }else{ + start = prop.start ? prop.start : (stroke && stroke.join || 0); + end = prop.end ? prop.end : (stroke && stroke.join || 0); + if(typeof start == "number" && typeof end == "number"){ + values.join = new InterpolNumber(start, end); + } + } + } + this.curve = new InterpolObject(values, stroke); + }); + d.connect(anim, "onAnimate", shape, "setStroke"); + return anim; + }; + + g.fx.animateFill = function(/*Object*/ args){ + // summary: + // returns the animation, which will change fill color over time, + // only solid fill color is supported at the moment + // example: + // | dojox.gfx.fx.animateFill{{ + // | shape: shape, + // | duration: 500, + // | color: {start: "red", end: "green"} + // | }).play(); + if(!args.easing){ args.easing = d._defaultEasing; } + var anim = new d._Animation(args), shape = args.shape, fill; + d.connect(anim, "beforeBegin", anim, function(){ + fill = shape.getFill(); + var prop = args.color, values = {}; + if(prop){ + this.curve = getColorInterpol(prop, fill, "", transparent); + } + }); + d.connect(anim, "onAnimate", shape, "setFill"); + return anim; + }; + + g.fx.animateFont = function(/*Object*/ args){ + // summary: + // returns the animation, which will change font properties over time + // example: + // | dojox.gfx.fx.animateFont{{ + // | shape: shape, + // | duration: 500, + // | variant: {values: ["normal", "small-caps"]}, + // | size: {end: 10, unit: "pt"} + // | }).play(); + if(!args.easing){ args.easing = d._defaultEasing; } + var anim = new d._Animation(args), shape = args.shape, font; + d.connect(anim, "beforeBegin", anim, function(){ + font = shape.getFont(); + var prop = args.style, values = {}, value, start, end; + if(prop && prop.values){ + values.style = new InterpolValues(prop.values); + } + prop = args.variant; + if(prop && prop.values){ + values.variant = new InterpolValues(prop.values); + } + prop = args.weight; + if(prop && prop.values){ + values.weight = new InterpolValues(prop.values); + } + prop = args.family; + if(prop && prop.values){ + values.family = new InterpolValues(prop.values); + } + prop = args.size; + if(prop && prop.unit){ + start = parseFloat(prop.start ? prop.start : (shape.font && shape.font.size || "0")); + end = parseFloat(prop.end ? prop.end : (shape.font && shape.font.size || "0")); + values.size = new InterpolUnit(start, end, prop.unit); + } + this.curve = new InterpolObject(values, font); + }); + d.connect(anim, "onAnimate", shape, "setFont"); + return anim; + }; + + g.fx.animateTransform = function(/*Object*/ args){ + // summary: + // returns the animation, which will change transformation over time + // example: + // | dojox.gfx.fx.animateTransform{{ + // | shape: shape, + // | duration: 500, + // | transform: [ + // | {name: "translate", start: [0, 0], end: [200, 200]}, + // | {name: "original"} + // | ] + // | }).play(); + if(!args.easing){ args.easing = d._defaultEasing; } + var anim = new d._Animation(args), shape = args.shape, original; + d.connect(anim, "beforeBegin", anim, function(){ + original = shape.getTransform(); + this.curve = new InterpolTransform(args.transform, original); + }); + d.connect(anim, "onAnimate", shape, "setTransform"); + return anim; + }; +})(); + +} diff --git a/includes/js/dojox/gfx/matrix.js b/includes/js/dojox/gfx/matrix.js new file mode 100644 index 0000000..f3402b1 --- /dev/null +++ b/includes/js/dojox/gfx/matrix.js @@ -0,0 +1,444 @@ +if(!dojo._hasResource["dojox.gfx.matrix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.matrix"] = true; +dojo.provide("dojox.gfx.matrix"); + +(function(){ + var m = dojox.gfx.matrix; + + // candidates for dojox.math: + m._degToRad = function(degree){ return Math.PI * degree / 180; }; + m._radToDeg = function(radian){ return radian / Math.PI * 180; }; + + m.Matrix2D = function(arg){ + // summary: a 2D matrix object + // description: Normalizes a 2D matrix-like object. If arrays is passed, + // all objects of the array are normalized and multiplied sequentially. + // arg: Object + // a 2D matrix-like object, a number, or an array of such objects + if(arg){ + if(typeof arg == "number"){ + this.xx = this.yy = arg; + }else if(arg instanceof Array){ + if(arg.length > 0){ + var matrix = m.normalize(arg[0]); + // combine matrices + for(var i = 1; i < arg.length; ++i){ + var l = matrix, r = dojox.gfx.matrix.normalize(arg[i]); + matrix = new m.Matrix2D(); + matrix.xx = l.xx * r.xx + l.xy * r.yx; + matrix.xy = l.xx * r.xy + l.xy * r.yy; + matrix.yx = l.yx * r.xx + l.yy * r.yx; + matrix.yy = l.yx * r.xy + l.yy * r.yy; + matrix.dx = l.xx * r.dx + l.xy * r.dy + l.dx; + matrix.dy = l.yx * r.dx + l.yy * r.dy + l.dy; + } + dojo.mixin(this, matrix); + } + }else{ + dojo.mixin(this, arg); + } + } + }; + + // the default (identity) matrix, which is used to fill in missing values + dojo.extend(m.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0}); + + dojo.mixin(m, { + // summary: class constants, and methods of dojox.gfx.matrix + + // matrix constants + + // identity: dojox.gfx.matrix.Matrix2D + // an identity matrix constant: identity * (x, y) == (x, y) + identity: new m.Matrix2D(), + + // flipX: dojox.gfx.matrix.Matrix2D + // a matrix, which reflects points at x = 0 line: flipX * (x, y) == (-x, y) + flipX: new m.Matrix2D({xx: -1}), + + // flipY: dojox.gfx.matrix.Matrix2D + // a matrix, which reflects points at y = 0 line: flipY * (x, y) == (x, -y) + flipY: new m.Matrix2D({yy: -1}), + + // flipXY: dojox.gfx.matrix.Matrix2D + // a matrix, which reflects points at the origin of coordinates: flipXY * (x, y) == (-x, -y) + flipXY: new m.Matrix2D({xx: -1, yy: -1}), + + // matrix creators + + translate: function(a, b){ + // summary: forms a translation matrix + // description: The resulting matrix is used to translate (move) points by specified offsets. + // a: Number: an x coordinate value + // b: Number: a y coordinate value + if(arguments.length > 1){ + return new m.Matrix2D({dx: a, dy: b}); // dojox.gfx.matrix.Matrix2D + } + // branch + // a: dojox.gfx.Point: a point-like object, which specifies offsets for both dimensions + // b: null + return new m.Matrix2D({dx: a.x, dy: a.y}); // dojox.gfx.matrix.Matrix2D + }, + scale: function(a, b){ + // summary: forms a scaling matrix + // description: The resulting matrix is used to scale (magnify) points by specified offsets. + // a: Number: a scaling factor used for the x coordinate + // b: Number: a scaling factor used for the y coordinate + if(arguments.length > 1){ + return new m.Matrix2D({xx: a, yy: b}); // dojox.gfx.matrix.Matrix2D + } + if(typeof a == "number"){ + // branch + // a: Number: a uniform scaling factor used for the both coordinates + // b: null + return new m.Matrix2D({xx: a, yy: a}); // dojox.gfx.matrix.Matrix2D + } + // branch + // a: dojox.gfx.Point: a point-like object, which specifies scale factors for both dimensions + // b: null + return new m.Matrix2D({xx: a.x, yy: a.y}); // dojox.gfx.matrix.Matrix2D + }, + rotate: function(angle){ + // summary: forms a rotating matrix + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified angle. + // angle: Number: an angle of rotation in radians (>0 for CW) + var c = Math.cos(angle); + var s = Math.sin(angle); + return new m.Matrix2D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx.matrix.Matrix2D + }, + rotateg: function(degree){ + // summary: forms a rotating matrix + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified degree. + // See dojox.gfx.matrix.rotate() for comparison. + // degree: Number: an angle of rotation in degrees (>0 for CW) + return m.rotate(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D + }, + skewX: function(angle) { + // summary: forms an x skewing matrix + // description: The resulting matrix is used to skew points in the x dimension + // around the origin of coordinates (0, 0) by specified angle. + // angle: Number: an skewing angle in radians + return new m.Matrix2D({xy: -Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D + }, + skewXg: function(degree){ + // summary: forms an x skewing matrix + // description: The resulting matrix is used to skew points in the x dimension + // around the origin of coordinates (0, 0) by specified degree. + // See dojox.gfx.matrix.skewX() for comparison. + // degree: Number: an skewing angle in degrees + return m.skewX(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D + }, + skewY: function(angle){ + // summary: forms a y skewing matrix + // description: The resulting matrix is used to skew points in the y dimension + // around the origin of coordinates (0, 0) by specified angle. + // angle: Number: an skewing angle in radians + return new m.Matrix2D({yx: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D + }, + skewYg: function(degree){ + // summary: forms a y skewing matrix + // description: The resulting matrix is used to skew points in the y dimension + // around the origin of coordinates (0, 0) by specified degree. + // See dojox.gfx.matrix.skewY() for comparison. + // degree: Number: an skewing angle in degrees + return m.skewY(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D + }, + reflect: function(a, b){ + // summary: forms a reflection matrix + // description: The resulting matrix is used to reflect points around a vector, + // which goes through the origin. + // a: dojox.gfx.Point: a point-like object, which specifies a vector of reflection + // b: null + if(arguments.length == 1){ + b = a.y; + a = a.x; + } + // branch + // a: Number: an x coordinate value + // b: Number: a y coordinate value + + // make a unit vector + var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = 2 * a * b / n2; + return new m.Matrix2D({xx: 2 * a2 / n2 - 1, xy: xy, yx: xy, yy: 2 * b2 / n2 - 1}); // dojox.gfx.matrix.Matrix2D + }, + project: function(a, b){ + // summary: forms an orthogonal projection matrix + // description: The resulting matrix is used to project points orthogonally on a vector, + // which goes through the origin. + // a: dojox.gfx.Point: a point-like object, which specifies a vector of projection + // b: null + if(arguments.length == 1){ + b = a.y; + a = a.x; + } + // branch + // a: Number: an x coordinate value + // b: Number: a y coordinate value + + // make a unit vector + var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = a * b / n2; + return new m.Matrix2D({xx: a2 / n2, xy: xy, yx: xy, yy: b2 / n2}); // dojox.gfx.matrix.Matrix2D + }, + + // ensure matrix 2D conformance + normalize: function(matrix){ + // summary: converts an object to a matrix, if necessary + // description: Converts any 2D matrix-like object or an array of + // such objects to a valid dojox.gfx.matrix.Matrix2D object. + // matrix: Object: an object, which is converted to a matrix, if necessary + return (matrix instanceof m.Matrix2D) ? matrix : new m.Matrix2D(matrix); // dojox.gfx.matrix.Matrix2D + }, + + // common operations + + clone: function(matrix){ + // summary: creates a copy of a 2D matrix + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be cloned + var obj = new m.Matrix2D(); + for(var i in matrix){ + if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i]; + } + return obj; // dojox.gfx.matrix.Matrix2D + }, + invert: function(matrix){ + // summary: inverts a 2D matrix + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be inverted + var M = m.normalize(matrix), + D = M.xx * M.yy - M.xy * M.yx, + M = new m.Matrix2D({ + xx: M.yy/D, xy: -M.xy/D, + yx: -M.yx/D, yy: M.xx/D, + dx: (M.xy * M.dy - M.yy * M.dx) / D, + dy: (M.yx * M.dx - M.xx * M.dy) / D + }); + return M; // dojox.gfx.matrix.Matrix2D + }, + _multiplyPoint: function(matrix, x, y){ + // summary: applies a matrix to a point + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied + // x: Number: an x coordinate of a point + // y: Number: a y coordinate of a point + return {x: matrix.xx * x + matrix.xy * y + matrix.dx, y: matrix.yx * x + matrix.yy * y + matrix.dy}; // dojox.gfx.Point + }, + multiplyPoint: function(matrix, /* Number||Point */ a, /* Number, optional */ b){ + // summary: applies a matrix to a point + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied + // a: Number: an x coordinate of a point + // b: Number: a y coordinate of a point + var M = m.normalize(matrix); + if(typeof a == "number" && typeof b == "number"){ + return m._multiplyPoint(M, a, b); // dojox.gfx.Point + } + // branch + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied + // a: dojox.gfx.Point: a point + // b: null + return m._multiplyPoint(M, a.x, a.y); // dojox.gfx.Point + }, + multiply: function(matrix){ + // summary: combines matrices by multiplying them sequentially in the given order + // matrix: dojox.gfx.matrix.Matrix2D...: a 2D matrix-like object, + // all subsequent arguments are matrix-like objects too + var M = m.normalize(matrix); + // combine matrices + for(var i = 1; i < arguments.length; ++i){ + var l = M, r = m.normalize(arguments[i]); + M = new m.Matrix2D(); + M.xx = l.xx * r.xx + l.xy * r.yx; + M.xy = l.xx * r.xy + l.xy * r.yy; + M.yx = l.yx * r.xx + l.yy * r.yx; + M.yy = l.yx * r.xy + l.yy * r.yy; + M.dx = l.xx * r.dx + l.xy * r.dy + l.dx; + M.dy = l.yx * r.dx + l.yy * r.dy + l.dy; + } + return M; // dojox.gfx.matrix.Matrix2D + }, + + // high level operations + + _sandwich: function(matrix, x, y){ + // summary: applies a matrix at a centrtal point + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object, which is applied at a central point + // x: Number: an x component of the central point + // y: Number: a y component of the central point + return m.multiply(m.translate(x, y), matrix, m.translate(-x, -y)); // dojox.gfx.matrix.Matrix2D + }, + scaleAt: function(a, b, c, d){ + // summary: scales a picture using a specified point as a center of scaling + // description: Compare with dojox.gfx.matrix.scale(). + // a: Number: a scaling factor used for the x coordinate + // b: Number: a scaling factor used for the y coordinate + // c: Number: an x component of a central point + // d: Number: a y component of a central point + + // accepts several signatures: + // 1) uniform scale factor, Point + // 2) uniform scale factor, x, y + // 3) x scale, y scale, Point + // 4) x scale, y scale, x, y + + switch(arguments.length){ + case 4: + // a and b are scale factor components, c and d are components of a point + return m._sandwich(m.scale(a, b), c, d); // dojox.gfx.matrix.Matrix2D + case 3: + if(typeof c == "number"){ + // branch + // a: Number: a uniform scaling factor used for both coordinates + // b: Number: an x component of a central point + // c: Number: a y component of a central point + // d: null + return m._sandwich(m.scale(a), b, c); // dojox.gfx.matrix.Matrix2D + } + // branch + // a: Number: a scaling factor used for the x coordinate + // b: Number: a scaling factor used for the y coordinate + // c: dojox.gfx.Point: a central point + // d: null + return m._sandwich(m.scale(a, b), c.x, c.y); // dojox.gfx.matrix.Matrix2D + } + // branch + // a: Number: a uniform scaling factor used for both coordinates + // b: dojox.gfx.Point: a central point + // c: null + // d: null + return m._sandwich(m.scale(a), b.x, b.y); // dojox.gfx.matrix.Matrix2D + }, + rotateAt: function(angle, a, b){ + // summary: rotates a picture using a specified point as a center of rotation + // description: Compare with dojox.gfx.matrix.rotate(). + // angle: Number: an angle of rotation in radians (>0 for CW) + // a: Number: an x component of a central point + // b: Number: a y component of a central point + + // accepts several signatures: + // 1) rotation angle in radians, Point + // 2) rotation angle in radians, x, y + + if(arguments.length > 2){ + return m._sandwich(m.rotate(angle), a, b); // dojox.gfx.matrix.Matrix2D + } + + // branch + // angle: Number: an angle of rotation in radians (>0 for CCW) + // a: dojox.gfx.Point: a central point + // b: null + return m._sandwich(m.rotate(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D + }, + rotategAt: function(degree, a, b){ + // summary: rotates a picture using a specified point as a center of rotation + // description: Compare with dojox.gfx.matrix.rotateg(). + // degree: Number: an angle of rotation in degrees (>0 for CW) + // a: Number: an x component of a central point + // b: Number: a y component of a central point + + // accepts several signatures: + // 1) rotation angle in degrees, Point + // 2) rotation angle in degrees, x, y + + if(arguments.length > 2){ + return m._sandwich(m.rotateg(degree), a, b); // dojox.gfx.matrix.Matrix2D + } + + // branch + // degree: Number: an angle of rotation in degrees (>0 for CCW) + // a: dojox.gfx.Point: a central point + // b: null + return m._sandwich(m.rotateg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D + }, + skewXAt: function(angle, a, b){ + // summary: skews a picture along the x axis using a specified point as a center of skewing + // description: Compare with dojox.gfx.matrix.skewX(). + // angle: Number: an skewing angle in radians + // a: Number: an x component of a central point + // b: Number: a y component of a central point + + // accepts several signatures: + // 1) skew angle in radians, Point + // 2) skew angle in radians, x, y + + if(arguments.length > 2){ + return m._sandwich(m.skewX(angle), a, b); // dojox.gfx.matrix.Matrix2D + } + + // branch + // angle: Number: an skewing angle in radians + // a: dojox.gfx.Point: a central point + // b: null + return m._sandwich(m.skewX(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D + }, + skewXgAt: function(degree, a, b){ + // summary: skews a picture along the x axis using a specified point as a center of skewing + // description: Compare with dojox.gfx.matrix.skewXg(). + // degree: Number: an skewing angle in degrees + // a: Number: an x component of a central point + // b: Number: a y component of a central point + + // accepts several signatures: + // 1) skew angle in degrees, Point + // 2) skew angle in degrees, x, y + + if(arguments.length > 2){ + return m._sandwich(m.skewXg(degree), a, b); // dojox.gfx.matrix.Matrix2D + } + + // branch + // degree: Number: an skewing angle in degrees + // a: dojox.gfx.Point: a central point + // b: null + return m._sandwich(m.skewXg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D + }, + skewYAt: function(angle, a, b){ + // summary: skews a picture along the y axis using a specified point as a center of skewing + // description: Compare with dojox.gfx.matrix.skewY(). + // angle: Number: an skewing angle in radians + // a: Number: an x component of a central point + // b: Number: a y component of a central point + + // accepts several signatures: + // 1) skew angle in radians, Point + // 2) skew angle in radians, x, y + + if(arguments.length > 2){ + return m._sandwich(m.skewY(angle), a, b); // dojox.gfx.matrix.Matrix2D + } + + // branch + // angle: Number: an skewing angle in radians + // a: dojox.gfx.Point: a central point + // b: null + return m._sandwich(m.skewY(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D + }, + skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number, optional */ b){ + // summary: skews a picture along the y axis using a specified point as a center of skewing + // description: Compare with dojox.gfx.matrix.skewYg(). + // degree: Number: an skewing angle in degrees + // a: Number: an x component of a central point + // b: Number: a y component of a central point + + // accepts several signatures: + // 1) skew angle in degrees, Point + // 2) skew angle in degrees, x, y + + if(arguments.length > 2){ + return m._sandwich(m.skewYg(degree), a, b); // dojox.gfx.matrix.Matrix2D + } + + // branch + // degree: Number: an skewing angle in degrees + // a: dojox.gfx.Point: a central point + // b: null + return m._sandwich(m.skewYg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D + } + + //TODO: rect-to-rect mapping, scale-to-fit (isotropic and anisotropic versions) + + }); +})(); + +// propagate Matrix2D up +dojox.gfx.Matrix2D = dojox.gfx.matrix.Matrix2D; + +} diff --git a/includes/js/dojox/gfx/move.js b/includes/js/dojox/gfx/move.js new file mode 100644 index 0000000..dba5ced --- /dev/null +++ b/includes/js/dojox/gfx/move.js @@ -0,0 +1,8 @@ +if(!dojo._hasResource["dojox.gfx.move"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.move"] = true; +dojo.provide("dojox.gfx.move"); + +dojo.require("dojox.gfx.Mover"); +dojo.require("dojox.gfx.Moveable"); + +} diff --git a/includes/js/dojox/gfx/path.js b/includes/js/dojox/gfx/path.js new file mode 100644 index 0000000..657136b --- /dev/null +++ b/includes/js/dojox/gfx/path.js @@ -0,0 +1,361 @@ +if(!dojo._hasResource["dojox.gfx.path"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.path"] = true; +dojo.provide("dojox.gfx.path"); + +dojo.require("dojox.gfx.shape"); + +dojo.declare("dojox.gfx.path.Path", dojox.gfx.Shape, { + // summary: a generalized path shape + + constructor: function(rawNode){ + // summary: a path constructor + // rawNode: Node: a DOM node to be used by this path object + this.shape = dojo.clone(dojox.gfx.defaultPath); + this.segments = []; + this.absolute = true; + this.last = {}; + this.rawNode = rawNode; + }, + + // mode manipulations + setAbsoluteMode: function(mode){ + // summary: sets an absolute or relative mode for path points + // mode: Boolean: true/false or "absolute"/"relative" to specify the mode + this.absolute = typeof mode == "string" ? (mode == "absolute") : mode; + return this; // self + }, + getAbsoluteMode: function(){ + // summary: returns a current value of the absolute mode + return this.absolute; // Boolean + }, + + getBoundingBox: function(){ + // summary: returns the bounding box {x, y, width, height} or null + return (this.bbox && ("l" in this.bbox)) ? {x: this.bbox.l, y: this.bbox.t, width: this.bbox.r - this.bbox.l, height: this.bbox.b - this.bbox.t} : null; // dojox.gfx.Rectangle + }, + + getLastPosition: function(){ + // summary: returns the last point in the path, or null + return "x" in this.last ? this.last : null; // Object + }, + + // segment interpretation + _updateBBox: function(x, y){ + // summary: updates the bounding box of path with new point + // x: Number: an x coordinate + // y: Number: a y coordinate + + // we use {l, b, r, t} representation of a bbox + if(this.bbox && ("l" in this.bbox)){ + if(this.bbox.l > x) this.bbox.l = x; + if(this.bbox.r < x) this.bbox.r = x; + if(this.bbox.t > y) this.bbox.t = y; + if(this.bbox.b < y) this.bbox.b = y; + }else{ + this.bbox = {l: x, b: y, r: x, t: y}; + } + }, + _updateWithSegment: function(segment){ + // summary: updates the bounding box of path with new segment + // segment: Object: a segment + var n = segment.args, l = n.length; + // update internal variables: bbox, absolute, last + switch(segment.action){ + case "M": + case "L": + case "C": + case "S": + case "Q": + case "T": + for(var i = 0; i < l; i += 2){ + this._updateBBox(n[i], n[i + 1]); + } + this.last.x = n[l - 2]; + this.last.y = n[l - 1]; + this.absolute = true; + break; + case "H": + for(var i = 0; i < l; ++i){ + this._updateBBox(n[i], this.last.y); + } + this.last.x = n[l - 1]; + this.absolute = true; + break; + case "V": + for(var i = 0; i < l; ++i){ + this._updateBBox(this.last.x, n[i]); + } + this.last.y = n[l - 1]; + this.absolute = true; + break; + case "m": + var start = 0; + if(!("x" in this.last)){ + this._updateBBox(this.last.x = n[0], this.last.y = n[1]); + start = 2; + } + for(var i = start; i < l; i += 2){ + this._updateBBox(this.last.x += n[i], this.last.y += n[i + 1]); + } + this.absolute = false; + break; + case "l": + case "t": + for(var i = 0; i < l; i += 2){ + this._updateBBox(this.last.x += n[i], this.last.y += n[i + 1]); + } + this.absolute = false; + break; + case "h": + for(var i = 0; i < l; ++i){ + this._updateBBox(this.last.x += n[i], this.last.y); + } + this.absolute = false; + break; + case "v": + for(var i = 0; i < l; ++i){ + this._updateBBox(this.last.x, this.last.y += n[i]); + } + this.absolute = false; + break; + case "c": + for(var i = 0; i < l; i += 6){ + this._updateBBox(this.last.x + n[i], this.last.y + n[i + 1]); + this._updateBBox(this.last.x + n[i + 2], this.last.y + n[i + 3]); + this._updateBBox(this.last.x += n[i + 4], this.last.y += n[i + 5]); + } + this.absolute = false; + break; + case "s": + case "q": + for(var i = 0; i < l; i += 4){ + this._updateBBox(this.last.x + n[i], this.last.y + n[i + 1]); + this._updateBBox(this.last.x += n[i + 2], this.last.y += n[i + 3]); + } + this.absolute = false; + break; + case "A": + for(var i = 0; i < l; i += 7){ + this._updateBBox(n[i + 5], n[i + 6]); + } + this.last.x = n[l - 2]; + this.last.y = n[l - 1]; + this.absolute = true; + break; + case "a": + for(var i = 0; i < l; i += 7){ + this._updateBBox(this.last.x += n[i + 5], this.last.y += n[i + 6]); + } + this.absolute = false; + break; + } + // add an SVG path segment + var path = [segment.action]; + for(var i = 0; i < l; ++i){ + path.push(dojox.gfx.formatNumber(n[i], true)); + } + if(typeof this.shape.path == "string"){ + this.shape.path += path.join(""); + }else{ + var l = path.length, a = this.shape.path; + for(var i = 0; i < l; ++i){ + a.push(path[i]); + } + } + }, + + // a dictionary, which maps segment type codes to a number of their argemnts + _validSegments: {m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0}, + + _pushSegment: function(action, args){ + // summary: adds a segment + // action: String: valid SVG code for a segment's type + // args: Array: a list of parameters for this segment + var group = this._validSegments[action.toLowerCase()]; + if(typeof group == "number"){ + if(group){ + if(args.length >= group){ + var segment = {action: action, args: args.slice(0, args.length - args.length % group)}; + this.segments.push(segment); + this._updateWithSegment(segment); + } + }else{ + var segment = {action: action, args: []}; + this.segments.push(segment); + this._updateWithSegment(segment); + } + } + }, + + _collectArgs: function(array, args){ + // summary: converts an array of arguments to plain numeric values + // array: Array: an output argument (array of numbers) + // args: Array: an input argument (can be values of Boolean, Number, dojox.gfx.Point, or an embedded array of them) + for(var i = 0; i < args.length; ++i){ + var t = args[i]; + if(typeof t == "boolean"){ + array.push(t ? 1 : 0); + }else if(typeof t == "number"){ + array.push(t); + }else if(t instanceof Array){ + this._collectArgs(array, t); + }else if("x" in t && "y" in t){ + array.push(t.x, t.y); + } + } + }, + + // segments + moveTo: function(){ + // summary: formes a move segment + var args = []; + this._collectArgs(args, arguments); + this._pushSegment(this.absolute ? "M" : "m", args); + return this; // self + }, + lineTo: function(){ + // summary: formes a line segment + var args = []; + this._collectArgs(args, arguments); + this._pushSegment(this.absolute ? "L" : "l", args); + return this; // self + }, + hLineTo: function(){ + // summary: formes a horizontal line segment + var args = []; + this._collectArgs(args, arguments); + this._pushSegment(this.absolute ? "H" : "h", args); + return this; // self + }, + vLineTo: function(){ + // summary: formes a vertical line segment + var args = []; + this._collectArgs(args, arguments); + this._pushSegment(this.absolute ? "V" : "v", args); + return this; // self + }, + curveTo: function(){ + // summary: formes a curve segment + var args = []; + this._collectArgs(args, arguments); + this._pushSegment(this.absolute ? "C" : "c", args); + return this; // self + }, + smoothCurveTo: function(){ + // summary: formes a smooth curve segment + var args = []; + this._collectArgs(args, arguments); + this._pushSegment(this.absolute ? "S" : "s", args); + return this; // self + }, + qCurveTo: function(){ + // summary: formes a quadratic curve segment + var args = []; + this._collectArgs(args, arguments); + this._pushSegment(this.absolute ? "Q" : "q", args); + return this; // self + }, + qSmoothCurveTo: function(){ + // summary: formes a quadratic smooth curve segment + var args = []; + this._collectArgs(args, arguments); + this._pushSegment(this.absolute ? "T" : "t", args); + return this; // self + }, + arcTo: function(){ + // summary: formes an elliptic arc segment + var args = []; + this._collectArgs(args, arguments); + this._pushSegment(this.absolute ? "A" : "a", args); + return this; // self + }, + closePath: function(){ + // summary: closes a path + this._pushSegment("Z", []); + return this; // self + }, + + // setShape + _setPath: function(path){ + // summary: forms a path using an SVG path string + // path: String: an SVG path string + var p = dojo.isArray(path) ? path : path.match(dojox.gfx.pathSvgRegExp); + this.segments = []; + this.absolute = true; + this.bbox = {}; + this.last = {}; + if(!p) return; + // create segments + var action = "", // current action + args = [], // current arguments + l = p.length; + for(var i = 0; i < l; ++i){ + var t = p[i], x = parseFloat(t); + if(isNaN(x)){ + if(action){ + this._pushSegment(action, args); + } + args = []; + action = t; + }else{ + args.push(x); + } + } + this._pushSegment(action, args); + }, + setShape: function(newShape){ + // summary: forms a path using a shape + // newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath) + dojox.gfx.Shape.prototype.setShape.call(this, typeof newShape == "string" ? {path: newShape} : newShape); + var path = this.shape.path; + // switch to non-updating version of path building + this.shape.path = []; + this._setPath(path); + // switch back to the string path + this.shape.path = this.shape.path.join(""); + return this; // self + }, + + // useful constant for descendants + _2PI: Math.PI * 2 +}); + +dojo.declare("dojox.gfx.path.TextPath", dojox.gfx.path.Path, { + // summary: a generalized TextPath shape + + constructor: function(rawNode){ + // summary: a TextPath shape constructor + // rawNode: Node: a DOM node to be used by this TextPath object + if(!("text" in this)){ + this.text = dojo.clone(dojox.gfx.defaultTextPath); + } + if(!("fontStyle" in this)){ + this.fontStyle = dojo.clone(dojox.gfx.defaultFont); + } + }, + getText: function(){ + // summary: returns the current text object or null + return this.text; // Object + }, + setText: function(newText){ + // summary: sets a text to be drawn along the path + this.text = dojox.gfx.makeParameters(this.text, + typeof newText == "string" ? {text: newText} : newText); + this._setText(); + return this; // self + }, + getFont: function(){ + // summary: returns the current font object or null + return this.fontStyle; // Object + }, + setFont: function(newFont){ + // summary: sets a font for text + this.fontStyle = typeof newFont == "string" ? + dojox.gfx.splitFontString(newFont) : + dojox.gfx.makeParameters(dojox.gfx.defaultFont, newFont); + this._setFont(); + return this; // self + } +}); + +} diff --git a/includes/js/dojox/gfx/shape.js b/includes/js/dojox/gfx/shape.js new file mode 100644 index 0000000..179f6c5 --- /dev/null +++ b/includes/js/dojox/gfx/shape.js @@ -0,0 +1,691 @@ +if(!dojo._hasResource["dojox.gfx.shape"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.shape"] = true; +dojo.provide("dojox.gfx.shape"); + +dojo.require("dojox.gfx._base"); + +dojo.declare("dojox.gfx.Shape", null, { + // summary: a Shape object, which knows how to apply + // graphical attributes and transformations + + constructor: function(){ + // rawNode: Node: underlying node + this.rawNode = null; + + // shape: Object: an abstract shape object + // (see dojox.gfx.defaultPath, + // dojox.gfx.defaultPolyline, + // dojox.gfx.defaultRect, + // dojox.gfx.defaultEllipse, + // dojox.gfx.defaultCircle, + // dojox.gfx.defaultLine, + // or dojox.gfx.defaultImage) + this.shape = null; + + // matrix: dojox.gfx.Matrix2D: a transformation matrix + this.matrix = null; + + // fillStyle: Object: a fill object + // (see dojox.gfx.defaultLinearGradient, + // dojox.gfx.defaultRadialGradient, + // dojox.gfx.defaultPattern, + // or dojo.Color) + this.fillStyle = null; + + // strokeStyle: Object: a stroke object + // (see dojox.gfx.defaultStroke) + this.strokeStyle = null; + + // bbox: dojox.gfx.Rectangle: a bounding box of this shape + // (see dojox.gfx.defaultRect) + this.bbox = null; + + // virtual group structure + + // parent: Object: a parent or null + // (see dojox.gfx.Surface, + // dojox.gfx.shape.VirtualGroup, + // or dojox.gfx.Group) + this.parent = null; + + // parentMatrix: dojox.gfx.Matrix2D + // a transformation matrix inherited from the parent + this.parentMatrix = null; + }, + + // trivial getters + + getNode: function(){ + // summary: returns the current DOM Node or null + return this.rawNode; // Node + }, + getShape: function(){ + // summary: returns the current shape object or null + // (see dojox.gfx.defaultPath, + // dojox.gfx.defaultPolyline, + // dojox.gfx.defaultRect, + // dojox.gfx.defaultEllipse, + // dojox.gfx.defaultCircle, + // dojox.gfx.defaultLine, + // or dojox.gfx.defaultImage) + return this.shape; // Object + }, + getTransform: function(){ + // summary: returns the current transformation matrix or null + return this.matrix; // dojox.gfx.Matrix2D + }, + getFill: function(){ + // summary: returns the current fill object or null + // (see dojox.gfx.defaultLinearGradient, + // dojox.gfx.defaultRadialGradient, + // dojox.gfx.defaultPattern, + // or dojo.Color) + return this.fillStyle; // Object + }, + getStroke: function(){ + // summary: returns the current stroke object or null + // (see dojox.gfx.defaultStroke) + return this.strokeStyle; // Object + }, + getParent: function(){ + // summary: returns the parent or null + // (see dojox.gfx.Surface, + // dojox.gfx.shape.VirtualGroup, + // or dojox.gfx.Group) + return this.parent; // Object + }, + getBoundingBox: function(){ + // summary: returns the bounding box or null + // (see dojox.gfx.defaultRect) + return this.bbox; // dojox.gfx.Rectangle + }, + getTransformedBoundingBox: function(){ + // summary: returns an array of four points or null + // four points represent four corners of the untransformed bounding box + var b = this.getBoundingBox(); + if(!b){ + return null; // null + } + var m = this._getRealMatrix(); + var r = []; + var g = dojox.gfx.matrix; + r.push(g.multiplyPoint(m, b.x, b.y)); + r.push(g.multiplyPoint(m, b.x + b.width, b.y)); + r.push(g.multiplyPoint(m, b.x + b.width, b.y + b.height)); + r.push(g.multiplyPoint(m, b.x, b.y + b.height)); + return r; // Array + }, + getEventSource: function(){ + // summary: returns a Node, which is used as + // a source of events for this shape + + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + + return this.rawNode; // Node + }, + + // empty settings + + setShape: function(shape){ + // summary: sets a shape object + // (the default implementation simply ignores it) + // shape: Object: a shape object + // (see dojox.gfx.defaultPath, + // dojox.gfx.defaultPolyline, + // dojox.gfx.defaultRect, + // dojox.gfx.defaultEllipse, + // dojox.gfx.defaultCircle, + // dojox.gfx.defaultLine, + // or dojox.gfx.defaultImage) + + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + + this.shape = dojox.gfx.makeParameters(this.shape, shape); + this.bbox = null; + return this; // self + }, + setFill: function(fill){ + // summary: sets a fill object + // (the default implementation simply ignores it) + // fill: Object: a fill object + // (see dojox.gfx.defaultLinearGradient, + // dojox.gfx.defaultRadialGradient, + // dojox.gfx.defaultPattern, + // or dojo.Color) + + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + + if(!fill){ + // don't fill + this.fillStyle = null; + return this; // self + } + var f = null; + if(typeof(fill) == "object" && "type" in fill){ + // gradient or pattern + switch(fill.type){ + case "linear": + f = dojox.gfx.makeParameters(dojox.gfx.defaultLinearGradient, fill); + break; + case "radial": + f = dojox.gfx.makeParameters(dojox.gfx.defaultRadialGradient, fill); + break; + case "pattern": + f = dojox.gfx.makeParameters(dojox.gfx.defaultPattern, fill); + break; + } + }else{ + // color object + f = dojox.gfx.normalizeColor(fill); + } + this.fillStyle = f; + return this; // self + }, + setStroke: function(stroke){ + // summary: sets a stroke object + // (the default implementation simply ignores it) + // stroke: Object: a stroke object + // (see dojox.gfx.defaultStroke) + + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + + if(!stroke){ + // don't stroke + this.strokeStyle = null; + return this; // self + } + // normalize the stroke + if(typeof stroke == "string"){ + stroke = {color: stroke}; + } + var s = this.strokeStyle = dojox.gfx.makeParameters(dojox.gfx.defaultStroke, stroke); + s.color = dojox.gfx.normalizeColor(s.color); + return this; // self + }, + setTransform: function(matrix){ + // summary: sets a transformation matrix + // matrix: dojox.gfx.Matrix2D: a matrix or a matrix-like object + // (see an argument of dojox.gfx.Matrix2D + // constructor for a list of acceptable arguments) + + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + + this.matrix = dojox.gfx.matrix.clone(matrix ? dojox.gfx.matrix.normalize(matrix) : dojox.gfx.matrix.identity); + return this._applyTransform(); // self + }, + + _applyTransform: function(){ + // summary: physically sets a matrix + + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + + return this; // self + }, + + // z-index + + moveToFront: function(){ + // summary: moves a shape to front of its parent's list of shapes + var p = this.getParent(); + if(p){ + p._moveChildToFront(this); + this._moveToFront(); // execute renderer-specific action + } + return this; // self + }, + moveToBack: function(){ + // summary: moves a shape to back of its parent's list of shapes + var p = this.getParent(); + if(p){ + p._moveChildToBack(this); + this._moveToBack(); // execute renderer-specific action + } + return this; + }, + _moveToFront: function(){ + // summary: renderer-specific hook, see dojox.gfx.shape.Shape.moveToFront() + + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + }, + _moveToBack: function(){ + // summary: renderer-specific hook, see dojox.gfx.shape.Shape.moveToFront() + + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + }, + + // apply left & right transformation + + applyRightTransform: function(matrix){ + // summary: multiplies the existing matrix with an argument on right side + // (this.matrix * matrix) + // matrix: dojox.gfx.Matrix2D: a matrix or a matrix-like object + // (see an argument of dojox.gfx.Matrix2D + // constructor for a list of acceptable arguments) + return matrix ? this.setTransform([this.matrix, matrix]) : this; // self + }, + applyLeftTransform: function(matrix){ + // summary: multiplies the existing matrix with an argument on left side + // (matrix * this.matrix) + // matrix: dojox.gfx.Matrix2D: a matrix or a matrix-like object + // (see an argument of dojox.gfx.Matrix2D + // constructor for a list of acceptable arguments) + return matrix ? this.setTransform([matrix, this.matrix]) : this; // self + }, + applyTransform: function(matrix){ + // summary: a shortcut for dojox.gfx.Shape.applyRightTransform + // matrix: dojox.gfx.Matrix2D: a matrix or a matrix-like object + // (see an argument of dojox.gfx.Matrix2D + // constructor for a list of acceptable arguments) + return matrix ? this.setTransform([this.matrix, matrix]) : this; // self + }, + + // virtual group methods + + removeShape: function(silently){ + // summary: removes the shape from its parent's list of shapes + // silently: Boolean?: if true, do not redraw a picture yet + if(this.parent){ + this.parent.remove(this, silently); + } + return this; // self + }, + _setParent: function(parent, matrix){ + // summary: sets a parent + // parent: Object: a parent or null + // (see dojox.gfx.Surface, + // dojox.gfx.shape.VirtualGroup, + // or dojox.gfx.Group) + // matrix: dojox.gfx.Matrix2D: + // a 2D matrix or a matrix-like object + this.parent = parent; + return this._updateParentMatrix(matrix); // self + }, + _updateParentMatrix: function(matrix){ + // summary: updates the parent matrix with new matrix + // matrix: dojox.gfx.Matrix2D: + // a 2D matrix or a matrix-like object + this.parentMatrix = matrix ? dojox.gfx.matrix.clone(matrix) : null; + return this._applyTransform(); // self + }, + _getRealMatrix: function(){ + // summary: returns the cumulative ("real") transformation matrix + // by combining the shape's matrix with its parent's matrix + var m = this.matrix; + var p = this.parent; + while(p){ + if(p.matrix){ + m = dojox.gfx.matrix.multiply(p.matrix, m); + } + p = p.parent; + } + return m; // dojox.gfx.Matrix2D + } +}); + +dojox.gfx.shape._eventsProcessing = { + connect: function(name, object, method){ + // summary: connects a handler to an event on this shape + + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + + return arguments.length > 2 ? // Object + dojo.connect(this.getEventSource(), name, object, method) : + dojo.connect(this.getEventSource(), name, object); + }, + disconnect: function(token){ + // summary: connects a handler by token from an event on this shape + + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + + dojo.disconnect(token); + } +}; + +dojo.extend(dojox.gfx.Shape, dojox.gfx.shape._eventsProcessing); + +dojox.gfx.shape.Container = { + // summary: a container of shapes, which can be used + // as a foundation for renderer-specific groups, or as a way + // to logically group shapes (e.g, to propagate matricies) + + _init: function() { + // children: Array: a list of children + this.children = []; + }, + + // group management + + add: function(shape){ + // summary: adds a shape to the list + // shape: dojox.gfx.Shape: a shape + var oldParent = shape.getParent(); + if(oldParent){ + oldParent.remove(shape, true); + } + this.children.push(shape); + return shape._setParent(this, this._getRealMatrix()); // self + }, + remove: function(shape, silently){ + // summary: removes a shape from the list + // silently: Boolean?: if true, do not redraw a picture yet + for(var i = 0; i < this.children.length; ++i){ + if(this.children[i] == shape){ + if(silently){ + // skip for now + }else{ + shape._setParent(null, null); + } + this.children.splice(i, 1); + break; + } + } + return this; // self + }, + clear: function(){ + // summary: removes all shapes from a group/surface + this.children = []; + return this; // self + }, + + // moving child nodes + + _moveChildToFront: function(shape){ + // summary: moves a shape to front of the list of shapes + for(var i = 0; i < this.children.length; ++i){ + if(this.children[i] == shape){ + this.children.splice(i, 1); + this.children.push(shape); + break; + } + } + return this; // self + }, + _moveChildToBack: function(shape){ + // summary: moves a shape to back of the list of shapes + for(var i = 0; i < this.children.length; ++i){ + if(this.children[i] == shape){ + this.children.splice(i, 1); + this.children.unshift(shape); + break; + } + } + return this; // self + } +}; + +dojo.declare("dojox.gfx.shape.Surface", null, { + // summary: a surface object to be used for drawings + constructor: function(){ + // underlying node + this.rawNode = null; + }, + getEventSource: function(){ + // summary: returns a node, which can be used to attach event listeners + return this.rawNode; // Node + }, + _getRealMatrix: function(){ + // summary: always returns the identity matrix + return null; // dojox.gfx.Matrix2D + } +}); + +dojo.extend(dojox.gfx.shape.Surface, dojox.gfx.shape._eventsProcessing); + +dojo.declare("dojox.gfx.Point", null, { + // summary: a hypothetical 2D point to be used for drawings - {x, y} + // description: This object is defined for documentation purposes. + // You should use the naked object instead: {x: 1, y: 2}. +}); + +dojo.declare("dojox.gfx.Rectangle", null, { + // summary: a hypothetical rectangle - {x, y, width, height} + // description: This object is defined for documentation purposes. + // You should use the naked object instead: {x: 1, y: 2, width: 100, height: 200}. +}); + +dojo.declare("dojox.gfx.shape.Rect", dojox.gfx.Shape, { + // summary: a generic rectangle + constructor: function(rawNode) { + // rawNode: Node: a DOM Node + this.shape = dojo.clone(dojox.gfx.defaultRect); + this.rawNode = rawNode; + }, + getBoundingBox: function(){ + // summary: returns the bounding box (its shape in this case) + return this.shape; // dojox.gfx.Rectangle + } +}); + +dojo.declare("dojox.gfx.shape.Ellipse", dojox.gfx.Shape, { + // summary: a generic ellipse + constructor: function(rawNode) { + // rawNode: Node: a DOM Node + this.shape = dojo.clone(dojox.gfx.defaultEllipse); + this.rawNode = rawNode; + }, + getBoundingBox: function(){ + // summary: returns the bounding box + if(!this.bbox){ + var shape = this.shape; + this.bbox = {x: shape.cx - shape.rx, y: shape.cy - shape.ry, + width: 2 * shape.rx, height: 2 * shape.ry}; + } + return this.bbox; // dojox.gfx.Rectangle + } +}); + +dojo.declare("dojox.gfx.shape.Circle", dojox.gfx.Shape, { + // summary: a generic circle + // (this is a helper object, which is defined for convenience) + constructor: function(rawNode) { + // rawNode: Node: a DOM Node + this.shape = dojo.clone(dojox.gfx.defaultCircle); + this.rawNode = rawNode; + }, + getBoundingBox: function(){ + // summary: returns the bounding box + if(!this.bbox){ + var shape = this.shape; + this.bbox = {x: shape.cx - shape.r, y: shape.cy - shape.r, + width: 2 * shape.r, height: 2 * shape.r}; + } + return this.bbox; // dojox.gfx.Rectangle + } +}); + +dojo.declare("dojox.gfx.shape.Line", dojox.gfx.Shape, { + // summary: a generic line + // (this is a helper object, which is defined for convenience) + constructor: function(rawNode) { + // rawNode: Node: a DOM Node + this.shape = dojo.clone(dojox.gfx.defaultLine); + this.rawNode = rawNode; + }, + getBoundingBox: function(){ + // summary: returns the bounding box + if(!this.bbox){ + var shape = this.shape; + this.bbox = { + x: Math.min(shape.x1, shape.x2), + y: Math.min(shape.y1, shape.y2), + width: Math.abs(shape.x2 - shape.x1), + height: Math.abs(shape.y2 - shape.y1) + }; + } + return this.bbox; // dojox.gfx.Rectangle + } +}); + +dojo.declare("dojox.gfx.shape.Polyline", dojox.gfx.Shape, { + // summary: a generic polyline/polygon + // (this is a helper object, which is defined for convenience) + constructor: function(rawNode) { + // rawNode: Node: a DOM Node + this.shape = dojo.clone(dojox.gfx.defaultPolyline); + this.rawNode = rawNode; + }, + setShape: function(points, closed){ + // summary: sets a polyline/polygon shape object + // points: Object: a polyline/polygon shape object + // closed: Boolean: close the polyline to make a polygon + if(points && points instanceof Array){ + // points: Array: an array of points + dojox.gfx.Shape.prototype.setShape.call(this, {points: points}); + if(closed && this.shape.points.length){ + this.shape.points.push(this.shape.points[0]); + } + }else{ + dojox.gfx.Shape.prototype.setShape.call(this, points); + } + return this; // self + }, + getBoundingBox: function(){ + // summary: returns the bounding box + if(!this.bbox && this.shape.points.length){ + var p = this.shape.points; + var l = p.length; + var t = p[0]; + var bbox = {l: t.x, t: t.y, r: t.x, b: t.y}; + for(var i = 1; i < l; ++i){ + t = p[i]; + if(bbox.l > t.x) bbox.l = t.x; + if(bbox.r < t.x) bbox.r = t.x; + if(bbox.t > t.y) bbox.t = t.y; + if(bbox.b < t.y) bbox.b = t.y; + } + this.bbox = { + x: bbox.l, + y: bbox.t, + width: bbox.r - bbox.l, + height: bbox.b - bbox.t + }; + } + return this.bbox; // dojox.gfx.Rectangle + } +}); + +dojo.declare("dojox.gfx.shape.Image", dojox.gfx.Shape, { + // summary: a generic image + // (this is a helper object, which is defined for convenience) + constructor: function(rawNode) { + // rawNode: Node: a DOM Node + this.shape = dojo.clone(dojox.gfx.defaultImage); + this.rawNode = rawNode; + }, + getBoundingBox: function(){ + // summary: returns the bounding box (its shape in this case) + return this.shape; // dojox.gfx.Rectangle + }, + setStroke: function(){ + // summary: ignore setting a stroke style + return this; // self + }, + setFill: function(){ + // summary: ignore setting a fill style + return this; // self + } +}); + +dojo.declare("dojox.gfx.shape.Text", dojox.gfx.Shape, { + // summary: a generic text + constructor: function(rawNode) { + // rawNode: Node: a DOM Node + this.fontStyle = null; + this.shape = dojo.clone(dojox.gfx.defaultText); + this.rawNode = rawNode; + }, + getFont: function(){ + // summary: returns the current font object or null + return this.fontStyle; // Object + }, + setFont: function(newFont){ + // summary: sets a font for text + // newFont: Object: a font object (see dojox.gfx.defaultFont) or a font string + this.fontStyle = typeof newFont == "string" ? dojox.gfx.splitFontString(newFont) : + dojox.gfx.makeParameters(dojox.gfx.defaultFont, newFont); + this._setFont(); + return this; // self + } +}); + +dojox.gfx.shape.Creator = { + // summary: shape creators + createShape: function(shape){ + // summary: creates a shape object based on its type; it is meant to be used + // by group-like objects + // shape: Object: a shape descriptor object + switch(shape.type){ + case dojox.gfx.defaultPath.type: return this.createPath(shape); + case dojox.gfx.defaultRect.type: return this.createRect(shape); + case dojox.gfx.defaultCircle.type: return this.createCircle(shape); + case dojox.gfx.defaultEllipse.type: return this.createEllipse(shape); + case dojox.gfx.defaultLine.type: return this.createLine(shape); + case dojox.gfx.defaultPolyline.type: return this.createPolyline(shape); + case dojox.gfx.defaultImage.type: return this.createImage(shape); + case dojox.gfx.defaultText.type: return this.createText(shape); + case dojox.gfx.defaultTextPath.type: return this.createTextPath(shape); + } + return null; + }, + createGroup: function(){ + // summary: creates an SVG group shape + return this.createObject(dojox.gfx.Group); // dojox.gfx.Group + }, + createRect: function(rect){ + // summary: creates an SVG rectangle shape + // rect: Object: a path object (see dojox.gfx.defaultRect) + return this.createObject(dojox.gfx.Rect, rect); // dojox.gfx.Rect + }, + createEllipse: function(ellipse){ + // summary: creates an SVG ellipse shape + // ellipse: Object: an ellipse object (see dojox.gfx.defaultEllipse) + return this.createObject(dojox.gfx.Ellipse, ellipse); // dojox.gfx.Ellipse + }, + createCircle: function(circle){ + // summary: creates an SVG circle shape + // circle: Object: a circle object (see dojox.gfx.defaultCircle) + return this.createObject(dojox.gfx.Circle, circle); // dojox.gfx.Circle + }, + createLine: function(line){ + // summary: creates an SVG line shape + // line: Object: a line object (see dojox.gfx.defaultLine) + return this.createObject(dojox.gfx.Line, line); // dojox.gfx.Line + }, + createPolyline: function(points){ + // summary: creates an SVG polyline/polygon shape + // points: Object: a points object (see dojox.gfx.defaultPolyline) + // or an Array of points + return this.createObject(dojox.gfx.Polyline, points); // dojox.gfx.Polyline + }, + createImage: function(image){ + // summary: creates an SVG image shape + // image: Object: an image object (see dojox.gfx.defaultImage) + return this.createObject(dojox.gfx.Image, image); // dojox.gfx.Image + }, + createText: function(text){ + // summary: creates an SVG text shape + // text: Object: a text object (see dojox.gfx.defaultText) + return this.createObject(dojox.gfx.Text, text); // dojox.gfx.Text + }, + createPath: function(path){ + // summary: creates an SVG path shape + // path: Object: a path object (see dojox.gfx.defaultPath) + return this.createObject(dojox.gfx.Path, path); // dojox.gfx.Path + }, + createTextPath: function(text){ + // summary: creates an SVG text shape + // text: Object: a textpath object (see dojox.gfx.defaultTextPath) + return this.createObject(dojox.gfx.TextPath, {}).setText(text); // dojox.gfx.TextPath + }, + createObject: function(shapeType, rawShape){ + // summary: creates an instance of the passed shapeType class + // shapeType: Function: a class constructor to create an instance of + // rawShape: Object: properties to be passed in to the classes "setShape" method + + // SHOULD BE RE-IMPLEMENTED BY THE RENDERER! + + return null; // dojox.gfx.Shape + } +}; + +} diff --git a/includes/js/dojox/gfx/silverlight.js b/includes/js/dojox/gfx/silverlight.js new file mode 100644 index 0000000..7a4becc --- /dev/null +++ b/includes/js/dojox/gfx/silverlight.js @@ -0,0 +1,693 @@ +if(!dojo._hasResource["dojox.gfx.silverlight"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.silverlight"] = true; +dojo.provide("dojox.gfx.silverlight"); + +dojo.require("dojox.gfx._base"); +dojo.require("dojox.gfx.shape"); +dojo.require("dojox.gfx.path"); + +dojo.experimental("dojox.gfx.silverlight"); + +dojox.gfx.silverlight.dasharray = { + solid: "none", + shortdash: [4, 1], + shortdot: [1, 1], + shortdashdot: [4, 1, 1, 1], + shortdashdotdot: [4, 1, 1, 1, 1, 1], + dot: [1, 3], + dash: [4, 3], + longdash: [8, 3], + dashdot: [4, 3, 1, 3], + longdashdot: [8, 3, 1, 3], + longdashdotdot: [8, 3, 1, 3, 1, 3] +}; + +dojox.gfx.silverlight.fontweight = { + normal: 400, + bold: 700 +}; + +dojox.gfx.silverlight.caps = {butt: "Flat", round: "Round", square: "Square"}; +dojox.gfx.silverlight.joins = {bevel: "Bevel", round: "Round"}; + +dojox.gfx.silverlight.fonts = { + serif: "Times New Roman", + times: "Times New Roman", + "sans-serif": "Arial", + helvetica: "Arial", + monotone: "Courier New", + courier: "Courier New" +}; + +dojox.gfx.silverlight.hexColor = function(/*String|Array|dojo.Color*/ color){ + // summary: converts a color object to a Silverlight hex color string (#aarrggbb) + var c = dojox.gfx.normalizeColor(color), + t = c.toHex(), a = Math.round(c.a * 255); + a = (a < 0 ? 0 : a > 255 ? 255 : a).toString(16); + return "#" + (a.length < 2 ? "0" + a : a) + t.slice(1); // String +}; + +dojo.extend(dojox.gfx.Shape, { + // summary: Silverlight-specific implementation of dojox.gfx.Shape methods + + setFill: function(fill){ + // summary: sets a fill object (Silverlight) + // fill: Object: a fill object + // (see dojox.gfx.defaultLinearGradient, + // dojox.gfx.defaultRadialGradient, + // dojox.gfx.defaultPattern, + // or dojo.Color) + + var p = this.rawNode.getHost().content, r = this.rawNode, f; + if(!fill){ + // don't fill + this.fillStyle = null; + this._setFillAttr(null); + return this; // self + } + if(typeof(fill) == "object" && "type" in fill){ + // gradient + switch(fill.type){ + case "linear": + this.fillStyle = f = dojox.gfx.makeParameters(dojox.gfx.defaultLinearGradient, fill); + var lgb = p.createFromXaml(""); + lgb.mappingMode = "Absolute"; + lgb.startPoint = f.x1 + "," + f.y1; + lgb.endPoint = f.x2 + "," + f.y2; + dojo.forEach(f.colors, function(c){ + var t = p.createFromXaml(""); + t.offset = c.offset; + t.color = dojox.gfx.silverlight.hexColor(c.color); + lgb.gradientStops.add(t); + }); + this._setFillAttr(lgb); + break; + case "radial": + this.fillStyle = f = dojox.gfx.makeParameters(dojox.gfx.defaultRadialGradient, fill); + var rgb = p.createFromXaml(""), w = r.width, h = r.height, + l = this.rawNode["Canvas.Left"], t = this.rawNode["Canvas.Top"]; + rgb.center = (f.cx - l) / w + "," + (f.cy - t) / h; + rgb.radiusX = f.r / w; + rgb.radiusY = f.r / h; + dojo.forEach(f.colors, function(c){ + var t = p.createFromXaml(""); + t.offset = c.offset; + t.color = dojox.gfx.silverlight.hexColor(c.color); + rgb.gradientStops.add(t); + }); + this._setFillAttr(rgb); + break; + case "pattern": + // don't fill: Silverlight doesn't define TileBrush for some reason + this.fillStyle = null; + this._setFillAttr(null); + break; + } + return this; // self + } + // color object + this.fillStyle = f = dojox.gfx.normalizeColor(fill); + var scb = p.createFromXaml(""); + scb.color = f.toHex(); + scb.opacity = f.a; + this._setFillAttr(scb); + return this; // self + }, + _setFillAttr: function(f){ + this.rawNode.fill = f; + }, + + setStroke: function(stroke){ + // summary: sets a stroke object (Silverlight) + // stroke: Object: a stroke object + // (see dojox.gfx.defaultStroke) + + var p = this.rawNode.getHost().content, r = this.rawNode; + if(!stroke){ + // don't stroke + this.strokeStyle = null; + r.stroke = null; + return this; + } + // normalize the stroke + if(typeof stroke == "string"){ + stroke = {color: stroke}; + } + var s = this.strokeStyle = dojox.gfx.makeParameters(dojox.gfx.defaultStroke, stroke); + s.color = dojox.gfx.normalizeColor(s.color); + // generate attributes + if(s){ + var scb = p.createFromXaml(""); + scb.color = s.color.toHex(); + scb.opacity = s.color.a; + r.stroke = scb; + r.strokeThickness = s.width; + r.strokeStartLineCap = r.strokeEndLineCap = r.strokeDashCap = + dojox.gfx.silverlight.caps[s.cap]; + if(typeof s.join == "number"){ + r.strokeLineJoin = "Miter"; + r.strokeMiterLimit = s.join; + }else{ + r.strokeLineJoin = dojox.gfx.silverlight.joins[s.join]; + } + var da = s.style.toLowerCase(); + if(da in dojox.gfx.silverlight.dasharray){ da = dojox.gfx.silverlight.dasharray[da]; } + if(da instanceof Array){ + da = dojo.clone(da); + /* + for(var i = 0; i < da.length; ++i){ + da[i] *= s.width; + } + */ + if(s.cap != "butt"){ + for(var i = 0; i < da.length; i += 2){ + //da[i] -= s.width; + --da[i] + if(da[i] < 1){ da[i] = 1; } + } + for(var i = 1; i < da.length; i += 2){ + //da[i] += s.width; + ++da[i]; + } + } + r.strokeDashArray = da.join(","); + }else{ + r.strokeDashArray = null; + } + } + return this; // self + }, + + _getParentSurface: function(){ + var surface = this.parent; + for(; surface && !(surface instanceof dojox.gfx.Surface); surface = surface.parent); + return surface; + }, + + _applyTransform: function() { + var tm = this.matrix, r = this.rawNode; + if(tm){ + var p = this.rawNode.getHost().content, + m = p.createFromXaml(""), + mm = p.createFromXaml(""); + mm.m11 = tm.xx; + mm.m21 = tm.xy; + mm.m12 = tm.yx; + mm.m22 = tm.yy; + mm.offsetX = tm.dx; + mm.offsetY = tm.dy; + m.matrix = mm; + r.renderTransform = m; + }else{ + r.renderTransform = null; + } + return this; + }, + + setRawNode: function(rawNode){ + // summary: + // assigns and clears the underlying node that will represent this + // shape. Once set, transforms, gradients, etc, can be applied. + // (no fill & stroke by default) + rawNode.fill = null; + rawNode.stroke = null; + this.rawNode = rawNode; + }, + + // move family + + _moveToFront: function(){ + // summary: moves a shape to front of its parent's list of shapes (Silverlight) + var c = this.parent.rawNode.children, r = this.rawNode; + c.remove(r); + c.add(r); + return this; // self + }, + _moveToBack: function(){ + // summary: moves a shape to back of its parent's list of shapes (Silverlight) + var c = this.parent.rawNode.children, r = this.rawNode; + c.remove(r); + c.insert(0, r); + return this; // self + } +}); + +dojo.declare("dojox.gfx.Group", dojox.gfx.Shape, { + // summary: a group shape (Silverlight), which can be used + // to logically group shapes (e.g, to propagate matricies) + constructor: function(){ + dojox.gfx.silverlight.Container._init.call(this); + }, + setRawNode: function(rawNode){ + // summary: sets a raw Silverlight node to be used by this shape + // rawNode: Node: an Silverlight node + this.rawNode = rawNode; + } +}); +dojox.gfx.Group.nodeType = "Canvas"; + +dojo.declare("dojox.gfx.Rect", dojox.gfx.shape.Rect, { + // summary: a rectangle shape (Silverlight) + setShape: function(newShape){ + // summary: sets a rectangle shape object (Silverlight) + // newShape: Object: a rectangle shape object + this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + var r = this.rawNode, n = this.shape; + r["Canvas.Left"] = n.x; + r["Canvas.Top"] = n.y; + r.width = n.width; + r.height = n.height; + r.radiusX = r.radiusY = n.r; + return this; // self + } +}); +dojox.gfx.Rect.nodeType = "Rectangle"; + +dojo.declare("dojox.gfx.Ellipse", dojox.gfx.shape.Ellipse, { + // summary: an ellipse shape (Silverlight) + setShape: function(newShape){ + // summary: sets an ellipse shape object (Silverlight) + // newShape: Object: an ellipse shape object + this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + var r = this.rawNode, n = this.shape; + r["Canvas.Left"] = n.cx - n.rx; + r["Canvas.Top"] = n.cy - n.ry; + r.width = 2 * n.rx; + r.height = 2 * n.ry; + return this; // self + } +}); +dojox.gfx.Ellipse.nodeType = "Ellipse"; + +dojo.declare("dojox.gfx.Circle", dojox.gfx.shape.Circle, { + // summary: a circle shape (Silverlight) + setShape: function(newShape){ + // summary: sets a circle shape object (Silverlight) + // newShape: Object: a circle shape object + this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + var r = this.rawNode, n = this.shape; + r["Canvas.Left"] = n.cx - n.r; + r["Canvas.Top"] = n.cy - n.r; + r.width = r.height = 2 * n.r; + return this; // self + } +}); +dojox.gfx.Circle.nodeType = "Ellipse"; + +dojo.declare("dojox.gfx.Line", dojox.gfx.shape.Line, { + // summary: a line shape (Silverlight) + setShape: function(newShape){ + // summary: sets a line shape object (Silverlight) + // newShape: Object: a line shape object + this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + var r = this.rawNode, n = this.shape; + r.x1 = n.x1; r.y1 = n.y1; r.x2 = n.x2; r.y2 = n.y2; + return this; // self + } +}); +dojox.gfx.Line.nodeType = "Line"; + +dojo.declare("dojox.gfx.Polyline", dojox.gfx.shape.Polyline, { + // summary: a polyline/polygon shape (Silverlight) + setShape: function(points, closed){ + // summary: sets a polyline/polygon shape object (Silverlight) + // points: Object: a polyline/polygon shape object + if(points && points instanceof Array){ + // branch + // points: Array: an array of points + this.shape = dojox.gfx.makeParameters(this.shape, {points: points}); + if(closed && this.shape.points.length){ + this.shape.points.push(this.shape.points[0]); + } + }else{ + this.shape = dojox.gfx.makeParameters(this.shape, points); + } + this.box = null; + var p = this.shape.points, rp = []; + for(var i = 0; i < p.length; ++i){ + if(typeof p[i] == "number"){ + rp.push(p[i], p[++i]); + }else{ + rp.push(p[i].x, p[i].y); + } + } + this.rawNode.points = rp.join(","); + return this; // self + } +}); +dojox.gfx.Polyline.nodeType = "Polyline"; + +dojo.declare("dojox.gfx.Image", dojox.gfx.shape.Image, { + // summary: an image (Silverlight) + setShape: function(newShape){ + // summary: sets an image shape object (Silverlight) + // newShape: Object: an image shape object + this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + var r = this.rawNode, n = this.shape; + r["Canvas.Left"] = n.x; + r["Canvas.Top"] = n.y; + r.width = n.width; + r.height = n.height; + r.source = n.src; + return this; // self + }, + setRawNode: function(rawNode){ + // summary: + // assigns and clears the underlying node that will represent this + // shape. Once set, transforms, gradients, etc, can be applied. + // (no fill & stroke by default) + this.rawNode = rawNode; + } +}); +dojox.gfx.Image.nodeType = "Image"; + +dojo.declare("dojox.gfx.Text", dojox.gfx.shape.Text, { + // summary: an anchored text (Silverlight) + setShape: function(newShape){ + // summary: sets a text shape object (Silverlight) + // newShape: Object: a text shape object + this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + var r = this.rawNode, s = this.shape; + r.text = s.text; + r.textDecorations = s.decoration == "underline" ? "Underline" : "None"; + r["Canvas.Left"] = -10000; + r["Canvas.Top"] = -10000; + window.setTimeout(dojo.hitch(this, "_delayAlignment"), 0); + return this; // self + }, + _delayAlignment: function(){ + // handle alignment + var r = this.rawNode, s = this.shape, + w = r.actualWidth, h = r.actualHeight, x = s.x, y = s.y - h * 0.75; + switch(s.align){ + case "middle": + x -= w / 2; + break; + case "end": + x -= w; + break; + } + var a = this.matrix ? dojox.gfx.matrix.multiplyPoint(this.matrix, x, y) : {x: x, y: y}; + r["Canvas.Left"] = a.x; + r["Canvas.Top"] = a.y; + }, + setStroke: function(){ + // summary: ignore setting a stroke style + return this; // self + }, + _setFillAttr: function(f){ + this.rawNode.foreground = f; + }, + setRawNode: function(rawNode){ + // summary: + // assigns and clears the underlying node that will represent this + // shape. Once set, transforms, gradients, etc, can be applied. + // (no fill & stroke by default) + this.rawNode = rawNode; + }, + _applyTransform: function() { + var tm = this.matrix, r = this.rawNode; + if(tm){ + // the next line is pure magic :-( + tm = dojox.gfx.matrix.normalize([1/100, tm, 100]); + var p = this.rawNode.getHost().content, + m = p.createFromXaml(""), + mm = p.createFromXaml(""); + mm.m11 = tm.xx; + mm.m21 = tm.xy; + mm.m12 = tm.yx; + mm.m22 = tm.yy; + mm.offsetX = tm.dx; + mm.offsetY = tm.dy; + m.matrix = mm; + r.renderTransform = m; + }else{ + r.renderTransform = null; + } + return this; + }, + getTextWidth: function(){ + // summary: get the text width in pixels + return this.rawNode.actualWidth; + } +}); +dojox.gfx.Text.nodeType = "TextBlock"; + +dojo.declare("dojox.gfx.Path", dojox.gfx.path.Path, { + // summary: a path shape (Silverlight) + _updateWithSegment: function(segment){ + // summary: updates the bounding box of path with new segment + // segment: Object: a segment + dojox.gfx.Path.superclass._updateWithSegment.apply(this, arguments); + var p = this.shape.path; + if(typeof(p) == "string"){ + this.rawNode.data = p ? p : null; + } + }, + setShape: function(newShape){ + // summary: forms a path using a shape (Silverlight) + // newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath) + dojox.gfx.Path.superclass.setShape.apply(this, arguments); + var p = this.shape.path; + this.rawNode.data = p ? p : null; + return this; // self + } +}); +dojox.gfx.Path.nodeType = "Path"; + +dojo.declare("dojox.gfx.TextPath", dojox.gfx.path.TextPath, { + // summary: a textpath shape (Silverlight) + _updateWithSegment: function(segment){ + // summary: updates the bounding box of path with new segment + // segment: Object: a segment + }, + setShape: function(newShape){ + // summary: forms a path using a shape (Silverlight) + // newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath) + }, + _setText: function(){ + } +}); +dojox.gfx.TextPath.nodeType = "text"; + +dojo.declare("dojox.gfx.Surface", dojox.gfx.shape.Surface, { + // summary: a surface object to be used for drawings (Silverlight) + constructor: function(){ + dojox.gfx.silverlight.Container._init.call(this); + }, + setDimensions: function(width, height){ + // summary: sets the width and height of the rawNode + // width: String: width of surface, e.g., "100px" + // height: String: height of surface, e.g., "100px" + this.width = dojox.gfx.normalizedLength(width); // in pixels + this.height = dojox.gfx.normalizedLength(height); // in pixels + var p = this.rawNode && this.rawNode.getHost(); + if(p){ + p.width = width; + p.height = height; + } + return this; // self + }, + getDimensions: function(){ + // summary: returns an object with properties "width" and "height" + var p = this.rawNode && this.rawNode.getHost(); + var t = p ? {width: p.content.actualWidth, height: p.content.actualHeight} : null; + if(t.width <= 0){ t.width = this.width; } + if(t.height <= 0){ t.height = this.height; } + return t; // Object + } +}); + +dojox.gfx.silverlight.surfaces = {}; + +dojox.gfx.createSurface = function(parentNode, width, height){ + // summary: creates a surface (Silverlight) + // parentNode: Node: a parent node + // width: String: width of surface, e.g., "100px" + // height: String: height of surface, e.g., "100px" + + var s = new dojox.gfx.Surface(); + parentNode = dojo.byId(parentNode); + // create an empty canvas + var t = parentNode.ownerDocument.createElement("script"); + t.type = "text/xaml"; + t.id = dojox.gfx._base._getUniqueId(); + t.text = ""; + document.body.appendChild(t); + // create a plugin + var pluginName = dojox.gfx._base._getUniqueId(); + Silverlight.createObject( + "#" + t.id, // none + parentNode, + pluginName, + { // Plugin properties. + width: String(width), // Width of rectangular region of plugin in pixels. + height: String(height), // Height of rectangular region of plugin in pixels. + inplaceInstallPrompt: "false", // Determines whether to display in-place install prompt if invalid version detected. + //background: "white", // Background color of plugin. + //isWindowless: "false", // Determines whether to display plugin in Windowless mode. + background: "transparent", // Background color of plugin. + isWindowless: "true", // Determines whether to display plugin in Windowless mode. + framerate: "24", // MaxFrameRate property value. + version: "1.0" // Silverlight version. + }, + {}, + null, + null + ); + s.rawNode = dojo.byId(pluginName).content.root; + // register the plugin with its parent node + dojox.gfx.silverlight.surfaces[s.rawNode.name] = parentNode; + s.width = dojox.gfx.normalizedLength(width); // in pixels + s.height = dojox.gfx.normalizedLength(height); // in pixels + return s; // dojox.gfx.Surface +}; + +// Extenders + +dojox.gfx.silverlight.Font = { + _setFont: function(){ + // summary: sets a font object (Silverlight) + var f = this.fontStyle, r = this.rawNode, + fw = dojox.gfx.silverlight.fontweight, + fo = dojox.gfx.silverlight.fonts, t = f.family.toLowerCase(); + r.fontStyle = f.style == "italic" ? "Italic" : "Normal"; + r.fontWeight = f.weight in fw ? fw[f.weight] : f.weight; + r.fontSize = dojox.gfx.normalizedLength(f.size); + r.fontFamily = t in fo ? fo[t] : f.family; + } +}; + +dojox.gfx.silverlight.Container = { + _init: function(){ + dojox.gfx.shape.Container._init.call(this); + }, + add: function(shape){ + // summary: adds a shape to a group/surface + // shape: dojox.gfx.Shape: an VML shape object + if(this != shape.getParent()){ + //dojox.gfx.Group.superclass.add.apply(this, arguments); + //this.inherited(arguments); + dojox.gfx.shape.Container.add.apply(this, arguments); + this.rawNode.children.add(shape.rawNode); + } + return this; // self + }, + remove: function(shape, silently){ + // summary: remove a shape from a group/surface + // shape: dojox.gfx.Shape: an VML shape object + // silently: Boolean?: if true, regenerate a picture + if(this == shape.getParent()){ + var parent = shape.rawNode.getParent(); + if(parent){ + parent.children.remove(shape.rawNode); + } + //dojox.gfx.Group.superclass.remove.apply(this, arguments); + //this.inherited(arguments); + dojox.gfx.shape.Container.remove.apply(this, arguments); + } + return this; // self + }, + clear: function(){ + // summary: removes all shapes from a group/surface + this.rawNode.children.clear(); + //return this.inherited(arguments); // self + return dojox.gfx.shape.Container.clear.apply(this, arguments); + }, + _moveChildToFront: dojox.gfx.shape.Container._moveChildToFront, + _moveChildToBack: dojox.gfx.shape.Container._moveChildToBack +}; + +dojo.mixin(dojox.gfx.shape.Creator, { + createObject: function(shapeType, rawShape){ + // summary: creates an instance of the passed shapeType class + // shapeType: Function: a class constructor to create an instance of + // rawShape: Object: properties to be passed in to the classes "setShape" method + if(!this.rawNode){ return null; } + var shape = new shapeType(); + var node = this.rawNode.getHost().content.createFromXaml("<" + shapeType.nodeType + "/>"); + shape.setRawNode(node); + shape.setShape(rawShape); + this.add(shape); + return shape; // dojox.gfx.Shape + } +}); + +dojo.extend(dojox.gfx.Text, dojox.gfx.silverlight.Font); +//dojo.extend(dojox.gfx.TextPath, dojox.gfx.silverlight.Font); + +dojo.extend(dojox.gfx.Group, dojox.gfx.silverlight.Container); +dojo.extend(dojox.gfx.Group, dojox.gfx.shape.Creator); + +dojo.extend(dojox.gfx.Surface, dojox.gfx.silverlight.Container); +dojo.extend(dojox.gfx.Surface, dojox.gfx.shape.Creator); + +(function(){ + var surfaces = dojox.gfx.silverlight.surfaces; + var mouseFix = function(s, a){ + var ev = {target: s, currentTarget: s, + preventDefault: function(){}, stopPropagation: function(){}}; + if(a){ + ev.ctrlKey = a.ctrl; + ev.shiftKey = a.shift; + var p = a.getPosition(null); + ev.x = ev.offsetX = ev.layerX = p.x; + ev.y = ev.offsetY = ev.layerY = p.y; + // calculate clientX and clientY + var parent = surfaces[s.getHost().content.root.name]; + var t = dojo._abs(parent); + ev.clientX = t.x + p.x; + ev.clientY = t.y + p.y; + } + return ev; + }; + var keyFix = function(s, a){ + var ev = { + keyCode: a.platformKeyCode, + ctrlKey: a.ctrl, + shiftKey: a.shift + }; + return ev; + }; + var eventNames = { + onclick: {name: "MouseLeftButtonUp", fix: mouseFix}, + onmouseenter: {name: "MouseEnter", fix: mouseFix}, + onmouseleave: {name: "MouseLeave", fix: mouseFix}, + onmousedown: {name: "MouseLeftButtonDown", fix: mouseFix}, + onmouseup: {name: "MouseLeftButtonUp", fix: mouseFix}, + onmousemove: {name: "MouseMove", fix: mouseFix}, + onkeydown: {name: "KeyDown", fix: keyFix}, + onkeyup: {name: "KeyUp", fix: keyFix} + }; + var eventsProcessing = { + connect: function(name, object, method){ + var token, n = name in eventNames ? eventNames[name] : + {name: name, fix: function(){ return {}; }}; + if(arguments.length > 2){ + token = this.getEventSource().addEventListener(n.name, + function(s, a){ dojo.hitch(object, method)(n.fix(s, a)); }); + }else{ + token = this.getEventSource().addEventListener(n.name, + function(s, a){ object(n.fix(s, a)); }); + } + return {name: n.name, token: token}; + }, + disconnect: function(token){ + this.getEventSource().removeEventListener(token.name, token.token); + } + }; + dojo.extend(dojox.gfx.Shape, eventsProcessing); + dojo.extend(dojox.gfx.Surface, eventsProcessing); + dojox.gfx.equalSources = function(a, b){ + return a && b && a.equals(b); + } + +})(); + +} diff --git a/includes/js/dojox/gfx/silverlight_attach.js b/includes/js/dojox/gfx/silverlight_attach.js new file mode 100644 index 0000000..1f5cd90 --- /dev/null +++ b/includes/js/dojox/gfx/silverlight_attach.js @@ -0,0 +1,87 @@ +dojo.require("dojox.gfx.silverlight"); + +dojo.experimental("dojox.gfx.silverlight_attach"); + +(function(){ + dojox.gfx.attachNode = function(node){ + // summary: creates a shape from a Node + // node: Node: an Silverlight node + return null; // for now + if(!node) return null; + var s = null; + switch(node.tagName.toLowerCase()){ + case dojox.gfx.Rect.nodeType: + s = new dojox.gfx.Rect(node); + break; + case dojox.gfx.Ellipse.nodeType: + if(node.width == node.height){ + s = new dojox.gfx.Circle(node); + }else{ + s = new dojox.gfx.Ellipse(node); + } + break; + case dojox.gfx.Polyline.nodeType: + s = new dojox.gfx.Polyline(node); + break; + case dojox.gfx.Path.nodeType: + s = new dojox.gfx.Path(node); + break; + case dojox.gfx.Line.nodeType: + s = new dojox.gfx.Line(node); + break; + case dojox.gfx.Image.nodeType: + s = new dojox.gfx.Image(node); + break; + case dojox.gfx.Text.nodeType: + s = new dojox.gfx.Text(node); + attachFont(s); + break; + default: + //console.debug("FATAL ERROR! tagName = " + node.tagName); + return null; + } + attachShape(s); + if(!(s instanceof dojox.gfx.Image)){ + attachFill(s); + attachStroke(s); + } + attachTransform(s); + return s; // dojox.gfx.Shape + }; + + dojox.gfx.attachSurface = function(node){ + // summary: creates a surface from a Node + // node: Node: an Silverlight node + return null; // dojox.gfx.Surface + }; + + var attachFill = function(rawNode){ + // summary: deduces a fill style from a Node. + // rawNode: Node: an Silverlight node + return null; // Object + }; + + var attachStroke = function(rawNode){ + // summary: deduces a stroke style from a Node. + // rawNode: Node: an SVG node + return null; // Object + }; + + var attachTransform = function(rawNode){ + // summary: deduces a transformation matrix from a Node. + // rawNode: Node: an Silverlight node + return null; // dojox.gfx.matrix.Matrix + }; + + var attachFont = function(rawNode){ + // summary: deduces a font style from a Node. + // rawNode: Node: an Silverlight node + return null; // Object + }; + + var attachShape = function(rawNode){ + // summary: builds a shape from a Node. + // rawNode: Node: an Silverlight node + return null; // dojox.gfx.Shape + }; +})(); diff --git a/includes/js/dojox/gfx/svg.js b/includes/js/dojox/gfx/svg.js new file mode 100644 index 0000000..5f6101c --- /dev/null +++ b/includes/js/dojox/gfx/svg.js @@ -0,0 +1,638 @@ +if(!dojo._hasResource["dojox.gfx.svg"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.svg"] = true; +dojo.provide("dojox.gfx.svg"); + +dojo.require("dojox.gfx._base"); +dojo.require("dojox.gfx.shape"); +dojo.require("dojox.gfx.path"); + +dojox.gfx.svg.xmlns = { + xlink: "http://www.w3.org/1999/xlink", + svg: "http://www.w3.org/2000/svg" +}; + +dojox.gfx.svg.getRef = function(name){ + // summary: returns a DOM Node specified by the name argument or null + // name: String: an SVG external reference + if(!name || name == "none") return null; + if(name.match(/^url\(#.+\)$/)){ + return dojo.byId(name.slice(5, -1)); // Node + } + // alternative representation of a reference + if(name.match(/^#dojoUnique\d+$/)){ + // we assume here that a reference was generated by dojox.gfx + return dojo.byId(name.slice(1)); // Node + } + return null; // Node +}; + +dojox.gfx.svg.dasharray = { + solid: "none", + shortdash: [4, 1], + shortdot: [1, 1], + shortdashdot: [4, 1, 1, 1], + shortdashdotdot: [4, 1, 1, 1, 1, 1], + dot: [1, 3], + dash: [4, 3], + longdash: [8, 3], + dashdot: [4, 3, 1, 3], + longdashdot: [8, 3, 1, 3], + longdashdotdot: [8, 3, 1, 3, 1, 3] +}; + +dojo.extend(dojox.gfx.Shape, { + // summary: SVG-specific implementation of dojox.gfx.Shape methods + + setFill: function(fill){ + // summary: sets a fill object (SVG) + // fill: Object: a fill object + // (see dojox.gfx.defaultLinearGradient, + // dojox.gfx.defaultRadialGradient, + // dojox.gfx.defaultPattern, + // or dojo.Color) + + if(!fill){ + // don't fill + this.fillStyle = null; + this.rawNode.setAttribute("fill", "none"); + this.rawNode.setAttribute("fill-opacity", 0); + return this; + } + var f; + // FIXME: slightly magical. We're using the outer scope's "f", but setting it later + var setter = function(x){ + // we assume that we're executing in the scope of the node to mutate + this.setAttribute(x, f[x].toFixed(8)); + }; + if(typeof(fill) == "object" && "type" in fill){ + // gradient + switch(fill.type){ + case "linear": + f = dojox.gfx.makeParameters(dojox.gfx.defaultLinearGradient, fill); + var gradient = this._setFillObject(f, "linearGradient"); + dojo.forEach(["x1", "y1", "x2", "y2"], setter, gradient); + break; + case "radial": + f = dojox.gfx.makeParameters(dojox.gfx.defaultRadialGradient, fill); + var gradient = this._setFillObject(f, "radialGradient"); + dojo.forEach(["cx", "cy", "r"], setter, gradient); + break; + case "pattern": + f = dojox.gfx.makeParameters(dojox.gfx.defaultPattern, fill); + var pattern = this._setFillObject(f, "pattern"); + dojo.forEach(["x", "y", "width", "height"], setter, pattern); + break; + } + this.fillStyle = f; + return this; + } + // color object + var f = dojox.gfx.normalizeColor(fill); + this.fillStyle = f; + this.rawNode.setAttribute("fill", f.toCss()); + this.rawNode.setAttribute("fill-opacity", f.a); + this.rawNode.setAttribute("fill-rule", "evenodd"); + return this; // self + }, + + setStroke: function(stroke){ + // summary: sets a stroke object (SVG) + // stroke: Object: a stroke object + // (see dojox.gfx.defaultStroke) + + if(!stroke){ + // don't stroke + this.strokeStyle = null; + this.rawNode.setAttribute("stroke", "none"); + this.rawNode.setAttribute("stroke-opacity", 0); + return this; + } + // normalize the stroke + if(typeof stroke == "string"){ + stroke = {color: stroke}; + } + var s = this.strokeStyle = dojox.gfx.makeParameters(dojox.gfx.defaultStroke, stroke); + s.color = dojox.gfx.normalizeColor(s.color); + // generate attributes + var rn = this.rawNode; + if(s){ + rn.setAttribute("stroke", s.color.toCss()); + rn.setAttribute("stroke-opacity", s.color.a); + rn.setAttribute("stroke-width", s.width); + rn.setAttribute("stroke-linecap", s.cap); + if(typeof s.join == "number"){ + rn.setAttribute("stroke-linejoin", "miter"); + rn.setAttribute("stroke-miterlimit", s.join); + }else{ + rn.setAttribute("stroke-linejoin", s.join); + } + var da = s.style.toLowerCase(); + if(da in dojox.gfx.svg.dasharray){ da = dojox.gfx.svg.dasharray[da]; } + if(da instanceof Array){ + da = dojo.clone(da); + for(var i = 0; i < da.length; ++i){ + da[i] *= s.width; + } + if(s.cap != "butt"){ + for(var i = 0; i < da.length; i += 2){ + da[i] -= s.width; + if(da[i] < 1){ da[i] = 1; } + } + for(var i = 1; i < da.length; i += 2){ + da[i] += s.width; + } + } + da = da.join(","); + } + rn.setAttribute("stroke-dasharray", da); + rn.setAttribute("dojoGfxStrokeStyle", s.style); + } + return this; // self + }, + + _getParentSurface: function(){ + var surface = this.parent; + for(; surface && !(surface instanceof dojox.gfx.Surface); surface = surface.parent); + return surface; + }, + + _setFillObject: function(f, nodeType){ + var svgns = dojox.gfx.svg.xmlns.svg; + this.fillStyle = f; + var surface = this._getParentSurface(), + defs = surface.defNode, + fill = this.rawNode.getAttribute("fill"), + ref = dojox.gfx.svg.getRef(fill); + if(ref){ + fill = ref; + if(fill.tagName.toLowerCase() != nodeType.toLowerCase()){ + var id = fill.id; + fill.parentNode.removeChild(fill); + fill = document.createElementNS(svgns, nodeType); + fill.setAttribute("id", id); + defs.appendChild(fill); + }else{ + while(fill.childNodes.length){ + fill.removeChild(fill.lastChild); + } + } + }else{ + fill = document.createElementNS(svgns, nodeType); + fill.setAttribute("id", dojox.gfx._base._getUniqueId()); + defs.appendChild(fill); + } + if(nodeType == "pattern"){ + if(dojo.isSafari){ + fill.setAttributeNS(null, "patternUnits", "userSpaceOnUse"); + }else{ + fill.setAttribute("patternUnits", "userSpaceOnUse"); + } + var img = document.createElementNS(svgns, "image"); + img.setAttribute("x", 0); + img.setAttribute("y", 0); + img.setAttribute("width", f.width .toFixed(8)); + img.setAttribute("height", f.height.toFixed(8)); + img.setAttributeNS(dojox.gfx.svg.xmlns.xlink, "href", f.src); + fill.appendChild(img); + }else{ + if(dojo.isSafari){ + fill.setAttributeNS(null, "gradientUnits", "userSpaceOnUse"); + }else{ + fill.setAttribute("gradientUnits", "userSpaceOnUse"); + } + for(var i = 0; i < f.colors.length; ++i){ + var c = f.colors[i], t = document.createElementNS(svgns, "stop"), + cc = c.color = dojox.gfx.normalizeColor(c.color); + t.setAttribute("offset", c.offset.toFixed(8)); + t.setAttribute("stop-color", cc.toCss()); + t.setAttribute("stop-opacity", cc.a); + fill.appendChild(t); + } + } + this.rawNode.setAttribute("fill", "url(#" + fill.getAttribute("id") +")"); + this.rawNode.removeAttribute("fill-opacity"); + this.rawNode.setAttribute("fill-rule", "evenodd"); + return fill; + }, + + _applyTransform: function() { + var matrix = this.matrix; + if(matrix){ + var tm = this.matrix; + this.rawNode.setAttribute("transform", "matrix(" + + tm.xx.toFixed(8) + "," + tm.yx.toFixed(8) + "," + + tm.xy.toFixed(8) + "," + tm.yy.toFixed(8) + "," + + tm.dx.toFixed(8) + "," + tm.dy.toFixed(8) + ")"); + }else{ + this.rawNode.removeAttribute("transform"); + } + return this; + }, + + setRawNode: function(rawNode){ + // summary: + // assigns and clears the underlying node that will represent this + // shape. Once set, transforms, gradients, etc, can be applied. + // (no fill & stroke by default) + var r = this.rawNode = rawNode; + r.setAttribute("fill", "none"); + r.setAttribute("fill-opacity", 0); + r.setAttribute("stroke", "none"); + r.setAttribute("stroke-opacity", 0); + r.setAttribute("stroke-width", 1); + r.setAttribute("stroke-linecap", "butt"); + r.setAttribute("stroke-linejoin", "miter"); + r.setAttribute("stroke-miterlimit", 4); + }, + + setShape: function(newShape){ + // summary: sets a shape object (SVG) + // newShape: Object: a shape object + // (see dojox.gfx.defaultPath, + // dojox.gfx.defaultPolyline, + // dojox.gfx.defaultRect, + // dojox.gfx.defaultEllipse, + // dojox.gfx.defaultCircle, + // dojox.gfx.defaultLine, + // or dojox.gfx.defaultImage) + this.shape = dojox.gfx.makeParameters(this.shape, newShape); + for(var i in this.shape){ + if(i != "type"){ this.rawNode.setAttribute(i, this.shape[i]); } + } + return this; // self + }, + + // move family + + _moveToFront: function(){ + // summary: moves a shape to front of its parent's list of shapes (SVG) + this.rawNode.parentNode.appendChild(this.rawNode); + return this; // self + }, + _moveToBack: function(){ + // summary: moves a shape to back of its parent's list of shapes (SVG) + this.rawNode.parentNode.insertBefore(this.rawNode, this.rawNode.parentNode.firstChild); + return this; // self + } +}); + +dojo.declare("dojox.gfx.Group", dojox.gfx.Shape, { + // summary: a group shape (SVG), which can be used + // to logically group shapes (e.g, to propagate matricies) + constructor: function(){ + dojox.gfx.svg.Container._init.call(this); + }, + setRawNode: function(rawNode){ + // summary: sets a raw SVG node to be used by this shape + // rawNode: Node: an SVG node + this.rawNode = rawNode; + } +}); +dojox.gfx.Group.nodeType = "g"; + +dojo.declare("dojox.gfx.Rect", dojox.gfx.shape.Rect, { + // summary: a rectangle shape (SVG) + setShape: function(newShape){ + // summary: sets a rectangle shape object (SVG) + // newShape: Object: a rectangle shape object + this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + for(var i in this.shape){ + if(i != "type" && i != "r"){ this.rawNode.setAttribute(i, this.shape[i]); } + } + if(this.shape.r){ + this.rawNode.setAttribute("ry", this.shape.r); + this.rawNode.setAttribute("rx", this.shape.r); + } + return this; // self + } +}); +dojox.gfx.Rect.nodeType = "rect"; + +dojox.gfx.Ellipse = dojox.gfx.shape.Ellipse; +dojox.gfx.Ellipse.nodeType = "ellipse"; + +dojox.gfx.Circle = dojox.gfx.shape.Circle; +dojox.gfx.Circle.nodeType = "circle"; + +dojox.gfx.Line = dojox.gfx.shape.Line; +dojox.gfx.Line.nodeType = "line"; + +dojo.declare("dojox.gfx.Polyline", dojox.gfx.shape.Polyline, { + // summary: a polyline/polygon shape (SVG) + setShape: function(points, closed){ + // summary: sets a polyline/polygon shape object (SVG) + // points: Object: a polyline/polygon shape object + if(points && points instanceof Array){ + // branch + // points: Array: an array of points + this.shape = dojox.gfx.makeParameters(this.shape, { points: points }); + if(closed && this.shape.points.length){ + this.shape.points.push(this.shape.points[0]); + } + }else{ + this.shape = dojox.gfx.makeParameters(this.shape, points); + } + this.box = null; + var attr = [], p = this.shape.points; + for(var i = 0; i < p.length; ++i){ + if(typeof p[i] == "number"){ + attr.push(p[i].toFixed(8)); + }else{ + attr.push(p[i].x.toFixed(8)); + attr.push(p[i].y.toFixed(8)); + } + } + this.rawNode.setAttribute("points", attr.join(" ")); + return this; // self + } +}); +dojox.gfx.Polyline.nodeType = "polyline"; + +dojo.declare("dojox.gfx.Image", dojox.gfx.shape.Image, { + // summary: an image (SVG) + setShape: function(newShape){ + // summary: sets an image shape object (SVG) + // newShape: Object: an image shape object + this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + var rawNode = this.rawNode; + for(var i in this.shape){ + if(i != "type" && i != "src"){ rawNode.setAttribute(i, this.shape[i]); } + } + rawNode.setAttributeNS(dojox.gfx.svg.xmlns.xlink, "href", this.shape.src); + return this; // self + } +}); +dojox.gfx.Image.nodeType = "image"; + +dojo.declare("dojox.gfx.Text", dojox.gfx.shape.Text, { + // summary: an anchored text (SVG) + setShape: function(newShape){ + // summary: sets a text shape object (SVG) + // newShape: Object: a text shape object + this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + var r = this.rawNode, s = this.shape; + r.setAttribute("x", s.x); + r.setAttribute("y", s.y); + r.setAttribute("text-anchor", s.align); + r.setAttribute("text-decoration", s.decoration); + r.setAttribute("rotate", s.rotated ? 90 : 0); + r.setAttribute("kerning", s.kerning ? "auto" : 0); + r.setAttribute("text-rendering", "optimizeLegibility"); + r.textContent = s.text; + return this; // self + }, + getTextWidth: function(){ + // summary: get the text width in pixels + var rawNode = this.rawNode, + oldParent = rawNode.parentNode, + _measurementNode = rawNode.cloneNode(true); + _measurementNode.style.visibility = "hidden"; + + // solution to the "orphan issue" in FF + var _width = 0, _text = _measurementNode.firstChild.nodeValue; + oldParent.appendChild(_measurementNode); + + // solution to the "orphan issue" in Opera + // (nodeValue == "" hangs firefox) + if(_text!=""){ + while(!_width){ + _width = parseInt(_measurementNode.getBBox().width); + } + } + oldParent.removeChild(_measurementNode); + return _width; + } +}); +dojox.gfx.Text.nodeType = "text"; + +dojo.declare("dojox.gfx.Path", dojox.gfx.path.Path, { + // summary: a path shape (SVG) + _updateWithSegment: function(segment){ + // summary: updates the bounding box of path with new segment + // segment: Object: a segment + dojox.gfx.Path.superclass._updateWithSegment.apply(this, arguments); + if(typeof(this.shape.path) == "string"){ + this.rawNode.setAttribute("d", this.shape.path); + } + }, + setShape: function(newShape){ + // summary: forms a path using a shape (SVG) + // newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath) + dojox.gfx.Path.superclass.setShape.apply(this, arguments); + this.rawNode.setAttribute("d", this.shape.path); + return this; // self + } +}); +dojox.gfx.Path.nodeType = "path"; + +dojo.declare("dojox.gfx.TextPath", dojox.gfx.path.TextPath, { + // summary: a textpath shape (SVG) + _updateWithSegment: function(segment){ + // summary: updates the bounding box of path with new segment + // segment: Object: a segment + dojox.gfx.Path.superclass._updateWithSegment.apply(this, arguments); + this._setTextPath(); + }, + setShape: function(newShape){ + // summary: forms a path using a shape (SVG) + // newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath) + dojox.gfx.Path.superclass.setShape.apply(this, arguments); + this._setTextPath(); + return this; // self + }, + _setTextPath: function(){ + if(typeof this.shape.path != "string"){ return; } + var r = this.rawNode; + if(!r.firstChild){ + var tp = document.createElementNS(dojox.gfx.svg.xmlns.svg, "textPath"), + tx = document.createTextNode(""); + tp.appendChild(tx); + r.appendChild(tp); + } + var ref = r.firstChild.getAttributeNS(dojox.gfx.svg.xmlns.xlink, "href"), + path = ref && dojox.gfx.svg.getRef(ref); + if(!path){ + var surface = this._getParentSurface(); + if(surface){ + var defs = surface.defNode; + path = document.createElementNS(dojox.gfx.svg.xmlns.svg, "path"); + var id = dojox.gfx._base._getUniqueId(); + path.setAttribute("id", id); + defs.appendChild(path); + r.firstChild.setAttributeNS(dojox.gfx.svg.xmlns.xlink, "href", "#" + id); + } + } + if(path){ + path.setAttribute("d", this.shape.path); + } + }, + _setText: function(){ + var r = this.rawNode; + if(!r.firstChild){ + var tp = document.createElementNS(dojox.gfx.svg.xmlns.svg, "textPath"), + tx = document.createTextNode(""); + tp.appendChild(tx); + r.appendChild(tp); + } + r = r.firstChild; + var t = this.text; + r.setAttribute("alignment-baseline", "middle"); + switch(t.align){ + case "middle": + r.setAttribute("text-anchor", "middle"); + r.setAttribute("startOffset", "50%"); + break; + case "end": + r.setAttribute("text-anchor", "end"); + r.setAttribute("startOffset", "100%"); + break; + default: + r.setAttribute("text-anchor", "start"); + r.setAttribute("startOffset", "0%"); + break; + } + //r.parentNode.setAttribute("alignment-baseline", "central"); + //r.setAttribute("dominant-baseline", "central"); + r.setAttribute("baseline-shift", "0.5ex"); + r.setAttribute("text-decoration", t.decoration); + r.setAttribute("rotate", t.rotated ? 90 : 0); + r.setAttribute("kerning", t.kerning ? "auto" : 0); + r.firstChild.data = t.text; + } +}); +dojox.gfx.TextPath.nodeType = "text"; + +dojo.declare("dojox.gfx.Surface", dojox.gfx.shape.Surface, { + // summary: a surface object to be used for drawings (SVG) + constructor: function(){ + dojox.gfx.svg.Container._init.call(this); + }, + setDimensions: function(width, height){ + // summary: sets the width and height of the rawNode + // width: String: width of surface, e.g., "100px" + // height: String: height of surface, e.g., "100px" + if(!this.rawNode){ return this; } + this.rawNode.setAttribute("width", width); + this.rawNode.setAttribute("height", height); + return this; // self + }, + getDimensions: function(){ + // summary: returns an object with properties "width" and "height" + return this.rawNode ? {width: this.rawNode.getAttribute("width"), height: this.rawNode.getAttribute("height")} : null; // Object + } +}); + +dojox.gfx.createSurface = function(parentNode, width, height){ + // summary: creates a surface (SVG) + // parentNode: Node: a parent node + // width: String: width of surface, e.g., "100px" + // height: String: height of surface, e.g., "100px" + + var s = new dojox.gfx.Surface(); + s.rawNode = document.createElementNS(dojox.gfx.svg.xmlns.svg, "svg"); + s.rawNode.setAttribute("width", width); + s.rawNode.setAttribute("height", height); + + var node = document.createElementNS(dojox.gfx.svg.xmlns.svg, "defs"); + s.rawNode.appendChild(node); + s.defNode = node; + + dojo.byId(parentNode).appendChild(s.rawNode); + return s; // dojox.gfx.Surface +}; + +// Extenders + +dojox.gfx.svg.Font = { + _setFont: function(){ + // summary: sets a font object (SVG) + var f = this.fontStyle; + // next line doesn't work in Firefox 2 or Opera 9 + //this.rawNode.setAttribute("font", dojox.gfx.makeFontString(this.fontStyle)); + this.rawNode.setAttribute("font-style", f.style); + this.rawNode.setAttribute("font-variant", f.variant); + this.rawNode.setAttribute("font-weight", f.weight); + this.rawNode.setAttribute("font-size", f.size); + this.rawNode.setAttribute("font-family", f.family); + } +}; + +dojox.gfx.svg.Container = { + _init: function(){ + dojox.gfx.shape.Container._init.call(this); + }, + add: function(shape){ + // summary: adds a shape to a group/surface + // shape: dojox.gfx.Shape: an VML shape object + if(this != shape.getParent()){ + this.rawNode.appendChild(shape.rawNode); + //dojox.gfx.Group.superclass.add.apply(this, arguments); + //this.inherited(arguments); + dojox.gfx.shape.Container.add.apply(this, arguments); + } + return this; // self + }, + remove: function(shape, silently){ + // summary: remove a shape from a group/surface + // shape: dojox.gfx.Shape: an VML shape object + // silently: Boolean?: if true, regenerate a picture + if(this == shape.getParent()){ + if(this.rawNode == shape.rawNode.parentNode){ + this.rawNode.removeChild(shape.rawNode); + } + //dojox.gfx.Group.superclass.remove.apply(this, arguments); + //this.inherited(arguments); + dojox.gfx.shape.Container.remove.apply(this, arguments); + } + return this; // self + }, + clear: function(){ + // summary: removes all shapes from a group/surface + var r = this.rawNode; + while(r.lastChild){ + r.removeChild(r.lastChild); + } + var d = this.defNode; + if(d){ + while(d.lastChild){ + d.removeChild(d.lastChild); + } + r.appendChild(d); + } + //return this.inherited(arguments); // self + return dojox.gfx.shape.Container.clear.apply(this, arguments); + }, + _moveChildToFront: dojox.gfx.shape.Container._moveChildToFront, + _moveChildToBack: dojox.gfx.shape.Container._moveChildToBack +}; + +dojo.mixin(dojox.gfx.shape.Creator, { + // summary: SVG shape creators + createObject: function(shapeType, rawShape){ + // summary: creates an instance of the passed shapeType class + // shapeType: Function: a class constructor to create an instance of + // rawShape: Object: properties to be passed in to the classes "setShape" method + if(!this.rawNode){ return null; } + var shape = new shapeType(), + node = document.createElementNS(dojox.gfx.svg.xmlns.svg, shapeType.nodeType); + shape.setRawNode(node); + this.rawNode.appendChild(node); + shape.setShape(rawShape); + this.add(shape); + return shape; // dojox.gfx.Shape + } +}); + +dojo.extend(dojox.gfx.Text, dojox.gfx.svg.Font); +dojo.extend(dojox.gfx.TextPath, dojox.gfx.svg.Font); + +dojo.extend(dojox.gfx.Group, dojox.gfx.svg.Container); +dojo.extend(dojox.gfx.Group, dojox.gfx.shape.Creator); + +dojo.extend(dojox.gfx.Surface, dojox.gfx.svg.Container); +dojo.extend(dojox.gfx.Surface, dojox.gfx.shape.Creator); + +} diff --git a/includes/js/dojox/gfx/svg_attach.js b/includes/js/dojox/gfx/svg_attach.js new file mode 100644 index 0000000..7ec9ed8 --- /dev/null +++ b/includes/js/dojox/gfx/svg_attach.js @@ -0,0 +1,224 @@ +dojo.require("dojox.gfx.svg"); + +dojo.experimental("dojox.gfx.svg_attach"); + +(function(){ + dojox.gfx.attachNode = function(node){ + // summary: creates a shape from a Node + // node: Node: an SVG node + if(!node) return null; + var s = null; + switch(node.tagName.toLowerCase()){ + case dojox.gfx.Rect.nodeType: + s = new dojox.gfx.Rect(node); + attachRect(s); + break; + case dojox.gfx.Ellipse.nodeType: + s = new dojox.gfx.Ellipse(node); + attachShape(s, dojox.gfx.defaultEllipse); + break; + case dojox.gfx.Polyline.nodeType: + s = new dojox.gfx.Polyline(node); + attachShape(s, dojox.gfx.defaultPolyline); + break; + case dojox.gfx.Path.nodeType: + s = new dojox.gfx.Path(node); + attachShape(s, dojox.gfx.defaultPath); + break; + case dojox.gfx.Circle.nodeType: + s = new dojox.gfx.Circle(node); + attachShape(s, dojox.gfx.defaultCircle); + break; + case dojox.gfx.Line.nodeType: + s = new dojox.gfx.Line(node); + attachShape(s, dojox.gfx.defaultLine); + break; + case dojox.gfx.Image.nodeType: + s = new dojox.gfx.Image(node); + attachShape(s, dojox.gfx.defaultImage); + break; + case dojox.gfx.Text.nodeType: + var t = node.getElementsByTagName("textPath"); + if(t && t.length){ + s = new dojox.gfx.TextPath(node); + attachShape(s, dojox.gfx.defaultPath); + attachTextPath(s); + }else{ + s = new dojox.gfx.Text(node); + attachText(s); + } + attachFont(s); + break; + default: + //console.debug("FATAL ERROR! tagName = " + node.tagName); + return null; + } + if(!(s instanceof dojox.gfx.Image)){ + attachFill(s); + attachStroke(s); + } + attachTransform(s); + return s; // dojox.gfx.Shape + }; + + dojox.gfx.attachSurface = function(node){ + // summary: creates a surface from a Node + // node: Node: an SVG node + var s = new dojox.gfx.Surface(); + s.rawNode = node; + var def_elems = node.getElementsByTagName("defs"); + if(def_elems.length == 0){ + return null; // dojox.gfx.Surface + } + s.defNode = def_elems[0]; + return s; // dojox.gfx.Surface + }; + + var attachFill = function(object){ + // summary: deduces a fill style from a node. + // object: dojox.gfx.Shape: an SVG shape + var fill = object.rawNode.getAttribute("fill"); + if(fill == "none"){ + object.fillStyle = null; + return; + } + var fillStyle = null, gradient = dojox.gfx.svg.getRef(fill); + if(ref){ + switch(gradient.tagName.toLowerCase()){ + case "lineargradient": + fillStyle = _getGradient(dojox.gfx.defaultLinearGradient, gradient); + dojo.forEach(["x1", "y1", "x2", "y2"], function(x){ + fillStyle[x] = gradient.getAttribute(x); + }); + break; + case "radialgradient": + fillStyle = _getGradient(dojox.gfx.defaultRadialGradient, gradient); + dojo.forEach(["cx", "cy", "r"], function(x){ + fillStyle[x] = gradient.getAttribute(x); + }); + fillStyle.cx = gradient.getAttribute("cx"); + fillStyle.cy = gradient.getAttribute("cy"); + fillStyle.r = gradient.getAttribute("r"); + break; + case "pattern": + fillStyle = dojo.lang.shallowCopy(dojox.gfx.defaultPattern, true); + dojo.forEach(["x", "y", "width", "height"], function(x){ + fillStyle[x] = gradient.getAttribute(x); + }); + fillStyle.src = gradient.firstChild.getAttributeNS(dojox.gfx.svg.xmlns.xlink, "href"); + break; + } + }else{ + fillStyle = new dojo.Color(fill); + var opacity = rawNode.getAttribute("fill-opacity"); + if(opacity != null){ fillStyle.a = opacity; } + } + object.fillStyle = fillStyle; + }; + + var _getGradient = function(defaultGradient, gradient){ + var fillStyle = dojo.clone(defaultGradient); + fillStyle.colors = []; + for(var i = 0; i < gradient.childNodes.length; ++i){ + fillStyle.colors.push({ + offset: gradient.childNodes[i].getAttribute("offset"), + color: new dojo.Color(gradient.childNodes[i].getAttribute("stop-color")) + }); + } + return fillStyle; + }; + + var attachStroke = function(object){ + // summary: deduces a stroke style from a node. + // object: dojox.gfx.Shape: an SVG shape + var rawNode = object.rawNode, stroke = rawNode.getAttribute("stroke"); + if(stroke == null || stroke == "none"){ + object.strokeStyle = null; + return; + } + var strokeStyle = object.strokeStyle = dojo.clone(dojox.gfx.defaultStroke); + var color = new dojo.Color(stroke); + if(color){ + strokeStyle.color = color; + strokeStyle.color.a = rawNode.getAttribute("stroke-opacity"); + strokeStyle.width = rawNode.getAttribute("stroke-width"); + strokeStyle.cap = rawNode.getAttribute("stroke-linecap"); + strokeStyle.join = rawNode.getAttribute("stroke-linejoin"); + if(strokeStyle.join == "miter"){ + strokeStyle.join = rawNode.getAttribute("stroke-miterlimit"); + } + strokeStyle.style = rawNode.getAttribute("dojoGfxStrokeStyle"); + } + }; + + var attachTransform = function(object){ + // summary: deduces a transformation matrix from a node. + // object: dojox.gfx.Shape: an SVG shape + var matrix = object.rawNode.getAttribute("transform"); + if(matrix.match(/^matrix\(.+\)$/)){ + var t = matrix.slice(7, -1).split(","); + object.matrix = dojox.gfx.matrix.normalize({ + xx: parseFloat(t[0]), xy: parseFloat(t[2]), + yx: parseFloat(t[1]), yy: parseFloat(t[3]), + dx: parseFloat(t[4]), dy: parseFloat(t[5]) + }); + }else{ + object.matrix = null; + } + }; + + var attachFont = function(object){ + // summary: deduces a font style from a Node. + // object: dojox.gfx.Shape: an SVG shape + var fontStyle = object.fontStyle = dojo.clone(dojox.gfx.defaultFont), + r = object.rawNode; + fontStyle.style = r.getAttribute("font-style"); + fontStyle.variant = r.getAttribute("font-variant"); + fontStyle.weight = r.getAttribute("font-weight"); + fontStyle.size = r.getAttribute("font-size"); + fontStyle.family = r.getAttribute("font-family"); + }; + + var attachShape = function(object, def){ + // summary: builds a shape from a node. + // object: dojox.gfx.Shape: an SVG shape + // def: Object: a default shape template + var shape = object.shape = dojo.clone(def), r = object.rawNode; + for(var i in shape) { + shape[i] = r.getAttribute(i); + } + }; + + var attachRect = function(object){ + // summary: builds a rectangle shape from a node. + // object: dojox.gfx.Shape: an SVG shape + attachShape(object, dojox.gfx.defaultRect); + object.shape.r = Math.min(object.rawNode.getAttribute("rx"), object.rawNode.getAttribute("ry")); + }; + + var attachText = function(object){ + // summary: builds a text shape from a node. + // object: dojox.gfx.Shape: an SVG shape + var shape = object.shape = dojo.clone(dojox.gfx.defaultText), + r = object.rawNode; + shape.x = r.getAttribute("x"); + shape.y = r.getAttribute("y"); + shape.align = r.getAttribute("text-anchor"); + shape.decoration = r.getAttribute("text-decoration"); + shape.rotated = parseFloat(r.getAttribute("rotate")) != 0; + shape.kerning = r.getAttribute("kerning") == "auto"; + shape.text = r.firstChild.nodeValue; + }; + + var attachTextPath = function(object){ + // summary: builds a textpath shape from a node. + // object: dojox.gfx.Shape: an SVG shape + var shape = object.shape = dojo.clone(dojox.gfx.defaultTextPath), + r = object.rawNode; + shape.align = r.getAttribute("text-anchor"); + shape.decoration = r.getAttribute("text-decoration"); + shape.rotated = parseFloat(r.getAttribute("rotate")) != 0; + shape.kerning = r.getAttribute("kerning") == "auto"; + shape.text = r.firstChild.nodeValue; + }; +})(); diff --git a/includes/js/dojox/gfx/tests/decompose.js b/includes/js/dojox/gfx/tests/decompose.js new file mode 100644 index 0000000..b488bdd --- /dev/null +++ b/includes/js/dojox/gfx/tests/decompose.js @@ -0,0 +1,114 @@ +if(!dojo._hasResource["dojox.gfx.tests.decompose"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.tests.decompose"] = true; +dojo.provide("dojox.gfx.tests.decompose"); +dojo.require("dojox.gfx.decompose"); + +(function(){ + var m = dojox.gfx.matrix; + var eq = function(t, a, b){ t.t(2 * Math.abs(a - b) / ((a < 1 && b < 1) ? 1 : a + b) < 1e-6); }; + var eqM = function(t, a, b){ + eq(t, a.xx, b.xx); + eq(t, a.yy, b.yy); + eq(t, a.xy, b.xy); + eq(t, a.yx, b.yx); + eq(t, a.dx, b.dx); + eq(t, a.dy, b.dy); + }; + var compose = function(r){ + return m.normalize([ + m.translate(r.dx, r.dy), + m.rotate(r.angle2), + m.scale(r.sx, r.sy), + m.rotate(r.angle1) + ]); + }; + var reconstruct = function(a){ + return compose(dojox.gfx.decompose(a)); + }; + var compare = function(t, a){ + var A = m.normalize(a); + eqM(t, A, reconstruct(A)); + }; + tests.register("dojox.gfx.tests.decompose", [ + function IdentityTest(t){ + compare(t, m.identity); + }, + function FlipXTest(t){ + compare(t, m.flipX); + }, + function FlipYTest(t){ + compare(t, m.flipY); + }, + function FlipXYTest(t){ + compare(t, m.flipXY); + }, + function TranslationTest(t){ + compare(t, m.translate(45, -15)); + }, + function RotationTest(t){ + compare(t, m.rotateg(35)); + }, + function SkewXTest(t){ + compare(t, m.skewXg(35)); + }, + function SkewYTest(t){ + compare(t, m.skewYg(35)); + }, + function ReflectTest(t){ + compare(t, m.reflect(13, 27)); + }, + function ProjectTest(t){ + compare(t, m.project(13, 27)); + }, + function ScaleTest1(t){ + compare(t, m.scale(3)); + }, + function ScaleTest2(t){ + compare(t, m.scale(3, -1)); + }, + function ScaleTest3(t){ + compare(t, m.scale(-3, 1)); + }, + function ScaleTest4(t){ + compare(t, m.scale(-3, -1)); + }, + function ScaleRotateTest1(t){ + compare(t, [m.scale(3), m.rotateAt(35, 13, 27)]); + }, + function ScaleRotateTest2(t){ + compare(t, [m.scale(3, -1), m.rotateAt(35, 13, 27)]); + }, + function ScaleRotateTest3(t){ + compare(t, [m.scale(-3, 1), m.rotateAt(35, 13, 27)]); + }, + function ScaleRotateTest4(t){ + compare(t, [m.scale(-3, -1), m.rotateAt(35, 13, 27)]); + }, + function RotateScaleTest1(t){ + compare(t, [m.rotateAt(35, 13, 27), m.scale(3)]); + }, + function RotateScaleTest2(t){ + compare(t, [m.rotateAt(35, 13, 27), m.scale(3, -1)]); + }, + function RotateScaleTest3(t){ + compare(t, [m.rotateAt(35, 13, 27), m.scale(-3, 1)]); + }, + function RotateScaleTest4(t){ + compare(t, [m.rotateAt(35, 13, 27), m.scale(-3, -1)]); + }, + function RotateScaleRotateTest1(t){ + compare(t, [m.rotateAt(35, 13, 27), m.scale(3), m.rotateAt(-15, 163, -287)]); + }, + function RotateScaleRotateTest2(t){ + compare(t, [m.rotateAt(35, 13, 27), m.scale(3, -1), m.rotateAt(-15, 163, -287)]); + }, + function RotateScaleRotateTest3(t){ + compare(t, [m.rotateAt(35, 13, 27), m.scale(-3, 1), m.rotateAt(-15, 163, -287)]); + }, + function RotateScaleRotateTest4(t){ + compare(t, [m.rotateAt(35, 13, 27), m.scale(-3, -1), m.rotateAt(-15, 163, -287)]); + } + ]); +})(); + +} diff --git a/includes/js/dojox/gfx/tests/matrix.js b/includes/js/dojox/gfx/tests/matrix.js new file mode 100644 index 0000000..282ec36 --- /dev/null +++ b/includes/js/dojox/gfx/tests/matrix.js @@ -0,0 +1,228 @@ +if(!dojo._hasResource["dojox.gfx.tests.matrix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.tests.matrix"] = true; +dojo.provide("dojox.gfx.tests.matrix"); +dojo.require("dojox.gfx.matrix"); + +(function(){ + var m = dojox.gfx.matrix; + var eq = function(t, a, b){ t.t(2 * Math.abs(a - b) / ((a < 1 && b < 1) ? 1 : a + b) < 1e-6); }; + tests.register("dojox.gfx.tests.matrix", [ + function IdentityTest(t){ + var a = new m.Matrix2D(); + eq(t, a.xx, 1); + eq(t, a.yy, 1); + eq(t, a.xy, 0); + eq(t, a.yx, 0); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + }, + function Rot30gTest(t){ + var a = m.rotateg(30); + eq(t, a.xx, a.yy); + eq(t, a.xy, -a.yx); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + eq(t, a.yx, 0.5); + t.t(a.xy < 0); + t.t(a.yx > 0); + }, + function Rot45gTest(t){ + var a = m.rotateg(45); + eq(t, a.xx, a.yy); + eq(t, a.xy, -a.yx); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + eq(t, a.xx, a.yx); + eq(t, a.yy, -a.xy); + }, + function Rot90gTest(t){ + var a = m.rotateg(90); + eq(t, a.xx, a.yy); + eq(t, a.xy, -a.yx); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + eq(t, a.xx, 0); + eq(t, a.yx, 1); + }, + function CombineIdentitiesTest(t){ + var a = m.normalize([new m.Matrix2D(), new m.Matrix2D(), new m.Matrix2D()]); + eq(t, a.xx, 1); + eq(t, a.yy, 1); + eq(t, a.xy, 0); + eq(t, a.yx, 0); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + }, + function CombineExclusiveTest(t){ + var a = m.normalize([m.rotateg(30), m.rotateg(-30)]); + eq(t, a.xx, 1); + eq(t, a.yy, 1); + eq(t, a.xy, 0); + eq(t, a.yx, 0); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + }, + function CombineInvertedTest(t){ + var a = m.normalize([m.rotateg(30), m.invert(m.rotateg(30))]); + eq(t, a.xx, 1); + eq(t, a.yy, 1); + eq(t, a.xy, 0); + eq(t, a.yx, 0); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + }, + function Rot90gAtTest(t){ + var a = m.rotategAt(90, 10, 10); + eq(t, a.xx, a.yy); + eq(t, a.xy, -a.yx); + eq(t, a.dx, 20); + eq(t, a.dy, 0); + eq(t, a.xx, 0); + eq(t, a.yx, 1); + }, + function MultPointTest1(t){ + var b = m.multiplyPoint(m.rotategAt(90, 10, 10), 10, 10); + eq(t, b.x, 10); + eq(t, b.y, 10); + }, + function MultPointTest2(t){ + var b = m.multiplyPoint(m.rotategAt(90, 10, 10), {x: 10, y: 5}); + eq(t, b.x, 15); + eq(t, b.y, 10); + }, + function MultPointTest3(t){ + var b = m.multiplyPoint(m.rotategAt(90, 10, 10), 10, 15); + eq(t, b.x, 5); + eq(t, b.y, 10); + }, + function ScaleTest1(t){ + var a = m.normalize([m.scale(2, 1), m.invert(m.rotateg(45))]); + eq(t, a.xx, 2 * a.yy); + eq(t, a.xy, -2 * a.yx); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + eq(t, a.xx, a.xy); + eq(t, a.yy, -a.yx); + }, + function ScaleTest2(t){ + var a = m.normalize([m.scale(1, 2), m.invert(m.rotateg(45))]); + eq(t, 2 * a.xx, a.yy); + eq(t, 2 * a.xy, -a.yx); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + eq(t, a.xx, a.xy); + eq(t, a.yy, -a.yx); + }, + function ScaleTest3(t){ + var a = m.normalize([m.rotateg(45), m.scale(2, 1)]); + eq(t, a.xx, 2 * a.yy); + eq(t, a.yx, -2 * a.xy); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + eq(t, a.xx, a.yx); + eq(t, a.yy, -a.xy); + }, + function ScaleTest4(t){ + var a = m.normalize([m.rotateg(45), m.scale(1, 2)]); + eq(t, 2 * a.xx, a.yy); + eq(t, 2 * a.yx, -a.xy); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + eq(t, a.xx, a.yx); + eq(t, a.yy, -a.xy); + }, + function ScaleTest5(t){ + var a = m.normalize([m.rotategAt(45, 100, 100), m.scale(2)]); + eq(t, a.xx, a.yy); + eq(t, a.xy, -a.yx); + eq(t, a.xx, a.yx); + eq(t, a.yy, -a.xy); + eq(t, a.dx, 100); + t.t(a.dy < 0); + var b = m.normalize([m.scale(2), m.rotategAt(45, 100, 100)]); + eq(t, b.xx, b.yy); + eq(t, b.xy, -b.yx); + eq(t, b.xx, b.yx); + eq(t, b.yy, -b.xy); + eq(t, b.dx, 200); + t.t(b.dy < 0); + eq(t, a.xx, b.xx); + eq(t, a.xy, b.xy); + eq(t, a.yx, b.yx); + eq(t, a.yy, b.yy); + eq(t, 2 * a.dx, b.dx); + eq(t, 2 * a.dy, b.dy); + var c = m.normalize([m.rotateg(45), m.scale(2)]); + eq(t, c.xx, c.yy); + eq(t, c.xy, -c.yx); + eq(t, c.xx, c.yx); + eq(t, c.yy, -c.xy); + eq(t, c.dx, 0); + eq(t, c.dy, 0); + var d = m.normalize([m.scale(2), m.rotateg(45)]); + eq(t, d.xx, d.yy); + eq(t, d.xy, -d.yx); + eq(t, d.xx, d.yx); + eq(t, d.yy, -d.xy); + eq(t, d.dx, 0); + eq(t, d.dy, 0); + eq(t, a.xx, c.xx); + eq(t, a.xy, c.xy); + eq(t, a.yx, c.yx); + eq(t, a.yy, c.yy); + eq(t, a.xx, d.xx); + eq(t, a.xy, d.xy); + eq(t, a.yx, d.yx); + eq(t, a.yy, d.yy); + }, + function ScaleTest6(t){ + var a = m.normalize(6); + eq(t, a.xx, 6); + eq(t, a.yy, 6); + eq(t, a.xy, 0); + eq(t, a.yx, 0); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + }, + function ScaleTest7(t){ + var a = m.normalize([2, m.scale(2, 1)]); + eq(t, a.xx, 4); + eq(t, a.yy, 2); + eq(t, a.xy, 0); + eq(t, a.yx, 0); + eq(t, a.dx, 0); + eq(t, a.dy, 0); + }, + function TranslateTest(t){ + var a = m.normalize({dx: 100, dy: 200}); + eq(t, a.xx, 1); + eq(t, a.yy, 1); + eq(t, a.xy, 0); + eq(t, a.yx, 0); + eq(t, a.dx, 100); + eq(t, a.dy, 200); + }, + function ReflectTest1(t){ + var b = m.multiplyPoint(m.reflect(1, 1), 1, 0); + eq(t, b.x, 0); + eq(t, b.y, 1); + }, + function ReflectTest2(t){ + var b = m.multiplyPoint(m.reflect(1, 1), 0, 1); + eq(t, b.x, 1); + eq(t, b.y, 0); + }, + function ProjectTest1(t){ + var b = m.multiplyPoint(m.project(1, 1), 1, 0); + eq(t, b.x, 0.5); + eq(t, b.y, 0.5); + }, + function ProjectTest2(t){ + var b = m.multiplyPoint(m.project(1, 1), 0, 1); + eq(t, b.x, 0.5); + eq(t, b.y, 0.5); + } + ]); +})(); + +} diff --git a/includes/js/dojox/gfx/tests/module.js b/includes/js/dojox/gfx/tests/module.js new file mode 100644 index 0000000..0790b6b --- /dev/null +++ b/includes/js/dojox/gfx/tests/module.js @@ -0,0 +1,13 @@ +if(!dojo._hasResource["dojox.gfx.tests.module"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.tests.module"] = true; +dojo.provide("dojox.gfx.tests.module"); + +try{ + dojo.require("dojox.gfx.tests.matrix"); + dojo.require("dojox.gfx.tests.decompose"); +}catch(e){ + doh.debug(e); +} + + +} diff --git a/includes/js/dojox/gfx/tests/runTests.html b/includes/js/dojox/gfx/tests/runTests.html new file mode 100644 index 0000000..4e13179 --- /dev/null +++ b/includes/js/dojox/gfx/tests/runTests.html @@ -0,0 +1,9 @@ + + + + Dojox Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/gfx/tests/test_arc.html b/includes/js/dojox/gfx/tests/test_arc.html new file mode 100644 index 0000000..f7fc589 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_arc.html @@ -0,0 +1,71 @@ + + +Testing arc + + + + + + + + + + + + + + + +

      Testing arc

      + +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_bezier.html b/includes/js/dojox/gfx/tests/test_bezier.html new file mode 100644 index 0000000..bcee2d0 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_bezier.html @@ -0,0 +1,85 @@ + + +Approximation of an arc with bezier + + + + + + + + + + + + + + + +

      Approximation of an arc with bezier

      + +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_decompose.html b/includes/js/dojox/gfx/tests/test_decompose.html new file mode 100644 index 0000000..6291cc2 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_decompose.html @@ -0,0 +1,54 @@ + + +Testing decompose + + + + + + + + +

      Testing decompose

      +

      + Example: m.rotategAt(30, 100, 100), m.scaleAt(2, 3, 5, 5), m.rotate(45)
      + +

      +

      Result:

      +

      + Original matrix
      + +

      +

      + Decomposed matrix
      + +

      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_fill.html b/includes/js/dojox/gfx/tests/test_fill.html new file mode 100644 index 0000000..84827ea --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_fill.html @@ -0,0 +1,47 @@ + + +Testing fill rule + + + + + + + + + + + + + +

      Testing fill rule

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_fx.html b/includes/js/dojox/gfx/tests/test_fx.html new file mode 100644 index 0000000..c7b5b81 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_fx.html @@ -0,0 +1,113 @@ + + + +Testing animation + + + + + + + + + + + + + +

      Testing animation

      +

      + +   + +   + +   + +

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_gfx.html b/includes/js/dojox/gfx/tests/test_gfx.html new file mode 100644 index 0000000..6d2bef3 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_gfx.html @@ -0,0 +1,489 @@ + + +Dojo Unified 2D Graphics + + + + + + + + + + + + + +

      dojox.gfx tests

      + + + +
      + + diff --git a/includes/js/dojox/gfx/tests/test_gradient.html b/includes/js/dojox/gfx/tests/test_gradient.html new file mode 100644 index 0000000..cd4e772 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_gradient.html @@ -0,0 +1,70 @@ + + +Dojo Unified 2D Graphics + + + + + + + + + + + +

      dojox.gfx Alpha gradient test

      +
      + + diff --git a/includes/js/dojox/gfx/tests/test_group.html b/includes/js/dojox/gfx/tests/test_group.html new file mode 100644 index 0000000..fe11b37 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_group.html @@ -0,0 +1,73 @@ + + +Dojo Unified 2D Graphics + + + + + + + + + + + + + + +

      dojox.gfx Group tests

      +

      +
      +
      + +

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_image1.html b/includes/js/dojox/gfx/tests/test_image1.html new file mode 100644 index 0000000..41b168e --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_image1.html @@ -0,0 +1,74 @@ + + +Testing image + + + + + + + + + + +

      dojox.gfx Image tests

      +

      Note: Silverlight doesn't allow downloading images when run from a file system. This demo should be run from a server.

      +

      +
      +
      +
      +
      +
      +

      +

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_image2.html b/includes/js/dojox/gfx/tests/test_image2.html new file mode 100644 index 0000000..25f71c0 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_image2.html @@ -0,0 +1,50 @@ + + +Testing image + + + + + + + + + +

      Testing image:

      +

      Note: Silverlight doesn't allow downloading images when run from a file system. This demo should be run from a server.

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_linearGradient.html b/includes/js/dojox/gfx/tests/test_linearGradient.html new file mode 100644 index 0000000..f18021a --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_linearGradient.html @@ -0,0 +1,80 @@ + + +Dojo Unified 2D Graphics + + + + + + + + + + + + + + + + + +

      dojox.gfx Linear Gradient test

      +
      + + diff --git a/includes/js/dojox/gfx/tests/test_linestyle.html b/includes/js/dojox/gfx/tests/test_linestyle.html new file mode 100644 index 0000000..c4a422b --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_linestyle.html @@ -0,0 +1,45 @@ + + +Dojo Unified 2D Graphics + + + + + + + + + + + + + +

      dojox.gfx: Line style test

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_pattern.html b/includes/js/dojox/gfx/tests/test_pattern.html new file mode 100644 index 0000000..04d5c3d --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_pattern.html @@ -0,0 +1,44 @@ + + +Testing pattern + + + + + + + + + + + + +

      dojox.gfx Pattern test

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_poly.html b/includes/js/dojox/gfx/tests/test_poly.html new file mode 100644 index 0000000..7db70f1 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_poly.html @@ -0,0 +1,53 @@ + + +Testing polyline and line transforms + + + + + + + + + + + + + + + +

      dojox.gfx Polyline test

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_resize.html b/includes/js/dojox/gfx/tests/test_resize.html new file mode 100644 index 0000000..3870ab0 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_resize.html @@ -0,0 +1,61 @@ + + +Testing surface resizing + + + + + + + + + + + + + + + +

      Testing surface resizing

      + +

      + +   + +   + +   + +

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_setPath.html b/includes/js/dojox/gfx/tests/test_setPath.html new file mode 100644 index 0000000..c8d7749 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_setPath.html @@ -0,0 +1,76 @@ + + +Testing setPath and curves + + + + + + + + + + + +

      dojox.gfx setPath and curve test

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_tbbox.html b/includes/js/dojox/gfx/tests/test_tbbox.html new file mode 100644 index 0000000..1fb1275 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_tbbox.html @@ -0,0 +1,117 @@ + + +Dojo Unified 2D Graphics + + + + + + + + + + + + + + + + +

      dojox.gfx Transformation test

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_text.html b/includes/js/dojox/gfx/tests/test_text.html new file mode 100644 index 0000000..446156f --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_text.html @@ -0,0 +1,88 @@ + + +Testing text + + + + + + + + + + + +

      dojox.gfx Text test

      +
      +
       
      +

       

      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_textpath.html b/includes/js/dojox/gfx/tests/test_textpath.html new file mode 100644 index 0000000..201b0b5 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_textpath.html @@ -0,0 +1,76 @@ + + +Testing textpath + + + + + + + + + +

      dojox.gfx Text on a Path test

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/tests/test_transform.html b/includes/js/dojox/gfx/tests/test_transform.html new file mode 100644 index 0000000..abc50d5 --- /dev/null +++ b/includes/js/dojox/gfx/tests/test_transform.html @@ -0,0 +1,98 @@ + + +Dojo Unified 2D Graphics + + + + + + + + + + +

      dojox.gfx Transform test

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx/utils.js b/includes/js/dojox/gfx/utils.js new file mode 100644 index 0000000..7ee4d9d --- /dev/null +++ b/includes/js/dojox/gfx/utils.js @@ -0,0 +1,87 @@ +if(!dojo._hasResource["dojox.gfx.utils"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.utils"] = true; +dojo.provide("dojox.gfx.utils"); + +dojo.require("dojox.gfx"); + +dojox.gfx.utils.serialize = function( + /* dojox.gfx.Surface || dojox.gfx.Shape */ object +){ + var t = {}, v, isSurface = object instanceof dojox.gfx.Surface; + if(isSurface || object instanceof dojox.gfx.Group){ + t.children = []; + for(var i = 0; i < object.children.length; ++i){ + t.children.push(dojox.gfx.utils.serialize(object.children[i])); + } + if(isSurface){ + return t.children; // Array + } + }else{ + t.shape = object.getShape(); + } + if(object.getTransform){ + v = object.getTransform(); + if(v){ t.transform = v; } + } + if(object.getStroke){ + v = object.getStroke(); + if(v){ t.stroke = v; } + } + if(object.getFill){ + v = object.getFill(); + if(v){ t.fill = v; } + } + if(object.getFont){ + v = object.getFont(); + if(v){ t.font = v; } + } + return t; // Object +}; + +dojox.gfx.utils.toJson = function( + /* dojox.gfx.Surface || dojox.gfx.Shape */ object, + /* Boolean? */ prettyPrint +){ + return dojo.toJson(dojox.gfx.utils.serialize(object), prettyPrint); // String +}; + +dojox.gfx.utils.deserialize = function( + /* dojox.gfx.Surface || dojox.gfx.Shape */ parent, + /* dojox.gfx.Shape || Array */ object +){ + if(object instanceof Array){ + var t = []; + for(var i = 0; i < object.length; ++i){ + t.push(dojox.gfx.utils.deserialize(parent, object[i])); + } + return t; // Array + } + var shape = ("shape" in object) ? parent.createShape(object.shape) : parent.createGroup(); + if("transform" in object){ + shape.setTransform(object.transform); + } + if("stroke" in object){ + shape.setStroke(object.stroke); + } + if("fill" in object){ + shape.setFill(object.fill); + } + if("font" in object){ + shape.setFont(object.font); + } + if("children" in object){ + for(var i = 0; i < object.children.length; ++i){ + dojox.gfx.utils.deserialize(shape, object.children[i]); + } + } + return shape; // dojox.gfx.Shape +}; + +dojox.gfx.utils.fromJson = function( + /* dojox.gfx.Surface || dojox.gfx.Shape */ parent, + /* String */ json +){ + return dojox.gfx.utils.deserialize(parent, dojo.fromJson(json)); // Array || dojox.gfx.Shape +}; + +} diff --git a/includes/js/dojox/gfx/vml.js b/includes/js/dojox/gfx/vml.js new file mode 100644 index 0000000..44f01db --- /dev/null +++ b/includes/js/dojox/gfx/vml.js @@ -0,0 +1,1165 @@ +if(!dojo._hasResource["dojox.gfx.vml"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx.vml"] = true; +dojo.provide("dojox.gfx.vml"); + +dojo.require("dojox.gfx._base"); +dojo.require("dojox.gfx.shape"); +dojo.require("dojox.gfx.path"); +dojo.require("dojox.gfx.arc"); + +// dojox.gfx.vml.xmlns: String: a VML's namespace +dojox.gfx.vml.xmlns = "urn:schemas-microsoft-com:vml"; + +// dojox.gfx.vml.text_alignment: Object: mapping from SVG alignment to VML alignment +dojox.gfx.vml.text_alignment = {start: "left", middle: "center", end: "right"}; + +dojox.gfx.vml._parseFloat = function(str) { + // summary: a helper function to parse VML-specific floating-point values + // str: String: a representation of a floating-point number + return str.match(/^\d+f$/i) ? parseInt(str) / 65536 : parseFloat(str); // Number +}; + +dojox.gfx.vml._bool = {"t": 1, "true": 1}; + +dojo.extend(dojox.gfx.Shape, { + // summary: VML-specific implementation of dojox.gfx.Shape methods + + setFill: function(fill){ + // summary: sets a fill object (VML) + // fill: Object: a fill object + // (see dojox.gfx.defaultLinearGradient, + // dojox.gfx.defaultRadialGradient, + // dojox.gfx.defaultPattern, + // or dojo.Color) + + if(!fill){ + // don't fill + this.fillStyle = null; + this.rawNode.filled = "f"; + return this; + } + if(typeof fill == "object" && "type" in fill){ + // gradient + var i, f, fo, a, s; + switch(fill.type){ + case "linear": + var matrix = this._getRealMatrix(), m = dojox.gfx.matrix; + s = []; + f = dojox.gfx.makeParameters(dojox.gfx.defaultLinearGradient, fill); + a = f.colors; + this.fillStyle = f; + dojo.forEach(a, function(v, i, a){ + a[i].color = dojox.gfx.normalizeColor(v.color); + }); + if(a[0].offset > 0){ + s.push("0 " + a[0].color.toHex()); + } + for(i = 0; i < a.length; ++i){ + s.push(a[i].offset.toFixed(8) + " " + a[i].color.toHex()); + } + i = a.length - 1; + if(a[i].offset < 1){ + s.push("1 " + a[i].color.toHex()); + } + fo = this.rawNode.fill; + fo.colors.value = s.join(";"); + fo.method = "sigma"; + fo.type = "gradient"; + var fc1 = matrix ? m.multiplyPoint(matrix, f.x1, f.y1) : {x: f.x1, y: f.y1}, + fc2 = matrix ? m.multiplyPoint(matrix, f.x2, f.y2) : {x: f.x2, y: f.y2}; + fo.angle = (m._radToDeg(Math.atan2(fc2.x - fc1.x, fc2.y - fc1.y)) + 180) % 360; + fo.on = true; + break; + case "radial": + f = dojox.gfx.makeParameters(dojox.gfx.defaultRadialGradient, fill); + this.fillStyle = f; + var l = parseFloat(this.rawNode.style.left), + t = parseFloat(this.rawNode.style.top), + w = parseFloat(this.rawNode.style.width), + h = parseFloat(this.rawNode.style.height), + c = isNaN(w) ? 1 : 2 * f.r / w; + a = []; + // add a color at the offset 0 (1 in VML coordinates) + if(f.colors[0].offset > 0){ + a.push({offset: 1, color: dojox.gfx.normalizeColor(f.colors[0].color)}); + } + // massage colors + dojo.forEach(f.colors, function(v, i){ + a.push({offset: 1 - v.offset * c, color: dojox.gfx.normalizeColor(v.color)}); + }); + i = a.length - 1; + while(i >= 0 && a[i].offset < 0){ --i; } + if(i < a.length - 1){ + // correct excessive colors + var q = a[i], p = a[i + 1]; + p.color = dojo.blendColors(q.color, p.color, q.offset / (q.offset - p.offset)); + p.offset = 0; + while(a.length - i > 2) a.pop(); + } + // set colors + i = a.length - 1, s = []; + if(a[i].offset > 0){ + s.push("0 " + a[i].color.toHex()); + } + for(; i >= 0; --i){ + s.push(a[i].offset.toFixed(8) + " " + a[i].color.toHex()); + } + fo = this.rawNode.fill; + fo.colors.value = s.join(";"); + fo.method = "sigma"; + fo.type = "gradientradial"; + if(isNaN(w) || isNaN(h) || isNaN(l) || isNaN(t)){ + fo.focusposition = "0.5 0.5"; + }else{ + fo.focusposition = ((f.cx - l) / w).toFixed(8) + " " + ((f.cy - t) / h).toFixed(8); + } + fo.focussize = "0 0"; + fo.on = true; + break; + case "pattern": + f = dojox.gfx.makeParameters(dojox.gfx.defaultPattern, fill); + this.fillStyle = f; + fo = this.rawNode.fill; + fo.type = "tile"; + fo.src = f.src; + if(f.width && f.height){ + // in points + fo.size.x = dojox.gfx.px2pt(f.width); + fo.size.y = dojox.gfx.px2pt(f.height); + } + fo.alignShape = "f"; + fo.position.x = 0; + fo.position.y = 0; + fo.origin.x = f.width ? f.x / f.width : 0; + fo.origin.y = f.height ? f.y / f.height : 0; + fo.on = true; + break; + } + this.rawNode.fill.opacity = 1; + return this; + } + // color object + this.fillStyle = dojox.gfx.normalizeColor(fill); + this.rawNode.fill.method = "any"; + this.rawNode.fill.type = "solid"; + this.rawNode.fillcolor = this.fillStyle.toHex(); + this.rawNode.fill.opacity = this.fillStyle.a; + this.rawNode.filled = true; + return this; // self + }, + + setStroke: function(stroke){ + // summary: sets a stroke object (VML) + // stroke: Object: a stroke object + // (see dojox.gfx.defaultStroke) + + if(!stroke){ + // don't stroke + this.strokeStyle = null; + this.rawNode.stroked = "f"; + return this; + } + // normalize the stroke + if(typeof stroke == "string"){ + stroke = {color: stroke}; + } + var s = this.strokeStyle = dojox.gfx.makeParameters(dojox.gfx.defaultStroke, stroke); + s.color = dojox.gfx.normalizeColor(s.color); + // generate attributes + var rn = this.rawNode; + rn.stroked = true; + rn.strokecolor = s.color.toCss(); + rn.strokeweight = s.width + "px"; // TODO: should we assume that the width is always in pixels? + if(rn.stroke) { + rn.stroke.opacity = s.color.a; + rn.stroke.endcap = this._translate(this._capMap, s.cap); + if(typeof s.join == "number") { + rn.stroke.joinstyle = "miter"; + rn.stroke.miterlimit = s.join; + }else{ + rn.stroke.joinstyle = s.join; + // rn.stroke.miterlimit = s.width; + } + rn.stroke.dashstyle = s.style == "none" ? "Solid" : s.style; + } + return this; // self + }, + + _capMap: { butt: 'flat' }, + _capMapReversed: { flat: 'butt' }, + + _translate: function(dict, value) { + return (value in dict) ? dict[value] : value; + }, + + _applyTransform: function() { + if(this.fillStyle && this.fillStyle.type == "linear"){ + this.setFill(this.fillStyle); + } + var matrix = this._getRealMatrix(); + if(!matrix) return this; + var skew = this.rawNode.skew; + if(typeof skew == "undefined"){ + for(var i = 0; i < this.rawNode.childNodes.length; ++i){ + if(this.rawNode.childNodes[i].tagName == "skew"){ + skew = this.rawNode.childNodes[i]; + break; + } + } + } + if(skew){ + skew.on = "f"; + var mt = matrix.xx.toFixed(8) + " " + matrix.xy.toFixed(8) + " " + + matrix.yx.toFixed(8) + " " + matrix.yy.toFixed(8) + " 0 0", + offset = Math.floor(matrix.dx).toFixed() + "px " + Math.floor(matrix.dy).toFixed() + "px", + s = this.rawNode.style, + l = parseFloat(s.left), + t = parseFloat(s.top), + w = parseFloat(s.width), + h = parseFloat(s.height); + if(isNaN(l)) l = 0; + if(isNaN(t)) t = 0; + if(isNaN(w)) w = 1; + if(isNaN(h)) h = 1; + var origin = (-l / w - 0.5).toFixed(8) + " " + (-t / h - 0.5).toFixed(8); + skew.matrix = mt; + skew.origin = origin; + skew.offset = offset; + skew.on = true; + } + return this; + }, + + setRawNode: function(rawNode){ + // summary: + // assigns and clears the underlying node that will represent this + // shape. Once set, transforms, gradients, etc, can be applied. + // (no fill & stroke by default) + rawNode.stroked = "f"; + rawNode.filled = "f"; + this.rawNode = rawNode; + }, + + // move family + + _moveToFront: function(){ + // summary: moves a shape to front of its parent's list of shapes (VML) + this.rawNode.parentNode.appendChild(this.rawNode); + return this; + }, + _moveToBack: function(){ + // summary: moves a shape to back of its parent's list of shapes (VML) + var r = this.rawNode, p = r.parentNode, n = p.firstChild; + p.insertBefore(r, n); + if(n.tagName == "rect"){ + // surface has a background rectangle, which position should be preserved + n.swapNode(r); + } + return this; + }, + + _getRealMatrix: function(){ + // summary: returns the cumulative ("real") transformation matrix + // by combining the shape's matrix with its parent's matrix + return this.parentMatrix ? new dojox.gfx.Matrix2D([this.parentMatrix, this.matrix]) : this.matrix; // dojox.gfx.Matrix2D + } +}); + +dojo.declare("dojox.gfx.Group", dojox.gfx.Shape, { + // summary: a group shape (VML), which can be used + // to logically group shapes (e.g, to propagate matricies) + constructor: function(){ + dojox.gfx.vml.Container._init.call(this); + }, + // apply transformation + _applyTransform: function(){ + // summary: applies a transformation matrix to a group + var matrix = this._getRealMatrix(); + for(var i = 0; i < this.children.length; ++i){ + this.children[i]._updateParentMatrix(matrix); + } + return this; // self + } +}); +dojox.gfx.Group.nodeType = "group"; + +dojo.declare("dojox.gfx.Rect", dojox.gfx.shape.Rect, { + // summary: a rectangle shape (VML) + setShape: function(newShape){ + // summary: sets a rectangle shape object (VML) + // newShape: Object: a rectangle shape object + var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + var style = this.rawNode.style; + style.left = shape.x.toFixed(); + style.top = shape.y.toFixed(); + style.width = (typeof shape.width == "string" && shape.width.indexOf("%") >= 0) ? shape.width : shape.width.toFixed(); + style.height = (typeof shape.width == "string" && shape.height.indexOf("%") >= 0) ? shape.height : shape.height.toFixed(); + var r = Math.min(1, (shape.r / Math.min(parseFloat(shape.width), parseFloat(shape.height)))).toFixed(8); + // a workaround for the VML's arcsize bug: cannot read arcsize of an instantiated node + var parent = this.rawNode.parentNode, before = null; + if(parent){ + if(parent.lastChild != this.rawNode){ + for(var i = 0; i < parent.childNodes.length; ++i){ + if(parent.childNodes[i] == this.rawNode){ + before = parent.childNodes[i+1]; + break; + } + } + } + parent.removeChild(this.rawNode); + } + this.rawNode.arcsize = r; + if(parent){ + if(before){ + parent.insertBefore(this.rawNode, before); + }else{ + parent.appendChild(this.rawNode); + } + } + // set all necessary styles, which are lost by VML (yes, it's a VML's bug) + return this.setTransform(this.matrix).setFill(this.fillStyle).setStroke(this.strokeStyle); // self + } +}); +dojox.gfx.Rect.nodeType = "roundrect"; // use a roundrect so the stroke join type is respected + +dojo.declare("dojox.gfx.Ellipse", dojox.gfx.shape.Ellipse, { + // summary: an ellipse shape (VML) + setShape: function(newShape){ + // summary: sets an ellipse shape object (VML) + // newShape: Object: an ellipse shape object + var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + var style = this.rawNode.style; + style.left = (shape.cx - shape.rx).toFixed(); + style.top = (shape.cy - shape.ry).toFixed(); + style.width = (shape.rx * 2).toFixed(); + style.height = (shape.ry * 2).toFixed(); + return this.setTransform(this.matrix); // self + } +}); +dojox.gfx.Ellipse.nodeType = "oval"; + +dojo.declare("dojox.gfx.Circle", dojox.gfx.shape.Circle, { + // summary: a circle shape (VML) + setShape: function(newShape){ + // summary: sets a circle shape object (VML) + // newShape: Object: a circle shape object + var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + var style = this.rawNode.style; + style.left = (shape.cx - shape.r).toFixed(); + style.top = (shape.cy - shape.r).toFixed(); + style.width = (shape.r * 2).toFixed(); + style.height = (shape.r * 2).toFixed(); + return this; // self + } +}); +dojox.gfx.Circle.nodeType = "oval"; + +dojo.declare("dojox.gfx.Line", dojox.gfx.shape.Line, { + // summary: a line shape (VML) + constructor: function(rawNode){ + if(rawNode) rawNode.setAttribute("dojoGfxType", "line"); + }, + setShape: function(newShape){ + // summary: sets a line shape object (VML) + // newShape: Object: a line shape object + var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + this.rawNode.path.v = "m" + shape.x1.toFixed() + " " + shape.y1.toFixed() + + "l" + shape.x2.toFixed() + " " + shape.y2.toFixed() + "e"; + return this.setTransform(this.matrix); // self + } +}); +dojox.gfx.Line.nodeType = "shape"; + +dojo.declare("dojox.gfx.Polyline", dojox.gfx.shape.Polyline, { + // summary: a polyline/polygon shape (VML) + constructor: function(rawNode){ + if(rawNode) rawNode.setAttribute("dojoGfxType", "polyline"); + }, + setShape: function(points, closed){ + // summary: sets a polyline/polygon shape object (VML) + // points: Object: a polyline/polygon shape object + // closed: Boolean?: if true, close the polyline explicitely + if(points && points instanceof Array){ + // branch + // points: Array: an array of points + this.shape = dojox.gfx.makeParameters(this.shape, { points: points }); + if(closed && this.shape.points.length) this.shape.points.push(this.shape.points[0]); + }else{ + this.shape = dojox.gfx.makeParameters(this.shape, points); + } + this.bbox = null; + var attr = [], p = this.shape.points; + if(p.length > 0){ + attr.push("m"); + var k = 1; + if(typeof p[0] == "number"){ + attr.push(p[0].toFixed()); + attr.push(p[1].toFixed()); + k = 2; + }else{ + attr.push(p[0].x.toFixed()); + attr.push(p[0].y.toFixed()); + } + if(p.length > k){ + attr.push("l"); + for(var i = k; i < p.length; ++i){ + if(typeof p[i] == "number"){ + attr.push(p[i].toFixed()); + }else{ + attr.push(p[i].x.toFixed()); + attr.push(p[i].y.toFixed()); + } + } + } + } + attr.push("e"); + this.rawNode.path.v = attr.join(" "); + return this.setTransform(this.matrix); // self + } +}); +dojox.gfx.Polyline.nodeType = "shape"; + +dojo.declare("dojox.gfx.Image", dojox.gfx.shape.Image, { + // summary: an image (VML) + constructor: function(rawNode){ + if(rawNode) rawNode.setAttribute("dojoGfxType", "image"); + }, + getEventSource: function() { + // summary: returns a Node, which is used as + // a source of events for this shape + return this.rawNode ? this.rawNode.firstChild : null; // Node + }, + setShape: function(newShape){ + // summary: sets an image shape object (VML) + // newShape: Object: an image shape object + var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + this.rawNode.firstChild.src = shape.src; + return this.setTransform(this.matrix); // self + }, + _setDimensions: function(s, w, h){ + if(w || h){ + s.width = w + "px"; + s.height = h + "px"; + } + }, + _resetImage: function(){ + var s = this.rawNode.firstChild.style, + shape = this.shape; + s.left = "0px"; + s.top = "0px"; + this._setDimensions(s, shape.width, shape.height); + }, + _applyTransform: function() { + var matrix = this._getRealMatrix(), + img = this.rawNode.firstChild, + s = img.style, + shape = this.shape; + if(matrix){ + matrix = dojox.gfx.matrix.multiply(matrix, {dx: shape.x, dy: shape.y}); + }else{ + matrix = dojox.gfx.matrix.normalize({dx: shape.x, dy: shape.y}); + } + if(matrix.xy == 0 && matrix.yx == 0 && matrix.xx > 0 && matrix.yy > 0){ + // special case to avoid filters + this.rawNode.style.filter = ""; + s.left = Math.floor(matrix.dx) + "px"; + s.top = Math.floor(matrix.dy) + "px"; + this._setDimensions(s, Math.floor(matrix.xx * shape.width), Math.floor(matrix.yy * shape.height)); + }else{ + this._resetImage(); + var f = this.rawNode.filters["DXImageTransform.Microsoft.Matrix"]; + if(f){ + f.M11 = matrix.xx; + f.M12 = matrix.xy; + f.M21 = matrix.yx; + f.M22 = matrix.yy; + f.Dx = matrix.dx; + f.Dy = matrix.dy; + }else{ + this.rawNode.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11=" + matrix.xx + + ", M12=" + matrix.xy + ", M21=" + matrix.yx + ", M22=" + matrix.yy + + ", Dx=" + matrix.dx + ", Dy=" + matrix.dy + ")"; + } + } + return this; + } +}); +dojox.gfx.Image.nodeType = "div"; + +dojo.declare("dojox.gfx.Text", dojox.gfx.shape.Text, { + // summary: an anchored text (VML) + constructor: function(rawNode){ + if(rawNode){rawNode.setAttribute("dojoGfxType", "text");} + this.fontStyle = null; + }, + _alignment: {start: "left", middle: "center", end: "right"}, + setShape: function(newShape){ + // summary: sets a text shape object (VML) + // newShape: Object: a text shape object + this.shape = dojox.gfx.makeParameters(this.shape, newShape); + this.bbox = null; + var r = this.rawNode, s = this.shape, x = s.x, y = s.y.toFixed(); + switch(s.align){ + case "middle": + x -= 5; + break; + case "end": + x -= 10; + break; + } + this.rawNode.path.v = "m" + x.toFixed() + "," + y + + "l" + (x + 10).toFixed() + "," + y + "e"; + // find path and text path + var p = null, t = null, c = r.childNodes; + for(var i = 0; i < c.length; ++i){ + var tag = c[i].tagName; + if(tag == "path"){ + p = c[i]; + if(t) break; + }else if(tag == "textpath"){ + t = c[i]; + if(p) break; + } + } + if(!p){ + p = this.rawNode.ownerDocument.createElement("v:path"); + r.appendChild(p); + } + if(!t){ + t = this.rawNode.ownerDocument.createElement("v:textpath"); + r.appendChild(t); + } + p.textPathOk = true; + t.on = true; + var a = dojox.gfx.vml.text_alignment[s.align]; + t.style["v-text-align"] = a ? a : "left"; + t.style["text-decoration"] = s.decoration; + t.style["v-rotate-letters"] = s.rotated; + t.style["v-text-kern"] = s.kerning; + t.string = s.text; + return this.setTransform(this.matrix); // self + }, + _setFont: function(){ + // summary: sets a font object (VML) + var f = this.fontStyle, c = this.rawNode.childNodes; + for(var i = 0; i < c.length; ++i){ + if(c[i].tagName == "textpath"){ + c[i].style.font = dojox.gfx.makeFontString(f); + break; + } + } + this.setTransform(this.matrix); + }, + _getRealMatrix: function(){ + // summary: returns the cumulative ("real") transformation matrix + // by combining the shape's matrix with its parent's matrix; + // it makes a correction for a font size + var matrix = dojox.gfx.Shape.prototype._getRealMatrix.call(this); + // It appears that text is always aligned vertically at a middle of x-height (???). + // It is impossible to obtain these metrics from VML => I try to approximate it with + // more-or-less util value of 0.7 * FontSize, which is typical for European fonts. + if(matrix){ + matrix = dojox.gfx.matrix.multiply(matrix, + {dy: -dojox.gfx.normalizedLength(this.fontStyle ? this.fontStyle.size : "10pt") * 0.35}); + } + return matrix; // dojox.gfx.Matrix2D + }, + getTextWidth: function(){ + // summary: get the text width, in px + var rawNode = this.rawNode, _display = rawNode.style.display; + rawNode.style.display = "inline"; + var _width = dojox.gfx.pt2px(parseFloat(rawNode.currentStyle.width)); + rawNode.style.display = _display; + return _width; + } +}); +dojox.gfx.Text.nodeType = "shape"; + +dojox.gfx.path._calcArc = function(alpha){ + // return a start point, 1st and 2nd control points, and an end point + var cosa = Math.cos(alpha), sina = Math.sin(alpha), + p2 = {x: cosa + (4 / 3) * (1 - cosa), y: sina - (4 / 3) * cosa * (1 - cosa) / sina}; + return { + s: {x: cosa, y: -sina}, + c1: {x: p2.x, y: -p2.y}, + c2: p2, + e: {x: cosa, y: sina} + }; +}; + +dojo.declare("dojox.gfx.Path", dojox.gfx.path.Path, { + // summary: a path shape (VML) + constructor: function(rawNode){ + if(rawNode && !rawNode.getAttribute("dojoGfxType")){ + rawNode.setAttribute("dojoGfxType", "path"); + } + this.vmlPath = ""; + this.lastControl = {}; + }, + _updateWithSegment: function(segment){ + // summary: updates the bounding box of path with new segment + // segment: Object: a segment + var last = dojo.clone(this.last); + dojox.gfx.Path.superclass._updateWithSegment.apply(this, arguments); + // add a VML path segment + var path = this[this.renderers[segment.action]](segment, last); + if(typeof this.vmlPath == "string"){ + this.vmlPath += path.join(""); + this.rawNode.path.v = this.vmlPath + " r0,0 e"; + }else{ + this.vmlPath = this.vmlPath.concat(path); + } + }, + setShape: function(newShape){ + // summary: forms a path using a shape (VML) + // newShape: Object: an VML path string or a path object (see dojox.gfx.defaultPath) + this.vmlPath = []; + this.lastControl = {}; + dojox.gfx.Path.superclass.setShape.apply(this, arguments); + this.vmlPath = this.vmlPath.join(""); + this.rawNode.path.v = this.vmlPath + " r0,0 e"; + return this; + }, + _pathVmlToSvgMap: {m: "M", l: "L", t: "m", r: "l", c: "C", v: "c", qb: "Q", x: "z", e: ""}, + // VML-specific segment renderers + renderers: { + M: "_moveToA", m: "_moveToR", + L: "_lineToA", l: "_lineToR", + H: "_hLineToA", h: "_hLineToR", + V: "_vLineToA", v: "_vLineToR", + C: "_curveToA", c: "_curveToR", + S: "_smoothCurveToA", s: "_smoothCurveToR", + Q: "_qCurveToA", q: "_qCurveToR", + T: "_qSmoothCurveToA", t: "_qSmoothCurveToR", + A: "_arcTo", a: "_arcTo", + Z: "_closePath", z: "_closePath" + }, + _addArgs: function(path, args, from, upto){ + if(typeof upto == "undefined"){ + upto = args.length; + } + if(typeof from == "undefined"){ + from = 0; + } + for(var i = from; i < upto; ++i){ + path.push(" "); + path.push(args[i].toFixed()); + } + }, + _addArgsAdjusted: function(path, last, args, from, upto){ + if(typeof upto == "undefined"){ + upto = args.length; + } + if(typeof from == "undefined"){ + from = 0; + } + for(var i = from; i < upto; i += 2){ + path.push(" "); + path.push((last.x + args[i]).toFixed()); + path.push(" "); + path.push((last.y + args[i + 1]).toFixed()); + } + }, + _moveToA: function(segment){ + var p = [" m"], n = segment.args, l = n.length; + if(l == 2){ + this._addArgs(p, n); + }else{ + this._addArgs(p, n, 0, 2); + p.push(" l"); + this._addArgs(p, n, 2); + } + this.lastControl = {}; + return p; + }, + _moveToR: function(segment, last){ + var p = ["x" in last ? " t" : " m"], n = segment.args, l = n.length; + if(l == 2){ + this._addArgs(p, n); + }else{ + this._addArgs(p, n, 0, 2); + p.push(" r"); + this._addArgs(p, n, 2); + } + this.lastControl = {}; + return p; + }, + _lineToA: function(segment){ + var p = [" l"]; + this._addArgs(p, segment.args); + this.lastControl = {}; + return p; + }, + _lineToR: function(segment){ + var p = [" r"]; + this._addArgs(p, segment.args); + this.lastControl = {}; + return p; + }, + _hLineToA: function(segment, last){ + var p = [" l"], n = segment.args, l = n.length, y = " " + last.y.toFixed(); + for(var i = 0; i < l; ++i){ + p.push(" "); + p.push(n[i].toFixed()); + p.push(y); + } + this.lastControl = {}; + return p; + }, + _hLineToR: function(segment){ + var p = [" r"], n = segment.args, l = n.length; + for(var i = 0; i < l; ++i){ + p.push(" "); + p.push(n[i].toFixed()); + p.push(" 0"); + } + this.lastControl = {}; + return p; + }, + _vLineToA: function(segment, last){ + var p = [" l"], n = segment.args, l = n.length, x = " " + last.x.toFixed(); + for(var i = 0; i < l; ++i){ + p.push(x); + p.push(" "); + p.push(n[i].toFixed()); + } + this.lastControl = {}; + return p; + }, + _vLineToR: function(segment){ + var p = [" r"], n = segment.args, l = n.length; + for(var i = 0; i < l; ++i){ + p.push(" 0 "); + p.push(n[i].toFixed()); + } + this.lastControl = {}; + return p; + }, + _curveToA: function(segment){ + var p = [], n = segment.args, l = n.length; + for(var i = 0; i < l; i += 6){ + p.push(" c"); + this._addArgs(p, n, i, i + 6); + } + this.lastControl = {x: n[l - 4], y: n[l - 3], type: "C"}; + return p; + }, + _curveToR: function(segment, last){ + var p = [], n = segment.args, l = n.length; + for(var i = 0; i < l; i += 6){ + p.push(" v"); + this._addArgs(p, n, i, i + 6); + this.lastControl = {x: last.x + n[i + 2], y: last.y + n[i + 3]}; + last.x += n[i + 4]; + last.y += n[i + 5]; + } + this.lastControl.type = "C"; + return p; + }, + _smoothCurveToA: function(segment, last){ + var p = [], n = segment.args, l = n.length; + for(var i = 0; i < l; i += 4){ + p.push(" c"); + if(this.lastControl.type == "C"){ + this._addArgs(p, [ + 2 * last.x - this.lastControl.x, + 2 * last.y - this.lastControl.y + ]); + }else{ + this._addArgs(p, [last.x, last.y]); + } + this._addArgs(p, n, i, i + 4); + } + this.lastControl = {x: n[l - 4], y: n[l - 3], type: "C"}; + return p; + }, + _smoothCurveToR: function(segment, last){ + var p = [], n = segment.args, l = n.length; + for(var i = 0; i < l; i += 4){ + p.push(" v"); + if(this.lastControl.type == "C"){ + this._addArgs(p, [ + last.x - this.lastControl.x, + last.y - this.lastControl.y + ]); + }else{ + this._addArgs(p, [0, 0]); + } + this._addArgs(p, n, i, i + 4); + this.lastControl = {x: last.x + n[i], y: last.y + n[i + 1]}; + last.x += n[i + 2]; + last.y += n[i + 3]; + } + this.lastControl.type = "C"; + return p; + }, + _qCurveToA: function(segment){ + var p = [], n = segment.args, l = n.length; + for(var i = 0; i < l; i += 4){ + p.push(" qb"); + this._addArgs(p, n, i, i + 4); + } + this.lastControl = {x: n[l - 4], y: n[l - 3], type: "Q"}; + return p; + }, + _qCurveToR: function(segment, last){ + var p = [], n = segment.args, l = n.length; + for(var i = 0; i < l; i += 4){ + p.push(" qb"); + this._addArgsAdjusted(p, last, n, i, i + 4); + this.lastControl = {x: last.x + n[i], y: last.y + n[i + 1]}; + last.x += n[i + 2]; + last.y += n[i + 3]; + } + this.lastControl.type = "Q"; + return p; + }, + _qSmoothCurveToA: function(segment, last){ + var p = [], n = segment.args, l = n.length; + for(var i = 0; i < l; i += 2){ + p.push(" qb"); + if(this.lastControl.type == "Q"){ + this._addArgs(p, [ + this.lastControl.x = 2 * last.x - this.lastControl.x, + this.lastControl.y = 2 * last.y - this.lastControl.y + ]); + }else{ + this._addArgs(p, [ + this.lastControl.x = last.x, + this.lastControl.y = last.y + ]); + } + this._addArgs(p, n, i, i + 2); + } + this.lastControl.type = "Q"; + return p; + }, + _qSmoothCurveToR: function(segment, last){ + var p = [], n = segment.args, l = n.length; + for(var i = 0; i < l; i += 2){ + p.push(" qb"); + if(this.lastControl.type == "Q"){ + this._addArgs(p, [ + this.lastControl.x = 2 * last.x - this.lastControl.x, + this.lastControl.y = 2 * last.y - this.lastControl.y + ]); + }else{ + this._addArgs(p, [ + this.lastControl.x = last.x, + this.lastControl.y = last.y + ]); + } + this._addArgsAdjusted(p, last, n, i, i + 2); + } + this.lastControl.type = "Q"; + return p; + }, + _arcTo: function(segment, last){ + var p = [], n = segment.args, l = n.length, relative = segment.action == "a"; + for(var i = 0; i < l; i += 7){ + var x1 = n[i + 5], y1 = n[i + 6]; + if(relative){ + x1 += last.x; + y1 += last.y; + } + var result = dojox.gfx.arc.arcAsBezier( + last, n[i], n[i + 1], n[i + 2], + n[i + 3] ? 1 : 0, n[i + 4] ? 1 : 0, + x1, y1 + ); + for(var j = 0; j < result.length; ++j){ + p.push(" c"); + this._addArgs(p, result[j]); + } + last = {x: x1, y: y1}; + } + this.lastControl = {}; + return p; + }, + _closePath: function(){ + this.lastControl = {}; + return ["x"]; + } +}); +dojox.gfx.Path.nodeType = "shape"; + +dojo.declare("dojox.gfx.TextPath", dojox.gfx.Path, { + // summary: a textpath shape (VML) + constructor: function(rawNode){ + if(rawNode){rawNode.setAttribute("dojoGfxType", "textpath");} + this.fontStyle = null; + if(!("text" in this)){ + this.text = dojo.clone(dojox.gfx.defaultTextPath); + } + if(!("fontStyle" in this)){ + this.fontStyle = dojo.clone(dojox.gfx.defaultFont); + } + }, + setText: function(newText){ + // summary: sets a text to be drawn along the path + this.text = dojox.gfx.makeParameters(this.text, + typeof newText == "string" ? {text: newText} : newText); + this._setText(); + return this; // self + }, + setFont: function(newFont){ + // summary: sets a font for text + this.fontStyle = typeof newFont == "string" ? + dojox.gfx.splitFontString(newFont) : + dojox.gfx.makeParameters(dojox.gfx.defaultFont, newFont); + this._setFont(); + return this; // self + }, + + _setText: function(){ + // summary: sets a text shape object (VML) + this.bbox = null; + var r = this.rawNode, s = this.text, + // find path and text path + p = null, t = null, c = r.childNodes; + for(var i = 0; i < c.length; ++i){ + var tag = c[i].tagName; + if(tag == "path"){ + p = c[i]; + if(t) break; + }else if(tag == "textpath"){ + t = c[i]; + if(p) break; + } + } + if(!p){ + p = this.rawNode.ownerDocument.createElement("v:path"); + r.appendChild(p); + } + if(!t){ + t = this.rawNode.ownerDocument.createElement("v:textpath"); + r.appendChild(t); + } + p.textPathOk = true; + t.on = true; + var a = dojox.gfx.vml.text_alignment[s.align]; + t.style["v-text-align"] = a ? a : "left"; + t.style["text-decoration"] = s.decoration; + t.style["v-rotate-letters"] = s.rotated; + t.style["v-text-kern"] = s.kerning; + t.string = s.text; + }, + _setFont: function(){ + // summary: sets a font object (VML) + var f = this.fontStyle, c = this.rawNode.childNodes; + for(var i = 0; i < c.length; ++i){ + if(c[i].tagName == "textpath"){ + c[i].style.font = dojox.gfx.makeFontString(f); + break; + } + } + } +}); +dojox.gfx.TextPath.nodeType = "shape"; + +dojo.declare("dojox.gfx.Surface", dojox.gfx.shape.Surface, { + // summary: a surface object to be used for drawings (VML) + constructor: function(){ + dojox.gfx.vml.Container._init.call(this); + }, + setDimensions: function(width, height){ + // summary: sets the width and height of the rawNode + // width: String: width of surface, e.g., "100px" + // height: String: height of surface, e.g., "100px" + this.width = dojox.gfx.normalizedLength(width); // in pixels + this.height = dojox.gfx.normalizedLength(height); // in pixels + if(!this.rawNode) return this; + var cs = this.clipNode.style, + r = this.rawNode, rs = r.style, + bs = this.bgNode.style; + cs.width = width; + cs.height = height; + cs.clip = "rect(0 " + width + " " + height + " 0)"; + rs.width = width; + rs.height = height; + r.coordsize = width + " " + height; + bs.width = width; + bs.height = height; + return this; // self + }, + getDimensions: function(){ + // summary: returns an object with properties "width" and "height" + var t = this.rawNode ? { + width: dojox.gfx.normalizedLength(this.rawNode.style.width), + height: dojox.gfx.normalizedLength(this.rawNode.style.height)} : null; + if(t.width <= 0){ t.width = this.width; } + if(t.height <= 0){ t.height = this.height; } + return t; // Object + } +}); + +dojox.gfx.createSurface = function(parentNode, width, height){ + // summary: creates a surface (VML) + // parentNode: Node: a parent node + // width: String: width of surface, e.g., "100px" + // height: String: height of surface, e.g., "100px" + + if(!width){ width = "100%"; } + if(!height){ height = "100%"; } + var s = new dojox.gfx.Surface(), p = dojo.byId(parentNode), + c = s.clipNode = p.ownerDocument.createElement("div"), + r = s.rawNode = p.ownerDocument.createElement("v:group"), + cs = c.style, rs = r.style; + + p.style.width = width; + p.style.height = height; + + cs.position = "absolute"; + cs.width = width; + cs.height = height; + cs.clip = "rect(0 " + width + " " + height + " 0)"; + rs.position = "absolute"; + rs.width = width; + rs.height = height; + r.coordsize = (width == "100%" ? width : parseFloat(width)) + " " + + (height == "100%" ? height : parseFloat(height)); + r.coordorigin = "0 0"; + + // create a background rectangle, which is required to show all other shapes + var b = s.bgNode = r.ownerDocument.createElement("v:rect"), bs = b.style; + bs.left = bs.top = 0; + bs.width = rs.width; + bs.height = rs.height; + b.filled = b.stroked = "f"; + + r.appendChild(b); + c.appendChild(r); + p.appendChild(c); + + s.width = dojox.gfx.normalizedLength(width); // in pixels + s.height = dojox.gfx.normalizedLength(height); // in pixels + + return s; // dojox.gfx.Surface +}; + +// Extenders + +dojox.gfx.vml.Container = { + _init: function(){ + dojox.gfx.shape.Container._init.call(this); + }, + add: function(shape){ + // summary: adds a shape to a group/surface + // shape: dojox.gfx.Shape: an VML shape object + if(this != shape.getParent()){ + this.rawNode.appendChild(shape.rawNode); + //dojox.gfx.Group.superclass.add.apply(this, arguments); + //this.inherited(arguments); + dojox.gfx.shape.Container.add.apply(this, arguments); + } + return this; // self + }, + remove: function(shape, silently){ + // summary: remove a shape from a group/surface + // shape: dojox.gfx.Shape: an VML shape object + // silently: Boolean?: if true, regenerate a picture + if(this == shape.getParent()){ + if(this.rawNode == shape.rawNode.parentNode){ + this.rawNode.removeChild(shape.rawNode); + } + //dojox.gfx.Group.superclass.remove.apply(this, arguments); + //this.inherited(arguments); + dojox.gfx.shape.Container.remove.apply(this, arguments); + } + return this; // self + }, + clear: function(){ + // summary: removes all shapes from a group/surface + var r = this.rawNode; + while(r.firstChild != r.lastChild){ + if(r.firstChild != this.bgNode){ + r.removeChild(r.firstChild); + } + if(r.lastChild != this.bgNode){ + r.removeChild(r.lastChild); + } + } + //return this.inherited(arguments); // self + return dojox.gfx.shape.Container.clear.apply(this, arguments); + }, + _moveChildToFront: dojox.gfx.shape.Container._moveChildToFront, + _moveChildToBack: dojox.gfx.shape.Container._moveChildToBack +}; + +dojo.mixin(dojox.gfx.shape.Creator, { + // summary: VML shape creators + createGroup: function(){ + // summary: creates a VML group shape + var g = this.createObject(dojox.gfx.Group, null); // dojox.gfx.Group + // create a background rectangle, which is required to show all other shapes + var r = g.rawNode.ownerDocument.createElement("v:rect"); + r.style.left = r.style.top = 0; + r.style.width = g.rawNode.style.width; + r.style.height = g.rawNode.style.height; + r.filled = r.stroked = "f"; + g.rawNode.appendChild(r); + g.bgNode = r; + return g; // dojox.gfx.Group + }, + createImage: function(image){ + // summary: creates a VML image shape + // image: Object: an image object (see dojox.gfx.defaultImage) + if(!this.rawNode) return null; + var shape = new dojox.gfx.Image(), node = this.rawNode.ownerDocument.createElement('div'); + node.style.position = "absolute"; + node.style.width = this.rawNode.style.width; + node.style.height = this.rawNode.style.height; + //node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11=1, M12=0, M21=0, M22=1, Dx=0, Dy=0)"; + var img = this.rawNode.ownerDocument.createElement('img'); + img.style.position = "relative"; + node.appendChild(img); + shape.setRawNode(node); + this.rawNode.appendChild(node); + shape.setShape(image); + this.add(shape); + return shape; // dojox.gfx.Image + }, + createObject: function(shapeType, rawShape) { + // summary: creates an instance of the passed shapeType class + // shapeType: Function: a class constructor to create an instance of + // rawShape: Object: properties to be passed in to the classes "setShape" method + // overrideSize: Boolean: set the size explicitly, if true + if(!this.rawNode) return null; + var shape = new shapeType(), + node = this.rawNode.ownerDocument.createElement('v:' + shapeType.nodeType); + shape.setRawNode(node); + this.rawNode.appendChild(node); + switch(shapeType){ + case dojox.gfx.Group: + case dojox.gfx.Line: + case dojox.gfx.Polyline: + case dojox.gfx.Text: + case dojox.gfx.Path: + case dojox.gfx.TextPath: + this._overrideSize(node); + } + shape.setShape(rawShape); + this.add(shape); + return shape; // dojox.gfx.Shape + }, + _overrideSize: function(node){ + var p = this; + while(p && !(p instanceof dojox.gfx.Surface)){ p = p.parent; } + node.style.width = p.width; + node.style.height = p.height; + node.coordsize = p.width + " " + p.height; + } +}); + +dojo.extend(dojox.gfx.Group, dojox.gfx.vml.Container); +dojo.extend(dojox.gfx.Group, dojox.gfx.shape.Creator); + +dojo.extend(dojox.gfx.Surface, dojox.gfx.vml.Container); +dojo.extend(dojox.gfx.Surface, dojox.gfx.shape.Creator); + +} diff --git a/includes/js/dojox/gfx/vml_attach.js b/includes/js/dojox/gfx/vml_attach.js new file mode 100644 index 0000000..b54d31b --- /dev/null +++ b/includes/js/dojox/gfx/vml_attach.js @@ -0,0 +1,362 @@ +dojo.require("dojox.gfx.vml"); + +dojo.experimental("dojox.gfx.vml_attach"); + +(function(){ + dojox.gfx.attachNode = function(node){ + // summary: creates a shape from a Node + // node: Node: an VML node + if(!node) return null; + var s = null; + switch(node.tagName.toLowerCase()){ + case dojox.gfx.Rect.nodeType: + s = new dojox.gfx.Rect(node); + attachRect(s); + break; + case dojox.gfx.Ellipse.nodeType: + if(node.style.width == node.style.height){ + s = new dojox.gfx.Circle(node); + attachCircle(s); + }else{ + s = new dojox.gfx.Ellipse(node); + attachEllipse(s); + } + break; + case dojox.gfx.Path.nodeType: + switch(node.getAttribute("dojoGfxType")){ + case "line": + s = new dojox.gfx.Line(node); + attachLine(s); + break; + case "polyline": + s = new dojox.gfx.Polyline(node); + attachPolyline(s); + break; + case "path": + s = new dojox.gfx.Path(node); + attachPath(s); + break; + case "text": + s = new dojox.gfx.Text(node); + attachText(s); + attachFont(s); + attachTextTransform(s); + break; + case "textpath": + s = new dojox.gfx.TextPath(node); + attachPath(s); + attachText(s); + attachFont(s); + break; + } + break; + case dojox.gfx.Image.nodeType: + switch(node.getAttribute("dojoGfxType")){ + case "image": + s = new dojox.gfx.Image(node); + attachImage(s); + attachImageTransform(s); + break; + } + break; + default: + //console.debug("FATAL ERROR! tagName = " + node.tagName); + return null; + } + if(!(s instanceof dojox.gfx.Image)){ + attachFill(s); + attachStroke(s); + if(!(s instanceof dojox.gfx.Text)){ + attachTransform(s); + } + } + return s; // dojox.gfx.Shape + }; + + dojox.gfx.attachSurface = function(node){ + // summary: creates a surface from a Node + // node: Node: an VML node + var s = new dojox.gfx.Surface(); + s.clipNode = node; + var r = s.rawNode = node.firstChild; + var b = r.firstChild; + if(!b || b.tagName != "rect"){ + return null; // dojox.gfx.Surface + } + s.bgNode = r; + return s; // dojox.gfx.Surface + }; + + var attachFill = function(object){ + // summary: deduces a fill style from a node. + // object: dojox.gfx.Shape: an VML shape + var fillStyle = null, r = object.rawNode, fo = r.fill; + if(fo.on && fo.type == "gradient"){ + var fillStyle = dojo.clone(dojox.gfx.defaultLinearGradient), + rad = dojox.gfx.matrix._degToRad(fo.angle); + fillStyle.x2 = Math.cos(rad); + fillStyle.y2 = Math.sin(rad); + fillStyle.colors = []; + var stops = fo.colors.value.split(";"); + for(var i = 0; i < stops.length; ++i){ + var t = stops[i].match(/\S+/g); + if(!t || t.length != 2){ continue; } + fillStyle.colors.push({offset: dojox.gfx.vml._parseFloat(t[0]), color: new dojo.Color(t[1])}); + } + }else if(fo.on && fo.type == "gradientradial"){ + var fillStyle = dojo.clone(dojox.gfx.defaultRadialGradient), + w = parseFloat(r.style.width), h = parseFloat(r.style.height); + fillStyle.cx = isNaN(w) ? 0 : fo.focusposition.x * w; + fillStyle.cy = isNaN(h) ? 0 : fo.focusposition.y * h; + fillStyle.r = isNaN(w) ? 1 : w / 2; + fillStyle.colors = []; + var stops = fo.colors.value.split(";"); + for(var i = stops.length - 1; i >= 0; --i){ + var t = stops[i].match(/\S+/g); + if(!t || t.length != 2){ continue; } + fillStyle.colors.push({offset: dojox.gfx.vml._parseFloat(t[0]), color: new dojo.Color(t[1])}); + } + }else if(fo.on && fo.type == "tile"){ + var fillStyle = dojo.clone(dojox.gfx.defaultPattern); + fillStyle.width = dojox.gfx.pt2px(fo.size.x); // from pt + fillStyle.height = dojox.gfx.pt2px(fo.size.y); // from pt + fillStyle.x = fo.origin.x * fillStyle.width; + fillStyle.y = fo.origin.y * fillStyle.height; + fillStyle.src = fo.src; + }else if(fo.on && r.fillcolor){ + // a color object ! + fillStyle = new dojo.Color(r.fillcolor+""); + fillStyle.a = fo.opacity; + } + object.fillStyle = fillStyle; + }; + + var attachStroke = function(object) { + // summary: deduces a stroke style from a node. + // object: dojox.gfx.Shape: an VML shape + var r = object.rawNode; + if(!r.stroked){ + object.strokeStyle = null; + return; + } + var strokeStyle = object.strokeStyle = dojo.clone(dojox.gfx.defaultStroke), + rs = r.stroke; + strokeStyle.color = new dojo.Color(r.strokecolor.value); + strokeStyle.width = dojox.gfx.normalizedLength(r.strokeweight+""); + strokeStyle.color.a = rs.opacity; + strokeStyle.cap = this._translate(this._capMapReversed, rs.endcap); + strokeStyle.join = rs.joinstyle == "miter" ? rs.miterlimit : rs.joinstyle; + strokeStyle.style = rs.dashstyle; + }; + + var attachTransform = function(object) { + // summary: deduces a transformation matrix from a node. + // object: dojox.gfx.Shape: an VML shape + var s = rawNode.skew, sm = s.matrix, so = s.offset; + object.matrix = dojox.gfx.matrix.normalize({ + xx: sm.xtox, + xy: sm.ytox, + yx: sm.xtoy, + yy: sm.ytoy, + dx: dojox.gfx.pt2px(so.x), + dy: dojox.gfx.pt2px(so.y) + }); + }; + + var attachGroup = function(object){ + // summary: reconstructs all group shape parameters from a node (VML). + // object: dojox.gfx.Shape: an VML shape + // attach the background + object.bgNode = object.rawNode.firstChild; // TODO: check it first + }; + + var attachRect = function(object){ + // summary: builds a rectangle shape from a node. + // object: dojox.gfx.Shape: an VML shape + // a workaround for the VML's arcsize bug: cannot read arcsize of an instantiated node + var r = object.rawNode, arcsize = r.outerHTML.match(/arcsize = \"(\d*\.?\d+[%f]?)\"/)[1], + style = r.style, width = parseFloat(style.width), height = parseFloat(style.height); + arcsize = (arcsize.indexOf("%") >= 0) ? parseFloat(arcsize) / 100 : dojox.gfx.vml._parseFloat(arcsize); + // make an object + object.shape = dojox.gfx.makeParameters(dojox.gfx.defaultRect, { + x: parseInt(style.left), + y: parseInt(style.top), + width: width, + height: height, + r: Math.min(width, height) * arcsize + }); + }; + + var attachEllipse = function(object){ + // summary: builds an ellipse shape from a node. + // object: dojox.gfx.Shape: an VML shape + var style = object.rawNode.style, + rx = parseInt(style.width ) / 2, + ry = parseInt(style.height) / 2; + object.shape = dojox.gfx.makeParameters(dojox.gfx.defaultEllipse, { + cx: parseInt(style.left) + rx, + cy: parseInt(style.top ) + ry, + rx: rx, + ry: ry + }); + }; + + var attachCircle = function(object){ + // summary: builds a circle shape from a node. + // object: dojox.gfx.Shape: an VML shape + var style = object.rawNode.style, r = parseInt(style.width) / 2; + object.shape = dojox.gfx.makeParameters(dojox.gfx.defaultCircle, { + cx: parseInt(style.left) + r, + cy: parseInt(style.top) + r, + r: r + }); + }; + + var attachLine = function(object){ + // summary: builds a line shape from a node. + // object: dojox.gfx.Shape: an VML shape + var shape = object.shape = dojo.clone(dojox.gfx.defaultLine), + p = object.rawNode.path.v.match(dojox.gfx.pathVmlRegExp); + do{ + if(p.length < 7 || p[0] != "m" || p[3] != "l" || p[6] != "e"){ break; } + shape.x1 = parseInt(p[1]); + shape.y1 = parseInt(p[2]); + shape.x2 = parseInt(p[4]); + shape.y2 = parseInt(p[5]); + }while(false); + }; + + var attachPolyline = function(object){ + // summary: builds a polyline/polygon shape from a node. + // object: dojox.gfx.Shape: an VML shape + var shape = object.shape = dojo.clone(dojox.gfx.defaultPolyline), + p = object.rawNode.path.v.match(dojox.gfx.pathVmlRegExp); + do{ + if(p.length < 3 || p[0] != "m"){ break; } + var x = parseInt(p[0]), y = parseInt(p[1]); + if(isNaN(x) || isNaN(y)){ break; } + shape.points.push({x: x, y: y}); + if(p.length < 6 || p[3] != "l"){ break; } + for(var i = 4; i < p.length; i += 2){ + x = parseInt(p[i]); + y = parseInt(p[i + 1]); + if(isNaN(x) || isNaN(y)){ break; } + shape.points.push({x: x, y: y}); + } + }while(false); + }; + + var attachImage = function(object){ + // summary: builds an image shape from a node. + // object: dojox.gfx.Shape: an VML shape + object.shape = dojo.clone(dojox.gfx.defaultImage); + object.shape.src = object.rawNode.firstChild.src; + }; + + var attachImageTransform = function(object) { + // summary: deduces a transformation matrix from a node. + // object: dojox.gfx.Shape: an VML shape + var m = object.rawNode.filters["DXImageTransform.Microsoft.Matrix"]; + object.matrix = dojox.gfx.matrix.normalize({ + xx: m.M11, + xy: m.M12, + yx: m.M21, + yy: m.M22, + dx: m.Dx, + dy: m.Dy + }); + }; + + var attachText = function(object){ + // summary: builds a text shape from a node. + // object: dojox.gfx.Shape: an VML shape + var shape = object.shape = dojo.clone(dojox.gfx.defaultText), + r = object.rawNode, p = r.path.v.match(dojox.gfx.pathVmlRegExp); + do{ + if(!p || p.length != 7){ break; } + var c = r.childNodes, i = 0; + for(; i < c.length && c[i].tagName != "textpath"; ++i); + if(i >= c.length){ break; } + var s = c[i].style; + shape.text = c[i].string; + switch(s["v-text-align"]){ + case "left": + shape.x = parseInt(p[1]); + shape.align = "start"; + break; + case "center": + shape.x = (parseInt(p[1]) + parseInt(p[4])) / 2; + shape.align = "middle"; + break; + case "right": + shape.x = parseInt(p[4]); + shape.align = "end"; + break; + } + shape.y = parseInt(p[2]); + shape.decoration = s["text-decoration"]; + shape.rotated = s["v-rotate-letters"].toLowerCase() in dojox.gfx.vml._bool; + shape.kerning = s["v-text-kern"].toLowerCase() in dojox.gfx.vml._bool; + return; + }while(false); + object.shape = null; + }; + + var attachFont = function(object){ + // summary: deduces a font style from a node. + // object: dojox.gfx.Shape: an VML shape + var fontStyle = object.fontStyle = dojo.clone(dojox.gfx.defaultFont), + c = object.rawNode.childNodes, i = 0; + for(; i < c.length && c[i].tagName == "textpath"; ++i); + if(i >= c.length){ + object.fontStyle = null; + return; + } + var s = c[i].style; + fontStyle.style = s.fontstyle; + fontStyle.variant = s.fontvariant; + fontStyle.weight = s.fontweight; + fontStyle.size = s.fontsize; + fontStyle.family = s.fontfamily; + }; + + var attachTextTransform = function(object) { + // summary: deduces a transformation matrix from a node. + // object: dojox.gfx.Shape: an VML shape + attachTransform(object); + var matrix = object.matrix, fs = object.fontStyle; + // see comments in _getRealMatrix() + if(matrix && fs){ + object.matrix = dojox.gfx.matrix.multiply(matrix, {dy: dojox.gfx.normalizedLength(fs.size) * 0.35}); + } + }; + + var attachPath = function(object){ + // summary: builds a path shape from a Node. + // object: dojox.gfx.Shape: an VML shape + var shape = object.shape = dojo.clone(dojox.gfx.defaultPath), + p = rawNode.path.v.match(dojox.gfx.pathVmlRegExp), + t = [], skip = false, map = dojox.gfx.Path._pathVmlToSvgMap; + for(var i = 0; i < p.length; ++p){ + var s = p[i]; + if(s in map) { + skip = false; + t.push(map[s]); + } else if(!skip){ + var n = parseInt(s); + if(isNaN(n)){ + skip = true; + }else{ + t.push(n); + } + } + } + var l = t.length; + if(l >= 4 && t[l - 1] == "" && t[l - 2] == 0 && t[l - 3] == 0 && t[l - 4] == "l"){ + t.splice(l - 4, 4); + } + if(l){ + shape.path = t.join(" "); + } + }; +})(); diff --git a/includes/js/dojox/gfx3d.js b/includes/js/dojox/gfx3d.js new file mode 100644 index 0000000..fbd5c63 --- /dev/null +++ b/includes/js/dojox/gfx3d.js @@ -0,0 +1,11 @@ +if(!dojo._hasResource["dojox.gfx3d"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx3d"] = true; +dojo.provide("dojox.gfx3d"); + +dojo.require("dojox.gfx3d.matrix"); +dojo.require("dojox.gfx3d._base"); +dojo.require("dojox.gfx3d.object"); + + + +} diff --git a/includes/js/dojox/gfx3d/README b/includes/js/dojox/gfx3d/README new file mode 100644 index 0000000..bc7ed4e --- /dev/null +++ b/includes/js/dojox/gfx3d/README @@ -0,0 +1,36 @@ +------------------------------------------------------------------------------- +dojox.gfx3d +------------------------------------------------------------------------------- +Version 0.100 +Release date: 10/31/2007 +------------------------------------------------------------------------------- +Project state: +beta +------------------------------------------------------------------------------- +Credits + Kun Xi (bookstack@gmail.com) + Eugene Lazutkin (eugene.lazutkin@gmail.com) +------------------------------------------------------------------------------- +Project description + +Implementation of simple portable 3D graphics library. +------------------------------------------------------------------------------- +Dependencies: + +Dojo Core, dojox.gfx. +------------------------------------------------------------------------------- +Documentation + +Not ready yet. +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/gfx3d.js +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/gfx3d/* + +Install into the following directory structure: +/dojox/gfx3d/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- diff --git a/includes/js/dojox/gfx3d/_base.js b/includes/js/dojox/gfx3d/_base.js new file mode 100644 index 0000000..dbc7748 --- /dev/null +++ b/includes/js/dojox/gfx3d/_base.js @@ -0,0 +1,19 @@ +if(!dojo._hasResource["dojox.gfx3d._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx3d._base"] = true; +dojo.provide("dojox.gfx3d._base"); + +dojo.mixin(dojox.gfx3d, { + // summary: defines constants, prototypes, and utility functions + + // default objects, which are used to fill in missing parameters + defaultEdges: {type: "edges", style: null, points: []}, + defaultTriangles: {type: "triangles", style: null, points: []}, + defaultQuads: {type: "quads", style: null, points: []}, + defaultOrbit: {type: "orbit", center: {x: 0, y: 0, z: 0}, radius: 50}, + defaultPath3d: {type: "path3d", path: []}, + defaultPolygon: {type: "polygon", path: []}, + defaultCube: {type: "cube", bottom: {x: 0, y: 0, z: 0}, top: {x: 100, y: 100, z: 100}}, + defaultCylinder: {type: "cylinder", center: /* center of bottom */ {x: 0, y: 0, z: 0}, height: 100, radius: 50} +}); + +} diff --git a/includes/js/dojox/gfx3d/gradient.js b/includes/js/dojox/gfx3d/gradient.js new file mode 100644 index 0000000..fa93720 --- /dev/null +++ b/includes/js/dojox/gfx3d/gradient.js @@ -0,0 +1,41 @@ +if(!dojo._hasResource["dojox.gfx3d.gradient"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx3d.gradient"] = true; +dojo.provide("dojox.gfx3d.gradient"); + +dojo.require("dojox.gfx3d.vector"); +dojo.require("dojox.gfx3d.matrix"); + +(function(){ + var dist = function(a, b){ return Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2)); }; + var N = 32; + + dojox.gfx3d.gradient = function(model, material, center, radius, from, to, matrix){ + // summary: calculate a cylindrical gradient + // model: dojox.gfx3d.lighting.Model: color model + // material: Object: defines visual properties + // center: Object: center of the cylinder's bottom + // radius: Number: radius of the cylinder + // from: Number: from position in radians + // to: Number: from position in radians + // matrix: dojox.gfx3d.Matrix3D: the cumulative transformation matrix + // tolerance: Number: tolerable diffirence in colors between gradient steps + + var m = dojox.gfx3d.matrix, v = dojox.gfx3d.vector, mx = m.normalize(matrix), + f = m.multiplyPoint(mx, radius * Math.cos(from) + center.x, radius * Math.sin(from) + center.y, center.z), + t = m.multiplyPoint(mx, radius * Math.cos(to) + center.x, radius * Math.sin(to) + center.y, center.z), + c = m.multiplyPoint(mx, center.x, center.y, center.z), step = (to - from) / N, r = dist(f, t) / 2, + mod = model[material.type], fin = material.finish, pmt = material.color, + colors = [{offset: 0, color: mod.call(model, v.substract(f, c), fin, pmt)}]; + + for(var a = from + step; a < to; a += step){ + var p = m.multiplyPoint(mx, radius * Math.cos(a) + center.x, radius * Math.sin(a) + center.y, center.z), + df = dist(f, p), dt = dist(t, p); + colors.push({offset: df / (df + dt), color: mod.call(model, v.substract(p, c), fin, pmt)}); + } + colors.push({offset: 1, color: mod.call(model, v.substract(t, c), fin, pmt)}); + + return {type: "linear", x1: 0, y1: -r, x2: 0, y2: r, colors: colors}; + }; +})(); + +} diff --git a/includes/js/dojox/gfx3d/lighting.js b/includes/js/dojox/gfx3d/lighting.js new file mode 100644 index 0000000..bbd40de --- /dev/null +++ b/includes/js/dojox/gfx3d/lighting.js @@ -0,0 +1,241 @@ +if(!dojo._hasResource["dojox.gfx3d.lighting"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx3d.lighting"] = true; +dojo.provide("dojox.gfx3d.lighting"); +dojo.require("dojox.gfx._base"); + +(function(){ + var lite = dojox.gfx3d.lighting; + + dojo.mixin(dojox.gfx3d.lighting, { + // color utilities + black: function(){ + return {r: 0, g: 0, b: 0, a: 1}; + }, + white: function(){ + return {r: 1, g: 1, b: 1, a: 1}; + }, + toStdColor: function(c){ + c = dojox.gfx.normalizeColor(c); + return {r: c.r / 255, g: c.g / 255, b: c.b / 255, a: c.a}; + }, + fromStdColor: function(c){ + return new dojo.Color([Math.round(255 * c.r), Math.round(255 * c.g), Math.round(255 * c.b), c.a]); + }, + scaleColor: function(s, c){ + return {r: s * c.r, g: s * c.g, b: s * c.b, a: s * c.a}; + }, + addColor: function(a, b){ + return {r: a.r + b.r, g: a.g + b.g, b: a.b + b.b, a: a.a + b.a}; + }, + multiplyColor: function(a, b){ + return {r: a.r * b.r, g: a.g * b.g, b: a.b * b.b, a: a.a * b.a}; + }, + saturateColor: function(c){ + return { + r: c.r < 0 ? 0 : c.r > 1 ? 1 : c.r, + g: c.g < 0 ? 0 : c.g > 1 ? 1 : c.g, + b: c.b < 0 ? 0 : c.b > 1 ? 1 : c.b, + a: c.a < 0 ? 0 : c.a > 1 ? 1 : c.a + }; + }, + mixColor: function(c1, c2, s){ + return lite.addColor(lite.scaleColor(s, c1), lite.scaleColor(1 - s, c2)); + }, + diff2Color: function(c1, c2){ + var r = c1.r - c2.r; + var g = c1.g - c2.g; + var b = c1.b - c2.b; + var a = c1.a - c2.a; + return r * r + g * g + b * b + a * a; + }, + length2Color: function(c){ + return c.r * c.r + c.g * c.g + c.b * c.b + c.a * c.a; + }, + + // vector utilities + //TODO: move vector utilities from this file to vector.js + dot: function(a, b){ + return a.x * b.x + a.y * b.y + a.z * b.z; + }, + scale: function(s, v){ + return {x: s * v.x, y: s * v.y, z: s * v.z}; + }, + add: function(a, b){ + return {x: a.x + b.x, y: a.y + b.y, z: a.z + b.z}; + }, + saturate: function(v){ + return Math.min(Math.max(v, 0), 1); + }, + length: function(v){ + return Math.sqrt(dojox.gfx3d.lighting.dot(v, v)); + }, + normalize: function(v){ + return lite.scale(1 / lite.length(v), v); + }, + faceforward: function(n, i){ + var p = dojox.gfx3d.lighting; + var s = p.dot(i, n) < 0 ? 1 : -1; + return p.scale(s, n); + }, + reflect: function(i, n){ + var p = dojox.gfx3d.lighting; + return p.add(i, p.scale(-2 * p.dot(i, n), n)); + }, + + // lighting utilities + diffuse: function(normal, lights){ + var c = lite.black(); + for(var i = 0; i < lights.length; ++i){ + var l = lights[i], + d = lite.dot(lite.normalize(l.direction), normal); + c = lite.addColor(c, lite.scaleColor(d, l.color)); + } + return lite.saturateColor(c); + }, + specular: function(normal, v, roughness, lights){ + var c = lite.black(); + for(var i = 0; i < lights.length; ++i){ + var l = lights[i], + h = lite.normalize(lite.add(lite.normalize(l.direction), v)), + s = Math.pow(Math.max(0, lite.dot(normal, h)), 1 / roughness); + c = lite.addColor(c, lite.scaleColor(s, l.color)); + } + return lite.saturateColor(c); + }, + phong: function(normal, v, size, lights){ + normal = lite.normalize(normal); + var c = lite.black(); + for(var i = 0; i < lights.length; ++i){ + var l = lights[i], + r = lite.reflect(lite.scale(-1, lite.normalize(v)), normal), + s = Math.pow(Math.max(0, lite.dot(r, lite.normalize(l.direction))), size); + c = lite.addColor(c, lite.scaleColor(s, l.color)); + } + return lite.saturateColor(c); + } + }); + + // this lighting model is derived from RenderMan Interface Specification Version 3.2 + + dojo.declare("dojox.gfx3d.lighting.Model", null, { + constructor: function(incident, lights, ambient, specular){ + this.incident = lite.normalize(incident); + this.lights = []; + for(var i = 0; i < lights.length; ++i){ + var l = lights[i]; + this.lights.push({direction: lite.normalize(l.direction), color: lite.toStdColor(l.color)}); + } + this.ambient = lite.toStdColor(ambient.color ? ambient.color : "white"); + this.ambient = lite.scaleColor(ambient.intensity, this.ambient); + this.ambient = lite.scaleColor(this.ambient.a, this.ambient); + this.ambient.a = 1; + this.specular = lite.toStdColor(specular ? specular : "white"); + this.specular = lite.scaleColor(this.specular.a, this.specular); + this.specular.a = 1; + this.npr_cool = {r: 0, g: 0, b: 0.4, a: 1}; + this.npr_warm = {r: 0.4, g: 0.4, b: 0.2, a: 1}; + this.npr_alpha = 0.2; + this.npr_beta = 0.6; + this.npr_scale = 0.6; + }, + constant: function(normal, finish, pigment){ + pigment = lite.toStdColor(pigment); + var alpha = pigment.a, color = lite.scaleColor(alpha, pigment); + color.a = alpha; + return lite.fromStdColor(lite.saturateColor(color)); + }, + matte: function(normal, finish, pigment){ + if(typeof finish == "string"){ finish = lite.finish[finish]; } + pigment = lite.toStdColor(pigment); + normal = lite.faceforward(lite.normalize(normal), this.incident); + var ambient = lite.scaleColor(finish.Ka, this.ambient), + shadow = lite.saturate(-4 * lite.dot(normal, this.incident)), + diffuse = lite.scaleColor(shadow * finish.Kd, lite.diffuse(normal, this.lights)), + color = lite.scaleColor(pigment.a, lite.multiplyColor(pigment, lite.addColor(ambient, diffuse))); + color.a = pigment.a; + return lite.fromStdColor(lite.saturateColor(color)); + }, + metal: function(normal, finish, pigment){ + if(typeof finish == "string"){ finish = lite.finish[finish]; } + pigment = lite.toStdColor(pigment); + normal = lite.faceforward(lite.normalize(normal), this.incident); + var v = lite.scale(-1, this.incident), specular, color, + ambient = lite.scaleColor(finish.Ka, this.ambient), + shadow = lite.saturate(-4 * lite.dot(normal, this.incident)); + if("phong" in finish){ + specular = lite.scaleColor(shadow * finish.Ks * finish.phong, lite.phong(normal, v, finish.phong_size, this.lights)); + }else{ + specular = lite.scaleColor(shadow * finish.Ks, lite.specular(normal, v, finish.roughness, this.lights)); + } + color = lite.scaleColor(pigment.a, lite.addColor(lite.multiplyColor(pigment, ambient), lite.multiplyColor(this.specular, specular))); + color.a = pigment.a; + return lite.fromStdColor(lite.saturateColor(color)); + }, + plastic: function(normal, finish, pigment){ + if(typeof finish == "string"){ finish = lite.finish[finish]; } + pigment = lite.toStdColor(pigment); + normal = lite.faceforward(lite.normalize(normal), this.incident); + var v = lite.scale(-1, this.incident), specular, color, + ambient = lite.scaleColor(finish.Ka, this.ambient), + shadow = lite.saturate(-4 * lite.dot(normal, this.incident)), + diffuse = lite.scaleColor(shadow * finish.Kd, lite.diffuse(normal, this.lights)); + if("phong" in finish){ + specular = lite.scaleColor(shadow * finish.Ks * finish.phong, lite.phong(normal, v, finish.phong_size, this.lights)); + }else{ + specular = lite.scaleColor(shadow * finish.Ks, lite.specular(normal, v, finish.roughness, this.lights)); + } + color = lite.scaleColor(pigment.a, lite.addColor(lite.multiplyColor(pigment, lite.addColor(ambient, diffuse)), lite.multiplyColor(this.specular, specular))); + color.a = pigment.a; + return lite.fromStdColor(lite.saturateColor(color)); + }, + npr: function(normal, finish, pigment){ + if(typeof finish == "string"){ finish = lite.finish[finish]; } + pigment = lite.toStdColor(pigment); + normal = lite.faceforward(lite.normalize(normal), this.incident); + var ambient = lite.scaleColor(finish.Ka, this.ambient), + shadow = lite.saturate(-4 * lite.dot(normal, this.incident)), + diffuse = lite.scaleColor(shadow * finish.Kd, lite.diffuse(normal, this.lights)), + color = lite.scaleColor(pigment.a, lite.multiplyColor(pigment, lite.addColor(ambient, diffuse))), + cool = lite.addColor(this.npr_cool, lite.scaleColor(this.npr_alpha, color)), + warm = lite.addColor(this.npr_warm, lite.scaleColor(this.npr_beta, color)), + d = (1 + lite.dot(this.incident, normal)) / 2, + color = lite.scaleColor(this.npr_scale, lite.addColor(color, lite.mixColor(cool, warm, d))); + color.a = pigment.a; + return lite.fromStdColor(lite.saturateColor(color)); + } + }); +})(); + +// POV-Ray basic finishes + +dojox.gfx3d.lighting.finish = { + + // Default + + defaults: {Ka: 0.1, Kd: 0.6, Ks: 0.0, roughness: 0.05}, + + dull: {Ka: 0.1, Kd: 0.6, Ks: 0.5, roughness: 0.15}, + shiny: {Ka: 0.1, Kd: 0.6, Ks: 1.0, roughness: 0.001}, + glossy: {Ka: 0.1, Kd: 0.6, Ks: 1.0, roughness: 0.0001}, + + phong_dull: {Ka: 0.1, Kd: 0.6, Ks: 0.5, phong: 0.5, phong_size: 1}, + phong_shiny: {Ka: 0.1, Kd: 0.6, Ks: 1.0, phong: 1.0, phong_size: 200}, + phong_glossy: {Ka: 0.1, Kd: 0.6, Ks: 1.0, phong: 1.0, phong_size: 300}, + + luminous: {Ka: 1.0, Kd: 0.0, Ks: 0.0, roughness: 0.05}, + + // Metals + + // very soft and dull + metalA: {Ka: 0.35, Kd: 0.3, Ks: 0.8, roughness: 1/20}, + // fairly soft and dull + metalB: {Ka: 0.30, Kd: 0.4, Ks: 0.7, roughness: 1/60}, + // medium reflectivity, holds color well + metalC: {Ka: 0.25, Kd: 0.5, Ks: 0.8, roughness: 1/80}, + // highly hard and polished, high reflectivity + metalD: {Ka: 0.15, Kd: 0.6, Ks: 0.8, roughness: 1/100}, + // very highly polished and reflective + metalE: {Ka: 0.10, Kd: 0.7, Ks: 0.8, roughness: 1/120} +}; + +} diff --git a/includes/js/dojox/gfx3d/matrix.js b/includes/js/dojox/gfx3d/matrix.js new file mode 100644 index 0000000..277b7d5 --- /dev/null +++ b/includes/js/dojox/gfx3d/matrix.js @@ -0,0 +1,339 @@ +if(!dojo._hasResource["dojox.gfx3d.matrix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx3d.matrix"] = true; +dojo.provide("dojox.gfx3d.matrix"); + +// candidates for dojox.math: +dojox.gfx3d.matrix._degToRad = function(degree){ return Math.PI * degree / 180; }; +dojox.gfx3d.matrix._radToDeg = function(radian){ return radian / Math.PI * 180; }; + +dojox.gfx3d.matrix.Matrix3D = function(arg){ + // summary: a 3D matrix object + // description: Normalizes a 3D matrix-like object. If arrays is passed, + // all objects of the array are normalized and multiplied sequentially. + // arg: Object + // a 3D matrix-like object, a number, or an array of such objects + if(arg){ + if(typeof arg == "number"){ + this.xx = this.yy = this.zz = arg; + }else if(arg instanceof Array){ + if(arg.length > 0){ + var m = dojox.gfx3d.matrix.normalize(arg[0]); + // combine matrices + for(var i = 1; i < arg.length; ++i){ + var l = m; + var r = dojox.gfx3d.matrix.normalize(arg[i]); + m = new dojox.gfx3d.matrix.Matrix3D(); + m.xx = l.xx * r.xx + l.xy * r.yx + l.xz * r.zx; + m.xy = l.xx * r.xy + l.xy * r.yy + l.xz * r.zy; + m.xz = l.xx * r.xz + l.xy * r.yz + l.xz * r.zz; + m.yx = l.yx * r.xx + l.yy * r.yx + l.yz * r.zx; + m.yy = l.yx * r.xy + l.yy * r.yy + l.yz * r.zy; + m.yz = l.yx * r.xz + l.yy * r.yz + l.yz * r.zz; + m.zx = l.zx * r.xx + l.zy * r.yx + l.zz * r.zx; + m.zy = l.zx * r.xy + l.zy * r.yy + l.zz * r.zy; + m.zz = l.zx * r.xz + l.zy * r.yz + l.zz * r.zz; + m.dx = l.xx * r.dx + l.xy * r.dy + l.xz * r.dz + l.dx; + m.dy = l.yx * r.dx + l.yy * r.dy + l.yz * r.dz + l.dy; + m.dz = l.zx * r.dx + l.zy * r.dy + l.zz * r.dz + l.dz; + } + dojo.mixin(this, m); + } + }else{ + dojo.mixin(this, arg); + } + } +}; + +// the default (identity) matrix, which is used to fill in missing values +dojo.extend(dojox.gfx3d.matrix.Matrix3D, {xx: 1, xy: 0, xz: 0, yx: 0, yy: 1, yz: 0, zx: 0, zy: 0, zz: 1, dx: 0, dy: 0, dz: 0}); + +dojo.mixin(dojox.gfx3d.matrix, { + // summary: class constants, and methods of dojox.gfx3d.matrix + + // matrix constants + + // identity: dojox.gfx3d.matrix.Matrix3D + // an identity matrix constant: identity * (x, y, z) == (x, y, z) + identity: new dojox.gfx3d.matrix.Matrix3D(), + + // matrix creators + + translate: function(a, b, c){ + // summary: forms a translation matrix + // description: The resulting matrix is used to translate (move) points by specified offsets. + // a: Number: an x coordinate value + // b: Number: a y coordinate value + // c: Number: a z coordinate value + if(arguments.length > 1){ + return new dojox.gfx3d.matrix.Matrix3D({dx: a, dy: b, dz: c}); // dojox.gfx3d.matrix.Matrix3D + } + // branch + // a: Object: a point-like object, which specifies offsets for 3 dimensions + // b: null + return new dojox.gfx3d.matrix.Matrix3D({dx: a.x, dy: a.y, dz: a.z}); // dojox.gfx3d.matrix.Matrix3D + }, + scale: function(a, b, c){ + // summary: forms a scaling matrix + // description: The resulting matrix is used to scale (magnify) points by specified offsets. + // a: Number: a scaling factor used for the x coordinate + // b: Number: a scaling factor used for the y coordinate + // c: Number: a scaling factor used for the z coordinate + if(arguments.length > 1){ + return new dojox.gfx3d.matrix.Matrix3D({xx: a, yy: b, zz: c}); // dojox.gfx3d.matrix.Matrix3D + } + if(typeof a == "number"){ + // branch + // a: Number: a uniform scaling factor used for the all coordinates + // b: null + return new dojox.gfx3d.matrix.Matrix3D({xx: a, yy: a, zz: a}); // dojox.gfx3d.matrix.Matrix3D + } + // branch + // a: Object: a point-like object, which specifies scale factors for 3 dimensions + // b: null + return new dojox.gfx3d.matrix.Matrix3D({xx: a.x, yy: a.y, zz: a.z}); // dojox.gfx3d.matrix.Matrix3D + }, + rotateX: function(angle){ + // summary: forms a rotating matrix (about the x axis) + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified angle. + // angle: Number: an angle of rotation in radians (>0 for CW) + var c = Math.cos(angle); + var s = Math.sin(angle); + return new dojox.gfx3d.matrix.Matrix3D({yy: c, yz: -s, zy: s, zz: c}); // dojox.gfx3d.matrix.Matrix3D + }, + rotateXg: function(degree){ + // summary: forms a rotating matrix (about the x axis) + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified degree. + // See dojox.gfx3d.matrix.rotateX() for comparison. + // degree: Number: an angle of rotation in degrees (>0 for CW) + return dojox.gfx3d.matrix.rotateX(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D + }, + rotateY: function(angle){ + // summary: forms a rotating matrix (about the y axis) + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified angle. + // angle: Number: an angle of rotation in radians (>0 for CW) + var c = Math.cos(angle); + var s = Math.sin(angle); + return new dojox.gfx3d.matrix.Matrix3D({xx: c, xz: s, zx: -s, zz: c}); // dojox.gfx3d.matrix.Matrix3D + }, + rotateYg: function(degree){ + // summary: forms a rotating matrix (about the y axis) + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified degree. + // See dojox.gfx3d.matrix.rotateY() for comparison. + // degree: Number: an angle of rotation in degrees (>0 for CW) + return dojox.gfx3d.matrix.rotateY(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D + }, + rotateZ: function(angle){ + // summary: forms a rotating matrix (about the z axis) + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified angle. + // angle: Number: an angle of rotation in radians (>0 for CW) + var c = Math.cos(angle); + var s = Math.sin(angle); + return new dojox.gfx3d.matrix.Matrix3D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx3d.matrix.Matrix3D + }, + rotateZg: function(degree){ + // summary: forms a rotating matrix (about the z axis) + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified degree. + // See dojox.gfx3d.matrix.rotateZ() for comparison. + // degree: Number: an angle of rotation in degrees (>0 for CW) + return dojox.gfx3d.matrix.rotateZ(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D + }, + + // camera transformation + cameraTranslate: function(a, b, c){ + // summary: forms a translation matrix + // description: The resulting matrix is used to translate (move) points by specified offsets. + // a: Number: an x coordinate value + // b: Number: a y coordinate value + // c: Number: a z coordinate value + if(arguments.length > 1){ + return new dojox.gfx3d.matrix.Matrix3D({dx: -a, dy: -b, dz: -c}); // dojox.gfx3d.matrix.Matrix3D + } + // branch + // a: Object: a point-like object, which specifies offsets for 3 dimensions + // b: null + return new dojox.gfx3d.matrix.Matrix3D({dx: -a.x, dy: -a.y, dz: -a.z}); // dojox.gfx3d.matrix.Matrix3D + }, + cameraRotateX: function(angle){ + // summary: forms a rotating matrix (about the x axis) in cameraTransform manner + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified angle. + // angle: Number: an angle of rotation in radians (>0 for CW) + var c = Math.cos(-angle); + var s = Math.sin(-angle); + return new dojox.gfx3d.matrix.Matrix3D({yy: c, yz: -s, zy: s, zz: c}); // dojox.gfx3d.matrix.Matrix3D + }, + cameraRotateXg: function(degree){ + // summary: forms a rotating matrix (about the x axis)in cameraTransform manner + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified degree. + // See dojox.gfx3d.matrix.rotateX() for comparison. + // degree: Number: an angle of rotation in degrees (>0 for CW) + return dojox.gfx3d.matrix.rotateX(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D + }, + cameraRotateY: function(angle){ + // summary: forms a rotating matrix (about the y axis) in cameraTransform manner + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified angle. + // angle: Number: an angle of rotation in radians (>0 for CW) + var c = Math.cos(-angle); + var s = Math.sin(-angle); + return new dojox.gfx3d.matrix.Matrix3D({xx: c, xz: s, zx: -s, zz: c}); // dojox.gfx3d.matrix.Matrix3D + }, + cameraRotateYg: function(degree){ + // summary: forms a rotating matrix (about the y axis) in cameraTransform manner + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified degree. + // See dojox.gfx3d.matrix.rotateY() for comparison. + // degree: Number: an angle of rotation in degrees (>0 for CW) + return dojox.gfx3d.matrix.rotateY(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D + }, + cameraRotateZ: function(angle){ + // summary: forms a rotating matrix (about the z axis) in cameraTransform manner + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified angle. + // angle: Number: an angle of rotation in radians (>0 for CW) + var c = Math.cos(-angle); + var s = Math.sin(-angle); + return new dojox.gfx3d.matrix.Matrix3D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx3d.matrix.Matrix3D + }, + cameraRotateZg: function(degree){ + // summary: forms a rotating matrix (about the z axis) in cameraTransform manner + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified degree. + // See dojox.gfx3d.matrix.rotateZ() for comparison. + // degree: Number: an angle of rotation in degrees (>0 for CW) + return dojox.gfx3d.matrix.rotateZ(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D + }, + + // ensure matrix 3D conformance + normalize: function(matrix){ + // summary: converts an object to a matrix, if necessary + // description: Converts any 3D matrix-like object or an array of + // such objects to a valid dojox.gfx3d.matrix.Matrix3D object. + // matrix: Object: an object, which is converted to a matrix, if necessary + return (matrix instanceof dojox.gfx3d.matrix.Matrix3D) ? matrix : new dojox.gfx3d.matrix.Matrix3D(matrix); // dojox.gfx3d.matrix.Matrix3D + }, + + // common operations + + clone: function(matrix){ + // summary: creates a copy of a 3D matrix + // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix-like object to be cloned + var obj = new dojox.gfx3d.matrix.Matrix3D(); + for(var i in matrix){ + if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i]; + } + return obj; // dojox.gfx3d.matrix.Matrix3D + }, + invert: function(matrix){ + // summary: inverts a 2D matrix + // matrix: dojox.gfx.matrix.Matrix3D: a 2D matrix-like object to be inverted + var m = dojox.gfx3d.matrix.normalize(matrix); + var D = m.xx * m.yy * m.zz + m.xy * m.yz * m.zx + m.xz * m.yx * m.zy - m.xx * m.yz * m.zy - m.xy * m.yx * m.zz - m.xz * m.yy * m.zx; + var M = new dojox.gfx3d.matrix.Matrix3D({ + xx: (m.yy * m.zz - m.yz * m.zy) / D, + xy: (m.xz * m.zy - m.xy * m.zz) / D, + xz: (m.xy * m.yz - m.xz * m.yy) / D, + yx: (m.yz * m.zx - m.yx * m.zz) / D, + yy: (m.xx * m.zz - m.xz * m.zx) / D, + yz: (m.xz * m.yx - m.xx * m.yz) / D, + zx: (m.yx * m.zy - m.yy * m.zx) / D, + zy: (m.xy * m.zx - m.xx * m.zy) / D, + zz: (m.xx * m.yy - m.xy * m.yx) / D, + dx: -1 * (m.xy * m.yz * m.dz + m.xz * m.dy * m.zy + m.dx * m.yy * m.zz - m.xy * m.dy * m.zz - m.xz * m.yy * m.dz - m.dx * m.yz * m.zy) / D, + dy: (m.xx * m.yz * m.dz + m.xz * m.dy * m.zx + m.dx * m.yx * m.zz - m.xx * m.dy * m.zz - m.xz * m.yx * m.dz - m.dx * m.yz * m.zx) / D, + dz: -1 * (m.xx * m.yy * m.dz + m.xy * m.dy * m.zx + m.dx * m.yx * m.zy - m.xx * m.dy * m.zy - m.xy * m.yx * m.dz - m.dx * m.yy * m.zx) / D + }); + return M; // dojox.gfx3d.matrix.Matrix3D + }, + _multiplyPoint: function(m, x, y, z){ + // summary: applies a matrix to a point + // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied + // x: Number: an x coordinate of a point + // y: Number: a y coordinate of a point + // z: Number: a z coordinate of a point + return {x: m.xx * x + m.xy * y + m.xz * z + m.dx, y: m.yx * x + m.yy * y + m.yz * z + m.dy, z: m.zx * x + m.zy * y + m.zz * z + m.dz}; // Object + }, + multiplyPoint: function(matrix, /* Number||Point */ a, /* Number, optional */ b, /* Number, optional */ c){ + // summary: applies a matrix to a point + // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied + // a: Number: an x coordinate of a point + // b: Number: a y coordinate of a point + // c: Number: a z coordinate of a point + var m = dojox.gfx3d.matrix.normalize(matrix); + if(typeof a == "number" && typeof b == "number" && typeof c == "number"){ + return dojox.gfx3d.matrix._multiplyPoint(m, a, b, c); // Object + } + // branch + // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied + // a: Object: a point + // b: null + // c: null + return dojox.gfx3d.matrix._multiplyPoint(m, a.x, a.y, a.z); // Object + }, + multiply: function(matrix){ + // summary: combines matrices by multiplying them sequentially in the given order + // matrix: dojox.gfx3d.matrix.Matrix3D...: a 3D matrix-like object, + // all subsequent arguments are matrix-like objects too + var m = dojox.gfx3d.matrix.normalize(matrix); + // combine matrices + for(var i = 1; i < arguments.length; ++i){ + var l = m; + var r = dojox.gfx3d.matrix.normalize(arguments[i]); + m = new dojox.gfx3d.matrix.Matrix3D(); + m.xx = l.xx * r.xx + l.xy * r.yx + l.xz * r.zx; + m.xy = l.xx * r.xy + l.xy * r.yy + l.xz * r.zy; + m.xz = l.xx * r.xz + l.xy * r.yz + l.xz * r.zz; + m.yx = l.yx * r.xx + l.yy * r.yx + l.yz * r.zx; + m.yy = l.yx * r.xy + l.yy * r.yy + l.yz * r.zy; + m.yz = l.yx * r.xz + l.yy * r.yz + l.yz * r.zz; + m.zx = l.zx * r.xx + l.zy * r.yx + l.zz * r.zx; + m.zy = l.zx * r.xy + l.zy * r.yy + l.zz * r.zy; + m.zz = l.zx * r.xz + l.zy * r.yz + l.zz * r.zz; + m.dx = l.xx * r.dx + l.xy * r.dy + l.xz * r.dz + l.dx; + m.dy = l.yx * r.dx + l.yy * r.dy + l.yz * r.dz + l.dy; + m.dz = l.zx * r.dx + l.zy * r.dy + l.zz * r.dz + l.dz; + } + return m; // dojox.gfx3d.matrix.Matrix3D + }, + + _project: function(m, x, y, z){ + // summary: applies a matrix to a point + // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied + // x: Number: an x coordinate of a point + // y: Number: a y coordinate of a point + // z: Number: a z coordinate of a point + return { // Object + x: m.xx * x + m.xy * y + m.xz * z + m.dx, + y: m.yx * x + m.yy * y + m.yz * z + m.dy, + z: m.zx * x + m.zy * y + m.zz * z + m.dz}; + }, + project: function(matrix, /* Number||Point */ a, /* Number, optional */ b, /* Number, optional */ c){ + // summary: applies a matrix to a point + // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied + // a: Number: an x coordinate of a point + // b: Number: a y coordinate of a point + // c: Number: a z coordinate of a point + var m = dojox.gfx3d.matrix.normalize(matrix); + if(typeof a == "number" && typeof b == "number" && typeof c == "number"){ + return dojox.gfx3d.matrix._project(m, a, b, c); // Object + } + // branch + // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied + // a: Object: a point + // b: null + // c: null + return dojox.gfx3d.matrix._project(m, a.x, a.y, a.z); // Object + } +}); + +// propagate matrix up +dojox.gfx3d.Matrix3D = dojox.gfx3d.matrix.Matrix3D; + +} diff --git a/includes/js/dojox/gfx3d/object.js b/includes/js/dojox/gfx3d/object.js new file mode 100644 index 0000000..e574c91 --- /dev/null +++ b/includes/js/dojox/gfx3d/object.js @@ -0,0 +1,1092 @@ +if(!dojo._hasResource["dojox.gfx3d.object"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx3d.object"] = true; +dojo.provide("dojox.gfx3d.object"); + +dojo.require("dojox.gfx"); +dojo.require("dojox.gfx3d.lighting"); +dojo.require("dojox.gfx3d.scheduler"); +dojo.require("dojox.gfx3d.vector"); +dojo.require("dojox.gfx3d.gradient"); + +// FIXME: why the global "out" var here? +var out = function(o, x){ + if(arguments.length > 1){ + // console.debug("debug:", o); + o = x; + } + var e = {}; + for(var i in o){ + if(i in e){ continue; } + // console.debug("debug:", i, typeof o[i], o[i]); + } +}; + +dojo.declare("dojox.gfx3d.Object", null, { + constructor: function(){ + // summary: a Object object, which knows how to map + // 3D objects to 2D shapes. + + // object: Object: an abstract Object object + // (see dojox.gfx3d.defaultEdges, + // dojox.gfx3d.defaultTriangles, + // dojox.gfx3d.defaultQuads + // dojox.gfx3d.defaultOrbit + // dojox.gfx3d.defaultCube + // or dojox.gfx3d.defaultCylinder) + this.object = null; + + // matrix: dojox.gfx3d.matrix: world transform + this.matrix = null; + // cache: buffer for intermediate result, used late for draw() + this.cache = null; + // renderer: a reference for the Viewport + this.renderer = null; + // parent: a reference for parent, Scene or Viewport object + this.parent = null; + + // strokeStyle: Object: a stroke object + this.strokeStyle = null; + // fillStyle: Object: a fill object or texture object + this.fillStyle = null; + // shape: dojox.gfx.Shape: an underlying 2D shape + this.shape = null; + }, + + setObject: function(newObject){ + // summary: sets a Object object + // object: Object: an abstract Object object + // (see dojox.gfx3d.defaultEdges, + // dojox.gfx3d.defaultTriangles, + // dojox.gfx3d.defaultQuads + // dojox.gfx3d.defaultOrbit + // dojox.gfx3d.defaultCube + // or dojox.gfx3d.defaultCylinder) + this.object = dojox.gfx.makeParameters(this.object, newObject); + return this; + }, + + setTransform: function(matrix){ + // summary: sets a transformation matrix + // matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object + // (see an argument of dojox.gfx3d.matrix.Matrix + // constructor for a list of acceptable arguments) + this.matrix = dojox.gfx3d.matrix.clone(matrix ? dojox.gfx3d.matrix.normalize(matrix) : dojox.gfx3d.identity, true); + return this; // self + }, + + // apply left & right transformation + + applyRightTransform: function(matrix){ + // summary: multiplies the existing matrix with an argument on right side + // (this.matrix * matrix) + // matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object + // (see an argument of dojox.gfx.matrix.Matrix + // constructor for a list of acceptable arguments) + return matrix ? this.setTransform([this.matrix, matrix]) : this; // self + }, + applyLeftTransform: function(matrix){ + // summary: multiplies the existing matrix with an argument on left side + // (matrix * this.matrix) + // matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object + // (see an argument of dojox.gfx.matrix.Matrix + // constructor for a list of acceptable arguments) + return matrix ? this.setTransform([matrix, this.matrix]) : this; // self + }, + + applyTransform: function(matrix){ + // summary: a shortcut for dojox.gfx.Shape.applyRightTransform + // matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object + // (see an argument of dojox.gfx.matrix.Matrix + // constructor for a list of acceptable arguments) + return matrix ? this.setTransform([this.matrix, matrix]) : this; // self + }, + + setFill: function(fill){ + // summary: sets a fill object + // (the default implementation is to delegate to + // the underlying 2D shape). + // fill: Object: a fill object + // (see dojox.gfx.defaultLinearGradient, + // dojox.gfx.defaultRadialGradient, + // dojox.gfx.defaultPattern, + // dojo.Color + // or dojox.gfx.MODEL) + this.fillStyle = fill; + return this; + }, + + setStroke: function(stroke){ + // summary: sets a stroke object + // (the default implementation simply ignores it) + // stroke: Object: a stroke object + // (see dojox.gfx.defaultStroke) + this.strokeStyle = stroke; + return this; + }, + + toStdFill: function(lighting, normal){ + return (this.fillStyle && typeof this.fillStyle['type'] != "undefined") ? lighting[this.fillStyle.type](normal, this.fillStyle.finish, this.fillStyle.color) : this.fillStyle; + }, + + invalidate: function(){ + this.renderer.addTodo(this); + }, + + destroy: function(){ + if(this.shape){ + var p = this.shape.getParent(); + if(p){ + p.remove(this.shape); + } + this.shape = null; + } + }, + + // All the 3D objects need to override the following virtual functions: + // render, getZOrder, getOutline, draw, redraw if necessary. + + render: function(camera){ + throw "Pure virtual function, not implemented"; + }, + + draw: function(lighting){ + throw "Pure virtual function, not implemented"; + }, + + getZOrder: function(){ + return 0; + }, + + getOutline: function(){ + return null; + } + +}); + +dojo.declare("dojox.gfx3d.Scene", dojox.gfx3d.Object, { + // summary: the Scene is just a containter. + // note: we have the following assumption: + // all objects in the Scene are not overlapped with other objects + // outside of the scene. + constructor: function(){ + // summary: a containter of other 3D objects + this.objects= []; + this.todos = []; + this.schedule = dojox.gfx3d.scheduler.zOrder; + this._draw = dojox.gfx3d.drawer.conservative; + }, + + setFill: function(fill){ + this.fillStyle = fill; + dojo.forEach(this.objects, function(item){ + item.setFill(fill); + }); + return this; + }, + + setStroke: function(stroke){ + this.strokeStyle = stroke; + dojo.forEach(this.objects, function(item){ + item.setStroke(stroke); + }); + return this; + }, + + render: function(camera, deep){ + var m = dojox.gfx3d.matrix.multiply(camera, this.matrix); + if(deep){ + this.todos = this.objects; + } + dojo.forEach(this.todos, function(item){ item.render(m, deep); }); + }, + + draw: function(lighting){ + this.objects = this.schedule(this.objects); + this._draw(this.todos, this.objects, this.renderer); + }, + + addTodo: function(newObject){ + // FIXME: use indexOf? + if(dojo.every(this.todos, function(item){ return item != newObject; })){ + this.todos.push(newObject); + this.invalidate(); + } + }, + + invalidate: function(){ + this.parent.addTodo(this); + }, + + getZOrder: function(){ + var zOrder = 0; + dojo.forEach(this.objects, function(item){ zOrder += item.getZOrder(); }); + return (this.objects.length > 1) ? zOrder / this.objects.length : 0; + } +}); + + +dojo.declare("dojox.gfx3d.Edges", dojox.gfx3d.Object, { + constructor: function(){ + // summary: a generic edge in 3D viewport + this.object = dojo.clone(dojox.gfx3d.defaultEdges); + }, + + setObject: function(newObject, /* String, optional */ style){ + // summary: setup the object + // newObject: Array of points || Object + // style: String, optional + this.object = dojox.gfx.makeParameters(this.object, (newObject instanceof Array) ? { points: newObject, style: style } : newObject); + return this; + }, + + getZOrder: function(){ + var zOrder = 0; + dojo.forEach(this.cache, function(item){ zOrder += item.z;} ); + return (this.cache.length > 1) ? zOrder / this.cache.length : 0; + }, + + render: function(camera){ + var m = dojox.gfx3d.matrix.multiply(camera, this.matrix); + this.cache = dojo.map(this.object.points, function(item){ + return dojox.gfx3d.matrix.multiplyPoint(m, item); + }); + }, + + draw: function(){ + var c = this.cache; + if(this.shape){ + this.shape.setShape("") + }else{ + this.shape = this.renderer.createPath(); + } + var p = this.shape.setAbsoluteMode("absolute"); + + if(this.object.style == "strip" || this.object.style == "loop"){ + p.moveTo(c[0].x, c[0].y); + dojo.forEach(c.slice(1), function(item){ + p.lineTo(item.x, item.y); + }); + if(this.object.style == "loop"){ + p.closePath(); + } + }else{ + for(var i = 0; i < this.cache.length; ){ + p.moveTo(c[i].x, c[i].y); + i ++; + p.lineTo(c[i].x, c[i].y); + i ++; + } + } + // FIXME: doe setFill make sense here? + p.setStroke(this.strokeStyle); + } +}); + +dojo.declare("dojox.gfx3d.Orbit", dojox.gfx3d.Object, { + constructor: function(){ + // summary: a generic edge in 3D viewport + this.object = dojo.clone(dojox.gfx3d.defaultOrbit); + }, + + render: function(camera){ + var m = dojox.gfx3d.matrix.multiply(camera, this.matrix); + var angles = [0, Math.PI/4, Math.PI/3]; + var center = dojox.gfx3d.matrix.multiplyPoint(m, this.object.center); + var marks = dojo.map(angles, function(item){ + return {x: this.center.x + this.radius * Math.cos(item), + y: this.center.y + this.radius * Math.sin(item), z: this.center.z}; + }, this.object); + + marks = dojo.map(marks, function(item){ + return dojox.gfx3d.matrix.multiplyPoint(m, item); + }); + + var normal = dojox.gfx3d.vector.normalize(marks); + + marks = dojo.map(marks, function(item){ + return dojox.gfx3d.vector.substract(item, center); + }); + + // Use the algorithm here: + // http://www.3dsoftware.com/Math/PlaneCurves/EllipseAlgebra/ + // After we normalize the marks, the equation is: + // a x^2 + 2b xy + cy^2 + f = 0: let a = 1 + // so the final equation is: + // [ xy, y^2, 1] * [2b, c, f]' = [ -x^2 ]' + + var A = { + xx: marks[0].x * marks[0].y, xy: marks[0].y * marks[0].y, xz: 1, + yx: marks[1].x * marks[1].y, yy: marks[1].y * marks[1].y, yz: 1, + zx: marks[2].x * marks[2].y, zy: marks[2].y * marks[2].y, zz: 1, + dx: 0, dy: 0, dz: 0 + }; + var b = dojo.map(marks, function(item){ + return -Math.pow(item.x, 2); + }); + + // X is 2b, c, f + var X = dojox.gfx3d.matrix.multiplyPoint(dojox.gfx3d.matrix.invert(A),b[0], b[1], b[2]); + var theta = Math.atan2(X.x, 1 - X.y) / 2; + + // rotate the marks back to the canonical form + var probes = dojo.map(marks, function(item){ + return dojox.gfx.matrix.multiplyPoint(dojox.gfx.matrix.rotate(-theta), item.x, item.y); + }); + + // we are solving the equation: Ax = b + // A = [x^2, y^2] X = [1/a^2, 1/b^2]', b = [1, 1]' + // so rx = Math.sqrt(1/ ( inv(A)[1:] * b ) ); + // so ry = Math.sqrt(1/ ( inv(A)[2:] * b ) ); + + var a = Math.pow(probes[0].x, 2); + var b = Math.pow(probes[0].y, 2); + var c = Math.pow(probes[1].x, 2); + var d = Math.pow(probes[1].y, 2); + + // the invert matrix is + // 1/(ad -bc) [ d, -b; -c, a]; + var rx = Math.sqrt( (a*d - b*c)/ (d-b) ); + var ry = Math.sqrt( (a*d - b*c)/ (a-c) ); + + this.cache = {cx: center.x, cy: center.y, rx: rx, ry: ry, theta: theta, normal: normal}; + }, + + draw: function(lighting){ + if(this.shape){ + this.shape.setShape(this.cache); + } else { + this.shape = this.renderer.createEllipse(this.cache); + } + this.shape.applyTransform(dojox.gfx.matrix.rotateAt(this.cache.theta, this.cache.cx, this.cache.cy)) + .setStroke(this.strokeStyle) + .setFill(this.toStdFill(lighting, this.cache.normal)); + } +}); + +dojo.declare("dojox.gfx3d.Path3d", dojox.gfx3d.Object, { + // This object is still very immature ! + constructor: function(){ + // summary: a generic line + // (this is a helper object, which is defined for convenience) + this.object = dojo.clone(dojox.gfx3d.defaultPath3d); + this.segments = []; + this.absolute = true; + this.last = {}; + this.path = ""; + }, + + _collectArgs: function(array, args){ + // summary: converts an array of arguments to plain numeric values + // array: Array: an output argument (array of numbers) + // args: Array: an input argument (can be values of Boolean, Number, dojox.gfx.Point, or an embedded array of them) + for(var i = 0; i < args.length; ++i){ + var t = args[i]; + if(typeof(t) == "boolean"){ + array.push(t ? 1 : 0); + }else if(typeof(t) == "number"){ + array.push(t); + }else if(t instanceof Array){ + this._collectArgs(array, t); + }else if("x" in t && "y" in t){ + array.push(t.x); + array.push(t.y); + } + } + }, + + // a dictionary, which maps segment type codes to a number of their argemnts + _validSegments: {m: 3, l: 3, z: 0}, + + _pushSegment: function(action, args){ + // summary: adds a segment + // action: String: valid SVG code for a segment's type + // args: Array: a list of parameters for this segment + var group = this._validSegments[action.toLowerCase()]; + if(typeof(group) == "number"){ + if(group){ + if(args.length >= group){ + var segment = {action: action, args: args.slice(0, args.length - args.length % group)}; + this.segments.push(segment); + } + }else{ + var segment = {action: action, args: []}; + this.segments.push(segment); + } + } + }, + + moveTo: function(){ + // summary: formes a move segment + var args = []; + this._collectArgs(args, arguments); + this._pushSegment(this.absolute ? "M" : "m", args); + return this; // self + }, + lineTo: function(){ + // summary: formes a line segment + var args = []; + this._collectArgs(args, arguments); + this._pushSegment(this.absolute ? "L" : "l", args); + return this; // self + }, + + closePath: function(){ + // summary: closes a path + this._pushSegment("Z", []); + return this; // self + }, + + render: function(camera){ + // TODO: we need to get the ancestors' matrix + var m = dojox.gfx3d.matrix.multiply(camera, this.matrix); + // iterate all the segments and convert them to 2D canvas + // TODO consider the relative mode + var path = "" + var _validSegments = this._validSegments; + dojo.forEach(this.segments, function(item){ + path += item.action; + for(var i = 0; i < item.args.length; i+= _validSegments[item.action.toLowerCase()] ){ + var pt = dojox.gfx3d.matrix.multiplyPoint(m, item.args[i], item.args[i+1], item.args[i+2]) + path += " " + pt.x + " " + pt.y; + } + }); + + this.cache = path; + }, + + _draw: function(){ + return this.parent.createPath(this.cache); + } +}); + +dojo.declare("dojox.gfx3d.Triangles", dojox.gfx3d.Object, { + constructor: function(){ + // summary: a generic triangle + // (this is a helper object, which is defined for convenience) + this.object = dojo.clone(dojox.gfx3d.defaultTriangles); + }, + + setObject: function(newObject, /* String, optional */ style){ + // summary: setup the object + // newObject: Array of points || Object + // style: String, optional + if(newObject instanceof Array){ + this.object = dojox.gfx.makeParameters(this.object, { points: newObject, style: style } ); + } else { + this.object = dojox.gfx.makeParameters(this.object, newObject); + } + return this; + }, + render: function(camera){ + var m = dojox.gfx3d.matrix.multiply(camera, this.matrix); + var c = dojo.map(this.object.points, function(item){ + return dojox.gfx3d.matrix.multiplyPoint(m, item); + }); + this.cache = []; + var pool = c.slice(0, 2); + var center = c[0]; + if(this.object.style == "strip"){ + dojo.forEach(c.slice(2), function(item){ + pool.push(item); + pool.push(pool[0]); + this.cache.push(pool); + pool = pool.slice(1, 3); + }, this); + } else if(this.object.style == "fan"){ + dojo.forEach(c.slice(2), function(item){ + pool.push(item); + pool.push(center); + this.cache.push(pool); + pool = [center, item]; + }, this); + } else { + for(var i = 0; i < c.length; ){ + this.cache.push( [ c[i], c[i+1], c[i+2], c[i] ]); + i += 3; + } + } + }, + + draw: function(lighting){ + // use the BSP to schedule + this.cache = dojox.gfx3d.scheduler.bsp(this.cache, function(it){ return it; }); + if(this.shape){ + this.shape.clear(); + } else { + this.shape = this.renderer.createGroup(); + } + dojo.forEach(this.cache, function(item){ + this.shape.createPolyline(item) + .setStroke(this.strokeStyle) + .setFill(this.toStdFill(lighting, dojox.gfx3d.vector.normalize(item))); + }, this); + }, + + getZOrder: function(){ + var zOrder = 0; + dojo.forEach(this.cache, function(item){ + zOrder += (item[0].z + item[1].z + item[2].z) / 3; }); + return (this.cache.length > 1) ? zOrder / this.cache.length : 0; + } +}); + +dojo.declare("dojox.gfx3d.Quads", dojox.gfx3d.Object, { + constructor: function(){ + // summary: a generic triangle + // (this is a helper object, which is defined for convenience) + this.object = dojo.clone(dojox.gfx3d.defaultQuads); + }, + + setObject: function(newObject, /* String, optional */ style){ + // summary: setup the object + // newObject: Array of points || Object + // style: String, optional + this.object = dojox.gfx.makeParameters(this.object, (newObject instanceof Array) ? { points: newObject, style: style } : newObject ); + return this; + }, + render: function(camera){ + var m = dojox.gfx3d.matrix.multiply(camera, this.matrix); + var c = dojo.map(this.object.points, function(item){ + return dojox.gfx3d.matrix.multiplyPoint(m, item); + }); + this.cache = []; + if(this.object.style == "strip"){ + var pool = c.slice(0, 2); + for(var i = 2; i < c.length; ){ + pool = pool.concat( [ c[i], c[i+1], pool[0] ] ); + this.cache.push(pool); + pool = pool.slice(2,4); + i += 2; + } + }else{ + for(var i = 0; i < c.length; ){ + this.cache.push( [c[i], c[i+1], c[i+2], c[i+3], c[i] ] ); + i += 4; + } + } + }, + + draw: function(lighting){ + // use the BSP to schedule + this.cache = dojox.gfx3d.scheduler.bsp(this.cache, function(it){ return it; }); + if(this.shape){ + this.shape.clear(); + }else{ + this.shape = this.renderer.createGroup(); + } + // using naive iteration to speed things up a bit by avoiding function call overhead + for(var x=0; x 1) ? zOrder / this.cache.length : 0; + } +}); + +dojo.declare("dojox.gfx3d.Polygon", dojox.gfx3d.Object, { + constructor: function(){ + // summary: a generic triangle + // (this is a helper object, which is defined for convenience) + this.object = dojo.clone(dojox.gfx3d.defaultPolygon); + }, + + setObject: function(newObject){ + // summary: setup the object + // newObject: Array of points || Object + this.object = dojox.gfx.makeParameters(this.object, (newObject instanceof Array) ? {path: newObject} : newObject) + return this; + }, + + render: function(camera){ + var m = dojox.gfx3d.matrix.multiply(camera, this.matrix); + this.cache = dojo.map(this.object.path, function(item){ + return dojox.gfx3d.matrix.multiplyPoint(m, item); + }); + // add the first point to close the polyline + this.cache.push(this.cache[0]); + }, + + draw: function(lighting){ + if(this.shape){ + this.shape.setShape({points: this.cache}); + }else{ + this.shape = this.renderer.createPolyline({points: this.cache}); + } + + this.shape.setStroke(this.strokeStyle) + .setFill(this.toStdFill(lighting, dojox.gfx3d.matrix.normalize(this.cache))); + }, + + getZOrder: function(){ + var zOrder = 0; + // using naive iteration to speed things up a bit by avoiding function call overhead + for(var x=0; x 1) ? zOrder / this.cache.length : 0; + }, + + getOutline: function(){ + return this.cache.slice(0, 3); + } +}); + +dojo.declare("dojox.gfx3d.Cube", dojox.gfx3d.Object, { + constructor: function(){ + // summary: a generic triangle + // (this is a helper object, which is defined for convenience) + this.object = dojo.clone(dojox.gfx3d.defaultCube); + this.polygons = []; + }, + + setObject: function(newObject){ + // summary: setup the object + // newObject: Array of points || Object + this.object = dojox.gfx.makeParameters(this.object, newObject); + }, + + render: function(camera){ + // parse the top, bottom to get 6 polygons: + var a = this.object.top; + var g = this.object.bottom; + var b = {x: g.x, y: a.y, z: a.z}; + var c = {x: g.x, y: g.y, z: a.z}; + var d = {x: a.x, y: g.y, z: a.z}; + var e = {x: a.x, y: a.y, z: g.z}; + var f = {x: g.x, y: a.y, z: g.z}; + var h = {x: a.x, y: g.y, z: g.z}; + var polygons = [a, b, c, d, e, f, g, h]; + var m = dojox.gfx3d.matrix.multiply(camera, this.matrix); + var p = dojo.map(polygons, function(item){ + return dojox.gfx3d.matrix.multiplyPoint(m, item); + }); + a = p[0]; b = p[1]; c = p[2]; d = p[3]; e = p[4]; f = p[5]; g = p[6]; h = p[7]; + this.cache = [[a, b, c, d, a], [e, f, g, h, e], [a, d, h, e, a], [d, c, g, h, d], [c, b, f, g, c], [b, a, e, f, b]]; + }, + + draw: function(lighting){ + // use bsp to sort. + this.cache = dojox.gfx3d.scheduler.bsp(this.cache, function(it){ return it; }); + // only the last 3 polys are visible. + var cache = this.cache.slice(3); + + if(this.shape){ + this.shape.clear(); + }else{ + this.shape = this.renderer.createGroup(); + } + for(var x=0; x 0){ + centers = [c.top, c.center]; + normal = v.substract(c.center, c.top); + } + + var color = this.renderer.lighting[this.fillStyle.type](normal, this.fillStyle.finish, this.fillStyle.color), + d = Math.sqrt( Math.pow(c.center.x - c.top.x, 2) + Math.pow(c.center.y - c.top.y, 2) ); + + if(this.shape){ + this.shape.clear(); + }else{ + this.shape = this.renderer.createGroup(); + } + + this.shape.createPath("") + .moveTo(0, -c.rx) + .lineTo(d, -c.rx) + .lineTo(d, c.rx) + .lineTo(0, c.rx) + .arcTo(c.ry, c.rx, 0, true, true, 0, -c.rx) + .setFill(c.gradient).setStroke(this.strokeStyle) + .setTransform([m.translate(centers[0]), + m.rotate(Math.atan2(centers[1].y - centers[0].y, centers[1].x - centers[0].x))]); + + if(c.rx > 0 && c.ry > 0){ + this.shape.createEllipse({cx: centers[1].x, cy: centers[1].y, rx: c.rx, ry: c.ry}) + .setFill(color).setStroke(this.strokeStyle) + .applyTransform(m.rotateAt(c.theta, centers[1])); + } + } +}); + + +// the ultimate container of 3D world +dojo.declare("dojox.gfx3d.Viewport", dojox.gfx.Group, { + constructor: function(){ + // summary: a viewport/container for 3D objects, which knows + // the camera and lightings + + // matrix: dojox.gfx3d.matrix: world transform + // dimension: Object: the dimension of the canvas + this.dimension = null; + + // objects: Array: all 3d Objects + this.objects = []; + // todos: Array: all 3d Objects that needs to redraw + this.todos = []; + + // FIXME: memory leak? + this.renderer = this; + // Using zOrder as the default scheduler + this.schedule = dojox.gfx3d.scheduler.zOrder; + this.draw = dojox.gfx3d.drawer.conservative; + // deep: boolean, true means the whole viewport needs to re-render, redraw + this.deep = false; + + // lights: Array: an array of light objects + this.lights = []; + this.lighting = null; + }, + + setCameraTransform: function(matrix){ + // summary: sets a transformation matrix + // matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object + // (see an argument of dojox.gfx.matrix.Matrix + // constructor for a list of acceptable arguments) + this.camera = dojox.gfx3d.matrix.clone(matrix ? dojox.gfx3d.matrix.normalize(matrix) : dojox.gfx3d.identity, true); + this.invalidate(); + return this; // self + }, + + applyCameraRightTransform: function(matrix){ + // summary: multiplies the existing matrix with an argument on right side + // (this.matrix * matrix) + // matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object + // (see an argument of dojox.gfx3d.matrix.Matrix + // constructor for a list of acceptable arguments) + return matrix ? this.setCameraTransform([this.camera, matrix]) : this; // self + }, + + applyCameraLeftTransform: function(matrix){ + // summary: multiplies the existing matrix with an argument on left side + // (matrix * this.matrix) + // matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object + // (see an argument of dojox.gfx3d.matrix.Matrix + // constructor for a list of acceptable arguments) + return matrix ? this.setCameraTransform([matrix, this.camera]) : this; // self + }, + + applyCameraTransform: function(matrix){ + // summary: a shortcut for dojox.gfx3d.Object.applyRightTransform + // matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object + // (see an argument of dojox.gfx3d.matrix.Matrix + // constructor for a list of acceptable arguments) + return this.applyCameraRightTransform(matrix); // self + }, + + setLights: function(/* Array || Object */lights, /* Color, optional */ ambient, + /* Color, optional */ specular){ + // summary: set the lights + // lights: Array: an array of light object + // or lights object + // ambient: Color: an ambient object + // specular: Color: an specular object + this.lights = (lights instanceof Array) ? {sources: lights, ambient: ambient, specular: specular} : lights; + var view = {x: 0, y: 0, z: 1}; + + this.lighting = new dojox.gfx3d.lighting.Model(view, this.lights.sources, + this.lights.ambient, this.lights.specular); + this.invalidate(); + return this; + }, + + addLights: function(lights){ + // summary: add new light/lights to the viewport. + // lights: Array || light object: light object(s) + return this.setLights(this.lights.sources.concat(lights)); + }, + + addTodo: function(newObject){ + // NOTE: Viewport implements almost the same addTodo, + // except calling invalidate, since invalidate is used as + // any modification needs to redraw the object itself, call invalidate. + // then call render. + if(dojo.every(this.todos, + function(item){ + return item != newObject; + } + )){ + this.todos.push(newObject); + } + }, + + invalidate: function(){ + this.deep = true; + this.todos = this.objects; + }, + + setDimensions: function(dim){ + if(dim){ + this.dimension = { + width: dojo.isString(dim.width) ? parseInt(dim.width) : dim.width, + height: dojo.isString(dim.height) ? parseInt(dim.height) : dim.height + }; + }else{ + this.dimension = null; + } + }, + + render: function(){ + // summary: iterate all children and call their render callback function. + if(!this.todos.length){ return; } + // console.debug("Viewport::render"); + var m = dojox.gfx3d.matrix; + + // Iterate the todos and call render to prepare the rendering: + for(var x=0; x 0, p is in the plus space, vice versa for minus space. + // n is the normal vector that is perpendicular the plate, defined as: + // n = ( b - a) crossProduct ( c - a ) + // + // in this implementation, n is declared as normal, ,a is declared as orient. + // + // obj: object: dojox.gfx3d.Object + this.plus = null; + this.minus = null; + this.object = obj; + + var o = outline(obj); + this.orient = o[0]; + this.normal = dojox.gfx3d.vector.normalize(o); + }, + + add: function(obj, outline){ + var epsilon = 0.5, o = outline(obj), v = dojox.gfx3d.vector, n = this.normal, a = this.orient; + + if(dojo.every(o, function(item){ return Math.floor(epsilon + v.dotProduct(n, v.substract(item, a))) <= 0; })){ + if(this.minus){ + this.minus.add(obj, outline); + } else { + this.minus = new dojox.gfx3d.scheduler.BinarySearchTree(obj, outline); + } + } else if(dojo.every(o, function(item){ return Math.floor(epsilon + v.dotProduct(n, v.substract(item, a))) >= 0; })){ + if(this.plus){ + this.plus.add(obj, outline); + } else { + this.plus = new dojox.gfx3d.scheduler.BinarySearchTree(obj, outline); + } + } else { + dojo.forEach(o, function(item){ console.debug(v.dotProduct(n, v.substract(item, a))); }); + throw "The case: polygon cross siblings' plate is not implemneted yet"; + } + }, + + iterate: function(outline){ + var epsilon = 0.5; + var v = dojox.gfx3d.vector; + var sorted = []; + var subs = null; + // FIXME: using Infinity here? + var view = {x: 0, y: 0, z: -10000}; + if(Math.floor( epsilon + v.dotProduct(this.normal, v.substract(view, this.orient))) <= 0){ + subs = [this.plus, this.minus]; + } else { + subs = [this.minus, this.plus]; + } + + if(subs[0]){ + sorted = sorted.concat(subs[0].iterate()); + } + sorted.push(this.object); + if(subs[1]){ + sorted = sorted.concat(subs[1].iterate()); + } + return sorted; + } + +}); + +dojo.mixin(dojox.gfx3d.drawer, { + conservative: function(todos, objects, viewport){ + console.debug('conservative draw'); + dojo.forEach(this.objects, function(item){ + item.destroy(); + }); + dojo.forEach(objects, function(item){ + item.draw(viewport.lighting); + }); + }, + chart: function(todos, objects, viewport){ + // NOTE: ondemand may require the todos' objects to use setShape + // to redraw themselves to maintain the z-order. + console.debug('chart draw'); + dojo.forEach(this.todos, function(item){ + item.draw(viewport.lighting); + }); + } + // More aggrasive optimization may re-order the DOM nodes using the order + // of objects, and only elements of todos call setShape. +}); + +} diff --git a/includes/js/dojox/gfx3d/tests/test_camerarotate.html b/includes/js/dojox/gfx3d/tests/test_camerarotate.html new file mode 100644 index 0000000..dcfa1a2 --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_camerarotate.html @@ -0,0 +1,93 @@ + + +Camera rotate of dojox.gfx3d. + + + + + + + + +

      Camera rotate

      +

      The cube is in the center (0, 0, 0): The color of X, Y, Z axes are red, green, blue. The view renders all the objects + in each frame, the conservative drawer is used.

      +
      + +
      + +
      + +
      +
      + +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_camerarotate_shaded.html b/includes/js/dojox/gfx3d/tests/test_camerarotate_shaded.html new file mode 100644 index 0000000..e9c0312 --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_camerarotate_shaded.html @@ -0,0 +1,97 @@ + + + Camera rotate of dojox.gfx3d. + + + + + + + + +

      Camera rotate

      +

      The cube is in the center (0, 0, 0): The color of X, Y, Z axes are red, green, blue. The view renders all the objects + in each frame, the conservative drawer is used.

      +
      + +
      + +
      + +
      +
      + +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_cube.html b/includes/js/dojox/gfx3d/tests/test_cube.html new file mode 100644 index 0000000..dcae739 --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_cube.html @@ -0,0 +1,50 @@ + + +Cube of dojox.gfx3d. + + + + + + + +

      Cube Test

      +
      + +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_cylinder.html b/includes/js/dojox/gfx3d/tests/test_cylinder.html new file mode 100644 index 0000000..cd1d5c1 --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_cylinder.html @@ -0,0 +1,66 @@ + + +Cylinder test of dojox.gfx3d. + + + + + + + + + +

      Cylinder Test

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_drawer.html b/includes/js/dojox/gfx3d/tests/test_drawer.html new file mode 100644 index 0000000..3a9af1f --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_drawer.html @@ -0,0 +1,92 @@ + + +Pilot test of dojox.gfx3d. + + + + + + +

      Pilot Test

      +

      The color of X, Y, Z axes are red, green, blue. One cube is in the center (0, 0, 0), click the button to move the other one back + and forth, using this to test dojox.gfx3d.drawer.conservative

      + + +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_edges.html b/includes/js/dojox/gfx3d/tests/test_edges.html new file mode 100644 index 0000000..07b78f0 --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_edges.html @@ -0,0 +1,73 @@ + + +Edges test of dojox.gfx3d. + + + + + + +

      Edges Test

      +

      Test of the Edges, there are three modes

      +
        +
      • none, any two vertice pair form one edge, lime
      • +
      • strip, vertices are connected by edges. red
      • +
      • loop, the same as strip, close the path, blue
      • +
      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_matrix.html b/includes/js/dojox/gfx3d/tests/test_matrix.html new file mode 100644 index 0000000..9acf399 --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_matrix.html @@ -0,0 +1,89 @@ + + +Dojo 3D Matrix + + + + + + +

      dojox.gfx3d.matrix test

      +

      Please check the debug console for test results.

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_orbit.html b/includes/js/dojox/gfx3d/tests/test_orbit.html new file mode 100644 index 0000000..cadc043 --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_orbit.html @@ -0,0 +1,50 @@ + + +Orbit test of dojox.gfx3d. + + + + + + +

      Orbit Test

      +

      Test how orbit looks like in 3D

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_overlap.html b/includes/js/dojox/gfx3d/tests/test_overlap.html new file mode 100644 index 0000000..19f63d5 --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_overlap.html @@ -0,0 +1,69 @@ + + +Test of dojox.gfx3d.scheduler + + + + + + +

      Scheduler Test

      +

      There are two schedulers available in dojox.gfx3d, zOrder and BSP. zOrder is much simpler, and it performs quite well in most cases, it may fail in some rare cases, for example: two triangles share the same two vertice, and have the same Z value of the third vertex, in this case, they have the same z-order. They are rendered in arbitary order. In this case, BSP is the rescure.

      +

      Current render: default

      +

       

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_polygon.html b/includes/js/dojox/gfx3d/tests/test_polygon.html new file mode 100644 index 0000000..ab9f174 --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_polygon.html @@ -0,0 +1,44 @@ + + +Polygon test of dojox.gfx3d. + + + + + + +

      Polygon Test

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_quads.html b/includes/js/dojox/gfx3d/tests/test_quads.html new file mode 100644 index 0000000..aff3b3b --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_quads.html @@ -0,0 +1,78 @@ + + +Quads test of dojox.gfx3d. + + + + + + +

      Quads Test

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_rotate.html b/includes/js/dojox/gfx3d/tests/test_rotate.html new file mode 100644 index 0000000..53c212f --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_rotate.html @@ -0,0 +1,123 @@ + + +Rotate test of dojox.gfx3d. + + + + + + +

      Pilot Test

      +

      There are two drawers(well, the name is quite misleading, it means draw-er) in dojox.gfx3d, conservative and chart:

      +
        +
      • conservative drawer is a pessimist, it assumes that the movement, transformation of objects would take a big fat impact to the viewport, so it not only render the modified objects, but also reorder all the underlying 2D shapes and redraw them.
      • +
      • chart drawer is an optimist, it assumes the change of the objects does not take effect on the z-order, this is most likely true in chart application. It only render and then draw the modified objects.
      • +
      +

      The cube is in the center (0, 0, 0): The color of X, Y, Z axes are red, green, blue as the reference. The cube would rotate around X, Y, Z or their combination, it is up to you.

      +

      Current Drawer: Conservative

      +
      + +
      + +
      + +
      + +
      +
      + +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_scene.html b/includes/js/dojox/gfx3d/tests/test_scene.html new file mode 100644 index 0000000..231b289 --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_scene.html @@ -0,0 +1,66 @@ + + +Scene test of dojox.gfx3d. + + + + + + +

      Scene Test

      +

      Test the setTransform of the Scene. the lime cube and yellow polygon are grouped in one Scene, and they are moved in one shot.

      +

      Test Viewport.invalidate with Scene.

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_triangles.html b/includes/js/dojox/gfx3d/tests/test_triangles.html new file mode 100644 index 0000000..cc4e65b --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_triangles.html @@ -0,0 +1,82 @@ + + +Triangles test of dojox.gfx3d. + + + + + + +

      Path3d Test

      +
      +

      That's all Folks!

      + + diff --git a/includes/js/dojox/gfx3d/tests/test_vector.html b/includes/js/dojox/gfx3d/tests/test_vector.html new file mode 100644 index 0000000..371d57e --- /dev/null +++ b/includes/js/dojox/gfx3d/tests/test_vector.html @@ -0,0 +1,59 @@ + + +Dojo 3D Vector + + + + + + +

      dojox.gfx3d.vector test

      +

      Please check the debug console for test results.

      + + diff --git a/includes/js/dojox/gfx3d/vector.js b/includes/js/dojox/gfx3d/vector.js new file mode 100644 index 0000000..7225273 --- /dev/null +++ b/includes/js/dojox/gfx3d/vector.js @@ -0,0 +1,110 @@ +if(!dojo._hasResource["dojox.gfx3d.vector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.gfx3d.vector"] = true; +dojo.provide("dojox.gfx3d.vector"); + +dojo.mixin(dojox.gfx3d.vector, { + sum: function(){ + // summary: sum of the vectors + var v = {x: 0, y: 0, z:0}; + dojo.forEach(arguments, function(item){ v.x += item.x; v.y += item.y; v.z += item.z; }); + return v; + }, + + center: function(){ + // summary: center of the vectors + var l = arguments.length; + if(l == 0){ + return {x: 0, y: 0, z: 0}; + } + var v = dojox.gfx3d.vector.sum(arguments); + return {x: v.x/l, y: v.y/l, z: v.z/l}; + }, + + substract: function(/* Pointer */a, /* Pointer */b){ + return {x: a.x - b.x, y: a.y - b.y, z: a.z - b.z}; + }, + + _crossProduct: function(x, y, z, u, v, w){ + // summary: applies a cross product of two vectorss, (x, y, z) and (u, v, w) + // x: Number: an x coordinate of a point + // y: Number: a y coordinate of a point + // z: Number: a z coordinate of a point + // u: Number: an x coordinate of a point + // v: Number: a y coordinate of a point + // w: Number: a z coordinate of a point + return {x: y * w - z * v, y: z * u - x * w, z: x * v - y * u}; // Object + }, + + crossProduct: function(/* Number||Point */ a, /* Number||Point */ b, /* Number, optional */ c, /* Number, optional */ d, /* Number, optional */ e, /* Number, optional */ f){ + // summary: applies a matrix to a point + // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied + // a: Number: an x coordinate of a point + // b: Number: a y coordinate of a point + // c: Number: a z coordinate of a point + // d: Number: an x coordinate of a point + // e: Number: a y coordinate of a point + // f: Number: a z coordinate of a point + if(arguments.length == 6 && dojo.every(arguments, function(item){ return typeof item == "number"; })){ + return dojox.gfx3d.vector._crossProduct(a, b, c, d, e, f); // Object + } + // branch + // a: Object: a point + // b: Object: a point + // c: null + // d: null + // e: null + // f: null + return dojox.gfx3d.vector._crossProduct(a.x, a.y, a.z, b.x, b.y, b.z); // Object + }, + + _dotProduct: function(x, y, z, u, v, w){ + // summary: applies a cross product of two vectorss, (x, y, z) and (u, v, w) + // x: Number: an x coordinate of a point + // y: Number: a y coordinate of a point + // z: Number: a z coordinate of a point + // u: Number: an x coordinate of a point + // v: Number: a y coordinate of a point + // w: Number: a z coordinate of a point + return x * u + y * v + z * w; // Number + }, + dotProduct: function(/* Number||Point */ a, /* Number||Point */ b, /* Number, optional */ c, /* Number, optional */ d, /* Number, optional */ e, /* Number, optional */ f){ + // summary: applies a matrix to a point + // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied + // a: Number: an x coordinate of a point + // b: Number: a y coordinate of a point + // c: Number: a z coordinate of a point + // d: Number: an x coordinate of a point + // e: Number: a y coordinate of a point + // f: Number: a z coordinate of a point + if(arguments.length == 6 && dojo.every(arguments, function(item){ return typeof item == "number"; })){ + return dojox.gfx3d.vector._dotProduct(a, b, c, d, e, f); // Object + } + // branch + // a: Object: a point + // b: Object: a point + // c: null + // d: null + // e: null + // f: null + return dojox.gfx3d.vector._dotProduct(a.x, a.y, a.z, b.x, b.y, b.z); // Object + }, + + normalize: function(/* Point||Array*/ a, /* Point */ b, /* Point */ c){ + // summary: find the normal of the implicit surface + // a: Object: a point + // b: Object: a point + // c: Object: a point + var l, m, n; + if(a instanceof Array){ + l = a[0]; m = a[1]; n = a[2]; + }else{ + l = a; m = b; n = c; + } + + var u = dojox.gfx3d.vector.substract(m, l); + var v = dojox.gfx3d.vector.substract(n, l); + return dojox.gfx3d.vector.crossProduct(u, v); + } +}); + +} diff --git a/includes/js/dojox/grid/Grid.js b/includes/js/dojox/grid/Grid.js new file mode 100644 index 0000000..309bb25 --- /dev/null +++ b/includes/js/dojox/grid/Grid.js @@ -0,0 +1,363 @@ +if(!dojo._hasResource["dojox.grid.Grid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid.Grid"] = true; +dojo.provide("dojox.grid.Grid"); +dojo.require("dojox.grid.VirtualGrid"); +dojo.require("dojox.grid._data.model"); +dojo.require("dojox.grid._data.editors"); +dojo.require("dojox.grid._data.dijitEditors"); + +// FIXME: +// we are at the wrong location! + +dojo.declare('dojox.Grid', dojox.VirtualGrid, { + // summary: + // A grid widget with virtual scrolling, cell editing, complex rows, + // sorting, fixed columns, sizeable columns, etc. + // description: + // Grid is a subclass of VirtualGrid, providing binding to a data + // store. + // example: + // define the grid structure: + // | var structure = [ // array of view objects + // | { cells: [// array of rows, a row is an array of cells + // | [ { name: "Alpha", width: 6 }, + // | { name: "Beta" }, + // | { name: "Gamma", get: formatFunction } + // | ] + // | ]} + // | ]; + // + // define a grid data model + // | var model = new dojox.grid.data.table(null, data); + // | + // |
      + // + + // model: + // string or object grid data model + model: 'dojox.grid.data.Table', + + // life cycle + postCreate: function(){ + if(this.model){ + var m = this.model; + if(dojo.isString(m)){ + m = dojo.getObject(m); + } + this.model = (dojo.isFunction(m)) ? new m() : m; + this._setModel(this.model); + } + this.inherited(arguments); + }, + + destroy: function(){ + this.setModel(null); + this.inherited(arguments); + }, + + // structure + _structureChanged: function() { + this.indexCellFields(); + this.inherited(arguments); + }, + + // model + _setModel: function(inModel){ + // if(!inModel){ return; } + this.model = inModel; + if(this.model){ + this.model.observer(this); + this.model.measure(); + this.indexCellFields(); + } + }, + + setModel: function(inModel){ + // summary: + // Set the grid's data model + // inModel: Object + // Model object, usually an instance of a dojox.grid.data.Model + // subclass + if(this.model){ + this.model.notObserver(this); + } + this._setModel(inModel); + }, + + + get: function(inRowIndex){ + // summary: data socket (called in cell's context) + return this.grid.model.getDatum(inRowIndex, this.fieldIndex); + }, + + // model modifications + modelAllChange: function(){ + this.rowCount = (this.model ? this.model.getRowCount() : 0); + this.updateRowCount(this.rowCount); + }, + + modelRowChange: function(inData, inRowIndex){ + this.updateRow(inRowIndex); + }, + + modelDatumChange: function(inDatum, inRowIndex, inFieldIndex){ + this.updateRow(inRowIndex); + }, + + modelFieldsChange: function() { + this.indexCellFields(); + this.render(); + }, + + // model insertion + modelInsertion: function(inRowIndex){ + this.updateRowCount(this.model.getRowCount()); + }, + + // model removal + modelRemoval: function(inKeys){ + this.updateRowCount(this.model.getRowCount()); + }, + + // cells + getCellName: function(inCell){ + var v = this.model.fields.values, i = inCell.fieldIndex; + return i>=0 && i 0 ? 1 : -1); + }, + + sort: function(){ + this.edit.apply(); + this.model.sort(this.getSortField()); + }, + + // row editing + addRow: function(inRowData, inIndex){ + this.edit.apply(); + var i = inIndex || -1; + if(i<0){ + i = this.selection.getFirstSelected() || 0; + } + if(i<0){ + i = 0; + } + this.model.insert(inRowData, i); + this.model.beginModifyRow(i); + // begin editing row + // FIXME: add to edit + for(var j=0, c; ((c=this.getCell(j)) && !c.editor); j++){} + if(c&&c.editor){ + this.edit.setEditCell(c, i); + this.focus.setFocusCell(c, i); + }else{ + this.focus.setFocusCell(this.getCell(0), i); + } + }, + + removeSelectedRows: function(){ + this.edit.apply(); + var s = this.selection.getSelected(); + if(s.length){ + this.model.remove(s); + this.selection.clear(); + } + }, + + //: protected + // editing + canEdit: function(inCell, inRowIndex){ + // summary: + // Determines if a given cell may be edited + // inCell: Object + // A grid cell + // inRowIndex: Integer + // Grid row index + // returns: Boolean + // True if given cell may be edited + return (this.model.canModify ? this.model.canModify(inRowIndex) : true); + }, + + doStartEdit: function(inCell, inRowIndex){ + this.model.beginModifyRow(inRowIndex); + this.onStartEdit(inCell, inRowIndex); + }, + + doApplyCellEdit: function(inValue, inRowIndex, inFieldIndex){ + this.model.setDatum(inValue, inRowIndex, inFieldIndex); + this.onApplyCellEdit(inValue, inRowIndex, inFieldIndex); + }, + + doCancelEdit: function(inRowIndex){ + this.model.cancelModifyRow(inRowIndex); + this.onCancelEdit.apply(this, arguments); + }, + + doApplyEdit: function(inRowIndex){ + this.model.endModifyRow(inRowIndex); + this.onApplyEdit(inRowIndex); + }, + + styleRowState: function(inRow){ + // summary: Perform row styling + if(this.model.getState){ + var states=this.model.getState(inRow.index), c=''; + for(var i=0, ss=["inflight", "error", "inserting"], s; s=ss[i]; i++){ + if(states[s]){ + c = ' dojoxGrid-row-' + s; + break; + } + } + inRow.customClasses += c; + } + }, + + onStyleRow: function(inRow){ + this.styleRowState(inRow); + this.inherited(arguments); + } + +}); + +dojox.Grid.markupFactory = function(props, node, ctor){ + // handle setting up a data model for a store if one + // isn't provided. There are some caveats: + // * we only really handle dojo.data sources well. They're the future + // so it's no big deal, but it's something to be aware of. + // * I'm pretty sure that colgroup introspection is missing some of + // the available settable properties. + // * No handling of cell formatting and content getting is done + var d = dojo; + var widthFromAttr = function(n){ + var w = d.attr(n, "width")||"auto"; + if((w != "auto")&&(w.substr(-2) != "em")){ + w = parseInt(w)+"px"; + } + return w; + } + if(!props.model && d.hasAttr(node, "store")){ + // if a model isn't specified and we point to a store, assume + // we're also folding the definition for a model up into the + // inline ctor for the Grid. This will then take properties + // like "query", "rowsPerPage", and "clientSort" from the grid + // definition. + var mNode = node.cloneNode(false); + d.attr(mNode, { + "jsId": null, + "dojoType": d.attr(node, "dataModelClass") || "dojox.grid.data.DojoData" + }); + props.model = d.parser.instantiate([mNode])[0]; + } + // if(!props.model){ console.debug("no model!"); } + // if a structure isn't referenced, do we have enough + // data to try to build one automatically? + if( !props.structure && + node.nodeName.toLowerCase() == "table"){ + + // try to discover a structure + props.structure = d.query("> colgroup", node).map(function(cg){ + var sv = d.attr(cg, "span"); + var v = { + noscroll: (d.attr(cg, "noscroll") == "true") ? true : false, + __span: (!!sv ? parseInt(sv) : 1), + cells: [] + }; + if(d.hasAttr(cg, "width")){ + v.width = widthFromAttr(cg); + } + return v; // for vendetta + }); + if(!props.structure.length){ + props.structure.push({ + __span: Infinity, + cells: [] // catch-all view + }); + } + // check to see if we're gonna have more than one view + + // for each tr in our th, create a row of cells + d.query("thead > tr", node).forEach(function(tr, tr_idx){ + var cellCount = 0; + var viewIdx = 0; + var lastViewIdx; + var cView = null; + d.query("> th", tr).map(function(th){ + // what view will this cell go into? + + // NOTE: + // to prevent extraneous iteration, we start counters over + // for each row, incrementing over the surface area of the + // structure that colgroup processing generates and + // creating cell objects for each to place into those + // cell groups. There's a lot of state-keepking logic + // here, but it is what it has to be. + if(!cView){ // current view book keeping + lastViewIdx = 0; + cView = props.structure[0]; + }else if(cellCount >= (lastViewIdx+cView.__span)){ + viewIdx++; + // move to allocating things into the next view + lastViewIdx += cView.__span; + lastView = cView; + cView = props.structure[viewIdx]; + } + + // actually define the cell from what markup hands us + var cell = { + name: d.trim(d.attr(th, "name")||th.innerHTML), + field: d.trim(d.attr(th, "field")||""), + colSpan: parseInt(d.attr(th, "colspan")||1) + }; + cellCount += cell.colSpan; + cell.field = cell.field||cell.name; + cell.width = widthFromAttr(th); + if(!cView.cells[tr_idx]){ + cView.cells[tr_idx] = []; + } + cView.cells[tr_idx].push(cell); + }); + }); + // console.debug(dojo.toJson(props.structure, true)); + } + return new dojox.Grid(props, node); +} + + +// alias us to the right location +dojox.grid.Grid = dojox.Grid; + +} diff --git a/includes/js/dojox/grid/README b/includes/js/dojox/grid/README new file mode 100644 index 0000000..f9dade3 --- /dev/null +++ b/includes/js/dojox/grid/README @@ -0,0 +1,39 @@ +------------------------------------------------------------------------------- +dojox.grid +------------------------------------------------------------------------------- +Version 1.00 +Release date: 10/04/2007 +------------------------------------------------------------------------------- +Project state: +beta +------------------------------------------------------------------------------- +Credits + Scott J. Miles (sjmiles@activegrid.com) + Steve Orvell (sorvell@activegrid.com) +------------------------------------------------------------------------------- +Project description + +TurboGrid has been made available in Dojo and is now the dojox.grid! + +------------------------------------------------------------------------------- +Dependencies: + +Dojo Core +Dijit Templated Widget +------------------------------------------------------------------------------- +Documentation + +None available for this version yet. + +See http://www.turboajax.com/products/turbogrid/ for legacy documentation. +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/grid/* + +Install into the following directory structure: +/dojox/grid/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- diff --git a/includes/js/dojox/grid/VirtualGrid.js b/includes/js/dojox/grid/VirtualGrid.js new file mode 100644 index 0000000..104054c --- /dev/null +++ b/includes/js/dojox/grid/VirtualGrid.js @@ -0,0 +1,779 @@ +if(!dojo._hasResource["dojox.grid.VirtualGrid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid.VirtualGrid"] = true; +dojo.provide("dojox.grid.VirtualGrid"); + +dojo.require("dojox.grid._grid.lib"); +dojo.require("dojox.grid._grid.scroller"); +dojo.require("dojox.grid._grid.view"); +dojo.require("dojox.grid._grid.views"); +dojo.require("dojox.grid._grid.layout"); +dojo.require("dojox.grid._grid.rows"); +dojo.require("dojox.grid._grid.focus"); +dojo.require("dojox.grid._grid.selection"); +dojo.require("dojox.grid._grid.edit"); +dojo.require("dojox.grid._grid.rowbar"); +dojo.require("dojox.grid._grid.publicEvents"); + +dojo.declare('dojox.VirtualGrid', + [ dijit._Widget, dijit._Templated ], + { + // summary: + // A grid widget with virtual scrolling, cell editing, complex rows, + // sorting, fixed columns, sizeable columns, etc. + // + // description: + // VirtualGrid provides the full set of grid features without any + // direct connection to a data store. + // + // The grid exposes a get function for the grid, or optionally + // individual columns, to populate cell contents. + // + // The grid is rendered based on its structure, an object describing + // column and cell layout. + // + // example: + // A quick sample: + // + // define a get function + // | function get(inRowIndex){ // called in cell context + // | return [this.index, inRowIndex].join(', '); + // | } + // + // define the grid structure: + // | var structure = [ // array of view objects + // | { cells: [// array of rows, a row is an array of cells + // | [ + // | { name: "Alpha", width: 6 }, + // | { name: "Beta" }, + // | { name: "Gamma", get: get }] + // | ]} + // | ]; + // + // |
      + + templateString:"
      \n\t
      \n\t
      \n\t\n
      \n", + + // classTag: String + // CSS class applied to the grid's domNode + classTag: 'dojoxGrid', + + get: function(inRowIndex){ + // summary: Default data getter. + // description: + // Provides data to display in a grid cell. Called in grid cell context. + // So this.cell.index is the column index. + // inRowIndex: Integer + // Row for which to provide data + // returns: + // Data to display for a given grid cell. + }, + + // settings + // rowCount: Integer + // Number of rows to display. + rowCount: 5, + + // keepRows: Integer + // Number of rows to keep in the rendering cache. + keepRows: 75, + + // rowsPerPage: Integer + // Number of rows to render at a time. + rowsPerPage: 25, + + // autoWidth: Boolean + // If autoWidth is true, grid width is automatically set to fit the data. + autoWidth: false, + + // autoHeight: Boolean + // If autoHeight is true, grid height is automatically set to fit the data. + autoHeight: false, + + // autoRender: Boolean + // If autoRender is true, grid will render itself after initialization. + autoRender: true, + + // defaultHeight: String + // default height of the grid, measured in any valid css unit. + defaultHeight: '15em', + + // structure: Object|String + // View layout defintion. Can be set to a layout object, or to the (string) name of a layout object. + structure: '', + + // elasticView: Integer + // Override defaults and make the indexed grid view elastic, thus filling available horizontal space. + elasticView: -1, + + // singleClickEdit: boolean + // Single-click starts editing. Default is double-click + singleClickEdit: false, + + // Used to store the last two clicks, to ensure double-clicking occurs based on the intended row + _click: null, + + // private + sortInfo: 0, + themeable: true, + + // initialization + buildRendering: function(){ + this.inherited(arguments); + // reset get from blank function (needed for markup parsing) to null, if not changed + if(this.get == dojox.VirtualGrid.prototype.get){ + this.get = null; + } + if(!this.domNode.getAttribute('tabIndex')){ + this.domNode.tabIndex = "0"; + } + this.createScroller(); + this.createLayout(); + this.createViews(); + this.createManagers(); + dojox.grid.initTextSizePoll(); + this.connect(dojox.grid, "textSizeChanged", "textSizeChanged"); + dojox.grid.funnelEvents(this.domNode, this, 'doKeyEvent', dojox.grid.keyEvents); + this.connect(this, "onShow", "renderOnIdle"); + }, + postCreate: function(){ + // replace stock styleChanged with one that triggers an update + this.styleChanged = this._styleChanged; + this.setStructure(this.structure); + this._click = []; + }, + + destroy: function(){ + this.domNode.onReveal = null; + this.domNode.onSizeChange = null; + this.edit.destroy(); + this.views.destroyViews(); + this.inherited(arguments); + }, + + styleChanged: function(){ + this.setStyledClass(this.domNode, ''); + }, + + _styleChanged: function(){ + this.styleChanged(); + this.update(); + }, + + textSizeChanged: function(){ + setTimeout(dojo.hitch(this, "_textSizeChanged"), 1); + }, + + _textSizeChanged: function(){ + if(this.domNode){ + this.views.forEach(function(v){ + v.content.update(); + }); + this.render(); + } + }, + + sizeChange: function(){ + dojox.grid.jobs.job(this.id + 'SizeChange', 50, dojo.hitch(this, "update")); + }, + + renderOnIdle: function() { + setTimeout(dojo.hitch(this, "render"), 1); + }, + + createManagers: function(){ + // summary: + // create grid managers for various tasks including rows, focus, selection, editing + + // row manager + this.rows = new dojox.grid.rows(this); + // focus manager + this.focus = new dojox.grid.focus(this); + // selection manager + this.selection = new dojox.grid.selection(this); + // edit manager + this.edit = new dojox.grid.edit(this); + }, + + createScroller: function(){ + // summary: Creates a new virtual scroller + this.scroller = new dojox.grid.scroller.columns(); + this.scroller._pageIdPrefix = this.id + '-'; + this.scroller.renderRow = dojo.hitch(this, "renderRow"); + this.scroller.removeRow = dojo.hitch(this, "rowRemoved"); + }, + + createLayout: function(){ + // summary: Creates a new Grid layout + this.layout = new dojox.grid.layout(this); + }, + + // views + createViews: function(){ + this.views = new dojox.grid.views(this); + this.views.createView = dojo.hitch(this, "createView"); + }, + + createView: function(inClass){ + if(dojo.isAIR){ + var obj = window; + var names = inClass.split('.'); + for(var i=0;i 0){ + }else if(this.domNode.clientHeight <= padBorder.h){ + if(this.domNode.parentNode == document.body){ + this.domNode.style.height = this.defaultHeight; + }else{ + this.fitTo = "parent"; + } + } + // if we are given dimensions, size the grid's domNode to those dimensions + if(this._sizeBox){ + dojo.contentBox(this.domNode, this._sizeBox); + }else if(this.fitTo == "parent"){ + var h = dojo._getContentBox(this.domNode.parentNode).h; + dojo.marginBox(this.domNode, { h: Math.max(0, h) }); + } + + var h = dojo._getContentBox(this.domNode).h; + if(h == 0 && !this.autoHeight){ + // We need to hide the header, since the Grid is essentially hidden. + this.viewsHeaderNode.style.display = "none"; + }else{ + // Otherwise, show the header and give it an appropriate height. + this.viewsHeaderNode.style.display = "block"; + } + + // NOTE: it is essential that width be applied before height + // Header height can only be calculated properly after view widths have been set. + // This is because flex column width is naturally 0 in Firefox. + // Therefore prior to width sizing flex columns with spaces are maximally wrapped + // and calculated to be too tall. + this.adaptWidth(); + this.adaptHeight(); + + // default row height (FIXME: use running average(?), remove magic #) + this.scroller.defaultRowHeight = this.rows.getDefaultHeightPx() + 1; + this.postresize(); + }, + + adaptWidth: function() { + // private: sets width and position for views and update grid width if necessary + var + w = this.autoWidth ? 0 : this.domNode.clientWidth || (this.domNode.offsetWidth - this._getPadBorder().w); + vw = this.views.arrange(1, w); + this.views.onEach("adaptWidth"); + if (this.autoWidth) + this.domNode.style.width = vw + "px"; + }, + + adaptHeight: function(){ + // private: measures and normalizes header height, then sets view heights, and then updates scroller + var vns = this.viewsHeaderNode.style, t = vns.display == "none" ? 0 : this.views.measureHeader(); + vns.height = t + 'px'; + // header heights are reset during measuring so must be normalized after measuring. + this.views.normalizeHeaderNodeHeight(); + // content extent + var h = (this.autoHeight ? -1 : Math.max(this.domNode.clientHeight - t, 0) || 0); + this.views.onEach('setSize', [0, h]); + this.views.onEach('adaptHeight'); + this.scroller.windowHeight = h; + }, + + // render + render: function(){ + // summary: + // Render the grid, headers, and views. Edit and scrolling states are reset. To retain edit and + // scrolling states, see Update. + + if(!this.domNode){return;} + + if(!this.hasLayout()) { + this.scroller.init(0, this.keepRows, this.rowsPerPage); + return; + } + // + this.update = this.defaultUpdate; + this.scroller.init(this.rowCount, this.keepRows, this.rowsPerPage); + this.prerender(); + this.setScrollTop(0); + this.postrender(); + }, + + prerender: function(){ + // if autoHeight, make sure scroller knows not to virtualize; everything must be rendered. + this.keepRows = this.autoHeight ? 0 : this.constructor.prototype.keepRows; + this.scroller.setKeepInfo(this.keepRows); + this.views.render(); + this._resize(); + }, + + postrender: function(){ + this.postresize(); + this.focus.initFocusView(); + // make rows unselectable + dojo.setSelectable(this.domNode, false); + }, + + postresize: function(){ + // views are position absolute, so they do not inflate the parent + if(this.autoHeight){ + this.viewsNode.style.height = this.views.measureContent() + 'px'; + } + }, + + renderRow: function(inRowIndex, inNodes){ + // summary: private, used internally to render rows + this.views.renderRow(inRowIndex, inNodes); + }, + + rowRemoved: function(inRowIndex){ + // summary: private, used internally to remove rows + this.views.rowRemoved(inRowIndex); + }, + + invalidated: null, + + updating: false, + + beginUpdate: function(){ + // summary: + // Use to make multiple changes to rows while queueing row updating. + // NOTE: not currently supporting nested begin/endUpdate calls + this.invalidated = []; + this.updating = true; + }, + + endUpdate: function(){ + // summary: + // Use after calling beginUpdate to render any changes made to rows. + this.updating = false; + var i = this.invalidated; + if(i.all){ + this.update(); + }else if(i.rowCount != undefined){ + this.updateRowCount(i.rowCount); + }else{ + for(r in i){ + this.updateRow(Number(r)); + } + } + this.invalidated = null; + }, + + // update + defaultUpdate: function(){ + // note: initial update calls render and subsequently this function. + if(!this.domNode){return;} + if(this.updating){ + this.invalidated.all = true; + return; + } + //this.edit.saveState(inRowIndex); + this.prerender(); + this.scroller.invalidateNodes(); + this.setScrollTop(this.scrollTop); + this.postrender(); + //this.edit.restoreState(inRowIndex); + }, + + update: function(){ + // summary: + // Update the grid, retaining edit and scrolling states. + this.render(); + }, + + updateRow: function(inRowIndex){ + // summary: + // Render a single row. + // inRowIndex: Integer + // Index of the row to render + inRowIndex = Number(inRowIndex); + if(this.updating){ + this.invalidated[inRowIndex]=true; + }else{ + this.views.updateRow(inRowIndex, this.rows.getHeight(inRowIndex)); + this.scroller.rowHeightChanged(inRowIndex); + } + }, + + updateRowCount: function(inRowCount){ + //summary: + // Change the number of rows. + // inRowCount: int + // Number of rows in the grid. + if(this.updating){ + this.invalidated.rowCount = inRowCount; + }else{ + this.rowCount = inRowCount; + if(this.layout.cells.length){ + this.scroller.updateRowCount(inRowCount); + this.setScrollTop(this.scrollTop); + } + this._resize(); + } + }, + + updateRowStyles: function(inRowIndex){ + // summary: + // Update the styles for a row after it's state has changed. + this.views.updateRowStyles(inRowIndex); + }, + + rowHeightChanged: function(inRowIndex){ + // summary: + // Update grid when the height of a row has changed. Row height is handled automatically as rows + // are rendered. Use this function only to update a row's height outside the normal rendering process. + // inRowIndex: Integer + // index of the row that has changed height + + this.views.renormalizeRow(inRowIndex); + this.scroller.rowHeightChanged(inRowIndex); + }, + + // fastScroll: Boolean + // flag modifies vertical scrolling behavior. Defaults to true but set to false for slower + // scroll performance but more immediate scrolling feedback + fastScroll: true, + + delayScroll: false, + + // scrollRedrawThreshold: int + // pixel distance a user must scroll vertically to trigger grid scrolling. + scrollRedrawThreshold: (dojo.isIE ? 100 : 50), + + // scroll methods + scrollTo: function(inTop){ + // summary: + // Vertically scroll the grid to a given pixel position + // inTop: Integer + // vertical position of the grid in pixels + if(!this.fastScroll){ + this.setScrollTop(inTop); + return; + } + var delta = Math.abs(this.lastScrollTop - inTop); + this.lastScrollTop = inTop; + if(delta > this.scrollRedrawThreshold || this.delayScroll){ + this.delayScroll = true; + this.scrollTop = inTop; + this.views.setScrollTop(inTop); + dojox.grid.jobs.job('dojoxGrid-scroll', 200, dojo.hitch(this, "finishScrollJob")); + }else{ + this.setScrollTop(inTop); + } + }, + + finishScrollJob: function(){ + this.delayScroll = false; + this.setScrollTop(this.scrollTop); + }, + + setScrollTop: function(inTop){ + this.scrollTop = this.views.setScrollTop(inTop); + this.scroller.scroll(this.scrollTop); + }, + + scrollToRow: function(inRowIndex){ + // summary: + // Scroll the grid to a specific row. + // inRowIndex: Integer + // grid row index + this.setScrollTop(this.scroller.findScrollTop(inRowIndex) + 1); + }, + + // styling (private, used internally to style individual parts of a row) + styleRowNode: function(inRowIndex, inRowNode){ + if(inRowNode){ + this.rows.styleRowNode(inRowIndex, inRowNode); + } + }, + + // cells + getCell: function(inIndex){ + // summary: + // Retrieves the cell object for a given grid column. + // inIndex: Integer + // Grid column index of cell to retrieve + // returns: + // a grid cell + return this.layout.cells[inIndex]; + }, + + setCellWidth: function(inIndex, inUnitWidth) { + this.getCell(inIndex).unitWidth = inUnitWidth; + }, + + getCellName: function(inCell){ + // summary: Returns the cell name of a passed cell + return "Cell " + inCell.index; // String + }, + + // sorting + canSort: function(inSortInfo){ + // summary: + // Determines if the grid can be sorted + // inSortInfo: Integer + // Sort information, 1-based index of column on which to sort, positive for an ascending sort + // and negative for a descending sort + // returns: Boolean + // True if grid can be sorted on the given column in the given direction + }, + + sort: function(){ + }, + + getSortAsc: function(inSortInfo){ + // summary: + // Returns true if grid is sorted in an ascending direction. + inSortInfo = inSortInfo == undefined ? this.sortInfo : inSortInfo; + return Boolean(inSortInfo > 0); // Boolean + }, + + getSortIndex: function(inSortInfo){ + // summary: + // Returns the index of the column on which the grid is sorted + inSortInfo = inSortInfo == undefined ? this.sortInfo : inSortInfo; + return Math.abs(inSortInfo) - 1; // Integer + }, + + setSortIndex: function(inIndex, inAsc){ + // summary: + // Sort the grid on a column in a specified direction + // inIndex: Integer + // Column index on which to sort. + // inAsc: Boolean + // If true, sort the grid in ascending order, otherwise in descending order + var si = inIndex +1; + if(inAsc != undefined){ + si *= (inAsc ? 1 : -1); + } else if(this.getSortIndex() == inIndex){ + si = -this.sortInfo; + } + this.setSortInfo(si); + }, + + setSortInfo: function(inSortInfo){ + if(this.canSort(inSortInfo)){ + this.sortInfo = inSortInfo; + this.sort(); + this.update(); + } + }, + + // DOM event handler + doKeyEvent: function(e){ + e.dispatch = 'do' + e.type; + this.onKeyEvent(e); + }, + + // event dispatch + //: protected + _dispatch: function(m, e){ + if(m in this){ + return this[m](e); + } + }, + + dispatchKeyEvent: function(e){ + this._dispatch(e.dispatch, e); + }, + + dispatchContentEvent: function(e){ + this.edit.dispatchEvent(e) || e.sourceView.dispatchContentEvent(e) || this._dispatch(e.dispatch, e); + }, + + dispatchHeaderEvent: function(e){ + e.sourceView.dispatchHeaderEvent(e) || this._dispatch('doheader' + e.type, e); + }, + + dokeydown: function(e){ + this.onKeyDown(e); + }, + + doclick: function(e){ + if(e.cellNode){ + this.onCellClick(e); + }else{ + this.onRowClick(e); + } + }, + + dodblclick: function(e){ + if(e.cellNode){ + this.onCellDblClick(e); + }else{ + this.onRowDblClick(e); + } + }, + + docontextmenu: function(e){ + if(e.cellNode){ + this.onCellContextMenu(e); + }else{ + this.onRowContextMenu(e); + } + }, + + doheaderclick: function(e){ + if(e.cellNode){ + this.onHeaderCellClick(e); + }else{ + this.onHeaderClick(e); + } + }, + + doheaderdblclick: function(e){ + if(e.cellNode){ + this.onHeaderCellDblClick(e); + }else{ + this.onHeaderDblClick(e); + } + }, + + doheadercontextmenu: function(e){ + if(e.cellNode){ + this.onHeaderCellContextMenu(e); + }else{ + this.onHeaderContextMenu(e); + } + }, + + // override to modify editing process + doStartEdit: function(inCell, inRowIndex){ + this.onStartEdit(inCell, inRowIndex); + }, + + doApplyCellEdit: function(inValue, inRowIndex, inFieldIndex){ + this.onApplyCellEdit(inValue, inRowIndex, inFieldIndex); + }, + + doCancelEdit: function(inRowIndex){ + this.onCancelEdit(inRowIndex); + }, + + doApplyEdit: function(inRowIndex){ + this.onApplyEdit(inRowIndex); + }, + + // row editing + addRow: function(){ + // summary: + // Add a row to the grid. + this.updateRowCount(this.rowCount+1); + }, + + removeSelectedRows: function(){ + // summary: + // Remove the selected rows from the grid. + this.updateRowCount(Math.max(0, this.rowCount - this.selection.getSelected().length)); + this.selection.clear(); + } + +}); + +dojo.mixin(dojox.VirtualGrid.prototype, dojox.grid.publicEvents); + +} diff --git a/includes/js/dojox/grid/_data/dijitEditors.js b/includes/js/dojox/grid/_data/dijitEditors.js new file mode 100644 index 0000000..695de44 --- /dev/null +++ b/includes/js/dojox/grid/_data/dijitEditors.js @@ -0,0 +1,170 @@ +if(!dojo._hasResource["dojox.grid._data.dijitEditors"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid._data.dijitEditors"] = true; +dojo.provide("dojox.grid._data.dijitEditors"); +dojo.require("dojox.grid._data.editors"); +dojo.require("dijit.form.DateTextBox"); +dojo.require("dijit.form.TimeTextBox"); +dojo.require("dijit.form.ComboBox"); +dojo.require("dojo.data.ItemFileReadStore"); +dojo.require("dijit.form.CheckBox"); +dojo.require("dijit.form.TextBox"); +dojo.require("dijit.form.NumberSpinner"); +dojo.require("dijit.form.NumberTextBox"); +dojo.require("dijit.form.CurrencyTextBox"); +dojo.require("dijit.form.Slider"); +dojo.require("dijit.Editor"); + +dojo.declare("dojox.grid.editors.Dijit", dojox.grid.editors.base, { + editorClass: "dijit.form.TextBox", + constructor: function(inCell){ + this.editor = null; + this.editorClass = dojo.getObject(this.cell.editorClass || this.editorClass); + }, + format: function(inDatum, inRowIndex){ + this.needFormatNode(inDatum, inRowIndex); + return "
      "; + }, + getValue: function(inRowIndex){ + return this.editor.getValue(); + }, + setValue: function(inRowIndex, inValue){ + if(this.editor&&this.editor.setValue){ + this.editor.setValue(inValue); + }else{ + this.inherited(arguments); + } + }, + getEditorProps: function(inDatum){ + return dojo.mixin({}, this.cell.editorProps||{}, { + constraints: dojo.mixin({}, this.cell.constraint) || {}, //TODO: really just for ValidationTextBoxes + value: inDatum + }); + }, + createEditor: function(inNode, inDatum, inRowIndex){ + return new this.editorClass(this.getEditorProps(inDatum), inNode); + + }, + attachEditor: function(inNode, inDatum, inRowIndex){ + inNode.appendChild(this.editor.domNode); + this.setValue(inRowIndex, inDatum); + }, + formatNode: function(inNode, inDatum, inRowIndex){ + if(!this.editorClass){ + return inDatum; + } + if(!this.editor){ + this.editor = this.createEditor.apply(this, arguments); + }else{ + this.attachEditor.apply(this, arguments); + } + this.sizeEditor.apply(this, arguments); + this.cell.grid.rowHeightChanged(inRowIndex); + this.focus(); + }, + sizeEditor: function(inNode, inDatum, inRowIndex){ + var + p = this.cell.getNode(inRowIndex), + box = dojo.contentBox(p); + dojo.marginBox(this.editor.domNode, {w: box.w}); + }, + focus: function(inRowIndex, inNode){ + if(this.editor){ + setTimeout(dojo.hitch(this.editor, function(){ + dojox.grid.fire(this, "focus"); + }), 0); + } + }, + _finish: function(inRowIndex){ + this.inherited(arguments); + dojox.grid.removeNode(this.editor.domNode); + } +}); + +dojo.declare("dojox.grid.editors.ComboBox", dojox.grid.editors.Dijit, { + editorClass: "dijit.form.ComboBox", + getEditorProps: function(inDatum){ + var items=[]; + dojo.forEach(this.cell.options, function(o){ + items.push({name: o, value: o}); + }); + var store = new dojo.data.ItemFileReadStore({data: {identifier:"name", items: items}}); + return dojo.mixin({}, this.cell.editorProps||{}, { + value: inDatum, + store: store + }); + }, + getValue: function(){ + var e = this.editor; + // make sure to apply the displayed value + e.setDisplayedValue(e.getDisplayedValue()); + return e.getValue(); + } +}); + +dojo.declare("dojox.grid.editors.DateTextBox", dojox.grid.editors.Dijit, { + editorClass: "dijit.form.DateTextBox", + setValue: function(inRowIndex, inValue){ + if(this.editor){ + this.editor.setValue(new Date(inValue)); + }else{ + this.inherited(arguments); + } + }, + getEditorProps: function(inDatum){ + return dojo.mixin(this.inherited(arguments), { + value: new Date(inDatum) + }); + } +}); + + +dojo.declare("dojox.grid.editors.CheckBox", dojox.grid.editors.Dijit, { + editorClass: "dijit.form.CheckBox", + getValue: function(){ + return this.editor.checked; + }, + setValue: function(inRowIndex, inValue){ + if(this.editor&&this.editor.setAttribute){ + this.editor.setAttribute("checked", inValue); + }else{ + this.inherited(arguments); + } + }, + sizeEditor: function(inNode, inDatum, inRowIndex){ + return; + } +}); + + +dojo.declare("dojox.grid.editors.Editor", dojox.grid.editors.Dijit, { + editorClass: "dijit.Editor", + getEditorProps: function(inDatum){ + return dojo.mixin({}, this.cell.editorProps||{}, { + height: this.cell.editorHeight || "100px" + }); + }, + createEditor: function(inNode, inDatum, inRowIndex){ + // editor needs its value set after creation + var editor = new this.editorClass(this.getEditorProps(inDatum), inNode); + dojo.connect(editor, 'onLoad', dojo.hitch(this, 'populateEditor')); + return editor; + }, + formatNode: function(inNode, inDatum, inRowIndex){ + this.content = inDatum; + this.inherited(arguments); + if(dojo.isMoz){ + // FIXME: seem to need to reopen the editor and display the toolbar + var e = this.editor; + e.open(); + if(this.cell.editorToolbar){ + dojo.place(e.toolbar.domNode, e.editingArea, "before"); + } + } + }, + populateEditor: function(){ + this.editor.setValue(this.content); + this.editor.placeCursorAtEnd(); + } +}); + +} diff --git a/includes/js/dojox/grid/_data/editors.js b/includes/js/dojox/grid/_data/editors.js new file mode 100644 index 0000000..48f76cc --- /dev/null +++ b/includes/js/dojox/grid/_data/editors.js @@ -0,0 +1,239 @@ +if(!dojo._hasResource["dojox.grid._data.editors"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid._data.editors"] = true; +dojo.provide("dojox.grid._data.editors"); +dojo.provide("dojox.grid.editors"); + +dojo.declare("dojox.grid.editors.Base", null, { + // summary: + // base grid editor class. Other grid editors should inherited from this class. + constructor: function(inCell){ + this.cell = inCell; + }, + //private + _valueProp: "value", + _formatPending: false, + format: function(inDatum, inRowIndex){ + // summary: + // formats the cell for editing + // inDatum: anything + // cell data to edit + // inRowIndex: int + // grid row index + // returns: string of html to place in grid cell + }, + //protected + needFormatNode: function(inDatum, inRowIndex){ + this._formatPending = true; + dojox.grid.whenIdle(this, "_formatNode", inDatum, inRowIndex); + }, + cancelFormatNode: function(){ + this._formatPending = false; + }, + //private + _formatNode: function(inDatum, inRowIndex){ + if(this._formatPending){ + this._formatPending = false; + // make cell selectable + dojo.setSelectable(this.cell.grid.domNode, true); + this.formatNode(this.getNode(inRowIndex), inDatum, inRowIndex); + } + }, + //protected + getNode: function(inRowIndex){ + return (this.cell.getNode(inRowIndex) || 0).firstChild || 0; + }, + formatNode: function(inNode, inDatum, inRowIndex){ + // summary: + // format the editing dom node. Use when editor is a widget. + // inNode: dom node + // dom node for the editor + // inDatum: anything + // cell data to edit + // inRowIndex: int + // grid row index + if(dojo.isIE){ + // IE sux bad + dojox.grid.whenIdle(this, "focus", inRowIndex, inNode); + }else{ + this.focus(inRowIndex, inNode); + } + }, + dispatchEvent: function(m, e){ + if(m in this){ + return this[m](e); + } + }, + //public + getValue: function(inRowIndex){ + // summary: + // returns value entered into editor + // inRowIndex: int + // grid row index + // returns: + // value of editor + return this.getNode(inRowIndex)[this._valueProp]; + }, + setValue: function(inRowIndex, inValue){ + // summary: + // set the value of the grid editor + // inRowIndex: int + // grid row index + // inValue: anything + // value of editor + var n = this.getNode(inRowIndex); + if(n){ + n[this._valueProp] = inValue + }; + }, + focus: function(inRowIndex, inNode){ + // summary: + // focus the grid editor + // inRowIndex: int + // grid row index + // inNode: dom node + // editor node + dojox.grid.focusSelectNode(inNode || this.getNode(inRowIndex)); + }, + save: function(inRowIndex){ + // summary: + // save editor state + // inRowIndex: int + // grid row index + this.value = this.value || this.getValue(inRowIndex); + //console.log("save", this.value, inCell.index, inRowIndex); + }, + restore: function(inRowIndex){ + // summary: + // restore editor state + // inRowIndex: int + // grid row index + this.setValue(inRowIndex, this.value); + //console.log("restore", this.value, inCell.index, inRowIndex); + }, + //protected + _finish: function(inRowIndex){ + // summary: + // called when editing is completed to clean up editor + // inRowIndex: int + // grid row index + dojo.setSelectable(this.cell.grid.domNode, false); + this.cancelFormatNode(this.cell); + }, + //public + apply: function(inRowIndex){ + // summary: + // apply edit from cell editor + // inRowIndex: int + // grid row index + this.cell.applyEdit(this.getValue(inRowIndex), inRowIndex); + this._finish(inRowIndex); + }, + cancel: function(inRowIndex){ + // summary: + // cancel cell edit + // inRowIndex: int + // grid row index + this.cell.cancelEdit(inRowIndex); + this._finish(inRowIndex); + } +}); +dojox.grid.editors.base = dojox.grid.editors.Base; // back-compat + +dojo.declare("dojox.grid.editors.Input", dojox.grid.editors.Base, { + // summary + // grid cell editor that provides a standard text input box + constructor: function(inCell){ + this.keyFilter = this.keyFilter || this.cell.keyFilter; + }, + // keyFilter: object + // optional regex for disallowing keypresses + keyFilter: null, + format: function(inDatum, inRowIndex){ + this.needFormatNode(inDatum, inRowIndex); + return ''; + }, + formatNode: function(inNode, inDatum, inRowIndex){ + this.inherited(arguments); + // FIXME: feels too specific for this interface + this.cell.registerOnBlur(inNode, inRowIndex); + }, + doKey: function(e){ + if(this.keyFilter){ + var key = String.fromCharCode(e.charCode); + if(key.search(this.keyFilter) == -1){ + dojo.stopEvent(e); + } + } + }, + _finish: function(inRowIndex){ + this.inherited(arguments); + var n = this.getNode(inRowIndex); + try{ + dojox.grid.fire(n, "blur"); + }catch(e){} + } +}); +dojox.grid.editors.input = dojox.grid.editors.Input; // back compat + +dojo.declare("dojox.grid.editors.Select", dojox.grid.editors.Input, { + // summary: + // grid cell editor that provides a standard select + // options: text of each item + // values: value for each item + // returnIndex: editor returns only the index of the selected option and not the value + constructor: function(inCell){ + this.options = this.options || this.cell.options; + this.values = this.values || this.cell.values || this.options; + }, + format: function(inDatum, inRowIndex){ + this.needFormatNode(inDatum, inRowIndex); + var h = [ ''); + return h.join(''); + }, + getValue: function(inRowIndex){ + var n = this.getNode(inRowIndex); + if(n){ + var i = n.selectedIndex, o = n.options[i]; + return this.cell.returnIndex ? i : o.value || o.innerHTML; + } + } +}); +dojox.grid.editors.select = dojox.grid.editors.Select; // back compat + +dojo.declare("dojox.grid.editors.AlwaysOn", dojox.grid.editors.Input, { + // summary: + // grid cell editor that is always on, regardless of grid editing state + // alwaysOn: boolean + // flag to use editor to format grid cell regardless of editing state. + alwaysOn: true, + _formatNode: function(inDatum, inRowIndex){ + this.formatNode(this.getNode(inRowIndex), inDatum, inRowIndex); + }, + applyStaticValue: function(inRowIndex){ + var e = this.cell.grid.edit; + e.applyCellEdit(this.getValue(inRowIndex), this.cell, inRowIndex); + e.start(this.cell, inRowIndex, true); + } +}); +dojox.grid.editors.alwaysOn = dojox.grid.editors.AlwaysOn; // back-compat + +dojo.declare("dojox.grid.editors.Bool", dojox.grid.editors.AlwaysOn, { + // summary: + // grid cell editor that provides a standard checkbox that is always on + _valueProp: "checked", + format: function(inDatum, inRowIndex){ + return ''; + }, + doclick: function(e){ + if(e.target.tagName == 'INPUT'){ + this.applyStaticValue(e.rowIndex); + } + } +}); +dojox.grid.editors.bool = dojox.grid.editors.Bool; // back-compat + +} diff --git a/includes/js/dojox/grid/_data/fields.js b/includes/js/dojox/grid/_data/fields.js new file mode 100644 index 0000000..230bede --- /dev/null +++ b/includes/js/dojox/grid/_data/fields.js @@ -0,0 +1,104 @@ +if(!dojo._hasResource["dojox.grid._data.fields"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid._data.fields"] = true; +dojo.provide("dojox.grid._data.fields"); + +dojo.declare("dojox.grid.data.Mixer", null, { + // summary: + // basic collection class that provides a default value for items + + constructor: function(){ + this.defaultValue = {}; + this.values = []; + }, + count: function(){ + return this.values.length; + }, + clear: function(){ + this.values = []; + }, + build: function(inIndex){ + var result = dojo.mixin({owner: this}, this.defaultValue); + result.key = inIndex; + this.values[inIndex] = result; + return result; + }, + getDefault: function(){ + return this.defaultValue; + }, + setDefault: function(inField /*[, inField2, ... inFieldN] */){ + for(var i=0, a; (a = arguments[i]); i++){ + dojo.mixin(this.defaultValue, a); + } + }, + get: function(inIndex){ + return this.values[inIndex] || this.build(inIndex); + }, + _set: function(inIndex, inField /*[, inField2, ... inFieldN] */){ + // each field argument can be a single field object of an array of field objects + var v = this.get(inIndex); + for(var i=1; i= this.values.length){ + this.values[inIndex] = inProps; + }else{ + this.values.splice(inIndex, 0, inProps); + } + }, + remove: function(inIndex){ + this.values.splice(inIndex, 1); + }, + swap: function(inIndexA, inIndexB){ + dojox.grid.arraySwap(this.values, inIndexA, inIndexB); + }, + move: function(inFromIndex, inToIndex){ + dojox.grid.arrayMove(this.values, inFromIndex, inToIndex); + } +}); + +dojox.grid.data.compare = function(a, b){ + return (a > b ? 1 : (a == b ? 0 : -1)); +} + +dojo.declare('dojox.grid.data.Field', null, { + constructor: function(inName){ + this.name = inName; + this.compare = dojox.grid.data.compare; + }, + na: dojox.grid.na +}); + +dojo.declare('dojox.grid.data.Fields', dojox.grid.data.Mixer, { + constructor: function(inFieldClass){ + var fieldClass = inFieldClass ? inFieldClass : dojox.grid.data.Field; + this.defaultValue = new fieldClass(); + }, + indexOf: function(inKey){ + for(var i=0; i=0; i--){ + idx = inIndices[i]; + col = Math.abs(idx) - 1; + if(col >= 0){ + field = this.fields.get(col); + result = this.generateComparator(field.compare, field.key, idx > 0, result); + } + } + return result; + }, + sort: null, + dummy: 0 +}); + +dojo.declare("dojox.grid.data.Rows", dojox.grid.data.Model, { + // observer events + allChange: function(){ + this.notify("AllChange", arguments); + this.notify("Change", arguments); + }, + rowChange: function(){ + this.notify("RowChange", arguments); + }, + datumChange: function(){ + this.notify("DatumChange", arguments); + }, + // copyRow: function(inRowIndex); // abstract + // update + beginModifyRow: function(inRowIndex){ + if(!this.cache[inRowIndex]){ + this.cache[inRowIndex] = this.copyRow(inRowIndex); + } + }, + endModifyRow: function(inRowIndex){ + var cache = this.cache[inRowIndex]; + if(cache){ + var data = this.getRow(inRowIndex); + if(!dojox.grid.arrayCompare(cache, data)){ + this.update(cache, data, inRowIndex); + } + delete this.cache[inRowIndex]; + } + }, + cancelModifyRow: function(inRowIndex){ + var cache = this.cache[inRowIndex]; + if(cache){ + this.setRow(cache, inRowIndex); + delete this.cache[inRowIndex]; + } + } +}); + +dojo.declare("dojox.grid.data.Table", dojox.grid.data.Rows, { + // summary: + // Basic grid data model for static data in the form of an array of rows + // that are arrays of cell data + constructor: function(){ + this.cache = []; + }, + colCount: 0, // tables introduce cols + data: null, + cache: null, + // morphology + measure: function(){ + this.count = this.getRowCount(); + this.colCount = this.getColCount(); + this.allChange(); + //this.notify("Measure"); + }, + getRowCount: function(){ + return (this.data ? this.data.length : 0); + }, + getColCount: function(){ + return (this.data && this.data.length ? this.data[0].length : this.fields.count()); + }, + badIndex: function(inCaller, inDescriptor){ + console.debug('dojox.grid.data.Table: badIndex'); + }, + isGoodIndex: function(inRowIndex, inColIndex){ + return (inRowIndex >= 0 && inRowIndex < this.count && (arguments.length < 2 || (inColIndex >= 0 && inColIndex < this.colCount))); + }, + // access + getRow: function(inRowIndex){ + return this.data[inRowIndex]; + }, + copyRow: function(inRowIndex){ + return this.getRow(inRowIndex).slice(0); + }, + getDatum: function(inRowIndex, inColIndex){ + return this.data[inRowIndex][inColIndex]; + }, + get: function(){ + throw('Plain "get" no longer supported. Use "getRow" or "getDatum".'); + }, + setData: function(inData){ + this.data = (inData || []); + this.allChange(); + }, + setRow: function(inData, inRowIndex){ + this.data[inRowIndex] = inData; + this.rowChange(inData, inRowIndex); + this.change(); + }, + setDatum: function(inDatum, inRowIndex, inColIndex){ + this.data[inRowIndex][inColIndex] = inDatum; + this.datumChange(inDatum, inRowIndex, inColIndex); + }, + set: function(){ + throw('Plain "set" no longer supported. Use "setData", "setRow", or "setDatum".'); + }, + setRows: function(inData, inRowIndex){ + for(var i=0, l=inData.length, r=inRowIndex; i=0; i--){ + dojox.grid.arrayRemove(this.data, inKeys[i]); + } + this.count -= inKeys.length; + return true; + }, + // sort + sort: function(/* (+|-)column_index+1, ... */){ + this.data.sort(this.makeComparator(arguments)); + }, + swap: function(inIndexA, inIndexB){ + dojox.grid.arraySwap(this.data, inIndexA, inIndexB); + this.rowChange(this.getRow(inIndexA), inIndexA); + this.rowChange(this.getRow(inIndexB), inIndexB); + this.change(); + }, + dummy: 0 +}); + +dojo.declare("dojox.grid.data.Objects", dojox.grid.data.Table, { + constructor: function(inFields, inData, inKey){ + if(!inFields){ + this.autoAssignFields(); + } + }, + allChange: function(){ + this.notify("FieldsChange"); + this.inherited(arguments); + }, + autoAssignFields: function(){ + var d = this.data[0], i = 0, field; + for(var f in d){ + field = this.fields.get(i++); + if (!dojo.isString(field.key)){ + field.key = f; + } + } + }, + setData: function(inData){ + this.data = (inData || []); + this.autoAssignFields(); + this.allChange(); + }, + getDatum: function(inRowIndex, inColIndex){ + return this.data[inRowIndex][this.fields.get(inColIndex).key]; + } +}); + +dojo.declare("dojox.grid.data.Dynamic", dojox.grid.data.Table, { + // summary: + // Grid data model for dynamic data such as data retrieved from a server. + // Retrieves data automatically when requested and provides notification when data is received + constructor: function(){ + this.page = []; + this.pages = []; + }, + page: null, + pages: null, + rowsPerPage: 100, + requests: 0, + bop: -1, + eop: -1, + // data + clearData: function(){ + this.pages = []; + this.bop = this.eop = -1; + this.setData([]); + }, + getRowCount: function(){ + return this.count; + }, + getColCount: function(){ + return this.fields.count(); + }, + setRowCount: function(inCount){ + this.count = inCount; + this.change(); + }, + // paging + requestsPending: function(inBoolean){ + }, + rowToPage: function(inRowIndex){ + return (this.rowsPerPage ? Math.floor(inRowIndex / this.rowsPerPage) : inRowIndex); + }, + pageToRow: function(inPageIndex){ + return (this.rowsPerPage ? this.rowsPerPage * inPageIndex : inPageIndex); + }, + requestRows: function(inRowIndex, inCount){ + // summary: + // stub. Fill in to perform actual data row fetching logic. The + // returning logic must provide the data back to the system via + // setRow + }, + rowsProvided: function(inRowIndex, inCount){ + this.requests--; + if(this.requests == 0){ + this.requestsPending(false); + } + }, + requestPage: function(inPageIndex){ + var row = this.pageToRow(inPageIndex); + var count = Math.min(this.rowsPerPage, this.count - row); + if(count > 0){ + this.requests++; + this.requestsPending(true); + setTimeout(dojo.hitch(this, "requestRows", row, count), 1); + //this.requestRows(row, count); + } + }, + needPage: function(inPageIndex){ + if(!this.pages[inPageIndex]){ + this.pages[inPageIndex] = true; + this.requestPage(inPageIndex); + } + }, + preparePage: function(inRowIndex, inColIndex){ + if(inRowIndex < this.bop || inRowIndex >= this.eop){ + var pageIndex = this.rowToPage(inRowIndex); + this.needPage(pageIndex); + this.bop = pageIndex * this.rowsPerPage; + this.eop = this.bop + (this.rowsPerPage || this.count); + } + }, + isRowLoaded: function(inRowIndex){ + return Boolean(this.data[inRowIndex]); + }, + // removal + removePages: function(inRowIndexes){ + for(var i=0, r; ((r=inRowIndexes[i]) != undefined); i++){ + this.pages[this.rowToPage(r)] = false; + } + this.bop = this.eop =-1; + }, + remove: function(inRowIndexes){ + this.removePages(inRowIndexes); + dojox.grid.data.Table.prototype.remove.apply(this, arguments); + }, + // access + getRow: function(inRowIndex){ + var row = this.data[inRowIndex]; + if(!row){ + this.preparePage(inRowIndex); + } + return row; + }, + getDatum: function(inRowIndex, inColIndex){ + var row = this.getRow(inRowIndex); + return (row ? row[inColIndex] : this.fields.get(inColIndex).na); + }, + setDatum: function(inDatum, inRowIndex, inColIndex){ + var row = this.getRow(inRowIndex); + if(row){ + row[inColIndex] = inDatum; + this.datumChange(inDatum, inRowIndex, inColIndex); + }else{ + console.debug('[' + this.declaredClass + '] dojox.grid.data.dynamic.set: cannot set data on an non-loaded row'); + } + }, + // sort + canSort: function(){ + return false; + } +}); + +// FIXME: deprecated: (included for backward compatibility only) +dojox.grid.data.table = dojox.grid.data.Table; +dojox.grid.data.dynamic = dojox.grid.data.Dynamic; + +// we treat dojo.data stores as dynamic stores because no matter how they got +// here, they should always fill that contract +dojo.declare("dojox.grid.data.DojoData", dojox.grid.data.Dynamic, { + // summary: + // A grid data model for dynamic data retreived from a store which + // implements the dojo.data API set. Retrieves data automatically when + // requested and provides notification when data is received + // description: + // This store subclasses the Dynamic grid data object in order to + // provide paginated data access support, notification and view + // updates for stores which support those features, and simple + // field/column mapping for all dojo.data stores. + constructor: function(inFields, inData, args){ + this.count = 1; + this._rowIdentities = {}; + this._currentlyProcessing = []; + if(args){ + dojo.mixin(this, args); + } + if(this.store){ + var f = this.store.getFeatures(); + this._canNotify = f['dojo.data.api.Notification']; + this._canWrite = f['dojo.data.api.Write']; + this._canIdentify = f['dojo.data.api.Identity']; + if(this._canNotify){ + dojo.connect(this.store, "onSet", this, "_storeDatumChange"); + dojo.connect(this.store, "onDelete", this, "_storeDatumDelete"); + dojo.connect(this.store, "onNew", this, "_storeDatumNew"); + } + if(this._canWrite) { + dojo.connect(this.store, "revert", this, "refresh"); + } + } + }, + markupFactory: function(args, node){ + return new dojox.grid.data.DojoData(null, null, args); + }, + query: { name: "*" }, // default, stupid query + store: null, + _currentlyProcessing: null, + _canNotify: false, + _canWrite: false, + _canIdentify: false, + _rowIdentities: {}, + clientSort: false, + sortFields: null, + queryOptions: null, + + // data + setData: function(inData){ + this.store = inData; + this.data = []; + this.allChange(); + }, + setRowCount: function(inCount){ + //console.debug("inCount:", inCount); + this.count = inCount; + this.allChange(); + }, + beginReturn: function(inCount){ + if(this.count != inCount){ + // this.setRowCount(0); + // this.clear(); + // console.debug(this.count, inCount); + this.setRowCount(inCount); + } + }, + _setupFields: function(dataItem){ + // abort if we already have setup fields + if(this.fields._nameMaps){ + return; + } + // set up field/index mappings + var m = {}; + //console.debug("setting up fields", m); + var fields = dojo.map(this.store.getAttributes(dataItem), + function(item, idx){ + m[item] = idx; + m[idx+".idx"] = item; + // name == display name, key = property name + return { name: item, key: item }; + }, + this + ); + this.fields._nameMaps = m; + // console.debug("new fields:", fields); + this.fields.set(fields); + this.notify("FieldsChange"); + }, + _getRowFromItem: function(item){ + // gets us the row object (and row index) of an item + }, + _createRow: function(item){ + var row = {}; + row.__dojo_data_item = item; + dojo.forEach(this.fields.values, function(a){ + value = this.store.getValue(item, a.name); + row[a.name] = (value === undefined || value === null)?"":value; + }, this); + return row; + }, + processRows: function(items, request){ + // console.debug(arguments); + if(!items || items.length == 0){ return; } + this._setupFields(items[0]); + dojo.forEach(items, function(item, idx){ + var row = this._createRow(item); + this._setRowId(item, request.start, idx); + this.setRow(row, request.start+idx); + }, this); + // FIXME: + // Q: scott, steve, how the hell do we actually get this to update + // the visible UI for these rows? + // A: the goal is that Grid automatically updates to reflect changes + // in model. In this case, setRow -> rowChanged -> (observed by) Grid -> modelRowChange -> updateRow + }, + // request data + requestRows: function(inRowIndex, inCount){ + var row = inRowIndex || 0; + var params = { + start: row, + count: this.rowsPerPage, + query: this.query, + sort: this.sortFields, + queryOptions: this.queryOptions, + onBegin: dojo.hitch(this, "beginReturn"), + onComplete: dojo.hitch(this, "processRows"), // add to deferred? + onError: dojo.hitch(this, "processError") + }; + this.store.fetch(params); + }, + getDatum: function(inRowIndex, inColIndex){ + //console.debug("getDatum", inRowIndex, inColIndex); + var row = this.getRow(inRowIndex); + var field = this.fields.values[inColIndex]; + return row && field ? row[field.name] : field ? field.na : '?'; + //var idx = row && this.fields._nameMaps[inColIndex+".idx"]; + //return (row ? row[idx] : this.fields.get(inColIndex).na); + }, + setDatum: function(inDatum, inRowIndex, inColIndex){ + var n = this.fields._nameMaps[inColIndex+".idx"]; + // console.debug("setDatum:", "n:"+n, inDatum, inRowIndex, inColIndex); + if(n){ + this.data[inRowIndex][n] = inDatum; + this.datumChange(inDatum, inRowIndex, inColIndex); + } + }, + // modification, update and store eventing + copyRow: function(inRowIndex){ + var row = {}; + var backstop = {}; + var src = this.getRow(inRowIndex); + for(var x in src){ + if(src[x] != backstop[x]){ + row[x] = src[x]; + } + } + return row; + }, + _attrCompare: function(cache, data){ + dojo.forEach(this.fields.values, function(a){ + if(cache[a.name] != data[a.name]){ return false; } + }, this); + return true; + }, + endModifyRow: function(inRowIndex){ + var cache = this.cache[inRowIndex]; + if(cache){ + var data = this.getRow(inRowIndex); + if(!this._attrCompare(cache, data)){ + this.update(cache, data, inRowIndex); + } + delete this.cache[inRowIndex]; + } + }, + cancelModifyRow: function(inRowIndex){ + // console.debug("cancelModifyRow", arguments); + var cache = this.cache[inRowIndex]; + if(cache){ + this.setRow(cache, inRowIndex); + delete this.cache[inRowIndex]; + } + }, + _setRowId: function(item, offset, idx){ + // FIXME: where else do we need to keep this in sync? + //Handle stores that implement identity and try to handle those that do not. + if (this._canIdentify) { + this._rowIdentities[this.store.getIdentity(item)] = {rowId: offset+idx, item: item}; + }else{ + var identity = dojo.toJson(this.query) + ":start:" + offset + ":idx:" + idx + ":sort:" + dojo.toJson(this.sortFields); + this._rowIdentities[identity] = {rowId: offset+idx, item: item}; + } + }, + _getRowId: function(item, isNotItem){ + // summary: + // Function determine the row index for a particular item + // item: + // The store item to examine to determine row index. + // isNotItem: + // Boolean flag to indicate if the item passed is a store item or not. + var rowId = null; + //Handle identity and nonidentity capable stores. + if(this._canIdentify && !isNotItem){ + rowId = this._rowIdentities[this.store.getIdentity(item)].rowId; + }else{ + //Not efficient, but without identity support, + //not a better way to do it. Basically, do our best to locate it + //This may or may not work, but best we can do here. + var id; + for(id in this._rowIdentities){ + if(this._rowIdentities[id].item === item){ + rowId = this._rowIdentities[id].rowId; + break; + } + } + } + return rowId; + }, + _storeDatumChange: function(item, attr, oldVal, newVal){ + // the store has changed some data under us, need to update the display + var rowId = this._getRowId(item); + var row = this.getRow(rowId); + if(row){ + row[attr] = newVal; + var colId = this.fields._nameMaps[attr]; + this.notify("DatumChange", [ newVal, rowId, colId ]); + } + }, + _storeDatumDelete: function(item){ + if(dojo.indexOf(this._currentlyProcessing, item) != -1) + return; + // the store has deleted some item under us, need to remove that item from + // the view if possible. It may be the deleted item isn't even in the grid. + var rowId = this._getRowId(item, true); + if(rowId != null){ + this._removeItems([rowId]); + } + }, + _storeDatumNew: function(item){ + if(this._disableNew){ + return; + } + // the store has added some item under us, need to add it to the view. + this._insertItem(item, this.data.length); + }, + insert: function(item, index){ + // Push the given item back to the store + this._disableNew = true; + var i = this.store.newItem(item); + this._disableNew = false; + this._insertItem(i, index); + }, + _insertItem: function(storeItem, index){ + // Set up our fields if we haven't already + if(!this.fields._nameMaps){ + this._setupFields(storeItem); + } + var row = this._createRow(storeItem); + for(var i in this._rowIdentities){ //increment all the remaining row ids up one + var rowIdentity = this._rowIdentities[i]; + if(rowIdentity.rowId >= index){ + rowIdentity.rowId++; + } + } + this._setRowId(storeItem, 0, index); + dojox.grid.data.Dynamic.prototype.insert.apply(this, [row, index]); + }, + datumChange: function(value, rowIdx, colIdx){ + if(this._canWrite){ + // we're chaning some data, which means we need to write back + var row = this.getRow(rowIdx); + var field = this.fields._nameMaps[colIdx+".idx"]; + this.store.setValue(row.__dojo_data_item, field, value); + // we don't need to call DatumChange, an eventing store will tell + // us about the row change events + }else{ + // we can't write back, so just go ahead and change our local copy + // of the data + this.notify("DatumChange", arguments); + } + }, + insertion: function(/* index */){ + console.debug("Insertion", arguments); + this.notify("Insertion", arguments); + this.notify("Change", arguments); + }, + removal: function(/* keys */){ + console.debug("Removal", arguments); + this.notify("Removal", arguments); + this.notify("Change", arguments); + }, + remove: function(inRowIndexes){ + // summary: + // Function to remove a set of items from the store based on the row index. + // inRowIndexes: + // An array of row indexes from the grid to remove from the store. + /* Call delete on the store */ + for(var i=inRowIndexes.length-1; i>=0; i--){ + // Need to find the item, then remove each from the data store + var item = this.data[inRowIndexes[i]].__dojo_data_item; + this._currentlyProcessing.push(item); + this.store.deleteItem(item); + } + /* Remove from internal data structure and the view */ + this._removeItems(inRowIndexes); + this._currentlyProcessing = []; + }, + _removeItems: function(inRowIndexes /*array*/){ + // summary: + // Function to remove a set of items from the store based on the row index. + // inRowIndexes: + // An array of row indexes from the grid to remove from the store. + dojox.grid.data.Dynamic.prototype.remove.apply(this, arguments); + // Rebuild _rowIdentities + this._rowIdentities = {}; + for (var i = 0; i < this.data.length; i++){ + this._setRowId(this.data[i].__dojo_data_item, 0, i); + } + }, + canSort: function(){ + // Q: Return true and re-issue the queries? + // A: Return true only. Re-issue the query in 'sort'. + // Note, above are original comments :) + return true; + }, + sort: function(colIndex){ + var col = Math.abs(colIndex) - 1; + this.sortFields = [{'attribute': this.fields.values[col].name, 'descending': (colIndex>0)}]; + + // Since we're relying on the data store to sort, we have to refresh our data. + this.refresh(); + }, + refresh: function(){ + // summary: + // Function to cause the model to re-query the store and rebuild the current viewport. + this.clearData(true); + this.requestRows(); + }, + clearData: function(/* boolean */ keepStore){ + this._rowIdentities = {}; + this.pages = []; + this.bop = this.eop = -1; + this.count = 0; + this.setData((keepStore?this.store:[])); + }, + processError: function(error, request){ + // summary: + // Hook function to trap error messages from the store and emit them. + // Intended for connecting to and handling the error object or at least reporting it. + // + // error: + // The error object returned by the store when a problem occurred. + // request: + // The request object that caused the error. + console.log(error); + } +}); + +} diff --git a/includes/js/dojox/grid/_grid/Grid.css b/includes/js/dojox/grid/_grid/Grid.css new file mode 100644 index 0000000..655be54 --- /dev/null +++ b/includes/js/dojox/grid/_grid/Grid.css @@ -0,0 +1,201 @@ +.dojoxGrid { + position: relative; + background-color: #EBEADB; + font-family: Geneva, Arial, Helvetica, sans-serif; + -moz-outline-style: none; + outline: none; + overflow: hidden; + height: 0; +} +.dojoxGrid table { + padding: 0; +} +.dojoxGrid td { + -moz-outline: none; +} +.dojoxGrid-master-header { + position: relative; +} +.dojoxGrid-master-view { + position: relative; +} +.dojoxGrid-view { + position: absolute; + overflow: hidden; +} +.dojoxGrid-header { + position: absolute; + overflow: hidden; +} +.dojoxGrid-header { + background-color: #E8E1CF; +} +.dojoxGrid-header table { + text-align: center; +} +.dojoxGrid-header .dojoxGrid-cell-content { + text-align: center; +} +.dojoxGrid-header .dojoxGrid-cell { + border: 1px solid; + border-color: #F6F4EB #ACA899 #ACA899 #F6F4EB; + background: url(images/grid_dx_gradient.gif) #E8E1CF top repeat-x; + padding-bottom: 2px; +} +.dojoxGrid-header .dojoxGrid-cell-over { + background-image: none; + background-color: white; + border-bottom-color: #FEBE47; + margin-bottom: 0; + padding-bottom: 0; + border-bottom-width: 3px; +} +.dojoxGrid-sort-down { + background: url(images/grid_sort_down.gif) left no-repeat; + padding-left:16px; + margin-left:4px; +} +.dojoxGrid-sort-up { + background: url(images/grid_sort_up.gif) left no-repeat; + padding-left:16px; + margin-left:4px; +} +.dojoxGrid-scrollbox { + position: relative; + overflow: scroll; + background-color: white; + width: 100%; +} +.dojoxGrid-content { + position: relative; + overflow: hidden; + -moz-outline-style: none; + outline: none; +} +.dojoxGrid-rowbar { + border: 1px solid; + border-color: #F6F4EB #ACA899 #ACA899 #F6F4EB; + border-top: none; + background: url(images/grid_dx_gradient.gif) #E8E1CF top repeat-x; +} +.dojoxGrid-rowbar-inner { + border-top: 1px solid #F6F4EB; +} +.dojoxGrid-rowbar-over { + background-image: none; + background-color: white; + border-top-color: #FEBE47; + border-bottom-color: #FEBE47; +} +.dojoxGrid-rowbar-selected { + background-color: #D9E8F9; + background-image: none; + + background-position: center; + background-repeat: no-repeat; +} +.dojoxGrid-row { + position: relative; + width: 9000em; +} +.dojoxGrid-row { + + border: 1px solid #E8E4D8; + border-color: #F8F7F1; + + border-left: none; + border-right: none; + background-color: white; + border-top: none; +} +.dojoxGrid-row-over { + border-top-color: #FEBE47; + border-bottom-color: #FEBE47; + + + +} +.dojoxGrid-row-odd { + background-color: #FFFDF3; + +} +.dojoxGrid-row-selected { + background-color: #D9E8F9; +} +.dojoxGrid-row-table { + table-layout: fixed; + width: 0; +} +.dojoxGrid-invisible { + visibility: hidden; +} +.Xdojo-ie .dojoxGrid-invisible { + display: none; +} +.dojoxGrid-invisible td, .dojoxGrid-header .dojoxGrid-invisible td { + border-top-width: 0; + border-bottom-width: 0; + padding-top: 0; + padding-bottom: 0; + height: 0; + overflow: hidden; +} +.dojoxGrid-cell { + border: 1px solid; + border-color: #EBEADB; + border-right-color: #D5CDB5; + padding: 3px 3px 3px 3px; + text-align: left; + overflow: hidden; +} +.dojoxGrid-cell-focus { + border: 1px dashed blue; +} +.dojoxGrid-cell-over { + border: 1px dotted #FEBE47; +} +.dojoxGrid-cell-focus.dojoxGrid-cell-over { + border: 1px dotted green; +} +.dojoxGrid-cell-clip { + width: 100%; + overflow: hidden; + white-space:nowrap; + text-overflow: ellipsis; +} +.dojoxGrid-row-editing td { + background-color: #F4FFF4; +} +.dojoxGrid-row-inserting td { + background-color: #F4FFF4; +} +.dojoxGrid-row-inflight td { + background-color: #F2F7B7; +} +.dojoxGrid-row-error td { + background-color: #F8B8B6; +} +.dojoxGrid-input, .dojoxGrid-select, .dojoxGrid-textarea { + margin: 0; + padding: 0; + border-style: none; + width: 100%; + font-size: 100%; + font-family: inherit; +} +.dojoxGrid-hidden-focus { + position: absolute; + left: -1000px; + top: -1000px; + height: 0px, width: 0px; +} +.gridArrowButtonChar { + display:none !important; +} +.dijit_a11y .gridArrowButtonChar { + display:inline !important; +} +.dijit_a11y .dojoxGrid-sort-down, .dijit_a11y .dojoxGrid-sort-up { + margin-left: 0; + padding-left: 0; +} diff --git a/includes/js/dojox/grid/_grid/Grid.css.commented.css b/includes/js/dojox/grid/_grid/Grid.css.commented.css new file mode 100644 index 0000000..227ffa3 --- /dev/null +++ b/includes/js/dojox/grid/_grid/Grid.css.commented.css @@ -0,0 +1,258 @@ +.dojoxGrid { + position: relative; + background-color: #EBEADB; + font-family: Geneva, Arial, Helvetica, sans-serif; + -moz-outline-style: none; + outline: none; + overflow: hidden; + height: 0; +} + +.dojoxGrid table { + padding: 0; +} + +.dojoxGrid td { + -moz-outline: none; +} + +/* master header */ + +.dojoxGrid-master-header { + position: relative; +} + +/* master view */ + +.dojoxGrid-master-view { + position: relative; +} + +/* views */ + +.dojoxGrid-view { + position: absolute; + overflow: hidden; +} + +/* header */ + +.dojoxGrid-header { + position: absolute; + overflow: hidden; +} + +.dojoxGrid-header { + background-color: #E8E1CF; +} + +.dojoxGrid-header table { + text-align: center; +} + +.dojoxGrid-header .dojoxGrid-cell-content { + text-align: center; +} + +.dojoxGrid-header .dojoxGrid-cell { + border: 1px solid; + border-color: #F6F4EB #ACA899 #ACA899 #F6F4EB; + background: url(images/grid_dx_gradient.gif) #E8E1CF top repeat-x; + padding-bottom: 2px; +} + +.dojoxGrid-header .dojoxGrid-cell-over { + background-image: none; + background-color: white; + border-bottom-color: #FEBE47; + margin-bottom: 0; + padding-bottom: 0; + border-bottom-width: 3px; +} + +.dojoxGrid-sort-down { + background: url(images/grid_sort_down.gif) left no-repeat; + padding-left:16px; + margin-left:4px; +} + +.dojoxGrid-sort-up { + background: url(images/grid_sort_up.gif) left no-repeat; + padding-left:16px; + margin-left:4px; +} + +/* content */ + +.dojoxGrid-scrollbox { + position: relative; + overflow: scroll; + background-color: white; + width: 100%; +} + +.dojoxGrid-content { + position: relative; + overflow: hidden; + -moz-outline-style: none; + outline: none; +} + +/* rowbar */ + +.dojoxGrid-rowbar { + border: 1px solid; + border-color: #F6F4EB #ACA899 #ACA899 #F6F4EB; + border-top: none; + background: url(images/grid_dx_gradient.gif) #E8E1CF top repeat-x; +} + +.dojoxGrid-rowbar-inner { + border-top: 1px solid #F6F4EB; +} + +.dojoxGrid-rowbar-over { + background-image: none; + background-color: white; + border-top-color: #FEBE47; + border-bottom-color: #FEBE47; +} + +.dojoxGrid-rowbar-selected { + background-color: #D9E8F9; + background-image: none; + /*background-image: url(images/grid_green_dot.gif);*/ + background-position: center; + background-repeat: no-repeat; +} + +/* rows */ + +.dojoxGrid-row { + position: relative; + width: 9000em; +} + +.dojoxGrid-row { + /*border: 1px solid #E8E4D8;*/ + border: 1px solid #E8E4D8; + border-color: #F8F7F1; + /*padding: 0 0 1px 0;*/ + border-left: none; + border-right: none; + background-color: white; + border-top: none; +} + +.dojoxGrid-row-over { + border-top-color: #FEBE47; + border-bottom-color: #FEBE47; + /*border-bottom-width: 2px; + padding-bottom: 0;*/ + /*background-color: #FFDD9D;*/ + /*background-color: #FDFDFD;*/ +} + +.dojoxGrid-row-odd { + background-color: #FFFDF3; + /*background-color: #F9F7E8;*/ +} + +.dojoxGrid-row-selected { + background-color: #D9E8F9; +} + +.dojoxGrid-row-table { + table-layout: fixed; + width: 0; +} + +.dojoxGrid-invisible { + visibility: hidden; +} + +.Xdojo-ie .dojoxGrid-invisible { + display: none; +} + +.dojoxGrid-invisible td, .dojoxGrid-header .dojoxGrid-invisible td { + border-top-width: 0; + border-bottom-width: 0; + padding-top: 0; + padding-bottom: 0; + height: 0; + overflow: hidden; +} + +/* cells */ + +.dojoxGrid-cell { + border: 1px solid; + border-color: #EBEADB; + border-right-color: #D5CDB5; + padding: 3px 3px 3px 3px; + text-align: left; + overflow: hidden; +} + +.dojoxGrid-cell-focus { + border: 1px dashed blue; +} + +.dojoxGrid-cell-over { + border: 1px dotted #FEBE47; +} + +.dojoxGrid-cell-focus.dojoxGrid-cell-over { + border: 1px dotted green; +} + +.dojoxGrid-cell-clip { + width: 100%; + overflow: hidden; + white-space:nowrap; + text-overflow: ellipsis; +} + +/* editing */ + +.dojoxGrid-row-editing td { + background-color: #F4FFF4; +} + +.dojoxGrid-row-inserting td { + background-color: #F4FFF4; +} +.dojoxGrid-row-inflight td { + background-color: #F2F7B7; +} +.dojoxGrid-row-error td { + background-color: #F8B8B6; +} + +.dojoxGrid-input, .dojoxGrid-select, .dojoxGrid-textarea { + margin: 0; + padding: 0; + border-style: none; + width: 100%; + font-size: 100%; + font-family: inherit; +} + +.dojoxGrid-hidden-focus { + position: absolute; + left: -1000px; + top: -1000px; + height: 0px, width: 0px; +} + +.gridArrowButtonChar { + display:none !important; +} +.dijit_a11y .gridArrowButtonChar { + display:inline !important; +} +.dijit_a11y .dojoxGrid-sort-down, .dijit_a11y .dojoxGrid-sort-up { + margin-left: 0; + padding-left: 0; +} diff --git a/includes/js/dojox/grid/_grid/Grid_rtl.css b/includes/js/dojox/grid/_grid/Grid_rtl.css new file mode 100644 index 0000000..88ab215 --- /dev/null +++ b/includes/js/dojox/grid/_grid/Grid_rtl.css @@ -0,0 +1,8 @@ +.dijitRtl .dojoxGrid-header table { +} +.dj_ie .dijitRtl .dojoxGrid-header table { + float:none; +} +.dijitRtl .dojoxGrid-content { + float:left; +} diff --git a/includes/js/dojox/grid/_grid/Grid_rtl.css.commented.css b/includes/js/dojox/grid/_grid/Grid_rtl.css.commented.css new file mode 100644 index 0000000..c240b4c --- /dev/null +++ b/includes/js/dojox/grid/_grid/Grid_rtl.css.commented.css @@ -0,0 +1,10 @@ +.dijitRtl .dojoxGrid-header table { +} + +.dj_ie .dijitRtl .dojoxGrid-header table { + float:none; +} + +.dijitRtl .dojoxGrid-content { + float:left; +} diff --git a/includes/js/dojox/grid/_grid/builder.js b/includes/js/dojox/grid/_grid/builder.js new file mode 100644 index 0000000..dccf7e2 --- /dev/null +++ b/includes/js/dojox/grid/_grid/builder.js @@ -0,0 +1,522 @@ +if(!dojo._hasResource["dojox.grid._grid.builder"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid._grid.builder"] = true; +dojo.provide("dojox.grid._grid.builder"); +dojo.require("dojox.grid._grid.drag"); + +dojo.declare("dojox.grid.Builder", + null, + { + // summary: + // Base class to produce html for grid content. + // Also provide event decoration, providing grid related information inside the event object + // passed to grid events. + constructor: function(inView){ + this.view = inView; + this.grid = inView.grid; + }, + + view: null, + // boilerplate HTML + _table: '', + + // generate starting tags for a cell + generateCellMarkup: function(inCell, inMoreStyles, inMoreClasses, isHeader){ + var result = [], html; + if (isHeader){ + html = [ '' : ''); + for(var i=0, cell, m, cc, cs; (cell=row[i]); i++){ + m = cell.markup, cc = cell.customClasses = [], cs = cell.customStyles = []; + // content (format can fill in cc and cs as side-effects) + m[5] = cell.format(inDataIndex); + // classes + m[1] = cc.join(' '); + // styles + m[3] = cs.join(';'); + // in-place concat + html.push.apply(html, m); + } + html.push(''); + } + html.push('
      '); + // result[4] => td postfix + result.push(html.join('')); + // SLOT: result[5] => content + result.push(''); + // result[6] => td closes + result.push(''); + return result; // Array + }, + + // cell finding + isCellNode: function(inNode){ + return Boolean(inNode && inNode.getAttribute && inNode.getAttribute("idx")); + }, + + getCellNodeIndex: function(inCellNode){ + return inCellNode ? Number(inCellNode.getAttribute("idx")) : -1; + }, + + getCellNode: function(inRowNode, inCellIndex){ + for(var i=0, row; row=dojox.grid.getTr(inRowNode.firstChild, i); i++){ + for(var j=0, cell; cell=row.cells[j]; j++){ + if(this.getCellNodeIndex(cell) == inCellIndex){ + return cell; + } + } + } + }, + + findCellTarget: function(inSourceNode, inTopNode){ + var n = inSourceNode; + while(n && (!this.isCellNode(n) || (dojox.grid.gridViewTag in n.offsetParent.parentNode && n.offsetParent.parentNode[dojox.grid.gridViewTag] != this.view.id)) && (n!=inTopNode)){ + n = n.parentNode; + } + return n!=inTopNode ? n : null + }, + + // event decoration + baseDecorateEvent: function(e){ + e.dispatch = 'do' + e.type; + e.grid = this.grid; + e.sourceView = this.view; + e.cellNode = this.findCellTarget(e.target, e.rowNode); + e.cellIndex = this.getCellNodeIndex(e.cellNode); + e.cell = (e.cellIndex >= 0 ? this.grid.getCell(e.cellIndex) : null); + }, + + // event dispatch + findTarget: function(inSource, inTag){ + var n = inSource; + while(n && (n!=this.domNode) && (!(inTag in n) || (dojox.grid.gridViewTag in n && n[dojox.grid.gridViewTag] != this.view.id))){ + n = n.parentNode; + } + return (n != this.domNode) ? n : null; + }, + + findRowTarget: function(inSource){ + return this.findTarget(inSource, dojox.grid.rowIndexTag); + }, + + isIntraNodeEvent: function(e){ + try{ + return (e.cellNode && e.relatedTarget && dojo.isDescendant(e.relatedTarget, e.cellNode)); + }catch(x){ + // e.relatedTarget has permission problem in FF if it's an input: https://bugzilla.mozilla.org/show_bug.cgi?id=208427 + return false; + } + }, + + isIntraRowEvent: function(e){ + try{ + var row = e.relatedTarget && this.findRowTarget(e.relatedTarget); + return !row && (e.rowIndex==-1) || row && (e.rowIndex==row.gridRowIndex); + }catch(x){ + // e.relatedTarget on INPUT has permission problem in FF: https://bugzilla.mozilla.org/show_bug.cgi?id=208427 + return false; + } + }, + + dispatchEvent: function(e){ + if(e.dispatch in this){ + return this[e.dispatch](e); + } + }, + + // dispatched event handlers + domouseover: function(e){ + if(e.cellNode && (e.cellNode!=this.lastOverCellNode)){ + this.lastOverCellNode = e.cellNode; + this.grid.onMouseOver(e); + } + this.grid.onMouseOverRow(e); + }, + + domouseout: function(e){ + if(e.cellNode && (e.cellNode==this.lastOverCellNode) && !this.isIntraNodeEvent(e, this.lastOverCellNode)){ + this.lastOverCellNode = null; + this.grid.onMouseOut(e); + if(!this.isIntraRowEvent(e)){ + this.grid.onMouseOutRow(e); + } + } + }, + + domousedown: function(e){ + if (e.cellNode) + this.grid.onMouseDown(e); + this.grid.onMouseDownRow(e) + } + +}); + +dojo.declare("dojox.grid.contentBuilder", + dojox.grid.Builder, + { + // summary: + // Produces html for grid data content. Owned by grid and used internally + // for rendering data. Override to implement custom rendering. + update: function(){ + this.prepareHtml(); + }, + + // cache html for rendering data rows + prepareHtml: function(){ + var defaultGet=this.grid.get, rows=this.view.structure.rows; + for(var j=0, row; (row=rows[j]); j++){ + for(var i=0, cell; (cell=row[i]); i++){ + cell.get = cell.get || (cell.value == undefined) && defaultGet; + cell.markup = this.generateCellMarkup(cell, cell.cellStyles, cell.cellClasses, false); + } + } + }, + + // time critical: generate html using cache and data source + generateHtml: function(inDataIndex, inRowIndex){ + var + html = [ this._table ], + v = this.view, + obr = v.onBeforeRow, + rows = v.structure.rows; + + obr && obr(inRowIndex, rows); + for(var j=0, row; (row=rows[j]); j++){ + if(row.hidden || row.header){ + continue; + } + html.push(!row.invisible ? '
      '); + return html.join(''); // String + }, + + decorateEvent: function(e){ + e.rowNode = this.findRowTarget(e.target); + if(!e.rowNode){return false}; + e.rowIndex = e.rowNode[dojox.grid.rowIndexTag]; + this.baseDecorateEvent(e); + e.cell = this.grid.getCell(e.cellIndex); + return true; // Boolean + } + +}); + +dojo.declare("dojox.grid.headerBuilder", + dojox.grid.Builder, + { + // summary: + // Produces html for grid header content. Owned by grid and used internally + // for rendering data. Override to implement custom rendering. + + bogusClickTime: 0, + overResizeWidth: 4, + minColWidth: 1, + + // FIXME: isn't this getting mixed from dojox.grid.Builder, -1 character? + _table: ''); + dojox.grid.fire(this.view, "onBeforeRow", [-1, rows]); + for(var j=0, row; (row=rows[j]); j++){ + if(row.hidden){ + continue; + } + html.push(!row.invisible ? '' : ''); + for(var i=0, cell, markup; (cell=row[i]); i++){ + cell.customClasses = []; + cell.customStyles = []; + markup = this.generateCellMarkup(cell, cell.headerStyles, cell.headerClasses, true); + // content + markup[5] = (inValue != undefined ? inValue : inGetValue(cell)); + // styles + markup[3] = cell.customStyles.join(';'); + // classes + markup[1] = cell.customClasses.join(' '); //(cell.customClasses ? ' ' + cell.customClasses : ''); + html.push(markup.join('')); + } + html.push(''); + } + html.push('
      '); + return html.join(''); + }, + + // event helpers + getCellX: function(e){ + var x = e.layerX; + if(dojo.isMoz){ + var n = dojox.grid.ascendDom(e.target, dojox.grid.makeNotTagName("th")); + x -= (n && n.offsetLeft) || 0; + var t = e.sourceView.getScrollbarWidth(); + if(!dojo._isBodyLtr() && e.sourceView.headerNode.scrollLeft < t) + x -= t; + //x -= getProp(ascendDom(e.target, mkNotTagName("td")), "offsetLeft") || 0; + } + var n = dojox.grid.ascendDom(e.target, function(){ + if(!n || n == e.cellNode){ + return false; + } + // Mozilla 1.8 (FF 1.5) has a bug that makes offsetLeft = -parent border width + // when parent has border, overflow: hidden, and is positioned + // handle this problem here ... not a general solution! + x += (n.offsetLeft < 0 ? 0 : n.offsetLeft); + return true; + }); + return x; + }, + + // event decoration + decorateEvent: function(e){ + this.baseDecorateEvent(e); + e.rowIndex = -1; + e.cellX = this.getCellX(e); + return true; + }, + + // event handlers + // resizing + prepareResize: function(e, mod){ + var i = dojox.grid.getTdIndex(e.cellNode); + e.cellNode = (i ? e.cellNode.parentNode.cells[i+mod] : null); + e.cellIndex = (e.cellNode ? this.getCellNodeIndex(e.cellNode) : -1); + return Boolean(e.cellNode); + }, + + canResize: function(e){ + if(!e.cellNode || e.cellNode.colSpan > 1){ + return false; + } + var cell = this.grid.getCell(e.cellIndex); + return !cell.noresize && !cell.isFlex(); + }, + + overLeftResizeArea: function(e){ + if(dojo._isBodyLtr()){ + return (e.cellIndex>0) && (e.cellX < this.overResizeWidth) && this.prepareResize(e, -1); + } + return t = e.cellNode && (e.cellX < this.overResizeWidth); + }, + + overRightResizeArea: function(e){ + if(dojo._isBodyLtr()){ + return e.cellNode && (e.cellX >= e.cellNode.offsetWidth - this.overResizeWidth); + } + return (e.cellIndex>0) && (e.cellX >= e.cellNode.offsetWidth - this.overResizeWidth) && this.prepareResize(e, -1); + }, + + domousemove: function(e){ + //console.log(e.cellIndex, e.cellX, e.cellNode.offsetWidth); + var c = (this.overRightResizeArea(e) ? 'e-resize' : (this.overLeftResizeArea(e) ? 'w-resize' : '')); + if(c && !this.canResize(e)){ + c = 'not-allowed'; + } + e.sourceView.headerNode.style.cursor = c || ''; //'default'; + if (c) + dojo.stopEvent(e); + }, + + domousedown: function(e){ + if(!dojox.grid.drag.dragging){ + if((this.overRightResizeArea(e) || this.overLeftResizeArea(e)) && this.canResize(e)){ + this.beginColumnResize(e); + }else{ + this.grid.onMouseDown(e); + this.grid.onMouseOverRow(e); + } + //else{ + // this.beginMoveColumn(e); + //} + } + }, + + doclick: function(e) { + if (new Date().getTime() < this.bogusClickTime) { + dojo.stopEvent(e); + return true; + } + }, + + // column resizing + beginColumnResize: function(e){ + dojo.stopEvent(e); + var spanners = [], nodes = this.tableMap.findOverlappingNodes(e.cellNode); + for(var i=0, cell; (cell=nodes[i]); i++){ + spanners.push({ node: cell, index: this.getCellNodeIndex(cell), width: cell.offsetWidth }); + //console.log("spanner: " + this.getCellNodeIndex(cell)); + } + var drag = { + scrollLeft: e.sourceView.headerNode.scrollLeft, + view: e.sourceView, + node: e.cellNode, + index: e.cellIndex, + w: e.cellNode.clientWidth, + spanners: spanners + }; + //console.log(drag.index, drag.w); + dojox.grid.drag.start(e.cellNode, dojo.hitch(this, 'doResizeColumn', drag), dojo.hitch(this, 'endResizeColumn', drag), e); + }, + + doResizeColumn: function(inDrag, inEvent){ + var isLtr = dojo._isBodyLtr(); + if(isLtr){ + var w = inDrag.w + inEvent.deltaX; + }else{ + var w = inDrag.w - inEvent.deltaX; + } + if(w >= this.minColWidth){ + for(var i=0, s, sw; (s=inDrag.spanners[i]); i++){ + if(isLtr){ + sw = s.width + inEvent.deltaX; + }else{ + sw = s.width - inEvent.deltaX; + } + s.node.style.width = sw + 'px'; + inDrag.view.setColWidth(s.index, sw); + //console.log('setColWidth', '#' + s.index, sw + 'px'); + } + inDrag.node.style.width = w + 'px'; + inDrag.view.setColWidth(inDrag.index, w); + if(!isLtr){ + inDrag.view.headerNode.scrollLeft = (inDrag.scrollLeft - inEvent.deltaX); + } + } + if(inDrag.view.flexCells && !inDrag.view.testFlexCells()){ + var t = dojox.grid.findTable(inDrag.node); + t && (t.style.width = ''); + } + }, + + endResizeColumn: function(inDrag){ + this.bogusClickTime = new Date().getTime() + 30; + setTimeout(dojo.hitch(inDrag.view, "update"), 50); + } + +}); + +dojo.declare("dojox.grid.tableMap", + null, + { + // summary: + // Maps an html table into a structure parsable for information about cell row and col spanning. + // Used by headerBuilder + constructor: function(inRows){ + this.mapRows(inRows); + }, + + map: null, + + mapRows: function(inRows){ + // summary: Map table topography + + //console.log('mapRows'); + // # of rows + var rowCount = inRows.length; + if(!rowCount){ + return; + } + // map which columns and rows fill which cells + this.map = [ ]; + for(var j=0, row; (row=inRows[j]); j++){ + this.map[j] = []; + } + for(var j=0, row; (row=inRows[j]); j++){ + for(var i=0, x=0, cell, colSpan, rowSpan; (cell=row[i]); i++){ + while (this.map[j][x]){x++}; + this.map[j][x] = { c: i, r: j }; + rowSpan = cell.rowSpan || 1; + colSpan = cell.colSpan || 1; + for(var y=0; y dgdrag.hysteresis; +} + +dgdrag.mousemove = function(inEvent){ + inEvent = dojo.fixEvent(inEvent); + dojo.stopEvent(inEvent); + dgdrag.calcDelta(inEvent); + if((!dgdrag.started)&&(dgdrag.hasMoved(inEvent))){ + dgdrag.events.start(inEvent); + dgdrag.started = true; + } + if(dgdrag.started){ + dgdrag.events.drag(inEvent); + } +} + +dgdrag.mouseup = function(inEvent){ + //console.debug("dojox.grid.drag.mouseup"); + dojo.stopEvent(dojo.fixEvent(inEvent)); + dgdrag.end(); +} + +dgdrag.click = function(inEvent){ + dojo.stopEvent(dojo.fixEvent(inEvent)); + //dgdrag.end(); +} + +})(); +// end closure + +} diff --git a/includes/js/dojox/grid/_grid/edit.js b/includes/js/dojox/grid/_grid/edit.js new file mode 100644 index 0000000..d918423 --- /dev/null +++ b/includes/js/dojox/grid/_grid/edit.js @@ -0,0 +1,238 @@ +if(!dojo._hasResource["dojox.grid._grid.edit"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid._grid.edit"] = true; +dojo.provide("dojox.grid._grid.edit"); + +dojo.declare("dojox.grid.edit", null, { + // summary: + // Controls grid cell editing process. Owned by grid and used internally for editing. + constructor: function(inGrid){ + // inGrid: dojox.Grid + // The dojox.Grid this editor should be attached to + this.grid = inGrid; + this.connections = []; + if(dojo.isIE){ + this.connections.push(dojo.connect(document.body, "onfocus", dojo.hitch(this, "_boomerangFocus"))); + } + }, + + info: {}, + + destroy: function(){ + dojo.forEach(this.connections,dojo.disconnect); + }, + + cellFocus: function(inCell, inRowIndex){ + // summary: + // Invoke editing when cell is focused + // inCell: cell object + // Grid cell object + // inRowIndex: Integer + // Grid row index + if(this.grid.singleClickEdit || this.isEditRow(inRowIndex)){ + // if same row or quick editing, edit + this.setEditCell(inCell, inRowIndex); + }else{ + // otherwise, apply any pending row edits + this.apply(); + } + // if dynamic or static editing... + if(this.isEditing() || (inCell && (inCell.editor||0).alwaysOn)){ + // let the editor focus itself as needed + this._focusEditor(inCell, inRowIndex); + } + }, + + rowClick: function(e){ + if(this.isEditing() && !this.isEditRow(e.rowIndex)){ + this.apply(); + } + }, + + styleRow: function(inRow){ + if(inRow.index == this.info.rowIndex){ + inRow.customClasses += ' dojoxGrid-row-editing'; + } + }, + + dispatchEvent: function(e){ + var c = e.cell, ed = c && c.editor; + return ed && ed.dispatchEvent(e.dispatch, e); + }, + + // Editing + isEditing: function(){ + // summary: + // Indicates editing state of the grid. + // returns: Boolean + // True if grid is actively editing + return this.info.rowIndex !== undefined; + }, + + isEditCell: function(inRowIndex, inCellIndex){ + // summary: + // Indicates if the given cell is being edited. + // inRowIndex: Integer + // Grid row index + // inCellIndex: Integer + // Grid cell index + // returns: Boolean + // True if given cell is being edited + return (this.info.rowIndex === inRowIndex) && (this.info.cell.index == inCellIndex); + }, + + isEditRow: function(inRowIndex){ + // summary: + // Indicates if the given row is being edited. + // inRowIndex: Integer + // Grid row index + // returns: Boolean + // True if given row is being edited + return this.info.rowIndex === inRowIndex; + }, + + setEditCell: function(inCell, inRowIndex){ + // summary: + // Set the given cell to be edited + // inRowIndex: Integer + // Grid row index + // inCell: Object + // Grid cell object + if(!this.isEditCell(inRowIndex, inCell.index) && this.grid.canEdit(inCell, inRowIndex)){ + this.start(inCell, inRowIndex, this.isEditRow(inRowIndex) || inCell.editor); + } + }, + + _focusEditor: function(inCell, inRowIndex){ + dojox.grid.fire(inCell.editor, "focus", [inRowIndex]); + }, + + focusEditor: function(){ + if(this.isEditing()){ + this._focusEditor(this.info.cell, this.info.rowIndex); + } + }, + + // implement fix for focus boomerang effect on IE + _boomerangWindow: 500, + _shouldCatchBoomerang: function(){ + return this._catchBoomerang > new Date().getTime(); + }, + _boomerangFocus: function(){ + //console.log("_boomerangFocus"); + if(this._shouldCatchBoomerang()){ + // make sure we don't utterly lose focus + this.grid.focus.focusGrid(); + // let the editor focus itself as needed + this.focusEditor(); + // only catch once + this._catchBoomerang = 0; + } + }, + _doCatchBoomerang: function(){ + // give ourselves a few ms to boomerang IE focus effects + if(dojo.isIE){this._catchBoomerang = new Date().getTime() + this._boomerangWindow;} + }, + // end boomerang fix API + + start: function(inCell, inRowIndex, inEditing){ + this.grid.beginUpdate(); + this.editorApply(); + if(this.isEditing() && !this.isEditRow(inRowIndex)){ + this.applyRowEdit(); + this.grid.updateRow(inRowIndex); + } + if(inEditing){ + this.info = { cell: inCell, rowIndex: inRowIndex }; + this.grid.doStartEdit(inCell, inRowIndex); + this.grid.updateRow(inRowIndex); + }else{ + this.info = {}; + } + this.grid.endUpdate(); + // make sure we don't utterly lose focus + this.grid.focus.focusGrid(); + // let the editor focus itself as needed + this._focusEditor(inCell, inRowIndex); + // give ourselves a few ms to boomerang IE focus effects + this._doCatchBoomerang(); + }, + + _editorDo: function(inMethod){ + var c = this.info.cell + //c && c.editor && c.editor[inMethod](c, this.info.rowIndex); + c && c.editor && c.editor[inMethod](this.info.rowIndex); + }, + + editorApply: function(){ + this._editorDo("apply"); + }, + + editorCancel: function(){ + this._editorDo("cancel"); + }, + + applyCellEdit: function(inValue, inCell, inRowIndex){ + if(this.grid.canEdit(inCell, inRowIndex)){ + this.grid.doApplyCellEdit(inValue, inRowIndex, inCell.fieldIndex); + } + }, + + applyRowEdit: function(){ + this.grid.doApplyEdit(this.info.rowIndex); + }, + + apply: function(){ + // summary: + // Apply a grid edit + if(this.isEditing()){ + this.grid.beginUpdate(); + this.editorApply(); + this.applyRowEdit(); + this.info = {}; + this.grid.endUpdate(); + this.grid.focus.focusGrid(); + this._doCatchBoomerang(); + } + }, + + cancel: function(){ + // summary: + // Cancel a grid edit + if(this.isEditing()){ + this.grid.beginUpdate(); + this.editorCancel(); + this.info = {}; + this.grid.endUpdate(); + this.grid.focus.focusGrid(); + this._doCatchBoomerang(); + } + }, + + save: function(inRowIndex, inView){ + // summary: + // Save the grid editing state + // inRowIndex: Integer + // Grid row index + // inView: Object + // Grid view + var c = this.info.cell; + if(this.isEditRow(inRowIndex) && (!inView || c.view==inView) && c.editor){ + c.editor.save(c, this.info.rowIndex); + } + }, + + restore: function(inView, inRowIndex){ + // summary: + // Restores the grid editing state + // inRowIndex: Integer + // Grid row index + // inView: Object + // Grid view + var c = this.info.cell; + if(this.isEditRow(inRowIndex) && c.view == inView && c.editor){ + c.editor.restore(c, this.info.rowIndex); + } + } +}); + +} diff --git a/includes/js/dojox/grid/_grid/focus.js b/includes/js/dojox/grid/_grid/focus.js new file mode 100644 index 0000000..8761042 --- /dev/null +++ b/includes/js/dojox/grid/_grid/focus.js @@ -0,0 +1,207 @@ +if(!dojo._hasResource["dojox.grid._grid.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid._grid.focus"] = true; +dojo.provide("dojox.grid._grid.focus"); + +// focus management +dojo.declare("dojox.grid.focus", null, { + // summary: + // Controls grid cell focus. Owned by grid and used internally for focusing. + // Note: grid cell actually receives keyboard input only when cell is being edited. + constructor: function(inGrid){ + this.grid = inGrid; + this.cell = null; + this.rowIndex = -1; + dojo.connect(this.grid.domNode, "onfocus", this, "doFocus"); + }, + tabbingOut: false, + focusClass: "dojoxGrid-cell-focus", + focusView: null, + initFocusView: function(){ + this.focusView = this.grid.views.getFirstScrollingView(); + }, + isFocusCell: function(inCell, inRowIndex){ + // summary: + // states if the given cell is focused + // inCell: object + // grid cell object + // inRowIndex: int + // grid row index + // returns: + // true of the given grid cell is focused + return (this.cell == inCell) && (this.rowIndex == inRowIndex); + }, + isLastFocusCell: function(){ + return (this.rowIndex == this.grid.rowCount-1) && (this.cell.index == this.grid.layout.cellCount-1); + }, + isFirstFocusCell: function(){ + return (this.rowIndex == 0) && (this.cell.index == 0); + }, + isNoFocusCell: function(){ + return (this.rowIndex < 0) || !this.cell; + }, + _focusifyCellNode: function(inBork){ + var n = this.cell && this.cell.getNode(this.rowIndex); + if(n){ + dojo.toggleClass(n, this.focusClass, inBork); + if (inBork){ + this.scrollIntoView(); + try{ + if(!this.grid.edit.isEditing()) + dojox.grid.fire(n, "focus"); + }catch(e){} + } + } + }, + scrollIntoView: function() { + if(!this.cell){ + return; + } + var + c = this.cell, + s = c.view.scrollboxNode, + sr = { + w: s.clientWidth, + l: s.scrollLeft, + t: s.scrollTop, + h: s.clientHeight + }, + n = c.getNode(this.rowIndex), + r = c.view.getRowNode(this.rowIndex), + rt = this.grid.scroller.findScrollTop(this.rowIndex); + // place cell within horizontal view + if(n.offsetLeft + n.offsetWidth > sr.l + sr.w){ + s.scrollLeft = n.offsetLeft + n.offsetWidth - sr.w; + }else if(n.offsetLeft < sr.l){ + s.scrollLeft = n.offsetLeft; + } + // place cell within vertical view + if(rt + r.offsetHeight > sr.t + sr.h){ + this.grid.setScrollTop(rt + r.offsetHeight - sr.h); + }else if(rt < sr.t){ + this.grid.setScrollTop(rt); + } + }, + styleRow: function(inRow){ + return; + }, + setFocusIndex: function(inRowIndex, inCellIndex){ + // summary: + // focuses the given grid cell + // inRowIndex: int + // grid row index + // inCellIndex: int + // grid cell index + this.setFocusCell(this.grid.getCell(inCellIndex), inRowIndex); + }, + setFocusCell: function(inCell, inRowIndex){ + // summary: + // focuses the given grid cell + // inCell: object + // grid cell object + // inRowIndex: int + // grid row index + if(inCell && !this.isFocusCell(inCell, inRowIndex)){ + this.tabbingOut = false; + this.focusGridView(); + this._focusifyCellNode(false); + this.cell = inCell; + this.rowIndex = inRowIndex; + this._focusifyCellNode(true); + } + // even if this cell isFocusCell, the document focus may need to be rejiggered + // call opera on delay to prevent keypress from altering focus + if(dojo.isOpera){ + setTimeout(dojo.hitch(this.grid, 'onCellFocus', this.cell, this.rowIndex), 1); + }else{ + this.grid.onCellFocus(this.cell, this.rowIndex); + } + }, + next: function(){ + // summary: + // focus next grid cell + var row=this.rowIndex, col=this.cell.index+1, cc=this.grid.layout.cellCount-1, rc=this.grid.rowCount-1; + if(col > cc){ + col = 0; + row++; + } + if(row > rc){ + col = cc; + row = rc; + } + this.setFocusIndex(row, col); + }, + previous: function(){ + // summary: + // focus previous grid cell + var row=(this.rowIndex || 0), col=(this.cell.index || 0) - 1; + if(col < 0){ + col = this.grid.layout.cellCount-1; + row--; + } + if(row < 0){ + row = 0; + col = 0; + } + this.setFocusIndex(row, col); + }, + move: function(inRowDelta, inColDelta) { + // summary: + // focus grid cell based on position relative to current focus + // inRowDelta: int + // vertical distance from current focus + // inColDelta: int + // horizontal distance from current focus + var + rc = this.grid.rowCount-1, + cc = this.grid.layout.cellCount-1, + r = this.rowIndex, + i = this.cell.index, + row = Math.min(rc, Math.max(0, r+inRowDelta)), + col = Math.min(cc, Math.max(0, i+inColDelta)); + this.setFocusIndex(row, col); + if(inRowDelta){ + this.grid.updateRow(r); + } + }, + previousKey: function(e){ + if(this.isFirstFocusCell()){ + this.tabOut(this.grid.domNode); + }else{ + dojo.stopEvent(e); + this.previous(); + } + }, + nextKey: function(e) { + if(this.isLastFocusCell()){ + this.tabOut(this.grid.lastFocusNode); + }else{ + dojo.stopEvent(e); + this.next(); + } + }, + tabOut: function(inFocusNode){ + this.tabbingOut = true; + inFocusNode.focus(); + }, + focusGridView: function(){ + dojox.grid.fire(this.focusView, "focus"); + }, + focusGrid: function(inSkipFocusCell){ + this.focusGridView(); + this._focusifyCellNode(true); + }, + doFocus: function(e){ + // trap focus only for grid dom node + if(e && e.target != e.currentTarget){ + return; + } + // do not focus for scrolling if grid is about to blur + if(!this.tabbingOut && this.isNoFocusCell()){ + // establish our virtual-focus, if necessary + this.setFocusIndex(0, 0); + } + this.tabbingOut = false; + } +}); + +} diff --git a/includes/js/dojox/grid/_grid/images/grid_dx_gradient.gif b/includes/js/dojox/grid/_grid/images/grid_dx_gradient.gif new file mode 100644 index 0000000..57f67ba Binary files /dev/null and b/includes/js/dojox/grid/_grid/images/grid_dx_gradient.gif differ diff --git a/includes/js/dojox/grid/_grid/images/grid_sort_down.gif b/includes/js/dojox/grid/_grid/images/grid_sort_down.gif new file mode 100644 index 0000000..7a73f82 Binary files /dev/null and b/includes/js/dojox/grid/_grid/images/grid_sort_down.gif differ diff --git a/includes/js/dojox/grid/_grid/images/grid_sort_up.gif b/includes/js/dojox/grid/_grid/images/grid_sort_up.gif new file mode 100644 index 0000000..9452da0 Binary files /dev/null and b/includes/js/dojox/grid/_grid/images/grid_sort_up.gif differ diff --git a/includes/js/dojox/grid/_grid/images/tabEnabled_rotated.png b/includes/js/dojox/grid/_grid/images/tabEnabled_rotated.png new file mode 100644 index 0000000..e326abd Binary files /dev/null and b/includes/js/dojox/grid/_grid/images/tabEnabled_rotated.png differ diff --git a/includes/js/dojox/grid/_grid/images/tabHover_rotated.png b/includes/js/dojox/grid/_grid/images/tabHover_rotated.png new file mode 100644 index 0000000..1a30e10 Binary files /dev/null and b/includes/js/dojox/grid/_grid/images/tabHover_rotated.png differ diff --git a/includes/js/dojox/grid/_grid/layout.js b/includes/js/dojox/grid/_grid/layout.js new file mode 100644 index 0000000..128f486 --- /dev/null +++ b/includes/js/dojox/grid/_grid/layout.js @@ -0,0 +1,75 @@ +if(!dojo._hasResource["dojox.grid._grid.layout"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid._grid.layout"] = true; +dojo.provide("dojox.grid._grid.layout"); +dojo.require("dojox.grid._grid.cell"); + +dojo.declare("dojox.grid.layout", null, { + // summary: + // Controls grid cell layout. Owned by grid and used internally. + constructor: function(inGrid){ + this.grid = inGrid; + }, + // flat array of grid cells + cells: [], + // structured array of grid cells + structure: null, + // default cell width + defaultWidth: '6em', + // methods + setStructure: function(inStructure){ + this.fieldIndex = 0; + this.cells = []; + var s = this.structure = []; + for(var i=0, viewDef, rows; (viewDef=inStructure[i]); i++){ + s.push(this.addViewDef(viewDef)); + } + this.cellCount = this.cells.length; + }, + addViewDef: function(inDef){ + this._defaultCellProps = inDef.defaultCell || {}; + return dojo.mixin({}, inDef, {rows: this.addRowsDef(inDef.rows || inDef.cells)}); + }, + addRowsDef: function(inDef){ + var result = []; + for(var i=0, row; inDef && (row=inDef[i]); i++){ + result.push(this.addRowDef(i, row)); + } + return result; + }, + addRowDef: function(inRowIndex, inDef){ + var result = []; + for(var i=0, def, cell; (def=inDef[i]); i++){ + cell = this.addCellDef(inRowIndex, i, def); + result.push(cell); + this.cells.push(cell); + } + return result; + }, + addCellDef: function(inRowIndex, inCellIndex, inDef){ + var w = 0; + if(inDef.colSpan > 1){ + w = 0; + }else if(!isNaN(inDef.width)){ + w = inDef.width + "em"; + }else{ + w = inDef.width || this.defaultWidth; + } + // fieldIndex progresses linearly from the last indexed field + // FIXME: support generating fieldIndex based a text field name (probably in Grid) + var fieldIndex = inDef.field != undefined ? inDef.field : (inDef.get ? -1 : this.fieldIndex); + if((inDef.field != undefined) || !inDef.get){ + this.fieldIndex = (inDef.field > -1 ? inDef.field : this.fieldIndex) + 1; + } + return new dojox.grid.cell( + dojo.mixin({}, this._defaultCellProps, inDef, { + grid: this.grid, + subrow: inRowIndex, + layoutIndex: inCellIndex, + index: this.cells.length, + fieldIndex: fieldIndex, + unitWidth: w + })); + } +}); + +} diff --git a/includes/js/dojox/grid/_grid/lib.js b/includes/js/dojox/grid/_grid/lib.js new file mode 100644 index 0000000..3644dbc --- /dev/null +++ b/includes/js/dojox/grid/_grid/lib.js @@ -0,0 +1,254 @@ +if(!dojo._hasResource["dojox.grid._grid.lib"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid._grid.lib"] = true; +dojo.provide("dojox.grid._grid.lib"); +// summary: grid utility library +dojo.mixin(dojox.grid,{ + + na: '...', + + nop: function(){ + // summary: a null function? + }, + + getTdIndex: function(td){ + return td.cellIndex >=0 ? td.cellIndex : dojo.indexOf(td.parentNode.cells, td); + }, + + getTrIndex: function(tr){ + return tr.rowIndex >=0 ? tr.rowIndex : dojo.indexOf(tr.parentNode.childNodes, tr); + }, + + getTr: function(rowOwner, index){ + return rowOwner && ((rowOwner.rows||0)[index] || rowOwner.childNodes[index]); + }, + + getTd: function(rowOwner, rowIndex, cellIndex){ + return (dojox.grid.getTr(inTable, rowIndex)||0)[cellIndex]; + }, + + findTable: function(node){ + for (var n=node; n && n.tagName!='TABLE'; n=n.parentNode); + return n; + }, + + ascendDom: function(inNode, inWhile){ + for (var n=inNode; n && inWhile(n); n=n.parentNode); + return n; + }, + + makeNotTagName: function(inTagName){ + var name = inTagName.toUpperCase(); + return function(node){ return node.tagName != name; }; + }, + + fire: function(ob, ev, args){ + var fn = ob && ev && ob[ev]; + return fn && (args ? fn.apply(ob, args) : ob[ev]()); + }, + + // from lib.js + setStyleText: function(inNode, inStyleText){ + if(inNode.style.cssText == undefined){ + inNode.setAttribute("style", inStyleText); + }else{ + inNode.style.cssText = inStyleText; + } + }, + + getStyleText: function(inNode, inStyleText){ + return (inNode.style.cssText == undefined ? inNode.getAttribute("style") : inNode.style.cssText); + }, + + setStyle: function(inElement, inStyle, inValue){ + if(inElement && inElement.style[inStyle] != inValue){ + inElement.style[inStyle] = inValue; + } + }, + + setStyleHeightPx: function(inElement, inHeight){ + if(inHeight >= 0){ + dojox.grid.setStyle(inElement, 'height', inHeight + 'px'); + } + }, + + mouseEvents: [ 'mouseover', 'mouseout', /*'mousemove',*/ 'mousedown', 'mouseup', 'click', 'dblclick', 'contextmenu' ], + + keyEvents: [ 'keyup', 'keydown', 'keypress' ], + + funnelEvents: function(inNode, inObject, inMethod, inEvents){ + var evts = (inEvents ? inEvents : dojox.grid.mouseEvents.concat(dojox.grid.keyEvents)); + for (var i=0, l=evts.length; i'; + }, + renderHeader: function(){ + }, + resize: function(){ + this.adaptHeight(); + }, + adaptWidth: function(){ + }, + // styling + doStyleRowNode: function(inRowIndex, inRowNode){ + var n = [ "dojoxGrid-rowbar" ]; + if(this.grid.rows.isOver(inRowIndex)){ + n.push("dojoxGrid-rowbar-over"); + } + if(this.grid.selection.isSelected(inRowIndex)){ + n.push("dojoxGrid-rowbar-selected"); + } + inRowNode.className = n.join(" "); + }, + // event handlers + domouseover: function(e){ + this.grid.onMouseOverRow(e); + }, + domouseout: function(e){ + if(!this.isIntraRowEvent(e)){ + this.grid.onMouseOutRow(e); + } + } +}); + +} diff --git a/includes/js/dojox/grid/_grid/rows.js b/includes/js/dojox/grid/_grid/rows.js new file mode 100644 index 0000000..37ecbcb --- /dev/null +++ b/includes/js/dojox/grid/_grid/rows.js @@ -0,0 +1,66 @@ +if(!dojo._hasResource["dojox.grid._grid.rows"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid._grid.rows"] = true; +dojo.provide("dojox.grid._grid.rows"); + +dojo.declare("dojox.grid.rows", null, { + // Stores information about grid rows. Owned by grid and used internally. + constructor: function(inGrid){ + this.grid = inGrid; + }, + linesToEms: 2, + defaultRowHeight: 1, // lines + overRow: -2, + // metrics + getHeight: function(inRowIndex){ + return ''; + }, + getDefaultHeightPx: function(){ + // summmary: + // retrieves the default row height + // returns: int, default row height + return 32; + //return Math.round(this.defaultRowHeight * this.linesToEms * this.grid.contentPixelToEmRatio); + }, + // styles + prepareStylingRow: function(inRowIndex, inRowNode){ + return { + index: inRowIndex, + node: inRowNode, + odd: Boolean(inRowIndex&1), + selected: this.grid.selection.isSelected(inRowIndex), + over: this.isOver(inRowIndex), + customStyles: "", + customClasses: "dojoxGrid-row" + } + }, + styleRowNode: function(inRowIndex, inRowNode){ + var row = this.prepareStylingRow(inRowIndex, inRowNode); + this.grid.onStyleRow(row); + this.applyStyles(row); + }, + applyStyles: function(inRow){ + with(inRow){ + node.className = customClasses; + var h = node.style.height; + dojox.grid.setStyleText(node, customStyles + ';' + (node._style||'')); + node.style.height = h; + } + }, + updateStyles: function(inRowIndex){ + this.grid.updateRowStyles(inRowIndex); + }, + // states and events + setOverRow: function(inRowIndex){ + var last = this.overRow; + this.overRow = inRowIndex; + if((last!=this.overRow)&&(last >=0)){ + this.updateStyles(last); + } + this.updateStyles(this.overRow); + }, + isOver: function(inRowIndex){ + return (this.overRow == inRowIndex); + } +}); + +} diff --git a/includes/js/dojox/grid/_grid/scroller.js b/includes/js/dojox/grid/_grid/scroller.js new file mode 100644 index 0000000..d331367 --- /dev/null +++ b/includes/js/dojox/grid/_grid/scroller.js @@ -0,0 +1,489 @@ +if(!dojo._hasResource['dojox.grid._grid.scroller']){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource['dojox.grid._grid.scroller'] = true; +dojo.provide('dojox.grid._grid.scroller'); + +dojo.declare('dojox.grid.scroller.base', null, { + // summary: + // virtual scrollbox, abstract class + // Content must in /rows/ + // Rows are managed in contiguous sets called /pages/ + // There are a fixed # of rows per page + // The minimum rendered unit is a page + constructor: function(){ + this.pageHeights = []; + this.stack = []; + }, + // specified + rowCount: 0, // total number of rows to manage + defaultRowHeight: 10, // default height of a row + keepRows: 100, // maximum number of rows that should exist at one time + contentNode: null, // node to contain pages + scrollboxNode: null, // node that controls scrolling + // calculated + defaultPageHeight: 0, // default height of a page + keepPages: 10, // maximum number of pages that should exists at one time + pageCount: 0, + windowHeight: 0, + firstVisibleRow: 0, + lastVisibleRow: 0, + // private + page: 0, + pageTop: 0, + // init + init: function(inRowCount, inKeepRows, inRowsPerPage){ + switch(arguments.length){ + case 3: this.rowsPerPage = inRowsPerPage; + case 2: this.keepRows = inKeepRows; + case 1: this.rowCount = inRowCount; + } + this.defaultPageHeight = this.defaultRowHeight * this.rowsPerPage; + //this.defaultPageHeight = this.defaultRowHeight * Math.min(this.rowsPerPage, this.rowCount); + this.pageCount = Math.ceil(this.rowCount / this.rowsPerPage); + this.setKeepInfo(this.keepRows); + this.invalidate(); + if(this.scrollboxNode){ + this.scrollboxNode.scrollTop = 0; + this.scroll(0); + this.scrollboxNode.onscroll = dojo.hitch(this, 'onscroll'); + } + }, + setKeepInfo: function(inKeepRows){ + this.keepRows = inKeepRows; + this.keepPages = !this.keepRows ? this.keepRows : Math.max(Math.ceil(this.keepRows / this.rowsPerPage), 2); + }, + // updating + invalidate: function(){ + this.invalidateNodes(); + this.pageHeights = []; + this.height = (this.pageCount ? (this.pageCount - 1)* this.defaultPageHeight + this.calcLastPageHeight() : 0); + this.resize(); + }, + updateRowCount: function(inRowCount){ + this.invalidateNodes(); + this.rowCount = inRowCount; + // update page count, adjust document height + oldPageCount = this.pageCount; + this.pageCount = Math.ceil(this.rowCount / this.rowsPerPage); + if(this.pageCount < oldPageCount){ + for(var i=oldPageCount-1; i>=this.pageCount; i--){ + this.height -= this.getPageHeight(i); + delete this.pageHeights[i] + } + }else if(this.pageCount > oldPageCount){ + this.height += this.defaultPageHeight * (this.pageCount - oldPageCount - 1) + this.calcLastPageHeight(); + } + this.resize(); + }, + // abstract interface + pageExists: function(inPageIndex){ + }, + measurePage: function(inPageIndex){ + }, + positionPage: function(inPageIndex, inPos){ + }, + repositionPages: function(inPageIndex){ + }, + installPage: function(inPageIndex){ + }, + preparePage: function(inPageIndex, inPos, inReuseNode){ + }, + renderPage: function(inPageIndex){ + }, + removePage: function(inPageIndex){ + }, + pacify: function(inShouldPacify){ + }, + // pacification + pacifying: false, + pacifyTicks: 200, + setPacifying: function(inPacifying){ + if(this.pacifying != inPacifying){ + this.pacifying = inPacifying; + this.pacify(this.pacifying); + } + }, + startPacify: function(){ + this.startPacifyTicks = new Date().getTime(); + }, + doPacify: function(){ + var result = (new Date().getTime() - this.startPacifyTicks) > this.pacifyTicks; + this.setPacifying(true); + this.startPacify(); + return result; + }, + endPacify: function(){ + this.setPacifying(false); + }, + // default sizing implementation + resize: function(){ + if(this.scrollboxNode){ + this.windowHeight = this.scrollboxNode.clientHeight; + } + dojox.grid.setStyleHeightPx(this.contentNode, this.height); + }, + calcLastPageHeight: function(){ + if(!this.pageCount){ + return 0; + } + var lastPage = this.pageCount - 1; + var lastPageHeight = ((this.rowCount % this.rowsPerPage)||(this.rowsPerPage)) * this.defaultRowHeight; + this.pageHeights[lastPage] = lastPageHeight; + return lastPageHeight; + }, + updateContentHeight: function(inDh){ + this.height += inDh; + this.resize(); + }, + updatePageHeight: function(inPageIndex){ + if(this.pageExists(inPageIndex)){ + var oh = this.getPageHeight(inPageIndex); + var h = (this.measurePage(inPageIndex))||(oh); + this.pageHeights[inPageIndex] = h; + if((h)&&(oh != h)){ + this.updateContentHeight(h - oh) + this.repositionPages(inPageIndex); + } + } + }, + rowHeightChanged: function(inRowIndex){ + this.updatePageHeight(Math.floor(inRowIndex / this.rowsPerPage)); + }, + // scroller core + invalidateNodes: function(){ + while(this.stack.length){ + this.destroyPage(this.popPage()); + } + }, + createPageNode: function(){ + var p = document.createElement('div'); + p.style.position = 'absolute'; + //p.style.width = '100%'; + p.style[dojo._isBodyLtr() ? "left" : "right"] = '0'; + return p; + }, + getPageHeight: function(inPageIndex){ + var ph = this.pageHeights[inPageIndex]; + return (ph !== undefined ? ph : this.defaultPageHeight); + }, + // FIXME: this is not a stack, it's a FIFO list + pushPage: function(inPageIndex){ + return this.stack.push(inPageIndex); + }, + popPage: function(){ + return this.stack.shift(); + }, + findPage: function(inTop){ + var i = 0, h = 0; + for(var ph = 0; i= inTop){ + break; + } + } + this.page = i; + this.pageTop = h; + }, + buildPage: function(inPageIndex, inReuseNode, inPos){ + this.preparePage(inPageIndex, inReuseNode); + this.positionPage(inPageIndex, inPos); + // order of operations is key below + this.installPage(inPageIndex); + this.renderPage(inPageIndex); + // order of operations is key above + this.pushPage(inPageIndex); + }, + needPage: function(inPageIndex, inPos){ + var h = this.getPageHeight(inPageIndex), oh = h; + if(!this.pageExists(inPageIndex)){ + this.buildPage(inPageIndex, this.keepPages&&(this.stack.length >= this.keepPages), inPos); + h = this.measurePage(inPageIndex) || h; + this.pageHeights[inPageIndex] = h; + if(h && (oh != h)){ + this.updateContentHeight(h - oh) + } + }else{ + this.positionPage(inPageIndex, inPos); + } + return h; + }, + onscroll: function(){ + this.scroll(this.scrollboxNode.scrollTop); + }, + scroll: function(inTop){ + this.startPacify(); + this.findPage(inTop); + var h = this.height; + var b = this.getScrollBottom(inTop); + for(var p=this.page, y=this.pageTop; (p= 0 ? inTop + this.windowHeight : -1); + }, + // events + processNodeEvent: function(e, inNode){ + var t = e.target; + while(t && (t != inNode) && t.parentNode && (t.parentNode.parentNode != inNode)){ + t = t.parentNode; + } + if(!t || !t.parentNode || (t.parentNode.parentNode != inNode)){ + return false; + } + var page = t.parentNode; + e.topRowIndex = page.pageIndex * this.rowsPerPage; + e.rowIndex = e.topRowIndex + dojox.grid.indexInParent(t); + e.rowTarget = t; + return true; + }, + processEvent: function(e){ + return this.processNodeEvent(e, this.contentNode); + }, + dummy: 0 +}); + +dojo.declare('dojox.grid.scroller', dojox.grid.scroller.base, { + // summary: + // virtual scroller class, makes no assumption about shape of items being scrolled + constructor: function(){ + this.pageNodes = []; + }, + // virtual rendering interface + renderRow: function(inRowIndex, inPageNode){ + }, + removeRow: function(inRowIndex){ + }, + // page node operations + getDefaultNodes: function(){ + return this.pageNodes; + }, + getDefaultPageNode: function(inPageIndex){ + return this.getDefaultNodes()[inPageIndex]; + }, + positionPageNode: function(inNode, inPos){ + inNode.style.top = inPos + 'px'; + }, + getPageNodePosition: function(inNode){ + return inNode.offsetTop; + }, + repositionPageNodes: function(inPageIndex, inNodes){ + var last = 0; + for(var i=0; i=0 && inBottom>inScrollBottom; i--, row--){ + inBottom -= rows[i].offsetHeight; + } + return row + 1; + }, + getLastVisibleRow: function(inPage, inBottom, inScrollBottom){ + if(!this.pageExists(inPage)){ + return 0; + } + return this.getLastVisibleRowNodes(inPage, inBottom, inScrollBottom, this.getDefaultNodes()); + }, + findTopRowForNodes: function(inScrollTop, inNodes){ + var rows = dojox.grid.divkids(inNodes[this.page]); + for(var i=0,l=rows.length,t=this.pageTop,h; i= inScrollTop){ + this.offset = h - (t - inScrollTop); + return i + this.page * this.rowsPerPage; + } + } + return -1; + }, + findScrollTopForNodes: function(inRow, inNodes){ + var rowPage = Math.floor(inRow / this.rowsPerPage); + var t = 0; + for(var i=0; i= inIndex){ + this.selectedIndex++; + } + }, + + remove: function(inIndex){ + this.selected.splice(inIndex, 1); + if(this.selectedIndex >= inIndex){ + this.selectedIndex--; + } + }, + + unselectAll: function(inExcept){ + for(var i in this.selected){ + if((i!=inExcept)&&(this.selected[i]===true)){ + this.deselect(i); + } + } + }, + + shiftSelect: function(inFrom, inTo){ + var s = (inFrom >= 0 ? inFrom : inTo), e = inTo; + if(s > e){ + e = s; + s = inTo; + } + for(var i=s; i<=e; i++){ + this.addToSelection(i); + } + }, + + clickSelect: function(inIndex, inCtrlKey, inShiftKey){ + this.beginUpdate(); + if(!this.multiSelect){ + this.select(inIndex); + }else{ + var lastSelected = this.selectedIndex; + if(!inCtrlKey){ + this.unselectAll(inIndex); + } + if(inShiftKey){ + this.shiftSelect(lastSelected, inIndex); + }else if(inCtrlKey){ + this.toggleSelect(inIndex); + }else{ + this.addToSelection(inIndex) + } + } + this.endUpdate(); + }, + + clickSelectEvent: function(e){ + this.clickSelect(e.rowIndex, e.ctrlKey, e.shiftKey); + }, + + clear: function(){ + this.beginUpdate(); + this.unselectAll(); + this.endUpdate(); + } + +}); + +} diff --git a/includes/js/dojox/grid/_grid/soriaGrid.css b/includes/js/dojox/grid/_grid/soriaGrid.css new file mode 100644 index 0000000..f244030 --- /dev/null +++ b/includes/js/dojox/grid/_grid/soriaGrid.css @@ -0,0 +1,212 @@ +.soria .dojoxGrid { + position: relative; + background-color: #e9e9e9; + font-size: 0.85em; + -moz-outline-style: none; + outline: none; + overflow: hidden; + height: 0; +} +.soria .dojoxGrid table { + padding: 0; +} +.soria .dojoxGrid td { + -moz-outline: none; +} +.soria .dojoxGrid-master-header { + position: relative; +} +.soria .dojoxGrid-master-view { + position: relative; +} +.soria .dojoxGrid-view { + position: absolute; + overflow: hidden; +} +.soria .dojoxGrid-header { + position: absolute; + overflow: hidden; +} +.soria .dojoxGrid-header { + background-color: #e9e9e9; +} +.soria .dojoxGrid-header table { + text-align: center; +} +.soria .dojoxGrid-header .dojoxGrid-cell-content { + text-align: center; +} +.soria .dojoxGrid-header .dojoxGrid-cell { + border: 1px solid transparent; + + border-color: white #ACA899 #919191 white; + background: url(../../../dijit/themes/soria/images/titleBar.png) #e9e9e9 repeat-x top; + padding-bottom: 2px; + color: #000 !important; +} +.soria .dojoxGrid-header .dojoxGrid-cell-over { + background: url(../../../dijit/themes/soria/images/titleBarActive.png) #e9e9e9 repeat-x top; +} +.soria .dojoxGrid-sort-down { + background: url(images/grid_sort_down.gif) right no-repeat; + padding-left: 0px; + margin-left: 0px; +} +.soria .dojoxGrid-sort-up { + background: url(images/grid_sort_up.gif) right no-repeat; + padding-left: 0px; + margin-left: 0px; +} +.soria .gridArrowButtonChar { + display:none !important; +} +.dijit_a11y .gridArrowButtonChar { + display:inline !important; +} +.soria .dojoxGrid-scrollbox { + position: relative; + overflow: scroll; + background-color: #fefefe; + width: 100%; +} +.soria .dojoxGrid-content { + position: relative; + overflow: hidden; + -moz-outline-style: none; + outline: none; +} +.soria .dojoxGrid-rowbar { + border: none; + + background: url(images/titleBar.png) #e9e9e9 repeat-y right; + border-right: 1px solid #cccccc; + padding: 0px; +} +.soria .dojoxGrid-rowbar-inner { + border: none; + border-bottom: 1px solid #cccccc; +} +.soria .dojoxGrid-rowbar-over { + background: url(images/titleBarActive.png) #e9e9e9 repeat-y right; +} +.soria .dojoxGrid-rowbar-selected { + background-color: #D9E8F9; + background-image: none; + background: url(../../../dijit/themes/soria/images/titleBar.png) #dddddd repeat-x top; + border-right: 1px solid #cccccc; + background-position: center; + background-repeat: no-repeat; +} +.soria .dojoxGrid-row { + position: relative; + width: 9000em; +} +.soria .dojoxGrid-row { + border: none; + border-left: none; + border-right: none; + background-color: white; + border-top: none; +} +.soria .dojoxGrid-row-over { + border-top-color: #cccccc; + border-bottom-color: #cccccc; +} +.soria .dojoxGrid-row-over .dojoxGrid-cell { + background-color: #60a1ea; + color:#fff; +} +.soria .dojoxGrid-row-odd { + background-color: #f2f5f9; + +} +.soria .dojoxGrid-row-selected { + background-color: #aec7e3; +} +.soria .dojoxGrid-row-table { + table-layout: fixed; + width: 0; + border-collapse: collapse; +} +.soria .dojoxGrid-invisible { + visibility: hidden; +} +.soria .Xdojo-ie .dojoxGrid-invisible { + display: none; +} +.soria .dojoxGrid-invisible td, .dojoxGrid-header .dojoxGrid-invisible td { + border-top-width: 0; + border-bottom-width: 0; + padding-top: 0; + padding-bottom: 0; + height: 0; + overflow: hidden; +} +.soria .dojoxGrid-cell { + border: 1px dotted #D5CDB5; + padding: 3px 3px 3px 3px; + text-align: left; + overflow: hidden; +} +.dj_ie6 .soria .dojoxGrid-cell { + border: 1px solid white; + border-right: 1px solid #D5CDB5; +} +.soria .dojoxGrid-cell-focus { + border: 1px dotted #a6a6a6; +} +.soria .dojoxGrid-cell-over { + border: 1px dotted #a6a6a6; +} +.soria .dojoxGrid-cell-focus.dojoxGrid-cell-over { + border: 1px dotted #595959; +} +.soria .dojoxGrid-cell-clip { + width: 100%; + overflow: hidden; + white-space:nowrap; + text-overflow: ellipsis; +} +.soria .dojoxGrid-row-editing td { + + background-color: #60a1ea; + +} +.soria .dojoxGrid-row-inserting td { + background-color: #F4FFF4; +} +.soria .dojoxGrid-row-inflight td { + background-color: #F2F7B7; +} +.soria .dojoxGrid-row-error td { + background-color: #F8B8B6; +} +.soria .dojoxGrid-input, +.soria .dojoxGrid-select, +.soria .dojoxGrid-textarea { + margin: 0; + padding: 0px; + border-style: none; + width: 100%; + font-size: 100%; + font-family: inherit; +} +.dojoxGrid-hidden-focus { + position: absolute; + left: -1000px; + top: -1000px; + height: 0px, width: 0px; +} +.dijit_a11y .dojoxGrid-rowbar-selected { + border-top: 1px solid white; + border-bottom: 1px dashed black; + border-top: 0; + background: none; +} +.dijit_a11y .dojoxGrid-rowbar-selected .dojoxGrid-rowbar-inner { + border: 0; + border-top: 1px solid white; +} +.dijit_a11y .dojoxGrid-row-selected { + border-bottom: 1px dashed black; +} diff --git a/includes/js/dojox/grid/_grid/soriaGrid.css.commented.css b/includes/js/dojox/grid/_grid/soriaGrid.css.commented.css new file mode 100644 index 0000000..06263ad --- /dev/null +++ b/includes/js/dojox/grid/_grid/soriaGrid.css.commented.css @@ -0,0 +1,276 @@ +.soria .dojoxGrid { + position: relative; + background-color: #e9e9e9; + font-size: 0.85em; /* inherit font-family from dojo.css */ + -moz-outline-style: none; + outline: none; + overflow: hidden; + height: 0; +} + +.soria .dojoxGrid table { + padding: 0; +} + +.soria .dojoxGrid td { + -moz-outline: none; +} + +/* master header */ + +.soria .dojoxGrid-master-header { + position: relative; +} + +/* master view */ + +.soria .dojoxGrid-master-view { + position: relative; +} + +/* views */ + +.soria .dojoxGrid-view { + position: absolute; + overflow: hidden; +} + +/* header */ + +.soria .dojoxGrid-header { + position: absolute; + overflow: hidden; +} + +.soria .dojoxGrid-header { + background-color: #e9e9e9; +} + +.soria .dojoxGrid-header table { + text-align: center; +} + +.soria .dojoxGrid-header .dojoxGrid-cell-content { + text-align: center; +} + +.soria .dojoxGrid-header .dojoxGrid-cell { + border: 1px solid transparent; + /* border-color: #F6F4EB #ACA899 #ACA899 #F6F4EB; */ + border-color: white #ACA899 #919191 white; + background: url(../../../dijit/themes/soria/images/titleBar.png) #e9e9e9 repeat-x top; + padding-bottom: 2px; + color: #000 !important; +} + +.soria .dojoxGrid-header .dojoxGrid-cell-over { + background: url(../../../dijit/themes/soria/images/titleBarActive.png) #e9e9e9 repeat-x top; +} + +.soria .dojoxGrid-sort-down { + background: url(images/grid_sort_down.gif) right no-repeat; + padding-left: 0px; + margin-left: 0px; +} + +.soria .dojoxGrid-sort-up { + background: url(images/grid_sort_up.gif) right no-repeat; + padding-left: 0px; + margin-left: 0px; +} + +.soria .gridArrowButtonChar { + display:none !important; +} +.dijit_a11y .gridArrowButtonChar { + display:inline !important; +} + +/* content */ + +.soria .dojoxGrid-scrollbox { + position: relative; + overflow: scroll; + background-color: #fefefe; + width: 100%; +} + +.soria .dojoxGrid-content { + position: relative; + overflow: hidden; + -moz-outline-style: none; + outline: none; +} + +/* rowbar */ + +.soria .dojoxGrid-rowbar { + border: none; + /* + border-color: #F6F4EB #ACA899 #ACA899 #F6F4EB; + */ + background: url(images/titleBar.png) #e9e9e9 repeat-y right; + border-right: 1px solid #cccccc; + padding: 0px; +} + +.soria .dojoxGrid-rowbar-inner { + border: none; + border-bottom: 1px solid #cccccc; +} + +.soria .dojoxGrid-rowbar-over { + background: url(images/titleBarActive.png) #e9e9e9 repeat-y right; +} + +.soria .dojoxGrid-rowbar-selected { + background-color: #D9E8F9; + background-image: none; + background: url(../../../dijit/themes/soria/images/titleBar.png) #dddddd repeat-x top; + border-right: 1px solid #cccccc; + background-position: center; + background-repeat: no-repeat; +} + +/* rows */ + +.soria .dojoxGrid-row { + position: relative; + width: 9000em; +} + +.soria .dojoxGrid-row { + border: none; + border-left: none; + border-right: none; + background-color: white; + border-top: none; +} + +.soria .dojoxGrid-row-over { + border-top-color: #cccccc; + border-bottom-color: #cccccc; +} + +.soria .dojoxGrid-row-over .dojoxGrid-cell { + background-color: #60a1ea; + color:#fff; +} + +.soria .dojoxGrid-row-odd { + background-color: #f2f5f9; + /*background-color: #F9F7E8;*/ +} + +.soria .dojoxGrid-row-selected { + background-color: #aec7e3; +} + +.soria .dojoxGrid-row-table { + table-layout: fixed; + width: 0; + border-collapse: collapse; +} + +.soria .dojoxGrid-invisible { + visibility: hidden; +} + +.soria .Xdojo-ie .dojoxGrid-invisible { + display: none; +} + +.soria .dojoxGrid-invisible td, .dojoxGrid-header .dojoxGrid-invisible td { + border-top-width: 0; + border-bottom-width: 0; + padding-top: 0; + padding-bottom: 0; + height: 0; + overflow: hidden; +} + +/* cells */ + +.soria .dojoxGrid-cell { + border: 1px dotted #D5CDB5; + padding: 3px 3px 3px 3px; + text-align: left; + overflow: hidden; +} + +.dj_ie6 .soria .dojoxGrid-cell { + border: 1px solid white; + border-right: 1px solid #D5CDB5; +} + +.soria .dojoxGrid-cell-focus { + border: 1px dotted #a6a6a6; +} + +.soria .dojoxGrid-cell-over { + border: 1px dotted #a6a6a6; +} + +.soria .dojoxGrid-cell-focus.dojoxGrid-cell-over { + border: 1px dotted #595959; +} + +.soria .dojoxGrid-cell-clip { + width: 100%; + overflow: hidden; + white-space:nowrap; + text-overflow: ellipsis; +} + +/* editing */ + +/* FIXME: these colors are off! */ +.soria .dojoxGrid-row-editing td { + /* background-color: #F4FFF4; */ + background-color: #60a1ea; + /* padding: 0px 3px 0px 3px; */ +} + +.soria .dojoxGrid-row-inserting td { + background-color: #F4FFF4; +} +.soria .dojoxGrid-row-inflight td { + background-color: #F2F7B7; +} +.soria .dojoxGrid-row-error td { + background-color: #F8B8B6; +} + +.soria .dojoxGrid-input, +.soria .dojoxGrid-select, +.soria .dojoxGrid-textarea { + margin: 0; + padding: 0px; + border-style: none; + width: 100%; + font-size: 100%; + font-family: inherit; +} + +.dojoxGrid-hidden-focus { + position: absolute; + left: -1000px; + top: -1000px; + height: 0px, width: 0px; +} + +.dijit_a11y .dojoxGrid-rowbar-selected { + border-top: 1px solid white; + border-bottom: 1px dashed black; + border-top: 0; + background: none; +} + +.dijit_a11y .dojoxGrid-rowbar-selected .dojoxGrid-rowbar-inner { + border: 0; + border-top: 1px solid white; +} + +.dijit_a11y .dojoxGrid-row-selected { + border-bottom: 1px dashed black; +} diff --git a/includes/js/dojox/grid/_grid/tundraGrid.css b/includes/js/dojox/grid/_grid/tundraGrid.css new file mode 100644 index 0000000..d7b7a5f --- /dev/null +++ b/includes/js/dojox/grid/_grid/tundraGrid.css @@ -0,0 +1,215 @@ +.tundra .dojoxGrid { + position: relative; + background-color: #e9e9e9; + font-size: 0.85em; + -moz-outline-style: none; + outline: none; + overflow: hidden; + height: 0; +} +.tundra .dojoxGrid table { + padding: 0; +} +.tundra .dojoxGrid td { + -moz-outline: none; +} +.tundra .dojoxGrid-master-header { + position: relative; +} +.tundra .dojoxGrid-master-view { + position: relative; +} +.tundra .dojoxGrid-view { + position: absolute; + overflow: hidden; +} +.tundra .dojoxGrid-header { + position: absolute; + overflow: hidden; +} +.tundra .dojoxGrid-header { + background-color: #e9e9e9; +} +.tundra .dojoxGrid-header table { + text-align: center; +} +.tundra .dojoxGrid-header .dojoxGrid-cell-content { + text-align: center; +} +.tundra .dojoxGrid-header .dojoxGrid-cell { + border: 1px solid transparent; + + border-color: white #ACA899 #919191 white; + background: url(../../../dijit/themes/tundra/images/tabEnabled.png) #e9e9e9 repeat-x top; + padding-bottom: 2px; + color: #000 !important; +} +.tundra .dojoxGrid-header .dojoxGrid-cell-over { + background: url(../../../dijit/themes/tundra/images/tabHover.png) #e9e9e9 repeat-x top; + color: #000 !important; +} +.tundra .dojoxGrid-sort-down { + background: url(../../../dijit/themes/tundra/images/arrowDown.png) right no-repeat; + padding-left: 0px; + margin-left: 0px; +} +.tundra .dojoxGrid-sort-up { + background: url(../../../dijit/themes/tundra/images/arrowUp.png) right no-repeat; + padding-left: 0px; + margin-left: 0px; +} +.tundra .gridArrowButtonChar { + display:none !important; +} +.dijit_a11y .gridArrowButtonChar { + display:inline !important; +} +.tundra .dojoxGrid-scrollbox { + position: relative; + overflow: scroll; + background-color: #fefefe; + width: 100%; +} +.tundra .dojoxGrid-content { + position: relative; + overflow: hidden; + -moz-outline-style: none; + outline: none; +} +.tundra .dojoxGrid-rowbar { + border: none; + + background: url(images/tabEnabled_rotated.png) #e9e9e9 repeat-y right; + border-right: 1px solid #cccccc; + padding: 0px; +} +.tundra .dojoxGrid-rowbar-inner { + border: none; + border-bottom: 1px solid #cccccc; +} +.tundra .dojoxGrid-rowbar-over { + background: url(images/tabHover_rotated.png) #e9e9e9 repeat-y right; +} +.tundra .dojoxGrid-rowbar-selected { + background-color: #D9E8F9; + background-image: none; + background: url(../../../dijit/themes/tundra/images/tabDisabled.png) #dddddd repeat-x top; + border-right: 1px solid #cccccc; + background-position: center; + background-repeat: no-repeat; +} +.tundra .dojoxGrid-row { + position: relative; + width: 9000em; +} +.tundra .dojoxGrid-row { + border: none; + border-left: none; + border-right: none; + background-color: white; + border-top: none; +} +.tundra .dojoxGrid-row-over { + border-top-color: #cccccc; + border-bottom-color: #cccccc; +} +.tundra .dojoxGrid-row-over .dojoxGrid-cell { + background-color: #60a1ea; + color:#fff; + +} +.tundra .dojoxGrid-row-odd { + background-color: #f2f5f9; + +} +.tundra .dojoxGrid-row-selected { + background-color: #aec7e3; + +} +.tundra .dojoxGrid-row-table { + table-layout: fixed; + width: 0; + border-collapse: collapse; +} +.tundra .dojoxGrid-invisible { + visibility: hidden; +} +.tundra .Xdojo-ie .dojoxGrid-invisible { + display: none; +} +.tundra .dojoxGrid-invisible td, .dojoxGrid-header .dojoxGrid-invisible td { + border-top-width: 0; + border-bottom-width: 0; + padding-top: 0; + padding-bottom: 0; + height: 0; + overflow: hidden; +} +.tundra .dojoxGrid-cell { + border: 1px dotted #D5CDB5; + padding: 3px 3px 3px 3px; + text-align: left; + overflow: hidden; +} +.dj_ie6 .tundra .dojoxGrid-cell { + border: 1px solid white; + border-right: 1px solid #D5CDB5; +} +.tundra .dojoxGrid-cell-focus { + border: 1px dotted #a6a6a6; +} +.tundra .dojoxGrid-cell-over { + border: 1px dotted #a6a6a6; +} +.tundra .dojoxGrid-cell-focus.dojoxGrid-cell-over { + border: 1px dotted #595959; +} +.tundra .dojoxGrid-cell-clip { + width: 100%; + overflow: hidden; + white-space:nowrap; + text-overflow: ellipsis; +} +.tundra .dojoxGrid-row-editing td { + + background-color: #60a1ea; + +} +.tundra .dojoxGrid-row-inserting td { + background-color: #F4FFF4; +} +.tundra .dojoxGrid-row-inflight td { + background-color: #F2F7B7; +} +.tundra .dojoxGrid-row-error td { + background-color: #F8B8B6; +} +.tundra .dojoxGrid-input, +.tundra .dojoxGrid-select, +.tundra .dojoxGrid-textarea { + margin: 0; + padding: 0px; + border-style: none; + width: 100%; + font-size: 100%; + font-family: inherit; +} +.dojoxGrid-hidden-focus { + position: absolute; + left: -1000px; + top: -1000px; + height: 0px, width: 0px; +} +.dijit_a11y .dojoxGrid-rowbar-selected { + border-top: 1px solid white; + border-bottom: 1px dashed black; + border-top: 0; + background: none; +} +.dijit_a11y .dojoxGrid-rowbar-selected .dojoxGrid-rowbar-inner { + border: 0; + border-top: 1px solid white; +} +.dijit_a11y .dojoxGrid-row-selected { + border-bottom: 1px dashed black; +} diff --git a/includes/js/dojox/grid/_grid/tundraGrid.css.commented.css b/includes/js/dojox/grid/_grid/tundraGrid.css.commented.css new file mode 100644 index 0000000..a282f58 --- /dev/null +++ b/includes/js/dojox/grid/_grid/tundraGrid.css.commented.css @@ -0,0 +1,281 @@ +.tundra .dojoxGrid { + position: relative; + background-color: #e9e9e9; + font-size: 0.85em; /* inherit font-family from dojo.css */ + -moz-outline-style: none; + outline: none; + overflow: hidden; + height: 0; +} + +.tundra .dojoxGrid table { + padding: 0; +} + +.tundra .dojoxGrid td { + -moz-outline: none; +} + +/* master header */ + +.tundra .dojoxGrid-master-header { + position: relative; +} + +/* master view */ + +.tundra .dojoxGrid-master-view { + position: relative; +} + +/* views */ + +.tundra .dojoxGrid-view { + position: absolute; + overflow: hidden; +} + +/* header */ + +.tundra .dojoxGrid-header { + position: absolute; + overflow: hidden; +} + +.tundra .dojoxGrid-header { + background-color: #e9e9e9; +} + +.tundra .dojoxGrid-header table { + text-align: center; +} + +.tundra .dojoxGrid-header .dojoxGrid-cell-content { + text-align: center; +} + +.tundra .dojoxGrid-header .dojoxGrid-cell { + border: 1px solid transparent; + /* border-color: #F6F4EB #ACA899 #ACA899 #F6F4EB; */ + border-color: white #ACA899 #919191 white; + background: url(../../../dijit/themes/tundra/images/tabEnabled.png) #e9e9e9 repeat-x top; + padding-bottom: 2px; + color: #000 !important; +} + +.tundra .dojoxGrid-header .dojoxGrid-cell-over { + background: url(../../../dijit/themes/tundra/images/tabHover.png) #e9e9e9 repeat-x top; + color: #000 !important; +} + +.tundra .dojoxGrid-sort-down { + background: url(../../../dijit/themes/tundra/images/arrowDown.png) right no-repeat; + padding-left: 0px; + margin-left: 0px; +} + +.tundra .dojoxGrid-sort-up { + background: url(../../../dijit/themes/tundra/images/arrowUp.png) right no-repeat; + padding-left: 0px; + margin-left: 0px; +} + +.tundra .gridArrowButtonChar { + display:none !important; +} +.dijit_a11y .gridArrowButtonChar { + display:inline !important; +} + +/* content */ + +.tundra .dojoxGrid-scrollbox { + position: relative; + overflow: scroll; + background-color: #fefefe; + width: 100%; +} + +.tundra .dojoxGrid-content { + position: relative; + overflow: hidden; + -moz-outline-style: none; + outline: none; +} + +/* rowbar */ + +.tundra .dojoxGrid-rowbar { + border: none; + /* + border-color: #F6F4EB #ACA899 #ACA899 #F6F4EB; + */ + background: url(images/tabEnabled_rotated.png) #e9e9e9 repeat-y right; + border-right: 1px solid #cccccc; + padding: 0px; +} + +.tundra .dojoxGrid-rowbar-inner { + border: none; + border-bottom: 1px solid #cccccc; +} + +.tundra .dojoxGrid-rowbar-over { + background: url(images/tabHover_rotated.png) #e9e9e9 repeat-y right; +} + +.tundra .dojoxGrid-rowbar-selected { + background-color: #D9E8F9; + background-image: none; + background: url(../../../dijit/themes/tundra/images/tabDisabled.png) #dddddd repeat-x top; + border-right: 1px solid #cccccc; + background-position: center; + background-repeat: no-repeat; +} + +/* rows */ + +.tundra .dojoxGrid-row { + position: relative; + width: 9000em; +} + +.tundra .dojoxGrid-row { + border: none; + border-left: none; + border-right: none; + background-color: white; + border-top: none; +} + +.tundra .dojoxGrid-row-over { + border-top-color: #cccccc; + border-bottom-color: #cccccc; +} + +.tundra .dojoxGrid-row-over .dojoxGrid-cell { + background-color: #60a1ea; + color:#fff; + /*background: url(../../../dijit/themes/tundra/images/tabEnabled.png) #e9e9e9 repeat-x top;*/ +} + +.tundra .dojoxGrid-row-odd { + background-color: #f2f5f9; + /*background-color: #F9F7E8;*/ +} + +.tundra .dojoxGrid-row-selected { + background-color: #aec7e3; + /* + background: url(../../../dijit/themes/tundra/images/tabDisabled.png) #dddddd repeat-x top; + */ +} + +.tundra .dojoxGrid-row-table { + table-layout: fixed; + width: 0; + border-collapse: collapse; +} + +.tundra .dojoxGrid-invisible { + visibility: hidden; +} + +.tundra .Xdojo-ie .dojoxGrid-invisible { + display: none; +} + +.tundra .dojoxGrid-invisible td, .dojoxGrid-header .dojoxGrid-invisible td { + border-top-width: 0; + border-bottom-width: 0; + padding-top: 0; + padding-bottom: 0; + height: 0; + overflow: hidden; +} + +/* cells */ + +.tundra .dojoxGrid-cell { + border: 1px dotted #D5CDB5; + padding: 3px 3px 3px 3px; + text-align: left; + overflow: hidden; +} + +.dj_ie6 .tundra .dojoxGrid-cell { + border: 1px solid white; + border-right: 1px solid #D5CDB5; +} + +.tundra .dojoxGrid-cell-focus { + border: 1px dotted #a6a6a6; +} + +.tundra .dojoxGrid-cell-over { + border: 1px dotted #a6a6a6; +} + +.tundra .dojoxGrid-cell-focus.dojoxGrid-cell-over { + border: 1px dotted #595959; +} + +.tundra .dojoxGrid-cell-clip { + width: 100%; + overflow: hidden; + white-space:nowrap; + text-overflow: ellipsis; +} + +/* editing */ + +/* FIXME: these colors are off! */ +.tundra .dojoxGrid-row-editing td { + /* background-color: #F4FFF4; */ + background-color: #60a1ea; + /* padding: 0px 3px 0px 3px; */ +} + +.tundra .dojoxGrid-row-inserting td { + background-color: #F4FFF4; +} +.tundra .dojoxGrid-row-inflight td { + background-color: #F2F7B7; +} +.tundra .dojoxGrid-row-error td { + background-color: #F8B8B6; +} + +.tundra .dojoxGrid-input, +.tundra .dojoxGrid-select, +.tundra .dojoxGrid-textarea { + margin: 0; + padding: 0px; + border-style: none; + width: 100%; + font-size: 100%; + font-family: inherit; +} + +.dojoxGrid-hidden-focus { + position: absolute; + left: -1000px; + top: -1000px; + height: 0px, width: 0px; +} + +.dijit_a11y .dojoxGrid-rowbar-selected { + border-top: 1px solid white; + border-bottom: 1px dashed black; + border-top: 0; + background: none; +} + +.dijit_a11y .dojoxGrid-rowbar-selected .dojoxGrid-rowbar-inner { + border: 0; + border-top: 1px solid white; +} + +.dijit_a11y .dojoxGrid-row-selected { + border-bottom: 1px dashed black; +} diff --git a/includes/js/dojox/grid/_grid/view.js b/includes/js/dojox/grid/_grid/view.js new file mode 100644 index 0000000..7f669cd --- /dev/null +++ b/includes/js/dojox/grid/_grid/view.js @@ -0,0 +1,336 @@ +if(!dojo._hasResource["dojox.grid._grid.view"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid._grid.view"] = true; +dojo.provide("dojox.grid._grid.view"); + +dojo.require("dijit._Widget"); +dojo.require("dijit._Templated"); +dojo.require("dojox.grid._grid.builder"); + +dojo.declare('dojox.GridView', + [dijit._Widget, dijit._Templated], + { + // summary: + // A collection of grid columns. A grid is comprised of a set of views that stack horizontally. + // Grid creates views automatically based on grid's layout structure. + // Users should typically not need to access individual views directly. + // + // defaultWidth: String + // Default widget of the view + defaultWidth: "18em", + + // viewWidth: String + // Width for the view, in valid css unit + viewWidth: "", + + templateString:"
      \n\t
      \n\t\t
      \n\t\t\t
      \n\t\t
      \n\t
      \n\t\n\t\n\t
      \n\t\t
      \n\t
      \n
      \n", + + themeable: false, + classTag: 'dojoxGrid', + marginBottom: 0, + rowPad: 2, + + postMixInProperties: function(){ + this.rowNodes = []; + }, + + postCreate: function(){ + this.connect(this.scrollboxNode,"onscroll","doscroll"); + dojox.grid.funnelEvents(this.contentNode, this, "doContentEvent", [ 'mouseover', 'mouseout', 'click', 'dblclick', 'contextmenu', 'mousedown' ]); + dojox.grid.funnelEvents(this.headerNode, this, "doHeaderEvent", [ 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'click', 'contextmenu' ]); + this.content = new dojox.grid.contentBuilder(this); + this.header = new dojox.grid.headerBuilder(this); + //BiDi: in RTL case, style width='9000em' causes scrolling problem in head node + if(!dojo._isBodyLtr()){ + this.headerNodeContainer.style.width = ""; + } + }, + + destroy: function(){ + dojox.grid.removeNode(this.headerNode); + this.inherited("destroy", arguments); + }, + + // focus + focus: function(){ + if(dojo.isSafari || dojo.isOpera){ + this.hiddenFocusNode.focus(); + }else{ + this.scrollboxNode.focus(); + } + }, + + setStructure: function(inStructure){ + var vs = this.structure = inStructure; + // FIXME: similar logic is duplicated in layout + if(vs.width && !isNaN(vs.width)){ + this.viewWidth = vs.width + 'em'; + }else{ + this.viewWidth = vs.width || this.viewWidth; //|| this.defaultWidth; + } + this.onBeforeRow = vs.onBeforeRow; + this.noscroll = vs.noscroll; + if(this.noscroll){ + this.scrollboxNode.style.overflow = "hidden"; + } + // bookkeeping + this.testFlexCells(); + // accomodate new structure + this.updateStructure(); + }, + + testFlexCells: function(){ + // FIXME: cheater, this function does double duty as initializer and tester + this.flexCells = false; + for(var j=0, row; (row=this.structure.rows[j]); j++){ + for(var i=0, cell; (cell=row[i]); i++){ + cell.view = this; + this.flexCells = this.flexCells || cell.isFlex(); + } + } + return this.flexCells; + }, + + updateStructure: function(){ + // header builder needs to update table map + this.header.update(); + // content builder needs to update markup cache + this.content.update(); + }, + + getScrollbarWidth: function(){ + return (this.noscroll ? 0 : dojox.grid.getScrollbarWidth()); // Integer + }, + + getColumnsWidth: function(){ + return this.headerContentNode.firstChild.offsetWidth; // Integer + }, + + getWidth: function(){ + return this.viewWidth || (this.getColumnsWidth()+this.getScrollbarWidth()) +'px'; // String + }, + + getContentWidth: function(){ + return Math.max(0, dojo._getContentBox(this.domNode).w - this.getScrollbarWidth()) + 'px'; // String + }, + + render: function(){ + this.scrollboxNode.style.height = ''; + this.renderHeader(); + }, + + renderHeader: function(){ + this.headerContentNode.innerHTML = this.header.generateHtml(this._getHeaderContent); + }, + + // note: not called in 'view' context + _getHeaderContent: function(inCell){ + var n = inCell.name || inCell.grid.getCellName(inCell); + if(inCell.index != inCell.grid.getSortIndex()){ + return n; + } + return [ '
      ', inCell.grid.sortInfo > 0 ? '▼' : '▲', '
      ', n, '
      ' ].join(''); + }, + + resize: function(){ + this.adaptHeight(); + this.adaptWidth(); + }, + + hasScrollbar: function(){ + return (this.scrollboxNode.clientHeight != this.scrollboxNode.offsetHeight); // Boolean + }, + + adaptHeight: function(){ + if(!this.grid.autoHeight){ + var h = this.domNode.clientHeight; + if(!this.hasScrollbar()){ // no scrollbar is rendered + h -= dojox.grid.getScrollbarWidth(); + } + dojox.grid.setStyleHeightPx(this.scrollboxNode, h); + } + }, + + adaptWidth: function(){ + if(this.flexCells){ + // the view content width + this.contentWidth = this.getContentWidth(); + this.headerContentNode.firstChild.style.width = this.contentWidth; + } + // FIXME: it should be easier to get w from this.scrollboxNode.clientWidth, + // but clientWidth seemingly does not include scrollbar width in some cases + var w = this.scrollboxNode.offsetWidth - this.getScrollbarWidth(); + w = Math.max(w, this.getColumnsWidth()) + 'px'; + with(this.contentNode){ + style.width = ''; + offsetWidth; + style.width = w; + } + }, + + setSize: function(w, h){ + with(this.domNode.style){ + if(w){ + width = w; + } + height = (h >= 0 ? h + 'px' : ''); + } + with(this.headerNode.style){ + if(w){ + width = w; + } + } + }, + + renderRow: function(inRowIndex, inHeightPx){ + var rowNode = this.createRowNode(inRowIndex); + this.buildRow(inRowIndex, rowNode, inHeightPx); + this.grid.edit.restore(this, inRowIndex); + return rowNode; + }, + + createRowNode: function(inRowIndex){ + var node = document.createElement("div"); + node.className = this.classTag + '-row'; + node[dojox.grid.gridViewTag] = this.id; + node[dojox.grid.rowIndexTag] = inRowIndex; + this.rowNodes[inRowIndex] = node; + return node; + }, + + buildRow: function(inRowIndex, inRowNode){ + this.buildRowContent(inRowIndex, inRowNode); + this.styleRow(inRowIndex, inRowNode); + }, + + buildRowContent: function(inRowIndex, inRowNode){ + inRowNode.innerHTML = this.content.generateHtml(inRowIndex, inRowIndex); + if(this.flexCells){ + // FIXME: accessing firstChild here breaks encapsulation + inRowNode.firstChild.style.width = this.contentWidth; + } + }, + + rowRemoved:function(inRowIndex){ + this.grid.edit.save(this, inRowIndex); + delete this.rowNodes[inRowIndex]; + }, + + getRowNode: function(inRowIndex){ + return this.rowNodes[inRowIndex]; + }, + + getCellNode: function(inRowIndex, inCellIndex){ + var row = this.getRowNode(inRowIndex); + if(row){ + return this.content.getCellNode(row, inCellIndex); + } + }, + + // styling + styleRow: function(inRowIndex, inRowNode){ + inRowNode._style = dojox.grid.getStyleText(inRowNode); + this.styleRowNode(inRowIndex, inRowNode); + }, + + styleRowNode: function(inRowIndex, inRowNode){ + if(inRowNode){ + this.doStyleRowNode(inRowIndex, inRowNode); + } + }, + + doStyleRowNode: function(inRowIndex, inRowNode){ + this.grid.styleRowNode(inRowIndex, inRowNode); + }, + + // updating + updateRow: function(inRowIndex, inHeightPx, inPageNode){ + var rowNode = this.getRowNode(inRowIndex); + if(rowNode){ + rowNode.style.height = ''; + this.buildRow(inRowIndex, rowNode); + } + return rowNode; + }, + + updateRowStyles: function(inRowIndex){ + this.styleRowNode(inRowIndex, this.getRowNode(inRowIndex)); + }, + + // scrolling + lastTop: 0, + firstScroll:0, + + doscroll: function(inEvent){ + //var s = dojo.marginBox(this.headerContentNode.firstChild); + var isLtr = dojo._isBodyLtr(); + if(this.firstScroll < 2){ + if((!isLtr && this.firstScroll == 1) || (isLtr && this.firstScroll == 0)){ + var s = dojo.marginBox(this.headerNodeContainer); + if(dojo.isIE){ + this.headerNodeContainer.style.width = s.w + this.getScrollbarWidth() + 'px'; + }else if(dojo.isMoz){ + //TODO currently only for FF, not sure for safari and opera + this.headerNodeContainer.style.width = s.w - this.getScrollbarWidth() + 'px'; + //this.headerNodeContainer.style.width = s.w + 'px'; + //set scroll to right in FF + if(isLtr){ + this.scrollboxNode.scrollLeft = this.scrollboxNode.scrollWidth - this.scrollboxNode.clientWidth; + }else{ + this.scrollboxNode.scrollLeft = this.scrollboxNode.clientWidth - this.scrollboxNode.scrollWidth; + } + } + } + this.firstScroll++; + } + this.headerNode.scrollLeft = this.scrollboxNode.scrollLeft; + // 'lastTop' is a semaphore to prevent feedback-loop with setScrollTop below + var top = this.scrollboxNode.scrollTop; + if(top != this.lastTop){ + this.grid.scrollTo(top); + } + }, + + setScrollTop: function(inTop){ + // 'lastTop' is a semaphore to prevent feedback-loop with doScroll above + this.lastTop = inTop; + this.scrollboxNode.scrollTop = inTop; + return this.scrollboxNode.scrollTop; + }, + + // event handlers (direct from DOM) + doContentEvent: function(e){ + if(this.content.decorateEvent(e)){ + this.grid.onContentEvent(e); + } + }, + + doHeaderEvent: function(e){ + if(this.header.decorateEvent(e)){ + this.grid.onHeaderEvent(e); + } + }, + + // event dispatch(from Grid) + dispatchContentEvent: function(e){ + return this.content.dispatchEvent(e); + }, + + dispatchHeaderEvent: function(e){ + return this.header.dispatchEvent(e); + }, + + // column resizing + setColWidth: function(inIndex, inWidth){ + this.grid.setCellWidth(inIndex, inWidth + 'px'); + }, + + update: function(){ + var left = this.scrollboxNode.scrollLeft; + this.content.update(); + this.grid.update(); + this.scrollboxNode.scrollLeft = left; + this.headerNode.scrollLeft = left; + } +}); + +} diff --git a/includes/js/dojox/grid/_grid/views.js b/includes/js/dojox/grid/_grid/views.js new file mode 100644 index 0000000..d13bbb7 --- /dev/null +++ b/includes/js/dojox/grid/_grid/views.js @@ -0,0 +1,277 @@ +if(!dojo._hasResource["dojox.grid._grid.views"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid._grid.views"] = true; +dojo.provide("dojox.grid._grid.views"); + +dojo.declare('dojox.grid.views', null, { + // summary: + // A collection of grid views. Owned by grid and used internally for managing grid views. + // description: + // Grid creates views automatically based on grid's layout structure. + // Users should typically not need to access individual views or the views collection directly. + constructor: function(inGrid){ + this.grid = inGrid; + }, + + defaultWidth: 200, + + views: [], + + // operations + resize: function(){ + this.onEach("resize"); + }, + + render: function(){ + this.onEach("render"); + }, + + // views + addView: function(inView){ + inView.idx = this.views.length; + this.views.push(inView); + }, + + destroyViews: function(){ + for (var i=0, v; v=this.views[i]; i++) + v.destroy(); + this.views = []; + }, + + getContentNodes: function(){ + var nodes = []; + for(var i=0, v; v=this.views[i]; i++){ + nodes.push(v.contentNode); + } + return nodes; + }, + + forEach: function(inCallback){ + for(var i=0, v; v=this.views[i]; i++){ + inCallback(v, i); + } + }, + + onEach: function(inMethod, inArgs){ + inArgs = inArgs || []; + for(var i=0, v; v=this.views[i]; i++){ + if(inMethod in v){ + v[inMethod].apply(v, inArgs); + } + } + }, + + // layout + normalizeHeaderNodeHeight: function(){ + var rowNodes = []; + for(var i=0, v; (v=this.views[i]); i++){ + if(v.headerContentNode.firstChild){ + rowNodes.push(v.headerContentNode) + }; + } + this.normalizeRowNodeHeights(rowNodes); + }, + + normalizeRowNodeHeights: function(inRowNodes){ + var h = 0; + for(var i=0, n, o; (n=inRowNodes[i]); i++){ + h = Math.max(h, (n.firstChild.clientHeight)||(n.firstChild.offsetHeight)); + } + h = (h >= 0 ? h : 0); + // + var hpx = h + 'px'; + for(var i=0, n; (n=inRowNodes[i]); i++){ + if(n.firstChild.clientHeight!=h){ + n.firstChild.style.height = hpx; + } + } + // + //console.log('normalizeRowNodeHeights ', h); + // + // querying the height here seems to help scroller measure the page on IE + if(inRowNodes&&inRowNodes[0]){ + inRowNodes[0].parentNode.offsetHeight; + } + }, + + resetHeaderNodeHeight: function(){ + for(var i=0, v, n; (v=this.views[i]); i++){ + n = v.headerContentNode.firstChild; + if(n) + n.style.height = ""; + } + }, + + renormalizeRow: function(inRowIndex){ + var rowNodes = []; + for(var i=0, v, n; (v=this.views[i])&&(n=v.getRowNode(inRowIndex)); i++){ + n.firstChild.style.height = ''; + rowNodes.push(n); + } + this.normalizeRowNodeHeights(rowNodes); + }, + + getViewWidth: function(inIndex){ + return this.views[inIndex].getWidth() || this.defaultWidth; + }, + + // must be called after view widths are properly set or height can be miscalculated + // if there are flex columns + measureHeader: function(){ + // need to reset view header heights so they are properly measured. + this.resetHeaderNodeHeight(); + this.forEach(function(inView){ + inView.headerContentNode.style.height = ''; + }); + var h = 0; + // calculate maximum view header height + this.forEach(function(inView){ + h = Math.max(inView.headerNode.offsetHeight, h); + }); + return h; + }, + + measureContent: function(){ + var h = 0; + this.forEach(function(inView) { + h = Math.max(inView.domNode.offsetHeight, h); + }); + return h; + }, + + findClient: function(inAutoWidth){ + // try to use user defined client + var c = this.grid.elasticView || -1; + // attempt to find implicit client + if(c < 0){ + for(var i=1, v; (v=this.views[i]); i++){ + if(v.viewWidth){ + for(i=1; (v=this.views[i]); i++){ + if(!v.viewWidth){ + c = i; + break; + } + } + break; + } + } + } + // client is in the middle by default + if(c < 0){ + c = Math.floor(this.views.length / 2); + } + return c; + }, + + arrange: function(l, w){ + var i, v, vw, len = this.views.length; + // find the client + var c = (w <= 0 ? len : this.findClient()); + // layout views + var setPosition = function(v, l){ + with(v.domNode.style){ + if(!dojo._isBodyLtr()){ + right = l + 'px'; + }else{ + left = l + 'px'; + } + top = 0 + 'px'; + } + with(v.headerNode.style){ + if(!dojo._isBodyLtr()){ + right = l + 'px'; + }else{ + left = l + 'px'; + } + top = 0; + } + } + // for views left of the client + //BiDi TODO: The left and right should not appear in BIDI environment. Should be replaced with + //leading and tailing concept. + for(i=0; (v=this.views[i])&&(i +
      +
      +
      +
      +
      + + +
      +
      +
      +
      \ No newline at end of file diff --git a/includes/js/dojox/grid/resources/VirtualGrid.html b/includes/js/dojox/grid/resources/VirtualGrid.html new file mode 100644 index 0000000..7253108 --- /dev/null +++ b/includes/js/dojox/grid/resources/VirtualGrid.html @@ -0,0 +1,5 @@ +
      +
      +
      + +
      diff --git a/includes/js/dojox/grid/tests/databaseModel.js b/includes/js/dojox/grid/tests/databaseModel.js new file mode 100644 index 0000000..3c879eb --- /dev/null +++ b/includes/js/dojox/grid/tests/databaseModel.js @@ -0,0 +1,337 @@ +if(!dojo._hasResource["dojox.grid.tests.databaseModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.grid.tests.databaseModel"] = true; +dojo.provide("dojox.grid.tests.databaseModel"); +dojo.require("dojox.grid._data.model"); + +// Provides a sparse array that is also traversable inorder +// with basic Array: +// - iterating by index is slow for large sparse arrays +// - for...in iteration is in order of element creation +// maintains a secondary index for interating +// over sparse elements inorder +dojo.declare("dojox.grid.Sparse", null, { + constructor: function() { + this.clear(); + }, + clear: function() { + this.indices = []; + this.values = []; + }, + length: function() { + return this.indices.length; + }, + set: function(inIndex, inValue) { + for (var i=0,l=this.indices.length; i= inIndex) + break; + } + if (this.indices[i] != inIndex) + this.indices.splice(i, 0, inIndex); + this.values[inIndex] = inValue; + }, + get: function(inIndex) { + return this.values[inIndex]; + }, + remove: function(inIndex) { + for (var i=0,l=this.indices.length; i=0) && ((k=inRowIndexes[i])!=undefined); i--) + this.setState(k, inState, inValue); + }, + clearStateForIndexes: function(inRowIndexes, inState) { + for (var i=inRowIndexes.length-1, k; (i>=0) && ((k=inRowIndexes[i])!=undefined); i--) + this.clearState(k, inState); + }, + //$ Return boolean stating whether or not an operation is in progress that may change row indexing. + isAddRemoving: function() { + return Boolean(this.states['inserting'].length() || this.states['removing'].length()); + }, + isInflight: function() { + return Boolean(this.states['inflight'].length()); + }, + //$ Return boolean stating if the model is currently undergoing any type of edit. + isEditing: function() { + for (var i=0, r={}, s; (s=this.stateNames[i]); i++) + if (this.states[s].length()) + return true; + }, + //$ Return true if ok to modify the given row. Override as needed, using model editing state information. + canModify: function(inRowIndex) { + return !this.getState(inRowIndex).inflight && !(this.isInflight() && this.isAddRemoving()); + }, + // server send / receive + getSendParams: function(inParams) { + var p = { + database: this.database || '', + table: this.table || '' + } + return dojo.mixin(p, inParams || {}); + }, + send: function(inAsync, inParams, inCallbacks) { + //console.log('send', inParams.command); + var p = this.getSendParams(inParams); + var d = dojo.xhrPost({ + url: this.server, + content: p, + handleAs: 'json-comment-filtered', + contentType: "application/x-www-form-urlencoded; charset=utf-8", + sync: !inAsync + }); + d.addCallbacks(dojo.hitch(this, "receive", inCallbacks), dojo.hitch(this, "receiveError", inCallbacks)); + return d; + }, + _callback: function(cb, eb, data) { + try{ cb && cb(data); } + catch(e){ eb && eb(data, e); } + }, + receive: function(inCallbacks, inData) { + inCallbacks && this._callback(inCallbacks.callback, inCallbacks.errback, inData); + }, + receiveError: function(inCallbacks, inErr) { + this._callback(inCallbacks.errback, null, inErr) + }, + encodeRow: function(inParams, inRow, inPrefix) { + for (var i=0, l=inRow.length; i < l; i++) + inParams['_' + (inPrefix ? inPrefix : '') + i] = (inRow[i] ? inRow[i] : ''); + }, + measure: function() { + this.send(true, { command: 'info' }, { callback: dojo.hitch(this, this.callbacks.info) }); + }, + fetchRowCount: function(inCallbacks) { + this.send(true, { command: 'count' }, inCallbacks); + }, + // server commits + commitEdit: function(inOldData, inNewData, inRowIndex, inCallbacks) { + this.setState(inRowIndex, "inflight", true); + var params = {command: 'update'}; + this.encodeRow(params, inOldData, 'o'); + this.encodeRow(params, inNewData); + this.send(true, params, inCallbacks); + }, + commitInsert: function(inRowIndex, inNewData, inCallbacks) { + this.setState(inRowIndex, "inflight", true); + var params = {command: 'insert'}; + this.encodeRow(params, inNewData); + this.send(true, params, inCallbacks); + }, + // NOTE: supported only in tables with pk + commitDelete: function(inRows, inCallbacks) { + var params = { + command: 'delete', + count: inRows.length + } + var pk = this.getPkIndex(); + if (pk < 0) + return; + for (var i=0; i < inRows.length; i++) { + params['_' + i] = inRows[i][pk]; + } + this.send(true, params, inCallbacks); + }, + getUpdateCallbacks: function(inRowIndex) { + return { + callback: dojo.hitch(this, this.callbacks.update, inRowIndex), + errback: dojo.hitch(this, this.callbacks.updateError, inRowIndex) + }; + }, + // primary key from fields + getPkIndex: function() { + for (var i=0, l=this.fields.count(), f; (i + + + 1 + Title of 1 + Author of 1 + + + 2 + Title of 2 + Author of 2 + + + 3 + Title of 3 + Author of 3 + + + 4 + Title of 4 + Author of 4 + + + 5 + Title of 5 + Author of 5 + + + 6 + Title of 6 + Author of 6 + + + 7 + Title of 7 + Author of 7 + + + 8 + Title of 8 + Author of 8 + + + 9 + Title of 9 + Author of 9 + + + 10 + Title of 10 + Author of 10 + + + 11 + Title of 11 + Author of 11 + + + 12 + Title of 12 + Author of 12 + + + 13 + Title of 13 + Author of 13 + + + 14 + Title of 14 + Author of 14 + + + 15 + Title of 15 + Author of 15 + + + 16 + Title of 16 + Author of 16 + + + 17 + Title of 17 + Author of 17 + + + 18 + Title of 18 + Author of 18 + + + 19 + Title of 19 + Author of 19 + + + 20 + Title of 20 + Author of 20 + + diff --git a/includes/js/dojox/grid/tests/support/data.php b/includes/js/dojox/grid/tests/support/data.php new file mode 100644 index 0000000..1beb6f0 --- /dev/null +++ b/includes/js/dojox/grid/tests/support/data.php @@ -0,0 +1,379 @@ +encode($inData) . ' */'; + } + + function error($inMessage) { + $inMessage = str_replace('"', '\\"', $inMessage); + error_log($inMessage); + //echo '/* ({error: true, message: "' . $inMessage . '"}) */'; + echoJson(array('error' => true, 'message' => $inMessage)); + exit; + } + + + function getArray($inResult, $inArray="true") { + $o = Array(); + while ($row = ($inArray ? mysql_fetch_row($inResult) : mysql_fetch_object($inResult))) + $o[] = $row; + return $o; + } + + // connect to DB + mysql_connect($dbserver, $dbuser, $dbpassword); + + // select DB + $database = getPostString("database"); + $database = ($database ? $database : $db); + if (!mysql_select_db($database)) + error('failed to select db: ' . mysql_error()); + + // select table + $table = getPostString("table"); + $table = ($table ? $table : $dbtable); + + // cache + $colCache = NULL; + $pkCache = NULL; + + // set UTF8 output (MySql > 4.0) + mysql_query("SET NAMES UTF8"); + + // server, database, table meta data + function getDatabases() { + $result = mysql_query("SHOW DATABASES"); + $output = Array(); + while ($row = mysql_fetch_row($result)) { + $r = strtolower($row[0]); + if ($r != 'mysql' && $r != 'information_schema') + $output[] = $row[0]; + } + return $output; + } + + function getTables() { + global $database; + $result = mysql_query("SHOW TABLES FROM $database"); + $output = Array(); + while ($row = mysql_fetch_row($result)) + $output[] = $row[0]; + return $output; + } + + function getColumns() { + global $table, $colCache; + if (!$colCache) { + $result = mysql_query("SHOW COLUMNS FROM `$table`"); + return getArray($result, false); + $colCache = getArray($result, false); + } + return $colCache; + } + + // returns object: $this->name, $this->index + function getPk() { + global $pkCache; + if (!$pkCache) { + $k = ''; + $columns = getColumns(); + for ($i=0; $i < count($columns); $i++) { + $c = $columns[$i]; + if ($c->Key == 'PRI') { + $k = $c->Field; + break; + } + } + $pkCache->index = $i; + $pkCache->name = $k; + } + return $pkCache; + } + + function getTableInfo() { + global $table, $database; + $c = getColumns(); + $r = rowcount(); + return array("count" => $r, "columns" => $c, "database" => $database, "table" => $table); + } + + function getOldPostPkValue() { + $pk = getPk(); + return getPostString('_o' . $pk->index); + } + + function getNewPostPkValue() { + $pk = getPk(); + return getPostString('_' . $pk->index); + } + + function getPostColumns() { + $columns = getColumns(); + for ($i=0, $a=array(), $p; (($p=getPostString("_".$i)) != ''); $i++) { + $r = new stdClass(); + $r->name = $columns[$i]->Field; + $r->value = $p; + $a[] = $r; + } + return $a; + } + + function getOrderBy() { + $ob = getPostString("orderby"); + if (is_numeric($ob)) { + $columns = getColumns(); + $ob = $columns[intval($ob)-1]->Field; + } + return $ob; + } + + function getWhere() { + $w = getPostString("where"); + return ($w ? " WHERE $w" : ""); + } + + // basic operations + function rowcount() { + global $table; + $query = "SELECT COUNT(*) FROM `$table`" . getWhere(); + $result = mysql_query($query); + if (!$result) + error("failed to perform query: $query. " . mysql_error()); + if ($row = mysql_fetch_row($result)) + return $row[0]; + else + return 0; + } + + function select($inQuery = '') { + global $table; + // built limit clause + $lim = (int)getPostString("limit"); + $off = (int)getPostString("offset"); + $limit = ($lim || $off ? " LIMIT $off, $lim" : ""); + // build order by clause + $desc = (boolean)getPostString("desc"); + $ob = getOrderBy(); + $orderby = ($ob ? " ORDER BY `" . $ob . "`" . ($desc ? " DESC" : "") : ""); + // build query + $query = ($inQuery ? $inQuery : "SELECT * FROM `$table`" . getWhere() . $orderby . $limit); + // execute query + if (!$result = mysql_query($query)) + error("failed to perform query: $query. " . mysql_error()); + // fetch each result row + return getArray($result); + } + + function reflectRow() { + global $table; + $pk = getPk(); + $key = getNewPostPkValue(); + $where = "`$pk->name`=\"$key\""; + return select("SELECT * FROM `$table` WHERE $where LIMIT 1"); + } + + function update() { + // build set clause + for ($i=0, $set = array(), $cols = getPostColumns(), $v; ($v=$cols[$i]); $i++) + $set[] = "`$v->name` = '$v->value'"; + $set = implode(', ', $set); + // our table + global $table; + // build query + $pk = getPk(); + $pkValue = getOldPostPkValue(); + $query = "UPDATE `$table` SET $set WHERE `$pk->name` = '$pkValue' LIMIT 1"; + // execute query + if (!mysql_query($query)) + error("failed to perform query: [$query]. " . + "MySql says: [" . mysql_error() ."]"); + else { + return reflectRow(); + } + } + + function insert() { + global $table; + // build values clause + for ($i=0, $values = array(), $cols = getPostColumns(), $v; ($v=$cols[$i]); $i++) + $values[] = $v->value; + $values = '"' . implode('", "', $values) . '"'; + // build query + $query = "INSERT INTO `$table` VALUES($values)"; + // execute query + if (!mysql_query($query)) + error("failed to perform query: [$query]. " . + "MySql says: [" . mysql_error() ."]"); + else { + return reflectRow(); + } + } + + function delete() { + global $table; + // build query + $n = getPostString("count"); + $pk = getPk(); + for ($i = 0, $deleted=array(); $i < $n; $i++) { + $key = getPostString("_$i"); + array_push($deleted, $key); + $query = "DELETE FROM `$table` WHERE `$pk->name`=\"$key\" LIMIT 1"; + // execute query + if (!mysql_query($query) || mysql_affected_rows() != 1) + error("failed to perform query: [$query]. " . + "Affected rows: " . mysql_affected_rows() .". " . + "MySql says: [" . mysql_error() ."]"); + } + return $deleted; + } + + // find (full text search) + function findData($inFindCol, $inFind, $inOrderBy, $inFullText) { + global $table; + $where = ($inFullText ? "WHERE MATCH(`$inFindCol`) AGAINST ('$inFind')" : "WHERE $inFindCol LIKE '$inFind'"); + $query = "SELECT * FROM $table $where $inOrderBy"; + $result = mysql_query($query); + // return rows + return getArray($result); + } + + // binary search through sorted data, supports start point ($inFindFrom) and direction ($inFindForward) + function findRow($inData, $inFindFrom=-1, $inFindForward) { + $b = -1; + $l = count($inData); + if (!$inData) + return $b; + if (!$inFindFrom==-1 || $l < 2) + $b = 0; + else { + // binary search + $t = $l-1; + $b = 0; + while ($b <= $t) { + $p = floor(($b+$t)/2); + $d = $inData[$p][0]; + if ($d < $inFindFrom) + $b = $p + 1; + else if ($d > $inFindFrom) + $t = $p - 1; + else { + $b = $p; + break; + } + } + if ($inFindFrom == $inData[$b][0]) { + // add or subtract 1 + $b = ($inFindForward ? ($b+1 > $l-1 ? 0 : $b+1) : ($b-1 < 0 ? $l-1 : $b-1) ); + } + else if (!$inFindForward) + // subtract 1 + $b = ($b-1 < 0 ? $l-1 : $b-1); + } + return $inData[$b][0]; + } + + function buildFindWhere($inFindData, $inKey, $inCol) { + $o = Array(); + foreach($inFindData as $row) + $o[] = $inCol . "='" . $row[$inKey] . "'"; + return (count($o) ? ' WHERE ' . implode(' OR ', $o) : ''); + } + + function find($inFindCol, $inFind='', $inOb='', $inFindFrom=0, $inFindForward=true, $inFullText=true) { + global $table; + // build order by clause + $desc = (boolean)getPostString("desc"); + if (!$inOb) + $inOb = getOrderBy(); + if ($inOb) + $inOb = "`" . $inOb . "`" ; + $orderby = ($inOb ? " ORDER BY $inOb " . ($desc ? " DESC" : "") : ""); + // update inputs from post + if (!$inFind) + $inFind = getPostString('findText'); + if (!$inFindCol) + $inFindCol = getPostString('findCol'); + if (empty($inFindFrom)) + $inFindFrom = getPostString('findFrom'); + $ff = getPostString('findForward'); + if ($ff) + $inFindForward = (strtolower($ff) == 'true' ? true : false); + $ft = getPostString('findFullText'); + if ($ft) + $inFullText = (strtolower($ft) == 'true' ? true : false); + + // get find data + $f = findData($inFindCol, $inFind, $orderby, $inFullText); + $pk = getPk(); + + // execute query + $where = buildFindWhere($f, $pk->index, 'f'); + $query = "SELECT Row, f FROM (SELECT @row := @row + 1 AS Row, $pk->name as f FROM `$table` $orderby) AS tempTable $where"; + mysql_query('SET @row = -1;'); + if (!$result = mysql_query($query)) + error("failed to perform query: $query. " . mysql_error()); + + // return row number + return findRow(getArray($result), $inFindFrom, $inFindForward); + } + + // our command list + $cmds = array( + "count" => "rowcount", + "select" => "select", + "update" => "update", + "insert" => "insert", + "delete" => "delete", + "find" => "find", + "databases" => "getDatabases", + "tables" => "getTables", + "columns" => "getColumns", + "info" => "getTableInfo" + ); + + // process input params + $cmd = @$_POST["command"]; + + //$cmd="select"; + + // dispatch command + $func = @$cmds[$cmd]; + if (function_exists($func)) + echoJson(call_user_func($func)); + else + error("bad command"); +?> diff --git a/includes/js/dojox/grid/tests/support/geography.xml b/includes/js/dojox/grid/tests/support/geography.xml new file mode 100644 index 0000000..070a8c1 --- /dev/null +++ b/includes/js/dojox/grid/tests/support/geography.xml @@ -0,0 +1,51 @@ + + + + geography.opml + 2006-11-10 + 2006-11-13 + Magellan, Ferdinand + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/includes/js/dojox/grid/tests/support/json.php b/includes/js/dojox/grid/tests/support/json.php new file mode 100644 index 0000000..84e3dfa --- /dev/null +++ b/includes/js/dojox/grid/tests/support/json.php @@ -0,0 +1,794 @@ + +* @author Matt Knapp +* @author Brett Stimmerman +* @copyright 2005 Michal Migurski +* @license http://www.opensource.org/licenses/bsd-license.php +* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 +*/ + +/** +* Marker constant for Services_JSON::decode(), used to flag stack state +*/ +define('SERVICES_JSON_SLICE', 1); + +/** +* Marker constant for Services_JSON::decode(), used to flag stack state +*/ +define('SERVICES_JSON_IN_STR', 2); + +/** +* Marker constant for Services_JSON::decode(), used to flag stack state +*/ +define('SERVICES_JSON_IN_ARR', 4); + +/** +* Marker constant for Services_JSON::decode(), used to flag stack state +*/ +define('SERVICES_JSON_IN_OBJ', 8); + +/** +* Marker constant for Services_JSON::decode(), used to flag stack state +*/ +define('SERVICES_JSON_IN_CMT', 16); + +/** +* Behavior switch for Services_JSON::decode() +*/ +define('SERVICES_JSON_LOOSE_TYPE', 10); + +/** +* Behavior switch for Services_JSON::decode() +*/ +define('SERVICES_JSON_STRICT_TYPE', 11); + +/** +* Encodings +*/ +define('SERVICES_JSON_ISO_8859_1', 'iso-8859-1'); +define('SERVICES_JSON_UTF_8', 'utf-8'); + +/** +* Converts to and from JSON format. +* +* Brief example of use: +* +* +* // create a new instance of Services_JSON +* $json = new Services_JSON(); +* +* // convert a complexe value to JSON notation, and send it to the browser +* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); +* $output = $json->encode($value); +* +* print($output); +* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] +* +* // accept incoming POST data, assumed to be in JSON notation +* $input = file_get_contents('php://input', 1000000); +* $value = $json->decode($input); +* +*/ +class Services_JSON +{ + /** + * constructs a new JSON instance + * + //>> SJM2005 + * @param string $encoding Strings are input/output in this encoding + * @param int $encode Encode input is expected in this character encoding + //<< SJM2005 + * + * @param int $use object behavior: when encoding or decoding, + * be loose or strict about object/array usage + * + * possible values: + * - SERVICES_JSON_STRICT_TYPE: strict typing, default. + * "{...}" syntax creates objects in decode(). + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays in decode(). + */ + function Services_JSON($encoding = SERVICES_JSON_UTF_8, $use = SERVICES_JSON_STRICT_TYPE) + { + //>> SJM2005 + $this->encoding = $encoding; + //<< SJM2005 + + $this->use = $use; + } + + /** + * convert a string from one UTF-16 char to one UTF-8 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch(true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + function utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return string JSON string representation of input var + * @access public + */ + function encode($var) + { + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + //>> SJM2005 + if ($this->encoding == SERVICES_JSON_UTF_8) + ; + else if ($this->encoding == SERVICES_JSON_ISO_8859_1) + $var = utf8_encode($var); + else if (!function_exists('mb_convert_encoding')) + die('Requested encoding requires mb_strings extension.'); + else + $var = mb_convert_encoding($var, "utf-8", $this->encoding); + //<< SJM2005 + + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + return '{' . + join(',', array_map(array($this, 'name_value'), + array_keys($var), + array_values($var))) + . '}'; + } + + // treat it like a regular array + return '[' . join(',', array_map(array($this, 'encode'), $var)) . ']'; + + case 'object': + $vars = get_object_vars($var); + return '{' . + join(',', array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars))) + . '}'; + + default: + return ''; + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + function name_value($name, $value) + { + return $this->encode(strval($name)) . ':' . $this->encode($value); + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').+(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + //echo ' matching single escaped unicode character from ' . substr($chrs, $c, 6); + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) + . chr(hexdec(substr($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + //>> SJM2005 + if ($this->encoding == SERVICES_JSON_UTF_8) + return $utf8; + if ($this->encoding == SERVICES_JSON_ISO_8859_1) + return utf8_decode($utf8); + else if (!function_exists('mb_convert_encoding')) + die('Requested encoding requires mb_strings extension.'); + else + return mb_convert_encoding($utf8, $this->encoding, SERVICES_JSON_UTF_8); + //<< SJM2005 + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + if ($str{0} == '[') { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, + 'where' => 0, + 'delim' => false)); + + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } + + } + + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + //>> SAO2006 + /*} elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == SERVICES_JSON_IN_STR) && + (($chrs{$c - 1} != '\\') || + ($chrs{$c - 1} == '\\' && $chrs{$c - 2} == '\\'))) {*/ + } elseif ($chrs{$c} == $top['delim'] && + $top['what'] == SERVICES_JSON_IN_STR) { + //print("Found potential end of string at {$c}\n"); + // verify quote is not escaped: it has no or an even number of \\ before it. + for ($i=0; ($chrs{$c - ($i+1)} == '\\'); $i++); + /*$i = 0; + while ( $chrs{$c - ($i+1)} == '\\') + $i++;*/ + //print("Found {$i} \ before delim\n"); + if ($i % 2 != 0) + { + //print("delim escaped, not end of string\n"); + continue; + } + //>> SAO2006 + // found a quote, we're in a string, and it's not escaped + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); + + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + return $obj; + + } + + } + } + } + +} + + /*function hex($s) + { + $l = strlen($s); + for ($i=0; $i < $l; $i++) + //echo '['.(ord($s{$i})).']'; + echo '['.bin2hex($s{$i}).']'; + } + + //$d = '["hello world\\""]'; + $d = '["\\\\\\"hello world,\\\\\\""]'; + //$d = '["\\\\", "\\\\"]'; + hex($d); + $test = new Services_JSON(); + echo('
      ');
      +	print_r($d . "\n");
      +	print_r($test->decode($d));
      +	echo('
      '); + */ +?> \ No newline at end of file diff --git a/includes/js/dojox/grid/tests/support/movies.csv b/includes/js/dojox/grid/tests/support/movies.csv new file mode 100644 index 0000000..baf71eb --- /dev/null +++ b/includes/js/dojox/grid/tests/support/movies.csv @@ -0,0 +1,9 @@ +Title, Year, Producer +City of God, 2002, Katia Lund +Rain,, Christine Jeffs +2001: A Space Odyssey, , Stanley Kubrick +"This is a ""fake"" movie title", 1957, Sidney Lumet +Alien, 1979 , Ridley Scott +"The Sequel to ""Dances With Wolves.""", 1982, Ridley Scott +"Caine Mutiny, The", 1954, "Dymtryk ""the King"", Edward" + diff --git a/includes/js/dojox/grid/tests/support/test_data.js b/includes/js/dojox/grid/tests/support/test_data.js new file mode 100644 index 0000000..4707380 --- /dev/null +++ b/includes/js/dojox/grid/tests/support/test_data.js @@ -0,0 +1,30 @@ +// example sample data and code +(function(){ + // some sample data + // global var "data" + data = [ + [ "normal", false, "new", 'But are not followed by two hexadecimal', 29.91, 10, false ], + [ "important", false, "new", 'Because a % sign always indicates', 9.33, -5, false ], + [ "important", false, "read", 'Signs can be selectively', 19.34, 0, true ], + [ "note", false, "read", 'However the reserved characters', 15.63, 0, true ], + [ "normal", false, "replied", 'It is therefore necessary', 24.22, 5.50, true ], + [ "important", false, "replied", 'To problems of corruption by', 9.12, -3, true ], + [ "note", false, "replied", 'Which would simply be awkward in', 12.15, -4, false ] + ]; + var rows = 100; + for(var i=0, l=data.length; i{text}', {href: inData[0], text: inData[1] }); +}; + +formatImage = function(inData, inRowIndex) { + if (!inData[0] || !inData[1]) + return ' '; + var o = { + href: inData[0], + src: inData[1].Url, + width: inData[1].Width, + height: inData[1].Height + } + return turbo.supplant('', o); +}; + +formatDate = function(inDatum, inRowIndex) { + if (inDatum == '') + return ' '; + var d = new Date(inDatum * 1000); + return turbo.printf('%s/%s/%s', d.getMonth(), d.getDate(), d.getFullYear()); +}; + +formatDimensions = function(inData, inRowIndex) { + if (!inData[0] || !inData[1]) + return ' '; + return inData[0] + ' x ' + inData[1]; +} diff --git a/includes/js/dojox/grid/tests/test_change_structure.html b/includes/js/dojox/grid/tests/test_change_structure.html new file mode 100644 index 0000000..4ecfa71 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_change_structure.html @@ -0,0 +1,124 @@ + + + + dojox.Grid Change Structure Example + + + + + + + +
      dojox.VirtualGrid Change Structure Example
      +

      + +

      +
      + + + diff --git a/includes/js/dojox/grid/tests/test_custom_sort.html b/includes/js/dojox/grid/tests/test_custom_sort.html new file mode 100644 index 0000000..51b0cf3 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_custom_sort.html @@ -0,0 +1,86 @@ + + + + Custom Sort Test - dojox.Grid + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      dojox.Grid Custom Sort Test
      +
      +Column 3's data field has a custom sorter that sorts by the 2nd letter in the string. +

      +
      + + diff --git a/includes/js/dojox/grid/tests/test_dojo_data_edit.html b/includes/js/dojox/grid/tests/test_dojo_data_edit.html new file mode 100644 index 0000000..7c9bc5c --- /dev/null +++ b/includes/js/dojox/grid/tests/test_dojo_data_edit.html @@ -0,0 +1,124 @@ + + + + Test dojox.Grid Editing with DojoData model + + + + + + + + +

      + dojox.Grid Basic Editing test +

      +
      +     +     +     + +     + +     + + +     + +     +   +
      + + + + +
      +
      + + +
      +
      + + + + + diff --git a/includes/js/dojox/grid/tests/test_dojo_data_empty.html b/includes/js/dojox/grid/tests/test_dojo_data_empty.html new file mode 100644 index 0000000..3096491 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_dojo_data_empty.html @@ -0,0 +1,63 @@ + + + +dojox.Grid with Dojo.Data via binding + + + + + + + +
      dojox.Grid using initially-empty Dojo.Data write stores and then adding an item. Item should show up correctly (no "?"s) when added.
      +
      + + +
      +
      + + + \ No newline at end of file diff --git a/includes/js/dojox/grid/tests/test_dojo_data_model.html b/includes/js/dojox/grid/tests/test_dojo_data_model.html new file mode 100644 index 0000000..fb8e200 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_dojo_data_model.html @@ -0,0 +1,84 @@ + + + + dojox.Grid with Dojo.Data via binding + + + + + + + +
      dojox.Grid using Dojo.Data stores via simple binding
      + + + + +
      +
      + + + + + +
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_dojo_data_model_EmptyResultSet.html b/includes/js/dojox/grid/tests/test_dojo_data_model_EmptyResultSet.html new file mode 100644 index 0000000..8a9048a --- /dev/null +++ b/includes/js/dojox/grid/tests/test_dojo_data_model_EmptyResultSet.html @@ -0,0 +1,57 @@ + + + + dojox.Grid with Dojo.Data via binding + + + + + + + +
      dojox.Grid using Dojo.Data stores where a query returns no results. No errors should be reported in Firebug and the grid should be empty
      +
      + + + + +
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_dojo_data_model_multiStores.html b/includes/js/dojox/grid/tests/test_dojo_data_model_multiStores.html new file mode 100644 index 0000000..46554e3 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_dojo_data_model_multiStores.html @@ -0,0 +1,291 @@ + + + + dojox.Grid with Dojo.Data via binding. Multiple Store implementations. + + + + + + + + +

      dojox.Grid using Dojo.Data stores via simple binding with multiple store implementations.

      +

      + This page demonstrates the Grid can display data accessed by dojo.data implementing Datastores. + Each of the datastores used stores data in a different format, and as this test and demonstration + page shows, the logic for rendering the data is virtually identical. You define your source store, + you define the model for accessing the data, which is ij this case the dojox.grid.data.DojoData model + and then you define the layout, which maps the data attribute names to columns in the grid. You can + even perform cusomization of what is displayed, as demonstrated in the dojox.data.FlickrStore layout. + The image url is displayed as a clickable link that opens a new page. +

      +

      + The choice of stores used were ones that did not require back end services to function for sake of + simplicity. There is no reason that dojox.data.QueryReadStore could not be used with grid as well, + it just requires a back end service to send it the query results. +

      +

      Stores used:

      +
        +
      • dojo.data.ItemFileReadStore
      • +
      • dojox.data.CvsStore
      • +
      • dojox.data.XmlStore
      • +
      • dojox.data.FlickrStore
      • +
      • dojox.data.OpmlStore
      • +
      • dojox.data.HtmlTableStore
      • +
      + +

      dojo.data.ItemFileReadStore:

      + Displays a list of countries through ItemFileReadStore format. + + + + +
      +
      + + +

      dojox.data.CsvStore:

      + Displays a list of movies that were stored in CSV format. + + + + +
      + +
      + +

      dojox.data.XmlStore:

      + Displays a list of books that were stored in XML format. + + + + +
      +
      + + +

      dojox.data.FlickrStore:

      + Displays Flickr imformation on 3DNY (Dojo Developer Days, New York) from the flickr public photo feed, accessed via the FlickrStore dojo.data implementation. + + + + +
      +
      + + +

      dojox.data.OpmlStore:

      + Scans an Opml based document for all items of type 'country' + + + + +
      +
      + + +

      dojox.data.HtmlStore:

      + Loads the grid from an HTML Table. + + + + +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/includes/js/dojox/grid/tests/test_dojo_data_model_processError.html b/includes/js/dojox/grid/tests/test_dojo_data_model_processError.html new file mode 100644 index 0000000..4130043 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_dojo_data_model_processError.html @@ -0,0 +1,65 @@ + + + + dojox.Grid with Dojo.Data model with trapping of data store errors. + + + + + + + + +

      dojox.Grid using Dojo.Data stores via simple binding

      + +

      dojox.data.CsvStore:

      . + This grid does not load data. The data store references a non-existent URL on purpose. It should trigger a failure that we catch and display in an alert + + + + + + +
      +
      + + + + diff --git a/includes/js/dojox/grid/tests/test_dojo_data_notification.html b/includes/js/dojox/grid/tests/test_dojo_data_notification.html new file mode 100644 index 0000000..f44c987 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_dojo_data_notification.html @@ -0,0 +1,114 @@ + + + + dojox.Grid with Dojo.Data via binding + + + + + + + +

      dojox.Grid using Dojo.Data stores via simple binding

      + +
      +

      Update some of the types

      + + + + + + + +
      +
      + +
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_edit.html b/includes/js/dojox/grid/tests/test_edit.html new file mode 100644 index 0000000..7ae1fdb --- /dev/null +++ b/includes/js/dojox/grid/tests/test_edit.html @@ -0,0 +1,149 @@ + + + + +Test dojox.Grid Editing + + + + + + + + + + + + + + + + + + + + + + + + + + +

      + dojox.Grid Basic Editing test +

      +
      +     + +     + +     + +     +   +
      +
      +
      +
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_edit_canEdit.html b/includes/js/dojox/grid/tests/test_edit_canEdit.html new file mode 100644 index 0000000..ed4e919 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_edit_canEdit.html @@ -0,0 +1,156 @@ + + + + +Test dojox.Grid Editing + + + + + + + + + + + + + + + + + + + + + + + + + + +

      + dojox.Grid Basic Editing test +

      +
      +     + +     + +     + +     +   +
      +
      +
      +
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_edit_dijit.html b/includes/js/dojox/grid/tests/test_edit_dijit.html new file mode 100644 index 0000000..484c7e5 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_edit_dijit.html @@ -0,0 +1,137 @@ + + + + + Test dojox.Grid Editing + + + + + + +

      dojox.Grid Basic Editing test

      +
      +
      + + + + + + + + +
      +
      +
      +
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_events.html b/includes/js/dojox/grid/tests/test_events.html new file mode 100644 index 0000000..8ea61a4 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_events.html @@ -0,0 +1,174 @@ + + + + Test dojox.Grid Events + + + + + + + +

      dojox.Grid Event Tracking

      +
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_expand.html b/includes/js/dojox/grid/tests/test_expand.html new file mode 100644 index 0000000..220c2a8 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_expand.html @@ -0,0 +1,107 @@ + + + + Test dojox.Grid Expand Rows + + + + + + + +
      dojox.Grid Expand Row Example
      + +
      + + + diff --git a/includes/js/dojox/grid/tests/test_grid.html b/includes/js/dojox/grid/tests/test_grid.html new file mode 100644 index 0000000..59d18dc --- /dev/null +++ b/includes/js/dojox/grid/tests/test_grid.html @@ -0,0 +1,69 @@ + + + + Test dojox.Grid Basic + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      dojox.Grid Basic Test
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_grid_dlg.html b/includes/js/dojox/grid/tests/test_grid_dlg.html new file mode 100644 index 0000000..7479e15 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_grid_dlg.html @@ -0,0 +1,88 @@ + + + + Test dojox.Grid Basic + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      dojox.Grid Basic Test
      + +
      + + + +
      +
      + + + diff --git a/includes/js/dojox/grid/tests/test_grid_headerHeight.html b/includes/js/dojox/grid/tests/test_grid_headerHeight.html new file mode 100644 index 0000000..b9960c4 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_grid_headerHeight.html @@ -0,0 +1,84 @@ + + + + Test dojox.Grid Basic + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      dojox.Grid Basic Test
      +
      +

      +
      + + diff --git a/includes/js/dojox/grid/tests/test_grid_layout.html b/includes/js/dojox/grid/tests/test_grid_layout.html new file mode 100644 index 0000000..148025d --- /dev/null +++ b/includes/js/dojox/grid/tests/test_grid_layout.html @@ -0,0 +1,112 @@ + + + + dojox.Grid in Layout Demo + + + + + + + + + + +
      +
      + top bar +
      +
      + bottom bar +
      +
      +
      + Left side +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_grid_layout_LayoutContainer.html b/includes/js/dojox/grid/tests/test_grid_layout_LayoutContainer.html new file mode 100644 index 0000000..4cf12ac --- /dev/null +++ b/includes/js/dojox/grid/tests/test_grid_layout_LayoutContainer.html @@ -0,0 +1,87 @@ + + + + dojox.Grid in Layout Demo + + + + + + + + + + +
      + +
      + top bar +
      +
      + bottom bar +
      + +
      + + +
      + + diff --git a/includes/js/dojox/grid/tests/test_grid_layout_borderContainer.html b/includes/js/dojox/grid/tests/test_grid_layout_borderContainer.html new file mode 100644 index 0000000..8f0d8d7 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_grid_layout_borderContainer.html @@ -0,0 +1,98 @@ + + + + Test dojox.Grid Editing + + + + + + + + +
      + +
      + +
      + + + + + + + + +
      +
      + +
      +
      +
      + +
      + + + diff --git a/includes/js/dojox/grid/tests/test_grid_object_model_change.html b/includes/js/dojox/grid/tests/test_grid_object_model_change.html new file mode 100644 index 0000000..54c6808 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_grid_object_model_change.html @@ -0,0 +1,86 @@ + + + + Test dojox.grid.data.Objects model change + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      dojox.grid.data.Objects model change
      +
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_grid_programmatic.html b/includes/js/dojox/grid/tests/test_grid_programmatic.html new file mode 100644 index 0000000..fe0794f --- /dev/null +++ b/includes/js/dojox/grid/tests/test_grid_programmatic.html @@ -0,0 +1,65 @@ + + + + Test dojox.Grid Programmatic Instantiation + + + + + + + + +
      dojox.Grid Programmatic Instantiation Test
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_grid_programmatic_layout.html b/includes/js/dojox/grid/tests/test_grid_programmatic_layout.html new file mode 100644 index 0000000..b55d975 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_grid_programmatic_layout.html @@ -0,0 +1,74 @@ + + + + Test dojox.Grid Programmatic Instantiation + + + + + + + + +
      dojox.Grid Programmatic Instantiation Test
      +
      +
      + ... stuff ... +
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_grid_rtl.html b/includes/js/dojox/grid/tests/test_grid_rtl.html new file mode 100644 index 0000000..c1b253d --- /dev/null +++ b/includes/js/dojox/grid/tests/test_grid_rtl.html @@ -0,0 +1,71 @@ + + + + Test dojox.Grid Basic + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      dojox.Grid Basic Test
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_grid_themes.html b/includes/js/dojox/grid/tests/test_grid_themes.html new file mode 100644 index 0000000..e0f80f6 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_grid_themes.html @@ -0,0 +1,118 @@ + + + + dojox.Grid themes + + + + + + + +
      dojox.grid.Grid structure from markup (tundra theme)
      + + + + + + + + + + + + + + +
      Title of MovieYear
      Producer
      + + + +
      Locked views specified with tables and colgroups (soria theme)
      + + + + + + + + + + + + + + + +
      Country/Continent NamePopulationLand MassTime ZoneType
      + +
      A "regular" Grid from markup (no table defintion, nihilo theme)
      + + + + +
      +
      + + + diff --git a/includes/js/dojox/grid/tests/test_grid_tooltip_menu.html b/includes/js/dojox/grid/tests/test_grid_tooltip_menu.html new file mode 100644 index 0000000..52c7726 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_grid_tooltip_menu.html @@ -0,0 +1,161 @@ + + + + Test dojox.Grid Basic + + + + + + + + + + + +
      dojox.Grid Basic Test
      +

      +    +   
      + Note: when the grid menu is disabled, the document's dijit context menu should be shown over the grid. +

      +
      + + diff --git a/includes/js/dojox/grid/tests/test_keyboard.html b/includes/js/dojox/grid/tests/test_keyboard.html new file mode 100644 index 0000000..69d4046 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_keyboard.html @@ -0,0 +1,90 @@ + + + + Test dojox.Grid Basic + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      dojox.Grid Basic Test
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_markup.html b/includes/js/dojox/grid/tests/test_markup.html new file mode 100644 index 0000000..7c57710 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_markup.html @@ -0,0 +1,112 @@ + + + + dojox.Grid with Dojo.Data via binding + + + + + + +
      dojox.grid.Grid structure from markup
      + + + + + + + + + + + + + +
      Title of MovieYear
      Producer
      + + + + +
      Locked views specified with tables and colgroups
      + + + + + + + + + + + + + +
      Country/Continent NamePopulationLand MassTime ZoneType
      + +
      A "regular" Grid from markup (no table defintion)
      + + + +
      +
      + + + diff --git a/includes/js/dojox/grid/tests/test_mysql_edit.html b/includes/js/dojox/grid/tests/test_mysql_edit.html new file mode 100644 index 0000000..dd6a762 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_mysql_edit.html @@ -0,0 +1,155 @@ + + + + dojox.Grid Test: Mysql Table Editing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      dojox.Grid Test: Mysql Table Editing

      +
      +    +    +    +    + +

      +
      +
      +

      Note: This test requires MySql and PHP and works with the database table available in support/testtbl.sql.

      + + diff --git a/includes/js/dojox/grid/tests/test_sizing.html b/includes/js/dojox/grid/tests/test_sizing.html new file mode 100644 index 0000000..fdd0897 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_sizing.html @@ -0,0 +1,175 @@ + + + + dojox.Grid Sizing Example + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      dojox.Grid Sizing Test
      + Grid width:   + and height:   +

      +   +   + +

      +
      + +

      Grid fits to a sized container by default:

      +
      +
      +
      + +

      Grid is essentially hidden (height of zero) when parent container is unsized + (nothing, including the header, should be displayed):

      +
      +
      +
      + +

      Grid is autoHeight and autoWidth via markup

      +
      + + diff --git a/includes/js/dojox/grid/tests/test_sizing_100rows.html b/includes/js/dojox/grid/tests/test_sizing_100rows.html new file mode 100644 index 0000000..4ea1aa3 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_sizing_100rows.html @@ -0,0 +1,168 @@ + + + + dojox.Grid Sizing Example + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      dojox.Grid Sizing Test
      + Grid width:   + and height:   +

      +   +   + +

      +
      + +

      Grid fits to a sized container by default:

      +
      +
      +
      + +

      Grid is essentially hidden (height of zero) when parent container is unsized + (nothing, including the header, should be displayed):

      +
      +
      +
      + +

      Grid is autoHeight and autoWidth via markup

      +
      + + diff --git a/includes/js/dojox/grid/tests/test_sizing_ResizeHandle.html b/includes/js/dojox/grid/tests/test_sizing_ResizeHandle.html new file mode 100644 index 0000000..d6809df --- /dev/null +++ b/includes/js/dojox/grid/tests/test_sizing_ResizeHandle.html @@ -0,0 +1,113 @@ + + + + dojox.Grid Sizing Example + + + + + + + + +
      dojox.Grid Sizing Test w/ the experimental dojox.layout.ResizeHandle
      + +

      While this test should work, dojox.layout.ResizeHandle is experimental.

      + +
      +
      +
      +
      + +

      Grid fits to a sized container by default:

      +
      +
      +
      +
      + +

      I am here to take up

      + +

      space

      + +

      as much as needed.

      + + + diff --git a/includes/js/dojox/grid/tests/test_styling.html b/includes/js/dojox/grid/tests/test_styling.html new file mode 100644 index 0000000..5671f50 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_styling.html @@ -0,0 +1,131 @@ + + + + dojox.Grid Styling Test + + + + + + + + +
      dojox.Grid Styling Example
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_subgrid.html b/includes/js/dojox/grid/tests/test_subgrid.html new file mode 100644 index 0000000..4e5b8cd --- /dev/null +++ b/includes/js/dojox/grid/tests/test_subgrid.html @@ -0,0 +1,179 @@ + + + +dojox.Grid Subgrid Test + + + + + + + + + +
      dojox.Grid showing sub-grid.
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_tundra_edit.html b/includes/js/dojox/grid/tests/test_tundra_edit.html new file mode 100644 index 0000000..0aa2eeb --- /dev/null +++ b/includes/js/dojox/grid/tests/test_tundra_edit.html @@ -0,0 +1,139 @@ + + + + Test dojox.Grid Editing + + + + + + +

      dojox.Grid Basic Editing test

      +
      +
      + + + + + + + + +
      +
      +
      +
      +
      + + diff --git a/includes/js/dojox/grid/tests/test_yahoo_images.html b/includes/js/dojox/grid/tests/test_yahoo_images.html new file mode 100644 index 0000000..fbab070 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_yahoo_images.html @@ -0,0 +1,148 @@ + + + + dojox.Grid - Image Search Test + + + + + + + + +
      dojox.Grid - Image Search Test
      + + +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      +

      Note: requires PHP for proxy.

      + + diff --git a/includes/js/dojox/grid/tests/test_yahoo_search.html b/includes/js/dojox/grid/tests/test_yahoo_search.html new file mode 100644 index 0000000..063c289 --- /dev/null +++ b/includes/js/dojox/grid/tests/test_yahoo_search.html @@ -0,0 +1,141 @@ + + + + dojox.Grid - Yahoo Search Test + + + + + + + + +
      dojox.Grid - Yahoo Search Test
      +
      +    + +
      +   +

      +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      +

      Note: requires PHP for proxy.

      + + diff --git a/includes/js/dojox/grid/tests/yahooSearch.js b/includes/js/dojox/grid/tests/yahooSearch.js new file mode 100644 index 0000000..1d57a8e --- /dev/null +++ b/includes/js/dojox/grid/tests/yahooSearch.js @@ -0,0 +1,137 @@ +dojo.require("dojo.io.script") +dojo.require("dojox.rpc.Service"); + +// model that works with Yahoo Search API +dojo.declare("dojox.grid.data.yahooSearch", dojox.grid.data.Dynamic, { + constructor: function(inFields, inData, inSearchNode){ + this.rowsPerPage = 20; + this.searchNode = inSearchNode; + this.fieldNames = dojo.map(inFields, "return item.name;"); + this.yahoo = new dojox.rpc.Service( + dojo.moduleUrl("dojox.rpc.SMDLibrary", "yahoo.smd") + ); + }, + // server send / receive + send: function(inAsync, inParams, inOnReceive, inOnError){ + var d = this.yahoo.imageSearch( + dojo.mixin({ + results: this.rowsPerPage, + query: this.getQuery() + }, inParams) + ); + d.addCallbacks( + dojo.hitch(this, "receive", inOnReceive, inOnError), + dojo.hitch(this, "error", inOnError) + ); + this.onSend(inParams); + return d; + }, + receive: function(inOnReceive, inOnError, inData){ + try{ + inData = inData.ResultSet; + inOnReceive(inData); + this.onReceive(inData); + }catch(e){ + if(inOnError){ + inOnError(inData); + } + } + }, + error: function(inOnError, inErr) { + var m = 'io error: ' + inErr.message; + alert(m); + if (inOnError) + inOnError(m); + }, + encodeParam: function(inName, inValue) { + return dojo.string.substitute('&${0}=${1}', [inName, inValue]); + }, + getQuery: function(){ + return dojo.byId(this.searchNode).value.replace(/ /g, '+'); + }, + fetchRowCount: function(inCallback){ + this.send(true, inCallback); + }, + // request data + requestRows: function(inRowIndex, inCount){ + inRowIndex = (inRowIndex == undefined ? 0 : inRowIndex); + var params = { + start: inRowIndex + 1 + } + this.send(true, params, dojo.hitch(this, this.processRows)); + }, + // server callbacks + processRows: function(inData){ + for(var i=0, l=inData.totalResultsReturned, s=inData.firstResultPosition; i${text}', + { href: inData, text: text } + ); +}; + +formatImage = function(inData, inRowIndex){ + if(!inData){ return ' '; } + var info = getCellData(this, inRowIndex, this.extraField); + var o = { + href: inData, + src: info.Url, + width: info.Width, + height: info.Height + } + return dojo.string.substitute( + '', o); +}; + +formatDate = function(inDatum, inRowIndex){ + if(!inDatum){ return ' '; } + var d = new Date(inDatum * 1000); + return dojo.string.substitute( + "${0}/${1}/${2}", + [ d.getMonth()+1, d.getDate(), d.getFullYear() ] + ); +}; + +formatDimensions = function(inData, inRowIndex){ + if(!inData){ return ' '; } + var w = inData, h = getCellData(this, inRowIndex, this.extraField); + return w + ' x ' + h; +} diff --git a/includes/js/dojox/help/README b/includes/js/dojox/help/README new file mode 100644 index 0000000..00a69a8 --- /dev/null +++ b/includes/js/dojox/help/README @@ -0,0 +1,35 @@ +------------------------------------------------------------------------------- +dojox.help +------------------------------------------------------------------------------- +Version 0.0 +Release date: 3/13/2008 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + Neil Roberts (pottedmeat@dojotoolkit.org) + Wolfram Kriesing (wolfram@kriesing.de) +------------------------------------------------------------------------------- +Project description + +Provide functionality for quick access to available documentation while +working in the browser. +------------------------------------------------------------------------------- +Dependencies: + +dojo +dojox.rpc +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/help/* + +Install into the following directory structure: +/dojox/help/ + +...which should be at the same level as your Dojo checkout. + +And run: dojo.require("dojox.help.console") in your console +------------------------------------------------------------------------------- diff --git a/includes/js/dojox/help/_base.js b/includes/js/dojox/help/_base.js new file mode 100644 index 0000000..109f3ca --- /dev/null +++ b/includes/js/dojox/help/_base.js @@ -0,0 +1,473 @@ +if(!dojo._hasResource["dojox.help._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.help._base"] = true; +dojo.provide("dojox.help._base"); +dojo.require("dojox.rpc.Service"); +dojo.require("dojo.io.script"); + +dojo.experimental("dojox.help"); +console.warn("Script causes side effects (on numbers, strings, and booleans). Call dojox.help.noConflict() if you plan on executing code."); + +dojox.help = { + // summary: + // Adds the help function to all variables. + locate: function(/*String*/ searchFor, /*String|Object|String[]|Object[]*/ searchIn, /*Number*/ maxResults){ + // summary: + // Search for dojo functionality that has something to do with the given string. + // description: + // Search for locally available data; variable names and any cached + // documentation results for matches containing our search parameter + // searchFor + // The string to search for. + // searchIn: + // The namespaces to search in. Defaults to dojox.help._namespaces + // maxResults: + // The maximum number of results. + maxResults = maxResults || 20; + var namespaces = []; + var roots = {}; + var root; + if(searchIn){ + if(!dojo.isArray(searchIn)){ + searchIn = [searchIn]; + } + for(var i = 0, namespace; namespace = searchIn[i]; i++){ + root = namespace; + if(dojo.isString(namespace)){ + namespace = dojo.getObject(namespace); + if(!namespace){ + continue; + } + }else if(dojo.isObject(namespace)){ + root = namespace.__name__; + }else{ + continue; + } + // Add to a list of namespace objects (in object form) + namespaces.push(namespace); + if(root){ + root = root.split(".")[0]; + if(!roots[root] && dojo.indexOf(dojox.help._namespaces, root) == -1){ + // Refresh anything that's not part of our global namespace list + dojox.help.refresh(root); + } + roots[root] = true; + } + } + } + if(!namespaces.length){ + namespaces.push({ __name__: "window" }); + dojo.forEach(dojox.help._namespaces, function(item){ roots[item] = true; }); + } + + var found = []; + out: + for(var i = 0, namespace; namespace = namespaces[i]; i++){ + var name = namespace.__name__ || ""; + var shorter = dojo.some(namespaces, function(item){ + // Return true if we find a namespace below + // the current namespace + item = item.__name__ || ""; + return (name.indexOf(item + ".") == 0); + }); + if(name && !shorter){ + root = name.split(".")[0]; + var names = []; + if(name == "window"){ + for(root in dojox.help._names){ + if(dojo.isArray(dojox.help._names[root])){ + names = names.concat(dojox.help._names[root]); + } + } + }else{ + names = dojox.help._names[root]; + } + for(var j = 0, variable; variable = names[j]; j++){ + if((name == "window" || variable.indexOf(name + ".") == 0) && variable.toLowerCase().indexOf(searchFor) != -1){ + if(variable.slice(-10) == ".prototype"){ continue; } + var obj = dojo.getObject(variable); + if(obj){ + found.push([variable, obj]); + if(found.length == maxResults){ + break out; + } + } + } + } + } + } + + dojox.help._displayLocated(found); + if(!+dojo.isFF){ + return ""; + } + }, + refresh: function(/*String?*/ namespace, /*Boolean?*/ recursive){ + // summary: + // Useful if you reset some values, and want to restore their + // help function + // namespace: + // The string-representation of a namespace. + // recursive: + // Whether to recurse through the namespace. + if(arguments.length < 2){ + recursive = true; + } + dojox.help._recurse(namespace, recursive); + }, + noConflict: function(/*Object?*/ item){ + // summary: + // Use this function when you want to resolve the problems + // created by including a dojox.help package. + // item: + // If you pass an item, only that item will be cleaned + if(arguments.length){ + return dojox.help._noConflict(item); + }else{ + while(dojox.help._overrides.length){ + var override = dojox.help._overrides.pop(); + var parent = override[0]; + var key = override[1]; + var child = parent[key]; + parent[key] = dojox.help._noConflict(child); + } + } + }, + init: function(/*String[]*/ namespaces, /*Boolen?*/ noConflict){ + // summary: + // Should be called by one of the implementations. Runs startup code + // namespaces: + // Any namespaces to add to the default (dojox.help._namespaces) + // noConflict: + // Whether to start in noConflict mode + if(namespaces){ + dojox.help._namespaces.concat(namespaces); + } + dojo.addOnLoad(function(){ + dojo.require = (function(require){ + return function(){ + dojox.help.noConflict(); + require.apply(dojo, arguments); + if(dojox.help._timer){ + clearTimeout(dojox.help._timer); + } + dojox.help._timer = setTimeout(function(){ + dojo.addOnLoad(function(){ + dojox.help.refresh(); + dojox.help._timer = false; + }); + }, 500); + } + })(dojo.require); + + dojox.help._recurse(); + }); + }, + _noConflict: function(item){ + if(item instanceof String){ + return item.toString(); + }else if(item instanceof Number){ + return +item; + }else if(item instanceof Boolean){ + return (item == true); + }else if(dojo.isObject(item)){ + delete item.__name__; + delete item.help; + } + return item; + }, + _namespaces: ["dojo", "dojox", "dijit", "djConfig"], + _rpc: new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc", "documentation.smd")), + _attributes: ["summary", "type", "returns", "parameters"], + _clean: function(self){ + var obj = {}; + for(var i = 0, attribute; attribute = dojox.help._attributes[i]; i++){ + var value = self["__" + attribute + "__"]; + if(value){ + obj[attribute] = value; + } + } + return obj; + }, + _displayLocated: function(located){ + // summary: + // Stub function to be overridden in one of the dojox.help packages + throw new Error("_displayLocated should be overridden in one of the dojox.help packages"); + }, + _displayHelp: function(loading, obj){ + // summary: + // Stub function to be overridden in one of the dojox.help packages + throw new Error("_displayHelp should be overridden in one of the dojox.help packages"); + }, + _addVersion: function(obj){ + if(obj.name){ + obj.version = [dojo.version.major, dojo.version.minor, dojo.version.patch].join("."); + var parts = obj.name.split("."); + if(parts[0] == "dojo" || parts[0] == "dijit" || parts[0] == "dojox"){ + obj.project = parts[0]; + } + } + return obj; + }, + _stripPrototype: function(original){ + var name = original.replace(/\.prototype(\.|$)/g, "."); + var search = name; + if(name.slice(-1) == "."){ + search = name = name.slice(0, -1); + }else{ + name = original; + } + return [search, name]; + }, + _help: function(){ + var name = this.__name__; + var search = dojox.help._stripPrototype(name)[0]; + var attributes = []; + for(var i = 0, attribute; attribute = dojox.help._attributes[i]; i++){ + if(!this["__" + attribute + "__"]){ + attributes.push(attribute); + } + } + + dojox.help._displayHelp(true, { name: this.__name__ }); + + if(!attributes.length || this.__searched__){ + dojox.help._displayHelp(false, dojox.help._clean(this)); + }else{ + this.__searched__ = true; + dojox.help._rpc.get(dojox.help._addVersion({ + name: search, + exact: true, + attributes: attributes + })).addCallback(this, function(data){ + if(this.toString === dojox.help._toString){ + this.toString(data); + } + if(data && data.length){ + data = data[0]; + for(var i = 0, attribute; attribute = dojox.help._attributes[i]; i++){ + if(data[attribute]){ + this["__" + attribute + "__"] = data[attribute]; + } + } + dojox.help._displayHelp(false, dojox.help._clean(this)); + }else{ + dojox.help._displayHelp(false, false); + } + }); + } + if(!+dojo.isFF){ + return ""; + } + }, + _parse: function(data){ + delete this.__searching__; + if(data && data.length){ + var parameters = data[0].parameters; + + if(parameters){ + var signature = ["function ", this.__name__, "("]; + this.__parameters__ = parameters; + for(var i = 0, parameter; parameter = parameters[i]; i++){ + if(i){ + signature.push(", "); + } + signature.push(parameter.name); + if(parameter.types){ + var types = []; + for(var j = 0, type; type = parameter.types[j]; j++){ + types.push(type.title); + } + if(types.length){ + signature.push(": "); + signature.push(types.join("|")); + } + } + if(parameter.repeating){ + signature.push("..."); + } + if(parameter.optional){ + signature.push("?"); + } + } + signature.push(")"); + + this.__source__ = this.__source__.replace(/function[^\(]*\([^\)]*\)/, signature.join("")); + } + + if(this.__output__){ + delete this.__output__; + console.log(this); + } + }else{ + dojox.help._displayHelp(false, false); + } + }, + _toStrings: {}, + _toString: function(data){ + if(!this.__source__){ + return this.__name__; + } + + var first = (!this.__parameters__); + this.__parameters__ = []; + + if(data){ + dojox.help._parse.call(this, data); + }else if(first){ + this.__searching__ = true; + dojox.help._toStrings[dojox.help._stripPrototype(this.__name__)[0]] = this; + if(dojox.help._toStringTimer){ + clearTimeout(dojox.help._toStringTimer); + } + dojox.help._toStringTimer = setTimeout(function(){ dojox.help.__toString(); }, 50); + } + + if(!first || !this.__searching__){ + return this.__source__; + } + + var message = "function Loading info for " + this.__name__ + "... (watch console for result) {}"; + + if(!+dojo.isFF){ + this.__output__ = true; + return message; + } + + return { + toString: dojo.hitch(this, function(){ + // Detect if this was called by Firebug + this.__output__ = true; + return message; + }) + }; + }, + __toString: function(){ + if(dojox.help._toStringTimer){ + clearTimeout(dojox.help._toStringTimer); + } + + var names = []; + dojox.help.noConflict(dojox.help._toStrings); + for(var name in dojox.help._toStrings){ + names.push(name); + } + while(names.length){ + dojox.help._rpc.batch(dojox.help._addVersion({ + names: names.splice(-50, 50), + exact: true, + attributes: ["parameters"] + })).addCallback(this, function(datas){ + for(var i = 0, data; data = datas[i]; i++){ + fn = dojox.help._toStrings[data.name]; + if(fn){ + dojox.help._parse.call(fn, [data]); + delete dojox.help._toStrings[data.name]; + } + } + }); + } + }, + _overrides: [], + _recursions: [], + _names: {}, + _recurse: function(/*String?*/ namespace, /*Boolean?*/ recursive){ + if(arguments.length < 2){ + recursive = true; + } + + var items = []; + + if(namespace && dojo.isString(namespace)){ + dojox.help.__recurse(dojo.getObject(namespace), namespace, namespace, items, recursive); + }else{ + for(var i = 0, namespace; namespace = dojox.help._namespaces[i]; i++){ + if(window[namespace]){ + dojox.help._recursions.push([window[namespace], namespace, namespace]); + window[namespace].__name__ = namespace; + if(!window[namespace].help){ + window[namespace].help = dojox.help._help; + } + } + } + } + + while(dojox.help._recursions.length){ + var recursion = dojox.help._recursions.shift(); + dojox.help.__recurse(recursion[0], recursion[1], recursion[2], items, recursive); + } + + for(var i = 0, item; item = items[i]; i++){ + delete item.__seen__; + } + }, + __recurse: function(namespace, root, name, items, recursive){ + for(var key in namespace){ + if(key.match(/([^\w_.$]|__[\w_.$]+__)/)){ + continue; + } + + var item = namespace[key]; + if(typeof item == "undefined" + || item === document + || item === window + || item === dojox.help._toString + || item === dojox.help._help + || item === null + || (+dojo.isIE && item.tagName) + || item.__seen__ + ) { + continue; + } + + var isFunction = dojo.isFunction(item); + var isObject = dojo.isObject(item) && !dojo.isArray(item) && !item.nodeType; + + var itemName = (name) ? (name + "." + key) : key; + + if(itemName == "dojo._blockAsync"){ + continue; + } + + if(!item.__name__){ + var parent = null; + if(dojo.isString(item)){ + parent = String; + }else if(typeof item == "number"){ + parent = Number; + }else if(typeof item == "boolean"){ + parent = Boolean; + } + if(parent){ + item = namespace[key] = new parent(item); + } + } + + item.__seen__ = true; + item.__name__ = itemName; + (dojox.help._names[root] = dojox.help._names[root] || []).push(itemName); + items.push(item); + if(!isFunction){ + dojox.help._overrides.push([namespace, key]); + } + + if((isFunction || isObject) && recursive){ + dojox.help._recursions.push([item, root, itemName]); + } + + if(isFunction){ + if(!item.__source__){ + item.__source__ = item.toString().replace(/^function\b ?/, "function " + itemName); + } + if(item.toString === Function.prototype.toString){ + item.toString = dojox.help._toString; + } + } + + if(!item.help){ + item.help = dojox.help._help; + } + } + } +}; + +} diff --git a/includes/js/dojox/help/console.js b/includes/js/dojox/help/console.js new file mode 100644 index 0000000..8474a5a --- /dev/null +++ b/includes/js/dojox/help/console.js @@ -0,0 +1,80 @@ +if(!dojo._hasResource["dojox.help.console"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.help.console"] = true; +dojo.provide("dojox.help.console"); +dojo.require("dojox.help._base"); + +dojo.mixin(dojox.help, { + _plainText: function(str){ + return str.replace(/(<[^>]*>|&[^;]{2,6};)/g, ''); + }, + _displayLocated: function(located){ + var obj = {}; + dojo.forEach(located, function(item){ obj[item[0]] = (+dojo.isFF) ? { toString: function(){ return "Click to view"; }, item: item[1] } : item[1]; }); + console.dir(obj); + }, + _displayHelp: function(loading, obj){ + if(loading){ + var message = "Help for: " + obj.name; + console.log(message); + var underline = ""; + for(var i = 0; i < message.length; i++){ + underline += "="; + } + console.log(underline); + }else if(!obj){ + console.log("No documentation for this object"); + }else{ + var anything = false; + for(var attribute in obj){ + var value = obj[attribute]; + if(attribute == "returns" && obj.type != "Function" && obj.type != "Constructor"){ + continue; + } + if(value && (!dojo.isArray(value) || value.length)){ + anything = true; + console.info(attribute.toUpperCase()); + value = dojo.isString(value) ? dojox.help._plainText(value) : value; + if(attribute == "returns"){ + var returns = dojo.map(value.types || [], "return item.title;").join("|"); + if(value.summary){ + if(returns){ + returns += ": "; + } + returns += dojox.help._plainText(value.summary); + } + console.log(returns || "Uknown"); + }else if(attribute == "parameters"){ + for(var j = 0, parameter; parameter = value[j]; j++){ + var type = dojo.map(parameter.types, "return item.title").join("|"); + console.log((type) ? (parameter.name + ": " + type) : parameter.name); + var summary = ""; + if(parameter.optional){ + summary += "Optional. "; + } + if(parameter.repating){ + summary += "Repeating. "; + } + summary += dojox.help._plainText(parameter.summary); + if(summary){ + summary = " - " + summary; + for(var k = 0; k < parameter.name.length; k++){ + summary = " " + summary; + } + console.log(summary); + } + } + }else{ + console.log(value); + } + } + } + if(!anything){ + console.log("No documentation for this object"); + } + } + } +}); + +dojox.help.init(); + +} diff --git a/includes/js/dojox/help/demos/demo_Console.html b/includes/js/dojox/help/demos/demo_Console.html new file mode 100644 index 0000000..564bb08 --- /dev/null +++ b/includes/js/dojox/help/demos/demo_Console.html @@ -0,0 +1,33 @@ + + + Simple demo of dojox.help.console + + + + +

      You'll want to open up Firebug for this

      +

      Click each of the items below to run the command: +

        +
      • dojo.require("dojox.help.console");
      • +
      • dojox.help.locate("xhr", dojo); searches variable names in the dojo namespaces for "xhr".
      • +
      • dojo.query.help(); displays help for dojo.byId
      • +
      • dojo.connect loads and displays the function signature for dojo.connect
      • +
      • dojo.isBrowser shows an example of a "conflict". It's using the Boolean object rather than the boolean generic.
      • +
      • dojox.help.noConflict(); fixes this conflict (click on dojo.isBrowser again).
      • +
      • dojox.help.refresh(); parses the page again
      • +
      • dojo.isBrowser and the conflict is back again!
      • +
      +

      + + \ No newline at end of file diff --git a/includes/js/dojox/highlight.js b/includes/js/dojox/highlight.js new file mode 100644 index 0000000..04e8d8d --- /dev/null +++ b/includes/js/dojox/highlight.js @@ -0,0 +1,6 @@ +if(!dojo._hasResource["dojox.highlight"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight"] = true; +dojo.provide("dojox.highlight"); +dojo.require("dojox.highlight._base"); + +} diff --git a/includes/js/dojox/highlight/README b/includes/js/dojox/highlight/README new file mode 100644 index 0000000..cdaed12 --- /dev/null +++ b/includes/js/dojox/highlight/README @@ -0,0 +1,31 @@ +------------------------------------------------------------------------------- +dojox.highlight +------------------------------------------------------------------------------- +Version 1.0 +Release date: 11/25/2007 +------------------------------------------------------------------------------- +Project state: +beta +------------------------------------------------------------------------------- +Credits + Ivan Sagalaev (softwaremaniacs.org) Author + Peter Higgins (dante) Dojo port +------------------------------------------------------------------------------- +Project description + +A syntax highlighting engine for the Dojo Toolkit +------------------------------------------------------------------------------- +Dependencies: + +dojo base only. +------------------------------------------------------------------------------- +Documentation + +------------------------------------------------------------------------------- +Installation instructions + +simply get the dojox/highlight folder (and dojox/highlight.js) from the +dojox SVN repository, and include in your page via + +dojo.require("dojox.highlight"); + diff --git a/includes/js/dojox/highlight/_base.js b/includes/js/dojox/highlight/_base.js new file mode 100644 index 0000000..46b5267 --- /dev/null +++ b/includes/js/dojox/highlight/_base.js @@ -0,0 +1,406 @@ +if(!dojo._hasResource["dojox.highlight._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight._base"] = true; +dojo.provide("dojox.highlight._base"); + +// +// dojox.highlight - syntax highlighting with language auto-detection +// released under CLA by the Dojo Toolkit +// orig BSD release available from: http://softwaremaniacs.org/soft/highlight/ +// + +(function(){ + var dh = dojox.highlight, + C_NUMBER_RE = '\\b(0x[A-Za-z0-9]+|\\d+(\\.\\d+)?)'; + + // constants + + dh.constants = { + IDENT_RE: '[a-zA-Z][a-zA-Z0-9_]*', + UNDERSCORE_IDENT_RE: '[a-zA-Z_][a-zA-Z0-9_]*', + NUMBER_RE: '\\b\\d+(\\.\\d+)?', + C_NUMBER_RE: C_NUMBER_RE, + // Common modes + APOS_STRING_MODE: { + className: 'string', + begin: '\'', end: '\'', + illegal: '\\n', + contains: ['escape'], + relevance: 0 + }, + QUOTE_STRING_MODE: { + className: 'string', + begin: '"', + end: '"', + illegal: '\\n', + contains: ['escape'], + relevance: 0 + }, + BACKSLASH_ESCAPE: { + className: 'escape', + begin: '\\\\.', end: '^', + relevance: 0 + }, + C_LINE_COMMENT_MODE: { + className: 'comment', + begin: '//', end: '$', + relevance: 0 + }, + C_BLOCK_COMMENT_MODE: { + className: 'comment', + begin: '/\\*', end: '\\*/' + }, + HASH_COMMENT_MODE: { + className: 'comment', + begin: '#', end: '$' + }, + C_NUMBER_MODE: { + className: 'number', + begin: C_NUMBER_RE, end: '^', + relevance: 0 + } + }; + + // utilities + + function esc(value){ + return value.replace(/&/gm, '&').replace(//gm, '>'); + } + + function verifyText(block){ + return dojo.every(block.childNodes, function(node){ + return node.nodeType == 3 || String(node.nodeName).toLowerCase() == 'br'; + }); + } + + function blockText(block){ + var result = []; + dojo.forEach(block.childNodes, function(node){ + if(node.nodeType == 3){ + result.push(node.nodeValue); + }else if(String(node.nodeName).toLowerCase() == 'br'){ + result.push("\n"); + }else{ + throw 'Complex markup'; + } + }); + return result.join(""); + } + + function buildKeywordGroups(mode){ + if(!mode.keywordGroups){ + for(var key in mode.keywords){ + var kw = mode.keywords[key]; + if(kw instanceof Object){ // dojo.isObject? + mode.keywordGroups = mode.keywords; + }else{ + mode.keywordGroups = {keyword: mode.keywords}; + } + break; + } + } + } + + function buildKeywords(lang){ + if(lang.defaultMode && lang.modes){ + buildKeywordGroups(lang.defaultMode); + dojo.forEach(lang.modes, buildKeywordGroups); + } + } + + // main object + + var Highlighter = function(langName, textBlock){ + // initialize the state + this.langName = langName; + this.lang = dh.languages[langName]; + this.modes = [this.lang.defaultMode]; + this.relevance = 0; + this.keywordCount = 0; + this.result = []; + + // build resources lazily + if(!this.lang.defaultMode.illegalRe){ + this.buildRes(); + buildKeywords(this.lang); + } + + // run the algorithm + try{ + this.highlight(textBlock); + this.result = this.result.join(""); + }catch(e){ + if(e == 'Illegal'){ + this.relevance = 0; + this.keywordCount = 0; + this.result = esc(textBlock); + }else{ + throw e; + } + } + }; + + dojo.extend(Highlighter, { + buildRes: function(){ + dojo.forEach(this.lang.modes, function(mode){ + if(mode.begin){ + mode.beginRe = this.langRe('^' + mode.begin); + } + if(mode.end){ + mode.endRe = this.langRe('^' + mode.end); + } + if(mode.illegal){ + mode.illegalRe = this.langRe('^(?:' + mode.illegal + ')'); + } + }, this); + this.lang.defaultMode.illegalRe = this.langRe('^(?:' + this.lang.defaultMode.illegal + ')'); + }, + + subMode: function(lexeme){ + var classes = this.modes[this.modes.length - 1].contains; + if(classes){ + var modes = this.lang.modes; + for(var i = 0; i < classes.length; ++i){ + var className = classes[i]; + for(var j = 0; j < modes.length; ++j){ + var mode = modes[j]; + if(mode.className == className && mode.beginRe.test(lexeme)){ return mode; } + } + } + } + return null; + }, + + endOfMode: function(lexeme){ + for(var i = this.modes.length - 1; i >= 0; --i){ + var mode = this.modes[i]; + if(mode.end && mode.endRe.test(lexeme)){ return this.modes.length - i; } + if(!mode.endsWithParent){ break; } + } + return 0; + }, + + isIllegal: function(lexeme){ + var illegalRe = this.modes[this.modes.length - 1].illegalRe; + return illegalRe && illegalRe.test(lexeme); + }, + + + langRe: function(value, global){ + var mode = 'm' + (this.lang.case_insensitive ? 'i' : '') + (global ? 'g' : ''); + return new RegExp(value, mode); + }, + + buildTerminators: function(){ + var mode = this.modes[this.modes.length - 1], + terminators = {}; + if(mode.contains){ + dojo.forEach(this.lang.modes, function(lmode){ + if(dojo.indexOf(mode.contains, lmode.className) >= 0){ + terminators[lmode.begin] = 1; + } + }); + } + for(var i = this.modes.length - 1; i >= 0; --i){ + var m = this.modes[i]; + if(m.end){ terminators[m.end] = 1; } + if(!m.endsWithParent){ break; } + } + if(mode.illegal){ terminators[mode.illegal] = 1; } + var t = []; + for(i in terminators){ t.push(i); } + mode.terminatorsRe = this.langRe("(" + t.join("|") + ")"); + }, + + eatModeChunk: function(value, index){ + var mode = this.modes[this.modes.length - 1]; + + // create terminators lazily + if(!mode.terminatorsRe){ + this.buildTerminators(); + } + + value = value.substr(index); + var match = mode.terminatorsRe.exec(value); + if(!match){ + return { + buffer: value, + lexeme: "", + end: true + }; + } + return { + buffer: match.index ? value.substr(0, match.index) : "", + lexeme: match[0], + end: false + }; + }, + + keywordMatch: function(mode, match){ + var matchStr = match[0]; + if(this.lang.case_insensitive){ matchStr = matchStr.toLowerCase(); } + for(var className in mode.keywordGroups){ + if(matchStr in mode.keywordGroups[className]){ return className; } + } + return ""; + }, + + buildLexemes: function(mode){ + var lexemes = {}; + dojo.forEach(mode.lexems, function(lexeme){ + lexemes[lexeme] = 1; + }); + var t = []; + for(var i in lexemes){ t.push(i); } + mode.lexemsRe = this.langRe("(" + t.join("|") + ")", true); + }, + + processKeywords: function(buffer){ + var mode = this.modes[this.modes.length - 1]; + if(!mode.keywords || !mode.lexems){ + return esc(buffer); + } + + // create lexemes lazily + if(!mode.lexemsRe){ + this.buildLexemes(mode); + } + + mode.lexemsRe.lastIndex = 0; + var result = [], lastIndex = 0, + match = mode.lexemsRe.exec(buffer); + while(match){ + result.push(esc(buffer.substr(lastIndex, match.index - lastIndex))); + var keywordM = this.keywordMatch(mode, match); + if(keywordM){ + ++this.keywordCount; + result.push('' + esc(match[0]) + ''); + }else{ + result.push(esc(match[0])); + } + lastIndex = mode.lexemsRe.lastIndex; + match = mode.lexemsRe.exec(buffer); + } + result.push(esc(buffer.substr(lastIndex, buffer.length - lastIndex))); + return result.join(""); + }, + + processModeInfo: function(buffer, lexeme, end) { + var mode = this.modes[this.modes.length - 1]; + if(end){ + this.result.push(this.processKeywords(mode.buffer + buffer)); + return; + } + if(this.isIllegal(lexeme)){ throw 'Illegal'; } + var newMode = this.subMode(lexeme); + if(newMode){ + mode.buffer += buffer; + this.result.push(this.processKeywords(mode.buffer)); + if(newMode.excludeBegin){ + this.result.push(lexeme + ''); + newMode.buffer = ''; + }else{ + this.result.push(''); + newMode.buffer = lexeme; + } + this.modes.push(newMode); + this.relevance += typeof newMode.relevance == "number" ? newMode.relevance : 1; + return; + } + var endLevel = this.endOfMode(lexeme); + if(endLevel){ + mode.buffer += buffer; + if(mode.excludeEnd){ + this.result.push(this.processKeywords(mode.buffer) + '' + lexeme); + }else{ + this.result.push(this.processKeywords(mode.buffer + lexeme) + ''); + } + while(endLevel > 1){ + this.result.push(''); + --endLevel; + this.modes.pop(); + } + this.modes.pop(); + this.modes[this.modes.length - 1].buffer = ''; + return; + } + }, + + highlight: function(value){ + var index = 0; + this.lang.defaultMode.buffer = ''; + do{ + var modeInfo = this.eatModeChunk(value, index); + this.processModeInfo(modeInfo.buffer, modeInfo.lexeme, modeInfo.end); + index += modeInfo.buffer.length + modeInfo.lexeme.length; + }while(!modeInfo.end); + if(this.modes.length > 1){ + throw 'Illegal'; + } + } + }); + + // more utilities + + function replaceText(node, className, text){ + if(String(node.tagName).toLowerCase() == "code" && String(node.parentNode.tagName).toLowerCase() == "pre"){ + // See these 4 lines? This is IE's notion of "node.innerHTML = text". Love this browser :-/ + var container = document.createElement('div'), + environment = node.parentNode.parentNode; + container.innerHTML = '
      ' + text + '
      '; + environment.replaceChild(container.firstChild, node.parentNode); + }else{ + node.className = className; + node.innerHTML = text; + } + } + + function highlightLanguage(block, lang){ + var highlight = new Highlighter(lang, blockText(block)); + replaceText(block, block.className, highlight.result); + } + + function highlightAuto(block){ + var result = "", langName = "", bestRelevance = 2, + textBlock = blockText(block); + for(var key in dh.languages){ + if(!dh.languages[key].defaultMode){ continue; } // skip internal members + var highlight = new Highlighter(key, textBlock), + relevance = highlight.keywordCount + highlight.relevance; + if(!result || relevance > relevanceMax){ + relevanceMax = relevance; + result = highlight.result; + langName = highlight.langName; + } + } + if(result){ + replaceText(block, langName, result); + } + } + + // the public API + + dh.init = function(/* DomNode */ block){ + // summary: the main (only required) public API. highlight a node. + if(dojo.hasClass(block,"no-highlight")){ return; } + if(!verifyText(block)){ return; } + + var classes = block.className.split(/\s+/), + flag = dojo.some(classes, function(className){ + if(className.charAt(0) != "_" && dh.languages[className]){ + highlightLanguage(block, className); + return true; // stop iterations + } + return false; // continue iterations + }); + if(!flag){ + highlightAuto(block); + } + }; + + // pseudo object for markup creation + dh.Code = function(params, node){ + dh.init(node); + }; +})(); + +} diff --git a/includes/js/dojox/highlight/languages/_all.js b/includes/js/dojox/highlight/languages/_all.js new file mode 100644 index 0000000..5097046 --- /dev/null +++ b/includes/js/dojox/highlight/languages/_all.js @@ -0,0 +1,11 @@ +if(!dojo._hasResource["dojox.highlight.languages._all"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages._all"] = true; +dojo.provide("dojox.highlight.languages._all"); + +/* groups of similar languages */ +dojo.require("dojox.highlight.languages._static"); +dojo.require("dojox.highlight.languages._dynamic"); +dojo.require("dojox.highlight.languages._www"); + + +} diff --git a/includes/js/dojox/highlight/languages/_dynamic.js b/includes/js/dojox/highlight/languages/_dynamic.js new file mode 100644 index 0000000..a3b510b --- /dev/null +++ b/includes/js/dojox/highlight/languages/_dynamic.js @@ -0,0 +1,11 @@ +if(!dojo._hasResource["dojox.highlight.languages._dynamic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages._dynamic"] = true; +dojo.provide("dojox.highlight.languages._dynamic"); + +/* common scripted languages */ +dojo.require("dojox.highlight.languages.python"); +// dojo.require("dojox.highlight.languages.perl"); +// dojo.require("dojox.highlight.languages.php"); +// dojo.require("dojox.highlight.languages.ruby"); + +} diff --git a/includes/js/dojox/highlight/languages/_static.js b/includes/js/dojox/highlight/languages/_static.js new file mode 100644 index 0000000..85212b4 --- /dev/null +++ b/includes/js/dojox/highlight/languages/_static.js @@ -0,0 +1,10 @@ +if(!dojo._hasResource["dojox.highlight.languages._static"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages._static"] = true; +dojo.provide("dojox.highlight.languages._static"); + +/* common static languages */ +dojo.require("dojox.highlight.languages.cpp") +// dojo.require("dojox.highlight.languages.java"); +dojo.require("dojox.highlight.languages.delphi"); + +} diff --git a/includes/js/dojox/highlight/languages/_www.js b/includes/js/dojox/highlight/languages/_www.js new file mode 100644 index 0000000..a04f073 --- /dev/null +++ b/includes/js/dojox/highlight/languages/_www.js @@ -0,0 +1,12 @@ +if(!dojo._hasResource["dojox.highlight.languages._www"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages._www"] = true; +dojo.provide("dojox.highlight.languages._www"); + +/* common web-centric languages */ +dojo.require("dojox.highlight.languages.xml"); +dojo.require("dojox.highlight.languages.html"); +dojo.require("dojox.highlight.languages.css"); +dojo.require("dojox.highlight.languages.django"); +dojo.require("dojox.highlight.languages.javascript"); + +} diff --git a/includes/js/dojox/highlight/languages/cpp.js b/includes/js/dojox/highlight/languages/cpp.js new file mode 100644 index 0000000..1e9edf2 --- /dev/null +++ b/includes/js/dojox/highlight/languages/cpp.js @@ -0,0 +1,53 @@ +if(!dojo._hasResource["dojox.highlight.languages.cpp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages.cpp"] = true; +dojo.provide("dojox.highlight.languages.cpp"); + +dojo.require("dojox.highlight._base"); + +(function(){ + var dh = dojox.highlight, dhc = dh.constants; + dh.languages.cpp = { + // summary: C++ highlight definitions + defaultMode: { + lexems: [dhc.UNDERSCORE_IDENT_RE], + illegal: '', + contains: ['attribute', 'template_comment', 'template_tag', 'variable'] + }, + x.XML_ATTR, + h.HTML_ATTR, + { + className: 'value', + begin: '"', end: '"', + contains: ['template_comment', 'template_tag', 'variable'] + }, + h.HTML_VALUE, + { + className: 'template_comment', + begin: '\\{\\%\\s*comment\\s*\\%\\}', + end: '\\{\\%\\s*endcomment\\s*\\%\\}' + }, + { + className: 'template_comment', + begin: '\\{#', end: '#\\}' + }, + { + className: 'template_tag', + begin: '\\{\\%', end: '\\%\\}', + lexems: [dhc.IDENT_RE], + keywords: { + 'comment': 1, 'endcomment': 1, 'load': 1, + 'templatetag': 1, 'ifchanged': 1, 'endifchanged': 1, + 'if': 1, 'endif': 1, 'firstof': 1, 'for': 1, + 'endfor': 1, 'in': 1, 'ifnotequal': 1, + 'endifnotequal': 1, 'widthratio': 1, 'extends': 1, + 'include': 1, 'spaceless': 1, 'endspaceless': 1, + 'regroup': 1, 'by': 1, 'as': 1, 'ifequal': 1, + 'endifequal': 1, 'ssi': 1, 'now': 1, 'with': 1, + 'cycle': 1, 'url': 1, 'filter': 1, 'endfilter': 1, + 'debug': 1, 'block': 1, 'endblock': 1, 'else': 1 + }, + contains: ['filter'] + }, + { + className: 'variable', + begin: '\\{\\{', end: '\\}\\}', + contains: ['filter'] + }, + { + className: 'filter', + begin: '\\|[A-Za-z]+\\:?', end: '^', excludeEnd: true, + lexems: [dhc.IDENT_RE], + keywords: { + 'truncatewords': 1, 'removetags': 1, 'linebreaksbr': 1, + 'yesno': 1, 'get_digit': 1, 'timesince': 1, 'random': 1, + 'striptags': 1, 'filesizeformat': 1, 'escape': 1, + 'linebreaks': 1, 'length_is': 1, 'ljust': 1, 'rjust': 1, + 'cut': 1, 'urlize': 1, 'fix_ampersands': 1, 'title': 1, + 'floatformat': 1, 'capfirst': 1, 'pprint': 1, + 'divisibleby': 1, 'add': 1, 'make_list': 1, + 'unordered_list': 1, 'urlencode': 1, 'timeuntil': 1, + 'urlizetrunc': 1, 'wordcount': 1, 'stringformat': 1, + 'linenumbers': 1, 'slice': 1, 'date': 1, 'dictsort': 1, + 'dictsortreversed': 1, 'default_if_none': 1, + 'pluralize': 1, 'lower': 1, 'join': 1, 'center': 1, + 'default': 1, 'truncatewords_html': 1, 'upper': 1, + 'length': 1, 'phone2numeric': 1, 'wordwrap': 1, 'time': 1, + 'addslashes': 1, 'slugify': 1, 'first': 1 + }, + contains: ['argument'] + }, + { + className: 'argument', + begin: '"', end: '"' + } + ] + }; +})(); + +} diff --git a/includes/js/dojox/highlight/languages/html.js b/includes/js/dojox/highlight/languages/html.js new file mode 100644 index 0000000..0a6cc46 --- /dev/null +++ b/includes/js/dojox/highlight/languages/html.js @@ -0,0 +1,70 @@ +if(!dojo._hasResource["dojox.highlight.languages.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages.html"] = true; +dojo.provide("dojox.highlight.languages.html"); + +dojo.require("dojox.highlight._base"); +dojo.require("dojox.highlight.languages.xml"); + +(function(){ + var HTML_TAGS = { + 'code': 1, 'kbd': 1, 'font': 1, 'noscript': 1, 'style': 1, 'img': 1, + 'title': 1, 'menu': 1, 'tt': 1, 'tr': 1, 'param': 1, 'li': 1, 'tfoot': 1, + 'th': 1, 'input': 1, 'td': 1, 'dl': 1, 'blockquote': 1, 'fieldset': 1, + 'big': 1, 'dd': 1, 'abbr': 1, 'optgroup': 1, 'dt': 1, 'button': 1, + 'isindex': 1, 'p': 1, 'small': 1, 'div': 1, 'dir': 1, 'em': 1, 'frame': 1, + 'meta': 1, 'sub': 1, 'bdo': 1, 'label': 1, 'acronym': 1, 'sup': 1, + 'body': 1, 'xml': 1, 'basefont': 1, 'base': 1, 'br': 1, 'address': 1, + 'strong': 1, 'legend': 1, 'ol': 1, 'script': 1, 'caption': 1, 's': 1, + 'col': 1, 'h2': 1, 'h3': 1, 'h1': 1, 'h6': 1, 'h4': 1, 'h5': 1, 'table': 1, + 'select': 1, 'noframes': 1, 'span': 1, 'area': 1, 'dfn': 1, 'strike': 1, + 'cite': 1, 'thead': 1, 'head': 1, 'option': 1, 'form': 1, 'hr': 1, + 'var': 1, 'link': 1, 'b': 1, 'colgroup': 1, 'ul': 1, 'applet': 1, 'del': 1, + 'iframe': 1, 'pre': 1, 'frameset': 1, 'ins': 1, 'tbody': 1, 'html': 1, + 'samp': 1, 'map': 1, 'object': 1, 'a': 1, 'xmlns': 1, 'center': 1, + 'textarea': 1, 'i': 1, 'q': 1, 'u': 1 + }; + var HTML_DOCTYPE = { + className: 'doctype', + begin: '', + relevance: 10 + }; + var HTML_ATTR = { + className: 'attribute', + begin: ' [a-zA-Z]+', end: '^' + }; + var HTML_VALUE = { + className: 'value', + begin: '[a-zA-Z0-9]+', end: '^' + }; + + var dh = dojox.highlight, dhc = dh.constants, dhl = dh.languages, x = dhl.xml; + dhl.html = { + defaultMode: { + contains: ['tag', 'comment', 'doctype'] + }, + case_insensitive: true, + modes: [ + x.XML_COMMENT, + HTML_DOCTYPE, + { + className: 'tag', + lexems: [dhc.IDENT_RE], + keywords: HTML_TAGS, + begin: '<[A-Za-z/]', end: '>', + contains: ['attribute'], + illegal: '[\\+\\.]' + }, + x.XML_ATTR, + HTML_ATTR, + x.XML_VALUE, + HTML_VALUE + ], + // exporting constants + HTML_TAGS: HTML_TAGS, + HTML_DOCTYPE: HTML_DOCTYPE, + HTML_ATTR: HTML_ATTR, + HTML_VALUE: HTML_VALUE + }; +})(); + +} diff --git a/includes/js/dojox/highlight/languages/javascript.js b/includes/js/dojox/highlight/languages/javascript.js new file mode 100644 index 0000000..587cb07 --- /dev/null +++ b/includes/js/dojox/highlight/languages/javascript.js @@ -0,0 +1,55 @@ +if(!dojo._hasResource["dojox.highlight.languages.javascript"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages.javascript"] = true; +dojo.provide("dojox.highlight.languages.javascript"); + +dojo.require("dojox.highlight._base"); + +(function(){ + var dh = dojox.highlight, dhc = dh.constants; + dh.languages.javascript = { + defaultMode: { + lexems: [dhc.UNDERSCORE_IDENT_RE], + contains: ['string', 'comment', 'number', 'regexp', 'function'], + keywords: { + 'keyword': { + 'in': 1, 'if': 1, 'for': 1, 'while': 1, 'finally': 1, 'var': 1, + 'new': 1, 'function': 1, 'do': 1, 'return': 1, 'void': 1, + 'else': 1, 'break': 1, 'catch': 1, 'instanceof': 1, 'with': 1, + 'throw': 1, 'case': 1, 'default': 1, 'try': 1, 'this': 1, + 'switch': 1, 'continue': 1, 'typeof': 1, 'delete': 1 + }, + 'literal': {'true': 1, 'false': 1, 'null': 1} + } + }, + modes: [ + dhc.C_LINE_COMMENT_MODE, + dhc.C_BLOCK_COMMENT_MODE, + dhc.C_NUMBER_MODE, + dhc.APOS_STRING_MODE, + dhc.QUOTE_STRING_MODE, + dhc.BACKSLASH_ESCAPE, + { + className: 'regexp', + begin: '/.*?[^\\\\/]/[gim]*', end: '^' + }, + { + className: 'function', + begin: 'function\\b', end: '{', + lexems: [dhc.UNDERSCORE_IDENT_RE], + keywords: {'function': 1}, + contains: ['title', 'params'] + }, + { + className: 'title', + begin: dhc.UNDERSCORE_IDENT_RE, end: '^' + }, + { + className: 'params', + begin: '\\(', end: '\\)', + contains: ['string', 'comment'] + } + ] + }; +})(); + +} diff --git a/includes/js/dojox/highlight/languages/pygments/_html.js b/includes/js/dojox/highlight/languages/pygments/_html.js new file mode 100644 index 0000000..64b3bfa --- /dev/null +++ b/includes/js/dojox/highlight/languages/pygments/_html.js @@ -0,0 +1,25 @@ +if(!dojo._hasResource["dojox.highlight.languages.pygments._html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages.pygments._html"] = true; +dojo.provide("dojox.highlight.languages.pygments._html"); + +// html-related constants + +dojox.highlight.languages.pygments._html.tags = { + "code": 1, "kbd": 1, "font": 1, "noscript": 1, "style": 1, "img": 1, + "title": 1, "menu": 1, "tt": 1, "tr": 1, "param": 1, "li": 1, "tfoot": 1, + "th": 1, "input": 1, "td": 1, "dl": 1, "blockquote": 1, "fieldset": 1, + "big": 1, "dd": 1, "abbr": 1, "optgroup": 1, "dt": 1, "button": 1, + "isindex": 1, "p": 1, "small": 1, "div": 1, "dir": 1, "em": 1, "frame": 1, + "meta": 1, "sub": 1, "bdo": 1, "label": 1, "acronym": 1, "sup": 1, + "body": 1, "xml": 1, "basefont": 1, "base": 1, "br": 1, "address": 1, + "strong": 1, "legend": 1, "ol": 1, "script": 1, "caption": 1, "s": 1, + "col": 1, "h2": 1, "h3": 1, "h1": 1, "h6": 1, "h4": 1, "h5": 1, "table": 1, + "select": 1, "noframes": 1, "span": 1, "area": 1, "dfn": 1, "strike": 1, + "cite": 1, "thead": 1, "head": 1, "option": 1, "form": 1, "hr": 1, + "var": 1, "link": 1, "b": 1, "colgroup": 1, "ul": 1, "applet": 1, "del": 1, + "iframe": 1, "pre": 1, "frameset": 1, "ins": 1, "tbody": 1, "html": 1, + "samp": 1, "map": 1, "object": 1, "a": 1, "xmlns": 1, "center": 1, + "textarea": 1, "i": 1, "q": 1, "u": 1 +}; + +} diff --git a/includes/js/dojox/highlight/languages/pygments/_www.js b/includes/js/dojox/highlight/languages/pygments/_www.js new file mode 100644 index 0000000..648ed6e --- /dev/null +++ b/includes/js/dojox/highlight/languages/pygments/_www.js @@ -0,0 +1,12 @@ +if(!dojo._hasResource["dojox.highlight.languages.pygments._www"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages.pygments._www"] = true; +dojo.provide("dojox.highlight.languages.pygments._www"); + +/* common web-centric languages */ +dojo.require("dojox.highlight.languages.pygments.xml"); +dojo.require("dojox.highlight.languages.pygments.html"); +dojo.require("dojox.highlight.languages.pygments.css"); +//dojo.require("dojox.highlight.languages.pygments.django"); +dojo.require("dojox.highlight.languages.pygments.javascript"); + +} diff --git a/includes/js/dojox/highlight/languages/pygments/css.js b/includes/js/dojox/highlight/languages/pygments/css.js new file mode 100644 index 0000000..bfb0680 --- /dev/null +++ b/includes/js/dojox/highlight/languages/pygments/css.js @@ -0,0 +1,211 @@ +if(!dojo._hasResource["dojox.highlight.languages.pygments.css"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages.pygments.css"] = true; +dojo.provide("dojox.highlight.languages.pygments.css"); + +dojo.require("dojox.highlight._base"); +dojo.require("dojox.highlight.languages.pygments._html"); + +(function(){ + var dh = dojox.highlight, dhl = dh.languages; + dhl.css = { + defaultMode: { + lexems: ["\\b[a-zA-Z0-9]+\\b", "\\b@media\b"], + keywords: { + "keyword": { + "@media": 1 + }, + "name tag": dhl.pygments._html.tags + }, + contains: [ + "comment", + "string single", "string double", + "punctuation", + "name decorator", "name class", "name function", + "_content" + ] + }, + modes: [ + // comments + { + className: "comment", + begin: "/\\*", end: "\\*/", + relevance: 0 + }, + { + className: "comment preproc", + begin: "@[a-z][a-zA-Z]*", end: "^" + }, + { + className: "comment preproc", + begin: "\\!important\\b", end: "^" + }, + + // numbers + { + className: "number", + begin: "\\#[a-fA-F0-9]{3}\\b", end: "^", + relevance: 0 + }, + { + className: "number", + begin: "\\#[a-fA-F0-9]{6}\\b", end: "^", + relevance: 0 + }, + { + className: "number", + begin: "[\\.\\-]?[0-9]*[\\.]?[0-9]+(em|px|\\%|pt|pc|in|mm|cm|ex)", end: "^", + relevance: 0 + }, + { + className: "number", + begin: "\\-?[0-9]+", end: "^", + relevance: 0 + }, + + // strings + { + className: "string single", + begin: "'", end: "'", + illegal: "\\n", + relevance: 0 + }, + { + className: "string double", + begin: '"', + end: '"', + illegal: "\\n", + relevance: 0 + }, + + // operators + { + className: "operator", + begin: "[~\\^\\*!%&\\[\\]\\(\\)<>\\|+=@:;,./?-]", end: "^", + relevance: 0 + }, + + // punctuations + { + className: "punctuation", + begin: "[\\[\\]();]+", end: "^", + relevance: 0 + }, + + // names + { + className: "name decorator", + begin: "\\:[a-zA-Z0-9_\\-]+\\b", end: "^" + }, + { + className: "name class", + begin: "\\.[a-zA-Z0-9_\\-]+\\b", end: "^" + }, + { + className: "name function", + begin: "\\#[a-zA-Z0-9_\\-]+\\b", end: "^" + }, + { + className: "_content", + begin: "\\{", end: "\\}", + lexems: ["\\b[a-zA-Z\\-]+\\b"], + keywords: { + "keyword": { + "azimuth": 1, "background-attachment": 1, "background-color": 1, + "background-image": 1, "background-position": 1, "background-repeat": 1, + "background": 1, "border-bottom-color": 1, "border-bottom-style": 1, + "border-bottom-width": 1, "border-left-color": 1, "border-left-style": 1, + "border-left-width": 1, "border-right": 1, "border-right-color": 1, + "border-right-style": 1, "border-right-width": 1, "border-top-color": 1, + "border-top-style": 1, "border-top-width": 1, "border-bottom": 1, + "border-collapse": 1, "border-left": 1, "border-width": 1, "border-color": 1, + "border-spacing": 1, "border-style": 1, "border-top": 1, "border": 1, "caption-side": 1, + "clear": 1, "clip": 1, "color": 1, "content": 1, "counter-increment": 1, "counter-reset": 1, + "cue-after": 1, "cue-before": 1, "cue": 1, "cursor": 1, "direction": 1, "display": 1, + "elevation": 1, "empty-cells": 1, "float": 1, "font-family": 1, "font-size": 1, + "font-size-adjust": 1, "font-stretch": 1, "font-style": 1, "font-variant": 1, + "font-weight": 1, "font": 1, "height": 1, "letter-spacing": 1, "line-height": 1, + "list-style-type": 1, "list-style-image": 1, "list-style-position": 1, + "list-style": 1, "margin-bottom": 1, "margin-left": 1, "margin-right": 1, + "margin-top": 1, "margin": 1, "marker-offset": 1, "marks": 1, "max-height": 1, "max-width": 1, + "min-height": 1, "min-width": 1, "opacity": 1, "orphans": 1, "outline": 1, "outline-color": 1, + "outline-style": 1, "outline-width": 1, "overflow": 1, "padding-bottom": 1, + "padding-left": 1, "padding-right": 1, "padding-top": 1, "padding": 1, "page": 1, + "page-break-after": 1, "page-break-before": 1, "page-break-inside": 1, + "pause-after": 1, "pause-before": 1, "pause": 1, "pitch": 1, "pitch-range": 1, + "play-during": 1, "position": 1, "quotes": 1, "richness": 1, "right": 1, "size": 1, + "speak-header": 1, "speak-numeral": 1, "speak-punctuation": 1, "speak": 1, + "speech-rate": 1, "stress": 1, "table-layout": 1, "text-align": 1, "text-decoration": 1, + "text-indent": 1, "text-shadow": 1, "text-transform": 1, "top": 1, "unicode-bidi": 1, + "vertical-align": 1, "visibility": 1, "voice-family": 1, "volume": 1, "white-space": 1, + "widows": 1, "width": 1, "word-spacing": 1, "z-index": 1, "bottom": 1, "left": 1, + "above": 1, "absolute": 1, "always": 1, "armenian": 1, "aural": 1, "auto": 1, "avoid": 1, "baseline": 1, + "behind": 1, "below": 1, "bidi-override": 1, "blink": 1, "block": 1, "bold": 1, "bolder": 1, "both": 1, + "capitalize": 1, "center-left": 1, "center-right": 1, "center": 1, "circle": 1, + "cjk-ideographic": 1, "close-quote": 1, "collapse": 1, "condensed": 1, "continuous": 1, + "crop": 1, "crosshair": 1, "cross": 1, "cursive": 1, "dashed": 1, "decimal-leading-zero": 1, + "decimal": 1, "default": 1, "digits": 1, "disc": 1, "dotted": 1, "double": 1, "e-resize": 1, "embed": 1, + "extra-condensed": 1, "extra-expanded": 1, "expanded": 1, "fantasy": 1, "far-left": 1, + "far-right": 1, "faster": 1, "fast": 1, "fixed": 1, "georgian": 1, "groove": 1, "hebrew": 1, "help": 1, + "hidden": 1, "hide": 1, "higher": 1, "high": 1, "hiragana-iroha": 1, "hiragana": 1, "icon": 1, + "inherit": 1, "inline-table": 1, "inline": 1, "inset": 1, "inside": 1, "invert": 1, "italic": 1, + "justify": 1, "katakana-iroha": 1, "katakana": 1, "landscape": 1, "larger": 1, "large": 1, + "left-side": 1, "leftwards": 1, "level": 1, "lighter": 1, "line-through": 1, "list-item": 1, + "loud": 1, "lower-alpha": 1, "lower-greek": 1, "lower-roman": 1, "lowercase": 1, "ltr": 1, + "lower": 1, "low": 1, "medium": 1, "message-box": 1, "middle": 1, "mix": 1, "monospace": 1, + "n-resize": 1, "narrower": 1, "ne-resize": 1, "no-close-quote": 1, "no-open-quote": 1, + "no-repeat": 1, "none": 1, "normal": 1, "nowrap": 1, "nw-resize": 1, "oblique": 1, "once": 1, + "open-quote": 1, "outset": 1, "outside": 1, "overline": 1, "pointer": 1, "portrait": 1, "px": 1, + "relative": 1, "repeat-x": 1, "repeat-y": 1, "repeat": 1, "rgb": 1, "ridge": 1, "right-side": 1, + "rightwards": 1, "s-resize": 1, "sans-serif": 1, "scroll": 1, "se-resize": 1, + "semi-condensed": 1, "semi-expanded": 1, "separate": 1, "serif": 1, "show": 1, "silent": 1, + "slow": 1, "slower": 1, "small-caps": 1, "small-caption": 1, "smaller": 1, "soft": 1, "solid": 1, + "spell-out": 1, "square": 1, "static": 1, "status-bar": 1, "super": 1, "sw-resize": 1, + "table-caption": 1, "table-cell": 1, "table-column": 1, "table-column-group": 1, + "table-footer-group": 1, "table-header-group": 1, "table-row": 1, + "table-row-group": 1, "text": 1, "text-bottom": 1, "text-top": 1, "thick": 1, "thin": 1, + "transparent": 1, "ultra-condensed": 1, "ultra-expanded": 1, "underline": 1, + "upper-alpha": 1, "upper-latin": 1, "upper-roman": 1, "uppercase": 1, "url": 1, + "visible": 1, "w-resize": 1, "wait": 1, "wider": 1, "x-fast": 1, "x-high": 1, "x-large": 1, "x-loud": 1, + "x-low": 1, "x-small": 1, "x-soft": 1, "xx-large": 1, "xx-small": 1, "yes": 1 + }, + "name builtin": { + "indigo": 1, "gold": 1, "firebrick": 1, "indianred": 1, "yellow": 1, "darkolivegreen": 1, + "darkseagreen": 1, "mediumvioletred": 1, "mediumorchid": 1, "chartreuse": 1, + "mediumslateblue": 1, "black": 1, "springgreen": 1, "crimson": 1, "lightsalmon": 1, "brown": 1, + "turquoise": 1, "olivedrab": 1, "cyan": 1, "silver": 1, "skyblue": 1, "gray": 1, "darkturquoise": 1, + "goldenrod": 1, "darkgreen": 1, "darkviolet": 1, "darkgray": 1, "lightpink": 1, "teal": 1, + "darkmagenta": 1, "lightgoldenrodyellow": 1, "lavender": 1, "yellowgreen": 1, "thistle": 1, + "violet": 1, "navy": 1, "orchid": 1, "blue": 1, "ghostwhite": 1, "honeydew": 1, "cornflowerblue": 1, + "darkblue": 1, "darkkhaki": 1, "mediumpurple": 1, "cornsilk": 1, "red": 1, "bisque": 1, "slategray": 1, + "darkcyan": 1, "khaki": 1, "wheat": 1, "deepskyblue": 1, "darkred": 1, "steelblue": 1, "aliceblue": 1, + "gainsboro": 1, "mediumturquoise": 1, "floralwhite": 1, "coral": 1, "purple": 1, "lightgrey": 1, + "lightcyan": 1, "darksalmon": 1, "beige": 1, "azure": 1, "lightsteelblue": 1, "oldlace": 1, + "greenyellow": 1, "royalblue": 1, "lightseagreen": 1, "mistyrose": 1, "sienna": 1, + "lightcoral": 1, "orangered": 1, "navajowhite": 1, "lime": 1, "palegreen": 1, "burlywood": 1, + "seashell": 1, "mediumspringgreen": 1, "fuchsia": 1, "papayawhip": 1, "blanchedalmond": 1, + "peru": 1, "aquamarine": 1, "white": 1, "darkslategray": 1, "ivory": 1, "dodgerblue": 1, + "lemonchiffon": 1, "chocolate": 1, "orange": 1, "forestgreen": 1, "slateblue": 1, "olive": 1, + "mintcream": 1, "antiquewhite": 1, "darkorange": 1, "cadetblue": 1, "moccasin": 1, + "limegreen": 1, "saddlebrown": 1, "darkslateblue": 1, "lightskyblue": 1, "deeppink": 1, + "plum": 1, "aqua": 1, "darkgoldenrod": 1, "maroon": 1, "sandybrown": 1, "magenta": 1, "tan": 1, + "rosybrown": 1, "pink": 1, "lightblue": 1, "palevioletred": 1, "mediumseagreen": 1, + "dimgray": 1, "powderblue": 1, "seagreen": 1, "snow": 1, "mediumblue": 1, "midnightblue": 1, + "paleturquoise": 1, "palegoldenrod": 1, "whitesmoke": 1, "darkorchid": 1, "salmon": 1, + "lightslategray": 1, "lawngreen": 1, "lightgreen": 1, "tomato": 1, "hotpink": 1, + "lightyellow": 1, "lavenderblush": 1, "linen": 1, "mediumaquamarine": 1, "green": 1, + "blueviolet": 1, "peachpuff": 1 + } + }, + contains: [ + "comment", "comment preproc", + "number", + "string single", "string double", + "punctuation", + "name decorator", "name class", "name function" + ] + } + ] + }; +})(); + +} diff --git a/includes/js/dojox/highlight/languages/pygments/html.js b/includes/js/dojox/highlight/languages/pygments/html.js new file mode 100644 index 0000000..e0e7475 --- /dev/null +++ b/includes/js/dojox/highlight/languages/pygments/html.js @@ -0,0 +1,101 @@ +if(!dojo._hasResource["dojox.highlight.languages.pygments.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages.pygments.html"] = true; +dojo.provide("dojox.highlight.languages.pygments.html"); + +dojo.require("dojox.highlight._base"); +dojo.require("dojox.highlight.languages.pygments._html"); + +(function(){ + var dh = dojox.highlight, dhl = dh.languages, tags = [], + ht = dhl.pygments._html.tags; + + for(var key in ht){ + tags.push(key); + } + tags = "\\b(" + tags.join("|") + ")\\b"; + + dhl.html = { + case_insensitive: true, + defaultMode: { + contains: [ + "name entity", + "comment", "comment preproc", + "_script", "_style", "_tag" + ] + }, + modes: [ + // comments + { + className: "comment", + begin: "" + }, + { + className: "comment preproc", + begin: "\\<\\!\\[CDATA\\[", end: "\\]\\]\\>" + }, + { + className: "comment preproc", + begin: "\\<\\!", end: "\\>" + }, + + // strings + { + className: "string", + begin: "'", end: "'", + illegal: "\\n", + relevance: 0 + }, + { + className: "string", + begin: '"', + end: '"', + illegal: "\\n", + relevance: 0 + }, + + // names + { + className: "name entity", + begin: "\\&[a-z]+;", end: "^" + }, + { + className: "name tag", + begin: tags, end: "^", + relevance: 5 + }, + { + className: "name attribute", + begin: "\\b[a-z0-9_\\:\\-]+\\s*=", end: "^", + relevance: 0 + }, + + { + className: "_script", + begin: "\\", + relevance: 5 + }, + { + className: "_style", + begin: "\\", + relevance: 5 + }, + + { + className: "_tag", + begin: "\\<(?!/)", end: "\\>", + contains: ["name tag", "name attribute", "string", "_value"] + }, + { + className: "_tag", + begin: "\\", + contains: ["name tag"] + }, + { + className: "_value", + begin: "[^\\s\\>]+", end: "^" + } + ] + }; +})(); + +} diff --git a/includes/js/dojox/highlight/languages/pygments/javascript.js b/includes/js/dojox/highlight/languages/pygments/javascript.js new file mode 100644 index 0000000..d6c0a6b --- /dev/null +++ b/includes/js/dojox/highlight/languages/pygments/javascript.js @@ -0,0 +1,152 @@ +if(!dojo._hasResource["dojox.highlight.languages.pygments.javascript"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages.pygments.javascript"] = true; +dojo.provide("dojox.highlight.languages.pygments.javascript"); + +dojo.require("dojox.highlight._base"); + +(function(){ + var dh = dojox.highlight, dhc = dh.constants; + dh.languages.javascript = { + defaultMode: { + lexems: ["\\b[a-zA-Z]+"], + keywords: { + "keyword": { + "for": 1, "in": 1, "while": 1, "do": 1, "break": 1, "return": 1, + "continue": 1, "if": 1, "else": 1, "throw": 1, "try": 1, + "catch": 1, "var": 1, "with": 1, "const": 1, "label": 1, + "function": 1, "new": 1, "typeof": 1, "instanceof": 1 + }, + "keyword constant": { + "true": 1, "false": 1, "null": 1, "NaN": 1, "Infinity": 1, "undefined": 1 + }, + "name builtin": { + "Array": 1, "Boolean": 1, "Date": 1, "Error": 1, "Function": 1, "Math": 1, + "netscape": 1, "Number": 1, "Object": 1, "Packages": 1, "RegExp": 1, + "String": 1, "sun": 1, "decodeURI": 1, "decodeURIComponent": 1, + "encodeURI": 1, "encodeURIComponent": 1, "Error": 1, "eval": 1, + "isFinite": 1, "isNaN": 1, "parseFloat": 1, "parseInt": 1, "document": 1, + "window": 1 + }, + "name builtin pseudo": { + "this": 1 + } + }, + contains: [ + "comment single", "comment multiline", + "number integer", "number oct", "number hex", "number float", + "string single", "string double", "string regex", + "operator", + "punctuation", + //"name variable", + "_function" + ] + }, + modes: [ + // comments + { + className: "comment single", + begin: "//", end: "$", + relevance: 0 + }, + { + className: "comment multiline", + begin: "/\\*", end: "\\*/" + }, + + // numbers + { + className: "number integer", + begin: "0|([1-9][0-9]*)", end: "^", + relevance: 0 + }, + { + className: "number oct", + begin: "0[0-9]+", end: "^", + relevance: 0 + }, + { + className: "number hex", + begin: "0x[0-9a-fA-F]+", end: "^", + relevance: 0 + }, + { + className: "number float", + begin: "([1-9][0-9]*\\.[0-9]*([eE][\\+-]?[0-9]+)?)|(\\.[0-9]+([eE][\\+-]?[0-9]+)?)|([0-9]+[eE][\\+-]?[0-9]+)", end: "^", + relevance: 0 + }, + + // strings + { + className: "string single", + begin: "'", end: "'", + illegal: "\\n", + contains: ["string escape"], + relevance: 0 + }, + { + className: "string double", + begin: '"', + end: '"', + illegal: "\\n", + contains: ["string escape"], + relevance: 0 + }, + { + className: "string escape", + begin: "\\\\.", end: "^", + relevance: 0 + }, + { + className: "string regex", + begin: "/.*?[^\\\\/]/[gim]*", end: "^" + }, + + // operators + { + className: "operator", + begin: "\\|\\||&&|\\+\\+|--|-=|\\+=|/=|\\*=|==|[-\\+\\*/=\\?:~\\^]", end: "^", + relevance: 0 + }, + + // punctuations + { + className: "punctuation", + begin: "[{}\\(\\)\\[\\]\\.;]", end: "^", + relevance: 0 + }, + + // functions + { + className: "_function", + begin: "function\\b", end: "{", + lexems: [dhc.UNDERSCORE_IDENT_RE], + keywords: { + keyword: { + "function": 1 + } + }, + contains: ["name function", "_params"], + relevance: 5 + }, + { + className: "name function", + begin: dhc.UNDERSCORE_IDENT_RE, end: '^' + }, + { + className: "_params", + begin: "\\(", end: "\\)", + contains: ["comment single", "comment multiline"] + } + /* + // names + { + className: "name variable", + begin: "\\b[$a-zA-Z_][$a-zA-Z0-9_]*", end: "^", + relevance: 0 + } + */ + ] + }; +})(); + +} diff --git a/includes/js/dojox/highlight/languages/pygments/xml.js b/includes/js/dojox/highlight/languages/pygments/xml.js new file mode 100644 index 0000000..5eb4832 --- /dev/null +++ b/includes/js/dojox/highlight/languages/pygments/xml.js @@ -0,0 +1,79 @@ +if(!dojo._hasResource["dojox.highlight.languages.pygments.xml"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages.pygments.xml"] = true; +dojo.provide("dojox.highlight.languages.pygments.xml"); + +dojo.require("dojox.highlight._base"); +dojox.highlight.languages.pygments.xml = {a: 1}; +dojox.highlight.languages.xml = { + defaultMode: { + contains: [ + "name entity", + "comment", "comment preproc", + "_tag" + ] + }, + modes: [ + // comments + { + className: "comment", + begin: "" + }, + { + className: "comment preproc", + begin: "\\<\\!\\[CDATA\\[", end: "\\]\\]\\>" + }, + { + className: "comment preproc", + begin: "\\<\\!", end: "\\>" + }, + { + className: "comment preproc", + begin: "\\<\\?", end: "\\?\\>", + relevance: 5 + }, + + // strings + { + className: "string", + begin: "'", end: "'", + illegal: "\\n", + relevance: 0 + }, + { + className: "string", + begin: '"', + end: '"', + illegal: "\\n", + relevance: 0 + }, + + // names + { + className: "name entity", + begin: "\\&[a-z]+;", end: "^" + }, + { + className: "name tag", + begin: "\\b[a-z0-9_\\:\\-]+\\b", end: "^" + }, + { + className: "name attribute", + begin: "\\b[a-z0-9_\\:\\-]+=", end: "^", + relevance: 0 + }, + + + { + className: "_tag", + begin: "\\<", end: "\\>", + contains: ["name tag", "name attribute", "string"] + }, + { + className: "_tag", + begin: "\\", + contains: ["name tag"] + } + ] +}; + +} diff --git a/includes/js/dojox/highlight/languages/python.js b/includes/js/dojox/highlight/languages/python.js new file mode 100644 index 0000000..eaffd1f --- /dev/null +++ b/includes/js/dojox/highlight/languages/python.js @@ -0,0 +1,102 @@ +if(!dojo._hasResource["dojox.highlight.languages.python"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages.python"] = true; +dojo.provide("dojox.highlight.languages.python"); + +dojo.require("dojox.highlight._base"); + +(function(){ + var dh = dojox.highlight, dhc = dh.constants; + dh.languages.python = { + // summary: Python highlight definitions + defaultMode: { + lexems: [dhc.UNDERSCORE_IDENT_RE], + illegal: '()', + contains: ['comment', 'string', 'function', 'class', 'number', 'decorator'], + keywords: {'and': 1, 'elif': 1, 'is': 1, 'global': 1, 'as': 1, 'in': 1, 'if': 1, + 'from': 1, 'raise': 1, 'for': 1, 'except': 1, 'finally': 1, 'print': 1, + 'import': 1, 'pass': 1, 'None': 1, 'return': 1, 'exec': 1, 'else': 1, + 'break': 1, 'not': 1, 'with': 1, 'class': 1, 'assert': 1, 'yield': 1, + 'try': 1, 'while': 1, 'continue': 1, 'del': 1, 'or': 1, 'def': 1, 'lambda': 1} + }, + modes: [ + { + className: 'function', + lexems: [dhc.UNDERSCORE_IDENT_RE], + begin: '\\bdef ', end: ':', + illegal: '$', + keywords: {'def': 1}, + contains: ['title', 'params'], + relevance: 10 + }, + { + className: 'class', + lexems: [dhc.UNDERSCORE_IDENT_RE], + begin: '\\bclass ', end: ':', + illegal: '[${]', + keywords: {'class': 1}, + contains: ['title', 'params',], + relevance: 10 + }, + { + className: 'title', + begin: dhc.UNDERSCORE_IDENT_RE, end: '^' + }, + { + className: 'params', + begin: '\\(', end: '\\)', + contains: ['string'] + }, + dhc.HASH_COMMENT_MODE, + dhc.C_NUMBER_MODE, + { + className: 'string', + begin: '\'\'\'', end: '\'\'\'', + relevance: 10 + }, + { + className: 'string', + begin: '"""', end: '"""', + relevance: 10 + }, + dhc.APOS_STRING_MODE, + dhc.QUOTE_STRING_MODE, + dhc.BACKSLASH_ESCAPE, + { + className: 'string', + begin: 'r\'', end: '\'', + relevance: 10 + }, + { + className: 'string', + begin: 'r"', end: '"', + relevance: 10 + }, + { + className: 'string', + begin: 'u\'', end: '(^|[^\\\\])\'', + relevance: 10 + }, + { + className: 'string', + begin: 'u"', end: '(^|[^\\\\])"', + relevance: 10 + }, + { + className: 'string', + begin: 'ur\'', end: '\'', + relevance: 10 + }, + { + className: 'string', + begin: 'ur"', end: '"', + relevance: 10 + }, + { + className: 'decorator', + begin: '@', end: '$' + } + ] + }; +})(); + +} diff --git a/includes/js/dojox/highlight/languages/sql.js b/includes/js/dojox/highlight/languages/sql.js new file mode 100644 index 0000000..0e1ca9c --- /dev/null +++ b/includes/js/dojox/highlight/languages/sql.js @@ -0,0 +1,101 @@ +if(!dojo._hasResource["dojox.highlight.languages.sql"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages.sql"] = true; +dojo.provide("dojox.highlight.languages.sql"); + +dojo.require("dojox.highlight._base"); + +(function(){ + var SQL_KEYWORDS = { + 'all': 1, 'partial': 1, 'global': 1, 'month': 1, + 'current_timestamp': 1, 'using': 1, 'go': 1, 'revoke': 1, + 'smallint': 1, 'indicator': 1, 'end-exec': 1, 'disconnect': 1, + 'zone': 1, 'with': 1, 'character': 1, 'assertion': 1, 'to': 1, + 'add': 1, 'current_user': 1, 'usage': 1, 'input': 1, 'local': 1, + 'alter': 1, 'match': 1, 'collate': 1, 'real': 1, 'then': 1, + 'rollback': 1, 'get': 1, 'read': 1, 'timestamp': 1, 'session_user': 1, + 'not': 1, 'integer': 1, 'bit': 1, 'unique': 1, 'day': 1, 'minute': 1, + 'desc': 1, 'insert': 1, 'execute': 1, 'like': 1, 'level': 1, + 'decimal': 1, 'drop': 1, 'continue': 1, 'isolation': 1, 'found': 1, + 'where': 1, 'constraints': 1, 'domain': 1, 'right': 1, 'national': 1, + 'some': 1, 'module': 1, 'transaction': 1, 'relative': 1, 'second': 1, + 'connect': 1, 'escape': 1, 'close': 1, 'system_user': 1, 'for': 1, + 'deferred': 1, 'section': 1, 'cast': 1, 'current': 1, 'sqlstate': 1, + 'allocate': 1, 'intersect': 1, 'deallocate': 1, 'numeric': 1, + 'public': 1, 'preserve': 1, 'full': 1, 'goto': 1, 'initially': 1, + 'asc': 1, 'no': 1, 'key': 1, 'output': 1, 'collation': 1, 'group': 1, + 'by': 1, 'union': 1, 'session': 1, 'both': 1, 'last': 1, 'language': 1, + 'constraint': 1, 'column': 1, 'of': 1, 'space': 1, 'foreign': 1, + 'deferrable': 1, 'prior': 1, 'connection': 1, 'unknown': 1, + 'action': 1, 'commit': 1, 'view': 1, 'or': 1, 'first': 1, 'into': 1, + 'float': 1, 'year': 1, 'primary': 1, 'cascaded': 1, 'except': 1, + 'restrict': 1, 'set': 1, 'references': 1, 'names': 1, 'table': 1, + 'outer': 1, 'open': 1, 'select': 1, 'size': 1, 'are': 1, 'rows': 1, + 'from': 1, 'prepare': 1, 'distinct': 1, 'leading': 1, 'create': 1, + 'only': 1, 'next': 1, 'inner': 1, 'authorization': 1, 'schema': 1, + 'corresponding': 1, 'option': 1, 'declare': 1, 'precision': 1, + 'immediate': 1, 'else': 1, 'timezone_minute': 1, 'external': 1, + 'varying': 1, 'translation': 1, 'true': 1, 'case': 1, 'exception': 1, + 'join': 1, 'hour': 1, 'default': 1, 'double': 1, 'scroll': 1, + 'value': 1, 'cursor': 1, 'descriptor': 1, 'values': 1, 'dec': 1, + 'fetch': 1, 'procedure': 1, 'delete': 1, 'and': 1, 'false': 1, + 'int': 1, 'is': 1, 'describe': 1, 'char': 1, 'as': 1, 'at': 1, 'in': 1, + 'varchar': 1, 'null': 1, 'trailing': 1, 'any': 1, 'absolute': 1, + 'current_time': 1, 'end': 1, 'grant': 1, 'privileges': 1, 'when': 1, + 'cross': 1, 'check': 1, 'write': 1, 'current_date': 1, 'pad': 1, + 'begin': 1, 'temporary': 1, 'exec': 1, 'time': 1, 'update': 1, + 'catalog': 1, 'user': 1, 'sql': 1, 'date': 1, 'on': 1, 'identity': 1, + 'timezone_hour': 1, 'natural': 1, 'whenever': 1, 'interval': 1, + 'work': 1, 'order': 1, 'cascade': 1, 'diagnostics': 1, 'nchar': 1, + 'having': 1, 'left': 1 + }; + + var dh = dojox.highlight, dhc = dh.constants; + dh.languages.sql = { + // summary: SQL highlight definitions + case_insensitive: true, + defaultMode: { + lexems: [dhc.IDENT_RE], + contains: ['string', 'number', 'comment'], + keywords: { + 'keyword': SQL_KEYWORDS, + 'aggregate': {'count': 1, 'sum': 1, 'min': 1, 'max': 1, 'avg': 1} + } + }, + modes: [ + dhc.C_NUMBER_MODE, + dhc.C_BLOCK_COMMENT_MODE, + { + className: 'comment', + begin: '--', end: '$' + }, + { + className: 'string', + begin: '\'', end: '\'', + contains: ['escape', 'squote'], + relevance: 0 + }, + { + className: 'squote', + begin: '\'\'', end: '^' + }, + { + className: 'string', + begin: '"', end: '"', + contains: [ 'escape', 'dquote'], + relevance: 0 + }, + { + className: 'dquote', + begin: '""', end: '^' + }, + { + className: 'string', + begin: '`', end: '`', + contains: ['escape'] + }, + dhc.BACKSLASH_ESCAPE + ] + }; +})(); + +} diff --git a/includes/js/dojox/highlight/languages/xml.js b/includes/js/dojox/highlight/languages/xml.js new file mode 100644 index 0000000..67dd81d --- /dev/null +++ b/includes/js/dojox/highlight/languages/xml.js @@ -0,0 +1,69 @@ +if(!dojo._hasResource["dojox.highlight.languages.xml"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.highlight.languages.xml"] = true; +dojo.provide("dojox.highlight.languages.xml"); + +dojo.require("dojox.highlight._base"); + +(function(){ + var XML_COMMENT = { + className: 'comment', + begin: '' + }; + + var XML_ATTR = { + className: 'attribute', + begin: ' [a-zA-Z-]+=', end: '^', + contains: ['value'] + }; + + var XML_VALUE = { + className: 'value', + begin: '"', end: '"' + }; + + var dh = dojox.highlight, dhc = dh.constants; + dh.languages.xml = { + defaultMode: { + contains: ['pi', 'comment', 'cdata', 'tag'] + }, + case_insensitive: true, + modes: [ + { + className: 'pi', + begin: '<\\?', end: '\\?>', + relevance: 10 + }, + XML_COMMENT, + { + className: 'cdata', + begin: '<\\!\\[CDATA\\[', end: '\\]\\]>' + }, + { + className: 'tag', + begin: '', + contains: ['title', 'tag_internal'], + relevance: 1.5 + }, + { + className: 'title', + begin: '[A-Za-z:_][A-Za-z0-9\\._:-]+', end: '^', + relevance: 0 + }, + { + className: 'tag_internal', + begin: '^', endsWithParent: true, + contains: ['attribute'], + relevance: 0, + illegal: '[\\+\\.]' + }, + XML_ATTR, + XML_VALUE + ], + // exporting constants + XML_COMMENT: XML_COMMENT, + XML_ATTR: XML_ATTR, + XML_VALUE: XML_VALUE + }; +})(); + +} diff --git a/includes/js/dojox/highlight/resources/highlight.css b/includes/js/dojox/highlight/resources/highlight.css new file mode 100644 index 0000000..45a61a3 --- /dev/null +++ b/includes/js/dojox/highlight/resources/highlight.css @@ -0,0 +1,51 @@ + +.string, +.function .title, +.class .title, +.tag .attribute .value, +.css .rules .value, +.preprocessor, +.ruby .symbol, +.ruby .instancevar, +.ruby .class .parent, +.built_in, +.sql .aggregate, +.django .template_tag, +.django .variable, +.smalltalk .class { + color: #800; +} +.comment, +.java .annotation, +.template_comment { + color: #888; +} +.number, +.regexp, +.javascript .literal, +.smalltalk .symbol, +.smalltalk .char { + color: #080; +} +.javadoc, +.ruby .string, +.python .decorator, +.django .filter .argument, +.smalltalk .localvars, +.smalltalk .array, +.css .attr_selector, +.xml .pi { + color: #88F; +} +.keyword, +.css .id, +.phpdoc, +.function .title, +.class .title, +.vbscript .built_in, +.sql .aggregate, +.rsl .built_in, +.smalltalk .class, +.xml .tag .title { + font-weight: bold; +} diff --git a/includes/js/dojox/highlight/resources/highlight.css.commented.css b/includes/js/dojox/highlight/resources/highlight.css.commented.css new file mode 100644 index 0000000..eddef1f --- /dev/null +++ b/includes/js/dojox/highlight/resources/highlight.css.commented.css @@ -0,0 +1,58 @@ +/* +You can use this file as is or as a starting point for you own styling +*/ + +.string, +.function .title, +.class .title, +.tag .attribute .value, +.css .rules .value, +.preprocessor, +.ruby .symbol, +.ruby .instancevar, +.ruby .class .parent, +.built_in, +.sql .aggregate, +.django .template_tag, +.django .variable, +.smalltalk .class { + color: #800; +} + +.comment, +.java .annotation, +.template_comment { + color: #888; +} + +.number, +.regexp, +.javascript .literal, +.smalltalk .symbol, +.smalltalk .char { + color: #080; +} + +.javadoc, +.ruby .string, +.python .decorator, +.django .filter .argument, +.smalltalk .localvars, +.smalltalk .array, +.css .attr_selector, +.xml .pi { + color: #88F; +} + +.keyword, +.css .id, +.phpdoc, +.function .title, +.class .title, +.vbscript .built_in, +.sql .aggregate, +.rsl .built_in, +.smalltalk .class, +.xml .tag .title { + font-weight: bold; +} diff --git a/includes/js/dojox/highlight/resources/pygments/autumn.css b/includes/js/dojox/highlight/resources/pygments/autumn.css new file mode 100644 index 0000000..b1846f4 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/autumn.css @@ -0,0 +1,22 @@ + +code .comment {color: #aaa; font-style: italic} +code .comment.preproc {color: #4c8317; font-style: normal} +code .comment.special {color: #00a} +code .keyword {color: #00a} +code .keyword.type {color: #0aa} +code .operator.word {color: #00a} +code .name.builtin {color: #0aa} +code .name.function {color: #0a0} +code .name.class {color: #0a0; text-decoration: underline} +code .name.namespace {color: #0aa; text-decoration: underline} +code .name.exception {color: #D2413A; font-weight: bold} +code .name.variable {color: #a00} +code .name.constant {color: #a00} +code .name.entity {color: #800; font-weight: bold} +code .name.attribute {color: #1e90ff} +code .name.tag {color: #1e90ff; font-weight: bold} +code .name.decorator {color: #888} +code .string {color: #a50} +code .string.regex {color: #099} +code .string.symbol {color: #00a} +code .number {color: #099} diff --git a/includes/js/dojox/highlight/resources/pygments/autumn.css.commented.css b/includes/js/dojox/highlight/resources/pygments/autumn.css.commented.css new file mode 100644 index 0000000..3deb7c4 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/autumn.css.commented.css @@ -0,0 +1,28 @@ +/* Pygments autumn style */ + +code .comment {color: #aaa; font-style: italic} +code .comment.preproc {color: #4c8317; font-style: normal} +code .comment.special {color: #00a} + +code .keyword {color: #00a} +code .keyword.type {color: #0aa} + +code .operator.word {color: #00a} + +code .name.builtin {color: #0aa} +code .name.function {color: #0a0} +code .name.class {color: #0a0; text-decoration: underline} +code .name.namespace {color: #0aa; text-decoration: underline} +code .name.exception {color: #D2413A; font-weight: bold} +code .name.variable {color: #a00} +code .name.constant {color: #a00} +code .name.entity {color: #800; font-weight: bold} +code .name.attribute {color: #1e90ff} +code .name.tag {color: #1e90ff; font-weight: bold} +code .name.decorator {color: #888} + +code .string {color: #a50} +code .string.regex {color: #099} +code .string.symbol {color: #00a} + +code .number {color: #099} diff --git a/includes/js/dojox/highlight/resources/pygments/borland.css b/includes/js/dojox/highlight/resources/pygments/borland.css new file mode 100644 index 0000000..85fb11f --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/borland.css @@ -0,0 +1,11 @@ + +code .comment {color: #080; font-style: italic} +code .comment.preproc {color: #008080; font-style: normal} +code .comment.special {font-weight: bold; font-style: normal} +code .keyword {color: #000080; font-weight: bold} +code .operator.word {font-weight: bold} +code .name.attribute {color: #f00} +code .name.tag {color: #000080; font-weight: bold} +code .string {color: #00f} +code .string.char {color: #800080} +code .number {color: #00f} diff --git a/includes/js/dojox/highlight/resources/pygments/borland.css.commented.css b/includes/js/dojox/highlight/resources/pygments/borland.css.commented.css new file mode 100644 index 0000000..9fb9d19 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/borland.css.commented.css @@ -0,0 +1,17 @@ +/* Pygments borland style */ + +code .comment {color: #080; font-style: italic} +code .comment.preproc {color: #008080; font-style: normal} +code .comment.special {font-weight: bold; font-style: normal} + +code .keyword {color: #000080; font-weight: bold} + +code .operator.word {font-weight: bold} + +code .name.attribute {color: #f00} +code .name.tag {color: #000080; font-weight: bold} + +code .string {color: #00f} +code .string.char {color: #800080} + +code .number {color: #00f} diff --git a/includes/js/dojox/highlight/resources/pygments/colorful.css b/includes/js/dojox/highlight/resources/pygments/colorful.css new file mode 100644 index 0000000..06de503 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/colorful.css @@ -0,0 +1,37 @@ + +code .comment {color: #888} +code .comment.preproc {color: #579} +code .comment.special {color: #c00; font-weight: bold} +code .keyword {color: #080; font-weight: bold} +code .keyword.pseudo {color: #038} +code .keyword.type {color: #339} +code .operator {color: #333} +code .operator.word {color: #000; font-weight: bold} +code .name.builtin {color: #007020} +code .name.function {color: #06b; font-weight: bold} +code .name.class {color: #b06; font-weight: bold} +code .name.namespace {color: #0e84b5; font-weight: bold} +code .name.exception {color: #f00; font-weight: bold} +code .name.variable {color: #963} +code .name.variable.instance {color: #33b} +code .name.variable.class {color: #369} +code .name.variable.global {color: #d70; font-weight: bold} +code .name.constant {color: #036; font-weight: bold} +code .name.label {color: #970; font-weight: bold} +code .name.entity {color: #800; font-weight: bold} +code .name.attribute {color: #00c} +code .name.tag {color: #070} +code .name.decorator {color: #555; font-weight: bold} +code .string {background-color: #fff0f0} +code .string.char {color: #04d; background-color: transparent} +code .string.doc {color: #d42; background-color: transparent} +code .string.interpol {background-color: #eee} +code .string.escape {color: #666; font-weight: bold} +code .string.regex {color: #000; background-color: #fff0f0} +code .string.symbol {color: #a60; background-color: transparent} +code .string.other {color: #d20} +code .number {color: #60e} +code .number.integer {color: #00d} +code .number.float {color: #60e} +code .number.hex {color: #058} +code .number.oct {color: #40e} diff --git a/includes/js/dojox/highlight/resources/pygments/colorful.css.commented.css b/includes/js/dojox/highlight/resources/pygments/colorful.css.commented.css new file mode 100644 index 0000000..d63728a --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/colorful.css.commented.css @@ -0,0 +1,43 @@ +/* Pygments colorful style */ + +code .comment {color: #888} +code .comment.preproc {color: #579} +code .comment.special {color: #c00; font-weight: bold} + +code .keyword {color: #080; font-weight: bold} +code .keyword.pseudo {color: #038} +code .keyword.type {color: #339} + +code .operator {color: #333} +code .operator.word {color: #000; font-weight: bold} + +code .name.builtin {color: #007020} +code .name.function {color: #06b; font-weight: bold} +code .name.class {color: #b06; font-weight: bold} +code .name.namespace {color: #0e84b5; font-weight: bold} +code .name.exception {color: #f00; font-weight: bold} +code .name.variable {color: #963} +code .name.variable.instance {color: #33b} +code .name.variable.class {color: #369} +code .name.variable.global {color: #d70; font-weight: bold} +code .name.constant {color: #036; font-weight: bold} +code .name.label {color: #970; font-weight: bold} +code .name.entity {color: #800; font-weight: bold} +code .name.attribute {color: #00c} +code .name.tag {color: #070} +code .name.decorator {color: #555; font-weight: bold} + +code .string {background-color: #fff0f0} +code .string.char {color: #04d; background-color: transparent} +code .string.doc {color: #d42; background-color: transparent} +code .string.interpol {background-color: #eee} +code .string.escape {color: #666; font-weight: bold} +code .string.regex {color: #000; background-color: #fff0f0} +code .string.symbol {color: #a60; background-color: transparent} +code .string.other {color: #d20} + +code .number {color: #60e} +code .number.integer {color: #00d} +code .number.float {color: #60e} +code .number.hex {color: #058} +code .number.oct {color: #40e} diff --git a/includes/js/dojox/highlight/resources/pygments/default.css b/includes/js/dojox/highlight/resources/pygments/default.css new file mode 100644 index 0000000..f0b5f05 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/default.css @@ -0,0 +1,28 @@ + +code {background-color: #f8f8f8} +code .comment {color: #408080; font-style: italic} +code .comment.preproc {color: #bc7a00; font-style: normal} +code .keyword {color: #008000; font-weight: bold} +code .keyword.pseudo {font-weight: normal} +code .operator {color: #666} +code .operator.word {color: #a2f} +code .name.builtin {color: #008000} +code .name.function {color: #00f} +code .name.class {color: #00f; font-weight: bold} +code .name.namespace {color: #00f; font-weight: bold} +code .name.exception {color: #d2413a; font-weight: bold} +code .name.variable {color: #19177c} +code .name.constant {color: #800} +code .name.label {color: #a0a000} +code .name.entity {color: #999; font-weight: bold} +code .name.attribute {color: #7d9029} +code .name.tag {color: #008000; font-weight: bold} +code .name.decorator {color: #a2f} +code .string {color: #ba2121} +code .string.doc {font-style: italic} +code .string.interpol {color: #b68; font-weight: bold} +code .string.escape {color: #b62; font-weight: bold} +code .string.regex {color: #b68} +code .string.symbol {color: #19177c} +code .string.other {color: #008000} +code .number {color: #666} diff --git a/includes/js/dojox/highlight/resources/pygments/default.css.commented.css b/includes/js/dojox/highlight/resources/pygments/default.css.commented.css new file mode 100644 index 0000000..9c13e30 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/default.css.commented.css @@ -0,0 +1,35 @@ +/* Pygments default style */ + +code {background-color: #f8f8f8} + +code .comment {color: #408080; font-style: italic} +code .comment.preproc {color: #bc7a00; font-style: normal} + +code .keyword {color: #008000; font-weight: bold} +code .keyword.pseudo {font-weight: normal} + +code .operator {color: #666} +code .operator.word {color: #a2f} + +code .name.builtin {color: #008000} +code .name.function {color: #00f} +code .name.class {color: #00f; font-weight: bold} +code .name.namespace {color: #00f; font-weight: bold} +code .name.exception {color: #d2413a; font-weight: bold} +code .name.variable {color: #19177c} +code .name.constant {color: #800} +code .name.label {color: #a0a000} +code .name.entity {color: #999; font-weight: bold} +code .name.attribute {color: #7d9029} +code .name.tag {color: #008000; font-weight: bold} +code .name.decorator {color: #a2f} + +code .string {color: #ba2121} +code .string.doc {font-style: italic} +code .string.interpol {color: #b68; font-weight: bold} +code .string.escape {color: #b62; font-weight: bold} +code .string.regex {color: #b68} +code .string.symbol {color: #19177c} +code .string.other {color: #008000} + +code .number {color: #666} diff --git a/includes/js/dojox/highlight/resources/pygments/emacs.css b/includes/js/dojox/highlight/resources/pygments/emacs.css new file mode 100644 index 0000000..8c815ed --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/emacs.css @@ -0,0 +1,29 @@ + +code {background-color: #f8f8f8} +code .comment {color: #080; font-style: italic} +code .comment.preproc {font-style: normal} +code .comment.special {font-style: normal; font-weight: bold} +code .keyword {color: #a2f; font-weight: bold} +code .keyword.pseudo {font-weight: normal} +code .operator {color: #666} +code .operator.word {color: #a2f; font-weight: bold} +code .name.builtin {color: #a2f} +code .name.function {color: #00a000} +code .name.class {color: #00f} +code .name.namespace {color: #00f; font-weight: bold} +code .name.exception {color: #d2413a; font-weight: bold} +code .name.variable {color: #b8860b} +code .name.constant {color: #800} +code .name.label {color: #a0a000} +code .name.entity {color: #999; font-weight: bold} +code .name.attribute {color: #b44} +code .name.tag {color: #008000; font-weight: bold} +code .name.decorator {color: #a2f} +code .string {color: #b44} +code .string.doc {font-style: italic} +code .string.interpol {color: #b68; font-weight: bold} +code .string.escape {color: #b62; font-weight: bold} +code .string.regex {color: #b68} +code .string.symbol {color: #b8860b} +code .string.other {color: #008000} +code .number {color: #666} diff --git a/includes/js/dojox/highlight/resources/pygments/emacs.css.commented.css b/includes/js/dojox/highlight/resources/pygments/emacs.css.commented.css new file mode 100644 index 0000000..ed391e1 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/emacs.css.commented.css @@ -0,0 +1,36 @@ +/* Pygments emacs style */ + +code {background-color: #f8f8f8} + +code .comment {color: #080; font-style: italic} +code .comment.preproc {font-style: normal} +code .comment.special {font-style: normal; font-weight: bold} + +code .keyword {color: #a2f; font-weight: bold} +code .keyword.pseudo {font-weight: normal} + +code .operator {color: #666} +code .operator.word {color: #a2f; font-weight: bold} + +code .name.builtin {color: #a2f} +code .name.function {color: #00a000} +code .name.class {color: #00f} +code .name.namespace {color: #00f; font-weight: bold} +code .name.exception {color: #d2413a; font-weight: bold} +code .name.variable {color: #b8860b} +code .name.constant {color: #800} +code .name.label {color: #a0a000} +code .name.entity {color: #999; font-weight: bold} +code .name.attribute {color: #b44} +code .name.tag {color: #008000; font-weight: bold} +code .name.decorator {color: #a2f} + +code .string {color: #b44} +code .string.doc {font-style: italic} +code .string.interpol {color: #b68; font-weight: bold} +code .string.escape {color: #b62; font-weight: bold} +code .string.regex {color: #b68} +code .string.symbol {color: #b8860b} +code .string.other {color: #008000} + +code .number {color: #666} diff --git a/includes/js/dojox/highlight/resources/pygments/friendly.css b/includes/js/dojox/highlight/resources/pygments/friendly.css new file mode 100644 index 0000000..c4d392a --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/friendly.css @@ -0,0 +1,29 @@ + +code {background-color: #f8f8f8} +code .comment {color: #60a0b0; font-style: italic} +code .comment.preproc {color: #007020; font-style: normal} +code .comment.special {background-color: #fff0f0; font-style: normal} +code .keyword {color: #007020; font-weight: bold} +code .keyword.pseudo {font-weight: normal} +code .operator {color: #666} +code .operator.word {color: #007020; font-weight: bold} +code .name.builtin {color: #007020} +code .name.function {color: #06287e} +code .name.class {color: #0e84b5; font-weight: bold} +code .name.namespace {color: #0e84b5; font-weight: bold} +code .name.exception {color: #007020} +code .name.variable {color: #bb60d5} +code .name.constant {color: #60add5} +code .name.label {color: #002070; font-weight: bold} +code .name.entity {color: #d55537; font-weight: bold} +code .name.attribute {color: #4070a0} +code .name.tag {color: #062873; font-weight: bold} +code .name.decorator {color: #555; font-weight: bold} +code .string {color: #4070a0} +code .string.doc {font-style: italic} +code .string.interpol {color: #70a0d0; font-style: italic} +code .string.escape {color: #4070a0; font-weight: bold} +code .string.regex {color: #235388} +code .string.symbol {color: #517918} +code .string.other {color: #c65d09} +code .number {color: #40a070} diff --git a/includes/js/dojox/highlight/resources/pygments/friendly.css.commented.css b/includes/js/dojox/highlight/resources/pygments/friendly.css.commented.css new file mode 100644 index 0000000..7a1c36f --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/friendly.css.commented.css @@ -0,0 +1,36 @@ +/* Pygments friendly style */ + +code {background-color: #f8f8f8} + +code .comment {color: #60a0b0; font-style: italic} +code .comment.preproc {color: #007020; font-style: normal} +code .comment.special {background-color: #fff0f0; font-style: normal} + +code .keyword {color: #007020; font-weight: bold} +code .keyword.pseudo {font-weight: normal} + +code .operator {color: #666} +code .operator.word {color: #007020; font-weight: bold} + +code .name.builtin {color: #007020} +code .name.function {color: #06287e} +code .name.class {color: #0e84b5; font-weight: bold} +code .name.namespace {color: #0e84b5; font-weight: bold} +code .name.exception {color: #007020} +code .name.variable {color: #bb60d5} +code .name.constant {color: #60add5} +code .name.label {color: #002070; font-weight: bold} +code .name.entity {color: #d55537; font-weight: bold} +code .name.attribute {color: #4070a0} +code .name.tag {color: #062873; font-weight: bold} +code .name.decorator {color: #555; font-weight: bold} + +code .string {color: #4070a0} +code .string.doc {font-style: italic} +code .string.interpol {color: #70a0d0; font-style: italic} +code .string.escape {color: #4070a0; font-weight: bold} +code .string.regex {color: #235388} +code .string.symbol {color: #517918} +code .string.other {color: #c65d09} + +code .number {color: #40a070} diff --git a/includes/js/dojox/highlight/resources/pygments/fruity.css b/includes/js/dojox/highlight/resources/pygments/fruity.css new file mode 100644 index 0000000..019fa02 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/fruity.css @@ -0,0 +1,14 @@ + +code {background-color: #111; color: #fff} +code .comment {color: #080; background-color: #0f140f; font-style: italic} +code .comment.preproc {color: #ff0007; font-weight: bold} +code .keyword {color: #fb660a; font-weight: bold} +code .keyword.pseudo {font-weight: normal} +code .keyword.type {color: #cdcaa9; font-weight: bold} +code .name.function {color: #ff0086; font-weight: bold} +code .name.variable {color: #fb660a} +code .name.constant {color: #0086d2} +code .name.attribute {color: #ff0086; font-weight: bold} +code .name.tag {color: #fb660a; font-weight: bold} +code .string {color: #0086d2} +code .number {color: #0086f7; font-weight: bold} diff --git a/includes/js/dojox/highlight/resources/pygments/fruity.css.commented.css b/includes/js/dojox/highlight/resources/pygments/fruity.css.commented.css new file mode 100644 index 0000000..adf0b59 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/fruity.css.commented.css @@ -0,0 +1,20 @@ +/* Pygments fruity style */ + +code {background-color: #111; color: #fff} + +code .comment {color: #080; background-color: #0f140f; font-style: italic} +code .comment.preproc {color: #ff0007; font-weight: bold} + +code .keyword {color: #fb660a; font-weight: bold} +code .keyword.pseudo {font-weight: normal} +code .keyword.type {color: #cdcaa9; font-weight: bold} + +code .name.function {color: #ff0086; font-weight: bold} +code .name.variable {color: #fb660a} +code .name.constant {color: #0086d2} +code .name.attribute {color: #ff0086; font-weight: bold} +code .name.tag {color: #fb660a; font-weight: bold} + +code .string {color: #0086d2} + +code .number {color: #0086f7; font-weight: bold} diff --git a/includes/js/dojox/highlight/resources/pygments/manni.css b/includes/js/dojox/highlight/resources/pygments/manni.css new file mode 100644 index 0000000..0cbf7e6 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/manni.css @@ -0,0 +1,30 @@ + +code {background-color: #f0f3f3} +code .comment {color: #09f; font-style: italic} +code .comment.preproc {color: #099; font-style: normal} +code .comment.special {font-weight: bold} +code .keyword {color: #069; font-weight: bold} +code .keyword.pseudo {font-weight: normal} +code .keyword.type {color: #078} +code .operator {color: #555} +code .operator.word {color: #000; font-weight: bold} +code .name.builtin {color: #366} +code .name.function {color: #c0f} +code .name.class {color: #0a8; font-weight: bold} +code .name.namespace {color: #0cf; font-weight: bold} +code .name.exception {color: #c00; font-weight: bold} +code .name.variable {color: #033} +code .name.constant {color: #360} +code .name.label {color: #99f} +code .name.entity {color: #999; font-weight: bold} +code .name.attribute {color: #309} +code .name.tag {color: #309; font-weight: bold} +code .name.decorator {color: #99f} +code .string {color: #c30} +code .string.doc {font-style: italic} +code .string.interpol {color: #a00} +code .string.escape {color: #c30; font-weight: bold} +code .string.regex {color: #3aa} +code .string.symbol {color: #fc3} +code .string.other {color: #c30} +code .number {color: #f60} diff --git a/includes/js/dojox/highlight/resources/pygments/manni.css.commented.css b/includes/js/dojox/highlight/resources/pygments/manni.css.commented.css new file mode 100644 index 0000000..d9ba41a --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/manni.css.commented.css @@ -0,0 +1,37 @@ +/* Pygments manni style */ + +code {background-color: #f0f3f3} + +code .comment {color: #09f; font-style: italic} +code .comment.preproc {color: #099; font-style: normal} +code .comment.special {font-weight: bold} + +code .keyword {color: #069; font-weight: bold} +code .keyword.pseudo {font-weight: normal} +code .keyword.type {color: #078} + +code .operator {color: #555} +code .operator.word {color: #000; font-weight: bold} + +code .name.builtin {color: #366} +code .name.function {color: #c0f} +code .name.class {color: #0a8; font-weight: bold} +code .name.namespace {color: #0cf; font-weight: bold} +code .name.exception {color: #c00; font-weight: bold} +code .name.variable {color: #033} +code .name.constant {color: #360} +code .name.label {color: #99f} +code .name.entity {color: #999; font-weight: bold} +code .name.attribute {color: #309} +code .name.tag {color: #309; font-weight: bold} +code .name.decorator {color: #99f} + +code .string {color: #c30} +code .string.doc {font-style: italic} +code .string.interpol {color: #a00} +code .string.escape {color: #c30; font-weight: bold} +code .string.regex {color: #3aa} +code .string.symbol {color: #fc3} +code .string.other {color: #c30} + +code .number {color: #f60} diff --git a/includes/js/dojox/highlight/resources/pygments/murphy.css b/includes/js/dojox/highlight/resources/pygments/murphy.css new file mode 100644 index 0000000..971b505 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/murphy.css @@ -0,0 +1,37 @@ + +code .comment {color: #666; font-style: italic} +code .comment.preproc {color: #579; font-style: normal} +code .comment.special {color: #c00; font-weight: bold} +code .keyword {color: #289; font-weight: bold} +code .keyword.pseudo {color: #08f} +code .keyword.type {color: #66f} +code .operator {color: #333} +code .operator.word {color: #000; font-weight: bold} +code .name.builtin {color: #072} +code .name.function {color: #5ed; font-weight: bold} +code .name.class {color: #e9e; font-weight: bold} +code .name.namespace {color: #0e84b5; font-weight: bold} +code .name.exception {color: #f00; font-weight: bold} +code .name.variable {color: #036} +code .name.variable.instance {color: #aaf} +code .name.variable.class {color: #ccf} +code .name.variable.global {color: #f84} +code .name.constant {color: #5ed; font-weight: bold} +code .name.label {color: #970; font-weight: bold} +code .name.entity {color: #800} +code .name.attribute {color: #007} +code .name.tag {color: #070} +code .name.decorator {color: #555; font-weight: bold} +code .string {background-color: #e0e0ff} +code .string.char {color: #88f; background-color: transparent} +code .string.doc {color: #d42; background-color: transparent} +code .string.interpol {background-color: #eee} +code .string.escape {color: #666; font-weight: bold} +code .string.regex {color: #000; background-color: #e0e0ff} +code .string.symbol {color: #fc8; background-color: transparent} +code .string.other {color: #f88} +code .number {color: #60e; font-weight: bold} +code .number.integer {color: #66f; font-weight: bold} +code .number.float {color: #60e; font-weight: bold} +code .number.hex {color: #058; font-weight: bold} +code .number.oct {color: #40e; font-weight: bold} diff --git a/includes/js/dojox/highlight/resources/pygments/murphy.css.commented.css b/includes/js/dojox/highlight/resources/pygments/murphy.css.commented.css new file mode 100644 index 0000000..bea43b5 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/murphy.css.commented.css @@ -0,0 +1,43 @@ +/* Pygments murphy style */ + +code .comment {color: #666; font-style: italic} +code .comment.preproc {color: #579; font-style: normal} +code .comment.special {color: #c00; font-weight: bold} + +code .keyword {color: #289; font-weight: bold} +code .keyword.pseudo {color: #08f} +code .keyword.type {color: #66f} + +code .operator {color: #333} +code .operator.word {color: #000; font-weight: bold} + +code .name.builtin {color: #072} +code .name.function {color: #5ed; font-weight: bold} +code .name.class {color: #e9e; font-weight: bold} +code .name.namespace {color: #0e84b5; font-weight: bold} +code .name.exception {color: #f00; font-weight: bold} +code .name.variable {color: #036} +code .name.variable.instance {color: #aaf} +code .name.variable.class {color: #ccf} +code .name.variable.global {color: #f84} +code .name.constant {color: #5ed; font-weight: bold} +code .name.label {color: #970; font-weight: bold} +code .name.entity {color: #800} +code .name.attribute {color: #007} +code .name.tag {color: #070} +code .name.decorator {color: #555; font-weight: bold} + +code .string {background-color: #e0e0ff} +code .string.char {color: #88f; background-color: transparent} +code .string.doc {color: #d42; background-color: transparent} +code .string.interpol {background-color: #eee} +code .string.escape {color: #666; font-weight: bold} +code .string.regex {color: #000; background-color: #e0e0ff} +code .string.symbol {color: #fc8; background-color: transparent} +code .string.other {color: #f88} + +code .number {color: #60e; font-weight: bold} +code .number.integer {color: #66f; font-weight: bold} +code .number.float {color: #60e; font-weight: bold} +code .number.hex {color: #058; font-weight: bold} +code .number.oct {color: #40e; font-weight: bold} diff --git a/includes/js/dojox/highlight/resources/pygments/native.css b/includes/js/dojox/highlight/resources/pygments/native.css new file mode 100644 index 0000000..47c361d --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/native.css @@ -0,0 +1,21 @@ + +code {background-color: #202020; color: #d0d0d0} +code .comment {color: #999; font-style: italic} +code .comment.preproc {color: #cd2828; font-style: normal; font-weight: bold} +code .comment.special {color: #e50808; font-style: normal; font-weight: bold; background-color: #520000} +code .keyword {color: #6ab825; font-weight: bold} +code .keyword.pseudo {font-weight: normal} +code .operator.word {color: #6ab825; font-weight: bold} +code .name.builtin {color: #24909d} +code .name.function {color: #40ffff} +code .name.class {color: #447fcf; text-decoration: underline} +code .name.namespace {color: #447fcf; text-decoration: underline} +code .name.exception {color: #bbb} +code .name.variable {color: #40ffff} +code .name.constant {color: #40ffff} +code .name.attribute {color: #bbb} +code .name.tag {color: #6ab825; font-weight: bold} +code .name.decorator {color: #ffa500} +code .string {color: #ed9d13} +code .string.other {color: #ffa500} +code .number {color: #3677a9} diff --git a/includes/js/dojox/highlight/resources/pygments/native.css.commented.css b/includes/js/dojox/highlight/resources/pygments/native.css.commented.css new file mode 100644 index 0000000..6d3306c --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/native.css.commented.css @@ -0,0 +1,28 @@ +/* Pygments native style */ + +code {background-color: #202020; color: #d0d0d0} + +code .comment {color: #999; font-style: italic} +code .comment.preproc {color: #cd2828; font-style: normal; font-weight: bold} +code .comment.special {color: #e50808; font-style: normal; font-weight: bold; background-color: #520000} + +code .keyword {color: #6ab825; font-weight: bold} +code .keyword.pseudo {font-weight: normal} + +code .operator.word {color: #6ab825; font-weight: bold} + +code .name.builtin {color: #24909d} +code .name.function {color: #40ffff} +code .name.class {color: #447fcf; text-decoration: underline} +code .name.namespace {color: #447fcf; text-decoration: underline} +code .name.exception {color: #bbb} +code .name.variable {color: #40ffff} +code .name.constant {color: #40ffff} +code .name.attribute {color: #bbb} +code .name.tag {color: #6ab825; font-weight: bold} +code .name.decorator {color: #ffa500} + +code .string {color: #ed9d13} +code .string.other {color: #ffa500} + +code .number {color: #3677a9} diff --git a/includes/js/dojox/highlight/resources/pygments/pastie.css b/includes/js/dojox/highlight/resources/pygments/pastie.css new file mode 100644 index 0000000..d5e20e3 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/pastie.css @@ -0,0 +1,30 @@ + +code .comment {color: #888} +code .comment.preproc {color: #c00; font-weight: bold} +code .comment.special {color: #c00; font-weight: bold; background-color: #fff0f0} +code .keyword {color: #008800; font-weight: bold} +code .keyword.pseudo {font-weight: normal} +code .keyword.type {color: #888} +code .operator.word {color: #080} +code .name.builtin {color: #038} +code .name.function {color: #06b; font-weight: bold} +code .name.class {color: #b06; font-weight: bold} +code .name.namespace {color: #b06; font-weight: bold} +code .name.exception {color: #b06; font-weight: bold} +code .name.variable {color: #369} +code .name.variable.class {color: #369} +code .name.variable.instance {color: #33b} +code .name.variable.global {color: #d70} +code .name.constant {color: #036; font-weight: bold} +code .name.label {color: #369; font-style: italic} +code .name.attribute {color: #369} +code .name.tag {color: #b06; font-weight: bold} +code .name.decorator {color: #555} +code .name.property {color: #369; font-weight: bold} +code .string {color: #d20; background-color: #fff0f0} +code .string.interpol {color: #33b} +code .string.escape {color: #04d} +code .string.regex {color: #080; background-color: #fff0f0} +code .string.symbol {color: #a60} +code .string.other {color: #2b2; background-color: #f0fff0} +code .number {color: #00d; font-weight: bold} diff --git a/includes/js/dojox/highlight/resources/pygments/pastie.css.commented.css b/includes/js/dojox/highlight/resources/pygments/pastie.css.commented.css new file mode 100644 index 0000000..5b11cae --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/pastie.css.commented.css @@ -0,0 +1,36 @@ +/* Pygments pastie style */ + +code .comment {color: #888} +code .comment.preproc {color: #c00; font-weight: bold} +code .comment.special {color: #c00; font-weight: bold; background-color: #fff0f0} + +code .keyword {color: #008800; font-weight: bold} +code .keyword.pseudo {font-weight: normal} +code .keyword.type {color: #888} + +code .operator.word {color: #080} + +code .name.builtin {color: #038} +code .name.function {color: #06b; font-weight: bold} +code .name.class {color: #b06; font-weight: bold} +code .name.namespace {color: #b06; font-weight: bold} +code .name.exception {color: #b06; font-weight: bold} +code .name.variable {color: #369} +code .name.variable.class {color: #369} +code .name.variable.instance {color: #33b} +code .name.variable.global {color: #d70} +code .name.constant {color: #036; font-weight: bold} +code .name.label {color: #369; font-style: italic} +code .name.attribute {color: #369} +code .name.tag {color: #b06; font-weight: bold} +code .name.decorator {color: #555} +code .name.property {color: #369; font-weight: bold} + +code .string {color: #d20; background-color: #fff0f0} +code .string.interpol {color: #33b} +code .string.escape {color: #04d} +code .string.regex {color: #080; background-color: #fff0f0} +code .string.symbol {color: #a60} +code .string.other {color: #2b2; background-color: #f0fff0} + +code .number {color: #00d; font-weight: bold} diff --git a/includes/js/dojox/highlight/resources/pygments/perldoc.css b/includes/js/dojox/highlight/resources/pygments/perldoc.css new file mode 100644 index 0000000..e9253e6 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/perldoc.css @@ -0,0 +1,23 @@ + +code {background-color: #eed} +code .comment {color: #228b22} +code .comment.preproc {color: #1e889b} +code .comment.special {color: #8b008b; font-weight: bold} +code .keyword {color: #8b008b; font-weight: bold} +code .keyword.type {color: #a7a7a7} +code .operator.word {color: #8b008b} +code .name.builtin {color: #658b00} +code .name.function {color: #008b45} +code .name.class {color: #008b45; font-weight: bold} +code .name.namespace {color: #008b45; text-decoration: underline} +code .name.exception {color: #008b45; font-weight: bold} +code .name.variable {color: #00688b} +code .name.constant {color: #00688b} +code .name.attribute {color: #658b00} +code .name.tag {color: #8b008b; font-weight: bold} +code .name.decorator {color: #707a7c} +code .string {color: #cd5555} +code .string.regex {color: #1c7e71} +code .string.other {color: #cb6c20} +code .string.heredoc {color: #1c7e71; font-style: italic} +code .number {color: #b452cd} diff --git a/includes/js/dojox/highlight/resources/pygments/perldoc.css.commented.css b/includes/js/dojox/highlight/resources/pygments/perldoc.css.commented.css new file mode 100644 index 0000000..2a56e2f --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/perldoc.css.commented.css @@ -0,0 +1,30 @@ +/* Pygments perldoc style */ + +code {background-color: #eed} + +code .comment {color: #228b22} +code .comment.preproc {color: #1e889b} +code .comment.special {color: #8b008b; font-weight: bold} + +code .keyword {color: #8b008b; font-weight: bold} +code .keyword.type {color: #a7a7a7} + +code .operator.word {color: #8b008b} + +code .name.builtin {color: #658b00} +code .name.function {color: #008b45} +code .name.class {color: #008b45; font-weight: bold} +code .name.namespace {color: #008b45; text-decoration: underline} +code .name.exception {color: #008b45; font-weight: bold} +code .name.variable {color: #00688b} +code .name.constant {color: #00688b} +code .name.attribute {color: #658b00} +code .name.tag {color: #8b008b; font-weight: bold} +code .name.decorator {color: #707a7c} + +code .string {color: #cd5555} +code .string.regex {color: #1c7e71} +code .string.other {color: #cb6c20} +code .string.heredoc {color: #1c7e71; font-style: italic} + +code .number {color: #b452cd} diff --git a/includes/js/dojox/highlight/resources/pygments/trac.css b/includes/js/dojox/highlight/resources/pygments/trac.css new file mode 100644 index 0000000..2085719 --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/trac.css @@ -0,0 +1,20 @@ + +code .comment {color: #998; font-style: italic} +code .comment.preproc {color: #999; font-style: normal; font-weight: bold} +code .comment.special {color: #999; font-weight: bold} +code .keyword {font-weight: bold} +code .keyword.type {color: #458} +code .operator {font-weight: bold} +code .name.builtin {color: #999} +code .name.function {color: #900; font-weight: bold} +code .name.class {color: #458; font-weight: bold} +code .name.namespace {color: #555} +code .name.exception {color: #900; font-weight: bold} +code .name.variable {color: #008080} +code .name.constant {color: #008080} +code .name.entity {color: #800080} +code .name.attribute {color: #008080} +code .name.tag {color: #000080} +code .string {color: #b84} +code .string.regex {color: #808000} +code .number {color: #099} diff --git a/includes/js/dojox/highlight/resources/pygments/trac.css.commented.css b/includes/js/dojox/highlight/resources/pygments/trac.css.commented.css new file mode 100644 index 0000000..127b1fb --- /dev/null +++ b/includes/js/dojox/highlight/resources/pygments/trac.css.commented.css @@ -0,0 +1,26 @@ +/* Pygments trac style */ + +code .comment {color: #998; font-style: italic} +code .comment.preproc {color: #999; font-style: normal; font-weight: bold} +code .comment.special {color: #999; font-weight: bold} + +code .keyword {font-weight: bold} +code .keyword.type {color: #458} + +code .operator {font-weight: bold} + +code .name.builtin {color: #999} +code .name.function {color: #900; font-weight: bold} +code .name.class {color: #458; font-weight: bold} +code .name.namespace {color: #555} +code .name.exception {color: #900; font-weight: bold} +code .name.variable {color: #008080} +code .name.constant {color: #008080} +code .name.entity {color: #800080} +code .name.attribute {color: #008080} +code .name.tag {color: #000080} + +code .string {color: #b84} +code .string.regex {color: #808000} + +code .number {color: #099} diff --git a/includes/js/dojox/highlight/tests/test_highlight.html b/includes/js/dojox/highlight/tests/test_highlight.html new file mode 100644 index 0000000..93b1534 --- /dev/null +++ b/includes/js/dojox/highlight/tests/test_highlight.html @@ -0,0 +1,327 @@ + + + dojox.highlight - syntax highlighting | The Dojo Toolkit + + + + + + + + + +

      dojox.highlight

      + +

      client-side syntax highlighting for a number of languages.

      + +

      NOTE: All languages listed here have working language definitions, though +not all exist in the release or dojo subversion. The missing packs are not publically available. +based on +

      + +

      Examples:

      + +

      Some Python code:

      + +
      @requires_authorization
      +def somefunc(param1, param2):
      +  '''A docstring'''
      +  if param1 > param2: # interesting
      +    print 'Gre\'ater'
      +    print ''
      +  return param2 - param1 + 1
      +  
      +class SomeClass:
      pass +
      + + + + +

      A chunk of PHP:

      + +
      
      +$opAr = array (    "-a|--append", // a or append toggle, nothing extra
      +        "-i|--input:", // i or input with next input being needed
      +        "-l|--list:",           // l with input needed
      +		//"--foo",     // broken
      +        "-f:",           // f with no input
      +        "--wot:"      // wot with input, no short
      +        );
      +
      +
      +$op = bgetop($opAr);
      +if (is_array($op)) { print_r($op); }
      +
      +/* here is the code: */
      +
      +function bgetop($opAr=array(),$unknown=true) {
      +
      +$argv = $_SERVER['argv'];
      +$argc = $_SERVER['argc'];
      +$argPos = 1; // zero is program running
      +
      +// foreach arg
      +while ($argPos<$argc) {
      +    $arg = $argv[$argPos];
      +    if ($arg{0}=="-") {
      +        if ($arg{1}=="-") {
      +        $var = substr($arg,2,strlen($arg));
      +        } else { $var = $arg{1}; }
      +        foreach ($opAr as $opk => $opv) {
      +            if (!isset($return[$var])) {
      +            if (strpos($opv,$arg) !== FALSE) {
      +                // this is where the -f -foo fix needs to be,
      +                // the partial string exists in this record,
      +                // but we need to determine if it's accurate
      +                // somehow (i'm thinking: eregi?)
      +                if ($accurate=1) {
      +                    // we foudn the key
      +                    if (strpos($opv,':') !== FALSE) {
      +                        // next value is the one to use,
      +                        // then skip it in the parser.
      +                        if (isset($argv[$argPos+1])) {
      +                            $return[$var] = $argv[++$argPos];
      +                            } else {
      +                            $return[$var] = FALSE;     
      +                            }
      +                        } else {
      +                        // just set the toggle
      +                        $return[$var] = TRUE;
      +                        }
      +                    // don't check this opAr value again
      +                    unset($opAr[$opk]);
      +                    }
      +                } // if accurate
      +            } // !isset already
      +            } // foreach opAr    
      +    } else { // we weren't expecting a non-hyphened argument, possibly just a filename, or whatnot
      +        if ($unknown) { $return['unknown'][]=$arg; }
      +    }
      +    $argPos++;
      +} // while argPos < argc
      +
      +if (is_array($return)) {
      +return $return;
      +} else { return 0; }
      +
      +} // end function bgetop
      +
      +
      + +

      A custom XML document:

      + +
      <?xml version="1.0"?>
      +<response value="ok">
      +  <text>Ok</text>
      +  <comment/>
      +  <ns:description><![CDATA[ 
      +  CDATA is <not> magical. 
      +  ]]></ns:description>
      +</response>
      +
      + +

      Some HTML code:

      + +
      <head>
      +  <title>Title</title>
      +<body>
      +  <p class="something">Something</p>
      +  <p class=something>Something</p>
      +  <!-- comment -->
      +  <p class>Something</p>
      +  <p class="something" title="p">Something</p>
      +</body>
      +
      + +

      HTML with Django templates:

      + +
      {% if articles|length %}
      +{% for article in articles %}
      +
      +{# Striped table #}
      +<tr class="{% cycle odd,even %}">
      +  <td>{{ article|default:"Hi... "|escape }}</td>
      +  <td>{{ article.date|date:"d.m.Y" }}</td>
      +</tr>
      +  
      +{% endfor %}
      +{% endif %}
      +
      +{% comment %}
      +Comments may be long and
      +multiline.
      +{% endcomment %}
      +
      + +

      Some CSS code:

      + +
      body, 
      +html {
      +  font: Tahoma, Arial, san-serif;
      +}
      +
      +#content {
      +  width: 100%; /* css comment */
      +  height: 100%
      +}
      +
      +p[lang=ru] {
      +  color: red;
      +}
      +
      + +

      Explicit Python highlight:

      + +
      for x in [1, 2, 3]:
      +  count(x)
      +
      + +

      Disabled highlighting:

      + +
      <div id="contents">
      +  <p>Hello, World!
      +</div>
      +
      + +

      Normal dojo-looking code

      + +
      
      +dojo.provide("some.object");
      +dojo.declare("some.object",null,{
      +	param: "value",
      +	_myMethod: function(/* Event */e){
      +		this.inherited(arguments);
      +	},
      +	// comments
      +	_another: function(){
      +		dojo.addClass("foo","hovered");
      +	}
      +});
      +dojo.addOnLoad(function(){
      +	//
      +	// comments with <HTML> inline
      +	var d = dojo;
      +	d.mixin(d,{
      +		foo: function(e){
      +			d.bar(e);
      +		},
      +		bar: function(e){
      +			alert(e);
      +		}
      +	});
      +});
      +
      + +

      Lazy, xhr'd code:

      + +
      + +
      + +

      Text with inlined JavaScript code: dojo.forEach(a, function(x){ console.log(x); }); — that was the inlined sample.

      + +
      + +

      Markuped code (python), no language was specified:

      + +
      @requires_authorization
      +def somefunc(param1, param2):
      +  '''A docstring'''
      +  if param1 > param2: # interesting
      +    print 'Gre\'ater'
      +    print ''
      +  return param2 - param1 + 1
      +  
      +class SomeClass:
      pass +
      + +

      Markuped code, "python" was specified:

      + +
      @requires_authorization
      +def somefunc(param1, param2):
      +  '''A docstring'''
      +  if param1 > param2: # interesting
      +    print 'Gre\'ater'
      +    print ''
      +  return param2 - param1 + 1
      +  
      +class SomeClass:
      pass +
      + + + diff --git a/includes/js/dojox/highlight/tests/test_pygments.html b/includes/js/dojox/highlight/tests/test_pygments.html new file mode 100644 index 0000000..6bdced6 --- /dev/null +++ b/includes/js/dojox/highlight/tests/test_pygments.html @@ -0,0 +1,142 @@ + + + + dojox.highlight.pygments - syntax highlighting | The Dojo Toolkit + + + + + + + + + + + +

      Test Pygments-based highlighting

      + +

      Current theme from the pygments set: + +

      + +

      Javascript:

      + +
      function initHighlight(block) {
      +  if (block.className.search(/\bno\-highlight\b/) != -1)
      +    return false;
      +  try {
      +    blockText(block);
      +  } catch (e) {
      +    if (e == 'Complex markup')
      +      return;
      +  }//try
      +  var classes = block.className.split(/\s+/);
      +  for (var i = 0; i < classes.length; i++) {
      +    if (LANGUAGES[classes[i]]) {
      +      highlightLanguage(block, classes[i]);
      +      return;
      +    }//if
      +  }//for
      +  highlightAuto(block);
      +}//initHighlight
      + +

      Some CSS code:

      + +
      body, 
      +html {
      +  font: Tahoma, Arial, sans-serif;
      +}
      +
      +#content {
      +  width: 100%; /* test comment */
      +  height: 100%
      +}
      +
      +p[lang=ru] {
      +  color: red;
      +}
      +
      + +

      Some HTML code:

      + +
      <head>
      +  <title>Title</title>
      +<body>
      +  <p class="something">Something</p>
      +  <p class=something>Something</p>
      +  <!-- comment -->
      +  <p class>Something</p>
      +  <p class="something" title="p">Something</p>
      +</body>
      +
      + +

      A custom XML document:

      + +
      <?xml version="1.0"?>
      +<response value="ok">
      +  <text>Ok</text>
      +  <comment/>
      +  <ns:description><![CDATA[ 
      +  CDATA is <not> magical. 
      +  ]]></ns:description>
      +</response>
      +
      + + + diff --git a/includes/js/dojox/image/Gallery.js b/includes/js/dojox/image/Gallery.js new file mode 100644 index 0000000..d29ae22 --- /dev/null +++ b/includes/js/dojox/image/Gallery.js @@ -0,0 +1,182 @@ +if(!dojo._hasResource["dojox.image.Gallery"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.image.Gallery"] = true; +dojo.provide("dojox.image.Gallery"); +dojo.experimental("dojox.image.Gallery"); +// +// dojox.image.Gallery courtesy Shane O Sullivan, licensed under a Dojo CLA +// @author Copyright 2007 Shane O Sullivan (shaneosullivan1@gmail.com) +// +// For a sample usage, see http://www.skynet.ie/~sos/photos.php +// +// TODO: Make public, document params and privitize non-API conformant methods. +// document topics. + +dojo.require("dojo.fx"); +dojo.require("dijit._Widget"); +dojo.require("dijit._Templated"); +dojo.require("dojox.image.ThumbnailPicker"); +dojo.require("dojox.image.SlideShow"); + +dojo.declare("dojox.image.Gallery", + [dijit._Widget, dijit._Templated], + { + // summary: + // Gallery widget that wraps a dojox.image.ThumbnailPicker and dojox.image.SlideShow widget + // + // imageHeight: Number + // Maximum height of an image in the SlideShow widget + imageHeight: 375, + + // imageWidth: Number + // Maximum width of an image in the SlideShow widget + imageWidth: 500, + + // pageSize: Number + // The number of records to retrieve from the data store per request. + pageSize: dojox.image.SlideShow.prototype.pageSize, + + // autoLoad: Boolean + // If true, images are loaded before the user views them. If false, an + // image is loaded when the user displays it. + autoLoad: true, + + // linkAttr: String + // Defines the name of the attribute to request from the store to retrieve the + // URL to link to from an image, if any. + linkAttr: "link", + + // imageThumbAttr: String + // Defines the name of the attribute to request from the store to retrieve the + // URL to the thumbnail image. + imageThumbAttr: "imageUrlThumb", + + // imageLargeAttr: String + // Defines the name of the attribute to request from the store to retrieve the + // URL to the image. + imageLargeAttr: "imageUrl", + + // titleAttr: String + // Defines the name of the attribute to request from the store to retrieve the + // title of the picture, if any. + titleAttr: "title", + + // slideshowInterval: Integer + // time in seconds, between image changes in the slide show. + slideshowInterval: 3, + + templateString:"
      \n\t
      \n\t
      \n
      \n", + + postCreate: function(){ + // summary: Initializes the widget, creates the ThumbnailPicker and SlideShow widgets + this.widgetid = this.id; + this.inherited(arguments) + + this.thumbPicker = new dojox.image.ThumbnailPicker({ + linkAttr: this.linkAttr, + imageLargeAttr: this.imageLargeAttr, + titleAttr: this.titleAttr, + useLoadNotifier: true, + size: this.imageWidth + }, this.thumbPickerNode); + + + this.slideShow = new dojox.image.SlideShow({ + imageHeight: this.imageHeight, + imageWidth: this.imageWidth, + autoLoad: this.autoLoad, + linkAttr: this.linkAttr, + imageLargeAttr: this.imageLargeAttr, + titleAttr: this.titleAttr, + slideshowInterval: this.slideshowInterval, + pageSize: this.pageSize + }, this.slideShowNode); + + var _this = this; + //When an image is shown in the Slideshow, make sure it is visible + //in the ThumbnailPicker + dojo.subscribe(this.slideShow.getShowTopicName(), function(packet){ + //if(packet.index < _this.thumbPicker._thumbIndex + // || packet.index > _this.thumbPicker._thumbIndex + _this.thumbPicker.numberThumbs -1){ + //if(!_this.thumbPicker.isVisible(packet.index)){ + //var index = packet.index - (packet.index % _this.thumbPicker.numberThumbs); + _this.thumbPicker._showThumbs(packet.index); + //} + }); + //When the user clicks a thumbnail, show that image + dojo.subscribe(this.thumbPicker.getClickTopicName(), function(evt){ + _this.slideShow.showImage(evt.index); + }); + //When the ThumbnailPicker moves to show a new set of pictures, + //make the Slideshow start loading those pictures first. + dojo.subscribe(this.thumbPicker.getShowTopicName(), function(evt){ + _this.slideShow.moveImageLoadingPointer(evt.index); + }); + //When an image finished loading in the slideshow, update the loading + //notification in the ThumbnailPicker + dojo.subscribe(this.slideShow.getLoadTopicName(), function(index){ + _this.thumbPicker.markImageLoaded(index); + }); + this._centerChildren(); + }, + + setDataStore: function(dataStore, request, /*optional*/paramNames){ + // summary: Sets the data store and request objects to read data from. + // dataStore: + // An implementation of the dojo.data.api.Read API. This accesses the image + // data. + // request: + // An implementation of the dojo.data.api.Request API. This specifies the + // query and paging information to be used by the data store + // paramNames: + // An object defining the names of the item attributes to fetch from the + // data store. The four attributes allowed are 'linkAttr', 'imageLargeAttr', + // 'imageThumbAttr' and 'titleAttr' + this.thumbPicker.setDataStore(dataStore, request, paramNames); + this.slideShow.setDataStore(dataStore, request, paramNames); + }, + + reset: function(){ + // summary: Resets the widget to its initial state + this.slideShow.reset(); + this.thumbPicker.reset(); + }, + + showNextImage: function(inTimer){ + // summary: Changes the image being displayed in the SlideShow to the next + // image in the data store + // inTimer: Boolean + // If true, a slideshow is active, otherwise the slideshow is inactive. + this.slideShow.showNextImage(); + }, + + toggleSlideshow: function(){ + // summary: Switches the slideshow mode on and off. + this.slideShow.toggleSlideshow(); + }, + + showImage: function(index, /*optional*/callback){ + // summary: Shows the image at index 'idx'. + // idx: Number + // The position of the image in the data store to display + // callback: Function + // Optional callback function to call when the image has finished displaying. + this.slideShow.showImage(index, callback); + }, + + _centerChildren: function() { + // summary: Ensures that the ThumbnailPicker and the SlideShow widgets + // are centered. + var thumbSize = dojo.marginBox(this.thumbPicker.outerNode); + var slideSize = dojo.marginBox(this.slideShow.outerNode); + + var diff = (thumbSize.w - slideSize.w) / 2; + + if(diff > 0) { + dojo.style(this.slideShow.outerNode, "marginLeft", diff + "px"); + } else if(diff < 0) { + dojo.style(this.thumbPicker.outerNode, "marginLeft", (diff * -1) + "px"); + } + } +}); + +} diff --git a/includes/js/dojox/image/Lightbox.js b/includes/js/dojox/image/Lightbox.js new file mode 100644 index 0000000..79056d3 --- /dev/null +++ b/includes/js/dojox/image/Lightbox.js @@ -0,0 +1,451 @@ +if(!dojo._hasResource["dojox.image.Lightbox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.image.Lightbox"] = true; +dojo.provide("dojox.image.Lightbox"); +dojo.experimental("dojox.image.Lightbox"); + +dojo.require("dijit.Dialog"); +dojo.require("dojox.fx._base"); + +dojo.declare("dojox.image.Lightbox", + dijit._Widget,{ + // summary: + // A dojo-based Lightbox implementation. + // + // description: + // An Elegant, keyboard accessible, markup and store capable Lightbox widget to show images + // in a modal dialog-esque format. Can show individual images as Modal dialog, or can group + // images with multiple entry points, all using a single "master" Dialog for visualization + // + // key controls: + // ESC - close + // Down Arrow / Rt Arrow / N - Next Image + // Up Arrow / Lf Arrow / P - Previous Image + // + // example: + // | show lightbox + // + // example: + // | show group lightbox + // | show group lightbox + // + // example: + // | not implemented fully yet, though works with basic datastore access. need to manually call + // | widget._attachedDialog.addImage(item,"fromStore") for each item in a store result set. + // |
      + // + // group: String + // Grouping images in a page with similar tags will provide a 'slideshow' like grouping of images + group: "", + + // title: String + // A string of text to be shown in the Lightbox beneath the image (empty if using a store) + title: "", + + // href; String + // Link to image to use for this Lightbox node (empty if using a store). + href: "", + + // duration: Integer + // Generic time in MS to adjust the feel of widget. could possibly add various + // durations for the various actions (dialog fadein, sizeing, img fadein ...) + duration: 500, + + // _allowPassthru: Boolean + // Privately set this to disable/enable natural link of anchor tags + _allowPassthru: false, + + // _attachedDialg: dojox.image._LightboxDialog + // The pointer to the global lightbox dialog for this widget + _attachedDialog: null, // try to share a single underlay per page? + + startup: function(){ + this.inherited(arguments); + // setup an attachment to the masterDialog (or create the masterDialog) + var tmp = dijit.byId('dojoxLightboxDialog'); + if(tmp){ + this._attachedDialog = tmp; + }else{ + // this is the first instance to start, so we make the masterDialog + this._attachedDialog = new dojox.image._LightboxDialog({ id: "dojoxLightboxDialog" }); + this._attachedDialog.startup(); + } + if(!this.store){ + // FIXME: full store support lacking, have to manually call this._attachedDialog.addImage(imgage,group) as it stands + this._addSelf(); + this.connect(this.domNode, "onclick", "_handleClick"); + } + }, + + _addSelf: function(){ + // summary: Add this instance to the master LightBoxDialog + this._attachedDialog.addImage({ + href: this.href, + title: this.title + },this.group||null); + }, + + _handleClick: function(/* Event */e){ + // summary: Handle the click on the link + if(!this._allowPassthru){ e.preventDefault(); } + else{ return; } + this.show(); + }, + + show: function(){ + // summary: Show the Lightbox with this instance as the starting point + this._attachedDialog.show(this); + }, + + disable: function(){ + // summary: Disables event clobbering and dialog, and follows natural link + this._allowPassthru = true; + }, + + enable: function(){ + // summary: Enables the dialog (prevents default link) + this._allowPassthru = false; + } + +}); + +dojo.declare("dojox.image._LightboxDialog", + dijit.Dialog,{ + // summary: + // The "dialog" shared between any Lightbox instances on the page + // + // description: + // + // A widget that intercepts anchor links (typically around images) + // and displays a modal Dialog. this is the actual Dialog, which you can + // create and populate manually, though should use simple Lightbox's + // unless you need to direct access. + // + // There should only be one of these on a page, so all dojox.image.Lightbox's will us it + // (the first instance of a Lightbox to be show()'n will create me If i do not exist) + // + // title: String + // The current title, read from object passed to show() + title: "", + + // FIXME: implement titleTemplate + + // inGroup: Array + // Array of objects. this is populated by from the JSON object _groups, and + // should not be populate manually. it is a placeholder for the currently + // showing group of images in this master dialog + inGroup: null, + + // imgUrl: String + // The src="" attribute of our imageNode (can be null at statup) + imgUrl: "", + + // errorMessage: String + // The text to display when an unreachable image is linked + errorMessage: "Image not found.", + + // adjust: Boolean + // If true, ensure the image always stays within the viewport + // more difficult than necessary to disable, but enabled by default + // seems sane in most use cases. + adjust: true, + + // an object of arrays, each array (of objects) being a unique 'group' + _groups: { XnoGroupX: [] }, + + // errorImg: Url + // Path to the image used when a 404 is encountered + errorImg: dojo.moduleUrl("dojox.image","resources/images/warning.png"), + + // privates: + _imageReady: false, + _blankImg: dojo.moduleUrl("dojo","resources/blank.gif"), + _clone: null, // the "untained" image + _wasStyled: null, // indicating taint on the imgNode + + // animation holders: + _loadingAnim:null, + _showImageAnim: null, + _showNavAnim: null, + _animConnects: [], + + templateString:"
      \n\t
      \n\t\t
      \n\t\t\t\"${title}\"\n\t\t\t
      \n\t\t\t\t
      \n\t\t\t\t
      \t\n\t\t\t\t
      \n\n\t\t\t\t
      ${title}
      \n\t\t\t
      \n\t\t
      \t\n\t\t\n\t
      \n
      \n", + + startup: function(){ + // summary: Add some extra event handlers, and startup our superclass. + + this.inherited(arguments); + this._clone = dojo.clone(this.imgNode); + this.connect(document.documentElement,"onkeypress","_handleKey"); + this.connect(window,"onresize","_position"); + this.connect(this.nextNode, "onclick", "_nextImage"); + this.connect(this.prevNode, "onclick", "_prevImage"); + this.connect(this.closeNode, "onclick", "hide"); + this._makeAnims(); + this._vp = dijit.getViewport(); + + }, + + show: function(/* Object */groupData){ + // summary: Show the Master Dialog. Starts the chain of events to show + // an image in the dialog, including showing the dialog if it is + // not already visible + // + // groupData: Object + // needs href and title attributes. the values for this image. + + var _t = this; // size + + // we only need to call dijit.Dialog.show() if we're not already open. + if(!_t.open){ _t.inherited(arguments); } + + if(this._wasStyled){ + // ugly fix for IE being stupid: + dojo._destroyElement(_t.imgNode); + _t.imgNode = dojo.clone(_t._clone); + dojo.place(_t.imgNode,_t.imageContainer,"first"); + _t._makeAnims(); + _t._wasStyled = false; + } + + dojo.style(_t.imgNode,"opacity","0"); + dojo.style(_t.titleNode,"opacity","0"); + + _t._imageReady = false; + _t.imgNode.src = groupData.href; + + if((groupData.group && groupData !== "XnoGroupX") || _t.inGroup){ + if(!_t.inGroup){ + _t.inGroup = _t._groups[(groupData.group)]; + // determine where we were or are in the show + dojo.forEach(_t.inGroup,function(g,i){ + if(g.href == groupData.href){ + _t._positionIndex = i; + } + },_t); + } + if(!_t._positionIndex){ + _t._positionIndex=0; + _t.imgNode.src = _t.inGroup[_t._positionIndex].href; + } + // FIXME: implement titleTemplate + _t.groupCount.innerHTML = " (" +(_t._positionIndex+1) +" of "+_t.inGroup.length+")"; + _t.prevNode.style.visibility = "visible"; + _t.nextNode.style.visibility = "visible"; + }else{ + // single images don't have buttons, or counters: + _t.groupCount.innerHTML = ""; + _t.prevNode.style.visibility = "hidden"; + _t.nextNode.style.visibility = "hidden"; + } + _t.textNode.innerHTML = groupData.title; + + if(!_t._imageReady || _t.imgNode.complete === true){ + // connect to the onload of the image + _t._imgConnect = dojo.connect(_t.imgNode, "onload", _t, function(){ + _t._imageReady = true; + _t.resizeTo({ + w: _t.imgNode.width, + h: _t.imgNode.height, + duration:_t.duration + }); + // cleanup + dojo.disconnect(_t._imgConnect); + if(_t._imgError){ dojo.disconnect(_t._imgError); } + }); + + // listen for 404's: + _t._imgError = dojo.connect(_t.imgNode, "onerror", _t, function(){ + dojo.disconnect(_t._imgError); + // trigger the above onload with a new src: + _t.imgNode.src = _t.errorImg; + _t._imageReady = true; + _t.textNode.innerHTML = _t.errorMessage; + }); + + // onload doesn't fire in IE if you connect before you set the src. + // hack to re-set the src after onload connection made: + if(dojo.isIE){ _t.imgNode.src = _t.imgNode.src; } + + }else{ + // do it quickly. kind of a hack, but image is ready now + _t.resizeTo({ w: _t.imgNode.width, h: _t.imgNode.height, duration: 1 }); + } + + }, + + _nextImage: function(){ + // summary: Load next image in group + if(!this.inGroup){ return; } + if(this._positionIndex+1 this._vp.h || size.w + 50 > this._vp.w)){ + size = this._scaleToFit(size); + } + + var _sizeAnim = dojox.fx.sizeTo({ + node: this.containerNode, + duration: size.duration||this.duration, + width: size.w, + height: size.h + 30 + }); + this.connect(_sizeAnim,"onEnd","_showImage"); + _sizeAnim.play(15); + }, + + _showImage: function(){ + // summary: Fade in the image, and fire showNav + this._showImageAnim.play(1); + }, + + _showNav: function(){ + // summary: Fade in the footer, and setup our connections. + this._showNavAnim.play(1); + }, + + hide: function(){ + // summary: Hide the Master Lightbox + dojo.fadeOut({node:this.titleNode, duration:200, + onEnd: dojo.hitch(this,function(){ + // refs #5112 - if you _don't_ change the .src, safari will _never_ fire onload for this image + this.imgNode.src = this._blankImg; + }) + }).play(5); + this.inherited(arguments); + this.inGroup = null; + this._positionIndex = null; + }, + + addImage: function(child, group){ + // summary: Add an image to this Master Lightbox + // + // child: Object + // The image information to add. + // href: String - link to image (required) + // title: String - title to display + // + // group: String? + // attach to group of similar tag or null for individual image instance + var g = group; + if(!child.href){ return; } + if(g){ + if(!this._groups[g]){ + this._groups[g] = []; + } + this._groups[g].push(child); + }else{ this._groups["XnoGroupX"].push(child); } + }, + + _handleKey: function(/* Event */e){ + // summary: Handle keyboard navigation internally + if(!this.open){ return; } + + var dk = dojo.keys; + var key = (e.charCode == dk.SPACE ? dk.SPACE : e.keyCode); + switch(key){ + + case dk.ESCAPE: this.hide(); break; + + case dk.DOWN_ARROW: + case dk.RIGHT_ARROW: + case 78: // key "n" + this._nextImage(); break; + + case dk.UP_ARROW: + case dk.LEFT_ARROW: + case 80: // key "p" + this._prevImage(); break; + } + }, + + _scaleToFit: function(/* Object */size){ + // summary: resize an image to fit within the bounds of the viewport + // size: Object + // The 'size' object passed around for this image + var ns = {}; + + // one of the dimensions is too big, go with the smaller viewport edge: + if(this._vp.h > this._vp.w){ + // don't actually touch the edges: + ns.w = this._vp.w - 70; + ns.h = ns.w * (size.h / size.w); + }else{ + // give a little room for the titlenode, too: + ns.h = this._vp.h - 80; + ns.w = ns.h * (size.w / size.h); + } + + // trigger the nasty width="auto" workaround in show() + this._wasStyled = true; + + // we actually have to style this image, it's too big + var s = this.imgNode.style; + s.height = ns.h + "px"; + s.width = ns.w + "px"; + + ns.duration = size.duration; + return ns; // Object + + }, + + _position: function(/* Event */e){ + // summary: we want to know the viewport size any time it changes + this.inherited(arguments); + this._vp = dijit.getViewport(); + }, + + _makeAnims: function(){ + // summary: make and cleanup animation and animation connections + + dojo.forEach(this._animConnects,dojo.disconnect); + this._animConnects = []; + this._showImageAnim = dojo.fadeIn({ + node: this.imgNode, + duration: this.duration + }); + this._animConnects.push(dojo.connect(this._showImageAnim, "onEnd", this, "_showNav")); + this._loadingAnim = dojo.fx.combine([ + dojo.fadeOut({ node:this.imgNode, duration:175 }), + dojo.fadeOut({ node:this.titleNode, duration:175 }) + ]); + this._animConnects.push(dojo.connect(this._loadingAnim, "onEnd", this, "_prepNodes")); + this._showNavAnim = dojo.fadeIn({ node: this.titleNode, duration:225 }); + } +}); + +} diff --git a/includes/js/dojox/image/Magnifier.js b/includes/js/dojox/image/Magnifier.js new file mode 100644 index 0000000..b6a3923 --- /dev/null +++ b/includes/js/dojox/image/Magnifier.js @@ -0,0 +1,75 @@ +if(!dojo._hasResource["dojox.image.Magnifier"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.image.Magnifier"] = true; +dojo.provide("dojox.image.Magnifier"); + +dojo.require("dojox.gfx"); +dojo.require("dojox.image.MagnifierLite"); + +dojo.declare("dojox.image.Magnifier", + [dojox.image.MagnifierLite],{ + // summary: Adds magnification on a portion of an image element, using dojox.gfx + // + // description: An unobtrusive way to add an unstyled overlay + // above the srcNode image element. The overlay/glass is a + // scaled version of the src image (so larger images sized down + // are clearer). + // + // over-ride the _createGlass method to create your custom surface, + // being sure to create an img node on that surface. + + _createGlass: function(){ + // summary: create the glassNode, and an img on a dojox.gfx surface + + // images are hard to make into workable templates, so just add outer overlay + // and skip using dijit._Templated + this.glassNode = dojo.doc.createElement('div'); + this.surfaceNode = this.glassNode.appendChild(dojo.doc.createElement('div')); + + dojo.addClass(this.glassNode,"glassNode"); + dojo.body().appendChild(this.glassNode); + + with(this.glassNode.style){ + height = this.glassSize + "px"; + width = this.glassSize + "px"; + } + + this.surface = dojox.gfx.createSurface(this.surfaceNode, this.glassSize, this.glassSize); + this.img = this.surface.createImage({ + src:this.domNode.src, + width:this._zoomSize.w, + height:this._zoomSize.h + }); + + }, + + _placeGlass: function(e){ + // summary: position the overlay centered under the cursor + var x = e.pageX - 2; + var y = e.pageY - 2 ; + var xMax = this.offset.x + this.offset.w + 2; + var yMax = this.offset.y + this.offset.h + 2; + + // with svg, our mouseout connection to the image surface doesn't + // fire, so we'r have to manually calculate offsets + if(xxMax || y>yMax){ + this._hideGlass(); + }else{ + this.inherited(arguments); + } + }, + + _setImage: function(e){ + // summary: set the image's offset in the clipping window relative to the mouse position + + var xOff = (e.pageX - this.offset.l) / this.offset.w; + var yOff = (e.pageY - this.offset.t) / this.offset.h; + var x = (this._zoomSize.w * xOff * -1)+(this.glassSize*xOff); + var y = (this._zoomSize.h * yOff * -1)+(this.glassSize*yOff); + // set the image offset + this.img.setShape({ x: x, y:y }); + + } + +}); + +} diff --git a/includes/js/dojox/image/MagnifierLite.js b/includes/js/dojox/image/MagnifierLite.js new file mode 100644 index 0000000..2e37340 --- /dev/null +++ b/includes/js/dojox/image/MagnifierLite.js @@ -0,0 +1,126 @@ +if(!dojo._hasResource["dojox.image.MagnifierLite"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.image.MagnifierLite"] = true; +dojo.provide("dojox.image.MagnifierLite"); +dojo.experimental("dojox.image.MagnifierLite"); + +dojo.require("dijit._Widget"); + +dojo.declare("dojox.image.MagnifierLite", + [dijit._Widget],{ + // summary: Adds magnification on a portion of an image element + // + // description: An unobtrusive way to add an unstyled overlay + // above the srcNode image element. The overlay/glass is a + // scaled version of the src image (so larger images sized down + // are clearer). + // + // The logic behind requiring the src image to be large is + // "it's going to be downloaded, anyway" so this method avoids + // having to make thumbnails and 2 http requests among other things. + // + // glassSize: Int + // the width and height of the bounding box + glassSize: 125, + + // scale: Decimal + // the multiplier of the Mangification. + scale: 6, + + postCreate: function(){ + this.inherited(arguments); + + // images are hard to make into workable templates, so just add outer overlay + // and skip using dijit._Templated + this._adjustScale(); + this._createGlass(); + + this.connect(this.domNode,"onmouseenter","_showGlass"); + this.connect(this.glassNode,"onmousemove","_placeGlass"); + this.connect(this.img,"onmouseout","_hideGlass"); + + // when position of domNode changes, _adjustScale needs to run. + // window.resize isn't it always, FIXME: + this.connect(window,"onresize","_adjustScale"); + + }, + + _createGlass: function(){ + // summary: make img and glassNode elements as children of the body + + this.glassNode = dojo.doc.createElement('div'); + this.surfaceNode = this.glassNode.appendChild(dojo.doc.createElement('div')); + dojo.addClass(this.glassNode,"glassNode"); + dojo.body().appendChild(this.glassNode); + with(this.glassNode.style){ + height = this.glassSize + "px"; + width = this.glassSize + "px"; + } + + this.img = dojo.doc.createElement('img'); + this.glassNode.appendChild(this.img); + this.img.src = this.domNode.src; + // float the image around inside the .glassNode + with(this.img.style){ + position = "relative"; + top = 0; left = 0; + width = this._zoomSize.w+"px"; + height = this._zoomSize.h+"px"; + } + + }, + + _adjustScale: function(){ + // summary: update the calculations should this.scale change + + this.offset = dojo.coords(this.domNode,true); + this._imageSize = { w: this.offset.w, h:this.offset.h }; + this._zoomSize = { + w: this._imageSize.w * this.scale, + h: this._imageSize.h * this.scale + }; + }, + + _showGlass: function(e){ + // summary: show the overlay + this._placeGlass(e); + with(this.glassNode.style){ + visibility = "visible"; + display = ""; + } + + }, + + _hideGlass: function(e){ + // summary: hide the overlay + this.glassNode.style.visibility = "hidden"; + this.glassNode.style.display = "none"; + }, + + _placeGlass: function(e){ + // summary: position the overlay centered under the cursor + + this._setImage(e); + var t = Math.floor(e.pageY - (this.glassSize/2)); + var l = Math.floor(e.pageX - (this.glassSize/2)); + dojo.style(this.glassNode,"top",t); + dojo.style(this.glassNode,"left",l); + + }, + + _setImage: function(e){ + // summary: set the image's offset in the clipping window relative to the mouse position + + var xOff = (e.pageX - this.offset.l) / this.offset.w; + var yOff = (e.pageY - this.offset.t) / this.offset.h; + var x = (this._zoomSize.w * xOff * -1)+(this.glassSize*xOff); + var y = (this._zoomSize.h * yOff * -1)+(this.glassSize*yOff); + with(this.img.style){ + top = y+"px"; + left = x+"px"; + } + + } + +}); + +} diff --git a/includes/js/dojox/image/README b/includes/js/dojox/image/README new file mode 100644 index 0000000..38e9c3d --- /dev/null +++ b/includes/js/dojox/image/README @@ -0,0 +1,66 @@ +------------------------------------------------------------------------------- +dojox.image +------------------------------------------------------------------------------- +Version 1.0 +Release date: 10/31/07 +------------------------------------------------------------------------------- +Project state: +prototype | experimental +------------------------------------------------------------------------------- +Credits + Peter Higgins (dante) + Shane O'Sullivan (shaneosullivan1@gmail.com) +------------------------------------------------------------------------------- +Project description + + A class to provide a common API for images, and home for image + related Widgets. + +------------------------------------------------------------------------------- +Dependencies: + + LightBox: dojo core, dojox.fx and optionally dojox.data. uses + either tundra or soria theme, no standalone icons. + + SlideShow: dojo core, dojo.fx, and dojo.data (optional + dojox.data store implementations apply) + + ThumbNailPicker: dojo core, dojo.fx and dojo.data. Combined + with a SlideShow, creates a sample Gallery app. + + Gallery: core, dojox.image.SlideShow, dojox.image.ThumbNailPicker + + Magnifier: dojo core, dijit._Widget, dojox.gfx + +------------------------------------------------------------------------------- +Documentation + +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/dojo/dojox/trunk/image/* + +Install into the following directory structure: +/dojox/image/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- +Additional Notes + + LightBox: currently works as individual items, and grouped items, + but usage of dojo.data is broken (atm). the API is subject to + change, and is marked accordingly. + + Hoping to implement: Carossel, and Reflect using + a common API provided by dojox.image.Pane (?) + + SlideShow: Shows an image, one by one, from a datastore. Acts + as standing ImagePane implementation, + + Gallery: A combination Thumbnail view and SlideShow, using + a datastore, and providing navigation, and common API. + + Magnifier: Unobtrusive way to attach a hovering window window + when moving the mouse over an image. The window shows a a zoomed + version of the original source. (experimental) diff --git a/includes/js/dojox/image/SlideShow.js b/includes/js/dojox/image/SlideShow.js new file mode 100644 index 0000000..4767cf1 --- /dev/null +++ b/includes/js/dojox/image/SlideShow.js @@ -0,0 +1,598 @@ +if(!dojo._hasResource["dojox.image.SlideShow"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.image.SlideShow"] = true; +dojo.provide("dojox.image.SlideShow"); +// +// dojox.image.SlideShow courtesy Shane O Sullivan, licensed under a Dojo CLA +// For a sample usage, see http://www.skynet.ie/~sos/photos.php +// +// @author Copyright 2007 Shane O Sullivan (shaneosullivan1@gmail.com) +// +// TODO: more cleanups +// +dojo.require("dojo.string"); +dojo.require("dojo.fx"); +dojo.require("dijit._Widget"); +dojo.require("dijit._Templated"); + +dojo.declare("dojox.image.SlideShow", + [dijit._Widget, dijit._Templated], + { + // summary: A Slideshow Widget + + // imageHeight: Number + // The maximum height of an image + imageHeight: 375, + + // imageWidth: Number + // The maximum width of an image. + imageWidth: 500, + + // title: String + // the initial title of the SlideShow + title: "", + + // titleTemplate: String + // a way to customize the wording in the title. supported parameters to be populated are: + // ${title} = the passed title of the image + // ${current} = the current index of the image + // ${total} = the total number of images in the SlideShow + // + // should add more? + titleTemplate: '${title} (${current} of ${total})', + + // noLink: Boolean + // Prevents the slideshow from putting an anchor link around the displayed image + // enables if true, though still will not link in absence of a url to link to + noLink: false, + + // loop: Boolean + // true/false - make the slideshow loop + loop: true, + + // hasNav: Boolean + // toggle to enable/disable the visual navigation controls + hasNav: true, + + // images: Array + // Contains the DOM nodes that individual images are stored in when loaded or loading. + images: [], + + // pageSize: Number + // The number of images to request each time. + pageSize: 20, + + // autoLoad: Boolean + // If true, then images are preloaded, before the user navigates to view them. + // If false, an image is not loaded until the user views it. + autoLoad: true, + + // autoStart: Boolean + // If true, the SlideShow begins playing immediately + autoStart: false, + + // fixedHeight: Boolean + // If true, the widget does not resize itself to fix the displayed image. + fixedHeight: false, + + // imageStore: Object + // Implementation of the dojo.data.api.Read API, which provides data on the images + // to be displayed. + imageStore: null, + + // linkAttr: String + // Defines the name of the attribute to request from the store to retrieve the + // URL to link to from an image, if any. + linkAttr: "link", + + // imageLargeAttr: String + // Defines the name of the attribute to request from the store to retrieve the + // URL to the image. + imageLargeAttr: "imageUrl", + + // titleAttr: String + // Defines the name of the attribute to request from the store to retrieve the + // title of the picture, if any. + titleAttr: "title", + + // slideshowInterval: Number + // Time, in seconds, between image transitions during a slideshow. + slideshowInterval: 3, + + templateString:"
      \n\t
      \n\t\t
      \n\t\t\t
      ${title}
      \n\t\t
      \n\t\t
      \n\t\t\t\n\t\t\t\n\t\t\t\n\t\t
      \n\t\t
      \t\t\n\t\t
      \n\t
      \n
      \n", + + // _tempImgPath: URL + // URL to the image to display when an image is not yet fully loaded. + _tempImgPath: dojo.moduleUrl("dojo", "resources/blank.gif"), + + // _imageCounter: Number + // A counter to keep track of which index image is to be loaded next + _imageCounter: 0, + + // _tmpImage: DomNode + // The temporary image to show when a picture is loading. + _tmpImage: null, + + // _request: Object + // Implementation of the dojo.data.api.Request API, which defines the query + // parameters for accessing the store. + _request: null, + + postCreate: function(){ + // summary: Initilizes the widget, sets up listeners and shows the first image + this.inherited(arguments); + var img = document.createElement("img"); + + // FIXME: should API be to normalize an image to fit in the specified height/width? + img.setAttribute("width", this.imageWidth); + img.setAttribute("height", this.imageHeight); + + if(this.hasNav){ + dojo.connect(this.outerNode, "onmouseover", function(evt){ + try{_this._showNav();} + catch(e){} //TODO: remove try/catch + }); + dojo.connect(this.outerNode, "onmouseout", function(evt){ + try{_this._hideNav(evt);} + catch(e){} //TODO: remove try/catch + }); + } + + this.outerNode.style.width = this.imageWidth + "px"; + + img.setAttribute("src", this._tempImgPath); + var _this = this; + + this.largeNode.appendChild(img); + this._tmpImage = this._currentImage = img; + this._fitSize(true); + + this._loadImage(0, function(){ + _this.showImage(0); + }); + this._calcNavDimensions(); + }, + + setDataStore: function(dataStore, request, /*optional*/paramNames){ + // summary: Sets the data store and request objects to read data from. + // dataStore: + // An implementation of the dojo.data.api.Read API. This accesses the image + // data. + // request: + // An implementation of the dojo.data.api.Request API. This specifies the + // query and paging information to be used by the data store + // paramNames: + // An object defining the names of the item attributes to fetch from the + // data store. The three attributes allowed are 'linkAttr', 'imageLargeAttr' and 'titleAttr' + this.reset(); + var _this = this; + + this._request = { + query: {}, + start: request.start || 0, + count: request.count || this.pageSize, + onBegin: function(count, request){ + _this.maxPhotos = count; + } + }; + if(request.query){ dojo.mixin(this._request.query, request.query); } + if(paramNames){ + dojo.forEach(["imageLargeAttr", "linkAttr", "titleAttr"], function(attrName){ + if(paramNames[attrName]){ this[attrName] = paramNames[attrName]; } + }, this); + } + + var _complete = function(items){ + _this.showImage(0); + _this._request.onComplete = null; + if(_this.autoStart){ + _this.toggleSlideShow(); + } + }; + + this.imageStore = dataStore; + this._request.onComplete = _complete; + this._request.start = 0; + this.imageStore.fetch(this._request); + }, + + reset: function(){ + // summary: Resets the widget to its initial state + // description: Removes all previously loaded images, and clears all caches. + while(this.largeNode.firstChild){ + this.largeNode.removeChild(this.largeNode.firstChild); + } + this.largeNode.appendChild(this._tmpImage); + while(this.hiddenNode.firstChild){ + this.hiddenNode.removeChild(this.hiddenNode.firstChild); + } + dojo.forEach(this.images, function(img){ + if(img && img.parentNode){ img.parentNode.removeChild(img); } + }); + this.images = []; + this.isInitialized = false; + this._imageCounter = 0; + }, + + isImageLoaded: function(index){ + // summary: Returns true if image at the specified index is loaded, false otherwise. + // index: + // The number index in the data store to check if it is loaded. + return this.images && this.images.length > index && this.images[index]; + }, + + moveImageLoadingPointer: function(index){ + // summary: If 'autoload' is true, this tells the widget to start loading + // images from the specified pointer. + // index: + // The number index in the data store to start loading images from. + this._imageCounter = index; + }, + + destroy: function(){ + // summary: Cleans up the widget when it is being destroyed + if(this._slideId) { this._stop(); } + this.inherited(arguments); + }, + + showNextImage: function(inTimer, forceLoop){ + // summary: Changes the image being displayed to the next image in the data store + // inTimer: Boolean + // If true, a slideshow is active, otherwise the slideshow is inactive. + if(inTimer && this._timerCancelled){return false;} + + if(this.imageIndex + 1 >= this.maxPhotos){ + if(inTimer && (this.loop || forceLoop)){ this.imageIndex = -1; } + else{ + if(this._slideId){ this._stop(); } + return false; + } + } + var _this = this; + this.showImage(this.imageIndex + 1, function(){ + if(inTimer){ _this._startTimer(); } + }); + return true; + }, + + toggleSlideShow: function(){ + // summary: Switches the slideshow mode on and off. + if(this._slideId){ + this._stop(); + }else{ + dojo.toggleClass(this.domNode,"slideShowPaused"); + this._timerCancelled = false; + var success = this.showNextImage(true, true); + if(!success){ + this._stop(); + } + } + }, + + getShowTopicName: function(){ + // summary: Returns the topic id published to when an image is shown + // description: + // The information published is: index, title and url + return (this.widgetId || this.id) + "/imageShow"; + }, + + getLoadTopicName: function(){ + // summary: Returns the topic id published to when an image finishes loading. + // description: + // The information published is the index position of the image loaded. + return (this.widgetId ? this.widgetId : this.id) + "/imageLoad"; + }, + + showImage: function(index, /* Function? */callback){ + // summary: Shows the image at index 'index'. + // index: Number + // The position of the image in the data store to display + // callback: Function + // Optional callback function to call when the image has finished displaying. + + if(!callback && this._slideId){ this.toggleSlideShow(); } + var _this = this; + var current = this.largeNode.getElementsByTagName("div"); + this.imageIndex = index; + + var showOrLoadIt = function() { + //If the image is already loaded, then show it. + if(_this.images[index]){ + while(_this.largeNode.firstChild){ + _this.largeNode.removeChild(_this.largeNode.firstChild); + } + _this.images[index].style.opacity = 0; + _this.largeNode.appendChild(_this.images[index]); + _this._currentImage = _this.images[index]._img; + _this._fitSize(); + + var onEnd = function(a,b,c) { + var img = _this.images[index].firstChild; + if(img.tagName.toLowerCase() != "img"){img = img.firstChild;} + title = img.getAttribute("title"); + + if(_this._navShowing){ + _this._showNav(true); + } + dojo.publish(_this.getShowTopicName(), [{ + index: index, + title: title, + url: img.getAttribute("src") + }]); + if(callback) { callback(a,b,c); } + _this._setTitle(title); + }; + + dojo.fadeIn({ + node: _this.images[index], + duration: 300, + onEnd: onEnd + }).play(); + }else{ + //If the image is not loaded yet, load it first, then show it. + _this._loadImage(index, function(){ + dojo.publish(_this.getLoadTopicName(), [index]); + _this.showImage(index, callback); + }); + } + }; + + //If an image is currently showing, fade it out, then show + //the new image. Otherwise, just show the new image. + if(current && current.length > 0){ + dojo.fadeOut({ + node: current[0], + duration: 300, + onEnd: function(){ + _this.hiddenNode.appendChild(current[0]); + showOrLoadIt(); + } + }).play(); + }else{ + showOrLoadIt(); + } + }, + + _fitSize: function(force){ + // summary: Fits the widget size to the size of the image being shown, + // or centers the image, depending on the value of 'fixedHeight' + // force: Boolean + // If true, the widget is always resized, regardless of the value of 'fixedHeight' + if(!this.fixedHeight || force){ + var height = (this._currentImage.height + (this.hasNav ? 20:0)); + dojo.style(this.innerWrapper, "height", height + "px"); + return; + } + dojo.style(this.largeNode, "paddingTop", this._getTopPadding() + "px"); + }, + + _getTopPadding: function(){ + if(!this.fixedHeight){return 0;} + // summary: Returns the padding to place at the top of the image to center it vertically. + return (this.imageHeight - this._currentImage.height)/2; + }, + + _loadNextImage: function(){ + //summary: Load the next unloaded image. + if(!this.autoLoad){ return; } + while(this.images.length >= this._imageCounter && this.images[this._imageCounter]){ + this._imageCounter++; + } + this._loadImage(this._imageCounter); + }, + + _loadImage: function(index, callbackFn){ + // summary: Load image at specified index + // description: + // This function loads the image at position 'index' into the + // internal cache of images. This does not cause the image to be displayed. + // index: + // The position in the data store to load an image from. + // callbackFn: + // An optional function to execute when the image has finished loading. + if(this.images[index] || !this._request) { return; } + + var pageStart = index - (index % this.pageSize); + + this._request.start = pageStart; + + this._request.onComplete = function(items){ + var diff = index - pageStart; + if(items && items.length > diff){ + loadIt(items[diff]); + }else{ /* Squelch - console.log("Got an empty set of items"); */ } + } + + var _this = this; + var loadIt = function(item){ + var url = _this.imageStore.getValue(item, _this.imageLargeAttr); + var img = document.createElement("img"); + var div = document.createElement("div"); + div._img = img; + + var link = _this.imageStore.getValue(item,_this.linkAttr); + if(!link || _this.noLink){ div.appendChild(img); + }else{ + var a = document.createElement("a"); + a.setAttribute("href", link); + a.setAttribute("target","_blank"); + div.appendChild(a); + a.appendChild(img); + } + + div.setAttribute("id",_this.id + "_imageDiv" + index); + dojo.connect(img, "onload", function(){ + _this._fitImage(img); + div.setAttribute("width",_this.imageWidth); + div.setAttribute("height",_this.imageHeight); + + dojo.publish(_this.getLoadTopicName(), [index]); + _this._loadNextImage(); + if(callbackFn){ callbackFn(); } + }); + _this.hiddenNode.appendChild(div); + + var titleDiv = document.createElement("div"); + dojo.addClass(titleDiv, "slideShowTitle"); + div.appendChild(titleDiv); + + _this.images[index] = div; + img.setAttribute("src", url); + + var title = _this.imageStore.getValue(item,_this.titleAttr); + if(title){ img.setAttribute("title",title); } + } + this.imageStore.fetch(this._request); + }, + + _stop: function(){ + // summary: Stops a running slide show. + if(this._slideId){ clearTimeout(this._slideId); } + this._slideId = null; + this._timerCancelled = true; + dojo.removeClass(this.domNode,"slideShowPaused"); + }, + + _prev: function(){ + // summary: Show the previous image. + // FIXME: either pull code from showNext/prev, or call it here + if(this.imageIndex < 1){ return; } + this.showImage(this.imageIndex - 1); + }, + + _next: function(){ + // summary: Show the next image + this.showNextImage(); + }, + + _startTimer: function(){ + // summary: Starts a timeout to show the next image when a slide show is active + var id = this.id; + this._slideId = setTimeout(function(){dijit.byId(id).showNextImage(true);}, this.slideshowInterval * 1000); + }, + + _calcNavDimensions: function() { + // summary: + // Calculates the dimensions of the navigation controls + dojo.style(this.navNode, "position", "absolute"); + + //Place the navigation controls far off screen + dojo.style(this.navNode, "top", "-10000px"); + + //Make the navigation controls visible + dojo._setOpacity(this.navNode, 99); + + this.navPlay._size = dojo.marginBox(this.navPlay); + this.navPrev._size = dojo.marginBox(this.navPrev); + this.navNext._size = dojo.marginBox(this.navNext); + + dojo._setOpacity(this.navNode, 0); + dojo.style(this.navNode, "position", ""); + dojo.style(this.navNode, "top", ""); + }, + + _setTitle: function(title){ + // summary: Sets the title of the image to be displayed + // title: String + // The String title of the image + this.titleNode.innerHTML = dojo.string.substitute(this.titleTemplate, + { title: title, current: 1 + this.imageIndex, total: this.maxPhotos}); + }, + + _fitImage: function(img) { + // summary: Ensures that the image width and height do not exceed the maximum. + // img: Node + // The image DOM node to optionally resize + var width = img.width; + var height = img.height; + + if(width > this.imageWidth){ + height = Math.floor(height * (this.imageWidth / width)); + img.setAttribute("height", height + "px"); + img.setAttribute("width", this.imageWidth + "px"); + } + if(height > this.imageHeight){ + width = Math.floor(width * (this.imageHeight / height)); + img.setAttribute("height", this.imageHeight + "px"); + img.setAttribute("width", width + "px"); + } + }, + + _handleClick: function(/* Event */e){ + // summary: Performs navigation on the images based on users mouse clicks + // e: + // An Event object + switch(e.target){ + case this.navNext:this._next(); break; + case this.navPrev:this._prev(); break; + case this.navPlay:this.toggleSlideShow(); break; + } + }, + + _showNav: function(force){ + // summary: + // Shows the navigation controls + // force: Boolean + // If true, the navigation controls are repositioned even if they are + // currently visible. + if(this._navShowing && !force){return;} + dojo.style(this.navNode, "marginTop", "0px"); + dojo.style(this.navPlay, "marginLeft", "0px"); + var wrapperSize = dojo.marginBox(this.outerNode); + + var margin = this._currentImage.height - this.navPlay._size.h - 10 + this._getTopPadding(); + + if(margin > this._currentImage.height){margin += 10;} + dojo[this.imageIndex < 1 ? "addClass":"removeClass"](this.navPrev, "slideShowCtrlHide"); + dojo[this.imageIndex + 1 >= this.maxPhotos ? "addClass":"removeClass"](this.navNext, "slideShowCtrlHide"); + + var _this = this; + if(this._navAnim) { + this._navAnim.stop(); + } + if(this._navShowing){return;} + this._navAnim = dojo.fadeIn({node: this.navNode, duration: 300, + onEnd: function(){_this._navAnim=null;}}); + + this._navAnim.play(); + this._navShowing = true; + }, + + _hideNav: function(/* Event */e){ + // summary: Hides the navigation controls + // e: Event + // The DOM Event that triggered this function + if(!e || !this._overElement(this.outerNode, e)) { + var _this = this; + if(this._navAnim) { + this._navAnim.stop(); + } + this._navAnim = dojo.fadeOut({node: this.navNode,duration:300, + onEnd: function(){_this._navAnim=null;}}); + this._navAnim.play(); + this._navShowing = false; + } + }, + + _overElement: function(/*DomNode*/element, /*Event*/e){ + // summary: + // Returns whether the mouse is over the passed element. + // Element must be display:block (ie, not a ) + + //When the page is unloading, if this method runs it will throw an + //exception. + if(typeof(dojo)=="undefined"){return false;} + element = dojo.byId(element); + var m = {x: e.pageX, y: e.pageY}; + var bb = dojo._getBorderBox(element); + var absl = dojo.coords(element, true); + var left = absl.x; + + return (m.x >= left + && m.x <= (left + bb.w) + && m.y >= absl.y + && m.y <= (top + bb.h) + ); // boolean + } +}); + +} diff --git a/includes/js/dojox/image/ThumbnailPicker.js b/includes/js/dojox/image/ThumbnailPicker.js new file mode 100644 index 0000000..42f9862 --- /dev/null +++ b/includes/js/dojox/image/ThumbnailPicker.js @@ -0,0 +1,535 @@ +if(!dojo._hasResource["dojox.image.ThumbnailPicker"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.image.ThumbnailPicker"] = true; +dojo.provide("dojox.image.ThumbnailPicker"); +dojo.experimental("dojox.image.ThumbnailPicker"); +// +// dojox.image.ThumbnailPicker courtesy Shane O Sullivan, licensed under a Dojo CLA +// @author Copyright 2007 Shane O Sullivan (shaneosullivan1@gmail.com) +// +// For a sample usage, see http://www.skynet.ie/~sos/photos.php +// +// document topics. + +dojo.require("dojo.fx"); +dojo.require("dijit._Widget"); +dojo.require("dijit._Templated"); + +dojo.declare("dojox.image.ThumbnailPicker", + [dijit._Widget, dijit._Templated], + { + // summary: A scrolling Thumbnail Picker widget + // + // imageStore: Object + // A data store that implements the dojo.data Read API. + imageStore: null, + + // request: Object + // A dojo.data Read API Request object. + request: null, + + // size: Number + // Width or height in pixels, depending if horizontal or vertical. + size: 500, //FIXME: use CSS? + + // thumbHeight: Number + // Default height of a thumbnail image + thumbHeight: 75, // FIXME: use CSS? + + // thumbWidth: Number + // Default width of an image + thumbWidth: 100, // FIXME: use CSS? + + // useLoadNotifier: Boolean + // Setting useLoadNotifier to true makes a colored DIV appear under each + // thumbnail image, which is used to display the loading status of each + // image in the data store. + useLoadNotifier: false, + + // useHyperlink: boolean + // Setting useHyperlink to true causes a click on a thumbnail to open a link. + useHyperlink: false, + + // hyperlinkTarget: String + // If hyperlinkTarget is set to "new", clicking on a thumb will open a new window + // If it is set to anything else, clicking a thumbnail will open the url in the + // current window. + hyperlinkTarget: "new", + + // isClickable: Boolean + // When set to true, the cursor over a thumbnail changes. + isClickable: true, + + // isScrollable: Boolean + // When true, uses smoothScroll to move between pages + isScrollable: true, + + // isHorizontal: Boolean + // If true, the thumbnails are displayed horizontally. Otherwise they are displayed + // vertically + isHorizontal: true, + + //autoLoad: Boolean + autoLoad: true, + + // linkAttr: String + // The attribute name for accessing the url from the data store + linkAttr: "link", + + // imageThumbAttr: String + // The attribute name for accessing the thumbnail image url from the data store + imageThumbAttr: "imageUrlThumb", + + // imageLargeAttr: String + // The attribute name for accessing the large image url from the data store + imageLargeAttr: "imageUrl", + + // pageSize: Number + // The number of images to request each time. + pageSize: 20, + + // titleAttr: String + // The attribute name for accessing the title from the data store + titleAttr: "title", + + templateString:"
      \n\t
      \n\t \n\t
      \n\t
      \n\t
      \n\t
      \n\t
      \n\t \n\t
      \n
      \n", + tempImgPath: dojo.moduleUrl("dojo", "resources/blank.gif"), + + // thumbs: Array + // Stores the image nodes for the thumbnails. + _thumbs: [], + + // _thumbIndex: Number + // The index of the first thumbnail shown + _thumbIndex: 0, + + // _maxPhotos: Number + // The total number of photos in the image store + _maxPhotos: 0, + + // _loadedImages: Object + // Stores the indices of images that have been marked as loaded using the + // markImageLoaded function. + _loadedImages: {}, + + postCreate: function(){ + // summary: Initializes styles and listeners + this.widgetid = this.id; + this.inherited(arguments); + this.pageSize = Number(this.pageSize); + + this._scrollerSize = this.size - (51 * 2); + + var sizeProp = this._sizeProperty = this.isHorizontal ? "width" : "height"; + + // FIXME: do this via css? calculate the correct width for the widget + dojo.style(this.outerNode, "textAlign","center"); + dojo.style(this.outerNode, sizeProp, this.size+"px"); + + dojo.style(this.thumbScroller, sizeProp, this._scrollerSize + "px"); + + //If useHyperlink is true, then listen for a click on a thumbnail, and + //open the link + if(this.useHyperlink){ + dojo.subscribe(this.getClickTopicName(), this, function(packet){ + var index = packet.index; + var url = this.imageStore.getValue(packet.data,this.linkAttr); + + //If the data item doesn't contain a URL, do nothing + if(!url){return;} + + if(this.hyperlinkTarget == "new"){ + window.open(url); + }else{ + window.location = url; + } + }); + } + + if(this.isScrollable) { + // FIXME: does this break builds or anything? + dojo.require("dojox.fx.scroll"); + dojo.require("dojox.fx.easing"); + } + if(this.isClickable){ + dojo.addClass(this.thumbsNode, "thumbClickable"); + } + this._totalSize = 0; + this.init(); + }, + + init: function(){ + // summary: Creates DOM nodes for thumbnail images and initializes their listeners + if(this.isInitialized) {return false;} + + var classExt = this.isHorizontal ? "Horiz" : "Vert"; + + // FIXME: can we setup a listener around the whole element and determine based on e.target? + dojo.addClass(this.navPrev, "prev" + classExt); + dojo.addClass(this.navNext, "next" + classExt); + dojo.addClass(this.thumbsNode, "thumb"+classExt); + dojo.addClass(this.outerNode, "thumb"+classExt); + + this.navNextImg.setAttribute("src", this.tempImgPath); + this.navPrevImg.setAttribute("src", this.tempImgPath); + + this.connect(this.navPrev, "onclick", "_prev"); + this.connect(this.navNext, "onclick", "_next"); + this.isInitialized = true; + + if(this.isHorizontal){ + this._offsetAttr = "offsetLeft"; + this._sizeAttr = "offsetWidth"; + this._scrollAttr = "scrollLeft"; + }else{ + this._offsetAttr = "offsetTop"; + this._sizeAttr = "offsetHeight"; + this._scrollAttr = "scrollTop"; + } + + this._updateNavControls(); + if(this.imageStore && this.request){this._loadNextPage();} + return true; + }, + + getClickTopicName: function(){ + // summary: Returns the name of the dojo topic that can be + // subscribed to in order to receive notifications on + // which thumbnail was selected. + return (this.widgetId || this.id) + "/select"; // String + }, + + getShowTopicName: function(){ + // summary: Returns the name of the dojo topic that can be + // subscribed to in order to receive notifications on + // which thumbnail is now visible + return (this.widgetId || this.id) + "/show"; // String + }, + + setDataStore: function(dataStore, request, /*optional*/paramNames){ + // summary: Sets the data store and request objects to read data from. + // dataStore: + // An implementation of the dojo.data.api.Read API. This accesses the image + // data. + // request: + // An implementation of the dojo.data.api.Request API. This specifies the + // query and paging information to be used by the data store + // paramNames: + // An object defining the names of the item attributes to fetch from the + // data store. The four attributes allowed are 'linkAttr', 'imageLargeAttr', + // 'imageThumbAttr' and 'titleAttr' + this.reset(); + + this.request = { + query: {}, + start: request.start || 0, + count: request.count || 10, + onBegin: dojo.hitch(this, function(total){ + this._maxPhotos = total; + }) + }; + + if(request.query){ dojo.mixin(this.request.query, request.query);} + + if(paramNames){ + dojo.forEach(["imageThumbAttr", "imageLargeAttr", "linkAttr", "titleAttr"], function(attrName){ + if(paramNames[attrName]){ this[attrName] = paramNames[attrName]; } + }, this); + } + + this.request.start = 0; + this.request.count = this.pageSize; + this.imageStore = dataStore; + + if(!this.init()){this._loadNextPage();} + }, + + reset: function(){ + // summary: Resets the widget back to its original state. + this._loadedImages = {}; + dojo.forEach(this._thumbs, function(img){ + if(img){ + // dojo.event.browser.clean(img); + if(img.parentNode){ + img.parentNode.removeChild(img); + } + } + }); + + this._thumbs = []; + this.isInitialized = false; + this._noImages = true; + }, + + isVisible: function(index) { + // summary: Returns true if the image at the specified index is currently visible. False otherwise. + var img = this._thumbs[index]; + if(!img){return false;} + var pos = this.isHorizontal ? "offsetLeft" : "offsetTop"; + var size = this.isHorizontal ? "offsetWidth" : "offsetHeight"; + var scrollAttr = this.isHorizontal ? "scrollLeft" : "scrollTop"; + var offset = img[pos] - this.thumbsNode[pos]; + return (offset >= this.thumbScroller[scrollAttr] + && offset + img[size] <= this.thumbScroller[scrollAttr] + this._scrollerSize); + }, + + _next: function() { + // summary: Displays the next page of images + var pos = this.isHorizontal ? "offsetLeft" : "offsetTop"; + var size = this.isHorizontal ? "offsetWidth" : "offsetHeight"; + var baseOffset = this.thumbsNode[pos]; + var firstThumb = this._thumbs[this._thumbIndex]; + var origOffset = firstThumb[pos] - baseOffset; + + var index = -1, img; + + for(var i = this._thumbIndex + 1; i < this._thumbs.length; i++){ + img = this._thumbs[i]; + if(img[pos] - baseOffset + img[size] - origOffset > this._scrollerSize){ + this._showThumbs(i); + return; + } + } + }, + + _prev: function(){ + // summary: Displays the next page of images + if(this.thumbScroller[this.isHorizontal ? "scrollLeft" : "scrollTop"] == 0){return;} + var pos = this.isHorizontal ? "offsetLeft" : "offsetTop"; + var size = this.isHorizontal ? "offsetWidth" : "offsetHeight"; + + var firstThumb = this._thumbs[this._thumbIndex]; + var origOffset = firstThumb[pos] - this.thumbsNode[pos]; + + var index = -1, img; + + for(var i = this._thumbIndex - 1; i > -1; i--) { + img = this._thumbs[i]; + if(origOffset - img[pos] > this._scrollerSize){ + this._showThumbs(i + 1); + return; + } + } + this._showThumbs(0); + }, + + _checkLoad: function(img, index){ + dojo.publish(this.getShowTopicName(), [{index:index}]); + this._updateNavControls(); + this._loadingImages = {}; + + this._thumbIndex = index; + + //If we have not already requested the data from the store, do so. + if(this.thumbsNode.offsetWidth - img.offsetLeft < (this._scrollerSize * 2)){ + this._loadNextPage(); + } + }, + + _showThumbs: function(index){ + // summary: Displays thumbnail images, starting at position 'index' + // index: Number + // The index of the first thumbnail + +//FIXME: When is this be called with an invalid index? Do we need this check at all? +// if(typeof index != "number"){ index = this._thumbIndex; } + index = Math.min(Math.max(index, 0), this._maxPhotos); + + if(index >= this._maxPhotos){ return; } + + var img = this._thumbs[index]; + if(!img){ return; } + + var left = img.offsetLeft - this.thumbsNode.offsetLeft; + var top = img.offsetTop - this.thumbsNode.offsetTop; + var offset = this.isHorizontal ? left : top; + + if( (offset >= this.thumbScroller[this._scrollAttr]) && + (offset + img[this._sizeAttr] <= this.thumbScroller[this._scrollAttr] + this._scrollerSize) + ){ + // FIXME: WTF is this checking for? + return; + } + + + if(this.isScrollable){ + var target = this.isHorizontal ? {x: left, y: 0} : { x:0, y:top}; + dojox.fx.smoothScroll({ + target: target, + win: this.thumbScroller, + duration:300, + easing:dojox.fx.easing.easeOut, + onEnd: dojo.hitch(this, "_checkLoad", img, index) + }).play(10); + }else{ + if(this.isHorizontal){ + this.thumbScroller.scrollLeft = left; + }else{ + this.thumbScroller.scrollTop = top; + } + this._checkLoad(img, index); + } + }, + + markImageLoaded: function(index){ + // summary: Changes a visual cue to show the image is loaded + // description: If 'useLoadNotifier' is set to true, then a visual cue is + // given to state whether the image is loaded or not. Calling this function + // marks an image as loaded. + var thumbNotifier = dojo.byId("loadingDiv_"+this.widgetid+"_"+index); + if(thumbNotifier){this._setThumbClass(thumbNotifier, "thumbLoaded");} + this._loadedImages[index] = true; + }, + + _setThumbClass: function(thumb, className){ + // summary: Adds a CSS class to a thumbnail, only if 'autoLoad' is true + // thumb: DomNode + // The thumbnail DOM node to set the class on + // className: String + // The CSS class to add to the DOM node. + if(!this.autoLoad){ return; } + dojo.addClass(thumb, className); + }, + + _loadNextPage: function(){ + // summary: Loads the next page of thumbnail images + if(this._loadInProgress){return;} + this._loadInProgress = true; + var start = this.request.start + (this._noImages ? 0 : this.pageSize); + + var pos = start; + while(pos < this._thumbs.length && this._thumbs[pos]){pos ++;} + + //Define the function to call when the items have been + //returned from the data store. + var complete = function(items, request){ + if(items && items.length){ + var itemCounter = 0; + var loadNext = dojo.hitch(this, function(){ + if(itemCounter >= items.length){ + this._loadInProgress = false; + return; + } + var counter = itemCounter++; + + this._loadImage(items[counter], pos + counter, loadNext); + }); + loadNext(); + + //Show or hide the navigation arrows on the thumbnails, + //depending on whether or not the widget is at the start, + //end, or middle of the list of images. + this._updateNavControls(); + }else{ + this._loadInProgress = false; + } + }; + + //Define the function to call if the store reports an error. + var error = function(){ + this._loadInProgress = false; + console.debug("Error getting items"); + }; + + this.request.onComplete = dojo.hitch(this, complete); + this.request.onError = dojo.hitch(this, error); + + //Increment the start parameter. This is the dojo.data API's + //version of paging. + this.request.start = start; + this._noImages = false; + + //Execute the request for data. + this.imageStore.fetch(this.request); + + }, + + _loadImage: function(data, index, callback){ + var url = this.imageStore.getValue(data,this.imageThumbAttr); + var img = document.createElement("img"); + var imgContainer = document.createElement("div"); + imgContainer.setAttribute("id","img_" + this.widgetid+"_"+index); + imgContainer.appendChild(img); + img._index = index; + img._data = data; + + this._thumbs[index] = imgContainer; + var loadingDiv; + if(this.useLoadNotifier){ + loadingDiv = document.createElement("div"); + loadingDiv.setAttribute("id","loadingDiv_" + this.widgetid+"_"+index); + + //If this widget was previously told that the main image for this + //thumb has been loaded, make the loading indicator transparent. + this._setThumbClass(loadingDiv, + this._loadedImages[index] ? "thumbLoaded":"thumbNotifier"); + + imgContainer.appendChild(loadingDiv); + } + var size = dojo.marginBox(this.thumbsNode); + var defaultSize; + var sizeParam; + if(this.isHorizontal){ + defaultSize = this.thumbWidth; + sizeParam = 'w'; + } else{ + defaultSize = this.thumbHeight; + sizeParam = 'h'; + } + size = size[sizeParam]; + var sl = this.thumbScroller.scrollLeft, st = this.thumbScroller.scrollTop; + dojo.style(this.thumbsNode, this._sizeProperty, (size + defaultSize + 20) + "px"); + //Remember the scroll values, as changing the size can alter them + this.thumbScroller.scrollLeft = sl; + this.thumbScroller.scrollTop = st; + this.thumbsNode.appendChild(imgContainer); + + dojo.connect(img, "onload", this, function(){ + var realSize = dojo.marginBox(img)[sizeParam]; + this._totalSize += (Number(realSize) + 4); + dojo.style(this.thumbsNode, this._sizeProperty, this._totalSize + "px"); + + if(this.useLoadNotifier){dojo.style(loadingDiv, "width", (img.width - 4) + "px"); } + callback(); + return false; + }); + + dojo.connect(img, "onclick", this, function(evt){ + dojo.publish(this.getClickTopicName(), [{ + index: evt.target._index, + data: evt.target._data, + url: img.getAttribute("src"), + largeUrl: this.imageStore.getValue(data,this.imageLargeAttr), + title: this.imageStore.getValue(data,this.titleAttr), + link: this.imageStore.getValue(data,this.linkAttr) + }]); + return false; + }); + dojo.addClass(img, "imageGalleryThumb"); + img.setAttribute("src", url); + var title = this.imageStore.getValue(data, this.titleAttr); + if(title){ img.setAttribute("title",title); } + this._updateNavControls(); + + }, + + _updateNavControls: function(){ + // summary: Updates the navigation controls to hide/show them when at + // the first or last images. + var cells = []; + var change = function(node, add){ + var fn = add ? "addClass" : "removeClass"; + dojo[fn](node,"enabled"); + dojo[fn](node,"thumbClickable"); + }; + + var pos = this.isHorizontal ? "scrollLeft" : "scrollTop"; + var size = this.isHorizontal ? "offsetWidth" : "offsetHeight"; + change(this.navPrev, (this.thumbScroller[pos] > 0)); + + var last = this._thumbs[this._thumbs.length - 1]; + var addClass = (this.thumbScroller[pos] + this._scrollerSize < this.thumbsNode[size]); + change(this.navNext, addClass); + } +}); + +} diff --git a/includes/js/dojox/image/resources/Gallery.html b/includes/js/dojox/image/resources/Gallery.html new file mode 100644 index 0000000..571dc4f --- /dev/null +++ b/includes/js/dojox/image/resources/Gallery.html @@ -0,0 +1,4 @@ +
      +
      +
      +
      \ No newline at end of file diff --git a/includes/js/dojox/image/resources/Lightbox.html b/includes/js/dojox/image/resources/Lightbox.html new file mode 100644 index 0000000..1eb292f --- /dev/null +++ b/includes/js/dojox/image/resources/Lightbox.html @@ -0,0 +1,15 @@ +
      +
      +
      + ${title} +
      +
      +
      +
      + +
      ${title}
      +
      +
      + +
      +
      \ No newline at end of file diff --git a/includes/js/dojox/image/resources/Magnifier.css b/includes/js/dojox/image/resources/Magnifier.css new file mode 100644 index 0000000..85eba72 --- /dev/null +++ b/includes/js/dojox/image/resources/Magnifier.css @@ -0,0 +1,5 @@ +.glassNode { + overflow:hidden; + position:absolute; + visibility:hidden; +} diff --git a/includes/js/dojox/image/resources/Magnifier.css.commented.css b/includes/js/dojox/image/resources/Magnifier.css.commented.css new file mode 100644 index 0000000..85eba72 --- /dev/null +++ b/includes/js/dojox/image/resources/Magnifier.css.commented.css @@ -0,0 +1,5 @@ +.glassNode { + overflow:hidden; + position:absolute; + visibility:hidden; +} diff --git a/includes/js/dojox/image/resources/SlideShow.html b/includes/js/dojox/image/resources/SlideShow.html new file mode 100644 index 0000000..fa4aca6 --- /dev/null +++ b/includes/js/dojox/image/resources/SlideShow.html @@ -0,0 +1,14 @@ +
      +
      +
      +
      ${title}
      +
      +
      + + + +
      +
      +
      +
      +
      \ No newline at end of file diff --git a/includes/js/dojox/image/resources/ThumbnailPicker.html b/includes/js/dojox/image/resources/ThumbnailPicker.html new file mode 100644 index 0000000..561ce2d --- /dev/null +++ b/includes/js/dojox/image/resources/ThumbnailPicker.html @@ -0,0 +1,11 @@ +
      +
      + +
      +
      +
      +
      +
      + +
      +
      \ No newline at end of file diff --git a/includes/js/dojox/image/resources/image.css b/includes/js/dojox/image/resources/image.css new file mode 100644 index 0000000..e626e0f --- /dev/null +++ b/includes/js/dojox/image/resources/image.css @@ -0,0 +1,283 @@ + +.dijitDialogUnderlay { + background-color:#000; +} +.dojoxLightbox { + position:absolute; + z-index:999; + overflow:hidden; + width:100px; + height:100px; + border:11px solid #fff; + background:#fff url('images/loading.gif') no-repeat center center; + + -webkit-box-shadow: 0px 6px 10px #636363; + -webkit-border-radius: 3px; + -moz-border-radius:4px; +} +.dojoxLightboxContainer { + position:absolute; + top:0; left:0; +} +.dojoxLightboxFooter { + height:50px; + position:relative; + bottom:0; + left:0; + margin-top:8px; + color:#333; + z-index:1000; + font-size:10pt; +} +.dojoxLightboxGroupText { + color:#666; + font-size:8pt; +} +.LightboxNext, +.LightboxPrev, +.LightboxClose { + float:right; + width:16px; + height:16px; + cursor:pointer; +} +.nihilo .LightboxClose, +.tundra .LightboxClose { + background:url('images/close.png') no-repeat center center; +} +.nihilo .LightboxNext, +.tundra .LightboxNext { + background:url('images/right.png') no-repeat center center; +} +.nihilo .LightboxPrev, +.tundra .LightboxPrev { + background:url('images/left.png') no-repeat center center; +} +.soria .LightboxClose, +.soria .LightboxNext, +.soria .LightboxPrev { + width:15px; + height:15px; + background:url('../../../dijit/themes/soria/images/spriteRoundedIconsSmall.png') no-repeat center center; + background-position:-60px; +} +.soria .LightboxNext { + background-position:-30px 0; +} +.soria .LightboxPrev { + background-position:0 0; +} +.slideShowWrapper { + position:relative; + background:#fff; + padding:8px; + border:1px solid #333; + padding-bottom:20px; + overflow:hidden; + text-align: center; + -moz-border-radius:3pt; + -webkit-border-radius:4pt; + -webkit-drop-shadow:#ccc 4pt; +} +.slideShowNav { + position:absolute; + bottom:-18px; + left:0px; + padding:0px 3px 2px 0px; + background-color:#fff; + width:100%; +} +.slideShowNavWrapper { float:right; } +.slideShowTitle { + float:left; + color:#333; + font-size:10pt; +} +.slideShowTitle .slideShowCounterText { + font-size:6pt; color:#666; +} +.slideShowHidden { + position:absolute; + display: none; + height: 1px; + width: 1px; +} +.slideShowImageWrapper { + position:relative; + text-align: center; + margin-top: -42px; + float: left; + width: 100%; +} +.slideShowImageWrapper img { + border: 0px none; +} +.slideShowNotifier { + background-color: red; + width: 100px; + height: 5px; + font-size: 1%; +} +.slideShowSlideShow { + position:absolute; + top:30px; + padding: 0 5px; + border: 0px; + text-decoration: none; + color: #2e6ab1; +} +.slideShowLoading { background-color: #fad66a; } +.slideShowLoaded { background-color: transparent; } +.slideShowCtrlPrev { + background-position: -96px 0px; + float: left; +} +.slideShowCtrlNext { + background-position: -144px 0px; + float: right; +} +.slideShowCtrlPlay { + background-position: -190px 0px; + position: absolute; +} +.slideShowPaused .slideShowCtrlPlay { + background-position: -236px 0px; + position: absolute; +} +.slideShowCtrl span.slideShowCtrlHide { + background-image: url("../../../dojo/resources/blank.gif"); + cursor: auto; +} +.slideShowCtrl { + height: 50px; + width: 100%; + position: relative; + z-index:999; + float: left; +} +.slideShowCtrl span { + width: 50px; + height: 100%; + background-image: url("images/buttons.png"); + cursor: pointer; +} +.dj_ie6 .slideShowCtrl span { + background-image: url("images/buttons.gif"); +} +.dj_ie6 .slideShowPager li.currentpage, +.dj_ie6 .pagination li.disablepage{ + + margin-right: 5px; + padding-right: 0; +} +.thumbWrapper .thumbNav { + background-repeat: no-repeat; + background-position: center; + padding-top: 1px; + width: 30px; + height: 100%; +} +.thumbOuter { + padding-bottom: 2px; +} +.thumbOuter.thumbHoriz { + width: 500px; + height: 85px; +} +.thumbOuter.thumbVert { + width: 100px; + height: 400px; +} +.thumbOuter .enabled { + background: transparent url("images/buttons.png") no-repeat center center; +} +.dj_ie6 .thumbOuter .enabled { background-image: url("images/buttons.gif"); } +.thumbOuter .thumbNav img { + width: 48px; + height: 75px; +} +.thumbOuter .thumbClickable div { + cursor: pointer; +} +.thumbOuter .prevHoriz { + background-position: -96px 12px; + position: relative; + float: left; + height: 100%; +} +.thumbOuter .nextHoriz { + background-position: -144px 12px; + position: relative; + float: right; + height: 100%; +} +.thumbOuter .prevVert { + background-position: 0px 0px; + height: 48px; + width:48px; + margin-left:24px; +} +.thumbOuter .nextVert { + background-position: -48px 0px; + height: 48px; + width:48px; + margin-left:24px; +} +.thumbWrapper img { + height: 75px; + max-width: 100px; + width: expression(this.width > 100 ? 100: true); +} +.thumbWrapper .thumbNav .imageGalleryThumb { + height: 50px; +} +.thumbWrapper .thumbNotifier { + background-color: red; + width: 0px; + margin-left: 2px; + height: 5px; + font-size: 1%; +} +.thumbWrapper .thumbLoaded { + background-color: transparent; +} +.thumbScroller { + overflow-x: hidden; + overflow-y: hidden; + white-space: nowrap; + text-align: center; +} +.thumbHoriz .thumbScroller { + width: 500px; + height: 85px; + float: left; +} +.thumbVert .thumbScroller { + height: 500px; + width: 100px; +} +.thumbWrapper { + float: left; +} +.thumbVert .thumbWrapper { + width: 100px; + height: 10px; +} +.thumbHoriz .thumbWapper { + height:85px; + width: 10px; +} +.thumbWrapper.thumbHoriz div { + float: left; + padding-right: 2px; +} +.thumbWrapper.thumbVert { + width: 100px; +} +.thumbWrapper.thumbVert div { + padding-bottom: 2px; +} +.imageGalleryWrapper { + padding-bottom: 20px; + text-align: center; +} diff --git a/includes/js/dojox/image/resources/image.css.commented.css b/includes/js/dojox/image/resources/image.css.commented.css new file mode 100644 index 0000000..3539a71 --- /dev/null +++ b/includes/js/dojox/image/resources/image.css.commented.css @@ -0,0 +1,345 @@ +/* + This is the master CSS file for the dojox.image project, and provides all + needed definitions for: + + dojox.image.Lightbox + dojox.image.Gallery [which is a combination of:] + dojox.image.SlideShow + dojox.image.ThumbNailPicker + +*/ + + +/* dojox.image.Lightbox:base */ +/* FIXME: should be be doing this? I want a black underlay, but this sets ALL dialogs to black, + but because it's decendant of body, i can't set this color any other way ... */ +.dijitDialogUnderlay { + background-color:#000; +} + +.dojoxLightbox { + position:absolute; + z-index:999; + overflow:hidden; + width:100px; + height:100px; + border:11px solid #fff; + background:#fff url('images/loading.gif') no-repeat center center; + + /* special safari + FF specific rounding + shadows */ + -webkit-box-shadow: 0px 6px 10px #636363; /* #adadad; */ + -webkit-border-radius: 3px; + -moz-border-radius:4px; +} + +.dojoxLightboxContainer { + position:absolute; + top:0; left:0; +} + +.dojoxLightboxFooter { + height:50px; + position:relative; + bottom:0; + left:0; + margin-top:8px; + color:#333; + z-index:1000; + font-size:10pt; +} + +.dojoxLightboxGroupText { + color:#666; + font-size:8pt; +} + +.LightboxNext, +.LightboxPrev, +.LightboxClose { + float:right; + width:16px; + height:16px; + cursor:pointer; +} + +/* dojox.image.Lightbox:tundra:nihilo */ + +.nihilo .LightboxClose, +.tundra .LightboxClose { + background:url('images/close.png') no-repeat center center; +} +.nihilo .LightboxNext, +.tundra .LightboxNext { + background:url('images/right.png') no-repeat center center; +} +.nihilo .LightboxPrev, +.tundra .LightboxPrev { + background:url('images/left.png') no-repeat center center; +} + +/* dojox.image.Lightbox:soria */ +.soria .LightboxClose, +.soria .LightboxNext, +.soria .LightboxPrev { + width:15px; + height:15px; + background:url('../../../dijit/themes/soria/images/spriteRoundedIconsSmall.png') no-repeat center center; + background-position:-60px; +} +.soria .LightboxNext { + background-position:-30px 0; +} +.soria .LightboxPrev { + background-position:0 0; +} + + + +/* dojox.image.SlideShow */ + +.slideShowWrapper { + position:relative; + background:#fff; + padding:8px; + border:1px solid #333; + padding-bottom:20px; + overflow:hidden; + text-align: center; + -moz-border-radius:3pt; + -webkit-border-radius:4pt; + -webkit-drop-shadow:#ccc 4pt; +} +.slideShowNav { + position:absolute; + bottom:-18px; + left:0px; + padding:0px 3px 2px 0px; + background-color:#fff; + width:100%; +} +.slideShowNavWrapper { float:right; } +.slideShowTitle { + float:left; + color:#333; + font-size:10pt; +} +.slideShowTitle .slideShowCounterText { + font-size:6pt; color:#666; +} +.slideShowHidden { + position:absolute; + display: none; + height: 1px; + width: 1px; +} +.slideShowImageWrapper { + position:relative; + text-align: center; + margin-top: -42px; + float: left; + width: 100%; +} +.slideShowImageWrapper img { + border: 0px none; +} +.slideShowNotifier { + background-color: red; + width: 100px; + height: 5px; + font-size: 1%;/*IE hack to get around the Empty-Div bug*/ +} +.slideShowSlideShow { + position:absolute; + top:30px; + padding: 0 5px; + border: 0px; + text-decoration: none; + color: #2e6ab1; +} +.slideShowLoading { background-color: #fad66a; } +.slideShowLoaded { background-color: transparent; } +/* +.sprite-arrowbottom { background-position: 0 -30px; } +.sprite-arrowtop { background-position: 0 -430px; } +*/ +.slideShowCtrlPrev { + background-position: -96px 0px; + float: left; +} +.slideShowCtrlNext { + background-position: -144px 0px; + float: right; +} +.slideShowCtrlPlay { + background-position: -190px 0px; + position: absolute; +} +.slideShowPaused .slideShowCtrlPlay { + background-position: -236px 0px; + position: absolute; +} +.slideShowCtrl span.slideShowCtrlHide { + background-image: url("../../../dojo/resources/blank.gif"); + cursor: auto; +} + +.slideShowCtrl { + height: 50px; + width: 100%; + position: relative; + z-index:999; + float: left; +} +.slideShowCtrl span { + width: 50px; + height: 100%; + background-image: url("images/buttons.png"); + cursor: pointer; +} +.dj_ie6 .slideShowCtrl span { + background-image: url("images/buttons.gif"); +} + +.dj_ie6 .slideShowPager li.currentpage, +.dj_ie6 .pagination li.disablepage{ + /*IE 6 and below. Adjust non linked LIs slightly to account for bugs*/ + margin-right: 5px; + padding-right: 0; +} + +/* dojox.image.ThumbnailPicker */ + +.thumbWrapper .thumbNav { + background-repeat: no-repeat; + background-position: center; + padding-top: 1px; + width: 30px; + height: 100%; +} + +.thumbOuter { + padding-bottom: 2px; +} + +.thumbOuter.thumbHoriz { + width: 500px; + height: 85px; +} + +.thumbOuter.thumbVert { + width: 100px; + height: 400px; +} + +.thumbOuter .enabled { + background: transparent url("images/buttons.png") no-repeat center center; +} +.dj_ie6 .thumbOuter .enabled { background-image: url("images/buttons.gif"); } + +.thumbOuter .thumbNav img { + width: 48px; + height: 75px; +} +.thumbOuter .thumbClickable div { + cursor: pointer; +} +.thumbOuter .prevHoriz { + background-position: -96px 12px; + position: relative; + float: left; + height: 100%; +} + +.thumbOuter .nextHoriz { + background-position: -144px 12px; + position: relative; + float: right; + height: 100%; +/* margin-top: -85px;*/ +} +.thumbOuter .prevVert { + background-position: 0px 0px; + height: 48px; + width:48px; + margin-left:24px; +} + +.thumbOuter .nextVert { + background-position: -48px 0px; + height: 48px; + width:48px; + margin-left:24px; +} + +.thumbWrapper img { + height: 75px; + max-width: 100px; + width: expression(this.width > 100 ? 100: true);/*IE Hack*/ +} + +.thumbWrapper .thumbNav .imageGalleryThumb { + height: 50px; +} + +.thumbWrapper .thumbNotifier { + background-color: red; + width: 0px; + margin-left: 2px; + height: 5px; + font-size: 1%;/*IE hack to get around the Empty-Div bug*/ +} + +.thumbWrapper .thumbLoaded { + background-color: transparent; +} + +.thumbScroller { + overflow-x: hidden; + overflow-y: hidden; + white-space: nowrap; + text-align: center; +} + +.thumbHoriz .thumbScroller { + width: 500px; + height: 85px; + float: left; +} + +.thumbVert .thumbScroller { + height: 500px; + width: 100px; +} + +.thumbWrapper { + float: left; +} + +.thumbVert .thumbWrapper { + width: 100px; + height: 10px; +} +.thumbHoriz .thumbWapper { + height:85px; + width: 10px; +} + +.thumbWrapper.thumbHoriz div { + float: left; + padding-right: 2px; +} + +.thumbWrapper.thumbVert { + width: 100px; +} + +.thumbWrapper.thumbVert div { + padding-bottom: 2px; +} + +/* dojox.image.Gallery */ + +.imageGalleryWrapper { + padding-bottom: 20px; + text-align: center; +} diff --git a/includes/js/dojox/image/resources/images/buttons.gif b/includes/js/dojox/image/resources/images/buttons.gif new file mode 100644 index 0000000..5f9081f Binary files /dev/null and b/includes/js/dojox/image/resources/images/buttons.gif differ diff --git a/includes/js/dojox/image/resources/images/buttons.png b/includes/js/dojox/image/resources/images/buttons.png new file mode 100644 index 0000000..306e2f8 Binary files /dev/null and b/includes/js/dojox/image/resources/images/buttons.png differ diff --git a/includes/js/dojox/image/resources/images/close.png b/includes/js/dojox/image/resources/images/close.png new file mode 100644 index 0000000..1ac9d10 Binary files /dev/null and b/includes/js/dojox/image/resources/images/close.png differ diff --git a/includes/js/dojox/image/resources/images/close_dark.png b/includes/js/dojox/image/resources/images/close_dark.png new file mode 100644 index 0000000..105fe55 Binary files /dev/null and b/includes/js/dojox/image/resources/images/close_dark.png differ diff --git a/includes/js/dojox/image/resources/images/left.png b/includes/js/dojox/image/resources/images/left.png new file mode 100644 index 0000000..0848dba Binary files /dev/null and b/includes/js/dojox/image/resources/images/left.png differ diff --git a/includes/js/dojox/image/resources/images/loading.gif b/includes/js/dojox/image/resources/images/loading.gif new file mode 100644 index 0000000..e4ab783 Binary files /dev/null and b/includes/js/dojox/image/resources/images/loading.gif differ diff --git a/includes/js/dojox/image/resources/images/right.png b/includes/js/dojox/image/resources/images/right.png new file mode 100644 index 0000000..7cab686 Binary files /dev/null and b/includes/js/dojox/image/resources/images/right.png differ diff --git a/includes/js/dojox/image/resources/images/warning.png b/includes/js/dojox/image/resources/images/warning.png new file mode 100644 index 0000000..a52a55f Binary files /dev/null and b/includes/js/dojox/image/resources/images/warning.png differ diff --git a/includes/js/dojox/image/tests/images.json b/includes/js/dojox/image/tests/images.json new file mode 100644 index 0000000..bd0cf96 --- /dev/null +++ b/includes/js/dojox/image/tests/images.json @@ -0,0 +1,32 @@ +{ items: [ + { + "thumb":"images/extraWide.jpg", + "large":"images/extraWide.jpg", + "title":"I'm wide, me", + "link":"http://www.flickr.com/photos/44153025@N00/748348847" + }, + { + "thumb":"images/imageHoriz.jpg", + "large":"images/imageHoriz.jpg", + "title":"I'm a horizontal picture", + "link":"http://www.flickr.com/photos/44153025@N00/735656038" + }, + { + "thumb":"images/imageHoriz2.jpg", + "large":"images/imageHoriz2.jpg", + "title":"I'm another horizontal picture", + "link":"http://www.flickr.com/photos/44153025@N00/714540483" + }, + { + "thumb":"images/imageVert.jpg", + "large":"images/imageVert.jpg", + "title":"I'm a vertical picture", + "link":"http://www.flickr.com/photos/44153025@N00/715392758" + }, + { + "large":"images/square.jpg", + "thumb":"images/square.jpg", + "link" :"images/square.jpg", + "title":"1:1 aspect ratio" + } +]} \ No newline at end of file diff --git a/includes/js/dojox/image/tests/images/extraWide.jpg b/includes/js/dojox/image/tests/images/extraWide.jpg new file mode 100644 index 0000000..2161825 Binary files /dev/null and b/includes/js/dojox/image/tests/images/extraWide.jpg differ diff --git a/includes/js/dojox/image/tests/images/huuuge.png b/includes/js/dojox/image/tests/images/huuuge.png new file mode 100644 index 0000000..ee98a39 Binary files /dev/null and b/includes/js/dojox/image/tests/images/huuuge.png differ diff --git a/includes/js/dojox/image/tests/images/imageHoriz.jpg b/includes/js/dojox/image/tests/images/imageHoriz.jpg new file mode 100644 index 0000000..3948416 Binary files /dev/null and b/includes/js/dojox/image/tests/images/imageHoriz.jpg differ diff --git a/includes/js/dojox/image/tests/images/imageHoriz2.jpg b/includes/js/dojox/image/tests/images/imageHoriz2.jpg new file mode 100644 index 0000000..fbbf404 Binary files /dev/null and b/includes/js/dojox/image/tests/images/imageHoriz2.jpg differ diff --git a/includes/js/dojox/image/tests/images/imageVert.jpg b/includes/js/dojox/image/tests/images/imageVert.jpg new file mode 100644 index 0000000..1652338 Binary files /dev/null and b/includes/js/dojox/image/tests/images/imageVert.jpg differ diff --git a/includes/js/dojox/image/tests/images/spanke.jpg b/includes/js/dojox/image/tests/images/spanke.jpg new file mode 100644 index 0000000..ec95fb0 Binary files /dev/null and b/includes/js/dojox/image/tests/images/spanke.jpg differ diff --git a/includes/js/dojox/image/tests/images/square.jpg b/includes/js/dojox/image/tests/images/square.jpg new file mode 100644 index 0000000..9094d5a Binary files /dev/null and b/includes/js/dojox/image/tests/images/square.jpg differ diff --git a/includes/js/dojox/image/tests/test_Gallery.html b/includes/js/dojox/image/tests/test_Gallery.html new file mode 100644 index 0000000..320c481 --- /dev/null +++ b/includes/js/dojox/image/tests/test_Gallery.html @@ -0,0 +1,67 @@ + + + + + Testing the Image Gallery + + + + + + + + + + + + + + + + + +

      dojox.image.Gallery

      + +

      From FlickrRestStore:

      +
      + + + + + diff --git a/includes/js/dojox/image/tests/test_Lightbox.html b/includes/js/dojox/image/tests/test_Lightbox.html new file mode 100644 index 0000000..15b34c8 --- /dev/null +++ b/includes/js/dojox/image/tests/test_Lightbox.html @@ -0,0 +1,105 @@ + + + + dojox.image.Lightbox Tests | The Dojo Toolkit + + + + + + + + + + + + + + +
      +

      a Dojo based Lightbox implementation:

      + +

      Individual

      +

      + tall + 4:3 image + Broken link + large than viewport? +

      + +

      Grouped:

      +

      + wide image + square + wide image + Broken link +

      + +

      Alternate Group:

      +

      + wide image + square + 4:3 image + tall +

      + +

      From dojox.data.FlickrStore:

      + +
      +
      + + + +
      + + + diff --git a/includes/js/dojox/image/tests/test_Magnifier.html b/includes/js/dojox/image/tests/test_Magnifier.html new file mode 100644 index 0000000..fef1ddd --- /dev/null +++ b/includes/js/dojox/image/tests/test_Magnifier.html @@ -0,0 +1,98 @@ + + + Testing image + + + + + + + + + + + +

      dojox.image.Magnifier test page

      + +

      They are just images. It's entirely unobtrusive to add magnification to an image, and style it accordingly.

      +

      This widget is based on dojox.image.MagnifierLite, an image-only variant on this dojox.gfx + based Widget. The idea was/is to include addational surfaces in some kind of _Templated GFX widget, based on _Widget.

      +

      + Scale= 2.34, 5.67, and 8.90:
      + + + + +

      + +

      + + I Am Some inline text.
      lorem ipsum.
      +

      + +

      A Transparent .png:
      + + +

      + +

      Programatic:
      + + + + + +
      + +

      + +

      Remote file (GTA:LCS/psp map):
      + + +
      Everybody loves Zelda, right?
      + +

      + +

      + +

      + + + diff --git a/includes/js/dojox/image/tests/test_MagnifierLite.html b/includes/js/dojox/image/tests/test_MagnifierLite.html new file mode 100644 index 0000000..6e6ccd7 --- /dev/null +++ b/includes/js/dojox/image/tests/test_MagnifierLite.html @@ -0,0 +1,91 @@ + + + Testing image + + + + + + + + + +

      dojox.image.MagnifierLite test page

      + +

      They are just images. It's entirely unobtrusive to add magnification to an image, and style it accordingly.

      + +

      This is the base class for dojox.image.Magnifier, a dojox.gfx-based extension + this portion does not require the dojox.gfx package, but is limited to CSS-based styling. +

      + +

      + Scale= 2.34, 5.67, and 8.90:
      + + + + +

      + +

      + + I Am Some inline text.
      lorem ipsum.
      +

      + +

      A Transparent .png: (url unavailable in release versions, need build-utils package, or svn)
      + + +

      + +

      Programatic: (destroy() removes this.domNode)
      + + + + + +
      + +

      + +

      Remote file (GTA:LCS/psp map):
      + + +
      Everybody loves Zelda:
      + +

      + + + diff --git a/includes/js/dojox/image/tests/test_SlideShow.html b/includes/js/dojox/image/tests/test_SlideShow.html new file mode 100644 index 0000000..9200c4b --- /dev/null +++ b/includes/js/dojox/image/tests/test_SlideShow.html @@ -0,0 +1,68 @@ + + + + + Testing dojox.image.SlideShow + + + + + + + + + + + + +

      dojox.image.SlideShow

      + +

      from dojo.data.ItemFileReadStore

      +
      + + This SlideShow should display five photos, and loop. It should also + open a URL when the image is clicked. The widget should also resize to + fit the image. +
      + +

      from dojox.data.FlickrRestStore

      + This SlideShow should display five photos, and not loop. It should also not + open a URL when the image is clicked. AutoLoading of images is also disabled. + The time between images in a SlideShow is 1 second. The widget should not resize to fit the image +
      + + + diff --git a/includes/js/dojox/image/tests/test_ThumbnailPicker.html b/includes/js/dojox/image/tests/test_ThumbnailPicker.html new file mode 100644 index 0000000..90cdf2e --- /dev/null +++ b/includes/js/dojox/image/tests/test_ThumbnailPicker.html @@ -0,0 +1,134 @@ + + + + + Testing the ThumbnailPicker + + + + + + + + + + +

      dojox.image.ThumbnailPicker

      + +
      + When you click on a thumbnail image, it's information is placed here +
      + +

      From FlickrRestStore:

      + This ThumbnailPicker should have 8 thumbnails, with each of them linking + to a URL when clicked on. The cursor should also change when over an image. +
      + +

      From ItemFileReadStore:

      + This ThumbnailPicker should have 5 thumbnails. Clicking on a thumbnail should NOT + open a URL, and the cursor should not change when over an image that is not an arrow. + +
      +
      + +

      From FlickrRestStore:

      + This ThumbnailPicker should have 6 thumbnails, with each of them linking + to a URL when clicked on. The cursor should also change when over an image. + Unlike the ThumbnailPicker above, when these links are clicked on, this page + changes, instead of a popup window. + +
      + +

      From ItemFileReadStore, and vertical:

      + This ThumbnailPicker should have 5 thumbnails. Clicking on a thumbnail should NOT + open a URL, and the cursor should not change when over an image that is not an arrow. + The thumbnails should also be aligned vertically. +
      + + + diff --git a/includes/js/dojox/io/README b/includes/js/dojox/io/README new file mode 100644 index 0000000..2dfd62e --- /dev/null +++ b/includes/js/dojox/io/README @@ -0,0 +1,45 @@ +------------------------------------------------------------------------------- +DojoX IO +------------------------------------------------------------------------------- +Version 0.3.1 +Release date: 09/06/2007 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + Bryan Forbes (bryan@reigndropsfall.net) +------------------------------------------------------------------------------- +Project description + +------------------------------------------------------------------------------- +Dependencies: + +DojoX IO depends on Dojo Core and DojoX UUID's generateRandomUuid function. +------------------------------------------------------------------------------- +Documentation + +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/uuid.js +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/uuid/* + +Install into the following directory structure: +/dojox/uuid/ + +AND + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/io/* + +Install into the following directory structure: +/dojox/io/ + +...both of which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- +Additional Notes + +The information contained in this README does not pertain to DojoX XHR IFrame Proxy. +For that information see proxy/README. diff --git a/includes/js/dojox/io/proxy/README b/includes/js/dojox/io/proxy/README new file mode 100644 index 0000000..8898a56 --- /dev/null +++ b/includes/js/dojox/io/proxy/README @@ -0,0 +1,82 @@ +------------------------------------------------------------------------------- +Project Name +------------------------------------------------------------------------------- +Version 0.6 +Release date: 01/31/2008 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + James Burke (jburke@dojotoolkit.org) +------------------------------------------------------------------------------- +Project description + +The XHR IFrame Proxy (xip) allows you to do cross-domain XMLHttpRequests (XHRs). +It works by using two iframes, one your domain (xip_client.html), one on the +other domain (xip_server.html). They use fragment IDs in the iframe URLs to pass +messages to each other. The xip.js file defines dojox.io.proxy.xip. This module +intercepts XHR calls made by the Dojo XHR methods (dojo.xhr* methods). The module +returns a facade object that acts like an XHR object. Once send is called on the +facade, the facade's data is serialized, given to xip_client.html. xip_client.html +then passes the serialized data to xip_server.html by changing xip_server.html's +URL fragment ID (the #xxxx part of an URL). xip_server.html deserializes the +message fragments, and does an XHR call, gets the response, and serializes the +data. The serialized data is then passed back to xip_client.html by changing +xip_client.html's fragment ID. Then the response is deserialized and used as +the response inside the facade XHR object that was created by dojox.io.proxy.xip. +------------------------------------------------------------------------------- +Dependencies: + +xip.js: Dojo Core, dojox.data.dom +xip_client.html: none +xip_server.html: none (but see Additional Notes section) +------------------------------------------------------------------------------- +Documentation + +There is some documentation that applies to the Dojo 0.4.x version of these files: +http://dojotoolkit.org/book/dojo-book-0-4/part-5-connecting-pieces/i-o/cross-domain-xmlhttprequest-using-iframe-proxy + +The general theory still applies to this code, but the specifics are different +for the Dojo 0.9+ codebase. Doc updates hopefully after the basic code is ported. + +The current implementation destroys the iframes used for a request after the request +completes. This seems to cause a memory leak, particularly in IE. So, it is not +suited for doing polling cross-domain requests. +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojox SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/io/proxy/xip.js +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/io/proxy/xip_client.html + +Install into the following directory structure: +/dojox/io/proxy/ + +...which should be at the same level as your Dojo checkout. + +Grab the following from the Dojox SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/io/proxy/xip_server.html + +and install it on the domain that you want to allow receiving cross-domain +requests. Be sure to read the documentation, the Additional Notes below, and +the in-file comments. +------------------------------------------------------------------------------- +Additional Notes + +xip_client.html and xip_server.html do not work right away. You need to uncomment +out the script tags in the files. Additionally, xip_server.html requires a JS file, +isAllowed.js, to be defined. See the notes in xip_server.html for more informaiton. + +XDOMAIN BUILD INSTRUCTIONS: +The dojox.io.proxy module requires some setup to use with an xdomain build. +The xip_client.html file has to be served from the same domain as your web page. +It cannot be served from the domain that has the xdomain build. Download xip_client.html +and install it on your server. Then set djConfig.xipClientUrl to the local path +of xip_client.html (just use a path, not a whole URL, since it will be on the same +domain as the page). The path to the file should be the path relative to the web +page that is using dojox.io.proxy. + + + + diff --git a/includes/js/dojox/io/proxy/tests/frag.xml b/includes/js/dojox/io/proxy/tests/frag.xml new file mode 100644 index 0000000..6904bba --- /dev/null +++ b/includes/js/dojox/io/proxy/tests/frag.xml @@ -0,0 +1,4 @@ + +This is the foo text node value +This is the bar text node value + diff --git a/includes/js/dojox/io/proxy/tests/xip.html b/includes/js/dojox/io/proxy/tests/xip.html new file mode 100644 index 0000000..5a5ba5f --- /dev/null +++ b/includes/js/dojox/io/proxy/tests/xip.html @@ -0,0 +1,62 @@ + + + + XHR IFrame Proxy Tests + + + + + + + + +

      XHR IFrame Proxy Tests

      +

      Run this test from a web server, not from local disk.

      + +

      + +

      +
      + + + diff --git a/includes/js/dojox/io/proxy/xip.js b/includes/js/dojox/io/proxy/xip.js new file mode 100644 index 0000000..b88d910 --- /dev/null +++ b/includes/js/dojox/io/proxy/xip.js @@ -0,0 +1,441 @@ +if(!dojo._hasResource["dojox.io.proxy.xip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.io.proxy.xip"] = true; +dojo.provide("dojox.io.proxy.xip"); + +dojo.require("dojo.io.iframe"); +dojo.require("dojox.data.dom"); + +dojox.io.proxy.xip = { + //summary: Object that implements the iframe handling for XMLHttpRequest + //IFrame Proxying. + //description: Do not use this object directly. See the Dojo Book page + //on XMLHttpRequest IFrame Proxying: + //http://dojotoolkit.org/book/dojo-book-0-4/part-5-connecting-pieces/i-o/cross-domain-xmlhttprequest-using-iframe-proxy + //Usage of XHR IFrame Proxying does not work from local disk in Safari. + + /* + This code is really focused on just sending one complete request to the server, and + receiving one complete response per iframe. The code does not expect to reuse iframes for multiple XHR request/response + sequences. This might be reworked later if performance indicates a need for it. + + xip fragment identifier/hash values have the form: + #id:cmd:realEncodedMessage + + id: some ID that should be unique among message fragments. No inherent meaning, + just something to make sure the hash value is unique so the message + receiver knows a new message is available. + + cmd: command to the receiver. Valid values are: + - init: message used to init the frame. Sent as the first URL when loading + the page. Contains some config parameters. + - loaded: the remote frame is loaded. Only sent from xip_client.html to this module. + - ok: the message that this page sent was received OK. The next message may + now be sent. + - start: the start message of a block of messages (a complete message may + need to be segmented into many messages to get around the limitiations + of the size of an URL that a browser accepts. + - part: indicates this is a part of a message. + - end: the end message of a block of messages. The message can now be acted upon. + If the message is small enough that it doesn't need to be segmented, then + just one hash value message can be sent with "end" as the command. + + To reassemble a segmented message, the realEncodedMessage parts just have to be concatenated + together. + */ + + xipClientUrl: ((dojo.config || djConfig)["xipClientUrl"]) || dojo.moduleUrl("dojox.io.proxy", "xip_client.html"), + + + //MSIE has the lowest limit for URLs with fragment identifiers, + //at around 4K. Choosing a slightly smaller number for good measure. + urlLimit: 4000, + + _callbackName: (dojox._scopeName || "dojox") + ".io.proxy.xip.fragmentReceived", + _state: {}, + _stateIdCounter: 0, + _isWebKit: navigator.userAgent.indexOf("WebKit") != -1, + + + send: function(/*Object*/facade){ + //summary: starts the xdomain request using the provided facade. + //This method first does some init work, then delegates to _realSend. + + var url = this.xipClientUrl; + //Make sure we are not dealing with javascript urls, just to be safe. + if(url.split(":")[0].match(/javascript/i) || facade._ifpServerUrl.split(":")[0].match(/javascript/i)){ + return; + } + + //Make xip_client a full URL. + var colonIndex = url.indexOf(":"); + var slashIndex = url.indexOf("/"); + if(colonIndex == -1 || slashIndex < colonIndex){ + //No colon or we are starting with a / before a colon, so we need to make a full URL. + var loc = window.location.href; + if(slashIndex == 0){ + //Have a full path, just need the domain. + url = loc.substring(0, loc.indexOf("/", 9)) + url; //Using 9 to get past http(s):// + }else{ + url = loc.substring(0, (loc.lastIndexOf("/") + 1)) + url; + } + } + this.fullXipClientUrl = url; + + //Set up an HTML5 messaging listener if postMessage exists. + //As of this writing, this is only useful to get Opera 9.25+ to work. + if(typeof document.postMessage != "undefined"){ + document.addEventListener("message", dojo.hitch(this, this.fragmentReceivedEvent), false); + } + + //Now that we did first time init, always use the realSend method. + this.send = this._realSend; + return this._realSend(facade); //Object + }, + + _realSend: function(facade){ + //summary: starts the actual xdomain request using the provided facade. + var stateId = "XhrIframeProxy" + (this._stateIdCounter++); + facade._stateId = stateId; + + var frameUrl = facade._ifpServerUrl + "#0:init:id=" + stateId + "&client=" + + encodeURIComponent(this.fullXipClientUrl) + "&callback=" + encodeURIComponent(this._callbackName); + + this._state[stateId] = { + facade: facade, + stateId: stateId, + clientFrame: dojo.io.iframe.create(stateId, "", frameUrl), + isSending: false, + serverUrl: facade._ifpServerUrl, + requestData: null, + responseMessage: "", + requestParts: [], + idCounter: 1, + partIndex: 0, + serverWindow: null + }; + + return stateId; //Object + }, + + receive: function(/*String*/stateId, /*String*/urlEncodedData){ + /* urlEncodedData should have the following params: + - responseHeaders + - status + - statusText + - responseText + */ + //Decode response data. + var response = {}; + var nvPairs = urlEncodedData.split("&"); + for(var i = 0; i < nvPairs.length; i++){ + if(nvPairs[i]){ + var nameValue = nvPairs[i].split("="); + response[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]); + } + } + + //Set data on facade object. + var state = this._state[stateId]; + var facade = state.facade; + + facade._setResponseHeaders(response.responseHeaders); + if(response.status == 0 || response.status){ + facade.status = parseInt(response.status, 10); + } + if(response.statusText){ + facade.statusText = response.statusText; + } + if(response.responseText){ + facade.responseText = response.responseText; + + //Fix responseXML. + var contentType = facade.getResponseHeader("Content-Type"); + if(contentType){ + var mimeType = contentType.split(";")[0]; + if(mimeType.indexOf("application/xml") == 0 || mimeType.indexOf("text/xml") == 0){ + facade.responseXML = dojox.data.dom.createDocument(response.responseText, contentType); + } + } + } + facade.readyState = 4; + + this.destroyState(stateId); + }, + + frameLoaded: function(/*String*/stateId){ + var state = this._state[stateId]; + var facade = state.facade; + + var reqHeaders = []; + for(var param in facade._requestHeaders){ + reqHeaders.push(param + ": " + facade._requestHeaders[param]); + } + + var requestData = { + uri: facade._uri + }; + if(reqHeaders.length > 0){ + requestData.requestHeaders = reqHeaders.join("\r\n"); + } + if(facade._method){ + requestData.method = facade._method; + } + if(facade._bodyData){ + requestData.data = facade._bodyData; + } + + this.sendRequest(stateId, dojo.objectToQuery(requestData)); + }, + + destroyState: function(/*String*/stateId){ + var state = this._state[stateId]; + if(state){ + delete this._state[stateId]; + var parentNode = state.clientFrame.parentNode; + parentNode.removeChild(state.clientFrame); + state.clientFrame = null; + state = null; + } + }, + + createFacade: function(){ + if(arguments && arguments[0] && arguments[0].iframeProxyUrl){ + return new dojox.io.proxy.xip.XhrIframeFacade(arguments[0].iframeProxyUrl); + }else{ + return dojox.io.proxy.xip._xhrObjOld.apply(dojo, arguments); + } + }, + + //**** State-bound methods **** + sendRequest: function(stateId, encodedData){ + var state = this._state[stateId]; + if(!state.isSending){ + state.isSending = true; + + state.requestData = encodedData || ""; + + //Get a handle to the server iframe. + state.serverWindow = frames[state.stateId]; + if (!state.serverWindow){ + state.serverWindow = document.getElementById(state.stateId).contentWindow; + } + + //Make sure we have contentWindow, but only do this for non-postMessage + //browsers (right now just opera is postMessage). + if(typeof document.postMessage == "undefined"){ + if(state.serverWindow.contentWindow){ + state.serverWindow = state.serverWindow.contentWindow; + } + } + + this.sendRequestStart(stateId); + } + }, + + sendRequestStart: function(stateId){ + //Break the message into parts, if necessary. + var state = this._state[stateId]; + state.requestParts = []; + var reqData = state.requestData; + var urlLength = state.serverUrl.length; + var partLength = this.urlLimit - urlLength; + var reqIndex = 0; + + while((reqData.length - reqIndex) + urlLength > this.urlLimit){ + var part = reqData.substring(reqIndex, reqIndex + partLength); + //Safari will do some extra hex escaping unless we keep the original hex + //escaping complete. + var percentIndex = part.lastIndexOf("%"); + if(percentIndex == part.length - 1 || percentIndex == part.length - 2){ + part = part.substring(0, percentIndex); + } + state.requestParts.push(part); + reqIndex += part.length; + } + state.requestParts.push(reqData.substring(reqIndex, reqData.length)); + + state.partIndex = 0; + this.sendRequestPart(stateId); + + }, + + sendRequestPart: function(stateId){ + var state = this._state[stateId]; + + if(state.partIndex < state.requestParts.length){ + //Get the message part. + var partData = state.requestParts[state.partIndex]; + + //Get the command. + var cmd = "part"; + if(state.partIndex + 1 == state.requestParts.length){ + cmd = "end"; + }else if (state.partIndex == 0){ + cmd = "start"; + } + + this.setServerUrl(stateId, cmd, partData); + state.partIndex++; + } + }, + + setServerUrl: function(stateId, cmd, message){ + var serverUrl = this.makeServerUrl(stateId, cmd, message); + var state = this._state[stateId]; + + //Safari won't let us replace across domains. + if(this._isWebKit){ + state.serverWindow.location = serverUrl; + }else{ + state.serverWindow.location.replace(serverUrl); + } + }, + + makeServerUrl: function(stateId, cmd, message){ + var state = this._state[stateId]; + var serverUrl = state.serverUrl + "#" + (state.idCounter++) + ":" + cmd; + if(message){ + serverUrl += ":" + message; + } + return serverUrl; + }, + + fragmentReceivedEvent: function(evt){ + //summary: HTML5 document messaging endpoint. Unpack the event to see + //if we want to use it. + if(evt.uri.split("#")[0] == this.fullXipClientUrl){ + this.fragmentReceived(evt.data); + } + }, + + fragmentReceived: function(frag){ + var index = frag.indexOf("#"); + var stateId = frag.substring(0, index); + var encodedData = frag.substring(index + 1, frag.length); + + var msg = this.unpackMessage(encodedData); + var state = this._state[stateId]; + + switch(msg.command){ + case "loaded": + this.frameLoaded(stateId); + break; + case "ok": + this.sendRequestPart(stateId); + break; + case "start": + state.responseMessage = "" + msg.message; + this.setServerUrl(stateId, "ok"); + break; + case "part": + state.responseMessage += msg.message; + this.setServerUrl(stateId, "ok"); + break; + case "end": + this.setServerUrl(stateId, "ok"); + state.responseMessage += msg.message; + this.receive(stateId, state.responseMessage); + break; + } + }, + + unpackMessage: function(encodedMessage){ + var parts = encodedMessage.split(":"); + var command = parts[1]; + encodedMessage = parts[2] || ""; + + var config = null; + if(command == "init"){ + var configParts = encodedMessage.split("&"); + config = {}; + for(var i = 0; i < configParts.length; i++){ + var nameValue = configParts[i].split("="); + config[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]); + } + } + return {command: command, message: encodedMessage, config: config}; + } +} + +//Replace the normal XHR factory with the proxy one. +dojox.io.proxy.xip._xhrObjOld = dojo._xhrObj; +dojo._xhrObj = dojox.io.proxy.xip.createFacade; + +/** + Using this a reference: http://www.w3.org/TR/XMLHttpRequest/ + + Does not implement the onreadystate callback since dojo.xhr* does + not use it. +*/ +dojox.io.proxy.xip.XhrIframeFacade = function(ifpServerUrl){ + //summary: XMLHttpRequest facade object used by dojox.io.proxy.xip. + + //description: Do not use this object directly. See the Dojo Book page + //on XMLHttpRequest IFrame Proxying: + //http://dojotoolkit.org/book/dojo-book-0-4/part-5-connecting-pieces/i-o/cross-domain-xmlhttprequest-using-iframe-proxy + this._requestHeaders = {}; + this._allResponseHeaders = null; + this._responseHeaders = {}; + this._method = null; + this._uri = null; + this._bodyData = null; + this.responseText = null; + this.responseXML = null; + this.status = null; + this.statusText = null; + this.readyState = 0; + + this._ifpServerUrl = ifpServerUrl; + this._stateId = null; +} + +dojo.extend(dojox.io.proxy.xip.XhrIframeFacade, { + //The open method does not properly reset since Dojo does not reuse XHR objects. + open: function(/*String*/method, /*String*/uri){ + this._method = method; + this._uri = uri; + + this.readyState = 1; + }, + + setRequestHeader: function(/*String*/header, /*String*/value){ + this._requestHeaders[header] = value; + }, + + send: function(/*String*/stringData){ + this._bodyData = stringData; + + this._stateId = dojox.io.proxy.xip.send(this); + + this.readyState = 2; + }, + abort: function(){ + dojox.io.proxy.xip.destroyState(this._stateId); + }, + + getAllResponseHeaders: function(){ + return this._allResponseHeaders; //String + }, + + getResponseHeader: function(/*String*/header){ + return this._responseHeaders[header]; //String + }, + + _setResponseHeaders: function(/*String*/allHeaders){ + if(allHeaders){ + this._allResponseHeaders = allHeaders; + + //Make sure ther are now CR characters in the headers. + allHeaders = allHeaders.replace(/\r/g, ""); + var nvPairs = allHeaders.split("\n"); + for(var i = 0; i < nvPairs.length; i++){ + if(nvPairs[i]){ + var nameValue = nvPairs[i].split(": "); + this._responseHeaders[nameValue[0]] = nameValue[1]; + } + } + } + } +}); + +} diff --git a/includes/js/dojox/io/proxy/xip_client.html b/includes/js/dojox/io/proxy/xip_client.html new file mode 100644 index 0000000..c51a839 --- /dev/null +++ b/includes/js/dojox/io/proxy/xip_client.html @@ -0,0 +1,102 @@ + + + + + + + + + + // + + + +

      The Dojo Toolkit -- xip_client.html

      + +

      This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the "client" file used + internally by dojox.io.proxy.xip.

      + + diff --git a/includes/js/dojox/io/proxy/xip_server.html b/includes/js/dojox/io/proxy/xip_server.html new file mode 100644 index 0000000..01b7274 --- /dev/null +++ b/includes/js/dojox/io/proxy/xip_server.html @@ -0,0 +1,382 @@ + + + + + + + + + + + // + + + +

      The Dojo Toolkit -- xip_server.html

      + +

      This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the the file + that should go on the server that will actually be doing the XHR request.

      +
      + + diff --git a/includes/js/dojox/io/xhrMultiPart.js b/includes/js/dojox/io/xhrMultiPart.js new file mode 100644 index 0000000..5792267 --- /dev/null +++ b/includes/js/dojox/io/xhrMultiPart.js @@ -0,0 +1,81 @@ +if(!dojo._hasResource["dojox.io.xhrMultiPart"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.io.xhrMultiPart"] = true; +dojo.provide("dojox.io.xhrMultiPart"); + +dojo.require("dojo._base.xhr"); +dojo.require("dojox.uuid.generateRandomUuid"); + +(function(){ + function _createPart(args, boundary){ + if(!args["name"] && !args["content"]){ + throw new Error("Each part of a multi-part request requires 'name' and 'content'."); + } + + var tmp = []; + tmp.push("--" + boundary, + "Content-Disposition: form-data; name=\"" + args.name + "\"" + + (args["filename"] ? "; filename=\"" + args.filename + "\"" : "")); + + if(args["contentType"]){ + var ct = "Content-Type: " + args.contentType; + if(args["charset"]){ + ct += "; Charset=" + args.charset; + } + tmp.push(ct); + } + + if(args["contentTransferEncoding"]){ + tmp.push("Content-Transfer-Encoding: " + args.contentTransferEncoding); + } + + tmp.push("", args.content); + + return tmp; + } + + function _needIframe(node){ + return (!!(dojo.query("input[type=file]", node).length)); + } + + function _partsFromNode(node, boundary){ + // TODO: write this function! + var tmp = []; + return tmp; + } + + dojox.io.xhrMultiPart = function(args){ + if(!args["file"] && !args["form"]){ + throw new Error("file or form must be provided to dojox.io.xhrMultiPart's arguments"); + } + + // unique guid as a boundary value for multipart posts + var boundary = dojox.uuid.generateRandomUuid(); + + var tmp = []; + var out = ""; + + if(args["file"]){ + var d = (dojo.isArray(args.file) ? args.file : [args.file]); + + for(var i=0; i < d.length; i++){ + tmp = tmp.concat(_createPart(d[i], boundary)); + } + } + + if(args["form"]){ + tmp = tmp.concat(_partsFromNode(args["form"], boundary)); + } + + if(tmp.length){ + tmp.push("--"+boundary+"--", ""); + out = tmp.join("\r\n"); + } + + return dojo.rawXhrPost(dojo.mixin(args, { + contentType: "multipart/form-data; boundary=" + boundary, + postData: out + })); + } +})(); + +} diff --git a/includes/js/dojox/jsonPath.js b/includes/js/dojox/jsonPath.js new file mode 100644 index 0000000..692e855 --- /dev/null +++ b/includes/js/dojox/jsonPath.js @@ -0,0 +1,6 @@ +if(!dojo._hasResource["dojox.jsonPath"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.jsonPath"] = true; +dojo.provide("dojox.jsonPath"); +dojo.require("dojox.jsonPath.query"); + +} diff --git a/includes/js/dojox/jsonPath/README b/includes/js/dojox/jsonPath/README new file mode 100644 index 0000000..2da2b31 --- /dev/null +++ b/includes/js/dojox/jsonPath/README @@ -0,0 +1,125 @@ +------------------------------------------------------------------------------- +dojox.jsonPath +------------------------------------------------------------------------------- +Version 1.0 +Release date: 11/14/2007 +------------------------------------------------------------------------------- +Project state: beta +------------------------------------------------------------------------------- +Project authors + Dustin Machi + Kris Zyp +------------------------------------------------------------------------------- +Project description + +jsonPath is a query system similar in idea to xpath, but for use against +javascript objects. This code is a port of the jsonPath code at +http://code.google.com/p/jsonpath/. It was contributed under CLA by Stefan +Goessner. Thanks Stefan! +------------------------------------------------------------------------------- +Dependencies: + +Dojo Core (package loader). +------------------------------------------------------------------------------- +Documentation + +Usage: + +var matches = dojox.jsonPath.query(objectToQuery, jsonPathExpresson) + +Expressions: + + $ The Root Object + @ The current object/element + . or [] The child operator + .. Recursive descent + * all objects + [] subscript operator + [,] Union operator + [start:end:step] array slice operator + ?() applies a filter/script expression + () script expresions + + some examples: + + Given the following test data set: + + var json = + { "store": { + "book": [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": { + "color": "red", + "price": 19.95 + } + } + }; + + Here are some example queries and their output: + + $.store.book[*].author + ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"] + + $..author + ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"] + + $.store.* + [[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],{"color":"red","price":19.95}] + + $.store..price + [8.95,12.99,8.99,22.99,19.95] + + $..book[(@.length-1)] + [{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}] + + $..book[-1] + [{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}] + + $..book[0,1] + [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}] + + $..book[:2] + [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}] + + $..book[?(@.isbn)] + [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}] + + $..book[?(@.price<10)] + [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}] + + $..* + [{"book":[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],"bicycle":{"color":"red","price":19.95}},[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],{"color":"red","price":19.95},{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99},"reference","Nigel Rees","Sayings of the Century",8.95,"fiction","Evelyn Waugh","Sword of Honour",12.99,"fiction","Herman Melville","Moby Dick","0-553-21311-3",8.99,"fiction","J. R. R. Tolkien","The Lord of the Rings","0-395-19395-8",22.99,"red",19.95] + + +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/jsonPath + +Install into the following directory structure: +/dojox/jsonPath/ + +...which should be at the same level as your Dojo checkout. diff --git a/includes/js/dojox/jsonPath/query.js b/includes/js/dojox/jsonPath/query.js new file mode 100644 index 0000000..4e24309 --- /dev/null +++ b/includes/js/dojox/jsonPath/query.js @@ -0,0 +1,163 @@ +if(!dojo._hasResource["dojox.jsonPath.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.jsonPath.query"] = true; +dojo.provide("dojox.jsonPath.query"); + +dojox.jsonPath.query = function(/*Object*/obj, /*String*/expr, /*Object*/arg){ + // summaRy + // Perform jsonPath query `expr` on javascript object or json string `obj` + // obj - object || json string to perform query on + // expr - jsonPath expression (string) to be evaluated + // arg - {}special arugments. + // resultType: "VALUE"||"BOTH"||"PATH"} (defaults to value) + // evalType: "RESULT"||"ITEM"} (defaults to ?) + + var re = dojox.jsonPath._regularExpressions; + if (!arg){arg={};} + + var strs = []; + function _str(i){ return strs[i];} + var acc; + if (arg.resultType == "PATH" && arg.evalType == "RESULT") throw Error("RESULT based evaluation not supported with PATH based results"); + var P = { + resultType: arg.resultType || "VALUE", + normalize: function(expr){ + var subx = []; + expr = expr.replace(/'([^']|'')*'/g, function(t){return "_str("+(strs.push(eval(t))-1)+")";}); + var ll = -1; + while(ll!=subx.length){ + ll=subx.length;//TODO: Do expression syntax checking + expr = expr.replace(/(\??\([^\(\)]*\))/g, function($0){return "#"+(subx.push($0)-1);}); + } + expr = expr.replace(/[\['](#[0-9]+)[\]']/g,'[$1]') + .replace(/'?\.'?|\['?/g, ";") + .replace(/;;;|;;/g, ";..;") + .replace(/;$|'?\]|'$/g, ""); + ll = -1; + while(ll!=expr){ + ll=expr; + expr = expr.replace(/#([0-9]+)/g, function($0,$1){return subx[$1];}); + } + return expr.split(";"); + }, + asPaths: function(paths){ + for (var j=0;j + + + Dojox Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/lang/LICENSE b/includes/js/dojox/lang/LICENSE new file mode 100644 index 0000000..d84a6aa --- /dev/null +++ b/includes/js/dojox/lang/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2007 Oliver Steele + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/includes/js/dojox/lang/README b/includes/js/dojox/lang/README new file mode 100644 index 0000000..753b943 --- /dev/null +++ b/includes/js/dojox/lang/README @@ -0,0 +1,37 @@ +------------------------------------------------------------------------------- +dojox.lang +------------------------------------------------------------------------------- +Version 0.991 +Release date: 07/30/2007 +------------------------------------------------------------------------------- +Project state: +[beta] +------------------------------------------------------------------------------- +Credits + Eugene Lazutkin (eugene.lazutkin@gmail.com) +------------------------------------------------------------------------------- +Project description + +Implementation of common functional operations, and provisions +Later we can add other JS language-related helpers. +------------------------------------------------------------------------------- +Dependencies: + +None. +------------------------------------------------------------------------------- +Documentation + +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/lang/* + +Install into the following directory structure: +/dojox/lang/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- +Additional Notes + +See tests and the source for more details. diff --git a/includes/js/dojox/lang/functional.js b/includes/js/dojox/lang/functional.js new file mode 100644 index 0000000..e75ad00 --- /dev/null +++ b/includes/js/dojox/lang/functional.js @@ -0,0 +1,9 @@ +if(!dojo._hasResource["dojox.lang.functional"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.functional"] = true; +dojo.provide("dojox.lang.functional"); + +dojo.require("dojox.lang.functional.lambda"); +dojo.require("dojox.lang.functional.array"); +dojo.require("dojox.lang.functional.object"); + +} diff --git a/includes/js/dojox/lang/functional/array.js b/includes/js/dojox/lang/functional/array.js new file mode 100644 index 0000000..45c2613 --- /dev/null +++ b/includes/js/dojox/lang/functional/array.js @@ -0,0 +1,113 @@ +if(!dojo._hasResource["dojox.lang.functional.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.functional.array"] = true; +dojo.provide("dojox.lang.functional.array"); + +dojo.require("dojox.lang.functional.lambda"); + +// This module adds high-level functions and related constructs: +// - array-processing functions similar to standard JS functions + +// Notes: +// - this module provides JS standard methods similar to high-level functions in dojo/_base/array.js: +// forEach, map, filter, every, some + +// Defined methods: +// - take any valid lambda argument as the functional argument +// - operate on dense arrays +// - take a string as the array argument +// - take an iterator objects as the array argument + +(function(){ + var d = dojo, df = dojox.lang.functional; + + d.mixin(df, { + // JS 1.6 standard array functions, which can take a lambda as a parameter. + // Consider using dojo._base.array functions, if you don't need the lambda support. + filter: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: creates a new array with all elements that pass the test + // implemented by the provided function. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var t = [], v; + if(d.isArray(a)){ + for(var i = 0, n = a.length; i < n; ++i){ + v = a[i]; + if(f.call(o, v, i, a)){ t.push(v); } + } + }else{ + for(var i = 0; a.hasNext();){ + v = a.next(); + if(f.call(o, v, i++)){ t.push(v); } + } + } + return t; // Array + }, + forEach: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: executes a provided function once per array element. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + if(d.isArray(a)){ + for(var i = 0, n = a.length; i < n; f.call(o, a[i], i, a), ++i); + }else{ + for(var i = 0; a.hasNext(); f.call(o, a.next(), i++)); + } + }, + map: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: creates a new array with the results of calling + // a provided function on every element in this array. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var t, n; + if(d.isArray(a)){ + t = new Array(n = a.length); + for(var i = 0; i < n; t[i] = f.call(o, a[i], i, a), ++i); + }else{ + t = []; + for(var i = 0; a.hasNext(); t.push(f.call(o, a.next(), i++))); + } + return t; // Array + }, + every: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: tests whether all elements in the array pass the test + // implemented by the provided function. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + if(d.isArray(a)){ + for(var i = 0, n = a.length; i < n; ++i){ + if(!f.call(o, a[i], i, a)){ + return false; // Boolean + } + } + }else{ + for(var i = 0; a.hasNext();){ + if(!f.call(o, a.next(), i++)){ + return false; // Boolean + } + } + } + return true; // Boolean + }, + some: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: tests whether some element in the array passes the test + // implemented by the provided function. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + if(d.isArray(a)){ + for(var i = 0, n = a.length; i < n; ++i){ + if(f.call(o, a[i], i, a)){ + return true; // Boolean + } + } + }else{ + for(var i = 0; a.hasNext();){ + if(f.call(o, a.next(), i++)){ + return true; // Boolean + } + } + } + return false; // Boolean + } + }); +})(); + +} diff --git a/includes/js/dojox/lang/functional/curry.js b/includes/js/dojox/lang/functional/curry.js new file mode 100644 index 0000000..7c795ec --- /dev/null +++ b/includes/js/dojox/lang/functional/curry.js @@ -0,0 +1,96 @@ +if(!dojo._hasResource["dojox.lang.functional.curry"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.functional.curry"] = true; +dojo.provide("dojox.lang.functional.curry"); + +dojo.require("dojox.lang.functional.lambda"); + +// This module adds high-level functions and related constructs: +// - currying and partial functions +// - argument pre-processing: mixer and flip + +// Acknoledgements: +// - partial() is based on work by Oliver Steele +// (http://osteele.com/sources/javascript/functional/functional.js) +// which was published under MIT License + +// Defined methods: +// - take any valid lambda argument as the functional argument + +(function(){ + var df = dojox.lang.functional; + + var currying = function(/*Object*/ info){ + return function(){ // Function + if(arguments.length + info.args.length < info.arity){ + return currying({func: info.func, arity: info.arity, + args: Array.prototype.concat.apply(info.args, arguments)}); + } + return info.func.apply(this, Array.prototype.concat.apply(info.args, arguments)); + }; + }; + + dojo.mixin(df, { + // currying and partial functions + curry: function(/*Function|String|Array*/ f, /*Number?*/ arity){ + // summary: curries a function until the arity is satisfied, at + // which point it returns the calculated value. + f = df.lambda(f); + arity = typeof arity == "number" ? arity : f.length; + return currying({func: f, arity: arity, args: []}); // Function + }, + arg: {}, // marker for missing arguments + partial: function(/*Function|String|Array*/ f){ + // summary: creates a function where some arguments are bound, and + // some arguments (marked as dojox.lang.functional.arg) are will be + // accepted by the final function in the order they are encountered. + // description: This method is used to produce partially bound + // functions. If you want to change the order of arguments, use + // dojox.lang.functional.mixer() or dojox.lang.functional.flip(). + var a = arguments, args = new Array(a.length - 1), p = []; + f = df.lambda(f); + for(var i = 1; i < a.length; ++i){ + var t = a[i]; + args[i - 1] = t; + if(t == df.arg){ + p.push(i - 1); + } + } + return function(){ // Function + var t = Array.prototype.slice.call(args, 0); // clone the array + for(var i = 0; i < p.length; ++i){ + t[p[i]] = arguments[i]; + } + return f.apply(this, t); + }; + }, + // argument pre-processing + mixer: function(/*Function|String|Array*/ f, /*Array*/ mix){ + // summary: changes the order of arguments using an array of + // numbers mix --- i-th argument comes from mix[i]-th place + // of supplied arguments. + f = df.lambda(f); + return function(){ // Function + var t = new Array(mix.length); + for(var i = 0; i < mix.length; ++i){ + t[i] = arguments[mix[i]]; + } + return f.apply(this, t); + }; + }, + flip: function(/*Function|String|Array*/ f){ + // summary: changes the order of arguments by reversing their + // order. + f = df.lambda(f); + return function(){ // Function + // reverse arguments + var a = arguments, l = a.length - 1, t = new Array(l + 1), i; + for(i = 0; i <= l; ++i){ + t[l - i] = a[i]; + } + return f.apply(this, t); + }; + } + }); +})(); + +} diff --git a/includes/js/dojox/lang/functional/fold.js b/includes/js/dojox/lang/functional/fold.js new file mode 100644 index 0000000..90a9a3d --- /dev/null +++ b/includes/js/dojox/lang/functional/fold.js @@ -0,0 +1,87 @@ +if(!dojo._hasResource["dojox.lang.functional.fold"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.functional.fold"] = true; +dojo.provide("dojox.lang.functional.fold"); + +dojo.require("dojox.lang.functional.lambda"); + +// This module adds high-level functions and related constructs: +// - "fold" family of functions + +// Notes: +// - missing high-level functions are provided with the compatible API: +// foldl, foldl1, foldr, foldr1 +// - missing JS standard functions are provided with the compatible API: +// reduce, reduceRight + +// Defined methods: +// - take any valid lambda argument as the functional argument +// - operate on dense arrays +// - take a string as the array argument +// - take an iterator objects as the array argument (only foldl, foldl1, and reduce) + +(function(){ + var d = dojo, df = dojox.lang.functional; + + d.mixin(df, { + // classic reduce-class functions + foldl: function(/*Array|String|Object*/ a, /*Function*/ f, /*Object*/ z, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from left + // to right using a seed value as a starting point; returns the final + // value. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + if(d.isArray(a)){ + for(var i = 0, n = a.length; i < n; z = f.call(o, z, a[i], i, a), ++i); + }else{ + for(var i = 0; a.hasNext(); z = f.call(o, z, a.next(), i++)); + } + return z; // Object + }, + foldl1: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from left + // to right; returns the final value. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var z; + if(d.isArray(a)){ + z = a[0]; + for(var i = 1, n = a.length; i < n; z = f.call(o, z, a[i], i, a), ++i); + }else if(a.hasNext()){ + z = a.next(); + for(var i = 1; a.hasNext(); z = f.call(o, z, a.next(), i++)); + } + return z; // Object + }, + foldr: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from right + // to left using a seed value as a starting point; returns the final + // value. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + for(var i = a.length; i > 0; --i, z = f.call(o, z, a[i], i, a)); + return z; // Object + }, + foldr1: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from right + // to left; returns the final value. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var n = a.length, z = a[n - 1]; + for(var i = n - 1; i > 0; --i, z = f.call(o, z, a[i], i, a)); + return z; // Object + }, + // JS 1.8 standard array functions, which can take a lambda as a parameter. + reduce: function(/*Array|String|Object*/ a, /*Function*/ f, /*Object?*/ z){ + // summary: apply a function simultaneously against two values of the array + // (from left-to-right) as to reduce it to a single value. + return arguments.length < 3 ? df.foldl1(a, f) : df.foldl(a, f, z); // Object + }, + reduceRight: function(/*Array|String*/ a, /*Function*/ f, /*Object?*/ z){ + // summary: apply a function simultaneously against two values of the array + // (from right-to-left) as to reduce it to a single value. + return arguments.length < 3 ? df.foldr1(a, f) : df.foldr(a, f, z); // Object + } + }); +})(); + +} diff --git a/includes/js/dojox/lang/functional/lambda.js b/includes/js/dojox/lang/functional/lambda.js new file mode 100644 index 0000000..60be9f3 --- /dev/null +++ b/includes/js/dojox/lang/functional/lambda.js @@ -0,0 +1,110 @@ +if(!dojo._hasResource["dojox.lang.functional.lambda"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.functional.lambda"] = true; +dojo.provide("dojox.lang.functional.lambda"); + +// This module adds high-level functions and related constructs: +// - anonymous functions built from the string + +// Acknoledgements: +// - lambda() is based on work by Oliver Steele +// (http://osteele.com/sources/javascript/functional/functional.js) +// which was published under MIT License + +// Notes: +// - lambda() produces functions, which after the compilation step are +// as fast as regular JS functions (at least theoretically). + +// Lambda input values: +// - returns functions unchanged +// - converts strings to functions +// - converts arrays to a functional composition + +(function(){ + var df = dojox.lang.functional; + + // split() is augmented on IE6 to ensure the uniform behavior + var split = "ab".split(/a*/).length > 1 ? String.prototype.split : + function(sep){ + var r = this.split.call(this, sep), + m = sep.exec(this); + if(m && m.index == 0){ r.unshift(""); } + return r; + }; + + var lambda = function(/*String*/ s){ + var args = [], sects = split.call(s, /\s*->\s*/m); + if(sects.length > 1){ + while(sects.length){ + s = sects.pop(); + args = sects.pop().split(/\s*,\s*|\s+/m); + if(sects.length){ sects.push("(function(" + args + "){return (" + s + ")})"); } + } + }else if(s.match(/\b_\b/)){ + args = ["_"]; + }else{ + var l = s.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m), + r = s.match(/[+\-*\/%&|\^\.=<>!]\s*$/m); + if(l || r){ + if(l){ + args.push("$1"); + s = "$1" + s; + } + if(r){ + args.push("$2"); + s = s + "$2"; + } + }else{ + // the point of the long regex below is to exclude all well-known + // lower-case words from the list of potential arguments + var vars = s. + replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*:|this|true|false|null|undefined|typeof|instanceof|in|delete|new|void|arguments|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|escape|eval|isFinite|isNaN|parseFloat|parseInt|unescape|dojo|dijit|dojox|window|document|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g, ""). + match(/([a-z_$][a-z_$\d]*)/gi) || []; + var t = {}; + dojo.forEach(vars, function(v){ + if(!(v in t)){ + args.push(v); + t[v] = 1; + } + }); + } + } + return {args: args, body: "return (" + s + ");"}; // Object + }; + + var compose = function(/*Array*/ a){ + return a.length ? + function(){ + var i = a.length - 1, x = df.lambda(a[i]).apply(this, arguments); + for(--i; i >= 0; --i){ x = df.lambda(a[i]).call(this, x); } + return x; + } + : + // identity + function(x){ return x; }; + }; + + dojo.mixin(df, { + // lambda + buildLambda: function(/*String*/ s){ + // summary: builds a function from a snippet, returns a string, + // which represents the function. + // description: This method returns a textual representation of a function + // built from the snippet. It is meant to be evaled in the proper context, + // so local variables can be pulled from the environment. + s = lambda(s); + return "function(" + s.args.join(",") + "){" + s.body + "}"; // String + }, + lambda: function(/*Function|String|Array*/ s){ + // summary: builds a function from a snippet, or array (composing), returns + // a function object; functions are passed through unmodified. + // description: This method is used to normalize a functional representation + // (a text snippet, an array, or a function) to a function object. + if(typeof s == "function"){ return s; } + if(s instanceof Array){ return compose(s); } + s = lambda(s); + return new Function(s.args, s.body); // Function + } + }); +})(); + +} diff --git a/includes/js/dojox/lang/functional/listcomp.js b/includes/js/dojox/lang/functional/listcomp.js new file mode 100644 index 0000000..adb4883 --- /dev/null +++ b/includes/js/dojox/lang/functional/listcomp.js @@ -0,0 +1,54 @@ +if(!dojo._hasResource["dojox.lang.functional.listcomp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.functional.listcomp"] = true; +dojo.provide("dojox.lang.functional.listcomp"); + +// This module adds high-level functions and related constructs: +// - list comprehensions similar to JavaScript 1.7 + +// Notes: +// - listcomp() produces functions, which after the compilation step are +// as fast as regular JS functions (at least theoretically). + +(function(){ + var g_re = /\bfor\b|\bif\b/gm; + + var listcomp = function(/*String*/ s){ + var frag = s.split(g_re), act = s.match(g_re), + head = ["var r = [];"], tail = []; + for(var i = 0; i < act.length;){ + var a = act[i], f = frag[++i]; + if(a == "for" && !/^\s*\(\s*(;|var)/.test(f)){ + f = f.replace(/^\s*\(/, "(var "); + } + head.push(a, f, "{"); + tail.push("}"); + } + return head.join("") + "r.push(" + frag[0] + ");" + tail.join("") + "return r;"; // String + }; + + dojo.mixin(dojox.lang.functional, { + buildListcomp: function(/*String*/ s){ + // summary: builds a function from a text snippet, which represents a valid + // JS 1.7 list comprehension, returns a string, which represents the function. + // description: This method returns a textual representation of a function + // built from the list comprehension text snippet (conformant to JS 1.7). + // It is meant to be evaled in the proper context, so local variable can be + // pulled from the environment. + return "function(){" + listcomp(s) + "}"; // String + }, + compileListcomp: function(/*String*/ s){ + // summary: builds a function from a text snippet, which represents a valid + // JS 1.7 list comprehension, returns a function object. + // description: This method returns a function built from the list + // comprehension text snippet (conformant to JS 1.7). It is meant to be + // reused several times. + return new Function([], listcomp(s)); // Function + }, + listcomp: function(/*String*/ s){ + // summary: executes the list comprehension building an array. + return (new Function([], listcomp(s)))(); // Array + } + }); +})(); + +} diff --git a/includes/js/dojox/lang/functional/object.js b/includes/js/dojox/lang/functional/object.js new file mode 100644 index 0000000..52b6272 --- /dev/null +++ b/includes/js/dojox/lang/functional/object.js @@ -0,0 +1,48 @@ +if(!dojo._hasResource["dojox.lang.functional.object"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.functional.object"] = true; +dojo.provide("dojox.lang.functional.object"); + +dojo.require("dojox.lang.functional.lambda"); + +// This module adds high-level functions and related constructs: +// - object/dictionary helpers + +// Defined methods: +// - take any valid lambda argument as the functional argument + +(function(){ + var d = dojo, df = dojox.lang.functional, empty = {}; + + d.mixin(df, { + // object helpers + forIn: function(/*Object*/ obj, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: iterates over all object members skipping members, which + // are present in the empty object (IE and/or 3rd-party libraries). + o = o || d.global; f = df.lambda(f); + for(var i in obj){ + if(i in empty){ continue; } + f.call(o, obj[i], i, obj); + } + }, + keys: function(/*Object*/ obj){ + // summary: returns an array of all keys in the object + var t = []; + for(var i in obj){ + if(i in empty){ continue; } + t.push(i); + } + return t; // Array + }, + values: function(/*Object*/ obj){ + // summary: returns an array of all values in the object + var t = []; + for(var i in obj){ + if(i in empty){ continue; } + t.push(obj[i]); + } + return t; // Array + } + }); +})(); + +} diff --git a/includes/js/dojox/lang/functional/reversed.js b/includes/js/dojox/lang/functional/reversed.js new file mode 100644 index 0000000..4375948 --- /dev/null +++ b/includes/js/dojox/lang/functional/reversed.js @@ -0,0 +1,79 @@ +if(!dojo._hasResource["dojox.lang.functional.reversed"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.functional.reversed"] = true; +dojo.provide("dojox.lang.functional.reversed"); + +dojo.require("dojox.lang.functional.lambda"); + +// This module adds high-level functions and related constructs: +// - reversed versions of array-processing functions similar to standard JS functions + +// Notes: +// - this module provides reversed versions of standard array-processing functions: +// forEachRev, mapRev, filterRev + +// Defined methods: +// - take any valid lambda argument as the functional argument +// - operate on dense arrays +// - take a string as the array argument + +(function(){ + var d = dojo, df = dojox.lang.functional; + + d.mixin(df, { + // JS 1.6 standard array functions, which can take a lambda as a parameter. + // Consider using dojo._base.array functions, if you don't need the lambda support. + filterRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: creates a new array with all elements that pass the test + // implemented by the provided function. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var t = [], v; + for(var i = a.length - 1; i >= 0; --i){ + v = a[i]; + if(f.call(o, v, i, a)){ t.push(v); } + } + return t; // Array + }, + forEachRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: executes a provided function once per array element. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + for(var i = a.length - 1; i >= 0; f.call(o, a[i], i, a), --i); + }, + mapRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: creates a new array with the results of calling + // a provided function on every element in this array. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var n = a.length, t = new Array(n); + for(var i = n - 1, j = 0; i >= 0; t[j++] = f.call(o, a[i], i, a), --i); + return t; // Array + }, + everyRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: tests whether all elements in the array pass the test + // implemented by the provided function. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + for(var i = a.length - 1; i >= 0; --i){ + if(!f.call(o, a[i], i, a)){ + return false; // Boolean + } + } + return true; // Boolean + }, + someRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: tests whether some element in the array passes the test + // implemented by the provided function. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + for(var i = a.length - 1; i >= 0; --i){ + if(f.call(o, a[i], i, a)){ + return true; // Boolean + } + } + return false; // Boolean + } + }); +})(); + +} diff --git a/includes/js/dojox/lang/functional/scan.js b/includes/js/dojox/lang/functional/scan.js new file mode 100644 index 0000000..65a3ef2 --- /dev/null +++ b/includes/js/dojox/lang/functional/scan.js @@ -0,0 +1,84 @@ +if(!dojo._hasResource["dojox.lang.functional.scan"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.functional.scan"] = true; +dojo.provide("dojox.lang.functional.scan"); + +dojo.require("dojox.lang.functional.lambda"); + +// This module adds high-level functions and related constructs: +// - "scan" family of functions + +// Notes: +// - missing high-level functions are provided with the compatible API: +// scanl, scanl1, scanr, scanr1 + +// Defined methods: +// - take any valid lambda argument as the functional argument +// - operate on dense arrays +// - take a string as the array argument +// - take an iterator objects as the array argument (only scanl, and scanl1) + +(function(){ + var d = dojo, df = dojox.lang.functional; + + d.mixin(df, { + // classic reduce-class functions + scanl: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from left + // to right using a seed value as a starting point; returns an array + // of values produced by foldl() at that point. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var t, n; + if(d.isArray(a)){ + t = new Array((n = a.length) + 1); + t[0] = z; + for(var i = 0; i < n; z = f.call(o, z, a[i], i, a), t[++i] = z); + }else{ + t = [z]; + for(var i = 0; a.hasNext(); t.push(z = f.call(o, z, a.next(), i++))); + } + return t; // Array + }, + scanl1: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from left + // to right; returns an array of values produced by foldl1() at that + // point. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var t, n, z; + if(d.isArray(a)){ + t = new Array(n = a.length); + t[0] = z = a[0]; + for(var i = 1; i < n; t[i] = z = f.call(o, z, a[i], i, a), ++i); + }else if(a.hasNext()){ + t = [z = a.next()]; + for(var i = 1; a.hasNext(); t.push(z = f.call(o, z, a.next(), i++))); + } + return t; // Array + }, + scanr: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from right + // to left using a seed value as a starting point; returns an array + // of values produced by foldr() at that point. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var n = a.length, t = new Array(n + 1); + t[n] = z; + for(var i = n; i > 0; --i, z = f.call(o, z, a[i], i, a), t[i] = z); + return t; // Array + }, + scanr1: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from right + // to left; returns an array of values produced by foldr1() at that + // point. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var n = a.length, t = new Array(n), z = a[n - 1]; + t[n - 1] = z; + for(var i = n - 1; i > 0; --i, z = f.call(o, z, a[i], i, a), t[i] = z); + return t; // Array + } + }); +})(); + +} diff --git a/includes/js/dojox/lang/functional/sequence.js b/includes/js/dojox/lang/functional/sequence.js new file mode 100644 index 0000000..c5aaa1c --- /dev/null +++ b/includes/js/dojox/lang/functional/sequence.js @@ -0,0 +1,38 @@ +if(!dojo._hasResource["dojox.lang.functional.sequence"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.functional.sequence"] = true; +dojo.provide("dojox.lang.functional.sequence"); + +dojo.require("dojox.lang.functional.lambda"); + +// This module adds high-level functions and related constructs: +// - sequence generators + +// Defined methods: +// - take any valid lambda argument as the functional argument + +(function(){ + var d = dojo, df = dojox.lang.functional; + + d.mixin(df, { + // sequence generators + repeat: function(/*Number*/ n, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ + // summary: builds an array by repeatedly applying a unary function N times + // with a seed value Z. + o = o || d.global; f = df.lambda(f); + var t = new Array(n); + t[0] = z; + for(var i = 1; i < n; t[i] = z = f.call(o, z), ++i); + return t; // Array + }, + until: function(/*Function|String|Array*/ pr, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ + // summary: builds an array by repeatedly applying a unary function with + // a seed value Z until the predicate is satisfied. + o = o || d.global; f = df.lambda(f); pr = df.lambda(pr); + var t = []; + for(; !pr.call(o, z); t.push(z), z = f.call(o, z)); + return t; // Array + } + }); +})(); + +} diff --git a/includes/js/dojox/lang/functional/zip.js b/includes/js/dojox/lang/functional/zip.js new file mode 100644 index 0000000..523f400 --- /dev/null +++ b/includes/js/dojox/lang/functional/zip.js @@ -0,0 +1,45 @@ +if(!dojo._hasResource["dojox.lang.functional.zip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.functional.zip"] = true; +dojo.provide("dojox.lang.functional.zip"); + +// This module adds high-level functions and related constructs: +// - zip combiners + +// Defined methods: +// - operate on dense arrays + +(function(){ + var df = dojox.lang.functional; + + dojo.mixin(df, { + // combiners + zip: function(){ + // summary: returns an array of arrays, where the i-th array + // contains the i-th element from each of the argument arrays. + // description: This is the venerable zip combiner (for example, + // see Python documentation for general details). The returned + // array is truncated to match the length of the shortest input + // array. + var n = arguments[0].length, m = arguments.length, i; + for(i = 1; i < m; n = Math.min(n, arguments[i++].length)); + var t = new Array(n), j; + for(i = 0; i < n; ++i){ + var p = new Array(m); + for(j = 0; j < m; p[j] = arguments[j][i], ++j); + t[i] = p; + } + return t; // Array + }, + unzip: function(/*Array*/ a){ + // summary: similar to dojox.lang.functional.zip(), but takes + // a single array of arrays as the input. + // description: This function is similar to dojox.lang.functional.zip() + // and can be used to unzip objects packed by + // dojox.lang.functional.zip(). It is here mostly to provide + // a short-cut for the different method signature. + return df.zip.apply(null, a); // Array + } + }); +})(); + +} diff --git a/includes/js/dojox/lang/tests/array.js b/includes/js/dojox/lang/tests/array.js new file mode 100644 index 0000000..292210c --- /dev/null +++ b/includes/js/dojox/lang/tests/array.js @@ -0,0 +1,84 @@ +if(!dojo._hasResource["dojox.lang.tests.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.tests.array"] = true; +dojo.provide("dojox.lang.tests.array"); + +dojo.require("dojox.lang.functional"); +dojo.require("dojox.lang.functional.fold"); +dojo.require("dojox.lang.functional.reversed"); + +(function(){ + var df = dojox.lang.functional, v, isOdd = "%2"; + + var revArrayIter = function(array){ + this.array = array; + this.position = array.length - 1; + }; + dojo.extend(revArrayIter, { + hasNext: df.lambda("this.position >= 0"), + next: df.lambda("this.array[this.position--]") + }); + + tests.register("dojox.lang.tests.array", [ + function testFilter1(t){ t.assertEqual(df.filter([1, 2, 3], isOdd), [1, 3]); }, + function testFilter2(t){ t.assertEqual(df.filter([1, 2, 3], "%2==0"), [2]); }, + function testFilterIter(t){ + var iter = new revArrayIter([1, 2, 3]); + t.assertEqual(df.filter(iter, isOdd), [3, 1]); + }, + function testFilterRev(t){ + var iter = new revArrayIter([1, 2, 3]); + t.assertEqual(df.filter(iter, isOdd), df.filterRev([1, 2, 3], isOdd)); + }, + + function testForEach(t){ + t.assertEqual((v = [], df.forEach([1, 2, 3], function(x){ v.push(x); }), v), [1, 2, 3]); + }, + function testForEachIter(t){ + var iter = new revArrayIter([1, 2, 3]); + t.assertEqual((v = [], df.forEach(iter, function(x){ v.push(x); }), v), [3, 2, 1]); + }, + function testForEachRev(t){ + t.assertEqual((v = [], df.forEachRev([1, 2, 3], function(x){ v.push(x); }), v), [3, 2, 1]); + }, + + function testMap(t){ t.assertEqual(df.map([1, 2, 3], "+3"), [4, 5, 6]); }, + function testMapIter(t){ + var iter = new revArrayIter([1, 2, 3]); + t.assertEqual(df.map(iter, "+3"), [6, 5, 4]); + }, + function testMapRev(t){ + var iter = new revArrayIter([1, 2, 3]); + t.assertEqual(df.map(iter, "+3"), df.mapRev([1, 2, 3], "+3")); + }, + + function testEvery1(t){ t.assertFalse(df.every([1, 2, 3], isOdd)); }, + function testEvery2(t){ t.assertTrue(df.every([1, 3, 5], isOdd)); }, + function testEveryIter(t){ + var iter = new revArrayIter([1, 3, 5]); + t.assertTrue(df.every(iter, isOdd)); + }, + function testEveryRev1(t){ t.assertFalse(df.everyRev([1, 2, 3], isOdd)); }, + function testEveryRev2(t){ t.assertTrue(df.everyRev([1, 3, 5], isOdd)); }, + + function testSome1(t){ t.assertFalse(df.some([2, 4, 6], isOdd)); }, + function testSome2(t){ t.assertTrue(df.some([1, 2, 3], isOdd)); }, + function testSomeIter(t){ + var iter = new revArrayIter([1, 2, 3]); + t.assertTrue(df.some(iter, isOdd)); + }, + function testSomeRev1(t){ t.assertFalse(df.someRev([2, 4, 6], isOdd)); }, + function testSomeRev2(t){ t.assertTrue(df.someRev([1, 2, 3], isOdd)); }, + + function testReduce1(t){ t.assertEqual(df.reduce([4, 2, 1], "x-y"), 1); }, + function testReduce2(t){ t.assertEqual(df.reduce([4, 2, 1], "x-y", 8), 1); }, + function testReduceIter(t){ + var iter = new revArrayIter([1, 2, 4]); + t.assertEqual(df.reduce(iter, "x-y"), 1); + }, + + function testReduceRight1(t){ t.assertEqual(df.reduceRight([4, 2, 1], "x-y"), -5); }, + function testReduceRight2(t){ t.assertEqual(df.reduceRight([4, 2, 1], "x-y", 8), 1); } + ]); +})(); + +} diff --git a/includes/js/dojox/lang/tests/curry.js b/includes/js/dojox/lang/tests/curry.js new file mode 100644 index 0000000..cb6fa6a --- /dev/null +++ b/includes/js/dojox/lang/tests/curry.js @@ -0,0 +1,31 @@ +if(!dojo._hasResource["dojox.lang.tests.curry"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.tests.curry"] = true; +dojo.provide("dojox.lang.tests.curry"); + +dojo.require("dojox.lang.functional.curry"); + +(function(){ + var df = dojox.lang.functional, add5 = df.curry("+")(5), sub3 = df.curry("_-3"), fun = df.lambda("100*a + 10*b + c"); + tests.register("dojox.lang.tests.curry", [ + function testCurry1(t){ t.assertEqual(df.curry("+")(1, 2), 3); }, + function testCurry2(t){ t.assertEqual(df.curry("+")(1)(2), 3); }, + function testCurry3(t){ t.assertEqual(df.curry("+")(1, 2, 3), 3); }, + function testCurry4(t){ t.assertEqual(add5(1), 6); }, + function testCurry5(t){ t.assertEqual(add5(3), 8); }, + function testCurry6(t){ t.assertEqual(add5(5), 10); }, + function testCurry7(t){ t.assertEqual(sub3(1), -2); }, + function testCurry8(t){ t.assertEqual(sub3(3), 0); }, + function testCurry9(t){ t.assertEqual(sub3(5), 2); }, + + function testPartial1(t){ t.assertEqual(df.partial(fun, 1, 2, 3)(), 123); }, + function testPartial2(t){ t.assertEqual(df.partial(fun, 1, 2, df.arg)(3), 123); }, + function testPartial3(t){ t.assertEqual(df.partial(fun, 1, df.arg, 3)(2), 123); }, + function testPartial4(t){ t.assertEqual(df.partial(fun, 1, df.arg, df.arg)(2, 3), 123); }, + function testPartial5(t){ t.assertEqual(df.partial(fun, df.arg, 2, 3)(1), 123); }, + function testPartial6(t){ t.assertEqual(df.partial(fun, df.arg, 2, df.arg)(1, 3), 123); }, + function testPartial7(t){ t.assertEqual(df.partial(fun, df.arg, df.arg, 3)(1, 2), 123); }, + function testPartial8(t){ t.assertEqual(df.partial(fun, df.arg, df.arg, df.arg)(1, 2, 3), 123); } + ]); +})(); + +} diff --git a/includes/js/dojox/lang/tests/fold.js b/includes/js/dojox/lang/tests/fold.js new file mode 100644 index 0000000..e766c62 --- /dev/null +++ b/includes/js/dojox/lang/tests/fold.js @@ -0,0 +1,64 @@ +if(!dojo._hasResource["dojox.lang.tests.fold"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.tests.fold"] = true; +dojo.provide("dojox.lang.tests.fold"); + +dojo.require("dojox.lang.functional.fold"); +dojo.require("dojox.lang.functional.scan"); +dojo.require("dojox.lang.functional.curry"); + +(function(){ + var df = dojox.lang.functional, a = df.arg; + + var revArrayIter = function(array){ + this.array = array; + this.position = array.length - 1; + }; + dojo.extend(revArrayIter, { + hasNext: df.lambda("this.position >= 0"), + next: df.lambda("this.array[this.position--]") + }); + + tests.register("dojox.lang.tests.fold", [ + function testFoldl1(t){ t.assertEqual(df.foldl([1, 2, 3], "+", 0), 6); }, + function testFoldl2(t){ t.assertEqual(df.foldl1([1, 2, 3], "*"), 6); }, + function testFoldl3(t){ t.assertEqual(df.foldl1([1, 2, 3], "/"), 1/6); }, + function testFoldl4(t){ t.assertEqual(df.foldl1([1, 2, 3], df.partial(Math.max, a, a)), 3); }, + function testFoldl5(t){ t.assertEqual(df.foldl1([1, 2, 3], df.partial(Math.min, a, a)), 1); }, + + function testFoldlIter(t){ + var iter = new revArrayIter([1, 2, 3]); + t.assertEqual(df.foldl(iter, "+", 0), 6); + }, + function testFoldl1Iter(t){ + var iter = new revArrayIter([1, 2, 3]); + t.assertEqual(df.foldl1(iter, "/"), 3/2); + }, + + function testFoldr1(t){ t.assertEqual(df.foldr([1, 2, 3], "+", 0), 6); }, + function testFoldr2(t){ t.assertEqual(df.foldr1([1, 2, 3], "*"), 6); }, + function testFoldr3(t){ t.assertEqual(df.foldr1([1, 2, 3], "/"), 3/2); }, + function testFoldr4(t){ t.assertEqual(df.foldr1([1, 2, 3], df.partial(Math.max, a, a)), 3); }, + function testFoldr5(t){ t.assertEqual(df.foldr1([1, 2, 3], df.partial(Math.min, a, a)), 1); }, + + function testScanl1(t){ t.assertEqual(df.scanl([1, 2, 3], "+", 0), [0, 1, 3, 6]); }, + function testScanl2(t){ t.assertEqual(df.scanl1([1, 2, 3], "*"), [1, 2, 6]); }, + function testScanl3(t){ t.assertEqual(df.scanl1([1, 2, 3], df.partial(Math.max, a, a)), [1, 2, 3]); }, + function testScanl4(t){ t.assertEqual(df.scanl1([1, 2, 3], df.partial(Math.min, a, a)), [1, 1, 1]); }, + + function testScanlIter(t){ + var iter = new revArrayIter([1, 2, 3]); + t.assertEqual(df.scanl(iter, "+", 0), [0, 3, 5, 6]); + }, + function testScanl1Iter(t){ + var iter = new revArrayIter([1, 2, 3]); + t.assertEqual(df.scanl1(iter, "*"), [3, 6, 6]); + }, + + function testScanr1(t){ t.assertEqual(df.scanr([1, 2, 3], "+", 0), [6, 5, 3, 0]); }, + function testScanr2(t){ t.assertEqual(df.scanr1([1, 2, 3], "*"), [6, 6, 3]); }, + function testScanr3(t){ t.assertEqual(df.scanr1([1, 2, 3], df.partial(Math.max, a, a)), [3, 3, 3]); }, + function testScanr4(t){ t.assertEqual(df.scanr1([1, 2, 3], df.partial(Math.min, a, a)), [1, 2, 3]); } + ]); +})(); + +} diff --git a/includes/js/dojox/lang/tests/fun_perf.html b/includes/js/dojox/lang/tests/fun_perf.html new file mode 100644 index 0000000..9d19a60 --- /dev/null +++ b/includes/js/dojox/lang/tests/fun_perf.html @@ -0,0 +1,176 @@ + + + clocking fun + + + + + + + + +

      This test is meant to run with Firebug.

      + + diff --git a/includes/js/dojox/lang/tests/lambda.js b/includes/js/dojox/lang/tests/lambda.js new file mode 100644 index 0000000..7e5e7ed --- /dev/null +++ b/includes/js/dojox/lang/tests/lambda.js @@ -0,0 +1,24 @@ +if(!dojo._hasResource["dojox.lang.tests.lambda"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.tests.lambda"] = true; +dojo.provide("dojox.lang.tests.lambda"); + +dojo.require("dojox.lang.functional"); +dojo.require("dojox.lang.functional.sequence"); + +(function(){ + var df = dojox.lang.functional; + tests.register("dojox.lang.tests.lambda", [ + function testLambda1(t){ t.assertEqual(df.repeat(3, "3*", 1), [1, 3, 9]); }, + function testLambda2(t){ t.assertEqual(df.repeat(3, "*3", 1), [1, 3, 9]); }, + function testLambda3(t){ t.assertEqual(df.repeat(3, "_*3", 1), [1, 3, 9]); }, + function testLambda4(t){ t.assertEqual(df.repeat(3, "3*_", 1), [1, 3, 9]); }, + function testLambda5(t){ t.assertEqual(df.repeat(3, "n->n*3", 1), [1, 3, 9]); }, + function testLambda6(t){ t.assertEqual(df.repeat(3, "n*3", 1), [1, 3, 9]); }, + function testLambda7(t){ t.assertEqual(df.repeat(3, "3*m", 1), [1, 3, 9]); }, + function testLambda8(t){ t.assertEqual(df.repeat(3, "->1", 1), [1, 1, 1]); }, + function testLambda9(t){ t.assertEqual(df.repeat(3, function(n){ return n * 3; }, 1), [1, 3, 9]); }, + function testLambda10(t){ t.assertEqual(df.repeat(3, ["_-1", ["*3"]], 1), [1, 2, 5]); } + ]); +})(); + +} diff --git a/includes/js/dojox/lang/tests/listcomp.js b/includes/js/dojox/lang/tests/listcomp.js new file mode 100644 index 0000000..45cd8ab --- /dev/null +++ b/includes/js/dojox/lang/tests/listcomp.js @@ -0,0 +1,28 @@ +if(!dojo._hasResource["dojox.lang.tests.listcomp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.tests.listcomp"] = true; +dojo.provide("dojox.lang.tests.listcomp"); + +dojo.require("dojox.lang.functional.listcomp"); +dojo.require("dojox.lang.functional.sequence"); + +(function(){ + var df = dojox.lang.functional; + tests.register("dojox.lang.tests.listcomp", [ + function testIterator1(t){ t.assertEqual(df.repeat(3, function(n){ return n + 1; }, 0), [0, 1, 2]); }, + function testIterator2(t){ t.assertEqual(df.repeat(3, function(n){ return n * 3; }, 1), [1, 3, 9]); }, + function testIterator3(t){ t.assertEqual(df.until(function(n){ return n > 10; }, function(n){ return n * 3; }, 1), [1, 3, 9]); }, + + function testListcomp1(t){ t.assertEqual(df.listcomp("i for(var i=0; i<3; ++i)"), [0, 1, 2]); }, + function testListcomp2(t){ t.assertEqual(df.listcomp("i*j for(var i=0; i<3; ++i) for(var j=0; j<3; ++j)"), [0, 0, 0, 0, 1, 2, 0, 2, 4]); }, + function testListcomp3(t){ t.assertEqual(df.listcomp("i*j for(var i=0; i<3; ++i) if(i%2==1) for(var j=0; j<3; ++j)"), [0, 1, 2]); }, + function testListcomp4(t){ t.assertEqual(df.listcomp("i+j for(var i=0; i<3; ++i) for(var j=0; j<3; ++j)"), [0, 1, 2, 1, 2, 3, 2, 3, 4]); }, + function testListcomp5(t){ t.assertEqual(df.listcomp("i+j for(var i=0; i<3; ++i) if(i%2==1) for(var j=0; j<3; ++j)"), [1, 2, 3]); }, + function testListcomp6(t){ t.assertEqual(df.listcomp("i for(i=0; i<3; ++i)"), [0, 1, 2]); }, + function testListcomp7(t){ t.assertEqual(df.listcomp("i*j for(i=0; i<3; ++i) for(j=0; j<3; ++j)"), [0, 0, 0, 0, 1, 2, 0, 2, 4]); }, + function testListcomp8(t){ t.assertEqual(df.listcomp("i*j for(i=0; i<3; ++i) if(i%2==1) for(j=0; j<3; ++j)"), [0, 1, 2]); }, + function testListcomp9(t){ t.assertEqual(df.listcomp("i+j for(i=0; i<3; ++i) for(j=0; j<3; ++j)"), [0, 1, 2, 1, 2, 3, 2, 3, 4]); }, + function testListcomp10(t){ t.assertEqual(df.listcomp("i+j for(i=0; i<3; ++i) if(i%2==1) for(j=0; j<3; ++j)"), [1, 2, 3]); } + ]); +})(); + +} diff --git a/includes/js/dojox/lang/tests/main.js b/includes/js/dojox/lang/tests/main.js new file mode 100644 index 0000000..1f0d7ab --- /dev/null +++ b/includes/js/dojox/lang/tests/main.js @@ -0,0 +1,17 @@ +if(!dojo._hasResource["dojox.lang.tests.main"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.tests.main"] = true; +dojo.provide("dojox.lang.tests.main"); + +try{ + // functional block + dojo.require("dojox.lang.tests.listcomp"); + dojo.require("dojox.lang.tests.lambda"); + dojo.require("dojox.lang.tests.fold"); + dojo.require("dojox.lang.tests.curry"); + dojo.require("dojox.lang.tests.misc"); + dojo.require("dojox.lang.tests.array"); +}catch(e){ + doh.debug(e); +} + +} diff --git a/includes/js/dojox/lang/tests/misc.js b/includes/js/dojox/lang/tests/misc.js new file mode 100644 index 0000000..f17ea8c --- /dev/null +++ b/includes/js/dojox/lang/tests/misc.js @@ -0,0 +1,31 @@ +if(!dojo._hasResource["dojox.lang.tests.misc"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.tests.misc"] = true; +dojo.provide("dojox.lang.tests.misc"); + +dojo.require("dojox.lang.functional.object"); +dojo.require("dojox.lang.functional.zip"); + +(function(){ + var df = dojox.lang.functional, fun = df.lambda("100*a + 10*b + c"), result = []; + df.forIn({a: 1, b: 2}, function(v, i){ result.push("[" + i + "] = " + v); }); + + tests.register("dojox.lang.tests.misc", [ + function testZip1(t){ t.assertEqual(df.zip([1, 2, 3], [4, 5, 6]), [[1, 4], [2, 5], [3, 6]]); }, + function testZip2(t){ t.assertEqual(df.zip([1, 2], [3, 4], [5, 6]), [[1, 3, 5], [2, 4, 6]]); }, + + function testUnzip1(t){ t.assertEqual(df.unzip([[1, 4], [2, 5], [3, 6]]), [[1, 2, 3], [4, 5, 6]]); }, + function testUnzip2(t){ t.assertEqual(df.unzip([[1, 3, 5], [2, 4, 6]]), [[1, 2], [3, 4], [5, 6]]); }, + + function testMixer(t){ t.assertEqual(df.mixer(fun, [1, 2, 0])(3, 1, 2), 123); }, + function testFlip(t){ t.assertEqual(df.flip(fun)(3, 2, 1), 123); }, + + function testCompose1(t){ t.assertEqual(df.lambda(["+5", "*3"])(8), 8 * 3 + 5); }, + function testCompose2(t){ t.assertEqual(df.lambda(["+5", "*3"].reverse())(8), (8 + 5) * 3); }, + + function testForIn(t){ t.assertEqual(result.sort().join(", "), "[a] = 1, [b] = 2"); }, + function testKeys(t){ t.assertEqual(df.keys({a: 1, b: 2, c: 3}), ["a", "b", "c"]); }, + function testValues(t){ t.assertEqual(df.values({a: 1, b: 2, c: 3}), [1, 2, 3]); } + ]); +})(); + +} diff --git a/includes/js/dojox/lang/tests/runTests.html b/includes/js/dojox/lang/tests/runTests.html new file mode 100644 index 0000000..32fdfdb --- /dev/null +++ b/includes/js/dojox/lang/tests/runTests.html @@ -0,0 +1,9 @@ + + + DojoX Functional Unit Test Runner + + + +

      Redirecting to D.O.H runner.

      + + diff --git a/includes/js/dojox/lang/utils.js b/includes/js/dojox/lang/utils.js new file mode 100644 index 0000000..b7926c6 --- /dev/null +++ b/includes/js/dojox/lang/utils.js @@ -0,0 +1,54 @@ +if(!dojo._hasResource["dojox.lang.utils"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.lang.utils"] = true; +dojo.provide("dojox.lang.utils"); + +(function(){ + var empty = {}, du = dojox.lang.utils; + + dojo.mixin(dojox.lang.utils, { + coerceType: function(target, source){ + switch(typeof target){ + case "number": return Number(eval("(" + source + ")")); + case "string": return String(source); + case "boolean": return Boolean(eval("(" + source + ")")); + } + return eval("(" + source + ")"); + }, + + updateWithObject: function(target, source, conv){ + // summary: updates an existing object in place with properties from an "source" object. + // target: Object: the "target" object to be updated + // source: Object: the "source" object, whose properties will be used to source the existed object. + // conv: Boolean?: force conversion to the original type + if(!source){ return target; } + for(var x in target){ + if(x in source && !(x in empty)){ + var t = target[x]; + if(t && typeof t == "object"){ + du.updateObject(t, source[x]); + }else{ + target[x] = conv ? du.coerceType(t, source[x]) : dojo.clone(source[x]); + } + } + } + return target; // Object + }, + + updateWithPattern: function(target, source, pattern, conv){ + // summary: updates an existing object in place with properties from an "source" object. + // target: Object: the "target" object to be updated + // source: Object: the "source" object, whose properties will be used to source the existed object. + // pattern: Array: an array of properties to be copied + // conv: Boolean?: force conversion to the original type + if(!source || !pattern){ return target; } + for(var x in pattern){ + if(x in source && !(x in empty)){ + target[x] = conv ? du.coerceType(pattern[x], source[x]) : dojo.clone(source[x]); + } + } + return target; // Object + } + }); +})(); + +} diff --git a/includes/js/dojox/layout/BorderContainer.js b/includes/js/dojox/layout/BorderContainer.js new file mode 100644 index 0000000..7fa5393 --- /dev/null +++ b/includes/js/dojox/layout/BorderContainer.js @@ -0,0 +1,7 @@ +if(!dojo._hasResource["dojox.layout.BorderContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.layout.BorderContainer"] = true; +dojo.provide("dojox.layout.BorderContainer"); + +console.error("dojox.layout.BorderContainer moved to dijit.layout.BorderContainer"); + +} diff --git a/includes/js/dojox/layout/ContentPane.js b/includes/js/dojox/layout/ContentPane.js new file mode 100644 index 0000000..d60202c --- /dev/null +++ b/includes/js/dojox/layout/ContentPane.js @@ -0,0 +1,479 @@ +if(!dojo._hasResource["dojox.layout.ContentPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.layout.ContentPane"] = true; +dojo.provide("dojox.layout.ContentPane"); + +dojo.require("dijit.layout.ContentPane"); + +(function(){ // private scope, sort of a namespace + + // TODO: should these methods be moved to dojox.html.cssPathAdjust or something? + + // css at-rules must be set before any css declarations according to CSS spec + // match: + // @import 'http://dojotoolkit.org/dojo.css'; + // @import 'you/never/thought/' print; + // @import url("it/would/work") tv, screen; + // @import url(/did/you/now.css); + // but not: + // @namespace dojo "http://dojotoolkit.org/dojo.css"; /* namespace URL should always be a absolute URI */ + // @charset 'utf-8'; + // @media print{ #menuRoot {display:none;} } + + + // we adjust all paths that dont start on '/' or contains ':' + //(?![a-z]+:|\/) + + if(dojo.isIE){ + var alphaImageLoader = /(AlphaImageLoader\([^)]*?src=(['"]))(?![a-z]+:|\/)([^\r\n;}]+?)(\2[^)]*\)\s*[;}]?)/g; + } + + var cssPaths = /(?:(?:@import\s*(['"])(?![a-z]+:|\/)([^\r\n;{]+?)\1)|url\(\s*(['"]?)(?![a-z]+:|\/)([^\r\n;]+?)\3\s*\))([a-z, \s]*[;}]?)/g; + + function adjustCssPaths(cssUrl, cssText){ + // summary: + // adjusts relative paths in cssText to be relative to cssUrl + // a path is considered relative if it doesn't start with '/' and not contains ':' + // description: + // Say we fetch a HTML page from level1/page.html + // It has some inline CSS: + // @import "css/page.css" tv, screen; + // ... + // background-image: url(images/aplhaimage.png); + // + // as we fetched this HTML and therefore this CSS + // from level1/page.html, these paths needs to be adjusted to: + // @import 'level1/css/page.css' tv, screen; + // ... + // background-image: url(level1/images/alphaimage.png); + // + // In IE it will also adjust relative paths in AlphaImageLoader() + // filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/alphaimage.png'); + // will be adjusted to: + // filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='level1/images/alphaimage.png'); + // + // Please note that any relative paths in AlphaImageLoader in external css files wont work, as + // the paths in AlphaImageLoader is MUST be declared relative to the HTML page, + // not relative to the CSS file that declares it + + if(!cssText || !cssUrl){ return; } + + // support the ImageAlphaFilter if it exists, most people use it in IE 6 for transparent PNGs + // We are NOT going to kill it in IE 7 just because the PNGs work there. Somebody might have + // other uses for it. + // If user want to disable css filter in IE6 he/she should + // unset filter in a declaration that just IE 6 doesn't understands + // like * > .myselector { filter:none; } + if(alphaImageLoader){ + cssText = cssText.replace(alphaImageLoader, function(ignore, pre, delim, url, post){ + return pre + (new dojo._Url(cssUrl, './'+url).toString()) + post; + }); + } + + return cssText.replace(cssPaths, function(ignore, delimStr, strUrl, delimUrl, urlUrl, media){ + if(strUrl){ + return '@import "' + (new dojo._Url(cssUrl, './'+strUrl).toString()) + '"' + media; + }else{ + return 'url(' + (new dojo._Url(cssUrl, './'+urlUrl).toString()) + ')' + media; + } + }); + } + + // attributepaths one tag can have multiple paths, example: + // or + // + var htmlAttrPaths = /(<[a-z][a-z0-9]*\s[^>]*)(?:(href|src)=(['"]?)([^>]*?)\3|style=(['"]?)([^>]*?)\5)([^>]*>)/gi; + + function adjustHtmlPaths(htmlUrl, cont){ + var url = htmlUrl || "./"; + + return cont.replace(htmlAttrPaths, + function(tag, start, name, delim, relUrl, delim2, cssText, end){ + return start + (name ? + (name + '=' + delim + (new dojo._Url(url, relUrl).toString()) + delim) + : ('style=' + delim2 + adjustCssPaths(url, cssText) + delim2) + ) + end; + } + ); + } + + function secureForInnerHtml(cont){ + /********* remove .. tag **********/ + // khtml is picky about dom faults, you can't attach a + + + + + +

      dojox.layout.ContentPane

      +

      As dojox ContentPane is derived from dijit ContentPane, make sure that the dijit test passes before running this test

      +

      Test relies on a php page as backend, so you need php installed on your server

      + +
      + Initial value +
      + + + + + + + + + + + + +
      + + \ No newline at end of file diff --git a/includes/js/dojox/layout/tests/_bottomPane.html b/includes/js/dojox/layout/tests/_bottomPane.html new file mode 100644 index 0000000..8f5090a --- /dev/null +++ b/includes/js/dojox/layout/tests/_bottomPane.html @@ -0,0 +1,53 @@ +
      + Bottom Pane Content: + + + + +
      \ No newline at end of file diff --git a/includes/js/dojox/layout/tests/_expando.css b/includes/js/dojox/layout/tests/_expando.css new file mode 100644 index 0000000..8efd20e --- /dev/null +++ b/includes/js/dojox/layout/tests/_expando.css @@ -0,0 +1,477 @@ + +body, div, dl, dt, dd, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, input, textarea, p, blockquote, th, td { + margin: 0; + padding: 0; +} +fieldset, img { + border: 0 none; +} +address, caption, cite, code, dfn, th, var { + font-style: normal; + font-weight: normal; +} +caption, th { + text-align: left; +} +q:before, q:after { + content:""; +} +abbr, acronym { + border:0; +} +body { + font: 13px Myriad,Arial,Helvetica,clean,sans-serif; + *font-size: small; + *font: x-small; +} +h1 { + font-size: 1.5em; + font-weight: normal; + line-height: 1em; + margin-top: 1em; + margin-bottom:0; +} +h2 { + font-size: 1.1667em; + font-weight: bold; + line-height: 1.286em; + margin-top: 1.929em; + margin-bottom:0.643em; +} +h3, h4, h5, h6 { + font-size: 1em; + font-weight: bold; + line-height: 1.5em; + margin-top: 1.5em; + margin-bottom: 0; +} +p { + font-size: 1em; + margin-top: 1.5em; + margin-bottom: 1.5em; + line-height: 1.5em; +} +blockquote { + font-size: 0.916em; + margin-top: 3.272em; + margin-bottom: 3.272em; + line-height: 1.636em; + padding: 1.636em; + border-top: 1px solid #ccc; + border-bottom: 1px solid #ccc; +} +ol li, ul li { + font-size: 1em; + line-height: 1.5em; + margin: 0; +} +pre, code { + font-size:115%; + *font-size:100%; + font-family: Courier, "Courier New"; + background-color: #efefef; + border: 1px solid #ccc; +} +pre { + border-width: 1px 0; + padding: 1.5em; +} +table { font-size:100%; } +table.dojoTabular { + border-collapse: collapse; + border-spacing: 0; + border: 1px solid #ccc; + margin: 0 1.5em; +} +.dojoTabular th { + text-align: center; + font-weight: bold; +} +table.dojoTabular thead, table.dojoTabular tfoot { + background-color: #efefef; + border: 1px solid #ccc; + border-width: 1px 0; +} +table.dojoTabular thead tr th, +table.dojoTabular thead tr td, +table.dojoTabular tbody tr td, +table.dojoTabular tfoot tr td { + padding: 0.25em 0.5em; +} +body { + background:#fff url(../../../dijit/tests/images/testsBodyBg.gif) repeat-x top left; + padding:2em 2em 2em 2em; +} +h1.testTitle { + font-size:2em; + margin:0 0 1em 0; +} +.plusIcon, .plusBlockIcon { + background-image: url(../../../dijit/tests/images/plus.gif); + background-repeat: no-repeat; + width: 16px; + height: 16px; +} +.plusBlockIcon { + display: block !important; +} +.noteIcon { + background-image: url(../../../dijit/tests/images/note.gif); + background-repeat: no-repeat; + width: 20px; + height: 20px; +} +.flatScreenIcon { + background-image: url(../../../dijit/tests/images/flatScreen.gif); + background-repeat: no-repeat; + width: 32px; + height: 32px; +} +.dijitTestNodeDialog { + position:absolute; + top:5px; + right:5px; + display:block; + width:200px; + visibility:hidden; + background-color:#fff !important; + color:#000 !important; + border:1px solid #000; + padding:5px; +} +.dijitTestNodeDialog table { + background-color:#fff !important; +} +.dijitTestNodeDialog td { + padding:3px; +} +.dijitTestNodeShowing { + visibility:visible; +} +.customFolderOpenedIcon, .customFolderClosedIcon { + background-image: url(../../../dijit/tests/../demos/mail/icons.png); + background-repeat: no-repeat; + width: 16px; + height: 16px; + text-align: center; + padding-right:4px; + background-position: -44px; +} +.dj_ie6 .customFolderOpenedIcon, .dj_ie6 .customFolderClosedIcon { + background-image: url(../../../dijit/tests/../demos/mail/icons.gif); +} +.customFolderClosedIcon { + background-position: -154px; +} +body .medium { + font-size: larger; +} +.dojoxFloatingPane { + background-color:#fff; + position:relative; + border: 1px solid #dedede; + overflow: hidden; + -webkit-box-shadow: 0px 5px 10px #adadad; +} +.dojoxFloatingPaneFg { + -webkit-box-shadow: 0px 8px 20px #525252; +} +.dojoxFloatingPaneTitle { + background: #cccccc; + background:#fafafa repeat-x bottom left; + border:1px solid #bfbfbf; + padding:4px 4px 2px 4px; + cursor: pointer; + white-space: nowrap; +} +.soria .dojoxFloatingPaneTitle { + background:#fff url(../../../dijit/themes/soria/images/titleBar.png) repeat-x top left; + border:1px solid #b1badf; + font-size: 0.9em; + font-weight: bold; + line-height:1.2em; +} +.tundra .dojoxFloatingPaneTitle { + background:#fafafa url(../../../dijit/themes/tundra/images/titleBarBg.gif) repeat-x bottom left; + border:1px solid #bfbfbf; + color:#000; +} +.dojoxFloatingCloseIcon { + background:url(../resources/icons/tabClose.png) no-repeat center center; + width:16px; + height:16px; + overflow:hidden; + float:right; +} +.dojoxFloatingMinimizeIcon { + background:url(../../../dijit/themes/tundra/images/arrowDown.png) no-repeat center center; + width:16px; + height:16px; + overflow:hidden; + float:right; +} +.soria .dojoxFloatingMinimizeIcon { + background:url(../../../dijit/themes/soria/images/spriteRoundedIconsSmallBl.png) no-repeat -15px top; +} +.floatingPaneMaximized .dojoxFloatingMaximizeIcon { display:none; } +.dojoxFloatingMaximizeIcon { + background:url(../../../dijit/themes/tundra/images/arrowUp.png) no-repeat center center; + width:16px; + height:16px; + overflow:hidden; + float:right; +} +.soria .dojoxFloatingMaximizeIcon { + background:url(../../../dijit/themes/soria/images/spriteRoundedIconsSmallBl.png) no-repeat -45px top; +} +.floatingPaneMaximized .dojoxFloatingRestoreIcon { display:inline; } +.dojoxFloatingRestoreIcon { + background:url(../../../dijit/themes/tundra/images/arrowDown.png) no-repeat center center; + width:16px; height:16px; + overflow:hidden; + float:right; + display:none; +} +.dojoxFloatingResizeHandle { + background:url(../resources/icons/resize.png) no-repeat bottom right; + position:absolute; + right:0; + bottom:0; + width:16px; + height:16px; + cursor:nw-resize; +} +.dojoxFloatingCloseIcon { + width:15px; + height:15px; + overflow:hidden; + float:right; + cursor:pointer; +} +.soria .dojoxFloatingCloseIcon { + background:url(../../../dijit/themes/soria/images/spriteRoundedIconsSmallBl.png) no-repeat -60px top; +} +.tundra .dojoxFloatingCloseIcon { + background:url(../../../dijit/themes/tundra/images/tabClose.png) no-repeat center center; +} +.dojoxFloatingDockDefault { + position:absolute; + bottom:0px; + left:0px; + overflow:hidden; + margin:0; + margin-bottom:3px; + padding:0px; + width:100%; + z-index:99; + background:transparent; + +} +.dojoxDockList { + padding: 0px; + margin: 0px; +} +.dojoxDockRestoreButton { + background:url(../../../dijit/themes/tundra/images/arrowUp.png) no-repeat center center; + width:16px; height:16px; + overflow:hidden; + float:left; + margin-top:2px; +} +.soria .dojoxDockRestoreButton { + background:url(../../../dijit/themes/soria/images/spriteRoundedIconsSmallBl.png) no-repeat -45px top; +} +.dojoxDockTitleNode { + overflow:hidden; +} +.dojoxDock { + display: block; + border: 1px solid black; + position: absolute; + padding:0; + margin:0; + background:#fcfcfc; +} +.dojoxDockNode { + border: 1px solid #adadad; + border-radius: 2px; + -webkit-border-radius: 2px; + -moz-border-radius: 3px; + cursor:pointer; + list-style: none; + padding: 2px; + margin: 0px; + height: 16px; + width: auto; + float: left; + background: #fafafa url(../resources/images/floatTitleBarBg.gif) repeat-x bottom left; +} +.soria .dojoxDockNode { + background:#b7cdee url(../../../dijit/themes/soria/images/titleBar.png) repeat-x; +} +.dojoxFloatingPaneContent { + overflow: auto; + background-color: #fff; + height: 100%; + width: 100%; +} +.dojoxFloatingPaneCanvas { + background-color:#fff; +} +.dojoxExpandoPane { + overflow:hidden; + margin-top:1px; + border-top:1px solid #ccc; + z-index:440; + background:#fff; +} +.dojoxExpandoPane .dojoxExpandoWrapper { + overflow:hidden; +} +.dojoxExpandoIcon { + width:14px; + cursor:pointer; + background-position:-60px 0px; + height:14px; +} +.soria .dojoxExpandoIcon { + background: url(../../../dijit/themes/soria/images/spriteRoundedIconsSmall.png) no-repeat center center; +} +.tundra .dojoxExpandoLeft .dojoxExpandoIcon, +.nihilo .dojoxExpandoLeft .dojoxExpandoIcon { + + background: url(../../../dijit/themes/tundra/images/minusButton.gif) no-repeat; +} +.tundra .dojoxExpandoRight .dojoxExpandoIcon, +.nihilo .dojoxExpandoRight .dojoxExpandoIcon { + + background: url(../../../dijit/themes/tundra/images/minusButton.gif) no-repeat; +} +.tundra .dojoxExpandoClosed .dojoxExpandoIcon { + background: url(../../../dijit/themes/tundra/images/plusButton.gif) no-repeat; +} +.dojoxExpandoClosed .dojoxExpandoIcon { + background-position: 0px 0px; +} +.dojoxExpandoClosed .dojoxExpandoTitleNode { + visibility:hidden; +} +.dojoxExpandoTitleNode { + padding-right:6px; padding-left:6px; +} +.dojoxExpandoClosed .dijitContentPane { + overflow: hidden; +} +.dojoxExpandoIcon .a11yNode { + display:none; + visibility:hidden; +} +.dojoxExpandoBottom .dojoxExpandoIcon, +.dojoxExpandoTop .dojoxExpandoIcon, +.dojoxExpandoLeft .dojoxExpandoIcon { + float:right; +} +.dojoxExpandoRight .dojoxExpandoIcon { + float:left; +} +.nihilo .dojoxExpandoTitle { + height:18px; + font-size:0.9em; + font-weight:bold; + padding:3px; + padding-top:7px; + padding-bottom:7px; + background:#fafafa url(../../../dijit/themes/nihilo/images/tabStripe.gif) repeat-x left bottom; + +} +.nihilo .dojoxExpandoTop { + border-bottom:1px solid #ccc; + border-left:1px solid #ccc; + border-right:1px solid #ccc; +} +.soria .dojoxExpandoTop { + +} +.soria .dojoxExpandoTitle { + height:18px; + font-size:0.9em; + font-weight:bold; + padding:3px; + padding-top:7px; + padding-bottom:7px; + background:#f0f4fc url(../../../dijit/themes/soria/images/tabStripe.gif) repeat-x left bottom; +} +.tundra .dojoxExpandoTitle { + font-size: 0.9em; + font-weight: bold; + padding: 3px; + padding-top: 7px; + padding-bottom: 7px; + background: #fafafa url(../../../dijit/themes/tundra/images/accordionItemActive.gif) repeat-x scroll left bottom; +} +.tundra .dojoxExpandoClosed { + + background-color: #fafafa; +} +.tundra .dojoxExpandoClosed .dojoxExpandoTitle { + background-image: none; + background-color: transparent; +} +body, html { + margin:0; + padding:0; + width:100%; + height:100%; + background: #fafafa; + overflow: hidden; +} +.wrap { + margin: 0; + padding: 15px; +} +.wrap h3 { + margin-top: 5px; +} +#header { + height:32px; +} +.searchBar { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 25px; + border-bottom: 1px solid #666; + background: #fafafa; +} +.searchBar p { + margin: 0; + padding: 2px; +} +.searchStuff { + position: absolute; + top: 25px; + margin: 0 auto; +} +.searchStuff ul { + width: auto; + margin: 0 auto; + padding: 0; +} +div.itty { + font-weight: normal; + font: 8pt Arial,sans-serif; + color:#666; + padding:5px; + padding-left:10px; +} +div.itty:hover { + color:#333; +} +.itemType { + font-style:italic; + font-size:12pt; +} +#runSearchIcon { + border:1px solid #000; +} diff --git a/includes/js/dojox/layout/tests/_expando.css.commented.css b/includes/js/dojox/layout/tests/_expando.css.commented.css new file mode 100644 index 0000000..2fd0636 --- /dev/null +++ b/includes/js/dojox/layout/tests/_expando.css.commented.css @@ -0,0 +1,64 @@ +@import "../../../dojo/resources/dojo.css"; +@import "../../../dijit/tests/css/dijitTests.css"; + +@import "../resources/FloatingPane.css"; +@import "../resources/ExpandoPane.css"; + +body, html { + margin:0; + padding:0; + width:100%; + height:100%; + background: #fafafa; + overflow: hidden; +} +.wrap { + margin: 0; + padding: 15px; +} +.wrap h3 { + margin-top: 5px; +} +#header { + height:32px; +} +.searchBar { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 25px; + border-bottom: 1px solid #666; + background: #fafafa; +} +.searchBar p { + margin: 0; + padding: 2px; +} +.searchStuff { + position: absolute; + top: 25px; + margin: 0 auto; +} +.searchStuff ul { + width: auto; + margin: 0 auto; + padding: 0; +} +div.itty { + font-weight: normal; + font: 8pt Arial,sans-serif; + color:#666; + padding:5px; + padding-left:10px; +} +div.itty:hover { + color:#333; +} +.itemType { + font-style:italic; + font-size:12pt; +} +#runSearchIcon { + border:1px solid #000; +} diff --git a/includes/js/dojox/layout/tests/_floating.html b/includes/js/dojox/layout/tests/_floating.html new file mode 100644 index 0000000..be5ece9 --- /dev/null +++ b/includes/js/dojox/layout/tests/_floating.html @@ -0,0 +1,48 @@ +
      +

      I am FloatingPane

      +

      Windows in the Browser is weird UI, but sometimes useful. Even more useful:
      +
      + +
      + +

      + (both technically unsupported) +

      + +
      \ No newline at end of file diff --git a/includes/js/dojox/layout/tests/_lorem.html b/includes/js/dojox/layout/tests/_lorem.html new file mode 100644 index 0000000..9e7aaef --- /dev/null +++ b/includes/js/dojox/layout/tests/_lorem.html @@ -0,0 +1,11 @@ +

      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nam facilisis enim. + Pellentesque in elit et lacus euismod dignissim. Aliquam dolor pede, convallis eget, + dictum a, blandit ac, urna. Pellentesque sed nunc ut justo volutpat egestas. Class + aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. + In erat. Suspendisse potenti. Fusce faucibus nibh sed nisi. Phasellus faucibus, dui + a cursus dapibus, mauris nulla euismod velit, a lobortis turpis arcu vel dui. Pellentesque + fermentum ultrices pede. Donec auctor lectus eu arcu. Curabitur non orci eget est porta gravida. + Aliquam pretium orci id nisi. Duis faucibus, mi non adipiscing venenatis, erat urna aliquet elit, + eu fringilla lacus tellus quis erat. Nam tempus ornare lorem. Nullam feugiat. +

      diff --git a/includes/js/dojox/layout/tests/_script.html b/includes/js/dojox/layout/tests/_script.html new file mode 100644 index 0000000..64bcd0e --- /dev/null +++ b/includes/js/dojox/layout/tests/_script.html @@ -0,0 +1,9 @@ + +

      + bar baz +

      diff --git a/includes/js/dojox/layout/tests/doc0.html b/includes/js/dojox/layout/tests/doc0.html new file mode 100644 index 0000000..10fd03a --- /dev/null +++ b/includes/js/dojox/layout/tests/doc0.html @@ -0,0 +1,14 @@ +

      Document 0

      +This document has
      a link.
      +(to check we're copying children around properly).
      +Also it's got a widget, a combo box:
      + +And a button too: + +Here's some text that comes AFTER the button. +Okay textbox: + diff --git a/includes/js/dojox/layout/tests/images/blank.gif b/includes/js/dojox/layout/tests/images/blank.gif new file mode 100644 index 0000000..e565824 Binary files /dev/null and b/includes/js/dojox/layout/tests/images/blank.gif differ diff --git a/includes/js/dojox/layout/tests/images/dojoLogo.png b/includes/js/dojox/layout/tests/images/dojoLogo.png new file mode 100644 index 0000000..1219de7 Binary files /dev/null and b/includes/js/dojox/layout/tests/images/dojoLogo.png differ diff --git a/includes/js/dojox/layout/tests/images/gridUnderlay.png b/includes/js/dojox/layout/tests/images/gridUnderlay.png new file mode 100644 index 0000000..016f129 Binary files /dev/null and b/includes/js/dojox/layout/tests/images/gridUnderlay.png differ diff --git a/includes/js/dojox/layout/tests/images/testImage.gif b/includes/js/dojox/layout/tests/images/testImage.gif new file mode 100644 index 0000000..4370d68 Binary files /dev/null and b/includes/js/dojox/layout/tests/images/testImage.gif differ diff --git a/includes/js/dojox/layout/tests/remote/getResponse.php b/includes/js/dojox/layout/tests/remote/getResponse.php new file mode 100644 index 0000000..0a37050 --- /dev/null +++ b/includes/js/dojox/layout/tests/remote/getResponse.php @@ -0,0 +1,108 @@ + +
      + + +
      +
      +
      +
      + + + + "; + break; + + case 'importCss': + header('Content-type: text/css; charset=utf-8'); + echo "#importMediaTest { + margin: 4px; + border: 1px dashed red; + width: 200px; + height: 200px; + } + #importCssTest { + margin: 4px; + border: 1px solid blue; + width: 100px; + height: 100px; + }"; + break; + + case 'linkCss': + header('Content-type: text/css; charset=utf-8'); + echo "#linkMediaTest { + margin: 4px; + border: 2px dashed red; + width: 200px; + height: 200px; + } + #linkCssTest { + margin: 4px; + border: 2px dashed red; + width: 100px; + height: 100px; + }"; + break; + + case 'importMediaPrint': // may download but not render + header('Content-type: text/css; charset=utf-8'); + echo "#importMediaTest { + margin: 10px; + border: 5px dashed gray; + width: 100px; + height: 100px; + }"; + break; + + case 'linkMediaPrint': // may download but not render + header('Content-type: text/css; charset=utf-8'); + echo "#linkMediaTest { + margin: 10px; + border: 5px dashed gray; + width: 100px; + height: 100px; + }"; + break; + + case 'remoteJsTrue': + header('Content-type: text/javascript; charset=utf-8'); + echo "unTypedVarInDocScope = true;"; + break; + + case 'remoteJsFalse': + header('Content-type: text/javascript; charset=utf-8'); + echo "unTypedVarInDocScope = false;"; + break; + + case 'bounceInput': + echo file_get_contents("php://input"); + break; + + case 'bounceHeaders'; + if(function_exists("apache_request_headers")){ + $headers = apache_request_headers(); + foreach($headers as $header => $vlu){ + echo "$header=$vlu\n
      "; + } + }else{ + // IIS, php as CGI etc gets here, messes formating, suboptimal + $headers = preg_grep('/HTTP_/i', array_keys($_SERVER)); + foreach($headers as $header){ + $vlu = preg_replace(array('/^HTTP_/', '/_/'), array('', '-'), $header); + echo "$vlu={$_SERVER[$header]}\n
      "; + } + } + break; + + default: + echo "unkown mode {$_GET['mode']}"; + } + } +?> \ No newline at end of file diff --git a/includes/js/dojox/layout/tests/test_DragPane.html b/includes/js/dojox/layout/tests/test_DragPane.html new file mode 100644 index 0000000..df38b7e --- /dev/null +++ b/includes/js/dojox/layout/tests/test_DragPane.html @@ -0,0 +1,93 @@ + + + + + DragPane layout widget Test + + + + + + + + + +
      +

      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend + sagittis turpis. purus purus in nibh. Phasellus in nunc. +

      +

      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend + sagittis turpis. purus purus in nibh. Phasellus in nunc. +

      +

      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend + sagittis turpis. purus purus in nibh. Phasellus in nunc. +

      +

      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend + sagittis turpis. purus purus in nibh. Phasellus in nunc. +

      +

      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend + sagittis turpis. purus purus in nibh. Phasellus in nunc. +

      +

      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend + sagittis turpis. purus purus in nibh. Phasellus in nunc. +

      +

      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend + sagittis turpis. purus purus in nibh. Phasellus in nunc. +

      +

      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend + sagittis turpis. purus purus in nibh. Phasellus in nunc. +

      +

      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend + sagittis turpis. purus purus in nibh. Phasellus in nunc. +

      +

      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend + sagittis turpis. purus purus in nibh. Phasellus in nunc. +

      +
      + + diff --git a/includes/js/dojox/layout/tests/test_ExpandoPane.html b/includes/js/dojox/layout/tests/test_ExpandoPane.html new file mode 100644 index 0000000..ceaad50 --- /dev/null +++ b/includes/js/dojox/layout/tests/test_ExpandoPane.html @@ -0,0 +1,307 @@ + + + + dojox.layout.ExpandoPane + + + + + + + + +
      + +
      +
      +
      + + +
      +
      +
      +
        +
        +
        +
          +
          +
          +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            a
            +
            b
            +
            +
            +
            +
              +
              +
              +
              +
              +
              + +
              +
              +
              +

              This select modifies the left Expando's easing function. An Expando can have an easeIn and an easeOut parameter. This sets both.

              + +

              +

              Some easing functions break when used with width: (negative width? but how?). Be warned.

              +
              +
              +
              +
              +

              This is a BorderContainer (the window). Each of the panes is set to one of + "left", "right", or "center". The left and right panes are ExpandoPanes (they collapse). +

              +

              + We can add other panes programatically: +
              + +

              +

              What does a FloatingPane look like here?
              + +

              +
              +
              +
              c
              +
              +
              +
              + +
              Loading progress
              + + + diff --git a/includes/js/dojox/layout/tests/test_ExpandoPane_code.html b/includes/js/dojox/layout/tests/test_ExpandoPane_code.html new file mode 100644 index 0000000..2b71fcc --- /dev/null +++ b/includes/js/dojox/layout/tests/test_ExpandoPane_code.html @@ -0,0 +1,98 @@ + + + + dojox.layout.ExpandoPane + + + + + + + +
              +
              + +
              + +
              +
              +
              pane 0 content
              +
              pane 1 content
              +
              pane 2 content
              +
              pane 3 content
              +
              + + diff --git a/includes/js/dojox/layout/tests/test_ExpandoPane_more.html b/includes/js/dojox/layout/tests/test_ExpandoPane_more.html new file mode 100644 index 0000000..aed990e --- /dev/null +++ b/includes/js/dojox/layout/tests/test_ExpandoPane_more.html @@ -0,0 +1,114 @@ + + + + dojox.layout.ExpandoPane + + + + + + + + + + + + + + +

              Basic ExpandoPane tests

              + +

              Left:

              +
              +
              + foo +
              +
              +
              +
              +
              +
              + +

              Right:

              +
              +
              +
              +
              +
              +
              +
              +
              +
              +
              +
              +
              + +

              Top (easeIn="dojox.fx.easing.bounceOut" duration="1200"):

              +
              +
              + foo +
              +
              +
              + +

              Bottom:

              +
              +
              + foo +
              +
              +
              + +

              Bottom/Left:

              +
              +
              + foo +
              +
              + foo +
              +
              +
              + +

              Top/Left/Right

              +
              +
              + foo +
              +
              + foo +
              +
              + foo +
              +
              +
              + +

              Top/Left/Right + splitters

              +
              +
              + foo +
              +
              + foo +
              +
              + foo +
              +
              +
              + + + + diff --git a/includes/js/dojox/layout/tests/test_FloatingPane.html b/includes/js/dojox/layout/tests/test_FloatingPane.html new file mode 100644 index 0000000..016f8a6 --- /dev/null +++ b/includes/js/dojox/layout/tests/test_FloatingPane.html @@ -0,0 +1,167 @@ + + + + dojox.layout.FloatPane - simplest extension on TitlePane ... ever. + + + + + + + + + + + + + hide first pane | + show first pane | + minimize 'uncloseable, dockable' pane pane | + new floater + +
              +

              I am the content to be floated around

              +
              + +
              +

              + I am dockable, though I have no dockTo="" attribute. I will create or use an existing dock + on the bottom of the screen. +

              + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc + eleifend sagittis turpis. purus purus in nibh. Phasellus in nunc. +

              +
              + +
              +

              + I am made into a FloatingPane in dojo.addOnLoad();

              + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend + sagittis turpis. purus purus in nibh. Phasellus in nunc. +

              +
              + +
              +
              +
              +

              + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In porta. Etiam mattis libero nec ante. Nam + porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend + sagittis turpis. purus purus in nibh. Phasellus in nunc. +

              +
              + + +

              + This is just a pane. You cannot close me, you cannot resize me, you cannot minimize me. +

              +
              + +
              + +
              + + + +
              +
              +
              + First Page +
              +
              +
              +
              + Story of Paul. +
              +
              + Story about Paul. +
              +
              + Story about... guess who. +
              +
              +
              +
              +
              + + diff --git a/includes/js/dojox/layout/tests/test_RadioGroup.html b/includes/js/dojox/layout/tests/test_RadioGroup.html new file mode 100644 index 0000000..d2c6ba0 --- /dev/null +++ b/includes/js/dojox/layout/tests/test_RadioGroup.html @@ -0,0 +1,61 @@ + + + + + RadioGroup Widget Test + + + + + + + + + + +

              dojox.layout.RadioGroup test

              + + +
              +
              +
              +
              +
              +
              + +
              +
              +
              +
              +
              + +
              +
              +
              +
              +
              +
              + + + diff --git a/includes/js/dojox/layout/tests/test_ResizeHandle.html b/includes/js/dojox/layout/tests/test_ResizeHandle.html new file mode 100644 index 0000000..ed16473 --- /dev/null +++ b/includes/js/dojox/layout/tests/test_ResizeHandle.html @@ -0,0 +1,134 @@ + + + + + Resize Widget Test + + + + + + + + + + +

              dojox.layout.ResizeHandle test

              + +

              Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nam facilisis enim. + Pellentesque in elit et lacus euismod dignissim. Aliquam dolor pede, convallis eget, + dictum a, blandit ac, urna. Pellentesque sed nunc ut justo volutpat egestas. Class + aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. + In erat. Suspendisse potenti. Fusce faucibus nibh sed nisi. Phasellus faucibus, dui + a cursus dapibus, mauris nulla euismod velit, a lobortis turpis arcu vel dui. Pellentesque + fermentum ultrices pede. Donec auctor lectus eu arcu. Curabitur non orci eget est porta gravida. + Aliquam pretium orci id nisi. Duis faucibus, mi non adipiscing venenatis, erat urna aliquet elit, + eu fringilla lacus tellus quis erat. Nam tempus ornare lorem. Nullam feugiat.

              + +

              Sed congue. Aenean blandit sollicitudin mi. Maecenas pellentesque. Vivamus ac urna. Nunc consequat nisi vitae quam. Suspendisse sed nunc. Proin suscipit porta magna. Duis accumsan nunc in velit. Nam et nibh. Nulla facilisi. Cras venenatis urna et magna. Aenean magna mauris, bibendum sit amet, semper quis, aliquet nec, sapien. Aliquam aliquam odio quis erat. Etiam est nisi, condimentum non, lacinia ac, vehicula laoreet, elit. Sed interdum augue sit amet quam dapibus semper. Nulla facilisi. Pellentesque lobortis erat nec quam.

              + + + +
              This is text!
              +

              +
              + + + Content Pane w/a resize handle. activeResize'ing only on layout Widgets? FIXME: :) +
              +
              + +
              + +
              + + Plain div w/a resize handle. All Default settings. +
              +
              + +

              + +
              + Plain div w/a resize handle but resizeAxis="y", and activeResize="true" +
              +
              + + +
              + Plain div w/a resize handle but resizeAxis="x" with animated sizing. +
              +
              + +

              + +
              + Plain div w/a resize handle but resizeAxis="xy" with animated sizing (combine). +
              +
              + +

              + +

              Sed arcu magna, molestie at, fringilla in, sodales eu, elit. Curabitur mattis lorem et est. Quisque et tortor. Integer bibendum vulputate odio. Nam nec ipsum. Vestibulum mollis eros feugiat augue. Integer fermentum odio lobortis odio. Nullam mollis nisl non metus. Maecenas nec nunc eget pede ultrices blandit. Ut non purus ut elit convallis eleifend. Fusce tincidunt, justo quis tempus euismod, magna nulla viverra libero, sit amet lacinia odio diam id risus. Ut varius viverra turpis. Morbi urna elit, imperdiet eu, porta ac, pharetra sed, nisi. Etiam ante libero, ultrices ac, faucibus ac, cursus sodales, nisl. Praesent nisl sem, fermentum eu, consequat quis, varius interdum, nulla. Donec neque tortor, sollicitudin sed, consequat nec, facilisis sit amet, orci. Aenean ut eros sit amet ante pharetra interdum.

              + +

              Fusce rutrum pede eget quam. Praesent purus. Aenean at elit in sem volutpat facilisis. Nunc est augue, commodo at, pretium a, fermentum at, quam. Nam sit amet enim. Suspendisse potenti. Cras hendrerit rhoncus justo. Integer libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Sed adipiscing mi vel ipsum.

              + +

              Sed aliquam, quam consectetuer condimentum bibendum, neque libero commodo metus, non consectetuer magna risus vitae eros. Pellentesque mollis augue id libero. Morbi nonummy hendrerit dui. Morbi nisi felis, fringilla ac, euismod vitae, dictum mollis, pede. Integer suscipit, est sed posuere ullamcorper, ipsum lectus interdum nunc, quis blandit erat eros hendrerit pede. Vestibulum varius, elit id mattis mattis, nulla est feugiat ante, eget vestibulum augue eros ut odio. Maecenas euismod purus quis felis. Ut hendrerit tincidunt est. Fusce euismod, nunc eu tempus tempor, purus ligula volutpat tellus, nec lacinia sapien enim id risus. Aliquam orci turpis, condimentum sed, sollicitudin vel, placerat in, purus. Proin tortor nisl, blandit quis, imperdiet quis, scelerisque at, nisl. Maecenas suscipit fringilla erat. Curabitur consequat, dui blandit suscipit dictum, felis lectus imperdiet tellus, sit amet ornare risus mauris non ipsum. Fusce a purus. Vestibulum sodales. Sed porta ultrices nibh. Vestibulum metus.

              + + + diff --git a/includes/js/dojox/layout/tests/test_ScrollPane.html b/includes/js/dojox/layout/tests/test_ScrollPane.html new file mode 100644 index 0000000..53a4a26 --- /dev/null +++ b/includes/js/dojox/layout/tests/test_ScrollPane.html @@ -0,0 +1,129 @@ + + + + + ScrollPane layout widget Test + + + + + + + + + + + +

              dojox.layout.ScrollPane

              + +

              An intuitive UI for lists of data in a confined space. supports horizontal or vertical "scrolling", but not both

              + +

              vertical:

              +
              + +
              +
                +
              1. testItem
              2. +
              +
              +
              +
              + +
              +
                +
                + +
                + +
                + +

                horizontal

                +
                + + + + + + + + + + + + + + + + + + + + + + +
                LOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUMLOREM IPSUM
                +
                + +

                In a layoutContainer:

                + +
                +
                +
                  +
                  +
                  +

                  Foo!

                  +
                  +
                  + +

                  Programatically:

                  + +
                  +
                    +
                    + + + diff --git a/includes/js/dojox/layout/tests/test_ScrollPaneSingle.html b/includes/js/dojox/layout/tests/test_ScrollPaneSingle.html new file mode 100644 index 0000000..3957fda --- /dev/null +++ b/includes/js/dojox/layout/tests/test_ScrollPaneSingle.html @@ -0,0 +1,71 @@ + + + + + ScrollPane layout widget Test + + + + + + + + + + +
                    +

                    dojox.layout.ScrollPane

                    +

                    horizontal

                    +
                    +
                    +
                    +

                    Foo!

                    text

                    • bar
                    • bar

                    +
                    +
                    +
                    +
                    + + diff --git a/includes/js/dojox/layout/tests/test_SizingPane.html b/includes/js/dojox/layout/tests/test_SizingPane.html new file mode 100644 index 0000000..372f396 --- /dev/null +++ b/includes/js/dojox/layout/tests/test_SizingPane.html @@ -0,0 +1,170 @@ + + + + dojox.layout.SizingPane + + + + + + + + + +

                    dojox.layout.SizingPane

                    + +

                    This is simply a test / example. There is no real dojox.layout.SizingPane, but this code + should/might become part of a dojox.fx.toggle class ... it's just "neat", isn't it?

                    + +
                    + lorem. lorem. lorem. +
                    + + + + diff --git a/includes/js/dojox/math.js b/includes/js/dojox/math.js new file mode 100644 index 0000000..a1ab261 --- /dev/null +++ b/includes/js/dojox/math.js @@ -0,0 +1,6 @@ +if(!dojo._hasResource["dojox.math"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.math"] = true; +dojo.provide("dojox.math"); +dojo.require("dojox.math._base"); + +} diff --git a/includes/js/dojox/math/README b/includes/js/dojox/math/README new file mode 100644 index 0000000..f9f50ad --- /dev/null +++ b/includes/js/dojox/math/README @@ -0,0 +1,38 @@ +------------------------------------------------------------------------------- +DojoX Math +------------------------------------------------------------------------------- +Version 0.9 +Release date: 10/20/2007 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + Cal Henderson + Dan Pupius + Tom Trenka (ttrenka AT gmail.com) +------------------------------------------------------------------------------- +Project description + +A port of the main functionality of dojo.math 0.4. Includes advanced math +functions, abstract curve definitions, and some point calculations. +------------------------------------------------------------------------------- +Dependencies: + +Depends on the Dojo Core, v1.0 +------------------------------------------------------------------------------- +Documentation + +See the API documentation. +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/math.js +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/math/* + +Install into the following directory structure: +/dojox/math/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- diff --git a/includes/js/dojox/math/_base.js b/includes/js/dojox/math/_base.js new file mode 100644 index 0000000..ef2243c --- /dev/null +++ b/includes/js/dojox/math/_base.js @@ -0,0 +1,122 @@ +if(!dojo._hasResource["dojox.math._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.math._base"] = true; +dojo.provide("dojox.math._base"); + +dojo.mixin(dojox.math, { + degreesToRadians: function(/* Number */n){ + // summary + // Convert the passed number to radians. + return (n*Math.PI)/180; // Number + }, + radiansToDegrees: function(/* Number */n){ + // summary + // Convert the passed number to degrees. + return (n*180)/Math.PI; // Number + }, + + factoral: function(/* Number */n){ + // summary + // Return the factoral of n. + if(n<1){ + return 0; // Number + } + var ret=1; + for(var i=1; i<=n; i++){ + ret*=i; + } + return ret; // Number + }, + permutations: function(/* Number */n, /* Number */k){ + // summary + // TODO + if(n==0 || k==0){ + return 1; // Number + } + return (this.factoral(n)/this.factoral(n-k)); + }, + combinations: function(/* Number */n, /* Number */r){ + // summary + // TODO + if(n==0 || r==0){ + return 1; // Number + } + return (this.factoral(n)/(this.factoral(n-r)*this.factoral(r))); // Number + }, + bernstein: function(/* Number */t, /* Number */n, /* Number */ i){ + // summary + // TODO + return (this.combinations(n, i)*Math.pow(t, i)*Math.pow(1-t, n-i)); // Number + }, + gaussian: function(){ + // summary + // Return a random number based on the Gaussian algo. + var k=2; + do{ + var i=2*Math.random()-1; + var j=2*Math.random()-1; + k = i*i+j*j; + }while(k>=1); + return (i * Math.sqrt((-2*Math.log(k))/k)); // Number + }, + + // basic statistics + sd: function(/* Array */a){ + // summary + // Returns the standard deviation of the passed arguments. + return Math.sqrt(this.variance(a)); // Number + }, + variance: function(/* Array */a){ + // summary + // Find the variance in the passed array of numbers. + var mean=0, squares=0; + dojo.forEach(a, function(item){ + mean+=item; + squares+=Math.pow(item,2); + }); + return (squares/a.length)-Math.pow(mean/a.length, 2); // Number + }, + + // create a range of numbers + range: function(/* Number */a, /* Number? */b, /* Number? */step){ + // summary + // Create a range of numbers based on the parameters. + if(arguments.length<2){ + b=a,a=0; + } + var s=step||1; + var range=[]; + if(s>0){ + for(var i=a; ib; i+=s){ + range.push(i); + } + }else{ + throw new Error("dojox.math.range: step must not be zero."); + } + } + return range; // Array + }, + distance: function(/* Array */a, /* Array */b){ + // summary + // Calculate the distance between point A and point B + return Math.sqrt(Math.pow(b[0]-a[0],2)+Math.pow(b[1]-a[1],2)); // Number + }, + midpoint: function(/* Array */a, /* Array */b){ + // summary + // Calculate the midpoint between points A and B. A and B may be multidimensional. + if(a.length!=b.length){ + console.error("dojox.math.midpoint: Points A and B are not the same dimensionally.", a, b); + } + var m=[]; + for(var i=0; i= 1) { + return this.p[this.p.length - 1]; + } + if (step <= 0) { + return this.p[0]; + } + var retVal = new Array(this.p[0].length); + for (var k = 0; j < this.p[0].length; k++) { + retVal[k] = 0; + } + for (var j = 0; j < this.p[0].length; j++) { + var C = 0; + var D = 0; + for (var i = 0; i < this.p.length; i++) { + C += this.p[i][j] * this.p[this.p.length - 1][0] * dojox.math.bernstein(step, this.p.length, i); + } + for (var l = 0; l < this.p.length; l++) { + D += this.p[this.p.length - 1][0] * dojox.math.bernstein(step, this.p.length, l); + } + retVal[j] = C / D; + } + return retVal; + }; + this.p = pnts; + return this; + }, + CatmullRom:function (pnts, c) { + this.getValue = function (step) { + var percent = step * (this.p.length - 1); + var node = Math.floor(percent); + var progress = percent - node; + var i0 = node - 1; + if (i0 < 0) { + i0 = 0; + } + var i = node; + var i1 = node + 1; + if (i1 >= this.p.length) { + i1 = this.p.length - 1; + } + var i2 = node + 2; + if (i2 >= this.p.length) { + i2 = this.p.length - 1; + } + var u = progress; + var u2 = progress * progress; + var u3 = progress * progress * progress; + var retVal = new Array(this.p[0].length); + for (var k = 0; k < this.p[0].length; k++) { + var x1 = (-this.c * this.p[i0][k]) + ((2 - this.c) * this.p[i][k]) + ((this.c - 2) * this.p[i1][k]) + (this.c * this.p[i2][k]); + var x2 = (2 * this.c * this.p[i0][k]) + ((this.c - 3) * this.p[i][k]) + ((3 - 2 * this.c) * this.p[i1][k]) + (-this.c * this.p[i2][k]); + var x3 = (-this.c * this.p[i0][k]) + (this.c * this.p[i1][k]); + var x4 = this.p[i][k]; + retVal[k] = x1 * u3 + x2 * u2 + x3 * u + x4; + } + return retVal; + }; + if (!c) { + this.c = 0.7; + } else { + this.c = c; + } + this.p = pnts; + return this; + }, + Arc:function (start, end, ccw){ + function translate(a,b){ + var c=new Array(a.length); + for(var i=0; i= r[0] && n < r[1]) { + var subN = (n - r[0]) / r[2]; + value = curves[i].getValue(subN); + found = true; + break; + } + } + if (!found) { + value = curves[curves.length - 1].getValue(1); + } + for (var j = 0; j < i; j++) { + value = dojox.math.points.translate(value, curves[j].getValue(1)); + } + return value; + }; + function computeRanges() { + var start = 0; + for (var i = 0; i < weights.length; i++) { + var end = start + weights[i] / totalWeight; + var len = end - start; + ranges[i] = [start, end, len]; + start = end; + } + } + return this; + } +}); + +} diff --git a/includes/js/dojox/math/matrix.js b/includes/js/dojox/math/matrix.js new file mode 100644 index 0000000..386bad3 --- /dev/null +++ b/includes/js/dojox/math/matrix.js @@ -0,0 +1,294 @@ +if(!dojo._hasResource["dojox.math.matrix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.math.matrix"] = true; +dojo.provide("dojox.math.matrix"); + +dojo.mixin(dojox.math.matrix, { + iDF:0, + ALMOST_ZERO: 1e-10, + multiply: function(/* Array */a, /* Array */b){ + // summary + // Multiply matrix a by matrix b. + var ay=a.length, ax=a[0].length, by=b.length, bx=b[0].length; + if(ax!=by){ + console.warn("Can't multiply matricies of sizes " + ax + "," + ay + " and " + bx + "," + by); + return [[0]]; + } + var c=[]; + for (var k=0; k-1){ + b+="."; + } + while(b.length0?a[0].length:0; + var buffer=""; + for(var y=0; y + +

                    Browser Bookmarklets

                    + +

                    Drag the following bookmarklets to your links toolbar and press to clear the Google Gears cache:

                    + +

                    Firefox: Clear Gears Cache

                    +

                    Internet Explorer: Clear Gears Cache

                    + + diff --git a/includes/js/dojox/off/files.js b/includes/js/dojox/off/files.js new file mode 100644 index 0000000..6c19ea0 --- /dev/null +++ b/includes/js/dojox/off/files.js @@ -0,0 +1,454 @@ +if(!dojo._hasResource["dojox.off.files"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.off.files"] = true; +dojo.provide("dojox.off.files"); + +// Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org + +// summary: +// Helps maintain resources that should be +// available offline, such as CSS files. +// description: +// dojox.off.files makes it easy to indicate +// what resources should be available offline, +// such as CSS files, JavaScript, HTML, etc. +dojox.off.files = { + // versionURL: String + // An optional file, that if present, records the version + // of our bundle of files to make available offline. If this + // file is present, and we are not currently debugging, + // then we only refresh our offline files if the version has + // changed. + versionURL: "version.js", + + // listOfURLs: Array + // For advanced usage; most developers can ignore this. + // Our list of URLs that will be cached and made available + // offline. + listOfURLs: [], + + // refreshing: boolean + // For advanced usage; most developers can ignore this. + // Whether we are currently in the middle + // of refreshing our list of offline files. + refreshing: false, + + _cancelID: null, + + _error: false, + _errorMessages: [], + _currentFileIndex: 0, + _store: null, + _doSlurp: false, + + slurp: function(){ + // summary: + // Autoscans the page to find all resources to + // cache. This includes scripts, images, CSS, and hyperlinks + // to pages that are in the same scheme/port/host as this + // page. We also scan the embedded CSS of any stylesheets + // to find @import statements and url()'s. + // You should call this method from the top-level, outside of + // any functions and before the page loads: + // + // + // + // Note that inline styles on elements are not handled (i.e. + // if you somehow have an inline style that uses a URL); + // object and embed tags are not scanned since their format + // differs based on type; and elements created by JavaScript + // after page load are not found. For these you must manually + // add them with a dojox.off.files.cache() method call. + + // just schedule the slurp once the page is loaded and + // Dojo Offline is ready to slurp; dojox.off will call + // our _slurp() method before indicating it is finished + // loading + this._doSlurp = true; + }, + + cache: function(urlOrList){ /* void */ + // summary: + // Caches a file or list of files to be available offline. This + // can either be a full URL, such as http://foobar.com/index.html, + // or a relative URL, such as ../index.html. This URL is not + // actually cached until dojox.off.sync.synchronize() is called. + // urlOrList: String or Array[] + // A URL of a file to cache or an Array of Strings of files to + // cache + + //console.debug("dojox.off.files.cache, urlOrList="+urlOrList); + + if(dojo.isString(urlOrList)){ + var url = this._trimAnchor(urlOrList+""); + if(!this.isAvailable(url)){ + this.listOfURLs.push(url); + } + }else if(urlOrList instanceof dojo._Url){ + var url = this._trimAnchor(urlOrList.uri); + if(!this.isAvailable(url)){ + this.listOfURLs.push(url); + } + }else{ + dojo.forEach(urlOrList, function(url){ + url = this._trimAnchor(url); + if(!this.isAvailable(url)){ + this.listOfURLs.push(url); + } + }, this); + } + }, + + printURLs: function(){ + // summary: + // A helper function that will dump and print out + // all of the URLs that are cached for offline + // availability. This can help with debugging if you + // are trying to make sure that all of your URLs are + // available offline + console.debug("The following URLs are cached for offline use:"); + dojo.forEach(this.listOfURLs, function(i){ + console.debug(i); + }); + }, + + remove: function(url){ /* void */ + // summary: + // Removes a URL from the list of files to cache. + // description: + // Removes a URL from the list of URLs to cache. Note that this + // does not actually remove the file from the offline cache; + // instead, it just prevents us from refreshing this file at a + // later time, so that it will naturally time out and be removed + // from the offline cache + // url: String + // The URL to remove + for(var i = 0; i < this.listOfURLs.length; i++){ + if(this.listOfURLs[i] == url){ + this.listOfURLs = this.listOfURLs.splice(i, 1); + break; + } + } + }, + + isAvailable: function(url){ /* boolean */ + // summary: + // Determines whether the given resource is available offline. + // url: String + // The URL to check + for(var i = 0; i < this.listOfURLs.length; i++){ + if(this.listOfURLs[i] == url){ + return true; + } + } + + return false; + }, + + refresh: function(callback){ /* void */ + //console.debug("dojox.off.files.refresh"); + // summary: + // For advanced usage; most developers can ignore this. + // Refreshes our list of offline resources, + // making them available offline. + // callback: Function + // A callback that receives two arguments: whether an error + // occurred, which is a boolean; and an array of error message strings + // with details on errors encountered. If no error occured then message is + // empty array with length 0. + try{ + if(dojo.config.isDebug){ + this.printURLs(); + } + + this.refreshing = true; + + if(this.versionURL){ + this._getVersionInfo(function(oldVersion, newVersion, justDebugged){ + //console.warn("getVersionInfo, oldVersion="+oldVersion+", newVersion="+newVersion + // + ", justDebugged="+justDebugged+", isDebug="+dojo.config.isDebug); + if(dojo.config.isDebug || !newVersion || justDebugged + || !oldVersion || oldVersion != newVersion){ + console.warn("Refreshing offline file list"); + this._doRefresh(callback, newVersion); + }else{ + console.warn("No need to refresh offline file list"); + callback(false, []); + } + }); + }else{ + console.warn("Refreshing offline file list"); + this._doRefresh(callback); + } + }catch(e){ + this.refreshing = false; + + // can't refresh files -- core operation -- + // fail fast + dojox.off.coreOpFailed = true; + dojox.off.enabled = false; + dojox.off.onFrameworkEvent("coreOperationFailed"); + } + }, + + abortRefresh: function(){ + // summary: + // For advanced usage; most developers can ignore this. + // Aborts and cancels a refresh. + if(!this.refreshing){ + return; + } + + this._store.abortCapture(this._cancelID); + this.refreshing = false; + }, + + _slurp: function(){ + if(!this._doSlurp){ + return; + } + + var handleUrl = dojo.hitch(this, function(url){ + if(this._sameLocation(url)){ + this.cache(url); + } + }); + + handleUrl(window.location.href); + + dojo.query("script").forEach(function(i){ + try{ + handleUrl(i.getAttribute("src")); + }catch(exp){ + //console.debug("dojox.off.files.slurp 'script' error: " + // + exp.message||exp); + } + }); + + dojo.query("link").forEach(function(i){ + try{ + if(!i.getAttribute("rel") + || i.getAttribute("rel").toLowerCase() != "stylesheet"){ + return; + } + + handleUrl(i.getAttribute("href")); + }catch(exp){ + //console.debug("dojox.off.files.slurp 'link' error: " + // + exp.message||exp); + } + }); + + dojo.query("img").forEach(function(i){ + try{ + handleUrl(i.getAttribute("src")); + }catch(exp){ + //console.debug("dojox.off.files.slurp 'img' error: " + // + exp.message||exp); + } + }); + + dojo.query("a").forEach(function(i){ + try{ + handleUrl(i.getAttribute("href")); + }catch(exp){ + //console.debug("dojox.off.files.slurp 'a' error: " + // + exp.message||exp); + } + }); + + // FIXME: handle 'object' and 'embed' tag + + // parse our style sheets for inline URLs and imports + dojo.forEach(document.styleSheets, function(sheet){ + try{ + if(sheet.cssRules){ // Firefox + dojo.forEach(sheet.cssRules, function(rule){ + var text = rule.cssText; + if(text){ + var matches = text.match(/url\(\s*([^\) ]*)\s*\)/i); + if(!matches){ + return; + } + + for(var i = 1; i < matches.length; i++){ + handleUrl(matches[i]) + } + } + }); + }else if(sheet.cssText){ // IE + var matches; + var text = sheet.cssText.toString(); + // unfortunately, using RegExp.exec seems to be flakey + // for looping across multiple lines on IE using the + // global flag, so we have to simulate it + var lines = text.split(/\f|\r|\n/); + for(var i = 0; i < lines.length; i++){ + matches = lines[i].match(/url\(\s*([^\) ]*)\s*\)/i); + if(matches && matches.length){ + handleUrl(matches[1]); + } + } + } + }catch(exp){ + //console.debug("dojox.off.files.slurp stylesheet parse error: " + // + exp.message||exp); + } + }); + + //this.printURLs(); + }, + + _sameLocation: function(url){ + if(!url){ return false; } + + // filter out anchors + if(url.length && url.charAt(0) == "#"){ + return false; + } + + // FIXME: dojo._Url should be made public; + // it's functionality is very useful for + // parsing URLs correctly, which is hard to + // do right + url = new dojo._Url(url); + + // totally relative -- ../../someFile.html + if(!url.scheme && !url.port && !url.host){ + return true; + } + + // scheme relative with port specified -- brad.com:8080 + if(!url.scheme && url.host && url.port + && window.location.hostname == url.host + && window.location.port == url.port){ + return true; + } + + // scheme relative with no-port specified -- brad.com + if(!url.scheme && url.host && !url.port + && window.location.hostname == url.host + && window.location.port == 80){ + return true; + } + + // else we have everything + return window.location.protocol == (url.scheme + ":") + && window.location.hostname == url.host + && (window.location.port == url.port || !window.location.port && !url.port); + }, + + _trimAnchor: function(url){ + return url.replace(/\#.*$/, ""); + }, + + _doRefresh: function(callback, newVersion){ + // get our local server + var localServer; + try{ + localServer = google.gears.factory.create("beta.localserver", "1.0"); + }catch(exp){ + dojo.setObject("google.gears.denied", true); + dojox.off.onFrameworkEvent("coreOperationFailed"); + throw "Google Gears must be allowed to run"; + } + + var storeName = "dot_store_" + + window.location.href.replace(/[^0-9A-Za-z_]/g, "_"); + + // clip at 64 characters, the max length of a resource store name + if(storeName.length >= 64){ + storeName = storeName.substring(0, 63); + } + + // refresh everything by simply removing + // any older stores + localServer.removeStore(storeName); + + // open/create the resource store + localServer.openStore(storeName); + var store = localServer.createStore(storeName); + this._store = store; + + // add our list of files to capture + var self = this; + this._currentFileIndex = 0; + this._cancelID = store.capture(this.listOfURLs, function(url, success, captureId){ + //console.debug("store.capture, url="+url+", success="+success); + if(!success && self.refreshing){ + self._cancelID = null; + self.refreshing = false; + var errorMsgs = []; + errorMsgs.push("Unable to capture: " + url); + callback(true, errorMsgs); + return; + }else if(success){ + self._currentFileIndex++; + } + + if(success && self._currentFileIndex >= self.listOfURLs.length){ + self._cancelID = null; + self.refreshing = false; + if(newVersion){ + dojox.storage.put("oldVersion", newVersion, null, + dojox.off.STORAGE_NAMESPACE); + } + dojox.storage.put("justDebugged", dojo.config.isDebug, null, + dojox.off.STORAGE_NAMESPACE); + callback(false, []); + } + }); + }, + + _getVersionInfo: function(callback){ + var justDebugged = dojox.storage.get("justDebugged", + dojox.off.STORAGE_NAMESPACE); + var oldVersion = dojox.storage.get("oldVersion", + dojox.off.STORAGE_NAMESPACE); + var newVersion = null; + + callback = dojo.hitch(this, callback); + + dojo.xhrGet({ + url: this.versionURL + "?browserbust=" + new Date().getTime(), + timeout: 5 * 1000, + handleAs: "javascript", + error: function(err){ + //console.warn("dojox.off.files._getVersionInfo, err=",err); + dojox.storage.remove("oldVersion", dojox.off.STORAGE_NAMESPACE); + dojox.storage.remove("justDebugged", dojox.off.STORAGE_NAMESPACE); + callback(oldVersion, newVersion, justDebugged); + }, + load: function(data){ + //console.warn("dojox.off.files._getVersionInfo, load=",data); + + // some servers incorrectly return 404's + // as a real page + if(data){ + newVersion = data; + } + + callback(oldVersion, newVersion, justDebugged); + } + }); + } +} + +} diff --git a/includes/js/dojox/off/network_check.txt b/includes/js/dojox/off/network_check.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/includes/js/dojox/off/network_check.txt @@ -0,0 +1 @@ +1 diff --git a/includes/js/dojox/off/offline.js b/includes/js/dojox/off/offline.js new file mode 100644 index 0000000..997206e --- /dev/null +++ b/includes/js/dojox/off/offline.js @@ -0,0 +1,20 @@ +/* + Copyright (c) 2004-2008, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/book/dojo-book-0-9/introduction/licensing +*/ + +/* + This is a compiled version of Dojo, built for deployment and not for + development. To get an editable version, please visit: + + http://dojotoolkit.org + + for documentation and information on getting the source. +*/ + +if(!dojo._hasResource["dojox.storage.Provider"]){dojo._hasResource["dojox.storage.Provider"]=true;dojo.provide("dojox.storage.Provider");dojo.declare("dojox.storage.Provider",null,{constructor:function(){},SUCCESS:"success",FAILED:"failed",PENDING:"pending",SIZE_NOT_AVAILABLE:"Size not available",SIZE_NO_LIMIT:"No size limit",DEFAULT_NAMESPACE:"default",onHideSettingsUI:null,initialize:function(){console.warn("dojox.storage.initialize not implemented");},isAvailable:function(){console.warn("dojox.storage.isAvailable not implemented");},put:function(_1,_2,_3,_4){console.warn("dojox.storage.put not implemented");},get:function(_5,_6){console.warn("dojox.storage.get not implemented");},hasKey:function(_7,_8){return !!this.get(_7,_8);},getKeys:function(_9){console.warn("dojox.storage.getKeys not implemented");},clear:function(_a){console.warn("dojox.storage.clear not implemented");},remove:function(_b,_c){console.warn("dojox.storage.remove not implemented");},getNamespaces:function(){console.warn("dojox.storage.getNamespaces not implemented");},isPermanent:function(){console.warn("dojox.storage.isPermanent not implemented");},getMaximumSize:function(){console.warn("dojox.storage.getMaximumSize not implemented");},putMultiple:function(_d,_e,_f,_10){console.warn("dojox.storage.putMultiple not implemented");},getMultiple:function(_11,_12){console.warn("dojox.storage.getMultiple not implemented");},removeMultiple:function(_13,_14){console.warn("dojox.storage.remove not implemented");},isValidKeyArray:function(_15){if(_15===null||_15===undefined||!dojo.isArray(_15)){return false;}return !dojo.some(_15,function(key){return !this.isValidKey(key);});},hasSettingsUI:function(){return false;},showSettingsUI:function(){console.warn("dojox.storage.showSettingsUI not implemented");},hideSettingsUI:function(){console.warn("dojox.storage.hideSettingsUI not implemented");},isValidKey:function(_17){if(_17===null||_17===undefined){return false;}return /^[0-9A-Za-z_]*$/.test(_17);},getResourceList:function(){return [];}});}if(!dojo._hasResource["dojox.storage.manager"]){dojo._hasResource["dojox.storage.manager"]=true;dojo.provide("dojox.storage.manager");dojox.storage.manager=new function(){this.currentProvider=null;this.available=false;this.providers=[];this._initialized=false;this._onLoadListeners=[];this.initialize=function(){this.autodetect();};this.register=function(_18,_19){this.providers.push(_19);this.providers[_18]=_19;};this.setProvider=function(_1a){};this.autodetect=function(){if(this._initialized){return;}var _1b=dojo.config["forceStorageProvider"]||false;var _1c;for(var i=0;i6&&i%Nk==4){_60=SubWord(_60);}}for(var t=0;t<4;t++){w[i][t]=w[i-Nk][t]^_60[t];}}return w;};function SubWord(w){for(var i=0;i<4;i++){w[i]=_3c[w[i]];}return w;};function RotWord(w){w[4]=w[0];for(var i=0;i<4;i++){w[i]=w[i+1];}return w;};function AESEncryptCtr(_68,_69,_6a){if(!(_6a==128||_6a==192||_6a==256)){return "";}var _6b=_6a/8;var _6c=new Array(_6b);for(var i=0;i<_6b;i++){_6c[i]=_69.charCodeAt(i)&255;}var key=Cipher(_6c,KeyExpansion(_6c));key=key.concat(key.slice(0,_6b-16));var _6f=16;var _70=new Array(_6f);var _71=(new Date()).getTime();for(var i=0;i<4;i++){_70[i]=(_71>>>i*8)&255;}for(var i=0;i<4;i++){_70[i+4]=(_71/4294967296>>>i*8)&255;}var _72=KeyExpansion(key);var _73=Math.ceil(_68.length/_6f);var _74=new Array(_73);for(var b=0;b<_73;b++){for(var c=0;c<4;c++){_70[15-c]=(b>>>c*8)&255;}for(var c=0;c<4;c++){_70[15-c-4]=(b/4294967296>>>c*8);}var _77=Cipher(_70,_72);var _78=b<_73-1?_6f:(_68.length-1)%_6f+1;var ct="";for(var i=0;i<_78;i++){var _7a=_68.charCodeAt(b*_6f+i);var _7b=_7a^_77[i];ct+=String.fromCharCode(_7b);}_74[b]=escCtrlChars(ct);}var _7c="";for(var i=0;i<8;i++){_7c+=String.fromCharCode(_70[i]);}_7c=escCtrlChars(_7c);return _7c+"-"+_74.join("-");};function AESDecryptCtr(_7d,_7e,_7f){if(!(_7f==128||_7f==192||_7f==256)){return "";}var _80=_7f/8;var _81=new Array(_80);for(var i=0;i<_80;i++){_81[i]=_7e.charCodeAt(i)&255;}var _83=KeyExpansion(_81);var key=Cipher(_81,_83);key=key.concat(key.slice(0,_80-16));var _85=KeyExpansion(key);_7d=_7d.split("-");var _86=16;var _87=new Array(_86);var _88=unescCtrlChars(_7d[0]);for(var i=0;i<8;i++){_87[i]=_88.charCodeAt(i);}var _89=new Array(_7d.length-1);for(var b=1;b<_7d.length;b++){for(var c=0;c<4;c++){_87[15-c]=((b-1)>>>c*8)&255;}for(var c=0;c<4;c++){_87[15-c-4]=((b/4294967296-1)>>>c*8)&255;}var _8c=Cipher(_87,_85);_7d[b]=unescCtrlChars(_7d[b]);var pt="";for(var i=0;i<_7d[b].length;i++){var _8e=_7d[b].charCodeAt(i);var _8f=_8e^_8c[i];pt+=String.fromCharCode(_8f);}_89[b-1]=pt;}return _89.join("");};function escCtrlChars(str){return str.replace(/[\0\t\n\v\f\r\xa0!-]/g,function(c){return "!"+c.charCodeAt(0)+"!";});};function unescCtrlChars(str){return str.replace(/!\d\d?\d?!/g,function(c){return String.fromCharCode(c.slice(1,-1));});};function encrypt(_94,_95){return AESEncryptCtr(_94,_95,256);};function decrypt(_96,_97){return AESDecryptCtr(_96,_97,256);};var cmd=msg.substr(0,4);var arg=msg.substr(5);if(cmd=="encr"){arg=eval("("+arg+")");var _9a=arg.plaintext;var _9b=arg.password;var _9c=encrypt(_9a,_9b);gearsWorkerPool.sendMessage(String(_9c),_3b);}else{if(cmd=="decr"){arg=eval("("+arg+")");var _9d=arg.ciphertext;var _9b=arg.password;var _9c=decrypt(_9d,_9b);gearsWorkerPool.sendMessage(String(_9c),_3b);}}}});}if(!dojo._hasResource["dojox._sql.common"]){dojo._hasResource["dojox._sql.common"]=true;dojo.provide("dojox._sql.common");dojox.sql=new Function("return dojox.sql._exec(arguments);");dojo.mixin(dojox.sql,{dbName:null,debug:(dojo.exists("dojox.sql.debug")?dojox.sql.debug:false),open:function(_9e){if(this._dbOpen&&(!_9e||_9e==this.dbName)){return;}if(!this.dbName){this.dbName="dot_store_"+window.location.href.replace(/[^0-9A-Za-z_]/g,"_");if(this.dbName.length>63){this.dbName=this.dbName.substring(0,63);}}if(!_9e){_9e=this.dbName;}try{this._initDb();this.db.open(_9e);this._dbOpen=true;}catch(exp){throw exp.message||exp;}},close:function(_9f){if(dojo.isIE){return;}if(!this._dbOpen&&(!_9f||_9f==this.dbName)){return;}if(!_9f){_9f=this.dbName;}try{this.db.close(_9f);this._dbOpen=false;}catch(exp){throw exp.message||exp;}},_exec:function(_a0){try{this._initDb();if(!this._dbOpen){this.open();this._autoClose=true;}var sql=null;var _a2=null;var _a3=null;var _a4=dojo._toArray(_a0);sql=_a4.splice(0,1)[0];if(this._needsEncrypt(sql)||this._needsDecrypt(sql)){_a2=_a4.splice(_a4.length-1,1)[0];_a3=_a4.splice(_a4.length-1,1)[0];}if(this.debug){this._printDebugSQL(sql,_a4);}if(this._needsEncrypt(sql)){var _a5=new dojox.sql._SQLCrypto("encrypt",sql,_a3,_a4,_a2);return;}else{if(this._needsDecrypt(sql)){var _a5=new dojox.sql._SQLCrypto("decrypt",sql,_a3,_a4,_a2);return;}}var rs=this.db.execute(sql,_a4);rs=this._normalizeResults(rs);if(this._autoClose){this.close();}return rs;}catch(exp){exp=exp.message||exp;console.debug("SQL Exception: "+exp);if(this._autoClose){try{this.close();}catch(e){console.debug("Error closing database: "+e.message||e);}}throw exp;}},_initDb:function(){if(!this.db){try{this.db=google.gears.factory.create("beta.database","1.0");}catch(exp){dojo.setObject("google.gears.denied",true);dojox.off.onFrameworkEvent("coreOperationFailed");throw "Google Gears must be allowed to run";}}},_printDebugSQL:function(sql,_a8){var msg="dojox.sql(\""+sql+"\"";for(var i=0;i<_a8.length;i++){if(typeof _a8[i]=="string"){msg+=", \""+_a8[i]+"\"";}else{msg+=", "+_a8[i];}}msg+=")";console.debug(msg);},_normalizeResults:function(rs){var _ac=[];if(!rs){return [];}while(rs.isValidRow()){var row={};for(var i=0;i=this._totalCrypto&&this._finishedSpawningCrypto){_d3(this._finalArgs);}}));}}this._finishedSpawningCrypto=true;},_decrypt:function(_d8,_d9,_da,_db){this._totalCrypto=0;this._finishedCrypto=0;this._finishedSpawningCrypto=false;this._finalResultSet=_d8;for(var i=0;i<_d8.length;i++){var row=_d8[i];for(var _de in row){if(_d9=="*"||_d9[_de]){this._totalCrypto++;var _df=row[_de];this._decryptSingleColumn(_de,_df,_da,i,function(_e0){_db(_e0);});}}}this._finishedSpawningCrypto=true;},_stripCryptoSQL:function(sql){sql=sql.replace(/DECRYPT\(\*\)/ig,"*");var _e2=sql.match(/ENCRYPT\([^\)]*\)/ig);if(_e2!=null){for(var i=0;i<_e2.length;i++){var _e4=_e2[i];var _e5=_e4.match(/ENCRYPT\(([^\)]*)\)/i)[1];sql=sql.replace(_e4,_e5);}}_e2=sql.match(/DECRYPT\([^\)]*\)/ig);if(_e2!=null){for(var i=0;i<_e2.length;i++){var _e6=_e2[i];var _e7=_e6.match(/DECRYPT\(([^\)]*)\)/i)[1];sql=sql.replace(_e6,_e7);}}return sql;},_flagEncryptedArgs:function(sql,_e9){var _ea=new RegExp(/([\"][^\"]*\?[^\"]*[\"])|([\'][^\']*\?[^\']*[\'])|(\?)/ig);var _eb;var _ec=0;var _ed=[];while((_eb=_ea.exec(sql))!=null){var _ee=RegExp.lastMatch+"";if(/^[\"\']/.test(_ee)){continue;}var _ef=false;if(/ENCRYPT\([^\)]*$/i.test(RegExp.leftContext)){_ef=true;}_ed[_ec]=_ef;_ec++;}return _ed;},_determineDecryptedColumns:function(sql){var _f1={};if(/DECRYPT\(\*\)/i.test(sql)){_f1="*";}else{var _f2=/DECRYPT\((?:\s*\w*\s*\,?)*\)/ig;var _f3;while(_f3=_f2.exec(sql)){var _f4=new String(RegExp.lastMatch);var _f5=_f4.replace(/DECRYPT\(/i,"");_f5=_f5.replace(/\)/,"");_f5=_f5.split(/\s*,\s*/);dojo.forEach(_f5,function(_f6){if(/\s*\w* AS (\w*)/i.test(_f6)){_f6=_f6.match(/\s*\w* AS (\w*)/i)[1];}_f1[_f6]=true;});}}return _f1;},_decryptSingleColumn:function(_f7,_f8,_f9,_fa,_fb){dojox._sql._crypto.decrypt(_f8,_f9,dojo.hitch(this,function(_fc){this._finalResultSet[_fa][_f7]=_fc;this._finishedCrypto++;if(this._finishedCrypto>=this._totalCrypto&&this._finishedSpawningCrypto){_fb(this._finalResultSet);}}));}});}if(!dojo._hasResource["dojox.sql"]){dojo._hasResource["dojox.sql"]=true;dojo.provide("dojox.sql");}if(!dojo._hasResource["dojox.storage.GearsStorageProvider"]){dojo._hasResource["dojox.storage.GearsStorageProvider"]=true;dojo.provide("dojox.storage.GearsStorageProvider");if(dojo.isGears){(function(){dojo.declare("dojox.storage.GearsStorageProvider",dojox.storage.Provider,{constructor:function(){},TABLE_NAME:"__DOJO_STORAGE",initialized:false,_available:null,initialize:function(){if(dojo.config["disableGearsStorage"]==true){return;}this.TABLE_NAME="__DOJO_STORAGE";try{dojox.sql("CREATE TABLE IF NOT EXISTS "+this.TABLE_NAME+"( "+" namespace TEXT, "+" key TEXT, "+" value TEXT "+")");dojox.sql("CREATE UNIQUE INDEX IF NOT EXISTS namespace_key_index"+" ON "+this.TABLE_NAME+" (namespace, key)");}catch(e){console.debug("dojox.storage.GearsStorageProvider.initialize:",e);this.initialized=false;dojox.storage.manager.loaded();return;}this.initialized=true;dojox.storage.manager.loaded();},isAvailable:function(){return this._available=dojo.isGears;},put:function(key,_fe,_ff,_100){if(this.isValidKey(key)==false){throw new Error("Invalid key given: "+key);}_100=_100||this.DEFAULT_NAMESPACE;if(dojo.isString(_fe)){_fe="string:"+_fe;}else{_fe=dojo.toJson(_fe);}try{dojox.sql("DELETE FROM "+this.TABLE_NAME+" WHERE namespace = ? AND key = ?",_100,key);dojox.sql("INSERT INTO "+this.TABLE_NAME+" VALUES (?, ?, ?)",_100,key,_fe);}catch(e){console.debug("dojox.storage.GearsStorageProvider.put:",e);_ff(this.FAILED,key,e.toString());return;}if(_ff){_ff(dojox.storage.SUCCESS,key,null);}},get:function(key,_102){if(this.isValidKey(key)==false){throw new Error("Invalid key given: "+key);}_102=_102||this.DEFAULT_NAMESPACE;var _103=dojox.sql("SELECT * FROM "+this.TABLE_NAME+" WHERE namespace = ? AND "+" key = ?",_102,key);if(!_103.length){return null;}else{_103=_103[0].value;}if(dojo.isString(_103)&&(/^string:/.test(_103))){_103=_103.substring("string:".length);}else{_103=dojo.fromJson(_103);}return _103;},getNamespaces:function(){var _104=[dojox.storage.DEFAULT_NAMESPACE];var rs=dojox.sql("SELECT namespace FROM "+this.TABLE_NAME+" DESC GROUP BY namespace");for(var i=0;idew){minw=dew;maxw=dbw;}else{maxw=dew;minw=dbw;}var dbh=_143.body.clientHeight;if(dbh>deh){minh=deh;maxh=dbh;}else{maxh=deh;minh=dbh;}w=(maxw>_142.innerWidth)?minw:maxw;h=(maxh>_142.innerHeight)?minh:maxh;}else{if(!dojo.isOpera&&_142.innerWidth){w=_142.innerWidth;h=_142.innerHeight;}else{if(dojo.isIE&&de&&deh){w=dew;h=deh;}else{if(dojo.body().clientWidth){w=dojo.body().clientWidth;h=dojo.body().clientHeight;}}}}var _14f=dojo._docScroll();return {w:w,h:h,l:_14f.x,t:_14f.y};};dijit.placeOnScreen=function(node,pos,_152,_153){var _154=dojo.map(_152,function(_155){return {corner:_155,pos:pos};});return dijit._place(node,_154);};dijit._place=function(node,_157,_158){var view=dijit.getViewport();if(!node.parentNode||String(node.parentNode.tagName).toLowerCase()!="body"){dojo.body().appendChild(node);}var best=null;dojo.some(_157,function(_15b){var _15c=_15b.corner;var pos=_15b.pos;if(_158){_158(node,_15b.aroundCorner,_15c);}var _15e=node.style;var _15f=_15e.display;var _160=_15e.visibility;_15e.visibility="hidden";_15e.display="";var mb=dojo.marginBox(node);_15e.display=_15f;_15e.visibility=_160;var _162=(_15c.charAt(1)=="L"?pos.x:Math.max(view.l,pos.x-mb.w)),_163=(_15c.charAt(0)=="T"?pos.y:Math.max(view.t,pos.y-mb.h)),endX=(_15c.charAt(1)=="L"?Math.min(view.l+view.w,_162+mb.w):pos.x),endY=(_15c.charAt(0)=="T"?Math.min(view.t+view.h,_163+mb.h):pos.y),_166=endX-_162,_167=endY-_163,_168=(mb.w-_166)+(mb.h-_167);if(best==null||_1680){for(var i=0;i0){for(var i=0;i","Function VBGetSwfVer(i)"," on error resume next"," Dim swControl, swVersion"," swVersion = 0"," set swControl = CreateObject(\"ShockwaveFlash.ShockwaveFlash.\" + CStr(i))"," if (IsObject(swControl)) then"," swVersion = swControl.GetVariable(\"$version\")"," end if"," VBGetSwfVer = swVersion","End Function",""].join("\r\n"));}this._detectVersion();};dojox.flash.Info.prototype={version:-1,versionMajor:-1,versionMinor:-1,versionRevision:-1,capable:false,installing:false,isVersionOrAbove:function(_17a,_17b,_17c){_17c=parseFloat("."+_17c);if(this.versionMajor>=_17a&&this.versionMinor>=_17b&&this.versionRevision>=_17c){return true;}else{return false;}},_detectVersion:function(){var _17d;for(var _17e=25;_17e>0;_17e--){if(dojo.isIE){_17d=VBGetSwfVer(_17e);}else{_17d=this._JSFlashInfo(_17e);}if(_17d==-1){this.capable=false;return;}else{if(_17d!=0){var _17f;if(dojo.isIE){var _180=_17d.split(" ");var _181=_180[1];_17f=_181.split(",");}else{_17f=_17d.split(".");}this.versionMajor=_17f[0];this.versionMinor=_17f[1];this.versionRevision=_17f[2];var _182=this.versionMajor+"."+this.versionRevision;this.version=parseFloat(_182);this.capable=true;break;}}}},_JSFlashInfo:function(_183){if(navigator.plugins!=null&&navigator.plugins.length>0){if(navigator.plugins["Shockwave Flash 2.0"]||navigator.plugins["Shockwave Flash"]){var _184=navigator.plugins["Shockwave Flash 2.0"]?" 2.0":"";var _185=navigator.plugins["Shockwave Flash"+_184].description;var _186=_185.split(" ");var _187=_186[2].split(".");var _188=_187[0];var _189=_187[1];if(_186[3]!=""){var _18a=_186[3].split("r");}else{var _18a=_186[4].split("r");}var _18b=_18a[1]>0?_18a[1]:0;var _18c=_188+"."+_189+"."+_18b;return _18c;}}return -1;}};dojox.flash.Embed=function(_18d){this._visible=_18d;};dojox.flash.Embed.prototype={width:215,height:138,id:"flashObject",_visible:true,protocol:function(){switch(window.location.protocol){case "https:":return "https";break;default:return "http";break;}},write:function(_18e){var _18f="";_18f+=("width: "+this.width+"px; ");_18f+=("height: "+this.height+"px; ");if(!this._visible){_18f+="position: absolute; z-index: 10000; top: -1000px; left: -1000px; ";}var _190;var _191=dojox.flash.url;var _192=_191;var _193=_191;var _194=dojo.baseUrl;if(_18e){var _195=escape(window.location);document.title=document.title.slice(0,47)+" - Flash Player Installation";var _196=escape(document.title);_192+="?MMredirectURL="+_195+"&MMplayerType=ActiveX"+"&MMdoctitle="+_196+"&baseUrl="+escape(_194);_193+="?MMredirectURL="+_195+"&MMplayerType=PlugIn"+"&baseUrl="+escape(_194);}else{_192+="?cachebust="+new Date().getTime();}if(_193.indexOf("?")==-1){_193+="?baseUrl="+escape(_194);}else{_193+="&baseUrl="+escape(_194);}_190="\n "+"\n "+"\n "+"\n "+"\n "+"\n"+"\n";dojo.connect(dojo,"loaded",dojo.hitch(this,function(){var div=document.createElement("div");div.setAttribute("id",this.id+"Container");div.setAttribute("style",_18f);div.innerHTML=_190;var body=document.getElementsByTagName("body");if(!body||!body.length){throw new Error("No body tag for this page");}body=body[0];body.appendChild(div);}));},get:function(){if(dojo.isIE||dojo.isSafari){return document.getElementById(this.id);}else{return document[this.id+"Embed"];}},setVisible:function(_199){var _19a=dojo.byId(this.id+"Container");if(_199==true){_19a.style.position="absolute";_19a.style.visibility="visible";}else{_19a.style.position="absolute";_19a.style.x="-1000px";_19a.style.y="-1000px";_19a.style.visibility="hidden";}},center:function(){var _19b=this.width;var _19c=this.height;var _19d=dijit.getViewport();var x=_19d.l+(_19d.w-_19b)/2;var y=_19d.t+(_19d.h-_19c)/2;var _1a0=dojo.byId(this.id+"Container");_1a0.style.top=y+"px";_1a0.style.left=x+"px";}};dojox.flash.Communicator=function(){};dojox.flash.Communicator.prototype={_addExternalInterfaceCallback:function(_1a1){var _1a2=dojo.hitch(this,function(){var _1a3=new Array(arguments.length);for(var i=0;i/g,">");data=data.replace("\\","&custom_backslash;");data=data.replace(/\0/g,"\\0");data=data.replace(/\"/g,""");return data;},_decodeData:function(data){if(data&&data.length&&typeof data!="string"){data=data[0];}if(!data||typeof data!="string"){return data;}data=data.replace(/\&custom_lt\;/g,"<");data=data.replace(/\&custom_gt\;/g,">");data=data.replace(/\&custom_backslash\;/g,"\\");data=data.replace(/\\0/g,"");return data;},_execFlash:function(_1a9,_1aa){var _1ab=dojox.flash.obj.get();_1aa=(_1aa)?_1aa:[];for(var i=0;i<_1aa;i++){if(typeof _1aa[i]=="string"){_1aa[i]=this._encodeData(_1aa[i]);}}var _1ad=function(){return eval(_1ab.CallFunction(""+__flash__argumentsToXML(_1aa,0)+""));};var _1ae=_1ad.call(_1aa);if(typeof _1ae=="string"){_1ae=this._decodeData(_1ae);}return _1ae;}};dojox.flash.Install=function(){};dojox.flash.Install.prototype={needed:function(){if(dojox.flash.info.capable==false){return true;}if(!dojox.flash.info.isVersionOrAbove(8,0,0)){return true;}return false;},install:function(){dojox.flash.info.installing=true;dojox.flash.installing();if(dojox.flash.info.capable==false){var _1af=new dojox.flash.Embed(false);_1af.write();}else{if(dojox.flash.info.isVersionOrAbove(6,0,65)){var _1af=new dojox.flash.Embed(false);_1af.write(true);_1af.setVisible(true);_1af.center();}else{alert("This content requires a more recent version of the Macromedia "+" Flash Player.");window.location.href=+dojox.flash.Embed.protocol()+"://www.macromedia.com/go/getflashplayer";}}},_onInstallStatus:function(msg){if(msg=="Download.Complete"){dojox.flash._initialize();}else{if(msg=="Download.Cancelled"){alert("This content requires a more recent version of the Macromedia "+" Flash Player.");window.location.href=dojox.flash.Embed.protocol()+"://www.macromedia.com/go/getflashplayer";}else{if(msg=="Download.Failed"){alert("There was an error downloading the Flash Player update. "+"Please try again later, or visit macromedia.com to download "+"the latest version of the Flash plugin.");}}}}};dojox.flash.info=new dojox.flash.Info();}if(!dojo._hasResource["dojox.flash"]){dojo._hasResource["dojox.flash"]=true;dojo.provide("dojox.flash");}if(!dojo._hasResource["dojox.storage.FlashStorageProvider"]){dojo._hasResource["dojox.storage.FlashStorageProvider"]=true;dojo.provide("dojox.storage.FlashStorageProvider");dojo.declare("dojox.storage.FlashStorageProvider",dojox.storage.Provider,{initialized:false,_available:null,_statusHandler:null,_flashReady:false,_pageReady:false,initialize:function(){if(dojo.config["disableFlashStorage"]==true){return;}dojox.flash.addLoadedListener(dojo.hitch(this,function(){this._flashReady=true;if(this._flashReady&&this._pageReady){this._loaded();}}));var _1b1=dojo.moduleUrl("dojox","storage/Storage.swf").toString();dojox.flash.setSwf(_1b1,false);dojo.connect(dojo,"loaded",this,function(){this._pageReady=true;if(this._flashReady&&this._pageReady){this._loaded();}});},setFlushDelay:function(_1b2){if(_1b2===null||typeof _1b2==="undefined"||isNaN(_1b2)){throw new Error("Invalid argunment: "+_1b2);}dojox.flash.comm.setFlushDelay(String(_1b2));},getFlushDelay:function(){return Number(dojox.flash.comm.getFlushDelay());},flush:function(_1b3){if(_1b3==null||typeof _1b3=="undefined"){_1b3=dojox.storage.DEFAULT_NAMESPACE;}dojox.flash.comm.flush(_1b3);},isAvailable:function(){return (this._available=!dojo.config["disableFlashStorage"]);},put:function(key,_1b5,_1b6,_1b7){if(!this.isValidKey(key)){throw new Error("Invalid key given: "+key);}if(!_1b7){_1b7=dojox.storage.DEFAULT_NAMESPACE;}if(!this.isValidKey(_1b7)){throw new Error("Invalid namespace given: "+_1b7);}this._statusHandler=_1b6;if(dojo.isString(_1b5)){_1b5="string:"+_1b5;}else{_1b5=dojo.toJson(_1b5);}dojox.flash.comm.put(key,_1b5,_1b7);},putMultiple:function(keys,_1b9,_1ba,_1bb){if(!this.isValidKeyArray(keys)||!_1b9 instanceof Array||keys.length!=_1b9.length){throw new Error("Invalid arguments: keys = ["+keys+"], values = ["+_1b9+"]");}if(!_1bb){_1bb=dojox.storage.DEFAULT_NAMESPACE;}if(!this.isValidKey(_1bb)){throw new Error("Invalid namespace given: "+_1bb);}this._statusHandler=_1ba;var _1bc=keys.join(",");var _1bd=[];for(var i=0;i<_1b9.length;i++){if(dojo.isString(_1b9[i])){_1b9[i]="string:"+_1b9[i];}else{_1b9[i]=dojo.toJson(_1b9[i]);}_1bd[i]=_1b9[i].length;}var _1bf=_1b9.join("");var _1c0=_1bd.join(",");dojox.flash.comm.putMultiple(_1bc,_1bf,_1c0,this.namespace);},get:function(key,_1c2){if(!this.isValidKey(key)){throw new Error("Invalid key given: "+key);}if(!_1c2){_1c2=dojox.storage.DEFAULT_NAMESPACE;}if(!this.isValidKey(_1c2)){throw new Error("Invalid namespace given: "+_1c2);}var _1c3=dojox.flash.comm.get(key,_1c2);if(_1c3==""){return null;}return this._destringify(_1c3);},getMultiple:function(keys,_1c5){if(!this.isValidKeyArray(keys)){throw new ("Invalid key array given: "+keys);}if(!_1c5){_1c5=dojox.storage.DEFAULT_NAMESPACE;}if(!this.isValidKey(_1c5)){throw new Error("Invalid namespace given: "+_1c5);}var _1c6=keys.join(",");var _1c7=dojox.flash.comm.getMultiple(_1c6,this.namespace);var _1c8=eval("("+_1c7+")");for(var i=0;i<_1c8.length;i++){_1c8[i]=(_1c8[i]=="")?null:this._destringify(_1c8[i]);}return _1c8;},_destringify:function(_1ca){if(dojo.isString(_1ca)&&(/^string:/.test(_1ca))){_1ca=_1ca.substring("string:".length);}else{_1ca=dojo.fromJson(_1ca);}return _1ca;},getKeys:function(_1cb){if(!_1cb){_1cb=dojox.storage.DEFAULT_NAMESPACE;}if(!this.isValidKey(_1cb)){throw new Error("Invalid namespace given: "+_1cb);}var _1cc=dojox.flash.comm.getKeys(_1cb);if(_1cc==null||_1cc=="null"){_1cc="";}_1cc=_1cc.split(",");_1cc.sort();return _1cc;},getNamespaces:function(){var _1cd=dojox.flash.comm.getNamespaces();if(_1cd==null||_1cd=="null"){_1cd=dojox.storage.DEFAULT_NAMESPACE;}_1cd=_1cd.split(",");_1cd.sort();return _1cd;},clear:function(_1ce){if(!_1ce){_1ce=dojox.storage.DEFAULT_NAMESPACE;}if(!this.isValidKey(_1ce)){throw new Error("Invalid namespace given: "+_1ce);}dojox.flash.comm.clear(_1ce);},remove:function(key,_1d0){if(!_1d0){_1d0=dojox.storage.DEFAULT_NAMESPACE;}if(!this.isValidKey(_1d0)){throw new Error("Invalid namespace given: "+_1d0);}dojox.flash.comm.remove(key,_1d0);},removeMultiple:function(keys,_1d2){if(!this.isValidKeyArray(keys)){dojo.raise("Invalid key array given: "+keys);}if(!_1d2){_1d2=dojox.storage.DEFAULT_NAMESPACE;}if(!this.isValidKey(_1d2)){throw new Error("Invalid namespace given: "+_1d2);}var _1d3=keys.join(",");dojox.flash.comm.removeMultiple(_1d3,this.namespace);},isPermanent:function(){return true;},getMaximumSize:function(){return dojox.storage.SIZE_NO_LIMIT;},hasSettingsUI:function(){return true;},showSettingsUI:function(){dojox.flash.comm.showSettings();dojox.flash.obj.setVisible(true);dojox.flash.obj.center();},hideSettingsUI:function(){dojox.flash.obj.setVisible(false);if(dojo.isFunction(dojox.storage.onHideSettingsUI)){dojox.storage.onHideSettingsUI.call(null);}},getResourceList:function(){return [];},_loaded:function(){this._allNamespaces=this.getNamespaces();this.initialized=true;dojox.storage.manager.loaded();},_onStatus:function(_1d4,key,_1d6){var ds=dojox.storage;var dfo=dojox.flash.obj;if(_1d4==ds.PENDING){dfo.center();dfo.setVisible(true);}else{dfo.setVisible(false);}if(ds._statusHandler){ds._statusHandler.call(null,_1d4,key,_1d6);}}});dojox.storage.manager.register("dojox.storage.FlashStorageProvider",new dojox.storage.FlashStorageProvider());}if(!dojo._hasResource["dojox.storage._common"]){dojo._hasResource["dojox.storage._common"]=true;dojo.provide("dojox.storage._common");dojox.storage.manager.initialize();}if(!dojo._hasResource["dojox.storage"]){dojo._hasResource["dojox.storage"]=true;dojo.provide("dojox.storage");}if(!dojo._hasResource["dojox.off.files"]){dojo._hasResource["dojox.off.files"]=true;dojo.provide("dojox.off.files");dojox.off.files={versionURL:"version.js",listOfURLs:[],refreshing:false,_cancelID:null,_error:false,_errorMessages:[],_currentFileIndex:0,_store:null,_doSlurp:false,slurp:function(){this._doSlurp=true;},cache:function(_1d9){if(dojo.isString(_1d9)){var url=this._trimAnchor(_1d9+"");if(!this.isAvailable(url)){this.listOfURLs.push(url);}}else{if(_1d9 instanceof dojo._Url){var url=this._trimAnchor(_1d9.uri);if(!this.isAvailable(url)){this.listOfURLs.push(url);}}else{dojo.forEach(_1d9,function(url){url=this._trimAnchor(url);if(!this.isAvailable(url)){this.listOfURLs.push(url);}},this);}}},printURLs:function(){console.debug("The following URLs are cached for offline use:");dojo.forEach(this.listOfURLs,function(i){console.debug(i);});},remove:function(url){for(var i=0;i=64){_1f9=_1f9.substring(0,63);}_1f8.removeStore(_1f9);_1f8.openStore(_1f9);var _1fa=_1f8.createStore(_1f9);this._store=_1fa;var self=this;this._currentFileIndex=0;this._cancelID=_1fa.capture(this.listOfURLs,function(url,_1fd,_1fe){if(!_1fd&&self.refreshing){self._cancelID=null;self.refreshing=false;var _1ff=[];_1ff.push("Unable to capture: "+url);_1f6(true,_1ff);return;}else{if(_1fd){self._currentFileIndex++;}}if(_1fd&&self._currentFileIndex>=self.listOfURLs.length){self._cancelID=null;self.refreshing=false;if(_1f7){dojox.storage.put("oldVersion",_1f7,null,dojox.off.STORAGE_NAMESPACE);}dojox.storage.put("justDebugged",dojo.config.isDebug,null,dojox.off.STORAGE_NAMESPACE);_1f6(false,[]);}});},_getVersionInfo:function(_200){var _201=dojox.storage.get("justDebugged",dojox.off.STORAGE_NAMESPACE);var _202=dojox.storage.get("oldVersion",dojox.off.STORAGE_NAMESPACE);var _203=null;_200=dojo.hitch(this,_200);dojo.xhrGet({url:this.versionURL+"?browserbust="+new Date().getTime(),timeout:5*1000,handleAs:"javascript",error:function(err){dojox.storage.remove("oldVersion",dojox.off.STORAGE_NAMESPACE);dojox.storage.remove("justDebugged",dojox.off.STORAGE_NAMESPACE);_200(_202,_203,_201);},load:function(data){if(data){_203=data;}_200(_202,_203,_201);}});}};}if(!dojo._hasResource["dojox.off.sync"]){dojo._hasResource["dojox.off.sync"]=true;dojo.provide("dojox.off.sync");dojo.mixin(dojox.off.sync,{isSyncing:false,cancelled:false,successful:true,details:[],error:false,actions:null,autoSync:true,onSync:function(type){},synchronize:function(){if(this.isSyncing||dojox.off.goingOnline||(!dojox.off.isOnline)){return;}this.isSyncing=true;this.successful=false;this.details=[];this.cancelled=false;this.start();},cancel:function(){if(!this.isSyncing){return;}this.cancelled=true;if(dojox.off.files.refreshing){dojox.off.files.abortRefresh();}this.onSync("cancel");},finishedDownloading:function(_207,_208){if(typeof _207=="undefined"){_207=true;}if(!_207){this.successful=false;this.details.push(_208);this.error=true;}this.finished();},start:function(){if(this.cancelled){this.finished();return;}this.onSync("start");this.refreshFiles();},refreshFiles:function(){if(this.cancelled){this.finished();return;}this.onSync("refreshFiles");dojox.off.files.refresh(dojo.hitch(this,function(_209,_20a){if(_209){this.error=true;this.successful=false;for(var i=0;i<_20a.length;i++){this.details.push(_20a[i]);}}this.upload();}));},upload:function(){if(this.cancelled){this.finished();return;}this.onSync("upload");dojo.connect(this.actions,"onReplayFinished",this,this.download);this.actions.replay();},download:function(){if(this.cancelled){this.finished();return;}this.onSync("download");},finished:function(){this.isSyncing=false;this.successful=(!this.cancelled&&!this.error);this.onSync("finished");},_save:function(_20c){this.actions._save(function(){_20c();});},_load:function(_20d){this.actions._load(function(){_20d();});}});dojo.declare("dojox.off.sync.ActionLog",null,{entries:[],reasonHalted:null,isReplaying:false,autoSave:true,add:function(_20e){if(this.isReplaying){throw "Programming error: you can not call "+"dojox.off.sync.actions.add() while "+"we are replaying an action log";}this.entries.push(_20e);if(this.autoSave){this._save();}},onReplay:function(_20f,_210){},length:function(){return this.entries.length;},haltReplay:function(_211){if(!this.isReplaying){return;}if(_211){this.reasonHalted=_211.toString();}if(this.autoSave){var self=this;this._save(function(){self.isReplaying=false;self.onReplayFinished();});}else{this.isReplaying=false;this.onReplayFinished();}},continueReplay:function(){if(!this.isReplaying){return;}this.entries.shift();if(!this.entries.length){if(this.autoSave){var self=this;this._save(function(){self.isReplaying=false;self.onReplayFinished();});return;}else{this.isReplaying=false;this.onReplayFinished();return;}}var _214=this.entries[0];this.onReplay(_214,this);},clear:function(){if(this.isReplaying){return;}this.entries=[];if(this.autoSave){this._save();}},replay:function(){if(this.isReplaying){return;}this.reasonHalted=null;if(!this.entries.length){this.onReplayFinished();return;}this.isReplaying=true;var _215=this.entries[0];this.onReplay(_215,this);},onReplayFinished:function(){},toString:function(){var _216="";_216+="[";for(var i=0;i";html+=dojox.off.sync.details[i];html+="";}html+="
                  \n";html+=""+"Close Window"+"\n";html+="";var _24c="height=400,width=600,resizable=true,"+"scrollbars=true,toolbar=no,menubar=no,"+"location=no,directories=no,dependent=yes";var _24d=window.open("","SyncDetails",_24c);if(!_24d){alert("Please allow popup windows for this domain; can't display sync details window");return;}_24d.document.open();_24d.document.write(html);_24d.document.close();if(_24d.focus){_24d.focus();}},_cancel:function(evt){evt.preventDefault();evt.stopPropagation();dojox.off.sync.cancel();},_needsBrowserRestart:function(){var _24f=dojo.byId("dot-widget-browser-restart");if(_24f){dojo.addClass(_24f,"dot-needs-browser-restart");}var _250=dojo.byId("dot-widget-browser-restart-app-name");if(_250){_250.innerHTML="";_250.appendChild(document.createTextNode(this.appName));}var _251=dojo.byId("dot-sync-status");if(_251){_251.style.display="none";}},_showNeedsOfflineCache:function(){var _252=dojo.byId("dot-widget-container");if(_252){dojo.addClass(_252,"dot-needs-offline-cache");}},_hideNeedsOfflineCache:function(){var _253=dojo.byId("dot-widget-container");if(_253){dojo.removeClass(_253,"dot-needs-offline-cache");}},_initMainEvtHandlers:function(){var _254=dojo.byId("dot-sync-details-button");if(_254){dojo.connect(_254,"onclick",this,this._showDetails);}var _255=dojo.byId("dot-sync-cancel-button");if(_255){dojo.connect(_255,"onclick",this,this._cancel);}},_setOfflineEnabled:function(_256){var _257=[];_257.push(dojo.byId("dot-sync-status"));for(var i=0;i<_257.length;i++){if(_257[i]){_257[i].style.visibility=(_256?"visible":"hidden");}}},_syncFinished:function(){this._updateSyncUI();var _259=dojo.byId("dot-success-checkmark");var _25a=dojo.byId("dot-sync-details");if(dojox.off.sync.successful==true){this._setSyncMessage("Sync Successful");if(_259){_259.style.display="inline";}}else{if(dojox.off.sync.cancelled==true){this._setSyncMessage("Sync Cancelled");if(_259){_259.style.display="none";}}else{this._setSyncMessage("Sync Error");var _25b=dojo.byId("dot-sync-messages");if(_25b){dojo.addClass(_25b,"dot-sync-error");}if(_259){_259.style.display="none";}}}if(dojox.off.sync.details.length&&_25a){_25a.style.display="inline";}},_onFrameworkEvent:function(type,_25d){if(type=="save"){if(_25d.status==dojox.storage.FAILED&&!_25d.isCoreSave){alert("Please increase the amount of local storage available "+"to this application");if(dojox.storage.hasSettingsUI()){dojox.storage.showSettingsUI();}}}else{if(type=="coreOperationFailed"){console.log("Application does not have permission to use Dojo Offline");if(!this._userInformed){alert("This application will not work if Google Gears is not allowed to run");this._userInformed=true;}}else{if(type=="offlineCacheInstalled"){this._hideNeedsOfflineCache();if(dojox.off.hasOfflineCache==true&&dojox.off.browserRestart==true){this._needsBrowserRestart();return;}else{var _25e=dojo.byId("dot-widget-browser-restart");if(_25e){_25e.style.display="none";}}this._updateSyncUI();this._initMainEvtHandlers();this._setOfflineEnabled(dojox.off.enabled);this._testNet();}}}},_onSync:function(type){switch(type){case "start":this._updateSyncUI();break;case "refreshFiles":this._setSyncMessage("Downloading UI...");break;case "upload":this._setSyncMessage("Uploading new data...");break;case "download":this._setSyncMessage("Downloading new data...");break;case "finished":this._syncFinished();break;case "cancel":this._setSyncMessage("Canceling Sync...");break;default:dojo.warn("Programming error: "+"Unknown sync type in dojox.off.ui: "+type);break;}},_onNetwork:function(type){if(!this._initialized){return;}this._updateNetIndicator();if(type=="offline"){this._setSyncMessage("You are working offline");var _261=dojo.byId("dot-sync-details");if(_261){_261.style.display="none";}this._updateSyncUI();}else{if(dojox.off.sync.autoSync){if(dojo.isAIR){window.setTimeout(function(){dojox.off.sync.synchronize();},1000);}else{window.setTimeout(dojox._scopeName+".off.sync.synchronize()",1000);}}}}});dojo.connect(dojox.off,"onFrameworkEvent",dojox.off.ui,"_onFrameworkEvent");dojo.connect(dojox.off,"onLoad",dojox.off.ui,dojox.off.ui._initialize);}if(!dojo._hasResource["dojox.off.offline"]){dojo._hasResource["dojox.off.offline"]=true;dojo.provide("dojox.off.offline");} diff --git a/includes/js/dojox/off/offline.js.uncompressed.js b/includes/js/dojox/off/offline.js.uncompressed.js new file mode 100644 index 0000000..aa2866d --- /dev/null +++ b/includes/js/dojox/off/offline.js.uncompressed.js @@ -0,0 +1,5910 @@ +/* + Copyright (c) 2004-2008, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/book/dojo-book-0-9/introduction/licensing +*/ + +/* + This is a compiled version of Dojo, built for deployment and not for + development. To get an editable version, please visit: + + http://dojotoolkit.org + + for documentation and information on getting the source. +*/ + +if(!dojo._hasResource["dojox.storage.Provider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.storage.Provider"] = true; +dojo.provide("dojox.storage.Provider"); + +dojo.declare("dojox.storage.Provider", null, { + // summary: A singleton for working with dojox.storage. + // description: + // dojox.storage exposes the current available storage provider on this + // platform. It gives you methods such as dojox.storage.put(), + // dojox.storage.get(), etc. + // + // For more details on dojox.storage, see the primary documentation + // page at + // http://manual.dojotoolkit.org/storage.html + // + // Note for storage provider developers who are creating subclasses- + // This is the base class for all storage providers Specific kinds of + // Storage Providers should subclass this and implement these methods. + // You should avoid initialization in storage provider subclass's + // constructor; instead, perform initialization in your initialize() + // method. + constructor: function(){ + }, + + // SUCCESS: String + // Flag that indicates a put() call to a + // storage provider was succesful. + SUCCESS: "success", + + // FAILED: String + // Flag that indicates a put() call to + // a storage provider failed. + FAILED: "failed", + + // PENDING: String + // Flag that indicates a put() call to a + // storage provider is pending user approval. + PENDING: "pending", + + // SIZE_NOT_AVAILABLE: String + // Returned by getMaximumSize() if this storage provider can not determine + // the maximum amount of data it can support. + SIZE_NOT_AVAILABLE: "Size not available", + + // SIZE_NO_LIMIT: String + // Returned by getMaximumSize() if this storage provider has no theoretical + // limit on the amount of data it can store. + SIZE_NO_LIMIT: "No size limit", + + // DEFAULT_NAMESPACE: String + // The namespace for all storage operations. This is useful if several + // applications want access to the storage system from the same domain but + // want different storage silos. + DEFAULT_NAMESPACE: "default", + + // onHideSettingsUI: Function + // If a function is assigned to this property, then when the settings + // provider's UI is closed this function is called. Useful, for example, + // if the user has just cleared out all storage for this provider using + // the settings UI, and you want to update your UI. + onHideSettingsUI: null, + + initialize: function(){ + // summary: + // Allows this storage provider to initialize itself. This is + // called after the page has finished loading, so you can not do + // document.writes(). Storage Provider subclasses should initialize + // themselves inside of here rather than in their function + // constructor. + console.warn("dojox.storage.initialize not implemented"); + }, + + isAvailable: function(){ /*Boolean*/ + // summary: + // Returns whether this storage provider is available on this + // platform. + console.warn("dojox.storage.isAvailable not implemented"); + }, + + put: function( /*string*/ key, + /*object*/ value, + /*function*/ resultsHandler, + /*string?*/ namespace){ + // summary: + // Puts a key and value into this storage system. + // description: + // Example- + // var resultsHandler = function(status, key, message){ + // alert("status="+status+", key="+key+", message="+message); + // }; + // dojox.storage.put("test", "hello world", resultsHandler); + // + // Important note: if you are using Dojo Storage in conjunction with + // Dojo Offline, then you don't need to provide + // a resultsHandler; this is because for Dojo Offline we + // use Google Gears to persist data, which has unlimited data + // once the user has given permission. If you are using Dojo + // Storage apart from Dojo Offline, then under the covers hidden + // Flash might be used, which is both asychronous and which might + // get denied; in this case you must provide a resultsHandler. + // key: + // A string key to use when retrieving this value in the future. + // value: + // A value to store; this can be any JavaScript type. + // resultsHandler: + // A callback function that will receive three arguments. The + // first argument is one of three values: dojox.storage.SUCCESS, + // dojox.storage.FAILED, or dojox.storage.PENDING; these values + // determine how the put request went. In some storage systems + // users can deny a storage request, resulting in a + // dojox.storage.FAILED, while in other storage systems a storage + // request must wait for user approval, resulting in a + // dojox.storage.PENDING status until the request is either + // approved or denied, resulting in another call back with + // dojox.storage.SUCCESS. + // The second argument in the call back is the key name that was being stored. + // The third argument in the call back is an optional message that + // details possible error messages that might have occurred during + // the storage process. + // namespace: + // Optional string namespace that this value will be placed into; + // if left off, the value will be placed into dojox.storage.DEFAULT_NAMESPACE + + console.warn("dojox.storage.put not implemented"); + }, + + get: function(/*string*/ key, /*string?*/ namespace){ /*Object*/ + // summary: + // Gets the value with the given key. Returns null if this key is + // not in the storage system. + // key: + // A string key to get the value of. + // namespace: + // Optional string namespace that this value will be retrieved from; + // if left off, the value will be retrieved from dojox.storage.DEFAULT_NAMESPACE + // return: Returns any JavaScript object type; null if the key is not present + console.warn("dojox.storage.get not implemented"); + }, + + hasKey: function(/*string*/ key, /*string?*/ namespace){ + // summary: Determines whether the storage has the given key. + return !!this.get(key, namespace); // Boolean + }, + + getKeys: function(/*string?*/ namespace){ /*Array*/ + // summary: Enumerates all of the available keys in this storage system. + // return: Array of available keys + console.warn("dojox.storage.getKeys not implemented"); + }, + + clear: function(/*string?*/ namespace){ + // summary: + // Completely clears this storage system of all of it's values and + // keys. If 'namespace' is provided just clears the keys in that + // namespace. + console.warn("dojox.storage.clear not implemented"); + }, + + remove: function(/*string*/ key, /*string?*/ namespace){ + // summary: Removes the given key from this storage system. + console.warn("dojox.storage.remove not implemented"); + }, + + getNamespaces: function(){ /*string[]*/ + console.warn("dojox.storage.getNamespaces not implemented"); + }, + + isPermanent: function(){ /*Boolean*/ + // summary: + // Returns whether this storage provider's values are persisted + // when this platform is shutdown. + console.warn("dojox.storage.isPermanent not implemented"); + }, + + getMaximumSize: function(){ /* mixed */ + // summary: The maximum storage allowed by this provider + // returns: + // Returns the maximum storage size + // supported by this provider, in + // thousands of bytes (i.e., if it + // returns 60 then this means that 60K + // of storage is supported). + // + // If this provider can not determine + // it's maximum size, then + // dojox.storage.SIZE_NOT_AVAILABLE is + // returned; if there is no theoretical + // limit on the amount of storage + // this provider can return, then + // dojox.storage.SIZE_NO_LIMIT is + // returned + console.warn("dojox.storage.getMaximumSize not implemented"); + }, + + putMultiple: function( /*array*/ keys, + /*array*/ values, + /*function*/ resultsHandler, + /*string?*/ namespace){ + // summary: + // Puts multiple keys and values into this storage system. + // description: + // Example- + // var resultsHandler = function(status, key, message){ + // alert("status="+status+", key="+key+", message="+message); + // }; + // dojox.storage.put(["test"], ["hello world"], resultsHandler); + // + // Important note: if you are using Dojo Storage in conjunction with + // Dojo Offline, then you don't need to provide + // a resultsHandler; this is because for Dojo Offline we + // use Google Gears to persist data, which has unlimited data + // once the user has given permission. If you are using Dojo + // Storage apart from Dojo Offline, then under the covers hidden + // Flash might be used, which is both asychronous and which might + // get denied; in this case you must provide a resultsHandler. + // keys: + // An array of string keys to use when retrieving this value in the future, + // one per value to be stored + // values: + // An array of values to store; this can be any JavaScript type, though the + // performance of plain strings is considerably better + // resultsHandler: + // A callback function that will receive three arguments. The + // first argument is one of three values: dojox.storage.SUCCESS, + // dojox.storage.FAILED, or dojox.storage.PENDING; these values + // determine how the put request went. In some storage systems + // users can deny a storage request, resulting in a + // dojox.storage.FAILED, while in other storage systems a storage + // request must wait for user approval, resulting in a + // dojox.storage.PENDING status until the request is either + // approved or denied, resulting in another call back with + // dojox.storage.SUCCESS. + // The second argument in the call back is the key name that was being stored. + // The third argument in the call back is an optional message that + // details possible error messages that might have occurred during + // the storage process. + // namespace: + // Optional string namespace that this value will be placed into; + // if left off, the value will be placed into dojox.storage.DEFAULT_NAMESPACE + + console.warn("dojox.storage.putMultiple not implemented"); + // JAC: We could implement a 'default' puMultiple here by just doing + // each put individually + }, + + getMultiple: function(/*array*/ keys, /*string?*/ namespace){ /*Object*/ + // summary: + // Gets the valuse corresponding to each of the given keys. + // Returns a null array element for each given key that is + // not in the storage system. + // keys: + // An array of string keys to get the value of. + // namespace: + // Optional string namespace that this value will be retrieved from; + // if left off, the value will be retrieved from dojox.storage.DEFAULT_NAMESPACE + // return: Returns any JavaScript object type; null if the key is not present + + console.warn("dojox.storage.getMultiple not implemented"); + // JAC: We could implement a 'default' getMultiple here by just + // doing each get individually + }, + + removeMultiple: function(/*array*/ keys, /*string?*/ namespace) { + // summary: Removes the given keys from this storage system. + + // JAC: We could implement a 'default' removeMultiple here by just + // doing each remove individually + console.warn("dojox.storage.remove not implemented"); + }, + + isValidKeyArray: function( keys) { + if(keys === null || keys === undefined || !dojo.isArray(keys)){ + return false; + } + + // JAC: This could be optimized by running the key validity test + // directly over a joined string + return !dojo.some(keys, function(key){ + return !this.isValidKey(key); + }); // Boolean + }, + + hasSettingsUI: function(){ /*Boolean*/ + // summary: Determines whether this provider has a settings UI. + return false; + }, + + showSettingsUI: function(){ + // summary: If this provider has a settings UI, determined + // by calling hasSettingsUI(), it is shown. + console.warn("dojox.storage.showSettingsUI not implemented"); + }, + + hideSettingsUI: function(){ + // summary: If this provider has a settings UI, hides it. + console.warn("dojox.storage.hideSettingsUI not implemented"); + }, + + isValidKey: function(/*string*/ keyName){ /*Boolean*/ + // summary: + // Subclasses can call this to ensure that the key given is valid + // in a consistent way across different storage providers. We use + // the lowest common denominator for key values allowed: only + // letters, numbers, and underscores are allowed. No spaces. + if(keyName === null || keyName === undefined){ + return false; + } + + return /^[0-9A-Za-z_]*$/.test(keyName); + }, + + getResourceList: function(){ /* Array[] */ + // summary: + // Returns a list of URLs that this + // storage provider might depend on. + // description: + // This method returns a list of URLs that this + // storage provider depends on to do its work. + // This list is used by the Dojo Offline Toolkit + // to cache these resources to ensure the machinery + // used by this storage provider is available offline. + // What is returned is an array of URLs. + // Note that Dojo Offline uses Gears as its native + // storage provider, and does not support using other + // kinds of storage providers while offline anymore. + + return []; + } +}); + +} + +if(!dojo._hasResource["dojox.storage.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.storage.manager"] = true; +dojo.provide("dojox.storage.manager"); +//dojo.require("dojo.AdapterRegistry"); +// FIXME: refactor this to use an AdapterRegistry + +dojox.storage.manager = new function(){ + // summary: A singleton class in charge of the dojox.storage system + // description: + // Initializes the storage systems and figures out the best available + // storage options on this platform. + + // currentProvider: Object + // The storage provider that was automagically chosen to do storage + // on this platform, such as dojox.storage.FlashStorageProvider. + this.currentProvider = null; + + // available: Boolean + // Whether storage of some kind is available. + this.available = false; + + // providers: Array + // Array of all the static provider instances, useful if you want to + // loop through and see what providers have been registered. + this.providers = []; + + this._initialized = false; + + this._onLoadListeners = []; + + this.initialize = function(){ + // summary: + // Initializes the storage system and autodetects the best storage + // provider we can provide on this platform + this.autodetect(); + }; + + this.register = function(/*string*/ name, /*Object*/ instance){ + // summary: + // Registers the existence of a new storage provider; used by + // subclasses to inform the manager of their existence. The + // storage manager will select storage providers based on + // their ordering, so the order in which you call this method + // matters. + // name: + // The full class name of this provider, such as + // "dojox.storage.FlashStorageProvider". + // instance: + // An instance of this provider, which we will use to call + // isAvailable() on. + + // keep list of providers as a list so that we can know what order + // storage providers are preferred; also, store the providers hashed + // by name in case someone wants to get a provider that uses + // a particular storage backend + this.providers.push(instance); + this.providers[name] = instance; + }; + + this.setProvider = function(storageClass){ + // summary: + // Instructs the storageManager to use the given storage class for + // all storage requests. + // description: + // Example- + // dojox.storage.setProvider( + // dojox.storage.IEStorageProvider) + + }; + + this.autodetect = function(){ + // summary: + // Autodetects the best possible persistent storage provider + // available on this platform. + + //console.debug("dojox.storage.manager.autodetect"); + + if(this._initialized){ // already finished + return; + } + + // a flag to force the storage manager to use a particular + // storage provider type, such as + // djConfig = {forceStorageProvider: "dojox.storage.WhatWGStorageProvider"}; + var forceProvider = dojo.config["forceStorageProvider"] || false; + + // go through each provider, seeing if it can be used + var providerToUse; + //FIXME: use dojo.some + for(var i = 0; i < this.providers.length; i++){ + providerToUse = this.providers[i]; + if(forceProvider && forceProvider == providerToUse.declaredClass){ + // still call isAvailable for this provider, since this helps some + // providers internally figure out if they are available + // FIXME: This should be refactored since it is non-intuitive + // that isAvailable() would initialize some state + providerToUse.isAvailable(); + break; + }else if(!forceProvider && providerToUse.isAvailable()){ + break; + } + } + + if(!providerToUse){ // no provider available + this._initialized = true; + this.available = false; + this.currentProvider = null; + console.warn("No storage provider found for this platform"); + this.loaded(); + return; + } + + // create this provider and mix in it's properties + // so that developers can do dojox.storage.put rather + // than dojox.storage.currentProvider.put, for example + this.currentProvider = providerToUse; + dojo.mixin(dojox.storage, this.currentProvider); + + // have the provider initialize itself + dojox.storage.initialize(); + + this._initialized = true; + this.available = true; + }; + + this.isAvailable = function(){ /*Boolean*/ + // summary: Returns whether any storage options are available. + return this.available; + }; + + this.addOnLoad = function(func){ /* void */ + // summary: + // Adds an onload listener to know when Dojo Offline can be used. + // description: + // Adds a listener to know when Dojo Offline can be used. This + // ensures that the Dojo Offline framework is loaded and that the + // local dojox.storage system is ready to be used. This method is + // useful if you don't want to have a dependency on Dojo Events + // when using dojox.storage. + // func: Function + // A function to call when Dojo Offline is ready to go + this._onLoadListeners.push(func); + + if(this.isInitialized()){ + this._fireLoaded(); + } + }; + + this.removeOnLoad = function(func){ /* void */ + // summary: Removes the given onLoad listener + for(var i = 0; i < this._onLoadListeners.length; i++){ + if(func == this._onLoadListeners[i]){ + this._onLoadListeners = this._onLoadListeners.splice(i, 1); + break; + } + } + }; + + this.isInitialized = function(){ /*Boolean*/ + // summary: + // Returns whether the storage system is initialized and ready to + // be used. + + // FIXME: This should REALLY not be in here, but it fixes a tricky + // Flash timing bug. + // Confirm that this is still needed with the newly refactored Dojo + // Flash. Used to be for Internet Explorer. -- Brad Neuberg + if(this.currentProvider != null + && this.currentProvider.declaredClass == "dojox.storage.FlashStorageProvider" + && dojox.flash.ready == false){ + return false; + }else{ + return this._initialized; + } + }; + + this.supportsProvider = function(/*string*/ storageClass){ /* Boolean */ + // summary: Determines if this platform supports the given storage provider. + // description: + // Example- + // dojox.storage.manager.supportsProvider( + // "dojox.storage.InternetExplorerStorageProvider"); + + // construct this class dynamically + try{ + // dynamically call the given providers class level isAvailable() + // method + var provider = eval("new " + storageClass + "()"); + var results = provider.isAvailable(); + if(!results){ return false; } + return results; + }catch(e){ + return false; + } + }; + + this.getProvider = function(){ /* Object */ + // summary: Gets the current provider + return this.currentProvider; + }; + + this.loaded = function(){ + // summary: + // The storage provider should call this method when it is loaded + // and ready to be used. Clients who will use the provider will + // connect to this method to know when they can use the storage + // system. You can either use dojo.connect to connect to this + // function, or can use dojox.storage.manager.addOnLoad() to add + // a listener that does not depend on the dojo.event package. + // description: + // Example 1- + // if(dojox.storage.manager.isInitialized() == false){ + // dojo.connect(dojox.storage.manager, "loaded", TestStorage, "initialize"); + // }else{ + // dojo.connect(dojo, "loaded", TestStorage, "initialize"); + // } + // Example 2- + // dojox.storage.manager.addOnLoad(someFunction); + + + // FIXME: we should just provide a Deferred for this. That way you + // don't care when this happens or has happened. Deferreds are in Base + this._fireLoaded(); + }; + + this._fireLoaded = function(){ + //console.debug("dojox.storage.manager._fireLoaded"); + + dojo.forEach(this._onLoadListeners, function(i){ + try{ + i(); + }catch(e){ console.debug(e); } + }); + }; + + this.getResourceList = function(){ + // summary: + // Returns a list of whatever resources are necessary for storage + // providers to work. + // description: + // This will return all files needed by all storage providers for + // this particular environment type. For example, if we are in the + // browser environment, then this will return the hidden SWF files + // needed by the FlashStorageProvider, even if we don't need them + // for the particular browser we are working within. This is meant + // to faciliate Dojo Offline, which must retrieve all resources we + // need offline into the offline cache -- we retrieve everything + // needed, in case another browser that requires different storage + // mechanisms hits the local offline cache. For example, if we + // were to sync against Dojo Offline on Firefox 2, then we would + // not grab the FlashStorageProvider resources needed for Safari. + var results = []; + dojo.forEach(dojox.storage.manager.providers, function(currentProvider){ + results = results.concat(currentProvider.getResourceList()); + }); + + return results; + } +}; + +} + +if(!dojo._hasResource["dojox._sql._crypto"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox._sql._crypto"] = true; +// Taken from http://www.movable-type.co.uk/scripts/aes.html by +// Chris Veness (CLA signed); adapted for Dojo and Google Gears Worker Pool +// by Brad Neuberg, bkn3@columbia.edu + +dojo.provide("dojox._sql._crypto"); + +dojo.mixin(dojox._sql._crypto,{ + // _POOL_SIZE: + // Size of worker pool to create to help with crypto + _POOL_SIZE: 100, + + encrypt: function(plaintext, password, callback){ + // summary: + // Use Corrected Block TEA to encrypt plaintext using password + // (note plaintext & password must be strings not string objects). + // Results will be returned to the 'callback' asychronously. + this._initWorkerPool(); + + var msg ={plaintext: plaintext, password: password}; + msg = dojo.toJson(msg); + msg = "encr:" + String(msg); + + this._assignWork(msg, callback); + }, + + decrypt: function(ciphertext, password, callback){ + // summary: + // Use Corrected Block TEA to decrypt ciphertext using password + // (note ciphertext & password must be strings not string objects). + // Results will be returned to the 'callback' asychronously. + this._initWorkerPool(); + + var msg ={ciphertext: ciphertext, password: password}; + msg = dojo.toJson(msg); + msg = "decr:" + String(msg); + + this._assignWork(msg, callback); + }, + + _initWorkerPool: function(){ + // bugs in Google Gears prevents us from dynamically creating + // and destroying workers as we need them -- the worker + // pool functionality stops working after a number of crypto + // cycles (probably related to a memory leak in Google Gears). + // this is too bad, since it results in much simpler code. + + // instead, we have to create a pool of workers and reuse them. we + // keep a stack of 'unemployed' Worker IDs that are currently not working. + // if a work request comes in, we pop off the 'unemployed' stack + // and put them to work, storing them in an 'employed' hashtable, + // keyed by their Worker ID with the value being the callback function + // that wants the result. when an employed worker is done, we get + // a message in our 'manager' which adds this worker back to the + // unemployed stack and routes the result to the callback that + // wanted it. if all the workers were employed in the past but + // more work needed to be done (i.e. it's a tight labor pool ;) + // then the work messages are pushed onto + // a 'handleMessage' queue as an object tuple{msg: msg, callback: callback} + + if(!this._manager){ + try{ + this._manager = google.gears.factory.create("beta.workerpool", "1.0"); + this._unemployed = []; + this._employed ={}; + this._handleMessage = []; + + var self = this; + this._manager.onmessage = function(msg, sender){ + // get the callback necessary to serve this result + var callback = self._employed["_" + sender]; + + // make this worker unemployed + self._employed["_" + sender] = undefined; + self._unemployed.push("_" + sender); + + // see if we need to assign new work + // that was queued up needing to be done + if(self._handleMessage.length){ + var handleMe = self._handleMessage.shift(); + self._assignWork(handleMe.msg, handleMe.callback); + } + + // return results + callback(msg); + } + + var workerInit = "function _workerInit(){" + + "gearsWorkerPool.onmessage = " + + String(this._workerHandler) + + ";" + + "}"; + + var code = workerInit + " _workerInit();"; + + // create our worker pool + for(var i = 0; i < this._POOL_SIZE; i++){ + this._unemployed.push("_" + this._manager.createWorker(code)); + } + }catch(exp){ + throw exp.message||exp; + } + } + }, + + _assignWork: function(msg, callback){ + // can we immediately assign this work? + if(!this._handleMessage.length && this._unemployed.length){ + // get an unemployed worker + var workerID = this._unemployed.shift().substring(1); // remove _ + + // list this worker as employed + this._employed["_" + workerID] = callback; + + // do the worke + this._manager.sendMessage(msg, workerID); + }else{ + // we have to queue it up + this._handleMessage ={msg: msg, callback: callback}; + } + }, + + _workerHandler: function(msg, sender){ + + /* Begin AES Implementation */ + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + // Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [§5.1.1] + var Sbox = [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16]; + + // Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [§5.2] + var Rcon = [ [0x00, 0x00, 0x00, 0x00], + [0x01, 0x00, 0x00, 0x00], + [0x02, 0x00, 0x00, 0x00], + [0x04, 0x00, 0x00, 0x00], + [0x08, 0x00, 0x00, 0x00], + [0x10, 0x00, 0x00, 0x00], + [0x20, 0x00, 0x00, 0x00], + [0x40, 0x00, 0x00, 0x00], + [0x80, 0x00, 0x00, 0x00], + [0x1b, 0x00, 0x00, 0x00], + [0x36, 0x00, 0x00, 0x00] ]; + + /* + * AES Cipher function: encrypt 'input' with Rijndael algorithm + * + * takes byte-array 'input' (16 bytes) + * 2D byte-array key schedule 'w' (Nr+1 x Nb bytes) + * + * applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage + * + * returns byte-array encrypted value (16 bytes) + */ + function Cipher(input, w) { // main Cipher function [§5.1] + var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES) + var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys + + var state = [[],[],[],[]]; // initialise 4xNb byte-array 'state' with input [§3.4] + for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i]; + + state = AddRoundKey(state, w, 0, Nb); + + for (var round=1; round 6 && i%Nk == 4) { + temp = SubWord(temp); + } + for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t]; + } + + return w; + } + + function SubWord(w) { // apply SBox to 4-byte word w + for (var i=0; i<4; i++) w[i] = Sbox[w[i]]; + return w; + } + + function RotWord(w) { // rotate 4-byte word w left by one byte + w[4] = w[0]; + for (var i=0; i<4; i++) w[i] = w[i+1]; + return w; + } + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + /* + * Use AES to encrypt 'plaintext' with 'password' using 'nBits' key, in 'Counter' mode of operation + * - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + * for each block + * - outputblock = cipher(counter, key) + * - cipherblock = plaintext xor outputblock + */ + function AESEncryptCtr(plaintext, password, nBits) { + if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys + + // for this example script, generate the key by applying Cipher to 1st 16/24/32 chars of password; + // for real-world applications, a more secure approach would be to hash the password e.g. with SHA-1 + var nBytes = nBits/8; // no bytes in key + var pwBytes = new Array(nBytes); + for (var i=0; i>> i*8) & 0xff; + for (var i=0; i<4; i++) counterBlock[i+4] = (nonce/0x100000000 >>> i*8) & 0xff; + + // generate key schedule - an expansion of the key into distinct Key Rounds for each round + var keySchedule = KeyExpansion(key); + + var blockCount = Math.ceil(plaintext.length/blockSize); + var ciphertext = new Array(blockCount); // ciphertext as array of strings + + for (var b=0; b>> c*8) & 0xff; + for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8) + + var cipherCntr = Cipher(counterBlock, keySchedule); // -- encrypt counter block -- + + // calculate length of final block: + var blockLength = b>> c*8) & 0xff; + for (var c=0; c<4; c++) counterBlock[15-c-4] = ((b/0x100000000-1) >>> c*8) & 0xff; + + var cipherCntr = Cipher(counterBlock, keySchedule); // encrypt counter block + + ciphertext[b] = unescCtrlChars(ciphertext[b]); + + var pt = ''; + for (var i=0; i 63){ + this.dbName = this.dbName.substring(0, 63); + } + } + + if(!dbName){ + dbName = this.dbName; + } + + try{ + this._initDb(); + this.db.open(dbName); + this._dbOpen = true; + }catch(exp){ + throw exp.message||exp; + } + }, + + close: function(dbName){ + // on Internet Explorer, Google Gears throws an exception + // "Object not a collection", when we try to close the + // database -- just don't close it on this platform + // since we are running into a Gears bug; the Gears team + // said it's ok to not close a database connection + if(dojo.isIE){ return; } + + if(!this._dbOpen && (!dbName || dbName == this.dbName)){ + return; + } + + if(!dbName){ + dbName = this.dbName; + } + + try{ + this.db.close(dbName); + this._dbOpen = false; + }catch(exp){ + throw exp.message||exp; + } + }, + + _exec: function(params){ + try{ + // get the Gears Database object + this._initDb(); + + // see if we need to open the db; if programmer + // manually called dojox.sql.open() let them handle + // it; otherwise we open and close automatically on + // each SQL execution + if(!this._dbOpen){ + this.open(); + this._autoClose = true; + } + + // determine our parameters + var sql = null; + var callback = null; + var password = null; + + var args = dojo._toArray(params); + + sql = args.splice(0, 1)[0]; + + // does this SQL statement use the ENCRYPT or DECRYPT + // keywords? if so, extract our callback and crypto + // password + if(this._needsEncrypt(sql) || this._needsDecrypt(sql)){ + callback = args.splice(args.length - 1, 1)[0]; + password = args.splice(args.length - 1, 1)[0]; + } + + // 'args' now just has the SQL parameters + + // print out debug SQL output if the developer wants that + if(this.debug){ + this._printDebugSQL(sql, args); + } + + // handle SQL that needs encryption/decryption differently + // do we have an ENCRYPT SQL statement? if so, handle that first + if(this._needsEncrypt(sql)){ + var crypto = new dojox.sql._SQLCrypto("encrypt", sql, + password, args, + callback); + return; // encrypted results will arrive asynchronously + }else if(this._needsDecrypt(sql)){ // otherwise we have a DECRYPT statement + var crypto = new dojox.sql._SQLCrypto("decrypt", sql, + password, args, + callback); + return; // decrypted results will arrive asynchronously + } + + // execute the SQL and get the results + var rs = this.db.execute(sql, args); + + // Gears ResultSet object's are ugly -- normalize + // these into something JavaScript programmers know + // how to work with, basically an array of + // JavaScript objects where each property name is + // simply the field name for a column of data + rs = this._normalizeResults(rs); + + if(this._autoClose){ + this.close(); + } + + return rs; + }catch(exp){ + exp = exp.message||exp; + + console.debug("SQL Exception: " + exp); + + if(this._autoClose){ + try{ + this.close(); + }catch(e){ + console.debug("Error closing database: " + + e.message||e); + } + } + + throw exp; + } + }, + + _initDb: function(){ + if(!this.db){ + try{ + this.db = google.gears.factory.create('beta.database', '1.0'); + }catch(exp){ + dojo.setObject("google.gears.denied", true); + dojox.off.onFrameworkEvent("coreOperationFailed"); + throw "Google Gears must be allowed to run"; + } + } + }, + + _printDebugSQL: function(sql, args){ + var msg = "dojox.sql(\"" + sql + "\""; + for(var i = 0; i < args.length; i++){ + if(typeof args[i] == "string"){ + msg += ", \"" + args[i] + "\""; + }else{ + msg += ", " + args[i]; + } + } + msg += ")"; + + console.debug(msg); + }, + + _normalizeResults: function(rs){ + var results = []; + if(!rs){ return []; } + + while(rs.isValidRow()){ + var row = {}; + + for(var i = 0; i < rs.fieldCount(); i++){ + var fieldName = rs.fieldName(i); + var fieldValue = rs.field(i); + row[fieldName] = fieldValue; + } + + results.push(row); + + rs.next(); + } + + rs.close(); + + return results; + }, + + _needsEncrypt: function(sql){ + return /encrypt\([^\)]*\)/i.test(sql); + }, + + _needsDecrypt: function(sql){ + return /decrypt\([^\)]*\)/i.test(sql); + } +}); + +// summary: +// A private class encapsulating any cryptography that must be done +// on a SQL statement. We instantiate this class and have it hold +// it's state so that we can potentially have several encryption +// operations happening at the same time by different SQL statements. +dojo.declare("dojox.sql._SQLCrypto", null, { + constructor: function(action, sql, password, args, callback){ + if(action == "encrypt"){ + this._execEncryptSQL(sql, password, args, callback); + }else{ + this._execDecryptSQL(sql, password, args, callback); + } + }, + + _execEncryptSQL: function(sql, password, args, callback){ + // strip the ENCRYPT/DECRYPT keywords from the SQL + var strippedSQL = this._stripCryptoSQL(sql); + + // determine what arguments need encryption + var encryptColumns = this._flagEncryptedArgs(sql, args); + + // asynchronously encrypt each argument that needs it + var self = this; + this._encrypt(strippedSQL, password, args, encryptColumns, function(finalArgs){ + // execute the SQL + var error = false; + var resultSet = []; + var exp = null; + try{ + resultSet = dojox.sql.db.execute(strippedSQL, finalArgs); + }catch(execError){ + error = true; + exp = execError.message||execError; + } + + // was there an error during SQL execution? + if(exp != null){ + if(dojox.sql._autoClose){ + try{ dojox.sql.close(); }catch(e){} + } + + callback(null, true, exp.toString()); + return; + } + + // normalize SQL results into a JavaScript object + // we can work with + resultSet = dojox.sql._normalizeResults(resultSet); + + if(dojox.sql._autoClose){ + dojox.sql.close(); + } + + // are any decryptions necessary on the result set? + if(dojox.sql._needsDecrypt(sql)){ + // determine which of the result set columns needs decryption + var needsDecrypt = self._determineDecryptedColumns(sql); + + // now decrypt columns asynchronously + // decrypt columns that need it + self._decrypt(resultSet, needsDecrypt, password, function(finalResultSet){ + callback(finalResultSet, false, null); + }); + }else{ + callback(resultSet, false, null); + } + }); + }, + + _execDecryptSQL: function(sql, password, args, callback){ + // strip the ENCRYPT/DECRYPT keywords from the SQL + var strippedSQL = this._stripCryptoSQL(sql); + + // determine which columns needs decryption; this either + // returns the value *, which means all result set columns will + // be decrypted, or it will return the column names that need + // decryption set on a hashtable so we can quickly test a given + // column name; the key is the column name that needs + // decryption and the value is 'true' (i.e. needsDecrypt["someColumn"] + // would return 'true' if it needs decryption, and would be 'undefined' + // or false otherwise) + var needsDecrypt = this._determineDecryptedColumns(sql); + + // execute the SQL + var error = false; + var resultSet = []; + var exp = null; + try{ + resultSet = dojox.sql.db.execute(strippedSQL, args); + }catch(execError){ + error = true; + exp = execError.message||execError; + } + + // was there an error during SQL execution? + if(exp != null){ + if(dojox.sql._autoClose){ + try{ dojox.sql.close(); }catch(e){} + } + + callback(resultSet, true, exp.toString()); + return; + } + + // normalize SQL results into a JavaScript object + // we can work with + resultSet = dojox.sql._normalizeResults(resultSet); + + if(dojox.sql._autoClose){ + dojox.sql.close(); + } + + // decrypt columns that need it + this._decrypt(resultSet, needsDecrypt, password, function(finalResultSet){ + callback(finalResultSet, false, null); + }); + }, + + _encrypt: function(sql, password, args, encryptColumns, callback){ + //console.debug("_encrypt, sql="+sql+", password="+password+", encryptColumns="+encryptColumns+", args="+args); + + this._totalCrypto = 0; + this._finishedCrypto = 0; + this._finishedSpawningCrypto = false; + this._finalArgs = args; + + for(var i = 0; i < args.length; i++){ + if(encryptColumns[i]){ + // we have an encrypt() keyword -- get just the value inside + // the encrypt() parantheses -- for now this must be a ? + var sqlParam = args[i]; + var paramIndex = i; + + // update the total number of encryptions we know must be done asynchronously + this._totalCrypto++; + + // FIXME: This currently uses DES as a proof-of-concept since the + // DES code used is quite fast and was easy to work with. Modify dojox.sql + // to be able to specify a different encryption provider through a + // a SQL-like syntax, such as dojox.sql("SET ENCRYPTION BLOWFISH"), + // and modify the dojox.crypto.Blowfish code to be able to work using + // a Google Gears Worker Pool + + // do the actual encryption now, asychronously on a Gears worker thread + dojox._sql._crypto.encrypt(sqlParam, password, dojo.hitch(this, function(results){ + // set the new encrypted value + this._finalArgs[paramIndex] = results; + this._finishedCrypto++; + // are we done with all encryption? + if(this._finishedCrypto >= this._totalCrypto + && this._finishedSpawningCrypto){ + callback(this._finalArgs); + } + })); + } + } + + this._finishedSpawningCrypto = true; + }, + + _decrypt: function(resultSet, needsDecrypt, password, callback){ + //console.debug("decrypt, resultSet="+resultSet+", needsDecrypt="+needsDecrypt+", password="+password); + + this._totalCrypto = 0; + this._finishedCrypto = 0; + this._finishedSpawningCrypto = false; + this._finalResultSet = resultSet; + + for(var i = 0; i < resultSet.length; i++){ + var row = resultSet[i]; + + // go through each of the column names in row, + // seeing if they need decryption + for(var columnName in row){ + if(needsDecrypt == "*" || needsDecrypt[columnName]){ + this._totalCrypto++; + var columnValue = row[columnName]; + + // forming a closure here can cause issues, with values not cleanly + // saved on Firefox/Mac OS X for some of the values above that + // are needed in the callback below; call a subroutine that will form + // a closure inside of itself instead + this._decryptSingleColumn(columnName, columnValue, password, i, + function(finalResultSet){ + callback(finalResultSet); + }); + } + } + } + + this._finishedSpawningCrypto = true; + }, + + _stripCryptoSQL: function(sql){ + // replace all DECRYPT(*) occurrences with a * + sql = sql.replace(/DECRYPT\(\*\)/ig, "*"); + + // match any ENCRYPT(?, ?, ?, etc) occurrences, + // then replace with just the question marks in the + // middle + var matches = sql.match(/ENCRYPT\([^\)]*\)/ig); + if(matches != null){ + for(var i = 0; i < matches.length; i++){ + var encryptStatement = matches[i]; + var encryptValue = encryptStatement.match(/ENCRYPT\(([^\)]*)\)/i)[1]; + sql = sql.replace(encryptStatement, encryptValue); + } + } + + // match any DECRYPT(COL1, COL2, etc) occurrences, + // then replace with just the column names + // in the middle + matches = sql.match(/DECRYPT\([^\)]*\)/ig); + if(matches != null){ + for(var i = 0; i < matches.length; i++){ + var decryptStatement = matches[i]; + var decryptValue = decryptStatement.match(/DECRYPT\(([^\)]*)\)/i)[1]; + sql = sql.replace(decryptStatement, decryptValue); + } + } + + return sql; + }, + + _flagEncryptedArgs: function(sql, args){ + // capture literal strings that have question marks in them, + // and also capture question marks that stand alone + var tester = new RegExp(/([\"][^\"]*\?[^\"]*[\"])|([\'][^\']*\?[^\']*[\'])|(\?)/ig); + var matches; + var currentParam = 0; + var results = []; + while((matches = tester.exec(sql)) != null){ + var currentMatch = RegExp.lastMatch+""; + + // are we a literal string? then ignore it + if(/^[\"\']/.test(currentMatch)){ + continue; + } + + // do we have an encrypt keyword to our left? + var needsEncrypt = false; + if(/ENCRYPT\([^\)]*$/i.test(RegExp.leftContext)){ + needsEncrypt = true; + } + + // set the encrypted flag + results[currentParam] = needsEncrypt; + + currentParam++; + } + + return results; + }, + + _determineDecryptedColumns: function(sql){ + var results = {}; + + if(/DECRYPT\(\*\)/i.test(sql)){ + results = "*"; + }else{ + var tester = /DECRYPT\((?:\s*\w*\s*\,?)*\)/ig; + var matches; + while(matches = tester.exec(sql)){ + var lastMatch = new String(RegExp.lastMatch); + var columnNames = lastMatch.replace(/DECRYPT\(/i, ""); + columnNames = columnNames.replace(/\)/, ""); + columnNames = columnNames.split(/\s*,\s*/); + dojo.forEach(columnNames, function(column){ + if(/\s*\w* AS (\w*)/i.test(column)){ + column = column.match(/\s*\w* AS (\w*)/i)[1]; + } + results[column] = true; + }); + } + } + + return results; + }, + + _decryptSingleColumn: function(columnName, columnValue, password, currentRowIndex, + callback){ + //console.debug("decryptSingleColumn, columnName="+columnName+", columnValue="+columnValue+", currentRowIndex="+currentRowIndex) + dojox._sql._crypto.decrypt(columnValue, password, dojo.hitch(this, function(results){ + // set the new decrypted value + this._finalResultSet[currentRowIndex][columnName] = results; + this._finishedCrypto++; + + // are we done with all encryption? + if(this._finishedCrypto >= this._totalCrypto + && this._finishedSpawningCrypto){ + //console.debug("done with all decrypts"); + callback(this._finalResultSet); + } + })); + } +}); + +} + +if(!dojo._hasResource["dojox.sql"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sql"] = true; + +dojo.provide("dojox.sql"); + +} + +if(!dojo._hasResource["dojox.storage.GearsStorageProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.storage.GearsStorageProvider"] = true; +dojo.provide("dojox.storage.GearsStorageProvider"); + + + + +if(dojo.isGears){ + + (function(){ + // make sure we don't define the gears provider if we're not gears + // enabled + + dojo.declare("dojox.storage.GearsStorageProvider", dojox.storage.Provider, { + // summary: + // Storage provider that uses the features of Google Gears + // to store data (it is saved into the local SQL database + // provided by Gears, using dojox.sql) + // description: + // You can disable this storage provider with the following djConfig + // variable: + // var djConfig = { disableGearsStorage: true }; + // + // Authors of this storage provider- + // Brad Neuberg, bkn3@columbia.edu + constructor: function(){ + }, + // instance methods and properties + TABLE_NAME: "__DOJO_STORAGE", + initialized: false, + + _available: null, + + initialize: function(){ + //console.debug("dojox.storage.GearsStorageProvider.initialize"); + if(dojo.config["disableGearsStorage"] == true){ + return; + } + + // partition our storage data so that multiple apps + // on the same host won't collide + this.TABLE_NAME = "__DOJO_STORAGE"; + + // create the table that holds our data + try{ + dojox.sql("CREATE TABLE IF NOT EXISTS " + this.TABLE_NAME + "( " + + " namespace TEXT, " + + " key TEXT, " + + " value TEXT " + + ")" + ); + dojox.sql("CREATE UNIQUE INDEX IF NOT EXISTS namespace_key_index" + + " ON " + this.TABLE_NAME + + " (namespace, key)"); + }catch(e){ + console.debug("dojox.storage.GearsStorageProvider.initialize:", e); + + this.initialized = false; // we were unable to initialize + dojox.storage.manager.loaded(); + return; + } + + // indicate that this storage provider is now loaded + this.initialized = true; + dojox.storage.manager.loaded(); + }, + + isAvailable: function(){ + // is Google Gears available and defined? + return this._available = dojo.isGears; + }, + + put: function(key, value, resultsHandler, namespace){ + if(this.isValidKey(key) == false){ + throw new Error("Invalid key given: " + key); + } + namespace = namespace||this.DEFAULT_NAMESPACE; + + // serialize the value; + // handle strings differently so they have better performance + if(dojo.isString(value)){ + value = "string:" + value; + }else{ + value = dojo.toJson(value); + } + + // try to store the value + try{ + dojox.sql("DELETE FROM " + this.TABLE_NAME + + " WHERE namespace = ? AND key = ?", + namespace, key); + dojox.sql("INSERT INTO " + this.TABLE_NAME + + " VALUES (?, ?, ?)", + namespace, key, value); + }catch(e){ + // indicate we failed + console.debug("dojox.storage.GearsStorageProvider.put:", e); + resultsHandler(this.FAILED, key, e.toString()); + return; + } + + if(resultsHandler){ + resultsHandler(dojox.storage.SUCCESS, key, null); + } + }, + + get: function(key, namespace){ + if(this.isValidKey(key) == false){ + throw new Error("Invalid key given: " + key); + } + namespace = namespace||this.DEFAULT_NAMESPACE; + + // try to find this key in the database + var results = dojox.sql("SELECT * FROM " + this.TABLE_NAME + + " WHERE namespace = ? AND " + + " key = ?", + namespace, key); + if(!results.length){ + return null; + }else{ + results = results[0].value; + } + + // destringify the content back into a + // real JavaScript object; + // handle strings differently so they have better performance + if(dojo.isString(results) && (/^string:/.test(results))){ + results = results.substring("string:".length); + }else{ + results = dojo.fromJson(results); + } + + return results; + }, + + getNamespaces: function(){ + var results = [ dojox.storage.DEFAULT_NAMESPACE ]; + + var rs = dojox.sql("SELECT namespace FROM " + this.TABLE_NAME + + " DESC GROUP BY namespace"); + for(var i = 0; i < rs.length; i++){ + if(rs[i].namespace != dojox.storage.DEFAULT_NAMESPACE){ + results.push(rs[i].namespace); + } + } + + return results; + }, + + getKeys: function(namespace){ + namespace = namespace||this.DEFAULT_NAMESPACE; + if(this.isValidKey(namespace) == false){ + throw new Error("Invalid namespace given: " + namespace); + } + + var rs = dojox.sql("SELECT key FROM " + this.TABLE_NAME + + " WHERE namespace = ?", + namespace); + + var results = []; + for(var i = 0; i < rs.length; i++){ + results.push(rs[i].key); + } + + return results; + }, + + clear: function(namespace){ + if(this.isValidKey(namespace) == false){ + throw new Error("Invalid namespace given: " + namespace); + } + namespace = namespace||this.DEFAULT_NAMESPACE; + + dojox.sql("DELETE FROM " + this.TABLE_NAME + + " WHERE namespace = ?", + namespace); + }, + + remove: function(key, namespace){ + namespace = namespace||this.DEFAULT_NAMESPACE; + + dojox.sql("DELETE FROM " + this.TABLE_NAME + + " WHERE namespace = ? AND" + + " key = ?", + namespace, + key); + }, + + putMultiple: function(keys, values, resultsHandler, namespace) { + if(this.isValidKeyArray(keys) === false + || ! values instanceof Array + || keys.length != values.length){ + throw new Error("Invalid arguments: keys = [" + + keys + "], values = [" + values + "]"); + } + + if(namespace == null || typeof namespace == "undefined"){ + namespace = dojox.storage.DEFAULT_NAMESPACE; + } + + if(this.isValidKey(namespace) == false){ + throw new Error("Invalid namespace given: " + namespace); + } + + this._statusHandler = resultsHandler; + + // try to store the value + try{ + dojox.sql.open(); + dojox.sql.db.execute("BEGIN TRANSACTION"); + var _stmt = "REPLACE INTO " + this.TABLE_NAME + " VALUES (?, ?, ?)"; + for(var i=0;i dew){ + minw = dew; + maxw = dbw; + }else{ + maxw = dew; + minw = dbw; + } + var dbh = _document.body.clientHeight; + if(dbh > deh){ + minh = deh; + maxh = dbh; + }else{ + maxh = deh; + minh = dbh; + } + w = (maxw > _window.innerWidth) ? minw : maxw; + h = (maxh > _window.innerHeight) ? minh : maxh; + }else if(!dojo.isOpera && _window.innerWidth){ + //in opera9, dojo.body().clientWidth should be used, instead + //of window.innerWidth/document.documentElement.clientWidth + //so we have to check whether it is opera + w = _window.innerWidth; + h = _window.innerHeight; + }else if(dojo.isIE && de && deh){ + w = dew; + h = deh; + }else if(dojo.body().clientWidth){ + // IE5, Opera + w = dojo.body().clientWidth; + h = dojo.body().clientHeight; + } + + // get scroll position + var scroll = dojo._docScroll(); + + return { w: w, h: h, l: scroll.x, t: scroll.y }; // object +}; + +dijit.placeOnScreen = function( + /* DomNode */ node, + /* Object */ pos, + /* Object */ corners, + /* boolean? */ tryOnly){ + // summary: + // Keeps 'node' in the visible area of the screen while trying to + // place closest to pos.x, pos.y. The input coordinates are + // expected to be the desired document position. + // + // Set which corner(s) you want to bind to, such as + // + // placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"]) + // + // The desired x/y will be treated as the topleft(TL)/topright(TR) or + // BottomLeft(BL)/BottomRight(BR) corner of the node. Each corner is tested + // and if a perfect match is found, it will be used. Otherwise, it goes through + // all of the specified corners, and choose the most appropriate one. + // + // NOTE: node is assumed to be absolutely or relatively positioned. + + var choices = dojo.map(corners, function(corner){ return { corner: corner, pos: pos }; }); + + return dijit._place(node, choices); +} + +dijit._place = function(/*DomNode*/ node, /* Array */ choices, /* Function */ layoutNode){ + // summary: + // Given a list of spots to put node, put it at the first spot where it fits, + // of if it doesn't fit anywhere then the place with the least overflow + // choices: Array + // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} } + // Above example says to put the top-left corner of the node at (10,20) + // layoutNode: Function(node, aroundNodeCorner, nodeCorner) + // for things like tooltip, they are displayed differently (and have different dimensions) + // based on their orientation relative to the parent. This adjusts the popup based on orientation. + + // get {x: 10, y: 10, w: 100, h:100} type obj representing position of + // viewport over document + var view = dijit.getViewport(); + + // This won't work if the node is inside a
                  , + // so reattach it to dojo.doc.body. (Otherwise, the positioning will be wrong + // and also it might get cutoff) + if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){ + dojo.body().appendChild(node); + } + + var best = null; + dojo.some(choices, function(choice){ + var corner = choice.corner; + var pos = choice.pos; + + // configure node to be displayed in given position relative to button + // (need to do this in order to get an accurate size for the node, because + // a tooltips size changes based on position, due to triangle) + if(layoutNode){ + layoutNode(node, choice.aroundCorner, corner); + } + + // get node's size + var style = node.style; + var oldDisplay = style.display; + var oldVis = style.visibility; + style.visibility = "hidden"; + style.display = ""; + var mb = dojo.marginBox(node); + style.display = oldDisplay; + style.visibility = oldVis; + + // coordinates and size of node with specified corner placed at pos, + // and clipped by viewport + var startX = (corner.charAt(1) == 'L' ? pos.x : Math.max(view.l, pos.x - mb.w)), + startY = (corner.charAt(0) == 'T' ? pos.y : Math.max(view.t, pos.y - mb.h)), + endX = (corner.charAt(1) == 'L' ? Math.min(view.l + view.w, startX + mb.w) : pos.x), + endY = (corner.charAt(0) == 'T' ? Math.min(view.t + view.h, startY + mb.h) : pos.y), + width = endX - startX, + height = endY - startY, + overflow = (mb.w - width) + (mb.h - height); + + if(best == null || overflow < best.overflow){ + best = { + corner: corner, + aroundCorner: choice.aroundCorner, + x: startX, + y: startY, + w: width, + h: height, + overflow: overflow + }; + } + return !overflow; + }); + + node.style.left = best.x + "px"; + node.style.top = best.y + "px"; + if(best.overflow && layoutNode){ + layoutNode(node, best.aroundCorner, best.corner); + } + return best; +} + +dijit.placeOnScreenAroundElement = function( + /* DomNode */ node, + /* DomNode */ aroundNode, + /* Object */ aroundCorners, + /* Function */ layoutNode){ + + // summary + // Like placeOnScreen, except it accepts aroundNode instead of x,y + // and attempts to place node around it. Uses margin box dimensions. + // + // aroundCorners + // specify Which corner of aroundNode should be + // used to place the node => which corner(s) of node to use (see the + // corners parameter in dijit.placeOnScreen) + // e.g. {'TL': 'BL', 'BL': 'TL'} + // + // layoutNode: Function(node, aroundNodeCorner, nodeCorner) + // for things like tooltip, they are displayed differently (and have different dimensions) + // based on their orientation relative to the parent. This adjusts the popup based on orientation. + + + // get coordinates of aroundNode + aroundNode = dojo.byId(aroundNode); + var oldDisplay = aroundNode.style.display; + aroundNode.style.display=""; + // #3172: use the slightly tighter border box instead of marginBox + var aroundNodeW = aroundNode.offsetWidth; //mb.w; + var aroundNodeH = aroundNode.offsetHeight; //mb.h; + var aroundNodePos = dojo.coords(aroundNode, true); + aroundNode.style.display=oldDisplay; + + // Generate list of possible positions for node + var choices = []; + for(var nodeCorner in aroundCorners){ + choices.push( { + aroundCorner: nodeCorner, + corner: aroundCorners[nodeCorner], + pos: { + x: aroundNodePos.x + (nodeCorner.charAt(1) == 'L' ? 0 : aroundNodeW), + y: aroundNodePos.y + (nodeCorner.charAt(0) == 'T' ? 0 : aroundNodeH) + } + }); + } + + return dijit._place(node, choices, layoutNode); +} + +} + +if(!dojo._hasResource["dojox.flash._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.flash._base"] = true; +dojo.provide("dojox.flash._base"); + +// for dijit.getViewport(), needed by dojox.flash.Embed.center() + + +dojox.flash = function(){ + // summary: + // The goal of dojox.flash is to make it easy to extend Flash's capabilities + // into an Ajax/DHTML environment. + // + // dojox.flash provides an easy object for interacting with the Flash plugin. + // This object provides methods to determine the current version of the Flash + // plugin (dojox.flash.info); write out the necessary markup to + // dynamically insert a Flash object into the page (dojox.flash.Embed; and + // do dynamic installation and upgrading of the current Flash plugin in + // use (dojox.flash.Install). If you want to call methods on the Flash object + // embedded into the page it is your responsibility to use Flash's ExternalInterface + // API and get a reference to the Flash object yourself. + // + // To use dojox.flash, you must first wait until Flash is finished loading + // and initializing before you attempt communication or interaction. + // To know when Flash is finished use dojo.connect: + // + // dojo.connect(dojox.flash, "loaded", myInstance, "myCallback"); + // + // Then, while the page is still loading provide the file name: + // + // dojox.flash.setSwf(dojo.moduleUrl("dojox", "_storage/storage.swf")); + // + // If no SWF files are specified, then Flash is not initialized. + // + // Your Flash must use Flash's ExternalInterface to expose Flash methods and + // to call JavaScript. + // + // setSwf can take an optional 'visible' attribute to control whether + // the Flash object is visible or not on the page; the default is visible: + // + // dojox.flash.setSwf(dojo.moduleUrl("dojox", "_storage/storage.swf"), + // false); + // + // Once finished, you can query Flash version information: + // + // dojox.flash.info.version + // + // Or can communicate with Flash methods that were exposed: + // + // var f = dojox.flash.get(); + // var results = f.sayHello("Some Message"); + // + // Your Flash files should use DojoExternalInterface.as to register methods; + // this file wraps Flash's normal ExternalInterface but correct various + // serialization bugs that ExternalInterface has. + // + // Note that dojox.flash is not meant to be a generic Flash embedding + // mechanism; it is as generic as necessary to make Dojo Storage's + // Flash Storage Provider as clean and modular as possible. If you want + // a generic Flash embed mechanism see SWFObject + // (http://blog.deconcept.com/swfobject/). + // + // Notes: + // Note that dojox.flash can currently only work with one Flash object + // on the page; it does not yet support multiple Flash objects on + // the same page. + // + // Your code can detect whether the Flash player is installing or having + // its version revved in two ways. First, if dojox.flash detects that + // Flash installation needs to occur, it sets dojox.flash.info.installing + // to true. Second, you can detect if installation is necessary with the + // following callback: + // + // dojo.connect(dojox.flash, "installing", myInstance, "myCallback"); + // + // You can use this callback to delay further actions that might need Flash; + // when installation is finished the full page will be refreshed and the + // user will be placed back on your page with Flash installed. + // + // ------------------- + // Todo/Known Issues + // ------------------- + // * On Internet Explorer, after doing a basic install, the page is + // not refreshed or does not detect that Flash is now available. The way + // to fix this is to create a custom small Flash file that is pointed to + // during installation; when it is finished loading, it does a callback + // that says that Flash installation is complete on IE, and we can proceed + // to initialize the dojox.flash subsystem. + // * Things aren't super tested for sending complex objects to Flash + // methods, since Dojo Storage only needs strings + // + // Author- Brad Neuberg, http://codinginparadise.org +} + +dojox.flash = { + ready: false, + url: null, + + _visible: true, + _loadedListeners: new Array(), + _installingListeners: new Array(), + + setSwf: function(/* String */ url, /* boolean? */ visible){ + // summary: Sets the SWF files and versions we are using. + // url: String + // The URL to this Flash file. + // visible: boolean? + // Whether the Flash file is visible or not. If it is not visible we hide it off the + // screen. This defaults to true (i.e. the Flash file is visible). + this.url = url; + + if(typeof visible != "undefined"){ + this._visible = visible; + } + + // initialize ourselves + this._initialize(); + }, + + addLoadedListener: function(/* Function */ listener){ + // summary: + // Adds a listener to know when Flash is finished loading. + // Useful if you don't want a dependency on dojo.event. + // listener: Function + // A function that will be called when Flash is done loading. + + this._loadedListeners.push(listener); + }, + + addInstallingListener: function(/* Function */ listener){ + // summary: + // Adds a listener to know if Flash is being installed. + // Useful if you don't want a dependency on dojo.event. + // listener: Function + // A function that will be called if Flash is being + // installed + + this._installingListeners.push(listener); + }, + + loaded: function(){ + // summary: Called back when the Flash subsystem is finished loading. + // description: + // A callback when the Flash subsystem is finished loading and can be + // worked with. To be notified when Flash is finished loading, add a + // loaded listener: + // + // dojox.flash.addLoadedListener(loadedListener); + + dojox.flash.ready = true; + if(dojox.flash._loadedListeners.length > 0){ + for(var i = 0;i < dojox.flash._loadedListeners.length; i++){ + dojox.flash._loadedListeners[i].call(null); + } + } + }, + + installing: function(){ + // summary: Called if Flash is being installed. + // description: + // A callback to know if Flash is currently being installed or + // having its version revved. To be notified if Flash is installing, connect + // your callback to this method using the following: + // + // dojo.event.connect(dojox.flash, "installing", myInstance, "myCallback"); + + if(dojox.flash._installingListeners.length > 0){ + for(var i = 0; i < dojox.flash._installingListeners.length; i++){ + dojox.flash._installingListeners[i].call(null); + } + } + }, + + // Initializes dojox.flash. + _initialize: function(){ + //console.debug("dojox.flash._initialize"); + // see if we need to rev or install Flash on this platform + var installer = new dojox.flash.Install(); + dojox.flash.installer = installer; + + if(installer.needed() == true){ + installer.install(); + }else{ + // write the flash object into the page + dojox.flash.obj = new dojox.flash.Embed(this._visible); + dojox.flash.obj.write(); + + // setup the communicator + dojox.flash.comm = new dojox.flash.Communicator(); + } + } +}; + + +dojox.flash.Info = function(){ + // summary: A class that helps us determine whether Flash is available. + // description: + // A class that helps us determine whether Flash is available, + // it's major and minor versions, and what Flash version features should + // be used for Flash/JavaScript communication. Parts of this code + // are adapted from the automatic Flash plugin detection code autogenerated + // by the Macromedia Flash 8 authoring environment. + // + // An instance of this class can be accessed on dojox.flash.info after + // the page is finished loading. + // + // This constructor must be called before the page is finished loading. + + // Visual basic helper required to detect Flash Player ActiveX control + // version information on Internet Explorer + if(dojo.isIE){ + document.write([ + ' + // + // Note that inline styles on elements are not handled (i.e. + // if you somehow have an inline style that uses a URL); + // object and embed tags are not scanned since their format + // differs based on type; and elements created by JavaScript + // after page load are not found. For these you must manually + // add them with a dojox.off.files.cache() method call. + + // just schedule the slurp once the page is loaded and + // Dojo Offline is ready to slurp; dojox.off will call + // our _slurp() method before indicating it is finished + // loading + this._doSlurp = true; + }, + + cache: function(urlOrList){ /* void */ + // summary: + // Caches a file or list of files to be available offline. This + // can either be a full URL, such as http://foobar.com/index.html, + // or a relative URL, such as ../index.html. This URL is not + // actually cached until dojox.off.sync.synchronize() is called. + // urlOrList: String or Array[] + // A URL of a file to cache or an Array of Strings of files to + // cache + + //console.debug("dojox.off.files.cache, urlOrList="+urlOrList); + + if(dojo.isString(urlOrList)){ + var url = this._trimAnchor(urlOrList+""); + if(!this.isAvailable(url)){ + this.listOfURLs.push(url); + } + }else if(urlOrList instanceof dojo._Url){ + var url = this._trimAnchor(urlOrList.uri); + if(!this.isAvailable(url)){ + this.listOfURLs.push(url); + } + }else{ + dojo.forEach(urlOrList, function(url){ + url = this._trimAnchor(url); + if(!this.isAvailable(url)){ + this.listOfURLs.push(url); + } + }, this); + } + }, + + printURLs: function(){ + // summary: + // A helper function that will dump and print out + // all of the URLs that are cached for offline + // availability. This can help with debugging if you + // are trying to make sure that all of your URLs are + // available offline + console.debug("The following URLs are cached for offline use:"); + dojo.forEach(this.listOfURLs, function(i){ + console.debug(i); + }); + }, + + remove: function(url){ /* void */ + // summary: + // Removes a URL from the list of files to cache. + // description: + // Removes a URL from the list of URLs to cache. Note that this + // does not actually remove the file from the offline cache; + // instead, it just prevents us from refreshing this file at a + // later time, so that it will naturally time out and be removed + // from the offline cache + // url: String + // The URL to remove + for(var i = 0; i < this.listOfURLs.length; i++){ + if(this.listOfURLs[i] == url){ + this.listOfURLs = this.listOfURLs.splice(i, 1); + break; + } + } + }, + + isAvailable: function(url){ /* boolean */ + // summary: + // Determines whether the given resource is available offline. + // url: String + // The URL to check + for(var i = 0; i < this.listOfURLs.length; i++){ + if(this.listOfURLs[i] == url){ + return true; + } + } + + return false; + }, + + refresh: function(callback){ /* void */ + //console.debug("dojox.off.files.refresh"); + // summary: + // For advanced usage; most developers can ignore this. + // Refreshes our list of offline resources, + // making them available offline. + // callback: Function + // A callback that receives two arguments: whether an error + // occurred, which is a boolean; and an array of error message strings + // with details on errors encountered. If no error occured then message is + // empty array with length 0. + try{ + if(dojo.config.isDebug){ + this.printURLs(); + } + + this.refreshing = true; + + if(this.versionURL){ + this._getVersionInfo(function(oldVersion, newVersion, justDebugged){ + //console.warn("getVersionInfo, oldVersion="+oldVersion+", newVersion="+newVersion + // + ", justDebugged="+justDebugged+", isDebug="+dojo.config.isDebug); + if(dojo.config.isDebug || !newVersion || justDebugged + || !oldVersion || oldVersion != newVersion){ + console.warn("Refreshing offline file list"); + this._doRefresh(callback, newVersion); + }else{ + console.warn("No need to refresh offline file list"); + callback(false, []); + } + }); + }else{ + console.warn("Refreshing offline file list"); + this._doRefresh(callback); + } + }catch(e){ + this.refreshing = false; + + // can't refresh files -- core operation -- + // fail fast + dojox.off.coreOpFailed = true; + dojox.off.enabled = false; + dojox.off.onFrameworkEvent("coreOperationFailed"); + } + }, + + abortRefresh: function(){ + // summary: + // For advanced usage; most developers can ignore this. + // Aborts and cancels a refresh. + if(!this.refreshing){ + return; + } + + this._store.abortCapture(this._cancelID); + this.refreshing = false; + }, + + _slurp: function(){ + if(!this._doSlurp){ + return; + } + + var handleUrl = dojo.hitch(this, function(url){ + if(this._sameLocation(url)){ + this.cache(url); + } + }); + + handleUrl(window.location.href); + + dojo.query("script").forEach(function(i){ + try{ + handleUrl(i.getAttribute("src")); + }catch(exp){ + //console.debug("dojox.off.files.slurp 'script' error: " + // + exp.message||exp); + } + }); + + dojo.query("link").forEach(function(i){ + try{ + if(!i.getAttribute("rel") + || i.getAttribute("rel").toLowerCase() != "stylesheet"){ + return; + } + + handleUrl(i.getAttribute("href")); + }catch(exp){ + //console.debug("dojox.off.files.slurp 'link' error: " + // + exp.message||exp); + } + }); + + dojo.query("img").forEach(function(i){ + try{ + handleUrl(i.getAttribute("src")); + }catch(exp){ + //console.debug("dojox.off.files.slurp 'img' error: " + // + exp.message||exp); + } + }); + + dojo.query("a").forEach(function(i){ + try{ + handleUrl(i.getAttribute("href")); + }catch(exp){ + //console.debug("dojox.off.files.slurp 'a' error: " + // + exp.message||exp); + } + }); + + // FIXME: handle 'object' and 'embed' tag + + // parse our style sheets for inline URLs and imports + dojo.forEach(document.styleSheets, function(sheet){ + try{ + if(sheet.cssRules){ // Firefox + dojo.forEach(sheet.cssRules, function(rule){ + var text = rule.cssText; + if(text){ + var matches = text.match(/url\(\s*([^\) ]*)\s*\)/i); + if(!matches){ + return; + } + + for(var i = 1; i < matches.length; i++){ + handleUrl(matches[i]) + } + } + }); + }else if(sheet.cssText){ // IE + var matches; + var text = sheet.cssText.toString(); + // unfortunately, using RegExp.exec seems to be flakey + // for looping across multiple lines on IE using the + // global flag, so we have to simulate it + var lines = text.split(/\f|\r|\n/); + for(var i = 0; i < lines.length; i++){ + matches = lines[i].match(/url\(\s*([^\) ]*)\s*\)/i); + if(matches && matches.length){ + handleUrl(matches[1]); + } + } + } + }catch(exp){ + //console.debug("dojox.off.files.slurp stylesheet parse error: " + // + exp.message||exp); + } + }); + + //this.printURLs(); + }, + + _sameLocation: function(url){ + if(!url){ return false; } + + // filter out anchors + if(url.length && url.charAt(0) == "#"){ + return false; + } + + // FIXME: dojo._Url should be made public; + // it's functionality is very useful for + // parsing URLs correctly, which is hard to + // do right + url = new dojo._Url(url); + + // totally relative -- ../../someFile.html + if(!url.scheme && !url.port && !url.host){ + return true; + } + + // scheme relative with port specified -- brad.com:8080 + if(!url.scheme && url.host && url.port + && window.location.hostname == url.host + && window.location.port == url.port){ + return true; + } + + // scheme relative with no-port specified -- brad.com + if(!url.scheme && url.host && !url.port + && window.location.hostname == url.host + && window.location.port == 80){ + return true; + } + + // else we have everything + return window.location.protocol == (url.scheme + ":") + && window.location.hostname == url.host + && (window.location.port == url.port || !window.location.port && !url.port); + }, + + _trimAnchor: function(url){ + return url.replace(/\#.*$/, ""); + }, + + _doRefresh: function(callback, newVersion){ + // get our local server + var localServer; + try{ + localServer = google.gears.factory.create("beta.localserver", "1.0"); + }catch(exp){ + dojo.setObject("google.gears.denied", true); + dojox.off.onFrameworkEvent("coreOperationFailed"); + throw "Google Gears must be allowed to run"; + } + + var storeName = "dot_store_" + + window.location.href.replace(/[^0-9A-Za-z_]/g, "_"); + + // clip at 64 characters, the max length of a resource store name + if(storeName.length >= 64){ + storeName = storeName.substring(0, 63); + } + + // refresh everything by simply removing + // any older stores + localServer.removeStore(storeName); + + // open/create the resource store + localServer.openStore(storeName); + var store = localServer.createStore(storeName); + this._store = store; + + // add our list of files to capture + var self = this; + this._currentFileIndex = 0; + this._cancelID = store.capture(this.listOfURLs, function(url, success, captureId){ + //console.debug("store.capture, url="+url+", success="+success); + if(!success && self.refreshing){ + self._cancelID = null; + self.refreshing = false; + var errorMsgs = []; + errorMsgs.push("Unable to capture: " + url); + callback(true, errorMsgs); + return; + }else if(success){ + self._currentFileIndex++; + } + + if(success && self._currentFileIndex >= self.listOfURLs.length){ + self._cancelID = null; + self.refreshing = false; + if(newVersion){ + dojox.storage.put("oldVersion", newVersion, null, + dojox.off.STORAGE_NAMESPACE); + } + dojox.storage.put("justDebugged", dojo.config.isDebug, null, + dojox.off.STORAGE_NAMESPACE); + callback(false, []); + } + }); + }, + + _getVersionInfo: function(callback){ + var justDebugged = dojox.storage.get("justDebugged", + dojox.off.STORAGE_NAMESPACE); + var oldVersion = dojox.storage.get("oldVersion", + dojox.off.STORAGE_NAMESPACE); + var newVersion = null; + + callback = dojo.hitch(this, callback); + + dojo.xhrGet({ + url: this.versionURL + "?browserbust=" + new Date().getTime(), + timeout: 5 * 1000, + handleAs: "javascript", + error: function(err){ + //console.warn("dojox.off.files._getVersionInfo, err=",err); + dojox.storage.remove("oldVersion", dojox.off.STORAGE_NAMESPACE); + dojox.storage.remove("justDebugged", dojox.off.STORAGE_NAMESPACE); + callback(oldVersion, newVersion, justDebugged); + }, + load: function(data){ + //console.warn("dojox.off.files._getVersionInfo, load=",data); + + // some servers incorrectly return 404's + // as a real page + if(data){ + newVersion = data; + } + + callback(oldVersion, newVersion, justDebugged); + } + }); + } +} + +} + +if(!dojo._hasResource["dojox.off.sync"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.off.sync"] = true; +dojo.provide("dojox.off.sync"); + + + + + +// Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org + +// summary: +// Exposes syncing functionality to offline applications +dojo.mixin(dojox.off.sync, { + // isSyncing: boolean + // Whether we are in the middle of a syncing session. + isSyncing: false, + + // cancelled: boolean + // Whether we were cancelled during our last sync request or not. If + // we are cancelled, then successful will be false. + cancelled: false, + + // successful: boolean + // Whether the last sync was successful or not. If false, an error + // occurred. + successful: true, + + // details: String[] + // Details on the sync. If the sync was successful, this will carry + // any conflict or merging messages that might be available; if the + // sync was unsuccessful, this will have an error message. For both + // of these, this should be an array of Strings, where each string + // carries details on the sync. + // Example: + // dojox.off.sync.details = ["The document 'foobar' had conflicts - yours one", + // "The document 'hello world' was automatically merged"]; + details: [], + + // error: boolean + // Whether an error occurred during the syncing process. + error: false, + + // actions: dojox.off.sync.ActionLog + // Our ActionLog that we store offline actions into for later + // replaying when we go online + actions: null, + + // autoSync: boolean + // For advanced usage; most developers can ignore this. + // Whether we do automatically sync on page load or when we go online. + // If true we do, if false syncing must be manually initiated. + // Defaults to true. + autoSync: true, + + // summary: + // An event handler that is called during the syncing process with + // the state of syncing. It is important that you connect to this + // method and respond to certain sync events, especially the + // "download" event. + // description: + // This event handler is called during the syncing process. You can + // do a dojo.connect to receive sync feedback: + // + // dojo.connect(dojox.off.sync, "onSync", someFunc); + // + // You will receive one argument, which is the type of the event + // and which can have the following values. + // + // The most common two types that you need to care about are "download" + // and "finished", especially if you are using the default + // Dojo Offline UI widget that does the hard work of informing + // the user through the UI about what is occuring during syncing. + // + // If you receive the "download" event, you should make a network call + // to retrieve and store your data somehow for offline access. The + // "finished" event indicates that syncing is done. An example: + // + // dojo.connect(dojox.off.sync, "onSync", function(type){ + // if(type == "download"){ + // // make a network call to download some data + // // for use offline + // dojo.xhrGet({ + // url: "downloadData.php", + // handleAs: "javascript", + // error: function(err){ + // dojox.off.sync.finishedDownloading(false, "Can't download data"); + // }, + // load: function(data){ + // // store our data + // dojox.storage.put("myData", data); + // + // // indicate we are finished downloading + // dojox.off.sync.finishedDownloading(true); + // } + // }); + // }else if(type == "finished"){ + // // update UI somehow to indicate we are finished, + // // such as using the download data to change the + // // available data + // } + // }) + // + // Here is the full list of event types if you want to do deep + // customization, such as updating your UI to display the progress + // of syncing (note that the default Dojo Offline UI widget does + // this for you if you choose to pull that in). Most of these + // are only appropriate for advanced usage and can be safely + // ignored: + // + // * "start" + // syncing has started + // * "refreshFiles" + // syncing will begin refreshing + // our offline file cache + // * "upload" + // syncing will begin uploading + // any local data changes we have on the client. + // This event is fired before we fire + // the dojox.off.sync.actions.onReplay event for + // each action to replay; use it to completely + // over-ride the replaying behavior and prevent + // it entirely, perhaps rolling your own sync + // protocol if needed. + // * "download" + // syncing will begin downloading any new data that is + // needed into persistent storage. Applications are required to + // implement this themselves, storing the required data into + // persistent local storage using Dojo Storage. + // * "finished" + // syncing is finished; this + // will be called whether an error ocurred or not; check + // dojox.off.sync.successful and dojox.off.sync.error for sync details + // * "cancel" + // Fired when canceling has been initiated; canceling will be + // attempted, followed by the sync event "finished". + onSync: function(/* String */ type){}, + + synchronize: function(){ /* void */ + // summary: Starts synchronizing + + //dojo.debug("synchronize"); + if(this.isSyncing || dojox.off.goingOnline || (!dojox.off.isOnline)){ + return; + } + + this.isSyncing = true; + this.successful = false; + this.details = []; + this.cancelled = false; + + this.start(); + }, + + cancel: function(){ /* void */ + // summary: + // Attempts to cancel this sync session + + if(!this.isSyncing){ return; } + + this.cancelled = true; + if(dojox.off.files.refreshing){ + dojox.off.files.abortRefresh(); + } + + this.onSync("cancel"); + }, + + finishedDownloading: function(successful /* boolean? */, + errorMessage /* String? */){ + // summary: + // Applications call this method from their + // after getting a "download" event in + // dojox.off.sync.onSync to signal that + // they are finished downloading any data + // that should be available offline + // successful: boolean? + // Whether our downloading was successful or not. + // If not present, defaults to true. + // errorMessage: String? + // If unsuccessful, a message explaining why + if(typeof successful == "undefined"){ + successful = true; + } + + if(!successful){ + this.successful = false; + this.details.push(errorMessage); + this.error = true; + } + + this.finished(); + }, + + start: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Called at the start of the syncing process. Advanced + // developers can over-ride this method to use their + // own sync mechanism to start syncing. + + if(this.cancelled){ + this.finished(); + return; + } + this.onSync("start"); + this.refreshFiles(); + }, + + refreshFiles: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Called when we are going to refresh our list + // of offline files during syncing. Advanced developers + // can over-ride this method to do some advanced magic related to + // refreshing files. + + //dojo.debug("refreshFiles"); + if(this.cancelled){ + this.finished(); + return; + } + + this.onSync("refreshFiles"); + + dojox.off.files.refresh(dojo.hitch(this, function(error, errorMessages){ + if(error){ + this.error = true; + this.successful = false; + for(var i = 0; i < errorMessages.length; i++){ + this.details.push(errorMessages[i]); + } + + // even if we get an error while syncing files, + // keep syncing so we can upload and download + // data + } + + this.upload(); + })); + }, + + upload: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Called when syncing wants to upload data. Advanced + // developers can over-ride this method to completely + // throw away the Action Log and replaying system + // and roll their own advanced sync mechanism if needed. + + if(this.cancelled){ + this.finished(); + return; + } + + this.onSync("upload"); + + // when we are done uploading start downloading + dojo.connect(this.actions, "onReplayFinished", this, this.download); + + // replay the actions log + this.actions.replay(); + }, + + download: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Called when syncing wants to download data. Advanced + // developers can over-ride this method to use their + // own sync mechanism. + + if(this.cancelled){ + this.finished(); + return; + } + + // apps should respond to the "download" + // event to download their data; when done + // they must call dojox.off.sync.finishedDownloading() + this.onSync("download"); + }, + + finished: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Called when syncing is finished. Advanced + // developers can over-ride this method to clean + // up after finishing their own sync + // mechanism they might have rolled. + this.isSyncing = false; + + this.successful = (!this.cancelled && !this.error); + + this.onSync("finished"); + }, + + _save: function(callback){ + this.actions._save(function(){ + callback(); + }); + }, + + _load: function(callback){ + this.actions._load(function(){ + callback(); + }); + } +}); + + +// summary: +// A class that records actions taken by a user when they are offline, +// suitable for replaying when the network reappears. +// description: +// The basic idea behind this method is to record user actions that would +// normally have to contact a server into an action log when we are +// offline, so that later when we are online we can simply replay this log +// in the order user actions happened so that they can be executed against +// the server, causing synchronization to happen. +// +// When we replay, for each of the actions that were added, we call a +// method named onReplay that applications should connect to and +// which will be called over and over for each of our actions -- +// applications should take the offline action +// information and use it to talk to a server to have this action +// actually happen online, 'syncing' themselves with the server. +// +// For example, if the action was "update" with the item that was updated, we +// might call some RESTian server API that exists for updating an item in +// our application. The server could either then do sophisticated merging +// and conflict resolution on the server side, for example, allowing you +// to pop up a custom merge UI, or could do automatic merging or nothing +// of the sort. When you are finished with this particular action, your +// application is then required to call continueReplay() on the actionLog object +// passed to onReplay() to continue replaying the action log, or haltReplay() +// with the reason for halting to completely stop the syncing/replaying +// process. +// +// For example, imagine that we have a web application that allows us to add +// contacts. If we are offline, and we update a contact, we would add an action; +// imagine that the user has to click an Update button after changing the values +// for a given contact: +// +// dojox.off.whenOffline(dojo.byId("updateButton"), "onclick", function(evt){ +// // get the updated customer values +// var customer = getCustomerValues(); +// +// // we are offline -- just record this action +// var action = {name: "update", customer: customer}; +// dojox.off.sync.actions.add(action) +// +// // persist this customer data into local storage as well +// dojox.storage.put(customer.name, customer); +// }) +// +// Then, when we go back online, the dojox.off.sync.actions.onReplay event +// will fire over and over, once for each action that was recorded while offline: +// +// dojo.connect(dojox.off.sync.actions, "onReplay", function(action, actionLog){ +// // called once for each action we added while offline, in the order +// // they were added +// if(action.name == "update"){ +// var customer = action.customer; +// +// // call some network service to update this customer +// dojo.xhrPost({ +// url: "updateCustomer.php", +// content: {customer: dojo.toJson(customer)}, +// error: function(err){ +// actionLog.haltReplay(err); +// }, +// load: function(data){ +// actionLog.continueReplay(); +// } +// }) +// } +// }) +// +// Note that the actions log is always automatically persisted locally while using it, so +// that if the user closes the browser or it crashes the actions will safely be stored +// for later replaying. +dojo.declare("dojox.off.sync.ActionLog", null, { + // entries: Array + // An array of our action entries, where each one is simply a custom + // object literal that were passed to add() when this action entry + // was added. + entries: [], + + // reasonHalted: String + // If we halted, the reason why + reasonHalted: null, + + // isReplaying: boolean + // If true, we are in the middle of replaying a command log; if false, + // then we are not + isReplaying: false, + + // autoSave: boolean + // Whether we automatically save the action log after each call to + // add(); defaults to true. For applications that are rapidly adding + // many action log entries in a short period of time, it can be + // useful to set this to false and simply call save() yourself when + // you are ready to persist your command log -- otherwise performance + // could be slow as the default action is to attempt to persist the + // actions log constantly with calls to add(). + autoSave: true, + + add: function(action /* Object */){ /* void */ + // summary: + // Adds an action to our action log + // description: + // This method will add an action to our + // action log, later to be replayed when we + // go from offline to online. 'action' + // will be available when this action is + // replayed and will be passed to onReplay. + // + // Example usage: + // + // dojox.off.sync.log.add({actionName: "create", itemType: "document", + // {title: "Message", content: "Hello World"}}); + // + // The object literal is simply a custom object appropriate + // for our application -- it can be anything that preserves the state + // of a user action that will be executed when we go back online + // and replay this log. In the above example, + // "create" is the name of this action; "documents" is the + // type of item this command is operating on, such as documents, contacts, + // tasks, etc.; and the final argument is the document that was created. + + if(this.isReplaying){ + throw "Programming error: you can not call " + + "dojox.off.sync.actions.add() while " + + "we are replaying an action log"; + } + + this.entries.push(action); + + // save our updated state into persistent + // storage + if(this.autoSave){ + this._save(); + } + }, + + onReplay: function(action /* Object */, + actionLog /* dojox.off.sync.ActionLog */){ /* void */ + // summary: + // Called when we replay our log, for each of our action + // entries. + // action: Object + // A custom object literal representing an action for this + // application, such as + // {actionName: "create", item: {title: "message", content: "hello world"}} + // actionLog: dojox.off.sync.ActionLog + // A reference to the dojox.off.sync.actions log so that developers + // can easily call actionLog.continueReplay() or actionLog.haltReplay(). + // description: + // This callback should be connected to by applications so that + // they can sync themselves when we go back online: + // + // dojo.connect(dojox.off.sync.actions, "onReplay", function(action, actionLog){ + // // do something + // }) + // + // When we replay our action log, this callback is called for each + // of our action entries in the order they were added. The + // 'action' entry that was passed to add() for this action will + // also be passed in to onReplay, so that applications can use this information + // to do their syncing, such as contacting a server web-service + // to create a new item, for example. + // + // Inside the method you connected to onReplay, you should either call + // actionLog.haltReplay(reason) if an error occurred and you would like to halt + // action replaying or actionLog.continueReplay() to have the action log + // continue replaying its log and proceed to the next action; + // the reason you must call these is the action you execute inside of + // onAction will probably be asynchronous, since it will be talking on + // the network, and you should call one of these two methods based on + // the result of your network call. + }, + + length: function(){ /* Number */ + // summary: + // Returns the length of this + // action log + return this.entries.length; + }, + + haltReplay: function(reason /* String */){ /* void */ + // summary: Halts replaying this command log. + // reason: String + // The reason we halted. + // description: + // This method is called as we are replaying an action log; it + // can be called from dojox.off.sync.actions.onReplay, for + // example, for an application to indicate an error occurred + // while replaying this action, halting further processing of + // the action log. Note that any action log entries that + // were processed before have their effects retained (i.e. + // they are not rolled back), while the action entry that was + // halted stays in our list of actions to later be replayed. + if(!this.isReplaying){ + return; + } + + if(reason){ + this.reasonHalted = reason.toString(); + } + + // save the state of our action log, then + // tell anyone who is interested that we are + // done when we are finished saving + if(this.autoSave){ + var self = this; + this._save(function(){ + self.isReplaying = false; + self.onReplayFinished(); + }); + }else{ + this.isReplaying = false; + this.onReplayFinished(); + } + }, + + continueReplay: function(){ /* void */ + // summary: + // Indicates that we should continue processing out list of + // actions. + // description: + // This method is called by applications that have overridden + // dojox.off.sync.actions.onReplay() to continue replaying our + // action log after the application has finished handling the + // current action. + if(!this.isReplaying){ + return; + } + + // shift off the old action we just ran + this.entries.shift(); + + // are we done? + if(!this.entries.length){ + // save the state of our action log, then + // tell anyone who is interested that we are + // done when we are finished saving + if(this.autoSave){ + var self = this; + this._save(function(){ + self.isReplaying = false; + self.onReplayFinished(); + }); + return; + }else{ + this.isReplaying = false; + this.onReplayFinished(); + return; + } + } + + // get the next action + var nextAction = this.entries[0]; + this.onReplay(nextAction, this); + }, + + clear: function(){ /* void */ + // summary: + // Completely clears this action log of its entries + + if(this.isReplaying){ + return; + } + + this.entries = []; + + // save our updated state into persistent + // storage + if(this.autoSave){ + this._save(); + } + }, + + replay: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Replays all of the commands that have been + // cached in this command log when we go back online; + // onCommand will be called for each command we have + + if(this.isReplaying){ + return; + } + + this.reasonHalted = null; + + if(!this.entries.length){ + this.onReplayFinished(); + return; + } + + this.isReplaying = true; + + var nextAction = this.entries[0]; + this.onReplay(nextAction, this); + }, + + // onReplayFinished: Function + // For advanced usage; most developers can ignore this. + // Called when we are finished replaying our commands; + // called if we have successfully exhausted all of our + // commands, or if an error occurred during replaying. + // The default implementation simply continues the + // synchronization process. Connect to this to register + // for the event: + // + // dojo.connect(dojox.off.sync.actions, "onReplayFinished", + // someFunc) + onReplayFinished: function(){ + }, + + toString: function(){ + var results = ""; + results += "["; + + for(var i = 0; i < this.entries.length; i++){ + results += "{"; + for(var j in this.entries[i]){ + results += j + ": \"" + this.entries[i][j] + "\""; + results += ", "; + } + results += "}, "; + } + + results += "]"; + + return results; + }, + + _save: function(callback){ + if(!callback){ + callback = function(){}; + } + + try{ + var self = this; + var resultsHandler = function(status, key, message){ + //console.debug("resultsHandler, status="+status+", key="+key+", message="+message); + if(status == dojox.storage.FAILED){ + dojox.off.onFrameworkEvent("save", + {status: dojox.storage.FAILED, + isCoreSave: true, + key: key, + value: message, + namespace: dojox.off.STORAGE_NAMESPACE}); + callback(); + }else if(status == dojox.storage.SUCCESS){ + callback(); + } + }; + + dojox.storage.put("actionlog", this.entries, resultsHandler, + dojox.off.STORAGE_NAMESPACE); + }catch(exp){ + console.debug("dojox.off.sync._save: " + exp.message||exp); + dojox.off.onFrameworkEvent("save", + {status: dojox.storage.FAILED, + isCoreSave: true, + key: "actionlog", + value: this.entries, + namespace: dojox.off.STORAGE_NAMESPACE}); + callback(); + } + }, + + _load: function(callback){ + var entries = dojox.storage.get("actionlog", dojox.off.STORAGE_NAMESPACE); + + if(!entries){ + entries = []; + } + + this.entries = entries; + + callback(); + } + } +); + +dojox.off.sync.actions = new dojox.off.sync.ActionLog(); + +} + +if(!dojo._hasResource["dojox.off._common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.off._common"] = true; +dojo.provide("dojox.off._common"); + + + + + +// Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org + +// summary: +// dojox.off is the main object for offline applications. +dojo.mixin(dojox.off, { + // isOnline: boolean + // true if we are online, false if not + isOnline: false, + + // NET_CHECK: int + // For advanced usage; most developers can ignore this. + // Time in seconds on how often we should check the status of the + // network with an automatic background timer. The current default + // is 5 seconds. + NET_CHECK: 5, + + // STORAGE_NAMESPACE: String + // For advanced usage; most developers can ignore this. + // The namespace we use to save core data into Dojo Storage. + STORAGE_NAMESPACE: "_dot", + + // enabled: boolean + // For advanced usage; most developers can ignore this. + // Whether offline ability is enabled or not. Defaults to true. + enabled: true, + + // availabilityURL: String + // For advanced usage; most developers can ignore this. + // The URL to check for site availability. We do a GET request on + // this URL to check for site availability. By default we check for a + // simple text file in src/off/network_check.txt that has one value + // it, the value '1'. + availabilityURL: dojo.moduleUrl("dojox", "off/network_check.txt"), + + // goingOnline: boolean + // For advanced usage; most developers can ignore this. + // True if we are attempting to go online, false otherwise + goingOnline: false, + + // coreOpFailed: boolean + // For advanced usage; most developers can ignore this. + // A flag set by the Dojo Offline framework that indicates that the + // user denied some operation that required the offline cache or an + // operation failed in some critical way that was unrecoverable. For + // example, if the offline cache is Google Gears and we try to get a + // Gears database, a popup window appears asking the user whether they + // will approve or deny this request. If the user denies the request, + // and we are doing some operation that is core to Dojo Offline, then + // we set this flag to 'true'. This flag causes a 'fail fast' + // condition, turning off offline ability. + coreOpFailed: false, + + // doNetChecking: boolean + // For advanced usage; most developers can ignore this. + // Whether to have a timing interval in the background doing automatic + // network checks at regular intervals; the length of time between + // checks is controlled by dojox.off.NET_CHECK. Defaults to true. + doNetChecking: true, + + // hasOfflineCache: boolean + // For advanced usage; most developers can ignore this. + // Determines if an offline cache is available or installed; an + // offline cache is a facility that can truely cache offline + // resources, such as JavaScript, HTML, etc. in such a way that they + // won't be removed from the cache inappropriately like a browser + // cache would. If this is false then an offline cache will be + // installed. Only Google Gears is currently supported as an offline + // cache. Future possible offline caches include Firefox 3. + hasOfflineCache: null, + + // browserRestart: boolean + // For advanced usage; most developers can ignore this. + // If true, the browser must be restarted to register the existence of + // a new host added offline (from a call to addHostOffline); if false, + // then nothing is needed. + browserRestart: false, + + _STORAGE_APP_NAME: window.location.href.replace(/[^0-9A-Za-z_]/g, "_"), + + _initializeCalled: false, + _storageLoaded: false, + _pageLoaded: false, + + onLoad: function(){ + // summary: + // Called when Dojo Offline can be used. + // description: + // Do a dojo.connect to this to know when you can + // start using Dojo Offline: + // dojo.connect(dojox.off, "onLoad", myFunc); + }, + + onNetwork: function(type){ + // summary: + // Called when our on- or offline- status changes. + // description: + // If we move online, then this method is called with the + // value "online". If we move offline, then this method is + // called with the value "offline". You can connect to this + // method to do add your own behavior: + // + // dojo.connect(dojox.off, "onNetwork", someFunc) + // + // Note that if you are using the default Dojo Offline UI + // widget that most of the on- and off-line notification + // and syncing is automatically handled and provided to the + // user. + // type: String + // Either "online" or "offline". + }, + + initialize: function(){ /* void */ + // summary: + // Called when a Dojo Offline-enabled application is finished + // configuring Dojo Offline, and is ready for Dojo Offline to + // initialize itself. + // description: + // When an application has finished filling out the variables Dojo + // Offline needs to work, such as dojox.off.ui.appName, it must + // this method to tell Dojo Offline to initialize itself. + + // Note: + // This method is needed for a rare edge case. In some conditions, + // especially if we are dealing with a compressed Dojo build, the + // entire Dojo Offline subsystem might initialize itself and be + // running even before the JavaScript for an application has had a + // chance to run and configure Dojo Offline, causing Dojo Offline + // to have incorrect initialization parameters for a given app, + // such as no value for dojox.off.ui.appName. This method is + // provided to prevent this scenario, to slightly 'slow down' Dojo + // Offline so it can be configured before running off and doing + // its thing. + + //console.debug("dojox.off.initialize"); + this._initializeCalled = true; + + if(this._storageLoaded && this._pageLoaded){ + this._onLoad(); + } + }, + + goOffline: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Manually goes offline, away from the network. + if((dojox.off.sync.isSyncing)||(this.goingOnline)){ return; } + + this.goingOnline = false; + this.isOnline = false; + }, + + goOnline: function(callback){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Attempts to go online. + // description: + // Attempts to go online, making sure this web application's web + // site is available. 'callback' is called asychronously with the + // result of whether we were able to go online or not. + // callback: Function + // An optional callback function that will receive one argument: + // whether the site is available or not and is boolean. If this + // function is not present we call dojo.xoff.onOnline instead if + // we are able to go online. + + //console.debug("goOnline"); + + if(dojox.off.sync.isSyncing || dojox.off.goingOnline){ + return; + } + + this.goingOnline = true; + this.isOnline = false; + + // see if can reach our web application's web site + this._isSiteAvailable(callback); + }, + + onFrameworkEvent: function(type /* String */, saveData /* Object? */){ + // summary: + // For advanced usage; most developers can ignore this. + // A standard event handler that can be attached to to find out + // about low-level framework events. Most developers will not need to + // attach to this method; it is meant for low-level information + // that can be useful for updating offline user-interfaces in + // exceptional circumstances. The default Dojo Offline UI + // widget takes care of most of these situations. + // type: String + // The type of the event: + // + // * "offlineCacheInstalled" + // An event that is fired when a user + // has installed an offline cache after the page has been loaded. + // If a user didn't have an offline cache when the page loaded, a + // UI of some kind might have prompted them to download one. This + // method is called if they have downloaded and installed an + // offline cache so a UI can reinitialize itself to begin using + // this offline cache. + // * "coreOperationFailed" + // Fired when a core operation during interaction with the + // offline cache is denied by the user. Some offline caches, such + // as Google Gears, prompts the user to approve or deny caching + // files, using the database, and more. If the user denies a + // request that is core to Dojo Offline's operation, we set + // dojox.off.coreOpFailed to true and call this method for + // listeners that would like to respond some how to Dojo Offline + // 'failing fast'. + // * "save" + // Called whenever the framework saves data into persistent + // storage. This could be useful for providing save feedback + // or providing appropriate error feedback if saving fails + // due to a user not allowing the save to occur + // saveData: Object? + // If the type was 'save', then a saveData object is provided with + // further save information. This object has the following properties: + // + // * status - dojox.storage.SUCCESS, dojox.storage.PENDING, dojox.storage.FAILED + // Whether the save succeeded, whether it is pending based on a UI + // dialog asking the user for permission, or whether it failed. + // + // * isCoreSave - boolean + // If true, then this save was for a core piece of data necessary + // for the functioning of Dojo Offline. If false, then it is a + // piece of normal data being saved for offline access. Dojo + // Offline will 'fail fast' if some core piece of data could not + // be saved, automatically setting dojox.off.coreOpFailed to + // 'true' and dojox.off.enabled to 'false'. + // + // * key - String + // The key that we are attempting to persist + // + // * value - Object + // The object we are trying to persist + // + // * namespace - String + // The Dojo Storage namespace we are saving this key/value pair + // into, such as "default", "Documents", "Contacts", etc. + // Optional. + if(type == "save"){ + if(saveData.isCoreSave && (saveData.status == dojox.storage.FAILED)){ + dojox.off.coreOpFailed = true; + dojox.off.enabled = false; + + // FIXME: Stop the background network thread + dojox.off.onFrameworkEvent("coreOperationFailed"); + } + }else if(type == "coreOperationFailed"){ + dojox.off.coreOpFailed = true; + dojox.off.enabled = false; + // FIXME: Stop the background network thread + } + }, + + _checkOfflineCacheAvailable: function(callback){ + // is a true, offline cache running on this machine? + this.hasOfflineCache = dojo.isGears; + + callback(); + }, + + _onLoad: function(){ + //console.debug("dojox.off._onLoad"); + + // both local storage and the page are finished loading + + // cache the Dojo JavaScript -- just use the default dojo.js + // name for the most common scenario + // FIXME: TEST: Make sure syncing doesn't break if dojo.js + // can't be found, or report an error to developer + dojox.off.files.cache(dojo.moduleUrl("dojo", "dojo.js")); + + // pull in the files needed by Dojo + this._cacheDojoResources(); + + // FIXME: need to pull in the firebug lite files here! + // workaround or else we will get an error on page load + // from Dojo that it can't find 'console.debug' for optimized builds + // dojox.off.files.cache(dojo.config.baseRelativePath + "src/debug.js"); + + // make sure that resources needed by all of our underlying + // Dojo Storage storage providers will be available + // offline + dojox.off.files.cache(dojox.storage.manager.getResourceList()); + + // slurp the page if the end-developer wants that + dojox.off.files._slurp(); + + // see if we have an offline cache; when done, move + // on to the rest of our startup tasks + this._checkOfflineCacheAvailable(dojo.hitch(this, "_onOfflineCacheChecked")); + }, + + _onOfflineCacheChecked: function(){ + // this method is part of our _onLoad series of startup tasks + + // if we have an offline cache, see if we have been added to the + // list of available offline web apps yet + if(this.hasOfflineCache && this.enabled){ + // load framework data; when we are finished, continue + // initializing ourselves + this._load(dojo.hitch(this, "_finishStartingUp")); + }else if(this.hasOfflineCache && !this.enabled){ + // we have an offline cache, but it is disabled for some reason + // perhaps due to the user denying a core operation + this._finishStartingUp(); + }else{ + this._keepCheckingUntilInstalled(); + } + }, + + _keepCheckingUntilInstalled: function(){ + // this method is part of our _onLoad series of startup tasks + + // kick off a background interval that keeps + // checking to see if an offline cache has been + // installed since this page loaded + + // FIXME: Gears: See if we are installed somehow after the + // page has been loaded + + // now continue starting up + this._finishStartingUp(); + }, + + _finishStartingUp: function(){ + //console.debug("dojox.off._finishStartingUp"); + + // this method is part of our _onLoad series of startup tasks + + if(!this.hasOfflineCache){ + this.onLoad(); + }else if(this.enabled){ + // kick off a thread to check network status on + // a regular basis + this._startNetworkThread(); + + // try to go online + this.goOnline(dojo.hitch(this, function(){ + //console.debug("Finished trying to go online"); + // indicate we are ready to be used + dojox.off.onLoad(); + })); + }else{ // we are disabled or a core operation failed + if(this.coreOpFailed){ + this.onFrameworkEvent("coreOperationFailed"); + }else{ + this.onLoad(); + } + } + }, + + _onPageLoad: function(){ + //console.debug("dojox.off._onPageLoad"); + this._pageLoaded = true; + + if(this._storageLoaded && this._initializeCalled){ + this._onLoad(); + } + }, + + _onStorageLoad: function(){ + //console.debug("dojox.off._onStorageLoad"); + this._storageLoaded = true; + + // were we able to initialize storage? if + // not, then this is a core operation, and + // let's indicate we will need to fail fast + if(!dojox.storage.manager.isAvailable() + && dojox.storage.manager.isInitialized()){ + this.coreOpFailed = true; + this.enabled = false; + } + + if(this._pageLoaded && this._initializeCalled){ + this._onLoad(); + } + }, + + _isSiteAvailable: function(callback){ + // summary: + // Determines if our web application's website is available. + // description: + // This method will asychronously determine if our web + // application's web site is available, which is a good proxy for + // network availability. The URL dojox.off.availabilityURL is + // used, which defaults to this site's domain name (ex: + // foobar.com). We check for dojox.off.AVAILABILITY_TIMEOUT (in + // seconds) and abort after that + // callback: Function + // An optional callback function that will receive one argument: + // whether the site is available or not and is boolean. If this + // function is not present we call dojox.off.onNetwork instead if we + // are able to go online. + dojo.xhrGet({ + url: this._getAvailabilityURL(), + handleAs: "text", + timeout: this.NET_CHECK * 1000, + error: dojo.hitch(this, function(err){ + //console.debug("dojox.off._isSiteAvailable.error: " + err); + this.goingOnline = false; + this.isOnline = false; + if(callback){ callback(false); } + }), + load: dojo.hitch(this, function(data){ + //console.debug("dojox.off._isSiteAvailable.load, data="+data); + this.goingOnline = false; + this.isOnline = true; + + if(callback){ callback(true); + }else{ this.onNetwork("online"); } + }) + }); + }, + + _startNetworkThread: function(){ + //console.debug("startNetworkThread"); + + // kick off a thread that does periodic + // checks on the status of the network + if(!this.doNetChecking){ + return; + } + + window.setInterval(dojo.hitch(this, function(){ + var d = dojo.xhrGet({ + url: this._getAvailabilityURL(), + handleAs: "text", + timeout: this.NET_CHECK * 1000, + error: dojo.hitch(this, + function(err){ + if(this.isOnline){ + this.isOnline = false; + + // FIXME: xhrGet() is not + // correctly calling abort + // on the XHR object when + // it times out; fix inside + // there instead of externally + // here + try{ + if(typeof d.ioArgs.xhr.abort == "function"){ + d.ioArgs.xhr.abort(); + } + }catch(e){} + + // if things fell in the middle of syncing, + // stop syncing + dojox.off.sync.isSyncing = false; + + this.onNetwork("offline"); + } + } + ), + load: dojo.hitch(this, + function(data){ + if(!this.isOnline){ + this.isOnline = true; + this.onNetwork("online"); + } + } + ) + }); + + }), this.NET_CHECK * 1000); + }, + + _getAvailabilityURL: function(){ + var url = this.availabilityURL.toString(); + + // bust the browser's cache to make sure we are really talking to + // the server + if(url.indexOf("?") == -1){ + url += "?"; + }else{ + url += "&"; + } + url += "browserbust=" + new Date().getTime(); + + return url; + }, + + _onOfflineCacheInstalled: function(){ + this.onFrameworkEvent("offlineCacheInstalled"); + }, + + _cacheDojoResources: function(){ + // if we are a non-optimized build, then the core Dojo bootstrap + // system was loaded as separate JavaScript files; + // add these to our offline cache list. these are + // loaded before the dojo.require() system exists + + // FIXME: create a better mechanism in the Dojo core to + // expose whether you are dealing with an optimized build; + // right now we just scan the SCRIPT tags attached to this + // page and see if there is one for _base/_loader/bootstrap.js + var isOptimizedBuild = true; + dojo.forEach(dojo.query("script"), function(i){ + var src = i.getAttribute("src"); + if(!src){ return; } + + if(src.indexOf("_base/_loader/bootstrap.js") != -1){ + isOptimizedBuild = false; + } + }); + + if(!isOptimizedBuild){ + dojox.off.files.cache(dojo.moduleUrl("dojo", "_base.js").uri); + dojox.off.files.cache(dojo.moduleUrl("dojo", "_base/_loader/loader.js").uri); + dojox.off.files.cache(dojo.moduleUrl("dojo", "_base/_loader/bootstrap.js").uri); + + // FIXME: pull in the host environment file in a more generic way + // for other host environments + dojox.off.files.cache(dojo.moduleUrl("dojo", "_base/_loader/hostenv_browser.js").uri); + } + + // add anything that was brought in with a + // dojo.require() that resulted in a JavaScript + // URL being fetched + + // FIXME: modify dojo/_base/_loader/loader.js to + // expose a public API to get this information + + for(var i = 0; i < dojo._loadedUrls.length; i++){ + dojox.off.files.cache(dojo._loadedUrls[i]); + } + + // FIXME: add the standard Dojo CSS file + }, + + _save: function(){ + // summary: + // Causes the Dojo Offline framework to save its configuration + // data into local storage. + }, + + _load: function(callback){ + // summary: + // Causes the Dojo Offline framework to load its configuration + // data from local storage + dojox.off.sync._load(callback); + } +}); + + +// wait until the storage system is finished loading +dojox.storage.manager.addOnLoad(dojo.hitch(dojox.off, "_onStorageLoad")); + +// wait until the page is finished loading +dojo.addOnLoad(dojox.off, "_onPageLoad"); + +} + +if(!dojo._hasResource["dojox.off"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.off"] = true; +dojo.provide("dojox.off"); + + +} + +if(!dojo._hasResource["dojox.off.ui"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.off.ui"] = true; +dojo.provide("dojox.off.ui"); + + + + + +// Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org + +// summary: +// dojox.off.ui provides a standard, +// default user-interface for a +// Dojo Offline Widget that can easily +// be dropped into applications that would +// like to work offline. +dojo.mixin(dojox.off.ui, { + // appName: String + // This application's name, such as "Foobar". Note that + // this is a string, not HTML, so embedded markup will + // not work, including entities. Only the following + // characters are allowed: numbers, letters, and spaces. + // You must set this property. + appName: "setme", + + // autoEmbed: boolean + // For advanced usage; most developers can ignore this. + // Whether to automatically auto-embed the default Dojo Offline + // widget into this page; default is true. + autoEmbed: true, + + // autoEmbedID: String + // For advanced usage; most developers can ignore this. + // The ID of the DOM element that will contain our + // Dojo Offline widget; defaults to the ID 'dot-widget'. + autoEmbedID: "dot-widget", + + // runLink: String + // For advanced usage; most developers can ignore this. + // The URL that should be navigated to to run this + // application offline; this will be placed inside of a + // link that the user can drag to their desktop and double + // click. Note that this URL must exactly match the URL + // of the main page of our resource that is offline for + // it to be retrieved from the offline cache correctly. + // For example, if you have cached your main page as + // http://foobar.com/index.html, and you set this to + // http://www.foobar.com/index.html, the run link will + // not work. By default this value is automatically set to + // the URL of this page, so it does not need to be set + // manually unless you have unusual needs. + runLink: window.location.href, + + // runLinkTitle: String + // For advanced usage; most developers can ignore this. + // The text that will be inside of the link that a user + // can drag to their desktop to run this application offline. + // By default this is automatically set to "Run " plus your + // application's name. + runLinkTitle: "Run Application", + + // learnHowPath: String + // For advanced usage; most developers can ignore this. + // The path to a web page that has information on + // how to use this web app offline; defaults to + // src/off/ui-template/learnhow.html, relative to + // your Dojo installation. Make sure to set + // dojo.to.ui.customLearnHowPath to true if you want + // a custom Learn How page. + learnHowPath: dojo.moduleUrl("dojox", "off/resources/learnhow.html"), + + // customLearnHowPath: boolean + // For advanced usage; most developers can ignore this. + // Whether the developer is using their own custom page + // for the Learn How instructional page; defaults to false. + // Use in conjunction with dojox.off.ui.learnHowPath. + customLearnHowPath: false, + + htmlTemplatePath: dojo.moduleUrl("dojox", "off/resources/offline-widget.html").uri, + cssTemplatePath: dojo.moduleUrl("dojox", "off/resources/offline-widget.css").uri, + onlineImagePath: dojo.moduleUrl("dojox", "off/resources/greenball.png").uri, + offlineImagePath: dojo.moduleUrl("dojox", "off/resources/redball.png").uri, + rollerImagePath: dojo.moduleUrl("dojox", "off/resources/roller.gif").uri, + checkmarkImagePath: dojo.moduleUrl("dojox", "off/resources/checkmark.png").uri, + learnHowJSPath: dojo.moduleUrl("dojox", "off/resources/learnhow.js").uri, + + _initialized: false, + + onLoad: function(){ + // summary: + // A function that should be connected to allow your + // application to know when Dojo Offline, the page, and + // the Offline Widget are all initialized and ready to be + // used: + // + // dojo.connect(dojox.off.ui, "onLoad", someFunc) + }, + + _initialize: function(){ + //console.debug("dojox.off.ui._initialize"); + + // make sure our app name is correct + if(this._validateAppName(this.appName) == false){ + alert("You must set dojox.off.ui.appName; it can only contain " + + "letters, numbers, and spaces; right now it " + + "is incorrectly set to '" + dojox.off.ui.appName + "'"); + dojox.off.enabled = false; + return; + } + + // set our run link text to its default + this.runLinkText = "Run " + this.appName; + + // setup our event listeners for Dojo Offline events + // to update our UI + dojo.connect(dojox.off, "onNetwork", this, "_onNetwork"); + dojo.connect(dojox.off.sync, "onSync", this, "_onSync"); + + // cache our default UI resources + dojox.off.files.cache([ + this.htmlTemplatePath, + this.cssTemplatePath, + this.onlineImagePath, + this.offlineImagePath, + this.rollerImagePath, + this.checkmarkImagePath + ]); + + // embed the offline widget UI + if(this.autoEmbed){ + this._doAutoEmbed(); + } + }, + + _doAutoEmbed: function(){ + // fetch our HTML for the offline widget + + // dispatch the request + dojo.xhrGet({ + url: this.htmlTemplatePath, + handleAs: "text", + error: function(err){ + dojox.off.enabled = false; + err = err.message||err; + alert("Error loading the Dojo Offline Widget from " + + this.htmlTemplatePath + ": " + err); + }, + load: dojo.hitch(this, this._templateLoaded) + }); + }, + + _templateLoaded: function(data){ + //console.debug("dojox.off.ui._templateLoaded"); + // inline our HTML + var container = dojo.byId(this.autoEmbedID); + if(container){ container.innerHTML = data; } + + // fill out our image paths + this._initImages(); + + // update our network indicator status ball + this._updateNetIndicator(); + + // update our 'Learn How' text + this._initLearnHow(); + + this._initialized = true; + + // check offline cache settings + if(!dojox.off.hasOfflineCache){ + this._showNeedsOfflineCache(); + return; + } + + // check to see if we need a browser restart + // to be able to use this web app offline + if(dojox.off.hasOfflineCache && dojox.off.browserRestart){ + this._needsBrowserRestart(); + return; + }else{ + var browserRestart = dojo.byId("dot-widget-browser-restart"); + if(browserRestart){ browserRestart.style.display = "none"; } + } + + // update our sync UI + this._updateSyncUI(); + + // register our event listeners for our main buttons + this._initMainEvtHandlers(); + + // if offline functionality is disabled, disable everything + this._setOfflineEnabled(dojox.off.enabled); + + // update our UI based on the state of the network + this._onNetwork(dojox.off.isOnline ? "online" : "offline"); + + // try to go online + this._testNet(); + }, + + _testNet: function(){ + dojox.off.goOnline(dojo.hitch(this, function(isOnline){ + //console.debug("testNet callback, isOnline="+isOnline); + + // display our online/offline results + this._onNetwork(isOnline ? "online" : "offline"); + + // indicate that our default UI + // and Dojo Offline are now ready to + // be used + this.onLoad(); + })); + }, + + _updateNetIndicator: function(){ + var onlineImg = dojo.byId("dot-widget-network-indicator-online"); + var offlineImg = dojo.byId("dot-widget-network-indicator-offline"); + var titleText = dojo.byId("dot-widget-title-text"); + + if(onlineImg && offlineImg){ + if(dojox.off.isOnline == true){ + onlineImg.style.display = "inline"; + offlineImg.style.display = "none"; + }else{ + onlineImg.style.display = "none"; + offlineImg.style.display = "inline"; + } + } + + if(titleText){ + if(dojox.off.isOnline){ + titleText.innerHTML = "Online"; + }else{ + titleText.innerHTML = "Offline"; + } + } + }, + + _initLearnHow: function(){ + var learnHow = dojo.byId("dot-widget-learn-how-link"); + + if(!learnHow){ return; } + + if(!this.customLearnHowPath){ + // add parameters to URL so the Learn How page + // can customize itself and display itself + // correctly based on framework settings + var dojoPath = dojo.config.baseRelativePath; + this.learnHowPath += "?appName=" + encodeURIComponent(this.appName) + + "&hasOfflineCache=" + dojox.off.hasOfflineCache + + "&runLink=" + encodeURIComponent(this.runLink) + + "&runLinkText=" + encodeURIComponent(this.runLinkText) + + "&baseRelativePath=" + encodeURIComponent(dojoPath); + + // cache our Learn How JavaScript page and + // the HTML version with full query parameters + // so it is available offline without a cache miss + dojox.off.files.cache(this.learnHowJSPath); + dojox.off.files.cache(this.learnHowPath); + } + + learnHow.setAttribute("href", this.learnHowPath); + + var appName = dojo.byId("dot-widget-learn-how-app-name"); + + if(!appName){ return; } + + appName.innerHTML = ""; + appName.appendChild(document.createTextNode(this.appName)); + }, + + _validateAppName: function(appName){ + if(!appName){ return false; } + + return (/^[a-z0-9 ]*$/i.test(appName)); + }, + + _updateSyncUI: function(){ + var roller = dojo.byId("dot-roller"); + var checkmark = dojo.byId("dot-success-checkmark"); + var syncMessages = dojo.byId("dot-sync-messages"); + var details = dojo.byId("dot-sync-details"); + var cancel = dojo.byId("dot-sync-cancel"); + + if(dojox.off.sync.isSyncing){ + this._clearSyncMessage(); + + if(roller){ roller.style.display = "inline"; } + + if(checkmark){ checkmark.style.display = "none"; } + + if(syncMessages){ + dojo.removeClass(syncMessages, "dot-sync-error"); + } + + if(details){ details.style.display = "none"; } + + if(cancel){ cancel.style.display = "inline"; } + }else{ + if(roller){ roller.style.display = "none"; } + + if(cancel){ cancel.style.display = "none"; } + + if(syncMessages){ + dojo.removeClass(syncMessages, "dot-sync-error"); + } + } + }, + + _setSyncMessage: function(message){ + var syncMessage = dojo.byId("dot-sync-messages"); + if(syncMessage){ + // when used with Google Gears pre-release in Firefox/Mac OS X, + // the browser would crash when testing in Moxie + // if we set the message this way for some reason. + // Brad Neuberg, bkn3@columbia.edu + //syncMessage.innerHTML = message; + + while(syncMessage.firstChild){ + syncMessage.removeChild(syncMessage.firstChild); + } + syncMessage.appendChild(document.createTextNode(message)); + } + }, + + _clearSyncMessage: function(){ + this._setSyncMessage(""); + }, + + _initImages: function(){ + var onlineImg = dojo.byId("dot-widget-network-indicator-online"); + if(onlineImg){ + onlineImg.setAttribute("src", this.onlineImagePath); + } + + var offlineImg = dojo.byId("dot-widget-network-indicator-offline"); + if(offlineImg){ + offlineImg.setAttribute("src", this.offlineImagePath); + } + + var roller = dojo.byId("dot-roller"); + if(roller){ + roller.setAttribute("src", this.rollerImagePath); + } + + var checkmark = dojo.byId("dot-success-checkmark"); + if(checkmark){ + checkmark.setAttribute("src", this.checkmarkImagePath); + } + }, + + _showDetails: function(evt){ + // cancel the button's default behavior + evt.preventDefault(); + evt.stopPropagation(); + + if(!dojox.off.sync.details.length){ + return; + } + + // determine our HTML message to display + var html = ""; + html += "Sync Details"; + html += "

                  Sync Details

                  \n"; + html += "
                    \n"; + for(var i = 0; i < dojox.off.sync.details.length; i++){ + html += "
                  • "; + html += dojox.off.sync.details[i]; + html += "
                  • "; + } + html += "
                  \n"; + html += "" + + "Close Window" + + "\n"; + html += ""; + + // open a popup window with this message + var windowParams = "height=400,width=600,resizable=true," + + "scrollbars=true,toolbar=no,menubar=no," + + "location=no,directories=no,dependent=yes"; + + var popup = window.open("", "SyncDetails", windowParams); + + if(!popup){ // aggressive popup blocker + alert("Please allow popup windows for this domain; can't display sync details window"); + return; + } + + popup.document.open(); + popup.document.write(html); + popup.document.close(); + + // put the focus on the popup window + if(popup.focus){ + popup.focus(); + } + }, + + _cancel: function(evt){ + // cancel the button's default behavior + evt.preventDefault(); + evt.stopPropagation(); + + dojox.off.sync.cancel(); + }, + + _needsBrowserRestart: function(){ + var browserRestart = dojo.byId("dot-widget-browser-restart"); + if(browserRestart){ + dojo.addClass(browserRestart, "dot-needs-browser-restart"); + } + + var appName = dojo.byId("dot-widget-browser-restart-app-name"); + if(appName){ + appName.innerHTML = ""; + appName.appendChild(document.createTextNode(this.appName)); + } + + var status = dojo.byId("dot-sync-status"); + if(status){ + status.style.display = "none"; + } + }, + + _showNeedsOfflineCache: function(){ + var widgetContainer = dojo.byId("dot-widget-container"); + if(widgetContainer){ + dojo.addClass(widgetContainer, "dot-needs-offline-cache"); + } + }, + + _hideNeedsOfflineCache: function(){ + var widgetContainer = dojo.byId("dot-widget-container"); + if(widgetContainer){ + dojo.removeClass(widgetContainer, "dot-needs-offline-cache"); + } + }, + + _initMainEvtHandlers: function(){ + var detailsButton = dojo.byId("dot-sync-details-button"); + if(detailsButton){ + dojo.connect(detailsButton, "onclick", this, this._showDetails); + } + var cancelButton = dojo.byId("dot-sync-cancel-button"); + if(cancelButton){ + dojo.connect(cancelButton, "onclick", this, this._cancel); + } + }, + + _setOfflineEnabled: function(enabled){ + var elems = []; + elems.push(dojo.byId("dot-sync-status")); + + for(var i = 0; i < elems.length; i++){ + if(elems[i]){ + elems[i].style.visibility = + (enabled ? "visible" : "hidden"); + } + } + }, + + _syncFinished: function(){ + this._updateSyncUI(); + + var checkmark = dojo.byId("dot-success-checkmark"); + var details = dojo.byId("dot-sync-details"); + + if(dojox.off.sync.successful == true){ + this._setSyncMessage("Sync Successful"); + if(checkmark){ checkmark.style.display = "inline"; } + }else if(dojox.off.sync.cancelled == true){ + this._setSyncMessage("Sync Cancelled"); + + if(checkmark){ checkmark.style.display = "none"; } + }else{ + this._setSyncMessage("Sync Error"); + + var messages = dojo.byId("dot-sync-messages"); + if(messages){ + dojo.addClass(messages, "dot-sync-error"); + } + + if(checkmark){ checkmark.style.display = "none"; } + } + + if(dojox.off.sync.details.length && details){ + details.style.display = "inline"; + } + }, + + _onFrameworkEvent: function(type, saveData){ + if(type == "save"){ + if(saveData.status == dojox.storage.FAILED && !saveData.isCoreSave){ + alert("Please increase the amount of local storage available " + + "to this application"); + if(dojox.storage.hasSettingsUI()){ + dojox.storage.showSettingsUI(); + } + + // FIXME: Be able to know if storage size has changed + // due to user configuration + } + }else if(type == "coreOperationFailed"){ + console.log("Application does not have permission to use Dojo Offline"); + + if(!this._userInformed){ + alert("This application will not work if Google Gears is not allowed to run"); + this._userInformed = true; + } + }else if(type == "offlineCacheInstalled"){ + // clear out the 'needs offline cache' info + this._hideNeedsOfflineCache(); + + // check to see if we need a browser restart + // to be able to use this web app offline + if(dojox.off.hasOfflineCache == true + && dojox.off.browserRestart == true){ + this._needsBrowserRestart(); + return; + }else{ + var browserRestart = dojo.byId("dot-widget-browser-restart"); + if(browserRestart){ + browserRestart.style.display = "none"; + } + } + + // update our sync UI + this._updateSyncUI(); + + // register our event listeners for our main buttons + this._initMainEvtHandlers(); + + // if offline is disabled, disable everything + this._setOfflineEnabled(dojox.off.enabled); + + // try to go online + this._testNet(); + } + }, + + _onSync: function(type){ + //console.debug("ui, onSync="+type); + switch(type){ + case "start": + this._updateSyncUI(); + break; + + case "refreshFiles": + this._setSyncMessage("Downloading UI..."); + break; + + case "upload": + this._setSyncMessage("Uploading new data..."); + break; + + case "download": + this._setSyncMessage("Downloading new data..."); + break; + + case "finished": + this._syncFinished(); + break; + + case "cancel": + this._setSyncMessage("Canceling Sync..."); + break; + + default: + dojo.warn("Programming error: " + + "Unknown sync type in dojox.off.ui: " + type); + break; + } + }, + + _onNetwork: function(type){ + // summary: + // Called when we go on- or off-line + // description: + // When we go online or offline, this method is called to update + // our UI. Default behavior is to update the Offline + // Widget UI and to attempt a synchronization. + // type: String + // "online" if we just moved online, and "offline" if we just + // moved offline. + + if(!this._initialized){ return; } + + // update UI + this._updateNetIndicator(); + + if(type == "offline"){ + this._setSyncMessage("You are working offline"); + + // clear old details + var details = dojo.byId("dot-sync-details"); + if(details){ details.style.display = "none"; } + + // if we fell offline during a sync, hide + // the sync info + this._updateSyncUI(); + }else{ // online + // synchronize, but pause for a few seconds + // so that the user can orient themselves + if(dojox.off.sync.autoSync){ + if(dojo.isAIR){ + window.setTimeout(function(){dojox.off.sync.synchronize();}, 1000); + }else{ + window.setTimeout(dojox._scopeName + ".off.sync.synchronize()", 1000); + } + } + } + } +}); + +// register ourselves for low-level framework events +dojo.connect(dojox.off, "onFrameworkEvent", dojox.off.ui, "_onFrameworkEvent"); + +// start our magic when the Dojo Offline framework is ready to go +dojo.connect(dojox.off, "onLoad", dojox.off.ui, dojox.off.ui._initialize); + +} + +if(!dojo._hasResource["dojox.off.offline"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.off.offline"] = true; +dojo.provide("dojox.off.offline"); + + + + + + + +} + diff --git a/includes/js/dojox/off/resources/checkmark.png b/includes/js/dojox/off/resources/checkmark.png new file mode 100644 index 0000000..a0ffbb1 Binary files /dev/null and b/includes/js/dojox/off/resources/checkmark.png differ diff --git a/includes/js/dojox/off/resources/greenball.png b/includes/js/dojox/off/resources/greenball.png new file mode 100644 index 0000000..520b6a6 Binary files /dev/null and b/includes/js/dojox/off/resources/greenball.png differ diff --git a/includes/js/dojox/off/resources/learnhow.html b/includes/js/dojox/off/resources/learnhow.html new file mode 100644 index 0000000..2833fcc --- /dev/null +++ b/includes/js/dojox/off/resources/learnhow.html @@ -0,0 +1,43 @@ + + + + + + + + +
                  +

                  Want to use Application offline?

                  + +

                  It's simple with Dojo Offline! Dojo Offline is a free open source utility that makes it easy + for this web application to work, even if you're offline. Now you can + access your data even when away from the network!

                  + +

                  Dojo Offline is an open source project brought to you by + Dojo, SitePen, + and Brad Neuberg. It incorporates + technologies created by Google.

                  + +

                  To get started:

                  + +
                    +
                  1. + Download Gears, a small, open source utility created by Google that allows this web site + to work offline. This tool is safe and secure for your machine, and only takes + a few seconds to download. +
                  2. +
                  3. + Once downloaded, run the installer. Restart your web browser when finished installing. +
                  4. + + +
                  +
                  + + \ No newline at end of file diff --git a/includes/js/dojox/off/resources/learnhow.js b/includes/js/dojox/off/resources/learnhow.js new file mode 100644 index 0000000..82d5506 --- /dev/null +++ b/includes/js/dojox/off/resources/learnhow.js @@ -0,0 +1,43 @@ +window.onload = function(){ + // get the app name from our URL + var href = window.location.href; + var matches = href.match(/appName=([a-z0-9 \%]*)/i); + var appName = "Application"; + if(matches && matches.length > 0){ + appName = decodeURIComponent(matches[1]); + } + + // set it in our UI + var appNameSpan = document.getElementById("dot-learn-how-app-name"); + appNameSpan.innerHTML = ""; + appNameSpan.appendChild(document.createTextNode(appName)); + + // if we need an offline cache, and we already have one installed, + // update the UI + matches = href.match(/hasOfflineCache=(true|false)/); + var hasOfflineCache = false; + if(matches && matches.length > 0){ + hasOfflineCache = matches[1]; + // convert to boolean + hasOfflineCache = (hasOfflineCache == "true") ? true : false; + } + if(hasOfflineCache == true){ + // delete the download and install steps + var downloadStep = document.getElementById("dot-download-step"); + var installStep = document.getElementById("dot-install-step"); + downloadStep.parentNode.removeChild(downloadStep); + installStep.parentNode.removeChild(installStep); + } + + // get our run link info and update the UI + matches = href.match(/runLink=([^\&]*)\&runLinkText=([^\&]*)/); + if(matches && matches.length > 0){ + var runLink = decodeURIComponent(matches[1]); + var runLinkElem = document.getElementById("dot-learn-how-run-link"); + runLinkElem.setAttribute("href", runLink); + + var runLinkText = decodeURIComponent(matches[2]); + runLinkElem.innerHTML = ""; + runLinkElem.appendChild(document.createTextNode(runLinkText)); + } +} diff --git a/includes/js/dojox/off/resources/offline-widget.css b/includes/js/dojox/off/resources/offline-widget.css new file mode 100644 index 0000000..3d095e9 --- /dev/null +++ b/includes/js/dojox/off/resources/offline-widget.css @@ -0,0 +1,88 @@ + +#dot-widget-container{ + + width: 13em; + height: auto; + border: 2px solid #CDDDE9; + position: relative; + visibility: visible !important; +} +#dot-widget-title-bar{ + background-color: #CDDDE9; + padding-top: 0.2em; + padding-bottom: 0.2em; +} +#dot-widget-network-indicator{ + height: 8px; + width: 8px; + padding-left: 0.3em; +} +#dot-widget-title-text{ + vertical-align: middle; + font-weight: bold; + font-size: 14pt; + padding-left: 2px; +} +#dot-widget-contents{ + padding: 8px 5px 8px 5px; +} +#dot-widget-learn-how{ + font-size: 11pt; +} +#dot-sync-cancel, +#dot-sync-status{ + font-size: 11pt; +} +#dot-success-checkmark{ + display: none; +} +#dot-roller{ + display: none; + padding-right: 4px; +} +.dot-sync-error{ + color: red; +} +#dot-sync-details{ + display: none; + padding-left: 0.2em; +} +#dot-sync-status{ + height: 2em; + margin-top: 0.8em; + margin-bottom: 0.8em; +} +.dot-needs-offline-cache #dot-widget-learn-how, +.dot-needs-browser-restart{ + text-align: center; + line-height: 1.2; + font-size: 16pt !important; +} +.dot-needs-offline-cache #dot-sync-status, +.dot-needs-offline-cache #dot-widget-browser-restart{ + display: none; +} +.dot-needs-browser-restart{ + font-size: 14pt !important; + padding-bottom: 1em; + padding-top: 1em; +} +#dot-learn-how-body{ + padding: 3em; + background-color: #CDDDE9; +} +#dot-learn-how-contents{ + border: 1px solid black; + background-color: white; + padding: 0.4em 0.6em 0.4em 0.6em; + font-size: 16pt; +} +#dot-learn-how-contents h1{ + font-size: 24pt; +} +#dot-learn-how-contents h2{ + font-size: 18pt; +} +#dot-learn-how-contents li{ + padding-bottom: 0.6em; +} diff --git a/includes/js/dojox/off/resources/offline-widget.css.commented.css b/includes/js/dojox/off/resources/offline-widget.css.commented.css new file mode 100644 index 0000000..374a43b --- /dev/null +++ b/includes/js/dojox/off/resources/offline-widget.css.commented.css @@ -0,0 +1,112 @@ +/** Offline Widget Styles */ + +#dot-widget-container{ + /** + Keep these as EMs so widget reflows fluidly based on + user-font size settings + */ + width: 13em; + height: auto; + border: 2px solid #CDDDE9; /* light tundra blue */ + position: relative; + visibility: visible !important; +} + +#dot-widget-title-bar{ + background-color: #CDDDE9; /* light tundra blue */ + padding-top: 0.2em; + padding-bottom: 0.2em; +} + +#dot-widget-network-indicator{ + height: 8px; + width: 8px; + padding-left: 0.3em; +} + +#dot-widget-title-text{ + vertical-align: middle; + font-weight: bold; + font-size: 14pt; + padding-left: 2px; +} + +#dot-widget-contents{ + padding: 8px 5px 8px 5px; +} + +#dot-widget-learn-how{ + font-size: 11pt; +} + +#dot-sync-cancel, +#dot-sync-status{ + font-size: 11pt; +} + +#dot-success-checkmark{ + display: none; +} + +#dot-roller{ + display: none; + padding-right: 4px; +} + +.dot-sync-error{ + color: red; +} + +#dot-sync-details{ + display: none; + padding-left: 0.2em; +} + +#dot-sync-status{ + height: 2em; + margin-top: 0.8em; + margin-bottom: 0.8em; +} + +.dot-needs-offline-cache #dot-widget-learn-how, +.dot-needs-browser-restart{ + text-align: center; + line-height: 1.2; + font-size: 16pt !important; +} + +.dot-needs-offline-cache #dot-sync-status, +.dot-needs-offline-cache #dot-widget-browser-restart{ + display: none; +} + +.dot-needs-browser-restart{ + font-size: 14pt !important; + padding-bottom: 1em; + padding-top: 1em; +} + +/** Learn How Page Styles */ +#dot-learn-how-body{ + padding: 3em; + background-color: #CDDDE9; /* light tundra blue */ +} + +#dot-learn-how-contents{ + border: 1px solid black; + background-color: white; + padding: 0.4em 0.6em 0.4em 0.6em; + font-size: 16pt; +} + +#dot-learn-how-contents h1{ + font-size: 24pt; +} + +#dot-learn-how-contents h2{ + font-size: 18pt; +} + +#dot-learn-how-contents li{ + padding-bottom: 0.6em; +} diff --git a/includes/js/dojox/off/resources/offline-widget.html b/includes/js/dojox/off/resources/offline-widget.html new file mode 100644 index 0000000..5791644 --- /dev/null +++ b/includes/js/dojox/off/resources/offline-widget.html @@ -0,0 +1,40 @@ + + + \ No newline at end of file diff --git a/includes/js/dojox/off/resources/redball.png b/includes/js/dojox/off/resources/redball.png new file mode 100644 index 0000000..cc224c3 Binary files /dev/null and b/includes/js/dojox/off/resources/redball.png differ diff --git a/includes/js/dojox/off/resources/roller.gif b/includes/js/dojox/off/resources/roller.gif new file mode 100644 index 0000000..24a3a24 Binary files /dev/null and b/includes/js/dojox/off/resources/roller.gif differ diff --git a/includes/js/dojox/off/sync.js b/includes/js/dojox/off/sync.js new file mode 100644 index 0000000..9927fbe --- /dev/null +++ b/includes/js/dojox/off/sync.js @@ -0,0 +1,690 @@ +if(!dojo._hasResource["dojox.off.sync"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.off.sync"] = true; +dojo.provide("dojox.off.sync"); + +dojo.require("dojox.storage.GearsStorageProvider"); +dojo.require("dojox.off._common"); +dojo.require("dojox.off.files"); + +// Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org + +// summary: +// Exposes syncing functionality to offline applications +dojo.mixin(dojox.off.sync, { + // isSyncing: boolean + // Whether we are in the middle of a syncing session. + isSyncing: false, + + // cancelled: boolean + // Whether we were cancelled during our last sync request or not. If + // we are cancelled, then successful will be false. + cancelled: false, + + // successful: boolean + // Whether the last sync was successful or not. If false, an error + // occurred. + successful: true, + + // details: String[] + // Details on the sync. If the sync was successful, this will carry + // any conflict or merging messages that might be available; if the + // sync was unsuccessful, this will have an error message. For both + // of these, this should be an array of Strings, where each string + // carries details on the sync. + // Example: + // dojox.off.sync.details = ["The document 'foobar' had conflicts - yours one", + // "The document 'hello world' was automatically merged"]; + details: [], + + // error: boolean + // Whether an error occurred during the syncing process. + error: false, + + // actions: dojox.off.sync.ActionLog + // Our ActionLog that we store offline actions into for later + // replaying when we go online + actions: null, + + // autoSync: boolean + // For advanced usage; most developers can ignore this. + // Whether we do automatically sync on page load or when we go online. + // If true we do, if false syncing must be manually initiated. + // Defaults to true. + autoSync: true, + + // summary: + // An event handler that is called during the syncing process with + // the state of syncing. It is important that you connect to this + // method and respond to certain sync events, especially the + // "download" event. + // description: + // This event handler is called during the syncing process. You can + // do a dojo.connect to receive sync feedback: + // + // dojo.connect(dojox.off.sync, "onSync", someFunc); + // + // You will receive one argument, which is the type of the event + // and which can have the following values. + // + // The most common two types that you need to care about are "download" + // and "finished", especially if you are using the default + // Dojo Offline UI widget that does the hard work of informing + // the user through the UI about what is occuring during syncing. + // + // If you receive the "download" event, you should make a network call + // to retrieve and store your data somehow for offline access. The + // "finished" event indicates that syncing is done. An example: + // + // dojo.connect(dojox.off.sync, "onSync", function(type){ + // if(type == "download"){ + // // make a network call to download some data + // // for use offline + // dojo.xhrGet({ + // url: "downloadData.php", + // handleAs: "javascript", + // error: function(err){ + // dojox.off.sync.finishedDownloading(false, "Can't download data"); + // }, + // load: function(data){ + // // store our data + // dojox.storage.put("myData", data); + // + // // indicate we are finished downloading + // dojox.off.sync.finishedDownloading(true); + // } + // }); + // }else if(type == "finished"){ + // // update UI somehow to indicate we are finished, + // // such as using the download data to change the + // // available data + // } + // }) + // + // Here is the full list of event types if you want to do deep + // customization, such as updating your UI to display the progress + // of syncing (note that the default Dojo Offline UI widget does + // this for you if you choose to pull that in). Most of these + // are only appropriate for advanced usage and can be safely + // ignored: + // + // * "start" + // syncing has started + // * "refreshFiles" + // syncing will begin refreshing + // our offline file cache + // * "upload" + // syncing will begin uploading + // any local data changes we have on the client. + // This event is fired before we fire + // the dojox.off.sync.actions.onReplay event for + // each action to replay; use it to completely + // over-ride the replaying behavior and prevent + // it entirely, perhaps rolling your own sync + // protocol if needed. + // * "download" + // syncing will begin downloading any new data that is + // needed into persistent storage. Applications are required to + // implement this themselves, storing the required data into + // persistent local storage using Dojo Storage. + // * "finished" + // syncing is finished; this + // will be called whether an error ocurred or not; check + // dojox.off.sync.successful and dojox.off.sync.error for sync details + // * "cancel" + // Fired when canceling has been initiated; canceling will be + // attempted, followed by the sync event "finished". + onSync: function(/* String */ type){}, + + synchronize: function(){ /* void */ + // summary: Starts synchronizing + + //dojo.debug("synchronize"); + if(this.isSyncing || dojox.off.goingOnline || (!dojox.off.isOnline)){ + return; + } + + this.isSyncing = true; + this.successful = false; + this.details = []; + this.cancelled = false; + + this.start(); + }, + + cancel: function(){ /* void */ + // summary: + // Attempts to cancel this sync session + + if(!this.isSyncing){ return; } + + this.cancelled = true; + if(dojox.off.files.refreshing){ + dojox.off.files.abortRefresh(); + } + + this.onSync("cancel"); + }, + + finishedDownloading: function(successful /* boolean? */, + errorMessage /* String? */){ + // summary: + // Applications call this method from their + // after getting a "download" event in + // dojox.off.sync.onSync to signal that + // they are finished downloading any data + // that should be available offline + // successful: boolean? + // Whether our downloading was successful or not. + // If not present, defaults to true. + // errorMessage: String? + // If unsuccessful, a message explaining why + if(typeof successful == "undefined"){ + successful = true; + } + + if(!successful){ + this.successful = false; + this.details.push(errorMessage); + this.error = true; + } + + this.finished(); + }, + + start: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Called at the start of the syncing process. Advanced + // developers can over-ride this method to use their + // own sync mechanism to start syncing. + + if(this.cancelled){ + this.finished(); + return; + } + this.onSync("start"); + this.refreshFiles(); + }, + + refreshFiles: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Called when we are going to refresh our list + // of offline files during syncing. Advanced developers + // can over-ride this method to do some advanced magic related to + // refreshing files. + + //dojo.debug("refreshFiles"); + if(this.cancelled){ + this.finished(); + return; + } + + this.onSync("refreshFiles"); + + dojox.off.files.refresh(dojo.hitch(this, function(error, errorMessages){ + if(error){ + this.error = true; + this.successful = false; + for(var i = 0; i < errorMessages.length; i++){ + this.details.push(errorMessages[i]); + } + + // even if we get an error while syncing files, + // keep syncing so we can upload and download + // data + } + + this.upload(); + })); + }, + + upload: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Called when syncing wants to upload data. Advanced + // developers can over-ride this method to completely + // throw away the Action Log and replaying system + // and roll their own advanced sync mechanism if needed. + + if(this.cancelled){ + this.finished(); + return; + } + + this.onSync("upload"); + + // when we are done uploading start downloading + dojo.connect(this.actions, "onReplayFinished", this, this.download); + + // replay the actions log + this.actions.replay(); + }, + + download: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Called when syncing wants to download data. Advanced + // developers can over-ride this method to use their + // own sync mechanism. + + if(this.cancelled){ + this.finished(); + return; + } + + // apps should respond to the "download" + // event to download their data; when done + // they must call dojox.off.sync.finishedDownloading() + this.onSync("download"); + }, + + finished: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Called when syncing is finished. Advanced + // developers can over-ride this method to clean + // up after finishing their own sync + // mechanism they might have rolled. + this.isSyncing = false; + + this.successful = (!this.cancelled && !this.error); + + this.onSync("finished"); + }, + + _save: function(callback){ + this.actions._save(function(){ + callback(); + }); + }, + + _load: function(callback){ + this.actions._load(function(){ + callback(); + }); + } +}); + + +// summary: +// A class that records actions taken by a user when they are offline, +// suitable for replaying when the network reappears. +// description: +// The basic idea behind this method is to record user actions that would +// normally have to contact a server into an action log when we are +// offline, so that later when we are online we can simply replay this log +// in the order user actions happened so that they can be executed against +// the server, causing synchronization to happen. +// +// When we replay, for each of the actions that were added, we call a +// method named onReplay that applications should connect to and +// which will be called over and over for each of our actions -- +// applications should take the offline action +// information and use it to talk to a server to have this action +// actually happen online, 'syncing' themselves with the server. +// +// For example, if the action was "update" with the item that was updated, we +// might call some RESTian server API that exists for updating an item in +// our application. The server could either then do sophisticated merging +// and conflict resolution on the server side, for example, allowing you +// to pop up a custom merge UI, or could do automatic merging or nothing +// of the sort. When you are finished with this particular action, your +// application is then required to call continueReplay() on the actionLog object +// passed to onReplay() to continue replaying the action log, or haltReplay() +// with the reason for halting to completely stop the syncing/replaying +// process. +// +// For example, imagine that we have a web application that allows us to add +// contacts. If we are offline, and we update a contact, we would add an action; +// imagine that the user has to click an Update button after changing the values +// for a given contact: +// +// dojox.off.whenOffline(dojo.byId("updateButton"), "onclick", function(evt){ +// // get the updated customer values +// var customer = getCustomerValues(); +// +// // we are offline -- just record this action +// var action = {name: "update", customer: customer}; +// dojox.off.sync.actions.add(action) +// +// // persist this customer data into local storage as well +// dojox.storage.put(customer.name, customer); +// }) +// +// Then, when we go back online, the dojox.off.sync.actions.onReplay event +// will fire over and over, once for each action that was recorded while offline: +// +// dojo.connect(dojox.off.sync.actions, "onReplay", function(action, actionLog){ +// // called once for each action we added while offline, in the order +// // they were added +// if(action.name == "update"){ +// var customer = action.customer; +// +// // call some network service to update this customer +// dojo.xhrPost({ +// url: "updateCustomer.php", +// content: {customer: dojo.toJson(customer)}, +// error: function(err){ +// actionLog.haltReplay(err); +// }, +// load: function(data){ +// actionLog.continueReplay(); +// } +// }) +// } +// }) +// +// Note that the actions log is always automatically persisted locally while using it, so +// that if the user closes the browser or it crashes the actions will safely be stored +// for later replaying. +dojo.declare("dojox.off.sync.ActionLog", null, { + // entries: Array + // An array of our action entries, where each one is simply a custom + // object literal that were passed to add() when this action entry + // was added. + entries: [], + + // reasonHalted: String + // If we halted, the reason why + reasonHalted: null, + + // isReplaying: boolean + // If true, we are in the middle of replaying a command log; if false, + // then we are not + isReplaying: false, + + // autoSave: boolean + // Whether we automatically save the action log after each call to + // add(); defaults to true. For applications that are rapidly adding + // many action log entries in a short period of time, it can be + // useful to set this to false and simply call save() yourself when + // you are ready to persist your command log -- otherwise performance + // could be slow as the default action is to attempt to persist the + // actions log constantly with calls to add(). + autoSave: true, + + add: function(action /* Object */){ /* void */ + // summary: + // Adds an action to our action log + // description: + // This method will add an action to our + // action log, later to be replayed when we + // go from offline to online. 'action' + // will be available when this action is + // replayed and will be passed to onReplay. + // + // Example usage: + // + // dojox.off.sync.log.add({actionName: "create", itemType: "document", + // {title: "Message", content: "Hello World"}}); + // + // The object literal is simply a custom object appropriate + // for our application -- it can be anything that preserves the state + // of a user action that will be executed when we go back online + // and replay this log. In the above example, + // "create" is the name of this action; "documents" is the + // type of item this command is operating on, such as documents, contacts, + // tasks, etc.; and the final argument is the document that was created. + + if(this.isReplaying){ + throw "Programming error: you can not call " + + "dojox.off.sync.actions.add() while " + + "we are replaying an action log"; + } + + this.entries.push(action); + + // save our updated state into persistent + // storage + if(this.autoSave){ + this._save(); + } + }, + + onReplay: function(action /* Object */, + actionLog /* dojox.off.sync.ActionLog */){ /* void */ + // summary: + // Called when we replay our log, for each of our action + // entries. + // action: Object + // A custom object literal representing an action for this + // application, such as + // {actionName: "create", item: {title: "message", content: "hello world"}} + // actionLog: dojox.off.sync.ActionLog + // A reference to the dojox.off.sync.actions log so that developers + // can easily call actionLog.continueReplay() or actionLog.haltReplay(). + // description: + // This callback should be connected to by applications so that + // they can sync themselves when we go back online: + // + // dojo.connect(dojox.off.sync.actions, "onReplay", function(action, actionLog){ + // // do something + // }) + // + // When we replay our action log, this callback is called for each + // of our action entries in the order they were added. The + // 'action' entry that was passed to add() for this action will + // also be passed in to onReplay, so that applications can use this information + // to do their syncing, such as contacting a server web-service + // to create a new item, for example. + // + // Inside the method you connected to onReplay, you should either call + // actionLog.haltReplay(reason) if an error occurred and you would like to halt + // action replaying or actionLog.continueReplay() to have the action log + // continue replaying its log and proceed to the next action; + // the reason you must call these is the action you execute inside of + // onAction will probably be asynchronous, since it will be talking on + // the network, and you should call one of these two methods based on + // the result of your network call. + }, + + length: function(){ /* Number */ + // summary: + // Returns the length of this + // action log + return this.entries.length; + }, + + haltReplay: function(reason /* String */){ /* void */ + // summary: Halts replaying this command log. + // reason: String + // The reason we halted. + // description: + // This method is called as we are replaying an action log; it + // can be called from dojox.off.sync.actions.onReplay, for + // example, for an application to indicate an error occurred + // while replaying this action, halting further processing of + // the action log. Note that any action log entries that + // were processed before have their effects retained (i.e. + // they are not rolled back), while the action entry that was + // halted stays in our list of actions to later be replayed. + if(!this.isReplaying){ + return; + } + + if(reason){ + this.reasonHalted = reason.toString(); + } + + // save the state of our action log, then + // tell anyone who is interested that we are + // done when we are finished saving + if(this.autoSave){ + var self = this; + this._save(function(){ + self.isReplaying = false; + self.onReplayFinished(); + }); + }else{ + this.isReplaying = false; + this.onReplayFinished(); + } + }, + + continueReplay: function(){ /* void */ + // summary: + // Indicates that we should continue processing out list of + // actions. + // description: + // This method is called by applications that have overridden + // dojox.off.sync.actions.onReplay() to continue replaying our + // action log after the application has finished handling the + // current action. + if(!this.isReplaying){ + return; + } + + // shift off the old action we just ran + this.entries.shift(); + + // are we done? + if(!this.entries.length){ + // save the state of our action log, then + // tell anyone who is interested that we are + // done when we are finished saving + if(this.autoSave){ + var self = this; + this._save(function(){ + self.isReplaying = false; + self.onReplayFinished(); + }); + return; + }else{ + this.isReplaying = false; + this.onReplayFinished(); + return; + } + } + + // get the next action + var nextAction = this.entries[0]; + this.onReplay(nextAction, this); + }, + + clear: function(){ /* void */ + // summary: + // Completely clears this action log of its entries + + if(this.isReplaying){ + return; + } + + this.entries = []; + + // save our updated state into persistent + // storage + if(this.autoSave){ + this._save(); + } + }, + + replay: function(){ /* void */ + // summary: + // For advanced usage; most developers can ignore this. + // Replays all of the commands that have been + // cached in this command log when we go back online; + // onCommand will be called for each command we have + + if(this.isReplaying){ + return; + } + + this.reasonHalted = null; + + if(!this.entries.length){ + this.onReplayFinished(); + return; + } + + this.isReplaying = true; + + var nextAction = this.entries[0]; + this.onReplay(nextAction, this); + }, + + // onReplayFinished: Function + // For advanced usage; most developers can ignore this. + // Called when we are finished replaying our commands; + // called if we have successfully exhausted all of our + // commands, or if an error occurred during replaying. + // The default implementation simply continues the + // synchronization process. Connect to this to register + // for the event: + // + // dojo.connect(dojox.off.sync.actions, "onReplayFinished", + // someFunc) + onReplayFinished: function(){ + }, + + toString: function(){ + var results = ""; + results += "["; + + for(var i = 0; i < this.entries.length; i++){ + results += "{"; + for(var j in this.entries[i]){ + results += j + ": \"" + this.entries[i][j] + "\""; + results += ", "; + } + results += "}, "; + } + + results += "]"; + + return results; + }, + + _save: function(callback){ + if(!callback){ + callback = function(){}; + } + + try{ + var self = this; + var resultsHandler = function(status, key, message){ + //console.debug("resultsHandler, status="+status+", key="+key+", message="+message); + if(status == dojox.storage.FAILED){ + dojox.off.onFrameworkEvent("save", + {status: dojox.storage.FAILED, + isCoreSave: true, + key: key, + value: message, + namespace: dojox.off.STORAGE_NAMESPACE}); + callback(); + }else if(status == dojox.storage.SUCCESS){ + callback(); + } + }; + + dojox.storage.put("actionlog", this.entries, resultsHandler, + dojox.off.STORAGE_NAMESPACE); + }catch(exp){ + console.debug("dojox.off.sync._save: " + exp.message||exp); + dojox.off.onFrameworkEvent("save", + {status: dojox.storage.FAILED, + isCoreSave: true, + key: "actionlog", + value: this.entries, + namespace: dojox.off.STORAGE_NAMESPACE}); + callback(); + } + }, + + _load: function(callback){ + var entries = dojox.storage.get("actionlog", dojox.off.STORAGE_NAMESPACE); + + if(!entries){ + entries = []; + } + + this.entries = entries; + + callback(); + } + } +); + +dojox.off.sync.actions = new dojox.off.sync.ActionLog(); + +} diff --git a/includes/js/dojox/off/ui.js b/includes/js/dojox/off/ui.js new file mode 100644 index 0000000..40f33c4 --- /dev/null +++ b/includes/js/dojox/off/ui.js @@ -0,0 +1,622 @@ +if(!dojo._hasResource["dojox.off.ui"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.off.ui"] = true; +dojo.provide("dojox.off.ui"); + +dojo.require("dojox.storage.Provider"); +dojo.require("dojox.storage.manager"); +dojo.require("dojox.storage.GearsStorageProvider"); + +// Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org + +// summary: +// dojox.off.ui provides a standard, +// default user-interface for a +// Dojo Offline Widget that can easily +// be dropped into applications that would +// like to work offline. +dojo.mixin(dojox.off.ui, { + // appName: String + // This application's name, such as "Foobar". Note that + // this is a string, not HTML, so embedded markup will + // not work, including entities. Only the following + // characters are allowed: numbers, letters, and spaces. + // You must set this property. + appName: "setme", + + // autoEmbed: boolean + // For advanced usage; most developers can ignore this. + // Whether to automatically auto-embed the default Dojo Offline + // widget into this page; default is true. + autoEmbed: true, + + // autoEmbedID: String + // For advanced usage; most developers can ignore this. + // The ID of the DOM element that will contain our + // Dojo Offline widget; defaults to the ID 'dot-widget'. + autoEmbedID: "dot-widget", + + // runLink: String + // For advanced usage; most developers can ignore this. + // The URL that should be navigated to to run this + // application offline; this will be placed inside of a + // link that the user can drag to their desktop and double + // click. Note that this URL must exactly match the URL + // of the main page of our resource that is offline for + // it to be retrieved from the offline cache correctly. + // For example, if you have cached your main page as + // http://foobar.com/index.html, and you set this to + // http://www.foobar.com/index.html, the run link will + // not work. By default this value is automatically set to + // the URL of this page, so it does not need to be set + // manually unless you have unusual needs. + runLink: window.location.href, + + // runLinkTitle: String + // For advanced usage; most developers can ignore this. + // The text that will be inside of the link that a user + // can drag to their desktop to run this application offline. + // By default this is automatically set to "Run " plus your + // application's name. + runLinkTitle: "Run Application", + + // learnHowPath: String + // For advanced usage; most developers can ignore this. + // The path to a web page that has information on + // how to use this web app offline; defaults to + // src/off/ui-template/learnhow.html, relative to + // your Dojo installation. Make sure to set + // dojo.to.ui.customLearnHowPath to true if you want + // a custom Learn How page. + learnHowPath: dojo.moduleUrl("dojox", "off/resources/learnhow.html"), + + // customLearnHowPath: boolean + // For advanced usage; most developers can ignore this. + // Whether the developer is using their own custom page + // for the Learn How instructional page; defaults to false. + // Use in conjunction with dojox.off.ui.learnHowPath. + customLearnHowPath: false, + + htmlTemplatePath: dojo.moduleUrl("dojox", "off/resources/offline-widget.html").uri, + cssTemplatePath: dojo.moduleUrl("dojox", "off/resources/offline-widget.css").uri, + onlineImagePath: dojo.moduleUrl("dojox", "off/resources/greenball.png").uri, + offlineImagePath: dojo.moduleUrl("dojox", "off/resources/redball.png").uri, + rollerImagePath: dojo.moduleUrl("dojox", "off/resources/roller.gif").uri, + checkmarkImagePath: dojo.moduleUrl("dojox", "off/resources/checkmark.png").uri, + learnHowJSPath: dojo.moduleUrl("dojox", "off/resources/learnhow.js").uri, + + _initialized: false, + + onLoad: function(){ + // summary: + // A function that should be connected to allow your + // application to know when Dojo Offline, the page, and + // the Offline Widget are all initialized and ready to be + // used: + // + // dojo.connect(dojox.off.ui, "onLoad", someFunc) + }, + + _initialize: function(){ + //console.debug("dojox.off.ui._initialize"); + + // make sure our app name is correct + if(this._validateAppName(this.appName) == false){ + alert("You must set dojox.off.ui.appName; it can only contain " + + "letters, numbers, and spaces; right now it " + + "is incorrectly set to '" + dojox.off.ui.appName + "'"); + dojox.off.enabled = false; + return; + } + + // set our run link text to its default + this.runLinkText = "Run " + this.appName; + + // setup our event listeners for Dojo Offline events + // to update our UI + dojo.connect(dojox.off, "onNetwork", this, "_onNetwork"); + dojo.connect(dojox.off.sync, "onSync", this, "_onSync"); + + // cache our default UI resources + dojox.off.files.cache([ + this.htmlTemplatePath, + this.cssTemplatePath, + this.onlineImagePath, + this.offlineImagePath, + this.rollerImagePath, + this.checkmarkImagePath + ]); + + // embed the offline widget UI + if(this.autoEmbed){ + this._doAutoEmbed(); + } + }, + + _doAutoEmbed: function(){ + // fetch our HTML for the offline widget + + // dispatch the request + dojo.xhrGet({ + url: this.htmlTemplatePath, + handleAs: "text", + error: function(err){ + dojox.off.enabled = false; + err = err.message||err; + alert("Error loading the Dojo Offline Widget from " + + this.htmlTemplatePath + ": " + err); + }, + load: dojo.hitch(this, this._templateLoaded) + }); + }, + + _templateLoaded: function(data){ + //console.debug("dojox.off.ui._templateLoaded"); + // inline our HTML + var container = dojo.byId(this.autoEmbedID); + if(container){ container.innerHTML = data; } + + // fill out our image paths + this._initImages(); + + // update our network indicator status ball + this._updateNetIndicator(); + + // update our 'Learn How' text + this._initLearnHow(); + + this._initialized = true; + + // check offline cache settings + if(!dojox.off.hasOfflineCache){ + this._showNeedsOfflineCache(); + return; + } + + // check to see if we need a browser restart + // to be able to use this web app offline + if(dojox.off.hasOfflineCache && dojox.off.browserRestart){ + this._needsBrowserRestart(); + return; + }else{ + var browserRestart = dojo.byId("dot-widget-browser-restart"); + if(browserRestart){ browserRestart.style.display = "none"; } + } + + // update our sync UI + this._updateSyncUI(); + + // register our event listeners for our main buttons + this._initMainEvtHandlers(); + + // if offline functionality is disabled, disable everything + this._setOfflineEnabled(dojox.off.enabled); + + // update our UI based on the state of the network + this._onNetwork(dojox.off.isOnline ? "online" : "offline"); + + // try to go online + this._testNet(); + }, + + _testNet: function(){ + dojox.off.goOnline(dojo.hitch(this, function(isOnline){ + //console.debug("testNet callback, isOnline="+isOnline); + + // display our online/offline results + this._onNetwork(isOnline ? "online" : "offline"); + + // indicate that our default UI + // and Dojo Offline are now ready to + // be used + this.onLoad(); + })); + }, + + _updateNetIndicator: function(){ + var onlineImg = dojo.byId("dot-widget-network-indicator-online"); + var offlineImg = dojo.byId("dot-widget-network-indicator-offline"); + var titleText = dojo.byId("dot-widget-title-text"); + + if(onlineImg && offlineImg){ + if(dojox.off.isOnline == true){ + onlineImg.style.display = "inline"; + offlineImg.style.display = "none"; + }else{ + onlineImg.style.display = "none"; + offlineImg.style.display = "inline"; + } + } + + if(titleText){ + if(dojox.off.isOnline){ + titleText.innerHTML = "Online"; + }else{ + titleText.innerHTML = "Offline"; + } + } + }, + + _initLearnHow: function(){ + var learnHow = dojo.byId("dot-widget-learn-how-link"); + + if(!learnHow){ return; } + + if(!this.customLearnHowPath){ + // add parameters to URL so the Learn How page + // can customize itself and display itself + // correctly based on framework settings + var dojoPath = dojo.config.baseRelativePath; + this.learnHowPath += "?appName=" + encodeURIComponent(this.appName) + + "&hasOfflineCache=" + dojox.off.hasOfflineCache + + "&runLink=" + encodeURIComponent(this.runLink) + + "&runLinkText=" + encodeURIComponent(this.runLinkText) + + "&baseRelativePath=" + encodeURIComponent(dojoPath); + + // cache our Learn How JavaScript page and + // the HTML version with full query parameters + // so it is available offline without a cache miss + dojox.off.files.cache(this.learnHowJSPath); + dojox.off.files.cache(this.learnHowPath); + } + + learnHow.setAttribute("href", this.learnHowPath); + + var appName = dojo.byId("dot-widget-learn-how-app-name"); + + if(!appName){ return; } + + appName.innerHTML = ""; + appName.appendChild(document.createTextNode(this.appName)); + }, + + _validateAppName: function(appName){ + if(!appName){ return false; } + + return (/^[a-z0-9 ]*$/i.test(appName)); + }, + + _updateSyncUI: function(){ + var roller = dojo.byId("dot-roller"); + var checkmark = dojo.byId("dot-success-checkmark"); + var syncMessages = dojo.byId("dot-sync-messages"); + var details = dojo.byId("dot-sync-details"); + var cancel = dojo.byId("dot-sync-cancel"); + + if(dojox.off.sync.isSyncing){ + this._clearSyncMessage(); + + if(roller){ roller.style.display = "inline"; } + + if(checkmark){ checkmark.style.display = "none"; } + + if(syncMessages){ + dojo.removeClass(syncMessages, "dot-sync-error"); + } + + if(details){ details.style.display = "none"; } + + if(cancel){ cancel.style.display = "inline"; } + }else{ + if(roller){ roller.style.display = "none"; } + + if(cancel){ cancel.style.display = "none"; } + + if(syncMessages){ + dojo.removeClass(syncMessages, "dot-sync-error"); + } + } + }, + + _setSyncMessage: function(message){ + var syncMessage = dojo.byId("dot-sync-messages"); + if(syncMessage){ + // when used with Google Gears pre-release in Firefox/Mac OS X, + // the browser would crash when testing in Moxie + // if we set the message this way for some reason. + // Brad Neuberg, bkn3@columbia.edu + //syncMessage.innerHTML = message; + + while(syncMessage.firstChild){ + syncMessage.removeChild(syncMessage.firstChild); + } + syncMessage.appendChild(document.createTextNode(message)); + } + }, + + _clearSyncMessage: function(){ + this._setSyncMessage(""); + }, + + _initImages: function(){ + var onlineImg = dojo.byId("dot-widget-network-indicator-online"); + if(onlineImg){ + onlineImg.setAttribute("src", this.onlineImagePath); + } + + var offlineImg = dojo.byId("dot-widget-network-indicator-offline"); + if(offlineImg){ + offlineImg.setAttribute("src", this.offlineImagePath); + } + + var roller = dojo.byId("dot-roller"); + if(roller){ + roller.setAttribute("src", this.rollerImagePath); + } + + var checkmark = dojo.byId("dot-success-checkmark"); + if(checkmark){ + checkmark.setAttribute("src", this.checkmarkImagePath); + } + }, + + _showDetails: function(evt){ + // cancel the button's default behavior + evt.preventDefault(); + evt.stopPropagation(); + + if(!dojox.off.sync.details.length){ + return; + } + + // determine our HTML message to display + var html = ""; + html += "Sync Details"; + html += "

                  Sync Details

                  \n"; + html += "
                    \n"; + for(var i = 0; i < dojox.off.sync.details.length; i++){ + html += "
                  • "; + html += dojox.off.sync.details[i]; + html += "
                  • "; + } + html += "
                  \n"; + html += "" + + "Close Window" + + "\n"; + html += ""; + + // open a popup window with this message + var windowParams = "height=400,width=600,resizable=true," + + "scrollbars=true,toolbar=no,menubar=no," + + "location=no,directories=no,dependent=yes"; + + var popup = window.open("", "SyncDetails", windowParams); + + if(!popup){ // aggressive popup blocker + alert("Please allow popup windows for this domain; can't display sync details window"); + return; + } + + popup.document.open(); + popup.document.write(html); + popup.document.close(); + + // put the focus on the popup window + if(popup.focus){ + popup.focus(); + } + }, + + _cancel: function(evt){ + // cancel the button's default behavior + evt.preventDefault(); + evt.stopPropagation(); + + dojox.off.sync.cancel(); + }, + + _needsBrowserRestart: function(){ + var browserRestart = dojo.byId("dot-widget-browser-restart"); + if(browserRestart){ + dojo.addClass(browserRestart, "dot-needs-browser-restart"); + } + + var appName = dojo.byId("dot-widget-browser-restart-app-name"); + if(appName){ + appName.innerHTML = ""; + appName.appendChild(document.createTextNode(this.appName)); + } + + var status = dojo.byId("dot-sync-status"); + if(status){ + status.style.display = "none"; + } + }, + + _showNeedsOfflineCache: function(){ + var widgetContainer = dojo.byId("dot-widget-container"); + if(widgetContainer){ + dojo.addClass(widgetContainer, "dot-needs-offline-cache"); + } + }, + + _hideNeedsOfflineCache: function(){ + var widgetContainer = dojo.byId("dot-widget-container"); + if(widgetContainer){ + dojo.removeClass(widgetContainer, "dot-needs-offline-cache"); + } + }, + + _initMainEvtHandlers: function(){ + var detailsButton = dojo.byId("dot-sync-details-button"); + if(detailsButton){ + dojo.connect(detailsButton, "onclick", this, this._showDetails); + } + var cancelButton = dojo.byId("dot-sync-cancel-button"); + if(cancelButton){ + dojo.connect(cancelButton, "onclick", this, this._cancel); + } + }, + + _setOfflineEnabled: function(enabled){ + var elems = []; + elems.push(dojo.byId("dot-sync-status")); + + for(var i = 0; i < elems.length; i++){ + if(elems[i]){ + elems[i].style.visibility = + (enabled ? "visible" : "hidden"); + } + } + }, + + _syncFinished: function(){ + this._updateSyncUI(); + + var checkmark = dojo.byId("dot-success-checkmark"); + var details = dojo.byId("dot-sync-details"); + + if(dojox.off.sync.successful == true){ + this._setSyncMessage("Sync Successful"); + if(checkmark){ checkmark.style.display = "inline"; } + }else if(dojox.off.sync.cancelled == true){ + this._setSyncMessage("Sync Cancelled"); + + if(checkmark){ checkmark.style.display = "none"; } + }else{ + this._setSyncMessage("Sync Error"); + + var messages = dojo.byId("dot-sync-messages"); + if(messages){ + dojo.addClass(messages, "dot-sync-error"); + } + + if(checkmark){ checkmark.style.display = "none"; } + } + + if(dojox.off.sync.details.length && details){ + details.style.display = "inline"; + } + }, + + _onFrameworkEvent: function(type, saveData){ + if(type == "save"){ + if(saveData.status == dojox.storage.FAILED && !saveData.isCoreSave){ + alert("Please increase the amount of local storage available " + + "to this application"); + if(dojox.storage.hasSettingsUI()){ + dojox.storage.showSettingsUI(); + } + + // FIXME: Be able to know if storage size has changed + // due to user configuration + } + }else if(type == "coreOperationFailed"){ + console.log("Application does not have permission to use Dojo Offline"); + + if(!this._userInformed){ + alert("This application will not work if Google Gears is not allowed to run"); + this._userInformed = true; + } + }else if(type == "offlineCacheInstalled"){ + // clear out the 'needs offline cache' info + this._hideNeedsOfflineCache(); + + // check to see if we need a browser restart + // to be able to use this web app offline + if(dojox.off.hasOfflineCache == true + && dojox.off.browserRestart == true){ + this._needsBrowserRestart(); + return; + }else{ + var browserRestart = dojo.byId("dot-widget-browser-restart"); + if(browserRestart){ + browserRestart.style.display = "none"; + } + } + + // update our sync UI + this._updateSyncUI(); + + // register our event listeners for our main buttons + this._initMainEvtHandlers(); + + // if offline is disabled, disable everything + this._setOfflineEnabled(dojox.off.enabled); + + // try to go online + this._testNet(); + } + }, + + _onSync: function(type){ + //console.debug("ui, onSync="+type); + switch(type){ + case "start": + this._updateSyncUI(); + break; + + case "refreshFiles": + this._setSyncMessage("Downloading UI..."); + break; + + case "upload": + this._setSyncMessage("Uploading new data..."); + break; + + case "download": + this._setSyncMessage("Downloading new data..."); + break; + + case "finished": + this._syncFinished(); + break; + + case "cancel": + this._setSyncMessage("Canceling Sync..."); + break; + + default: + dojo.warn("Programming error: " + + "Unknown sync type in dojox.off.ui: " + type); + break; + } + }, + + _onNetwork: function(type){ + // summary: + // Called when we go on- or off-line + // description: + // When we go online or offline, this method is called to update + // our UI. Default behavior is to update the Offline + // Widget UI and to attempt a synchronization. + // type: String + // "online" if we just moved online, and "offline" if we just + // moved offline. + + if(!this._initialized){ return; } + + // update UI + this._updateNetIndicator(); + + if(type == "offline"){ + this._setSyncMessage("You are working offline"); + + // clear old details + var details = dojo.byId("dot-sync-details"); + if(details){ details.style.display = "none"; } + + // if we fell offline during a sync, hide + // the sync info + this._updateSyncUI(); + }else{ // online + // synchronize, but pause for a few seconds + // so that the user can orient themselves + if(dojox.off.sync.autoSync){ + if(dojo.isAIR){ + window.setTimeout(function(){dojox.off.sync.synchronize();}, 1000); + }else{ + window.setTimeout(dojox._scopeName + ".off.sync.synchronize()", 1000); + } + } + } + } +}); + +// register ourselves for low-level framework events +dojo.connect(dojox.off, "onFrameworkEvent", dojox.off.ui, "_onFrameworkEvent"); + +// start our magic when the Dojo Offline framework is ready to go +dojo.connect(dojox.off, "onLoad", dojox.off.ui, dojox.off.ui._initialize); + +} diff --git a/includes/js/dojox/presentation.js b/includes/js/dojox/presentation.js new file mode 100644 index 0000000..a1c1a8a --- /dev/null +++ b/includes/js/dojox/presentation.js @@ -0,0 +1,6 @@ +if(!dojo._hasResource["dojox.presentation"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.presentation"] = true; +dojo.provide("dojox.presentation"); +dojo.require("dojox.presentation._base"); + +} diff --git a/includes/js/dojox/presentation/README b/includes/js/dojox/presentation/README new file mode 100644 index 0000000..4be60f5 --- /dev/null +++ b/includes/js/dojox/presentation/README @@ -0,0 +1,72 @@ +------------------------------------------------------------------------------- +dojox.presentation +------------------------------------------------------------------------------- +Version 0.9 +Release date: 10/31/2007 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + pete higgins (dante) +------------------------------------------------------------------------------- + +Project description + +This is the presentation base class. It provides a mechanism for various +display-oriented tasks. It includes a powerpoint-esque engine [prototype]. +The SlideShow aspect of this project has been deprecated and lives now +in dojox.image project. + +------------------------------------------------------------------------------- + +Dependencies: + +dojox.presentation requires both Dojo Base, Dojo FX Core, and Dijit system(s). + +------------------------------------------------------------------------------- + +Documentation + +See the Dojo API tool (http://dojotoolkit.org/api) + +------------------------------------------------------------------------------- + +Installation instructions + +This package is self-contained, but needs Dijit sytem. + +Grab the following from the Dojo SVN Repository: + +svn co http://svn.dojotoolkit.org/dojo/dojox/trunk/presentation* +svn co http://svn.dojotoolkit.org/dojo/dijit/* + +into your: +/dojo root folder [checkout/release root] + +and require in dependancies via dojo.require('dojox.presentation'); + +see /dojox/presentation/tests/test_presentation.html for example usage, but +basically the structure is this: + +presentation /> + Slide /> + Slide /> + Text Outside of Part is Static + Part /> + Part /> + Action forPart/> + Action forPart/> + Slide href="remote.html" /> + Slide /> + Part /> + Action forPart/> +/presentation> + +NOTE: project marked experimental, and API has a planned deprecation. To +participate in the formation of the new presentation class, visit +the dojotoolkit forums at: + +http://dojotoolkit.org/forums + + diff --git a/includes/js/dojox/presentation/_base.js b/includes/js/dojox/presentation/_base.js new file mode 100644 index 0000000..2077a4e --- /dev/null +++ b/includes/js/dojox/presentation/_base.js @@ -0,0 +1,557 @@ +if(!dojo._hasResource["dojox.presentation._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.presentation._base"] = true; +dojo.provide("dojox.presentation._base"); +dojo.experimental("dojox.presentation"); + +dojo.require("dijit._Widget"); +dojo.require("dijit._Container"); +dojo.require("dijit._Templated"); +dojo.require("dijit.layout.StackContainer"); +dojo.require("dijit.layout.ContentPane"); +dojo.require("dojo.fx"); + +dojo.declare("dojox.presentation.Deck", [ dijit.layout.StackContainer, dijit._Templated ], { + // summary: + // dojox.presentation class + // basic powerpoint esque engine for handling transitons and control + // in a page-by-page and part-by-part way + // + // FIXME: parsing part(s)/widget(s) in href="" Slides not working + // TODO: make auto actions progress. + // FIXME: Safari keydown/press/up listener not working. + // noClick=true prevents progression of slides in that broweser + // + // fullScreen: Boolean + // unsupported (that i know of) just yet. Default it to take control + // of window. Would be nice to be able to contain presentation in a + // styled container, like StackContainer ... theoretically possible. + // [and may not need this variable?] + fullScreen: true, + + // useNav: Boolean + // true to allow navigation popup, false to disallow + useNav: true, + + // navDuration: Integer + // time in MS fadein/out of popup nav [default: 250] + navDuration: 250, + + // noClick: Boolean + // if true, prevents _any_ click events to propagate actions + // (limiting control to keyboard and/or action.on="auto" or action.delay="" + // actions. + noClick: false, + + // setHash: Boolean + // if true, window location bar will get a #link to slide for direct + // access to a particular slide number. + setHash: true, + + // just to over-ride: + templateString: null, + templateString:"
                  \n\t
                  \n\t
                  \n\t\t\n\t\t\n\t\t\n\t
                  \n\t
                  \n\t
                  \n
                  \n", + + // nextIcon: String + // icon for navigation "next" button + nextIcon: dojo.moduleUrl('dojox.presentation','resources/icons/next.png'), + + // prevIcon: String + // icon for navigation "previous" button + prevIcon: dojo.moduleUrl('dojox.presentation','resources/icons/prev.png'), + + _navOpacMin: 0, + _navOpacMax: 0.85, + _slideIndex: 0, + + // Private: + _slides: [], + _navShowing: true, + _inNav: false, + + startup: function(){ + // summary: connect to the various handlers and controls for this presention + this.inherited(arguments); + + if(this.useNav){ + this._hideNav(); + }else{ + this.showNav.style.display = "none"; + } + + this.connect(document,'onclick', '_onEvent'); + this.connect(document,'onkeypress', '_onEvent'); + + // only if this.fullScreen == true? + this.connect(window, 'onresize', '_resizeWindow'); + this._resizeWindow(); + + this._updateSlides(); + + this._readHash(); + this._setHash(); + }, + + moveTo: function(/* Integer */ number){ + // summary: jump to slide based on param + var slideIndex = number - 1; + + if(slideIndex < 0) + slideIndex = 0; + + if(slideIndex > this._slides.length - 1) + slideIndex = this._slides.length - 1; + + this._gotoSlide(slideIndex); + }, + + onMove: function (number){ + // summary: stub function? TODOC: ? + }, + + nextSlide: function(/*Event*/ evt){ + // summary: transition to the next slide. + if (!this.selectedChildWidget.isLastChild) { + this._gotoSlide(this._slideIndex+1); + } + if (evt) { evt.stopPropagation(); } + }, + + previousSlide: function(/*Event*/ evt){ + // summary: transition to the previous slide + if (!this.selectedChildWidget.isFirstChild) { + + this._gotoSlide(this._slideIndex-1); + + } else { this.selectedChildWidget._reset(); } + if (evt) { evt.stopPropagation();} + }, + + getHash: function(id){ + // summary: get the current hash to set in localtion + return this.id+"_SlideNo_"+id; + }, + + _hideNav: function(evt){ + // summary: hides navigation + if(this._navAnim){ this._navAnim.stop(); } + this._navAnim = dojo.animateProperty({ + node:this.showNav, + duration:this.navDuration, + properties: { + opacity: { end:this._navOpacMin } + } + }).play(); + }, + + _showNav: function(evt){ + // summary: shows navigation + if(this._navAnim){ this._navAnim.stop(); } + this._navAnim = dojo.animateProperty({ + node:this.showNav, + duration:this.navDuration, + properties: { + opacity: { end:this._navOpacMax } + } + }).play(); + }, + + _handleNav: function(evt){ + // summary: does nothing? _that_ seems useful. + evt.stopPropagation(); + }, + + _updateSlides: function(){ + // summary: + // populate navigation select list with refs to slides call this + // if you add a node to your presentation dynamically. + this._slides = this.getChildren(); + if(this.useNav){ + // populate the select box with top-level slides + var i=0; + dojo.forEach(this._slides,dojo.hitch(this,function(slide){ + i++; + var tmp = this._option.cloneNode(true); + tmp.text = slide.title+" ("+i+") "; + this._option.parentNode.insertBefore(tmp,this._option); + })); + if(this._option.parentNode){ + this._option.parentNode.removeChild(this._option); + } + // dojo._destroyElement(this._option); + } + }, + + _onEvent: function(/* Event */ evt){ + // summary: + // main presentation function, determines next 'best action' for a + // specified event. + var _node = evt.target; + var _type = evt.type; + + if(_type == "click" || _type == "change"){ + if(_node.index && _node.parentNode == this.select){ + this._gotoSlide(_node.index); + }else if(_node == this.select){ + this._gotoSlide(_node.selectedIndex); + }else{ + if (this.noClick || this.selectedChildWidget.noClick || this._isUnclickable(evt)) return; + this.selectedChildWidget._nextAction(evt); + } + }else if(_type=="keydown" || _type == "keypress"){ + + // FIXME: safari doesn't report keydown/keypress? + + var key = (evt.charCode == dojo.keys.SPACE ? dojo.keys.SPACE : evt.keyCode); + switch(key){ + case dojo.keys.DELETE: + case dojo.keys.BACKSPACE: + case dojo.keys.LEFT_ARROW: + case dojo.keys.UP_ARROW: + case dojo.keys.PAGE_UP: + case 80: // key 'p' + this.previousSlide(evt); + break; + + case dojo.keys.ENTER: + case dojo.keys.SPACE: + case dojo.keys.RIGHT_ARROW: + case dojo.keys.DOWN_ARROW: + case dojo.keys.PAGE_DOWN: + case 78: // key 'n' + this.selectedChildWidget._nextAction(evt); + break; + + case dojo.keys.HOME: this._gotoSlide(0); + } + } + this._resizeWindow(); + evt.stopPropagation(); + }, + + _gotoSlide: function(/* Integer */ slideIndex){ + // summary: goes to slide + this.selectChild(this._slides[slideIndex]); + this.selectedChildWidget._reset(); + + this._slideIndex = slideIndex; + + if(this.useNav){ + this.select.selectedIndex = slideIndex; + } + + if(this.setHash){ + this._setHash(); + } + this.onMove(this._slideIndex+1); + }, + + _isUnclickable: function(/* Event */ evt){ + // summary: returns true||false base of a nodes click-ability + var nodeName = evt.target.nodeName.toLowerCase(); + // TODO: check for noClick='true' in target attrs & return true + // TODO: check for relayClick='true' in target attrs & return false + switch(nodeName){ + case 'a' : + case 'input' : + case 'textarea' : return true; break; + } + return false; + }, + + _readHash: function(){ + var th = window.location.hash; + if (th.length && this.setHash) { + var parts = (""+window.location).split(this.getHash('')); + if(parts.length>1){ + this._gotoSlide(parseInt(parts[1])-1); + } + } + }, + + _setHash: function(){ + // summary: sets url #mark to direct slide access + if(this.setHash){ + var slideNo = this._slideIndex+1; + window.location.href = "#"+this.getHash(slideNo); + } + }, + + _resizeWindow: function(/*Event*/ evt){ + // summary: resize this and children to fix this window/container + + // only if this.fullScreen? + dojo.body().style.height = "auto"; + var wh = dijit.getViewport(); + var h = Math.max( + document.documentElement.scrollHeight || dojo.body().scrollHeight, + wh.h); + var w = wh.w; + this.selectedChildWidget.domNode.style.height = h +'px'; + this.selectedChildWidget.domNode.style.width = w +'px'; + }, + + _transition: function(newWidget,oldWidget){ + // summary: over-ride stackcontainers _transition method + // but atm, i find it to be ugly with not way to call + // _showChild() without over-riding it too. hopefull + // basic toggles in superclass._transition will be available + // in dijit, and this won't be necessary. + var anims = []; + if(oldWidget){ + /* + anims.push(dojo.fadeOut({ node: oldWidget.domNode, + duration:250, + onEnd: dojo.hitch(this,function(){ + this._hideChild(oldWidget); + }) + })); + */ + this._hideChild(oldWidget); + } + if(newWidget){ + /* + anims.push(dojo.fadeIn({ + node:newWidget.domNode, start:0, end:1, + duration:300, + onEnd: dojo.hitch(this,function(){ + this._showChild(newWidget); + newWidget._reset(); + }) + }) + ); + */ + this._showChild(newWidget); + newWidget._reset(); + } + //dojo.fx.combine(anims).play(); + } +}); + +dojo.declare( + "dojox.presentation.Slide", + [dijit.layout.ContentPane,dijit._Contained,dijit._Container,dijit._Templated], + { + // summary: + // a Comonent of a dojox.presentation, and container for each 'Slide' + // made up of direct HTML (no part/action relationship), and dojox.presentation.Part(s), + // and their attached Actions. + + // templatPath: String + // make a ContentPane templated, and style the 'titleNode' + templateString:"
                  \n\t

                  ${title}

                  \n\t
                  \n
                  \n", + + // title: String + // string to insert into titleNode, title of Slide + title: "", + + // inherited from ContentPane FIXME: don't seem to work ATM? + refreshOnShow: true, + preLoad: false, + doLayout: true, + parseContent: true, + + // noClick: Boolean + // true on slide tag prevents clicking, false allows + // (can also be set on base presentation for global control) + noClick: false, + + // private holders: + _parts: [], + _actions: [], + _actionIndex: 0, + _runningDelay: false, + + startup: function(){ + // summary: setup this slide with actions and components (Parts) + this.inherited(arguments); + this.slideTitleText.innerHTML = this.title; + var children = this.getChildren(); + this._actions = []; + dojo.forEach(children,function(child){ + var tmpClass = child.declaredClass.toLowerCase(); + switch(tmpClass){ + case "dojox.presentation.part" : this._parts.push(child); break; + case "dojox.presentation.action" : this._actions.push(child); break; + } + },this); + }, + + + _nextAction: function(evt){ + // summary: gotoAndPlay current cached action + var tmpAction = this._actions[this._actionIndex] || 0; + if (tmpAction){ + // is this action a delayed action? [auto? thoughts?] + if(tmpAction.on == "delay"){ + this._runningDelay = setTimeout( + dojo.hitch(tmpAction,"_runAction"),tmpAction.delay + ); + console.debug('started delay action',this._runningDelay); + }else{ + tmpAction._runAction(); + } + + // FIXME: it gets hairy here. maybe runAction should + // call _actionIndex++ onEnd? if a delayed action is running, do + // we want to prevent action++? + var tmpNext = this._getNextAction(); + this._actionIndex++; + + if(tmpNext.on == "delay"){ + // FIXME: yeah it looks like _runAction() onend should report + // _actionIndex++ + console.debug('started delay action',this._runningDelay); + setTimeout(dojo.hitch(tmpNext,"_runAction"),tmpNext.delay); + } + }else{ + // no more actions in this slide + this.getParent().nextSlide(evt); + } + }, + + _getNextAction: function(){ + // summary: returns the _next action in this sequence + return this._actions[this._actionIndex+1] || 0; + }, + + _reset: function(){ + // summary: set action chain back to 0 and re-init each Part + this._actionIndex = [0]; + dojo.forEach(this._parts,function(part){ + part._reset(); + },this); + } +}); + +dojo.declare("dojox.presentation.Part", [dijit._Widget,dijit._Contained], { + // summary: + // a node in a presentation.Slide that inherits control from a + // dojox.presentation.Action + // can be any element type, and requires styling before parsing + // + // as: String + // like an ID, attach to Action via (part) as="" / (action) forSlide="" tags + // this should be unique identifier? + as: "", + + // startVisible: boolean + // true to leave in page on slide startup/reset + // false to hide on slide startup/reset + startVisible: false, + + // isShowing: Boolean, + // private holder for _current_ state of Part + _isShowing: false, + + postCreate: function(){ + // summary: override and init() this component + this._reset(); + }, + + _reset: function(){ + // summary: set part back to initial calculate state + // these _seem_ backwards, but quickToggle flips it + this._isShowing =! this.startVisible; + this._quickToggle(); + }, + + _quickToggle: function(){ + // summary: ugly [unworking] fix to test setting state of component + // before/after an animation. display:none prevents fadeIns? + if(this._isShowing){ + dojo.style(this.domNode,'display','none'); + dojo.style(this.domNode,'visibility','hidden'); + dojo.style(this.domNode,'opacity',0); + }else{ + dojo.style(this.domNode,'display',''); + dojo.style(this.domNode,'visibility','visible'); + dojo.style(this.domNode,'opacity',1); + } + this._isShowing =! this._isShowing; + } +}); + +dojo.declare("dojox.presentation.Action", [dijit._Widget,dijit._Contained], { + // summary: + // a widget to attach to a dojox.presentation.Part to control + // it's properties based on an inherited chain of events ... + // + // + // on: String + // FIXME: only 'click' supported ATM. plans include on="delay", + // on="end" of="", and on="auto". those should make semantic sense + // to you. + on: 'click', + + // forSlide: String + // attach this action to a dojox.presentation.Part with a matching 'as' attribute + forSlide: "", + + // toggle: String + // will toggle attached [matching] node(s) via forSlide/as relationship(s) + toggle: 'fade', + + // delay: Integer + // + delay: 0, + + // duration: Integer + // default time in MS to run this action effect on it's 'forSlide' node + duration: 1000, + + // private holders: + _attached: [], + _nullAnim: false, + + _runAction: function(){ + // summary: runs this action on attached node(s) + + var anims = []; + // executes the action for each attached 'Part' + dojo.forEach(this._attached,function(node){ + // FIXME: this is ugly, and where is toggle class? :( + var dir = (node._isShowing) ? "Out" : "In"; + // node._isShowing =! node._isShowing; + //var _anim = dojox.fx[ this.toggle ? this.toggle+dir : "fade"+dir]({ + var _anim = dojo.fadeIn({ + node:node.domNode, + duration: this.duration, + beforeBegin: dojo.hitch(node,"_quickToggle") + }); + anims.push(_anim); + },this); + var _anim = dojo.fx.combine(anims); + if(_anim){ _anim.play(); } + }, + + _getSiblingsByType: function(/* String */ declaredClass){ + // summary: quick replacement for getChildrenByType("class"), but in + // a child here ... so it's getSiblings. courtesy bill in #dojo + // could be moved into parent, and just call this.getChildren(), + // which makes more sense. + var siblings = dojo.filter( this.getParent().getChildren(), function(widget){ + return widget.declaredClass==declaredClass; + } + ); + return siblings; // dijit._Widget + }, + + postCreate: function(){ + // summary: run this once, should this be startup: function()? + + this.inherited(arguments); + // prevent actions from being visible, _always_ + dojo.style(this.domNode,"display","none"); + var parents = this._getSiblingsByType('dojox.presentation.Part'); + // create a list of "parts" we are attached to via forSlide/as + this._attached = []; + dojo.forEach(parents,function(parentPart){ + if(this.forSlide == parentPart.as){ + this._attached.push(parentPart); + } + },this); + } + +}); + +} diff --git a/includes/js/dojox/presentation/resources/Show.css b/includes/js/dojox/presentation/resources/Show.css new file mode 100644 index 0000000..8610675 --- /dev/null +++ b/includes/js/dojox/presentation/resources/Show.css @@ -0,0 +1,100 @@ +@media screen { + html, body { + margin: 0px; + padding: 0px; + } + + h1.showTitle { + margin:0; + margin-left:0; + padding:0; + font-size: 60px; + background:transparent; + border-bottom:1px solid #000; + } + p, li { + font-size: 17pt; + } + .dojoShowNav { + border-top:1px solid #ccc; + background: #ededed; + overflow: hidden; + position: absolute; + bottom: 0px; + left: 0px; + width: 100%; + text-align: center; + z-index:420; + padding:0; + margin-bttom:5px; height:34px; + } + .dojoShowNav img { cursor:pointer; } + + .dojoShowSlide { + + } + .dojoShowNav option { font:6pt; color:#333; } + .dojoShowNav select { + margin: 0px; + color: #999; + margin-top: 5px; + padding: 2px; + border: 1px solid #ccc; + -moz-border-radius:6pt 6pt; + } + .dojoShowHider { + height: 5px; + overflow: hidden; + width: 100%; + z-index:421; + } + .dojoShowPrint { + position: absolute; + left: 0px; + top: 0px; + width:100%; + } + .dojoShowBody { + background:#fff url('../../../dijit/themes/tundra/images/testBodyBg.gif') repeat-x top left; + padding:10px; + } + .dojoShow { + width:100%; height:100%; + overflow:hidden; + } +} +@media print { + .dojoShow { + display: none !important; + } + .dojoShowPrint { + display: block !important; + } + .dojoShowPrintSlide { + border: 1px solid #aaa; + padding: 10px; + margin-bottom: 15px; + } + .dojoShowPrintSlide, ul { + page-break-inside: avoid; + } + h1 { + margin-top: 0; + page-break-after: avoid; + } +} +.dojoShowSlideTitle { + height: 100px; + width:100%; + display:block; + background-color: #ededed; + border-bottom:1px solid #666; +} +.dojoShowSlideTitle h1 { + margin-top: 0; + +} +.dojoShowSlideBody { + margin: 15px; + background:#fff url('../../../dijit/themes/tundra/images/testBodyBg.gif') repeat-x top left; +} diff --git a/includes/js/dojox/presentation/resources/Show.css.commented.css b/includes/js/dojox/presentation/resources/Show.css.commented.css new file mode 100644 index 0000000..ee205e4 --- /dev/null +++ b/includes/js/dojox/presentation/resources/Show.css.commented.css @@ -0,0 +1,110 @@ +@media screen { + html, body { + margin: 0px; + padding: 0px; + } + + h1.showTitle { + margin:0; + margin-left:0; + padding:0; + font-size: 60px; + background:transparent; + border-bottom:1px solid #000; + } + + p, li { + font-size: 17pt; + } + + .dojoShowNav { + border-top:1px solid #ccc; + background: #ededed; + overflow: hidden; + position: absolute; + bottom: 0px; + left: 0px; + width: 100%; + text-align: center; + z-index:420; + padding:0; + margin-bttom:5px; height:34px; + } + + .dojoShowNav img { cursor:pointer; } + + .dojoShowSlide { + /* width:100%; height:100%; */ + } + + .dojoShowNav option { font:6pt; color:#333; } + .dojoShowNav select { + margin: 0px; + color: #999; + margin-top: 5px; + padding: 2px; + border: 1px solid #ccc; + -moz-border-radius:6pt 6pt; + } + + .dojoShowHider { + height: 5px; + overflow: hidden; + width: 100%; + z-index:421; + } + .dojoShowPrint { + position: absolute; + left: 0px; + top: 0px; + width:100%; + } + + .dojoShowBody { + background:#fff url('../../../dijit/themes/tundra/images/testBodyBg.gif') repeat-x top left; + padding:10px; + } + + .dojoShow { + width:100%; height:100%; + overflow:hidden; + } +} + +@media print { + .dojoShow { + display: none !important; + } + .dojoShowPrint { + display: block !important; + } + .dojoShowPrintSlide { + border: 1px solid #aaa; + padding: 10px; + margin-bottom: 15px; + } + .dojoShowPrintSlide, ul { + page-break-inside: avoid; + } + h1 { + margin-top: 0; + page-break-after: avoid; + } +} + +.dojoShowSlideTitle { + height: 100px; + width:100%; + display:block; + background-color: #ededed; + border-bottom:1px solid #666; +} +.dojoShowSlideTitle h1 { + margin-top: 0; + /* line-height: 100px; + margin-left: 30px; */ +} +.dojoShowSlideBody { + margin: 15px; + background:#fff url('../../../dijit/themes/tundra/images/testBodyBg.gif') repeat-x top left; +} diff --git a/includes/js/dojox/presentation/resources/Show.html b/includes/js/dojox/presentation/resources/Show.html new file mode 100644 index 0000000..33672db --- /dev/null +++ b/includes/js/dojox/presentation/resources/Show.html @@ -0,0 +1,12 @@ +
                  +
                  +
                  + + + +
                  +
                  +
                  +
                  diff --git a/includes/js/dojox/presentation/resources/Slide.html b/includes/js/dojox/presentation/resources/Slide.html new file mode 100644 index 0000000..dc4627b --- /dev/null +++ b/includes/js/dojox/presentation/resources/Slide.html @@ -0,0 +1,4 @@ +
                  +

                  ${title}

                  +
                  +
                  diff --git a/includes/js/dojox/presentation/resources/icons/down.png b/includes/js/dojox/presentation/resources/icons/down.png new file mode 100644 index 0000000..46bf9ba Binary files /dev/null and b/includes/js/dojox/presentation/resources/icons/down.png differ diff --git a/includes/js/dojox/presentation/resources/icons/next.png b/includes/js/dojox/presentation/resources/icons/next.png new file mode 100644 index 0000000..16afa87 Binary files /dev/null and b/includes/js/dojox/presentation/resources/icons/next.png differ diff --git a/includes/js/dojox/presentation/resources/icons/prev.png b/includes/js/dojox/presentation/resources/icons/prev.png new file mode 100644 index 0000000..5519eb5 Binary files /dev/null and b/includes/js/dojox/presentation/resources/icons/prev.png differ diff --git a/includes/js/dojox/presentation/resources/icons/up.png b/includes/js/dojox/presentation/resources/icons/up.png new file mode 100644 index 0000000..d77816a Binary files /dev/null and b/includes/js/dojox/presentation/resources/icons/up.png differ diff --git a/includes/js/dojox/presentation/tests/_ext1.html b/includes/js/dojox/presentation/tests/_ext1.html new file mode 100644 index 0000000..d56be0e --- /dev/null +++ b/includes/js/dojox/presentation/tests/_ext1.html @@ -0,0 +1,21 @@ +

                  WARNING:

                  + +

                  +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
                  +semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin
                  +porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.
                  +Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis.
                  +Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitae
                  +risus. +

                  + +

                  +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean +semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin +porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.
                  +Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis.
                  +Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitae +risus. +

                  + + diff --git a/includes/js/dojox/presentation/tests/test_presentation.html b/includes/js/dojox/presentation/tests/test_presentation.html new file mode 100644 index 0000000..d9e86b5 --- /dev/null +++ b/includes/js/dojox/presentation/tests/test_presentation.html @@ -0,0 +1,162 @@ + + + + dojox.presentation - Presentation Mechanism + + + + + + + + + + + + + + +
                  +
                  + +

                  This is a brief overview of what this presentation widget is capable of.

                  + +
                  ... it's new, and completely different, so watch close
                  + + + + +
                  + +
                  +

                  Click, and more text will appear

                  + +
                  +

                  Lorem something something. I am text, hear me _roar_.

                  +
                  + + +
                  + I am here to make sure click-advancing is disabled on normal input type elements: + + +
                  + + + +
                  +
                  + +

                  First You See me ...

                  +

                  Then you see ME ...

                  +

                  oh yeah!

                  + + + + + + +
                  + +
                  +

                  You cannot click on this page

                  +

                  I told you that you can't click ...

                  + click here to move the title + + + +
                  + +
                  +

                  There is a widget in this page:

                  +

                  clicking has been stopped on this page to demonstrate the usage ..

                  +
                  + There _should_ be a _Calendar widget here
                  +
                  +
                  +
                  + I am a titlepane, you can do cool things with me. + +
                  +
                  +

                  ... so I'm providing a next button:

                  +
                  + +
                  + +
                  +

                  Thanks for watching!

                  +
                  +
                  + + diff --git a/includes/js/dojox/resources/README.template b/includes/js/dojox/resources/README.template new file mode 100644 index 0000000..293f2b7 --- /dev/null +++ b/includes/js/dojox/resources/README.template @@ -0,0 +1,36 @@ +------------------------------------------------------------------------------- +Project Name +------------------------------------------------------------------------------- +Version X.XXX +Release date: MM/DD/YYYY +------------------------------------------------------------------------------- +Project state: +prototype | experimental | beta | stable | production +------------------------------------------------------------------------------- +Credits + Author one (author contact info) + Author two (author contact info) +------------------------------------------------------------------------------- +Project description + +Describe the point of the project here. +------------------------------------------------------------------------------- +Dependencies: + +List any dependencies here. +------------------------------------------------------------------------------- +Documentation + +------------------------------------------------------------------------------- +Installation instructions + +Use this to explain in detail what a person needs to do in order to use this +project. Include URLs for grabbing source, URLs for any dependencies, etc. +Also be sure to include any additional information, such as where to place +CSS files, images, other media, etc. The goal is that someone reading this +file can follow your instructions and be using this project within minutes. +------------------------------------------------------------------------------- +Additional Notes + +Anything else you think is of interest (for example, object hierarchy) should +be placed here. diff --git a/includes/js/dojox/resources/_modules.js b/includes/js/dojox/resources/_modules.js new file mode 100644 index 0000000..d894a91 --- /dev/null +++ b/includes/js/dojox/resources/_modules.js @@ -0,0 +1,204 @@ +/*===== +// this file is in place as a quick way to give summaries to all available dojox projects. + +dojox = { + // summary: + // DojoX: the home for Dojo eXtensions + // + // description: + // DojoX is a collection of subprojects provided by Dojo committers and subject to + // the generous licensing and policies of the [Dojo CLA](http://dojotoolkit.org/cla) + // Each subproject in DojoX has its own top-level directory and a README file with + // status information and project status and a stability rating (experimental, beta, stable) + // + // Projects may or may not depend on other top-level Dojo projects, like Dojo or Dijit. + // Unlike Dojo and Dijit, code is not subject to i18n and a11y restrictions and may vary + // in quality (experimental code is encouraged in DojoX, but currently prohibited in Dojo + // and Dijit) + // + // DojoX projects may mature to a stable state and stay in DojoX, or on occasion + // after proving themselves may migrate to Dojo Core or Dijit. Dojo and Dijit projects + // are constrained both by development resources as well as design goals, so DojoX is + // a natural place to provide enhanced behavior or extend Dojo Core or Dijit primitives. + // DojoX can also be an incubator for entirely new projects. +} + +dojox._sql = { + // summary: objects to support Dojo Offline (dojox.off) +}; + +dojox.charting = { + // summary: Vector graphic, data-driven graphs and charts +}; + +dojox.collections = { + // summary: A set of lists and hashes for easy use within your applications. +}; + +dojox.color = { + // summary: Advanced color methods, including HSV, HSL, and CMYK conversion, a color generator and advanced colorspace calculations. +}; + +dojox.cometd = { + // summary: A cometd client written in Dojo +}; + +dojox.crypto = { + // summary: Cryptography in JS. DEPRECATED: use dojox.encoding instead. +}; + +dojox.data = { + // summary: Additional dojo.data data stores and demos +}; + +dojox.date = { + // summary: Additional date manipulation functions +}; + +dojox.dtl = { + // summary: Django Templating Language implementation +}; + +dojox.encoding = { + // summary: Various encoding algorithms, including crypto and digests. +}; + +dojox.flash = { + // summary: Utilities to embed and communicate with Flash-based objects +}; + +dojox.fx = { + // summary: Extension animations to the core dojo FX project + // + // description: + // A package of animations, and FX-related code, extending Dojo Core fx. + // Including this package includes all the Base and Core fx packages. + // + + style: { // summary: Module to provide CSS animations + }, + + scroll: { // summary: Module to provide scroll-related FX + } +}; +dojox.fx["ext-dojo"] = { + // summary: Direct extensions to dojo.fx namespace + NodeList: { + // summary: module to include to support dojox.fx animations in dojo.query() + } +}; + +dojox.gfx = { + // summary: Cross-browser vector graphics API + // description: + // + // dojox.gfx is an advanced API providing normalized vector drawing + // in a variety of browsers. It has individual renderers for SVG, VML, + // Canvas, and Silverlight. +}; + +dojox.gfx3d = { + // summary: A 3d API for dojox.gfx +}; + +dojox.grid = { + // summary: An advanced Grid widget with virtual scrolling, cell editing, and much more +}; + +dojox.highlight = { + // summary: A client-side syntax highlighting engine. + // description: + // This project parses pre > code nodes, and applies syntax highlighting for + // a wide variety of languages. Simply dojo.require() in all the + // dojox.highlight.languages you wish to include in your highlighingting, + // and customize colors in the highlight.css. + // + // It is provided as a dojo package, contributed under CLA + // by Ivan Sagalaev and is available originally from: + // http://softwaremaniacs.org/soft/highlight/en/ + // +}; + +dojox.image = { + // summary: A collection of image related widgets +}; + +dojox.io = { + // summary: Extensions to the Core dojo.io transports +}; + +dojox.jsonPath = { + // summary: A query system for JavaScript objects +}; + +dojox.layout = { + // summary: A collection of layout related Widgets +}; + +dojox.lang = { + // summary: Language specific extensions + functional: { + // summary: Functional language constructs, including currying and lambda. + } +}; + +dojox.math = { + // summary: A collection of various advanced math functions. +}; + +dojox.off = { + // summary: the Dojo Offline project +}; + +dojox.presentation = { + // summary: A simple, experimental PowerPoint-like presentation project +}; + +dojox.regexp = { + // summary: Additional pre-made regular expressions for use +}; + +dojox.storage = { + // summary: Objects for mass storage within the browser. For when cookies just aren't enough. +}; + +dojox.string = { + // summary: A collection of various objects for advanced string manipulation, including a Builder and a tokenizer. +}; + +dojox.timing = { + // summary: A set of objects to perform advanced time-based tasks, including a basic Timer. +}; + +dojox.uuid = { + // summary: Universally Unique Identifier (UUID) implementations, including an implementation of UUID 2 +}; + +dojox.validate = { + // summary: Additional input validation methods + ca : { + // summary: Methods specific to the Canadian provinces + }, + creditCard : { + // summary: Validate various credit card types + } +}; + +dojox.widget = { + // summary: A collection of un-categorized widgets, or code not requiring it's own package. + // + // description: + // These are standalone widgets with varying levels of stability. Some are useful, + // some were created for demonstration purposes, and learning tools. The each maintain + // their own .css file (typically dojox/widget/WidgetName/WidgetName.css) +}; + +dojox.wire = { + // summary: + // Declarative data binding and action tags for simplified MVC +}; + +dojox.xml = { + // summary: XML utilities. Currently only includes a DomParser, which returns a psuedo-XML document in JSON-like form. +}; +=====*/ diff --git a/includes/js/dojox/resources/manualTests.html b/includes/js/dojox/resources/manualTests.html new file mode 100644 index 0000000..1cdda13 --- /dev/null +++ b/includes/js/dojox/resources/manualTests.html @@ -0,0 +1,12 @@ + + + + Dojox Manual Test Runner + + + Redirecting to D.O.H runner + + + diff --git a/includes/js/dojox/resources/manualTests.js b/includes/js/dojox/resources/manualTests.js new file mode 100644 index 0000000..3a6d947 --- /dev/null +++ b/includes/js/dojox/resources/manualTests.js @@ -0,0 +1,211 @@ +if(!dojo._hasResource["dojox.tests.manualTests"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.tests.manualTests"] = true; +dojo.provide("dojox.tests.manualTests"); + +try{ +if(dojo.isBrowser){ + var userArgs = window.location.search.replace(/[\?&](dojoUrl|testUrl|testModule)=[^&]*/g,"").replace(/^&/,"?"); + doh.registerUrl("dojox/analytics/tests/test_analytics.html", dojo.moduleUrl("dojox","analytics/tests/test_analytics.html"+userArgs), 99999999); + doh.registerUrl("dojox/av/tests/flash.html", dojo.moduleUrl("dojox","av/tests/flash.html"+userArgs), 99999999); + doh.registerUrl("dojox/av/tests/quicktime.html", dojo.moduleUrl("dojox","av/tests/quicktime.html"+userArgs), 99999999); + doh.registerUrl("dojox/charting/tests/test_bars.html", dojo.moduleUrl("dojox","charting/tests/test_bars.html"+userArgs), 99999999); + doh.registerUrl("dojox/charting/tests/test_chart2d.html", dojo.moduleUrl("dojox","charting/tests/test_chart2d.html"+userArgs), 99999999); + doh.registerUrl("dojox/charting/tests/test_chart2d_updating.html", dojo.moduleUrl("dojox","charting/tests/test_chart2d_updating.html"+userArgs), 99999999); + doh.registerUrl("dojox/charting/tests/test_cylinders.html", dojo.moduleUrl("dojox","charting/tests/test_cylinders.html"+userArgs), 99999999); + doh.registerUrl("dojox/charting/tests/test_labels2d.html", dojo.moduleUrl("dojox","charting/tests/test_labels2d.html"+userArgs), 99999999); + doh.registerUrl("dojox/charting/tests/test_pie2d.html", dojo.moduleUrl("dojox","charting/tests/test_pie2d.html"+userArgs), 99999999); + doh.registerUrl("dojox/charting/tests/test_scaler.html", dojo.moduleUrl("dojox","charting/tests/test_scaler.html"+userArgs), 99999999); + doh.registerUrl("dojox/charting/tests/test_sparklines.html", dojo.moduleUrl("dojox","charting/tests/test_sparklines.html"+userArgs), 99999999); + doh.registerUrl("dojox/charting/tests/test_widget2d.html", dojo.moduleUrl("dojox","charting/tests/test_widget2d.html"+userArgs), 99999999); + doh.registerUrl("dojox/data/demos/demo_DataDemoTable.html", dojo.moduleUrl("dojox","data/demos/demo_DataDemoTable.html"+userArgs), 99999999); + doh.registerUrl("dojox/data/demos/demo_FlickrRestStore.html", dojo.moduleUrl("dojox","data/demos/demo_FlickrRestStore.html"+userArgs), 99999999); + doh.registerUrl("dojox/data/demos/demo_FlickrStore.html", dojo.moduleUrl("dojox","data/demos/demo_FlickrStore.html"+userArgs), 99999999); + doh.registerUrl("dojox/data/demos/demo_LazyLoad.html", dojo.moduleUrl("dojox","data/demos/demo_LazyLoad.html"+userArgs), 99999999); + doh.registerUrl("dojox/data/demos/demo_MultiStores.html", dojo.moduleUrl("dojox","data/demos/demo_MultiStores.html"+userArgs), 99999999); + doh.registerUrl("dojox/data/demos/demo_PicasaStore.html", dojo.moduleUrl("dojox","data/demos/demo_PicasaStore.html"+userArgs), 99999999); + doh.registerUrl("dojox/data/demos/demo_QueryReadStore.html", dojo.moduleUrl("dojox","data/demos/demo_QueryReadStore.html"+userArgs), 99999999); + doh.registerUrl("dojox/data/demos/demo_QueryReadStore_filter.html", dojo.moduleUrl("dojox","data/demos/demo_QueryReadStore_filter.html"+userArgs), 99999999); + doh.registerUrl("dojox/data/demos/demo_QueryReadStore_sort.html", dojo.moduleUrl("dojox","data/demos/demo_QueryReadStore_sort.html"+userArgs), 99999999); + doh.registerUrl("dojox/data/tests/QueryReadStore.html", dojo.moduleUrl("dojox","data/tests/QueryReadStore.html"+userArgs), 99999999); + doh.registerUrl("dojox/data/tests/test_Tree_vs_jsonPathStore.html", dojo.moduleUrl("dojox","data/tests/test_Tree_vs_jsonPathStore.html"+userArgs), 99999999); + doh.registerUrl("dojox/dtl/demos/demo_Animation.html", dojo.moduleUrl("dojox","dtl/demos/demo_Animation.html"+userArgs), 99999999); + doh.registerUrl("dojox/dtl/demos/demo_Blog.html", dojo.moduleUrl("dojox","dtl/demos/demo_Blog.html"+userArgs), 99999999); + doh.registerUrl("dojox/dtl/demos/demo_Data.html", dojo.moduleUrl("dojox","dtl/demos/demo_Data.html"+userArgs), 99999999); + doh.registerUrl("dojox/dtl/demos/demo_Dijitless.html", dojo.moduleUrl("dojox","dtl/demos/demo_Dijitless.html"+userArgs), 99999999); + doh.registerUrl("dojox/dtl/demos/demo_Events.html", dojo.moduleUrl("dojox","dtl/demos/demo_Events.html"+userArgs), 99999999); + doh.registerUrl("dojox/dtl/demos/demo_HtmlTemplated.html", dojo.moduleUrl("dojox","dtl/demos/demo_HtmlTemplated.html"+userArgs), 99999999); + doh.registerUrl("dojox/dtl/demos/demo_Inline.html", dojo.moduleUrl("dojox","dtl/demos/demo_Inline.html"+userArgs), 99999999); + doh.registerUrl("dojox/dtl/demos/demo_NodeList.html", dojo.moduleUrl("dojox","dtl/demos/demo_NodeList.html"+userArgs), 99999999); + doh.registerUrl("dojox/dtl/demos/demo_Table.html", dojo.moduleUrl("dojox","dtl/demos/demo_Table.html"+userArgs), 99999999); + doh.registerUrl("dojox/dtl/demos/demo_Templated.html", dojo.moduleUrl("dojox","dtl/demos/demo_Templated.html"+userArgs), 99999999); + doh.registerUrl("dojox/dtl/demos/demo_Tree.html", dojo.moduleUrl("dojox","dtl/demos/demo_Tree.html"+userArgs), 99999999); + doh.registerUrl("dojox/dtl/tests/demo_Templated_Jaxer.html", dojo.moduleUrl("dojox","dtl/tests/demo_Templated_Jaxer.html"+userArgs), 99999999); + doh.registerUrl("dojox/encoding/tests/compression/colors2.html", dojo.moduleUrl("dojox","encoding/tests/compression/colors2.html"+userArgs), 99999999); + doh.registerUrl("dojox/encoding/tests/compression/colors3.html", dojo.moduleUrl("dojox","encoding/tests/compression/colors3.html"+userArgs), 99999999); + doh.registerUrl("dojox/encoding/tests/compression/test.html", dojo.moduleUrl("dojox","encoding/tests/compression/test.html"+userArgs), 99999999); + doh.registerUrl("dojox/encoding/tests/compression/vq.html", dojo.moduleUrl("dojox","encoding/tests/compression/vq.html"+userArgs), 99999999); + doh.registerUrl("dojox/flash/tests/test_flash.html", dojo.moduleUrl("dojox","flash/tests/test_flash.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/example_backgroundPosition.html", dojo.moduleUrl("dojox","fx/tests/example_backgroundPosition.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/example_dojoAnimations.html", dojo.moduleUrl("dojox","fx/tests/example_dojoAnimations.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/example_easingChart2D.html", dojo.moduleUrl("dojox","fx/tests/example_easingChart2D.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/example_Line.html", dojo.moduleUrl("dojox","fx/tests/example_Line.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/test_animateClass.html", dojo.moduleUrl("dojox","fx/tests/test_animateClass.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/test_crossFade.html", dojo.moduleUrl("dojox","fx/tests/test_crossFade.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/test_easing.html", dojo.moduleUrl("dojox","fx/tests/test_easing.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/test_highlight.html", dojo.moduleUrl("dojox","fx/tests/test_highlight.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/test_Nodelist-fx.html", dojo.moduleUrl("dojox","fx/tests/test_Nodelist-fx.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/test_scroll.html", dojo.moduleUrl("dojox","fx/tests/test_scroll.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/test_Shadow.html", dojo.moduleUrl("dojox","fx/tests/test_Shadow.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/test_sizeTo.html", dojo.moduleUrl("dojox","fx/tests/test_sizeTo.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/test_slideBy.html", dojo.moduleUrl("dojox","fx/tests/test_slideBy.html"+userArgs), 99999999); + doh.registerUrl("dojox/fx/tests/test_wipeTo.html", dojo.moduleUrl("dojox","fx/tests/test_wipeTo.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/beautify.html", dojo.moduleUrl("dojox","gfx/demos/beautify.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/butterfly.html", dojo.moduleUrl("dojox","gfx/demos/butterfly.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/career_test.html", dojo.moduleUrl("dojox","gfx/demos/career_test.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/circles.html", dojo.moduleUrl("dojox","gfx/demos/circles.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/clock.html", dojo.moduleUrl("dojox","gfx/demos/clock.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/clockWidget.html", dojo.moduleUrl("dojox","gfx/demos/clockWidget.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/clock_black.html", dojo.moduleUrl("dojox","gfx/demos/clock_black.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/creator.html", dojo.moduleUrl("dojox","gfx/demos/creator.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/inspector.html", dojo.moduleUrl("dojox","gfx/demos/inspector.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/lion.html", dojo.moduleUrl("dojox","gfx/demos/lion.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/roundedPane.html", dojo.moduleUrl("dojox","gfx/demos/roundedPane.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/tiger.html", dojo.moduleUrl("dojox","gfx/demos/tiger.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/demos/tooltip.html", dojo.moduleUrl("dojox","gfx/demos/tooltip.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_arc.html", dojo.moduleUrl("dojox","gfx/tests/test_arc.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_bezier.html", dojo.moduleUrl("dojox","gfx/tests/test_bezier.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_decompose.html", dojo.moduleUrl("dojox","gfx/tests/test_decompose.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_fill.html", dojo.moduleUrl("dojox","gfx/tests/test_fill.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_fx.html", dojo.moduleUrl("dojox","gfx/tests/test_fx.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_gfx.html", dojo.moduleUrl("dojox","gfx/tests/test_gfx.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_gradient.html", dojo.moduleUrl("dojox","gfx/tests/test_gradient.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_group.html", dojo.moduleUrl("dojox","gfx/tests/test_group.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_image1.html", dojo.moduleUrl("dojox","gfx/tests/test_image1.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_image2.html", dojo.moduleUrl("dojox","gfx/tests/test_image2.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_linearGradient.html", dojo.moduleUrl("dojox","gfx/tests/test_linearGradient.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_linestyle.html", dojo.moduleUrl("dojox","gfx/tests/test_linestyle.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_pattern.html", dojo.moduleUrl("dojox","gfx/tests/test_pattern.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_poly.html", dojo.moduleUrl("dojox","gfx/tests/test_poly.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_resize.html", dojo.moduleUrl("dojox","gfx/tests/test_resize.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_setPath.html", dojo.moduleUrl("dojox","gfx/tests/test_setPath.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_tbbox.html", dojo.moduleUrl("dojox","gfx/tests/test_tbbox.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_text.html", dojo.moduleUrl("dojox","gfx/tests/test_text.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_textpath.html", dojo.moduleUrl("dojox","gfx/tests/test_textpath.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx/tests/test_transform.html", dojo.moduleUrl("dojox","gfx/tests/test_transform.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_camerarotate.html", dojo.moduleUrl("dojox","gfx3d/tests/test_camerarotate.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_camerarotate_shaded.html", dojo.moduleUrl("dojox","gfx3d/tests/test_camerarotate_shaded.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_cube.html", dojo.moduleUrl("dojox","gfx3d/tests/test_cube.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_cylinder.html", dojo.moduleUrl("dojox","gfx3d/tests/test_cylinder.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_drawer.html", dojo.moduleUrl("dojox","gfx3d/tests/test_drawer.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_edges.html", dojo.moduleUrl("dojox","gfx3d/tests/test_edges.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_matrix.html", dojo.moduleUrl("dojox","gfx3d/tests/test_matrix.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_orbit.html", dojo.moduleUrl("dojox","gfx3d/tests/test_orbit.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_overlap.html", dojo.moduleUrl("dojox","gfx3d/tests/test_overlap.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_polygon.html", dojo.moduleUrl("dojox","gfx3d/tests/test_polygon.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_quads.html", dojo.moduleUrl("dojox","gfx3d/tests/test_quads.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_rotate.html", dojo.moduleUrl("dojox","gfx3d/tests/test_rotate.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_scene.html", dojo.moduleUrl("dojox","gfx3d/tests/test_scene.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_triangles.html", dojo.moduleUrl("dojox","gfx3d/tests/test_triangles.html"+userArgs), 99999999); + doh.registerUrl("dojox/gfx3d/tests/test_vector.html", dojo.moduleUrl("dojox","gfx3d/tests/test_vector.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_change_structure.html", dojo.moduleUrl("dojox","grid/tests/test_change_structure.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_custom_sort.html", dojo.moduleUrl("dojox","grid/tests/test_custom_sort.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_dojo_data_edit.html", dojo.moduleUrl("dojox","grid/tests/test_dojo_data_edit.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_dojo_data_model.html", dojo.moduleUrl("dojox","grid/tests/test_dojo_data_model.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_dojo_data_model_EmptyResultSet.html", dojo.moduleUrl("dojox","grid/tests/test_dojo_data_model_EmptyResultSet.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_dojo_data_model_multiStores.html", dojo.moduleUrl("dojox","grid/tests/test_dojo_data_model_multiStores.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_dojo_data_model_processError.html", dojo.moduleUrl("dojox","grid/tests/test_dojo_data_model_processError.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_dojo_data_notification.html", dojo.moduleUrl("dojox","grid/tests/test_dojo_data_notification.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_edit.html", dojo.moduleUrl("dojox","grid/tests/test_edit.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_edit_canEdit.html", dojo.moduleUrl("dojox","grid/tests/test_edit_canEdit.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_edit_dijit.html", dojo.moduleUrl("dojox","grid/tests/test_edit_dijit.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_events.html", dojo.moduleUrl("dojox","grid/tests/test_events.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_expand.html", dojo.moduleUrl("dojox","grid/tests/test_expand.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_grid.html", dojo.moduleUrl("dojox","grid/tests/test_grid.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_grid_dlg.html", dojo.moduleUrl("dojox","grid/tests/test_grid_dlg.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_grid_headerHeight.html", dojo.moduleUrl("dojox","grid/tests/test_grid_headerHeight.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_grid_layout.html", dojo.moduleUrl("dojox","grid/tests/test_grid_layout.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_grid_layout_borderContainer.html", dojo.moduleUrl("dojox","grid/tests/test_grid_layout_borderContainer.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_grid_layout_LayoutContainer.html", dojo.moduleUrl("dojox","grid/tests/test_grid_layout_LayoutContainer.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_grid_object_model_change.html", dojo.moduleUrl("dojox","grid/tests/test_grid_object_model_change.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_grid_programmatic.html", dojo.moduleUrl("dojox","grid/tests/test_grid_programmatic.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_grid_programmatic_layout.html", dojo.moduleUrl("dojox","grid/tests/test_grid_programmatic_layout.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_grid_rtl.html", dojo.moduleUrl("dojox","grid/tests/test_grid_rtl.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_grid_themes.html", dojo.moduleUrl("dojox","grid/tests/test_grid_themes.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_grid_tooltip_menu.html", dojo.moduleUrl("dojox","grid/tests/test_grid_tooltip_menu.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_keyboard.html", dojo.moduleUrl("dojox","grid/tests/test_keyboard.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_markup.html", dojo.moduleUrl("dojox","grid/tests/test_markup.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_mysql_edit.html", dojo.moduleUrl("dojox","grid/tests/test_mysql_edit.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_sizing.html", dojo.moduleUrl("dojox","grid/tests/test_sizing.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_sizing_100rows.html", dojo.moduleUrl("dojox","grid/tests/test_sizing_100rows.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_sizing_ResizeHandle.html", dojo.moduleUrl("dojox","grid/tests/test_sizing_ResizeHandle.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_styling.html", dojo.moduleUrl("dojox","grid/tests/test_styling.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_subgrid.html", dojo.moduleUrl("dojox","grid/tests/test_subgrid.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_tundra_edit.html", dojo.moduleUrl("dojox","grid/tests/test_tundra_edit.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_yahoo_images.html", dojo.moduleUrl("dojox","grid/tests/test_yahoo_images.html"+userArgs), 99999999); + doh.registerUrl("dojox/grid/tests/test_yahoo_search.html", dojo.moduleUrl("dojox","grid/tests/test_yahoo_search.html"+userArgs), 99999999); + doh.registerUrl("dojox/help/demos/demo_Console.html", dojo.moduleUrl("dojox","help/demos/demo_Console.html"+userArgs), 99999999); + doh.registerUrl("dojox/highlight/tests/test_highlight.html", dojo.moduleUrl("dojox","highlight/tests/test_highlight.html"+userArgs), 99999999); + doh.registerUrl("dojox/highlight/tests/test_pygments.html", dojo.moduleUrl("dojox","highlight/tests/test_pygments.html"+userArgs), 99999999); + doh.registerUrl("dojox/image/tests/test_Gallery.html", dojo.moduleUrl("dojox","image/tests/test_Gallery.html"+userArgs), 99999999); + doh.registerUrl("dojox/image/tests/test_Lightbox.html", dojo.moduleUrl("dojox","image/tests/test_Lightbox.html"+userArgs), 99999999); + doh.registerUrl("dojox/image/tests/test_Magnifier.html", dojo.moduleUrl("dojox","image/tests/test_Magnifier.html"+userArgs), 99999999); + doh.registerUrl("dojox/image/tests/test_MagnifierLite.html", dojo.moduleUrl("dojox","image/tests/test_MagnifierLite.html"+userArgs), 99999999); + doh.registerUrl("dojox/image/tests/test_SlideShow.html", dojo.moduleUrl("dojox","image/tests/test_SlideShow.html"+userArgs), 99999999); + doh.registerUrl("dojox/image/tests/test_ThumbnailPicker.html", dojo.moduleUrl("dojox","image/tests/test_ThumbnailPicker.html"+userArgs), 99999999); + doh.registerUrl("dojox/io/proxy/tests/xip.html", dojo.moduleUrl("dojox","io/proxy/tests/xip.html"+userArgs), 99999999); + doh.registerUrl("dojox/lang/tests/fun_perf.html", dojo.moduleUrl("dojox","lang/tests/fun_perf.html"+userArgs), 99999999); + doh.registerUrl("dojox/layout/tests/test_DragPane.html", dojo.moduleUrl("dojox","layout/tests/test_DragPane.html"+userArgs), 99999999); + doh.registerUrl("dojox/layout/tests/test_ExpandoPane.html", dojo.moduleUrl("dojox","layout/tests/test_ExpandoPane.html"+userArgs), 99999999); + doh.registerUrl("dojox/layout/tests/test_ExpandoPane_code.html", dojo.moduleUrl("dojox","layout/tests/test_ExpandoPane_code.html"+userArgs), 99999999); + doh.registerUrl("dojox/layout/tests/test_ExpandoPane_more.html", dojo.moduleUrl("dojox","layout/tests/test_ExpandoPane_more.html"+userArgs), 99999999); + doh.registerUrl("dojox/layout/tests/test_FloatingPane.html", dojo.moduleUrl("dojox","layout/tests/test_FloatingPane.html"+userArgs), 99999999); + doh.registerUrl("dojox/layout/tests/test_RadioGroup.html", dojo.moduleUrl("dojox","layout/tests/test_RadioGroup.html"+userArgs), 99999999); + doh.registerUrl("dojox/layout/tests/test_ResizeHandle.html", dojo.moduleUrl("dojox","layout/tests/test_ResizeHandle.html"+userArgs), 99999999); + doh.registerUrl("dojox/layout/tests/test_ScrollPane.html", dojo.moduleUrl("dojox","layout/tests/test_ScrollPane.html"+userArgs), 99999999); + doh.registerUrl("dojox/layout/tests/test_ScrollPaneSingle.html", dojo.moduleUrl("dojox","layout/tests/test_ScrollPaneSingle.html"+userArgs), 99999999); + doh.registerUrl("dojox/layout/tests/test_SizingPane.html", dojo.moduleUrl("dojox","layout/tests/test_SizingPane.html"+userArgs), 99999999); + doh.registerUrl("dojox/off/demos/editor/editor.html", dojo.moduleUrl("dojox","off/demos/editor/editor.html"+userArgs), 99999999); + doh.registerUrl("dojox/off/demos/helloworld/helloworld.html", dojo.moduleUrl("dojox","off/demos/helloworld/helloworld.html"+userArgs), 99999999); + doh.registerUrl("dojox/presentation/tests/test_presentation.html", dojo.moduleUrl("dojox","presentation/tests/test_presentation.html"+userArgs), 99999999); + doh.registerUrl("dojox/rpc/demos/demo_JsonRestStore_CouchDB.html", dojo.moduleUrl("dojox","rpc/demos/demo_JsonRestStore_CouchDB.html"+userArgs), 99999999); + doh.registerUrl("dojox/rpc/demos/demo_JsonRestStore_Persevere.html", dojo.moduleUrl("dojox","rpc/demos/demo_JsonRestStore_Persevere.html"+userArgs), 99999999); + doh.registerUrl("dojox/rpc/demos/documentation.html", dojo.moduleUrl("dojox","rpc/demos/documentation.html"+userArgs), 99999999); + doh.registerUrl("dojox/rpc/demos/yahoo.html", dojo.moduleUrl("dojox","rpc/demos/yahoo.html"+userArgs), 99999999); + doh.registerUrl("dojox/rpc/tests/test_dojo_data_model_persevere.html", dojo.moduleUrl("dojox","rpc/tests/test_dojo_data_model_persevere.html"+userArgs), 99999999); + doh.registerUrl("dojox/sketch/tests/test_full.html", dojo.moduleUrl("dojox","sketch/tests/test_full.html"+userArgs), 99999999); + doh.registerUrl("dojox/storage/demos/helloworld.html", dojo.moduleUrl("dojox","storage/demos/helloworld.html"+userArgs), 99999999); + doh.registerUrl("dojox/storage/tests/test_storage.html", dojo.moduleUrl("dojox","storage/tests/test_storage.html"+userArgs), 99999999); + doh.registerUrl("dojox/string/tests/BuilderPerf.html", dojo.moduleUrl("dojox","string/tests/BuilderPerf.html"+userArgs), 99999999); + doh.registerUrl("dojox/string/tests/peller.html", dojo.moduleUrl("dojox","string/tests/peller.html"+userArgs), 99999999); + doh.registerUrl("dojox/string/tests/PerfFun.html", dojo.moduleUrl("dojox","string/tests/PerfFun.html"+userArgs), 99999999); + doh.registerUrl("dojox/timing/tests/test_Sequence.html", dojo.moduleUrl("dojox","timing/tests/test_Sequence.html"+userArgs), 99999999); + doh.registerUrl("dojox/timing/tests/test_ThreadPool.html", dojo.moduleUrl("dojox","timing/tests/test_ThreadPool.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/demo_FisheyeList-orig.html", dojo.moduleUrl("dojox","widget/tests/demo_FisheyeList-orig.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/demo_FisheyeList.html", dojo.moduleUrl("dojox","widget/tests/demo_FisheyeList.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/demo_FisheyeLite.html", dojo.moduleUrl("dojox","widget/tests/demo_FisheyeLite.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/test_ColorPicker.html", dojo.moduleUrl("dojox","widget/tests/test_ColorPicker.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/test_FileInput.html", dojo.moduleUrl("dojox","widget/tests/test_FileInput.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/test_FisheyeList.html", dojo.moduleUrl("dojox","widget/tests/test_FisheyeList.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/test_FisheyeLite.html", dojo.moduleUrl("dojox","widget/tests/test_FisheyeLite.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/test_Iterator.html", dojo.moduleUrl("dojox","widget/tests/test_Iterator.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/test_Loader.html", dojo.moduleUrl("dojox","widget/tests/test_Loader.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/test_MultiComboBox.html", dojo.moduleUrl("dojox","widget/tests/test_MultiComboBox.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/test_Rating.html", dojo.moduleUrl("dojox","widget/tests/test_Rating.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/test_SortList.html", dojo.moduleUrl("dojox","widget/tests/test_SortList.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/test_TimeSpinner.html", dojo.moduleUrl("dojox","widget/tests/test_TimeSpinner.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/test_Toaster.html", dojo.moduleUrl("dojox","widget/tests/test_Toaster.html"+userArgs), 99999999); + doh.registerUrl("dojox/widget/tests/test_Wizard.html", dojo.moduleUrl("dojox","widget/tests/test_Wizard.html"+userArgs), 99999999); + doh.registerUrl("dojox/wire/demos/markup/demo_ActionChaining.html", dojo.moduleUrl("dojox","wire/demos/markup/demo_ActionChaining.html"+userArgs), 99999999); + doh.registerUrl("dojox/wire/demos/markup/demo_ActionWiring.html", dojo.moduleUrl("dojox","wire/demos/markup/demo_ActionWiring.html"+userArgs), 99999999); + doh.registerUrl("dojox/wire/demos/markup/demo_BasicChildWire.html", dojo.moduleUrl("dojox","wire/demos/markup/demo_BasicChildWire.html"+userArgs), 99999999); + doh.registerUrl("dojox/wire/demos/markup/demo_BasicColumnWiring.html", dojo.moduleUrl("dojox","wire/demos/markup/demo_BasicColumnWiring.html"+userArgs), 99999999); + doh.registerUrl("dojox/wire/demos/markup/demo_ConditionalActions.html", dojo.moduleUrl("dojox","wire/demos/markup/demo_ConditionalActions.html"+userArgs), 99999999); + doh.registerUrl("dojox/wire/demos/markup/demo_FlickrStoreWire.html", dojo.moduleUrl("dojox","wire/demos/markup/demo_FlickrStoreWire.html"+userArgs), 99999999); + doh.registerUrl("dojox/wire/demos/markup/demo_TopicWiring.html", dojo.moduleUrl("dojox","wire/demos/markup/demo_TopicWiring.html"+userArgs), 99999999); + doh.registerUrl("dojox/_sql/demos/customers/customers.html", dojo.moduleUrl("dojox","_sql/demos/customers/customers.html"+userArgs), 99999999); +} +}catch(e){ + doh.debug(e); +} + +} diff --git a/includes/js/dojox/rpc/CouchDBRestStore.js b/includes/js/dojox/rpc/CouchDBRestStore.js new file mode 100644 index 0000000..f61836c --- /dev/null +++ b/includes/js/dojox/rpc/CouchDBRestStore.js @@ -0,0 +1,87 @@ +if(!dojo._hasResource["dojox.data.CouchDBRestStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.CouchDBRestStore"] = true; +dojo.provide("dojox.data.CouchDBRestStore"); +dojo.require("dojox.data.JsonRestStore"); +dojo.require("dojox.json.ref"); // TODO: Make it work without this dependency + +// A CouchDBRestStore is an extension of JsonRestStore to handle CouchDB's idiosyncrasies, special features, +// and deviations from standard HTTP Rest. +// NOTE: CouchDB is not designed to be run on a public facing network. There is no access control +// on database documents, and you should NOT rely on client side control to implement security. + + +dojo.declare("dojox.data.CouchDBRestStore", + dojox.data.JsonRestStore, + { + _commitAppend: function(listId,item) { + var deferred = this.service.post(listId,item); + var prefix = this.service.serviceName + '/'; + deferred.addCallback(function(result) { + item._id = prefix + result.id; // update the object with the results of the post + item._rev = result.rev; + return result; + //TODO: Need to go down the graph assigned _id based on path, so that sub items can be modified and properly reflected to the root item (being careful of circular references) + }); + return deferred; + }, + fetch: function(args) { + // summary: + // This only differs from JsonRestStore in that it, will put the query string the query part of the URL and it handles start and count + if (typeof args == 'string') { + args = {query: '_all_docs?' + args}; + } + else if (typeof args.query == 'string') { + args.query = '_all_docs?' + args.query; + } + else + args.query = '_all_docs?'; + if (args.start) { + args.query = (args.query ? (args.query + '&') : '') + 'skip=' + args.start; + delete args.start; + } + if (args.count) { + args.query = (args.query ? (args.query + '&') : '') + 'count=' + args.count; + delete args.count; + } + var prefix = this.service.serviceName + '/'; + var oldOnComplete = args.onComplete; + args.onComplete=function(results) { + if (results.rows) { + for (var i = 0; i < results.rows.length; i++) { + var row = results.rows[i]; // make it into a reference + row._id = prefix + (row.$ref = row.id); + } + } + if (oldOnComplete) + oldOnComplete.apply(this,arguments); + }; + return dojox.data.JsonRestStore.prototype.fetch.call(this,args); + } + } +); + + +dojox.data.CouchDBRestStore.generateSMD = function(couchServerUrl) { + var couchSMD = {contentType:"application/json", + transport:"REST", + envelope:"PATH", + services:{}, + target: couchServerUrl, + }; + var def = dojo.xhrGet({ + url: couchServerUrl+"_all_dbs", + handleAs: "json", + sync: true + }); + def.addCallback(function(dbs) { + for (var i = 0; i < dbs.length; i++) + couchSMD.services[dbs[i]] = { + target:dbs[i], + returns:{}, + parameters:[{type:"string"}] + } + }); + return couchSMD; +} + +} diff --git a/includes/js/dojox/rpc/JsonRPC.js b/includes/js/dojox/rpc/JsonRPC.js new file mode 100644 index 0000000..1710b31 --- /dev/null +++ b/includes/js/dojox/rpc/JsonRPC.js @@ -0,0 +1,58 @@ +if(!dojo._hasResource["dojox.rpc.JsonRPC"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.JsonRPC"] = true; +dojo.provide("dojox.rpc.JsonRPC"); + +dojox.rpc.envelopeRegistry.register( + "JSON-RPC-1.0",function(str){return str == "JSON-RPC-1.0"},{ + serialize: function(smd, method, data, options){ + //not converted to json it self. This will be done, if appropriate, at the + //transport level + var d = dojox.rpc.toOrdered(method, data); + d = dojox.rpc.toJson({id: this._requestId++, method: method.name, params: d}); + + return { + data: d, + contentType: 'application/json', + transport:"POST" + } + }, + + deserialize: function(results){ + var obj = dojox.rpc.resolveJson(results); + if (obj.error) { + var e = new Error(obj.error); + e._rpcErrorObject = obj.error; + return e; + } + return obj.result || true; + } + } +); + +dojox.rpc.envelopeRegistry.register( + "JSON-RPC-1.2",function(str){return str == "JSON-RPC-1.2"},{ + serialize: function(smd, method, data, options){ + var trans = method.transport || smd.transport || "POST"; + var d = dojox.rpc.toNamed(method, data); + + d = dojox.rpc.toJson({id: this._requestId++, method: method.name, params: data}); + return { + data: d, + contentType: 'application/json', + transport:"POST" + } + }, + + deserialize: function(results){ + var obj = dojox.rpc.resolveJson(results); + if (obj.error) { + var e = new Error(obj.error.message); + e._rpcErrorObject = obj.error; + return e; + } + return obj.result || true; + } + } +); + +} diff --git a/includes/js/dojox/rpc/JsonReferencing.js b/includes/js/dojox/rpc/JsonReferencing.js new file mode 100644 index 0000000..618ea06 --- /dev/null +++ b/includes/js/dojox/rpc/JsonReferencing.js @@ -0,0 +1,265 @@ +if(!dojo._hasResource["dojox.rpc.JsonReferencing"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.JsonReferencing"] = true; +dojo.provide("dojox.rpc.JsonReferencing"); +dojo.require("dojo.date.stamp"); +dojo.require("dojo._base.Deferred"); + +// summary: +// Adds advanced JSON {de}serialization capabilities to the base json library. +// This enhances the capabilities of dojo.toJson and dojo.fromJson, +// adding referencing support, date handling, and other extra format handling. +// On parsing, references are resolved. When references are made to +// ids/objects that have been loaded yet, a Deferred object will be used as the +// value and as soon as a callback is added to the Deferred object, the target +// object will be loaded. + + + +dojox.rpc._index={}; // the global map of id->object +dojox.rpc.onUpdate = function(/*Object*/ object, /* attribute-name-string */ attribute, /* any */ oldValue, /* any */ newValue){ + // summary: + // This function is called when an existing object in the system is updated. Existing objects are found by id. +}; + +dojox.rpc.resolveJson = function(/*Object*/ root,/*Object?*/ schema){ + // summary: + // Indexes and resolves references in the JSON object. + // A JSON Schema object that can be used to advise the handling of the JSON (defining ids, date properties, urls, etc) + // + // root: + // The root object of the object graph to be processed + // + // schema: A JSON Schema object that can be used to advise the parsing of the JSON (defining ids, date properties, urls, etc) // + // Currently this provides a means for context based id handling + // + // return: + // An object, the result of the processing + var ref,reWalk=[]; + function makeIdInfo(schema){ // find out what attribute and what id prefix to use + if (schema){ + var attr; + if (!(attr = schema._idAttr)){ + for (var i in schema.properties){ + if (schema.properties[i].unique){ + schema._idAttr = attr = i; + } + } + } + if (attr || schema._idPrefix){ + return {attr:attr || 'id',prefix:schema._idPrefix}; + } + } + + return false; + } + function walk(it,stop,schema,idInfo,defaultId){ + // this walks the new graph, resolving references and making other changes + var val,i; + var id = it[idInfo.attr]; + id = (id && (idInfo.prefix + id)) || defaultId; // if there is an id, prefix it, otherwise inherit + var target = it; + + if (id){ // if there is an id available... + it._id = id; + if (dojox.rpc._index[id]){ // if the id already exists in the system, we should use the existing object, and just update it + target = dojox.rpc._index[id]; + delete target.$ref; // remove this artifact + } + dojox.rpc._index[id] = target; // add the prefix, set _id, and index it + if (schema && dojox.validate && dojox.validate.jsonSchema){ // if json schema is activated, we can load it in the registry of instance schemas map + dojox.validate.jsonSchema._schemas[id] = schema; + } + + } + for (i in it){ + if (it.hasOwnProperty(i) && (typeof (val=it[i]) =='object') && val){ + ref=val.$ref; + if (ref){ // a reference was found + var stripped = ref.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');// trim it + if(/[\w\[\]\.\$ \/\r\n\t]/.test(stripped) && !/=|((^|\W)new\W)/.test(stripped)){ // make sure it is a safe reference + var path = ref.match(/(^\.*[^\.\[]+)([\.\[].*)?/); // divide along the path + if ((ref=path[1]=='$' ? root:dojox.rpc._index[new dojo._Url(idInfo.prefix,path[1])]) && // a $ indicates to start with the root, otherwise start with an id + (ref = path[2] ? eval('ref' + path[2]) : ref)){// starting point was found, use eval to resolve remaining property references + // otherwise, no starting point was found (id not found), if stop is set, it does not exist, we have + // unloaded reference, if stop is not set, it may be in a part of the graph not walked yet, + // we will wait for the second loop + val = ref; + } + else{ + if (!stop){ + if (!rewalking) + reWalk.push(it); // we need to rewalk it to resolve references + var rewalking = true; // we only want to add it once + } + else { + ref = val.$ref; + val = new dojo.Deferred(); + val._id = idInfo.prefix + ref; + (function(val,ref){ + var connectId = dojo.connect(val,"addCallbacks",function(){ + dojo.disconnect(connectId); + dojox.rpc.services[idInfo.prefix.substring(0,idInfo.prefix.length-1)](ref) // otherwise call by looking up the service + .addCallback(dojo.hitch(val,val.callback)); + + }); + })(val,ref); + } + } + } + } + else { + if (!stop){ // if we are in stop, that means we are in the second loop, and we only need to check this current one, + // further walking may lead down circular loops + var valSchema = val.schema || // a schema can be self-defined by the object, + (schema && schema.properties && schema.properties[i]); // or it can from the schema sub-object definition + if (valSchema){ + idInfo = makeIdInfo(valSchema)||idInfo; + } + val = walk(val,reWalk==it,valSchema,idInfo,id && (id + ('[' + dojo._escapeString(i) + ']'))); + } + } + } + if (dojo.isString(val) && schema && schema.properties && schema.properties[i] && schema.properties[i].format=='date-time'){// parse the date string + val = dojo.date.stamp.fromISOString(val); // create a date object + } + it[i] = val; + var old = target[i]; + if (val !== old){ // only update if it changed + target[i] = val; // update the target + propertyChange(i,old,val); + } + } + function propertyChange(key,old,newValue){ + setTimeout(function(){ + dojox.rpc.onUpdate(target,i,old,newValue); // call the listener for each update + }); + } + if (target != it){ // this means we are updating, we need to remove deleted + for (i in target){ + if (!it.hasOwnProperty(i) && i != '_id' && !(target instanceof Array && isNaN(i))){ + propertyChange(i,target[i],undefined); + delete target[i]; + } + } + } + return target; + } + var idInfo = makeIdInfo(schema)||{attr:'id',prefix:''}; + if (!root){ return root; } + root = walk(root,false,schema,idInfo,dojox._newId && (new dojo._Url(idInfo.prefix,dojox._newId) +'')); // do the main walk through + walk(reWalk,false,schema,idInfo); // re walk any parts that were not able to resolve references on the first round + return root; +}; +dojox.rpc.fromJson = function(/*String*/ str,/*Object?*/ schema){ + // summary: + // evaluates the passed string-form of a JSON object. + // A JSON Schema object that can be used to advise the parsing of the JSON (defining ids, date properties, urls, etc) + // which may defined by setting dojox.currentSchema to the current schema you want to use for this evaluation + // + // json: + // a string literal of a JSON item, for instance: + // '{ "foo": [ "bar", 1, { "baz": "thud" } ] }' + // schema: A JSON Schema object that can be used to advise the parsing of the JSON (defining ids, date properties, urls, etc) // + // Currently this provides a means for context based id handling + // + // return: + // An object, the result of the evaluation + root = eval('(' + str + ')'); // do the eval + if (root){ + return this.resolveJson(root,schema); + } + return root; +} +dojox.rpc.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*Object?*/ schema){ + // summary: + // Create a JSON serialization of an object. + // This has support for referencing, including circular references, duplicate references, and out-of-message references + // id and path-based referencing is supported as well and is based on http://www.json.com/2007/10/19/json-referencing-proposal-and-library/. + // + // it: + // an object to be serialized. + // + // prettyPrint: + // if true, we indent objects and arrays to make the output prettier. + // The variable dojo.toJsonIndentStr is used as the indent string + // -- to use something other than the default (tab), + // change that variable before calling dojo.toJson(). + // + // schema: A JSON Schema object that can be used to advise the parsing of the JSON (defining ids, date properties, urls, etc) // + // Currently this provides a means for context based id handling + // + // return: + // a String representing the serialized version of the passed object. + + var idPrefix = (schema&& schema._idPrefix) || ''; // the id prefix for this context + var paths={}; + function serialize(it,path,_indentStr){ + if (it && dojo.isObject(it)){ + var value; + if (it instanceof Date){ // properly serialize dates + return '"' + dojo.date.stamp.toISOString(it,{zulu:true}) + '"'; + } + var id = it._id; + if (id){ // we found an identifiable object, we will just serialize a reference to it... unless it is the root + + if (path != '$'){ + return serialize({$ref:id.charAt(0)=='$' ? id : // a pure path based reference, leave it alone + id.substring(0,idPrefix.length)==idPrefix ? // see if the reference is in the current context + id.substring(idPrefix.length): // a reference with a prefix matching the current context, the prefix should be removed + '../' + id});// a reference to a different context, assume relative url based referencing + } + path = id; + } + else { + it._id = path; // we will create path ids for other objects in case they are circular + paths[path] = it;// save it here so they can be deleted at the end + } + _indentStr = _indentStr || ""; + var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : ""; + var newLine = prettyPrint ? "\n" : ""; + var sep = prettyPrint ? " " : ""; + + if (it instanceof Array){ + var res = dojo.map(it, function(obj,i){ + var val = serialize(obj, path + '[' + i + ']', nextIndent); + if(!dojo.isString(val)){ + val = "undefined"; + } + return newLine + nextIndent + val; + }); + return "[" + res.join("," + sep) + newLine + _indentStr + "]"; + } + + var output = []; + for(var i in it){ + var keyStr; + if(typeof i == "number"){ + keyStr = '"' + i + '"'; + }else if(dojo.isString(i) && i != '_id'){ + keyStr = dojo._escapeString(i); + }else{ + // skip non-string or number keys + continue; + } + var val = serialize(it[i],path+(i.match(/^[a-zA-Z]\w*$/) ? // can we use simple .property syntax? + ('.' + i) : // yes, otherwise we have to escape it + ('[' + dojo._escapeString(i) + ']')),nextIndent); + if(!dojo.isString(val)){ + // skip non-serializable values + continue; + } + output.push(newLine + nextIndent + keyStr + ":" + sep + val); + } + return "{" + output.join("," + sep) + newLine + _indentStr + "}"; + } + + return dojo.toJson(it); // use the default serializer for primitives + } + var json = serialize(it,'$',''); + for (i in paths){ // cleanup the temporary path-generated ids + delete paths[i]._id; + } + return json; +} + +} diff --git a/includes/js/dojox/rpc/JsonRestStore.js b/includes/js/dojox/rpc/JsonRestStore.js new file mode 100644 index 0000000..dd14874 --- /dev/null +++ b/includes/js/dojox/rpc/JsonRestStore.js @@ -0,0 +1,661 @@ +if(!dojo._hasResource["dojox.data.JsonRestStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.JsonRestStore"] = true; +dojo.provide("dojox.data.JsonRestStore"); +dojo.require("dojox.rpc.Rest"); +dojo.require("dojox.rpc.JsonReferencing"); // TODO: Make it work without this dependency + +// A JsonRestStore takes a REST service and uses it the remote communication for a +// read/write dojo.data implementation. To use a JsonRestStore you should create a +// service with a REST transport. This can be configured with an SMD: +//{ +// services: { +// jsonRestStore: { +// transport: "REST", +// envelope: "URL", +// target: "store.php", +// contentType:"application/json", +// parameters: [ +// {name: "location", type: "string", optional: true} +// ] +// } +// } +//} +// The SMD can then be used to create service, and the service can be passed to a JsonRestStore. For example: +// var myServices = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd")); +// var jsonStore = new dojox.data.JsonRestStore({service:myServices.jsonRestStore}); +// +// The JsonRestStore will then cause all saved modifications to be server using Rest commands (PUT, POST, or DELETE). +// The JsonRestStore also supports lazy loading. References can be made to objects that have not been loaded. +// For example if a service returned: +// {"name":"Example","lazyLoadedObject":{"$ref":"obj2"}} +// +// And this object has accessed using the dojo.data API: +// var obj = jsonStore.getValue(myObject,"lazyLoadedObject"); +// The object would automatically be requested from the server (with an object id of "obj2"). +// +// When using a Rest store on a public network, it is important to implement proper security measures to +// control access to resources + +dojox.data.ASYNC_MODE = 0; +dojox.data.SYNC_MODE = 1; +dojo.declare("dojox.data.JsonRestStore", + null, + { + mode: dojox.data.ASYNC_MODE, + constructor: function(options){ + //summary: + // JsonRestStore constructor, instantiate a new JsonRestStore + // A JsonRestStore can be configured from a JSON Schema. Queries are just + // passed through as URLs for XHR requests, + // so there is nothing to configure, just plug n play. + // Of course there are some options to fiddle with if you want: + // + // jsonSchema: /* object */ + // + // service: /* function */ + // This is the service object that is used to retrieve lazy data and save results + // The function should be directly callable with a single parameter of an object id to be loaded + // The function should also have the following methods: + // put(id,value) - puts the value at the given id + // post(id,value) - posts (appends) the value at the given id + // delete(id) - deletes the value corresponding to the given id + // + // idAttribute: /* string */ + // Defaults to 'id'. The name of the attribute that holds an objects id. + // This can be a preexisting id provided by the server. + // If an ID isn't already provided when an object + // is fetched or added to the store, the autoIdentity system + // will generate an id for it and add it to the index. + + // mode: dojox.data.ASYNC_MODE || dojox.data.SYNC_MODE + // Defaults to ASYNC_MODE. This option sets the default mode for this store. + // Sync calls return their data immediately from the calling function + // instead of calling the callback functions. Functions such as + // fetchItemByIdentity() and fetch() both accept a string parameter in addtion + // to the normal keywordArgs parameter. When passed this option, SYNC_MODE will + // automatically be used even when the default mode of the system is ASYNC_MODE. + // A normal request to fetch or fetchItemByIdentity (with kwArgs object) can also + // include a mode property to override this setting for that one request. + + //setup a byId alias to the api call + this.byId=this.fetchItemByIdentity; + // if the advanced json parser is enabled, we can pass through object updates as onSet events + dojo.connect(dojox.rpc,"onUpdate",this,function(obj,attrName,oldValue,newValue){ + var prefix = this.service.serviceName + '/'; + if (!obj._id){ + console.log("no id on updated object ", obj); + } + else if (obj._id.substring(0,prefix.length) == prefix) + this.onSet(obj,attrName,oldValue,newValue); + }); + if (options){ + dojo.mixin(this,options); + } + if (!this.service) + throw Error("A service is required for JsonRestStore"); + if (!(this.service.contentType + '').match(/application\/json/)) + throw Error("A service must use a contentType of 'application/json' in order to be used in a JsonRestStore"); + this.idAttribute = (this.service._schema && this.service._schema._idAttr) || 'id'; + var arrayModifyingMethodNames = ["splice","push","pop","unshift","shift","reverse","sort"]; + this._arrayModifyingMethods = {}; + var array = []; + var _this = this; + // setup array augmentation, for catching mods and setting arrays as dirty + for (var i = 0; i < arrayModifyingMethodNames.length; i++){ + (function(key){ // closure for the method to be bound correctly + var method = array[key]; + _this._arrayModifyingMethods[key] = function(){ + _this._setDirty(this); // set the array as dirty before the native modifying operation + return method.apply(this,arguments); + } + _this._arrayModifyingMethods[key]._augmented = 1; + })(arrayModifyingMethodNames[i]); + } + this._deletedItems=[]; + this._dirtyItems=[]; + //given a url, load json data from as the store + }, + + _loadById: function(id,callback){ + var slashIndex = id.indexOf('/'); + var serviceName = id.substring(0,slashIndex); + var id = id.substring(slashIndex + 1); + (this.service.serviceName == serviceName ? + this.service : // use the current service if it is the right one + dojox.rpc.services[serviceName])(id) // otherwise call by looking up the service + .addCallback(callback); + }, + getValue: function(item, property,lazyCallback){ + // summary: + // Gets the value of an item's 'property' + // + // item: /* object */ + // property: /* string */ + // property to look up value for + // lazyCallback: /* function*/ + // not part of the API, but if you are using lazy loading properties, you may provide a callback to resume, in order to have asynchronous loading + var value = item[property]; + if (value && value.$ref){ + dojox.rpc._sync = !lazyCallback; // tell the service to operate synchronously (I have some concerns about the "thread" safety with FF3, as I think it does event stacking on sync calls) + this._loadById((value && value._id) || (item._id + '.' + property),lazyCallback); + delete dojox.rpc._sync; // revert to normal async behavior + } else if (lazyCallback){lazyCallback(value);} + return value; + }, + + getValues: function(item, property){ + // summary: + // Gets the value of an item's 'property' and returns + // it. If this value is an array it is just returned, + // if not, the value is added to an array and that is returned. + // + // item: /* object */ + // property: /* string */ + // property to look up value for + + var val = this.getValue(item,property); + return dojo.isArray(val) ? val : [val]; + }, + + getAttributes: function(item){ + // summary: + // Gets the available attributes of an item's 'property' and returns + // it as an array. + // + // item: /* object */ + + var res = []; + for (var i in item){ + res.push(i); + } + return res; + }, + + hasAttribute: function(item,attribute){ + // summary: + // Checks to see if item has attribute + // + // item: /* object */ + // attribute: /* string */ + return attribute in item; + }, + + containsValue: function(item, attribute, value){ + // summary: + // Checks to see if 'item' has 'value' at 'attribute' + // + // item: /* object */ + // attribute: /* string */ + // value: /* anything */ + return getValue(item,attribute)==value; + }, + + + isItem: function(item){ + // summary: + // Checks to see if a passed 'item' + // is really a JsonRestStore item. + // + // item: /* object */ + // attribute: /* string */ + + return !!(dojo.isObject(item) && item._id); + }, + + isItemLoaded: function(item){ + // summary: + // returns isItem() :) + // + // item: /* object */ + + return !item.$ref; + }, + + loadItem: function(item){ + // summary: + // Loads an item that has not been loaded yet. Lazy loading should happen through getValue, and if used properly, this should never need to be called + // returns true. Note this does not work with lazy loaded primitives! + if (item.$ref){ + dojox.rpc._sync = true; // tell the service to operate synchronously + this._loadById(item._id) + delete dojox.rpc._sync; // revert to normal async behavior + } + + return true; + }, + + _walk : function(value,forEach){ + // walk the graph, avoiding duplication + var walked=[]; + function walk(value){ + if (value && typeof value == 'object' && !value.__walked){ + value.__walked = true; + walked.push(value); + for (var i in value){ + if (walk(value[i])){ + forEach(value,i,value[i]); + } + } + return true; + } + } + walk(value); + forEach({},null,value); + for (var i = 0; i < walked.length;i++) + delete walked[i].__walked; + }, + fetch: function(args){ + //console.log("fetch() ", args); + // summary + // + // fetch takes either a string argument or a keywordArgs + // object containing the parameters for the search. + // If passed a string, fetch will interpret this string + // as the query to be performed and will do so in + // SYNC_MODE returning the results immediately. + // If an object is supplied as 'args', its options will be + // parsed and then contained query executed. + // + // query: /* string or object */ + // Defaults to "". This is basically passed to the XHR request as the URL to get the data + // + // start: /* int */ + // Starting item in result set + // + // count: /* int */ + // Maximum number of items to return + // + // cache: /* boolean */ + // + // sort: /* function */ + // Not Implemented yet + // + // The following only apply to ASYNC requests (the default) + // + // onBegin: /* function */ + // called before any results are returned. Parameters + // will be the count and the original fetch request + // + // onItem: /*function*/ + // called for each returned item. Parameters will be + // the item and the fetch request + // + // onComplete: /* function */ + // called on completion of the request. Parameters will + // be the complete result set and the request + // + // onError: /* function */ + // colled in the event of an error + + if(dojo.isString(args)){ + query = args; + args={query: query, mode: dojox.data.SYNC_MODE}; + + } + + var query; + if (!args || !args.query){ + if (!args){ + var args={}; + } + + if (!args.query){ + args.query=""; + query=args.query; + } + + } + + if (dojo.isObject(args.query)){ + if (args.query.query){ + query = args.query.query; + }else{ + query = args.query = ""; + } + if (args.query.queryOptions){ + args.queryOptions=args.query.queryOptions + } + }else{ + query=args.query; + } + if (args.start || args.count){ + query += '[' + (args.start ? args.start : '') + ':' + (args.count ? ((args.start || 0) + args.count) : '') + ']'; + } + var results = dojox.rpc._index[this.service.serviceName + '/' + query]; + if (!args.mode){args.mode = this.mode;} + var _this = this; + var defResult; + dojox.rpc._sync = this.mode; + dojox._newId = query; + if (results && !("cache" in args && !args.cache)){ // TODO: Add TTL maybe? + defResult = new dojo.Deferred; + defResult.callback(results); + } + else { + defResult = this.service(query); + } + defResult.addCallback(function(results){ + delete dojox._newId; // cleanup + if (args.onBegin){ + args["onBegin"].call(_this, results.length, args); + } + _this._walk(results,function(obj,i,value){ + if (value instanceof Array){ + for (var i in _this._arrayModifyingMethods){ + if (!value[i]._augmented){ + value[i] = _this._arrayModifyingMethods[i]; + } + } + + } + }); + if (args.onItem){ + for (var i=0; i 0){ + var dirty = this._dirtyItems.pop(); + var item = dirty.item; + var append = false; + left++; + var deferred; + if (item instanceof Array && dirty.old instanceof Array){ + // see if we can just append the item with a post + append = true; + for (var i = 0, l = dirty.old.length; i < l; i++){ + if (item[i] != dirty.old[i]){ + append = false; + } + } + if (append){ // if we can, we will do posts to add from here + for (;i 0){ + left++; + this.service['delete'](this.getIdentity(this._deletedItems.pop())).addCallback(finishOne); + } + }, + + + revert: function(){ + // summary + // returns any modified data to its original state prior to a save(); + + while (this._dirtyItems.length>0){ + var i; + var d = this._dirtyItems.pop(); + for (i in d.old){ + d.item[i] = d.old[i]; + } + for (i in d.item){ + if (!d.old.hasOwnProperty(i)) + delete d.item[i] + } + } + this.onRevert(); + }, + + + isDirty: function(item){ + // summary + // returns true if the item is marked as dirty. + for (var i=0, l=this._dirtyItems.length; i 0; j--) + arguments[j] = arguments[j-1]; // shift them over + arguments[0] = dojo.mixin({restMethod: restMethod},method); + return svc._executeMethod.apply(svc,arguments); + } + })(); + + } + executor.contentType = method.contentType || svc._smd.contentType; // this is so a Rest service can be examined to know what type of content type to expect + return executor; + }, + restMethods:dojox.rpc._restMethods + } +); + +} diff --git a/includes/js/dojox/rpc/SMDLibrary/yahoo.smd b/includes/js/dojox/rpc/SMDLibrary/yahoo.smd new file mode 100644 index 0000000..cf08ee7 --- /dev/null +++ b/includes/js/dojox/rpc/SMDLibrary/yahoo.smd @@ -0,0 +1,493 @@ +{ + "SMDVersion": "2.0", + // FIXME: is this the kind of value we're supposed to use here? + "id": "http://developer.yahoo.com/search/", + "description": "Yahoo's search API", + + transport: "JSONP", + envelope: "URL", + additionalParameters: true, + parameters: [ + { name: "appid", optional: false, "default": "dojotoolkit" }, + { name: "output", optional: false, "default": "json" } + ], + + // FIXME: Quite a few of these APIs can take multiple entries for the same parameter, to behave + // as multi-select options. How should we handle these? + + services: { + // + // ANSWERS + // + // FIXME: Some of these API endpoints' names only make sense when you know they're in the + // Yahoo Answers part of the API; just reading a flat listing of methods in this SMD + // likely won't have enough information about what they do. Should we split this up? + + // http://developer.yahoo.com/answers/V1/questionSearch.html + questionSearch: { + target: "http://answers.yahooapis.com/AnswersService/V1/questionSearch", + parameters: [ + { name: "query", type: "string", optional: false, "default": "" }, + { name: "search_in", type: "string", optional: true, "default": "all" }, // can be "all", "question", "best_answer" + { name: "category_id", type: "integer", optional: true, "default": null }, // one of (category_id, category_name) is required + { name: "category_name", type: "string", optional: true, "default": null }, + { name: "region", type: "string", optional: true, "default": "us" }, // can be "us", "uk", "ca", "au", "in", "es", "br", "ar", "mx", "e1", "it", "de", "fr", "sg" + { name: "date_range", type: "string", optional: true, "default": "all" }, // can be "all", "7", "7-30", "30-60", "60-90", "more90" + { name: "sort", type: "string", optional: true, "default": "relevance" }, // can be "relevance", "date_desc", "date_asc" + { name: "type", type: "string", optional: true, "default": "all" }, // can be "all", "resolved", "open", "undecided" + { name: "start", type: "integer", optional: true, "default": 0 }, + { name: "results", type: "integer", optional: true, "default": 10 } // max 50 + ] + }, + + // http://developer.yahoo.com/answers/V1/getByCategory.html + getByCategory: { + target: "http://answers.yahooapis.com/AnswersService/V1/getByCategory", + parameters: [ + { name: "category_id", type: "integer", optional: true, "default": null }, // one of (category_id, category_name) is required + { name: "category_name", type: "string", optional: true, "default": null }, + { name: "type", type: "string", optional: true, "default": "all" }, // can be "all", "resolved", "open", "undecided" + { name: "region", type: "string", optional: true, "default": "us" }, // can be "us", "uk", "ca", "au", "in", "es", "br", "ar", "mx", "e1", "it", "de", "fr", "sg" + { name: "sort", type: "string", optional: true, "default": "date_desc" }, // can be "date_desc", "date_asc", "ans_count_desc", "ans_count_asc" + { name: "start", type: "integer", optional: true, "default": 0 }, + { name: "results", type: "integer", optional: true, "default": 10 } // max 50 + ] + }, + + // http://developer.yahoo.com/answers/V1/getQuestion.html + getQuestion: { + target: "http://answers.yahooapis.com/AnswersService/V1/getQuestion", + parameters: [ + { name: "question_id", type: "string", optional: true, "default": null } + ] + }, + + // http://developer.yahoo.com/answers/V1/getByUser.html + getByUser: { + target: "http://answers.yahooapis.com/AnswersService/V1/getByUser", + parameters: [ + { name: "user_id", type: "string", optional: false, "default": "" }, + { name: "type", type: "string", optional: true, "default": "all" }, // can be "all", "resolved", "open", "undecided" + { name: "filter", type: "string", optional: true, "default": "question" }, // can be "question", "answer", "best_answer" + { name: "sort", type: "string", optional: true, "default": "date_desc" }, // can be "date_desc", "date_asc", "ans_count_desc", "ans_count_asc" + { name: "start", type: "integer", optional: true, "default": 0 }, + { name: "results", type: "integer", optional: true, "default": 10 } // max 50 + ] + }, + + // + // AUDIO SEARCH + // + + // http://developer.yahoo.com/search/audio/V1/artistSearch.html + artistSearch: { + target: "http://search.yahooapis.com/AudioSearchService/V1/artistSearch", + parameters: [ + { name: "artist", type: "string", optional: true, "default": "" }, // one of (artist, artistid) is required + { name: "artistid", type: "string", optional: true, "default": "" }, + { name: "type", type: "string", optional: true, "default": "all" }, // can be "all", "any", "phrase" + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/search/audio/V1/albumSearch.html + albumSearch: { + target: "http://search.yahooapis.com/AudioSearchService/V1/albumSearch", + parameters: [ + { name: "artist", type: "string", optional: true, "default": "" }, + { name: "artistid", type: "string", optional: true, "default": "" }, + { name: "album", type: "string", optional: true, "default": "" }, + { name: "albumid", type: "string", optional: true, "default": "" }, + { name: "type", type: "string", optional: true, "default": "all" }, // can be "all", "any", "phrase" + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/search/audio/V1/songSearch.html + songSearch: { + // beware, this method has returned many a JSON string containing syntax error(s) + target: "http://search.yahooapis.com/AudioSearchService/V1/songSearch", + parameters: [ + { name: "artist", type: "string", optional: true, "default": "" }, + { name: "artistid", type: "string", optional: true, "default": "" }, + { name: "album", type: "string", optional: true, "default": "" }, + { name: "albumid", type: "string", optional: true, "default": "" }, + { name: "song", type: "string", optional: true, "default": "" }, + { name: "songid", type: "string", optional: true, "default": "" }, + { name: "type", type: "string", optional: true, "default": "all" }, // can be "all", "any", "phrase" + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/search/audio/V1/songDownloadLocation.html + songDownloadLocation: { + target: "http://search.yahooapis.com/AudioSearchService/V1/songDownloadLocation", + parameters: [ + { name: "songid", type: "string", optional: false, "default": "" }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 }, + { name: "source", type: "string", optional: true, "default": "" } // can be "audiolunchbox", "artistdirect", "buymusic", "dmusic", "emusic", "epitonic", "garageband", "itunes", "yahoo", "livedownloads", "mp34u", "msn", "musicmatch", "mapster", "passalong", "rhapsody", "soundclick", "theweb" + ] + }, + + // + // CONTENT ANALYSIS + // + + // http://developer.yahoo.com/search/content/V1/termExtraction.html + contextSearch: { + // FIXME: the API docs say to submit this as a POST, but we need JSONP for cross-domain, right? + // transport: "POST", + target: "http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction", + parameters: [ + { name: "context", type: "string", optional: false, "default": "" }, + { name: "query", type: "string", optional: true, "default": "" } + ] + }, + + // + // IMAGE SEARCH + // + + // http://developer.yahoo.com/search/image/V1/imageSearch.html + imageSearch: { + target: "http://search.yahooapis.com/ImageSearchService/V1/imageSearch", + parameters: [ + { name: "query", type: "string", optional: false, "default": "" }, + { name: "type", type: "string", optional: true, "default": "any" }, // can be "all", "any", "phrase" + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 }, + { name: "format", type: "string", optional: true, "default": "any" }, // can be "any", "bmp", "gif", "jpeg", "png" + { name: "adult_ok", type: "boolean", optional: true, "default": null }, + { name: "coloration", type: "string", optional: true, "default": "any" }, // can be "any", "color", "bw" + { name: "site", type: "string", optional: true, "default": null } + ] + }, + + // + // LOCAL SEARCH + // + + // http://developer.yahoo.com/search/local/V3/localSearch.html + localSearch: { + target: "http://local.yahooapis.com/LocalSearchService/V3/localSearch", + parameters: [ + { name: "query", type: "string", optional: true, "default": "" }, // optional, but one of (query, listing_id) is required + { name: "listing_id", type: "string", optional: true, "default": "" }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 20 + { name: "start", type: "integer", optional: true, "default": 1 }, + { name: "sort", type: "string", optional: true, "default": "relevance" }, // can be "relevance", "title", "distance", "rating" + { name: "radius", type: "float", optional: true }, // the default varies according to location + { name: "street", type: "string", optional: true, "default": null }, + { name: "city", type: "string", optional: true, "default": null }, + { name: "state", type: "string", optional: true, "default": null }, // full name or two-letter abbreviation + { name: "zip", type: "any", optional: true, "default": null }, // ddddd or ddddd-dddd format + { name: "location", type: "string", optional: true, "default": null }, // free text, supersedes the street, city, state, zip fields + { name: "latitude", type: "float", optional: true }, // -90 to 90 + { name: "longitude", type: "float", optional: true }, // -180 to 180 + { name: "category", type: "integer", optional: true }, + { name: "omit_category", type: "integer", optional: true }, + { name: "minimum_rating", type: "integer", optional: true } + ] + }, + + // http://developer.yahoo.com/local/V1/collectionSearch.html + collectionSearch: { + target: "http://collections.local.yahooapis.com/LocalSearchService/V1/collectionSearch", + parameters: [ + { name: "query", type: "string", optional: true, "default": "" }, // optional, but at least one of (query, username) is required + { name: "username", type: "string", optional: true, "default": "" }, + { name: "city", type: "string", optional: true, "default": null }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/local/V1/getCollection.html + getCollection: { + target: "http://collections.local.yahooapis.com/LocalSearchService/V1/getCollection", + parameters: [ + { name: "collection_id", type: "integer", optional: false, "default": "" } + ] + }, + + // + // MY WEB 2.0 + // + + // http://developer.yahoo.com/search/myweb/V1/urlSearch.html + urlSearch: { + target: "http://search.yahooapis.com/MyWebService/V1/urlSearch", + parameters: [ + { name: "tag", type: "string", optional: true, "default": "" }, + { name: "yahooid", type: "string", optional: true, "default": "" }, + { name: "sort", type: "string", optional: true, "default": "date" }, // can be "date", "title", "url" + { name: "reverse_sort", type: "boolean", optional: true, "default": 0 }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/search/myweb/V1/tagSearch.html + tagSearch: { + target: "http://search.yahooapis.com/MyWebService/V1/tagSearch", + parameters: [ + { name: "url", type: "string", optional: true, "default": "" }, + { name: "yahooid", type: "string", optional: true, "default": "" }, + { name: "sort", type: "string", optional: true, "default": "popularity" }, // can be "popularity", "tag", "date" + { name: "reverse_sort", type: "boolean", optional: true, "default": 0 }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/search/myweb/V1/relatedTags.html + relatedTags: { + target: "http://search.yahooapis.com/MyWebService/V1/relatedTags", + parameters: [ + { name: "tag", type: "string", optional: false, "default": "" }, + { name: "yahooid", type: "string", optional: true, "default": "" }, + { name: "sort", type: "string", optional: true, "default": "popularity" }, // can be "popularity", "tag", "date" + { name: "reverse_sort", type: "boolean", optional: true, "default": 0 }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // + // NEWS SEARCH + // + + // http://developer.yahoo.com/search/news/V1/newsSearch.html + newsSearch: { + target: "http://search.yahooapis.com/NewsSearchService/V1/newsSearch", + parameters: [ + { name: "query", type: "string", optional: false, "default": "" }, + { name: "type", type: "string", optional: true, "default": "any" }, // can be "all", "any", "phrase" + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 }, + { name: "sort", type: "string", optional: true, "default": "rank" }, // can be "rank", "date" + { name: "language", type: "string", optional: true, "default": null }, + { name: "site", type: "string", optional: true, "default": null } + ] + }, + + // + // SHOPPING + // + + // http://developer.yahoo.com/shopping/V2/catalogListing.html + catalogListing: { + target: "http://shopping.yahooapis.com/ShoppingService/V2/catalogListing", + parameters: [ + { name: "catalogid", type: "integer", optional: true, "default": null }, // required if idtype,idvalue are not specified + { name: "getlisting", type: "boolean", optional: true, "default": 1 }, + { name: "getreview", type: "boolean", optional: true, "default": 0 }, + { name: "getspec", type: "boolean", optional: true, "default": 0 }, + { name: "idtype", type: "string", optional: true, "default": null }, // can be "upc", "brand,model", "brand,partnum"; required if catalogid is not specified + { name: "idvalue", type: "string", optional: true, "default": null }, // required if catalogid is not specified + { name: "onlynew", type: "boolean", optional: true, "default": 1 }, + { name: "reviewstart", type: "integer", optional: true, "default": 1 }, + { name: "reviewsort", type: "string", optional: true, "default": "mostRecommended_descending" }, // can be "mostRecommended_descending", "mostRecommended_ascending", "latest_descending", "latest_ascending", "highestRated_descending", "highestRated_ascending" + { name: "zip", type: "string", optional: true, "default": null } + ] + }, + + + // http://developer.yahoo.com/shopping/V1/merchantSearch.html + merchantSearch: { + target: "http://api.shopping.yahoo.com/ShoppingService/V1/merchantSearch", + parameters: [ + { name: "merchantid", type: "integer", optional: false, "default": null } + ] + }, + + + // http://developer.yahoo.com/shopping/V3/productSearch.html + productSearch: { + target: "http://shopping.yahooapis.com/ShoppingService/V3/productSearch", + parameters: [ + { name: "query", type: "string", optional: true, "default": "" }, // required if category is not specified + { name: "category", type: "any", optional: true, "default": "" }, // required if query is not specified + { name: "class", type: "string", optional: true, "default": null }, // can be "catalogs", "freeoffers", "paidoffers"; defaults to all three of these + { name: "department", type: "integer", optional: true, "default": null }, + { name: "highestprice", type: "float", optional: true, "default": null }, + { name: "lowestprice", type: "float", optional: true, "default": null }, + { name: "merchantId", type: "integer", optional: true, "default": null }, + { name: "refinement", type: "string", optional: true, "default": null }, // used only if category is specified + { name: "results", type: "integer", optional: true, "default": 10 }, // 1-50 + { name: "show_numratings", type: "boolean", optional: true, "default": 0 }, + { name: "show_narrowing", type: "boolean", optional: true, "default": 1 }, + { name: "sort", type: "string", optional: true }, // can be "price_ascending", "price_descending", "userrating_ascending", "userrating_descending"; omitted, the default is to sort by relevance + { name: "start", type: "integer", optional: true, "default": 1 } // 1-300 + ] + }, + + // + // SITE EXPLORER + // + + // http://developer.yahoo.com/search/siteexplorer/V1/inlinkData.html + inlinkData: { + target: "http://search.yahooapis.com/SiteExplorerService/V1/inlinkData", + parameters: [ + { name: "query", type: "string", optional: false, "default": "" }, + { name: "results", type: "integer", optional: true, "default": 50 }, // max 100 + { name: "start", type: "integer", optional: true, "default": 1 }, + { name: "entire_site", type: "boolean", optional: true, "default": null }, + { name: "omit_inlinks", type: "string", optional: true, "default": "none" } // can be "none", "domain", "subdomain" + ] + }, + + // http://developer.yahoo.com/search/siteexplorer/V1/pageData.html + pageData: { + target: "http://search.yahooapis.com/SiteExplorerService/V1/pageData", + parameters: [ + { name: "query", type: "string", optional: false, "default": "" }, + { name: "results", type: "integer", optional: true, "default": 50 }, // max 100 + { name: "start", type: "integer", optional: true, "default": 1 }, + { name: "domain_only", type: "boolean", optional: true, "default": null } + ] + }, + + // http://developer.yahoo.com/search/siteexplorer/V1/ping.html + ping: { + target: "http://search.yahooapis.com/SiteExplorerService/V1/ping", + parameters: [ + { name: "sitemap", type: "string", optional: false, "default": "" } + ] + }, + + // http://developer.yahoo.com/search/siteexplorer/V1/updateNotification.html + updateNotification: { + target: "http://search.yahooapis.com/SiteExplorerService/V1/updateNotification", + parameters: [ + { name: "url", type: "string", optional: false, "default": "" } + ] + }, + + // + // TRAFFIC + // + + // http://developer.yahoo.com/traffic/rest/V1/index.html + trafficData: { + target: "http://local.yahooapis.com/MapsService/V1/trafficData", + parameters: [ + { name: "street", type: "string", optional: true, "default": "" }, + { name: "city", type: "string", optional: true, "default": "" }, + { name: "state", type: "string", optional: true, "default": null }, // full name or two-letter abbreviation + { name: "zip", type: "any", optional: true, "default": null }, // ddddd or ddddd-dddd format + { name: "location", type: "string", optional: true, "default": null }, // free text, supersedes the street, city, state, zip fields + { name: "latitude", type: "float", optional: true }, // -90 to 90 + { name: "longitude", type: "float", optional: true }, // -180 to 180 + { name: "severity", type: "integer", optional: true, "default": 1 }, // can be 1-5 + { name: "zoom", type: "integer", optional: true, "default": 6 }, // can be 1-12 + { name: "radius", type: "float", optional: true }, // in miles, default varies with location; ignored if zoom is specified + { name: "include_map", type: "boolean", optional: true, "default": 0 }, + { name: "image_type", type: "string", optional: true, "default": "png" }, // can be "png" or "gif" + { name: "image_height", type: "integer", optional: true, "default": 500 }, // in pixels, can be 10-2000 + { name: "image_width", type: "integer", optional: true, "default": 620 } // in pixels, can be 10-2000 + ] + }, + + // + // TRAVEL + // + + // http://developer.yahoo.com/travel/tripservice/V1.1/tripSearch.html + tripSearch: { + target: "http://travel.yahooapis.com/TripService/V1.1/tripSearch", + parameters: [ + { name: "query", type: "string", optional: true, "default": "" }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/travel/tripservice/V1.1/getTrip.html + getTrip: { + target: "http://travel.yahooapis.com/TripService/V1.1/getTrip", + parameters: [ + { name: "id", type: "integer", optional: false, "default": null } + ] + }, + + // + // UTILITY SERVICES + // + + // http://developer.yahoo.com/util/timeservice/V1/getTime.html + /* RGG: commented out because it refuses to return JSON format even when you tell it + to do so (it returns a + + + + + + + + + +

                  + + DEMO: JsonRestStore Search + +

                  + +
                  + +

                  + + Description: + +

                  + +

                  + + This simple demo shows how JsonRestStore can be used with Persevere. + +

                  + +

                  + +

                  + + + +
                  + + + + + + + + + + + + + + + + + +
                  + + + +
                  + +
                  + + + + + diff --git a/includes/js/dojox/rpc/demos/demo_JsonRestStore_Persevere.html b/includes/js/dojox/rpc/demos/demo_JsonRestStore_Persevere.html new file mode 100644 index 0000000..40c6bac --- /dev/null +++ b/includes/js/dojox/rpc/demos/demo_JsonRestStore_Persevere.html @@ -0,0 +1,65 @@ + + + + Demo of JsonRestStore + + + + + + + +

                  + DEMO: JsonRestStore Search +

                  +
                  +

                  + Description: +

                  +

                  + This simple demo shows how JsonRestStore can be used with Persevere. +

                  +

                  +

                  + +
                  + + + + + + + + +
                  + +
                  +
                  + + diff --git a/includes/js/dojox/rpc/demos/documentation.html b/includes/js/dojox/rpc/demos/documentation.html new file mode 100644 index 0000000..4c28103 --- /dev/null +++ b/includes/js/dojox/rpc/demos/documentation.html @@ -0,0 +1,33 @@ + + + + + + +
                  + + \ No newline at end of file diff --git a/includes/js/dojox/rpc/demos/templates/documentation.html b/includes/js/dojox/rpc/demos/templates/documentation.html new file mode 100644 index 0000000..d14cf16 --- /dev/null +++ b/includes/js/dojox/rpc/demos/templates/documentation.html @@ -0,0 +1,8 @@ +
                  + +
                    + {% for result in results %} +
                  • {% if result.type %}{{ result.type }} {% endif %}{% ifequal result.type "Function" %}{% if not result.resources %}function {% endif %}{% endifequal %}{{ result.name }}{% ifequal result.type "Function" %}{% if not result.resources %}({% for parameter in result.parameters %}{% if not forloop.first %}, {% endif %}{% if parameter.types %}{% for type in parameter.types %}{% if not forloop.first %}|{% endif %}{{ type.title }}{% endfor %}{% if parameter.optional %}?{% endif %}{% if parameter.repeating %}...{% endif %} {% endif %}{{ parameter.name }}{% endfor %}{% endif %}{% endifequal %}{% ifequal result.type "Function" %}{% if not result.resources %}){% endif %}{% endifequal %}
                  • + {% endfor %} +
                  +
                  \ No newline at end of file diff --git a/includes/js/dojox/rpc/demos/templates/yahoo.html b/includes/js/dojox/rpc/demos/templates/yahoo.html new file mode 100644 index 0000000..04339d2 --- /dev/null +++ b/includes/js/dojox/rpc/demos/templates/yahoo.html @@ -0,0 +1,31 @@ +
                  + +
                    + {% for result in results.Result %} +
                  • {{ result.Title }}
                    {{ result.Summary }}
                  • + {% endfor %} +
                  + + {% if results.firstResultPosition %} + + + + + {% endif %}{% if results.totalResultsAvailable %} + + + + + {% endif %}{% if results.totalResultsReturned %} + + + + + {% endif %}{% if results.type %} + + + + + {% endif %} +
                  First Result{{ results.firstResultPosition }}
                  Total Results Available{{ results.totalResultsAvailable }}
                  Results Returned{{ results.totalResultsReturned }}
                  Type{{ results.type }}
                  +
                  diff --git a/includes/js/dojox/rpc/demos/yahoo.html b/includes/js/dojox/rpc/demos/yahoo.html new file mode 100644 index 0000000..39cee00 --- /dev/null +++ b/includes/js/dojox/rpc/demos/yahoo.html @@ -0,0 +1,39 @@ + + + + Yahoo Search Demo + + + + + +

                  Yahoo Web Search

                  +
                  + + diff --git a/includes/js/dojox/rpc/documentation.smd b/includes/js/dojox/rpc/documentation.smd new file mode 100644 index 0000000..3ff1623 --- /dev/null +++ b/includes/js/dojox/rpc/documentation.smd @@ -0,0 +1,30 @@ +{ + envelope: "URL", + transport: "JSONP", + callbackParamName: "callback", + services: { + get: { + target: "http://redesign.dojotoolkit.org/jsdoc/jsonp", + parameters: [ + { name: "name", type: "string", optional: false }, + { name: "exact", type: "boolean", optional: true }, + { name: "recursion", type: "boolean", optional: true }, + { name: "resource", type: "string", optional: true }, + { name: "project", type: "string", optional: true }, + { name: "version", type: "string", optional: true }, + { name: "attributes", type: "array", optional: true } + ] + }, + batch: { + target: "http://redesign.dojotoolkit.org/jsdoc/jsonp/batch", + parameters: [ + { name: "names", type: "array", optional: false }, + { name: "exact", type: "boolean", optional: true }, + { name: "recursion", type: "boolean", optional: true }, + { name: "project", type: "string", optional: true }, + { name: "version", type: "string", optional: true }, + { name: "attributes", type: "array", optional: false } + ] + } + } +} \ No newline at end of file diff --git a/includes/js/dojox/rpc/test.txt b/includes/js/dojox/rpc/test.txt new file mode 100644 index 0000000..e69de29 diff --git a/includes/js/dojox/rpc/tests/JsonReferencing.js b/includes/js/dojox/rpc/tests/JsonReferencing.js new file mode 100644 index 0000000..69a6782 --- /dev/null +++ b/includes/js/dojox/rpc/tests/JsonReferencing.js @@ -0,0 +1,30 @@ +if(!dojo._hasResource["dojox.rpc.tests.JsonReferencing"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.tests.JsonReferencing"] = true; +dojo.provide("dojox.rpc.tests.JsonReferencing"); +dojo.require("dojox.rpc.JsonReferencing"); + + +doh.register("dojox.rpc.tests.JsonReferencing", [ + function fromRefJson(t) { + var testStr = '{a:{$ref:"$"},id:"root",c:{d:"e",f:{$ref:"root.c"}},b:{$ref:"$.c"}}'; + + var mirrorObj = dojox.rpc.fromJson(testStr); + t.assertEqual(mirrorObj, mirrorObj.a); + t.assertEqual(mirrorObj.c, mirrorObj.c.f); + t.assertEqual(mirrorObj.c, mirrorObj.b); + }, + function toAndFromRefJson(t) { + var testObj = {a:{},b:{c:{}}}; + testObj.a.d= testObj; + testObj.b.g=testObj.a; + testObj.b.c.f = testObj.b; + testObj.b.h=testObj.a; + var mirrorObj = dojox.rpc.fromJson(dojox.rpc.toJson(testObj)); + t.assertEqual(mirrorObj.a.d, mirrorObj); + t.assertEqual(mirrorObj.b.g, mirrorObj.a); + t.assertEqual(mirrorObj.b.c.f, mirrorObj.b); + t.assertEqual(mirrorObj.b.h, mirrorObj.a); + } +]); + +} diff --git a/includes/js/dojox/rpc/tests/Service.js b/includes/js/dojox/rpc/tests/Service.js new file mode 100644 index 0000000..353519e --- /dev/null +++ b/includes/js/dojox/rpc/tests/Service.js @@ -0,0 +1,702 @@ +if(!dojo._hasResource["dojox.rpc.tests.Service"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.tests.Service"] = true; +dojo.provide("dojox.rpc.tests.Service"); +dojo.require("dojo.io.script"); +dojo.require("dojox.rpc.Service"); +dojo.require("dojox.rpc.JsonRPC"); +dojo.require("dojox.rpc.Rest"); +//this is a copy of our smd in js form, so we can just share it easily +//dojo.require("dojox.rpc.tests.resources.testSmd"); + + +dojox.rpc.tests.service = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd")); + +doh.register("dojox.rpc.tests.echo", + [ + { + name: "#1 POST,URL,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + //test when given named params + var td = this.svc.postEcho({message: this.name,foo:2}); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#2 POST,URL,Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postEcho(this.name,2); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#3 GET,URL,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.getEcho({message: this.name}); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + + { + name: "#3.1 REST PUT,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + res = this.name + Math.random(); + //test when given named params + var td = this.svc.restStore.put({location: "res"},res); + td.addCallback(this, function(result){ + var td = this.svc.restStore({location: "res"}); + td.addCallback(this, function(result){ + if (result==res){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + }); + + return d; + } + }, + { + name: "#3.2 REST POST,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + var newRes = this.name + Math.random(); + res += newRes; + //test when given named params + var td = this.svc.restStore.post({location: "res"},newRes); + td.addCallback(this, function(result){ + var td = this.svc.restStore({location: "res"}); + td.addCallback(this, function(result){ + if (result==res){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + }); + + return d; + } + }, + { + name: "#3.3 REST DELETE,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.restStore['delete']({location: "res"}); + td.addCallback(this, function(result){ + var td = this.svc.restStore({location: "res"}); + td.addCallback(this, function(result){ + if (result=="deleted"){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + }); + + return d; + } + }, + { + name: "#3.4 GET,URL,Named Parameters, Returning Json", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.getEchoJson({message:'{"foo":"bar"}'}); + td.addCallback(this, function(result){ + if (result.foo=='bar'){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#3.5 GET,PATH,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.getPathEcho({path: "pathname"}); + td.addCallback(this, function(result){ + if (result=="/path/pathname"){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + + { + name: "#4 GET,URL,Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.getEcho(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + + { + name: "#5 POST,URL,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonEcho({message: this.name}); + td.addCallback(this, function(res){ + var result = dojo.fromJson(res); + if (result && result.message && result.message==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + + { + name: "#6 POST,JSON,Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonEcho(this.name); + td.addCallback(this, function(res){ + var result = dojo.fromJson(res); + if (result && result.message && result.message==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#7 JSONP,URL,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.jsonpEcho({message: this.name}); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#8 JSONP,URL, Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.jsonpEcho(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#9 POST,JSON-RPC-1.0,Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc10Echo(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#10 POST,JSON-RPC-1.0,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc10EchoNamed(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#11 POST,JSON-RPC 1.2, Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc12Echo(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#12 POST,JSON-RPC 1.2, Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc12Echo({message: this.name}); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + } + /* + ,{ + name: "#13 GET,JSON-RPC 1.2, Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.getJsonRpc12Echo(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#14 GET,JSON-RPC 1.2, Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.getJsonRpc12EchoNamed({message: this.name}); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + ,{ + name: "#15 JSONP,JSON-RPC 1.2, Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.jsonpJsonRpc12Echo(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + } + */ + ] +); + +doh.register("dojox.rpc.tests.jsonRpcForcedError", [ + { + name: "POST,JSON-RPC 1.0, Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc10ForcedError(this.name); + + td.addErrback(this, function(error){ + d.callback(true); + }); + + return d; + } + }, + { + name: "POST,JSON-RPC 1.2, Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc12ForcedError(this.name); + + td.addErrback(this, function(error){ + d.callback(true); + }); + + return d; + } + }, + { + name: "POST,JSON-RPC 1.2, Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc12ForcedError({message: this.name}); + + td.addErrback(this, function(error){ + d.callback(true); + }); + + return d; + } + } +]); + +} diff --git a/includes/js/dojox/rpc/tests/Yahoo.js b/includes/js/dojox/rpc/tests/Yahoo.js new file mode 100644 index 0000000..7e5dbfa --- /dev/null +++ b/includes/js/dojox/rpc/tests/Yahoo.js @@ -0,0 +1,317 @@ +if(!dojo._hasResource["dojox.rpc.tests.Yahoo"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.tests.Yahoo"] = true; +dojo.provide("dojox.rpc.tests.Yahoo"); +dojo.require("dojo.io.script"); +dojo.require("dojox.rpc.Service"); + +dojox.rpc.tests.yahooService = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.SMDLibrary", "yahoo.smd")); + +dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT = 8000; +dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT = 30000; + +dojox.rpc.tests.yahooService._testMethod = function(method){ + return function(m){ + var d = new doh.Deferred(); + + if (method.name && method.parameters && method.expectedResult) { + var yd = dojox.rpc.tests.yahooService[method.name](method.parameters); + yd.addCallback(this, function(result){ + if (result[method.expectedResult]){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + } + + return d; + } +}; + +doh.register("dojox.rpc.tests.yahoo", + [ + { + name: "#1, Yahoo Answers::questionSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "questionSearch", + parameters: {query: "dojo toolkit"}, + expectedResult: "all" + }) + }, + { + name: "#2, Yahoo Answers::getByCategory", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "getByCategory", + parameters: {category_name: "Computers+%26+Internet%3ESoftware"}, + expectedResult: "all" + }) + }, + { + name: "#3, Yahoo Answers::getQuestion", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "getQuestion", + parameters: {question_id: "1005120800412"}, + expectedResult: "all" + }) + }, + { + name: "#4, Yahoo Answers::getByUser", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "getByUser", + parameters: {user_id: "AA10001397"}, + expectedResult: "all" + }) + }, + { + name: "#5, Yahoo Audio::artistSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "artistSearch", + parameters: {artist: "The Beatles"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#6, Yahoo Audio::albumSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "albumSearch", + parameters: {artist: "The Beatles", album: "Magical Mystery Tour"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#7, Yahoo Audio::songSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "songSearch", + parameters: {artist: "The Beatles", album: "Magical Mystery Tour", song: "Penny Lane"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#8, Yahoo Audio::songDownloadLocation", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "songDownloadLocation", + parameters: {songid: "XXXXXXT000995691"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#9, Yahoo ContentAnalysis::contextSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "contextSearch", + parameters: { + context: "Welcome to the Book of Dojo. This book covers both versions 0.9 and 1.0, and all 1.0 extensions and changes are clearly marked for your enjoyment. Please use the forums for support questions, but if you see something missing, incomplete, or just plain wrong in this book, please leave a comment.", + query: "dojo" + }, + expectedResult: "ResultSet" + }) + }, + { + name: "#10, Yahoo Image::imageSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "imageSearch", + parameters: {query: "dojo"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#11, Yahoo Local::localSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "localSearch", + parameters: {query: "pizza", zip: "98201"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#12, Yahoo Local::collectionSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "collectionSearch", + parameters: {query: "dojo"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#13, Yahoo Local::getCollection", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + expectedResult: "getCollection", + parameters: {collection_id: "1000031487"}, + expectedResult: "Result" + }) + }, + { + name: "#14, Yahoo Local::trafficData", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "trafficData", + parameters: {street: "1600 Pennsylvania Ave", city: "Washington, DC"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#15, Yahoo MyWebs::urlSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "urlSearch", + parameters: {tag: "javascript"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#16, Yahoo MyWebs::tagSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "tagSearch", + parameters: {url: "dojotoolkit.org"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#17, Yahoo MyWebs::relatedTags", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "relatedTags", + parameters: {tag: "javascript"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#18, Yahoo NewsSearch::newsSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "newsSearch", + parameters: {query: "dojo toolkit"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#19, Yahoo Shopping::catalogListing", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "catalogListing", + parameters: {idtype: "brand,partnum", idvalue: "canon,1079B001", getspec: 1}, + expectedResult: "Catalog" + }) + }, + { + name: "#20, Yahoo Shopping::merchantSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "merchantSearch", + parameters: {merchantid: "1021849"}, + expectedResult: "Merchant" + }) + }, + { + name: "#21, Yahoo Shopping::productSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "productSearch", + parameters: {query: "dojo"}, + expectedResult: "Categories" + }) + }, + { + name: "#22, Yahoo SiteExplorer::inlinkData", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "inlinkData", + parameters: {query: "dojotoolkit.org"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#23, Yahoo SiteExplorer::pageData", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "pageData", + parameters: {query: "dojotoolkit.org"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#24, Yahoo SiteExplorer::ping", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "ping", + parameters: {sitemap: "http://www.yahoo.com"}, + expectedResult: "Success" + }) + }, + { + name: "#25, Yahoo SiteExplorer::updateNotification", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "updateNotification", + parameters: {url: "http://www.yahoo.com"}, + expectedResult: "Success" + }) + }, + { + name: "#26, Yahoo Trip::tripSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "tripSearch", + parameters: {query: "eiffel tower"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#27, Yahoo Trip::getTrip", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "getTrip", + parameters: {id: "546303"}, + expectedResult: "Result" + }) + }, + { + name: "#28, Yahoo Video::videoSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "videoSearch", + parameters: {query: "star wars kid"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#29, Yahoo Web::webSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "webSearch", + parameters: {query: "dojo toolkit"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#30, Yahoo Web::spellingSuggestion", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "spellingSuggestion", + parameters: {query: "beatls"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#31, Yahoo Web::relatedSuggestion", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "relatedSuggestion", + parameters: {query: "dojo toolkit"}, + expectedResult: "ResultSet" + }) + } +]); + +} diff --git a/includes/js/dojox/rpc/tests/libraryTests.js b/includes/js/dojox/rpc/tests/libraryTests.js new file mode 100644 index 0000000..7af2ae6 --- /dev/null +++ b/includes/js/dojox/rpc/tests/libraryTests.js @@ -0,0 +1,12 @@ +if(!dojo._hasResource["dojox.rpc.tests.libraryTests"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.tests.libraryTests"] = true; +dojo.provide("dojox.rpc.tests.libraryTests"); + +try{ + dojo.require("dojox.rpc.tests.Yahoo"); +}catch(e){ + doh.debug(e); +} + + +} diff --git a/includes/js/dojox/rpc/tests/module.js b/includes/js/dojox/rpc/tests/module.js new file mode 100644 index 0000000..038a9ad --- /dev/null +++ b/includes/js/dojox/rpc/tests/module.js @@ -0,0 +1,13 @@ +if(!dojo._hasResource["dojox.rpc.tests.module"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.tests.module"] = true; +dojo.provide("dojox.rpc.tests.module"); + +try{ + dojo.require("dojox.rpc.tests.Service"); + dojo.require("dojox.rpc.tests.JsonReferencing"); +}catch(e){ + doh.debug(e); +} + + +} diff --git a/includes/js/dojox/rpc/tests/resources/JSON.php b/includes/js/dojox/rpc/tests/resources/JSON.php new file mode 100644 index 0000000..4a21ce7 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/JSON.php @@ -0,0 +1,724 @@ + + * @author Matt Knapp + * @author Brett Stimmerman + * @copyright 2005 Michal Migurski + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_SLICE', 1); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_STR', 2); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_ARR', 4); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_OBJ', 8); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_CMT', 16); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_LOOSE_TYPE', 10); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_STRICT_TYPE', 11); + +/** + * Converts to and from JSON format. + * + * Brief example of use: + * + * + * // create a new instance of Services_JSON + * $json = new Services_JSON(); + * + * // convert a complexe value to JSON notation, and send it to the browser + * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); + * $output = $json->encode($value); + * + * print($output); + * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] + * + * // accept incoming POST data, assumed to be in JSON notation + * $input = file_get_contents('php://input', 1000000); + * $value = $json->decode($input); + * + */ +class Services_JSON +{ + /** + * constructs a new JSON instance + * + * @param int $use object behavior: when encoding or decoding, + * be loose or strict about object/array usage + * + * possible values: + * - SERVICES_JSON_STRICT_TYPE: strict typing, default. + * "{...}" syntax creates objects in decode(). + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays in decode(). + */ + function Services_JSON($use = SERVICES_JSON_STRICT_TYPE) + { + $this->use = $use; + } + + /** + * convert a string from one UTF-16 char to one UTF-8 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch(true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + function utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $ut8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return string JSON string representation of input var + * @access public + */ + function encode($var) + { + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + return '{' . + join(',', array_map(array($this, 'name_value'), + array_keys($var), + array_values($var))) + . '}'; + } + + // treat it like a regular array + return '[' . join(',', array_map(array($this, 'encode'), $var)) . ']'; + + case 'object': + $vars = get_object_vars($var); + return '{' . + join(',', array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars))) + . '}'; + + default: + return ''; + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + function name_value($name, $value) + { + return $this->encode(strval($name)) . ':' . $this->encode($value); + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) + . chr(hexdec(substr($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + + if ($str{0} == '[') { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, + 'where' => 0, + 'delim' => false)); + + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } + + } + + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + } elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == SERVICES_JSON_IN_STR) && + (($chrs{$c - 1} != '\\') || + ($chrs{$c - 1} == '\\' && $chrs{$c - 2} == '\\'))) { + // found a quote, we're in a string, and it's not escaped + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); + + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + return $obj; + + } + + } + } + } + +} + +?> \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/bigQuery b/includes/js/dojox/rpc/tests/resources/bigQuery new file mode 100644 index 0000000..e8f9429 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/bigQuery @@ -0,0 +1 @@ +[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20] \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/bigQuery5 b/includes/js/dojox/rpc/tests/resources/bigQuery5 new file mode 100644 index 0000000..e77ca8d --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/bigQuery5 @@ -0,0 +1 @@ +[1,2,3,4,5] \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/echo.php b/includes/js/dojox/rpc/tests/resources/echo.php new file mode 100644 index 0000000..b38a3ee --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/echo.php @@ -0,0 +1,7 @@ + diff --git a/includes/js/dojox/rpc/tests/resources/echoJson.php b/includes/js/dojox/rpc/tests/resources/echoJson.php new file mode 100644 index 0000000..52b5d03 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/echoJson.php @@ -0,0 +1,8 @@ + diff --git a/includes/js/dojox/rpc/tests/resources/fakestore.php b/includes/js/dojox/rpc/tests/resources/fakestore.php new file mode 100644 index 0000000..075926a --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/fakestore.php @@ -0,0 +1,36 @@ + diff --git a/includes/js/dojox/rpc/tests/resources/jsonRpc10.php b/includes/js/dojox/rpc/tests/resources/jsonRpc10.php new file mode 100644 index 0000000..fc99b75 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonRpc10.php @@ -0,0 +1,47 @@ + sudo pear install File + // Your server will also need the Pear library directory included in PHP's + // include_path configuration directive + // require_once('File.php'); + + // ensure that we don't try to send "html" down to the client + header("Content-Type: text/plain"); + + $json = new Services_JSON; + //$fp = new File(); + + $results = array(); + $results['error'] = null; + + $jsonRequest = file_get_contents('php://input'); + //$jsonRequest = '{"params":["Blah"],"method":"myecho","id":86}'; + + $req = $json->decode($jsonRequest); + + $method = $req->method; + $params = $req->params; + + switch($method) { + case "postJsonRpc10EchoNamed": + case "postJsonRpc10Echo": + $results['result']=$params[0]; + break; + default: + $results['result']=""; + $results['error']="JSON-RPC 1.0 METHOD NOT FOUND"; + break; + } + + $results['id'] = $req->id; + + $encoded = $json->encode($results); + + print $encoded; +?> diff --git a/includes/js/dojox/rpc/tests/resources/jsonRpc11.php b/includes/js/dojox/rpc/tests/resources/jsonRpc11.php new file mode 100644 index 0000000..1c91e51 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonRpc11.php @@ -0,0 +1,52 @@ + sudo pear install File + // Your server will also need the Pear library directory included in PHP's + // include_path configuration directive + // require_once('File.php'); + + // ensure that we don't try to send "html" down to the client + header("Content-Type: text/plain"); + + $json = new Services_JSON; + //$fp = new File(); + + $results = array(); + $results['error'] = null; + + $jsonRequest = file_get_contents('php://input'); + //$jsonRequest = '{"params":["Blah"],"method":"myecho","id":86}'; + + $req = $json->decode($jsonRequest); + + $method = $req->method; + $params = $req->params; + + switch($method) { + case "rawPostJsonRpc11Echo": + if (is_array($params)){ + $results['result']=$params; + }else{ + $results['result']=$params->message; + } + break; + default: + $results['result']=""; + $results['error']=array(); + $results['error']['code']=-32601; + $results['error']["message"]="The requested remote-procedure does not exist / is not available."; + break; + } + + $results['id'] = $req->id; + + $encoded = $json->encode($results); + + print $encoded; +?> diff --git a/includes/js/dojox/rpc/tests/resources/jsonRpc12.php b/includes/js/dojox/rpc/tests/resources/jsonRpc12.php new file mode 100644 index 0000000..8fad2e5 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonRpc12.php @@ -0,0 +1,53 @@ + sudo pear install File + // Your server will also need the Pear library directory included in PHP's + // include_path configuration directive + // require_once('File.php'); + + // ensure that we don't try to send "html" down to the client + header("Content-Type: text/plain"); + + $json = new Services_JSON; + //$fp = new File(); + + $results = array(); + $results['error'] = null; + + $jsonRequest = file_get_contents('php://input'); + //$jsonRequest = '{"params":["Blah"],"method":"myecho","id":86}'; + + $req = $json->decode($jsonRequest); + + $method = $req->method; + $params = $req->params; + + switch($method) { + case "postJsonRpc12Echo": + case "postJsonRpc12EchoNamed": + if (is_array($params)){ + $results['result']=$params; + }else{ + $results['result']=$params->message; + } + break; + default: + $results['result']=""; + $results['error']=array(); + $results['error']['code']=-32601; + $results['error']["message"]="The requested remote-procedure does not exist / is not available."; + break; + } + + $results['id'] = $req->id; + + $encoded = $json->encode($results); + + print $encoded; +?> diff --git a/includes/js/dojox/rpc/tests/resources/jsonRpcPostGetEcho.php b/includes/js/dojox/rpc/tests/resources/jsonRpcPostGetEcho.php new file mode 100644 index 0000000..7db9153 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonRpcPostGetEcho.php @@ -0,0 +1,38 @@ +decode($params); + $result = "{id:" . $id . ", 'result':'" . $p[0]. "', error:''}"; + break; + case "postJsonRpc12Echo": + case "getJsonRpc12Echo": + case "postJsonRpc12EchoNamed": + case "getJsonRpc12EchoNamed": + $p = $json->decode($params); + + if ($p->message){ + $d = $p->message; + }else{ + $d=$p[0]; + } + $result = "{id:" . $id . ", 'result':'" . $d . "'}"; + break; + default: + $result = "{id:'1','error':'Unknown Method', 'result':'this result only here for this test, shouldnt be here in real code'}"; + break; + } + + print $result; + +?> diff --git a/includes/js/dojox/rpc/tests/resources/jsonpEcho.php b/includes/js/dojox/rpc/tests/resources/jsonpEcho.php new file mode 100644 index 0000000..15d9aaa --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonpEcho.php @@ -0,0 +1,23 @@ + diff --git a/includes/js/dojox/rpc/tests/resources/jsonpEcho.phps b/includes/js/dojox/rpc/tests/resources/jsonpEcho.phps new file mode 100644 index 0000000..15d9aaa --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonpEcho.phps @@ -0,0 +1,23 @@ + diff --git a/includes/js/dojox/rpc/tests/resources/jsonpJsonRpcEcho.php b/includes/js/dojox/rpc/tests/resources/jsonpJsonRpcEcho.php new file mode 100644 index 0000000..251f38e --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonpJsonRpcEcho.php @@ -0,0 +1,37 @@ +decode($_REQUEST['params']); + $callback = $_REQUEST["callback"]; + + switch($method){ + case "jsonpJsonRpc10EchoNamed": + case "jsonpJsonRpc11Echo": + case "jsonpJsonRpc11EchoNamed": + case "jsonpJsonRpc10Echo": + if ( ($method=="jsonpJsonRpc10EchoNamed")||($method=="jsonpJsonRpc11EchoNamed")){ + $message = $params->message; + }else{ + $message = $params[0]; + } + if ($message){ + switch($method){ + case "jsonpJsonRpc11Echo": + case "jsonpJsonRpc11EchoNamed": + $res = "{'id': '$id', result: '$message'}"; + break; + default: + $res = "{'id': '$id', result: '$message', 'error':''}"; + break; + } + }else{ + $res = "{'id': '$id', error: {'code': 100, 'message':'no message provided'}}"; + } + } + + print "$callback($res)"; + +?> diff --git a/includes/js/dojox/rpc/tests/resources/obj1 b/includes/js/dojox/rpc/tests/resources/obj1 new file mode 100644 index 0000000..ff02ba8 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/obj1 @@ -0,0 +1 @@ +{"id":"obj1","name":"Object 1","updated":1202755814406,"obj":{"foo":"bar"},"obj dup":{"$ref":"obj1.obj"},"testArray":[1,2,3,4]} \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/obj1testArray b/includes/js/dojox/rpc/tests/resources/obj1testArray new file mode 100644 index 0000000..0c624c1 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/obj1testArray @@ -0,0 +1 @@ +[1,2,3,undefined,4] \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/obj3 b/includes/js/dojox/rpc/tests/resources/obj3 new file mode 100644 index 0000000..21cb328 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/obj3 @@ -0,0 +1 @@ +{"id":"obj3","name":"Object 3"} \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/obj4 b/includes/js/dojox/rpc/tests/resources/obj4 new file mode 100644 index 0000000..a429ecf --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/obj4 @@ -0,0 +1 @@ +{"id":"obj4","name":"Object 4"} \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/query b/includes/js/dojox/rpc/tests/resources/query new file mode 100644 index 0000000..cd18d6e --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/query @@ -0,0 +1,6 @@ +[ + {id:"obj1",name:"Object 1"}, + {id:"obj2",name:"Object 2"}, + {$ref:"obj3"}, + {$ref:"obj4"} +] \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/rawEcho.php b/includes/js/dojox/rpc/tests/resources/rawEcho.php new file mode 100644 index 0000000..e0c15c0 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/rawEcho.php @@ -0,0 +1,5 @@ + + diff --git a/includes/js/dojox/rpc/tests/resources/res b/includes/js/dojox/rpc/tests/resources/res new file mode 100644 index 0000000..3c22137 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/res @@ -0,0 +1 @@ +deleted \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/store.php b/includes/js/dojox/rpc/tests/resources/store.php new file mode 100644 index 0000000..941e113 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/store.php @@ -0,0 +1,24 @@ + diff --git a/includes/js/dojox/rpc/tests/resources/test.smd b/includes/js/dojox/rpc/tests/resources/test.smd new file mode 100644 index 0000000..6ad56be --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/test.smd @@ -0,0 +1,189 @@ +{ + transport: "POST", + envelope: "URL", + strictParameters: false, + parameters: { + appId: {}, + outputType: { + default: "json" + }, + + ignoreErrors: { + optional: true + } + }, + + services: { + postEcho: { + target: "echo.php", + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + + getEcho: { + transport: "GET", + target: "echo.php", + + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + getEchoJson: { + transport: "GET", + target: "echoJson.php", + contentType:"application/json", + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + getPathEcho: { + transport: "GET", + envelope: "PATH", + target: "echo.php?message=", + + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + restStore: { + transport: "REST", + contentType:"text/plain", + target: "fakestore.php", + parameters: [ + {name: "location", type: "string", optional: true} + ] + }, + jsonRestStore: { + transport: "REST", + target: "fakestore.php", + contentType:"application/json", + parameters: [ + {name: "location", type: "string", optional: true} + ] + }, + + + + postJsonEcho: { + transport: "POST", + envelope: "JSON", + target: "rawEcho.php", + + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + + jsonpEcho: { + transport: "JSONP", + target: "jsonpEcho.php", + callbackParamName: "testCallbackParam", + + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + + postJsonRpc10Echo: { + transport: "POST", + envelope: "JSON-RPC-1.0", + target: "jsonRpc10.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + postJsonRpc10EchoNamed: { + transport: "POST", + envelope: "JSON-RPC-1.0", + target: "jsonRpc10.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + jsonpJsonRpc12Echo: { + transport: "JSONP", + envelope: "JSON-RPC-2.0", + target: "jsonpJsonRpcEcho.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + jsonpJsonRpc12EchoNamed: { + transport: "JSONP", + envelope: "JSON-RPC-2.0", + target: "jsonpJsonRpcEcho.php", + + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + + postJsonRpc10ForcedError: { + envelope: "JSON-RPC-1.0", + transport: "POST", + target: "jsonRpc10.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + postJsonRpc12Echo: { + transport: "POST", + envelope: "JSON-RPC-2.0", + target: "jsonRpc12.php", + + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + + getJsonRpc12Echo: { + transport: "GET", + envelope: "JSON-RPC-2.0", + target: "jsonRpcPostGetEcho.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + postJsonRpc12EchoNamed: { + transport: "POST", + envelope: "JSON-RPC-2.0", + target: "jsonRpcPostGetEcho.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + getJsonRpc12EchoNamed: { + transport: "GET", + envelope: "JSON-RPC-2.0", + target: "jsonRpcPostGetEcho.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + + postJsonRpc12ForcedError: { + envelope: "JSON-RPC-2.0", + transport: "POST", + target: "jsonRpc12.php", + + parameters: [ + {type: "string", optional: true} + ] + } + } +} diff --git a/includes/js/dojox/rpc/tests/runLibraryTests.html b/includes/js/dojox/rpc/tests/runLibraryTests.html new file mode 100644 index 0000000..25c88a7 --- /dev/null +++ b/includes/js/dojox/rpc/tests/runLibraryTests.html @@ -0,0 +1,9 @@ + + + + Dojox Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/rpc/tests/runTests.html b/includes/js/dojox/rpc/tests/runTests.html new file mode 100644 index 0000000..bb937c6 --- /dev/null +++ b/includes/js/dojox/rpc/tests/runTests.html @@ -0,0 +1,9 @@ + + + + Dojox Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/rpc/tests/stores/JsonRestStore.js b/includes/js/dojox/rpc/tests/stores/JsonRestStore.js new file mode 100644 index 0000000..25e0fc7 --- /dev/null +++ b/includes/js/dojox/rpc/tests/stores/JsonRestStore.js @@ -0,0 +1,237 @@ +if(!dojo._hasResource["dojox.data.tests.stores.JsonRestStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.stores.JsonRestStore"] = true; +dojo.provide("dojox.data.tests.stores.JsonRestStore"); +dojo.require("dojox.data.JsonRestStore"); +dojo.require("dojo.data.api.Read"); +dojo.require("dojox.rpc.Service"); + +dojox.data.tests.stores.JsonRestStore.error = function(t, d, errData){ + // summary: + // The error callback function to be used for all of the tests. + d.errback(errData); +} +var testServices = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd")); +var jsonStore = new dojox.data.JsonRestStore({service:testServices.jsonRestStore}); + +doh.register("dojox.data.tests.stores.JsonRestStore", + [ + { + name: "Fetch some items", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // Simple test of a basic fetch on JsonRestStore of a simple query. + var d = new doh.Deferred(); + jsonStore.fetch({query:"query", + onComplete: function(items, request){ + t.is(4, items.length); + d.callback(true); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + { + name: "fetch by id", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // Simple test of a basic fetch on JsonRestStore of a single item. + var d = new doh.Deferred(); + jsonStore.fetch({query:"obj1", + onComplete: function(item, request){ + t.is("Object 1", item.name); + t.t(jsonStore.hasAttribute(item,"name")); + t.is(jsonStore.getValues(item,"name").length,1); + t.t(jsonStore.isItem(item)); + d.callback(true); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + { + name: "Modify,save, check by id", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // Fetch an item from a query, modify and save it, and check to see if it was modified correctly + var d = new doh.Deferred(); + jsonStore.fetch({query:"query", + onComplete: function(items, request){ + var now = new Date().getTime(); + jsonStore.setValue(items[0],"updated",now); + jsonStore.setValue(items[0],"obj",{foo:'bar'}); + jsonStore.setValue(items[0],"obj dup",items[0].obj); + jsonStore.setValue(items[0],"testArray",[1,2,3,4]); + jsonStore.save(); + jsonStore.fetch({query:"obj1", + onComplete: function(item, request){ + t.is("Object 1", item.name); + t.is(now, item.updated); + t.is("bar", item.obj.foo); + t.is(item.obj, item['obj dup']); + d.callback(true); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + { + name: "Post, delete, and put", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // append/post an item, delete it, sort the lists, resort the list, saving each time. + var d = new doh.Deferred(); + jsonStore.fetch({query:"obj1", + onComplete: function(item, request){ + var now = new Date().getTime(); + var testArray = item.testArray; + var newObject = {"name":"new object"}; + testArray.push(newObject); + jsonStore.save(); + jsonStore.deleteItem(newObject,{parent:testArray}); + jsonStore.save(); + testArray.sort(function(obj1,obj2) { return obj1 < obj2; }); + jsonStore.save(); + testArray.sort(function(obj1,obj2) { return obj1 > obj2; }); + jsonStore.save(); + d.callback(true); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + { + name: "Revert", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // append/post an item, delete it, sort the lists, resort the list, saving each time. + var d = new doh.Deferred(); + jsonStore.fetch({query:"obj1", + onComplete: function(item, request){ + jsonStore.setValue(item,"name","new name"); + jsonStore.setValue(item,"newProp","new value"); + jsonStore.unsetAttribute(item,"updated"); + t.is(jsonStore.getValue(item,"name"),"new name"); + t.is(jsonStore.getValue(item,"newProp"),"new value"); + t.is(jsonStore.getValue(item,"updated"),undefined); + jsonStore.revert(); + t.is(jsonStore.getValue(item,"name"),"Object 1"); + t.is(jsonStore.getValue(item,"newProp"),undefined); + t.t(typeof jsonStore.getValue(item,"updated") == 'number'); + d.callback(true); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + { + name: "Lazy loading", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // test lazy loading + var d = new doh.Deferred(); + jsonStore.fetch({query:"query", + onComplete: function(items, request){ + /*var item = jsonStore.getValue(items,2); // sync lazy loading + t.is(item.name == 'Object 3');*/ + jsonStore.getValue(items,3,function(item) { // async lazy loading + t.is(item.name,'Object 4'); + d.callback(true); + }); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + { + name: "Array manipulation", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // test array manipulation + var d = new doh.Deferred(); + jsonStore.fetch({query:"obj1", + onComplete: function(item, request){ + var testArray = item.testArray; + testArray.reverse(); + testArray.unshift(testArray.pop()); + jsonStore.onSave = function(data) { + t.is(data.length,1); + d.callback(true); + jsonStore.onSave = function(){}; + }; + jsonStore.save(); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + + { + name: "ReadAPI: Fetch_20_Streaming", + timeout: 10000, //10 seconds. Json can sometimes be slow. + runTest: function(t) { + // summary: + // fetching with paging + + var d = new doh.Deferred(); + var count = 0; + + function onItem(item, requestObj){ + t.assertTrue(typeof item == 'number'); + count++; + } + function onComplete(items, request){ + t.is(5, count); + + t.is(null, items); + d.callback(true); + } + //Get everything... + jsonStore.fetch({ + query: "bigQuery", + onBegin: null, + count: 5, + onItem: onItem, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, t, d) + }); + return d; //Object + } + }, + function testReadAPI_functionConformance(t){ + // summary: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + + var readApi = new dojo.data.api.Read(); + var passed = true; + + for(i in readApi){ + if(i.toString().charAt(0) !== '_') + { + var member = readApi[i]; + //Check that all the 'Read' defined functions exist on the test store. + if(typeof member === "function"){ + var testStoreMember = jsonStore [i]; + if(!(typeof testStoreMember === "function")){ + passed = false; + break; + } + } + } + } + } + ] +); + + +} diff --git a/includes/js/dojox/rpc/tests/test_dojo_data_model_persevere.html b/includes/js/dojox/rpc/tests/test_dojo_data_model_persevere.html new file mode 100644 index 0000000..063dc9b --- /dev/null +++ b/includes/js/dojox/rpc/tests/test_dojo_data_model_persevere.html @@ -0,0 +1,146 @@ + + + + dojox.Grid with Dojo.Data via binding + + + + + + + +
                  dojox.Grid using interactive PersevereRestStore
                  +
                  + + +     + +     + + + +
                  + +
                  +
                  + + diff --git a/includes/js/dojox/sketch.js b/includes/js/dojox/sketch.js new file mode 100644 index 0000000..6da3443 --- /dev/null +++ b/includes/js/dojox/sketch.js @@ -0,0 +1,13 @@ +if(!dojo._hasResource["dojox.sketch"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sketch"] = true; +dojo.provide("dojox.sketch"); +try{ + // fix IE image caching issue + document.execCommand("BackgroundImageCache", false, true); +}catch(e){ } +dojo.require("dojox.xml.DomParser"); +dojo.require("dojox.sketch.UndoStack"); +dojo.require("dojox.sketch.Figure"); +dojo.require("dojox.sketch.Toolbar"); + +} diff --git a/includes/js/dojox/sketch/Anchor.js b/includes/js/dojox/sketch/Anchor.js new file mode 100644 index 0000000..de72ac0 --- /dev/null +++ b/includes/js/dojox/sketch/Anchor.js @@ -0,0 +1,61 @@ +if(!dojo._hasResource["dojox.sketch.Anchor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sketch.Anchor"] = true; +dojo.provide("dojox.sketch.Anchor"); +dojo.require("dojox.gfx"); + +(function(){ + var ta=dojox.sketch; + ta.Anchor=function(an, id, isControl){ + var self=this; + var size=4; // .5 * size of anchor. + var rect=null; + + this.type=function(){ return "Anchor"; }; + this.annotation=an; + + this.id=id; + this._key="anchor-" + ta.Anchor.count++; + this.shape=null; + this.isControl=(isControl!=null)?isControl:true; + + this.beginEdit=function(){ + this.annotation.beginEdit(ta.CommandTypes.Modify); + }; + this.endEdit=function(){ + this.annotation.endEdit(); + }; + this.doChange=function(pt){ + if(this.isControl) this.shape.applyTransform(pt); + else{ + an.transform.dx+=pt.dx; + an.transform.dy+=pt.dy; + } + }; + this.setBinding=function(pt){ + an[id]={ x: an[id].x+pt.dx, y:an[id].y+pt.dy }; + an.draw(); + an.drawBBox(); + }; + this.setUndo=function(){ an.setUndo(); }; + + this.enable=function(){ + if(!an.shape) return; + an.figure._add(this); + rect={ x:an[id].x-size, y:an[id].y-size, width:size*2, height:size*2 }; + this.shape=an.shape.createRect(rect) + .setStroke({ color:"black", width:1 }) + .setFill([255,255,255,0.35]); + this.shape.getEventSource().setAttribute("id", self._key); + this.shape.getEventSource().setAttribute("shape-rendering", "crispEdges"); + }; + this.disable=function(){ + an.figure._remove(this); + if(an.shape) an.shape.remove(this.shape); + this.shape=null; + rect=null; + }; + }; + ta.Anchor.count=0; +})(); + +} diff --git a/includes/js/dojox/sketch/Annotation.js b/includes/js/dojox/sketch/Annotation.js new file mode 100644 index 0000000..ea260ca --- /dev/null +++ b/includes/js/dojox/sketch/Annotation.js @@ -0,0 +1,223 @@ +if(!dojo._hasResource["dojox.sketch.Annotation"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sketch.Annotation"] = true; +dojo.provide("dojox.sketch.Annotation"); +dojo.require("dojox.sketch.Anchor"); +dojo.require("dojox.sketch._Plugin"); + +(function(){ + var ta=dojox.sketch; + dojo.declare("dojox.sketch.AnnotationTool", ta._Plugin, { +// constructor: function(){ +//// console.log('this.shape',this.shape); +//// this.annotation=ta.tools[this.shape]; +// }, + onMouseMove: function(e,rect){ + if(this._cshape){ + this._cshape.setShape(rect); + } else { + this._cshape=this.figure.surface.createRect(rect) + .setStroke({color:"#999", width:1, style:"ShortDot"}) + .setFill([255,255,255,0.7]); + this._cshape.getEventSource().setAttribute("shape-rendering","crispEdges"); + } + }, + onMouseUp: function(e){ + var f=this.figure; + if(!(f._startPoint.x==e.pageX&&f._startPoint.y==e.pageY)){ + if(this._cshape){ + // The minimum number of pixels one has to travel before a shape + // gets drawn. + var limit=40; + if(Math.max( + limit, + Math.abs(f._absEnd.x-f._start.x), + Math.abs(f._absEnd.y-f._start.y) + )>limit){ + this._create(f._start, f._end); + } + } + } + if(this._cshape) f.surface.remove(this._cshape); + }, + _create: function(start,end){ + // create a new shape, needs to be accessible from the + // dragging functions. + var f=this.figure; + var _=f.nextKey(); + var a=new (this.annotation)(f, "annotation-"+_); + a.transform={dx:start.x/f.zoomFactor, dy:start.y/f.zoomFactor}; + a.end={ x:end.x/f.zoomFactor, y:end.y/f.zoomFactor }; + if(a.control){ + a.control={ x:Math.round((end.x/2)/f.zoomFactor),y:Math.round((end.y/2)/f.zoomFactor) }; + } + f.onBeforeCreateShape(a); + a.initialize(); + f.select(a); + f.onCreateShape(a); + f.history.add(ta.CommandTypes.Create,a); + } + }); + ta.Annotation=function(figure, id){ + // for editing stuff. + this.id=this._key=id; + this.figure=figure; + this.mode=ta.Annotation.Modes.View; + this.shape=null; // dojox.gfx.Group + this.boundingBox=null; // rect for boundaries + this.hasAnchors=true; + this.anchors={}; // ta.Anchor + this._properties={ + 'stroke':{ color:"blue", width:2 }, + 'fill': "blue", + 'label': "" + }; + + if(this.figure) this.figure.add(this); + }; + var p=ta.Annotation.prototype; + p.constructor=ta.Annotation; + p.type=function(){ return ''; }; + p.getType=function(){ return ta.Annotation; }; + + p.remove=function(){ + this.figure.history.add(ta.CommandTypes.Delete, this, this.serialize()); + }; + p.property=function(name,/*?*/value){ + var r; + name=name.toLowerCase(); + if(this._properties[name]!==undefined){ + r=this._properties[name]; + } + if(arguments.length>1){ + this._properties[name]=value; + } + if(r!=value){ + this.onPropertyChange(name,r); + } + return r; + }; + p.onPropertyChange=function(name,oldvalue){}; + p.onCreate=function(){ + this.figure.history.add(ta.CommandTypes.Create,this); + } + p.onDblClick=function(event){ + var l=prompt('Set new text:',this.property('label')); + if(l!==false){ + this.beginEdit(ta.CommandTypes.Modify); + this.property('label',l); + this.draw(); + this.endEdit(); + } + } + p.initialize=function(){ }; + p.destroy=function(){ }; + p.draw=function(){ }; + p.apply=function(obj){ }; + p.serialize=function(){ }; + p.getBBox=function(){ }; + p.beginEdit=function(type){ + this._type=type||ta.CommandTypes.Move; + this._prevState=this.serialize(); + }; + p.endEdit=function(){ + var newstep=true; + if(this._type==ta.CommandTypes.Move){ + var f=this.figure; + if(f._absEnd.x==f._start.x&&f._absEnd.y==f._start.y){ + newstep=false; + } + } + if(newstep){ + this.figure.history.add(this._type,this,this._prevState); + } + this._type=this._prevState=''; + }; + p.calculate={ + slope:function(p1, p2){ + if(!(p1.x-p2.x)) return 0; + return ((p1.y-p2.y)/(p1.x-p2.x)); + }, + dx:function(p1, p2, dy){ + var s=this.slope(p1,p2); + if(s==0) return s; + return dy/s; + }, + dy:function(p1, p2, dx){ return this.slope(p1,p2)*dx; } + }; + p.drawBBox=function(){ + var r=this.getBBox(); + if(!this.boundingBox){ + this.boundingBox=this.shape.createRect(r) + .moveToBack() + .setStroke({color:"#999", width:1, style:"Dash"}) + .setFill([238,238,238,0.3]); + this.boundingBox.getEventSource().setAttribute("id",this.id+"-boundingBox"); + this.boundingBox.getEventSource().setAttribute("shape-rendering","crispEdges"); + this.figure._add(this); + } else this.boundingBox.setShape(r); + }; + p.setBinding=function(pt){ + this.transform.dx+=pt.dx; + this.transform.dy+=pt.dy; + this.draw(); + }; + p.doChange=function(pt){ }; + p.getTextBox=function(){ + return dojox.gfx._base._getTextBox(this.property('label'),ta.Annotation.labelFont); + }; + p.setMode=function(m){ + if(this.mode==m) return; + this.mode=m; + var method="disable"; + if(m==ta.Annotation.Modes.Edit) method="enable"; + if(method=="enable"){ + // draw the bounding box + this.drawBBox(); + this.figure._add(this); + } else { + if(this.boundingBox){ + if(this.shape) this.shape.remove(this.boundingBox); + this.boundingBox=null; + } + } + for(var p in this.anchors){ this.anchors[p][method](); } + }; +// p.writeProperties=function(){ +// var ps=this._properties; +// return ""; +// }; + p.writeCommonAttrs=function(){ + return 'id="' + this.id + '" dojoxsketch:type="' + this.type() + '"' + + ' transform="translate('+ this.transform.dx + "," + this.transform.dy + ')"' + + (this.data?(' >=this.end.x) rot+=Math.PI; + var endRot=dojox.gfx.matrix.rotateAt(rot, this.end.x, this.end.y); + + // draw the shapes + this.shape=this.figure.group.createGroup(); + this.shape.getEventSource().setAttribute("id", this.id); + if(this.transform.dx||this.transform.dy) this.shape.setTransform(this.transform); + this.pathShape=this.shape.createPath( + "M"+this.start.x+" "+this.start.y+"Q"+this.control.x+" "+this.control.y+" "+this.end.x+" "+this.end.y + " l0,0" + ).setStroke(this.property('stroke')); + + this.startArrowGroup=this.shape.createGroup().setTransform({ dx:this.start.x, dy:this.start.y }); + this.startArrowGroup.applyTransform(startRot); +// console.log('startArrow',this.property('fill')); + this.startArrow=this.startArrowGroup.createPath("M0,0 l20,-5 -3,5 3,5 Z").setFill(this.property('fill')); + + this.endArrowGroup=this.shape.createGroup().setTransform(endRot); + this.endArrow=this.endArrowGroup.createPath( + "M" + this.end.x + "," + this.end.y + " l-20,-5 3,5 -3,5 Z" + ).setFill(this.property('fill')); + this.labelShape=this.shape.createText({ + x:this.textPosition.x, y:this.textPosition.y, text:this.property('label'), align:this.textAlign + }).setFont(font).setFill(this.property('fill')); + }; + p.destroy=function(){ + if(!this.shape) return; + this.startArrowGroup.remove(this.startArrow); + this.endArrowGroup.remove(this.endArrow); + this.shape.remove(this.startArrowGroup); + this.shape.remove(this.endArrowGroup); + this.shape.remove(this.pathShape); + this.shape.remove(this.labelShape); + this.figure.group.remove(this.shape); + this.shape=this.pathShape=this.labelShape=this.startArrowGroup=this.startArrow=this.endArrowGroup=this.endArrow=null; + }; + p.draw=function(obj){ + this.apply(obj); + this._rot(); + this._pos(); + // rotation matrix + var rot=this.startRotation; + if(this.control.x=this.end.x) rot+=Math.PI; + var endRot=dojox.gfx.matrix.rotateAt(rot, this.end.x, this.end.y); + + this.shape.setTransform(this.transform); + this.pathShape.setShape( + "M"+this.start.x+" "+this.start.y+" Q"+this.control.x+" "+this.control.y+" "+this.end.x+" "+this.end.y + " l0,0" + ).setStroke(this.property('stroke')); + this.startArrowGroup.setTransform({ dx:this.start.x, dy:this.start.y }); + this.startArrowGroup.applyTransform(startRot); + this.startArrow.setFill(this.property('fill')); + + this.endArrowGroup.setTransform(endRot); + this.endArrow.setShape( + "M" + this.end.x + "," + this.end.y + " l-20,-5 3,5 -3,5 Z" + ).setFill(this.property('fill')); + this.labelShape.setShape({x:this.textPosition.x, y:this.textPosition.y, text:this.property('label')}).setFill(this.property('fill')); + }; + p.getBBox=function(){ + var x=Math.min(this.start.x, this.control.x, this.end.x); + var y=Math.min(this.start.y, this.control.y, this.end.y); + var w=Math.max(this.start.x, this.control.x, this.end.x)-x; + var h=Math.max(this.start.y, this.control.y, this.end.y)-y; + return { x:x, y:y, width:w, height:h }; + }; + p.serialize=function(){ + var s=this.property('stroke'); + return '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + this.property('label') + + '' + + ''; + }; + + ta.Annotation.register("DoubleArrow"); +})(); + +} diff --git a/includes/js/dojox/sketch/Figure.js b/includes/js/dojox/sketch/Figure.js new file mode 100644 index 0000000..ae573bb --- /dev/null +++ b/includes/js/dojox/sketch/Figure.js @@ -0,0 +1,493 @@ +if(!dojo._hasResource["dojox.sketch.Figure"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sketch.Figure"] = true; +dojo.provide("dojox.sketch.Figure"); +dojo.experimental("dojox.sketch"); + +dojo.require("dojox.gfx"); +dojo.require("dojox.sketch.UndoStack"); + +(function(){ + var ta=dojox.sketch; + ta.tools={}; + ta.registerTool=function(type, fn){ ta.tools[type]=fn; }; + ta.Figure = function(){ + var self=this; + var annCounter=1; + + this.shapes=[]; + this.image=null; + this.imageSrc=null; + this.size={ w:0, h:0 }; + this.surface=null; + this.group=null; + this.node=null; + + this.zoomFactor=1; // multiplier for zooming. + + this.tools=null; // toolbar reference. + this.nextKey=function(){ return annCounter++; }; + + this.obj={}; // lookup table for shapes. Not keen on this solution. + + this.initUndoStack(); + + // what is selected. + this.selected=[]; + this.hasSelections=function(){ return this.selected.length>0 }; + this.isSelected=function(obj){ + for(var i=0; i-1){ + obj.setMode(ta.Annotation.Modes.View); + self.selected.splice(idx,1); + } + return obj; + }; + this.clearSelections=function(){ + for(var i=0; i-1){ + self.selected.splice(idx,1,n); + } + }; + + // for the drag and drop handlers. + this._c=null; // current shape + this._ctr=null; // container measurements + this._lp=null; // last position + this._action=null; + this._prevState=null; + this._startPoint=null; // test to record a move. + + // if an object isn't selected and we're dragging anyways. + this._ctool=null; // hard code it. + this._start=null; + this._end=null; + this._absEnd=null; + this._cshape=null; + + this._click=function(e){ + if(self._c){ + dojo.stopEvent(e); + return; + } + var o=self._fromEvt(e); + if(!o){ + self.clearSelections(); + dojo.stopEvent(e); + } else if(!o.setMode){ + // skip me. + } else self.select(o); + }; + this._dblclick=function(e){ + var o=self._fromEvt(e); + if(o){ + self.onDblClickShape(o,e); + } + }; + + this._keydown=function(e){ + var prevent=false; + if(e.ctrlKey){ + if(e.keyCode==90){ //ctrl+z + self.undo(); + prevent = true; + }else if(e.keyCode==89){ //ctrl+y + self.redo(); + prevent = true; + } + } + + if(e.keyCode==46 || e.keyCode==8){ //delete or backspace + self._delete(self.selected); + prevent = true; + } + + if(prevent){ + dojo.stopEvent(e); + } + }; + + // drag handlers. + this._md=function(e){ + var o=self._fromEvt(e); + self._startPoint={ x:e.pageX, y:e.pageY }; + var win = dijit.getDocumentWindow(self.node.ownerDocument); + // figure out the coordinates within the iframe + self._ctr=dojo._abs(self.node); + var scroll=dojo.withGlobal(win,dojo._docScroll); + self._ctr={x:self._ctr.x-scroll.x, y:self._ctr.y-scroll.y}; + var X=e.clientX-self._ctr.x, Y=e.clientY-self._ctr.y; + self._lp={ x:X, y:Y }; + + // capture it separately + self._start={ x:X, y:Y }; + self._end={ x:X, y:Y }; + self._absEnd={ x:X, y:Y }; + if(!o){ + self.clearSelections(); + self._ctool.onMouseDown(e); + }else{ + if(o.type && o.type()!="Anchor"){ + self.select(o); + } + o.beginEdit(); + self._c=o; + } + }; + this._mm=function(e){ + if(!self._ctr) return; + var x=e.clientX-self._ctr.x; + var y=e.clientY-self._ctr.y; + var dx=x-self._lp.x; + var dy=y-self._lp.y; + self._absEnd={x:x, y:y}; + if(self._c){ + self._c.doChange({dx:Math.round(dx/self.zoomFactor), dy:Math.round(dy/self.zoomFactor)}); + self._c.setBinding({dx:Math.round(dx/self.zoomFactor), dy:Math.round(dy/self.zoomFactor)}); + self._lp={x:x, y:y}; + } + else { + self._end={x:dx, y:dy}; + var rect={ + x:Math.min(self._start.x,self._absEnd.x), + y:Math.min(self._start.y,self._absEnd.y), + width:Math.abs(self._start.x-self._absEnd.x), + height:Math.abs(self._start.y-self._absEnd.y) + } + self._ctool.onMouseMove(e,rect); + } + }; + this._mu=function(e){ + if(self._c){ + // record the event. + self._c.endEdit(); + }else{ + self._ctool.onMouseUp(e); + } + + // clear the stuff out. + self._c=self._ctr=self._lp=self._action=self._prevState=self._startPoint=null; + self._cshape=self._start=self._end=self._absEnd=null; + }; + + this._delete=function(arr,noundo){ + for(var i=0; i + this.group.createRect({ x:0, y:0, width:this.size.w, height:this.size.h }); + this.image=this.group.createImage({ width:this.size.w, height:this.size.h, src:this.imageSrc }); + }; + p.destroy=function(isLoading){ + if(!this.node){ + return; + } + if(!isLoading){ + if(this.history) this.history.destroy(); + if(this._subscribed){ + dojo.unsubscribe(this._subscribed); + delete this._subscribed; + } + } + dojo.forEach(this._cons,dojo.disconnect); + this._cons=[]; + + this.node.removeChild(this.surface.getEventSource()); + this.group=this.surface=null; + this.obj={}; + this.shapes=[]; + }; + p.draw=function(){ }; + p.zoom=function(pct){ + // first get the new dimensions + this.zoomFactor=pct/100; + var w=this.size.w*this.zoomFactor; + var h=this.size.h*this.zoomFactor; + this.surface.setDimensions(w, h); + // then scale it. + this.group.setTransform(dojox.gfx.matrix.scale(this.zoomFactor, this.zoomFactor)); + if(dojo.isIE){ + this.image.rawNode.style.width=Math.max(w,this.size.w); + this.image.rawNode.style.height=Math.max(h,this.size.h); + } + //this.rect.setShape({width:w,height:h}); + }; + p.getFit=function(){ + // assume fitting the parent node. +// var box=dojo.html.getContentBox(this.node.parentNode); + //the following should work under IE and FF, not sure about others though + var wF=(this.node.parentNode.clientWidth-5)/this.size.w; + var hF=(this.node.parentNode.clientHeight-5)/this.size.h; + return Math.min(wF, hF)*100; + }; + p.unzoom=function(){ + // restore original size. + this.zoomFactor=1; + this.surface.setDimensions(this.size.w, this.size.h); + this.group.setTransform(); + }; + + // object registry for drag handling. + p._add=function(obj){ this.obj[obj._key]=obj; }; + p._remove=function(obj){ + if(this.obj[obj._key]){ + delete this.obj[obj._key]; + } + }; + p._get=function(key){ + if(key&&key.indexOf("bounding")>-1) key=key.replace("-boundingBox",""); + return this.obj[key]; + }; + p._fromEvt=function(e){ + var key=e.target.id+""; + if(key.length==0){ + // ancestor tree until you get to the end (meaning this.surface) + var p=e.target.parentNode; + var node=this.surface.getEventSource(); + while(p && p.id.length==0 && p!=node){ + p=p.parentNode; + } + key=p.id; + } + return this._get(key); + }; + + p.add=function(annotation){ + for(var i=0; i-1) this.shapes.splice(idx, 1); + return annotation; + }; + p.get=function(id){ + for(var i=0; i' + + '' + + ''; + for(var i=0; i=1){ + x=this.end.x+this.calculate.dx(this.control, this.end, offset); + if(this.control.y>this.end.y) y=this.end.y-offset; + else y=this.end.y+offset+this.textYOffset; + } else if(slope==0){ + x=this.end.x+offset; + y=this.end.y+this.textYOffset; + } else { + if(this.start.x>this.end.x){ + x=this.end.x-offset; + this.textAlign="end"; + } else { + x=this.end.x+offset; + this.textAlign="start"; + } + if(this.start.y' + + '' + + '' + + this.property('label') + + '' + + ''; + }; + + ta.Annotation.register("Lead"); +})(); + +} diff --git a/includes/js/dojox/sketch/PreexistingAnnotation.js b/includes/js/dojox/sketch/PreexistingAnnotation.js new file mode 100644 index 0000000..a8c123e --- /dev/null +++ b/includes/js/dojox/sketch/PreexistingAnnotation.js @@ -0,0 +1,121 @@ +if(!dojo._hasResource["dojox.sketch.PreexistingAnnotation"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sketch.PreexistingAnnotation"] = true; +dojo.provide("dojox.sketch.PreexistingAnnotation"); + +dojo.require("dojox.sketch.Annotation"); +dojo.require("dojox.sketch.Anchor"); + +(function(){ + var ta=dojox.sketch; + ta.PreexistingAnnotation=function(figure, id){ + ta.Annotation.call(this, figure, id); + this.transform={dx:0, dy:0}; + this.start={ x:0, y:0 }; + this.end={ x:200, y:200 }; + this.radius=8; + this.textPosition={ x:196, y:196 }; + this.textOffset=4; + this.textAlign="end"; + + this.property('label',this.id); + this.rectShape=null; + this.labelShape=null; + + this.anchors.start=new ta.Anchor(this, "start"); + this.anchors.end=new ta.Anchor(this, "end"); + }; + ta.PreexistingAnnotation.prototype=new ta.Annotation; + var p=ta.PreexistingAnnotation.prototype; + p.constructor=ta.PreexistingAnnotation; + + p.type=function(){ return 'Preexisting' }; + p.getType=function(){ return ta.PreexistingAnnotation; }; + + p._pos=function(){ + var x=Math.min(this.start.x, this.end.x); + var y=Math.min(this.start.y, this.end.y); + var w=Math.max(this.start.x, this.end.x); + var h=Math.max(this.start.y, this.end.y); + this.start={ x:x, y:y }; + this.end={ x:w, y:h }; + this.textPosition={ x:this.end.x-this.textOffset, y:this.end.y-this.textOffset }; + }; + p.apply=function(obj){ + if(!obj) return; + if(obj.documentElement) obj=obj.documentElement; + this.readCommonAttrs(obj); + + for(var i=0; i' + + '' + + '' + + this.property('label') + + '' + + ''; + }; + + ta.Annotation.register("Preexisting"); +})(); + +} diff --git a/includes/js/dojox/sketch/README b/includes/js/dojox/sketch/README new file mode 100644 index 0000000..85b2264 --- /dev/null +++ b/includes/js/dojox/sketch/README @@ -0,0 +1,58 @@ +------------------------------------------------------------------------------- +dojox.sketch +------------------------------------------------------------------------------- +Version 0.1 +Release date: 28/01/2008 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + Contributed by TeamPatent (supported by National Science Foundation grant 638334) + Tom Trenka (ttrenka@gmail.com) + Heng Liu/LiuCougar (heng@teampatent.com) +------------------------------------------------------------------------------- +Project description + +A cross-browser drawing editor based on dojox.gfx. +------------------------------------------------------------------------------- +Dependencies: + +dijit (Toolbar, Button, Slider) +dojox.gfx +dojox.xml +------------------------------------------------------------------------------- +Documentation + +Currently, 5 shapes are supported: line, single arrow line, double arrow line, +underline text and text. The first 3 shapes can have optinal text associated. + +Shapes can be added, deleted, moved and modified. All of these operations can +be undo-ed or redo-ed. + +TODO: + * provide UI to change various properties on shapes (fill, stroke, text) and +allow changing of background image + * serialize/unserialize in dojox.gfx to svg (and maybe vml as well?) (or another +simplier format? such as a json based one, which is easier to parse, and then +write a convertor to convert the json format to svg or any other format?) + * Move mousedown/up/move to each shape (to prepare for the following) + * Add shapes for other primitive shapes (needs to decide which primitive +dojox.gfx.shapes are useful), and add in support for user to group any +shapes/groups to form a single "compound shape" (need to add support to set +fill/stroke properties on the entire compound shape, which shallpropagate to +all children shapes) +------------------------------------------------------------------------------- +Installation instructions + +Install dijit, dojox.gfx and dojox.xml first + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/sketch.js +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/sketch/* + +Install into the following directory structure: +/dojox/sketch/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- diff --git a/includes/js/dojox/sketch/SingleArrowAnnotation.js b/includes/js/dojox/sketch/SingleArrowAnnotation.js new file mode 100644 index 0000000..29ad7f0 --- /dev/null +++ b/includes/js/dojox/sketch/SingleArrowAnnotation.js @@ -0,0 +1,183 @@ +if(!dojo._hasResource["dojox.sketch.SingleArrowAnnotation"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sketch.SingleArrowAnnotation"] = true; +dojo.provide("dojox.sketch.SingleArrowAnnotation"); +dojo.require("dojox.sketch.Annotation"); +dojo.require("dojox.sketch.Anchor"); + +(function(){ + var ta=dojox.sketch; + ta.SingleArrowAnnotation=function(figure, id){ + ta.Annotation.call(this, figure, id); + this.transform={ dx:0, dy:0 }; + this.start={x:0, y:0}; + this.control={x:100, y:-50}; + this.end={x:200, y:0}; + this.textPosition={ x:0, y:0 }; + this.textOffset=4; + this.textAlign="middle"; + this.textYOffset=10; + this.rotation=0; + +// this.property('label',this.id); +// this.label=this.id; + this.pathShape=null; + this.arrowhead=null; + this.arrowheadGroup=null; + this.labelShape=null; + + this.anchors.start=new ta.Anchor(this, "start"); + this.anchors.control=new ta.Anchor(this, "control"); + this.anchors.end=new ta.Anchor(this, "end"); + }; + ta.SingleArrowAnnotation.prototype=new ta.Annotation; + var p=ta.SingleArrowAnnotation.prototype; + p.constructor=ta.SingleArrowAnnotation; + + p.type=function(){ return 'SingleArrow'; }; + p.getType=function(){ return ta.SingleArrowAnnotation; }; + + // helper functions + p._rot=function(){ + // arrowhead rotation + var opp=this.start.y-this.control.y; + var adj=this.start.x-this.control.x; + if(!adj) adj=1; + this.rotation=Math.atan(opp/adj); + }; + p._pos=function(){ + // text position + var offset=this.textOffset, x=0, y=0; + var slope=this.calculate.slope(this.control, this.end); + if(Math.abs(slope)>=1){ + x=this.end.x+this.calculate.dx(this.control, this.end, offset); + if(this.control.y>this.end.y) y=this.end.y-offset; + else y=this.end.y+offset+this.textYOffset; + } else if(slope==0){ + x=this.end.x+offset; + y=this.end.y+this.textYOffset; + } else { + if(this.start.x>this.end.x){ + x=this.end.x-offset; + this.textAlign="end"; + } else { + x=this.end.x+offset; + this.textAlign="start"; + } + if(this.start.y=this.end.x&&this.control.xthis.end.x) r-=180; + r=Math.round(r*Math.pow(10,4))/Math.pow(10,4); + return '' + + '' + + '' + + '' + + '' + + '' + + this.property('label') + + '' + + ''; + }; + + ta.Annotation.register("SingleArrow"); +})(); + +} diff --git a/includes/js/dojox/sketch/Slider.js b/includes/js/dojox/sketch/Slider.js new file mode 100644 index 0000000..e014e78 --- /dev/null +++ b/includes/js/dojox/sketch/Slider.js @@ -0,0 +1,31 @@ +if(!dojo._hasResource["dojox.sketch.Slider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sketch.Slider"] = true; +dojo.provide("dojox.sketch.Slider"); + +dojo.require("dijit.form.Slider"); +dojo.declare("dojox.sketch.Slider",dojox.sketch._Plugin,{ + _initButton: function(){ + this.slider=new dijit.form.HorizontalSlider({minimum:20,maximum:200,value:20,style:"width:200px;float:right"}); + this.connect(this.slider,'onChange','_setZoom'); + this.connect(this.slider.sliderHandle,'ondblclick','_zoomToFit'); + }, + _zoomToFit: function(){ + this.slider.setValue(this.figure.getFit(),true); + }, + _setZoom: function(v){ + if(this.figure){ + this.figure.zoom(v); + } + }, + setToolbar: function(t){ + t.addChild(this.slider); + if(!t._reset2Zoom){ + t._reset2Zoom=true; + this.connect(t,'reset','_zoomToFit'); + } + } +}); + +dojox.sketch.registerTool("Slider", dojox.sketch.Slider); + +} diff --git a/includes/js/dojox/sketch/Toolbar.js b/includes/js/dojox/sketch/Toolbar.js new file mode 100644 index 0000000..73dc82c --- /dev/null +++ b/includes/js/dojox/sketch/Toolbar.js @@ -0,0 +1,96 @@ +if(!dojo._hasResource["dojox.sketch.Toolbar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sketch.Toolbar"] = true; +dojo.provide("dojox.sketch.Toolbar"); + +dojo.require("dojox.sketch.Annotation"); +dojo.require("dijit.Toolbar"); +dojo.require("dijit.form.Button"); +dojo.require("dijit.form.Slider"); + +dojo.declare("dojox.sketch.ButtonGroup", null, { + constructor: function(){ + this._childMaps={}; + this._children=[]; + }, + add: function(/*_Plugin*/ plugin){ + this._childMaps[plugin]=plugin.connect(plugin,'onActivate',dojo.hitch(this,'_resetGroup',plugin)); + this._children.push(plugin); + }, +// remove: function(/*_Plugin*/ plugin){ +// widget.disconnect(this._childMaps[widget.id]); +// delete this._childMaps[widget.id]; +// this._children.splice(this._children.indexOf(widget.id),1); +// }, + _resetGroup: function(p){ + var cs=this._children; + dojo.forEach(cs,function(c){ + if(p!=c && c['attr']){ + c.attr('checked',false); + } + }); + } +}); + +dojo.declare("dojox.sketch.Toolbar", dijit.Toolbar, { + figure: null, + plugins: null, + postCreate: function(){ + this.inherited(arguments); + this.shapeGroup=new dojox.sketch.ButtonGroup; + + this.connect(this.figure,'onLoad','reset'); + if(!this.plugins){ + this.plugins=['Slider','Lead','SingleArrow','DoubleArrow','Underline','Preexisting']; + } + this._plugins=[]; + + dojo.forEach(this.plugins,function(obj){ + var name=dojo.isString(obj)?obj:obj.name; + var p=new dojox.sketch.tools[name](obj.args||{}); + this._plugins.push(p); + p.setFigure(this.figure); + p.setToolbar(this); + if(!this._defaultTool && p.button){ + this._defaultTool=p; + } + },this); + }, + destroy: function(){ + dojo.forEach(this._plugins,function(p){ + p.destroy(); + }); + this.inherited(arguments); + delete this._defaultTool; + delete this._plugins; + }, + addGroupItem: function(/*_Plugin*/item,group){ + if(group!='toolsGroup'){ + console.error('not supported group '+group); + return; + } + + this.shapeGroup.add(item); + }, + reset: function(){ + this._defaultTool.activate(); + }, + _setShape: function(s){ + if(!this.figure.surface) return; + // now do the action. + if(this.figure.hasSelections()){ + for(var i=0; i' + + '' + + '' + + this.property('label') + + '' + + ''; + }; + + ta.Annotation.register("Underline"); +})(); + +} diff --git a/includes/js/dojox/sketch/UndoStack.js b/includes/js/dojox/sketch/UndoStack.js new file mode 100644 index 0000000..e711557 --- /dev/null +++ b/includes/js/dojox/sketch/UndoStack.js @@ -0,0 +1,104 @@ +if(!dojo._hasResource["dojox.sketch.UndoStack"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sketch.UndoStack"] = true; +dojo.provide("dojox.sketch.UndoStack"); +dojo.require("dojox.xml.DomParser"); + +(function(){ + var ta=dojox.sketch; + ta.CommandTypes={ Create:"Create", Move:"Move", Modify:"Modify", Delete:"Delete", Convert:"Convert"}; + + dojo.declare("dojox.sketch.UndoStack",null,{ + constructor: function(figure){ + this.figure=figure; + this._steps=[]; + this._undoedSteps=[]; + }, + apply: function(state, from, to){ + // the key here is to neutrally move from one state to another. + // we let the individual functions (i.e. undo and redo) actually + // determine the from and to; all we do here is implement it. + + // check whether this is a fullText step + if(!from && !to && state.fullText){ + this.figure.setValue(state.fullText); + return; + } + + var fromText=from.shapeText; + var toText=to.shapeText; + + if(fromText.length==0&&toText.length==0){ + // nothing to reapply? + return; + } + if(fromText.length==0){ + // We are creating. + var o=dojox.xml.DomParser.parse(toText).documentElement; + var a=this.figure._loadAnnotation(o); + if(a) this.figure._add(a); + return; + } + if(toText.length==0){ + // we are deleting. + var ann=this.figure.get(from.shapeId); + this.figure._delete([ann],true); + return; + } + + // we can simply reinit and draw from the shape itself, + // regardless of the actual command. + var nann=this.figure.get(to.shapeId); + var no=dojox.xml.DomParser.parse(toText).documentElement; + nann.draw(no); + this.figure.select(nann); + return; + }, + // stack methods. + add: function(/*String*/cmd, /*ta.Annotation?*/ann, /*String?*/before){ + var id=ann?ann.id:''; + //var bbox=ann?ann.getBBox():{}; + var after=ann?ann.serialize():""; + if(cmd==ta.CommandTypes.Delete) after=""; + + /*if(ann){ + // fix the bbox x/y coords + var t=ann.transform; + bbox.x+=t.dx; + bbox.y+=t.dy; + }*/ + var state={ + cmdname:cmd, + //bbox:bbox, +// fullText:fullText, + before:{ + shapeId: id, + shapeText:before||'' + }, + after:{ + shapeId: id, + shapeText:after + } + }; + //console.log('dojox.sketch history add',state); + this._steps.push(state); + this._undoedSteps = []; + }, + destroy: function(){}, + undo: function(){ + var state=this._steps.pop(); + if(state){ + this._undoedSteps.push(state); + this.apply(state,state.after,state.before); + } + }, + redo: function(){ + var state=this._undoedSteps.pop(); + if(state){ + this._steps.push(state); + this.apply(state,state.before,state.after); + } + } + }); +})(); + +} diff --git a/includes/js/dojox/sketch/_Plugin.js b/includes/js/dojox/sketch/_Plugin.js new file mode 100644 index 0000000..fb7cb93 --- /dev/null +++ b/includes/js/dojox/sketch/_Plugin.js @@ -0,0 +1,83 @@ +if(!dojo._hasResource["dojox.sketch._Plugin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sketch._Plugin"] = true; +dojo.provide("dojox.sketch._Plugin"); +//dojo.require("dojox.sketch"); +dojo.require("dijit.form.Button"); + +dojo.declare("dojox.sketch._Plugin", null, { + // summary + // This represents a "plugin" to the dojox.sketch.Figure, which is basically + // a single button on the Toolbar and some associated code + constructor: function(/*Object?*/args){ + if(args){ + dojo.mixin(this, args); + } + this._connects=[]; + }, + + figure: null, + iconClassPrefix: "dojoxSketchIcon", + itemGroup: 'toolsGroup', + button: null, + queryCommand: null, + shape: "", + useDefaultCommand: true, + buttonClass: dijit.form.ToggleButton, + _initButton: function(){ + if(this.shape.length){ + //TODO: i18n +// var label = dojox.sketch.shapes[this.shape]; + var className = this.iconClassPrefix+" "+this.iconClassPrefix + this.shape.charAt(0).toUpperCase() + this.shape.substr(1); + if(!this.button){ + var props = { + label: this.shape, + showLabel: false, + iconClass: className, + dropDown: this.dropDown, + tabIndex: "-1" + }; + this.button = new this.buttonClass(props); + this.connect(this.button,'onClick','activate'); + } + } + }, + attr: function(name,/*?*/value){ + if(arguments.length>1){ + this.button.setAttribute(name,value); + }else{ + this.button.getAttribute(name); + } + }, + onActivate: function(){}, + activate: function(/*?*/e){ + this.onActivate(); + this.figure.setTool(this); + this.attr('checked',true); + }, + onMouseDown: function(e){}, + onMouseMove: function(e){}, + onMouseUp: function(e){}, + destroy: function(f){ + dojo.forEach(this._connects,dojo.disconnect); + }, + connect: function(o,f,tf){ + this._connects.push(dojo.connect(o,f,this,tf)); + }, + setFigure: function(/*Widget*/figure){ + // FIXME: detatch from previous figure!! + this.figure = figure; + + // FIXME: prevent creating this if we don't need to (i.e., figure can't handle our command) + this._initButton(); + }, + setToolbar: function(/*Widget*/toolbar){ + if(this.button){ + toolbar.addChild(this.button); + } + if(this.itemGroup){ + toolbar.addGroupItem(this,this.itemGroup); + } + } +}); + +} diff --git a/includes/js/dojox/sketch/resources/images/icons.gif b/includes/js/dojox/sketch/resources/images/icons.gif new file mode 100644 index 0000000..ab33b0a Binary files /dev/null and b/includes/js/dojox/sketch/resources/images/icons.gif differ diff --git a/includes/js/dojox/sketch/resources/sketch.css b/includes/js/dojox/sketch/resources/sketch.css new file mode 100644 index 0000000..7451395 --- /dev/null +++ b/includes/js/dojox/sketch/resources/sketch.css @@ -0,0 +1,17 @@ +.dojoxSketchIcon{ + background-repeat:no-repeat; + height:16px; + min-width:16px; + text-align:center; + width:16px; +} +.dojoxSketchIcon { background-image:url(images/icons.gif); } +.ShowCallouts{ background-position:0px 0px; } +.PreviousCallout{ background-position:0px -16px; } +.NextCallout{ background-position:0px -32px; } +.dojoxSketchIconLead{ background-position:0px -48px; } +.dojoxSketchIconUnderline{ background-position:0px -64px; } +.dojoxSketchIconSingleArrow{ background-position:0px -80px; } +.dojoxSketchIconBrace{ background-position:0px -96px; } +.dojoxSketchIconDoubleArrow{ background-position:0px -112px; } +.dojoxSketchIconPreexisting{ background-position:0px -128px; } diff --git a/includes/js/dojox/sketch/resources/sketch.css.commented.css b/includes/js/dojox/sketch/resources/sketch.css.commented.css new file mode 100644 index 0000000..7451395 --- /dev/null +++ b/includes/js/dojox/sketch/resources/sketch.css.commented.css @@ -0,0 +1,17 @@ +.dojoxSketchIcon{ + background-repeat:no-repeat; + height:16px; + min-width:16px; + text-align:center; + width:16px; +} +.dojoxSketchIcon { background-image:url(images/icons.gif); } +.ShowCallouts{ background-position:0px 0px; } +.PreviousCallout{ background-position:0px -16px; } +.NextCallout{ background-position:0px -32px; } +.dojoxSketchIconLead{ background-position:0px -48px; } +.dojoxSketchIconUnderline{ background-position:0px -64px; } +.dojoxSketchIconSingleArrow{ background-position:0px -80px; } +.dojoxSketchIconBrace{ background-position:0px -96px; } +.dojoxSketchIconDoubleArrow{ background-position:0px -112px; } +.dojoxSketchIconPreexisting{ background-position:0px -128px; } diff --git a/includes/js/dojox/sketch/tests/annotation.svg b/includes/js/dojox/sketch/tests/annotation.svg new file mode 100644 index 0000000..9638588 --- /dev/null +++ b/includes/js/dojox/sketch/tests/annotation.svg @@ -0,0 +1 @@ +12345 \ No newline at end of file diff --git a/includes/js/dojox/sketch/tests/images/figure2.gif b/includes/js/dojox/sketch/tests/images/figure2.gif new file mode 100644 index 0000000..7218a4c Binary files /dev/null and b/includes/js/dojox/sketch/tests/images/figure2.gif differ diff --git a/includes/js/dojox/sketch/tests/images/testsBodyBg.gif b/includes/js/dojox/sketch/tests/images/testsBodyBg.gif new file mode 100644 index 0000000..4e0b4a7 Binary files /dev/null and b/includes/js/dojox/sketch/tests/images/testsBodyBg.gif differ diff --git a/includes/js/dojox/sketch/tests/test_full.html b/includes/js/dojox/sketch/tests/test_full.html new file mode 100644 index 0000000..b78c232 --- /dev/null +++ b/includes/js/dojox/sketch/tests/test_full.html @@ -0,0 +1,66 @@ + + + + Annotator/Figure Testing + + + + + + + + + +

                  Annotator/Figure Testing Platform

                  +

                  This is a generic test to create a figure from an existing SVG file, to edit that figure, and to test the undo stack. Double click a shape to set new text for it.

                  +
                  +
                  +
                  +
                  +

                  Serialized output

                  + + + diff --git a/includes/js/dojox/sql.js b/includes/js/dojox/sql.js new file mode 100644 index 0000000..d4a77ef --- /dev/null +++ b/includes/js/dojox/sql.js @@ -0,0 +1,6 @@ +if(!dojo._hasResource["dojox.sql"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sql"] = true; +dojo.require("dojox._sql.common"); +dojo.provide("dojox.sql"); + +} diff --git a/includes/js/dojox/storage.js b/includes/js/dojox/storage.js new file mode 100644 index 0000000..0fed636 --- /dev/null +++ b/includes/js/dojox/storage.js @@ -0,0 +1,6 @@ +if(!dojo._hasResource["dojox.storage"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.storage"] = true; +dojo.provide("dojox.storage"); +dojo.require("dojox.storage._common"); + +} diff --git a/includes/js/dojox/storage/AirDBStorageProvider.js b/includes/js/dojox/storage/AirDBStorageProvider.js new file mode 100644 index 0000000..a846b94 --- /dev/null +++ b/includes/js/dojox/storage/AirDBStorageProvider.js @@ -0,0 +1,252 @@ +if(!dojo._hasResource["dojox.storage.AirDBStorageProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.storage.AirDBStorageProvider"] = true; +dojo.provide("dojox.storage.AirDBStorageProvider"); +dojo.require("dojox.storage.manager"); +dojo.require("dojox.storage.Provider"); + +if (dojo.isAIR) { + (function(){ + + if (!air) { + var air = {}; + } + air.File = window.runtime.flash.filesystem.File; + air.SQLConnection = window.runtime.flash.data.SQLConnection; + air.SQLStatement = window.runtime.flash.data.SQLStatement; + + // summary: + // Storage provider that uses features in the Adobe AIR runtime to achieve + // permanent storage + dojo.declare("dojox.storage.AirDBStorageProvider", [ dojox.storage.Provider ], { + DATABASE_FILE: "dojo.db", + TABLE_NAME: "__DOJO_STORAGE", + initialized: false, + + _db: null, + + initialize: function(){ + this.initialized = false; + + // need to initialize our storage database + try{ + this._db = new air.SQLConnection(); + this._db.open(air.File.applicationStorageDirectory.resolvePath(this.DATABASE_FILE)); + + this._sql("CREATE TABLE IF NOT EXISTS " + this.TABLE_NAME + "(namespace TEXT, key TEXT, value TEXT)"); + this._sql("CREATE UNIQUE INDEX IF NOT EXISTS namespace_key_index ON " + this.TABLE_NAME + " (namespace, key)"); + + this.initialized = true; + }catch(e){ + console.debug("dojox.storage.AirDBStorageProvider.initialize:", e); + } + + // indicate that this storage provider is now loaded + dojox.storage.manager.loaded(); + }, + + _sql: function(query, params){ + var stmt = new air.SQLStatement(); + stmt.sqlConnection = this._db; + stmt.text = query; + if (params){ + for (var param in params){ + stmt.parameters[param] = params[param]; + } + } + stmt.execute(); + return stmt.getResult(); + }, + + _beginTransaction: function(){ + this._db.begin(); + }, + + _commitTransaction: function(){ + this._db.commit(); + }, + + isAvailable: function(){ + return true; + }, + + put: function(key, value, resultsHandler, namespace){ + if(this.isValidKey(key) == false){ + throw new Error("Invalid key given: " + key); + } + namespace = namespace||this.DEFAULT_NAMESPACE; + if(this.isValidKey(namespace) == false){ + throw new Error("Invalid namespace given: " + namespace); + } + + // try to store the value + try{ + this._sql("DELETE FROM " + this.TABLE_NAME + " WHERE namespace = :namespace AND key = :key", + { ":namespace":namespace, ":key":key }); + this._sql("INSERT INTO " + this.TABLE_NAME + " VALUES (:namespace, :key, :value)", + { ":namespace":namespace, ":key":key, ":value":value }); + }catch(e){ + // indicate we failed + console.debug("dojox.storage.AirDBStorageProvider.put:", e); + resultsHandler(this.FAILED, key, e.toString()); + return; + } + + if(resultsHandler){ + resultsHandler(this.SUCCESS, key, null); + } + }, + + get: function(key, namespace){ + if(this.isValidKey(key) == false){ + throw new Error("Invalid key given: " + key); + } + namespace = namespace||this.DEFAULT_NAMESPACE; + + var results = this._sql("SELECT * FROM " + this.TABLE_NAME + " WHERE namespace = :namespace AND key = :key", + { ":namespace":namespace, ":key":key }); + + if(results.data && results.data.length){ + return results.data[0].value; + } + + return null; + }, + + getNamespaces: function(){ + var results = [ this.DEFAULT_NAMESPACE ]; + var rs = this._sql("SELECT namespace FROM " + this.TABLE_NAME + " DESC GROUP BY namespace"); + if (rs.data){ + for(var i = 0; i < rs.data.length; i++){ + if(rs.data[i].namespace != this.DEFAULT_NAMESPACE){ + results.push(rs.data[i].namespace); + } + } + } + return results; + }, + + getKeys: function(namespace){ + namespace = namespace||this.DEFAULT_NAMESPACE; + if(this.isValidKey(namespace) == false){ + throw new Error("Invalid namespace given: " + namespace); + } + + var results = []; + var rs = this._sql("SELECT key FROM " + this.TABLE_NAME + " WHERE namespace = :namespace", { ":namespace":namespace }); + if (rs.data){ + for(var i = 0; i < rs.data.length; i++){ + results.push(rs.data[i].key); + } + } + return results; + }, + + clear: function(namespace){ + if(this.isValidKey(namespace) == false){ + throw new Error("Invalid namespace given: " + namespace); + } + this._sql("DELETE FROM " + this.TABLE_NAME + " WHERE namespace = :namespace", { ":namespace":namespace }); + }, + + remove: function(key, namespace){ + namespace = namespace||this.DEFAULT_NAMESPACE; + this._sql("DELETE FROM " + this.TABLE_NAME + " WHERE namespace = :namespace AND key = :key", + { ":namespace":namespace, ":key":key }); + }, + + putMultiple: function(keys, values, resultsHandler, namespace) { + if(this.isValidKeyArray(keys) === false + || ! values instanceof Array + || keys.length != values.length){ + throw new Error("Invalid arguments: keys = [" + keys + "], values = [" + values + "]"); + } + + if(namespace == null || typeof namespace == "undefined"){ + namespace = this.DEFAULT_NAMESPACE; + } + + if(this.isValidKey(namespace) == false){ + throw new Error("Invalid namespace given: " + namespace); + } + + this._statusHandler = resultsHandler; + + // try to store the value + try{ + this._beginTransaction(); + for(var i=0;i 0 : Wait until 'newDelay' ms have passed without any "put" request to flush + // -1 : Do not automatically flush + setFlushDelay: function(newDelay){ + if(newDelay === null || typeof newDelay === "undefined" || isNaN(newDelay)){ + throw new Error("Invalid argunment: " + newDelay); + } + + dojox.flash.comm.setFlushDelay(String(newDelay)); + }, + + getFlushDelay: function(){ + return Number(dojox.flash.comm.getFlushDelay()); + }, + + flush: function(namespace){ + //FIXME: is this test necessary? Just use !namespace + if(namespace == null || typeof namespace == "undefined"){ + namespace = dojox.storage.DEFAULT_NAMESPACE; + } + dojox.flash.comm.flush(namespace); + }, + + isAvailable: function(){ + return (this._available = !dojo.config["disableFlashStorage"]); + }, + + put: function(key, value, resultsHandler, namespace){ + if(!this.isValidKey(key)){ + throw new Error("Invalid key given: " + key); + } + + if(!namespace){ + namespace = dojox.storage.DEFAULT_NAMESPACE; + } + + if(!this.isValidKey(namespace)){ + throw new Error("Invalid namespace given: " + namespace); + } + + this._statusHandler = resultsHandler; + + // serialize the value; + // handle strings differently so they have better performance + if(dojo.isString(value)){ + value = "string:" + value; + }else{ + value = dojo.toJson(value); + } + + dojox.flash.comm.put(key, value, namespace); + }, + + putMultiple: function(keys, values, resultsHandler, namespace){ + if(!this.isValidKeyArray(keys) || ! values instanceof Array + || keys.length != values.length){ + throw new Error("Invalid arguments: keys = [" + keys + "], values = [" + values + "]"); + } + + if(!namespace){ + namespace = dojox.storage.DEFAULT_NAMESPACE; + } + + if(!this.isValidKey(namespace)){ + throw new Error("Invalid namespace given: " + namespace); + } + + this._statusHandler = resultsHandler; + + // Convert the arguments on strings we can pass along to Flash + var metaKey = keys.join(","); + var lengths = []; + for(var i=0;i
                  ', + + _isNode: function(/* object */wh){ + // summary: + // checks to see if wh is actually a node. + if(typeof Element == "function") { + try{ + return wh instanceof Element; // boolean + }catch(e){} + }else{ + // best-guess + return wh && !isNaN(wh.nodeType); // boolean + } + }, + + _hasParent: function(/*Node*/node){ + // summary: + // returns whether or not node is a child of another node. + return Boolean(node && node.parentNode && this._isNode(node.parentNode)); // boolean + }, + + postCreate: function() { + + // set image + if((this.iconSrc.toLowerCase().substring(this.iconSrc.length-4)==".png")&&(dojo.isIE)&&(dojo.isIE<7)){ + /* we set the id of the new fisheyeListItem to the id of the div defined in the HTML */ + if(this._hasParent(this.imgNode) && this.id != ""){ + var parent = this.imgNode.parentNode; + parent.setAttribute("id", this.id); + } + this.imgNode.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+this.iconSrc+"', sizingMethod='scale')"; + this.imgNode.src = this._blankImgPath.toString(); + }else{ + if(this._hasParent(this.imgNode) && this.id != ""){ + var parent = this.imgNode.parentNode; + parent.setAttribute("id", this.id); + } + this.imgNode.src = this.iconSrc; + } + + // Label + if(this.lblNode){ + this.lblNode.appendChild(document.createTextNode(this.label)); + } + dojo.setSelectable(this.domNode, false); + this.startup(); + }, + + startup: function(){ + this.parent = this.getParent(); + }, + + onMouseOver: function(/*Event*/ e){ + // summary: callback when user moves mouse over this menu item + // in conservative mode, don't activate the menu until user mouses over an icon + if(!this.parent.isOver){ + this.parent._setActive(e); + } + if(this.label != "" ){ + dojo.addClass(this.lblNode, "dojoxFishSelected"); + this.parent._positionLabel(this); + } + }, + + onMouseOut: function(/*Event*/ e){ + // summary: callback when user moves mouse off of this menu item + dojo.removeClass(this.lblNode, "dojoxFishSelected"); + }, + + onClick: function(/*Event*/ e){ + // summary: user overridable callback when user clicks this menu item + } +}); + +} diff --git a/includes/js/dojox/widget/FisheyeList/FisheyeList.css b/includes/js/dojox/widget/FisheyeList/FisheyeList.css new file mode 100644 index 0000000..c9b78a9 --- /dev/null +++ b/includes/js/dojox/widget/FisheyeList/FisheyeList.css @@ -0,0 +1,24 @@ +.dojoxFisheyeListItemLabel { + font-family: Arial, Helvetica, sans-serif; + background-color: #eee; + border: 2px solid #666; + padding: 2px; + text-align: center; + position: absolute; + display: none; + white-space:pre; +} +.dojoxFisheyeListItemLabel.dojoxFishSelected { + display: block; +} +.dojoxFisheyeListItemImage { + border: 0px; + position: absolute; +} +.dojoxFisheyeListItem { + position: absolute; + z-index: 2; +} +.dojoxFisheyeListBar { + position: relative; +} diff --git a/includes/js/dojox/widget/FisheyeList/FisheyeList.css.commented.css b/includes/js/dojox/widget/FisheyeList/FisheyeList.css.commented.css new file mode 100644 index 0000000..82469d8 --- /dev/null +++ b/includes/js/dojox/widget/FisheyeList/FisheyeList.css.commented.css @@ -0,0 +1,28 @@ +.dojoxFisheyeListItemLabel { + font-family: Arial, Helvetica, sans-serif; + background-color: #eee; + border: 2px solid #666; + padding: 2px; + text-align: center; + position: absolute; + display: none; + white-space:pre; +} + +.dojoxFisheyeListItemLabel.dojoxFishSelected { + display: block; +} + +.dojoxFisheyeListItemImage { + border: 0px; + position: absolute; +} + +.dojoxFisheyeListItem { + position: absolute; + z-index: 2; +} + +.dojoxFisheyeListBar { + position: relative; +} diff --git a/includes/js/dojox/widget/FisheyeLite.js b/includes/js/dojox/widget/FisheyeLite.js new file mode 100644 index 0000000..34818ae --- /dev/null +++ b/includes/js/dojox/widget/FisheyeLite.js @@ -0,0 +1,135 @@ +if(!dojo._hasResource["dojox.widget.FisheyeLite"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.widget.FisheyeLite"] = true; +dojo.provide("dojox.widget.FisheyeLite"); +dojo.experimental("dojox.widget.FisheyeLite"); + +dojo.require("dijit._Widget"); +dojo.require("dojox.fx.easing"); + +dojo.declare("dojox.widget.FisheyeLite", + dijit._Widget, + { + // summary: A Light-weight Fisheye Component, or an exhanced version + // of dojo.fx.Toggler ... + // + // description: + // A Simple FisheyeList-like widget which (in the interest of + // performance) relies on well-styled content for positioning, + // and natural page layout for rendering. + // + // use position:absolute/relative nodes to prevent layout + // changes, and use caution when seleting properties to + // scale. Negative scaling works, but some properties + // react poorly to being set to negative values, IE being + // particularly annoying in that regard. + // + // quirk: uses the domNode as the target of the animation + // unless it finds a node class="fisheyeTarget" in the container + // being turned into a FisheyeLite instance + // + // example: + // | // make all the LI's in a node Fisheye's: + // | dojo.query("#node li").forEach(function(n){ + // | new dojox.widget.FisheyeLite({},n); + // | }); + // + // duationIn: Integer + // The time (in ms) the run the show animation + durationIn: 350, + + // easeIn: Function + // An easing function to use for the show animation + easeIn: dojox.fx.easing.backOut, + + // durationOut: Integer + // The Time (in ms) to run the hide animation + durationOut: 1420, + + // easeOut: Function + // An easing function to use for the hide animation + easeOut: dojox.fx.easing.elasticOut, + + // properties: Object + // An object of "property":scale pairs + // defaults to font-size with a scale of 2.75 + properties: { + fontSize: 2.75 + }, + + // unit: String + // Sometimes, you need to specify a unit. Should be part of + // properties attrib, but was trying to shorthand the logic there + unit:"px", + + postCreate: function(){ + + this.inherited(arguments); + this._target = dojo.query(".fisheyeTarget",this.domNode)[0] || this.domNode; + this._makeAnims(); + + this.connect(this.domNode,"onmouseover","show"); + this.connect(this.domNode,"onmouseout","hide"); + this.connect(this._target,"onclick","onClick"); + + }, + + show: function(){ + // summary: + // Show this Fisheye item. + this._runningOut.stop(); + this._runningIn.play(); + }, + + hide: function(){ + // summary: + // Hide this fisheye item on mouse leave + this._runningIn.stop(); + this._runningOut.play(); + }, + + _makeAnims: function(){ + // summary: + // Pre-generate the animations + + // create two properties: objects, one for each "state" + var _in = {}; + var _out = {}; + var cs = dojo.getComputedStyle(this._target); + for(var p in this.properties){ + var v = parseInt(cs[p]); + // note: do not set negative scale for [a list of properties] for IE support + // note: filter:'s are your own issue, too ;) + _out[p] = { end: v, unit:this.unit }; + _in[p] = { end: (this.properties[p]*v), unit:this.unit }; + } + + this._runningIn = dojo.animateProperty({ + node: this._target, + easing: this.easeIn, + duration: this.durationIn, + properties: _in + }); + + this._runningOut = dojo.animateProperty({ + node: this._target, + duration: this.durationOut, + easing: this.easeOut, + properties: _out + }); + + this.connect(this._runningIn,"onEnd",dojo.hitch(this,"onSelected",this)); + }, + + onClick: function(/* Event */e){ + // summary: stub function fired when target is clicked + // connect or override to use. + }, + + onSelected: function(/* Object */e){ + // summary: stub function fired when Fisheye Item is fully visible and + // hovered. connect or override use. + } + +}); + +} diff --git a/includes/js/dojox/widget/Iterator.js b/includes/js/dojox/widget/Iterator.js new file mode 100644 index 0000000..c2f510d --- /dev/null +++ b/includes/js/dojox/widget/Iterator.js @@ -0,0 +1,177 @@ +if(!dojo._hasResource["dojox.widget.Iterator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.widget.Iterator"] = true; +dojo.provide("dojox.widget.Iterator"); +dojo.require("dijit.Declaration"); + +dojo.experimental("dojox.widget.Iterator"); // level: prototype, designed for dijit.chat.demo + +/* + example: + from markup: + | + | + |
                  + |
                  + | ${name} is a ${type} + |
                  + |
                  + + example: + programmatic: + | var store = new dojo.data.ItemFileReadStore({ url: "countries.json" }); + | + | var iter = new dojox.widget.Iterator({ + | store: store, + | template: "" + | }); + | + + example: + programmatic from an array of objects: + | var dataArr = [ + | { name: "foo", valueAttr: "bar" }, + | { name: "thinger", valueAttr: "blah" } + | ]; + | + | var iter = new dojox.widget.Iterator({ + | data: dataArr, + | template: "" + | }); + + example: + programmatic from an array of strings: + | var dataArr = [ + | { name: "foo", valueAttr: "bar" }, + | { name: "thinger", valueAttr: "blah" } + | ]; + | + | var iter = new dojox.widget.Iterator({ + | data: dataArr, + | template: "" + | }); + +*/ + + +dojo.declare("dojox.widget.Iterator", + [ dijit.Declaration ], + { + + constructor: (function(){ + var ctr = 0; + return function(){ + this.attrs = []; + this.children = []; + this.widgetClass = "dojox.widget.Iterator._classes._"+(ctr++); + } + })(), + + start: 0, + fetchMax: 1000, + query: { name: "*" }, + attrs: [], + defaultValue: "", + widgetCtor: null, + dataValues: [], // an array of strings + data: null, // should be a reference to an Array + store: null, + _srcIndex: 0, + _srcParent: null, + + _setSrcIndex: function(s){ + this._srcIndex = 0; + this._srcParent = s.parentNode; + var ts = s; + while(ts.previousSibling){ + this._srcIndex++; + ts = ts.previousSibling; + }; + }, + + postscript: function(p, s){ + // figure out the position of the source node in it's parent + this._setSrcIndex(s); + // this._srcIndex = dojo.query(">", this._srcParent).indexOf(s); + + this.inherited("postscript", arguments); + var wc = this.widgetCtor = dojo.getObject(this.widgetClass); + + this.attrs = dojo.map( + wc.prototype.templateString.match(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g), + function(s){ return s.slice(2, -1); } + ); + dojo.forEach( + this.attrs, + function(m){ wc.prototype[m] = ""; } + ); + this.update(); + }, + + clear: function(){ + if(this.children.length){ + this._setSrcIndex(this.children[0].domNode); + } + dojo.forEach(this.children, "item.destroy();"); + this.children = []; + }, + + update: function(){ + if(this.store){ + // we're executing a query + this.fetch(); + }else{ + // we came from an array of objects. Easier! + this.onDataAvailable(this.data||this.dataValues); + } + }, + + _addItem: function(/*Object*/config, idx){ + if(dojo.isString(config)){ + config = { value: config }; + } + var widget = new this.widgetCtor(config); + this.children.push(widget); + dojo.place(widget.domNode, this._srcParent, this._srcIndex+idx); + }, + + getAttrValuesObj: function(item){ + var obj = {}; + if(dojo.isString(item)){ + dojo.forEach(this.attrs, function(attr){ + obj[attr] = (attr == "value") ? item : this.defaultValue; + }, this); + }else{ + dojo.forEach(this.attrs, function(attr){ + if(this.store){ + obj[attr] = this.store.getValue(item, attr)||this.defaultValue; + }else{ + obj[attr] = item[attr]||this.defaultValue; + } + }, this); + } + return obj; + }, + + onDataAvailable: function(data){ + this.clear(); + // console.debug(data); + dojo.forEach(data, function(item, idx){ + this._addItem(this.getAttrValuesObj(item), idx); + }, this); + }, + + fetch: function(query, start, end){ + this.store.fetch({ + query: query||this.query, + start: start||this.start, + count: end||this.fetchMax, + onComplete: dojo.hitch(this,"onDataAvailable") + }); + } +}); + +dojox.widget.Iterator._classes = {}; + +} diff --git a/includes/js/dojox/widget/Loader.js b/includes/js/dojox/widget/Loader.js new file mode 100644 index 0000000..2493d5a --- /dev/null +++ b/includes/js/dojox/widget/Loader.js @@ -0,0 +1,103 @@ +if(!dojo._hasResource["dojox.widget.Loader"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.widget.Loader"] = true; +dojo.provide("dojox.widget.Loader"); +dojo.experimental("dojox.widget.Loader"); + +dojo.require("dijit._Widget"); +dojo.require("dijit._Templated"); + +dojo.declare("dojox.widget.Loader", [dijit._Widget,dijit._Templated], { + // summary: a configurable global xhr-listener to display + // a loading message during running xhr's or to simply provide + // base-level topic to subscribe to for custom loading messages + + // loadIcon: String + // location to the icon used. + loadIcon: dojo.moduleUrl("dojox.widget.Loader","icons/loading.gif"), + + // loadMessage: String + // string to use for progress loading + loadMessage: 'Loading ...', + + // hasVisuals: Boolean + // true to display a fixed loading message in TR cornder, false to unly provide + // "Loader" topic to subscribe to for your own custom loading message. + hasVisuals: true, + + // attachToPointer + // true to use visual indicator where cursor is + attachToPointer: true, + + // duration: Integer + // time in ms to toggle in/out the visual load indicator + duration: 125, + + // _offset: Integer + // distance in px from the mouse pointer to show attachToPointer avatar + _offset: 16, + + // holder for mousemove connection + _pointerConnect: null, + _xhrStart: null, + _xhrEnd: null, + + templateString: '
                  ' + +' ' + +'
                  ', + + postCreate: function(){ + // summary: setup the loader + + if(!this.hasVisuals){ + this.loadNode.style.display = "none"; // _destroy()? + }else{ + if(this.attachToPointer){ + dojo.removeClass(this.loadNode,"dojoxLoader"); + dojo.addClass(this.loadNode,"dojoxLoaderPointer"); + } + this._hide(); + } + this._setMessage(this.loadMessage); + + // FIXME: create our connections. would be easier, and this might be redundant + // if Deferred published something + this._xhrStart = dojo.connect(dojo,"_ioSetArgs",this,"_show"); + this._xhrEnd = dojo.connect(dojo.Deferred.prototype,"_fire",this,"_hide"); + + }, + + _setMessage: function(/* String */ message){ + // summary: set's the message in the loader + this.loadMessageNode.innerHTML = message; + }, + + _putLoader: function(/* Event */ e){ + // summary: place the floating loading element based on mousemove connection position + dijit.placeOnScreen(this.loadNode,{ x: e.clientX+this._offset, y:e.clientY+this._offset }, ["TL","BR"]); + }, + + _show: function(){ + // summary: publish and show progress indicator + dojo.publish("Loader",[{ message: 'started' }]); + if(this.hasVisuals){ + if(this.attachToPointer){ + this._pointerConnect = dojo.connect(document,"onmousemove",this,"_putLoader"); + } + dojo.fadeIn({ node: this.loadNode, duration:this.duration }).play(); + } + }, + + _hide: function(){ + // summary: publish "xhr ended" and hide progress indicator + dojo.publish("Loader",[{ message: 'ended' }]); + if(this.hasVisuals){ + if(this.attachToPointer){ + dojo.disconnect(this._pointerConnect); + } + dojo.fadeOut({ node: this.loadNode, duration:this.duration }).play(); + } + } + +}); + +} diff --git a/includes/js/dojox/widget/Loader/Loader.css b/includes/js/dojox/widget/Loader/Loader.css new file mode 100644 index 0000000..f209d70 --- /dev/null +++ b/includes/js/dojox/widget/Loader/Loader.css @@ -0,0 +1,24 @@ +.dojoxLoaderPointer { + position:absolute; + z-index:999; +} +.dojoxLoader { + float:right; + position:fixed; + height:25px; + width:100px; + top:0; + right:0; + padding:3px; + border:1px solid #ccc; + background:#fff; + min-width:42px; +} +.dojoxLoaderIcon { + height:22px; width:22px; + vertical-align:middle; +} +.dojoxLoaderMessage { + font:8pt Arial,san-serif; + color:#666; +} diff --git a/includes/js/dojox/widget/Loader/Loader.css.commented.css b/includes/js/dojox/widget/Loader/Loader.css.commented.css new file mode 100644 index 0000000..4b2d19c --- /dev/null +++ b/includes/js/dojox/widget/Loader/Loader.css.commented.css @@ -0,0 +1,27 @@ +.dojoxLoaderPointer { + position:absolute; + z-index:999; +} + +.dojoxLoader { + float:right; + position:fixed; + height:25px; + width:100px; + top:0; + right:0; + padding:3px; + border:1px solid #ccc; + background:#fff; + min-width:42px; +} + +.dojoxLoaderIcon { + height:22px; width:22px; + vertical-align:middle; +} + +.dojoxLoaderMessage { + font:8pt Arial,san-serif; + color:#666; +} diff --git a/includes/js/dojox/widget/Loader/README b/includes/js/dojox/widget/Loader/README new file mode 100644 index 0000000..df6c73d --- /dev/null +++ b/includes/js/dojox/widget/Loader/README @@ -0,0 +1,39 @@ +------------------------------------------------------------------------------- +dojox.widget.Loader +------------------------------------------------------------------------------- +Version 0.1 +Release date: 07/15/2007 +------------------------------------------------------------------------------- +Project state: +prototype / expermental +------------------------------------------------------------------------------- +Credits: Pete Higgins (phiggins@gmail.com) +------------------------------------------------------------------------------- +Description: + a class to indicatie some xhr request + is going on via topics, with optional + eye-candy indicators either offset + from mouse pointer, or in a fixed position + node. + +------------------------------------------------------------------------------- +Dependencies: + widget: none. + test page: to enhance visual effect, a .php + file is used to slowly pass data to an xhr + request. You will need a php-enabled + webserver to view /dojox/tests/test_Loader.html + +------------------------------------------------------------------------------- +Documentation + +------------------------------------------------------------------------------- +Installation instructions + + simply dojo.require("dojox.widget.Loader") and + attach to a div: +
                  + + Configuration options can be found in the API tool. + + diff --git a/includes/js/dojox/widget/Loader/honey.php b/includes/js/dojox/widget/Loader/honey.php new file mode 100644 index 0000000..aeb7776 --- /dev/null +++ b/includes/js/dojox/widget/Loader/honey.php @@ -0,0 +1,27 @@ +"; + $dataSent += $blockSize; + sleep(1); +} + +?> diff --git a/includes/js/dojox/widget/Loader/icons/loading.gif b/includes/js/dojox/widget/Loader/icons/loading.gif new file mode 100644 index 0000000..6e7c8e5 Binary files /dev/null and b/includes/js/dojox/widget/Loader/icons/loading.gif differ diff --git a/includes/js/dojox/widget/MultiComboBox.js b/includes/js/dojox/widget/MultiComboBox.js new file mode 100644 index 0000000..6239d8a --- /dev/null +++ b/includes/js/dojox/widget/MultiComboBox.js @@ -0,0 +1,61 @@ +if(!dojo._hasResource["dojox.widget.MultiComboBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.widget.MultiComboBox"] = true; +dojo.provide("dojox.widget.MultiComboBox"); +dojo.experimental("dojox.widget.MultiComboBox"); +dojo.require("dijit.form.ComboBox"); +dojo.require("dijit.form.ValidationTextBox"); + +dojo.declare("dojox.widget.MultiComboBox", + [dijit.form.ValidationTextBox, dijit.form.ComboBoxMixin],{ + // + // summary: A ComboBox that accpets multiple inputs on a single line? + // + // delimiter: String + // The character to use to separate items in the ComboBox input + delimiter: ",", + _previousMatches: false, + + setValue: function(value){ + if (this.delimiter && value.length != 0){ + value = value+this.delimiter+" "; + arguments[0] = this._addPreviousMatches(value); + } + this.inherited(arguments); + }, + + _addPreviousMatches: function(/* String */text){ + if(this._previousMatches){ + if(!text.match(new RegExp("^"+this._previousMatches))){ + text = this._previousMatches+text; + } + text = this._cleanupDelimiters(text); + } + return text; // String + }, + + _cleanupDelimiters: function(/* String */text){ + if(this.delimiter){ + text = text.replace(new RegExp(" +"), " "); + text = text.replace(new RegExp("^ *"+this.delimiter+"* *"), ""); + text = text.replace(new RegExp(this.delimiter+" *"+this.delimiter), this.delimiter); + } + return text; + }, + + _autoCompleteText: function(/* String */text){ + arguments[0] = this._addPreviousMatches(text); + this.inherited(arguments); + }, + + _startSearch: function(/* String */text){ + text = this._cleanupDelimiters(text); + var re = new RegExp("^.*"+this.delimiter+" *"); + + if(this._previousMatches = text.match(re)){ + arguments[0] = text.replace(re, ""); + } + this.inherited(arguments); + } +}); + +} diff --git a/includes/js/dojox/widget/README b/includes/js/dojox/widget/README new file mode 100644 index 0000000..8e8cb60 --- /dev/null +++ b/includes/js/dojox/widget/README @@ -0,0 +1,84 @@ +------------------------------------------------------------------------------- +dojox.widget Collection +------------------------------------------------------------------------------- +Version 1.0 +Release date: 10/31/2007 +------------------------------------------------------------------------------- +Project state: +experimental | beta +------------------------------------------------------------------------------- +Credits + Peter Higgins (dante) + Karl Tiedt (ktiedt@gmail.com) + Wolfram Kriesing (http://wolfram.kriesing.de/blog/): Rating +------------------------------------------------------------------------------- +Project description + + This is a collection of standalone widgets for use in + your website. Each individual widget is independant + of the others. +------------------------------------------------------------------------------- +Dependencies: + + Each widget has it's own requirements and dependencies. + Most inherit from dijit base-classes such as dijit._Widget, + dijit._Templated, etc ... So we will assume the availablility + of dojo (core), and dijit packages. +------------------------------------------------------------------------------- +Documentation + + Please refer to the API-tool, or in-line documentation. +------------------------------------------------------------------------------- +Installation instructions + + These are standalone Widgets, so putting the [widget].js file + in your dojox/widget folder, and copying any files in the + /dojox/widget/[widget]/ folder as supplements/templates/etc + should be all you need to do. + + eg: FisheyeList: + /dojox/widget/FisheyeList.js + /dojox/widget/FisheyeList/blank.gif + /dojox/widget/FisheyeList/FisheyeList.css + + should be all you need to use the Fisheye widget. + + you can safely import the whole widget project into your + dojox/ root directory from the following SVN url: + + http://svn.dojotoolkit.org/dojo/dojox/widget + +------------------------------------------------------------------------------- +Other Notes (Brief widget list): + + * ColorPicker - Photoshop-like color picker + + * FileInput - experimental dijit-like input type="file" + + * FileInputAuto/Blind - extension to FileInput for + added flair/automation + + * FisheyeList - the classic FishEye Picker + + * Iterator - Basic array and datastore iterator class + + * Loader - an experimental Class that listens to XHR + connections in the background, and displays + a loading indicator. + + * MultiComboBox - an experimental ComboBox that allows + multiple entries bases on a separator character. + + * SortList - a degradable UL with a fixed header, scrolling, + and sorting. Can be the direct descendat of a + LayoutContainer and will size to fit. + + * TimeSpinner - a number spinner that revolves through + time constrainsts + + * Toaster - a messaging system to display non-obstrusive + alerts on screen. + + * Wizard - a StackContainer with built-in navigation to + ease in the creation of 'step-based' content. + Requires dojo >= 1.1 diff --git a/includes/js/dojox/widget/Rating.js b/includes/js/dojox/widget/Rating.js new file mode 100644 index 0000000..8f12d62 --- /dev/null +++ b/includes/js/dojox/widget/Rating.js @@ -0,0 +1,90 @@ +if(!dojo._hasResource["dojox.widget.Rating"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.widget.Rating"] = true; +dojo.provide("dojox.widget.Rating"); + +dojo.require("dijit.form._FormWidget"); + +dojo.declare("dojox.widget.Rating", + dijit.form._FormWidget,{ + // summary: + // A widget for rating using stars. + // + // required: Boolean + // TODO: Can be true or false, default is false. + // required: false, + + templateString: null, + + // numStars: Integer + // The number of stars to show, default is 3. + numStars: 3, + // value: Integer + // The current value of the Rating + value: 0, + + constructor:function(params){ + // Build the templateString. The number of stars is given by this.numStars, + // which is normally an attribute to the widget node. + dojo.mixin(this, params); + + // TODO actually "dijitInline" should be applied to the surrounding div, but FF2 + // screws up when we dojo.query() for the star nodes, it orders them randomly, because of the use + // of display:--moz-inline-box ... very strange bug + // Since using ul and li in combintaion with dijitInline this problem doesnt exist anymore. + + // The focusNode is normally used to store the value, i dont know if that is right here, but seems standard for _FormWidgets + var tpl = '
                  ' + + '
                    ${stars}
                  ' + + '
                  '; + // the value-attribute is used to "read" the value for processing in the widget class --> + var starTpl = '
                1. '; + var rendered = ""; + for(var i = 0; i < this.numStars; i++){ + rendered += dojo.string.substitute(starTpl, {value:i+1}); + } + this.templateString = dojo.string.substitute(tpl, {stars:rendered}); + }, + + postCreate: function(){ + this.inherited(arguments); + this._renderStars(this.value); + }, + + _onMouse: function(evt){ + this.inherited(arguments); + if(this._hovering){ + var hoverValue = +dojo.attr(evt.target, "value"); + this.onMouseOver(evt, hoverValue); + this._renderStars(hoverValue, true); + }else{ + this._renderStars(this.value); + } + }, + + _renderStars: function(value, hover){ + // summary: Render the stars depending on the value. + dojo.query(".dojoxRatingStar", this.domNode).forEach(function(star, i){ + if(i + 1 > value){ + dojo.removeClass(star, "dojoxRatingStarHover"); + dojo.removeClass(star, "dojoxRatingStarChecked"); + }else{ + dojo.removeClass(star, "dojoxRatingStar" + (hover ? "Checked" : "Hover")); + dojo.addClass(star, "dojoxRatingStar" + (hover ? "Hover" : "Checked")); + } + }); + }, + + onStarClick:function(/* Event */evt){ +// TODOC: needs summary + var newVal = +dojo.attr(evt.target, "value"); + this.setAttribute("value", newVal == this.value ? 0 : newVal); + this._renderStars(this.value); + this.onChange(this.value); // Do I have to call this by hand? + }, + + onMouseOver: function(/*evt, value*/){ + // summary: connect here if you like to, the value is passed to this function as the second parameter! + } +}); + +} diff --git a/includes/js/dojox/widget/Rating/Rating.css b/includes/js/dojox/widget/Rating/Rating.css new file mode 100644 index 0000000..f4c0957 --- /dev/null +++ b/includes/js/dojox/widget/Rating/Rating.css @@ -0,0 +1,20 @@ +.dojoxRating ul { + padding:0; + margin:0; +} +.dojoxRatingStar { + display:inline-block; + background-image:url(rating_empty.gif); + background-position:left center; + position:relative; + height:15px; + width:15px; + float:left; +} +.dojoxRatingStarChecked { + background-image:url(rating_full.gif); +} +.dojoxRatingStarHover { + background-image:url(rating_full.gif); + opacity:.5; +} diff --git a/includes/js/dojox/widget/Rating/Rating.css.commented.css b/includes/js/dojox/widget/Rating/Rating.css.commented.css new file mode 100644 index 0000000..5fcdcb4 --- /dev/null +++ b/includes/js/dojox/widget/Rating/Rating.css.commented.css @@ -0,0 +1,24 @@ +.dojoxRating ul { + padding:0; + margin:0; +} + +.dojoxRatingStar { + display:inline-block; + background-image:url(rating_empty.gif); + background-position:left center; + position:relative; + height:15px; + width:15px; + float:left; +} + +.dojoxRatingStarChecked { + background-image:url(rating_full.gif); +} + +.dojoxRatingStarHover { + background-image:url(rating_full.gif); + opacity:.5; +} + diff --git a/includes/js/dojox/widget/Rating/rating_empty.gif b/includes/js/dojox/widget/Rating/rating_empty.gif new file mode 100644 index 0000000..8662c43 Binary files /dev/null and b/includes/js/dojox/widget/Rating/rating_empty.gif differ diff --git a/includes/js/dojox/widget/Rating/rating_empty.png b/includes/js/dojox/widget/Rating/rating_empty.png new file mode 100644 index 0000000..39cd985 Binary files /dev/null and b/includes/js/dojox/widget/Rating/rating_empty.png differ diff --git a/includes/js/dojox/widget/Rating/rating_full.gif b/includes/js/dojox/widget/Rating/rating_full.gif new file mode 100644 index 0000000..6fe24bf Binary files /dev/null and b/includes/js/dojox/widget/Rating/rating_full.gif differ diff --git a/includes/js/dojox/widget/Rating/rating_full.png b/includes/js/dojox/widget/Rating/rating_full.png new file mode 100644 index 0000000..bf4c9f1 Binary files /dev/null and b/includes/js/dojox/widget/Rating/rating_full.png differ diff --git a/includes/js/dojox/widget/Rating/rating_half.png b/includes/js/dojox/widget/Rating/rating_half.png new file mode 100644 index 0000000..1201c85 Binary files /dev/null and b/includes/js/dojox/widget/Rating/rating_half.png differ diff --git a/includes/js/dojox/widget/SortList.js b/includes/js/dojox/widget/SortList.js new file mode 100644 index 0000000..e50ec2b --- /dev/null +++ b/includes/js/dojox/widget/SortList.js @@ -0,0 +1,151 @@ +if(!dojo._hasResource["dojox.widget.SortList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.widget.SortList"] = true; +dojo.provide("dojox.widget.SortList"); +dojo.experimental("dojox.widget.SortList"); // level: prototype, designed for dijit.chat.demo + +dojo.require("dijit.layout._LayoutWidget"); +dojo.require("dijit._Templated"); + +dojo.declare("dojox.widget.SortList", + [dijit.layout._LayoutWidget, dijit._Templated], + { + // summary: A sortable unordered-list with a fixed header for use in dijit.demos.chat + // for demonstration purposes only for now. feel free to make API suggestions + // or fixes. + // + // title: String + // The title in the header + title: "", + + // heading: String + // In the event a parent container is expecting a title="" attribute, set it for the parent + // via title, and the title of this widget via heading="" ... assuming you want different + // titles for each. eg: TabContainer, AccordionContainer, etc. + heading: "", + + // descending: Boolean + // Toggle sort order based on this value. + descending: true, + + // selected: Array + // A list of the selected
                2. nodes at any given time. + selected: null, + + // sortable: Boolean + // toggle to enable/disable sorting + sortable: true, + + // FIXME: this is really simple store support + store: "", + key: "name", + + templateString:"
                  \n\t\t
                  \n\t\t
                  \n\t\t${title}\n\t\t
                  \n\t\t
                  \n\t\t
                    \n\t
                    \n
                    \n", + + _addItem: function(item){ + var node = dojo.doc.createElement("li"); + var text = this.store.getValue(item,this.key); + node.innerHTML = text; + this.containerNode.appendChild(node); + }, + + postCreate: function(){ + if(this.store){ + this.store = dojo.getObject(this.store); + var props = { + onItem: dojo.hitch(this,"_addItem"), + onComplete: dojo.hitch(this,"onSort") + }; + this.store.fetch(props); + }else{ this.onSort(); } + this.inherited(arguments); + }, + + startup: function(){ + this.inherited(arguments); + if(this.heading){ + this.setTitle(this.heading); this.title=this.heading; + } + // we cheat, and give the browser just enough time so we know our height + setTimeout(dojo.hitch(this,"resize"),5); + if (this.sortable){ this.connect(this.titleNode,"onclick", "onSort"); } + }, + + resize: function(){ + // summary: do our additional calculations when resize() is called by or in a parent + this.inherited(arguments); + // FIXME: + // the 10 comes from the difference between the contentBox and calculated height + // because of badding and border extents. this shouldn't be done this way, a theme change will + // break it: but we also don't want to run getComputedStyle or dojo.coords() every time resize() + // is fired. + var offset = ((this._contentBox.h) - (dojo.style(this.titleNode,"height")))-10; + this.bodyWrapper.style.height = Math.abs(offset) + "px"; + }, + + onSort: function(/* Event */e){ + // summary: sort the data, and style the nodes. + + var arr = dojo.query("li",this.domNode); + if (this.sortable){ + this.descending = !this.descending; + dojo.addClass(this.titleNode,((this.descending)?"sortListDesc":"sortListAsc")); + dojo.removeClass(this.titleNode,((this.descending)?"sortListAsc":"sortListDesc")); + arr.sort(this._sorter); + if(this.descending){ arr.reverse(); } + } + var i=0; + dojo.forEach(arr,function(item){ + dojo[(i++)%2 === 0 ? "addClass" : "removeClass"](item,"sortListItemOdd"); + this.containerNode.appendChild(item); + },this); + }, + + _set: function(/* Event */e){ + // summary: set hover state + if(e.target !== this.bodyWrapper){ + dojo.addClass(e.target,"sortListItemHover"); + } + }, + + _unset: function(/* Event */e){ + // summary: remove hover state (FIXME: combine with _set?) + dojo.removeClass(e.target,"sortListItemHover"); + }, + + _handleClick: function(/* Event */e){ + // summary: click listener for data portion of widget. toggle selected state + // of node, and update this.selected array accordingly + dojo.toggleClass(e.target,"sortListItemSelected"); + e.target.focus(); + this._updateValues(e.target.innerHTML); + }, + + _updateValues: function(){ + this._selected = dojo.query("li.sortListItemSelected",this.containerNode); + this.selected = []; + dojo.forEach(this._selected,function(node){ + this.selected.push(node.innerHTML); + },this); + this.onChanged(arguments); + }, + + _sorter: function(a,b){ + // summary: a basic sort function, use query sort, or keep this? + var aStr = a.innerHTML; + var bStr = b.innerHTML; + if(aStr>bStr){ return 1; } + if(aStr +
                    +
                    + ${title} +
                    +
                    +
                      +
                      +
                    • \ No newline at end of file diff --git a/includes/js/dojox/widget/TimeSpinner.js b/includes/js/dojox/widget/TimeSpinner.js new file mode 100644 index 0000000..a60c083 --- /dev/null +++ b/includes/js/dojox/widget/TimeSpinner.js @@ -0,0 +1,48 @@ +if(!dojo._hasResource["dojox.widget.TimeSpinner"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.widget.TimeSpinner"] = true; +dojo.provide("dojox.widget.TimeSpinner"); + +dojo.require("dijit.form._Spinner"); +dojo.require("dijit.form.NumberTextBox"); +dojo.require("dojo.date"); +dojo.require("dojo.date.locale"); +dojo.require("dojo.date.stamp"); + +dojo.declare( +"dojox.widget.TimeSpinner", +[dijit.form._Spinner], +{ + // summary: Time Spinner + // description: This widget is the same as a normal NumberSpinner, but for the time component of a date object instead + + required: false, + + adjust: function(/* Object */ val, /*Number*/ delta){ + return dojo.date.add(val, "minute", delta) + }, + + //FIXME should we allow for constraints in this widget? + isValid: function(){return true;}, + + smallDelta: 5, + + largeDelta: 30, + + timeoutChangeRate: 0.50, + + parse: function(time, locale){ + return dojo.date.locale.parse(time, {selector:"time", formatLength:"short"}); + }, + + format: function(time, locale){ + if (dojo.isString(time)) { return time; } + return dojo.date.locale.format(time, {selector:"time", formatLength:"short"}); + }, + + serialize: dojo.date.stamp.toISOString, + + value: "12:00 AM" + +}); + +} diff --git a/includes/js/dojox/widget/Toaster.js b/includes/js/dojox/widget/Toaster.js new file mode 100644 index 0000000..5505ede --- /dev/null +++ b/includes/js/dojox/widget/Toaster.js @@ -0,0 +1,268 @@ +if(!dojo._hasResource["dojox.widget.Toaster"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.widget.Toaster"] = true; +dojo.provide("dojox.widget.Toaster"); + +dojo.require("dojo.fx"); +dojo.require("dijit._Widget"); +dojo.require("dijit._Templated"); + +dojo.declare("dojox.widget.Toaster", [dijit._Widget, dijit._Templated], { + // summary: + // Message that slides in from the corner of the screen, used for notifications + // like "new email". + + templateString: '
                      ', + + // messageTopic: String + // Name of topic; anything published to this topic will be displayed as a message. + // Message format is either String or an object like + // {message: "hello word", type: "error", duration: 500} + messageTopic: "", + + _uniqueId: 0, + + // messageTypes: Enumeration + // Possible message types. + messageTypes: { + MESSAGE: "message", + WARNING: "warning", + ERROR: "error", + FATAL: "fatal" + }, + + // defaultType: String + // If message type isn't specified (see "messageTopic" parameter), + // then display message as this type. + // Possible values in messageTypes enumeration ("message", "warning", "error", "fatal") + defaultType: "message", + + // positionDirection: String + // Position from which message slides into screen, one of + // ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right"] + positionDirection: "br-up", + + // positionDirectionTypes: Array + // Possible values for positionDirection parameter + positionDirectionTypes: ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right"], + + // duration: Integer + // Number of milliseconds to show message + duration: "2000", + + //separator: String + // String used to separate messages if consecutive calls are made to setContent before previous messages go away + separator: "
                      ", + + postCreate: function(){ + this.inherited(arguments); + this.hide(); + + this.clipNode.className = "dijitToasterClip"; + this.containerNode.className += " dijitToasterContainer"; + this.contentNode.className = "dijitToasterContent"; + if(this.messageTopic){ + dojo.subscribe(this.messageTopic, this, "_handleMessage"); + } + }, + + _handleMessage: function(/*String|Object*/message){ + if(dojo.isString(message)){ + this.setContent(message); + }else{ + this.setContent(message.message, message.type, message.duration); + } + }, + + _capitalize: function(/* String */w){ + return w.substring(0,1).toUpperCase() + w.substring(1); + }, + + setContent: function(/*String*/message, /*String*/messageType, /*int?*/duration){ + // summary: + // sets and displays the given message and show duration + // message: + // the message + // messageType: + // type of message; possible values in messageTypes enumeration ("message", "warning", "error", "fatal") + // duration: + // duration in milliseconds to display message before removing it. Widget has default value. + duration = duration||this.duration; + // sync animations so there are no ghosted fades and such + if(this.slideAnim){ + if(this.slideAnim.status() != "playing"){ + this.slideAnim.stop(); + } + if(this.slideAnim.status() == "playing" || (this.fadeAnim && this.fadeAnim.status() == "playing")){ + setTimeout(dojo.hitch(this, function(){ + this.setContent(message, messageType, duration); + }), 50); + return; + } + } + + // determine type of content and apply appropriately + for(var type in this.messageTypes){ + dojo.removeClass(this.containerNode, "dijitToaster" + this._capitalize(this.messageTypes[type])); + } + + dojo.style(this.containerNode, "opacity", 1); + + if(message && this.isVisible){ + message = this.contentNode.innerHTML + this.separator + message; + } + this.contentNode.innerHTML = message; + + dojo.addClass(this.containerNode, "dijitToaster" + this._capitalize(messageType || this.defaultType)); + + // now do funky animation of widget appearing from + // bottom right of page and up + this.show(); + var nodeSize = dojo.marginBox(this.containerNode); + this._cancelHideTimer(); + if(this.isVisible){ + this._placeClip(); + //update hide timer if no sticky message in stack + if (!this._stickyMessage) + this._setHideTimer(duration); + + }else{ + var style = this.containerNode.style; + var pd = this.positionDirection; + // sets up initial position of container node and slide-out direction + if(pd.indexOf("-up") >= 0){ + style.left=0+"px"; + style.top=nodeSize.h + 10 + "px"; + }else if(pd.indexOf("-left") >= 0){ + style.left=nodeSize.w + 10 +"px"; + style.top=0+"px"; + }else if(pd.indexOf("-right") >= 0){ + style.left = 0 - nodeSize.w - 10 + "px"; + style.top = 0+"px"; + }else if(pd.indexOf("-down") >= 0){ + style.left = 0+"px"; + style.top = 0 - nodeSize.h - 10 + "px"; + }else{ + throw new Error(this.id + ".positionDirection is invalid: " + pd); + } + this.slideAnim = dojo.fx.slideTo({ + node: this.containerNode, + top: 0, left: 0, + duration: 450}); + this.connect(this.slideAnim, "onEnd", function(nodes, anim){ + //we build the fadeAnim here so we dont have to duplicate it later + // can't do a fadeHide because we're fading the + // inner node rather than the clipping node + this.fadeAnim = dojo.fadeOut({ + node: this.containerNode, + duration: 1000}); + this.connect(this.fadeAnim, "onEnd", function(evt){ + this.isVisible = false; + this.hide(); + }); + this._setHideTimer(duration); + this.connect(this, 'onSelect', function(evt){ + this._cancelHideTimer(); + //force clear sticky message + this._stickyMessage=false; + this.fadeAnim.play(); + }); + + this.isVisible = true; + }); + this.slideAnim.play(); + } + }, + + _cancelHideTimer:function(){ + if (this._hideTimer){ + clearTimeout(this._hideTimer); + this._hideTimer=null; + } + }, + + _setHideTimer:function(duration){ + this._cancelHideTimer(); + //if duration == 0 we keep the message displayed until clicked + if(duration>0){ + this._cancelHideTimer(); + this._hideTimer=setTimeout(dojo.hitch(this, function(evt){ + // we must hide the iframe in order to fade + // TODO: figure out how to fade with a BackgroundIframe + if(this.bgIframe && this.bgIframe.iframe){ + this.bgIframe.iframe.style.display="none"; + } + this._hideTimer=null; + //force clear sticky message + this._stickyMessage=false; + this.fadeAnim.play(); + }), duration); + } + else + this._stickyMessage=true; + }, + + _placeClip: function(){ + var view = dijit.getViewport(); + + var nodeSize = dojo.marginBox(this.containerNode); + + var style = this.clipNode.style; + // sets up the size of the clipping node + style.height = nodeSize.h+"px"; + style.width = nodeSize.w+"px"; + + // sets up the position of the clipping node + var pd = this.positionDirection; + if(pd.match(/^t/)){ + style.top = view.t+"px"; + }else if(pd.match(/^b/)){ + style.top = (view.h - nodeSize.h - 2 + view.t)+"px"; + } + if(pd.match(/^[tb]r-/)){ + style.left = (view.w - nodeSize.w - 1 - view.l)+"px"; + }else if(pd.match(/^[tb]l-/)){ + style.left = 0 + "px"; + } + + style.clip = "rect(0px, " + nodeSize.w + "px, " + nodeSize.h + "px, 0px)"; + if(dojo.isIE){ + if(!this.bgIframe){ + this.clipNode.id = "__dojoXToaster_"+this._uniqueId++; + this.bgIframe = new dijit.BackgroundIframe(this.clipNode); + } + var iframe = this.bgIframe.iframe; + if(iframe){ iframe.style.display="block"; } + } + }, + + onSelect: function(/*Event*/e){ + // summary: callback for when user clicks the message + }, + + show: function(){ + // summary: show the Toaster + dojo.style(this.domNode, 'display', 'block'); + + this._placeClip(); + + if(!this._scrollConnected){ + this._scrollConnected = dojo.connect(window, "onscroll", this, this._placeClip); + } + }, + + hide: function(){ + // summary: hide the Toaster + + dojo.style(this.domNode, 'display', 'none'); + + if(this._scrollConnected){ + dojo.disconnect(this._scrollConnected); + this._scrollConnected = false; + } + + dojo.style(this.containerNode, "opacity", 1); + } + } +); + +} diff --git a/includes/js/dojox/widget/Toaster/Toaster.css b/includes/js/dojox/widget/Toaster/Toaster.css new file mode 100644 index 0000000..b898452 --- /dev/null +++ b/includes/js/dojox/widget/Toaster/Toaster.css @@ -0,0 +1,39 @@ + +.dijitToasterContent { + padding:1em; + padding-top:0.25em; + background:#73c74a; +} +.dijitToasterMessage{ + color:#fff; +} +.dijitToasterWarning{ } +.dijitToasterError, +.dijitToasterFatal{ + font-weight:bold; + color:#fff; +} +.dijitToasterWarning .dijitToasterContent{ + padding:1em; + padding-top:0.25em; + background:#d4d943; +} +.dijitToasterError .dijitToasterContent{ + padding:1em; + padding-top:0.25em; + background:#c46600; +} + +.dijitToasterClip { + position: absolute; + z-index: 5000; + overflow: hidden; +} +.dijitToasterContainer { + display: block; + position: absolute; + width: 17.5em; + margin: 0px; + font:0.75em Tahoma, Helvetica, Verdana, Arial; +} + diff --git a/includes/js/dojox/widget/Toaster/Toaster.css.commented.css b/includes/js/dojox/widget/Toaster/Toaster.css.commented.css new file mode 100644 index 0000000..b933063 --- /dev/null +++ b/includes/js/dojox/widget/Toaster/Toaster.css.commented.css @@ -0,0 +1,47 @@ +/* main classes for dojox.widget.Toaster */ + +.dijitToasterContent { + padding:1em; + padding-top:0.25em; + background:#73c74a; +} + +.dijitToasterMessage{ + color:#fff; +} + +.dijitToasterWarning{ } +.dijitToasterError, +.dijitToasterFatal{ + font-weight:bold; + color:#fff; +} + +.dijitToasterWarning .dijitToasterContent{ + padding:1em; + padding-top:0.25em; + background:#d4d943; +} + +.dijitToasterError .dijitToasterContent{ + padding:1em; + padding-top:0.25em; + background:#c46600; +} + +/* imported from dijit.css */ + +.dijitToasterClip { + position: absolute; + z-index: 5000; + overflow: hidden; +} + +.dijitToasterContainer { + display: block; + position: absolute; + width: 17.5em; + margin: 0px; + font:0.75em Tahoma, Helvetica, Verdana, Arial; +} + diff --git a/includes/js/dojox/widget/Wizard.js b/includes/js/dojox/widget/Wizard.js new file mode 100644 index 0000000..b8921b1 --- /dev/null +++ b/includes/js/dojox/widget/Wizard.js @@ -0,0 +1,192 @@ +if(!dojo._hasResource["dojox.widget.Wizard"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.widget.Wizard"] = true; +dojo.provide("dojox.widget.Wizard"); + +dojo.require("dijit.layout.StackContainer"); +dojo.require("dijit.layout.ContentPane"); +dojo.require("dijit.form.Button"); + +dojo.require("dojo.i18n"); +dojo.requireLocalization("dijit", "common", null, "zh,pt,da,tr,ru,de,sv,ja,he,fi,nb,el,ar,ROOT,pt-pt,cs,fr,es,ko,nl,zh-tw,pl,it,hu"); +dojo.requireLocalization("dojox.widget", "Wizard", null, "zh,pt,da,tr,ru,de,sv,ja,he,fi,nb,el,ar,pt-pt,cs,fr,es,nl,ko,zh-tw,ROOT,pl,it,hu"); + +dojo.declare( + "dojox.widget.WizardContainer", + [dijit.layout.StackContainer,dijit._Templated], + { + // summary: + // A set of panels that display sequentially, typically notating a step-by-step + // procedure like an install + // + + widgetsInTemplate: true, + templateString:"
                      \n
                      \n
                      \n \n \n \n \n
                      \n
                      \n", + + // nextButtonLabel: String + // Label override for the "Next" button. + nextButtonLabel: "", + + // previousButtonLabel: String + // Label override for the "Previous" button. + previousButtonLabel: "", + + // cancelButtonLabel: String + // Label override for the "Cancel" button. + cancelButtonLabel: "", + + // doneButtonLabel: String + // Label override for the "Done" button. + doneButtonLabel: "", + + // cancelFunction: FunctionName + // Name of function to call if user presses cancel button. + // Cancel button is not displayed if function is not specified. + cancelFunction: "", + + // hideDisabled: Boolean + // If true, disabled buttons are hidden; otherwise, they are assigned the + // "WizardButtonDisabled" CSS class + hideDisabled: false, + + postMixInProperties: function(){ + this.inherited(arguments); + var labels = dojo.mixin({cancel: dojo.i18n.getLocalization("dijit", "common", this.lang).buttonCancel}, + dojo.i18n.getLocalization("dojox.widget", "Wizard", this.lang)); + for(prop in labels){ + if(!this[prop + "ButtonLabel"]){ + this[prop + "ButtonLabel"] = labels[prop]; + } + } + }, + + startup: function(){ + this.inherited(arguments); + + this.connect(this.nextButton, "onClick", "_forward"); + this.connect(this.previousButton, "onClick", "back"); + + if(this.cancelFunction){ + this.cancelFunction = dojo.getObject(this.cancelFunction); + this.connect(this.cancelButton, "onClick", this.cancelFunction); + }else{ + this.cancelButton.domNode.style.display = "none"; + } + this.connect(this.doneButton, "onClick", "done"); + + this._subscription = dojo.subscribe(this.id+"-selectChild", dojo.hitch(this,"_checkButtons")); + this._checkButtons(); + }, + + _checkButtons: function(){ + + var sw = this.selectedChildWidget; + + var lastStep = sw.isLastChild; + this.nextButton.setAttribute("disabled", lastStep); + this._setButtonClass(this.nextButton); + if(sw.doneFunction){ + this.doneButton.domNode.style.display = ""; + if(lastStep){ + this.nextButton.domNode.style.display = "none"; + } + }else{ + // #1438 issue here. + this.doneButton.domNode.style.display = "none"; + } + this.previousButton.setAttribute("disabled", !this.selectedChildWidget.canGoBack); + this._setButtonClass(this.previousButton); + }, + + _setButtonClass: function(button){ + button.domNode.style.display = (this.hideDisabled && button.disabled) ? "none" : ""; + }, + + _forward: function(){ + // summary: callback when next button is clicked + if(this.selectedChildWidget._checkPass()){ + this.forward(); + } + }, + + done: function(){ + // summary: Finish the wizard's operation + this.selectedChildWidget.done(); + }, + + destroy: function(){ + dojo.unsubscribe(this._subscription); + this.inherited(arguments); + } +}); + +dojo.declare( + "dojox.widget.WizardPane", + dijit.layout.ContentPane, + { + // summary: a panel in a WizardContainer + // + // description: + // An extended ContentPane with additional hooks for passing named + // functions to prevent the pane from going either forward or + // backwards. + // + // canGoBack: Boolean + // If true, then can move back to a previous panel (by clicking the "Previous" button) + canGoBack: true, + + // passFunction: String + // Name of function that checks if it's OK to advance to the next panel. + // If it's not OK (for example, mandatory field hasn't been entered), then + // returns an error message (String) explaining the reason. + passFunction: "", + + // doneFunction: String + // Name of function that is run if you press the "Done" button from this panel + doneFunction: "", + + postMixInProperties: function(){ + if(this.passFunction){ + this.passFunction = dojo.getObject(this.passFunction); + } + if(this.doneFunction){ + this.doneFunction = dojo.getObject(this.doneFunction); + } + this.inherited(arguments); + }, + + startup: function(){ + this.inherited(arguments); + if(this.isFirstChild){ this.canGoBack = false; } + }, + + _checkPass: function(){ + // summary: + // Called when the user presses the "next" button. + // Calls passFunction to see if it's OK to advance to next panel, and + // if it isn't, then display error. + // Returns true to advance, false to not advance. + var r = true; + if(this.passFunction && dojo.isFunction(this.passFunction)){ + var failMessage = this.passFunction(); + switch(typeof failMessage){ + case "boolean": + r = failMessage; + break; + case "string": + alert(failMessage); + r = false; + break; + } + } + return r; + }, + + done: function(){ + if(this.doneFunction && dojo.isFunction(this.doneFunction)){ + this.doneFunction(); + } + } + +}); + +} diff --git a/includes/js/dojox/widget/Wizard/Wizard.css b/includes/js/dojox/widget/Wizard/Wizard.css new file mode 100644 index 0000000..f1a9177 --- /dev/null +++ b/includes/js/dojox/widget/Wizard/Wizard.css @@ -0,0 +1,19 @@ +.dojoxWizard { + position:relative; +} +.dojoxWizardButtons { + position:absolute; + bottom:5px; + right:5px; +} +.tundra .dojoxWizard { + background: #eeeeee; + border: #b7b7b7 1px solid; + padding: 2px; + -moz-border-radius:3pt; + -webkit-border-radius:4pt; +} +.soria .dojoxWizard { + border:1px solid #b7b7b7; + padding:2px; +} diff --git a/includes/js/dojox/widget/Wizard/Wizard.css.commented.css b/includes/js/dojox/widget/Wizard/Wizard.css.commented.css new file mode 100644 index 0000000..61340f5 --- /dev/null +++ b/includes/js/dojox/widget/Wizard/Wizard.css.commented.css @@ -0,0 +1,22 @@ +.dojoxWizard { + position:relative; +} + +.dojoxWizardButtons { + position:absolute; + bottom:5px; + right:5px; +} + +.tundra .dojoxWizard { + background: #eeeeee; + border: #b7b7b7 1px solid; + padding: 2px; + -moz-border-radius:3pt; + -webkit-border-radius:4pt; +} + +.soria .dojoxWizard { + border:1px solid #b7b7b7; + padding:2px; +} diff --git a/includes/js/dojox/widget/Wizard/Wizard.html b/includes/js/dojox/widget/Wizard/Wizard.html new file mode 100644 index 0000000..1ae6a1e --- /dev/null +++ b/includes/js/dojox/widget/Wizard/Wizard.html @@ -0,0 +1,9 @@ +
                      +
                      +
                      + + + + +
                      +
                      diff --git a/includes/js/dojox/widget/nls/Wizard.js b/includes/js/dojox/widget/nls/Wizard.js new file mode 100644 index 0000000..ec10f3f --- /dev/null +++ b/includes/js/dojox/widget/nls/Wizard.js @@ -0,0 +1 @@ +({"next":"Next","done":"Done","previous":"Previous"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/ar/Wizard.js b/includes/js/dojox/widget/nls/ar/Wizard.js new file mode 100644 index 0000000..66209a5 --- /dev/null +++ b/includes/js/dojox/widget/nls/ar/Wizard.js @@ -0,0 +1 @@ +({"next":"تالي","done":"اتمام","previous":"سابق"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/cs/Wizard.js b/includes/js/dojox/widget/nls/cs/Wizard.js new file mode 100644 index 0000000..4075772 --- /dev/null +++ b/includes/js/dojox/widget/nls/cs/Wizard.js @@ -0,0 +1 @@ +({"next":"Další","done":"Hotovo","previous":"Předchozí"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/da/Wizard.js b/includes/js/dojox/widget/nls/da/Wizard.js new file mode 100644 index 0000000..a3b161f --- /dev/null +++ b/includes/js/dojox/widget/nls/da/Wizard.js @@ -0,0 +1 @@ +({"next":"Næste","done":"Udført","previous":"Foregående"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/de/Wizard.js b/includes/js/dojox/widget/nls/de/Wizard.js new file mode 100644 index 0000000..a7f2164 --- /dev/null +++ b/includes/js/dojox/widget/nls/de/Wizard.js @@ -0,0 +1 @@ +({"next":"Weiter","done":"Fertig","previous":"Zurück"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/el/Wizard.js b/includes/js/dojox/widget/nls/el/Wizard.js new file mode 100644 index 0000000..6a25346 --- /dev/null +++ b/includes/js/dojox/widget/nls/el/Wizard.js @@ -0,0 +1 @@ +({"next":"Επόμενο","done":"Ολοκλήρωση","previous":"Προηγούμενο"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/es/Wizard.js b/includes/js/dojox/widget/nls/es/Wizard.js new file mode 100644 index 0000000..aab5661 --- /dev/null +++ b/includes/js/dojox/widget/nls/es/Wizard.js @@ -0,0 +1 @@ +({"next":"Siguiente","done":"Terminado","previous":"Anterior"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/fi/Wizard.js b/includes/js/dojox/widget/nls/fi/Wizard.js new file mode 100644 index 0000000..ea6a9db --- /dev/null +++ b/includes/js/dojox/widget/nls/fi/Wizard.js @@ -0,0 +1 @@ +({"next":"Seuraava","done":"Valmis","previous":"Edellinen"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/fr/Wizard.js b/includes/js/dojox/widget/nls/fr/Wizard.js new file mode 100644 index 0000000..779919e --- /dev/null +++ b/includes/js/dojox/widget/nls/fr/Wizard.js @@ -0,0 +1 @@ +({"next":"Suivant","done":"Terminé","previous":"Précédent"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/he/Wizard.js b/includes/js/dojox/widget/nls/he/Wizard.js new file mode 100644 index 0000000..e5ee2ee --- /dev/null +++ b/includes/js/dojox/widget/nls/he/Wizard.js @@ -0,0 +1 @@ +({"next":"הבא","done":"סיום","previous":"הקודם"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/hu/Wizard.js b/includes/js/dojox/widget/nls/hu/Wizard.js new file mode 100644 index 0000000..6ad86c7 --- /dev/null +++ b/includes/js/dojox/widget/nls/hu/Wizard.js @@ -0,0 +1 @@ +({"next":"Következő","done":"Kész","previous":"Előző"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/it/Wizard.js b/includes/js/dojox/widget/nls/it/Wizard.js new file mode 100644 index 0000000..78ea64b --- /dev/null +++ b/includes/js/dojox/widget/nls/it/Wizard.js @@ -0,0 +1 @@ +({"next":"Successivo","done":"Eseguito","previous":"Precedente"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/ja/Wizard.js b/includes/js/dojox/widget/nls/ja/Wizard.js new file mode 100644 index 0000000..6394cb3 --- /dev/null +++ b/includes/js/dojox/widget/nls/ja/Wizard.js @@ -0,0 +1 @@ +({"next":"次へ","done":"完了","previous":"前へ"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/ko/Wizard.js b/includes/js/dojox/widget/nls/ko/Wizard.js new file mode 100644 index 0000000..dec3546 --- /dev/null +++ b/includes/js/dojox/widget/nls/ko/Wizard.js @@ -0,0 +1 @@ +({"next":"다음","done":"완료","previous":"이전"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/nb/Wizard.js b/includes/js/dojox/widget/nls/nb/Wizard.js new file mode 100644 index 0000000..0cbe813 --- /dev/null +++ b/includes/js/dojox/widget/nls/nb/Wizard.js @@ -0,0 +1 @@ +({"next":"Neste","done":"Ferdig","previous":"Forrige"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/nl/Wizard.js b/includes/js/dojox/widget/nls/nl/Wizard.js new file mode 100644 index 0000000..d5e680f --- /dev/null +++ b/includes/js/dojox/widget/nls/nl/Wizard.js @@ -0,0 +1 @@ +({"next":"Volgende","done":"Klaar","previous":"Vorige"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/pl/Wizard.js b/includes/js/dojox/widget/nls/pl/Wizard.js new file mode 100644 index 0000000..c7dc6a1 --- /dev/null +++ b/includes/js/dojox/widget/nls/pl/Wizard.js @@ -0,0 +1 @@ +({"next":"Dalej","done":"Gotowe","previous":"Wstecz"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/pt-pt/Wizard.js b/includes/js/dojox/widget/nls/pt-pt/Wizard.js new file mode 100644 index 0000000..2b6bb1e --- /dev/null +++ b/includes/js/dojox/widget/nls/pt-pt/Wizard.js @@ -0,0 +1 @@ +({"next":"Seguinte","done":"Concluído","previous":"Anterior"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/pt/Wizard.js b/includes/js/dojox/widget/nls/pt/Wizard.js new file mode 100644 index 0000000..1840985 --- /dev/null +++ b/includes/js/dojox/widget/nls/pt/Wizard.js @@ -0,0 +1 @@ +({"next":"Avançar","done":"Concluído","previous":"Voltar"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/ru/Wizard.js b/includes/js/dojox/widget/nls/ru/Wizard.js new file mode 100644 index 0000000..bbc1b51 --- /dev/null +++ b/includes/js/dojox/widget/nls/ru/Wizard.js @@ -0,0 +1 @@ +({"next":"Далее","done":"Готово","previous":"Назад"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/sv/Wizard.js b/includes/js/dojox/widget/nls/sv/Wizard.js new file mode 100644 index 0000000..ae75b03 --- /dev/null +++ b/includes/js/dojox/widget/nls/sv/Wizard.js @@ -0,0 +1 @@ +({"next":"Nästa","done":"Stäng","previous":"Föregående"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/tr/Wizard.js b/includes/js/dojox/widget/nls/tr/Wizard.js new file mode 100644 index 0000000..752b8ac --- /dev/null +++ b/includes/js/dojox/widget/nls/tr/Wizard.js @@ -0,0 +1 @@ +({"next":"İleri","done":"Bitti","previous":"Geri"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/zh-tw/Wizard.js b/includes/js/dojox/widget/nls/zh-tw/Wizard.js new file mode 100644 index 0000000..fe45203 --- /dev/null +++ b/includes/js/dojox/widget/nls/zh-tw/Wizard.js @@ -0,0 +1 @@ +({"next":"下一步","done":"完成","previous":"上一步"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/nls/zh/Wizard.js b/includes/js/dojox/widget/nls/zh/Wizard.js new file mode 100644 index 0000000..fe45203 --- /dev/null +++ b/includes/js/dojox/widget/nls/zh/Wizard.js @@ -0,0 +1 @@ +({"next":"下一步","done":"完成","previous":"上一步"}) \ No newline at end of file diff --git a/includes/js/dojox/widget/tests/_tags.json b/includes/js/dojox/widget/tests/_tags.json new file mode 100644 index 0000000..421031a --- /dev/null +++ b/includes/js/dojox/widget/tests/_tags.json @@ -0,0 +1,100 @@ +{identifier:"tag", +items: [ + {tag: "accounting"}, + {tag: "attorney"}, + {tag: "atv"}, + {tag: "backcountry"}, + {tag: "bakery"}, + {tag: "bandb"}, + {tag: "bank"}, + {tag: "bar"}, + {tag: "bicycle"}, + {tag: "cabin"}, + {tag: "cabinoutside"}, + {tag: "camp"}, + {tag: "campoutside"}, + {tag: "catering"}, + {tag: "chamber"}, + {tag: "church"}, + {tag: "city"}, + {tag: "classes"}, + {tag: "coffeehouse"}, + {tag: "condo"}, + {tag: "condooutside"}, + {tag: "conference"}, + {tag: "county"}, + {tag: "crosscountryski"}, + {tag: "dentist"}, + {tag: "dining"}, + {tag: "fishing"}, + {tag: "gallery"}, + {tag: "general"}, + {tag: "golf"}, + {tag: "graphicart"}, + {tag: "grocery"}, + {tag: "guideservice"}, + {tag: "hair"}, + {tag: "health"}, + {tag: "home"}, + {tag: "homeoutside"}, + {tag: "horse"}, + {tag: "hotel"}, + {tag: "hoteloutside"}, + {tag: "hotsprings"}, + {tag: "hotspringspool"}, + {tag: "hunting"}, + {tag: "iceclimbing"}, + {tag: "iceskating"}, + {tag: "inspection"}, + {tag: "insurance"}, + {tag: "internet"}, + {tag: "jeeping"}, + {tag: "jewelry"}, + {tag: "live"}, + {tag: "liveentertainment"}, + {tag: "lodging"}, + {tag: "manicure"}, + {tag: "manufacturing"}, + {tag: "maps"}, + {tag: "massage"}, + {tag: "menu:aboutouray"}, + {tag: "menu:recreation"}, + {tag: "minetour"}, + {tag: "mining"}, + {tag: "mountaineering"}, + {tag: "museum"}, + {tag: "nonprofit"}, + {tag: "offroad"}, + {tag: "online"}, + {tag: "ouraymuseum"}, + {tag: "park"}, + {tag: "performingarts"}, + {tag: "pet"}, + {tag: "pharmacy"}, + {tag: "photographer"}, + {tag: "photography"}, + {tag: "printing"}, + {tag: "publishing"}, + {tag: "rafting"}, + {tag: "railroad"}, + {tag: "realestate"}, + {tag: "recreation"}, + {tag: "rentals"}, + {tag: "retail"}, + {tag: "rockclimbing"}, + {tag: "rv"}, + {tag: "rvoutside"}, + {tag: "school"}, + {tag: "shop"}, + {tag: "skirentals"}, + {tag: "snowmobiling"}, + {tag: "spa"}, + {tag: "summer"}, + {tag: "tours"}, + {tag: "trails"}, + {tag: "utility"}, + {tag: "waterfall"}, + {tag: "wedding"}, + {tag: "weddingplanner"}, + {tag: "winter"} +]} diff --git a/includes/js/dojox/widget/tests/demo_FisheyeList-orig.html b/includes/js/dojox/widget/tests/demo_FisheyeList-orig.html new file mode 100644 index 0000000..a36d32c --- /dev/null +++ b/includes/js/dojox/widget/tests/demo_FisheyeList-orig.html @@ -0,0 +1,111 @@ + + + + FisheyeList Widget Demonstration + + + + + +
                      +
                      +
                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      +
                      + +
                      +

                      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nam facilisis enim. Pellentesque in elit et lacus euismod dignissim. Aliquam dolor pede, convallis eget, dictum a, blandit ac, urna. Pellentesque sed nunc ut justo volutpat egestas. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. In erat. Suspendisse potenti. Fusce faucibus nibh sed nisi. Phasellus faucibus, dui a cursus dapibus, mauris nulla euismod velit, a lobortis turpis arcu vel dui. Pellentesque fermentum ultrices pede. Donec auctor lectus eu arcu. Curabitur non orci eget est porta gravida. Aliquam pretium orci id nisi. Duis faucibus, mi non adipiscing venenatis, erat urna aliquet elit, eu fringilla lacus tellus quis erat. Nam tempus ornare lorem. Nullam feugiat.

                      + +

                      Sed congue. Aenean blandit sollicitudin mi. Maecenas pellentesque. Vivamus ac urna. Nunc consequat nisi vitae quam. Suspendisse sed nunc. Proin suscipit porta magna. Duis accumsan nunc in velit. Nam et nibh. Nulla facilisi. Cras venenatis urna et magna. Aenean magna mauris, bibendum sit amet, semper quis, aliquet nec, sapien. Aliquam aliquam odio quis erat. Etiam est nisi, condimentum non, lacinia ac, vehicula laoreet, elit. Sed interdum augue sit amet quam dapibus semper. Nulla facilisi. Pellentesque lobortis erat nec quam.

                      + +

                      Sed arcu magna, molestie at, fringilla in, sodales eu, elit. Curabitur mattis lorem et est. Quisque et tortor. Integer bibendum vulputate odio. Nam nec ipsum. Vestibulum mollis eros feugiat augue. Integer fermentum odio lobortis odio. Nullam mollis nisl non metus. Maecenas nec nunc eget pede ultrices blandit. Ut non purus ut elit convallis eleifend. Fusce tincidunt, justo quis tempus euismod, magna nulla viverra libero, sit amet lacinia odio diam id risus. Ut varius viverra turpis. Morbi urna elit, imperdiet eu, porta ac, pharetra sed, nisi. Etiam ante libero, ultrices ac, faucibus ac, cursus sodales, nisl. Praesent nisl sem, fermentum eu, consequat quis, varius interdum, nulla. Donec neque tortor, sollicitudin sed, consequat nec, facilisis sit amet, orci. Aenean ut eros sit amet ante pharetra interdum.

                      + +

                      Fusce rutrum pede eget quam. Praesent purus. Aenean at elit in sem volutpat facilisis. Nunc est augue, commodo at, pretium a, fermentum at, quam. Nam sit amet enim. Suspendisse potenti. Cras hendrerit rhoncus justo. Integer libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Sed adipiscing mi vel ipsum.

                      + +

                      Sed aliquam, quam consectetuer condimentum bibendum, neque libero commodo metus, non consectetuer magna risus vitae eros. Pellentesque mollis augue id libero. Morbi nonummy hendrerit dui. Morbi nisi felis, fringilla ac, euismod vitae, dictum mollis, pede. Integer suscipit, est sed posuere ullamcorper, ipsum lectus interdum nunc, quis blandit erat eros hendrerit pede. Vestibulum varius, elit id mattis mattis, nulla est feugiat ante, eget vestibulum augue eros ut odio. Maecenas euismod purus quis felis. Ut hendrerit tincidunt est. Fusce euismod, nunc eu tempus tempor, purus ligula volutpat tellus, nec lacinia sapien enim id risus. Aliquam orci turpis, condimentum sed, sollicitudin vel, placerat in, purus. Proin tortor nisl, blandit quis, imperdiet quis, scelerisque at, nisl. Maecenas suscipit fringilla erat. Curabitur consequat, dui blandit suscipit dictum, felis lectus imperdiet tellus, sit amet ornare risus mauris non ipsum. Fusce a purus. Vestibulum sodales. Sed porta ultrices nibh. Vestibulum metus.

                      + + +
                      + + + + + diff --git a/includes/js/dojox/widget/tests/demo_FisheyeList.html b/includes/js/dojox/widget/tests/demo_FisheyeList.html new file mode 100644 index 0000000..703fc55 --- /dev/null +++ b/includes/js/dojox/widget/tests/demo_FisheyeList.html @@ -0,0 +1,117 @@ + + + + FisheyeList Widget Demonstration + + + + + +
                      +
                      + + + + + + + + + + + +
                      + +
                      +

                      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nam facilisis enim. Pellentesque in elit et lacus euismod dignissim. Aliquam dolor pede, convallis eget, dictum a, blandit ac, urna. Pellentesque sed nunc ut justo volutpat egestas. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. In erat. Suspendisse potenti. Fusce faucibus nibh sed nisi. Phasellus faucibus, dui a cursus dapibus, mauris nulla euismod velit, a lobortis turpis arcu vel dui. Pellentesque fermentum ultrices pede. Donec auctor lectus eu arcu. Curabitur non orci eget est porta gravida. Aliquam pretium orci id nisi. Duis faucibus, mi non adipiscing venenatis, erat urna aliquet elit, eu fringilla lacus tellus quis erat. Nam tempus ornare lorem. Nullam feugiat.

                      + +

                      Sed congue. Aenean blandit sollicitudin mi. Maecenas pellentesque. Vivamus ac urna. Nunc consequat nisi vitae quam. Suspendisse sed nunc. Proin suscipit porta magna. Duis accumsan nunc in velit. Nam et nibh. Nulla facilisi. Cras venenatis urna et magna. Aenean magna mauris, bibendum sit amet, semper quis, aliquet nec, sapien. Aliquam aliquam odio quis erat. Etiam est nisi, condimentum non, lacinia ac, vehicula laoreet, elit. Sed interdum augue sit amet quam dapibus semper. Nulla facilisi. Pellentesque lobortis erat nec quam.

                      + +

                      Sed arcu magna, molestie at, fringilla in, sodales eu, elit. Curabitur mattis lorem et est. Quisque et tortor. Integer bibendum vulputate odio. Nam nec ipsum. Vestibulum mollis eros feugiat augue. Integer fermentum odio lobortis odio. Nullam mollis nisl non metus. Maecenas nec nunc eget pede ultrices blandit. Ut non purus ut elit convallis eleifend. Fusce tincidunt, justo quis tempus euismod, magna nulla viverra libero, sit amet lacinia odio diam id risus. Ut varius viverra turpis. Morbi urna elit, imperdiet eu, porta ac, pharetra sed, nisi. Etiam ante libero, ultrices ac, faucibus ac, cursus sodales, nisl. Praesent nisl sem, fermentum eu, consequat quis, varius interdum, nulla. Donec neque tortor, sollicitudin sed, consequat nec, facilisis sit amet, orci. Aenean ut eros sit amet ante pharetra interdum.

                      + +

                      Fusce rutrum pede eget quam. Praesent purus. Aenean at elit in sem volutpat facilisis. Nunc est augue, commodo at, pretium a, fermentum at, quam. Nam sit amet enim. Suspendisse potenti. Cras hendrerit rhoncus justo. Integer libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Sed adipiscing mi vel ipsum.

                      + +

                      Sed aliquam, quam consectetuer condimentum bibendum, neque libero commodo metus, non consectetuer magna risus vitae eros. Pellentesque mollis augue id libero. Morbi nonummy hendrerit dui. Morbi nisi felis, fringilla ac, euismod vitae, dictum mollis, pede. Integer suscipit, est sed posuere ullamcorper, ipsum lectus interdum nunc, quis blandit erat eros hendrerit pede. Vestibulum varius, elit id mattis mattis, nulla est feugiat ante, eget vestibulum augue eros ut odio. Maecenas euismod purus quis felis. Ut hendrerit tincidunt est. Fusce euismod, nunc eu tempus tempor, purus ligula volutpat tellus, nec lacinia sapien enim id risus. Aliquam orci turpis, condimentum sed, sollicitudin vel, placerat in, purus. Proin tortor nisl, blandit quis, imperdiet quis, scelerisque at, nisl. Maecenas suscipit fringilla erat. Curabitur consequat, dui blandit suscipit dictum, felis lectus imperdiet tellus, sit amet ornare risus mauris non ipsum. Fusce a purus. Vestibulum sodales. Sed porta ultrices nibh. Vestibulum metus.

                      + + +
                      + + + + + diff --git a/includes/js/dojox/widget/tests/demo_FisheyeLite.html b/includes/js/dojox/widget/tests/demo_FisheyeLite.html new file mode 100644 index 0000000..e937698 --- /dev/null +++ b/includes/js/dojox/widget/tests/demo_FisheyeLite.html @@ -0,0 +1,175 @@ + + + + A responsive Fisheye-like FisheyeLite widget | The Dojo Toolkit + + + + + + + + +
                      +
                      +

                      The Dojo Toolkit:

                      +
                      + +
                      +
                      +
                      + Dojo Pane +
                      +
                      +
                      +
                      + Dijit Pane +
                      +
                      +
                      +
                      + DojoX Pane +
                      +
                      +
                      +
                      + + + \ No newline at end of file diff --git a/includes/js/dojox/widget/tests/images/fisheye_1.png b/includes/js/dojox/widget/tests/images/fisheye_1.png new file mode 100644 index 0000000..7499dcc Binary files /dev/null and b/includes/js/dojox/widget/tests/images/fisheye_1.png differ diff --git a/includes/js/dojox/widget/tests/images/fisheye_2.png b/includes/js/dojox/widget/tests/images/fisheye_2.png new file mode 100644 index 0000000..2db041b Binary files /dev/null and b/includes/js/dojox/widget/tests/images/fisheye_2.png differ diff --git a/includes/js/dojox/widget/tests/images/fisheye_3.png b/includes/js/dojox/widget/tests/images/fisheye_3.png new file mode 100644 index 0000000..5d9cc09 Binary files /dev/null and b/includes/js/dojox/widget/tests/images/fisheye_3.png differ diff --git a/includes/js/dojox/widget/tests/images/fisheye_4.png b/includes/js/dojox/widget/tests/images/fisheye_4.png new file mode 100644 index 0000000..4e74550 Binary files /dev/null and b/includes/js/dojox/widget/tests/images/fisheye_4.png differ diff --git a/includes/js/dojox/widget/tests/images/icon_browser.png b/includes/js/dojox/widget/tests/images/icon_browser.png new file mode 100644 index 0000000..72fae26 Binary files /dev/null and b/includes/js/dojox/widget/tests/images/icon_browser.png differ diff --git a/includes/js/dojox/widget/tests/images/icon_calendar.png b/includes/js/dojox/widget/tests/images/icon_calendar.png new file mode 100644 index 0000000..d9e9a22 Binary files /dev/null and b/includes/js/dojox/widget/tests/images/icon_calendar.png differ diff --git a/includes/js/dojox/widget/tests/images/icon_email.png b/includes/js/dojox/widget/tests/images/icon_email.png new file mode 100644 index 0000000..899dfa5 Binary files /dev/null and b/includes/js/dojox/widget/tests/images/icon_email.png differ diff --git a/includes/js/dojox/widget/tests/images/icon_texteditor.png b/includes/js/dojox/widget/tests/images/icon_texteditor.png new file mode 100644 index 0000000..ced8c14 Binary files /dev/null and b/includes/js/dojox/widget/tests/images/icon_texteditor.png differ diff --git a/includes/js/dojox/widget/tests/images/icon_update.png b/includes/js/dojox/widget/tests/images/icon_update.png new file mode 100644 index 0000000..b741cd0 Binary files /dev/null and b/includes/js/dojox/widget/tests/images/icon_update.png differ diff --git a/includes/js/dojox/widget/tests/images/icon_users.png b/includes/js/dojox/widget/tests/images/icon_users.png new file mode 100644 index 0000000..569e712 Binary files /dev/null and b/includes/js/dojox/widget/tests/images/icon_users.png differ diff --git a/includes/js/dojox/widget/tests/images/rating_empty.gif b/includes/js/dojox/widget/tests/images/rating_empty.gif new file mode 100644 index 0000000..dc6ecd8 Binary files /dev/null and b/includes/js/dojox/widget/tests/images/rating_empty.gif differ diff --git a/includes/js/dojox/widget/tests/images/rating_empty.png b/includes/js/dojox/widget/tests/images/rating_empty.png new file mode 100644 index 0000000..3515d1a Binary files /dev/null and b/includes/js/dojox/widget/tests/images/rating_empty.png differ diff --git a/includes/js/dojox/widget/tests/images/rating_full.gif b/includes/js/dojox/widget/tests/images/rating_full.gif new file mode 100644 index 0000000..2e816a8 Binary files /dev/null and b/includes/js/dojox/widget/tests/images/rating_full.gif differ diff --git a/includes/js/dojox/widget/tests/images/rating_full.png b/includes/js/dojox/widget/tests/images/rating_full.png new file mode 100644 index 0000000..86fb2e0 Binary files /dev/null and b/includes/js/dojox/widget/tests/images/rating_full.png differ diff --git a/includes/js/dojox/widget/tests/test_ColorPicker.html b/includes/js/dojox/widget/tests/test_ColorPicker.html new file mode 100644 index 0000000..87d173e --- /dev/null +++ b/includes/js/dojox/widget/tests/test_ColorPicker.html @@ -0,0 +1,41 @@ + + + + Dojox ColorPicker Test + + + + + + + + +

                      Dojox ColorPicker test

                      + +

                      defaults:

                      +
                      + +

                      no animation, no hsv, no rgb, no webSafe info:

                      +
                      + + + diff --git a/includes/js/dojox/widget/tests/test_FileInput.html b/includes/js/dojox/widget/tests/test_FileInput.html new file mode 100644 index 0000000..caccd0f --- /dev/null +++ b/includes/js/dojox/widget/tests/test_FileInput.html @@ -0,0 +1,115 @@ + + + + dojox.widget.FileInput | The Dojo Toolkit + + + + + + + + + +

                      dojox FileInput widget:

                      +

                      This is a prototype of a dojo input type="file" with a FormWidget mixin, to be styled to match tundra and soria themes

                      +

                      The API is up for discussion, nor is it known to drop into forms and "just work" yet

                      +

                      FileInputAuto API is up for discussion, as well, though by use of the url="" attrib, you can basically + do all your file-processing server side, and just use the filename sent that remains in the form input

                      +

                      There are two parts. dojo.require("dojox.widget.FileInput") for just the base class, or dojo.require("dojox.widget.FileInputAuto"); + to provide the Auto Uploading widget (on blur), and the Blind Auto Upload widget.

                      +

                      Both themes are defined in the FileInput.css file, as well as basic styling needed to run

                      + +

                      A standard file input:

                      + + +

                      The default dojox.widget.FileInput:

                      +

                      + +

                      + +

                      default dojox.widget.FileInput, tundra:

                      +

                      + +

                      + +

                      dojox.widget.FileInputAuto, soria theme:

                      +

                      + +

                      + +

                      another one, tundra theme (with callback)

                      +

                      + +

                      + +

                      a blind auto upload widget, tundra:

                      +

                      + +

                      + +

                      dojox.widget.FileInputBlind - soria

                      +

                      + +

                      + +

                      dynamic, tundra, dojox.widget.FileInputAuto:

                      + +

                      +
                      + + + diff --git a/includes/js/dojox/widget/tests/test_FisheyeList.html b/includes/js/dojox/widget/tests/test_FisheyeList.html new file mode 100644 index 0000000..348ea13 --- /dev/null +++ b/includes/js/dojox/widget/tests/test_FisheyeList.html @@ -0,0 +1,144 @@ + + + + FisheyeList Widget Dojo Tests + + + + + + + +

                      dojox.widget.FisheyeList test

                      +

                      HTML before

                      + +

                      HTML before

                      +

                      HTML before

                      +

                      Liberal trigger: move the mouse anywhere near the menu and it will start to expand:

                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      +
                      + +

                      HTML after

                      +

                      HTML after

                      +

                      HTML after

                      +

                      This one has strict triggering, so you actually have to mouse over the menu to make it start moving:

                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      + +
                      +
                      +
                      + + + + diff --git a/includes/js/dojox/widget/tests/test_FisheyeLite.html b/includes/js/dojox/widget/tests/test_FisheyeLite.html new file mode 100644 index 0000000..0935d10 --- /dev/null +++ b/includes/js/dojox/widget/tests/test_FisheyeLite.html @@ -0,0 +1,257 @@ + + + + A responsive Fisheye-like FisheyeLite widget | The Dojo Toolkit + + + + + + + +
                      + +
                      +
                        +
                      • Dojo
                        the javascript toolkit
                      • +
                      • Dijit
                        UI y mas - themeable, plugable.
                      • +
                      • DojoX
                        extensions, experimentals, extras. innovation.
                      • +
                      • Dojo
                        the javascript toolkit
                      • +
                      • Dijit
                        UI y mas - themeable, plugable.
                      • +
                      • DojoX
                        extensions, experimentals, extras. innovation.
                      • +
                      • Dojo
                        the javascript toolkit
                      • +
                      • Dijit
                        UI y mas - themeable, plugable.
                      • +
                      +
                      + +

                      A paragraph: (with links)

                      + +

                      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean + semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. + Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla + facilisi. Maecenas luctus venenatis nulla. In sit amet dui non mi + semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum + magna. Sed vitae risus. +

                      + +

                      read the fine print:

                      + +

                      + + + + +

                      + +
                      + Aliquam vitae enim. Duis scelerisque metus auctor est venenatis + imperdiet. Fusce dignissim porta augue. Nulla vestibulum. Integer + lorem nunc, ullamcorper a, commodo ac, malesuada sed, dolor. Aenean + id mi in massa bibendum suscipit. Integer eros. Nullam suscipit + mauris. In pellentesque. Mauris ipsum est, pharetra semper, + pharetra in, viverra quis, tellus. Etiam purus. +
                      + +

                      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean + semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. + Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla + facilisi. Maecenas luctus venenatis nulla. In sit amet dui non mi + semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum + magna. Sed vitae risus. +

                      +

                      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean + semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. + Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla + facilisi. Maecenas luctus venenatis nulla. In sit amet dui non mi + semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum + magna. Sed vitae risus. +

                      +

                      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean + semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. + Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla + facilisi. Maecenas luctus venenatis nulla. In sit amet dui non mi + semper iaculis. Sed molestie tortor at ipsum. Morbi dictum rutrum + magna. Sed vitae risus. +

                      +

                      + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean + semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. + Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla + facilisi. Maecenas luctus venenatis nulla. In sit amet dui non mi + semper iaculis. Sed molestie tortor at ipsum. +

                      +

                      another list: (no target, or ilk)

                      +
                      +
                      +
                        +
                      • Foo
                      • +
                      • Bar
                      • +
                      • Baz
                      • +
                      • Bam
                      • +
                      +
                      +
                      + +

                      oh right, Images:

                      + +
                      + + + + + + + +
                      + +
                      +
                      +
                      +
                      +
                      +
                      +
                      + +
                      + +

                      + + Aliquam vitae enim. Duis scelerisque metus auctor est venenatis + imperdiet. Fusce dignissim porta augue. Nulla vestibulum. Integer + lorem nunc, ullamcorper a, commodo ac, malesuada sed, dolor. Aenean + id mi in massa bibendum suscipit. Integer eros. Nullam suscipit + mauris. In pellentesque. Mauris ipsum est, pharetra semper, + pharetra in, viverra quis, tellus. Etiam purus. Quisque egestas, + tortor ac cursus lacinia, felis leo adipiscing nisi, et rhoncus + elit dolor eget eros. Fusce ut quam. Suspendisse eleifend leo vitae + ligula. Nulla facilisi. Nulla rutrum, erat vitae lacinia dictum, + pede purus imperdiet lacus, ut semper velit ante id metus. Praesent + massa dolor, porttitor sed, pulvinar in, consequat ut, leo. Nullam + nec est. Aenean id risus blandit tortor pharetra congue. + Suspendisse pulvinar. +

                      + +

                      the end

                      + +
                      + + diff --git a/includes/js/dojox/widget/tests/test_Iterator.html b/includes/js/dojox/widget/tests/test_Iterator.html new file mode 100644 index 0000000..7cf82ff --- /dev/null +++ b/includes/js/dojox/widget/tests/test_Iterator.html @@ -0,0 +1,73 @@ + + + + Dojox Iterator Test + + + + + + + + +

                      Dojox Iterator test

                      + +
                      + +

                      Data store backed Iterator

                      +
                        +
                      • before
                      • +
                      • + ${name} +
                      • +
                      • after
                      • +
                      + +

                      Array backed Iterator

                      +
                        +
                      • before
                      • + +
                      • + ${name} ${thinger} +
                      • +
                      • after
                      • +
                      + +

                      Array-property Iterator

                      +
                        +
                      • before
                      • +
                      • blah
                      • +
                      • + ${value} +
                      • +
                      • after
                      • +
                      + + + diff --git a/includes/js/dojox/widget/tests/test_Loader.html b/includes/js/dojox/widget/tests/test_Loader.html new file mode 100644 index 0000000..3c014a2 --- /dev/null +++ b/includes/js/dojox/widget/tests/test_Loader.html @@ -0,0 +1,81 @@ + + + + Dojo Visual Loader Test + + + + + + + +
                      + + + +

                      Dojox xhrListener test

                      + + start xhrGet demo + start xhrPost demo + +

                      No additional code is required except for the existance of a + dojoType="dojox.widget.Loader" node. It will listen for the start + and end of xhr* requests (via _ioSetArgs [ugh] and Deferred.prototype._fire .. +

                      + +
                      +
                      + +
                      spacer
                      + + + diff --git a/includes/js/dojox/widget/tests/test_MultiComboBox.html b/includes/js/dojox/widget/tests/test_MultiComboBox.html new file mode 100644 index 0000000..86f6c54 --- /dev/null +++ b/includes/js/dojox/widget/tests/test_MultiComboBox.html @@ -0,0 +1,70 @@ + + + + Multi-input ComboBox widget + + + + + + +

                      dojox.widget.MultiComboBox

                      +

                      + This widget is an extension to ComboBox to allow "tag" style input using a datastore. Start typing + into the box, and your options will be presented. The default delimiter is a comma, which can be over-ridden + by the delimiter="" attrbute. +

                      + +
                      + +

                      Default:

                      + + +

                      Alternate delimiter (:)

                      + + +

                      From code:

                      +
                      + + + + + + diff --git a/includes/js/dojox/widget/tests/test_Rating.html b/includes/js/dojox/widget/tests/test_Rating.html new file mode 100644 index 0000000..e87168f --- /dev/null +++ b/includes/js/dojox/widget/tests/test_Rating.html @@ -0,0 +1,91 @@ + + + + Dojox Rating Test + + + + + + + + + + + + +

                      Dojox Rating test

                      + +

                      default usage:

                      + The attribute "numStars" is not given, so the default 3 stars are shown.
                      + + The value is: 0 +

                      + +

                      5 stars:

                      + The attribute "numStars" is given and set to 5, the initial value is 3.
                      + +

                      + +

                      Customized, "my big stars":

                      + The stars are bigger, and styled this way that there is space around each. + When hovering the background color is changed too. All this is achieved via CSS, see top of this file. +
                      + The attribute "numStars" is set to 10, so we see ten stars. +
                      + + + + +

                      + The value is: 0 +
                      + The mouse is over: 0 +
                      + +

                      Spacing

                      + Surrounded by text to see that it really takes all it's space + Surrounded by text to see that it really takes all it's space + Surrounded by text to see that it really takes all it's space + Surrounded by text to see that it really takes all it's space + Surrounded by text to see that it really takes all it's space
                      + Surrounded by text to see that it really takes all it's space + Surrounded by text to see that it really takes all it's space + Surrounded by text to see that it really takes all it's space + Surrounded by text to see that it really takes all it's space +

                      + + diff --git a/includes/js/dojox/widget/tests/test_SortList.html b/includes/js/dojox/widget/tests/test_SortList.html new file mode 100644 index 0000000..55cb7a1 --- /dev/null +++ b/includes/js/dojox/widget/tests/test_SortList.html @@ -0,0 +1,74 @@ + + + + Dojox SortList Test + + + + + + + + + +

                      Dojox SortList test

                      + +
                      + +

                      Simple sortable example

                      +
                        + +

                        Children of a TabContainer

                        +
                        +
                        +
                        +
                        +
                        + +

                        Child of a SplitContainer

                        +
                        +
                        +
                        +
                        +
                        + +
                        +

                        Raw, degradable UL list:

                        +
                          +
                        • one
                        • +
                        • two
                        • +
                        • three
                        • +
                        • four
                        • +
                        • five
                        • +
                        • six
                        • +
                        • four
                        • +
                        • five
                        • +
                        • six
                        • +
                        • four
                        • +
                        • five
                        • +
                        • six
                        • +
                        • four
                        • +
                        • five
                        • +
                        • six
                        • +
                        + +

                        normal ul:

                        +
                          +
                        • one
                        • one
                        • one
                        • one
                        • one
                        • one
                        • one
                        • one
                        • +
                        + + + diff --git a/includes/js/dojox/widget/tests/test_TimeSpinner.html b/includes/js/dojox/widget/tests/test_TimeSpinner.html new file mode 100644 index 0000000..6009f6d --- /dev/null +++ b/includes/js/dojox/widget/tests/test_TimeSpinner.html @@ -0,0 +1,87 @@ + + + + Dojo Spinner Widget Test + + + + + + + + + + +

                        Dojox TimeSpinner Test

                        + Try typing values, and use the up/down arrow keys and/or the arrow push + buttons to spin +
                        + +

                        time spinner

                        +
                        + + + +
                        + +
                        + + + diff --git a/includes/js/dojox/widget/tests/test_Toaster.html b/includes/js/dojox/widget/tests/test_Toaster.html new file mode 100644 index 0000000..015ebbe --- /dev/null +++ b/includes/js/dojox/widget/tests/test_Toaster.html @@ -0,0 +1,147 @@ + + + + Toaster Widget Dojo Tests + + + + + + +
                        + +
                        + + + + + +

                        dojox.widget.Toaster test

                        + +
                        + When you click any of the buttons above, the bottom right hand message will + stay on the screen until you acknowledge it by clicking inside the message + box. If you click one of the message buttons while a message is still + displayed in the bottom right corner it should append the new message below + the old one with a separator between them. +
                        +

                        + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper + sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum + lacus. Etiam consequat scelerisque quam. Nulla facilisi. Maecenas luctus + venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie + tortor at ipsum. Morbi dictum rutrum magna. Sed vitae risus. +

                        +

                        + Aliquam vitae enim. Duis scelerisque metus auctor est venenatis imperdiet. + Fusce dignissim porta augue. Nulla vestibulum. Integer lorem nunc, + ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in massa + bibendum suscipit. Integer eros. Nullam suscipit mauris. In pellentesque. + Mauris ipsum est, pharetra semper, pharetra in, viverra quis, tellus. Etiam + purus. Quisque egestas, tortor ac cursus lacinia, felis leo adipiscing + nisi, et rhoncus elit dolor eget eros. Fusce ut quam. Suspendisse eleifend + leo vitae ligula. Nulla facilisi. Nulla rutrum, erat vitae lacinia dictum, + pede purus imperdiet lacus, ut semper velit ante id metus. Praesent massa + dolor, porttitor sed, pulvinar in, consequat ut, leo. Nullam nec est. + Aenean id risus blandit tortor pharetra congue. Suspendisse pulvinar. +

                        +

                        + Vestibulum convallis eros ac justo. Proin dolor. Etiam aliquam. Nam ornare + elit vel augue. Suspendisse potenti. Etiam sed mauris eu neque nonummy + mollis. Vestibulum vel purus ac pede semper accumsan. Vivamus lobortis, sem + vitae nonummy lacinia, nisl est gravida magna, non cursus est quam sed + urna. Phasellus adipiscing justo in ipsum. Duis sagittis dolor sit amet + magna. Suspendisse suscipit, neque eu dictum auctor, nisi augue tincidunt + arcu, non lacinia magna purus nec magna. Praesent pretium sollicitudin + sapien. Suspendisse imperdiet. Class aptent taciti sociosqu ad litora + torquent per conubia nostra, per inceptos hymenaeos. +

                        +

                        + Mauris pharetra lorem sit amet sapien. Nulla libero metus, tristique et, + dignissim a, tempus et, metus. Ut libero. Vivamus tempus purus vel ipsum. + Quisque mauris urna, vestibulum commodo, rutrum vitae, ultrices vitae, + nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, + per inceptos hymenaeos. Nulla id erat sit amet odio luctus eleifend. Proin + massa libero, ultricies non, tincidunt a, vestibulum non, tellus. Nunc nunc + purus, lobortis a, pulvinar at, egestas a, mi. Cras adipiscing velit a + mauris. Morbi felis. Etiam at felis. Cras eget eros et justo mattis + pulvinar. Nullam at justo id risus porttitor dignissim. Vestibulum sed + velit vel metus tincidunt tempus. Nunc euismod nisl id dolor tristique + tincidunt. Nullam placerat turpis sed odio. Curabitur in est id nibh tempus + ultrices. Aliquam consectetuer dapibus eros. Aliquam nisl. +

                        +

                        + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper + sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum + lacus. Etiam consequat scelerisque quam. Nulla facilisi. Maecenas luctus + venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie + tortor at ipsum. Morbi dictum rutrum magna. Sed vitae risus. +

                        +

                        + Aliquam vitae enim. Duis scelerisque metus auctor est venenatis imperdiet. + Fusce dignissim porta augue. Nulla vestibulum. Integer lorem nunc, + ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in massa + bibendum suscipit. Integer eros. Nullam suscipit mauris. In pellentesque. + Mauris ipsum est, pharetra semper, pharetra in, viverra quis, tellus. Etiam + purus. Quisque egestas, tortor ac cursus lacinia, felis leo adipiscing + nisi, et rhoncus elit dolor eget eros. Fusce ut quam. Suspendisse eleifend + leo vitae ligula. Nulla facilisi. Nulla rutrum, erat vitae lacinia dictum, + pede purus imperdiet lacus, ut semper velit ante id metus. Praesent massa + dolor, porttitor sed, pulvinar in, consequat ut, leo. Nullam nec est. + Aenean id risus blandit tortor pharetra congue. Suspendisse pulvinar. +

                        +

                        + Vestibulum convallis eros ac justo. Proin dolor. Etiam aliquam. Nam ornare + elit vel augue. Suspendisse potenti. Etiam sed mauris eu neque nonummy + mollis. Vestibulum vel purus ac pede semper accumsan. Vivamus lobortis, sem + vitae nonummy lacinia, nisl est gravida magna, non cursus est quam sed + urna. Phasellus adipiscing justo in ipsum. Duis sagittis dolor sit amet + magna. Suspendisse suscipit, neque eu dictum auctor, nisi augue tincidunt + arcu, non lacinia magna purus nec magna. Praesent pretium sollicitudin + sapien. Suspendisse imperdiet. Class aptent taciti sociosqu ad litora + torquent per conubia nostra, per inceptos hymenaeos. +

                        + + diff --git a/includes/js/dojox/widget/tests/test_Wizard.html b/includes/js/dojox/widget/tests/test_Wizard.html new file mode 100644 index 0000000..5de9f02 --- /dev/null +++ b/includes/js/dojox/widget/tests/test_Wizard.html @@ -0,0 +1,118 @@ + + +Wizard Demo + + + + + + + + + + + + +
                        + +

                        dojox.widget.Wizard tests

                        + +

                        This example shows a wizard with customized button labels.

                        + +
                        +
                        +

                        Tab 1

                        +

                        Sized content, box one

                        +
                        +
                        +

                        Tab 2

                        +
                        +
                        +

                        Tab 3

                        + + You won't be able to come back, but you can finish now... +
                        +
                        +

                        Tab 4

                        + + ... and now you can't go back. +
                        +
                        +

                        Tab 5

                        + ... and now you can finish up. +
                        +
                        + +

                        The next shows the option to hide the inactive buttons, with a smaller width...

                        + +
                        +
                        +

                        Step 1 of 3

                        +

                        Lorem ipsum dolor sit amet

                        +
                        +
                        +

                        Step 2 of 3

                        +

                        consectetur adipisicing elit

                        +
                        +
                        +

                        Step 3 of 3

                        +

                        sed do eiusmod tempor incididunt ut labore et dolore magna aliqua

                        +
                        +
                        + +

                        The next shows blocking moving to the next step with a JS function...

                        + + +
                        +
                        +

                        Agreement Terms

                        + +
                        + +
                        +

                        + I accept the terms of this agreement. +

                        +
                        +
                        +
                        +

                        Complete

                        +

                        The license has been accepted.

                        +
                        +
                        +
                        + + + + + diff --git a/includes/js/dojox/wire.js b/includes/js/dojox/wire.js new file mode 100644 index 0000000..7eb0b85 --- /dev/null +++ b/includes/js/dojox/wire.js @@ -0,0 +1,7 @@ +if(!dojo._hasResource["dojox.wire"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire"] = true; +dojo.provide("dojox.wire"); +dojo.require("dojox.wire._base"); + + +} diff --git a/includes/js/dojox/wire/CompositeWire.js b/includes/js/dojox/wire/CompositeWire.js new file mode 100644 index 0000000..7d1015d --- /dev/null +++ b/includes/js/dojox/wire/CompositeWire.js @@ -0,0 +1,103 @@ +if(!dojo._hasResource["dojox.wire.CompositeWire"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.CompositeWire"] = true; +dojo.provide("dojox.wire.CompositeWire"); + +dojo.require("dojox.wire._base"); +dojo.require("dojox.wire.Wire"); + +dojo.declare("dojox.wire.CompositeWire", dojox.wire.Wire, { + // summary: + // A Wire for composite values in object or array + // description: + // This class has multiple child Wires for object properties or array + // elements. + // When an object with Wires is specified to 'children' property, they + // are used to get or set an object with property values. + // When an array of Wiares is specified to 'children' property, they + // are used to get or set an array with element values. + + _wireClass: "dojox.wire.CompositeWire", + + constructor: function(/*Object*/args){ + // summary: + // Initialize properties + // description: + // If object properties or array elements specified in 'children' + // property are not Wires, Wires are created from them as + // arguments, with 'parent' property set to this Wire instance. + // args: + // Arguments to initialize properties + // children: + // An object or array containing child Wires + this._initializeChildren(this.children); + }, + _getValue: function(/*Object||Array*/object){ + // summary: + // Return an object with property values or an array with element + // values + // description: + // This method calls getValue() method of the child Wires with + // 'object' argument and returns an object with the values as + // properties or an arary of the values as elements. + // object: + // A root object + // returns: + // An object or array with values + if(!object || !this.children){ + return object; //Object||Array + } + + var value = (dojo.isArray(this.children) ? [] : {}); // array or object + for(var c in this.children){ + value[c] = this.children[c].getValue(object); + } + return value;//Object||Array + }, + + _setValue: function(/*Object||Array*/object, /*Object||Array*/value){ + // summary: + // Set an object properties or an array elements to an object + // desription: + // This method calls setValues() method of the child Wires with + // a corresponding property or element in 'value' argument and + // 'object' argument. + // object: + // A root object + // value: + // An object or array with values to set + // returns: + // 'object' + if(!object || !this.children){ + return object; //Object||Array + } + + for(var c in this.children){ + this.children[c].setValue(value[c], object); + } + return object; //Object||Array + }, + + _initializeChildren: function(/*Object||Array*/children){ + // summary: + // Initialize child Wires + // description: + // If object properties or array elements specified in 'children' + // argument are not Wires, Wires are created from them as + // arguments, with 'parent' property set to this Wire instance. + // children: + // An object or array containing child Wires + if(!children){ + return; //undefined + } + + for(var c in children){ + var child = children[c]; + child.parent = this; + if(!dojox.wire.isWire(child)){ + children[c] = dojox.wire.create(child); + } + } + } +}); + +} diff --git a/includes/js/dojox/wire/DataWire.js b/includes/js/dojox/wire/DataWire.js new file mode 100644 index 0000000..ecb6223 --- /dev/null +++ b/includes/js/dojox/wire/DataWire.js @@ -0,0 +1,179 @@ +if(!dojo._hasResource["dojox.wire.DataWire"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.DataWire"] = true; +dojo.provide("dojox.wire.DataWire"); + +dojo.require("dojox.wire.Wire"); + +dojo.declare("dojox.wire.DataWire", dojox.wire.Wire, { + // summary: + // A Wire for item attributes of data stores + // description: + // This class accesses item attributes of data stores with a dotted + // notation of attribute names specified to 'attribute' property, + // using data APIs of a data store specified to 'dataStore' property. + // The root object for this class must be an item of the data store. + // Intermediate attribute names in the dotted notation specify + // attributes for child items, which are used for repeated calls to + // data APIs until reached to a descendant attribute. + // Attribute names may have an array index, such as "a[0]", to + // identify an array element of the attribute value. + + _wireClass: "dojox.wire.DataWire", + + constructor: function(/*Object*/args){ + // summary: + // Initialize properties + // description: + // If 'dataStore' property is not specified, but 'parent' property + // is specified, 'dataStore' property is copied from the parent. + // args: + // Arguments to initialize properties + // dataStore: + // A data store + // attribute: + // A dotted notation to a descendant attribute + if(!this.dataStore && this.parent){ + this.dataStore = this.parent.dataStore; + } + }, + _getValue: function(/*Object*/object){ + // summary: + // Return an attribute value of an item + // description: + // This method uses a root item passed in 'object' argument and + // 'attribute' property to call getValue() method of + // 'dataStore'. + // If an attribute name have an array suffix ("[]"), getValues() + // method is called, instead. + // If an index is specified in the array suffix, an array element + // for the index is returned, instead of the array itself. + // object: + // A root item + // returns: + // A value found, otherwise 'undefined' + if(!object || !this.attribute || !this.dataStore){ + return object; //Object + } + + var value = object; + var list = this.attribute.split('.'); + for(var i in list){ + value = this._getAttributeValue(value, list[i]); + if(!value){ + return undefined; //undefined + } + } + return value; //anything + }, + + _setValue: function(/*Object*/object, /*anything*/value){ + // summary: + // Set an attribute value to an item + // description: + // This method uses a root item passed in 'object' argument and + // 'attribute' property to identify an item. + // Then, setValue() method of 'dataStore' is called with a leaf + // attribute name and 'value' argument. + // If an attribute name have an array suffix ("[]"), setValues() + // method is called, instead. + // If an index is specified in the array suffix, an array element + // for the index is set to 'value', instead of the array itself. + // object: + // A root item + // value: + // A value to set + // returns: + // 'object', or 'undefined' for invalid attribute + if(!object || !this.attribute || !this.dataStore){ + return object; //Object + } + + var item = object; + var list = this.attribute.split('.'); + var last = list.length - 1; + for(var i = 0; i < last; i++){ + item = this._getAttributeValue(item, list[i]); + if(!item){ + return undefined; //undefined + } + } + this._setAttributeValue(item, list[last], value); + return object; //Object + }, + + _getAttributeValue: function(/*Object*/item, /*String*/attribute){ + // summary: + // Return an attribute value of an item + // description: + // This method uses an item passed in 'item' argument and + // 'attribute' argument to call getValue() method of 'dataStore'. + // If an attribute name have an array suffix ("[]"), getValues() + // method is called, instead. + // If an index is specified in the array suffix, an array element + // for the index is returned, instead of the array itself. + // item: + // An item + // attribute + // An attribute name + // returns: + // A value found, otherwise 'undefined' + var value = undefined; + var i1 = attribute.indexOf('['); + if(i1 >= 0){ + var i2 = attribute.indexOf(']'); + var index = attribute.substring(i1 + 1, i2); + attribute = attribute.substring(0, i1); + var array = this.dataStore.getValues(item, attribute); + if(array){ + if(!index){ // return array for "attribute[]" + value = array; + }else{ + value = array[index]; + } + } + }else{ + value = this.dataStore.getValue(item, attribute); + } + return value; //anything + }, + + _setAttributeValue: function(/*Object*/item, /*String*/attribute, /*anything*/value){ + // summary: + // Set an attribute value to an item + // description: + // This method uses an item passed in 'item' argument and + // 'attribute' argument to call setValue() method of 'dataStore' + // with 'value' argument. + // If an attribute name have an array suffix ("[]"), setValues() + // method is called, instead. + // If an index is specified in the array suffix, an array element + // for the index is set to 'value', instead of the array itself. + // item: + // An item + // attribute: + // An attribute name + // value: + // A value to set + var i1 = attribute.indexOf('['); + if(i1 >= 0){ + var i2 = attribute.indexOf(']'); + var index = attribute.substring(i1 + 1, i2); + attribute = attribute.substring(0, i1); + var array = null; + if(!index){ // replace whole array for "attribute[]" + array = value; + }else{ + array = this.dataStore.getValues(item, attribute); + if(!array){ + array = []; + } + array[index] = value; + } + this.dataStore.setValues(item, attribute, array); + }else{ + this.dataStore.setValue(item, attribute, value); + } + } +}); + +} diff --git a/includes/js/dojox/wire/README b/includes/js/dojox/wire/README new file mode 100644 index 0000000..8f3f831 --- /dev/null +++ b/includes/js/dojox/wire/README @@ -0,0 +1,53 @@ +------------------------------------------------------------------------------- +DojoX Wire +------------------------------------------------------------------------------- +Version 1.0 +Release date: 05/29/2007 +------------------------------------------------------------------------------- +Project state: stable +------------------------------------------------------------------------------- +Project authors + Jared Jurkiewicz (jared.jurkiewicz@gmail.com) +------------------------------------------------------------------------------- +Project description + +The DojoX Wire project is a set of functions that build a generic data binding +and service invocation library to simplify how data values across a wide +variety of widget and non-widget JavaScript constructs are accessed, updated, +and passed to and from services. It also provides a set of widgets +within the dojox.wire.ml package to allow for declarative data binding +definitions in addition to the programmatic APIs. + +In essense, this project is an API to provide a simplified way of doing MVC +patterns in the client. + +------------------------------------------------------------------------------- +Dependencies: + +DojoX Wire has dependencies on core dojo, the dijit widget system (for classes +in the dojox.wire.ml package), dojox.data, and the D.O.H. unit test framework. +------------------------------------------------------------------------------- +Documentation: + +See the Dojo API tool (http://dojotoolkit.org/api) +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/wire.js +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/wire/* + +Install into the following directory structure: +/dojox/wire/ + +...which should be at the same level as your Dojo checkout. + +It should look like: +/dojox/wire.js +/dojox/wire/* + +Require in dojox.wire for all baseline functions (dojox.wire.connect, +dojox.wire.register, etc). For specific Wire classes, +require in the appropriate dojox.wire.. +------------------------------------------------------------------------------- + diff --git a/includes/js/dojox/wire/TableAdapter.js b/includes/js/dojox/wire/TableAdapter.js new file mode 100644 index 0000000..16a5280 --- /dev/null +++ b/includes/js/dojox/wire/TableAdapter.js @@ -0,0 +1,88 @@ +if(!dojo._hasResource["dojox.wire.TableAdapter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.TableAdapter"] = true; +dojo.provide("dojox.wire.TableAdapter"); + +dojo.require("dojox.wire.CompositeWire"); + +dojo.declare("dojox.wire.TableAdapter", dojox.wire.CompositeWire, { + // summary: + // A composite Wire for table rows + // description: + // This class has multiple child Wires for object properties or array + // elements of a table row. + // The root object for this class must be an array. + // When an object with Wires is specified to 'columns' property, they + // are used to get a row object with property values. + // When an array of Wires is specified to 'columns' property, they + // are used to get a row array with element values. + // The row values are returned in an array. + // This class only supports getValue(), but not setValue(). + + _wireClass: "dojox.wire.TableAdapter", + + constructor: function(/*Object*/args){ + // summary: + // Initialize properties + // description: + // If object properties or array elements specified in 'columns' + // property are not Wires, Wires are created from them as + // arguments, with 'parent' property set to this Wire instance. + // args: + // Arguments to initialize properties + // columns: + // An object or array containing child Wires for column values + this._initializeChildren(this.columns); + }, + + _getValue: function(/*Array*/object){ + // summary: + // Return an array of table row value (object or array) + // description: + // This method iterates over an array specified to 'object' + // argument and calls getValue() method of the child Wires with + // each element of the array to get a row object or array. + // Finally, an array with the row objects or arrays are retuned. + // object: + // A root array + // returns: + // An array of table row value + if(!object || !this.columns){ + return object; //Array + } + + var array = object; + if(!dojo.isArray(array)){ + array = [array]; + } + + var rows = []; + for(var i in array){ + var row = this._getRow(array[i]); + rows.push(row); + } + return rows; //Array + }, + + _setValue: function(/*Array*/object, /*Array*/value){ + // summary: + // Not supported + throw new Error("Unsupported API: " + this._wireClass + "._setValue"); + }, + + _getRow: function(/*Object||Array*/object){ + // summary: + // Return an array or object for a table row + // description: + // This method calls getValue() method of the child Wires to + // create a row object or array. + // returns: + // An array or object for a table row + var row = (dojo.isArray(this.columns) ? [] : {}); // array or object + for(var c in this.columns){ + row[c] = this.columns[c].getValue(object); + } + return row; //Array||Object + } +}); + +} diff --git a/includes/js/dojox/wire/TextAdapter.js b/includes/js/dojox/wire/TextAdapter.js new file mode 100644 index 0000000..36e7f1d --- /dev/null +++ b/includes/js/dojox/wire/TextAdapter.js @@ -0,0 +1,88 @@ +if(!dojo._hasResource["dojox.wire.TextAdapter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.TextAdapter"] = true; +dojo.provide("dojox.wire.TextAdapter"); + +dojo.require("dojox.wire.CompositeWire"); + +dojo.declare("dojox.wire.TextAdapter", dojox.wire.CompositeWire, { + // summary: + // A composite Wire for a concatenated text + // description: + // This class has multiple child Wires for text segment values. + // Wires in 'segments' property are used to get text segments and + // values are concatenated with an optional delimiter string specified + // to 'delimiter' property. + + _wireClass: "dojox.wire.TextAdapter", + + constructor: function(/*Object*/args){ + // summary: + // Initialize properties + // description: + // If array elements specified in 'segments' are not Wires, Wires + // are created from them as arguments, with 'parent' property set + // to this Wire instance. + // args: + // Arguments to initialize properties + // segments: + // An array containing child Wires for text segment values + // delimiter: + // A delimiter string + this._initializeChildren(this.segments); + if(!this.delimiter){ + this.delimiter = ""; + } + }, + + _getValue: function(/*Object||Array*/object){ + // summary: + // Return a concatenated text + // description: + // This method calls getValue() method of the child Wires wuth + // 'object' argument and concatenate the values with 'delimiter' + // property to return. + // arg: + // A root object + // returns: + // A concatinated text + if(!object || !this.segments){ + return object; //Object||Array + } + + var text = ""; + for(var i in this.segments){ + var segment = this.segments[i].getValue(object); + text = this._addSegment(text, segment); + } + return text; //String + }, + + _setValue: function(/*Object||Array*/object, /*String*/value){ + // summary: + // Not supported + throw new Error("Unsupported API: " + this._wireClass + "._setValue"); + }, + + _addSegment: function(/*String*/text, /*String*/segment){ + // summary: + // Return a concatenated text + // description: + // This method add a text segment specified to 'segment' argument + // to a base text specified to 'text', with 'delimiter' property. + // text: + // A base text + // segment: + // A text segment to add + // returns: + // A concatinated text + if(!segment){ + return text; //String + }else if(!text){ + return segment; //String + }else{ + return text + this.delimiter + segment; //String + } + } +}); + +} diff --git a/includes/js/dojox/wire/TreeAdapter.js b/includes/js/dojox/wire/TreeAdapter.js new file mode 100644 index 0000000..b9b16bf --- /dev/null +++ b/includes/js/dojox/wire/TreeAdapter.js @@ -0,0 +1,188 @@ +if(!dojo._hasResource["dojox.wire.TreeAdapter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.TreeAdapter"] = true; +dojo.provide("dojox.wire.TreeAdapter"); + +dojo.require("dojox.wire.CompositeWire"); + +dojo.declare("dojox.wire.TreeAdapter", dojox.wire.CompositeWire, { + // summary: + // A composite Wire for tree nodes + // description: + // This class has multiple child Wires for tree nodes, their title and + // child nodes. + // The root object for this class must be an array. + // 'node' Wires in 'nodes' property is used to identify an object + // representing a node. + // 'title' Wires in 'nodes' property is used to get the title string + // of a node. + // 'children' Wires in 'nodes' property is used to iterate over child + // node objects. + // The node values are returned in an array as follows: + // [ + // {title: title1, + // children: [ + // {title: title2, + // child: ...}, + // {title: title3, + // child: ...}, + // ... + // ]}, + // ... + // ] + // This class only supports getValue(), but not setValue(). + + _wireClass: "dojox.wire.TreeAdapter", + + constructor: function(/*Object*/args){ + // summary: + // Initialize properties + // description: + // If object properties ('node', 'title' and 'children') of array + // elements specified in 'nodes' property are not Wires, Wires are + // created from them as arguments, with 'parent' property set to + // this Wire instance. + // args: + // Arguments to initialize properties + // nodes: + // An array containing objects for child Wires for node values + this._initializeChildren(this.nodes); + }, + _getValue: function(/*Array*/object){ + // summary: + // Return an array of tree node values + // description: + // This method iterates over an array specified to 'object' + // argument and calls getValue() method of 'node' Wires with each + // element of the array to get object(s) that represetns nodes. + // (If 'node' Wires are omitted, the array element is used for + // further processing.) + // Then, getValue() method of 'title' Wires are called to get + // title strings for nodes. + // (If 'title' Wires are omitted, the objects representing nodes + // are used as title strings.) + // And if an array of objects with 'node' and 'title' Wires is + // specified to 'children', it is used to gather child nodes and + // their title strings in the same way recursively. + // Finally, an array of the top-level node objects are retuned. + // object: + // A root array + // returns: + // An array of tree node values + if(!object || !this.nodes){ + return object; //Array + } + + var array = object; + if(!dojo.isArray(array)){ + array = [array]; + } + + var nodes = []; + for(var i in array){ + for(var i2 in this.nodes){ + nodes = nodes.concat(this._getNodes(array[i], this.nodes[i2])); + } + } + return nodes; //Array + }, + + _setValue: function(/*Array*/object, /*Array*/value){ + // summary: + // Not supported + throw new Error("Unsupported API: " + this._wireClass + "._setValue"); + }, + + _initializeChildren: function(/*Array*/children){ + // summary: + // Initialize child Wires + // description: + // If 'node' or 'title' properties of array elements specified in + // 'children' argument are not Wires, Wires are created from them + // as arguments, with 'parent' property set to this Wire instance. + // If an array element has 'children' property, this method is + // called recursively with it. + // children: + // An array of objects containing child Wires + if(!children){ + return; //undefined + } + + for(var i in children){ + var child = children[i]; + if(child.node){ + child.node.parent = this; + if(!dojox.wire.isWire(child.node)){ + child.node = dojox.wire.create(child.node); + } + } + if(child.title){ + child.title.parent = this; + if(!dojox.wire.isWire(child.title)){ + child.title = dojox.wire.create(child.title); + } + } + if(child.children){ + this._initializeChildren(child.children); + } + } + }, + + _getNodes: function(/*Object*/object, /*Object*/child){ + // summary: + // Return an array of tree node values + // description: + // This method calls getValue() method of 'node' Wires with + // 'object' argument to get object(s) that represents nodes. + // (If 'node' Wires are omitted, 'object' is used for further + // processing.) + // Then, getValue() method of 'title' Wires are called to get + // title strings for nodes. + // (If 'title' Wires are omitted, the objects representing nodes + // are used as title strings.) + // And if an array of objects with 'node' and 'title' Wires is + // specified to 'children', it is used to gather child nodes and + // their title strings in the same way recursively. + // Finally, an array of node objects are returned. + // object: + // An object + // child: + // An object with child Wires + // returns: + var array = null; + if(child.node){ + array = child.node.getValue(object); + if(!array){ + return []; + } + if(!dojo.isArray(array)){ + array = [array]; + } + }else{ + array = [object]; + } + + var nodes = []; + for(var i in array){ + object = array[i]; + var node = {}; + if(child.title){ + node.title = child.title.getValue(object); + }else{ + node.title = object; + } + if(child.children){ + var children = []; + for(var i2 in child.children){ + children = children.concat(this._getNodes(object, child.children[i2])); + } + if(children.length > 0){ + node.children = children; + } + } + nodes.push(node); + } + return nodes; //Array + } +}); + +} diff --git a/includes/js/dojox/wire/Wire.js b/includes/js/dojox/wire/Wire.js new file mode 100644 index 0000000..f9dde1d --- /dev/null +++ b/includes/js/dojox/wire/Wire.js @@ -0,0 +1,336 @@ +if(!dojo._hasResource["dojox.wire.Wire"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.Wire"] = true; +dojo.provide("dojox.wire.Wire"); + +dojo.require("dojox.wire._base"); + +dojo.declare("dojox.wire.Wire", null, { + // summary: + // A default and base Wire to access an object property + // description: + // This class accesses a property of an object with a dotted notation + // specified to 'property' property, such as "a.b.c", which identifies + // a descendant property, "object.a.b.c". + // Property names in the dotted notation may have an array index, such + // as "a[0]", to identify an array element, literally, "object.a[0]". + // When a notation start with an array index, such as "[0].a", it + // specifies an array element of the root object (array), + // "object[0].a". + // This class also serves as a base class for other Wire classes, + // preparing a root object and converting a return value, so that + // sub-classes just can implement _getValue() and _setValue() called + // from getValue() and setValue() implemented by this calss. + + _wireClass: "dojox.wire.Wire", + + constructor: function(/*Object*/args){ + // summary: + // Initialize properties + // description: + // If 'converter' property is specified and is a string for + // a converter class, an instanceof the converter class is + // created. + // args: + // Arguments to initialize properties + // object: + // A root object (or another Wire to access a root object) + // property: + // A dotted notation to a descendant property + // type: + // A type of the return value (for the source Wire) + // converter: + // A converter object (or class name) to convert the return + // value (for the source Wire) + dojo.mixin(this, args); + + if(this.converter){ + if(dojo.isString(this.converter)){ + //First check the object tree for it. Might be defined variable + //name/global function (like a jsId, or just a function name). + var convertObject = dojo.getObject(this.converter); + if (dojo.isFunction(convertObject)){ + //We need to see if this is a pure function or an object constructor... + try{ + var testObj = new convertObject(); + if(testObj && !dojo.isFunction(testObj["convert"])){ + //Looks like a 'pure' function... + this.converter = {convert: convertObject}; + }else{ + this.converter = testObj; + } + }catch(e){ + //Do if this fails. + } + }else if(dojo.isObject(convertObject)){ + //It's an object, like a jsId ... see if it has a convert function + if(dojo.isFunction(convertObject["convert"])){ + this.converter = convertObject; + } + } + + //No object with that name (Converter is still a string), + //then look for a class that needs to be dynamically loaded... + if (dojo.isString(this.converter)) { + var converterClass = dojox.wire._getClass(this.converter); + if(converterClass){ + this.converter = new converterClass(); + }else{ + this.converter = undefined; + } + } + }else if(dojo.isFunction(this.converter)){ + this.converter = {convert: this.converter}; + } + } + }, + + getValue: function(/*Object||Array*/defaultObject){ + // summary: + // Return a value of an object + // description: + // This method first determins a root object as follows: + // 1. If 'object' property specified, + // 1.1 If 'object' is a Wire, its getValue() method is called to + // obtain a root object. + // 1.2 Otherwise, use 'object' as a root object. + // 2. Otherwise, use 'defaultObject' argument. + // 3. If 'property' is specified, it is used to get a property + // value. + // Then, if a sub-class implements _getValue() method, it is + // called with the root object to get the return value. + // Otherwise, the root object (typically, a property valye) is + // used for the return value. + // Finally, if 'type' property is specified, the return value is + // converted to the specified primitive type ("string", "number", + // "boolean" and "array"). + // If 'converter' property is specified, its convert() method is + // called to convert the value. + // defaultObject: + // A default root object + // returns: + // A value found + var object = undefined; + if(dojox.wire.isWire(this.object)){ + object = this.object.getValue(defaultObject); + }else{ + object = (this.object || defaultObject); + } + + if(this.property){ + var list = this.property.split('.'); + for(var i in list){ + if(!object){ + return object; //anything (null, undefined, etc) + } + object = this._getPropertyValue(object, list[i]); + } + } + + var value = undefined; + if(this._getValue){ + value = this._getValue(object); + }else{ + value = object; + } + + if(value){ + if(this.type){ + if(this.type == "string"){ + value = value.toString(); + }else if(this.type == "number"){ + value = parseInt(value); + }else if(this.type == "boolean"){ + value = (value != "false"); + }else if(this.type == "array"){ + if(!dojo.isArray(value)){ + value = [value]; + } + } + } + if(this.converter && this.converter.convert){ + value = this.converter.convert(value, this); // optional "this" context + } + } + return value; //anything + }, + + setValue: function(/*anything*/value, /*Object||Array*/defaultObject){ + // summary: + // Set a value to an object + // description: + // This method first determins a root object as follows: + // 1. If 'object' property specified, + // 1.1 If 'object' is a Wire, its getValue() method is called to + // obtain a root object. + // 1.2 Otherwise, use 'object' as a root object. + // 2. Otherwise, use 'defaultObject' argument. + // 3. If 'property' is specified, it is used to get a property + // value. + // Then, if a sub-class implements _setValue() method, it is + // called with the root object and 'value' argument to set + // the value. + // Otherwise, 'value' is set to a property specified with + // 'property' property. + // If the root object is undefined and 'object' property is a Wire + // and a new object is created and returned by _setValue() it is + // set through 'object' (setValue() method). + // value: + // A value to set + // defaultObject: + // A default root object + var object = undefined; + if(dojox.wire.isWire(this.object)){ + object = this.object.getValue(defaultObject); + }else{ + object = (this.object || defaultObject); + } + + var property = undefined; + if(this.property){ + if(!object){ + if(dojox.wire.isWire(this.object)){ + object = {}; + this.object.setValue(object, defaultObject); + }else{ + throw new Error(this._wireClass + ".setValue(): invalid object"); + } + } + var list = this.property.split('.'); + var last = list.length - 1; + for(var i = 0; i < last; i++){ + var p = list[i]; + var o = this._getPropertyValue(object, p); + if(!o){ + o = {}; + this._setPropertyValue(object, p, o); + } + object = o; + } + property = list[last]; + } + + if(this._setValue){ + if(property){ + var o = this._getPropertyValue(object, property); + if(!o){ + o = {}; + this._setPropertyValue(object, property, o); + } + object = o; + } + var newObject = this._setValue(object, value); + if(!object && newObject){ + if(dojox.wire.isWire(this.object)){ + this.object.setValue(newObject, defaultObject); + }else{ + throw new Error(this._wireClass + ".setValue(): invalid object"); + } + } + }else{ + if(property){ + this._setPropertyValue(object, property, value); + }else{ + if(dojox.wire.isWire(this.object)){ + this.object.setValue(value, defaultObject); + }else{ + throw new Error(this._wireClass + ".setValue(): invalid property"); + } + } + } + }, + + _getPropertyValue: function(/*Object||Array*/object, /*String*/property){ + // summary: + // Return a property value of an object + // description: + // A value for 'property' of 'object' is returned. + // If 'property' ends with an array index, it is used to indentify + // an element of an array property. + // If 'object' implements getPropertyValue(), it is called with + // 'property' to obtain the property value. + // If 'object' implements a getter for the property, it is called + // to obtain the property value. + // object: + // A default root object + // property: + // A property name + // returns: + // A value found, otherwise 'undefined' + var value = undefined; + var i1 = property.indexOf('['); + if(i1 >= 0){ + var i2 = property.indexOf(']'); + var index = property.substring(i1 + 1, i2); + var array = null; + if(i1 === 0){ // object is array + array = object; + }else{ + property = property.substring(0, i1); + array = this._getPropertyValue(object, property); + if(array && !dojo.isArray(array)){ + array = [array]; + } + } + if(array){ + value = array[index]; + } + }else if(object.getPropertyValue){ + value = object.getPropertyValue(property); + }else{ + var getter = "get" + property.charAt(0).toUpperCase() + property.substring(1); + if(object[getter]){ + value = object[getter](); + }else{ + value = object[property]; + } + } + return value; //anything + }, + + _setPropertyValue: function(/*Object||Array*/object, /*String*/property, /*anything*/value){ + // summary: + // Set a property value to an object + // description: + // 'value' is set to 'property' of 'object'. + // If 'property' ends with an array index, it is used to indentify + // an element of an array property to set the value. + // If 'object' implements setPropertyValue(), it is called with + // 'property' and 'value' to set the property value. + // If 'object' implements a setter for the property, it is called + // with 'value' to set the property value. + // object: + // An object + // property: + // A property name + // value: + // A value to set + var i1 = property.indexOf('['); + if(i1 >= 0){ + var i2 = property.indexOf(']'); + var index = property.substring(i1 + 1, i2); + var array = null; + if(i1 === 0){ // object is array + array = object; + }else{ + property = property.substring(0, i1); + array = this._getPropertyValue(object, property); + if(!array){ + array = []; + this._setPropertyValue(object, property, array); + } + } + array[index] = value; + }else if(object.setPropertyValue){ + object.setPropertyValue(property, value); + }else{ + var setter = "set" + property.charAt(0).toUpperCase() + property.substring(1); + if(object[setter]){ + object[setter](value); + }else{ + object[property] = value; + } + } + } +}); + +} diff --git a/includes/js/dojox/wire/XmlWire.js b/includes/js/dojox/wire/XmlWire.js new file mode 100644 index 0000000..dc5666f --- /dev/null +++ b/includes/js/dojox/wire/XmlWire.js @@ -0,0 +1,244 @@ +if(!dojo._hasResource["dojox.wire.XmlWire"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.XmlWire"] = true; +dojo.provide("dojox.wire.XmlWire"); + +dojo.require("dojox.data.dom"); +dojo.require("dojox.wire.Wire"); + +dojo.declare("dojox.wire.XmlWire", dojox.wire.Wire, { + // summary: + // A Wire for XML nodes or values (element, attribute and text) + // description: + // This class accesses XML nodes or value with a simplified XPath + // specified to 'path' property. + // The root object for this class must be an DOM document or element + // node. + // "@name" accesses to an attribute value of an element and "text()" + // accesses to a text value of an element. + // The hierarchy of the elements from the root node can be specified + // with slash-separated list, such as "a/b/@c", which specifies + // the value of an attribute named "c" of an element named "b" as + // a child of another element named "a" of a child of the root node. + + _wireClass: "dojox.wire.XmlWire", + + constructor: function(/*Object*/args){ + // summary: + // Initialize properties + // description: + // 'args' is just mixed in with no further processing. + // args: + // Arguments to initialize properties + // path: + // A simplified XPath to an attribute, a text or elements + }, + _getValue: function(/*Node*/object){ + // summary: + // Return an attribute value, a text value or an array of elements + // description: + // This method first uses a root node passed in 'object' argument + // and 'path' property to identify an attribute, a text or + // elements. + // If 'path' starts with a slash (absolute), the first path + // segment is ignored assuming it point to the root node. + // (That is, "/a/b/@c" and "b/@c" against a root node access + // the same attribute value, assuming the root node is an element + // with a tag name, "a".) + // object: + // A root node + // returns: + // A value found, otherwise 'undefined' + if(!object || !this.path){ + return object; //Node + } + + var node = object; + var path = this.path; + if(path.charAt(0) == '/'){ // absolute + // skip the first expression (supposed to select the top node) + var i = path.indexOf('/', 1); + path = path.substring(i + 1); + } + var list = path.split('/'); + var last = list.length - 1; + for(var i = 0; i < last; i++){ + node = this._getChildNode(node, list[i]); + if(!node){ + return undefined; //undefined + } + } + var value = this._getNodeValue(node, list[last]); + return value; //String||Array + }, + + _setValue: function(/*Node*/object, /*String*/value){ + // summary: + // Set an attribute value or a child text value to an element + // description: + // This method first uses a root node passed in 'object' argument + // and 'path' property to identify an attribute, a text or + // elements. + // If an intermediate element does not exist, it creates + // an element of the tag name in the 'path' segment as a child + // node of the current node. + // Finally, 'value' argument is set to an attribute or a text + // (a child node) of the leaf element. + // object: + // A root node + // value: + // A value to set + if(!this.path){ + return object; //Node + } + + var node = object; + var doc = this._getDocument(node); + var path = this.path; + if(path.charAt(0) == '/'){ // absolute + var i = path.indexOf('/', 1); + if(!node){ + var name = path.substring(1, i); + node = doc.createElement(name); + object = node; // to be returned as a new object + } + // skip the first expression (supposed to select the top node) + path = path.substring(i + 1); + }else{ + if(!node){ + return undefined; //undefined + } + } + + var list = path.split('/'); + var last = list.length - 1; + for(var i = 0; i < last; i++){ + var child = this._getChildNode(node, list[i]); + if(!child){ + child = doc.createElement(list[i]); + node.appendChild(child); + } + node = child; + } + this._setNodeValue(node, list[last], value); + return object; //Node + }, + + _getNodeValue: function(/*Node*/node, /*String*/exp){ + // summary: + // Return an attribute value, a text value or an array of elements + // description: + // If 'exp' starts with '@', an attribute value of the specified + // attribute is returned. + // If 'exp' is "text()", a child text value is returned. + // Otherwise, an array of child elements, the tag name of which + // match 'exp', is returned. + // node: + // A node + // exp: + // An expression for attribute, text or elements + // returns: + // A value found, otherwise 'undefined' + var value = undefined; + if(exp.charAt(0) == '@'){ + var attribute = exp.substring(1); + value = node.getAttribute(attribute); + }else if(exp == "text()"){ + var text = node.firstChild; + if(text){ + value = text.nodeValue; + } + }else{ // assume elements + value = []; + for(var i = 0; i < node.childNodes.length; i++){ + var child = node.childNodes[i]; + if(child.nodeType === 1 /* ELEMENT_NODE */ && child.nodeName == exp){ + value.push(child); + } + } + } + return value; //String||Array + }, + + _setNodeValue: function(/*Node*/node, /*String*/exp, /*String*/value){ + // summary: + // Set an attribute value or a child text value to an element + // description: + // If 'exp' starts with '@', 'value' is set to the specified + // attribute. + // If 'exp' is "text()", 'value' is set to a child text. + // node: + // A node + // exp: + // An expression for attribute or text + // value: + // A value to set + if(exp.charAt(0) == '@'){ + var attribute = exp.substring(1); + if(value){ + node.setAttribute(attribute, value); + }else{ + node.removeAttribute(attribute); + } + }else if(exp == "text()"){ + while(node.firstChild){ + node.removeChild(node.firstChild); + } + if(value){ + var text = this._getDocument(node).createTextNode(value); + node.appendChild(text); + } + } + // else not supported + }, + + _getChildNode: function(/*Node*/node, /*String*/name){ + // summary: + // Return a child node + // description: + // A child element of the tag name specified with 'name' is + // returned. + // If 'name' ends with an array index, it is used to pick up + // the corresponding element from multiple child elements. + // node: + // A parent node + // name: + // A tag name + // returns: + // A child node + var index = 1; + var i1 = name.indexOf('['); + if(i1 >= 0){ + var i2 = name.indexOf(']'); + index = name.substring(i1 + 1, i2); + name = name.substring(0, i1); + } + var count = 1; + for(var i = 0; i < node.childNodes.length; i++){ + var child = node.childNodes[i]; + if(child.nodeType === 1 /* ELEMENT_NODE */ && child.nodeName == name){ + if(count == index){ + return child; //Node + } + count++; + } + } + return null; //null + }, + + _getDocument: function(/*Node*/node){ + // summary: + // Return a DOM document + // description: + // If 'node' is specified, a DOM document of the node is returned. + // Otherwise, a DOM document is created. + // returns: + // A DOM document + if(node){ + return (node.nodeType == 9 /* DOCUMENT_NODE */ ? node : node.ownerDocument); //Document + }else{ + return dojox.data.dom.createDocument(); //Document + } + } +}); + +} diff --git a/includes/js/dojox/wire/_base.js b/includes/js/dojox/wire/_base.js new file mode 100644 index 0000000..cc632c1 --- /dev/null +++ b/includes/js/dojox/wire/_base.js @@ -0,0 +1,195 @@ +if(!dojo._hasResource["dojox.wire._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire._base"] = true; +dojo.provide("dojox.wire._base"); + +dojox.wire._defaultWireClass = "dojox.wire.Wire"; + +dojox.wire._wireClasses = { + "attribute": "dojox.wire.DataWire", + "path": "dojox.wire.XmlWire", + "children": "dojox.wire.CompositeWire", + "columns": "dojox.wire.TableAdapter", + "nodes": "dojox.wire.TreeAdapter", + "segments": "dojox.wire.TextAdapter" +}; + +dojox.wire.register = function(/*Function||String*/wireClass, /*String*/key){ + // summary: + // Register a Wire class + // desription: + // The specified Wire class or a class name is registered with + // a key property of arguments to create a Wire + // wireClass: + // A class or full qualified class name + // key: + // A key property of arguments to create a Wire + if(!wireClass || !key){ + return; //undefined + } + if(dojox.wire._wireClasses[key]){ // key already in use + return; //undefined + } + dojox.wire._wireClasses[key] = wireClass; +}; + +dojox.wire._getClass = function(/*String*/name){ + // summary: + // Returns a class + // description: + // The class is loaded by dojo.require() and returned + // by dojo.getObject(). + // name: + // A class name + // returns: + // A class + dojo["require"](name); // use dojo["require"] instead of dojo.require to avoid a build problem + return dojo.getObject(name); //Function +}; + +dojox.wire.create = function(/*Object*/args){ + // summary: + // Create a Wire from arguments + // description: + // If 'args' specifies 'wireClass', it is used as a class or full + // qualified class name to create a Wire with 'args' as arguments. + // Otherwise, a Wire class is determined by other proeprties of 'args' + // checking if 'args' specifies a key property for a Wire class. + // If no key property found, the default Wire class is used. + // args: + // Arguments to create a Wire + // returns: + // A Wire + if(!args){ + args = {}; + } + var wireClass = args.wireClass; + if(wireClass){ + if(dojo.isString(wireClass)){ + wireClass = dojox.wire._getClass(wireClass); + } + }else{ + for(var key in args){ + if(!args[key]){ + continue; + } + wireClass = dojox.wire._wireClasses[key]; + if(wireClass){ + if(dojo.isString(wireClass)){ + wireClass = dojox.wire._getClass(wireClass); + dojox.wire._wireClasses[key] = wireClass; + } + break; + } + } + } + if(!wireClass){ + if(dojo.isString(dojox.wire._defaultWireClass)){ + dojox.wire._defaultWireClass = dojox.wire._getClass(dojox.wire._defaultWireClass); + } + wireClass = dojox.wire._defaultWireClass; + } + return new wireClass(args); //Object +}; + +dojox.wire.isWire = function(/*Object*/wire){ + // summary: + // Check if an object is a Wire + // description: + // If the specified object is a Wire, true is returned. + // Otherwise, false is returned. + // wire: + // An object to check + // returns: + // True if the object is a Wire, otherwise false + return (wire && wire._wireClass); //Boolean +}; + +dojox.wire.transfer = function(/*Wire||Object*/source, /*Wire||Object*/target, /*Object?*/defaultObject, /*Object?*/defaultTargetObject){ + // summary: + // Transfer a source value to a target value + // description: + // If 'source' and/or 'target' are not Wires, Wires are created with + // them as arguments. + // A value is got through the source Wire and set through the target + // Wire. + // 'defaultObject' is passed to Wires as a default root object. + // If 'defaultTargetObject' is specified, it is passed to the target + // Wire as a default root object, instead of 'defaultObject'. + // source: + // A Wire or arguments to create a Wire for a source value + // target: + // A Wire or arguments to create a Wire for a target value + // defaultObject: + // defaultTargetObject; + // Optional default root objects passed to Wires + if(!source || !target){ + return; //undefined + } + if(!dojox.wire.isWire(source)){ + source = dojox.wire.create(source); + } + if(!dojox.wire.isWire(target)){ + target = dojox.wire.create(target); + } + + var value = source.getValue(defaultObject); + target.setValue(value, (defaultTargetObject || defaultObject)); +}; + +dojox.wire.connect = function(/*Object*/trigger, /*Wire||Object*/source, /*Wire||Object*/target){ + // summary: + // Transfer a source value to a target value on a trigger event or + // topic + // description: + // If 'trigger' specifies 'topic', the topic is subscribed to transer + // a value on the topic. + // Otherwise, the event specified to 'event' of 'trigger' is listened + // to transfer a value. + // On the specified event or topic, transfer() is called with + // 'source', 'target' and the arguments of the event or topic (as + // default root objects). + // trigger: + // An event or topic to trigger a transfer + // source: + // A Wire or arguments to create a Wire for a source value + // target: + // A Wire or arguments to create a Wire for a target value + // returns: + // A connection handle for disconnect() + if(!trigger || !source || !target){ + return; //undefined + } + + var connection = {topic: trigger.topic}; + if(trigger.topic){ + connection.handle = dojo.subscribe(trigger.topic, function(){ + dojox.wire.transfer(source, target, arguments); + }); + }else if(trigger.event){ + connection.handle = dojo.connect(trigger.scope, trigger.event, function(){ + dojox.wire.transfer(source, target, arguments); + }); + } + return connection; //Object +}; + +dojox.wire.disconnect = function(/*Object*/connection){ + // summary: + // Remove a connection or subscription for transfer + // description: + // If 'handle' has 'topic', the topic is unsubscribed. + // Otherwise, the listener to an event is removed. + // connection: + // A connection handle returned by connect() + if(!connection || !connection.handle){ + return; //undefined + } + + if(connection.topic){ + dojo.unsubscribe(connection.handle); + }else{ + dojo.disconnect(connection.handle); + } +}; + +} diff --git a/includes/js/dojox/wire/demos/TableContainer.css b/includes/js/dojox/wire/demos/TableContainer.css new file mode 100644 index 0000000..fded51f --- /dev/null +++ b/includes/js/dojox/wire/demos/TableContainer.css @@ -0,0 +1,25 @@ +.tablecontainer { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; + border-collapse: separate; +} +.tablecontainer th { + text-align: left; +} +.tablecontainer tr { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} +.tablecontainer tr td { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} +.alternate { + background-color: #EEEEEE; +} diff --git a/includes/js/dojox/wire/demos/TableContainer.css.commented.css b/includes/js/dojox/wire/demos/TableContainer.css.commented.css new file mode 100644 index 0000000..4ee2706 --- /dev/null +++ b/includes/js/dojox/wire/demos/TableContainer.css.commented.css @@ -0,0 +1,30 @@ +.tablecontainer { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; + border-collapse: separate; +} + +.tablecontainer th { + text-align: left; +} + +.tablecontainer tr { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} + +.tablecontainer tr td { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} + +.alternate { + background-color: #EEEEEE; +} + diff --git a/includes/js/dojox/wire/demos/TableContainer.js b/includes/js/dojox/wire/demos/TableContainer.js new file mode 100644 index 0000000..fd4ad73 --- /dev/null +++ b/includes/js/dojox/wire/demos/TableContainer.js @@ -0,0 +1,68 @@ +if(!dojo._hasResource["dojox.wire.demos.TableContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.demos.TableContainer"] = true; +dojo.provide("dojox.wire.demos.TableContainer"); + +dojo.require("dojo.parser"); +dojo.require("dijit._Widget"); +dojo.require("dijit._Templated"); + +dojo.declare("dojox.wire.demos.TableContainer", [ dijit._Widget, dijit._Templated, dijit._Container ], { + // summary: + // Extremely simple 'widget' that is a table generator with an addRow function that takes an array + // as the row to add, where each entry is a cell in the row. This demo widget is for use with the + // wire demos. + + templateString: "
                        ", + rowCount: 0, + headers: "", + addRow: function(array){ + // summary: + // Function to add in a new row from the elements in the array map to cells in the row. + // array: + // Array of row values to add. + try{ + var row = document.createElement("tr"); + if((this.rowCount%2) === 0){ + dojo.addClass(row, "alternate"); + } + this.rowCount++; + for(var i in array){ + var cell = document.createElement("td"); + var text = document.createTextNode(array[i]); + cell.appendChild(text); + row.appendChild(cell); + + } + this.tableContainer.appendChild(row); + }catch(e){ console.debug(e); } + }, + + clearTable: function(){ + // summary: + // Function to clear all the current rows in the table, except for the header. + + //Always leave the first row, which is the table header. + while(this.tableContainer.firstChild.nextSibling){ + this.tableContainer.removeChild(this.tableContainer.firstChild.nextSibling); + } + this.rowCount = 0; + }, + + postCreate: function(){ + // summary: + // Widget lifecycle function to handle generation of the header elements in the table. + var headers = this.headers.split(","); + var tr = document.createElement("tr"); + for(i in headers){ + + var header = headers[i]; + var th = document.createElement("th"); + var text = document.createTextNode(header); + th.appendChild(text); + tr.appendChild(th); + } + this.tableContainer.appendChild(tr); + } +}); + +} diff --git a/includes/js/dojox/wire/demos/WidgetRepeater.js b/includes/js/dojox/wire/demos/WidgetRepeater.js new file mode 100644 index 0000000..ad1b8b0 --- /dev/null +++ b/includes/js/dojox/wire/demos/WidgetRepeater.js @@ -0,0 +1,33 @@ +if(!dojo._hasResource["dojox.wire.demos.WidgetRepeater"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.demos.WidgetRepeater"] = true; +dojo.provide("dojox.wire.demos.WidgetRepeater") + +dojo.require("dojo.parser"); +dojo.require("dijit._Widget"); +dojo.require("dijit._Templated"); +dojo.require("dijit._Container"); + +dojo.declare("dojox.wire.demos.WidgetRepeater", [ dijit._Widget, dijit._Templated, dijit._Container ], { + // summary: + // Simple widget that does generation of widgets repetatively, based on calls to + // the createNew function and contains them as child widgets. + templateString: "
                        ", + widget: null, + repeater: null, + createNew: function(obj){ + // summary: + // Function to handle the creation of a new widget and appending it into the widget tree. + // obj: + // The parameters to pass to the widget. + try{ + if(dojo.isString(this.widget)){ + dojo.require(this.widget); + this.widget = dojo.getObject(this.widget); + } + this.addChild(new this.widget(obj)); + this.repeaterNode.appendChild(document.createElement("br")); + }catch(e){ console.debug(e); } + } +}); + +} diff --git a/includes/js/dojox/wire/demos/markup/countries.json b/includes/js/dojox/wire/demos/markup/countries.json new file mode 100644 index 0000000..ad3a07a --- /dev/null +++ b/includes/js/dojox/wire/demos/markup/countries.json @@ -0,0 +1,43 @@ +{ identifier: 'name', + items: [ + { name:'Africa', type:'continent', + children:[{_reference:'Egypt'}, {_reference:'Kenya'}, {_reference:'Sudan'}] }, + { name:'Egypt', type:'country' }, + { name:'Kenya', type:'country', + children:[{_reference:'Nairobi'}, {_reference:'Mombasa'}] }, + { name:'Nairobi', type:'city' }, + { name:'Mombasa', type:'city' }, + { name:'Sudan', type:'country', + children:{_reference:'Khartoum'} }, + { name:'Khartoum', type:'city' }, + { name:'Asia', type:'continent', + children:[{_reference:'China'}, {_reference:'India'}, {_reference:'Russia'}, {_reference:'Mongolia'}] }, + { name:'China', type:'country' }, + { name:'India', type:'country' }, + { name:'Russia', type:'country' }, + { name:'Mongolia', type:'country' }, + { name:'Australia', type:'continent', population:'21 million', + children:{_reference:'Commonwealth of Australia'}}, + { name:'Commonwealth of Australia', type:'country', population:'21 million'}, + { name:'Europe', type:'continent', + children:[{_reference:'Germany'}, {_reference:'France'}, {_reference:'Spain'}, {_reference:'Italy'}] }, + { name:'Germany', type:'country' }, + { name:'France', type:'country' }, + { name:'Spain', type:'country' }, + { name:'Italy', type:'country' }, + { name:'North America', type:'continent', + children:[{_reference:'Mexico'}, {_reference:'Canada'}, {_reference:'United States of America'}] }, + { name:'Mexico', type:'country', population:'108 million', area:'1,972,550 sq km', + children:[{_reference:'Mexico City'}, {_reference:'Guadalajara'}] }, + { name:'Mexico City', type:'city', population:'19 million', timezone:'-6 UTC'}, + { name:'Guadalajara', type:'city', population:'4 million', timezone:'-6 UTC' }, + { name:'Canada', type:'country', population:'33 million', area:'9,984,670 sq km', + children:[{_reference:'Ottawa'}, {_reference:'Toronto'}] }, + { name:'Ottawa', type:'city', population:'0.9 million', timezone:'-5 UTC'}, + { name:'Toronto', type:'city', population:'2.5 million', timezone:'-5 UTC' }, + { name:'United States of America', type:'country' }, + { name:'South America', type:'continent', + children:[{_reference:'Brazil'}, {_reference:'Argentina'}] }, + { name:'Brazil', type:'country', population:'186 million' }, + { name:'Argentina', type:'country', population:'40 million' } +]} diff --git a/includes/js/dojox/wire/demos/markup/demo_ActionChaining.html b/includes/js/dojox/wire/demos/markup/demo_ActionChaining.html new file mode 100644 index 0000000..596d6ec --- /dev/null +++ b/includes/js/dojox/wire/demos/markup/demo_ActionChaining.html @@ -0,0 +1,108 @@ + + + + Sample Action Chaining + + + + + + + + + + Demo of Chaining Actions:

                        + This demo shows how you can chain actions together to fire in a sequence. + Such as the completion of setting one value on a widget triggers the setting of another value on the widget +
                        +
                        + + + + + + + + + + +
                        +
                        +
                        +
                        +
                        +
                        +
                        + + + + + +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        +
                        + + +
                        + +
                        +
                        + + diff --git a/includes/js/dojox/wire/demos/markup/demo_ActionWiring.html b/includes/js/dojox/wire/demos/markup/demo_ActionWiring.html new file mode 100644 index 0000000..995b67f --- /dev/null +++ b/includes/js/dojox/wire/demos/markup/demo_ActionWiring.html @@ -0,0 +1,142 @@ + + + + Sample declarative data binding + + + + + + + + + +
                        +
                        + Demo Searcher (Searches on Attribute 'name'):

                        + Usage:
                        + Enter the name you want to search the store for. Wildcards * (multiple character), and ? (single character), are allowed. +
                        +
                        + + + + + +
                        +
                        Search Datastore
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + + + + + +
                        +
                        + + +
                        +
                        +
                        +
                        + + +
                        +
                        + + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + + diff --git a/includes/js/dojox/wire/demos/markup/demo_BasicChildWire.html b/includes/js/dojox/wire/demos/markup/demo_BasicChildWire.html new file mode 100644 index 0000000..f5973e7 --- /dev/null +++ b/includes/js/dojox/wire/demos/markup/demo_BasicChildWire.html @@ -0,0 +1,78 @@ + + + + Sample Composite (Child) Wire usage. + + + + + + + +
                        +
                        + + +
                        +
                        + + +
                        +
                        + + +
                        +
                        +
                        +
                        +
                        +
                        + + diff --git a/includes/js/dojox/wire/demos/markup/demo_BasicColumnWiring.html b/includes/js/dojox/wire/demos/markup/demo_BasicColumnWiring.html new file mode 100644 index 0000000..48c327e --- /dev/null +++ b/includes/js/dojox/wire/demos/markup/demo_BasicColumnWiring.html @@ -0,0 +1,90 @@ + + + + Sample Declarative Data Binding using ColumnWire + + + + + + + + +
                        +
                        + + +
                        + + +
                        + + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + + diff --git a/includes/js/dojox/wire/demos/markup/demo_ConditionalActions.html b/includes/js/dojox/wire/demos/markup/demo_ConditionalActions.html new file mode 100644 index 0000000..ea0ca64 --- /dev/null +++ b/includes/js/dojox/wire/demos/markup/demo_ConditionalActions.html @@ -0,0 +1,221 @@ + + + + Conditional Actions Demo + + + + + + + + + + Demo of Conditional Actions:

                        + This demo shows how you can use actions to read and set widget values, as well as have actions only occur if + if certain conditions are met, such as cloning values as they are typed from the billing address over to the + shipping address if the 'Use Same Address' checkbox is checked true. +
                        +
                        +
                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        + Use Same Address:
                        +
                        + Billing Address + + Shipping Address +
                        + Name:
                        +
                        + Name:
                        +
                        + Address 1:
                        +
                        + Address 1:
                        +
                        + Address 2:
                        +
                        + Address 2:
                        +
                        + City:
                        +
                        + City:
                        +
                        + State:
                        +
                        + State:
                        +
                        + Zip code:
                        +
                        + Zip code:
                        +
                        + + + + + +
                        +
                        +
                        + + + +
                        + +
                        +
                        +
                        +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        + + + +
                        +
                        + + +
                        +
                        +
                        +
                        +
                        +
                        +
                        + + + diff --git a/includes/js/dojox/wire/demos/markup/demo_FlickrStoreWire.html b/includes/js/dojox/wire/demos/markup/demo_FlickrStoreWire.html new file mode 100644 index 0000000..54068a9 --- /dev/null +++ b/includes/js/dojox/wire/demos/markup/demo_FlickrStoreWire.html @@ -0,0 +1,281 @@ + + + + Demo of FlickrStore + + + + + + + +

                        + DEMO: FlickrStore Search +

                        +
                        +

                        + Description: +

                        +

                        + This simple demo shows how services, such as Flickr, can be wrapped by the datastore API. In this demo, you can search public + Flickr images through a simple FlickrStore by specifying a series of tags (separated by spaces) to search on. The results + will be displayed below the search box. This demo is the same as the example demo provided in dojox/data/demos/demo_FlickrStore.html, + except that all the interactions are implemented via Wire instead of a script that runs at dojo.addOnLoad(). +

                        +

                        + For fun, search on the 3dny tag! +

                        + +
                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        + Status: + +
                        +
                        + ID: + +
                        +
                        + Tags: + +
                        +
                        + Tagmode: + + +
                        + Number of Pictures: + +
                        +
                        + +
                        +
                        +
                        + +
                        +
                        + + + + + +
                        +
                        +
                        +
                        +
                        +
                        + + + +
                        + + +
                        +
                        + + + +
                        +
                        +
                        +
                        + +
                        +
                        + +
                        +
                        + + + +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        + + + +
                        +
                        + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + + diff --git a/includes/js/dojox/wire/demos/markup/demo_TopicWiring.html b/includes/js/dojox/wire/demos/markup/demo_TopicWiring.html new file mode 100644 index 0000000..e091e8b --- /dev/null +++ b/includes/js/dojox/wire/demos/markup/demo_TopicWiring.html @@ -0,0 +1,78 @@ + + + + Sample Topic Wiring + + + + + + + + + + Demo of Topic Wiring

                        + This demo shows how you can wire events to publish to a topic as well as recieve topic events +
                        +
                        + + + + + + + +
                        +
                        +
                        +
                        +
                        + + + + + +
                        +
                        +
                        + + +
                        + + diff --git a/includes/js/dojox/wire/demos/markup/flickrDemo.css b/includes/js/dojox/wire/demos/markup/flickrDemo.css new file mode 100644 index 0000000..793d1c6 --- /dev/null +++ b/includes/js/dojox/wire/demos/markup/flickrDemo.css @@ -0,0 +1,29 @@ +.flickrView { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; + border-collapse: separate; + width: 100%; +} +.flickrView th { + text-align: left; +} +.flickrView tr { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} +.flickrView tr td { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} +.flickrView { + background-color: #EFEFEF; +} +.flickrTitle { + background-color: #CCCCCC; +} diff --git a/includes/js/dojox/wire/demos/markup/flickrDemo.css.commented.css b/includes/js/dojox/wire/demos/markup/flickrDemo.css.commented.css new file mode 100644 index 0000000..7e75a5d --- /dev/null +++ b/includes/js/dojox/wire/demos/markup/flickrDemo.css.commented.css @@ -0,0 +1,35 @@ +.flickrView { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; + border-collapse: separate; + width: 100%; +} + +.flickrView th { + text-align: left; +} + +.flickrView tr { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} + +.flickrView tr td { + padding: 3 3 3 3; + border-width: 1px; + border-style: solid; + border-color: #000000; +} + +.flickrView { + background-color: #EFEFEF; +} + +.flickrTitle { + background-color: #CCCCCC; +} + diff --git a/includes/js/dojox/wire/demos/markup/states.json b/includes/js/dojox/wire/demos/markup/states.json new file mode 100644 index 0000000..bdaa609 --- /dev/null +++ b/includes/js/dojox/wire/demos/markup/states.json @@ -0,0 +1,56 @@ +{"identifier":"abbreviation", +"label": "label", +"items": [ + {"name":"Alabama", "label":"Alabama","abbreviation":"AL"}, + {"name":"Alaska", "label":"Alaska","abbreviation":"AK"}, + {"name":"American Samoa", "label":"American Samoa","abbreviation":"AS"}, + {"name":"Arizona", "label":"Arizona","abbreviation":"AZ"}, + {"name":"Arkansas", "label":"Arkansas","abbreviation":"AR"}, + {"name":"California", "label":"California","abbreviation":"CA"}, + {"name":"Colorado", "label":"Colorado","abbreviation":"CO"}, + {"name":"Connecticut", "label":"Connecticut","abbreviation":"CT"}, + {"name":"Delaware", "label":"Delaware","abbreviation":"DE"}, + {"name":"Florida", "label":"Florida","abbreviation":"FL"}, + {"name":"Georgia", "label":"Georgia","abbreviation":"GA"}, + {"name":"Hawaii", "label":"Hawaii","abbreviation":"HI"}, + {"name":"Idaho", "label":"Idaho","abbreviation":"ID"}, + {"name":"Illinois", "label":"Illinois","abbreviation":"IL"}, + {"name":"Indiana", "label":"Indiana","abbreviation":"IN"}, + {"name":"Iowa", "label":"Iowa","abbreviation":"IA"}, + {"name":"Kansas", "label":"Kansas","abbreviation":"KS"}, + {"name":"Kentucky", "label":"Kentucky","abbreviation":"KY"}, + {"name":"Louisiana", "label":"Louisiana","abbreviation":"LA"}, + {"name":"Maine", "label":"Maine","abbreviation":"ME"}, + {"name":"Marshall Islands", "label":"Marshall Islands","abbreviation":"MH"}, + {"name":"Maryland", "label":"Maryland","abbreviation":"MD"}, + {"name":"Massachusetts", "label":"Massachusetts","abbreviation":"MA"}, + {"name":"Michigan", "label":"Michigan","abbreviation":"MI"}, + {"name":"Minnesota", "label":"Minnesota","abbreviation":"MN"}, + {"name":"Mississippi", "label":"Mississippi","abbreviation":"MS"}, + {"name":"Missouri", "label":"Missouri","abbreviation":"MO"}, + {"name":"Montana", "label":"Montana","abbreviation":"MT"}, + {"name":"Nebraska", "label":"Nebraska","abbreviation":"NE"}, + {"name":"Nevada", "label":"Nevada","abbreviation":"NV"}, + {"name":"New Hampshire", "label":"New Hampshire","abbreviation":"NH"}, + {"name":"New Jersey", "label":"New Jersey","abbreviation":"NJ"}, + {"name":"New Mexico", "label":"New Mexico","abbreviation":"NM"}, + {"name":"New York", "label":"New York","abbreviation":"NY"}, + {"name":"North Carolina", "label":"North Carolina","abbreviation":"NC"}, + {"name":"North Dakota", "label":"North Dakota","abbreviation":"ND"}, + {"name":"Ohio", "label":"Ohio","abbreviation":"OH"}, + {"name":"Oklahoma", "label":"Oklahoma","abbreviation":"OK"}, + {"name":"Oregon", "label":"Oregon","abbreviation":"OR"}, + {"name":"Pennsylvania", "label":"Pennsylvania","abbreviation":"PA"}, + {"name":"Rhode Island", "label":"Rhode Island","abbreviation":"RI"}, + {"name":"South Carolina", "label":"South Carolina","abbreviation":"SC"}, + {"name":"South Dakota", "label":"South Dakota","abbreviation":"SD"}, + {"name":"Tennessee", "label":"Tennessee","abbreviation":"TN"}, + {"name":"Texas", "label":"Texas","abbreviation":"TX"}, + {"name":"Utah", "label":"Utah","abbreviation":"UT"}, + {"name":"Vermont", "label":"Vermont","abbreviation":"VT"}, + {"name":"Virginia", "label":"Virginia","abbreviation":"VA"}, + {"name":"Washington", "label":"Washington","abbreviation":"WA"}, + {"name":"West Virginia", "label":"West Virginia","abbreviation":"WV"}, + {"name":"Wisconsin", "label":"Wisconsin","abbreviation":"WI"}, + {"name":"Wyoming", "label":"Wyoming","abbreviation":"WY"} +]} \ No newline at end of file diff --git a/includes/js/dojox/wire/ml/Action.js b/includes/js/dojox/wire/ml/Action.js new file mode 100644 index 0000000..637de41 --- /dev/null +++ b/includes/js/dojox/wire/ml/Action.js @@ -0,0 +1,225 @@ +if(!dojo._hasResource["dojox.wire.ml.Action"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.Action"] = true; +dojo.provide("dojox.wire.ml.Action"); +dojo.provide("dojox.wire.ml.ActionFilter"); + +dojo.require("dijit._Widget"); +dojo.require("dijit._Container"); +dojo.require("dojox.wire.Wire"); +dojo.require("dojox.wire.ml.util"); + +dojo.declare("dojox.wire.ml.Action", [dijit._Widget, dijit._Container], { + // summary: + // A base widget to "run" a task on an event or a topic + // description: + // This widget represents a controller task to be run when an event + // (a function) or a topic is issued. + // Sub-classes must implement _run() method to implement their tasks. + // 'trigger' specifies an event scope, an ID of a widget or an DOM + // element, or its property with the optional dotted notation. + // If this widget has child ActionFilter widgets, their filter() + // methods are called with the arguments to the event or the topic. + // If one of filter() methods returns false, run() won't be invoked. + // This widget also can serve as a composite task to run child + // Actions on an event or a topic specified to this widget. + // trigger: + // An event scope + // triggerEvent: + // An event (function) name + // triggerTopic: + // A topic name + trigger: "", + triggerEvent: "", + triggerTopic: "", + + postCreate: function(){ + // summary: + // Call _connect() + // description: + // See _connect(). + this._connect(); + }, + + _connect: function(){ + // summary: + // Connect run() method to an event or a topic + // description: + // If 'triggerEvent' and 'trigger' are specified, connect() is + // used to set up run() to be called on the event. + // If 'triggerTopic' is specified, subscribe() is used to set up + // run() to be called on the topic. + if(this.triggerEvent){ + if(this.trigger){ + var scope = dojox.wire.ml._getValue(this.trigger); + if(scope){ + if(!scope[this.triggerEvent]){ + // set a dummy function for an anonymous object + scope[this.triggerEvent] = function(){}; + } + this._triggerHandle = dojo.connect(scope, this.triggerEvent, this, "run"); + } + }else{ + var event = this.triggerEvent.toLowerCase(); + if(event == "onload"){ + var self = this; + dojo.addOnLoad(function(){ + self._run.apply(self, arguments); + }); + } + } + }else if(this.triggerTopic){ + this._triggerHandle = dojo.subscribe(this.triggerTopic, this, "run"); + } + }, + + _disconnect: function(){ + // summary: + // Disconnect run() method from an event or a topic + // description: + // If 'triggerEvent' and 'trigger' are specified, disconnect() is + // used to set up run() not to be called on the event. + // If 'triggerTopic' is specified, unsubscribe() is used to set up + // run() not to be called on the topic. + if(this._triggerHandle){ + if(this.triggerTopic){ + dojo.unsubscribe(this.triggerTopic, this._triggerHandle); + }else{ + dojo.disconnect(this._triggerHandle); + } + } + }, + + run: function(){ + // summary: + // Run a task + // description: + // This method calls filter() method of child ActionFilter + // widgets. + // If one of them returns false, this method returns. + // Otherwise, _run() method is called. + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if(child instanceof dojox.wire.ml.ActionFilter){ + if(!child.filter.apply(child, arguments)){ + return; + } + } + } + this._run.apply(this, arguments); + }, + + _run: function(){ + // summary: + // Call run() methods of child Action widgets + // description: + // If this widget has child Action widgets, their run() methods + // are called. + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if(child instanceof dojox.wire.ml.Action){ + child.run.apply(child, arguments); + } + } + }, + + uninitialize: function(){ + // summary: + // Over-ride of base widget unitialize function to do some connection cleanup. + this._disconnect(); + return true; + } +}); + +dojo.declare("dojox.wire.ml.ActionFilter", dijit._Widget, { + // summary: + // A widget to define a filter for the parent Action to run + // description: + // This base class checks a required property specified with + // 'required' attribute. + // If 'message' is specified, the message is set to a property + // specified with 'error'. + // Subclasses may implement their own filter() method. + // required: + // A property required + // requiredValue: + // Optional. A specific value the property is required to have. If this isn't provided + // than any non-false/non-null value of the required propery will cause this filter + // to pass. + // type: + // Optional. A specific type to compare the values as (if requiredValue is set) + // Valid values for type are boolean, int, string. Default is string. + // message: + // An error message to emit if the filter doesn't execute due to property mismatch. + // error: + // A property to store an error due to property mismatch. + required: "", + requiredValue: "", + type: "", + message: "", + error: "", + + + filter: function(){ + // summary: + // Check if a required property is specified. Also, if provided, check to see + // if the required property contains a specific value. + // description: + // If a value is undefined for a property, specified with + // 'required', this method returns false. + // If the value for a property is defined, but there isn't a requiredValue for it + // then any non-false value will cause the method to return true. + // if requiredValue is set, then filter compares that value with the value from + // the required property and returns true if and only if they match. + // The type option just allows for a way to convert the required property values + // into a proper form for comparison (boolean, number, etc). + // If 'message' is specified, it is set to a proeprty specified + // with 'error' or shown with alert(). + // If 'required' starts with "arguments", a property of + // the method arguments are checked. + // returns: + // True if a required property is specified (and if requiredValue is specified, + // that they match), otherwise false + if(this.required === ""){ + return true; //Boolean + }else{ + var value = dojox.wire.ml._getValue(this.required, arguments); + if(this.requiredValue === ""){ + //Just see if there's a value, nothing to compare it to. + if(value){ + return true; //Boolean + } + }else{ + //See if we need to type convert. + var reqValue = this.requiredValue; + if(this.type !== ""){ + var lType = this.type.toLowerCase(); + if(lType === "boolean"){ + if(reqValue.toLowerCase() === "false"){ + reqValue = false; + }else{ + reqValue = true; + } + }else if(lType === "number"){ + reqValue = parseInt(reqValue, 10); + } + } + if(value === reqValue){ + return true; //boolean + } + } + } + + if(this.message){ + if(this.error){ + dojox.wire.ml._setValue(this.error, this.message); + }else{ + alert(this.message); + } + } + return false; //Boolean + } +}); + +} diff --git a/includes/js/dojox/wire/ml/Data.js b/includes/js/dojox/wire/ml/Data.js new file mode 100644 index 0000000..71ab0ad --- /dev/null +++ b/includes/js/dojox/wire/ml/Data.js @@ -0,0 +1,143 @@ +if(!dojo._hasResource["dojox.wire.ml.Data"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.Data"] = true; +dojo.provide("dojox.wire.ml.Data"); +dojo.provide("dojox.wire.ml.DataProperty"); + +dojo.require("dijit._Widget"); +dojo.require("dijit._Container"); +dojo.require("dojox.wire.ml.util"); + +dojo.declare("dojox.wire.ml.Data", [dijit._Widget, dijit._Container], { + // summary: + // A widget for a data object + // description: + // This widget represents an object with '_properties' property. + // If child 'DataProperty' widgets exist, they are used to initialize + // propertiy values of '_properties' object. + + startup: function(){ + // summary: + // Call _initializeProperties() + // description: + // See _initializeProperties(). + this._initializeProperties(); + }, + + _initializeProperties: function(/*Boolean*/reset){ + // summary: + // Initialize a data object + // description: + // If this widget has child DataProperty widgets, their getValue() + // methods are called and set the return value to a property + // specified by 'name' attribute of the child widgets. + // reset: + // A boolean to reset current properties + if(!this._properties || reset){ + this._properties = {}; + } + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if((child instanceof dojox.wire.ml.DataProperty) && child.name){ + this.setPropertyValue(child.name, child.getValue()); + } + } + }, + + getPropertyValue: function(/*String*/property){ + // summary: + // Return a property value + // description: + // This method returns the value of a property, specified with + // 'property' argument, in '_properties' object. + // property: + // A property name + // returns: + // A property value + return this._properties[property]; //anything + }, + + setPropertyValue: function(/*String*/property, /*anything*/value){ + // summary: + // Store a property value + // description: + // This method stores 'value' as a property, specified with + // 'property' argument, in '_properties' object. + // property: + // A property name + // value: + // A property value + this._properties[property] = value; + } +}); + +dojo.declare("dojox.wire.ml.DataProperty", [dijit._Widget, dijit._Container], { + // summary: + // A widget to define a data property + // description: + // Attributes of this widget are used to add a property to the parent + // Data widget. + // 'type' attribute specifies one of "string", "number", "boolean", + // "array", "object" and "element" (DOM Element) + // (default to "string"). + // If 'type' is "array" or "object", child DataProperty widgets are + // used to initialize the array elements or the object properties. + // name: + // A property name + // type: + // A property type name + // value: + // A property value + name: "", + type: "", + value: "", + + getValue: function(){ + // summary: + // Returns a property value + // description: + // If 'type' is specified, 'value' attribute is converted to + // the specified type and returned. + // Otherwise, 'value' attribute is returned as is. + // returns: + // A property value + var value = this.value; + if(this.type){ + if(this.type == "number"){ + value = parseInt(value); + }else if(this.type == "boolean"){ + value = (value == "true"); + }else if(this.type == "array"){ + value = []; + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if(child instanceof dojox.wire.ml.DataProperty){ + value.push(child.getValue()); + } + } + }else if(this.type == "object"){ + value = {}; + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if((child instanceof dojox.wire.ml.DataProperty) && child.name){ + value[child.name] = child.getValue(); + } + } + }else if(this.type == "element"){ + value = new dojox.wire.ml.XmlElement(value); + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if((child instanceof dojox.wire.ml.DataProperty) && child.name){ + value.setPropertyValue(child.name, child.getValue()); + } + } + } + } + return value; //anything + } +}); + +} diff --git a/includes/js/dojox/wire/ml/DataStore.js b/includes/js/dojox/wire/ml/DataStore.js new file mode 100644 index 0000000..e366d05 --- /dev/null +++ b/includes/js/dojox/wire/ml/DataStore.js @@ -0,0 +1,116 @@ +if(!dojo._hasResource["dojox.wire.ml.DataStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.DataStore"] = true; +dojo.provide("dojox.wire.ml.DataStore"); + +dojo.require("dijit._Widget"); +dojo.require("dojox.wire._base"); + +dojo.declare("dojox.wire.ml.DataStore", dijit._Widget, { + // summary: + // A widget for a data store + // description: + // This widget represents a data store of 'storeClass' attribute. + // storeClass: + // A class name of a data store + storeClass: "", + + postCreate: function(){ + // summary: + // Call _createStore() + // description: + // See _createStore(). + this.store = this._createStore(); + }, + + _createStore: function(){ + // summary: + // Create a data store + // desription: + // A data store of 'storeClass' is created with arguments + // specified with attributes. + // returns: + // A data store + if(!this.storeClass){ + return null; //null + } + var storeClass = dojox.wire._getClass(this.storeClass); + if(!storeClass){ + return null; //null + } + var args = {}; + var attributes = this.domNode.attributes; + for(var i = 0; i < attributes.length; i++){ + var a = attributes.item(i); + if(a.specified && !this[a.nodeName]){ + args[a.nodeName] = a.nodeValue; + } + } + return new storeClass(args); //Object + }, + + getFeatures: function(){ + // summary: + // Call getFeatures() method of a data store + // description: + // See dojo.data.api.Read.getFeatures(). + // returns: + // A features object + return this.store.getFeatures(); //Object + }, + + fetch: function(/*Object*/request){ + // summary: + // Call fetch() method of a data store + // description: + // See dojo.data.api.Read.fetch(). + // request: + // A request object + // returns: + // A request object + return this.store.fetch(request); //Object + }, + + save: function(/*Object*/args){ + // summary: + // Call save() method of a data store + // description: + // See dojo.data.api.Write.save(). + // args: + // A save arguments object + this.store.save(args); + }, + + newItem: function(/*Object*/args){ + // summary: + // Call newItem() method of a data store + // description: + // See dojo.data.api.Write.newItem(). + // args: + // A new item arguments object + // returns: + // A new item + return this.store.newItem(args); //Object + }, + + deleteItem: function(/*Object*/item){ + // summary: + // Call deleteItem() method of a data store + // description: + // See dojo.data.api.Write.deleteItem(). + // returns: + // A boolean + return this.store.deleteItem(item); //Boolean + }, + + revert: function(){ + // summary: + // Call revert() method of a data store + // description: + // See dojo.data.api.Write.revert(). + // returns: + // A boolean + return this.store.revert(); //Boolean + } +}); + +} diff --git a/includes/js/dojox/wire/ml/Invocation.js b/includes/js/dojox/wire/ml/Invocation.js new file mode 100644 index 0000000..3d36623 --- /dev/null +++ b/includes/js/dojox/wire/ml/Invocation.js @@ -0,0 +1,171 @@ +if(!dojo._hasResource["dojox.wire.ml.Invocation"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.Invocation"] = true; +dojo.provide("dojox.wire.ml.Invocation"); + +dojo.require("dojox.wire.ml.Action"); + +dojo.declare("dojox.wire.ml.Invocation", dojox.wire.ml.Action, { + // summary: + // A widget to invoke a method or publish a topic + // description: + // This widget represents a controller task to invoke a method or + // publish a topic when an event (a function) or a topic is issued. + // object: + // A scope of a method to invoke + // method: + // A name of a method to invoke + // topic: + // A name of a topic to publish + // parameters: + // Arguments for the method or the topic + // result: + // A property to store a return value of the method call + // error: + // A property to store an error on the method call + object: "", + method: "", + topic: "", + parameters: "", + result: "", + error: "", + + _run: function(){ + // summary: + // Invoke a method or publish a topic + // description: + // If 'topic' is specified, the topic is published with arguments + // specified to 'parameters'. + // If 'method' and 'object' are specified, the method is invoked + // with arguments specified to 'parameters' and set the return + // value to a property specified to 'result'. + // 'object', 'parameters' and 'result' can specify properties of + // a widget or an DOM element with the dotted notation. + // If 'parameters' are omitted, the arguments to this method are + // passed as is. + if(this.topic){ + var args = this._getParameters(arguments); + try{ + dojo.publish(this.topic, args); + this.onComplete(); + }catch(e){ + this.onError(e); + } + }else if(this.method){ + var scope = (this.object ? dojox.wire.ml._getValue(this.object) : dojo.global); + if(!scope){ + return; //undefined + } + var args = this._getParameters(arguments); + var func = scope[this.method]; + if(!func){ + func = scope.callMethod; + if(!func){ + return; //undefined + } + args = [this.method, args]; + } + try{ + var connected = false; + if(scope.getFeatures){ + var features = scope.getFeatures(); + if((this.method == "fetch" && features["dojo.data.api.Read"]) || + (this.method == "save" && features["dojo.data.api.Write"])){ + var arg = args[0]; + if(!arg.onComplete){ + arg.onComplete = function(){}; + } + //dojo.connect(arg, "onComplete", this, "onComplete"); + this.connect(arg, "onComplete", "onComplete"); + if(!arg.onError){ + arg.onError = function(){}; + } + //dojo.connect(arg, "onError", this, "onError"); + this.connect(arg, "onError", "onError"); + connected = true; + } + } + var r = func.apply(scope, args); + if(!connected){ + if(r && (r instanceof dojo.Deferred)){ + var self = this; + r.addCallbacks( + function(result){self.onComplete(result);}, + function(error){self.onError(error);} + ); + }else{ + this.onComplete(r); + } + } + }catch(e){ + this.onError(e); + } + } + }, + + onComplete: function(/*anything*/result){ + // summary: + // A function called when the method or the topic publish + // completed + // description: + // If 'result' attribute is specified, the result object also set + // to the specified property. + // result: + // The return value of a method or undefined for a topic + if(this.result){ + dojox.wire.ml._setValue(this.result, result); + } + if(this.error){ // clear error + dojox.wire.ml._setValue(this.error, ""); + } + }, + + onError: function(/*anything*/error){ + // summary: + // A function called on an error occurs + // description: + // If 'error' attribute is specified, the error object also set to + // the specified property. + // error: + // The exception or error occurred + if(this.error){ + if(error && error.message){ + error = error.message; + } + dojox.wire.ml._setValue(this.error, error); + } + }, + + _getParameters: function(/*Array*/args){ + // summary: + // Returns arguments to a method or topic to invoke + // description: + // This method retunrs an array of arguments specified by + // 'parameters' attribute, a comma-separated list of IDs and + // their properties in a dotted notation. + // If 'parameters' are omitted, the original arguments are + // used. + // args: + // Arguments to a trigger event or topic + if(!this.parameters){ + // use arguments as is + return args; //Array + } + var parameters = []; + var list = this.parameters.split(","); + if(list.length == 1){ + var parameter = dojox.wire.ml._getValue(dojo.trim(list[0]), args); + if(dojo.isArray(parameter)){ + parameters = parameter; + }else{ + parameters.push(parameter); + } + }else{ + for(var i in list){ + parameters.push(dojox.wire.ml._getValue(dojo.trim(list[i]), args)); + } + } + return parameters; //Array + } +}); + +} diff --git a/includes/js/dojox/wire/ml/Service.js b/includes/js/dojox/wire/ml/Service.js new file mode 100644 index 0000000..15f074b --- /dev/null +++ b/includes/js/dojox/wire/ml/Service.js @@ -0,0 +1,340 @@ +if(!dojo._hasResource["dojox.wire.ml.Service"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.Service"] = true; +dojo.provide("dojox.wire.ml.Service"); +dojo.provide("dojox.wire.ml.RestHandler"); +dojo.provide("dojox.wire.ml.XmlHandler"); +dojo.provide("dojox.wire.ml.JsonHandler"); + +dojo.require("dijit._Widget"); +dojo.require("dojox.data.dom"); +dojo.require("dojox.wire._base"); +dojo.require("dojox.wire.ml.util"); + +dojo.declare("dojox.wire.ml.Service", dijit._Widget, { + // summary: + // A widget for a service + // description: + // This widget represents a service defined by a service description + // specified with 'url' attribute. + // If 'serviceType' and 'serviceUrl' attributes are specified, 'url' + // attribute can be omitted. + // url: + // A URL to a service description + // serviceUrl: + // A URL to a service + // serviceType: + // A service type + // handlerClass: + // A service handler class name + url: "", + serviceUrl: "", + serviceType: "", + handlerClass: "", + preventCache: true, + + postCreate: function(){ + // summary: + // Call _createHandler() + // description: + // See _createHandler(). + this.handler = this._createHandler(); + }, + + _handlerClasses: { + "TEXT": "dojox.wire.ml.RestHandler", + "XML": "dojox.wire.ml.XmlHandler", + "JSON": "dojox.wire.ml.JsonHandler", + "JSON-RPC": "dojo.rpc.JsonService" + }, + + _createHandler: function(){ + // summary: + // Create a service handler + // desription: + // A service handler class is determined by: + // 1. 'handlerClass' attribute + // 2. 'serviceType' attribute + // 3. 'serviceType' property in a service description + // returns: + // A service handler + if(this.url){ + var self = this; + var d = dojo.xhrGet({ + url: this.url, + handleAs: "json", + sync: true + }); + d.addCallback(function(result){ + self.smd = result; + }); + if(this.smd && !this.serviceUrl){ + this.serviceUrl = (this.smd.serviceUrl || this.smd.serviceURL); + } + } + var handlerClass = undefined; + if(this.handlerClass){ + handlerClass = dojox.wire._getClass(this.handlerClass); + }else if(this.serviceType){ + handlerClass = this._handlerClasses[this.serviceType]; + if(handlerClass && dojo.isString(handlerClass)){ + handlerClass = dojox.wire._getClass(handlerClass); + this._handlerClasses[this.serviceType] = handlerClass; + } + }else if(this.smd && this.smd.serviceType){ + handlerClass = this._handlerClasses[this.smd.serviceType]; + if(handlerClass && dojo.isString(handlerClass)){ + handlerClass = dojox.wire._getClass(handlerClass); + this._handlerClasses[this.smd.serviceType] = handlerClass; + } + } + if(!handlerClass){ + return null; //null + } + return new handlerClass(); //Object + }, + + callMethod: function(method, parameters){ + // summary: + // Call a service method with parameters + // method: + // A method name + // parameters: + // An array parameters + var deferred = new dojo.Deferred(); + this.handler.bind(method, parameters, deferred, this.serviceUrl); + return deferred; + } +}); + +dojo.declare("dojox.wire.ml.RestHandler", null, { + // summary: + // A REST service handler + // description: + // This class serves as a base REST service. + // Sub-classes may override _getContent() and _getResult() to handle + // specific content types. + contentType: "text/plain", + handleAs: "text", + + bind: function(method, parameters, deferred, url){ + // summary: + // Call a service method with parameters. + // description: + // A service is called with a URL generated by _getUrl() and + // an HTTP method specified with 'method'. + // For "POST" and "PUT", a content is generated by _getContent(). + // When data is loaded, _getResult() is used to pass the result to + // Deferred.callback(). + // method: + // A method name + // parameters: + // An array of parameters + // deferred: + // 'Deferred' + // url: + // A URL for the method + method = method.toUpperCase(); + var self = this; + var args = { + url: this._getUrl(method, parameters, url), + contentType: this.contentType, + handleAs: this.handleAs, + headers: this.headers, + preventCache: this.preventCache + }; + var d = null; + if(method == "POST"){ + args.postData = this._getContent(method, parameters); + d = dojo.rawXhrPost(args); + }else if(method == "PUT"){ + args.putData = this._getContent(method, parameters); + d = dojo.rawXhrPut(args); + }else if(method == "DELETE"){ + d = dojo.xhrDelete(args); + }else{ // "GET" + d = dojo.xhrGet(args); + } + d.addCallbacks(function(result){ + deferred.callback(self._getResult(result)); + }, function(error){ + deferred.errback(error); + }); + }, + + _getUrl: function(/*String*/method, /*Array*/parameters, /*String*/url){ + // summary: + // Generate a URL + // description: + // If 'method' is "GET" or "DELETE", a query string is generated + // from a query object specified to the first parameter in + // 'parameters' and appended to 'url'. + // If 'url' contains variable seguments ("{parameter_name}"), + // they are replaced with corresponding parameter values, instead. + // method: + // A method name + // parameters: + // An array of parameters + // url: + // A base URL + // returns: + // A URL + var query; + if(method == "GET" || method == "DELETE"){ + if(parameters.length > 0){ + query = parameters[0]; + } + }else{ // "POST" || "PUT" + if(parameters.length > 1){ + query = parameters[1]; + } + } + if(query){ + var queryString = ""; + for(var name in query){ + var value = query[name]; + if(value){ + value = encodeURIComponent(value); + var variable = "{" + name + "}"; + var index = url.indexOf(variable); + if(index >= 0){ // encode in path + url = url.substring(0, index) + value + url.substring(index + variable.length); + }else{ // encode as query string + if(queryString){ + queryString += "&"; + } + queryString += (name + "=" + value); + } + } + } + if(queryString){ + url += "?" + queryString; + } + } + return url; //String + }, + + _getContent: function(/*String*/method, /*Array*/parameters){ + // summary: + // Generate a request content + // description: + // If 'method' is "POST" or "PUT", the first parameter in + // 'parameters' is returned. + // method: + // A method name + // parameters: + // An array of parameters + // returns: + // A request content + if(method == "POST" || method == "PUT"){ + return (parameters ? parameters[0] : null); //anything + }else{ + return null; //null + } + }, + + _getResult: function(/*anything*/data){ + // summary: + // Extract a result + // description: + // A response data is returned as is. + // data: + // A response data returned by a service + // returns: + // A result object + return data; //anything + } +}); + +dojo.declare("dojox.wire.ml.XmlHandler", dojox.wire.ml.RestHandler, { + // summary: + // A REST service handler for XML + // description: + // This class provides XML handling for a REST service. + contentType: "text/xml", + handleAs: "xml", + + _getContent: function(/*String*/method, /*Array*/parameters){ + // description: + // If 'method' is "POST" or "PUT", the first parameter in + // 'parameters' is used to generate an XML content. + // method: + // A method name + // parameters: + // An array of parameters + // returns: + // A request content + var content = null; + if(method == "POST" || method == "PUT"){ + var p = parameters[0]; + if(p){ + if(dojo.isString(p)){ + content = p; + }else{ + var element = p; + if(element instanceof dojox.wire.ml.XmlElement){ + element = element.element; + }else if(element.nodeType === 9 /* DOCUMENT_NODE */){ + element = element.documentElement; + } + var declaration = ""; // TODO: encoding? + content = declaration + dojox.data.dom.innerXML(element); + } + } + } + return content; + }, + + _getResult: function(/*Document*/data){ + // summary: + // Extract a result + // description: + // A response data (XML Document) is returned wrapped with + // XmlElement. + // data: + // A response data returned by a service + // returns: + // A result object + if(data){ + data = new dojox.wire.ml.XmlElement(data); + } + return data; + } +}); + +dojo.declare("dojox.wire.ml.JsonHandler", dojox.wire.ml.RestHandler, { + // summary: + // A REST service handler for JSON + // description: + // This class provides JSON handling for a REST service. + contentType: "text/json", + handleAs: "json", + headers: {"Accept": "*/json"}, + + _getContent: function(/*String*/method, /*Array*/parameters){ + // summary: + // Generate a request content + // description: + // If 'method' is "POST" or "PUT", the first parameter in + // 'parameter' is used to generate a JSON content. + // method: + // A method name + // parameters: + // An array of parameters + // returns: + // A request content + var content = null; + if(method == "POST" || method == "PUT"){ + var p = (parameters ? parameters[0] : undefined); + if(p){ + if(dojo.isString(p)){ + content = p; + }else{ + content = dojo.toJson(p); + } + } + } + return content; //String + } +}); + +} diff --git a/includes/js/dojox/wire/ml/Transfer.js b/includes/js/dojox/wire/ml/Transfer.js new file mode 100644 index 0000000..c7780ca --- /dev/null +++ b/includes/js/dojox/wire/ml/Transfer.js @@ -0,0 +1,359 @@ +if(!dojo._hasResource["dojox.wire.ml.Transfer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.Transfer"] = true; +dojo.provide("dojox.wire.ml.Transfer"); +dojo.provide("dojox.wire.ml.ChildWire"); +dojo.provide("dojox.wire.ml.ColumnWire"); +dojo.provide("dojox.wire.ml.NodeWire"); +dojo.provide("dojox.wire.ml.SegmentWire"); + +dojo.require("dijit._Widget"); +dojo.require("dijit._Container"); +dojo.require("dojox.wire._base"); +dojo.require("dojox.wire.ml.Action"); + +dojo.declare("dojox.wire.ml.Transfer", dojox.wire.ml.Action, { + // summary: + // A widget to transfer values through source and target Wires + // description: + // This widget represents a controller task to transfer a value from + // a source to a target, through a source and a target Wires, when + // an event (a function) or a topic is issued. + // If this widget has child ChildWire widgets, their _addWire() + // methods are called to add Wire arguments to a source or a target + // Wire. + // source: + // A source object and/or property + // sourceStore: + // A data store for a source data item + // sourceAttribute: + // An attribute of a source data item + // sourcePath: + // A simplified XPath to a source property of an XML element + // type: + // A type of the value to be transferred + // converter: + // A class name of a converter for the value to be transferred + // target: + // A target object and/or property + // targetStore: + // A data store for a target data item + // targetAttribute: + // An attribute of a target data item + // targetPath: + // A simplified XPath to a target property of an XML element + source: "", + sourceStore: "", + sourceAttribute: "", + sourcePath: "", + type: "", + converter: "", + delimiter: "", + target: "", + targetStore: "", + targetAttribute: "", + targetPath: "", + + _run: function(){ + // summary: + // Transfer a value from a source to a target + // description: + // First, Wires for a source and a target are created from attributes. + // Then, a value is obtained by getValue() of the source Wire is set + // by setValue() of the target Wire. + // The arguments to this method is passed to getValue() and setValue() + // of Wires, so that they can be used to identify the root objects off + // the arguments. + var sourceWire = this._getWire("source"); + var targetWire = this._getWire("target"); + dojox.wire.transfer(sourceWire, targetWire, arguments); + }, + + _getWire: function(/*String*/which){ + // summary: + // Build Wire arguments from attributes + // description: + // Arguments object for a source or a target Wire, specified by + // 'which' argument, are build from corresponding attributes, + // including '*Store' (for 'dataStore'), '*Attribute' + // (for 'attribute), '*Path' (for 'path'), 'type' and 'converter'. + // 'source' or 'target' attribute is parsed as: + // "object_id.property_name[.sub_property_name...]" + // If 'source' or 'target' starts with "arguments", 'object' + // argument for a Wire is set to null, so that the root object is + // given as an event or topic arguments. + // If this widget has child ChildWire widgets with a corresponding + // 'which' attribute, their _addWire() methods are called to add + // additional Wire arguments and nested Wire is created, + // specifying the Wire defined by this widget to 'object' argument. + // which: + // Which Wire arguments to build, "source" or "target" + // returns: + // Wire arguments object + var args = undefined; + if(which == "source"){ + args = { + object: this.source, + dataStore: this.sourceStore, + attribute: this.sourceAttribute, + path: this.sourcePath, + type: this.type, + converter: this.converter + }; + }else{ // "target" + args = { + object: this.target, + dataStore: this.targetStore, + attribute: this.targetAttribute, + path: this.targetPath + }; + } + if(args.object){ + if(args.object.length >= 9 && args.object.substring(0, 9) == "arguments"){ + args.property = args.object.substring(9); + args.object = null; + }else{ + var i = args.object.indexOf('.'); + if(i < 0){ + args.object = dojox.wire.ml._getValue(args.object); + }else{ + args.property = args.object.substring(i + 1); + args.object = dojox.wire.ml._getValue(args.object.substring(0, i)); + } + } + } + if(args.dataStore){ + args.dataStore = dojox.wire.ml._getValue(args.dataStore); + } + var childArgs = undefined; + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if(child instanceof dojox.wire.ml.ChildWire && child.which == which){ + if(!childArgs){ + childArgs = {}; + } + child._addWire(this, childArgs); + } + } + if(childArgs){ // make nested Wires + childArgs.object = dojox.wire.create(args); + childArgs.dataStore = args.dataStore; + args = childArgs; + } + return args; //Object + } +}); + +dojo.declare("dojox.wire.ml.ChildWire", dijit._Widget, { + // summary: + // A widget to add a child wire + // description: + // Attributes of this widget are used to add a child Wire to + // a composite Wire of the parent Transfer widget. + // which: + // Which Wire to add a child Wire, "source" or "target", default to + // "source" + // object: + // A root object for the value + // property: + // A property for the value + // type: + // A type of the value + // converter: + // A class name of a converter for the value + // attribute: + // A data item attribute for the value + // path: + // A simplified XPath for the value + // name: + // A composite property name + which: "source", + object: "", + property: "", + type: "", + converter: "", + attribute: "", + path: "", + name: "", + + _addWire: function(/*Transfer*/parent, /*Object*/args){ + // summary: + // Add a child Wire to Wire arguments + // description: + // If 'name' attribute is specified, a child Wire is added as + // the named property of 'children' object of 'args'. + // Otherwise, a child Wire is added to 'children' array of 'args'. + // parent: + // A parent Transfer widget + // args: + // Wire arguments + if(this.name){ // object + if(!args.children){ + args.children = {}; + } + args.children[this.name] = this._getWire(parent); + }else{ // array + if(!args.children){ + args.children = []; + } + args.children.push(this._getWire(parent)); + } + }, + + _getWire: function(/*Transfer*/parent){ + // summary: + // Build child Wire arguments from attributes + // description: + // Arguments object for a child Wire are build from attributes, + // including 'object', 'property', 'type', 'converter', + // 'attribute' and 'path'. + // parent: + // A parent Transfer widget + // returns: + // Wire arguments object + return { + object: (this.object ? dojox.wire.ml._getValue(this.object) : undefined), + property: this.property, + type: this.type, + converter: this.converter, + attribute: this.attribute, + path: this.path + }; //Object + } +}); + +dojo.declare("dojox.wire.ml.ColumnWire", dojox.wire.ml.ChildWire, { + // summary: + // A widget to add a column wire + // description: + // Attributes of this widget are used to add a column Wire to + // a TableAdapter of the parent Transfer widget. + // column: + // A column name + column: "", + + _addWire: function(/*Transfer*/parent, /*Object*/args){ + // summary: + // Add a column Wire to Wire arguments + // description: + // If 'column' attribute is specified, a column Wire is added as + // the named property of 'columns' object of 'args'. + // Otherwise, a column Wire is added to 'columns' array of 'args'. + // parent: + // A parent Transfer widget + // args: + // Wire arguments + if(this.column){ // object + if(!args.columns){ + args.columns = {}; + } + args.columns[this.column] = this._getWire(parent); + }else{ // array + if(!args.columns){ + args.columns = []; + } + args.columns.push(this._getWire(parent)); + } + } +}); + +dojo.declare("dojox.wire.ml.NodeWire", [dojox.wire.ml.ChildWire, dijit._Container], { + // summary: + // A widget to add node wires + // description: + // Attributes of this widget are used to add node Wires to + // a TreeAdapter of the parent Transfer widget. + // titleProperty: + // A property for the node title + // titleAttribute: + // A data item attribute for the node title + // titlePath: + // A simplified XPath for the node title + titleProperty: "", + titleAttribute: "", + titlePath: "", + + _addWire: function(/*Transfer*/parent, /*Object*/args){ + // summary: + // Add node Wires to Wire arguments + // description: + // Node Wires are added to 'nodes' array of 'args'. + // parent: + // A parent Transfer widget + // args: + // Wire arguments + if(!args.nodes){ + args.nodes = []; + } + args.nodes.push(this._getWires(parent)); + }, + + _getWires: function(/*Transfer*/parent){ + // summary: + // Build node Wires arguments from attributes + // description: + // Arguments object for 'node' Wire are build from attributes, + // including 'object', 'property', 'type', 'converter', + // 'attribute' and 'path'. + // Arguments object for 'title' Wire are build from another set of + // attributes, 'titleProperty', 'titleAttribute' and 'titlePath'. + // If this widget has child NodeWire widgets, their _getWires() + // methods are called recursively to build 'children' array of + // 'args'. + // parent: + // A parent Transfer widget + // returns: + // Wire arguments object + var args = { + node: this._getWire(parent), + title: { + type: "string", + property: this.titleProperty, + attribute: this.titleAttribute, + path: this.titlePath + } + }; + var childArgs = []; + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if(child instanceof dojox.wire.ml.NodeWire){ + childArgs.push(child._getWires(parent)); + } + } + if(childArgs.length > 0){ + args.children = childArgs; + } + return args; //Object + } +}); + +dojo.declare("dojox.wire.ml.SegmentWire", dojox.wire.ml.ChildWire, { + // summary: + // A widget to add a segment wire + // description: + // Attributes of this widget are used to add a segment Wire to + // a TextAdapter of the parent Transfer widget. + + _addWire: function(/*Transfer*/parent, /*Object*/args){ + // summary: + // Add a segument Wire to Wire arguments + // description: + // A segment Wire is added to 'segments' array of 'args'. + // If 'parent' has 'delimiter' attribute, it is used for + // 'delimiter' property of 'args'. + // parent: + // A parent Transfer widget + // args: + // Wire arguments + if(!args.segments){ + args.segments = []; + } + args.segments.push(this._getWire(parent)); + if(parent.delimiter && !args.delimiter){ + args.delimiter = parent.delimiter; + } + } +}); + +} diff --git a/includes/js/dojox/wire/ml/util.js b/includes/js/dojox/wire/ml/util.js new file mode 100644 index 0000000..a336b28 --- /dev/null +++ b/includes/js/dojox/wire/ml/util.js @@ -0,0 +1,295 @@ +if(!dojo._hasResource["dojox.wire.ml.util"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.util"] = true; +dojo.provide("dojox.wire.ml.util"); + +dojo.require("dojox.data.dom"); +dojo.require("dojox.wire.Wire"); + +dojox.wire.ml._getValue = function(/*String*/source, /*Array*/args){ + // summary: + // Return a value + // description: + // This method obtains an object by an ID of a widget or an DOM + // element. + // If 'source' specifies a dotted notation to its property, a Wire is + // used to get the object property. + // If 'source' starts with "arguments", 'args' is used as a root + // object for the Wire. + // source: + // A string to specify an object and its property + // args: + // An optional arguments array + // returns: + // A value + if(!source){ + return undefined; //undefined + } + var property = undefined; + if(args && source.length >= 9 && source.substring(0, 9) == "arguments"){ + property = source.substring(9); + return new dojox.wire.Wire({property: property}).getValue(args); + } + var i = source.indexOf('.'); + if(i >= 0){ + property = source.substring(i + 1); + source = source.substring(0, i); + } + var object = (dijit.byId(source) || dojo.byId(source) || dojo.getObject(source)); + if(!object){ + return undefined; //undefined + } + if(!property){ + return object; //Object + }else{ + return new dojox.wire.Wire({object: object, property: property}).getValue(); //anything + } +}; + +dojox.wire.ml._setValue = function(/*String*/target, /*anything*/value){ + // summary: + // Store a value + // description: + // This method stores a value by an ID of a widget or an DOM + // element with a dotted notation to its property, using a Wire. + // target: + // A string to specify an object and its property + // value: + // A value + if(!target){ + return; //undefined + } + var i = target.indexOf('.'); + if(i < 0){ + return; //undefined + } + var object = this._getValue(target.substring(0, i)); + if(!object){ + return; //undefined + } + var property = target.substring(i + 1); + new dojox.wire.Wire({object: object, property: property}).setValue(value); +}; + +dojo.declare("dojox.wire.ml.XmlElement", null, { + // summary: + // An object wrapping an XML element + // description: + // This class represents an XML element. + + constructor: function(/*Element||String*/element){ + // summary: + // Initialize with an XML element or a tag name + // element: + // An XML element or a tag name + if(dojo.isString(element)){ + element = this._getDocument().createElement(element); + } + this.element = element; + }, + getPropertyValue: function(/*String*/property){ + // summary: + // Return a property value + // description: + // If 'property' starts with '@', the attribute value is returned. + // If 'property' specifies "text()", the value of the first child + // text is returned. + // Otherwise, child elements of the tag name specified with + // 'property' are returned. + // property: + // A property name + // returns: + // A property value + var value = undefined; + if(!this.element){ + return value; //undefined + } + if(!property){ + return value; //undefined + } + + if(property.charAt(0) == '@'){ + var attribute = property.substring(1); + value = this.element.getAttribute(attribute); + }else if(property == "text()"){ + var text = this.element.firstChild; + if(text){ + value = text.nodeValue; + } + }else{ // child elements + var elements = []; + for(var i = 0; i < this.element.childNodes.length; i++){ + var child = this.element.childNodes[i]; + if(child.nodeType === 1 /* ELEMENT_NODE */ && child.nodeName == property){ + elements.push(new dojox.wire.ml.XmlElement(child)); + } + } + if(elements.length > 0){ + if(elements.length === 1){ + value = elements[0]; + }else{ + value = elements; + } + } + } + return value; //String||Array||XmlElement + }, + + setPropertyValue: function(/*String*/property, /*String||Array||XmlElement*/value){ + // summary: + // Store a property value + // description: + // If 'property' starts with '@', 'value' is set to the attribute. + // If 'property' specifies "text()", 'value' is set as the first + // child text. + // If 'value' is a string, a child element of the tag name + // specified with 'property' is created and 'value' is set as + // the first child text of the child element. + // Otherwise, 'value' is set to as child elements. + // property: + // A property name + // value: + // A property value + if(!this.element){ + return; //undefined + } + if(!property){ + return; //undefined + } + + if(property.charAt(0) == '@'){ + var attribute = property.substring(1); + if(value){ + this.element.setAttribute(attribute, value); + }else{ + this.element.removeAttribute(attribute); + } + }else if(property == "text()"){ + while(this.element.firstChild){ + this.element.removeChild(this.element.firstChild); + } + if(value){ + var text = this._getDocument().createTextNode(value); + this.element.appendChild(text); + } + }else{ // child elements + var nextChild = null; + for(var i = this.element.childNodes.length - 1; i >= 0; i--){ + var child = this.element.childNodes[i]; + if(child.nodeType === 1 /* ELEMENT_NODE */ && child.nodeName == property){ + if(!nextChild){ + nextChild = child.nextSibling; + } + this.element.removeChild(child); + } + } + if(value){ + if(dojo.isArray(value)){ + for(var i in value){ + var e = value[i]; + if(e.element){ + this.element.insertBefore(e.element, nextChild); + } + } + }else if(value instanceof dojox.wire.ml.XmlElement){ + if(value.element){ + this.element.insertBefore(value.element, nextChild); + } + }else{ // assume string + var child = this._getDocument().createElement(property); + var text = this._getDocument().createTextNode(value); + child.appendChild(text); + this.element.insertBefore(child, nextChild); + } + } + } + }, + + toString: function(){ + // summary: + // Return a value of the first text child of the element + // description: + // A value of the first text child of the element is returned. + // returns: + // A value of the first text child of the element + var s = ""; + if(this.element){ + var text = this.element.firstChild; + if(text){ + s = text.nodeValue; + } + } + return s; //String + }, + + toObject: function(){ + // summary: + // Return an object representation of the element + // description: + // An object with properties for child elements, attributes and + // text is returned. + // returns: + // An object representation of the element + if(!this.element){ + return null; //null + } + var text = ""; + var obj = {}; + var elements = 0; + for(var i = 0; i < this.element.childNodes.length; i++){ + var child = this.element.childNodes[i]; + if(child.nodeType === 1 /* ELEMENT_NODE */){ + elements++; + var o = new dojox.wire.ml.XmlElement(child).toObject(); + var name = child.nodeName; + var p = obj[name]; + if(!p){ + obj[name] = o; + }else if(dojo.isArray(p)){ + p.push(o); + }else{ + obj[name] = [p, o]; // make them array + } + }else if(child.nodeType === 3 /* TEXT_NODE */ || + child.nodeType === 4 /* CDATA_SECTION_NODE */){ + text += child.nodeValue; + } + } + var attributes = 0; + if(this.element.nodeType === 1 /* ELEMENT_NODE */){ + attributes = this.element.attributes.length; + for(var i = 0; i < attributes; i++){ + var attr = this.element.attributes[i]; + obj["@" + attr.nodeName] = attr.nodeValue; + } + } + if(elements === 0){ + if(attributes === 0){ + // text only + return text; //String + } + // text with attributes + obj["text()"] = text; + } + // else ignore text + return obj; //Object + }, + + _getDocument: function(){ + // summary: + // Return a DOM document + // description: + // If 'element' is specified, a DOM document of the element is + // returned. + // Otherwise, a DOM document is created. + // returns: + // A DOM document + if(this.element){ + return (this.element.nodeType == 9 /* DOCUMENT_NODE */ ? + this.element : this.element.ownerDocument); //Document + }else{ + return dojox.data.dom.createDocument(); //Document + } + } +}); + +} diff --git a/includes/js/dojox/wire/tests/markup/Action.html b/includes/js/dojox/wire/tests/markup/Action.html new file mode 100644 index 0000000..75cbd49 --- /dev/null +++ b/includes/js/dojox/wire/tests/markup/Action.html @@ -0,0 +1,147 @@ + + +Test Action + + + + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + + + diff --git a/includes/js/dojox/wire/tests/markup/Data.html b/includes/js/dojox/wire/tests/markup/Data.html new file mode 100644 index 0000000..b1107c0 --- /dev/null +++ b/includes/js/dojox/wire/tests/markup/Data.html @@ -0,0 +1,105 @@ + + +Test Data + + + + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + + diff --git a/includes/js/dojox/wire/tests/markup/DataStore.html b/includes/js/dojox/wire/tests/markup/DataStore.html new file mode 100644 index 0000000..3c55f7e --- /dev/null +++ b/includes/js/dojox/wire/tests/markup/DataStore.html @@ -0,0 +1,66 @@ + + +Test DataStore + + + + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + + diff --git a/includes/js/dojox/wire/tests/markup/DataStore.xml b/includes/js/dojox/wire/tests/markup/DataStore.xml new file mode 100644 index 0000000..eeff4c2 --- /dev/null +++ b/includes/js/dojox/wire/tests/markup/DataStore.xml @@ -0,0 +1,18 @@ + + + + X1 + Y1 + Z1 + + + X2 + Y2 + Z2 + + + X3 + Y3 + Z3 + + diff --git a/includes/js/dojox/wire/tests/markup/Invocation.html b/includes/js/dojox/wire/tests/markup/Invocation.html new file mode 100644 index 0000000..dd6f6e4 --- /dev/null +++ b/includes/js/dojox/wire/tests/markup/Invocation.html @@ -0,0 +1,53 @@ + + +Test Invocation + + + + +
                        +
                        +
                        + + diff --git a/includes/js/dojox/wire/tests/markup/Service.html b/includes/js/dojox/wire/tests/markup/Service.html new file mode 100644 index 0000000..0448c61 --- /dev/null +++ b/includes/js/dojox/wire/tests/markup/Service.html @@ -0,0 +1,84 @@ + + +Test Service + + + + +
                        +
                        +
                        +
                        +
                        +
                        + + diff --git a/includes/js/dojox/wire/tests/markup/Service/JSON.smd b/includes/js/dojox/wire/tests/markup/Service/JSON.smd new file mode 100644 index 0000000..2ac9682 --- /dev/null +++ b/includes/js/dojox/wire/tests/markup/Service/JSON.smd @@ -0,0 +1,11 @@ +{ + "serviceType": "JSON", + "serviceURL": "Service/{name}.json", + "methods": [{ + "name": "get", + "parameters": [{ + "name": "name", + "type": "str" + }] + }] +} diff --git a/includes/js/dojox/wire/tests/markup/Service/XML.smd b/includes/js/dojox/wire/tests/markup/Service/XML.smd new file mode 100644 index 0000000..d833f88 --- /dev/null +++ b/includes/js/dojox/wire/tests/markup/Service/XML.smd @@ -0,0 +1,11 @@ +{ + "serviceType": "XML", + "serviceURL": "Service/{name}.xml", + "methods": [{ + "name": "get", + "parameters": [{ + "name": "name", + "type": "str" + }] + }] +} diff --git a/includes/js/dojox/wire/tests/markup/Service/a.json b/includes/js/dojox/wire/tests/markup/Service/a.json new file mode 100644 index 0000000..93fc00b --- /dev/null +++ b/includes/js/dojox/wire/tests/markup/Service/a.json @@ -0,0 +1,5 @@ +{ + "item": { + "name": "a" + } +} diff --git a/includes/js/dojox/wire/tests/markup/Service/a.xml b/includes/js/dojox/wire/tests/markup/Service/a.xml new file mode 100644 index 0000000..21e4367 --- /dev/null +++ b/includes/js/dojox/wire/tests/markup/Service/a.xml @@ -0,0 +1,5 @@ + + + a + + diff --git a/includes/js/dojox/wire/tests/markup/Transfer.html b/includes/js/dojox/wire/tests/markup/Transfer.html new file mode 100644 index 0000000..3ec11a4 --- /dev/null +++ b/includes/js/dojox/wire/tests/markup/Transfer.html @@ -0,0 +1,157 @@ + + +Test Transfer + + + + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + + diff --git a/includes/js/dojox/wire/tests/module.js b/includes/js/dojox/wire/tests/module.js new file mode 100644 index 0000000..17f10c3 --- /dev/null +++ b/includes/js/dojox/wire/tests/module.js @@ -0,0 +1,13 @@ +if(!dojo._hasResource["dojox.wire.tests.module"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.tests.module"] = true; +dojo.provide("dojox.wire.tests.module"); + +try{ + dojo.require("dojox.wire.tests.wire"); + dojo.require("dojox.wire.tests.wireml"); +}catch(e){ + doh.debug(e); +} + + +} diff --git a/includes/js/dojox/wire/tests/programmatic/CompositeWire.js b/includes/js/dojox/wire/tests/programmatic/CompositeWire.js new file mode 100644 index 0000000..ae9866a --- /dev/null +++ b/includes/js/dojox/wire/tests/programmatic/CompositeWire.js @@ -0,0 +1,51 @@ +if(!dojo._hasResource["dojox.wire.tests.programmatic.CompositeWire"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.tests.programmatic.CompositeWire"] = true; +dojo.provide("dojox.wire.tests.programmatic.CompositeWire"); + +dojo.require("dojox.wire.CompositeWire"); + +tests.register("dojox.wire.tests.programmatic.CompositeWire", [ + + function test_CompositeWire_children(t){ + var source = {a: "A", b: "B"}; + var target = {}; + var children = {x: {property: "a"}, y: {property: "b"}}; + var value = new dojox.wire.CompositeWire({object: source, children: children}).getValue(); + t.assertEqual(source.a, value.x); + t.assertEqual(source.b, value.y); + new dojox.wire.CompositeWire({object: target, children: children}).setValue(value); + t.assertEqual(source.a, target.a); + t.assertEqual(source.b, target.b); + + // with argument + target = {}; + value = new dojox.wire.CompositeWire({children: children}).getValue(source); + t.assertEqual(source.a, value.x); + t.assertEqual(source.b, value.y); + new dojox.wire.CompositeWire({children: children}).setValue(value, target); + t.assertEqual(source.a, target.a); + t.assertEqual(source.b, target.b); + + // by array + target = {}; + children = [{property: "a"}, {property: "b"}]; + value = new dojox.wire.CompositeWire({object: source, children: children}).getValue(); + t.assertEqual(source.a, value[0]); + t.assertEqual(source.b, value[1]); + new dojox.wire.CompositeWire({object: target, children: children}).setValue(value); + t.assertEqual(source.a, target.a); + t.assertEqual(source.b, target.b); + + // by array with argument + target = {}; + value = new dojox.wire.CompositeWire({children: children}).getValue(source); + t.assertEqual(source.a, value[0]); + t.assertEqual(source.b, value[1]); + new dojox.wire.CompositeWire({children: children}).setValue(value, target); + t.assertEqual(source.a, target.a); + t.assertEqual(source.b, target.b); + } + +]); + +} diff --git a/includes/js/dojox/wire/tests/programmatic/ConverterDynamic.js b/includes/js/dojox/wire/tests/programmatic/ConverterDynamic.js new file mode 100644 index 0000000..2665148 --- /dev/null +++ b/includes/js/dojox/wire/tests/programmatic/ConverterDynamic.js @@ -0,0 +1,12 @@ +if(!dojo._hasResource["dojox.wire.tests.programmatic.ConverterDynamic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.tests.programmatic.ConverterDynamic"] = true; +dojo.provide("dojox.wire.tests.programmatic.ConverterDynamic"); + +dojo.declare("dojox.wire.tests.programmatic.ConverterDynamic", null, { + convert: function(v){ + return v + 1; + } +}); + + +} diff --git a/includes/js/dojox/wire/tests/programmatic/DataWire.js b/includes/js/dojox/wire/tests/programmatic/DataWire.js new file mode 100644 index 0000000..b146901 --- /dev/null +++ b/includes/js/dojox/wire/tests/programmatic/DataWire.js @@ -0,0 +1,25 @@ +if(!dojo._hasResource["dojox.wire.tests.programmatic.DataWire"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.tests.programmatic.DataWire"] = true; +dojo.provide("dojox.wire.tests.programmatic.DataWire"); + +dojo.require("dojox.wire.DataWire"); +dojo.require("dojox.data.XmlStore"); + +tests.register("dojox.wire.tests.programmatic.DataWire", [ + + function test_DataWire_attribute(t){ + var store = new dojox.data.XmlStore(); + var item = store.newItem({tagName: "x"}); + new dojox.wire.DataWire({dataStore: store, object: item, attribute: "y"}).setValue("Y"); + var value = new dojox.wire.DataWire({dataStore: store, object: item, attribute: "y"}).getValue(); + t.assertEqual("Y", value); + + // nested attribute + new dojox.wire.DataWire({dataStore: store, object: item, attribute: "y.z"}).setValue("Z"); + value = new dojox.wire.DataWire({dataStore: store, object: item, attribute: "y.z"}).getValue(); + t.assertEqual("Z", value); + } + +]); + +} diff --git a/includes/js/dojox/wire/tests/programmatic/TableAdapter.js b/includes/js/dojox/wire/tests/programmatic/TableAdapter.js new file mode 100644 index 0000000..9e6adc1 --- /dev/null +++ b/includes/js/dojox/wire/tests/programmatic/TableAdapter.js @@ -0,0 +1,24 @@ +if(!dojo._hasResource["dojox.wire.tests.programmatic.TableAdapter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.tests.programmatic.TableAdapter"] = true; +dojo.provide("dojox.wire.tests.programmatic.TableAdapter"); + +dojo.require("dojox.wire.TableAdapter"); + +tests.register("dojox.wire.tests.programmatic.TableAdapter", [ + + function test_TableAdapter_columns(t){ + var source = [ + {a: "A1", b: "B1", c: "C1"}, + {a: "A2", b: "B2", c: "C2"}, + {a: "A3", b: "B3", c: "C3"} + ]; + var columns = {x: {property: "a"}, y: {property: "b"}, z: {property: "c"}}; + var value = new dojox.wire.TableAdapter({object: source, columns: columns}).getValue(); + t.assertEqual(source[0].a, value[0].x); + t.assertEqual(source[1].b, value[1].y); + t.assertEqual(source[2].c, value[2].z); + } + +]); + +} diff --git a/includes/js/dojox/wire/tests/programmatic/TextAdapter.js b/includes/js/dojox/wire/tests/programmatic/TextAdapter.js new file mode 100644 index 0000000..1014b5c --- /dev/null +++ b/includes/js/dojox/wire/tests/programmatic/TextAdapter.js @@ -0,0 +1,25 @@ +if(!dojo._hasResource["dojox.wire.tests.programmatic.TextAdapter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.tests.programmatic.TextAdapter"] = true; +dojo.provide("dojox.wire.tests.programmatic.TextAdapter"); + +dojo.require("dojox.wire.TextAdapter"); + +tests.register("dojox.wire.tests.programmatic.TextAdapter", [ + + function test_TextAdapter_segments(t){ + var source = {a: "a", b: "b", c: "c"}; + var segments = [{property: "a"}, {property: "b"}, {property: "c"}]; + var value = new dojox.wire.TextAdapter({object: source, segments: segments}).getValue(); + t.assertEqual("abc", value); + }, + + function test_TextAdapter_delimiter(t){ + var source = {a: "a", b: "b", c: "c"}; + var segments = [{property: "a"}, {property: "b"}, {property: "c"}]; + var value = new dojox.wire.TextAdapter({object: source, segments: segments, delimiter: "/"}).getValue(); + t.assertEqual("a/b/c", value); + } + +]); + +} diff --git a/includes/js/dojox/wire/tests/programmatic/TreeAdapter.js b/includes/js/dojox/wire/tests/programmatic/TreeAdapter.js new file mode 100644 index 0000000..e1671ed --- /dev/null +++ b/includes/js/dojox/wire/tests/programmatic/TreeAdapter.js @@ -0,0 +1,29 @@ +if(!dojo._hasResource["dojox.wire.tests.programmatic.TreeAdapter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.tests.programmatic.TreeAdapter"] = true; +dojo.provide("dojox.wire.tests.programmatic.TreeAdapter"); + +dojo.require("dojox.wire.TreeAdapter"); + +tests.register("dojox.wire.tests.programmatic.TreeAdapter", [ + + function test_TreeAdapter_nodes(t){ + var source = [ + {a: "A1", b: "B1", c: "C1"}, + {a: "A2", b: "B2", c: "C2"}, + {a: "A3", b: "B3", c: "C3"} + ]; + var nodes = [ + {title: {property: "a"}, children: [ + {node: {property: "b"}}, + {title: {property: "c"}} + ]} + ]; + var value = new dojox.wire.TreeAdapter({object: source, nodes: nodes}).getValue(); + t.assertEqual(source[0].a, value[0].title); + t.assertEqual(source[1].b, value[1].children[0].title); + t.assertEqual(source[2].c, value[2].children[1].title); + } + +]); + +} diff --git a/includes/js/dojox/wire/tests/programmatic/Wire.js b/includes/js/dojox/wire/tests/programmatic/Wire.js new file mode 100644 index 0000000..25a82ec --- /dev/null +++ b/includes/js/dojox/wire/tests/programmatic/Wire.js @@ -0,0 +1,123 @@ +if(!dojo._hasResource["dojox.wire.tests.programmatic.Wire"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.tests.programmatic.Wire"] = true; +dojo.provide("dojox.wire.tests.programmatic.Wire"); +dojo.require("dojox.wire.Wire"); + +//Simple connverter class to try to use. +dojo.declare("dojox.wire.tests.programmatic.Wire.Converter", null, { + convert: function(v){ + return v + 1; + } +}); + +//Simple converter function to try to use. +//To get it in the global namespace, gotta assign it to the +//'window' toplevel object. Otherwise it ends up in the +//dojo NS and can't be found. +if (dojo.isBrowser) { + window["__wireTestConverterFunction"] = function(v){ + return v + 1; + }; +}else{ + var __wireTestConverterFunction = function(v){ + return v + 1; + }; +} + +tests.register("dojox.wire.tests.programmatic.Wire", [ + + function test_Wire_property(t){ + var source = {a: "A", b: {c: "B.C"}}; + var target = {a: "a", b: {c: "b.c"}}; + var value = new dojox.wire.Wire({object: source, property: "a"}).getValue(); + new dojox.wire.Wire({object: target, property: "a"}).setValue(value); + t.assertEqual(source.a, target.a); + + // child property + value = new dojox.wire.Wire({object: source, property: "b.c"}).getValue(); + new dojox.wire.Wire({object: target, property: "b.c"}).setValue(value); + t.assertEqual(source.b.c, target.b.c); + + // new property + target = {}; + value = new dojox.wire.Wire({object: source, property: "a"}).getValue(); + new dojox.wire.Wire({object: target, property: "a"}).setValue(value); + t.assertEqual(source.a, target.a); + + // new parent and child property + target.b = {}; + value = new dojox.wire.Wire({object: source, property: "b.c"}).getValue(); + new dojox.wire.Wire({object: target, property: "b.c"}).setValue(value); + t.assertEqual(source.b.c, target.b.c); + + // new parent and child property + target = {}; + value = new dojox.wire.Wire({object: source, property: "b.c"}).getValue(); + new dojox.wire.Wire({object: target, property: "b.c"}).setValue(value); + t.assertEqual(source.b.c, target.b.c); + + // new array property + source = {a: ["A"]}; + target = {}; + value = new dojox.wire.Wire({object: source, property: "a[0]"}).getValue(); + new dojox.wire.Wire({object: target, property: "a[0]"}).setValue(value); + t.assertEqual(source.a[0], target.a[0]); + + // by getter/setter + source = {getA: function() { return this._a; }, _a: "A"}; + target = {setA: function(a) { this._a = a; }}; + value = new dojox.wire.Wire({object: source, property: "a"}).getValue(); + new dojox.wire.Wire({object: target, property: "a"}).setValue(value); + t.assertEqual(source._a, target._a); + + // by get/setPropertyValue + source = {getPropertyValue: function(p) { return this["_" + p]; }, _a: "A"}; + target = {setPropertyValue: function(p, v) { this["_" + p] = v; }}; + value = new dojox.wire.Wire({object: source, property: "a"}).getValue(); + new dojox.wire.Wire({object: target, property: "a"}).setValue(value); + t.assertEqual(source._a, target._a); + }, + + function test_Wire_type(t){ + var source = {a: "1"}; + var string = new dojox.wire.Wire({object: source, property: "a"}).getValue(); + t.assertEqual("11", string + 1); + var number = new dojox.wire.Wire({object: source, property: "a", type: "number"}).getValue(); + t.assertEqual(2, number + 1); + }, + + function test_Wire_converterObject(t){ + var source = {a: "1"}; + var converter = {convert: function(v) { return v + 1; }}; + var string = new dojox.wire.Wire({object: source, property: "a", converter: converter}).getValue(); + t.assertEqual("11", string); + }, + + function test_Wire_converterFunction(t){ + var source = {a: "1"}; + var converter = {convert: function(v) { return v + 1; }}; + var number = new dojox.wire.Wire({object: source, property: "a", type: "number", converter: converter.convert}).getValue(); + t.assertEqual(2, number); + }, + + function test_Wire_converterObjectByString(t){ + var source = {a: "1"}; + var number = new dojox.wire.Wire({object: source, property: "a", type: "number", converter: "dojox.wire.tests.programmatic.Wire.Converter"}).getValue(); + t.assertEqual(2, number); + }, + + function test_Wire_converterFunctionByString(t){ + var source = {a: "1"}; + var number = new dojox.wire.Wire({object: source, property: "a", type: "number", converter: "__wireTestConverterFunction"}).getValue(); + t.assertEqual(2, number); + }, + + function test_Wire_converterObjectByStringDynamic(t){ + var source = {a: "1"}; + var number = new dojox.wire.Wire({object: source, property: "a", type: "number", converter: "dojox.wire.tests.programmatic.ConverterDynamic"}).getValue(); + t.assertEqual(2, number); + } + +]); + +} diff --git a/includes/js/dojox/wire/tests/programmatic/XmlWire.js b/includes/js/dojox/wire/tests/programmatic/XmlWire.js new file mode 100644 index 0000000..b0772d7 --- /dev/null +++ b/includes/js/dojox/wire/tests/programmatic/XmlWire.js @@ -0,0 +1,32 @@ +if(!dojo._hasResource["dojox.wire.tests.programmatic.XmlWire"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.tests.programmatic.XmlWire"] = true; +dojo.provide("dojox.wire.tests.programmatic.XmlWire"); + +dojo.require("dojox.wire.XmlWire"); + +tests.register("dojox.wire.tests.programmatic.XmlWire", [ + + function test_XmlWire_path(t){ + var object = {}; + var wire = dojox.wire.create({object: object, property: "element"}); + new dojox.wire.XmlWire({object: wire, path: "/x/y/text()"}).setValue("Y"); + var value = new dojox.wire.XmlWire({object: object, property: "element", path: "y/text()"}).getValue(); + t.assertEqual("Y", value); + + // attribute + new dojox.wire.XmlWire({object: object, property: "element", path: "y/@z"}).setValue("Z"); + value = new dojox.wire.XmlWire({object: wire, path: "/x/y/@z"}).getValue(); + t.assertEqual("Z", value); + + // with index + var document = object.element.ownerDocument; + var element = document.createElement("y"); + element.appendChild(document.createTextNode("Y2")); + object.element.appendChild(element); + value = new dojox.wire.XmlWire({object: object.element, path: "y[2]/text()"}).getValue(); + t.assertEqual("Y2", value); + } + +]); + +} diff --git a/includes/js/dojox/wire/tests/programmatic/_base.js b/includes/js/dojox/wire/tests/programmatic/_base.js new file mode 100644 index 0000000..00f9abe --- /dev/null +++ b/includes/js/dojox/wire/tests/programmatic/_base.js @@ -0,0 +1,111 @@ +if(!dojo._hasResource["dojox.wire.tests.programmatic._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.tests.programmatic._base"] = true; +dojo.provide("dojox.wire.tests.programmatic._base"); + +dojo.require("dojox.wire._base"); + +tests.register("dojox.wire.tests.programmatic._base", [ + + function test_create(t){ + var wire = dojox.wire.create({}); + t.assertTrue(wire instanceof dojox.wire.Wire); + + wire = dojox.wire.create({property: "a"}); + t.assertTrue(wire instanceof dojox.wire.Wire); + + wire = dojox.wire.create({attribute: "a"}); + t.assertTrue(wire instanceof dojox.wire.DataWire); + + wire = dojox.wire.create({path: "a"}); + t.assertTrue(wire instanceof dojox.wire.XmlWire); + + wire = dojox.wire.create({children: "a"}); + t.assertTrue(wire instanceof dojox.wire.CompositeWire); + + wire = dojox.wire.create({columns: "a"}); + t.assertTrue(wire instanceof dojox.wire.TableAdapter); + + wire = dojox.wire.create({nodes: "a"}); + t.assertTrue(wire instanceof dojox.wire.TreeAdapter); + + wire = dojox.wire.create({segments: "a"}); + t.assertTrue(wire instanceof dojox.wire.TextAdapter); + + wire = dojox.wire.create({wireClass: "dojox.wire.DataWire"}); + t.assertTrue(wire instanceof dojox.wire.DataWire); + }, + + function test_transfer(t){ + var source = {a: "A"}; + var target = {}; + dojox.wire.transfer( + {object: source, property: "a"}, + {object: target, property: "a"}); + t.assertEqual(source.a, target.a); + }, + + function test_connect(t){ + var trigger = {transfer: function() {}, transferArgument: function() {}}; + var source = {a: "A"}; + var target = {}; + dojox.wire.connect({scope: trigger, event: "transfer"}, + {object: source, property: "a"}, + {object: target, property: "a"}); + trigger.transfer(); + t.assertEqual(source.a, target.a); + + // with argument + target = {}; + dojox.wire.connect({scope: trigger, event: "transferArgument"}, + {property: "[0].a"}, + {object: target, property: "a"}); + trigger.transferArgument(source); + t.assertEqual(source.a, target.a); + + // by topic + target = {}; + dojox.wire.connect({topic: "transfer"}, + {object: source, property: "a"}, + {object: target, property: "a"}); + dojo.publish("transfer"); + t.assertEqual(source.a, target.a); + + // by topic with argument + target = {}; + dojox.wire.connect({topic: "transferArgument"}, + {property: "[0].a"}, + {object: target, property: "a"}); + dojo.publish("transferArgument", [source]); + t.assertEqual(source.a, target.a); + }, + + function test_disconnect(t){ + var trigger = {transferDisconnect: function() {}}; + var source = {a: "A"}; + var target = {}; + var connection = dojox.wire.connect({scope: trigger, event: "transferDisconnect"}, + {object: source, property: "a"}, + {object: target, property: "a"}); + trigger.transferDisconnect(); + t.assertEqual(source.a, target.a); + delete target.a; + dojox.wire.disconnect(connection); + trigger.transferDisconnect(); + t.assertEqual(undefined, target.a); + + // by topic + target = {}; + connection = dojox.wire.connect({topic: "transferDisconnect"}, + {object: source, property: "a"}, + {object: target, property: "a"}); + dojo.publish("transferDisconnect"); + t.assertEqual(source.a, target.a); + delete target.a; + dojox.wire.disconnect(connection); + dojo.publish("transferDisconnect"); + t.assertEqual(undefined, target.a); + } + +]); + +} diff --git a/includes/js/dojox/wire/tests/runTests.html b/includes/js/dojox/wire/tests/runTests.html new file mode 100644 index 0000000..f4a51de --- /dev/null +++ b/includes/js/dojox/wire/tests/runTests.html @@ -0,0 +1,9 @@ + + + + Dojox.wire Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/wire/tests/wire.js b/includes/js/dojox/wire/tests/wire.js new file mode 100644 index 0000000..e4e2a21 --- /dev/null +++ b/includes/js/dojox/wire/tests/wire.js @@ -0,0 +1,18 @@ +if(!dojo._hasResource["dojox.wire.tests.wire"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.tests.wire"] = true; +dojo.provide("dojox.wire.tests.wire"); + +try{ + dojo.require("dojox.wire.tests.programmatic._base"); + dojo.require("dojox.wire.tests.programmatic.Wire"); + dojo.requireIf(dojo.isBrowser, "dojox.wire.tests.programmatic.DataWire"); + dojo.requireIf(dojo.isBrowser, "dojox.wire.tests.programmatic.XmlWire"); + dojo.require("dojox.wire.tests.programmatic.CompositeWire"); + dojo.require("dojox.wire.tests.programmatic.TableAdapter"); + dojo.require("dojox.wire.tests.programmatic.TreeAdapter"); + dojo.require("dojox.wire.tests.programmatic.TextAdapter"); +}catch(e){ + doh.debug(e); +} + +} diff --git a/includes/js/dojox/wire/tests/wireml.js b/includes/js/dojox/wire/tests/wireml.js new file mode 100644 index 0000000..db47056 --- /dev/null +++ b/includes/js/dojox/wire/tests/wireml.js @@ -0,0 +1,18 @@ +if(!dojo._hasResource["dojox.wire.tests.wireml"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.tests.wireml"] = true; +dojo.provide("dojox.wire.tests.wireml"); + +try{ + if(dojo.isBrowser){ + doh.registerUrl("dojox.wire.tests.ml.Action", dojo.moduleUrl("dojox", "wire/tests/markup/Action.html")); + doh.registerUrl("dojox.wire.tests.ml.Transfer", dojo.moduleUrl("dojox", "wire/tests/markup/Transfer.html")); + doh.registerUrl("dojox.wire.tests.ml.Invocation", dojo.moduleUrl("dojox", "wire/tests/markup/Invocation.html")); + doh.registerUrl("dojox.wire.tests.ml.Data", dojo.moduleUrl("dojox", "wire/tests/markup/Data.html")); + doh.registerUrl("dojox.wire.tests.ml.DataStore", dojo.moduleUrl("dojox", "wire/tests/markup/DataStore.html")); + doh.registerUrl("dojox.wire.tests.ml.Service", dojo.moduleUrl("dojox", "wire/tests/markup/Service.html")); + } +}catch(e){ + doh.debug(e); +} + +} diff --git a/includes/js/dojox/xml/DomParser.js b/includes/js/dojox/xml/DomParser.js new file mode 100644 index 0000000..f61e653 --- /dev/null +++ b/includes/js/dojox/xml/DomParser.js @@ -0,0 +1,379 @@ +if(!dojo._hasResource["dojox.xml.DomParser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.xml.DomParser"] = true; +dojo.provide("dojox.xml.DomParser"); + +dojox.xml.DomParser=new (function(){ + /********************************************************** + * The DomParser is a close-to (but not entirely) + * conforming XML parser based on regular + * expressions. It will take any XML fragment + * and return a lightweight JS structure that is + * similar to (but not exactly) the DOM specification. + * + * Getter and setter methods are NOT available; the goal + * was to keep the resulting object model entirely JS-like. + * + * All node types but document fragments are supported; + * all nodes support getElementsByTagName and + * getElementsByTagNameNS (with short names byName and + * byNameNS). The document node supports getElementById + * (byId), and all nodes support a supplimental + * childrenByName/childrenByNameNS method as well. + * + * The object model is intended to be a READONLY format; + * mutation events are NOT supported, and though you + * can change properties on a node-by-node basis, certain + * operations are not supported (such as changing the ID + * of an element). + **********************************************************/ + + // internal use only. + var nodeTypes={ ELEMENT:1, ATTRIBUTE:2, TEXT:3, CDATA_SECTION:4, PROCESSING_INSTRUCTION:7, COMMENT:8, DOCUMENT:9 }; + + // compile the regular expressions once. + var reTags=/<([^>\/\s+]*)([^>]*)>([^<]*)/g; + var reAttr=/([^=]*)="([^"]*)"/g; + var reEntity=//g; + var reCData=//g; + var reComments=//g; + var trim=/^\s+|\s+$/g; + var normalize=/\s+/g; + var egt=/\>/g; + var elt=/\</g; + var equot=/\"/g; + var eapos=/\'/g; + var eamp=/\&/g; + var dNs="_def_"; + + // create a root node. + function _doc(){ + return new (function(){ + var all={}; + this.nodeType=nodeTypes.DOCUMENT; + this.nodeName="#document"; + this.namespaces={}; + this._nsPaths={}; + this.childNodes=[]; + this.documentElement=null; + + // any element with an ID attribute will be added to the internal hashtable. + this._add=function(obj){ + if(typeof(obj.id)!="undefined"){ all[obj.id]=obj; } + }; + this._remove=function(id){ + if(all[id]){ delete all[id]; } + }; + + this.byId=this.getElementById=function(id){ return keys[id]; }; + this.byName=this.getElementsByTagName=byName; + this.byNameNS=this.getElementsByTagNameNS=byNameNS; + this.childrenByName=childrenByName; + })(); + } + + // functions attached to element nodes + function byName(name){ + // return all descendants with name. Fully qualified (i.e. svg:svg) + function __(node, name, arr){ + dojo.forEach(node.childNodes, function(c){ + if(c.nodeType==nodeTypes.ELEMENT){ + if(name=="*"){ arr.push(c); } + else if(c.nodeName==name){ arr.push(c); } + __(c, name, arr); + } + }); + } + var a=[]; + __(this, name, a); + return a; + } + function byNameNS(name, ns){ + // return all descendants with name by namespace. If no namespace passed, the default is used. + function __(node, name, ns, arr){ + dojo.forEach(node.childNodes, function(c){ + if(c.nodeType==nodeTypes.ELEMENT){ + if(name=="*"&&c.ownerDocument._nsPaths[ns]==c.namespace){ arr.push(c); } + else if(c.localName==name&&c.ownerDocument._nsPaths[ns]==c.namespace){ arr.push(c); } + __(c, name, ns, arr); + } + }); + } + if(!ns){ ns=dNs; } + var a=[]; + __(this, name, ns, a); + return a; + } + // Only child nodes with name. + function childrenByName(name){ + var a=[]; + dojo.forEach(this.childNodes, function(c){ + if(c.nodeType==nodeTypes.ELEMENT){ + if(name=="*"){ a.push(c); } + else if(c.nodeName==name){ a.push(c); } + } + }); + return a; + } + + function _createTextNode(v){ + return { + nodeType:nodeTypes.TEXT, + nodeName:"#text", + nodeValue:v.replace(normalize," ").replace(egt,">").replace(elt,"<").replace(eapos,"'").replace(equot,'"').replace(eamp,"&") + }; + } + + // attribute functions + function getAttr(name){ + for(var i=0; i0){ + return p.childNodes[i-1]; + } + } + } + return null; + } + function next(){ + var p=this.parentNode; + if(p){ + for(var i=0;i0){ + var entity, eRe=[]; + if(reEntity.test(str)){ + reEntity.lastIndex=0; + // match entities + while((entity=reEntity.exec(str))!=null){ + eRe.push({ + entity:"&"+entity[1].replace(trim,"")+";", + expression:entity[2] + }); + } + // replace instances in the document. + for(var i=0; i0) + obj.appendChild(_createTextNode(text)); + }else + + // open tags. + if(res[1].length>0){ + // figure out the type of node. + if(res[1].charAt(0)=="?"){ + // processing instruction + var name=res[1].substr(1); + var target=res[2].substr(0,res[2].length-2); + obj.childNodes.push({ + nodeType:nodeTypes.PROCESSING_INSTRUCTION, + nodeName:name, + nodeValue:target + }); + } + else if(res[1].charAt(0)=="!"){ + // CDATA; skip over any declaration elements. + if(res[1].indexOf("![CDATA[")==0){ + var val=parseInt(res[1].replace("![CDATA[","").replace("]]","")); + obj.childNodes.push({ + nodeType:nodeTypes.CDATA_SECTION, + nodeName:"#cdata-section", + nodeValue:cdSections[val] + }); + } + // Comments. + else if(res[1].substr(0,3)=="!--"){ + var val=parseInt(res[1].replace("!--","").replace("--","")); + obj.childNodes.push({ + nodeType:nodeTypes.COMMENT, + nodeName:"#comment", + nodeValue:comments[val] + }); + } + } + else { + // Elements (with attribute and text) + var name=res[1].replace(trim,""); + var o={ + nodeType:nodeTypes.ELEMENT, + nodeName:name, + localName:name, + namespace:dNs, + ownerDocument:root, + attributes:[], + parentNode:null, + childNodes:[] + }; + + // check to see if it's namespaced. + if(name.indexOf(":")>-1){ + var t=name.split(":"); + o.namespace=t[0]; + o.localName=t[1]; + } + + // set the function references. + o.byName=o.getElementsByTagName=byName; + o.byNameNS=o.getElementsByTagNameNS=byNameNS; + o.childrenByName=childrenByName; + o.getAttribute=getAttr; + o.getAttributeNS=getAttrNS; + o.setAttribute=setAttr; + o.setAttributeNS=setAttrNS; + o.previous=o.previousSibling=prev; + o.next=o.nextSibling=next; + + // parse the attribute string. + var attr; + while((attr=reAttr.exec(res[2]))!=null){ + if(attr.length>0){ + var name=attr[1].replace(trim,""); + var val=attr[2].replace(normalize," ") + .replace(egt,">") + .replace(elt,"<") + .replace(eapos,"'") + .replace(equot,'"') + .replace(eamp,"&"); + if(name.indexOf("xmlns")==0){ + if(name.indexOf(":")>0){ + var ns=name.split(":"); + root.namespaces[ns[1]]=val; + root._nsPaths[val]=ns[1]; + } else { + root.namespaces[dNs]=val; + root._nsPaths[val]=dNs; + } + } else { + var ln=name; + var ns=dNs; + if(name.indexOf(":")>0){ + var t=name.split(":"); + ln=t[1]; + ns=t[0]; + } + o.attributes.push({ + nodeType:nodeTypes.ATTRIBUTE, + nodeName:name, + localName:ln, + namespace:ns, + nodeValue:val + }); + + // only add id as a property. + if(ln=="id"){ o.id=val; } + } + } + } + root._add(o); + + if(obj){ + obj.childNodes.push(o); + o.parentNode=obj; + // if it's not a self-closing node. + if(res[2].charAt(res[2].length-1)!="/"){ + obj=o; + } + } + var text=res[3]; + if(text.length>0){ + obj.childNodes.push(_createTextNode(text)); + } + } + } + } + + // set the document element + for(var i=0; i