aboutsummaryrefslogtreecommitdiff
path: root/includes/js/dojo
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dojo')
-rw-r--r--includes/js/dojo/AdapterRegistry.js99
-rw-r--r--includes/js/dojo/DeferredList.js88
-rw-r--r--includes/js/dojo/LICENSE195
-rw-r--r--includes/js/dojo/NodeList-fx.js137
-rw-r--r--includes/js/dojo/OpenAjax.js194
-rw-r--r--includes/js/dojo/_base.js13
-rw-r--r--includes/js/dojo/_base/Color.js156
-rw-r--r--includes/js/dojo/_base/Deferred.js408
-rw-r--r--includes/js/dojo/_base/NodeList.js532
-rw-r--r--includes/js/dojo/_base/_loader/bootstrap.js436
-rw-r--r--includes/js/dojo/_base/_loader/hostenv_browser.js379
-rw-r--r--includes/js/dojo/_base/_loader/hostenv_rhino.js238
-rw-r--r--includes/js/dojo/_base/_loader/hostenv_spidermonkey.js80
-rw-r--r--includes/js/dojo/_base/_loader/loader.js690
-rw-r--r--includes/js/dojo/_base/_loader/loader_debug.js61
-rw-r--r--includes/js/dojo/_base/_loader/loader_xd.js631
-rw-r--r--includes/js/dojo/_base/array.js182
-rw-r--r--includes/js/dojo/_base/browser.js21
-rw-r--r--includes/js/dojo/_base/connect.js285
-rw-r--r--includes/js/dojo/_base/declare.js178
-rw-r--r--includes/js/dojo/_base/event.js529
-rw-r--r--includes/js/dojo/_base/fx.js584
-rw-r--r--includes/js/dojo/_base/html.js1227
-rw-r--r--includes/js/dojo/_base/json.js137
-rw-r--r--includes/js/dojo/_base/lang.js257
-rw-r--r--includes/js/dojo/_base/query.js1191
-rw-r--r--includes/js/dojo/_base/window.js145
-rw-r--r--includes/js/dojo/_base/xhr.js730
-rw-r--r--includes/js/dojo/_firebug/LICENSE37
-rw-r--r--includes/js/dojo/_firebug/errorIcon.pngbin0 -> 457 bytes
-rw-r--r--includes/js/dojo/_firebug/firebug.css176
-rw-r--r--includes/js/dojo/_firebug/firebug.css.commented.css222
-rw-r--r--includes/js/dojo/_firebug/firebug.js1103
-rw-r--r--includes/js/dojo/_firebug/infoIcon.pngbin0 -> 524 bytes
-rw-r--r--includes/js/dojo/_firebug/warningIcon.pngbin0 -> 516 bytes
-rw-r--r--includes/js/dojo/back.js394
-rw-r--r--includes/js/dojo/behavior.js185
-rw-r--r--includes/js/dojo/build.txt126
-rw-r--r--includes/js/dojo/cldr/LICENSE29
-rw-r--r--includes/js/dojo/cldr/README18
-rw-r--r--includes/js/dojo/cldr/monetary.js27
-rw-r--r--includes/js/dojo/cldr/nls/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/de-de/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/de/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/de/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/de/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/en-au/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/en-au/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/en-au/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/en-ca/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/en-ca/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/en-gb/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/en-gb/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/en-us/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/en-us/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/en/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/en/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/en/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/es-es/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/es-es/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/es/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/es/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/es/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/fr/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/fr/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/fr/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/it-it/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/it/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/it/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/it/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/ja-jp/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/ja/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/ja/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/ja/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/ko-kr/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/ko-kr/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/ko/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/ko/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/ko/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/pt-br/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/pt/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/pt/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/pt/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/zh-cn/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/zh-cn/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/zh-tw/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/zh-tw/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/zh-tw/number.js1
-rw-r--r--includes/js/dojo/cldr/nls/zh/currency.js1
-rw-r--r--includes/js/dojo/cldr/nls/zh/gregorian.js1
-rw-r--r--includes/js/dojo/cldr/nls/zh/number.js1
-rw-r--r--includes/js/dojo/cldr/supplemental.js74
-rw-r--r--includes/js/dojo/colors.js225
-rw-r--r--includes/js/dojo/cookie.js95
-rw-r--r--includes/js/dojo/currency.js97
-rw-r--r--includes/js/dojo/data/ItemFileReadStore.js765
-rw-r--r--includes/js/dojo/data/ItemFileWriteStore.js804
-rw-r--r--includes/js/dojo/data/api/Identity.js107
-rw-r--r--includes/js/dojo/data/api/Notification.js119
-rw-r--r--includes/js/dojo/data/api/Read.js506
-rw-r--r--includes/js/dojo/data/api/Request.js32
-rw-r--r--includes/js/dojo/data/api/Write.js226
-rw-r--r--includes/js/dojo/data/util/filter.js69
-rw-r--r--includes/js/dojo/data/util/simpleFetch.js90
-rw-r--r--includes/js/dojo/data/util/sorter.js81
-rw-r--r--includes/js/dojo/date.js343
-rw-r--r--includes/js/dojo/date/locale.js656
-rw-r--r--includes/js/dojo/date/stamp.js141
-rw-r--r--includes/js/dojo/dnd/Avatar.js82
-rw-r--r--includes/js/dojo/dnd/Container.js311
-rw-r--r--includes/js/dojo/dnd/Manager.js180
-rw-r--r--includes/js/dojo/dnd/Moveable.js130
-rw-r--r--includes/js/dojo/dnd/Mover.js84
-rw-r--r--includes/js/dojo/dnd/Selector.js244
-rw-r--r--includes/js/dojo/dnd/Source.js393
-rw-r--r--includes/js/dojo/dnd/TimedMoveable.js66
-rw-r--r--includes/js/dojo/dnd/autoscroll.js103
-rw-r--r--includes/js/dojo/dnd/common.js35
-rw-r--r--includes/js/dojo/dnd/move.js202
-rw-r--r--includes/js/dojo/dojo.js20
-rw-r--r--includes/js/dojo/dojo.js.uncompressed.js8165
-rw-r--r--includes/js/dojo/fx.js415
-rw-r--r--includes/js/dojo/i18n.js249
-rw-r--r--includes/js/dojo/io/iframe.js358
-rw-r--r--includes/js/dojo/io/script.js211
-rw-r--r--includes/js/dojo/jaxer.js15
-rw-r--r--includes/js/dojo/nls/ar/colors.js1
-rw-r--r--includes/js/dojo/nls/colors.js1
-rw-r--r--includes/js/dojo/nls/cs/colors.js1
-rw-r--r--includes/js/dojo/nls/da/colors.js1
-rw-r--r--includes/js/dojo/nls/de/colors.js1
-rw-r--r--includes/js/dojo/nls/el/colors.js1
-rw-r--r--includes/js/dojo/nls/es/colors.js1
-rw-r--r--includes/js/dojo/nls/fi/colors.js1
-rw-r--r--includes/js/dojo/nls/fr/colors.js1
-rw-r--r--includes/js/dojo/nls/he/colors.js1
-rw-r--r--includes/js/dojo/nls/hu/colors.js1
-rw-r--r--includes/js/dojo/nls/it/colors.js1
-rw-r--r--includes/js/dojo/nls/ja/colors.js1
-rw-r--r--includes/js/dojo/nls/ko/colors.js1
-rw-r--r--includes/js/dojo/nls/nb/colors.js1
-rw-r--r--includes/js/dojo/nls/nl/colors.js1
-rw-r--r--includes/js/dojo/nls/pl/colors.js1
-rw-r--r--includes/js/dojo/nls/pt-pt/colors.js1
-rw-r--r--includes/js/dojo/nls/pt/colors.js1
-rw-r--r--includes/js/dojo/nls/ru/colors.js1
-rw-r--r--includes/js/dojo/nls/sv/colors.js1
-rw-r--r--includes/js/dojo/nls/tr/colors.js1
-rw-r--r--includes/js/dojo/nls/zh-tw/colors.js1
-rw-r--r--includes/js/dojo/nls/zh/colors.js1
-rw-r--r--includes/js/dojo/number.js551
-rw-r--r--includes/js/dojo/parser.js277
-rw-r--r--includes/js/dojo/regexp.js69
-rw-r--r--includes/js/dojo/resources/LICENSE30
-rw-r--r--includes/js/dojo/resources/_modules.js36
-rw-r--r--includes/js/dojo/resources/blank.gifbin0 -> 43 bytes
-rw-r--r--includes/js/dojo/resources/blank.html1
-rw-r--r--includes/js/dojo/resources/dnd.css9
-rw-r--r--includes/js/dojo/resources/dnd.css.commented.css9
-rw-r--r--includes/js/dojo/resources/dojo.css100
-rw-r--r--includes/js/dojo/resources/dojo.css.commented.css198
-rw-r--r--includes/js/dojo/resources/iframe_history.html79
-rw-r--r--includes/js/dojo/resources/images/dndCopy.pngbin0 -> 814 bytes
-rw-r--r--includes/js/dojo/resources/images/dndMove.pngbin0 -> 785 bytes
-rw-r--r--includes/js/dojo/resources/images/dndNoCopy.pngbin0 -> 756 bytes
-rw-r--r--includes/js/dojo/resources/images/dndNoMove.pngbin0 -> 750 bytes
-rw-r--r--includes/js/dojo/rpc/JsonService.js83
-rw-r--r--includes/js/dojo/rpc/JsonpService.js65
-rw-r--r--includes/js/dojo/rpc/RpcService.js172
-rw-r--r--includes/js/dojo/string.js84
-rw-r--r--includes/js/dojo/tests.js12
-rw-r--r--includes/js/dojo/tests/AdapterRegistry.js75
-rw-r--r--includes/js/dojo/tests/DeferredList.js206
-rw-r--r--includes/js/dojo/tests/NodeList-fx.html150
-rw-r--r--includes/js/dojo/tests/TODO11
-rw-r--r--includes/js/dojo/tests/_base.js136
-rw-r--r--includes/js/dojo/tests/_base/Color.js32
-rw-r--r--includes/js/dojo/tests/_base/Deferred.js76
-rw-r--r--includes/js/dojo/tests/_base/NodeList.html370
-rw-r--r--includes/js/dojo/tests/_base/_loader/addLoadEvents.html37
-rw-r--r--includes/js/dojo/tests/_base/_loader/afterOnLoad.html56
-rw-r--r--includes/js/dojo/tests/_base/_loader/bootstrap.js86
-rw-r--r--includes/js/dojo/tests/_base/_loader/getText.txt1
-rw-r--r--includes/js/dojo/tests/_base/_loader/hostenv_browser.js15
-rw-r--r--includes/js/dojo/tests/_base/_loader/hostenv_rhino.js17
-rw-r--r--includes/js/dojo/tests/_base/_loader/hostenv_spidermonkey.js15
-rw-r--r--includes/js/dojo/tests/_base/_loader/loader.js52
-rw-r--r--includes/js/dojo/tests/_base/_loader/scope/scope04.html80
-rw-r--r--includes/js/dojo/tests/_base/_loader/scope/scopeContained.html71
-rw-r--r--includes/js/dojo/tests/_base/_loader/scope/scopeContainedXd.html84
-rw-r--r--includes/js/dojo/tests/_base/_loader/scope/scopeDjConfig.html64
-rw-r--r--includes/js/dojo/tests/_base/_loader/scope/scopeSingle.html62
-rw-r--r--includes/js/dojo/tests/_base/_loader/scope/scopeSingleDaac.html63
-rw-r--r--includes/js/dojo/tests/_base/array.js301
-rw-r--r--includes/js/dojo/tests/_base/connect.js225
-rw-r--r--includes/js/dojo/tests/_base/declare.js197
-rw-r--r--includes/js/dojo/tests/_base/fx.html342
-rw-r--r--includes/js/dojo/tests/_base/fx.js8
-rw-r--r--includes/js/dojo/tests/_base/fx_delay.html22
-rw-r--r--includes/js/dojo/tests/_base/html.html556
-rw-r--r--includes/js/dojo/tests/_base/html.js12
-rw-r--r--includes/js/dojo/tests/_base/html_box.html207
-rw-r--r--includes/js/dojo/tests/_base/html_box_quirks.html205
-rw-r--r--includes/js/dojo/tests/_base/html_quirks.html322
-rw-r--r--includes/js/dojo/tests/_base/html_rtl.html110
-rw-r--r--includes/js/dojo/tests/_base/json.js37
-rw-r--r--includes/js/dojo/tests/_base/lang.js180
-rw-r--r--includes/js/dojo/tests/_base/query.html154
-rw-r--r--includes/js/dojo/tests/_base/query.js9
-rw-r--r--includes/js/dojo/tests/_base/timeout.php7
-rw-r--r--includes/js/dojo/tests/_base/xhr.html404
-rw-r--r--includes/js/dojo/tests/_base/xhr.js8
-rw-r--r--includes/js/dojo/tests/_base/xhrDummyMethod.php7
-rw-r--r--includes/js/dojo/tests/back-hash.js33
-rw-r--r--includes/js/dojo/tests/back.html107
-rw-r--r--includes/js/dojo/tests/back.js8
-rw-r--r--includes/js/dojo/tests/behavior.html106
-rw-r--r--includes/js/dojo/tests/behavior.js8
-rw-r--r--includes/js/dojo/tests/cldr.js19
-rw-r--r--includes/js/dojo/tests/colors.js48
-rw-r--r--includes/js/dojo/tests/cookie.html84
-rw-r--r--includes/js/dojo/tests/cookie.js8
-rw-r--r--includes/js/dojo/tests/currency.js48
-rw-r--r--includes/js/dojo/tests/data.js12
-rw-r--r--includes/js/dojo/tests/data/ItemFileReadStore.js10
-rw-r--r--includes/js/dojo/tests/data/ItemFileWriteStore.js1402
-rw-r--r--includes/js/dojo/tests/data/countries.json11
-rw-r--r--includes/js/dojo/tests/data/countries_commentFiltered.json12
-rw-r--r--includes/js/dojo/tests/data/countries_idcollision.json10
-rw-r--r--includes/js/dojo/tests/data/countries_references.json44
-rw-r--r--includes/js/dojo/tests/data/countries_withBoolean.json11
-rw-r--r--includes/js/dojo/tests/data/countries_withDates.json21
-rw-r--r--includes/js/dojo/tests/data/countries_withNull.json10
-rw-r--r--includes/js/dojo/tests/data/countries_withoutid.json10
-rw-r--r--includes/js/dojo/tests/data/data_multitype.json18
-rw-r--r--includes/js/dojo/tests/data/geography_hierarchy_large.json44
-rw-r--r--includes/js/dojo/tests/data/geography_hierarchy_small.json19
-rw-r--r--includes/js/dojo/tests/data/readOnlyItemFileTestTemplates.js2260
-rw-r--r--includes/js/dojo/tests/data/reference_integrity.json27
-rw-r--r--includes/js/dojo/tests/data/runTests.html9
-rw-r--r--includes/js/dojo/tests/data/utils.js203
-rw-r--r--includes/js/dojo/tests/date.js716
-rw-r--r--includes/js/dojo/tests/date/locale.js398
-rw-r--r--includes/js/dojo/tests/date/stamp.js94
-rw-r--r--includes/js/dojo/tests/dnd/dndDefault.css52
-rw-r--r--includes/js/dojo/tests/dnd/dndDefault.css.commented.css69
-rw-r--r--includes/js/dojo/tests/dnd/flickr_viewer.html168
-rw-r--r--includes/js/dojo/tests/dnd/test_box_constraints.html61
-rw-r--r--includes/js/dojo/tests/dnd/test_container.html74
-rw-r--r--includes/js/dojo/tests/dnd/test_container_markup.html67
-rw-r--r--includes/js/dojo/tests/dnd/test_custom_constraints.html51
-rw-r--r--includes/js/dojo/tests/dnd/test_dnd.html130
-rw-r--r--includes/js/dojo/tests/dnd/test_dnd_handles.html65
-rw-r--r--includes/js/dojo/tests/dnd/test_form.html103
-rw-r--r--includes/js/dojo/tests/dnd/test_moveable.html106
-rw-r--r--includes/js/dojo/tests/dnd/test_moveable_markup.html83
-rw-r--r--includes/js/dojo/tests/dnd/test_params.html61
-rw-r--r--includes/js/dojo/tests/dnd/test_parent_constraints.html53
-rw-r--r--includes/js/dojo/tests/dnd/test_parent_constraints_margins.html51
-rw-r--r--includes/js/dojo/tests/dnd/test_selector.html80
-rw-r--r--includes/js/dojo/tests/dnd/test_selector_markup.html71
-rw-r--r--includes/js/dojo/tests/dnd/test_timed_moveable.html112
-rw-r--r--includes/js/dojo/tests/fx.html310
-rw-r--r--includes/js/dojo/tests/fx.js9
-rw-r--r--includes/js/dojo/tests/i18n.js88
-rw-r--r--includes/js/dojo/tests/io/iframe.html124
-rw-r--r--includes/js/dojo/tests/io/iframe.js8
-rw-r--r--includes/js/dojo/tests/io/iframeResponse.html8
-rw-r--r--includes/js/dojo/tests/io/iframeResponse.js.html7
-rw-r--r--includes/js/dojo/tests/io/iframeResponse.json.html7
-rw-r--r--includes/js/dojo/tests/io/iframeResponse.text.html7
-rw-r--r--includes/js/dojo/tests/io/iframeUploadTest.html50
-rw-r--r--includes/js/dojo/tests/io/script.html101
-rw-r--r--includes/js/dojo/tests/io/script.js8
-rw-r--r--includes/js/dojo/tests/io/scriptJsonp.js57
-rw-r--r--includes/js/dojo/tests/io/scriptSimple.js5
-rw-r--r--includes/js/dojo/tests/io/scriptTimeout.html67
-rw-r--r--includes/js/dojo/tests/io/upload.cgi60
-rw-r--r--includes/js/dojo/tests/manualTests.html12
-rw-r--r--includes/js/dojo/tests/manualTests.js45
-rw-r--r--includes/js/dojo/tests/module.js29
-rw-r--r--includes/js/dojo/tests/nls/ar/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/cs/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/de/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/el/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/en-au/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/en-us-hawaii/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/en-us-new_york-brooklyn/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/en-us-texas/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/es/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/fa/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/fr/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/he/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/hi/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/it/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/ja/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/ko/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/pl/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/pt/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/ru/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/sw/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/th/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/tr/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/yi/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/zh-cn/salutations.js1
-rw-r--r--includes/js/dojo/tests/nls/zh-tw/salutations.js1
-rw-r--r--includes/js/dojo/tests/number.js966
-rw-r--r--includes/js/dojo/tests/parser.html241
-rw-r--r--includes/js/dojo/tests/parser.js8
-rw-r--r--includes/js/dojo/tests/resources/ApplicationState.js28
-rw-r--r--includes/js/dojo/tests/resources/JSON.php724
-rw-r--r--includes/js/dojo/tests/resources/testClass.php20
-rw-r--r--includes/js/dojo/tests/resources/testClass.smd40
-rw-r--r--includes/js/dojo/tests/resources/test_JsonRPCMediator.php43
-rw-r--r--includes/js/dojo/tests/resources/test_css.html100
-rw-r--r--includes/js/dojo/tests/resources/yahoo_smd_v1.smd268
-rw-r--r--includes/js/dojo/tests/rpc.js151
-rw-r--r--includes/js/dojo/tests/runTests.html9
-rw-r--r--includes/js/dojo/tests/string.js31
-rw-r--r--includes/js/dojo/tests/test_FirebugLite.html100
-rw-r--r--includes/js/dojo/tests/test_FirebugLitePopup.html101
-rw-r--r--includes/js/dojo/tests/test_fx.html107
325 files changed, 45968 insertions, 0 deletions
diff --git a/includes/js/dojo/AdapterRegistry.js b/includes/js/dojo/AdapterRegistry.js
new file mode 100644
index 0000000..34bc8be
--- /dev/null
+++ b/includes/js/dojo/AdapterRegistry.js
@@ -0,0 +1,99 @@
+if(!dojo._hasResource["dojo.AdapterRegistry"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.AdapterRegistry"] = true;
+dojo.provide("dojo.AdapterRegistry");
+
+dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){
+ // summary:
+ // A registry to make contextual calling/searching easier.
+ // description:
+ // Objects of this class keep list of arrays in the form [name, check,
+ // wrap, directReturn] that are used to determine what the contextual
+ // result of a set of checked arguments is. All check/wrap functions
+ // in this registry should be of the same arity.
+ // example:
+ // | // create a new registry
+ // | var reg = new dojo.AdapterRegistry();
+ // | reg.register("handleString",
+ // | dojo.isString,
+ // | function(str){
+ // | // do something with the string here
+ // | }
+ // | );
+ // | reg.register("handleArr",
+ // | dojo.isArray,
+ // | function(arr){
+ // | // do something with the array here
+ // | }
+ // | );
+ // |
+ // | // now we can pass reg.match() *either* an array or a string and
+ // | // the value we pass will get handled by the right function
+ // | reg.match("someValue"); // will call the first function
+ // | reg.match(["someValue"]); // will call the second
+
+ this.pairs = [];
+ this.returnWrappers = returnWrappers || false; // Boolean
+}
+
+dojo.extend(dojo.AdapterRegistry, {
+ register: function(/*String*/ name, /*Function*/ check, /*Function*/ wrap, /*Boolean?*/ directReturn, /*Boolean?*/ override){
+ // summary:
+ // register a check function to determine if the wrap function or
+ // object gets selected
+ // name:
+ // a way to identify this matcher.
+ // check:
+ // a function that arguments are passed to from the adapter's
+ // match() function. The check function should return true if the
+ // given arguments are appropriate for the wrap function.
+ // directReturn:
+ // If directReturn is true, the value passed in for wrap will be
+ // returned instead of being called. Alternately, the
+ // AdapterRegistry can be set globally to "return not call" using
+ // the returnWrappers property. Either way, this behavior allows
+ // the registry to act as a "search" function instead of a
+ // function interception library.
+ // override:
+ // If override is given and true, the check function will be given
+ // highest priority. Otherwise, it will be the lowest priority
+ // adapter.
+ this.pairs[((override) ? "unshift" : "push")]([name, check, wrap, directReturn]);
+ },
+
+ match: function(/* ... */){
+ // summary:
+ // Find an adapter for the given arguments. If no suitable adapter
+ // is found, throws an exception. match() accepts any number of
+ // arguments, all of which are passed to all matching functions
+ // from the registered pairs.
+ for(var i = 0; i < this.pairs.length; i++){
+ var pair = this.pairs[i];
+ if(pair[1].apply(this, arguments)){
+ if((pair[3])||(this.returnWrappers)){
+ return pair[2];
+ }else{
+ return pair[2].apply(this, arguments);
+ }
+ }
+ }
+ throw new Error("No match found");
+ },
+
+ unregister: function(name){
+ // summary: Remove a named adapter from the registry
+
+ // FIXME: this is kind of a dumb way to handle this. On a large
+ // registry this will be slow-ish and we can use the name as a lookup
+ // should we choose to trade memory for speed.
+ for(var i = 0; i < this.pairs.length; i++){
+ var pair = this.pairs[i];
+ if(pair[0] == name){
+ this.pairs.splice(i, 1);
+ return true;
+ }
+ }
+ return false;
+ }
+});
+
+}
diff --git a/includes/js/dojo/DeferredList.js b/includes/js/dojo/DeferredList.js
new file mode 100644
index 0000000..0a77d11
--- /dev/null
+++ b/includes/js/dojo/DeferredList.js
@@ -0,0 +1,88 @@
+if(!dojo._hasResource["dojo.DeferredList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.DeferredList"] = true;
+dojo.provide("dojo.DeferredList");
+dojo.declare("dojo.DeferredList", dojo.Deferred, {
+ constructor: function(/*Array*/ list, /*Boolean?*/ fireOnOneCallback, /*Boolean?*/ fireOnOneErrback, /*Boolean?*/ consumeErrors, /*Function?*/ canceller){
+ // summary:
+ // Provides event handling for a group of Deferred objects.
+ // description:
+ // DeferredList takes an array of existing deferreds and returns a new deferred of its own
+ // this new deferred will typically have its callback fired when all of the deferreds in
+ // the given list have fired their own deferreds. The parameters `fireOnOneCallback` and
+ // fireOnOneErrback, will fire before all the deferreds as appropriate
+ //
+ // list:
+ // The list of deferreds to be synchronizied with this DeferredList
+ // fireOnOneCallback:
+ // Will cause the DeferredLists callback to be fired as soon as any
+ // of the deferreds in its list have been fired instead of waiting until
+ // the entire list has finished
+ // fireonOneErrback:
+ // Will cause the errback to fire upon any of the deferreds errback
+ // canceller:
+ // A deferred canceller function, see dojo.Deferred
+ this.list = list;
+ this.resultList = new Array(this.list.length);
+
+ // Deferred init
+ this.chain = [];
+ this.id = this._nextId();
+ this.fired = -1;
+ this.paused = 0;
+ this.results = [null, null];
+ this.canceller = canceller;
+ this.silentlyCancelled = false;
+
+ if(this.list.length === 0 && !fireOnOneCallback){
+ this.callback(this.resultList);
+ }
+
+ this.finishedCount = 0;
+ this.fireOnOneCallback = fireOnOneCallback;
+ this.fireOnOneErrback = fireOnOneErrback;
+ this.consumeErrors = consumeErrors;
+
+ dojo.forEach(this.list, function(d, index){
+ d.addCallback(this, function(r){ this._cbDeferred(index, true, r); return r; });
+ d.addErrback(this, function(r){ this._cbDeferred(index, false, r); return r; });
+ }, this);
+ },
+
+ _cbDeferred: function(index, succeeded, result){
+ // summary:
+ // The DeferredLists' callback handler
+
+ this.resultList[index] = [succeeded, result]; this.finishedCount += 1;
+ if(this.fired !== 0){
+ if(succeeded && this.fireOnOneCallback){
+ this.callback([index, result]);
+ }else if(!succeeded && this.fireOnOneErrback){
+ this.errback(result);
+ }else if(this.finishedCount == this.list.length){
+ this.callback(this.resultList);
+ }
+ }
+ if(!succeeded && this.consumeErrors){
+ result = null;
+ }
+ return result;
+ },
+
+ gatherResults: function(deferredList){
+ // summary:
+ // Gathers the results of the deferreds for packaging
+ // as the parameters to the Deferred Lists' callback
+
+ var d = new dojo.DeferredList(deferredList, false, true, false);
+ d.addCallback(function(results){
+ var ret = [];
+ dojo.forEach(results, function(result){
+ ret.push(result[1]);
+ });
+ return ret;
+ });
+ return d;
+ }
+});
+
+}
diff --git a/includes/js/dojo/LICENSE b/includes/js/dojo/LICENSE
new file mode 100644
index 0000000..3fa2720
--- /dev/null
+++ b/includes/js/dojo/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/dojo/NodeList-fx.js b/includes/js/dojo/NodeList-fx.js
new file mode 100644
index 0000000..ede0a89
--- /dev/null
+++ b/includes/js/dojo/NodeList-fx.js
@@ -0,0 +1,137 @@
+if(!dojo._hasResource["dojo.NodeList-fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.NodeList-fx"] = true;
+dojo.provide("dojo.NodeList-fx");
+dojo.require("dojo.fx");
+
+/*=====
+dojo["NodeList-fx"] = {
+ // summary: Adds dojo.fx animation support to dojo.query()
+};
+=====*/
+
+dojo.extend(dojo.NodeList, {
+ _anim: function(obj, method, args){
+ args = args||{};
+ return dojo.fx.combine(
+ this.map(function(item){
+ var tmpArgs = { node: item };
+ dojo.mixin(tmpArgs, args);
+ return obj[method](tmpArgs);
+ })
+ ); // dojo._Animation
+ },
+
+ wipeIn: function(args){
+ // summary:
+ // wipe in all elements of this NodeList. Returns an instance of dojo._Animation
+ // example:
+ // Fade in all tables with class "blah":
+ // | dojo.query("table.blah").wipeIn().play();
+ return this._anim(dojo.fx, "wipeIn", args); // dojo._Animation
+ },
+
+ wipeOut: function(args){
+ // summary:
+ // wipe out all elements of this NodeList. Returns an instance of dojo._Animation
+ // example:
+ // Wipe out all tables with class "blah":
+ // | dojo.query("table.blah").wipeOut().play();
+ return this._anim(dojo.fx, "wipeOut", args); // dojo._Animation
+ },
+
+ slideTo: function(args){
+ // summary:
+ // slide all elements of the node list to the specified place.
+ // Returns an instance of dojo._Animation
+ // example:
+ // | Move all tables with class "blah" to 300/300:
+ // | dojo.query("table.blah").slideTo({
+ // | left: 40,
+ // | top: 50
+ // | }).play();
+ return this._anim(dojo.fx, "slideTo", args); // dojo._Animation
+ },
+
+
+ fadeIn: function(args){
+ // summary:
+ // fade in all elements of this NodeList. Returns an instance of dojo._Animation
+ // example:
+ // Fade in all tables with class "blah":
+ // | dojo.query("table.blah").fadeIn().play();
+ return this._anim(dojo, "fadeIn", args); // dojo._Animation
+ },
+
+ fadeOut: function(args){
+ // summary:
+ // fade out all elements of this NodeList. Returns an instance of dojo._Animation
+ // example:
+ // Fade out all elements with class "zork":
+ // | dojo.query(".zork").fadeOut().play();
+ // example:
+ // Fade them on a delay and do something at the end:
+ // | var fo = dojo.query(".zork").fadeOut();
+ // | dojo.connect(fo, "onEnd", function(){ /*...*/ });
+ // | fo.play();
+ return this._anim(dojo, "fadeOut", args); // dojo._Animation
+ },
+
+ animateProperty: function(args){
+ // summary:
+ // see dojo.animateProperty(). Animate all elements of this
+ // NodeList across the properties specified.
+ // example:
+ // | dojo.query(".zork").animateProperty({
+ // | duration: 500,
+ // | properties: {
+ // | color: { start: "black", end: "white" },
+ // | left: { end: 300 }
+ // | }
+ // | }).play();
+ return this._anim(dojo, "animateProperty", args); // dojo._Animation
+ },
+
+ anim: function( /*Object*/ properties,
+ /*Integer?*/ duration,
+ /*Function?*/ easing,
+ /*Function?*/ onEnd,
+ /*Integer?*/ delay){
+ // summary:
+ // Animate one or more CSS properties for all nodes in this list.
+ // The returned animation object will already be playing when it
+ // is returned. See the docs for `dojo.anim` for full details.
+ // properties: Object
+ // the properties to animate
+ // duration: Integer?
+ // Optional. The time to run the animations for
+ // easing: Function?
+ // Optional. The easing function to use.
+ // onEnd: Function?
+ // A function to be called when the animation ends
+ // delay:
+ // how long to delay playing the returned animation
+ // example:
+ // Another way to fade out:
+ // | dojo.query(".thinger").anim({ opacity: 0 });
+ // example:
+ // animate all elements with the "thigner" class to a width of 500
+ // pixels over half a second
+ // | dojo.query(".thinger").anim({ width: 500 }, 700);
+ var canim = dojo.fx.combine(
+ this.map(function(item){
+ return dojo.animateProperty({
+ node: item,
+ properties: properties,
+ duration: duration||350,
+ easing: easing
+ });
+ })
+ );
+ if(onEnd){
+ dojo.connect(canim, "onEnd", onEnd);
+ }
+ return canim.play(delay||0); // dojo._Animation
+ }
+});
+
+}
diff --git a/includes/js/dojo/OpenAjax.js b/includes/js/dojo/OpenAjax.js
new file mode 100644
index 0000000..32cf358
--- /dev/null
+++ b/includes/js/dojo/OpenAjax.js
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * OpenAjax.js
+ *
+ * Reference implementation of the OpenAjax Hub, as specified by OpenAjax Alliance.
+ * Specification is under development at:
+ *
+ * http://www.openajax.org/member/wiki/OpenAjax_Hub_Specification
+ *
+ * Copyright 2006-2007 OpenAjax Alliance
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0 . Unless
+ * required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ ******************************************************************************/
+
+// prevent re-definition of the OpenAjax object
+if(!window["OpenAjax"]){
+ OpenAjax = new function(){
+ // summary: the OpenAjax hub
+ // description: see http://www.openajax.org/member/wiki/OpenAjax_Hub_Specification
+
+ var t = true;
+ var f = false;
+ var g = window;
+ var libs;
+ var ooh = "org.openajax.hub.";
+
+ var h = {};
+ this.hub = h;
+ h.implementer = "http://openajax.org";
+ h.implVersion = "0.6";
+ h.specVersion = "0.6";
+ h.implExtraData = {};
+ var libs = {};
+ h.libraries = libs;
+
+ h.registerLibrary = function(prefix, nsURL, version, extra){
+ libs[prefix] = {
+ prefix: prefix,
+ namespaceURI: nsURL,
+ version: version,
+ extraData: extra
+ };
+ this.publish(ooh+"registerLibrary", libs[prefix]);
+ }
+ h.unregisterLibrary = function(prefix){
+ this.publish(ooh+"unregisterLibrary", libs[prefix]);
+ delete libs[prefix];
+ }
+
+ h._subscriptions = { c:{}, s:[] };
+ h._cleanup = [];
+ h._subIndex = 0;
+ h._pubDepth = 0;
+
+ h.subscribe = function(name, callback, scope, subscriberData, filter){
+ if(!scope){
+ scope = window;
+ }
+ var handle = name + "." + this._subIndex;
+ var sub = { scope: scope, cb: callback, fcb: filter, data: subscriberData, sid: this._subIndex++, hdl: handle };
+ var path = name.split(".");
+ this._subscribe(this._subscriptions, path, 0, sub);
+ return handle;
+ }
+
+ h.publish = function(name, message){
+ var path = name.split(".");
+ this._pubDepth++;
+ this._publish(this._subscriptions, path, 0, name, message);
+ this._pubDepth--;
+ if((this._cleanup.length > 0) && (this._pubDepth == 0)){
+ for(var i = 0; i < this._cleanup.length; i++){
+ this.unsubscribe(this._cleanup[i].hdl);
+ }
+ delete(this._cleanup);
+ this._cleanup = [];
+ }
+ }
+
+ h.unsubscribe = function(sub){
+ var path = sub.split(".");
+ var sid = path.pop();
+ this._unsubscribe(this._subscriptions, path, 0, sid);
+ }
+
+ h._subscribe = function(tree, path, index, sub){
+ var token = path[index];
+ if(index == path.length){
+ tree.s.push(sub);
+ }else{
+ if(typeof tree.c == "undefined"){
+ tree.c = {};
+ }
+ if(typeof tree.c[token] == "undefined"){
+ tree.c[token] = { c: {}, s: [] };
+ this._subscribe(tree.c[token], path, index + 1, sub);
+ }else{
+ this._subscribe( tree.c[token], path, index + 1, sub);
+ }
+ }
+ }
+
+ h._publish = function(tree, path, index, name, msg){
+ if(typeof tree != "undefined"){
+ var node;
+ if(index == path.length) {
+ node = tree;
+ }else{
+ this._publish(tree.c[path[index]], path, index + 1, name, msg);
+ this._publish(tree.c["*"], path, index + 1, name, msg);
+ node = tree.c["**"];
+ }
+ if(typeof node != "undefined"){
+ var callbacks = node.s;
+ var max = callbacks.length;
+ for(var i = 0; i < max; i++){
+ if(callbacks[i].cb){
+ var sc = callbacks[i].scope;
+ var cb = callbacks[i].cb;
+ var fcb = callbacks[i].fcb;
+ var d = callbacks[i].data;
+ if(typeof cb == "string"){
+ // get a function object
+ cb = sc[cb];
+ }
+ if(typeof fcb == "string"){
+ // get a function object
+ fcb = sc[fcb];
+ }
+ if((!fcb) ||
+ (fcb.call(sc, name, msg, d))) {
+ cb.call(sc, name, msg, d);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ h._unsubscribe = function(tree, path, index, sid) {
+ if(typeof tree != "undefined") {
+ if(index < path.length) {
+ var childNode = tree.c[path[index]];
+ this._unsubscribe(childNode, path, index + 1, sid);
+ if(childNode.s.length == 0) {
+ for(var x in childNode.c)
+ return;
+ delete tree.c[path[index]];
+ }
+ return;
+ }
+ else {
+ var callbacks = tree.s;
+ var max = callbacks.length;
+ for(var i = 0; i < max; i++)
+ if(sid == callbacks[i].sid) {
+ if(this._pubDepth > 0) {
+ callbacks[i].cb = null;
+ this._cleanup.push(callbacks[i]);
+ }
+ else
+ callbacks.splice(i, 1);
+ return;
+ }
+ }
+ }
+ }
+ // The following function is provided for automatic testing purposes.
+ // It is not expected to be deployed in run-time OpenAjax Hub implementations.
+ h.reinit = function()
+ {
+ for (var lib in OpenAjax.hub.libraries) {
+ delete OpenAjax.hub.libraries[lib];
+ }
+ OpenAjax.hub.registerLibrary("OpenAjax", "http://openajax.org/hub", "0.6", {});
+
+ delete OpenAjax._subscriptions;
+ OpenAjax._subscriptions = {c:{},s:[]};
+ delete OpenAjax._cleanup;
+ OpenAjax._cleanup = [];
+ OpenAjax._subIndex = 0;
+ OpenAjax._pubDepth = 0;
+ }
+ };
+ // Register the OpenAjax Hub itself as a library.
+ OpenAjax.hub.registerLibrary("OpenAjax", "http://openajax.org/hub", "0.6", {});
+
+}
diff --git a/includes/js/dojo/_base.js b/includes/js/dojo/_base.js
new file mode 100644
index 0000000..e1a7edd
--- /dev/null
+++ b/includes/js/dojo/_base.js
@@ -0,0 +1,13 @@
+if(!dojo._hasResource["dojo._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base"] = true;
+dojo.provide("dojo._base");
+dojo.require("dojo._base.lang");
+dojo.require("dojo._base.declare");
+dojo.require("dojo._base.connect");
+dojo.require("dojo._base.Deferred");
+dojo.require("dojo._base.json");
+dojo.require("dojo._base.array");
+dojo.require("dojo._base.Color");
+dojo.requireIf(dojo.isBrowser, "dojo._base.browser");
+
+}
diff --git a/includes/js/dojo/_base/Color.js b/includes/js/dojo/_base/Color.js
new file mode 100644
index 0000000..38d0584
--- /dev/null
+++ b/includes/js/dojo/_base/Color.js
@@ -0,0 +1,156 @@
+if(!dojo._hasResource["dojo._base.Color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.Color"] = true;
+dojo.provide("dojo._base.Color");
+dojo.require("dojo._base.array");
+dojo.require("dojo._base.lang");
+
+dojo.Color = function(/*Array|String|Object*/ color){
+ // summary:
+ // takes a named string, hex string, array of rgb or rgba values,
+ // an object with r, g, b, and a properties, or another dojo.Color object
+ if(color){ this.setColor(color); }
+};
+
+// FIXME: there's got to be a more space-efficient way to encode or discover these!! Use hex?
+dojo.Color.named = {
+ black: [0,0,0],
+ silver: [192,192,192],
+ gray: [128,128,128],
+ white: [255,255,255],
+ maroon: [128,0,0],
+ red: [255,0,0],
+ purple: [128,0,128],
+ fuchsia: [255,0,255],
+ green: [0,128,0],
+ lime: [0,255,0],
+ olive: [128,128,0],
+ yellow: [255,255,0],
+ navy: [0,0,128],
+ blue: [0,0,255],
+ teal: [0,128,128],
+ aqua: [0,255,255]
+};
+
+
+dojo.extend(dojo.Color, {
+ r: 255, g: 255, b: 255, a: 1,
+ _set: function(r, g, b, a){
+ var t = this; t.r = r; t.g = g; t.b = b; t.a = a;
+ },
+ setColor: function(/*Array|String|Object*/ color){
+ // summary:
+ // takes a named string, hex string, array of rgb or rgba values,
+ // an object with r, g, b, and a properties, or another dojo.Color object
+ var d = dojo;
+ if(d.isString(color)){
+ d.colorFromString(color, this);
+ }else if(d.isArray(color)){
+ d.colorFromArray(color, this);
+ }else{
+ this._set(color.r, color.g, color.b, color.a);
+ if(!(color instanceof d.Color)){ this.sanitize(); }
+ }
+ return this; // dojo.Color
+ },
+ sanitize: function(){
+ // summary:
+ // makes sure that the object has correct attributes
+ // description:
+ // the default implementation does nothing, include dojo.colors to
+ // augment it to real checks
+ return this; // dojo.Color
+ },
+ toRgb: function(){
+ // summary: returns 3 component array of rgb values
+ var t = this;
+ return [t.r, t.g, t.b]; // Array
+ },
+ toRgba: function(){
+ // summary: returns a 4 component array of rgba values
+ var t = this;
+ return [t.r, t.g, t.b, t.a]; // Array
+ },
+ toHex: function(){
+ // summary: returns a css color string in hexadecimal representation
+ var arr = dojo.map(["r", "g", "b"], function(x){
+ var s = this[x].toString(16);
+ return s.length < 2 ? "0" + s : s;
+ }, this);
+ return "#" + arr.join(""); // String
+ },
+ toCss: function(/*Boolean?*/ includeAlpha){
+ // summary: returns a css color string in rgb(a) representation
+ var t = this, rgb = t.r + ", " + t.g + ", " + t.b;
+ return (includeAlpha ? "rgba(" + rgb + ", " + t.a : "rgb(" + rgb) + ")"; // String
+ },
+ toString: function(){
+ // summary: returns a visual representation of the color
+ return this.toCss(true); // String
+ }
+});
+
+dojo.blendColors = function(
+ /*dojo.Color*/ start,
+ /*dojo.Color*/ end,
+ /*Number*/ weight,
+ /*dojo.Color?*/ obj
+){
+ // summary:
+ // blend colors end and start with weight from 0 to 1, 0.5 being a 50/50 blend,
+ // can reuse a previously allocated dojo.Color object for the result
+ var d = dojo, t = obj || new dojo.Color();
+ d.forEach(["r", "g", "b", "a"], function(x){
+ t[x] = start[x] + (end[x] - start[x]) * weight;
+ if(x != "a"){ t[x] = Math.round(t[x]); }
+ });
+ return t.sanitize(); // dojo.Color
+};
+
+dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
+ // summary: get rgb(a) array from css-style color declarations
+ var m = color.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/);
+ return m && dojo.colorFromArray(m[1].split(/\s*,\s*/), obj); // dojo.Color
+};
+
+dojo.colorFromHex = function(/*String*/ color, /*dojo.Color?*/ obj){
+ // summary: converts a hex string with a '#' prefix to a color object.
+ // Supports 12-bit #rgb shorthand.
+ var d = dojo, t = obj || new d.Color(),
+ bits = (color.length == 4) ? 4 : 8,
+ mask = (1 << bits) - 1;
+ color = Number("0x" + color.substr(1));
+ if(isNaN(color)){
+ return null; // dojo.Color
+ }
+ d.forEach(["b", "g", "r"], function(x){
+ var c = color & mask;
+ color >>= bits;
+ t[x] = bits == 4 ? 17 * c : c;
+ });
+ t.a = 1;
+ return t; // dojo.Color
+};
+
+dojo.colorFromArray = function(/*Array*/ a, /*dojo.Color?*/ obj){
+ // summary: builds a color from 1, 2, 3, or 4 element array
+ var t = obj || new dojo.Color();
+ t._set(Number(a[0]), Number(a[1]), Number(a[2]), Number(a[3]));
+ if(isNaN(t.a)){ t.a = 1; }
+ return t.sanitize(); // dojo.Color
+};
+
+dojo.colorFromString = function(/*String*/ str, /*dojo.Color?*/ obj){
+ // summary:
+ // parses str for a color value.
+ // description:
+ // Acceptable input values for str may include arrays of any form
+ // accepted by dojo.colorFromArray, hex strings such as "#aaaaaa", or
+ // rgb or rgba strings such as "rgb(133, 200, 16)" or "rgba(10, 10,
+ // 10, 50)"
+ // returns:
+ // a dojo.Color object. If obj is passed, it will be the return value.
+ var a = dojo.Color.named[str];
+ return a && dojo.colorFromArray(a, obj) || dojo.colorFromRgb(str, obj) || dojo.colorFromHex(str, obj);
+};
+
+}
diff --git a/includes/js/dojo/_base/Deferred.js b/includes/js/dojo/_base/Deferred.js
new file mode 100644
index 0000000..9fe8918
--- /dev/null
+++ b/includes/js/dojo/_base/Deferred.js
@@ -0,0 +1,408 @@
+if(!dojo._hasResource["dojo._base.Deferred"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.Deferred"] = true;
+dojo.provide("dojo._base.Deferred");
+dojo.require("dojo._base.lang");
+
+dojo.Deferred = function(/*Function?*/ canceller){
+ // summary:
+ // Encapsulates a sequence of callbacks in response to a value that
+ // may not yet be available. This is modeled after the Deferred class
+ // from Twisted <http://twistedmatrix.com>.
+ // description:
+ // JavaScript has no threads, and even if it did, threads are hard.
+ // Deferreds are a way of abstracting non-blocking events, such as the
+ // final response to an XMLHttpRequest. Deferreds create a promise to
+ // return a response a some point in the future and an easy way to
+ // register your interest in receiving that response.
+ //
+ // The most important methods for Deffered users are:
+ //
+ // * addCallback(handler)
+ // * addErrback(handler)
+ // * callback(result)
+ // * errback(result)
+ //
+ // In general, when a function returns a Deferred, users then "fill
+ // in" the second half of the contract by registering callbacks and
+ // error handlers. You may register as many callback and errback
+ // handlers as you like and they will be executed in the order
+ // registered when a result is provided. Usually this result is
+ // provided as the result of an asynchronous operation. The code
+ // "managing" the Deferred (the code that made the promise to provide
+ // an answer later) will use the callback() and errback() methods to
+ // communicate with registered listeners about the result of the
+ // operation. At this time, all registered result handlers are called
+ // *with the most recent result value*.
+ //
+ // Deferred callback handlers are treated as a chain, and each item in
+ // the chain is required to return a value that will be fed into
+ // successive handlers. The most minimal callback may be registered
+ // like this:
+ //
+ // | var d = new dojo.Deferred();
+ // | d.addCallback(function(result){ return result; });
+ //
+ // Perhaps the most common mistake when first using Deferreds is to
+ // forget to return a value (in most cases, the value you were
+ // passed).
+ //
+ // The sequence of callbacks is internally represented as a list of
+ // 2-tuples containing the callback/errback pair. For example, the
+ // following call sequence:
+ //
+ // | var d = new dojo.Deferred();
+ // | d.addCallback(myCallback);
+ // | d.addErrback(myErrback);
+ // | d.addBoth(myBoth);
+ // | d.addCallbacks(myCallback, myErrback);
+ //
+ // is translated into a Deferred with the following internal
+ // representation:
+ //
+ // | [
+ // | [myCallback, null],
+ // | [null, myErrback],
+ // | [myBoth, myBoth],
+ // | [myCallback, myErrback]
+ // | ]
+ //
+ // The Deferred also keeps track of its current status (fired). Its
+ // status may be one of three things:
+ //
+ // * -1: no value yet (initial condition)
+ // * 0: success
+ // * 1: error
+ //
+ // A Deferred will be in the error state if one of the following three
+ // conditions are met:
+ //
+ // 1. The result given to callback or errback is "instanceof" Error
+ // 2. The previous callback or errback raised an exception while
+ // executing
+ // 3. The previous callback or errback returned a value
+ // "instanceof" Error
+ //
+ // Otherwise, the Deferred will be in the success state. The state of
+ // the Deferred determines the next element in the callback sequence
+ // to run.
+ //
+ // When a callback or errback occurs with the example deferred chain,
+ // something equivalent to the following will happen (imagine
+ // that exceptions are caught and returned):
+ //
+ // | // d.callback(result) or d.errback(result)
+ // | if(!(result instanceof Error)){
+ // | result = myCallback(result);
+ // | }
+ // | if(result instanceof Error){
+ // | result = myErrback(result);
+ // | }
+ // | result = myBoth(result);
+ // | if(result instanceof Error){
+ // | result = myErrback(result);
+ // | }else{
+ // | result = myCallback(result);
+ // | }
+ //
+ // The result is then stored away in case another step is added to the
+ // callback sequence. Since the Deferred already has a value
+ // available, any new callbacks added will be called immediately.
+ //
+ // There are two other "advanced" details about this implementation
+ // that are useful:
+ //
+ // Callbacks are allowed to return Deferred instances themselves, so
+ // you can build complicated sequences of events with ease.
+ //
+ // The creator of the Deferred may specify a canceller. The canceller
+ // is a function that will be called if Deferred.cancel is called
+ // before the Deferred fires. You can use this to implement clean
+ // aborting of an XMLHttpRequest, etc. Note that cancel will fire the
+ // deferred with a CancelledError (unless your canceller returns
+ // another kind of error), so the errbacks should be prepared to
+ // handle that error for cancellable Deferreds.
+ // example:
+ // | var deferred = new dojo.Deferred();
+ // | setTimeout(function(){ deferred.callback({success: true}); }, 1000);
+ // | return deferred;
+ // example:
+ // Deferred objects are often used when making code asynchronous. It
+ // may be easiest to write functions in a synchronous manner and then
+ // split code using a deferred to trigger a response to a long-lived
+ // operation. For example, instead of register a callback function to
+ // denote when a rendering operation completes, the function can
+ // simply return a deferred:
+ //
+ // | // callback style:
+ // | function renderLotsOfData(data, callback){
+ // | var success = false
+ // | try{
+ // | for(var x in data){
+ // | renderDataitem(data[x]);
+ // | }
+ // | success = true;
+ // | }catch(e){ }
+ // | if(callback){
+ // | callback(success);
+ // | }
+ // | }
+ //
+ // | // using callback style
+ // | renderLotsOfData(someDataObj, function(success){
+ // | // handles success or failure
+ // | if(!success){
+ // | promptUserToRecover();
+ // | }
+ // | });
+ // | // NOTE: no way to add another callback here!!
+ // example:
+ // Using a Deferred doesn't simplify the sending code any, but it
+ // provides a standard interface for callers and senders alike,
+ // providing both with a simple way to service multiple callbacks for
+ // an operation and freeing both sides from worrying about details
+ // such as "did this get called already?". With Deferreds, new
+ // callbacks can be added at any time.
+ //
+ // | // Deferred style:
+ // | function renderLotsOfData(data){
+ // | var d = new dojo.Deferred();
+ // | try{
+ // | for(var x in data){
+ // | renderDataitem(data[x]);
+ // | }
+ // | d.callback(true);
+ // | }catch(e){
+ // | d.errback(new Error("rendering failed"));
+ // | }
+ // | return d;
+ // | }
+ //
+ // | // using Deferred style
+ // | renderLotsOfData(someDataObj).addErrback(function(){
+ // | promptUserToRecover();
+ // | });
+ // | // NOTE: addErrback and addCallback both return the Deferred
+ // | // again, so we could chain adding callbacks or save the
+ // | // deferred for later should we need to be notified again.
+ // example:
+ // In this example, renderLotsOfData is syncrhonous and so both
+ // versions are pretty artificial. Putting the data display on a
+ // timeout helps show why Deferreds rock:
+ //
+ // | // Deferred style and async func
+ // | function renderLotsOfData(data){
+ // | var d = new dojo.Deferred();
+ // | setTimeout(function(){
+ // | try{
+ // | for(var x in data){
+ // | renderDataitem(data[x]);
+ // | }
+ // | d.callback(true);
+ // | }catch(e){
+ // | d.errback(new Error("rendering failed"));
+ // | }
+ // | }, 100);
+ // | return d;
+ // | }
+ //
+ // | // using Deferred style
+ // | renderLotsOfData(someDataObj).addErrback(function(){
+ // | promptUserToRecover();
+ // | });
+ //
+ // Note that the caller doesn't have to change his code at all to
+ // handle the asynchronous case.
+
+ this.chain = [];
+ this.id = this._nextId();
+ this.fired = -1;
+ this.paused = 0;
+ this.results = [null, null];
+ this.canceller = canceller;
+ this.silentlyCancelled = false;
+};
+
+dojo.extend(dojo.Deferred, {
+ /*
+ makeCalled: function(){
+ // summary:
+ // returns a new, empty deferred, which is already in the called
+ // state. Calling callback() or errback() on this deferred will
+ // yeild an error and adding new handlers to it will result in
+ // them being called immediately.
+ var deferred = new dojo.Deferred();
+ deferred.callback();
+ return deferred;
+ },
+
+ toString: function(){
+ var state;
+ if(this.fired == -1){
+ state = 'unfired';
+ }else{
+ state = this.fired ? 'success' : 'error';
+ }
+ return 'Deferred(' + this.id + ', ' + state + ')';
+ },
+ */
+
+ _nextId: (function(){
+ var n = 1;
+ return function(){ return n++; };
+ })(),
+
+ cancel: function(){
+ // summary:
+ // Cancels a Deferred that has not yet received a value, or is
+ // waiting on another Deferred as its value.
+ // description:
+ // If a canceller is defined, the canceller is called. If the
+ // canceller did not return an error, or there was no canceller,
+ // then the errback chain is started.
+ var err;
+ if(this.fired == -1){
+ if(this.canceller){
+ err = this.canceller(this);
+ }else{
+ this.silentlyCancelled = true;
+ }
+ if(this.fired == -1){
+ if(!(err instanceof Error)){
+ var res = err;
+ err = new Error("Deferred Cancelled");
+ err.dojoType = "cancel";
+ err.cancelResult = res;
+ }
+ this.errback(err);
+ }
+ }else if( (this.fired == 0) &&
+ (this.results[0] instanceof dojo.Deferred)
+ ){
+ this.results[0].cancel();
+ }
+ },
+
+
+ _resback: function(res){
+ // summary:
+ // The private primitive that means either callback or errback
+ this.fired = ((res instanceof Error) ? 1 : 0);
+ this.results[this.fired] = res;
+ this._fire();
+ },
+
+ _check: function(){
+ if(this.fired != -1){
+ if(!this.silentlyCancelled){
+ throw new Error("already called!");
+ }
+ this.silentlyCancelled = false;
+ return;
+ }
+ },
+
+ callback: function(res){
+ // summary:
+ // Begin the callback sequence with a non-error value.
+
+ /*
+ callback or errback should only be called once on a given
+ Deferred.
+ */
+ this._check();
+ this._resback(res);
+ },
+
+ errback: function(/*Error*/res){
+ // summary:
+ // Begin the callback sequence with an error result.
+ this._check();
+ if(!(res instanceof Error)){
+ res = new Error(res);
+ }
+ this._resback(res);
+ },
+
+ addBoth: function(/*Function|Object*/cb, /*String?*/cbfn){
+ // summary:
+ // Add the same function as both a callback and an errback as the
+ // next element on the callback sequence.This is useful for code
+ // that you want to guarantee to run, e.g. a finalizer.
+ var enclosed = dojo.hitch.apply(dojo, arguments);
+ return this.addCallbacks(enclosed, enclosed);
+ },
+
+ addCallback: function(/*Function|Object*/cb, /*String?*/cbfn /*...*/){
+ // summary:
+ // Add a single callback to the end of the callback sequence.
+ return this.addCallbacks(dojo.hitch.apply(dojo, arguments));
+ },
+
+ addErrback: function(cb, cbfn){
+ // summary:
+ // Add a single callback to the end of the callback sequence.
+ return this.addCallbacks(null, dojo.hitch.apply(dojo, arguments));
+ },
+
+ addCallbacks: function(cb, eb){
+ // summary:
+ // Add separate callback and errback to the end of the callback
+ // sequence.
+ this.chain.push([cb, eb])
+ if(this.fired >= 0){
+ this._fire();
+ }
+ return this;
+ },
+
+ _fire: function(){
+ // summary:
+ // Used internally to exhaust the callback sequence when a result
+ // is available.
+ var chain = this.chain;
+ var fired = this.fired;
+ var res = this.results[fired];
+ var self = this;
+ var cb = null;
+ while(
+ (chain.length > 0) &&
+ (this.paused == 0)
+ ){
+ // Array
+ var f = chain.shift()[fired];
+ if(!f){ continue; }
+ try{
+ res = f(res);
+ fired = ((res instanceof Error) ? 1 : 0);
+ if(res instanceof dojo.Deferred){
+ cb = function(res){
+ self._resback(res);
+ // inlined from _pause()
+ self.paused--;
+ if(
+ (self.paused == 0) &&
+ (self.fired >= 0)
+ ){
+ self._fire();
+ }
+ }
+ // inlined from _unpause
+ this.paused++;
+ }
+ }catch(err){
+ console.debug(err);
+ fired = 1;
+ res = err;
+ }
+ }
+ this.fired = fired;
+ this.results[fired] = res;
+ if((cb)&&(this.paused)){
+ // this is for "tail recursion" in case the dependent
+ // deferred is already fired
+ res.addBoth(cb);
+ }
+ }
+});
+
+}
diff --git a/includes/js/dojo/_base/NodeList.js b/includes/js/dojo/_base/NodeList.js
new file mode 100644
index 0000000..c10e18d
--- /dev/null
+++ b/includes/js/dojo/_base/NodeList.js
@@ -0,0 +1,532 @@
+if(!dojo._hasResource["dojo._base.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.NodeList"] = true;
+dojo.provide("dojo._base.NodeList");
+dojo.require("dojo._base.lang");
+dojo.require("dojo._base.array");
+
+(function(){
+
+ var d = dojo;
+
+ var tnl = function(arr){
+ // decorate an array to make it look like a NodeList
+ arr.constructor = dojo.NodeList;
+ dojo._mixin(arr, dojo.NodeList.prototype);
+ return arr;
+ }
+
+ var _mapIntoDojo = function(func, alwaysThis){
+ // returns a function which, when executed in the scope of its caller,
+ // applies the passed arguments to a particular dojo.* function (named
+ // in func) and aggregates the returns. if alwaysThis is true, it
+ // always returns the scope object and not the collected returns from
+ // the Dojo method
+ return function(){
+ var _a = arguments;
+ var aa = d._toArray(_a, 0, [null]);
+ var s = this.map(function(i){
+ aa[0] = i;
+ return d[func].apply(d, aa);
+ });
+ return (alwaysThis || ( (_a.length > 1) || !d.isString(_a[0]) )) ? this : s; // String||dojo.NodeList
+ }
+ };
+
+ dojo.NodeList = function(){
+ // summary:
+ // dojo.NodeList is as subclass of Array which adds syntactic
+ // sugar for chaining, common iteration operations, animation,
+ // and node manipulation. NodeLists are most often returned as
+ // the result of dojo.query() calls.
+ // example:
+ // create a node list from a node
+ // | new dojo.NodeList(dojo.byId("foo"));
+
+ return tnl(Array.apply(null, arguments));
+ }
+
+ dojo.NodeList._wrap = tnl;
+
+ dojo.extend(dojo.NodeList, {
+ // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
+
+ // FIXME: handle return values for #3244
+ // http://trac.dojotoolkit.org/ticket/3244
+
+ // FIXME:
+ // need to wrap or implement:
+ // join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
+ // reduce
+ // reduceRight
+
+ slice: function(/*===== begin, end =====*/){
+ // summary:
+ // Returns a new NodeList, maintaining this one in place
+ // description:
+ // This method behaves exactly like the Array.slice method
+ // with the caveat that it returns a dojo.NodeList and not a
+ // raw Array. For more details, see:
+ // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice
+ // begin: Integer
+ // Can be a positive or negative integer, with positive
+ // integers noting the offset to begin at, and negative
+ // integers denoting an offset from the end (i.e., to the left
+ // of the end)
+ // end: Integer?
+ // Optional parameter to describe what position relative to
+ // the NodeList's zero index to end the slice at. Like begin,
+ // can be positive or negative.
+ var a = dojo._toArray(arguments);
+ return tnl(a.slice.apply(this, a));
+ },
+
+ splice: function(/*===== index, howmany, item =====*/){
+ // summary:
+ // Returns a new NodeList, manipulating this NodeList based on
+ // the arguments passed, potentially splicing in new elements
+ // at an offset, optionally deleting elements
+ // description:
+ // This method behaves exactly like the Array.splice method
+ // with the caveat that it returns a dojo.NodeList and not a
+ // raw Array. For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice>
+ // index: Integer
+ // begin can be a positive or negative integer, with positive
+ // integers noting the offset to begin at, and negative
+ // integers denoting an offset from the end (i.e., to the left
+ // of the end)
+ // howmany: Integer?
+ // Optional parameter to describe what position relative to
+ // the NodeList's zero index to end the slice at. Like begin,
+ // can be positive or negative.
+ // item: Object...?
+ // Any number of optional parameters may be passed in to be
+ // spliced into the NodeList
+ // returns:
+ // dojo.NodeList
+ var a = dojo._toArray(arguments);
+ return tnl(a.splice.apply(this, a));
+ },
+
+ concat: function(/*===== item =====*/){
+ // summary:
+ // Returns a new NodeList comprised of items in this NodeList
+ // as well as items passed in as parameters
+ // description:
+ // This method behaves exactly like the Array.concat method
+ // with the caveat that it returns a dojo.NodeList and not a
+ // raw Array. For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat>
+ // item: Object...?
+ // Any number of optional parameters may be passed in to be
+ // spliced into the NodeList
+ // returns:
+ // dojo.NodeList
+ var a = dojo._toArray(arguments, 0, [this]);
+ return tnl(a.concat.apply([], a));
+ },
+
+ indexOf: function(/*Object*/ value, /*Integer?*/ fromIndex){
+ // summary:
+ // see dojo.indexOf(). The primary difference is that the acted-on
+ // array is implicitly this NodeList
+ // value:
+ // The value to search for.
+ // fromIndex:
+ // The loction to start searching from. Optional. Defaults to 0.
+ // description:
+ // For more details on the behavior of indexOf, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
+ // returns:
+ // Positive Integer or 0 for a match, -1 of not found.
+ return d.indexOf(this, value, fromIndex); // Integer
+ },
+
+ lastIndexOf: function(/*===== value, fromIndex =====*/){
+ // summary:
+ // see dojo.lastIndexOf(). The primary difference is that the
+ // acted-on array is implicitly this NodeList
+ // description:
+ // For more details on the behavior of lastIndexOf, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf>
+ // value: Object
+ // The value to search for.
+ // fromIndex: Integer?
+ // The loction to start searching from. Optional. Defaults to 0.
+ // returns:
+ // Positive Integer or 0 for a match, -1 of not found.
+ return d.lastIndexOf.apply(d, d._toArray(arguments, 0, [this])); // Integer
+ },
+
+ every: function(/*Function*/callback, /*Object?*/thisObject){
+ // summary:
+ // see `dojo.every()` and:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
+ // Takes the same structure of arguments and returns as
+ // dojo.every() with the caveat that the passed array is
+ // implicitly this NodeList
+ return d.every(this, callback, thisObject); // Boolean
+ },
+
+ some: function(/*Function*/callback, /*Object?*/thisObject){
+ // summary:
+ // see dojo.some() and:
+ // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some
+ // Takes the same structure of arguments and returns as
+ // dojo.some() with the caveat that the passed array is
+ // implicitly this NodeList
+ return d.some(this, callback, thisObject); // Boolean
+ },
+
+ map: function(/*Function*/ func, /*Function?*/ obj){
+ // summary:
+ // see dojo.map(). The primary difference is that the acted-on
+ // array is implicitly this NodeList and the return is a
+ // dojo.NodeList (a subclass of Array)
+
+ return d.map(this, func, obj, d.NodeList); // dojo.NodeList
+ },
+
+ forEach: function(callback, thisObj){
+ // summary:
+ // see dojo.forEach(). The primary difference is that the acted-on
+ // array is implicitly this NodeList
+
+ d.forEach(this, callback, thisObj);
+ // non-standard return to allow easier chaining
+ return this; // dojo.NodeList
+ },
+
+ // custom methods
+
+ coords: function(){
+ // summary:
+ // Returns the box objects all elements in a node list as
+ // an Array (*not* a NodeList)
+
+ return d.map(this, d.coords); // Array
+ },
+
+ /*=====
+ attr: function(property, value){
+ // summary:
+ // gets or sets the DOM attribute for every element in the
+ // NodeList
+ // property: String
+ // the attribute to get/set
+ // value: String?
+ // optional. The value to set the property to
+ // return:
+ // if no value is passed, the result is an array of attribute values
+ // If a value is passed, the return is this NodeList
+ },
+
+ style: function(property, value){
+ // summary:
+ // gets or sets the CSS property for every element in the NodeList
+ // property: String
+ // the CSS property to get/set, in JavaScript notation
+ // ("lineHieght" instead of "line-height")
+ // value: String?
+ // optional. The value to set the property to
+ // return:
+ // if no value is passed, the result is an array of strings.
+ // If a value is passed, the return is this NodeList
+ },
+
+ addClass: function(className){
+ // summary:
+ // adds the specified class to every node in the list
+ // className: String
+ // the CSS class to add
+ // return:
+ // dojo.NodeList, this list
+ },
+
+ removeClass: function(className){
+ // summary:
+ // removes the specified class from every node in the list
+ // className: String
+ // the CSS class to add
+ // return:
+ // dojo.NodeList, this list
+ },
+
+ toggleClass: function(className, condition){
+ // summary:
+ // Adds a class to node if not present, or removes if present.
+ // Pass a boolean condition if you want to explicitly add or remove.
+ // condition: Boolean?
+ // If passed, true means to add the class, false means to remove.
+ // className: String
+ // the CSS class to add
+ // return: dojo.NodeList
+ // this list
+ },
+
+ connect: function(methodName, objOrFunc, funcName){
+ // summary:
+ // attach event handlers to every item of the NodeList. Uses dojo.connect()
+ // so event properties are normalized
+ // methodName: String
+ // the name of the method to attach to. For DOM events, this should be
+ // the lower-case name of the event
+ // objOrFunc: Object|Function|String
+ // if 2 arguments are passed (methodName, objOrFunc), objOrFunc should
+ // reference a function or be the name of the function in the global
+ // namespace to attach. If 3 arguments are provided
+ // (methodName, objOrFunc, funcName), objOrFunc must be the scope to
+ // locate the bound function in
+ // funcName: String?
+ // optional. A string naming the function in objOrFunc to bind to the
+ // event. May also be a function reference.
+ // example:
+ // add an onclick handler to every button on the page
+ // | dojo.query("div:nth-child(odd)").connect("onclick", function(e){
+ // | console.debug("clicked!");
+ // | });
+ // example:
+ // attach foo.bar() to every odd div's onmouseover
+ // | dojo.query("div:nth-child(odd)").connect("onmouseover", foo, "bar");
+ },
+ =====*/
+ attr: _mapIntoDojo("attr"),
+ style: _mapIntoDojo("style"),
+ addClass: _mapIntoDojo("addClass", true),
+ removeClass: _mapIntoDojo("removeClass", true),
+ toggleClass: _mapIntoDojo("toggleClass", true),
+ connect: _mapIntoDojo("connect", true),
+
+ // FIXME: connectPublisher()? connectRunOnce()?
+
+ place: function(/*String||Node*/ queryOrNode, /*String*/ position){
+ // summary:
+ // places elements of this node list relative to the first element matched
+ // by queryOrNode. Returns the original NodeList.
+ // queryOrNode:
+ // may be a string representing any valid CSS3 selector or a DOM node.
+ // In the selector case, only the first matching element will be used
+ // for relative positioning.
+ // position:
+ // can be one of:
+ // * "last"||"end" (default)
+ // * "first||"start"
+ // * "before"
+ // * "after"
+ // or an offset in the childNodes property
+ var item = d.query(queryOrNode)[0];
+ return this.forEach(function(i){ d.place(i, item, (position||"last")); }); // dojo.NodeList
+ },
+
+ orphan: function(/*String?*/ simpleFilter){
+ // summary:
+ // removes elements in this list that match the simple
+ // filter from their parents and returns them as a new
+ // NodeList.
+ // simpleFilter:
+ // single-expression CSS filter
+ // return:
+ // `dojo.NodeList` the orpahned elements
+ var orphans = simpleFilter ? d._filterQueryResult(this, simpleFilter) : this;
+ orphans.forEach(function(item){
+ if(item.parentNode){
+ item.parentNode.removeChild(item);
+ }
+ });
+ return orphans; // dojo.NodeList
+ },
+
+ adopt: function(/*String||Array||DomNode*/ queryOrListOrNode, /*String?*/ position){
+ // summary:
+ // places any/all elements in queryOrListOrNode at a
+ // position relative to the first element in this list.
+ // Returns a dojo.NodeList of the adopted elements.
+ // queryOrListOrNode:
+ // a DOM node or a query string or a query result.
+ // Represents the nodes to be adopted relative to the
+ // first element of this NodeList.
+ // position:
+ // can be one of:
+ // * "last"||"end" (default)
+ // * "first||"start"
+ // * "before"
+ // * "after"
+ // or an offset in the childNodes property
+ var item = this[0];
+ return d.query(queryOrListOrNode).forEach(function(ai){ d.place(ai, item, position || "last"); }); // dojo.NodeList
+ },
+
+ // FIXME: do we need this?
+ query: function(/*String*/ queryStr){
+ // summary:
+ // Returns a new, flattened NodeList. Elements of the new list
+ // satisfy the passed query but use elements of the
+ // current NodeList as query roots.
+
+ if(!queryStr){ return this; }
+
+ // FIXME: probably slow
+ // FIXME: use map?
+ var ret = d.NodeList();
+ this.forEach(function(item){
+ d.query(queryStr, item).forEach(function(subItem){
+ if(subItem !== undefined){
+ ret.push(subItem);
+ }
+ });
+ });
+ return ret; // dojo.NodeList
+ },
+
+ filter: function(/*String*/ simpleQuery){
+ // summary:
+ // "masks" the built-in javascript filter() method to support
+ // passing a simple string filter in addition to supporting
+ // filtering function objects.
+ // example:
+ // "regular" JS filter syntax as exposed in dojo.filter:
+ // | dojo.query("*").filter(function(item){
+ // | // highlight every paragraph
+ // | return (item.nodeName == "p");
+ // | }).styles("backgroundColor", "yellow");
+ // example:
+ // the same filtering using a CSS selector
+ // | dojo.query("*").filter("p").styles("backgroundColor", "yellow");
+
+ var items = this;
+ var _a = arguments;
+ var r = d.NodeList();
+ var rp = function(t){
+ if(t !== undefined){
+ r.push(t);
+ }
+ }
+ if(d.isString(simpleQuery)){
+ items = d._filterQueryResult(this, _a[0]);
+ if(_a.length == 1){
+ // if we only got a string query, pass back the filtered results
+ return items; // dojo.NodeList
+ }
+ // if we got a callback, run it over the filtered items
+ _a.shift();
+ }
+ // handle the (callback, [thisObject]) case
+ d.forEach(d.filter(items, _a[0], _a[1]), rp);
+ return r; // dojo.NodeList
+ },
+
+ /*
+ // FIXME: should this be "copyTo" and include parenting info?
+ clone: function(){
+ // summary:
+ // creates node clones of each element of this list
+ // and returns a new list containing the clones
+ },
+ */
+
+ addContent: function(/*String*/ content, /*String||Integer?*/ position){
+ // summary:
+ // add a node or some HTML as a string to every item in the list.
+ // Returns the original list.
+ // description:
+ // a copy of the HTML content is added to each item in the
+ // list, with an optional position argument. If no position
+ // argument is provided, the content is appended to the end of
+ // each item.
+ // content:
+ // the HTML in string format to add at position to every item
+ // position:
+ // can be one of:
+ // * "last"||"end" (default)
+ // * "first||"start"
+ // * "before"
+ // * "after"
+ // or an offset in the childNodes property
+ // example:
+ // appends content to the end if the position is ommitted
+ // | dojo.query("h3 > p").addContent("hey there!");
+ // example:
+ // add something to the front of each element that has a "thinger" property:
+ // | dojo.query("[thinger]").addContent("...", "first");
+ // example:
+ // adds a header before each element of the list
+ // | dojo.query(".note").addContent("<h4>NOTE:</h4>", "before");
+ var ta = d.doc.createElement("span");
+ if(d.isString(content)){
+ ta.innerHTML = content;
+ }else{
+ ta.appendChild(content);
+ }
+ if(position === undefined){
+ position = "last";
+ }
+ var ct = (position == "first" || position == "after") ? "lastChild" : "firstChild";
+ this.forEach(function(item){
+ var tn = ta.cloneNode(true);
+ while(tn[ct]){
+ d.place(tn[ct], item, position);
+ }
+ });
+ return this; // dojo.NodeList
+ },
+
+ empty: function(){
+ // summary:
+ // clears all content from each node in the list
+ return this.forEach("item.innerHTML='';"); // dojo.NodeList
+
+ // FIXME: should we be checking for and/or disposing of widgets below these nodes?
+ },
+
+ instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){
+ // summary:
+ // Create a new instance of a specified class, using the
+ // specified properties and each node in the nodeList as a
+ // srcNodeRef
+ //
+ var c = d.isFunction(declaredClass) ? declaredClass : d.getObject(declaredClass);
+ return this.forEach(function(i){
+ new c(properties||{},i);
+ }) // dojo.NodeList
+ }
+
+ });
+
+ // syntactic sugar for DOM events
+ d.forEach([
+ "blur", "focus", "click", "keydown", "keypress", "keyup", "mousedown",
+ "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover",
+ "mouseup"
+ ], function(evt){
+ var _oe = "on"+evt;
+ dojo.NodeList.prototype[_oe] = function(a, b){
+ return this.connect(_oe, a, b);
+ }
+ // FIXME: should these events trigger publishes?
+ /*
+ return (a ? this.connect(_oe, a, b) :
+ this.forEach(function(n){
+ // FIXME:
+ // listeners get buried by
+ // addEventListener and can't be dug back
+ // out to be triggered externally.
+ // see:
+ // http://developer.mozilla.org/en/docs/DOM:element
+
+ console.debug(n, evt, _oe);
+
+ // FIXME: need synthetic event support!
+ var _e = { target: n, faux: true, type: evt };
+ // dojo._event_listener._synthesizeEvent({}, { target: n, faux: true, type: evt });
+ try{ n[evt](_e); }catch(e){ console.debug(e); }
+ try{ n[_oe](_e); }catch(e){ console.debug(e); }
+ })
+ );
+ }
+ */
+ }
+ );
+
+})();
+
+}
diff --git a/includes/js/dojo/_base/_loader/bootstrap.js b/includes/js/dojo/_base/_loader/bootstrap.js
new file mode 100644
index 0000000..c62ab6a
--- /dev/null
+++ b/includes/js/dojo/_base/_loader/bootstrap.js
@@ -0,0 +1,436 @@
+/*=====
+// note:
+// 'djConfig' does not exist under 'dojo.*' so that it can be set before the
+// 'dojo' variable exists.
+// note:
+// Setting any of these variables *after* the library has loaded does
+// nothing at all.
+
+djConfig = {
+ // summary:
+ // Application code can set the global 'djConfig' prior to loading
+ // the library to override certain global settings for how dojo works.
+ //
+ // isDebug: Boolean
+ // Defaults to `false`. If set to `true`, ensures that Dojo provides
+ // extende debugging feedback via Firebug. If Firebug is not available
+ // on your platform, setting `isDebug` to `true` will force Dojo to
+ // pull in (and display) the version of Firebug Lite which is
+ // integrated into the Dojo distribution, thereby always providing a
+ // debugging/logging console when `isDebug` is enabled. Note that
+ // Firebug's `console.*` methods are ALWAYS defined by Dojo. If
+ // `isDebug` is false and you are on a platform without Firebug, these
+ // methods will be defined as no-ops.
+ isDebug: false,
+ // debugAtAllCosts: Boolean
+ // Defaults to `false`. If set to `true`, this triggers an alternate
+ // mode of the package system in which dependencies are detected and
+ // only then are resources evaluated in dependency order via
+ // `<script>` tag inclusion. This may double-request resources and
+ // cause problems with scripts which expect `dojo.require()` to
+ // preform synchronously. `debugAtAllCosts` can be an invaluable
+ // debugging aid, but when using it, ensure that all code which
+ // depends on Dojo modules is wrapped in `dojo.addOnLoad()` handlers.
+ // Due to the somewhat unpredictable side-effects of using
+ // `debugAtAllCosts`, it is strongly recommended that you enable this
+ // flag as a last resort. `debugAtAllCosts` has no effect when loading
+ // resources across domains. For usage information, see the
+ // [Dojo Book](http://dojotoolkit.org/book/book-dojo/part-4-meta-dojo-making-your-dojo-code-run-faster-and-better/debugging-facilities/deb)
+ debugAtAllCosts: false,
+ // locale: String
+ // The locale to assume for loading localized resources in this page,
+ // specified according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt).
+ // Must be specified entirely in lowercase, e.g. `en-us` and `zh-cn`.
+ // See the documentation for `dojo.i18n` and `dojo.requireLocalization`
+ // for details on loading localized resources. If no locale is specified,
+ // Dojo assumes the locale of the user agent, according to `navigator.userLanguage`
+ // or `navigator.language` properties.
+ locale: undefined,
+ // extraLocale: Array
+ // No default value. Specifies additional locales whose
+ // resources should also be loaded alongside the default locale when
+ // calls to `dojo.requireLocalization()` are processed.
+ extraLocale: undefined,
+ // baseUrl: String
+ // The directory in which `dojo.js` is located. Under normal
+ // conditions, Dojo auto-detects the correct location from which it
+ // was loaded. You may need to manually configure `baseUrl` in cases
+ // where you have renamed `dojo.js` or in which `<base>` tags confuse
+ // some browsers (e.g., IE 6). The variable `dojo.baseUrl` is assigned
+ // either the value of `djConfig.baseUrl` if one is provided or the
+ // auto-detected root if not. Other modules are located relative to
+ // this path.
+ baseUrl: undefined,
+ // modulePaths: Object
+ // A map of module names to paths relative to `dojo.baseUrl`. The
+ // key/value pairs correspond directly to the arguments which
+ // `dojo.registerModulePath` accepts. Specifiying
+ // `djConfig.modulePaths = { "foo": "../../bar" }` is the equivalent
+ // of calling `dojo.registerModulePath("foo", "../../bar");`. Multiple
+ // modules may be configured via `djConfig.modulePaths`.
+ modulePaths: {},
+}
+=====*/
+
+(function(){
+ // firebug stubs
+
+ // if((!this["console"])||(!console["firebug"])){
+
+ if(!this["console"]){
+ this.console = {
+ log: function(){} // no-op
+ };
+ }
+
+ var cn = [
+ "assert", "count", "debug", "dir", "dirxml", "error", "group",
+ "groupEnd", "info", "profile", "profileEnd", "time", "timeEnd",
+ "trace", "warn", "log"
+ ];
+ var i=0, tn;
+ while((tn=cn[i++])){
+ if(!console[tn]){
+ (function(){
+ var tcn = tn+"";
+ console[tcn] = function(){
+ var a = Array.apply({}, arguments);
+ a.unshift(tcn+":");
+ console.log(a.join(" "));
+ }
+ })();
+ }
+ }
+
+ //TODOC: HOW TO DOC THIS?
+ // dojo is the root variable of (almost all) our public symbols -- make sure it is defined.
+ if(typeof dojo == "undefined"){
+ this.dojo = {
+ _scopeName: "dojo",
+ _scopePrefix: "",
+ _scopePrefixArgs: "",
+ _scopeSuffix: "",
+ _scopeMap: {},
+ _scopeMapRev: {}
+ };
+ }
+
+ var d = dojo;
+
+ //Need placeholders for dijit and dojox for scoping code.
+ if(typeof dijit == "undefined"){
+ this.dijit = {_scopeName: "dijit"};
+ }
+ if(typeof dojox == "undefined"){
+ this.dojox = {_scopeName: "dojox"};
+ }
+
+ if(!d._scopeArgs){
+ d._scopeArgs = [dojo, dijit, dojox];
+ }
+
+/*=====
+dojo.global = {
+ // summary:
+ // Alias for the global scope
+ // (e.g. the window object in a browser).
+ // description:
+ // Refer to 'dojo.global' rather than referring to window to ensure your
+ // code runs correctly in contexts other than web browsers (e.g. Rhino on a server).
+}
+=====*/
+ d.global = this;
+
+ d.config =/*===== djConfig = =====*/{
+ isDebug: false,
+ debugAtAllCosts: false
+ };
+
+ if(typeof djConfig != "undefined"){
+ for(var opt in djConfig){
+ d.config[opt] = djConfig[opt];
+ }
+ }
+
+ var _platforms = ["Browser", "Rhino", "Spidermonkey", "Mobile"];
+ var t;
+ while((t=_platforms.shift())){
+ d["is"+t] = false;
+ }
+
+/*=====
+ // Override locale setting, if specified
+ dojo.locale = {
+ // summary: the locale as defined by Dojo (read-only)
+ };
+=====*/
+ dojo.locale = d.config.locale;
+
+ var rev = "$Rev: 13707 $".match(/\d+/);
+
+ dojo.version = {
+ // summary:
+ // version number of dojo
+ // major: Integer
+ // Major version. If total version is "1.2.0beta1", will be 1
+ // minor: Integer
+ // Minor version. If total version is "1.2.0beta1", will be 2
+ // patch: Integer
+ // Patch version. If total version is "1.2.0beta1", will be 0
+ // flag: String
+ // Descriptor flag. If total version is "1.2.0beta1", will be "beta1"
+ // revision: Number
+ // The SVN rev from which dojo was pulled
+ major: 1, minor: 1, patch: 1, flag: "",
+ revision: rev ? +rev[0] : 999999, //FIXME: use NaN?
+ toString: function(){
+ with(d.version){
+ return major + "." + minor + "." + patch + flag + " (" + revision + ")"; // String
+ }
+ }
+ }
+
+ // Register with the OpenAjax hub
+ if(typeof OpenAjax != "undefined"){
+ OpenAjax.hub.registerLibrary(dojo._scopeName, "http://dojotoolkit.org", d.version.toString());
+ }
+
+ dojo._mixin = function(/*Object*/ obj, /*Object*/ props){
+ // summary:
+ // Adds all properties and methods of props to obj. This addition
+ // is "prototype extension safe", so that instances of objects
+ // will not pass along prototype defaults.
+ var tobj = {};
+ for(var x in props){
+ // the "tobj" condition avoid copying properties in "props"
+ // inherited from Object.prototype. For example, if obj has a custom
+ // toString() method, don't overwrite it with the toString() method
+ // that props inherited from Object.prototype
+ if(tobj[x] === undefined || tobj[x] != props[x]){
+ obj[x] = props[x];
+ }
+ }
+ // IE doesn't recognize custom toStrings in for..in
+ if(d["isIE"] && props){
+ var p = props.toString;
+ if(typeof p == "function" && p != obj.toString && p != tobj.toString &&
+ p != "\nfunction toString() {\n [native code]\n}\n"){
+ obj.toString = props.toString;
+ }
+ }
+ return obj; // Object
+ }
+
+ dojo.mixin = function(/*Object*/obj, /*Object...*/props){
+ // summary:
+ // Adds all properties and methods of props to obj and returns the
+ // (now modified) obj.
+ // description:
+ // `dojo.mixin` can mix multiple source objects into a
+ // destionation object which is then returned. Unlike regular
+ // `for...in` iteration, `dojo.mixin` is also smart about avoiding
+ // extensions which other toolkits may unwisely add to the root
+ // object prototype
+ // obj:
+ // The object to mix properties into. Also the return value.
+ // props:
+ // One or more objects whose values are successively copied into
+ // obj. If more than one of these objects contain the same value,
+ // the one specified last in the function call will "win".
+ // example:
+ // make a shallow copy of an object
+ // | var copy = dojo.mixin({}, source);
+ // example:
+ // many class constructors often take an object which specifies
+ // values to be configured on the object. In this case, it is
+ // often simplest to call `dojo.mixin` on the `this` object:
+ // | dojo.declare("acme.Base", null, {
+ // | constructor: function(properties){
+ // | // property configuration:
+ // | dojo.mixin(this, properties);
+ // |
+ // | console.debug(this.quip);
+ // | // ...
+ // | },
+ // | quip: "I wasn't born yesterday, you know - I've seen movies.",
+ // | // ...
+ // | });
+ // |
+ // | // create an instance of the class and configure it
+ // | var b = new acme.Base({quip: "That's what it does!" });
+ // example:
+ // copy in properties from multiple objects
+ // | var flattened = dojo.mixin(
+ // | {
+ // | name: "Frylock",
+ // | braces: true,
+ // | }
+ // | {
+ // | name: "Carl Brutanananadilewski"
+ // | }
+ // | );
+ // |
+ // | // will print "Carl Brutanananadilewski"
+ // | console.debug(flattened.name);
+ // | // will print "true"
+ // | console.debug(flattened.braces);
+ for(var i=1, l=arguments.length; i<l; i++){
+ d._mixin(obj, arguments[i]);
+ }
+ return obj; // Object
+ }
+
+ dojo._getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){
+ var obj=context || d.global;
+ for(var i=0, p; obj && (p=parts[i]); i++){
+ if(i == 0 && this._scopeMap[p]){
+ p = this._scopeMap[p];
+ }
+ obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined));
+ }
+ return obj; // mixed
+ }
+
+ dojo.setObject = function(/*String*/name, /*Object*/value, /*Object?*/context){
+ // summary:
+ // Set a property from a dot-separated string, such as "A.B.C"
+ // description:
+ // Useful for longer api chains where you have to test each object in
+ // the chain, or when you have an object reference in string format.
+ // Objects are created as needed along `path`. Returns the passed
+ // value if setting is successful or `undefined` if not.
+ // name:
+ // Path to a property, in the form "A.B.C".
+ // context:
+ // Optional. Object to use as root of path. Defaults to
+ // `dojo.global`.
+ // example:
+ // set the value of `foo.bar.baz`, regardless of whether
+ // intermediate objects already exist:
+ // | dojo.setObject("foo.bar.baz", value);
+ // example:
+ // without `dojo.setObject`, we often see code like this:
+ // | // ensure that intermediate objects are available
+ // | if(!obj["parent"]){ obj.parent = {}; }
+ // | if(!obj.parent["child"]){ obj.parent.child= {}; }
+ // | // now we can safely set the property
+ // | obj.parent.child.prop = "some value";
+ // wheras with `dojo.setObject`, we can shorten that to:
+ // | dojo.setObject("parent.child.prop", "some value", obj);
+ var parts=name.split("."), p=parts.pop(), obj=d._getProp(parts, true, context);
+ return obj && p ? (obj[p]=value) : undefined; // Object
+ }
+
+ dojo.getObject = function(/*String*/name, /*Boolean*/create, /*Object*/context){
+ // summary:
+ // Get a property from a dot-separated string, such as "A.B.C"
+ // description:
+ // Useful for longer api chains where you have to test each object in
+ // the chain, or when you have an object reference in string format.
+ // name:
+ // Path to an property, in the form "A.B.C".
+ // context:
+ // Optional. Object to use as root of path. Defaults to
+ // 'dojo.global'. Null may be passed.
+ // create:
+ // Optional. Defaults to `false`. If `true`, Objects will be
+ // created at any point along the 'path' that is undefined.
+ return d._getProp(name.split("."), create, context); // Object
+ }
+
+ dojo.exists = function(/*String*/name, /*Object?*/obj){
+ // summary:
+ // determine if an object supports a given method
+ // description:
+ // useful for longer api chains where you have to test each object in
+ // the chain
+ // name:
+ // Path to an object, in the form "A.B.C".
+ // obj:
+ // Object to use as root of path. Defaults to
+ // 'dojo.global'. Null may be passed.
+ // example:
+ // | // define an object
+ // | var foo = {
+ // | bar: { }
+ // | };
+ // |
+ // | // search the global scope
+ // | dojo.exists("foo.bar"); // true
+ // | dojo.exists("foo.bar.baz"); // false
+ // |
+ // | // search from a particular scope
+ // | dojo.exists("bar", foo); // true
+ // | dojo.exists("bar.baz", foo); // false
+ return !!d.getObject(name, false, obj); // Boolean
+ }
+
+
+ dojo["eval"] = function(/*String*/ scriptFragment){
+ // summary:
+ // Perform an evaluation in the global scope. Use this rather than
+ // calling 'eval()' directly.
+ // description:
+ // Placed in a separate function to minimize size of trapped
+ // exceptions. Calling eval() directly from some other scope may
+ // complicate tracebacks on some platforms.
+ // return:
+ // The result of the evaluation. Often `undefined`
+
+
+ // note:
+ // - JSC eval() takes an optional second argument which can be 'unsafe'.
+ // - Mozilla/SpiderMonkey eval() takes an optional second argument which is the
+ // scope object for new symbols.
+
+ // FIXME: investigate Joseph Smarr's technique for IE:
+ // http://josephsmarr.com/2007/01/31/fixing-eval-to-use-global-scope-in-ie/
+ // see also:
+ // http://trac.dojotoolkit.org/ticket/744
+ return d.global.eval ? d.global.eval(scriptFragment) : eval(scriptFragment); // Object
+ }
+
+ /*=====
+ dojo.deprecated = function(behaviour, extra, removal){
+ // summary:
+ // Log a debug message to indicate that a behavior has been
+ // deprecated.
+ // behaviour: String
+ // The API or behavior being deprecated. Usually in the form
+ // of "myApp.someFunction()".
+ // extra: String?
+ // Text to append to the message. Often provides advice on a
+ // new function or facility to achieve the same goal during
+ // the deprecation period.
+ // removal: String?
+ // Text to indicate when in the future the behavior will be
+ // removed. Usually a version number.
+ // example:
+ // | dojo.deprecated("myApp.getTemp()", "use myApp.getLocaleTemp() instead", "1.0");
+ }
+
+ dojo.experimental = function(moduleName, extra){
+ // summary: Marks code as experimental.
+ // description:
+ // This can be used to mark a function, file, or module as
+ // experimental. Experimental code is not ready to be used, and the
+ // APIs are subject to change without notice. Experimental code may be
+ // completed deleted without going through the normal deprecation
+ // process.
+ // moduleName: String
+ // The name of a module, or the name of a module file or a specific
+ // function
+ // extra: String?
+ // some additional message for the user
+ // example:
+ // | dojo.experimental("dojo.data.Result");
+ // example:
+ // | dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA");
+ }
+ =====*/
+
+ //Real functions declared in dojo._firebug.firebug.
+ d.deprecated = d.experimental = function(){};
+
+})();
+// vim:ai:ts=4:noet
diff --git a/includes/js/dojo/_base/_loader/hostenv_browser.js b/includes/js/dojo/_base/_loader/hostenv_browser.js
new file mode 100644
index 0000000..f508830
--- /dev/null
+++ b/includes/js/dojo/_base/_loader/hostenv_browser.js
@@ -0,0 +1,379 @@
+/*=====
+dojo.isBrowser = {
+ // example:
+ // | if(dojo.isBrowser){ ... }
+};
+
+dojo.isFF = {
+ // example:
+ // | if(dojo.isFF > 1){ ... }
+};
+
+dojo.isIE = {
+ // example:
+ // | if(dojo.isIE > 6){
+ // | // we are IE7
+ // | }
+};
+
+dojo.isSafari = {
+ // example:
+ // | if(dojo.isSafari){ ... }
+ // example:
+ // Detect iPhone:
+ // | if(dojo.isSafari && (navigator.userAgent.indexOf("iPhone") < 0)){
+ // | // we are iPhone. iPod touch reports "iPod" above
+ // | }
+};
+
+dojo = {
+ // isBrowser: Boolean
+ // True if the client is a web-browser
+ isBrowser: true,
+ // isFF: Number
+ // Greater than zero if client is FireFox. 0 otherwise. Corresponds to
+ // major detected FireFox version (1.5, 2, 3, etc.)
+ isFF: 2,
+ // isIE: Number
+ // Greater than zero if client is MSIE(PC). 0 otherwise. Corresponds to
+ // major detected IE version (6, 7, 8, etc.)
+ isIE: 6,
+ // isKhtml: Number
+ // Greater than zero if client is a KTHML-derived browser (Konqueror,
+ // Safari, etc.). 0 otherwise. Corresponds to major detected version.
+ isKhtml: 0,
+ // isMozilla: Number
+ // Greater than zero if client is a Mozilla-based browser (Firefox,
+ // SeaMonkey). 0 otherwise. Corresponds to major detected version.
+ isMozilla: 0,
+ // isOpera: Number
+ // Greater than zero if client is Opera. 0 otherwise. Corresponds to
+ // major detected version.
+ isOpera: 0,
+ // isSafari: Number
+ // Greater than zero if client is Safari or iPhone. 0 otherwise.
+ isSafari: 0
+}
+=====*/
+
+if(typeof window != 'undefined'){
+ dojo.isBrowser = true;
+ dojo._name = "browser";
+
+
+ // attempt to figure out the path to dojo if it isn't set in the config
+ (function(){
+ var d = dojo;
+ // this is a scope protection closure. We set browser versions and grab
+ // the URL we were loaded from here.
+
+ // grab the node we were loaded from
+ if(document && document.getElementsByTagName){
+ var scripts = document.getElementsByTagName("script");
+ var rePkg = /dojo(\.xd)?\.js(\W|$)/i;
+ for(var i = 0; i < scripts.length; i++){
+ var src = scripts[i].getAttribute("src");
+ if(!src){ continue; }
+ var m = src.match(rePkg);
+ if(m){
+ // find out where we came from
+ if(!d.config.baseUrl){
+ d.config.baseUrl = src.substring(0, m.index);
+ }
+ // and find out if we need to modify our behavior
+ var cfg = scripts[i].getAttribute("djConfig");
+ if(cfg){
+ var cfgo = eval("({ "+cfg+" })");
+ for(var x in cfgo){
+ dojo.config[x] = cfgo[x];
+ }
+ }
+ break; // "first Dojo wins"
+ }
+ }
+ }
+ d.baseUrl = d.config.baseUrl;
+
+ // fill in the rendering support information in dojo.render.*
+ var n = navigator;
+ var dua = n.userAgent;
+ var dav = n.appVersion;
+ var tv = parseFloat(dav);
+
+ d.isOpera = (dua.indexOf("Opera") >= 0) ? tv : 0;
+ // safari detection derived from:
+ // http://developer.apple.com/internet/safari/faq.html#anchor2
+ // http://developer.apple.com/internet/safari/uamatrix.html
+ var idx = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0);
+ if(idx){
+ // try to grab the explicit Safari version first. If we don't get
+ // one, look for 419.3+ as the indication that we're on something
+ // "Safari 3-ish". Lastly, default to "Safari 2" handling.
+ d.isSafari = parseFloat(dav.split("Version/")[1]) || ( ( parseFloat(dav.substr(idx+7)) >= 419.3 ) ? 3 : 2 ) || 2;
+ }
+ d.isAIR = (dua.indexOf("AdobeAIR") >= 0) ? 1 : 0;
+ d.isKhtml = (dav.indexOf("Konqueror") >= 0 || d.isSafari) ? tv : 0;
+ d.isMozilla = d.isMoz = (dua.indexOf("Gecko") >= 0 && !d.isKhtml) ? tv : 0;
+ d.isFF = d.isIE = 0;
+ if(d.isMoz){
+ d.isFF = parseFloat(dua.split("Firefox/")[1]) || 0;
+ }
+ if(document.all && !d.isOpera){
+ d.isIE = parseFloat(dav.split("MSIE ")[1]) || 0;
+ }
+
+ //Workaround to get local file loads of dojo to work on IE 7
+ //by forcing to not use native xhr.
+ if(dojo.isIE && window.location.protocol === "file:"){
+ dojo.config.ieForceActiveXXhr=true;
+ }
+
+ var cm = document.compatMode;
+ d.isQuirks = cm == "BackCompat" || cm == "QuirksMode" || d.isIE < 6;
+
+ // TODO: is the HTML LANG attribute relevant?
+ d.locale = dojo.config.locale || (d.isIE ? n.userLanguage : n.language).toLowerCase();
+
+ // These are in order of decreasing likelihood; this will change in time.
+ d._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
+
+ d._xhrObj = function(){
+ // summary:
+ // does the work of portably generating a new XMLHTTPRequest
+ // object.
+ var http = null;
+ var last_e = null;
+ if(!dojo.isIE || !dojo.config.ieForceActiveXXhr){
+ try{ http = new XMLHttpRequest(); }catch(e){}
+ }
+ if(!http){
+ for(var i=0; i<3; ++i){
+ var progid = d._XMLHTTP_PROGIDS[i];
+ try{
+ http = new ActiveXObject(progid);
+ }catch(e){
+ last_e = e;
+ }
+
+ if(http){
+ d._XMLHTTP_PROGIDS = [progid]; // so faster next time
+ break;
+ }
+ }
+ }
+
+ if(!http){
+ throw new Error("XMLHTTP not available: "+last_e);
+ }
+
+ return http; // XMLHTTPRequest instance
+ }
+
+ d._isDocumentOk = function(http){
+ var stat = http.status || 0;
+ return (stat >= 200 && stat < 300) || // Boolean
+ stat == 304 || // allow any 2XX response code
+ stat == 1223 || // get it out of the cache
+ (!stat && (location.protocol=="file:" || location.protocol=="chrome:") ); // Internet Explorer mangled the status code
+ }
+
+ //See if base tag is in use.
+ //This is to fix http://trac.dojotoolkit.org/ticket/3973,
+ //but really, we need to find out how to get rid of the dojo._Url reference
+ //below and still have DOH work with the dojo.i18n test following some other
+ //test that uses the test frame to load a document (trac #2757).
+ //Opera still has problems, but perhaps a larger issue of base tag support
+ //with XHR requests (hasBase is true, but the request is still made to document
+ //path, not base path).
+ var owloc = window.location+"";
+ var base = document.getElementsByTagName("base");
+ var hasBase = (base && base.length > 0);
+
+ d._getText = function(/*URI*/ uri, /*Boolean*/ fail_ok){
+ // summary: Read the contents of the specified uri and return those contents.
+ // uri:
+ // A relative or absolute uri. If absolute, it still must be in
+ // the same "domain" as we are.
+ // fail_ok:
+ // Default false. If fail_ok and loading fails, return null
+ // instead of throwing.
+ // returns: The response text. null is returned when there is a
+ // failure and failure is okay (an exception otherwise)
+
+ // alert("_getText: " + uri);
+
+ // NOTE: must be declared before scope switches ie. this._xhrObj()
+ var http = this._xhrObj();
+
+ if(!hasBase && dojo._Url){
+ uri = (new dojo._Url(owloc, uri)).toString();
+ }
+ /*
+ console.debug("_getText:", uri);
+ console.debug(window.location+"");
+ alert(uri);
+ */
+
+ if(d.config.cacheBust){
+ uri += (uri.indexOf("?") == -1 ? "?" : "&") + String(d.config.cacheBust).replace(/\W+/g,"");
+ }
+
+ http.open('GET', uri, false);
+ try{
+ http.send(null);
+ // alert(http);
+ if(!d._isDocumentOk(http)){
+ var err = Error("Unable to load "+uri+" status:"+ http.status);
+ err.status = http.status;
+ err.responseText = http.responseText;
+ throw err;
+ }
+ }catch(e){
+ if(fail_ok){ return null; } // null
+ // rethrow the exception
+ throw e;
+ }
+ return http.responseText; // String
+ }
+ })();
+
+ dojo._initFired = false;
+ // BEGIN DOMContentLoaded, from Dean Edwards (http://dean.edwards.name/weblog/2006/06/again/)
+ dojo._loadInit = function(e){
+ dojo._initFired = true;
+ // allow multiple calls, only first one will take effect
+ // A bug in khtml calls events callbacks for document for event which isnt supported
+ // for example a created contextmenu event calls DOMContentLoaded, workaround
+ var type = (e && e.type) ? e.type.toLowerCase() : "load";
+ if(arguments.callee.initialized || (type != "domcontentloaded" && type != "load")){ return; }
+ arguments.callee.initialized = true;
+ if("_khtmlTimer" in dojo){
+ clearInterval(dojo._khtmlTimer);
+ delete dojo._khtmlTimer;
+ }
+
+ if(dojo._inFlightCount == 0){
+ dojo._modulesLoaded();
+ }
+ }
+
+ dojo._fakeLoadInit = function(){
+ dojo._loadInit({type: "load"});
+ }
+
+ if(!dojo.config.afterOnLoad){
+ // START DOMContentLoaded
+ // Mozilla and Opera 9 expose the event we could use
+ if(document.addEventListener){
+ // NOTE:
+ // due to a threading issue in Firefox 2.0, we can't enable
+ // DOMContentLoaded on that platform. For more information, see:
+ // http://trac.dojotoolkit.org/ticket/1704
+ if(dojo.isOpera || dojo.isFF >= 3 || (dojo.isMoz && dojo.config.enableMozDomContentLoaded === true)){
+ document.addEventListener("DOMContentLoaded", dojo._loadInit, null);
+ }
+
+ // mainly for Opera 8.5, won't be fired if DOMContentLoaded fired already.
+ // also used for Mozilla because of trac #1640
+ window.addEventListener("load", dojo._loadInit, null);
+ }
+
+ if(dojo.isAIR){
+ window.addEventListener("load", dojo._loadInit, null);
+ }else if(/(WebKit|khtml)/i.test(navigator.userAgent)){ // sniff
+ dojo._khtmlTimer = setInterval(function(){
+ if(/loaded|complete/.test(document.readyState)){
+ dojo._loadInit(); // call the onload handler
+ }
+ }, 10);
+ }
+ // END DOMContentLoaded
+ }
+
+ (function(){
+ var _w = window;
+ var _handleNodeEvent = function(/*String*/evtName, /*Function*/fp){
+ // summary:
+ // non-destructively adds the specified function to the node's
+ // evtName handler.
+ // evtName: should be in the form "onclick" for "onclick" handlers.
+ // Make sure you pass in the "on" part.
+ var oldHandler = _w[evtName] || function(){};
+ _w[evtName] = function(){
+ fp.apply(_w, arguments);
+ oldHandler.apply(_w, arguments);
+ };
+ };
+
+ if(dojo.isIE){
+ // for Internet Explorer. readyState will not be achieved on init
+ // call, but dojo doesn't need it however, we'll include it
+ // because we don't know if there are other functions added that
+ // might. Note that this has changed because the build process
+ // strips all comments -- including conditional ones.
+ if(!dojo.config.afterOnLoad){
+ document.write('<scr'+'ipt defer src="//:" '
+ + 'onreadystatechange="if(this.readyState==\'complete\'){' + dojo._scopeName + '._loadInit();}">'
+ + '</scr'+'ipt>'
+ );
+ }
+
+ // IE WebControl hosted in an application can fire "beforeunload" and "unload"
+ // events when control visibility changes, causing Dojo to unload too soon. The
+ // following code fixes the problem
+ // Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;199155
+ var _unloading = true;
+ _handleNodeEvent("onbeforeunload", function(){
+ _w.setTimeout(function(){ _unloading = false; }, 0);
+ });
+ _handleNodeEvent("onunload", function(){
+ if(_unloading){ dojo.unloaded(); }
+ });
+
+ try{
+ document.namespaces.add("v","urn:schemas-microsoft-com:vml");
+ document.createStyleSheet().addRule("v\\:*", "behavior:url(#default#VML)");
+ }catch(e){}
+ }else{
+ // FIXME: dojo.unloaded requires dojo scope, so using anon function wrapper.
+ _handleNodeEvent("onbeforeunload", function() { dojo.unloaded(); });
+ }
+
+ })();
+
+ /*
+ OpenAjax.subscribe("OpenAjax", "onload", function(){
+ if(dojo._inFlightCount == 0){
+ dojo._modulesLoaded();
+ }
+ });
+
+ OpenAjax.subscribe("OpenAjax", "onunload", function(){
+ dojo.unloaded();
+ });
+ */
+} //if (typeof window != 'undefined')
+
+//Register any module paths set up in djConfig. Need to do this
+//in the hostenvs since hostenv_browser can read djConfig from a
+//script tag's attribute.
+(function(){
+ var mp = dojo.config["modulePaths"];
+ if(mp){
+ for(var param in mp){
+ dojo.registerModulePath(param, mp[param]);
+ }
+ }
+})();
+
+//Load debug code if necessary.
+if(dojo.config.isDebug){
+ dojo.require("dojo._firebug.firebug");
+}
+
+if(dojo.config.debugAtAllCosts){
+ dojo.config.useXDomain = true;
+ dojo.require("dojo._base._loader.loader_xd");
+ dojo.require("dojo._base._loader.loader_debug");
+ dojo.require("dojo.i18n");
+}
diff --git a/includes/js/dojo/_base/_loader/hostenv_rhino.js b/includes/js/dojo/_base/_loader/hostenv_rhino.js
new file mode 100644
index 0000000..d363861
--- /dev/null
+++ b/includes/js/dojo/_base/_loader/hostenv_rhino.js
@@ -0,0 +1,238 @@
+/*
+* Rhino host environment
+*/
+
+if(dojo.config["baseUrl"]){
+ dojo.baseUrl = dojo.config["baseUrl"];
+}else{
+ dojo.baseUrl = "./";
+}
+
+dojo.locale = dojo.locale || String(java.util.Locale.getDefault().toString().replace('_','-').toLowerCase());
+dojo._name = 'rhino';
+dojo.isRhino = true;
+
+if(typeof print == "function"){
+ console.debug = print;
+}
+
+if(typeof dojo["byId"] == "undefined"){
+ dojo.byId = function(id, doc){
+ if(id && (typeof id == "string" || id instanceof String)){
+ if(!doc){ doc = document; }
+ return doc.getElementById(id);
+ }
+ return id; // assume it's a node
+ }
+}
+
+// see comments in spidermonkey loadUri
+dojo._loadUri = function(uri, cb){
+ try{
+ var local = (new java.io.File(uri)).exists();
+ if(!local){
+ try{
+ // try it as a file first, URL second
+ var stream = (new java.net.URL(uri)).openStream();
+ // close the stream so we don't leak resources
+ stream.close();
+ }catch(e){
+ // no debug output; this failure just means the uri was not found.
+ return false;
+ }
+ }
+ //FIXME: Use Rhino 1.6 native readFile/readUrl if available?
+ if(cb){
+ var contents = (local ? readText : readUri)(uri, "UTF-8");
+ cb(eval('('+contents+')'));
+ }else{
+ load(uri);
+ }
+ return true;
+ }catch(e){
+ console.debug("rhino load('" + uri + "') failed. Exception: " + e);
+ return false;
+ }
+}
+
+dojo.exit = function(exitcode){
+ quit(exitcode);
+}
+
+// Hack to determine current script...
+//
+// These initial attempts failed:
+// 1. get an EcmaError and look at e.getSourceName(): try {eval ("static in return")} catch(e) { ...
+// Won't work because NativeGlobal.java only does a put of "name" and "message", not a wrapped reflecting object.
+// Even if the EcmaError object had the sourceName set.
+//
+// 2. var e = Packages.org.mozilla.javascript.Context.getCurrentContext().reportError('');
+// Won't work because it goes directly to the errorReporter, not the return value.
+// We want context.interpreterSourceFile and context.interpreterLine, which are used in static Context.getSourcePositionFromStack
+// (set by Interpreter.java at interpretation time, if in interpreter mode).
+//
+// 3. var e = Packages.org.mozilla.javascript.Context.getCurrentContext().reportRuntimeError('');
+// This returns an object, but e.message still does not have source info.
+// In compiler mode, perhaps not set; in interpreter mode, perhaps not used by errorReporter?
+//
+// What we found works is to do basically the same hack as is done in getSourcePositionFromStack,
+// making a new java.lang.Exception() and then calling printStackTrace on a string stream.
+// We have to parse the string for the .js files (different from the java files).
+// This only works however in compiled mode (-opt 0 or higher).
+// In interpreter mode, entire stack is java.
+// When compiled, printStackTrace is like:
+// java.lang.Exception
+// at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
+// at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
+// at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
+// at java.lang.reflect.Constructor.newInstance(Constructor.java:274)
+// at org.mozilla.javascript.NativeJavaClass.constructSpecific(NativeJavaClass.java:228)
+// at org.mozilla.javascript.NativeJavaClass.construct(NativeJavaClass.java:185)
+// at org.mozilla.javascript.ScriptRuntime.newObject(ScriptRuntime.java:1269)
+// at org.mozilla.javascript.gen.c2.call(/Users/mda/Sites/burstproject/testrhino.js:27)
+// ...
+// at org.mozilla.javascript.tools.shell.Main.main(Main.java:76)
+//
+// Note may get different answers based on:
+// Context.setOptimizationLevel(-1)
+// Context.setGeneratingDebug(true)
+// Context.setGeneratingSource(true)
+//
+// Some somewhat helpful posts:
+// http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=9v9n0g%246gr1%40ripley.netscape.com
+// http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=3BAA2DC4.6010702%40atg.com
+//
+// Note that Rhino1.5R5 added source name information in some exceptions.
+// But this seems not to help in command-line Rhino, because Context.java has an error reporter
+// so no EvaluationException is thrown.
+
+// do it by using java java.lang.Exception
+dojo._rhinoCurrentScriptViaJava = function(depth){
+ var optLevel = Packages.org.mozilla.javascript.Context.getCurrentContext().getOptimizationLevel();
+ var caw = new java.io.CharArrayWriter();
+ var pw = new java.io.PrintWriter(caw);
+ var exc = new java.lang.Exception();
+ var s = caw.toString();
+ // we have to exclude the ones with or without line numbers because they put double entries in:
+ // at org.mozilla.javascript.gen.c3._c4(/Users/mda/Sites/burstproject/burst/Runtime.js:56)
+ // at org.mozilla.javascript.gen.c3.call(/Users/mda/Sites/burstproject/burst/Runtime.js)
+ var matches = s.match(/[^\(]*\.js\)/gi);
+ if(!matches){
+ throw Error("cannot parse printStackTrace output: " + s);
+ }
+
+ // matches[0] is entire string, matches[1] is this function, matches[2] is caller, ...
+ var fname = ((typeof depth != 'undefined')&&(depth)) ? matches[depth + 1] : matches[matches.length - 1];
+ var fname = matches[3];
+ if(!fname){ fname = matches[1]; }
+ // print("got fname '" + fname + "' from stack string '" + s + "'");
+ if (!fname){ throw Error("could not find js file in printStackTrace output: " + s); }
+ //print("Rhino getCurrentScriptURI returning '" + fname + "' from: " + s);
+ return fname;
+}
+
+// reading a file from disk in Java is a humiliating experience by any measure.
+// Lets avoid that and just get the freaking text
+function readText(path, encoding){
+ encoding = encoding || "utf-8";
+ // NOTE: we intentionally avoid handling exceptions, since the caller will
+ // want to know
+ var jf = new java.io.File(path);
+ var is = new java.io.FileInputStream(jf);
+ return dj_readInputStream(is, encoding);
+}
+
+function readUri(uri, encoding){
+ var conn = (new java.net.URL(uri)).openConnection();
+ encoding = encoding || conn.getContentEncoding() || "utf-8";
+ var is = conn.getInputStream();
+ return dj_readInputStream(is, encoding);
+}
+
+function dj_readInputStream(is, encoding){
+ var input = new java.io.BufferedReader(new java.io.InputStreamReader(is, encoding));
+ try {
+ var sb = new java.lang.StringBuffer();
+ var line = "";
+ while((line = input.readLine()) !== null){
+ sb.append(line);
+ sb.append(java.lang.System.getProperty("line.separator"));
+ }
+ return sb.toString();
+ } finally {
+ input.close();
+ }
+}
+
+// call this now because later we may not be on the top of the stack
+if(
+ (!dojo.config.libraryScriptUri)||
+ (!dojo.config.libraryScriptUri.length)
+){
+ try{
+ dojo.config.libraryScriptUri = dojo._rhinoCurrentScriptViaJava(1);
+ }catch(e){
+ // otherwise just fake it
+ if(dojo.config["isDebug"]){
+ print("\n");
+ print("we have no idea where Dojo is located.");
+ print("Please try loading rhino in a non-interpreted mode or set a");
+ print("\n\tdjConfig.libraryScriptUri\n");
+ print("Setting the dojo path to './'");
+ print("This is probably wrong!");
+ print("\n");
+ print("Dojo will try to load anyway");
+ }
+ dojo.config.libraryScriptUri = "./";
+ }
+}
+
+// summary:
+// return the document object associated with the dojo.global
+dojo.doc = typeof(document) != "undefined" ? document : null;
+
+dojo.body = function(){
+ return document.body;
+}
+
+dojo._timeouts = [];
+
+function clearTimeout(idx){
+ if(!dojo._timeouts[idx]){ return; }
+ dojo._timeouts[idx].stop();
+}
+
+function setTimeout(func, delay){
+ // summary: provides timed callbacks using Java threads
+
+ var def={
+ sleepTime:delay,
+ hasSlept:false,
+
+ run:function(){
+ if(!this.hasSlept){
+ this.hasSlept=true;
+ java.lang.Thread.currentThread().sleep(this.sleepTime);
+ }
+ try{
+ func();
+ }catch(e){
+ console.debug("Error running setTimeout thread:" + e);
+ }
+ }
+ };
+
+ var runnable = new java.lang.Runnable(def);
+ var thread = new java.lang.Thread(runnable);
+ thread.start();
+ return dojo._timeouts.push(thread)-1;
+}
+
+//Register any module paths set up in djConfig. Need to do this
+//in the hostenvs since hostenv_browser can read djConfig from a
+//script tag's attribute.
+if(dojo.config["modulePaths"]){
+ for(var param in dojo.config["modulePaths"]){
+ dojo.registerModulePath(param, dojo.config["modulePaths"][param]);
+ }
+}
diff --git a/includes/js/dojo/_base/_loader/hostenv_spidermonkey.js b/includes/js/dojo/_base/_loader/hostenv_spidermonkey.js
new file mode 100644
index 0000000..e31539f
--- /dev/null
+++ b/includes/js/dojo/_base/_loader/hostenv_spidermonkey.js
@@ -0,0 +1,80 @@
+/*
+ * SpiderMonkey host environment
+ */
+
+if(dojo.config["baseUrl"]){
+ dojo.baseUrl = dojo.config["baseUrl"];
+}else{
+ dojo.baseUrl = "./";
+}
+
+dojo._name = 'spidermonkey';
+
+/*=====
+dojo.isSpidermonkey = {
+ // summary: Detect spidermonkey
+};
+=====*/
+
+dojo.isSpidermonkey = true;
+dojo.exit = function(exitcode){
+ quit(exitcode);
+}
+
+if(typeof print == "function"){
+ console.debug = print;
+}
+
+if(typeof line2pc == 'undefined'){
+ throw new Error("attempt to use SpiderMonkey host environment when no 'line2pc' global");
+}
+
+dojo._spidermonkeyCurrentFile = function(depth){
+ //
+ // This is a hack that determines the current script file by parsing a
+ // generated stack trace (relying on the non-standard "stack" member variable
+ // of the SpiderMonkey Error object).
+ //
+ // If param depth is passed in, it'll return the script file which is that far down
+ // the stack, but that does require that you know how deep your stack is when you are
+ // calling.
+ //
+ var s = '';
+ try{
+ throw Error("whatever");
+ }catch(e){
+ s = e.stack;
+ }
+ // lines are like: bu_getCurrentScriptURI_spidermonkey("ScriptLoader.js")@burst/Runtime.js:101
+ var matches = s.match(/[^@]*\.js/gi);
+ if(!matches){
+ throw Error("could not parse stack string: '" + s + "'");
+ }
+ var fname = (typeof depth != 'undefined' && depth) ? matches[depth + 1] : matches[matches.length - 1];
+ if(!fname){
+ throw Error("could not find file name in stack string '" + s + "'");
+ }
+ //print("SpiderMonkeyRuntime got fname '" + fname + "' from stack string '" + s + "'");
+ return fname;
+}
+
+// print(dojo._spidermonkeyCurrentFile(0));
+
+dojo._loadUri = function(uri){
+ // spidermonkey load() evaluates the contents into the global scope (which
+ // is what we want).
+ // TODO: sigh, load() does not return a useful value.
+ // Perhaps it is returning the value of the last thing evaluated?
+ var ok = load(uri);
+ // console.debug("spidermonkey load(", uri, ") returned ", ok);
+ return 1;
+}
+
+//Register any module paths set up in djConfig. Need to do this
+//in the hostenvs since hostenv_browser can read djConfig from a
+//script tag's attribute.
+if(dojo.config["modulePaths"]){
+ for(var param in dojo.config["modulePaths"]){
+ dojo.registerModulePath(param, dojo.config["modulePaths"][param]);
+ }
+}
diff --git a/includes/js/dojo/_base/_loader/loader.js b/includes/js/dojo/_base/_loader/loader.js
new file mode 100644
index 0000000..6a16e4f
--- /dev/null
+++ b/includes/js/dojo/_base/_loader/loader.js
@@ -0,0 +1,690 @@
+if(!dojo._hasResource["dojo.foo"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.foo"] = true;
+/*
+ * loader.js - A bootstrap module. Runs before the hostenv_*.js file. Contains
+ * all of the package loading methods.
+ */
+
+(function(){
+ var d = dojo;
+
+ d.mixin(d, {
+ _loadedModules: {},
+ _inFlightCount: 0,
+ _hasResource: {},
+
+ _modulePrefixes: {
+ dojo: { name: "dojo", value: "." },
+ // dojox: { name: "dojox", value: "../dojox" },
+ // dijit: { name: "dijit", value: "../dijit" },
+ doh: { name: "doh", value: "../util/doh" },
+ tests: { name: "tests", value: "tests" }
+ },
+
+ _moduleHasPrefix: function(/*String*/module){
+ // summary: checks to see if module has been established
+ var mp = this._modulePrefixes;
+ return !!(mp[module] && mp[module].value); // Boolean
+ },
+
+ _getModulePrefix: function(/*String*/module){
+ // summary: gets the prefix associated with module
+ var mp = this._modulePrefixes;
+ if(this._moduleHasPrefix(module)){
+ return mp[module].value; // String
+ }
+ return module; // String
+ },
+
+ _loadedUrls: [],
+
+ //WARNING:
+ // This variable is referenced by packages outside of bootstrap:
+ // FloatingPane.js and undo/browser.js
+ _postLoad: false,
+
+ //Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
+ _loaders: [],
+ _unloaders: [],
+ _loadNotifying: false
+ });
+
+
+ dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){
+ // summary:
+ // Load a Javascript module given a relative path
+ //
+ // description:
+ // Loads and interprets the script located at relpath, which is
+ // relative to the script root directory. If the script is found but
+ // its interpretation causes a runtime exception, that exception is
+ // not caught by us, so the caller will see it. We return a true
+ // value if and only if the script is found.
+ //
+ // relpath:
+ // A relative path to a script (no leading '/', and typically ending
+ // in '.js').
+ // module:
+ // A module whose existance to check for after loading a path. Can be
+ // used to determine success or failure of the load.
+ // cb:
+ // a callback function to pass the result of evaluating the script
+
+ var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : this.baseUrl) + relpath;
+ try{
+ return !module ? this._loadUri(uri, cb) : this._loadUriAndCheck(uri, module, cb); // Boolean
+ }catch(e){
+ console.error(e);
+ return false; // Boolean
+ }
+ }
+
+ dojo._loadUri = function(/*String*/uri, /*Function?*/cb){
+ // summary:
+ // Loads JavaScript from a URI
+ // description:
+ // Reads the contents of the URI, and evaluates the contents. This is
+ // used to load modules as well as resource bundles. Returns true if
+ // it succeeded. Returns false if the URI reading failed. Throws if
+ // the evaluation throws.
+ // uri: a uri which points at the script to be loaded
+ // cb:
+ // a callback function to process the result of evaluating the script
+ // as an expression, typically used by the resource bundle loader to
+ // load JSON-style resources
+
+ if(this._loadedUrls[uri]){
+ return true; // Boolean
+ }
+ var contents = this._getText(uri, true);
+ if(!contents){ return false; } // Boolean
+ this._loadedUrls[uri] = true;
+ this._loadedUrls.push(uri);
+ if(cb){
+ contents = '('+contents+')';
+ }else{
+ //Only do the scoping if no callback. If a callback is specified,
+ //it is most likely the i18n bundle stuff.
+ contents = this._scopePrefix + contents + this._scopeSuffix;
+ }
+ if(d.isMoz){ contents += "\r\n//@ sourceURL=" + uri; } // debugging assist for Firebug
+ var value = d["eval"](contents);
+ if(cb){ cb(value); }
+ return true; // Boolean
+ }
+
+ // FIXME: probably need to add logging to this method
+ dojo._loadUriAndCheck = function(/*String*/uri, /*String*/moduleName, /*Function?*/cb){
+ // summary: calls loadUri then findModule and returns true if both succeed
+ var ok = false;
+ try{
+ ok = this._loadUri(uri, cb);
+ }catch(e){
+ console.error("failed loading " + uri + " with error: " + e);
+ }
+ return !!(ok && this._loadedModules[moduleName]); // Boolean
+ }
+
+ dojo.loaded = function(){
+ // summary:
+ // signal fired when initial environment and package loading is
+ // complete. You may use dojo.addOnLoad() or dojo.connect() to
+ // this method in order to handle initialization tasks that
+ // require the environment to be initialized. In a browser host,
+ // declarative widgets will be constructed when this function
+ // finishes runing.
+ this._loadNotifying = true;
+ this._postLoad = true;
+ var mll = d._loaders;
+
+ //Clear listeners so new ones can be added
+ //For other xdomain package loads after the initial load.
+ this._loaders = [];
+
+ for(var x = 0; x < mll.length; x++){
+ try{
+ mll[x]();
+ }catch(e){
+ throw e;
+ console.error("dojo.addOnLoad callback failed: " + e, e); /* let other load events fire, like the parser, but report the error */
+ }
+ }
+
+ this._loadNotifying = false;
+
+ //Make sure nothing else got added to the onload queue
+ //after this first run. If something did, and we are not waiting for any
+ //more inflight resources, run again.
+ if(d._postLoad && d._inFlightCount == 0 && mll.length){
+ d._callLoaded();
+ }
+ }
+
+ dojo.unloaded = function(){
+ // summary:
+ // signal fired by impending environment destruction. You may use
+ // dojo.addOnUnload() or dojo.connect() to this method to perform
+ // page/application cleanup methods.
+ var mll = this._unloaders;
+ while(mll.length){
+ (mll.pop())();
+ }
+ }
+
+ var onto = function(arr, obj, fn){
+ if(!fn){
+ arr.push(obj);
+ }else if(fn){
+ var func = (typeof fn == "string") ? obj[fn] : fn;
+ arr.push(function(){ func.call(obj); });
+ }
+ }
+
+ dojo.addOnLoad = function(/*Object?*/obj, /*String|Function*/functionName){
+ // summary:
+ // Registers a function to be triggered after the DOM has finished
+ // loading and widgets declared in markup have been instantiated.
+ // Images and CSS files may or may not have finished downloading when
+ // the specified function is called. (Note that widgets' CSS and HTML
+ // code is guaranteed to be downloaded before said widgets are
+ // instantiated.)
+ // example:
+ // | dojo.addOnLoad(functionPointer);
+ // | dojo.addOnLoad(object, "functionName");
+ // | dojo.addOnLoad(object, function(){ /* ... */});
+
+ onto(d._loaders, obj, functionName);
+
+ //Added for xdomain loading. dojo.addOnLoad is used to
+ //indicate callbacks after doing some dojo.require() statements.
+ //In the xdomain case, if all the requires are loaded (after initial
+ //page load), then immediately call any listeners.
+ if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){
+ d._callLoaded();
+ }
+ }
+
+ dojo.addOnUnload = function(/*Object?*/obj, /*String|Function?*/functionName){
+ // summary:
+ // registers a function to be triggered when the page unloads
+ // example:
+ // | dojo.addOnUnload(functionPointer)
+ // | dojo.addOnUnload(object, "functionName")
+ // | dojo.addOnUnload(object, function(){ /* ... */});
+
+ onto(d._unloaders, obj, functionName);
+ }
+
+ dojo._modulesLoaded = function(){
+ if(d._postLoad){ return; }
+ if(d._inFlightCount > 0){
+ console.warn("files still in flight!");
+ return;
+ }
+ d._callLoaded();
+ }
+
+ dojo._callLoaded = function(){
+
+ // The "object" check is for IE, and the other opera check fixes an
+ // issue in Opera where it could not find the body element in some
+ // widget test cases. For 0.9, maybe route all browsers through the
+ // setTimeout (need protection still for non-browser environments
+ // though). This might also help the issue with FF 2.0 and freezing
+ // issues where we try to do sync xhr while background css images are
+ // being loaded (trac #2572)? Consider for 0.9.
+ if(typeof setTimeout == "object" || (dojo.config.useXDomain && d.isOpera)){
+ if(dojo.isAIR){
+ setTimeout(function(){dojo.loaded();}, 0);
+ }else{
+ setTimeout(dojo._scopeName + ".loaded();", 0);
+ }
+ }else{
+ d.loaded();
+ }
+ }
+
+ dojo._getModuleSymbols = function(/*String*/modulename){
+ // summary:
+ // Converts a module name in dotted JS notation to an array
+ // representing the path in the source tree
+ var syms = modulename.split(".");
+ for(var i = syms.length; i>0; i--){
+ var parentModule = syms.slice(0, i).join(".");
+ if((i==1) && !this._moduleHasPrefix(parentModule)){
+ // Support default module directory (sibling of dojo) for top-level modules
+ syms[0] = "../" + syms[0];
+ }else{
+ var parentModulePath = this._getModulePrefix(parentModule);
+ if(parentModulePath != parentModule){
+ syms.splice(0, i, parentModulePath);
+ break;
+ }
+ }
+ }
+ // console.debug(syms);
+ return syms; // Array
+ }
+
+ dojo._global_omit_module_check = false;
+
+ dojo._loadModule = dojo.require = function(/*String*/moduleName, /*Boolean?*/omitModuleCheck){
+ // summary:
+ // loads a Javascript module from the appropriate URI
+ // moduleName:
+ // module name to load. Module paths are de-referenced by dojo's
+ // internal mapping of locations to names and are disambiguated by
+ // longest prefix. See `dojo.registerModulePath()` for details on
+ // registering new modules.
+ // omitModuleCheck:
+ // if `true`, omitModuleCheck skips the step of ensuring that the
+ // loaded file actually defines the symbol it is referenced by.
+ // For example if it called as `dojo._loadModule("a.b.c")` and the
+ // file located at `a/b/c.js` does not define an object `a.b.c`,
+ // and exception will be throws whereas no exception is raised
+ // when called as `dojo._loadModule("a.b.c", true)`
+ // description:
+ // `dojo._loadModule("A.B")` first checks to see if symbol A.B is
+ // defined. If it is, it is simply returned (nothing to do).
+ //
+ // If it is not defined, it will look for `A/B.js` in the script root
+ // directory.
+ //
+ // `dojo._loadModule` throws an excpetion if it cannot find a file
+ // to load, or if the symbol `A.B` is not defined after loading.
+ //
+ // It returns the object `A.B`.
+ //
+ // `dojo._loadModule()` does nothing about importing symbols into
+ // the current namespace. It is presumed that the caller will
+ // take care of that. For example, to import all symbols into a
+ // local block, you might write:
+ //
+ // | with (dojo._loadModule("A.B")) {
+ // | ...
+ // | }
+ //
+ // And to import just the leaf symbol to a local variable:
+ //
+ // | var B = dojo._loadModule("A.B");
+ // | ...
+ // returns: the required namespace object
+ omitModuleCheck = this._global_omit_module_check || omitModuleCheck;
+
+ //Check if it is already loaded.
+ var module = this._loadedModules[moduleName];
+ if(module){
+ return module;
+ }
+
+ // convert periods to slashes
+ var relpath = this._getModuleSymbols(moduleName).join("/") + '.js';
+
+ var modArg = (!omitModuleCheck) ? moduleName : null;
+ var ok = this._loadPath(relpath, modArg);
+
+ if(!ok && !omitModuleCheck){
+ throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
+ }
+
+ // check that the symbol was defined
+ // Don't bother if we're doing xdomain (asynchronous) loading.
+ if(!omitModuleCheck && !this._isXDomain){
+ // pass in false so we can give better error
+ module = this._loadedModules[moduleName];
+ if(!module){
+ throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'");
+ }
+ }
+
+ return module;
+ }
+
+ dojo.provide = function(/*String*/ resourceName){
+ // summary:
+ // Each javascript source file must have at least one
+ // `dojo.provide()` call at the top of the file, corresponding to
+ // the file name. For example, `js/dojo/foo.js` must have
+ // `dojo.provide("dojo.foo");` before any calls to
+ // `dojo.require()` are made.
+ // description:
+ // Each javascript source file is called a resource. When a
+ // resource is loaded by the browser, `dojo.provide()` registers
+ // that it has been loaded.
+ //
+ // For backwards compatibility reasons, in addition to registering
+ // the resource, `dojo.provide()` also ensures that the javascript
+ // object for the module exists. For example,
+ // `dojo.provide("dojox.data.FlickrStore")`, in addition to
+ // registering that `FlickrStore.js` is a resource for the
+ // `dojox.data` module, will ensure that the `dojox.data`
+ // javascript object exists, so that calls like
+ // `dojo.data.foo = function(){ ... }` don't fail.
+ //
+ // In the case of a build where multiple javascript source files
+ // are combined into one bigger file (similar to a .lib or .jar
+ // file), that file may contain multiple dojo.provide() calls, to
+ // note that it includes multiple resources.
+
+ //Make sure we have a string.
+ resourceName = resourceName + "";
+ return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object
+ }
+
+ //Start of old bootstrap2:
+
+ dojo.platformRequire = function(/*Object*/modMap){
+ // summary:
+ // require one or more modules based on which host environment
+ // Dojo is currently operating in
+ // description:
+ // This method takes a "map" of arrays which one can use to
+ // optionally load dojo modules. The map is indexed by the
+ // possible dojo.name_ values, with two additional values:
+ // "default" and "common". The items in the "default" array will
+ // be loaded if none of the other items have been choosen based on
+ // dojo.name_, set by your host environment. The items in the
+ // "common" array will *always* be loaded, regardless of which
+ // list is chosen.
+ // example:
+ // | dojo.platformRequire({
+ // | browser: [
+ // | "foo.sample", // simple module
+ // | "foo.test",
+ // | ["foo.bar.baz", true] // skip object check in _loadModule
+ // | ],
+ // | default: [ "foo.sample._base" ],
+ // | common: [ "important.module.common" ]
+ // | });
+
+ var common = modMap.common || [];
+ var result = common.concat(modMap[d._name] || modMap["default"] || []);
+
+ for(var x=0; x<result.length; x++){
+ var curr = result[x];
+ if(curr.constructor == Array){
+ d._loadModule.apply(d, curr);
+ }else{
+ d._loadModule(curr);
+ }
+ }
+ }
+
+ dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){
+ // summary:
+ // If the condition is true then call dojo.require() for the specified
+ // resource
+ if(condition === true){
+ // FIXME: why do we support chained require()'s here? does the build system?
+ var args = [];
+ for(var i = 1; i < arguments.length; i++){
+ args.push(arguments[i]);
+ }
+ d.require.apply(d, args);
+ }
+ }
+
+ dojo.requireAfterIf = d.requireIf;
+
+ dojo.registerModulePath = function(/*String*/module, /*String*/prefix){
+ // summary:
+ // maps a module name to a path
+ // description:
+ // An unregistered module is given the default path of ../[module],
+ // relative to Dojo root. For example, module acme is mapped to
+ // ../acme. If you want to use a different module name, use
+ // dojo.registerModulePath.
+ // example:
+ // If your dojo.js is located at this location in the web root:
+ // | /myapp/js/dojo/dojo/dojo.js
+ // and your modules are located at:
+ // | /myapp/js/foo/bar.js
+ // | /myapp/js/foo/baz.js
+ // | /myapp/js/foo/thud/xyzzy.js
+ // Your application can tell Dojo to locate the "foo" namespace by calling:
+ // | dojo.registerModulePath("foo", "../../foo");
+ // At which point you can then use dojo.require() to load the
+ // modules (assuming they provide() the same things which are
+ // required). The full code might be:
+ // | <script type="text/javascript"
+ // | src="/myapp/js/dojo/dojo/dojo.js"></script>
+ // | <script type="text/javascript">
+ // | dojo.registerModulePath("foo", "../../foo");
+ // | dojo.require("foo.bar");
+ // | dojo.require("foo.baz");
+ // | dojo.require("foo.thud.xyzzy");
+ // | </script>
+ d._modulePrefixes[module] = { name: module, value: prefix };
+ }
+
+ dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
+ // summary:
+ // Declares translated resources and loads them if necessary, in the
+ // same style as dojo.require. Contents of the resource bundle are
+ // typically strings, but may be any name/value pair, represented in
+ // JSON format. See also dojo.i18n.getLocalization.
+ // moduleName:
+ // name of the package containing the "nls" directory in which the
+ // bundle is found
+ // bundleName:
+ // bundle name, i.e. the filename without the '.js' suffix
+ // locale:
+ // the locale to load (optional) By default, the browser's user
+ // locale as defined by dojo.locale
+ // availableFlatLocales:
+ // A comma-separated list of the available, flattened locales for this
+ // bundle. This argument should only be set by the build process.
+ // description:
+ // Load translated resource bundles provided underneath the "nls"
+ // directory within a package. Translated resources may be located in
+ // different packages throughout the source tree. For example, a
+ // particular widget may define one or more resource bundles,
+ // structured in a program as follows, where moduleName is
+ // mycode.mywidget and bundleNames available include bundleone and
+ // bundletwo:
+ //
+ // | ...
+ // | mycode/
+ // | mywidget/
+ // | nls/
+ // | bundleone.js (the fallback translation, English in this example)
+ // | bundletwo.js (also a fallback translation)
+ // | de/
+ // | bundleone.js
+ // | bundletwo.js
+ // | de-at/
+ // | bundleone.js
+ // | en/
+ // | (empty; use the fallback translation)
+ // | en-us/
+ // | bundleone.js
+ // | en-gb/
+ // | bundleone.js
+ // | es/
+ // | bundleone.js
+ // | bundletwo.js
+ // | ...etc
+ // | ...
+ //
+ // Each directory is named for a locale as specified by RFC 3066,
+ // (http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase.
+ // Note that the two bundles in the example do not define all the
+ // same variants. For a given locale, bundles will be loaded for
+ // that locale and all more general locales above it, including a
+ // fallback at the root directory. For example, a declaration for
+ // the "de-at" locale will first load `nls/de-at/bundleone.js`,
+ // then `nls/de/bundleone.js` and finally `nls/bundleone.js`. The
+ // data will be flattened into a single Object so that lookups
+ // will follow this cascading pattern. An optional build step can
+ // preload the bundles to avoid data redundancy and the multiple
+ // network hits normally required to load these resources.
+
+ d.require("dojo.i18n");
+ d.i18n._requireLocalization.apply(d.hostenv, arguments);
+ };
+
+
+ var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$");
+ var ire = new RegExp("^((([^:]+:)?([^@]+))@)?([^:]*)(:([0-9]+))?$");
+
+ dojo._Url = function(/*dojo._Url||String...*/){
+ // summary:
+ // Constructor to create an object representing a URL.
+ // It is marked as private, since we might consider removing
+ // or simplifying it.
+ // description:
+ // Each argument is evaluated in order relative to the next until
+ // a canonical uri is produced. To get an absolute Uri relative to
+ // the current document use:
+ // new dojo._Url(document.baseURI, url)
+
+ var n = null;
+
+ // TODO: support for IPv6, see RFC 2732
+ var _a = arguments;
+ var uri = [_a[0]];
+ // resolve uri components relative to each other
+ for(var i = 1; i<_a.length; i++){
+ if(!_a[i]){ continue; }
+
+ // Safari doesn't support this.constructor so we have to be explicit
+ // FIXME: Tracked (and fixed) in Webkit bug 3537.
+ // http://bugs.webkit.org/show_bug.cgi?id=3537
+ var relobj = new d._Url(_a[i]+"");
+ var uriobj = new d._Url(uri[0]+"");
+
+ if(
+ relobj.path == "" &&
+ !relobj.scheme &&
+ !relobj.authority &&
+ !relobj.query
+ ){
+ if(relobj.fragment != n){
+ uriobj.fragment = relobj.fragment;
+ }
+ relobj = uriobj;
+ }else if(!relobj.scheme){
+ relobj.scheme = uriobj.scheme;
+
+ if(!relobj.authority){
+ relobj.authority = uriobj.authority;
+
+ if(relobj.path.charAt(0) != "/"){
+ var path = uriobj.path.substring(0,
+ uriobj.path.lastIndexOf("/") + 1) + relobj.path;
+
+ var segs = path.split("/");
+ for(var j = 0; j < segs.length; j++){
+ if(segs[j] == "."){
+ // flatten "./" references
+ if(j == segs.length - 1){
+ segs[j] = "";
+ }else{
+ segs.splice(j, 1);
+ j--;
+ }
+ }else if(j > 0 && !(j == 1 && segs[0] == "") &&
+ segs[j] == ".." && segs[j-1] != ".."){
+ // flatten "../" references
+ if(j == (segs.length - 1)){
+ segs.splice(j, 1);
+ segs[j - 1] = "";
+ }else{
+ segs.splice(j - 1, 2);
+ j -= 2;
+ }
+ }
+ }
+ relobj.path = segs.join("/");
+ }
+ }
+ }
+
+ uri = [];
+ if(relobj.scheme){
+ uri.push(relobj.scheme, ":");
+ }
+ if(relobj.authority){
+ uri.push("//", relobj.authority);
+ }
+ uri.push(relobj.path);
+ if(relobj.query){
+ uri.push("?", relobj.query);
+ }
+ if(relobj.fragment){
+ uri.push("#", relobj.fragment);
+ }
+ }
+
+ this.uri = uri.join("");
+
+ // break the uri into its main components
+ var r = this.uri.match(ore);
+
+ this.scheme = r[2] || (r[1] ? "" : n);
+ this.authority = r[4] || (r[3] ? "" : n);
+ this.path = r[5]; // can never be undefined
+ this.query = r[7] || (r[6] ? "" : n);
+ this.fragment = r[9] || (r[8] ? "" : n);
+
+ if(this.authority != n){
+ // server based naming authority
+ r = this.authority.match(ire);
+
+ this.user = r[3] || n;
+ this.password = r[4] || n;
+ this.host = r[5];
+ this.port = r[7] || n;
+ }
+ }
+
+ dojo._Url.prototype.toString = function(){ return this.uri; };
+
+ dojo.moduleUrl = function(/*String*/module, /*dojo._Url||String*/url){
+ // summary:
+ // Returns a `dojo._Url` object relative to a module.
+ // example:
+ // | var pngPath = dojo.moduleUrl("acme","images/small.png");
+ // | console.dir(pngPath); // list the object properties
+ // | // create an image and set it's source to pngPath's value:
+ // | var img = document.createElement("img");
+ // | // NOTE: we assign the string representation of the url object
+ // | img.src = pngPath.toString();
+ // | // add our image to the document
+ // | dojo.body().appendChild(img);
+ // example:
+ // you may de-reference as far as you like down the package
+ // hierarchy. This is sometimes handy to avoid lenghty relative
+ // urls or for building portable sub-packages. In this example,
+ // the `acme.widget` and `acme.util` directories may be located
+ // under different roots (see `dojo.registerModulePath`) but the
+ // the modules which reference them can be unaware of their
+ // relative locations on the filesystem:
+ // | // somewhere in a configuration block
+ // | dojo.registerModulePath("acme.widget", "../../acme/widget");
+ // | dojo.registerModulePath("acme.util", "../../util");
+ // |
+ // | // ...
+ // |
+ // | // code in a module using acme resources
+ // | var tmpltPath = dojo.moduleUrl("acme.widget","templates/template.html");
+ // | var dataPath = dojo.moduleUrl("acme.util","resources/data.json");
+
+ var loc = d._getModuleSymbols(module).join('/');
+ if(!loc){ return null; }
+ if(loc.lastIndexOf("/") != loc.length-1){
+ loc += "/";
+ }
+
+ //If the path is an absolute path (starts with a / or is on another
+ //domain/xdomain) then don't add the baseUrl.
+ var colonIndex = loc.indexOf(":");
+ if(loc.charAt(0) != "/" && (colonIndex == -1 || colonIndex > loc.indexOf("/"))){
+ loc = d.baseUrl + loc;
+ }
+
+ return new d._Url(loc, url); // String
+ }
+})();
+
+}
diff --git a/includes/js/dojo/_base/_loader/loader_debug.js b/includes/js/dojo/_base/_loader/loader_debug.js
new file mode 100644
index 0000000..7e52373
--- /dev/null
+++ b/includes/js/dojo/_base/_loader/loader_debug.js
@@ -0,0 +1,61 @@
+if(!dojo._hasResource["dojo._base._loader.loader_debug"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base._loader.loader_debug"] = true;
+dojo.provide("dojo._base._loader.loader_debug");
+
+//Override dojo.provide, so we can trigger the next
+//script tag for the next local module. We can only add one
+//at a time because there are browsers that execute script tags
+//in the order that the code is received, and not in the DOM order.
+dojo.nonDebugProvide = dojo.provide;
+
+dojo.provide = function(resourceName){
+ var dbgQueue = dojo["_xdDebugQueue"];
+ if(dbgQueue && dbgQueue.length > 0 && resourceName == dbgQueue["currentResourceName"]){
+ //Set a timeout so the module can be executed into existence. Normally the
+ //dojo.provide call in a module is the first line. Don't want to risk attaching
+ //another script tag until the current one finishes executing.
+ if(dojo.isAIR){
+ window.setTimeout(function(){dojo._xdDebugFileLoaded(resourceName);}, 1);
+ }else{
+ window.setTimeout(dojo._scopeName + "._xdDebugFileLoaded('" + resourceName + "')", 1);
+ }
+ }
+
+ return dojo.nonDebugProvide.apply(dojo, arguments);
+}
+
+dojo._xdDebugFileLoaded = function(resourceName){
+
+ if(!this._xdDebugScopeChecked){
+ //If using a scoped dojo, we need to expose dojo as a real global
+ //for the debugAtAllCosts stuff to work.
+ if(dojo._scopeName != "dojo"){
+ window.dojo = window[dojo.config.scopeMap[0][1]];
+ window.dijit = window[dojo.config.scopeMap[1][1]];
+ window.dojox = window[dojo.config.scopeMap[2][1]];
+ }
+
+ this._xdDebugScopeChecked = true;
+ }
+
+ var dbgQueue = this._xdDebugQueue;
+
+ if(resourceName && resourceName == dbgQueue.currentResourceName){
+ dbgQueue.shift();
+ }
+
+ if(dbgQueue.length == 0){
+ dbgQueue.currentResourceName = null;
+ this._xdNotifyLoaded();
+ }else{
+ if(resourceName == dbgQueue.currentResourceName){
+ dbgQueue.currentResourceName = dbgQueue[0].resourceName;
+ var element = document.createElement("script");
+ element.type = "text/javascript";
+ element.src = dbgQueue[0].resourcePath;
+ document.getElementsByTagName("head")[0].appendChild(element);
+ }
+ }
+}
+
+}
diff --git a/includes/js/dojo/_base/_loader/loader_xd.js b/includes/js/dojo/_base/_loader/loader_xd.js
new file mode 100644
index 0000000..d851df8
--- /dev/null
+++ b/includes/js/dojo/_base/_loader/loader_xd.js
@@ -0,0 +1,631 @@
+if(!dojo._hasResource["dojo._base._loader.loader_xd"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base._loader.loader_xd"] = true;
+//Cross-domain resource loader.
+dojo.provide("dojo._base._loader.loader_xd");
+
+dojo._xdReset = function(){
+ //summary: Internal xd loader function. Resets the xd state.
+
+ //This flag indicates where or not we have crossed into xdomain territory. Once any resource says
+ //it is cross domain, then the rest of the resources have to be treated as xdomain because we need
+ //to evaluate resources in order. If there is a xdomain resource followed by a xhr resource, we can't load
+ //the xhr resource until the one before it finishes loading. The text of the xhr resource will be converted
+ //to match the format for a xd resource and put in the xd load queue.
+ this._isXDomain = dojo.config.useXDomain || false;
+
+ this._xdTimer = 0;
+ this._xdInFlight = {};
+ this._xdOrderedReqs = [];
+ this._xdDepMap = {};
+ this._xdContents = [];
+ this._xdDefList = [];
+}
+
+//Call reset immediately to set the state.
+dojo._xdReset();
+
+dojo._xdCreateResource = function(/*String*/contents, /*String*/resourceName, /*String*/resourcePath){
+ //summary: Internal xd loader function. Creates an xd module source given an
+ //non-xd module contents.
+
+ //Remove comments. Not perfect, but good enough for dependency resolution.
+ var depContents = contents.replace(/(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg , "");
+
+ //Find dependencies.
+ var deps = [];
+ var depRegExp = /dojo.(require|requireIf|provide|requireAfterIf|platformRequire|requireLocalization)\(([\w\W]*?)\)/mg;
+ var match;
+ while((match = depRegExp.exec(depContents)) != null){
+ if(match[1] == "requireLocalization"){
+ //Need to load the local bundles asap, since they are not
+ //part of the list of modules watched for loading.
+ eval(match[0]);
+ }else{
+ deps.push('"' + match[1] + '", ' + match[2]);
+ }
+ }
+
+ //Create resource object and the call to _xdResourceLoaded.
+ var output = [];
+ output.push(dojo._scopeName + "._xdResourceLoaded({\n");
+
+ //Add dependencies
+ if(deps.length > 0){
+ output.push("depends: [");
+ for(var i = 0; i < deps.length; i++){
+ if(i > 0){
+ output.push(",\n");
+ }
+ output.push("[" + deps[i] + "]");
+ }
+ output.push("],");
+ }
+
+ //Add the contents of the file inside a function.
+ //Pass in scope arguments so we can support multiple versions of the
+ //same module on a page.
+ output.push("\ndefineResource: function(" + dojo._scopePrefixArgs + "){");
+
+ //Don't put in the contents in the debugAtAllCosts case
+ //since the contents may have syntax errors. Let those
+ //get pushed up when the script tags are added to the page
+ //in the debugAtAllCosts case.
+ if(!dojo.config["debugAtAllCosts"] || resourceName == "dojo._base._loader.loader_debug"){
+ output.push(contents);
+ }
+ //Add isLocal property so we know if we have to do something different
+ //in debugAtAllCosts situations.
+ output.push("\n}, resourceName: '" + resourceName + "', resourcePath: '" + resourcePath + "'});");
+
+ return output.join(""); //String
+}
+
+dojo._xdIsXDomainPath = function(/*string*/relpath) {
+ //summary: Figure out whether the path is local or x-domain
+ //If there is a colon before the first / then, we have a URL with a protocol.
+
+ var colonIndex = relpath.indexOf(":");
+ var slashIndex = relpath.indexOf("/");
+
+ if(colonIndex > 0 && colonIndex < slashIndex){
+ return true;
+ }else{
+ //Is the base script URI-based URL a cross domain URL?
+ //If so, then the relpath will be evaluated relative to
+ //baseUrl, and therefore qualify as xdomain.
+ //Only treat it as xdomain if the page does not have a
+ //host (file:// url) or if the baseUrl does not match the
+ //current window's domain.
+ var url = this.baseUrl;
+ colonIndex = url.indexOf(":");
+ slashIndex = url.indexOf("/");
+ if(colonIndex > 0 && colonIndex < slashIndex && (!location.host || url.indexOf("http://" + location.host) != 0)){
+ return true;
+ }
+ }
+ return false;
+}
+
+dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){
+ //summary: Internal xd loader function. Overrides loadPath() from loader.js.
+ //xd loading requires slightly different behavior from loadPath().
+
+ var currentIsXDomain = this._xdIsXDomainPath(relpath);
+ this._isXDomain |= currentIsXDomain;
+
+ var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : this.baseUrl) + relpath;
+
+ try{
+ return ((!module || this._isXDomain) ? this._loadUri(uri, cb, currentIsXDomain, module) : this._loadUriAndCheck(uri, module, cb)); //Boolean
+ }catch(e){
+ console.debug(e);
+ return false; //Boolean
+ }
+}
+
+dojo._loadUri = function(/*String*/uri, /*Function?*/cb, /*boolean*/currentIsXDomain, /*String?*/module){
+ //summary: Internal xd loader function. Overrides loadUri() from loader.js.
+ // xd loading requires slightly different behavior from loadPath().
+ //description: Wanted to override getText(), but it is used by
+ // the widget code in too many, synchronous ways right now.
+ if(this._loadedUrls[uri]){
+ return 1; //Boolean
+ }
+
+ //Add the module (resource) to the list of modules.
+ //Only do this work if we have a modlue name. Otherwise,
+ //it is a non-xd i18n bundle, which can load immediately and does not
+ //need to be tracked. Also, don't track dojo.i18n, since it is a prerequisite
+ //and will be loaded correctly if we load it right away: it has no dependencies.
+ if(this._isXDomain && module && module != "dojo.i18n"){
+ this._xdOrderedReqs.push(module);
+
+ //Add to waiting resources if it is an xdomain resource.
+ //Don't add non-xdomain i18n bundles, those get evaled immediately.
+ if(currentIsXDomain || uri.indexOf("/nls/") == -1){
+ this._xdInFlight[module] = true;
+
+ //Increment inFlightCount
+ //This will stop the modulesLoaded from firing all the way.
+ this._inFlightCount++;
+ }
+
+ //Start timer
+ if(!this._xdTimer){
+ if(dojo.isAIR){
+ this._xdTimer = setInterval(function(){dojo._xdWatchInFlight();}, 100);
+ }else{
+ this._xdTimer = setInterval(dojo._scopeName + "._xdWatchInFlight();", 100);
+ }
+ }
+ this._xdStartTime = (new Date()).getTime();
+ }
+
+ if (currentIsXDomain){
+ //Fix name to be a .xd.fileextension name.
+ var lastIndex = uri.lastIndexOf('.');
+ if(lastIndex <= 0){
+ lastIndex = uri.length - 1;
+ }
+
+ var xdUri = uri.substring(0, lastIndex) + ".xd";
+ if(lastIndex != uri.length - 1){
+ xdUri += uri.substring(lastIndex, uri.length);
+ }
+
+ if (dojo.isAIR){
+ xdUri = xdUri.replace("app:/", "/");
+ }
+
+ //Add to script src
+ var element = document.createElement("script");
+ element.type = "text/javascript";
+ element.src = xdUri;
+ if(!this.headElement){
+ this._headElement = document.getElementsByTagName("head")[0];
+
+ //Head element may not exist, particularly in html
+ //html 4 or tag soup cases where the page does not
+ //have a head tag in it. Use html element, since that will exist.
+ //Seems to be an issue mostly with Opera 9 and to lesser extent Safari 2
+ if(!this._headElement){
+ this._headElement = document.getElementsByTagName("html")[0];
+ }
+ }
+ this._headElement.appendChild(element);
+ }else{
+ var contents = this._getText(uri, null, true);
+ if(contents == null){ return 0; /*boolean*/}
+
+ //If this is not xdomain, or if loading a i18n resource bundle, then send it down
+ //the normal eval/callback path.
+ if(this._isXDomain
+ && uri.indexOf("/nls/") == -1
+ && module != "dojo.i18n"){
+ var res = this._xdCreateResource(contents, module, uri);
+ dojo.eval(res);
+ }else{
+ if(cb){
+ contents = '('+contents+')';
+ }else{
+ //Only do the scoping if no callback. If a callback is specified,
+ //it is most likely the i18n bundle stuff.
+ contents = this._scopePrefix + contents + this._scopeSuffix;
+ }
+ var value = dojo["eval"](contents+"\r\n//@ sourceURL="+uri);
+ if(cb){
+ cb(value);
+ }
+ }
+ }
+
+ //These steps are done in the non-xd loader version of this function.
+ //Maintain these steps to fit in with the existing system.
+ this._loadedUrls[uri] = true;
+ this._loadedUrls.push(uri);
+ return true; //Boolean
+}
+
+dojo._xdResourceLoaded = function(/*Object*/res){
+ //summary: Internal xd loader function. Called by an xd module resource when
+ //it has been loaded via a script tag.
+ var deps = res.depends;
+ var requireList = null;
+ var requireAfterList = null;
+ var provideList = [];
+ if(deps && deps.length > 0){
+ var dep = null;
+ var insertHint = 0;
+ var attachedResource = false;
+ for(var i = 0; i < deps.length; i++){
+ dep = deps[i];
+
+ //Look for specific dependency indicators.
+ if (dep[0] == "provide"){
+ provideList.push(dep[1]);
+ }else{
+ if(!requireList){
+ requireList = [];
+ }
+ if(!requireAfterList){
+ requireAfterList = [];
+ }
+
+ var unpackedDeps = this._xdUnpackDependency(dep);
+ if(unpackedDeps.requires){
+ requireList = requireList.concat(unpackedDeps.requires);
+ }
+ if(unpackedDeps.requiresAfter){
+ requireAfterList = requireAfterList.concat(unpackedDeps.requiresAfter);
+ }
+ }
+
+ //Call the dependency indicator to allow for the normal dojo setup.
+ //Only allow for one dot reference, for the i18n._preloadLocalizations calls
+ //(and maybe future, one-dot things).
+ var depType = dep[0];
+ var objPath = depType.split(".");
+ if(objPath.length == 2){
+ dojo[objPath[0]][objPath[1]].apply(dojo[objPath[0]], dep.slice(1));
+ }else{
+ dojo[depType].apply(dojo, dep.slice(1));
+ }
+ }
+
+
+ //If loading the debugAtAllCosts module, eval it right away since we need
+ //its functions to properly load the other modules.
+ if(provideList.length == 1 && provideList[0] == "dojo._base._loader.loader_debug"){
+ res.defineResource(dojo);
+ }else{
+ //Save off the resource contents for definition later.
+ var contentIndex = this._xdContents.push({
+ content: res.defineResource,
+ resourceName: res["resourceName"],
+ resourcePath: res["resourcePath"],
+ isDefined: false
+ }) - 1;
+
+ //Add provide/requires to dependency map.
+ for(var i = 0; i < provideList.length; i++){
+ this._xdDepMap[provideList[i]] = { requires: requireList, requiresAfter: requireAfterList, contentIndex: contentIndex };
+ }
+ }
+
+ //Now update the inflight status for any provided resources in this loaded resource.
+ //Do this at the very end (in a *separate* for loop) to avoid shutting down the
+ //inflight timer check too soon.
+ for(var i = 0; i < provideList.length; i++){
+ this._xdInFlight[provideList[i]] = false;
+ }
+ }
+}
+
+dojo._xdLoadFlattenedBundle = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*Object*/bundleData){
+ //summary: Internal xd loader function. Used when loading
+ //a flattened localized bundle via a script tag.
+ locale = locale || "root";
+ var jsLoc = dojo.i18n.normalizeLocale(locale).replace('-', '_');
+ var bundleResource = [moduleName, "nls", bundleName].join(".");
+ var bundle = dojo["provide"](bundleResource);
+ bundle[jsLoc] = bundleData;
+
+ //Assign the bundle for the original locale(s) we wanted.
+ var mapName = [moduleName, jsLoc, bundleName].join(".");
+ var bundleMap = dojo._xdBundleMap[mapName];
+ if(bundleMap){
+ for(var param in bundleMap){
+ bundle[param] = bundleData;
+ }
+ }
+};
+
+
+dojo._xdInitExtraLocales = function(){
+ // Simulate the extra locale work that dojo.requireLocalization does.
+
+ var extra = dojo.config.extraLocale;
+ if(extra){
+ if(!extra instanceof Array){
+ extra = [extra];
+ }
+
+ dojo._xdReqLoc = dojo.xdRequireLocalization;
+ dojo.xdRequireLocalization = function(m, b, locale, fLocales){
+ dojo._xdReqLoc(m,b,locale, fLocales);
+ if(locale){return;}
+ for(var i=0; i<extra.length; i++){
+ dojo._xdReqLoc(m,b,extra[i], fLocales);
+ }
+ };
+ }
+}
+
+dojo._xdBundleMap = {};
+
+dojo.xdRequireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String*/availableFlatLocales){
+ //summary: Internal xd loader function. The xd version of dojo.requireLocalization.
+
+
+ //Account for allowing multiple extra locales. Do this here inside the function
+ //since dojo._xdInitExtraLocales() depends on djConfig being set up, but that only
+ //happens after hostenv_browser runs. loader_xd has to come before hostenv_browser
+ //though since hostenv_browser can do a dojo.require for the debug module.
+ if(dojo._xdInitExtraLocales){
+ dojo._xdInitExtraLocales();
+ dojo._xdInitExtraLocales = null;
+ dojo.xdRequireLocalization.apply(dojo, arguments);
+ return;
+ }
+
+ var locales = availableFlatLocales.split(",");
+
+ //Find the best-match locale to load.
+ //Assumes dojo.i18n has already been loaded. This is true for xdomain builds,
+ //since it is included in dojo.xd.js.
+ var jsLoc = dojo.i18n.normalizeLocale(locale);
+
+ var bestLocale = "";
+ for(var i = 0; i < locales.length; i++){
+ //Locale must match from start of string.
+ if(jsLoc.indexOf(locales[i]) == 0){
+ if(locales[i].length > bestLocale.length){
+ bestLocale = locales[i];
+ }
+ }
+ }
+
+ var fixedBestLocale = bestLocale.replace('-', '_');
+ //See if the bundle we are going to use is already loaded.
+ var bundleResource = dojo.getObject([moduleName, "nls", bundleName].join("."));
+ if(bundleResource && bundleResource[fixedBestLocale]){
+ bundle[jsLoc.replace('-', '_')] = bundleResource[fixedBestLocale];
+ }else{
+ //Need to remember what locale we wanted and which one we actually use.
+ //Then when we load the one we are actually using, use that bundle for the one
+ //we originally wanted.
+ var mapName = [moduleName, (fixedBestLocale||"root"), bundleName].join(".");
+ var bundleMap = dojo._xdBundleMap[mapName];
+ if(!bundleMap){
+ bundleMap = dojo._xdBundleMap[mapName] = {};
+ }
+ bundleMap[jsLoc.replace('-', '_')] = true;
+
+ //Do just a normal dojo.require so the resource tracking stuff works as usual.
+ dojo.require(moduleName + ".nls" + (bestLocale ? "." + bestLocale : "") + "." + bundleName);
+ }
+}
+
+// Replace dojo.requireLocalization with a wrapper
+dojo._xdRealRequireLocalization = dojo.requireLocalization;
+dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String*/availableFlatLocales){
+ // summary: loads a bundle intelligently based on whether the module is
+ // local or xd. Overrides the local-case implementation.
+
+ var modulePath = this.moduleUrl(moduleName).toString();
+ if (this._xdIsXDomainPath(modulePath)) {
+ // call cross-domain loader
+ return dojo.xdRequireLocalization.apply(dojo, arguments);
+ } else {
+ // call local-loader
+ return dojo._xdRealRequireLocalization.apply(dojo, arguments);
+ }
+}
+
+//This is a bit brittle: it has to know about the dojo methods that deal with dependencies
+//It would be ideal to intercept the actual methods and do something fancy at that point,
+//but I have concern about knowing which provide to match to the dependency in that case,
+//since scripts can load whenever they want, and trigger new calls to dojo._xdResourceLoaded().
+dojo._xdUnpackDependency = function(/*Array*/dep){
+ //summary: Internal xd loader function. Determines what to do with a dependency
+ //that was listed in an xd version of a module contents.
+
+ //Extract the dependency(ies).
+ var newDeps = null;
+ var newAfterDeps = null;
+ switch(dep[0]){
+ case "requireIf":
+ case "requireAfterIf":
+ //First arg (dep[1]) is the test. Depedency is dep[2].
+ if(dep[1] === true){
+ newDeps = [{name: dep[2], content: null}];
+ }
+ break;
+ case "platformRequire":
+ var modMap = dep[1];
+ var common = modMap["common"]||[];
+ var newDeps = (modMap[dojo.hostenv.name_]) ? common.concat(modMap[dojo.hostenv.name_]||[]) : common.concat(modMap["default"]||[]);
+ //Flatten the array of arrays into a one-level deep array.
+ //Each result could be an array of 3 elements (the 3 arguments to dojo.require).
+ //We only need the first one.
+ if(newDeps){
+ for(var i = 0; i < newDeps.length; i++){
+ if(newDeps[i] instanceof Array){
+ newDeps[i] = {name: newDeps[i][0], content: null};
+ }else{
+ newDeps[i] = {name: newDeps[i], content: null};
+ }
+ }
+ }
+ break;
+ case "require":
+ //Just worry about dep[1]
+ newDeps = [{name: dep[1], content: null}];
+ break;
+ case "i18n._preloadLocalizations":
+ //We can eval these immediately, since they load i18n bundles.
+ //Since i18n bundles have no dependencies, whenever they are loaded
+ //in a script tag, they are evaluated immediately, so we do not have to
+ //treat them has an explicit dependency for the dependency mapping.
+ //We can call it immediately since dojo.i18n is part of dojo.xd.js.
+ dojo.i18n._preloadLocalizations.apply(dojo.i18n._preloadLocalizations, dep.slice(1));
+ break;
+ }
+
+ //The requireIf and requireAfterIf needs to be evaluated after the current resource is evaluated.
+ if(dep[0] == "requireAfterIf" || dep[0] == "requireIf"){
+ newAfterDeps = newDeps;
+ newDeps = null;
+ }
+ return {requires: newDeps, requiresAfter: newAfterDeps}; //Object
+}
+
+dojo._xdWalkReqs = function(){
+ //summary: Internal xd loader function.
+ //Walks the requires and evaluates module resource contents in
+ //the right order.
+ var reqChain = null;
+ var req;
+ for(var i = 0; i < this._xdOrderedReqs.length; i++){
+ req = this._xdOrderedReqs[i];
+ if(this._xdDepMap[req]){
+ reqChain = [req];
+ reqChain[req] = true; //Allow for fast lookup of the req in the array
+ this._xdEvalReqs(reqChain);
+ }
+ }
+}
+
+dojo._xdEvalReqs = function(/*Array*/reqChain){
+ //summary: Internal xd loader function.
+ //Does a depth first, breadth second search and eval of required modules.
+ while(reqChain.length > 0){
+ var req = reqChain[reqChain.length - 1];
+ var res = this._xdDepMap[req];
+ if(res){
+ //Trace down any requires for this resource.
+ //START dojo._xdTraceReqs() inlining for small Safari 2.0 call stack
+ var reqs = res.requires;
+ if(reqs && reqs.length > 0){
+ var nextReq;
+ for(var i = 0; i < reqs.length; i++){
+ nextReq = reqs[i].name;
+ if(nextReq && !reqChain[nextReq]){
+ //New req depedency. Follow it down.
+ reqChain.push(nextReq);
+ reqChain[nextReq] = true;
+ this._xdEvalReqs(reqChain);
+ }
+ }
+ }
+ //END dojo._xdTraceReqs() inlining for small Safari 2.0 call stack
+
+ //Evaluate the resource.
+ var contents = this._xdContents[res.contentIndex];
+ if(!contents.isDefined){
+ var content = contents.content;
+ content["resourceName"] = contents["resourceName"];
+ content["resourcePath"] = contents["resourcePath"];
+ this._xdDefList.push(content);
+ contents.isDefined = true;
+ }
+ this._xdDepMap[req] = null;
+
+ //Trace down any requireAfters for this resource.
+ //START dojo._xdTraceReqs() inlining for small Safari 2.0 call stack
+ var reqs = res.requiresAfter;
+ if(reqs && reqs.length > 0){
+ var nextReq;
+ for(var i = 0; i < reqs.length; i++){
+ nextReq = reqs[i].name;
+ if(nextReq && !reqChain[nextReq]){
+ //New req depedency. Follow it down.
+ reqChain.push(nextReq);
+ reqChain[nextReq] = true;
+ this._xdEvalReqs(reqChain);
+ }
+ }
+ }
+ //END dojo._xdTraceReqs() inlining for small Safari 2.0 call stack
+ }
+
+ //Done with that require. Remove it and go to the next one.
+ reqChain.pop();
+ }
+}
+
+dojo._xdClearInterval = function(){
+ //summary: Internal xd loader function.
+ //Clears the interval timer used to check on the
+ //status of in-flight xd module resource requests.
+ clearInterval(this._xdTimer);
+ this._xdTimer = 0;
+}
+
+dojo._xdWatchInFlight = function(){
+ //summary: Internal xd loader function.
+ //Monitors in-flight requests for xd module resources.
+
+ var noLoads = "";
+ var waitInterval = (dojo.config.xdWaitSeconds || 15) * 1000;
+ var expired = (this._xdStartTime + waitInterval) < (new Date()).getTime();
+
+ //If any xdInFlight are true, then still waiting for something to load.
+ //Come back later. If we timed out, report the things that did not load.
+ for(var param in this._xdInFlight){
+ if(this._xdInFlight[param] === true){
+ if(expired){
+ noLoads += param + " ";
+ }else{
+ return;
+ }
+ }
+ }
+
+ //All done. Clean up and notify.
+ this._xdClearInterval();
+
+ if(expired){
+ throw "Could not load cross-domain resources: " + noLoads;
+ }
+
+ this._xdWalkReqs();
+
+ var defLength = this._xdDefList.length;
+ for(var i= 0; i < defLength; i++){
+ var content = dojo._xdDefList[i];
+ if(dojo.config["debugAtAllCosts"] && content["resourceName"]){
+ if(!this["_xdDebugQueue"]){
+ this._xdDebugQueue = [];
+ }
+ this._xdDebugQueue.push({resourceName: content.resourceName, resourcePath: content.resourcePath});
+ }else{
+ //Evaluate the resource to bring it into being.
+ //Pass in scope args to allow multiple versions of modules in a page.
+ content.apply(dojo.global, dojo._scopeArgs);
+ }
+ }
+
+ //Evaluate any resources that were not evaled before.
+ //This normally shouldn't happen with proper dojo.provide and dojo.require
+ //usage, but providing it just in case. Note that these may not be executed
+ //in the original order that the developer intended.
+ for(var i = 0; i < this._xdContents.length; i++){
+ var current = this._xdContents[i];
+ if(current.content && !current.isDefined){
+ //Pass in scope args to allow multiple versions of modules in a page.
+ current.content.apply(dojo.global, dojo._scopeArgs);
+ }
+ }
+
+ //Clean up for the next round of xd loading.
+ this._xdReset();
+
+ if(this["_xdDebugQueue"] && this._xdDebugQueue.length > 0){
+ this._xdDebugFileLoaded();
+ }else{
+ this._xdNotifyLoaded();
+ }
+}
+
+dojo._xdNotifyLoaded = function(){
+ //Clear inflight count so we will finally do finish work.
+ this._inFlightCount = 0;
+
+ //Only trigger call loaded if dj_load_init has run.
+ if(this._initFired && !this._loadNotifying){
+ this._callLoaded();
+ }
+}
+
+}
diff --git a/includes/js/dojo/_base/array.js b/includes/js/dojo/_base/array.js
new file mode 100644
index 0000000..b0c68fa
--- /dev/null
+++ b/includes/js/dojo/_base/array.js
@@ -0,0 +1,182 @@
+if(!dojo._hasResource["dojo._base.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.array"] = true;
+dojo.require("dojo._base.lang");
+dojo.provide("dojo._base.array");
+
+(function(){
+ var _getParts = function(arr, obj, cb){
+ return [
+ dojo.isString(arr) ? arr.split("") : arr,
+ obj || dojo.global,
+ // FIXME: cache the anonymous functions we create here?
+ dojo.isString(cb) ? new Function("item", "index", "array", cb) : cb
+ ];
+ };
+
+ dojo.mixin(dojo, {
+ indexOf: function( /*Array*/ array,
+ /*Object*/ value,
+ /*Integer?*/ fromIndex,
+ /*Boolean?*/ findLast){
+ // summary:
+ // locates the first index of the provided value in the
+ // passed array. If the value is not found, -1 is returned.
+ // description:
+ // For details on this method, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
+
+ var step = 1, end = array.length || 0, i = 0;
+ if(findLast){
+ i = end - 1;
+ step = end = -1;
+ }
+ if(fromIndex != undefined){ i = fromIndex; }
+ if((findLast && i > end) || i < end){
+ for(; i != end; i += step){
+ if(array[i] == value){ return i; }
+ }
+ }
+ return -1; // Number
+ },
+
+ lastIndexOf: function(/*Array*/array, /*Object*/value, /*Integer?*/fromIndex){
+ // summary:
+ // locates the last index of the provided value in the passed array.
+ // If the value is not found, -1 is returned.
+ // description:
+ // For details on this method, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf>
+ return dojo.indexOf(array, value, fromIndex, true); // Number
+ },
+
+ forEach: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ // summary:
+ // for every item in arr, callback is invoked. Return values are ignored.
+ // arr: the array to iterate on. If a string, operates on individual characters.
+ // callback: a function is invoked with three arguments: item, index, and array
+ // thisObject: may be used to scope the call to callback
+ // description:
+ // This function corresponds to the JavaScript 1.6 Array.forEach() method.
+ // In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
+ // For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach>
+
+ // match the behavior of the built-in forEach WRT empty arrs
+ if(!arr || !arr.length){ return; }
+
+ // FIXME: there are several ways of handilng thisObject. Is
+ // dojo.global always the default context?
+ var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+ for(var i=0,l=_p[0].length; i<l; i++){
+ _p[2].call(_p[1], arr[i], i, arr);
+ }
+ },
+
+ _everyOrSome: function(/*Boolean*/every, /*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+ for(var i = 0, l = arr.length; i < l; i++){
+ var result = !!_p[2].call(_p[1], arr[i], i, arr);
+ if(every ^ result){
+ return result; // Boolean
+ }
+ }
+ return every; // Boolean
+ },
+
+ every: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ // summary:
+ // Determines whether or not every item in arr satisfies the
+ // condition implemented by callback.
+ // arr: the array to iterate on. If a string, operates on individual characters.
+ // callback: a function is invoked with three arguments: item, index, and array and returns true
+ // if the condition is met.
+ // thisObject: may be used to scope the call to callback
+ // description:
+ // This function corresponds to the JavaScript 1.6 Array.every() method.
+ // In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
+ // For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
+ // example:
+ // | dojo.every([1, 2, 3, 4], function(item){ return item>1; });
+ // returns false
+ // example:
+ // | dojo.every([1, 2, 3, 4], function(item){ return item>0; });
+ // returns true
+ return this._everyOrSome(true, arr, callback, thisObject); // Boolean
+ },
+
+ some: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ // summary:
+ // Determines whether or not any item in arr satisfies the
+ // condition implemented by callback.
+ // arr: the array to iterate on. If a string, operates on individual characters.
+ // callback: a function is invoked with three arguments: item, index, and array and returns true
+ // if the condition is met.
+ // thisObject: may be used to scope the call to callback
+ // description:
+ // This function corresponds to the JavaScript 1.6 Array.some() method.
+ // In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
+ // For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some>
+ // example:
+ // | dojo.some([1, 2, 3, 4], function(item){ return item>1; });
+ // returns true
+ // example:
+ // | dojo.some([1, 2, 3, 4], function(item){ return item<1; });
+ // returns false
+ return this._everyOrSome(false, arr, callback, thisObject); // Boolean
+ },
+
+ map: function(/*Array|String*/arr, /*Function|String*/callback, /*Function?*/thisObject){
+ // summary:
+ // applies callback to each element of arr and returns
+ // an Array with the results
+ // arr: the array to iterate on. If a string, operates on individual characters.
+ // callback: a function is invoked with three arguments: item, index, and array and returns a value
+ // thisObject: may be used to scope the call to callback
+ // description:
+ // This function corresponds to the JavaScript 1.6 Array.map() method.
+ // In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
+ // For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map>
+ // example:
+ // | dojo.map([1, 2, 3, 4], function(item){ return item+1 });
+ // returns [2, 3, 4, 5]
+ var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+ var outArr = (arguments[3] ? (new arguments[3]()) : []);
+ for(var i=0;i<arr.length;++i){
+ outArr.push(_p[2].call(_p[1], arr[i], i, arr));
+ }
+ return outArr; // Array
+ },
+
+ filter: function(/*Array*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ // summary:
+ // Returns a new Array with those items from arr that match the
+ // condition implemented by callback.
+ // arr: the array to iterate on. If a string, operates on individual characters.
+ // callback: a function is invoked with three arguments: item, index, and array and returns true
+ // if the condition is met.
+ // thisObject: may be used to scope the call to callback
+ // description:
+ // This function corresponds to the JavaScript 1.6 Array.filter() method.
+ // In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
+ // For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter>
+ // example:
+ // | dojo.filter([1, 2, 3, 4], function(item){ return item>1; });
+ // returns [2, 3, 4]
+
+ var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+ var outArr = [];
+ for(var i = 0; i < arr.length; i++){
+ if(_p[2].call(_p[1], arr[i], i, arr)){
+ outArr.push(arr[i]);
+ }
+ }
+ return outArr; // Array
+ }
+ });
+})();
+
+}
diff --git a/includes/js/dojo/_base/browser.js b/includes/js/dojo/_base/browser.js
new file mode 100644
index 0000000..9ee17a7
--- /dev/null
+++ b/includes/js/dojo/_base/browser.js
@@ -0,0 +1,21 @@
+if(!dojo._hasResource["dojo._base.browser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.browser"] = true;
+dojo.provide("dojo._base.browser");
+
+dojo.require("dojo._base.window");
+dojo.require("dojo._base.event");
+dojo.require("dojo._base.html");
+dojo.require("dojo._base.NodeList");
+dojo.require("dojo._base.query");
+dojo.require("dojo._base.xhr");
+dojo.require("dojo._base.fx");
+
+//Need this to be the last code segment in base, so do not place any
+//dojo.requireIf calls in this file. Otherwise, due to how the build system
+//puts all requireIf dependencies after the current file, the require calls
+//could be called before all of base is defined.
+if(dojo.config.require){
+ dojo.forEach(dojo.config.require, "dojo['require'](item);");
+}
+
+}
diff --git a/includes/js/dojo/_base/connect.js b/includes/js/dojo/_base/connect.js
new file mode 100644
index 0000000..5111372
--- /dev/null
+++ b/includes/js/dojo/_base/connect.js
@@ -0,0 +1,285 @@
+if(!dojo._hasResource["dojo._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.connect"] = true;
+dojo.provide("dojo._base.connect");
+dojo.require("dojo._base.lang");
+
+// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
+
+// low-level delegation machinery
+dojo._listener = {
+ // create a dispatcher function
+ getDispatcher: function(){
+ // following comments pulled out-of-line to prevent cloning them
+ // in the returned function.
+ // - indices (i) that are really in the array of listeners (ls) will
+ // not be in Array.prototype. This is the 'sparse array' trick
+ // that keeps us safe from libs that take liberties with built-in
+ // objects
+ // - listener is invoked with current scope (this)
+ return function(){
+ var ap=Array.prototype, c=arguments.callee, ls=c._listeners, t=c.target;
+ // return value comes from original target function
+ var r=t && t.apply(this, arguments);
+ // invoke listeners after target function
+ for(var i in ls){
+ if(!(i in ap)){
+ ls[i].apply(this, arguments);
+ }
+ }
+ // return value comes from original target function
+ return r;
+ }
+ },
+ // add a listener to an object
+ add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
+ // Whenever 'method' is invoked, 'listener' will have the same scope.
+ // Trying to supporting a context object for the listener led to
+ // complexity.
+ // Non trivial to provide 'once' functionality here
+ // because listener could be the result of a dojo.hitch call,
+ // in which case two references to the same hitch target would not
+ // be equivalent.
+ source = source || dojo.global;
+ // The source method is either null, a dispatcher, or some other function
+ var f = source[method];
+ // Ensure a dispatcher
+ if(!f||!f._listeners){
+ var d = dojo._listener.getDispatcher();
+ // original target function is special
+ d.target = f;
+ // dispatcher holds a list of listeners
+ d._listeners = [];
+ // redirect source to dispatcher
+ f = source[method] = d;
+ }
+ // The contract is that a handle is returned that can
+ // identify this listener for disconnect.
+ //
+ // The type of the handle is private. Here is it implemented as Integer.
+ // DOM event code has this same contract but handle is Function
+ // in non-IE browsers.
+ //
+ // We could have separate lists of before and after listeners.
+ return f._listeners.push(listener) ; /*Handle*/
+ },
+ // remove a listener from an object
+ remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
+ var f = (source||dojo.global)[method];
+ // remember that handle is the index+1 (0 is not a valid handle)
+ if(f && f._listeners && handle--){
+ delete f._listeners[handle];
+ }
+ }
+};
+
+// Multiple delegation for arbitrary methods.
+
+// This unit knows nothing about DOM,
+// but we include DOM aware
+// documentation and dontFix
+// argument here to help the autodocs.
+// Actual DOM aware code is in event.js.
+
+dojo.connect = function(/*Object|null*/ obj,
+ /*String*/ event,
+ /*Object|null*/ context,
+ /*String|Function*/ method,
+ /*Boolean*/ dontFix){
+ // summary:
+ // Create a link that calls one function when another executes.
+ //
+ // description:
+ // Connects method to event, so that after event fires, method
+ // does too. All connected functions are passed the same arguments as
+ // the event function was initially called with. You may connect as
+ // many methods to event as needed.
+ //
+ // event must be a string. If obj is null, dojo.global is used.
+ //
+ // null arguments may simply be omitted.
+ //
+ // obj[event] can resolve to a function or undefined (null).
+ // If obj[event] is null, it is assigned a function.
+ //
+ // The return value is a handle that is needed to
+ // remove this connection with dojo.disconnect.
+ //
+ // obj:
+ // The source object for the event function.
+ // Defaults to dojo.global if null.
+ // If obj is a DOM node, the connection is delegated
+ // to the DOM event manager (unless dontFix is true).
+ //
+ // event:
+ // String name of the event function in obj.
+ // I.e. identifies a property obj[event].
+ //
+ // context:
+ // The object that method will receive as "this".
+ //
+ // If context is null and method is a function, then method
+ // inherits the context of event.
+ //
+ // If method is a string then context must be the source
+ // object object for method (context[method]). If context is null,
+ // dojo.global is used.
+ //
+ // method:
+ // A function reference, or name of a function in context.
+ // The function identified by method fires after event does.
+ // method receives the same arguments as the event.
+ // See context argument comments for information on method's scope.
+ //
+ // dontFix:
+ // If obj is a DOM node, set dontFix to true to prevent delegation
+ // of this connection to the DOM event manager.
+ //
+ // example:
+ // When obj.onchange(), do ui.update():
+ // | dojo.connect(obj, "onchange", ui, "update");
+ // | dojo.connect(obj, "onchange", ui, ui.update); // same
+ //
+ // example:
+ // Using return value for disconnect:
+ // | var link = dojo.connect(obj, "onchange", ui, "update");
+ // | ...
+ // | dojo.disconnect(link);
+ //
+ // example:
+ // When onglobalevent executes, watcher.handler is invoked:
+ // | dojo.connect(null, "onglobalevent", watcher, "handler");
+ //
+ // example:
+ // When ob.onCustomEvent executes, customEventHandler is invoked:
+ // | dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
+ // | dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
+ //
+ // example:
+ // When ob.onCustomEvent executes, customEventHandler is invoked
+ // with the same scope (this):
+ // | dojo.connect(ob, "onCustomEvent", null, customEventHandler);
+ // | dojo.connect(ob, "onCustomEvent", customEventHandler); // same
+ //
+ // example:
+ // When globalEvent executes, globalHandler is invoked
+ // with the same scope (this):
+ // | dojo.connect(null, "globalEvent", null, globalHandler);
+ // | dojo.connect("globalEvent", globalHandler); // same
+
+ // normalize arguments
+ var a=arguments, args=[], i=0;
+ // if a[0] is a String, obj was ommited
+ args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]);
+ // if the arg-after-next is a String or Function, context was NOT omitted
+ var a1 = a[i+1];
+ args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]);
+ // absorb any additional arguments
+ for(var l=a.length; i<l; i++){ args.push(a[i]); }
+ // do the actual work
+ return dojo._connect.apply(this, args); /*Handle*/
+}
+
+// used by non-browser hostenvs. always overriden by event.js
+dojo._connect = function(obj, event, context, method){
+ var l=dojo._listener, h=l.add(obj, event, dojo.hitch(context, method));
+ return [obj, event, h, l]; // Handle
+}
+
+dojo.disconnect = function(/*Handle*/ handle){
+ // summary:
+ // Remove a link created by dojo.connect.
+ // description:
+ // Removes the connection between event and the method referenced by handle.
+ // handle:
+ // the return value of the dojo.connect call that created the connection.
+ if(handle && handle[0] !== undefined){
+ dojo._disconnect.apply(this, handle);
+ // let's not keep this reference
+ delete handle[0];
+ }
+}
+
+dojo._disconnect = function(obj, event, handle, listener){
+ listener.remove(obj, event, handle);
+}
+
+// topic publish/subscribe
+
+dojo._topics = {};
+
+dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method){
+ // summary:
+ // Attach a listener to a named topic. The listener function is invoked whenever the
+ // named topic is published (see: dojo.publish).
+ // Returns a handle which is needed to unsubscribe this listener.
+ // context:
+ // Scope in which method will be invoked, or null for default scope.
+ // method:
+ // The name of a function in context, or a function reference. This is the function that
+ // is invoked when topic is published.
+ // example:
+ // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
+ // | dojo.publish("alerts", [ "read this", "hello world" ]);
+
+ // support for 2 argument invocation (omitting context) depends on hitch
+ return [topic, dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method))]; /*Handle*/
+}
+
+dojo.unsubscribe = function(/*Handle*/ handle){
+ // summary:
+ // Remove a topic listener.
+ // handle:
+ // The handle returned from a call to subscribe.
+ // example:
+ // | var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
+ // | ...
+ // | dojo.unsubscribe(alerter);
+ if(handle){
+ dojo._listener.remove(dojo._topics, handle[0], handle[1]);
+ }
+}
+
+dojo.publish = function(/*String*/ topic, /*Array*/ args){
+ // summary:
+ // Invoke all listener method subscribed to topic.
+ // topic:
+ // The name of the topic to publish.
+ // args:
+ // An array of arguments. The arguments will be applied
+ // to each topic subscriber (as first class parameters, via apply).
+ // example:
+ // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
+ // | dojo.publish("alerts", [ "read this", "hello world" ]);
+
+ // Note that args is an array, which is more efficient vs variable length
+ // argument list. Ideally, var args would be implemented via Array
+ // throughout the APIs.
+ var f = dojo._topics[topic];
+ if(f){
+ f.apply(this, args||[]);
+ }
+}
+
+dojo.connectPublisher = function( /*String*/ topic,
+ /*Object|null*/ obj,
+ /*String*/ event){
+ // summary:
+ // Ensure that everytime obj.event() is called, a message is published
+ // on the topic. Returns a handle which can be passed to
+ // dojo.disconnect() to disable subsequent automatic publication on
+ // the topic.
+ // topic:
+ // The name of the topic to publish.
+ // obj:
+ // The source object for the event function. Defaults to dojo.global
+ // if null.
+ // event:
+ // The name of the event function in obj.
+ // I.e. identifies a property obj[event].
+ // example:
+ // | dojo.connectPublisher("/ajax/start", dojo, "xhrGet"};
+ var pf = function(){ dojo.publish(topic, arguments); }
+ return (event) ? dojo.connect(obj, event, pf) : dojo.connect(obj, pf); //Handle
+};
+
+}
diff --git a/includes/js/dojo/_base/declare.js b/includes/js/dojo/_base/declare.js
new file mode 100644
index 0000000..6c2ec55
--- /dev/null
+++ b/includes/js/dojo/_base/declare.js
@@ -0,0 +1,178 @@
+if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.declare"] = true;
+dojo.provide("dojo._base.declare");
+dojo.require("dojo._base.lang");
+
+// this file courtesy of the TurboAjax group, licensed under a Dojo CLA
+
+dojo.declare = function(/*String*/ className, /*Function|Function[]*/ superclass, /*Object*/ props){
+ // summary:
+ // Create a feature-rich constructor from compact notation
+ // className:
+ // The name of the constructor (loosely, a "class")
+ // stored in the "declaredClass" property in the created prototype
+ // superclass:
+ // May be null, a Function, or an Array of Functions. If an array,
+ // the first element is used as the prototypical ancestor and
+ // any following Functions become mixin ancestors.
+ // props:
+ // An object whose properties are copied to the
+ // created prototype.
+ // Add an instance-initialization function by making it a property
+ // named "constructor".
+ // description:
+ // Create a constructor using a compact notation for inheritance and
+ // prototype extension.
+ //
+ // All superclasses (including mixins) must be Functions (not simple Objects).
+ //
+ // Mixin ancestors provide a type of multiple inheritance. Prototypes of mixin
+ // ancestors are copied to the new class: changes to mixin prototypes will
+ // not affect classes to which they have been mixed in.
+ //
+ // "className" is cached in "declaredClass" property of the new class.
+ //
+ // example:
+ // | dojo.declare("my.classes.bar", my.classes.foo, {
+ // | // properties to be added to the class prototype
+ // | someValue: 2,
+ // | // initialization function
+ // | constructor: function(){
+ // | this.myComplicatedObject = new ReallyComplicatedObject();
+ // | },
+ // | // other functions
+ // | someMethod: function(){
+ // | doStuff();
+ // | }
+ // | );
+
+ // process superclass argument
+ // var dd=dojo.declare, mixins=null;
+ var dd = arguments.callee, mixins;
+ if(dojo.isArray(superclass)){
+ mixins = superclass;
+ superclass = mixins.shift();
+ }
+ // construct intermediate classes for mixins
+ if(mixins){
+ dojo.forEach(mixins, function(m){
+ if(!m){ throw(className + ": mixin #" + i + " is null"); } // It's likely a required module is not loaded
+ superclass = dd._delegate(superclass, m);
+ });
+ }
+ // prepare values
+ var init = (props||0).constructor, ctor = dd._delegate(superclass), fn;
+ // name methods (experimental)
+ for(var i in props){ if(dojo.isFunction(fn = props[i]) && !0[i]){fn.nom = i;} } // 0[i] checks Object.prototype
+ // decorate prototype
+ dojo.extend(ctor, {declaredClass: className, _constructor: init, preamble: null}, props || 0);
+ // special help for IE
+ ctor.prototype.constructor = ctor;
+ // create named reference
+ return dojo.setObject(className, ctor); // Function
+};
+
+dojo.mixin(dojo.declare, {
+ _delegate: function(base, mixin){
+ var bp = (base||0).prototype, mp = (mixin||0).prototype;
+ // fresh constructor, fresh prototype
+ var ctor = dojo.declare._makeCtor();
+ // cache ancestry
+ dojo.mixin(ctor, {superclass: bp, mixin: mp, extend: dojo.declare._extend});
+ // chain prototypes
+ if(base){ctor.prototype = dojo._delegate(bp);}
+ // add mixin and core
+ dojo.extend(ctor, dojo.declare._core, mp||0, {_constructor: null, preamble: null});
+ // special help for IE
+ ctor.prototype.constructor = ctor;
+ // name this class for debugging
+ ctor.prototype.declaredClass = (bp||0).declaredClass + '_' + (mp||0).declaredClass;
+ return ctor;
+ },
+ _extend: function(props){
+ for(var i in props){ if(dojo.isFunction(fn=props[i]) && !0[i]){fn.nom=i;} }
+ dojo.extend(this, props);
+ },
+ _makeCtor: function(){
+ // we have to make a function, but don't want to close over anything
+ return function(){ this._construct(arguments); };
+ },
+ _core: {
+ _construct: function(args){
+ var c=args.callee, s=c.superclass, ct=s&&s.constructor, m=c.mixin, mct=m&&m.constructor, a=args, ii, fn;
+ // side-effect of = used on purpose here, lint may complain, don't try this at home
+ if(a[0]){
+ // FIXME: preambles for each mixin should be allowed
+ // FIXME:
+ // should we allow the preamble here NOT to modify the
+ // default args, but instead to act on each mixin
+ // independently of the class instance being constructed
+ // (for impedence matching)?
+
+ // allow any first argument w/ a "preamble" property to act as a
+ // class preamble (not exclusive of the prototype preamble)
+ if(/*dojo.isFunction*/((fn = a[0].preamble))){
+ a = fn.apply(this, a) || a;
+ }
+ }
+ // prototype preamble
+ if((fn = c.prototype.preamble)){a = fn.apply(this, a) || a;}
+ // FIXME:
+ // need to provide an optional prototype-settable
+ // "_explicitSuper" property which disables this
+ // initialize superclass
+ if(ct&&ct.apply){ct.apply(this, a);}
+ // initialize mixin
+ if(mct&&mct.apply){mct.apply(this, a);}
+ // initialize self
+ if((ii=c.prototype._constructor)){ii.apply(this, args);}
+ // post construction
+ if(this.constructor.prototype==c.prototype && (ct=this.postscript)){ ct.apply(this, args); }
+ },
+ _findMixin: function(mixin){
+ var c = this.constructor, p, m;
+ while(c){
+ p = c.superclass;
+ m = c.mixin;
+ if(m==mixin || (m instanceof mixin.constructor)){return p;}
+ if(m && (m=m._findMixin(mixin))){return m;}
+ c = p && p.constructor;
+ }
+ },
+ _findMethod: function(name, method, ptype, has){
+ // consciously trading readability for bytes and speed in this low-level method
+ var p=ptype, c, m, f;
+ do{
+ c = p.constructor;
+ m = c.mixin;
+ // find method by name in our mixin ancestor
+ if(m && (m=this._findMethod(name, method, m, has))){return m;}
+ // if we found a named method that either exactly-is or exactly-is-not 'method'
+ if((f=p[name])&&(has==(f==method))){return p;}
+ // ascend chain
+ p = c.superclass;
+ }while(p);
+ // if we couldn't find an ancestor in our primary chain, try a mixin chain
+ return !has && (p=this._findMixin(ptype)) && this._findMethod(name, method, p, has);
+ },
+ inherited: function(name, args, newArgs){
+ // optionalize name argument (experimental)
+ var a = arguments;
+ if(!dojo.isString(a[0])){newArgs=args; args=name; name=args.callee.nom;}
+ a = newArgs||args;
+ var c = args.callee, p = this.constructor.prototype, fn, mp;
+ // if not an instance override
+ if(this[name] != c || p[name] == c){
+ mp = this._findMethod(name, c, p, true);
+ if(!mp){throw(this.declaredClass + ': inherited method "' + name + '" mismatch');}
+ p = this._findMethod(name, c, mp, false);
+ }
+ fn = p && p[name];
+ if(!fn){throw(mp.declaredClass + ': inherited method "' + name + '" not found');}
+ // if the function exists, invoke it in our scope
+ return fn.apply(this, a);
+ }
+ }
+});
+
+}
diff --git a/includes/js/dojo/_base/event.js b/includes/js/dojo/_base/event.js
new file mode 100644
index 0000000..41cfd4d
--- /dev/null
+++ b/includes/js/dojo/_base/event.js
@@ -0,0 +1,529 @@
+if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.event"] = true;
+dojo.provide("dojo._base.event");
+dojo.require("dojo._base.connect");
+
+// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
+
+(function(){
+ // DOM event listener machinery
+ var del = (dojo._event_listener = {
+ add: function(/*DOMNode*/node, /*String*/name, /*Function*/fp){
+ if(!node){return;}
+ name = del._normalizeEventName(name);
+ fp = del._fixCallback(name, fp);
+ var oname = name;
+ if(!dojo.isIE && (name == "mouseenter" || name == "mouseleave")){
+ var ofp = fp;
+ //oname = name;
+ name = (name == "mouseenter") ? "mouseover" : "mouseout";
+ fp = function(e){
+ // thanks ben!
+ if(!dojo.isDescendant(e.relatedTarget, node)){
+ // e.type = oname; // FIXME: doesn't take? SJM: event.type is generally immutable.
+ return ofp.call(this, e);
+ }
+ }
+ }
+ node.addEventListener(name, fp, false);
+ return fp; /*Handle*/
+ },
+ remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
+ // summary:
+ // clobbers the listener from the node
+ // node:
+ // DOM node to attach the event to
+ // event:
+ // the name of the handler to remove the function from
+ // handle:
+ // the handle returned from add
+ if (node){
+ node.removeEventListener(del._normalizeEventName(event), handle, false);
+ }
+ },
+ _normalizeEventName: function(/*String*/name){
+ // Generally, name should be lower case, unless it is special
+ // somehow (e.g. a Mozilla DOM event).
+ // Remove 'on'.
+ return name.slice(0,2) =="on" ? name.slice(2) : name;
+ },
+ _fixCallback: function(/*String*/name, fp){
+ // By default, we only invoke _fixEvent for 'keypress'
+ // If code is added to _fixEvent for other events, we have
+ // to revisit this optimization.
+ // This also applies to _fixEvent overrides for Safari and Opera
+ // below.
+ return name != "keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); };
+ },
+ _fixEvent: function(evt, sender){
+ // _fixCallback only attaches us to keypress.
+ // Switch on evt.type anyway because we might
+ // be called directly from dojo.fixEvent.
+ switch(evt.type){
+ case "keypress":
+ del._setKeyChar(evt);
+ break;
+ }
+ return evt;
+ },
+ _setKeyChar: function(evt){
+ evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
+ }
+ });
+
+ // DOM events
+
+ dojo.fixEvent = function(/*Event*/evt, /*DOMNode*/sender){
+ // summary:
+ // normalizes properties on the event object including event
+ // bubbling methods, keystroke normalization, and x/y positions
+ // evt: Event
+ // native event object
+ // sender: DOMNode
+ // node to treat as "currentTarget"
+ return del._fixEvent(evt, sender);
+ }
+
+ dojo.stopEvent = function(/*Event*/evt){
+ // summary:
+ // prevents propagation and clobbers the default action of the
+ // passed event
+ // evt: Event
+ // The event object. If omitted, window.event is used on IE.
+ evt.preventDefault();
+ evt.stopPropagation();
+ // NOTE: below, this method is overridden for IE
+ }
+
+ // the default listener to use on dontFix nodes, overriden for IE
+ var node_listener = dojo._listener;
+
+ // Unify connect and event listeners
+ dojo._connect = function(obj, event, context, method, dontFix){
+ // FIXME: need a more strict test
+ var isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener);
+ // choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node
+ // we need the third option to provide leak prevention on broken browsers (IE)
+ var lid = !isNode ? 0 : (!dontFix ? 1 : 2), l = [dojo._listener, del, node_listener][lid];
+ // create a listener
+ var h = l.add(obj, event, dojo.hitch(context, method));
+ // formerly, the disconnect package contained "l" directly, but if client code
+ // leaks the disconnect package (by connecting it to a node), referencing "l"
+ // compounds the problem.
+ // instead we return a listener id, which requires custom _disconnect below.
+ // return disconnect package
+ return [ obj, event, h, lid ];
+ }
+
+ dojo._disconnect = function(obj, event, handle, listener){
+ ([dojo._listener, del, node_listener][listener]).remove(obj, event, handle);
+ }
+
+ // Constants
+
+ // Public: client code should test
+ // keyCode against these named constants, as the
+ // actual codes can vary by browser.
+ dojo.keys = {
+ // summary: definitions for common key values
+ BACKSPACE: 8,
+ TAB: 9,
+ CLEAR: 12,
+ ENTER: 13,
+ SHIFT: 16,
+ CTRL: 17,
+ ALT: 18,
+ PAUSE: 19,
+ CAPS_LOCK: 20,
+ ESCAPE: 27,
+ SPACE: 32,
+ PAGE_UP: 33,
+ PAGE_DOWN: 34,
+ END: 35,
+ HOME: 36,
+ LEFT_ARROW: 37,
+ UP_ARROW: 38,
+ RIGHT_ARROW: 39,
+ DOWN_ARROW: 40,
+ INSERT: 45,
+ DELETE: 46,
+ HELP: 47,
+ LEFT_WINDOW: 91,
+ RIGHT_WINDOW: 92,
+ SELECT: 93,
+ NUMPAD_0: 96,
+ NUMPAD_1: 97,
+ NUMPAD_2: 98,
+ NUMPAD_3: 99,
+ NUMPAD_4: 100,
+ NUMPAD_5: 101,
+ NUMPAD_6: 102,
+ NUMPAD_7: 103,
+ NUMPAD_8: 104,
+ NUMPAD_9: 105,
+ NUMPAD_MULTIPLY: 106,
+ NUMPAD_PLUS: 107,
+ NUMPAD_ENTER: 108,
+ NUMPAD_MINUS: 109,
+ NUMPAD_PERIOD: 110,
+ NUMPAD_DIVIDE: 111,
+ F1: 112,
+ F2: 113,
+ F3: 114,
+ F4: 115,
+ F5: 116,
+ F6: 117,
+ F7: 118,
+ F8: 119,
+ F9: 120,
+ F10: 121,
+ F11: 122,
+ F12: 123,
+ F13: 124,
+ F14: 125,
+ F15: 126,
+ NUM_LOCK: 144,
+ SCROLL_LOCK: 145
+ };
+
+ // IE event normalization
+ if(dojo.isIE){
+ var _trySetKeyCode = function(e, code){
+ try{
+ // squelch errors when keyCode is read-only
+ // (e.g. if keyCode is ctrl or shift)
+ return (e.keyCode = code);
+ }catch(e){
+ return 0;
+ }
+ }
+
+ // by default, use the standard listener
+ var iel = dojo._listener;
+ // dispatcher tracking property
+ if(!dojo.config._allow_leaks){
+ // custom listener that handles leak protection for DOM events
+ node_listener = iel = dojo._ie_listener = {
+ // support handler indirection: event handler functions are
+ // referenced here. Event dispatchers hold only indices.
+ handlers: [],
+ // add a listener to an object
+ add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
+ source = source || dojo.global;
+ var f = source[method];
+ if(!f||!f._listeners){
+ var d = dojo._getIeDispatcher();
+ // original target function is special
+ d.target = f && (ieh.push(f) - 1);
+ // dispatcher holds a list of indices into handlers table
+ d._listeners = [];
+ // redirect source to dispatcher
+ f = source[method] = d;
+ }
+ return f._listeners.push(ieh.push(listener) - 1) ; /*Handle*/
+ },
+ // remove a listener from an object
+ remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
+ var f = (source||dojo.global)[method], l = f && f._listeners;
+ if(f && l && handle--){
+ delete ieh[l[handle]];
+ delete l[handle];
+ }
+ }
+ };
+ // alias used above
+ var ieh = iel.handlers;
+ }
+
+ dojo.mixin(del, {
+ add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){
+ if(!node){return;} // undefined
+ event = del._normalizeEventName(event);
+ if(event=="onkeypress"){
+ // we need to listen to onkeydown to synthesize
+ // keypress events that otherwise won't fire
+ // on IE
+ var kd = node.onkeydown;
+ if(!kd || !kd._listeners || !kd._stealthKeydownHandle){
+ var h = del.add(node, "onkeydown", del._stealthKeyDown);
+ kd = node.onkeydown;
+ kd._stealthKeydownHandle = h;
+ kd._stealthKeydownRefs = 1;
+ }else{
+ kd._stealthKeydownRefs++;
+ }
+ }
+ return iel.add(node, event, del._fixCallback(fp));
+ },
+ remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
+ event = del._normalizeEventName(event);
+ iel.remove(node, event, handle);
+ if(event=="onkeypress"){
+ var kd = node.onkeydown;
+ if(--kd._stealthKeydownRefs <= 0){
+ iel.remove(node, "onkeydown", kd._stealthKeydownHandle);
+ delete kd._stealthKeydownHandle;
+ }
+ }
+ },
+ _normalizeEventName: function(/*String*/eventName){
+ // Generally, eventName should be lower case, unless it is
+ // special somehow (e.g. a Mozilla event)
+ // ensure 'on'
+ return eventName.slice(0,2) != "on" ? "on" + eventName : eventName;
+ },
+ _nop: function(){},
+ _fixEvent: function(/*Event*/evt, /*DOMNode*/sender){
+ // summary:
+ // normalizes properties on the event object including event
+ // bubbling methods, keystroke normalization, and x/y positions
+ // evt: native event object
+ // sender: node to treat as "currentTarget"
+ if(!evt){
+ var w = sender && (sender.ownerDocument || sender.document || sender).parentWindow || window;
+ evt = w.event;
+ }
+ if(!evt){return(evt);}
+ evt.target = evt.srcElement;
+ evt.currentTarget = (sender || evt.srcElement);
+ evt.layerX = evt.offsetX;
+ evt.layerY = evt.offsetY;
+ // FIXME: scroll position query is duped from dojo.html to
+ // avoid dependency on that entire module. Now that HTML is in
+ // Base, we should convert back to something similar there.
+ var se = evt.srcElement, doc = (se && se.ownerDocument) || document;
+ // DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used
+ // here rather than document.body
+ var docBody = ((dojo.isIE < 6) || (doc["compatMode"] == "BackCompat")) ? doc.body : doc.documentElement;
+ var offset = dojo._getIeDocumentElementOffset();
+ evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x;
+ evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y;
+ if(evt.type == "mouseover"){
+ evt.relatedTarget = evt.fromElement;
+ }
+ if(evt.type == "mouseout"){
+ evt.relatedTarget = evt.toElement;
+ }
+ evt.stopPropagation = del._stopPropagation;
+ evt.preventDefault = del._preventDefault;
+ return del._fixKeys(evt);
+ },
+ _fixKeys: function(evt){
+ switch(evt.type){
+ case "keypress":
+ var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
+ if (c==10){
+ // CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
+ c=0;
+ evt.keyCode = 13;
+ }else if(c==13||c==27){
+ c=0; // Mozilla considers ENTER and ESC non-printable
+ }else if(c==3){
+ c=99; // Mozilla maps CTRL-BREAK to CTRL-c
+ }
+ // Mozilla sets keyCode to 0 when there is a charCode
+ // but that stops the event on IE.
+ evt.charCode = c;
+ del._setKeyChar(evt);
+ break;
+ }
+ return evt;
+ },
+ // some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE
+ // we map those virtual key codes to ascii here
+ // not valid for all (non-US) keyboards, so maybe we shouldn't bother
+ _punctMap: {
+ 106:42,
+ 111:47,
+ 186:59,
+ 187:43,
+ 188:44,
+ 189:45,
+ 190:46,
+ 191:47,
+ 192:96,
+ 219:91,
+ 220:92,
+ 221:93,
+ 222:39
+ },
+ _stealthKeyDown: function(evt){
+ // IE doesn't fire keypress for most non-printable characters.
+ // other browsers do, we simulate it here.
+ var kp = evt.currentTarget.onkeypress;
+ // only works if kp exists and is a dispatcher
+ if(!kp || !kp._listeners){ return; }
+ // munge key/charCode
+ var k=evt.keyCode;
+ // These are Windows Virtual Key Codes
+ // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
+ var unprintable = (k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);
+ // synthesize keypress for most unprintables and CTRL-keys
+ if(unprintable||evt.ctrlKey){
+ var c = unprintable ? 0 : k;
+ if(evt.ctrlKey){
+ if(k==3 || k==13){
+ return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
+ }else if(c>95 && c<106){
+ c -= 48; // map CTRL-[numpad 0-9] to ASCII
+ }else if((!evt.shiftKey)&&(c>=65&&c<=90)){
+ c += 32; // map CTRL-[A-Z] to lowercase
+ }else{
+ c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
+ }
+ }
+ // simulate a keypress event
+ var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
+ kp.call(evt.currentTarget, faux);
+ evt.cancelBubble = faux.cancelBubble;
+ evt.returnValue = faux.returnValue;
+ _trySetKeyCode(evt, faux.keyCode);
+ }
+ },
+ // Called in Event scope
+ _stopPropagation: function(){
+ this.cancelBubble = true;
+ },
+ _preventDefault: function(){
+ // Setting keyCode to 0 is the only way to prevent certain keypresses (namely
+ // ctrl-combinations that correspond to menu accelerator keys).
+ // Otoh, it prevents upstream listeners from getting this information
+ // Try to split the difference here by clobbering keyCode only for ctrl
+ // combinations. If you still need to access the key upstream, bubbledKeyCode is
+ // provided as a workaround.
+ this.bubbledKeyCode = this.keyCode;
+ if(this.ctrlKey){_trySetKeyCode(this, 0);}
+ this.returnValue = false;
+ }
+ });
+
+ // override stopEvent for IE
+ dojo.stopEvent = function(evt){
+ evt = evt || window.event;
+ del._stopPropagation.call(evt);
+ del._preventDefault.call(evt);
+ }
+ }
+
+ del._synthesizeEvent = function(evt, props){
+ var faux = dojo.mixin({}, evt, props);
+ del._setKeyChar(faux);
+ // FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault);
+ // but it throws an error when preventDefault is invoked on Safari
+ // does Event.preventDefault not support "apply" on Safari?
+ faux.preventDefault = function(){ evt.preventDefault(); };
+ faux.stopPropagation = function(){ evt.stopPropagation(); };
+ return faux;
+ }
+
+ // Opera event normalization
+ if(dojo.isOpera){
+ dojo.mixin(del, {
+ _fixEvent: function(evt, sender){
+ switch(evt.type){
+ case "keypress":
+ var c = evt.which;
+ if(c==3){
+ c=99; // Mozilla maps CTRL-BREAK to CTRL-c
+ }
+ // can't trap some keys at all, like INSERT and DELETE
+ // there is no differentiating info between DELETE and ".", or INSERT and "-"
+ c = ((c<41)&&(!evt.shiftKey) ? 0 : c);
+ if((evt.ctrlKey)&&(!evt.shiftKey)&&(c>=65)&&(c<=90)){
+ // lowercase CTRL-[A-Z] keys
+ c += 32;
+ }
+ return del._synthesizeEvent(evt, { charCode: c });
+ }
+ return evt;
+ }
+ });
+ }
+
+ // Safari event normalization
+ if(dojo.isSafari){
+ dojo.mixin(del, {
+ _fixEvent: function(evt, sender){
+ switch(evt.type){
+ case "keypress":
+ var c = evt.charCode, s = evt.shiftKey, k = evt.keyCode;
+ // FIXME: This is a hack, suggest we rethink keyboard strategy.
+ // Arrow and page keys have 0 "keyCode" in keypress events.on Safari for Windows
+ k = k || identifierMap[evt.keyIdentifier] || 0;
+ if(evt.keyIdentifier=="Enter"){
+ c = 0; // differentiate Enter from CTRL-m (both code 13)
+ }else if((evt.ctrlKey)&&(c>0)&&(c<27)){
+ c += 96; // map CTRL-[A-Z] codes to ASCII
+ } else if (c==dojo.keys.SHIFT_TAB) {
+ c = dojo.keys.TAB; // morph SHIFT_TAB into TAB + shiftKey: true
+ s = true;
+ } else {
+ c = (c>=32 && c<63232 ? c : 0); // avoid generating keyChar for non-printables
+ }
+ return del._synthesizeEvent(evt, {charCode: c, shiftKey: s, keyCode: k});
+ }
+ return evt;
+ }
+ });
+
+ dojo.mixin(dojo.keys, {
+ SHIFT_TAB: 25,
+ UP_ARROW: 63232,
+ DOWN_ARROW: 63233,
+ LEFT_ARROW: 63234,
+ RIGHT_ARROW: 63235,
+ F1: 63236,
+ F2: 63237,
+ F3: 63238,
+ F4: 63239,
+ F5: 63240,
+ F6: 63241,
+ F7: 63242,
+ F8: 63243,
+ F9: 63244,
+ F10: 63245,
+ F11: 63246,
+ F12: 63247,
+ PAUSE: 63250,
+ DELETE: 63272,
+ HOME: 63273,
+ END: 63275,
+ PAGE_UP: 63276,
+ PAGE_DOWN: 63277,
+ INSERT: 63302,
+ PRINT_SCREEN: 63248,
+ SCROLL_LOCK: 63249,
+ NUM_LOCK: 63289
+ });
+ var dk = dojo.keys, identifierMap = { "Up": dk.UP_ARROW, "Down": dk.DOWN_ARROW, "Left": dk.LEFT_ARROW, "Right": dk.RIGHT_ARROW, "PageUp": dk.PAGE_UP, "PageDown": dk.PAGE_DOWN };
+ }
+})();
+
+if(dojo.isIE){
+ // keep this out of the closure
+ // closing over 'iel' or 'ieh' b0rks leak prevention
+ // ls[i] is an index into the master handler array
+ dojo._ieDispatcher = function(args, sender){
+ var ap=Array.prototype, h=dojo._ie_listener.handlers, c=args.callee, ls=c._listeners, t=h[c.target];
+ // return value comes from original target function
+ var r = t && t.apply(sender, args);
+ // invoke listeners after target function
+ for(var i in ls){
+ if(!(i in ap)){
+ h[ls[i]].apply(sender, args);
+ }
+ }
+ return r;
+ }
+ dojo._getIeDispatcher = function(){
+ // ensure the returned function closes over nothing
+ return new Function(dojo._scopeName + "._ieDispatcher(arguments, this)"); // function
+ }
+ // keep this out of the closure to reduce RAM allocation
+ dojo._event_listener._fixCallback = function(fp){
+ var f = dojo._event_listener._fixEvent;
+ return function(e){ return fp.call(this, f(e, this)); };
+ }
+}
+
+}
diff --git a/includes/js/dojo/_base/fx.js b/includes/js/dojo/_base/fx.js
new file mode 100644
index 0000000..33307a9
--- /dev/null
+++ b/includes/js/dojo/_base/fx.js
@@ -0,0 +1,584 @@
+if(!dojo._hasResource["dojo._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.fx"] = true;
+dojo.provide("dojo._base.fx");
+dojo.require("dojo._base.Color");
+dojo.require("dojo._base.connect");
+dojo.require("dojo._base.declare");
+dojo.require("dojo._base.lang");
+dojo.require("dojo._base.html");
+
+/*
+ Animation losely package based on Dan Pupius' work, contributed under CLA:
+ http://pupius.co.uk/js/Toolkit.Drawing.js
+*/
+(function(){
+
+ var d = dojo;
+
+ dojo._Line = function(/*int*/ start, /*int*/ end){
+ // summary:
+ // dojo._Line is the object used to generate values from a start value
+ // to an end value
+ // start: int
+ // Beginning value for range
+ // end: int
+ // Ending value for range
+ this.start = start;
+ this.end = end;
+ this.getValue = function(/*float*/ n){
+ // summary: returns the point on the line
+ // n: a floating point number greater than 0 and less than 1
+ return ((this.end - this.start) * n) + this.start; // Decimal
+ }
+ }
+
+ d.declare("dojo._Animation", null, {
+ // summary
+ // A generic animation class that fires callbacks into its handlers
+ // object at various states. Nearly all dojo animation functions
+ // return an instance of this method, usually without calling the
+ // .play() method beforehand. Therefore, you will likely need to
+ // call .play() on instances of dojo._Animation when one is
+ // returned.
+ constructor: function(/*Object*/ args){
+ d.mixin(this, args);
+ if(d.isArray(this.curve)){
+ /* curve: Array
+ pId: a */
+ this.curve = new d._Line(this.curve[0], this.curve[1]);
+ }
+ },
+
+ // duration: Integer
+ // The time in milliseonds the animation will take to run
+ duration: 350,
+
+ /*=====
+ // curve: dojo._Line||Array
+ // A two element array of start and end values, or a dojo._Line instance to be
+ // used in the Animation.
+ curve: null,
+
+ // easing: Function
+ // A Function to adjust the acceleration (or deceleration) of the progress
+ // across a dojo._Line
+ easing: null,
+ =====*/
+
+ // repeat: Integer
+ // The number of times to loop the animation
+ repeat: 0,
+
+ // rate: Integer
+ // the time in milliseconds to wait before advancing to next frame
+ // (used as a fps timer: rate/1000 = fps)
+ rate: 10 /* 100 fps */,
+
+ /*=====
+ // delay: Integer
+ // The time in milliseconds to wait before starting animation after it has been .play()'ed
+ delay: null,
+
+ // events
+ //
+ // beforeBegin: Event
+ // Synthetic event fired before a dojo._Animation begins playing (synchronous)
+ beforeBegin: null,
+
+ // onBegin: Event
+ // Synthetic event fired as a dojo._Animation begins playing (useful?)
+ onBegin: null,
+
+ // onAnimate: Event
+ // Synthetic event fired at each interval of a dojo._Animation
+ onAnimate: null,
+
+ // onEnd: Event
+ // Synthetic event fired after the final frame of a dojo._Animation
+ onEnd: null,
+
+ // onPlay: Event
+ // Synthetic event fired any time a dojo._Animation is play()'ed
+ onPlay: null,
+
+ // onPause: Event
+ // Synthetic event fired when a dojo._Animation is paused
+ onPause: null,
+
+ // onStop: Event
+ // Synthetic event fires when a dojo._Animation is stopped
+ onStop: null,
+
+ =====*/
+
+ _percent: 0,
+ _startRepeatCount: 0,
+
+ _fire: function(/*Event*/ evt, /*Array?*/ args){
+ // summary:
+ // Convenience function. Fire event "evt" and pass it the
+ // arguments specified in "args".
+ // evt:
+ // The event to fire.
+ // args:
+ // The arguments to pass to the event.
+ try{
+ if(this[evt]){
+ this[evt].apply(this, args||[]);
+ }
+ }catch(e){
+ // squelch and log because we shouldn't allow exceptions in
+ // synthetic event handlers to cause the internal timer to run
+ // amuck, potentially pegging the CPU. I'm not a fan of this
+ // squelch, but hopefully logging will make it clear what's
+ // going on
+ console.error("exception in animation handler for:", evt);
+ console.error(e);
+ }
+ return this; // dojo._Animation
+ },
+
+ play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
+ // summary:
+ // Start the animation.
+ // delay:
+ // How many milliseconds to delay before starting.
+ // gotoStart:
+ // If true, starts the animation from the beginning; otherwise,
+ // starts it from its current position.
+ var _t = this;
+ if(gotoStart){
+ _t._stopTimer();
+ _t._active = _t._paused = false;
+ _t._percent = 0;
+ }else if(_t._active && !_t._paused){
+ return _t; // dojo._Animation
+ }
+
+ _t._fire("beforeBegin");
+
+ var de = delay||_t.delay;
+ var _p = dojo.hitch(_t, "_play", gotoStart);
+ if(de > 0){
+ setTimeout(_p, de);
+ return _t; // dojo._Animation
+ }
+ _p();
+ return _t;
+ },
+
+ _play: function(gotoStart){
+ var _t = this;
+ _t._startTime = new Date().valueOf();
+ if(_t._paused){
+ _t._startTime -= _t.duration * _t._percent;
+ }
+ _t._endTime = _t._startTime + _t.duration;
+
+ _t._active = true;
+ _t._paused = false;
+
+ var value = _t.curve.getValue(_t._percent);
+ if(!_t._percent){
+ if(!_t._startRepeatCount){
+ _t._startRepeatCount = _t.repeat;
+ }
+ _t._fire("onBegin", [value]);
+ }
+
+ _t._fire("onPlay", [value]);
+
+ _t._cycle();
+ return _t; // dojo._Animation
+ },
+
+ pause: function(){
+ // summary: Pauses a running animation.
+ this._stopTimer();
+ if(!this._active){ return this; /*dojo._Animation*/ }
+ this._paused = true;
+ this._fire("onPause", [this.curve.getValue(this._percent)]);
+ return this; // dojo._Animation
+ },
+
+ gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){
+ // summary:
+ // Sets the progress of the animation.
+ // percent:
+ // A percentage in decimal notation (between and including 0.0 and 1.0).
+ // andPlay:
+ // If true, play the animation after setting the progress.
+ this._stopTimer();
+ this._active = this._paused = true;
+ this._percent = percent;
+ if(andPlay){ this.play(); }
+ return this; // dojo._Animation
+ },
+
+ stop: function(/*boolean?*/ gotoEnd){
+ // summary: Stops a running animation.
+ // gotoEnd: If true, the animation will end.
+ if(!this._timer){ return this; /* dojo._Animation */ }
+ this._stopTimer();
+ if(gotoEnd){
+ this._percent = 1;
+ }
+ this._fire("onStop", [this.curve.getValue(this._percent)]);
+ this._active = this._paused = false;
+ return this; // dojo._Animation
+ },
+
+ status: function(){
+ // summary: Returns a string token representation of the status of
+ // the animation, one of: "paused", "playing", "stopped"
+ if(this._active){
+ return this._paused ? "paused" : "playing"; // String
+ }
+ return "stopped"; // String
+ },
+
+ _cycle: function(){
+ var _t = this;
+ if(_t._active){
+ var curr = new Date().valueOf();
+ var step = (curr - _t._startTime) / (_t._endTime - _t._startTime);
+
+ if(step >= 1){
+ step = 1;
+ }
+ _t._percent = step;
+
+ // Perform easing
+ if(_t.easing){
+ step = _t.easing(step);
+ }
+
+ _t._fire("onAnimate", [_t.curve.getValue(step)]);
+
+ if(_t._percent < 1){
+ _t._startTimer();
+ }else{
+ _t._active = false;
+
+ if(_t.repeat > 0){
+ _t.repeat--;
+ _t.play(null, true);
+ }else if(_t.repeat == -1){
+ _t.play(null, true);
+ }else{
+ if(_t._startRepeatCount){
+ _t.repeat = _t._startRepeatCount;
+ _t._startRepeatCount = 0;
+ }
+ }
+ _t._percent = 0;
+ _t._fire("onEnd");
+ _t._stopTimer();
+ }
+ }
+ return _t; // dojo._Animation
+ }
+ });
+
+ var ctr = 0;
+ var _globalTimerList = [];
+ var runner = {
+ run: function(){ }
+ };
+ var timer = null;
+ dojo._Animation.prototype._startTimer = function(){
+ // this._timer = setTimeout(dojo.hitch(this, "_cycle"), this.rate);
+ if(!this._timer){
+ this._timer = d.connect(runner, "run", this, "_cycle");
+ ctr++;
+ }
+ if(!timer){
+ timer = setInterval(d.hitch(runner, "run"), this.rate);
+ }
+ };
+
+ dojo._Animation.prototype._stopTimer = function(){
+ if(this._timer){
+ d.disconnect(this._timer);
+ this._timer = null;
+ ctr--;
+ }
+ if(ctr <= 0){
+ clearInterval(timer);
+ timer = null;
+ ctr = 0;
+ }
+ };
+
+ var _makeFadeable = (d.isIE) ? function(node){
+ // only set the zoom if the "tickle" value would be the same as the
+ // default
+ var ns = node.style;
+ if(!ns.zoom.length && d.style(node, "zoom") == "normal"){
+ // make sure the node "hasLayout"
+ // NOTE: this has been tested with larger and smaller user-set text
+ // sizes and works fine
+ ns.zoom = "1";
+ // node.style.zoom = "normal";
+ }
+ // don't set the width to auto if it didn't already cascade that way.
+ // We don't want to f anyones designs
+ if(!ns.width.length && d.style(node, "width") == "auto"){
+ ns.width = "auto";
+ }
+ } : function(){};
+
+ dojo._fade = function(/*Object*/ args){
+ // summary:
+ // Returns an animation that will fade the node defined by
+ // args.node from the start to end values passed (args.start
+ // args.end) (end is mandatory, start is optional)
+
+ args.node = d.byId(args.node);
+ var fArgs = d.mixin({ properties: {} }, args);
+ var props = (fArgs.properties.opacity = {});
+ props.start = !("start" in fArgs) ?
+ function(){
+ return Number(d.style(fArgs.node, "opacity"));
+ } : fArgs.start;
+ props.end = fArgs.end;
+
+ var anim = d.animateProperty(fArgs);
+ d.connect(anim, "beforeBegin", d.partial(_makeFadeable, fArgs.node));
+
+ return anim; // dojo._Animation
+ }
+
+ /*=====
+ dojo.__FadeArgs = function(node, duration, easing){
+ // node: DOMNode|String
+ // The node referenced in the animation
+ // duration: Integer?
+ // Duration of the animation in milliseconds.
+ // easing: Function?
+ // An easing function.
+ this.node = node;
+ this.duration = duration;
+ this.easing = easing;
+ }
+ =====*/
+
+ dojo.fadeIn = function(/*dojo.__FadeArgs*/ args){
+ // summary:
+ // Returns an animation that will fade node defined in 'args' from
+ // its current opacity to fully opaque.
+ return d._fade(d.mixin({ end: 1 }, args)); // dojo._Animation
+ }
+
+ dojo.fadeOut = function(/*dojo.__FadeArgs*/ args){
+ // summary:
+ // Returns an animation that will fade node defined in 'args'
+ // from its current opacity to fully transparent.
+ return d._fade(d.mixin({ end: 0 }, args)); // dojo._Animation
+ }
+
+ dojo._defaultEasing = function(/*Decimal?*/ n){
+ // summary: The default easing function for dojo._Animation(s)
+ return 0.5 + ((Math.sin((n + 1.5) * Math.PI))/2);
+ }
+
+ var PropLine = function(properties){
+ // PropLine is an internal class which is used to model the values of
+ // an a group of CSS properties across an animation lifecycle. In
+ // particular, the "getValue" function handles getting interpolated
+ // values between start and end for a particular CSS value.
+ this._properties = properties;
+ for(var p in properties){
+ var prop = properties[p];
+ if(prop.start instanceof d.Color){
+ // create a reusable temp color object to keep intermediate results
+ prop.tempColor = new d.Color();
+ }
+ }
+ this.getValue = function(r){
+ var ret = {};
+ for(var p in this._properties){
+ var prop = this._properties[p];
+ var start = prop.start;
+ if(start instanceof d.Color){
+ ret[p] = d.blendColors(start, prop.end, r, prop.tempColor).toCss();
+ }else if(!d.isArray(start)){
+ ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units||"px" : "");
+ }
+ }
+ return ret;
+ }
+ }
+
+ /*=====
+ dojo.declare("dojo.__AnimArgs", [dojo.__FadeArgs], {
+ // Properties: Object?
+ // A hash map of style properties to Objects describing the transition,
+ // such as the properties of dojo._Line with an additional 'unit' property
+ properties: {}
+
+ //TODOC: add event callbacks
+ });
+ =====*/
+
+ dojo.animateProperty = function(/*dojo.__AnimArgs*/ args){
+ // summary:
+ // Returns an animation that will transition the properties of
+ // node defined in 'args' depending how they are defined in
+ // 'args.properties'
+ //
+ // description:
+ // dojo.animateProperty is the foundation of most dojo.fx
+ // animations. It takes an object of "properties" corresponding to
+ // style properties, and animates them in parallel over a set
+ // duration.
+ //
+ // example:
+ // A simple animation that changes the width of the specified node.
+ // | dojo.animateProperty({
+ // | node: "nodeId",
+ // | properties: { width: 400 },
+ // | }).play();
+ // Dojo figures out the start value for the width and converts the
+ // integer specified for the width to the more expressive but
+ // verbose form `{ width: { end: '400', units: 'px' } }` which you
+ // can also specify directly
+ // example:
+ // animate width, height, and padding over 2 seconds...the
+ // pedantic way:
+ // | dojo.animateProperty({ node: node, duration:2000,
+ // | properties: {
+ // | width: { start: '200', end: '400', unit:"px" },
+ // | height: { start:'200', end: '400', unit:"px" },
+ // | paddingTop: { start:'5', end:'50', unit:"px" }
+ // | }
+ // | }).play();
+ //
+ // example:
+ // plug in a different easing function and register a callback for
+ // when the animation ends. Easing functions accept values between
+ // zero and one and return a value on that basis. In this case, an
+ // exponential-in curve.
+ // | dojo.animateProperty({
+ // | node: "nodeId",
+ // | // dojo figures out the start value
+ // | properties: { width: { end: 400 } },
+ // | easing: function(n){
+ // | return (n==0) ? 0 : Math.pow(2, 10 * (n - 1));
+ // | },
+ // | onEnd: function(){
+ // | // called when the animation finishes
+ // | }
+ // | }).play(500); // delay playing half a second
+
+ args.node = d.byId(args.node);
+ if(!args.easing){ args.easing = d._defaultEasing; }
+
+ var anim = new d._Animation(args);
+ d.connect(anim, "beforeBegin", anim, function(){
+ var pm = {};
+ for(var p in this.properties){
+ // Make shallow copy of properties into pm because we overwrite
+ // some values below. In particular if start/end are functions
+ // we don't want to overwrite them or the functions won't be
+ // called if the animation is reused.
+ if(p == "width" || p == "height"){
+ this.node.display = "block";
+ }
+ var prop = this.properties[p];
+ prop = pm[p] = d.mixin({}, (d.isObject(prop) ? prop: { end: prop }));
+
+ if(d.isFunction(prop.start)){
+ prop.start = prop.start();
+ }
+ if(d.isFunction(prop.end)){
+ prop.end = prop.end();
+ }
+ var isColor = (p.toLowerCase().indexOf("color") >= 0);
+ function getStyle(node, p){
+ // dojo.style(node, "height") can return "auto" or "" on IE; this is more reliable:
+ var v = ({height: node.offsetHeight, width: node.offsetWidth})[p];
+ if(v !== undefined){ return v; }
+ v = d.style(node, p);
+ return (p=="opacity") ? Number(v) : (isColor ? v : parseFloat(v));
+ }
+ if(!("end" in prop)){
+ prop.end = getStyle(this.node, p);
+ }else if(!("start" in prop)){
+ prop.start = getStyle(this.node, p);
+ }
+
+ if(isColor){
+ prop.start = new d.Color(prop.start);
+ prop.end = new d.Color(prop.end);
+ }else{
+ prop.start = (p == "opacity") ? Number(prop.start) : parseFloat(prop.start);
+ }
+ }
+ this.curve = new PropLine(pm);
+ });
+ d.connect(anim, "onAnimate", anim, function(propValues){
+ // try{
+ for(var s in propValues){
+ d.style(this.node, s, propValues[s]);
+ // this.node.style[s] = propValues[s];
+ }
+ });
+ return anim; // dojo._Animation
+ }
+
+ dojo.anim = function( /*DOMNode|String*/ node,
+ /*Object*/ properties,
+ /*Integer?*/ duration,
+ /*Function?*/ easing,
+ /*Function?*/ onEnd,
+ /*Integer?*/ delay){
+ // summary:
+ // A simpler interface to `dojo.animateProperty()`, also returns
+ // an instance of `dojo._Animation` but begins the animation
+ // immediately, unlike nearly every other Dojo animation API.
+ // description:
+ // `dojo.anim` is a simpler (but somewhat less powerful) version
+ // of `dojo.animateProperty`. It uses defaults for many basic properties
+ // and allows for positional parameters to be used in place of the
+ // packed "property bag" which is used for other Dojo animation
+ // methods.
+ //
+ // The `dojo._Animation` object returned from `dojo.anim` will be
+ // already playing when it is returned from this function, so
+ // calling play() on it again is (usually) a no-op.
+ // node:
+ // a DOM node or the id of a node to animate CSS properties on
+ // duration:
+ // The number of milliseconds over which the animation
+ // should run. Defaults to the global animation default duration
+ // (350ms).
+ // easing:
+ // An easing function over which to calculate acceleration
+ // and deceleration of the animation through its duration.
+ // A default easing algorithm is provided, but you may
+ // plug in any you wish. A large selection of easing algorithms
+ // are available in `dojox.fx.easing`.
+ // onEnd:
+ // A function to be called when the animation finishes
+ // running.
+ // delay:
+ // The number of milliseconds to delay beginning the
+ // animation by. The default is 0.
+ // example:
+ // Fade out a node
+ // | dojo.anim("id", { opacity: 0 });
+ // example:
+ // Fade out a node over a full second
+ // | dojo.anim("id", { opacity: 0 }, 1000);
+ return d.animateProperty({
+ node: node,
+ duration: duration||d._Animation.prototype.duration,
+ properties: properties,
+ easing: easing,
+ onEnd: onEnd
+ }).play(delay||0);
+ }
+})();
+
+}
diff --git a/includes/js/dojo/_base/html.js b/includes/js/dojo/_base/html.js
new file mode 100644
index 0000000..d673eb1
--- /dev/null
+++ b/includes/js/dojo/_base/html.js
@@ -0,0 +1,1227 @@
+if(!dojo._hasResource["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.html"] = true;
+dojo.require("dojo._base.lang");
+dojo.provide("dojo._base.html");
+
+// FIXME: need to add unit tests for all the semi-public methods
+
+try{
+ document.execCommand("BackgroundImageCache", false, true);
+}catch(e){
+ // sane browsers don't have cache "issues"
+}
+
+// =============================
+// DOM Functions
+// =============================
+
+/*=====
+dojo.byId = function(id, doc){
+ // summary:
+ // Returns DOM node with matching `id` attribute or `null`
+ // if not found, similar to "$" function in another library.
+ // If `id` is a DomNode, this function is a no-op.
+ //
+ // id: String|DOMNode
+ // A string to match an HTML id attribute or a reference to a DOM Node
+ //
+ // doc: Document?
+ // Document to work in. Defaults to the current value of
+ // dojo.doc. Can be used to retrieve
+ // node references from other documents.
+=====*/
+if(dojo.isIE || dojo.isOpera){
+ dojo.byId = function(id, doc){
+ if(dojo.isString(id)){
+ var _d = doc || dojo.doc;
+ var te = _d.getElementById(id);
+ // attributes.id.value is better than just id in case the
+ // user has a name=id inside a form
+ if(te && te.attributes.id.value == id){
+ return te;
+ }else{
+ var eles = _d.all[id];
+ if(!eles || !eles.length){ return eles; }
+ // if more than 1, choose first with the correct id
+ var i=0;
+ while((te=eles[i++])){
+ if(te.attributes.id.value == id){ return te; }
+ }
+ }
+ }else{
+ return id; // DomNode
+ }
+ }
+}else{
+ dojo.byId = function(id, doc){
+ return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode
+ }
+}
+/*=====
+}
+=====*/
+
+(function(){
+ /*
+ dojo.createElement = function(obj, parent, position){
+ // TODO: need to finish this!
+ }
+ */
+
+ var d = dojo;
+
+ var _destroyContainer = null;
+ dojo.addOnUnload(function(){
+ _destroyContainer=null; //prevent IE leak
+ });
+ dojo._destroyElement = function(/*String||DomNode*/node){
+ // summary:
+ // removes node from its parent, clobbers it and all of its
+ // children.
+ // node:
+ // the element to be destroyed, either as an ID or a reference
+
+ node = d.byId(node);
+ try{
+ if(!_destroyContainer){
+ _destroyContainer = document.createElement("div");
+ }
+ _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node);
+ // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature
+ _destroyContainer.innerHTML = "";
+ }catch(e){
+ /* squelch */
+ }
+ };
+
+ dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){
+ // summary:
+ // Returns true if node is a descendant of ancestor
+ // node: id or node reference to test
+ // ancestor: id or node reference of potential parent to test against
+ try{
+ node = d.byId(node);
+ ancestor = d.byId(ancestor);
+ while(node){
+ if(node === ancestor){
+ return true; // Boolean
+ }
+ node = node.parentNode;
+ }
+ }catch(e){ /* squelch, return false */ }
+ return false; // Boolean
+ };
+
+ dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){
+ // summary: enable or disable selection on a node
+ // node:
+ // id or reference to node
+ // selectable:
+ node = d.byId(node);
+ if(d.isMozilla){
+ node.style.MozUserSelect = selectable ? "" : "none";
+ }else if(d.isKhtml){
+ node.style.KhtmlUserSelect = selectable ? "auto" : "none";
+ }else if(d.isIE){
+ node.unselectable = selectable ? "" : "on";
+ d.query("*", node).forEach(function(descendant){
+ descendant.unselectable = selectable ? "" : "on";
+ });
+ }
+ //FIXME: else? Opera?
+ };
+
+ var _insertBefore = function(/*Node*/node, /*Node*/ref){
+ ref.parentNode.insertBefore(node, ref);
+ return true; // boolean
+ }
+
+ var _insertAfter = function(/*Node*/node, /*Node*/ref){
+ // summary:
+ // Try to insert node after ref
+ var pn = ref.parentNode;
+ if(ref == pn.lastChild){
+ pn.appendChild(node);
+ }else{
+ return _insertBefore(node, ref.nextSibling); // boolean
+ }
+ return true; // boolean
+ }
+
+ dojo.place = function(/*String|DomNode*/node, /*String|DomNode*/refNode, /*String|Number*/position){
+ // summary:
+ // Attempt to insert node into the DOM, choosing from various positioning options.
+ // Returns true if successful, false otherwise.
+ // node:
+ // id or node reference to place relative to refNode
+ // refNode:
+ // id or node reference to use as basis for placement
+ // position:
+ // string noting the position of node relative to refNode or a
+ // number indicating the location in the childNodes collection of
+ // refNode. Accepted string values are:
+ //
+ // * before
+ // * after
+ // * first
+ // * last
+ //
+ // "first" and "last" indicate positions as children of refNode.
+
+ // FIXME: need to write tests for this!!!!
+ if(!node || !refNode || position === undefined){
+ return false; // boolean
+ }
+ node = d.byId(node);
+ refNode = d.byId(refNode);
+ if(typeof position == "number"){
+ var cn = refNode.childNodes;
+ if((position == 0 && cn.length == 0) ||
+ cn.length == position){
+ refNode.appendChild(node); return true;
+ }
+ if(position == 0){
+ return _insertBefore(node, refNode.firstChild);
+ }
+ return _insertAfter(node, cn[position-1]);
+ }
+ switch(position.toLowerCase()){
+ case "before":
+ return _insertBefore(node, refNode); // boolean
+ case "after":
+ return _insertAfter(node, refNode); // boolean
+ case "first":
+ if(refNode.firstChild){
+ return _insertBefore(node, refNode.firstChild); // boolean
+ }
+ // else fallthrough...
+ default: // aka: last
+ refNode.appendChild(node);
+ return true; // boolean
+ }
+ }
+
+ // Box functions will assume this model.
+ // On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode.
+ // Can be set to change behavior of box setters.
+
+ // can be either:
+ // "border-box"
+ // "content-box" (default)
+ dojo.boxModel = "content-box";
+
+ // We punt per-node box mode testing completely.
+ // If anybody cares, we can provide an additional (optional) unit
+ // that overrides existing code to include per-node box sensitivity.
+
+ // Opera documentation claims that Opera 9 uses border-box in BackCompat mode.
+ // but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box.
+ // IIRC, earlier versions of Opera did in fact use border-box.
+ // Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault.
+
+ if(d.isIE /*|| dojo.isOpera*/){
+ var _dcm = document.compatMode;
+ // client code may have to adjust if compatMode varies across iframes
+ d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE<6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support?
+ }
+
+ // =============================
+ // Style Functions
+ // =============================
+
+ // getComputedStyle drives most of the style code.
+ // Wherever possible, reuse the returned object.
+ //
+ // API functions below that need to access computed styles accept an
+ // optional computedStyle parameter.
+ // If this parameter is omitted, the functions will call getComputedStyle themselves.
+ // This way, calling code can access computedStyle once, and then pass the reference to
+ // multiple API functions.
+
+/*=====
+ dojo.getComputedStyle = function(node){
+ // summary:
+ // Returns a "computed style" object.
+ //
+ // description:
+ // Gets a "computed style" object which can be used to gather
+ // information about the current state of the rendered node.
+ //
+ // Note that this may behave differently on different browsers.
+ // Values may have different formats and value encodings across
+ // browsers.
+ //
+ // Note also that this method is expensive. Wherever possible,
+ // reuse the returned object.
+ //
+ // Use the dojo.style() method for more consistent (pixelized)
+ // return values.
+ //
+ // node: DOMNode
+ // A reference to a DOM node. Does NOT support taking an
+ // ID string for speed reasons.
+ // example:
+ // | dojo.getComputedStyle(dojo.byId('foo')).borderWidth;
+ return; // CSS2Properties
+ }
+=====*/
+
+ var gcs, dv = document.defaultView;
+ if(d.isSafari){
+ gcs = function(/*DomNode*/node){
+ var s = dv.getComputedStyle(node, null);
+ if(!s && node.style){
+ node.style.display = "";
+ s = dv.getComputedStyle(node, null);
+ }
+ return s || {};
+ };
+ }else if(d.isIE){
+ gcs = function(node){
+ return node.currentStyle;
+ };
+ }else{
+ gcs = function(node){
+ return dv.getComputedStyle(node, null);
+ };
+ }
+ dojo.getComputedStyle = gcs;
+
+ if(!d.isIE){
+ dojo._toPixelValue = function(element, value){
+ // style values can be floats, client code may want
+ // to round for integer pixels.
+ return parseFloat(value) || 0;
+ }
+ }else{
+ dojo._toPixelValue = function(element, avalue){
+ if(!avalue){ return 0; }
+ // on IE7, medium is usually 4 pixels
+ if(avalue=="medium"){ return 4; }
+ // style values can be floats, client code may
+ // want to round this value for integer pixels.
+ if(avalue.slice && (avalue.slice(-2)=='px')){ return parseFloat(avalue); }
+ with(element){
+ var sLeft = style.left;
+ var rsLeft = runtimeStyle.left;
+ runtimeStyle.left = currentStyle.left;
+ try{
+ // 'avalue' may be incompatible with style.left, which can cause IE to throw
+ // this has been observed for border widths using "thin", "medium", "thick" constants
+ // those particular constants could be trapped by a lookup
+ // but perhaps there are more
+ style.left = avalue;
+ avalue = style.pixelLeft;
+ }catch(e){
+ avalue = 0;
+ }
+ style.left = sLeft;
+ runtimeStyle.left = rsLeft;
+ }
+ return avalue;
+ }
+ }
+ var px = d._toPixelValue;
+
+ // FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
+ /*=====
+ dojo._getOpacity = function(node){
+ // summary:
+ // Returns the current opacity of the passed node as a
+ // floating-point value between 0 and 1.
+ // node: DomNode
+ // a reference to a DOM node. Does NOT support taking an
+ // ID string for speed reasons.
+ // return: Number between 0 and 1
+ }
+ =====*/
+
+ dojo._getOpacity = d.isIE ? function(node){
+ try{
+ return node.filters.alpha.opacity / 100; // Number
+ }catch(e){
+ return 1; // Number
+ }
+ } : function(node){
+ return gcs(node).opacity;
+ };
+
+ /*=====
+ dojo._setOpacity = function(node, opacity){
+ // summary:
+ // set the opacity of the passed node portably. Returns the
+ // new opacity of the node.
+ // node: DOMNode
+ // a reference to a DOM node. Does NOT support taking an
+ // ID string for performance reasons.
+ // opacity: Number
+ // A Number between 0 and 1. 0 specifies transparent.
+ // return: Number between 0 and 1
+ }
+ =====*/
+
+ dojo._setOpacity = d.isIE ? function(/*DomNode*/node, /*Number*/opacity){
+ if(opacity == 1){
+ // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so remove it altogether (bug #2661)
+ var filterRE = /FILTER:[^;]*;?/i;
+ node.style.cssText = node.style.cssText.replace(filterRE, "");
+ if(node.nodeName.toLowerCase() == "tr"){
+ d.query("> td", node).forEach(function(i){
+ i.style.cssText = i.style.cssText.replace(filterRE, "");
+ });
+ }
+ }else{
+ var o = "Alpha(Opacity="+ opacity * 100 +")";
+ node.style.filter = o;
+ }
+ if(node.nodeName.toLowerCase() == "tr"){
+ d.query("> td", node).forEach(function(i){
+ i.style.filter = o;
+ });
+ }
+ return opacity;
+ } : function(node, opacity){
+ return node.style.opacity = opacity;
+ };
+
+ var _pixelNamesCache = {
+ left: true, top: true
+ };
+ var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border
+ var _toStyleValue = function(node, type, value){
+ type = type.toLowerCase();
+ if(d.isIE && value == "auto"){
+ if(type == "height"){ return node.offsetHeight; }
+ if(type == "width"){ return node.offsetWidth; }
+ }
+ if(!(type in _pixelNamesCache)){
+ // if(dojo.isOpera && type == "cssText"){
+ // FIXME: add workaround for #2855 here
+ // }
+ _pixelNamesCache[type] = _pixelRegExp.test(type);
+ }
+ return _pixelNamesCache[type] ? px(node, value) : value;
+ }
+
+ var _floatStyle = d.isIE ? "styleFloat" : "cssFloat";
+ var _floatAliases = { "cssFloat": _floatStyle, "styleFloat": _floatStyle, "float": _floatStyle };
+
+ // public API
+
+ dojo.style = function( /*DomNode|String*/ node,
+ /*String?|Object?*/ style,
+ /*String?*/ value){
+ // summary:
+ // Accesses styles on a node. If 2 arguments are
+ // passed, acts as a getter. If 3 arguments are passed, acts
+ // as a setter.
+ // node:
+ // id or reference to node to get/set style for
+ // style:
+ // the style property to set in DOM-accessor format
+ // ("borderWidth", not "border-width") or an object with key/value
+ // pairs suitable for setting each property.
+ // value:
+ // If passed, sets value on the node for style, handling
+ // cross-browser concerns.
+ // example:
+ // Passing only an ID or node returns the computed style object of
+ // the node:
+ // | dojo.style("thinger");
+ // example:
+ // Passing a node and a style property returns the current
+ // normalized, computed value for that property:
+ // | dojo.style("thinger", "opacity"); // 1 by default
+ //
+ // example:
+ // Passing a node, a style property, and a value changes the
+ // current display of the node and returns the new computed value
+ // | dojo.style("thinger", "opacity", 0.5); // == 0.5
+ //
+ // example:
+ // Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node:
+ // | dojo.style("thinger", {
+ // | "opacity": 0.5,
+ // | "border": "3px solid black",
+ // | "height": 300
+ // | });
+ //
+ // example:
+ // When the CSS style property is hyphenated, the JavaScript property is camelCased.
+ // font-size becomes fontSize, and so on.
+ // | dojo.style("thinger",{
+ // | fontSize:"14pt",
+ // | letterSpacing:"1.2em"
+ // | });
+ //
+ // example:
+ // dojo.NodeList implements .style() using the same syntax, omitting the "node" parameter, calling
+ // dojo.style() on every element of the list. See: dojo.query and dojo.NodeList
+ // | dojo.query(".someClassName").style("visibility","hidden");
+ // | // or
+ // | dojo.query("#baz > div").style({
+ // | opacity:0.75,
+ // | fontSize:"13pt"
+ // | });
+
+ var n = d.byId(node), args = arguments.length, op = (style=="opacity");
+ style = _floatAliases[style] || style;
+ if(args == 3){
+ return op ? d._setOpacity(n, value) : n.style[style] = value; /*Number*/
+ }
+ if(args == 2 && op){
+ return d._getOpacity(n);
+ }
+ var s = gcs(n);
+ if(args == 2 && !d.isString(style)){
+ for(var x in style){
+ d.style(node, x, style[x]);
+ }
+ return s;
+ }
+ return (args == 1) ? s : _toStyleValue(n, style, s[style]); /* CSS2Properties||String||Number */
+ }
+
+ // =============================
+ // Box Functions
+ // =============================
+
+ dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+ // summary:
+ // Returns object with special values specifically useful for node
+ // fitting.
+ //
+ // * l/t = left/top padding (respectively)
+ // * w = the total of the left and right padding
+ // * h = the total of the top and bottom padding
+ //
+ // If 'node' has position, l/t forms the origin for child nodes.
+ // The w/h are used for calculating boxes.
+ // Normally application code will not need to invoke this
+ // directly, and will use the ...box... functions instead.
+ var
+ s = computedStyle||gcs(n),
+ l = px(n, s.paddingLeft),
+ t = px(n, s.paddingTop);
+ return {
+ l: l,
+ t: t,
+ w: l+px(n, s.paddingRight),
+ h: t+px(n, s.paddingBottom)
+ };
+ }
+
+ dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+ // summary:
+ // returns an object with properties useful for noting the border
+ // dimensions.
+ //
+ // * l/t = the sum of left/top border (respectively)
+ // * w = the sum of the left and right border
+ // * h = the sum of the top and bottom border
+ //
+ // The w/h are used for calculating boxes.
+ // Normally application code will not need to invoke this
+ // directly, and will use the ...box... functions instead.
+ var
+ ne = "none",
+ s = computedStyle||gcs(n),
+ bl = (s.borderLeftStyle != ne ? px(n, s.borderLeftWidth) : 0),
+ bt = (s.borderTopStyle != ne ? px(n, s.borderTopWidth) : 0);
+ return {
+ l: bl,
+ t: bt,
+ w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0),
+ h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0)
+ };
+ }
+
+ dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+ // summary:
+ // returns object with properties useful for box fitting with
+ // regards to padding.
+ //
+ // * l/t = the sum of left/top padding and left/top border (respectively)
+ // * w = the sum of the left and right padding and border
+ // * h = the sum of the top and bottom padding and border
+ //
+ // The w/h are used for calculating boxes.
+ // Normally application code will not need to invoke this
+ // directly, and will use the ...box... functions instead.
+ var
+ s = computedStyle||gcs(n),
+ p = d._getPadExtents(n, s),
+ b = d._getBorderExtents(n, s);
+ return {
+ l: p.l + b.l,
+ t: p.t + b.t,
+ w: p.w + b.w,
+ h: p.h + b.h
+ };
+ }
+
+ dojo._getMarginExtents = function(n, computedStyle){
+ // summary:
+ // returns object with properties useful for box fitting with
+ // regards to box margins (i.e., the outer-box).
+ //
+ // * l/t = marginLeft, marginTop, respectively
+ // * w = total width, margin inclusive
+ // * h = total height, margin inclusive
+ //
+ // The w/h are used for calculating boxes.
+ // Normally application code will not need to invoke this
+ // directly, and will use the ...box... functions instead.
+ var
+ s = computedStyle||gcs(n),
+ l = px(n, s.marginLeft),
+ t = px(n, s.marginTop),
+ r = px(n, s.marginRight),
+ b = px(n, s.marginBottom);
+ if(d.isSafari && (s.position != "absolute")){
+ // FIXME: Safari's version of the computed right margin
+ // is the space between our right edge and the right edge
+ // of our offsetParent.
+ // What we are looking for is the actual margin value as
+ // determined by CSS.
+ // Hack solution is to assume left/right margins are the same.
+ r = l;
+ }
+ return {
+ l: l,
+ t: t,
+ w: l+r,
+ h: t+b
+ };
+ }
+
+ // Box getters work in any box context because offsetWidth/clientWidth
+ // are invariant wrt box context
+ //
+ // They do *not* work for display: inline objects that have padding styles
+ // because the user agent ignores padding (it's bogus styling in any case)
+ //
+ // Be careful with IMGs because they are inline or block depending on
+ // browser and browser mode.
+
+ // Although it would be easier to read, there are not separate versions of
+ // _getMarginBox for each browser because:
+ // 1. the branching is not expensive
+ // 2. factoring the shared code wastes cycles (function call overhead)
+ // 3. duplicating the shared code wastes bytes
+
+ dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){
+ // summary:
+ // returns an object that encodes the width, height, left and top
+ // positions of the node's margin box.
+ var s = computedStyle||gcs(node), me = d._getMarginExtents(node, s);
+ var l = node.offsetLeft - me.l, t = node.offsetTop - me.t;
+ if(d.isMoz){
+ // Mozilla:
+ // If offsetParent has a computed overflow != visible, the offsetLeft is decreased
+ // by the parent's border.
+ // We don't want to compute the parent's style, so instead we examine node's
+ // computed left/top which is more stable.
+ var sl = parseFloat(s.left), st = parseFloat(s.top);
+ if(!isNaN(sl) && !isNaN(st)){
+ l = sl, t = st;
+ }else{
+ // If child's computed left/top are not parseable as a number (e.g. "auto"), we
+ // have no choice but to examine the parent's computed style.
+ var p = node.parentNode;
+ if(p && p.style){
+ var pcs = gcs(p);
+ if(pcs.overflow != "visible"){
+ var be = d._getBorderExtents(p, pcs);
+ l += be.l, t += be.t;
+ }
+ }
+ }
+ }else if(d.isOpera){
+ // On Opera, offsetLeft includes the parent's border
+ var p = node.parentNode;
+ if(p){
+ var be = d._getBorderExtents(p);
+ l -= be.l, t -= be.t;
+ }
+ }
+ return {
+ l: l,
+ t: t,
+ w: node.offsetWidth + me.w,
+ h: node.offsetHeight + me.h
+ };
+ }
+
+ dojo._getContentBox = function(node, computedStyle){
+ // summary:
+ // Returns an object that encodes the width, height, left and top
+ // positions of the node's content box, irrespective of the
+ // current box model.
+
+ // clientWidth/Height are important since the automatically account for scrollbars
+ // fallback to offsetWidth/Height for special cases (see #3378)
+ var s=computedStyle||gcs(node), pe=d._getPadExtents(node, s), be=d._getBorderExtents(node, s), w=node.clientWidth, h;
+ if(!w){
+ w=node.offsetWidth, h=node.offsetHeight;
+ }else{
+ h=node.clientHeight, be.w = be.h = 0;
+ }
+ // On Opera, offsetLeft includes the parent's border
+ if(d.isOpera){ pe.l += be.l; pe.t += be.t; };
+ return {
+ l: pe.l,
+ t: pe.t,
+ w: w - pe.w - be.w,
+ h: h - pe.h - be.h
+ };
+ }
+
+ dojo._getBorderBox = function(node, computedStyle){
+ var s=computedStyle||gcs(node), pe=d._getPadExtents(node, s), cb=d._getContentBox(node, s);
+ return {
+ l: cb.l - pe.l,
+ t: cb.t - pe.t,
+ w: cb.w + pe.w,
+ h: cb.h + pe.h
+ };
+ }
+
+ // Box setters depend on box context because interpretation of width/height styles
+ // vary wrt box context.
+ //
+ // The value of dojo.boxModel is used to determine box context.
+ // dojo.boxModel can be set directly to change behavior.
+ //
+ // Beware of display: inline objects that have padding styles
+ // because the user agent ignores padding (it's a bogus setup anyway)
+ //
+ // Be careful with IMGs because they are inline or block depending on
+ // browser and browser mode.
+ //
+ // Elements other than DIV may have special quirks, like built-in
+ // margins or padding, or values not detectable via computedStyle.
+ // In particular, margins on TABLE do not seems to appear
+ // at all in computedStyle on Mozilla.
+
+ dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){
+ // summary:
+ // sets width/height/left/top in the current (native) box-model
+ // dimentions. Uses the unit passed in u.
+ // node: DOM Node reference. Id string not supported for performance reasons.
+ // l: optional. left offset from parent.
+ // t: optional. top offset from parent.
+ // w: optional. width in current box model.
+ // h: optional. width in current box model.
+ // u: optional. unit measure to use for other measures. Defaults to "px".
+ u = u || "px";
+ var s = node.style;
+ if(!isNaN(l)){ s.left = l+u; }
+ if(!isNaN(t)){ s.top = t+u; }
+ if(w>=0){ s.width = w+u; }
+ if(h>=0){ s.height = h+u; }
+ }
+
+ dojo._usesBorderBox = function(/*DomNode*/node){
+ // summary:
+ // True if the node uses border-box layout.
+
+ // We could test the computed style of node to see if a particular box
+ // has been specified, but there are details and we choose not to bother.
+ var n = node.tagName;
+ // For whatever reason, TABLE and BUTTON are always border-box by default.
+ // If you have assigned a different box to either one via CSS then
+ // box functions will break.
+ return d.boxModel=="border-box" || n=="TABLE" || n=="BUTTON"; // boolean
+ }
+
+ dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){
+ // summary:
+ // Sets the size of the node's contents, irrespective of margins,
+ // padding, or borders.
+ if(d._usesBorderBox(node)){
+ var pb = d._getPadBorderExtents(node, computedStyle);
+ if(widthPx >= 0){ widthPx += pb.w; }
+ if(heightPx >= 0){ heightPx += pb.h; }
+ }
+ d._setBox(node, NaN, NaN, widthPx, heightPx);
+ }
+
+ dojo._setMarginBox = function(/*DomNode*/node, /*Number?*/leftPx, /*Number?*/topPx,
+ /*Number?*/widthPx, /*Number?*/heightPx,
+ /*Object*/computedStyle){
+ // summary:
+ // sets the size of the node's margin box and placement
+ // (left/top), irrespective of box model. Think of it as a
+ // passthrough to dojo._setBox that handles box-model vagaries for
+ // you.
+
+ var s = computedStyle||gcs(node);
+ // Some elements have special padding, margin, and box-model settings.
+ // To use box functions you may need to set padding, margin explicitly.
+ // Controlling box-model is harder, in a pinch you might set dojo.boxModel.
+ var bb=d._usesBorderBox(node),
+ pb=bb ? _nilExtents : d._getPadBorderExtents(node, s),
+ mb=d._getMarginExtents(node, s);
+ if(widthPx>=0){ widthPx = Math.max(widthPx - pb.w - mb.w, 0); }
+ if(heightPx>=0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); }
+ d._setBox(node, leftPx, topPx, widthPx, heightPx);
+ }
+
+ var _nilExtents = { l:0, t:0, w:0, h:0 };
+
+ // public API
+
+ dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){
+ // summary:
+ // Getter/setter for the margin-box of node.
+ // description:
+ // Returns an object in the expected format of box (regardless
+ // if box is passed). The object might look like:
+ // `{ l: 50, t: 200, w: 300: h: 150 }`
+ // for a node offset from its parent 50px to the left, 200px from
+ // the top with a margin width of 300px and a margin-height of
+ // 150px.
+ // node:
+ // id or reference to DOM Node to get/set box for
+ // box:
+ // If passed, denotes that dojo.marginBox() should
+ // update/set the margin box for node. Box is an object in the
+ // above format. All properties are optional if passed.
+ var n=d.byId(node), s=gcs(n), b=box;
+ return !b ? d._getMarginBox(n, s) : d._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object
+ }
+
+ dojo.contentBox = function(/*DomNode|String*/node, /*Object?*/box){
+ // summary:
+ // Getter/setter for the content-box of node.
+ // description:
+ // Returns an object in the expected format of box (regardless if box is passed).
+ // The object might look like:
+ // `{ l: 50, t: 200, w: 300: h: 150 }`
+ // for a node offset from its parent 50px to the left, 200px from
+ // the top with a content width of 300px and a content-height of
+ // 150px. Note that the content box may have a much larger border
+ // or margin box, depending on the box model currently in use and
+ // CSS values set/inherited for node.
+ // node:
+ // id or reference to DOM Node to get/set box for
+ // box:
+ // If passed, denotes that dojo.contentBox() should
+ // update/set the content box for node. Box is an object in the
+ // above format. All properties are optional if passed.
+ var n=dojo.byId(node), s=gcs(n), b=box;
+ return !b ? d._getContentBox(n, s) : d._setContentSize(n, b.w, b.h, s); // Object
+ }
+
+ // =============================
+ // Positioning
+ // =============================
+
+ var _sumAncestorProperties = function(node, prop){
+ if(!(node = (node||0).parentNode)){return 0};
+ var val, retVal = 0, _b = d.body();
+ while(node && node.style){
+ if(gcs(node).position == "fixed"){
+ return 0;
+ }
+ val = node[prop];
+ if(val){
+ retVal += val - 0;
+ // opera and khtml #body & #html has the same values, we only
+ // need one value
+ if(node == _b){ break; }
+ }
+ node = node.parentNode;
+ }
+ return retVal; // integer
+ }
+
+ dojo._docScroll = function(){
+ var
+ _b = d.body(),
+ _w = d.global,
+ de = d.doc.documentElement;
+ return {
+ y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0),
+ x: (_w.pageXOffset || d._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0)
+ };
+ };
+
+ dojo._isBodyLtr = function(){
+ //FIXME: could check html and body tags directly instead of computed style? need to ignore case, accept empty values
+ return !("_bodyLtr" in d) ?
+ d._bodyLtr = gcs(d.body()).direction == "ltr" :
+ d._bodyLtr; // Boolean
+ }
+
+ dojo._getIeDocumentElementOffset = function(){
+ // summary
+ // The following values in IE contain an offset:
+ // event.clientX
+ // event.clientY
+ // node.getBoundingClientRect().left
+ // node.getBoundingClientRect().top
+ // But other position related values do not contain this offset, such as
+ // node.offsetLeft, node.offsetTop, node.style.left and node.style.top.
+ // The offset is always (2, 2) in LTR direction. When the body is in RTL
+ // direction, the offset counts the width of left scroll bar's width.
+ // This function computes the actual offset.
+
+ //NOTE: assumes we're being called in an IE browser
+
+ var de = d.doc.documentElement;
+ //FIXME: use this instead? var de = d.compatMode == "BackCompat" ? d.body : d.documentElement;
+
+ return (d.isIE >= 7) ?
+ {x: de.getBoundingClientRect().left, y: de.getBoundingClientRect().top}
+ :
+ // IE 6.0
+ {x: d._isBodyLtr() || window.parent == window ?
+ de.clientLeft : de.offsetWidth - de.clientWidth - de.clientLeft,
+ y: de.clientTop}; // Object
+ };
+
+ dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){
+ // In RTL direction, scrollLeft should be a negative value, but IE
+ // returns a positive one. All codes using documentElement.scrollLeft
+ // must call this function to fix this error, otherwise the position
+ // will offset to right when there is a horizontal scrollbar.
+ var dd = d.doc;
+ if(d.isIE && !dojo._isBodyLtr()){
+ var de = dd.compatMode == "BackCompat" ? dd.body : dd.documentElement;
+ return scrollLeft + de.clientWidth - de.scrollWidth; // Integer
+ }
+ return scrollLeft; // Integer
+ }
+
+ dojo._abs = function(/*DomNode*/node, /*Boolean?*/includeScroll){
+ // summary:
+ // Gets the position of the passed element relative to
+ // the viewport (if includeScroll==false), or relative to the
+ // document root (if includeScroll==true).
+ //
+ // Returns an object of the form:
+ // { x: 100, y: 300 }
+ // if includeScroll is passed, the x and y values will include any
+ // document offsets that may affect the position relative to the
+ // viewport.
+
+ // FIXME: need to decide in the brave-new-world if we're going to be
+ // margin-box or border-box.
+ var ownerDocument = node.ownerDocument;
+ var ret = {
+ x: 0,
+ y: 0
+ };
+
+ // targetBoxType == "border-box"
+ var db = d.body();
+ if(d.isIE || (d.isFF >= 3)){
+ var client = node.getBoundingClientRect();
+ var offset = (d.isIE) ? d._getIeDocumentElementOffset() : { x: 0, y: 0};
+ ret.x = client.left - offset.x;
+ ret.y = client.top - offset.y;
+ }else if(ownerDocument["getBoxObjectFor"]){
+ // mozilla
+ var bo = ownerDocument.getBoxObjectFor(node),
+ b = d._getBorderExtents(node);
+ ret.x = bo.x - b.l - _sumAncestorProperties(node, "scrollLeft");
+ ret.y = bo.y - b.t - _sumAncestorProperties(node, "scrollTop");
+ }else{
+ if(node["offsetParent"]){
+ var endNode;
+ // in Safari, if the node is an absolutely positioned child of
+ // the body and the body has a margin the offset of the child
+ // and the body contain the body's margins, so we need to end
+ // at the body
+ // FIXME: getting contrary results to the above in latest WebKit.
+ if(d.isSafari &&
+ //(node.style.getPropertyValue("position") == "absolute") &&
+ (gcs(node).position == "absolute") &&
+ (node.parentNode == db)){
+ endNode = db;
+ }else{
+ endNode = db.parentNode;
+ }
+ if(node.parentNode != db){
+ var nd = node;
+ if(d.isOpera){ nd = db; }
+ ret.x -= _sumAncestorProperties(nd, "scrollLeft");
+ ret.y -= _sumAncestorProperties(nd, "scrollTop");
+ }
+ var curnode = node;
+ do{
+ var n = curnode.offsetLeft;
+ //FIXME: ugly hack to workaround the submenu in
+ //popupmenu2 does not shown up correctly in opera.
+ //Someone have a better workaround?
+ if(!d.isOpera || n > 0){
+ ret.x += isNaN(n) ? 0 : n;
+ }
+ var t = curnode.offsetTop;
+ ret.y += isNaN(t) ? 0 : t;
+ if(d.isSafari && curnode != node){
+ var cs = gcs(curnode);
+ ret.x += px(curnode, cs.borderLeftWidth);
+ ret.y += px(curnode, cs.borderTopWidth);
+ }
+ curnode = curnode.offsetParent;
+ }while((curnode != endNode) && curnode);
+ }else if(node.x && node.y){
+ ret.x += isNaN(node.x) ? 0 : node.x;
+ ret.y += isNaN(node.y) ? 0 : node.y;
+ }
+ }
+ // account for document scrolling
+ // if offsetParent is used, ret value already includes scroll position
+ // so we may have to actually remove that value if !includeScroll
+ if(includeScroll){
+ var scroll = d._docScroll();
+ ret.y += scroll.y;
+ ret.x += scroll.x;
+ }
+
+ return ret; // object
+ }
+
+ // FIXME: need a setter for coords or a moveTo!!
+ dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){
+ // summary:
+ // Returns an object that measures margin box width/height and
+ // absolute positioning data from dojo._abs().
+ //
+ // description:
+ // Returns an object that measures margin box width/height and
+ // absolute positioning data from dojo._abs().
+ // Return value will be in the form:
+ // `{ l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }`
+ // Does not act as a setter. If includeScroll is passed, the x and
+ // y params are affected as one would expect in dojo._abs().
+ var n=d.byId(node), s=gcs(n), mb=d._getMarginBox(n, s);
+ var abs = d._abs(n, includeScroll);
+ mb.x = abs.x;
+ mb.y = abs.y;
+ return mb;
+ }
+
+ // =============================
+ // Element attribute Functions
+ // =============================
+
+ var _fixAttrName = function(/*String*/name){
+ switch(name.toLowerCase()){
+ case "tabindex":
+ // Internet Explorer will only set or remove tabindex
+ // if it is spelled "tabIndex"
+ // console.debug((dojo.isIE && dojo.isIE < 8)? "tabIndex" : "tabindex");
+ return (d.isIE && d.isIE < 8) ? "tabIndex" : "tabindex";
+ default:
+ return name;
+ }
+ }
+
+ // non-deprecated HTML4 attributes with default values
+ // http://www.w3.org/TR/html401/index/attributes.html
+ // FF and Safari will return the default values if you
+ // access the attributes via a property but not
+ // via getAttribute()
+ var _attrProps = {
+ colspan: "colSpan",
+ enctype: "enctype",
+ frameborder: "frameborder",
+ method: "method",
+ rowspan: "rowSpan",
+ scrolling: "scrolling",
+ shape: "shape",
+ span: "span",
+ type: "type",
+ valuetype: "valueType"
+ }
+
+ dojo.hasAttr = function(/*DomNode|String*/node, /*String*/name){
+ // summary:
+ // Returns true if the requested attribute is specified on the
+ // given element, and false otherwise.
+ // node:
+ // id or reference to the element to check
+ // name:
+ // the name of the attribute
+ // returns:
+ // true if the requested attribute is specified on the
+ // given element, and false otherwise
+ var attr = d.byId(node).getAttributeNode(_fixAttrName(name));
+ return attr ? attr.specified : false; // Boolean
+ }
+
+ var _evtHdlrMap = {
+
+ }
+
+ var _ctr = 0;
+ var _attrId = dojo._scopeName + "attrid";
+
+ dojo.attr = function(/*DomNode|String*/node, /*String|Object*/name, /*String?*/value){
+ // summary:
+ // Gets or sets an attribute on an HTML element.
+ // description:
+ // Handles normalized getting and setting of attributes on DOM
+ // Nodes. If 2 arguments are passed, and a the second argumnt is a
+ // string, acts as a getter.
+ //
+ // If a third argument is passed, or if the second argumnt is a
+ // map of attributes, acts as a setter.
+ //
+ // When passing functions as values, note that they will not be
+ // directly assigned to slots on the node, but rather the default
+ // behavior will be removed and the new behavior will be added
+ // using `dojo.connect()`, meaning that event handler properties
+ // will be normalized and that some caveats with regards to
+ // non-standard behaviors for onsubmit apply. Namely that you
+ // should cancel form submission using `dojo.stopEvent()` on the
+ // passed event object instead of returning a boolean value from
+ // the handler itself.
+ // node:
+ // id or reference to the element to get or set the attribute on
+ // name:
+ // the name of the attribute to get or set.
+ // value:
+ // The value to set for the attribute
+ // returns:
+ // when used as a getter, the value of the requested attribute
+ // or null if that attribute does not have a specified or
+ // default value;
+ //
+ // when user as a setter, undefined
+ // example:
+ // | // get the current value of the "foo" attribute on a node
+ // | dojo.attr(dojo.byId("nodeId"), "foo");
+ // |
+ // | // we can just pass the id:
+ // | dojo.attr("nodeId", "foo");
+ // |
+ // | // use attr() to set the tab index
+ // | dojo.attr("nodeId", "tabindex", 3);
+ // |
+ // | // set multiple values at once, including event handlers:
+ // | dojo.attr("formId", {
+ // | "foo": "bar",
+ // | "tabindex": -1,
+ // | "method": "POST",
+ // | "onsubmit": function(e){
+ // | // stop submitting the form. Note that the IE behavior
+ // | // of returning true or false will have no effect here
+ // | // since our handler is connect()ed to the built-in
+ // | // onsubmit behavior and so we need to use
+ // | // dojo.stopEvent() to ensure that the submission
+ // | // doesn't proceed.
+ // | dojo.stopEvent(e);
+ // |
+ // | // submit the form with Ajax
+ // | dojo.xhrPost({ form: "formId" });
+ // | }
+ // | });
+
+ var args = arguments.length;
+ if(args == 2 && !d.isString(name)){
+ for(var x in name){ d.attr(node, x, name[x]); }
+ return;
+ }
+ node = d.byId(node);
+ name = _fixAttrName(name);
+ if(args == 3){
+ if(d.isFunction(value)){
+ // clobber if we can
+ var attrId = d.attr(node, _attrId);
+ if(!attrId){
+ attrId = _ctr++;
+ d.attr(node, _attrId, attrId);
+ }
+ if(!_evtHdlrMap[attrId]){
+ _evtHdlrMap[attrId] = {};
+ }
+ var h = _evtHdlrMap[attrId][name];
+ if(h){
+ d.disconnect(h);
+ }else{
+ try{
+ delete node[name];
+ }catch(e){}
+ }
+
+ // ensure that event objects are normalized, etc.
+ _evtHdlrMap[attrId][name] = d.connect(node, name, value);
+
+ }else if(typeof value == "boolean"){ // e.g. onsubmit, disabled
+ // if a function, we should normalize the event object here!!!
+ node[name] = value;
+ }else{
+ node.setAttribute(name, value);
+ }
+ return;
+ }else{
+ // should we access this attribute via a property or
+ // via getAttribute()?
+ var prop = _attrProps[name.toLowerCase()];
+ if(prop){
+ return node[prop];
+ }else{
+ var value = node[name];
+ return (typeof value == 'boolean' || typeof value == 'function') ? value : (d.hasAttr(node, name) ? node.getAttribute(name) : null);
+ }
+ }
+ }
+
+ dojo.removeAttr = function(/*DomNode|String*/node, /*String*/name){
+ // summary:
+ // Removes an attribute from an HTML element.
+ // node:
+ // id or reference to the element to remove the attribute from
+ // name:
+ // the name of the attribute to remove
+ d.byId(node).removeAttribute(_fixAttrName(name));
+ }
+})();
+
+// =============================
+// (CSS) Class Functions
+// =============================
+
+dojo.hasClass = function(/*DomNode|String*/node, /*String*/classStr){
+ // summary:
+ // Returns whether or not the specified classes are a portion of the
+ // class list currently applied to the node.
+ return ((" "+dojo.byId(node).className+" ").indexOf(" "+classStr+" ") >= 0); // Boolean
+};
+
+dojo.addClass = function(/*DomNode|String*/node, /*String*/classStr){
+ // summary:
+ // Adds the specified classes to the end of the class list on the
+ // passed node.
+ node = dojo.byId(node);
+ var cls = node.className;
+ if((" "+cls+" ").indexOf(" "+classStr+" ") < 0){
+ node.className = cls + (cls ? ' ' : '') + classStr;
+ }
+};
+
+dojo.removeClass = function(/*DomNode|String*/node, /*String*/classStr){
+ // summary: Removes the specified classes from node.
+ node = dojo.byId(node);
+ var t = dojo.trim((" " + node.className + " ").replace(" " + classStr + " ", " "));
+ if(node.className != t){ node.className = t; }
+};
+
+dojo.toggleClass = function(/*DomNode|String*/node, /*String*/classStr, /*Boolean?*/condition){
+ // summary:
+ // Adds a class to node if not present, or removes if present.
+ // Pass a boolean condition if you want to explicitly add or remove.
+ // condition:
+ // If passed, true means to add the class, false means to remove.
+ if(condition === undefined){
+ condition = !dojo.hasClass(node, classStr);
+ }
+ dojo[condition ? "addClass" : "removeClass"](node, classStr);
+};
+
+}
diff --git a/includes/js/dojo/_base/json.js b/includes/js/dojo/_base/json.js
new file mode 100644
index 0000000..55d8035
--- /dev/null
+++ b/includes/js/dojo/_base/json.js
@@ -0,0 +1,137 @@
+if(!dojo._hasResource["dojo._base.json"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.json"] = true;
+dojo.provide("dojo._base.json");
+
+dojo.fromJson = function(/*String*/ json){
+ // summary:
+ // Parses a [JSON](http://json.org) string to return a JavaScript object.
+ // json:
+ // a string literal of a JSON item, for instance:
+ // `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
+
+ return eval("(" + json + ")"); // Object
+}
+
+dojo._escapeString = function(/*String*/str){
+ //summary:
+ // Adds escape sequences for non-visual characters, double quote and
+ // backslash and surrounds with double quotes to form a valid string
+ // literal.
+ return ('"' + str.replace(/(["\\])/g, '\\$1') + '"').
+ replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n").
+ replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string
+}
+
+dojo.toJsonIndentStr = "\t";
+dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*String?*/ _indentStr){
+ // summary:
+ // Returns a [JSON](http://json.org) serialization of an object.
+ //
+ // description:
+ // Returns a [JSON](http://json.org) serialization of an object.
+ // Note that this doesn't check for infinite recursion, so don't do that!
+ //
+ // it:
+ // an object to be serialized. Objects may define their own
+ // serialization via a special "__json__" or "json" function
+ // property. If a specialized serializer has been defined, it will
+ // be used as a fallback.
+ //
+ // 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().
+ //
+ // _indentStr:
+ // private variable for recursive calls when pretty printing, do not use.
+
+ if(it === undefined){
+ return "undefined";
+ }
+ var objtype = typeof it;
+ if(objtype == "number" || objtype == "boolean"){
+ return it + "";
+ }
+ if(it === null){
+ return "null";
+ }
+ if(dojo.isString(it)){
+ return dojo._escapeString(it);
+ }
+ if(it.nodeType && it.cloneNode){ // isNode
+ return ""; // FIXME: would something like outerHTML be better here?
+ }
+ // recurse
+ var recurse = arguments.callee;
+ // short-circuit for objects that support "json" serialization
+ // if they return "self" then just pass-through...
+ var newObj;
+ _indentStr = _indentStr || "";
+ var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : "";
+ if(typeof it.__json__ == "function"){
+ newObj = it.__json__();
+ if(it !== newObj){
+ return recurse(newObj, prettyPrint, nextIndent);
+ }
+ }
+ if(typeof it.json == "function"){
+ newObj = it.json();
+ if(it !== newObj){
+ return recurse(newObj, prettyPrint, nextIndent);
+ }
+ }
+
+ var sep = prettyPrint ? " " : "";
+ var newLine = prettyPrint ? "\n" : "";
+
+ // array
+ if(dojo.isArray(it)){
+ var res = dojo.map(it, function(obj){
+ var val = recurse(obj, prettyPrint, nextIndent);
+ if(typeof val != "string"){
+ val = "undefined";
+ }
+ return newLine + nextIndent + val;
+ });
+ return "[" + res.join("," + sep) + newLine + _indentStr + "]";
+ }
+ /*
+ // look in the registry
+ try {
+ window.o = it;
+ newObj = dojo.json.jsonRegistry.match(it);
+ return recurse(newObj, prettyPrint, nextIndent);
+ }catch(e){
+ // console.debug(e);
+ }
+ // it's a function with no adapter, skip it
+ */
+ if(objtype == "function"){
+ return null; // null
+ }
+ // generic object code path
+ var output = [];
+ for(var key in it){
+ var keyStr;
+ if(typeof key == "number"){
+ keyStr = '"' + key + '"';
+ }else if(typeof key == "string"){
+ keyStr = dojo._escapeString(key);
+ }else{
+ // skip non-string or number keys
+ continue;
+ }
+ val = recurse(it[key], prettyPrint, nextIndent);
+ if(typeof val != "string"){
+ // skip non-serializable values
+ continue;
+ }
+ // FIXME: use += on Moz!!
+ // MOW NOTE: using += is a pain because you have to account for the dangling comma...
+ output.push(newLine + nextIndent + keyStr + ":" + sep + val);
+ }
+ return "{" + output.join("," + sep) + newLine + _indentStr + "}"; // String
+}
+
+}
diff --git a/includes/js/dojo/_base/lang.js b/includes/js/dojo/_base/lang.js
new file mode 100644
index 0000000..feedc21
--- /dev/null
+++ b/includes/js/dojo/_base/lang.js
@@ -0,0 +1,257 @@
+if(!dojo._hasResource["dojo._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.lang"] = true;
+dojo.provide("dojo._base.lang");
+
+// Crockford (ish) functions
+
+dojo.isString = function(/*anything*/ it){
+ // summary:
+ // Return true if it is a String
+ return !!arguments.length && it != null && (typeof it == "string" || it instanceof String); // Boolean
+}
+
+dojo.isArray = function(/*anything*/ it){
+ // summary:
+ // Return true if it is an Array
+ return it && (it instanceof Array || typeof it == "array"); // Boolean
+}
+
+/*=====
+dojo.isFunction = function(it){
+ // summary: Return true if it is a Function
+ // it: anything
+ // return: Boolean
+}
+=====*/
+
+dojo.isFunction = (function(){
+ var _isFunction = function(/*anything*/ it){
+ return it && (typeof it == "function" || it instanceof Function); // Boolean
+ };
+
+ return dojo.isSafari ?
+ // only slow this down w/ gratuitious casting in Safari since it's what's b0rken
+ function(/*anything*/ it){
+ if(typeof it == "function" && it == "[object NodeList]"){ return false; }
+ return _isFunction(it); // Boolean
+ } : _isFunction;
+})();
+
+dojo.isObject = function(/*anything*/ it){
+ // summary:
+ // Returns true if it is a JavaScript object (or an Array, a Function
+ // or null)
+ return it !== undefined &&
+ (it === null || typeof it == "object" || dojo.isArray(it) || dojo.isFunction(it)); // Boolean
+}
+
+dojo.isArrayLike = function(/*anything*/ it){
+ // summary:
+ // similar to dojo.isArray() but more permissive
+ // description:
+ // Doesn't strongly test for "arrayness". Instead, settles for "isn't
+ // a string or number and has a length property". Arguments objects
+ // and DOM collections will return true when passed to
+ // dojo.isArrayLike(), but will return false when passed to
+ // dojo.isArray().
+ // return:
+ // If it walks like a duck and quicks like a duck, return `true`
+ var d = dojo;
+ return it && it !== undefined &&
+ // keep out built-in constructors (Number, String, ...) which have length
+ // properties
+ !d.isString(it) && !d.isFunction(it) &&
+ !(it.tagName && it.tagName.toLowerCase() == 'form') &&
+ (d.isArray(it) || isFinite(it.length)); // Boolean
+}
+
+dojo.isAlien = function(/*anything*/ it){
+ // summary:
+ // Returns true if it is a built-in function or some other kind of
+ // oddball that *should* report as a function but doesn't
+ return it && !dojo.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
+}
+
+dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
+ // summary:
+ // Adds all properties and methods of props to constructor's
+ // prototype, making them available to all instances created with
+ // constructor.
+ for(var i=1, l=arguments.length; i<l; i++){
+ dojo._mixin(constructor.prototype, arguments[i]);
+ }
+ return constructor; // Object
+}
+
+dojo._hitchArgs = function(scope, method /*,...*/){
+ var pre = dojo._toArray(arguments, 2);
+ var named = dojo.isString(method);
+ return function(){
+ // arrayify arguments
+ var args = dojo._toArray(arguments);
+ // locate our method
+ var f = named ? (scope||dojo.global)[method] : method;
+ // invoke with collected args
+ return f && f.apply(scope || this, pre.concat(args)); // mixed
+ } // Function
+}
+
+dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){
+ // summary:
+ // Returns a function that will only ever execute in the a given scope.
+ // This allows for easy use of object member functions
+ // in callbacks and other places in which the "this" keyword may
+ // otherwise not reference the expected scope.
+ // Any number of default positional arguments may be passed as parameters
+ // beyond "method".
+ // Each of these values will be used to "placehold" (similar to curry)
+ // for the hitched function.
+ // scope:
+ // The scope to use when method executes. If method is a string,
+ // scope is also the object containing method.
+ // method:
+ // A function to be hitched to scope, or the name of the method in
+ // scope to be hitched.
+ // example:
+ // | dojo.hitch(foo, "bar")();
+ // runs foo.bar() in the scope of foo
+ // example:
+ // | dojo.hitch(foo, myFunction);
+ // returns a function that runs myFunction in the scope of foo
+ if(arguments.length > 2){
+ return dojo._hitchArgs.apply(dojo, arguments); // Function
+ }
+ if(!method){
+ method = scope;
+ scope = null;
+ }
+ if(dojo.isString(method)){
+ scope = scope || dojo.global;
+ if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
+ return function(){ return scope[method].apply(scope, arguments || []); }; // Function
+ }
+ return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function
+}
+
+/*=====
+dojo.delegate = function(obj, props){
+ // summary:
+ // returns a new object which "looks" to obj for properties which it
+ // does not have a value for. Optionally takes a bag of properties to
+ // seed the returned object with initially.
+ // description:
+ // This is a small implementaton of the Boodman/Crockford delegation
+ // pattern in JavaScript. An intermediate object constructor mediates
+ // the prototype chain for the returned object, using it to delegate
+ // down to obj for property lookup when object-local lookup fails.
+ // This can be thought of similarly to ES4's "wrap", save that it does
+ // not act on types but rather on pure objects.
+ // obj:
+ // The object to delegate to for properties not found directly on the
+ // return object or in props.
+ // props:
+ // an object containing properties to assign to the returned object
+ // returns:
+ // an Object of anonymous type
+ // example:
+ // | var foo = { bar: "baz" };
+ // | var thinger = dojo.delegate(foo, { thud: "xyzzy"});
+ // | thinger.bar == "baz"; // delegated to foo
+ // | foo.thud == undefined; // by definition
+ // | thinger.thud == "xyzzy"; // mixed in from props
+ // | foo.bar = "thonk";
+ // | thinger.bar == "thonk"; // still delegated to foo's bar
+}
+=====*/
+
+
+dojo.delegate = dojo._delegate = function(obj, props){
+
+ // boodman/crockford delegation
+ function TMP(){};
+ TMP.prototype = obj;
+ var tmp = new TMP();
+ if(props){
+ dojo.mixin(tmp, props);
+ }
+ return tmp; // Object
+}
+
+dojo.partial = function(/*Function|String*/method /*, ...*/){
+ // summary:
+ // similar to hitch() except that the scope object is left to be
+ // whatever the execution context eventually becomes.
+ // description:
+ // Calling dojo.partial is the functional equivalent of calling:
+ // | dojo.hitch(null, funcName, ...);
+ var arr = [ null ];
+ return dojo.hitch.apply(dojo, arr.concat(dojo._toArray(arguments))); // Function
+}
+
+dojo._toArray = function(/*Object*/obj, /*Number?*/offset, /*Array?*/ startWith){
+ // summary:
+ // Converts an array-like object (i.e. arguments, DOMCollection) to an
+ // array. Returns a new Array with the elements of obj.
+ // obj:
+ // the object to "arrayify". We expect the object to have, at a
+ // minimum, a length property which corresponds to integer-indexed
+ // properties.
+ // offset:
+ // the location in obj to start iterating from. Defaults to 0.
+ // Optional.
+ // startWith:
+ // An array to pack with the properties of obj. If provided,
+ // properties in obj are appended at the end of startWith and
+ // startWith is the returned array.
+ var arr = startWith||[];
+ for(var x = offset || 0; x < obj.length; x++){
+ arr.push(obj[x]);
+ }
+ return arr; // Array
+}
+
+dojo.clone = function(/*anything*/ o){
+ // summary:
+ // Clones objects (including DOM nodes) and all children.
+ // Warning: do not clone cyclic structures.
+ if(!o){ return o; }
+ if(dojo.isArray(o)){
+ var r = [];
+ for(var i = 0; i < o.length; ++i){
+ r.push(dojo.clone(o[i]));
+ }
+ return r; // Array
+ }
+ if(!dojo.isObject(o)){
+ return o; /*anything*/
+ }
+ if(o.nodeType && o.cloneNode){ // isNode
+ return o.cloneNode(true); // Node
+ }
+ if(o instanceof Date){
+ return new Date(o.getTime()); // Date
+ }
+ // Generic objects
+ var r = new o.constructor(); // specific to dojo.declare()'d classes!
+ for(var i in o){
+ if(!(i in r) || r[i] != o[i]){
+ r[i] = dojo.clone(o[i]);
+ }
+ }
+ return r; // Object
+}
+
+dojo.trim = function(/*String*/ str){
+ // summary:
+ // trims whitespaces from both sides of the string
+ // description:
+ // This version of trim() was selected for inclusion into the base due
+ // to its compact size and relatively good performance (see Steven
+ // Levithan's blog:
+ // http://blog.stevenlevithan.com/archives/faster-trim-javascript).
+ // The fastest but longest version of this function is located at
+ // dojo.string.trim()
+ return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // String
+}
+
+}
diff --git a/includes/js/dojo/_base/query.js b/includes/js/dojo/_base/query.js
new file mode 100644
index 0000000..8743df8
--- /dev/null
+++ b/includes/js/dojo/_base/query.js
@@ -0,0 +1,1191 @@
+if(!dojo._hasResource["dojo._base.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.query"] = true;
+dojo.provide("dojo._base.query");
+dojo.require("dojo._base.NodeList");
+
+/*
+ dojo.query() architectural overview:
+
+ dojo.query is a relatively full-featured CSS3 query library. It is
+ designed to take any valid CSS3 selector and return the nodes matching
+ the selector. To do this quickly, it processes queries in several
+ steps, applying caching where profitable.
+
+ The steps (roughly in reverse order of the way they appear in the code):
+ 1.) check to see if we already have a "query dispatcher"
+ - if so, use that with the given parameterization. Skip to step 4.
+ 2.) attempt to determine which branch to dispatch the query to:
+ - JS (optimized DOM iteration)
+ - xpath (for browsers that support it and where it's fast)
+ - native (not available in any browser yet)
+ 3.) tokenize and convert to executable "query dispatcher"
+ - this is where the lion's share of the complexity in the
+ system lies. In the DOM version, the query dispatcher is
+ assembled as a chain of "yes/no" test functions pertaining to
+ a section of a simple query statement (".blah:nth-child(odd)"
+ but not "div div", which is 2 simple statements). Individual
+ statement dispatchers are cached (to prevent re-definition)
+ as are entire dispatch chains (to make re-execution of the
+ same query fast)
+ - in the xpath path, tokenization yeilds a concatenation of
+ parameterized xpath selectors. As with the DOM version, both
+ simple selector blocks and overall evaluators are cached to
+ prevent re-defintion
+ 4.) the resulting query dispatcher is called in the passed scope (by default the top-level document)
+ - for DOM queries, this results in a recursive, top-down
+ evaluation of nodes based on each simple query section
+ - xpath queries can, thankfully, be executed in one shot
+ 5.) matched nodes are pruned to ensure they are unique
+*/
+
+;(function(){
+ // define everything in a closure for compressability reasons. "d" is an
+ // alias to "dojo" since it's so frequently used. This seems a
+ // transformation that the build system could perform on a per-file basis.
+
+ ////////////////////////////////////////////////////////////////////////
+ // Utility code
+ ////////////////////////////////////////////////////////////////////////
+
+ var d = dojo;
+ var childNodesName = dojo.isIE ? "children" : "childNodes";
+ var caseSensitive = false;
+
+ var getQueryParts = function(query){
+ // summary: state machine for query tokenization
+ if(">~+".indexOf(query.charAt(query.length-1)) >= 0){
+ query += " *"
+ }
+ query += " "; // ensure that we terminate the state machine
+
+ var ts = function(s, e){
+ return d.trim(query.slice(s, e));
+ }
+
+ // the overall data graph of the full query, as represented by queryPart objects
+ var qparts = [];
+ // state keeping vars
+ var inBrackets = -1;
+ var inParens = -1;
+ var inMatchFor = -1;
+ var inPseudo = -1;
+ var inClass = -1;
+ var inId = -1;
+ var inTag = -1;
+ var lc = ""; // the last character
+ var cc = ""; // the current character
+ var pStart;
+ // iteration vars
+ var x = 0; // index in the query
+ var ql = query.length;
+ var currentPart = null; // data structure representing the entire clause
+ var _cp = null; // the current pseudo or attr matcher
+
+ var endTag = function(){
+ if(inTag >= 0){
+ var tv = (inTag == x) ? null : ts(inTag, x).toLowerCase();
+ currentPart[ (">~+".indexOf(tv) < 0) ? "tag" : "oper" ] = tv;
+ inTag = -1;
+ }
+ }
+
+ var endId = function(){
+ if(inId >= 0){
+ currentPart.id = ts(inId, x).replace(/\\/g, "");
+ inId = -1;
+ }
+ }
+
+ var endClass = function(){
+ if(inClass >= 0){
+ currentPart.classes.push(ts(inClass+1, x).replace(/\\/g, ""));
+ inClass = -1;
+ }
+ }
+
+ var endAll = function(){
+ endId(); endTag(); endClass();
+ }
+
+ for(; lc=cc, cc=query.charAt(x),x<ql; x++){
+ if(lc == "\\"){ continue; }
+ if(!currentPart){
+ // NOTE: I hate all this alloc, but it's shorter than writing tons of if's
+ pStart = x;
+ currentPart = {
+ query: null,
+ pseudos: [],
+ attrs: [],
+ classes: [],
+ tag: null,
+ oper: null,
+ id: null
+ };
+ inTag = x;
+ }
+
+ if(inBrackets >= 0){
+ // look for a the close first
+ if(cc == "]"){
+ if(!_cp.attr){
+ _cp.attr = ts(inBrackets+1, x);
+ }else{
+ _cp.matchFor = ts((inMatchFor||inBrackets+1), x);
+ }
+ var cmf = _cp.matchFor;
+ if(cmf){
+ if( (cmf.charAt(0) == '"') || (cmf.charAt(0) == "'") ){
+ _cp.matchFor = cmf.substring(1, cmf.length-1);
+ }
+ }
+ currentPart.attrs.push(_cp);
+ _cp = null; // necessaray?
+ inBrackets = inMatchFor = -1;
+ }else if(cc == "="){
+ var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : "";
+ _cp.type = addToCc+cc;
+ _cp.attr = ts(inBrackets+1, x-addToCc.length);
+ inMatchFor = x+1;
+ }
+ // now look for other clause parts
+ }else if(inParens >= 0){
+ if(cc == ")"){
+ if(inPseudo >= 0){
+ _cp.value = ts(inParens+1, x);
+ }
+ inPseudo = inParens = -1;
+ }
+ }else if(cc == "#"){
+ endAll();
+ inId = x+1;
+ }else if(cc == "."){
+ endAll();
+ inClass = x;
+ }else if(cc == ":"){
+ endAll();
+ inPseudo = x;
+ }else if(cc == "["){
+ endAll();
+ inBrackets = x;
+ _cp = {
+ /*=====
+ attr: null, type: null, matchFor: null
+ =====*/
+ };
+ }else if(cc == "("){
+ if(inPseudo >= 0){
+ _cp = {
+ name: ts(inPseudo+1, x),
+ value: null
+ }
+ currentPart.pseudos.push(_cp);
+ }
+ inParens = x;
+ }else if(cc == " " && lc != cc){
+ // note that we expect the string to be " " terminated
+ endAll();
+ if(inPseudo >= 0){
+ currentPart.pseudos.push({ name: ts(inPseudo+1, x) });
+ }
+ currentPart.hasLoops = (
+ currentPart.pseudos.length ||
+ currentPart.attrs.length ||
+ currentPart.classes.length );
+ currentPart.query = ts(pStart, x);
+ currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
+ qparts.push(currentPart);
+ currentPart = null;
+ }
+ }
+ return qparts;
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // XPath query code
+ ////////////////////////////////////////////////////////////////////////
+
+ // this array is a lookup used to generate an attribute matching function.
+ // There is a similar lookup/generator list for the DOM branch with similar
+ // calling semantics.
+ var xPathAttrs = {
+ "*=": function(attr, value){
+ return "[contains(@"+attr+", '"+ value +"')]";
+ },
+ "^=": function(attr, value){
+ return "[starts-with(@"+attr+", '"+ value +"')]";
+ },
+ "$=": function(attr, value){
+ return "[substring(@"+attr+", string-length(@"+attr+")-"+(value.length-1)+")='"+value+"']";
+ },
+ "~=": function(attr, value){
+ return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
+ },
+ "|=": function(attr, value){
+ return "[contains(concat(' ',@"+attr+",' '), ' "+ value +"-')]";
+ },
+ "=": function(attr, value){
+ return "[@"+attr+"='"+ value +"']";
+ }
+ };
+
+ // takes a list of attribute searches, the overall query, a function to
+ // generate a default matcher, and a closure-bound method for providing a
+ // matching function that generates whatever type of yes/no distinguisher
+ // the query method needs. The method is a bit tortured and hard to read
+ // because it needs to be used in both the XPath and DOM branches.
+ var handleAttrs = function( attrList,
+ query,
+ getDefault,
+ handleMatch){
+ d.forEach(query.attrs, function(attr){
+ var matcher;
+ // type, attr, matchFor
+ if(attr.type && attrList[attr.type]){
+ matcher = attrList[attr.type](attr.attr, attr.matchFor);
+ }else if(attr.attr.length){
+ matcher = getDefault(attr.attr);
+ }
+ if(matcher){ handleMatch(matcher); }
+ });
+ }
+
+ var buildPath = function(query){
+ var xpath = ".";
+ var qparts = getQueryParts(d.trim(query));
+ while(qparts.length){
+ var tqp = qparts.shift();
+ var prefix;
+ var postfix = "";
+ if(tqp.oper == ">"){
+ prefix = "/";
+ // prefix = "/child::*";
+ tqp = qparts.shift();
+ }else if(tqp.oper == "~"){
+ prefix = "/following-sibling::"; // get element following siblings
+ tqp = qparts.shift();
+ }else if(tqp.oper == "+"){
+ // FIXME:
+ // fails when selecting subsequent siblings by node type
+ // because the position() checks the position in the list
+ // of matching elements and not the localized siblings
+ prefix = "/following-sibling::";
+ postfix = "[position()=1]";
+ tqp = qparts.shift();
+ }else{
+ prefix = "//";
+ // prefix = "/descendant::*"
+ }
+
+ // get the tag name (if any)
+
+ xpath += prefix + tqp.tag + postfix;
+
+ // check to see if it's got an id. Needs to come first in xpath.
+ if(tqp.id){
+ xpath += "[@id='"+tqp.id+"'][1]";
+ }
+
+ d.forEach(tqp.classes, function(cn){
+ var cnl = cn.length;
+ var padding = " ";
+ if(cn.charAt(cnl-1) == "*"){
+ padding = ""; cn = cn.substr(0, cnl-1);
+ }
+ xpath +=
+ "[contains(concat(' ',@class,' '), ' "+
+ cn + padding + "')]";
+ });
+
+ handleAttrs(xPathAttrs, tqp,
+ function(condition){
+ return "[@"+condition+"]";
+ },
+ function(matcher){
+ xpath += matcher;
+ }
+ );
+
+ // FIXME: need to implement pseudo-class checks!!
+ };
+ return xpath;
+ };
+
+ var _xpathFuncCache = {};
+ var getXPathFunc = function(path){
+ if(_xpathFuncCache[path]){
+ return _xpathFuncCache[path];
+ }
+
+ var doc = d.doc;
+ // don't need to memoize. The closure scope handles it for us.
+ var xpath = buildPath(path);
+
+ var tf = function(parent){
+ // XPath query strings are memoized.
+ var ret = [];
+ var xpathResult;
+ try{
+ xpathResult = doc.evaluate(xpath, parent, null,
+ // XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
+ XPathResult.ANY_TYPE, null);
+ }catch(e){
+ console.debug("failure in exprssion:", xpath, "under:", parent);
+ console.debug(e);
+ }
+ var result = xpathResult.iterateNext();
+ while(result){
+ ret.push(result);
+ result = xpathResult.iterateNext();
+ }
+ return ret;
+ }
+ return _xpathFuncCache[path] = tf;
+ };
+
+ /*
+ d.xPathMatch = function(query){
+ // XPath based DOM query system. Handles a small subset of CSS
+ // selectors, subset is identical to the non-XPath version of this
+ // function.
+
+ return getXPathFunc(query)();
+ }
+ */
+
+ ////////////////////////////////////////////////////////////////////////
+ // DOM query code
+ ////////////////////////////////////////////////////////////////////////
+
+ var _filtersCache = {};
+ var _simpleFiltersCache = {};
+
+ // the basic building block of the yes/no chaining system. agree(f1, f2)
+ // generates a new function which returns the boolean results of both of
+ // the passed functions to a single logical-anded result.
+ var agree = function(first, second){
+ if(!first){ return second; }
+ if(!second){ return first; }
+
+ return function(){
+ return first.apply(window, arguments) && second.apply(window, arguments);
+ }
+ }
+
+ var _childElements = function(root){
+ var ret = [];
+ var te, x=0, tret = root[childNodesName];
+ while(te=tret[x++]){
+ if(te.nodeType == 1){ ret.push(te); }
+ }
+ return ret;
+ }
+
+ var _nextSiblings = function(root, single){
+ var ret = [];
+ var te = root;
+ while(te = te.nextSibling){
+ if(te.nodeType == 1){
+ ret.push(te);
+ if(single){ break; }
+ }
+ }
+ return ret;
+ }
+
+ var _filterDown = function(element, queryParts, matchArr, idx){
+ // NOTE:
+ // in the fast path! this function is called recursively and for
+ // every run of a query.
+ var nidx = idx+1;
+ var isFinal = (queryParts.length == nidx);
+ var tqp = queryParts[idx];
+
+ // see if we can constrain our next level to direct children
+ if(tqp.oper){
+ var ecn = (tqp.oper == ">") ?
+ _childElements(element) :
+ _nextSiblings(element, (tqp.oper == "+"));
+
+ if(!ecn || !ecn.length){
+ return;
+ }
+ nidx++;
+ isFinal = (queryParts.length == nidx);
+ // kinda janky, too much array alloc
+ var tf = getFilterFunc(queryParts[idx+1]);
+ // for(var x=ecn.length-1, te; x>=0, te=ecn[x]; x--){
+ for(var x=0, ecnl=ecn.length, te; x<ecnl, te=ecn[x]; x++){
+ if(tf(te)){
+ if(isFinal){
+ matchArr.push(te);
+ }else{
+ _filterDown(te, queryParts, matchArr, nidx);
+ }
+ }
+ /*
+ if(x==0){
+ break;
+ }
+ */
+ }
+ }
+
+ // otherwise, keep going down, unless we'er at the end
+ var candidates = getElementsFunc(tqp)(element);
+ if(isFinal){
+ while(candidates.length){
+ matchArr.push(candidates.shift());
+ }
+ /*
+ candidates.unshift(0, matchArr.length-1);
+ matchArr.splice.apply(matchArr, candidates);
+ */
+ }else{
+ // if we're not yet at the bottom, keep going!
+ while(candidates.length){
+ _filterDown(candidates.shift(), queryParts, matchArr, nidx);
+ }
+ }
+ }
+
+ var filterDown = function(elements, queryParts){
+ var ret = [];
+
+ // for every root, get the elements that match the descendant selector
+ // for(var x=elements.length-1, te; x>=0, te=elements[x]; x--){
+ var x = elements.length - 1, te;
+ while(te = elements[x--]){
+ _filterDown(te, queryParts, ret, 0);
+ }
+ return ret;
+ }
+
+ var getFilterFunc = function(q){
+ // note: query can't have spaces!
+ if(_filtersCache[q.query]){
+ return _filtersCache[q.query];
+ }
+ var ff = null;
+
+ // does it have a tagName component?
+ if(q.tag){
+ if(q.tag == "*"){
+ ff = agree(ff,
+ function(elem){
+ return (elem.nodeType == 1);
+ }
+ );
+ }else{
+ // tag name match
+ ff = agree(ff,
+ function(elem){
+ return (
+ (elem.nodeType == 1) &&
+ (q.tag == elem.tagName.toLowerCase())
+ );
+ // return isTn;
+ }
+ );
+ }
+ }
+
+ // does the node have an ID?
+ if(q.id){
+ ff = agree(ff,
+ function(elem){
+ return (
+ (elem.nodeType == 1) &&
+ (elem.id == q.id)
+ );
+ }
+ );
+ }
+
+ if(q.hasLoops){
+ // if we have other query param parts, make sure we add them to the
+ // filter chain
+ ff = agree(ff, getSimpleFilterFunc(q));
+ }
+
+ return _filtersCache[q.query] = ff;
+ }
+
+ var getNodeIndex = function(node){
+ // NOTE:
+ // we could have a more accurate caching mechanism by invalidating
+ // caches after the query has finished, but I think that'd lead to
+ // significantly more cache churn than the cache would provide
+ // value for in the common case. Generally, we're more
+ // conservative (and therefore, more accurate) than jQuery and
+ // DomQuery WRT node node indexes, but there may be corner cases
+ // in which we fall down. How much we care about them is TBD.
+
+ var pn = node.parentNode;
+ var pnc = pn.childNodes;
+
+ // check to see if we can trust the cache. If not, re-key the whole
+ // thing and return our node match from that.
+
+ var nidx = -1;
+ var child = pn.firstChild;
+ if(!child){
+ return nidx;
+ }
+
+ var ci = node["__cachedIndex"];
+ var cl = pn["__cachedLength"];
+
+ // only handle cache building if we've gone out of sync
+ if(((typeof cl == "number")&&(cl != pnc.length))||(typeof ci != "number")){
+ // rip though the whole set, building cache indexes as we go
+ pn["__cachedLength"] = pnc.length;
+ var idx = 1;
+ do{
+ // we only assign indexes for nodes with nodeType == 1, as per:
+ // http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
+ // only elements are counted in the search order, and they
+ // begin at 1 for the first child's index
+
+ if(child === node){
+ nidx = idx;
+ }
+ if(child.nodeType == 1){
+ child["__cachedIndex"] = idx;
+ idx++;
+ }
+ child = child.nextSibling;
+ }while(child);
+ }else{
+ // NOTE:
+ // could be incorrect in some cases (node swaps involving the
+ // passed node, etc.), but we ignore those due to the relative
+ // unlikelihood of that occuring
+ nidx = ci;
+ }
+ return nidx;
+ }
+
+ var firedCount = 0;
+
+ var blank = "";
+ var _getAttr = function(elem, attr){
+ if(attr == "class"){
+ return elem.className || blank;
+ }
+ if(attr == "for"){
+ return elem.htmlFor || blank;
+ }
+ return elem.getAttribute(attr, 2) || blank;
+ }
+
+ var attrs = {
+ "*=": function(attr, value){
+ return function(elem){
+ // E[foo*="bar"]
+ // an E element whose "foo" attribute value contains
+ // the substring "bar"
+ return (_getAttr(elem, attr).indexOf(value)>=0);
+ }
+ },
+ "^=": function(attr, value){
+ // E[foo^="bar"]
+ // an E element whose "foo" attribute value begins exactly
+ // with the string "bar"
+ return function(elem){
+ return (_getAttr(elem, attr).indexOf(value)==0);
+ }
+ },
+ "$=": function(attr, value){
+ // E[foo$="bar"]
+ // an E element whose "foo" attribute value ends exactly
+ // with the string "bar"
+ var tval = " "+value;
+ return function(elem){
+ var ea = " "+_getAttr(elem, attr);
+ return (ea.lastIndexOf(value)==(ea.length-value.length));
+ }
+ },
+ "~=": function(attr, value){
+ // E[foo~="bar"]
+ // an E element whose "foo" attribute value is a list of
+ // space-separated values, one of which is exactly equal
+ // to "bar"
+
+ // return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
+ var tval = " "+value+" ";
+ return function(elem){
+ var ea = " "+_getAttr(elem, attr)+" ";
+ return (ea.indexOf(tval)>=0);
+ }
+ },
+ "|=": function(attr, value){
+ // E[hreflang|="en"]
+ // an E element whose "hreflang" attribute has a
+ // hyphen-separated list of values beginning (from the
+ // left) with "en"
+ var valueDash = " "+value+"-";
+ return function(elem){
+ var ea = " "+(elem.getAttribute(attr, 2) || "");
+ return (
+ (ea == value) ||
+ (ea.indexOf(valueDash)==0)
+ );
+ }
+ },
+ "=": function(attr, value){
+ return function(elem){
+ return (_getAttr(elem, attr) == value);
+ }
+ }
+ };
+
+ var pseudos = {
+ "first-child": function(name, condition){
+ return function(elem){
+ if(elem.nodeType != 1){ return false; }
+ // check to see if any of the previous siblings are elements
+ var fc = elem.previousSibling;
+ while(fc && (fc.nodeType != 1)){
+ fc = fc.previousSibling;
+ }
+ return (!fc);
+ }
+ },
+ "last-child": function(name, condition){
+ return function(elem){
+ if(elem.nodeType != 1){ return false; }
+ // check to see if any of the next siblings are elements
+ var nc = elem.nextSibling;
+ while(nc && (nc.nodeType != 1)){
+ nc = nc.nextSibling;
+ }
+ return (!nc);
+ }
+ },
+ "empty": function(name, condition){
+ return function(elem){
+ // DomQuery and jQuery get this wrong, oddly enough.
+ // The CSS 3 selectors spec is pretty explicit about
+ // it, too.
+ var cn = elem.childNodes;
+ var cnl = elem.childNodes.length;
+ // if(!cnl){ return true; }
+ for(var x=cnl-1; x >= 0; x--){
+ var nt = cn[x].nodeType;
+ if((nt == 1)||(nt == 3)){ return false; }
+ }
+ return true;
+ }
+ },
+ "contains": function(name, condition){
+ return function(elem){
+ // FIXME: I dislike this version of "contains", as
+ // whimsical attribute could set it off. An inner-text
+ // based version might be more accurate, but since
+ // jQuery and DomQuery also potentially get this wrong,
+ // I'm leaving it for now.
+ return (elem.innerHTML.indexOf(condition) >= 0);
+ }
+ },
+ "not": function(name, condition){
+ var ntf = getFilterFunc(getQueryParts(condition)[0]);
+ return function(elem){
+ return (!ntf(elem));
+ }
+ },
+ "nth-child": function(name, condition){
+ var pi = parseInt;
+ if(condition == "odd"){
+ return function(elem){
+ return (
+ ((getNodeIndex(elem)) % 2) == 1
+ );
+ }
+ }else if((condition == "2n")||
+ (condition == "even")){
+ return function(elem){
+ return ((getNodeIndex(elem) % 2) == 0);
+ }
+ }else if(condition.indexOf("0n+") == 0){
+ var ncount = pi(condition.substr(3));
+ return function(elem){
+ return (elem.parentNode[childNodesName][ncount-1] === elem);
+ }
+ }else if( (condition.indexOf("n+") > 0) &&
+ (condition.length > 3) ){
+ var tparts = condition.split("n+", 2);
+ var pred = pi(tparts[0]);
+ var idx = pi(tparts[1]);
+ return function(elem){
+ return ((getNodeIndex(elem) % pred) == idx);
+ }
+ }else if(condition.indexOf("n") == -1){
+ var ncount = pi(condition);
+ return function(elem){
+ return (getNodeIndex(elem) == ncount);
+ }
+ }
+ }
+ };
+
+ var defaultGetter = (d.isIE) ? function(cond){
+ var clc = cond.toLowerCase();
+ return function(elem){
+ return elem[cond]||elem[clc];
+ }
+ } : function(cond){
+ return function(elem){
+ return (elem && elem.getAttribute && elem.hasAttribute(cond));
+ }
+ };
+
+ var getSimpleFilterFunc = function(query){
+
+ var fcHit = (_simpleFiltersCache[query.query]||_filtersCache[query.query]);
+ if(fcHit){ return fcHit; }
+
+ var ff = null;
+
+ // the only case where we'll need the tag name is if we came from an ID query
+ if(query.id){ // do we have an ID component?
+ if(query.tag != "*"){
+ ff = agree(ff, function(elem){
+ return (elem.tagName.toLowerCase() == query.tag);
+ });
+ }
+ }
+
+ // if there's a class in our query, generate a match function for it
+ d.forEach(query.classes, function(cname, idx, arr){
+ // get the class name
+ var isWildcard = cname.charAt(cname.length-1) == "*";
+ if(isWildcard){
+ cname = cname.substr(0, cname.length-1);
+ }
+ // I dislike the regex thing, even if memozied in a cache, but it's VERY short
+ var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
+ ff = agree(ff, function(elem){
+ return re.test(elem.className);
+ });
+ ff.count = idx;
+ });
+
+ d.forEach(query.pseudos, function(pseudo){
+ if(pseudos[pseudo.name]){
+ ff = agree(ff, pseudos[pseudo.name](pseudo.name, pseudo.value));
+ }
+ });
+
+ handleAttrs(attrs, query, defaultGetter,
+ function(tmatcher){ ff = agree(ff, tmatcher); }
+ );
+ if(!ff){
+ ff = function(){ return true; };
+ }
+ return _simpleFiltersCache[query.query] = ff;
+ }
+
+ var _getElementsFuncCache = { };
+
+ var getElementsFunc = function(query, root){
+ var fHit = _getElementsFuncCache[query.query];
+ if(fHit){ return fHit; }
+
+ // NOTE: this function is in the fast path! not memoized!!!
+
+ // the query doesn't contain any spaces, so there's only so many
+ // things it could be
+
+ if(query.id && !query.hasLoops && !query.tag){
+ // ID-only query. Easy.
+ return _getElementsFuncCache[query.query] = function(root){
+ // FIXME: if root != document, check for parenting!
+ return [ d.byId(query.id) ];
+ }
+ }
+
+ var filterFunc = getSimpleFilterFunc(query);
+
+ var retFunc;
+ if(query.tag && query.id && !query.hasLoops){
+ // we got a filtered ID search (e.g., "h4#thinger")
+ retFunc = function(root){
+ var te = d.byId(query.id);
+ if(filterFunc(te)){
+ return [ te ];
+ }
+ }
+ }else{
+ var tret;
+
+ if(!query.hasLoops){
+ // it's just a plain-ol elements-by-tag-name query from the root
+ retFunc = function(root){
+ var ret = [];
+ var te, x=0, tret = root.getElementsByTagName(query.tag);
+ while(te=tret[x++]){
+ ret.push(te);
+ }
+ return ret;
+ }
+ }else{
+ retFunc = function(root){
+ var ret = [];
+ var te, x=0, tret = root.getElementsByTagName(query.tag);
+ while(te=tret[x++]){
+ if(filterFunc(te)){
+ ret.push(te);
+ }
+ }
+ return ret;
+ }
+ }
+ }
+ return _getElementsFuncCache[query.query] = retFunc;
+ }
+
+ var _partsCache = {};
+
+ ////////////////////////////////////////////////////////////////////////
+ // the query runner
+ ////////////////////////////////////////////////////////////////////////
+
+ // this is the second level of spliting, from full-length queries (e.g.,
+ // "div.foo .bar") into simple query expressions (e.g., ["div.foo",
+ // ".bar"])
+ var _queryFuncCache = {
+ "*": d.isIE ?
+ function(root){
+ return root.all;
+ } :
+ function(root){
+ return root.getElementsByTagName("*");
+ },
+ "~": _nextSiblings,
+ "+": function(root){ return _nextSiblings(root, true); },
+ ">": _childElements
+ };
+
+ var getStepQueryFunc = function(query){
+ // if it's trivial, get a fast-path dispatcher
+ var qparts = getQueryParts(d.trim(query));
+ // if(query[query.length-1] == ">"){ query += " *"; }
+ if(qparts.length == 1){
+ var tt = getElementsFunc(qparts[0]);
+ tt.nozip = true;
+ return tt;
+ }
+
+ // otherwise, break it up and return a runner that iterates over the parts recursively
+ var sqf = function(root){
+ var localQueryParts = qparts.slice(0); // clone the src arr
+ var candidates;
+ if(localQueryParts[0].oper == ">"){ // FIXME: what if it's + or ~?
+ candidates = [ root ];
+ // root = document;
+ }else{
+ candidates = getElementsFunc(localQueryParts.shift())(root);
+ }
+ return filterDown(candidates, localQueryParts);
+ }
+ return sqf;
+ }
+
+ // a specialized method that implements our primoridal "query optimizer".
+ // This allows us to dispatch queries to the fastest subsystem we can get.
+ var _getQueryFunc = (
+ // NOTE:
+ // XPath on the Webkit nighlies is slower than it's DOM iteration
+ // for most test cases
+ // FIXME:
+ // we should try to capture some runtime speed data for each query
+ // function to determine on the fly if we should stick w/ the
+ // potentially optimized variant or if we should try something
+ // new.
+ (document["evaluate"] && !d.isSafari) ?
+ function(query){
+ // has xpath support that's faster than DOM
+ var qparts = query.split(" ");
+ // can we handle it?
+ if( (document["evaluate"])&&
+ (query.indexOf(":") == -1)&&
+ (query.indexOf("+") == -1) // skip direct sibling matches. See line ~344
+ ){
+ // dojo.debug(query);
+ // should we handle it?
+
+ // kind of a lame heuristic, but it works
+ if(
+ // a "div div div" style query
+ ((qparts.length > 2)&&(query.indexOf(">") == -1))||
+ // or something else with moderate complexity. kinda janky
+ (qparts.length > 3)||
+ (query.indexOf("[")>=0)||
+ // or if it's a ".thinger" query
+ ((1 == qparts.length)&&(0 <= query.indexOf(".")))
+
+ ){
+ // use get and cache a xpath runner for this selector
+ return getXPathFunc(query);
+ }
+ }
+
+ // fallthrough
+ return getStepQueryFunc(query);
+ } : getStepQueryFunc
+ );
+ // uncomment to disable XPath for testing and tuning the DOM path
+ // _getQueryFunc = getStepQueryFunc;
+
+ // FIXME: we've got problems w/ the NodeList query()/filter() functions if we go XPath for everything
+
+ // uncomment to disable DOM queries for testing and tuning XPath
+ // _getQueryFunc = getXPathFunc;
+
+ // this is the primary caching for full-query results. The query dispatcher
+ // functions are generated here and then pickled for hash lookup in the
+ // future
+ var getQueryFunc = function(query){
+ // return a cached version if one is available
+ var qcz = query.charAt(0);
+ if(d.doc["querySelectorAll"] &&
+ ( (!d.isSafari) || (d.isSafari > 3.1) ) && // see #5832
+ // as per CSS 3, we can't currently start w/ combinator:
+ // http://www.w3.org/TR/css3-selectors/#w3cselgrammar
+ (">+~".indexOf(qcz) == -1)
+ ){
+ return function(root){
+ var r = root.querySelectorAll(query);
+ r.nozip = true; // skip expensive duplication checks and just wrap in a NodeList
+ return r;
+ };
+ }
+ if(_queryFuncCache[query]){ return _queryFuncCache[query]; }
+ if(0 > query.indexOf(",")){
+ // if it's not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
+ return _queryFuncCache[query] = _getQueryFunc(query);
+ }else{
+ // if it's a complex query, break it up into it's constituent parts
+ // and return a dispatcher that will merge the parts when run
+
+ // var parts = query.split(", ");
+ var parts = query.split(/\s*,\s*/);
+ var tf = function(root){
+ var pindex = 0; // avoid array alloc for every invocation
+ var ret = [];
+ var tp;
+ while(tp = parts[pindex++]){
+ ret = ret.concat(_getQueryFunc(tp, tp.indexOf(" "))(root));
+ }
+ return ret;
+ }
+ // ...cache and return
+ return _queryFuncCache[query] = tf;
+ }
+ }
+
+ // FIXME:
+ // Dean's Base2 uses a system whereby queries themselves note if
+ // they'll need duplicate filtering. We need to get on that plan!!
+
+ // attempt to efficiently determine if an item in a list is a dupe,
+ // returning a list of "uniques", hopefully in doucment order
+ var _zipIdx = 0;
+ var _zip = function(arr){
+ if(arr && arr.nozip){ return d.NodeList._wrap(arr); }
+ var ret = new d.NodeList();
+ if(!arr){ return ret; }
+ if(arr[0]){
+ ret.push(arr[0]);
+ }
+ if(arr.length < 2){ return ret; }
+ _zipIdx++;
+ arr[0]["_zipIdx"] = _zipIdx;
+ for(var x=1, te; te = arr[x]; x++){
+ if(arr[x]["_zipIdx"] != _zipIdx){
+ ret.push(te);
+ }
+ te["_zipIdx"] = _zipIdx;
+ }
+ // FIXME: should we consider stripping these properties?
+ return ret;
+ }
+
+ // the main executor
+ d.query = function(/*String*/ query, /*String|DOMNode?*/ root){
+ // summary:
+ // Returns nodes which match the given CSS3 selector, searching the
+ // entire document by default but optionally taking a node to scope
+ // the search by. Returns an instance of dojo.NodeList.
+ // description:
+ // dojo.query() is the swiss army knife of DOM node manipulation in
+ // Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's
+ // "$" function, dojo.query provides robust, high-performance
+ // CSS-based node selector support with the option of scoping searches
+ // to a particular sub-tree of a document.
+ //
+ // Supported Selectors:
+ // --------------------
+ //
+ // dojo.query() supports a rich set of CSS3 selectors, including:
+ //
+ // * class selectors (e.g., `.foo`)
+ // * node type selectors like `span`
+ // * ` ` descendant selectors
+ // * `>` child element selectors
+ // * `#foo` style ID selectors
+ // * `*` universal selector
+ // * `~`, the immediately preceeded-by sibling selector
+ // * `+`, the preceeded-by sibling selector
+ // * attribute queries:
+ // | * `[foo]` attribute presence selector
+ // | * `[foo='bar']` attribute value exact match
+ // | * `[foo~='bar']` attribute value list item match
+ // | * `[foo^='bar']` attribute start match
+ // | * `[foo$='bar']` attribute end match
+ // | * `[foo*='bar']` attribute substring match
+ // * `:first-child`, `:last-child` positional selectors
+ // * `:empty` content emtpy selector
+ // * `:empty` content emtpy selector
+ // * `:nth-child(n)`, `:nth-child(2n+1)` style positional calculations
+ // * `:nth-child(even)`, `:nth-child(odd)` positional selectors
+ // * `:not(...)` negation pseudo selectors
+ //
+ // Any legal combination of these selectors will work with
+ // `dojo.query()`, including compound selectors ("," delimited).
+ // Very complex and useful searches can be constructed with this
+ // palette of selectors and when combined with functions for
+ // maniplation presented by dojo.NodeList, many types of DOM
+ // manipulation operations become very straightforward.
+ //
+ // Unsupported Selectors:
+ // ----------------------
+ //
+ // While dojo.query handles many CSS3 selectors, some fall outside of
+ // what's resaonable for a programmatic node querying engine to
+ // handle. Currently unsupported selectors include:
+ //
+ // * namespace-differentiated selectors of any form
+ // * all `::` pseduo-element selectors
+ // * certain pseduo-selectors which don't get a lot of day-to-day use:
+ // | * `:root`, `:lang()`, `:target`, `:focus`
+ // * all visual and state selectors:
+ // | * `:root`, `:active`, `:hover`, `:visisted`, `:link`,
+ // `:enabled`, `:disabled`, `:checked`
+ // * `:*-of-type` pseudo selectors
+ //
+ // dojo.query and XML Documents:
+ // -----------------------------
+ //
+ // `dojo.query` currently only supports searching XML documents
+ // whose tags and attributes are 100% lower-case. This is a known
+ // limitation and will [be addressed soon](http://trac.dojotoolkit.org/ticket/3866)
+ // Non-selector Queries:
+ // ---------------------
+ //
+ // If something other than a String is passed for the query,
+ // `dojo.query` will return a new `dojo.NodeList` constructed from
+ // that parameter alone and all further processing will stop. This
+ // means that if you have a reference to a node or NodeList, you
+ // can quickly construct a new NodeList from the original by
+ // calling `dojo.query(node)` or `dojo.query(list)`.
+ //
+ // query:
+ // The CSS3 expression to match against. For details on the syntax of
+ // CSS3 selectors, see <http://www.w3.org/TR/css3-selectors/#selectors>
+ // root:
+ // A DOMNode (or node id) to scope the search from. Optional.
+ // returns: dojo.NodeList
+ // An instance of `dojo.NodeList`. Many methods are available on
+ // NodeLists for searching, iterating, manipulating, and handling
+ // events on the matched nodes in the returned list.
+ // example:
+ // search the entire document for elements with the class "foo":
+ // | dojo.query(".foo");
+ // these elements will match:
+ // | <span class="foo"></span>
+ // | <span class="foo bar"></span>
+ // | <p class="thud foo"></p>
+ // example:
+ // search the entire document for elements with the classes "foo" *and* "bar":
+ // | dojo.query(".foo.bar");
+ // these elements will match:
+ // | <span class="foo bar"></span>
+ // while these will not:
+ // | <span class="foo"></span>
+ // | <p class="thud foo"></p>
+ // example:
+ // find `<span>` elements which are descendants of paragraphs and
+ // which have a "highlighted" class:
+ // | dojo.query("p span.highlighted");
+ // the innermost span in this fragment matches:
+ // | <p class="foo">
+ // | <span>...
+ // | <span class="highlighted foo bar">...</span>
+ // | </span>
+ // | </p>
+ // example:
+ // set an "odd" class on all odd table rows inside of the table
+ // `#tabular_data`, using the `>` (direct child) selector to avoid
+ // affecting any nested tables:
+ // | dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
+ // example:
+ // remove all elements with the class "error" from the document
+ // and store them in a list:
+ // | var errors = dojo.query(".error").orphan();
+ // example:
+ // add an onclick handler to every submit button in the document
+ // which causes the form to be sent via Ajax instead:
+ // | dojo.query("input[type='submit']").onclick(function(e){
+ // | dojo.stopEvent(e); // prevent sending the form
+ // | var btn = e.target;
+ // | dojo.xhrPost({
+ // | form: btn.form,
+ // | load: function(data){
+ // | // replace the form with the response
+ // | var div = dojo.doc.createElement("div");
+ // | dojo.place(div, btn.form, "after");
+ // | div.innerHTML = data;
+ // | dojo.style(btn.form, "display", "none");
+ // | }
+ // | });
+ // | });
+
+
+ // NOTE: elementsById is not currently supported
+ // NOTE: ignores xpath-ish queries for now
+
+ if(query.constructor == d.NodeList){
+ return query;
+ }
+ if(!d.isString(query)){
+ return new d.NodeList(query); // dojo.NodeList
+ }
+ if(d.isString(root)){
+ root = d.byId(root);
+ }
+
+ return _zip(getQueryFunc(query)(root||d.doc)); // dojo.NodeList
+ }
+
+ /*
+ // exposing this was a mistake
+ d.query.attrs = attrs;
+ */
+ // exposing this because new pseudo matches are only executed through the
+ // DOM query path (never through the xpath optimizing branch)
+ d.query.pseudos = pseudos;
+
+ // one-off function for filtering a NodeList based on a simple selector
+ d._filterQueryResult = function(nodeList, simpleFilter){
+ var tnl = new d.NodeList();
+ var ff = (simpleFilter) ? getFilterFunc(getQueryParts(simpleFilter)[0]) : function(){ return true; };
+ for(var x=0, te; te = nodeList[x]; x++){
+ if(ff(te)){ tnl.push(te); }
+ }
+ return tnl;
+ }
+})();
+
+}
diff --git a/includes/js/dojo/_base/window.js b/includes/js/dojo/_base/window.js
new file mode 100644
index 0000000..892768d
--- /dev/null
+++ b/includes/js/dojo/_base/window.js
@@ -0,0 +1,145 @@
+if(!dojo._hasResource["dojo._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.window"] = true;
+dojo.provide("dojo._base.window");
+
+dojo._gearsObject = function(){
+ // summary:
+ // factory method to get a Google Gears plugin instance to
+ // expose in the browser runtime environment, if present
+ var factory;
+ var results;
+
+ var gearsObj = dojo.getObject("google.gears");
+ if(gearsObj){ return gearsObj; } // already defined elsewhere
+
+ if(typeof GearsFactory != "undefined"){ // Firefox
+ factory = new GearsFactory();
+ }else{
+ if(dojo.isIE){
+ // IE
+ try{
+ factory = new ActiveXObject("Gears.Factory");
+ }catch(e){
+ // ok to squelch; there's no gears factory. move on.
+ }
+ }else if(navigator.mimeTypes["application/x-googlegears"]){
+ // Safari?
+ factory = document.createElement("object");
+ factory.setAttribute("type", "application/x-googlegears");
+ factory.setAttribute("width", 0);
+ factory.setAttribute("height", 0);
+ factory.style.display = "none";
+ document.documentElement.appendChild(factory);
+ }
+ }
+
+ // still nothing?
+ if(!factory){ return null; }
+
+ // define the global objects now; don't overwrite them though if they
+ // were somehow set internally by the Gears plugin, which is on their
+ // dev roadmap for the future
+ dojo.setObject("google.gears.factory", factory);
+ return dojo.getObject("google.gears");
+};
+
+/*=====
+dojo.isGears = {
+ // summary: True if client is using Google Gears
+};
+=====*/
+// see if we have Google Gears installed, and if
+// so, make it available in the runtime environment
+// and in the Google standard 'google.gears' global object
+dojo.isGears = (!!dojo._gearsObject())||0;
+
+/*=====
+dojo.doc = {
+ // summary:
+ // Alias for the current document. 'dojo.doc' can be modified
+ // for temporary context shifting. Also see dojo.withDoc().
+ // description:
+ // Refer to dojo.doc rather
+ // than referring to 'window.document' to ensure your code runs
+ // correctly in managed contexts.
+ // example:
+ // | n.appendChild(dojo.doc.createElement('div'));
+}
+=====*/
+dojo.doc = window["document"] || null;
+
+dojo.body = function(){
+ // summary:
+ // Return the body element of the document
+ // return the body object associated with dojo.doc
+ // example:
+ // | dojo.body().appendChild(dojo.doc.createElement('div'));
+
+ // Note: document.body is not defined for a strict xhtml document
+ // Would like to memoize this, but dojo.doc can change vi dojo.withDoc().
+ return dojo.doc.body || dojo.doc.getElementsByTagName("body")[0]; // Node
+}
+
+dojo.setContext = function(/*Object*/globalObject, /*DocumentElement*/globalDocument){
+ // summary:
+ // changes the behavior of many core Dojo functions that deal with
+ // namespace and DOM lookup, changing them to work in a new global
+ // context (e.g., an iframe). The varibles dojo.global and dojo.doc
+ // are modified as a result of calling this function and the result of
+ // `dojo.body()` likewise differs.
+ dojo.global = globalObject;
+ dojo.doc = globalDocument;
+};
+
+dojo._fireCallback = function(callback, context, cbArguments){
+ if(context && dojo.isString(callback)){
+ callback = context[callback];
+ }
+ return callback.apply(context, cbArguments || [ ]);
+}
+
+dojo.withGlobal = function( /*Object*/globalObject,
+ /*Function*/callback,
+ /*Object?*/thisObject,
+ /*Array?*/cbArguments){
+ // summary:
+ // Call callback with globalObject as dojo.global and
+ // globalObject.document as dojo.doc. If provided, globalObject
+ // will be executed in the context of object thisObject
+ // description:
+ // When callback() returns or throws an error, the dojo.global
+ // and dojo.doc will be restored to its previous state.
+ var rval;
+ var oldGlob = dojo.global;
+ var oldDoc = dojo.doc;
+ try{
+ dojo.setContext(globalObject, globalObject.document);
+ rval = dojo._fireCallback(callback, thisObject, cbArguments);
+ }finally{
+ dojo.setContext(oldGlob, oldDoc);
+ }
+ return rval;
+}
+
+dojo.withDoc = function( /*Object*/documentObject,
+ /*Function*/callback,
+ /*Object?*/thisObject,
+ /*Array?*/cbArguments){
+ // summary:
+ // Call callback with documentObject as dojo.doc. If provided,
+ // callback will be executed in the context of object thisObject
+ // description:
+ // When callback() returns or throws an error, the dojo.doc will
+ // be restored to its previous state.
+ var rval;
+ var oldDoc = dojo.doc;
+ try{
+ dojo.doc = documentObject;
+ rval = dojo._fireCallback(callback, thisObject, cbArguments);
+ }finally{
+ dojo.doc = oldDoc;
+ }
+ return rval;
+};
+
+}
diff --git a/includes/js/dojo/_base/xhr.js b/includes/js/dojo/_base/xhr.js
new file mode 100644
index 0000000..f6e7f1a
--- /dev/null
+++ b/includes/js/dojo/_base/xhr.js
@@ -0,0 +1,730 @@
+if(!dojo._hasResource["dojo._base.xhr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.xhr"] = true;
+dojo.provide("dojo._base.xhr");
+dojo.require("dojo._base.Deferred");
+dojo.require("dojo._base.json");
+dojo.require("dojo._base.lang");
+dojo.require("dojo._base.query");
+
+(function(){
+ var _d = dojo;
+ function setValue(/*Object*/obj, /*String*/name, /*String*/value){
+ //summary:
+ // For the nameed property in object, set the value. If a value
+ // already exists and it is a string, convert the value to be an
+ // array of values.
+ var val = obj[name];
+ if(_d.isString(val)){
+ obj[name] = [val, value];
+ }else if(_d.isArray(val)){
+ val.push(value);
+ }else{
+ obj[name] = value;
+ }
+ }
+
+ dojo.formToObject = function(/*DOMNode||String*/ formNode){
+ // summary:
+ // dojo.formToObject returns the values encoded in an HTML form as
+ // string properties in an object which it then returns. Disabled form
+ // elements, buttons, and other non-value form elements are skipped.
+ // Multi-select elements are returned as an array of string values.
+ // description:
+ // This form:
+ //
+ // | <form id="test_form">
+ // | <input type="text" name="blah" value="blah">
+ // | <input type="text" name="no_value" value="blah" disabled>
+ // | <input type="button" name="no_value2" value="blah">
+ // | <select type="select" multiple name="multi" size="5">
+ // | <option value="blah">blah</option>
+ // | <option value="thud" selected>thud</option>
+ // | <option value="thonk" selected>thonk</option>
+ // | </select>
+ // | </form>
+ //
+ // yields this object structure as the result of a call to
+ // formToObject():
+ //
+ // | {
+ // | blah: "blah",
+ // | multi: [
+ // | "thud",
+ // | "thonk"
+ // | ]
+ // | };
+
+ var ret = {};
+ var iq = "input:not([type=file]):not([type=submit]):not([type=image]):not([type=reset]):not([type=button]), select, textarea";
+ _d.query(iq, formNode).filter(function(node){
+ return !node.disabled && node.name;
+ }).forEach(function(item){
+ var _in = item.name;
+ var type = (item.type||"").toLowerCase();
+ if(type == "radio" || type == "checkbox"){
+ if(item.checked){ setValue(ret, _in, item.value); }
+ }else if(item.multiple){
+ ret[_in] = [];
+ _d.query("option", item).forEach(function(opt){
+ if(opt.selected){
+ setValue(ret, _in, opt.value);
+ }
+ });
+ }else{
+ setValue(ret, _in, item.value);
+ if(type == "image"){
+ ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0;
+ }
+ }
+ });
+ return ret; // Object
+ }
+
+ dojo.objectToQuery = function(/*Object*/ map){
+ // summary:
+ // takes a name/value mapping object and returns a string representing
+ // a URL-encoded version of that object.
+ // example:
+ // this object:
+ //
+ // | {
+ // | blah: "blah",
+ // | multi: [
+ // | "thud",
+ // | "thonk"
+ // | ]
+ // | };
+ //
+ // yields the following query string:
+ //
+ // | "blah=blah&multi=thud&multi=thonk"
+
+ // FIXME: need to implement encodeAscii!!
+ var enc = encodeURIComponent;
+ var pairs = [];
+ var backstop = {};
+ for(var name in map){
+ var value = map[name];
+ if(value != backstop[name]){
+ var assign = enc(name) + "=";
+ if(_d.isArray(value)){
+ for(var i=0; i < value.length; i++){
+ pairs.push(assign + enc(value[i]));
+ }
+ }else{
+ pairs.push(assign + enc(value));
+ }
+ }
+ }
+ return pairs.join("&"); // String
+ }
+
+ dojo.formToQuery = function(/*DOMNode||String*/ formNode){
+ // summary:
+ // Returns a URL-encoded string representing the form passed as either a
+ // node or string ID identifying the form to serialize
+ return _d.objectToQuery(_d.formToObject(formNode)); // String
+ }
+
+ dojo.formToJson = function(/*DOMNode||String*/ formNode, /*Boolean?*/prettyPrint){
+ // summary:
+ // return a serialized JSON string from a form node or string
+ // ID identifying the form to serialize
+ return _d.toJson(_d.formToObject(formNode), prettyPrint); // String
+ }
+
+ dojo.queryToObject = function(/*String*/ str){
+ // summary:
+ // returns an object representing a de-serialized query section of a
+ // URL. Query keys with multiple values are returned in an array.
+ // description:
+ // This string:
+ //
+ // | "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&"
+ //
+ // results in this object structure:
+ //
+ // | {
+ // | foo: [ "bar", "baz" ],
+ // | thinger: " spaces =blah",
+ // | zonk: "blarg"
+ // | }
+ //
+ // Note that spaces and other urlencoded entities are correctly
+ // handled.
+
+ // FIXME: should we grab the URL string if we're not passed one?
+ var ret = {};
+ var qp = str.split("&");
+ var dec = decodeURIComponent;
+ _d.forEach(qp, function(item){
+ if(item.length){
+ var parts = item.split("=");
+ var name = dec(parts.shift());
+ var val = dec(parts.join("="));
+ if(_d.isString(ret[name])){
+ ret[name] = [ret[name]];
+ }
+ if(_d.isArray(ret[name])){
+ ret[name].push(val);
+ }else{
+ ret[name] = val;
+ }
+ }
+ });
+ return ret; // Object
+ }
+
+ /*
+ from refactor.txt:
+
+ all bind() replacement APIs take the following argument structure:
+
+ {
+ url: "blah.html",
+
+ // all below are optional, but must be supported in some form by
+ // every IO API
+ timeout: 1000, // milliseconds
+ handleAs: "text", // replaces the always-wrong "mimetype"
+ content: {
+ key: "value"
+ },
+
+ // browser-specific, MAY be unsupported
+ sync: true, // defaults to false
+ form: dojo.byId("someForm")
+ }
+ */
+
+ // need to block async callbacks from snatching this thread as the result
+ // of an async callback might call another sync XHR, this hangs khtml forever
+ // must checked by watchInFlight()
+
+ dojo._blockAsync = false;
+
+ dojo._contentHandlers = {
+ "text": function(xhr){ return xhr.responseText; },
+ "json": function(xhr){
+ if(!dojo.config.usePlainJson){
+ console.warn("Consider using mimetype:text/json-comment-filtered"
+ + " to avoid potential security issues with JSON endpoints"
+ + " (use djConfig.usePlainJson=true to turn off this message)");
+ }
+ return (xhr.status == 204) ? undefined : _d.fromJson(xhr.responseText);
+ },
+ "json-comment-filtered": function(xhr){
+ // NOTE: we provide the json-comment-filtered option as one solution to
+ // the "JavaScript Hijacking" issue noted by Fortify and others. It is
+ // not appropriate for all circumstances.
+
+ var value = xhr.responseText;
+ var cStartIdx = value.indexOf("\/*");
+ var cEndIdx = value.lastIndexOf("*\/");
+ if(cStartIdx == -1 || cEndIdx == -1){
+ throw new Error("JSON was not comment filtered");
+ }
+ return (xhr.status == 204) ? undefined :
+ _d.fromJson(value.substring(cStartIdx+2, cEndIdx));
+ },
+ "javascript": function(xhr){
+ // FIXME: try Moz and IE specific eval variants?
+ return _d.eval(xhr.responseText);
+ },
+ "xml": function(xhr){
+ var result = xhr.responseXML;
+ if(_d.isIE && (!result || window.location.protocol == "file:")){
+ _d.forEach(["MSXML2", "Microsoft", "MSXML", "MSXML3"], function(prefix){
+ try{
+ var dom = new ActiveXObject(prefix + ".XMLDOM");
+ dom.async = false;
+ dom.loadXML(xhr.responseText);
+ result = dom;
+ }catch(e){ /* Not available. Squelch and try next one. */ }
+ });
+ }
+ return result; // DOMDocument
+ }
+ };
+
+ dojo._contentHandlers["json-comment-optional"] = function(xhr){
+ var handlers = _d._contentHandlers;
+ try{
+ return handlers["json-comment-filtered"](xhr);
+ }catch(e){
+ return handlers["json"](xhr);
+ }
+ };
+
+ /*=====
+ dojo.__IoArgs = function(){
+ // url: String
+ // URL to server endpoint.
+ // content: Object?
+ // Contains properties with string values. These
+ // properties will be serialized as name1=value2 and
+ // passed in the request.
+ // timeout: Integer?
+ // Milliseconds to wait for the response. If this time
+ // passes, the then error callbacks are called.
+ // form: DOMNode?
+ // DOM node for a form. Used to extract the form values
+ // and send to the server.
+ // preventCache: Boolean?
+ // Default is false. If true, then a
+ // "dojo.preventCache" parameter is sent in the request
+ // with a value that changes with each request
+ // (timestamp). Useful only with GET-type requests.
+ // handleAs: String?
+ // Acceptable values depend on the type of IO
+ // transport (see specific IO calls for more information).
+ // load: Function?
+ // function(response, ioArgs){}. response is an Object, ioArgs
+ // is of type dojo.__IoCallbackArgs. The load function will be
+ // called on a successful response.
+ // error: Function?
+ // function(response, ioArgs){}. response is an Object, ioArgs
+ // is of type dojo.__IoCallbackArgs. The error function will
+ // be called in an error case.
+ // handle: Function?
+ // function(response, ioArgs){}. response is an Object, ioArgs
+ // is of type dojo.__IoCallbackArgs. The handle function will
+ // be called in either the successful or error case. For
+ // the load, error and handle functions, the ioArgs object
+ // will contain the following properties:
+ this.url = url;
+ this.content = content;
+ this.timeout = timeout;
+ this.form = form;
+ this.preventCache = preventCache;
+ this.handleAs = handleAs;
+ this.load = load;
+ this.error = error;
+ this.handle = handle;
+ }
+ =====*/
+
+ /*=====
+ dojo.__IoCallbackArgs = function(args, xhr, url, query, handleAs, id, canDelete, json){
+ // args: Object
+ // the original object argument to the IO call.
+ // xhr: XMLHttpRequest
+ // For XMLHttpRequest calls only, the
+ // XMLHttpRequest object that was used for the
+ // request.
+ // url: String
+ // The final URL used for the call. Many times it
+ // will be different than the original args.url
+ // value.
+ // query: String
+ // For non-GET requests, the
+ // name1=value1&name2=value2 parameters sent up in
+ // the request.
+ // handleAs: String
+ // The final indicator on how the response will be
+ // handled.
+ // id: String
+ // For dojo.io.script calls only, the internal
+ // script ID used for the request.
+ // canDelete: Boolean
+ // For dojo.io.script calls only, indicates
+ // whether the script tag that represents the
+ // request can be deleted after callbacks have
+ // been called. Used internally to know when
+ // cleanup can happen on JSONP-type requests.
+ // json: Object
+ // For dojo.io.script calls only: holds the JSON
+ // response for JSONP-type requests. Used
+ // internally to hold on to the JSON responses.
+ // You should not need to access it directly --
+ // the same object should be passed to the success
+ // callbacks directly.
+ this.args = args;
+ this.xhr = xhr;
+ this.url = url;
+ this.query = query;
+ this.handleAs = handleAs;
+ this.id = id;
+ this.canDelete = canDelete;
+ this.json = json;
+ }
+ =====*/
+
+
+
+ dojo._ioSetArgs = function(/*dojo.__IoArgs*/args,
+ /*Function*/canceller,
+ /*Function*/okHandler,
+ /*Function*/errHandler){
+ // summary:
+ // sets up the Deferred and ioArgs property on the Deferred so it
+ // can be used in an io call.
+ // args:
+ // The args object passed into the public io call. Recognized properties on
+ // the args object are:
+ // canceller:
+ // The canceller function used for the Deferred object. The function
+ // will receive one argument, the Deferred object that is related to the
+ // canceller.
+ // okHandler:
+ // The first OK callback to be registered with Deferred. It has the opportunity
+ // to transform the OK response. It will receive one argument -- the Deferred
+ // object returned from this function.
+ // errHandler:
+ // The first error callback to be registered with Deferred. It has the opportunity
+ // to do cleanup on an error. It will receive two arguments: error (the
+ // Error object) and dfd, the Deferred object returned from this function.
+
+ var ioArgs = {args: args, url: args.url};
+
+ //Get values from form if requestd.
+ var formObject = null;
+ if(args.form){
+ var form = _d.byId(args.form);
+ //IE requires going through getAttributeNode instead of just getAttribute in some form cases,
+ //so use it for all. See #2844
+ var actnNode = form.getAttributeNode("action");
+ ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : null);
+ formObject = _d.formToObject(form);
+ }
+
+ // set up the query params
+ var miArgs = [{}];
+
+ if(formObject){
+ // potentially over-ride url-provided params w/ form values
+ miArgs.push(formObject);
+ }
+ if(args.content){
+ // stuff in content over-rides what's set by form
+ miArgs.push(args.content);
+ }
+ if(args.preventCache){
+ miArgs.push({"dojo.preventCache": new Date().valueOf()});
+ }
+ ioArgs.query = _d.objectToQuery(_d.mixin.apply(null, miArgs));
+
+ // .. and the real work of getting the deferred in order, etc.
+ ioArgs.handleAs = args.handleAs || "text";
+ var d = new _d.Deferred(canceller);
+ d.addCallbacks(okHandler, function(error){
+ return errHandler(error, d);
+ });
+
+ //Support specifying load, error and handle callback functions from the args.
+ //For those callbacks, the "this" object will be the args object.
+ //The callbacks will get the deferred result value as the
+ //first argument and the ioArgs object as the second argument.
+ var ld = args.load;
+ if(ld && _d.isFunction(ld)){
+ d.addCallback(function(value){
+ return ld.call(args, value, ioArgs);
+ });
+ }
+ var err = args.error;
+ if(err && _d.isFunction(err)){
+ d.addErrback(function(value){
+ return err.call(args, value, ioArgs);
+ });
+ }
+ var handle = args.handle;
+ if(handle && _d.isFunction(handle)){
+ d.addBoth(function(value){
+ return handle.call(args, value, ioArgs);
+ });
+ }
+
+ d.ioArgs = ioArgs;
+
+ // FIXME: need to wire up the xhr object's abort method to something
+ // analagous in the Deferred
+ return d;
+ }
+
+ var _deferredCancel = function(/*Deferred*/dfd){
+ //summary: canceller function for dojo._ioSetArgs call.
+
+ dfd.canceled = true;
+ var xhr = dfd.ioArgs.xhr;
+ var _at = typeof xhr.abort;
+ if(_at == "function" || _at == "unknown"){
+ xhr.abort();
+ }
+ var err = new Error("xhr cancelled");
+ err.dojoType = "cancel";
+ return err;
+ }
+ var _deferredOk = function(/*Deferred*/dfd){
+ //summary: okHandler function for dojo._ioSetArgs call.
+
+ return _d._contentHandlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
+ }
+ var _deferError = function(/*Error*/error, /*Deferred*/dfd){
+ //summary: errHandler function for dojo._ioSetArgs call.
+
+ // console.debug("xhr error in:", dfd.ioArgs.xhr);
+ console.debug(error);
+ return error;
+ }
+
+ var _makeXhrDeferred = function(/*dojo.__XhrArgs*/args){
+ //summary: makes the Deferred object for this xhr request.
+ var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError);
+ //Pass the args to _xhrObj, to allow xhr iframe proxy interceptions.
+ dfd.ioArgs.xhr = _d._xhrObj(dfd.ioArgs.args);
+ return dfd;
+ }
+
+ // avoid setting a timer per request. It degrades performance on IE
+ // something fierece if we don't use unified loops.
+ var _inFlightIntvl = null;
+ var _inFlight = [];
+ var _watchInFlight = function(){
+ //summary:
+ // internal method that checks each inflight XMLHttpRequest to see
+ // if it has completed or if the timeout situation applies.
+
+ var now = (new Date()).getTime();
+ // make sure sync calls stay thread safe, if this callback is called
+ // during a sync call and this results in another sync call before the
+ // first sync call ends the browser hangs
+ if(!_d._blockAsync){
+ // we need manual loop because we often modify _inFlight (and therefore 'i') while iterating
+ // note: the second clause is an assigment on purpose, lint may complain
+ for(var i = 0, tif; i < _inFlight.length && (tif = _inFlight[i]); i++){
+ var dfd = tif.dfd;
+ try{
+ if(!dfd || dfd.canceled || !tif.validCheck(dfd)){
+ _inFlight.splice(i--, 1);
+ }else if(tif.ioCheck(dfd)){
+ _inFlight.splice(i--, 1);
+ tif.resHandle(dfd);
+ }else if(dfd.startTime){
+ //did we timeout?
+ if(dfd.startTime + (dfd.ioArgs.args.timeout || 0) < now){
+ _inFlight.splice(i--, 1);
+ var err = new Error("timeout exceeded");
+ err.dojoType = "timeout";
+ dfd.errback(err);
+ //Cancel the request so the io module can do appropriate cleanup.
+ dfd.cancel();
+ }
+ }
+ }catch(e){
+ // FIXME: make sure we errback! (fixed? remove console.debug?)
+ console.debug(e);
+ dfd.errback(new Error("_watchInFlightError!"));
+ }
+ }
+ }
+
+ if(!_inFlight.length){
+ clearInterval(_inFlightIntvl);
+ _inFlightIntvl = null;
+ return;
+ }
+
+ }
+
+ dojo._ioCancelAll = function(){
+ //summary: Cancels all pending IO requests, regardless of IO type
+ //(xhr, script, iframe).
+ try{
+ _d.forEach(_inFlight, function(i){
+ i.dfd.cancel();
+ });
+ }catch(e){/*squelch*/}
+ }
+
+ //Automatically call cancel all io calls on unload
+ //in IE for trac issue #2357.
+ if(_d.isIE){
+ _d.addOnUnload(_d._ioCancelAll);
+ }
+
+ _d._ioWatch = function(/*Deferred*/dfd,
+ /*Function*/validCheck,
+ /*Function*/ioCheck,
+ /*Function*/resHandle){
+ //summary: watches the io request represented by dfd to see if it completes.
+ //dfd:
+ // The Deferred object to watch.
+ //validCheck:
+ // Function used to check if the IO request is still valid. Gets the dfd
+ // object as its only argument.
+ //ioCheck:
+ // Function used to check if basic IO call worked. Gets the dfd
+ // object as its only argument.
+ //resHandle:
+ // Function used to process response. Gets the dfd
+ // object as its only argument.
+ if(dfd.ioArgs.args.timeout){
+ dfd.startTime = (new Date()).getTime();
+ }
+ _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle});
+ if(!_inFlightIntvl){
+ _inFlightIntvl = setInterval(_watchInFlight, 50);
+ }
+ _watchInFlight(); // handle sync requests
+ }
+
+ var _defaultContentType = "application/x-www-form-urlencoded";
+
+ var _validCheck = function(/*Deferred*/dfd){
+ return dfd.ioArgs.xhr.readyState; //boolean
+ }
+ var _ioCheck = function(/*Deferred*/dfd){
+ return 4 == dfd.ioArgs.xhr.readyState; //boolean
+ }
+ var _resHandle = function(/*Deferred*/dfd){
+ var xhr = dfd.ioArgs.xhr;
+ if(_d._isDocumentOk(xhr)){
+ dfd.callback(dfd);
+ }else{
+ var err = new Error("Unable to load " + dfd.ioArgs.url + " status:" + xhr.status);
+ err.status = xhr.status;
+ err.responseText = xhr.responseText;
+ dfd.errback(err);
+ }
+ }
+
+ var _doIt = function(/*String*/type, /*Deferred*/dfd){
+ // IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open).
+ // workaround for IE6's apply() "issues"
+ var ioArgs = dfd.ioArgs;
+ var args = ioArgs.args;
+ var xhr = ioArgs.xhr;
+ xhr.open(type, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined);
+ if(args.headers){
+ for(var hdr in args.headers){
+ if(hdr.toLowerCase() === "content-type" && !args.contentType){
+ args.contentType = args.headers[hdr];
+ }else{
+ xhr.setRequestHeader(hdr, args.headers[hdr]);
+ }
+ }
+ }
+ // FIXME: is this appropriate for all content types?
+ xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType);
+ if(!args.headers || !args.headers["X-Requested-With"]){
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+ }
+ // FIXME: set other headers here!
+ try{
+ xhr.send(ioArgs.query);
+ }catch(e){
+ dfd.cancel();
+ }
+ _d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);
+ xhr = null;
+ return dfd; //Deferred
+ }
+
+ dojo._ioAddQueryToUrl = function(/*dojo.__IoCallbackArgs*/ioArgs){
+ //summary: Adds query params discovered by the io deferred construction to the URL.
+ //Only use this for operations which are fundamentally GET-type operations.
+ if(ioArgs.query.length){
+ ioArgs.url += (ioArgs.url.indexOf("?") == -1 ? "?" : "&") + ioArgs.query;
+ ioArgs.query = null;
+ }
+ }
+
+ /*=====
+ dojo.declare("dojo.__XhrArgs", dojo.__IoArgs, {
+ constructor: function(){
+ // summary:
+ // In addition to the properties listed for the dojo._IoArgs type,
+ // the following properties are allowed for dojo.xhr* methods.
+ // handleAs: String?
+ // Acceptable values are: text (default), json, json-comment-optional,
+ // json-comment-filtered, javascript, xml
+ // sync: Boolean?
+ // false is default. Indicates whether the request should
+ // be a synchronous (blocking) request.
+ // headers: Object?
+ // Additional HTTP headers to send in the request.
+ this.handleAs = handleAs;
+ this.sync = sync;
+ this.headers = headers;
+ }
+ });
+ =====*/
+
+ dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){
+ // summary:
+ // Sends an HTTP request with the given method. If the request has an
+ // HTTP body, then pass true for hasBody. The method argument should be uppercase.
+ // Also look at dojo.xhrGet(), xhrPost(), xhrPut() and dojo.xhrDelete() for shortcuts
+ // for those HTTP methods. There are also methods for "raw" PUT and POST methods
+ // via dojo.rawXhrPut() and dojo.rawXhrPost() respectively.
+ var dfd = _makeXhrDeferred(args);
+ if(!hasBody){
+ _d._ioAddQueryToUrl(dfd.ioArgs);
+ }
+ return _doIt(method, dfd); // dojo.Deferred
+ }
+
+ dojo.xhrGet = function(/*dojo.__XhrArgs*/ args){
+ // summary:
+ // Sends an HTTP GET request to the server.
+ return _d.xhr("GET", args); //dojo.Deferred
+ }
+
+ dojo.xhrPost = function(/*dojo.__XhrArgs*/ args){
+ //summary:
+ // Sends an HTTP POST request to the server.
+ return _d.xhr("POST", args, true); // dojo.Deferred
+ }
+
+ dojo.rawXhrPost = function(/*dojo.__XhrArgs*/ args){
+ // summary:
+ // Sends an HTTP POST request to the server. In addtion to the properties
+ // listed for the dojo.__XhrArgs type, the following property is allowed:
+ // postData:
+ // String. The raw data to send in the body of the POST request.
+ var dfd = _makeXhrDeferred(args);
+ dfd.ioArgs.query = args.postData;
+ return _doIt("POST", dfd); // dojo.Deferred
+ }
+
+ dojo.xhrPut = function(/*dojo.__XhrArgs*/ args){
+ // summary:
+ // Sends an HTTP PUT request to the server.
+ return _d.xhr("PUT", args, true); // dojo.Deferred
+ }
+
+ dojo.rawXhrPut = function(/*dojo.__XhrArgs*/ args){
+ // summary:
+ // Sends an HTTP PUT request to the server. In addtion to the properties
+ // listed for the dojo.__XhrArgs type, the following property is allowed:
+ // putData:
+ // String. The raw data to send in the body of the PUT request.
+ var dfd = _makeXhrDeferred(args);
+ var ioArgs = dfd.ioArgs;
+ if(args.putData){
+ ioArgs.query = args.putData;
+ args.putData = null;
+ }
+ return _doIt("PUT", dfd); // dojo.Deferred
+ }
+
+ dojo.xhrDelete = function(/*dojo.__XhrArgs*/ args){
+ // summary:
+ // Sends an HTTP DELETE request to the server.
+ return _d.xhr("DELETE", args); //dojo.Deferred
+ }
+
+ /*
+ dojo.wrapForm = function(formNode){
+ //summary:
+ // A replacement for FormBind, but not implemented yet.
+
+ // FIXME: need to think harder about what extensions to this we might
+ // want. What should we allow folks to do w/ this? What events to
+ // set/send?
+ throw new Error("dojo.wrapForm not yet implemented");
+ }
+ */
+})();
+
+}
diff --git a/includes/js/dojo/_firebug/LICENSE b/includes/js/dojo/_firebug/LICENSE
new file mode 100644
index 0000000..8c777a2
--- /dev/null
+++ b/includes/js/dojo/_firebug/LICENSE
@@ -0,0 +1,37 @@
+License Disclaimer:
+
+All contents of this directory are Copyright (c) the Dojo Foundation, with the
+following exceptions:
+-------------------------------------------------------------------------------
+
+firebug.html, firebug.js, errIcon.png, infoIcon.png, warningIcon.png:
+ * Copyright (c) 2006-2007, Joe Hewitt, All rights reserved.
+ Distributed under the terms of the BSD License (see below)
+
+-------------------------------------------------------------------------------
+
+Copyright (c) 2006-2007, Joe Hewitt
+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.
diff --git a/includes/js/dojo/_firebug/errorIcon.png b/includes/js/dojo/_firebug/errorIcon.png
new file mode 100644
index 0000000..2d75261
--- /dev/null
+++ b/includes/js/dojo/_firebug/errorIcon.png
Binary files differ
diff --git a/includes/js/dojo/_firebug/firebug.css b/includes/js/dojo/_firebug/firebug.css
new file mode 100644
index 0000000..0b154f2
--- /dev/null
+++ b/includes/js/dojo/_firebug/firebug.css
@@ -0,0 +1,176 @@
+.firebug {
+ margin: 0;
+ background:#fff;
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ font-size: 11px;
+ overflow: hidden;
+ border: 1px solid black;
+ position: relative;
+}
+.firebug a {
+ text-decoration: none;
+}
+.firebug a:hover {
+ text-decoration: underline;
+}
+.firebug a:visited{
+ color:#0000FF;
+}
+.firebug #firebugToolbar {
+ height: 14px;
+ border-top: 1px solid ThreeDHighlight;
+ border-bottom: 1px solid ThreeDShadow;
+ padding: 2px 6px;
+ background: ThreeDFace;
+}
+.firebug .firebugToolbarRight {
+ position: absolute;
+ top: 4px;
+ right: 6px;
+}
+.firebug #firebugLog, .firebug #objectLog {
+ overflow: auto;
+ position: absolute;
+ left: 0;
+ width: 100%;
+}
+#objectLog{
+ overflow:scroll;
+ height:258px;
+}
+.firebug #firebugCommandLine {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 18px;
+ border: none;
+ border-top: 1px solid ThreeDShadow;
+}
+.firebug .logRow {
+ position: relative;
+ border-bottom: 1px solid #D7D7D7;
+ padding: 2px 4px 1px 6px;
+ background-color: #FFFFFF;
+}
+.firebug .logRow-command {
+ font-family: Monaco, monospace;
+ color: blue;
+}
+.firebug .objectBox-null {
+ padding: 0 2px;
+ border: 1px solid #666666;
+ background-color: #888888;
+ color: #FFFFFF;
+}
+.firebug .objectBox-string {
+ font-family: Monaco, monospace;
+ color: red;
+ white-space: pre;
+}
+.firebug .objectBox-number {
+ color: #000088;
+}
+.firebug .objectBox-function {
+ font-family: Monaco, monospace;
+ color: DarkGreen;
+}
+.firebug .objectBox-object {
+ color: DarkGreen;
+ font-weight: bold;
+}
+.firebug .logRow-info,
+.firebug .logRow-error,
+.firebug .logRow-warning
+ {
+ background: #00FFFF no-repeat 2px 2px;
+ padding-left: 20px;
+ padding-bottom: 3px;
+}
+.firebug .logRow-info {
+ background: #FFF url(infoIcon.png) no-repeat 2px 2px;
+ padding-left: 20px;
+ padding-bottom: 3px;
+}
+.firebug .logRow-warning {
+
+ background: #00FFFF url(warningIcon.png) no-repeat 2px 2px;
+ padding-left: 20px;
+ padding-bottom: 3px;
+}
+.firebug .logRow-error {
+ background: LightYellow url(errorIcon.png) no-repeat 2px 2px;
+ padding-left: 20px;
+ padding-bottom: 3px;
+}
+.firebug .errorMessage {
+ vertical-align: top;
+ color: #FF0000;
+}
+.firebug .objectBox-sourceLink {
+ position: absolute;
+ right: 4px;
+ top: 2px;
+ padding-left: 8px;
+ font-family: Lucida Grande, sans-serif;
+ font-weight: bold;
+ color: #0000FF;
+}
+.firebug .logRow-group {
+ background: #EEEEEE;
+ border-bottom: none;
+}
+.firebug .logGroup {
+ background: #EEEEEE;
+}
+.firebug .logGroupBox {
+ margin-left: 24px;
+ border-top: 1px solid #D7D7D7;
+ border-left: 1px solid #D7D7D7;
+}
+.firebug .selectorTag,
+.firebug .selectorId,
+.firebug .selectorClass {
+ font-family: Monaco, monospace;
+ font-weight: normal;
+}
+.firebug .selectorTag {
+ color: #0000FF;
+}
+.firebug .selectorId {
+ color: DarkBlue;
+}
+.firebug .selectorClass {
+ color: red;
+}
+.firebug .objectBox-element {
+ font-family: Monaco, monospace;
+ color: #000088;
+}
+.firebug .nodeChildren {
+ margin-left: 16px;
+}
+.firebug .nodeTag {
+ color: blue;
+}
+.firebug .nodeValue {
+ color: #FF0000;
+ font-weight: normal;
+}
+.firebug .nodeText,
+.firebug .nodeComment {
+ margin: 0 2px;
+ vertical-align: top;
+}
+.firebug .nodeText {
+ color: #333333;
+}
+.firebug .nodeComment {
+ color: DarkGreen;
+}
+.firebug .propertyNameCell {
+ vertical-align: top;
+}
+.firebug .propertyName {
+ font-weight: bold;
+}
diff --git a/includes/js/dojo/_firebug/firebug.css.commented.css b/includes/js/dojo/_firebug/firebug.css.commented.css
new file mode 100644
index 0000000..8c4c4f4
--- /dev/null
+++ b/includes/js/dojo/_firebug/firebug.css.commented.css
@@ -0,0 +1,222 @@
+.firebug {
+ margin: 0;
+ background:#fff;
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ font-size: 11px;
+ overflow: hidden;
+ border: 1px solid black;
+ position: relative;
+}
+
+.firebug a {
+ text-decoration: none;
+}
+
+.firebug a:hover {
+ text-decoration: underline;
+}
+.firebug a:visited{
+ color:#0000FF;
+}
+.firebug #firebugToolbar {
+ height: 14px;
+ border-top: 1px solid ThreeDHighlight;
+ border-bottom: 1px solid ThreeDShadow;
+ padding: 2px 6px;
+ background: ThreeDFace;
+}
+
+.firebug .firebugToolbarRight {
+ position: absolute;
+ top: 4px;
+ right: 6px;
+}
+
+.firebug #firebugLog, .firebug #objectLog {
+ overflow: auto;
+ position: absolute;
+ left: 0;
+ width: 100%;
+}
+#objectLog{
+ overflow:scroll;
+ height:258px;
+}
+.firebug #firebugCommandLine {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 18px;
+ border: none;
+ border-top: 1px solid ThreeDShadow;
+}
+
+/************************************************************************************************/
+
+.firebug .logRow {
+ position: relative;
+ border-bottom: 1px solid #D7D7D7;
+ padding: 2px 4px 1px 6px;
+ background-color: #FFFFFF;
+}
+
+.firebug .logRow-command {
+ font-family: Monaco, monospace;
+ color: blue;
+}
+
+.firebug .objectBox-null {
+ padding: 0 2px;
+ border: 1px solid #666666;
+ background-color: #888888;
+ color: #FFFFFF;
+}
+
+.firebug .objectBox-string {
+ font-family: Monaco, monospace;
+ color: red;
+ white-space: pre;
+}
+
+.firebug .objectBox-number {
+ color: #000088;
+}
+
+.firebug .objectBox-function {
+ font-family: Monaco, monospace;
+ color: DarkGreen;
+}
+
+.firebug .objectBox-object {
+ color: DarkGreen;
+ font-weight: bold;
+}
+
+/************************************************************************************************/
+
+.firebug .logRow-info,
+.firebug .logRow-error,
+.firebug .logRow-warning
+ {
+ background: #00FFFF no-repeat 2px 2px;
+ padding-left: 20px;
+ padding-bottom: 3px;
+}
+
+.firebug .logRow-info {
+ background: #FFF url(infoIcon.png) no-repeat 2px 2px;
+ padding-left: 20px;
+ padding-bottom: 3px;
+}
+
+.firebug .logRow-warning {
+
+ background: #00FFFF url(warningIcon.png) no-repeat 2px 2px;
+ padding-left: 20px;
+ padding-bottom: 3px;
+}
+
+.firebug .logRow-error {
+
+ background: LightYellow url(errorIcon.png) no-repeat 2px 2px;
+ padding-left: 20px;
+ padding-bottom: 3px;
+}
+
+.firebug .errorMessage {
+ vertical-align: top;
+ color: #FF0000;
+}
+
+.firebug .objectBox-sourceLink {
+ position: absolute;
+ right: 4px;
+ top: 2px;
+ padding-left: 8px;
+ font-family: Lucida Grande, sans-serif;
+ font-weight: bold;
+ color: #0000FF;
+}
+
+/************************************************************************************************/
+
+.firebug .logRow-group {
+ background: #EEEEEE;
+ border-bottom: none;
+}
+
+.firebug .logGroup {
+ background: #EEEEEE;
+}
+
+.firebug .logGroupBox {
+ margin-left: 24px;
+ border-top: 1px solid #D7D7D7;
+ border-left: 1px solid #D7D7D7;
+}
+
+/************************************************************************************************/
+
+.firebug .selectorTag,
+.firebug .selectorId,
+.firebug .selectorClass {
+ font-family: Monaco, monospace;
+ font-weight: normal;
+}
+
+.firebug .selectorTag {
+ color: #0000FF;
+}
+
+.firebug .selectorId {
+ color: DarkBlue;
+}
+
+.firebug .selectorClass {
+ color: red;
+}
+
+/************************************************************************************************/
+
+.firebug .objectBox-element {
+ font-family: Monaco, monospace;
+ color: #000088;
+}
+
+.firebug .nodeChildren {
+ margin-left: 16px;
+}
+
+.firebug .nodeTag {
+ color: blue;
+}
+
+.firebug .nodeValue {
+ color: #FF0000;
+ font-weight: normal;
+}
+
+.firebug .nodeText,
+.firebug .nodeComment {
+ margin: 0 2px;
+ vertical-align: top;
+}
+
+.firebug .nodeText {
+ color: #333333;
+}
+
+.firebug .nodeComment {
+ color: DarkGreen;
+}
+
+/************************************************************************************************/
+
+.firebug .propertyNameCell {
+ vertical-align: top;
+}
+
+.firebug .propertyName {
+ font-weight: bold;
+}
diff --git a/includes/js/dojo/_firebug/firebug.js b/includes/js/dojo/_firebug/firebug.js
new file mode 100644
index 0000000..ee189b2
--- /dev/null
+++ b/includes/js/dojo/_firebug/firebug.js
@@ -0,0 +1,1103 @@
+if(!dojo._hasResource["dojo._firebug.firebug"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._firebug.firebug"] = true;
+dojo.provide("dojo._firebug.firebug");
+
+dojo.deprecated = function(/*String*/ behaviour, /*String?*/ extra, /*String?*/ removal){
+ // summary:
+ // Log a debug message to indicate that a behavior has been
+ // deprecated.
+ // extra: Text to append to the message.
+ // removal:
+ // Text to indicate when in the future the behavior will be removed.
+ var message = "DEPRECATED: " + behaviour;
+ if(extra){ message += " " + extra; }
+ if(removal){ message += " -- will be removed in version: " + removal; }
+ console.warn(message);
+}
+
+dojo.experimental = function(/* String */ moduleName, /* String? */ extra){
+ // summary: Marks code as experimental.
+ // description:
+ // This can be used to mark a function, file, or module as
+ // experimental. Experimental code is not ready to be used, and the
+ // APIs are subject to change without notice. Experimental code may be
+ // completed deleted without going through the normal deprecation
+ // process.
+ // moduleName:
+ // The name of a module, or the name of a module file or a specific
+ // function
+ // extra:
+ // some additional message for the user
+ // example:
+ // | dojo.experimental("dojo.data.Result");
+ // example:
+ // | dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA");
+ var message = "EXPERIMENTAL: " + moduleName + " -- APIs subject to change without notice.";
+ if(extra){ message += " " + extra; }
+ console.warn(message);
+}
+
+// FIREBUG LITE
+ // summary: Firebug Lite, the baby brother to Joe Hewitt's Firebug for Mozilla Firefox
+ // description:
+ // Opens a console for logging, debugging, and error messages.
+ // Contains partial functionality to Firebug. See function list below.
+ // NOTE:
+ // Firebug is a Firefox extension created by Joe Hewitt (see license). You do not need Dojo to run Firebug.
+ // Firebug Lite is included in Dojo by permission from Joe Hewitt
+ // If you are new to Firebug, or used to the Dojo 0.4 dojo.debug, you can learn Firebug
+ // functionality by reading the function comments below or visiting http://www.getfirebug.com/docs.html
+ // NOTE:
+ // To test Firebug Lite in Firefox, set console = null;
+ //
+ // example:
+ // Supports inline objects in object inspector window (only simple trace of dom nodes, however)
+ // | console.log("my object", {foo:"bar"})
+ // example:
+ // Option for console to open in popup window
+ // | var djConfig = {isDebug: true, popup:true };
+ // example:
+ // Option for console height (ignored for popup)
+ // | var djConfig = {isDebug: true, debugHeight:100 };
+
+if((!("console" in window) || !("firebug" in console)) &&
+ dojo.config.noFirebugLite !== true){
+
+(function(){
+ // don't build a firebug frame in iframes
+ try{
+ if(window != window.parent){
+ // but if we've got a parent logger, connect to it
+ if(window.parent["console"]){
+ window.console = window.parent.console;
+ }
+ return;
+ }
+ }catch(e){/*squelch*/}
+
+ window.console = {
+ _connects: [],
+ log: function(){
+ // summary:
+ // Sends arguments to console.
+ logFormatted(arguments, "");
+ },
+
+ debug: function(){
+ // summary:
+ // Sends arguments to console. Missing finctionality to show script line of trace.
+ logFormatted(arguments, "debug");
+ },
+
+ info: function(){
+ // summary:
+ // Sends arguments to console, highlighted with (I) icon.
+ logFormatted(arguments, "info");
+ },
+
+ warn: function(){
+ // summary:
+ // Sends warning arguments to console, highlighted with (!) icon and blue style.
+ logFormatted(arguments, "warning");
+ },
+
+ error: function(){
+ // summary:
+ // Sends error arguments (object) to console, highlighted with (X) icon and yellow style
+ // NEW: error object now displays in object inspector
+ logFormatted(arguments, "error");
+ },
+
+ assert: function(truth, message){
+ // summary:
+ // Tests for true. Throws exception if false.
+ if(!truth){
+ var args = [];
+ for(var i = 1; i < arguments.length; ++i){
+ args.push(arguments[i]);
+ }
+
+ logFormatted(args.length ? args : ["Assertion Failure"], "error");
+ throw message ? message : "Assertion Failure";
+ }
+ },
+
+ dir: function(object){
+ // summary:
+ // Traces object. Only partially implemented.
+
+ var pairs = [];
+ for(var prop in object){
+ try{
+ pairs.push([prop, object[prop]]);
+ }catch(e){
+ /* squelch */
+ }
+ }
+
+ pairs.sort(function(a, b){
+ return a[0] < b[0] ? -1 : 1;
+ });
+
+ var html = ['<table>'];
+ for(var i = 0; i < pairs.length; ++i){
+ var name = pairs[i][0], value = pairs[i][1];
+
+ html.push('<tr>',
+ '<td class="propertyNameCell"><span class="propertyName">',
+ escapeHTML(name), '</span></td>', '<td><span class="propertyValue">');
+ appendObject(value, html);
+ html.push('</span></td></tr>');
+ }
+ html.push('</table>');
+
+ logRow(html, "dir");
+ },
+
+ dirxml: function(node){
+ // summary:
+ //
+ var html = [];
+
+ appendNode(node, html);
+ logRow(html, "dirxml");
+ },
+
+ group: function(){
+ // summary:
+ // collects log messages into a group, starting with this call and ending with
+ // groupEnd(). Missing collapse functionality
+ logRow(arguments, "group", pushGroup);
+ },
+
+ groupEnd: function(){
+ // summary:
+ // Closes group. See above
+ logRow(arguments, "", popGroup);
+ },
+
+ time: function(name){
+ // summary:
+ // Starts timers assigned to name given in argument. Timer stops and displays on timeEnd(title);
+ // example:
+ // | console.time("load");
+ // | console.time("myFunction");
+ // | console.timeEnd("load");
+ // | console.timeEnd("myFunction");
+ timeMap[name] = (new Date()).getTime();
+ },
+
+ timeEnd: function(name){
+ // summary:
+ // See above.
+ if(name in timeMap){
+ var delta = (new Date()).getTime() - timeMap[name];
+ logFormatted([name+ ":", delta+"ms"]);
+ delete timeMap[name];
+ }
+ },
+
+ count: function(){
+ // summary:
+ // Not supported
+ this.warn(["count() not supported."]);
+ },
+
+ trace: function(){
+ // summary:
+ // Not supported
+ this.warn(["trace() not supported."]);
+ },
+
+ profile: function(){
+ // summary:
+ // Not supported
+ this.warn(["profile() not supported."]);
+ },
+
+ profileEnd: function(){ },
+
+ clear: function(){
+ // summary:
+ // Clears message console. Do not call this directly
+ while(consoleBody.childNodes.length){
+ dojo._destroyElement(consoleBody.firstChild);
+ }
+ dojo.forEach(this._connects,dojo.disconnect);
+ },
+
+ open: function(){
+ // summary:
+ // Opens message console. Do not call this directly
+ toggleConsole(true);
+ },
+
+ close: function(){
+ // summary:
+ // Closes message console. Do not call this directly
+ if(frameVisible){
+ toggleConsole();
+ }
+ },
+ closeObjectInspector:function(){
+ // summary:
+ // Closes object inspector and opens message console. Do not call this directly
+ consoleObjectInspector.innerHTML = "";
+ consoleObjectInspector.style.display = "none";
+ consoleBody.style.display = "block";
+ }
+ };
+
+ // ***************************************************************************
+
+ // using global objects so they can be accessed
+ // most of the objects in this script are run anonomously
+ var _firebugDoc = document;
+ var _firebugWin = window;
+ var __consoleAnchorId__ = 0;
+
+ var consoleFrame = null;
+ var consoleBody = null;
+ var commandLine = null;
+ var consoleToolbar = null;
+
+ var frameVisible = false;
+ var messageQueue = [];
+ var groupStack = [];
+ var timeMap = {};
+
+ var clPrefix = ">>> ";
+
+ // ***************************************************************************
+
+ function toggleConsole(forceOpen){
+ frameVisible = forceOpen || !frameVisible;
+ if(consoleFrame){
+ consoleFrame.style.display = frameVisible ? "block" : "none";
+ }
+ }
+
+ function focusCommandLine(){
+ toggleConsole(true);
+ if(commandLine){
+ commandLine.focus();
+ }
+ }
+
+ function openWin(x,y,w,h){
+ var win = window.open("","_firebug","status=0,menubar=0,resizable=1,top="+y+",left="+x+",width="+w+",height="+h+",scrollbars=1,addressbar=0");
+ if(!win){
+ var msg = "Firebug Lite could not open a pop-up window, most likely because of a blocker.\n" +
+ "Either enable pop-ups for this domain, or change the djConfig to popup=false.";
+ alert(msg);
+ }
+ createResizeHandler(win);
+ var newDoc=win.document;
+ //Safari needs an HTML height
+ HTMLstring= '<html style="height:100%;"><head><title>Firebug Lite</title></head>\n' +
+ '<body bgColor="#ccc" style="height:98%;" onresize="opener.onFirebugResize()">\n' +
+ '<div id="fb"></div>' +
+ '</body></html>';
+
+ newDoc.write(HTMLstring);
+ newDoc.close();
+ return win;
+ }
+
+ function createResizeHandler(wn){
+ // summary
+ // Creates handle for onresize window. Called from script in popup's body tag (so that it will work with IE).
+ //
+
+ var d = new Date();
+ d.setTime(d.getTime()+(60*24*60*60*1000)); // 60 days
+ d = d.toUTCString();
+
+ var dc = wn.document,
+ getViewport;
+
+ if (wn.innerWidth){
+ getViewport = function(){
+ return{w:wn.innerWidth, h:wn.innerHeight};
+ }
+ }else if (dc.documentElement && dc.documentElement.clientWidth){
+ getViewport = function(){
+ return{w:dc.documentElement.clientWidth, h:dc.documentElement.clientHeight};
+ }
+ }else if (dc.body){
+ getViewport = function(){
+ return{w:dc.body.clientWidth, h:dc.body.clientHeight};
+ }
+ }
+
+
+ window.onFirebugResize = function(){
+
+ //resize the height of the console log body
+ layout(getViewport().h);
+
+ clearInterval(wn._firebugWin_resize);
+ wn._firebugWin_resize = setTimeout(function(){
+ var x = wn.screenLeft,
+ y = wn.screenTop,
+ w = wn.outerWidth || wn.document.body.offsetWidth,
+ h = wn.outerHeight || wn.document.body.offsetHeight;
+
+ document.cookie = "_firebugPosition=" + [x,y,w,h].join(",") + "; expires="+d+"; path=/";
+
+ }, 5000); //can't capture window.onMove - long timeout gives better chance of capturing a resize, then the move
+
+ }
+ }
+
+
+ /*****************************************************************************/
+
+
+ function createFrame(){
+ if(consoleFrame){
+ return;
+ }
+
+ if(dojo.config.popup){
+ var containerHeight = "100%";
+ var cookieMatch = document.cookie.match(/(?:^|; )_firebugPosition=([^;]*)/);
+ var p = cookieMatch ? cookieMatch[1].split(",") : [2,2,320,480];
+
+ _firebugWin = openWin(p[0],p[1],p[2],p[3]); // global
+ _firebugDoc = _firebugWin.document; // global
+
+ djConfig.debugContainerId = 'fb';
+
+ // connecting popup
+ _firebugWin.console = window.console;
+ _firebugWin.dojo = window.dojo;
+ }else{
+ _firebugDoc = document;
+ containerHeight = (dojo.config.debugHeight || 300) + "px";
+ }
+
+ var styleElement = _firebugDoc.createElement("link");
+ styleElement.href = dojo.moduleUrl("dojo._firebug", "firebug.css");
+ styleElement.rel = "stylesheet";
+ styleElement.type = "text/css";
+ var styleParent = _firebugDoc.getElementsByTagName("head");
+ if(styleParent){
+ styleParent = styleParent[0];
+ }
+ if(!styleParent){
+ styleParent = _firebugDoc.getElementsByTagName("html")[0];
+ }
+ if(dojo.isIE){
+ window.setTimeout(function(){ styleParent.appendChild(styleElement); }, 0);
+ }else{
+ styleParent.appendChild(styleElement);
+ }
+
+ if(dojo.config.debugContainerId){
+ consoleFrame = _firebugDoc.getElementById(dojo.config.debugContainerId);
+ }
+ if(!consoleFrame){
+ consoleFrame = _firebugDoc.createElement("div");
+ _firebugDoc.body.appendChild(consoleFrame);
+ }
+ consoleFrame.className += " firebug";
+ consoleFrame.style.height = containerHeight;
+ consoleFrame.style.display = (frameVisible ? "block" : "none");
+
+ var closeStr = dojo.config.popup ? "" : ' <a href="#" onclick="console.close(); return false;">Close</a>';
+ consoleFrame.innerHTML =
+ '<div id="firebugToolbar">'
+ + ' <a href="#" onclick="console.clear(); return false;">Clear</a>'
+ + ' <span class="firebugToolbarRight">'
+ + closeStr
+ + ' </span>'
+ + '</div>'
+ + '<input type="text" id="firebugCommandLine" />'
+ + '<div id="firebugLog"></div>'
+ + '<div id="objectLog" style="display:none;"></div>';
+
+
+ consoleToolbar = _firebugDoc.getElementById("firebugToolbar");
+ consoleToolbar.onmousedown = onSplitterMouseDown;
+
+ commandLine = _firebugDoc.getElementById("firebugCommandLine");
+ addEvent(commandLine, "keydown", onCommandLineKeyDown);
+
+ addEvent(_firebugDoc, dojo.isIE || dojo.isSafari ? "keydown" : "keypress", onKeyDown);
+
+ consoleBody = _firebugDoc.getElementById("firebugLog");
+ consoleObjectInspector = _firebugDoc.getElementById("objectLog");
+
+ layout();
+ flush();
+ }
+
+ dojo.addOnLoad(createFrame);
+
+ function clearFrame(){
+ _firebugDoc = null;
+
+ if(_firebugWin.console){
+ _firebugWin.console.clear();
+ }
+ _firebugWin = null;
+ consoleFrame = null;
+ consoleBody = null;
+ consoleObjectInspector = null;
+ commandLine = null;
+ messageQueue = [];
+ groupStack = [];
+ timeMap = {};
+ }
+ dojo.addOnUnload(clearFrame);
+
+ function evalCommandLine(){
+ var text = commandLine.value;
+ commandLine.value = "";
+
+ logRow([clPrefix, text], "command");
+
+ var value;
+ try{
+ value = eval(text);
+ }catch(e){
+ console.debug(e); // put exception on the console
+ }
+
+ console.log(value);
+ }
+
+ function layout(h){
+ var height = h ?
+ h - (consoleToolbar.offsetHeight + commandLine.offsetHeight +25 + (h*.01)) + "px" :
+ consoleFrame.offsetHeight - (consoleToolbar.offsetHeight + commandLine.offsetHeight) + "px";
+
+ consoleBody.style.top = consoleToolbar.offsetHeight + "px";
+ consoleBody.style.height = height;
+ consoleObjectInspector.style.height = height;
+ consoleObjectInspector.style.top = consoleToolbar.offsetHeight + "px";
+ commandLine.style.bottom = 0;
+ }
+
+ function logRow(message, className, handler){
+ if(consoleBody){
+ writeMessage(message, className, handler);
+ }else{
+ messageQueue.push([message, className, handler]);
+ }
+ }
+
+ function flush(){
+ var queue = messageQueue;
+ messageQueue = [];
+
+ for(var i = 0; i < queue.length; ++i){
+ writeMessage(queue[i][0], queue[i][1], queue[i][2]);
+ }
+ }
+
+ function writeMessage(message, className, handler){
+ var isScrolledToBottom =
+ consoleBody.scrollTop + consoleBody.offsetHeight >= consoleBody.scrollHeight;
+
+ handler = handler||writeRow;
+
+ handler(message, className);
+
+ if(isScrolledToBottom){
+ consoleBody.scrollTop = consoleBody.scrollHeight - consoleBody.offsetHeight;
+ }
+ }
+
+ function appendRow(row){
+ var container = groupStack.length ? groupStack[groupStack.length-1] : consoleBody;
+ container.appendChild(row);
+ }
+
+ function writeRow(message, className){
+ var row = consoleBody.ownerDocument.createElement("div");
+ row.className = "logRow" + (className ? " logRow-"+className : "");
+ row.innerHTML = message.join("");
+ appendRow(row);
+ }
+
+ function pushGroup(message, className){
+ logFormatted(message, className);
+
+ //var groupRow = consoleBody.ownerDocument.createElement("div");
+ //groupRow.className = "logGroup";
+ var groupRowBox = consoleBody.ownerDocument.createElement("div");
+ groupRowBox.className = "logGroupBox";
+ //groupRow.appendChild(groupRowBox);
+ appendRow(groupRowBox);
+ groupStack.push(groupRowBox);
+ }
+
+ function popGroup(){
+ groupStack.pop();
+ }
+
+ // ***************************************************************************
+
+ function logFormatted(objects, className){
+ var html = [];
+
+ var format = objects[0];
+ var objIndex = 0;
+
+ if(typeof(format) != "string"){
+ format = "";
+ objIndex = -1;
+ }
+
+ var parts = parseFormat(format);
+
+ for(var i = 0; i < parts.length; ++i){
+ var part = parts[i];
+ if(part && typeof part == "object"){
+ part.appender(objects[++objIndex], html);
+ }else{
+ appendText(part, html);
+ }
+ }
+
+
+ var ids = [];
+ var obs = [];
+ for(i = objIndex+1; i < objects.length; ++i){
+ appendText(" ", html);
+
+ var object = objects[i];
+ if(object === undefined || object === null ){
+ appendNull(object, html);
+
+ }else if(typeof(object) == "string"){
+ appendText(object, html);
+
+ }else if(object.nodeType == 9){
+ appendText("[ XmlDoc ]", html);
+
+ }else if(object.nodeType == 1){
+ // simple tracing of dom nodes
+ appendText("< "+object.tagName+" id=\""+ object.id+"\" />", html);
+
+ }else{
+ // Create link for object inspector
+ // need to create an ID for this link, since it is currently text
+ var id = "_a" + __consoleAnchorId__++;
+ ids.push(id);
+ // need to save the object, so the arrays line up
+ obs.push(object);
+ var str = '<a id="'+id+'" href="javascript:void(0);">'+getObjectAbbr(object)+'</a>';
+
+ appendLink( str , html);
+ }
+ }
+
+ logRow(html, className);
+
+ // Now that the row is inserted in the DOM, loop through all of the links that were just created
+ for(i=0; i<ids.length; i++){
+ var btn = _firebugDoc.getElementById(ids[i]);
+ if(!btn){ continue; }
+
+ // store the object in the dom btn for reference later
+ // avoid parsing these objects unless necessary
+ btn.obj = obs[i];
+
+ _firebugWin.console._connects.push(dojo.connect(btn, "onclick", function(){
+ // hide rows
+ consoleBody.style.display = "none";
+ consoleObjectInspector.style.display = "block";
+ // create a back button
+ var bkBtn = '<a href="javascript:console.closeObjectInspector();">&nbsp;<<&nbsp;Back</a>';
+ try{
+ printObject(this.obj);
+ }catch(e){
+ this.obj = e;
+ }
+ consoleObjectInspector.innerHTML = bkBtn + "<pre>" + printObject( this.obj ) + "</pre>";
+ }));
+ }
+ }
+
+ function parseFormat(format){
+ var parts = [];
+
+ var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;
+ var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};
+
+ for(var m = reg.exec(format); m; m = reg.exec(format)){
+ var type = m[8] ? m[8] : m[5];
+ var appender = type in appenderMap ? appenderMap[type] : appendObject;
+ var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
+
+ parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
+ parts.push({appender: appender, precision: precision});
+
+ format = format.substr(m.index+m[0].length);
+ }
+
+ parts.push(format);
+
+ return parts;
+ }
+
+ function escapeHTML(value){
+ function replaceChars(ch){
+ switch(ch){
+ case "<":
+ return "&lt;";
+ case ">":
+ return "&gt;";
+ case "&":
+ return "&amp;";
+ case "'":
+ return "&#39;";
+ case '"':
+ return "&quot;";
+ }
+ return "?";
+ }
+ return String(value).replace(/[<>&"']/g, replaceChars);
+ }
+
+ function objectToString(object){
+ try{
+ return object+"";
+ }catch(e){
+ return null;
+ }
+ }
+
+ // ***************************************************************************
+ function appendLink(object, html){
+ // needed for object links - no HTML escaping
+ html.push( objectToString(object) );
+ }
+
+ function appendText(object, html){
+ html.push(escapeHTML(objectToString(object)));
+ }
+
+ function appendNull(object, html){
+ html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
+ }
+
+ function appendString(object, html){
+ html.push('<span class="objectBox-string">&quot;', escapeHTML(objectToString(object)),
+ '&quot;</span>');
+ }
+
+ function appendInteger(object, html){
+ html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
+ }
+
+ function appendFloat(object, html){
+ html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
+ }
+
+ function appendFunction(object, html){
+ html.push('<span class="objectBox-function">', getObjectAbbr(object), '</span>');
+ }
+
+ function appendObject(object, html){
+ try{
+ if(object === undefined){
+ appendNull("undefined", html);
+ }else if(object === null){
+ appendNull("null", html);
+ }else if(typeof object == "string"){
+ appendString(object, html);
+ }else if(typeof object == "number"){
+ appendInteger(object, html);
+ }else if(typeof object == "function"){
+ appendFunction(object, html);
+ }else if(object.nodeType == 1){
+ appendSelector(object, html);
+ }else if(typeof object == "object"){
+ appendObjectFormatted(object, html);
+ }else{
+ appendText(object, html);
+ }
+ }catch(e){
+ /* squelch */
+ }
+ }
+
+ function appendObjectFormatted(object, html){
+ var text = objectToString(object);
+ var reObject = /\[object (.*?)\]/;
+
+ var m = reObject.exec(text);
+ html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>');
+ }
+
+ function appendSelector(object, html){
+ html.push('<span class="objectBox-selector">');
+
+ html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
+ if(object.id){
+ html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
+ }
+ if(object.className){
+ html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');
+ }
+
+ html.push('</span>');
+ }
+
+ function appendNode(node, html){
+ if(node.nodeType == 1){
+ html.push(
+ '<div class="objectBox-element">',
+ '&lt;<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');
+
+ for(var i = 0; i < node.attributes.length; ++i){
+ var attr = node.attributes[i];
+ if(!attr.specified){ continue; }
+
+ html.push('&nbsp;<span class="nodeName">', attr.nodeName.toLowerCase(),
+ '</span>=&quot;<span class="nodeValue">', escapeHTML(attr.nodeValue),
+ '</span>&quot;');
+ }
+
+ if(node.firstChild){
+ html.push('&gt;</div><div class="nodeChildren">');
+
+ for(var child = node.firstChild; child; child = child.nextSibling){
+ appendNode(child, html);
+ }
+
+ html.push('</div><div class="objectBox-element">&lt;/<span class="nodeTag">',
+ node.nodeName.toLowerCase(), '&gt;</span></div>');
+ }else{
+ html.push('/&gt;</div>');
+ }
+ }else if (node.nodeType == 3){
+ html.push('<div class="nodeText">', escapeHTML(node.nodeValue),
+ '</div>');
+ }
+ }
+
+ // ***************************************************************************
+
+ function addEvent(object, name, handler){
+ if(document.all){
+ object.attachEvent("on"+name, handler);
+ }else{
+ object.addEventListener(name, handler, false);
+ }
+ }
+
+ function removeEvent(object, name, handler){
+ if(document.all){
+ object.detachEvent("on"+name, handler);
+ }else{
+ object.removeEventListener(name, handler, false);
+ }
+ }
+
+ function cancelEvent(event){
+ if(document.all){
+ event.cancelBubble = true;
+ }else{
+ event.stopPropagation();
+ }
+ }
+
+ function onError(msg, href, lineNo){
+ var lastSlash = href.lastIndexOf("/");
+ var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
+
+ var html = [
+ '<span class="errorMessage">', msg, '</span>',
+ '<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
+ ];
+
+ logRow(html, "error");
+ }
+
+
+ //After converting to div instead of iframe, now getting two keydowns right away in IE 6.
+ //Make sure there is a little bit of delay.
+ var onKeyDownTime = (new Date()).getTime();
+
+ function onKeyDown(event){
+ var timestamp = (new Date()).getTime();
+ if(timestamp > onKeyDownTime + 200){
+ event = dojo.fixEvent(event);
+ var keys = dojo.keys;
+ var ekc = event.keyCode;
+ onKeyDownTime = timestamp;
+ if(ekc == keys.F12){
+ toggleConsole();
+ }else if(
+ (ekc == keys.NUMPAD_ENTER || ekc == 76) &&
+ event.shiftKey &&
+ (event.metaKey || event.ctrlKey)
+ ){
+ focusCommandLine();
+ }else{
+ return;
+ }
+ cancelEvent(event);
+ }
+ }
+
+
+ function onSplitterMouseDown(event){
+ if(dojo.isSafari || dojo.isOpera){
+ return;
+ }
+
+ addEvent(document, "mousemove", onSplitterMouseMove);
+ addEvent(document, "mouseup", onSplitterMouseUp);
+
+ for(var i = 0; i < frames.length; ++i){
+ addEvent(frames[i].document, "mousemove", onSplitterMouseMove);
+ addEvent(frames[i].document, "mouseup", onSplitterMouseUp);
+ }
+ }
+
+ function onSplitterMouseMove(event){
+ var win = document.all ?
+ event.srcElement.ownerDocument.parentWindow :
+ event.target.ownerDocument.defaultView;
+
+ var clientY = event.clientY;
+ if(win != win.parent){
+ clientY += win.frameElement ? win.frameElement.offsetTop : 0;
+ }
+
+ var height = consoleFrame.offsetTop + consoleFrame.clientHeight;
+ var y = height - clientY;
+
+ consoleFrame.style.height = y + "px";
+ layout();
+ }
+
+ function onSplitterMouseUp(event){
+ removeEvent(document, "mousemove", onSplitterMouseMove);
+ removeEvent(document, "mouseup", onSplitterMouseUp);
+
+ for(var i = 0; i < frames.length; ++i){
+ removeEvent(frames[i].document, "mousemove", onSplitterMouseMove);
+ removeEvent(frames[i].document, "mouseup", onSplitterMouseUp);
+ }
+ }
+
+ function onCommandLineKeyDown(event){
+ if(event.keyCode == 13 && commandLine.value){
+ addToHistory(commandLine.value);
+ evalCommandLine();
+ }else if(event.keyCode == 27){
+ commandLine.value = "";
+ }else if(event.keyCode == dojo.keys.UP_ARROW || event.charCode == dojo.keys.UP_ARROW){
+ navigateHistory("older");
+ }else if(event.keyCode == dojo.keys.DOWN_ARROW || event.charCode == dojo.keys.DOWN_ARROW){
+ navigateHistory("newer");
+ }else if(event.keyCode == dojo.keys.HOME || event.charCode == dojo.keys.HOME){
+ historyPosition = 1;
+ navigateHistory("older");
+ }else if(event.keyCode == dojo.keys.END || event.charCode == dojo.keys.END){
+ historyPosition = 999999;
+ navigateHistory("newer");
+ }
+ }
+
+ var historyPosition = -1;
+ var historyCommandLine = null;
+
+ function addToHistory(value){
+ var history = cookie("firebug_history");
+ history = (history) ? dojo.fromJson(history) : [];
+ var pos = dojo.indexOf(history, value);
+ if (pos != -1){
+ history.splice(pos, 1);
+ }
+ history.push(value);
+ cookie("firebug_history", dojo.toJson(history), 30);
+ while(history.length && !cookie("firebug_history")){
+ history.shift();
+ cookie("firebug_history", dojo.toJson(history), 30);
+ }
+ historyCommandLine = null;
+ historyPosition = -1;
+ }
+
+ function navigateHistory(direction){
+ var history = cookie("firebug_history");
+ history = (history) ? dojo.fromJson(history) : [];
+ if(!history.length){
+ return;
+ }
+
+ if(historyCommandLine === null){
+ historyCommandLine = commandLine.value;
+ }
+
+ if(historyPosition == -1){
+ historyPosition = history.length;
+ }
+
+ if(direction == "older"){
+ --historyPosition;
+ if(historyPosition < 0){
+ historyPosition = 0;
+ }
+ }else if(direction == "newer"){
+ ++historyPosition;
+ if(historyPosition > history.length){
+ historyPosition = history.length;
+ }
+ }
+
+ if(historyPosition == history.length){
+ commandLine.value = historyCommandLine;
+ historyCommandLine = null;
+ }else{
+ commandLine.value = history[historyPosition];
+ }
+ }
+
+ function cookie(name, value){
+ var c = document.cookie;
+ if(arguments.length == 1){
+ var matches = c.match(new RegExp("(?:^|; )" + name + "=([^;]*)"));
+ return matches ? decodeURIComponent(matches[1]) : undefined; // String or undefined
+ }else{
+ var d = new Date();
+ d.setMonth(d.getMonth()+1);
+ document.cookie = name + "=" + encodeURIComponent(value) + ((d.toUtcString) ? "; expires=" + d.toUTCString() : "");
+ }
+ };
+
+ function isArray(it){
+ return it && it instanceof Array || typeof it == "array";
+ }
+
+ //***************************************************************************************************
+ // Print Object Helpers
+ function getAtts(o){
+ //Get amount of items in an object
+ if(isArray(o)){
+ return "[array with " + o.length + " slots]";
+ }else{
+ var i = 0;
+ for(var nm in o){
+ i++;
+ }
+ return "{object with " + i + " items}";
+ }
+ }
+
+ function printObject(o, i, txt, used){
+ // Recursively trace object, indenting to represent depth for display in object inspector
+ // TODO: counter to prevent overly complex or looped objects (will probably help with dom nodes)
+ var br = "\n"; // using a <pre>... otherwise we'd need a <br />
+ var ind = " ";
+ txt = txt || "";
+ i = i || ind;
+ used = used || [];
+ looking:
+ for(var nm in o){
+ if(o[nm] === window || o[nm] === document){
+ continue;
+ }else if(o[nm] && o[nm].nodeType){
+ if(o[nm].nodeType == 1){
+ txt += i+nm + " : < "+o[nm].tagName+" id=\""+ o[nm].id+"\" />" + br;
+ }else if(o[nm].nodeType == 3){
+ txt += i+nm + " : [ TextNode "+o[nm].data + " ]" + br;
+ }
+ }else if(typeof o[nm] == "object" && (o[nm] instanceof String || o[nm] instanceof Number || o[nm] instanceof Boolean)){
+ txt += i+nm + " : " + o[nm] + br;
+ }else if(typeof(o[nm]) == "object" && o[nm]){
+ for(var j = 0, seen; seen = used[j]; j++){
+ if(o[nm] === seen){
+ txt += i+nm + " : RECURSION" + br;
+ continue looking;
+ }
+ }
+ used.push(o[nm]);
+ txt += i+nm +" -> " + getAtts(o[nm]) + br;
+ txt += printObject(o[nm], i+ind, "", used);
+ }else if(typeof o[nm] == "undefined"){
+ txt += i+nm + " : undefined" + br;
+ }else if(nm == "toString" && typeof o[nm] == "function"){
+ var toString = o[nm]();
+ if(typeof toString == "string" && toString.match(/function ?(.*?)\(/)){
+ toString = escapeHTML(getObjectAbbr(o[nm]));
+ }
+ txt += i+nm +" : " + toString + br;
+ }else{
+ txt += i+nm +" : "+ escapeHTML(getObjectAbbr(o[nm])) + br;
+ }
+ }
+ txt += br; // keeps data from running to the edge of page
+ return txt;
+ }
+
+ function getObjectAbbr(obj){
+ // Gets an abbreviation of an object for display in log
+ // X items in object, including id
+ // X items in an array
+ // TODO: Firebug Sr. actually goes by char count
+ var isError = (obj instanceof Error);
+ var nm = (obj && (obj.id || obj.name || obj.ObjectID || obj.widgetId));
+ if(!isError && nm){ return "{"+nm+"}"; }
+
+ var obCnt = 2;
+ var arCnt = 4;
+ var cnt = 0;
+
+ if(isError){
+ nm = "[ Error: "+(obj.message || obj.description || obj)+" ]";
+ }else if(isArray(obj)){
+ nm = "[" + obj.slice(0,arCnt).join(",");
+ if(obj.length > arCnt){
+ nm += " ... ("+obj.length+" items)";
+ }
+ nm += "]";
+ }else if(typeof obj == "function"){
+ nm = obj + "";
+ var reg = /function\s*([^\(]*)(\([^\)]*\))[^\{]*\{/;
+ var m = reg.exec(nm);
+ if(m){
+ if(!m[1]){
+ m[1] = "function";
+ }
+ nm = m[1] + m[2];
+ }else{
+ nm = "function()";
+ }
+ }else if(typeof obj != "object" || typeof obj == "string"){
+ nm = obj + "";
+ }else{
+ nm = "{";
+ for(var i in obj){
+ cnt++;
+ if(cnt > obCnt){ break; }
+ nm += i+"="+obj[i]+" ";
+ }
+ nm+="}";
+ }
+
+ return nm;
+ }
+
+ //*************************************************************************************
+
+ window.onerror = onError;
+ addEvent(document, dojo.isIE || dojo.isSafari ? "keydown" : "keypress", onKeyDown);
+
+ if( (document.documentElement.getAttribute("debug") == "true")||
+ (dojo.config.isDebug)
+ ){
+ toggleConsole(true);
+ }
+})();
+}
+
+}
diff --git a/includes/js/dojo/_firebug/infoIcon.png b/includes/js/dojo/_firebug/infoIcon.png
new file mode 100644
index 0000000..da1e533
--- /dev/null
+++ b/includes/js/dojo/_firebug/infoIcon.png
Binary files differ
diff --git a/includes/js/dojo/_firebug/warningIcon.png b/includes/js/dojo/_firebug/warningIcon.png
new file mode 100644
index 0000000..de51084
--- /dev/null
+++ b/includes/js/dojo/_firebug/warningIcon.png
Binary files differ
diff --git a/includes/js/dojo/back.js b/includes/js/dojo/back.js
new file mode 100644
index 0000000..3c62b82
--- /dev/null
+++ b/includes/js/dojo/back.js
@@ -0,0 +1,394 @@
+if(!dojo._hasResource["dojo.back"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.back"] = true;
+dojo.provide("dojo.back");
+
+/*=====
+dojo.back = {
+ // summary: Browser history management resources
+}
+=====*/
+
+
+(function(){
+ var back = dojo.back;
+
+ // everyone deals with encoding the hash slightly differently
+
+ function getHash(){
+ var h = window.location.hash;
+ if(h.charAt(0) == "#"){ h = h.substring(1); }
+ return dojo.isMozilla ? h : decodeURIComponent(h);
+ }
+
+ function setHash(h){
+ if(!h){ h = ""; }
+ window.location.hash = encodeURIComponent(h);
+ historyCounter = history.length;
+ }
+
+ // if we're in the test for these methods, expose them on dojo.back. ok'd with alex.
+ if(dojo.exists("tests.back-hash")){
+ back.getHash = getHash;
+ back.setHash = setHash;
+ }
+
+ var initialHref = (typeof(window) !== "undefined") ? window.location.href : "";
+ var initialHash = (typeof(window) !== "undefined") ? getHash() : "";
+ var initialState = null;
+
+ var locationTimer = null;
+ var bookmarkAnchor = null;
+ var historyIframe = null;
+ var forwardStack = [];
+ var historyStack = [];
+ var moveForward = false;
+ var changingUrl = false;
+ var historyCounter;
+
+ function handleBackButton(){
+ //summary: private method. Do not call this directly.
+
+ //The "current" page is always at the top of the history stack.
+ //console.debug("handlingBackButton");
+ var current = historyStack.pop();
+ if(!current){ return; }
+ var last = historyStack[historyStack.length-1];
+ if(!last && historyStack.length == 0){
+ last = initialState;
+ }
+ if(last){
+ if(last.kwArgs["back"]){
+ last.kwArgs["back"]();
+ }else if(last.kwArgs["backButton"]){
+ last.kwArgs["backButton"]();
+ }else if(last.kwArgs["handle"]){
+ last.kwArgs.handle("back");
+ }
+ }
+ forwardStack.push(current);
+ //console.debug("done handling back");
+ }
+
+ back.goBack = handleBackButton;
+
+ function handleForwardButton(){
+ //summary: private method. Do not call this directly.
+ //console.debug("handling forward");
+ var last = forwardStack.pop();
+ if(!last){ return; }
+ if(last.kwArgs["forward"]){
+ last.kwArgs.forward();
+ }else if(last.kwArgs["forwardButton"]){
+ last.kwArgs.forwardButton();
+ }else if(last.kwArgs["handle"]){
+ last.kwArgs.handle("forward");
+ }
+ historyStack.push(last);
+ //console.debug("done handling forward");
+ }
+
+ back.goForward = handleForwardButton;
+
+ function createState(url, args, hash){
+ //summary: private method. Do not call this directly.
+ return {"url": url, "kwArgs": args, "urlHash": hash}; //Object
+ }
+
+ function getUrlQuery(url){
+ //summary: private method. Do not call this directly.
+ var segments = url.split("?");
+ if(segments.length < 2){
+ return null; //null
+ }
+ else{
+ return segments[1]; //String
+ }
+ }
+
+ function loadIframeHistory(){
+ //summary: private method. Do not call this directly.
+ var url = (dojo.config["dojoIframeHistoryUrl"] || dojo.moduleUrl("dojo", "resources/iframe_history.html")) + "?" + (new Date()).getTime();
+ moveForward = true;
+ if(historyIframe){
+ dojo.isSafari ? historyIframe.location = url : window.frames[historyIframe.name].location = url;
+ }else{
+ //console.warn("dojo.back: Not initialised. You need to call dojo.back.init() from a <script> block that lives inside the <body> tag.");
+ }
+ return url; //String
+ }
+
+ function checkLocation(){
+ //console.debug("checking url");
+ if(!changingUrl){
+ var hsl = historyStack.length;
+
+ var hash = getHash();
+
+ if((hash === initialHash||window.location.href == initialHref)&&(hsl == 1)){
+ // FIXME: could this ever be a forward button?
+ // we can't clear it because we still need to check for forwards. Ugg.
+ // clearInterval(this.locationTimer);
+ handleBackButton();
+ return;
+ }
+
+ // first check to see if we could have gone forward. We always halt on
+ // a no-hash item.
+ if(forwardStack.length > 0){
+ if(forwardStack[forwardStack.length-1].urlHash === hash){
+ handleForwardButton();
+ return;
+ }
+ }
+
+ // ok, that didn't work, try someplace back in the history stack
+ if((hsl >= 2)&&(historyStack[hsl-2])){
+ if(historyStack[hsl-2].urlHash === hash){
+ handleBackButton();
+ return;
+ }
+ }
+
+ if(dojo.isSafari && dojo.isSafari < 3){
+ var hisLen = history.length;
+ if(hisLen > historyCounter) handleForwardButton();
+ else if(hisLen < historyCounter) handleBackButton();
+ historyCounter = hisLen;
+ }
+ }
+ //console.debug("done checking");
+ };
+
+ back.init = function(){
+ //summary: Initializes the undo stack. This must be called from a <script>
+ // block that lives inside the <body> tag to prevent bugs on IE.
+ if(dojo.byId("dj_history")){ return; } // prevent reinit
+ var src = dojo.config["dojoIframeHistoryUrl"] || dojo.moduleUrl("dojo", "resources/iframe_history.html");
+ document.write('<iframe style="border:0;width:1px;height:1px;position:absolute;visibility:hidden;bottom:0;right:0;" name="dj_history" id="dj_history" src="' + src + '"></iframe>');
+ };
+
+ back.setInitialState = function(/*Object*/args){
+ //summary:
+ // Sets the state object and back callback for the very first page
+ // that is loaded.
+ //description:
+ // It is recommended that you call this method as part of an event
+ // listener that is registered via dojo.addOnLoad().
+ //args: Object
+ // See the addToHistory() function for the list of valid args properties.
+ initialState = createState(initialHref, args, initialHash);
+ };
+
+ //FIXME: Make these doc comments not be awful. At least they're not wrong.
+ //FIXME: Would like to support arbitrary back/forward jumps. Have to rework iframeLoaded among other things.
+ //FIXME: is there a slight race condition in moz using change URL with the timer check and when
+ // the hash gets set? I think I have seen a back/forward call in quick succession, but not consistent.
+
+
+ /*=====
+ dojo.__backArgs = function(kwArgs){
+ // back: Function?
+ // A function to be called when this state is reached via the user
+ // clicking the back button.
+ // forward: Function?
+ // Upon return to this state from the "back, forward" combination
+ // of navigation steps, this function will be called. Somewhat
+ // analgous to the semantic of an "onRedo" event handler.
+ // changeUrl: Boolean?|String?
+ // Boolean indicating whether or not to create a unique hash for
+ // this state. If a string is passed instead, it is used as the
+ // hash.
+ }
+ =====*/
+
+ back.addToHistory = function(/*dojo.__backArgs*/ args){
+ // summary:
+ // adds a state object (args) to the history list.
+ // description:
+ // To support getting back button notifications, the object
+ // argument should implement a function called either "back",
+ // "backButton", or "handle". The string "back" will be passed as
+ // the first and only argument to this callback.
+ //
+ // To support getting forward button notifications, the object
+ // argument should implement a function called either "forward",
+ // "forwardButton", or "handle". The string "forward" will be
+ // passed as the first and only argument to this callback.
+ //
+ // If you want the browser location string to change, define "changeUrl" on the object. If the
+ // value of "changeUrl" is true, then a unique number will be appended to the URL as a fragment
+ // identifier (http://some.domain.com/path#uniquenumber). If it is any other value that does
+ // not evaluate to false, that value will be used as the fragment identifier. For example,
+ // if changeUrl: 'page1', then the URL will look like: http://some.domain.com/path#page1
+ //
+ // example:
+ // | dojo.back.addToHistory({
+ // | back: function(){ console.debug('back pressed'); },
+ // | forward: function(){ console.debug('forward pressed'); },
+ // | changeUrl: true
+ // | });
+
+ // BROWSER NOTES:
+ // Safari 1.2:
+ // back button "works" fine, however it's not possible to actually
+ // DETECT that you've moved backwards by inspecting window.location.
+ // Unless there is some other means of locating.
+ // FIXME: perhaps we can poll on history.length?
+ // Safari 2.0.3+ (and probably 1.3.2+):
+ // works fine, except when changeUrl is used. When changeUrl is used,
+ // Safari jumps all the way back to whatever page was shown before
+ // the page that uses dojo.undo.browser support.
+ // IE 5.5 SP2:
+ // back button behavior is macro. It does not move back to the
+ // previous hash value, but to the last full page load. This suggests
+ // that the iframe is the correct way to capture the back button in
+ // these cases.
+ // Don't test this page using local disk for MSIE. MSIE will not create
+ // a history list for iframe_history.html if served from a file: URL.
+ // The XML served back from the XHR tests will also not be properly
+ // created if served from local disk. Serve the test pages from a web
+ // server to test in that browser.
+ // IE 6.0:
+ // same behavior as IE 5.5 SP2
+ // Firefox 1.0+:
+ // the back button will return us to the previous hash on the same
+ // page, thereby not requiring an iframe hack, although we do then
+ // need to run a timer to detect inter-page movement.
+
+ //If addToHistory is called, then that means we prune the
+ //forward stack -- the user went back, then wanted to
+ //start a new forward path.
+ forwardStack = [];
+
+ var hash = null;
+ var url = null;
+ if(!historyIframe){
+ if(dojo.config["useXDomain"] && !dojo.config["dojoIframeHistoryUrl"]){
+ console.debug("dojo.back: When using cross-domain Dojo builds,"
+ + " please save iframe_history.html to your domain and set djConfig.dojoIframeHistoryUrl"
+ + " to the path on your domain to iframe_history.html");
+ }
+ historyIframe = window.frames["dj_history"];
+ }
+ if(!bookmarkAnchor){
+ bookmarkAnchor = document.createElement("a");
+ dojo.body().appendChild(bookmarkAnchor);
+ bookmarkAnchor.style.display = "none";
+ }
+ if(args["changeUrl"]){
+ hash = ""+ ((args["changeUrl"]!==true) ? args["changeUrl"] : (new Date()).getTime());
+
+ //If the current hash matches the new one, just replace the history object with
+ //this new one. It doesn't make sense to track different state objects for the same
+ //logical URL. This matches the browser behavior of only putting in one history
+ //item no matter how many times you click on the same #hash link, at least in Firefox
+ //and Safari, and there is no reliable way in those browsers to know if a #hash link
+ //has been clicked on multiple times. So making this the standard behavior in all browsers
+ //so that dojo.back's behavior is the same in all browsers.
+ if(historyStack.length == 0 && initialState.urlHash == hash){
+ initialState = createState(url, args, hash);
+ return;
+ }else if(historyStack.length > 0 && historyStack[historyStack.length - 1].urlHash == hash){
+ historyStack[historyStack.length - 1] = createState(url, args, hash);
+ return;
+ }
+
+ changingUrl = true;
+ setTimeout(function() {
+ setHash(hash);
+ changingUrl = false;
+ }, 1);
+ bookmarkAnchor.href = hash;
+
+ if(dojo.isIE){
+ url = loadIframeHistory();
+
+ var oldCB = args["back"]||args["backButton"]||args["handle"];
+
+ //The function takes handleName as a parameter, in case the
+ //callback we are overriding was "handle". In that case,
+ //we will need to pass the handle name to handle.
+ var tcb = function(handleName){
+ if(getHash() != ""){
+ setTimeout(function() { setHash(hash); }, 1);
+ }
+ //Use apply to set "this" to args, and to try to avoid memory leaks.
+ oldCB.apply(this, [handleName]);
+ };
+
+ //Set interceptor function in the right place.
+ if(args["back"]){
+ args.back = tcb;
+ }else if(args["backButton"]){
+ args.backButton = tcb;
+ }else if(args["handle"]){
+ args.handle = tcb;
+ }
+
+ var oldFW = args["forward"]||args["forwardButton"]||args["handle"];
+
+ //The function takes handleName as a parameter, in case the
+ //callback we are overriding was "handle". In that case,
+ //we will need to pass the handle name to handle.
+ var tfw = function(handleName){
+ if(getHash() != ""){
+ setHash(hash);
+ }
+ if(oldFW){ // we might not actually have one
+ //Use apply to set "this" to args, and to try to avoid memory leaks.
+ oldFW.apply(this, [handleName]);
+ }
+ };
+
+ //Set interceptor function in the right place.
+ if(args["forward"]){
+ args.forward = tfw;
+ }else if(args["forwardButton"]){
+ args.forwardButton = tfw;
+ }else if(args["handle"]){
+ args.handle = tfw;
+ }
+
+ }else if(!dojo.isIE){
+ // start the timer
+ if(!locationTimer){
+ locationTimer = setInterval(checkLocation, 200);
+ }
+
+ }
+ }else{
+ url = loadIframeHistory();
+ }
+
+ historyStack.push(createState(url, args, hash));
+ };
+
+ back._iframeLoaded = function(evt, ifrLoc){
+ //summary:
+ // private method. Do not call this directly.
+ var query = getUrlQuery(ifrLoc.href);
+ if(query == null){
+ // alert("iframeLoaded");
+ // we hit the end of the history, so we should go back
+ if(historyStack.length == 1){
+ handleBackButton();
+ }
+ return;
+ }
+ if(moveForward){
+ // we were expecting it, so it's not either a forward or backward movement
+ moveForward = false;
+ return;
+ }
+
+ //Check the back stack first, since it is more likely.
+ //Note that only one step back or forward is supported.
+ if(historyStack.length >= 2 && query == getUrlQuery(historyStack[historyStack.length-2].url)){
+ handleBackButton();
+ }else if(forwardStack.length > 0 && query == getUrlQuery(forwardStack[forwardStack.length-1].url)){
+ handleForwardButton();
+ }
+ };
+ })();
+
+}
diff --git a/includes/js/dojo/behavior.js b/includes/js/dojo/behavior.js
new file mode 100644
index 0000000..012f940
--- /dev/null
+++ b/includes/js/dojo/behavior.js
@@ -0,0 +1,185 @@
+if(!dojo._hasResource["dojo.behavior"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.behavior"] = true;
+dojo.provide("dojo.behavior");
+
+dojo.behavior = new function(){
+ function arrIn(obj, name){
+ if(!obj[name]){ obj[name] = []; }
+ return obj[name];
+ }
+
+ var _inc = 0;
+
+ function forIn(obj, scope, func){
+ var tmpObj = {};
+ for(var x in obj){
+ if(typeof tmpObj[x] == "undefined"){
+ if(!func){
+ scope(obj[x], x);
+ }else{
+ func.call(scope, obj[x], x);
+ }
+ }
+ }
+ }
+
+ // FIXME: need a better test so we don't exclude nightly Safari's!
+ this._behaviors = {};
+ this.add = function(behaviorObj){
+ // summary:
+ // add the specified behavior to the list of behaviors which will
+ // be applied the next time apply() is called. Calls to add() for
+ // an already existing behavior do not replace the previous rules,
+ // but are instead additive. New nodes which match the rule will
+ // have all add()-ed behaviors applied to them when matched.
+ //
+ // description:
+ // behavior objects are specified in the following format(s):
+ //
+ // {
+ // "#id": {
+ // "found": function(element){
+ // // ...
+ // },
+ //
+ // "onblah": {targetObj: foo, targetFunc: "bar"},
+ //
+ // "onblarg": "/foo/bar/baz/blarg",
+ //
+ // "onevent": function(evt){
+ // },
+ //
+ // "onotherevent: function(evt){
+ // // ...
+ // }
+ // },
+ //
+ // "#id2": {
+ // // ...
+ // },
+ //
+ // "#id3": function(element){
+ // // ...
+ // },
+ //
+ // // publish the match on a topic
+ // "#id4": "/found/topic/name",
+ //
+ // // match all direct descendants
+ // "#id4 > *": function(element){
+ // // ...
+ // },
+ //
+ // // match the first child node that's an element
+ // "#id4 > :first-child": { ... },
+ //
+ // // match the last child node that's an element
+ // "#id4 > :last-child": { ... },
+ //
+ // // all elements of type tagname
+ // "tagname": {
+ // // ...
+ // },
+ //
+ // "tagname1 tagname2 tagname3": {
+ // // ...
+ // },
+ //
+ // ".classname": {
+ // // ...
+ // },
+ //
+ // "tagname.classname": {
+ // // ...
+ // },
+ // }
+ //
+ // The "found" method is a generalized handler that's called as soon
+ // as the node matches the selector. Rules for values that follow also
+ // apply to the "found" key.
+ //
+ // The "on*" handlers are attached with dojo.connect().
+ //
+ // If the value corresponding to the ID key is a function and not a
+ // list, it's treated as though it was the value of "found".
+
+ var tmpObj = {};
+ forIn(behaviorObj, this, function(behavior, name){
+ var tBehavior = arrIn(this._behaviors, name);
+ if(typeof tBehavior["id"] != "number"){
+ tBehavior.id = _inc++;
+ }
+ var cversion = [];
+ tBehavior.push(cversion);
+ if((dojo.isString(behavior))||(dojo.isFunction(behavior))){
+ behavior = { found: behavior };
+ }
+ forIn(behavior, function(rule, ruleName){
+ arrIn(cversion, ruleName).push(rule);
+ });
+ });
+ }
+
+ var _applyToNode = function(node, action, ruleSetName){
+ if(dojo.isString(action)){
+ if(ruleSetName == "found"){
+ dojo.publish(action, [ node ]);
+ }else{
+ dojo.connect(node, ruleSetName, function(){
+ dojo.publish(action, arguments);
+ });
+ }
+ }else if(dojo.isFunction(action)){
+ if(ruleSetName == "found"){
+ action(node);
+ }else{
+ dojo.connect(node, ruleSetName, action);
+ }
+ }
+ }
+
+ this.apply = function(){
+ // summary:
+ // applies all currently registered behaviors to the document,
+ // taking care to ensure that only incremental updates are made
+ // since the last time add() or apply() were called. If new
+ // matching nodes have been added, all rules in a behavior will be
+ // applied to that node. For previously matched nodes, only
+ // behaviors which have been added since the last call to apply()
+ // will be added to the nodes.
+ forIn(this._behaviors, function(tBehavior, id){
+ dojo.query(id).forEach(
+ function(elem){
+ var runFrom = 0;
+ var bid = "_dj_behavior_"+tBehavior.id;
+ if(typeof elem[bid] == "number"){
+ runFrom = elem[bid];
+ // console.debug(bid, runFrom);
+ if(runFrom == (tBehavior.length)){
+ return;
+ }
+ }
+ // run through the versions, applying newer rules at each step
+
+ for(var x=runFrom, tver; tver = tBehavior[x]; x++){
+ // console.debug(tver);
+ forIn(tver, function(ruleSet, ruleSetName){
+ if(dojo.isArray(ruleSet)){
+ dojo.forEach(ruleSet, function(action){
+ _applyToNode(elem, action, ruleSetName);
+ });
+ }
+ });
+ }
+
+ // ensure that re-application only adds new rules to the node
+ elem[bid] = tBehavior.length;
+ }
+ );
+ });
+ }
+}
+
+dojo.addOnLoad(dojo.behavior, "apply");
+
+}
diff --git a/includes/js/dojo/build.txt b/includes/js/dojo/build.txt
new file mode 100644
index 0000000..e1d08c6
--- /dev/null
+++ b/includes/js/dojo/build.txt
@@ -0,0 +1,126 @@
+Files baked into this build:
+
+dojo.js:
+./jslib/dojoGuardStart.jsfrag
+./../../dojo/_base/_loader/bootstrap.js
+./../../dojo/_base/_loader/loader.js
+./../../dojo/_base/_loader/hostenv_browser.js
+./../../release/dojo-release-1.1.1/dojo/_base/lang.js
+./../../release/dojo-release-1.1.1/dojo/_base/declare.js
+./../../release/dojo-release-1.1.1/dojo/_base/connect.js
+./../../release/dojo-release-1.1.1/dojo/_base/Deferred.js
+./../../release/dojo-release-1.1.1/dojo/_base/json.js
+./../../release/dojo-release-1.1.1/dojo/_base/array.js
+./../../release/dojo-release-1.1.1/dojo/_base/Color.js
+./../../release/dojo-release-1.1.1/dojo/_base.js
+./../../release/dojo-release-1.1.1/dojo/_base/window.js
+./../../release/dojo-release-1.1.1/dojo/_base/event.js
+./../../release/dojo-release-1.1.1/dojo/_base/html.js
+./../../release/dojo-release-1.1.1/dojo/_base/NodeList.js
+./../../release/dojo-release-1.1.1/dojo/_base/query.js
+./../../release/dojo-release-1.1.1/dojo/_base/xhr.js
+./../../release/dojo-release-1.1.1/dojo/_base/fx.js
+./../../release/dojo-release-1.1.1/dojo/_base/browser.js
+./jslib/dojoGuardEnd.jsfrag
+
+../dijit/dijit.js:
+./../../release/dojo-release-1.1.1/dijit/_base/focus.js
+./../../release/dojo-release-1.1.1/dijit/_base/manager.js
+./../../release/dojo-release-1.1.1/dijit/_base/place.js
+./../../release/dojo-release-1.1.1/dijit/_base/window.js
+./../../release/dojo-release-1.1.1/dijit/_base/popup.js
+./../../release/dojo-release-1.1.1/dijit/_base/scroll.js
+./../../release/dojo-release-1.1.1/dijit/_base/sniff.js
+./../../release/dojo-release-1.1.1/dijit/_base/bidi.js
+./../../release/dojo-release-1.1.1/dijit/_base/typematic.js
+./../../release/dojo-release-1.1.1/dijit/_base/wai.js
+./../../release/dojo-release-1.1.1/dijit/_base.js
+./../../release/dojo-release-1.1.1/dojo/date/stamp.js
+./../../release/dojo-release-1.1.1/dojo/parser.js
+./../../release/dojo-release-1.1.1/dijit/_Widget.js
+./../../release/dojo-release-1.1.1/dojo/string.js
+./../../release/dojo-release-1.1.1/dijit/_Templated.js
+./../../release/dojo-release-1.1.1/dijit/_Container.js
+./../../release/dojo-release-1.1.1/dijit/layout/_LayoutWidget.js
+./../../release/dojo-release-1.1.1/dijit/form/_FormWidget.js
+./../../release/dojo-release-1.1.1/dijit/dijit.js
+
+../dijit/dijit-all.js:
+./../../release/dojo-release-1.1.1/dojo/colors.js
+./../../release/dojo-release-1.1.1/dojo/i18n.js
+./../../release/dojo-release-1.1.1/dijit/ColorPalette.js
+./../../release/dojo-release-1.1.1/dijit/Declaration.js
+./../../release/dojo-release-1.1.1/dojo/dnd/common.js
+./../../release/dojo-release-1.1.1/dojo/dnd/autoscroll.js
+./../../release/dojo-release-1.1.1/dojo/dnd/Mover.js
+./../../release/dojo-release-1.1.1/dojo/dnd/Moveable.js
+./../../release/dojo-release-1.1.1/dojo/dnd/TimedMoveable.js
+./../../release/dojo-release-1.1.1/dojo/fx.js
+./../../release/dojo-release-1.1.1/dijit/layout/ContentPane.js
+./../../release/dojo-release-1.1.1/dijit/form/Form.js
+./../../release/dojo-release-1.1.1/dijit/Dialog.js
+./../../release/dojo-release-1.1.1/dijit/_editor/selection.js
+./../../release/dojo-release-1.1.1/dijit/_editor/html.js
+./../../release/dojo-release-1.1.1/dijit/_editor/RichText.js
+./../../release/dojo-release-1.1.1/dijit/Toolbar.js
+./../../release/dojo-release-1.1.1/dijit/form/Button.js
+./../../release/dojo-release-1.1.1/dijit/_editor/_Plugin.js
+./../../release/dojo-release-1.1.1/dijit/Editor.js
+./../../release/dojo-release-1.1.1/dijit/Menu.js
+./../../release/dojo-release-1.1.1/dojo/regexp.js
+./../../release/dojo-release-1.1.1/dojo/number.js
+./../../release/dojo-release-1.1.1/dijit/ProgressBar.js
+./../../release/dojo-release-1.1.1/dijit/TitlePane.js
+./../../release/dojo-release-1.1.1/dijit/Tooltip.js
+./../../release/dojo-release-1.1.1/dojo/cookie.js
+./../../release/dojo-release-1.1.1/dijit/Tree.js
+./../../release/dojo-release-1.1.1/dijit/form/TextBox.js
+./../../release/dojo-release-1.1.1/dijit/InlineEditBox.js
+./../../release/dojo-release-1.1.1/dijit/form/CheckBox.js
+./../../release/dojo-release-1.1.1/dijit/form/ValidationTextBox.js
+./../../release/dojo-release-1.1.1/dijit/form/ComboBox.js
+./../../release/dojo-release-1.1.1/dojo/cldr/monetary.js
+./../../release/dojo-release-1.1.1/dojo/currency.js
+./../../release/dojo-release-1.1.1/dijit/form/NumberTextBox.js
+./../../release/dojo-release-1.1.1/dijit/form/CurrencyTextBox.js
+./../../release/dojo-release-1.1.1/dojo/cldr/supplemental.js
+./../../release/dojo-release-1.1.1/dojo/date.js
+./../../release/dojo-release-1.1.1/dojo/date/locale.js
+./../../release/dojo-release-1.1.1/dijit/_Calendar.js
+./../../release/dojo-release-1.1.1/dijit/form/_DateTimeTextBox.js
+./../../release/dojo-release-1.1.1/dijit/form/DateTextBox.js
+./../../release/dojo-release-1.1.1/dijit/form/FilteringSelect.js
+./../../release/dojo-release-1.1.1/dijit/form/_Spinner.js
+./../../release/dojo-release-1.1.1/dijit/form/NumberSpinner.js
+./../../release/dojo-release-1.1.1/dojo/dnd/move.js
+./../../release/dojo-release-1.1.1/dijit/form/Slider.js
+./../../release/dojo-release-1.1.1/dijit/form/Textarea.js
+./../../release/dojo-release-1.1.1/dijit/layout/StackContainer.js
+./../../release/dojo-release-1.1.1/dijit/layout/AccordionContainer.js
+./../../release/dojo-release-1.1.1/dijit/layout/BorderContainer.js
+./../../release/dojo-release-1.1.1/dijit/layout/LayoutContainer.js
+./../../release/dojo-release-1.1.1/dijit/layout/LinkPane.js
+./../../release/dojo-release-1.1.1/dijit/layout/SplitContainer.js
+./../../release/dojo-release-1.1.1/dijit/layout/TabContainer.js
+./../../release/dojo-release-1.1.1/dijit/dijit-all.js
+
+../dojox/off/offline.js:
+./../../release/dojo-release-1.1.1/dojox/storage/Provider.js
+./../../release/dojo-release-1.1.1/dojox/storage/manager.js
+./../../release/dojo-release-1.1.1/dojox/_sql/_crypto.js
+./../../release/dojo-release-1.1.1/dojox/_sql/common.js
+./../../release/dojo-release-1.1.1/dojox/sql.js
+./../../release/dojo-release-1.1.1/dojox/storage/GearsStorageProvider.js
+./../../release/dojo-release-1.1.1/dojox/storage/WhatWGStorageProvider.js
+./../../release/dojo-release-1.1.1/dijit/_base/place.js
+./../../release/dojo-release-1.1.1/dojox/flash/_base.js
+./../../release/dojo-release-1.1.1/dojox/flash.js
+./../../release/dojo-release-1.1.1/dojox/storage/FlashStorageProvider.js
+./../../release/dojo-release-1.1.1/dojox/storage/_common.js
+./../../release/dojo-release-1.1.1/dojox/storage.js
+./../../release/dojo-release-1.1.1/dojox/off/files.js
+./../../release/dojo-release-1.1.1/dojox/off/sync.js
+./../../release/dojo-release-1.1.1/dojox/off/_common.js
+./../../release/dojo-release-1.1.1/dojox/off.js
+./../../release/dojo-release-1.1.1/dojox/off/ui.js
+./../../release/dojo-release-1.1.1/dojox/off/offline.js
diff --git a/includes/js/dojo/cldr/LICENSE b/includes/js/dojo/cldr/LICENSE
new file mode 100644
index 0000000..7aeb1dd
--- /dev/null
+++ b/includes/js/dojo/cldr/LICENSE
@@ -0,0 +1,29 @@
+UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
+
+Unicode Data Files include all data files under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/,
+and http://www.unicode.org/cldr/data/ . Unicode Software includes any source code published in the Unicode Standard or under
+the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/.
+NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR
+OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU
+UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS
+AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
+
+COPYRIGHT AND PERMISSION NOTICE
+Copyright © 1991-2007 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of the Unicode data files and any associated
+documentation (the "Data Files") or Unicode software and any associated documentation (the "Software") to deal in the Data
+Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell
+copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided
+that (a) the above copyright notice(s) and this permission notice appear with all copies of the Data Files or Software, (b) both the
+above copyright notice(s) and this permission notice appear in associated documentation, and (c) there is clear notice in each modified Data File
+or in the Software as well as in the documentation associated with the Data File(s) or Software that the data or software has been modified.
+THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
+INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in these Data Files or Software without prior written authorization of the copyright holder. \ No newline at end of file
diff --git a/includes/js/dojo/cldr/README b/includes/js/dojo/cldr/README
new file mode 100644
index 0000000..3687676
--- /dev/null
+++ b/includes/js/dojo/cldr/README
@@ -0,0 +1,18 @@
+All files within this directory were derived from the Common Locale
+Data Repository (see http://unicode.org/cldr) The CLDR project is
+responsible for the accuracy and maintenance of this data. A copy
+of this data is checked into the Dojo util project as a zip file.
+The XML data is transformed to the JSON-style Javascript you see
+under the nls/ directory. These Javascript files include data
+necessary to do things like format and parse dates, numbers, and
+currencies in different locales to consider cultural differences.
+They are used by other modules in core Dojo such as dojo.date,
+dojo.number and dojo.currency. It usually is not necessary to use
+dojo.cldr directly.
+
+An arbitrary subset of locales have been checked in to dojo/cldr
+under svn. To support other locales, the full set may be generated
+by using xslt scripts in the util/buildscripts/cldr/ ant script.
+Hundreds of locales are supported by the CLDR project.
+
+See terms of use: http://www.unicode.org/copyright.html#Exhibit1
diff --git a/includes/js/dojo/cldr/monetary.js b/includes/js/dojo/cldr/monetary.js
new file mode 100644
index 0000000..e373d00
--- /dev/null
+++ b/includes/js/dojo/cldr/monetary.js
@@ -0,0 +1,27 @@
+if(!dojo._hasResource["dojo.cldr.monetary"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.cldr.monetary"] = true;
+dojo.provide("dojo.cldr.monetary");
+
+dojo.cldr.monetary.getData = function(/*String*/code){
+// summary: A mapping of currency code to currency-specific formatting information. Returns a unique object with properties: places, round.
+// code: an [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code
+
+// from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/currencyData/fractions
+
+ var placesData = {
+ ADP:0,BHD:3,BIF:0,BYR:0,CLF:0,CLP:0,DJF:0,ESP:0,GNF:0,
+ IQD:3,ITL:0,JOD:3,JPY:0,KMF:0,KRW:0,KWD:3,LUF:0,LYD:3,
+ MGA:0,MGF:0,OMR:3,PYG:0,RWF:0,TND:3,TRL:0,VUV:0,XAF:0,
+ XOF:0,XPF:0
+ };
+
+ var roundingData = {CHF:5};
+
+ var places = placesData[code], round = roundingData[code];
+ if(typeof places == "undefined"){ places = 2; }
+ if(typeof round == "undefined"){ round = 0; }
+
+ return {places: places, round: round}; // Object
+};
+
+}
diff --git a/includes/js/dojo/cldr/nls/currency.js b/includes/js/dojo/cldr/nls/currency.js
new file mode 100644
index 0000000..742b390
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/currency.js
@@ -0,0 +1 @@
+({"USD_symbol":"US$","EUR_displayName":"EUR","GBP_displayName":"GBP","JPY_displayName":"JPY","GBP_symbol":"UK£","JPY_symbol":"JP¥","EUR_symbol":"€","USD_displayName":"USD"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/de-de/number.js b/includes/js/dojo/cldr/nls/de-de/number.js
new file mode 100644
index 0000000..35a2d9b
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/de-de/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"#,##0.00 ¤","decimalFormat":"#,##0.###","group":".","scientificFormat":"#E0","percentFormat":"#,##0 %","decimal":",","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/de/currency.js b/includes/js/dojo/cldr/nls/de/currency.js
new file mode 100644
index 0000000..4e7a954
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/de/currency.js
@@ -0,0 +1 @@
+({"HKD_displayName":"Hongkong-Dollar","CHF_displayName":"Schweizer Franken","CHF_symbol":"SFr.","CAD_displayName":"Kanadischer Dollar","CNY_displayName":"Renminbi Yuan","USD_symbol":"$","AUD_displayName":"Australischer Dollar","JPY_displayName":"Yen","USD_displayName":"US-Dollar","GBP_displayName":"Pfund Sterling","EUR_displayName":"Euro","GBP_symbol":"UK£","JPY_symbol":"JP¥","EUR_symbol":"€"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/de/gregorian.js b/includes/js/dojo/cldr/nls/de/gregorian.js
new file mode 100644
index 0000000..2cd17a9
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/de/gregorian.js
@@ -0,0 +1 @@
+({"quarters-format-abbreviated":["Q1","Q2","Q3","Q4"],"dateFormat-medium":"dd.MM.yyyy","field-second":"Sekunde","field-week":"Woche","pm":"nachm.","timeFormat-full":"HH:mm:ss v","dateTimeAvailableFormats":["E d","H","HH:mm","HH:mm:ss","E MMM d","d. MMMM","dd.MM.","d.M.","mm:ss","MM.yy","MMM yy","Q yy","yyyy","MMMM yyyy"],"months-standAlone-narrow":["J","F","M","A","M","J","J","A","S","O","N","D"],"eraNames":["v. Chr.","n. Chr."],"am":"vorm.","days-standAlone-narrow":["S","M","D","M","D","F","S"],"field-year":"Jahr","field-minute":"Minute","timeFormat-medium":"HH:mm:ss","quarters-stand-alone-narrow":["1","2","3","4"],"field-hour":"Stunde","dateFormat-long":"d. MMMM yyyy","field-day":"Tag","field-dayperiod":"Tageshälfte","field-month":"Monat","dateFormat-short":"dd.MM.yy","months-format-wide":["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],"field-era":"Epoche","timeFormat-short":"HH:mm","months-format-abbr":["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],"days-format-wide":["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"],"eraAbbr":["v. Chr.","n. Chr."],"timeFormat-long":"HH:mm:ss z","quarters-format-wide":["1. Quartal","2. Quartal","3. Quartal","4. Quartal"],"dateFormat-full":"EEEE, d. MMMM yyyy","field-weekday":"Wochentag","days-format-abbr":["So","Mo","Di","Mi","Do","Fr","Sa"],"field-zone":"Zone","dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","dateTimeFormats-appendItem-Year":"{0} {1}","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateTimeFormat":"{1} {0}","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/de/number.js b/includes/js/dojo/cldr/nls/de/number.js
new file mode 100644
index 0000000..e6e47f8
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/de/number.js
@@ -0,0 +1 @@
+({"decimalFormat":"#,##0.###","group":".","scientificFormat":"#E0","percentFormat":"#,##0 %","currencyFormat":"#,##0.00 ¤","decimal":",","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/en-au/currency.js b/includes/js/dojo/cldr/nls/en-au/currency.js
new file mode 100644
index 0000000..a65a14b
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/en-au/currency.js
@@ -0,0 +1 @@
+({"AUD_symbol":"$","USD_symbol":"US$","HKD_displayName":"Hong Kong Dollar","CHF_displayName":"Swiss Franc","CHF_symbol":"SwF","JPY_symbol":"¥","HKD_symbol":"HK$","CAD_displayName":"Canadian Dollar","CNY_displayName":"Chinese Yuan Renminbi","AUD_displayName":"Australian Dollar","JPY_displayName":"Japanese Yen","CAD_symbol":"Can$","USD_displayName":"US Dollar","CNY_symbol":"Y","GBP_displayName":"British Pound Sterling","GBP_symbol":"£","EUR_displayName":"Euro","EUR_symbol":"€"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/en-au/gregorian.js b/includes/js/dojo/cldr/nls/en-au/gregorian.js
new file mode 100644
index 0000000..6612d6c
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/en-au/gregorian.js
@@ -0,0 +1 @@
+({"dateFormat-short":"d/MM/yy","dateFormat-medium":"dd/MM/yyyy","dateFormat-long":"d MMMM yyyy","dateFormat-full":"EEEE, d MMMM yyyy","quarters-format-abbreviated":["Q1","Q2","Q3","Q4"],"pm":"PM","timeFormat-full":"h:mm:ss a v","dateTimeFormat":"{1} {0}","dateTimeAvailableFormats":["HH:mm","HH:mm:ss","MMMM d","M/d","mm:ss","MM/yy","Q yy","QQQQ yy","MMM yyyy","yy MMM","yy Q","yyyy"],"months-standAlone-narrow":["J","F","M","A","M","J","J","A","S","O","N","D"],"eraNames":["Before Christ","Anno Domini"],"am":"AM","days-standAlone-narrow":["S","M","T","W","T","F","S"],"timeFormat-medium":"h:mm:ss a","field-dayperiod":"AM/PM","months-format-wide":["January","February","March","April","May","June","July","August","September","October","November","December"],"timeFormat-short":"h:mm a","months-format-abbr":["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"eraAbbr":["BC","AD"],"days-format-wide":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"timeFormat-long":"h:mm:ss a z","quarters-format-wide":["1st quarter","2nd quarter","3rd quarter","4th quarter"],"days-format-abbr":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","field-minute":"Minute","field-weekday":"Day of the Week","dateTimeFormats-appendItem-Year":"{0} {1}","field-era":"Era","field-hour":"Hour","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","field-zone":"Zone","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","field-year":"Year","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","field-week":"Week","field-month":"Month","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","field-second":"Second","field-day":"Day","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","quarters-stand-alone-narrow":["1","2","3","4"],"dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/en-au/number.js b/includes/js/dojo/cldr/nls/en-au/number.js
new file mode 100644
index 0000000..a223279
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/en-au/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"¤#,##0.00","group":",","decimal":".","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","percentFormat":"#,##0%","decimalFormat":"#,##0.###","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/en-ca/currency.js b/includes/js/dojo/cldr/nls/en-ca/currency.js
new file mode 100644
index 0000000..af03325
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/en-ca/currency.js
@@ -0,0 +1 @@
+({"CAD_symbol":"$","USD_symbol":"US$","HKD_displayName":"Hong Kong Dollar","CHF_displayName":"Swiss Franc","CHF_symbol":"SwF","JPY_symbol":"¥","HKD_symbol":"HK$","CAD_displayName":"Canadian Dollar","CNY_displayName":"Chinese Yuan Renminbi","AUD_displayName":"Australian Dollar","JPY_displayName":"Japanese Yen","USD_displayName":"US Dollar","CNY_symbol":"Y","GBP_displayName":"British Pound Sterling","GBP_symbol":"£","AUD_symbol":"$A","EUR_displayName":"Euro","EUR_symbol":"€"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/en-ca/gregorian.js b/includes/js/dojo/cldr/nls/en-ca/gregorian.js
new file mode 100644
index 0000000..b161f0c
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/en-ca/gregorian.js
@@ -0,0 +1 @@
+({"dateFormat-medium":"yyyy-MM-dd","dateFormat-short":"yy-MM-dd","quarters-format-abbreviated":["Q1","Q2","Q3","Q4"],"pm":"PM","timeFormat-full":"h:mm:ss a v","dateTimeFormat":"{1} {0}","dateTimeAvailableFormats":["HH:mm","HH:mm:ss","MMMM d","M/d","mm:ss","MM/yy","Q yy","QQQQ yy","MMM yyyy","yy MMM","yy Q","yyyy"],"months-standAlone-narrow":["J","F","M","A","M","J","J","A","S","O","N","D"],"eraNames":["Before Christ","Anno Domini"],"am":"AM","days-standAlone-narrow":["S","M","T","W","T","F","S"],"timeFormat-medium":"h:mm:ss a","dateFormat-long":"MMMM d, yyyy","field-dayperiod":"AM/PM","months-format-wide":["January","February","March","April","May","June","July","August","September","October","November","December"],"timeFormat-short":"h:mm a","months-format-abbr":["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"eraAbbr":["BC","AD"],"days-format-wide":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"timeFormat-long":"h:mm:ss a z","quarters-format-wide":["1st quarter","2nd quarter","3rd quarter","4th quarter"],"dateFormat-full":"EEEE, MMMM d, yyyy","days-format-abbr":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","field-minute":"Minute","field-weekday":"Day of the Week","dateTimeFormats-appendItem-Year":"{0} {1}","field-era":"Era","field-hour":"Hour","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","field-zone":"Zone","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","field-year":"Year","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","field-week":"Week","field-month":"Month","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","field-second":"Second","field-day":"Day","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","quarters-stand-alone-narrow":["1","2","3","4"],"dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/en-gb/gregorian.js b/includes/js/dojo/cldr/nls/en-gb/gregorian.js
new file mode 100644
index 0000000..df55d7f
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/en-gb/gregorian.js
@@ -0,0 +1 @@
+({"dateFormat-short":"dd/MM/yyyy","timeFormat-long":"HH:mm:ss z","dateFormat-medium":"d MMM yyyy","dateFormat-long":"d MMMM yyyy","timeFormat-medium":"HH:mm:ss","timeFormat-short":"HH:mm","timeFormat-full":"HH:mm:ss v","dateFormat-full":"EEEE, d MMMM yyyy","quarters-format-abbreviated":["Q1","Q2","Q3","Q4"],"pm":"PM","dateTimeFormat":"{1} {0}","dateTimeAvailableFormats":["HH:mm","HH:mm:ss","MMMM d","M/d","mm:ss","MM/yy","Q yy","QQQQ yy","MMM yyyy","yy MMM","yy Q","yyyy"],"months-standAlone-narrow":["J","F","M","A","M","J","J","A","S","O","N","D"],"eraNames":["Before Christ","Anno Domini"],"am":"AM","days-standAlone-narrow":["S","M","T","W","T","F","S"],"field-dayperiod":"AM/PM","months-format-wide":["January","February","March","April","May","June","July","August","September","October","November","December"],"months-format-abbr":["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"eraAbbr":["BC","AD"],"days-format-wide":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"quarters-format-wide":["1st quarter","2nd quarter","3rd quarter","4th quarter"],"days-format-abbr":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","field-minute":"Minute","field-weekday":"Day of the Week","dateTimeFormats-appendItem-Year":"{0} {1}","field-era":"Era","field-hour":"Hour","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","field-zone":"Zone","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","field-year":"Year","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","field-week":"Week","field-month":"Month","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","field-second":"Second","field-day":"Day","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","quarters-stand-alone-narrow":["1","2","3","4"],"dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/en-gb/number.js b/includes/js/dojo/cldr/nls/en-gb/number.js
new file mode 100644
index 0000000..a223279
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/en-gb/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"¤#,##0.00","group":",","decimal":".","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","percentFormat":"#,##0%","decimalFormat":"#,##0.###","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/en-us/currency.js b/includes/js/dojo/cldr/nls/en-us/currency.js
new file mode 100644
index 0000000..8b793f6
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/en-us/currency.js
@@ -0,0 +1 @@
+({"USD_symbol":"$","HKD_displayName":"Hong Kong Dollar","CHF_displayName":"Swiss Franc","CHF_symbol":"SwF","JPY_symbol":"¥","HKD_symbol":"HK$","CAD_displayName":"Canadian Dollar","CNY_displayName":"Chinese Yuan Renminbi","AUD_displayName":"Australian Dollar","JPY_displayName":"Japanese Yen","CAD_symbol":"Can$","USD_displayName":"US Dollar","CNY_symbol":"Y","GBP_displayName":"British Pound Sterling","GBP_symbol":"£","AUD_symbol":"$A","EUR_displayName":"Euro","EUR_symbol":"€"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/en-us/number.js b/includes/js/dojo/cldr/nls/en-us/number.js
new file mode 100644
index 0000000..24c0ad0
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/en-us/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"¤#,##0.00;(¤#,##0.00)","group":",","decimal":".","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","percentFormat":"#,##0%","decimalFormat":"#,##0.###","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/en/currency.js b/includes/js/dojo/cldr/nls/en/currency.js
new file mode 100644
index 0000000..36d441e
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/en/currency.js
@@ -0,0 +1 @@
+({"HKD_displayName":"Hong Kong Dollar","CHF_displayName":"Swiss Franc","CHF_symbol":"SwF","JPY_symbol":"¥","HKD_symbol":"HK$","CAD_displayName":"Canadian Dollar","CNY_displayName":"Chinese Yuan Renminbi","USD_symbol":"$","AUD_displayName":"Australian Dollar","JPY_displayName":"Japanese Yen","CAD_symbol":"Can$","USD_displayName":"US Dollar","CNY_symbol":"Y","GBP_displayName":"British Pound Sterling","GBP_symbol":"£","AUD_symbol":"$A","EUR_displayName":"Euro","EUR_symbol":"€"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/en/gregorian.js b/includes/js/dojo/cldr/nls/en/gregorian.js
new file mode 100644
index 0000000..e994327
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/en/gregorian.js
@@ -0,0 +1 @@
+({"quarters-format-abbreviated":["Q1","Q2","Q3","Q4"],"dateFormat-medium":"MMM d, yyyy","pm":"PM","timeFormat-full":"h:mm:ss a v","dateTimeFormat":"{1} {0}","dateTimeAvailableFormats":["HH:mm","HH:mm:ss","MMMM d","M/d","mm:ss","MM/yy","Q yy","QQQQ yy","MMM yyyy","yy MMM","yy Q","yyyy"],"months-standAlone-narrow":["J","F","M","A","M","J","J","A","S","O","N","D"],"eraNames":["Before Christ","Anno Domini"],"am":"AM","days-standAlone-narrow":["S","M","T","W","T","F","S"],"timeFormat-medium":"h:mm:ss a","dateFormat-long":"MMMM d, yyyy","field-dayperiod":"AM/PM","dateFormat-short":"M/d/yy","months-format-wide":["January","February","March","April","May","June","July","August","September","October","November","December"],"timeFormat-short":"h:mm a","months-format-abbr":["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"eraAbbr":["BC","AD"],"days-format-wide":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"timeFormat-long":"h:mm:ss a z","quarters-format-wide":["1st quarter","2nd quarter","3rd quarter","4th quarter"],"dateFormat-full":"EEEE, MMMM d, yyyy","days-format-abbr":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","field-minute":"Minute","field-weekday":"Day of the Week","dateTimeFormats-appendItem-Year":"{0} {1}","field-era":"Era","field-hour":"Hour","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","field-zone":"Zone","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","field-year":"Year","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","field-week":"Week","field-month":"Month","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","field-second":"Second","field-day":"Day","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","quarters-stand-alone-narrow":["1","2","3","4"],"dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/en/number.js b/includes/js/dojo/cldr/nls/en/number.js
new file mode 100644
index 0000000..24c0ad0
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/en/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"¤#,##0.00;(¤#,##0.00)","group":",","decimal":".","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","percentFormat":"#,##0%","decimalFormat":"#,##0.###","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/es-es/gregorian.js b/includes/js/dojo/cldr/nls/es-es/gregorian.js
new file mode 100644
index 0000000..ed856e2
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/es-es/gregorian.js
@@ -0,0 +1 @@
+({"timeFormat-medium":"H:mm:ss","timeFormat-full":"HH'H'mm''ss\" v","timeFormat-short":"H:mm","quarters-format-abbreviated":["T1","T2","T3","T4"],"dateFormat-medium":"dd/MM/yyyy","field-second":"segundo","field-week":"semana","pm":"p.m.","dateTimeAvailableFormats":"QQQQ 'de' yy","months-standAlone-narrow":["E","F","M","A","M","J","J","A","S","O","N","D"],"eraNames":["antes de Cristo","anno Dómini"],"am":"a.m.","days-standAlone-narrow":["D","L","M","M","J","V","S"],"field-year":"año","field-minute":"minuto","field-hour":"hora","dateFormat-long":"d 'de' MMMM 'de' yyyy","field-day":"día","field-dayperiod":"periodo del día","field-month":"mes","dateFormat-short":"dd/MM/yy","months-format-wide":["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],"field-era":"era","months-format-abbr":["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],"days-format-wide":["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],"eraAbbr":["a.C.","d.C."],"quarters-format-wide":["1er trimestre","2º trimestre","3er trimestre","4º trimestre"],"dateFormat-full":"EEEE d 'de' MMMM 'de' yyyy","field-weekday":"día de la semana","days-format-abbr":["dom","lun","mar","mié","jue","vie","sáb"],"field-zone":"zona","dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","dateTimeFormats-appendItem-Year":"{0} {1}","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateTimeFormat":"{1} {0}","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","timeFormat-long":"HH:mm:ss z","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","quarters-stand-alone-narrow":["1","2","3","4"],"dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/es-es/number.js b/includes/js/dojo/cldr/nls/es-es/number.js
new file mode 100644
index 0000000..336afa8
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/es-es/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"#,##0.00 ¤","group":".","decimal":",","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","percentFormat":"#,##0%","decimalFormat":"#,##0.###","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/es/currency.js b/includes/js/dojo/cldr/nls/es/currency.js
new file mode 100644
index 0000000..40b4661
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/es/currency.js
@@ -0,0 +1 @@
+({"HKD_displayName":"dólar de Hong Kong","CHF_displayName":"franco suizo","CHF_symbol":"SwF","HKD_symbol":"HK$","CAD_displayName":"dólar canadiense","CNY_displayName":"yuan renminbi chino","AUD_displayName":"dólar australiano","JPY_displayName":"yen japonés","CAD_symbol":"Can$","USD_displayName":"dólar estadounidense","CNY_symbol":"Y","GBP_displayName":"libra esterlina británica","AUD_symbol":"$A","EUR_displayName":"euro","USD_symbol":"US$","GBP_symbol":"UK£","JPY_symbol":"JP¥","EUR_symbol":"€"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/es/gregorian.js b/includes/js/dojo/cldr/nls/es/gregorian.js
new file mode 100644
index 0000000..d17374d
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/es/gregorian.js
@@ -0,0 +1 @@
+({"quarters-format-abbreviated":["T1","T2","T3","T4"],"dateFormat-medium":"dd/MM/yyyy","field-second":"segundo","field-week":"semana","pm":"p.m.","timeFormat-full":"hh:mm:ss a v","dateTimeAvailableFormats":"QQQQ 'de' yy","months-standAlone-narrow":["E","F","M","A","M","J","J","A","S","O","N","D"],"eraNames":["antes de Cristo","anno Dómini"],"am":"a.m.","days-standAlone-narrow":["D","L","M","M","J","V","S"],"field-year":"año","field-minute":"minuto","field-hour":"hora","dateFormat-long":"d 'de' MMMM 'de' yyyy","field-day":"día","field-dayperiod":"periodo del día","field-month":"mes","dateFormat-short":"dd/MM/yy","months-format-wide":["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],"field-era":"era","months-format-abbr":["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],"days-format-wide":["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],"eraAbbr":["a.C.","d.C."],"quarters-format-wide":["1er trimestre","2º trimestre","3er trimestre","4º trimestre"],"dateFormat-full":"EEEE d 'de' MMMM 'de' yyyy","field-weekday":"día de la semana","days-format-abbr":["dom","lun","mar","mié","jue","vie","sáb"],"field-zone":"zona","dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","dateTimeFormats-appendItem-Year":"{0} {1}","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","timeFormat-medium":"HH:mm:ss","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateTimeFormat":"{1} {0}","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","timeFormat-long":"HH:mm:ss z","timeFormat-short":"HH:mm","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","quarters-stand-alone-narrow":["1","2","3","4"],"dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/es/number.js b/includes/js/dojo/cldr/nls/es/number.js
new file mode 100644
index 0000000..fa366d8
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/es/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"¤ #,##0.00","group":".","decimal":",","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","percentFormat":"#,##0%","decimalFormat":"#,##0.###","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/fr/currency.js b/includes/js/dojo/cldr/nls/fr/currency.js
new file mode 100644
index 0000000..f85f1d5
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/fr/currency.js
@@ -0,0 +1 @@
+({"HKD_displayName":"dollar de Hong Kong","CHF_displayName":"franc suisse","CHF_symbol":"sFr.","JPY_symbol":"¥JP","HKD_symbol":"$HK","CAD_displayName":"dollar canadien","CNY_displayName":"Yuan Ren-min-bi","USD_symbol":"$US","AUD_displayName":"dollar australien","JPY_displayName":"yen","CAD_symbol":"$Ca","USD_displayName":"dollars américains","GBP_displayName":"livre sterling","GBP_symbol":"£UK","AUD_symbol":"$A","EUR_displayName":"euro","EUR_symbol":"€"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/fr/gregorian.js b/includes/js/dojo/cldr/nls/fr/gregorian.js
new file mode 100644
index 0000000..e605b4d
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/fr/gregorian.js
@@ -0,0 +1 @@
+({"quarters-format-abbreviated":["T1","T2","T3","T4"],"dateFormat-medium":"d MMM yyyy","field-second":"seconde","field-week":"semaine","pm":"PM","timeFormat-full":"HH:mm:ss v","dateTimeFormat":"{1} {0}","dateTimeAvailableFormats":["HH:mm","HH:mm:ss","E d MMM","d MMMM","dd/MM","d/M","mm:ss","MM/yy","MMM yy","Q yy","QQQQ yy","MMMM yyyy"],"months-standAlone-narrow":["J","F","M","A","M","J","J","A","S","O","N","D"],"eraNames":["avant Jésus-Christ","après Jésus-Christ"],"am":"AM","days-standAlone-narrow":["D","L","M","M","J","V","S"],"field-year":"année","field-minute":"minute","timeFormat-medium":"HH:mm:ss","quarters-stand-alone-narrow":["1","2","3","4"],"field-hour":"heure","dateFormat-long":"d MMMM yyyy","field-day":"jour","field-dayperiod":"cadran","field-month":"mois","dateFormat-short":"dd/MM/yy","months-format-wide":["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],"field-era":"ère","timeFormat-short":"HH:mm","months-format-abbr":["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc."],"days-format-wide":["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],"eraAbbr":["av. J.-C.","ap. J.-C."],"timeFormat-long":"HH:mm:ss z","quarters-format-wide":["1er trimestre","2e trimestre","3e trimestre","4e trimestre"],"dateFormat-full":"EEEE d MMMM yyyy","field-weekday":"jour de la semaine","days-format-abbr":["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],"field-zone":"fuseau horaire","dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","dateTimeFormats-appendItem-Year":"{0} {1}","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/fr/number.js b/includes/js/dojo/cldr/nls/fr/number.js
new file mode 100644
index 0000000..e729e2e
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/fr/number.js
@@ -0,0 +1 @@
+({"decimalFormat":"#,##0.###","group":" ","scientificFormat":"#E0","percentFormat":"#,##0 %","currencyFormat":"#,##0.00 ¤","decimal":",","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/gregorian.js b/includes/js/dojo/cldr/nls/gregorian.js
new file mode 100644
index 0000000..9a0fd20
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/gregorian.js
@@ -0,0 +1 @@
+({"dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","field-dayperiod":"Dayperiod","field-minute":"Minute","eraNames":["BCE","CE"],"field-weekday":"Day of the Week","months-standAlone-narrow":["1","2","3","4","5","6","7","8","9","10","11","12"],"dateTimeFormats-appendItem-Year":"{0} {1}","field-era":"Era","field-hour":"Hour","timeFormat-full":"HH:mm:ss v","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","days-standAlone-narrow":["1","2","3","4","5","6","7"],"eraAbbr":["BCE","CE"],"dateFormat-long":"yyyy MMMM d","timeFormat-medium":"HH:mm:ss","field-zone":"Zone","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateFormat-medium":"yyyy MMM d","quarters-format-abbreviated":["Q1","Q2","Q3","Q4"],"dateTimeFormat":"{1} {0}","field-year":"Year","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","field-week":"Week","timeFormat-long":"HH:mm:ss z","months-format-abbr":["1","2","3","4","5","6","7","8","9","10","11","12"],"timeFormat-short":"HH:mm","field-month":"Month","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","days-format-abbr":["1","2","3","4","5","6","7"],"pm":"PM","field-second":"Second","field-day":"Day","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","am":"AM","quarters-stand-alone-narrow":["1","2","3","4"],"dateFormat-short":"yyyy-MM-dd","dateFormat-full":"EEEE, yyyy MMMM dd","months-format-wide":["1","2","3","4","5","6","7","8","9","10","11","12"],"dateTimeAvailableFormats":["E d","H","HH:mm","HH:mm:ss","E MMM d","MMMM d","M-d","mm:ss","yy-MM","yy MMM","yy Q","yyyy"],"dateTimeFormats-appendItem-Era":"{0} {1}","quarters-format-wide":["Q1","Q2","Q3","Q4"],"days-format-wide":["1","2","3","4","5","6","7"],"eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/it-it/gregorian.js b/includes/js/dojo/cldr/nls/it-it/gregorian.js
new file mode 100644
index 0000000..cc717b9
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/it-it/gregorian.js
@@ -0,0 +1 @@
+({"timeFormat-long":"H:mm:ss z","quarters-format-abbreviated":["T1","T2","T3","T4"],"dateFormat-medium":"dd/MMM/yyyy","field-second":"secondo","field-week":"settimana","pm":"p.","months-standAlone-narrow":["G","F","M","A","M","G","L","A","S","O","N","D"],"am":"m.","days-standAlone-narrow":["D","L","M","M","G","V","S"],"field-year":"anno","field-minute":"minuto","field-hour":"ora","dateFormat-long":"dd MMMM yyyy","field-day":"giorno","field-dayperiod":"periodo del giorno","field-month":"mese","dateFormat-short":"dd/MM/yy","months-format-wide":["gennaio","febbraio","marzo","aprile","maggio","giugno","luglio","agosto","settembre","ottobre","novembre","dicembre"],"field-era":"era","months-format-abbr":["gen","feb","mar","apr","mag","giu","lug","ago","set","ott","nov","dic"],"days-format-wide":["domenica","lunedì","martedì","mercoledì","giovedì","venerdì","sabato"],"eraAbbr":["aC","dC"],"quarters-format-wide":["1o trimestre","2o trimestre","3o trimestre","4o trimestre"],"dateFormat-full":"EEEE d MMMM yyyy","field-weekday":"giorno della settimana","days-format-abbr":["dom","lun","mar","mer","gio","ven","sab"],"field-zone":"zona","dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","eraNames":["BCE","CE"],"dateTimeFormats-appendItem-Year":"{0} {1}","timeFormat-full":"HH:mm:ss v","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","timeFormat-medium":"HH:mm:ss","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateTimeFormat":"{1} {0}","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","timeFormat-short":"HH:mm","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","quarters-stand-alone-narrow":["1","2","3","4"],"dateTimeAvailableFormats":["E d","H","HH:mm","HH:mm:ss","E MMM d","MMMM d","M-d","mm:ss","yy-MM","yy MMM","yy Q","yyyy"],"dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/it/currency.js b/includes/js/dojo/cldr/nls/it/currency.js
new file mode 100644
index 0000000..375ec67
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/it/currency.js
@@ -0,0 +1 @@
+({"HKD_displayName":"Dollaro di Hong Kong","CHF_displayName":"Franco Svizzero","CHF_symbol":"SFr.","CAD_displayName":"Dollaro Canadese","CNY_displayName":"Renmimbi Cinese","AUD_displayName":"Dollaro Australiano","JPY_displayName":"Yen Giapponese","USD_displayName":"Dollaro Statunitense","GBP_displayName":"Sterlina Inglese","EUR_displayName":"Euro","USD_symbol":"US$","GBP_symbol":"UK£","JPY_symbol":"JP¥","EUR_symbol":"€"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/it/gregorian.js b/includes/js/dojo/cldr/nls/it/gregorian.js
new file mode 100644
index 0000000..78ebae9
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/it/gregorian.js
@@ -0,0 +1 @@
+({"quarters-format-abbreviated":["T1","T2","T3","T4"],"dateFormat-medium":"dd/MMM/yyyy","field-second":"secondo","field-week":"settimana","pm":"p.","months-standAlone-narrow":["G","F","M","A","M","G","L","A","S","O","N","D"],"am":"m.","days-standAlone-narrow":["D","L","M","M","G","V","S"],"field-year":"anno","field-minute":"minuto","field-hour":"ora","dateFormat-long":"dd MMMM yyyy","field-day":"giorno","field-dayperiod":"periodo del giorno","field-month":"mese","dateFormat-short":"dd/MM/yy","months-format-wide":["gennaio","febbraio","marzo","aprile","maggio","giugno","luglio","agosto","settembre","ottobre","novembre","dicembre"],"field-era":"era","months-format-abbr":["gen","feb","mar","apr","mag","giu","lug","ago","set","ott","nov","dic"],"days-format-wide":["domenica","lunedì","martedì","mercoledì","giovedì","venerdì","sabato"],"eraAbbr":["aC","dC"],"quarters-format-wide":["1o trimestre","2o trimestre","3o trimestre","4o trimestre"],"dateFormat-full":"EEEE d MMMM yyyy","field-weekday":"giorno della settimana","days-format-abbr":["dom","lun","mar","mer","gio","ven","sab"],"field-zone":"zona","dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","eraNames":["BCE","CE"],"dateTimeFormats-appendItem-Year":"{0} {1}","timeFormat-full":"HH:mm:ss v","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","timeFormat-medium":"HH:mm:ss","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateTimeFormat":"{1} {0}","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","timeFormat-long":"HH:mm:ss z","timeFormat-short":"HH:mm","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","quarters-stand-alone-narrow":["1","2","3","4"],"dateTimeAvailableFormats":["E d","H","HH:mm","HH:mm:ss","E MMM d","MMMM d","M-d","mm:ss","yy-MM","yy MMM","yy Q","yyyy"],"dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/it/number.js b/includes/js/dojo/cldr/nls/it/number.js
new file mode 100644
index 0000000..fab013b
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/it/number.js
@@ -0,0 +1 @@
+({"group":".","decimal":",","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencyFormat":"¤ #,##0.00","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","percentFormat":"#,##0%","decimalFormat":"#,##0.###","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/ja-jp/number.js b/includes/js/dojo/cldr/nls/ja-jp/number.js
new file mode 100644
index 0000000..4b50174
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/ja-jp/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"¤#,##0.00","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","group":",","percentFormat":"#,##0%","decimalFormat":"#,##0.###","decimal":".","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/ja/currency.js b/includes/js/dojo/cldr/nls/ja/currency.js
new file mode 100644
index 0000000..76cd3d9
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/ja/currency.js
@@ -0,0 +1 @@
+({"HKD_displayName":"香港ドル","CHF_displayName":"スイス フラン","JPY_symbol":"ï¿¥","CAD_displayName":"カナダ ドル","CNY_displayName":"中国人民元","AUD_displayName":"オーストラリア ドル","JPY_displayName":"日本円","USD_displayName":"米ドル","CNY_symbol":"å…ƒ","GBP_displayName":"英国ãƒãƒ³ãƒ‰","EUR_displayName":"ユーロ","USD_symbol":"US$","GBP_symbol":"UK£","EUR_symbol":"€"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/ja/gregorian.js b/includes/js/dojo/cldr/nls/ja/gregorian.js
new file mode 100644
index 0000000..523fa7b
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/ja/gregorian.js
@@ -0,0 +1 @@
+({"quarters-format-abbreviated":["Q1","Q2","Q3","Q4"],"dateFormat-medium":"yyyy/MM/dd","field-second":"秒","field-week":"週","pm":"åˆå¾Œ","timeFormat-full":"H時mm分ss秒v","dateTimeFormat":"{1} {0}","dateTimeAvailableFormats":["d 日(E)","GGGGyå¹´M月dæ—¥","H 時","MMM/d(E)","MMMM d æ—¥","MM/dd","M/d","mm:ss","yy å¹´ MMM","yy/Q","yy Q","yyyy"],"months-standAlone-narrow":["1","2","3","4","5","6","7","8","9","10","11","12"],"eraNames":["紀元å‰","西暦"],"am":"åˆå‰","days-standAlone-narrow":["æ—¥","月","ç«","æ°´","木","金","土"],"field-year":"å¹´","field-minute":"分","timeFormat-medium":"H:mm:ss","field-hour":"時","dateFormat-long":"yyyyå¹´M月dæ—¥","field-day":"æ—¥","field-dayperiod":"åˆå‰/åˆå¾Œ","field-month":"月","dateFormat-short":"yy/MM/dd","months-format-wide":["1 月","2 月","3 月","4 月","5 月","6 月","7 月","8 月","9 月","10 月","11 月","12 月"],"field-era":"時代","timeFormat-short":"H:mm","months-format-abbr":["1 月","2 月","3 月","4 月","5 月","6 月","7 月","8 月","9 月","10 月","11 月","12 月"],"eraAbbr":["紀元å‰","西暦"],"days-format-wide":["日曜日","月曜日","ç«æ›œæ—¥","水曜日","木曜日","金曜日","土曜日"],"timeFormat-long":"H:mm:ss:z","quarters-format-wide":["第 1 å››åŠæœŸ","第 2 å››åŠæœŸ","第 3 å››åŠæœŸ","第 4 å››åŠæœŸ"],"dateFormat-full":"yyyyå¹´M月dæ—¥EEEE","field-weekday":"曜日","field-zone":"時間帯","days-format-abbr":["æ—¥","月","ç«","æ°´","木","金","土"],"dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","dateTimeFormats-appendItem-Year":"{0} {1}","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","quarters-stand-alone-narrow":["1","2","3","4"],"dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/ja/number.js b/includes/js/dojo/cldr/nls/ja/number.js
new file mode 100644
index 0000000..4b50174
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/ja/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"¤#,##0.00","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","group":",","percentFormat":"#,##0%","decimalFormat":"#,##0.###","decimal":".","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/ko-kr/gregorian.js b/includes/js/dojo/cldr/nls/ko-kr/gregorian.js
new file mode 100644
index 0000000..03a8510
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/ko-kr/gregorian.js
@@ -0,0 +1 @@
+({"timeFormat-medium":"a h:mm:ss","timeFormat-short":"a h:mm","quarters-format-abbreviated":["1분기","2분기","3분기","4분기"],"dateFormat-medium":"yyyy. M. d.","field-second":"ì´ˆ","field-week":"주","pm":"오후","timeFormat-full":"a hhì‹œ mm분 ssì´ˆ v","dateTimeFormat":"{1} {0}","dateTimeAvailableFormats":["dì¼ (E)","HH:mm","HH:mm:ss","Hì‹œ m분 sì´ˆ","MMM dì¼ (E)","MMMM dì¼","M. d.","mm:ss","yyë…„ MMM","yyë…„ Q분기","yyyy. MM","yyyy"],"months-standAlone-narrow":["1ì›”","2ì›”","3ì›”","4ì›”","5ì›”","6ì›”","7ì›”","8ì›”","9ì›”","10ì›”","11ì›”","12ì›”"],"eraNames":["서력기ì›ì „","서력기ì›"],"am":"오전","days-standAlone-narrow":["ì¼","ì›”","í™”","수","목","금","토"],"field-year":"ë…„","field-minute":"분","quarters-stand-alone-narrow":["1","2","3","4"],"field-hour":"ì‹œ","dateFormat-long":"yyyyë…„ Mì›” dì¼","field-day":"ì¼","field-dayperiod":"오전/오후","field-month":"ì›”","dateFormat-short":"yy. M. d.","months-format-wide":["1ì›”","2ì›”","3ì›”","4ì›”","5ì›”","6ì›”","7ì›”","8ì›”","9ì›”","10ì›”","11ì›”","12ì›”"],"field-era":"연호","months-format-abbr":["1ì›”","2ì›”","3ì›”","4ì›”","5ì›”","6ì›”","7ì›”","8ì›”","9ì›”","10ì›”","11ì›”","12ì›”"],"eraAbbr":["기ì›ì „","서기"],"days-format-wide":["ì¼ìš”ì¼","월요ì¼","화요ì¼","수요ì¼","목요ì¼","금요ì¼","토요ì¼"],"timeFormat-long":"a hhì‹œ mm분 ssì´ˆ z","quarters-format-wide":["ì œ 1/4분기","ì œ 2/4분기","ì œ 3/4분기","ì œ 4/4분기"],"dateFormat-full":"yyyyë…„ Mì›” dì¼ EEEE","field-weekday":"ìš”ì¼","field-zone":"시간대","days-format-abbr":["ì¼","ì›”","í™”","수","목","금","토"],"dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","dateTimeFormats-appendItem-Year":"{0} {1}","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/ko-kr/number.js b/includes/js/dojo/cldr/nls/ko-kr/number.js
new file mode 100644
index 0000000..4b50174
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/ko-kr/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"¤#,##0.00","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","group":",","percentFormat":"#,##0%","decimalFormat":"#,##0.###","decimal":".","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/ko/currency.js b/includes/js/dojo/cldr/nls/ko/currency.js
new file mode 100644
index 0000000..8ae77f3
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/ko/currency.js
@@ -0,0 +1 @@
+({"HKD_displayName":"í™ì½© 달러","JPY_symbol":"ï¿¥","HKD_symbol":"HK$","CAD_displayName":"ìºë‚˜ë‹¤ 달러","CNY_displayName":"중국 위안 ì¸ë¯¼í","AUD_displayName":"호주 달러","JPY_displayName":"ì¼ë³¸ 엔화","CAD_symbol":"Can$","USD_displayName":"미국 달러","GBP_displayName":"ì˜êµ­ë ¹ 파운드 스털ë§","EUR_displayName":"유로화","USD_symbol":"US$","GBP_symbol":"UK£","EUR_symbol":"€"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/ko/gregorian.js b/includes/js/dojo/cldr/nls/ko/gregorian.js
new file mode 100644
index 0000000..a135399
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/ko/gregorian.js
@@ -0,0 +1 @@
+({"quarters-format-abbreviated":["1분기","2분기","3분기","4분기"],"dateFormat-medium":"yyyy. M. d.","field-second":"ì´ˆ","field-week":"주","pm":"오후","timeFormat-full":"a hhì‹œ mm분 ssì´ˆ v","dateTimeFormat":"{1} {0}","dateTimeAvailableFormats":["dì¼ (E)","HH:mm","HH:mm:ss","Hì‹œ m분 sì´ˆ","MMM dì¼ (E)","MMMM dì¼","M. d.","mm:ss","yyë…„ MMM","yyë…„ Q분기","yyyy. MM","yyyy"],"months-standAlone-narrow":["1ì›”","2ì›”","3ì›”","4ì›”","5ì›”","6ì›”","7ì›”","8ì›”","9ì›”","10ì›”","11ì›”","12ì›”"],"eraNames":["서력기ì›ì „","서력기ì›"],"am":"오전","days-standAlone-narrow":["ì¼","ì›”","í™”","수","목","금","토"],"field-year":"ë…„","field-minute":"분","timeFormat-medium":"a h:mm:ss","quarters-stand-alone-narrow":["1","2","3","4"],"field-hour":"ì‹œ","dateFormat-long":"yyyyë…„ Mì›” dì¼","field-day":"ì¼","field-dayperiod":"오전/오후","field-month":"ì›”","dateFormat-short":"yy. M. d.","months-format-wide":["1ì›”","2ì›”","3ì›”","4ì›”","5ì›”","6ì›”","7ì›”","8ì›”","9ì›”","10ì›”","11ì›”","12ì›”"],"field-era":"연호","timeFormat-short":"a h:mm","months-format-abbr":["1ì›”","2ì›”","3ì›”","4ì›”","5ì›”","6ì›”","7ì›”","8ì›”","9ì›”","10ì›”","11ì›”","12ì›”"],"eraAbbr":["기ì›ì „","서기"],"days-format-wide":["ì¼ìš”ì¼","월요ì¼","화요ì¼","수요ì¼","목요ì¼","금요ì¼","토요ì¼"],"timeFormat-long":"a hhì‹œ mm분 ssì´ˆ z","quarters-format-wide":["ì œ 1/4분기","ì œ 2/4분기","ì œ 3/4분기","ì œ 4/4분기"],"dateFormat-full":"yyyyë…„ Mì›” dì¼ EEEE","field-weekday":"ìš”ì¼","field-zone":"시간대","days-format-abbr":["ì¼","ì›”","í™”","수","목","금","토"],"dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","dateTimeFormats-appendItem-Year":"{0} {1}","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/ko/number.js b/includes/js/dojo/cldr/nls/ko/number.js
new file mode 100644
index 0000000..4b50174
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/ko/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"¤#,##0.00","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","group":",","percentFormat":"#,##0%","decimalFormat":"#,##0.###","decimal":".","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/number.js b/includes/js/dojo/cldr/nls/number.js
new file mode 100644
index 0000000..bfec12f
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/number.js
@@ -0,0 +1 @@
+({"scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencyFormat":"¤ #,##0.00","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","group":",","percentFormat":"#,##0%","decimalFormat":"#,##0.###","decimal":".","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/pt-br/gregorian.js b/includes/js/dojo/cldr/nls/pt-br/gregorian.js
new file mode 100644
index 0000000..aeb5946
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/pt-br/gregorian.js
@@ -0,0 +1 @@
+({"field-hour":"Hora","field-dayperiod":"Período do dia","field-minute":"Minuto","timeFormat-full":"HH'h'mm'min'ss's' z","field-week":"Semana","field-weekday":"Dia da semana","field-second":"Segundo","dateFormat-medium":"dd/MM/yyyy","field-day":"Dia","timeFormat-long":"H'h'm'min's's' z","field-month":"Mês","field-year":"Ano","dateFormat-short":"dd/MM/yy","field-zone":"Fuso","quarters-format-abbreviated":["T1","T2","T3","T4"],"pm":"PM","dateTimeFormat":"{1} {0}","dateTimeAvailableFormats":["HH:mm","HH:mm:ss","d MMMM","d/M","mm:ss","MM/yy","MMM yy","Q yy","MMM/yyyy","yy MMM","yy Q","yyyy"],"months-standAlone-narrow":["J","F","M","A","M","J","J","A","S","O","N","D"],"eraNames":["Antes de Cristo","Ano do Senhor"],"am":"AM","days-standAlone-narrow":["D","S","T","Q","Q","S","S"],"timeFormat-medium":"HH:mm:ss","quarters-stand-alone-narrow":["1","2","3","4"],"dateFormat-long":"d 'de' MMMM 'de' yyyy","months-format-wide":["janeiro","fevereiro","março","abril","maio","junho","julho","agosto","setembro","outubro","novembro","dezembro"],"field-era":"Era","timeFormat-short":"HH:mm","months-format-abbr":["jan","fev","mar","abr","mai","jun","jul","ago","set","out","nov","dez"],"eraAbbr":["a.C.","d.C."],"days-format-wide":["domingo","segunda-feira","terça-feira","quarta-feira","quinta-feira","sexta-feira","sábado"],"quarters-format-wide":["1º trimestre","2º trimestre","3º trimestre","4º trimestre"],"dateFormat-full":"EEEE, d 'de' MMMM 'de' yyyy","days-format-abbr":["dom","seg","ter","qua","qui","sex","sáb"],"dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","dateTimeFormats-appendItem-Year":"{0} {1}","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/pt/currency.js b/includes/js/dojo/cldr/nls/pt/currency.js
new file mode 100644
index 0000000..5d84294
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/pt/currency.js
@@ -0,0 +1 @@
+({"HKD_displayName":"Dólar de Hong Kong","CHF_displayName":"Franco suíço","CAD_displayName":"Dólar canadense","CNY_displayName":"Yuan Renminbi chinês","AUD_displayName":"Dólar australiano","JPY_displayName":"Iene japonês","USD_displayName":"Dólar norte-americano","GBP_displayName":"Libra esterlina britânica","EUR_displayName":"Euro","USD_symbol":"US$","GBP_symbol":"UK£","JPY_symbol":"JP¥","EUR_symbol":"€"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/pt/gregorian.js b/includes/js/dojo/cldr/nls/pt/gregorian.js
new file mode 100644
index 0000000..109062f
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/pt/gregorian.js
@@ -0,0 +1 @@
+({"quarters-format-abbreviated":["T1","T2","T3","T4"],"dateFormat-medium":"dd/MM/yyyy","field-second":"Segundo","field-week":"Semana","pm":"PM","timeFormat-full":"HH'h'mm'min'ss's' v","dateTimeFormat":"{1} {0}","dateTimeAvailableFormats":["HH:mm","HH:mm:ss","d MMMM","d/M","mm:ss","MM/yy","MMM yy","Q yy","MMM/yyyy","yy MMM","yy Q","yyyy"],"months-standAlone-narrow":["J","F","M","A","M","J","J","A","S","O","N","D"],"eraNames":["Antes de Cristo","Ano do Senhor"],"am":"AM","days-standAlone-narrow":["D","S","T","Q","Q","S","S"],"field-year":"Ano","field-minute":"Minuto","timeFormat-medium":"HH:mm:ss","quarters-stand-alone-narrow":["1","2","3","4"],"field-hour":"Hora","dateFormat-long":"d 'de' MMMM 'de' yyyy","field-day":"Dia","field-dayperiod":"Período do dia","field-month":"Mês","dateFormat-short":"dd/MM/yy","months-format-wide":["janeiro","fevereiro","março","abril","maio","junho","julho","agosto","setembro","outubro","novembro","dezembro"],"field-era":"Era","timeFormat-short":"HH:mm","months-format-abbr":["jan","fev","mar","abr","mai","jun","jul","ago","set","out","nov","dez"],"eraAbbr":["a.C.","d.C."],"days-format-wide":["domingo","segunda-feira","terça-feira","quarta-feira","quinta-feira","sexta-feira","sábado"],"quarters-format-wide":["1º trimestre","2º trimestre","3º trimestre","4º trimestre"],"dateFormat-full":"EEEE, d 'de' MMMM 'de' yyyy","field-weekday":"Dia da semana","field-zone":"Fuso","days-format-abbr":["dom","seg","ter","qua","qui","sex","sáb"],"dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","dateTimeFormats-appendItem-Year":"{0} {1}","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","timeFormat-long":"HH:mm:ss z","dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/pt/number.js b/includes/js/dojo/cldr/nls/pt/number.js
new file mode 100644
index 0000000..f41a5a8
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/pt/number.js
@@ -0,0 +1 @@
+({"decimalFormat":"#,##0.###","group":".","scientificFormat":"#E0","percentFormat":"#,##0%","currencyFormat":"¤#,##0.00;(¤#,##0.00)","decimal":",","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/zh-cn/gregorian.js b/includes/js/dojo/cldr/nls/zh-cn/gregorian.js
new file mode 100644
index 0000000..6c9e6c9
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/zh-cn/gregorian.js
@@ -0,0 +1 @@
+({"dateFormat-short":"yy-M-d","timeFormat-long":"ahh'æ—¶'mm'分'ss'秒'","dateFormat-medium":"yyyy-M-d","dateFormat-long":"yyyy'å¹´'M'月'd'æ—¥'","timeFormat-medium":"ahh:mm:ss","timeFormat-short":"ah:mm","timeFormat-full":"ahh'æ—¶'mm'分'ss'秒' z","dateFormat-full":"yyyy'å¹´'M'月'd'æ—¥'EEEE","field-second":"秒钟","field-week":"周","pm":"下åˆ","dateTimeAvailableFormats":"M-d","months-standAlone-narrow":["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],"months-standAlone-wide":["一月","二月","三月","四月","五月","六月","七月","八月","ä¹æœˆ","å月","å一月","å二月"],"am":"上åˆ","days-standAlone-narrow":["æ—¥","一","二","三","å››","五","å…­"],"field-year":"å¹´","months-standAlone-abbr":["一月","二月","三月","四月","五月","六月","七月","八月","ä¹æœˆ","å月","å一月","å二月"],"field-minute":"分钟","field-hour":"å°æ—¶","field-day":"æ—¥","field-dayperiod":"上åˆ/下åˆ","field-month":"月","months-format-wide":["1","2","3","4","5","6","7","8","9","10","11","12"],"field-era":"时期","days-format-wide":["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],"eraAbbr":["公元å‰","公元"],"field-weekday":"周天","days-format-abbr":["周日","周一","周二","周三","周四","周五","周六"],"field-zone":"区域","dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","eraNames":["BCE","CE"],"dateTimeFormats-appendItem-Year":"{0} {1}","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","quarters-format-abbreviated":["Q1","Q2","Q3","Q4"],"dateTimeFormat":"{1} {0}","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","months-format-abbr":["1","2","3","4","5","6","7","8","9","10","11","12"],"dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","quarters-stand-alone-narrow":["1","2","3","4"],"dateTimeFormats-appendItem-Era":"{0} {1}","quarters-format-wide":["Q1","Q2","Q3","Q4"],"eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/zh-cn/number.js b/includes/js/dojo/cldr/nls/zh-cn/number.js
new file mode 100644
index 0000000..a223279
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/zh-cn/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"¤#,##0.00","group":",","decimal":".","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","percentFormat":"#,##0%","decimalFormat":"#,##0.###","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/zh-tw/currency.js b/includes/js/dojo/cldr/nls/zh-tw/currency.js
new file mode 100644
index 0000000..98b3640
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/zh-tw/currency.js
@@ -0,0 +1 @@
+({"EUR_displayName":"æ­å…ƒ","CAD_displayName":"加幣","GBP_displayName":"英鎊","JPY_displayName":"日圓","GBP_symbol":"GBP","AUD_displayName":"澳幣","EUR_symbol":"EUR","CNY_displayName":"人民幣","HKD_displayName":"港元","CHF_displayName":"瑞士法郎","HKD_symbol":"HK$","USD_displayName":"美元","CNY_symbol":"ï¿¥","USD_symbol":"US$","JPY_symbol":"JPÂ¥"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/zh-tw/gregorian.js b/includes/js/dojo/cldr/nls/zh-tw/gregorian.js
new file mode 100644
index 0000000..90e3776
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/zh-tw/gregorian.js
@@ -0,0 +1 @@
+({"quarters-format-abbreviated":["1å­£","2å­£","3å­£","4å­£"],"dateFormat-medium":"yyyy/M/d","field-second":"秒","field-week":"週","timeFormat-full":"ahh時mm分ss秒 v","dateTimeAvailableFormats":"M/d","eraNames":["西元å‰","西元"],"field-minute":"分é˜","timeFormat-medium":"a h:mm:ss","field-hour":"å°æ™‚","dateFormat-short":"yyyy/M/d","field-era":"年代","timeFormat-short":"a h:mm","timeFormat-long":"ahh時mm分ss秒 z","quarters-format-wide":["第1å­£","第2å­£","第3å­£","第4å­£"],"quarters-stand-alone-abbreviated":["1å­£","2å­£","3å­£","4å­£"],"field-weekday":"週天","field-zone":"å€åŸŸ","days-format-abbr":["週日","週一","週二","週三","週四","週五","週六"],"pm":"下åˆ","months-standAlone-narrow":["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],"months-standAlone-wide":["一月","二月","三月","四月","五月","六月","七月","八月","ä¹æœˆ","å月","å一月","å二月"],"am":"上åˆ","days-standAlone-narrow":["æ—¥","一","二","三","å››","五","å…­"],"field-year":"å¹´","months-standAlone-abbr":["一月","二月","三月","四月","五月","六月","七月","八月","ä¹æœˆ","å月","å一月","å二月"],"dateFormat-long":"yyyyå¹´M月dæ—¥","field-day":"æ—¥","field-dayperiod":"上åˆ/下åˆ","field-month":"月","months-format-wide":["1","2","3","4","5","6","7","8","9","10","11","12"],"days-format-wide":["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],"eraAbbr":["公元å‰","公元"],"dateFormat-full":"yyyyå¹´M月dæ—¥EEEE","dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","dateTimeFormats-appendItem-Year":"{0} {1}","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","dateTimeFormat":"{1} {0}","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","months-format-abbr":["1","2","3","4","5","6","7","8","9","10","11","12"],"dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","quarters-stand-alone-narrow":["1","2","3","4"],"dateTimeFormats-appendItem-Era":"{0} {1}","eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/zh-tw/number.js b/includes/js/dojo/cldr/nls/zh-tw/number.js
new file mode 100644
index 0000000..0ab604d
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/zh-tw/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"¤#,##0.00","group":",","list":";","decimal":".","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","percentFormat":"#,##0%","decimalFormat":"#,##0.###","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/zh/currency.js b/includes/js/dojo/cldr/nls/zh/currency.js
new file mode 100644
index 0000000..50efc23
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/zh/currency.js
@@ -0,0 +1 @@
+({"HKD_displayName":"港元","CHF_displayName":"瑞士法郎","HKD_symbol":"HK$","CAD_displayName":"加拿大元","CNY_displayName":"人民å¸","AUD_displayName":"澳大利亚元","JPY_displayName":"日元","USD_displayName":"美元","CNY_symbol":"ï¿¥","GBP_displayName":"英镑","EUR_displayName":"欧元","USD_symbol":"US$","GBP_symbol":"UK£","JPY_symbol":"JPÂ¥","EUR_symbol":"€"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/zh/gregorian.js b/includes/js/dojo/cldr/nls/zh/gregorian.js
new file mode 100644
index 0000000..c99ce7b
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/zh/gregorian.js
@@ -0,0 +1 @@
+({"dateFormat-medium":"yyyy-M-d","field-second":"秒钟","field-week":"周","pm":"下åˆ","timeFormat-full":"ahhæ—¶mm分ss秒 v","dateTimeAvailableFormats":"M-d","months-standAlone-narrow":["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],"months-standAlone-wide":["一月","二月","三月","四月","五月","六月","七月","八月","ä¹æœˆ","å月","å一月","å二月"],"am":"上åˆ","days-standAlone-narrow":["æ—¥","一","二","三","å››","五","å…­"],"field-year":"å¹´","months-standAlone-abbr":["一月","二月","三月","四月","五月","六月","七月","八月","ä¹æœˆ","å月","å一月","å二月"],"field-minute":"分钟","timeFormat-medium":"ahh:mm:ss","field-hour":"å°æ—¶","dateFormat-long":"yyyyå¹´M月dæ—¥","field-day":"æ—¥","field-dayperiod":"上åˆ/下åˆ","field-month":"月","dateFormat-short":"yy-M-d","months-format-wide":["1","2","3","4","5","6","7","8","9","10","11","12"],"field-era":"时期","timeFormat-short":"ah:mm","days-format-wide":["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],"timeFormat-long":"ahhæ—¶mm分ss秒 z","eraAbbr":["公元å‰","公元"],"dateFormat-full":"yyyyå¹´M月dæ—¥EEEE","field-weekday":"周天","days-format-abbr":["周日","周一","周二","周三","周四","周五","周六"],"field-zone":"区域","dateTimeFormats-appendItem-Second":"{0} ({2}: {1})","eraNames":["BCE","CE"],"dateTimeFormats-appendItem-Year":"{0} {1}","dateTimeFormats-appendItem-Week":"{0} ({2}: {1})","dateTimeFormats-appendItem-Timezone":"{0} {1}","dateTimeFormats-appendItem-Month":"{0} ({2}: {1})","dateTimeFormats-appendItem-Minute":"{0} ({2}: {1})","quarters-format-abbreviated":["Q1","Q2","Q3","Q4"],"dateTimeFormat":"{1} {0}","dateTimeFormats-appendItem-Day":"{0} ({2}: {1})","months-format-abbr":["1","2","3","4","5","6","7","8","9","10","11","12"],"dateTimeFormats-appendItem-Quarter":"{0} ({2}: {1})","dateTimeFormats-appendItem-Day-Of-Week":"{0} {1}","dateTimeFormats-appendItem-Hour":"{0} ({2}: {1})","quarters-stand-alone-narrow":["1","2","3","4"],"dateTimeFormats-appendItem-Era":"{0} {1}","quarters-format-wide":["Q1","Q2","Q3","Q4"],"eraNarrow":["BCE","CE"]}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/nls/zh/number.js b/includes/js/dojo/cldr/nls/zh/number.js
new file mode 100644
index 0000000..a223279
--- /dev/null
+++ b/includes/js/dojo/cldr/nls/zh/number.js
@@ -0,0 +1 @@
+({"currencyFormat":"¤#,##0.00","group":",","decimal":".","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","percentFormat":"#,##0%","decimalFormat":"#,##0.###","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"}) \ No newline at end of file
diff --git a/includes/js/dojo/cldr/supplemental.js b/includes/js/dojo/cldr/supplemental.js
new file mode 100644
index 0000000..9b22b08
--- /dev/null
+++ b/includes/js/dojo/cldr/supplemental.js
@@ -0,0 +1,74 @@
+if(!dojo._hasResource["dojo.cldr.supplemental"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.cldr.supplemental"] = true;
+dojo.provide("dojo.cldr.supplemental");
+
+dojo.require("dojo.i18n");
+
+dojo.cldr.supplemental.getFirstDayOfWeek = function(/*String?*/locale){
+// summary: Returns a zero-based index for first day of the week
+// description:
+// Returns a zero-based index for first day of the week, as used by the local (Gregorian) calendar.
+// e.g. Sunday (returns 0), or Monday (returns 1)
+
+ // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/firstDay
+ var firstDay = {/*default is 1=Monday*/
+ mv:5,
+ ae:6,af:6,bh:6,dj:6,dz:6,eg:6,er:6,et:6,iq:6,ir:6,jo:6,ke:6,kw:6,lb:6,ly:6,ma:6,om:6,qa:6,sa:6,
+ sd:6,so:6,tn:6,ye:6,
+ as:0,au:0,az:0,bw:0,ca:0,cn:0,fo:0,ge:0,gl:0,gu:0,hk:0,ie:0,il:0,is:0,jm:0,jp:0,kg:0,kr:0,la:0,
+ mh:0,mo:0,mp:0,mt:0,nz:0,ph:0,pk:0,sg:0,th:0,tt:0,tw:0,um:0,us:0,uz:0,vi:0,za:0,zw:0,
+ et:0,mw:0,ng:0,tj:0,
+// variant. do not use? gb:0,
+ sy:4
+ };
+
+ var country = dojo.cldr.supplemental._region(locale);
+ var dow = firstDay[country];
+ return (dow === undefined) ? 1 : dow; /*Number*/
+};
+
+dojo.cldr.supplemental._region = function(/*String?*/locale){
+ locale = dojo.i18n.normalizeLocale(locale);
+ var tags = locale.split('-');
+ var region = tags[1];
+ if(!region){
+ // IE often gives language only (#2269)
+ // Arbitrary mappings of language-only locales to a country:
+ region = {de:"de", en:"us", es:"es", fi:"fi", fr:"fr", hu:"hu", it:"it",
+ ja:"jp", ko:"kr", nl:"nl", pt:"br", sv:"se", zh:"cn"}[tags[0]];
+ }else if(region.length == 4){
+ // The ISO 3166 country code is usually in the second position, unless a
+ // 4-letter script is given. See http://www.ietf.org/rfc/rfc4646.txt
+ region = tags[2];
+ }
+ return region;
+}
+
+dojo.cldr.supplemental.getWeekend = function(/*String?*/locale){
+// summary: Returns a hash containing the start and end days of the weekend
+// description:
+// Returns a hash containing the start and end days of the weekend according to local custom using locale,
+// or by default in the user's locale.
+// e.g. {start:6, end:0}
+
+ // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/weekend{Start,End}
+ var weekendStart = {/*default is 6=Saturday*/
+ eg:5,il:5,sy:5,
+ 'in':0,
+ ae:4,bh:4,dz:4,iq:4,jo:4,kw:4,lb:4,ly:4,ma:4,om:4,qa:4,sa:4,sd:4,tn:4,ye:4
+ };
+
+ var weekendEnd = {/*default is 0=Sunday*/
+ ae:5,bh:5,dz:5,iq:5,jo:5,kw:5,lb:5,ly:5,ma:5,om:5,qa:5,sa:5,sd:5,tn:5,ye:5,af:5,ir:5,
+ eg:6,il:6,sy:6
+ };
+
+ var country = dojo.cldr.supplemental._region(locale);
+ var start = weekendStart[country];
+ var end = weekendEnd[country];
+ if(start === undefined){start=6;}
+ if(end === undefined){end=0;}
+ return {start:start, end:end}; /*Object {start,end}*/
+};
+
+}
diff --git a/includes/js/dojo/colors.js b/includes/js/dojo/colors.js
new file mode 100644
index 0000000..af83373
--- /dev/null
+++ b/includes/js/dojo/colors.js
@@ -0,0 +1,225 @@
+if(!dojo._hasResource["dojo.colors"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.colors"] = true;
+dojo.provide("dojo.colors");
+
+//TODO: this module appears to break naming conventions
+
+/*=====
+dojo.colors = {
+ // summary: Color utilities
+}
+=====*/
+
+(function(){
+ // this is a standard conversion prescribed by the CSS3 Color Module
+ var hue2rgb = function(m1, m2, h){
+ if(h < 0){ ++h; }
+ if(h > 1){ --h; }
+ var h6 = 6 * h;
+ if(h6 < 1){ return m1 + (m2 - m1) * h6; }
+ if(2 * h < 1){ return m2; }
+ if(3 * h < 2){ return m1 + (m2 - m1) * (2 / 3 - h) * 6; }
+ return m1;
+ };
+
+ dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
+ // summary:
+ // get rgb(a) array from css-style color declarations
+ // description:
+ // this function can handle all 4 CSS3 Color Module formats: rgb,
+ // rgba, hsl, hsla, including rgb(a) with percentage values.
+ var m = color.toLowerCase().match(/^(rgba?|hsla?)\(([\s\.\-,%0-9]+)\)/);
+ if(m){
+ var c = m[2].split(/\s*,\s*/), l = c.length, t = m[1];
+ if((t == "rgb" && l == 3) || (t == "rgba" && l == 4)){
+ var r = c[0];
+ if(r.charAt(r.length - 1) == "%"){
+ // 3 rgb percentage values
+ var a = dojo.map(c, function(x){
+ return parseFloat(x) * 2.56;
+ });
+ if(l == 4){ a[3] = c[3]; }
+ return dojo.colorFromArray(a, obj); // dojo.Color
+ }
+ return dojo.colorFromArray(c, obj); // dojo.Color
+ }
+ if((t == "hsl" && l == 3) || (t == "hsla" && l == 4)){
+ // normalize hsl values
+ var H = ((parseFloat(c[0]) % 360) + 360) % 360 / 360,
+ S = parseFloat(c[1]) / 100,
+ L = parseFloat(c[2]) / 100,
+ // calculate rgb according to the algorithm
+ // recommended by the CSS3 Color Module
+ m2 = L <= 0.5 ? L * (S + 1) : L + S - L * S,
+ m1 = 2 * L - m2,
+ a = [hue2rgb(m1, m2, H + 1 / 3) * 256,
+ hue2rgb(m1, m2, H) * 256, hue2rgb(m1, m2, H - 1 / 3) * 256, 1];
+ if(l == 4){ a[3] = c[3]; }
+ return dojo.colorFromArray(a, obj); // dojo.Color
+ }
+ }
+ return null; // dojo.Color
+ };
+
+ var confine = function(c, low, high){
+ // summary:
+ // sanitize a color component by making sure it is a number,
+ // and clamping it to valid values
+ c = Number(c);
+ return isNaN(c) ? high : c < low ? low : c > high ? high : c; // Number
+ };
+
+ dojo.Color.prototype.sanitize = function(){
+ // summary: makes sure that the object has correct attributes
+ var t = this;
+ t.r = Math.round(confine(t.r, 0, 255));
+ t.g = Math.round(confine(t.g, 0, 255));
+ t.b = Math.round(confine(t.b, 0, 255));
+ t.a = confine(t.a, 0, 1);
+ return this; // dojo.Color
+ };
+})();
+
+
+dojo.colors.makeGrey = function(/*Number*/ g, /*Number?*/ a){
+ // summary: creates a greyscale color with an optional alpha
+ return dojo.colorFromArray([g, g, g, a]);
+};
+
+// mixin all CSS3 named colors not already in _base, along with SVG 1.0 variant spellings
+dojo.Color.named = dojo.mixin({
+ aliceblue: [240,248,255],
+ antiquewhite: [250,235,215],
+ aquamarine: [127,255,212],
+ azure: [240,255,255],
+ beige: [245,245,220],
+ bisque: [255,228,196],
+ blanchedalmond: [255,235,205],
+ 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],
+ gainsboro: [220,220,220],
+ ghostwhite: [248,248,255],
+ gold: [255,215,0],
+ goldenrod: [218,165,32],
+ 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],
+ limegreen: [50,205,50],
+ linen: [250,240,230],
+ magenta: [255,0,255],
+ 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],
+ oldlace: [253,245,230],
+ 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],
+ 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],
+ 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],
+ thistle: [216,191,216],
+ tomato: [255,99,71],
+ transparent: [0, 0, 0, 0],
+ turquoise: [64,224,208],
+ violet: [238,130,238],
+ wheat: [245,222,179],
+ whitesmoke: [245,245,245],
+ yellowgreen: [154,205,50]
+}, dojo.Color.named);
+
+}
diff --git a/includes/js/dojo/cookie.js b/includes/js/dojo/cookie.js
new file mode 100644
index 0000000..bc39417
--- /dev/null
+++ b/includes/js/dojo/cookie.js
@@ -0,0 +1,95 @@
+if(!dojo._hasResource["dojo.cookie"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.cookie"] = true;
+dojo.provide("dojo.cookie");
+
+dojo.require("dojo.regexp");
+
+/*=====
+dojo.__cookieProps = function(){
+ // expires: Date|String|Number?
+ // If a number, the number of days from today at which the cookie
+ // will expire. If a date, the date past which the cookie will expire.
+ // If expires is in the past, the cookie will be deleted.
+ // If expires is omitted or is 0, the cookie will expire when the browser closes. << FIXME: 0 seems to disappear right away? FF3.
+ // path: String?
+ // The path to use for the cookie.
+ // domain: String?
+ // The domain to use for the cookie.
+ // secure: Boolean?
+ // Whether to only send the cookie on secure connections
+ this.expires = expires;
+ this.path = path;
+ this.domain = domain;
+ this.secure = secure;
+}
+=====*/
+
+
+dojo.cookie = function(/*String*/name, /*String?*/value, /*dojo.__cookieProps?*/props){
+ // summary:
+ // Get or set a cookie.
+ // description:
+ // If one argument is passed, returns the value of the cookie
+ // For two or more arguments, acts as a setter.
+ // name:
+ // Name of the cookie
+ // value:
+ // Value for the cookie
+ // props:
+ // Properties for the cookie
+ // example:
+ // set a cookie with the JSON-serialized contents of an object which
+ // will expire 5 days from now:
+ // | dojo.cookie("configObj", dojo.toJson(config), { expires: 5 });
+ //
+ // example:
+ // de-serialize a cookie back into a JavaScript object:
+ // | var config = dojo.fromJson(dojo.cookie("configObj"));
+ //
+ // example:
+ // delete a cookie:
+ // | dojo.cookie("configObj", null, {expires: -1});
+ var c = document.cookie;
+ if(arguments.length == 1){
+ var matches = c.match(new RegExp("(?:^|; )" + dojo.regexp.escapeString(name) + "=([^;]*)"));
+ return matches ? decodeURIComponent(matches[1]) : undefined; // String or undefined
+ }else{
+ props = props || {};
+// FIXME: expires=0 seems to disappear right away, not on close? (FF3) Change docs?
+ var exp = props.expires;
+ if(typeof exp == "number"){
+ var d = new Date();
+ d.setTime(d.getTime() + exp*24*60*60*1000);
+ exp = props.expires = d;
+ }
+ if(exp && exp.toUTCString){ props.expires = exp.toUTCString(); }
+
+ value = encodeURIComponent(value);
+ var updatedCookie = name + "=" + value;
+ for(propName in props){
+ updatedCookie += "; " + propName;
+ var propValue = props[propName];
+ if(propValue !== true){ updatedCookie += "=" + propValue; }
+ }
+ document.cookie = updatedCookie;
+ }
+};
+
+dojo.cookie.isSupported = function(){
+ // summary:
+ // Use to determine if the current browser supports cookies or not.
+ //
+ // Returns true if user allows cookies.
+ // Returns false if user doesn't allow cookies.
+
+ if(!("cookieEnabled" in navigator)){
+ this("__djCookieTest__", "CookiesAllowed");
+ navigator.cookieEnabled = this("__djCookieTest__") == "CookiesAllowed";
+ if(navigator.cookieEnabled){
+ this("__djCookieTest__", "", {expires: -1});
+ }
+ }
+ return navigator.cookieEnabled;
+};
+
+}
diff --git a/includes/js/dojo/currency.js b/includes/js/dojo/currency.js
new file mode 100644
index 0000000..6e0eb31
--- /dev/null
+++ b/includes/js/dojo/currency.js
@@ -0,0 +1,97 @@
+if(!dojo._hasResource["dojo.currency"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.currency"] = true;
+dojo.provide("dojo.currency");
+
+dojo.require("dojo.number");
+dojo.require("dojo.i18n");
+dojo.requireLocalization("dojo.cldr", "currency", null, "zh,en-ca,pt,en-us,de,ja,en,en-au,ROOT,fr,es,ko,zh-tw,it");
+dojo.require("dojo.cldr.monetary");
+
+/*=====
+dojo.currency = {
+ // summary: localized formatting and parsing routines for currencies
+}
+=====*/
+
+dojo.currency._mixInDefaults = function(options){
+ options = options || {};
+ options.type = "currency";
+
+ // Get locale-depenent currency data, like the symbol
+ var bundle = dojo.i18n.getLocalization("dojo.cldr", "currency", options.locale) || {};
+
+ // Mixin locale-independent currency data, like # of places
+ var iso = options.currency;
+ var data = dojo.cldr.monetary.getData(iso);
+
+ dojo.forEach(["displayName","symbol","group","decimal"], function(prop){
+ data[prop] = bundle[iso+"_"+prop];
+ });
+
+ data.fractional = [true, false];
+
+ // Mixin with provided options
+ return dojo.mixin(data, options);
+}
+
+dojo.currency.format = function(/*Number*/value, /*dojo.number.__FormatOptions?*/options){
+// summary:
+// Format a Number as a currency, using locale-specific settings
+//
+// description:
+// Create a string from a Number using a known, localized pattern.
+// [Formatting patterns](http://www.unicode.org/reports/tr35/#Number_Elements) appropriate to the locale are chosen from the [CLDR](http://unicode.org/cldr)
+// as well as the appropriate symbols and delimiters.
+//
+// value:
+// the number to be formatted.
+
+ return dojo.number.format(value, dojo.currency._mixInDefaults(options));
+}
+
+dojo.currency.regexp = function(/*dojo.number.__RegexpOptions?*/options){
+//
+// summary:
+// Builds the regular needed to parse a currency value
+//
+// description:
+// Returns regular expression with positive and negative match, group and decimal separators
+// Note: the options.places default, the number of decimal places to accept, is defined by the currency type.
+ return dojo.number.regexp(dojo.currency._mixInDefaults(options)); // String
+}
+
+/*=====
+dojo.declare("dojo.currency.__ParseOptions", [dojo.number.__ParseOptions], {
+ // type: String?
+ // currency, set by default.
+ // symbol: String?
+ // override currency symbol. Normally, will be looked up in table of supported currencies,
+ // and ISO currency code will be used if not found. See dojo.i18n.cldr.nls->currency.js
+ // places: Number?
+ // number of decimal places to accept. Default is defined by currency.
+ // fractional: Boolean?|Array?
+ // where places are implied by pattern or explicit 'places' parameter, whether to include the fractional portion.
+ // By default for currencies, it the fractional portion is optional.
+ type: "",
+ symbol: "",
+ places: "",
+ fractional: ""
+});
+=====*/
+
+dojo.currency.parse = function(/*String*/expression, /*dojo.currency.__ParseOptions?*/options){
+ //
+ // summary:
+ // Convert a properly formatted currency string to a primitive Number,
+ // using locale-specific settings.
+ //
+ // description:
+ // Create a Number from a string using a known, localized pattern.
+ // [Formatting patterns](http://www.unicode.org/reports/tr35/#Number_Format_Patterns) are chosen appropriate to the locale.
+ //
+ // expression: A string representation of a Number
+
+ return dojo.number.parse(expression, dojo.currency._mixInDefaults(options));
+}
+
+}
diff --git a/includes/js/dojo/data/ItemFileReadStore.js b/includes/js/dojo/data/ItemFileReadStore.js
new file mode 100644
index 0000000..eb116eb
--- /dev/null
+++ b/includes/js/dojo/data/ItemFileReadStore.js
@@ -0,0 +1,765 @@
+if(!dojo._hasResource["dojo.data.ItemFileReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.ItemFileReadStore"] = true;
+dojo.provide("dojo.data.ItemFileReadStore");
+
+dojo.require("dojo.data.util.filter");
+dojo.require("dojo.data.util.simpleFetch");
+dojo.require("dojo.date.stamp");
+
+dojo.declare("dojo.data.ItemFileReadStore", null,{
+ // summary:
+ // The ItemFileReadStore implements the dojo.data.api.Read API and reads
+ // data from JSON files that have contents in this format --
+ // { items: [
+ // { name:'Kermit', color:'green', age:12, friends:['Gonzo', {_reference:{name:'Fozzie Bear'}}]},
+ // { name:'Fozzie Bear', wears:['hat', 'tie']},
+ // { name:'Miss Piggy', pets:'Foo-Foo'}
+ // ]}
+ // Note that it can also contain an 'identifer' property that specified which attribute on the items
+ // in the array of items that acts as the unique identifier for that item.
+ //
+ constructor: function(/* Object */ keywordParameters){
+ // summary: constructor
+ // keywordParameters: {url: String}
+ // keywordParameters: {data: jsonObject}
+ // keywordParameters: {typeMap: object)
+ // The structure of the typeMap object is as follows:
+ // {
+ // type0: function || object,
+ // type1: function || object,
+ // ...
+ // typeN: function || object
+ // }
+ // Where if it is a function, it is assumed to be an object constructor that takes the
+ // value of _value as the initialization parameters. If it is an object, then it is assumed
+ // to be an object of general form:
+ // {
+ // type: function, //constructor.
+ // deserialize: function(value) //The function that parses the value and constructs the object defined by type appropriately.
+ // }
+
+ this._arrayOfAllItems = [];
+ this._arrayOfTopLevelItems = [];
+ this._loadFinished = false;
+ this._jsonFileUrl = keywordParameters.url;
+ this._jsonData = keywordParameters.data;
+ this._datatypeMap = keywordParameters.typeMap || {};
+ if(!this._datatypeMap['Date']){
+ //If no default mapping for dates, then set this as default.
+ //We use the dojo.date.stamp here because the ISO format is the 'dojo way'
+ //of generically representing dates.
+ this._datatypeMap['Date'] = {
+ type: Date,
+ deserialize: function(value){
+ return dojo.date.stamp.fromISOString(value);
+ }
+ };
+ }
+ this._features = {'dojo.data.api.Read':true, 'dojo.data.api.Identity':true};
+ this._itemsByIdentity = null;
+ this._storeRefPropName = "_S"; // Default name for the store reference to attach to every item.
+ this._itemNumPropName = "_0"; // Default Item Id for isItem to attach to every item.
+ this._rootItemPropName = "_RI"; // Default Item Id for isItem to attach to every item.
+ this._reverseRefMap = "_RRM"; // Default attribute for constructing a reverse reference map for use with reference integrity
+ this._loadInProgress = false; //Got to track the initial load to prevent duelling loads of the dataset.
+ this._queuedFetches = [];
+ },
+
+ url: "", // use "" rather than undefined for the benefit of the parser (#3539)
+
+ _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("dojo.data.ItemFileReadStore: 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("dojo.data.ItemFileReadStore: Invalid attribute argument.");
+ }
+ },
+
+ getValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* value? */ defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ return (values.length > 0)?values[0]:defaultValue; // mixed
+ },
+
+ getValues: function(/* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.getValues()
+
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ return item[attribute] || []; // Array
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ var attributes = [];
+ for(var key in item){
+ // Save off only the real item attributes, not the special id marks for O(1) isItem.
+ if((key !== this._storeRefPropName) && (key !== this._itemNumPropName) && (key !== this._rootItemPropName) && (key !== this._reverseRefMap)){
+ attributes.push(key);
+ }
+ }
+ return attributes; // Array
+ },
+
+ hasAttribute: function( /* item */ item,
+ /* attribute-name-string */ attribute) {
+ // summary:
+ // See dojo.data.api.Read.hasAttribute()
+ return this.getValues(item, attribute).length > 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'
+ return dojo.some(this.getValues(item, attribute), function(possibleValue){
+ if(possibleValue !== null && !dojo.isObject(possibleValue) && regexp){
+ if(possibleValue.toString().match(regexp)){
+ return true; // Boolean
+ }
+ }else if(value === possibleValue){
+ return true; // Boolean
+ }
+ });
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ if(something && something[this._storeRefPropName] === this){
+ if(this._arrayOfAllItems[something[this._itemNumPropName]] === something){
+ return true;
+ }
+ }
+ return false; // Boolean
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ return this.isItem(something); //boolean
+ },
+
+ loadItem: function(/* object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ this._assertIsItem(keywordArgs.item);
+ },
+
+ 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._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( /* Object */ keywordArgs,
+ /* Function */ findCallback,
+ /* Function */ errorCallback){
+ // summary:
+ // See dojo.data.util.simpleFetch.fetch()
+ var self = this;
+ var filter = function(requestArgs, arrayOfItems){
+ var items = [];
+ if(requestArgs.query){
+ 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];
+ if(candidateItem === null){
+ match = false;
+ }else{
+ 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);
+ }
+ }
+ findCallback(items, requestArgs);
+ }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. We also need to
+ // filter out any null values that have been left as a result of deleteItem()
+ // calls in ItemFileWriteStore.
+ for(var i = 0; i < arrayOfItems.length; ++i){
+ var item = arrayOfItems[i];
+ if(item !== null){
+ items.push(item);
+ }
+ }
+ findCallback(items, requestArgs);
+ }
+ };
+
+ if(this._loadFinished){
+ filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
+ }else{
+
+ if(this._jsonFileUrl){
+ //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._jsonFileUrl,
+ handleAs: "json-comment-optional"
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ try{
+ self._getItemsFromLoadedData(data);
+ self._loadFinished = true;
+ self._loadInProgress = false;
+
+ filter(keywordArgs, self._getItemsArray(keywordArgs.queryOptions));
+ self._handleQueuedFetches();
+ }catch(e){
+ self._loadFinished = true;
+ self._loadInProgress = false;
+ errorCallback(e, keywordArgs);
+ }
+ });
+ getHandler.addErrback(function(error){
+ self._loadInProgress = false;
+ errorCallback(error, keywordArgs);
+ });
+ }
+ }else if(this._jsonData){
+ try{
+ this._loadFinished = true;
+ this._getItemsFromLoadedData(this._jsonData);
+ this._jsonData = null;
+ filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
+ }catch(e){
+ errorCallback(e, keywordArgs);
+ }
+ }else{
+ errorCallback(new Error("dojo.data.ItemFileReadStore: No JSON source data was provided as either URL or a nested Javascript object."), keywordArgs);
+ }
+ }
+ },
+
+ _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 = [];
+ }
+ },
+
+ _getItemsArray: function(/*object?*/queryOptions){
+ // summary:
+ // Internal function to determine which list of items to search over.
+ // queryOptions: The query options parameter, if any.
+ if(queryOptions && queryOptions.deep) {
+ return this._arrayOfAllItems;
+ }
+ return this._arrayOfTopLevelItems;
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ },
+
+ _getItemsFromLoadedData: function(/* Object */ dataObject){
+ // summary:
+ // Function to parse the loaded data into item format and build the internal items array.
+ // description:
+ // Function to parse the loaded data into item format and build the internal items array.
+ //
+ // dataObject:
+ // The JS data object containing the raw data to convery into item format.
+ //
+ // returns: array
+ // Array of items in store item format.
+
+ // First, we define a couple little utility functions...
+
+ function valueIsAnItem(/* anything */ aValue){
+ // summary:
+ // Given any sort of value that could be in the raw json data,
+ // return true if we should interpret the value as being an
+ // item itself, rather than a literal value or a reference.
+ // example:
+ // | false == valueIsAnItem("Kermit");
+ // | false == valueIsAnItem(42);
+ // | false == valueIsAnItem(new Date());
+ // | false == valueIsAnItem({_type:'Date', _value:'May 14, 1802'});
+ // | false == valueIsAnItem({_reference:'Kermit'});
+ // | true == valueIsAnItem({name:'Kermit', color:'green'});
+ // | true == valueIsAnItem({iggy:'pop'});
+ // | true == valueIsAnItem({foo:42});
+ var isItem = (
+ (aValue != null) &&
+ (typeof aValue == "object") &&
+ (!dojo.isArray(aValue)) &&
+ (!dojo.isFunction(aValue)) &&
+ (aValue.constructor == Object) &&
+ (typeof aValue._reference == "undefined") &&
+ (typeof aValue._type == "undefined") &&
+ (typeof aValue._value == "undefined")
+ );
+ return isItem;
+ }
+
+ var self = this;
+ function addItemAndSubItemsToArrayOfAllItems(/* Item */ anItem){
+ self._arrayOfAllItems.push(anItem);
+ for(var attribute in anItem){
+ var valueForAttribute = anItem[attribute];
+ if(valueForAttribute){
+ if(dojo.isArray(valueForAttribute)){
+ var valueArray = valueForAttribute;
+ for(var k = 0; k < valueArray.length; ++k){
+ var singleValue = valueArray[k];
+ if(valueIsAnItem(singleValue)){
+ addItemAndSubItemsToArrayOfAllItems(singleValue);
+ }
+ }
+ }else{
+ if(valueIsAnItem(valueForAttribute)){
+ addItemAndSubItemsToArrayOfAllItems(valueForAttribute);
+ }
+ }
+ }
+ }
+ }
+
+ this._labelAttr = dataObject.label;
+
+ // We need to do some transformations to convert the data structure
+ // that we read from the file into a format that will be convenient
+ // to work with in memory.
+
+ // Step 1: Walk through the object hierarchy and build a list of all items
+ var i;
+ var item;
+ this._arrayOfAllItems = [];
+ this._arrayOfTopLevelItems = dataObject.items;
+
+ for(i = 0; i < this._arrayOfTopLevelItems.length; ++i){
+ item = this._arrayOfTopLevelItems[i];
+ addItemAndSubItemsToArrayOfAllItems(item);
+ item[this._rootItemPropName]=true;
+ }
+
+ // Step 2: Walk through all the attribute values of all the items,
+ // and replace single values with arrays. For example, we change this:
+ // { name:'Miss Piggy', pets:'Foo-Foo'}
+ // into this:
+ // { name:['Miss Piggy'], pets:['Foo-Foo']}
+ //
+ // We also store the attribute names so we can validate our store
+ // reference and item id special properties for the O(1) isItem
+ var allAttributeNames = {};
+ var key;
+
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i];
+ for(key in item){
+ if (key !== this._rootItemPropName)
+ {
+ var value = item[key];
+ if(value !== null){
+ if(!dojo.isArray(value)){
+ item[key] = [value];
+ }
+ }else{
+ item[key] = [null];
+ }
+ }
+ allAttributeNames[key]=key;
+ }
+ }
+
+ // Step 3: Build unique property names to use for the _storeRefPropName and _itemNumPropName
+ // This should go really fast, it will generally never even run the loop.
+ while(allAttributeNames[this._storeRefPropName]){
+ this._storeRefPropName += "_";
+ }
+ while(allAttributeNames[this._itemNumPropName]){
+ this._itemNumPropName += "_";
+ }
+ while(allAttributeNames[this._reverseRefMap]){
+ this._reverseRefMap += "_";
+ }
+
+ // Step 4: Some data files specify an optional 'identifier', which is
+ // the name of an attribute that holds the identity of each item.
+ // If this data file specified an identifier attribute, then build a
+ // hash table of items keyed by the identity of the items.
+ var arrayOfValues;
+
+ var identifier = dataObject.identifier;
+ if(identifier){
+ this._itemsByIdentity = {};
+ this._features['dojo.data.api.Identity'] = identifier;
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i];
+ arrayOfValues = item[identifier];
+ var identity = arrayOfValues[0];
+ if(!this._itemsByIdentity[identity]){
+ this._itemsByIdentity[identity] = item;
+ }else{
+ if(this._jsonFileUrl){
+ throw new Error("dojo.data.ItemFileReadStore: The json data as specified by: [" + this._jsonFileUrl + "] is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]");
+ }else if(this._jsonData){
+ throw new Error("dojo.data.ItemFileReadStore: The json data provided by the creation arguments is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]");
+ }
+ }
+ }
+ }else{
+ this._features['dojo.data.api.Identity'] = Number;
+ }
+
+ // Step 5: Walk through all the items, and set each item's properties
+ // for _storeRefPropName and _itemNumPropName, so that store.isItem() will return true.
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i];
+ item[this._storeRefPropName] = this;
+ item[this._itemNumPropName] = i;
+ }
+
+ // Step 6: We walk through all the attribute values of all the items,
+ // looking for type/value literals and item-references.
+ //
+ // We replace item-references with pointers to items. For example, we change:
+ // { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
+ // into this:
+ // { name:['Kermit'], friends:[miss_piggy] }
+ // (where miss_piggy is the object representing the 'Miss Piggy' item).
+ //
+ // We replace type/value pairs with typed-literals. For example, we change:
+ // { name:['Nelson Mandela'], born:[{_type:'Date', _value:'July 18, 1918'}] }
+ // into this:
+ // { name:['Kermit'], born:(new Date('July 18, 1918')) }
+ //
+ // We also generate the associate map for all items for the O(1) isItem function.
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i]; // example: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
+ for(key in item){
+ arrayOfValues = item[key]; // example: [{_reference:{name:'Miss Piggy'}}]
+ for(var j = 0; j < arrayOfValues.length; ++j) {
+ value = arrayOfValues[j]; // example: {_reference:{name:'Miss Piggy'}}
+ if(value !== null && typeof value == "object"){
+ if(value._type && value._value){
+ var type = value._type; // examples: 'Date', 'Color', or 'ComplexNumber'
+ var mappingObj = this._datatypeMap[type]; // examples: Date, dojo.Color, foo.math.ComplexNumber, {type: dojo.Color, deserialize(value){ return new dojo.Color(value)}}
+ if(!mappingObj){
+ throw new Error("dojo.data.ItemFileReadStore: in the typeMap constructor arg, no object class was specified for the datatype '" + type + "'");
+ }else if(dojo.isFunction(mappingObj)){
+ arrayOfValues[j] = new mappingObj(value._value);
+ }else if(dojo.isFunction(mappingObj.deserialize)){
+ arrayOfValues[j] = mappingObj.deserialize(value._value);
+ }else{
+ throw new Error("dojo.data.ItemFileReadStore: Value provided in typeMap was neither a constructor, nor a an object with a deserialize function");
+ }
+ }
+ if(value._reference){
+ var referenceDescription = value._reference; // example: {name:'Miss Piggy'}
+ if(!dojo.isObject(referenceDescription)){
+ // example: 'Miss Piggy'
+ // from an item like: { name:['Kermit'], friends:[{_reference:'Miss Piggy'}]}
+ arrayOfValues[j] = this._itemsByIdentity[referenceDescription];
+ }else{
+ // example: {name:'Miss Piggy'}
+ // from an item like: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
+ for(var k = 0; k < this._arrayOfAllItems.length; ++k){
+ var candidateItem = this._arrayOfAllItems[k];
+ var found = true;
+ for(var refKey in referenceDescription){
+ if(candidateItem[refKey] != referenceDescription[refKey]){
+ found = false;
+ }
+ }
+ if(found){
+ arrayOfValues[j] = candidateItem;
+ }
+ }
+ }
+ if(this.referenceIntegrity){
+ var refItem = arrayOfValues[j];
+ if(this.isItem(refItem)){
+ this._addReferenceToMap(refItem, item, key);
+ }
+ }
+ }else if(this.isItem(value)){
+ //It's a child item (not one referenced through _reference).
+ //We need to treat this as a referenced item, so it can be cleaned up
+ //in a write store easily.
+ if(this.referenceIntegrity){
+ this._addReferenceToMap(value, item, key);
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+
+ _addReferenceToMap: function(/*item*/ refItem, /*item*/ parentItem, /*string*/ attribute){
+ // summary:
+ // Method to add an reference map entry for an item and attribute.
+ // description:
+ // Method to add an reference map entry for an item and attribute. //
+ // refItem:
+ // The item that is referenced.
+ // parentItem:
+ // The item that holds the new reference to refItem.
+ // attribute:
+ // The attribute on parentItem that contains the new reference.
+
+ //Stub function, does nothing. Real processing is in ItemFileWriteStore.
+ },
+
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ var identifier = this._features['dojo.data.api.Identity'];
+ if(identifier === Number){
+ return item[this._itemNumPropName]; // Number
+ }else{
+ var arrayOfValues = item[identifier];
+ if(arrayOfValues){
+ return arrayOfValues[0]; // Object || String
+ }
+ }
+ 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._jsonFileUrl){
+
+ if(this._loadInProgress){
+ this._queuedFetches.push({args: keywordArgs});
+ }else{
+ this._loadInProgress = true;
+ var getArgs = {
+ url: self._jsonFileUrl,
+ handleAs: "json-comment-optional"
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ try{
+ self._getItemsFromLoadedData(data);
+ self._loadFinished = true;
+ self._loadInProgress = false;
+ var item = self._getItemByIdentity(keywordArgs.identity);
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, item);
+ }
+ self._handleQueuedFetches();
+ }catch(error){
+ self._loadInProgress = false;
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, error);
+ }
+ }
+ });
+ getHandler.addErrback(function(error){
+ self._loadInProgress = false;
+ if(keywordArgs.onError){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onError.call(scope, error);
+ }
+ });
+ }
+
+ }else if(this._jsonData){
+ // Passed in data, no need to xhr.
+ self._getItemsFromLoadedData(self._jsonData);
+ self._jsonData = null;
+ self._loadFinished = true;
+ var item = self._getItemByIdentity(keywordArgs.identity);
+ 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._getItemByIdentity(keywordArgs.identity);
+ if(keywordArgs.onItem){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ },
+
+ _getItemByIdentity: function(/* Object */ identity){
+ // summary:
+ // Internal function to look an item up by its identity map.
+ var item = null;
+ if(this._itemsByIdentity){
+ item = this._itemsByIdentity[identity];
+ }else{
+ item = this._arrayOfAllItems[identity];
+ }
+ if(item === undefined){
+ item = null;
+ }
+ return item; // Object
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentifierAttributes()
+
+ var identifier = this._features['dojo.data.api.Identity'];
+ if(identifier === Number){
+ // If (identifier === Number) it means getIdentity() just returns
+ // an integer item-number for each item. The dojo.data.api.Identity
+ // spec says we need to return null if the identity is not composed
+ // of attributes
+ return null; // null
+ }else{
+ return [identifier]; // Array
+ }
+ },
+
+ _forceLoad: function(){
+ // summary:
+ // Internal function to force a load of the store if it hasn't occurred yet. This is required
+ // for specific functions to work properly.
+ var self = this;
+ if(this._jsonFileUrl){
+ var getArgs = {
+ url: self._jsonFileUrl,
+ handleAs: "json-comment-optional",
+ sync: true
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ try{
+ //Check to be sure there wasn't another load going on concurrently
+ //So we don't clobber data that comes in on it. If there is a load going on
+ //then do not save this data. It will potentially clobber current data.
+ //We mainly wanted to sync/wait here.
+ //TODO: Revisit the loading scheme of this store to improve multi-initial
+ //request handling.
+ if (self._loadInProgress !== true && !self._loadFinished) {
+ self._getItemsFromLoadedData(data);
+ self._loadFinished = true;
+ }
+ }catch(e){
+ console.log(e);
+ throw e;
+ }
+ });
+ getHandler.addErrback(function(error){
+ throw error;
+ });
+ }else if(this._jsonData){
+ self._getItemsFromLoadedData(self._jsonData);
+ self._jsonData = null;
+ self._loadFinished = true;
+ }
+ }
+});
+//Mix in the simple fetch implementation to this class.
+dojo.extend(dojo.data.ItemFileReadStore,dojo.data.util.simpleFetch);
+
+}
diff --git a/includes/js/dojo/data/ItemFileWriteStore.js b/includes/js/dojo/data/ItemFileWriteStore.js
new file mode 100644
index 0000000..6630338
--- /dev/null
+++ b/includes/js/dojo/data/ItemFileWriteStore.js
@@ -0,0 +1,804 @@
+if(!dojo._hasResource["dojo.data.ItemFileWriteStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.ItemFileWriteStore"] = true;
+dojo.provide("dojo.data.ItemFileWriteStore");
+dojo.require("dojo.data.ItemFileReadStore");
+
+dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
+ constructor: function(/* object */ keywordParameters){
+ // keywordParameters: {typeMap: object)
+ // The structure of the typeMap object is as follows:
+ // {
+ // type0: function || object,
+ // type1: function || object,
+ // ...
+ // typeN: function || object
+ // }
+ // Where if it is a function, it is assumed to be an object constructor that takes the
+ // value of _value as the initialization parameters. It is serialized assuming object.toString()
+ // serialization. If it is an object, then it is assumed
+ // to be an object of general form:
+ // {
+ // type: function, //constructor.
+ // deserialize: function(value) //The function that parses the value and constructs the object defined by type appropriately.
+ // serialize: function(object) //The function that converts the object back into the proper file format form.
+ // }
+
+ // ItemFileWriteStore extends ItemFileReadStore to implement these additional dojo.data APIs
+ this._features['dojo.data.api.Write'] = true;
+ this._features['dojo.data.api.Notification'] = true;
+
+ // For keeping track of changes so that we can implement isDirty and revert
+ this._pending = {
+ _newItems:{},
+ _modifiedItems:{},
+ _deletedItems:{}
+ };
+
+ if(!this._datatypeMap['Date'].serialize){
+ this._datatypeMap['Date'].serialize = function(obj){
+ return dojo.date.stamp.toISOString(obj, {zulu:true});
+ };
+ }
+ //Disable only if explicitly set to false.
+ if(keywordParameters && (keywordParameters.referenceIntegrity === false)){
+ this.referenceIntegrity = false;
+ }
+
+ // this._saveInProgress is set to true, briefly, from when save() is first called to when it completes
+ this._saveInProgress = false;
+ },
+
+ referenceIntegrity: true, //Flag that defaultly enabled reference integrity tracking. This way it can also be disabled pogrammatially or declaratively.
+
+ _assert: function(/* boolean */ condition){
+ if(!condition) {
+ throw new Error("assertion failed in ItemFileWriteStore");
+ }
+ },
+
+ _getIdentifierAttribute: function(){
+ var identifierAttribute = this.getFeatures()['dojo.data.api.Identity'];
+ // this._assert((identifierAttribute === Number) || (dojo.isString(identifierAttribute)));
+ return identifierAttribute;
+ },
+
+
+/* dojo.data.api.Write */
+
+ newItem: function(/* Object? */ keywordArgs, /* Object? */ parentInfo){
+ // summary: See dojo.data.api.Write.newItem()
+
+ this._assert(!this._saveInProgress);
+
+ if (!this._loadFinished){
+ // We need to do this here so that we'll be able to find out what
+ // identifierAttribute was specified in the data file.
+ this._forceLoad();
+ }
+
+ if(typeof keywordArgs != "object" && typeof keywordArgs != "undefined"){
+ throw new Error("newItem() was passed something other than an object");
+ }
+ var newIdentity = null;
+ var identifierAttribute = this._getIdentifierAttribute();
+ if(identifierAttribute === Number){
+ newIdentity = this._arrayOfAllItems.length;
+ }else{
+ newIdentity = keywordArgs[identifierAttribute];
+ if (typeof newIdentity === "undefined"){
+ throw new Error("newItem() was not passed an identity for the new item");
+ }
+ if (dojo.isArray(newIdentity)){
+ throw new Error("newItem() was not passed an single-valued identity");
+ }
+ }
+
+ // make sure this identity is not already in use by another item, if identifiers were
+ // defined in the file. Otherwise it would be the item count,
+ // which should always be unique in this case.
+ if(this._itemsByIdentity){
+ this._assert(typeof this._itemsByIdentity[newIdentity] === "undefined");
+ }
+ this._assert(typeof this._pending._newItems[newIdentity] === "undefined");
+ this._assert(typeof this._pending._deletedItems[newIdentity] === "undefined");
+
+ var newItem = {};
+ newItem[this._storeRefPropName] = this;
+ newItem[this._itemNumPropName] = this._arrayOfAllItems.length;
+ if(this._itemsByIdentity){
+ this._itemsByIdentity[newIdentity] = newItem;
+ //We have to set the identifier now, otherwise we can't look it
+ //up at calls to setValueorValues in parentInfo handling.
+ newItem[identifierAttribute] = [newIdentity];
+ }
+ this._arrayOfAllItems.push(newItem);
+
+ //We need to construct some data for the onNew call too...
+ var pInfo = null;
+
+ // Now we need to check to see where we want to assign this thingm if any.
+ if(parentInfo && parentInfo.parent && parentInfo.attribute){
+ pInfo = {
+ item: parentInfo.parent,
+ attribute: parentInfo.attribute,
+ oldValue: undefined
+ };
+
+ //See if it is multi-valued or not and handle appropriately
+ //Generally, all attributes are multi-valued for this store
+ //So, we only need to append if there are already values present.
+ var values = this.getValues(parentInfo.parent, parentInfo.attribute);
+ if(values && values.length > 0){
+ var tempValues = values.slice(0, values.length);
+ if(values.length === 1){
+ pInfo.oldValue = values[0];
+ }else{
+ pInfo.oldValue = values.slice(0, values.length);
+ }
+ tempValues.push(newItem);
+ this._setValueOrValues(parentInfo.parent, parentInfo.attribute, tempValues, false);
+ pInfo.newValue = this.getValues(parentInfo.parent, parentInfo.attribute);
+ }else{
+ this._setValueOrValues(parentInfo.parent, parentInfo.attribute, newItem, false);
+ pInfo.newValue = newItem;
+ }
+ }else{
+ //Toplevel item, add to both top list as well as all list.
+ newItem[this._rootItemPropName]=true;
+ this._arrayOfTopLevelItems.push(newItem);
+ }
+
+ this._pending._newItems[newIdentity] = newItem;
+
+ //Clone over the properties to the new item
+ for(var key in keywordArgs){
+ if(key === this._storeRefPropName || key === this._itemNumPropName){
+ // Bummer, the user is trying to do something like
+ // newItem({_S:"foo"}). Unfortunately, our superclass,
+ // ItemFileReadStore, is already using _S in each of our items
+ // to hold private info. To avoid a naming collision, we
+ // need to move all our private info to some other property
+ // of all the items/objects. So, we need to iterate over all
+ // the items and do something like:
+ // item.__S = item._S;
+ // item._S = undefined;
+ // But first we have to make sure the new "__S" variable is
+ // not in use, which means we have to iterate over all the
+ // items checking for that.
+ throw new Error("encountered bug in ItemFileWriteStore.newItem");
+ }
+ var value = keywordArgs[key];
+ if(!dojo.isArray(value)){
+ value = [value];
+ }
+ newItem[key] = value;
+ if(this.referenceIntegrity){
+ for(var i = 0; i < value.length; i++){
+ var val = value[i];
+ if(this.isItem(val)){
+ this._addReferenceToMap(val, newItem, key);
+ }
+ }
+ }
+ }
+ this.onNew(newItem, pInfo); // dojo.data.api.Notification call
+ return newItem; // item
+ },
+
+ _removeArrayElement: function(/* Array */ array, /* anything */ element){
+ var index = dojo.indexOf(array, element);
+ if (index != -1){
+ array.splice(index, 1);
+ return true;
+ }
+ return false;
+ },
+
+ deleteItem: function(/* item */ item){
+ // summary: See dojo.data.api.Write.deleteItem()
+ this._assert(!this._saveInProgress);
+ this._assertIsItem(item);
+
+ // Remove this item from the _arrayOfAllItems, but leave a null value in place
+ // of the item, so as not to change the length of the array, so that in newItem()
+ // we can still safely do: newIdentity = this._arrayOfAllItems.length;
+ var indexInArrayOfAllItems = item[this._itemNumPropName];
+ var identity = this.getIdentity(item);
+
+ //If we have reference integrity on, we need to do reference cleanup for the deleted item
+ if(this.referenceIntegrity){
+ //First scan all the attributes of this items for references and clean them up in the map
+ //As this item is going away, no need to track its references anymore.
+
+ //Get the attributes list before we generate the backup so it
+ //doesn't pollute the attributes list.
+ var attributes = this.getAttributes(item);
+
+ //Backup the map, we'll have to restore it potentially, in a revert.
+ if(item[this._reverseRefMap]){
+ item["backup_" + this._reverseRefMap] = dojo.clone(item[this._reverseRefMap]);
+ }
+
+ //TODO: This causes a reversion problem. This list won't be restored on revert since it is
+ //attached to the 'value'. item, not ours. Need to back tese up somehow too.
+ //Maybe build a map of the backup of the entries and attach it to the deleted item to be restored
+ //later. Or just record them and call _addReferenceToMap on them in revert.
+ dojo.forEach(attributes, function(attribute){
+ dojo.forEach(this.getValues(item, attribute), function(value){
+ if(this.isItem(value)){
+ //We have to back up all the references we had to others so they can be restored on a revert.
+ if(!item["backupRefs_" + this._reverseRefMap]){
+ item["backupRefs_" + this._reverseRefMap] = [];
+ }
+ item["backupRefs_" + this._reverseRefMap].push({id: this.getIdentity(value), attr: attribute});
+ this._removeReferenceFromMap(value, item, attribute);
+ }
+ }, this);
+ }, this);
+
+ //Next, see if we have references to this item, if we do, we have to clean them up too.
+ var references = item[this._reverseRefMap];
+ if(references){
+ //Look through all the items noted as references to clean them up.
+ for(var itemId in references){
+ var containingItem = null;
+ if(this._itemsByIdentity){
+ containingItem = this._itemsByIdentity[itemId];
+ }else{
+ containingItem = this._arrayOfAllItems[itemId];
+ }
+ //We have a reference to a containing item, now we have to process the
+ //attributes and clear all references to the item being deleted.
+ if(containingItem){
+ for(var attribute in references[itemId]){
+ var oldValues = this.getValues(containingItem, attribute) || [];
+ var newValues = dojo.filter(oldValues, function(possibleItem){
+ return !(this.isItem(possibleItem) && this.getIdentity(possibleItem) == identity);
+ }, this);
+ //Remove the note of the reference to the item and set the values on the modified attribute.
+ this._removeReferenceFromMap(item, containingItem, attribute);
+ if(newValues.length < oldValues.length){
+ this.setValues(containingItem, attribute, newValues);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ this._arrayOfAllItems[indexInArrayOfAllItems] = null;
+
+ item[this._storeRefPropName] = null;
+ if(this._itemsByIdentity){
+ delete this._itemsByIdentity[identity];
+ }
+ this._pending._deletedItems[identity] = item;
+
+ //Remove from the toplevel items, if necessary...
+ if(item[this._rootItemPropName]){
+ this._removeArrayElement(this._arrayOfTopLevelItems, item);
+ }
+ this.onDelete(item); // dojo.data.api.Notification call
+ return true;
+ },
+
+ setValue: function(/* item */ item, /* attribute-name-string */ attribute, /* almost anything */ value){
+ // summary: See dojo.data.api.Write.set()
+ return this._setValueOrValues(item, attribute, value, true); // boolean
+ },
+
+ setValues: function(/* item */ item, /* attribute-name-string */ attribute, /* array */ values){
+ // summary: See dojo.data.api.Write.setValues()
+ return this._setValueOrValues(item, attribute, values, true); // boolean
+ },
+
+ unsetAttribute: function(/* item */ item, /* attribute-name-string */ attribute){
+ // summary: See dojo.data.api.Write.unsetAttribute()
+ return this._setValueOrValues(item, attribute, [], true);
+ },
+
+ _setValueOrValues: function(/* item */ item, /* attribute-name-string */ attribute, /* anything */ newValueOrValues, /*boolean?*/ callOnSet){
+ this._assert(!this._saveInProgress);
+
+ // Check for valid arguments
+ this._assertIsItem(item);
+ this._assert(dojo.isString(attribute));
+ this._assert(typeof newValueOrValues !== "undefined");
+
+ // Make sure the user isn't trying to change the item's identity
+ var identifierAttribute = this._getIdentifierAttribute();
+ if(attribute == identifierAttribute){
+ throw new Error("ItemFileWriteStore does not have support for changing the value of an item's identifier.");
+ }
+
+ // To implement the Notification API, we need to make a note of what
+ // the old attribute value was, so that we can pass that info when
+ // we call the onSet method.
+ var oldValueOrValues = this._getValueOrValues(item, attribute);
+
+ var identity = this.getIdentity(item);
+ if(!this._pending._modifiedItems[identity]){
+ // Before we actually change the item, we make a copy of it to
+ // record the original state, so that we'll be able to revert if
+ // the revert method gets called. If the item has already been
+ // modified then there's no need to do this now, since we already
+ // have a record of the original state.
+ var copyOfItemState = {};
+ for(var key in item){
+ if((key === this._storeRefPropName) || (key === this._itemNumPropName) || (key === this._rootItemPropName)){
+ copyOfItemState[key] = item[key];
+ }else if(key === this._reverseRefMap){
+ copyOfItemState[key] = dojo.clone(item[key]);
+ }else{
+ copyOfItemState[key] = item[key].slice(0, item[key].length);
+ }
+ }
+ // Now mark the item as dirty, and save the copy of the original state
+ this._pending._modifiedItems[identity] = copyOfItemState;
+ }
+
+ // Okay, now we can actually change this attribute on the item
+ var success = false;
+
+ if(dojo.isArray(newValueOrValues) && newValueOrValues.length === 0){
+
+ // If we were passed an empty array as the value, that counts
+ // as "unsetting" the attribute, so we need to remove this
+ // attribute from the item.
+ success = delete item[attribute];
+ newValueOrValues = undefined; // used in the onSet Notification call below
+
+ if(this.referenceIntegrity && oldValueOrValues){
+ var oldValues = oldValueOrValues;
+ if (!dojo.isArray(oldValues)){
+ oldValues = [oldValues];
+ }
+ for(var i = 0; i < oldValues.length; i++){
+ var value = oldValues[i];
+ if(this.isItem(value)){
+ this._removeReferenceFromMap(value, item, attribute);
+ }
+ }
+ }
+ }else{
+ var newValueArray;
+ if(dojo.isArray(newValueOrValues)){
+ var newValues = newValueOrValues;
+ // Unfortunately, it's not safe to just do this:
+ // newValueArray = newValues;
+ // Instead, we need to copy the array, which slice() does very nicely.
+ // This is so that our internal data structure won't
+ // get corrupted if the user mucks with the values array *after*
+ // calling setValues().
+ newValueArray = newValueOrValues.slice(0, newValueOrValues.length);
+ }else{
+ newValueArray = [newValueOrValues];
+ }
+
+ //We need to handle reference integrity if this is on.
+ //In the case of set, we need to see if references were added or removed
+ //and update the reference tracking map accordingly.
+ if(this.referenceIntegrity){
+ if(oldValueOrValues){
+ var oldValues = oldValueOrValues;
+ if(!dojo.isArray(oldValues)){
+ oldValues = [oldValues];
+ }
+ //Use an associative map to determine what was added/removed from the list.
+ //Should be O(n) performant. First look at all the old values and make a list of them
+ //Then for any item not in the old list, we add it. If it was already present, we remove it.
+ //Then we pass over the map and any references left it it need to be removed (IE, no match in
+ //the new values list).
+ var map = {};
+ dojo.forEach(oldValues, function(possibleItem){
+ if(this.isItem(possibleItem)){
+ var id = this.getIdentity(possibleItem);
+ map[id.toString()] = true;
+ }
+ }, this);
+ dojo.forEach(newValueArray, function(possibleItem){
+ if(this.isItem(possibleItem)){
+ var id = this.getIdentity(possibleItem);
+ if(map[id.toString()]){
+ delete map[id.toString()];
+ }else{
+ this._addReferenceToMap(possibleItem, item, attribute);
+ }
+ }
+ }, this);
+ for(var rId in map){
+ var removedItem;
+ if(this._itemsByIdentity){
+ removedItem = this._itemsByIdentity[rId];
+ }else{
+ removedItem = this._arrayOfAllItems[rId];
+ }
+ this._removeReferenceFromMap(removedItem, item, attribute);
+ }
+ }else{
+ //Everything is new (no old values) so we have to just
+ //insert all the references, if any.
+ for(var i = 0; i < newValueArray.length; i++){
+ var value = newValueArray[i];
+ if(this.isItem(value)){
+ this._addReferenceToMap(value, item, attribute);
+ }
+ }
+ }
+ }
+ item[attribute] = newValueArray;
+ success = true;
+ }
+
+ // Now we make the dojo.data.api.Notification call
+ if(callOnSet){
+ this.onSet(item, attribute, oldValueOrValues, newValueOrValues);
+ }
+ return success; // boolean
+ },
+
+ _addReferenceToMap: function(/*item*/ refItem, /*item*/ parentItem, /*string*/ attribute){
+ // summary:
+ // Method to add an reference map entry for an item and attribute.
+ // description:
+ // Method to add an reference map entry for an item and attribute. //
+ // refItem:
+ // The item that is referenced.
+ // parentItem:
+ // The item that holds the new reference to refItem.
+ // attribute:
+ // The attribute on parentItem that contains the new reference.
+
+ var parentId = this.getIdentity(parentItem);
+ var references = refItem[this._reverseRefMap];
+
+ if(!references){
+ references = refItem[this._reverseRefMap] = {};
+ }
+ var itemRef = references[parentId];
+ if(!itemRef){
+ itemRef = references[parentId] = {};
+ }
+ itemRef[attribute] = true;
+ },
+
+ _removeReferenceFromMap: function(/* item */ refItem, /* item */ parentItem, /*strin*/ attribute){
+ // summary:
+ // Method to remove an reference map entry for an item and attribute.
+ // description:
+ // Method to remove an reference map entry for an item and attribute. This will
+ // also perform cleanup on the map such that if there are no more references at all to
+ // the item, its reference object and entry are removed.
+ //
+ // refItem:
+ // The item that is referenced.
+ // parentItem:
+ // The item holding a reference to refItem.
+ // attribute:
+ // The attribute on parentItem that contains the reference.
+ var identity = this.getIdentity(parentItem);
+ var references = refItem[this._reverseRefMap];
+ var itemId;
+ if(references){
+ for(itemId in references){
+ if(itemId == identity){
+ delete references[itemId][attribute];
+ if(this._isEmpty(references[itemId])){
+ delete references[itemId];
+ }
+ }
+ }
+ if(this._isEmpty(references)){
+ delete refItem[this._reverseRefMap];
+ }
+ }
+ },
+
+ _dumpReferenceMap: function(){
+ // summary:
+ // Function to dump the reverse reference map of all items in the store for debug purposes.
+ // description:
+ // Function to dump the reverse reference map of all items in the store for debug purposes.
+ var i;
+ for(i = 0; i < this._arrayOfAllItems.length; i++){
+ var item = this._arrayOfAllItems[i];
+ if(item && item[this._reverseRefMap]){
+ console.log("Item: [" + this.getIdentity(item) + "] is referenced by: " + dojo.toJson(item[this._reverseRefMap]));
+ }
+ }
+ },
+
+ _getValueOrValues: function(/* item */ item, /* attribute-name-string */ attribute){
+ var valueOrValues = undefined;
+ if(this.hasAttribute(item, attribute)){
+ var valueArray = this.getValues(item, attribute);
+ if(valueArray.length == 1){
+ valueOrValues = valueArray[0];
+ }else{
+ valueOrValues = valueArray;
+ }
+ }
+ return valueOrValues;
+ },
+
+ _flatten: function(/* anything */ value){
+ if(this.isItem(value)){
+ var item = value;
+ // Given an item, return an serializable object that provides a
+ // reference to the item.
+ // For example, given kermit:
+ // var kermit = store.newItem({id:2, name:"Kermit"});
+ // we want to return
+ // {_reference:2}
+ var identity = this.getIdentity(item);
+ var referenceObject = {_reference: identity};
+ return referenceObject;
+ }else{
+ if(typeof value === "object"){
+ for(var type in this._datatypeMap){
+ var typeMap = this._datatypeMap[type];
+ if (dojo.isObject(typeMap) && !dojo.isFunction(typeMap)){
+ if(value instanceof typeMap.type){
+ if(!typeMap.serialize){
+ throw new Error("ItemFileWriteStore: No serializer defined for type mapping: [" + type + "]");
+ }
+ return {_type: type, _value: typeMap.serialize(value)};
+ }
+ } else if(value instanceof typeMap){
+ //SImple mapping, therefore, return as a toString serialization.
+ return {_type: type, _value: value.toString()};
+ }
+ }
+ }
+ return value;
+ }
+ },
+
+ _getNewFileContentString: function(){
+ // summary:
+ // Generate a string that can be saved to a file.
+ // The result should look similar to:
+ // http://trac.dojotoolkit.org/browser/dojo/trunk/tests/data/countries.json
+ var serializableStructure = {};
+
+ var identifierAttribute = this._getIdentifierAttribute();
+ if(identifierAttribute !== Number){
+ serializableStructure.identifier = identifierAttribute;
+ }
+ if(this._labelAttr){
+ serializableStructure.label = this._labelAttr;
+ }
+ serializableStructure.items = [];
+ for(var i = 0; i < this._arrayOfAllItems.length; ++i){
+ var item = this._arrayOfAllItems[i];
+ if(item !== null){
+ var serializableItem = {};
+ for(var key in item){
+ if(key !== this._storeRefPropName && key !== this._itemNumPropName){
+ var attribute = key;
+ var valueArray = this.getValues(item, attribute);
+ if(valueArray.length == 1){
+ serializableItem[attribute] = this._flatten(valueArray[0]);
+ }else{
+ var serializableArray = [];
+ for(var j = 0; j < valueArray.length; ++j){
+ serializableArray.push(this._flatten(valueArray[j]));
+ serializableItem[attribute] = serializableArray;
+ }
+ }
+ }
+ }
+ serializableStructure.items.push(serializableItem);
+ }
+ }
+ var prettyPrint = true;
+ return dojo.toJson(serializableStructure, prettyPrint);
+ },
+
+ _isEmpty: function(something){
+ // summary:
+ // Function to determine if an array or object has no properties or values.
+ // something:
+ // The array or object to examine.
+ var empty = true;
+ if(dojo.isObject(something)){
+ var i;
+ for(i in something){
+ empty = false;
+ break;
+ }
+ }else if(dojo.isArray(something)){
+ if(something.length > 0){
+ empty = false;
+ }
+ }
+ return empty; //boolean
+ },
+
+ save: function(/* object */ keywordArgs){
+ // summary: See dojo.data.api.Write.save()
+ this._assert(!this._saveInProgress);
+
+ // this._saveInProgress is set to true, briefly, from when save is first called to when it completes
+ this._saveInProgress = true;
+
+ var self = this;
+ var saveCompleteCallback = function(){
+ self._pending = {
+ _newItems:{},
+ _modifiedItems:{},
+ _deletedItems:{}
+ };
+
+ self._saveInProgress = false; // must come after this._pending is cleared, but before any callbacks
+ if(keywordArgs && keywordArgs.onComplete){
+ var scope = keywordArgs.scope || dojo.global;
+ keywordArgs.onComplete.call(scope);
+ }
+ };
+ var saveFailedCallback = function(){
+ self._saveInProgress = false;
+ if(keywordArgs && keywordArgs.onError){
+ var scope = keywordArgs.scope || dojo.global;
+ keywordArgs.onError.call(scope);
+ }
+ };
+
+ if(this._saveEverything){
+ var newFileContentString = this._getNewFileContentString();
+ this._saveEverything(saveCompleteCallback, saveFailedCallback, newFileContentString);
+ }
+ if(this._saveCustom){
+ this._saveCustom(saveCompleteCallback, saveFailedCallback);
+ }
+ if(!this._saveEverything && !this._saveCustom){
+ // Looks like there is no user-defined save-handler function.
+ // That's fine, it just means the datastore is acting as a "mock-write"
+ // store -- changes get saved in memory but don't get saved to disk.
+ saveCompleteCallback();
+ }
+ },
+
+ revert: function(){
+ // summary: See dojo.data.api.Write.revert()
+ this._assert(!this._saveInProgress);
+
+ var identity;
+ for(identity in this._pending._newItems){
+ var newItem = this._pending._newItems[identity];
+ newItem[this._storeRefPropName] = null;
+ // null out the new item, but don't change the array index so
+ // so we can keep using _arrayOfAllItems.length.
+ this._arrayOfAllItems[newItem[this._itemNumPropName]] = null;
+ if(newItem[this._rootItemPropName]){
+ this._removeArrayElement(this._arrayOfTopLevelItems, newItem);
+ }
+ if(this._itemsByIdentity){
+ delete this._itemsByIdentity[identity];
+ }
+ }
+ for(identity in this._pending._modifiedItems){
+ // find the original item and the modified item that replaced it
+ var originalItem = this._pending._modifiedItems[identity];
+ var modifiedItem = null;
+ if(this._itemsByIdentity){
+ modifiedItem = this._itemsByIdentity[identity];
+ }else{
+ modifiedItem = this._arrayOfAllItems[identity];
+ }
+
+ // make the original item into a full-fledged item again
+ originalItem[this._storeRefPropName] = this;
+ modifiedItem[this._storeRefPropName] = null;
+
+ // replace the modified item with the original one
+ var arrayIndex = modifiedItem[this._itemNumPropName];
+ this._arrayOfAllItems[arrayIndex] = originalItem;
+
+ if(modifiedItem[this._rootItemPropName]){
+ var i;
+ for (i = 0; i < this._arrayOfTopLevelItems.length; i++) {
+ var possibleMatch = this._arrayOfTopLevelItems[i];
+ if (this.getIdentity(possibleMatch) == identity){
+ this._arrayOfTopLevelItems[i] = originalItem;
+ break;
+ }
+ }
+ }
+ if(this._itemsByIdentity){
+ this._itemsByIdentity[identity] = originalItem;
+ }
+ }
+ var deletedItem;
+ for(identity in this._pending._deletedItems){
+ deletedItem = this._pending._deletedItems[identity];
+ deletedItem[this._storeRefPropName] = this;
+ var index = deletedItem[this._itemNumPropName];
+
+ //Restore the reverse refererence map, if any.
+ if(deletedItem["backup_" + this._reverseRefMap]){
+ deletedItem[this._reverseRefMap] = deletedItem["backup_" + this._reverseRefMap];
+ delete deletedItem["backup_" + this._reverseRefMap];
+ }
+ this._arrayOfAllItems[index] = deletedItem;
+ if (this._itemsByIdentity) {
+ this._itemsByIdentity[identity] = deletedItem;
+ }
+ if(deletedItem[this._rootItemPropName]){
+ this._arrayOfTopLevelItems.push(deletedItem);
+ }
+ }
+ //We have to pass through it again and restore the reference maps after all the
+ //undeletes have occurred.
+ for(identity in this._pending._deletedItems){
+ deletedItem = this._pending._deletedItems[identity];
+ if(deletedItem["backupRefs_" + this._reverseRefMap]){
+ dojo.forEach(deletedItem["backupRefs_" + this._reverseRefMap], function(reference){
+ var refItem;
+ if(this._itemsByIdentity){
+ refItem = this._itemsByIdentity[reference.id];
+ }else{
+ refItem = this._arrayOfAllItems[reference.id];
+ }
+ this._addReferenceToMap(refItem, deletedItem, reference.attr);
+ }, this);
+ delete deletedItem["backupRefs_" + this._reverseRefMap];
+ }
+ }
+
+ this._pending = {
+ _newItems:{},
+ _modifiedItems:{},
+ _deletedItems:{}
+ };
+ return true; // boolean
+ },
+
+ isDirty: function(/* item? */ item){
+ // summary: See dojo.data.api.Write.isDirty()
+ if(item){
+ // return true if the item is dirty
+ var identity = this.getIdentity(item);
+ return new Boolean(this._pending._newItems[identity] ||
+ this._pending._modifiedItems[identity] ||
+ this._pending._deletedItems[identity]); // boolean
+ }else{
+ // return true if the store is dirty -- which means return true
+ // if there are any new items, dirty items, or modified items
+ if(!this._isEmpty(this._pending._newItems) ||
+ !this._isEmpty(this._pending._modifiedItems) ||
+ !this._isEmpty(this._pending._deletedItems)){
+ return true;
+ }
+ return false; // boolean
+ }
+ },
+
+/* dojo.data.api.Notification */
+
+ onSet: function(/* item */ item,
+ /*attribute-name-string*/ attribute,
+ /*object | array*/ oldValue,
+ /*object | array*/ newValue){
+ // summary: See dojo.data.api.Notification.onSet()
+
+ // No need to do anything. This method is here just so that the
+ // client code can connect observers to it.
+ },
+
+ onNew: function(/* item */ newItem, /*object?*/ parentInfo){
+ // summary: See dojo.data.api.Notification.onNew()
+
+ // No need to do anything. This method is here just so that the
+ // client code can connect observers to it.
+ },
+
+ onDelete: function(/* item */ deletedItem){
+ // summary: See dojo.data.api.Notification.onDelete()
+
+ // No need to do anything. This method is here just so that the
+ // client code can connect observers to it.
+ }
+});
+
+}
diff --git a/includes/js/dojo/data/api/Identity.js b/includes/js/dojo/data/api/Identity.js
new file mode 100644
index 0000000..d6d47f7
--- /dev/null
+++ b/includes/js/dojo/data/api/Identity.js
@@ -0,0 +1,107 @@
+if(!dojo._hasResource["dojo.data.api.Identity"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.api.Identity"] = true;
+dojo.provide("dojo.data.api.Identity");
+dojo.require("dojo.data.api.Read");
+
+dojo.declare("dojo.data.api.Identity", dojo.data.api.Read, {
+ // summary:
+ // This is an abstract API that data provider implementations conform to.
+ // This file defines methods signatures and intentionally leaves all the
+ // methods unimplemented.
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Identity': true
+ };
+ },
+
+ getIdentity: function(/* item */ item){
+ // summary:
+ // Returns a unique identifier for an item. The return value will be
+ // either a string or something that has a toString() method (such as,
+ // for example, a dojox.uuid.Uuid object).
+ // item:
+ // The item from the store from which to obtain its identifier.
+ // exceptions:
+ // Conforming implementations may throw an exception or return null if
+ // item is not an item.
+ // example:
+ // | var itemId = store.getIdentity(kermit);
+ // | assert(kermit === store.findByIdentity(store.getIdentity(kermit)));
+ throw new Error('Unimplemented API: dojo.data.api.Identity.getIdentity');
+ var itemIdentityString = null;
+ return itemIdentityString; // string
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // Returns an array of attribute names that are used to generate the identity.
+ // For most stores, this is a single attribute, but for some complex stores
+ // such as RDB backed stores that use compound (multi-attribute) identifiers
+ // it can be more than one. If the identity is not composed of attributes
+ // on the item, it will return null. This function is intended to identify
+ // the attributes that comprise the identity so that so that during a render
+ // of all attributes, the UI can hide the the identity information if it
+ // chooses.
+ // item:
+ // The item from the store from which to obtain the array of public attributes that
+ // compose the identifier, if any.
+ // example:
+ // | var itemId = store.getIdentity(kermit);
+ // | var identifiers = store.getIdentityAttributes(itemId);
+ // | assert(typeof identifiers === "array" || identifiers === null);
+ throw new Error('Unimplemented API: dojo.data.api.Identity.getIdentityAttributes');
+ return null; // string
+ },
+
+
+ fetchItemByIdentity: function(/* object */ keywordArgs){
+ // summary:
+ // Given the identity of an item, this method returns the item that has
+ // that identity through the onItem callback. Conforming implementations
+ // should return null if there is no item with the given identity.
+ // Implementations of fetchItemByIdentity() may sometimes return an item
+ // from a local cache and may sometimes fetch an item from a remote server,
+ //
+ // keywordArgs:
+ // An anonymous object that defines the item to locate and callbacks to invoke when the
+ // item has been located and load has completed. The format of the object is as follows:
+ // {
+ // identity: string|object,
+ // onItem: Function,
+ // onError: Function,
+ // scope: object
+ // }
+ // The *identity* parameter.
+ // The identity parameter is the identity of the item you wish to locate and load
+ // This attribute is required. It should be a string or an object that toString()
+ // can be called on.
+ //
+ // The *onItem* parameter.
+ // Function(item)
+ // The onItem parameter is the callback to invoke when the item has been loaded. It takes only one
+ // parameter, the item located, or null if none found.
+ //
+ // The *onError* parameter.
+ // Function(error)
+ // The onError parameter is the callback to invoke when the item load encountered an error. It takes only one
+ // parameter, the error object
+ //
+ // The *scope* parameter.
+ // If a scope object is provided, all of the callback functions (onItem,
+ // onError, etc) will be invoked in the context of the scope object.
+ // In the body of the callback function, the value of the "this"
+ // keyword will be the scope object. If no scope object is provided,
+ // the callback functions will be called in the context of dojo.global.
+ // For example, onItem.call(scope, item, request) vs.
+ // onItem.call(dojo.global, item, request)
+ if (!this.isItemLoaded(keywordArgs.item)) {
+ throw new Error('Unimplemented API: dojo.data.api.Identity.fetchItemByIdentity');
+ }
+ }
+});
+
+}
diff --git a/includes/js/dojo/data/api/Notification.js b/includes/js/dojo/data/api/Notification.js
new file mode 100644
index 0000000..72708d1
--- /dev/null
+++ b/includes/js/dojo/data/api/Notification.js
@@ -0,0 +1,119 @@
+if(!dojo._hasResource["dojo.data.api.Notification"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.api.Notification"] = true;
+dojo.provide("dojo.data.api.Notification");
+dojo.require("dojo.data.api.Read");
+
+dojo.declare("dojo.data.api.Notification", dojo.data.api.Read, {
+ // summary:
+ // This is an abstract API that data provider implementations conform to.
+ // This file defines functions signatures and intentionally leaves all the
+ // functions unimplemented.
+ //
+ // description:
+ // This API defines a set of APIs that all datastores that conform to the
+ // Notifications API must implement. In general, most stores will implement
+ // these APIs as no-op functions for users who wish to monitor them to be able
+ // to connect to then via dojo.connect(). For non-users of dojo.connect,
+ // they should be able to just replace the function on the store to obtain
+ // notifications. Both read-only and read-write stores may implement
+ // this feature. In the case of a read-only store, this feature makes sense if
+ // the store itself does internal polling to a back-end server and periodically updates
+ // its cache of items (deletes, adds, and updates).
+ //
+ // example:
+ //
+ // | function onSet(item, attribute, oldValue, newValue) {
+ // | //Do something with the information...
+ // | };
+ // | var store = new some.newStore();
+ // | dojo.connect(store, "onSet", onSet);
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Notification': true
+ };
+ },
+
+ onSet: function(/* item */ item,
+ /* attribute-name-string */ attribute,
+ /* object | array */ oldValue,
+ /* object | array */ newValue){
+ // summary:
+ // This function is called any time an item is modified via setValue, setValues, unsetAttribute, etc.
+ // description:
+ // This function is called any time an item is modified via setValue, setValues, unsetAttribute, etc.
+ // Its purpose is to provide a hook point for those who wish to monitor actions on items in the store
+ // in a simple manner. The general expected usage is to dojo.connect() to the store's
+ // implementation and be called after the store function is called.
+ //
+ // item:
+ // The item being modified.
+ // attribute:
+ // The attribute being changed represented as a string name.
+ // oldValue:
+ // The old value of the attribute. In the case of single value calls, such as setValue, unsetAttribute, etc,
+ // this value will be generally be an atomic value of some sort (string, int, etc, object). In the case of
+ // multi-valued attributes, it will be an array.
+ // newValue:
+ // The new value of the attribute. In the case of single value calls, such as setValue, this value will be
+ // generally be an atomic value of some sort (string, int, etc, object). In the case of multi-valued attributes,
+ // it will be an array. In the case of unsetAttribute, the new value will be 'undefined'.
+ //
+ // returns:
+ // Nothing.
+ throw new Error('Unimplemented API: dojo.data.api.Notification.onSet');
+ },
+
+ onNew: function(/* item */ newItem, /*object?*/ parentInfo){
+ // summary:
+ // This function is called any time a new item is created in the store.
+ // It is called immediately after the store newItem processing has completed.
+ // description:
+ // This function is called any time a new item is created in the store.
+ // It is called immediately after the store newItem processing has completed.
+ //
+ // newItem:
+ // The item created.
+ // parentInfo:
+ // An optional javascript object that is passed when the item created was placed in the store
+ // hierarchy as a value f another item's attribute, instead of a root level item. Note that if this
+ // function is invoked with a value for parentInfo, then onSet is not invoked stating the attribute of
+ // the parent item was modified. This is to avoid getting two notification events occurring when a new item
+ // with a parent is created. The structure passed in is as follows:
+ // {
+ // item: someItem, //The parent item
+ // attribute: "attribute-name-string", //The attribute the new item was assigned to.
+ // oldValue: something //Whatever was the previous value for the attribute.
+ // //If it is a single-value attribute only, then this value will be a single value.
+ // //If it was a multi-valued attribute, then this will be an array of all the values minues the new one.
+ // newValue: something //The new value of the attribute. In the case of single value calls, such as setValue, this value will be
+ // //generally be an atomic value of some sort (string, int, etc, object). In the case of multi-valued attributes,
+ // //it will be an array.
+ // }
+ //
+ // returns:
+ // Nothing.
+ throw new Error('Unimplemented API: dojo.data.api.Notification.onNew');
+ },
+
+ onDelete: function(/* item */ deletedItem){
+ // summary:
+ // This function is called any time an item is deleted from the store.
+ // It is called immediately after the store deleteItem processing has completed.
+ // description:
+ // This function is called any time an item is deleted from the store.
+ // It is called immediately after the store deleteItem processing has completed.
+ //
+ // deletedItem:
+ // The item deleted.
+ //
+ // returns:
+ // Nothing.
+ throw new Error('Unimplemented API: dojo.data.api.Notification.onDelete');
+ }
+});
+
+}
diff --git a/includes/js/dojo/data/api/Read.js b/includes/js/dojo/data/api/Read.js
new file mode 100644
index 0000000..e566d65
--- /dev/null
+++ b/includes/js/dojo/data/api/Read.js
@@ -0,0 +1,506 @@
+if(!dojo._hasResource["dojo.data.api.Read"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.api.Read"] = true;
+dojo.provide("dojo.data.api.Read");
+dojo.require("dojo.data.api.Request");
+
+dojo.declare("dojo.data.api.Read", null, {
+ // summary:
+ // This is an abstract API that data provider implementations conform to.
+ // This file defines methods signatures and intentionally leaves all the
+ // methods unimplemented. For more information on the dojo.data APIs,
+ // please visit: http://www.dojotoolkit.org/node/98
+
+ getValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* value? */ defaultValue){
+ // summary:
+ // Returns a single attribute value.
+ // Returns defaultValue if and only if *item* does not have a value for *attribute*.
+ // Returns null if and only if null was explicitly set as the attribute value.
+ // Returns undefined if and only if the item does not have a value for the
+ // given attribute (which is the same as saying the item does not have the attribute).
+ // description:
+ // Saying that an "item x does not have a value for an attribute y"
+ // is identical to saying that an "item x does not have attribute y".
+ // It is an oxymoron to say "that attribute is present but has no values"
+ // or "the item has that attribute but does not have any attribute values".
+ // If store.hasAttribute(item, attribute) returns false, then
+ // store.getValue(item, attribute) will return undefined.
+ //
+ // item:
+ // The item to access values on.
+ // attribute:
+ // The attribute to access represented as a string.
+ // defaultValue:
+ // Optional. A default value to use for the getValue return in the attribute does not exist or has no value.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or *attribute* is not a string
+ // example:
+ // | var darthVader = store.getValue(lukeSkywalker, "father");
+ var attributeValue = null;
+ throw new Error('Unimplemented API: dojo.data.api.Read.getValue');
+ return attributeValue; // a literal, an item, null, or undefined (never an array)
+ },
+
+ getValues: function(/* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // This getValues() method works just like the getValue() method, but getValues()
+ // always returns an array rather than a single attribute value. The array
+ // may be empty, may contain a single attribute value, or may contain
+ // many attribute values.
+ // If the item does not have a value for the given attribute, then getValues()
+ // will return an empty array: []. (So, if store.hasAttribute(item, attribute)
+ // has a return of false, then store.getValues(item, attribute) will return [].)
+ //
+ // item:
+ // The item to access values on.
+ // attribute:
+ // The attribute to access represented as a string.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or *attribute* is not a string
+ // example:
+ // | var friendsOfLuke = store.getValues(lukeSkywalker, "friends");
+ var array = [];
+ throw new Error('Unimplemented API: dojo.data.api.Read.getValues');
+ return array; // an array that may contain literals and items
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // Returns an array with all the attributes that this item has. This
+ // method will always return an array; if the item has no attributes
+ // at all, getAttributes() will return an empty array: [].
+ //
+ // item:
+ // The item to access attributes on.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or *attribute* is not a string
+ // example:
+ // | var array = store.getAttributes(kermit);
+ var array = [];
+ throw new Error('Unimplemented API: dojo.data.api.Read.getAttributes');
+ return array; // array
+ },
+
+ hasAttribute: function( /* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // Returns true if the given *item* has a value for the given *attribute*.
+ //
+ // item:
+ // The item to access attributes on.
+ // attribute:
+ // The attribute to access represented as a string.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or *attribute* is not a string
+ // example:
+ // | var trueOrFalse = store.hasAttribute(kermit, "color");
+ throw new Error('Unimplemented API: dojo.data.api.Read.hasAttribute');
+ return false; // boolean
+ },
+
+ containsValue: function(/* item */ item,
+ /* attribute-name-string */ attribute,
+ /* anything */ value){
+ // summary:
+ // Returns true if the given *value* is one of the values that getValues()
+ // would return.
+ //
+ // item:
+ // The item to access values on.
+ // attribute:
+ // The attribute to access represented as a string.
+ // value:
+ // The value to match as a value for the attribute.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or *attribute* is not a string
+ // example:
+ // | var trueOrFalse = store.containsValue(kermit, "color", "green");
+ throw new Error('Unimplemented API: dojo.data.api.Read.containsValue');
+ return false; // boolean
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // Returns true if *something* is an item and came from the store instance.
+ // Returns false if *something* is a literal, an item from another store instance,
+ // or is any object other than an item.
+ //
+ // something:
+ // Can be anything.
+ //
+ // example:
+ // | var yes = store.isItem(store.newItem());
+ // | var no = store.isItem("green");
+ throw new Error('Unimplemented API: dojo.data.api.Read.isItem');
+ return false; // boolean
+ },
+
+ isItemLoaded: function(/* anything */ something) {
+ // summary:
+ // Returns false if isItem(something) is false. Returns false if
+ // if isItem(something) is true but the the item is not yet loaded
+ // in local memory (for example, if the item has not yet been read
+ // from the server).
+ //
+ // something:
+ // Can be anything.
+ //
+ // example:
+ // | var yes = store.isItemLoaded(store.newItem());
+ // | var no = store.isItemLoaded("green");
+ throw new Error('Unimplemented API: dojo.data.api.Read.isItemLoaded');
+ return false; // boolean
+ },
+
+ loadItem: function(/* object */ keywordArgs){
+ // summary:
+ // Given an item, this method loads the item so that a subsequent call
+ // to store.isItemLoaded(item) will return true. 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. So, before invoking this method, check that
+ // the item has not already been loaded.
+ // keywordArgs:
+ // An anonymous object that defines the item to load and callbacks to invoke when the
+ // load has completed. The format of the object is as follows:
+ // {
+ // item: object,
+ // onItem: Function,
+ // onError: Function,
+ // scope: object
+ // }
+ // The *item* parameter.
+ // The item parameter is an object that represents the item in question that should be
+ // contained by the store. This attribute is required.
+
+ // The *onItem* parameter.
+ // Function(item)
+ // The onItem parameter is the callback to invoke when the item has been loaded. It takes only one
+ // parameter, the fully loaded item.
+ //
+ // The *onError* parameter.
+ // Function(error)
+ // The onError parameter is the callback to invoke when the item load encountered an error. It takes only one
+ // parameter, the error object
+ //
+ // The *scope* parameter.
+ // If a scope object is provided, all of the callback functions (onItem,
+ // onError, etc) will be invoked in the context of the scope object.
+ // In the body of the callback function, the value of the "this"
+ // keyword will be the scope object. If no scope object is provided,
+ // the callback functions will be called in the context of dojo.global().
+ // For example, onItem.call(scope, item, request) vs.
+ // onItem.call(dojo.global(), item, request)
+ if (!this.isItemLoaded(keywordArgs.item)) {
+ throw new Error('Unimplemented API: dojo.data.api.Read.loadItem');
+ }
+ },
+
+ fetch: function(/* Object */ keywordArgs){
+ // summary:
+ // Given a query and set of defined options, such as a start and count of items to return,
+ // this method executes the query and makes the results available as data items.
+ // The format and expectations of stores is that they operate in a generally asynchronous
+ // manner, therefore callbacks are always used to return items located by the fetch parameters.
+ //
+ // description:
+ // A Request object will always be returned and is returned immediately.
+ // The basic request is nothing more than the keyword args passed to fetch and
+ // an additional function attached, abort(). The returned request object may then be used
+ // to cancel a fetch. All data items returns are passed through the callbacks defined in the
+ // fetch parameters and are not present on the 'request' object.
+ //
+ // This does not mean that custom stores can not add methods and properties to the request object
+ // returned, only that the API does not require it. For more info about the Request API,
+ // see dojo.data.api.Request
+ //
+ // keywordArgs:
+ // The keywordArgs parameter may either be an instance of
+ // conforming to dojo.data.api.Request or may be a simple anonymous object
+ // that may contain any of the following:
+ // {
+ // query: query-object or query-string,
+ // queryOptions: object,
+ // onBegin: Function,
+ // onItem: Function,
+ // onComplete: Function,
+ // onError: Function,
+ // scope: object,
+ // start: int
+ // count: int
+ // sort: array
+ // }
+ // All implementations should accept keywordArgs objects with any of
+ // the 9 standard properties: query, onBegin, onItem, onComplete, onError
+ // scope, sort, start, and count. Some implementations may accept additional
+ // properties in the keywordArgs object as valid parameters, such as
+ // {includeOutliers:true}.
+ //
+ // The *query* parameter.
+ // The query may be optional in some data store implementations.
+ // The dojo.data.api.Read API does not specify the syntax or semantics
+ // of the query itself -- each different data store implementation
+ // may have its own notion of what a query should look like.
+ // However, as of dojo 0.9, 1.0, and 1.1, all the provided datastores in dojo.data
+ // and dojox.data support an object structure query, where the object is a set of
+ // name/value parameters such as { attrFoo: valueBar, attrFoo1: valueBar1}. Most of the
+ // dijit widgets, such as ComboBox assume this to be the case when working with a datastore
+ // when they dynamically update the query. Therefore, for maximum compatibility with dijit
+ // widgets the recommended query parameter is a key/value object. That does not mean that the
+ // the datastore may not take alternative query forms, such as a simple string, a Date, a number,
+ // or a mix of such. Ultimately, The dojo.data.api.Read API is agnostic about what the query
+ // format.
+ // Further note: In general for query objects that accept strings as attribute
+ // value matches, the store should also support basic filtering capability, such as *
+ // (match any character) and ? (match single character). An example query that is a query object
+ // would be like: { attrFoo: "value*"}. Which generally means match all items where they have
+ // an attribute named attrFoo, with a value that starts with 'value'.
+ //
+ // The *queryOptions* parameter
+ // The queryOptions parameter is an optional parameter used to specify optiosn that may modify
+ // the query in some fashion, such as doing a case insensitive search, or doing a deep search
+ // where all items in a hierarchical representation of data are scanned instead of just the root
+ // items. It currently defines two options that all datastores should attempt to honor if possible:
+ // {
+ // ignoreCase: boolean, //Whether or not the query should match case sensitively or not. Default behaviour is false.
+ // deep: boolean //Whether or not a fetch should do a deep search of items and all child
+ // //items instead of just root-level items in a datastore. Default is false.
+ // }
+ //
+ // The *onBegin* parameter.
+ // function(size, request);
+ // If an onBegin callback function is provided, the callback function
+ // will be called just once, before the first onItem callback is called.
+ // The onBegin callback function will be passed two arguments, the
+ // the total number of items identified and the Request object. If the total number is
+ // unknown, then size will be -1. Note that size is not necessarily the size of the
+ // collection of items returned from the query, as the request may have specified to return only a
+ // subset of the total set of items through the use of the start and count parameters.
+ //
+ // The *onItem* parameter.
+ // function(item, request);
+ // If an onItem callback function is provided, the callback function
+ // will be called as each item in the result is received. The callback
+ // function will be passed two arguments: the item itself, and the
+ // Request object.
+ //
+ // The *onComplete* parameter.
+ // function(items, request);
+ //
+ // If an onComplete callback function is provided, the callback function
+ // will be called just once, after the last onItem callback is called.
+ // Note that if the onItem callback is not present, then onComplete will be passed
+ // an array containing all items which matched the query and the request object.
+ // If the onItem callback is present, then onComplete is called as:
+ // onComplete(null, request).
+ //
+ // The *onError* parameter.
+ // function(errorData, request);
+ // If an onError callback function is provided, the callback function
+ // will be called if there is any sort of error while attempting to
+ // execute the query.
+ // The onError callback function will be passed two arguments:
+ // an Error object and the Request object.
+ //
+ // The *scope* parameter.
+ // If a scope object is provided, all of the callback functions (onItem,
+ // onComplete, onError, etc) will be invoked in the context of the scope
+ // object. In the body of the callback function, the value of the "this"
+ // keyword will be the scope object. If no scope object is provided,
+ // the callback functions will be called in the context of dojo.global().
+ // For example, onItem.call(scope, item, request) vs.
+ // onItem.call(dojo.global(), item, request)
+ //
+ // The *start* parameter.
+ // If a start parameter is specified, this is a indication to the datastore to
+ // only start returning items once the start number of items have been located and
+ // skipped. When this parameter is paired withh 'count', the store should be able
+ // to page across queries with millions of hits by only returning subsets of the
+ // hits for each query
+ //
+ // The *count* parameter.
+ // If a count parameter is specified, this is a indication to the datastore to
+ // only return up to that many items. This allows a fetch call that may have
+ // millions of item matches to be paired down to something reasonable.
+ //
+ // The *sort* parameter.
+ // If a sort parameter is specified, this is a indication to the datastore to
+ // sort the items in some manner before returning the items. The array is an array of
+ // javascript objects that must conform to the following format to be applied to the
+ // fetching of items:
+ // {
+ // attribute: attribute || attribute-name-string,
+ // descending: true|false; // Optional. Default is false.
+ // }
+ // Note that when comparing attributes, if an item contains no value for the attribute
+ // (undefined), then it the default ascending sort logic should push it to the bottom
+ // of the list. In the descending order case, it such items should appear at the top of the list.
+ //
+ // returns:
+ // The fetch() method will return a javascript object conforming to the API
+ // defined in dojo.data.api.Request. In general, it will be the keywordArgs
+ // object returned with the required functions in Request.js attached.
+ // Its general purpose is to provide a convenient way for a caller to abort an
+ // ongoing fetch.
+ //
+ // The Request object may also have additional properties when it is returned
+ // such as request.store property, which is a pointer to the datastore object that
+ // fetch() is a method of.
+ //
+ // exceptions:
+ // Throws an exception if the query is not valid, or if the query
+ // is required but was not supplied.
+ //
+ // example:
+ // Fetch all books identified by the query and call 'showBooks' when complete
+ // | var request = store.fetch({query:"all books", onComplete: showBooks});
+ // example:
+ // Fetch all items in the story and call 'showEverything' when complete.
+ // | var request = store.fetch(onComplete: showEverything);
+ // example:
+ // Fetch only 10 books that match the query 'all books', starting at the fifth book found during the search.
+ // This demonstrates how paging can be done for specific queries.
+ // | var request = store.fetch({query:"all books", start: 4, count: 10, onComplete: showBooks});
+ // example:
+ // Fetch all items that match the query, calling 'callback' each time an item is located.
+ // | var request = store.fetch({query:"foo/bar", onItem:callback});
+ // example:
+ // Fetch the first 100 books by author King, call showKing when up to 100 items have been located.
+ // | var request = store.fetch({query:{author:"King"}, start: 0, count:100, onComplete: showKing});
+ // example:
+ // Locate the books written by Author King, sort it on title and publisher, then return the first 100 items from the sorted items.
+ // | var request = store.fetch({query:{author:"King"}, sort: [{ attribute: "title", descending: true}, {attribute: "publisher"}], ,start: 0, count:100, onComplete: 'showKing'});
+ // example:
+ // Fetch the first 100 books by authors starting with the name King, then call showKing when up to 100 items have been located.
+ // | var request = store.fetch({query:{author:"King*"}, start: 0, count:100, onComplete: showKing});
+ // example:
+ // Fetch the first 100 books by authors ending with 'ing', but only have one character before it (King, Bing, Ling, Sing, etc.), then call showBooks when up to 100 items have been located.
+ // | var request = store.fetch({query:{author:"?ing"}, start: 0, count:100, onComplete: showBooks});
+ // example:
+ // Fetch the first 100 books by author King, where the name may appear as King, king, KING, kInG, and so on, then call showKing when up to 100 items have been located.
+ // | var request = store.fetch({query:{author:"King"}, queryOptions:(ignoreCase: true}, start: 0, count:100, onComplete: showKing});
+ // example:
+ // Paging
+ // | var store = new dojo.data.LargeRdbmsStore({url:"jdbc:odbc:foobar"});
+ // | var fetchArgs = {
+ // | query: {type:"employees", name:"Hillary *"}, // string matching
+ // | sort: [{attribute:"department", descending:true}],
+ // | start: 0,
+ // | count: 20,
+ // | scope: displayer,
+ // | onBegin: showThrobber,
+ // | onItem: displayItem,
+ // | onComplete: stopThrobber,
+ // | onError: handleFetchError,
+ // | };
+ // | store.fetch(fetchArgs);
+ // | ...
+ // and then when the user presses the "Next Page" button...
+ // | fetchArgs.start += 20;
+ // | store.fetch(fetchArgs); // get the next 20 items
+ var request = null;
+ throw new Error('Unimplemented API: dojo.data.api.Read.fetch');
+ return request; // an object conforming to the dojo.data.api.Request API
+ },
+
+ getFeatures: function(){
+ // summary:
+ // The getFeatures() method returns an simple keyword values object
+ // that specifies what interface features the datastore implements.
+ // A simple CsvStore may be read-only, and the only feature it
+ // implements will be the 'dojo.data.api.Read' interface, so the
+ // getFeatures() method will return an object like this one:
+ // {'dojo.data.api.Read': true}.
+ // A more sophisticated datastore might implement a variety of
+ // interface features, like 'dojo.data.api.Read', 'dojo.data.api.Write',
+ // 'dojo.data.api.Identity', and 'dojo.data.api.Attribution'.
+ return {
+ 'dojo.data.api.Read': true
+ };
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // The close() method is intended for instructing the store to 'close' out
+ // any information associated with a particular request.
+ //
+ // description:
+ // The close() method is intended for instructing the store to 'close' out
+ // any information associated with a particular request. In general, this API
+ // expects to recieve as a parameter a request object returned from a fetch.
+ // It will then close out anything associated with that request, such as
+ // clearing any internal datastore caches and closing any 'open' connections.
+ // For some store implementations, this call may be a no-op.
+ //
+ // request:
+ // An instance of a request for the store to use to identify what to close out.
+ // If no request is passed, then the store should clear all internal caches (if any)
+ // and close out all 'open' connections. It does not render the store unusable from
+ // there on, it merely cleans out any current data and resets the store to initial
+ // state.
+ //
+ // example:
+ // | var request = store.fetch({onComplete: doSomething});
+ // | ...
+ // | store.close(request);
+ throw new Error('Unimplemented API: dojo.data.api.Read.close');
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // Method to inspect the item and return a user-readable 'label' for the item
+ // that provides a general/adequate description of what the item is.
+ //
+ // description:
+ // Method to inspect the item and return a user-readable 'label' for the item
+ // that provides a general/adequate description of what the item is. In general
+ // most labels will be a specific attribute value or collection of the attribute
+ // values that combine to label the item in some manner. For example for an item
+ // that represents a person it may return the label as: "firstname lastlame" where
+ // the firstname and lastname are attributes on the item. If the store is unable
+ // to determine an adequate human readable label, it should return undefined. Users that wish
+ // to customize how a store instance labels items should replace the getLabel() function on
+ // their instance of the store, or extend the store and replace the function in
+ // the extension class.
+ //
+ // item:
+ // The item to return the label for.
+ //
+ // returns:
+ // A user-readable string representing the item or undefined if no user-readable label can
+ // be generated.
+ throw new Error('Unimplemented API: dojo.data.api.Read.getLabel');
+ return undefined;
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // Method to inspect the item and return an array of what attributes of the item were used
+ // to generate its label, if any.
+ //
+ // description:
+ // Method to inspect the item and return an array of what attributes of the item were used
+ // to generate its label, if any. This function is to assist UI developers in knowing what
+ // attributes can be ignored out of the attributes an item has when displaying it, in cases
+ // where the UI is using the label as an overall identifer should they wish to hide
+ // redundant information.
+ //
+ // item:
+ // The item to return the list of label attributes for.
+ //
+ // returns:
+ // An array of attribute names that were used to generate the label, or null if public attributes
+ // were not used to generate the label.
+ throw new Error('Unimplemented API: dojo.data.api.Read.getLabelAttributes');
+ return null;
+ }
+});
+
+}
diff --git a/includes/js/dojo/data/api/Request.js b/includes/js/dojo/data/api/Request.js
new file mode 100644
index 0000000..803bad8
--- /dev/null
+++ b/includes/js/dojo/data/api/Request.js
@@ -0,0 +1,32 @@
+if(!dojo._hasResource["dojo.data.api.Request"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.api.Request"] = true;
+dojo.provide("dojo.data.api.Request");
+
+dojo.declare("dojo.data.api.Request", null, {
+ // summary:
+ // This class defines out the semantics of what a 'Request' object looks like
+ // when returned from a fetch() method. In general, a request object is
+ // nothing more than the original keywordArgs from fetch with an abort function
+ // attached to it to allow users to abort a particular request if they so choose.
+ // No other functions are required on a general Request object return. That does not
+ // inhibit other store implementations from adding extentions to it, of course.
+ //
+ // This is an abstract API that data provider implementations conform to.
+ // This file defines methods signatures and intentionally leaves all the
+ // methods unimplemented.
+ //
+ // For more details on fetch, see dojo.data.api.Read.fetch().
+
+ abort: function(){
+ // summary:
+ // This function is a hook point for stores to provide as a way for
+ // a fetch to be halted mid-processing.
+ // description:
+ // This function is a hook point for stores to provide as a way for
+ // a fetch to be halted mid-processing. For more details on the fetch() api,
+ // please see dojo.data.api.Read.fetch().
+ throw new Error('Unimplemented API: dojo.data.api.Request.abort');
+ }
+});
+
+}
diff --git a/includes/js/dojo/data/api/Write.js b/includes/js/dojo/data/api/Write.js
new file mode 100644
index 0000000..b02eb6e
--- /dev/null
+++ b/includes/js/dojo/data/api/Write.js
@@ -0,0 +1,226 @@
+if(!dojo._hasResource["dojo.data.api.Write"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.api.Write"] = true;
+dojo.provide("dojo.data.api.Write");
+dojo.require("dojo.data.api.Read");
+
+dojo.declare("dojo.data.api.Write", dojo.data.api.Read, {
+ // summary:
+ // This is an abstract API that data provider implementations conform to.
+ // This file defines function signatures and intentionally leaves all the
+ // functionss unimplemented.
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Write': true
+ };
+ },
+
+ newItem: function(/* Object? */ keywordArgs, /*Object?*/ parentInfo){
+ // summary:
+ // Returns a newly created item. Sets the attributes of the new
+ // item based on the *keywordArgs* provided. In general, the attribute
+ // names in the keywords become the attributes in the new item and as for
+ // the attribute values in keywordArgs, they become the values of the attributes
+ // in the new item. In addition, for stores that support hierarchical item
+ // creation, an optional second parameter is accepted that defines what item is the parent
+ // of the new item and what attribute of that item should the new item be assigned to.
+ // In general, this will assume that the attribute targetted is multi-valued and a new item
+ // is appended onto the list of values for that attribute.
+ //
+ // keywordArgs:
+ // A javascript object defining the initial content of the item as a set of JavaScript 'property name: value' pairs.
+ // parentInfo:
+ // An optional javascript object defining what item is the parent of this item (in a hierarchical store. Not all stores do hierarchical items),
+ // and what attribute of that parent to assign the new item to. If this is present, and the attribute specified
+ // is a multi-valued attribute, it will append this item into the array of values for that attribute. The structure
+ // of the object is as follows:
+ // {
+ // parent: someItem,
+ // attribute: "attribute-name-string"
+ // }
+ //
+ // exceptions:
+ // Throws an exception if *keywordArgs* is a string or a number or
+ // anything other than a simple anonymous object.
+ // Throws an exception if the item in parentInfo is not an item from the store
+ // or if the attribute isn't an attribute name string.
+ // example:
+ // | var kermit = store.newItem({name: "Kermit", color:[blue, green]});
+
+ var newItem;
+ throw new Error('Unimplemented API: dojo.data.api.Write.newItem');
+ return newItem; // item
+ },
+
+ deleteItem: function(/* item */ item){
+ // summary:
+ // Deletes an item from the store.
+ //
+ // item:
+ // The item to delete.
+ //
+ // exceptions:
+ // Throws an exception if the argument *item* is not an item
+ // (if store.isItem(item) returns false).
+ // example:
+ // | var success = store.deleteItem(kermit);
+ throw new Error('Unimplemented API: dojo.data.api.Write.deleteItem');
+ return false; // boolean
+ },
+
+ setValue: function( /* item */ item,
+ /* string */ attribute,
+ /* almost anything */ value){
+ // summary:
+ // Sets the value of an attribute on an item.
+ // Replaces any previous value or values.
+ //
+ // item:
+ // The item to modify.
+ // attribute:
+ // The attribute of the item to change represented as a string name.
+ // value:
+ // The value to assign to the item.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or if *attribute*
+ // is neither an attribute object or a string.
+ // Throws an exception if *value* is undefined.
+ // example:
+ // | var success = store.set(kermit, "color", "green");
+ throw new Error('Unimplemented API: dojo.data.api.Write.setValue');
+ return false; // boolean
+ },
+
+ setValues: function(/* item */ item,
+ /* string */ attribute,
+ /* array */ values){
+ // summary:
+ // Adds each value in the *values* array as a value of the given
+ // attribute on the given item.
+ // Replaces any previous value or values.
+ // Calling store.setValues(x, y, []) (with *values* as an empty array) has
+ // the same effect as calling store.unsetAttribute(x, y).
+ //
+ // item:
+ // The item to modify.
+ // attribute:
+ // The attribute of the item to change represented as a string name.
+ // values:
+ // An array of values to assign to the attribute..
+ //
+ // exceptions:
+ // Throws an exception if *values* is not an array, if *item* is not an
+ // item, or if *attribute* is neither an attribute object or a string.
+ // example:
+ // | var success = store.setValues(kermit, "color", ["green", "aqua"]);
+ // | success = store.setValues(kermit, "color", []);
+ // | if (success) {assert(!store.hasAttribute(kermit, "color"));}
+ throw new Error('Unimplemented API: dojo.data.api.Write.setValues');
+ return false; // boolean
+ },
+
+ unsetAttribute: function( /* item */ item,
+ /* string */ attribute){
+ // summary:
+ // Deletes all the values of an attribute on an item.
+ //
+ // item:
+ // The item to modify.
+ // attribute:
+ // The attribute of the item to unset represented as a string.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or if *attribute*
+ // is neither an attribute object or a string.
+ // example:
+ // | var success = store.unsetAttribute(kermit, "color");
+ // | if (success) {assert(!store.hasAttribute(kermit, "color"));}
+ throw new Error('Unimplemented API: dojo.data.api.Write.clear');
+ return false; // boolean
+ },
+
+ save: function(/* object */ keywordArgs){
+ // summary:
+ // Saves to the server all the changes that have been made locally.
+ // The save operation may take some time and is generally performed
+ // in an asynchronous fashion. The outcome of the save action is
+ // is passed into the set of supported callbacks for the save.
+ //
+ // keywordArgs:
+ // {
+ // onComplete: function
+ // onError: function
+ // scope: object
+ // }
+ //
+ // The *onComplete* parameter.
+ // function();
+ //
+ // If an onComplete callback function is provided, the callback function
+ // will be called just once, after the save has completed. No parameters
+ // are generally passed to the onComplete.
+ //
+ // The *onError* parameter.
+ // function(errorData);
+ //
+ // If an onError callback function is provided, the callback function
+ // will be called if there is any sort of error while attempting to
+ // execute the save. The onError function will be based one parameter, the
+ // error.
+ //
+ // The *scope* parameter.
+ // If a scope object is provided, all of the callback function (
+ // onComplete, onError, etc) will be invoked in the context of the scope
+ // object. In the body of the callback function, the value of the "this"
+ // keyword will be the scope object. If no scope object is provided,
+ // the callback functions will be called in the context of dojo.global.
+ // For example, onComplete.call(scope) vs.
+ // onComplete.call(dojo.global)
+ //
+ // returns:
+ // Nothing. Since the saves are generally asynchronous, there is
+ // no need to return anything. All results are passed via callbacks.
+ // example:
+ // | store.save({onComplete: onSave});
+ // | store.save({scope: fooObj, onComplete: onSave, onError: saveFailed});
+ throw new Error('Unimplemented API: dojo.data.api.Write.save');
+ },
+
+ revert: function(){
+ // summary:
+ // Discards any unsaved changes.
+ // description:
+ // Discards any unsaved changes.
+ //
+ // example:
+ // | var success = store.revert();
+ throw new Error('Unimplemented API: dojo.data.api.Write.revert');
+ return false; // boolean
+ },
+
+ isDirty: function(/* item? */ item){
+ // summary:
+ // Given an item, isDirty() returns true if the item has been modified
+ // since the last save(). If isDirty() is called with no *item* argument,
+ // then this function returns true if any item has been modified since
+ // the last save().
+ //
+ // item:
+ // The item to check.
+ //
+ // exceptions:
+ // Throws an exception if isDirty() is passed an argument and the
+ // argument is not an item.
+ // example:
+ // | var trueOrFalse = store.isDirty(kermit); // true if kermit is dirty
+ // | var trueOrFalse = store.isDirty(); // true if any item is dirty
+ throw new Error('Unimplemented API: dojo.data.api.Write.isDirty');
+ return false; // boolean
+ }
+});
+
+}
diff --git a/includes/js/dojo/data/util/filter.js b/includes/js/dojo/data/util/filter.js
new file mode 100644
index 0000000..125d264
--- /dev/null
+++ b/includes/js/dojo/data/util/filter.js
@@ -0,0 +1,69 @@
+if(!dojo._hasResource["dojo.data.util.filter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.util.filter"] = true;
+dojo.provide("dojo.data.util.filter");
+
+dojo.data.util.filter.patternToRegExp = function(/*String*/pattern, /*boolean?*/ ignoreCase){
+ // summary:
+ // Helper function to convert a simple pattern to a regular expression for matching.
+ // description:
+ // Returns a regular expression object that conforms to the defined conversion rules.
+ // For example:
+ // ca* -> /^ca.*$/
+ // *ca* -> /^.*ca.*$/
+ // *c\*a* -> /^.*c\*a.*$/
+ // *c\*a?* -> /^.*c\*a..*$/
+ // and so on.
+ //
+ // pattern: string
+ // A simple matching pattern to convert that follows basic rules:
+ // * Means match anything, so ca* means match anything starting with ca
+ // ? Means match single character. So, b?b will match to bob and bab, and so on.
+ // \ is an escape character. So for example, \* means do not treat * as a match, but literal character *.
+ // To use a \ as a character in the string, it must be escaped. So in the pattern it should be
+ // represented by \\ to be treated as an ordinary \ character instead of an escape.
+ //
+ // ignoreCase:
+ // An optional flag to indicate if the pattern matching should be treated as case-sensitive or not when comparing
+ // By default, it is assumed case sensitive.
+
+ var rxp = "^";
+ var c = null;
+ for(var i = 0; i < pattern.length; i++){
+ c = pattern.charAt(i);
+ switch (c) {
+ case '\\':
+ rxp += c;
+ i++;
+ rxp += pattern.charAt(i);
+ break;
+ case '*':
+ rxp += ".*"; break;
+ case '?':
+ rxp += "."; break;
+ case '$':
+ case '^':
+ case '/':
+ case '+':
+ case '.':
+ case '|':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ rxp += "\\"; //fallthrough
+ default:
+ rxp += c;
+ }
+ }
+ rxp += "$";
+ if(ignoreCase){
+ return new RegExp(rxp,"i"); //RegExp
+ }else{
+ return new RegExp(rxp); //RegExp
+ }
+
+};
+
+}
diff --git a/includes/js/dojo/data/util/simpleFetch.js b/includes/js/dojo/data/util/simpleFetch.js
new file mode 100644
index 0000000..f54d763
--- /dev/null
+++ b/includes/js/dojo/data/util/simpleFetch.js
@@ -0,0 +1,90 @@
+if(!dojo._hasResource["dojo.data.util.simpleFetch"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.util.simpleFetch"] = true;
+dojo.provide("dojo.data.util.simpleFetch");
+dojo.require("dojo.data.util.sorter");
+
+dojo.data.util.simpleFetch.fetch = function(/* Object? */ request){
+ // summary:
+ // The simpleFetch mixin is designed to serve as a set of function(s) that can
+ // be mixed into other datastore implementations to accelerate their development.
+ // The simpleFetch mixin should work well for any datastore that can respond to a _fetchItems()
+ // call by returning an array of all the found items that matched the query. The simpleFetch mixin
+ // is not designed to work for datastores that respond to a fetch() call by incrementally
+ // loading items, or sequentially loading partial batches of the result
+ // set. For datastores that mixin simpleFetch, simpleFetch
+ // implements a fetch method that automatically handles eight of the fetch()
+ // arguments -- onBegin, onItem, onComplete, onError, start, count, sort and scope
+ // The class mixing in simpleFetch should not implement fetch(),
+ // but should instead implement a _fetchItems() method. The _fetchItems()
+ // method takes three arguments, the keywordArgs object that was passed
+ // to fetch(), a callback function to be called when the result array is
+ // available, and an error callback to be called if something goes wrong.
+ // The _fetchItems() method should ignore any keywordArgs parameters for
+ // start, count, onBegin, onItem, onComplete, onError, sort, and scope.
+ // The _fetchItems() method needs to correctly handle any other keywordArgs
+ // parameters, including the query parameter and any optional parameters
+ // (such as includeChildren). The _fetchItems() method should create an array of
+ // result items and pass it to the fetchHandler along with the original request object
+ // -- or, the _fetchItems() method may, if it wants to, create an new request object
+ // with other specifics about the request that are specific to the datastore and pass
+ // that as the request object to the handler.
+ //
+ // For more information on this specific function, see dojo.data.api.Read.fetch()
+ 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){
+ var oldAbortFunction = requestObject.abort || null;
+ var aborted = false;
+
+ var startIndex = requestObject.start?requestObject.start: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, items.length, requestObject);
+ }
+ if(requestObject.sort){
+ 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
+};
+
+}
diff --git a/includes/js/dojo/data/util/sorter.js b/includes/js/dojo/data/util/sorter.js
new file mode 100644
index 0000000..e13fedc
--- /dev/null
+++ b/includes/js/dojo/data/util/sorter.js
@@ -0,0 +1,81 @@
+if(!dojo._hasResource["dojo.data.util.sorter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.util.sorter"] = true;
+dojo.provide("dojo.data.util.sorter");
+
+dojo.data.util.sorter.basicComparator = function( /*anything*/ a,
+ /*anything*/ b){
+ // summary:
+ // Basic comparision function that compares if an item is greater or less than another item
+ // description:
+ // returns 1 if a > b, -1 if a < b, 0 if equal.
+ // undefined values are treated as larger values so that they're pushed to the end of the list.
+
+ var ret = 0;
+ if(a > b || typeof a === "undefined" || a === null){
+ ret = 1;
+ }else if(a < b || typeof b === "undefined" || b === null){
+ ret = -1;
+ }
+ return ret; //int, {-1,0,1}
+};
+
+dojo.data.util.sorter.createSortFunction = function( /* attributes array */sortSpec,
+ /*dojo.data.core.Read*/ store){
+ // summary:
+ // Helper function to generate the sorting function based off the list of sort attributes.
+ // description:
+ // The sort function creation will look for a property on the store called 'comparatorMap'. If it exists
+ // it will look in the mapping for comparisons function for the attributes. If one is found, it will
+ // use it instead of the basic comparator, which is typically used for strings, ints, booleans, and dates.
+ // Returns the sorting function for this particular list of attributes and sorting directions.
+ //
+ // sortSpec: array
+ // A JS object that array that defines out what attribute names to sort on and whether it should be descenting or asending.
+ // The objects should be formatted as follows:
+ // {
+ // attribute: "attributeName-string" || attribute,
+ // descending: true|false; // Default is false.
+ // }
+ // store: object
+ // The datastore object to look up item values from.
+ //
+ var sortFunctions=[];
+
+ function createSortFunction(attr, dir){
+ return function(itemA, itemB){
+ var a = store.getValue(itemA, attr);
+ var b = store.getValue(itemB, attr);
+ //See if we have a override for an attribute comparison.
+ var comparator = null;
+ if(store.comparatorMap){
+ if(typeof attr !== "string"){
+ attr = store.getIdentity(attr);
+ }
+ comparator = store.comparatorMap[attr]||dojo.data.util.sorter.basicComparator;
+ }
+ comparator = comparator||dojo.data.util.sorter.basicComparator;
+ return dir * comparator(a,b); //int
+ };
+ }
+
+ for(var i = 0; i < sortSpec.length; i++){
+ sortAttribute = sortSpec[i];
+ if(sortAttribute.attribute){
+ var direction = (sortAttribute.descending) ? -1 : 1;
+ sortFunctions.push(createSortFunction(sortAttribute.attribute, direction));
+ }
+ }
+
+ return function(rowA, rowB){
+ var i=0;
+ while(i < sortFunctions.length){
+ var ret = sortFunctions[i++](rowA, rowB);
+ if(ret !== 0){
+ return ret;//int
+ }
+ }
+ return 0; //int
+ }; // Function
+};
+
+}
diff --git a/includes/js/dojo/date.js b/includes/js/dojo/date.js
new file mode 100644
index 0000000..c84ea84
--- /dev/null
+++ b/includes/js/dojo/date.js
@@ -0,0 +1,343 @@
+if(!dojo._hasResource["dojo.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.date"] = true;
+dojo.provide("dojo.date");
+
+/*=====
+dojo.date = {
+ // summary: Date manipulation utilities
+}
+=====*/
+
+dojo.date.getDaysInMonth = function(/*Date*/dateObject){
+ // summary:
+ // Returns the number of days in the month used by dateObject
+ var month = dateObject.getMonth();
+ var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+ if(month == 1 && dojo.date.isLeapYear(dateObject)){ return 29; } // Number
+ return days[month]; // Number
+}
+
+dojo.date.isLeapYear = function(/*Date*/dateObject){
+ // summary:
+ // Determines if the year of the dateObject is a leap year
+ // description:
+ // Leap years are years with an additional day YYYY-02-29, where the
+ // year number is a multiple of four with the following exception: If
+ // a year is a multiple of 100, then it is only a leap year if it is
+ // also a multiple of 400. For example, 1900 was not a leap year, but
+ // 2000 is one.
+
+ var year = dateObject.getFullYear();
+ return !(year%400) || (!(year%4) && !!(year%100)); // Boolean
+}
+
+// FIXME: This is not localized
+dojo.date.getTimezoneName = function(/*Date*/dateObject){
+ // summary:
+ // Get the user's time zone as provided by the browser
+ // dateObject:
+ // Needed because the timezone may vary with time (daylight savings)
+ // description:
+ // Try to get time zone info from toString or toLocaleString method of
+ // the Date object -- UTC offset is not a time zone. See
+ // http://www.twinsun.com/tz/tz-link.htm Note: results may be
+ // inconsistent across browsers.
+
+ var str = dateObject.toString(); // Start looking in toString
+ var tz = ''; // The result -- return empty string if nothing found
+ var match;
+
+ // First look for something in parentheses -- fast lookup, no regex
+ var pos = str.indexOf('(');
+ if(pos > -1){
+ tz = str.substring(++pos, str.indexOf(')'));
+ }else{
+ // If at first you don't succeed ...
+ // If IE knows about the TZ, it appears before the year
+ // Capital letters or slash before a 4-digit year
+ // at the end of string
+ var pat = /([A-Z\/]+) \d{4}$/;
+ if((match = str.match(pat))){
+ tz = match[1];
+ }else{
+ // Some browsers (e.g. Safari) glue the TZ on the end
+ // of toLocaleString instead of putting it in toString
+ str = dateObject.toLocaleString();
+ // Capital letters or slash -- end of string,
+ // after space
+ pat = / ([A-Z\/]+)$/;
+ if((match = str.match(pat))){
+ tz = match[1];
+ }
+ }
+ }
+
+ // Make sure it doesn't somehow end up return AM or PM
+ return (tz == 'AM' || tz == 'PM') ? '' : tz; // String
+}
+
+// Utility methods to do arithmetic calculations with Dates
+
+dojo.date.compare = function(/*Date*/date1, /*Date?*/date2, /*String?*/portion){
+ // summary:
+ // Compare two date objects by date, time, or both.
+ // description:
+ // Returns 0 if equal, positive if a > b, else negative.
+ // date1:
+ // Date object
+ // date2:
+ // Date object. If not specified, the current Date is used.
+ // portion:
+ // A string indicating the "date" or "time" portion of a Date object.
+ // Compares both "date" and "time" by default. One of the following:
+ // "date", "time", "datetime"
+
+ // Extra step required in copy for IE - see #3112
+ date1 = new Date(Number(date1));
+ date2 = new Date(Number(date2 || new Date()));
+
+ if(portion !== "undefined"){
+ if(portion == "date"){
+ // Ignore times and compare dates.
+ date1.setHours(0, 0, 0, 0);
+ date2.setHours(0, 0, 0, 0);
+ }else if(portion == "time"){
+ // Ignore dates and compare times.
+ date1.setFullYear(0, 0, 0);
+ date2.setFullYear(0, 0, 0);
+ }
+ }
+
+ if(date1 > date2){ return 1; } // int
+ if(date1 < date2){ return -1; } // int
+ return 0; // int
+};
+
+dojo.date.add = function(/*Date*/date, /*String*/interval, /*int*/amount){
+ // summary:
+ // Add to a Date in intervals of different size, from milliseconds to years
+ // date: Date
+ // Date object to start with
+ // interval:
+ // A string representing the interval. One of the following:
+ // "year", "month", "day", "hour", "minute", "second",
+ // "millisecond", "quarter", "week", "weekday"
+ // amount:
+ // How much to add to the date.
+
+ var sum = new Date(Number(date)); // convert to Number before copying to accomodate IE (#3112)
+ var fixOvershoot = false;
+ var property = "Date";
+
+ switch(interval){
+ case "day":
+ break;
+ case "weekday":
+ //i18n FIXME: assumes Saturday/Sunday weekend, but this is not always true. see dojo.cldr.supplemental
+
+ // Divide the increment time span into weekspans plus leftover days
+ // e.g., 8 days is one 5-day weekspan / and two leftover days
+ // Can't have zero leftover days, so numbers divisible by 5 get
+ // a days value of 5, and the remaining days make up the number of weeks
+ var days, weeks;
+ var mod = amount % 5;
+ if(!mod){
+ days = (amount > 0) ? 5 : -5;
+ weeks = (amount > 0) ? ((amount-5)/5) : ((amount+5)/5);
+ }else{
+ days = mod;
+ weeks = parseInt(amount/5);
+ }
+ // Get weekday value for orig date param
+ var strt = date.getDay();
+ // Orig date is Sat / positive incrementer
+ // Jump over Sun
+ var adj = 0;
+ if(strt == 6 && amount > 0){
+ adj = 1;
+ }else if(strt == 0 && amount < 0){
+ // Orig date is Sun / negative incrementer
+ // Jump back over Sat
+ adj = -1;
+ }
+ // Get weekday val for the new date
+ var trgt = strt + days;
+ // New date is on Sat or Sun
+ if(trgt == 0 || trgt == 6){
+ adj = (amount > 0) ? 2 : -2;
+ }
+ // Increment by number of weeks plus leftover days plus
+ // weekend adjustments
+ amount = (7 * weeks) + days + adj;
+ break;
+ case "year":
+ property = "FullYear";
+ // Keep increment/decrement from 2/29 out of March
+ fixOvershoot = true;
+ break;
+ case "week":
+ amount *= 7;
+ break;
+ case "quarter":
+ // Naive quarter is just three months
+ amount *= 3;
+ // fallthrough...
+ case "month":
+ // Reset to last day of month if you overshoot
+ fixOvershoot = true;
+ property = "Month";
+ break;
+ case "hour":
+ case "minute":
+ case "second":
+ case "millisecond":
+ property = "UTC"+interval.charAt(0).toUpperCase() + interval.substring(1) + "s";
+ }
+
+ if(property){
+ sum["set"+property](sum["get"+property]()+amount);
+ }
+
+ if(fixOvershoot && (sum.getDate() < date.getDate())){
+ sum.setDate(0);
+ }
+
+ return sum; // Date
+};
+
+dojo.date.difference = function(/*Date*/date1, /*Date?*/date2, /*String?*/interval){
+ // summary:
+ // Get the difference in a specific unit of time (e.g., number of
+ // months, weeks, days, etc.) between two dates, rounded to the
+ // nearest integer.
+ // date1:
+ // Date object
+ // date2:
+ // Date object. If not specified, the current Date is used.
+ // interval:
+ // A string representing the interval. One of the following:
+ // "year", "month", "day", "hour", "minute", "second",
+ // "millisecond", "quarter", "week", "weekday"
+ // Defaults to "day".
+
+ date2 = date2 || new Date();
+ interval = interval || "day";
+ var yearDiff = date2.getFullYear() - date1.getFullYear();
+ var delta = 1; // Integer return value
+
+ switch(interval){
+ case "quarter":
+ var m1 = date1.getMonth();
+ var m2 = date2.getMonth();
+ // Figure out which quarter the months are in
+ var q1 = Math.floor(m1/3) + 1;
+ var q2 = Math.floor(m2/3) + 1;
+ // Add quarters for any year difference between the dates
+ q2 += (yearDiff * 4);
+ delta = q2 - q1;
+ break;
+ case "weekday":
+ var days = Math.round(dojo.date.difference(date1, date2, "day"));
+ var weeks = parseInt(dojo.date.difference(date1, date2, "week"));
+ var mod = days % 7;
+
+ // Even number of weeks
+ if(mod == 0){
+ days = weeks*5;
+ }else{
+ // Weeks plus spare change (< 7 days)
+ var adj = 0;
+ var aDay = date1.getDay();
+ var bDay = date2.getDay();
+
+ weeks = parseInt(days/7);
+ mod = days % 7;
+ // Mark the date advanced by the number of
+ // round weeks (may be zero)
+ var dtMark = new Date(date1);
+ dtMark.setDate(dtMark.getDate()+(weeks*7));
+ var dayMark = dtMark.getDay();
+
+ // Spare change days -- 6 or less
+ if(days > 0){
+ switch(true){
+ // Range starts on Sat
+ case aDay == 6:
+ adj = -1;
+ break;
+ // Range starts on Sun
+ case aDay == 0:
+ adj = 0;
+ break;
+ // Range ends on Sat
+ case bDay == 6:
+ adj = -1;
+ break;
+ // Range ends on Sun
+ case bDay == 0:
+ adj = -2;
+ break;
+ // Range contains weekend
+ case (dayMark + mod) > 5:
+ adj = -2;
+ }
+ }else if(days < 0){
+ switch(true){
+ // Range starts on Sat
+ case aDay == 6:
+ adj = 0;
+ break;
+ // Range starts on Sun
+ case aDay == 0:
+ adj = 1;
+ break;
+ // Range ends on Sat
+ case bDay == 6:
+ adj = 2;
+ break;
+ // Range ends on Sun
+ case bDay == 0:
+ adj = 1;
+ break;
+ // Range contains weekend
+ case (dayMark + mod) < 0:
+ adj = 2;
+ }
+ }
+ days += adj;
+ days -= (weeks*2);
+ }
+ delta = days;
+ break;
+ case "year":
+ delta = yearDiff;
+ break;
+ case "month":
+ delta = (date2.getMonth() - date1.getMonth()) + (yearDiff * 12);
+ break;
+ case "week":
+ // Truncate instead of rounding
+ // Don't use Math.floor -- value may be negative
+ delta = parseInt(dojo.date.difference(date1, date2, "day")/7);
+ break;
+ case "day":
+ delta /= 24;
+ // fallthrough
+ case "hour":
+ delta /= 60;
+ // fallthrough
+ case "minute":
+ delta /= 60;
+ // fallthrough
+ case "second":
+ delta /= 1000;
+ // fallthrough
+ case "millisecond":
+ delta *= date2.getTime() - date1.getTime();
+ }
+
+ // Round for fractional values and DST leaps
+ return Math.round(delta); // Number (integer)
+};
+
+}
diff --git a/includes/js/dojo/date/locale.js b/includes/js/dojo/date/locale.js
new file mode 100644
index 0000000..e72f643
--- /dev/null
+++ b/includes/js/dojo/date/locale.js
@@ -0,0 +1,656 @@
+if(!dojo._hasResource["dojo.date.locale"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.date.locale"] = true;
+dojo.provide("dojo.date.locale");
+
+// Localization methods for Date. Honor local customs using locale-dependent dojo.cldr data.
+
+dojo.require("dojo.date");
+dojo.require("dojo.cldr.supplemental");
+dojo.require("dojo.regexp");
+dojo.require("dojo.string");
+dojo.require("dojo.i18n");
+
+// Load the bundles containing localization information for
+// names and formats
+dojo.requireLocalization("dojo.cldr", "gregorian", null, "zh-cn,zh,en-ca,ko-kr,pt,pt-br,it-it,ROOT,en-gb,de,ja,en,en-au,fr,es,ko,zh-tw,it,es-es");
+
+//NOTE: Everything in this module assumes Gregorian calendars.
+// Other calendars will be implemented in separate modules.
+
+(function(){
+ // Format a pattern without literals
+ function formatPattern(dateObject, bundle, fullYear, pattern){
+ return pattern.replace(/([a-z])\1*/ig, function(match){
+ var s, pad;
+ var c = match.charAt(0);
+ var l = match.length;
+ var widthList = ["abbr", "wide", "narrow"];
+ switch(c){
+ case 'G':
+ s = bundle[(l < 4) ? "eraAbbr" : "eraNames"][dateObject.getFullYear() < 0 ? 0 : 1];
+ break;
+ case 'y':
+ s = dateObject.getFullYear();
+ switch(l){
+ case 1:
+ break;
+ case 2:
+ if(!fullYear){
+ s = String(s); s = s.substr(s.length - 2);
+ break;
+ }
+ // fallthrough
+ default:
+ pad = true;
+ }
+ break;
+ case 'Q':
+ case 'q':
+ s = Math.ceil((dateObject.getMonth()+1)/3);
+// switch(l){
+// case 1: case 2:
+ pad = true;
+// break;
+// case 3: case 4: // unimplemented
+// }
+ break;
+ case 'M':
+ case 'L':
+ var m = dateObject.getMonth();
+ var widthM;
+ switch(l){
+ case 1: case 2:
+ s = m+1; pad = true;
+ break;
+ case 3: case 4: case 5:
+ widthM = widthList[l-3];
+ break;
+ }
+ if(widthM){
+ var typeM = (c == "L") ? "standalone" : "format";
+ var propM = ["months", typeM, widthM].join("-");
+ s = bundle[propM][m];
+ }
+ break;
+ case 'w':
+ var firstDay = 0;
+ s = dojo.date.locale._getWeekOfYear(dateObject, firstDay); pad = true;
+ break;
+ case 'd':
+ s = dateObject.getDate(); pad = true;
+ break;
+ case 'D':
+ s = dojo.date.locale._getDayOfYear(dateObject); pad = true;
+ break;
+ case 'E':
+ case 'e':
+ case 'c': // REVIEW: don't see this in the spec?
+ var d = dateObject.getDay();
+ var widthD;
+ switch(l){
+ case 1: case 2:
+ if(c == 'e'){
+ var first = dojo.cldr.supplemental.getFirstDayOfWeek(options.locale);
+ d = (d-first+7)%7;
+ }
+ if(c != 'c'){
+ s = d+1; pad = true;
+ break;
+ }
+ // else fallthrough...
+ case 3: case 4: case 5:
+ widthD = widthList[l-3];
+ break;
+ }
+ if(widthD){
+ var typeD = (c == "c") ? "standalone" : "format";
+ var propD = ["days", typeD, widthD].join("-");
+ s = bundle[propD][d];
+ }
+ break;
+ case 'a':
+ var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm';
+ s = bundle[timePeriod];
+ break;
+ case 'h':
+ case 'H':
+ case 'K':
+ case 'k':
+ var h = dateObject.getHours();
+ // strange choices in the date format make it impossible to write this succinctly
+ switch (c){
+ case 'h': // 1-12
+ s = (h % 12) || 12;
+ break;
+ case 'H': // 0-23
+ s = h;
+ break;
+ case 'K': // 0-11
+ s = (h % 12);
+ break;
+ case 'k': // 1-24
+ s = h || 24;
+ break;
+ }
+ pad = true;
+ break;
+ case 'm':
+ s = dateObject.getMinutes(); pad = true;
+ break;
+ case 's':
+ s = dateObject.getSeconds(); pad = true;
+ break;
+ case 'S':
+ s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3)); pad = true;
+ break;
+ case 'v': // FIXME: don't know what this is. seems to be same as z?
+ case 'z':
+ // We only have one timezone to offer; the one from the browser
+ s = dojo.date.getTimezoneName(dateObject);
+ if(s){break;}
+ l=4;
+ // fallthrough... use GMT if tz not available
+ case 'Z':
+ var offset = dateObject.getTimezoneOffset();
+ var tz = [
+ (offset<=0 ? "+" : "-"),
+ dojo.string.pad(Math.floor(Math.abs(offset)/60), 2),
+ dojo.string.pad(Math.abs(offset)% 60, 2)
+ ];
+ if(l==4){
+ tz.splice(0, 0, "GMT");
+ tz.splice(3, 0, ":");
+ }
+ s = tz.join("");
+ break;
+// case 'Y': case 'u': case 'W': case 'F': case 'g': case 'A':
+// console.debug(match+" modifier unimplemented");
+ default:
+ throw new Error("dojo.date.locale.format: invalid pattern char: "+pattern);
+ }
+ if(pad){ s = dojo.string.pad(s, l); }
+ return s;
+ });
+ }
+
+/*=====
+ dojo.date.locale.__FormatOptions = function(){
+ // selector: String
+ // choice of 'time','date' (default: date and time)
+ // formatLength: String
+ // choice of long, short, medium or full (plus any custom additions). Defaults to 'short'
+ // datePattern:String
+ // override pattern with this string
+ // timePattern:String
+ // override pattern with this string
+ // am: String
+ // override strings for am in times
+ // pm: String
+ // override strings for pm in times
+ // locale: String
+ // override the locale used to determine formatting rules
+ // fullYear: Boolean
+ // (format only) use 4 digit years whenever 2 digit years are called for
+ // strict: Boolean
+ // (parse only) strict parsing, off by default
+ this.selector = selector;
+ this.formatLength = formatLength;
+ this.datePattern = datePattern;
+ this.timePattern = timePattern;
+ this.am = am;
+ this.pm = pm;
+ this.locale = locale;
+ this.fullYear = fullYear;
+ this.strict = strict;
+ }
+=====*/
+
+dojo.date.locale.format = function(/*Date*/dateObject, /*dojo.date.locale.__FormatOptions?*/options){
+ // summary:
+ // Format a Date object as a String, using locale-specific settings.
+ //
+ // description:
+ // Create a string from a Date object using a known localized pattern.
+ // By default, this method formats both date and time from dateObject.
+ // Formatting patterns are chosen appropriate to the locale. Different
+ // formatting lengths may be chosen, with "full" used by default.
+ // Custom patterns may be used or registered with translations using
+ // the dojo.date.locale.addCustomFormats method.
+ // Formatting patterns are implemented using [the syntax described at
+ // unicode.org](http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns)
+ //
+ // dateObject:
+ // the date and/or time to be formatted. If a time only is formatted,
+ // the values in the year, month, and day fields are irrelevant. The
+ // opposite is true when formatting only dates.
+
+ options = options || {};
+
+ var locale = dojo.i18n.normalizeLocale(options.locale);
+ var formatLength = options.formatLength || 'short';
+ var bundle = dojo.date.locale._getGregorianBundle(locale);
+ var str = [];
+ var sauce = dojo.hitch(this, formatPattern, dateObject, bundle, options.fullYear);
+ if(options.selector == "year"){
+ // Special case as this is not yet driven by CLDR data
+ var year = dateObject.getFullYear();
+ if(locale.match(/^zh|^ja/)){
+ year += "\u5E74";
+ }
+ return year;
+ }
+ if(options.selector != "time"){
+ var datePattern = options.datePattern || bundle["dateFormat-"+formatLength];
+ if(datePattern){str.push(_processPattern(datePattern, sauce));}
+ }
+ if(options.selector != "date"){
+ var timePattern = options.timePattern || bundle["timeFormat-"+formatLength];
+ if(timePattern){str.push(_processPattern(timePattern, sauce));}
+ }
+ var result = str.join(" "); //TODO: use locale-specific pattern to assemble date + time
+ return result; // String
+};
+
+dojo.date.locale.regexp = function(/*dojo.date.locale.__FormatOptions?*/options){
+ // summary:
+ // Builds the regular needed to parse a localized date
+
+ return dojo.date.locale._parseInfo(options).regexp; // String
+};
+
+dojo.date.locale._parseInfo = function(/*dojo.date.locale.__FormatOptions?*/options){
+ options = options || {};
+ var locale = dojo.i18n.normalizeLocale(options.locale);
+ var bundle = dojo.date.locale._getGregorianBundle(locale);
+ var formatLength = options.formatLength || 'short';
+ var datePattern = options.datePattern || bundle["dateFormat-" + formatLength];
+ var timePattern = options.timePattern || bundle["timeFormat-" + formatLength];
+ var pattern;
+ if(options.selector == 'date'){
+ pattern = datePattern;
+ }else if(options.selector == 'time'){
+ pattern = timePattern;
+ }else{
+ pattern = datePattern + ' ' + timePattern; //TODO: use locale-specific pattern to assemble date + time
+ }
+
+ var tokens = [];
+ var re = _processPattern(pattern, dojo.hitch(this, _buildDateTimeRE, tokens, bundle, options));
+ return {regexp: re, tokens: tokens, bundle: bundle};
+};
+
+dojo.date.locale.parse = function(/*String*/value, /*dojo.date.locale.__FormatOptions?*/options){
+ // summary:
+ // Convert a properly formatted string to a primitive Date object,
+ // using locale-specific settings.
+ //
+ // description:
+ // Create a Date object from a string using a known localized pattern.
+ // By default, this method parses looking for both date and time in the string.
+ // Formatting patterns are chosen appropriate to the locale. Different
+ // formatting lengths may be chosen, with "full" used by default.
+ // Custom patterns may be used or registered with translations using
+ // the dojo.date.locale.addCustomFormats method.
+ //
+ // Formatting patterns are implemented using [the syntax described at
+ // unicode.org](http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns)
+ // When two digit years are used, a century is chosen according to a sliding
+ // window of 80 years before and 20 years after present year, for both `yy` and `yyyy` patterns.
+ // year < 100CE requires strict mode.
+ //
+ // value:
+ // A string representation of a date
+
+ var info = dojo.date.locale._parseInfo(options);
+ var tokens = info.tokens, bundle = info.bundle;
+ var re = new RegExp("^" + info.regexp + "$");
+ var match = re.exec(value);
+ if(!match){ return null; } // null
+
+ var widthList = ['abbr', 'wide', 'narrow'];
+ var result = [1970,0,1,0,0,0,0]; // will get converted to a Date at the end
+ var amPm = "";
+ var valid = dojo.every(match, function(v, i){
+ if(!i){return true;}
+ var token=tokens[i-1];
+ var l=token.length;
+ switch(token.charAt(0)){
+ case 'y':
+ if(l != 2 && options.strict){
+ //interpret year literally, so '5' would be 5 A.D.
+ result[0] = v;
+ }else{
+ if(v<100){
+ v = Number(v);
+ //choose century to apply, according to a sliding window
+ //of 80 years before and 20 years after present year
+ var year = '' + new Date().getFullYear();
+ var century = year.substring(0, 2) * 100;
+ var cutoff = Math.min(Number(year.substring(2, 4)) + 20, 99);
+ var num = (v < cutoff) ? century + v : century - 100 + v;
+ result[0] = num;
+ }else{
+ //we expected 2 digits and got more...
+ if(options.strict){
+ return false;
+ }
+ //interpret literally, so '150' would be 150 A.D.
+ //also tolerate '1950', if 'yyyy' input passed to 'yy' format
+ result[0] = v;
+ }
+ }
+ break;
+ case 'M':
+ if(l>2){
+ var months = bundle['months-format-' + widthList[l-3]].concat();
+ if(!options.strict){
+ //Tolerate abbreviating period in month part
+ //Case-insensitive comparison
+ v = v.replace(".","").toLowerCase();
+ months = dojo.map(months, function(s){ return s.replace(".","").toLowerCase(); } );
+ }
+ v = dojo.indexOf(months, v);
+ if(v == -1){
+// console.debug("dojo.date.locale.parse: Could not parse month name: '" + v + "'.");
+ return false;
+ }
+ }else{
+ v--;
+ }
+ result[1] = v;
+ break;
+ case 'E':
+ case 'e':
+ var days = bundle['days-format-' + widthList[l-3]].concat();
+ if(!options.strict){
+ //Case-insensitive comparison
+ v = v.toLowerCase();
+ days = dojo.map(days, function(d){return d.toLowerCase();});
+ }
+ v = dojo.indexOf(days, v);
+ if(v == -1){
+// console.debug("dojo.date.locale.parse: Could not parse weekday name: '" + v + "'.");
+ return false;
+ }
+
+ //TODO: not sure what to actually do with this input,
+ //in terms of setting something on the Date obj...?
+ //without more context, can't affect the actual date
+ //TODO: just validate?
+ break;
+ case 'D':
+ result[1] = 0;
+ // fallthrough...
+ case 'd':
+ result[2] = v;
+ break;
+ case 'a': //am/pm
+ var am = options.am || bundle.am;
+ var pm = options.pm || bundle.pm;
+ if(!options.strict){
+ var period = /\./g;
+ v = v.replace(period,'').toLowerCase();
+ am = am.replace(period,'').toLowerCase();
+ pm = pm.replace(period,'').toLowerCase();
+ }
+ if(options.strict && v != am && v != pm){
+// console.debug("dojo.date.locale.parse: Could not parse am/pm part.");
+ return false;
+ }
+
+ // we might not have seen the hours field yet, so store the state and apply hour change later
+ amPm = (v == pm) ? 'p' : (v == am) ? 'a' : '';
+ break;
+ case 'K': //hour (1-24)
+ if(v == 24){ v = 0; }
+ // fallthrough...
+ case 'h': //hour (1-12)
+ case 'H': //hour (0-23)
+ case 'k': //hour (0-11)
+ //TODO: strict bounds checking, padding
+ if(v > 23){
+// console.debug("dojo.date.locale.parse: Illegal hours value");
+ return false;
+ }
+
+ //in the 12-hour case, adjusting for am/pm requires the 'a' part
+ //which could come before or after the hour, so we will adjust later
+ result[3] = v;
+ break;
+ case 'm': //minutes
+ result[4] = v;
+ break;
+ case 's': //seconds
+ result[5] = v;
+ break;
+ case 'S': //milliseconds
+ result[6] = v;
+// break;
+// case 'w':
+//TODO var firstDay = 0;
+// default:
+//TODO: throw?
+// console.debug("dojo.date.locale.parse: unsupported pattern char=" + token.charAt(0));
+ }
+ return true;
+ });
+
+ var hours = +result[3];
+ if(amPm === 'p' && hours < 12){
+ result[3] = hours + 12; //e.g., 3pm -> 15
+ }else if(amPm === 'a' && hours == 12){
+ result[3] = 0; //12am -> 0
+ }
+
+ //TODO: implement a getWeekday() method in order to test
+ //validity of input strings containing 'EEE' or 'EEEE'...
+
+ var dateObject = new Date(result[0], result[1], result[2], result[3], result[4], result[5], result[6]); // Date
+ if(options.strict){
+ dateObject.setFullYear(result[0]);
+ }
+
+ // Check for overflow. The Date() constructor normalizes things like April 32nd...
+ //TODO: why isn't this done for times as well?
+ var allTokens = tokens.join("");
+ if(!valid ||
+ (allTokens.indexOf('M') != -1 && dateObject.getMonth() != result[1]) ||
+ (allTokens.indexOf('d') != -1 && dateObject.getDate() != result[2])){
+ return null;
+ }
+
+ return dateObject; // Date
+};
+
+function _processPattern(pattern, applyPattern, applyLiteral, applyAll){
+ //summary: Process a pattern with literals in it
+
+ // Break up on single quotes, treat every other one as a literal, except '' which becomes '
+ var identity = function(x){return x;};
+ applyPattern = applyPattern || identity;
+ applyLiteral = applyLiteral || identity;
+ applyAll = applyAll || identity;
+
+ //split on single quotes (which escape literals in date format strings)
+ //but preserve escaped single quotes (e.g., o''clock)
+ var chunks = pattern.match(/(''|[^'])+/g);
+ var literal = false;
+
+ dojo.forEach(chunks, function(chunk, i){
+ if(!chunk){
+ chunks[i]='';
+ }else{
+ chunks[i]=(literal ? applyLiteral : applyPattern)(chunk);
+ literal = !literal;
+ }
+ });
+ return applyAll(chunks.join(''));
+}
+
+function _buildDateTimeRE(tokens, bundle, options, pattern){
+ pattern = dojo.regexp.escapeString(pattern);
+ if(!options.strict){ pattern = pattern.replace(" a", " ?a"); } // kludge to tolerate no space before am/pm
+ return pattern.replace(/([a-z])\1*/ig, function(match){
+ // Build a simple regexp. Avoid captures, which would ruin the tokens list
+ var s;
+ var c = match.charAt(0);
+ var l = match.length;
+ var p2 = '', p3 = '';
+ if(options.strict){
+ if(l > 1){ p2 = '0' + '{'+(l-1)+'}'; }
+ if(l > 2){ p3 = '0' + '{'+(l-2)+'}'; }
+ }else{
+ p2 = '0?'; p3 = '0{0,2}';
+ }
+ switch(c){
+ case 'y':
+ s = '\\d{2,4}';
+ break;
+ case 'M':
+ s = (l>2) ? '\\S+' : p2+'[1-9]|1[0-2]';
+ break;
+ case 'D':
+ s = p2+'[1-9]|'+p3+'[1-9][0-9]|[12][0-9][0-9]|3[0-5][0-9]|36[0-6]';
+ break;
+ case 'd':
+ s = p2+'[1-9]|[12]\\d|3[01]';
+ break;
+ case 'w':
+ s = p2+'[1-9]|[1-4][0-9]|5[0-3]';
+ break;
+ case 'E':
+ s = '\\S+';
+ break;
+ case 'h': //hour (1-12)
+ s = p2+'[1-9]|1[0-2]';
+ break;
+ case 'k': //hour (0-11)
+ s = p2+'\\d|1[01]';
+ break;
+ case 'H': //hour (0-23)
+ s = p2+'\\d|1\\d|2[0-3]';
+ break;
+ case 'K': //hour (1-24)
+ s = p2+'[1-9]|1\\d|2[0-4]';
+ break;
+ case 'm':
+ case 's':
+ s = '[0-5]\\d';
+ break;
+ case 'S':
+ s = '\\d{'+l+'}';
+ break;
+ case 'a':
+ var am = options.am || bundle.am || 'AM';
+ var pm = options.pm || bundle.pm || 'PM';
+ if(options.strict){
+ s = am + '|' + pm;
+ }else{
+ s = am + '|' + pm;
+ if(am != am.toLowerCase()){ s += '|' + am.toLowerCase(); }
+ if(pm != pm.toLowerCase()){ s += '|' + pm.toLowerCase(); }
+ }
+ break;
+ default:
+ // case 'v':
+ // case 'z':
+ // case 'Z':
+ s = ".*";
+// console.debug("parse of date format, pattern=" + pattern);
+ }
+
+ if(tokens){ tokens.push(match); }
+
+ return "(" + s + ")"; // add capture
+ }).replace(/[\xa0 ]/g, "[\\s\\xa0]"); // normalize whitespace. Need explicit handling of \xa0 for IE.
+}
+})();
+
+(function(){
+var _customFormats = [];
+dojo.date.locale.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){
+ // summary:
+ // Add a reference to a bundle containing localized custom formats to be
+ // used by date/time formatting and parsing routines.
+ //
+ // description:
+ // The user may add custom localized formats where the bundle has properties following the
+ // same naming convention used by dojo.cldr: `dateFormat-xxxx` / `timeFormat-xxxx`
+ // The pattern string should match the format used by the CLDR.
+ // See dojo.date.locale.format() for details.
+ // The resources must be loaded by dojo.requireLocalization() prior to use
+
+ _customFormats.push({pkg:packageName,name:bundleName});
+};
+
+dojo.date.locale._getGregorianBundle = function(/*String*/locale){
+ var gregorian = {};
+ dojo.forEach(_customFormats, function(desc){
+ var bundle = dojo.i18n.getLocalization(desc.pkg, desc.name, locale);
+ gregorian = dojo.mixin(gregorian, bundle);
+ }, this);
+ return gregorian; /*Object*/
+};
+})();
+
+dojo.date.locale.addCustomFormats("dojo.cldr","gregorian");
+
+dojo.date.locale.getNames = function(/*String*/item, /*String*/type, /*String?*/use, /*String?*/locale){
+ // summary:
+ // Used to get localized strings from dojo.cldr for day or month names.
+ //
+ // item:
+ // 'months' || 'days'
+ // type:
+ // 'wide' || 'narrow' || 'abbr' (e.g. "Monday", "Mon", or "M" respectively, in English)
+ // use:
+ // 'standAlone' || 'format' (default)
+ // locale:
+ // override locale used to find the names
+
+ var label;
+ var lookup = dojo.date.locale._getGregorianBundle(locale);
+ var props = [item, use, type];
+ if(use == 'standAlone'){
+ label = lookup[props.join('-')];
+ }
+ props[1] = 'format';
+
+ // return by copy so changes won't be made accidentally to the in-memory model
+ return (label || lookup[props.join('-')]).concat(); /*Array*/
+};
+
+dojo.date.locale.isWeekend = function(/*Date?*/dateObject, /*String?*/locale){
+ // summary:
+ // Determines if the date falls on a weekend, according to local custom.
+
+ var weekend = dojo.cldr.supplemental.getWeekend(locale);
+ var day = (dateObject || new Date()).getDay();
+ if(weekend.end < weekend.start){
+ weekend.end += 7;
+ if(day < weekend.start){ day += 7; }
+ }
+ return day >= weekend.start && day <= weekend.end; // Boolean
+};
+
+// These are used only by format and strftime. Do they need to be public? Which module should they go in?
+
+dojo.date.locale._getDayOfYear = function(/*Date*/dateObject){
+ // summary: gets the day of the year as represented by dateObject
+ return dojo.date.difference(new Date(dateObject.getFullYear(), 0, 1), dateObject) + 1; // Number
+};
+
+dojo.date.locale._getWeekOfYear = function(/*Date*/dateObject, /*Number*/firstDayOfWeek){
+ if(arguments.length == 1){ firstDayOfWeek = 0; } // Sunday
+
+ var firstDayOfYear = new Date(dateObject.getFullYear(), 0, 1).getDay();
+ var adj = (firstDayOfYear - firstDayOfWeek + 7) % 7;
+ var week = Math.floor((dojo.date.locale._getDayOfYear(dateObject) + adj - 1) / 7);
+
+ // if year starts on the specified day, start counting weeks at 1
+ if(firstDayOfYear == firstDayOfWeek){ week++; }
+
+ return week; // Number
+};
+
+}
diff --git a/includes/js/dojo/date/stamp.js b/includes/js/dojo/date/stamp.js
new file mode 100644
index 0000000..5ac978f
--- /dev/null
+++ b/includes/js/dojo/date/stamp.js
@@ -0,0 +1,141 @@
+if(!dojo._hasResource["dojo.date.stamp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.date.stamp"] = true;
+dojo.provide("dojo.date.stamp");
+
+// Methods to convert dates to or from a wire (string) format using well-known conventions
+
+dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){
+ // summary:
+ // Returns a Date object given a string formatted according to a subset of the ISO-8601 standard.
+ //
+ // description:
+ // Accepts a string formatted according to a profile of ISO8601 as defined by
+ // [RFC3339](http://www.ietf.org/rfc/rfc3339.txt), except that partial input is allowed.
+ // Can also process dates as specified [by the W3C](http://www.w3.org/TR/NOTE-datetime)
+ // The following combinations are valid:
+ //
+ // * dates only
+ // | * yyyy
+ // | * yyyy-MM
+ // | * yyyy-MM-dd
+ // * times only, with an optional time zone appended
+ // | * THH:mm
+ // | * THH:mm:ss
+ // | * THH:mm:ss.SSS
+ // * and "datetimes" which could be any combination of the above
+ //
+ // timezones may be specified as Z (for UTC) or +/- followed by a time expression HH:mm
+ // Assumes the local time zone if not specified. Does not validate. Improperly formatted
+ // input may return null. Arguments which are out of bounds will be handled
+ // by the Date constructor (e.g. January 32nd typically gets resolved to February 1st)
+ // Only years between 100 and 9999 are supported.
+ //
+ // formattedString:
+ // A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00
+ //
+ // defaultTime:
+ // Used for defaults for fields omitted in the formattedString.
+ // Uses 1970-01-01T00:00:00.0Z by default.
+
+ if(!dojo.date.stamp._isoRegExp){
+ dojo.date.stamp._isoRegExp =
+//TODO: could be more restrictive and check for 00-59, etc.
+ /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/;
+ }
+
+ var match = dojo.date.stamp._isoRegExp.exec(formattedString);
+ var result = null;
+
+ if(match){
+ match.shift();
+ if(match[1]){match[1]--;} // Javascript Date months are 0-based
+ if(match[6]){match[6] *= 1000;} // Javascript Date expects fractional seconds as milliseconds
+
+ if(defaultTime){
+ // mix in defaultTime. Relatively expensive, so use || operators for the fast path of defaultTime === 0
+ defaultTime = new Date(defaultTime);
+ dojo.map(["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"], function(prop){
+ return defaultTime["get" + prop]();
+ }).forEach(function(value, index){
+ if(match[index] === undefined){
+ match[index] = value;
+ }
+ });
+ }
+ result = new Date(match[0]||1970, match[1]||0, match[2]||1, match[3]||0, match[4]||0, match[5]||0, match[6]||0);
+// result.setFullYear(match[0]||1970); // for year < 100
+
+ var offset = 0;
+ var zoneSign = match[7] && match[7].charAt(0);
+ if(zoneSign != 'Z'){
+ offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0);
+ if(zoneSign != '-'){ offset *= -1; }
+ }
+ if(zoneSign){
+ offset -= result.getTimezoneOffset();
+ }
+ if(offset){
+ result.setTime(result.getTime() + offset * 60000);
+ }
+ }
+
+ return result; // Date or null
+}
+
+/*=====
+ dojo.date.stamp.__Options = function(){
+ // selector: String
+ // "date" or "time" for partial formatting of the Date object.
+ // Both date and time will be formatted by default.
+ // zulu: Boolean
+ // if true, UTC/GMT is used for a timezone
+ // milliseconds: Boolean
+ // if true, output milliseconds
+ this.selector = selector;
+ this.zulu = zulu;
+ this.milliseconds = milliseconds;
+ }
+=====*/
+
+dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*dojo.date.stamp.__Options?*/options){
+ // summary:
+ // Format a Date object as a string according a subset of the ISO-8601 standard
+ //
+ // description:
+ // When options.selector is omitted, output follows [RFC3339](http://www.ietf.org/rfc/rfc3339.txt)
+ // The local time zone is included as an offset from GMT, except when selector=='time' (time without a date)
+ // Does not check bounds. Only years between 100 and 9999 are supported.
+ //
+ // dateObject:
+ // A Date object
+
+ var _ = function(n){ return (n < 10) ? "0" + n : n; };
+ options = options || {};
+ var formattedDate = [];
+ var getter = options.zulu ? "getUTC" : "get";
+ var date = "";
+ if(options.selector != "time"){
+ var year = dateObject[getter+"FullYear"]();
+ date = ["0000".substr((year+"").length)+year, _(dateObject[getter+"Month"]()+1), _(dateObject[getter+"Date"]())].join('-');
+ }
+ formattedDate.push(date);
+ if(options.selector != "date"){
+ var time = [_(dateObject[getter+"Hours"]()), _(dateObject[getter+"Minutes"]()), _(dateObject[getter+"Seconds"]())].join(':');
+ var millis = dateObject[getter+"Milliseconds"]();
+ if(options.milliseconds){
+ time += "."+ (millis < 100 ? "0" : "") + _(millis);
+ }
+ if(options.zulu){
+ time += "Z";
+ }else if(options.selector != "time"){
+ var timezoneOffset = dateObject.getTimezoneOffset();
+ var absOffset = Math.abs(timezoneOffset);
+ time += (timezoneOffset > 0 ? "-" : "+") +
+ _(Math.floor(absOffset/60)) + ":" + _(absOffset%60);
+ }
+ formattedDate.push(time);
+ }
+ return formattedDate.join('T'); // String
+}
+
+}
diff --git a/includes/js/dojo/dnd/Avatar.js b/includes/js/dojo/dnd/Avatar.js
new file mode 100644
index 0000000..33ccb07
--- /dev/null
+++ b/includes/js/dojo/dnd/Avatar.js
@@ -0,0 +1,82 @@
+if(!dojo._hasResource["dojo.dnd.Avatar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Avatar"] = true;
+dojo.provide("dojo.dnd.Avatar");
+
+dojo.require("dojo.dnd.common");
+
+dojo.declare("dojo.dnd.Avatar", null, {
+ // summary: an object, which represents transferred DnD items visually
+ // manager: Object: a DnD manager object
+
+ constructor: function(manager){
+ this.manager = manager;
+ this.construct();
+ },
+
+ // methods
+ construct: function(){
+ // summary: a constructor function;
+ // it is separate so it can be (dynamically) overwritten in case of need
+ var a = dojo.doc.createElement("table");
+ a.className = "dojoDndAvatar";
+ a.style.position = "absolute";
+ a.style.zIndex = 1999;
+ a.style.margin = "0px"; // to avoid dojo.marginBox() problems with table's margins
+ var b = dojo.doc.createElement("tbody");
+ var tr = dojo.doc.createElement("tr");
+ tr.className = "dojoDndAvatarHeader";
+ var td = dojo.doc.createElement("td");
+ td.innerHTML = this._generateText();
+ tr.appendChild(td);
+ dojo.style(tr, "opacity", 0.9);
+ b.appendChild(tr);
+ var k = Math.min(5, this.manager.nodes.length);
+ var source = this.manager.source;
+ for(var i = 0; i < k; ++i){
+ tr = dojo.doc.createElement("tr");
+ tr.className = "dojoDndAvatarItem";
+ td = dojo.doc.createElement("td");
+ if(source.creator){
+ // create an avatar representation of the node
+ node = source._normalizedCreator(source.getItem(this.manager.nodes[i].id).data, "avatar").node;
+ }else{
+ // or just clone the node and hope it works
+ node = this.manager.nodes[i].cloneNode(true);
+ if(node.tagName.toLowerCase() == "tr"){
+ // insert extra table nodes
+ var table = dojo.doc.createElement("table"),
+ tbody = dojo.doc.createElement("tbody");
+ tbody.appendChild(node);
+ table.appendChild(tbody);
+ node = table;
+ }
+ }
+ node.id = "";
+ td.appendChild(node);
+ tr.appendChild(td);
+ dojo.style(tr, "opacity", (9 - i) / 10);
+ b.appendChild(tr);
+ }
+ a.appendChild(b);
+ this.node = a;
+ },
+ destroy: function(){
+ // summary: a desctructor for the avatar, called to remove all references so it can be garbage-collected
+ dojo._destroyElement(this.node);
+ this.node = false;
+ },
+ update: function(){
+ // summary: updates the avatar to reflect the current DnD state
+ dojo[(this.manager.canDropFlag ? "add" : "remove") + "Class"](this.node, "dojoDndAvatarCanDrop");
+ // replace text
+ dojo.query("tr.dojoDndAvatarHeader td").forEach(function(node){
+ node.innerHTML = this._generateText();
+ }, this);
+ },
+ _generateText: function(){
+ // summary: generates a proper text to reflect copying or moving of items
+ return this.manager.nodes.length.toString();
+ }
+});
+
+}
diff --git a/includes/js/dojo/dnd/Container.js b/includes/js/dojo/dnd/Container.js
new file mode 100644
index 0000000..92b3211
--- /dev/null
+++ b/includes/js/dojo/dnd/Container.js
@@ -0,0 +1,311 @@
+if(!dojo._hasResource["dojo.dnd.Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Container"] = true;
+dojo.provide("dojo.dnd.Container");
+
+dojo.require("dojo.dnd.common");
+dojo.require("dojo.parser");
+
+/*
+ Container states:
+ "" - normal state
+ "Over" - mouse over a container
+ Container item states:
+ "" - normal state
+ "Over" - mouse over a container item
+*/
+
+dojo.declare("dojo.dnd.Container", null, {
+ // summary: a Container object, which knows when mouse hovers over it,
+ // and know over which element it hovers
+
+ // object attributes (for markup)
+ skipForm: false,
+
+ constructor: function(node, params){
+ // summary: a constructor of the Container
+ // node: Node: node or node's id to build the container on
+ // params: Object: a dict of parameters, recognized parameters are:
+ // creator: Function: a creator function, which takes a data item, and returns an object like that:
+ // {node: newNode, data: usedData, type: arrayOfStrings}
+ // skipForm: Boolean: don't start the drag operation, if clicked on form elements
+ // _skipStartup: Boolean: skip startup(), which collects children, for deferred initialization
+ // (this is used in the markup mode)
+ this.node = dojo.byId(node);
+ if(!params){ params = {}; }
+ this.creator = params.creator || null;
+ this.skipForm = params.skipForm;
+ this.defaultCreator = dojo.dnd._defaultCreator(this.node);
+
+ // class-specific variables
+ this.map = {};
+ this.current = null;
+
+ // states
+ this.containerState = "";
+ dojo.addClass(this.node, "dojoDndContainer");
+
+ // mark up children
+ if(!(params && params._skipStartup)){
+ this.startup();
+ }
+
+ // set up events
+ this.events = [
+ dojo.connect(this.node, "onmouseover", this, "onMouseOver"),
+ dojo.connect(this.node, "onmouseout", this, "onMouseOut"),
+ // cancel text selection and text dragging
+ dojo.connect(this.node, "ondragstart", this, "onSelectStart"),
+ dojo.connect(this.node, "onselectstart", this, "onSelectStart")
+ ];
+ },
+
+ // object attributes (for markup)
+ creator: function(){}, // creator function, dummy at the moment
+
+ // abstract access to the map
+ getItem: function(/*String*/ key){
+ // summary: returns a data item by its key (id)
+ return this.map[key]; // Object
+ },
+ setItem: function(/*String*/ key, /*Object*/ data){
+ // summary: associates a data item with its key (id)
+ this.map[key] = data;
+ },
+ delItem: function(/*String*/ key){
+ // summary: removes a data item from the map by its key (id)
+ delete this.map[key];
+ },
+ forInItems: function(/*Function*/ f, /*Object?*/ o){
+ // summary: iterates over a data map skipping members, which
+ // are present in the empty object (IE and/or 3rd-party libraries).
+ o = o || dojo.global;
+ var m = this.map, e = dojo.dnd._empty;
+ for(var i in this.map){
+ if(i in e){ continue; }
+ f.call(o, m[i], i, m);
+ }
+ },
+ clearItems: function(){
+ // summary: removes all data items from the map
+ this.map = {};
+ },
+
+ // methods
+ getAllNodes: function(){
+ // summary: returns a list (an array) of all valid child nodes
+ return dojo.query("> .dojoDndItem", this.parent); // NodeList
+ },
+ insertNodes: function(data, before, anchor){
+ // summary: inserts an array of new nodes before/after an anchor node
+ // data: Array: a list of data items, which should be processed by the creator function
+ // before: Boolean: insert before the anchor, if true, and after the anchor otherwise
+ // anchor: Node: the anchor node to be used as a point of insertion
+ if(!this.parent.firstChild){
+ anchor = null;
+ }else if(before){
+ if(!anchor){
+ anchor = this.parent.firstChild;
+ }
+ }else{
+ if(anchor){
+ anchor = anchor.nextSibling;
+ }
+ }
+ if(anchor){
+ for(var i = 0; i < data.length; ++i){
+ var t = this._normalizedCreator(data[i]);
+ this.setItem(t.node.id, {data: t.data, type: t.type});
+ this.parent.insertBefore(t.node, anchor);
+ }
+ }else{
+ for(var i = 0; i < data.length; ++i){
+ var t = this._normalizedCreator(data[i]);
+ this.setItem(t.node.id, {data: t.data, type: t.type});
+ this.parent.appendChild(t.node);
+ }
+ }
+ return this; // self
+ },
+ destroy: function(){
+ // summary: prepares the object to be garbage-collected
+ dojo.forEach(this.events, dojo.disconnect);
+ this.clearItems();
+ this.node = this.parent = this.current;
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ params._skipStartup = true;
+ return new dojo.dnd.Container(node, params);
+ },
+ startup: function(){
+ // summary: collects valid child items and populate the map
+
+ // set up the real parent node
+ this.parent = this.node;
+ if(this.parent.tagName.toLowerCase() == "table"){
+ var c = this.parent.getElementsByTagName("tbody");
+ if(c && c.length){ this.parent = c[0]; }
+ }
+
+ // process specially marked children
+ this.getAllNodes().forEach(function(node){
+ if(!node.id){ node.id = dojo.dnd.getUniqueId(); }
+ var type = node.getAttribute("dndType"),
+ data = node.getAttribute("dndData");
+ this.setItem(node.id, {
+ data: data ? data : node.innerHTML,
+ type: type ? type.split(/\s*,\s*/) : ["text"]
+ });
+ }, this);
+ },
+
+ // mouse events
+ onMouseOver: function(e){
+ // summary: event processor for onmouseover
+ // e: Event: mouse event
+ var n = e.relatedTarget;
+ while(n){
+ if(n == this.node){ break; }
+ try{
+ n = n.parentNode;
+ }catch(x){
+ n = null;
+ }
+ }
+ if(!n){
+ this._changeState("Container", "Over");
+ this.onOverEvent();
+ }
+ n = this._getChildByEvent(e);
+ if(this.current == n){ return; }
+ if(this.current){ this._removeItemClass(this.current, "Over"); }
+ if(n){ this._addItemClass(n, "Over"); }
+ this.current = n;
+ },
+ onMouseOut: function(e){
+ // summary: event processor for onmouseout
+ // e: Event: mouse event
+ for(var n = e.relatedTarget; n;){
+ if(n == this.node){ return; }
+ try{
+ n = n.parentNode;
+ }catch(x){
+ n = null;
+ }
+ }
+ if(this.current){
+ this._removeItemClass(this.current, "Over");
+ this.current = null;
+ }
+ this._changeState("Container", "");
+ this.onOutEvent();
+ },
+ onSelectStart: function(e){
+ // summary: event processor for onselectevent and ondragevent
+ // e: Event: mouse event
+ if(!this.skipForm || !dojo.dnd.isFormElement(e)){
+ dojo.stopEvent(e);
+ }
+ },
+
+ // utilities
+ onOverEvent: function(){
+ // summary: this function is called once, when mouse is over our container
+ },
+ onOutEvent: function(){
+ // summary: this function is called once, when mouse is out of our container
+ },
+ _changeState: function(type, newState){
+ // summary: changes a named state to new state value
+ // type: String: a name of the state to change
+ // newState: String: new state
+ var prefix = "dojoDnd" + type;
+ var state = type.toLowerCase() + "State";
+ //dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
+ dojo.removeClass(this.node, prefix + this[state]);
+ dojo.addClass(this.node, prefix + newState);
+ this[state] = newState;
+ },
+ _addItemClass: function(node, type){
+ // summary: adds a class with prefix "dojoDndItem"
+ // node: Node: a node
+ // type: String: a variable suffix for a class name
+ dojo.addClass(node, "dojoDndItem" + type);
+ },
+ _removeItemClass: function(node, type){
+ // summary: removes a class with prefix "dojoDndItem"
+ // node: Node: a node
+ // type: String: a variable suffix for a class name
+ dojo.removeClass(node, "dojoDndItem" + type);
+ },
+ _getChildByEvent: function(e){
+ // summary: gets a child, which is under the mouse at the moment, or null
+ // e: Event: a mouse event
+ var node = e.target;
+ if(node){
+ for(var parent = node.parentNode; parent; node = parent, parent = node.parentNode){
+ if(parent == this.parent && dojo.hasClass(node, "dojoDndItem")){ return node; }
+ }
+ }
+ return null;
+ },
+ _normalizedCreator: function(item, hint){
+ // summary: adds all necessary data to the output of the user-supplied creator function
+ var t = (this.creator ? this.creator : this.defaultCreator)(item, hint);
+ if(!dojo.isArray(t.type)){ t.type = ["text"]; }
+ if(!t.node.id){ t.node.id = dojo.dnd.getUniqueId(); }
+ dojo.addClass(t.node, "dojoDndItem");
+ return t;
+ }
+});
+
+dojo.dnd._createNode = function(tag){
+ // summary: returns a function, which creates an element of given tag
+ // (SPAN by default) and sets its innerHTML to given text
+ // tag: String: a tag name or empty for SPAN
+ if(!tag){ return dojo.dnd._createSpan; }
+ return function(text){ // Function
+ var n = dojo.doc.createElement(tag);
+ n.innerHTML = text;
+ return n;
+ };
+};
+
+dojo.dnd._createTrTd = function(text){
+ // summary: creates a TR/TD structure with given text as an innerHTML of TD
+ // text: String: a text for TD
+ var tr = dojo.doc.createElement("tr");
+ var td = dojo.doc.createElement("td");
+ td.innerHTML = text;
+ tr.appendChild(td);
+ return tr; // Node
+};
+
+dojo.dnd._createSpan = function(text){
+ // summary: creates a SPAN element with given text as its innerHTML
+ // text: String: a text for SPAN
+ var n = dojo.doc.createElement("span");
+ n.innerHTML = text;
+ return n; // Node
+};
+
+// dojo.dnd._defaultCreatorNodes: Object: a dicitionary, which maps container tag names to child tag names
+dojo.dnd._defaultCreatorNodes = {ul: "li", ol: "li", div: "div", p: "div"};
+
+dojo.dnd._defaultCreator = function(node){
+ // summary: takes a container node, and returns an appropriate creator function
+ // node: Node: a container node
+ var tag = node.tagName.toLowerCase();
+ var c = tag == "table" ? dojo.dnd._createTrTd : dojo.dnd._createNode(dojo.dnd._defaultCreatorNodes[tag]);
+ return function(item, hint){ // Function
+ var isObj = dojo.isObject(item) && item;
+ var data = (isObj && item.data) ? item.data : item;
+ var type = (isObj && item.type) ? item.type : ["text"];
+ var t = String(data), n = (hint == "avatar" ? dojo.dnd._createSpan : c)(t);
+ n.id = dojo.dnd.getUniqueId();
+ return {node: n, data: data, type: type};
+ };
+};
+
+}
diff --git a/includes/js/dojo/dnd/Manager.js b/includes/js/dojo/dnd/Manager.js
new file mode 100644
index 0000000..8044b42
--- /dev/null
+++ b/includes/js/dojo/dnd/Manager.js
@@ -0,0 +1,180 @@
+if(!dojo._hasResource["dojo.dnd.Manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Manager"] = true;
+dojo.provide("dojo.dnd.Manager");
+
+dojo.require("dojo.dnd.common");
+dojo.require("dojo.dnd.autoscroll");
+dojo.require("dojo.dnd.Avatar");
+
+dojo.declare("dojo.dnd.Manager", null, {
+ // summary: the manager of DnD operations (usually a singleton)
+ constructor: function(){
+ this.avatar = null;
+ this.source = null;
+ this.nodes = [];
+ this.copy = true;
+ this.target = null;
+ this.canDropFlag = false;
+ this.events = [];
+ },
+
+ // avatar's offset from the mouse
+ OFFSET_X: 16,
+ OFFSET_Y: 16,
+
+ // methods
+ overSource: function(source){
+ // summary: called when a source detected a mouse-over conditiion
+ // source: Object: the reporter
+ if(this.avatar){
+ this.target = (source && source.targetState != "Disabled") ? source : null;
+ this.avatar.update();
+ }
+ dojo.publish("/dnd/source/over", [source]);
+ },
+ outSource: function(source){
+ // summary: called when a source detected a mouse-out conditiion
+ // source: Object: the reporter
+ if(this.avatar){
+ if(this.target == source){
+ this.target = null;
+ this.canDropFlag = false;
+ this.avatar.update();
+ dojo.publish("/dnd/source/over", [null]);
+ }
+ }else{
+ dojo.publish("/dnd/source/over", [null]);
+ }
+ },
+ startDrag: function(source, nodes, copy){
+ // summary: called to initiate the DnD operation
+ // source: Object: the source which provides items
+ // nodes: Array: the list of transferred items
+ // copy: Boolean: copy items, if true, move items otherwise
+ this.source = source;
+ this.nodes = nodes;
+ this.copy = Boolean(copy); // normalizing to true boolean
+ this.avatar = this.makeAvatar();
+ dojo.body().appendChild(this.avatar.node);
+ dojo.publish("/dnd/start", [source, nodes, this.copy]);
+ this.events = [
+ dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"),
+ dojo.connect(dojo.doc, "onmouseup", this, "onMouseUp"),
+ dojo.connect(dojo.doc, "onkeydown", this, "onKeyDown"),
+ dojo.connect(dojo.doc, "onkeyup", this, "onKeyUp")
+ ];
+ var c = "dojoDnd" + (copy ? "Copy" : "Move");
+ dojo.addClass(dojo.body(), c);
+ },
+ canDrop: function(flag){
+ // summary: called to notify if the current target can accept items
+ var canDropFlag = Boolean(this.target && flag);
+ if(this.canDropFlag != canDropFlag){
+ this.canDropFlag = canDropFlag;
+ this.avatar.update();
+ }
+ },
+ stopDrag: function(){
+ // summary: stop the DnD in progress
+ dojo.removeClass(dojo.body(), "dojoDndCopy");
+ dojo.removeClass(dojo.body(), "dojoDndMove");
+ dojo.forEach(this.events, dojo.disconnect);
+ this.events = [];
+ this.avatar.destroy();
+ this.avatar = null;
+ this.source = null;
+ this.nodes = [];
+ },
+ makeAvatar: function(){
+ // summary: makes the avatar, it is separate to be overwritten dynamically, if needed
+ return new dojo.dnd.Avatar(this);
+ },
+ updateAvatar: function(){
+ // summary: updates the avatar, it is separate to be overwritten dynamically, if needed
+ this.avatar.update();
+ },
+ // mouse event processors
+ onMouseMove: function(e){
+ // summary: event processor for onmousemove
+ // e: Event: mouse event
+ var a = this.avatar;
+ if(a){
+ //dojo.dnd.autoScrollNodes(e);
+ dojo.dnd.autoScroll(e);
+ var s = a.node.style;
+ s.left = (e.pageX + this.OFFSET_X) + "px";
+ s.top = (e.pageY + this.OFFSET_Y) + "px";
+ var copy = Boolean(this.source.copyState(dojo.dnd.getCopyKeyState(e)));
+ if(this.copy != copy){
+ this._setCopyStatus(copy);
+ }
+ }
+ },
+ onMouseUp: function(e){
+ // summary: event processor for onmouseup
+ // e: Event: mouse event
+ if(this.avatar && (!("mouseButton" in this.source) || this.source.mouseButton == e.button)){
+ if(this.target && this.canDropFlag){
+ var params = [this.source, this.nodes, Boolean(this.source.copyState(dojo.dnd.getCopyKeyState(e))), this.target];
+ dojo.publish("/dnd/drop/before", params);
+ dojo.publish("/dnd/drop", params);
+ }else{
+ dojo.publish("/dnd/cancel");
+ }
+ this.stopDrag();
+ }
+ },
+ // keyboard event processors
+ onKeyDown: function(e){
+ // summary: event processor for onkeydown:
+ // watching for CTRL for copy/move status, watching for ESCAPE to cancel the drag
+ // e: Event: keyboard event
+ if(this.avatar){
+ switch(e.keyCode){
+ case dojo.keys.CTRL:
+ var copy = Boolean(this.source.copyState(true));
+ if(this.copy != copy){
+ this._setCopyStatus(copy);
+ }
+ break;
+ case dojo.keys.ESCAPE:
+ dojo.publish("/dnd/cancel");
+ this.stopDrag();
+ break;
+ }
+ }
+ },
+ onKeyUp: function(e){
+ // summary: event processor for onkeyup, watching for CTRL for copy/move status
+ // e: Event: keyboard event
+ if(this.avatar && e.keyCode == dojo.keys.CTRL){
+ var copy = Boolean(this.source.copyState(false));
+ if(this.copy != copy){
+ this._setCopyStatus(copy);
+ }
+ }
+ },
+ // utilities
+ _setCopyStatus: function(copy){
+ // summary: changes the copy status
+ // copy: Boolean: the copy status
+ this.copy = copy;
+ this.source._markDndStatus(this.copy);
+ this.updateAvatar();
+ dojo.removeClass(dojo.body(), "dojoDnd" + (this.copy ? "Move" : "Copy"));
+ dojo.addClass(dojo.body(), "dojoDnd" + (this.copy ? "Copy" : "Move"));
+ }
+});
+
+// summary: the manager singleton variable, can be overwritten, if needed
+dojo.dnd._manager = null;
+
+dojo.dnd.manager = function(){
+ // summary: returns the current DnD manager, creates one if it is not created yet
+ if(!dojo.dnd._manager){
+ dojo.dnd._manager = new dojo.dnd.Manager();
+ }
+ return dojo.dnd._manager; // Object
+};
+
+}
diff --git a/includes/js/dojo/dnd/Moveable.js b/includes/js/dojo/dnd/Moveable.js
new file mode 100644
index 0000000..e9fd805
--- /dev/null
+++ b/includes/js/dojo/dnd/Moveable.js
@@ -0,0 +1,130 @@
+if(!dojo._hasResource["dojo.dnd.Moveable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Moveable"] = true;
+dojo.provide("dojo.dnd.Moveable");
+
+dojo.require("dojo.dnd.Mover");
+
+dojo.declare("dojo.dnd.Moveable", null, {
+ // object attributes (for markup)
+ handle: "",
+ delay: 0,
+ skip: false,
+
+ constructor: function(node, params){
+ // summary: an object, which makes a node moveable
+ // node: Node: a node (or node's id) to be moved
+ // params: Object: an optional object with additional parameters;
+ // following parameters are recognized:
+ // handle: Node: a node (or node's id), which is used as a mouse handle
+ // if omitted, the node itself is used as a handle
+ // delay: Number: delay move by this number of pixels
+ // skip: Boolean: skip move of form elements
+ // mover: Object: a constructor of custom Mover
+ this.node = dojo.byId(node);
+ if(!params){ params = {}; }
+ this.handle = params.handle ? dojo.byId(params.handle) : null;
+ if(!this.handle){ this.handle = this.node; }
+ this.delay = params.delay > 0 ? params.delay : 0;
+ this.skip = params.skip;
+ this.mover = params.mover ? params.mover : dojo.dnd.Mover;
+ this.events = [
+ dojo.connect(this.handle, "onmousedown", this, "onMouseDown"),
+ // cancel text selection and text dragging
+ dojo.connect(this.handle, "ondragstart", this, "onSelectStart"),
+ dojo.connect(this.handle, "onselectstart", this, "onSelectStart")
+ ];
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.Moveable(node, params);
+ },
+
+ // methods
+ destroy: function(){
+ // summary: stops watching for possible move, deletes all references, so the object can be garbage-collected
+ dojo.forEach(this.events, dojo.disconnect);
+ this.events = this.node = this.handle = null;
+ },
+
+ // mouse event processors
+ onMouseDown: function(e){
+ // summary: event processor for onmousedown, creates a Mover for the node
+ // e: Event: mouse event
+ if(this.skip && dojo.dnd.isFormElement(e)){ return; }
+ if(this.delay){
+ this.events.push(dojo.connect(this.handle, "onmousemove", this, "onMouseMove"));
+ this.events.push(dojo.connect(this.handle, "onmouseup", this, "onMouseUp"));
+ this._lastX = e.pageX;
+ this._lastY = e.pageY;
+ }else{
+ new this.mover(this.node, 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.pageX - this._lastX) > this.delay || Math.abs(e.pageY - this._lastY) > this.delay){
+ this.onMouseUp(e);
+ new this.mover(this.node, e, this);
+ }
+ dojo.stopEvent(e);
+ },
+ onMouseUp: function(e){
+ // summary: event processor for onmouseup, used only for delayed delayed drags
+ // e: Event: mouse event
+ dojo.disconnect(this.events.pop());
+ dojo.disconnect(this.events.pop());
+ },
+ onSelectStart: function(e){
+ // summary: event processor for onselectevent and ondragevent
+ // e: Event: mouse event
+ if(!this.skip || !dojo.dnd.isFormElement(e)){
+ dojo.stopEvent(e);
+ }
+ },
+
+ // local events
+ onMoveStart: function(/* dojo.dnd.Mover */ mover){
+ // summary: called before every move operation
+ dojo.publish("/dnd/move/start", [mover]);
+ dojo.addClass(dojo.body(), "dojoMove");
+ dojo.addClass(this.node, "dojoMoveItem");
+ },
+ onMoveStop: function(/* dojo.dnd.Mover */ mover){
+ // summary: called after every move operation
+ dojo.publish("/dnd/move/stop", [mover]);
+ dojo.removeClass(dojo.body(), "dojoMove");
+ dojo.removeClass(this.node, "dojoMoveItem");
+ },
+ onFirstMove: function(/* dojo.dnd.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(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ // summary: called during every move notification,
+ // should actually move the node, can be overwritten.
+ this.onMoving(mover, leftTop);
+ var s = mover.node.style;
+ s.left = leftTop.l + "px";
+ s.top = leftTop.t + "px";
+ this.onMoved(mover, leftTop);
+ },
+ onMoving: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ // summary: called before every incremental move,
+ // can be overwritten.
+
+ // default implementation does nothing
+ },
+ onMoved: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ // summary: called after every incremental move,
+ // can be overwritten.
+
+ // default implementation does nothing
+ }
+});
+
+}
diff --git a/includes/js/dojo/dnd/Mover.js b/includes/js/dojo/dnd/Mover.js
new file mode 100644
index 0000000..94f84f1
--- /dev/null
+++ b/includes/js/dojo/dnd/Mover.js
@@ -0,0 +1,84 @@
+if(!dojo._hasResource["dojo.dnd.Mover"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Mover"] = true;
+dojo.provide("dojo.dnd.Mover");
+
+dojo.require("dojo.dnd.common");
+dojo.require("dojo.dnd.autoscroll");
+
+dojo.declare("dojo.dnd.Mover", null, {
+ constructor: function(node, e, host){
+ // summary: an object, which makes a node follow the mouse,
+ // used as a default mover, and as a base class for custom movers
+ // node: Node: a node (or node's id) to be moved
+ // e: Event: a mouse event, which started the move;
+ // only pageX and pageY properties are used
+ // host: Object?: object which implements the functionality of the move,
+ // and defines proper events (onMoveStart and onMoveStop)
+ this.node = dojo.byId(node);
+ this.marginBox = {l: e.pageX, t: e.pageY};
+ this.mouseButton = e.button;
+ var h = this.host = host, d = node.ownerDocument,
+ firstEvent = dojo.connect(d, "onmousemove", this, "onFirstMove");
+ this.events = [
+ dojo.connect(d, "onmousemove", this, "onMouseMove"),
+ dojo.connect(d, "onmouseup", this, "onMouseUp"),
+ // 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
+ dojo.dnd.autoScroll(e);
+ var m = this.marginBox;
+ this.host.onMove(this, {l: m.l + e.pageX, t: m.t + e.pageY});
+ },
+ onMouseUp: function(e){
+ if(this.mouseButton == e.button){
+ this.destroy();
+ }
+ },
+ // utilities
+ onFirstMove: function(){
+ // summary: makes the node absolute; it is meant to be called only once
+ var s = this.node.style, l, t;
+ switch(s.position){
+ case "relative":
+ case "absolute":
+ // assume that left and top values are in pixels already
+ l = Math.round(parseFloat(s.left));
+ t = Math.round(parseFloat(s.top));
+ break;
+ default:
+ s.position = "absolute"; // enforcing the absolute mode
+ var m = dojo.marginBox(this.node);
+ l = m.l;
+ t = m.t;
+ break;
+ }
+ this.marginBox.l = l - this.marginBox.l;
+ this.marginBox.t = t - this.marginBox.t;
+ 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.node = null;
+ }
+});
+
+}
diff --git a/includes/js/dojo/dnd/Selector.js b/includes/js/dojo/dnd/Selector.js
new file mode 100644
index 0000000..f942e7e
--- /dev/null
+++ b/includes/js/dojo/dnd/Selector.js
@@ -0,0 +1,244 @@
+if(!dojo._hasResource["dojo.dnd.Selector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Selector"] = true;
+dojo.provide("dojo.dnd.Selector");
+
+dojo.require("dojo.dnd.common");
+dojo.require("dojo.dnd.Container");
+
+/*
+ Container item states:
+ "" - an item is not selected
+ "Selected" - an item is selected
+ "Anchor" - an item is selected, and is an anchor for a "shift" selection
+*/
+
+dojo.declare("dojo.dnd.Selector", dojo.dnd.Container, {
+ // summary: a Selector object, which knows how to select its children
+
+ constructor: function(node, params){
+ // summary: a constructor of the Selector
+ // node: Node: node or node's id to build the selector on
+ // params: Object: a dict of parameters, recognized parameters are:
+ // singular: Boolean: allows selection of only one element, if true
+ // the rest of parameters are passed to the container
+ if(!params){ params = {}; }
+ this.singular = params.singular;
+ // class-specific variables
+ this.selection = {};
+ this.anchor = null;
+ this.simpleSelection = false;
+ // set up events
+ this.events.push(
+ dojo.connect(this.node, "onmousedown", this, "onMouseDown"),
+ dojo.connect(this.node, "onmouseup", this, "onMouseUp"));
+ },
+
+ // object attributes (for markup)
+ singular: false, // is singular property
+
+ // methods
+ getSelectedNodes: function(){
+ // summary: returns a list (an array) of selected nodes
+ var t = new dojo.NodeList();
+ var e = dojo.dnd._empty;
+ for(var i in this.selection){
+ if(i in e){ continue; }
+ t.push(dojo.byId(i));
+ }
+ return t; // Array
+ },
+ selectNone: function(){
+ // summary: unselects all items
+ return this._removeSelection()._removeAnchor(); // self
+ },
+ selectAll: function(){
+ // summary: selects all items
+ this.forInItems(function(data, id){
+ this._addItemClass(dojo.byId(id), "Selected");
+ this.selection[id] = 1;
+ }, this);
+ return this._removeAnchor(); // self
+ },
+ deleteSelectedNodes: function(){
+ // summary: deletes all selected items
+ var e = dojo.dnd._empty;
+ for(var i in this.selection){
+ if(i in e){ continue; }
+ var n = dojo.byId(i);
+ this.delItem(i);
+ dojo._destroyElement(n);
+ }
+ this.anchor = null;
+ this.selection = {};
+ return this; // self
+ },
+ insertNodes: function(addSelected, data, before, anchor){
+ // summary: inserts new data items (see Container's insertNodes method for details)
+ // addSelected: Boolean: all new nodes will be added to selected items, if true, no selection change otherwise
+ // data: Array: a list of data items, which should be processed by the creator function
+ // before: Boolean: insert before the anchor, if true, and after the anchor otherwise
+ // anchor: Node: the anchor node to be used as a point of insertion
+ var oldCreator = this._normalizedCreator;
+ this._normalizedCreator = function(item, hint){
+ var t = oldCreator.call(this, item, hint);
+ if(addSelected){
+ if(!this.anchor){
+ this.anchor = t.node;
+ this._removeItemClass(t.node, "Selected");
+ this._addItemClass(this.anchor, "Anchor");
+ }else if(this.anchor != t.node){
+ this._removeItemClass(t.node, "Anchor");
+ this._addItemClass(t.node, "Selected");
+ }
+ this.selection[t.node.id] = 1;
+ }else{
+ this._removeItemClass(t.node, "Selected");
+ this._removeItemClass(t.node, "Anchor");
+ }
+ return t;
+ };
+ dojo.dnd.Selector.superclass.insertNodes.call(this, data, before, anchor);
+ this._normalizedCreator = oldCreator;
+ return this; // self
+ },
+ destroy: function(){
+ // summary: prepares the object to be garbage-collected
+ dojo.dnd.Selector.superclass.destroy.call(this);
+ this.selection = this.anchor = null;
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ params._skipStartup = true;
+ return new dojo.dnd.Selector(node, params);
+ },
+
+ // mouse events
+ onMouseDown: function(e){
+ // summary: event processor for onmousedown
+ // e: Event: mouse event
+ if(!this.current){ return; }
+ if(!this.singular && !dojo.dnd.getCopyKeyState(e) && !e.shiftKey && (this.current.id in this.selection)){
+ this.simpleSelection = true;
+ dojo.stopEvent(e);
+ return;
+ }
+ if(!this.singular && e.shiftKey){
+ if(!dojo.dnd.getCopyKeyState(e)){
+ this._removeSelection();
+ }
+ var c = this.getAllNodes();
+ if(c.length){
+ if(!this.anchor){
+ this.anchor = c[0];
+ this._addItemClass(this.anchor, "Anchor");
+ }
+ this.selection[this.anchor.id] = 1;
+ if(this.anchor != this.current){
+ var i = 0;
+ for(; i < c.length; ++i){
+ var node = c[i];
+ if(node == this.anchor || node == this.current){ break; }
+ }
+ for(++i; i < c.length; ++i){
+ var node = c[i];
+ if(node == this.anchor || node == this.current){ break; }
+ this._addItemClass(node, "Selected");
+ this.selection[node.id] = 1;
+ }
+ this._addItemClass(this.current, "Selected");
+ this.selection[this.current.id] = 1;
+ }
+ }
+ }else{
+ if(this.singular){
+ if(this.anchor == this.current){
+ if(dojo.dnd.getCopyKeyState(e)){
+ this.selectNone();
+ }
+ }else{
+ this.selectNone();
+ this.anchor = this.current;
+ this._addItemClass(this.anchor, "Anchor");
+ this.selection[this.current.id] = 1;
+ }
+ }else{
+ if(dojo.dnd.getCopyKeyState(e)){
+ if(this.anchor == this.current){
+ delete this.selection[this.anchor.id];
+ this._removeAnchor();
+ }else{
+ if(this.current.id in this.selection){
+ this._removeItemClass(this.current, "Selected");
+ delete this.selection[this.current.id];
+ }else{
+ if(this.anchor){
+ this._removeItemClass(this.anchor, "Anchor");
+ this._addItemClass(this.anchor, "Selected");
+ }
+ this.anchor = this.current;
+ this._addItemClass(this.current, "Anchor");
+ this.selection[this.current.id] = 1;
+ }
+ }
+ }else{
+ if(!(this.current.id in this.selection)){
+ this.selectNone();
+ this.anchor = this.current;
+ this._addItemClass(this.current, "Anchor");
+ this.selection[this.current.id] = 1;
+ }
+ }
+ }
+ }
+ dojo.stopEvent(e);
+ },
+ onMouseUp: function(e){
+ // summary: event processor for onmouseup
+ // e: Event: mouse event
+ if(!this.simpleSelection){ return; }
+ this.simpleSelection = false;
+ this.selectNone();
+ if(this.current){
+ this.anchor = this.current;
+ this._addItemClass(this.anchor, "Anchor");
+ this.selection[this.current.id] = 1;
+ }
+ },
+ onMouseMove: function(e){
+ // summary: event processor for onmousemove
+ // e: Event: mouse event
+ this.simpleSelection = false;
+ },
+
+ // utilities
+ onOverEvent: function(){
+ // summary: this function is called once, when mouse is over our container
+ this.onmousemoveEvent = dojo.connect(this.node, "onmousemove", this, "onMouseMove");
+ },
+ onOutEvent: function(){
+ // summary: this function is called once, when mouse is out of our container
+ dojo.disconnect(this.onmousemoveEvent);
+ delete this.onmousemoveEvent;
+ },
+ _removeSelection: function(){
+ // summary: unselects all items
+ var e = dojo.dnd._empty;
+ for(var i in this.selection){
+ if(i in e){ continue; }
+ var node = dojo.byId(i);
+ if(node){ this._removeItemClass(node, "Selected"); }
+ }
+ this.selection = {};
+ return this; // self
+ },
+ _removeAnchor: function(){
+ if(this.anchor){
+ this._removeItemClass(this.anchor, "Anchor");
+ this.anchor = null;
+ }
+ return this; // self
+ }
+});
+
+}
diff --git a/includes/js/dojo/dnd/Source.js b/includes/js/dojo/dnd/Source.js
new file mode 100644
index 0000000..1779756
--- /dev/null
+++ b/includes/js/dojo/dnd/Source.js
@@ -0,0 +1,393 @@
+if(!dojo._hasResource["dojo.dnd.Source"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Source"] = true;
+dojo.provide("dojo.dnd.Source");
+
+dojo.require("dojo.dnd.Selector");
+dojo.require("dojo.dnd.Manager");
+
+/*
+ Container property:
+ "Horizontal"- if this is the horizontal container
+ Source states:
+ "" - normal state
+ "Moved" - this source is being moved
+ "Copied" - this source is being copied
+ Target states:
+ "" - normal state
+ "Disabled" - the target cannot accept an avatar
+ Target anchor state:
+ "" - item is not selected
+ "Before" - insert point is before the anchor
+ "After" - insert point is after the anchor
+*/
+
+/*=====
+dojo.dnd.__SourceArgs = function(){
+ // summary:
+ // a dict of parameters for DnD Source configuration. Note that any
+ // property on Source elements may be configured, but this is the
+ // short-list
+ // isSource: Boolean?
+ // can be used as a DnD source. Defaults to true.
+ // accept: Array?
+ // list of accepted types (text strings) for a target; defaults to
+ // ["text"]
+ // horizontal: Boolean?
+ // a horizontal container, if true, vertical otherwise or when omitted
+ // copyOnly: Boolean?
+ // always copy items, if true, use a state of Ctrl key otherwise
+ // withHandles: Boolean?
+ // allows dragging only by handles
+ this.isSource = isSource;
+ this.accept = accept;
+ this.horizontal = horizontal;
+ this.copyOnly = copyOnly;
+ this.withHandles = withHandles;
+}
+=====*/
+
+dojo.declare("dojo.dnd.Source", dojo.dnd.Selector, {
+ // summary: a Source object, which can be used as a DnD source, or a DnD target
+
+ // object attributes (for markup)
+ isSource: true,
+ horizontal: false,
+ copyOnly: false,
+ skipForm: false,
+ withHandles: false,
+ accept: ["text"],
+
+ constructor: function(/*DOMNode|String*/node, /*dojo.dnd.__SourceArgs?*/params){
+ // summary:
+ // a constructor of the Source
+ // node:
+ // node or node's id to build the source on
+ // params:
+ // any property of this class may be configured via the params
+ // object which is mixed-in to the `dojo.dnd.Source` instance
+ dojo.mixin(this, dojo.mixin({}, params));
+ var type = this.accept;
+ if(type.length){
+ this.accept = {};
+ for(var i = 0; i < type.length; ++i){
+ this.accept[type[i]] = 1;
+ }
+ }
+ // class-specific variables
+ this.isDragging = false;
+ this.mouseDown = false;
+ this.targetAnchor = null;
+ this.targetBox = null;
+ this.before = true;
+ // states
+ this.sourceState = "";
+ if(this.isSource){
+ dojo.addClass(this.node, "dojoDndSource");
+ }
+ this.targetState = "";
+ if(this.accept){
+ dojo.addClass(this.node, "dojoDndTarget");
+ }
+ if(this.horizontal){
+ dojo.addClass(this.node, "dojoDndHorizontal");
+ }
+ // set up events
+ this.topics = [
+ dojo.subscribe("/dnd/source/over", this, "onDndSourceOver"),
+ dojo.subscribe("/dnd/start", this, "onDndStart"),
+ dojo.subscribe("/dnd/drop", this, "onDndDrop"),
+ dojo.subscribe("/dnd/cancel", this, "onDndCancel")
+ ];
+ },
+
+ // methods
+ checkAcceptance: function(source, nodes){
+ // summary: checks, if the target can accept nodes from this source
+ // source: Object: the source which provides items
+ // nodes: Array: the list of transferred items
+ if(this == source){ return true; }
+ for(var i = 0; i < nodes.length; ++i){
+ var type = source.getItem(nodes[i].id).type;
+ // type instanceof Array
+ var flag = false;
+ for(var j = 0; j < type.length; ++j){
+ if(type[j] in this.accept){
+ flag = true;
+ break;
+ }
+ }
+ if(!flag){
+ return false; // Boolean
+ }
+ }
+ return true; // Boolean
+ },
+ copyState: function(keyPressed){
+ // summary: Returns true, if we need to copy items, false to move.
+ // It is separated to be overwritten dynamically, if needed.
+ // keyPressed: Boolean: the "copy" was pressed
+ return this.copyOnly || keyPressed; // Boolean
+ },
+ destroy: function(){
+ // summary: prepares the object to be garbage-collected
+ dojo.dnd.Source.superclass.destroy.call(this);
+ dojo.forEach(this.topics, dojo.unsubscribe);
+ this.targetAnchor = null;
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ params._skipStartup = true;
+ return new dojo.dnd.Source(node, params);
+ },
+
+ // mouse event processors
+ onMouseMove: function(e){
+ // summary: event processor for onmousemove
+ // e: Event: mouse event
+ if(this.isDragging && this.targetState == "Disabled"){ return; }
+ dojo.dnd.Source.superclass.onMouseMove.call(this, e);
+ var m = dojo.dnd.manager();
+ if(this.isDragging){
+ // calculate before/after
+ var before = false;
+ if(this.current){
+ if(!this.targetBox || this.targetAnchor != this.current){
+ this.targetBox = {
+ xy: dojo.coords(this.current, true),
+ w: this.current.offsetWidth,
+ h: this.current.offsetHeight
+ };
+ }
+ if(this.horizontal){
+ before = (e.pageX - this.targetBox.xy.x) < (this.targetBox.w / 2);
+ }else{
+ before = (e.pageY - this.targetBox.xy.y) < (this.targetBox.h / 2);
+ }
+ }
+ if(this.current != this.targetAnchor || before != this.before){
+ this._markTargetAnchor(before);
+ m.canDrop(!this.current || m.source != this || !(this.current.id in this.selection));
+ }
+ }else{
+ if(this.mouseDown && this.isSource){
+ var nodes = this.getSelectedNodes();
+ if(nodes.length){
+ m.startDrag(this, nodes, this.copyState(dojo.dnd.getCopyKeyState(e)));
+ }
+ }
+ }
+ },
+ onMouseDown: function(e){
+ // summary: event processor for onmousedown
+ // e: Event: mouse event
+ if(this._legalMouseDown(e) && (!this.skipForm || !dojo.dnd.isFormElement(e))){
+ this.mouseDown = true;
+ this.mouseButton = e.button;
+ dojo.dnd.Source.superclass.onMouseDown.call(this, e);
+ }
+ },
+ onMouseUp: function(e){
+ // summary: event processor for onmouseup
+ // e: Event: mouse event
+ if(this.mouseDown){
+ this.mouseDown = false;
+ dojo.dnd.Source.superclass.onMouseUp.call(this, e);
+ }
+ },
+
+ // topic event processors
+ onDndSourceOver: function(source){
+ // summary: topic event processor for /dnd/source/over, called when detected a current source
+ // source: Object: the source which has the mouse over it
+ if(this != source){
+ this.mouseDown = false;
+ if(this.targetAnchor){
+ this._unmarkTargetAnchor();
+ }
+ }else if(this.isDragging){
+ var m = dojo.dnd.manager();
+ m.canDrop(this.targetState != "Disabled" && (!this.current || m.source != this || !(this.current.id in this.selection)));
+ }
+ },
+ onDndStart: function(source, nodes, copy){
+ // summary: topic event processor for /dnd/start, called to initiate the DnD operation
+ // source: Object: the source which provides items
+ // nodes: Array: the list of transferred items
+ // copy: Boolean: copy items, if true, move items otherwise
+ if(this.isSource){
+ this._changeState("Source", this == source ? (copy ? "Copied" : "Moved") : "");
+ }
+ var accepted = this.accept && this.checkAcceptance(source, nodes);
+ this._changeState("Target", accepted ? "" : "Disabled");
+ if(accepted && this == source){
+ dojo.dnd.manager().overSource(this);
+ }
+ this.isDragging = true;
+ },
+ onDndDrop: function(source, nodes, copy){
+ // summary: topic event processor for /dnd/drop, called to finish the DnD operation
+ // source: Object: the source which provides items
+ // nodes: Array: the list of transferred items
+ // copy: Boolean: copy items, if true, move items otherwise
+ do{ //break box
+ if(this.containerState != "Over"){ break; }
+ var oldCreator = this._normalizedCreator;
+ if(this != source){
+ // transferring nodes from the source to the target
+ if(this.creator){
+ // use defined creator
+ this._normalizedCreator = function(node, hint){
+ return oldCreator.call(this, source.getItem(node.id).data, hint);
+ };
+ }else{
+ // we have no creator defined => move/clone nodes
+ if(copy){
+ // clone nodes
+ this._normalizedCreator = function(node, hint){
+ var t = source.getItem(node.id);
+ var n = node.cloneNode(true);
+ n.id = dojo.dnd.getUniqueId();
+ return {node: n, data: t.data, type: t.type};
+ };
+ }else{
+ // move nodes
+ this._normalizedCreator = function(node, hint){
+ var t = source.getItem(node.id);
+ source.delItem(node.id);
+ return {node: node, data: t.data, type: t.type};
+ };
+ }
+ }
+ }else{
+ // transferring nodes within the single source
+ if(this.current && this.current.id in this.selection){ break; }
+ if(this.creator){
+ // use defined creator
+ if(copy){
+ // create new copies of data items
+ this._normalizedCreator = function(node, hint){
+ return oldCreator.call(this, source.getItem(node.id).data, hint);
+ };
+ }else{
+ // move nodes
+ if(!this.current){ break; }
+ this._normalizedCreator = function(node, hint){
+ var t = source.getItem(node.id);
+ return {node: node, data: t.data, type: t.type};
+ };
+ }
+ }else{
+ // we have no creator defined => move/clone nodes
+ if(copy){
+ // clone nodes
+ this._normalizedCreator = function(node, hint){
+ var t = source.getItem(node.id);
+ var n = node.cloneNode(true);
+ n.id = dojo.dnd.getUniqueId();
+ return {node: n, data: t.data, type: t.type};
+ };
+ }else{
+ // move nodes
+ if(!this.current){ break; }
+ this._normalizedCreator = function(node, hint){
+ var t = source.getItem(node.id);
+ return {node: node, data: t.data, type: t.type};
+ };
+ }
+ }
+ }
+ this._removeSelection();
+ if(this != source){
+ this._removeAnchor();
+ }
+ if(this != source && !copy && !this.creator){
+ source.selectNone();
+ }
+ this.insertNodes(true, nodes, this.before, this.current);
+ if(this != source && !copy && this.creator){
+ source.deleteSelectedNodes();
+ }
+ this._normalizedCreator = oldCreator;
+ }while(false);
+ this.onDndCancel();
+ },
+ onDndCancel: function(){
+ // summary: topic event processor for /dnd/cancel, called to cancel the DnD operation
+ if(this.targetAnchor){
+ this._unmarkTargetAnchor();
+ this.targetAnchor = null;
+ }
+ this.before = true;
+ this.isDragging = false;
+ this.mouseDown = false;
+ delete this.mouseButton;
+ this._changeState("Source", "");
+ this._changeState("Target", "");
+ },
+
+ // utilities
+ onOverEvent: function(){
+ // summary: this function is called once, when mouse is over our container
+ dojo.dnd.Source.superclass.onOverEvent.call(this);
+ dojo.dnd.manager().overSource(this);
+ },
+ onOutEvent: function(){
+ // summary: this function is called once, when mouse is out of our container
+ dojo.dnd.Source.superclass.onOutEvent.call(this);
+ dojo.dnd.manager().outSource(this);
+ },
+ _markTargetAnchor: function(before){
+ // summary: assigns a class to the current target anchor based on "before" status
+ // before: Boolean: insert before, if true, after otherwise
+ if(this.current == this.targetAnchor && this.before == before){ return; }
+ if(this.targetAnchor){
+ this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");
+ }
+ this.targetAnchor = this.current;
+ this.targetBox = null;
+ this.before = before;
+ if(this.targetAnchor){
+ this._addItemClass(this.targetAnchor, this.before ? "Before" : "After");
+ }
+ },
+ _unmarkTargetAnchor: function(){
+ // summary: removes a class of the current target anchor based on "before" status
+ if(!this.targetAnchor){ return; }
+ this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");
+ this.targetAnchor = null;
+ this.targetBox = null;
+ this.before = true;
+ },
+ _markDndStatus: function(copy){
+ // summary: changes source's state based on "copy" status
+ this._changeState("Source", copy ? "Copied" : "Moved");
+ },
+ _legalMouseDown: function(e){
+ // summary: checks if user clicked on "approved" items
+ // e: Event: mouse event
+ if(!this.withHandles){ return true; }
+ for(var node = e.target; node && !dojo.hasClass(node, "dojoDndItem"); node = node.parentNode){
+ if(dojo.hasClass(node, "dojoDndHandle")){ return true; }
+ }
+ return false; // Boolean
+ }
+});
+
+dojo.declare("dojo.dnd.Target", dojo.dnd.Source, {
+ // summary: a Target object, which can be used as a DnD target
+
+ constructor: function(node, params){
+ // summary: a constructor of the Target --- see the Source constructor for details
+ this.isSource = false;
+ dojo.removeClass(this.node, "dojoDndSource");
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ params._skipStartup = true;
+ return new dojo.dnd.Target(node, params);
+ }
+});
+
+}
diff --git a/includes/js/dojo/dnd/TimedMoveable.js b/includes/js/dojo/dnd/TimedMoveable.js
new file mode 100644
index 0000000..4f4fb0b
--- /dev/null
+++ b/includes/js/dojo/dnd/TimedMoveable.js
@@ -0,0 +1,66 @@
+if(!dojo._hasResource["dojo.dnd.TimedMoveable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.TimedMoveable"] = true;
+dojo.provide("dojo.dnd.TimedMoveable");
+
+dojo.require("dojo.dnd.Moveable");
+
+(function(){
+ // precalculate long expressions
+ var oldOnMove = dojo.dnd.Moveable.prototype.onMove;
+
+ dojo.declare("dojo.dnd.TimedMoveable", dojo.dnd.Moveable, {
+ // summary:
+ // A specialized version of Moveable to support an FPS throttling.
+ // This class puts an upper restriction on FPS, which may reduce
+ // the CPU load. The additional parameter "timeout" regulates
+ // the delay before actually moving the moveable object.
+
+ // object attributes (for markup)
+ timeout: 40, // in ms, 40ms corresponds to 25 fps
+
+ constructor: function(node, params){
+ // summary: an object, which makes a node moveable with a timer
+ // node: Node: a node (or node's id) to be moved
+ // params: Object: an optional object with additional parameters.
+ // See dojo.dnd.Moveable for details on general parameters.
+ // Following parameters are specific for this class:
+ // timeout: Number: delay move by this number of ms
+ // accumulating position changes during the timeout
+
+ // sanitize parameters
+ if(!params){ params = {}; }
+ if(params.timeout && typeof params.timeout == "number" && params.timeout >= 0){
+ this.timeout = params.timeout;
+ }
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.TimedMoveable(node, params);
+ },
+
+ onMoveStop: function(/* dojo.dnd.Mover */ mover){
+ if(mover._timer){
+ // stop timer
+ clearTimeout(mover._timer)
+ // reflect the last received position
+ oldOnMove.call(this, mover, mover._leftTop)
+ }
+ dojo.dnd.Moveable.prototype.onMoveStop.apply(this, arguments);
+ },
+ onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ mover._leftTop = leftTop;
+ if(!mover._timer){
+ var _t = this; // to avoid using dojo.hitch()
+ mover._timer = setTimeout(function(){
+ // we don't have any pending requests
+ mover._timer = null;
+ // reflect the last received position
+ oldOnMove.call(_t, mover, mover._leftTop);
+ }, this.timeout);
+ }
+ }
+ });
+})();
+
+}
diff --git a/includes/js/dojo/dnd/autoscroll.js b/includes/js/dojo/dnd/autoscroll.js
new file mode 100644
index 0000000..07ab61e
--- /dev/null
+++ b/includes/js/dojo/dnd/autoscroll.js
@@ -0,0 +1,103 @@
+if(!dojo._hasResource["dojo.dnd.autoscroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.autoscroll"] = true;
+dojo.provide("dojo.dnd.autoscroll");
+
+dojo.dnd.getViewport = function(){
+ // summary: returns a viewport size (visible part of the window)
+
+ // FIXME: need more docs!!
+ var d = dojo.doc, dd = d.documentElement, w = window, b = dojo.body();
+ if(dojo.isMozilla){
+ return {w: dd.clientWidth, h: w.innerHeight}; // Object
+ }else if(!dojo.isOpera && w.innerWidth){
+ return {w: w.innerWidth, h: w.innerHeight}; // Object
+ }else if (!dojo.isOpera && dd && dd.clientWidth){
+ return {w: dd.clientWidth, h: dd.clientHeight}; // Object
+ }else if (b.clientWidth){
+ return {w: b.clientWidth, h: b.clientHeight}; // Object
+ }
+ return null; // Object
+};
+
+dojo.dnd.V_TRIGGER_AUTOSCROLL = 32;
+dojo.dnd.H_TRIGGER_AUTOSCROLL = 32;
+
+dojo.dnd.V_AUTOSCROLL_VALUE = 16;
+dojo.dnd.H_AUTOSCROLL_VALUE = 16;
+
+dojo.dnd.autoScroll = function(e){
+ // summary:
+ // a handler for onmousemove event, which scrolls the window, if
+ // necesary
+ // e: Event:
+ // onmousemove event
+
+ // FIXME: needs more docs!
+ var v = dojo.dnd.getViewport(), dx = 0, dy = 0;
+ if(e.clientX < dojo.dnd.H_TRIGGER_AUTOSCROLL){
+ dx = -dojo.dnd.H_AUTOSCROLL_VALUE;
+ }else if(e.clientX > v.w - dojo.dnd.H_TRIGGER_AUTOSCROLL){
+ dx = dojo.dnd.H_AUTOSCROLL_VALUE;
+ }
+ if(e.clientY < dojo.dnd.V_TRIGGER_AUTOSCROLL){
+ dy = -dojo.dnd.V_AUTOSCROLL_VALUE;
+ }else if(e.clientY > v.h - dojo.dnd.V_TRIGGER_AUTOSCROLL){
+ dy = dojo.dnd.V_AUTOSCROLL_VALUE;
+ }
+ window.scrollBy(dx, dy);
+};
+
+dojo.dnd._validNodes = {"div": 1, "p": 1, "td": 1};
+dojo.dnd._validOverflow = {"auto": 1, "scroll": 1};
+
+dojo.dnd.autoScrollNodes = function(e){
+ // summary:
+ // a handler for onmousemove event, which scrolls the first avaialble
+ // Dom element, it falls back to dojo.dnd.autoScroll()
+ // e: Event:
+ // onmousemove event
+
+ // FIXME: needs more docs!
+ for(var n = e.target; n;){
+ if(n.nodeType == 1 && (n.tagName.toLowerCase() in dojo.dnd._validNodes)){
+ var s = dojo.getComputedStyle(n);
+ if(s.overflow.toLowerCase() in dojo.dnd._validOverflow){
+ var b = dojo._getContentBox(n, s), t = dojo._abs(n, true);
+ // console.debug(b.l, b.t, t.x, t.y, n.scrollLeft, n.scrollTop);
+ b.l += t.x + n.scrollLeft;
+ b.t += t.y + n.scrollTop;
+ var w = Math.min(dojo.dnd.H_TRIGGER_AUTOSCROLL, b.w / 2),
+ h = Math.min(dojo.dnd.V_TRIGGER_AUTOSCROLL, b.h / 2),
+ rx = e.pageX - b.l, ry = e.pageY - b.t, dx = 0, dy = 0;
+ if(rx > 0 && rx < b.w){
+ if(rx < w){
+ dx = -dojo.dnd.H_AUTOSCROLL_VALUE;
+ }else if(rx > b.w - w){
+ dx = dojo.dnd.H_AUTOSCROLL_VALUE;
+ }
+ }
+ //console.debug("ry =", ry, "b.h =", b.h, "h =", h);
+ if(ry > 0 && ry < b.h){
+ if(ry < h){
+ dy = -dojo.dnd.V_AUTOSCROLL_VALUE;
+ }else if(ry > b.h - h){
+ dy = dojo.dnd.V_AUTOSCROLL_VALUE;
+ }
+ }
+ var oldLeft = n.scrollLeft, oldTop = n.scrollTop;
+ n.scrollLeft = n.scrollLeft + dx;
+ n.scrollTop = n.scrollTop + dy;
+ // if(dx || dy){ console.debug(oldLeft + ", " + oldTop + "\n" + dx + ", " + dy + "\n" + n.scrollLeft + ", " + n.scrollTop); }
+ if(oldLeft != n.scrollLeft || oldTop != n.scrollTop){ return; }
+ }
+ }
+ try{
+ n = n.parentNode;
+ }catch(x){
+ n = null;
+ }
+ }
+ dojo.dnd.autoScroll(e);
+};
+
+}
diff --git a/includes/js/dojo/dnd/common.js b/includes/js/dojo/dnd/common.js
new file mode 100644
index 0000000..79e7679
--- /dev/null
+++ b/includes/js/dojo/dnd/common.js
@@ -0,0 +1,35 @@
+if(!dojo._hasResource["dojo.dnd.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.common"] = true;
+dojo.provide("dojo.dnd.common");
+
+dojo.dnd._copyKey = navigator.appVersion.indexOf("Macintosh") < 0 ? "ctrlKey" : "metaKey";
+
+dojo.dnd.getCopyKeyState = function(e) {
+ // summary: abstracts away the difference between selection on Mac and PC,
+ // and returns the state of the "copy" key to be pressed.
+ // e: Event: mouse event
+ return e[dojo.dnd._copyKey]; // Boolean
+};
+
+dojo.dnd._uniqueId = 0;
+dojo.dnd.getUniqueId = function(){
+ // summary: returns a unique string for use with any DOM element
+ var id;
+ do{
+ id = dojo._scopeName + "Unique" + (++dojo.dnd._uniqueId);
+ }while(dojo.byId(id));
+ return id;
+};
+
+dojo.dnd._empty = {};
+
+dojo.dnd.isFormElement = function(/*Event*/ e){
+ // summary: returns true, if user clicked on a form element
+ var t = e.target;
+ if(t.nodeType == 3 /*TEXT_NODE*/){
+ t = t.parentNode;
+ }
+ return " button textarea input select option ".indexOf(" " + t.tagName.toLowerCase() + " ") >= 0; // Boolean
+};
+
+}
diff --git a/includes/js/dojo/dnd/move.js b/includes/js/dojo/dnd/move.js
new file mode 100644
index 0000000..1e58222
--- /dev/null
+++ b/includes/js/dojo/dnd/move.js
@@ -0,0 +1,202 @@
+if(!dojo._hasResource["dojo.dnd.move"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.move"] = true;
+dojo.provide("dojo.dnd.move");
+
+dojo.require("dojo.dnd.Mover");
+dojo.require("dojo.dnd.Moveable");
+
+dojo.declare("dojo.dnd.move.constrainedMoveable", dojo.dnd.Moveable, {
+ // object attributes (for markup)
+ constraints: function(){},
+ within: false,
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.move.constrainedMoveable(node, params);
+ },
+
+ constructor: function(node, params){
+ // summary: an object, which makes a node moveable
+ // node: Node: a node (or node's id) to be moved
+ // params: Object: an optional object with additional parameters;
+ // following parameters are recognized:
+ // constraints: Function: a function, which calculates a constraint box,
+ // it is called in a context of the moveable object.
+ // within: Boolean: restrict move within boundaries.
+ // the rest is passed to the base class
+ if(!params){ params = {}; }
+ this.constraints = params.constraints;
+ this.within = params.within;
+ },
+ onFirstMove: function(/* dojo.dnd.Mover */ mover){
+ // summary: called during the very first move notification,
+ // can be used to initialize coordinates, can be overwritten.
+ var c = this.constraintBox = this.constraints.call(this, mover);
+ c.r = c.l + c.w;
+ c.b = c.t + c.h;
+ if(this.within){
+ var mb = dojo.marginBox(mover.node);
+ c.r -= mb.w;
+ c.b -= mb.h;
+ }
+ },
+ onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ // summary: called during every move notification,
+ // should actually move the node, can be overwritten.
+ var c = this.constraintBox, s = mover.node.style;
+ s.left = (leftTop.l < c.l ? c.l : c.r < leftTop.l ? c.r : leftTop.l) + "px";
+ s.top = (leftTop.t < c.t ? c.t : c.b < leftTop.t ? c.b : leftTop.t) + "px";
+ }
+});
+
+dojo.declare("dojo.dnd.move.boxConstrainedMoveable", dojo.dnd.move.constrainedMoveable, {
+ // object attributes (for markup)
+ box: {},
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.move.boxConstrainedMoveable(node, params);
+ },
+
+ constructor: function(node, params){
+ // summary: an object, which makes a node moveable
+ // node: Node: a node (or node's id) to be moved
+ // params: Object: an optional object with additional parameters;
+ // following parameters are recognized:
+ // box: Object: a constraint box
+ // the rest is passed to the base class
+ var box = params && params.box;
+ this.constraints = function(){ return box; };
+ }
+});
+
+dojo.declare("dojo.dnd.move.parentConstrainedMoveable", dojo.dnd.move.constrainedMoveable, {
+ // object attributes (for markup)
+ area: "content",
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.move.parentConstrainedMoveable(node, params);
+ },
+
+ constructor: function(node, params){
+ // summary: an object, which makes a node moveable
+ // node: Node: a node (or node's id) to be moved
+ // params: Object: an optional object with additional parameters;
+ // following parameters are recognized:
+ // area: String: a parent's area to restrict the move,
+ // can be "margin", "border", "padding", or "content".
+ // the rest is passed to the base class
+ var area = params && params.area;
+ this.constraints = function(){
+ var n = this.node.parentNode,
+ s = dojo.getComputedStyle(n),
+ mb = dojo._getMarginBox(n, s);
+ if(area == "margin"){
+ return mb; // Object
+ }
+ var t = dojo._getMarginExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ if(area == "border"){
+ return mb; // Object
+ }
+ t = dojo._getBorderExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ if(area == "padding"){
+ return mb; // Object
+ }
+ t = dojo._getPadExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ return mb; // Object
+ };
+ }
+});
+
+// WARNING: below are obsolete objects, instead of custom movers use custom moveables (above)
+
+dojo.dnd.move.constrainedMover = function(fun, within){
+ // summary: returns a constrained version of dojo.dnd.Mover
+ // description: this function produces n object, which will put a constraint on
+ // the margin box of dragged object in absolute coordinates
+ // fun: Function: called on drag, and returns a constraint box
+ // within: Boolean: if true, constraints the whole dragged object withtin the rectangle,
+ // otherwise the constraint is applied to the left-top corner
+ dojo.deprecated("dojo.dnd.move.constrainedMover, use dojo.dnd.move.constrainedMoveable instead");
+ var mover = function(node, e, notifier){
+ dojo.dnd.Mover.call(this, node, e, notifier);
+ };
+ dojo.extend(mover, dojo.dnd.Mover.prototype);
+ dojo.extend(mover, {
+ onMouseMove: function(e){
+ // summary: event processor for onmousemove
+ // e: Event: mouse event
+ dojo.dnd.autoScroll(e);
+ var m = this.marginBox, c = this.constraintBox,
+ l = m.l + e.pageX, t = m.t + e.pageY;
+ l = l < c.l ? c.l : c.r < l ? c.r : l;
+ t = t < c.t ? c.t : c.b < t ? c.b : t;
+ this.host.onMove(this, {l: l, t: t});
+ },
+ onFirstMove: function(){
+ // summary: called once to initialize things; it is meant to be called only once
+ dojo.dnd.Mover.prototype.onFirstMove.call(this);
+ var c = this.constraintBox = fun.call(this);
+ c.r = c.l + c.w;
+ c.b = c.t + c.h;
+ if(within){
+ var mb = dojo.marginBox(this.node);
+ c.r -= mb.w;
+ c.b -= mb.h;
+ }
+ }
+ });
+ return mover; // Object
+};
+
+dojo.dnd.move.boxConstrainedMover = function(box, within){
+ // summary: a specialization of dojo.dnd.constrainedMover, which constrains to the specified box
+ // box: Object: a constraint box (l, t, w, h)
+ // within: Boolean: if true, constraints the whole dragged object withtin the rectangle,
+ // otherwise the constraint is applied to the left-top corner
+ dojo.deprecated("dojo.dnd.move.boxConstrainedMover, use dojo.dnd.move.boxConstrainedMoveable instead");
+ return dojo.dnd.move.constrainedMover(function(){ return box; }, within); // Object
+};
+
+dojo.dnd.move.parentConstrainedMover = function(area, within){
+ // summary: a specialization of dojo.dnd.constrainedMover, which constrains to the parent node
+ // area: String: "margin" to constrain within the parent's margin box, "border" for the border box,
+ // "padding" for the padding box, and "content" for the content box; "content" is the default value.
+ // within: Boolean: if true, constraints the whole dragged object withtin the rectangle,
+ // otherwise the constraint is applied to the left-top corner
+ dojo.deprecated("dojo.dnd.move.parentConstrainedMover, use dojo.dnd.move.parentConstrainedMoveable instead");
+ var fun = function(){
+ var n = this.node.parentNode,
+ s = dojo.getComputedStyle(n),
+ mb = dojo._getMarginBox(n, s);
+ if(area == "margin"){
+ return mb; // Object
+ }
+ var t = dojo._getMarginExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ if(area == "border"){
+ return mb; // Object
+ }
+ t = dojo._getBorderExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ if(area == "padding"){
+ return mb; // Object
+ }
+ t = dojo._getPadExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ return mb; // Object
+ };
+ return dojo.dnd.move.constrainedMover(fun, within); // Object
+};
+
+// patching functions one level up for compatibility
+
+dojo.dnd.constrainedMover = dojo.dnd.move.constrainedMover;
+dojo.dnd.boxConstrainedMover = dojo.dnd.move.boxConstrainedMover;
+dojo.dnd.parentConstrainedMover = dojo.dnd.move.parentConstrainedMover;
+
+}
diff --git a/includes/js/dojo/dojo.js b/includes/js/dojo/dojo.js
new file mode 100644
index 0000000..13986ec
--- /dev/null
+++ b/includes/js/dojo/dojo.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.
+*/
+
+(function(){var _1=null;if((_1||(typeof djConfig!="undefined"&&djConfig.scopeMap))&&(typeof window!="undefined")){var _2="",_3="",_4="",_5={},_6={};_1=_1||djConfig.scopeMap;for(var i=0;i<_1.length;i++){var _8=_1[i];_2+="var "+_8[0]+" = {}; "+_8[1]+" = "+_8[0]+";"+_8[1]+"._scopeName = '"+_8[1]+"';";_3+=(i==0?"":",")+_8[0];_4+=(i==0?"":",")+_8[1];_5[_8[0]]=_8[1];_6[_8[1]]=_8[0];}eval(_2+"dojo._scopeArgs = ["+_4+"];");dojo._scopePrefixArgs=_3;dojo._scopePrefix="(function("+_3+"){";dojo._scopeSuffix="})("+_4+")";dojo._scopeMap=_5;dojo._scopeMapRev=_6;}(function(){if(!this["console"]){this.console={log:function(){}};}var cn=["assert","count","debug","dir","dirxml","error","group","groupEnd","info","profile","profileEnd","time","timeEnd","trace","warn","log"];var i=0,tn;while((tn=cn[i++])){if(!console[tn]){(function(){var _c=tn+"";console[_c]=function(){var a=Array.apply({},arguments);a.unshift(_c+":");console.log(a.join(" "));};})();}}if(typeof dojo=="undefined"){this.dojo={_scopeName:"dojo",_scopePrefix:"",_scopePrefixArgs:"",_scopeSuffix:"",_scopeMap:{},_scopeMapRev:{}};}var d=dojo;if(typeof dijit=="undefined"){this.dijit={_scopeName:"dijit"};}if(typeof dojox=="undefined"){this.dojox={_scopeName:"dojox"};}if(!d._scopeArgs){d._scopeArgs=[dojo,dijit,dojox];}d.global=this;d.config={isDebug:false,debugAtAllCosts:false};if(typeof djConfig!="undefined"){for(var _f in djConfig){d.config[_f]=djConfig[_f];}}var _10=["Browser","Rhino","Spidermonkey","Mobile"];var t;while((t=_10.shift())){d["is"+t]=false;}dojo.locale=d.config.locale;var rev="$Rev: 13707 $".match(/\d+/);dojo.version={major:1,minor:1,patch:1,flag:"",revision:rev?+rev[0]:999999,toString:function(){with(d.version){return major+"."+minor+"."+patch+flag+" ("+revision+")";}}};if(typeof OpenAjax!="undefined"){OpenAjax.hub.registerLibrary(dojo._scopeName,"http://dojotoolkit.org",d.version.toString());}dojo._mixin=function(obj,_14){var _15={};for(var x in _14){if(_15[x]===undefined||_15[x]!=_14[x]){obj[x]=_14[x];}}if(d["isIE"]&&_14){var p=_14.toString;if(typeof p=="function"&&p!=obj.toString&&p!=_15.toString&&p!="\nfunction toString() {\n [native code]\n}\n"){obj.toString=_14.toString;}}return obj;};dojo.mixin=function(obj,_19){for(var i=1,l=arguments.length;i<l;i++){d._mixin(obj,arguments[i]);}return obj;};dojo._getProp=function(_1c,_1d,_1e){var obj=_1e||d.global;for(var i=0,p;obj&&(p=_1c[i]);i++){if(i==0&&this._scopeMap[p]){p=this._scopeMap[p];}obj=(p in obj?obj[p]:(_1d?obj[p]={}:undefined));}return obj;};dojo.setObject=function(_22,_23,_24){var _25=_22.split("."),p=_25.pop(),obj=d._getProp(_25,true,_24);return obj&&p?(obj[p]=_23):undefined;};dojo.getObject=function(_28,_29,_2a){return d._getProp(_28.split("."),_29,_2a);};dojo.exists=function(_2b,obj){return !!d.getObject(_2b,false,obj);};dojo["eval"]=function(_2d){return d.global.eval?d.global.eval(_2d):eval(_2d);};d.deprecated=d.experimental=function(){};})();(function(){var d=dojo;d.mixin(d,{_loadedModules:{},_inFlightCount:0,_hasResource:{},_modulePrefixes:{dojo:{name:"dojo",value:"."},doh:{name:"doh",value:"../util/doh"},tests:{name:"tests",value:"tests"}},_moduleHasPrefix:function(_2f){var mp=this._modulePrefixes;return !!(mp[_2f]&&mp[_2f].value);},_getModulePrefix:function(_31){var mp=this._modulePrefixes;if(this._moduleHasPrefix(_31)){return mp[_31].value;}return _31;},_loadedUrls:[],_postLoad:false,_loaders:[],_unloaders:[],_loadNotifying:false});dojo._loadPath=function(_33,_34,cb){var uri=((_33.charAt(0)=="/"||_33.match(/^\w+:/))?"":this.baseUrl)+_33;try{return !_34?this._loadUri(uri,cb):this._loadUriAndCheck(uri,_34,cb);}catch(e){console.error(e);return false;}};dojo._loadUri=function(uri,cb){if(this._loadedUrls[uri]){return true;}var _39=this._getText(uri,true);if(!_39){return false;}this._loadedUrls[uri]=true;this._loadedUrls.push(uri);if(cb){_39="("+_39+")";}else{_39=this._scopePrefix+_39+this._scopeSuffix;}if(d.isMoz){_39+="\r\n//@ sourceURL="+uri;}var _3a=d["eval"](_39);if(cb){cb(_3a);}return true;};dojo._loadUriAndCheck=function(uri,_3c,cb){var ok=false;try{ok=this._loadUri(uri,cb);}catch(e){console.error("failed loading "+uri+" with error: "+e);}return !!(ok&&this._loadedModules[_3c]);};dojo.loaded=function(){this._loadNotifying=true;this._postLoad=true;var mll=d._loaders;this._loaders=[];for(var x=0;x<mll.length;x++){try{mll[x]();}catch(e){throw e;console.error("dojo.addOnLoad callback failed: "+e,e);}}this._loadNotifying=false;if(d._postLoad&&d._inFlightCount==0&&mll.length){d._callLoaded();}};dojo.unloaded=function(){var mll=this._unloaders;while(mll.length){(mll.pop())();}};var _42=function(arr,obj,fn){if(!fn){arr.push(obj);}else{if(fn){var _46=(typeof fn=="string")?obj[fn]:fn;arr.push(function(){_46.call(obj);});}}};dojo.addOnLoad=function(obj,_48){_42(d._loaders,obj,_48);if(d._postLoad&&d._inFlightCount==0&&!d._loadNotifying){d._callLoaded();}};dojo.addOnUnload=function(obj,_4a){_42(d._unloaders,obj,_4a);};dojo._modulesLoaded=function(){if(d._postLoad){return;}if(d._inFlightCount>0){console.warn("files still in flight!");return;}d._callLoaded();};dojo._callLoaded=function(){if(typeof setTimeout=="object"||(dojo.config.useXDomain&&d.isOpera)){if(dojo.isAIR){setTimeout(function(){dojo.loaded();},0);}else{setTimeout(dojo._scopeName+".loaded();",0);}}else{d.loaded();}};dojo._getModuleSymbols=function(_4b){var _4c=_4b.split(".");for(var i=_4c.length;i>0;i--){var _4e=_4c.slice(0,i).join(".");if((i==1)&&!this._moduleHasPrefix(_4e)){_4c[0]="../"+_4c[0];}else{var _4f=this._getModulePrefix(_4e);if(_4f!=_4e){_4c.splice(0,i,_4f);break;}}}return _4c;};dojo._global_omit_module_check=false;dojo._loadModule=dojo.require=function(_50,_51){_51=this._global_omit_module_check||_51;var _52=this._loadedModules[_50];if(_52){return _52;}var _53=this._getModuleSymbols(_50).join("/")+".js";var _54=(!_51)?_50:null;var ok=this._loadPath(_53,_54);if(!ok&&!_51){throw new Error("Could not load '"+_50+"'; last tried '"+_53+"'");}if(!_51&&!this._isXDomain){_52=this._loadedModules[_50];if(!_52){throw new Error("symbol '"+_50+"' is not defined after loading '"+_53+"'");}}return _52;};dojo.provide=function(_56){_56=_56+"";return (d._loadedModules[_56]=d.getObject(_56,true));};dojo.platformRequire=function(_57){var _58=_57.common||[];var _59=_58.concat(_57[d._name]||_57["default"]||[]);for(var x=0;x<_59.length;x++){var _5b=_59[x];if(_5b.constructor==Array){d._loadModule.apply(d,_5b);}else{d._loadModule(_5b);}}};dojo.requireIf=function(_5c,_5d){if(_5c===true){var _5e=[];for(var i=1;i<arguments.length;i++){_5e.push(arguments[i]);}d.require.apply(d,_5e);}};dojo.requireAfterIf=d.requireIf;dojo.registerModulePath=function(_60,_61){d._modulePrefixes[_60]={name:_60,value:_61};};dojo.requireLocalization=function(_62,_63,_64,_65){d.require("dojo.i18n");d.i18n._requireLocalization.apply(d.hostenv,arguments);};var ore=new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$");var ire=new RegExp("^((([^:]+:)?([^@]+))@)?([^:]*)(:([0-9]+))?$");dojo._Url=function(){var n=null;var _a=arguments;var uri=[_a[0]];for(var i=1;i<_a.length;i++){if(!_a[i]){continue;}var _6c=new d._Url(_a[i]+"");var _6d=new d._Url(uri[0]+"");if(_6c.path==""&&!_6c.scheme&&!_6c.authority&&!_6c.query){if(_6c.fragment!=n){_6d.fragment=_6c.fragment;}_6c=_6d;}else{if(!_6c.scheme){_6c.scheme=_6d.scheme;if(!_6c.authority){_6c.authority=_6d.authority;if(_6c.path.charAt(0)!="/"){var _6e=_6d.path.substring(0,_6d.path.lastIndexOf("/")+1)+_6c.path;var _6f=_6e.split("/");for(var j=0;j<_6f.length;j++){if(_6f[j]=="."){if(j==_6f.length-1){_6f[j]="";}else{_6f.splice(j,1);j--;}}else{if(j>0&&!(j==1&&_6f[0]=="")&&_6f[j]==".."&&_6f[j-1]!=".."){if(j==(_6f.length-1)){_6f.splice(j,1);_6f[j-1]="";}else{_6f.splice(j-1,2);j-=2;}}}}_6c.path=_6f.join("/");}}}}uri=[];if(_6c.scheme){uri.push(_6c.scheme,":");}if(_6c.authority){uri.push("//",_6c.authority);}uri.push(_6c.path);if(_6c.query){uri.push("?",_6c.query);}if(_6c.fragment){uri.push("#",_6c.fragment);}}this.uri=uri.join("");var r=this.uri.match(ore);this.scheme=r[2]||(r[1]?"":n);this.authority=r[4]||(r[3]?"":n);this.path=r[5];this.query=r[7]||(r[6]?"":n);this.fragment=r[9]||(r[8]?"":n);if(this.authority!=n){r=this.authority.match(ire);this.user=r[3]||n;this.password=r[4]||n;this.host=r[5];this.port=r[7]||n;}};dojo._Url.prototype.toString=function(){return this.uri;};dojo.moduleUrl=function(_72,url){var loc=d._getModuleSymbols(_72).join("/");if(!loc){return null;}if(loc.lastIndexOf("/")!=loc.length-1){loc+="/";}var _75=loc.indexOf(":");if(loc.charAt(0)!="/"&&(_75==-1||_75>loc.indexOf("/"))){loc=d.baseUrl+loc;}return new d._Url(loc,url);};})();if(typeof window!="undefined"){dojo.isBrowser=true;dojo._name="browser";(function(){var d=dojo;if(document&&document.getElementsByTagName){var _77=document.getElementsByTagName("script");var _78=/dojo(\.xd)?\.js(\W|$)/i;for(var i=0;i<_77.length;i++){var src=_77[i].getAttribute("src");if(!src){continue;}var m=src.match(_78);if(m){if(!d.config.baseUrl){d.config.baseUrl=src.substring(0,m.index);}var cfg=_77[i].getAttribute("djConfig");if(cfg){var _7d=eval("({ "+cfg+" })");for(var x in _7d){dojo.config[x]=_7d[x];}}break;}}}d.baseUrl=d.config.baseUrl;var n=navigator;var dua=n.userAgent;var dav=n.appVersion;var tv=parseFloat(dav);d.isOpera=(dua.indexOf("Opera")>=0)?tv:0;var idx=Math.max(dav.indexOf("WebKit"),dav.indexOf("Safari"),0);if(idx){d.isSafari=parseFloat(dav.split("Version/")[1])||((parseFloat(dav.substr(idx+7))>=419.3)?3:2)||2;}d.isAIR=(dua.indexOf("AdobeAIR")>=0)?1:0;d.isKhtml=(dav.indexOf("Konqueror")>=0||d.isSafari)?tv:0;d.isMozilla=d.isMoz=(dua.indexOf("Gecko")>=0&&!d.isKhtml)?tv:0;d.isFF=d.isIE=0;if(d.isMoz){d.isFF=parseFloat(dua.split("Firefox/")[1])||0;}if(document.all&&!d.isOpera){d.isIE=parseFloat(dav.split("MSIE ")[1])||0;}if(dojo.isIE&&window.location.protocol==="file:"){dojo.config.ieForceActiveXXhr=true;}var cm=document.compatMode;d.isQuirks=cm=="BackCompat"||cm=="QuirksMode"||d.isIE<6;d.locale=dojo.config.locale||(d.isIE?n.userLanguage:n.language).toLowerCase();d._XMLHTTP_PROGIDS=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"];d._xhrObj=function(){var _85=null;var _86=null;if(!dojo.isIE||!dojo.config.ieForceActiveXXhr){try{_85=new XMLHttpRequest();}catch(e){}}if(!_85){for(var i=0;i<3;++i){var _88=d._XMLHTTP_PROGIDS[i];try{_85=new ActiveXObject(_88);}catch(e){_86=e;}if(_85){d._XMLHTTP_PROGIDS=[_88];break;}}}if(!_85){throw new Error("XMLHTTP not available: "+_86);}return _85;};d._isDocumentOk=function(_89){var _8a=_89.status||0;return (_8a>=200&&_8a<300)||_8a==304||_8a==1223||(!_8a&&(location.protocol=="file:"||location.protocol=="chrome:"));};var _8b=window.location+"";var _8c=document.getElementsByTagName("base");var _8d=(_8c&&_8c.length>0);d._getText=function(uri,_8f){var _90=this._xhrObj();if(!_8d&&dojo._Url){uri=(new dojo._Url(_8b,uri)).toString();}if(d.config.cacheBust){uri+=(uri.indexOf("?")==-1?"?":"&")+String(d.config.cacheBust).replace(/\W+/g,"");}_90.open("GET",uri,false);try{_90.send(null);if(!d._isDocumentOk(_90)){var err=Error("Unable to load "+uri+" status:"+_90.status);err.status=_90.status;err.responseText=_90.responseText;throw err;}}catch(e){if(_8f){return null;}throw e;}return _90.responseText;};})();dojo._initFired=false;dojo._loadInit=function(e){dojo._initFired=true;var _93=(e&&e.type)?e.type.toLowerCase():"load";if(arguments.callee.initialized||(_93!="domcontentloaded"&&_93!="load")){return;}arguments.callee.initialized=true;if("_khtmlTimer" in dojo){clearInterval(dojo._khtmlTimer);delete dojo._khtmlTimer;}if(dojo._inFlightCount==0){dojo._modulesLoaded();}};dojo._fakeLoadInit=function(){dojo._loadInit({type:"load"});};if(!dojo.config.afterOnLoad){if(document.addEventListener){if(dojo.isOpera||dojo.isFF>=3||(dojo.isMoz&&dojo.config.enableMozDomContentLoaded===true)){document.addEventListener("DOMContentLoaded",dojo._loadInit,null);}window.addEventListener("load",dojo._loadInit,null);}if(dojo.isAIR){window.addEventListener("load",dojo._loadInit,null);}else{if(/(WebKit|khtml)/i.test(navigator.userAgent)){dojo._khtmlTimer=setInterval(function(){if(/loaded|complete/.test(document.readyState)){dojo._loadInit();}},10);}}}(function(){var _w=window;var _95=function(_96,fp){var _98=_w[_96]||function(){};_w[_96]=function(){fp.apply(_w,arguments);_98.apply(_w,arguments);};};if(dojo.isIE){if(!dojo.config.afterOnLoad){document.write("<scr"+"ipt defer src=\"//:\" "+"onreadystatechange=\"if(this.readyState=='complete'){"+dojo._scopeName+"._loadInit();}\">"+"</scr"+"ipt>");}var _99=true;_95("onbeforeunload",function(){_w.setTimeout(function(){_99=false;},0);});_95("onunload",function(){if(_99){dojo.unloaded();}});try{document.namespaces.add("v","urn:schemas-microsoft-com:vml");document.createStyleSheet().addRule("v\\:*","behavior:url(#default#VML)");}catch(e){}}else{_95("onbeforeunload",function(){dojo.unloaded();});}})();}(function(){var mp=dojo.config["modulePaths"];if(mp){for(var _9b in mp){dojo.registerModulePath(_9b,mp[_9b]);}}})();if(dojo.config.isDebug){dojo.require("dojo._firebug.firebug");}if(dojo.config.debugAtAllCosts){dojo.config.useXDomain=true;dojo.require("dojo._base._loader.loader_xd");dojo.require("dojo._base._loader.loader_debug");dojo.require("dojo.i18n");}if(!dojo._hasResource["dojo._base.lang"]){dojo._hasResource["dojo._base.lang"]=true;dojo.provide("dojo._base.lang");dojo.isString=function(it){return !!arguments.length&&it!=null&&(typeof it=="string"||it instanceof String);};dojo.isArray=function(it){return it&&(it instanceof Array||typeof it=="array");};dojo.isFunction=(function(){var _9e=function(it){return it&&(typeof it=="function"||it instanceof Function);};return dojo.isSafari?function(it){if(typeof it=="function"&&it=="[object NodeList]"){return false;}return _9e(it);}:_9e;})();dojo.isObject=function(it){return it!==undefined&&(it===null||typeof it=="object"||dojo.isArray(it)||dojo.isFunction(it));};dojo.isArrayLike=function(it){var d=dojo;return it&&it!==undefined&&!d.isString(it)&&!d.isFunction(it)&&!(it.tagName&&it.tagName.toLowerCase()=="form")&&(d.isArray(it)||isFinite(it.length));};dojo.isAlien=function(it){return it&&!dojo.isFunction(it)&&/\{\s*\[native code\]\s*\}/.test(String(it));};dojo.extend=function(_a5,_a6){for(var i=1,l=arguments.length;i<l;i++){dojo._mixin(_a5.prototype,arguments[i]);}return _a5;};dojo._hitchArgs=function(_a9,_aa){var pre=dojo._toArray(arguments,2);var _ac=dojo.isString(_aa);return function(){var _ad=dojo._toArray(arguments);var f=_ac?(_a9||dojo.global)[_aa]:_aa;return f&&f.apply(_a9||this,pre.concat(_ad));};};dojo.hitch=function(_af,_b0){if(arguments.length>2){return dojo._hitchArgs.apply(dojo,arguments);}if(!_b0){_b0=_af;_af=null;}if(dojo.isString(_b0)){_af=_af||dojo.global;if(!_af[_b0]){throw (["dojo.hitch: scope[\"",_b0,"\"] is null (scope=\"",_af,"\")"].join(""));}return function(){return _af[_b0].apply(_af,arguments||[]);};}return !_af?_b0:function(){return _b0.apply(_af,arguments||[]);};};dojo.delegate=dojo._delegate=function(obj,_b2){function TMP(){};TMP.prototype=obj;var tmp=new TMP();if(_b2){dojo.mixin(tmp,_b2);}return tmp;};dojo.partial=function(_b4){var arr=[null];return dojo.hitch.apply(dojo,arr.concat(dojo._toArray(arguments)));};dojo._toArray=function(obj,_b7,_b8){var arr=_b8||[];for(var x=_b7||0;x<obj.length;x++){arr.push(obj[x]);}return arr;};dojo.clone=function(o){if(!o){return o;}if(dojo.isArray(o)){var r=[];for(var i=0;i<o.length;++i){r.push(dojo.clone(o[i]));}return r;}if(!dojo.isObject(o)){return o;}if(o.nodeType&&o.cloneNode){return o.cloneNode(true);}if(o instanceof Date){return new Date(o.getTime());}var r=new o.constructor();for(var i in o){if(!(i in r)||r[i]!=o[i]){r[i]=dojo.clone(o[i]);}}return r;};dojo.trim=function(str){return str.replace(/^\s\s*/,"").replace(/\s\s*$/,"");};}if(!dojo._hasResource["dojo._base.declare"]){dojo._hasResource["dojo._base.declare"]=true;dojo.provide("dojo._base.declare");dojo.declare=function(_bf,_c0,_c1){var dd=arguments.callee,_c3;if(dojo.isArray(_c0)){_c3=_c0;_c0=_c3.shift();}if(_c3){dojo.forEach(_c3,function(m){if(!m){throw (_bf+": mixin #"+i+" is null");}_c0=dd._delegate(_c0,m);});}var _c5=(_c1||0).constructor,_c6=dd._delegate(_c0),fn;for(var i in _c1){if(dojo.isFunction(fn=_c1[i])&&!0[i]){fn.nom=i;}}dojo.extend(_c6,{declaredClass:_bf,_constructor:_c5,preamble:null},_c1||0);_c6.prototype.constructor=_c6;return dojo.setObject(_bf,_c6);};dojo.mixin(dojo.declare,{_delegate:function(_c9,_ca){var bp=(_c9||0).prototype,mp=(_ca||0).prototype;var _cd=dojo.declare._makeCtor();dojo.mixin(_cd,{superclass:bp,mixin:mp,extend:dojo.declare._extend});if(_c9){_cd.prototype=dojo._delegate(bp);}dojo.extend(_cd,dojo.declare._core,mp||0,{_constructor:null,preamble:null});_cd.prototype.constructor=_cd;_cd.prototype.declaredClass=(bp||0).declaredClass+"_"+(mp||0).declaredClass;return _cd;},_extend:function(_ce){for(var i in _ce){if(dojo.isFunction(fn=_ce[i])&&!0[i]){fn.nom=i;}}dojo.extend(this,_ce);},_makeCtor:function(){return function(){this._construct(arguments);};},_core:{_construct:function(_d0){var c=_d0.callee,s=c.superclass,ct=s&&s.constructor,m=c.mixin,mct=m&&m.constructor,a=_d0,ii,fn;if(a[0]){if(((fn=a[0].preamble))){a=fn.apply(this,a)||a;}}if((fn=c.prototype.preamble)){a=fn.apply(this,a)||a;}if(ct&&ct.apply){ct.apply(this,a);}if(mct&&mct.apply){mct.apply(this,a);}if((ii=c.prototype._constructor)){ii.apply(this,_d0);}if(this.constructor.prototype==c.prototype&&(ct=this.postscript)){ct.apply(this,_d0);}},_findMixin:function(_d9){var c=this.constructor,p,m;while(c){p=c.superclass;m=c.mixin;if(m==_d9||(m instanceof _d9.constructor)){return p;}if(m&&(m=m._findMixin(_d9))){return m;}c=p&&p.constructor;}},_findMethod:function(_dd,_de,_df,has){var p=_df,c,m,f;do{c=p.constructor;m=c.mixin;if(m&&(m=this._findMethod(_dd,_de,m,has))){return m;}if((f=p[_dd])&&(has==(f==_de))){return p;}p=c.superclass;}while(p);return !has&&(p=this._findMixin(_df))&&this._findMethod(_dd,_de,p,has);},inherited:function(_e5,_e6,_e7){var a=arguments;if(!dojo.isString(a[0])){_e7=_e6;_e6=_e5;_e5=_e6.callee.nom;}a=_e7||_e6;var c=_e6.callee,p=this.constructor.prototype,fn,mp;if(this[_e5]!=c||p[_e5]==c){mp=this._findMethod(_e5,c,p,true);if(!mp){throw (this.declaredClass+": inherited method \""+_e5+"\" mismatch");}p=this._findMethod(_e5,c,mp,false);}fn=p&&p[_e5];if(!fn){throw (mp.declaredClass+": inherited method \""+_e5+"\" not found");}return fn.apply(this,a);}}});}if(!dojo._hasResource["dojo._base.connect"]){dojo._hasResource["dojo._base.connect"]=true;dojo.provide("dojo._base.connect");dojo._listener={getDispatcher:function(){return function(){var ap=Array.prototype,c=arguments.callee,ls=c._listeners,t=c.target;var r=t&&t.apply(this,arguments);for(var i in ls){if(!(i in ap)){ls[i].apply(this,arguments);}}return r;};},add:function(_f3,_f4,_f5){_f3=_f3||dojo.global;var f=_f3[_f4];if(!f||!f._listeners){var d=dojo._listener.getDispatcher();d.target=f;d._listeners=[];f=_f3[_f4]=d;}return f._listeners.push(_f5);},remove:function(_f8,_f9,_fa){var f=(_f8||dojo.global)[_f9];if(f&&f._listeners&&_fa--){delete f._listeners[_fa];}}};dojo.connect=function(obj,_fd,_fe,_ff,_100){var a=arguments,args=[],i=0;args.push(dojo.isString(a[0])?null:a[i++],a[i++]);var a1=a[i+1];args.push(dojo.isString(a1)||dojo.isFunction(a1)?a[i++]:null,a[i++]);for(var l=a.length;i<l;i++){args.push(a[i]);}return dojo._connect.apply(this,args);};dojo._connect=function(obj,_106,_107,_108){var l=dojo._listener,h=l.add(obj,_106,dojo.hitch(_107,_108));return [obj,_106,h,l];};dojo.disconnect=function(_10b){if(_10b&&_10b[0]!==undefined){dojo._disconnect.apply(this,_10b);delete _10b[0];}};dojo._disconnect=function(obj,_10d,_10e,_10f){_10f.remove(obj,_10d,_10e);};dojo._topics={};dojo.subscribe=function(_110,_111,_112){return [_110,dojo._listener.add(dojo._topics,_110,dojo.hitch(_111,_112))];};dojo.unsubscribe=function(_113){if(_113){dojo._listener.remove(dojo._topics,_113[0],_113[1]);}};dojo.publish=function(_114,args){var f=dojo._topics[_114];if(f){f.apply(this,args||[]);}};dojo.connectPublisher=function(_117,obj,_119){var pf=function(){dojo.publish(_117,arguments);};return (_119)?dojo.connect(obj,_119,pf):dojo.connect(obj,pf);};}if(!dojo._hasResource["dojo._base.Deferred"]){dojo._hasResource["dojo._base.Deferred"]=true;dojo.provide("dojo._base.Deferred");dojo.Deferred=function(_11b){this.chain=[];this.id=this._nextId();this.fired=-1;this.paused=0;this.results=[null,null];this.canceller=_11b;this.silentlyCancelled=false;};dojo.extend(dojo.Deferred,{_nextId:(function(){var n=1;return function(){return n++;};})(),cancel:function(){var err;if(this.fired==-1){if(this.canceller){err=this.canceller(this);}else{this.silentlyCancelled=true;}if(this.fired==-1){if(!(err instanceof Error)){var res=err;err=new Error("Deferred Cancelled");err.dojoType="cancel";err.cancelResult=res;}this.errback(err);}}else{if((this.fired==0)&&(this.results[0] instanceof dojo.Deferred)){this.results[0].cancel();}}},_resback:function(res){this.fired=((res instanceof Error)?1:0);this.results[this.fired]=res;this._fire();},_check:function(){if(this.fired!=-1){if(!this.silentlyCancelled){throw new Error("already called!");}this.silentlyCancelled=false;return;}},callback:function(res){this._check();this._resback(res);},errback:function(res){this._check();if(!(res instanceof Error)){res=new Error(res);}this._resback(res);},addBoth:function(cb,cbfn){var _124=dojo.hitch.apply(dojo,arguments);return this.addCallbacks(_124,_124);},addCallback:function(cb,cbfn){return this.addCallbacks(dojo.hitch.apply(dojo,arguments));},addErrback:function(cb,cbfn){return this.addCallbacks(null,dojo.hitch.apply(dojo,arguments));},addCallbacks:function(cb,eb){this.chain.push([cb,eb]);if(this.fired>=0){this._fire();}return this;},_fire:function(){var _12b=this.chain;var _12c=this.fired;var res=this.results[_12c];var self=this;var cb=null;while((_12b.length>0)&&(this.paused==0)){var f=_12b.shift()[_12c];if(!f){continue;}try{res=f(res);_12c=((res instanceof Error)?1:0);if(res instanceof dojo.Deferred){cb=function(res){self._resback(res);self.paused--;if((self.paused==0)&&(self.fired>=0)){self._fire();}};this.paused++;}}catch(err){console.debug(err);_12c=1;res=err;}}this.fired=_12c;this.results[_12c]=res;if((cb)&&(this.paused)){res.addBoth(cb);}}});}if(!dojo._hasResource["dojo._base.json"]){dojo._hasResource["dojo._base.json"]=true;dojo.provide("dojo._base.json");dojo.fromJson=function(json){return eval("("+json+")");};dojo._escapeString=function(str){return ("\""+str.replace(/(["\\])/g,"\\$1")+"\"").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r");};dojo.toJsonIndentStr="\t";dojo.toJson=function(it,_135,_136){if(it===undefined){return "undefined";}var _137=typeof it;if(_137=="number"||_137=="boolean"){return it+"";}if(it===null){return "null";}if(dojo.isString(it)){return dojo._escapeString(it);}if(it.nodeType&&it.cloneNode){return "";}var _138=arguments.callee;var _139;_136=_136||"";var _13a=_135?_136+dojo.toJsonIndentStr:"";if(typeof it.__json__=="function"){_139=it.__json__();if(it!==_139){return _138(_139,_135,_13a);}}if(typeof it.json=="function"){_139=it.json();if(it!==_139){return _138(_139,_135,_13a);}}var sep=_135?" ":"";var _13c=_135?"\n":"";if(dojo.isArray(it)){var res=dojo.map(it,function(obj){var val=_138(obj,_135,_13a);if(typeof val!="string"){val="undefined";}return _13c+_13a+val;});return "["+res.join(","+sep)+_13c+_136+"]";}if(_137=="function"){return null;}var _140=[];for(var key in it){var _142;if(typeof key=="number"){_142="\""+key+"\"";}else{if(typeof key=="string"){_142=dojo._escapeString(key);}else{continue;}}val=_138(it[key],_135,_13a);if(typeof val!="string"){continue;}_140.push(_13c+_13a+_142+":"+sep+val);}return "{"+_140.join(","+sep)+_13c+_136+"}";};}if(!dojo._hasResource["dojo._base.array"]){dojo._hasResource["dojo._base.array"]=true;dojo.provide("dojo._base.array");(function(){var _143=function(arr,obj,cb){return [dojo.isString(arr)?arr.split(""):arr,obj||dojo.global,dojo.isString(cb)?new Function("item","index","array",cb):cb];};dojo.mixin(dojo,{indexOf:function(_147,_148,_149,_14a){var step=1,end=_147.length||0,i=0;if(_14a){i=end-1;step=end=-1;}if(_149!=undefined){i=_149;}if((_14a&&i>end)||i<end){for(;i!=end;i+=step){if(_147[i]==_148){return i;}}}return -1;},lastIndexOf:function(_14d,_14e,_14f){return dojo.indexOf(_14d,_14e,_14f,true);},forEach:function(arr,_151,_152){if(!arr||!arr.length){return;}var _p=_143(arr,_152,_151);arr=_p[0];for(var i=0,l=_p[0].length;i<l;i++){_p[2].call(_p[1],arr[i],i,arr);}},_everyOrSome:function(_156,arr,_158,_159){var _p=_143(arr,_159,_158);arr=_p[0];for(var i=0,l=arr.length;i<l;i++){var _15d=!!_p[2].call(_p[1],arr[i],i,arr);if(_156^_15d){return _15d;}}return _156;},every:function(arr,_15f,_160){return this._everyOrSome(true,arr,_15f,_160);},some:function(arr,_162,_163){return this._everyOrSome(false,arr,_162,_163);},map:function(arr,_165,_166){var _p=_143(arr,_166,_165);arr=_p[0];var _168=(arguments[3]?(new arguments[3]()):[]);for(var i=0;i<arr.length;++i){_168.push(_p[2].call(_p[1],arr[i],i,arr));}return _168;},filter:function(arr,_16b,_16c){var _p=_143(arr,_16c,_16b);arr=_p[0];var _16e=[];for(var i=0;i<arr.length;i++){if(_p[2].call(_p[1],arr[i],i,arr)){_16e.push(arr[i]);}}return _16e;}});})();}if(!dojo._hasResource["dojo._base.Color"]){dojo._hasResource["dojo._base.Color"]=true;dojo.provide("dojo._base.Color");dojo.Color=function(_170){if(_170){this.setColor(_170);}};dojo.Color.named={black:[0,0,0],silver:[192,192,192],gray:[128,128,128],white:[255,255,255],maroon:[128,0,0],red:[255,0,0],purple:[128,0,128],fuchsia:[255,0,255],green:[0,128,0],lime:[0,255,0],olive:[128,128,0],yellow:[255,255,0],navy:[0,0,128],blue:[0,0,255],teal:[0,128,128],aqua:[0,255,255]};dojo.extend(dojo.Color,{r:255,g:255,b:255,a:1,_set:function(r,g,b,a){var t=this;t.r=r;t.g=g;t.b=b;t.a=a;},setColor:function(_176){var d=dojo;if(d.isString(_176)){d.colorFromString(_176,this);}else{if(d.isArray(_176)){d.colorFromArray(_176,this);}else{this._set(_176.r,_176.g,_176.b,_176.a);if(!(_176 instanceof d.Color)){this.sanitize();}}}return this;},sanitize:function(){return this;},toRgb:function(){var t=this;return [t.r,t.g,t.b];},toRgba:function(){var t=this;return [t.r,t.g,t.b,t.a];},toHex:function(){var arr=dojo.map(["r","g","b"],function(x){var s=this[x].toString(16);return s.length<2?"0"+s:s;},this);return "#"+arr.join("");},toCss:function(_17d){var t=this,rgb=t.r+", "+t.g+", "+t.b;return (_17d?"rgba("+rgb+", "+t.a:"rgb("+rgb)+")";},toString:function(){return this.toCss(true);}});dojo.blendColors=function(_180,end,_182,obj){var d=dojo,t=obj||new dojo.Color();d.forEach(["r","g","b","a"],function(x){t[x]=_180[x]+(end[x]-_180[x])*_182;if(x!="a"){t[x]=Math.round(t[x]);}});return t.sanitize();};dojo.colorFromRgb=function(_187,obj){var m=_187.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/);return m&&dojo.colorFromArray(m[1].split(/\s*,\s*/),obj);};dojo.colorFromHex=function(_18a,obj){var d=dojo,t=obj||new d.Color(),bits=(_18a.length==4)?4:8,mask=(1<<bits)-1;_18a=Number("0x"+_18a.substr(1));if(isNaN(_18a)){return null;}d.forEach(["b","g","r"],function(x){var c=_18a&mask;_18a>>=bits;t[x]=bits==4?17*c:c;});t.a=1;return t;};dojo.colorFromArray=function(a,obj){var t=obj||new dojo.Color();t._set(Number(a[0]),Number(a[1]),Number(a[2]),Number(a[3]));if(isNaN(t.a)){t.a=1;}return t.sanitize();};dojo.colorFromString=function(str,obj){var a=dojo.Color.named[str];return a&&dojo.colorFromArray(a,obj)||dojo.colorFromRgb(str,obj)||dojo.colorFromHex(str,obj);};}if(!dojo._hasResource["dojo._base"]){dojo._hasResource["dojo._base"]=true;dojo.provide("dojo._base");}if(!dojo._hasResource["dojo._base.window"]){dojo._hasResource["dojo._base.window"]=true;dojo.provide("dojo._base.window");dojo._gearsObject=function(){var _198;var _199;var _19a=dojo.getObject("google.gears");if(_19a){return _19a;}if(typeof GearsFactory!="undefined"){_198=new GearsFactory();}else{if(dojo.isIE){try{_198=new ActiveXObject("Gears.Factory");}catch(e){}}else{if(navigator.mimeTypes["application/x-googlegears"]){_198=document.createElement("object");_198.setAttribute("type","application/x-googlegears");_198.setAttribute("width",0);_198.setAttribute("height",0);_198.style.display="none";document.documentElement.appendChild(_198);}}}if(!_198){return null;}dojo.setObject("google.gears.factory",_198);return dojo.getObject("google.gears");};dojo.isGears=(!!dojo._gearsObject())||0;dojo.doc=window["document"]||null;dojo.body=function(){return dojo.doc.body||dojo.doc.getElementsByTagName("body")[0];};dojo.setContext=function(_19b,_19c){dojo.global=_19b;dojo.doc=_19c;};dojo._fireCallback=function(_19d,_19e,_19f){if(_19e&&dojo.isString(_19d)){_19d=_19e[_19d];}return _19d.apply(_19e,_19f||[]);};dojo.withGlobal=function(_1a0,_1a1,_1a2,_1a3){var rval;var _1a5=dojo.global;var _1a6=dojo.doc;try{dojo.setContext(_1a0,_1a0.document);rval=dojo._fireCallback(_1a1,_1a2,_1a3);}finally{dojo.setContext(_1a5,_1a6);}return rval;};dojo.withDoc=function(_1a7,_1a8,_1a9,_1aa){var rval;var _1ac=dojo.doc;try{dojo.doc=_1a7;rval=dojo._fireCallback(_1a8,_1a9,_1aa);}finally{dojo.doc=_1ac;}return rval;};}if(!dojo._hasResource["dojo._base.event"]){dojo._hasResource["dojo._base.event"]=true;dojo.provide("dojo._base.event");(function(){var del=(dojo._event_listener={add:function(node,name,fp){if(!node){return;}name=del._normalizeEventName(name);fp=del._fixCallback(name,fp);var _1b1=name;if(!dojo.isIE&&(name=="mouseenter"||name=="mouseleave")){var ofp=fp;name=(name=="mouseenter")?"mouseover":"mouseout";fp=function(e){if(!dojo.isDescendant(e.relatedTarget,node)){return ofp.call(this,e);}};}node.addEventListener(name,fp,false);return fp;},remove:function(node,_1b5,_1b6){if(node){node.removeEventListener(del._normalizeEventName(_1b5),_1b6,false);}},_normalizeEventName:function(name){return name.slice(0,2)=="on"?name.slice(2):name;},_fixCallback:function(name,fp){return name!="keypress"?fp:function(e){return fp.call(this,del._fixEvent(e,this));};},_fixEvent:function(evt,_1bc){switch(evt.type){case "keypress":del._setKeyChar(evt);break;}return evt;},_setKeyChar:function(evt){evt.keyChar=evt.charCode?String.fromCharCode(evt.charCode):"";}});dojo.fixEvent=function(evt,_1bf){return del._fixEvent(evt,_1bf);};dojo.stopEvent=function(evt){evt.preventDefault();evt.stopPropagation();};var _1c1=dojo._listener;dojo._connect=function(obj,_1c3,_1c4,_1c5,_1c6){var _1c7=obj&&(obj.nodeType||obj.attachEvent||obj.addEventListener);var lid=!_1c7?0:(!_1c6?1:2),l=[dojo._listener,del,_1c1][lid];var h=l.add(obj,_1c3,dojo.hitch(_1c4,_1c5));return [obj,_1c3,h,lid];};dojo._disconnect=function(obj,_1cc,_1cd,_1ce){([dojo._listener,del,_1c1][_1ce]).remove(obj,_1cc,_1cd);};dojo.keys={BACKSPACE:8,TAB:9,CLEAR:12,ENTER:13,SHIFT:16,CTRL:17,ALT:18,PAUSE:19,CAPS_LOCK:20,ESCAPE:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT_ARROW:37,UP_ARROW:38,RIGHT_ARROW:39,DOWN_ARROW:40,INSERT:45,DELETE:46,HELP:47,LEFT_WINDOW:91,RIGHT_WINDOW:92,SELECT:93,NUMPAD_0:96,NUMPAD_1:97,NUMPAD_2:98,NUMPAD_3:99,NUMPAD_4:100,NUMPAD_5:101,NUMPAD_6:102,NUMPAD_7:103,NUMPAD_8:104,NUMPAD_9:105,NUMPAD_MULTIPLY:106,NUMPAD_PLUS:107,NUMPAD_ENTER:108,NUMPAD_MINUS:109,NUMPAD_PERIOD:110,NUMPAD_DIVIDE:111,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,F13:124,F14:125,F15:126,NUM_LOCK:144,SCROLL_LOCK:145};if(dojo.isIE){var _1cf=function(e,code){try{return (e.keyCode=code);}catch(e){return 0;}};var iel=dojo._listener;if(!dojo.config._allow_leaks){_1c1=iel=dojo._ie_listener={handlers:[],add:function(_1d3,_1d4,_1d5){_1d3=_1d3||dojo.global;var f=_1d3[_1d4];if(!f||!f._listeners){var d=dojo._getIeDispatcher();d.target=f&&(ieh.push(f)-1);d._listeners=[];f=_1d3[_1d4]=d;}return f._listeners.push(ieh.push(_1d5)-1);},remove:function(_1d9,_1da,_1db){var f=(_1d9||dojo.global)[_1da],l=f&&f._listeners;if(f&&l&&_1db--){delete ieh[l[_1db]];delete l[_1db];}}};var ieh=iel.handlers;}dojo.mixin(del,{add:function(node,_1df,fp){if(!node){return;}_1df=del._normalizeEventName(_1df);if(_1df=="onkeypress"){var kd=node.onkeydown;if(!kd||!kd._listeners||!kd._stealthKeydownHandle){var h=del.add(node,"onkeydown",del._stealthKeyDown);kd=node.onkeydown;kd._stealthKeydownHandle=h;kd._stealthKeydownRefs=1;}else{kd._stealthKeydownRefs++;}}return iel.add(node,_1df,del._fixCallback(fp));},remove:function(node,_1e4,_1e5){_1e4=del._normalizeEventName(_1e4);iel.remove(node,_1e4,_1e5);if(_1e4=="onkeypress"){var kd=node.onkeydown;if(--kd._stealthKeydownRefs<=0){iel.remove(node,"onkeydown",kd._stealthKeydownHandle);delete kd._stealthKeydownHandle;}}},_normalizeEventName:function(_1e7){return _1e7.slice(0,2)!="on"?"on"+_1e7:_1e7;},_nop:function(){},_fixEvent:function(evt,_1e9){if(!evt){var w=_1e9&&(_1e9.ownerDocument||_1e9.document||_1e9).parentWindow||window;evt=w.event;}if(!evt){return (evt);}evt.target=evt.srcElement;evt.currentTarget=(_1e9||evt.srcElement);evt.layerX=evt.offsetX;evt.layerY=evt.offsetY;var se=evt.srcElement,doc=(se&&se.ownerDocument)||document;var _1ed=((dojo.isIE<6)||(doc["compatMode"]=="BackCompat"))?doc.body:doc.documentElement;var _1ee=dojo._getIeDocumentElementOffset();evt.pageX=evt.clientX+dojo._fixIeBiDiScrollLeft(_1ed.scrollLeft||0)-_1ee.x;evt.pageY=evt.clientY+(_1ed.scrollTop||0)-_1ee.y;if(evt.type=="mouseover"){evt.relatedTarget=evt.fromElement;}if(evt.type=="mouseout"){evt.relatedTarget=evt.toElement;}evt.stopPropagation=del._stopPropagation;evt.preventDefault=del._preventDefault;return del._fixKeys(evt);},_fixKeys:function(evt){switch(evt.type){case "keypress":var c=("charCode" in evt?evt.charCode:evt.keyCode);if(c==10){c=0;evt.keyCode=13;}else{if(c==13||c==27){c=0;}else{if(c==3){c=99;}}}evt.charCode=c;del._setKeyChar(evt);break;}return evt;},_punctMap:{106:42,111:47,186:59,187:43,188:44,189:45,190:46,191:47,192:96,219:91,220:92,221:93,222:39},_stealthKeyDown:function(evt){var kp=evt.currentTarget.onkeypress;if(!kp||!kp._listeners){return;}var k=evt.keyCode;var _1f4=(k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);if(_1f4||evt.ctrlKey){var c=_1f4?0:k;if(evt.ctrlKey){if(k==3||k==13){return;}else{if(c>95&&c<106){c-=48;}else{if((!evt.shiftKey)&&(c>=65&&c<=90)){c+=32;}else{c=del._punctMap[c]||c;}}}}var faux=del._synthesizeEvent(evt,{type:"keypress",faux:true,charCode:c});kp.call(evt.currentTarget,faux);evt.cancelBubble=faux.cancelBubble;evt.returnValue=faux.returnValue;_1cf(evt,faux.keyCode);}},_stopPropagation:function(){this.cancelBubble=true;},_preventDefault:function(){this.bubbledKeyCode=this.keyCode;if(this.ctrlKey){_1cf(this,0);}this.returnValue=false;}});dojo.stopEvent=function(evt){evt=evt||window.event;del._stopPropagation.call(evt);del._preventDefault.call(evt);};}del._synthesizeEvent=function(evt,_1f9){var faux=dojo.mixin({},evt,_1f9);del._setKeyChar(faux);faux.preventDefault=function(){evt.preventDefault();};faux.stopPropagation=function(){evt.stopPropagation();};return faux;};if(dojo.isOpera){dojo.mixin(del,{_fixEvent:function(evt,_1fc){switch(evt.type){case "keypress":var c=evt.which;if(c==3){c=99;}c=((c<41)&&(!evt.shiftKey)?0:c);if((evt.ctrlKey)&&(!evt.shiftKey)&&(c>=65)&&(c<=90)){c+=32;}return del._synthesizeEvent(evt,{charCode:c});}return evt;}});}if(dojo.isSafari){dojo.mixin(del,{_fixEvent:function(evt,_1ff){switch(evt.type){case "keypress":var c=evt.charCode,s=evt.shiftKey,k=evt.keyCode;k=k||_203[evt.keyIdentifier]||0;if(evt.keyIdentifier=="Enter"){c=0;}else{if((evt.ctrlKey)&&(c>0)&&(c<27)){c+=96;}else{if(c==dojo.keys.SHIFT_TAB){c=dojo.keys.TAB;s=true;}else{c=(c>=32&&c<63232?c:0);}}}return del._synthesizeEvent(evt,{charCode:c,shiftKey:s,keyCode:k});}return evt;}});dojo.mixin(dojo.keys,{SHIFT_TAB:25,UP_ARROW:63232,DOWN_ARROW:63233,LEFT_ARROW:63234,RIGHT_ARROW:63235,F1:63236,F2:63237,F3:63238,F4:63239,F5:63240,F6:63241,F7:63242,F8:63243,F9:63244,F10:63245,F11:63246,F12:63247,PAUSE:63250,DELETE:63272,HOME:63273,END:63275,PAGE_UP:63276,PAGE_DOWN:63277,INSERT:63302,PRINT_SCREEN:63248,SCROLL_LOCK:63249,NUM_LOCK:63289});var dk=dojo.keys,_203={"Up":dk.UP_ARROW,"Down":dk.DOWN_ARROW,"Left":dk.LEFT_ARROW,"Right":dk.RIGHT_ARROW,"PageUp":dk.PAGE_UP,"PageDown":dk.PAGE_DOWN};}})();if(dojo.isIE){dojo._ieDispatcher=function(args,_206){var ap=Array.prototype,h=dojo._ie_listener.handlers,c=args.callee,ls=c._listeners,t=h[c.target];var r=t&&t.apply(_206,args);for(var i in ls){if(!(i in ap)){h[ls[i]].apply(_206,args);}}return r;};dojo._getIeDispatcher=function(){return new Function(dojo._scopeName+"._ieDispatcher(arguments, this)");};dojo._event_listener._fixCallback=function(fp){var f=dojo._event_listener._fixEvent;return function(e){return fp.call(this,f(e,this));};};}}if(!dojo._hasResource["dojo._base.html"]){dojo._hasResource["dojo._base.html"]=true;dojo.provide("dojo._base.html");try{document.execCommand("BackgroundImageCache",false,true);}catch(e){}if(dojo.isIE||dojo.isOpera){dojo.byId=function(id,doc){if(dojo.isString(id)){var _d=doc||dojo.doc;var te=_d.getElementById(id);if(te&&te.attributes.id.value==id){return te;}else{var eles=_d.all[id];if(!eles||!eles.length){return eles;}var i=0;while((te=eles[i++])){if(te.attributes.id.value==id){return te;}}}}else{return id;}};}else{dojo.byId=function(id,doc){return dojo.isString(id)?(doc||dojo.doc).getElementById(id):id;};}(function(){var d=dojo;var _21a=null;dojo.addOnUnload(function(){_21a=null;});dojo._destroyElement=function(node){node=d.byId(node);try{if(!_21a){_21a=document.createElement("div");}_21a.appendChild(node.parentNode?node.parentNode.removeChild(node):node);_21a.innerHTML="";}catch(e){}};dojo.isDescendant=function(node,_21d){try{node=d.byId(node);_21d=d.byId(_21d);while(node){if(node===_21d){return true;}node=node.parentNode;}}catch(e){}return false;};dojo.setSelectable=function(node,_21f){node=d.byId(node);if(d.isMozilla){node.style.MozUserSelect=_21f?"":"none";}else{if(d.isKhtml){node.style.KhtmlUserSelect=_21f?"auto":"none";}else{if(d.isIE){node.unselectable=_21f?"":"on";d.query("*",node).forEach(function(_220){_220.unselectable=_21f?"":"on";});}}}};var _221=function(node,ref){ref.parentNode.insertBefore(node,ref);return true;};var _224=function(node,ref){var pn=ref.parentNode;if(ref==pn.lastChild){pn.appendChild(node);}else{return _221(node,ref.nextSibling);}return true;};dojo.place=function(node,_229,_22a){if(!node||!_229||_22a===undefined){return false;}node=d.byId(node);_229=d.byId(_229);if(typeof _22a=="number"){var cn=_229.childNodes;if((_22a==0&&cn.length==0)||cn.length==_22a){_229.appendChild(node);return true;}if(_22a==0){return _221(node,_229.firstChild);}return _224(node,cn[_22a-1]);}switch(_22a.toLowerCase()){case "before":return _221(node,_229);case "after":return _224(node,_229);case "first":if(_229.firstChild){return _221(node,_229.firstChild);}default:_229.appendChild(node);return true;}};dojo.boxModel="content-box";if(d.isIE){var _dcm=document.compatMode;d.boxModel=_dcm=="BackCompat"||_dcm=="QuirksMode"||d.isIE<6?"border-box":"content-box";}var gcs,dv=document.defaultView;if(d.isSafari){gcs=function(node){var s=dv.getComputedStyle(node,null);if(!s&&node.style){node.style.display="";s=dv.getComputedStyle(node,null);}return s||{};};}else{if(d.isIE){gcs=function(node){return node.currentStyle;};}else{gcs=function(node){return dv.getComputedStyle(node,null);};}}dojo.getComputedStyle=gcs;if(!d.isIE){dojo._toPixelValue=function(_233,_234){return parseFloat(_234)||0;};}else{dojo._toPixelValue=function(_235,_236){if(!_236){return 0;}if(_236=="medium"){return 4;}if(_236.slice&&(_236.slice(-2)=="px")){return parseFloat(_236);}with(_235){var _237=style.left;var _238=runtimeStyle.left;runtimeStyle.left=currentStyle.left;try{style.left=_236;_236=style.pixelLeft;}catch(e){_236=0;}style.left=_237;runtimeStyle.left=_238;}return _236;};}var px=d._toPixelValue;dojo._getOpacity=d.isIE?function(node){try{return node.filters.alpha.opacity/100;}catch(e){return 1;}}:function(node){return gcs(node).opacity;};dojo._setOpacity=d.isIE?function(node,_23d){if(_23d==1){var _23e=/FILTER:[^;]*;?/i;node.style.cssText=node.style.cssText.replace(_23e,"");if(node.nodeName.toLowerCase()=="tr"){d.query("> td",node).forEach(function(i){i.style.cssText=i.style.cssText.replace(_23e,"");});}}else{var o="Alpha(Opacity="+_23d*100+")";node.style.filter=o;}if(node.nodeName.toLowerCase()=="tr"){d.query("> td",node).forEach(function(i){i.style.filter=o;});}return _23d;}:function(node,_243){return node.style.opacity=_243;};var _244={left:true,top:true};var _245=/margin|padding|width|height|max|min|offset/;var _246=function(node,type,_249){type=type.toLowerCase();if(d.isIE&&_249=="auto"){if(type=="height"){return node.offsetHeight;}if(type=="width"){return node.offsetWidth;}}if(!(type in _244)){_244[type]=_245.test(type);}return _244[type]?px(node,_249):_249;};var _24a=d.isIE?"styleFloat":"cssFloat";var _24b={"cssFloat":_24a,"styleFloat":_24a,"float":_24a};dojo.style=function(node,_24d,_24e){var n=d.byId(node),args=arguments.length,op=(_24d=="opacity");_24d=_24b[_24d]||_24d;if(args==3){return op?d._setOpacity(n,_24e):n.style[_24d]=_24e;}if(args==2&&op){return d._getOpacity(n);}var s=gcs(n);if(args==2&&!d.isString(_24d)){for(var x in _24d){d.style(node,x,_24d[x]);}return s;}return (args==1)?s:_246(n,_24d,s[_24d]);};dojo._getPadExtents=function(n,_255){var s=_255||gcs(n),l=px(n,s.paddingLeft),t=px(n,s.paddingTop);return {l:l,t:t,w:l+px(n,s.paddingRight),h:t+px(n,s.paddingBottom)};};dojo._getBorderExtents=function(n,_25a){var ne="none",s=_25a||gcs(n),bl=(s.borderLeftStyle!=ne?px(n,s.borderLeftWidth):0),bt=(s.borderTopStyle!=ne?px(n,s.borderTopWidth):0);return {l:bl,t:bt,w:bl+(s.borderRightStyle!=ne?px(n,s.borderRightWidth):0),h:bt+(s.borderBottomStyle!=ne?px(n,s.borderBottomWidth):0)};};dojo._getPadBorderExtents=function(n,_260){var s=_260||gcs(n),p=d._getPadExtents(n,s),b=d._getBorderExtents(n,s);return {l:p.l+b.l,t:p.t+b.t,w:p.w+b.w,h:p.h+b.h};};dojo._getMarginExtents=function(n,_265){var s=_265||gcs(n),l=px(n,s.marginLeft),t=px(n,s.marginTop),r=px(n,s.marginRight),b=px(n,s.marginBottom);if(d.isSafari&&(s.position!="absolute")){r=l;}return {l:l,t:t,w:l+r,h:t+b};};dojo._getMarginBox=function(node,_26c){var s=_26c||gcs(node),me=d._getMarginExtents(node,s);var l=node.offsetLeft-me.l,t=node.offsetTop-me.t;if(d.isMoz){var sl=parseFloat(s.left),st=parseFloat(s.top);if(!isNaN(sl)&&!isNaN(st)){l=sl,t=st;}else{var p=node.parentNode;if(p&&p.style){var pcs=gcs(p);if(pcs.overflow!="visible"){var be=d._getBorderExtents(p,pcs);l+=be.l,t+=be.t;}}}}else{if(d.isOpera){var p=node.parentNode;if(p){var be=d._getBorderExtents(p);l-=be.l,t-=be.t;}}}return {l:l,t:t,w:node.offsetWidth+me.w,h:node.offsetHeight+me.h};};dojo._getContentBox=function(node,_277){var s=_277||gcs(node),pe=d._getPadExtents(node,s),be=d._getBorderExtents(node,s),w=node.clientWidth,h;if(!w){w=node.offsetWidth,h=node.offsetHeight;}else{h=node.clientHeight,be.w=be.h=0;}if(d.isOpera){pe.l+=be.l;pe.t+=be.t;}return {l:pe.l,t:pe.t,w:w-pe.w-be.w,h:h-pe.h-be.h};};dojo._getBorderBox=function(node,_27e){var s=_27e||gcs(node),pe=d._getPadExtents(node,s),cb=d._getContentBox(node,s);return {l:cb.l-pe.l,t:cb.t-pe.t,w:cb.w+pe.w,h:cb.h+pe.h};};dojo._setBox=function(node,l,t,w,h,u){u=u||"px";var s=node.style;if(!isNaN(l)){s.left=l+u;}if(!isNaN(t)){s.top=t+u;}if(w>=0){s.width=w+u;}if(h>=0){s.height=h+u;}};dojo._usesBorderBox=function(node){var n=node.tagName;return d.boxModel=="border-box"||n=="TABLE"||n=="BUTTON";};dojo._setContentSize=function(node,_28c,_28d,_28e){if(d._usesBorderBox(node)){var pb=d._getPadBorderExtents(node,_28e);if(_28c>=0){_28c+=pb.w;}if(_28d>=0){_28d+=pb.h;}}d._setBox(node,NaN,NaN,_28c,_28d);};dojo._setMarginBox=function(node,_291,_292,_293,_294,_295){var s=_295||gcs(node);var bb=d._usesBorderBox(node),pb=bb?_299:d._getPadBorderExtents(node,s),mb=d._getMarginExtents(node,s);if(_293>=0){_293=Math.max(_293-pb.w-mb.w,0);}if(_294>=0){_294=Math.max(_294-pb.h-mb.h,0);}d._setBox(node,_291,_292,_293,_294);};var _299={l:0,t:0,w:0,h:0};dojo.marginBox=function(node,box){var n=d.byId(node),s=gcs(n),b=box;return !b?d._getMarginBox(n,s):d._setMarginBox(n,b.l,b.t,b.w,b.h,s);};dojo.contentBox=function(node,box){var n=dojo.byId(node),s=gcs(n),b=box;return !b?d._getContentBox(n,s):d._setContentSize(n,b.w,b.h,s);};var _2a5=function(node,prop){if(!(node=(node||0).parentNode)){return 0;}var val,_2a9=0,_b=d.body();while(node&&node.style){if(gcs(node).position=="fixed"){return 0;}val=node[prop];if(val){_2a9+=val-0;if(node==_b){break;}}node=node.parentNode;}return _2a9;};dojo._docScroll=function(){var _b=d.body(),_w=d.global,de=d.doc.documentElement;return {y:(_w.pageYOffset||de.scrollTop||_b.scrollTop||0),x:(_w.pageXOffset||d._fixIeBiDiScrollLeft(de.scrollLeft)||_b.scrollLeft||0)};};dojo._isBodyLtr=function(){return !("_bodyLtr" in d)?d._bodyLtr=gcs(d.body()).direction=="ltr":d._bodyLtr;};dojo._getIeDocumentElementOffset=function(){var de=d.doc.documentElement;return (d.isIE>=7)?{x:de.getBoundingClientRect().left,y:de.getBoundingClientRect().top}:{x:d._isBodyLtr()||window.parent==window?de.clientLeft:de.offsetWidth-de.clientWidth-de.clientLeft,y:de.clientTop};};dojo._fixIeBiDiScrollLeft=function(_2af){var dd=d.doc;if(d.isIE&&!dojo._isBodyLtr()){var de=dd.compatMode=="BackCompat"?dd.body:dd.documentElement;return _2af+de.clientWidth-de.scrollWidth;}return _2af;};dojo._abs=function(node,_2b3){var _2b4=node.ownerDocument;var ret={x:0,y:0};var db=d.body();if(d.isIE||(d.isFF>=3)){var _2b7=node.getBoundingClientRect();var _2b8=(d.isIE)?d._getIeDocumentElementOffset():{x:0,y:0};ret.x=_2b7.left-_2b8.x;ret.y=_2b7.top-_2b8.y;}else{if(_2b4["getBoxObjectFor"]){var bo=_2b4.getBoxObjectFor(node),b=d._getBorderExtents(node);ret.x=bo.x-b.l-_2a5(node,"scrollLeft");ret.y=bo.y-b.t-_2a5(node,"scrollTop");}else{if(node["offsetParent"]){var _2bb;if(d.isSafari&&(gcs(node).position=="absolute")&&(node.parentNode==db)){_2bb=db;}else{_2bb=db.parentNode;}if(node.parentNode!=db){var nd=node;if(d.isOpera){nd=db;}ret.x-=_2a5(nd,"scrollLeft");ret.y-=_2a5(nd,"scrollTop");}var _2bd=node;do{var n=_2bd.offsetLeft;if(!d.isOpera||n>0){ret.x+=isNaN(n)?0:n;}var t=_2bd.offsetTop;ret.y+=isNaN(t)?0:t;if(d.isSafari&&_2bd!=node){var cs=gcs(_2bd);ret.x+=px(_2bd,cs.borderLeftWidth);ret.y+=px(_2bd,cs.borderTopWidth);}_2bd=_2bd.offsetParent;}while((_2bd!=_2bb)&&_2bd);}else{if(node.x&&node.y){ret.x+=isNaN(node.x)?0:node.x;ret.y+=isNaN(node.y)?0:node.y;}}}}if(_2b3){var _2c1=d._docScroll();ret.y+=_2c1.y;ret.x+=_2c1.x;}return ret;};dojo.coords=function(node,_2c3){var n=d.byId(node),s=gcs(n),mb=d._getMarginBox(n,s);var abs=d._abs(n,_2c3);mb.x=abs.x;mb.y=abs.y;return mb;};var _2c8=function(name){switch(name.toLowerCase()){case "tabindex":return (d.isIE&&d.isIE<8)?"tabIndex":"tabindex";default:return name;}};var _2ca={colspan:"colSpan",enctype:"enctype",frameborder:"frameborder",method:"method",rowspan:"rowSpan",scrolling:"scrolling",shape:"shape",span:"span",type:"type",valuetype:"valueType"};dojo.hasAttr=function(node,name){var attr=d.byId(node).getAttributeNode(_2c8(name));return attr?attr.specified:false;};var _2ce={};var _ctr=0;var _2d0=dojo._scopeName+"attrid";dojo.attr=function(node,name,_2d3){var args=arguments.length;if(args==2&&!d.isString(name)){for(var x in name){d.attr(node,x,name[x]);}return;}node=d.byId(node);name=_2c8(name);if(args==3){if(d.isFunction(_2d3)){var _2d6=d.attr(node,_2d0);if(!_2d6){_2d6=_ctr++;d.attr(node,_2d0,_2d6);}if(!_2ce[_2d6]){_2ce[_2d6]={};}var h=_2ce[_2d6][name];if(h){d.disconnect(h);}else{try{delete node[name];}catch(e){}}_2ce[_2d6][name]=d.connect(node,name,_2d3);}else{if(typeof _2d3=="boolean"){node[name]=_2d3;}else{node.setAttribute(name,_2d3);}}return;}else{var prop=_2ca[name.toLowerCase()];if(prop){return node[prop];}else{var _2d3=node[name];return (typeof _2d3=="boolean"||typeof _2d3=="function")?_2d3:(d.hasAttr(node,name)?node.getAttribute(name):null);}}};dojo.removeAttr=function(node,name){d.byId(node).removeAttribute(_2c8(name));};})();dojo.hasClass=function(node,_2dc){return ((" "+dojo.byId(node).className+" ").indexOf(" "+_2dc+" ")>=0);};dojo.addClass=function(node,_2de){node=dojo.byId(node);var cls=node.className;if((" "+cls+" ").indexOf(" "+_2de+" ")<0){node.className=cls+(cls?" ":"")+_2de;}};dojo.removeClass=function(node,_2e1){node=dojo.byId(node);var t=dojo.trim((" "+node.className+" ").replace(" "+_2e1+" "," "));if(node.className!=t){node.className=t;}};dojo.toggleClass=function(node,_2e4,_2e5){if(_2e5===undefined){_2e5=!dojo.hasClass(node,_2e4);}dojo[_2e5?"addClass":"removeClass"](node,_2e4);};}if(!dojo._hasResource["dojo._base.NodeList"]){dojo._hasResource["dojo._base.NodeList"]=true;dojo.provide("dojo._base.NodeList");(function(){var d=dojo;var tnl=function(arr){arr.constructor=dojo.NodeList;dojo._mixin(arr,dojo.NodeList.prototype);return arr;};var _2e9=function(func,_2eb){return function(){var _a=arguments;var aa=d._toArray(_a,0,[null]);var s=this.map(function(i){aa[0]=i;return d[func].apply(d,aa);});return (_2eb||((_a.length>1)||!d.isString(_a[0])))?this:s;};};dojo.NodeList=function(){return tnl(Array.apply(null,arguments));};dojo.NodeList._wrap=tnl;dojo.extend(dojo.NodeList,{slice:function(){var a=dojo._toArray(arguments);return tnl(a.slice.apply(this,a));},splice:function(){var a=dojo._toArray(arguments);return tnl(a.splice.apply(this,a));},concat:function(){var a=dojo._toArray(arguments,0,[this]);return tnl(a.concat.apply([],a));},indexOf:function(_2f3,_2f4){return d.indexOf(this,_2f3,_2f4);},lastIndexOf:function(){return d.lastIndexOf.apply(d,d._toArray(arguments,0,[this]));},every:function(_2f5,_2f6){return d.every(this,_2f5,_2f6);},some:function(_2f7,_2f8){return d.some(this,_2f7,_2f8);},map:function(func,obj){return d.map(this,func,obj,d.NodeList);},forEach:function(_2fb,_2fc){d.forEach(this,_2fb,_2fc);return this;},coords:function(){return d.map(this,d.coords);},attr:_2e9("attr"),style:_2e9("style"),addClass:_2e9("addClass",true),removeClass:_2e9("removeClass",true),toggleClass:_2e9("toggleClass",true),connect:_2e9("connect",true),place:function(_2fd,_2fe){var item=d.query(_2fd)[0];return this.forEach(function(i){d.place(i,item,(_2fe||"last"));});},orphan:function(_301){var _302=_301?d._filterQueryResult(this,_301):this;_302.forEach(function(item){if(item.parentNode){item.parentNode.removeChild(item);}});return _302;},adopt:function(_304,_305){var item=this[0];return d.query(_304).forEach(function(ai){d.place(ai,item,_305||"last");});},query:function(_308){if(!_308){return this;}var ret=d.NodeList();this.forEach(function(item){d.query(_308,item).forEach(function(_30b){if(_30b!==undefined){ret.push(_30b);}});});return ret;},filter:function(_30c){var _30d=this;var _a=arguments;var r=d.NodeList();var rp=function(t){if(t!==undefined){r.push(t);}};if(d.isString(_30c)){_30d=d._filterQueryResult(this,_a[0]);if(_a.length==1){return _30d;}_a.shift();}d.forEach(d.filter(_30d,_a[0],_a[1]),rp);return r;},addContent:function(_312,_313){var ta=d.doc.createElement("span");if(d.isString(_312)){ta.innerHTML=_312;}else{ta.appendChild(_312);}if(_313===undefined){_313="last";}var ct=(_313=="first"||_313=="after")?"lastChild":"firstChild";this.forEach(function(item){var tn=ta.cloneNode(true);while(tn[ct]){d.place(tn[ct],item,_313);}});return this;},empty:function(){return this.forEach("item.innerHTML='';");},instantiate:function(_318,_319){var c=d.isFunction(_318)?_318:d.getObject(_318);return this.forEach(function(i){new c(_319||{},i);});}});d.forEach(["blur","focus","click","keydown","keypress","keyup","mousedown","mouseenter","mouseleave","mousemove","mouseout","mouseover","mouseup"],function(evt){var _oe="on"+evt;dojo.NodeList.prototype[_oe]=function(a,b){return this.connect(_oe,a,b);};});})();}if(!dojo._hasResource["dojo._base.query"]){dojo._hasResource["dojo._base.query"]=true;dojo.provide("dojo._base.query");(function(){var d=dojo;var _321=dojo.isIE?"children":"childNodes";var _322=false;var _323=function(_324){if(">~+".indexOf(_324.charAt(_324.length-1))>=0){_324+=" *";}_324+=" ";var ts=function(s,e){return d.trim(_324.slice(s,e));};var _328=[];var _329=-1;var _32a=-1;var _32b=-1;var _32c=-1;var _32d=-1;var inId=-1;var _32f=-1;var lc="";var cc="";var _332;var x=0;var ql=_324.length;var _335=null;var _cp=null;var _337=function(){if(_32f>=0){var tv=(_32f==x)?null:ts(_32f,x).toLowerCase();_335[(">~+".indexOf(tv)<0)?"tag":"oper"]=tv;_32f=-1;}};var _339=function(){if(inId>=0){_335.id=ts(inId,x).replace(/\\/g,"");inId=-1;}};var _33a=function(){if(_32d>=0){_335.classes.push(ts(_32d+1,x).replace(/\\/g,""));_32d=-1;}};var _33b=function(){_339();_337();_33a();};for(;lc=cc,cc=_324.charAt(x),x<ql;x++){if(lc=="\\"){continue;}if(!_335){_332=x;_335={query:null,pseudos:[],attrs:[],classes:[],tag:null,oper:null,id:null};_32f=x;}if(_329>=0){if(cc=="]"){if(!_cp.attr){_cp.attr=ts(_329+1,x);}else{_cp.matchFor=ts((_32b||_329+1),x);}var cmf=_cp.matchFor;if(cmf){if((cmf.charAt(0)=="\"")||(cmf.charAt(0)=="'")){_cp.matchFor=cmf.substring(1,cmf.length-1);}}_335.attrs.push(_cp);_cp=null;_329=_32b=-1;}else{if(cc=="="){var _33d=("|~^$*".indexOf(lc)>=0)?lc:"";_cp.type=_33d+cc;_cp.attr=ts(_329+1,x-_33d.length);_32b=x+1;}}}else{if(_32a>=0){if(cc==")"){if(_32c>=0){_cp.value=ts(_32a+1,x);}_32c=_32a=-1;}}else{if(cc=="#"){_33b();inId=x+1;}else{if(cc=="."){_33b();_32d=x;}else{if(cc==":"){_33b();_32c=x;}else{if(cc=="["){_33b();_329=x;_cp={};}else{if(cc=="("){if(_32c>=0){_cp={name:ts(_32c+1,x),value:null};_335.pseudos.push(_cp);}_32a=x;}else{if(cc==" "&&lc!=cc){_33b();if(_32c>=0){_335.pseudos.push({name:ts(_32c+1,x)});}_335.hasLoops=(_335.pseudos.length||_335.attrs.length||_335.classes.length);_335.query=ts(_332,x);_335.tag=(_335["oper"])?null:(_335.tag||"*");_328.push(_335);_335=null;}}}}}}}}}return _328;};var _33e={"*=":function(attr,_340){return "[contains(@"+attr+", '"+_340+"')]";},"^=":function(attr,_342){return "[starts-with(@"+attr+", '"+_342+"')]";},"$=":function(attr,_344){return "[substring(@"+attr+", string-length(@"+attr+")-"+(_344.length-1)+")='"+_344+"']";},"~=":function(attr,_346){return "[contains(concat(' ',@"+attr+",' '), ' "+_346+" ')]";},"|=":function(attr,_348){return "[contains(concat(' ',@"+attr+",' '), ' "+_348+"-')]";},"=":function(attr,_34a){return "[@"+attr+"='"+_34a+"']";}};var _34b=function(_34c,_34d,_34e,_34f){d.forEach(_34d.attrs,function(attr){var _351;if(attr.type&&_34c[attr.type]){_351=_34c[attr.type](attr.attr,attr.matchFor);}else{if(attr.attr.length){_351=_34e(attr.attr);}}if(_351){_34f(_351);}});};var _352=function(_353){var _354=".";var _355=_323(d.trim(_353));while(_355.length){var tqp=_355.shift();var _357;var _358="";if(tqp.oper==">"){_357="/";tqp=_355.shift();}else{if(tqp.oper=="~"){_357="/following-sibling::";tqp=_355.shift();}else{if(tqp.oper=="+"){_357="/following-sibling::";_358="[position()=1]";tqp=_355.shift();}else{_357="//";}}}_354+=_357+tqp.tag+_358;if(tqp.id){_354+="[@id='"+tqp.id+"'][1]";}d.forEach(tqp.classes,function(cn){var cnl=cn.length;var _35b=" ";if(cn.charAt(cnl-1)=="*"){_35b="";cn=cn.substr(0,cnl-1);}_354+="[contains(concat(' ',@class,' '), ' "+cn+_35b+"')]";});_34b(_33e,tqp,function(_35c){return "[@"+_35c+"]";},function(_35d){_354+=_35d;});}return _354;};var _35e={};var _35f=function(path){if(_35e[path]){return _35e[path];}var doc=d.doc;var _362=_352(path);var tf=function(_364){var ret=[];var _366;try{_366=doc.evaluate(_362,_364,null,XPathResult.ANY_TYPE,null);}catch(e){console.debug("failure in exprssion:",_362,"under:",_364);console.debug(e);}var _367=_366.iterateNext();while(_367){ret.push(_367);_367=_366.iterateNext();}return ret;};return _35e[path]=tf;};var _368={};var _369={};var _36a=function(_36b,_36c){if(!_36b){return _36c;}if(!_36c){return _36b;}return function(){return _36b.apply(window,arguments)&&_36c.apply(window,arguments);};};var _36d=function(root){var ret=[];var te,x=0,tret=root[_321];while(te=tret[x++]){if(te.nodeType==1){ret.push(te);}}return ret;};var _373=function(root,_375){var ret=[];var te=root;while(te=te.nextSibling){if(te.nodeType==1){ret.push(te);if(_375){break;}}}return ret;};var _378=function(_379,_37a,_37b,idx){var nidx=idx+1;var _37e=(_37a.length==nidx);var tqp=_37a[idx];if(tqp.oper){var ecn=(tqp.oper==">")?_36d(_379):_373(_379,(tqp.oper=="+"));if(!ecn||!ecn.length){return;}nidx++;_37e=(_37a.length==nidx);var tf=_382(_37a[idx+1]);for(var x=0,ecnl=ecn.length,te;x<ecnl,te=ecn[x];x++){if(tf(te)){if(_37e){_37b.push(te);}else{_378(te,_37a,_37b,nidx);}}}}var _386=_387(tqp)(_379);if(_37e){while(_386.length){_37b.push(_386.shift());}}else{while(_386.length){_378(_386.shift(),_37a,_37b,nidx);}}};var _388=function(_389,_38a){var ret=[];var x=_389.length-1,te;while(te=_389[x--]){_378(te,_38a,ret,0);}return ret;};var _382=function(q){if(_368[q.query]){return _368[q.query];}var ff=null;if(q.tag){if(q.tag=="*"){ff=_36a(ff,function(elem){return (elem.nodeType==1);});}else{ff=_36a(ff,function(elem){return ((elem.nodeType==1)&&(q.tag==elem.tagName.toLowerCase()));});}}if(q.id){ff=_36a(ff,function(elem){return ((elem.nodeType==1)&&(elem.id==q.id));});}if(q.hasLoops){ff=_36a(ff,_393(q));}return _368[q.query]=ff;};var _394=function(node){var pn=node.parentNode;var pnc=pn.childNodes;var nidx=-1;var _399=pn.firstChild;if(!_399){return nidx;}var ci=node["__cachedIndex"];var cl=pn["__cachedLength"];if(((typeof cl=="number")&&(cl!=pnc.length))||(typeof ci!="number")){pn["__cachedLength"]=pnc.length;var idx=1;do{if(_399===node){nidx=idx;}if(_399.nodeType==1){_399["__cachedIndex"]=idx;idx++;}_399=_399.nextSibling;}while(_399);}else{nidx=ci;}return nidx;};var _39d=0;var _39e="";var _39f=function(elem,attr){if(attr=="class"){return elem.className||_39e;}if(attr=="for"){return elem.htmlFor||_39e;}return elem.getAttribute(attr,2)||_39e;};var _3a2={"*=":function(attr,_3a4){return function(elem){return (_39f(elem,attr).indexOf(_3a4)>=0);};},"^=":function(attr,_3a7){return function(elem){return (_39f(elem,attr).indexOf(_3a7)==0);};},"$=":function(attr,_3aa){var tval=" "+_3aa;return function(elem){var ea=" "+_39f(elem,attr);return (ea.lastIndexOf(_3aa)==(ea.length-_3aa.length));};},"~=":function(attr,_3af){var tval=" "+_3af+" ";return function(elem){var ea=" "+_39f(elem,attr)+" ";return (ea.indexOf(tval)>=0);};},"|=":function(attr,_3b4){var _3b5=" "+_3b4+"-";return function(elem){var ea=" "+(elem.getAttribute(attr,2)||"");return ((ea==_3b4)||(ea.indexOf(_3b5)==0));};},"=":function(attr,_3b9){return function(elem){return (_39f(elem,attr)==_3b9);};}};var _3bb={"first-child":function(name,_3bd){return function(elem){if(elem.nodeType!=1){return false;}var fc=elem.previousSibling;while(fc&&(fc.nodeType!=1)){fc=fc.previousSibling;}return (!fc);};},"last-child":function(name,_3c1){return function(elem){if(elem.nodeType!=1){return false;}var nc=elem.nextSibling;while(nc&&(nc.nodeType!=1)){nc=nc.nextSibling;}return (!nc);};},"empty":function(name,_3c5){return function(elem){var cn=elem.childNodes;var cnl=elem.childNodes.length;for(var x=cnl-1;x>=0;x--){var nt=cn[x].nodeType;if((nt==1)||(nt==3)){return false;}}return true;};},"contains":function(name,_3cc){return function(elem){return (elem.innerHTML.indexOf(_3cc)>=0);};},"not":function(name,_3cf){var ntf=_382(_323(_3cf)[0]);return function(elem){return (!ntf(elem));};},"nth-child":function(name,_3d3){var pi=parseInt;if(_3d3=="odd"){return function(elem){return (((_394(elem))%2)==1);};}else{if((_3d3=="2n")||(_3d3=="even")){return function(elem){return ((_394(elem)%2)==0);};}else{if(_3d3.indexOf("0n+")==0){var _3d7=pi(_3d3.substr(3));return function(elem){return (elem.parentNode[_321][_3d7-1]===elem);};}else{if((_3d3.indexOf("n+")>0)&&(_3d3.length>3)){var _3d9=_3d3.split("n+",2);var pred=pi(_3d9[0]);var idx=pi(_3d9[1]);return function(elem){return ((_394(elem)%pred)==idx);};}else{if(_3d3.indexOf("n")==-1){var _3d7=pi(_3d3);return function(elem){return (_394(elem)==_3d7);};}}}}}}};var _3de=(d.isIE)?function(cond){var clc=cond.toLowerCase();return function(elem){return elem[cond]||elem[clc];};}:function(cond){return function(elem){return (elem&&elem.getAttribute&&elem.hasAttribute(cond));};};var _393=function(_3e4){var _3e5=(_369[_3e4.query]||_368[_3e4.query]);if(_3e5){return _3e5;}var ff=null;if(_3e4.id){if(_3e4.tag!="*"){ff=_36a(ff,function(elem){return (elem.tagName.toLowerCase()==_3e4.tag);});}}d.forEach(_3e4.classes,function(_3e8,idx,arr){var _3eb=_3e8.charAt(_3e8.length-1)=="*";if(_3eb){_3e8=_3e8.substr(0,_3e8.length-1);}var re=new RegExp("(?:^|\\s)"+_3e8+(_3eb?".*":"")+"(?:\\s|$)");ff=_36a(ff,function(elem){return re.test(elem.className);});ff.count=idx;});d.forEach(_3e4.pseudos,function(_3ee){if(_3bb[_3ee.name]){ff=_36a(ff,_3bb[_3ee.name](_3ee.name,_3ee.value));}});_34b(_3a2,_3e4,_3de,function(_3ef){ff=_36a(ff,_3ef);});if(!ff){ff=function(){return true;};}return _369[_3e4.query]=ff;};var _3f0={};var _387=function(_3f1,root){var fHit=_3f0[_3f1.query];if(fHit){return fHit;}if(_3f1.id&&!_3f1.hasLoops&&!_3f1.tag){return _3f0[_3f1.query]=function(root){return [d.byId(_3f1.id)];};}var _3f5=_393(_3f1);var _3f6;if(_3f1.tag&&_3f1.id&&!_3f1.hasLoops){_3f6=function(root){var te=d.byId(_3f1.id);if(_3f5(te)){return [te];}};}else{var tret;if(!_3f1.hasLoops){_3f6=function(root){var ret=[];var te,x=0,tret=root.getElementsByTagName(_3f1.tag);while(te=tret[x++]){ret.push(te);}return ret;};}else{_3f6=function(root){var ret=[];var te,x=0,tret=root.getElementsByTagName(_3f1.tag);while(te=tret[x++]){if(_3f5(te)){ret.push(te);}}return ret;};}}return _3f0[_3f1.query]=_3f6;};var _402={};var _403={"*":d.isIE?function(root){return root.all;}:function(root){return root.getElementsByTagName("*");},"~":_373,"+":function(root){return _373(root,true);},">":_36d};var _407=function(_408){var _409=_323(d.trim(_408));if(_409.length==1){var tt=_387(_409[0]);tt.nozip=true;return tt;}var sqf=function(root){var _40d=_409.slice(0);var _40e;if(_40d[0].oper==">"){_40e=[root];}else{_40e=_387(_40d.shift())(root);}return _388(_40e,_40d);};return sqf;};var _40f=((document["evaluate"]&&!d.isSafari)?function(_410){var _411=_410.split(" ");if((document["evaluate"])&&(_410.indexOf(":")==-1)&&(_410.indexOf("+")==-1)){if(((_411.length>2)&&(_410.indexOf(">")==-1))||(_411.length>3)||(_410.indexOf("[")>=0)||((1==_411.length)&&(0<=_410.indexOf(".")))){return _35f(_410);}}return _407(_410);}:_407);var _412=function(_413){var qcz=_413.charAt(0);if(d.doc["querySelectorAll"]&&((!d.isSafari)||(d.isSafari>3.1))&&(">+~".indexOf(qcz)==-1)){return function(root){var r=root.querySelectorAll(_413);r.nozip=true;return r;};}if(_403[_413]){return _403[_413];}if(0>_413.indexOf(",")){return _403[_413]=_40f(_413);}else{var _417=_413.split(/\s*,\s*/);var tf=function(root){var _41a=0;var ret=[];var tp;while(tp=_417[_41a++]){ret=ret.concat(_40f(tp,tp.indexOf(" "))(root));}return ret;};return _403[_413]=tf;}};var _41d=0;var _zip=function(arr){if(arr&&arr.nozip){return d.NodeList._wrap(arr);}var ret=new d.NodeList();if(!arr){return ret;}if(arr[0]){ret.push(arr[0]);}if(arr.length<2){return ret;}_41d++;arr[0]["_zipIdx"]=_41d;for(var x=1,te;te=arr[x];x++){if(arr[x]["_zipIdx"]!=_41d){ret.push(te);}te["_zipIdx"]=_41d;}return ret;};d.query=function(_423,root){if(_423.constructor==d.NodeList){return _423;}if(!d.isString(_423)){return new d.NodeList(_423);}if(d.isString(root)){root=d.byId(root);}return _zip(_412(_423)(root||d.doc));};d.query.pseudos=_3bb;d._filterQueryResult=function(_425,_426){var tnl=new d.NodeList();var ff=(_426)?_382(_323(_426)[0]):function(){return true;};for(var x=0,te;te=_425[x];x++){if(ff(te)){tnl.push(te);}}return tnl;};})();}if(!dojo._hasResource["dojo._base.xhr"]){dojo._hasResource["dojo._base.xhr"]=true;dojo.provide("dojo._base.xhr");(function(){var _d=dojo;function setValue(obj,name,_42e){var val=obj[name];if(_d.isString(val)){obj[name]=[val,_42e];}else{if(_d.isArray(val)){val.push(_42e);}else{obj[name]=_42e;}}};dojo.formToObject=function(_430){var ret={};var iq="input:not([type=file]):not([type=submit]):not([type=image]):not([type=reset]):not([type=button]), select, textarea";_d.query(iq,_430).filter(function(node){return !node.disabled&&node.name;}).forEach(function(item){var _in=item.name;var type=(item.type||"").toLowerCase();if(type=="radio"||type=="checkbox"){if(item.checked){setValue(ret,_in,item.value);}}else{if(item.multiple){ret[_in]=[];_d.query("option",item).forEach(function(opt){if(opt.selected){setValue(ret,_in,opt.value);}});}else{setValue(ret,_in,item.value);if(type=="image"){ret[_in+".x"]=ret[_in+".y"]=ret[_in].x=ret[_in].y=0;}}}});return ret;};dojo.objectToQuery=function(map){var enc=encodeURIComponent;var _43a=[];var _43b={};for(var name in map){var _43d=map[name];if(_43d!=_43b[name]){var _43e=enc(name)+"=";if(_d.isArray(_43d)){for(var i=0;i<_43d.length;i++){_43a.push(_43e+enc(_43d[i]));}}else{_43a.push(_43e+enc(_43d));}}}return _43a.join("&");};dojo.formToQuery=function(_440){return _d.objectToQuery(_d.formToObject(_440));};dojo.formToJson=function(_441,_442){return _d.toJson(_d.formToObject(_441),_442);};dojo.queryToObject=function(str){var ret={};var qp=str.split("&");var dec=decodeURIComponent;_d.forEach(qp,function(item){if(item.length){var _448=item.split("=");var name=dec(_448.shift());var val=dec(_448.join("="));if(_d.isString(ret[name])){ret[name]=[ret[name]];}if(_d.isArray(ret[name])){ret[name].push(val);}else{ret[name]=val;}}});return ret;};dojo._blockAsync=false;dojo._contentHandlers={"text":function(xhr){return xhr.responseText;},"json":function(xhr){if(!dojo.config.usePlainJson){console.warn("Consider using mimetype:text/json-comment-filtered"+" to avoid potential security issues with JSON endpoints"+" (use djConfig.usePlainJson=true to turn off this message)");}return (xhr.status==204)?undefined:_d.fromJson(xhr.responseText);},"json-comment-filtered":function(xhr){var _44e=xhr.responseText;var _44f=_44e.indexOf("/*");var _450=_44e.lastIndexOf("*/");if(_44f==-1||_450==-1){throw new Error("JSON was not comment filtered");}return (xhr.status==204)?undefined:_d.fromJson(_44e.substring(_44f+2,_450));},"javascript":function(xhr){return _d.eval(xhr.responseText);},"xml":function(xhr){var _453=xhr.responseXML;if(_d.isIE&&(!_453||window.location.protocol=="file:")){_d.forEach(["MSXML2","Microsoft","MSXML","MSXML3"],function(_454){try{var dom=new ActiveXObject(_454+".XMLDOM");dom.async=false;dom.loadXML(xhr.responseText);_453=dom;}catch(e){}});}return _453;}};dojo._contentHandlers["json-comment-optional"]=function(xhr){var _457=_d._contentHandlers;try{return _457["json-comment-filtered"](xhr);}catch(e){return _457["json"](xhr);}};dojo._ioSetArgs=function(args,_459,_45a,_45b){var _45c={args:args,url:args.url};var _45d=null;if(args.form){var form=_d.byId(args.form);var _45f=form.getAttributeNode("action");_45c.url=_45c.url||(_45f?_45f.value:null);_45d=_d.formToObject(form);}var _460=[{}];if(_45d){_460.push(_45d);}if(args.content){_460.push(args.content);}if(args.preventCache){_460.push({"dojo.preventCache":new Date().valueOf()});}_45c.query=_d.objectToQuery(_d.mixin.apply(null,_460));_45c.handleAs=args.handleAs||"text";var d=new _d.Deferred(_459);d.addCallbacks(_45a,function(_462){return _45b(_462,d);});var ld=args.load;if(ld&&_d.isFunction(ld)){d.addCallback(function(_464){return ld.call(args,_464,_45c);});}var err=args.error;if(err&&_d.isFunction(err)){d.addErrback(function(_466){return err.call(args,_466,_45c);});}var _467=args.handle;if(_467&&_d.isFunction(_467)){d.addBoth(function(_468){return _467.call(args,_468,_45c);});}d.ioArgs=_45c;return d;};var _469=function(dfd){dfd.canceled=true;var xhr=dfd.ioArgs.xhr;var _at=typeof xhr.abort;if(_at=="function"||_at=="unknown"){xhr.abort();}var err=new Error("xhr cancelled");err.dojoType="cancel";return err;};var _46e=function(dfd){return _d._contentHandlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);};var _470=function(_471,dfd){console.debug(_471);return _471;};var _473=function(args){var dfd=_d._ioSetArgs(args,_469,_46e,_470);dfd.ioArgs.xhr=_d._xhrObj(dfd.ioArgs.args);return dfd;};var _476=null;var _477=[];var _478=function(){var now=(new Date()).getTime();if(!_d._blockAsync){for(var i=0,tif;i<_477.length&&(tif=_477[i]);i++){var dfd=tif.dfd;try{if(!dfd||dfd.canceled||!tif.validCheck(dfd)){_477.splice(i--,1);}else{if(tif.ioCheck(dfd)){_477.splice(i--,1);tif.resHandle(dfd);}else{if(dfd.startTime){if(dfd.startTime+(dfd.ioArgs.args.timeout||0)<now){_477.splice(i--,1);var err=new Error("timeout exceeded");err.dojoType="timeout";dfd.errback(err);dfd.cancel();}}}}}catch(e){console.debug(e);dfd.errback(new Error("_watchInFlightError!"));}}}if(!_477.length){clearInterval(_476);_476=null;return;}};dojo._ioCancelAll=function(){try{_d.forEach(_477,function(i){i.dfd.cancel();});}catch(e){}};if(_d.isIE){_d.addOnUnload(_d._ioCancelAll);}_d._ioWatch=function(dfd,_480,_481,_482){if(dfd.ioArgs.args.timeout){dfd.startTime=(new Date()).getTime();}_477.push({dfd:dfd,validCheck:_480,ioCheck:_481,resHandle:_482});if(!_476){_476=setInterval(_478,50);}_478();};var _483="application/x-www-form-urlencoded";var _484=function(dfd){return dfd.ioArgs.xhr.readyState;};var _486=function(dfd){return 4==dfd.ioArgs.xhr.readyState;};var _488=function(dfd){var xhr=dfd.ioArgs.xhr;if(_d._isDocumentOk(xhr)){dfd.callback(dfd);}else{var err=new Error("Unable to load "+dfd.ioArgs.url+" status:"+xhr.status);err.status=xhr.status;err.responseText=xhr.responseText;dfd.errback(err);}};var _48c=function(type,dfd){var _48f=dfd.ioArgs;var args=_48f.args;var xhr=_48f.xhr;xhr.open(type,_48f.url,args.sync!==true,args.user||undefined,args.password||undefined);if(args.headers){for(var hdr in args.headers){if(hdr.toLowerCase()==="content-type"&&!args.contentType){args.contentType=args.headers[hdr];}else{xhr.setRequestHeader(hdr,args.headers[hdr]);}}}xhr.setRequestHeader("Content-Type",args.contentType||_483);if(!args.headers||!args.headers["X-Requested-With"]){xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");}try{xhr.send(_48f.query);}catch(e){dfd.cancel();}_d._ioWatch(dfd,_484,_486,_488);xhr=null;return dfd;};dojo._ioAddQueryToUrl=function(_493){if(_493.query.length){_493.url+=(_493.url.indexOf("?")==-1?"?":"&")+_493.query;_493.query=null;}};dojo.xhr=function(_494,args,_496){var dfd=_473(args);if(!_496){_d._ioAddQueryToUrl(dfd.ioArgs);}return _48c(_494,dfd);};dojo.xhrGet=function(args){return _d.xhr("GET",args);};dojo.xhrPost=function(args){return _d.xhr("POST",args,true);};dojo.rawXhrPost=function(args){var dfd=_473(args);dfd.ioArgs.query=args.postData;return _48c("POST",dfd);};dojo.xhrPut=function(args){return _d.xhr("PUT",args,true);};dojo.rawXhrPut=function(args){var dfd=_473(args);var _49f=dfd.ioArgs;if(args.putData){_49f.query=args.putData;args.putData=null;}return _48c("PUT",dfd);};dojo.xhrDelete=function(args){return _d.xhr("DELETE",args);};})();}if(!dojo._hasResource["dojo._base.fx"]){dojo._hasResource["dojo._base.fx"]=true;dojo.provide("dojo._base.fx");(function(){var d=dojo;dojo._Line=function(_4a2,end){this.start=_4a2;this.end=end;this.getValue=function(n){return ((this.end-this.start)*n)+this.start;};};d.declare("dojo._Animation",null,{constructor:function(args){d.mixin(this,args);if(d.isArray(this.curve)){this.curve=new d._Line(this.curve[0],this.curve[1]);}},duration:350,repeat:0,rate:10,_percent:0,_startRepeatCount:0,_fire:function(evt,args){try{if(this[evt]){this[evt].apply(this,args||[]);}}catch(e){console.error("exception in animation handler for:",evt);console.error(e);}return this;},play:function(_4a8,_4a9){var _t=this;if(_4a9){_t._stopTimer();_t._active=_t._paused=false;_t._percent=0;}else{if(_t._active&&!_t._paused){return _t;}}_t._fire("beforeBegin");var de=_4a8||_t.delay;var _p=dojo.hitch(_t,"_play",_4a9);if(de>0){setTimeout(_p,de);return _t;}_p();return _t;},_play:function(_4ad){var _t=this;_t._startTime=new Date().valueOf();if(_t._paused){_t._startTime-=_t.duration*_t._percent;}_t._endTime=_t._startTime+_t.duration;_t._active=true;_t._paused=false;var _4af=_t.curve.getValue(_t._percent);if(!_t._percent){if(!_t._startRepeatCount){_t._startRepeatCount=_t.repeat;}_t._fire("onBegin",[_4af]);}_t._fire("onPlay",[_4af]);_t._cycle();return _t;},pause:function(){this._stopTimer();if(!this._active){return this;}this._paused=true;this._fire("onPause",[this.curve.getValue(this._percent)]);return this;},gotoPercent:function(_4b0,_4b1){this._stopTimer();this._active=this._paused=true;this._percent=_4b0;if(_4b1){this.play();}return this;},stop:function(_4b2){if(!this._timer){return this;}this._stopTimer();if(_4b2){this._percent=1;}this._fire("onStop",[this.curve.getValue(this._percent)]);this._active=this._paused=false;return this;},status:function(){if(this._active){return this._paused?"paused":"playing";}return "stopped";},_cycle:function(){var _t=this;if(_t._active){var curr=new Date().valueOf();var step=(curr-_t._startTime)/(_t._endTime-_t._startTime);if(step>=1){step=1;}_t._percent=step;if(_t.easing){step=_t.easing(step);}_t._fire("onAnimate",[_t.curve.getValue(step)]);if(_t._percent<1){_t._startTimer();}else{_t._active=false;if(_t.repeat>0){_t.repeat--;_t.play(null,true);}else{if(_t.repeat==-1){_t.play(null,true);}else{if(_t._startRepeatCount){_t.repeat=_t._startRepeatCount;_t._startRepeatCount=0;}}}_t._percent=0;_t._fire("onEnd");_t._stopTimer();}}return _t;}});var ctr=0;var _4b7=[];var _4b8={run:function(){}};var _4b9=null;dojo._Animation.prototype._startTimer=function(){if(!this._timer){this._timer=d.connect(_4b8,"run",this,"_cycle");ctr++;}if(!_4b9){_4b9=setInterval(d.hitch(_4b8,"run"),this.rate);}};dojo._Animation.prototype._stopTimer=function(){if(this._timer){d.disconnect(this._timer);this._timer=null;ctr--;}if(ctr<=0){clearInterval(_4b9);_4b9=null;ctr=0;}};var _4ba=(d.isIE)?function(node){var ns=node.style;if(!ns.zoom.length&&d.style(node,"zoom")=="normal"){ns.zoom="1";}if(!ns.width.length&&d.style(node,"width")=="auto"){ns.width="auto";}}:function(){};dojo._fade=function(args){args.node=d.byId(args.node);var _4be=d.mixin({properties:{}},args);var _4bf=(_4be.properties.opacity={});_4bf.start=!("start" in _4be)?function(){return Number(d.style(_4be.node,"opacity"));}:_4be.start;_4bf.end=_4be.end;var anim=d.animateProperty(_4be);d.connect(anim,"beforeBegin",d.partial(_4ba,_4be.node));return anim;};dojo.fadeIn=function(args){return d._fade(d.mixin({end:1},args));};dojo.fadeOut=function(args){return d._fade(d.mixin({end:0},args));};dojo._defaultEasing=function(n){return 0.5+((Math.sin((n+1.5)*Math.PI))/2);};var _4c4=function(_4c5){this._properties=_4c5;for(var p in _4c5){var prop=_4c5[p];if(prop.start instanceof d.Color){prop.tempColor=new d.Color();}}this.getValue=function(r){var ret={};for(var p in this._properties){var prop=this._properties[p];var _4cc=prop.start;if(_4cc instanceof d.Color){ret[p]=d.blendColors(_4cc,prop.end,r,prop.tempColor).toCss();}else{if(!d.isArray(_4cc)){ret[p]=((prop.end-_4cc)*r)+_4cc+(p!="opacity"?prop.units||"px":"");}}}return ret;};};dojo.animateProperty=function(args){args.node=d.byId(args.node);if(!args.easing){args.easing=d._defaultEasing;}var anim=new d._Animation(args);d.connect(anim,"beforeBegin",anim,function(){var pm={};for(var p in this.properties){if(p=="width"||p=="height"){this.node.display="block";}var prop=this.properties[p];prop=pm[p]=d.mixin({},(d.isObject(prop)?prop:{end:prop}));if(d.isFunction(prop.start)){prop.start=prop.start();}if(d.isFunction(prop.end)){prop.end=prop.end();}var _4d2=(p.toLowerCase().indexOf("color")>=0);function getStyle(node,p){var v=({height:node.offsetHeight,width:node.offsetWidth})[p];if(v!==undefined){return v;}v=d.style(node,p);return (p=="opacity")?Number(v):(_4d2?v:parseFloat(v));};if(!("end" in prop)){prop.end=getStyle(this.node,p);}else{if(!("start" in prop)){prop.start=getStyle(this.node,p);}}if(_4d2){prop.start=new d.Color(prop.start);prop.end=new d.Color(prop.end);}else{prop.start=(p=="opacity")?Number(prop.start):parseFloat(prop.start);}}this.curve=new _4c4(pm);});d.connect(anim,"onAnimate",anim,function(_4d6){for(var s in _4d6){d.style(this.node,s,_4d6[s]);}});return anim;};dojo.anim=function(node,_4d9,_4da,_4db,_4dc,_4dd){return d.animateProperty({node:node,duration:_4da||d._Animation.prototype.duration,properties:_4d9,easing:_4db,onEnd:_4dc}).play(_4dd||0);};})();}if(!dojo._hasResource["dojo._base.browser"]){dojo._hasResource["dojo._base.browser"]=true;dojo.provide("dojo._base.browser");if(dojo.config.require){dojo.forEach(dojo.config.require,"dojo['require'](item);");}}if(dojo.config.afterOnLoad&&dojo.isBrowser){window.setTimeout(dojo._fakeLoadInit,1000);}})();
diff --git a/includes/js/dojo/dojo.js.uncompressed.js b/includes/js/dojo/dojo.js.uncompressed.js
new file mode 100644
index 0000000..6746345
--- /dev/null
+++ b/includes/js/dojo/dojo.js.uncompressed.js
@@ -0,0 +1,8165 @@
+/*
+ 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.
+*/
+
+;(function(){
+
+ /*
+ dojo, dijit, and dojox must always be the first three, and in that order.
+ djConfig.scopeMap = [
+ ["dojo", "fojo"],
+ ["dijit", "fijit"],
+ ["dojox", "fojox"]
+
+ ]
+ */
+
+ /**Build will replace this comment with a scoped djConfig **/
+
+ //The null below can be relaced by a build-time value used instead of djConfig.scopeMap.
+ var sMap = null;
+
+ //See if new scopes need to be defined.
+ if((sMap || (typeof djConfig != "undefined" && djConfig.scopeMap)) && (typeof window != "undefined")){
+ var scopeDef = "", scopePrefix = "", scopeSuffix = "", scopeMap = {}, scopeMapRev = {};
+ sMap = sMap || djConfig.scopeMap;
+ for(var i = 0; i < sMap.length; i++){
+ //Make local variables, then global variables that use the locals.
+ var newScope = sMap[i];
+ scopeDef += "var " + newScope[0] + " = {}; " + newScope[1] + " = " + newScope[0] + ";" + newScope[1] + "._scopeName = '" + newScope[1] + "';";
+ scopePrefix += (i == 0 ? "" : ",") + newScope[0];
+ scopeSuffix += (i == 0 ? "" : ",") + newScope[1];
+ scopeMap[newScope[0]] = newScope[1];
+ scopeMapRev[newScope[1]] = newScope[0];
+ }
+
+ eval(scopeDef + "dojo._scopeArgs = [" + scopeSuffix + "];");
+
+ dojo._scopePrefixArgs = scopePrefix;
+ dojo._scopePrefix = "(function(" + scopePrefix + "){";
+ dojo._scopeSuffix = "})(" + scopeSuffix + ")";
+ dojo._scopeMap = scopeMap;
+ dojo._scopeMapRev = scopeMapRev;
+ }
+
+/*=====
+// note:
+// 'djConfig' does not exist under 'dojo.*' so that it can be set before the
+// 'dojo' variable exists.
+// note:
+// Setting any of these variables *after* the library has loaded does
+// nothing at all.
+
+djConfig = {
+ // summary:
+ // Application code can set the global 'djConfig' prior to loading
+ // the library to override certain global settings for how dojo works.
+ //
+ // isDebug: Boolean
+ // Defaults to `false`. If set to `true`, ensures that Dojo provides
+ // extende debugging feedback via Firebug. If Firebug is not available
+ // on your platform, setting `isDebug` to `true` will force Dojo to
+ // pull in (and display) the version of Firebug Lite which is
+ // integrated into the Dojo distribution, thereby always providing a
+ // debugging/logging console when `isDebug` is enabled. Note that
+ // Firebug's `console.*` methods are ALWAYS defined by Dojo. If
+ // `isDebug` is false and you are on a platform without Firebug, these
+ // methods will be defined as no-ops.
+ isDebug: false,
+ // debugAtAllCosts: Boolean
+ // Defaults to `false`. If set to `true`, this triggers an alternate
+ // mode of the package system in which dependencies are detected and
+ // only then are resources evaluated in dependency order via
+ // `<script>` tag inclusion. This may double-request resources and
+ // cause problems with scripts which expect `dojo.require()` to
+ // preform synchronously. `debugAtAllCosts` can be an invaluable
+ // debugging aid, but when using it, ensure that all code which
+ // depends on Dojo modules is wrapped in `dojo.addOnLoad()` handlers.
+ // Due to the somewhat unpredictable side-effects of using
+ // `debugAtAllCosts`, it is strongly recommended that you enable this
+ // flag as a last resort. `debugAtAllCosts` has no effect when loading
+ // resources across domains. For usage information, see the
+ // [Dojo Book](http://dojotoolkit.org/book/book-dojo/part-4-meta-dojo-making-your-dojo-code-run-faster-and-better/debugging-facilities/deb)
+ debugAtAllCosts: false,
+ // locale: String
+ // The locale to assume for loading localized resources in this page,
+ // specified according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt).
+ // Must be specified entirely in lowercase, e.g. `en-us` and `zh-cn`.
+ // See the documentation for `dojo.i18n` and `dojo.requireLocalization`
+ // for details on loading localized resources. If no locale is specified,
+ // Dojo assumes the locale of the user agent, according to `navigator.userLanguage`
+ // or `navigator.language` properties.
+ locale: undefined,
+ // extraLocale: Array
+ // No default value. Specifies additional locales whose
+ // resources should also be loaded alongside the default locale when
+ // calls to `dojo.requireLocalization()` are processed.
+ extraLocale: undefined,
+ // baseUrl: String
+ // The directory in which `dojo.js` is located. Under normal
+ // conditions, Dojo auto-detects the correct location from which it
+ // was loaded. You may need to manually configure `baseUrl` in cases
+ // where you have renamed `dojo.js` or in which `<base>` tags confuse
+ // some browsers (e.g., IE 6). The variable `dojo.baseUrl` is assigned
+ // either the value of `djConfig.baseUrl` if one is provided or the
+ // auto-detected root if not. Other modules are located relative to
+ // this path.
+ baseUrl: undefined,
+ // modulePaths: Object
+ // A map of module names to paths relative to `dojo.baseUrl`. The
+ // key/value pairs correspond directly to the arguments which
+ // `dojo.registerModulePath` accepts. Specifiying
+ // `djConfig.modulePaths = { "foo": "../../bar" }` is the equivalent
+ // of calling `dojo.registerModulePath("foo", "../../bar");`. Multiple
+ // modules may be configured via `djConfig.modulePaths`.
+ modulePaths: {},
+}
+=====*/
+
+(function(){
+ // firebug stubs
+
+ // if((!this["console"])||(!console["firebug"])){
+
+ if(!this["console"]){
+ this.console = {
+ log: function(){} // no-op
+ };
+ }
+
+ var cn = [
+ "assert", "count", "debug", "dir", "dirxml", "error", "group",
+ "groupEnd", "info", "profile", "profileEnd", "time", "timeEnd",
+ "trace", "warn", "log"
+ ];
+ var i=0, tn;
+ while((tn=cn[i++])){
+ if(!console[tn]){
+ (function(){
+ var tcn = tn+"";
+ console[tcn] = function(){
+ var a = Array.apply({}, arguments);
+ a.unshift(tcn+":");
+ console.log(a.join(" "));
+ }
+ })();
+ }
+ }
+
+ //TODOC: HOW TO DOC THIS?
+ // dojo is the root variable of (almost all) our public symbols -- make sure it is defined.
+ if(typeof dojo == "undefined"){
+ this.dojo = {
+ _scopeName: "dojo",
+ _scopePrefix: "",
+ _scopePrefixArgs: "",
+ _scopeSuffix: "",
+ _scopeMap: {},
+ _scopeMapRev: {}
+ };
+ }
+
+ var d = dojo;
+
+ //Need placeholders for dijit and dojox for scoping code.
+ if(typeof dijit == "undefined"){
+ this.dijit = {_scopeName: "dijit"};
+ }
+ if(typeof dojox == "undefined"){
+ this.dojox = {_scopeName: "dojox"};
+ }
+
+ if(!d._scopeArgs){
+ d._scopeArgs = [dojo, dijit, dojox];
+ }
+
+/*=====
+dojo.global = {
+ // summary:
+ // Alias for the global scope
+ // (e.g. the window object in a browser).
+ // description:
+ // Refer to 'dojo.global' rather than referring to window to ensure your
+ // code runs correctly in contexts other than web browsers (e.g. Rhino on a server).
+}
+=====*/
+ d.global = this;
+
+ d.config =/*===== djConfig = =====*/{
+ isDebug: false,
+ debugAtAllCosts: false
+ };
+
+ if(typeof djConfig != "undefined"){
+ for(var opt in djConfig){
+ d.config[opt] = djConfig[opt];
+ }
+ }
+
+ var _platforms = ["Browser", "Rhino", "Spidermonkey", "Mobile"];
+ var t;
+ while((t=_platforms.shift())){
+ d["is"+t] = false;
+ }
+
+/*=====
+ // Override locale setting, if specified
+ dojo.locale = {
+ // summary: the locale as defined by Dojo (read-only)
+ };
+=====*/
+ dojo.locale = d.config.locale;
+
+ var rev = "$Rev: 13707 $".match(/\d+/);
+
+ dojo.version = {
+ // summary:
+ // version number of dojo
+ // major: Integer
+ // Major version. If total version is "1.2.0beta1", will be 1
+ // minor: Integer
+ // Minor version. If total version is "1.2.0beta1", will be 2
+ // patch: Integer
+ // Patch version. If total version is "1.2.0beta1", will be 0
+ // flag: String
+ // Descriptor flag. If total version is "1.2.0beta1", will be "beta1"
+ // revision: Number
+ // The SVN rev from which dojo was pulled
+ major: 1, minor: 1, patch: 1, flag: "",
+ revision: rev ? +rev[0] : 999999, //FIXME: use NaN?
+ toString: function(){
+ with(d.version){
+ return major + "." + minor + "." + patch + flag + " (" + revision + ")"; // String
+ }
+ }
+ }
+
+ // Register with the OpenAjax hub
+ if(typeof OpenAjax != "undefined"){
+ OpenAjax.hub.registerLibrary(dojo._scopeName, "http://dojotoolkit.org", d.version.toString());
+ }
+
+ dojo._mixin = function(/*Object*/ obj, /*Object*/ props){
+ // summary:
+ // Adds all properties and methods of props to obj. This addition
+ // is "prototype extension safe", so that instances of objects
+ // will not pass along prototype defaults.
+ var tobj = {};
+ for(var x in props){
+ // the "tobj" condition avoid copying properties in "props"
+ // inherited from Object.prototype. For example, if obj has a custom
+ // toString() method, don't overwrite it with the toString() method
+ // that props inherited from Object.prototype
+ if(tobj[x] === undefined || tobj[x] != props[x]){
+ obj[x] = props[x];
+ }
+ }
+ // IE doesn't recognize custom toStrings in for..in
+ if(d["isIE"] && props){
+ var p = props.toString;
+ if(typeof p == "function" && p != obj.toString && p != tobj.toString &&
+ p != "\nfunction toString() {\n [native code]\n}\n"){
+ obj.toString = props.toString;
+ }
+ }
+ return obj; // Object
+ }
+
+ dojo.mixin = function(/*Object*/obj, /*Object...*/props){
+ // summary:
+ // Adds all properties and methods of props to obj and returns the
+ // (now modified) obj.
+ // description:
+ // `dojo.mixin` can mix multiple source objects into a
+ // destionation object which is then returned. Unlike regular
+ // `for...in` iteration, `dojo.mixin` is also smart about avoiding
+ // extensions which other toolkits may unwisely add to the root
+ // object prototype
+ // obj:
+ // The object to mix properties into. Also the return value.
+ // props:
+ // One or more objects whose values are successively copied into
+ // obj. If more than one of these objects contain the same value,
+ // the one specified last in the function call will "win".
+ // example:
+ // make a shallow copy of an object
+ // | var copy = dojo.mixin({}, source);
+ // example:
+ // many class constructors often take an object which specifies
+ // values to be configured on the object. In this case, it is
+ // often simplest to call `dojo.mixin` on the `this` object:
+ // | dojo.declare("acme.Base", null, {
+ // | constructor: function(properties){
+ // | // property configuration:
+ // | dojo.mixin(this, properties);
+ // |
+ // | console.debug(this.quip);
+ // | // ...
+ // | },
+ // | quip: "I wasn't born yesterday, you know - I've seen movies.",
+ // | // ...
+ // | });
+ // |
+ // | // create an instance of the class and configure it
+ // | var b = new acme.Base({quip: "That's what it does!" });
+ // example:
+ // copy in properties from multiple objects
+ // | var flattened = dojo.mixin(
+ // | {
+ // | name: "Frylock",
+ // | braces: true,
+ // | }
+ // | {
+ // | name: "Carl Brutanananadilewski"
+ // | }
+ // | );
+ // |
+ // | // will print "Carl Brutanananadilewski"
+ // | console.debug(flattened.name);
+ // | // will print "true"
+ // | console.debug(flattened.braces);
+ for(var i=1, l=arguments.length; i<l; i++){
+ d._mixin(obj, arguments[i]);
+ }
+ return obj; // Object
+ }
+
+ dojo._getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){
+ var obj=context || d.global;
+ for(var i=0, p; obj && (p=parts[i]); i++){
+ if(i == 0 && this._scopeMap[p]){
+ p = this._scopeMap[p];
+ }
+ obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined));
+ }
+ return obj; // mixed
+ }
+
+ dojo.setObject = function(/*String*/name, /*Object*/value, /*Object?*/context){
+ // summary:
+ // Set a property from a dot-separated string, such as "A.B.C"
+ // description:
+ // Useful for longer api chains where you have to test each object in
+ // the chain, or when you have an object reference in string format.
+ // Objects are created as needed along `path`. Returns the passed
+ // value if setting is successful or `undefined` if not.
+ // name:
+ // Path to a property, in the form "A.B.C".
+ // context:
+ // Optional. Object to use as root of path. Defaults to
+ // `dojo.global`.
+ // example:
+ // set the value of `foo.bar.baz`, regardless of whether
+ // intermediate objects already exist:
+ // | dojo.setObject("foo.bar.baz", value);
+ // example:
+ // without `dojo.setObject`, we often see code like this:
+ // | // ensure that intermediate objects are available
+ // | if(!obj["parent"]){ obj.parent = {}; }
+ // | if(!obj.parent["child"]){ obj.parent.child= {}; }
+ // | // now we can safely set the property
+ // | obj.parent.child.prop = "some value";
+ // wheras with `dojo.setObject`, we can shorten that to:
+ // | dojo.setObject("parent.child.prop", "some value", obj);
+ var parts=name.split("."), p=parts.pop(), obj=d._getProp(parts, true, context);
+ return obj && p ? (obj[p]=value) : undefined; // Object
+ }
+
+ dojo.getObject = function(/*String*/name, /*Boolean*/create, /*Object*/context){
+ // summary:
+ // Get a property from a dot-separated string, such as "A.B.C"
+ // description:
+ // Useful for longer api chains where you have to test each object in
+ // the chain, or when you have an object reference in string format.
+ // name:
+ // Path to an property, in the form "A.B.C".
+ // context:
+ // Optional. Object to use as root of path. Defaults to
+ // 'dojo.global'. Null may be passed.
+ // create:
+ // Optional. Defaults to `false`. If `true`, Objects will be
+ // created at any point along the 'path' that is undefined.
+ return d._getProp(name.split("."), create, context); // Object
+ }
+
+ dojo.exists = function(/*String*/name, /*Object?*/obj){
+ // summary:
+ // determine if an object supports a given method
+ // description:
+ // useful for longer api chains where you have to test each object in
+ // the chain
+ // name:
+ // Path to an object, in the form "A.B.C".
+ // obj:
+ // Object to use as root of path. Defaults to
+ // 'dojo.global'. Null may be passed.
+ // example:
+ // | // define an object
+ // | var foo = {
+ // | bar: { }
+ // | };
+ // |
+ // | // search the global scope
+ // | dojo.exists("foo.bar"); // true
+ // | dojo.exists("foo.bar.baz"); // false
+ // |
+ // | // search from a particular scope
+ // | dojo.exists("bar", foo); // true
+ // | dojo.exists("bar.baz", foo); // false
+ return !!d.getObject(name, false, obj); // Boolean
+ }
+
+
+ dojo["eval"] = function(/*String*/ scriptFragment){
+ // summary:
+ // Perform an evaluation in the global scope. Use this rather than
+ // calling 'eval()' directly.
+ // description:
+ // Placed in a separate function to minimize size of trapped
+ // exceptions. Calling eval() directly from some other scope may
+ // complicate tracebacks on some platforms.
+ // return:
+ // The result of the evaluation. Often `undefined`
+
+
+ // note:
+ // - JSC eval() takes an optional second argument which can be 'unsafe'.
+ // - Mozilla/SpiderMonkey eval() takes an optional second argument which is the
+ // scope object for new symbols.
+
+ // FIXME: investigate Joseph Smarr's technique for IE:
+ // http://josephsmarr.com/2007/01/31/fixing-eval-to-use-global-scope-in-ie/
+ // see also:
+ // http://trac.dojotoolkit.org/ticket/744
+ return d.global.eval ? d.global.eval(scriptFragment) : eval(scriptFragment); // Object
+ }
+
+ /*=====
+ dojo.deprecated = function(behaviour, extra, removal){
+ // summary:
+ // Log a debug message to indicate that a behavior has been
+ // deprecated.
+ // behaviour: String
+ // The API or behavior being deprecated. Usually in the form
+ // of "myApp.someFunction()".
+ // extra: String?
+ // Text to append to the message. Often provides advice on a
+ // new function or facility to achieve the same goal during
+ // the deprecation period.
+ // removal: String?
+ // Text to indicate when in the future the behavior will be
+ // removed. Usually a version number.
+ // example:
+ // | dojo.deprecated("myApp.getTemp()", "use myApp.getLocaleTemp() instead", "1.0");
+ }
+
+ dojo.experimental = function(moduleName, extra){
+ // summary: Marks code as experimental.
+ // description:
+ // This can be used to mark a function, file, or module as
+ // experimental. Experimental code is not ready to be used, and the
+ // APIs are subject to change without notice. Experimental code may be
+ // completed deleted without going through the normal deprecation
+ // process.
+ // moduleName: String
+ // The name of a module, or the name of a module file or a specific
+ // function
+ // extra: String?
+ // some additional message for the user
+ // example:
+ // | dojo.experimental("dojo.data.Result");
+ // example:
+ // | dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA");
+ }
+ =====*/
+
+ //Real functions declared in dojo._firebug.firebug.
+ d.deprecated = d.experimental = function(){};
+
+})();
+// vim:ai:ts=4:noet
+
+/*
+ * loader.js - A bootstrap module. Runs before the hostenv_*.js file. Contains
+ * all of the package loading methods.
+ */
+
+(function(){
+ var d = dojo;
+
+ d.mixin(d, {
+ _loadedModules: {},
+ _inFlightCount: 0,
+ _hasResource: {},
+
+ _modulePrefixes: {
+ dojo: { name: "dojo", value: "." },
+ // dojox: { name: "dojox", value: "../dojox" },
+ // dijit: { name: "dijit", value: "../dijit" },
+ doh: { name: "doh", value: "../util/doh" },
+ tests: { name: "tests", value: "tests" }
+ },
+
+ _moduleHasPrefix: function(/*String*/module){
+ // summary: checks to see if module has been established
+ var mp = this._modulePrefixes;
+ return !!(mp[module] && mp[module].value); // Boolean
+ },
+
+ _getModulePrefix: function(/*String*/module){
+ // summary: gets the prefix associated with module
+ var mp = this._modulePrefixes;
+ if(this._moduleHasPrefix(module)){
+ return mp[module].value; // String
+ }
+ return module; // String
+ },
+
+ _loadedUrls: [],
+
+ //WARNING:
+ // This variable is referenced by packages outside of bootstrap:
+ // FloatingPane.js and undo/browser.js
+ _postLoad: false,
+
+ //Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
+ _loaders: [],
+ _unloaders: [],
+ _loadNotifying: false
+ });
+
+
+ dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){
+ // summary:
+ // Load a Javascript module given a relative path
+ //
+ // description:
+ // Loads and interprets the script located at relpath, which is
+ // relative to the script root directory. If the script is found but
+ // its interpretation causes a runtime exception, that exception is
+ // not caught by us, so the caller will see it. We return a true
+ // value if and only if the script is found.
+ //
+ // relpath:
+ // A relative path to a script (no leading '/', and typically ending
+ // in '.js').
+ // module:
+ // A module whose existance to check for after loading a path. Can be
+ // used to determine success or failure of the load.
+ // cb:
+ // a callback function to pass the result of evaluating the script
+
+ var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : this.baseUrl) + relpath;
+ try{
+ return !module ? this._loadUri(uri, cb) : this._loadUriAndCheck(uri, module, cb); // Boolean
+ }catch(e){
+ console.error(e);
+ return false; // Boolean
+ }
+ }
+
+ dojo._loadUri = function(/*String*/uri, /*Function?*/cb){
+ // summary:
+ // Loads JavaScript from a URI
+ // description:
+ // Reads the contents of the URI, and evaluates the contents. This is
+ // used to load modules as well as resource bundles. Returns true if
+ // it succeeded. Returns false if the URI reading failed. Throws if
+ // the evaluation throws.
+ // uri: a uri which points at the script to be loaded
+ // cb:
+ // a callback function to process the result of evaluating the script
+ // as an expression, typically used by the resource bundle loader to
+ // load JSON-style resources
+
+ if(this._loadedUrls[uri]){
+ return true; // Boolean
+ }
+ var contents = this._getText(uri, true);
+ if(!contents){ return false; } // Boolean
+ this._loadedUrls[uri] = true;
+ this._loadedUrls.push(uri);
+ if(cb){
+ contents = '('+contents+')';
+ }else{
+ //Only do the scoping if no callback. If a callback is specified,
+ //it is most likely the i18n bundle stuff.
+ contents = this._scopePrefix + contents + this._scopeSuffix;
+ }
+ if(d.isMoz){ contents += "\r\n//@ sourceURL=" + uri; } // debugging assist for Firebug
+ var value = d["eval"](contents);
+ if(cb){ cb(value); }
+ return true; // Boolean
+ }
+
+ // FIXME: probably need to add logging to this method
+ dojo._loadUriAndCheck = function(/*String*/uri, /*String*/moduleName, /*Function?*/cb){
+ // summary: calls loadUri then findModule and returns true if both succeed
+ var ok = false;
+ try{
+ ok = this._loadUri(uri, cb);
+ }catch(e){
+ console.error("failed loading " + uri + " with error: " + e);
+ }
+ return !!(ok && this._loadedModules[moduleName]); // Boolean
+ }
+
+ dojo.loaded = function(){
+ // summary:
+ // signal fired when initial environment and package loading is
+ // complete. You may use dojo.addOnLoad() or dojo.connect() to
+ // this method in order to handle initialization tasks that
+ // require the environment to be initialized. In a browser host,
+ // declarative widgets will be constructed when this function
+ // finishes runing.
+ this._loadNotifying = true;
+ this._postLoad = true;
+ var mll = d._loaders;
+
+ //Clear listeners so new ones can be added
+ //For other xdomain package loads after the initial load.
+ this._loaders = [];
+
+ for(var x = 0; x < mll.length; x++){
+ try{
+ mll[x]();
+ }catch(e){
+ throw e;
+ console.error("dojo.addOnLoad callback failed: " + e, e); /* let other load events fire, like the parser, but report the error */
+ }
+ }
+
+ this._loadNotifying = false;
+
+ //Make sure nothing else got added to the onload queue
+ //after this first run. If something did, and we are not waiting for any
+ //more inflight resources, run again.
+ if(d._postLoad && d._inFlightCount == 0 && mll.length){
+ d._callLoaded();
+ }
+ }
+
+ dojo.unloaded = function(){
+ // summary:
+ // signal fired by impending environment destruction. You may use
+ // dojo.addOnUnload() or dojo.connect() to this method to perform
+ // page/application cleanup methods.
+ var mll = this._unloaders;
+ while(mll.length){
+ (mll.pop())();
+ }
+ }
+
+ var onto = function(arr, obj, fn){
+ if(!fn){
+ arr.push(obj);
+ }else if(fn){
+ var func = (typeof fn == "string") ? obj[fn] : fn;
+ arr.push(function(){ func.call(obj); });
+ }
+ }
+
+ dojo.addOnLoad = function(/*Object?*/obj, /*String|Function*/functionName){
+ // summary:
+ // Registers a function to be triggered after the DOM has finished
+ // loading and widgets declared in markup have been instantiated.
+ // Images and CSS files may or may not have finished downloading when
+ // the specified function is called. (Note that widgets' CSS and HTML
+ // code is guaranteed to be downloaded before said widgets are
+ // instantiated.)
+ // example:
+ // | dojo.addOnLoad(functionPointer);
+ // | dojo.addOnLoad(object, "functionName");
+ // | dojo.addOnLoad(object, function(){ /* ... */});
+
+ onto(d._loaders, obj, functionName);
+
+ //Added for xdomain loading. dojo.addOnLoad is used to
+ //indicate callbacks after doing some dojo.require() statements.
+ //In the xdomain case, if all the requires are loaded (after initial
+ //page load), then immediately call any listeners.
+ if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){
+ d._callLoaded();
+ }
+ }
+
+ dojo.addOnUnload = function(/*Object?*/obj, /*String|Function?*/functionName){
+ // summary:
+ // registers a function to be triggered when the page unloads
+ // example:
+ // | dojo.addOnUnload(functionPointer)
+ // | dojo.addOnUnload(object, "functionName")
+ // | dojo.addOnUnload(object, function(){ /* ... */});
+
+ onto(d._unloaders, obj, functionName);
+ }
+
+ dojo._modulesLoaded = function(){
+ if(d._postLoad){ return; }
+ if(d._inFlightCount > 0){
+ console.warn("files still in flight!");
+ return;
+ }
+ d._callLoaded();
+ }
+
+ dojo._callLoaded = function(){
+
+ // The "object" check is for IE, and the other opera check fixes an
+ // issue in Opera where it could not find the body element in some
+ // widget test cases. For 0.9, maybe route all browsers through the
+ // setTimeout (need protection still for non-browser environments
+ // though). This might also help the issue with FF 2.0 and freezing
+ // issues where we try to do sync xhr while background css images are
+ // being loaded (trac #2572)? Consider for 0.9.
+ if(typeof setTimeout == "object" || (dojo.config.useXDomain && d.isOpera)){
+ if(dojo.isAIR){
+ setTimeout(function(){dojo.loaded();}, 0);
+ }else{
+ setTimeout(dojo._scopeName + ".loaded();", 0);
+ }
+ }else{
+ d.loaded();
+ }
+ }
+
+ dojo._getModuleSymbols = function(/*String*/modulename){
+ // summary:
+ // Converts a module name in dotted JS notation to an array
+ // representing the path in the source tree
+ var syms = modulename.split(".");
+ for(var i = syms.length; i>0; i--){
+ var parentModule = syms.slice(0, i).join(".");
+ if((i==1) && !this._moduleHasPrefix(parentModule)){
+ // Support default module directory (sibling of dojo) for top-level modules
+ syms[0] = "../" + syms[0];
+ }else{
+ var parentModulePath = this._getModulePrefix(parentModule);
+ if(parentModulePath != parentModule){
+ syms.splice(0, i, parentModulePath);
+ break;
+ }
+ }
+ }
+ // console.debug(syms);
+ return syms; // Array
+ }
+
+ dojo._global_omit_module_check = false;
+
+ dojo._loadModule = dojo.require = function(/*String*/moduleName, /*Boolean?*/omitModuleCheck){
+ // summary:
+ // loads a Javascript module from the appropriate URI
+ // moduleName:
+ // module name to load. Module paths are de-referenced by dojo's
+ // internal mapping of locations to names and are disambiguated by
+ // longest prefix. See `dojo.registerModulePath()` for details on
+ // registering new modules.
+ // omitModuleCheck:
+ // if `true`, omitModuleCheck skips the step of ensuring that the
+ // loaded file actually defines the symbol it is referenced by.
+ // For example if it called as `dojo._loadModule("a.b.c")` and the
+ // file located at `a/b/c.js` does not define an object `a.b.c`,
+ // and exception will be throws whereas no exception is raised
+ // when called as `dojo._loadModule("a.b.c", true)`
+ // description:
+ // `dojo._loadModule("A.B")` first checks to see if symbol A.B is
+ // defined. If it is, it is simply returned (nothing to do).
+ //
+ // If it is not defined, it will look for `A/B.js` in the script root
+ // directory.
+ //
+ // `dojo._loadModule` throws an excpetion if it cannot find a file
+ // to load, or if the symbol `A.B` is not defined after loading.
+ //
+ // It returns the object `A.B`.
+ //
+ // `dojo._loadModule()` does nothing about importing symbols into
+ // the current namespace. It is presumed that the caller will
+ // take care of that. For example, to import all symbols into a
+ // local block, you might write:
+ //
+ // | with (dojo._loadModule("A.B")) {
+ // | ...
+ // | }
+ //
+ // And to import just the leaf symbol to a local variable:
+ //
+ // | var B = dojo._loadModule("A.B");
+ // | ...
+ // returns: the required namespace object
+ omitModuleCheck = this._global_omit_module_check || omitModuleCheck;
+
+ //Check if it is already loaded.
+ var module = this._loadedModules[moduleName];
+ if(module){
+ return module;
+ }
+
+ // convert periods to slashes
+ var relpath = this._getModuleSymbols(moduleName).join("/") + '.js';
+
+ var modArg = (!omitModuleCheck) ? moduleName : null;
+ var ok = this._loadPath(relpath, modArg);
+
+ if(!ok && !omitModuleCheck){
+ throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
+ }
+
+ // check that the symbol was defined
+ // Don't bother if we're doing xdomain (asynchronous) loading.
+ if(!omitModuleCheck && !this._isXDomain){
+ // pass in false so we can give better error
+ module = this._loadedModules[moduleName];
+ if(!module){
+ throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'");
+ }
+ }
+
+ return module;
+ }
+
+ dojo.provide = function(/*String*/ resourceName){
+ // summary:
+ // Each javascript source file must have at least one
+ // `dojo.provide()` call at the top of the file, corresponding to
+ // the file name. For example, `js/dojo/foo.js` must have
+ // `dojo.provide("dojo.foo");` before any calls to
+ // `dojo.require()` are made.
+ // description:
+ // Each javascript source file is called a resource. When a
+ // resource is loaded by the browser, `dojo.provide()` registers
+ // that it has been loaded.
+ //
+ // For backwards compatibility reasons, in addition to registering
+ // the resource, `dojo.provide()` also ensures that the javascript
+ // object for the module exists. For example,
+ // `dojo.provide("dojox.data.FlickrStore")`, in addition to
+ // registering that `FlickrStore.js` is a resource for the
+ // `dojox.data` module, will ensure that the `dojox.data`
+ // javascript object exists, so that calls like
+ // `dojo.data.foo = function(){ ... }` don't fail.
+ //
+ // In the case of a build where multiple javascript source files
+ // are combined into one bigger file (similar to a .lib or .jar
+ // file), that file may contain multiple dojo.provide() calls, to
+ // note that it includes multiple resources.
+
+ //Make sure we have a string.
+ resourceName = resourceName + "";
+ return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object
+ }
+
+ //Start of old bootstrap2:
+
+ dojo.platformRequire = function(/*Object*/modMap){
+ // summary:
+ // require one or more modules based on which host environment
+ // Dojo is currently operating in
+ // description:
+ // This method takes a "map" of arrays which one can use to
+ // optionally load dojo modules. The map is indexed by the
+ // possible dojo.name_ values, with two additional values:
+ // "default" and "common". The items in the "default" array will
+ // be loaded if none of the other items have been choosen based on
+ // dojo.name_, set by your host environment. The items in the
+ // "common" array will *always* be loaded, regardless of which
+ // list is chosen.
+ // example:
+ // | dojo.platformRequire({
+ // | browser: [
+ // | "foo.sample", // simple module
+ // | "foo.test",
+ // | ["foo.bar.baz", true] // skip object check in _loadModule
+ // | ],
+ // | default: [ "foo.sample._base" ],
+ // | common: [ "important.module.common" ]
+ // | });
+
+ var common = modMap.common || [];
+ var result = common.concat(modMap[d._name] || modMap["default"] || []);
+
+ for(var x=0; x<result.length; x++){
+ var curr = result[x];
+ if(curr.constructor == Array){
+ d._loadModule.apply(d, curr);
+ }else{
+ d._loadModule(curr);
+ }
+ }
+ }
+
+ dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){
+ // summary:
+ // If the condition is true then call dojo.require() for the specified
+ // resource
+ if(condition === true){
+ // FIXME: why do we support chained require()'s here? does the build system?
+ var args = [];
+ for(var i = 1; i < arguments.length; i++){
+ args.push(arguments[i]);
+ }
+ d.require.apply(d, args);
+ }
+ }
+
+ dojo.requireAfterIf = d.requireIf;
+
+ dojo.registerModulePath = function(/*String*/module, /*String*/prefix){
+ // summary:
+ // maps a module name to a path
+ // description:
+ // An unregistered module is given the default path of ../[module],
+ // relative to Dojo root. For example, module acme is mapped to
+ // ../acme. If you want to use a different module name, use
+ // dojo.registerModulePath.
+ // example:
+ // If your dojo.js is located at this location in the web root:
+ // | /myapp/js/dojo/dojo/dojo.js
+ // and your modules are located at:
+ // | /myapp/js/foo/bar.js
+ // | /myapp/js/foo/baz.js
+ // | /myapp/js/foo/thud/xyzzy.js
+ // Your application can tell Dojo to locate the "foo" namespace by calling:
+ // | dojo.registerModulePath("foo", "../../foo");
+ // At which point you can then use dojo.require() to load the
+ // modules (assuming they provide() the same things which are
+ // required). The full code might be:
+ // | <script type="text/javascript"
+ // | src="/myapp/js/dojo/dojo/dojo.js"></script>
+ // | <script type="text/javascript">
+ // | dojo.registerModulePath("foo", "../../foo");
+ // | dojo.require("foo.bar");
+ // | dojo.require("foo.baz");
+ // | dojo.require("foo.thud.xyzzy");
+ // | </script>
+ d._modulePrefixes[module] = { name: module, value: prefix };
+ }
+
+ dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
+ // summary:
+ // Declares translated resources and loads them if necessary, in the
+ // same style as dojo.require. Contents of the resource bundle are
+ // typically strings, but may be any name/value pair, represented in
+ // JSON format. See also dojo.i18n.getLocalization.
+ // moduleName:
+ // name of the package containing the "nls" directory in which the
+ // bundle is found
+ // bundleName:
+ // bundle name, i.e. the filename without the '.js' suffix
+ // locale:
+ // the locale to load (optional) By default, the browser's user
+ // locale as defined by dojo.locale
+ // availableFlatLocales:
+ // A comma-separated list of the available, flattened locales for this
+ // bundle. This argument should only be set by the build process.
+ // description:
+ // Load translated resource bundles provided underneath the "nls"
+ // directory within a package. Translated resources may be located in
+ // different packages throughout the source tree. For example, a
+ // particular widget may define one or more resource bundles,
+ // structured in a program as follows, where moduleName is
+ // mycode.mywidget and bundleNames available include bundleone and
+ // bundletwo:
+ //
+ // | ...
+ // | mycode/
+ // | mywidget/
+ // | nls/
+ // | bundleone.js (the fallback translation, English in this example)
+ // | bundletwo.js (also a fallback translation)
+ // | de/
+ // | bundleone.js
+ // | bundletwo.js
+ // | de-at/
+ // | bundleone.js
+ // | en/
+ // | (empty; use the fallback translation)
+ // | en-us/
+ // | bundleone.js
+ // | en-gb/
+ // | bundleone.js
+ // | es/
+ // | bundleone.js
+ // | bundletwo.js
+ // | ...etc
+ // | ...
+ //
+ // Each directory is named for a locale as specified by RFC 3066,
+ // (http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase.
+ // Note that the two bundles in the example do not define all the
+ // same variants. For a given locale, bundles will be loaded for
+ // that locale and all more general locales above it, including a
+ // fallback at the root directory. For example, a declaration for
+ // the "de-at" locale will first load `nls/de-at/bundleone.js`,
+ // then `nls/de/bundleone.js` and finally `nls/bundleone.js`. The
+ // data will be flattened into a single Object so that lookups
+ // will follow this cascading pattern. An optional build step can
+ // preload the bundles to avoid data redundancy and the multiple
+ // network hits normally required to load these resources.
+
+ d.require("dojo.i18n");
+ d.i18n._requireLocalization.apply(d.hostenv, arguments);
+ };
+
+
+ var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$");
+ var ire = new RegExp("^((([^:]+:)?([^@]+))@)?([^:]*)(:([0-9]+))?$");
+
+ dojo._Url = function(/*dojo._Url||String...*/){
+ // summary:
+ // Constructor to create an object representing a URL.
+ // It is marked as private, since we might consider removing
+ // or simplifying it.
+ // description:
+ // Each argument is evaluated in order relative to the next until
+ // a canonical uri is produced. To get an absolute Uri relative to
+ // the current document use:
+ // new dojo._Url(document.baseURI, url)
+
+ var n = null;
+
+ // TODO: support for IPv6, see RFC 2732
+ var _a = arguments;
+ var uri = [_a[0]];
+ // resolve uri components relative to each other
+ for(var i = 1; i<_a.length; i++){
+ if(!_a[i]){ continue; }
+
+ // Safari doesn't support this.constructor so we have to be explicit
+ // FIXME: Tracked (and fixed) in Webkit bug 3537.
+ // http://bugs.webkit.org/show_bug.cgi?id=3537
+ var relobj = new d._Url(_a[i]+"");
+ var uriobj = new d._Url(uri[0]+"");
+
+ if(
+ relobj.path == "" &&
+ !relobj.scheme &&
+ !relobj.authority &&
+ !relobj.query
+ ){
+ if(relobj.fragment != n){
+ uriobj.fragment = relobj.fragment;
+ }
+ relobj = uriobj;
+ }else if(!relobj.scheme){
+ relobj.scheme = uriobj.scheme;
+
+ if(!relobj.authority){
+ relobj.authority = uriobj.authority;
+
+ if(relobj.path.charAt(0) != "/"){
+ var path = uriobj.path.substring(0,
+ uriobj.path.lastIndexOf("/") + 1) + relobj.path;
+
+ var segs = path.split("/");
+ for(var j = 0; j < segs.length; j++){
+ if(segs[j] == "."){
+ // flatten "./" references
+ if(j == segs.length - 1){
+ segs[j] = "";
+ }else{
+ segs.splice(j, 1);
+ j--;
+ }
+ }else if(j > 0 && !(j == 1 && segs[0] == "") &&
+ segs[j] == ".." && segs[j-1] != ".."){
+ // flatten "../" references
+ if(j == (segs.length - 1)){
+ segs.splice(j, 1);
+ segs[j - 1] = "";
+ }else{
+ segs.splice(j - 1, 2);
+ j -= 2;
+ }
+ }
+ }
+ relobj.path = segs.join("/");
+ }
+ }
+ }
+
+ uri = [];
+ if(relobj.scheme){
+ uri.push(relobj.scheme, ":");
+ }
+ if(relobj.authority){
+ uri.push("//", relobj.authority);
+ }
+ uri.push(relobj.path);
+ if(relobj.query){
+ uri.push("?", relobj.query);
+ }
+ if(relobj.fragment){
+ uri.push("#", relobj.fragment);
+ }
+ }
+
+ this.uri = uri.join("");
+
+ // break the uri into its main components
+ var r = this.uri.match(ore);
+
+ this.scheme = r[2] || (r[1] ? "" : n);
+ this.authority = r[4] || (r[3] ? "" : n);
+ this.path = r[5]; // can never be undefined
+ this.query = r[7] || (r[6] ? "" : n);
+ this.fragment = r[9] || (r[8] ? "" : n);
+
+ if(this.authority != n){
+ // server based naming authority
+ r = this.authority.match(ire);
+
+ this.user = r[3] || n;
+ this.password = r[4] || n;
+ this.host = r[5];
+ this.port = r[7] || n;
+ }
+ }
+
+ dojo._Url.prototype.toString = function(){ return this.uri; };
+
+ dojo.moduleUrl = function(/*String*/module, /*dojo._Url||String*/url){
+ // summary:
+ // Returns a `dojo._Url` object relative to a module.
+ // example:
+ // | var pngPath = dojo.moduleUrl("acme","images/small.png");
+ // | console.dir(pngPath); // list the object properties
+ // | // create an image and set it's source to pngPath's value:
+ // | var img = document.createElement("img");
+ // | // NOTE: we assign the string representation of the url object
+ // | img.src = pngPath.toString();
+ // | // add our image to the document
+ // | dojo.body().appendChild(img);
+ // example:
+ // you may de-reference as far as you like down the package
+ // hierarchy. This is sometimes handy to avoid lenghty relative
+ // urls or for building portable sub-packages. In this example,
+ // the `acme.widget` and `acme.util` directories may be located
+ // under different roots (see `dojo.registerModulePath`) but the
+ // the modules which reference them can be unaware of their
+ // relative locations on the filesystem:
+ // | // somewhere in a configuration block
+ // | dojo.registerModulePath("acme.widget", "../../acme/widget");
+ // | dojo.registerModulePath("acme.util", "../../util");
+ // |
+ // | // ...
+ // |
+ // | // code in a module using acme resources
+ // | var tmpltPath = dojo.moduleUrl("acme.widget","templates/template.html");
+ // | var dataPath = dojo.moduleUrl("acme.util","resources/data.json");
+
+ var loc = d._getModuleSymbols(module).join('/');
+ if(!loc){ return null; }
+ if(loc.lastIndexOf("/") != loc.length-1){
+ loc += "/";
+ }
+
+ //If the path is an absolute path (starts with a / or is on another
+ //domain/xdomain) then don't add the baseUrl.
+ var colonIndex = loc.indexOf(":");
+ if(loc.charAt(0) != "/" && (colonIndex == -1 || colonIndex > loc.indexOf("/"))){
+ loc = d.baseUrl + loc;
+ }
+
+ return new d._Url(loc, url); // String
+ }
+})();
+
+/*=====
+dojo.isBrowser = {
+ // example:
+ // | if(dojo.isBrowser){ ... }
+};
+
+dojo.isFF = {
+ // example:
+ // | if(dojo.isFF > 1){ ... }
+};
+
+dojo.isIE = {
+ // example:
+ // | if(dojo.isIE > 6){
+ // | // we are IE7
+ // | }
+};
+
+dojo.isSafari = {
+ // example:
+ // | if(dojo.isSafari){ ... }
+ // example:
+ // Detect iPhone:
+ // | if(dojo.isSafari && (navigator.userAgent.indexOf("iPhone") < 0)){
+ // | // we are iPhone. iPod touch reports "iPod" above
+ // | }
+};
+
+dojo = {
+ // isBrowser: Boolean
+ // True if the client is a web-browser
+ isBrowser: true,
+ // isFF: Number
+ // Greater than zero if client is FireFox. 0 otherwise. Corresponds to
+ // major detected FireFox version (1.5, 2, 3, etc.)
+ isFF: 2,
+ // isIE: Number
+ // Greater than zero if client is MSIE(PC). 0 otherwise. Corresponds to
+ // major detected IE version (6, 7, 8, etc.)
+ isIE: 6,
+ // isKhtml: Number
+ // Greater than zero if client is a KTHML-derived browser (Konqueror,
+ // Safari, etc.). 0 otherwise. Corresponds to major detected version.
+ isKhtml: 0,
+ // isMozilla: Number
+ // Greater than zero if client is a Mozilla-based browser (Firefox,
+ // SeaMonkey). 0 otherwise. Corresponds to major detected version.
+ isMozilla: 0,
+ // isOpera: Number
+ // Greater than zero if client is Opera. 0 otherwise. Corresponds to
+ // major detected version.
+ isOpera: 0,
+ // isSafari: Number
+ // Greater than zero if client is Safari or iPhone. 0 otherwise.
+ isSafari: 0
+}
+=====*/
+
+if(typeof window != 'undefined'){
+ dojo.isBrowser = true;
+ dojo._name = "browser";
+
+
+ // attempt to figure out the path to dojo if it isn't set in the config
+ (function(){
+ var d = dojo;
+ // this is a scope protection closure. We set browser versions and grab
+ // the URL we were loaded from here.
+
+ // grab the node we were loaded from
+ if(document && document.getElementsByTagName){
+ var scripts = document.getElementsByTagName("script");
+ var rePkg = /dojo(\.xd)?\.js(\W|$)/i;
+ for(var i = 0; i < scripts.length; i++){
+ var src = scripts[i].getAttribute("src");
+ if(!src){ continue; }
+ var m = src.match(rePkg);
+ if(m){
+ // find out where we came from
+ if(!d.config.baseUrl){
+ d.config.baseUrl = src.substring(0, m.index);
+ }
+ // and find out if we need to modify our behavior
+ var cfg = scripts[i].getAttribute("djConfig");
+ if(cfg){
+ var cfgo = eval("({ "+cfg+" })");
+ for(var x in cfgo){
+ dojo.config[x] = cfgo[x];
+ }
+ }
+ break; // "first Dojo wins"
+ }
+ }
+ }
+ d.baseUrl = d.config.baseUrl;
+
+ // fill in the rendering support information in dojo.render.*
+ var n = navigator;
+ var dua = n.userAgent;
+ var dav = n.appVersion;
+ var tv = parseFloat(dav);
+
+ d.isOpera = (dua.indexOf("Opera") >= 0) ? tv : 0;
+ // safari detection derived from:
+ // http://developer.apple.com/internet/safari/faq.html#anchor2
+ // http://developer.apple.com/internet/safari/uamatrix.html
+ var idx = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0);
+ if(idx){
+ // try to grab the explicit Safari version first. If we don't get
+ // one, look for 419.3+ as the indication that we're on something
+ // "Safari 3-ish". Lastly, default to "Safari 2" handling.
+ d.isSafari = parseFloat(dav.split("Version/")[1]) || ( ( parseFloat(dav.substr(idx+7)) >= 419.3 ) ? 3 : 2 ) || 2;
+ }
+ d.isAIR = (dua.indexOf("AdobeAIR") >= 0) ? 1 : 0;
+ d.isKhtml = (dav.indexOf("Konqueror") >= 0 || d.isSafari) ? tv : 0;
+ d.isMozilla = d.isMoz = (dua.indexOf("Gecko") >= 0 && !d.isKhtml) ? tv : 0;
+ d.isFF = d.isIE = 0;
+ if(d.isMoz){
+ d.isFF = parseFloat(dua.split("Firefox/")[1]) || 0;
+ }
+ if(document.all && !d.isOpera){
+ d.isIE = parseFloat(dav.split("MSIE ")[1]) || 0;
+ }
+
+ //Workaround to get local file loads of dojo to work on IE 7
+ //by forcing to not use native xhr.
+ if(dojo.isIE && window.location.protocol === "file:"){
+ dojo.config.ieForceActiveXXhr=true;
+ }
+
+ var cm = document.compatMode;
+ d.isQuirks = cm == "BackCompat" || cm == "QuirksMode" || d.isIE < 6;
+
+ // TODO: is the HTML LANG attribute relevant?
+ d.locale = dojo.config.locale || (d.isIE ? n.userLanguage : n.language).toLowerCase();
+
+ // These are in order of decreasing likelihood; this will change in time.
+ d._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
+
+ d._xhrObj = function(){
+ // summary:
+ // does the work of portably generating a new XMLHTTPRequest
+ // object.
+ var http = null;
+ var last_e = null;
+ if(!dojo.isIE || !dojo.config.ieForceActiveXXhr){
+ try{ http = new XMLHttpRequest(); }catch(e){}
+ }
+ if(!http){
+ for(var i=0; i<3; ++i){
+ var progid = d._XMLHTTP_PROGIDS[i];
+ try{
+ http = new ActiveXObject(progid);
+ }catch(e){
+ last_e = e;
+ }
+
+ if(http){
+ d._XMLHTTP_PROGIDS = [progid]; // so faster next time
+ break;
+ }
+ }
+ }
+
+ if(!http){
+ throw new Error("XMLHTTP not available: "+last_e);
+ }
+
+ return http; // XMLHTTPRequest instance
+ }
+
+ d._isDocumentOk = function(http){
+ var stat = http.status || 0;
+ return (stat >= 200 && stat < 300) || // Boolean
+ stat == 304 || // allow any 2XX response code
+ stat == 1223 || // get it out of the cache
+ (!stat && (location.protocol=="file:" || location.protocol=="chrome:") ); // Internet Explorer mangled the status code
+ }
+
+ //See if base tag is in use.
+ //This is to fix http://trac.dojotoolkit.org/ticket/3973,
+ //but really, we need to find out how to get rid of the dojo._Url reference
+ //below and still have DOH work with the dojo.i18n test following some other
+ //test that uses the test frame to load a document (trac #2757).
+ //Opera still has problems, but perhaps a larger issue of base tag support
+ //with XHR requests (hasBase is true, but the request is still made to document
+ //path, not base path).
+ var owloc = window.location+"";
+ var base = document.getElementsByTagName("base");
+ var hasBase = (base && base.length > 0);
+
+ d._getText = function(/*URI*/ uri, /*Boolean*/ fail_ok){
+ // summary: Read the contents of the specified uri and return those contents.
+ // uri:
+ // A relative or absolute uri. If absolute, it still must be in
+ // the same "domain" as we are.
+ // fail_ok:
+ // Default false. If fail_ok and loading fails, return null
+ // instead of throwing.
+ // returns: The response text. null is returned when there is a
+ // failure and failure is okay (an exception otherwise)
+
+ // alert("_getText: " + uri);
+
+ // NOTE: must be declared before scope switches ie. this._xhrObj()
+ var http = this._xhrObj();
+
+ if(!hasBase && dojo._Url){
+ uri = (new dojo._Url(owloc, uri)).toString();
+ }
+ /*
+ console.debug("_getText:", uri);
+ console.debug(window.location+"");
+ alert(uri);
+ */
+
+ if(d.config.cacheBust){
+ uri += (uri.indexOf("?") == -1 ? "?" : "&") + String(d.config.cacheBust).replace(/\W+/g,"");
+ }
+
+ http.open('GET', uri, false);
+ try{
+ http.send(null);
+ // alert(http);
+ if(!d._isDocumentOk(http)){
+ var err = Error("Unable to load "+uri+" status:"+ http.status);
+ err.status = http.status;
+ err.responseText = http.responseText;
+ throw err;
+ }
+ }catch(e){
+ if(fail_ok){ return null; } // null
+ // rethrow the exception
+ throw e;
+ }
+ return http.responseText; // String
+ }
+ })();
+
+ dojo._initFired = false;
+ // BEGIN DOMContentLoaded, from Dean Edwards (http://dean.edwards.name/weblog/2006/06/again/)
+ dojo._loadInit = function(e){
+ dojo._initFired = true;
+ // allow multiple calls, only first one will take effect
+ // A bug in khtml calls events callbacks for document for event which isnt supported
+ // for example a created contextmenu event calls DOMContentLoaded, workaround
+ var type = (e && e.type) ? e.type.toLowerCase() : "load";
+ if(arguments.callee.initialized || (type != "domcontentloaded" && type != "load")){ return; }
+ arguments.callee.initialized = true;
+ if("_khtmlTimer" in dojo){
+ clearInterval(dojo._khtmlTimer);
+ delete dojo._khtmlTimer;
+ }
+
+ if(dojo._inFlightCount == 0){
+ dojo._modulesLoaded();
+ }
+ }
+
+ dojo._fakeLoadInit = function(){
+ dojo._loadInit({type: "load"});
+ }
+
+ if(!dojo.config.afterOnLoad){
+ // START DOMContentLoaded
+ // Mozilla and Opera 9 expose the event we could use
+ if(document.addEventListener){
+ // NOTE:
+ // due to a threading issue in Firefox 2.0, we can't enable
+ // DOMContentLoaded on that platform. For more information, see:
+ // http://trac.dojotoolkit.org/ticket/1704
+ if(dojo.isOpera || dojo.isFF >= 3 || (dojo.isMoz && dojo.config.enableMozDomContentLoaded === true)){
+ document.addEventListener("DOMContentLoaded", dojo._loadInit, null);
+ }
+
+ // mainly for Opera 8.5, won't be fired if DOMContentLoaded fired already.
+ // also used for Mozilla because of trac #1640
+ window.addEventListener("load", dojo._loadInit, null);
+ }
+
+ if(dojo.isAIR){
+ window.addEventListener("load", dojo._loadInit, null);
+ }else if(/(WebKit|khtml)/i.test(navigator.userAgent)){ // sniff
+ dojo._khtmlTimer = setInterval(function(){
+ if(/loaded|complete/.test(document.readyState)){
+ dojo._loadInit(); // call the onload handler
+ }
+ }, 10);
+ }
+ // END DOMContentLoaded
+ }
+
+ (function(){
+ var _w = window;
+ var _handleNodeEvent = function(/*String*/evtName, /*Function*/fp){
+ // summary:
+ // non-destructively adds the specified function to the node's
+ // evtName handler.
+ // evtName: should be in the form "onclick" for "onclick" handlers.
+ // Make sure you pass in the "on" part.
+ var oldHandler = _w[evtName] || function(){};
+ _w[evtName] = function(){
+ fp.apply(_w, arguments);
+ oldHandler.apply(_w, arguments);
+ };
+ };
+
+ if(dojo.isIE){
+ // for Internet Explorer. readyState will not be achieved on init
+ // call, but dojo doesn't need it however, we'll include it
+ // because we don't know if there are other functions added that
+ // might. Note that this has changed because the build process
+ // strips all comments -- including conditional ones.
+ if(!dojo.config.afterOnLoad){
+ document.write('<scr'+'ipt defer src="//:" '
+ + 'onreadystatechange="if(this.readyState==\'complete\'){' + dojo._scopeName + '._loadInit();}">'
+ + '</scr'+'ipt>'
+ );
+ }
+
+ // IE WebControl hosted in an application can fire "beforeunload" and "unload"
+ // events when control visibility changes, causing Dojo to unload too soon. The
+ // following code fixes the problem
+ // Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;199155
+ var _unloading = true;
+ _handleNodeEvent("onbeforeunload", function(){
+ _w.setTimeout(function(){ _unloading = false; }, 0);
+ });
+ _handleNodeEvent("onunload", function(){
+ if(_unloading){ dojo.unloaded(); }
+ });
+
+ try{
+ document.namespaces.add("v","urn:schemas-microsoft-com:vml");
+ document.createStyleSheet().addRule("v\\:*", "behavior:url(#default#VML)");
+ }catch(e){}
+ }else{
+ // FIXME: dojo.unloaded requires dojo scope, so using anon function wrapper.
+ _handleNodeEvent("onbeforeunload", function() { dojo.unloaded(); });
+ }
+
+ })();
+
+ /*
+ OpenAjax.subscribe("OpenAjax", "onload", function(){
+ if(dojo._inFlightCount == 0){
+ dojo._modulesLoaded();
+ }
+ });
+
+ OpenAjax.subscribe("OpenAjax", "onunload", function(){
+ dojo.unloaded();
+ });
+ */
+} //if (typeof window != 'undefined')
+
+//Register any module paths set up in djConfig. Need to do this
+//in the hostenvs since hostenv_browser can read djConfig from a
+//script tag's attribute.
+(function(){
+ var mp = dojo.config["modulePaths"];
+ if(mp){
+ for(var param in mp){
+ dojo.registerModulePath(param, mp[param]);
+ }
+ }
+})();
+
+//Load debug code if necessary.
+if(dojo.config.isDebug){
+ dojo.require("dojo._firebug.firebug");
+}
+
+if(dojo.config.debugAtAllCosts){
+ dojo.config.useXDomain = true;
+ dojo.require("dojo._base._loader.loader_xd");
+ dojo.require("dojo._base._loader.loader_debug");
+ dojo.require("dojo.i18n");
+}
+
+if(!dojo._hasResource["dojo._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.lang"] = true;
+dojo.provide("dojo._base.lang");
+
+// Crockford (ish) functions
+
+dojo.isString = function(/*anything*/ it){
+ // summary:
+ // Return true if it is a String
+ return !!arguments.length && it != null && (typeof it == "string" || it instanceof String); // Boolean
+}
+
+dojo.isArray = function(/*anything*/ it){
+ // summary:
+ // Return true if it is an Array
+ return it && (it instanceof Array || typeof it == "array"); // Boolean
+}
+
+/*=====
+dojo.isFunction = function(it){
+ // summary: Return true if it is a Function
+ // it: anything
+ // return: Boolean
+}
+=====*/
+
+dojo.isFunction = (function(){
+ var _isFunction = function(/*anything*/ it){
+ return it && (typeof it == "function" || it instanceof Function); // Boolean
+ };
+
+ return dojo.isSafari ?
+ // only slow this down w/ gratuitious casting in Safari since it's what's b0rken
+ function(/*anything*/ it){
+ if(typeof it == "function" && it == "[object NodeList]"){ return false; }
+ return _isFunction(it); // Boolean
+ } : _isFunction;
+})();
+
+dojo.isObject = function(/*anything*/ it){
+ // summary:
+ // Returns true if it is a JavaScript object (or an Array, a Function
+ // or null)
+ return it !== undefined &&
+ (it === null || typeof it == "object" || dojo.isArray(it) || dojo.isFunction(it)); // Boolean
+}
+
+dojo.isArrayLike = function(/*anything*/ it){
+ // summary:
+ // similar to dojo.isArray() but more permissive
+ // description:
+ // Doesn't strongly test for "arrayness". Instead, settles for "isn't
+ // a string or number and has a length property". Arguments objects
+ // and DOM collections will return true when passed to
+ // dojo.isArrayLike(), but will return false when passed to
+ // dojo.isArray().
+ // return:
+ // If it walks like a duck and quicks like a duck, return `true`
+ var d = dojo;
+ return it && it !== undefined &&
+ // keep out built-in constructors (Number, String, ...) which have length
+ // properties
+ !d.isString(it) && !d.isFunction(it) &&
+ !(it.tagName && it.tagName.toLowerCase() == 'form') &&
+ (d.isArray(it) || isFinite(it.length)); // Boolean
+}
+
+dojo.isAlien = function(/*anything*/ it){
+ // summary:
+ // Returns true if it is a built-in function or some other kind of
+ // oddball that *should* report as a function but doesn't
+ return it && !dojo.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
+}
+
+dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
+ // summary:
+ // Adds all properties and methods of props to constructor's
+ // prototype, making them available to all instances created with
+ // constructor.
+ for(var i=1, l=arguments.length; i<l; i++){
+ dojo._mixin(constructor.prototype, arguments[i]);
+ }
+ return constructor; // Object
+}
+
+dojo._hitchArgs = function(scope, method /*,...*/){
+ var pre = dojo._toArray(arguments, 2);
+ var named = dojo.isString(method);
+ return function(){
+ // arrayify arguments
+ var args = dojo._toArray(arguments);
+ // locate our method
+ var f = named ? (scope||dojo.global)[method] : method;
+ // invoke with collected args
+ return f && f.apply(scope || this, pre.concat(args)); // mixed
+ } // Function
+}
+
+dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){
+ // summary:
+ // Returns a function that will only ever execute in the a given scope.
+ // This allows for easy use of object member functions
+ // in callbacks and other places in which the "this" keyword may
+ // otherwise not reference the expected scope.
+ // Any number of default positional arguments may be passed as parameters
+ // beyond "method".
+ // Each of these values will be used to "placehold" (similar to curry)
+ // for the hitched function.
+ // scope:
+ // The scope to use when method executes. If method is a string,
+ // scope is also the object containing method.
+ // method:
+ // A function to be hitched to scope, or the name of the method in
+ // scope to be hitched.
+ // example:
+ // | dojo.hitch(foo, "bar")();
+ // runs foo.bar() in the scope of foo
+ // example:
+ // | dojo.hitch(foo, myFunction);
+ // returns a function that runs myFunction in the scope of foo
+ if(arguments.length > 2){
+ return dojo._hitchArgs.apply(dojo, arguments); // Function
+ }
+ if(!method){
+ method = scope;
+ scope = null;
+ }
+ if(dojo.isString(method)){
+ scope = scope || dojo.global;
+ if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
+ return function(){ return scope[method].apply(scope, arguments || []); }; // Function
+ }
+ return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function
+}
+
+/*=====
+dojo.delegate = function(obj, props){
+ // summary:
+ // returns a new object which "looks" to obj for properties which it
+ // does not have a value for. Optionally takes a bag of properties to
+ // seed the returned object with initially.
+ // description:
+ // This is a small implementaton of the Boodman/Crockford delegation
+ // pattern in JavaScript. An intermediate object constructor mediates
+ // the prototype chain for the returned object, using it to delegate
+ // down to obj for property lookup when object-local lookup fails.
+ // This can be thought of similarly to ES4's "wrap", save that it does
+ // not act on types but rather on pure objects.
+ // obj:
+ // The object to delegate to for properties not found directly on the
+ // return object or in props.
+ // props:
+ // an object containing properties to assign to the returned object
+ // returns:
+ // an Object of anonymous type
+ // example:
+ // | var foo = { bar: "baz" };
+ // | var thinger = dojo.delegate(foo, { thud: "xyzzy"});
+ // | thinger.bar == "baz"; // delegated to foo
+ // | foo.thud == undefined; // by definition
+ // | thinger.thud == "xyzzy"; // mixed in from props
+ // | foo.bar = "thonk";
+ // | thinger.bar == "thonk"; // still delegated to foo's bar
+}
+=====*/
+
+
+dojo.delegate = dojo._delegate = function(obj, props){
+
+ // boodman/crockford delegation
+ function TMP(){};
+ TMP.prototype = obj;
+ var tmp = new TMP();
+ if(props){
+ dojo.mixin(tmp, props);
+ }
+ return tmp; // Object
+}
+
+dojo.partial = function(/*Function|String*/method /*, ...*/){
+ // summary:
+ // similar to hitch() except that the scope object is left to be
+ // whatever the execution context eventually becomes.
+ // description:
+ // Calling dojo.partial is the functional equivalent of calling:
+ // | dojo.hitch(null, funcName, ...);
+ var arr = [ null ];
+ return dojo.hitch.apply(dojo, arr.concat(dojo._toArray(arguments))); // Function
+}
+
+dojo._toArray = function(/*Object*/obj, /*Number?*/offset, /*Array?*/ startWith){
+ // summary:
+ // Converts an array-like object (i.e. arguments, DOMCollection) to an
+ // array. Returns a new Array with the elements of obj.
+ // obj:
+ // the object to "arrayify". We expect the object to have, at a
+ // minimum, a length property which corresponds to integer-indexed
+ // properties.
+ // offset:
+ // the location in obj to start iterating from. Defaults to 0.
+ // Optional.
+ // startWith:
+ // An array to pack with the properties of obj. If provided,
+ // properties in obj are appended at the end of startWith and
+ // startWith is the returned array.
+ var arr = startWith||[];
+ for(var x = offset || 0; x < obj.length; x++){
+ arr.push(obj[x]);
+ }
+ return arr; // Array
+}
+
+dojo.clone = function(/*anything*/ o){
+ // summary:
+ // Clones objects (including DOM nodes) and all children.
+ // Warning: do not clone cyclic structures.
+ if(!o){ return o; }
+ if(dojo.isArray(o)){
+ var r = [];
+ for(var i = 0; i < o.length; ++i){
+ r.push(dojo.clone(o[i]));
+ }
+ return r; // Array
+ }
+ if(!dojo.isObject(o)){
+ return o; /*anything*/
+ }
+ if(o.nodeType && o.cloneNode){ // isNode
+ return o.cloneNode(true); // Node
+ }
+ if(o instanceof Date){
+ return new Date(o.getTime()); // Date
+ }
+ // Generic objects
+ var r = new o.constructor(); // specific to dojo.declare()'d classes!
+ for(var i in o){
+ if(!(i in r) || r[i] != o[i]){
+ r[i] = dojo.clone(o[i]);
+ }
+ }
+ return r; // Object
+}
+
+dojo.trim = function(/*String*/ str){
+ // summary:
+ // trims whitespaces from both sides of the string
+ // description:
+ // This version of trim() was selected for inclusion into the base due
+ // to its compact size and relatively good performance (see Steven
+ // Levithan's blog:
+ // http://blog.stevenlevithan.com/archives/faster-trim-javascript).
+ // The fastest but longest version of this function is located at
+ // dojo.string.trim()
+ return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // String
+}
+
+}
+
+if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.declare"] = true;
+dojo.provide("dojo._base.declare");
+
+
+// this file courtesy of the TurboAjax group, licensed under a Dojo CLA
+
+dojo.declare = function(/*String*/ className, /*Function|Function[]*/ superclass, /*Object*/ props){
+ // summary:
+ // Create a feature-rich constructor from compact notation
+ // className:
+ // The name of the constructor (loosely, a "class")
+ // stored in the "declaredClass" property in the created prototype
+ // superclass:
+ // May be null, a Function, or an Array of Functions. If an array,
+ // the first element is used as the prototypical ancestor and
+ // any following Functions become mixin ancestors.
+ // props:
+ // An object whose properties are copied to the
+ // created prototype.
+ // Add an instance-initialization function by making it a property
+ // named "constructor".
+ // description:
+ // Create a constructor using a compact notation for inheritance and
+ // prototype extension.
+ //
+ // All superclasses (including mixins) must be Functions (not simple Objects).
+ //
+ // Mixin ancestors provide a type of multiple inheritance. Prototypes of mixin
+ // ancestors are copied to the new class: changes to mixin prototypes will
+ // not affect classes to which they have been mixed in.
+ //
+ // "className" is cached in "declaredClass" property of the new class.
+ //
+ // example:
+ // | dojo.declare("my.classes.bar", my.classes.foo, {
+ // | // properties to be added to the class prototype
+ // | someValue: 2,
+ // | // initialization function
+ // | constructor: function(){
+ // | this.myComplicatedObject = new ReallyComplicatedObject();
+ // | },
+ // | // other functions
+ // | someMethod: function(){
+ // | doStuff();
+ // | }
+ // | );
+
+ // process superclass argument
+ // var dd=dojo.declare, mixins=null;
+ var dd = arguments.callee, mixins;
+ if(dojo.isArray(superclass)){
+ mixins = superclass;
+ superclass = mixins.shift();
+ }
+ // construct intermediate classes for mixins
+ if(mixins){
+ dojo.forEach(mixins, function(m){
+ if(!m){ throw(className + ": mixin #" + i + " is null"); } // It's likely a required module is not loaded
+ superclass = dd._delegate(superclass, m);
+ });
+ }
+ // prepare values
+ var init = (props||0).constructor, ctor = dd._delegate(superclass), fn;
+ // name methods (experimental)
+ for(var i in props){ if(dojo.isFunction(fn = props[i]) && !0[i]){fn.nom = i;} } // 0[i] checks Object.prototype
+ // decorate prototype
+ dojo.extend(ctor, {declaredClass: className, _constructor: init, preamble: null}, props || 0);
+ // special help for IE
+ ctor.prototype.constructor = ctor;
+ // create named reference
+ return dojo.setObject(className, ctor); // Function
+};
+
+dojo.mixin(dojo.declare, {
+ _delegate: function(base, mixin){
+ var bp = (base||0).prototype, mp = (mixin||0).prototype;
+ // fresh constructor, fresh prototype
+ var ctor = dojo.declare._makeCtor();
+ // cache ancestry
+ dojo.mixin(ctor, {superclass: bp, mixin: mp, extend: dojo.declare._extend});
+ // chain prototypes
+ if(base){ctor.prototype = dojo._delegate(bp);}
+ // add mixin and core
+ dojo.extend(ctor, dojo.declare._core, mp||0, {_constructor: null, preamble: null});
+ // special help for IE
+ ctor.prototype.constructor = ctor;
+ // name this class for debugging
+ ctor.prototype.declaredClass = (bp||0).declaredClass + '_' + (mp||0).declaredClass;
+ return ctor;
+ },
+ _extend: function(props){
+ for(var i in props){ if(dojo.isFunction(fn=props[i]) && !0[i]){fn.nom=i;} }
+ dojo.extend(this, props);
+ },
+ _makeCtor: function(){
+ // we have to make a function, but don't want to close over anything
+ return function(){ this._construct(arguments); };
+ },
+ _core: {
+ _construct: function(args){
+ var c=args.callee, s=c.superclass, ct=s&&s.constructor, m=c.mixin, mct=m&&m.constructor, a=args, ii, fn;
+ // side-effect of = used on purpose here, lint may complain, don't try this at home
+ if(a[0]){
+ // FIXME: preambles for each mixin should be allowed
+ // FIXME:
+ // should we allow the preamble here NOT to modify the
+ // default args, but instead to act on each mixin
+ // independently of the class instance being constructed
+ // (for impedence matching)?
+
+ // allow any first argument w/ a "preamble" property to act as a
+ // class preamble (not exclusive of the prototype preamble)
+ if(/*dojo.isFunction*/((fn = a[0].preamble))){
+ a = fn.apply(this, a) || a;
+ }
+ }
+ // prototype preamble
+ if((fn = c.prototype.preamble)){a = fn.apply(this, a) || a;}
+ // FIXME:
+ // need to provide an optional prototype-settable
+ // "_explicitSuper" property which disables this
+ // initialize superclass
+ if(ct&&ct.apply){ct.apply(this, a);}
+ // initialize mixin
+ if(mct&&mct.apply){mct.apply(this, a);}
+ // initialize self
+ if((ii=c.prototype._constructor)){ii.apply(this, args);}
+ // post construction
+ if(this.constructor.prototype==c.prototype && (ct=this.postscript)){ ct.apply(this, args); }
+ },
+ _findMixin: function(mixin){
+ var c = this.constructor, p, m;
+ while(c){
+ p = c.superclass;
+ m = c.mixin;
+ if(m==mixin || (m instanceof mixin.constructor)){return p;}
+ if(m && (m=m._findMixin(mixin))){return m;}
+ c = p && p.constructor;
+ }
+ },
+ _findMethod: function(name, method, ptype, has){
+ // consciously trading readability for bytes and speed in this low-level method
+ var p=ptype, c, m, f;
+ do{
+ c = p.constructor;
+ m = c.mixin;
+ // find method by name in our mixin ancestor
+ if(m && (m=this._findMethod(name, method, m, has))){return m;}
+ // if we found a named method that either exactly-is or exactly-is-not 'method'
+ if((f=p[name])&&(has==(f==method))){return p;}
+ // ascend chain
+ p = c.superclass;
+ }while(p);
+ // if we couldn't find an ancestor in our primary chain, try a mixin chain
+ return !has && (p=this._findMixin(ptype)) && this._findMethod(name, method, p, has);
+ },
+ inherited: function(name, args, newArgs){
+ // optionalize name argument (experimental)
+ var a = arguments;
+ if(!dojo.isString(a[0])){newArgs=args; args=name; name=args.callee.nom;}
+ a = newArgs||args;
+ var c = args.callee, p = this.constructor.prototype, fn, mp;
+ // if not an instance override
+ if(this[name] != c || p[name] == c){
+ mp = this._findMethod(name, c, p, true);
+ if(!mp){throw(this.declaredClass + ': inherited method "' + name + '" mismatch');}
+ p = this._findMethod(name, c, mp, false);
+ }
+ fn = p && p[name];
+ if(!fn){throw(mp.declaredClass + ': inherited method "' + name + '" not found');}
+ // if the function exists, invoke it in our scope
+ return fn.apply(this, a);
+ }
+ }
+});
+
+}
+
+if(!dojo._hasResource["dojo._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.connect"] = true;
+dojo.provide("dojo._base.connect");
+
+
+// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
+
+// low-level delegation machinery
+dojo._listener = {
+ // create a dispatcher function
+ getDispatcher: function(){
+ // following comments pulled out-of-line to prevent cloning them
+ // in the returned function.
+ // - indices (i) that are really in the array of listeners (ls) will
+ // not be in Array.prototype. This is the 'sparse array' trick
+ // that keeps us safe from libs that take liberties with built-in
+ // objects
+ // - listener is invoked with current scope (this)
+ return function(){
+ var ap=Array.prototype, c=arguments.callee, ls=c._listeners, t=c.target;
+ // return value comes from original target function
+ var r=t && t.apply(this, arguments);
+ // invoke listeners after target function
+ for(var i in ls){
+ if(!(i in ap)){
+ ls[i].apply(this, arguments);
+ }
+ }
+ // return value comes from original target function
+ return r;
+ }
+ },
+ // add a listener to an object
+ add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
+ // Whenever 'method' is invoked, 'listener' will have the same scope.
+ // Trying to supporting a context object for the listener led to
+ // complexity.
+ // Non trivial to provide 'once' functionality here
+ // because listener could be the result of a dojo.hitch call,
+ // in which case two references to the same hitch target would not
+ // be equivalent.
+ source = source || dojo.global;
+ // The source method is either null, a dispatcher, or some other function
+ var f = source[method];
+ // Ensure a dispatcher
+ if(!f||!f._listeners){
+ var d = dojo._listener.getDispatcher();
+ // original target function is special
+ d.target = f;
+ // dispatcher holds a list of listeners
+ d._listeners = [];
+ // redirect source to dispatcher
+ f = source[method] = d;
+ }
+ // The contract is that a handle is returned that can
+ // identify this listener for disconnect.
+ //
+ // The type of the handle is private. Here is it implemented as Integer.
+ // DOM event code has this same contract but handle is Function
+ // in non-IE browsers.
+ //
+ // We could have separate lists of before and after listeners.
+ return f._listeners.push(listener) ; /*Handle*/
+ },
+ // remove a listener from an object
+ remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
+ var f = (source||dojo.global)[method];
+ // remember that handle is the index+1 (0 is not a valid handle)
+ if(f && f._listeners && handle--){
+ delete f._listeners[handle];
+ }
+ }
+};
+
+// Multiple delegation for arbitrary methods.
+
+// This unit knows nothing about DOM,
+// but we include DOM aware
+// documentation and dontFix
+// argument here to help the autodocs.
+// Actual DOM aware code is in event.js.
+
+dojo.connect = function(/*Object|null*/ obj,
+ /*String*/ event,
+ /*Object|null*/ context,
+ /*String|Function*/ method,
+ /*Boolean*/ dontFix){
+ // summary:
+ // Create a link that calls one function when another executes.
+ //
+ // description:
+ // Connects method to event, so that after event fires, method
+ // does too. All connected functions are passed the same arguments as
+ // the event function was initially called with. You may connect as
+ // many methods to event as needed.
+ //
+ // event must be a string. If obj is null, dojo.global is used.
+ //
+ // null arguments may simply be omitted.
+ //
+ // obj[event] can resolve to a function or undefined (null).
+ // If obj[event] is null, it is assigned a function.
+ //
+ // The return value is a handle that is needed to
+ // remove this connection with dojo.disconnect.
+ //
+ // obj:
+ // The source object for the event function.
+ // Defaults to dojo.global if null.
+ // If obj is a DOM node, the connection is delegated
+ // to the DOM event manager (unless dontFix is true).
+ //
+ // event:
+ // String name of the event function in obj.
+ // I.e. identifies a property obj[event].
+ //
+ // context:
+ // The object that method will receive as "this".
+ //
+ // If context is null and method is a function, then method
+ // inherits the context of event.
+ //
+ // If method is a string then context must be the source
+ // object object for method (context[method]). If context is null,
+ // dojo.global is used.
+ //
+ // method:
+ // A function reference, or name of a function in context.
+ // The function identified by method fires after event does.
+ // method receives the same arguments as the event.
+ // See context argument comments for information on method's scope.
+ //
+ // dontFix:
+ // If obj is a DOM node, set dontFix to true to prevent delegation
+ // of this connection to the DOM event manager.
+ //
+ // example:
+ // When obj.onchange(), do ui.update():
+ // | dojo.connect(obj, "onchange", ui, "update");
+ // | dojo.connect(obj, "onchange", ui, ui.update); // same
+ //
+ // example:
+ // Using return value for disconnect:
+ // | var link = dojo.connect(obj, "onchange", ui, "update");
+ // | ...
+ // | dojo.disconnect(link);
+ //
+ // example:
+ // When onglobalevent executes, watcher.handler is invoked:
+ // | dojo.connect(null, "onglobalevent", watcher, "handler");
+ //
+ // example:
+ // When ob.onCustomEvent executes, customEventHandler is invoked:
+ // | dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
+ // | dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
+ //
+ // example:
+ // When ob.onCustomEvent executes, customEventHandler is invoked
+ // with the same scope (this):
+ // | dojo.connect(ob, "onCustomEvent", null, customEventHandler);
+ // | dojo.connect(ob, "onCustomEvent", customEventHandler); // same
+ //
+ // example:
+ // When globalEvent executes, globalHandler is invoked
+ // with the same scope (this):
+ // | dojo.connect(null, "globalEvent", null, globalHandler);
+ // | dojo.connect("globalEvent", globalHandler); // same
+
+ // normalize arguments
+ var a=arguments, args=[], i=0;
+ // if a[0] is a String, obj was ommited
+ args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]);
+ // if the arg-after-next is a String or Function, context was NOT omitted
+ var a1 = a[i+1];
+ args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]);
+ // absorb any additional arguments
+ for(var l=a.length; i<l; i++){ args.push(a[i]); }
+ // do the actual work
+ return dojo._connect.apply(this, args); /*Handle*/
+}
+
+// used by non-browser hostenvs. always overriden by event.js
+dojo._connect = function(obj, event, context, method){
+ var l=dojo._listener, h=l.add(obj, event, dojo.hitch(context, method));
+ return [obj, event, h, l]; // Handle
+}
+
+dojo.disconnect = function(/*Handle*/ handle){
+ // summary:
+ // Remove a link created by dojo.connect.
+ // description:
+ // Removes the connection between event and the method referenced by handle.
+ // handle:
+ // the return value of the dojo.connect call that created the connection.
+ if(handle && handle[0] !== undefined){
+ dojo._disconnect.apply(this, handle);
+ // let's not keep this reference
+ delete handle[0];
+ }
+}
+
+dojo._disconnect = function(obj, event, handle, listener){
+ listener.remove(obj, event, handle);
+}
+
+// topic publish/subscribe
+
+dojo._topics = {};
+
+dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method){
+ // summary:
+ // Attach a listener to a named topic. The listener function is invoked whenever the
+ // named topic is published (see: dojo.publish).
+ // Returns a handle which is needed to unsubscribe this listener.
+ // context:
+ // Scope in which method will be invoked, or null for default scope.
+ // method:
+ // The name of a function in context, or a function reference. This is the function that
+ // is invoked when topic is published.
+ // example:
+ // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
+ // | dojo.publish("alerts", [ "read this", "hello world" ]);
+
+ // support for 2 argument invocation (omitting context) depends on hitch
+ return [topic, dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method))]; /*Handle*/
+}
+
+dojo.unsubscribe = function(/*Handle*/ handle){
+ // summary:
+ // Remove a topic listener.
+ // handle:
+ // The handle returned from a call to subscribe.
+ // example:
+ // | var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
+ // | ...
+ // | dojo.unsubscribe(alerter);
+ if(handle){
+ dojo._listener.remove(dojo._topics, handle[0], handle[1]);
+ }
+}
+
+dojo.publish = function(/*String*/ topic, /*Array*/ args){
+ // summary:
+ // Invoke all listener method subscribed to topic.
+ // topic:
+ // The name of the topic to publish.
+ // args:
+ // An array of arguments. The arguments will be applied
+ // to each topic subscriber (as first class parameters, via apply).
+ // example:
+ // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
+ // | dojo.publish("alerts", [ "read this", "hello world" ]);
+
+ // Note that args is an array, which is more efficient vs variable length
+ // argument list. Ideally, var args would be implemented via Array
+ // throughout the APIs.
+ var f = dojo._topics[topic];
+ if(f){
+ f.apply(this, args||[]);
+ }
+}
+
+dojo.connectPublisher = function( /*String*/ topic,
+ /*Object|null*/ obj,
+ /*String*/ event){
+ // summary:
+ // Ensure that everytime obj.event() is called, a message is published
+ // on the topic. Returns a handle which can be passed to
+ // dojo.disconnect() to disable subsequent automatic publication on
+ // the topic.
+ // topic:
+ // The name of the topic to publish.
+ // obj:
+ // The source object for the event function. Defaults to dojo.global
+ // if null.
+ // event:
+ // The name of the event function in obj.
+ // I.e. identifies a property obj[event].
+ // example:
+ // | dojo.connectPublisher("/ajax/start", dojo, "xhrGet"};
+ var pf = function(){ dojo.publish(topic, arguments); }
+ return (event) ? dojo.connect(obj, event, pf) : dojo.connect(obj, pf); //Handle
+};
+
+}
+
+if(!dojo._hasResource["dojo._base.Deferred"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.Deferred"] = true;
+dojo.provide("dojo._base.Deferred");
+
+
+dojo.Deferred = function(/*Function?*/ canceller){
+ // summary:
+ // Encapsulates a sequence of callbacks in response to a value that
+ // may not yet be available. This is modeled after the Deferred class
+ // from Twisted <http://twistedmatrix.com>.
+ // description:
+ // JavaScript has no threads, and even if it did, threads are hard.
+ // Deferreds are a way of abstracting non-blocking events, such as the
+ // final response to an XMLHttpRequest. Deferreds create a promise to
+ // return a response a some point in the future and an easy way to
+ // register your interest in receiving that response.
+ //
+ // The most important methods for Deffered users are:
+ //
+ // * addCallback(handler)
+ // * addErrback(handler)
+ // * callback(result)
+ // * errback(result)
+ //
+ // In general, when a function returns a Deferred, users then "fill
+ // in" the second half of the contract by registering callbacks and
+ // error handlers. You may register as many callback and errback
+ // handlers as you like and they will be executed in the order
+ // registered when a result is provided. Usually this result is
+ // provided as the result of an asynchronous operation. The code
+ // "managing" the Deferred (the code that made the promise to provide
+ // an answer later) will use the callback() and errback() methods to
+ // communicate with registered listeners about the result of the
+ // operation. At this time, all registered result handlers are called
+ // *with the most recent result value*.
+ //
+ // Deferred callback handlers are treated as a chain, and each item in
+ // the chain is required to return a value that will be fed into
+ // successive handlers. The most minimal callback may be registered
+ // like this:
+ //
+ // | var d = new dojo.Deferred();
+ // | d.addCallback(function(result){ return result; });
+ //
+ // Perhaps the most common mistake when first using Deferreds is to
+ // forget to return a value (in most cases, the value you were
+ // passed).
+ //
+ // The sequence of callbacks is internally represented as a list of
+ // 2-tuples containing the callback/errback pair. For example, the
+ // following call sequence:
+ //
+ // | var d = new dojo.Deferred();
+ // | d.addCallback(myCallback);
+ // | d.addErrback(myErrback);
+ // | d.addBoth(myBoth);
+ // | d.addCallbacks(myCallback, myErrback);
+ //
+ // is translated into a Deferred with the following internal
+ // representation:
+ //
+ // | [
+ // | [myCallback, null],
+ // | [null, myErrback],
+ // | [myBoth, myBoth],
+ // | [myCallback, myErrback]
+ // | ]
+ //
+ // The Deferred also keeps track of its current status (fired). Its
+ // status may be one of three things:
+ //
+ // * -1: no value yet (initial condition)
+ // * 0: success
+ // * 1: error
+ //
+ // A Deferred will be in the error state if one of the following three
+ // conditions are met:
+ //
+ // 1. The result given to callback or errback is "instanceof" Error
+ // 2. The previous callback or errback raised an exception while
+ // executing
+ // 3. The previous callback or errback returned a value
+ // "instanceof" Error
+ //
+ // Otherwise, the Deferred will be in the success state. The state of
+ // the Deferred determines the next element in the callback sequence
+ // to run.
+ //
+ // When a callback or errback occurs with the example deferred chain,
+ // something equivalent to the following will happen (imagine
+ // that exceptions are caught and returned):
+ //
+ // | // d.callback(result) or d.errback(result)
+ // | if(!(result instanceof Error)){
+ // | result = myCallback(result);
+ // | }
+ // | if(result instanceof Error){
+ // | result = myErrback(result);
+ // | }
+ // | result = myBoth(result);
+ // | if(result instanceof Error){
+ // | result = myErrback(result);
+ // | }else{
+ // | result = myCallback(result);
+ // | }
+ //
+ // The result is then stored away in case another step is added to the
+ // callback sequence. Since the Deferred already has a value
+ // available, any new callbacks added will be called immediately.
+ //
+ // There are two other "advanced" details about this implementation
+ // that are useful:
+ //
+ // Callbacks are allowed to return Deferred instances themselves, so
+ // you can build complicated sequences of events with ease.
+ //
+ // The creator of the Deferred may specify a canceller. The canceller
+ // is a function that will be called if Deferred.cancel is called
+ // before the Deferred fires. You can use this to implement clean
+ // aborting of an XMLHttpRequest, etc. Note that cancel will fire the
+ // deferred with a CancelledError (unless your canceller returns
+ // another kind of error), so the errbacks should be prepared to
+ // handle that error for cancellable Deferreds.
+ // example:
+ // | var deferred = new dojo.Deferred();
+ // | setTimeout(function(){ deferred.callback({success: true}); }, 1000);
+ // | return deferred;
+ // example:
+ // Deferred objects are often used when making code asynchronous. It
+ // may be easiest to write functions in a synchronous manner and then
+ // split code using a deferred to trigger a response to a long-lived
+ // operation. For example, instead of register a callback function to
+ // denote when a rendering operation completes, the function can
+ // simply return a deferred:
+ //
+ // | // callback style:
+ // | function renderLotsOfData(data, callback){
+ // | var success = false
+ // | try{
+ // | for(var x in data){
+ // | renderDataitem(data[x]);
+ // | }
+ // | success = true;
+ // | }catch(e){ }
+ // | if(callback){
+ // | callback(success);
+ // | }
+ // | }
+ //
+ // | // using callback style
+ // | renderLotsOfData(someDataObj, function(success){
+ // | // handles success or failure
+ // | if(!success){
+ // | promptUserToRecover();
+ // | }
+ // | });
+ // | // NOTE: no way to add another callback here!!
+ // example:
+ // Using a Deferred doesn't simplify the sending code any, but it
+ // provides a standard interface for callers and senders alike,
+ // providing both with a simple way to service multiple callbacks for
+ // an operation and freeing both sides from worrying about details
+ // such as "did this get called already?". With Deferreds, new
+ // callbacks can be added at any time.
+ //
+ // | // Deferred style:
+ // | function renderLotsOfData(data){
+ // | var d = new dojo.Deferred();
+ // | try{
+ // | for(var x in data){
+ // | renderDataitem(data[x]);
+ // | }
+ // | d.callback(true);
+ // | }catch(e){
+ // | d.errback(new Error("rendering failed"));
+ // | }
+ // | return d;
+ // | }
+ //
+ // | // using Deferred style
+ // | renderLotsOfData(someDataObj).addErrback(function(){
+ // | promptUserToRecover();
+ // | });
+ // | // NOTE: addErrback and addCallback both return the Deferred
+ // | // again, so we could chain adding callbacks or save the
+ // | // deferred for later should we need to be notified again.
+ // example:
+ // In this example, renderLotsOfData is syncrhonous and so both
+ // versions are pretty artificial. Putting the data display on a
+ // timeout helps show why Deferreds rock:
+ //
+ // | // Deferred style and async func
+ // | function renderLotsOfData(data){
+ // | var d = new dojo.Deferred();
+ // | setTimeout(function(){
+ // | try{
+ // | for(var x in data){
+ // | renderDataitem(data[x]);
+ // | }
+ // | d.callback(true);
+ // | }catch(e){
+ // | d.errback(new Error("rendering failed"));
+ // | }
+ // | }, 100);
+ // | return d;
+ // | }
+ //
+ // | // using Deferred style
+ // | renderLotsOfData(someDataObj).addErrback(function(){
+ // | promptUserToRecover();
+ // | });
+ //
+ // Note that the caller doesn't have to change his code at all to
+ // handle the asynchronous case.
+
+ this.chain = [];
+ this.id = this._nextId();
+ this.fired = -1;
+ this.paused = 0;
+ this.results = [null, null];
+ this.canceller = canceller;
+ this.silentlyCancelled = false;
+};
+
+dojo.extend(dojo.Deferred, {
+ /*
+ makeCalled: function(){
+ // summary:
+ // returns a new, empty deferred, which is already in the called
+ // state. Calling callback() or errback() on this deferred will
+ // yeild an error and adding new handlers to it will result in
+ // them being called immediately.
+ var deferred = new dojo.Deferred();
+ deferred.callback();
+ return deferred;
+ },
+
+ toString: function(){
+ var state;
+ if(this.fired == -1){
+ state = 'unfired';
+ }else{
+ state = this.fired ? 'success' : 'error';
+ }
+ return 'Deferred(' + this.id + ', ' + state + ')';
+ },
+ */
+
+ _nextId: (function(){
+ var n = 1;
+ return function(){ return n++; };
+ })(),
+
+ cancel: function(){
+ // summary:
+ // Cancels a Deferred that has not yet received a value, or is
+ // waiting on another Deferred as its value.
+ // description:
+ // If a canceller is defined, the canceller is called. If the
+ // canceller did not return an error, or there was no canceller,
+ // then the errback chain is started.
+ var err;
+ if(this.fired == -1){
+ if(this.canceller){
+ err = this.canceller(this);
+ }else{
+ this.silentlyCancelled = true;
+ }
+ if(this.fired == -1){
+ if(!(err instanceof Error)){
+ var res = err;
+ err = new Error("Deferred Cancelled");
+ err.dojoType = "cancel";
+ err.cancelResult = res;
+ }
+ this.errback(err);
+ }
+ }else if( (this.fired == 0) &&
+ (this.results[0] instanceof dojo.Deferred)
+ ){
+ this.results[0].cancel();
+ }
+ },
+
+
+ _resback: function(res){
+ // summary:
+ // The private primitive that means either callback or errback
+ this.fired = ((res instanceof Error) ? 1 : 0);
+ this.results[this.fired] = res;
+ this._fire();
+ },
+
+ _check: function(){
+ if(this.fired != -1){
+ if(!this.silentlyCancelled){
+ throw new Error("already called!");
+ }
+ this.silentlyCancelled = false;
+ return;
+ }
+ },
+
+ callback: function(res){
+ // summary:
+ // Begin the callback sequence with a non-error value.
+
+ /*
+ callback or errback should only be called once on a given
+ Deferred.
+ */
+ this._check();
+ this._resback(res);
+ },
+
+ errback: function(/*Error*/res){
+ // summary:
+ // Begin the callback sequence with an error result.
+ this._check();
+ if(!(res instanceof Error)){
+ res = new Error(res);
+ }
+ this._resback(res);
+ },
+
+ addBoth: function(/*Function|Object*/cb, /*String?*/cbfn){
+ // summary:
+ // Add the same function as both a callback and an errback as the
+ // next element on the callback sequence.This is useful for code
+ // that you want to guarantee to run, e.g. a finalizer.
+ var enclosed = dojo.hitch.apply(dojo, arguments);
+ return this.addCallbacks(enclosed, enclosed);
+ },
+
+ addCallback: function(/*Function|Object*/cb, /*String?*/cbfn /*...*/){
+ // summary:
+ // Add a single callback to the end of the callback sequence.
+ return this.addCallbacks(dojo.hitch.apply(dojo, arguments));
+ },
+
+ addErrback: function(cb, cbfn){
+ // summary:
+ // Add a single callback to the end of the callback sequence.
+ return this.addCallbacks(null, dojo.hitch.apply(dojo, arguments));
+ },
+
+ addCallbacks: function(cb, eb){
+ // summary:
+ // Add separate callback and errback to the end of the callback
+ // sequence.
+ this.chain.push([cb, eb])
+ if(this.fired >= 0){
+ this._fire();
+ }
+ return this;
+ },
+
+ _fire: function(){
+ // summary:
+ // Used internally to exhaust the callback sequence when a result
+ // is available.
+ var chain = this.chain;
+ var fired = this.fired;
+ var res = this.results[fired];
+ var self = this;
+ var cb = null;
+ while(
+ (chain.length > 0) &&
+ (this.paused == 0)
+ ){
+ // Array
+ var f = chain.shift()[fired];
+ if(!f){ continue; }
+ try{
+ res = f(res);
+ fired = ((res instanceof Error) ? 1 : 0);
+ if(res instanceof dojo.Deferred){
+ cb = function(res){
+ self._resback(res);
+ // inlined from _pause()
+ self.paused--;
+ if(
+ (self.paused == 0) &&
+ (self.fired >= 0)
+ ){
+ self._fire();
+ }
+ }
+ // inlined from _unpause
+ this.paused++;
+ }
+ }catch(err){
+ console.debug(err);
+ fired = 1;
+ res = err;
+ }
+ }
+ this.fired = fired;
+ this.results[fired] = res;
+ if((cb)&&(this.paused)){
+ // this is for "tail recursion" in case the dependent
+ // deferred is already fired
+ res.addBoth(cb);
+ }
+ }
+});
+
+}
+
+if(!dojo._hasResource["dojo._base.json"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.json"] = true;
+dojo.provide("dojo._base.json");
+
+dojo.fromJson = function(/*String*/ json){
+ // summary:
+ // Parses a [JSON](http://json.org) string to return a JavaScript object.
+ // json:
+ // a string literal of a JSON item, for instance:
+ // `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
+
+ return eval("(" + json + ")"); // Object
+}
+
+dojo._escapeString = function(/*String*/str){
+ //summary:
+ // Adds escape sequences for non-visual characters, double quote and
+ // backslash and surrounds with double quotes to form a valid string
+ // literal.
+ return ('"' + str.replace(/(["\\])/g, '\\$1') + '"').
+ replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n").
+ replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string
+}
+
+dojo.toJsonIndentStr = "\t";
+dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*String?*/ _indentStr){
+ // summary:
+ // Returns a [JSON](http://json.org) serialization of an object.
+ //
+ // description:
+ // Returns a [JSON](http://json.org) serialization of an object.
+ // Note that this doesn't check for infinite recursion, so don't do that!
+ //
+ // it:
+ // an object to be serialized. Objects may define their own
+ // serialization via a special "__json__" or "json" function
+ // property. If a specialized serializer has been defined, it will
+ // be used as a fallback.
+ //
+ // 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().
+ //
+ // _indentStr:
+ // private variable for recursive calls when pretty printing, do not use.
+
+ if(it === undefined){
+ return "undefined";
+ }
+ var objtype = typeof it;
+ if(objtype == "number" || objtype == "boolean"){
+ return it + "";
+ }
+ if(it === null){
+ return "null";
+ }
+ if(dojo.isString(it)){
+ return dojo._escapeString(it);
+ }
+ if(it.nodeType && it.cloneNode){ // isNode
+ return ""; // FIXME: would something like outerHTML be better here?
+ }
+ // recurse
+ var recurse = arguments.callee;
+ // short-circuit for objects that support "json" serialization
+ // if they return "self" then just pass-through...
+ var newObj;
+ _indentStr = _indentStr || "";
+ var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : "";
+ if(typeof it.__json__ == "function"){
+ newObj = it.__json__();
+ if(it !== newObj){
+ return recurse(newObj, prettyPrint, nextIndent);
+ }
+ }
+ if(typeof it.json == "function"){
+ newObj = it.json();
+ if(it !== newObj){
+ return recurse(newObj, prettyPrint, nextIndent);
+ }
+ }
+
+ var sep = prettyPrint ? " " : "";
+ var newLine = prettyPrint ? "\n" : "";
+
+ // array
+ if(dojo.isArray(it)){
+ var res = dojo.map(it, function(obj){
+ var val = recurse(obj, prettyPrint, nextIndent);
+ if(typeof val != "string"){
+ val = "undefined";
+ }
+ return newLine + nextIndent + val;
+ });
+ return "[" + res.join("," + sep) + newLine + _indentStr + "]";
+ }
+ /*
+ // look in the registry
+ try {
+ window.o = it;
+ newObj = dojo.json.jsonRegistry.match(it);
+ return recurse(newObj, prettyPrint, nextIndent);
+ }catch(e){
+ // console.debug(e);
+ }
+ // it's a function with no adapter, skip it
+ */
+ if(objtype == "function"){
+ return null; // null
+ }
+ // generic object code path
+ var output = [];
+ for(var key in it){
+ var keyStr;
+ if(typeof key == "number"){
+ keyStr = '"' + key + '"';
+ }else if(typeof key == "string"){
+ keyStr = dojo._escapeString(key);
+ }else{
+ // skip non-string or number keys
+ continue;
+ }
+ val = recurse(it[key], prettyPrint, nextIndent);
+ if(typeof val != "string"){
+ // skip non-serializable values
+ continue;
+ }
+ // FIXME: use += on Moz!!
+ // MOW NOTE: using += is a pain because you have to account for the dangling comma...
+ output.push(newLine + nextIndent + keyStr + ":" + sep + val);
+ }
+ return "{" + output.join("," + sep) + newLine + _indentStr + "}"; // String
+}
+
+}
+
+if(!dojo._hasResource["dojo._base.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.array"] = true;
+
+dojo.provide("dojo._base.array");
+
+(function(){
+ var _getParts = function(arr, obj, cb){
+ return [
+ dojo.isString(arr) ? arr.split("") : arr,
+ obj || dojo.global,
+ // FIXME: cache the anonymous functions we create here?
+ dojo.isString(cb) ? new Function("item", "index", "array", cb) : cb
+ ];
+ };
+
+ dojo.mixin(dojo, {
+ indexOf: function( /*Array*/ array,
+ /*Object*/ value,
+ /*Integer?*/ fromIndex,
+ /*Boolean?*/ findLast){
+ // summary:
+ // locates the first index of the provided value in the
+ // passed array. If the value is not found, -1 is returned.
+ // description:
+ // For details on this method, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
+
+ var step = 1, end = array.length || 0, i = 0;
+ if(findLast){
+ i = end - 1;
+ step = end = -1;
+ }
+ if(fromIndex != undefined){ i = fromIndex; }
+ if((findLast && i > end) || i < end){
+ for(; i != end; i += step){
+ if(array[i] == value){ return i; }
+ }
+ }
+ return -1; // Number
+ },
+
+ lastIndexOf: function(/*Array*/array, /*Object*/value, /*Integer?*/fromIndex){
+ // summary:
+ // locates the last index of the provided value in the passed array.
+ // If the value is not found, -1 is returned.
+ // description:
+ // For details on this method, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf>
+ return dojo.indexOf(array, value, fromIndex, true); // Number
+ },
+
+ forEach: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ // summary:
+ // for every item in arr, callback is invoked. Return values are ignored.
+ // arr: the array to iterate on. If a string, operates on individual characters.
+ // callback: a function is invoked with three arguments: item, index, and array
+ // thisObject: may be used to scope the call to callback
+ // description:
+ // This function corresponds to the JavaScript 1.6 Array.forEach() method.
+ // In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
+ // For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach>
+
+ // match the behavior of the built-in forEach WRT empty arrs
+ if(!arr || !arr.length){ return; }
+
+ // FIXME: there are several ways of handilng thisObject. Is
+ // dojo.global always the default context?
+ var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+ for(var i=0,l=_p[0].length; i<l; i++){
+ _p[2].call(_p[1], arr[i], i, arr);
+ }
+ },
+
+ _everyOrSome: function(/*Boolean*/every, /*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+ for(var i = 0, l = arr.length; i < l; i++){
+ var result = !!_p[2].call(_p[1], arr[i], i, arr);
+ if(every ^ result){
+ return result; // Boolean
+ }
+ }
+ return every; // Boolean
+ },
+
+ every: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ // summary:
+ // Determines whether or not every item in arr satisfies the
+ // condition implemented by callback.
+ // arr: the array to iterate on. If a string, operates on individual characters.
+ // callback: a function is invoked with three arguments: item, index, and array and returns true
+ // if the condition is met.
+ // thisObject: may be used to scope the call to callback
+ // description:
+ // This function corresponds to the JavaScript 1.6 Array.every() method.
+ // In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
+ // For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
+ // example:
+ // | dojo.every([1, 2, 3, 4], function(item){ return item>1; });
+ // returns false
+ // example:
+ // | dojo.every([1, 2, 3, 4], function(item){ return item>0; });
+ // returns true
+ return this._everyOrSome(true, arr, callback, thisObject); // Boolean
+ },
+
+ some: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ // summary:
+ // Determines whether or not any item in arr satisfies the
+ // condition implemented by callback.
+ // arr: the array to iterate on. If a string, operates on individual characters.
+ // callback: a function is invoked with three arguments: item, index, and array and returns true
+ // if the condition is met.
+ // thisObject: may be used to scope the call to callback
+ // description:
+ // This function corresponds to the JavaScript 1.6 Array.some() method.
+ // In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
+ // For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some>
+ // example:
+ // | dojo.some([1, 2, 3, 4], function(item){ return item>1; });
+ // returns true
+ // example:
+ // | dojo.some([1, 2, 3, 4], function(item){ return item<1; });
+ // returns false
+ return this._everyOrSome(false, arr, callback, thisObject); // Boolean
+ },
+
+ map: function(/*Array|String*/arr, /*Function|String*/callback, /*Function?*/thisObject){
+ // summary:
+ // applies callback to each element of arr and returns
+ // an Array with the results
+ // arr: the array to iterate on. If a string, operates on individual characters.
+ // callback: a function is invoked with three arguments: item, index, and array and returns a value
+ // thisObject: may be used to scope the call to callback
+ // description:
+ // This function corresponds to the JavaScript 1.6 Array.map() method.
+ // In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
+ // For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map>
+ // example:
+ // | dojo.map([1, 2, 3, 4], function(item){ return item+1 });
+ // returns [2, 3, 4, 5]
+ var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+ var outArr = (arguments[3] ? (new arguments[3]()) : []);
+ for(var i=0;i<arr.length;++i){
+ outArr.push(_p[2].call(_p[1], arr[i], i, arr));
+ }
+ return outArr; // Array
+ },
+
+ filter: function(/*Array*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ // summary:
+ // Returns a new Array with those items from arr that match the
+ // condition implemented by callback.
+ // arr: the array to iterate on. If a string, operates on individual characters.
+ // callback: a function is invoked with three arguments: item, index, and array and returns true
+ // if the condition is met.
+ // thisObject: may be used to scope the call to callback
+ // description:
+ // This function corresponds to the JavaScript 1.6 Array.filter() method.
+ // In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
+ // For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter>
+ // example:
+ // | dojo.filter([1, 2, 3, 4], function(item){ return item>1; });
+ // returns [2, 3, 4]
+
+ var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+ var outArr = [];
+ for(var i = 0; i < arr.length; i++){
+ if(_p[2].call(_p[1], arr[i], i, arr)){
+ outArr.push(arr[i]);
+ }
+ }
+ return outArr; // Array
+ }
+ });
+})();
+
+}
+
+if(!dojo._hasResource["dojo._base.Color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.Color"] = true;
+dojo.provide("dojo._base.Color");
+
+
+
+dojo.Color = function(/*Array|String|Object*/ color){
+ // summary:
+ // takes a named string, hex string, array of rgb or rgba values,
+ // an object with r, g, b, and a properties, or another dojo.Color object
+ if(color){ this.setColor(color); }
+};
+
+// FIXME: there's got to be a more space-efficient way to encode or discover these!! Use hex?
+dojo.Color.named = {
+ black: [0,0,0],
+ silver: [192,192,192],
+ gray: [128,128,128],
+ white: [255,255,255],
+ maroon: [128,0,0],
+ red: [255,0,0],
+ purple: [128,0,128],
+ fuchsia: [255,0,255],
+ green: [0,128,0],
+ lime: [0,255,0],
+ olive: [128,128,0],
+ yellow: [255,255,0],
+ navy: [0,0,128],
+ blue: [0,0,255],
+ teal: [0,128,128],
+ aqua: [0,255,255]
+};
+
+
+dojo.extend(dojo.Color, {
+ r: 255, g: 255, b: 255, a: 1,
+ _set: function(r, g, b, a){
+ var t = this; t.r = r; t.g = g; t.b = b; t.a = a;
+ },
+ setColor: function(/*Array|String|Object*/ color){
+ // summary:
+ // takes a named string, hex string, array of rgb or rgba values,
+ // an object with r, g, b, and a properties, or another dojo.Color object
+ var d = dojo;
+ if(d.isString(color)){
+ d.colorFromString(color, this);
+ }else if(d.isArray(color)){
+ d.colorFromArray(color, this);
+ }else{
+ this._set(color.r, color.g, color.b, color.a);
+ if(!(color instanceof d.Color)){ this.sanitize(); }
+ }
+ return this; // dojo.Color
+ },
+ sanitize: function(){
+ // summary:
+ // makes sure that the object has correct attributes
+ // description:
+ // the default implementation does nothing, include dojo.colors to
+ // augment it to real checks
+ return this; // dojo.Color
+ },
+ toRgb: function(){
+ // summary: returns 3 component array of rgb values
+ var t = this;
+ return [t.r, t.g, t.b]; // Array
+ },
+ toRgba: function(){
+ // summary: returns a 4 component array of rgba values
+ var t = this;
+ return [t.r, t.g, t.b, t.a]; // Array
+ },
+ toHex: function(){
+ // summary: returns a css color string in hexadecimal representation
+ var arr = dojo.map(["r", "g", "b"], function(x){
+ var s = this[x].toString(16);
+ return s.length < 2 ? "0" + s : s;
+ }, this);
+ return "#" + arr.join(""); // String
+ },
+ toCss: function(/*Boolean?*/ includeAlpha){
+ // summary: returns a css color string in rgb(a) representation
+ var t = this, rgb = t.r + ", " + t.g + ", " + t.b;
+ return (includeAlpha ? "rgba(" + rgb + ", " + t.a : "rgb(" + rgb) + ")"; // String
+ },
+ toString: function(){
+ // summary: returns a visual representation of the color
+ return this.toCss(true); // String
+ }
+});
+
+dojo.blendColors = function(
+ /*dojo.Color*/ start,
+ /*dojo.Color*/ end,
+ /*Number*/ weight,
+ /*dojo.Color?*/ obj
+){
+ // summary:
+ // blend colors end and start with weight from 0 to 1, 0.5 being a 50/50 blend,
+ // can reuse a previously allocated dojo.Color object for the result
+ var d = dojo, t = obj || new dojo.Color();
+ d.forEach(["r", "g", "b", "a"], function(x){
+ t[x] = start[x] + (end[x] - start[x]) * weight;
+ if(x != "a"){ t[x] = Math.round(t[x]); }
+ });
+ return t.sanitize(); // dojo.Color
+};
+
+dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
+ // summary: get rgb(a) array from css-style color declarations
+ var m = color.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/);
+ return m && dojo.colorFromArray(m[1].split(/\s*,\s*/), obj); // dojo.Color
+};
+
+dojo.colorFromHex = function(/*String*/ color, /*dojo.Color?*/ obj){
+ // summary: converts a hex string with a '#' prefix to a color object.
+ // Supports 12-bit #rgb shorthand.
+ var d = dojo, t = obj || new d.Color(),
+ bits = (color.length == 4) ? 4 : 8,
+ mask = (1 << bits) - 1;
+ color = Number("0x" + color.substr(1));
+ if(isNaN(color)){
+ return null; // dojo.Color
+ }
+ d.forEach(["b", "g", "r"], function(x){
+ var c = color & mask;
+ color >>= bits;
+ t[x] = bits == 4 ? 17 * c : c;
+ });
+ t.a = 1;
+ return t; // dojo.Color
+};
+
+dojo.colorFromArray = function(/*Array*/ a, /*dojo.Color?*/ obj){
+ // summary: builds a color from 1, 2, 3, or 4 element array
+ var t = obj || new dojo.Color();
+ t._set(Number(a[0]), Number(a[1]), Number(a[2]), Number(a[3]));
+ if(isNaN(t.a)){ t.a = 1; }
+ return t.sanitize(); // dojo.Color
+};
+
+dojo.colorFromString = function(/*String*/ str, /*dojo.Color?*/ obj){
+ // summary:
+ // parses str for a color value.
+ // description:
+ // Acceptable input values for str may include arrays of any form
+ // accepted by dojo.colorFromArray, hex strings such as "#aaaaaa", or
+ // rgb or rgba strings such as "rgb(133, 200, 16)" or "rgba(10, 10,
+ // 10, 50)"
+ // returns:
+ // a dojo.Color object. If obj is passed, it will be the return value.
+ var a = dojo.Color.named[str];
+ return a && dojo.colorFromArray(a, obj) || dojo.colorFromRgb(str, obj) || dojo.colorFromHex(str, obj);
+};
+
+}
+
+if(!dojo._hasResource["dojo._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base"] = true;
+dojo.provide("dojo._base");
+
+
+
+
+
+
+
+
+
+}
+
+if(!dojo._hasResource["dojo._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.window"] = true;
+dojo.provide("dojo._base.window");
+
+dojo._gearsObject = function(){
+ // summary:
+ // factory method to get a Google Gears plugin instance to
+ // expose in the browser runtime environment, if present
+ var factory;
+ var results;
+
+ var gearsObj = dojo.getObject("google.gears");
+ if(gearsObj){ return gearsObj; } // already defined elsewhere
+
+ if(typeof GearsFactory != "undefined"){ // Firefox
+ factory = new GearsFactory();
+ }else{
+ if(dojo.isIE){
+ // IE
+ try{
+ factory = new ActiveXObject("Gears.Factory");
+ }catch(e){
+ // ok to squelch; there's no gears factory. move on.
+ }
+ }else if(navigator.mimeTypes["application/x-googlegears"]){
+ // Safari?
+ factory = document.createElement("object");
+ factory.setAttribute("type", "application/x-googlegears");
+ factory.setAttribute("width", 0);
+ factory.setAttribute("height", 0);
+ factory.style.display = "none";
+ document.documentElement.appendChild(factory);
+ }
+ }
+
+ // still nothing?
+ if(!factory){ return null; }
+
+ // define the global objects now; don't overwrite them though if they
+ // were somehow set internally by the Gears plugin, which is on their
+ // dev roadmap for the future
+ dojo.setObject("google.gears.factory", factory);
+ return dojo.getObject("google.gears");
+};
+
+/*=====
+dojo.isGears = {
+ // summary: True if client is using Google Gears
+};
+=====*/
+// see if we have Google Gears installed, and if
+// so, make it available in the runtime environment
+// and in the Google standard 'google.gears' global object
+dojo.isGears = (!!dojo._gearsObject())||0;
+
+/*=====
+dojo.doc = {
+ // summary:
+ // Alias for the current document. 'dojo.doc' can be modified
+ // for temporary context shifting. Also see dojo.withDoc().
+ // description:
+ // Refer to dojo.doc rather
+ // than referring to 'window.document' to ensure your code runs
+ // correctly in managed contexts.
+ // example:
+ // | n.appendChild(dojo.doc.createElement('div'));
+}
+=====*/
+dojo.doc = window["document"] || null;
+
+dojo.body = function(){
+ // summary:
+ // Return the body element of the document
+ // return the body object associated with dojo.doc
+ // example:
+ // | dojo.body().appendChild(dojo.doc.createElement('div'));
+
+ // Note: document.body is not defined for a strict xhtml document
+ // Would like to memoize this, but dojo.doc can change vi dojo.withDoc().
+ return dojo.doc.body || dojo.doc.getElementsByTagName("body")[0]; // Node
+}
+
+dojo.setContext = function(/*Object*/globalObject, /*DocumentElement*/globalDocument){
+ // summary:
+ // changes the behavior of many core Dojo functions that deal with
+ // namespace and DOM lookup, changing them to work in a new global
+ // context (e.g., an iframe). The varibles dojo.global and dojo.doc
+ // are modified as a result of calling this function and the result of
+ // `dojo.body()` likewise differs.
+ dojo.global = globalObject;
+ dojo.doc = globalDocument;
+};
+
+dojo._fireCallback = function(callback, context, cbArguments){
+ if(context && dojo.isString(callback)){
+ callback = context[callback];
+ }
+ return callback.apply(context, cbArguments || [ ]);
+}
+
+dojo.withGlobal = function( /*Object*/globalObject,
+ /*Function*/callback,
+ /*Object?*/thisObject,
+ /*Array?*/cbArguments){
+ // summary:
+ // Call callback with globalObject as dojo.global and
+ // globalObject.document as dojo.doc. If provided, globalObject
+ // will be executed in the context of object thisObject
+ // description:
+ // When callback() returns or throws an error, the dojo.global
+ // and dojo.doc will be restored to its previous state.
+ var rval;
+ var oldGlob = dojo.global;
+ var oldDoc = dojo.doc;
+ try{
+ dojo.setContext(globalObject, globalObject.document);
+ rval = dojo._fireCallback(callback, thisObject, cbArguments);
+ }finally{
+ dojo.setContext(oldGlob, oldDoc);
+ }
+ return rval;
+}
+
+dojo.withDoc = function( /*Object*/documentObject,
+ /*Function*/callback,
+ /*Object?*/thisObject,
+ /*Array?*/cbArguments){
+ // summary:
+ // Call callback with documentObject as dojo.doc. If provided,
+ // callback will be executed in the context of object thisObject
+ // description:
+ // When callback() returns or throws an error, the dojo.doc will
+ // be restored to its previous state.
+ var rval;
+ var oldDoc = dojo.doc;
+ try{
+ dojo.doc = documentObject;
+ rval = dojo._fireCallback(callback, thisObject, cbArguments);
+ }finally{
+ dojo.doc = oldDoc;
+ }
+ return rval;
+};
+
+}
+
+if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.event"] = true;
+dojo.provide("dojo._base.event");
+
+
+// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
+
+(function(){
+ // DOM event listener machinery
+ var del = (dojo._event_listener = {
+ add: function(/*DOMNode*/node, /*String*/name, /*Function*/fp){
+ if(!node){return;}
+ name = del._normalizeEventName(name);
+ fp = del._fixCallback(name, fp);
+ var oname = name;
+ if(!dojo.isIE && (name == "mouseenter" || name == "mouseleave")){
+ var ofp = fp;
+ //oname = name;
+ name = (name == "mouseenter") ? "mouseover" : "mouseout";
+ fp = function(e){
+ // thanks ben!
+ if(!dojo.isDescendant(e.relatedTarget, node)){
+ // e.type = oname; // FIXME: doesn't take? SJM: event.type is generally immutable.
+ return ofp.call(this, e);
+ }
+ }
+ }
+ node.addEventListener(name, fp, false);
+ return fp; /*Handle*/
+ },
+ remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
+ // summary:
+ // clobbers the listener from the node
+ // node:
+ // DOM node to attach the event to
+ // event:
+ // the name of the handler to remove the function from
+ // handle:
+ // the handle returned from add
+ if (node){
+ node.removeEventListener(del._normalizeEventName(event), handle, false);
+ }
+ },
+ _normalizeEventName: function(/*String*/name){
+ // Generally, name should be lower case, unless it is special
+ // somehow (e.g. a Mozilla DOM event).
+ // Remove 'on'.
+ return name.slice(0,2) =="on" ? name.slice(2) : name;
+ },
+ _fixCallback: function(/*String*/name, fp){
+ // By default, we only invoke _fixEvent for 'keypress'
+ // If code is added to _fixEvent for other events, we have
+ // to revisit this optimization.
+ // This also applies to _fixEvent overrides for Safari and Opera
+ // below.
+ return name != "keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); };
+ },
+ _fixEvent: function(evt, sender){
+ // _fixCallback only attaches us to keypress.
+ // Switch on evt.type anyway because we might
+ // be called directly from dojo.fixEvent.
+ switch(evt.type){
+ case "keypress":
+ del._setKeyChar(evt);
+ break;
+ }
+ return evt;
+ },
+ _setKeyChar: function(evt){
+ evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
+ }
+ });
+
+ // DOM events
+
+ dojo.fixEvent = function(/*Event*/evt, /*DOMNode*/sender){
+ // summary:
+ // normalizes properties on the event object including event
+ // bubbling methods, keystroke normalization, and x/y positions
+ // evt: Event
+ // native event object
+ // sender: DOMNode
+ // node to treat as "currentTarget"
+ return del._fixEvent(evt, sender);
+ }
+
+ dojo.stopEvent = function(/*Event*/evt){
+ // summary:
+ // prevents propagation and clobbers the default action of the
+ // passed event
+ // evt: Event
+ // The event object. If omitted, window.event is used on IE.
+ evt.preventDefault();
+ evt.stopPropagation();
+ // NOTE: below, this method is overridden for IE
+ }
+
+ // the default listener to use on dontFix nodes, overriden for IE
+ var node_listener = dojo._listener;
+
+ // Unify connect and event listeners
+ dojo._connect = function(obj, event, context, method, dontFix){
+ // FIXME: need a more strict test
+ var isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener);
+ // choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node
+ // we need the third option to provide leak prevention on broken browsers (IE)
+ var lid = !isNode ? 0 : (!dontFix ? 1 : 2), l = [dojo._listener, del, node_listener][lid];
+ // create a listener
+ var h = l.add(obj, event, dojo.hitch(context, method));
+ // formerly, the disconnect package contained "l" directly, but if client code
+ // leaks the disconnect package (by connecting it to a node), referencing "l"
+ // compounds the problem.
+ // instead we return a listener id, which requires custom _disconnect below.
+ // return disconnect package
+ return [ obj, event, h, lid ];
+ }
+
+ dojo._disconnect = function(obj, event, handle, listener){
+ ([dojo._listener, del, node_listener][listener]).remove(obj, event, handle);
+ }
+
+ // Constants
+
+ // Public: client code should test
+ // keyCode against these named constants, as the
+ // actual codes can vary by browser.
+ dojo.keys = {
+ // summary: definitions for common key values
+ BACKSPACE: 8,
+ TAB: 9,
+ CLEAR: 12,
+ ENTER: 13,
+ SHIFT: 16,
+ CTRL: 17,
+ ALT: 18,
+ PAUSE: 19,
+ CAPS_LOCK: 20,
+ ESCAPE: 27,
+ SPACE: 32,
+ PAGE_UP: 33,
+ PAGE_DOWN: 34,
+ END: 35,
+ HOME: 36,
+ LEFT_ARROW: 37,
+ UP_ARROW: 38,
+ RIGHT_ARROW: 39,
+ DOWN_ARROW: 40,
+ INSERT: 45,
+ DELETE: 46,
+ HELP: 47,
+ LEFT_WINDOW: 91,
+ RIGHT_WINDOW: 92,
+ SELECT: 93,
+ NUMPAD_0: 96,
+ NUMPAD_1: 97,
+ NUMPAD_2: 98,
+ NUMPAD_3: 99,
+ NUMPAD_4: 100,
+ NUMPAD_5: 101,
+ NUMPAD_6: 102,
+ NUMPAD_7: 103,
+ NUMPAD_8: 104,
+ NUMPAD_9: 105,
+ NUMPAD_MULTIPLY: 106,
+ NUMPAD_PLUS: 107,
+ NUMPAD_ENTER: 108,
+ NUMPAD_MINUS: 109,
+ NUMPAD_PERIOD: 110,
+ NUMPAD_DIVIDE: 111,
+ F1: 112,
+ F2: 113,
+ F3: 114,
+ F4: 115,
+ F5: 116,
+ F6: 117,
+ F7: 118,
+ F8: 119,
+ F9: 120,
+ F10: 121,
+ F11: 122,
+ F12: 123,
+ F13: 124,
+ F14: 125,
+ F15: 126,
+ NUM_LOCK: 144,
+ SCROLL_LOCK: 145
+ };
+
+ // IE event normalization
+ if(dojo.isIE){
+ var _trySetKeyCode = function(e, code){
+ try{
+ // squelch errors when keyCode is read-only
+ // (e.g. if keyCode is ctrl or shift)
+ return (e.keyCode = code);
+ }catch(e){
+ return 0;
+ }
+ }
+
+ // by default, use the standard listener
+ var iel = dojo._listener;
+ // dispatcher tracking property
+ if(!dojo.config._allow_leaks){
+ // custom listener that handles leak protection for DOM events
+ node_listener = iel = dojo._ie_listener = {
+ // support handler indirection: event handler functions are
+ // referenced here. Event dispatchers hold only indices.
+ handlers: [],
+ // add a listener to an object
+ add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
+ source = source || dojo.global;
+ var f = source[method];
+ if(!f||!f._listeners){
+ var d = dojo._getIeDispatcher();
+ // original target function is special
+ d.target = f && (ieh.push(f) - 1);
+ // dispatcher holds a list of indices into handlers table
+ d._listeners = [];
+ // redirect source to dispatcher
+ f = source[method] = d;
+ }
+ return f._listeners.push(ieh.push(listener) - 1) ; /*Handle*/
+ },
+ // remove a listener from an object
+ remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
+ var f = (source||dojo.global)[method], l = f && f._listeners;
+ if(f && l && handle--){
+ delete ieh[l[handle]];
+ delete l[handle];
+ }
+ }
+ };
+ // alias used above
+ var ieh = iel.handlers;
+ }
+
+ dojo.mixin(del, {
+ add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){
+ if(!node){return;} // undefined
+ event = del._normalizeEventName(event);
+ if(event=="onkeypress"){
+ // we need to listen to onkeydown to synthesize
+ // keypress events that otherwise won't fire
+ // on IE
+ var kd = node.onkeydown;
+ if(!kd || !kd._listeners || !kd._stealthKeydownHandle){
+ var h = del.add(node, "onkeydown", del._stealthKeyDown);
+ kd = node.onkeydown;
+ kd._stealthKeydownHandle = h;
+ kd._stealthKeydownRefs = 1;
+ }else{
+ kd._stealthKeydownRefs++;
+ }
+ }
+ return iel.add(node, event, del._fixCallback(fp));
+ },
+ remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
+ event = del._normalizeEventName(event);
+ iel.remove(node, event, handle);
+ if(event=="onkeypress"){
+ var kd = node.onkeydown;
+ if(--kd._stealthKeydownRefs <= 0){
+ iel.remove(node, "onkeydown", kd._stealthKeydownHandle);
+ delete kd._stealthKeydownHandle;
+ }
+ }
+ },
+ _normalizeEventName: function(/*String*/eventName){
+ // Generally, eventName should be lower case, unless it is
+ // special somehow (e.g. a Mozilla event)
+ // ensure 'on'
+ return eventName.slice(0,2) != "on" ? "on" + eventName : eventName;
+ },
+ _nop: function(){},
+ _fixEvent: function(/*Event*/evt, /*DOMNode*/sender){
+ // summary:
+ // normalizes properties on the event object including event
+ // bubbling methods, keystroke normalization, and x/y positions
+ // evt: native event object
+ // sender: node to treat as "currentTarget"
+ if(!evt){
+ var w = sender && (sender.ownerDocument || sender.document || sender).parentWindow || window;
+ evt = w.event;
+ }
+ if(!evt){return(evt);}
+ evt.target = evt.srcElement;
+ evt.currentTarget = (sender || evt.srcElement);
+ evt.layerX = evt.offsetX;
+ evt.layerY = evt.offsetY;
+ // FIXME: scroll position query is duped from dojo.html to
+ // avoid dependency on that entire module. Now that HTML is in
+ // Base, we should convert back to something similar there.
+ var se = evt.srcElement, doc = (se && se.ownerDocument) || document;
+ // DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used
+ // here rather than document.body
+ var docBody = ((dojo.isIE < 6) || (doc["compatMode"] == "BackCompat")) ? doc.body : doc.documentElement;
+ var offset = dojo._getIeDocumentElementOffset();
+ evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x;
+ evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y;
+ if(evt.type == "mouseover"){
+ evt.relatedTarget = evt.fromElement;
+ }
+ if(evt.type == "mouseout"){
+ evt.relatedTarget = evt.toElement;
+ }
+ evt.stopPropagation = del._stopPropagation;
+ evt.preventDefault = del._preventDefault;
+ return del._fixKeys(evt);
+ },
+ _fixKeys: function(evt){
+ switch(evt.type){
+ case "keypress":
+ var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
+ if (c==10){
+ // CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
+ c=0;
+ evt.keyCode = 13;
+ }else if(c==13||c==27){
+ c=0; // Mozilla considers ENTER and ESC non-printable
+ }else if(c==3){
+ c=99; // Mozilla maps CTRL-BREAK to CTRL-c
+ }
+ // Mozilla sets keyCode to 0 when there is a charCode
+ // but that stops the event on IE.
+ evt.charCode = c;
+ del._setKeyChar(evt);
+ break;
+ }
+ return evt;
+ },
+ // some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE
+ // we map those virtual key codes to ascii here
+ // not valid for all (non-US) keyboards, so maybe we shouldn't bother
+ _punctMap: {
+ 106:42,
+ 111:47,
+ 186:59,
+ 187:43,
+ 188:44,
+ 189:45,
+ 190:46,
+ 191:47,
+ 192:96,
+ 219:91,
+ 220:92,
+ 221:93,
+ 222:39
+ },
+ _stealthKeyDown: function(evt){
+ // IE doesn't fire keypress for most non-printable characters.
+ // other browsers do, we simulate it here.
+ var kp = evt.currentTarget.onkeypress;
+ // only works if kp exists and is a dispatcher
+ if(!kp || !kp._listeners){ return; }
+ // munge key/charCode
+ var k=evt.keyCode;
+ // These are Windows Virtual Key Codes
+ // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
+ var unprintable = (k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);
+ // synthesize keypress for most unprintables and CTRL-keys
+ if(unprintable||evt.ctrlKey){
+ var c = unprintable ? 0 : k;
+ if(evt.ctrlKey){
+ if(k==3 || k==13){
+ return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
+ }else if(c>95 && c<106){
+ c -= 48; // map CTRL-[numpad 0-9] to ASCII
+ }else if((!evt.shiftKey)&&(c>=65&&c<=90)){
+ c += 32; // map CTRL-[A-Z] to lowercase
+ }else{
+ c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
+ }
+ }
+ // simulate a keypress event
+ var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
+ kp.call(evt.currentTarget, faux);
+ evt.cancelBubble = faux.cancelBubble;
+ evt.returnValue = faux.returnValue;
+ _trySetKeyCode(evt, faux.keyCode);
+ }
+ },
+ // Called in Event scope
+ _stopPropagation: function(){
+ this.cancelBubble = true;
+ },
+ _preventDefault: function(){
+ // Setting keyCode to 0 is the only way to prevent certain keypresses (namely
+ // ctrl-combinations that correspond to menu accelerator keys).
+ // Otoh, it prevents upstream listeners from getting this information
+ // Try to split the difference here by clobbering keyCode only for ctrl
+ // combinations. If you still need to access the key upstream, bubbledKeyCode is
+ // provided as a workaround.
+ this.bubbledKeyCode = this.keyCode;
+ if(this.ctrlKey){_trySetKeyCode(this, 0);}
+ this.returnValue = false;
+ }
+ });
+
+ // override stopEvent for IE
+ dojo.stopEvent = function(evt){
+ evt = evt || window.event;
+ del._stopPropagation.call(evt);
+ del._preventDefault.call(evt);
+ }
+ }
+
+ del._synthesizeEvent = function(evt, props){
+ var faux = dojo.mixin({}, evt, props);
+ del._setKeyChar(faux);
+ // FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault);
+ // but it throws an error when preventDefault is invoked on Safari
+ // does Event.preventDefault not support "apply" on Safari?
+ faux.preventDefault = function(){ evt.preventDefault(); };
+ faux.stopPropagation = function(){ evt.stopPropagation(); };
+ return faux;
+ }
+
+ // Opera event normalization
+ if(dojo.isOpera){
+ dojo.mixin(del, {
+ _fixEvent: function(evt, sender){
+ switch(evt.type){
+ case "keypress":
+ var c = evt.which;
+ if(c==3){
+ c=99; // Mozilla maps CTRL-BREAK to CTRL-c
+ }
+ // can't trap some keys at all, like INSERT and DELETE
+ // there is no differentiating info between DELETE and ".", or INSERT and "-"
+ c = ((c<41)&&(!evt.shiftKey) ? 0 : c);
+ if((evt.ctrlKey)&&(!evt.shiftKey)&&(c>=65)&&(c<=90)){
+ // lowercase CTRL-[A-Z] keys
+ c += 32;
+ }
+ return del._synthesizeEvent(evt, { charCode: c });
+ }
+ return evt;
+ }
+ });
+ }
+
+ // Safari event normalization
+ if(dojo.isSafari){
+ dojo.mixin(del, {
+ _fixEvent: function(evt, sender){
+ switch(evt.type){
+ case "keypress":
+ var c = evt.charCode, s = evt.shiftKey, k = evt.keyCode;
+ // FIXME: This is a hack, suggest we rethink keyboard strategy.
+ // Arrow and page keys have 0 "keyCode" in keypress events.on Safari for Windows
+ k = k || identifierMap[evt.keyIdentifier] || 0;
+ if(evt.keyIdentifier=="Enter"){
+ c = 0; // differentiate Enter from CTRL-m (both code 13)
+ }else if((evt.ctrlKey)&&(c>0)&&(c<27)){
+ c += 96; // map CTRL-[A-Z] codes to ASCII
+ } else if (c==dojo.keys.SHIFT_TAB) {
+ c = dojo.keys.TAB; // morph SHIFT_TAB into TAB + shiftKey: true
+ s = true;
+ } else {
+ c = (c>=32 && c<63232 ? c : 0); // avoid generating keyChar for non-printables
+ }
+ return del._synthesizeEvent(evt, {charCode: c, shiftKey: s, keyCode: k});
+ }
+ return evt;
+ }
+ });
+
+ dojo.mixin(dojo.keys, {
+ SHIFT_TAB: 25,
+ UP_ARROW: 63232,
+ DOWN_ARROW: 63233,
+ LEFT_ARROW: 63234,
+ RIGHT_ARROW: 63235,
+ F1: 63236,
+ F2: 63237,
+ F3: 63238,
+ F4: 63239,
+ F5: 63240,
+ F6: 63241,
+ F7: 63242,
+ F8: 63243,
+ F9: 63244,
+ F10: 63245,
+ F11: 63246,
+ F12: 63247,
+ PAUSE: 63250,
+ DELETE: 63272,
+ HOME: 63273,
+ END: 63275,
+ PAGE_UP: 63276,
+ PAGE_DOWN: 63277,
+ INSERT: 63302,
+ PRINT_SCREEN: 63248,
+ SCROLL_LOCK: 63249,
+ NUM_LOCK: 63289
+ });
+ var dk = dojo.keys, identifierMap = { "Up": dk.UP_ARROW, "Down": dk.DOWN_ARROW, "Left": dk.LEFT_ARROW, "Right": dk.RIGHT_ARROW, "PageUp": dk.PAGE_UP, "PageDown": dk.PAGE_DOWN };
+ }
+})();
+
+if(dojo.isIE){
+ // keep this out of the closure
+ // closing over 'iel' or 'ieh' b0rks leak prevention
+ // ls[i] is an index into the master handler array
+ dojo._ieDispatcher = function(args, sender){
+ var ap=Array.prototype, h=dojo._ie_listener.handlers, c=args.callee, ls=c._listeners, t=h[c.target];
+ // return value comes from original target function
+ var r = t && t.apply(sender, args);
+ // invoke listeners after target function
+ for(var i in ls){
+ if(!(i in ap)){
+ h[ls[i]].apply(sender, args);
+ }
+ }
+ return r;
+ }
+ dojo._getIeDispatcher = function(){
+ // ensure the returned function closes over nothing
+ return new Function(dojo._scopeName + "._ieDispatcher(arguments, this)"); // function
+ }
+ // keep this out of the closure to reduce RAM allocation
+ dojo._event_listener._fixCallback = function(fp){
+ var f = dojo._event_listener._fixEvent;
+ return function(e){ return fp.call(this, f(e, this)); };
+ }
+}
+
+}
+
+if(!dojo._hasResource["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.html"] = true;
+
+dojo.provide("dojo._base.html");
+
+// FIXME: need to add unit tests for all the semi-public methods
+
+try{
+ document.execCommand("BackgroundImageCache", false, true);
+}catch(e){
+ // sane browsers don't have cache "issues"
+}
+
+// =============================
+// DOM Functions
+// =============================
+
+/*=====
+dojo.byId = function(id, doc){
+ // summary:
+ // Returns DOM node with matching `id` attribute or `null`
+ // if not found, similar to "$" function in another library.
+ // If `id` is a DomNode, this function is a no-op.
+ //
+ // id: String|DOMNode
+ // A string to match an HTML id attribute or a reference to a DOM Node
+ //
+ // doc: Document?
+ // Document to work in. Defaults to the current value of
+ // dojo.doc. Can be used to retrieve
+ // node references from other documents.
+=====*/
+if(dojo.isIE || dojo.isOpera){
+ dojo.byId = function(id, doc){
+ if(dojo.isString(id)){
+ var _d = doc || dojo.doc;
+ var te = _d.getElementById(id);
+ // attributes.id.value is better than just id in case the
+ // user has a name=id inside a form
+ if(te && te.attributes.id.value == id){
+ return te;
+ }else{
+ var eles = _d.all[id];
+ if(!eles || !eles.length){ return eles; }
+ // if more than 1, choose first with the correct id
+ var i=0;
+ while((te=eles[i++])){
+ if(te.attributes.id.value == id){ return te; }
+ }
+ }
+ }else{
+ return id; // DomNode
+ }
+ }
+}else{
+ dojo.byId = function(id, doc){
+ return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode
+ }
+}
+/*=====
+}
+=====*/
+
+(function(){
+ /*
+ dojo.createElement = function(obj, parent, position){
+ // TODO: need to finish this!
+ }
+ */
+
+ var d = dojo;
+
+ var _destroyContainer = null;
+ dojo.addOnUnload(function(){
+ _destroyContainer=null; //prevent IE leak
+ });
+ dojo._destroyElement = function(/*String||DomNode*/node){
+ // summary:
+ // removes node from its parent, clobbers it and all of its
+ // children.
+ // node:
+ // the element to be destroyed, either as an ID or a reference
+
+ node = d.byId(node);
+ try{
+ if(!_destroyContainer){
+ _destroyContainer = document.createElement("div");
+ }
+ _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node);
+ // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature
+ _destroyContainer.innerHTML = "";
+ }catch(e){
+ /* squelch */
+ }
+ };
+
+ dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){
+ // summary:
+ // Returns true if node is a descendant of ancestor
+ // node: id or node reference to test
+ // ancestor: id or node reference of potential parent to test against
+ try{
+ node = d.byId(node);
+ ancestor = d.byId(ancestor);
+ while(node){
+ if(node === ancestor){
+ return true; // Boolean
+ }
+ node = node.parentNode;
+ }
+ }catch(e){ /* squelch, return false */ }
+ return false; // Boolean
+ };
+
+ dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){
+ // summary: enable or disable selection on a node
+ // node:
+ // id or reference to node
+ // selectable:
+ node = d.byId(node);
+ if(d.isMozilla){
+ node.style.MozUserSelect = selectable ? "" : "none";
+ }else if(d.isKhtml){
+ node.style.KhtmlUserSelect = selectable ? "auto" : "none";
+ }else if(d.isIE){
+ node.unselectable = selectable ? "" : "on";
+ d.query("*", node).forEach(function(descendant){
+ descendant.unselectable = selectable ? "" : "on";
+ });
+ }
+ //FIXME: else? Opera?
+ };
+
+ var _insertBefore = function(/*Node*/node, /*Node*/ref){
+ ref.parentNode.insertBefore(node, ref);
+ return true; // boolean
+ }
+
+ var _insertAfter = function(/*Node*/node, /*Node*/ref){
+ // summary:
+ // Try to insert node after ref
+ var pn = ref.parentNode;
+ if(ref == pn.lastChild){
+ pn.appendChild(node);
+ }else{
+ return _insertBefore(node, ref.nextSibling); // boolean
+ }
+ return true; // boolean
+ }
+
+ dojo.place = function(/*String|DomNode*/node, /*String|DomNode*/refNode, /*String|Number*/position){
+ // summary:
+ // Attempt to insert node into the DOM, choosing from various positioning options.
+ // Returns true if successful, false otherwise.
+ // node:
+ // id or node reference to place relative to refNode
+ // refNode:
+ // id or node reference to use as basis for placement
+ // position:
+ // string noting the position of node relative to refNode or a
+ // number indicating the location in the childNodes collection of
+ // refNode. Accepted string values are:
+ //
+ // * before
+ // * after
+ // * first
+ // * last
+ //
+ // "first" and "last" indicate positions as children of refNode.
+
+ // FIXME: need to write tests for this!!!!
+ if(!node || !refNode || position === undefined){
+ return false; // boolean
+ }
+ node = d.byId(node);
+ refNode = d.byId(refNode);
+ if(typeof position == "number"){
+ var cn = refNode.childNodes;
+ if((position == 0 && cn.length == 0) ||
+ cn.length == position){
+ refNode.appendChild(node); return true;
+ }
+ if(position == 0){
+ return _insertBefore(node, refNode.firstChild);
+ }
+ return _insertAfter(node, cn[position-1]);
+ }
+ switch(position.toLowerCase()){
+ case "before":
+ return _insertBefore(node, refNode); // boolean
+ case "after":
+ return _insertAfter(node, refNode); // boolean
+ case "first":
+ if(refNode.firstChild){
+ return _insertBefore(node, refNode.firstChild); // boolean
+ }
+ // else fallthrough...
+ default: // aka: last
+ refNode.appendChild(node);
+ return true; // boolean
+ }
+ }
+
+ // Box functions will assume this model.
+ // On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode.
+ // Can be set to change behavior of box setters.
+
+ // can be either:
+ // "border-box"
+ // "content-box" (default)
+ dojo.boxModel = "content-box";
+
+ // We punt per-node box mode testing completely.
+ // If anybody cares, we can provide an additional (optional) unit
+ // that overrides existing code to include per-node box sensitivity.
+
+ // Opera documentation claims that Opera 9 uses border-box in BackCompat mode.
+ // but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box.
+ // IIRC, earlier versions of Opera did in fact use border-box.
+ // Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault.
+
+ if(d.isIE /*|| dojo.isOpera*/){
+ var _dcm = document.compatMode;
+ // client code may have to adjust if compatMode varies across iframes
+ d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE<6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support?
+ }
+
+ // =============================
+ // Style Functions
+ // =============================
+
+ // getComputedStyle drives most of the style code.
+ // Wherever possible, reuse the returned object.
+ //
+ // API functions below that need to access computed styles accept an
+ // optional computedStyle parameter.
+ // If this parameter is omitted, the functions will call getComputedStyle themselves.
+ // This way, calling code can access computedStyle once, and then pass the reference to
+ // multiple API functions.
+
+/*=====
+ dojo.getComputedStyle = function(node){
+ // summary:
+ // Returns a "computed style" object.
+ //
+ // description:
+ // Gets a "computed style" object which can be used to gather
+ // information about the current state of the rendered node.
+ //
+ // Note that this may behave differently on different browsers.
+ // Values may have different formats and value encodings across
+ // browsers.
+ //
+ // Note also that this method is expensive. Wherever possible,
+ // reuse the returned object.
+ //
+ // Use the dojo.style() method for more consistent (pixelized)
+ // return values.
+ //
+ // node: DOMNode
+ // A reference to a DOM node. Does NOT support taking an
+ // ID string for speed reasons.
+ // example:
+ // | dojo.getComputedStyle(dojo.byId('foo')).borderWidth;
+ return; // CSS2Properties
+ }
+=====*/
+
+ var gcs, dv = document.defaultView;
+ if(d.isSafari){
+ gcs = function(/*DomNode*/node){
+ var s = dv.getComputedStyle(node, null);
+ if(!s && node.style){
+ node.style.display = "";
+ s = dv.getComputedStyle(node, null);
+ }
+ return s || {};
+ };
+ }else if(d.isIE){
+ gcs = function(node){
+ return node.currentStyle;
+ };
+ }else{
+ gcs = function(node){
+ return dv.getComputedStyle(node, null);
+ };
+ }
+ dojo.getComputedStyle = gcs;
+
+ if(!d.isIE){
+ dojo._toPixelValue = function(element, value){
+ // style values can be floats, client code may want
+ // to round for integer pixels.
+ return parseFloat(value) || 0;
+ }
+ }else{
+ dojo._toPixelValue = function(element, avalue){
+ if(!avalue){ return 0; }
+ // on IE7, medium is usually 4 pixels
+ if(avalue=="medium"){ return 4; }
+ // style values can be floats, client code may
+ // want to round this value for integer pixels.
+ if(avalue.slice && (avalue.slice(-2)=='px')){ return parseFloat(avalue); }
+ with(element){
+ var sLeft = style.left;
+ var rsLeft = runtimeStyle.left;
+ runtimeStyle.left = currentStyle.left;
+ try{
+ // 'avalue' may be incompatible with style.left, which can cause IE to throw
+ // this has been observed for border widths using "thin", "medium", "thick" constants
+ // those particular constants could be trapped by a lookup
+ // but perhaps there are more
+ style.left = avalue;
+ avalue = style.pixelLeft;
+ }catch(e){
+ avalue = 0;
+ }
+ style.left = sLeft;
+ runtimeStyle.left = rsLeft;
+ }
+ return avalue;
+ }
+ }
+ var px = d._toPixelValue;
+
+ // FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
+ /*=====
+ dojo._getOpacity = function(node){
+ // summary:
+ // Returns the current opacity of the passed node as a
+ // floating-point value between 0 and 1.
+ // node: DomNode
+ // a reference to a DOM node. Does NOT support taking an
+ // ID string for speed reasons.
+ // return: Number between 0 and 1
+ }
+ =====*/
+
+ dojo._getOpacity = d.isIE ? function(node){
+ try{
+ return node.filters.alpha.opacity / 100; // Number
+ }catch(e){
+ return 1; // Number
+ }
+ } : function(node){
+ return gcs(node).opacity;
+ };
+
+ /*=====
+ dojo._setOpacity = function(node, opacity){
+ // summary:
+ // set the opacity of the passed node portably. Returns the
+ // new opacity of the node.
+ // node: DOMNode
+ // a reference to a DOM node. Does NOT support taking an
+ // ID string for performance reasons.
+ // opacity: Number
+ // A Number between 0 and 1. 0 specifies transparent.
+ // return: Number between 0 and 1
+ }
+ =====*/
+
+ dojo._setOpacity = d.isIE ? function(/*DomNode*/node, /*Number*/opacity){
+ if(opacity == 1){
+ // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so remove it altogether (bug #2661)
+ var filterRE = /FILTER:[^;]*;?/i;
+ node.style.cssText = node.style.cssText.replace(filterRE, "");
+ if(node.nodeName.toLowerCase() == "tr"){
+ d.query("> td", node).forEach(function(i){
+ i.style.cssText = i.style.cssText.replace(filterRE, "");
+ });
+ }
+ }else{
+ var o = "Alpha(Opacity="+ opacity * 100 +")";
+ node.style.filter = o;
+ }
+ if(node.nodeName.toLowerCase() == "tr"){
+ d.query("> td", node).forEach(function(i){
+ i.style.filter = o;
+ });
+ }
+ return opacity;
+ } : function(node, opacity){
+ return node.style.opacity = opacity;
+ };
+
+ var _pixelNamesCache = {
+ left: true, top: true
+ };
+ var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border
+ var _toStyleValue = function(node, type, value){
+ type = type.toLowerCase();
+ if(d.isIE && value == "auto"){
+ if(type == "height"){ return node.offsetHeight; }
+ if(type == "width"){ return node.offsetWidth; }
+ }
+ if(!(type in _pixelNamesCache)){
+ // if(dojo.isOpera && type == "cssText"){
+ // FIXME: add workaround for #2855 here
+ // }
+ _pixelNamesCache[type] = _pixelRegExp.test(type);
+ }
+ return _pixelNamesCache[type] ? px(node, value) : value;
+ }
+
+ var _floatStyle = d.isIE ? "styleFloat" : "cssFloat";
+ var _floatAliases = { "cssFloat": _floatStyle, "styleFloat": _floatStyle, "float": _floatStyle };
+
+ // public API
+
+ dojo.style = function( /*DomNode|String*/ node,
+ /*String?|Object?*/ style,
+ /*String?*/ value){
+ // summary:
+ // Accesses styles on a node. If 2 arguments are
+ // passed, acts as a getter. If 3 arguments are passed, acts
+ // as a setter.
+ // node:
+ // id or reference to node to get/set style for
+ // style:
+ // the style property to set in DOM-accessor format
+ // ("borderWidth", not "border-width") or an object with key/value
+ // pairs suitable for setting each property.
+ // value:
+ // If passed, sets value on the node for style, handling
+ // cross-browser concerns.
+ // example:
+ // Passing only an ID or node returns the computed style object of
+ // the node:
+ // | dojo.style("thinger");
+ // example:
+ // Passing a node and a style property returns the current
+ // normalized, computed value for that property:
+ // | dojo.style("thinger", "opacity"); // 1 by default
+ //
+ // example:
+ // Passing a node, a style property, and a value changes the
+ // current display of the node and returns the new computed value
+ // | dojo.style("thinger", "opacity", 0.5); // == 0.5
+ //
+ // example:
+ // Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node:
+ // | dojo.style("thinger", {
+ // | "opacity": 0.5,
+ // | "border": "3px solid black",
+ // | "height": 300
+ // | });
+ //
+ // example:
+ // When the CSS style property is hyphenated, the JavaScript property is camelCased.
+ // font-size becomes fontSize, and so on.
+ // | dojo.style("thinger",{
+ // | fontSize:"14pt",
+ // | letterSpacing:"1.2em"
+ // | });
+ //
+ // example:
+ // dojo.NodeList implements .style() using the same syntax, omitting the "node" parameter, calling
+ // dojo.style() on every element of the list. See: dojo.query and dojo.NodeList
+ // | dojo.query(".someClassName").style("visibility","hidden");
+ // | // or
+ // | dojo.query("#baz > div").style({
+ // | opacity:0.75,
+ // | fontSize:"13pt"
+ // | });
+
+ var n = d.byId(node), args = arguments.length, op = (style=="opacity");
+ style = _floatAliases[style] || style;
+ if(args == 3){
+ return op ? d._setOpacity(n, value) : n.style[style] = value; /*Number*/
+ }
+ if(args == 2 && op){
+ return d._getOpacity(n);
+ }
+ var s = gcs(n);
+ if(args == 2 && !d.isString(style)){
+ for(var x in style){
+ d.style(node, x, style[x]);
+ }
+ return s;
+ }
+ return (args == 1) ? s : _toStyleValue(n, style, s[style]); /* CSS2Properties||String||Number */
+ }
+
+ // =============================
+ // Box Functions
+ // =============================
+
+ dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+ // summary:
+ // Returns object with special values specifically useful for node
+ // fitting.
+ //
+ // * l/t = left/top padding (respectively)
+ // * w = the total of the left and right padding
+ // * h = the total of the top and bottom padding
+ //
+ // If 'node' has position, l/t forms the origin for child nodes.
+ // The w/h are used for calculating boxes.
+ // Normally application code will not need to invoke this
+ // directly, and will use the ...box... functions instead.
+ var
+ s = computedStyle||gcs(n),
+ l = px(n, s.paddingLeft),
+ t = px(n, s.paddingTop);
+ return {
+ l: l,
+ t: t,
+ w: l+px(n, s.paddingRight),
+ h: t+px(n, s.paddingBottom)
+ };
+ }
+
+ dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+ // summary:
+ // returns an object with properties useful for noting the border
+ // dimensions.
+ //
+ // * l/t = the sum of left/top border (respectively)
+ // * w = the sum of the left and right border
+ // * h = the sum of the top and bottom border
+ //
+ // The w/h are used for calculating boxes.
+ // Normally application code will not need to invoke this
+ // directly, and will use the ...box... functions instead.
+ var
+ ne = "none",
+ s = computedStyle||gcs(n),
+ bl = (s.borderLeftStyle != ne ? px(n, s.borderLeftWidth) : 0),
+ bt = (s.borderTopStyle != ne ? px(n, s.borderTopWidth) : 0);
+ return {
+ l: bl,
+ t: bt,
+ w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0),
+ h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0)
+ };
+ }
+
+ dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+ // summary:
+ // returns object with properties useful for box fitting with
+ // regards to padding.
+ //
+ // * l/t = the sum of left/top padding and left/top border (respectively)
+ // * w = the sum of the left and right padding and border
+ // * h = the sum of the top and bottom padding and border
+ //
+ // The w/h are used for calculating boxes.
+ // Normally application code will not need to invoke this
+ // directly, and will use the ...box... functions instead.
+ var
+ s = computedStyle||gcs(n),
+ p = d._getPadExtents(n, s),
+ b = d._getBorderExtents(n, s);
+ return {
+ l: p.l + b.l,
+ t: p.t + b.t,
+ w: p.w + b.w,
+ h: p.h + b.h
+ };
+ }
+
+ dojo._getMarginExtents = function(n, computedStyle){
+ // summary:
+ // returns object with properties useful for box fitting with
+ // regards to box margins (i.e., the outer-box).
+ //
+ // * l/t = marginLeft, marginTop, respectively
+ // * w = total width, margin inclusive
+ // * h = total height, margin inclusive
+ //
+ // The w/h are used for calculating boxes.
+ // Normally application code will not need to invoke this
+ // directly, and will use the ...box... functions instead.
+ var
+ s = computedStyle||gcs(n),
+ l = px(n, s.marginLeft),
+ t = px(n, s.marginTop),
+ r = px(n, s.marginRight),
+ b = px(n, s.marginBottom);
+ if(d.isSafari && (s.position != "absolute")){
+ // FIXME: Safari's version of the computed right margin
+ // is the space between our right edge and the right edge
+ // of our offsetParent.
+ // What we are looking for is the actual margin value as
+ // determined by CSS.
+ // Hack solution is to assume left/right margins are the same.
+ r = l;
+ }
+ return {
+ l: l,
+ t: t,
+ w: l+r,
+ h: t+b
+ };
+ }
+
+ // Box getters work in any box context because offsetWidth/clientWidth
+ // are invariant wrt box context
+ //
+ // They do *not* work for display: inline objects that have padding styles
+ // because the user agent ignores padding (it's bogus styling in any case)
+ //
+ // Be careful with IMGs because they are inline or block depending on
+ // browser and browser mode.
+
+ // Although it would be easier to read, there are not separate versions of
+ // _getMarginBox for each browser because:
+ // 1. the branching is not expensive
+ // 2. factoring the shared code wastes cycles (function call overhead)
+ // 3. duplicating the shared code wastes bytes
+
+ dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){
+ // summary:
+ // returns an object that encodes the width, height, left and top
+ // positions of the node's margin box.
+ var s = computedStyle||gcs(node), me = d._getMarginExtents(node, s);
+ var l = node.offsetLeft - me.l, t = node.offsetTop - me.t;
+ if(d.isMoz){
+ // Mozilla:
+ // If offsetParent has a computed overflow != visible, the offsetLeft is decreased
+ // by the parent's border.
+ // We don't want to compute the parent's style, so instead we examine node's
+ // computed left/top which is more stable.
+ var sl = parseFloat(s.left), st = parseFloat(s.top);
+ if(!isNaN(sl) && !isNaN(st)){
+ l = sl, t = st;
+ }else{
+ // If child's computed left/top are not parseable as a number (e.g. "auto"), we
+ // have no choice but to examine the parent's computed style.
+ var p = node.parentNode;
+ if(p && p.style){
+ var pcs = gcs(p);
+ if(pcs.overflow != "visible"){
+ var be = d._getBorderExtents(p, pcs);
+ l += be.l, t += be.t;
+ }
+ }
+ }
+ }else if(d.isOpera){
+ // On Opera, offsetLeft includes the parent's border
+ var p = node.parentNode;
+ if(p){
+ var be = d._getBorderExtents(p);
+ l -= be.l, t -= be.t;
+ }
+ }
+ return {
+ l: l,
+ t: t,
+ w: node.offsetWidth + me.w,
+ h: node.offsetHeight + me.h
+ };
+ }
+
+ dojo._getContentBox = function(node, computedStyle){
+ // summary:
+ // Returns an object that encodes the width, height, left and top
+ // positions of the node's content box, irrespective of the
+ // current box model.
+
+ // clientWidth/Height are important since the automatically account for scrollbars
+ // fallback to offsetWidth/Height for special cases (see #3378)
+ var s=computedStyle||gcs(node), pe=d._getPadExtents(node, s), be=d._getBorderExtents(node, s), w=node.clientWidth, h;
+ if(!w){
+ w=node.offsetWidth, h=node.offsetHeight;
+ }else{
+ h=node.clientHeight, be.w = be.h = 0;
+ }
+ // On Opera, offsetLeft includes the parent's border
+ if(d.isOpera){ pe.l += be.l; pe.t += be.t; };
+ return {
+ l: pe.l,
+ t: pe.t,
+ w: w - pe.w - be.w,
+ h: h - pe.h - be.h
+ };
+ }
+
+ dojo._getBorderBox = function(node, computedStyle){
+ var s=computedStyle||gcs(node), pe=d._getPadExtents(node, s), cb=d._getContentBox(node, s);
+ return {
+ l: cb.l - pe.l,
+ t: cb.t - pe.t,
+ w: cb.w + pe.w,
+ h: cb.h + pe.h
+ };
+ }
+
+ // Box setters depend on box context because interpretation of width/height styles
+ // vary wrt box context.
+ //
+ // The value of dojo.boxModel is used to determine box context.
+ // dojo.boxModel can be set directly to change behavior.
+ //
+ // Beware of display: inline objects that have padding styles
+ // because the user agent ignores padding (it's a bogus setup anyway)
+ //
+ // Be careful with IMGs because they are inline or block depending on
+ // browser and browser mode.
+ //
+ // Elements other than DIV may have special quirks, like built-in
+ // margins or padding, or values not detectable via computedStyle.
+ // In particular, margins on TABLE do not seems to appear
+ // at all in computedStyle on Mozilla.
+
+ dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){
+ // summary:
+ // sets width/height/left/top in the current (native) box-model
+ // dimentions. Uses the unit passed in u.
+ // node: DOM Node reference. Id string not supported for performance reasons.
+ // l: optional. left offset from parent.
+ // t: optional. top offset from parent.
+ // w: optional. width in current box model.
+ // h: optional. width in current box model.
+ // u: optional. unit measure to use for other measures. Defaults to "px".
+ u = u || "px";
+ var s = node.style;
+ if(!isNaN(l)){ s.left = l+u; }
+ if(!isNaN(t)){ s.top = t+u; }
+ if(w>=0){ s.width = w+u; }
+ if(h>=0){ s.height = h+u; }
+ }
+
+ dojo._usesBorderBox = function(/*DomNode*/node){
+ // summary:
+ // True if the node uses border-box layout.
+
+ // We could test the computed style of node to see if a particular box
+ // has been specified, but there are details and we choose not to bother.
+ var n = node.tagName;
+ // For whatever reason, TABLE and BUTTON are always border-box by default.
+ // If you have assigned a different box to either one via CSS then
+ // box functions will break.
+ return d.boxModel=="border-box" || n=="TABLE" || n=="BUTTON"; // boolean
+ }
+
+ dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){
+ // summary:
+ // Sets the size of the node's contents, irrespective of margins,
+ // padding, or borders.
+ if(d._usesBorderBox(node)){
+ var pb = d._getPadBorderExtents(node, computedStyle);
+ if(widthPx >= 0){ widthPx += pb.w; }
+ if(heightPx >= 0){ heightPx += pb.h; }
+ }
+ d._setBox(node, NaN, NaN, widthPx, heightPx);
+ }
+
+ dojo._setMarginBox = function(/*DomNode*/node, /*Number?*/leftPx, /*Number?*/topPx,
+ /*Number?*/widthPx, /*Number?*/heightPx,
+ /*Object*/computedStyle){
+ // summary:
+ // sets the size of the node's margin box and placement
+ // (left/top), irrespective of box model. Think of it as a
+ // passthrough to dojo._setBox that handles box-model vagaries for
+ // you.
+
+ var s = computedStyle||gcs(node);
+ // Some elements have special padding, margin, and box-model settings.
+ // To use box functions you may need to set padding, margin explicitly.
+ // Controlling box-model is harder, in a pinch you might set dojo.boxModel.
+ var bb=d._usesBorderBox(node),
+ pb=bb ? _nilExtents : d._getPadBorderExtents(node, s),
+ mb=d._getMarginExtents(node, s);
+ if(widthPx>=0){ widthPx = Math.max(widthPx - pb.w - mb.w, 0); }
+ if(heightPx>=0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); }
+ d._setBox(node, leftPx, topPx, widthPx, heightPx);
+ }
+
+ var _nilExtents = { l:0, t:0, w:0, h:0 };
+
+ // public API
+
+ dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){
+ // summary:
+ // Getter/setter for the margin-box of node.
+ // description:
+ // Returns an object in the expected format of box (regardless
+ // if box is passed). The object might look like:
+ // `{ l: 50, t: 200, w: 300: h: 150 }`
+ // for a node offset from its parent 50px to the left, 200px from
+ // the top with a margin width of 300px and a margin-height of
+ // 150px.
+ // node:
+ // id or reference to DOM Node to get/set box for
+ // box:
+ // If passed, denotes that dojo.marginBox() should
+ // update/set the margin box for node. Box is an object in the
+ // above format. All properties are optional if passed.
+ var n=d.byId(node), s=gcs(n), b=box;
+ return !b ? d._getMarginBox(n, s) : d._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object
+ }
+
+ dojo.contentBox = function(/*DomNode|String*/node, /*Object?*/box){
+ // summary:
+ // Getter/setter for the content-box of node.
+ // description:
+ // Returns an object in the expected format of box (regardless if box is passed).
+ // The object might look like:
+ // `{ l: 50, t: 200, w: 300: h: 150 }`
+ // for a node offset from its parent 50px to the left, 200px from
+ // the top with a content width of 300px and a content-height of
+ // 150px. Note that the content box may have a much larger border
+ // or margin box, depending on the box model currently in use and
+ // CSS values set/inherited for node.
+ // node:
+ // id or reference to DOM Node to get/set box for
+ // box:
+ // If passed, denotes that dojo.contentBox() should
+ // update/set the content box for node. Box is an object in the
+ // above format. All properties are optional if passed.
+ var n=dojo.byId(node), s=gcs(n), b=box;
+ return !b ? d._getContentBox(n, s) : d._setContentSize(n, b.w, b.h, s); // Object
+ }
+
+ // =============================
+ // Positioning
+ // =============================
+
+ var _sumAncestorProperties = function(node, prop){
+ if(!(node = (node||0).parentNode)){return 0};
+ var val, retVal = 0, _b = d.body();
+ while(node && node.style){
+ if(gcs(node).position == "fixed"){
+ return 0;
+ }
+ val = node[prop];
+ if(val){
+ retVal += val - 0;
+ // opera and khtml #body & #html has the same values, we only
+ // need one value
+ if(node == _b){ break; }
+ }
+ node = node.parentNode;
+ }
+ return retVal; // integer
+ }
+
+ dojo._docScroll = function(){
+ var
+ _b = d.body(),
+ _w = d.global,
+ de = d.doc.documentElement;
+ return {
+ y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0),
+ x: (_w.pageXOffset || d._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0)
+ };
+ };
+
+ dojo._isBodyLtr = function(){
+ //FIXME: could check html and body tags directly instead of computed style? need to ignore case, accept empty values
+ return !("_bodyLtr" in d) ?
+ d._bodyLtr = gcs(d.body()).direction == "ltr" :
+ d._bodyLtr; // Boolean
+ }
+
+ dojo._getIeDocumentElementOffset = function(){
+ // summary
+ // The following values in IE contain an offset:
+ // event.clientX
+ // event.clientY
+ // node.getBoundingClientRect().left
+ // node.getBoundingClientRect().top
+ // But other position related values do not contain this offset, such as
+ // node.offsetLeft, node.offsetTop, node.style.left and node.style.top.
+ // The offset is always (2, 2) in LTR direction. When the body is in RTL
+ // direction, the offset counts the width of left scroll bar's width.
+ // This function computes the actual offset.
+
+ //NOTE: assumes we're being called in an IE browser
+
+ var de = d.doc.documentElement;
+ //FIXME: use this instead? var de = d.compatMode == "BackCompat" ? d.body : d.documentElement;
+
+ return (d.isIE >= 7) ?
+ {x: de.getBoundingClientRect().left, y: de.getBoundingClientRect().top}
+ :
+ // IE 6.0
+ {x: d._isBodyLtr() || window.parent == window ?
+ de.clientLeft : de.offsetWidth - de.clientWidth - de.clientLeft,
+ y: de.clientTop}; // Object
+ };
+
+ dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){
+ // In RTL direction, scrollLeft should be a negative value, but IE
+ // returns a positive one. All codes using documentElement.scrollLeft
+ // must call this function to fix this error, otherwise the position
+ // will offset to right when there is a horizontal scrollbar.
+ var dd = d.doc;
+ if(d.isIE && !dojo._isBodyLtr()){
+ var de = dd.compatMode == "BackCompat" ? dd.body : dd.documentElement;
+ return scrollLeft + de.clientWidth - de.scrollWidth; // Integer
+ }
+ return scrollLeft; // Integer
+ }
+
+ dojo._abs = function(/*DomNode*/node, /*Boolean?*/includeScroll){
+ // summary:
+ // Gets the position of the passed element relative to
+ // the viewport (if includeScroll==false), or relative to the
+ // document root (if includeScroll==true).
+ //
+ // Returns an object of the form:
+ // { x: 100, y: 300 }
+ // if includeScroll is passed, the x and y values will include any
+ // document offsets that may affect the position relative to the
+ // viewport.
+
+ // FIXME: need to decide in the brave-new-world if we're going to be
+ // margin-box or border-box.
+ var ownerDocument = node.ownerDocument;
+ var ret = {
+ x: 0,
+ y: 0
+ };
+
+ // targetBoxType == "border-box"
+ var db = d.body();
+ if(d.isIE || (d.isFF >= 3)){
+ var client = node.getBoundingClientRect();
+ var offset = (d.isIE) ? d._getIeDocumentElementOffset() : { x: 0, y: 0};
+ ret.x = client.left - offset.x;
+ ret.y = client.top - offset.y;
+ }else if(ownerDocument["getBoxObjectFor"]){
+ // mozilla
+ var bo = ownerDocument.getBoxObjectFor(node),
+ b = d._getBorderExtents(node);
+ ret.x = bo.x - b.l - _sumAncestorProperties(node, "scrollLeft");
+ ret.y = bo.y - b.t - _sumAncestorProperties(node, "scrollTop");
+ }else{
+ if(node["offsetParent"]){
+ var endNode;
+ // in Safari, if the node is an absolutely positioned child of
+ // the body and the body has a margin the offset of the child
+ // and the body contain the body's margins, so we need to end
+ // at the body
+ // FIXME: getting contrary results to the above in latest WebKit.
+ if(d.isSafari &&
+ //(node.style.getPropertyValue("position") == "absolute") &&
+ (gcs(node).position == "absolute") &&
+ (node.parentNode == db)){
+ endNode = db;
+ }else{
+ endNode = db.parentNode;
+ }
+ if(node.parentNode != db){
+ var nd = node;
+ if(d.isOpera){ nd = db; }
+ ret.x -= _sumAncestorProperties(nd, "scrollLeft");
+ ret.y -= _sumAncestorProperties(nd, "scrollTop");
+ }
+ var curnode = node;
+ do{
+ var n = curnode.offsetLeft;
+ //FIXME: ugly hack to workaround the submenu in
+ //popupmenu2 does not shown up correctly in opera.
+ //Someone have a better workaround?
+ if(!d.isOpera || n > 0){
+ ret.x += isNaN(n) ? 0 : n;
+ }
+ var t = curnode.offsetTop;
+ ret.y += isNaN(t) ? 0 : t;
+ if(d.isSafari && curnode != node){
+ var cs = gcs(curnode);
+ ret.x += px(curnode, cs.borderLeftWidth);
+ ret.y += px(curnode, cs.borderTopWidth);
+ }
+ curnode = curnode.offsetParent;
+ }while((curnode != endNode) && curnode);
+ }else if(node.x && node.y){
+ ret.x += isNaN(node.x) ? 0 : node.x;
+ ret.y += isNaN(node.y) ? 0 : node.y;
+ }
+ }
+ // account for document scrolling
+ // if offsetParent is used, ret value already includes scroll position
+ // so we may have to actually remove that value if !includeScroll
+ if(includeScroll){
+ var scroll = d._docScroll();
+ ret.y += scroll.y;
+ ret.x += scroll.x;
+ }
+
+ return ret; // object
+ }
+
+ // FIXME: need a setter for coords or a moveTo!!
+ dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){
+ // summary:
+ // Returns an object that measures margin box width/height and
+ // absolute positioning data from dojo._abs().
+ //
+ // description:
+ // Returns an object that measures margin box width/height and
+ // absolute positioning data from dojo._abs().
+ // Return value will be in the form:
+ // `{ l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }`
+ // Does not act as a setter. If includeScroll is passed, the x and
+ // y params are affected as one would expect in dojo._abs().
+ var n=d.byId(node), s=gcs(n), mb=d._getMarginBox(n, s);
+ var abs = d._abs(n, includeScroll);
+ mb.x = abs.x;
+ mb.y = abs.y;
+ return mb;
+ }
+
+ // =============================
+ // Element attribute Functions
+ // =============================
+
+ var _fixAttrName = function(/*String*/name){
+ switch(name.toLowerCase()){
+ case "tabindex":
+ // Internet Explorer will only set or remove tabindex
+ // if it is spelled "tabIndex"
+ // console.debug((dojo.isIE && dojo.isIE < 8)? "tabIndex" : "tabindex");
+ return (d.isIE && d.isIE < 8) ? "tabIndex" : "tabindex";
+ default:
+ return name;
+ }
+ }
+
+ // non-deprecated HTML4 attributes with default values
+ // http://www.w3.org/TR/html401/index/attributes.html
+ // FF and Safari will return the default values if you
+ // access the attributes via a property but not
+ // via getAttribute()
+ var _attrProps = {
+ colspan: "colSpan",
+ enctype: "enctype",
+ frameborder: "frameborder",
+ method: "method",
+ rowspan: "rowSpan",
+ scrolling: "scrolling",
+ shape: "shape",
+ span: "span",
+ type: "type",
+ valuetype: "valueType"
+ }
+
+ dojo.hasAttr = function(/*DomNode|String*/node, /*String*/name){
+ // summary:
+ // Returns true if the requested attribute is specified on the
+ // given element, and false otherwise.
+ // node:
+ // id or reference to the element to check
+ // name:
+ // the name of the attribute
+ // returns:
+ // true if the requested attribute is specified on the
+ // given element, and false otherwise
+ var attr = d.byId(node).getAttributeNode(_fixAttrName(name));
+ return attr ? attr.specified : false; // Boolean
+ }
+
+ var _evtHdlrMap = {
+
+ }
+
+ var _ctr = 0;
+ var _attrId = dojo._scopeName + "attrid";
+
+ dojo.attr = function(/*DomNode|String*/node, /*String|Object*/name, /*String?*/value){
+ // summary:
+ // Gets or sets an attribute on an HTML element.
+ // description:
+ // Handles normalized getting and setting of attributes on DOM
+ // Nodes. If 2 arguments are passed, and a the second argumnt is a
+ // string, acts as a getter.
+ //
+ // If a third argument is passed, or if the second argumnt is a
+ // map of attributes, acts as a setter.
+ //
+ // When passing functions as values, note that they will not be
+ // directly assigned to slots on the node, but rather the default
+ // behavior will be removed and the new behavior will be added
+ // using `dojo.connect()`, meaning that event handler properties
+ // will be normalized and that some caveats with regards to
+ // non-standard behaviors for onsubmit apply. Namely that you
+ // should cancel form submission using `dojo.stopEvent()` on the
+ // passed event object instead of returning a boolean value from
+ // the handler itself.
+ // node:
+ // id or reference to the element to get or set the attribute on
+ // name:
+ // the name of the attribute to get or set.
+ // value:
+ // The value to set for the attribute
+ // returns:
+ // when used as a getter, the value of the requested attribute
+ // or null if that attribute does not have a specified or
+ // default value;
+ //
+ // when user as a setter, undefined
+ // example:
+ // | // get the current value of the "foo" attribute on a node
+ // | dojo.attr(dojo.byId("nodeId"), "foo");
+ // |
+ // | // we can just pass the id:
+ // | dojo.attr("nodeId", "foo");
+ // |
+ // | // use attr() to set the tab index
+ // | dojo.attr("nodeId", "tabindex", 3);
+ // |
+ // | // set multiple values at once, including event handlers:
+ // | dojo.attr("formId", {
+ // | "foo": "bar",
+ // | "tabindex": -1,
+ // | "method": "POST",
+ // | "onsubmit": function(e){
+ // | // stop submitting the form. Note that the IE behavior
+ // | // of returning true or false will have no effect here
+ // | // since our handler is connect()ed to the built-in
+ // | // onsubmit behavior and so we need to use
+ // | // dojo.stopEvent() to ensure that the submission
+ // | // doesn't proceed.
+ // | dojo.stopEvent(e);
+ // |
+ // | // submit the form with Ajax
+ // | dojo.xhrPost({ form: "formId" });
+ // | }
+ // | });
+
+ var args = arguments.length;
+ if(args == 2 && !d.isString(name)){
+ for(var x in name){ d.attr(node, x, name[x]); }
+ return;
+ }
+ node = d.byId(node);
+ name = _fixAttrName(name);
+ if(args == 3){
+ if(d.isFunction(value)){
+ // clobber if we can
+ var attrId = d.attr(node, _attrId);
+ if(!attrId){
+ attrId = _ctr++;
+ d.attr(node, _attrId, attrId);
+ }
+ if(!_evtHdlrMap[attrId]){
+ _evtHdlrMap[attrId] = {};
+ }
+ var h = _evtHdlrMap[attrId][name];
+ if(h){
+ d.disconnect(h);
+ }else{
+ try{
+ delete node[name];
+ }catch(e){}
+ }
+
+ // ensure that event objects are normalized, etc.
+ _evtHdlrMap[attrId][name] = d.connect(node, name, value);
+
+ }else if(typeof value == "boolean"){ // e.g. onsubmit, disabled
+ // if a function, we should normalize the event object here!!!
+ node[name] = value;
+ }else{
+ node.setAttribute(name, value);
+ }
+ return;
+ }else{
+ // should we access this attribute via a property or
+ // via getAttribute()?
+ var prop = _attrProps[name.toLowerCase()];
+ if(prop){
+ return node[prop];
+ }else{
+ var value = node[name];
+ return (typeof value == 'boolean' || typeof value == 'function') ? value : (d.hasAttr(node, name) ? node.getAttribute(name) : null);
+ }
+ }
+ }
+
+ dojo.removeAttr = function(/*DomNode|String*/node, /*String*/name){
+ // summary:
+ // Removes an attribute from an HTML element.
+ // node:
+ // id or reference to the element to remove the attribute from
+ // name:
+ // the name of the attribute to remove
+ d.byId(node).removeAttribute(_fixAttrName(name));
+ }
+})();
+
+// =============================
+// (CSS) Class Functions
+// =============================
+
+dojo.hasClass = function(/*DomNode|String*/node, /*String*/classStr){
+ // summary:
+ // Returns whether or not the specified classes are a portion of the
+ // class list currently applied to the node.
+ return ((" "+dojo.byId(node).className+" ").indexOf(" "+classStr+" ") >= 0); // Boolean
+};
+
+dojo.addClass = function(/*DomNode|String*/node, /*String*/classStr){
+ // summary:
+ // Adds the specified classes to the end of the class list on the
+ // passed node.
+ node = dojo.byId(node);
+ var cls = node.className;
+ if((" "+cls+" ").indexOf(" "+classStr+" ") < 0){
+ node.className = cls + (cls ? ' ' : '') + classStr;
+ }
+};
+
+dojo.removeClass = function(/*DomNode|String*/node, /*String*/classStr){
+ // summary: Removes the specified classes from node.
+ node = dojo.byId(node);
+ var t = dojo.trim((" " + node.className + " ").replace(" " + classStr + " ", " "));
+ if(node.className != t){ node.className = t; }
+};
+
+dojo.toggleClass = function(/*DomNode|String*/node, /*String*/classStr, /*Boolean?*/condition){
+ // summary:
+ // Adds a class to node if not present, or removes if present.
+ // Pass a boolean condition if you want to explicitly add or remove.
+ // condition:
+ // If passed, true means to add the class, false means to remove.
+ if(condition === undefined){
+ condition = !dojo.hasClass(node, classStr);
+ }
+ dojo[condition ? "addClass" : "removeClass"](node, classStr);
+};
+
+}
+
+if(!dojo._hasResource["dojo._base.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.NodeList"] = true;
+dojo.provide("dojo._base.NodeList");
+
+
+
+(function(){
+
+ var d = dojo;
+
+ var tnl = function(arr){
+ // decorate an array to make it look like a NodeList
+ arr.constructor = dojo.NodeList;
+ dojo._mixin(arr, dojo.NodeList.prototype);
+ return arr;
+ }
+
+ var _mapIntoDojo = function(func, alwaysThis){
+ // returns a function which, when executed in the scope of its caller,
+ // applies the passed arguments to a particular dojo.* function (named
+ // in func) and aggregates the returns. if alwaysThis is true, it
+ // always returns the scope object and not the collected returns from
+ // the Dojo method
+ return function(){
+ var _a = arguments;
+ var aa = d._toArray(_a, 0, [null]);
+ var s = this.map(function(i){
+ aa[0] = i;
+ return d[func].apply(d, aa);
+ });
+ return (alwaysThis || ( (_a.length > 1) || !d.isString(_a[0]) )) ? this : s; // String||dojo.NodeList
+ }
+ };
+
+ dojo.NodeList = function(){
+ // summary:
+ // dojo.NodeList is as subclass of Array which adds syntactic
+ // sugar for chaining, common iteration operations, animation,
+ // and node manipulation. NodeLists are most often returned as
+ // the result of dojo.query() calls.
+ // example:
+ // create a node list from a node
+ // | new dojo.NodeList(dojo.byId("foo"));
+
+ return tnl(Array.apply(null, arguments));
+ }
+
+ dojo.NodeList._wrap = tnl;
+
+ dojo.extend(dojo.NodeList, {
+ // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
+
+ // FIXME: handle return values for #3244
+ // http://trac.dojotoolkit.org/ticket/3244
+
+ // FIXME:
+ // need to wrap or implement:
+ // join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
+ // reduce
+ // reduceRight
+
+ slice: function(/*===== begin, end =====*/){
+ // summary:
+ // Returns a new NodeList, maintaining this one in place
+ // description:
+ // This method behaves exactly like the Array.slice method
+ // with the caveat that it returns a dojo.NodeList and not a
+ // raw Array. For more details, see:
+ // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice
+ // begin: Integer
+ // Can be a positive or negative integer, with positive
+ // integers noting the offset to begin at, and negative
+ // integers denoting an offset from the end (i.e., to the left
+ // of the end)
+ // end: Integer?
+ // Optional parameter to describe what position relative to
+ // the NodeList's zero index to end the slice at. Like begin,
+ // can be positive or negative.
+ var a = dojo._toArray(arguments);
+ return tnl(a.slice.apply(this, a));
+ },
+
+ splice: function(/*===== index, howmany, item =====*/){
+ // summary:
+ // Returns a new NodeList, manipulating this NodeList based on
+ // the arguments passed, potentially splicing in new elements
+ // at an offset, optionally deleting elements
+ // description:
+ // This method behaves exactly like the Array.splice method
+ // with the caveat that it returns a dojo.NodeList and not a
+ // raw Array. For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice>
+ // index: Integer
+ // begin can be a positive or negative integer, with positive
+ // integers noting the offset to begin at, and negative
+ // integers denoting an offset from the end (i.e., to the left
+ // of the end)
+ // howmany: Integer?
+ // Optional parameter to describe what position relative to
+ // the NodeList's zero index to end the slice at. Like begin,
+ // can be positive or negative.
+ // item: Object...?
+ // Any number of optional parameters may be passed in to be
+ // spliced into the NodeList
+ // returns:
+ // dojo.NodeList
+ var a = dojo._toArray(arguments);
+ return tnl(a.splice.apply(this, a));
+ },
+
+ concat: function(/*===== item =====*/){
+ // summary:
+ // Returns a new NodeList comprised of items in this NodeList
+ // as well as items passed in as parameters
+ // description:
+ // This method behaves exactly like the Array.concat method
+ // with the caveat that it returns a dojo.NodeList and not a
+ // raw Array. For more details, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat>
+ // item: Object...?
+ // Any number of optional parameters may be passed in to be
+ // spliced into the NodeList
+ // returns:
+ // dojo.NodeList
+ var a = dojo._toArray(arguments, 0, [this]);
+ return tnl(a.concat.apply([], a));
+ },
+
+ indexOf: function(/*Object*/ value, /*Integer?*/ fromIndex){
+ // summary:
+ // see dojo.indexOf(). The primary difference is that the acted-on
+ // array is implicitly this NodeList
+ // value:
+ // The value to search for.
+ // fromIndex:
+ // The loction to start searching from. Optional. Defaults to 0.
+ // description:
+ // For more details on the behavior of indexOf, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
+ // returns:
+ // Positive Integer or 0 for a match, -1 of not found.
+ return d.indexOf(this, value, fromIndex); // Integer
+ },
+
+ lastIndexOf: function(/*===== value, fromIndex =====*/){
+ // summary:
+ // see dojo.lastIndexOf(). The primary difference is that the
+ // acted-on array is implicitly this NodeList
+ // description:
+ // For more details on the behavior of lastIndexOf, see:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf>
+ // value: Object
+ // The value to search for.
+ // fromIndex: Integer?
+ // The loction to start searching from. Optional. Defaults to 0.
+ // returns:
+ // Positive Integer or 0 for a match, -1 of not found.
+ return d.lastIndexOf.apply(d, d._toArray(arguments, 0, [this])); // Integer
+ },
+
+ every: function(/*Function*/callback, /*Object?*/thisObject){
+ // summary:
+ // see `dojo.every()` and:
+ // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
+ // Takes the same structure of arguments and returns as
+ // dojo.every() with the caveat that the passed array is
+ // implicitly this NodeList
+ return d.every(this, callback, thisObject); // Boolean
+ },
+
+ some: function(/*Function*/callback, /*Object?*/thisObject){
+ // summary:
+ // see dojo.some() and:
+ // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some
+ // Takes the same structure of arguments and returns as
+ // dojo.some() with the caveat that the passed array is
+ // implicitly this NodeList
+ return d.some(this, callback, thisObject); // Boolean
+ },
+
+ map: function(/*Function*/ func, /*Function?*/ obj){
+ // summary:
+ // see dojo.map(). The primary difference is that the acted-on
+ // array is implicitly this NodeList and the return is a
+ // dojo.NodeList (a subclass of Array)
+
+ return d.map(this, func, obj, d.NodeList); // dojo.NodeList
+ },
+
+ forEach: function(callback, thisObj){
+ // summary:
+ // see dojo.forEach(). The primary difference is that the acted-on
+ // array is implicitly this NodeList
+
+ d.forEach(this, callback, thisObj);
+ // non-standard return to allow easier chaining
+ return this; // dojo.NodeList
+ },
+
+ // custom methods
+
+ coords: function(){
+ // summary:
+ // Returns the box objects all elements in a node list as
+ // an Array (*not* a NodeList)
+
+ return d.map(this, d.coords); // Array
+ },
+
+ /*=====
+ attr: function(property, value){
+ // summary:
+ // gets or sets the DOM attribute for every element in the
+ // NodeList
+ // property: String
+ // the attribute to get/set
+ // value: String?
+ // optional. The value to set the property to
+ // return:
+ // if no value is passed, the result is an array of attribute values
+ // If a value is passed, the return is this NodeList
+ },
+
+ style: function(property, value){
+ // summary:
+ // gets or sets the CSS property for every element in the NodeList
+ // property: String
+ // the CSS property to get/set, in JavaScript notation
+ // ("lineHieght" instead of "line-height")
+ // value: String?
+ // optional. The value to set the property to
+ // return:
+ // if no value is passed, the result is an array of strings.
+ // If a value is passed, the return is this NodeList
+ },
+
+ addClass: function(className){
+ // summary:
+ // adds the specified class to every node in the list
+ // className: String
+ // the CSS class to add
+ // return:
+ // dojo.NodeList, this list
+ },
+
+ removeClass: function(className){
+ // summary:
+ // removes the specified class from every node in the list
+ // className: String
+ // the CSS class to add
+ // return:
+ // dojo.NodeList, this list
+ },
+
+ toggleClass: function(className, condition){
+ // summary:
+ // Adds a class to node if not present, or removes if present.
+ // Pass a boolean condition if you want to explicitly add or remove.
+ // condition: Boolean?
+ // If passed, true means to add the class, false means to remove.
+ // className: String
+ // the CSS class to add
+ // return: dojo.NodeList
+ // this list
+ },
+
+ connect: function(methodName, objOrFunc, funcName){
+ // summary:
+ // attach event handlers to every item of the NodeList. Uses dojo.connect()
+ // so event properties are normalized
+ // methodName: String
+ // the name of the method to attach to. For DOM events, this should be
+ // the lower-case name of the event
+ // objOrFunc: Object|Function|String
+ // if 2 arguments are passed (methodName, objOrFunc), objOrFunc should
+ // reference a function or be the name of the function in the global
+ // namespace to attach. If 3 arguments are provided
+ // (methodName, objOrFunc, funcName), objOrFunc must be the scope to
+ // locate the bound function in
+ // funcName: String?
+ // optional. A string naming the function in objOrFunc to bind to the
+ // event. May also be a function reference.
+ // example:
+ // add an onclick handler to every button on the page
+ // | dojo.query("div:nth-child(odd)").connect("onclick", function(e){
+ // | console.debug("clicked!");
+ // | });
+ // example:
+ // attach foo.bar() to every odd div's onmouseover
+ // | dojo.query("div:nth-child(odd)").connect("onmouseover", foo, "bar");
+ },
+ =====*/
+ attr: _mapIntoDojo("attr"),
+ style: _mapIntoDojo("style"),
+ addClass: _mapIntoDojo("addClass", true),
+ removeClass: _mapIntoDojo("removeClass", true),
+ toggleClass: _mapIntoDojo("toggleClass", true),
+ connect: _mapIntoDojo("connect", true),
+
+ // FIXME: connectPublisher()? connectRunOnce()?
+
+ place: function(/*String||Node*/ queryOrNode, /*String*/ position){
+ // summary:
+ // places elements of this node list relative to the first element matched
+ // by queryOrNode. Returns the original NodeList.
+ // queryOrNode:
+ // may be a string representing any valid CSS3 selector or a DOM node.
+ // In the selector case, only the first matching element will be used
+ // for relative positioning.
+ // position:
+ // can be one of:
+ // * "last"||"end" (default)
+ // * "first||"start"
+ // * "before"
+ // * "after"
+ // or an offset in the childNodes property
+ var item = d.query(queryOrNode)[0];
+ return this.forEach(function(i){ d.place(i, item, (position||"last")); }); // dojo.NodeList
+ },
+
+ orphan: function(/*String?*/ simpleFilter){
+ // summary:
+ // removes elements in this list that match the simple
+ // filter from their parents and returns them as a new
+ // NodeList.
+ // simpleFilter:
+ // single-expression CSS filter
+ // return:
+ // `dojo.NodeList` the orpahned elements
+ var orphans = simpleFilter ? d._filterQueryResult(this, simpleFilter) : this;
+ orphans.forEach(function(item){
+ if(item.parentNode){
+ item.parentNode.removeChild(item);
+ }
+ });
+ return orphans; // dojo.NodeList
+ },
+
+ adopt: function(/*String||Array||DomNode*/ queryOrListOrNode, /*String?*/ position){
+ // summary:
+ // places any/all elements in queryOrListOrNode at a
+ // position relative to the first element in this list.
+ // Returns a dojo.NodeList of the adopted elements.
+ // queryOrListOrNode:
+ // a DOM node or a query string or a query result.
+ // Represents the nodes to be adopted relative to the
+ // first element of this NodeList.
+ // position:
+ // can be one of:
+ // * "last"||"end" (default)
+ // * "first||"start"
+ // * "before"
+ // * "after"
+ // or an offset in the childNodes property
+ var item = this[0];
+ return d.query(queryOrListOrNode).forEach(function(ai){ d.place(ai, item, position || "last"); }); // dojo.NodeList
+ },
+
+ // FIXME: do we need this?
+ query: function(/*String*/ queryStr){
+ // summary:
+ // Returns a new, flattened NodeList. Elements of the new list
+ // satisfy the passed query but use elements of the
+ // current NodeList as query roots.
+
+ if(!queryStr){ return this; }
+
+ // FIXME: probably slow
+ // FIXME: use map?
+ var ret = d.NodeList();
+ this.forEach(function(item){
+ d.query(queryStr, item).forEach(function(subItem){
+ if(subItem !== undefined){
+ ret.push(subItem);
+ }
+ });
+ });
+ return ret; // dojo.NodeList
+ },
+
+ filter: function(/*String*/ simpleQuery){
+ // summary:
+ // "masks" the built-in javascript filter() method to support
+ // passing a simple string filter in addition to supporting
+ // filtering function objects.
+ // example:
+ // "regular" JS filter syntax as exposed in dojo.filter:
+ // | dojo.query("*").filter(function(item){
+ // | // highlight every paragraph
+ // | return (item.nodeName == "p");
+ // | }).styles("backgroundColor", "yellow");
+ // example:
+ // the same filtering using a CSS selector
+ // | dojo.query("*").filter("p").styles("backgroundColor", "yellow");
+
+ var items = this;
+ var _a = arguments;
+ var r = d.NodeList();
+ var rp = function(t){
+ if(t !== undefined){
+ r.push(t);
+ }
+ }
+ if(d.isString(simpleQuery)){
+ items = d._filterQueryResult(this, _a[0]);
+ if(_a.length == 1){
+ // if we only got a string query, pass back the filtered results
+ return items; // dojo.NodeList
+ }
+ // if we got a callback, run it over the filtered items
+ _a.shift();
+ }
+ // handle the (callback, [thisObject]) case
+ d.forEach(d.filter(items, _a[0], _a[1]), rp);
+ return r; // dojo.NodeList
+ },
+
+ /*
+ // FIXME: should this be "copyTo" and include parenting info?
+ clone: function(){
+ // summary:
+ // creates node clones of each element of this list
+ // and returns a new list containing the clones
+ },
+ */
+
+ addContent: function(/*String*/ content, /*String||Integer?*/ position){
+ // summary:
+ // add a node or some HTML as a string to every item in the list.
+ // Returns the original list.
+ // description:
+ // a copy of the HTML content is added to each item in the
+ // list, with an optional position argument. If no position
+ // argument is provided, the content is appended to the end of
+ // each item.
+ // content:
+ // the HTML in string format to add at position to every item
+ // position:
+ // can be one of:
+ // * "last"||"end" (default)
+ // * "first||"start"
+ // * "before"
+ // * "after"
+ // or an offset in the childNodes property
+ // example:
+ // appends content to the end if the position is ommitted
+ // | dojo.query("h3 > p").addContent("hey there!");
+ // example:
+ // add something to the front of each element that has a "thinger" property:
+ // | dojo.query("[thinger]").addContent("...", "first");
+ // example:
+ // adds a header before each element of the list
+ // | dojo.query(".note").addContent("<h4>NOTE:</h4>", "before");
+ var ta = d.doc.createElement("span");
+ if(d.isString(content)){
+ ta.innerHTML = content;
+ }else{
+ ta.appendChild(content);
+ }
+ if(position === undefined){
+ position = "last";
+ }
+ var ct = (position == "first" || position == "after") ? "lastChild" : "firstChild";
+ this.forEach(function(item){
+ var tn = ta.cloneNode(true);
+ while(tn[ct]){
+ d.place(tn[ct], item, position);
+ }
+ });
+ return this; // dojo.NodeList
+ },
+
+ empty: function(){
+ // summary:
+ // clears all content from each node in the list
+ return this.forEach("item.innerHTML='';"); // dojo.NodeList
+
+ // FIXME: should we be checking for and/or disposing of widgets below these nodes?
+ },
+
+ instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){
+ // summary:
+ // Create a new instance of a specified class, using the
+ // specified properties and each node in the nodeList as a
+ // srcNodeRef
+ //
+ var c = d.isFunction(declaredClass) ? declaredClass : d.getObject(declaredClass);
+ return this.forEach(function(i){
+ new c(properties||{},i);
+ }) // dojo.NodeList
+ }
+
+ });
+
+ // syntactic sugar for DOM events
+ d.forEach([
+ "blur", "focus", "click", "keydown", "keypress", "keyup", "mousedown",
+ "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover",
+ "mouseup"
+ ], function(evt){
+ var _oe = "on"+evt;
+ dojo.NodeList.prototype[_oe] = function(a, b){
+ return this.connect(_oe, a, b);
+ }
+ // FIXME: should these events trigger publishes?
+ /*
+ return (a ? this.connect(_oe, a, b) :
+ this.forEach(function(n){
+ // FIXME:
+ // listeners get buried by
+ // addEventListener and can't be dug back
+ // out to be triggered externally.
+ // see:
+ // http://developer.mozilla.org/en/docs/DOM:element
+
+ console.debug(n, evt, _oe);
+
+ // FIXME: need synthetic event support!
+ var _e = { target: n, faux: true, type: evt };
+ // dojo._event_listener._synthesizeEvent({}, { target: n, faux: true, type: evt });
+ try{ n[evt](_e); }catch(e){ console.debug(e); }
+ try{ n[_oe](_e); }catch(e){ console.debug(e); }
+ })
+ );
+ }
+ */
+ }
+ );
+
+})();
+
+}
+
+if(!dojo._hasResource["dojo._base.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.query"] = true;
+dojo.provide("dojo._base.query");
+
+
+/*
+ dojo.query() architectural overview:
+
+ dojo.query is a relatively full-featured CSS3 query library. It is
+ designed to take any valid CSS3 selector and return the nodes matching
+ the selector. To do this quickly, it processes queries in several
+ steps, applying caching where profitable.
+
+ The steps (roughly in reverse order of the way they appear in the code):
+ 1.) check to see if we already have a "query dispatcher"
+ - if so, use that with the given parameterization. Skip to step 4.
+ 2.) attempt to determine which branch to dispatch the query to:
+ - JS (optimized DOM iteration)
+ - xpath (for browsers that support it and where it's fast)
+ - native (not available in any browser yet)
+ 3.) tokenize and convert to executable "query dispatcher"
+ - this is where the lion's share of the complexity in the
+ system lies. In the DOM version, the query dispatcher is
+ assembled as a chain of "yes/no" test functions pertaining to
+ a section of a simple query statement (".blah:nth-child(odd)"
+ but not "div div", which is 2 simple statements). Individual
+ statement dispatchers are cached (to prevent re-definition)
+ as are entire dispatch chains (to make re-execution of the
+ same query fast)
+ - in the xpath path, tokenization yeilds a concatenation of
+ parameterized xpath selectors. As with the DOM version, both
+ simple selector blocks and overall evaluators are cached to
+ prevent re-defintion
+ 4.) the resulting query dispatcher is called in the passed scope (by default the top-level document)
+ - for DOM queries, this results in a recursive, top-down
+ evaluation of nodes based on each simple query section
+ - xpath queries can, thankfully, be executed in one shot
+ 5.) matched nodes are pruned to ensure they are unique
+*/
+
+;(function(){
+ // define everything in a closure for compressability reasons. "d" is an
+ // alias to "dojo" since it's so frequently used. This seems a
+ // transformation that the build system could perform on a per-file basis.
+
+ ////////////////////////////////////////////////////////////////////////
+ // Utility code
+ ////////////////////////////////////////////////////////////////////////
+
+ var d = dojo;
+ var childNodesName = dojo.isIE ? "children" : "childNodes";
+ var caseSensitive = false;
+
+ var getQueryParts = function(query){
+ // summary: state machine for query tokenization
+ if(">~+".indexOf(query.charAt(query.length-1)) >= 0){
+ query += " *"
+ }
+ query += " "; // ensure that we terminate the state machine
+
+ var ts = function(s, e){
+ return d.trim(query.slice(s, e));
+ }
+
+ // the overall data graph of the full query, as represented by queryPart objects
+ var qparts = [];
+ // state keeping vars
+ var inBrackets = -1;
+ var inParens = -1;
+ var inMatchFor = -1;
+ var inPseudo = -1;
+ var inClass = -1;
+ var inId = -1;
+ var inTag = -1;
+ var lc = ""; // the last character
+ var cc = ""; // the current character
+ var pStart;
+ // iteration vars
+ var x = 0; // index in the query
+ var ql = query.length;
+ var currentPart = null; // data structure representing the entire clause
+ var _cp = null; // the current pseudo or attr matcher
+
+ var endTag = function(){
+ if(inTag >= 0){
+ var tv = (inTag == x) ? null : ts(inTag, x).toLowerCase();
+ currentPart[ (">~+".indexOf(tv) < 0) ? "tag" : "oper" ] = tv;
+ inTag = -1;
+ }
+ }
+
+ var endId = function(){
+ if(inId >= 0){
+ currentPart.id = ts(inId, x).replace(/\\/g, "");
+ inId = -1;
+ }
+ }
+
+ var endClass = function(){
+ if(inClass >= 0){
+ currentPart.classes.push(ts(inClass+1, x).replace(/\\/g, ""));
+ inClass = -1;
+ }
+ }
+
+ var endAll = function(){
+ endId(); endTag(); endClass();
+ }
+
+ for(; lc=cc, cc=query.charAt(x),x<ql; x++){
+ if(lc == "\\"){ continue; }
+ if(!currentPart){
+ // NOTE: I hate all this alloc, but it's shorter than writing tons of if's
+ pStart = x;
+ currentPart = {
+ query: null,
+ pseudos: [],
+ attrs: [],
+ classes: [],
+ tag: null,
+ oper: null,
+ id: null
+ };
+ inTag = x;
+ }
+
+ if(inBrackets >= 0){
+ // look for a the close first
+ if(cc == "]"){
+ if(!_cp.attr){
+ _cp.attr = ts(inBrackets+1, x);
+ }else{
+ _cp.matchFor = ts((inMatchFor||inBrackets+1), x);
+ }
+ var cmf = _cp.matchFor;
+ if(cmf){
+ if( (cmf.charAt(0) == '"') || (cmf.charAt(0) == "'") ){
+ _cp.matchFor = cmf.substring(1, cmf.length-1);
+ }
+ }
+ currentPart.attrs.push(_cp);
+ _cp = null; // necessaray?
+ inBrackets = inMatchFor = -1;
+ }else if(cc == "="){
+ var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : "";
+ _cp.type = addToCc+cc;
+ _cp.attr = ts(inBrackets+1, x-addToCc.length);
+ inMatchFor = x+1;
+ }
+ // now look for other clause parts
+ }else if(inParens >= 0){
+ if(cc == ")"){
+ if(inPseudo >= 0){
+ _cp.value = ts(inParens+1, x);
+ }
+ inPseudo = inParens = -1;
+ }
+ }else if(cc == "#"){
+ endAll();
+ inId = x+1;
+ }else if(cc == "."){
+ endAll();
+ inClass = x;
+ }else if(cc == ":"){
+ endAll();
+ inPseudo = x;
+ }else if(cc == "["){
+ endAll();
+ inBrackets = x;
+ _cp = {
+ /*=====
+ attr: null, type: null, matchFor: null
+ =====*/
+ };
+ }else if(cc == "("){
+ if(inPseudo >= 0){
+ _cp = {
+ name: ts(inPseudo+1, x),
+ value: null
+ }
+ currentPart.pseudos.push(_cp);
+ }
+ inParens = x;
+ }else if(cc == " " && lc != cc){
+ // note that we expect the string to be " " terminated
+ endAll();
+ if(inPseudo >= 0){
+ currentPart.pseudos.push({ name: ts(inPseudo+1, x) });
+ }
+ currentPart.hasLoops = (
+ currentPart.pseudos.length ||
+ currentPart.attrs.length ||
+ currentPart.classes.length );
+ currentPart.query = ts(pStart, x);
+ currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
+ qparts.push(currentPart);
+ currentPart = null;
+ }
+ }
+ return qparts;
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // XPath query code
+ ////////////////////////////////////////////////////////////////////////
+
+ // this array is a lookup used to generate an attribute matching function.
+ // There is a similar lookup/generator list for the DOM branch with similar
+ // calling semantics.
+ var xPathAttrs = {
+ "*=": function(attr, value){
+ return "[contains(@"+attr+", '"+ value +"')]";
+ },
+ "^=": function(attr, value){
+ return "[starts-with(@"+attr+", '"+ value +"')]";
+ },
+ "$=": function(attr, value){
+ return "[substring(@"+attr+", string-length(@"+attr+")-"+(value.length-1)+")='"+value+"']";
+ },
+ "~=": function(attr, value){
+ return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
+ },
+ "|=": function(attr, value){
+ return "[contains(concat(' ',@"+attr+",' '), ' "+ value +"-')]";
+ },
+ "=": function(attr, value){
+ return "[@"+attr+"='"+ value +"']";
+ }
+ };
+
+ // takes a list of attribute searches, the overall query, a function to
+ // generate a default matcher, and a closure-bound method for providing a
+ // matching function that generates whatever type of yes/no distinguisher
+ // the query method needs. The method is a bit tortured and hard to read
+ // because it needs to be used in both the XPath and DOM branches.
+ var handleAttrs = function( attrList,
+ query,
+ getDefault,
+ handleMatch){
+ d.forEach(query.attrs, function(attr){
+ var matcher;
+ // type, attr, matchFor
+ if(attr.type && attrList[attr.type]){
+ matcher = attrList[attr.type](attr.attr, attr.matchFor);
+ }else if(attr.attr.length){
+ matcher = getDefault(attr.attr);
+ }
+ if(matcher){ handleMatch(matcher); }
+ });
+ }
+
+ var buildPath = function(query){
+ var xpath = ".";
+ var qparts = getQueryParts(d.trim(query));
+ while(qparts.length){
+ var tqp = qparts.shift();
+ var prefix;
+ var postfix = "";
+ if(tqp.oper == ">"){
+ prefix = "/";
+ // prefix = "/child::*";
+ tqp = qparts.shift();
+ }else if(tqp.oper == "~"){
+ prefix = "/following-sibling::"; // get element following siblings
+ tqp = qparts.shift();
+ }else if(tqp.oper == "+"){
+ // FIXME:
+ // fails when selecting subsequent siblings by node type
+ // because the position() checks the position in the list
+ // of matching elements and not the localized siblings
+ prefix = "/following-sibling::";
+ postfix = "[position()=1]";
+ tqp = qparts.shift();
+ }else{
+ prefix = "//";
+ // prefix = "/descendant::*"
+ }
+
+ // get the tag name (if any)
+
+ xpath += prefix + tqp.tag + postfix;
+
+ // check to see if it's got an id. Needs to come first in xpath.
+ if(tqp.id){
+ xpath += "[@id='"+tqp.id+"'][1]";
+ }
+
+ d.forEach(tqp.classes, function(cn){
+ var cnl = cn.length;
+ var padding = " ";
+ if(cn.charAt(cnl-1) == "*"){
+ padding = ""; cn = cn.substr(0, cnl-1);
+ }
+ xpath +=
+ "[contains(concat(' ',@class,' '), ' "+
+ cn + padding + "')]";
+ });
+
+ handleAttrs(xPathAttrs, tqp,
+ function(condition){
+ return "[@"+condition+"]";
+ },
+ function(matcher){
+ xpath += matcher;
+ }
+ );
+
+ // FIXME: need to implement pseudo-class checks!!
+ };
+ return xpath;
+ };
+
+ var _xpathFuncCache = {};
+ var getXPathFunc = function(path){
+ if(_xpathFuncCache[path]){
+ return _xpathFuncCache[path];
+ }
+
+ var doc = d.doc;
+ // don't need to memoize. The closure scope handles it for us.
+ var xpath = buildPath(path);
+
+ var tf = function(parent){
+ // XPath query strings are memoized.
+ var ret = [];
+ var xpathResult;
+ try{
+ xpathResult = doc.evaluate(xpath, parent, null,
+ // XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
+ XPathResult.ANY_TYPE, null);
+ }catch(e){
+ console.debug("failure in exprssion:", xpath, "under:", parent);
+ console.debug(e);
+ }
+ var result = xpathResult.iterateNext();
+ while(result){
+ ret.push(result);
+ result = xpathResult.iterateNext();
+ }
+ return ret;
+ }
+ return _xpathFuncCache[path] = tf;
+ };
+
+ /*
+ d.xPathMatch = function(query){
+ // XPath based DOM query system. Handles a small subset of CSS
+ // selectors, subset is identical to the non-XPath version of this
+ // function.
+
+ return getXPathFunc(query)();
+ }
+ */
+
+ ////////////////////////////////////////////////////////////////////////
+ // DOM query code
+ ////////////////////////////////////////////////////////////////////////
+
+ var _filtersCache = {};
+ var _simpleFiltersCache = {};
+
+ // the basic building block of the yes/no chaining system. agree(f1, f2)
+ // generates a new function which returns the boolean results of both of
+ // the passed functions to a single logical-anded result.
+ var agree = function(first, second){
+ if(!first){ return second; }
+ if(!second){ return first; }
+
+ return function(){
+ return first.apply(window, arguments) && second.apply(window, arguments);
+ }
+ }
+
+ var _childElements = function(root){
+ var ret = [];
+ var te, x=0, tret = root[childNodesName];
+ while(te=tret[x++]){
+ if(te.nodeType == 1){ ret.push(te); }
+ }
+ return ret;
+ }
+
+ var _nextSiblings = function(root, single){
+ var ret = [];
+ var te = root;
+ while(te = te.nextSibling){
+ if(te.nodeType == 1){
+ ret.push(te);
+ if(single){ break; }
+ }
+ }
+ return ret;
+ }
+
+ var _filterDown = function(element, queryParts, matchArr, idx){
+ // NOTE:
+ // in the fast path! this function is called recursively and for
+ // every run of a query.
+ var nidx = idx+1;
+ var isFinal = (queryParts.length == nidx);
+ var tqp = queryParts[idx];
+
+ // see if we can constrain our next level to direct children
+ if(tqp.oper){
+ var ecn = (tqp.oper == ">") ?
+ _childElements(element) :
+ _nextSiblings(element, (tqp.oper == "+"));
+
+ if(!ecn || !ecn.length){
+ return;
+ }
+ nidx++;
+ isFinal = (queryParts.length == nidx);
+ // kinda janky, too much array alloc
+ var tf = getFilterFunc(queryParts[idx+1]);
+ // for(var x=ecn.length-1, te; x>=0, te=ecn[x]; x--){
+ for(var x=0, ecnl=ecn.length, te; x<ecnl, te=ecn[x]; x++){
+ if(tf(te)){
+ if(isFinal){
+ matchArr.push(te);
+ }else{
+ _filterDown(te, queryParts, matchArr, nidx);
+ }
+ }
+ /*
+ if(x==0){
+ break;
+ }
+ */
+ }
+ }
+
+ // otherwise, keep going down, unless we'er at the end
+ var candidates = getElementsFunc(tqp)(element);
+ if(isFinal){
+ while(candidates.length){
+ matchArr.push(candidates.shift());
+ }
+ /*
+ candidates.unshift(0, matchArr.length-1);
+ matchArr.splice.apply(matchArr, candidates);
+ */
+ }else{
+ // if we're not yet at the bottom, keep going!
+ while(candidates.length){
+ _filterDown(candidates.shift(), queryParts, matchArr, nidx);
+ }
+ }
+ }
+
+ var filterDown = function(elements, queryParts){
+ var ret = [];
+
+ // for every root, get the elements that match the descendant selector
+ // for(var x=elements.length-1, te; x>=0, te=elements[x]; x--){
+ var x = elements.length - 1, te;
+ while(te = elements[x--]){
+ _filterDown(te, queryParts, ret, 0);
+ }
+ return ret;
+ }
+
+ var getFilterFunc = function(q){
+ // note: query can't have spaces!
+ if(_filtersCache[q.query]){
+ return _filtersCache[q.query];
+ }
+ var ff = null;
+
+ // does it have a tagName component?
+ if(q.tag){
+ if(q.tag == "*"){
+ ff = agree(ff,
+ function(elem){
+ return (elem.nodeType == 1);
+ }
+ );
+ }else{
+ // tag name match
+ ff = agree(ff,
+ function(elem){
+ return (
+ (elem.nodeType == 1) &&
+ (q.tag == elem.tagName.toLowerCase())
+ );
+ // return isTn;
+ }
+ );
+ }
+ }
+
+ // does the node have an ID?
+ if(q.id){
+ ff = agree(ff,
+ function(elem){
+ return (
+ (elem.nodeType == 1) &&
+ (elem.id == q.id)
+ );
+ }
+ );
+ }
+
+ if(q.hasLoops){
+ // if we have other query param parts, make sure we add them to the
+ // filter chain
+ ff = agree(ff, getSimpleFilterFunc(q));
+ }
+
+ return _filtersCache[q.query] = ff;
+ }
+
+ var getNodeIndex = function(node){
+ // NOTE:
+ // we could have a more accurate caching mechanism by invalidating
+ // caches after the query has finished, but I think that'd lead to
+ // significantly more cache churn than the cache would provide
+ // value for in the common case. Generally, we're more
+ // conservative (and therefore, more accurate) than jQuery and
+ // DomQuery WRT node node indexes, but there may be corner cases
+ // in which we fall down. How much we care about them is TBD.
+
+ var pn = node.parentNode;
+ var pnc = pn.childNodes;
+
+ // check to see if we can trust the cache. If not, re-key the whole
+ // thing and return our node match from that.
+
+ var nidx = -1;
+ var child = pn.firstChild;
+ if(!child){
+ return nidx;
+ }
+
+ var ci = node["__cachedIndex"];
+ var cl = pn["__cachedLength"];
+
+ // only handle cache building if we've gone out of sync
+ if(((typeof cl == "number")&&(cl != pnc.length))||(typeof ci != "number")){
+ // rip though the whole set, building cache indexes as we go
+ pn["__cachedLength"] = pnc.length;
+ var idx = 1;
+ do{
+ // we only assign indexes for nodes with nodeType == 1, as per:
+ // http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
+ // only elements are counted in the search order, and they
+ // begin at 1 for the first child's index
+
+ if(child === node){
+ nidx = idx;
+ }
+ if(child.nodeType == 1){
+ child["__cachedIndex"] = idx;
+ idx++;
+ }
+ child = child.nextSibling;
+ }while(child);
+ }else{
+ // NOTE:
+ // could be incorrect in some cases (node swaps involving the
+ // passed node, etc.), but we ignore those due to the relative
+ // unlikelihood of that occuring
+ nidx = ci;
+ }
+ return nidx;
+ }
+
+ var firedCount = 0;
+
+ var blank = "";
+ var _getAttr = function(elem, attr){
+ if(attr == "class"){
+ return elem.className || blank;
+ }
+ if(attr == "for"){
+ return elem.htmlFor || blank;
+ }
+ return elem.getAttribute(attr, 2) || blank;
+ }
+
+ var attrs = {
+ "*=": function(attr, value){
+ return function(elem){
+ // E[foo*="bar"]
+ // an E element whose "foo" attribute value contains
+ // the substring "bar"
+ return (_getAttr(elem, attr).indexOf(value)>=0);
+ }
+ },
+ "^=": function(attr, value){
+ // E[foo^="bar"]
+ // an E element whose "foo" attribute value begins exactly
+ // with the string "bar"
+ return function(elem){
+ return (_getAttr(elem, attr).indexOf(value)==0);
+ }
+ },
+ "$=": function(attr, value){
+ // E[foo$="bar"]
+ // an E element whose "foo" attribute value ends exactly
+ // with the string "bar"
+ var tval = " "+value;
+ return function(elem){
+ var ea = " "+_getAttr(elem, attr);
+ return (ea.lastIndexOf(value)==(ea.length-value.length));
+ }
+ },
+ "~=": function(attr, value){
+ // E[foo~="bar"]
+ // an E element whose "foo" attribute value is a list of
+ // space-separated values, one of which is exactly equal
+ // to "bar"
+
+ // return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
+ var tval = " "+value+" ";
+ return function(elem){
+ var ea = " "+_getAttr(elem, attr)+" ";
+ return (ea.indexOf(tval)>=0);
+ }
+ },
+ "|=": function(attr, value){
+ // E[hreflang|="en"]
+ // an E element whose "hreflang" attribute has a
+ // hyphen-separated list of values beginning (from the
+ // left) with "en"
+ var valueDash = " "+value+"-";
+ return function(elem){
+ var ea = " "+(elem.getAttribute(attr, 2) || "");
+ return (
+ (ea == value) ||
+ (ea.indexOf(valueDash)==0)
+ );
+ }
+ },
+ "=": function(attr, value){
+ return function(elem){
+ return (_getAttr(elem, attr) == value);
+ }
+ }
+ };
+
+ var pseudos = {
+ "first-child": function(name, condition){
+ return function(elem){
+ if(elem.nodeType != 1){ return false; }
+ // check to see if any of the previous siblings are elements
+ var fc = elem.previousSibling;
+ while(fc && (fc.nodeType != 1)){
+ fc = fc.previousSibling;
+ }
+ return (!fc);
+ }
+ },
+ "last-child": function(name, condition){
+ return function(elem){
+ if(elem.nodeType != 1){ return false; }
+ // check to see if any of the next siblings are elements
+ var nc = elem.nextSibling;
+ while(nc && (nc.nodeType != 1)){
+ nc = nc.nextSibling;
+ }
+ return (!nc);
+ }
+ },
+ "empty": function(name, condition){
+ return function(elem){
+ // DomQuery and jQuery get this wrong, oddly enough.
+ // The CSS 3 selectors spec is pretty explicit about
+ // it, too.
+ var cn = elem.childNodes;
+ var cnl = elem.childNodes.length;
+ // if(!cnl){ return true; }
+ for(var x=cnl-1; x >= 0; x--){
+ var nt = cn[x].nodeType;
+ if((nt == 1)||(nt == 3)){ return false; }
+ }
+ return true;
+ }
+ },
+ "contains": function(name, condition){
+ return function(elem){
+ // FIXME: I dislike this version of "contains", as
+ // whimsical attribute could set it off. An inner-text
+ // based version might be more accurate, but since
+ // jQuery and DomQuery also potentially get this wrong,
+ // I'm leaving it for now.
+ return (elem.innerHTML.indexOf(condition) >= 0);
+ }
+ },
+ "not": function(name, condition){
+ var ntf = getFilterFunc(getQueryParts(condition)[0]);
+ return function(elem){
+ return (!ntf(elem));
+ }
+ },
+ "nth-child": function(name, condition){
+ var pi = parseInt;
+ if(condition == "odd"){
+ return function(elem){
+ return (
+ ((getNodeIndex(elem)) % 2) == 1
+ );
+ }
+ }else if((condition == "2n")||
+ (condition == "even")){
+ return function(elem){
+ return ((getNodeIndex(elem) % 2) == 0);
+ }
+ }else if(condition.indexOf("0n+") == 0){
+ var ncount = pi(condition.substr(3));
+ return function(elem){
+ return (elem.parentNode[childNodesName][ncount-1] === elem);
+ }
+ }else if( (condition.indexOf("n+") > 0) &&
+ (condition.length > 3) ){
+ var tparts = condition.split("n+", 2);
+ var pred = pi(tparts[0]);
+ var idx = pi(tparts[1]);
+ return function(elem){
+ return ((getNodeIndex(elem) % pred) == idx);
+ }
+ }else if(condition.indexOf("n") == -1){
+ var ncount = pi(condition);
+ return function(elem){
+ return (getNodeIndex(elem) == ncount);
+ }
+ }
+ }
+ };
+
+ var defaultGetter = (d.isIE) ? function(cond){
+ var clc = cond.toLowerCase();
+ return function(elem){
+ return elem[cond]||elem[clc];
+ }
+ } : function(cond){
+ return function(elem){
+ return (elem && elem.getAttribute && elem.hasAttribute(cond));
+ }
+ };
+
+ var getSimpleFilterFunc = function(query){
+
+ var fcHit = (_simpleFiltersCache[query.query]||_filtersCache[query.query]);
+ if(fcHit){ return fcHit; }
+
+ var ff = null;
+
+ // the only case where we'll need the tag name is if we came from an ID query
+ if(query.id){ // do we have an ID component?
+ if(query.tag != "*"){
+ ff = agree(ff, function(elem){
+ return (elem.tagName.toLowerCase() == query.tag);
+ });
+ }
+ }
+
+ // if there's a class in our query, generate a match function for it
+ d.forEach(query.classes, function(cname, idx, arr){
+ // get the class name
+ var isWildcard = cname.charAt(cname.length-1) == "*";
+ if(isWildcard){
+ cname = cname.substr(0, cname.length-1);
+ }
+ // I dislike the regex thing, even if memozied in a cache, but it's VERY short
+ var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
+ ff = agree(ff, function(elem){
+ return re.test(elem.className);
+ });
+ ff.count = idx;
+ });
+
+ d.forEach(query.pseudos, function(pseudo){
+ if(pseudos[pseudo.name]){
+ ff = agree(ff, pseudos[pseudo.name](pseudo.name, pseudo.value));
+ }
+ });
+
+ handleAttrs(attrs, query, defaultGetter,
+ function(tmatcher){ ff = agree(ff, tmatcher); }
+ );
+ if(!ff){
+ ff = function(){ return true; };
+ }
+ return _simpleFiltersCache[query.query] = ff;
+ }
+
+ var _getElementsFuncCache = { };
+
+ var getElementsFunc = function(query, root){
+ var fHit = _getElementsFuncCache[query.query];
+ if(fHit){ return fHit; }
+
+ // NOTE: this function is in the fast path! not memoized!!!
+
+ // the query doesn't contain any spaces, so there's only so many
+ // things it could be
+
+ if(query.id && !query.hasLoops && !query.tag){
+ // ID-only query. Easy.
+ return _getElementsFuncCache[query.query] = function(root){
+ // FIXME: if root != document, check for parenting!
+ return [ d.byId(query.id) ];
+ }
+ }
+
+ var filterFunc = getSimpleFilterFunc(query);
+
+ var retFunc;
+ if(query.tag && query.id && !query.hasLoops){
+ // we got a filtered ID search (e.g., "h4#thinger")
+ retFunc = function(root){
+ var te = d.byId(query.id);
+ if(filterFunc(te)){
+ return [ te ];
+ }
+ }
+ }else{
+ var tret;
+
+ if(!query.hasLoops){
+ // it's just a plain-ol elements-by-tag-name query from the root
+ retFunc = function(root){
+ var ret = [];
+ var te, x=0, tret = root.getElementsByTagName(query.tag);
+ while(te=tret[x++]){
+ ret.push(te);
+ }
+ return ret;
+ }
+ }else{
+ retFunc = function(root){
+ var ret = [];
+ var te, x=0, tret = root.getElementsByTagName(query.tag);
+ while(te=tret[x++]){
+ if(filterFunc(te)){
+ ret.push(te);
+ }
+ }
+ return ret;
+ }
+ }
+ }
+ return _getElementsFuncCache[query.query] = retFunc;
+ }
+
+ var _partsCache = {};
+
+ ////////////////////////////////////////////////////////////////////////
+ // the query runner
+ ////////////////////////////////////////////////////////////////////////
+
+ // this is the second level of spliting, from full-length queries (e.g.,
+ // "div.foo .bar") into simple query expressions (e.g., ["div.foo",
+ // ".bar"])
+ var _queryFuncCache = {
+ "*": d.isIE ?
+ function(root){
+ return root.all;
+ } :
+ function(root){
+ return root.getElementsByTagName("*");
+ },
+ "~": _nextSiblings,
+ "+": function(root){ return _nextSiblings(root, true); },
+ ">": _childElements
+ };
+
+ var getStepQueryFunc = function(query){
+ // if it's trivial, get a fast-path dispatcher
+ var qparts = getQueryParts(d.trim(query));
+ // if(query[query.length-1] == ">"){ query += " *"; }
+ if(qparts.length == 1){
+ var tt = getElementsFunc(qparts[0]);
+ tt.nozip = true;
+ return tt;
+ }
+
+ // otherwise, break it up and return a runner that iterates over the parts recursively
+ var sqf = function(root){
+ var localQueryParts = qparts.slice(0); // clone the src arr
+ var candidates;
+ if(localQueryParts[0].oper == ">"){ // FIXME: what if it's + or ~?
+ candidates = [ root ];
+ // root = document;
+ }else{
+ candidates = getElementsFunc(localQueryParts.shift())(root);
+ }
+ return filterDown(candidates, localQueryParts);
+ }
+ return sqf;
+ }
+
+ // a specialized method that implements our primoridal "query optimizer".
+ // This allows us to dispatch queries to the fastest subsystem we can get.
+ var _getQueryFunc = (
+ // NOTE:
+ // XPath on the Webkit nighlies is slower than it's DOM iteration
+ // for most test cases
+ // FIXME:
+ // we should try to capture some runtime speed data for each query
+ // function to determine on the fly if we should stick w/ the
+ // potentially optimized variant or if we should try something
+ // new.
+ (document["evaluate"] && !d.isSafari) ?
+ function(query){
+ // has xpath support that's faster than DOM
+ var qparts = query.split(" ");
+ // can we handle it?
+ if( (document["evaluate"])&&
+ (query.indexOf(":") == -1)&&
+ (query.indexOf("+") == -1) // skip direct sibling matches. See line ~344
+ ){
+ // dojo.debug(query);
+ // should we handle it?
+
+ // kind of a lame heuristic, but it works
+ if(
+ // a "div div div" style query
+ ((qparts.length > 2)&&(query.indexOf(">") == -1))||
+ // or something else with moderate complexity. kinda janky
+ (qparts.length > 3)||
+ (query.indexOf("[")>=0)||
+ // or if it's a ".thinger" query
+ ((1 == qparts.length)&&(0 <= query.indexOf(".")))
+
+ ){
+ // use get and cache a xpath runner for this selector
+ return getXPathFunc(query);
+ }
+ }
+
+ // fallthrough
+ return getStepQueryFunc(query);
+ } : getStepQueryFunc
+ );
+ // uncomment to disable XPath for testing and tuning the DOM path
+ // _getQueryFunc = getStepQueryFunc;
+
+ // FIXME: we've got problems w/ the NodeList query()/filter() functions if we go XPath for everything
+
+ // uncomment to disable DOM queries for testing and tuning XPath
+ // _getQueryFunc = getXPathFunc;
+
+ // this is the primary caching for full-query results. The query dispatcher
+ // functions are generated here and then pickled for hash lookup in the
+ // future
+ var getQueryFunc = function(query){
+ // return a cached version if one is available
+ var qcz = query.charAt(0);
+ if(d.doc["querySelectorAll"] &&
+ ( (!d.isSafari) || (d.isSafari > 3.1) ) && // see #5832
+ // as per CSS 3, we can't currently start w/ combinator:
+ // http://www.w3.org/TR/css3-selectors/#w3cselgrammar
+ (">+~".indexOf(qcz) == -1)
+ ){
+ return function(root){
+ var r = root.querySelectorAll(query);
+ r.nozip = true; // skip expensive duplication checks and just wrap in a NodeList
+ return r;
+ };
+ }
+ if(_queryFuncCache[query]){ return _queryFuncCache[query]; }
+ if(0 > query.indexOf(",")){
+ // if it's not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
+ return _queryFuncCache[query] = _getQueryFunc(query);
+ }else{
+ // if it's a complex query, break it up into it's constituent parts
+ // and return a dispatcher that will merge the parts when run
+
+ // var parts = query.split(", ");
+ var parts = query.split(/\s*,\s*/);
+ var tf = function(root){
+ var pindex = 0; // avoid array alloc for every invocation
+ var ret = [];
+ var tp;
+ while(tp = parts[pindex++]){
+ ret = ret.concat(_getQueryFunc(tp, tp.indexOf(" "))(root));
+ }
+ return ret;
+ }
+ // ...cache and return
+ return _queryFuncCache[query] = tf;
+ }
+ }
+
+ // FIXME:
+ // Dean's Base2 uses a system whereby queries themselves note if
+ // they'll need duplicate filtering. We need to get on that plan!!
+
+ // attempt to efficiently determine if an item in a list is a dupe,
+ // returning a list of "uniques", hopefully in doucment order
+ var _zipIdx = 0;
+ var _zip = function(arr){
+ if(arr && arr.nozip){ return d.NodeList._wrap(arr); }
+ var ret = new d.NodeList();
+ if(!arr){ return ret; }
+ if(arr[0]){
+ ret.push(arr[0]);
+ }
+ if(arr.length < 2){ return ret; }
+ _zipIdx++;
+ arr[0]["_zipIdx"] = _zipIdx;
+ for(var x=1, te; te = arr[x]; x++){
+ if(arr[x]["_zipIdx"] != _zipIdx){
+ ret.push(te);
+ }
+ te["_zipIdx"] = _zipIdx;
+ }
+ // FIXME: should we consider stripping these properties?
+ return ret;
+ }
+
+ // the main executor
+ d.query = function(/*String*/ query, /*String|DOMNode?*/ root){
+ // summary:
+ // Returns nodes which match the given CSS3 selector, searching the
+ // entire document by default but optionally taking a node to scope
+ // the search by. Returns an instance of dojo.NodeList.
+ // description:
+ // dojo.query() is the swiss army knife of DOM node manipulation in
+ // Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's
+ // "$" function, dojo.query provides robust, high-performance
+ // CSS-based node selector support with the option of scoping searches
+ // to a particular sub-tree of a document.
+ //
+ // Supported Selectors:
+ // --------------------
+ //
+ // dojo.query() supports a rich set of CSS3 selectors, including:
+ //
+ // * class selectors (e.g., `.foo`)
+ // * node type selectors like `span`
+ // * ` ` descendant selectors
+ // * `>` child element selectors
+ // * `#foo` style ID selectors
+ // * `*` universal selector
+ // * `~`, the immediately preceeded-by sibling selector
+ // * `+`, the preceeded-by sibling selector
+ // * attribute queries:
+ // | * `[foo]` attribute presence selector
+ // | * `[foo='bar']` attribute value exact match
+ // | * `[foo~='bar']` attribute value list item match
+ // | * `[foo^='bar']` attribute start match
+ // | * `[foo$='bar']` attribute end match
+ // | * `[foo*='bar']` attribute substring match
+ // * `:first-child`, `:last-child` positional selectors
+ // * `:empty` content emtpy selector
+ // * `:empty` content emtpy selector
+ // * `:nth-child(n)`, `:nth-child(2n+1)` style positional calculations
+ // * `:nth-child(even)`, `:nth-child(odd)` positional selectors
+ // * `:not(...)` negation pseudo selectors
+ //
+ // Any legal combination of these selectors will work with
+ // `dojo.query()`, including compound selectors ("," delimited).
+ // Very complex and useful searches can be constructed with this
+ // palette of selectors and when combined with functions for
+ // maniplation presented by dojo.NodeList, many types of DOM
+ // manipulation operations become very straightforward.
+ //
+ // Unsupported Selectors:
+ // ----------------------
+ //
+ // While dojo.query handles many CSS3 selectors, some fall outside of
+ // what's resaonable for a programmatic node querying engine to
+ // handle. Currently unsupported selectors include:
+ //
+ // * namespace-differentiated selectors of any form
+ // * all `::` pseduo-element selectors
+ // * certain pseduo-selectors which don't get a lot of day-to-day use:
+ // | * `:root`, `:lang()`, `:target`, `:focus`
+ // * all visual and state selectors:
+ // | * `:root`, `:active`, `:hover`, `:visisted`, `:link`,
+ // `:enabled`, `:disabled`, `:checked`
+ // * `:*-of-type` pseudo selectors
+ //
+ // dojo.query and XML Documents:
+ // -----------------------------
+ //
+ // `dojo.query` currently only supports searching XML documents
+ // whose tags and attributes are 100% lower-case. This is a known
+ // limitation and will [be addressed soon](http://trac.dojotoolkit.org/ticket/3866)
+ // Non-selector Queries:
+ // ---------------------
+ //
+ // If something other than a String is passed for the query,
+ // `dojo.query` will return a new `dojo.NodeList` constructed from
+ // that parameter alone and all further processing will stop. This
+ // means that if you have a reference to a node or NodeList, you
+ // can quickly construct a new NodeList from the original by
+ // calling `dojo.query(node)` or `dojo.query(list)`.
+ //
+ // query:
+ // The CSS3 expression to match against. For details on the syntax of
+ // CSS3 selectors, see <http://www.w3.org/TR/css3-selectors/#selectors>
+ // root:
+ // A DOMNode (or node id) to scope the search from. Optional.
+ // returns: dojo.NodeList
+ // An instance of `dojo.NodeList`. Many methods are available on
+ // NodeLists for searching, iterating, manipulating, and handling
+ // events on the matched nodes in the returned list.
+ // example:
+ // search the entire document for elements with the class "foo":
+ // | dojo.query(".foo");
+ // these elements will match:
+ // | <span class="foo"></span>
+ // | <span class="foo bar"></span>
+ // | <p class="thud foo"></p>
+ // example:
+ // search the entire document for elements with the classes "foo" *and* "bar":
+ // | dojo.query(".foo.bar");
+ // these elements will match:
+ // | <span class="foo bar"></span>
+ // while these will not:
+ // | <span class="foo"></span>
+ // | <p class="thud foo"></p>
+ // example:
+ // find `<span>` elements which are descendants of paragraphs and
+ // which have a "highlighted" class:
+ // | dojo.query("p span.highlighted");
+ // the innermost span in this fragment matches:
+ // | <p class="foo">
+ // | <span>...
+ // | <span class="highlighted foo bar">...</span>
+ // | </span>
+ // | </p>
+ // example:
+ // set an "odd" class on all odd table rows inside of the table
+ // `#tabular_data`, using the `>` (direct child) selector to avoid
+ // affecting any nested tables:
+ // | dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
+ // example:
+ // remove all elements with the class "error" from the document
+ // and store them in a list:
+ // | var errors = dojo.query(".error").orphan();
+ // example:
+ // add an onclick handler to every submit button in the document
+ // which causes the form to be sent via Ajax instead:
+ // | dojo.query("input[type='submit']").onclick(function(e){
+ // | dojo.stopEvent(e); // prevent sending the form
+ // | var btn = e.target;
+ // | dojo.xhrPost({
+ // | form: btn.form,
+ // | load: function(data){
+ // | // replace the form with the response
+ // | var div = dojo.doc.createElement("div");
+ // | dojo.place(div, btn.form, "after");
+ // | div.innerHTML = data;
+ // | dojo.style(btn.form, "display", "none");
+ // | }
+ // | });
+ // | });
+
+
+ // NOTE: elementsById is not currently supported
+ // NOTE: ignores xpath-ish queries for now
+
+ if(query.constructor == d.NodeList){
+ return query;
+ }
+ if(!d.isString(query)){
+ return new d.NodeList(query); // dojo.NodeList
+ }
+ if(d.isString(root)){
+ root = d.byId(root);
+ }
+
+ return _zip(getQueryFunc(query)(root||d.doc)); // dojo.NodeList
+ }
+
+ /*
+ // exposing this was a mistake
+ d.query.attrs = attrs;
+ */
+ // exposing this because new pseudo matches are only executed through the
+ // DOM query path (never through the xpath optimizing branch)
+ d.query.pseudos = pseudos;
+
+ // one-off function for filtering a NodeList based on a simple selector
+ d._filterQueryResult = function(nodeList, simpleFilter){
+ var tnl = new d.NodeList();
+ var ff = (simpleFilter) ? getFilterFunc(getQueryParts(simpleFilter)[0]) : function(){ return true; };
+ for(var x=0, te; te = nodeList[x]; x++){
+ if(ff(te)){ tnl.push(te); }
+ }
+ return tnl;
+ }
+})();
+
+}
+
+if(!dojo._hasResource["dojo._base.xhr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.xhr"] = true;
+dojo.provide("dojo._base.xhr");
+
+
+
+
+
+(function(){
+ var _d = dojo;
+ function setValue(/*Object*/obj, /*String*/name, /*String*/value){
+ //summary:
+ // For the nameed property in object, set the value. If a value
+ // already exists and it is a string, convert the value to be an
+ // array of values.
+ var val = obj[name];
+ if(_d.isString(val)){
+ obj[name] = [val, value];
+ }else if(_d.isArray(val)){
+ val.push(value);
+ }else{
+ obj[name] = value;
+ }
+ }
+
+ dojo.formToObject = function(/*DOMNode||String*/ formNode){
+ // summary:
+ // dojo.formToObject returns the values encoded in an HTML form as
+ // string properties in an object which it then returns. Disabled form
+ // elements, buttons, and other non-value form elements are skipped.
+ // Multi-select elements are returned as an array of string values.
+ // description:
+ // This form:
+ //
+ // | <form id="test_form">
+ // | <input type="text" name="blah" value="blah">
+ // | <input type="text" name="no_value" value="blah" disabled>
+ // | <input type="button" name="no_value2" value="blah">
+ // | <select type="select" multiple name="multi" size="5">
+ // | <option value="blah">blah</option>
+ // | <option value="thud" selected>thud</option>
+ // | <option value="thonk" selected>thonk</option>
+ // | </select>
+ // | </form>
+ //
+ // yields this object structure as the result of a call to
+ // formToObject():
+ //
+ // | {
+ // | blah: "blah",
+ // | multi: [
+ // | "thud",
+ // | "thonk"
+ // | ]
+ // | };
+
+ var ret = {};
+ var iq = "input:not([type=file]):not([type=submit]):not([type=image]):not([type=reset]):not([type=button]), select, textarea";
+ _d.query(iq, formNode).filter(function(node){
+ return !node.disabled && node.name;
+ }).forEach(function(item){
+ var _in = item.name;
+ var type = (item.type||"").toLowerCase();
+ if(type == "radio" || type == "checkbox"){
+ if(item.checked){ setValue(ret, _in, item.value); }
+ }else if(item.multiple){
+ ret[_in] = [];
+ _d.query("option", item).forEach(function(opt){
+ if(opt.selected){
+ setValue(ret, _in, opt.value);
+ }
+ });
+ }else{
+ setValue(ret, _in, item.value);
+ if(type == "image"){
+ ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0;
+ }
+ }
+ });
+ return ret; // Object
+ }
+
+ dojo.objectToQuery = function(/*Object*/ map){
+ // summary:
+ // takes a name/value mapping object and returns a string representing
+ // a URL-encoded version of that object.
+ // example:
+ // this object:
+ //
+ // | {
+ // | blah: "blah",
+ // | multi: [
+ // | "thud",
+ // | "thonk"
+ // | ]
+ // | };
+ //
+ // yields the following query string:
+ //
+ // | "blah=blah&multi=thud&multi=thonk"
+
+ // FIXME: need to implement encodeAscii!!
+ var enc = encodeURIComponent;
+ var pairs = [];
+ var backstop = {};
+ for(var name in map){
+ var value = map[name];
+ if(value != backstop[name]){
+ var assign = enc(name) + "=";
+ if(_d.isArray(value)){
+ for(var i=0; i < value.length; i++){
+ pairs.push(assign + enc(value[i]));
+ }
+ }else{
+ pairs.push(assign + enc(value));
+ }
+ }
+ }
+ return pairs.join("&"); // String
+ }
+
+ dojo.formToQuery = function(/*DOMNode||String*/ formNode){
+ // summary:
+ // Returns a URL-encoded string representing the form passed as either a
+ // node or string ID identifying the form to serialize
+ return _d.objectToQuery(_d.formToObject(formNode)); // String
+ }
+
+ dojo.formToJson = function(/*DOMNode||String*/ formNode, /*Boolean?*/prettyPrint){
+ // summary:
+ // return a serialized JSON string from a form node or string
+ // ID identifying the form to serialize
+ return _d.toJson(_d.formToObject(formNode), prettyPrint); // String
+ }
+
+ dojo.queryToObject = function(/*String*/ str){
+ // summary:
+ // returns an object representing a de-serialized query section of a
+ // URL. Query keys with multiple values are returned in an array.
+ // description:
+ // This string:
+ //
+ // | "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&"
+ //
+ // results in this object structure:
+ //
+ // | {
+ // | foo: [ "bar", "baz" ],
+ // | thinger: " spaces =blah",
+ // | zonk: "blarg"
+ // | }
+ //
+ // Note that spaces and other urlencoded entities are correctly
+ // handled.
+
+ // FIXME: should we grab the URL string if we're not passed one?
+ var ret = {};
+ var qp = str.split("&");
+ var dec = decodeURIComponent;
+ _d.forEach(qp, function(item){
+ if(item.length){
+ var parts = item.split("=");
+ var name = dec(parts.shift());
+ var val = dec(parts.join("="));
+ if(_d.isString(ret[name])){
+ ret[name] = [ret[name]];
+ }
+ if(_d.isArray(ret[name])){
+ ret[name].push(val);
+ }else{
+ ret[name] = val;
+ }
+ }
+ });
+ return ret; // Object
+ }
+
+ /*
+ from refactor.txt:
+
+ all bind() replacement APIs take the following argument structure:
+
+ {
+ url: "blah.html",
+
+ // all below are optional, but must be supported in some form by
+ // every IO API
+ timeout: 1000, // milliseconds
+ handleAs: "text", // replaces the always-wrong "mimetype"
+ content: {
+ key: "value"
+ },
+
+ // browser-specific, MAY be unsupported
+ sync: true, // defaults to false
+ form: dojo.byId("someForm")
+ }
+ */
+
+ // need to block async callbacks from snatching this thread as the result
+ // of an async callback might call another sync XHR, this hangs khtml forever
+ // must checked by watchInFlight()
+
+ dojo._blockAsync = false;
+
+ dojo._contentHandlers = {
+ "text": function(xhr){ return xhr.responseText; },
+ "json": function(xhr){
+ if(!dojo.config.usePlainJson){
+ console.warn("Consider using mimetype:text/json-comment-filtered"
+ + " to avoid potential security issues with JSON endpoints"
+ + " (use djConfig.usePlainJson=true to turn off this message)");
+ }
+ return (xhr.status == 204) ? undefined : _d.fromJson(xhr.responseText);
+ },
+ "json-comment-filtered": function(xhr){
+ // NOTE: we provide the json-comment-filtered option as one solution to
+ // the "JavaScript Hijacking" issue noted by Fortify and others. It is
+ // not appropriate for all circumstances.
+
+ var value = xhr.responseText;
+ var cStartIdx = value.indexOf("\/*");
+ var cEndIdx = value.lastIndexOf("*\/");
+ if(cStartIdx == -1 || cEndIdx == -1){
+ throw new Error("JSON was not comment filtered");
+ }
+ return (xhr.status == 204) ? undefined :
+ _d.fromJson(value.substring(cStartIdx+2, cEndIdx));
+ },
+ "javascript": function(xhr){
+ // FIXME: try Moz and IE specific eval variants?
+ return _d.eval(xhr.responseText);
+ },
+ "xml": function(xhr){
+ var result = xhr.responseXML;
+ if(_d.isIE && (!result || window.location.protocol == "file:")){
+ _d.forEach(["MSXML2", "Microsoft", "MSXML", "MSXML3"], function(prefix){
+ try{
+ var dom = new ActiveXObject(prefix + ".XMLDOM");
+ dom.async = false;
+ dom.loadXML(xhr.responseText);
+ result = dom;
+ }catch(e){ /* Not available. Squelch and try next one. */ }
+ });
+ }
+ return result; // DOMDocument
+ }
+ };
+
+ dojo._contentHandlers["json-comment-optional"] = function(xhr){
+ var handlers = _d._contentHandlers;
+ try{
+ return handlers["json-comment-filtered"](xhr);
+ }catch(e){
+ return handlers["json"](xhr);
+ }
+ };
+
+ /*=====
+ dojo.__IoArgs = function(){
+ // url: String
+ // URL to server endpoint.
+ // content: Object?
+ // Contains properties with string values. These
+ // properties will be serialized as name1=value2 and
+ // passed in the request.
+ // timeout: Integer?
+ // Milliseconds to wait for the response. If this time
+ // passes, the then error callbacks are called.
+ // form: DOMNode?
+ // DOM node for a form. Used to extract the form values
+ // and send to the server.
+ // preventCache: Boolean?
+ // Default is false. If true, then a
+ // "dojo.preventCache" parameter is sent in the request
+ // with a value that changes with each request
+ // (timestamp). Useful only with GET-type requests.
+ // handleAs: String?
+ // Acceptable values depend on the type of IO
+ // transport (see specific IO calls for more information).
+ // load: Function?
+ // function(response, ioArgs){}. response is an Object, ioArgs
+ // is of type dojo.__IoCallbackArgs. The load function will be
+ // called on a successful response.
+ // error: Function?
+ // function(response, ioArgs){}. response is an Object, ioArgs
+ // is of type dojo.__IoCallbackArgs. The error function will
+ // be called in an error case.
+ // handle: Function?
+ // function(response, ioArgs){}. response is an Object, ioArgs
+ // is of type dojo.__IoCallbackArgs. The handle function will
+ // be called in either the successful or error case. For
+ // the load, error and handle functions, the ioArgs object
+ // will contain the following properties:
+ this.url = url;
+ this.content = content;
+ this.timeout = timeout;
+ this.form = form;
+ this.preventCache = preventCache;
+ this.handleAs = handleAs;
+ this.load = load;
+ this.error = error;
+ this.handle = handle;
+ }
+ =====*/
+
+ /*=====
+ dojo.__IoCallbackArgs = function(args, xhr, url, query, handleAs, id, canDelete, json){
+ // args: Object
+ // the original object argument to the IO call.
+ // xhr: XMLHttpRequest
+ // For XMLHttpRequest calls only, the
+ // XMLHttpRequest object that was used for the
+ // request.
+ // url: String
+ // The final URL used for the call. Many times it
+ // will be different than the original args.url
+ // value.
+ // query: String
+ // For non-GET requests, the
+ // name1=value1&name2=value2 parameters sent up in
+ // the request.
+ // handleAs: String
+ // The final indicator on how the response will be
+ // handled.
+ // id: String
+ // For dojo.io.script calls only, the internal
+ // script ID used for the request.
+ // canDelete: Boolean
+ // For dojo.io.script calls only, indicates
+ // whether the script tag that represents the
+ // request can be deleted after callbacks have
+ // been called. Used internally to know when
+ // cleanup can happen on JSONP-type requests.
+ // json: Object
+ // For dojo.io.script calls only: holds the JSON
+ // response for JSONP-type requests. Used
+ // internally to hold on to the JSON responses.
+ // You should not need to access it directly --
+ // the same object should be passed to the success
+ // callbacks directly.
+ this.args = args;
+ this.xhr = xhr;
+ this.url = url;
+ this.query = query;
+ this.handleAs = handleAs;
+ this.id = id;
+ this.canDelete = canDelete;
+ this.json = json;
+ }
+ =====*/
+
+
+
+ dojo._ioSetArgs = function(/*dojo.__IoArgs*/args,
+ /*Function*/canceller,
+ /*Function*/okHandler,
+ /*Function*/errHandler){
+ // summary:
+ // sets up the Deferred and ioArgs property on the Deferred so it
+ // can be used in an io call.
+ // args:
+ // The args object passed into the public io call. Recognized properties on
+ // the args object are:
+ // canceller:
+ // The canceller function used for the Deferred object. The function
+ // will receive one argument, the Deferred object that is related to the
+ // canceller.
+ // okHandler:
+ // The first OK callback to be registered with Deferred. It has the opportunity
+ // to transform the OK response. It will receive one argument -- the Deferred
+ // object returned from this function.
+ // errHandler:
+ // The first error callback to be registered with Deferred. It has the opportunity
+ // to do cleanup on an error. It will receive two arguments: error (the
+ // Error object) and dfd, the Deferred object returned from this function.
+
+ var ioArgs = {args: args, url: args.url};
+
+ //Get values from form if requestd.
+ var formObject = null;
+ if(args.form){
+ var form = _d.byId(args.form);
+ //IE requires going through getAttributeNode instead of just getAttribute in some form cases,
+ //so use it for all. See #2844
+ var actnNode = form.getAttributeNode("action");
+ ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : null);
+ formObject = _d.formToObject(form);
+ }
+
+ // set up the query params
+ var miArgs = [{}];
+
+ if(formObject){
+ // potentially over-ride url-provided params w/ form values
+ miArgs.push(formObject);
+ }
+ if(args.content){
+ // stuff in content over-rides what's set by form
+ miArgs.push(args.content);
+ }
+ if(args.preventCache){
+ miArgs.push({"dojo.preventCache": new Date().valueOf()});
+ }
+ ioArgs.query = _d.objectToQuery(_d.mixin.apply(null, miArgs));
+
+ // .. and the real work of getting the deferred in order, etc.
+ ioArgs.handleAs = args.handleAs || "text";
+ var d = new _d.Deferred(canceller);
+ d.addCallbacks(okHandler, function(error){
+ return errHandler(error, d);
+ });
+
+ //Support specifying load, error and handle callback functions from the args.
+ //For those callbacks, the "this" object will be the args object.
+ //The callbacks will get the deferred result value as the
+ //first argument and the ioArgs object as the second argument.
+ var ld = args.load;
+ if(ld && _d.isFunction(ld)){
+ d.addCallback(function(value){
+ return ld.call(args, value, ioArgs);
+ });
+ }
+ var err = args.error;
+ if(err && _d.isFunction(err)){
+ d.addErrback(function(value){
+ return err.call(args, value, ioArgs);
+ });
+ }
+ var handle = args.handle;
+ if(handle && _d.isFunction(handle)){
+ d.addBoth(function(value){
+ return handle.call(args, value, ioArgs);
+ });
+ }
+
+ d.ioArgs = ioArgs;
+
+ // FIXME: need to wire up the xhr object's abort method to something
+ // analagous in the Deferred
+ return d;
+ }
+
+ var _deferredCancel = function(/*Deferred*/dfd){
+ //summary: canceller function for dojo._ioSetArgs call.
+
+ dfd.canceled = true;
+ var xhr = dfd.ioArgs.xhr;
+ var _at = typeof xhr.abort;
+ if(_at == "function" || _at == "unknown"){
+ xhr.abort();
+ }
+ var err = new Error("xhr cancelled");
+ err.dojoType = "cancel";
+ return err;
+ }
+ var _deferredOk = function(/*Deferred*/dfd){
+ //summary: okHandler function for dojo._ioSetArgs call.
+
+ return _d._contentHandlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
+ }
+ var _deferError = function(/*Error*/error, /*Deferred*/dfd){
+ //summary: errHandler function for dojo._ioSetArgs call.
+
+ // console.debug("xhr error in:", dfd.ioArgs.xhr);
+ console.debug(error);
+ return error;
+ }
+
+ var _makeXhrDeferred = function(/*dojo.__XhrArgs*/args){
+ //summary: makes the Deferred object for this xhr request.
+ var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError);
+ //Pass the args to _xhrObj, to allow xhr iframe proxy interceptions.
+ dfd.ioArgs.xhr = _d._xhrObj(dfd.ioArgs.args);
+ return dfd;
+ }
+
+ // avoid setting a timer per request. It degrades performance on IE
+ // something fierece if we don't use unified loops.
+ var _inFlightIntvl = null;
+ var _inFlight = [];
+ var _watchInFlight = function(){
+ //summary:
+ // internal method that checks each inflight XMLHttpRequest to see
+ // if it has completed or if the timeout situation applies.
+
+ var now = (new Date()).getTime();
+ // make sure sync calls stay thread safe, if this callback is called
+ // during a sync call and this results in another sync call before the
+ // first sync call ends the browser hangs
+ if(!_d._blockAsync){
+ // we need manual loop because we often modify _inFlight (and therefore 'i') while iterating
+ // note: the second clause is an assigment on purpose, lint may complain
+ for(var i = 0, tif; i < _inFlight.length && (tif = _inFlight[i]); i++){
+ var dfd = tif.dfd;
+ try{
+ if(!dfd || dfd.canceled || !tif.validCheck(dfd)){
+ _inFlight.splice(i--, 1);
+ }else if(tif.ioCheck(dfd)){
+ _inFlight.splice(i--, 1);
+ tif.resHandle(dfd);
+ }else if(dfd.startTime){
+ //did we timeout?
+ if(dfd.startTime + (dfd.ioArgs.args.timeout || 0) < now){
+ _inFlight.splice(i--, 1);
+ var err = new Error("timeout exceeded");
+ err.dojoType = "timeout";
+ dfd.errback(err);
+ //Cancel the request so the io module can do appropriate cleanup.
+ dfd.cancel();
+ }
+ }
+ }catch(e){
+ // FIXME: make sure we errback! (fixed? remove console.debug?)
+ console.debug(e);
+ dfd.errback(new Error("_watchInFlightError!"));
+ }
+ }
+ }
+
+ if(!_inFlight.length){
+ clearInterval(_inFlightIntvl);
+ _inFlightIntvl = null;
+ return;
+ }
+
+ }
+
+ dojo._ioCancelAll = function(){
+ //summary: Cancels all pending IO requests, regardless of IO type
+ //(xhr, script, iframe).
+ try{
+ _d.forEach(_inFlight, function(i){
+ i.dfd.cancel();
+ });
+ }catch(e){/*squelch*/}
+ }
+
+ //Automatically call cancel all io calls on unload
+ //in IE for trac issue #2357.
+ if(_d.isIE){
+ _d.addOnUnload(_d._ioCancelAll);
+ }
+
+ _d._ioWatch = function(/*Deferred*/dfd,
+ /*Function*/validCheck,
+ /*Function*/ioCheck,
+ /*Function*/resHandle){
+ //summary: watches the io request represented by dfd to see if it completes.
+ //dfd:
+ // The Deferred object to watch.
+ //validCheck:
+ // Function used to check if the IO request is still valid. Gets the dfd
+ // object as its only argument.
+ //ioCheck:
+ // Function used to check if basic IO call worked. Gets the dfd
+ // object as its only argument.
+ //resHandle:
+ // Function used to process response. Gets the dfd
+ // object as its only argument.
+ if(dfd.ioArgs.args.timeout){
+ dfd.startTime = (new Date()).getTime();
+ }
+ _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle});
+ if(!_inFlightIntvl){
+ _inFlightIntvl = setInterval(_watchInFlight, 50);
+ }
+ _watchInFlight(); // handle sync requests
+ }
+
+ var _defaultContentType = "application/x-www-form-urlencoded";
+
+ var _validCheck = function(/*Deferred*/dfd){
+ return dfd.ioArgs.xhr.readyState; //boolean
+ }
+ var _ioCheck = function(/*Deferred*/dfd){
+ return 4 == dfd.ioArgs.xhr.readyState; //boolean
+ }
+ var _resHandle = function(/*Deferred*/dfd){
+ var xhr = dfd.ioArgs.xhr;
+ if(_d._isDocumentOk(xhr)){
+ dfd.callback(dfd);
+ }else{
+ var err = new Error("Unable to load " + dfd.ioArgs.url + " status:" + xhr.status);
+ err.status = xhr.status;
+ err.responseText = xhr.responseText;
+ dfd.errback(err);
+ }
+ }
+
+ var _doIt = function(/*String*/type, /*Deferred*/dfd){
+ // IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open).
+ // workaround for IE6's apply() "issues"
+ var ioArgs = dfd.ioArgs;
+ var args = ioArgs.args;
+ var xhr = ioArgs.xhr;
+ xhr.open(type, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined);
+ if(args.headers){
+ for(var hdr in args.headers){
+ if(hdr.toLowerCase() === "content-type" && !args.contentType){
+ args.contentType = args.headers[hdr];
+ }else{
+ xhr.setRequestHeader(hdr, args.headers[hdr]);
+ }
+ }
+ }
+ // FIXME: is this appropriate for all content types?
+ xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType);
+ if(!args.headers || !args.headers["X-Requested-With"]){
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+ }
+ // FIXME: set other headers here!
+ try{
+ xhr.send(ioArgs.query);
+ }catch(e){
+ dfd.cancel();
+ }
+ _d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);
+ xhr = null;
+ return dfd; //Deferred
+ }
+
+ dojo._ioAddQueryToUrl = function(/*dojo.__IoCallbackArgs*/ioArgs){
+ //summary: Adds query params discovered by the io deferred construction to the URL.
+ //Only use this for operations which are fundamentally GET-type operations.
+ if(ioArgs.query.length){
+ ioArgs.url += (ioArgs.url.indexOf("?") == -1 ? "?" : "&") + ioArgs.query;
+ ioArgs.query = null;
+ }
+ }
+
+ /*=====
+ dojo.declare("dojo.__XhrArgs", dojo.__IoArgs, {
+ constructor: function(){
+ // summary:
+ // In addition to the properties listed for the dojo._IoArgs type,
+ // the following properties are allowed for dojo.xhr* methods.
+ // handleAs: String?
+ // Acceptable values are: text (default), json, json-comment-optional,
+ // json-comment-filtered, javascript, xml
+ // sync: Boolean?
+ // false is default. Indicates whether the request should
+ // be a synchronous (blocking) request.
+ // headers: Object?
+ // Additional HTTP headers to send in the request.
+ this.handleAs = handleAs;
+ this.sync = sync;
+ this.headers = headers;
+ }
+ });
+ =====*/
+
+ dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){
+ // summary:
+ // Sends an HTTP request with the given method. If the request has an
+ // HTTP body, then pass true for hasBody. The method argument should be uppercase.
+ // Also look at dojo.xhrGet(), xhrPost(), xhrPut() and dojo.xhrDelete() for shortcuts
+ // for those HTTP methods. There are also methods for "raw" PUT and POST methods
+ // via dojo.rawXhrPut() and dojo.rawXhrPost() respectively.
+ var dfd = _makeXhrDeferred(args);
+ if(!hasBody){
+ _d._ioAddQueryToUrl(dfd.ioArgs);
+ }
+ return _doIt(method, dfd); // dojo.Deferred
+ }
+
+ dojo.xhrGet = function(/*dojo.__XhrArgs*/ args){
+ // summary:
+ // Sends an HTTP GET request to the server.
+ return _d.xhr("GET", args); //dojo.Deferred
+ }
+
+ dojo.xhrPost = function(/*dojo.__XhrArgs*/ args){
+ //summary:
+ // Sends an HTTP POST request to the server.
+ return _d.xhr("POST", args, true); // dojo.Deferred
+ }
+
+ dojo.rawXhrPost = function(/*dojo.__XhrArgs*/ args){
+ // summary:
+ // Sends an HTTP POST request to the server. In addtion to the properties
+ // listed for the dojo.__XhrArgs type, the following property is allowed:
+ // postData:
+ // String. The raw data to send in the body of the POST request.
+ var dfd = _makeXhrDeferred(args);
+ dfd.ioArgs.query = args.postData;
+ return _doIt("POST", dfd); // dojo.Deferred
+ }
+
+ dojo.xhrPut = function(/*dojo.__XhrArgs*/ args){
+ // summary:
+ // Sends an HTTP PUT request to the server.
+ return _d.xhr("PUT", args, true); // dojo.Deferred
+ }
+
+ dojo.rawXhrPut = function(/*dojo.__XhrArgs*/ args){
+ // summary:
+ // Sends an HTTP PUT request to the server. In addtion to the properties
+ // listed for the dojo.__XhrArgs type, the following property is allowed:
+ // putData:
+ // String. The raw data to send in the body of the PUT request.
+ var dfd = _makeXhrDeferred(args);
+ var ioArgs = dfd.ioArgs;
+ if(args.putData){
+ ioArgs.query = args.putData;
+ args.putData = null;
+ }
+ return _doIt("PUT", dfd); // dojo.Deferred
+ }
+
+ dojo.xhrDelete = function(/*dojo.__XhrArgs*/ args){
+ // summary:
+ // Sends an HTTP DELETE request to the server.
+ return _d.xhr("DELETE", args); //dojo.Deferred
+ }
+
+ /*
+ dojo.wrapForm = function(formNode){
+ //summary:
+ // A replacement for FormBind, but not implemented yet.
+
+ // FIXME: need to think harder about what extensions to this we might
+ // want. What should we allow folks to do w/ this? What events to
+ // set/send?
+ throw new Error("dojo.wrapForm not yet implemented");
+ }
+ */
+})();
+
+}
+
+if(!dojo._hasResource["dojo._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.fx"] = true;
+dojo.provide("dojo._base.fx");
+
+
+
+
+
+
+/*
+ Animation losely package based on Dan Pupius' work, contributed under CLA:
+ http://pupius.co.uk/js/Toolkit.Drawing.js
+*/
+(function(){
+
+ var d = dojo;
+
+ dojo._Line = function(/*int*/ start, /*int*/ end){
+ // summary:
+ // dojo._Line is the object used to generate values from a start value
+ // to an end value
+ // start: int
+ // Beginning value for range
+ // end: int
+ // Ending value for range
+ this.start = start;
+ this.end = end;
+ this.getValue = function(/*float*/ n){
+ // summary: returns the point on the line
+ // n: a floating point number greater than 0 and less than 1
+ return ((this.end - this.start) * n) + this.start; // Decimal
+ }
+ }
+
+ d.declare("dojo._Animation", null, {
+ // summary
+ // A generic animation class that fires callbacks into its handlers
+ // object at various states. Nearly all dojo animation functions
+ // return an instance of this method, usually without calling the
+ // .play() method beforehand. Therefore, you will likely need to
+ // call .play() on instances of dojo._Animation when one is
+ // returned.
+ constructor: function(/*Object*/ args){
+ d.mixin(this, args);
+ if(d.isArray(this.curve)){
+ /* curve: Array
+ pId: a */
+ this.curve = new d._Line(this.curve[0], this.curve[1]);
+ }
+ },
+
+ // duration: Integer
+ // The time in milliseonds the animation will take to run
+ duration: 350,
+
+ /*=====
+ // curve: dojo._Line||Array
+ // A two element array of start and end values, or a dojo._Line instance to be
+ // used in the Animation.
+ curve: null,
+
+ // easing: Function
+ // A Function to adjust the acceleration (or deceleration) of the progress
+ // across a dojo._Line
+ easing: null,
+ =====*/
+
+ // repeat: Integer
+ // The number of times to loop the animation
+ repeat: 0,
+
+ // rate: Integer
+ // the time in milliseconds to wait before advancing to next frame
+ // (used as a fps timer: rate/1000 = fps)
+ rate: 10 /* 100 fps */,
+
+ /*=====
+ // delay: Integer
+ // The time in milliseconds to wait before starting animation after it has been .play()'ed
+ delay: null,
+
+ // events
+ //
+ // beforeBegin: Event
+ // Synthetic event fired before a dojo._Animation begins playing (synchronous)
+ beforeBegin: null,
+
+ // onBegin: Event
+ // Synthetic event fired as a dojo._Animation begins playing (useful?)
+ onBegin: null,
+
+ // onAnimate: Event
+ // Synthetic event fired at each interval of a dojo._Animation
+ onAnimate: null,
+
+ // onEnd: Event
+ // Synthetic event fired after the final frame of a dojo._Animation
+ onEnd: null,
+
+ // onPlay: Event
+ // Synthetic event fired any time a dojo._Animation is play()'ed
+ onPlay: null,
+
+ // onPause: Event
+ // Synthetic event fired when a dojo._Animation is paused
+ onPause: null,
+
+ // onStop: Event
+ // Synthetic event fires when a dojo._Animation is stopped
+ onStop: null,
+
+ =====*/
+
+ _percent: 0,
+ _startRepeatCount: 0,
+
+ _fire: function(/*Event*/ evt, /*Array?*/ args){
+ // summary:
+ // Convenience function. Fire event "evt" and pass it the
+ // arguments specified in "args".
+ // evt:
+ // The event to fire.
+ // args:
+ // The arguments to pass to the event.
+ try{
+ if(this[evt]){
+ this[evt].apply(this, args||[]);
+ }
+ }catch(e){
+ // squelch and log because we shouldn't allow exceptions in
+ // synthetic event handlers to cause the internal timer to run
+ // amuck, potentially pegging the CPU. I'm not a fan of this
+ // squelch, but hopefully logging will make it clear what's
+ // going on
+ console.error("exception in animation handler for:", evt);
+ console.error(e);
+ }
+ return this; // dojo._Animation
+ },
+
+ play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
+ // summary:
+ // Start the animation.
+ // delay:
+ // How many milliseconds to delay before starting.
+ // gotoStart:
+ // If true, starts the animation from the beginning; otherwise,
+ // starts it from its current position.
+ var _t = this;
+ if(gotoStart){
+ _t._stopTimer();
+ _t._active = _t._paused = false;
+ _t._percent = 0;
+ }else if(_t._active && !_t._paused){
+ return _t; // dojo._Animation
+ }
+
+ _t._fire("beforeBegin");
+
+ var de = delay||_t.delay;
+ var _p = dojo.hitch(_t, "_play", gotoStart);
+ if(de > 0){
+ setTimeout(_p, de);
+ return _t; // dojo._Animation
+ }
+ _p();
+ return _t;
+ },
+
+ _play: function(gotoStart){
+ var _t = this;
+ _t._startTime = new Date().valueOf();
+ if(_t._paused){
+ _t._startTime -= _t.duration * _t._percent;
+ }
+ _t._endTime = _t._startTime + _t.duration;
+
+ _t._active = true;
+ _t._paused = false;
+
+ var value = _t.curve.getValue(_t._percent);
+ if(!_t._percent){
+ if(!_t._startRepeatCount){
+ _t._startRepeatCount = _t.repeat;
+ }
+ _t._fire("onBegin", [value]);
+ }
+
+ _t._fire("onPlay", [value]);
+
+ _t._cycle();
+ return _t; // dojo._Animation
+ },
+
+ pause: function(){
+ // summary: Pauses a running animation.
+ this._stopTimer();
+ if(!this._active){ return this; /*dojo._Animation*/ }
+ this._paused = true;
+ this._fire("onPause", [this.curve.getValue(this._percent)]);
+ return this; // dojo._Animation
+ },
+
+ gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){
+ // summary:
+ // Sets the progress of the animation.
+ // percent:
+ // A percentage in decimal notation (between and including 0.0 and 1.0).
+ // andPlay:
+ // If true, play the animation after setting the progress.
+ this._stopTimer();
+ this._active = this._paused = true;
+ this._percent = percent;
+ if(andPlay){ this.play(); }
+ return this; // dojo._Animation
+ },
+
+ stop: function(/*boolean?*/ gotoEnd){
+ // summary: Stops a running animation.
+ // gotoEnd: If true, the animation will end.
+ if(!this._timer){ return this; /* dojo._Animation */ }
+ this._stopTimer();
+ if(gotoEnd){
+ this._percent = 1;
+ }
+ this._fire("onStop", [this.curve.getValue(this._percent)]);
+ this._active = this._paused = false;
+ return this; // dojo._Animation
+ },
+
+ status: function(){
+ // summary: Returns a string token representation of the status of
+ // the animation, one of: "paused", "playing", "stopped"
+ if(this._active){
+ return this._paused ? "paused" : "playing"; // String
+ }
+ return "stopped"; // String
+ },
+
+ _cycle: function(){
+ var _t = this;
+ if(_t._active){
+ var curr = new Date().valueOf();
+ var step = (curr - _t._startTime) / (_t._endTime - _t._startTime);
+
+ if(step >= 1){
+ step = 1;
+ }
+ _t._percent = step;
+
+ // Perform easing
+ if(_t.easing){
+ step = _t.easing(step);
+ }
+
+ _t._fire("onAnimate", [_t.curve.getValue(step)]);
+
+ if(_t._percent < 1){
+ _t._startTimer();
+ }else{
+ _t._active = false;
+
+ if(_t.repeat > 0){
+ _t.repeat--;
+ _t.play(null, true);
+ }else if(_t.repeat == -1){
+ _t.play(null, true);
+ }else{
+ if(_t._startRepeatCount){
+ _t.repeat = _t._startRepeatCount;
+ _t._startRepeatCount = 0;
+ }
+ }
+ _t._percent = 0;
+ _t._fire("onEnd");
+ _t._stopTimer();
+ }
+ }
+ return _t; // dojo._Animation
+ }
+ });
+
+ var ctr = 0;
+ var _globalTimerList = [];
+ var runner = {
+ run: function(){ }
+ };
+ var timer = null;
+ dojo._Animation.prototype._startTimer = function(){
+ // this._timer = setTimeout(dojo.hitch(this, "_cycle"), this.rate);
+ if(!this._timer){
+ this._timer = d.connect(runner, "run", this, "_cycle");
+ ctr++;
+ }
+ if(!timer){
+ timer = setInterval(d.hitch(runner, "run"), this.rate);
+ }
+ };
+
+ dojo._Animation.prototype._stopTimer = function(){
+ if(this._timer){
+ d.disconnect(this._timer);
+ this._timer = null;
+ ctr--;
+ }
+ if(ctr <= 0){
+ clearInterval(timer);
+ timer = null;
+ ctr = 0;
+ }
+ };
+
+ var _makeFadeable = (d.isIE) ? function(node){
+ // only set the zoom if the "tickle" value would be the same as the
+ // default
+ var ns = node.style;
+ if(!ns.zoom.length && d.style(node, "zoom") == "normal"){
+ // make sure the node "hasLayout"
+ // NOTE: this has been tested with larger and smaller user-set text
+ // sizes and works fine
+ ns.zoom = "1";
+ // node.style.zoom = "normal";
+ }
+ // don't set the width to auto if it didn't already cascade that way.
+ // We don't want to f anyones designs
+ if(!ns.width.length && d.style(node, "width") == "auto"){
+ ns.width = "auto";
+ }
+ } : function(){};
+
+ dojo._fade = function(/*Object*/ args){
+ // summary:
+ // Returns an animation that will fade the node defined by
+ // args.node from the start to end values passed (args.start
+ // args.end) (end is mandatory, start is optional)
+
+ args.node = d.byId(args.node);
+ var fArgs = d.mixin({ properties: {} }, args);
+ var props = (fArgs.properties.opacity = {});
+ props.start = !("start" in fArgs) ?
+ function(){
+ return Number(d.style(fArgs.node, "opacity"));
+ } : fArgs.start;
+ props.end = fArgs.end;
+
+ var anim = d.animateProperty(fArgs);
+ d.connect(anim, "beforeBegin", d.partial(_makeFadeable, fArgs.node));
+
+ return anim; // dojo._Animation
+ }
+
+ /*=====
+ dojo.__FadeArgs = function(node, duration, easing){
+ // node: DOMNode|String
+ // The node referenced in the animation
+ // duration: Integer?
+ // Duration of the animation in milliseconds.
+ // easing: Function?
+ // An easing function.
+ this.node = node;
+ this.duration = duration;
+ this.easing = easing;
+ }
+ =====*/
+
+ dojo.fadeIn = function(/*dojo.__FadeArgs*/ args){
+ // summary:
+ // Returns an animation that will fade node defined in 'args' from
+ // its current opacity to fully opaque.
+ return d._fade(d.mixin({ end: 1 }, args)); // dojo._Animation
+ }
+
+ dojo.fadeOut = function(/*dojo.__FadeArgs*/ args){
+ // summary:
+ // Returns an animation that will fade node defined in 'args'
+ // from its current opacity to fully transparent.
+ return d._fade(d.mixin({ end: 0 }, args)); // dojo._Animation
+ }
+
+ dojo._defaultEasing = function(/*Decimal?*/ n){
+ // summary: The default easing function for dojo._Animation(s)
+ return 0.5 + ((Math.sin((n + 1.5) * Math.PI))/2);
+ }
+
+ var PropLine = function(properties){
+ // PropLine is an internal class which is used to model the values of
+ // an a group of CSS properties across an animation lifecycle. In
+ // particular, the "getValue" function handles getting interpolated
+ // values between start and end for a particular CSS value.
+ this._properties = properties;
+ for(var p in properties){
+ var prop = properties[p];
+ if(prop.start instanceof d.Color){
+ // create a reusable temp color object to keep intermediate results
+ prop.tempColor = new d.Color();
+ }
+ }
+ this.getValue = function(r){
+ var ret = {};
+ for(var p in this._properties){
+ var prop = this._properties[p];
+ var start = prop.start;
+ if(start instanceof d.Color){
+ ret[p] = d.blendColors(start, prop.end, r, prop.tempColor).toCss();
+ }else if(!d.isArray(start)){
+ ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units||"px" : "");
+ }
+ }
+ return ret;
+ }
+ }
+
+ /*=====
+ dojo.declare("dojo.__AnimArgs", [dojo.__FadeArgs], {
+ // Properties: Object?
+ // A hash map of style properties to Objects describing the transition,
+ // such as the properties of dojo._Line with an additional 'unit' property
+ properties: {}
+
+ //TODOC: add event callbacks
+ });
+ =====*/
+
+ dojo.animateProperty = function(/*dojo.__AnimArgs*/ args){
+ // summary:
+ // Returns an animation that will transition the properties of
+ // node defined in 'args' depending how they are defined in
+ // 'args.properties'
+ //
+ // description:
+ // dojo.animateProperty is the foundation of most dojo.fx
+ // animations. It takes an object of "properties" corresponding to
+ // style properties, and animates them in parallel over a set
+ // duration.
+ //
+ // example:
+ // A simple animation that changes the width of the specified node.
+ // | dojo.animateProperty({
+ // | node: "nodeId",
+ // | properties: { width: 400 },
+ // | }).play();
+ // Dojo figures out the start value for the width and converts the
+ // integer specified for the width to the more expressive but
+ // verbose form `{ width: { end: '400', units: 'px' } }` which you
+ // can also specify directly
+ // example:
+ // animate width, height, and padding over 2 seconds...the
+ // pedantic way:
+ // | dojo.animateProperty({ node: node, duration:2000,
+ // | properties: {
+ // | width: { start: '200', end: '400', unit:"px" },
+ // | height: { start:'200', end: '400', unit:"px" },
+ // | paddingTop: { start:'5', end:'50', unit:"px" }
+ // | }
+ // | }).play();
+ //
+ // example:
+ // plug in a different easing function and register a callback for
+ // when the animation ends. Easing functions accept values between
+ // zero and one and return a value on that basis. In this case, an
+ // exponential-in curve.
+ // | dojo.animateProperty({
+ // | node: "nodeId",
+ // | // dojo figures out the start value
+ // | properties: { width: { end: 400 } },
+ // | easing: function(n){
+ // | return (n==0) ? 0 : Math.pow(2, 10 * (n - 1));
+ // | },
+ // | onEnd: function(){
+ // | // called when the animation finishes
+ // | }
+ // | }).play(500); // delay playing half a second
+
+ args.node = d.byId(args.node);
+ if(!args.easing){ args.easing = d._defaultEasing; }
+
+ var anim = new d._Animation(args);
+ d.connect(anim, "beforeBegin", anim, function(){
+ var pm = {};
+ for(var p in this.properties){
+ // Make shallow copy of properties into pm because we overwrite
+ // some values below. In particular if start/end are functions
+ // we don't want to overwrite them or the functions won't be
+ // called if the animation is reused.
+ if(p == "width" || p == "height"){
+ this.node.display = "block";
+ }
+ var prop = this.properties[p];
+ prop = pm[p] = d.mixin({}, (d.isObject(prop) ? prop: { end: prop }));
+
+ if(d.isFunction(prop.start)){
+ prop.start = prop.start();
+ }
+ if(d.isFunction(prop.end)){
+ prop.end = prop.end();
+ }
+ var isColor = (p.toLowerCase().indexOf("color") >= 0);
+ function getStyle(node, p){
+ // dojo.style(node, "height") can return "auto" or "" on IE; this is more reliable:
+ var v = ({height: node.offsetHeight, width: node.offsetWidth})[p];
+ if(v !== undefined){ return v; }
+ v = d.style(node, p);
+ return (p=="opacity") ? Number(v) : (isColor ? v : parseFloat(v));
+ }
+ if(!("end" in prop)){
+ prop.end = getStyle(this.node, p);
+ }else if(!("start" in prop)){
+ prop.start = getStyle(this.node, p);
+ }
+
+ if(isColor){
+ prop.start = new d.Color(prop.start);
+ prop.end = new d.Color(prop.end);
+ }else{
+ prop.start = (p == "opacity") ? Number(prop.start) : parseFloat(prop.start);
+ }
+ }
+ this.curve = new PropLine(pm);
+ });
+ d.connect(anim, "onAnimate", anim, function(propValues){
+ // try{
+ for(var s in propValues){
+ d.style(this.node, s, propValues[s]);
+ // this.node.style[s] = propValues[s];
+ }
+ });
+ return anim; // dojo._Animation
+ }
+
+ dojo.anim = function( /*DOMNode|String*/ node,
+ /*Object*/ properties,
+ /*Integer?*/ duration,
+ /*Function?*/ easing,
+ /*Function?*/ onEnd,
+ /*Integer?*/ delay){
+ // summary:
+ // A simpler interface to `dojo.animateProperty()`, also returns
+ // an instance of `dojo._Animation` but begins the animation
+ // immediately, unlike nearly every other Dojo animation API.
+ // description:
+ // `dojo.anim` is a simpler (but somewhat less powerful) version
+ // of `dojo.animateProperty`. It uses defaults for many basic properties
+ // and allows for positional parameters to be used in place of the
+ // packed "property bag" which is used for other Dojo animation
+ // methods.
+ //
+ // The `dojo._Animation` object returned from `dojo.anim` will be
+ // already playing when it is returned from this function, so
+ // calling play() on it again is (usually) a no-op.
+ // node:
+ // a DOM node or the id of a node to animate CSS properties on
+ // duration:
+ // The number of milliseconds over which the animation
+ // should run. Defaults to the global animation default duration
+ // (350ms).
+ // easing:
+ // An easing function over which to calculate acceleration
+ // and deceleration of the animation through its duration.
+ // A default easing algorithm is provided, but you may
+ // plug in any you wish. A large selection of easing algorithms
+ // are available in `dojox.fx.easing`.
+ // onEnd:
+ // A function to be called when the animation finishes
+ // running.
+ // delay:
+ // The number of milliseconds to delay beginning the
+ // animation by. The default is 0.
+ // example:
+ // Fade out a node
+ // | dojo.anim("id", { opacity: 0 });
+ // example:
+ // Fade out a node over a full second
+ // | dojo.anim("id", { opacity: 0 }, 1000);
+ return d.animateProperty({
+ node: node,
+ duration: duration||d._Animation.prototype.duration,
+ properties: properties,
+ easing: easing,
+ onEnd: onEnd
+ }).play(delay||0);
+ }
+})();
+
+}
+
+if(!dojo._hasResource["dojo._base.browser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.browser"] = true;
+dojo.provide("dojo._base.browser");
+
+
+
+
+
+
+
+
+
+//Need this to be the last code segment in base, so do not place any
+//dojo.requireIf calls in this file. Otherwise, due to how the build system
+//puts all requireIf dependencies after the current file, the require calls
+//could be called before all of base is defined.
+if(dojo.config.require){
+ dojo.forEach(dojo.config.require, "dojo['require'](item);");
+}
+
+}
+
+
+ if(dojo.config.afterOnLoad && dojo.isBrowser){
+ //Dojo is being added to the page after page load, so just trigger
+ //the init sequence after a timeout. Using a timeout so the rest of this
+ //script gets evaluated properly. This work needs to happen after the
+ //dojo.config.require work done in dojo._base.
+ window.setTimeout(dojo._fakeLoadInit, 1000);
+ }
+
+})();
+
diff --git a/includes/js/dojo/fx.js b/includes/js/dojo/fx.js
new file mode 100644
index 0000000..1473531
--- /dev/null
+++ b/includes/js/dojo/fx.js
@@ -0,0 +1,415 @@
+if(!dojo._hasResource["dojo.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.fx"] = true;
+dojo.provide("dojo.fx");
+dojo.provide("dojo.fx.Toggler");
+
+/*=====
+dojo.fx = {
+ // summary: Effects library on top of Base animations
+};
+=====*/
+
+(function(){
+ var _baseObj = {
+ _fire: function(evt, args){
+ if(this[evt]){
+ this[evt].apply(this, args||[]);
+ }
+ return this;
+ }
+ };
+
+ var _chain = function(animations){
+ this._index = -1;
+ this._animations = animations||[];
+ this._current = this._onAnimateCtx = this._onEndCtx = null;
+
+ this.duration = 0;
+ dojo.forEach(this._animations, function(a){
+ this.duration += a.duration;
+ if(a.delay){ this.duration += a.delay; }
+ }, this);
+ };
+ dojo.extend(_chain, {
+ _onAnimate: function(){
+ this._fire("onAnimate", arguments);
+ },
+ _onEnd: function(){
+ dojo.disconnect(this._onAnimateCtx);
+ dojo.disconnect(this._onEndCtx);
+ this._onAnimateCtx = this._onEndCtx = null;
+ if(this._index + 1 == this._animations.length){
+ this._fire("onEnd");
+ }else{
+ // switch animations
+ this._current = this._animations[++this._index];
+ this._onAnimateCtx = dojo.connect(this._current, "onAnimate", this, "_onAnimate");
+ this._onEndCtx = dojo.connect(this._current, "onEnd", this, "_onEnd");
+ this._current.play(0, true);
+ }
+ },
+ play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
+ if(!this._current){ this._current = this._animations[this._index = 0]; }
+ if(!gotoStart && this._current.status() == "playing"){ return this; }
+ var beforeBegin = dojo.connect(this._current, "beforeBegin", this, function(){
+ this._fire("beforeBegin");
+ }),
+ onBegin = dojo.connect(this._current, "onBegin", this, function(arg){
+ this._fire("onBegin", arguments);
+ }),
+ onPlay = dojo.connect(this._current, "onPlay", this, function(arg){
+ this._fire("onPlay", arguments);
+ dojo.disconnect(beforeBegin);
+ dojo.disconnect(onBegin);
+ dojo.disconnect(onPlay);
+ });
+ if(this._onAnimateCtx){
+ dojo.disconnect(this._onAnimateCtx);
+ }
+ this._onAnimateCtx = dojo.connect(this._current, "onAnimate", this, "_onAnimate");
+ if(this._onEndCtx){
+ dojo.disconnect(this._onEndCtx);
+ }
+ this._onEndCtx = dojo.connect(this._current, "onEnd", this, "_onEnd");
+ this._current.play.apply(this._current, arguments);
+ return this;
+ },
+ pause: function(){
+ if(this._current){
+ var e = dojo.connect(this._current, "onPause", this, function(arg){
+ this._fire("onPause", arguments);
+ dojo.disconnect(e);
+ });
+ this._current.pause();
+ }
+ return this;
+ },
+ gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
+ this.pause();
+ var offset = this.duration * percent;
+ this._current = null;
+ dojo.some(this._animations, function(a){
+ if(a.duration <= offset){
+ this._current = a;
+ return true;
+ }
+ offset -= a.duration;
+ return false;
+ });
+ if(this._current){
+ this._current.gotoPercent(offset / _current.duration, andPlay);
+ }
+ return this;
+ },
+ stop: function(/*boolean?*/ gotoEnd){
+ if(this._current){
+ if(gotoEnd){
+ for(; this._index + 1 < this._animations.length; ++this._index){
+ this._animations[this._index].stop(true);
+ }
+ this._current = this._animations[this._index];
+ }
+ var e = dojo.connect(this._current, "onStop", this, function(arg){
+ this._fire("onStop", arguments);
+ dojo.disconnect(e);
+ });
+ this._current.stop();
+ }
+ return this;
+ },
+ status: function(){
+ return this._current ? this._current.status() : "stopped";
+ },
+ destroy: function(){
+ if(this._onAnimateCtx){ dojo.disconnect(this._onAnimateCtx); }
+ if(this._onEndCtx){ dojo.disconnect(this._onEndCtx); }
+ }
+ });
+ dojo.extend(_chain, _baseObj);
+
+ dojo.fx.chain = function(/*dojo._Animation[]*/ animations){
+ // summary: Chain a list of dojo._Animation s to run in sequence
+ // example:
+ // | dojo.fx.chain([
+ // | dojo.fadeIn({ node:node }),
+ // | dojo.fadeOut({ node:otherNode })
+ // | ]).play();
+ //
+ return new _chain(animations) // dojo._Animation
+ };
+
+ var _combine = function(animations){
+ this._animations = animations||[];
+ this._connects = [];
+ this._finished = 0;
+
+ this.duration = 0;
+ dojo.forEach(animations, function(a){
+ var duration = a.duration;
+ if(a.delay){ duration += a.delay; }
+ if(this.duration < duration){ this.duration = duration; }
+ this._connects.push(dojo.connect(a, "onEnd", this, "_onEnd"));
+ }, this);
+
+ this._pseudoAnimation = new dojo._Animation({curve: [0, 1], duration: this.duration});
+ dojo.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop"],
+ function(evt){
+ this._connects.push(dojo.connect(this._pseudoAnimation, evt, dojo.hitch(this, "_fire", evt)));
+ },
+ this
+ );
+ };
+ dojo.extend(_combine, {
+ _doAction: function(action, args){
+ dojo.forEach(this._animations, function(a){
+ a[action].apply(a, args);
+ });
+ return this;
+ },
+ _onEnd: function(){
+ if(++this._finished == this._animations.length){
+ this._fire("onEnd");
+ }
+ },
+ _call: function(action, args){
+ var t = this._pseudoAnimation;
+ t[action].apply(t, args);
+ },
+ play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
+ this._finished = 0;
+ this._doAction("play", arguments);
+ this._call("play", arguments);
+ return this;
+ },
+ pause: function(){
+ this._doAction("pause", arguments);
+ this._call("pause", arguments);
+ return this;
+ },
+ gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
+ var ms = this.duration * percent;
+ dojo.forEach(this._animations, function(a){
+ a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay);
+ });
+ this._call("gotoProcent", arguments);
+ return this;
+ },
+ stop: function(/*boolean?*/ gotoEnd){
+ this._doAction("stop", arguments);
+ this._call("stop", arguments);
+ return this;
+ },
+ status: function(){
+ return this._pseudoAnimation.status();
+ },
+ destroy: function(){
+ dojo.forEach(this._connects, dojo.disconnect);
+ }
+ });
+ dojo.extend(_combine, _baseObj);
+
+ dojo.fx.combine = function(/*dojo._Animation[]*/ animations){
+ // summary: Combine a list of dojo._Animation s to run in parallel
+ // example:
+ // | dojo.fx.combine([
+ // | dojo.fadeIn({ node:node }),
+ // | dojo.fadeOut({ node:otherNode })
+ // | ]).play();
+ return new _combine(animations); // dojo._Animation
+ };
+})();
+
+dojo.declare("dojo.fx.Toggler", null, {
+ // summary:
+ // class constructor for an animation toggler. It accepts a packed
+ // set of arguments about what type of animation to use in each
+ // direction, duration, etc.
+ //
+ // example:
+ // | var t = new dojo.fx.Toggler({
+ // | node: "nodeId",
+ // | showDuration: 500,
+ // | // hideDuration will default to "200"
+ // | showFunc: dojo.wipeIn,
+ // | // hideFunc will default to "fadeOut"
+ // | });
+ // | t.show(100); // delay showing for 100ms
+ // | // ...time passes...
+ // | t.hide();
+
+ // FIXME: need a policy for where the toggler should "be" the next
+ // time show/hide are called if we're stopped somewhere in the
+ // middle.
+
+ constructor: function(args){
+ var _t = this;
+
+ dojo.mixin(_t, args);
+ _t.node = args.node;
+ _t._showArgs = dojo.mixin({}, args);
+ _t._showArgs.node = _t.node;
+ _t._showArgs.duration = _t.showDuration;
+ _t.showAnim = _t.showFunc(_t._showArgs);
+
+ _t._hideArgs = dojo.mixin({}, args);
+ _t._hideArgs.node = _t.node;
+ _t._hideArgs.duration = _t.hideDuration;
+ _t.hideAnim = _t.hideFunc(_t._hideArgs);
+
+ dojo.connect(_t.showAnim, "beforeBegin", dojo.hitch(_t.hideAnim, "stop", true));
+ dojo.connect(_t.hideAnim, "beforeBegin", dojo.hitch(_t.showAnim, "stop", true));
+ },
+
+ // node: DomNode
+ // the node to toggle
+ node: null,
+
+ // showFunc: Function
+ // The function that returns the dojo._Animation to show the node
+ showFunc: dojo.fadeIn,
+
+ // hideFunc: Function
+ // The function that returns the dojo._Animation to hide the node
+ hideFunc: dojo.fadeOut,
+
+ // showDuration:
+ // Time in milliseconds to run the show Animation
+ showDuration: 200,
+
+ // hideDuration:
+ // Time in milliseconds to run the hide Animation
+ hideDuration: 200,
+
+ /*=====
+ _showArgs: null,
+ _showAnim: null,
+
+ _hideArgs: null,
+ _hideAnim: null,
+
+ _isShowing: false,
+ _isHiding: false,
+ =====*/
+
+ show: function(delay){
+ // summary: Toggle the node to showing
+ return this.showAnim.play(delay || 0);
+ },
+
+ hide: function(delay){
+ // summary: Toggle the node to hidden
+ return this.hideAnim.play(delay || 0);
+ }
+});
+
+dojo.fx.wipeIn = function(/*Object*/ args){
+ // summary
+ // Returns an animation that will expand the
+ // node defined in 'args' object from it's current height to
+ // it's natural height (with no scrollbar).
+ // Node must have no margin/border/padding.
+ args.node = dojo.byId(args.node);
+ var node = args.node, s = node.style;
+
+ var anim = dojo.animateProperty(dojo.mixin({
+ properties: {
+ height: {
+ // 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.height="1px";
+ s.display="";
+ s.visibility="";
+ return 1;
+ }else{
+ var height = dojo.style(node, "height");
+ return Math.max(height, 1);
+ }
+ },
+ end: function(){
+ return node.scrollHeight;
+ }
+ }
+ }
+ }, args));
+
+ dojo.connect(anim, "onEnd", function(){
+ s.height = "auto";
+ });
+
+ return anim; // dojo._Animation
+}
+
+dojo.fx.wipeOut = function(/*Object*/ args){
+ // summary
+ // Returns an animation that will shrink node defined in "args"
+ // from it's current height to 1px, and then hide it.
+ var node = args.node = dojo.byId(args.node);
+ var s = node.style;
+
+ var anim = dojo.animateProperty(dojo.mixin({
+ properties: {
+ height: {
+ end: 1 // 0 causes IE to display the whole panel
+ }
+ }
+ }, args));
+
+ dojo.connect(anim, "beforeBegin", function(){
+ s.overflow = "hidden";
+ s.display = "";
+ });
+ dojo.connect(anim, "onEnd", function(){
+ s.height = "auto";
+ s.display = "none";
+ });
+
+ return anim; // dojo._Animation
+}
+
+dojo.fx.slideTo = function(/*Object?*/ args){
+ // summary
+ // Returns an animation that will slide "node"
+ // defined in args Object from its current position to
+ // the position defined by (args.left, args.top).
+ // example:
+ // | dojo.fx.slideTo({ node: node, left:"40", top:"50", unit:"px" }).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: {
+ top: { end: args.top||0 },
+ left: { end: args.left||0 }
+ }
+ }, args));
+ dojo.connect(anim, "beforeBegin", anim, init);
+
+ return anim; // dojo._Animation
+}
+
+}
diff --git a/includes/js/dojo/i18n.js b/includes/js/dojo/i18n.js
new file mode 100644
index 0000000..6f417b3
--- /dev/null
+++ b/includes/js/dojo/i18n.js
@@ -0,0 +1,249 @@
+if(!dojo._hasResource["dojo.i18n"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.i18n"] = true;
+dojo.provide("dojo.i18n");
+
+/*=====
+dojo.i18n = {
+ // summary: Utility classes to enable loading of resources for internationalization (i18n)
+};
+=====*/
+
+dojo.i18n.getLocalization = function(/*String*/packageName, /*String*/bundleName, /*String?*/locale){
+ // summary:
+ // Returns an Object containing the localization for a given resource
+ // bundle in a package, matching the specified locale.
+ // description:
+ // Returns a hash containing name/value pairs in its prototypesuch
+ // that values can be easily overridden. Throws an exception if the
+ // bundle is not found. Bundle must have already been loaded by
+ // `dojo.requireLocalization()` or by a build optimization step. NOTE:
+ // try not to call this method as part of an object property
+ // definition (`var foo = { bar: dojo.i18n.getLocalization() }`). In
+ // some loading situations, the bundle may not be available in time
+ // for the object definition. Instead, call this method inside a
+ // function that is run after all modules load or the page loads (like
+ // in `dojo.addOnLoad()`), or in a widget lifecycle method.
+ // packageName:
+ // package which is associated with this resource
+ // bundleName:
+ // the base filename of the resource bundle (without the ".js" suffix)
+ // locale:
+ // the variant to load (optional). By default, the locale defined by
+ // the host environment: dojo.locale
+
+ locale = dojo.i18n.normalizeLocale(locale);
+
+ // look for nearest locale match
+ var elements = locale.split('-');
+ var module = [packageName,"nls",bundleName].join('.');
+ var bundle = dojo._loadedModules[module];
+ if(bundle){
+ var localization;
+ for(var i = elements.length; i > 0; i--){
+ var loc = elements.slice(0, i).join('_');
+ if(bundle[loc]){
+ localization = bundle[loc];
+ break;
+ }
+ }
+ if(!localization){
+ localization = bundle.ROOT;
+ }
+
+ // make a singleton prototype so that the caller won't accidentally change the values globally
+ if(localization){
+ var clazz = function(){};
+ clazz.prototype = localization;
+ return new clazz(); // Object
+ }
+ }
+
+ throw new Error("Bundle not found: " + bundleName + " in " + packageName+" , locale=" + locale);
+};
+
+dojo.i18n.normalizeLocale = function(/*String?*/locale){
+ // summary:
+ // Returns canonical form of locale, as used by Dojo.
+ //
+ // description:
+ // All variants are case-insensitive and are separated by '-' as specified in [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt).
+ // If no locale is specified, the dojo.locale is returned. dojo.locale is defined by
+ // the user agent's locale unless overridden by djConfig.
+
+ var result = locale ? locale.toLowerCase() : dojo.locale;
+ if(result == "root"){
+ result = "ROOT";
+ }
+ return result; // String
+};
+
+dojo.i18n._requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
+ // summary:
+ // See dojo.requireLocalization()
+ // description:
+ // Called by the bootstrap, but factored out so that it is only
+ // included in the build when needed.
+
+ var targetLocale = dojo.i18n.normalizeLocale(locale);
+ var bundlePackage = [moduleName, "nls", bundleName].join(".");
+ // NOTE:
+ // When loading these resources, the packaging does not match what is
+ // on disk. This is an implementation detail, as this is just a
+ // private data structure to hold the loaded resources. e.g.
+ // `tests/hello/nls/en-us/salutations.js` is loaded as the object
+ // `tests.hello.nls.salutations.en_us={...}` The structure on disk is
+ // intended to be most convenient for developers and translators, but
+ // in memory it is more logical and efficient to store in a different
+ // order. Locales cannot use dashes, since the resulting path will
+ // not evaluate as valid JS, so we translate them to underscores.
+
+ //Find the best-match locale to load if we have available flat locales.
+ var bestLocale = "";
+ if(availableFlatLocales){
+ var flatLocales = availableFlatLocales.split(",");
+ for(var i = 0; i < flatLocales.length; i++){
+ //Locale must match from start of string.
+ if(targetLocale.indexOf(flatLocales[i]) == 0){
+ if(flatLocales[i].length > bestLocale.length){
+ bestLocale = flatLocales[i];
+ }
+ }
+ }
+ if(!bestLocale){
+ bestLocale = "ROOT";
+ }
+ }
+
+ //See if the desired locale is already loaded.
+ var tempLocale = availableFlatLocales ? bestLocale : targetLocale;
+ var bundle = dojo._loadedModules[bundlePackage];
+ var localizedBundle = null;
+ if(bundle){
+ if(dojo.config.localizationComplete && bundle._built){return;}
+ var jsLoc = tempLocale.replace(/-/g, '_');
+ var translationPackage = bundlePackage+"."+jsLoc;
+ localizedBundle = dojo._loadedModules[translationPackage];
+ }
+
+ if(!localizedBundle){
+ bundle = dojo["provide"](bundlePackage);
+ var syms = dojo._getModuleSymbols(moduleName);
+ var modpath = syms.concat("nls").join("/");
+ var parent;
+
+ dojo.i18n._searchLocalePath(tempLocale, availableFlatLocales, function(loc){
+ var jsLoc = loc.replace(/-/g, '_');
+ var translationPackage = bundlePackage + "." + jsLoc;
+ var loaded = false;
+ if(!dojo._loadedModules[translationPackage]){
+ // Mark loaded whether it's found or not, so that further load attempts will not be made
+ dojo["provide"](translationPackage);
+ var module = [modpath];
+ if(loc != "ROOT"){module.push(loc);}
+ module.push(bundleName);
+ var filespec = module.join("/") + '.js';
+ loaded = dojo._loadPath(filespec, null, function(hash){
+ // Use singleton with prototype to point to parent bundle, then mix-in result from loadPath
+ var clazz = function(){};
+ clazz.prototype = parent;
+ bundle[jsLoc] = new clazz();
+ for(var j in hash){ bundle[jsLoc][j] = hash[j]; }
+ });
+ }else{
+ loaded = true;
+ }
+ if(loaded && bundle[jsLoc]){
+ parent = bundle[jsLoc];
+ }else{
+ bundle[jsLoc] = parent;
+ }
+
+ if(availableFlatLocales){
+ //Stop the locale path searching if we know the availableFlatLocales, since
+ //the first call to this function will load the only bundle that is needed.
+ return true;
+ }
+ });
+ }
+
+ //Save the best locale bundle as the target locale bundle when we know the
+ //the available bundles.
+ if(availableFlatLocales && targetLocale != bestLocale){
+ bundle[targetLocale.replace(/-/g, '_')] = bundle[bestLocale.replace(/-/g, '_')];
+ }
+};
+
+(function(){
+ // If other locales are used, dojo.requireLocalization should load them as
+ // well, by default.
+ //
+ // Override dojo.requireLocalization to do load the default bundle, then
+ // iterate through the extraLocale list and load those translations as
+ // well, unless a particular locale was requested.
+
+ var extra = dojo.config.extraLocale;
+ if(extra){
+ if(!extra instanceof Array){
+ extra = [extra];
+ }
+
+ var req = dojo.i18n._requireLocalization;
+ dojo.i18n._requireLocalization = function(m, b, locale, availableFlatLocales){
+ req(m,b,locale, availableFlatLocales);
+ if(locale){return;}
+ for(var i=0; i<extra.length; i++){
+ req(m,b,extra[i], availableFlatLocales);
+ }
+ };
+ }
+})();
+
+dojo.i18n._searchLocalePath = function(/*String*/locale, /*Boolean*/down, /*Function*/searchFunc){
+ // summary:
+ // A helper method to assist in searching for locale-based resources.
+ // Will iterate through the variants of a particular locale, either up
+ // or down, executing a callback function. For example, "en-us" and
+ // true will try "en-us" followed by "en" and finally "ROOT".
+
+ locale = dojo.i18n.normalizeLocale(locale);
+
+ var elements = locale.split('-');
+ var searchlist = [];
+ for(var i = elements.length; i > 0; i--){
+ searchlist.push(elements.slice(0, i).join('-'));
+ }
+ searchlist.push(false);
+ if(down){searchlist.reverse();}
+
+ for(var j = searchlist.length - 1; j >= 0; j--){
+ var loc = searchlist[j] || "ROOT";
+ var stop = searchFunc(loc);
+ if(stop){ break; }
+ }
+};
+
+dojo.i18n._preloadLocalizations = function(/*String*/bundlePrefix, /*Array*/localesGenerated){
+ // summary:
+ // Load built, flattened resource bundles, if available for all
+ // locales used in the page. Only called by built layer files.
+
+ function preload(locale){
+ locale = dojo.i18n.normalizeLocale(locale);
+ dojo.i18n._searchLocalePath(locale, true, function(loc){
+ for(var i=0; i<localesGenerated.length;i++){
+ if(localesGenerated[i] == loc){
+ dojo["require"](bundlePrefix+"_"+loc);
+ return true; // Boolean
+ }
+ }
+ return false; // Boolean
+ });
+ }
+ preload();
+ var extra = dojo.config.extraLocale||[];
+ for(var i=0; i<extra.length; i++){
+ preload(extra[i]);
+ }
+};
+
+}
diff --git a/includes/js/dojo/io/iframe.js b/includes/js/dojo/io/iframe.js
new file mode 100644
index 0000000..a3003ba
--- /dev/null
+++ b/includes/js/dojo/io/iframe.js
@@ -0,0 +1,358 @@
+if(!dojo._hasResource["dojo.io.iframe"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.io.iframe"] = true;
+dojo.provide("dojo.io.iframe");
+
+dojo.io.iframe = {
+ create: function(/*String*/fname, /*String*/onloadstr, /*String?*/uri){
+ // summary:
+ // Creates a hidden iframe in the page. Used mostly for IO
+ // transports. You do not need to call this to start a
+ // dojo.io.iframe request. Just call send().
+ // fname: String
+ // The name of the iframe. Used for the name attribute on the
+ // iframe.
+ // onloadstr: String
+ // A string of JavaScript that will be executed when the content
+ // in the iframe loads.
+ // uri: String
+ // The value of the src attribute on the iframe element. If a
+ // value is not given, then dojo/resources/blank.html will be
+ // used.
+ if(window[fname]){ return window[fname]; }
+ if(window.frames[fname]){ return window.frames[fname]; }
+ var cframe = null;
+ var turi = uri;
+ if(!turi){
+ if(dojo.config["useXDomain"] && !dojo.config["dojoBlankHtmlUrl"]){
+ console.debug("dojo.io.iframe.create: When using cross-domain Dojo builds,"
+ + " please save dojo/resources/blank.html to your domain and set djConfig.dojoBlankHtmlUrl"
+ + " to the path on your domain to blank.html");
+ }
+ turi = (dojo.config["dojoBlankHtmlUrl"]||dojo.moduleUrl("dojo", "resources/blank.html"));
+ }
+ var ifrstr = dojo.isIE ? '<iframe name="'+fname+'" src="'+turi+'" onload="'+onloadstr+'">' : 'iframe';
+ cframe = dojo.doc.createElement(ifrstr);
+ with(cframe){
+ name = fname;
+ setAttribute("name", fname);
+ id = fname;
+ }
+ dojo.body().appendChild(cframe);
+ window[fname] = cframe;
+
+ with(cframe.style){
+ if(dojo.isSafari < 3){
+ //We can't change the src in Safari 2.0.3 if absolute position. Bizarro.
+ position = "absolute";
+ }
+ left = top = "1px";
+ height = width = "1px";
+ visibility = "hidden";
+ }
+
+ if(!dojo.isIE){
+ this.setSrc(cframe, turi, true);
+ cframe.onload = new Function(onloadstr);
+ }
+
+ return cframe;
+ },
+
+ setSrc: function(/*DOMNode*/iframe, /*String*/src, /*Boolean*/replace){
+ //summary:
+ // Sets the URL that is loaded in an IFrame. The replace parameter
+ // indicates whether location.replace() should be used when
+ // changing the location of the iframe.
+ try{
+ if(!replace){
+ if(dojo.isSafari){
+ iframe.location = src;
+ }else{
+ frames[iframe.name].location = src;
+ }
+ }else{
+ // Fun with DOM 0 incompatibilities!
+ var idoc;
+ if(dojo.isIE || dojo.isSafari > 2){
+ idoc = iframe.contentWindow.document;
+ }else if(dojo.isSafari){
+ idoc = iframe.document;
+ }else{ // if(d.isMozilla){
+ idoc = iframe.contentWindow;
+ }
+
+ //For Safari (at least 2.0.3) and Opera, if the iframe
+ //has just been created but it doesn't have content
+ //yet, then iframe.document may be null. In that case,
+ //use iframe.location and return.
+ if(!idoc){
+ iframe.location = src;
+ return;
+ }else{
+ idoc.location.replace(src);
+ }
+ }
+ }catch(e){
+ console.debug("dojo.io.iframe.setSrc: ", e);
+ }
+ },
+
+ doc: function(/*DOMNode*/iframeNode){
+ //summary: Returns the document object associated with the iframe DOM Node argument.
+ var doc = iframeNode.contentDocument || // W3
+ (
+ (
+ (iframeNode.name) && (iframeNode.document) &&
+ (document.getElementsByTagName("iframe")[iframeNode.name].contentWindow) &&
+ (document.getElementsByTagName("iframe")[iframeNode.name].contentWindow.document)
+ )
+ ) || // IE
+ (
+ (iframeNode.name)&&(document.frames[iframeNode.name])&&
+ (document.frames[iframeNode.name].document)
+ ) || null;
+ return doc;
+ },
+
+ /*=====
+ dojo.io.iframe.__ioArgs = function(kwArgs){
+ // summary:
+ // All the properties described in the dojo.__ioArgs type, apply
+ // to this type. The following additional properties are allowed
+ // for dojo.io.iframe.send():
+ // method: String?
+ // The HTTP method to use. "GET" or "POST" are the only supported
+ // values. It will try to read the value from the form node's
+ // method, then try this argument. If neither one exists, then it
+ // defaults to POST.
+ // handleAs: String?
+ // Specifies what format the result data should be given to the
+ // load/handle callback. Valid values are: text, html, javascript,
+ // json. IMPORTANT: For all values EXCEPT html, The server
+ // response should be an HTML file with a textarea element. The
+ // response data should be inside the textarea element. Using an
+ // HTML document the only reliable, cross-browser way this
+ // transport can know when the response has loaded. For the html
+ // handleAs value, just return a normal HTML document. NOTE: xml
+ // or any other XML type is NOT supported by this transport.
+ // content: Object?
+ // If "form" is one of the other args properties, then the content
+ // object properties become hidden form form elements. For
+ // instance, a content object of {name1 : "value1"} is converted
+ // to a hidden form element with a name of "name1" and a value of
+ // "value1". If there is not a "form" property, then the content
+ // object is converted into a name=value&name=value string, by
+ // using dojo.objectToQuery().
+ }
+ =====*/
+
+ send: function(/*dojo.io.iframe.__ioArgs*/args){
+ //summary: function that sends the request to the server.
+ //This transport can only process one send() request at a time, so if send() is called
+ //multiple times, it will queue up the calls and only process one at a time.
+ if(!this["_frame"]){
+ this._frame = this.create(this._iframeName, dojo._scopeName + ".io.iframe._iframeOnload();");
+ }
+
+ //Set up the deferred.
+ var dfd = dojo._ioSetArgs(
+ args,
+ function(/*Deferred*/dfd){
+ //summary: canceller function for dojo._ioSetArgs call.
+ dfd.canceled = true;
+ dfd.ioArgs._callNext();
+ },
+ function(/*Deferred*/dfd){
+ //summary: okHandler function for dojo._ioSetArgs call.
+ var value = null;
+ try{
+ var ioArgs = dfd.ioArgs;
+ var dii = dojo.io.iframe;
+ var ifd = dii.doc(dii._frame);
+ var handleAs = ioArgs.handleAs;
+
+ //Assign correct value based on handleAs value.
+ value = ifd; //html
+ if(handleAs != "html"){
+ value = ifd.getElementsByTagName("textarea")[0].value; //text
+ if(handleAs == "json"){
+ value = dojo.fromJson(value); //json
+ }else if(handleAs == "javascript"){
+ value = dojo.eval(value); //javascript
+ }
+ }
+ }catch(e){
+ value = e;
+ }finally{
+ ioArgs._callNext();
+ }
+ return value;
+ },
+ function(/*Error*/error, /*Deferred*/dfd){
+ //summary: errHandler function for dojo._ioSetArgs call.
+ dfd.ioArgs._hasError = true;
+ dfd.ioArgs._callNext();
+ return error;
+ }
+ );
+
+ //Set up a function that will fire the next iframe request. Make sure it only
+ //happens once per deferred.
+ dfd.ioArgs._callNext = function(){
+ if(!this["_calledNext"]){
+ this._calledNext = true;
+ dojo.io.iframe._currentDfd = null;
+ dojo.io.iframe._fireNextRequest();
+ }
+ }
+
+ this._dfdQueue.push(dfd);
+ this._fireNextRequest();
+
+ //Add it the IO watch queue, to get things like timeout support.
+ dojo._ioWatch(
+ dfd,
+ function(/*Deferred*/dfd){
+ //validCheck
+ return !dfd.ioArgs["_hasError"];
+ },
+ function(dfd){
+ //ioCheck
+ return (!!dfd.ioArgs["_finished"]);
+ },
+ function(dfd){
+ //resHandle
+ if(dfd.ioArgs._finished){
+ dfd.callback(dfd);
+ }else{
+ dfd.errback(new Error("Invalid dojo.io.iframe request state"));
+ }
+ }
+ );
+
+ return dfd;
+ },
+
+ _currentDfd: null,
+ _dfdQueue: [],
+ _iframeName: dojo._scopeName + "IoIframe",
+
+ _fireNextRequest: function(){
+ //summary: Internal method used to fire the next request in the bind queue.
+ try{
+ if((this._currentDfd)||(this._dfdQueue.length == 0)){ return; }
+ var dfd = this._currentDfd = this._dfdQueue.shift();
+ var ioArgs = dfd.ioArgs;
+ var args = ioArgs.args;
+
+ ioArgs._contentToClean = [];
+ var fn = dojo.byId(args["form"]);
+ var content = args["content"] || {};
+ if(fn){
+ if(content){
+ // if we have things in content, we need to add them to the form
+ // before submission
+ for(var x in content){
+ if(!fn[x]){
+ var tn;
+ if(dojo.isIE){
+ tn = dojo.doc.createElement("<input type='hidden' name='"+x+"'>");
+ }else{
+ tn = dojo.doc.createElement("input");
+ tn.type = "hidden";
+ tn.name = x;
+ }
+ tn.value = content[x];
+ fn.appendChild(tn);
+ ioArgs._contentToClean.push(x);
+ }else{
+ fn[x].value = content[x];
+ }
+ }
+ }
+ //IE requires going through getAttributeNode instead of just getAttribute in some form cases,
+ //so use it for all. See #2844
+ var actnNode = fn.getAttributeNode("action");
+ var mthdNode = fn.getAttributeNode("method");
+ var trgtNode = fn.getAttributeNode("target");
+ if(args["url"]){
+ ioArgs._originalAction = actnNode ? actnNode.value : null;
+ if(actnNode){
+ actnNode.value = args.url;
+ }else{
+ fn.setAttribute("action",args.url);
+ }
+ }
+ if(!mthdNode || !mthdNode.value){
+ if(mthdNode){
+ mthdNode.value= (args["method"]) ? args["method"] : "post";
+ }else{
+ fn.setAttribute("method", (args["method"]) ? args["method"] : "post");
+ }
+ }
+ ioArgs._originalTarget = trgtNode ? trgtNode.value: null;
+ if(trgtNode){
+ trgtNode.value = this._iframeName;
+ }else{
+ fn.setAttribute("target", this._iframeName);
+ }
+ fn.target = this._iframeName;
+ fn.submit();
+ }else{
+ // otherwise we post a GET string by changing URL location for the
+ // iframe
+ var tmpUrl = args.url + (args.url.indexOf("?") > -1 ? "&" : "?") + ioArgs.query;
+ this.setSrc(this._frame, tmpUrl, true);
+ }
+ }catch(e){
+ dfd.errback(e);
+ }
+ },
+
+ _iframeOnload: function(){
+ var dfd = this._currentDfd;
+ if(!dfd){
+ this._fireNextRequest();
+ return;
+ }
+
+ var ioArgs = dfd.ioArgs;
+ var args = ioArgs.args;
+ var fNode = dojo.byId(args.form);
+
+ if(fNode){
+ // remove all the hidden content inputs
+ var toClean = ioArgs._contentToClean;
+ for(var i = 0; i < toClean.length; i++) {
+ var key = toClean[i];
+ if(dojo.isSafari < 3){
+ //In Safari (at least 2.0.3), can't use form[key] syntax to find the node,
+ //for nodes that were dynamically added.
+ for(var j = 0; j < fNode.childNodes.length; j++){
+ var chNode = fNode.childNodes[j];
+ if(chNode.name == key){
+ dojo._destroyElement(chNode);
+ break;
+ }
+ }
+ }else{
+ dojo._destroyElement(fNode[key]);
+ fNode[key] = null;
+ }
+ }
+
+ // restore original action + target
+ if(ioArgs["_originalAction"]){
+ fNode.setAttribute("action", ioArgs._originalAction);
+ }
+ if(ioArgs["_originalTarget"]){
+ fNode.setAttribute("target", ioArgs._originalTarget);
+ fNode.target = ioArgs._originalTarget;
+ }
+ }
+
+ ioArgs._finished = true;
+ }
+}
+
+}
diff --git a/includes/js/dojo/io/script.js b/includes/js/dojo/io/script.js
new file mode 100644
index 0000000..c38d070
--- /dev/null
+++ b/includes/js/dojo/io/script.js
@@ -0,0 +1,211 @@
+if(!dojo._hasResource["dojo.io.script"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.io.script"] = true;
+dojo.provide("dojo.io.script");
+
+/*=====
+dojo.io.script.__ioArgs = function(kwArgs){
+ // summary:
+ // All the properties described in the dojo.__ioArgs type, apply to this
+ // type as well, EXCEPT "handleAs". It is not applicable to
+ // dojo.io.script.get() calls, since it is implied by the usage of
+ // "callbackParamName" (response will be a JSONP call returning JSON)
+ // or "checkString" (response is pure JavaScript defined in
+ // the body of the script that was attached). The following additional
+ // properties are allowed for dojo.io.script.get():
+ // callbackParamName: String
+ // The URL parameter name that indicates the JSONP callback string.
+ // For instance, when using Yahoo JSONP calls it is normally,
+ // callbackParamName: "callback". For AOL JSONP calls it is normally
+ // callbackParamName: "c".
+ // checkString: String
+ // A string of JavaScript that when evaluated like so:
+ // "typeof(" + checkString + ") != 'undefined'"
+ // being true means that the script fetched has been loaded.
+ // Do not use this if doing a JSONP type of call (use callbackParamName instead).
+ // frameDoc: Document.
+ // The Document object for a child iframe. If this is passed in, the script
+ // will be attached to that document. This can be helpful in some comet long-polling
+ // scenarios with Firefox and Opera.
+}
+=====*/
+
+dojo.io.script = {
+ get: function(/*dojo.io.script.__ioArgs*/args){
+ // summary:
+ // sends a get request using a dynamically created script tag.
+ var dfd = this._makeScriptDeferred(args);
+ var ioArgs = dfd.ioArgs;
+ dojo._ioAddQueryToUrl(ioArgs);
+
+ this.attach(ioArgs.id, ioArgs.url, args.frameDoc);
+ dojo._ioWatch(dfd, this._validCheck, this._ioCheck, this._resHandle);
+ return dfd;
+ },
+
+ attach: function(/*String*/id, /*String*/url, /*Document?*/frameDocument){
+ // summary:
+ // creates a new <script> tag pointing to the specified URL and
+ // adds it to the document.
+ // description:
+ // Attaches the script element to the DOM. Use this method if you
+ // just want to attach a script to the DOM and do not care when or
+ // if it loads.
+ var doc = (frameDocument || dojo.doc);
+ var element = doc.createElement("script");
+ element.type = "text/javascript";
+ element.src = url;
+ element.id = id;
+ doc.getElementsByTagName("head")[0].appendChild(element);
+ },
+
+ remove: function(/*String*/id){
+ //summary: removes the script element with the given id.
+ dojo._destroyElement(dojo.byId(id));
+
+ //Remove the jsonp callback on dojo.io.script, if it exists.
+ if(this["jsonp_" + id]){
+ delete this["jsonp_" + id];
+ }
+ },
+
+ _makeScriptDeferred: function(/*Object*/args){
+ //summary:
+ // sets up a Deferred object for an IO request.
+ var dfd = dojo._ioSetArgs(args, this._deferredCancel, this._deferredOk, this._deferredError);
+
+ var ioArgs = dfd.ioArgs;
+ ioArgs.id = dojo._scopeName + "IoScript" + (this._counter++);
+ ioArgs.canDelete = false;
+
+ //Special setup for jsonp case
+ if(args.callbackParamName){
+ //Add the jsonp parameter.
+ ioArgs.query = ioArgs.query || "";
+ if(ioArgs.query.length > 0){
+ ioArgs.query += "&";
+ }
+ ioArgs.query += args.callbackParamName
+ + "="
+ + (args.frameDoc ? "parent." : "")
+ + "dojo.io.script.jsonp_" + ioArgs.id + "._jsonpCallback";
+
+ //Setup the Deferred to have the jsonp callback.
+ ioArgs.canDelete = true;
+ dfd._jsonpCallback = this._jsonpCallback;
+ this["jsonp_" + ioArgs.id] = dfd;
+ }
+ return dfd; // dojo.Deferred
+ },
+
+ _deferredCancel: function(/*Deferred*/dfd){
+ //summary: canceller function for dojo._ioSetArgs call.
+
+ //DO NOT use "this" and expect it to be dojo.io.script.
+ dfd.canceled = true;
+ if(dfd.ioArgs.canDelete){
+ dojo.io.script._deadScripts.push(dfd.ioArgs.id);
+ }
+ },
+
+ _deferredOk: function(/*Deferred*/dfd){
+ //summary: okHandler function for dojo._ioSetArgs call.
+
+ //DO NOT use "this" and expect it to be dojo.io.script.
+
+ //Add script to list of things that can be removed.
+ if(dfd.ioArgs.canDelete){
+ dojo.io.script._deadScripts.push(dfd.ioArgs.id);
+ }
+
+ if(dfd.ioArgs.json){
+ //Make sure to *not* remove the json property from the
+ //Deferred, so that the Deferred can still function correctly
+ //after the response is received.
+ return dfd.ioArgs.json;
+ }else{
+ //FIXME: cannot return the dfd here, otherwise that stops
+ //the callback chain in Deferred. So return the ioArgs instead.
+ //This doesn't feel right.
+ return dfd.ioArgs;
+ }
+ },
+
+ _deferredError: function(/*Error*/error, /*Deferred*/dfd){
+ //summary: errHandler function for dojo._ioSetArgs call.
+
+ if(dfd.ioArgs.canDelete){
+ //DO NOT use "this" and expect it to be dojo.io.script.
+ if(error.dojoType == "timeout"){
+ //For timeouts, remove the script element immediately to
+ //avoid a response from it coming back later and causing trouble.
+ dojo.io.script.remove(dfd.ioArgs.id);
+ }else{
+ dojo.io.script._deadScripts.push(dfd.ioArgs.id);
+ }
+ }
+ console.debug("dojo.io.script error", error);
+ return error;
+ },
+
+ _deadScripts: [],
+ _counter: 1,
+
+ _validCheck: function(/*Deferred*/dfd){
+ //summary: inflight check function to see if dfd is still valid.
+
+ //Do script cleanup here. We wait for one inflight pass
+ //to make sure we don't get any weird things by trying to remove a script
+ //tag that is part of the call chain (IE 6 has been known to
+ //crash in that case).
+ var _self = dojo.io.script;
+ var deadScripts = _self._deadScripts;
+ if(deadScripts && deadScripts.length > 0){
+ for(var i = 0; i < deadScripts.length; i++){
+ //Remove the script tag
+ _self.remove(deadScripts[i]);
+ }
+ dojo.io.script._deadScripts = [];
+ }
+
+ return true;
+ },
+
+ _ioCheck: function(/*Deferred*/dfd){
+ //summary: inflight check function to see if IO finished.
+
+ //Check for finished jsonp
+ if(dfd.ioArgs.json){
+ return true;
+ }
+
+ //Check for finished "checkString" case.
+ var checkString = dfd.ioArgs.args.checkString;
+ if(checkString && eval("typeof(" + checkString + ") != 'undefined'")){
+ return true;
+ }
+
+ return false;
+ },
+
+ _resHandle: function(/*Deferred*/dfd){
+ //summary: inflight function to handle a completed response.
+ if(dojo.io.script._ioCheck(dfd)){
+ dfd.callback(dfd);
+ }else{
+ //This path should never happen since the only way we can get
+ //to _resHandle is if _ioCheck is true.
+ dfd.errback(new Error("inconceivable dojo.io.script._resHandle error"));
+ }
+ },
+
+ _jsonpCallback: function(/*JSON Object*/json){
+ //summary:
+ // generic handler for jsonp callback. A pointer to this function
+ // is used for all jsonp callbacks. NOTE: the "this" in this
+ // function will be the Deferred object that represents the script
+ // request.
+ this.ioArgs.json = json;
+ }
+}
+
+}
diff --git a/includes/js/dojo/jaxer.js b/includes/js/dojo/jaxer.js
new file mode 100644
index 0000000..d26e13f
--- /dev/null
+++ b/includes/js/dojo/jaxer.js
@@ -0,0 +1,15 @@
+if(!dojo._hasResource["dojo.jaxer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.jaxer"] = true;
+dojo.provide("dojo.jaxer");
+
+if(typeof print == "function"){
+ console.debug = Jaxer.Log.debug;
+ console.warn = Jaxer.Log.warn;
+ console.error = Jaxer.Log.error;
+ console.info = Jaxer.Log.info;
+ console.log = Jaxer.Log.warn;
+}
+
+onserverload = dojo._loadInit;
+
+}
diff --git a/includes/js/dojo/nls/ar/colors.js b/includes/js/dojo/nls/ar/colors.js
new file mode 100644
index 0000000..07abeb7
--- /dev/null
+++ b/includes/js/dojo/nls/ar/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"أزرق معدني Ùاتح","orangered":"أحمر مائل للبرتقالي ","midnightblue":"أزرق بحري ","cadetblue":"أزرق ملون بالرمادي","seashell":"أبيض مائل للأصÙر Ùاتح ","slategrey":"رمادي اردوازي ","coral":"مرجاني","darkturquoise":"تركواز داكن","antiquewhite":"أبيض عتيق","mediumspringgreen":"أخضر ربيعي متوسط ","salmon":"برتقالي وردي شاحب ","darkgrey":"رمادي داكن","ivory":"عاجي","greenyellow":"أخضر مائل للأصÙر","mistyrose":"وردي ","lightsalmon":"Ùضي Ùاتح","silver":"Ùضي ","dimgrey":"رمادي شاحب","orange":"برتقالي ","white":"أبيض ","navajowhite":"أبيض ملاحي ","royalblue":"أزرق ملكي ","deeppink":"أحمر وردي غامق","lime":"ليموني ","oldlace":"برتقالي مائل للأصÙر شاحب ","chartreuse":"أخضر مائل للصÙرة","darkcyan":"أزرق سماوي داكن","yellow":"أصÙر ","linen":"كتاني ","olive":"أخضر زيتوني داكن ","gold":"ذهبي","lawngreen":"أخضر بلون العشب ","lightyellow":"أصÙر Ùاتح ","tan":"خمري ","darkviolet":"بنÙسجي داكن","lightslategrey":"رمادي اردوازي Ùاتح","grey":"رمادي","darkkhaki":"كاكي داكن","green":"أخضر","deepskyblue":"أزرق سماوي غامق","aqua":"أزرق مائي","sienna":"بني محروق ","mintcream":"أصÙر شاحب مائل للأخضر الزرعي ","rosybrown":"بني وردي ","mediumslateblue":"أزرق اردوازي متوسط ","magenta":"أحمر قرمزي ","lightseagreen":"أخضر مائل للأزرق Ùاتح","cyan":"أزرق سماوي","olivedrab":"أسود Ùاتح ","darkgoldenrod":"أصÙر ذهبي داكن ","slateblue":"أزرق اردوازي ","mediumaquamarine":"أزرق مائل للأخضر (زبرجد) متوسط ","lavender":"أرجواني شاحب","mediumseagreen":"أخضر مائل للأزرق متوسط ","maroon":"أحمر داكن ","darkslategray":"رمادي اردوازي داكن","mediumturquoise":"تركواز متوسط ","ghostwhite":"أبيض Ø´ÙاÙ","darkblue":"أزرق داكن","mediumvioletred":"أحمر-بنÙسجي متوسط ","brown":"بني","lightgray":"رمادي Ùاتح","sandybrown":"بني مائل للصÙرة ","pink":"وردي ","firebrick":"أصÙر زاهي","indigo":"نيلي","snow":"أبيض ثلجي ","darkorchid":"أرجواني داكن","turquoise":"تركواز ","chocolate":"بني غامق","springgreen":"أخضر ربيعي ","moccasin":"نحاسي أحمر ","navy":"أزرق داكن ","lemonchiffon":"أصÙر Ø´Ùا٠","teal":"بترولي ","floralwhite":"أبيض زهري ","cornflowerblue":"أزرق عنبري","paleturquoise":"تركواز شاحب ","purple":"ارجواني ","gainsboro":"رمادي مائل للأزرق Ùاتح ","plum":"أرجواني داكن ","red":"أحمر ","blue":"أزرق","forestgreen":"أخضر بلون أشجار الغابات ","darkgreen":"أخضر داكن","honeydew":"أبيض مائل للأخضر ","darkseagreen":"أخضر مائل للأزرق داكن","lightcoral":"مرجاني Ùاتح","palevioletred":"أحمر-بنÙسجي شاحب ","mediumpurple":"قرمزي متوسط ","saddlebrown":"بني Ùاتح ","darkmagenta":"قرمزي داكن","thistle":"ارجواني شاحب ","whitesmoke":"دخان أبيض ","wheat":"أخضر قمحي ","violet":"بنÙسجي ","lightskyblue":"أزرق سماوي Ùاتح","goldenrod":"أصÙر ذهبي ","mediumblue":"أزرق متوسط ","skyblue":"أزرق سماوي ","crimson":"قرمزي","darksalmon":"Ùضي داكن","darkred":"أحمر داكن","darkslategrey":"رمادي اردوازي داكن","peru":"بني جملي ","lightgrey":"رمادي Ùاتح","lightgoldenrodyellow":"أصÙر ذهبي Ùاتح","blanchedalmond":"أخضر مائل للبياض","aliceblue":"أزرق Ùاتح","bisque":"أصÙر برتقالي الى رمادي مصÙر","slategray":"رمادي اردوازي ","palegoldenrod":"أصÙر ذهبي شاحب ","darkorange":"برتقالي داكن","aquamarine":"أزرق مائل للأخضر (زبرجد) ","lightgreen":"أخضر Ùاتح","burlywood":"خشبي","dodgerblue":"أزرق عنبري","darkgray":"رمادي داكن","lightcyan":"سماوي Ùاتح","powderblue":"أزرق مائل للأصÙر ","blueviolet":"أزرق-بنÙسجي","orchid":"أرجواني Ùاتح ","dimgray":"رمادي شاحب","beige":"بيج","fuchsia":"Ùوشيا","lavenderblush":"أحمر أرجواني","hotpink":"أحمر وردي زاهي","steelblue":"أزرق معدني ","tomato":"أحمر مائل للأصÙر ","lightpink":"وردي Ùاتح","limegreen":"أخضر ليموني ","indianred":"أحمر هندي","papayawhip":"خوخي Ùاتح ","lightslategray":"رمادي اردوازي Ùاتح","gray":"رمادي","mediumorchid":"أرجواني متوسط ","cornsilk":"حريري","black":"أسود","seagreen":"أخضر مائل للأزرق ","darkslateblue":"أزرق اردوازي داكن","khaki":"كاكي","lightblue":"أزرق Ùاتح","palegreen":"أخضر شاحب ","azure":"أزرق سماوي ","peachpuff":"خوخي مائل للأصÙر ","darkolivegreen":"أخضر زيتوني داكن","yellowgreen":"أخضر مائل للأصÙر "}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/colors.js b/includes/js/dojo/nls/colors.js
new file mode 100644
index 0000000..454e644
--- /dev/null
+++ b/includes/js/dojo/nls/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"light steel blue","orangered":"orange red","midnightblue":"midnight blue","cadetblue":"cadet blue","seashell":"seashell","slategrey":"slate gray","coral":"coral","darkturquoise":"dark turquoise","antiquewhite":"antique white","mediumspringgreen":"medium spring green","salmon":"salmon","darkgrey":"dark gray","ivory":"ivory","greenyellow":"green-yellow","mistyrose":"misty rose","lightsalmon":"light salmon","silver":"silver","dimgrey":"dim gray","orange":"orange","white":"white","navajowhite":"navajo white","royalblue":"royal blue","deeppink":"deep pink","lime":"lime","oldlace":"old lace","chartreuse":"chartreuse","darkcyan":"dark cyan","yellow":"yellow","linen":"linen","olive":"olive","gold":"gold","lawngreen":"lawn green","lightyellow":"light yellow","tan":"tan","darkviolet":"dark violet","lightslategrey":"light slate gray","grey":"gray","darkkhaki":"dark khaki","green":"green","deepskyblue":"deep sky blue","aqua":"aqua","sienna":"sienna","mintcream":"mint cream","rosybrown":"rosy brown","mediumslateblue":"medium slate blue","magenta":"magenta","lightseagreen":"light sea green","cyan":"cyan","olivedrab":"olive drab","darkgoldenrod":"dark goldenrod","slateblue":"slate blue","mediumaquamarine":"medium aquamarine","lavender":"lavender","mediumseagreen":"medium sea green","maroon":"maroon","darkslategray":"dark slate gray","mediumturquoise":"medium turquoise","ghostwhite":"ghost white","darkblue":"dark blue","mediumvioletred":"medium violet-red","brown":"brown","lightgray":"light gray","sandybrown":"sandy brown","pink":"pink","firebrick":"fire brick","indigo":"indigo","snow":"snow","darkorchid":"dark orchid","turquoise":"turquoise","chocolate":"chocolate","springgreen":"spring green","moccasin":"moccasin","navy":"navy","lemonchiffon":"lemon chiffon","teal":"teal","floralwhite":"floral white","cornflowerblue":"cornflower blue","paleturquoise":"pale turquoise","purple":"purple","gainsboro":"gainsboro","plum":"plum","red":"red","blue":"blue","forestgreen":"forest green","darkgreen":"dark green","honeydew":"honeydew","darkseagreen":"dark sea green","lightcoral":"light coral","palevioletred":"pale violet-red","mediumpurple":"medium purple","saddlebrown":"saddle brown","darkmagenta":"dark magenta","thistle":"thistle","whitesmoke":"white smoke","wheat":"wheat","violet":"violet","lightskyblue":"light sky blue","goldenrod":"goldenrod","mediumblue":"medium blue","skyblue":"sky blue","crimson":"crimson","darksalmon":"dark salmon","darkred":"dark red","darkslategrey":"dark slate gray","peru":"peru","lightgrey":"light gray","lightgoldenrodyellow":"light goldenrod yellow","blanchedalmond":"blanched almond","aliceblue":"alice blue","bisque":"bisque","slategray":"slate gray","palegoldenrod":"pale goldenrod","darkorange":"dark orange","aquamarine":"aquamarine","lightgreen":"light green","burlywood":"burlywood","dodgerblue":"dodger blue","darkgray":"dark gray","lightcyan":"light cyan","powderblue":"powder blue","blueviolet":"blue-violet","orchid":"orchid","dimgray":"dim gray","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavender blush","hotpink":"hot pink","steelblue":"steel blue","tomato":"tomato","lightpink":"light pink","limegreen":"lime green","indianred":"indian red","papayawhip":"papaya whip","lightslategray":"light slate gray","gray":"gray","mediumorchid":"medium orchid","cornsilk":"cornsilk","black":"black","seagreen":"sea green","darkslateblue":"dark slate blue","khaki":"khaki","lightblue":"light blue","palegreen":"pale green","azure":"azure","peachpuff":"peach puff","darkolivegreen":"dark olive green","yellowgreen":"yellow green"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/cs/colors.js b/includes/js/dojo/nls/cs/colors.js
new file mode 100644
index 0000000..7ae5d30
--- /dev/null
+++ b/includes/js/dojo/nls/cs/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"svÄ›tlá ocelová modrá","orangered":"oranžovoÄervená","midnightblue":"temnÄ› modrá","cadetblue":"Å¡edomodrá","seashell":"lasturová","slategrey":"bÅ™idlicová Å¡edá","coral":"korálová Äervená","darkturquoise":"tmavÄ› tyrkysová","antiquewhite":"krémovÄ› bílá","mediumspringgreen":"stÅ™ední jarní zelená","salmon":"lososová","darkgrey":"tmavÄ› Å¡edá","ivory":"slonovinová","greenyellow":"zelenožlutá","mistyrose":"růžovobílá","lightsalmon":"svÄ›tle lososová","silver":"stříbrná","dimgrey":"kouÅ™ovÄ› Å¡edá","orange":"oranžová","white":"bílá","navajowhite":"svÄ›tle krémová","royalblue":"královská modrá","deeppink":"sytÄ› růžová","lime":"limetková","oldlace":"svÄ›tle béžová","chartreuse":"chartreuska","darkcyan":"tmavÄ› azurová","yellow":"žlutá","linen":"bledÄ› Å¡edobéžová","olive":"olivová","gold":"zlatá","lawngreen":"jasnÄ› zelená","lightyellow":"bledÄ› žlutá","tan":"Å¡edobéžová","darkviolet":"tmavÄ› fialová","lightslategrey":"svÄ›tlá bÅ™idlicová Å¡edá","grey":"Å¡edá","darkkhaki":"pískovÄ› hnÄ›dá","green":"zelená","deepskyblue":"sytá nebeská modrá","aqua":"azurová","sienna":"siena","mintcream":"mentolová","rosybrown":"růžovohnÄ›dá","mediumslateblue":"stÅ™ední bÅ™idlicová modrá","magenta":"purpurová","lightseagreen":"svÄ›tlá moÅ™ská zelená","cyan":"azurová","olivedrab":"khaki","darkgoldenrod":"tmavÄ› béžová","slateblue":"bÅ™idlicová modrá","mediumaquamarine":"stÅ™ední akvamarínová","lavender":"levandulová","mediumseagreen":"stÅ™ední moÅ™ská zelená","maroon":"kaÅ¡tanová","darkslategray":"tmavá bÅ™idlicová Å¡edá","mediumturquoise":"stÅ™ednÄ› tyrkysová","ghostwhite":"modravÄ› bílá","darkblue":"tmavÄ› modrá","mediumvioletred":"stÅ™ednÄ› fialovoÄervená","brown":"ÄervenohnÄ›dá","lightgray":"svÄ›tle Å¡edá","sandybrown":"oranžovohnÄ›dá","pink":"růžová","firebrick":"cihlová","indigo":"indigovÄ› modrá","snow":"snÄ›hobílá","darkorchid":"tmavÄ› orchidejová","turquoise":"tyrkysová","chocolate":"hnÄ›dobéžová","springgreen":"jarní zelená","moccasin":"bledÄ› krémová","navy":"námoÅ™nická modrá","lemonchiffon":"svÄ›tle citrónová","teal":"Å¡edozelená","floralwhite":"kvÄ›tinovÄ› bílá","cornflowerblue":"chrpovÄ› modrá","paleturquoise":"bledÄ› tyrkysová","purple":"nachová","gainsboro":"bledÄ› Å¡edá","plum":"Å¡vestková","red":"Äervená","blue":"modrá","forestgreen":"lesní zelená","darkgreen":"tmavÄ› zelená","honeydew":"nazelenalá","darkseagreen":"tmavá moÅ™ská zelená","lightcoral":"svÄ›tle korálová","palevioletred":"bledÄ› fialovoÄervená","mediumpurple":"stÅ™ednÄ› nachová","saddlebrown":"hnÄ›dá","darkmagenta":"tmavÄ› purpurová","thistle":"bodláková","whitesmoke":"kouÅ™ovÄ› bílá","wheat":"zlatohnÄ›dá","violet":"fialová","lightskyblue":"svÄ›tlá nebeská modrá","goldenrod":"béžová","mediumblue":"stÅ™ednÄ› modrá","skyblue":"nebeská modrá","crimson":"karmínová","darksalmon":"tmavÄ› lososová","darkred":"tmavÄ› Äervená","darkslategrey":"tmavá bÅ™idlicová Å¡edá","peru":"karamelová","lightgrey":"svÄ›tle Å¡edá","lightgoldenrodyellow":"svÄ›tle žlutá","blanchedalmond":"mandlová","aliceblue":"modravá","bisque":"bledÄ› oranžová","slategray":"bÅ™idlicová Å¡edá","palegoldenrod":"bledÄ› písková","darkorange":"tmavÄ› oranžová","aquamarine":"akvamarínová","lightgreen":"svÄ›tle zelená","burlywood":"krémová","dodgerblue":"jasnÄ› modrá","darkgray":"tmavÄ› Å¡edá","lightcyan":"svÄ›tle azurová","powderblue":"bledÄ› modrá","blueviolet":"modrofialová","orchid":"orchidejová","dimgray":"kouÅ™ovÄ› Å¡edá","beige":"bledÄ› béžová","fuchsia":"fuchsiová","lavenderblush":"levandulová růžová","hotpink":"jasnÄ› růžová","steelblue":"ocelová modrá","tomato":"tomatová","lightpink":"svÄ›tle růžová","limegreen":"limetkovÄ› zelená","indianred":"indiánská Äervená","papayawhip":"papájová","lightslategray":"svÄ›tlá bÅ™idlicová Å¡edá","gray":"Å¡edá","mediumorchid":"stÅ™ednÄ› orchidejová","cornsilk":"režná","black":"Äerná","seagreen":"moÅ™ská zelená","darkslateblue":"tmavá bÅ™idlicová modrá","khaki":"písková","lightblue":"svÄ›tle modrá","palegreen":"bledÄ› zelená","azure":"bledÄ› azurová","peachpuff":"broskvová","darkolivegreen":"tmavÄ› olivová","yellowgreen":"žlutozelená"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/da/colors.js b/includes/js/dojo/nls/da/colors.js
new file mode 100644
index 0000000..322154f
--- /dev/null
+++ b/includes/js/dojo/nls/da/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"lys stålblå","orangered":"orangerød","midnightblue":"midnatsblå","cadetblue":"kadetblå","seashell":"muslingeskal","slategrey":"skifergrå","coral":"koralrød","darkturquoise":"mørk turkis","antiquewhite":"antikhvid","mediumspringgreen":"mellemforårsgrøn","salmon":"laksefarvet","darkgrey":"mørkegrå","ivory":"elfenben","greenyellow":"grøngul","mistyrose":"blegrosa","lightsalmon":"lys laksefarvet","silver":"sølv","dimgrey":"svag grå","orange":"orange","white":"hvid","navajowhite":"navajo-hvid","royalblue":"kongeblå","deeppink":"dyb pink","lime":"lime","oldlace":"kniplingshvid","chartreuse":"chartreuse","darkcyan":"mørk cyan","yellow":"gul","linen":"lærred","olive":"olivengrøn","gold":"guld","lawngreen":"græsgrøn","lightyellow":"lysegul","tan":"tan","darkviolet":"mørkelilla","lightslategrey":"lys skifergrå","grey":"grå","darkkhaki":"mørk khaki","green":"grøn","deepskyblue":"dyb himmelblå","aqua":"akvablå","sienna":"sienna","mintcream":"pebermyntecreme","rosybrown":"rosabrun","mediumslateblue":"mellemskiferblå","magenta":"magenta","lightseagreen":"lys havgrøn","cyan":"cyan","olivedrab":"brungrøn","darkgoldenrod":"mørk gyldenris","slateblue":"skiferblå","mediumaquamarine":"mellem akvamarin","lavender":"lysviolet","mediumseagreen":"mellemhavgrøn","maroon":"rødbrun","darkslategray":"mørk skifergrå","mediumturquoise":"mellemturkis","ghostwhite":"spøgelseshvid","darkblue":"mørkeblå","mediumvioletred":"mellemviolet","brown":"brun","lightgray":"lysegrå","sandybrown":"sandbrun","pink":"pink","firebrick":"chamottesten","indigo":"indigo","snow":"sne","darkorchid":"mørk orkide","turquoise":"turkis","chocolate":"rust","springgreen":"forårsgrøn","moccasin":"fruesko","navy":"marineblå","lemonchiffon":"citronfromage","teal":"blågrøn","floralwhite":"blomsterhvid","cornflowerblue":"kornblomstblå","paleturquoise":"bleg turkis","purple":"lilla","gainsboro":"gainsboro","plum":"blomme","red":"rød","blue":"blå","forestgreen":"skovgrøn","darkgreen":"mørkegrøn","honeydew":"honningdug","darkseagreen":"mørk havgrøn","lightcoral":"lys koralrød","palevioletred":"blegviolet","mediumpurple":"mellemlilla","saddlebrown":"saddelbrun","darkmagenta":"mørk magenta","thistle":"tidsel","whitesmoke":"hvid røg","wheat":"korngul","violet":"lilla","lightskyblue":"lys himmelblå","goldenrod":"gyldenris","mediumblue":"mellemblå","skyblue":"himmelblå","crimson":"blodrød","darksalmon":"mørk laksefarvet","darkred":"mørkerød","darkslategrey":"mørk skifergrå","peru":"peru","lightgrey":"lysegrå","lightgoldenrodyellow":"lys gyldenrisgul","blanchedalmond":"blanceret mandel","aliceblue":"babyblå","bisque":"gulgrå","slategray":"skifergrå","palegoldenrod":"bleg gyldenris","darkorange":"mørk orange","aquamarine":"akvamarin","lightgreen":"lysegrøn","burlywood":"tobak","dodgerblue":"dodgerblå","darkgray":"mørkegrå","lightcyan":"lys cyan","powderblue":"pudderblå","blueviolet":"blåviolet","orchid":"orkide","dimgray":"svag grå","beige":"beige","fuchsia":"lyslilla","lavenderblush":"lavendelrød","hotpink":"mørk rosa","steelblue":"metalblå","tomato":"tomat","lightpink":"lys pink","limegreen":"limegrøn","indianred":"lys rødbrun","papayawhip":"papaya","lightslategray":"lys skifergrå","gray":"grå","mediumorchid":"mellem orkide","cornsilk":"majs","black":"sort","seagreen":"havgrøn","darkslateblue":"mørk skiferblå","khaki":"khaki","lightblue":"lyseblå","palegreen":"bleggrøn","azure":"azurblå","peachpuff":"fersken","darkolivegreen":"mørk olivengrøn","yellowgreen":"gulgrøn"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/de/colors.js b/includes/js/dojo/nls/de/colors.js
new file mode 100644
index 0000000..7ae21bf
--- /dev/null
+++ b/includes/js/dojo/nls/de/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"Helles Stahlblau","orangered":"Orangerot","midnightblue":"Mitternachtblau","cadetblue":"Kadettenblau","seashell":"Muschelweiß","slategrey":"Schiefergrau","coral":"Koralle","darkturquoise":"Dunkeltürkis","antiquewhite":"Antikweiß","mediumspringgreen":"Mittelfrühlingsgrün","salmon":"Lachs","darkgrey":"Dunkelgrau","ivory":"Elfenbein","greenyellow":"Grüngelb","mistyrose":"Blassrose","lightsalmon":"Helllachs","silver":"Silbergrau","dimgrey":"Blassgrau","orange":"Orange","white":"Weiß","navajowhite":"Navajo-weiß","royalblue":"Königsblau","deeppink":"Tiefrosa","lime":"Limone","oldlace":"Alte Spitze","chartreuse":"Helles Gelbgrün","darkcyan":"Dunkelzyan","yellow":"Gelb","linen":"Leinen","olive":"Oliv","gold":"Gold","lawngreen":"Grasgrün","lightyellow":"Hellgelb","tan":"Hautfarben","darkviolet":"Dunkelviolett","lightslategrey":"Helles Schiefergrau","grey":"Grau","darkkhaki":"Dunkelkhaki","green":"Grün","deepskyblue":"Dunkles Himmelblau","aqua":"Wasserblau","sienna":"Sienna","mintcream":"Mintcreme","rosybrown":"Rosigbraun","mediumslateblue":"Mittelschieferblau ","magenta":"Magenta","lightseagreen":"Helles Meergrün","cyan":"Zyan","olivedrab":"Olivgrau","darkgoldenrod":"Dunkelgoldgelb","slateblue":"Schieferblau","mediumaquamarine":"Mittelaquamarin","lavender":"Lavendelblau","mediumseagreen":"Mittelmeeresgrün","maroon":"Kastanienbraun","darkslategray":"Dunkelschiefergrau","mediumturquoise":"Mitteltürkis ","ghostwhite":"Geisterweiß","darkblue":"Dunkelblau","mediumvioletred":"Mittelviolettrot ","brown":"Braun","lightgray":"Hellgrau","sandybrown":"Sandbraun","pink":"Rosa","firebrick":"Schamottestein","indigo":"Indigoblau","snow":"Schneeweiß","darkorchid":"Dunkelorchidee","turquoise":"Türkis","chocolate":"Schokoladenbraun","springgreen":"Frühlingsgrün","moccasin":"Mokassin","navy":"Marineblau","lemonchiffon":"Zitronenchiffon","teal":"Smaragdgrün","floralwhite":"Blütenweiß","cornflowerblue":"Kornblumenblau","paleturquoise":"Blasstürkis","purple":"Purpurrot","gainsboro":"Gainsboro","plum":"Pflaume","red":"Rot","blue":"Blau","forestgreen":"Forstgrün","darkgreen":"Dunkelgrün","honeydew":"Honigtau","darkseagreen":"Dunkles Meergrün","lightcoral":"Hellkoralle","palevioletred":"Blassviolettrot ","mediumpurple":"Mittelpurpur","saddlebrown":"Sattelbraun","darkmagenta":"Dunkelmagenta","thistle":"Distel","whitesmoke":"Rauchweiß","wheat":"Weizen","violet":"Violett","lightskyblue":"Helles Himmelblau","goldenrod":"Goldgelb","mediumblue":"Mittelblau","skyblue":"Himmelblau","crimson":"Karmesinrot","darksalmon":"Dunkellachs","darkred":"Dunkelrot","darkslategrey":"Dunkelschiefergrau","peru":"Peru","lightgrey":"Hellgrau","lightgoldenrodyellow":"Hellgoldgelb","blanchedalmond":"Mandelweiß","aliceblue":"Alice-blau","bisque":"Bisquit","slategray":"Schiefergrau","palegoldenrod":"Blassgoldgelb","darkorange":"Dunkelorange","aquamarine":"Aquamarin","lightgreen":"Hellgrün","burlywood":"Burlywood","dodgerblue":"Dodger-blau","darkgray":"Dunkelgrau","lightcyan":"Hellzyan","powderblue":"Pulverblau","blueviolet":"Blauviolett","orchid":"Orchidee","dimgray":"Blassgrau","beige":"Beige","fuchsia":"Fuchsia","lavenderblush":"Lavendelhauch","hotpink":"Knallrosa","steelblue":"Stahlblau","tomato":"Tomatenrot","lightpink":"Hellrosa","limegreen":"Limonengrün","indianred":"Indischrot","papayawhip":"Papayacreme","lightslategray":"Helles Schiefergrau","gray":"Grau","mediumorchid":"Mittelorchidee","cornsilk":"Kornseide","black":"Schwarz","seagreen":"Meeresgrün","darkslateblue":"Dunkelschieferblau","khaki":"Khaki","lightblue":"Hellblau","palegreen":"Blassgrün","azure":"Azur","peachpuff":"Pfirsich","darkolivegreen":"Dunkelolivgrün","yellowgreen":"Gelbgrün"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/el/colors.js b/includes/js/dojo/nls/el/colors.js
new file mode 100644
index 0000000..a80df97
--- /dev/null
+++ b/includes/js/dojo/nls/el/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"ανοιχτό μπλε ατσαλιοÏ","orangered":"ποÏτοκαλοκόκκινο","midnightblue":"Ï€Î¿Î»Ï ÏƒÎºÎ¿ÏÏο μπλε","cadetblue":"μπλε του στÏατοÏ","seashell":"κοχÏλι","slategrey":"μεταλλικό γκÏι","coral":"κοÏαλί","darkturquoise":"σκοÏÏο Ï„Ï…Ïκουάζ","antiquewhite":"ξεθωÏιασμένο λευκό","mediumspringgreen":"μεσαίο Ï€Ïάσινο της άνοιξης","salmon":"σομόν","darkgrey":"σκοÏÏο γκÏι","ivory":"ιβουάÏ","greenyellow":"Ï€ÏασινοκίτÏινο","mistyrose":"Ï„Ïιανταφυλλί","lightsalmon":"ανοιχτό σομόν","silver":"ασημί","dimgrey":"αχνό γκÏι","orange":"ποÏτοκαλί","white":"λευκό","navajowhite":"άσπÏο Îαβάχο","royalblue":"έντονο μπλε","deeppink":"Î²Î±Î¸Ï Ïοζ","lime":"λαχανί","oldlace":"εκÏοÏ","chartreuse":"φωτεινό κιτÏινοπÏάσινο","darkcyan":"σκοÏÏο κυανό","yellow":"κίτÏινο","linen":"σπαγγί","olive":"Ï€Ïάσινο λαδί","gold":"χÏυσαφί","lawngreen":"σκοÏÏο Ï€Ïάσινο","lightyellow":"ανοιχτό κίτÏινο","tan":"ώχÏα","darkviolet":"σκοÏÏο βιολετί","lightslategrey":"ανοιχτό μεταλλικό γκÏι","grey":"γκÏι","darkkhaki":"σκοÏÏο χακί","green":"Ï€Ïάσινο","deepskyblue":"Î²Î±Î¸Ï Î¼Ï€Î»Îµ το ουÏανοÏ","aqua":"γαλάζιο","sienna":"καφεκίτÏινο","mintcream":"βεÏαμάν","rosybrown":"καστανό","mediumslateblue":"μεσαίο μεταλλικό μπλε","magenta":"ματζέντα","lightseagreen":"ανοιχτό Ï€Ïάσινο της θάλασσας","cyan":"κυανό","olivedrab":"λαδί","darkgoldenrod":"σκοÏÏο χÏυσοκίτÏινο","slateblue":"μεταλλικό μπλε","mediumaquamarine":"μεσαίο γαλαζοπÏάσινο","lavender":"λίλα","mediumseagreen":"μεσαίο Ï€Ïάσινο της θάλασσας","maroon":"βυσσινί","darkslategray":"σκοÏÏο μεταλλικό γκÏι","mediumturquoise":"μεσαίο Ï„Ï…Ïκουάζ","ghostwhite":"άσπÏο","darkblue":"σκοÏÏο μπλε","mediumvioletred":"μεσαίο κόκκινο βιολετί","brown":"καφέ","lightgray":"ανοιχτό γκÏι","sandybrown":"μπεζ της άμμου","pink":"Ïοζ","firebrick":"κεÏαμιδί","indigo":"λουλακί","snow":"χιονί","darkorchid":"σκοÏÏα οÏχιδέα","turquoise":"Ï„Ï…Ïκουάζ","chocolate":"σοκολατί","springgreen":"Ï€Ïάσινο της άνοιξης","moccasin":"μόκα","navy":"μπλε του ναυτικοÏ","lemonchiffon":"λεμονί","teal":"πετÏόλ","floralwhite":"λευκό των ανθών","cornflowerblue":"μεσαίο μπλε","paleturquoise":"αχνό Ï„Ï…Ïκουάζ","purple":"μωβ","gainsboro":"γκÏι σιέλ","plum":"δαμασκηνί","red":"κόκκινο","blue":"μπλε","forestgreen":"Ï€Ïάσινο του δάσους","darkgreen":"σκοÏÏο Ï€Ïάσινο","honeydew":"μελί","darkseagreen":"σκοÏÏο Ï€Ïάσινο της θάλασσας","lightcoral":"ανοιχτό κοÏαλί","palevioletred":"αχνό κόκκινο βιολετί","mediumpurple":"μεσαίο μωβ","saddlebrown":"Î²Î±Î¸Ï ÎºÎ±Ï†Î­","darkmagenta":"σκοÏÏο ματζέντα","thistle":"μωβ βιολετί","whitesmoke":"λευκός καπνός","wheat":"σταÏένιο","violet":"βιολετί","lightskyblue":"ανοιχτό μπλε το ουÏανοÏ","goldenrod":"χÏυσοκίτÏινο","mediumblue":"μεσαίο μπλε","skyblue":"μπλε του ουÏανοÏ","crimson":"Î²Î±Î¸Ï ÎºÏŒÎºÎºÎ¹Î½Î¿","darksalmon":"σκοÏÏο σομόν","darkred":"σκοÏÏο κόκκινο","darkslategrey":"σκοÏÏο μεταλλικό γκÏι","peru":"πεÏοÏ","lightgrey":"ανοιχτό γκÏι","lightgoldenrodyellow":"ανοιχτό χÏυσοκίτÏινο","blanchedalmond":"ζαχαÏί","aliceblue":"σιέλ","bisque":"σκοÏÏο κÏεμ","slategray":"μεταλλικό γκÏι","palegoldenrod":"αχνό χÏυσοκίτÏινο","darkorange":"σκοÏÏο ποÏτοκαλί","aquamarine":"γαλαζοπÏάσινο","lightgreen":"ανοιχτό Ï€Ïάσινο","burlywood":"καφέ του ξÏλου","dodgerblue":"σκοÏÏο ελεκτÏίκ","darkgray":"σκοÏÏο γκÏι","lightcyan":"ανοιχτό κυανό","powderblue":"αχνό μπλε","blueviolet":"βιολετί","orchid":"οÏχιδέα","dimgray":"αχνό γκÏι","beige":"μπεζ","fuchsia":"φοÏξια","lavenderblush":"μωβ λεβάντας","hotpink":"έντονο Ïοζ","steelblue":"μπλε ατσαλιοÏ","tomato":"κόκκινο της ντομάτας","lightpink":"ανοιχτό Ïοζ","limegreen":"Ï€Ïάσινο λαχανί","indianred":"ινδικό κόκκινο","papayawhip":"αχνό Ïοζ","lightslategray":"ανοιχτό μεταλλικό γκÏι","gray":"γκÏι","mediumorchid":"μεσαία οÏχιδέα","cornsilk":"ασημί του καλαμποκιοÏ","black":"μαÏÏο","seagreen":"Ï€Ïάσινο της θάλασσας","darkslateblue":"σκοÏÏο μεταλλικό μπλε","khaki":"χακί","lightblue":"ανοιχτό μπλε","palegreen":"αχνό Ï€Ïάσινο","azure":"μπλε του ουÏανοÏ","peachpuff":"Ïοδακινί","darkolivegreen":"σκοÏÏο Ï€Ïάσινο λαδί","yellowgreen":"κιτÏινοπÏάσινο"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/es/colors.js b/includes/js/dojo/nls/es/colors.js
new file mode 100644
index 0000000..95bb23e
--- /dev/null
+++ b/includes/js/dojo/nls/es/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"azul acero claro","orangered":"rojo anaranjado","midnightblue":"azul medianoche","cadetblue":"azul cadete","seashell":"blanco marfil","slategrey":"gris pizarra","coral":"coral","darkturquoise":"turquesa oscuro","antiquewhite":"blanco antiguo","mediumspringgreen":"verde primavera medio","salmon":"salmón","darkgrey":"gris oscuro","ivory":"marfil","greenyellow":"amarillo verdoso","mistyrose":"rosa difuminado","lightsalmon":"salmón claro","silver":"plateado","dimgrey":"gris marengo","orange":"naranja","white":"blanco","navajowhite":"blanco navajo","royalblue":"azul real","deeppink":"rosa fuerte","lime":"lima","oldlace":"encaje antiguo","chartreuse":"verde pálido 2","darkcyan":"cian oscuro","yellow":"amarillo","linen":"blanco arena","olive":"verde oliva","gold":"oro","lawngreen":"verde césped","lightyellow":"amarillo claro","tan":"canela","darkviolet":"violeta oscuro","lightslategrey":"gris pizarra claro","grey":"gris","darkkhaki":"caqui oscuro","green":"verde","deepskyblue":"azul cielo fuerte","aqua":"aguamarina","sienna":"siena","mintcream":"crema menta","rosybrown":"marrón rosáceo","mediumslateblue":"azul pizarra medio","magenta":"magenta","lightseagreen":"verde mar claro","cyan":"cian","olivedrab":"verde oliva pardusco","darkgoldenrod":"ocre oscuro","slateblue":"azul pizarra","mediumaquamarine":"aguamarina medio","lavender":"lavanda","mediumseagreen":"verde mar medio","maroon":"granate","darkslategray":"gris pizarra oscuro","mediumturquoise":"turquesa medio","ghostwhite":"blanco ligero","darkblue":"azul oscuro","mediumvioletred":"rojo violáceo medio","brown":"marrón","lightgray":"gris claro","sandybrown":"marrón arcilla","pink":"rosa","firebrick":"teja","indigo":"añil","snow":"nieve","darkorchid":"orquídea oscuro","turquoise":"turquesa","chocolate":"chocolate","springgreen":"verde fuerte","moccasin":"arena","navy":"azul marino","lemonchiffon":"amarillo pastel","teal":"verde azulado","floralwhite":"blanco manteca","cornflowerblue":"azul aciano","paleturquoise":"turquesa pálido","purple":"púrpura","gainsboro":"azul gainsboro","plum":"ciruela","red":"rojo","blue":"azul","forestgreen":"verde pino","darkgreen":"verde oscuro","honeydew":"flor de rocío","darkseagreen":"verde mar oscuro","lightcoral":"coral claro","palevioletred":"rojo violáceo pálido","mediumpurple":"púrpura medio","saddlebrown":"cuero","darkmagenta":"magenta oscuro","thistle":"cardo","whitesmoke":"blanco ahumado","wheat":"trigo","violet":"violeta","lightskyblue":"azul cielo claro","goldenrod":"ocre","mediumblue":"azul medio","skyblue":"azul cielo","crimson":"carmesí","darksalmon":"salmón oscuro","darkred":"rojo oscuro","darkslategrey":"gris pizarra oscuro","peru":"perú","lightgrey":"gris claro","lightgoldenrodyellow":"ocre claro","blanchedalmond":"almendra pálido","aliceblue":"blanco azulado","bisque":"miel","slategray":"gris pizarra","palegoldenrod":"ocre pálido","darkorange":"naranja oscuro","aquamarine":"aguamarina 2","lightgreen":"verde claro","burlywood":"madera","dodgerblue":"azul fuerte","darkgray":"gris oscuro","lightcyan":"cian claro","powderblue":"azul suave","blueviolet":"azul violáceo","orchid":"orquídea","dimgray":"gris marengo","beige":"beige","fuchsia":"fucsia","lavenderblush":"lavanda rosácea","hotpink":"rosa oscuro","steelblue":"azul acero","tomato":"tomate","lightpink":"rosa claro","limegreen":"lima limón","indianred":"rojo teja","papayawhip":"papaya claro","lightslategray":"gris pizarra claro","gray":"gris","mediumorchid":"orquídea medio","cornsilk":"crudo","black":"negro","seagreen":"verde mar","darkslateblue":"azul pizarra oscuro","khaki":"caqui","lightblue":"azul claro","palegreen":"verde pálido","azure":"blanco cielo","peachpuff":"melocotón","darkolivegreen":"verde oliva oscuro","yellowgreen":"verde amarillento"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/fi/colors.js b/includes/js/dojo/nls/fi/colors.js
new file mode 100644
index 0000000..454e644
--- /dev/null
+++ b/includes/js/dojo/nls/fi/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"light steel blue","orangered":"orange red","midnightblue":"midnight blue","cadetblue":"cadet blue","seashell":"seashell","slategrey":"slate gray","coral":"coral","darkturquoise":"dark turquoise","antiquewhite":"antique white","mediumspringgreen":"medium spring green","salmon":"salmon","darkgrey":"dark gray","ivory":"ivory","greenyellow":"green-yellow","mistyrose":"misty rose","lightsalmon":"light salmon","silver":"silver","dimgrey":"dim gray","orange":"orange","white":"white","navajowhite":"navajo white","royalblue":"royal blue","deeppink":"deep pink","lime":"lime","oldlace":"old lace","chartreuse":"chartreuse","darkcyan":"dark cyan","yellow":"yellow","linen":"linen","olive":"olive","gold":"gold","lawngreen":"lawn green","lightyellow":"light yellow","tan":"tan","darkviolet":"dark violet","lightslategrey":"light slate gray","grey":"gray","darkkhaki":"dark khaki","green":"green","deepskyblue":"deep sky blue","aqua":"aqua","sienna":"sienna","mintcream":"mint cream","rosybrown":"rosy brown","mediumslateblue":"medium slate blue","magenta":"magenta","lightseagreen":"light sea green","cyan":"cyan","olivedrab":"olive drab","darkgoldenrod":"dark goldenrod","slateblue":"slate blue","mediumaquamarine":"medium aquamarine","lavender":"lavender","mediumseagreen":"medium sea green","maroon":"maroon","darkslategray":"dark slate gray","mediumturquoise":"medium turquoise","ghostwhite":"ghost white","darkblue":"dark blue","mediumvioletred":"medium violet-red","brown":"brown","lightgray":"light gray","sandybrown":"sandy brown","pink":"pink","firebrick":"fire brick","indigo":"indigo","snow":"snow","darkorchid":"dark orchid","turquoise":"turquoise","chocolate":"chocolate","springgreen":"spring green","moccasin":"moccasin","navy":"navy","lemonchiffon":"lemon chiffon","teal":"teal","floralwhite":"floral white","cornflowerblue":"cornflower blue","paleturquoise":"pale turquoise","purple":"purple","gainsboro":"gainsboro","plum":"plum","red":"red","blue":"blue","forestgreen":"forest green","darkgreen":"dark green","honeydew":"honeydew","darkseagreen":"dark sea green","lightcoral":"light coral","palevioletred":"pale violet-red","mediumpurple":"medium purple","saddlebrown":"saddle brown","darkmagenta":"dark magenta","thistle":"thistle","whitesmoke":"white smoke","wheat":"wheat","violet":"violet","lightskyblue":"light sky blue","goldenrod":"goldenrod","mediumblue":"medium blue","skyblue":"sky blue","crimson":"crimson","darksalmon":"dark salmon","darkred":"dark red","darkslategrey":"dark slate gray","peru":"peru","lightgrey":"light gray","lightgoldenrodyellow":"light goldenrod yellow","blanchedalmond":"blanched almond","aliceblue":"alice blue","bisque":"bisque","slategray":"slate gray","palegoldenrod":"pale goldenrod","darkorange":"dark orange","aquamarine":"aquamarine","lightgreen":"light green","burlywood":"burlywood","dodgerblue":"dodger blue","darkgray":"dark gray","lightcyan":"light cyan","powderblue":"powder blue","blueviolet":"blue-violet","orchid":"orchid","dimgray":"dim gray","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavender blush","hotpink":"hot pink","steelblue":"steel blue","tomato":"tomato","lightpink":"light pink","limegreen":"lime green","indianred":"indian red","papayawhip":"papaya whip","lightslategray":"light slate gray","gray":"gray","mediumorchid":"medium orchid","cornsilk":"cornsilk","black":"black","seagreen":"sea green","darkslateblue":"dark slate blue","khaki":"khaki","lightblue":"light blue","palegreen":"pale green","azure":"azure","peachpuff":"peach puff","darkolivegreen":"dark olive green","yellowgreen":"yellow green"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/fr/colors.js b/includes/js/dojo/nls/fr/colors.js
new file mode 100644
index 0000000..cf1e7e9
--- /dev/null
+++ b/includes/js/dojo/nls/fr/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"bleu acier clair","orangered":"rouge orangé","midnightblue":"bleu nuit","cadetblue":"bleu pétrole","seashell":"coquillage","slategrey":"gris ardoise","coral":"corail","darkturquoise":"turquoise foncé","antiquewhite":"blanc antique","mediumspringgreen":"vert printemps moyen","salmon":"saumon","darkgrey":"gris foncé","ivory":"ivoire","greenyellow":"vert-jaune","mistyrose":"rose pâle","lightsalmon":"saumon clair","silver":"argent","dimgrey":"gris soutenu","orange":"orange","white":"blanc","navajowhite":"chair","royalblue":"bleu roi","deeppink":"rose soutenu","lime":"vert citron","oldlace":"blanc cassé","chartreuse":"vert vif","darkcyan":"cyan foncé","yellow":"jaune","linen":"écru","olive":"olive","gold":"or","lawngreen":"vert prairie","lightyellow":"jaune clair","tan":"grège","darkviolet":"violet foncé","lightslategrey":"gris ardoise clair","grey":"gris","darkkhaki":"kaki foncé","green":"vert","deepskyblue":"bleu ciel soutenu","aqua":"bleu-vert","sienna":"terre de sienne","mintcream":"crème de menthe","rosybrown":"vieux rose","mediumslateblue":"bleu ardoise moyen","magenta":"magenta","lightseagreen":"vert d'eau clair","cyan":"cyan","olivedrab":"brun verdâtre","darkgoldenrod":"jaune paille foncé","slateblue":"bleu ardoise","mediumaquamarine":"aigue-marine moyen","lavender":"lavande","mediumseagreen":"vert d'eau moyen","maroon":"marron","darkslategray":"gris ardoise foncé","mediumturquoise":"turquoise moyen","ghostwhite":"blanc laiteux","darkblue":"bleu foncé","mediumvioletred":"rouge violacé moyen","brown":"brun","lightgray":"gris clair","sandybrown":"sable","pink":"rose","firebrick":"rouge brique","indigo":"indigo","snow":"neige","darkorchid":"lilas foncé","turquoise":"turquoise","chocolate":"chocolat","springgreen":"vert printemps","moccasin":"chamois","navy":"bleu marine","lemonchiffon":"mousse de citron","teal":"sarcelle","floralwhite":"lys","cornflowerblue":"bleuet","paleturquoise":"turquoise pâle","purple":"pourpre","gainsboro":"gris souris","plum":"prune","red":"rouge","blue":"bleu","forestgreen":"vert sapin","darkgreen":"vert foncé","honeydew":"opalin","darkseagreen":"vert d'eau foncé","lightcoral":"corail clair","palevioletred":"rouge violacé pâle","mediumpurple":"pourpre moyen","saddlebrown":"brun cuir","darkmagenta":"magenta foncé","thistle":"chardon","whitesmoke":"blanc cendré","wheat":"blé","violet":"violet","lightskyblue":"bleu ciel clair","goldenrod":"jaune paille","mediumblue":"bleu moyen","skyblue":"bleu ciel","crimson":"cramoisi","darksalmon":"saumon foncé","darkred":"rouge foncé","darkslategrey":"gris ardoise foncé","peru":"caramel","lightgrey":"gris clair","lightgoldenrodyellow":"jaune paille clair","blanchedalmond":"coquille d'oeuf","aliceblue":"bleu gris","bisque":"beige rosé","slategray":"gris ardoise","palegoldenrod":"jaune paille pâle","darkorange":"orange foncé","aquamarine":"aigue-marine","lightgreen":"vert clair","burlywood":"bois précieux","dodgerblue":"bleu France","darkgray":"gris foncé","lightcyan":"cyan clair","powderblue":"bleu de smalt","blueviolet":"bleu-violet","orchid":"lilas","dimgray":"gris soutenu","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavandin","hotpink":"rose intense","steelblue":"bleu acier","tomato":"tomate","lightpink":"rose clair","limegreen":"citron vert","indianred":"rose indien","papayawhip":"crème de papaye","lightslategray":"gris ardoise clair","gray":"gris","mediumorchid":"lilas moyen","cornsilk":"vanille","black":"noir","seagreen":"vert d'eau","darkslateblue":"bleu ardoise foncé","khaki":"kaki","lightblue":"bleu clair","palegreen":"vert pâle","azure":"bleu azur","peachpuff":"pêche","darkolivegreen":"olive foncé","yellowgreen":"vert jaunâtre"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/he/colors.js b/includes/js/dojo/nls/he/colors.js
new file mode 100644
index 0000000..3d6d08d
--- /dev/null
+++ b/includes/js/dojo/nls/he/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"כחול פלדה בהיר","orangered":"×›×ª×•× ××“×•× ","midnightblue":"midnight blue","cadetblue":"כחול ×™×","seashell":"צדף ","slategrey":"×פור צפחה","coral":"×למוג","darkturquoise":"טורקיז ×›×”×”","antiquewhite":"antique white","mediumspringgreen":"medium spring green","salmon":"סלמון ","darkgrey":"×פור ×›×”×”","ivory":"שנהב","greenyellow":"ירוק-צהוב","mistyrose":"misty rose","lightsalmon":"סלמון בהיר","silver":"כסף","dimgrey":"×פור עמו×","orange":"×›×ª×•× ","white":"לבן ","navajowhite":"navajo white","royalblue":"כחול מלכותי","deeppink":"ורוד עמוק","lime":"לימון","oldlace":"old lace","chartreuse":"chartreuse","darkcyan":"טורקיז ×›×”×”","yellow":"צהוב ","linen":"linen","olive":"olive","gold":"זהב","lawngreen":"ירוק דש×","lightyellow":"צהוב בהיר","tan":"×—×•× ×דמד×","darkviolet":"סגול ×›×”×”","lightslategrey":"×פור צפחה בהיר","grey":"×פור","darkkhaki":"×—×קי ×›×”×” ","green":"ירוק","deepskyblue":"כחול ×©×ž×™×™× ×¢×ž×•×§","aqua":"aqua","sienna":"sienna","mintcream":"mint cream","rosybrown":"×—×•× ×•×¨×“×¨×“ ","mediumslateblue":"medium slate blue","magenta":"בורדו ","lightseagreen":"ירוק ×™× ×‘×”×™×¨","cyan":"טורקיז","olivedrab":"זית ×¢×ž×•× ","darkgoldenrod":"dark goldenrod","slateblue":"כחול צפחה","mediumaquamarine":"medium aquamarine","lavender":"לבנדר ","mediumseagreen":"medium sea green","maroon":"×—×•× ×דמד×","darkslategray":"×פור צפחה ×›×”×”","mediumturquoise":"medium turquoise","ghostwhite":"ghost white","darkblue":"כחול ×›×”×”","mediumvioletred":"medium violet-red","brown":"חו×","lightgray":"×פור בהיר","sandybrown":"×—×•× ×—×•×œ×™ ","pink":"pink","firebrick":"fire brick","indigo":"×ינדיגו","snow":"שלג","darkorchid":"dark orchid","turquoise":"טורקיז ","chocolate":"שוקולד","springgreen":"ירוק ×ביב","moccasin":"moccasin","navy":"navy","lemonchiffon":"lemon chiffon","teal":"כחול-ירוק ×›×”×”","floralwhite":"floral white","cornflowerblue":"cornflower blue","paleturquoise":"pale turquoise","purple":"סגול ","gainsboro":"gainsboro","plum":"שזיף ","red":"×דו×","blue":"כחול","forestgreen":"ירוק יער","darkgreen":"ירוק ×›×”×”","honeydew":"honeydew","darkseagreen":"ירוק ×™× ×›×”×”","lightcoral":"×למוג בהיר","palevioletred":"pale violet-red","mediumpurple":"medium purple","saddlebrown":"×—×•× ×“×”×•×™","darkmagenta":"בורדו ×›×”×”","thistle":"דרדר","whitesmoke":"עשן לבן ","wheat":"חיוט","violet":"סגול ","lightskyblue":"כחול ×©×ž×™×™× ×‘×”×™×¨","goldenrod":"goldenrod","mediumblue":"medium blue","skyblue":"כחול ×©×ž×™×™× ","crimson":"×רגמן ","darksalmon":"סלמון ×›×”×”","darkred":"××“×•× ×›×”×”","darkslategrey":"×פור צפחה ×›×”×”","peru":"peru","lightgrey":"×פור בהיר","lightgoldenrodyellow":"light goldenrod yellow","blanchedalmond":"blanched almond","aliceblue":"alice blue","bisque":"bisque","slategray":"×פור צפחה","palegoldenrod":"pale goldenrod","darkorange":"×›×ª×•× ×›×”×”","aquamarine":"aquamarine","lightgreen":"ירוק בהיר","burlywood":"burlywood","dodgerblue":"כחול","darkgray":"×פור ×›×”×”","lightcyan":"טורקיז בהיר","powderblue":"כחול חיוור","blueviolet":"כחול-סגול","orchid":"סחלב ","dimgray":"×פור עמו×","beige":"בז'","fuchsia":"ורוד בהיר","lavenderblush":"סומק לבנדר","hotpink":"ורוד לוהט","steelblue":"כחול פלדה","tomato":"עגבניה","lightpink":"ורוד בהיר ","limegreen":"ירוק לימוני","indianred":"indian red","papayawhip":"papaya whip","lightslategray":"×פור צפחה בהיר","gray":"×פור","mediumorchid":"medium orchid","cornsilk":"cornsilk","black":"שחור","seagreen":"ירוק ×™×","darkslateblue":"כחול צפחה ×›×”×”","khaki":"×—×קי ","lightblue":"תכלת","palegreen":"pale green","azure":"תכלת ×¢×–","peachpuff":"peach puff","darkolivegreen":"ירוק זית ×›×”×”","yellowgreen":"ירוק צהוב"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/hu/colors.js b/includes/js/dojo/nls/hu/colors.js
new file mode 100644
index 0000000..c0bce74
--- /dev/null
+++ b/includes/js/dojo/nls/hu/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"világos acélkék","orangered":"narancsvörös","midnightblue":"éjkék","cadetblue":"kadétkék","seashell":"kagyló","slategrey":"palaszürke","coral":"korall","darkturquoise":"sötét türkizkék","antiquewhite":"antik fehér","mediumspringgreen":"közepes tavaszzöld","salmon":"lazacszín","darkgrey":"sötétszürke","ivory":"elefántcsont","greenyellow":"zöldessárga","mistyrose":"halvány rózsaszín","lightsalmon":"világos lazacszín","silver":"ezüst","dimgrey":"halványszürke","orange":"narancssárga","white":"fehér","navajowhite":"navajo fehér","royalblue":"királykék","deeppink":"sötétrózsaszín","lime":"lime","oldlace":"régi csipke","chartreuse":"chartreuse","darkcyan":"sötét ciánkék","yellow":"sárga","linen":"vászonfehér","olive":"olajzöld","gold":"arany","lawngreen":"fűzöld","lightyellow":"világossárga","tan":"rozsdabarna","darkviolet":"sötét ibolyaszín","lightslategrey":"világos palaszürke","grey":"szürke","darkkhaki":"sötét khakiszín","green":"zöld","deepskyblue":"sötét égszínkék","aqua":"vízszín","sienna":"vörösesbarna","mintcream":"mentaszósz","rosybrown":"barnásrózsaszín","mediumslateblue":"közepes palakék","magenta":"bíbor","lightseagreen":"világos tengerzöld","cyan":"ciánkék","olivedrab":"olajzöld drapp","darkgoldenrod":"sötét aranyvessző","slateblue":"palakék","mediumaquamarine":"közepes akvamarin","lavender":"levendula","mediumseagreen":"közepes tengerzöld","maroon":"gesztenyebarna","darkslategray":"sötét palaszürke","mediumturquoise":"közepes türkizkék","ghostwhite":"szellemfehér","darkblue":"sötétkék","mediumvioletred":"közepes ibolyavörös","brown":"barna","lightgray":"világosszürke","sandybrown":"homokbarna","pink":"rózsaszín","firebrick":"téglavörös","indigo":"indigó","snow":"hó","darkorchid":"sötét orchidea","turquoise":"türkizkék","chocolate":"csokoládé","springgreen":"tavaszzöld","moccasin":"mokkaszín","navy":"tengerészkék","lemonchiffon":"sárga műselyem","teal":"pávakék","floralwhite":"virágfehér","cornflowerblue":"búzavirágkék","paleturquoise":"halvány türkizkék","purple":"lila","gainsboro":"gainsboro","plum":"szilvakék","red":"vörös","blue":"kék","forestgreen":"erdőzöld","darkgreen":"sötétzöld","honeydew":"mézharmat","darkseagreen":"sötét tengerzöld","lightcoral":"világos korall","palevioletred":"halvány ibolyavörös","mediumpurple":"közepes lila","saddlebrown":"nyeregbarna","darkmagenta":"sötétbíbor","thistle":"bogáncs","whitesmoke":"fehér füst","wheat":"búza","violet":"ibolyaszín","lightskyblue":"világos égszínkék","goldenrod":"aranyvessző","mediumblue":"közepes kék","skyblue":"égszínkék","crimson":"karmazsinvörös","darksalmon":"sötét lazacszín","darkred":"sötétvörös","darkslategrey":"sötét palaszürke","peru":"peru","lightgrey":"világosszürke","lightgoldenrodyellow":"világos aranyvessző sárga","blanchedalmond":"hámozott mandula","aliceblue":"Alice kék","bisque":"porcelán","slategray":"palaszürke","palegoldenrod":"halvány aranyvessző","darkorange":"sötét narancssárga","aquamarine":"akvamarin","lightgreen":"világoszöld","burlywood":"nyersfa","dodgerblue":"dodger kék","darkgray":"sötétszürke","lightcyan":"világos ciánkék","powderblue":"púderkék","blueviolet":"ibolyakék","orchid":"orchidea","dimgray":"halványszürke","beige":"bézs","fuchsia":"fukszia","lavenderblush":"pirosas levendula","hotpink":"meleg rózsaszín","steelblue":"acélkék","tomato":"paradicsom","lightpink":"világos rózsaszín","limegreen":"limezöld","indianred":"indiánvörös","papayawhip":"papayahab","lightslategray":"világos palaszürke","gray":"szürke","mediumorchid":"közepes orchidea","cornsilk":"kukoricahaj","black":"fekete","seagreen":"tengerzöld","darkslateblue":"sötét palakék","khaki":"khakiszín","lightblue":"világoskék","palegreen":"halványzöld","azure":"azúrkék","peachpuff":"barackszín","darkolivegreen":"sötét olajzöld","yellowgreen":"sárgászöld"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/it/colors.js b/includes/js/dojo/nls/it/colors.js
new file mode 100644
index 0000000..8a53007
--- /dev/null
+++ b/includes/js/dojo/nls/it/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"blu acciao chiaro","orangered":"vermiglio","midnightblue":"blu melanzana scuro","cadetblue":"verde acqua","seashell":"sabbia rosa","slategrey":"grigio ardesia","coral":"corallo","darkturquoise":"turchese scuro","antiquewhite":"bianco antico","mediumspringgreen":"verde primavera medio","salmon":"salmone","darkgrey":"grigio scuro","ivory":"avorio","greenyellow":"giallo verde","mistyrose":"rosa pallido","lightsalmon":"salmone chiaro","silver":"grigio 25%","dimgrey":"grigio 80%","orange":"arancione","white":"bianco","navajowhite":"pesca chiaro","royalblue":"blu reale","deeppink":"ciclamino","lime":"verde fluorescente","oldlace":"mandorla","chartreuse":"verde brillante","darkcyan":"ciano scuro","yellow":"giallo","linen":"lino","olive":"verde oliva","gold":"oro","lawngreen":"verde prato","lightyellow":"giallo chiaro","tan":"grigio bruno","darkviolet":"viola scuro","lightslategrey":"grigio ardesia chiaro","grey":"grigio","darkkhaki":"kaki scuro","green":"verde","deepskyblue":"azzurro cielo scuro","aqua":"acqua","sienna":"cuoio","mintcream":"bianco nuvola","rosybrown":"marrone rosato","mediumslateblue":"blu ardesia medio","magenta":"magenta","lightseagreen":"verde mare chiaro","cyan":"ciano","olivedrab":"marrone oliva","darkgoldenrod":"ocra scuro","slateblue":"blu ardesia","mediumaquamarine":"acquamarina medio","lavender":"lavanda","mediumseagreen":"verde mare medio","maroon":"scarlatto","darkslategray":"grigio ardesia scuro","mediumturquoise":"turchese medio","ghostwhite":"bianco gesso","darkblue":"blu scuro","mediumvioletred":"vinaccia","brown":"marrone","lightgray":"grigio chiaro","sandybrown":"marrone sabbia","pink":"rosa","firebrick":"rosso mattone","indigo":"indaco","snow":"neve","darkorchid":"orchidea scuro","turquoise":"turchese","chocolate":"cioccolato","springgreen":"verde primavera","moccasin":"mocassino","navy":"blu notte","lemonchiffon":"caffelatte chiaro","teal":"verde turchese","floralwhite":"bianco giglio","cornflowerblue":"blu fiordaliso","paleturquoise":"turchese pallido","purple":"porpora","gainsboro":"grigio 10%","plum":"prugna","red":"rosso","blue":"blu","forestgreen":"verde foresta","darkgreen":"verde scuro","honeydew":"bianco germoglio","darkseagreen":"verde mare scuro","lightcoral":"rosa corallo","palevioletred":"vinaccia chiaro","mediumpurple":"porpora medio","saddlebrown":"cacao","darkmagenta":"magenta scuro","thistle":"rosa cenere","whitesmoke":"bianco fumo","wheat":"sabbia","violet":"viola","lightskyblue":"azzurro cielo chiaro","goldenrod":"ocra gialla","mediumblue":"blu medio","skyblue":"azzurro cielo","crimson":"cremisi","darksalmon":"salmone scuro","darkred":"rosso scuro","darkslategrey":"grigio ardesia scuro","peru":"marrone terra bruciata","lightgrey":"grigio chiaro","lightgoldenrodyellow":"giallo tenue","blanchedalmond":"mandorla chiaro","aliceblue":"blu alice","bisque":"incarnato","slategray":"grigio ardesia","palegoldenrod":"giallo zolfo chiaro","darkorange":"arancione scuro","aquamarine":"acquamarina","lightgreen":"verde chiaro","burlywood":"tabacco","dodgerblue":"blu d'oriente","darkgray":"grigio scuro","lightcyan":"ciano chiaro","powderblue":"azzurro polvere","blueviolet":"blu violetto","orchid":"orchidea","dimgray":"grigio 80%","beige":"beige","fuchsia":"fucsia","lavenderblush":"bianco rosato","hotpink":"rosa acceso","steelblue":"blu acciao","tomato":"pomodoro","lightpink":"rosa chiaro","limegreen":"verde lime","indianred":"terra indiana","papayawhip":"cipria","lightslategray":"grigio ardesia chiaro","gray":"grigio","mediumorchid":"orchidea medio","cornsilk":"crema","black":"nero","seagreen":"verde mare","darkslateblue":"blu ardesia scuro","khaki":"kaki","lightblue":"azzurro","palegreen":"verde pallido","azure":"azzurro ghiaccio","peachpuff":"pesca","darkolivegreen":"verde oliva scuro","yellowgreen":"giallo verde"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/ja/colors.js b/includes/js/dojo/nls/ja/colors.js
new file mode 100644
index 0000000..46aa1f2
--- /dev/null
+++ b/includes/js/dojo/nls/ja/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"ライト・スãƒãƒ¼ãƒ«ãƒ»ãƒ–ルー","orangered":"オレンジ・レッド","midnightblue":"ミッドナイト・ブルー","cadetblue":"ãã™ã‚“ã é’","seashell":"シーシェル","slategrey":"スレート・グレイ","coral":"çŠç‘š","darkturquoise":"ダーク・ターコイズ","antiquewhite":"アンティーク・ホワイト","mediumspringgreen":"ミディアム・スプリング・グリーン","salmon":"サーモン","darkgrey":"ダーク・グレイ","ivory":"アイボリー","greenyellow":"緑黄色","mistyrose":"ミスティ・ローズ","lightsalmon":"ライト・サーモン","silver":"銀","dimgrey":"ãã™ã‚“ã ã‚°ãƒ¬ã‚¤","orange":"オレンジ","white":"白","navajowhite":"ナãƒãƒ›ãƒ»ãƒ›ãƒ¯ã‚¤ãƒˆ","royalblue":"藤色","deeppink":"濃ã„ピンク","lime":"ライム","oldlace":"オールド・レイス","chartreuse":"淡黄緑","darkcyan":"ダーク・シアン・ブルー","yellow":"黄","linen":"亜麻色","olive":"オリーブ","gold":"金","lawngreen":"ローン・グリーン","lightyellow":"ライト・イエロー","tan":"茶è¤è‰²","darkviolet":"ダーク・ãƒã‚¤ã‚ªãƒ¬ãƒƒãƒˆ","lightslategrey":"ライト・スレート・グレイ","grey":"グレイ","darkkhaki":"ダーク・カーキー","green":"ç·‘","deepskyblue":"濃ã„空色","aqua":"アクア","sienna":"黄è¤è‰²","mintcream":"ミント・クリーム","rosybrown":"ロージー・ブラウン","mediumslateblue":"ミディアム・スレート・ブルー","magenta":"赤紫","lightseagreen":"ライト・シー・グリーン","cyan":"シアン・ブルー","olivedrab":"濃黄緑","darkgoldenrod":"ダーク・ゴールデン・ロッド","slateblue":"スレート・ブルー","mediumaquamarine":"ミディアム・アクアマリーン","lavender":"ラベンダー","mediumseagreen":"ミディアム・シー・グリーン","maroon":"ãˆã³èŒ¶","darkslategray":"ダーク・スレート・グレイ","mediumturquoise":"ミディアム・ターコイズ","ghostwhite":"ゴースト・ホワイト","darkblue":"ダーク・ブルー","mediumvioletred":"ミディアム・ãƒã‚¤ã‚ªãƒ¬ãƒƒãƒˆãƒ»ãƒ¬ãƒƒãƒ‰","brown":"茶","lightgray":"ライト・グレイ","sandybrown":"ç ‚è¤è‰²","pink":"ピンク","firebrick":"赤煉瓦色","indigo":"è—色","snow":"雪色","darkorchid":"ダーク・オーキッド","turquoise":"ターコイズ","chocolate":"ãƒãƒ§ã‚³ãƒ¬ãƒ¼ãƒˆ","springgreen":"スプリング・グリーン","moccasin":"モカシン","navy":"濃紺","lemonchiffon":"レモン・シフォン","teal":"ティール","floralwhite":"フローラル・ホワイト","cornflowerblue":"コーンフラワー・ブルー","paleturquoise":"ペイル・ターコイズ","purple":"ç´«","gainsboro":"ゲインズボーロ","plum":"深紫","red":"赤","blue":"é’","forestgreen":"フォレスト・グリーン","darkgreen":"ダーク・グリーン","honeydew":"ãƒãƒ‹ãƒ¼ãƒ‡ãƒ¥ãƒ¼","darkseagreen":"ダーク・シー・グリーン","lightcoral":"ライト・コーラル","palevioletred":"ペイル・ãƒã‚¤ã‚ªãƒ¬ãƒƒãƒˆãƒ»ãƒ¬ãƒƒãƒ‰","mediumpurple":"ミディアム・パープル","saddlebrown":"サドル・ブラウン","darkmagenta":"ダーク・マジェンタ","thistle":"シスル","whitesmoke":"ホワイト・スモーク","wheat":"å°éº¦è‰²","violet":"ã™ã¿ã‚Œè‰²","lightskyblue":"ライト・スカイ・ブルー","goldenrod":"ゴールデン・ロッド","mediumblue":"ミディアム・ブルー","skyblue":"スカイ・ブルー","crimson":"深紅","darksalmon":"ダーク・サーモン","darkred":"ダーク・レッド","darkslategrey":"ダーク・スレート・グレイ","peru":"ペルー","lightgrey":"ライト・グレイ","lightgoldenrodyellow":"ライト・ゴールデン・ロッド・イエロー","blanchedalmond":"çš®ãªã—アーモンド","aliceblue":"アリス・ブルー","bisque":"ビスク","slategray":"スレート・グレイ","palegoldenrod":"ペイル・ゴールデン・ロッド","darkorange":"ダーク・オレンジ","aquamarine":"碧緑","lightgreen":"ライト・グリーン","burlywood":"ãƒãƒ¼ãƒªãƒ¼ã‚¦ãƒƒãƒ‰","dodgerblue":"ドッジャー・ブルー","darkgray":"ダーク・グレイ","lightcyan":"ライト・シアン","powderblue":"æ·¡é’","blueviolet":"é’ç´«","orchid":"è–„ç´«","dimgray":"ãã™ã‚“ã ã‚°ãƒ¬ã‚¤","beige":"ベージュ","fuchsia":"紫紅色","lavenderblush":"ラベンダー・ブラッシ","hotpink":"ホット・ピンク","steelblue":"鋼色","tomato":"トマト色","lightpink":"ライト・ピンク","limegreen":"ライム・グリーン","indianred":"インディアン・レッド","papayawhip":"パパイア・ホイップ","lightslategray":"ライト・スレート・グレイ","gray":"グレイ","mediumorchid":"ミディアム・オーキッド","cornsilk":"コーンシルク","black":"é»’","seagreen":"シー・グリーン","darkslateblue":"ダーク・スレート・ブルー","khaki":"カーキー","lightblue":"ライト・ブルー","palegreen":"ペイル・グリーン","azure":"è–„ã„空色","peachpuff":"ピーãƒãƒ»ãƒ‘フ","darkolivegreen":"ダーク・オリーブ・グリーン","yellowgreen":"黄緑"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/ko/colors.js b/includes/js/dojo/nls/ko/colors.js
new file mode 100644
index 0000000..0c6576b
--- /dev/null
+++ b/includes/js/dojo/nls/ko/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"ë¼ì´íŠ¸ 스틸 블루(light steel blue)","orangered":"오렌지 레드(orange red)","midnightblue":"미드나잇 블루(midnight blue)","cadetblue":"카뎃 블루(cadet blue)","seashell":"씨쉘(seashell)","slategrey":"슬레ì´íŠ¸ 그레ì´(slate gray)","coral":"코랄(coral)","darkturquoise":"ë‹¤í¬ í„°ì½°ì¦ˆ(dark turquoise)","antiquewhite":"앤틱 í™”ì´íŠ¸(antique white)","mediumspringgreen":"미디엄 ìŠ¤í”„ë§ ê·¸ë¦°(medium spring green)","salmon":"ìƒëª¬(salmon)","darkgrey":"ë‹¤í¬ ê·¸ë ˆì´(dark gray)","ivory":"ì•„ì´ë³´ë¦¬(ivory)","greenyellow":"그린 ì˜ë¡œìš°(green-yellow)","mistyrose":"미스티 로즈(misty rose)","lightsalmon":"ë¼ì´íŠ¸ ìƒëª¬(light salmon)","silver":"실버(silver)","dimgrey":"딤 그레ì´(dim gray)","orange":"오렌지(orange)","white":"í™”ì´íŠ¸(white)","navajowhite":"나바호 í™”ì´íŠ¸(navajo white)","royalblue":"로얄 블루(royal blue)","deeppink":"딥 í•‘í¬(deep pink)","lime":"ë¼ìž„(lime)","oldlace":"올드 ë ˆì´ìŠ¤(old lace)","chartreuse":"샤르트뢰즈(chartreuse)","darkcyan":"ë‹¤í¬ ì‹œì•ˆ(dark cyan)","yellow":"ì˜ë¡œìš°(yellow)","linen":"리넨(linen)","olive":"올리브(olive)","gold":"골드(gold)","lawngreen":"ë¡  그린(lawn green)","lightyellow":"ë¼ì´íŠ¸ ì˜ë¡œìš°(light yellow)","tan":"탠(tan)","darkviolet":"ë‹¤í¬ ë°”ì´ì˜¬ë ›(dark violet)","lightslategrey":"ë¼ì´íŠ¸ 슬레ì´íŠ¸ 그레ì´(light slate gray)","grey":"그레ì´(gray)","darkkhaki":"ë‹¤í¬ ì¹´í‚¤(dark khaki)","green":"그린(green)","deepskyblue":"딥 ìŠ¤ì¹´ì´ ë¸”ë£¨(deep sky blue)","aqua":"ì•„ì¿ ì•„(aqua)","sienna":"ì‹œì—나(sienna)","mintcream":"민트 í¬ë¦¼(mint cream)","rosybrown":"로지 브ë¼ìš´(rosy brown)","mediumslateblue":"미디엄 슬레ì´íŠ¸ 블루(medium slate blue)","magenta":"마젠타(magenta)","lightseagreen":"ë¼ì´íŠ¸ 씨 그린(light sea green)","cyan":"시안(cyan)","olivedrab":"올리브 드랩(olive drab)","darkgoldenrod":"ë‹¤í¬ ê³¨ë“ ë¡œë“œ(dark goldenrod)","slateblue":"슬레ì´íŠ¸ 블루(slate blue)","mediumaquamarine":"미디엄 아쿠아마린(medium aquamarine)","lavender":"ë¼ë²¤ë”(lavender)","mediumseagreen":"미디엄 씨 그린(medium sea green)","maroon":"마룬(maroon)","darkslategray":"ë‹¤í¬ ìŠ¬ë ˆì´íŠ¸ 그레ì´(dark slate gray)","mediumturquoise":"미디엄 터콰즈(medium turquoise)","ghostwhite":"고스트 í™”ì´íŠ¸(ghost white)","darkblue":"ë‹¤í¬ ë¸”ë£¨(dark blue)","mediumvioletred":"미디엄 ë°”ì´ì˜¬ë › 레드(medium violet-red)","brown":"브ë¼ìš´(brown)","lightgray":"ë¼ì´íŠ¸ 그레ì´(light gray)","sandybrown":"샌디 브ë¼ìš´(sandy brown)","pink":"í•‘í¬(pink)","firebrick":"파ì´ì–´ 브릭(fire brick)","indigo":"ì¸ë””ê³ (indigo)","snow":"스노우(snow)","darkorchid":"ë‹¤í¬ ì˜¤í‚¤ë“œ(dark orchid)","turquoise":"터콰즈(turquoise)","chocolate":"초콜렛(chocolate)","springgreen":"ìŠ¤í”„ë§ ê·¸ë¦°(spring green)","moccasin":"모카신(moccasin)","navy":"네ì´ë¹„(navy)","lemonchiffon":"레몬 쉬í°(lemon chiffon)","teal":"틸(teal)","floralwhite":"플로랄 í™”ì´íŠ¸(floral white)","cornflowerblue":"콘플ë¼ì›Œ 블루(cornflower blue)","paleturquoise":"íŽ˜ì¼ í„°ì½°ì¦ˆ(pale turquoise)","purple":"í¼í”Œ(purple)","gainsboro":"게ì¸ìŠ¤ë¸Œë¡œ(gainsboro)","plum":"플럼(plum)","red":"레드(red)","blue":"블루(blue)","forestgreen":"í¬ë ˆìŠ¤íŠ¸ 그린(forest green)","darkgreen":"ë‹¤í¬ ê·¸ë¦°(dark green)","honeydew":"허니듀(honeydew)","darkseagreen":"ë‹¤í¬ ì”¨ 그린(dark sea green)","lightcoral":"ë¼ì´íŠ¸ 코랄(light coral)","palevioletred":"íŽ˜ì¼ ë°”ì´ì˜¬ë › 레드(pale violet-red)","mediumpurple":"미디엄 í¼í”Œ(medium purple)","saddlebrown":"새들 브ë¼ìš´(saddle brown)","darkmagenta":"ë‹¤í¬ ë§ˆì  íƒ€(dark magenta)","thistle":"시슬(thistle)","whitesmoke":"í™”ì´íŠ¸ 스모í¬(white smoke)","wheat":"휘트(wheat)","violet":"ë°”ì´ì˜¬ë ›(violet)","lightskyblue":"ë¼ì´íŠ¸ ìŠ¤ì¹´ì´ ë¸”ë£¨(light sky blue)","goldenrod":"골든로드(goldenrod)","mediumblue":"미디엄 블루(medium blue)","skyblue":"ìŠ¤ì¹´ì´ ë¸”ë£¨(sky blue)","crimson":"í¬ë¦¼ìŠ¨(crimson)","darksalmon":"ë‹¤í¬ ìƒëª¬(dark salmon)","darkred":"ë‹¤í¬ ë ˆë“œ(dark red)","darkslategrey":"ë‹¤í¬ ìŠ¬ë ˆì´íŠ¸ 그레ì´(dark slate gray)","peru":"페루(peru)","lightgrey":"ë¼ì´íŠ¸ 그레ì´(light gray)","lightgoldenrodyellow":"ë¼ì´íŠ¸ 골든로드 ì˜ë¡œìš°(light goldenrod yellow)","blanchedalmond":"블랜치 아몬드(blanched almond)","aliceblue":"앨리스 블루(alice blue)","bisque":"비스í¬(bisque)","slategray":"슬레ì´íŠ¸ 그레ì´(slate gray)","palegoldenrod":"íŽ˜ì¼ ê³¨ë“ ë¡œë“œ(pale goldenrod)","darkorange":"ë‹¤í¬ ì˜¤ë Œì§€(dark orange)","aquamarine":"아쿠아마린(aquamarine)","lightgreen":"ë¼ì´íŠ¸ 그린(light green)","burlywood":"벌리우드(burlywood)","dodgerblue":"다저 블루(dodger blue)","darkgray":"ë‹¤í¬ ê·¸ë ˆì´(dark gray)","lightcyan":"ë¼ì´íŠ¸ 시안(light cyan)","powderblue":"íŒŒìš°ë” ë¸”ë£¨(powder blue)","blueviolet":"블루 ë°”ì´ì˜¬ë ›(blue-violet)","orchid":"오키드(orchid)","dimgray":"딤 그레ì´(dim gray)","beige":"ë² ì´ì§€(beige)","fuchsia":"후í¬ìƒ¤(fuchsia)","lavenderblush":"ë¼ë²¤ë” 블러쉬(lavender blush)","hotpink":"í•« í•‘í¬(hot pink)","steelblue":"스틸 블루(steel blue)","tomato":"토마토(tomato)","lightpink":"ë¼ì´íŠ¸ í•‘í¬(light pink)","limegreen":"ë¼ìž„ 그린(lime green)","indianred":"ì¸ë””안 레드(indian red)","papayawhip":"파파야 휩(papaya whip)","lightslategray":"ë¼ì´íŠ¸ 슬레ì´íŠ¸ 그레ì´(light slate gray)","gray":"그레ì´(gray)","mediumorchid":"미디엄 오키드(medium orchid)","cornsilk":"콘실í¬(cornsilk)","black":"블랙(black)","seagreen":"씨 그린(sea green)","darkslateblue":"ë‹¤í¬ ìŠ¬ë ˆì´íŠ¸ 블루(dark slate blue)","khaki":"카키(khaki)","lightblue":"ë¼ì´íŠ¸ 블루(light blue)","palegreen":"íŽ˜ì¼ ê·¸ë¦°(pale green)","azure":"애쥬어(azure)","peachpuff":"피치 í¼í”„(peach puff)","darkolivegreen":"ë‹¤í¬ ì˜¬ë¦¬ë¸Œ 그린(dark olive green)","yellowgreen":"ì˜ë¡œìš° 그린(yellow green)"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/nb/colors.js b/includes/js/dojo/nls/nb/colors.js
new file mode 100644
index 0000000..15770a4
--- /dev/null
+++ b/includes/js/dojo/nls/nb/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"lys stålblå","orangered":"rødoransje","midnightblue":"midnattsblå","cadetblue":"mørk grønnblå","seashell":"skjellhvit","slategrey":"skifergrå","coral":"korall","darkturquoise":"mørk turkis","antiquewhite":"antikk hvit","mediumspringgreen":"middels vårgrønn","salmon":"lakserosa","darkgrey":"mørk grå","ivory":"elfenbenshvit","greenyellow":"gulgrønn","mistyrose":"lys rosenrød","lightsalmon":"lys lakserosa","silver":"sølvfarget","dimgrey":"mørk mørkegrå","orange":"oransje","white":"hvit","navajowhite":"gulbrun","royalblue":"kongeblå","deeppink":"dyp rosa","lime":"lime","oldlace":"kniplingshvit","chartreuse":"løvgrønn","darkcyan":"mørk cyan","yellow":"gul","linen":"lin","olive":"oliven","gold":"gull","lawngreen":"plengrønn","lightyellow":"lys gul","tan":"matt mellombrun","darkviolet":"mørk fiolett","lightslategrey":"lys skifergrå","grey":"grå","darkkhaki":"mørk khaki","green":"grønn","deepskyblue":"dyp himmelblå","aqua":"akva","sienna":"nøttebrun","mintcream":"mintkrem","rosybrown":"brunlilla","mediumslateblue":"middels skiferblå","magenta":"magenta","lightseagreen":"lys sjøgrønn","cyan":"cyan","olivedrab":"middels olivengrønn","darkgoldenrod":"mørk gyldenris","slateblue":"skiferblå","mediumaquamarine":"middels akvamarin","lavender":"lavendel","mediumseagreen":"middels sjøgrønn","maroon":"rødbrun","darkslategray":"mørk skifergrå","mediumturquoise":"middels turkis","ghostwhite":"egghvit","darkblue":"mørk blå","mediumvioletred":"middels fiolettrød","brown":"brun","lightgray":"lys grå","sandybrown":"sandbrun","pink":"rosa","firebrick":"mursteinsrød","indigo":"indigo","snow":"snøhvit","darkorchid":"mørk orkide","turquoise":"turkis","chocolate":"sjokolade","springgreen":"vårgrønn","moccasin":"lys gulbrun","navy":"marineblå","lemonchiffon":"ferskenfarget","teal":"mørk grønnblå","floralwhite":"blomsterhvit","cornflowerblue":"kornblå","paleturquoise":"svak turkis","purple":"purpur","gainsboro":"lys lys grå","plum":"plommefarget","red":"rød","blue":"blå","forestgreen":"skoggrønn","darkgreen":"mørk grønn","honeydew":"grønnhvit","darkseagreen":"mørk sjøgrønn","lightcoral":"lys korall","palevioletred":"svak fiolettrød","mediumpurple":"middels purpur","saddlebrown":"mørk nøttebrun","darkmagenta":"mørk magenta","thistle":"lys grålilla","whitesmoke":"røykhvit","wheat":"varm sienna","violet":"fiolett","lightskyblue":"lys himmelblå","goldenrod":"gyldenris","mediumblue":"mellomblå","skyblue":"himmelblå","crimson":"karmosinrødt","darksalmon":"mørk lakserosa","darkred":"mørk rød","darkslategrey":"mørk skifergrå","peru":"lys nøttebrun","lightgrey":"lys grå","lightgoldenrodyellow":"lys gyldenrisgul","blanchedalmond":"lys mandel","aliceblue":"blåhvit","bisque":"gulrosa","slategray":"skifergrå","palegoldenrod":"svak gyldenris","darkorange":"mørk oransje","aquamarine":"akvamarin","lightgreen":"lys grønn","burlywood":"matt mellombrun","dodgerblue":"lys havblå","darkgray":"mørk grå","lightcyan":"lys cyan","powderblue":"lys grønnblå","blueviolet":"blåfiolett","orchid":"orkide","dimgray":"mørk mørkegrå","beige":"beige","fuchsia":"fuksia","lavenderblush":"lillahvit","hotpink":"halvmørk rosa","steelblue":"stålblå","tomato":"tomatrød","lightpink":"lys rosa","limegreen":"limegrønn","indianred":"rustrød","papayawhip":"lys papaya","lightslategray":"lys skifergrå","gray":"grå","mediumorchid":"middels orkide","cornsilk":"cornsilk","black":"svart","seagreen":"sjøgrønn","darkslateblue":"mørk skiferblå","khaki":"khaki","lightblue":"lys blå","palegreen":"svak grønn","azure":"asur","peachpuff":"brunrosa","darkolivegreen":"mørk olivengrønn","yellowgreen":"gulgrønn"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/nl/colors.js b/includes/js/dojo/nls/nl/colors.js
new file mode 100644
index 0000000..ae0ccbf
--- /dev/null
+++ b/includes/js/dojo/nls/nl/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"lichtstaalblauw","orangered":"oranjerood","midnightblue":"nachtblauw","cadetblue":"donkerstaalblauw","seashell":"schelp","slategrey":"leigrijs","coral":"koraalrood","darkturquoise":"donkerturquoise","antiquewhite":"antiekwit","mediumspringgreen":"midlentegroen","salmon":"zalm","darkgrey":"donkergrijs","ivory":"ivoorwit","greenyellow":"groengeel","mistyrose":"matroze","lightsalmon":"lichtzalm","silver":"zilvergrijs","dimgrey":"dofgrijs","orange":"oranje","white":"wit","navajowhite":"navajowit","royalblue":"koningsblauw","deeppink":"donkerroze","lime":"limoen","oldlace":"kant","chartreuse":"groengeel","darkcyan":"donkercyaan","yellow":"geel","linen":"linnen","olive":"olijfgroen","gold":"goud","lawngreen":"grasgroen","lightyellow":"lichtgeel","tan":"geelbruin","darkviolet":"donkerviolet","lightslategrey":"lichtblauwgrijs","grey":"grijs","darkkhaki":"donkerkaki","green":"groen","deepskyblue":"diephemelblauw","aqua":"aqua","sienna":"sienna","mintcream":"mintroomgeel","rosybrown":"roodbruin","mediumslateblue":"midgrijsblauw","magenta":"magenta","lightseagreen":"lichtzeegroen","cyan":"cyaan","olivedrab":"grijsbruin","darkgoldenrod":"donkergoud","slateblue":"leiblauw","mediumaquamarine":"midaquamarijn","lavender":"lavendelblauw","mediumseagreen":"midzeegroen","maroon":"kastanjebruin","darkslategray":"donkerblauwgrijs","mediumturquoise":"midturquoise","ghostwhite":"spierwit","darkblue":"donkerblauw","mediumvioletred":"midvioletrood","brown":"bruin","lightgray":"lichtgrijs","sandybrown":"zandbruin","pink":"roze","firebrick":"vuursteenrood","indigo":"indigo","snow":"sneeuwwit","darkorchid":"donkerorchidee","turquoise":"turquoise","chocolate":"chocoladebruin","springgreen":"lentegroen","moccasin":"moccasin","navy":"marineblauw","lemonchiffon":"citroengeel","teal":"grijsblauw","floralwhite":"rozewit","cornflowerblue":"korenbloemblauw","paleturquoise":"bleekturquoise","purple":"purper","gainsboro":"lichtblauwgrijs","plum":"pruim","red":"rood","blue":"blauw","forestgreen":"bosgroen","darkgreen":"donkergroen","honeydew":"meloen","darkseagreen":"donkerzeegroen","lightcoral":"lichtkoraal","palevioletred":"bleekvioletrood","mediumpurple":"midpurper","saddlebrown":"leerbruin","darkmagenta":"donkermagenta","thistle":"distel","whitesmoke":"rookwit","wheat":"tarwebruin","violet":"violet","lightskyblue":"lichthemelsblauw","goldenrod":"goudbruin","mediumblue":"midblauw","skyblue":"hemelsblauw","crimson":"karmozijnrood","darksalmon":"donkerzalm","darkred":"donkerrood","darkslategrey":"donkerblauwgrijs","peru":"bruin","lightgrey":"lichtgrijs","lightgoldenrodyellow":"lichtgoudgeel","blanchedalmond":"amandel","aliceblue":"lichtblauw","bisque":"oranjegeel","slategray":"leigrijs","palegoldenrod":"bleekgeel","darkorange":"donkeroranje","aquamarine":"aquamarijn","lightgreen":"lichtgroen","burlywood":"lichtbruin","dodgerblue":"helderblauw","darkgray":"donkergrijs","lightcyan":"lichtcyaan","powderblue":"lichtblauw-wit","blueviolet":"violet","orchid":"orchidee","dimgray":"dofgrijs","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavendelblos","hotpink":"acaciaroze","steelblue":"staalblauw","tomato":"tomaat","lightpink":"lichtroze","limegreen":"limoengroen","indianred":"indisch rood","papayawhip":"papajaroze","lightslategray":"lichtblauwgrijs","gray":"grijs","mediumorchid":"midorchidee","cornsilk":"maïsgeel","black":"zwart","seagreen":"zeegroen","darkslateblue":"donkergrijsblauw","khaki":"kaki","lightblue":"lichtblauw","palegreen":"bleekgroen","azure":"azuur","peachpuff":"perzikroze","darkolivegreen":"donkerolijfgroen","yellowgreen":"geelgroen"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/pl/colors.js b/includes/js/dojo/nls/pl/colors.js
new file mode 100644
index 0000000..852268c
--- /dev/null
+++ b/includes/js/dojo/nls/pl/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"jasny stalowoniebieski","orangered":"pomarańczowoczerwony","midnightblue":"ciemnogranatowy","cadetblue":"niebieskoszary","seashell":"muszla","slategrey":"łupkowy szary","coral":"koralowy","darkturquoise":"ciemnoturkusowy","antiquewhite":"biel antyczna","mediumspringgreen":"średnia wiosenna zieleń","salmon":"łososiowy","darkgrey":"ciemnoszary","ivory":"kość słoniowa","greenyellow":"zielonożółty","mistyrose":"bladoróżany","lightsalmon":"jasnołososiowy","silver":"srebrny","dimgrey":"przytłumiony szary","orange":"pomarańczowy","white":"biały","navajowhite":"piaskowy","royalblue":"błękit królewski","deeppink":"głęboki różowy","lime":"limetkowy","oldlace":"bladopomarańczowy","chartreuse":"jaskrawozielony","darkcyan":"ciemny cyjan","yellow":"żółty","linen":"lniany","olive":"oliwkowy","gold":"złoty","lawngreen":"trawiasty","lightyellow":"jasnożółty","tan":"kawowy","darkviolet":"ciemnofioletowy","lightslategrey":"jasny łupkowy szary","grey":"szary","darkkhaki":"ciemny khaki","green":"zielony","deepskyblue":"intensywny błękit nieba","aqua":"wodny","sienna":"siena","mintcream":"jasnomiętowy","rosybrown":"różowobrązowy","mediumslateblue":"średni łupkowy niebieski","magenta":"magenta","lightseagreen":"jasna morska zieleń","cyan":"cyjan","olivedrab":"oliwkowa zieleń","darkgoldenrod":"ciemnogliniany","slateblue":"łupkowy niebieski","mediumaquamarine":"średnia akwamaryna","lavender":"lawendowy","mediumseagreen":"średnia morska zieleń","maroon":"bordowy","darkslategray":"ciemny łupkowy szary","mediumturquoise":"średni turkusowy","ghostwhite":"bladobiały","darkblue":"ciemnoniebieski","mediumvioletred":"średni fioletowoczerwony","brown":"brązowy","lightgray":"jasnoszary","sandybrown":"piaskowy brąz","pink":"różowy","firebrick":"ceglasty","indigo":"indygo","snow":"śnieżny","darkorchid":"ciemna orchidea","turquoise":"turkusowy","chocolate":"czekoladowy","springgreen":"wiosenna zieleń","moccasin":"mokasynowy","navy":"granatowy","lemonchiffon":"cytrynowy","teal":"cyrankowy","floralwhite":"kwiatowa biel","cornflowerblue":"chabrowy","paleturquoise":"bladoturkusowy","purple":"purpurowy","gainsboro":"bladoszary","plum":"śliwkowy","red":"czerwony","blue":"niebieski","forestgreen":"leśna zieleń","darkgreen":"ciemnozielony","honeydew":"melon","darkseagreen":"ciemna morska zieleń","lightcoral":"jasnokoralowy","palevioletred":"blady fioletowoczerwony","mediumpurple":"średnia purpura","saddlebrown":"skórzany brązowy","darkmagenta":"ciemna magenta","thistle":"bladofioletowy","whitesmoke":"przydymiony biały","wheat":"pszeniczny","violet":"fioletowy","lightskyblue":"jasny błękit nieba","goldenrod":"gliniany","mediumblue":"średni niebieski","skyblue":"błękit nieba","crimson":"karmazynowy","darksalmon":"ciemnołososiowy","darkred":"ciemnoczerwony","darkslategrey":"ciemny łupkowy szary","peru":"jasnobrązowy","lightgrey":"jasnoszary","lightgoldenrodyellow":"jasnogliniana żółć","blanchedalmond":"migdałowy","aliceblue":"bladoniebieski","bisque":"biszkoptowy","slategray":"łupkowy szary","palegoldenrod":"bladogliniany","darkorange":"ciemnopomarańczowy","aquamarine":"akwamaryna","lightgreen":"jasnozielony","burlywood":"kolor drewna","dodgerblue":"błękit Dodgers","darkgray":"ciemnoszary","lightcyan":"jasny cyjan","powderblue":"pudrowy niebieski","blueviolet":"niebieskofioletowy","orchid":"orchidea","dimgray":"przytłumiony szary","beige":"beżowy","fuchsia":"fuksja","lavenderblush":"lawendoworóżowy","hotpink":"intensywny różowy","steelblue":"stalowy niebieski","tomato":"pomidorowy","lightpink":"jasnoróżowy","limegreen":"limetkowozielony","indianred":"kasztanowy","papayawhip":"papaja","lightslategray":"jasny łupkowy szary","gray":"szary","mediumorchid":"średnia orchidea","cornsilk":"kukurydziany","black":"czarny","seagreen":"morska zieleń","darkslateblue":"ciemny łupkowy niebieski","khaki":"khaki","lightblue":"jasnoniebieski","palegreen":"bladozielony","azure":"lazur","peachpuff":"brzoskwiniowy","darkolivegreen":"ciemnooliwkowy","yellowgreen":"żółtozielony"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/pt-pt/colors.js b/includes/js/dojo/nls/pt-pt/colors.js
new file mode 100644
index 0000000..e01afd2
--- /dev/null
+++ b/includes/js/dojo/nls/pt-pt/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"azul-aço claro","orangered":"vermelho alaranjado","midnightblue":"azul meia-noite","cadetblue":"azul cadete","seashell":"concha","slategrey":"cinzento ardósia","coral":"coral","darkturquoise":"turquesa escuro","antiquewhite":"branco antigo","mediumspringgreen":"verde primavera médio","salmon":"salmão","darkgrey":"cinzento escuro","ivory":"marfim","greenyellow":"amarelo esverdeado","mistyrose":"rosa pálido","lightsalmon":"salmão claro","silver":"prateado","dimgrey":"cinzento escuro","orange":"laranja","white":"branco","navajowhite":"branco navajo","royalblue":"azul real","deeppink":"rosa profundo","lime":"lima","oldlace":"renda antiga","chartreuse":"amarelo esverdeado","darkcyan":"ciano escuro","yellow":"amarelo","linen":"linho","olive":"azeitona","gold":"dourado","lawngreen":"verde relva","lightyellow":"amarelo claro","tan":"castanho claro","darkviolet":"violeta escuro","lightslategrey":"cinzento ardósia claro","grey":"cinzento","darkkhaki":"caqui escuro","green":"verde","deepskyblue":"azul céu profundo","aqua":"verde-água","sienna":"castanho-avermelhado","mintcream":"creme de menta","rosybrown":"castanho rosado","mediumslateblue":"azul ardósia médio","magenta":"magenta","lightseagreen":"verde marinho claro","cyan":"ciano","olivedrab":"azeitona claro","darkgoldenrod":"ouro velho escuro","slateblue":"azul ardósia","mediumaquamarine":"verde-azulado médio","lavender":"alfazema","mediumseagreen":"verde marinho médio","maroon":"bordeaux","darkslategray":"cinzento ardósia escuro","mediumturquoise":"turquesa médio","ghostwhite":"branco sombreado","darkblue":"azul escuro","mediumvioletred":"violeta avermelhado médio","brown":"castanho","lightgray":"cinzento claro","sandybrown":"castanho areia","pink":"rosa","firebrick":"tijolo fogo","indigo":"índigo","snow":"branco-neve","darkorchid":"orquídea escuro","turquoise":"turquesa","chocolate":"chocolate","springgreen":"verde primavera","moccasin":"mocassim","navy":"azul marinho","lemonchiffon":"limão chiffon","teal":"verde-azulado","floralwhite":"branco floral","cornflowerblue":"azul-violáceo","paleturquoise":"turquesa pálido","purple":"roxo","gainsboro":"cinzento azulado claro","plum":"cor-de-ameixa","red":"vermelho","blue":"azul","forestgreen":"verde floresta","darkgreen":"verde escuro","honeydew":"mel","darkseagreen":"verde marinho escuro","lightcoral":"coral claro","palevioletred":"violeta avermelhado pálido","mediumpurple":"roxo médio","saddlebrown":"castanho sela","darkmagenta":"magenta escuro","thistle":"cardo","whitesmoke":"fumo branco","wheat":"trigo","violet":"violeta","lightskyblue":"azul céu claro","goldenrod":"ouro velho","mediumblue":"azul médio","skyblue":"azul céu","crimson":"carmesim","darksalmon":"salmão escuro","darkred":"vermelho escuro","darkslategrey":"cinzento ardósia escuro","peru":"peru","lightgrey":"cinzento claro","lightgoldenrodyellow":"ouro velho amarelado claro","blanchedalmond":"amêndoa claro","aliceblue":"azul alice","bisque":"rosa-velho","slategray":"cinzento ardósia","palegoldenrod":"ouro velho pálido","darkorange":"laranja escuro","aquamarine":"verde-azulado","lightgreen":"verde claro","burlywood":"castanho pinho","dodgerblue":"azul furtivo","darkgray":"cinzento escuro","lightcyan":"ciano claro","powderblue":"azul de esmalte","blueviolet":"azul violeta","orchid":"orquídea","dimgray":"cinzento escuro","beige":"bege","fuchsia":"fúcsia","lavenderblush":"alfazema rosado","hotpink":"rosa forte","steelblue":"azul-aço","tomato":"vermelho tomate","lightpink":"rosa claro","limegreen":"verde-lima","indianred":"almagre","papayawhip":"creme de papaia","lightslategray":"cinzento ardósia claro","gray":"cinzento","mediumorchid":"orquídea médio","cornsilk":"branco seda","black":"preto","seagreen":"verde marinho","darkslateblue":"azul ardósia escuro","khaki":"caqui","lightblue":"azul claro","palegreen":"verde pálido","azure":"azul-celeste","peachpuff":"pêssego","darkolivegreen":"verde-azeitona escuro","yellowgreen":"verde amarelado"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/pt/colors.js b/includes/js/dojo/nls/pt/colors.js
new file mode 100644
index 0000000..025ee71
--- /dev/null
+++ b/includes/js/dojo/nls/pt/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"azul metálico claro","orangered":"vermelho-alaranjado","midnightblue":"azul noturno","cadetblue":"azul-cadete","seashell":"concha marinha","slategrey":"ardósia cinza","coral":"coral","darkturquoise":"turquesa-escuro","antiquewhite":"branco velho","mediumspringgreen":"verde primavera médio","salmon":"salmão","darkgrey":"cinza-escuro","ivory":"marfim","greenyellow":"verde-amarelado","mistyrose":"rosa nublado","lightsalmon":"salmão claro","silver":"prata","dimgrey":"cinza-escuro","orange":"laranja","white":"branco","navajowhite":"branco navajo","royalblue":"azul real","deeppink":"rosa profundo","lime":"lima","oldlace":"fita velha","chartreuse":"verde-amarelado","darkcyan":"ciano-escuro","yellow":"amarelo","linen":"linho","olive":"verde-oliva","gold":"dourado","lawngreen":"verde grama","lightyellow":"amarelo-claro","tan":"canela","darkviolet":"violeta-escuro","lightslategrey":"ardósia cinza-claro","grey":"cinza","darkkhaki":"cáqui-escuro","green":"verde","deepskyblue":"azul celeste profundo","aqua":"azul-água","sienna":"marrom-avermelhado","mintcream":"menta","rosybrown":"marrom rosado","mediumslateblue":"ardósia azul médio","magenta":"magenta","lightseagreen":"verde-mar claro","cyan":"ciano","olivedrab":"verde-acastanhado","darkgoldenrod":"ouro-escuro","slateblue":"ardósia azul","mediumaquamarine":"verde-azulado temperado","lavender":"lavanda","mediumseagreen":"verde mar temperado","maroon":"castanho","darkslategray":"ardósia cinza-escuro","mediumturquoise":"turquesa médio","ghostwhite":"branco sombreado","darkblue":"azul-escuro","mediumvioletred":"violeta avermelhado médio","brown":"marrom","lightgray":"cinza-claro","sandybrown":"marrom arenoso","pink":"rosado","firebrick":"tijolo queimado","indigo":"índigo","snow":"branco neve","darkorchid":"orquídea-escuro","turquoise":"turquesa","chocolate":"chocolate","springgreen":"verde primavera","moccasin":"mocassim","navy":"marinho","lemonchiffon":"gaze limão","teal":"azul-esverdeado","floralwhite":"branco floral","cornflowerblue":"centáurea azul","paleturquoise":"turquesa pálida","purple":"púrpura","gainsboro":"gainsboro","plum":"ameixa","red":"vermelho","blue":"azul","forestgreen":"verde floresta","darkgreen":"verde-escuro","honeydew":"verde mel","darkseagreen":"verde-mar escuro","lightcoral":"coral-claro","palevioletred":"violeta pálida","mediumpurple":"púrpura temperado","saddlebrown":"marrom couro","darkmagenta":"magenta-escuro","thistle":"cardo","whitesmoke":"branco esfumaçado","wheat":"trigo","violet":"violeta","lightskyblue":"azul celeste claro","goldenrod":"ouro","mediumblue":"azul temperado","skyblue":"azul celeste","crimson":"carmim","darksalmon":"salmão escuro","darkred":"vermelho-escuro","darkslategrey":"ardósia cinza-escuro","peru":"peru","lightgrey":"cinza-claro","lightgoldenrodyellow":"amarelo-claro","blanchedalmond":"branco-amêndoa","aliceblue":"azul-bebê","bisque":"biscuit","slategray":"ardósia cinza","palegoldenrod":"ouro pálido","darkorange":"laranja-escuro","aquamarine":"água-marinha","lightgreen":"verde-claro","burlywood":"madeira","dodgerblue":"azul fugidio","darkgray":"cinza-escuro","lightcyan":"ciano-claro","powderblue":"azul pólvora","blueviolet":"violeta azulado","orchid":"orquídea","dimgray":"cinza-escuro","beige":"bege","fuchsia":"fúcsia","lavenderblush":"lavanda avermelhada","hotpink":"rosa quente","steelblue":"azul metálico","tomato":"vermelho tomate","lightpink":"rosa-claro","limegreen":"verde lima","indianred":"vermelho oriental","papayawhip":"mamão papaia","lightslategray":"ardósia cinza-claro","gray":"cinza","mediumorchid":"orquídea temperado","cornsilk":"fios de milho","black":"preto","seagreen":"verde-mar","darkslateblue":"ardósia azul-escuro","khaki":"cáqui","lightblue":"azul-claro","palegreen":"verde pálido","azure":"azul-celeste","peachpuff":"pêssego","darkolivegreen":"verde-oliva escuro","yellowgreen":"amarelo esverdeado"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/ru/colors.js b/includes/js/dojo/nls/ru/colors.js
new file mode 100644
index 0000000..4b67053
--- /dev/null
+++ b/includes/js/dojo/nls/ru/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"Ñветлый Ñтальной","orangered":"оранжево-краÑный","midnightblue":"полуночно-Ñиний","cadetblue":"Ñеро-Ñиний","seashell":"морÑÐºÐ°Ñ Ñ€Ð°ÐºÐ¾Ð²Ð¸Ð½Ð°","slategrey":"грифельно-Ñерый","coral":"коралловый","darkturquoise":"темный бирюзовый","antiquewhite":"белый антик","mediumspringgreen":"нейтральный веÑенне-зеленый","salmon":"лоÑоÑевый","darkgrey":"темно-Ñерый","ivory":"Ñлоновой коÑти","greenyellow":"зелено-желтый","mistyrose":"блекло-розовый","lightsalmon":"Ñветло-лоÑоÑевый","silver":"ÑеребриÑтый","dimgrey":"туÑкло-Ñерый","orange":"оранжевый","white":"белый","navajowhite":"белый навахо","royalblue":"королевÑкий голубой","deeppink":"темно-розовый","lime":"лайм","oldlace":"матово-белый","chartreuse":"желто-Ñалатный","darkcyan":"темный циан","yellow":"желтый","linen":"хлопковый","olive":"оливковый","gold":"золотой","lawngreen":"Ð·ÐµÐ»ÐµÐ½Ð°Ñ Ð»ÑƒÐ¶Ð°Ð¹ÐºÐ°","lightyellow":"Ñветло-желтый","tan":"рыжевато-коричневый","darkviolet":"темно-фиолетовый","lightslategrey":"Ñветлый грифельно-Ñерый","grey":"Ñерый","darkkhaki":"темный хаки","green":"зеленый","deepskyblue":"темный небеÑно-голубой","aqua":"зеленовато-голубой","sienna":"охра","mintcream":"мÑтно-кремовый","rosybrown":"розово-коричневый","mediumslateblue":"нейтральный грифельно-Ñиний","magenta":"пурпурный","lightseagreen":"Ñветлый морÑкой волны","cyan":"циан","olivedrab":"желтовато-Ñерый","darkgoldenrod":"темно-золотиÑтый","slateblue":"грифельно-Ñиний","mediumaquamarine":"нейтральный аквамарин","lavender":"бледно-лиловый","mediumseagreen":"нейтральный морÑкой волны","maroon":"темно-бордовый","darkslategray":"темный грифельно-Ñерый","mediumturquoise":"нейтральный бирюзовый","ghostwhite":"призрачно-белый","darkblue":"темно-Ñиний","mediumvioletred":"нейтральный фиолетово-краÑный","brown":"коричневый","lightgray":"Ñветло-Ñерый","sandybrown":"коричнево-пеÑчаный","pink":"розовый","firebrick":"кирпичный","indigo":"индиго","snow":"белоÑнежный","darkorchid":"темный орÑель","turquoise":"бирюзовый","chocolate":"шоколадный","springgreen":"веÑенний зеленый","moccasin":"мокаÑин","navy":"темно-Ñиний","lemonchiffon":"бледно-лимонный","teal":"чирок","floralwhite":"цветочно-белый","cornflowerblue":"фиолетово-Ñиний","paleturquoise":"бледно-бирюзовый","purple":"фиолетовый","gainsboro":"бледно-Ñерый","plum":"Ñливовый","red":"краÑный","blue":"Ñиний","forestgreen":"зеленый леÑной","darkgreen":"темно-зеленый","honeydew":"медовый","darkseagreen":"темный морÑкой волны","lightcoral":"Ñветло-коралловый","palevioletred":"бледный фиолетово-краÑный","mediumpurple":"нейтральный фиолетовый","saddlebrown":"кожано-коричневый","darkmagenta":"темно-пурпурный","thistle":"чертополох","whitesmoke":"дымчато-белый","wheat":"пшеница","violet":"фиолетовый","lightskyblue":"Ñветлый небеÑно-голубой","goldenrod":"золотиÑтый","mediumblue":"нейтральный Ñиний","skyblue":"небеÑно-голубой","crimson":"малиновый","darksalmon":"темно-лоÑоÑевый","darkred":"темно-краÑный","darkslategrey":"темный грифельно-Ñерый","peru":"перу","lightgrey":"Ñветло-Ñерый","lightgoldenrodyellow":"Ñветло-золотиÑтый","blanchedalmond":"Ñветло-миндальный","aliceblue":"Ñеро-голубой","bisque":"биÑквитный","slategray":"грифельно-Ñерый","palegoldenrod":"бледно-золотиÑтый","darkorange":"темно-оранжевый","aquamarine":"аквамарин","lightgreen":"Ñветло-зеленый","burlywood":"Ñветло-коричневый","dodgerblue":"бледно-Ñиний","darkgray":"темно-Ñерый","lightcyan":"Ñветлый циан","powderblue":"пороховой","blueviolet":"Ñине-фиолетовый","orchid":"орÑель","dimgray":"туÑкло-Ñерый","beige":"бежевый","fuchsia":"фукÑин","lavenderblush":"розовато-лиловый","hotpink":"краÑно-розовый","steelblue":"Ñтальной","tomato":"помидор","lightpink":"Ñветло-розовый","limegreen":"зеленый лайм","indianred":"индийÑкий краÑный","papayawhip":"черенок папайи","lightslategray":"Ñветлый грифельно-Ñерый","gray":"Ñерый","mediumorchid":"нейтральный орÑель","cornsilk":"шелковый оттенок","black":"черный","seagreen":"морÑкой волны","darkslateblue":"темный грифельно-Ñиний","khaki":"хаки","lightblue":"Ñветло-Ñиний","palegreen":"бледно-зеленый","azure":"лазурный","peachpuff":"перÑиковый","darkolivegreen":"темно-оливковый","yellowgreen":"желто-зеленый"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/sv/colors.js b/includes/js/dojo/nls/sv/colors.js
new file mode 100644
index 0000000..032e0c3
--- /dev/null
+++ b/includes/js/dojo/nls/sv/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"ljust stålblått","orangered":"orangerött","midnightblue":"midnattsblått","cadetblue":"kadettblått","seashell":"snäckskal","slategrey":"skiffergrått","coral":"korall","darkturquoise":"mörkturkost","antiquewhite":"antikvitt","mediumspringgreen":"medelvårgrönt","salmon":"laxfärgat","darkgrey":"mörkgrått","ivory":"elfenbensvitt","greenyellow":"gröngult","mistyrose":"dunkelrosa","lightsalmon":"ljust laxfärgat","silver":"silver","dimgrey":"smutsgrått","orange":"orange","white":"vitt","navajowhite":"navajovitt","royalblue":"kungligt blått","deeppink":"djuprosa","lime":"lime","oldlace":"spetsvitt","chartreuse":"chartreuse","darkcyan":"mörkt cyan","yellow":"gult","linen":"linne","olive":"olivfärgat","gold":"guld","lawngreen":"gräsmattegrönt","lightyellow":"ljusgult","tan":"mellanbrunt","darkviolet":"mörkviolett","lightslategrey":"ljust skiffergrått","grey":"grått","darkkhaki":"mörkt kaki","green":"grönt","deepskyblue":"mörkt himmelsblått","aqua":"akvamarin","sienna":"sienna","mintcream":"mintgrädde","rosybrown":"rosenbrunt","mediumslateblue":"medelskifferblått","magenta":"magenta","lightseagreen":"ljust havsgrönt","cyan":"cyan","olivedrab":"olivsmutsgult","darkgoldenrod":"mörkt gullris","slateblue":"skifferblått","mediumaquamarine":"medelakvamarin","lavender":"lavendel","mediumseagreen":"medelhavsgrönt","maroon":"rödbrunt","darkslategray":"mörkt skiffergrått","mediumturquoise":"medelturkost","ghostwhite":"spökvitt","darkblue":"mörkblått","mediumvioletred":"medelviolettrött","brown":"brunt","lightgray":"ljusgrått","sandybrown":"sandbrunt","pink":"rosa","firebrick":"tegelstensrött","indigo":"indigo","snow":"snö","darkorchid":"mörkt orkidé","turquoise":"turkost","chocolate":"choklad","springgreen":"vårgrönt","moccasin":"mockasin","navy":"marinblått","lemonchiffon":"citronchiffong","teal":"blågrönt","floralwhite":"blomvitt","cornflowerblue":"kornblått","paleturquoise":"blekturkost","purple":"lila","gainsboro":"gainsboro","plum":"plommon","red":"rött","blue":"blått","forestgreen":"skogsgrönt","darkgreen":"mörkgrönt","honeydew":"honungsdagg","darkseagreen":"mörkt havsgrönt","lightcoral":"ljuskorall","palevioletred":"blekviolettrött","mediumpurple":"medellila","saddlebrown":"sadelbrunt","darkmagenta":"mörk magenta","thistle":"tistel","whitesmoke":"vit rök","wheat":"vete","violet":"violett","lightskyblue":"ljust himmelsblått","goldenrod":"gullris","mediumblue":"medelblått","skyblue":"himmelsblått","crimson":"karmosinrött","darksalmon":"mörkt laxfärgat","darkred":"mörkrött","darkslategrey":"mörkt skiffergrått","peru":"peru","lightgrey":"ljusgrått","lightgoldenrodyellow":"ljust gullrisgult","blanchedalmond":"skållad mandel","aliceblue":"aliceblå","bisque":"biskvi","slategray":"skiffergrått","palegoldenrod":"blekt gullris","darkorange":"mörkorange","aquamarine":"akvamarin","lightgreen":"ljusgrönt","burlywood":"träfärgat","dodgerblue":"dodgerblått","darkgray":"mörkgrått","lightcyan":"ljust cyan","powderblue":"pulverblått","blueviolet":"blåviolett","orchid":"orkidé","dimgray":"smutsgrått","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavendelskimrande","hotpink":"varmrosa","steelblue":"stålblått","tomato":"tomatrött","lightpink":"ljusrosa","limegreen":"limegrönt","indianred":"indianrött","papayawhip":"papayaröra","lightslategray":"ljust skiffergrått","gray":"grått","mediumorchid":"medelorkidé","cornsilk":"gulvitt","black":"black","seagreen":"havsgrönt","darkslateblue":"mörkt skifferblått","khaki":"kaki","lightblue":"ljusblått","palegreen":"blekgrönt","azure":"azurblått","peachpuff":"persika","darkolivegreen":"mörkt olivgrönt","yellowgreen":"gulgrönt"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/tr/colors.js b/includes/js/dojo/nls/tr/colors.js
new file mode 100644
index 0000000..a75f12f
--- /dev/null
+++ b/includes/js/dojo/nls/tr/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"açık metalik mavi","orangered":"turuncu kırmızı","midnightblue":"gece mavisi","cadetblue":"denizci mavisi","seashell":"deniz kabuğu","slategrey":"arduvaz grisi","coral":"mercan","darkturquoise":"koyu turkuaz","antiquewhite":"antik beyaz","mediumspringgreen":"orta bahar yeşili","salmon":"somon","darkgrey":"koyu gri","ivory":"fildişi","greenyellow":"yeşil-sarı","mistyrose":"gülkurusu","lightsalmon":"açık somon","silver":"gümüş","dimgrey":"soluk gri","orange":"turuncu","white":"beyaz","navajowhite":"navajo beyazı","royalblue":"parlak koyu mavi","deeppink":"koyu pembe","lime":"limon yeşili","oldlace":"eski dantel","chartreuse":"chartreuse","darkcyan":"koyu camgöbeği","yellow":"sarı","linen":"keten","olive":"zeytin","gold":"altın","lawngreen":"çimen yeşili","lightyellow":"açık sarı","tan":"güneş yanığı","darkviolet":"koyu eflatun","lightslategrey":"açık arduvaz grisi","grey":"gri","darkkhaki":"koyu haki","green":"yeşil","deepskyblue":"koyu gök mavisi","aqua":"deniz mavisi","sienna":"koyu kahve","mintcream":"naneli krem","rosybrown":"pembemsi kahverengi","mediumslateblue":"orta arduvaz mavisi","magenta":"macenta","lightseagreen":"açık deniz yeşili","cyan":"camgöbeği","olivedrab":"asker yeşili","darkgoldenrod":"koyu sarı","slateblue":"arduvaz mavisi","mediumaquamarine":"orta akuamarin","lavender":"lavanta","mediumseagreen":"orta deniz yeşili","maroon":"kestane","darkslategray":"koyu arduvaz grisi","mediumturquoise":"orta turkuaz","ghostwhite":"silik beyaz","darkblue":"koyu mavi","mediumvioletred":"orta menekşe kırmızısı","brown":"kahverengi","lightgray":"açık gri","sandybrown":"kum rengi","pink":"pembe","firebrick":"canlı kiremit","indigo":"çivit mavisi","snow":"kar","darkorchid":"koyu orkide","turquoise":"turkuaz","chocolate":"çikolata","springgreen":"bahar yeşili","moccasin":"mokosen","navy":"lacivert","lemonchiffon":"limoni","teal":"Teal mavi","floralwhite":"çiçek beyazı","cornflowerblue":"peygamber çiçeği mavisi","paleturquoise":"soluk turkuaz","purple":"mor","gainsboro":"gainsboro","plum":"erik","red":"kırmızı","blue":"mavi","forestgreen":"koyu deniz yeşili","darkgreen":"koyu yeşil","honeydew":"çam sakızı","darkseagreen":"koyu deniz yeşili","lightcoral":"açık mercan","palevioletred":"soluk menekşe kırmızısı","mediumpurple":"orta mor","saddlebrown":"açık kahve","darkmagenta":"koyu mor","thistle":"devedikeni","whitesmoke":"beyaz duman","wheat":"buğday","violet":"eflatun","lightskyblue":"açık gök mavisi","goldenrod":"sarısabır","mediumblue":"orta mavi","skyblue":"gök mavisi","crimson":"crimson","darksalmon":"koyu somon","darkred":"koyu kırmızı","darkslategrey":"koyu arduvaz grisi","peru":"peru","lightgrey":"açık gri","lightgoldenrodyellow":"açık sarısabır","blanchedalmond":"soluk badem","aliceblue":"alice mavisi","bisque":"bisküvi","slategray":"arduvaz grisi","palegoldenrod":"soluk sarısabır","darkorange":"koyu turuncu","aquamarine":"akuamarin","lightgreen":"açık yeşil","burlywood":"sarımsı kahverengi","dodgerblue":"toz mavisi","darkgray":"koyu gri","lightcyan":"açık camgöbeği","powderblue":"pudra mavisi","blueviolet":"mavi-mor","orchid":"orkide","dimgray":"soluk gri","beige":"bej","fuchsia":"fuşya","lavenderblush":"lavanta pembesi","hotpink":"sıcak pembe","steelblue":"metalik mavi","tomato":"domates","lightpink":"açık pembe","limegreen":"küf yeşili","indianred":"kızılderili kırmızısı","papayawhip":"papaya sapı","lightslategray":"açık arduvaz grisi","gray":"gri","mediumorchid":"orta orkide","cornsilk":"mısır rengi","black":"siyah","seagreen":"deniz yeşili","darkslateblue":"koyu arduvaz mavisi","khaki":"haki","lightblue":"açık mavi","palegreen":"soluk yeşil","azure":"azur mavisi","peachpuff":"açık şeftali","darkolivegreen":"koyu zeytin yeşili","yellowgreen":"sarı yeşil"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/zh-tw/colors.js b/includes/js/dojo/nls/zh-tw/colors.js
new file mode 100644
index 0000000..6ee6c5e
--- /dev/null
+++ b/includes/js/dojo/nls/zh-tw/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"æ·¡éµè—色","orangered":"橙紅色","midnightblue":"åˆå¤œè—","cadetblue":"è»æœè—","seashell":"æµ·è²è‰²","slategrey":"岩ç°è‰²","coral":"çŠç‘šç´…","darkturquoise":"æš—æ¾çŸ³ç¶ ","antiquewhite":"米白色","mediumspringgreen":"中春綠色","salmon":"鮭紅色","darkgrey":"æš—ç°è‰²","ivory":"象牙色","greenyellow":"綠黃色","mistyrose":"霧玫瑰色","lightsalmon":"æ·¡é®­ç´…","silver":"銀色","dimgrey":"æ˜ç°è‰²","orange":"橙色","white":"白色","navajowhite":"å°åœ°å®‰é»ƒè‰²","royalblue":"å“è—色","deeppink":"深粉紅色","lime":"檸檬色","oldlace":"舊蕾絲色","chartreuse":"淡黃綠色","darkcyan":"æš—é’色","yellow":"黃色","linen":"亞麻色","olive":"橄欖色","gold":"金色","lawngreen":"è‰ç¶ è‰²","lightyellow":"淡黃色","tan":"çš®é©è‰²","darkviolet":"暗紫羅蘭色","lightslategrey":"淡岩ç°è‰²","grey":"ç°è‰²","darkkhaki":"æš—å¡å…¶è‰²","green":"綠色","deepskyblue":"深天è—色","aqua":"水色","sienna":"黃土赭色","mintcream":"è–„è·ä¹³ç™½è‰²","rosybrown":"玫瑰è¤","mediumslateblue":"中岩è—色","magenta":"紫紅色","lightseagreen":"淡海綠色","cyan":"é’色","olivedrab":"橄欖綠","darkgoldenrod":"暗金èŠè‰²","slateblue":"岩è—色","mediumaquamarine":"中碧綠色","lavender":"è–°è¡£è‰ç´«","mediumseagreen":"中海綠色","maroon":"栗色","darkslategray":"暗岩ç°è‰²","mediumturquoise":"中æ¾çŸ³ç¶ ","ghostwhite":"å¹½éˆè‰²","darkblue":"æš—è—色","mediumvioletred":"中紫羅蘭紅","brown":"è¤è‰²","lightgray":"æ·¡ç°è‰²","sandybrown":"æ²™è¤è‰²","pink":"粉紅色","firebrick":"紅磚色","indigo":"é›è—色","snow":"雪白色","darkorchid":"暗蘭花色","turquoise":"æ¾çŸ³ç¶ ","chocolate":"巧克力色","springgreen":"春綠色","moccasin":"鹿皮黃色","navy":"æµ·è»è—","lemonchiffon":"奶油黃","teal":"æ·±è—綠色","floralwhite":"花å‰ç™½","cornflowerblue":"矢車èŠè—","paleturquoise":"ç°æ¾çŸ³ç¶ ","purple":"紫色","gainsboro":"石æ¿ç°","plum":"æŽç´«è‰²","red":"紅色","blue":"è—色","forestgreen":"森綠色","darkgreen":"暗綠色","honeydew":"密瓜色","darkseagreen":"暗海綠色","lightcoral":"æ·¡çŠç‘šç´…","palevioletred":"ç°ç´«ç¾…蘭紅","mediumpurple":"中紫色","saddlebrown":"éžè¤è‰²","darkmagenta":"暗紫紅色","thistle":"薊色","whitesmoke":"白煙色","wheat":"å°éº¥è‰²","violet":"紫羅蘭色","lightskyblue":"淡天è—色","goldenrod":"金èŠè‰²","mediumblue":"中è—色","skyblue":"天è—色","crimson":"暗深紅色","darksalmon":"æš—é®­ç´…","darkred":"暗紅色","darkslategrey":"暗岩ç°è‰²","peru":"祕魯色","lightgrey":"æ·¡ç°è‰²","lightgoldenrodyellow":"淡金èŠé»ƒ","blanchedalmond":"æä»ç™½","aliceblue":"愛麗絲è—","bisque":"橘黃色","slategray":"岩ç°è‰²","palegoldenrod":"ç°é‡‘èŠè‰²","darkorange":"暗橙色","aquamarine":"碧綠色","lightgreen":"淡綠色","burlywood":"實木色","dodgerblue":"é“奇è—","darkgray":"æš—ç°è‰²","lightcyan":"æ·¡é’色","powderblue":"粉è—色","blueviolet":"è—紫色","orchid":"蘭花色","dimgray":"æ˜ç°è‰²","beige":"ç°æ£•è‰²","fuchsia":"海棠紅","lavenderblush":"è–°è¡£è‰ç´«ç´…","hotpink":"暖粉紅色","steelblue":"éµè—色","tomato":"蕃茄紅","lightpink":"淡粉紅色","limegreen":"檸檬綠","indianred":"å°åº¦ç´…","papayawhip":"番木瓜色","lightslategray":"淡岩ç°è‰²","gray":"ç°è‰²","mediumorchid":"中蘭紫色","cornsilk":"玉米黃","black":"黑色","seagreen":"海綠色","darkslateblue":"暗岩è—色","khaki":"å¡å…¶è‰²","lightblue":"æ·¡è—色","palegreen":"ç°ç¶ è‰²","azure":"天è—色","peachpuff":"粉撲桃色","darkolivegreen":"暗橄欖綠","yellowgreen":"黃綠色"}) \ No newline at end of file
diff --git a/includes/js/dojo/nls/zh/colors.js b/includes/js/dojo/nls/zh/colors.js
new file mode 100644
index 0000000..93268e1
--- /dev/null
+++ b/includes/js/dojo/nls/zh/colors.js
@@ -0,0 +1 @@
+({"lightsteelblue":"æµ…é’¢è“色","orangered":"橙红色","midnightblue":"æ·±è“色","cadetblue":"ç°è“色","seashell":"æµ·è´è‰²","slategrey":"ç°çŸ³è‰²","coral":"çŠç‘šè‰²","darkturquoise":"深粉è“","antiquewhite":"å¤è‘£ç™½","mediumspringgreen":"间春绿色","salmon":"橙红","darkgrey":"æ·±ç°è‰²","ivory":"象牙色","greenyellow":"绿黄色","mistyrose":"浅玫瑰色","lightsalmon":"淡橙色","silver":"银白色","dimgrey":"æš—ç°è‰²","orange":"橙色","white":"白色","navajowhite":"纳瓦白","royalblue":"å“è“","deeppink":"深粉红色","lime":"淡黄绿色","oldlace":"è€ç™½è‰²","chartreuse":"黄绿色","darkcyan":"æ·±é’绿","yellow":"黄色","linen":"亚麻色","olive":"橄榄绿","gold":"金黄色","lawngreen":"è‰ç»¿è‰²","lightyellow":"浅黄色","tan":"棕è¤è‰²","darkviolet":"深紫色","lightslategrey":"æµ…é’ç°","grey":"ç°è‰²","darkkhaki":"æ·±å¡å…¶è‰²","green":"绿色","deepskyblue":"深天è“色","aqua":"浅绿色","sienna":"赭色","mintcream":"è–„è·è‰²","rosybrown":"è¤çŽ«ç‘°çº¢","mediumslateblue":"é—´æš—è“色","magenta":"洋红色","lightseagreen":"浅海藻绿","cyan":"é’è“色","olivedrab":"è‰ç»¿è‰²","darkgoldenrod":"深金黄","slateblue":"石è“色","mediumaquamarine":"间绿色","lavender":"淡紫色","mediumseagreen":"é—´æµ·è“色","maroon":"栗色","darkslategray":"æ·±é’ç°","mediumturquoise":"间绿å®çŸ³è‰²","ghostwhite":"è‹ç™½","darkblue":"æ·±è“","mediumvioletred":"间紫罗兰色","brown":"棕色","lightgray":"æµ…ç°è‰²","sandybrown":"æ²™è¤è‰²","pink":"粉红色","firebrick":"砖红","indigo":"é›é’","snow":"雪白色","darkorchid":"深紫色","turquoise":"绿å®çŸ³è‰²","chocolate":"巧克力色","springgreen":"春绿色","moccasin":"鹿皮色","navy":"æ·±è“色","lemonchiffon":"柠檬绸色","teal":"水鸭色","floralwhite":"花白色","cornflowerblue":"æµ…è“色","paleturquoise":"è‹ç»¿è‰²","purple":"紫色","gainsboro":"æ·¡ç°è‰²","plum":"æ¨æŽè‰²","red":"红色","blue":"è“色","forestgreen":"森林绿","darkgreen":"深绿色","honeydew":"蜜æ±è‰²","darkseagreen":"深海藻绿","lightcoral":"æµ…çŠç‘šè‰²","palevioletred":"è‹ç´«ç½—兰色","mediumpurple":"间紫色","saddlebrown":"é‡è¤è‰²","darkmagenta":"深洋红色","thistle":"蓟色","whitesmoke":"烟白色","wheat":"浅黄色","violet":"紫色","lightskyblue":"浅天è“色","goldenrod":"金麒麟色","mediumblue":"é—´è“色","skyblue":"天è“色","crimson":"深红色","darksalmon":"深橙红","darkred":"深红色","darkslategrey":"æ·±é’ç°","peru":"秘é²è‰²","lightgrey":"æµ…ç°è‰²","lightgoldenrodyellow":"浅金黄色","blanchedalmond":"白æ色","aliceblue":"爱丽ä¸è“","bisque":"桔黄色","slategray":"ç°çŸ³è‰²","palegoldenrod":"淡金黄色","darkorange":"深橙色","aquamarine":"碧绿色","lightgreen":"浅绿色","burlywood":"实木色","dodgerblue":"é—ªè“色","darkgray":"æ·±ç°è‰²","lightcyan":"æµ…é’色","powderblue":"é“è“","blueviolet":"紫罗兰色","orchid":"紫色","dimgray":"æš—ç°è‰²","beige":"米色","fuchsia":"紫红色","lavenderblush":"淡紫红","hotpink":"深粉红","steelblue":"é’¢è“色","tomato":"西红柿色","lightpink":"浅粉红色","limegreen":"橙绿色","indianred":"å°åº¦çº¢","papayawhip":"木瓜色","lightslategray":"æµ…é’ç°","gray":"ç°è‰²","mediumorchid":"间紫色","cornsilk":"米绸色","black":"黑色","seagreen":"海绿色","darkslateblue":"æ·±é’è“","khaki":"å¡å…¶è‰²","lightblue":"æ·¡è“色","palegreen":"淡绿色","azure":"天è“色","peachpuff":"桃色","darkolivegreen":"深橄榄绿","yellowgreen":"黄绿色"}) \ No newline at end of file
diff --git a/includes/js/dojo/number.js b/includes/js/dojo/number.js
new file mode 100644
index 0000000..4632acc
--- /dev/null
+++ b/includes/js/dojo/number.js
@@ -0,0 +1,551 @@
+if(!dojo._hasResource["dojo.number"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.number"] = true;
+dojo.provide("dojo.number");
+
+dojo.require("dojo.i18n");
+dojo.requireLocalization("dojo.cldr", "number", null, "zh-cn,zh,ko-kr,pt,en-us,en-gb,de,ja,ja-jp,en,ROOT,en-au,fr,es,ko,zh-tw,it,es-es,de-de");
+dojo.require("dojo.string");
+dojo.require("dojo.regexp");
+
+
+/*=====
+dojo.number = {
+ // summary: localized formatting and parsing routines for Number
+}
+
+dojo.number.__FormatOptions = function(){
+ // pattern: String?
+ // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // with this string
+ // type: String?
+ // choose a format type based on the locale from the following:
+ // decimal, scientific, percent, currency. decimal by default.
+ // places: Number?
+ // fixed number of decimal places to show. This overrides any
+ // information in the provided pattern.
+ // round: Number?
+ // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
+ // means don't round.
+ // currency: String?
+ // an [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD"
+ // symbol: String?
+ // localized currency symbol
+ // locale: String?
+ // override the locale used to determine formatting rules
+ this.pattern = pattern;
+ this.type = type;
+ this.places = places;
+ this.round = round;
+ this.currency = currency;
+ this.symbol = symbol;
+ this.locale = locale;
+}
+=====*/
+
+dojo.number.format = function(/*Number*/value, /*dojo.number.__FormatOptions?*/options){
+ // summary:
+ // Format a Number as a String, using locale-specific settings
+ // description:
+ // Create a string from a Number using a known localized pattern.
+ // Formatting patterns appropriate to the locale are chosen from the
+ // [CLDR](http://unicode.org/cldr) as well as the appropriate symbols and
+ // delimiters. See <http://www.unicode.org/reports/tr35/#Number_Elements>
+ // value:
+ // the number to be formatted. If not a valid JavaScript number,
+ // return null.
+
+ options = dojo.mixin({}, options || {});
+ var locale = dojo.i18n.normalizeLocale(options.locale);
+ var bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale);
+ options.customs = bundle;
+ var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
+ if(isNaN(value)){ return null; } // null
+ return dojo.number._applyPattern(value, pattern, options); // String
+};
+
+//dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enough
+dojo.number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enough
+
+dojo.number._applyPattern = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatOptions?*/options){
+ // summary:
+ // Apply pattern to format value as a string using options. Gives no
+ // consideration to local customs.
+ // value:
+ // the number to be formatted.
+ // pattern:
+ // a pattern string as described by
+ // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // options: dojo.number.__FormatOptions?
+ // _applyPattern is usually called via `dojo.number.format()` which
+ // populates an extra property in the options parameter, "customs".
+ // The customs object specifies group and decimal parameters if set.
+
+ //TODO: support escapes
+ options = options || {};
+ var group = options.customs.group;
+ var decimal = options.customs.decimal;
+
+ var patternList = pattern.split(';');
+ var positivePattern = patternList[0];
+ pattern = patternList[(value < 0) ? 1 : 0] || ("-" + positivePattern);
+
+ //TODO: only test against unescaped
+ if(pattern.indexOf('%') != -1){
+ value *= 100;
+ }else if(pattern.indexOf('\u2030') != -1){
+ value *= 1000; // per mille
+ }else if(pattern.indexOf('\u00a4') != -1){
+ group = options.customs.currencyGroup || group;//mixins instead?
+ decimal = options.customs.currencyDecimal || decimal;// Should these be mixins instead?
+ pattern = pattern.replace(/\u00a4{1,3}/, function(match){
+ var prop = ["symbol", "currency", "displayName"][match.length-1];
+ return options[prop] || options.currency || "";
+ });
+ }else if(pattern.indexOf('E') != -1){
+ throw new Error("exponential notation not supported");
+ }
+
+ //TODO: support @ sig figs?
+ var numberPatternRE = dojo.number._numberPatternRE;
+ var numberPattern = positivePattern.match(numberPatternRE);
+ if(!numberPattern){
+ throw new Error("unable to find a number expression in pattern: "+pattern);
+ }
+ return pattern.replace(numberPatternRE,
+ dojo.number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places}));
+}
+
+dojo.number.round = function(/*Number*/value, /*Number*/places, /*Number?*/multiple){
+ // summary:
+ // Rounds the number at the given number of places
+ // value:
+ // the number to round
+ // places:
+ // the number of decimal places where rounding takes place
+ // multiple:
+ // rounds next place to nearest multiple
+
+ var pieces = String(value).split(".");
+ var length = (pieces[1] && pieces[1].length) || 0;
+ if(length > places){
+ var factor = Math.pow(10, places);
+ if(multiple > 0){factor *= 10/multiple;places++;} //FIXME
+ value = Math.round(value * factor)/factor;
+
+ // truncate to remove any residual floating point values
+ pieces = String(value).split(".");
+ length = (pieces[1] && pieces[1].length) || 0;
+ if(length > places){
+ pieces[1] = pieces[1].substr(0, places);
+ value = Number(pieces.join("."));
+ }
+ }
+ return value; //Number
+}
+
+/*=====
+dojo.number.__FormatAbsoluteOptions = function(){
+ // decimal: String?
+ // the decimal separator
+ // group: String?
+ // the group separator
+ // places: Integer?
+ // number of decimal places
+ // round: Number?
+ // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
+ // means don't round.
+ this.decimal = decimal;
+ this.group = group;
+ this.places = places;
+ this.round = round;
+}
+=====*/
+
+dojo.number._formatAbsolute = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatAbsoluteOptions?*/options){
+ // summary:
+ // Apply numeric pattern to absolute value using options. Gives no
+ // consideration to local customs.
+ // value:
+ // the number to be formatted, ignores sign
+ // pattern:
+ // the number portion of a pattern (e.g. `#,##0.00`)
+ options = options || {};
+ if(options.places === true){options.places=0;}
+ if(options.places === Infinity){options.places=6;} // avoid a loop; pick a limit
+
+ var patternParts = pattern.split(".");
+ var maxPlaces = (options.places >= 0) ? options.places : (patternParts[1] && patternParts[1].length) || 0;
+ if(!(options.round < 0)){
+ value = dojo.number.round(value, maxPlaces, options.round);
+ }
+
+ var valueParts = String(Math.abs(value)).split(".");
+ var fractional = valueParts[1] || "";
+ if(options.places){
+ valueParts[1] = dojo.string.pad(fractional.substr(0, options.places), options.places, '0', true);
+ }else if(patternParts[1] && options.places !== 0){
+ // Pad fractional with trailing zeros
+ var pad = patternParts[1].lastIndexOf("0") + 1;
+ if(pad > fractional.length){
+ valueParts[1] = dojo.string.pad(fractional, pad, '0', true);
+ }
+
+ // Truncate fractional
+ var places = patternParts[1].length;
+ if(places < fractional.length){
+ valueParts[1] = fractional.substr(0, places);
+ }
+ }else{
+ if(valueParts[1]){ valueParts.pop(); }
+ }
+
+ // Pad whole with leading zeros
+ var patternDigits = patternParts[0].replace(',', '');
+ pad = patternDigits.indexOf("0");
+ if(pad != -1){
+ pad = patternDigits.length - pad;
+ if(pad > valueParts[0].length){
+ valueParts[0] = dojo.string.pad(valueParts[0], pad);
+ }
+
+ // Truncate whole
+ if(patternDigits.indexOf("#") == -1){
+ valueParts[0] = valueParts[0].substr(valueParts[0].length - pad);
+ }
+ }
+
+ // Add group separators
+ var index = patternParts[0].lastIndexOf(',');
+ var groupSize, groupSize2;
+ if(index != -1){
+ groupSize = patternParts[0].length - index - 1;
+ var remainder = patternParts[0].substr(0, index);
+ index = remainder.lastIndexOf(',');
+ if(index != -1){
+ groupSize2 = remainder.length - index - 1;
+ }
+ }
+ var pieces = [];
+ for(var whole = valueParts[0]; whole;){
+ var off = whole.length - groupSize;
+ pieces.push((off > 0) ? whole.substr(off) : whole);
+ whole = (off > 0) ? whole.slice(0, off) : "";
+ if(groupSize2){
+ groupSize = groupSize2;
+ delete groupSize2;
+ }
+ }
+ valueParts[0] = pieces.reverse().join(options.group || ",");
+
+ return valueParts.join(options.decimal || ".");
+};
+
+/*=====
+dojo.number.__RegexpOptions = function(){
+ // pattern: String?
+ // override pattern with this string. Default is provided based on
+ // locale.
+ // type: String?
+ // choose a format type based on the locale from the following:
+ // decimal, scientific, percent, currency. decimal by default.
+ // locale: String?
+ // override the locale used to determine formatting rules
+ // strict: Boolean?
+ // strict parsing, false by default
+ // places: Number|String?
+ // number of decimal places to accept: Infinity, a positive number, or
+ // a range "n,m". By default, defined by pattern.
+ this.pattern = pattern;
+ this.type = type;
+ this.locale = locale;
+ this.strict = strict;
+ this.places = places;
+}
+=====*/
+dojo.number.regexp = function(/*dojo.number.__RegexpOptions?*/options){
+ // summary:
+ // Builds the regular needed to parse a number
+ // description:
+ // Returns regular expression with positive and negative match, group
+ // and decimal separators
+ return dojo.number._parseInfo(options).regexp; // String
+}
+
+dojo.number._parseInfo = function(/*Object?*/options){
+ options = options || {};
+ var locale = dojo.i18n.normalizeLocale(options.locale);
+ var bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale);
+ var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
+//TODO: memoize?
+ var group = bundle.group;
+ var decimal = bundle.decimal;
+ var factor = 1;
+
+ if(pattern.indexOf('%') != -1){
+ factor /= 100;
+ }else if(pattern.indexOf('\u2030') != -1){
+ factor /= 1000; // per mille
+ }else{
+ var isCurrency = pattern.indexOf('\u00a4') != -1;
+ if(isCurrency){
+ group = bundle.currencyGroup || group;
+ decimal = bundle.currencyDecimal || decimal;
+ }
+ }
+
+ //TODO: handle quoted escapes
+ var patternList = pattern.split(';');
+ if(patternList.length == 1){
+ patternList.push("-" + patternList[0]);
+ }
+
+ var re = dojo.regexp.buildGroupRE(patternList, function(pattern){
+ pattern = "(?:"+dojo.regexp.escapeString(pattern, '.')+")";
+ return pattern.replace(dojo.number._numberPatternRE, function(format){
+ var flags = {
+ signed: false,
+ separator: options.strict ? group : [group,""],
+ fractional: options.fractional,
+ decimal: decimal,
+ exponent: false};
+ var parts = format.split('.');
+ var places = options.places;
+ if(parts.length == 1 || places === 0){flags.fractional = false;}
+ else{
+ if(places === undefined){ places = parts[1].lastIndexOf('0')+1; }
+ if(places && options.fractional == undefined){flags.fractional = true;} // required fractional, unless otherwise specified
+ if(!options.places && (places < parts[1].length)){ places += "," + parts[1].length; }
+ flags.places = places;
+ }
+ var groups = parts[0].split(',');
+ if(groups.length>1){
+ flags.groupSize = groups.pop().length;
+ if(groups.length>1){
+ flags.groupSize2 = groups.pop().length;
+ }
+ }
+ return "("+dojo.number._realNumberRegexp(flags)+")";
+ });
+ }, true);
+
+ if(isCurrency){
+ // substitute the currency symbol for the placeholder in the pattern
+ re = re.replace(/(\s*)(\u00a4{1,3})(\s*)/g, function(match, before, target, after){
+ var prop = ["symbol", "currency", "displayName"][target.length-1];
+ var symbol = dojo.regexp.escapeString(options[prop] || options.currency || "");
+ before = before ? "\\s" : "";
+ after = after ? "\\s" : "";
+ if(!options.strict){
+ if(before){before += "*";}
+ if(after){after += "*";}
+ return "(?:"+before+symbol+after+")?";
+ }
+ return before+symbol+after;
+ });
+ }
+
+//TODO: substitute localized sign/percent/permille/etc.?
+
+ // normalize whitespace and return
+ return {regexp: re.replace(/[\xa0 ]/g, "[\\s\\xa0]"), group: group, decimal: decimal, factor: factor}; // Object
+}
+
+/*=====
+dojo.number.__ParseOptions = function(){
+ // pattern: String
+ // override pattern with this string. Default is provided based on
+ // locale.
+ // type: String?
+ // choose a format type based on the locale from the following:
+ // decimal, scientific, percent, currency. decimal by default.
+ // locale: String
+ // override the locale used to determine formatting rules
+ // strict: Boolean?
+ // strict parsing, false by default
+ // currency: Object
+ // object with currency information
+ this.pattern = pattern;
+ this.type = type;
+ this.locale = locale;
+ this.strict = strict;
+ this.currency = currency;
+}
+=====*/
+dojo.number.parse = function(/*String*/expression, /*dojo.number.__ParseOptions?*/options){
+ // summary:
+ // Convert a properly formatted string to a primitive Number, using
+ // locale-specific settings.
+ // description:
+ // Create a Number from a string using a known localized pattern.
+ // Formatting patterns are chosen appropriate to the locale
+ // and follow the syntax described by
+ // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // expression:
+ // A string representation of a Number
+ var info = dojo.number._parseInfo(options);
+ var results = (new RegExp("^"+info.regexp+"$")).exec(expression);
+ if(!results){
+ return NaN; //NaN
+ }
+ var absoluteMatch = results[1]; // match for the positive expression
+ if(!results[1]){
+ if(!results[2]){
+ return NaN; //NaN
+ }
+ // matched the negative pattern
+ absoluteMatch =results[2];
+ info.factor *= -1;
+ }
+
+ // Transform it to something Javascript can parse as a number. Normalize
+ // decimal point and strip out group separators or alternate forms of whitespace
+ absoluteMatch = absoluteMatch.
+ replace(new RegExp("["+info.group + "\\s\\xa0"+"]", "g"), "").
+ replace(info.decimal, ".");
+ // Adjust for negative sign, percent, etc. as necessary
+ return Number(absoluteMatch) * info.factor; //Number
+};
+
+/*=====
+dojo.number.__RealNumberRegexpFlags = function(){
+ // places: Number?
+ // The integer number of decimal places or a range given as "n,m". If
+ // not given, the decimal part is optional and the number of places is
+ // unlimited.
+ // decimal: String?
+ // A string for the character used as the decimal point. Default
+ // is ".".
+ // fractional: Boolean|Array?
+ // Whether decimal places are allowed. Can be true, false, or [true,
+ // false]. Default is [true, false]
+ // exponent: Boolean|Array?
+ // Express in exponential notation. Can be true, false, or [true,
+ // false]. Default is [true, false], (i.e. will match if the
+ // exponential part is present are not).
+ // eSigned: Boolean|Array?
+ // The leading plus-or-minus sign on the exponent. Can be true,
+ // false, or [true, false]. Default is [true, false], (i.e. will
+ // match if it is signed or unsigned). flags in regexp.integer can be
+ // applied.
+ this.places = places;
+ this.decimal = decimal;
+ this.fractional = fractional;
+ this.exponent = exponent;
+ this.eSigned = eSigned;
+}
+=====*/
+
+dojo.number._realNumberRegexp = function(/*dojo.number.__RealNumberRegexpFlags?*/flags){
+ // summary:
+ // Builds a regular expression to match a real number in exponential
+ // notation
+
+ // assign default values to missing paramters
+ flags = flags || {};
+ //TODO: use mixin instead?
+ if(!("places" in flags)){ flags.places = Infinity; }
+ if(typeof flags.decimal != "string"){ flags.decimal = "."; }
+ if(!("fractional" in flags) || /^0/.test(flags.places)){ flags.fractional = [true, false]; }
+ if(!("exponent" in flags)){ flags.exponent = [true, false]; }
+ if(!("eSigned" in flags)){ flags.eSigned = [true, false]; }
+
+ // integer RE
+ var integerRE = dojo.number._integerRegexp(flags);
+
+ // decimal RE
+ var decimalRE = dojo.regexp.buildGroupRE(flags.fractional,
+ function(q){
+ var re = "";
+ if(q && (flags.places!==0)){
+ re = "\\" + flags.decimal;
+ if(flags.places == Infinity){
+ re = "(?:" + re + "\\d+)?";
+ }else{
+ re += "\\d{" + flags.places + "}";
+ }
+ }
+ return re;
+ },
+ true
+ );
+
+ // exponent RE
+ var exponentRE = dojo.regexp.buildGroupRE(flags.exponent,
+ function(q){
+ if(q){ return "([eE]" + dojo.number._integerRegexp({ signed: flags.eSigned}) + ")"; }
+ return "";
+ }
+ );
+
+ // real number RE
+ var realRE = integerRE + decimalRE;
+ // allow for decimals without integers, e.g. .25
+ if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";}
+ return realRE + exponentRE; // String
+};
+
+/*=====
+dojo.number.__IntegerRegexpFlags = function(){
+ // signed: Boolean?
+ // The leading plus-or-minus sign. Can be true, false, or `[true,false]`.
+ // Default is `[true, false]`, (i.e. will match if it is signed
+ // or unsigned).
+ // separator: String?
+ // The character used as the thousands separator. Default is no
+ // separator. For more than one symbol use an array, e.g. `[",", ""]`,
+ // makes ',' optional.
+ // groupSize: Number?
+ // group size between separators
+ // groupSize2: Number?
+ // second grouping, where separators 2..n have a different interval than the first separator (for India)
+ this.signed = signed;
+ this.separator = separator;
+ this.groupSize = groupSize;
+ this.groupSize2 = groupSize2;
+}
+=====*/
+
+dojo.number._integerRegexp = function(/*dojo.number.__IntegerRegexpFlags?*/flags){
+ // summary:
+ // Builds a regular expression that matches an integer
+
+ // assign default values to missing paramters
+ flags = flags || {};
+ if(!("signed" in flags)){ flags.signed = [true, false]; }
+ if(!("separator" in flags)){
+ flags.separator = "";
+ }else if(!("groupSize" in flags)){
+ flags.groupSize = 3;
+ }
+ // build sign RE
+ var signRE = dojo.regexp.buildGroupRE(flags.signed,
+ function(q) { return q ? "[-+]" : ""; },
+ true
+ );
+
+ // number RE
+ var numberRE = dojo.regexp.buildGroupRE(flags.separator,
+ function(sep){
+ if(!sep){
+ return "(?:0|[1-9]\\d*)";
+ }
+
+ sep = dojo.regexp.escapeString(sep);
+ if(sep == " "){ sep = "\\s"; }
+ else if(sep == "\xa0"){ sep = "\\s\\xa0"; }
+
+ var grp = flags.groupSize, grp2 = flags.groupSize2;
+ if(grp2){
+ var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})";
+ return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE;
+ }
+ return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)";
+ },
+ true
+ );
+
+ // integer RE
+ return signRE + numberRE; // String
+}
+
+}
diff --git a/includes/js/dojo/parser.js b/includes/js/dojo/parser.js
new file mode 100644
index 0000000..5394338
--- /dev/null
+++ b/includes/js/dojo/parser.js
@@ -0,0 +1,277 @@
+if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.parser"] = true;
+dojo.provide("dojo.parser");
+dojo.require("dojo.date.stamp");
+
+dojo.parser = new function(){
+ // summary: The Dom/Widget parsing package
+
+ var d = dojo;
+ var dtName = d._scopeName + "Type";
+ var qry = "[" + dtName + "]";
+
+ function val2type(/*Object*/ value){
+ // summary:
+ // Returns name of type of given value.
+
+ if(d.isString(value)){ return "string"; }
+ if(typeof value == "number"){ return "number"; }
+ if(typeof value == "boolean"){ return "boolean"; }
+ if(d.isFunction(value)){ return "function"; }
+ if(d.isArray(value)){ return "array"; } // typeof [] == "object"
+ if(value instanceof Date) { return "date"; } // assume timestamp
+ if(value instanceof d._Url){ return "url"; }
+ return "object";
+ }
+
+ function str2obj(/*String*/ value, /*String*/ type){
+ // summary:
+ // Convert given string value to given type
+ switch(type){
+ case "string":
+ return value;
+ case "number":
+ return value.length ? Number(value) : NaN;
+ case "boolean":
+ // for checked/disabled value might be "" or "checked". interpret as true.
+ return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
+ case "function":
+ if(d.isFunction(value)){
+ // IE gives us a function, even when we say something like onClick="foo"
+ // (in which case it gives us an invalid function "function(){ foo }").
+ // Therefore, convert to string
+ value=value.toString();
+ value=d.trim(value.substring(value.indexOf('{')+1, value.length-1));
+ }
+ try{
+ if(value.search(/[^\w\.]+/i) != -1){
+ // TODO: "this" here won't work
+ value = d.parser._nameAnonFunc(new Function(value), this);
+ }
+ return d.getObject(value, false);
+ }catch(e){ return new Function(); }
+ case "array":
+ return value.split(/\s*,\s*/);
+ case "date":
+ switch(value){
+ case "": return new Date(""); // the NaN of dates
+ case "now": return new Date(); // current date
+ default: return d.date.stamp.fromISOString(value);
+ }
+ case "url":
+ return d.baseUrl + value;
+ default:
+ return d.fromJson(value);
+ }
+ }
+
+ var instanceClasses = {
+ // map from fully qualified name (like "dijit.Button") to structure like
+ // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
+ };
+
+ function getClassInfo(/*String*/ className){
+ // className:
+ // fully qualified name (like "dijit.Button")
+ // returns:
+ // structure like
+ // {
+ // cls: dijit.Button,
+ // params: { label: "string", disabled: "boolean"}
+ // }
+
+ if(!instanceClasses[className]){
+ // get pointer to widget class
+ var cls = d.getObject(className);
+ if(!d.isFunction(cls)){
+ throw new Error("Could not load class '" + className +
+ "'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?");
+ }
+ var proto = cls.prototype;
+
+ // get table of parameter names & types
+ var params={};
+ for(var name in proto){
+ if(name.charAt(0)=="_"){ continue; } // skip internal properties
+ var defVal = proto[name];
+ params[name]=val2type(defVal);
+ }
+
+ instanceClasses[className] = { cls: cls, params: params };
+ }
+ return instanceClasses[className];
+ }
+
+ this._functionFromScript = function(script){
+ var preamble = "";
+ var suffix = "";
+ var argsStr = script.getAttribute("args");
+ if(argsStr){
+ d.forEach(argsStr.split(/\s*,\s*/), function(part, idx){
+ preamble += "var "+part+" = arguments["+idx+"]; ";
+ });
+ }
+ var withStr = script.getAttribute("with");
+ if(withStr && withStr.length){
+ d.forEach(withStr.split(/\s*,\s*/), function(part){
+ preamble += "with("+part+"){";
+ suffix += "}";
+ });
+ }
+ return new Function(preamble+script.innerHTML+suffix);
+ }
+
+ this.instantiate = function(/* Array */nodes){
+ // summary:
+ // Takes array of nodes, and turns them into class instances and
+ // potentially calls a layout method to allow them to connect with
+ // any children
+ var thelist = [];
+ d.forEach(nodes, function(node){
+ if(!node){ return; }
+ var type = node.getAttribute(dtName);
+ if((!type)||(!type.length)){ return; }
+ var clsInfo = getClassInfo(type);
+ var clazz = clsInfo.cls;
+ var ps = clazz._noScript||clazz.prototype._noScript;
+
+ // read parameters (ie, attributes).
+ // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
+ var params = {};
+ var attributes = node.attributes;
+ for(var name in clsInfo.params){
+ var item = attributes.getNamedItem(name);
+ if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; }
+ var value = item.value;
+ // Deal with IE quirks for 'class' and 'style'
+ switch(name){
+ case "class":
+ value = node.className;
+ break;
+ case "style":
+ value = node.style && node.style.cssText; // FIXME: Opera?
+ }
+ var _type = clsInfo.params[name];
+ params[name] = str2obj(value, _type);
+ }
+
+ // Process <script type="dojo/*"> script tags
+ // <script type="dojo/method" event="foo"> tags are added to params, and passed to
+ // the widget on instantiation.
+ // <script type="dojo/method"> tags (with no event) are executed after instantiation
+ // <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation
+ // note: dojo/* script tags cannot exist in self closing widgets, like <input />
+ if(!ps){
+ var connects = [], // functions to connect after instantiation
+ calls = []; // functions to call after instantiation
+
+ d.query("> script[type^='dojo/']", node).orphan().forEach(function(script){
+ var event = script.getAttribute("event"),
+ type = script.getAttribute("type"),
+ nf = d.parser._functionFromScript(script);
+ if(event){
+ if(type == "dojo/connect"){
+ connects.push({event: event, func: nf});
+ }else{
+ params[event] = nf;
+ }
+ }else{
+ calls.push(nf);
+ }
+ });
+ }
+
+ var markupFactory = clazz["markupFactory"];
+ if(!markupFactory && clazz["prototype"]){
+ markupFactory = clazz.prototype["markupFactory"];
+ }
+ // create the instance
+ var instance = markupFactory ? markupFactory(params, node, clazz) : new clazz(params, node);
+ thelist.push(instance);
+
+ // map it to the JS namespace if that makes sense
+ var jsname = node.getAttribute("jsId");
+ if(jsname){
+ d.setObject(jsname, instance);
+ }
+
+ // process connections and startup functions
+ if(!ps){
+ d.forEach(connects, function(connect){
+ d.connect(instance, connect.event, null, connect.func);
+ });
+ d.forEach(calls, function(func){
+ func.call(instance);
+ });
+ }
+ });
+
+ // Call startup on each top level instance if it makes sense (as for
+ // widgets). Parent widgets will recursively call startup on their
+ // (non-top level) children
+ d.forEach(thelist, function(instance){
+ if( instance &&
+ instance.startup &&
+ !instance._started &&
+ (!instance.getParent || !instance.getParent())
+ ){
+ instance.startup();
+ }
+ });
+ return thelist;
+ };
+
+ this.parse = function(/*DomNode?*/ rootNode){
+ // summary:
+ // Search specified node (or root node) recursively for class instances,
+ // and instantiate them Searches for
+ // dojoType="qualified.class.name"
+ var list = d.query(qry, rootNode);
+ // go build the object instances
+ var instances = this.instantiate(list);
+ return instances;
+ };
+}();
+
+//Register the parser callback. It should be the first callback
+//after the a11y test.
+
+(function(){
+ var parseRunner = function(){
+ if(dojo.config["parseOnLoad"] == true){
+ dojo.parser.parse();
+ }
+ };
+
+ // FIXME: need to clobber cross-dependency!!
+ if(dojo.exists("dijit.wai.onload") && (dijit.wai.onload === dojo._loaders[0])){
+ dojo._loaders.splice(1, 0, parseRunner);
+ }else{
+ dojo._loaders.unshift(parseRunner);
+ }
+})();
+
+//TODO: ported from 0.4.x Dojo. Can we reduce this?
+dojo.parser._anonCtr = 0;
+dojo.parser._anon = {}; // why is this property required?
+dojo.parser._nameAnonFunc = function(/*Function*/anonFuncPtr, /*Object*/thisObj){
+ // summary:
+ // Creates a reference to anonFuncPtr in thisObj with a completely
+ // unique name. The new name is returned as a String.
+ var jpn = "$joinpoint";
+ var nso = (thisObj|| dojo.parser._anon);
+ if(dojo.isIE){
+ var cn = anonFuncPtr["__dojoNameCache"];
+ if(cn && nso[cn] === anonFuncPtr){
+ return anonFuncPtr["__dojoNameCache"];
+ }
+ }
+ var ret = "__"+dojo.parser._anonCtr++;
+ while(typeof nso[ret] != "undefined"){
+ ret = "__"+dojo.parser._anonCtr++;
+ }
+ nso[ret] = anonFuncPtr;
+ return ret; // String
+}
+
+}
diff --git a/includes/js/dojo/regexp.js b/includes/js/dojo/regexp.js
new file mode 100644
index 0000000..302a5b4
--- /dev/null
+++ b/includes/js/dojo/regexp.js
@@ -0,0 +1,69 @@
+if(!dojo._hasResource["dojo.regexp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.regexp"] = true;
+dojo.provide("dojo.regexp");
+
+/*=====
+dojo.regexp = {
+ // summary: Regular expressions and Builder resources
+};
+=====*/
+
+dojo.regexp.escapeString = function(/*String*/str, /*String?*/except){
+ // summary:
+ // Adds escape sequences for special characters in regular expressions
+ // except:
+ // a String with special characters to be left unescaped
+
+// return str.replace(/([\f\b\n\t\r[\^$|?*+(){}])/gm, "\\$1"); // string
+ return str.replace(/([\.$?*!=:|{}\(\)\[\]\\\/^])/g, function(ch){
+ if(except && except.indexOf(ch) != -1){
+ return ch;
+ }
+ return "\\" + ch;
+ }); // String
+}
+
+dojo.regexp.buildGroupRE = function(/*Object|Array*/arr, /*Function*/re, /*Boolean?*/nonCapture){
+ // summary:
+ // Builds a regular expression that groups subexpressions
+ // description:
+ // A utility function used by some of the RE generators. The
+ // subexpressions are constructed by the function, re, in the second
+ // parameter. re builds one subexpression for each elem in the array
+ // a, in the first parameter. Returns a string for a regular
+ // expression that groups all the subexpressions.
+ // arr:
+ // A single value or an array of values.
+ // re:
+ // A function. Takes one parameter and converts it to a regular
+ // expression.
+ // nonCapture:
+ // If true, uses non-capturing match, otherwise matches are retained
+ // by regular expression. Defaults to false
+
+ // case 1: a is a single value.
+ if(!(arr instanceof Array)){
+ return re(arr); // String
+ }
+
+ // case 2: a is an array
+ var b = [];
+ for(var i = 0; i < arr.length; i++){
+ // convert each elem to a RE
+ b.push(re(arr[i]));
+ }
+
+ // join the REs as alternatives in a RE group.
+ return dojo.regexp.group(b.join("|"), nonCapture); // String
+}
+
+dojo.regexp.group = function(/*String*/expression, /*Boolean?*/nonCapture){
+ // summary:
+ // adds group match to expression
+ // nonCapture:
+ // If true, uses non-capturing match, otherwise matches are retained
+ // by regular expression.
+ return "(" + (nonCapture ? "?:":"") + expression + ")"; // String
+}
+
+}
diff --git a/includes/js/dojo/resources/LICENSE b/includes/js/dojo/resources/LICENSE
new file mode 100644
index 0000000..eb28b7e
--- /dev/null
+++ b/includes/js/dojo/resources/LICENSE
@@ -0,0 +1,30 @@
+License Disclaimer:
+
+All contents of this directory are Copyright (c) the Dojo Foundation, with the
+following exceptions:
+-------------------------------------------------------------------------------
+
+dojo.css:
+ * parts Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ Distributed under the terms of the BSD License
+
+The Program includes all or portions of the following software which was obtained under the terms and conditions of the BSD License.
+
+http://developer.yahoo.com/yui/license.html
+
+Copyright (c) 2007, Yahoo! Inc.
+ All rights reserved.
+ Redistribution and use of this software 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 Yahoo! Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without
+specific prior written permission of Yahoo! Inc.
+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.
diff --git a/includes/js/dojo/resources/_modules.js b/includes/js/dojo/resources/_modules.js
new file mode 100644
index 0000000..bfc6c76
--- /dev/null
+++ b/includes/js/dojo/resources/_modules.js
@@ -0,0 +1,36 @@
+/*=====
+// Supplemental summaries for those hard-to-doc places your conventional doc parser can't reach.
+// Where possible, these summaries should appear inline in the code.
+//
+// this is "package level documentation"
+
+dojo.cldr = {
+ // summary: transformation of relevant pieces of the Unicode.org Common Locale Data Repository
+ // (see http://unicode.org/cldr) to JSON from the original XML with associated utility classes
+};
+
+dojo.data = {
+ // summary: A uniform data access layer
+};
+
+dojo.dnd = {
+ // summary: Drag and Drop resources
+};
+
+dojo.io = {
+ // summary: Additional I/O transports (Ajax)
+};
+
+dojo.rpc = {
+ // summary: Dojo remote-procedure-call resources
+};
+
+// "variables"
+
+dojo.baseUrl = {
+ // summary: The root relative path to dojo.js (as a string)
+ // example:
+ // if(typeof dojo != "undefined"){ console.log(dojo.baseUrl); }
+};
+
+=====*/
diff --git a/includes/js/dojo/resources/blank.gif b/includes/js/dojo/resources/blank.gif
new file mode 100644
index 0000000..e565824
--- /dev/null
+++ b/includes/js/dojo/resources/blank.gif
Binary files differ
diff --git a/includes/js/dojo/resources/blank.html b/includes/js/dojo/resources/blank.html
new file mode 100644
index 0000000..40fe770
--- /dev/null
+++ b/includes/js/dojo/resources/blank.html
@@ -0,0 +1 @@
+<html><head><script>isLoaded = true;</script></head><body></body></html>
diff --git a/includes/js/dojo/resources/dnd.css b/includes/js/dojo/resources/dnd.css
new file mode 100644
index 0000000..8bf39e7
--- /dev/null
+++ b/includes/js/dojo/resources/dnd.css
@@ -0,0 +1,9 @@
+
+.dojoDndAvatar {font-size: 75%; color: black;}
+.dojoDndAvatarHeader td {padding-left: 20px; padding-right: 4px;}
+.dojoDndAvatarHeader {background: #ccc;}
+.dojoDndAvatarItem {background: #eee;}
+.dojoDndMove .dojoDndAvatarHeader {background-image: url(images/dndNoMove.png); background-repeat: no-repeat;}
+.dojoDndCopy .dojoDndAvatarHeader {background-image: url(images/dndNoCopy.png); background-repeat: no-repeat;}
+.dojoDndMove .dojoDndAvatarCanDrop .dojoDndAvatarHeader {background-image: url(images/dndMove.png); background-repeat: no-repeat;}
+.dojoDndCopy .dojoDndAvatarCanDrop .dojoDndAvatarHeader {background-image: url(images/dndCopy.png); background-repeat: no-repeat;}
diff --git a/includes/js/dojo/resources/dnd.css.commented.css b/includes/js/dojo/resources/dnd.css.commented.css
new file mode 100644
index 0000000..b9fac47
--- /dev/null
+++ b/includes/js/dojo/resources/dnd.css.commented.css
@@ -0,0 +1,9 @@
+/* DnD avatar-specific settings */
+.dojoDndAvatar {font-size: 75%; color: black;}
+.dojoDndAvatarHeader td {padding-left: 20px; padding-right: 4px;}
+.dojoDndAvatarHeader {background: #ccc;}
+.dojoDndAvatarItem {background: #eee;}
+.dojoDndMove .dojoDndAvatarHeader {background-image: url(images/dndNoMove.png); background-repeat: no-repeat;}
+.dojoDndCopy .dojoDndAvatarHeader {background-image: url(images/dndNoCopy.png); background-repeat: no-repeat;}
+.dojoDndMove .dojoDndAvatarCanDrop .dojoDndAvatarHeader {background-image: url(images/dndMove.png); background-repeat: no-repeat;}
+.dojoDndCopy .dojoDndAvatarCanDrop .dojoDndAvatarHeader {background-image: url(images/dndCopy.png); background-repeat: no-repeat;}
diff --git a/includes/js/dojo/resources/dojo.css b/includes/js/dojo/resources/dojo.css
new file mode 100644
index 0000000..33179d0
--- /dev/null
+++ b/includes/js/dojo/resources/dojo.css
@@ -0,0 +1,100 @@
+
+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;
+}
diff --git a/includes/js/dojo/resources/dojo.css.commented.css b/includes/js/dojo/resources/dojo.css.commented.css
new file mode 100644
index 0000000..b9de9c0
--- /dev/null
+++ b/includes/js/dojo/resources/dojo.css.commented.css
@@ -0,0 +1,198 @@
+/*
+ dojo.css
+ Baseline CSS file for general usage.
+
+ This file is intended to be a "quick and dirty" stylesheet you can use to give
+ a straight-up web page some basic styling without having to do the dirty work
+ yourself. It includes a modified version of YUI's reset.css (we pulled some
+ of the list reset definitions, among other things), and then provides some very
+ basic style rules to be applied to general HTML elements.
+
+ This stylesheet is NOT intended to serve as the foundation for more complex things--
+ including the use of a TABLE for layout purposes. The table definitions in this
+ file make the assumption that you will be using tables for thier declared purpose:
+ displaying tabular data.
+
+ If you are looking for a baseline stylesheet using tables for grid layout, you will
+ need to supply your own layout rules to override the ones in this stylesheet.
+
+ Applications using Dojo will function correctly without including this
+ file, but it should provide sane defaults for many common things that page
+ authors often need to set up manually.
+
+ The Dojo Core uses this stylesheet to quickly style HTML-based tests and demos. Feel
+ free to use it as you will.
+*/
+
+/*****************************************************************************************/
+
+/*
+ The below are borrowed from YUI's reset style sheets for pages and fonts.
+ We've verified w/ the YUI development team that these are entirely
+ copyright Yahoo, written entirely by Nate Koechley and Matt Sweeney without
+ external contributions.
+
+ Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ Code licensed under the BSD License:
+ http://developer.yahoo.net/yui/license.txt
+ version: 2.2.1
+*/
+
+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;
+}
+/* End YUI imported code. */
+
+/*****************************************************************************************/
+
+/*
+ Begin Dojo additions.
+
+ Style definitions, based loosely on the Dijit Tundra theme.
+ Relative unit calculations based on "Compose to a Vertical Rhythm",
+ by Richard Rutter (http://24ways.org/2006/compose-to-a-vertical-rhythm)
+
+ If changing the font size, make sure you do it in both
+ percent and px (% for IE, px for everything else).
+ % value based on default size of 16px (in most browsers).
+ So if you want the default size to be 14px, set the
+ % to 87% (14 / 16 = 0.875).
+
+ Typical values:
+ 10px: 62.5%
+ 11px: 69% (68.75)
+ 12px: 75%
+ 13px: 81.25%
+ 14px: 87.5%
+ 16px: 100%
+
+ Default: 13px, specified by the YUI imports.
+*/
+body {
+ font: 13px Myriad,Arial,Helvetica,clean,sans-serif;
+ *font-size: small;
+ *font: x-small;
+}
+
+/* Headings */
+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;
+}
+
+/* paragraphs, quotes and lists */
+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 and code */
+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;
+}
+
+/*
+ Tables
+
+ Note that these table definitions make the assumption that you are using tables
+ to display tabular data, and NOT using tables as layout mechanisms. If you are
+ using tables for layout, you will probably want to override these rules with
+ more specific ones.
+
+ These definitions make tabular data look presentable, particularly when presented
+ inline with paragraphs.
+*/
+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;
+}
diff --git a/includes/js/dojo/resources/iframe_history.html b/includes/js/dojo/resources/iframe_history.html
new file mode 100644
index 0000000..aee368f
--- /dev/null
+++ b/includes/js/dojo/resources/iframe_history.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
+ <script type="text/javascript">
+ // <!--
+ var noInit = false;
+
+ function defineParams(sparams){
+ if(sparams){
+ var ss = (sparams.indexOf("&amp;") >= 0) ? "&amp;" : "&";
+ sparams = sparams.split(ss);
+ for(var x=0; x<sparams.length; x++){
+ var tp = sparams[x].split("=");
+ if(typeof window[tp[0]] != "undefined"){
+ window[tp[0]] = ((tp[1]=="true")||(tp[1]=="false")) ? eval(tp[1]) : tp[1];
+ }
+ }
+ }
+ }
+
+ function init(){
+ // parse the query string if there is one to try to get params that
+ // we can act on. Also allow params to be in a fragment identifier.
+ var query = null;
+ var frag = null;
+ var url = document.location.href;
+ var hashIndex = url.indexOf("#");
+
+ //Extract fragment identifier
+ if(hashIndex != -1){
+ frag = url.substring(hashIndex + 1, url.length);
+ url = url.substring(0, hashIndex);
+ }
+
+ //Extract querystring
+ var parts = url.split("?");
+ if(parts.length == 2){
+ query = parts[1];
+ }
+
+ defineParams(query);
+ defineParams(frag);
+
+ if(noInit){ return; }
+ var hasParentDojo = false;
+ try{
+ hasParentDojo = window.parent != window && window.parent["dojo"];
+ }catch(e){
+ alert("Initializing iframe_history.html failed. If you are using a cross-domain Dojo build,"
+ + " please save iframe_history.html to your domain and set djConfig.dojoIframeHistoryUrl"
+ + " to the path on your domain to iframe_history.html");
+ throw e;
+ }
+
+ if(hasParentDojo){
+ //Set the page title so IE history shows up with a somewhat correct name.
+ document.title = window.parent.document.title;
+
+ //Notify parent that we are loaded.
+ var pdj = window.parent.dojo;
+ if(pdj["back"]){
+ pdj.back._iframeLoaded(null, window.location);
+ }
+ }
+
+ }
+ // -->
+ </script>
+</head>
+<body onload="try{ init(); }catch(e){ alert(e); }">
+ <h4>The Dojo Toolkit -- iframe_history.html</h4>
+
+ <p>This file is used in Dojo's back/fwd button management.</p>
+</body>
+</html>
diff --git a/includes/js/dojo/resources/images/dndCopy.png b/includes/js/dojo/resources/images/dndCopy.png
new file mode 100644
index 0000000..660ca4f
--- /dev/null
+++ b/includes/js/dojo/resources/images/dndCopy.png
Binary files differ
diff --git a/includes/js/dojo/resources/images/dndMove.png b/includes/js/dojo/resources/images/dndMove.png
new file mode 100644
index 0000000..74af29c
--- /dev/null
+++ b/includes/js/dojo/resources/images/dndMove.png
Binary files differ
diff --git a/includes/js/dojo/resources/images/dndNoCopy.png b/includes/js/dojo/resources/images/dndNoCopy.png
new file mode 100644
index 0000000..87f3aa0
--- /dev/null
+++ b/includes/js/dojo/resources/images/dndNoCopy.png
Binary files differ
diff --git a/includes/js/dojo/resources/images/dndNoMove.png b/includes/js/dojo/resources/images/dndNoMove.png
new file mode 100644
index 0000000..d75ed86
--- /dev/null
+++ b/includes/js/dojo/resources/images/dndNoMove.png
Binary files differ
diff --git a/includes/js/dojo/rpc/JsonService.js b/includes/js/dojo/rpc/JsonService.js
new file mode 100644
index 0000000..d9775f6
--- /dev/null
+++ b/includes/js/dojo/rpc/JsonService.js
@@ -0,0 +1,83 @@
+if(!dojo._hasResource["dojo.rpc.JsonService"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.rpc.JsonService"] = true;
+dojo.provide("dojo.rpc.JsonService");
+dojo.require("dojo.rpc.RpcService");
+
+dojo.declare("dojo.rpc.JsonService", dojo.rpc.RpcService, {
+ bustCache: false,
+ contentType: "application/json-rpc",
+ lastSubmissionId: 0,
+
+ callRemote: function(method, params){
+ // summary:
+ // call an arbitrary remote method without requiring it to be
+ // predefined with SMD
+ // method: string
+ // the name of the remote method you want to call.
+ // params: array
+ // array of parameters to pass to method
+
+ var deferred = new dojo.Deferred();
+ this.bind(method, params, deferred);
+ return deferred;
+ },
+
+ bind: function(method, parameters, deferredRequestHandler, url){
+ //summary:
+ // JSON-RPC bind method. Takes remote method, parameters,
+ // deferred, and a url, calls createRequest to make a JSON-RPC
+ // envelope and passes that off with bind.
+ // method: string
+ // The name of the method we are calling
+ // parameters: array
+ // The parameters we are passing off to the method
+ // deferredRequestHandler: deferred
+ // The Deferred object for this particular request
+
+ var def = dojo.rawXhrPost({
+ url: url||this.serviceUrl,
+ postData: this.createRequest(method, parameters),
+ contentType: this.contentType,
+ timeout: this.timeout,
+ handleAs: "json-comment-optional"
+ });
+ def.addCallbacks(this.resultCallback(deferredRequestHandler), this.errorCallback(deferredRequestHandler));
+ },
+
+ createRequest: function(method, params){
+ // summary:
+ // create a JSON-RPC envelope for the request
+ // method: string
+ // The name of the method we are creating the requst for
+ // params: array
+ // The array of parameters for this request;
+
+ var req = { "params": params, "method": method, "id": ++this.lastSubmissionId };
+ var data = dojo.toJson(req);
+ return data;
+ },
+
+ parseResults: function(/*anything*/obj){
+ //summary:
+ // parse the result envelope and pass the results back to
+ // the callback function
+ // obj: Object
+ // Object containing envelope of data we recieve from the server
+
+ if(dojo.isObject(obj)){
+ if("result" in obj){
+ return obj.result;
+ }
+ if("Result" in obj){
+ return obj.Result;
+ }
+ if("ResultSet" in obj){
+ return obj.ResultSet;
+ }
+ }
+ return obj;
+ }
+ }
+);
+
+}
diff --git a/includes/js/dojo/rpc/JsonpService.js b/includes/js/dojo/rpc/JsonpService.js
new file mode 100644
index 0000000..c07d5b9
--- /dev/null
+++ b/includes/js/dojo/rpc/JsonpService.js
@@ -0,0 +1,65 @@
+if(!dojo._hasResource["dojo.rpc.JsonpService"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.rpc.JsonpService"] = true;
+dojo.provide("dojo.rpc.JsonpService");
+dojo.require("dojo.rpc.RpcService");
+dojo.require("dojo.io.script");
+
+dojo.declare("dojo.rpc.JsonpService", dojo.rpc.RpcService, {
+ // summary:
+ // Generic JSONP service. Minimally extends RpcService to allow
+ // easy definition of nearly any JSONP style service. Example
+ // SMD files exist in dojox.data
+
+ constructor: function(args, requiredArgs){
+ if(this.required) {
+ if(requiredArgs){
+ dojo.mixin(this.required, requiredArgs);
+ }
+
+ dojo.forEach(this.required, function(req){
+ if(req=="" || req==undefined){
+ throw new Error("Required Service Argument not found: "+req);
+ }
+ });
+ }
+ },
+
+ strictArgChecks: false,
+
+ bind: function(method, parameters, deferredRequestHandler, url){
+ //summary:
+ // JSONP bind method. Takes remote method, parameters,
+ // deferred, and a url, calls createRequest to make a JSON-RPC
+ // envelope and passes that off with bind.
+ // method: string
+ // The name of the method we are calling
+ // parameters: array
+ // The parameters we are passing off to the method
+ // deferredRequestHandler: deferred
+ // The Deferred object for this particular request
+
+ var def = dojo.io.script.get({
+ url: url||this.serviceUrl,
+ callbackParamName: this.callbackParamName||"callback",
+ content: this.createRequest(parameters),
+ timeout: this.timeout,
+ handleAs: "json",
+ preventCache: true
+ });
+ def.addCallbacks(this.resultCallback(deferredRequestHandler), this.errorCallback(deferredRequestHandler));
+ },
+
+ createRequest: function(parameters){
+ // summary:
+ // create a JSONP req
+ // params: array
+ // The array of parameters for this request;
+
+ var params = (dojo.isArrayLike(parameters) && parameters.length==1) ?
+ parameters[0] : {};
+ dojo.mixin(params,this.required);
+ return params;
+ }
+});
+
+}
diff --git a/includes/js/dojo/rpc/RpcService.js b/includes/js/dojo/rpc/RpcService.js
new file mode 100644
index 0000000..22e40ca
--- /dev/null
+++ b/includes/js/dojo/rpc/RpcService.js
@@ -0,0 +1,172 @@
+if(!dojo._hasResource["dojo.rpc.RpcService"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.rpc.RpcService"] = true;
+dojo.provide("dojo.rpc.RpcService");
+
+dojo.declare("dojo.rpc.RpcService", null, {
+ constructor: function(args){
+ //summary:
+ //Take a string as a url to retrieve an smd or an object that is an smd or partial smd to use
+ //as a definition for the service
+ //
+ // args: object
+ // Takes a number of properties as kwArgs for defining the service. It also
+ // accepts a string. When passed a string, it is treated as a url from
+ // which it should synchronously retrieve an smd file. Otherwise it is a kwArgs
+ // object. It accepts serviceUrl, to manually define a url for the rpc service
+ // allowing the rpc system to be used without an smd definition. strictArgChecks
+ // forces the system to verify that the # of arguments provided in a call
+ // matches those defined in the smd. smdString allows a developer to pass
+ // a jsonString directly, which will be converted into an object or alternatively
+ // smdObject is accepts an smdObject directly.
+ //
+ if(args){
+ //if the arg is a string, we assume it is a url to retrieve an smd definition from
+ if( (dojo.isString(args)) || (args instanceof dojo._Url)){
+ if (args instanceof dojo._Url){
+ var url = args + "";
+ }else{
+ url = args;
+ }
+ var def = dojo.xhrGet({
+ url: url,
+ handleAs: "json-comment-optional",
+ sync: true
+ });
+
+ def.addCallback(this, "processSmd");
+ def.addErrback(function() {
+ throw new Error("Unable to load SMD from " + args);
+ });
+
+ }else if(args.smdStr){
+ this.processSmd(dojo.eval("("+args.smdStr+")"));
+ }else{
+ // otherwise we assume it's an arguments object with the following
+ // (optional) properties:
+ // - serviceUrl
+ // - strictArgChecks
+ // - smdStr
+ // - smdObj
+
+ if(args.serviceUrl){
+ this.serviceUrl = args.serviceUrl;
+ }
+
+ this.timeout = args.timeout || 3000;
+
+ if("strictArgChecks" in args){
+ this.strictArgChecks = args.strictArgChecks;
+ }
+
+ this.processSmd(args);
+ }
+ }
+ },
+
+ strictArgChecks: true,
+ serviceUrl: "",
+
+ parseResults: function(obj){
+ // summary
+ // parse the results coming back from an rpc request. this
+ // base implementation, just returns the full object
+ // subclasses should parse and only return the actual results
+ // obj: Object
+ // Object that is the return results from an rpc request
+ return obj;
+ },
+
+ errorCallback: function(/* dojo.Deferred */ deferredRequestHandler){
+ // summary:
+ // create callback that calls the Deferres errback method
+ // deferredRequestHandler: Deferred
+ // The deferred object handling a request.
+ return function(data){
+ deferredRequestHandler.errback(new Error(data.message));
+ };
+ },
+
+ resultCallback: function(/* dojo.Deferred */ deferredRequestHandler){
+ // summary:
+ // create callback that calls the Deferred's callback method
+ // deferredRequestHandler: Deferred
+ // The deferred object handling a request.
+
+ var tf = dojo.hitch(this,
+ function(obj){
+ if(obj.error!=null){
+ var err;
+ if(typeof obj.error == 'object'){
+ err = new Error(obj.error.message);
+ err.code = obj.error.code;
+ err.error = obj.error.error;
+ }else{
+ err = new Error(obj.error);
+ }
+ err.id = obj.id;
+ err.errorObject = obj;
+ deferredRequestHandler.errback(err);
+ }else{
+ deferredRequestHandler.callback(this.parseResults(obj));
+ }
+ }
+ );
+ return tf;
+ },
+
+ generateMethod: function(/*string*/ method, /*array*/ parameters, /*string*/ url){
+ // summary:
+ // generate the local bind methods for the remote object
+ // method: string
+ // The name of the method we are generating
+ // parameters: array
+ // the array of parameters for this call.
+ // url: string
+ // the service url for this call
+
+ return dojo.hitch(this, function(){
+ var deferredRequestHandler = new dojo.Deferred();
+
+ // if params weren't specified, then we can assume it's varargs
+ if( (this.strictArgChecks) &&
+ (parameters != null) &&
+ (arguments.length != parameters.length)
+ ){
+ // put error stuff here, no enough params
+ throw new Error("Invalid number of parameters for remote method.");
+ }else{
+ this.bind(method, dojo._toArray(arguments), deferredRequestHandler, url);
+ }
+
+ return deferredRequestHandler;
+ });
+ },
+
+ processSmd: function(object){
+ // summary:
+ // callback method for reciept of a smd object. Parse the smd
+ // and generate functions based on the description
+ // object:
+ // smd object defining this service.
+
+ if(object.methods){
+ dojo.forEach(object.methods, function(m){
+ if(m && m.name){
+ this[m.name] = this.generateMethod( m.name,
+ m.parameters,
+ m.url||m.serviceUrl||m.serviceURL);
+ if(!dojo.isFunction(this[m.name])){
+ throw new Error("RpcService: Failed to create" + m.name + "()");
+ /*console.debug("RpcService: Failed to create", m.name, "()");*/
+ }
+ }
+ }, this);
+ }
+
+ this.serviceUrl = object.serviceUrl||object.serviceURL;
+ this.required = object.required;
+ this.smd = object;
+ }
+});
+
+}
diff --git a/includes/js/dojo/string.js b/includes/js/dojo/string.js
new file mode 100644
index 0000000..a407744
--- /dev/null
+++ b/includes/js/dojo/string.js
@@ -0,0 +1,84 @@
+if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.string"] = true;
+dojo.provide("dojo.string");
+
+/*=====
+dojo.string = {
+ // summary: String utilities for Dojo
+};
+=====*/
+
+dojo.string.pad = function(/*String*/text, /*int*/size, /*String?*/ch, /*boolean?*/end){
+ // summary:
+ // Pad a string to guarantee that it is at least `size` length by
+ // filling with the character `ch` at either the start or end of the
+ // string. Pads at the start, by default.
+ // text: the string to pad
+ // size: length to provide padding
+ // ch: character to pad, defaults to '0'
+ // end: adds padding at the end if true, otherwise pads at start
+
+ var out = String(text);
+ if(!ch){
+ ch = '0';
+ }
+ while(out.length < size){
+ if(end){
+ out += ch;
+ }else{
+ out = ch + out;
+ }
+ }
+ return out; // String
+};
+
+dojo.string.substitute = function( /*String*/template,
+ /*Object|Array*/map,
+ /*Function?*/transform,
+ /*Object?*/thisObject){
+ // summary:
+ // Performs parameterized substitutions on a string. Throws an
+ // exception if any parameter is unmatched.
+ // description:
+ // For example,
+ // | dojo.string.substitute("File '${0}' is not found in directory '${1}'.",["foo.html","/temp"]);
+ // | dojo.string.substitute("File '${name}' is not found in directory '${info.dir}'.",
+ // | {name: "foo.html", info: {dir: "/temp"}});
+ // both return
+ // | "File 'foo.html' is not found in directory '/temp'."
+ // template:
+ // a string with expressions in the form `${key}` to be replaced or
+ // `${key:format}` which specifies a format function.
+ // map: hash to search for substitutions
+ // transform:
+ // a function to process all parameters before substitution takes
+ // place, e.g. dojo.string.encodeXML
+ // thisObject:
+ // where to look for optional format function; default to the global
+ // namespace
+
+ return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(match, key, format){
+ var value = dojo.getObject(key,false,map);
+ if(format){ value = dojo.getObject(format,false,thisObject)(value);}
+ if(transform){ value = transform(value, key); }
+ return value.toString();
+ }); // string
+};
+
+dojo.string.trim = function(/*String*/ str){
+ // summary: trims whitespaces from both sides of the string
+ // description:
+ // This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript).
+ // The short yet performant version of this function is
+ // dojo.trim(), which is part of Dojo base.
+ str = str.replace(/^\s+/, '');
+ for(var i = str.length - 1; i > 0; i--){
+ if(/\S/.test(str.charAt(i))){
+ str = str.substring(0, i + 1);
+ break;
+ }
+ }
+ return str; // String
+};
+
+}
diff --git a/includes/js/dojo/tests.js b/includes/js/dojo/tests.js
new file mode 100644
index 0000000..04d192a
--- /dev/null
+++ b/includes/js/dojo/tests.js
@@ -0,0 +1,12 @@
+//This file is the command-line entry point for running the tests in
+//Rhino and Spidermonkey.
+
+/*=====
+dojo.tests = {
+ // summary: D.O.H. Test files for Dojo unit testing.
+};
+=====*/
+
+load("dojo.js");
+load("tests/runner.js");
+tests.run();
diff --git a/includes/js/dojo/tests/AdapterRegistry.js b/includes/js/dojo/tests/AdapterRegistry.js
new file mode 100644
index 0000000..4565e27
--- /dev/null
+++ b/includes/js/dojo/tests/AdapterRegistry.js
@@ -0,0 +1,75 @@
+if(!dojo._hasResource["tests.AdapterRegistry"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.AdapterRegistry"] = true;
+dojo.provide("tests.AdapterRegistry");
+dojo.require("dojo.AdapterRegistry");
+
+doh.register("tests.AdapterRegistry",
+ [
+ function ctor(t){
+ var taa = new dojo.AdapterRegistry();
+ t.is(0, taa.pairs.length);
+ t.f(taa.returnWrappers);
+
+ var taa = new dojo.AdapterRegistry(true);
+ t.t(taa.returnWrappers);
+ },
+
+ function register(t){
+ var taa = new dojo.AdapterRegistry();
+ taa.register("blah",
+ function(str){ return str == "blah"; },
+ function(){ return "blah"; }
+ );
+ t.is(1, taa.pairs.length);
+ t.is("blah", taa.pairs[0][0]);
+
+ taa.register("thinger");
+ taa.register("prepend", null, null, true, true);
+ t.is("prepend", taa.pairs[0][0]);
+ t.t(taa.pairs[0][3]);
+ },
+
+ /*
+ function match(t){
+ },
+ */
+
+ function noMatch(t){
+ var taa = new dojo.AdapterRegistry();
+ var threw = false;
+ try{
+ taa.match("blah");
+ }catch(e){
+ threw = true;
+ }
+ t.t(threw);
+ },
+
+ function returnWrappers(t){
+ var taa = new dojo.AdapterRegistry();
+ taa.register("blah",
+ function(str){ return str == "blah"; },
+ function(){ return "blah"; }
+ );
+ t.is("blah", taa.match("blah"));
+
+ taa.returnWrappers = true;
+ t.is("blah", taa.match("blah")());
+ },
+
+ function unregister(t){
+ var taa = new dojo.AdapterRegistry();
+ taa.register("blah",
+ function(str){ return str == "blah"; },
+ function(){ return "blah"; }
+ );
+ taa.register("thinger");
+ taa.register("prepend", null, null, true, true);
+ taa.unregister("prepend");
+ t.is(2, taa.pairs.length);
+ t.is("blah", taa.pairs[0][0]);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/DeferredList.js b/includes/js/dojo/tests/DeferredList.js
new file mode 100644
index 0000000..9353bfa
--- /dev/null
+++ b/includes/js/dojo/tests/DeferredList.js
@@ -0,0 +1,206 @@
+if(!dojo._hasResource["tests.DeferredList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.DeferredList"] = true;
+dojo.provide("tests.DeferredList");
+
+dojo.require("dojo.DeferredList");
+
+doh.register("tests.DeferredList",
+ [
+ function callback(t){
+ var d1 = new dojo.Deferred();
+ var d2 = new dojo.Deferred();
+ var dl = new dojo.DeferredList([d1, d2]);
+ var fired = false;
+
+ dl.addCallback(function(res){
+ doh.debug("debug from dojo.DeferredList callback");
+ return res;
+ });
+ dl.addCallback(function(res){
+ console.log("res: ", res, res.length);
+ t.assertTrue(res.length == 2);
+ t.assertTrue(res[0][0]);
+ t.assertEqual(res[0][1], "foo");
+ t.assertTrue(res[1][0]);
+ t.assertEqual(res[1][1], "bar");
+ fired = true;
+ return res;
+ });
+ d1.callback("foo");
+ d2.callback("bar");
+ t.assertTrue(fired);
+ },
+
+ function errback(t){
+ var d1 = new dojo.Deferred();
+ var d2 = new dojo.Deferred();
+ var dl = new dojo.DeferredList([d1, d2]);
+ var fired = false;
+ var e1 = new Error("foo");
+ var e2 = new Error("bar");
+
+ dl.addCallback(function(res){
+ doh.debug("debug from dojo.DeferredList callback");
+ return res;
+ });
+ dl.addCallback(function(res){
+ t.assertTrue(res.length == 2);
+ t.assertTrue(!res[0][0]);
+
+ t.assertEqual(res[0][1], e1);
+ t.assertTrue(!res[1][0]);
+ t.assertEqual(res[1][1], e2);
+ fired = true;
+ return res;
+ });
+ d1.errback(e1);
+ d2.errback(e2);
+ t.assertTrue(fired);
+ },
+
+
+ function mixed(t){
+ var d1 = new dojo.Deferred();
+ var d2 = new dojo.Deferred();
+ var dl = new dojo.DeferredList([d1, d2]);
+ var fired = false;
+ var e = new Error("foo");
+
+ dl.addCallback(function(res){
+ doh.debug("debug from dojo.DeferredList callback");
+ return res;
+ });
+ dl.addCallback(function(res){
+ t.assertTrue(res.length == 2);
+ t.assertTrue(!res[0][0]);
+
+ t.assertEqual(res[0][1], e);
+ t.assertTrue(res[1][0]);
+ t.assertEqual(res[1][1], "bar");
+ fired = true;
+ return res;
+ });
+ d1.errback(e);
+ d2.callback("bar");
+ t.assertTrue(fired);
+ },
+
+ function gather(t){
+ var d1 = new dojo.Deferred();
+ var d2 = new dojo.Deferred();
+ var dl = dojo.DeferredList.prototype.gatherResults([d1, d2]);
+ var fired = false;
+ dl.addCallback(function(res){
+ t.assertEqual(res[0], "foo");
+ t.assertEqual(res[1], "bar");
+ fired = true;
+ return res;
+ });
+ d1.callback("foo");
+ d2.callback("bar");
+ t.assertTrue(fired);
+ }
+ ]
+);
+dojo.provide("tests.DeferredList");
+
+dojo.require("dojo.DeferredList");
+
+doh.register("tests.DeferredList",
+ [
+ function callback(t){
+ var d1 = new dojo.Deferred();
+ var d2 = new dojo.Deferred();
+ var dl = new dojo.DeferredList([d1, d2]);
+ var fired = false;
+ dl.addCallback(function(res){
+ doh.debug("debug from dojo.DeferredList callback");
+ return res;
+ });
+ dl.addCallback(function(res){
+ t.assertTrue(res.length == 2);
+ t.assertTrue(res[0][0]);
+ t.assertEqual(res[0][1], "foo");
+ t.assertTrue(res[1][0]);
+ t.assertEqual(res[1][1], "bar");
+ fired = true;
+ return res;
+ });
+ d1.callback("foo");
+ d2.callback("bar");
+ t.assertTrue(fired);
+ },
+
+ function errback(t){
+ var d1 = new dojo.Deferred();
+ var d2 = new dojo.Deferred();
+ var dl = new dojo.DeferredList([d1, d2]);
+ var fired = false;
+ var e1 = new Error("foo");
+ var e2 = new Error("bar");
+
+ dl.addCallback(function(res){
+ doh.debug("debug from dojo.DeferredList callback");
+ return res;
+ });
+ dl.addCallback(function(res){
+ t.assertTrue(res.length == 2);
+ t.assertTrue(!res[0][0]);
+
+ t.assertEqual(res[0][1], e1);
+ t.assertTrue(!res[1][0]);
+ t.assertEqual(res[1][1], e2);
+ fired = true;
+ return res;
+ });
+ d1.errback(e1);
+ d2.errback(e2);
+ t.assertTrue(fired);
+ },
+
+
+ function mixed(t){
+ var d1 = new dojo.Deferred();
+ var d2 = new dojo.Deferred();
+ var dl = new dojo.DeferredList([d1, d2]);
+ var fired = false;
+ var e = new Error("foo");
+
+ dl.addCallback(function(res){
+ doh.debug("debug from dojo.DeferredList callback");
+ return res;
+ });
+ dl.addCallback(function(res){
+ t.assertTrue(res.length == 2);
+ t.assertTrue(!res[0][0]);
+
+ t.assertEqual(res[0][1], e);
+ t.assertTrue(res[1][0]);
+ t.assertEqual(res[1][1], "bar");
+ fired = true;
+ return res;
+ });
+ d1.errback(e);
+ d2.callback("bar");
+ t.assertTrue(fired);
+ },
+
+ function gather(t){
+ var d1 = new dojo.Deferred();
+ var d2 = new dojo.Deferred();
+ var dl = dojo.DeferredList.prototype.gatherResults([d1, d2]);
+ var fired = false;
+ dl.addCallback(function(res){
+ t.assertEqual(res[0], "foo");
+ t.assertEqual(res[1], "bar");
+ fired = true;
+ return res;
+ });
+ d1.callback("foo");
+ d2.callback("bar");
+ t.assertTrue(fired);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/NodeList-fx.html b/includes/js/dojo/tests/NodeList-fx.html
new file mode 100644
index 0000000..07fdbe0
--- /dev/null
+++ b/includes/js/dojo/tests/NodeList-fx.html
@@ -0,0 +1,150 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Testing dojo.fx extensions to dojo.NodeList</title>
+ <style type="text/css">
+ @import "../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ src="../dojo.js" djConfig="isDebug: true, popup: true"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+ dojo.require("dojo.NodeList-fx");
+
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ function fadeOut(){
+ dojo.query("p").style("opacity", 1);
+ var anim = dojo.query("p").fadeOut();
+ var d = new doh.Deferred();
+ dojo.connect(anim, "onEnd", function(){
+ doh.t(dojo.query("p").every(function(item){
+ return dojo.style(item, "opacity") == 0;
+ }));
+ d.callback(true);
+ });
+ anim.play();
+ return d;
+ },
+ function fadeIn(){
+ dojo.query("p").style("opacity", 0);
+ var anim = dojo.query("p").fadeIn();
+ var d = new doh.Deferred();
+ dojo.connect(anim, "onEnd", function(){
+ doh.t(dojo.query("p").every(function(item){
+ return dojo.style(item, "opacity") == 1;
+ }));
+ d.callback(true);
+ });
+ anim.play();
+ return d;
+ },
+ function wipeOut(){
+ dojo.query("p").style("height", "");
+ var anim = dojo.query("p").wipeOut();
+ var d = new doh.Deferred();
+ dojo.connect(anim, "onEnd", function(){
+ doh.t(dojo.query("p").every(function(item){
+ return dojo.style(item, "height") == 0;
+ }));
+ d.callback(true);
+ });
+ anim.play();
+ return d;
+ },
+ function wipeIn(){
+ dojo.query("p").style("height", 0);
+ var anim = dojo.query("p").wipeIn();
+ var d = new doh.Deferred();
+ dojo.connect(anim, "onEnd", function(){
+ doh.t(dojo.query("p").every(function(item){
+ // FIXME: need a more robust test for "have wiped all the way in"
+ return dojo.style(item, "height") != 0;
+ }));
+ d.callback(true);
+ });
+ anim.play();
+ return d;
+ },
+ function slideTo(){
+ var anim = dojo.query("p").slideTo({
+ left: 500
+ });
+ var d = new doh.Deferred();
+ dojo.connect(anim, "onEnd", function(){
+ doh.t(dojo.query("p").every(function(item){
+ // FIXME: need a more robust test for "have wiped all the way in"
+ return dojo.style(item, "left") == 500;
+ }));
+ d.callback(true);
+ });
+ anim.play();
+ return d;
+ },
+ function anim(){
+ dojo.query("p").style("position", "");
+ dojo.query("p").style("left", "");
+ var anim = dojo.query("p").anim({
+ width: 500
+ });
+ console.debug(anim);
+ var d = new doh.Deferred();
+ dojo.connect(anim, "onEnd", function(){
+ /*
+ doh.t(dojo.query("p").every(function(item){
+ // FIXME: need a more robust test for "have wiped all the way in"
+ return dojo.style(item, "width") == 500;
+ }));
+ */
+ d.callback(true);
+ });
+ return d;
+ }
+ ]
+ );
+ doh.run();
+ });
+ </script>
+ </head>
+ <body>
+ <p>
+ 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.
+ </p>
+ <p>
+ 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.
+ </p>
+ <p>
+ 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.
+ </p>
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/TODO b/includes/js/dojo/tests/TODO
new file mode 100644
index 0000000..c18bc3a
--- /dev/null
+++ b/includes/js/dojo/tests/TODO
@@ -0,0 +1,11 @@
+This file lists tests that need to be implemented or expanded. See ticket #3121
+for changes related to things listed here.
+
+Tests to add:
+-------------
+ * add tests for dojo.place()
+
+Tests to improve:
+-----------------
+ * cookie tests don't seem to test expiry or date functions
+ * NodeList isn't testing several of its public methods (place, orphan, adopt, etc.)
diff --git a/includes/js/dojo/tests/_base.js b/includes/js/dojo/tests/_base.js
new file mode 100644
index 0000000..7bc5301
--- /dev/null
+++ b/includes/js/dojo/tests/_base.js
@@ -0,0 +1,136 @@
+if(!dojo._hasResource["tests._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base"] = true;
+var testGlobal = this;
+try{
+ dojo.provide("tests._base");
+ testGlobal = dojo.global;
+}catch(e){ }
+
+// the test suite for the bootstrap. Requires hostenv and other base tests at
+// the end
+
+if(doh.selfTest){
+
+ doh.register("doh.smokeTest",
+ [
+ function sanityCheckHarness(t){
+ // sanity checks
+ t.assertTrue(true);
+ t.assertFalse(false);
+ t.assertFalse(0);
+ t.assertFalse(null);
+ var tObj = { w00t: false, blarg: true };
+ t.assertEqual(
+ ["thinger", "blah", tObj],
+ ["thinger", "blah", tObj]
+ );
+ t.assertEqual(tObj, tObj);
+ },
+ /*
+ // uncomment to tests exception handling
+ function sanityCheckassertTrue(t){
+ // should throw an error
+ t.assertTrue(false);
+ },
+ function sanityCheckassertFalse(t){
+ // should throw an error
+ t.assertFalse(true);
+ },
+ function sanityCheckassertEqual(t){
+ // should throw an error
+ t.assertEqual("foo", "bar");
+ },
+ */
+ {
+ name: "eqTest",
+ // smoke test the fixture system
+ setUp: function(t){
+ this.foo = "blah";
+ },
+ runTest: function(t){
+ t.assertEqual("blah", this.foo);
+ },
+ tearDown: function(t){
+ }
+ }
+ ]
+ );
+
+ if(testGlobal["dojo"]){
+ doh.register("tests._base",
+ [
+ function dojoIsAvailable(t){
+ t.assertTrue(testGlobal["dojo"]);
+ }
+ ]
+ );
+ }
+
+ if(testGlobal["setTimeout"]){
+ // a stone-stupid async test
+ doh.register("tests.async",
+ [
+ {
+ name: "deferredSuccess",
+ runTest: function(t){
+ var d = new doh.Deferred();
+ setTimeout(d.getTestCallback(function(){
+ t.assertTrue(true);
+ t.assertFalse(false);
+ }), 50);
+ return d;
+ }
+ },
+ {
+ name: "deferredFailure",
+ runTest: function(t){
+ var d = new doh.Deferred();
+ setTimeout(function(){
+ d.errback(new Error("hrm..."));
+ }, 50);
+ return d;
+ }
+ },
+ {
+ name: "timeoutFailure",
+ timeout: 50,
+ runTest: function(t){
+ // timeout of 50
+ var d = new doh.Deferred();
+ setTimeout(function(){
+ d.callback(true);
+ }, 100);
+ return d;
+ }
+ }
+ ]
+ );
+ }
+}
+
+try{
+ // go grab the others
+ dojo.require("tests._base._loader.bootstrap");
+ dojo.require("tests._base._loader.loader");
+ dojo.platformRequire({
+ browser: ["tests._base._loader.hostenv_browser"],
+ rhino: ["tests._base._loader.hostenv_rhino"],
+ spidermonkey: ["tests._base._loader.hostenv_spidermonkey"]
+ });
+ dojo.require("tests._base.array");
+ dojo.require("tests._base.Color");
+ dojo.require("tests._base.lang");
+ dojo.require("tests._base.declare");
+ dojo.require("tests._base.connect");
+ dojo.require("tests._base.Deferred");
+ dojo.require("tests._base.json");
+ // FIXME: add test includes for the rest of the Dojo Base groups here
+ dojo.requireIf(dojo.isBrowser, "tests._base.html");
+ dojo.requireIf(dojo.isBrowser, "tests._base.fx");
+ dojo.requireIf(dojo.isBrowser, "tests._base.query");
+ dojo.requireIf(dojo.isBrowser, "tests._base.xhr");
+}catch(e){
+ doh.debug(e);
+}
+
+}
diff --git a/includes/js/dojo/tests/_base/Color.js b/includes/js/dojo/tests/_base/Color.js
new file mode 100644
index 0000000..fa09842
--- /dev/null
+++ b/includes/js/dojo/tests/_base/Color.js
@@ -0,0 +1,32 @@
+if(!dojo._hasResource["tests._base.Color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base.Color"] = true;
+dojo.provide("tests._base.Color");
+
+(function(){
+ var white = dojo.colorFromString("white").toRgba();
+ var maroon = dojo.colorFromString("maroon").toRgba();
+ var verifyColor = function(t, source, expected){
+ var color = new dojo.Color(source);
+ t.is(expected, color.toRgba());
+ dojo.forEach(color.toRgba(), function(n){ t.is("number", typeof(n)); });
+ }
+
+ doh.register("tests._base.Color",
+ [
+ function testColor1(t){ verifyColor(t, "maroon", maroon); },
+ function testColor2(t){ verifyColor(t, "white", white); },
+ function testColor3(t){ verifyColor(t, "#fff", white); },
+ function testColor4(t){ verifyColor(t, "#ffffff", white); },
+ function testColor5(t){ verifyColor(t, "rgb(255,255,255)", white); },
+ function testColor6(t){ verifyColor(t, "#800000", maroon); },
+ function testColor7(t){ verifyColor(t, "rgb(128, 0, 0)", maroon); },
+ function testColor8(t){ verifyColor(t, "rgba(128, 0, 0, 0.5)", [128, 0, 0, 0.5]); },
+ function testColor9(t){ verifyColor(t, maroon, maroon); },
+ function testColor10(t){ verifyColor(t, [1, 2, 3], [1, 2, 3, 1]); },
+ function testColor11(t){ verifyColor(t, [1, 2, 3, 0.5], [1, 2, 3, 0.5]); },
+ function testColor12(t){ verifyColor(t, dojo.blendColors(new dojo.Color("black"), new dojo.Color("white"), 0.5), [128, 128, 128, 1]); }
+ ]
+ );
+})();
+
+}
diff --git a/includes/js/dojo/tests/_base/Deferred.js b/includes/js/dojo/tests/_base/Deferred.js
new file mode 100644
index 0000000..5dcf003
--- /dev/null
+++ b/includes/js/dojo/tests/_base/Deferred.js
@@ -0,0 +1,76 @@
+if(!dojo._hasResource["tests._base.Deferred"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base.Deferred"] = true;
+dojo.provide("tests._base.Deferred");
+
+doh.register("tests._base.Deferred",
+ [
+
+ function callback(t){
+ var nd = new dojo.Deferred();
+ var cnt = 0;
+ nd.addCallback(function(res){
+ doh.debug("debug from dojo.Deferred callback");
+ return res;
+ });
+ nd.addCallback(function(res){
+ // t.debug("val:", res);
+ cnt+=res;
+ return cnt;
+ });
+ nd.callback(5);
+ // t.debug("cnt:", cnt);
+ t.assertEqual(cnt, 5);
+ },
+
+ function callback_extra_args(t){
+ var nd = new dojo.Deferred();
+ var cnt = 0;
+ nd.addCallback(dojo.global, function(base, res){ cnt+=base; cnt+=res; return cnt; }, 30);
+ nd.callback(5);
+ t.assertEqual(cnt, 35);
+ },
+
+ function errback(t){
+ var nd = new dojo.Deferred();
+ var cnt = 0;
+ nd.addErrback(function(val){
+ return ++cnt;
+ });
+ nd.errback();
+ t.assertEqual(cnt, 1);
+ },
+
+ function callbackTwice(t){
+ var nd = new dojo.Deferred();
+ var cnt = 0;
+ nd.addCallback(function(res){
+ return ++cnt;
+ });
+ nd.callback();
+ t.assertEqual(cnt, 1);
+ var thrown = false;
+ try{
+ nd.callback();
+ }catch(e){
+ thrown = true;
+ }
+ t.assertTrue(thrown);
+ },
+
+ function addBoth(t){
+ var nd = new dojo.Deferred();
+ var cnt = 0;
+ nd.addBoth(function(res){
+ return ++cnt;
+ });
+ nd.callback();
+ t.assertEqual(cnt, 1);
+
+ // nd.callback();
+ // t.debug(cnt);
+ // t.assertEqual(cnt, 1);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/_base/NodeList.html b/includes/js/dojo/tests/_base/NodeList.html
new file mode 100644
index 0000000..e3f08c5
--- /dev/null
+++ b/includes/js/dojo/tests/_base/NodeList.html
@@ -0,0 +1,370 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<!--
+ we use a strict-mode DTD to ensure that the box model is the same for these
+ basic tests
+-->
+<html>
+ <head>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ html, body {
+ padding: 0px;
+ margin: 0px;
+ border: 0px;
+ }
+
+ #sq100 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 100px;
+ top: 100px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding: 0px;
+ margin: 0px;
+ overflow: hidden;
+ }
+
+ </style>
+ <title>testing dojo.NodeList</title>
+ <script type="text/javascript" src="../../dojo.js"
+ djConfig="isDebug: true, noFirebugLite: true"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+ dojo.addOnLoad(function(){
+ var c = dojo.byId("c1");
+ var t = dojo.byId("t");
+ var s = dojo.byId("sq100");
+ var fourElementNL = new dojo.NodeList(c, t, c, t);
+ doh.register("t",
+ [
+ // constructor tests
+ function ctor(){
+ var nl = new dojo.NodeList();
+ nl.push(c);
+ doh.is(1, nl.length);
+ },
+ function ctorArgs(){
+ var nl = new dojo.NodeList(4);
+ nl.push(c);
+ doh.is(5, nl.length);
+ },
+ function ctorArgs2(){
+ var nl = new dojo.NodeList(c, t);
+ doh.is(2, nl.length);
+ doh.is(c, nl[0]);
+ doh.is(t, nl[1]);
+ },
+ // iteration and array tests
+ function forEach(){
+ var lastItem;
+ var nl = new dojo.NodeList(c, t);
+ nl.forEach(function(i){ lastItem = i; });
+ doh.is(t, lastItem);
+
+ var r = nl.forEach(function(i, idx, arr){
+ doh.t(arr.constructor == dojo.NodeList);
+ doh.is(2, arr.length);
+ });
+ doh.t(r.constructor == dojo.NodeList);
+ doh.is(r, nl);
+ },
+
+ function indexOf(){
+ doh.is(0, fourElementNL.indexOf(c));
+ doh.is(1, fourElementNL.indexOf(t));
+ doh.is(-1, fourElementNL.indexOf(null));
+ },
+
+ function lastIndexOf(){
+ doh.is(2, fourElementNL.lastIndexOf(c));
+ doh.is(3, fourElementNL.lastIndexOf(t));
+ doh.is(-1, fourElementNL.lastIndexOf(null));
+ },
+
+ function every(){
+ var ctr = 0;
+ var ret = fourElementNL.every(function(){
+ ctr++;
+ return true;
+ });
+ doh.is(4, ctr);
+ doh.t(ret);
+
+ ctr = 0;
+ var ret = fourElementNL.every(function(){
+ ctr++;
+ return false;
+ });
+ doh.is(1, ctr);
+ doh.f(ret);
+ },
+
+ function some(){
+ var ret = fourElementNL.some(function(){
+ return true;
+ });
+ doh.t(ret);
+
+ var ret = fourElementNL.some(function(i){
+ return (i.id == "t");
+ });
+ doh.t(ret);
+ },
+
+ function map(){
+ var ret = fourElementNL.map(function(){
+ return true;
+ });
+
+ doh.is(ret, [true, true, true, true]);
+ var cnt = 0;
+ var ret = fourElementNL.map(function(){
+ return cnt++;
+ });
+ // doh.is(ret, [0, 1, 2, 3]);
+
+ doh.t(ret.constructor == dojo.NodeList);
+
+ // make sure that map() returns a NodeList
+ var sum = 0;
+ fourElementNL.map(function(){ return 2; }).forEach( function(x){ sum += x; } );
+ doh.is(sum, 8);
+ },
+
+ function slice(){
+ var pnl = new dojo.NodeList(t, t, c);
+ doh.is(2, pnl.slice(1).length);
+ doh.is(3, pnl.length);
+ doh.is(c, pnl.slice(-1)[0]);
+ doh.is(2, pnl.slice(-2).length);
+ },
+
+ function splice(){
+ var pnl = new dojo.NodeList(t, t, c);
+ console.debug(pnl.splice(1));
+ /*
+ doh.is(2, pnl.splice(1).length);
+ doh.is(1, pnl.length);
+ pnl = new dojo.NodeList(t, t, c);
+ doh.is(c, pnl.splice(-1)[0]);
+ doh.is(2, pnl.length);
+ pnl = new dojo.NodeList(t, t, c);
+ doh.is(2, pnl.splice(-2).length);
+ */
+ },
+
+ function spliceInsert(){
+ // insert 1
+ var pnl = new dojo.NodeList(t, t, c);
+ pnl.splice(0, 0, c);
+ doh.is(4, pnl.length);
+ doh.is(c, pnl[0]);
+
+ // insert multiple
+ pnl = new dojo.NodeList(t, t, c);
+ pnl.splice(0, 0, c, s);
+ doh.is(5, pnl.length);
+ doh.is(c, pnl[0]);
+ doh.is(s, pnl[1]);
+ doh.is(t, pnl[2]);
+
+ // insert multiple at offset
+ pnl = new dojo.NodeList(t, t, c);
+ pnl.splice(1, 0, c, s);
+ doh.is(5, pnl.length);
+ doh.is(t, pnl[0]);
+ doh.is(c, pnl[1]);
+ doh.is(s, pnl[2]);
+ doh.is(t, pnl[3]);
+ },
+
+ function spliceDel(){
+ // clobbery 1
+ var pnl = new dojo.NodeList(c, t, s);
+ pnl.splice(0, 1);
+ doh.is(2, pnl.length);
+ doh.is(t, pnl[0]);
+
+ // clobber multiple
+ pnl = new dojo.NodeList(c, t, s);
+ pnl.splice(0, 2);
+ doh.is(1, pnl.length);
+ doh.is(s, pnl[0]);
+
+ // ...at an offset
+ pnl = new dojo.NodeList(c, t, s);
+ pnl.splice(1, 1);
+ doh.is(2, pnl.length);
+ doh.is(c, pnl[0]);
+ doh.is(s, pnl[1]);
+
+ },
+
+ function spliceInsertDel(){
+ // clobbery 1
+ var pnl = new dojo.NodeList(c, t, s);
+ pnl.splice(1, 1, s);
+ doh.is(3, pnl.length);
+ doh.is(dojo.NodeList(c, s, s), pnl);
+
+ pnl = new dojo.NodeList(c, t, s);
+ pnl.splice(1, 2, s);
+ doh.is(2, pnl.length);
+ doh.is(dojo.NodeList(c, s), pnl);
+ },
+
+ // sub-search
+ function query(){
+ var pnl = new dojo.NodeList(t);
+ doh.is(c, pnl.query("span")[0]);
+ doh.is(t, dojo.query("body").query(":last-child")[0]);
+ doh.is(c, dojo.query("body").query(":last-child")[1]);
+ doh.is(1, pnl.query().length);
+ },
+
+ function filter(){
+ doh.is(dojo.query("body :first-child").filter(":last-child")[0], c);
+ doh.is(1, dojo.query("*").filter(function(n){ return (n.nodeName.toLowerCase() == "span"); }).length);
+
+ var filterObj = {
+ filterFunc: function(n){
+ return (n.nodeName.toLowerCase() == "span");
+ }
+ };
+ doh.is(1, dojo.query("*").filter(filterObj.filterFunc).length);
+ doh.is(1, dojo.query("*").filter(filterObj.filterFunc, filterObj).length);
+ },
+
+ // layout DOM functions
+ function coords(){
+ var tnl = new dojo.NodeList(dojo.byId('sq100'))
+ doh.t(dojo.isArray(tnl));
+ doh.is(100, tnl.coords()[0].w);
+ doh.is(100, tnl.coords()[0].h);
+ doh.is(document.body.getElementsByTagName("*").length, dojo.query("body *").coords().length);
+ },
+
+ function styleGet(){
+ // test getting
+ var tnl = new dojo.NodeList(s);
+ doh.is(1, tnl.style("opacity")[0]);
+ tnl.push(t);
+ dojo.style(t, "opacity", 0.5);
+ doh.is(0.5, tnl.style("opacity").slice(-1)[0]);
+ tnl.style("opacity", 1);
+ },
+
+ function styleSet(){
+ // test setting
+ var tnl = new dojo.NodeList(s, t);
+ tnl.style("opacity", 0.5);
+ doh.is(0.5, dojo.style(tnl[0], "opacity"));
+ doh.is(0.5, dojo.style(tnl[1], "opacity"));
+ // reset
+ tnl.style("opacity", 1);
+ },
+
+ function style(){
+ var tnl = new dojo.NodeList(s, t);
+ tnl.style("opacity", 1);
+ doh.is(1, tnl.style("opacity")[0]);
+ dojo.style(t, "opacity", 0.5);
+ doh.is(1.0, tnl.style("opacity")[0]);
+ doh.is(0.5, tnl.style("opacity")[1]);
+ // reset things
+ tnl.style("opacity", 1);
+ },
+
+ function concat(){
+ var spans = dojo.query("span");
+ var divs = dojo.query("div");
+ console.debug(spans.concat(divs));
+ doh.is(spans.concat(divs).constructor, dojo.NodeList);
+ doh.is((divs.length + spans.length), spans.concat(divs).length);
+ },
+
+ function concat2(t){
+ var spans = dojo.query("span");
+ var divs = dojo.query("div");
+ doh.is(spans.concat([]).constructor, dojo.NodeList);
+ },
+
+ function place(t){
+ var ih = "<div><span></span></div><span class='thud'><b>blah</b></span>";
+
+ var tn = document.createElement("div");
+ tn.innerHTML = ih;
+ dojo.body().appendChild(tn);
+ var nl = dojo.query("b", tn).place(tn, "first");
+ doh.t(nl.constructor == dojo.NodeList);
+ doh.is(1, nl.length);
+ doh.is("b", nl[0].nodeName.toLowerCase());
+ doh.is(tn, nl[0].parentNode);
+ doh.is(tn.firstChild, nl[0]);
+ },
+
+ function orphan(t){
+ var ih = "<div><span></span></div><span class='thud'><b>blah</b></span>";
+
+ var tn = document.createElement("div");
+ tn.innerHTML = ih;
+ dojo.body().appendChild(tn);
+ var nl = dojo.query("span", tn).orphan();
+ doh.t(nl.constructor == dojo.NodeList);
+
+ doh.is(2, nl.length);
+ doh.is(1, tn.getElementsByTagName("*").length);
+
+ tn.innerHTML = ih;
+ var nl = dojo.query("*", tn).orphan("b");
+ doh.is(1, nl.length);
+ doh.is("blah", nl[0].innerHTML);
+ },
+
+ /*
+ // FIXME
+ function adopt(t){
+ },
+
+ function addContent(t){
+ },
+ */
+
+ function connect(t){
+ var ih = "<div><span></span></div><span class='thud'><button>blah</button></span>";
+
+ var tn = document.createElement("div");
+ tn.innerHTML = ih;
+ dojo.body().appendChild(tn);
+
+ var ctr = 0;
+ var nl = dojo.query("button", tn).connect("onclick", function(){
+ ctr++;
+ });
+ nl[0].click();
+ doh.is(1, ctr);
+ nl[0].click();
+ nl[0].click();
+ doh.is(3, ctr);
+ }
+ ]
+ );
+ doh.run();
+ });
+ </script>
+ </head>
+ <body>
+ <h1>testing dojo.NodeList</h1>
+ <div id="sq100">
+ 100px square, abs
+ </div>
+ <div id="t">
+ <span id="c1">c1</span>
+ </div>
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/_loader/addLoadEvents.html b/includes/js/dojo/tests/_base/_loader/addLoadEvents.html
new file mode 100644
index 0000000..53e669f
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/addLoadEvents.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Testing dojo.addOnLoad() and dojo.addOnUnload()</title>
+ <script type="text/javascript"
+ src="../../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.addOnLoad(function(){
+ console.debug("addOnLoad(func) works");
+ });
+ var scope = {
+ named: function(){ console.debug("addOnLoad(obj, name) works"); },
+ refd: function(){ console.debug("addOnLoad(obj, func) works"); }
+ };
+ dojo.addOnLoad(scope, "named");
+ dojo.addOnLoad(scope, scope.refd);
+ // dojo.addOnLoad(scope, "named");
+ // dojo.addOnLoad(scope, scope.refd);
+
+ dojo.addOnUnload(function(){
+ alert("addOnUnload works");
+ });
+ </script>
+ </head>
+ <body>
+ <h1>Testing dojo.addOnLoad() and dojo.addOnUnload()</h1>
+
+ <p>This page has registers a function with dojo.addOnLoad() and dojo.addOnUnload.</p>
+
+ <p><b>dojo.addOnLoad()</b>: You should see an alert with the page first loads ("addOnLoad works").</p>
+
+ <p><b>dojo.addOnUnload()</b>: You should see an alert if the page is reloaded, or if you navigate to a
+ different web page ("addOnUnload works").
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/_loader/afterOnLoad.html b/includes/js/dojo/tests/_base/_loader/afterOnLoad.html
new file mode 100644
index 0000000..48ebd60
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/afterOnLoad.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Testing afterOnLoad</title>
+
+ <link rel="stylesheet" type="text/css" href="../../../resources/dojo.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../dijit/tests/css/dijitTests.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../dijit/themes/tundra/tundra.css" />
+
+ <script type="text/javascript">
+ window.onload = function(){
+ //Create global djConfig object first. We cannot use the djConfig attribute
+ //on the script tag since it may not be visible in some browsers at the time
+ //dojo.js executes. This causes problems when the "require" property is used
+ //as part of djConfig. Also note that you have to set baseUrl directly, since
+ //it cannot be detected as part of script tag.
+ djConfig = {
+ baseUrl: "../../../",
+ parseOnLoad: true,
+ afterOnLoad:true,
+ require: [
+ 'dojo.parser',
+ 'dijit._Calendar'
+ ],
+ isDebug: true
+ };
+
+ var script = document.createElement("script");
+ script.type = "text/javascript";
+ script.src = "../../../dojo.js";
+
+ document.getElementsByTagName("head")[0].appendChild(script);
+ }
+
+ function myHandler(id,newValue){
+ console.debug("onChange for id = " + id + ", value: " + newValue);
+ }
+ </script>
+ </head>
+ <body>
+ <h1>Testing afterOnLoad</h1>
+
+ <p><b>This page only works with a dojo build</b>. It will not work properly if you run it directly from the subversion source.</p>
+
+ <p>This page tests loading dojo after the page is loaded. </p>
+
+ <p>When the window.onload fires, the dojo script tag will be added to the DOM
+ and configured to fire the onload callbacks. If everything works, you should
+ see a Calendar below.</p>
+
+ <p class="tundra">
+ <input id="calendar1" dojoType="dijit._Calendar" onChange="myHandler(this.id,arguments[0])">
+ </p>
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/_base/_loader/bootstrap.js b/includes/js/dojo/tests/_base/_loader/bootstrap.js
new file mode 100644
index 0000000..c2605cb
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/bootstrap.js
@@ -0,0 +1,86 @@
+if(!dojo._hasResource["tests._base._loader.bootstrap"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base._loader.bootstrap"] = true;
+dojo.provide("tests._base._loader.bootstrap");
+
+tests.register("tests._base._loader.bootstrap",
+ [
+
+ function hasConsole(t){
+ t.assertTrue("console" in dojo.global);
+ t.assertTrue("assert" in console);
+ t.assertEqual("function", typeof console.assert);
+ },
+
+ {
+ name: "getObject",
+ setUp: function(){
+ //Set an object in global scope.
+ dojo.global.globalValue = {
+ color: "blue",
+ size: 20
+ };
+
+ //Set up an object in a specific scope.
+ this.foo = {
+ bar: {
+ color: "red",
+ size: 100
+ }
+ };
+ },
+ runTest: function(t){
+ //Test for existing object using global as root path.
+ var globalVar = dojo.getObject("globalValue");
+ t.is("object", (typeof globalVar));
+ t.assertEqual("blue", globalVar.color);
+ t.assertEqual(20, globalVar.size);
+ t.assertEqual("blue", dojo.getObject("globalValue.color"));
+
+ //Test for non-existent object using global as root path.
+ //Then create it.
+ t.assertFalse(dojo.getObject("something.thatisNew"));
+ t.assertTrue(typeof(dojo.getObject("something.thatisNew", true)) == "object");
+
+ //Test for existing object using another object as root path.
+ var scopedVar = dojo.getObject("foo.bar", false, this);
+ t.assertTrue(typeof(scopedVar) == "object");
+ t.assertEqual("red", scopedVar.color);
+ t.assertEqual(100, scopedVar.size);
+ t.assertEqual("red", dojo.getObject("foo.bar.color", true, this));
+
+ //Test for existing object using another object as root path.
+ //Then create it.
+ t.assertFalse(dojo.getObject("something.thatisNew", false, this));
+ t.assertTrue(typeof(dojo.getObject("something.thatisNew", true, this)) == "object");
+ },
+ tearDown: function(){
+ //Clean up global object that should not exist if
+ //the test is re-run.
+ try{
+ delete dojo.global.something;
+ delete this.something;
+ }catch(e){}
+ }
+ },
+
+ {
+ name: "exists",
+ setUp: function(){
+ this.foo = {
+ bar: {}
+ };
+ },
+ runTest: function(t){
+ t.assertTrue(dojo.exists("foo.bar", this));
+ t.assertFalse(dojo.exists("foo.bar"));
+ }
+ },
+
+ function evalWorks(t){
+ t.assertTrue(dojo.eval("(true)"));
+ t.assertFalse(dojo.eval("(false)"));
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/_base/_loader/getText.txt b/includes/js/dojo/tests/_base/_loader/getText.txt
new file mode 100644
index 0000000..054e8e8
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/getText.txt
@@ -0,0 +1 @@
+dojo._getText() test data \ No newline at end of file
diff --git a/includes/js/dojo/tests/_base/_loader/hostenv_browser.js b/includes/js/dojo/tests/_base/_loader/hostenv_browser.js
new file mode 100644
index 0000000..255fca5
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/hostenv_browser.js
@@ -0,0 +1,15 @@
+if(!dojo._hasResource["tests._base._loader.hostenv_browser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base._loader.hostenv_browser"] = true;
+dojo.provide("tests._base._loader.hostenv_browser");
+
+tests.register("tests._base._loader.hostenv_browser",
+ [
+ function getText(t){
+ var filePath = dojo.moduleUrl("tests._base._loader", "getText.txt");
+ var text = dojo._getText(filePath);
+ t.assertEqual("dojo._getText() test data", text);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/_base/_loader/hostenv_rhino.js b/includes/js/dojo/tests/_base/_loader/hostenv_rhino.js
new file mode 100644
index 0000000..c121576
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/hostenv_rhino.js
@@ -0,0 +1,17 @@
+if(!dojo._hasResource["tests._base._loader.hostenv_rhino"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base._loader.hostenv_rhino"] = true;
+dojo.provide("tests._base._loader.hostenv_rhino");
+
+tests.register("tests._base._loader.hostenv_rhino",
+ [
+ function getText(t){
+ var filePath = dojo.moduleUrl("tests._base._loader", "getText.txt");
+ var text = (new String(readText(filePath)));
+ //The Java file read seems to add a line return.
+ text = text.replace(/[\r\n]+$/, "");
+ t.assertEqual("dojo._getText() test data", text);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/_base/_loader/hostenv_spidermonkey.js b/includes/js/dojo/tests/_base/_loader/hostenv_spidermonkey.js
new file mode 100644
index 0000000..980d624
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/hostenv_spidermonkey.js
@@ -0,0 +1,15 @@
+if(!dojo._hasResource["tests._base._loader.hostenv_spidermonkey"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base._loader.hostenv_spidermonkey"] = true;
+dojo.provide("tests._base._loader.hostenv_spidermonkey");
+
+tests.register("tests._base._loader.hostenv_spidermonkey",
+ [
+ function getText(t){
+ var filePath = dojo.moduleUrl("tests._base._loader", "getText.txt");
+ var text = readText(filePath);
+ t.assertEqual("dojo._getText() test data", text);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/_base/_loader/loader.js b/includes/js/dojo/tests/_base/_loader/loader.js
new file mode 100644
index 0000000..af1a338
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/loader.js
@@ -0,0 +1,52 @@
+if(!dojo._hasResource["tests._base._loader.loader"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base._loader.loader"] = true;
+dojo.provide("tests._base._loader.loader");
+
+tests.register("tests._base._loader.loader",
+ [
+ function baseUrl(t){
+ var originalBaseUrl = dojo.config["baseUrl"] || "./";
+
+ t.assertEqual(originalBaseUrl, dojo.baseUrl);
+ },
+
+ function modulePaths(t){
+ dojo.registerModulePath("mycoolmod", "../some/path/mycoolpath");
+ dojo.registerModulePath("mycoolmod.widget", "http://some.domain.com/another/path/mycoolpath/widget");
+
+ t.assertEqual("../some/path/mycoolpath/util", dojo._getModuleSymbols("mycoolmod.util").join("/"));
+ t.assertEqual("http://some.domain.com/another/path/mycoolpath/widget", dojo._getModuleSymbols("mycoolmod.widget").join("/"));
+ t.assertEqual("http://some.domain.com/another/path/mycoolpath/widget/thingy", dojo._getModuleSymbols("mycoolmod.widget.thingy").join("/"));
+ },
+
+ function moduleUrls(t){
+ dojo.registerModulePath("mycoolmod", "some/path/mycoolpath");
+ dojo.registerModulePath("mycoolmod2", "/some/path/mycoolpath2");
+ dojo.registerModulePath("mycoolmod.widget", "http://some.domain.com/another/path/mycoolpath/widget");
+
+
+ var basePrefix = dojo.baseUrl;
+ //dojo._Uri will strip off "./" characters, so do the same here
+ if(basePrefix == "./"){
+ basePrefix = "";
+ }
+
+ t.assertEqual(basePrefix + "some/path/mycoolpath/my/favorite.html",
+ dojo.moduleUrl("mycoolmod", "my/favorite.html").toString());
+ t.assertEqual(basePrefix + "some/path/mycoolpath/my/favorite.html",
+ dojo.moduleUrl("mycoolmod.my", "favorite.html").toString());
+
+ t.assertEqual("/some/path/mycoolpath2/my/favorite.html",
+ dojo.moduleUrl("mycoolmod2", "my/favorite.html").toString());
+ t.assertEqual("/some/path/mycoolpath2/my/favorite.html",
+ dojo.moduleUrl("mycoolmod2.my", "favorite.html").toString());
+
+ t.assertEqual("http://some.domain.com/another/path/mycoolpath/widget/my/favorite.html",
+ dojo.moduleUrl("mycoolmod.widget", "my/favorite.html").toString());
+ t.assertEqual("http://some.domain.com/another/path/mycoolpath/widget/my/favorite.html",
+ dojo.moduleUrl("mycoolmod.widget.my", "favorite.html").toString());
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/_base/_loader/scope/scope04.html b/includes/js/dojo/tests/_base/_loader/scope/scope04.html
new file mode 100644
index 0000000..1866e4a
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/scope/scope04.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Multiversion Dojo: 0.4.3 and 1.0</title>
+
+ <link rel="stylesheet" type="text/css" href="../../../../resources/dojo.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../../dijit/css/dijitTests.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../../dijit/themes/tundra/tundra.css" />
+
+ <script type="text/javascript">
+ //djConfig for 0.4.3 setup.
+ djConfig = {
+ isDebug: true
+ };
+ </script>
+ <script type="text/javascript" src="http://o.aolcdn.com/dojo/0.4.3/dojo.js"></script>
+
+ <script type="text/javascript">
+ //Need scope map defined in a script block. It will not work as part of the
+ //djConfig attribute on the script that loads Dojo.
+ //Also, just adding properties instead of redefining djConfig, since that
+ //will wipe out djConfig values set up by the 0.4.3 dojo.
+ djConfig.parseOnLoad = true;
+ djConfig.baseUrl = "../../../../";
+ djConfig.scopeMap = [
+ ["dojo", "dojo10"],
+ ["dijit", "dijit10"],
+ ["dojox", "dojox10"]
+ ];
+ </script>
+ <script type="text/javascript" src="../../../../dojo.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.widget.DropdownDatePicker");
+ dojo10.require("dijit._Calendar");
+ dojo10.require("dojo.date.locale");
+ dojo10.require("dojo.parser"); // scan page for widgets
+
+ dojo.addOnLoad(function(){
+ dojo.byId("output043").innerHTML = dojo.version.toString();
+ });
+ dojo10.addOnLoad(function(){
+ dojo.byId("output10").innerHTML = dojo10.version.toString();
+ });
+
+ function myHandler(id,newValue){
+ console.debug("onChange for id = " + id + ", value: " + newValue);
+ }
+
+ function foobar(){
+ dojo.byId("typeOut").innerHTML = (typeof dojo.addClass);
+ }
+ setTimeout(foobar, 2000);
+
+ </script>
+ </head>
+ <body>
+ <h1>Multiversion Dojo: 0.4.3 and 1.0</h1>
+
+ <p><b>NOTE: This test only works with a built version of Dojo</b></p>
+
+ <p>This page loads Dojo 0.4.3 and Dojo 1.0.</p>
+
+ <p>Dojo 0.4.3 version: <span id="output043"></span></p>
+
+ <p>Dojo 1.0 version: <span id="output10"></span></p>
+
+ <p><b>dojo.addClass should be undefined:</b> <span id="typeOut"></span></p>
+
+ <p>
+ <input dojoType="dropdowndatepicker" value="2006-10-31" containerToggle="wipe" containerToggleDuration="300" >
+ </p>
+
+ <p class="tundra">
+ <input id="calendar1" dojo10Type="dijit._Calendar" onChange="myHandler(this.id,arguments[0])">
+ </p>
+
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/_loader/scope/scopeContained.html b/includes/js/dojo/tests/_base/_loader/scope/scopeContained.html
new file mode 100644
index 0000000..0acea5b
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/scope/scopeContained.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Multiversion Dojo: 0.4.3 and 1.0</title>
+
+ <link rel="stylesheet" type="text/css" href="../../../../resources/dojo.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../../dijit/css/dijitTests.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../../dijit/themes/tundra/tundra.css" />
+
+ <script type="text/javascript">
+ //djConfig for 0.4.3 setup.
+ djConfig = {
+ isDebug: true
+ };
+ </script>
+ <script type="text/javascript" src="http://o.aolcdn.com/dojo/0.4.3/dojo.js"></script>
+
+ <script type="text/javascript">
+ //Scope map for this page is "burned in" via a build command (see HTML notes below).
+ //Also, just adding properties instead of redefining djConfig, since that
+ //will wipe out djConfig values set up by the 0.4.3 dojo.
+ djConfig.parseOnLoad = true;
+ djConfig.baseUrl = "../../../../";
+ </script>
+ <script type="text/javascript" src="../../../../dojo.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.widget.DropdownDatePicker");
+
+ //Notice that dijit._Calendar is required, not jidit._Calendar.
+ //Same for the dojo resources (not jodo resources).
+ jodo.require("dijit._Calendar");
+ jodo.require("dojo.date.locale");
+ jodo.require("dojo.parser"); // scan page for widgets
+
+ dojo.addOnLoad(function(){
+ dojo.byId("output043").innerHTML = dojo.version.toString();
+ });
+ jodo.addOnLoad(function(){
+ dojo.byId("output10").innerHTML = jodo.version.toString();
+ });
+
+ function myHandler(id,newValue){
+ console.debug("onChange for id = " + id + ", value: " + newValue);
+ }
+ </script>
+ </head>
+ <body>
+ <h1>Multiversion Dojo: 0.4.3 and 1.0</h1>
+
+ <p><b>NOTE: This test only works with a built version of Dojo, and it must be built with the scopeMap parameter (the backslashes below are required):</b></p>
+
+ <p style="color: blue; background-color: yellow">build.sh profile=standard action=release scopeMap=[[\"dojo\",\"jodo\"],[\"dijit\",\"jidit\"],[\"dojox\",\"jodox\"]]</p>
+
+ <p>This page loads Dojo 0.4.3 and Dojo 1.0 (under the jodo scope)</p>
+
+ <p>Dojo 0.4.3 version: <span id="output043"></span></p>
+
+ <p>Jodo version: <span id="output10"></span></p>
+
+ <p>
+ <input dojoType="dropdowndatepicker" value="2006-10-31" containerToggle="wipe" containerToggleDuration="300" >
+ </p>
+
+ <p class="tundra">
+ <input id="calendar1" jodoType="dijit._Calendar" onChange="myHandler(this.id,arguments[0])">
+ </p>
+
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/_loader/scope/scopeContainedXd.html b/includes/js/dojo/tests/_base/_loader/scope/scopeContainedXd.html
new file mode 100644
index 0000000..c4c2eda
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/scope/scopeContainedXd.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Multiversion Dojo: 0.4.3 and 1.0</title>
+
+ <link rel="stylesheet" type="text/css" href="../../../../resources/dojo.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../../dijit/css/dijitTests.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../../dijit/themes/tundra/tundra.css" />
+
+ <script type="text/javascript">
+ //djConfig for 0.4.3 setup.
+ djConfig = {
+ isDebug: true
+ };
+ </script>
+ <script type="text/javascript" src="http://o.aolcdn.com/dojo/0.4.3/dojo.js"></script>
+
+ <script type="text/javascript">
+ //Scope map for this page is "burned in" via a build command (see HTML notes below).
+ //Also, just adding properties instead of redefining djConfig, since that
+ //will wipe out djConfig values set up by the 0.4.3 dojo.
+ djConfig.parseOnLoad = true;
+ djConfig.baseUrl = "../../../../";
+ djConfig.useXDomain = true; //Technically this was set already in the 0.4.3 xd dojo.js file.
+ </script>
+ <script type="text/javascript" src="../../../../dojo.xd.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.widget.DropdownDatePicker");
+
+ //Get base xd path
+ var xdPath = location.href;
+ var lastIndex = location.href.lastIndexOf("/");
+ xdPath = xdPath.substring(0, lastIndex + 1);
+
+ //Set up xdomain locations for dojo/dijit/dojox.
+ jodo.registerModulePath("dojo", xdPath + "../../../../../dojo");
+ jodo.registerModulePath("dijit", xdPath + "../../../../../dijit");
+ jodo.registerModulePath("dojox", xdPath + "../../../../../dojox");
+
+ //Notice that dijit._Calendar is required, not jidit._Calendar.
+ //Same for the dojo resources (not jodo resources).
+ jodo.require("dijit._Calendar");
+ jodo.require("dojo.date.locale");
+ jodo.require("dojo.parser"); // scan page for widgets
+
+ dojo.addOnLoad(function(){
+ dojo.byId("output043").innerHTML = dojo.version.toString();
+ });
+ jodo.addOnLoad(function(){
+ dojo.byId("output10").innerHTML = jodo.version.toString();
+ });
+
+ function myHandler(id,newValue){
+ console.debug("onChange for id = " + id + ", value: " + newValue);
+ }
+ </script>
+ </head>
+ <body>
+ <h1>XDomain Multiversion Dojo: 0.4.3 and 1.0</h1>
+
+ <p><b>NOTE: This test only works with a built, xdomain version of Dojo, and it must be built with the scopeMap parameter (the backslashes below are required):</b></p>
+
+ <p style="color: blue; background-color: yellow">build.sh profile=standard action=release scopeMap=[[\"dojo\",\"jodo\"],[\"dijit\",\"jidit\"],[\"dojox\",\"jodox\"]] xdDojoScopeName=jodo loader=xdomain</p>
+
+ <p><b>Only load this page from an http:// URL</b>. Otherwise, the xd loading will not happen.</p>
+
+ <p>This page xdomain loads Dojo 0.4.3 and Dojo 1.0 (under the jodo scope)</p>
+
+ <p>Dojo 0.4.3 version: <span id="output043"></span></p>
+
+ <p>Jodo version: <span id="output10"></span></p>
+
+ <p>
+ <input dojoType="dropdowndatepicker" value="2006-10-31" containerToggle="wipe" containerToggleDuration="300" >
+ </p>
+
+ <p class="tundra">
+ <input id="calendar1" jodoType="dijit._Calendar" onChange="myHandler(this.id,arguments[0])">
+ </p>
+
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/_loader/scope/scopeDjConfig.html b/includes/js/dojo/tests/_base/_loader/scope/scopeDjConfig.html
new file mode 100644
index 0000000..0ef5daa
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/scope/scopeDjConfig.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Multiversion Dojo: 0.4.3 and 1.0 (scoped djConfig)</title>
+
+ <link rel="stylesheet" type="text/css" href="../../../../resources/dojo.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../../dijit/css/dijitTests.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../../dijit/themes/tundra/tundra.css" />
+
+ <script type="text/javascript">
+ //djConfig for 0.4.3 setup.
+ djConfig = {
+ isDebug: true
+ };
+ </script>
+ <script type="text/javascript" src="http://o.aolcdn.com/dojo/0.4.3/dojo.js"></script>
+
+ <script type="text/javascript" src="../../../../dojo.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.widget.DropdownDatePicker");
+
+ //Notice that dijit._Calendar is required, not jidit._Calendar.
+ //Same for the dojo resources (not jodo resources).
+ jodo.require("dijit._Calendar");
+ jodo.require("dojo.date.locale");
+ jodo.require("dojo.parser"); // scan page for widgets
+
+ dojo.addOnLoad(function(){
+ dojo.byId("output043").innerHTML = djConfig.baseUrl;
+ });
+ jodo.addOnLoad(function(){
+ dojo.byId("output10").innerHTML = jodo.baseUrl;
+ });
+
+ function myHandler(id,newValue){
+ console.debug("onChange for id = " + id + ", value: " + newValue);
+ }
+ </script>
+ </head>
+ <body>
+ <h1>Multiversion Dojo: 0.4.3 and 1.0 (scoped djConfig)</h1>
+
+ <p><b>NOTE: This test only works with a built version of Dojo, and it must be built with the scopeDjConfig parameter (the backslashes below are required):</b></p>
+
+ <p style="color: blue; background-color: yellow">build.sh profile=standard action=release scopeDjConfig=\{parseOnLoad:true,baseUrl:\"../../../../\",foo:\"bar\",scopeMap:[[\"dojo\",\"jodo\"],[\"dijit\",\"jidit\"],[\"dojox\",\"jodox\"]]\}</p>
+
+ <p>This page loads Dojo 0.4.3 and Dojo 1.0 (under the jodo scope)</p>
+
+ <p>djConfig.baseUrl should <b>not</b> exist: <span id="output043"></span></p>
+
+ <p>jodo.baseUrl should be "../../../../": <span id="output10"></span></p>
+
+ <p>
+ <input dojoType="dropdowndatepicker" value="2006-10-31" containerToggle="wipe" containerToggleDuration="300" >
+ </p>
+
+ <p class="tundra">
+ <input id="calendar1" jodoType="dijit._Calendar" onChange="myHandler(this.id,arguments[0])">
+ </p>
+
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/_loader/scope/scopeSingle.html b/includes/js/dojo/tests/_base/_loader/scope/scopeSingle.html
new file mode 100644
index 0000000..759fcbe
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/scope/scopeSingle.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Using scope names inside dojo.require/dojoType</title>
+
+ <link rel="stylesheet" type="text/css" href="../../../../resources/dojo.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../../dijit/css/dijitTests.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../../dijit/themes/tundra/tundra.css" />
+
+ <script type="text/javascript">
+ //djConfig for 0.4.3 setup.
+ djConfig = {
+ isDebug: true,
+ parseOnLoad: true,
+ baseUrl: "../../../../",
+ scopeMap: [
+ ["dojo", "jodo"],
+ ["dijit", "jidit"],
+ ["dojox", "jodox"]
+ ]
+ };
+ </script>
+
+ <script type="text/javascript" src="../../../../dojo.js"></script>
+ <script type="text/javascript">
+
+ //Notice that dijit._Calendar is required, not jidit._Calendar.
+ //Same for the dojo resources (not jodo resources).
+ jodo.require("dijit._Calendar");
+ jodo.require("dojo.date.locale");
+ jodo.require("dojo.parser"); // scan page for widgets
+
+ jodo.addOnLoad(function(){
+ jodo.byId("output10").innerHTML = jodo.version.toString();
+ });
+
+ function myHandler(id,newValue){
+ console.debug("onChange for id = " + id + ", value: " + newValue);
+ }
+ function foobar(){
+ jodo.byId("typeOut").innerHTML = "typeof dojo: " + (typeof dojo) + "<br>typeof dijit: " + (typeof dijit) + "<br>typeof dojox: " + (typeof dojox);
+ }
+ setTimeout(foobar, 2000);
+ </script>
+ </head>
+ <body>
+ <h1>Using scope names inside dojo.require/dojoType</h1>
+
+ <p><b>NOTE: This test only works with a built version of Dojo.</b></p>
+
+ <p>Jodo version: <span id="output10"></span></p>
+
+ <p><b>typeof dojo, dijit and dojox should be undefined</b>: <br><span id="typeOut"></span></p>
+
+ <p class="tundra">
+ <input id="calendar1" jodoType="jidit._Calendar" onChange="myHandler(this.id,arguments[0])">
+ </p>
+
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/_loader/scope/scopeSingleDaac.html b/includes/js/dojo/tests/_base/_loader/scope/scopeSingleDaac.html
new file mode 100644
index 0000000..8f9d7d8
--- /dev/null
+++ b/includes/js/dojo/tests/_base/_loader/scope/scopeSingleDaac.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Using scope names inside dojo.require/dojoType</title>
+
+ <link rel="stylesheet" type="text/css" href="../../../../resources/dojo.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../../dijit/css/dijitTests.css" />
+ <link rel="stylesheet" type="text/css" href="../../../../../dijit/themes/tundra/tundra.css" />
+
+ <script type="text/javascript">
+ //djConfig for 0.4.3 setup.
+ djConfig = {
+ isDebug: true,
+ debugAtAllCosts: true,
+ parseOnLoad: true,
+ baseUrl: "../../../../",
+ scopeMap: [
+ ["dojo", "jodo"],
+ ["dijit", "jidit"],
+ ["dojox", "jodox"]
+ ]
+ };
+ </script>
+
+ <script type="text/javascript" src="../../../../dojo.js"></script>
+ <script type="text/javascript">
+
+ //Notice that dijit._Calendar is required, not jidit._Calendar.
+ //Same for the dojo resources (not jodo resources).
+ jodo.require("dijit._Calendar");
+ jodo.require("dojo.date.locale");
+ jodo.require("dojo.parser"); // scan page for widgets
+
+ jodo.addOnLoad(function(){
+ jodo.byId("output10").innerHTML = jodo.version.toString();
+ });
+
+ function myHandler(id,newValue){
+ console.debug("onChange for id = " + id + ", value: " + newValue);
+ }
+ function foobar(){
+ jodo.byId("typeOut").innerHTML = "typeof dojo: " + (typeof dojo) + "<br>typeof dijit: " + (typeof dijit) + "<br>typeof dojox: " + (typeof dojox);
+ }
+ setTimeout(foobar, 2000);
+ </script>
+ </head>
+ <body>
+ <h1>Using scope names inside dojo.require/dojoType</h1>
+
+ <p><b>NOTE: This test only works with a built version of Dojo.</b></p>
+
+ <p>Jodo version: <span id="output10"></span></p>
+
+ <p><b>typeof dojo, dijit and dojox should be object, since debugAtAllCosts is ON</b>: <br><span id="typeOut"></span></p>
+
+ <p class="tundra">
+ <input id="calendar1" jodoType="jidit._Calendar" onChange="myHandler(this.id,arguments[0])">
+ </p>
+
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/array.js b/includes/js/dojo/tests/_base/array.js
new file mode 100644
index 0000000..6611257
--- /dev/null
+++ b/includes/js/dojo/tests/_base/array.js
@@ -0,0 +1,301 @@
+if(!dojo._hasResource["tests._base.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base.array"] = true;
+dojo.provide("tests._base.array");
+
+tests.register("tests._base.array",
+ [
+ function testIndexOf(t){
+ var foo = [128, 256, 512];
+ var bar = ["aaa", "bbb", "ccc"];
+
+ t.assertEqual(1, dojo.indexOf([45, 56, 85], 56));
+ t.assertEqual(1, dojo.indexOf([Number, String, Date], String));
+ t.assertEqual(1, dojo.indexOf(foo, foo[1]));
+ t.assertEqual(2, dojo.indexOf(foo, foo[2]));
+ t.assertEqual(1, dojo.indexOf(bar, bar[1]));
+ t.assertEqual(2, dojo.indexOf(bar, bar[2]));
+ t.assertEqual(-1, dojo.indexOf({a:1}, "a"));
+
+ foo.push(bar);
+ t.assertEqual(3, dojo.indexOf(foo, bar));
+ },
+
+ function testIndexOfFromIndex(t){
+ var foo = [128, 256, 512];
+ var bar = ["aaa", "bbb", "ccc"];
+
+ t.assertEqual(-1, dojo.indexOf([45, 56, 85], 56, 2));
+ t.assertEqual(1, dojo.indexOf([45, 56, 85], 56, 1));
+ t.assertEqual(1, dojo.indexOf([45, 56, 85], 56, -1));
+ // Make sure going out of bounds doesn't throw us in an infinite loop
+ t.assertEqual(-1, dojo.indexOf([45, 56, 85], 56, 3));
+ },
+
+ function testLastIndexOf(t){
+ var foo = [128, 256, 512];
+ var bar = ["aaa", "bbb", "aaa", "ccc"];
+
+ t.assertEqual(1, dojo.indexOf([45, 56, 85], 56));
+ t.assertEqual(1, dojo.indexOf([Number, String, Date], String));
+ t.assertEqual(1, dojo.lastIndexOf(foo, foo[1]));
+ t.assertEqual(2, dojo.lastIndexOf(foo, foo[2]));
+ t.assertEqual(1, dojo.lastIndexOf(bar, bar[1]));
+ t.assertEqual(2, dojo.lastIndexOf(bar, bar[2]));
+ t.assertEqual(2, dojo.lastIndexOf(bar, bar[0]));
+ },
+
+ function testLastIndexOfFromIndex(t){
+ t.assertEqual(1, dojo.lastIndexOf([45, 56, 85], 56, 1));
+ t.assertEqual(-1, dojo.lastIndexOf([45, 56, 85], 85, 1));
+ t.assertEqual(-1, dojo.lastIndexOf([45, 56, 85], 85, -1));
+ t.assertEqual(0, dojo.lastIndexOf([45, 56, 45], 45, 0));
+ },
+
+ function testForEach(t){
+ var foo = [128, "bbb", 512];
+ dojo.forEach(foo, function(elt, idx, array){
+ switch(idx){
+ case 0: t.assertEqual(128, elt); break;
+ case 1: t.assertEqual("bbb", elt); break;
+ case 2: t.assertEqual(512, elt); break;
+ default: t.assertTrue(false);
+ }
+ });
+
+ var noException = true;
+ try{
+ dojo.forEach(undefined, function(){});
+ }catch(e){
+ noException = false;
+ }
+ t.assertTrue(noException);
+ },
+
+ function testForEach_str(t){
+ var bar = 'abc';
+ dojo.forEach(bar, function(elt, idx, array){
+ switch(idx){
+ case 0: t.assertEqual("a", elt); break;
+ case 1: t.assertEqual("b", elt); break;
+ case 2: t.assertEqual("c", elt); break;
+ default: t.assertTrue(false);
+ }
+ });
+ },
+ // FIXME: test forEach w/ a NodeList()?
+
+ function testForEach_string_callback(t){
+ // Test using strings as callback", which accept the parameters with
+ // the names "item", "index" and "array"!
+ var foo = [128, "bbb", 512];
+ // Test that the variable "item" contains the value of each item.
+ this._res = "";
+ dojo.forEach(foo, 'this._res+=item', this);
+ t.assertEqual(this._res, "128bbb512");
+ // Test that the variable "index" contains each index.
+ this._res = [];
+ dojo.forEach(foo, 'this._res.push(index)', this);
+ t.assertEqual(this._res, [0,1,2]);
+ // Test that the variable "array" always contains the entire array.
+ this._res = [];
+ dojo.forEach(foo, 'this._res.push(array)', this);
+ t.assertEqual(this._res, [[128, "bbb", 512],[128, "bbb", 512],[128, "bbb", 512]]);
+ // Catch undefined variable usage (I used to use "i" :-)).
+ var caughtException = false;
+ try{
+ dojo.forEach(foo, 'this._res+=i', this);
+ }catch(e){
+ caughtException = true;
+ }
+ t.assertTrue(caughtException);
+ },
+
+ // FIXME: test forEach w/ a NodeList()?
+ function testEvery(t){
+ var foo = [128, "bbb", 512];
+
+ t.assertTrue(
+ dojo.every(foo, function(elt, idx, array){
+ t.assertEqual(Array, array.constructor);
+ t.assertTrue(dojo.isArray(array));
+ t.assertTrue(typeof idx == "number");
+ if(idx == 1){ t.assertEqual("bbb" , elt); }
+ return true;
+ })
+ );
+
+ t.assertTrue(
+ dojo.every(foo, function(elt, idx, array){
+ switch(idx){
+ case 0: t.assertEqual(128, elt); return true;
+ case 1: t.assertEqual("bbb", elt); return true;
+ case 2: t.assertEqual(512, elt); return true;
+ default: return false;
+ }
+ })
+ );
+
+ t.assertFalse(
+ dojo.every(foo, function(elt, idx, array){
+ switch(idx){
+ case 0: t.assertEqual(128, elt); return true;
+ case 1: t.assertEqual("bbb", elt); return true;
+ case 2: t.assertEqual(512, elt); return false;
+ default: return true;
+ }
+ })
+ );
+
+ },
+
+ function testEvery_str(t){
+ var bar = 'abc';
+ t.assertTrue(
+ dojo.every(bar, function(elt, idx, array){
+ switch(idx){
+ case 0: t.assertEqual("a", elt); return true;
+ case 1: t.assertEqual("b", elt); return true;
+ case 2: t.assertEqual("c", elt); return true;
+ default: return false;
+ }
+ })
+ );
+
+ t.assertFalse(
+ dojo.every(bar, function(elt, idx, array){
+ switch(idx){
+ case 0: t.assertEqual("a", elt); return true;
+ case 1: t.assertEqual("b", elt); return true;
+ case 2: t.assertEqual("c", elt); return false;
+ default: return true;
+ }
+ })
+ );
+ },
+ // FIXME: test NodeList for every()?
+
+ function testSome(t){
+ var foo = [128, "bbb", 512];
+ t.assertTrue(
+ dojo.some(foo, function(elt, idx, array){
+ t.assertEqual(3, array.length);
+ return true;
+ })
+ );
+
+ t.assertTrue(
+ dojo.some(foo, function(elt, idx, array){
+ if(idx < 1){ return true; }
+ return false;
+ })
+ );
+
+ t.assertFalse(
+ dojo.some(foo, function(elt, idx, array){
+ return false;
+ })
+ );
+
+ t.assertTrue(
+ dojo.some(foo, function(elt, idx, array){
+ t.assertEqual(Array, array.constructor);
+ t.assertTrue(dojo.isArray(array));
+ t.assertTrue(typeof idx == "number");
+ if(idx == 1){ t.assertEqual("bbb" , elt); }
+ return true;
+ })
+ );
+ },
+
+ function testSome_str(t){
+ var bar = 'abc';
+ t.assertTrue(
+ dojo.some(bar, function(elt, idx, array){
+ t.assertEqual(3, array.length);
+ switch(idx){
+ case 0: t.assertEqual("a", elt); return true;
+ case 1: t.assertEqual("b", elt); return true;
+ case 2: t.assertEqual("c", elt); return true;
+ default: return false;
+ }
+ })
+ );
+
+ t.assertTrue(
+ dojo.some(bar, function(elt, idx, array){
+ switch(idx){
+ case 0: t.assertEqual("a", elt); return true;
+ case 1: t.assertEqual("b", elt); return true;
+ case 2: t.assertEqual("c", elt); return false;
+ default: return true;
+ }
+ })
+ );
+
+ t.assertFalse(
+ dojo.some(bar, function(elt, idx, array){
+ return false;
+ })
+ );
+ },
+ // FIXME: need to add scoping tests for all of these!!!
+
+ function testFilter(t){
+ var foo = ["foo", "bar", 10];
+
+ t.assertEqual(["foo"],
+ dojo.filter(foo, function(elt, idx, array){
+ return idx < 1;
+ })
+ );
+
+ t.assertEqual(["foo"],
+ dojo.filter(foo, function(elt, idx, array){
+ return elt == "foo";
+ })
+ );
+
+ t.assertEqual([],
+ dojo.filter(foo, function(elt, idx, array){
+ return false;
+ })
+ );
+
+ t.assertEqual([10],
+ dojo.filter(foo, function(elt, idx, array){
+ return typeof elt == "number";
+ })
+ );
+ },
+
+ function testFilter_str(t){
+ var foo = "thinger blah blah blah";
+ t.assertEqual(["t", "h", "i"],
+ dojo.filter(foo, function(elt, idx, array){
+ return idx < 3;
+ })
+ );
+
+ t.assertEqual([],
+ dojo.filter(foo, function(elt, idx, array){
+ return false;
+ })
+ );
+ },
+
+ function testMap(t){
+ t.assertEqual([],
+ dojo.map([], function(){ return true; })
+ );
+
+ t.assertEqual([1, 2, 3],
+ dojo.map(["cat", "dog", "mouse"], function(elt, idx, array){
+ return idx+1;
+ })
+ );
+ }
+ ]
+);
+
+
+}
diff --git a/includes/js/dojo/tests/_base/connect.js b/includes/js/dojo/tests/_base/connect.js
new file mode 100644
index 0000000..3761861
--- /dev/null
+++ b/includes/js/dojo/tests/_base/connect.js
@@ -0,0 +1,225 @@
+if(!dojo._hasResource["tests._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base.connect"] = true;
+dojo.provide("tests._base.connect");
+
+hub = function(){
+}
+
+failures = 0;
+bad = function(){
+ failures++;
+}
+
+good = function(){
+}
+
+// make 'iterations' connections to hub
+// roughly half of which will be to 'good' and
+// half to 'bad'
+// all connections to 'bad' are disconnected
+// test can then be performed on the values
+// 'failures' and 'successes'
+markAndSweepTest = function(iterations){
+ var marked = [];
+ // connections
+ for(var i=0; i<iterations; i++){
+ if(Math.random() < 0.5){
+ marked.push(dojo.connect('hub', bad));
+ }else{
+ dojo.connect('hub', good);
+ }
+ }
+ // Randomize markers (only if the count isn't very high)
+ if(i < Math.pow(10, 4)){
+ var rm = [ ];
+ while(marked.length){
+ var m = Math.floor(Math.random() * marked.length);
+ rm.push(marked[m]);
+ marked.splice(m, 1);
+ }
+ marked = rm;
+ }
+ for(var m=0; m<marked.length; m++){
+ dojo.disconnect(marked[m]);
+ }
+ // test
+ failures = 0;
+ hub();
+ // return number of disconnected functions that fired (should be 0)
+ return failures;
+}
+
+markAndSweepSubscribersTest = function(iterations){
+ var topic = "hubbins";
+ var marked = [];
+ // connections
+ for(var i=0; i<iterations; i++){
+ if(Math.random() < 0.5){
+ marked.push(dojo.subscribe(topic, bad));
+ }else{
+ dojo.subscribe(topic, good);
+ }
+ }
+ // Randomize markers (only if the count isn't very high)
+ if(i < Math.pow(10, 4)){
+ var rm = [ ];
+ while(marked.length){
+ var m = Math.floor(Math.random() * marked.length);
+ rm.push(marked[m]);
+ marked.splice(m, 1);
+ }
+ marked = rm;
+ }
+ for(var m=0; m<marked.length; m++){
+ dojo.unsubscribe(marked[m]);
+ }
+ // test
+ failures = 0;
+ dojo.publish(topic);
+ // return number of unsubscribed functions that fired (should be 0)
+ return failures;
+}
+
+tests.register("tests._base.connect",
+ [
+ function smokeTest(t){
+ // foo sets ok to false
+ var ok = false;
+ var foo = { "foo": function(){ ok=false; } };
+ // connected function sets ok to true
+ dojo.connect(foo, "foo", null, function(){ ok=true; });
+ foo.foo();
+ t.is(true, ok);
+ },
+ function basicTest(t) {
+ var out = '';
+ var obj = {
+ foo: function() {
+ out += 'foo';
+ },
+ bar: function() {
+ out += 'bar';
+ },
+ baz: function() {
+ out += 'baz';
+ }
+ };
+ //
+ var foobar = dojo.connect(obj, "foo", obj, "bar");
+ dojo.connect(obj, "bar", obj, "baz");
+ //
+ out = '';
+ obj.foo();
+ t.is('foobarbaz', out);
+ //
+ out = '';
+ obj.bar();
+ t.is('barbaz', out);
+ //
+ out = '';
+ obj.baz();
+ t.is('baz', out);
+ //
+ dojo.connect(obj, "foo", obj, "baz");
+ dojo.disconnect(foobar);
+ //
+ out = '';
+ obj.foo();
+ t.is('foobaz', out);
+ //
+ out = '';
+ obj.bar();
+ t.is('barbaz', out);
+ //
+ out = '';
+ obj.baz();
+ t.is('baz', out);
+ },
+ function hubConnectDisconnect1000(t){
+ t.is(0, markAndSweepTest(1000));
+ },
+ function args4Test(t){
+ // standard 4 args test
+ var ok, obj = { foo: function(){ok=false;}, bar: function(){ok=true} };
+ dojo.connect(obj, "foo", obj, "bar");
+ obj.foo();
+ t.is(true, ok);
+ },
+ function args3Test(t){
+ // make some globals
+ var ok;
+ dojo.global["gFoo"] = function(){ok=false;};
+ dojo.global["gOk"] = function(){ok=true;};
+ // 3 arg shorthand for globals (a)
+ var link = dojo.connect("gFoo", null, "gOk");
+ gFoo();
+ dojo.disconnect(link);
+ t.is(true, ok);
+ // 3 arg shorthand for globals (b)
+ link = dojo.connect(null, "gFoo", "gOk");
+ gFoo();
+ dojo.disconnect(link);
+ t.is(true, ok);
+ // verify disconnections
+ gFoo();
+ t.is(false, ok);
+ },
+ function args2Test(t){
+ // make some globals
+ var ok;
+ dojo.global["gFoo"] = function(){ok=false;};
+ dojo.global["gOk"] = function(){ok=true;};
+ // 2 arg shorthand for globals
+ var link = dojo.connect("gFoo", "gOk");
+ gFoo();
+ dojo.disconnect(link);
+ t.is(true, ok);
+ // 2 arg shorthand for globals, alternate scoping
+ link = dojo.connect("gFoo", gOk);
+ gFoo();
+ dojo.disconnect(link);
+ t.is(true, ok);
+ },
+ function scopeTest1(t){
+ var foo = { ok: true, foo: function(){this.ok=false;} };
+ var bar = { ok: false, bar: function(){this.ok=true} };
+ // link foo.foo to bar.bar with natural scope
+ var link = dojo.connect(foo, "foo", bar, "bar");
+ foo.foo();
+ t.is(false, foo.ok);
+ t.is(true, bar.ok);
+ },
+ function scopeTest2(t){
+ var foo = { ok: true, foo: function(){this.ok=false;} };
+ var bar = { ok: false, bar: function(){this.ok=true} };
+ // link foo.foo to bar.bar such that scope is always 'foo'
+ var link = dojo.connect(foo, "foo", bar.bar);
+ foo.foo();
+ t.is(true, foo.ok);
+ t.is(false, bar.ok);
+ },
+ function connectPublisher(t){
+ var foo = { inc: 0, foo: function(){ this.inc++; } };
+ var bar = { inc: 0, bar: function(){ this.inc++; } };
+ var c1h = dojo.connectPublisher("/blah", foo, "foo");
+ var c2h = dojo.connectPublisher("/blah", foo, "foo");
+ dojo.subscribe("/blah", bar, "bar");
+ foo.foo();
+ t.is(1, foo.inc);
+ t.is(2, bar.inc);
+ dojo.disconnect(c1h);
+ foo.foo();
+ t.is(2, foo.inc);
+ t.is(3, bar.inc);
+ dojo.disconnect(c2h);
+ foo.foo();
+ t.is(3, foo.inc);
+ t.is(3, bar.inc);
+ },
+ function publishSubscribe1000(t){
+ t.is(markAndSweepSubscribersTest(1000), 0);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/_base/declare.js b/includes/js/dojo/tests/_base/declare.js
new file mode 100644
index 0000000..11720ec
--- /dev/null
+++ b/includes/js/dojo/tests/_base/declare.js
@@ -0,0 +1,197 @@
+if(!dojo._hasResource["tests._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base.declare"] = true;
+dojo.provide("tests._base.declare");
+
+tests.register("tests._base.declare",
+ [
+ function smokeTest(t){
+ dojo.declare("tests._base.declare.tmp");
+ var tmp = new tests._base.declare.tmp();
+ dojo.declare("testsFoo");
+ var tmp = new testsFoo();
+ },
+ function smokeTest2(t){
+ dojo.declare("tests._base.declare.foo", null, {
+ foo: "thonk"
+ });
+ var tmp = new tests._base.declare.foo();
+ t.is("thonk", tmp.foo);
+
+ dojo.declare("testsFoo2", null, {
+ foo: "thonk"
+ });
+ var tmp2 = new testsFoo2();
+ t.is("thonk", tmp2.foo);
+ },
+ function smokeTestWithCtor(t){
+ dojo.declare("tests._base.declare.fooBar", null, {
+ constructor: function(){
+ this.foo = "blah";
+ },
+ foo: "thonk"
+ });
+ var tmp = new tests._base.declare.fooBar();
+ t.is("blah", tmp.foo);
+ },
+ function smokeTestCompactArgs(t){
+ dojo.declare("tests._base.declare.fooBar2", null, {
+ foo: "thonk"
+ });
+ var tmp = new tests._base.declare.fooBar2();
+ t.is("thonk", tmp.foo);
+ },
+ function subclass(t){
+ dojo.declare("tests._base.declare.tmp3", null, {
+ foo: "thonk"
+ });
+ dojo.declare("tests._base.declare.tmp4", tests._base.declare.tmp3);
+ var tmp = new tests._base.declare.tmp4();
+ t.is("thonk", tmp.foo);
+ },
+ function subclassWithCtor(t){
+ dojo.declare("tests._base.declare.tmp5", null, {
+ constructor: function(){
+ this.foo = "blah";
+ },
+ foo: "thonk"
+ });
+ dojo.declare("tests._base.declare.tmp6", tests._base.declare.tmp5);
+ var tmp = new tests._base.declare.tmp6();
+ t.is("blah", tmp.foo);
+ },
+ function mixinSubclass(t){
+ dojo.declare("tests._base.declare.tmp7", null, {
+ foo: "thonk"
+ });
+ dojo.declare("tests._base.declare.tmp8", null, {
+ constructor: function(){
+ this.foo = "blah";
+ }
+ });
+ var tmp = new tests._base.declare.tmp8();
+ t.is("blah", tmp.foo);
+ dojo.declare("tests._base.declare.tmp9",
+ [
+ tests._base.declare.tmp7, // prototypal
+ tests._base.declare.tmp8 // mixin
+ ]);
+ var tmp2 = new tests._base.declare.tmp9();
+ t.is("blah", tmp2.foo);
+ },
+ function superclassRef(t){
+ dojo.declare("tests._base.declare.tmp10", null, {
+ foo: "thonk"
+ });
+ dojo.declare("tests._base.declare.tmp11", tests._base.declare.tmp10, {
+ constructor: function(){
+ this.foo = "blah";
+ }
+ });
+ var tmp = new tests._base.declare.tmp11();
+ t.is("blah", tmp.foo);
+ t.is("thonk", tests._base.declare.tmp11.superclass.foo);
+ },
+ function inheritedCall(t){
+ var foo = "xyzzy";
+ dojo.declare("tests._base.declare.tmp12", null, {
+ foo: "thonk",
+ bar: function(arg1, arg2){
+ if(arg1){
+ this.foo = arg1;
+ }
+ if(arg2){
+ foo = arg2;
+ }
+ }
+ });
+ dojo.declare("tests._base.declare.tmp13", tests._base.declare.tmp12, {
+ constructor: function(){
+ this.foo = "blah";
+ }
+ });
+ var tmp = new tests._base.declare.tmp13();
+ t.is("blah", tmp.foo);
+ t.is("xyzzy", foo);
+ tmp.bar("zot");
+ t.is("zot", tmp.foo);
+ t.is("xyzzy", foo);
+ tmp.bar("trousers", "squiggle");
+ t.is("trousers", tmp.foo);
+ t.is("squiggle", foo);
+ },
+ function inheritedExplicitCall(t){
+ var foo = "xyzzy";
+ dojo.declare("tests._base.declare.tmp14", null, {
+ foo: "thonk",
+ bar: function(arg1, arg2){
+ if(arg1){
+ this.foo = arg1;
+ }
+ if(arg2){
+ foo = arg2;
+ }
+ }
+ });
+ dojo.declare("tests._base.declare.tmp15", tests._base.declare.tmp14, {
+ constructor: function(){
+ this.foo = "blah";
+ },
+ bar: function(arg1, arg2){
+ this.inherited("bar", arguments, [arg2, arg1]);
+ },
+ baz: function(arg1, arg2){
+ tests._base.declare.tmp15.superclass.bar.apply(this, arguments);
+ }
+ });
+ var tmp = new tests._base.declare.tmp15();
+ t.is("blah", tmp.foo);
+ t.is("xyzzy", foo);
+ tmp.baz("zot");
+ t.is("zot", tmp.foo);
+ t.is("xyzzy", foo);
+ tmp.bar("trousers", "squiggle");
+ t.is("squiggle", tmp.foo);
+ t.is("trousers", foo);
+ },
+ function inheritedMixinCalls(t){
+ dojo.declare("tests._base.declare.tmp16", null, {
+ foo: "",
+ bar: function(){
+ this.foo += "tmp16";
+ }
+ });
+ dojo.declare("tests._base.declare.mixin16", null, {
+ bar: function(){
+ this.inherited(arguments);
+ this.foo += ".mixin16";
+ }
+ });
+ dojo.declare("tests._base.declare.mixin17", tests._base.declare.mixin16, {
+ bar: function(){
+ this.inherited(arguments);
+ this.foo += ".mixin17";
+ }
+ });
+ dojo.declare("tests._base.declare.tmp17", [tests._base.declare.tmp16, tests._base.declare.mixin17], {
+ bar: function(){
+ this.inherited(arguments);
+ this.foo += ".tmp17";
+ }
+ });
+ var tmp = new tests._base.declare.tmp17();
+ tmp.bar();
+ t.is("tmp16.mixin16.mixin17.tmp17", tmp.foo);
+ },
+ function mixinPreamble(t){
+ var passed = false;
+ dojo.declare("tests._base.declare.tmp16");
+ new tests._base.declare.tmp16({ preamble: function(){ passed = true; } });
+ t.t(passed);
+ }
+ // FIXME: there are still some permutations to test like:
+ // - ctor arguments
+ // - multi-level inheritance + L/R conflict checks
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/_base/fx.html b/includes/js/dojo/tests/_base/fx.html
new file mode 100644
index 0000000..2ef751c
--- /dev/null
+++ b/includes/js/dojo/tests/_base/fx.html
@@ -0,0 +1,342 @@
+<html>
+ <head>
+ <title>testing Core FX</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ src="../../dojo.js"
+ djConfig="isDebug: true"></script>
+ <script type="text/javascript" src="../../_base/fx.js"></script>
+ <script type="text/javascript">
+ var duration = 500;
+ var timeout = 750;
+ dojo.require("doh.runner");
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ {
+ name: "fadeOut",
+ timeout: timeout,
+ runTest: function(){
+ var opacity = dojo.style('foo', 'opacity');
+ doh.is(1, opacity);
+ var anim = dojo.fadeOut({ node: 'foo', duration: duration });
+ var d = new doh.Deferred();
+ dojo.connect(anim, "onEnd", function(){
+ var opacity = dojo.style('foo', 'opacity');
+ var elapsed = (new Date()) - anim._start;
+ doh.is(0, opacity);
+ doh.t(elapsed >= duration);
+ d.callback(true);
+ });
+ anim._start = new Date();
+ anim.play();
+ return d;
+ }
+ },
+ {
+ name: "fadeIn",
+ timeout: timeout,
+ runTest: function(){
+ var opacity = dojo.style('foo', 'opacity');
+ doh.is(0, opacity);
+ var anim = dojo.fadeIn({ node: 'foo', duration: duration });
+ var d = new doh.Deferred();
+ dojo.connect(anim, "onEnd", function(){
+ var opacity = dojo.style('foo', 'opacity');
+ var elapsed = (new Date()) - anim._start;
+ doh.is(1, opacity);
+ doh.t(elapsed >= duration);
+ d.callback(true);
+ });
+ anim._start = new Date();
+ anim.play();
+ return d;
+ }
+ },
+ {
+ name: "animateColor",
+ timeout: timeout,
+ runTest: function(){
+ var d = new doh.Deferred();
+ var anim = dojo.animateProperty({
+ node: "foo",
+ duration: duration,
+ properties: {
+ color: { start: "black", end: "white" },
+ backgroundColor: { start: "white", end: "black" }
+ }
+ });
+ dojo.connect(anim, "onEnd", anim, function(){
+ d.callback(true);
+ });
+ anim.play();
+ return d;
+ }
+ },
+ {
+ name: "animateColorBack",
+ timeout: timeout,
+ runTest: function(){
+ var d = new doh.Deferred();
+ var anim = dojo.animateProperty({
+ node: "foo",
+ duration: duration,
+ properties: {
+ color: { end: "black" },
+ backgroundColor: { end: "#5d81b4" },
+ letterSpacing: { start: 0, end: 10 }
+ }
+ });
+ dojo.connect(anim, "onEnd", anim, function(){
+ d.callback(true);
+ });
+ anim.play();
+ return d;
+ }
+ },
+ {
+ name: "animateHeight",
+ timeout: timeout,
+ runTest: function(t){
+ dojo.byId("foo").style.height = "";
+ var startHeight = dojo.marginBox("foo").h;
+ var endHeight = Math.round(startHeight / 2);
+
+ var anim = dojo.animateProperty({
+ node: "foo",
+ properties: { height: { end: endHeight } },
+ duration: duration
+ });
+
+ var d = new doh.Deferred();
+
+ dojo.connect(anim, "onEnd", anim, function(){
+ var elapsed = (new Date().valueOf()) - anim._startTime;
+ doh.t(elapsed >= duration);
+ var height = dojo.marginBox("foo").h;
+ doh.is(height, endHeight);
+ d.callback(true);
+ });
+
+ anim.play();
+ return d;
+ }
+ },
+ {
+ name: "animateHeight_defaults_syntax",
+ timeout: timeout,
+ runTest: function(){
+ dojo.byId("foo").style.height = "";
+ var startHeight = dojo.marginBox("foo").h;
+ var endHeight = Math.round(startHeight / 2);
+
+ var anim = dojo.animateProperty({
+ node: "foo",
+ properties: { height: endHeight },
+ duration: duration
+ });
+
+ var d = new doh.Deferred();
+
+ dojo.connect(anim, "onEnd", anim, function(){
+ var elapsed = (new Date().valueOf()) - anim._startTime;
+ doh.t(elapsed >= duration);
+ var height = dojo.marginBox("foo").h;
+ doh.is(height, endHeight);
+ d.callback(true);
+ });
+
+ anim.play();
+ return d;
+ }
+ },
+ {
+ name: "inlineWidth",
+ timeout: timeout,
+ runTest: function(){
+ dojo.style("foo", "display", "none");
+ dojo.style("bar", "display", "");
+ var startWidth = dojo.marginBox("bar").w;
+ var endWidth = Math.round(startWidth / 2);
+
+ var anim = dojo.animateProperty({
+ node: "bar",
+ properties: { width: endWidth },
+ duration: duration
+ });
+
+ var d = new doh.Deferred();
+
+ dojo.connect(anim, "onEnd", anim, function(){
+ var elapsed = (new Date().valueOf()) - anim._startTime;
+ doh.t(elapsed >= duration);
+ doh.is(dojo.marginBox("bar").w, endWidth);
+ d.callback(true);
+ });
+
+ anim.play();
+ return d;
+ }
+ },
+ {
+ name: "anim",
+ timeout: timeout+500,
+ runTest: function(){
+ var id = "baz";
+ dojo.style("bar", "display", "none");
+ dojo.style(id, "display", "");
+ var kickoff = new Date().valueOf();
+ var startWidth = dojo.marginBox(id).w;
+ var endWidth = Math.round(startWidth / 2);
+
+ var d = new doh.Deferred();
+ var anim = dojo.anim(
+ id,
+ {
+ width: endWidth,
+ opacity: 0
+ },
+ duration,
+ null,
+ function(){
+ var elapsed = (new Date().valueOf()) - anim._startTime;
+ doh.t(elapsed >= duration);
+ doh.t((new Date().valueOf()) >= (kickoff+duration+500));
+ doh.is(dojo.marginBox(id).w, endWidth);
+ doh.is(dojo.style(id, "opacity"), 0);
+ d.callback(true);
+ },
+ 500
+ );
+ return d;
+ }
+ },
+ {
+ name: "anim_defaults",
+ timeout: 1000,
+ runTest: function(){
+ var id = "thud";
+ dojo.style("baz", "display", "none");
+ dojo.style(id, "display", "");
+ var startWidth = dojo.marginBox(id).w;
+ var endWidth = Math.round(startWidth / 2);
+
+ var d = new doh.Deferred();
+ var anim = dojo.anim(id, { width: endWidth });
+ dojo.connect(anim, "onEnd", function(){
+ var elapsed = (new Date().valueOf()) - anim._startTime;
+ doh.t(elapsed >= dojo._Animation.prototype.duration); // the default
+ doh.is(dojo.marginBox(id).w, endWidth);
+ d.callback(true);
+ });
+ return d;
+ }
+ }
+ ]
+ );
+ doh.run();
+ });
+ </script>
+ <style type="text/css">
+ body {
+ margin: 1em;
+ background-color: #DEDEDE;
+ }
+
+ .box {
+ color: #292929;
+ /* color: #424242; */
+ /* text-align: left; */
+ width: 300px;
+ border: 1px solid #BABABA;
+ background-color: white;
+ padding-left: 10px;
+ padding-right: 10px;
+ margin-left: 10px;
+ -o-border-radius: 10px;
+ -moz-border-radius: 12px;
+ -webkit-border-radius: 10px;
+ /* -opera-border-radius: 10px; */
+ border-radius: 10px;
+ -moz-box-sizing: border-box;
+ -opera-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -khtml-box-sizing: border-box;
+ box-sizing: border-box;
+ overflow: hidden;
+ /* position: absolute; */
+ }
+ </style>
+ </head>
+ <body>
+ <h1>testing Core FX</h1>
+ <form name="testForm">
+ <input type="button" onClick="dojo.fadeOut({ node: 'foo', duration: 1000 }).play()" value="fade out"></input>
+ <input type="button" onClick="dojo.fadeIn({ node: 'foo', duration: 1000 }).play()" value="fade in"></input>
+ </form>
+ <div id="foo" class="box" style="float: left;">
+ <p>
+ 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.
+ </p>
+ <p>
+ 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.
+ </p>
+ </div>
+ <p id="bar" style="display: none;">
+ 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.
+ </p>
+ <p id="baz" style="display: none;">
+ 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.
+ </p>
+ <p id="thud" style="display: none;">
+ 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.
+ </p>
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/fx.js b/includes/js/dojo/tests/_base/fx.js
new file mode 100644
index 0000000..acb1ca3
--- /dev/null
+++ b/includes/js/dojo/tests/_base/fx.js
@@ -0,0 +1,8 @@
+if(!dojo._hasResource["tests._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base.fx"] = true;
+dojo.provide("tests._base.fx");
+if(dojo.isBrowser){
+ doh.registerUrl("tests._base.fx", dojo.moduleUrl("tests", "_base/fx.html"), 15000);
+}
+
+}
diff --git a/includes/js/dojo/tests/_base/fx_delay.html b/includes/js/dojo/tests/_base/fx_delay.html
new file mode 100644
index 0000000..c2a1cd9
--- /dev/null
+++ b/includes/js/dojo/tests/_base/fx_delay.html
@@ -0,0 +1,22 @@
+<html>
+<head>
+<style type="text/css">
+#inner { width: 200px; height: 200px; background-color: #484}
+</style>
+<script type="text/javascript" src="../../dojo.js"></script>
+<script type="text/javascript">
+dojo.require("dojo._base.fx");
+dojo.require("dojo._base.html");
+dojo.addOnLoad(function(){
+ var box = dojo.byId("box");
+ dojo.connect(box, "onclick", function(){
+ dojo.style(box, "opacity", "0");
+ dojo.fadeIn({node:box, delay:1}).play();
+ });
+});
+</script>
+</head>
+<body>
+<div id="box"><button id="inner">click me</button></div>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/_base/html.html b/includes/js/dojo/tests/_base/html.html
new file mode 100644
index 0000000..912c8a6
--- /dev/null
+++ b/includes/js/dojo/tests/_base/html.html
@@ -0,0 +1,556 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<!--
+ we use a strict-mode DTD to ensure that the box model is the same for these
+ basic tests
+-->
+<html>
+ <head>
+ <title>testing Core HTML/DOM/CSS/Style utils</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ src="../../dojo.js"
+ djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+
+ function getIframeDocument(/*DOMNode*/iframeNode){
+ //summary: Returns the document object associated with the iframe DOM Node argument.
+ var doc = iframeNode.contentDocument || // W3
+ (
+ (iframeNode.contentWindow)&&(iframeNode.contentWindow.document)
+ ) || // IE
+ (
+ (iframeNode.name)&&(documendoh.frames[iframeNode.name])&&
+ (documendoh.frames[iframeNode.name].document)
+ ) || null;
+ return doc;
+ }
+
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ "doh.is(100, dojo.marginBox('sq100').w);",
+ "doh.is(100, dojo.marginBox('sq100').h);",
+
+ "doh.is(120, dojo.marginBox('sq100margin10').w);",
+ "doh.is(120, dojo.marginBox('sq100margin10').h);",
+ "doh.is(100, dojo.contentBox('sq100margin10').w);",
+ "doh.is(100, dojo.contentBox('sq100margin10').h);",
+
+ "doh.is(140, dojo.marginBox('sq100margin10pad10').w);",
+ "doh.is(140, dojo.marginBox('sq100margin10pad10').h);",
+
+ "doh.is(120, dojo.marginBox('sq100pad10').w);",
+ "doh.is(120, dojo.marginBox('sq100pad10').h);",
+
+ "doh.is(110, dojo.marginBox('sq100ltpad10').w);",
+ "doh.is(110, dojo.marginBox('sq100ltpad10').h);",
+ "doh.is(100, dojo.contentBox('sq100ltpad10').w);",
+ "doh.is(100, dojo.contentBox('sq100ltpad10').h);",
+
+ "doh.is(120, dojo.marginBox('sq100ltpad10rbmargin10').w);",
+ "doh.is(120, dojo.marginBox('sq100ltpad10rbmargin10').h);",
+
+ "doh.is(120, dojo.marginBox('sq100border10').w);",
+ "doh.is(120, dojo.marginBox('sq100border10').h);",
+ "doh.is(100, dojo.contentBox('sq100border10').w);",
+ "doh.is(100, dojo.contentBox('sq100border10').h);",
+
+ "doh.is(140, dojo.marginBox('sq100border10margin10').w);",
+ "doh.is(140, dojo.marginBox('sq100border10margin10').h);",
+ "doh.is(100, dojo.contentBox('sq100border10margin10').w);",
+ "doh.is(100, dojo.contentBox('sq100border10margin10').h);",
+
+ "doh.is(160, dojo.marginBox('sq100border10margin10pad10').w);",
+ "doh.is(160, dojo.marginBox('sq100border10margin10pad10').h);",
+ "doh.is(100, dojo.contentBox('sq100border10margin10pad10').w);",
+ "doh.is(100, dojo.contentBox('sq100border10margin10pad10').h);",
+
+ // FIXME: the 'correct' w is not 100 on Safari WebKit (2.0.4 [419.3]), the right-margin extends to the document edge
+ // "doh.is(100, dojo.marginBox('sq100nopos').w);",
+ "doh.is(100, dojo.marginBox('sq100nopos').h);",
+
+ "doh.is(10, dojo._getPadExtents(dojo.byId('sq100ltpad10rbmargin10')).l);",
+ "doh.is(10, dojo._getPadExtents(dojo.byId('sq100ltpad10rbmargin10')).t);",
+ "doh.is(10, dojo._getPadExtents(dojo.byId('sq100ltpad10rbmargin10')).w);",
+ "doh.is(10, dojo._getPadExtents(dojo.byId('sq100ltpad10rbmargin10')).h);",
+
+ "doh.is(0, dojo._getMarginExtents(dojo.byId('sq100ltpad10rbmargin10')).l);",
+ "doh.is(0, dojo._getMarginExtents(dojo.byId('sq100ltpad10rbmargin10')).t);",
+ "doh.is(10, dojo._getMarginExtents(dojo.byId('sq100ltpad10rbmargin10')).w);",
+ "doh.is(10, dojo._getMarginExtents(dojo.byId('sq100ltpad10rbmargin10')).h);",
+
+ "doh.is(10, dojo._getBorderExtents(dojo.byId('sq100border10margin10pad10')).l);",
+ "doh.is(10, dojo._getBorderExtents(dojo.byId('sq100border10margin10pad10')).t);",
+ "doh.is(20, dojo._getBorderExtents(dojo.byId('sq100border10margin10pad10')).w);",
+ "doh.is(20, dojo._getBorderExtents(dojo.byId('sq100border10margin10pad10')).h);",
+
+ "doh.is(20, dojo._getPadBorderExtents(dojo.byId('sq100border10margin10pad10')).l);",
+ "doh.is(20, dojo._getPadBorderExtents(dojo.byId('sq100border10margin10pad10')).t);",
+ "doh.is(40, dojo._getPadBorderExtents(dojo.byId('sq100border10margin10pad10')).w);",
+ "doh.is(40, dojo._getPadBorderExtents(dojo.byId('sq100border10margin10pad10')).h);",
+
+ function coordsBasic(t){
+ var pos = dojo.coords("sq100", false);
+ // console.debug(pos);
+ doh.is(100, pos.x);
+ doh.is(100, pos.y);
+ doh.is(100, pos.w);
+ doh.is(100, pos.h);
+ },
+ function coordsMargin(t){
+ // coords is getting us the margin-box location, is
+ // this right?
+ var pos = dojo.coords("sq100margin10", false);
+ doh.is(260, pos.x);
+ doh.is(110, pos.y);
+ doh.is(120, pos.w);
+ doh.is(120, pos.h);
+ },
+ function coordsBorder(t){
+ var pos = dojo.coords("sq100border10", false);
+ doh.is(100, pos.x);
+ doh.is(400, pos.y);
+ },
+ function sq100nopos(t){
+ var pos = dojo.coords("sq100nopos", false);
+ // console.debug(pos);
+ doh.is(0, pos.x);
+ doh.t(pos.y > 0);
+ // FIXME: the 'correct' w is not 100 on Safari WebKit (2.0.4 [419.3]), the right-margin extends to the document edge
+ // doh.is(100, pos.w);
+ doh.is(100, pos.h);
+ },
+ function coordsScrolled(t) {
+ var s = document.createElement('div');
+ var c = document.createElement('div');
+ document.body.appendChild(s);
+ s.appendChild(c);
+ var x=257, y= 285;
+ with (s.style) {
+ position = 'absolute';
+ overflow = 'scroll';
+ border = "10px solid black";
+ }
+ dojo._setMarginBox(s, x, y, 100, 100);
+ dojo._setMarginBox(c, 0, 0, 500, 500);
+ s.scrollTop = 200;
+ var pos = dojo.coords(s, true);
+ doh.is(x, pos.x);
+ doh.is(y, pos.y);
+ },
+ "doh.is(1, dojo.style('sq100nopos', 'opacity'));",
+ "doh.is(0.1, dojo.style('sq100nopos', 'opacity', 0.1));",
+ "doh.is(0.8, dojo.style('sq100nopos', 'opacity', 0.8));",
+ function styleObject(){
+ dojo.style('sq100nopos', { 'opacity': 0.1 });
+ doh.is(0.1, dojo.style('sq100nopos', 'opacity'));
+ dojo.style('sq100nopos', { 'opacity': 0.8 });
+ doh.is(0.8, dojo.style('sq100nopos', 'opacity'));
+ },
+ "doh.is('static', dojo.style('sq100nopos', 'position'));",
+ function getBgcolor(t){
+ var bgc = dojo.style('sq100nopos', 'backgroundColor');
+ doh.t((bgc == "rgb(0, 0, 0)")||(bgc == "black")||(bgc == "#000000"));
+ },
+ function isDescendant(t){
+ doh.t(dojo.isDescendant("sq100", dojo.body()));
+ doh.t(dojo.isDescendant("sq100", dojo.doc));
+ doh.t(dojo.isDescendant("sq100", "sq100"));
+ doh.t(dojo.isDescendant(dojo.byId("sq100"), "sq100"));
+ doh.f(dojo.isDescendant("sq100", dojo.byId("sq100").firstChild));
+ doh.t(dojo.isDescendant(dojo.byId("sq100").firstChild, "sq100"));
+ },
+ function isDescendantIframe(t){
+ var bif = dojo.byId("blah");
+ getIframeDocument(bif).write("<html><body><div id='subDiv'></div></body></html>");
+ getIframeDocument(bif).close();
+ // this test barely makes sense. disabling it for now.
+ // doh.t(dojo.isDescendant(bif.contentDocument.getElementById("subDiv"), bif.parentNode));
+ var subDiv = getIframeDocument(bif).getElementById("subDiv");
+ doh.t(dojo.isDescendant(subDiv, subDiv));
+ doh.t(dojo.isDescendant(subDiv, subDiv.parentNode));
+ doh.f(dojo.isDescendant(subDiv.parentNode, subDiv));
+
+ },
+ function testClassFunctions(t){
+ var node = dojo.byId("sq100");
+ dojo.addClass(node, "a");
+ doh.is("a", node.className);
+ dojo.removeClass(node, "c");
+ doh.is("a", node.className);
+ t.assertTrue(dojo.hasClass(node, "a"));
+ t.assertFalse(dojo.hasClass(node, "b"));
+ dojo.addClass(node, "b");
+ doh.is("a b", node.className);
+ t.assertTrue(dojo.hasClass(node, "a"));
+ t.assertTrue(dojo.hasClass(node, "b"));
+ dojo.removeClass(node, "a");
+ doh.is("b", node.className);
+ t.assertFalse(dojo.hasClass(node, "a"));
+ t.assertTrue(dojo.hasClass(node, "b"));
+ dojo.toggleClass(node, "a");
+ doh.is("b a", node.className);
+ t.assertTrue(dojo.hasClass(node, "a"));
+ t.assertTrue(dojo.hasClass(node, "b"));
+ dojo.toggleClass(node, "a");
+ doh.is("b", node.className);
+ t.assertFalse(dojo.hasClass(node, "a"));
+ t.assertTrue(dojo.hasClass(node, "b"));
+ dojo.toggleClass(node, "b");
+ doh.is("", node.className);
+ t.assertFalse(dojo.hasClass(node, "a"));
+ t.assertFalse(dojo.hasClass(node, "b"));
+ dojo.removeClass(node, "c");
+ t.assertTrue(!node.className);
+ },
+ function getTypeInput(t){
+ doh.f(dojo.hasAttr(dojo.byId("input-no-type"), "type"));
+ doh.is("text", dojo.attr(dojo.byId("input-no-type"), "type"));
+ doh.t(dojo.hasAttr(dojo.byId("input-with-type"), "type"));
+ doh.is("checkbox", dojo.attr(dojo.byId("input-with-type"), "type"));
+ },
+ function getWithString(t){
+ doh.f(dojo.hasAttr("input-no-type", "type"));
+ doh.is("text", dojo.attr("input-no-type", "type"));
+ doh.t(dojo.hasAttr("input-with-type", "type"));
+ doh.is("checkbox", dojo.attr("input-with-type", "type"));
+ },
+ function attrId(t){
+ doh.t(dojo.hasAttr("div-no-tabindex", "id"));
+ doh.is("div-no-tabindex", dojo.attr("div-no-tabindex", "id"));
+ var div = document.createElement("div");
+ doh.f(dojo.hasAttr(div, "id"));
+ doh.is(null, dojo.attr(div, "id"));
+ dojo.attr(div, "id", "attrId1");
+ doh.t(dojo.hasAttr(div, "id"));
+ doh.is("attrId1", dojo.attr(div, "id"));
+ dojo.removeAttr(div, "id");
+ doh.f(dojo.hasAttr(div, "id"));
+ doh.is(null, dojo.attr(div, "id"));
+ },
+ function getTabindexDiv(t){
+ doh.f(dojo.hasAttr("div-no-tabindex", "tabindex"));
+ doh.is(null, dojo.attr("div-no-tabindex", "tabindex"));
+ doh.t(dojo.hasAttr("div-tabindex-minus-1", "tabindex"));
+ if(!dojo.isOpera){
+ // Opera (at least <= 9) does not support tabindex="-1"
+ doh.is(-1, dojo.attr("div-tabindex-minus-1", "tabindex"));
+ }
+ doh.t(dojo.hasAttr("div-tabindex-0", "tabindex"));
+ doh.is(0, dojo.attr("div-tabindex-0", "tabindex"));
+ doh.is(1, dojo.attr("div-tabindex-1", "tabindex"));
+ },
+ function getTabindexInput(t){
+ doh.f(dojo.hasAttr("input-no-tabindex", "tabindex"));
+ doh.is(null, dojo.attr("input-no-tabindex", "tabindex"));
+ doh.t(dojo.hasAttr("input-tabindex-minus-1", "tabindex"));
+ if(!dojo.isOpera){
+ // Opera (at least <= 9) does not support tabindex="-1"
+ doh.is(-1, dojo.attr("input-tabindex-minus-1", "tabindex"));
+ }
+ doh.t(dojo.hasAttr("input-tabindex-0", "tabindex"));
+ doh.is(0, dojo.attr("input-tabindex-0", "tabindex"));
+ doh.is(1, dojo.attr("input-tabindex-1", "tabindex"));
+ },
+ function setTabindexDiv(t){
+ var div = document.createElement("div");
+ doh.is(null, dojo.attr(div, "tabindex"));
+ dojo.attr(div, "tabindex", -1);
+ if(!dojo.isOpera){
+ // Opera (at least <= 9) does not support tabindex="-1"
+ doh.is(-1, dojo.attr(div, "tabindex"));
+ }
+ dojo.attr(div, "tabindex", 0);
+ doh.is(0, dojo.attr(div, "tabindex"));
+ dojo.attr(div, "tabindex", 1);
+ doh.is(1, dojo.attr(div, "tabindex"));
+ },
+ function setTabindexInput(t){
+ var input = document.createElement("input");
+ doh.is(null, dojo.attr(input, "tabindex"));
+ dojo.attr(input, "tabindex", -1);
+ if(!dojo.isOpera){
+ // Opera (at least <= 9) does not support tabindex="-1"
+ doh.is(-1, dojo.attr(input, "tabindex"));
+ }
+ dojo.attr(input, "tabindex", 0);
+ doh.is(0, dojo.attr(input, "tabindex"));
+ dojo.attr(input, "tabindex", 1);
+ doh.is(1, dojo.attr(input, "tabindex"));
+ },
+ function removeTabindexFromDiv(t){
+ var div = document.createElement("div");
+ dojo.attr(div, "tabindex", 1);
+ doh.is(1, dojo.attr(div, "tabindex"));
+ dojo.removeAttr(div, "tabindex");
+ doh.is(null, dojo.attr(div, "tabindex"));
+ },
+ function removeTabindexFromInput(t){
+ var input = document.createElement("input");
+ dojo.attr(input, "tabindex", 1);
+ doh.is(1, dojo.attr(input, "tabindex"));
+ dojo.removeAttr(input, "tabindex");
+ doh.is(null, dojo.attr(input, "tabindex"));
+ },
+ function attr_map(t){
+ var input = document.createElement("input");
+ var ctr= 0;
+ dojo.attr(input, {
+ "tabindex": 1,
+ "type": "text",
+ "onfocus": function(e){
+ ctr++;
+ }
+ });
+ dojo.body().appendChild(input);
+ doh.is(1, dojo.attr(input, "tabindex"));
+ doh.is("text", dojo.attr(input, "type"));
+ doh.is(0, ctr);
+ var def = new doh.Deferred();
+ input.focus();
+ setTimeout(function(){
+ doh.is(1, ctr);
+ input.blur();
+ input.focus();
+ setTimeout(function(){
+ doh.is(2, ctr);
+ def.callback(true);
+ }, 10);
+ }, 10);
+ return def;
+ },
+ function attr_reconnect(t){
+ var input = document.createElement("input");
+ var ctr = 0;
+ dojo.attr(input, "type", "text");
+ dojo.attr(input, "onfocus", function(e){ ctr++; });
+ dojo.attr(input, "onfocus", function(e){ ctr++; });
+ dojo.attr(input, "onfocus", function(e){ ctr++; });
+ dojo.body().appendChild(input);
+ doh.is("text", dojo.attr(input, "type"));
+ doh.is(0, ctr);
+ var def = new doh.Deferred();
+ input.focus();
+ setTimeout(function(){
+ doh.is(1, ctr);
+ input.blur();
+ input.focus();
+ setTimeout(function(){
+ doh.is(2, ctr);
+ def.callback(true);
+ }, 10);
+ }, 10);
+ return def;
+ }
+ ]
+ );
+ doh.run();
+ });
+ </script>
+ <style type="text/css">
+ html, body {
+ padding: 0px;
+ margin: 0px;
+ border: 0px;
+ }
+
+ #sq100 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 100px;
+ top: 100px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding: 0px;
+ margin: 0px;
+ overflow: hidden;
+ }
+
+ #sq100margin10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 250px;
+ top: 100px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding: 0px;
+ margin: 10px;
+ overflow: hidden;
+ }
+
+ #sq100margin10pad10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 400px;
+ top: 100px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding: 10px;
+ margin: 10px;
+ overflow: hidden;
+ }
+
+ #sq100pad10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 100px;
+ top: 250px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding: 10px;
+ margin: 0px;
+ overflow: hidden;
+ }
+
+ #sq100ltpad10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 250px;
+ top: 250px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding-left: 10px;
+ padding-top: 10px;
+ padding-right: 0px;
+ padding-bottom: 0px;
+ margin: 0px;
+ overflow: hidden;
+ }
+
+ #sq100ltpad10rbmargin10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 400px;
+ top: 250px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding-left: 10px;
+ padding-top: 10px;
+ padding-right: 0px;
+ padding-bottom: 0px;
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-right: 10px;
+ margin-bottom: 10px;
+ overflow: hidden;
+ }
+
+ #sq100border10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 100px;
+ top: 400px;
+ width: 100px;
+ height: 100px;
+ border: 10px solid yellow;
+ padding: 0px;
+ margin: 0px;
+ overflow: hidden;
+ }
+
+ #sq100border10margin10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 250px;
+ top: 400px;
+ width: 100px;
+ height: 100px;
+ border: 10px solid yellow;
+ padding: 0px;
+ margin: 10px;
+ overflow: hidden;
+ }
+
+ #sq100border10margin10pad10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 400px;
+ top: 400px;
+ width: 100px;
+ height: 100px;
+ border: 10px solid yellow;
+ padding: 10px;
+ margin: 10px;
+ overflow: hidden;
+ }
+
+ #sq100nopos {
+ background-color: black;
+ color: white;
+ width: 100px;
+ height: 100px;
+ padding: 0px;
+ margin: 0px;
+ }
+
+ </style>
+ </head>
+ <body>
+ <h1>testing Core HTML/DOM/CSS/Style utils</h1>
+ <div id="sq100">
+ 100px square, abs
+ </div>
+ <div id="sq100margin10">
+ 100px square, abs, 10px margin
+ </div>
+ <div id="sq100margin10pad10">
+ 100px square, abs, 10px margin, 10px padding
+ </div>
+ <div id="sq100pad10">
+ 100px square, abs, 10px padding
+ </div>
+ <div id="sq100ltpad10">
+ 100px square, abs, 10px left and top padding
+ </div>
+ <div id="sq100ltpad10rbmargin10">
+ 100px square, abs, 10px left and top padding, 10px bottom and right margin
+ </div>
+ <div id="sq100border10">
+ 100px square, abs, 10px yellow border
+ </div>
+ <div id="sq100border10margin10">
+ 100px square, abs, 10px yellow border, 10px margin
+ </div>
+ <div id="sq100border10margin10pad10">
+ 100px square, abs, 10px yellow border, 10px margin, 10px padding
+ </div>
+ <div id="sq100nopos">
+ 100px square, no positioning
+ </div>
+ <iframe id="blah"></iframe>
+
+ <div id="div-no-tabindex"></div>
+ <div id="div-tabindex-minus-1" tabindex="-1"></div>
+ <div id="div-tabindex-0" tabindex="0"></div>
+ <div id="div-tabindex-1" tabindex="1"></div>
+
+ <div>
+ <input id="input-no-type">
+ <input id="input-with-type" type="checkbox">
+ <input id="input-no-tabindex">
+ <input id="input-tabindex-minus-1" tabindex="-1">
+ <input id="input-tabindex-0" tabindex="0">
+ <input id="input-tabindex-1" tabindex="1">
+ </div>
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/html.js b/includes/js/dojo/tests/_base/html.js
new file mode 100644
index 0000000..99fe80b
--- /dev/null
+++ b/includes/js/dojo/tests/_base/html.js
@@ -0,0 +1,12 @@
+if(!dojo._hasResource["tests._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base.html"] = true;
+dojo.provide("tests._base.html");
+if(dojo.isBrowser){
+ doh.registerUrl("tests._base.html", dojo.moduleUrl("tests", "_base/html.html"), 15000);
+ doh.registerUrl("tests._base.html_rtl", dojo.moduleUrl("tests", "_base/html_rtl.html"), 15000);
+ doh.registerUrl("tests._base.html_quirks", dojo.moduleUrl("tests", "_base/html_quirks.html"), 15000);
+ doh.registerUrl("tests._base.html_box", dojo.moduleUrl("tests", "_base/html_box.html"), 35000);
+ doh.registerUrl("tests._base.html_box_quirks", dojo.moduleUrl("tests", "_base/html_box_quirks.html"), 35000);
+}
+
+}
diff --git a/includes/js/dojo/tests/_base/html_box.html b/includes/js/dojo/tests/_base/html_box.html
new file mode 100644
index 0000000..fd7ec53
--- /dev/null
+++ b/includes/js/dojo/tests/_base/html_box.html
@@ -0,0 +1,207 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!--
+ we use a strict-mode DTD to ensure that the box model is the same for these
+ basic tests
+-->
+<html>
+ <head>
+ <title> test html.js Box utils</title>
+ <style type="text/css">
+ /*@import "../../resources/dojo.css";*/
+ </style>
+ <script type="text/javascript"
+ src="../../dojo.js"
+ djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+
+ var margin = '1px';
+ var border = '3px solid black';
+ var padding = '5px';
+ var defaultStyles = {
+ height: '100px',
+ width: '100px',
+ position: 'absolute',
+ backgroundColor: 'red'
+ };
+
+ var defaultChildStyles = {
+ height: '20px',
+ width: '20px',
+ backgroundColor: 'blue'
+ }
+
+ var testStyles = [
+ {},
+ {margin: margin},
+ {border: border},
+ {padding: padding},
+ {margin: margin, border: border},
+ {margin: margin, padding: padding},
+ {border: border, padding: padding},
+ {margin: margin, border: border, padding: padding}
+ ]
+
+
+ function sameBox(inBox1, inBox2) {
+ for (var i in inBox1)
+ if (inBox1[i] != inBox2[i]) {
+ console.log((arguments[2]||'box1') + '.' + i + ': ', inBox1[i], ' != ', (arguments[3]||'box2') + '.' + i + ': ', inBox2[i]);
+ return false;
+ }
+ return true;
+ }
+
+ function reciprocalMarginBoxTest(inNode, inBox) {
+ var s = inBox || dojo.marginBox(inNode);
+ dojo.marginBox(inNode, s);
+ var e = dojo.marginBox(inNode);
+ return sameBox(s, e);
+ }
+
+ function fitTest(inParent, inChild) {
+ var pcb = dojo.contentBox(inParent);
+ return reciprocalMarginBoxTest(inChild, pcb);
+ }
+
+ function createStyledElement(inStyle, inParent, inElement, inNoDefault) {
+ inStyle = inStyle||{};
+ if (!inNoDefault) {
+ for (var i in defaultStyles)
+ if (!inStyle[i])
+ inStyle[i] = defaultStyles[i];
+ }
+ var n = document.createElement(inElement || 'div');
+ (inParent||document.body).appendChild(n);
+ dojo.mixin(n.style, inStyle);
+ return n;
+ }
+
+ var _testTopInc = 0;
+ var _testTop = 150;
+ var _testInitTop = 250;
+ function styleIncTop(inStyle) {
+ inStyle = dojo.mixin({}, inStyle||{});
+ inStyle.top = (_testInitTop + _testTop*_testTopInc) + 'px';
+ _testTopInc++;
+ return inStyle;
+ }
+
+ function removeTestNode(inNode) {
+ // leave nodes for inspection or don't return to delete them
+ return;
+ inNode = dojo.byId(inNode);
+ inNode.parentNode.removeChild(inNode);
+ _testTopInc--;
+ }
+
+ function testAndCallback(inTest, inAssert, inComment, inOk, inErr) {
+ inTest.assertTrue('/* ' + inComment + '*/' + inAssert);
+ if (inAssert)
+ inOk&&inOk();
+ else
+ inErr&&inErr();
+ }
+
+ // args are (styles, parent, element name, no default)
+ function mixCreateElementArgs(inMix, inArgs) {
+ args = [{}];
+ if (inArgs&&inArgs[0])
+ dojo.mixin(args[0], inArgs[0]);
+ if (inMix.length)
+ dojo.mixin(args[0], inMix[0]||{});
+ // parent comes from source
+ if (inMix.length > 1)
+ args[1] = inMix[1];
+ args[2] = inArgs[2];
+ args[3] = inArgs[3]
+ return args;
+ };
+
+ function createStyledNodes(inArgs, inFunc) {
+ for (var i=0, n; (s=testStyles[i]); i++) {
+ n = createStyledElement.apply(this, mixCreateElementArgs([styleIncTop(s)], inArgs));
+ inFunc&&inFunc(n);
+ }
+ }
+
+ function createStyledParentChild(inParentArgs, inChildArgs, inFunc) {
+ for (var i=0, s, p, c; (s=testStyles[i]); i++) {
+ p = createStyledElement.apply(this, mixCreateElementArgs([styleIncTop(s)], inParentArgs));
+ c = createStyledElement.apply(this, mixCreateElementArgs([{}, p], inChildArgs));
+ inFunc&&inFunc(p, c);
+ }
+ }
+
+ function createStyledParentChildren(inParentArgs, inChildArgs, inFunc) {
+ for (var i=0, s, p; (s=testStyles[i]); i++)
+ for (var j=0, sc, c, props; (sc=testStyles[j]); j++) {
+ p = createStyledElement.apply(this, mixCreateElementArgs([styleIncTop(s)], inParentArgs));
+ c = createStyledElement.apply(this, mixCreateElementArgs([sc, p], inChildArgs));
+ inFunc&&inFunc(p, c);
+ }
+
+ for (var i=0, s, p, c; (s=testStyles[i]); i++) {
+ p = createStyledElement.apply(this, mixCreateElementArgs([styleIncTop(s)], inParentArgs));
+ c = createStyledElement.apply(this, mixCreateElementArgs([{}, p], inChildArgs));
+ inFunc&&inFunc(p, c);
+ }
+ }
+
+
+ function runFitTest(inTest, inParentStyles, inChildStyles) {
+ createStyledParentChildren([inParentStyles], [inChildStyles], function(p, c) {
+ testAndCallback(inTest, fitTest(p, c), '', function() {removeTestNode(p); });
+ });
+ }
+
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ function reciprocalTests(t) {
+ createStyledNodes([], function(n) {
+ testAndCallback(t, reciprocalMarginBoxTest(n), '', function() {removeTestNode(n); });
+ });
+ },
+ function fitTests(t) {
+ runFitTest(t, null, dojo.mixin({}, defaultChildStyles));
+ },
+ function fitTestsOverflow(t) {
+ runFitTest(t, null, dojo.mixin({overflow:'hidden'}, defaultChildStyles));
+ runFitTest(t, {overflow: 'hidden'}, dojo.mixin({}, defaultChildStyles));
+ runFitTest(t, {overflow: 'hidden'}, dojo.mixin({overflow:'hidden'}, defaultChildStyles));
+ },
+ function fitTestsFloat(t) {
+ runFitTest(t, null, dojo.mixin({float: 'left'}, defaultChildStyles));
+ runFitTest(t, {float: 'left'}, dojo.mixin({}, defaultChildStyles));
+ runFitTest(t, {float: 'left'}, dojo.mixin({float: 'left'}, defaultChildStyles));
+ },
+ function reciprocalTestsInline(t) {
+ createStyledParentChild([], [{}, null, 'span'], function(p, c) {
+ c.innerHTML = 'Hello World';
+ testAndCallback(t, reciprocalMarginBoxTest(c), '', function() {removeTestNode(c); });
+ });
+ },
+ function reciprocalTestsButtonChild(t) {
+ createStyledParentChild([], [{}, null, 'button'], function(p, c) {
+ c.innerHTML = 'Hello World';
+ testAndCallback(t, reciprocalMarginBoxTest(c), '', function() {removeTestNode(c); });
+ });
+ }
+ ]
+ );
+ doh.run();
+ });
+ </script>
+ <style type="text/css">
+ html, body {
+ padding: 0px;
+ margin: 0px;
+ border: 0px;
+ }
+ </style>
+ </head>
+ <body>
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/html_box_quirks.html b/includes/js/dojo/tests/_base/html_box_quirks.html
new file mode 100644
index 0000000..f87ca44
--- /dev/null
+++ b/includes/js/dojo/tests/_base/html_box_quirks.html
@@ -0,0 +1,205 @@
+<!--
+ we use a quirks-mode DTD to check for quirks!
+-->
+<html>
+ <head>
+ <title> test html.js Box utils</title>
+ <style type="text/css">
+ /*@import "../../resources/dojo.css";*/
+ </style>
+ <script type="text/javascript"
+ src="../../dojo.js"
+ djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+
+ var margin = '1px';
+ var border = '3px solid black';
+ var padding = '5px';
+ var defaultStyles = {
+ height: '100px',
+ width: '100px',
+ position: 'absolute',
+ backgroundColor: 'red'
+ };
+
+ var defaultChildStyles = {
+ height: '20px',
+ width: '20px',
+ backgroundColor: 'blue'
+ }
+
+ var testStyles = [
+ {},
+ {margin: margin},
+ {border: border},
+ {padding: padding},
+ {margin: margin, border: border},
+ {margin: margin, padding: padding},
+ {border: border, padding: padding},
+ {margin: margin, border: border, padding: padding}
+ ]
+
+
+ function sameBox(inBox1, inBox2) {
+ for (var i in inBox1)
+ if (inBox1[i] != inBox2[i]) {
+ console.log((arguments[2]||'box1') + '.' + i + ': ', inBox1[i], ' != ', (arguments[3]||'box2') + '.' + i + ': ', inBox2[i]);
+ return false;
+ }
+ return true;
+ }
+
+ function reciprocalMarginBoxTest(inNode, inBox) {
+ var s = inBox || dojo.marginBox(inNode);
+ dojo.marginBox(inNode, s);
+ var e = dojo.marginBox(inNode);
+ return sameBox(s, e);
+ }
+
+ function fitTest(inParent, inChild) {
+ var pcb = dojo.contentBox(inParent);
+ return reciprocalMarginBoxTest(inChild, pcb);
+ }
+
+ function createStyledElement(inStyle, inParent, inElement, inNoDefault) {
+ inStyle = inStyle||{};
+ if (!inNoDefault) {
+ for (var i in defaultStyles)
+ if (!inStyle[i])
+ inStyle[i] = defaultStyles[i];
+ }
+ var n = document.createElement(inElement || 'div');
+ (inParent||document.body).appendChild(n);
+ dojo.mixin(n.style, inStyle);
+ return n;
+ }
+
+ var _testTopInc = 0;
+ var _testTop = 150;
+ var _testInitTop = 250;
+ function styleIncTop(inStyle) {
+ inStyle = dojo.mixin({}, inStyle||{});
+ inStyle.top = (_testInitTop + _testTop*_testTopInc) + 'px';
+ _testTopInc++;
+ return inStyle;
+ }
+
+ function removeTestNode(inNode) {
+ // leave nodes for inspection or don't return to delete them
+ return;
+ inNode = dojo.byId(inNode);
+ inNode.parentNode.removeChild(inNode);
+ _testTopInc--;
+ }
+
+ function testAndCallback(inTest, inAssert, inComment, inOk, inErr) {
+ inTest.assertTrue('/* ' + inComment + '*/' + inAssert);
+ if (inAssert)
+ inOk&&inOk();
+ else
+ inErr&&inErr();
+ }
+
+ // args are (styles, parent, element name, no default)
+ function mixCreateElementArgs(inMix, inArgs) {
+ args = [{}];
+ if (inArgs&&inArgs[0])
+ dojo.mixin(args[0], inArgs[0]);
+ if (inMix.length)
+ dojo.mixin(args[0], inMix[0]||{});
+ // parent comes from source
+ if (inMix.length > 1)
+ args[1] = inMix[1];
+ args[2] = inArgs[2];
+ args[3] = inArgs[3]
+ return args;
+ };
+
+ function createStyledNodes(inArgs, inFunc) {
+ for (var i=0, n; (s=testStyles[i]); i++) {
+ n = createStyledElement.apply(this, mixCreateElementArgs([styleIncTop(s)], inArgs));
+ inFunc&&inFunc(n);
+ }
+ }
+
+ function createStyledParentChild(inParentArgs, inChildArgs, inFunc) {
+ for (var i=0, s, p, c; (s=testStyles[i]); i++) {
+ p = createStyledElement.apply(this, mixCreateElementArgs([styleIncTop(s)], inParentArgs));
+ c = createStyledElement.apply(this, mixCreateElementArgs([{}, p], inChildArgs));
+ inFunc&&inFunc(p, c);
+ }
+ }
+
+ function createStyledParentChildren(inParentArgs, inChildArgs, inFunc) {
+ for (var i=0, s, p; (s=testStyles[i]); i++)
+ for (var j=0, sc, c, props; (sc=testStyles[j]); j++) {
+ p = createStyledElement.apply(this, mixCreateElementArgs([styleIncTop(s)], inParentArgs));
+ c = createStyledElement.apply(this, mixCreateElementArgs([sc, p], inChildArgs));
+ inFunc&&inFunc(p, c);
+ }
+
+ for (var i=0, s, p, c; (s=testStyles[i]); i++) {
+ p = createStyledElement.apply(this, mixCreateElementArgs([styleIncTop(s)], inParentArgs));
+ c = createStyledElement.apply(this, mixCreateElementArgs([{}, p], inChildArgs));
+ inFunc&&inFunc(p, c);
+ }
+ }
+
+
+ function runFitTest(inTest, inParentStyles, inChildStyles) {
+ createStyledParentChildren([inParentStyles], [inChildStyles], function(p, c) {
+ testAndCallback(inTest, fitTest(p, c), '', function() {removeTestNode(p); });
+ });
+ }
+
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ function reciprocalTests(t) {
+ createStyledNodes([], function(n) {
+ testAndCallback(t, reciprocalMarginBoxTest(n), '', function() {removeTestNode(n); });
+ });
+ },
+ function fitTests(t) {
+ runFitTest(t, null, dojo.mixin({}, defaultChildStyles));
+ },
+ function fitTestsOverflow(t) {
+ runFitTest(t, null, dojo.mixin({overflow:'hidden'}, defaultChildStyles));
+ runFitTest(t, {overflow: 'hidden'}, dojo.mixin({}, defaultChildStyles));
+ runFitTest(t, {overflow: 'hidden'}, dojo.mixin({overflow:'hidden'}, defaultChildStyles));
+ },
+ function fitTestsFloat(t) {
+ runFitTest(t, null, dojo.mixin({float: 'left'}, defaultChildStyles));
+ runFitTest(t, {float: 'left'}, dojo.mixin({}, defaultChildStyles));
+ runFitTest(t, {float: 'left'}, dojo.mixin({float: 'left'}, defaultChildStyles));
+ },
+ function reciprocalTestsInline(t) {
+ createStyledParentChild([], [{}, null, 'span'], function(p, c) {
+ c.innerHTML = 'Hello World';
+ testAndCallback(t, reciprocalMarginBoxTest(c), '', function() {removeTestNode(c); });
+ });
+ },
+ function reciprocalTestsButtonChild(t) {
+ createStyledParentChild([], [{}, null, 'button'], function(p, c) {
+ c.innerHTML = 'Hello World';
+ testAndCallback(t, reciprocalMarginBoxTest(c), '', function() {removeTestNode(c); });
+ });
+ }
+ ]
+ );
+ doh.run();
+ });
+ </script>
+ <style type="text/css">
+ html, body {
+ padding: 0px;
+ margin: 0px;
+ border: 0px;
+ }
+ </style>
+ </head>
+ <body>
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/html_quirks.html b/includes/js/dojo/tests/_base/html_quirks.html
new file mode 100644
index 0000000..ddc7825
--- /dev/null
+++ b/includes/js/dojo/tests/_base/html_quirks.html
@@ -0,0 +1,322 @@
+<html>
+ <!--
+ we use a quirks-mode DTD on purpose to ensure that things go tilt. Wheee!!
+ -->
+ <head>
+ <title>testing Core HTML/DOM/CSS/Style utils in quirks mode</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ src="../../dojo.js"
+ djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ "t.is(100, dojo.marginBox('sq100').w);",
+ "t.is(100, dojo.marginBox('sq100').h);",
+
+ "t.is(120, dojo.marginBox('sq100margin10').w);",
+ "t.is(120, dojo.marginBox('sq100margin10').h);",
+ "t.is(100, dojo.contentBox('sq100margin10').w);",
+ "t.is(100, dojo.contentBox('sq100margin10').h);",
+
+ // FIXME: the 'correct' w is not 100 on Safari WebKit (2.0.4 [419.3]), the right-margin extends to the document edge
+ //"t.is(100, dojo.marginBox('sq100nopos').w);",
+ "t.is(100, dojo.marginBox('sq100nopos').h);",
+
+ function coordsBasic(t){
+ var pos = dojo.coords("sq100", false);
+ // console.debug(pos);
+ t.is(100, pos.x);
+ t.is(100, pos.y);
+ t.is(100, pos.w);
+ t.is(100, pos.h);
+ },
+ function coordsMargin(t){
+ // coords is getting us the margin-box location, is
+ // this right?
+ var pos = dojo.coords("sq100margin10", false);
+ t.is(260, pos.x);
+ t.is(110, pos.y);
+ t.is(120, pos.w);
+ t.is(120, pos.h);
+ },
+ function coordsBorder(t){
+ var pos = dojo.coords("sq100border10", false);
+ t.is(100, pos.x);
+ t.is(400, pos.y);
+ },
+ function sq100nopos(t){
+ var pos = dojo.coords("sq100nopos", false);
+ // console.debug(pos);
+ t.is(0, pos.x);
+ t.t(pos.y > 0);
+ // FIXME: the 'correct' w is not 100 on Safari WebKit (2.0.4 [419.3]), the right-margin extends to the document edge
+ //t.is(100, pos.w);
+ t.is(100, pos.h);
+ }
+ ]
+ );
+ if(dojo.isIE){
+ // IE collapses padding in quirks mode. We just report on it.
+ doh.register("t",
+ [
+ "t.is(120, dojo.marginBox('sq100margin10pad10').w);",
+ "t.is(120, dojo.marginBox('sq100margin10pad10').h);",
+
+ "t.is(100, dojo.marginBox('sq100pad10').w);",
+ "t.is(100, dojo.marginBox('sq100pad10').h);",
+
+ "t.is(100, dojo.marginBox('sq100ltpad10').w);",
+ "t.is(100, dojo.marginBox('sq100ltpad10').h);",
+ "t.is(90, dojo.contentBox('sq100ltpad10').w);",
+ "t.is(90, dojo.contentBox('sq100ltpad10').h);",
+
+ "t.is(110, dojo.marginBox('sq100ltpad10rbmargin10').w);",
+ "t.is(110, dojo.marginBox('sq100ltpad10rbmargin10').h);",
+
+ "t.is(100, dojo.marginBox('sq100border10').w);",
+ "t.is(100, dojo.marginBox('sq100border10').h);",
+ "t.is(80, dojo.contentBox('sq100border10').w);",
+ "t.is(80, dojo.contentBox('sq100border10').h);",
+
+ "t.is(120, dojo.marginBox('sq100border10margin10').w);",
+ "t.is(120, dojo.marginBox('sq100border10margin10').h);",
+ "t.is(80, dojo.contentBox('sq100border10margin10').w);",
+ "t.is(80, dojo.contentBox('sq100border10margin10').h);",
+
+ "t.is(120, dojo.marginBox('sq100border10margin10pad10').w);",
+ "t.is(120, dojo.marginBox('sq100border10margin10pad10').h);",
+ "t.is(60, dojo.contentBox('sq100border10margin10pad10').w);",
+ "t.is(60, dojo.contentBox('sq100border10margin10pad10').h);"
+ ]
+ );
+ }else{
+ doh.register("t",
+ [
+ "t.is(140, dojo.marginBox('sq100margin10pad10').w);",
+ "t.is(140, dojo.marginBox('sq100margin10pad10').h);",
+
+ "t.is(120, dojo.marginBox('sq100pad10').w);",
+ "t.is(120, dojo.marginBox('sq100pad10').h);",
+
+ "t.is(110, dojo.marginBox('sq100ltpad10').w);",
+ "t.is(110, dojo.marginBox('sq100ltpad10').h);",
+ "t.is(100, dojo.contentBox('sq100ltpad10').w);",
+ "t.is(100, dojo.contentBox('sq100ltpad10').h);",
+
+ "t.is(120, dojo.marginBox('sq100ltpad10rbmargin10').w);",
+ "t.is(120, dojo.marginBox('sq100ltpad10rbmargin10').h);",
+
+ "t.is(120, dojo.marginBox('sq100border10').w);",
+ "t.is(120, dojo.marginBox('sq100border10').h);",
+ "t.is(100, dojo.contentBox('sq100border10').w);",
+ "t.is(100, dojo.contentBox('sq100border10').h);",
+
+ "t.is(140, dojo.marginBox('sq100border10margin10').w);",
+ "t.is(140, dojo.marginBox('sq100border10margin10').h);",
+ "t.is(100, dojo.contentBox('sq100border10margin10').w);",
+ "t.is(100, dojo.contentBox('sq100border10margin10').h);",
+
+ "t.is(160, dojo.marginBox('sq100border10margin10pad10').w);",
+ "t.is(160, dojo.marginBox('sq100border10margin10pad10').h);",
+ "t.is(100, dojo.contentBox('sq100border10margin10pad10').w);",
+ "t.is(100, dojo.contentBox('sq100border10margin10pad10').h);"
+ ]
+ );
+ }
+
+ doh.run();
+ });
+ </script>
+ <style type="text/css">
+ html, body {
+ padding: 0px;
+ margin: 0px;
+ border: 0px;
+ }
+
+ #sq100 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 100px;
+ top: 100px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding: 0px;
+ margin: 0px;
+ overflow: hidden;
+ }
+
+ #sq100margin10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 250px;
+ top: 100px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding: 0px;
+ margin: 10px;
+ overflow: hidden;
+ }
+
+ #sq100margin10pad10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 400px;
+ top: 100px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding: 10px;
+ margin: 10px;
+ overflow: hidden;
+ }
+
+ #sq100pad10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 100px;
+ top: 250px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding: 10px;
+ margin: 0px;
+ overflow: hidden;
+ }
+
+ #sq100ltpad10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 250px;
+ top: 250px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding-left: 10px;
+ padding-top: 10px;
+ padding-right: 0px;
+ padding-bottom: 0px;
+ margin: 0px;
+ overflow: hidden;
+ }
+
+ #sq100ltpad10rbmargin10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 400px;
+ top: 250px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding-left: 10px;
+ padding-top: 10px;
+ padding-right: 0px;
+ padding-bottom: 0px;
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-right: 10px;
+ margin-bottom: 10px;
+ overflow: hidden;
+ }
+
+ #sq100border10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 100px;
+ top: 400px;
+ width: 100px;
+ height: 100px;
+ border: 10px solid yellow;
+ padding: 0px;
+ margin: 0px;
+ overflow: hidden;
+ }
+
+ #sq100border10margin10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 250px;
+ top: 400px;
+ width: 100px;
+ height: 100px;
+ border: 10px solid yellow;
+ padding: 0px;
+ margin: 10px;
+ overflow: hidden;
+ }
+
+ #sq100border10margin10pad10 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 400px;
+ top: 400px;
+ width: 100px;
+ height: 100px;
+ border: 10px solid yellow;
+ padding: 10px;
+ margin: 10px;
+ overflow: hidden;
+ }
+
+ #sq100nopos {
+ background-color: black;
+ color: white;
+ width: 100px;
+ height: 100px;
+ padding: 0px;
+ margin: 0px;
+ }
+
+ </style>
+ </head>
+ <body>
+ <h1>testing Core HTML/DOM/CSS/Style utils</h1>
+ <div id="sq100">
+ 100px square, abs
+ </div>
+ <div id="sq100margin10">
+ 100px square, abs, 10px margin
+ </div>
+ <div id="sq100margin10pad10">
+ 100px square, abs, 10px margin, 10px padding
+ </div>
+ <div id="sq100pad10">
+ 100px square, abs, 10px padding
+ </div>
+ <div id="sq100ltpad10">
+ 100px square, abs, 10px left and top padding
+ </div>
+ <div id="sq100ltpad10rbmargin10">
+ 100px square, abs, 10px left and top padding, 10px bottom and right margin
+ </div>
+ <div id="sq100border10">
+ 100px square, abs, 10px yellow border
+ </div>
+ <div id="sq100border10margin10">
+ 100px square, abs, 10px yellow border, 10px margin
+ </div>
+ <div id="sq100border10margin10pad10">
+ 100px square, abs, 10px yellow border, 10px margin, 10px padding
+ </div>
+ <div id="sq100nopos">
+ 100px square, no positioning
+ </div>
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/html_rtl.html b/includes/js/dojo/tests/_base/html_rtl.html
new file mode 100644
index 0000000..8d74afa
--- /dev/null
+++ b/includes/js/dojo/tests/_base/html_rtl.html
@@ -0,0 +1,110 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html dir="rtl">
+ <head>
+ <title>testing Core HTML/DOM/CSS/Style utils</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ src="../../dojo.js"
+ djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ function coordsWithVertScrollbar(t){
+ // show vertical scrollbar
+ dojo.byId("rect_vert").style.display = "";
+ try{
+ t.is(100, dojo.coords('rect100').x);
+ }finally{
+ dojo.byId("rect_vert").style.display = "none";
+ }
+ },
+
+ function coordsWithHorzScrollbar(t){
+ // show horizonal scrollbar & scroll a bit left
+ dojo.byId("rect_horz").style.display = "";
+ scrollBy(-50, 0);
+ try{
+ t.is(100, dojo.coords('rect100', true).x);
+ }finally{
+ dojo.byId("rect_horz").style.display = "none";
+ }
+ },
+
+ function eventClientXY(t){ // IE only test
+ if(dojo.isIE){
+ // show vertical scrollbar
+ dojo.byId("rect_vert").style.display = "";
+
+ var rect = dojo.byId("rect100");
+ var assertException = null;
+
+ function rect_onclick(e){
+ // move the rectangle to the mouse point
+ rect.style.left = e.pageX + "px";
+ rect.style.top = e.pageY + "px";
+ window.alert("Do NOT move your mouse!!!\n\n" +
+ "The black rectangle's top-left point should be under the mouse point.\n\n" +
+ "If not, you will see a failure in the test report later.\n\n" +
+ "Now press the space bar, but do NOT move your mouse.");
+ rect.fireEvent('ondblclick');
+ }
+
+ function rect_ondblclick(){
+ // test if the rectangle is really under the mouse point
+ try{
+ t.is(0, event.offsetX);
+ t.is(0, event.offsetY);
+ }catch (e){ // allow the exception in a event handler go to the event firer
+ assertException = e;
+ }
+ }
+
+ dojo.connect(rect, "onclick", null, rect_onclick);
+ dojo.connect(rect, "ondblclick", null, rect_ondblclick);
+ window.alert("Move the mouse to anywhere in this page, and then press the space bar.");
+ rect.fireEvent('onclick');
+ if(assertException != null){
+ throw assertException;
+ }
+ }
+ }
+
+ ]
+ );
+ doh.run();
+ });
+ </script>
+ <style type="text/css">
+ #rect100 {
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 100px;
+ top: 100px;
+ width: 100px;
+ height: 100px;
+ border: 0px;
+ padding: 0px;
+ margin: 0px;
+ overflow: hidden;
+ }
+
+ </style>
+ </head>
+ <body>
+ <h1>testing Core HTML/DOM/CSS/Style utils</h1>
+ <div id="rect100">
+ 100px rect, abs,
+ mouse point is at top-left after the test "eventClientXY"
+ </div>
+ <div id="rect_vert" style="height:1600px;display:none">show vertical scrollbar</div>
+ <div id="rect_horz" style="width:1600px;display:none">show horizonal scrollbar</div>
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/json.js b/includes/js/dojo/tests/_base/json.js
new file mode 100644
index 0000000..3a9a24c
--- /dev/null
+++ b/includes/js/dojo/tests/_base/json.js
@@ -0,0 +1,37 @@
+if(!dojo._hasResource["tests._base.json"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base.json"] = true;
+dojo.provide("tests._base.json");
+
+tests.register("tests._base.json",
+ [
+ //Not testing dojo.toJson() on its own since Rhino will output the object properties in a different order.
+ //Still valid json, but just in a different order than the source string.
+
+ // take a json-compatible object, convert it to a json string, then put it back into json.
+ function toAndFromJson(t){
+ var testObj = {a:"a", b:1, c:"c", d:"d", e:{e1:"e1", e2:2}, f:[1,2,3], g:"g",h:{h1:{h2:{h3:"h3"}}}};
+
+ var mirrorObj = dojo.fromJson(dojo.toJson(testObj));
+ t.assertEqual("a", mirrorObj.a);
+ t.assertEqual(1, mirrorObj.b);
+ t.assertEqual("c", mirrorObj.c);
+ t.assertEqual("d", mirrorObj.d);
+ t.assertEqual("e1", mirrorObj.e.e1);
+ t.assertEqual(2, mirrorObj.e.e2);
+ t.assertEqual(1, mirrorObj.f[0]);
+ t.assertEqual(2, mirrorObj.f[1]);
+ t.assertEqual(3, mirrorObj.f[2]);
+ t.assertEqual("g", mirrorObj.g);
+ t.assertEqual("h3", mirrorObj.h.h1.h2.h3);
+ var badJson;
+ try{
+ badJson = dojo.fromJson("bad json"); // this should throw an exception, and not set badJson
+ }catch(e){
+ }
+ t.assertEqual(undefined,badJson);
+ }
+ ]
+);
+
+
+}
diff --git a/includes/js/dojo/tests/_base/lang.js b/includes/js/dojo/tests/_base/lang.js
new file mode 100644
index 0000000..38acbff
--- /dev/null
+++ b/includes/js/dojo/tests/_base/lang.js
@@ -0,0 +1,180 @@
+if(!dojo._hasResource["tests._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base.lang"] = true;
+dojo.provide("tests._base.lang");
+
+tests.register("tests._base.lang",
+ [
+ function mixin(t){
+ var src = {
+ foo: function(){
+ t.debug("foo");
+ },
+ bar: "bar"
+ };
+ var dest = {};
+ dojo.mixin(dest, src);
+ t.assertEqual("function", typeof dest["foo"]);
+ t.assertEqual("string", typeof dest["bar"]);
+ },
+
+ function extend(t){
+ var src = {
+ foo: function(){
+ t.debug("foo");
+ },
+ bar: "bar"
+ };
+ function dest(){}
+ dojo.extend(dest, src);
+ var test = new dest();
+ t.assertEqual("function", typeof test["foo"]);
+ t.assertEqual("string", typeof test["bar"]);
+ },
+
+ function isObject(t){
+ t.assertFalse(dojo.isObject(true));
+ t.assertFalse(dojo.isObject(false));
+ t.assertFalse(dojo.isObject("foo"));
+ t.assertTrue(dojo.isObject(new String("foo")));
+ t.assertTrue(dojo.isObject(null));
+ t.assertTrue(dojo.isObject({}));
+ t.assertTrue(dojo.isObject([]));
+ t.assertTrue(dojo.isObject(new Array()));
+ },
+
+ function isArray(t){
+ t.assertTrue(dojo.isArray([]));
+ t.assertTrue(dojo.isArray(new Array()));
+ t.assertFalse(dojo.isArray({}));
+ },
+
+ function isArrayLike(t){
+ t.assertFalse(dojo.isArrayLike("thinger"));
+ t.assertTrue(dojo.isArrayLike(new Array()));
+ t.assertFalse(dojo.isArrayLike({}));
+ t.assertTrue(dojo.isArrayLike(arguments));
+ },
+
+ function isString(t){
+ t.assertFalse(dojo.isString(true));
+ t.assertFalse(dojo.isString(false));
+ t.assertTrue(dojo.isString("foo"));
+ t.assertTrue(dojo.isString(new String("foo")));
+ t.assertFalse(dojo.isString(null));
+ t.assertFalse(dojo.isString({}));
+ t.assertFalse(dojo.isString([]));
+ },
+
+ function partial(t){
+ var scope = { foo: "bar" };
+ var scope2 = { foo: "baz" };
+ function thinger(arg1, arg2){
+ return [this.foo, arg1, arg2];
+ }
+
+ var st1 = dojo.partial(thinger);
+ t.assertEqual("bar", st1.call(scope)[0]);
+ t.assertEqual(undefined, st1()[0]);
+ var st2 = dojo.partial(thinger, "foo", "bar");
+ t.assertEqual("bar", st2()[2]);
+ var st3 = dojo.partial(thinger, "foo", "bar");
+ },
+
+ function nestedPartial(t){
+ function thinger(arg1, arg2){
+ return [arg1, arg2];
+ }
+
+ var st1 = dojo.partial(thinger, "foo");
+ t.assertEqual(undefined, st1()[1]);
+ t.assertEqual("bar", st1("bar")[1]);
+
+ // partials can accumulate
+ var st2 = dojo.partial(st1, "thud");
+ t.assertEqual("foo", st2()[0]);
+ t.assertEqual("thud", st2()[1]);
+ },
+
+ function hitch(t){
+ var scope = { foo: "bar" };
+ var scope2 = { foo: "baz" };
+ function thinger(){
+ return [this.foo, arguments.length];
+ }
+
+ var st1 = dojo.hitch(scope, thinger);
+ t.assertEqual("bar", st1()[0]);
+ t.assertEqual(0, st1()[1]);
+
+ var st2 = dojo.hitch(scope2, thinger);
+ t.assertEqual("baz", st2()[0]);
+ t.assertEqual(0, st1()[1]);
+ t.assertEqual(1, st1("blah")[1]);
+
+ // st2 should be "scope proof"
+ t.assertEqual("baz", st2.call(scope)[0]);
+ },
+
+ function hitchWithArgs(t){
+ var scope = { foo: "bar" };
+ var scope2 = { foo: "baz" };
+ function thinger(){
+ return [this.foo, arguments.length];
+ }
+
+ var st1 = dojo.hitch(scope, thinger, "foo", "bar");
+ t.assertEqual("bar", st1()[0]);
+ t.assertEqual(2, st1()[1]);
+ var st2 = dojo.hitch(scope2, thinger, "foo", "bar");
+ t.assertEqual("baz", st2()[0]);
+ t.assertEqual(2, st2()[1]);
+ },
+
+ function hitchAsPartial(t){
+ var scope = { foo: "bar" };
+ var scope2 = { foo: "baz" };
+ function thinger(arg1, arg2){
+ return [this.foo, arg1, arg2];
+ }
+
+ var st1 = dojo.hitch(null, thinger);
+ t.assertEqual("bar", st1.call(scope)[0]);
+ t.assertEqual(undefined, st1()[0]);
+ var st2 = dojo.hitch(null, thinger, "foo", "bar");
+ t.assertEqual("bar", st2()[2]);
+ var st3 = dojo.hitch(null, thinger, "foo", "bar");
+ },
+
+ function _toArray(t){
+ var obj1 = [ 'foo', 'bar', 'spam', 'ham' ];
+
+ function thinger(){
+ return dojo._toArray(arguments);
+ }
+ var obj2 = thinger.apply(this, obj1);
+ t.assertEqual(obj1[0], obj2[0]);
+ },
+
+ function clone(t) {
+ var obj1 = {foo: 'bar', answer: 42, jan102007: new Date(2007, 0, 10),
+ baz: {
+ a: null,
+ b: [
+ 1, "b", 2.3, true, false
+ //, function(){ return 4; }, /\d+/gm
+ ]
+ }
+ };
+ var obj2 = dojo.clone(obj1);
+ t.assertEqual(obj1.foo, obj2.foo);
+ t.assertEqual(obj1.answer, obj2.answer);
+ t.assertEqual(obj1.jan102007, obj2.jan102007);
+ t.assertEqual(obj1.baz.a, obj2.baz.a);
+ for(var i = 0; i < obj1.baz.b.length; ++i){
+ t.assertEqual(obj1.baz.b[i], obj2.baz.b[i]);
+ }
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/_base/query.html b/includes/js/dojo/tests/_base/query.html
new file mode 100644
index 0000000..5c92221
--- /dev/null
+++ b/includes/js/dojo/tests/_base/query.html
@@ -0,0 +1,154 @@
+<html>
+ <head>
+ <title>testing dojo.query()</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ </style>
+ <script type="text/javascript" src="../../dojo.js"
+ djConfig="isDebug: true, debugAtAllCosts: false, noFirebugLite: true"></script>
+ <script type="text/javascript" src="../../../util/doh/runner.js"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+ dojo.require("dojox.data.dom");
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ // basic sanity checks
+ "doh.is(4, (dojo.query('h3')).length);",
+ "doh.is(1, (dojo.query('h1:first-child')).length);",
+ "doh.is(2, (dojo.query('h3:first-child')).length);",
+ "doh.is(1, (dojo.query('#t')).length);",
+ "doh.is(1, (dojo.query('#bug')).length);",
+ "doh.is(4, (dojo.query('#t h3')).length);",
+ "doh.is(1, (dojo.query('div#t')).length);",
+ "doh.is(4, (dojo.query('div#t h3')).length);",
+ "doh.is(0, (dojo.query('span#t')).length);",
+ "doh.is(1, (dojo.query('#t div > h3')).length);",
+ "doh.is(2, (dojo.query('.foo')).length);",
+ "doh.is(1, (dojo.query('.foo.bar')).length);",
+ "doh.is(2, (dojo.query('.baz')).length);",
+ "doh.is(3, (dojo.query('#t > h3')).length);",
+ // syntactic equivalents
+ "doh.is(12, (dojo.query('#t > *')).length);",
+ "doh.is(12, (dojo.query('#t >')).length);",
+ "doh.is(3, (dojo.query('.foo >')).length);",
+ "doh.is(3, (dojo.query('.foo > *')).length);",
+ // with a root, by ID
+ "doh.is(3, (dojo.query('> *', 'container')).length);",
+ "doh.is(3, (dojo.query('> h3', 't')).length);",
+ // compound queries
+ "doh.is(2, (dojo.query('.foo, .bar')).length);",
+ "doh.is(2, (dojo.query('.foo,.bar')).length);",
+ // multiple class attribute
+ "doh.is(1, (dojo.query('.foo.bar')).length);",
+ "doh.is(2, (dojo.query('.foo')).length);",
+ "doh.is(2, (dojo.query('.baz')).length);",
+ // case sensitivity
+ "doh.is(1, (dojo.query('span.baz')).length);",
+ "doh.is(1, (dojo.query('sPaN.baz')).length);",
+ "doh.is(1, (dojo.query('SPAN.baz')).length);",
+ "doh.is(1, (dojo.query('[class = \"foo bar\"]')).length);",
+ "doh.is(2, (dojo.query('[foo~=\"bar\"]')).length);",
+ "doh.is(2, (dojo.query('[ foo ~= \"bar\" ]')).length);",
+ // "t.is(0, (dojo.query('[ foo ~= \"\\'bar\\'\" ]')).length);",
+ "doh.is(3, (dojo.query('[foo]')).length);",
+ "doh.is(1, (dojo.query('[foo$=\"thud\"]')).length);",
+ "doh.is(1, (dojo.query('[foo$=thud]')).length);",
+ "doh.is(1, (dojo.query('[foo$=\"thudish\"]')).length);",
+ "doh.is(1, (dojo.query('#t [foo$=thud]')).length);",
+ "doh.is(1, (dojo.query('#t [ title $= thud ]')).length);",
+ "doh.is(0, (dojo.query('#t span[ title $= thud ]')).length);",
+ "doh.is(1, (dojo.query('[foo|=\"bar\"]')).length);",
+ "doh.is(1, (dojo.query('[foo|=\"bar-baz\"]')).length);",
+ "doh.is(0, (dojo.query('[foo|=\"baz\"]')).length);",
+ "doh.is(dojo.byId('_foo'), dojo.query('.foo:nth-child(2)')[0]);",
+ "doh.is(dojo.query('style')[0], dojo.query(':nth-child(2)')[0]);",
+ // descendant selectors
+ "doh.is(3, dojo.query('>', 'container').length);",
+ "doh.is(3, dojo.query('> *', 'container').length);",
+ "doh.is(2, dojo.query('> [qux]', 'container').length);",
+ "doh.is('child1', dojo.query('> [qux]', 'container')[0].id);",
+ "doh.is('child3', dojo.query('> [qux]', 'container')[1].id);",
+ "doh.is(3, dojo.query('>', 'container').length);",
+ "doh.is(3, dojo.query('> *', 'container').length);",
+ "doh.is('passed', dojo.query('#bug')[0].value);",
+ // sibling selectors
+ "doh.is(1, dojo.query('+', 'container').length);",
+ "doh.is(3, dojo.query('~', 'container').length);",
+ "doh.is(1, (dojo.query('.foo + span')).length);",
+ "doh.is(4, (dojo.query('.foo ~ span')).length);",
+ "doh.is(1, (dojo.query('#foo ~ *')).length);",
+ "doh.is(1, (dojo.query('#foo ~')).length);",
+ // sub-selector parsing
+ "doh.is(1, dojo.query('#t span.foo:not(span:first-child)').length);",
+ "doh.is(1, dojo.query('#t span.foo:not(:first-child)').length);",
+
+ // nth-child tests
+ "doh.is(2, dojo.query('#t > h3:nth-child(odd)').length);",
+ "doh.is(3, dojo.query('#t h3:nth-child(odd)').length);",
+ "doh.is(3, dojo.query('#t h3:nth-child(2n+1)').length);",
+ "doh.is(1, dojo.query('#t h3:nth-child(even)').length);",
+ "doh.is(1, dojo.query('#t h3:nth-child(2n)').length);",
+ "doh.is(0, dojo.query('#t h3:nth-child(2n+3)').length);",
+ "doh.is(2, dojo.query('#t h3:nth-child(1)').length);",
+ "doh.is(1, dojo.query('#t > h3:nth-child(1)').length);",
+ "doh.is(3, dojo.query('#t :nth-child(3)').length);",
+ "doh.is(0, dojo.query('#t > div:nth-child(1)').length);",
+ "doh.is(7, dojo.query('#t span').length);",
+ // :empty pseudo-selector
+ "doh.is(4, dojo.query('#t > span:empty').length);",
+ "doh.is(6, dojo.query('#t span:empty').length);",
+ "doh.is(0, dojo.query('h3 span:empty').length);",
+ "doh.is(1, dojo.query('h3 :not(:empty)').length);",
+ // escaping of ":" chars inside an ID
+ function silly_IDs1(){
+ doh.t(document.getElementById("silly:id::with:colons"));
+ doh.is(1, dojo.query("#silly\\:id\\:\\:with\\:colons").length);
+ },
+ function NodeList_identity(){
+ var foo = new dojo.NodeList([dojo.byId("container")]);
+ doh.is(foo, dojo.query(foo));
+ },
+ function xml(){
+ try{
+ var doc = dojox.data.dom.createDocument("<ResultSet><Result>One</Result><Result>Two</Result></ResultSet>");
+ console.debug(doc);
+ console.debug(dojox.data.dom.innerXML(doc.documentElement));
+ console.debug(dojo.query("Result", doc.documentElement).length);
+ }catch(e){ console.debug(e); }
+ }
+ ]
+ );
+ doh.run();
+ });
+ </script>
+ </head>
+ <body>
+ <h1>testing dojo.query()</h1>
+ <div id="t">
+ <h3>h3 <span>span</span> endh3 </h3>
+ <!-- comment to throw things off -->
+ <div class="foo bar" id="_foo">
+ <h3>h3</h3>
+ <span id="foo"></span>
+ <span></span>
+ </div>
+ <h3>h3</h3>
+ <h3 class="baz" title="thud">h3</h3>
+ <span class="foobar baz foo"></span>
+ <span foo="bar"></span>
+ <span foo="baz bar thud"></span>
+ <!-- FIXME: should foo="bar-baz-thud" match? [foo$=thud] ??? -->
+ <span foo="bar-baz-thudish" id="silly:id::with:colons"></span>
+ <div id="container">
+ <div id="child1" qux="true"></div>
+ <div id="child2"></div>
+ <div id="child3" qux="true"></div>
+ </div>
+ <div qux="true"></div>
+ <input id="notbug" name="bug" type="hidden" value="failed" />
+ <input id="bug" type="hidden" value="passed" />
+ </div>
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/query.js b/includes/js/dojo/tests/_base/query.js
new file mode 100644
index 0000000..20d2fc4
--- /dev/null
+++ b/includes/js/dojo/tests/_base/query.js
@@ -0,0 +1,9 @@
+if(!dojo._hasResource["tests._base.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base.query"] = true;
+dojo.provide("tests._base.query");
+if(dojo.isBrowser){
+ doh.registerUrl("tests._base.query", dojo.moduleUrl("tests", "_base/query.html"));
+ doh.registerUrl("tests._base.NodeList", dojo.moduleUrl("tests", "_base/NodeList.html"));
+}
+
+}
diff --git a/includes/js/dojo/tests/_base/timeout.php b/includes/js/dojo/tests/_base/timeout.php
new file mode 100644
index 0000000..560b0d3
--- /dev/null
+++ b/includes/js/dojo/tests/_base/timeout.php
@@ -0,0 +1,7 @@
+<?php
+
+$callbackName = $_REQUEST["callback"];
+sleep(5);
+print "SuperXFooBarVariable = 'Oh no! SuperXFooBarVariable is defined (should not be for timeout case).'; {$callbackName}({Status: 'good'});";
+
+?>
diff --git a/includes/js/dojo/tests/_base/xhr.html b/includes/js/dojo/tests/_base/xhr.html
new file mode 100644
index 0000000..ddc1bb4
--- /dev/null
+++ b/includes/js/dojo/tests/_base/xhr.html
@@ -0,0 +1,404 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>testing form and xhr utils</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ src="../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+ dojo.addOnLoad(function(){
+ var f1fo = { 'blah': "blah" };
+ var f1foStr = "blah=blah";
+ var f1foJson = '{"blah":"blah"}';
+
+ var f2fo = {
+ blah: "blah",
+ multi: [
+ "thud",
+ "thonk"
+ ],
+ textarea: "textarea_value"
+ };
+ var f2foStr = "blah=blah&multi=thud&multi=thonk&textarea=textarea_value";
+ var f2foJson = '{"blah":"blah","multi":["thud","thonk"],"textarea":"textarea_value"}';
+
+ var f3fo = {
+ spaces: "string with spaces"
+ };
+ var f3foStr = "spaces=string%20with%20spaces&";
+ var f3foJson = '{"spaces":"string with spaces"}';
+
+ var f5fo = { 'blåh': "bláh" };
+ var f5foStr = "bl%C3%A5h=bl%C3%A1h";
+ var f5foJson = '{"blåh":"bláh"}';
+
+
+ doh.register("t",
+ [
+ function formNodeToObject(t){
+ t.is(f1fo , dojo.formToObject(dojo.byId("f1")));
+ t.is(f5fo , dojo.formToObject(dojo.byId("f5")));
+ },
+ function formIdToObject(t){
+ t.is(f1fo , dojo.formToObject("f1"));
+ t.is(f5fo , dojo.formToObject("f5"));
+ },
+ function formToObjectWithMultiSelect(t){
+ t.is(f2fo , dojo.formToObject("f2"));
+ },
+ function objectToQuery(t){
+ t.is(f1foStr , dojo.objectToQuery(f1fo));
+ t.is(f5foStr , dojo.objectToQuery(f5fo));
+ },
+ function objectToQueryArr(t){
+ t.is(f2foStr, dojo.objectToQuery(f2fo));
+ },
+ function formToQuery(t){
+ t.is(f1foStr, dojo.formToQuery("f1"));
+ t.is(f5foStr, dojo.formToQuery("f5"));
+ },
+ function formToQueryArr(t){
+ t.is(f2foStr, dojo.formToQuery("f2"));
+ },
+ function formToJson(t){
+ t.is(f1foJson, dojo.formToJson("f1"));
+ t.is(f5foJson, dojo.formToJson("f5"));
+ },
+ function formToJsonArr(t){
+ t.is(f2foJson, dojo.formToJson("f2"));
+ },
+ function queryToObject(t){
+ t.is(f1fo , dojo.queryToObject(f1foStr));
+ t.is(f2fo , dojo.queryToObject(f2foStr));
+ t.is(f3fo , dojo.queryToObject(f3foStr));
+ t.is(f5fo , dojo.queryToObject(f5foStr));
+ },
+ function textContentHandler(t){
+ t.is("foo bar baz ",
+ dojo._contentHandlers.text({
+ responseText: "foo bar baz "
+ })
+ );
+ },
+ function jsonContentHandler(t){
+ var jsonObj = {
+ foo: "bar",
+ baz: [
+ { thonk: "blarg" },
+ "xyzzy!"
+ ]
+ };
+ t.is(jsonObj,
+ dojo._contentHandlers.json({
+ responseText: dojo.toJson(jsonObj)
+ })
+ );
+ },
+ function jsonCFContentHandler(t){
+ var jsonObj = {
+ foo: "bar",
+ baz: [
+ { thonk: "blarg" },
+ "xyzzy!"
+ ]
+ };
+ var e;
+ try{
+ dojo._contentHandlers["json-comment-filtered"]({
+ responseText: dojo.toJson(jsonObj)
+ })
+ }catch(ex){
+ e = ex;
+ }finally{
+ // did we fail closed?
+ t.is((typeof e), "object");
+ }
+ t.is(jsonObj,
+ dojo._contentHandlers["json-comment-filtered"]({
+ responseText: "\tblag\n/*"+dojo.toJson(jsonObj)+"*/\n\r\t\r"
+ })
+ );
+ },
+ function jsContentHandler(t){
+ var jsonObj = {
+ foo: "bar",
+ baz: [
+ { thonk: "blarg" },
+ "xyzzy!"
+ ]
+ };
+ t.is(jsonObj,
+ dojo._contentHandlers["javascript"]({
+ responseText: "("+dojo.toJson(jsonObj)+")"
+ })
+ );
+ t.t(dojo._contentHandlers["javascript"]({
+ responseText: "true;"
+ })
+ );
+ t.f(dojo._contentHandlers["javascript"]({
+ responseText: "false;"
+ })
+ );
+ },
+ function xmlContentHandler(t){
+ var fauxObj = {
+ foo: "bar",
+ baz: [
+ { thonk: "blarg" },
+ "xyzzy!"
+ ]
+ };
+ t.is(fauxObj,
+ dojo._contentHandlers["xml"]({ responseXML: fauxObj })
+ );
+ },
+ function xhrGet(t){
+ var d = new doh.Deferred();
+ var td = dojo.xhrGet({
+ url: "xhr.html", // self
+ preventCache: true,
+ load: function(text, ioArgs){
+ t.is(4, ioArgs.xhr.readyState);
+ return text; //must return a value here or the parent test deferred fails.
+ }
+ });
+ t.t(td instanceof dojo.Deferred);
+ td.addCallback(d, "callback");
+ return d;
+ },
+ function xhrGet404(t){
+ var d = new doh.Deferred();
+ try{
+ var td = dojo.xhrGet({
+ url: "xhr_blarg.html", // doesn't exist
+ error: function(err, ioArgs){
+ t.is(404, ioArgs.xhr.status);
+ return err; //must return a value here or the parent test deferred fails.
+ }
+ });
+ // td.addErrback(d, "callback");
+ }catch(e){
+ d.callback(true);
+ }
+ // return d;
+ },
+ function xhrGetContent(t){
+ var d = new doh.Deferred();
+ var td = dojo.xhrGet({
+ url: "xhr.html?color=blue",
+ content: {
+ foo: [ "bar", "baz" ],
+ thud: "thonk",
+ xyzzy: 3
+ }
+ });
+ td.addCallback(function(text){
+ // console.debug(td, td.xhr, td.args);
+ t.is("xhr.html?color=blue&foo=bar&foo=baz&thud=thonk&xyzzy=3",
+ td.ioArgs.url);
+ d.callback(true);
+ });
+ return d;
+ },
+ function xhrGetForm(t){
+ var d = new doh.Deferred();
+ var td = dojo.xhrGet({
+ url: "xhr.html", // self
+ form: "f3"
+ });
+ td.addCallback(function(xhr){
+ // console.debug(td.args.url);
+ t.is("xhr.html?spaces=string%20with%20spaces", td.ioArgs.url);
+ d.callback(true);
+ });
+ return d;
+ },
+ function xhrGetFormWithContent(t){
+ // ensure that stuff passed via content over-rides
+ // what's specified in the form
+ var d = new doh.Deferred();
+ var td = dojo.xhrGet({
+ url: "xhr.html", // self
+ form: "f3",
+ content: { spaces: "blah" }
+ });
+ td.addCallback(function(xhr){
+ // console.debug(td.args.url);
+ t.is("xhr.html?spaces=blah", td.ioArgs.url);
+ d.callback(true);
+ });
+ return d;
+ },
+ function xhrPost(t){
+ var d = new doh.Deferred();
+ var td = dojo.xhrPost({
+ url: "xhr.html?foo=bar", // self
+ content: { color: "blue"},
+ handle: function(res, ioArgs){
+ if((dojo._isDocumentOk(ioArgs.xhr))||
+ (ioArgs.xhr.status == 405)
+ ){
+ d.callback(true);
+ }else{
+ d.errback(false);
+ }
+ }
+ });
+ // t.t(td instanceof dojo.Deferred);
+ return d;
+ },
+ function xhrPostWithContent(t){
+ var d = new doh.Deferred();
+ var td = dojo.xhrPost({
+ url: "xhr.html",
+ content: {
+ foo: [ "bar", "baz" ],
+ thud: "thonk",
+ xyzzy: 3
+ }
+ });
+ td.addBoth(function(text){
+ t.is("foo=bar&foo=baz&thud=thonk&xyzzy=3",
+ td.ioArgs.query);
+ if( (dojo._isDocumentOk(td.ioArgs.xhr))||
+ (td.ioArgs.xhr.status == 405)
+ ){
+ d.callback(true);
+ }else{
+ d.errback(false);
+ }
+ });
+ return d;
+ },
+ function xhrPostForm(t){
+ var d = new doh.Deferred();
+ var form = dojo.byId("f4");
+
+ //Make sure we can send a form to its
+ //action URL. See trac: #2844.
+ var td = dojo.xhrPost({
+ form: form
+ });
+ td.addCallback(function(){
+ d.callback(true);
+ });
+ td.addErrback(function(error){
+ d.callback(error);
+ });
+ // t.t(td instanceof dojo.Deferred);
+ return d;
+ },
+ function rawXhrPost(t){
+ var d = new doh.Deferred();
+ var td = dojo.rawXhrPost({
+ url: "xhr.html", // self
+ postContent: "foo=bar&color=blue&height=average",
+ handle: function(res, ioArgs){
+ if((dojo._isDocumentOk(ioArgs.xhr))||
+ (ioArgs.xhr.status == 405)
+ ){
+ d.callback(true);
+ }else{
+ d.errback(false);
+ }
+ }
+ });
+ // t.t(td instanceof dojo.Deferred);
+ return d;
+ },
+ function xhrPut(t){
+ var d = new doh.Deferred();
+ var td = dojo.xhrPut({
+ url: "xhrDummyMethod.php?foo=bar", // self
+ content: { color: "blue"},
+ handle: function(res, ioArgs){
+ if((dojo._isDocumentOk(ioArgs.xhr))||
+ (ioArgs.xhr.status == 403)
+ ){
+ d.callback(true);
+ }else{
+ d.errback(false);
+ }
+ }
+ });
+ // t.t(td instanceof dojo.Deferred);
+ return d;
+ },
+ function xhrDelete(t){
+ var d = new doh.Deferred();
+ var td = dojo.xhrDelete({
+ url: "xhrDummyMethod.php", // self
+ preventCache: true,
+ handle: function(res, ioArgs){
+ if((dojo._isDocumentOk(ioArgs.xhr))||
+ (ioArgs.xhr.status == 403)
+ ){
+ d.callback(true);
+ }else{
+ d.errback(false);
+ }
+ }
+ });
+ // t.t(td instanceof dojo.Deferred);
+ return d;
+ },
+ function xhrCancel(t){
+ var d = new doh.Deferred();
+ var td = dojo.xhrPost({
+ url: "xhrDummyMethod.php", // self
+ handle: function(res, ioArgs){
+ if(res instanceof Error && res.dojoType == "cancel"){
+ d.callback(true);
+ }else{
+ d.errback(false);
+ }
+ }
+ });
+ td.cancel();
+ // t.t(td instanceof dojo.Deferred);
+ return d;
+ }
+ // FIXME: need to add tests for wrapForm
+ ]
+ );
+ doh.run();
+ });
+ </script>
+ </head>
+ <body>
+ <form id="f1" style="border: 1px solid black;">
+ <input type="text" name="blah" value="blah">
+ <input type="text" name="no_value" value="blah" disabled>
+ <input type="button" name="no_value2" value="blah">
+ </form>
+ <form id="f2" style="border: 1px solid black;">
+ <input type="text" name="blah" value="blah">
+ <input type="text" name="no_value" value="blah" disabled>
+ <input type="button" name="no_value2" value="blah">
+ <select type="select" multiple name="multi" size="5">
+ <option value="blah">blah</option>
+ <option value="thud" selected>thud</option>
+ <option value="thonk" selected>thonk</option>
+ </select>
+ <textarea name="textarea">textarea_value</textarea>
+ </form>
+ <form id="f3" style="border: 1px solid black;">
+ <input type="hidden" name="spaces" value="string with spaces">
+ </form>
+ <form id="f4" style="border: 1px solid black;" action="xhrDummyMethod.php">
+ <input type="hidden" name="action" value="Form with input named action">
+ </form>
+ <form id="f5" style="border: 1px solid black;">
+ <input type="text" name="blåh" value="bláh">
+ <input type="text" name="no_value" value="blah" disabled>
+ <input type="button" name="no_value2" value="blah">
+ </form>
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/_base/xhr.js b/includes/js/dojo/tests/_base/xhr.js
new file mode 100644
index 0000000..885bbfe
--- /dev/null
+++ b/includes/js/dojo/tests/_base/xhr.js
@@ -0,0 +1,8 @@
+if(!dojo._hasResource["tests._base.xhr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests._base.xhr"] = true;
+dojo.provide("tests._base.xhr");
+if(dojo.isBrowser){
+ doh.registerUrl("tests._base.xhr", dojo.moduleUrl("tests", "_base/xhr.html"));
+}
+
+}
diff --git a/includes/js/dojo/tests/_base/xhrDummyMethod.php b/includes/js/dojo/tests/_base/xhrDummyMethod.php
new file mode 100644
index 0000000..c9206fe
--- /dev/null
+++ b/includes/js/dojo/tests/_base/xhrDummyMethod.php
@@ -0,0 +1,7 @@
+<?php
+//Just a dummy end point to use in HTTP method calls like PUT and DELETE.
+//This avoids getting a 405 method not allowed calls for the tests that reference
+//this file.
+
+header("HTTP/1.1 200 OK");
+?>
diff --git a/includes/js/dojo/tests/back-hash.js b/includes/js/dojo/tests/back-hash.js
new file mode 100644
index 0000000..3fef2c5
--- /dev/null
+++ b/includes/js/dojo/tests/back-hash.js
@@ -0,0 +1,33 @@
+if(!dojo._hasResource["tests.back-hash"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.back-hash"] = true;
+dojo.provide("tests.back-hash");
+
+dojo.require("dojo.back");
+
+(function(){
+ tests.register("tests.back.hash", [
+ function getAndSet(t) {
+ var cases = [
+ "test",
+ "test with spaces",
+ "test%20with%20encoded",
+ "test+with+pluses",
+ " leading",
+ "trailing ",
+ "under_score",
+ "extra#mark",
+ "extra?instring",
+ "extra&instring",
+ "#leadinghash"
+ ];
+ var b = dojo.back;
+ function verify(s){
+ dojo.back.setHash(s);
+ t.is(s, dojo.back.getHash(s));
+ }
+ dojo.forEach(cases, verify);
+ }
+ ]);
+})();
+
+}
diff --git a/includes/js/dojo/tests/back.html b/includes/js/dojo/tests/back.html
new file mode 100644
index 0000000..1b9ca1c
--- /dev/null
+++ b/includes/js/dojo/tests/back.html
@@ -0,0 +1,107 @@
+<html>
+<head>
+ <script language="JavaScript" type="text/javascript">
+ // Dojo configuration
+ djConfig = {
+ //debugAtAllCosts: true, //Don't normally need this in applications.
+ isDebug: true,
+ dojoIframeHistoryUrl: "../../resources/iframe_history.html" //for xdomain
+ };
+ </script>
+ <script type="text/javascript"
+ src="../dojo.js"
+ djConfig="isDebug:true, dojoIframeHistoryUrl: '../resources/iframe_history.html'"></script>
+ <script type="text/javascript" src="../back.js"></script>
+ <script type="text/javascript">
+ ApplicationState = function(stateData, outputDivId, backForwardOutputDivId, bookmarkValue){
+ this.stateData = stateData;
+ this.outputDivId = outputDivId;
+ this.backForwardOutputDivId = backForwardOutputDivId;
+ this.changeUrl = bookmarkValue || false;
+ }
+
+ dojo.extend(ApplicationState, {
+ back: function(){
+ this.showBackForwardMessage("BACK for State Data: " + this.stateData);
+ this.showStateData();
+ },
+ forward: function(){
+ this.showBackForwardMessage("FORWARD for State Data: " + this.stateData);
+ this.showStateData();
+ },
+ showStateData: function(){
+ dojo.byId(this.outputDivId).innerHTML += this.stateData + '<br />';
+ },
+ showBackForwardMessage: function(message){
+ dojo.byId(this.backForwardOutputDivId).innerHTML += message + '<br />';
+ }
+ });
+
+ var data = {
+ link0: "This is the initial state (page first loaded)",
+ "link with spaces": "This is data for a state with spaces",
+ "link%20with%20encoded": "This is data for a state with encoded bits",
+ "link+with+pluses": "This is data for a state with pluses",
+ link1: "This is data for link 1",
+ link2: "This is data for link 2",
+ link3: "This is data for link 3",
+ link4: "This is data for link 4",
+ link5: "This is data for link 5",
+ link6: "This is data for link 6",
+ link7: "This is data for link 7"
+ };
+
+ function goNav(id){
+ var appState = new ApplicationState(data[id], "output", "dataOutput", id);
+ appState.showStateData();
+ dojo.back.addToHistory(appState);
+ }
+
+ dojo.addOnLoad(function(){
+ var appState = new ApplicationState(data["link0"], "output", "dataOutput");
+ appState.showStateData();
+ dojo.back.setInitialState(appState);
+ });
+ </script>
+</head>
+<body>
+ <script type="text/javascript">dojo.back.init();</script>
+ <div style="padding-bottom: 20px; width: 100%; border-bottom: 1px solid gray">
+ <h3>dojo.back test</h3>
+
+
+ <p>This page tests the dojo.back back/forward code.</p>
+
+ <p>The buttons that start with "Link" on them don't use any dojo.xhr* calls,
+ just JS data already in the page.</p>
+
+ <ul>
+ <li>Don't test this page using local disk for MSIE. MSIE will not
+ create a history list for iframe_history.html if served from a file:
+ URL. Serve the test pages from a web server to test in that browser.</li>
+ <li>Safari 2.0.3+ (and probably 1.3.2+): Only the back button works OK
+ (not the forward button).</li>
+ <li>Opera 8.5.3: Does not work.</li>
+ <li>Konqueror: Unknown. The latest may have Safari's behavior.</li>
+ </ul>
+ </div>
+ <div style="float:left; padding: 20px">
+ <button onclick="goNav('link1')">Link 1</button><br />
+ <button onclick="goNav('link with spaces')">Link with Spaces</button><br />
+ <button onclick="goNav('link%20with%20encoded')">Link with Encoded</button><br />
+ <button onclick="goNav('link+with+pluses')">Link with Pluses</button><br />
+ <button onclick="goNav('link3')">Link 3</button><br />
+ <button onclick="goNav('link4')">Link 4</button><br />
+ <button onclick="goNav('link5')">Link 5</button><br />
+ <button onclick="goNav('link6')">Link 6</button><br />
+ <button onclick="goNav('link7')">Link 7</button><br />
+ </div>
+ <div style="float: left; padding: 20px">
+ <b>Data Output:</b><br />
+ <div id="output"></div>
+ <hr />
+ <i>Back/Forward Info:</i><br />
+ <div id="dataOutput"></div>
+ </div>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/back.js b/includes/js/dojo/tests/back.js
new file mode 100644
index 0000000..0565716
--- /dev/null
+++ b/includes/js/dojo/tests/back.js
@@ -0,0 +1,8 @@
+if(!dojo._hasResource["tests.back"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.back"] = true;
+dojo.provide("tests.back");
+if(dojo.isBrowser){
+ doh.registerUrl("tests.back", dojo.moduleUrl("tests", "back.html"));
+}
+
+}
diff --git a/includes/js/dojo/tests/behavior.html b/includes/js/dojo/tests/behavior.html
new file mode 100644
index 0000000..280fc29
--- /dev/null
+++ b/includes/js/dojo/tests/behavior.html
@@ -0,0 +1,106 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Testing dojo.behavior</title>
+ <style type="text/css">
+ @import "../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ src="../dojo.js" djConfig="isDebug: true, popup: true"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+ dojo.require("dojo.behavior");
+
+ var applyCount = 0;
+
+ var behaviorObj = {
+ ".bar": function(elem){
+ dojo.style(elem, "opacity", 0.5);
+ applyCount++;
+ },
+ ".foo > span": function(elem){
+ elem.style.fontStyle = "italic";
+ applyCount++;
+ }
+ }
+
+ topicCount = 0;
+ dojo.subscribe("/foo", function(){ topicCount++; });
+
+ // no behaviors should be executed when onload fires
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ function add(t){
+ t.f(dojo.behavior._behaviors[".bar"]);
+ t.f(dojo.behavior._behaviors[".foo > span"]);
+ dojo.behavior.add(behaviorObj);
+ // make sure they got plopped in
+ t.t(dojo.behavior._behaviors[".bar"]);
+ t.is(1, dojo.behavior._behaviors[".bar"].length);
+ t.t(dojo.behavior._behaviors[".foo > span"]);
+ t.is(1, dojo.behavior._behaviors[".foo > span"].length);
+ },
+ function apply(t){
+ t.is(0, applyCount);
+ dojo.behavior.apply();
+ t.is(2, applyCount);
+
+ // reapply and make sure we only match once
+ dojo.behavior.apply();
+ t.is(2, applyCount);
+ },
+ function reapply(t){
+ t.is(2, applyCount);
+ // add the rules again
+ dojo.behavior.add(behaviorObj);
+ dojo.behavior.apply();
+ t.is(4, applyCount);
+ // dojo.behavior.apply();
+ // t.is(4, applyCount);
+ // dojo.query(".bar").styles("opacity", 1.0);
+ },
+ function topics(t){
+ var d = new doh.Deferred();
+ t.is(0, topicCount);
+ dojo.behavior.add({ ".foo": "/foo" });
+ dojo.behavior.apply();
+ t.is(2, topicCount);
+
+ dojo.behavior.add({ ".foo": {
+ "onfocus": "/foo"
+ }
+ });
+ dojo.behavior.apply();
+ t.is(2, topicCount);
+ dojo.byId("blah").focus();
+ dojo.byId("blah").blur();
+ dojo.byId("blah").focus();
+ setTimeout(function(){
+ // blur/focus event generation isn't synchronous on IE
+ try{
+ t.is(4, topicCount);
+ d.callback(true);
+ }catch(e){
+ d.errback(e);
+ }
+ }, 10);
+ return d;
+ }
+ ]
+ );
+ doh.run();
+ });
+ </script>
+ </head>
+ <body>
+ <div class="foo" id="fooOne">
+ <span>.foo &gt; span</span>
+ <div class="bar">
+ <span>.foo &gt; .bar &gt; span</span>
+ </div>
+ </div>
+ <input type="text" id="blah" class="foo blah" name="thinger" value="thinger" tabIndex="0">
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/behavior.js b/includes/js/dojo/tests/behavior.js
new file mode 100644
index 0000000..e09de9d
--- /dev/null
+++ b/includes/js/dojo/tests/behavior.js
@@ -0,0 +1,8 @@
+if(!dojo._hasResource["tests.behavior"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.behavior"] = true;
+dojo.provide("tests.behavior");
+if(dojo.isBrowser){
+ doh.registerUrl("tests.behavior", dojo.moduleUrl("tests", "behavior.html"));
+}
+
+}
diff --git a/includes/js/dojo/tests/cldr.js b/includes/js/dojo/tests/cldr.js
new file mode 100644
index 0000000..e9edfad
--- /dev/null
+++ b/includes/js/dojo/tests/cldr.js
@@ -0,0 +1,19 @@
+if(!dojo._hasResource["tests.cldr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.cldr"] = true;
+dojo.provide("tests.cldr");
+
+dojo.require("dojo.cldr.supplemental");
+dojo.require("dojo.cldr.monetary");
+
+tests.register("tests.cldr",
+ [
+ function test_date_getWeekend(t){
+ t.is(6, dojo.cldr.supplemental.getWeekend('en-us').start);
+ t.is(0, dojo.cldr.supplemental.getWeekend('en-us').end);
+ t.is(5, dojo.cldr.supplemental.getWeekend('he-il').start);
+ t.is(6, dojo.cldr.supplemental.getWeekend('he-il').end);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/colors.js b/includes/js/dojo/tests/colors.js
new file mode 100644
index 0000000..7f3808e
--- /dev/null
+++ b/includes/js/dojo/tests/colors.js
@@ -0,0 +1,48 @@
+if(!dojo._hasResource["tests.colors"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.colors"] = true;
+dojo.provide("tests.colors");
+dojo.require("dojo.colors");
+
+(function(){
+ var verifyColor = function(t, source, expected){
+ var source = new dojo.Color(source);
+ var expected = new dojo.Color(expected);
+ t.is(expected.toRgba(), source.toRgba());
+ dojo.forEach(source.toRgba(), function(n){ t.is("number", typeof(n)); });
+ }
+
+ doh.register("tests.colors",
+ [
+ // all tests below are taken from #4.2 of the CSS3 Color Module
+ function testColorEx01(t){ verifyColor(t, "black", [0, 0, 0]); },
+ function testColorEx02(t){ verifyColor(t, "white", [255, 255, 255]); },
+ function testColorEx03(t){ verifyColor(t, "maroon", [128, 0, 0]); },
+ function testColorEx04(t){ verifyColor(t, "olive", [128, 128, 0]); },
+ function testColorEx05(t){ verifyColor(t, "#f00", "red"); },
+ function testColorEx06(t){ verifyColor(t, "#ff0000", "red"); },
+ function testColorEx07(t){ verifyColor(t, "rgb(255, 0, 0)", "red"); },
+ function testColorEx08(t){ verifyColor(t, "rgb(100%, 0%, 0%)", "red"); },
+ function testColorEx09(t){ verifyColor(t, "rgb(300, 0, 0)", "red"); },
+ function testColorEx10(t){ verifyColor(t, "rgb(255, -10, 0)", "red"); },
+ function testColorEx11(t){ verifyColor(t, "rgb(110%, 0%, 0%)", "red"); },
+ function testColorEx12(t){ verifyColor(t, "rgba(255, 0, 0, 1)", "red"); },
+ function testColorEx13(t){ verifyColor(t, "rgba(100%, 0%, 0%, 1)", "red"); },
+ function testColorEx14(t){ verifyColor(t, "rgba(0, 0, 255, 0.5)", [0, 0, 255, 0.5]); },
+ function testColorEx15(t){ verifyColor(t, "rgba(100%, 50%, 0%, 0.1)", [255, 128, 0, 0.1]); },
+ function testColorEx16(t){ verifyColor(t, "hsl(0, 100%, 50%)", "red"); },
+ function testColorEx17(t){ verifyColor(t, "hsl(120, 100%, 50%)", "lime"); },
+ function testColorEx18(t){ verifyColor(t, "hsl(120, 100%, 25%)", "green"); },
+ function testColorEx19(t){ verifyColor(t, "hsl(120, 100%, 75%)", "#80ff80"); },
+ function testColorEx20(t){ verifyColor(t, "hsl(120, 50%, 50%)", "#40c040"); },
+ function testColorEx21(t){ verifyColor(t, "hsla(120, 100%, 50%, 1)", "lime"); },
+ function testColorEx22(t){ verifyColor(t, "hsla(240, 100%, 50%, 0.5)", [0, 0, 255, 0.5]); },
+ function testColorEx23(t){ verifyColor(t, "hsla(30, 100%, 50%, 0.1)", [255, 128, 0, 0.1]); },
+ function testColorEx24(t){ verifyColor(t, "transparent", [0, 0, 0, 0]); },
+ // all tests below test greyscale colors
+ function testColorEx25(t){ verifyColor(t, dojo.colors.makeGrey(5), [5, 5, 5, 1]); },
+ function testColorEx26(t){ verifyColor(t, dojo.colors.makeGrey(2, 0.3), [2, 2, 2, 0.3]); }
+ ]
+ );
+})();
+
+}
diff --git a/includes/js/dojo/tests/cookie.html b/includes/js/dojo/tests/cookie.html
new file mode 100644
index 0000000..a89b0f8
--- /dev/null
+++ b/includes/js/dojo/tests/cookie.html
@@ -0,0 +1,84 @@
+<html>
+ <head>
+ <title>testing Cookies</title>
+ <style type="text/css">
+ @import "../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ src="../dojo.js"
+ djConfig="isDebug:true"></script>
+ <script type="text/javascript" src="../cookie.js"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ {
+ name: "basicSet",
+ runTest: function(t){
+ // make sure the cookie is dead
+ var old = new Date(1976, 8, 15);
+ document.cookie = "dojo_test=blah; expires=" + old.toUTCString();
+ t.is(-1, document.cookie.indexOf("dojo_test="));
+
+ // set the new one
+ var n = "dojo_test";
+ var v = "test value";
+ dojo.cookie(n, v);
+ t.t(document.cookie.indexOf(n+"=") >= 0);
+ var start = document.cookie.indexOf(n+"=") + n.length + 1;
+ var end = document.cookie.indexOf(";", start);
+ if(end == -1){ end = document.cookie.length; }
+ t.is(v, decodeURIComponent(document.cookie.substring(start, end)));
+ }
+ },
+ {
+ name: "basicGet",
+ runTest: function(t){
+ // set the cookie
+ var n = "dojo_test";
+ var v = "foofoo";
+ document.cookie = n + "=" + v;
+
+ t.is(v, dojo.cookie(n));
+ }
+ },
+ {
+ name: "daysAsNumber",
+ runTest: function(t){
+ // set a cookie with a numerical expires
+ dojo.cookie("dojo_num", "foo", { expires: 10 });
+ t.is("foo", dojo.cookie("dojo_num"));
+
+ // remove the cookie by setting it with a negative
+ // numerical expires. value doesn't really matter here
+ dojo.cookie("dojo_num", "-deleted-", { expires: -10 });
+ t.is(null, dojo.cookie("dojo_num"));
+ }
+ },
+ {
+ name: "nameSuffix",
+ runTest: function(t){
+ // set two cookies with the same suffix
+ dojo.cookie("user", "123", { expires: 10 });
+ dojo.cookie("xuser", "abc", { expires: 10 });
+ t.is("123", dojo.cookie("user"));
+ t.is("abc", dojo.cookie("xuser"));
+
+ // remove the cookie by setting it with a negative
+ // numerical expires. value doesn't really matter here
+ dojo.cookie("user", "-deleted-", { expires: -10 });
+ t.is(null, dojo.cookie("user"));
+ dojo.cookie("xuser", "-deleted-", { expires: -10 });
+ t.is(null, dojo.cookie("xuser"));
+ }
+ }
+ ]
+ );
+ doh.run();
+ });
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/cookie.js b/includes/js/dojo/tests/cookie.js
new file mode 100644
index 0000000..46cd519
--- /dev/null
+++ b/includes/js/dojo/tests/cookie.js
@@ -0,0 +1,8 @@
+if(!dojo._hasResource["tests.cookie"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.cookie"] = true;
+dojo.provide("tests.cookie");
+if(dojo.isBrowser){
+ doh.registerUrl("tests.cookie", dojo.moduleUrl("tests", "cookie.html"));
+}
+
+}
diff --git a/includes/js/dojo/tests/currency.js b/includes/js/dojo/tests/currency.js
new file mode 100644
index 0000000..8375725
--- /dev/null
+++ b/includes/js/dojo/tests/currency.js
@@ -0,0 +1,48 @@
+if(!dojo._hasResource["tests.currency"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.currency"] = true;
+dojo.provide("tests.currency");
+
+dojo.require("dojo.currency");
+
+tests.register("tests.currency",
+ [
+ {
+ // Test formatting and parsing of currencies in various locales pre-built in dojo.cldr
+ // NOTE: we can't set djConfig.extraLocale before bootstrapping unit tests, so directly
+ // load resources here for specific locales:
+
+ name: "currency",
+ setUp: function(){
+ var partLocaleList = ["en-us", "en-ca", "de-de"];
+ for(var i = 0 ; i < partLocaleList.length; i ++){
+ dojo.requireLocalization("dojo.cldr","currency",partLocaleList[i], "zh,en-ca,pt,en-us,de,ja,en,en-au,ROOT,fr,es,ko,zh-tw,it");
+ dojo.requireLocalization("dojo.cldr","number",partLocaleList[i], "zh-cn,zh,ko-kr,pt,en-us,en-gb,de,ja,ja-jp,en,ROOT,en-au,fr,es,ko,zh-tw,it,es-es,de-de");
+ }
+ },
+ runTest: function(t){
+ t.is("\u20ac123.45", dojo.currency.format(123.45, {currency: "EUR", locale: "en-us"}));
+ t.is("$123.45", dojo.currency.format(123.45, {currency: "USD", locale: "en-us"}));
+ t.is("$1,234.56", dojo.currency.format(1234.56, {currency: "USD", locale: "en-us"}));
+ t.is("US$123.45", dojo.currency.format(123.45, {currency: "USD", locale: "en-ca"}));
+ t.is("$123.45", dojo.currency.format(123.45, {currency: "CAD", locale: "en-ca"}));
+ t.is("Can$123.45", dojo.currency.format(123.45, {currency: "CAD", locale: "en-us"}));
+ t.is("123,45 \u20ac", dojo.currency.format(123.45, {currency: "EUR", locale: "de-de"}));
+ t.is("1.234,56 \u20ac", dojo.currency.format(1234.56, {currency: "EUR", locale: "de-de"}));
+ // There is no special currency symbol for ADP, so expect the ISO code instead
+ t.is("ADP123", dojo.currency.format(123, {currency: "ADP", locale: "en-us"}));
+
+ t.is(123.45, dojo.currency.parse("$123.45", {currency: "USD", locale: "en-us"}));
+ t.is(1234.56, dojo.currency.parse("$1,234.56", {currency: "USD", locale: "en-us"}));
+ t.is(123.45, dojo.currency.parse("123,45 \u20ac", {currency: "EUR", locale: "de-de"}));
+ t.is(1234.56, dojo.currency.parse("1.234,56 \u20ac", {currency: "EUR", locale: "de-de"}));
+ t.is(1234.56, dojo.currency.parse("1.234,56\u20ac", {currency: "EUR", locale: "de-de"}));
+
+ t.is(1234, dojo.currency.parse("$1,234", {currency: "USD", locale: "en-us"}));
+ t.is(1234, dojo.currency.parse("$1,234", {currency: "USD", fractional: false, locale: "en-us"}));
+ t.t(isNaN(dojo.currency.parse("$1,234", {currency: "USD", fractional: true, locale: "en-us"})));
+ }
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/data.js b/includes/js/dojo/tests/data.js
new file mode 100644
index 0000000..6556236
--- /dev/null
+++ b/includes/js/dojo/tests/data.js
@@ -0,0 +1,12 @@
+if(!dojo._hasResource["tests.data"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.data"] = true;
+dojo.provide("tests.data");
+//Squelch any json comment messages for now, since the UT allows for both.
+dojo.config.usePlainJson = true;
+dojo.require("tests.data.utils");
+dojo.require("tests.data.ItemFileReadStore");
+dojo.require("tests.data.ItemFileWriteStore");
+
+
+
+}
diff --git a/includes/js/dojo/tests/data/ItemFileReadStore.js b/includes/js/dojo/tests/data/ItemFileReadStore.js
new file mode 100644
index 0000000..19d37da
--- /dev/null
+++ b/includes/js/dojo/tests/data/ItemFileReadStore.js
@@ -0,0 +1,10 @@
+if(!dojo._hasResource["tests.data.ItemFileReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.data.ItemFileReadStore"] = true;
+dojo.provide("tests.data.ItemFileReadStore");
+dojo.require("tests.data.readOnlyItemFileTestTemplates");
+dojo.require("dojo.data.ItemFileReadStore");
+
+tests.data.readOnlyItemFileTestTemplates.registerTestsForDatastore("dojo.data.ItemFileReadStore");
+
+
+}
diff --git a/includes/js/dojo/tests/data/ItemFileWriteStore.js b/includes/js/dojo/tests/data/ItemFileWriteStore.js
new file mode 100644
index 0000000..9dd938e
--- /dev/null
+++ b/includes/js/dojo/tests/data/ItemFileWriteStore.js
@@ -0,0 +1,1402 @@
+if(!dojo._hasResource["tests.data.ItemFileWriteStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.data.ItemFileWriteStore"] = true;
+dojo.provide("tests.data.ItemFileWriteStore");
+dojo.require("tests.data.readOnlyItemFileTestTemplates");
+
+dojo.require("dojo.data.ItemFileWriteStore");
+dojo.require("dojo.data.api.Read");
+dojo.require("dojo.data.api.Identity");
+dojo.require("dojo.data.api.Write");
+dojo.require("dojo.data.api.Notification");
+
+
+// First, make sure ItemFileWriteStore can still pass all the same unit tests
+// that we use for its superclass, ItemFileReadStore:
+tests.data.readOnlyItemFileTestTemplates.registerTestsForDatastore("dojo.data.ItemFileWriteStore");
+
+tests.data.ItemFileWriteStore.getTestData = function(name){
+ var data = {};
+ if(name === "reference_integrity"){
+ if(dojo.isBrowser){
+ data = {url: dojo.moduleUrl("tests", "data/reference_integrity.json").toString() };
+ }else{
+ data =
+ { data: {
+ "identifier": "id",
+ "label": "name",
+ "items": [
+ {"id": 1, "name": "Item 1"},
+ {"id": 2, "name": "Item 2"},
+ {"id": 3, "name": "Item 3"},
+ {"id": 4, "name": "Item 4"},
+ {"id": 5, "name": "Item 5"},
+ {"id": 6, "name": "Item 6"},
+ {"id": 7, "name": "Item 7"},
+ {"id": 8, "name": "Item 8"},
+ {"id": 9, "name": "Item 9"},
+ {"id": 10, "name": "Item 10", "friends": [{"_reference": 1},{"_reference": 3},{"_reference": 5}]},
+ {"id": 11, "name": "Item 11", "friends": [{"_reference": 10}], "siblings": [{"_reference": 10}]},
+ {"id": 12, "name": "Item 12", "friends": [{"_reference": 3},{"_reference": 7}], "enemies": [{"_reference": 10}]},
+ {"id": 13, "name": "Item 13", "friends": [{"_reference": 10}]},
+ {"id": 14, "name": "Item 14", "friends": [{"_reference": 11}]},
+ {"id": 15, "name": "item 15", "friends": [{"id": 16, "name": "Item 16"}]}
+ ]
+ }
+ }
+ }
+ }
+ return data;
+};
+
+
+// Now run some tests that are specific to the write-access features:
+doh.register("tests.data.ItemFileWriteStore",
+ [
+ function test_getFeatures(){
+ // summary:
+ // Simple test of the getFeatures function of the store
+ // description:
+ // Simple test of the getFeatures function of the store
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var features = store.getFeatures();
+
+ // make sure we have the expected features:
+ doh.assertTrue(features["dojo.data.api.Read"] != null);
+ doh.assertTrue(features["dojo.data.api.Identity"] != null);
+ doh.assertTrue(features["dojo.data.api.Write"] != null);
+ doh.assertTrue(features["dojo.data.api.Notification"] != null);
+ doh.assertFalse(features["iggy"]);
+
+ // and only the expected features:
+ var count = 0;
+ for(var i in features){
+ doh.assertTrue((i === "dojo.data.api.Read" ||
+ i === "dojo.data.api.Identity" ||
+ i === "dojo.data.api.Write" ||
+ i === "dojo.data.api.Notification"));
+ count++;
+ }
+ doh.assertEqual(count, 4);
+ },
+ function testWriteAPI_setValue(){
+ // summary:
+ // Simple test of the setValue API
+ // description:
+ // Simple test of the setValue API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ function onComplete(items, request){
+ doh.assertEqual(1, items.length);
+ var item = items[0];
+ doh.assertTrue(store.containsValue(item, "capital", "Cairo"));
+
+ // FIXME:
+ // Okay, so this seems very odd. Maybe I'm just being dense.
+ // These tests works:
+ doh.assertEqual(store.isDirty(item), false);
+ doh.assertTrue(store.isDirty(item) == false);
+ // But these seemingly equivalent tests will not work:
+ // doh.assertFalse(store.isDirty(item));
+ // doh.assertTrue(!(store.isDirty(item)));
+ //
+ // All of which seems especially weird, given that this *does* work:
+ doh.assertFalse(store.isDirty());
+
+
+ doh.assertTrue(store.isDirty(item) == false);
+ doh.assertTrue(!store.isDirty());
+ store.setValue(item, "capital", "New Cairo");
+ doh.assertTrue(store.isDirty(item));
+ doh.assertTrue(store.isDirty());
+ doh.assertEqual(store.getValue(item, "capital").toString(), "New Cairo");
+ deferred.callback(true);
+ }
+ function onError(error, request){
+ deferred.errback(error);
+ }
+ store.fetch({query:{name:"Egypt"}, onComplete: onComplete, onError: onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_setValues(){
+ // summary:
+ // Simple test of the setValues API
+ // description:
+ // Simple test of the setValues API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ function onComplete(items, request){
+ doh.assertEqual(1, items.length);
+ var item = items[0];
+ doh.assertTrue(store.containsValue(item, "name", "Egypt"));
+ doh.assertTrue(store.isDirty(item) == false);
+ doh.assertTrue(!store.isDirty());
+ store.setValues(item, "name", ["Egypt 1", "Egypt 2"]);
+ doh.assertTrue(store.isDirty(item));
+ doh.assertTrue(store.isDirty());
+ var values = store.getValues(item, "name");
+ doh.assertTrue(values[0] == "Egypt 1");
+ doh.assertTrue(values[1] == "Egypt 2");
+ deferred.callback(true);
+ }
+ function onError(error, request){
+ deferred.errback(error);
+ }
+ store.fetch({query:{name:"Egypt"}, onComplete: onComplete, onError: onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_unsetAttribute(){
+ // summary:
+ // Simple test of the unsetAttribute API
+ // description:
+ // Simple test of the unsetAttribute API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ function onComplete(items, request) {
+ doh.assertEqual(1, items.length);
+ var item = items[0];
+ doh.assertTrue(store.containsValue(item, "name", "Egypt"));
+ doh.assertTrue(store.isDirty(item) == false);
+ doh.assertTrue(!store.isDirty());
+ store.unsetAttribute(item, "name");
+ doh.assertTrue(store.isDirty(item));
+ doh.assertTrue(store.isDirty());
+ doh.assertTrue(!store.hasAttribute(item, "name"));
+ deferred.callback(true);
+ }
+ function onError(error, request) {
+ deferred.errback(error);
+ }
+ store.fetch({query:{name:"Egypt"}, onComplete: onComplete, onError: onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_newItem(){
+ // summary:
+ // Simple test of the newItem API
+ // description:
+ // Simple test of the newItem API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ doh.assertTrue(!store.isDirty());
+
+ var onNewInvoked = false;
+ store.onNew = function(newItem, parentInfo){
+
+ doh.assertTrue(newItem !== null);
+ doh.assertTrue(parentInfo === null);
+ doh.assertTrue(store.isItem(newItem));
+ onNewInvoked = true;
+ };
+ var canada = store.newItem({name: "Canada", abbr:"ca", capital:"Ottawa"});
+ doh.assertTrue(onNewInvoked);
+
+ doh.assertTrue(store.isDirty(canada));
+ doh.assertTrue(store.isDirty());
+ doh.assertTrue(store.getValues(canada, "name") == "Canada");
+ function onComplete(items, request){
+ doh.assertEqual(1, items.length);
+ var item = items[0];
+ doh.assertTrue(store.containsValue(item, "name", "Canada"));
+ deferred.callback(true);
+ }
+ function onError(error, request){
+ deferred.errback(error);
+ }
+ store.fetch({query:{name:"Canada"}, onComplete: onComplete, onError: onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_newItem_withParent(){
+ // summary:
+ // Simple test of the newItem API with a parent assignment
+ // description:
+ // Simple test of the newItem API with a parent assignment
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ doh.assertTrue(!store.isDirty());
+ function onComplete(items, request){
+ doh.assertEqual(1, items.length);
+ var item = items[0];
+ doh.assertTrue(store.containsValue(item, "name", "Egypt"));
+
+ //Attach an onNew to validate we get expected values.
+ var onNewInvoked = false;
+ store.onNew = function(newItem, parentInfo){
+ doh.assertEqual(item, parentInfo.item);
+ doh.assertEqual("cities", parentInfo.attribute);
+ doh.assertTrue(parentInfo.oldValue === undefined);
+ doh.assertTrue(parentInfo.newValue === newItem);
+ onNewInvoked = true;
+ };
+
+ //Attach an onSet and verify onSet is NOT called in this case.
+ store.onSet = function(item, attribute, oldValue, newValue){
+ doh.assertTrue(false);
+ };
+
+ //See if we can add in a new item representing the city of Cairo.
+ //This should also call the onNew set above....
+ var newItem = store.newItem({name: "Cairo", abbr: "Cairo"}, {parent: item, attribute: "cities"});
+ doh.assertTrue(onNewInvoked);
+
+ function onCompleteNewItemShallow(items, request){
+ doh.assertEqual(0, items.length);
+ function onCompleteNewItemDeep(items, request){
+ doh.assertEqual(1, items.length);
+ var item = items[0];
+ doh.assertEqual("Cairo", store.getValue(item, "name"));
+ deferred.callback(true);
+ }
+ //Do a deep search now, should find the new item of the city with name attribute Cairo.
+ store.fetch({query:{name:"Cairo"}, onComplete: onCompleteNewItemDeep, onError: onError, queryOptions: {deep:true}});
+ }
+ //Do a shallow search first, should find nothing.
+ store.fetch({query:{name:"Cairo"}, onComplete: onCompleteNewItemShallow, onError: onError});
+ }
+ function onError(error, request){
+ deferred.errback(error);
+ }
+ store.fetch({query:{name:"Egypt"}, onComplete: onComplete, onError: onError});
+ return deferred; //Object
+ },
+
+ function testWriteAPI_newItem_multiple_withParent(){
+ // summary:
+ // Simple test of the newItem API with a parent assignment multiple times.
+ // description:
+ // Simple test of the newItem API with a parent assignment multiple times.
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+
+ doh.assertTrue(!store.isDirty());
+
+ function onComplete(items, request){
+ doh.assertEqual(1, items.length);
+ var item = items[0];
+ doh.assertTrue(store.containsValue(item, "name", "Egypt"));
+
+ //Attach an onNew to validate we get expected values.
+ store.onNew = function(newItem, parentInfo){
+ doh.assertEqual(item, parentInfo.item);
+ doh.assertEqual("cities", parentInfo.attribute);
+
+ doh.assertTrue(parentInfo.oldValue === undefined);
+
+ doh.assertTrue(parentInfo.newValue === newItem);
+ };
+
+ //See if we can add in a new item representing the city of Cairo.
+ //This should also call the onNew set above....
+ var newItem1 = store.newItem({name: "Cairo", abbr: "Cairo"}, {parent: item, attribute: "cities"});
+
+ //Attach a new onNew to validate we get expected values.
+ store.onNew = function(newItem, parentInfo){
+ doh.assertEqual(item, parentInfo.item);
+ doh.assertEqual("cities", parentInfo.attribute);
+
+ console.log(parentInfo.oldValue);
+ doh.assertTrue(parentInfo.oldValue == newItem1);
+
+ doh.assertTrue(parentInfo.newValue[0] == newItem1);
+ doh.assertTrue(parentInfo.newValue[1] == newItem);
+ };
+ var newItem2 = store.newItem({name: "Banha", abbr: "Banha"}, {parent: item, attribute: "cities"});
+
+ //Attach a new onNew to validate we get expected values.
+ store.onNew = function(newItem, parentInfo){
+ doh.assertEqual(item, parentInfo.item);
+ doh.assertEqual("cities", parentInfo.attribute);
+
+ doh.assertTrue(parentInfo.oldValue[0] == newItem1);
+ doh.assertTrue(parentInfo.oldValue[1] == newItem2);
+
+ doh.assertTrue(parentInfo.newValue[0] == newItem1);
+ doh.assertTrue(parentInfo.newValue[1] == newItem2);
+ doh.assertTrue(parentInfo.newValue[2] == newItem);
+ };
+ var newItem3 = store.newItem({name: "Damanhur", abbr: "Damanhur"}, {parent: item, attribute: "cities"});
+ deferred.callback(true);
+ }
+ function onError(error, request){
+ deferred.errback(error);
+ }
+ store.fetch({query:{name:"Egypt"}, onComplete: onComplete, onError: onError});
+ return deferred; //Object
+ },
+
+ function testWriteAPI_deleteItem(){
+ // summary:
+ // Simple test of the deleteItem API
+ // description:
+ // Simple test of the deleteItem API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ function onComplete(items, request){
+ doh.assertEqual(1, items.length);
+ var item = items[0];
+ doh.assertTrue(store.containsValue(item, "name", "Egypt"));
+ doh.assertTrue(store.isDirty(item) == false);
+ doh.assertTrue(!store.isDirty());
+ store.deleteItem(item);
+ doh.assertTrue(store.isDirty(item));
+ doh.assertTrue(store.isDirty());
+ function onCompleteToo(itemsToo, requestToo) {
+ doh.assertEqual(0, itemsToo.length);
+ deferred.callback(true);
+ }
+ store.fetch({query:{name:"Egypt"}, onComplete: onCompleteToo, onError: onError});
+ }
+ function onError(error, request){
+ deferred.errback(error);
+ }
+ store.fetch({query:{name:"Egypt"}, onComplete: onComplete, onError: onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_isDirty(){
+ // summary:
+ // Simple test of the isDirty API
+ // description:
+ // Simple test of the isDirty API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ function onComplete(items, request) {
+ doh.assertEqual(1, items.length);
+ var item = items[0];
+ doh.assertTrue(store.containsValue(item, "name", "Egypt"));
+ store.setValue(item, "name", "Egypt 2");
+ doh.assertTrue(store.getValue(item, "name") == "Egypt 2");
+ doh.assertTrue(store.isDirty(item));
+ deferred.callback(true);
+ }
+ function onError(error, request) {
+ deferred.errback(error);
+ }
+ store.fetch({query:{name:"Egypt"}, onComplete: onComplete, onError: onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_revert(){
+ // summary:
+ // Simple test of the revert API
+ // description:
+ // Simple test of the revert API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ function onComplete(items, request) {
+ doh.assertEqual(1, items.length);
+ var item = items[0];
+ doh.assertTrue(store.containsValue(item, "name", "Egypt"));
+ doh.assertTrue(store.isDirty(item) == false);
+ doh.assertTrue(!store.isDirty());
+ store.setValue(item, "name", "Egypt 2");
+ doh.assertTrue(store.getValue(item, "name") == "Egypt 2");
+ doh.assertTrue(store.isDirty(item));
+ doh.assertTrue(store.isDirty());
+ store.revert();
+
+ //Fetch again to see if it reset the state.
+ function onCompleteToo(itemsToo, requestToo){
+ doh.assertEqual(1, itemsToo.length);
+ var itemToo = itemsToo[0];
+ doh.assertTrue(store.containsValue(itemToo, "name", "Egypt"));
+ deferred.callback(true);
+ }
+ store.fetch({query:{name:"Egypt"}, onComplete: onCompleteToo, onError: onError});
+ }
+ function onError(error, request){
+ deferred.errback(error);
+ }
+ store.fetch({query:{name:"Egypt"}, onComplete: onComplete, onError: onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_save(){
+ // summary:
+ // Simple test of the save API
+ // description:
+ // Simple test of the save API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ function onError(error){
+ deferred.errback(error);
+ }
+ function onItem(item){
+ store.setValue(item, "capital", "New Cairo");
+ function onComplete() {
+ deferred.callback(true);
+ }
+ store.save({onComplete:onComplete, onError:onError});
+ }
+ store.fetchItemByIdentity({identity:"eg", onItem:onItem, onError:onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_saveVerifyState(){
+ // summary:
+ // Simple test of the save API
+ // description:
+ // Simple test of the save API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ function onError(error){
+ deferred.errback(error);
+ }
+ function onItem(item){
+ store.setValue(item, "capital", "New Cairo");
+ function onComplete() {
+ //Check internal state. Note: Users should NOT do this, this is a UT verification
+ //of internals in this case. Ref tracker: #4394
+ doh.assertTrue(!store._saveInProgress);
+ deferred.callback(true);
+ }
+ store.save({onComplete:onComplete, onError:onError});
+ }
+ store.fetchItemByIdentity({identity:"eg", onItem:onItem, onError:onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_saveEverything(){
+ // summary:
+ // Simple test of the save API
+ // description:
+ // Simple test of the save API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+ var egypt;
+ store._saveEverything = function(saveCompleteCallback, saveFailedCallback, newFileContentString){
+ var struct = dojo.fromJson(newFileContentString);
+ doh.assertEqual(struct.identifier, store.getIdentityAttributes(egypt)[0]);
+ doh.assertEqual(struct.label, store.getLabelAttributes(egypt)[0]);
+ doh.assertEqual(struct.items.length, 7);
+
+ var cloneStore = new dojo.data.ItemFileWriteStore({data:struct});
+ function onItemClone(itemClone){
+ var egyptClone = itemClone;
+ doh.assertEqual(store.getIdentityAttributes(egypt)[0], cloneStore.getIdentityAttributes(egyptClone)[0]);
+ doh.assertEqual(store.getLabelAttributes(egypt)[0], cloneStore.getLabelAttributes(egyptClone)[0]);
+ doh.assertEqual(store.getValue(egypt, "name"), cloneStore.getValue(egyptClone, "name"));
+ }
+ cloneStore.fetchItemByIdentity({identity:"eg", onItem:onItemClone, onError:onError});
+
+ saveCompleteCallback();
+ };
+
+ var deferred = new doh.Deferred();
+ function onError(error){
+ deferred.errback(error);
+ }
+ function onItem(item){
+ egypt = item;
+ function onComplete() {
+ deferred.callback(true);
+ }
+ store.setValue(egypt, "capital", "New Cairo");
+ store.save({onComplete:onComplete, onError:onError});
+ }
+ store.fetchItemByIdentity({identity:"eg", onItem:onItem, onError:onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_saveEverything_withDateType(){
+ // summary:
+ // Simple test of the save API with a non-atomic type (Date) that has a type mapping.
+ // description:
+ // Simple test of the save API with a non-atomic type (Date) that has a type mapping.
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+ store._saveEverything = function(saveCompleteCallback, saveFailedCallback, newFileContentString){
+
+ //Now load the new data into a datastore and validate that it stored the date right.
+ var dataset = dojo.fromJson(newFileContentString);
+ var newStore = new dojo.data.ItemFileWriteStore({data: dataset});
+
+ function gotItem(item){
+ var independenceDate = newStore.getValue(item,"independence");
+ doh.assertTrue(independenceDate instanceof Date);
+ doh.assertTrue(dojo.date.compare(new Date(1993,04,24), independenceDate, "date") === 0);
+ saveCompleteCallback();
+ }
+ function failed(error, request){
+ deferred.errback(error);
+ saveFailedCallback();
+ }
+ newStore.fetchItemByIdentity({identity:"eg", onItem:gotItem, onError:failed});
+ };
+
+ var deferred = new doh.Deferred();
+ function onError(error){
+ deferred.errback(error);
+ }
+ function onItem(item){
+ function onComplete() {
+ deferred.callback(true);
+ }
+ store.setValue(item, "independence", new Date(1993,04,24));
+ store.save({onComplete:onComplete, onError:onError});
+ }
+ store.fetchItemByIdentity({identity:"eg", onItem:onItem, onError:onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_saveEverything_withCustomColorTypeSimple(){
+ // summary:
+ // Simple test of the save API with a non-atomic type (dojo.Color) that has a type mapping.
+ // description:
+ // Simple test of the save API with a non-atomic type (dojo.Color) that has a type mapping.
+
+ //Set up the store basics: What data it has, and what to do when save is called for saveEverything
+ //And how to map the 'Color' type in and out of the format.
+ //(Test of saving all to a some location...)
+ var dataset = {
+ identifier:'name',
+ items: [
+ { name:'Kermit', species:'frog', color:{_type:'Color', _value:'green'} },
+ { name:'Beaker', hairColor:{_type:'Color', _value:'red'} }
+ ]
+ };
+
+ var customTypeMap = {'Color': dojo.Color };
+
+ var store = new dojo.data.ItemFileWriteStore({
+ data:dataset,
+ typeMap: customTypeMap
+ });
+
+ store._saveEverything = function(saveCompleteCallback, saveFailedCallback, newFileContentString){
+ //Now load the new data into a datastore and validate that it stored the Color right.
+ var dataset = dojo.fromJson(newFileContentString);
+ var newStore = new dojo.data.ItemFileWriteStore({data: dataset, typeMap: customTypeMap});
+
+ function gotItem(item){
+ var hairColor = newStore.getValue(item,"hairColor");
+ doh.assertTrue(hairColor instanceof dojo.Color);
+ doh.assertEqual("rgba(255, 255, 0, 1)", hairColor.toString());
+ saveCompleteCallback();
+ }
+ function failed(error, request){
+ deferred.errback(error);
+ saveFailedCallback();
+ }
+ newStore.fetchItemByIdentity({identity:"Animal", onItem:gotItem, onError:failed});
+ };
+
+ //Add a new item with a color type, then save it.
+ var deferred = new doh.Deferred();
+ function onError(error){
+ deferred.errback(error);
+ }
+ function onComplete() {
+ deferred.callback(true);
+ }
+
+ var animal = store.newItem({name: "Animal", hairColor: new dojo.Color("yellow")});
+ store.save({onComplete:onComplete, onError:onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_saveEverything_withCustomColorTypeGeneral(){
+ // summary:
+ // Simple test of the save API with a non-atomic type (dojo.Color) that has a type mapping.
+ // description:
+ // Simple test of the save API with a non-atomic type (dojo.Color) that has a type mapping.
+
+ //Set up the store basics: What data it has, and what to do when save is called for saveEverything
+ //And how to map the 'Color' type in and out of the format.
+ //(Test of saving all to a some location...)
+ var dataset = {
+ identifier:'name',
+ items: [
+ { name:'Kermit', species:'frog', color:{_type:'Color', _value:'green'} },
+ { name:'Beaker', hairColor:{_type:'Color', _value:'red'} }
+ ]
+ };
+
+ var customTypeMap = {'Color': {
+ type: dojo.Color,
+ deserialize: function(value){
+ return new dojo.Color(value);
+ },
+ serialize: function(obj){
+ return obj.toString();
+ }
+ }
+ }
+ var store = new dojo.data.ItemFileWriteStore({
+ data:dataset,
+ typeMap: customTypeMap
+ });
+ store._saveEverything = function(saveCompleteCallback, saveFailedCallback, newFileContentString){
+ //Now load the new data into a datastore and validate that it stored the Color right.
+ var dataset = dojo.fromJson(newFileContentString);
+ var newStore = new dojo.data.ItemFileWriteStore({data: dataset, typeMap: customTypeMap});
+
+ function gotItem(item){
+ var hairColor = newStore.getValue(item,"hairColor");
+ doh.assertTrue(hairColor instanceof dojo.Color);
+ doh.assertEqual("rgba(255, 255, 0, 1)", hairColor.toString());
+ saveCompleteCallback();
+ }
+ function failed(error, request){
+ deferred.errback(error);
+ saveFailedCallback();
+ }
+ newStore.fetchItemByIdentity({identity:"Animal", onItem:gotItem, onError:failed});
+ };
+
+ //Add a new item with a color type, then save it.
+ var deferred = new doh.Deferred();
+ function onError(error){
+ deferred.errback(error);
+ }
+ function onComplete() {
+ deferred.callback(true);
+ }
+
+ var animal = store.newItem({name: "Animal", hairColor: new dojo.Color("yellow")});
+ store.save({onComplete:onComplete, onError:onError});
+ return deferred; //Object
+ },
+ function testWriteAPI_newItem_revert(){
+ // summary:
+ // Test for bug #5357. Ensure that the revert properly nulls the identity position
+ // for a new item after revert.
+ var args = {data: {
+ label:"name",
+ items:[
+ {name:'Ecuador', capital:'Quito'},
+ {name:'Egypt', capital:'Cairo'},
+ {name:'El Salvador', capital:'San Salvador'},
+ {name:'Equatorial Guinea', capital:'Malabo'},
+ {name:'Eritrea', capital:'Asmara'},
+ {name:'Estonia', capital:'Tallinn'},
+ {name:'Ethiopia', capital:'Addis Ababa'}
+ ]
+ } };
+ var store = new dojo.data.ItemFileWriteStore(args);
+
+ var newCountry = store.newItem({name: "Utopia", capitol: "Perfect"});
+
+ //DO NOT ACCESS THIS WAY. THESE ARE INTERNAL VARIABLES. DOING THIS FOR TEST PURPOSES.
+ var itemEntryNum = newCountry[store._itemNumPropName];
+ doh.assertTrue(store._arrayOfAllItems[itemEntryNum] === newCountry);
+ store.revert();
+ doh.assertTrue(store._arrayOfAllItems[itemEntryNum] === null);
+ },
+ function testNotificationAPI_onSet(){
+ // summary:
+ // Simple test of the onSet API
+ // description:
+ // Simple test of the onSet API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ function onError(error){
+ deferred.errback(error);
+ }
+ function onItem(fetchedItem){
+ var egypt = fetchedItem;
+ var connectHandle = null;
+ function setValueHandler(item, attribute, oldValue, newValue){
+ doh.assertTrue(store.isItem(item));
+ doh.assertTrue(item == egypt);
+ doh.assertTrue(attribute == "capital");
+ doh.assertTrue(oldValue == "Cairo");
+ doh.assertTrue(newValue == "New Cairo");
+ deferred.callback(true);
+ dojo.disconnect(connectHandle);
+ }
+ connectHandle = dojo.connect(store, "onSet", setValueHandler);
+ store.setValue(egypt, "capital", "New Cairo");
+ }
+ store.fetchItemByIdentity({identity:"eg", onItem:onItem, onError:onError});
+ },
+ function testNotificationAPI_onNew(){
+ // summary:
+ // Simple test of the onNew API
+ // description:
+ // Simple test of the onNew API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ var connectHandle = null;
+ function newItemHandler(item){
+ doh.assertTrue(store.isItem(item));
+ doh.assertTrue(store.getValue(item, "name") == "Canada");
+ deferred.callback(true);
+ dojo.disconnect(connectHandle);
+ }
+ connectHandle = dojo.connect(store, "onNew", newItemHandler);
+ var canada = store.newItem({name:"Canada", abbr:"ca", capital:"Ottawa"});
+ },
+ function testNotificationAPI_onDelete(){
+ // summary:
+ // Simple test of the onDelete API
+ // description:
+ // Simple test of the onDelete API
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var deferred = new doh.Deferred();
+ function onError(error){
+ deferred.errback(error);
+ }
+ function onItem(fetchedItem){
+ var egypt = fetchedItem;
+ var connectHandle = null;
+ function deleteItemHandler(item){
+ doh.assertTrue(store.isItem(item) == false);
+ doh.assertTrue(item == egypt);
+ deferred.callback(true);
+ dojo.disconnect(connectHandle);
+ }
+ connectHandle = dojo.connect(store, "onDelete", deleteItemHandler);
+ store.deleteItem(egypt);
+ }
+ store.fetchItemByIdentity({identity:"eg", onItem:onItem, onError:onError});
+ },
+ function testReadAPI_functionConformanceToo(){
+ // 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 dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+ var readApi = new dojo.data.api.Read();
+ var passed = true;
+
+ for(var functionName in readApi){
+ var member = readApi[functionName];
+ //Check that all the 'Read' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[functionName];
+ if(!(typeof testStoreMember === "function")){
+ passed = false;
+ break;
+ }
+ }
+ }
+ doh.assertTrue(passed);
+ },
+ function testWriteAPI_functionConformance(){
+ // 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 = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+ var writeApi = new dojo.data.api.Write();
+ var passed = true;
+
+ for(var functionName in writeApi){
+ var member = writeApi[functionName];
+ //Check that all the 'Write' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[functionName];
+ if(!(typeof testStoreMember === "function")){
+ passed = false;
+ break;
+ }
+ }
+ }
+ doh.assertTrue(passed);
+ },
+ function testNotificationAPI_functionConformance(){
+ // summary:
+ // Simple test Notification API conformance. Checks to see all declared functions are actual functions on the instances.
+ // description:
+ // Simple test Notification API conformance. Checks to see all declared functions are actual functions on the instances.
+ var testStore = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+ var api = new dojo.data.api.Notification();
+ var passed = true;
+
+ for(var functionName in api){
+ var member = api[functionName];
+ //Check that all the 'Write' defined functions exist on the test store.
+ if(typeof member === "function"){
+ var testStoreMember = testStore[functionName];
+ if(!(typeof testStoreMember === "function")){
+ passed = false;
+ break;
+ }
+ }
+ }
+ doh.assertTrue(passed);
+ },
+ function testIdentityAPI_noIdentifierSpecified(){
+ // summary:
+ // Test for bug #3873. Given a datafile that does not specify an
+ // identifier, make sure ItemFileWriteStore auto-creates identities
+ // that are unique even after calls to deleteItem() and newItem()
+ var args = {data: {
+ label:"name",
+ items:[
+ {name:'Ecuador', capital:'Quito'},
+ {name:'Egypt', capital:'Cairo'},
+ {name:'El Salvador', capital:'San Salvador'},
+ {name:'Equatorial Guinea', capital:'Malabo'},
+ {name:'Eritrea', capital:'Asmara'},
+ {name:'Estonia', capital:'Tallinn'},
+ {name:'Ethiopia', capital:'Addis Ababa'}
+ ]
+ } };
+ var store = new dojo.data.ItemFileWriteStore(args);
+ var deferred = new doh.Deferred();
+
+ var onError = function(error, request){
+ deferred.errback(error);
+ }
+ var onComplete = function(items, request){
+ doh.assertEqual(7, items.length);
+
+ var lastItem = items[(items.length - 1)];
+ var idOfLastItem = store.getIdentity(lastItem);
+ store.deleteItem(lastItem);
+ store.newItem({name:'Canada', capital:'Ottawa'});
+
+ var onCompleteAgain = function(itemsAgain, requestAgain){
+ doh.assertEqual(7, itemsAgain.length);
+ var identitiesInUse = {};
+ for(var i = 0; i < itemsAgain.length; ++i){
+ var item = itemsAgain[i];
+ var id = store.getIdentity(item);
+ if(identitiesInUse.hasOwnProperty(id)){
+ // there should not already be an entry for this id
+ doh.assertTrue(false);
+ }else{
+ // we want to add the entry now
+ identitiesInUse[id] = item;
+ }
+ }
+ deferred.callback(true);
+ }
+ store.fetch({onComplete:onCompleteAgain, onError:onError});
+ }
+
+ store.fetch({onComplete:onComplete, onError:onError});
+ return deferred;
+ },
+ function testIdentityAPI_noIdentifierSpecified_revert(){
+ // summary:
+ // Test for bug #4691 Given a datafile that does not specify an
+ // identifier, make sure ItemFileWriteStore auto-creates identities
+ // that are unique even after calls to deleteItem() and newItem()
+ var args = {data: {
+ label:"name",
+ items:[
+ {name:'Ecuador', capital:'Quito'},
+ {name:'Egypt', capital:'Cairo'},
+ {name:'El Salvador', capital:'San Salvador'},
+ {name:'Equatorial Guinea', capital:'Malabo'},
+ {name:'Eritrea', capital:'Asmara'},
+ {name:'Estonia', capital:'Tallinn'},
+ {name:'Ethiopia', capital:'Addis Ababa'}
+ ]
+ } };
+ var store = new dojo.data.ItemFileWriteStore(args);
+ var deferred = new doh.Deferred();
+
+ var onError = function(error, request){
+ deferred.errback(error);
+ }
+ var onComplete = function(items, request){
+ doh.assertEqual(7, items.length);
+
+ var lastItem = items[(items.length - 1)];
+ var idOfLastItem = store.getIdentity(lastItem);
+ store.deleteItem(lastItem);
+ store.newItem({name:'Canada', capital:'Ottawa'});
+
+ var onCompleteAgain = function(itemsAgain, requestAgain){
+ doh.assertEqual(7, itemsAgain.length);
+ var identitiesInUse = {};
+ for(var i = 0; i < itemsAgain.length; ++i){
+ var item = itemsAgain[i];
+ var id = store.getIdentity(item);
+ if(identitiesInUse.hasOwnProperty(id)){
+ // there should not already be an entry for this id
+ doh.assertTrue(false);
+ }else{
+ // we want to add the entry now
+ identitiesInUse[id] = item;
+ }
+ }
+ //Last test, revert everything and check item sizes.
+ store.revert();
+
+ //Now call fetch again and verify store state.
+ var revertComplete = function(itemsReverted, request){
+ doh.assertEqual(7, itemsReverted.length);
+ deferred.callback(true);
+ }
+ store.fetch({onComplete:revertComplete, onError:onError});
+ }
+ store.fetch({onComplete:onCompleteAgain, onError:onError});
+ }
+ store.fetch({onComplete:onComplete, onError:onError});
+ return deferred;
+ },
+ function testReferenceIntegrity_checkReferences(){
+ // summary:
+ // Simple test to verify the references were properly resolved.
+ // description:
+ // Simple test to verify the references were properly resolved.
+
+ var store = new dojo.data.ItemFileWriteStore(tests.data.ItemFileWriteStore.getTestData("reference_integrity"));
+
+ var deferred = new doh.Deferred();
+ function onError(error, request){
+ deferred.errback(error);
+ }
+ function onComplete(items, request){
+
+ var item10 = null;
+ var item1 = null;
+ var item3 = null;
+ var item5 = null;
+
+ for (var i = 0; i < items.length; i++) {
+ var ident = store.getIdentity(items[i]);
+ if (ident === 10) {
+ item10 = items[i];
+ }else if (ident === 1) {
+ item1 = items[i];
+ }else if (ident === 3) {
+ item3 = items[i];
+ }else if (ident === 5) {
+ item5 = items[i];
+ }
+ }
+ var friends = store.getValues(item10, "friends");
+ doh.assertTrue(friends !== null);
+ doh.assertTrue(friends !== undefined);
+
+ doh.assertTrue(store.isItem(item10));
+ doh.assertTrue(store.isItem(item1));
+ doh.assertTrue(store.isItem(item3));
+ doh.assertTrue(store.isItem(item5));
+ var found = 0;
+ try{
+ for (var i = 0; i < friends.length; i++) {
+ if (i === 0) {
+ doh.assertTrue(store.isItem(friends[i]));
+ doh.assertEqual(friends[i], item1);
+ doh.assertEqual(store.getIdentity(friends[i]), 1);
+ found++;
+ }else if (i === 1) {
+ doh.assertTrue(store.isItem(friends[i]));
+ doh.assertEqual(friends[i], item3);
+ doh.assertEqual(store.getIdentity(friends[i]), 3);
+ found++;
+ }else if (i === 2) {
+ doh.assertTrue(store.isItem(friends[i]));
+ doh.assertEqual(friends[i], item5);
+ doh.assertEqual(store.getIdentity(friends[i]), 5);
+ found++;
+ }
+ }
+ }catch(e){
+ doh.errback(e);
+ }
+ doh.assertEqual(3, found);
+ deferred.callback(true);
+ }
+ store.fetch({onError: onError, onComplete: onComplete});
+ return deferred;
+ },
+ function testReferenceIntegrity_deleteReferencedItem(){
+ // summary:
+ // Simple test to verify the references were properly deleted.
+ // description:
+ // Simple test to verify the references were properly deleted.
+
+ var store = new dojo.data.ItemFileWriteStore(tests.data.ItemFileWriteStore.getTestData("reference_integrity"));
+
+ var deferred = new doh.Deferred();
+ var passed = true;
+ function onError(error, request){
+ deferred.errback(error);
+ }
+ function onItem(item, request){
+ try{
+ console.log("Before delete map state is: " + dojo.toJson(item[store._reverseRefMap]));
+ store.deleteItem(item);
+ console.log("After delete map state is: " + dojo.toJson(item[store._reverseRefMap]));
+ function verifyRefDelete(items, request){
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var curItem = items[i];
+ var attributes = store.getAttributes(curItem);
+ for(var j = 0; j < attributes.length; j++){
+ var values = store.getValues(curItem, attributes[j]);
+ var badRef = false;
+ for(var k = 0; k < values.length; k++){
+ var value = values[k];
+ try{
+ var id = store.getIdentity(value);
+ if(id == 10){
+ badRef = true;
+ break;
+ }
+ }catch(e){/*Not an item, even a dead one, just eat it.*/}
+ }
+ if(badRef){
+ deferred.errback(new Error("Found a reference remaining to a deleted item. Failure."));
+ passed = false;
+ break;
+ }
+ }
+ }
+ if(passed){
+ deferred.callback(true);
+ }
+ }
+ store.fetch({onComplete: verifyRefDelete, onError: onError});
+ }catch(error){
+ deferred.errback(error);
+ }
+ }
+ store.fetchItemByIdentity({identity: 10, onError: onError, onItem: onItem});
+ return deferred;
+ },
+ function testReferenceIntegrity_deleteReferencedItemThenRevert(){
+ // summary:
+ // Simple test to verify the references were properly deleted.
+ // description:
+ // Simple test to verify the references were properly deleted.
+
+ var store = new dojo.data.ItemFileWriteStore(tests.data.ItemFileWriteStore.getTestData("reference_integrity"));
+
+ var deferred = new doh.Deferred();
+ var passed = true;
+ function onError(error, request){
+ deferred.errback(error);
+ }
+ function onItem(item, request){
+ try{
+ //DO NOT EVER ACCESS THESE VARIABLES LIKE THIS!
+ //THIS IS FOR TESTING INTERNAL STATE!
+ console.log("Map before delete:");
+ store._dumpReferenceMap();
+ var beforeDelete = dojo.toJson(item[store._reverseRefMap]);
+ store.deleteItem(item);
+ console.log("Map after delete:");
+ store._dumpReferenceMap();
+ var afterDelete = dojo.toJson(item[store._reverseRefMap]);
+ store.revert();
+ console.log("Map after revert:");
+ store._dumpReferenceMap();
+ var afterRevert = dojo.toJson(item[store._reverseRefMap]);
+ doh.assertTrue(afterRevert === beforeDelete);
+ }catch(e){
+ deferred.errback(e);
+ passed = false;
+ }
+ if(passed){
+ deferred.callback(true);
+ }
+ }
+ store.fetchItemByIdentity({identity: 10, onError: onError, onItem: onItem});
+ return deferred;
+ },
+ function testReferenceIntegrity_deleteMultipleItemsWithReferencesAndRevert(){
+ // summary:
+ // Simple test to verify that a flow of deleting items with references and reverting does not damage the internal structure.
+ // Created for tracker bug: #5743
+ // description:
+ // Simple test to verify that a flow of deleting items with references and reverting does not damage the internal structure.
+ // Created for tracker bug: #5743
+
+ var store = new dojo.data.ItemFileWriteStore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries_references"));
+
+ var deferred = new doh.Deferred();
+ var passed = true;
+ function onError(error, request){
+ deferred.errback(error);
+ doh.assertTrue(false);
+ }
+ function onItem(item, request){
+ //Save off the located item, then locate another one (peer to Egypt)
+ doh.assertTrue(store.isItem(item));
+ var egypt = item;
+
+ function onItem2(item, request){
+ doh.assertTrue(store.isItem(item));
+ var nairobi = item;
+
+ //Delete them
+ store.deleteItem(egypt);
+ store.deleteItem(nairobi);
+ try{
+ //Revert, then do a fetch. If the internals have been damaged, this will generally
+ //cause onError to fire instead of onComplete.
+ store.revert();
+ function onComplete(items, request){
+ deferred.callback(true);
+ }
+ store.fetch({query: {name: "*"}, start: 0, count: 20, onComplete: onComplete, onError: onError});
+ }catch(e){
+ deferred.errback(e)
+ }
+ }
+ store.fetchItemByIdentity({identity: "Nairobi", onError: onError, onItem: onItem2});
+ }
+ store.fetchItemByIdentity({identity: "Egypt", onError: onError, onItem: onItem});
+ return deferred;
+ },
+ function testReferenceIntegrity_removeReferenceFromAttribute(){
+ // summary:
+ // Simple test to verify the reference removal updates the internal map.
+ // description:
+ // Simple test to verify the reference removal updates the internal map.
+
+ var store = new dojo.data.ItemFileWriteStore(tests.data.ItemFileWriteStore.getTestData("reference_integrity"));
+
+ var deferred = new doh.Deferred();
+ var passed = true;
+ function onError(error, request){
+ deferred.errback(error);
+ doh.assertTrue(false);
+ }
+ function onItem(item, request){
+ try{
+ store.setValues(item, "friends", [null]);
+
+ function onItem2(item10, request){
+ //DO NOT EVER ACCESS THESE VARIABLES LIKE THIS!
+ //THIS IS FOR TESTING INTERNAL STATE!
+ var refMap = item10[store._reverseRefMap];
+ store._dumpReferenceMap();
+
+ console.log("MAP for Item 10 is: " + dojo.toJson(refMap));
+
+ //Assert there is no reference to item 10 in item 11's attribute 'friends'.
+ doh.assertTrue(!refMap["11"]["friends"]);
+ store.setValues(item, "siblings", [0, 1, 2]);
+ //Assert there are no more references to 10 in 11. Ergo, "11" should be a 'undefined' attribute for the map of items referencing '10'..
+ doh.assertTrue(!refMap["11"]);
+ deferred.callback(true);
+ }
+ store.fetchItemByIdentity({identity: 10, onError: onError, onItem: onItem2});
+
+ }catch(e){
+ console.debug(e);
+ deferred.errback(e);
+ doh.assertTrue(false);
+ }
+ }
+ store.fetchItemByIdentity({identity: 11, onError: onError, onItem: onItem});
+ return deferred;
+ },
+ function testReferenceIntegrity_deleteReferencedItemNonParent(){
+ // summary:
+ // Simple test to verify the references to a non-parent item was properly deleted.
+ // description:
+ // Simple test to verify the references to a non-parent item was properly deleted.
+
+ var store = new dojo.data.ItemFileWriteStore(tests.data.ItemFileWriteStore.getTestData("reference_integrity"));
+
+ var deferred = new doh.Deferred();
+ var passed = true;
+ function onError(error, request){
+ deferred.errback(error);
+ }
+ function onItem(item, request){
+ try{
+ console.log("Reference state for item 16 is: " + dojo.toJson(item[store._reverseRefMap]));
+ store.deleteItem(item);
+ function verifyRefDelete(items, request){
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var curItem = items[i];
+ var attributes = store.getAttributes(curItem);
+ for(var j = 0; j < attributes.length; j++){
+ var values = store.getValues(curItem, attributes[j]);
+ var badRef = false;
+ for(var k = 0; k < values.length; k++){
+ var value = values[k];
+ try{
+ var id = store.getIdentity(value);
+ if(id == 16){
+ badRef = true;
+ break;
+ }
+ }catch(e){/*Not an item, even a dead one, just eat it.*/}
+ }
+ if(badRef){
+ deferred.errback(new Error("Found a reference remaining to a deleted item. Failure."));
+ passed = false;
+ break;
+ }
+ }
+ }
+ if(passed){
+ deferred.callback(true);
+ }
+ }
+ store.fetch({onComplete: verifyRefDelete, onError: onError});
+ }catch(error){
+ deferred.errback(error);
+ }
+ }
+ store.fetchItemByIdentity({identity: 16, onError: onError, onItem: onItem});
+ return deferred;
+ },
+ function testReferenceIntegrity_addReferenceToAttribute(){
+ // summary:
+ // Simple test to verify the reference additions can happen.
+ // description:
+ // Simple test to verify the reference additions can happen.
+
+ var store = new dojo.data.ItemFileWriteStore(tests.data.ItemFileWriteStore.getTestData("reference_integrity"));
+
+ var deferred = new doh.Deferred();
+ var passed = true;
+ function onError(error, request){
+ deferred.errback(error);
+ doh.assertTrue(false);
+ }
+ function onComplete(items, request){
+
+ doh.assertTrue(items.length > 2);
+
+ var item1 = items[0];
+ var item2 = items[1];
+
+ //DO NOT EVER ACCESS THESE VARIABLES LIKE THIS!
+ //THIS IS FOR TESTING INTERNAL STATE!
+ console.log("Map state for Item 1 is: " + dojo.toJson(item1[store._reverseRefMap]));
+ console.log("Map state for Item 2 is: " + dojo.toJson(item2[store._reverseRefMap]));
+
+ store.setValue(item1, "siblings", item2);
+
+ //Emit the current map state for inspection.
+ console.log("Map state for Item 1 is: " + dojo.toJson(item1[store._reverseRefMap]));
+ console.log("Map state for Item 2 is: " + dojo.toJson(item2[store._reverseRefMap]));
+
+ doh.assertTrue(item2[store._reverseRefMap] != null);
+
+ //Assert there is a recorded reference to item 2 in item 1's attribute 'sibling'.
+ doh.assertTrue(item2[store._reverseRefMap][store.getIdentity(item1)]["siblings"]);
+
+ deferred.callback(true);
+ }
+ store.fetch({onError: onError, onComplete: onComplete});
+ return deferred;
+ },
+ function testReferenceIntegrity_newItemWithParentReference(){
+ // summary:
+ // Simple test to verify that newItems with a parent properly record the parent's reference in the map.
+ // description:
+ // Simple test to verify that newItems with a parent properly record the parent's reference in the map.
+
+ var store = new dojo.data.ItemFileWriteStore(tests.data.ItemFileWriteStore.getTestData("reference_integrity"));
+
+ var deferred = new doh.Deferred();
+ var passed = true;
+ function onError(error, request){
+ deferred.errback(error);
+ doh.assertTrue(false);
+ }
+ function onItem(item, request){
+ try{
+ //Create a new item and set its parent to item 10's uncle attribute.
+ var newItem = store.newItem({id: 17, name: "Item 17"}, {parent: item, attribute: "uncles"});
+
+ //DO NOT EVER ACCESS THESE VARIABLES LIKE THIS!
+ //THIS IS FOR TESTING INTERNAL STATE!
+ //Look up the references to 17, as item 10 has one now on attribute 'uncles'
+ var refs = newItem[store._reverseRefMap];
+
+ //Assert there is a reference from 10 to item 17, on attribute uncle
+ doh.assertTrue(refs["10"]["uncles"]);
+
+ console.log("State of map of item 17 after newItem: " + dojo.toJson(refs));
+ }catch(e){
+ console.debug(e);
+ deferred.errback(e);
+ doh.assertTrue(false);
+ passed = false;
+ }
+ if(passed){
+ deferred.callback(true);
+ }
+ }
+ store.fetchItemByIdentity({identity: 10, onError: onError, onItem: onItem});
+ return deferred;
+ },
+ function testReferenceIntegrity_newItemWithReferenceToExistingItem(){
+ // summary:
+ // Simple test to verify that a new item with references to existing items properly record the references in the map.
+ // description:
+ // Simple test to verify that a new item with references to existing items properly record the references in the map.
+
+ var store = new dojo.data.ItemFileWriteStore(tests.data.ItemFileWriteStore.getTestData("reference_integrity"));
+
+ var deferred = new doh.Deferred();
+ var passed = true;
+ function onError(error, request){
+ deferred.errback(error);
+ doh.assertTrue(false);
+ }
+ function onItem(item, request){
+ try{
+ //DO NOT EVER ACCESS THESE VARIABLES LIKE THIS!
+ //THIS IS FOR TESTING INTERNAL STATE!
+ console.log("State of reference map to item 10 before newItem: " + dojo.toJson(item[store._reverseRefMap]));
+
+ //Create a new item and set its parent to item 10's uncle attribute.
+ var newItem = store.newItem({id: 17, name: "Item 17", friends: [item]});
+
+ //DO NOT EVER ACCESS THESE VARIABLES LIKE THIS!
+ //THIS IS FOR TESTING INTERNAL STATE!
+ //Look up the references to 10, as item 17 has one on friends now.
+ var refs = item[store._reverseRefMap];
+
+ //Assert there is a reference from 15 to item 10, on attribute friends
+ doh.assertTrue(refs["17"]["friends"]);
+
+ console.log("State of reference map to item 10 after newItem: " + dojo.toJson(refs));
+ }catch(e){
+ console.debug(e);
+ deferred.errback(e);
+ doh.assertTrue(false);
+ passed = false;
+ }
+ if(passed){
+ deferred.callback(true);
+ }
+ }
+ store.fetchItemByIdentity({identity: 10, onError: onError, onItem: onItem});
+ return deferred;
+ },
+ function testReferenceIntegrity_disableReferenceIntegrity(){
+ // summary:
+ // Simple test to verify reference integrity can be disabled.
+ // description:
+ // Simple test to verify reference integrity can be disabled.
+
+ var params = tests.data.ItemFileWriteStore.getTestData("reference_integrity");
+ params.referenceIntegrity = false;
+ var store = new dojo.data.ItemFileWriteStore(params);
+
+ var deferred = new doh.Deferred();
+ function onError(error, request){
+ deferred.errback(error);
+ doh.assertTrue(false);
+ }
+ function onItem(item, request){
+ //DO NOT EVER ACCESS THESE VARIABLES LIKE THIS!
+ //THIS IS FOR TESTING INTERNAL STATE!
+ if(item[store._reverseRefMap] === undefined){
+ deferred.callback(true);
+ }else{
+ deferred.errback(new Error("Disabling of reference integrity failed."));
+ }
+ }
+ store.fetchItemByIdentity({identity: 10, onError: onError, onItem: onItem});
+ return deferred;
+ }
+ ]
+);
+
+
+
+}
diff --git a/includes/js/dojo/tests/data/countries.json b/includes/js/dojo/tests/data/countries.json
new file mode 100644
index 0000000..71631da
--- /dev/null
+++ b/includes/js/dojo/tests/data/countries.json
@@ -0,0 +1,11 @@
+{ identifier: 'abbr',
+ label: 'name',
+ items: [
+ { abbr:'ec', name:'Ecuador', capital:'Quito' },
+ { abbr:'eg', name:'Egypt', capital:'Cairo' },
+ { abbr:'sv', name:'El Salvador', capital:'San Salvador' },
+ { abbr:'gq', name:'Equatorial Guinea', capital:'Malabo' },
+ { abbr:'er', name:'Eritrea', capital:'Asmara' },
+ { abbr:'ee', name:'Estonia', capital:'Tallinn' },
+ { abbr:'et', name:'Ethiopia', capital:'Addis Ababa' }
+]}
diff --git a/includes/js/dojo/tests/data/countries_commentFiltered.json b/includes/js/dojo/tests/data/countries_commentFiltered.json
new file mode 100644
index 0000000..319e429
--- /dev/null
+++ b/includes/js/dojo/tests/data/countries_commentFiltered.json
@@ -0,0 +1,12 @@
+/*
+{ identifier: 'abbr',
+ items: [
+ { abbr:'ec', name:'Ecuador', capital:'Quito' },
+ { abbr:'eg', name:'Egypt', capital:'Cairo' },
+ { abbr:'sv', name:'El Salvador', capital:'San Salvador' },
+ { abbr:'gq', name:'Equatorial Guinea', capital:'Malabo' },
+ { abbr:'er', name:'Eritrea', capital:'Asmara' },
+ { abbr:'ee', name:'Estonia', capital:'Tallinn' },
+ { abbr:'et', name:'Ethiopia', capital:'Addis Ababa' }
+]}
+*/
diff --git a/includes/js/dojo/tests/data/countries_idcollision.json b/includes/js/dojo/tests/data/countries_idcollision.json
new file mode 100644
index 0000000..a0c4a7b
--- /dev/null
+++ b/includes/js/dojo/tests/data/countries_idcollision.json
@@ -0,0 +1,10 @@
+{ identifier: 'abbr',
+ items: [
+ { abbr:'ec', name:'Ecuador', capital:'Quito' },
+ { abbr:'sv', name:'El Salvador', capital:'San Salvador' },
+ { abbr:'gq', name:'Equatorial Guinea', capital:'Malabo' },
+ { abbr:'er', name:'Eritrea', capital:'Asmara' },
+ { abbr:'ec', name:'Egypt', capital:'Cairo' },
+ { abbr:'ee', name:'Estonia', capital:'Tallinn' },
+ { abbr:'et', name:'Ethiopia', capital:'Addis Ababa' }
+]}
diff --git a/includes/js/dojo/tests/data/countries_references.json b/includes/js/dojo/tests/data/countries_references.json
new file mode 100644
index 0000000..136f3c2
--- /dev/null
+++ b/includes/js/dojo/tests/data/countries_references.json
@@ -0,0 +1,44 @@
+{ 'identifier': 'name',
+ 'label': '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/dojo/tests/data/countries_withBoolean.json b/includes/js/dojo/tests/data/countries_withBoolean.json
new file mode 100644
index 0000000..783d8a8
--- /dev/null
+++ b/includes/js/dojo/tests/data/countries_withBoolean.json
@@ -0,0 +1,11 @@
+{ identifier: 'abbr',
+ items: [
+ { abbr:'ec', name:'Ecuador', capital:'Quito', real:true},
+ { abbr:'eg', name:'Egypt', capital:'Cairo', real:true},
+ { abbr:'sv', name:'El Salvador', capital:'San Salvador', real:true},
+ { abbr:'gq', name:'Equatorial Guinea', capital:'Malabo', real:true},
+ { abbr:'er', name:'Eritrea', capital:'Asmara', real:true},
+ { abbr:'ee', name:'Estonia', capital:'Tallinn', real:true},
+ { abbr:'et', name:'Ethiopia', capital:'Addis Ababa', real:true},
+ { abbr:'ut', name:'Utopia', capital:'Paradise', real:false}
+]}
diff --git a/includes/js/dojo/tests/data/countries_withDates.json b/includes/js/dojo/tests/data/countries_withDates.json
new file mode 100644
index 0000000..fdd2153
--- /dev/null
+++ b/includes/js/dojo/tests/data/countries_withDates.json
@@ -0,0 +1,21 @@
+{ identifier: 'abbr',
+ label: 'name',
+ items: [
+ { abbr:'ec', name:'Ecuador', capital:'Quito' },
+ { abbr:'eg', name:'Egypt', capital:'Cairo' },
+ { abbr:'sv', name:'El Salvador', capital:'San Salvador' },
+ { abbr:'gq', name:'Equatorial Guinea', capital:'Malabo' },
+ { abbr:'er',
+ name:'Eritrea',
+ capital:'Asmara',
+ independence:{_type:'Date', _value:"1993-05-24T00:00:00Z"} // May 24, 1993 in ISO-8601 standard
+ },
+ { abbr:'ee',
+ name:'Estonia',
+ capital:'Tallinn',
+ independence:{_type:'Date', _value:"1991-08-20T00:00:00Z"} // August 20, 1991 in ISO-8601 standard
+ },
+ { abbr:'et',
+ name:'Ethiopia',
+ capital:'Addis Ababa' }
+]}
diff --git a/includes/js/dojo/tests/data/countries_withNull.json b/includes/js/dojo/tests/data/countries_withNull.json
new file mode 100644
index 0000000..a0a7a3f
--- /dev/null
+++ b/includes/js/dojo/tests/data/countries_withNull.json
@@ -0,0 +1,10 @@
+{ identifier: 'abbr',
+ items: [
+ { abbr:'ec', name:null, capital:'Quito' },
+ { abbr:'eg', name:null, capital:'Cairo' },
+ { abbr:'sv', name:'El Salvador', capital:'San Salvador' },
+ { abbr:'gq', name:'Equatorial Guinea', capital:'Malabo' },
+ { abbr:'er', name:'Eritrea', capital:'Asmara' },
+ { abbr:'ee', name:null, capital:'Tallinn' },
+ { abbr:'et', name:'Ethiopia', capital:'Addis Ababa' }
+]}
diff --git a/includes/js/dojo/tests/data/countries_withoutid.json b/includes/js/dojo/tests/data/countries_withoutid.json
new file mode 100644
index 0000000..8db3046
--- /dev/null
+++ b/includes/js/dojo/tests/data/countries_withoutid.json
@@ -0,0 +1,10 @@
+{ label: 'name',
+ items: [
+ { abbr:'ec', name:'Ecuador', capital:'Quito' },
+ { abbr:'eg', name:'Egypt', capital:'Cairo' },
+ { abbr:'sv', name:'El Salvador', capital:'San Salvador' },
+ { abbr:'gq', name:'Equatorial Guinea', capital:'Malabo' },
+ { abbr:'er', name:'Eritrea', capital:'Asmara' },
+ { abbr:'ee', name:'Estonia', capital:'Tallinn' },
+ { abbr:'et', name:'Ethiopia', capital:'Addis Ababa' }
+]}
diff --git a/includes/js/dojo/tests/data/data_multitype.json b/includes/js/dojo/tests/data/data_multitype.json
new file mode 100644
index 0000000..449995a
--- /dev/null
+++ b/includes/js/dojo/tests/data/data_multitype.json
@@ -0,0 +1,18 @@
+{
+ "identifier": "count",
+ "label": "count",
+ "items": [
+ { "count": 1, "value": "true" },
+ { "count": 2, "value": true },
+ { "count": 3, "value": "false"},
+ { "count": 4, "value": false },
+ { "count": 5, "value": true },
+ { "count": 6, "value": true },
+ { "count": 7, "value": "true" },
+ { "count": 8, "value": "true" },
+ { "count": 9, "value": "false"},
+ { "count": 10, "value": false },
+ { "count": 11, "value": [false, false]},
+ { "count": "12", "value": [false, "true"]}
+ ]
+}
diff --git a/includes/js/dojo/tests/data/geography_hierarchy_large.json b/includes/js/dojo/tests/data/geography_hierarchy_large.json
new file mode 100644
index 0000000..71fd29b
--- /dev/null
+++ b/includes/js/dojo/tests/data/geography_hierarchy_large.json
@@ -0,0 +1,44 @@
+{ identifier: '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/dojo/tests/data/geography_hierarchy_small.json b/includes/js/dojo/tests/data/geography_hierarchy_small.json
new file mode 100644
index 0000000..989e5f7
--- /dev/null
+++ b/includes/js/dojo/tests/data/geography_hierarchy_small.json
@@ -0,0 +1,19 @@
+{ items:[
+ { name:'Africa', countries:[
+ { name:'Egypt', capital:'Cairo' },
+ { name:'Kenya', capital:'Nairobi' },
+ { name:'Sudan', capital:'Khartoum' }]},
+ { name:'Australia', capital:'Canberra' },
+ { name:'North America', countries:[
+ { name:'Canada', population:'33 million', cities:[
+ { name:'Toronto', population:'2.5 million' },
+ { name:'Alberta', population:'1 million' }
+ ]},
+ { name: 'United States of America', capital: 'Washington DC', states:[
+ { name: 'Missouri'},
+ { name: 'Arkansas'}
+ ]}
+ ]}
+ ]
+}
+
diff --git a/includes/js/dojo/tests/data/readOnlyItemFileTestTemplates.js b/includes/js/dojo/tests/data/readOnlyItemFileTestTemplates.js
new file mode 100644
index 0000000..7e194b4
--- /dev/null
+++ b/includes/js/dojo/tests/data/readOnlyItemFileTestTemplates.js
@@ -0,0 +1,2260 @@
+if(!dojo._hasResource["tests.data.readOnlyItemFileTestTemplates"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.data.readOnlyItemFileTestTemplates"] = true;
+dojo.provide("tests.data.readOnlyItemFileTestTemplates");
+dojo.require("dojo.data.api.Read");
+dojo.require("dojo.data.api.Identity");
+dojo.require("dojo.date");
+dojo.require("dojo.date.stamp");
+
+
+tests.data.readOnlyItemFileTestTemplates.registerTestsForDatastore = function(/* String */ datastoreClassName){
+ // summary:
+ // Given the name of a datastore class to use, this function creates
+ // a set of unit tests for that datastore, and registers the new test
+ // group with the doh test framework. The new unit tests are based
+ // on a set of "template" unit tests.
+ var datastoreClass = dojo.getObject(datastoreClassName);
+ var testTemplates = tests.data.readOnlyItemFileTestTemplates.testTemplates;
+ var testsForDatastore = [];
+ var makeNewTestFunction = function(template){
+ return function(t){return template.runTest(datastoreClass, t);};
+ };
+ for(var i = 0; i < testTemplates.length; ++i) {
+ var testTemplate = testTemplates[i];
+ var test = {};
+ test.name = testTemplate.name;
+ test.runTest = makeNewTestFunction(testTemplate);
+ testsForDatastore.push(test);
+ }
+ var testGroupName = "tests.data.readOnlyItemFileTestTemplates, with datastore " + datastoreClassName;
+ doh.register(testGroupName, testsForDatastore);
+};
+
+
+//-----------------------------------------------------
+// testFile data-sets
+tests.data.readOnlyItemFileTestTemplates.getTestData = function(name){
+ var data = null;
+ if(name === "countries"){
+ if(dojo.isBrowser){
+ data = {url: dojo.moduleUrl("tests", "data/countries.json").toString() };
+ }else{
+ data = {data: {
+ identifier:"abbr",
+ label:"name",
+ items:[
+ {abbr:"ec", name:"Ecuador", capital:"Quito"},
+ {abbr:'eg', name:'Egypt', capital:'Cairo'},
+ {abbr:'sv', name:'El Salvador', capital:'San Salvador'},
+ {abbr:'gq', name:'Equatorial Guinea', capital:'Malabo'},
+ {abbr:'er', name:'Eritrea', capital:'Asmara'},
+ {abbr:'ee', name:'Estonia', capital:'Tallinn'},
+ {abbr:'et', name:'Ethiopia', capital:'Addis Ababa'}
+ ]
+ } };
+ }
+ }else if(name === "countries_withNull"){
+ if(dojo.isBrowser){
+ data = {url: dojo.moduleUrl("tests", "data/countries_withNull.json").toString() };
+ }else{
+ data = {data: {
+ identifier:"abbr",
+ items:[
+ {abbr:"ec", name:null, capital:"Quito"},
+ {abbr:'eg', name:null, capital:'Cairo'},
+ {abbr:'sv', name:'El Salvador', capital:'San Salvador'},
+ {abbr:'gq', name:'Equatorial Guinea', capital:'Malabo'},
+ {abbr:'er', name:'Eritrea', capital:'Asmara'},
+ {abbr:'ee', name:null, capital:'Tallinn'},
+ {abbr:'et', name:'Ethiopia', capital:'Addis Ababa'}
+ ]
+ } };
+ }
+ }else if(name === "countries_withoutid"){
+ if(dojo.isBrowser){
+ data = {url: dojo.moduleUrl("tests", "data/countries_withoutid.json").toString() };
+ }else{
+ data = {data: {
+ label: "name",
+ items:[
+ {abbr:"ec", name:null, capital:"Quito"},
+ {abbr:'eg', name:null, capital:'Cairo'},
+ {abbr:'sv', name:'El Salvador', capital:'San Salvador'},
+ {abbr:'gq', name:'Equatorial Guinea', capital:'Malabo'},
+ {abbr:'er', name:'Eritrea', capital:'Asmara'},
+ {abbr:'ee', name:null, capital:'Tallinn'},
+ {abbr:'et', name:'Ethiopia', capital:'Addis Ababa'}
+ ]
+ } };
+ }
+ }else if (name === "countries_withBoolean"){
+ if(dojo.isBrowser){
+ data = {url: dojo.moduleUrl("tests", "data/countries_withBoolean.json").toString() };
+ }else{
+ data = {data: {
+ identifier:"abbr",
+ items:[
+ {abbr:"ec", name:"Ecuador", capital:"Quito", real:true},
+ {abbr:'eg', name:'Egypt', capital:'Cairo', real:true},
+ {abbr:'sv', name:'El Salvador', capital:'San Salvador', real:true},
+ {abbr:'gq', name:'Equatorial Guinea', capital:'Malabo', real:true},
+ {abbr:'er', name:'Eritrea', capital:'Asmara', real:true},
+ {abbr:'ee', name:'Estonia', capital:'Tallinn', real:true},
+ {abbr:'et', name:'Ethiopia', capital:'Addis Ababa', real:true},
+ {abbr:'ut', name:'Utopia', capital:'Paradise', real:false}
+ ]
+ } };
+ }
+ }else if (name === "countries_withDates"){
+ if(dojo.isBrowser){
+ data = {url: dojo.moduleUrl("tests", "data/countries_withDates.json").toString() };
+ }else{
+ data = {data: {
+ identifier:"abbr",
+ items:[
+ {abbr:"ec", name:"Ecuador", capital:"Quito"},
+ {abbr:'eg', name:'Egypt', capital:'Cairo'},
+ {abbr:'sv', name:'El Salvador', capital:'San Salvador'},
+ {abbr:'gq', name:'Equatorial Guinea', capital:'Malabo'},
+ {abbr:'er', name:'Eritrea', capital:'Asmara', independence:{_type:'Date', _value:"1993-05-24T00:00:00Z"}}, // May 24, 1993,
+ {abbr:'ee', name:'Estonia', capital:'Tallinn', independence:{_type:'Date', _value:"1991-08-20T00:00:00Z"}}, // August 20, 1991
+ {abbr:'et', name:'Ethiopia', capital:'Addis Ababa'}
+ ]
+ } };
+ }
+ }else if (name === "geography_hierarchy_small"){
+ if(dojo.isBrowser){
+ data = {url: dojo.moduleUrl("tests", "data/geography_hierarchy_small.json").toString() };
+ }else{
+ data = {data: {
+ items:[
+ { name:'Africa', countries:[
+ { name:'Egypt', capital:'Cairo' },
+ { name:'Kenya', capital:'Nairobi' },
+ { name:'Sudan', capital:'Khartoum' }]},
+ { name:'Australia', capital:'Canberra' },
+ { name:'North America', countries:[
+ { name:'Canada', population:'33 million', cities:[
+ { name:'Toronto', population:'2.5 million' },
+ { name:'Alberta', population:'1 million' }
+ ]},
+ { name: 'United States of America', capital: 'Washington DC', states:[
+ { name: 'Missouri'},
+ { name: 'Arkansas'}
+ ]}
+ ]}
+ ]
+ }};
+ }
+ }else if (name === "data_multitype"){
+ if(dojo.isBrowser){
+ data = {url: dojo.moduleUrl("tests", "data/data_multitype.json").toString() };
+ }else{
+ data = {data: {
+ "identifier": "count",
+ "label": "count",
+ items: [
+ { count: 1, value: "true" },
+ { count: 2, value: true },
+ { count: 3, value: "false"},
+ { count: 4, value: false },
+ { count: 5, value: true },
+ { count: 6, value: true },
+ { count: 7, value: "true" },
+ { count: 8, value: "true" },
+ { count: 9, value: "false"},
+ { count: 10, value: false },
+ { count: 11, value: [false, false]},
+ { count: "12", value: [false, "true"]}
+ ]
+ }
+ };
+ }
+ }else if (name === "countries_references"){
+ if(dojo.isBrowser){
+ data = {url: dojo.moduleUrl("tests", "data/countries_references.json").toString() };
+ }else{
+ data = {data: { identifier: 'name',
+ label: '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' }
+ ]
+ }
+ };
+ }
+ }
+ return data;
+};
+
+//-----------------------------------------------------
+// testTemplates
+tests.data.readOnlyItemFileTestTemplates.testTemplates = [
+ {
+ name: "Identity API: fetchItemByIdentity()",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ if(item !== null){
+ var name = store.getValue(item,"name");
+ t.assertEqual(name, "El Salvador");
+ }
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "sv", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Identity API: fetchItemByIdentity() notFound",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item === null);
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "sv_not", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Identity API: getIdentityAttributes()",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the getIdentityAttributes function.
+ // description:
+ // Simple test of the getIdentityAttributes function.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null)
+ var identifiers = store.getIdentityAttributes(item);
+ t.assertTrue(dojo.isArray(identifiers));
+ t.assertEqual(1, identifiers.length);
+ t.assertEqual("abbr", identifiers[0]);
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "sv", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Identity API: fetchItemByIdentity() commentFilteredJson",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store.
+ // This tests loading a comment-filtered json file so that people using secure
+ // data with this store can bypass the JavaSceipt hijack noted in Fortify's
+ // paper.
+
+ if(dojo.isBrowser){
+ var store = new datastore({url: dojo.moduleUrl("tests", "data/countries_commentFiltered.json").toString()});
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ var name = store.getValue(item,"name");
+ t.assertEqual(name, "El Salvador");
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "sv", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ }
+ },
+ {
+ name: "Identity API: fetchItemByIdentity() nullValue",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store, checling a null value.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store, checking a null value.
+ // This tests handling attributes in json that were defined as null properly.
+ // Introduced because of tracker: #3153
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries_withNull"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ var name = store.getValue(item,"name");
+ t.assertEqual(name, null);
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "ec", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Identity API: fetchItemByIdentity() booleanValue",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the fetchItemByIdentity function of the store, checking a boolean value.
+ // description:
+ // Simple test of the fetchItemByIdentity function of the store, checking a boolean value.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries_withBoolean"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ var name = store.getValue(item,"name");
+ t.assertEqual(name, "Utopia");
+ var real = store.getValue(item,"real");
+ t.assertEqual(real, false);
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "ut", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Identity API: fetchItemByIdentity() withoutSpecifiedIdInData",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of bug #4691, looking up something by assigned id, not one specified in the JSON data.
+ // description:
+ // Simple test of bug #4691, looking up something by assigned id, not one specified in the JSON data.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries_withoutid"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ var name = store.getValue(item,"name");
+ t.assertEqual(name, "El Salvador");
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "2", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Identity API: getIdentity()",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the getIdentity function of the store.
+ // description:
+ // Simple test of the getIdentity function of the store.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.assertTrue(store.getIdentity(item) === "sv");
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "sv", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Identity API: getIdentity() withoutSpecifiedId",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the #4691 bug
+ // description:
+ // Simple test of the #4691 bug
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries_withoutid"));
+
+ var d = new doh.Deferred();
+ function onItem(item, request){
+ t.assertTrue(item !== null);
+ t.assertTrue(store.getIdentity(item) === 2);
+ d.callback(true);
+ }
+ function onError(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetch({ query:{abbr: "sv"}, onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Read API: fetch() all",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of a basic fetch on ItemFileReadStore.
+ // description:
+ // Simple test of a basic fetch on ItemFileReadStore.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function completedAll(items, request){
+ t.is(7, items.length);
+ d.callback(true);
+ }
+ function error(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+
+ //Get everything...
+ store.fetch({ onComplete: completedAll, onError: error});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() one",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of a basic fetch on ItemFileReadStore of a single item.
+ // description:
+ // Simple test of a basic fetch on ItemFileReadStore of a single item.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ d.callback(true);
+ }
+ function onError(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetch({ query: {abbr: "ec"},
+ onComplete: onComplete,
+ onError: onError
+ });
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() shallow",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of a basic fetch on ItemFileReadStore of only toplevel items
+ // description:
+ // Simple test of a basic fetch on ItemFileReadStore of only toplevel items.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("geography_hierarchy_small"));
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 2);
+ d.callback(true);
+ }
+ function onError(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ //Find all items starting with A, only toplevel (root) items.
+ store.fetch({ query: {name: "A*"},
+ onComplete: onComplete,
+ onError: onError
+ });
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() Multiple",
+ runTest: function(datastore, t){
+ // summary:
+ // Tests that multiple fetches at the same time queue up properly and do not clobber each other on initial load.
+ // description:
+ // Tests that multiple fetches at the same time queue up properly and do not clobber each other on initial load.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("geography_hierarchy_small"));
+
+ var d = new doh.Deferred();
+ var done = [false, false];
+
+ function onCompleteOne(items, request){
+ done[0] = true;
+ t.assertEqual(items.length, 2);
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+ function onCompleteTwo(items, request){
+ done[1] = true;
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+ function onError(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ //Find all items starting with A, only toplevel (root) items.
+ store.fetch({ query: {name: "A*"},
+ onComplete: onCompleteOne,
+ onError: onError
+ });
+
+ //Find all items starting with A, only toplevel (root) items.
+ store.fetch({ query: {name: "N*"},
+ onComplete: onCompleteTwo,
+ onError: onError
+ });
+
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() MultipleMixedFetch",
+ runTest: function(datastore, t){
+ // summary:
+ // Tests that multiple fetches at the same time queue up properly and do not clobber each other on initial load.
+ // description:
+ // Tests that multiple fetches at the same time queue up properly and do not clobber each other on initial load.
+ // Tests an item fetch and an identity fetch.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ var done = [false, false];
+
+ function onComplete(items, request){
+ done[0] = true;
+ t.assertEqual(items.length, 1);
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+ function onItem(item){
+ done[1] = true;
+ t.assertTrue(item !== null);
+ var name = store.getValue(item,"name");
+ t.assertEqual(name, "El Salvador");
+
+ if(done[0] && done[1]){
+ d.callback(true);
+ }
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+
+ //Find all items starting with A, only toplevel (root) items.
+ store.fetch({ query: {name: "El*"},
+ onComplete: onComplete,
+ onError: onError
+ });
+
+ store.fetchItemByIdentity({identity: "sv", onItem: onItem, onError: onError});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() deep",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of a basic fetch on ItemFileReadStore of all items (including children (nested))
+ // description:
+ // Simple test of a basic fetch on ItemFileReadStore of all items (including children (nested))
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("geography_hierarchy_small"));
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 4);
+ d.callback(true);
+ }
+ function onError(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ //Find all items starting with A, including child (nested) items.
+ store.fetch({ query: {name: "A*"},
+ onComplete: onComplete,
+ onError: onError,
+ queryOptions: {deep:true}
+ });
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() one_commentFilteredJson",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of a basic fetch on ItemFileReadStore of a single item.
+ // description:
+ // Simple test of a basic fetch on ItemFileReadStore of a single item.
+ // This tests loading a comment-filtered json file so that people using secure
+ // data with this store can bypass the JavaSceipt hijack noted in Fortify's
+ // paper.
+ if(dojo.isBrowser){
+ var store = new datastore({url: dojo.moduleUrl("tests", "data/countries_commentFiltered.json").toString()});
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ d.callback(true);
+ }
+ function onError(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetch({ query: {abbr: "ec"},
+ onComplete: onComplete,
+ onError: onError
+ });
+ return d;
+ }
+ }
+ },
+ {
+ name: "Read API: fetch() withNull",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of a basic fetch on ItemFileReadStore of a single item where some attributes are null.
+ // description:
+ // Simple test of a basic fetch on ItemFileReadStore of a single item where some attributes are null.
+ // Introduced because of tracker: #3153
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries_withNull"));
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(4, items.length);
+ d.callback(true);
+ }
+ function onError(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetch({ query: {name: "E*"},
+ onComplete: onComplete,
+ onError: onError
+ });
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() all_streaming",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of a basic fetch on ItemFileReadStore.
+ // description:
+ // Simple test of a basic fetch on ItemFileReadStore.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ count = 0;
+
+ function onBegin(size, requestObj){
+ t.assertEqual(size, 7);
+ }
+ function onItem(item, requestObj){
+ t.assertTrue(store.isItem(item));
+ count++;
+ }
+ function onComplete(items, request){
+ t.assertEqual(count, 7);
+ t.assertTrue(items === null);
+ d.callback(true);
+ }
+ function onError(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+
+ //Get everything...
+ store.fetch({ onBegin: onBegin,
+ onItem: onItem,
+ onComplete: onComplete,
+ onError: onError
+ });
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() paging",
+ runTest: function(datastore, 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 datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function dumpFirstFetch(items, request){
+ t.assertEqual(items.length, 5);
+ request.start = 3;
+ request.count = 1;
+ request.onComplete = dumpSecondFetch;
+ store.fetch(request);
+ }
+
+ function dumpSecondFetch(items, request){
+ t.assertEqual(items.length, 1);
+ request.start = 0;
+ request.count = 5;
+ request.onComplete = dumpThirdFetch;
+ store.fetch(request);
+ }
+
+ function dumpThirdFetch(items, request){
+ t.assertEqual(items.length, 5);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpFourthFetch;
+ store.fetch(request);
+ }
+
+ function dumpFourthFetch(items, request){
+ t.assertEqual(items.length, 5);
+ request.start = 9;
+ request.count = 100;
+ request.onComplete = dumpFifthFetch;
+ store.fetch(request);
+ }
+
+ function dumpFifthFetch(items, request){
+ t.assertEqual(items.length, 0);
+ request.start = 2;
+ request.count = 20;
+ request.onComplete = dumpSixthFetch;
+ store.fetch(request);
+ }
+
+ function dumpSixthFetch(items, request){
+ t.assertEqual(items.length, 5);
+ d.callback(true);
+ }
+
+ function completed(items, request){
+ t.assertEqual(items.length, 7);
+ request.start = 1;
+ request.count = 5;
+ request.onComplete = dumpFirstFetch;
+ store.fetch(request);
+ }
+
+ function error(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetch({onComplete: completed, onError: error});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() with MultiType Match",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of a basic fetch againct an attribute that has different types for the value across items
+ // description:
+ // Simple test of a basic fetch againct an attribute that has different types for the value across items
+ // Introduced because of tracker: #4931
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("data_multitype"));
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(4, items.length);
+ d.callback(true);
+ }
+ function onError(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetch({ query: {count: "1*"},
+ onComplete: onComplete,
+ onError: onError
+ });
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() with MultiType, MultiValue Match",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of a basic fetch againct an attribute that has different types for the value across items
+ // description:
+ // Simple test of a basic fetch againct an attribute that has different types for the value across items
+ // Introduced because of tracker: #4931
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("data_multitype"));
+
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(7, items.length);
+ d.callback(true);
+ }
+ function onError(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetch({ query: {value: "true"},
+ onComplete: onComplete,
+ onError: onError
+ });
+ return d;
+ }
+ },
+ {
+ name: "Read API: getLabel()",
+ runTest: function(datastore, 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 = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ 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("Ecuador", label);
+ d.callback(true);
+ }
+ function onError(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetch({ query: {abbr: "ec"},
+ onComplete: onComplete,
+ onError: onError
+ });
+ return d;
+ }
+ },
+ {
+ name: "Read API: getLabelAttributes()",
+ runTest: function(datastore, 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 = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ 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("name", labelList[0]);
+ d.callback(true);
+ }
+ function onError(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetch({ query: {abbr: "ec"},
+ onComplete: onComplete,
+ onError: onError
+ });
+ return d;
+ }
+ },
+ {
+ name: "Read API: getValue()",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the getValue function of the store.
+ // description:
+ // Simple test of the getValue function of the store.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ var name = store.getValue(item,"name");
+ t.assertTrue(name === "El Salvador");
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "sv", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Read API: getValues()",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the getValues function of the store.
+ // description:
+ // Simple test of the getValues function of the store.
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ var names = store.getValues(item,"name");
+ t.assertTrue(dojo.isArray(names));
+ t.assertEqual(names.length, 1);
+ t.assertEqual(names[0], "El Salvador");
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "sv", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Read API: isItem()",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the isItem function of the store
+ // description:
+ // Simple test of the isItem function of the store
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.assertTrue(store.isItem(item));
+ t.assertTrue(!store.isItem({}));
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "sv", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Read API: isItem() multistore",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the isItem function of the store
+ // to verify two different store instances do not accept
+ // items from each other.
+ // description:
+ // Simple test of the isItem function of the store
+ // to verify two different store instances do not accept
+ // items from each other.
+
+ // Two different instances, even if they read from the same URL
+ // should not accept items between each other!
+ var store1 = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+ var store2 = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function onItem1(item1){
+ t.assertTrue(item1 !== null);
+
+ function onItem2(item2){
+ t.assertTrue(item1 !== null);
+ t.assertTrue(item2 !== null);
+ t.assertTrue(store1.isItem(item1));
+ t.assertTrue(store2.isItem(item2));
+ t.assertTrue(!store1.isItem(item2));
+ t.assertTrue(!store2.isItem(item1));
+ d.callback(true);
+ }
+ store2.fetchItemByIdentity({identity: "sv", onItem: onItem2, onError: onError});
+
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store1.fetchItemByIdentity({identity: "sv", onItem: onItem1, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Read API: hasAttribute()",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the hasAttribute function of the store
+ // description:
+ // Simple test of the hasAttribute function of the store
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.assertTrue(store.hasAttribute(item, "abbr"));
+ t.assertTrue(!store.hasAttribute(item, "abbr_not"));
+
+ //Test that null attributes throw an exception
+ var passed = false;
+ try{
+ store.hasAttribute(item, null);
+ }catch (e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "sv", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Read API: containsValue()",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the containsValue function of the store
+ // description:
+ // Simple test of the containsValue function of the store
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.assertTrue(store.containsValue(item, "abbr", "sv"));
+ t.assertTrue(!store.containsValue(item, "abbr", "sv1"));
+ t.assertTrue(!store.containsValue(item, "abbr", null));
+
+ //Test that null attributes throw an exception
+ var passed = false;
+ try{
+ store.containsValue(item, null, "foo");
+ }catch (e){
+ passed = true;
+ }
+ t.assertTrue(passed);
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "sv", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Read API: getAttributes()",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the getAttributes function of the store
+ // description:
+ // Simple test of the getAttributes function of the store
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ t.assertTrue(store.isItem(item));
+
+ var attributes = store.getAttributes(item);
+ t.assertEqual(attributes.length, 3);
+ for(var i = 0; i < attributes.length; i++){
+ t.assertTrue((attributes[i] === "name" || attributes[i] === "abbr" || attributes[i] === "capital"));
+ }
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity: "sv", onItem: onItem, onError: onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Read API: getFeatures()",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the getFeatures function of the store
+ // description:
+ // Simple test of the getFeatures function of the store
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var features = store.getFeatures();
+ t.assertTrue(features["dojo.data.api.Read"] != null);
+ t.assertTrue(features["dojo.data.api.Identity"] != null);
+ }
+ },
+ {
+ name: "Read API: fetch() patternMatch0",
+ runTest: function(datastore, 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 store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+
+ var d = new doh.Deferred();
+ function completed(items, request) {
+ t.assertEqual(items.length, 5);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "abbr");
+ if(!(value === "ec" || value === "eg" || value === "er" || value === "ee" || value === "et")){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected abbreviation found, match failure."));
+ }
+ }
+ function error(error, request) {
+ t.assertTrue(false);
+ d.errback(error);
+ }
+ store.fetch({query: {abbr: "e*"}, onComplete: completed, onError: error});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() patternMatch1",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test pattern matching of everything with $ in it.
+ // description:
+ // Function to test pattern matching of everything with $ in it.
+
+ var store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 1, value:"foo*bar"},
+ {uniqueId: 2, value:"bar*foo"},
+ {uniqueId: 3, value:"boomBam"},
+ {uniqueId: 4, value:"bit$Bite"},
+ {uniqueId: 5, value:"ouagadogou"},
+ {uniqueId: 6, value:"BaBaMaSaRa***Foo"},
+ {uniqueId: 7, value:"squawl"},
+ {uniqueId: 8, value:"seaweed"},
+ {uniqueId: 9, value:"jfq4@#!$!@Rf14r14i5u"}
+ ]
+ }
+ });
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.assertEqual(items.length, 2);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!(value === "bit$Bite" || value === "jfq4@#!$!@Rf14r14i5u")){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected pattern matched. Filter failure."));
+ }
+ }
+ function error(error, request){
+ t.assertTrue(false);
+ d.errback(error);
+ }
+ store.fetch({query: {value: "*$*"}, onComplete: completed, onError: error});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() patternMatch2",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test exact pattern match
+ // description:
+ // Function to test exact pattern match
+
+ var store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 1, value:"foo*bar"},
+ {uniqueId: 2, value:"bar*foo"},
+ {uniqueId: 3, value:"boomBam"},
+ {uniqueId: 4, value:"bit$Bite"},
+ {uniqueId: 5, value:"ouagadogou"},
+ {uniqueId: 6, value:"BaBaMaSaRa***Foo"},
+ {uniqueId: 7, value:"squawl"},
+ {uniqueId: 8, value:"seaweed"},
+ {uniqueId: 9, value:"jfq4@#!$!@Rf14r14i5u"}
+ ]
+ }
+ });
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.assertEqual(items.length, 1);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!(value === "bar*foo")){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected abbreviation found, match failure."));
+ }
+ }
+ function error(error, request){
+ t.assertTrue(false);
+ d.errback(error);
+ }
+ store.fetch({query: {value: "bar\*foo"}, onComplete: completed, onError: error});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() patternMatch_caseSensitive",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test pattern matching of a pattern case-sensitively
+ // description:
+ // Function to test pattern matching of a pattern case-sensitively
+
+ var store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 1, value:"foo*bar"},
+ {uniqueId: 2, value:"bar*foo"},
+ {uniqueId: 3, value:"BAR*foo"},
+ {uniqueId: 4, value:"BARBananafoo"}
+ ]
+ }
+ });
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.assertEqual(1, items.length);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!(value === "bar*foo")){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected pattern matched. Filter failure."));
+ }
+ }
+ function error(error, request){
+ t.assertTrue(false);
+ d.errback(error);
+ }
+ store.fetch({query: {value: "bar\\*foo"}, queryOptions: {ignoreCase: false} , onComplete: completed, onError: error});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() patternMatch_caseInsensitive",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test pattern matching of a pattern case-insensitively
+ // description:
+ // Function to test pattern matching of a pattern case-insensitively
+
+ var store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 1, value:"foo*bar"},
+ {uniqueId: 2, value:"bar*foo"},
+ {uniqueId: 3, value:"BAR*foo"},
+ {uniqueId: 4, value:"BARBananafoo"}
+ ]
+ }
+ });
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.assertEqual(items.length, 2);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!(value === "BAR*foo" || value === "bar*foo")){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected pattern matched. Filter failure."));
+ }
+ }
+ function error(error, request){
+ t.assertTrue(false);
+ d.errback(error);
+ }
+ store.fetch({query: {value: "bar\\*foo"}, queryOptions: {ignoreCase: true}, onComplete: completed, onError: error});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() sortNumeric",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test sorting numerically.
+ // description:
+ // Function to test sorting numerically.
+
+ var store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 0, value:"fo|o*b.ar"},
+ {uniqueId: 1, value:"ba|r*foo"},
+ {uniqueId: 2, value:"boomBam"},
+ {uniqueId: 3, value:"bit$Bite"},
+ {uniqueId: 4, value:"ouagadogou"},
+ {uniqueId: 5, value:"jfq4@#!$!@|f1.$4r14i5u"},
+ {uniqueId: 6, value:"BaB{aMa|SaRa***F}oo"},
+ {uniqueId: 7, value:"squawl"},
+ {uniqueId: 9, value:"seaweed"},
+ {uniqueId: 10, value:"zulu"},
+ {uniqueId: 8, value:"seaweed"}
+ ]
+ }
+ });
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.assertEqual(items.length, 11);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!(store.getValue(items[i], "uniqueId") === i)){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected sorting order found, sort failure."));
+ }
+ }
+
+ function error(error, request){
+ t.assertTrue(false);
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "uniqueId"}];
+ store.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() sortNumericDescending",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test sorting numerically.
+ // description:
+ // Function to test sorting numerically.
+
+ var store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 0, value:"fo|o*b.ar"},
+ {uniqueId: 1, value:"ba|r*foo"},
+ {uniqueId: 2, value:"boomBam"},
+ {uniqueId: 3, value:"bit$Bite"},
+ {uniqueId: 4, value:"ouagadogou"},
+ {uniqueId: 5, value:"jfq4@#!$!@|f1.$4r14i5u"},
+ {uniqueId: 6, value:"BaB{aMa|SaRa***F}oo"},
+ {uniqueId: 7, value:"squawl"},
+ {uniqueId: 9, value:"seaweed"},
+ {uniqueId: 10, value:"zulu"},
+ {uniqueId: 8, value:"seaweed"}
+ ]
+ }
+ });
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.assertEqual(items.length, 11);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!((items.length - (store.getValue(items[i], "uniqueId") + 1)) === i)){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected sorting order found, sort failure."));
+ }
+ }
+
+ function error(error, request){
+ t.assertTrue(false);
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "uniqueId", descending: true}];
+ store.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() sortNumericWithCount",
+ runTest: function(datastore, 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 store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 0, value:"fo|o*b.ar"},
+ {uniqueId: 1, value:"ba|r*foo"},
+ {uniqueId: 2, value:"boomBam"},
+ {uniqueId: 3, value:"bit$Bite"},
+ {uniqueId: 4, value:"ouagadogou"},
+ {uniqueId: 5, value:"jfq4@#!$!@|f1.$4r14i5u"},
+ {uniqueId: 6, value:"BaB{aMa|SaRa***F}oo"},
+ {uniqueId: 7, value:"squawl"},
+ {uniqueId: 9, value:"seaweed"},
+ {uniqueId: 10, value:"zulu"},
+ {uniqueId: 8, value:"seaweed"}
+ ]
+ }
+ });
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ t.assertEqual(items.length, 5);
+ var itemId = 10;
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!(store.getValue(items[i], "uniqueId") === itemId)){
+ passed=false;
+ break;
+ }
+ itemId--; // Decrement the item id. We are descending sorted, so it should go 10, 9, 8, etc.
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected sorting order found, sort failure."));
+ }
+ }
+
+ function error(error, request){
+ t.assertTrue(false);
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "uniqueId", descending: true}];
+ store.fetch({onComplete: completed, onError: error, sort: sortAttributes, count: 5});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() sortAlphabetic",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test sorting alphabetic ordering.
+ // description:
+ // Function to test sorting alphabetic ordering.
+
+ var store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 0, value:"abc"},
+ {uniqueId: 1, value:"bca"},
+ {uniqueId: 2, value:"abcd"},
+ {uniqueId: 3, value:"abcdefg"},
+ {uniqueId: 4, value:"lmnop"},
+ {uniqueId: 5, value:"foghorn"},
+ {uniqueId: 6, value:"qberty"},
+ {uniqueId: 7, value:"qwerty"},
+ {uniqueId: 8, value:""},
+ {uniqueId: 9, value:"seaweed"},
+ {uniqueId: 10, value:"123abc"}
+
+ ]
+ }
+ });
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ //Output should be in this order...
+ var orderedArray = [ "",
+ "123abc",
+ "abc",
+ "abcd",
+ "abcdefg",
+ "bca",
+ "foghorn",
+ "lmnop",
+ "qberty",
+ "qwerty",
+ "seaweed"
+ ];
+ t.assertEqual(items.length, 11);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!(store.getValue(items[i], "value") === orderedArray[i])){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected sorting order found, sort failure."));
+ }
+ }
+
+ function error(error, request) {
+ t.assertTrue(false);
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "value"}];
+ store.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() sortAlphabeticDescending",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test sorting alphabetic ordering in descending mode.
+ // description:
+ // Function to test sorting alphabetic ordering in descending mode.
+
+ var store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 0, value:"abc"},
+ {uniqueId: 1, value:"bca"},
+ {uniqueId: 2, value:"abcd"},
+ {uniqueId: 3, value:"abcdefg"},
+ {uniqueId: 4, value:"lmnop"},
+ {uniqueId: 5, value:"foghorn"},
+ {uniqueId: 6, value:"qberty"},
+ {uniqueId: 7, value:"qwerty"},
+ {uniqueId: 8, value:""},
+ {uniqueId: 9, value:"seaweed"},
+ {uniqueId: 10, value:"123abc"}
+
+ ]
+ }
+ });
+ var d = new doh.Deferred();
+ function completed(items, request){
+ //Output should be in this order...
+ var orderedArray = [ "",
+ "123abc",
+ "abc",
+ "abcd",
+ "abcdefg",
+ "bca",
+ "foghorn",
+ "lmnop",
+ "qberty",
+ "qwerty",
+ "seaweed"
+ ];
+ orderedArray = orderedArray.reverse();
+ t.assertEqual(items.length, 11);
+
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!(store.getValue(items[i], "value") === orderedArray[i])){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected sorting order found, sort failure."));
+ }
+ }
+
+ function error(error, request) {
+ t.assertTrue(false);
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "value", descending: true}];
+ store.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() sortDate",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test sorting date.
+ // description:
+ // Function to test sorting date.
+
+ var store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 0, value: new Date(0)},
+ {uniqueId: 1, value: new Date(100)},
+ {uniqueId: 2, value:new Date(1000)},
+ {uniqueId: 3, value:new Date(2000)},
+ {uniqueId: 4, value:new Date(3000)},
+ {uniqueId: 5, value:new Date(4000)},
+ {uniqueId: 6, value:new Date(5000)},
+ {uniqueId: 7, value:new Date(6000)},
+ {uniqueId: 8, value:new Date(7000)},
+ {uniqueId: 9, value:new Date(8000)},
+ {uniqueId: 10, value:new Date(9000)}
+
+ ]
+ }
+ });
+
+ var d = new doh.Deferred();
+ function completed(items,request){
+ var orderedArray = [0,100,1000,2000,3000,4000,5000,6000,7000,8000,9000];
+ t.assertEqual(items.length, 11);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!(store.getValue(items[i], "value").getTime() === orderedArray[i])){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected sorting order found, sort failure."));
+ }
+ }
+
+ function error(error, request){
+ t.assertTrue(false);
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "value"}];
+ store.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() sortDateDescending",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test sorting date in descending order.
+ // description:
+ // Function to test sorting date in descending order.
+
+ var store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 0, value: new Date(0)},
+ {uniqueId: 1, value: new Date(100)},
+ {uniqueId: 2, value:new Date(1000)},
+ {uniqueId: 3, value:new Date(2000)},
+ {uniqueId: 4, value:new Date(3000)},
+ {uniqueId: 5, value:new Date(4000)},
+ {uniqueId: 6, value:new Date(5000)},
+ {uniqueId: 7, value:new Date(6000)},
+ {uniqueId: 8, value:new Date(7000)},
+ {uniqueId: 9, value:new Date(8000)},
+ {uniqueId: 10, value:new Date(9000)}
+
+ ]
+ }
+ });
+
+ var d = new doh.Deferred();
+ function completed(items,request){
+ var orderedArray = [0,100,1000,2000,3000,4000,5000,6000,7000,8000,9000];
+ orderedArray = orderedArray.reverse();
+ t.assertEqual(items.length, 11);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!(store.getValue(items[i], "value").getTime() === orderedArray[i])){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected sorting order found, sort failure."));
+ }
+ }
+
+ function error(error, request){
+ t.assertTrue(false);
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "value", descending: true}];
+ store.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() sortMultiple",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test sorting on multiple attributes.
+ // description:
+ // Function to test sorting on multiple attributes.
+
+ var store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 1, value:"fo|o*b.ar"},
+ {uniqueId: 2, value:"ba|r*foo"},
+ {uniqueId: 3, value:"boomBam"},
+ {uniqueId: 4, value:"bit$Bite"},
+ {uniqueId: 5, value:"ouagadogou"},
+ {uniqueId: 6, value:"jfq4@#!$!@|f1.$4r14i5u"},
+ {uniqueId: 7, value:"BaB{aMa|SaRa***F}oo"},
+ {uniqueId: 8, value:"squawl"},
+ {uniqueId: 10, value:"seaweed"},
+ {uniqueId: 12, value:"seaweed"},
+ {uniqueId: 11, value:"zulu"},
+ {uniqueId: 9, value:"seaweed"}
+ ]
+ }
+ });
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ var orderedArray0 = [7,2,4,3,1,6,5,12,10,9,8,11];
+ var orderedArray1 = [ "BaB{aMa|SaRa***F}oo",
+ "ba|r*foo",
+ "bit$Bite",
+ "boomBam",
+ "fo|o*b.ar",
+ "jfq4@#!$!@|f1.$4r14i5u",
+ "ouagadogou",
+ "seaweed",
+ "seaweed",
+ "seaweed",
+ "squawl",
+ "zulu"
+ ];
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!( (store.getValue(items[i], "uniqueId") === orderedArray0[i])&&
+ (store.getValue(items[i], "value") === orderedArray1[i]))
+ ){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected sorting order found, sort failure."));
+ }
+ }
+
+ function error(error, request){
+ t.assertTrue(false);
+ d.errback(error);
+ }
+
+ var sortAttributes = [{ attribute: "value"}, { attribute: "uniqueId", descending: true}];
+ store.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() sortMultipleSpecialComparator",
+ runTest: function(datastore, 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 store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 1, status:"CLOSED"},
+ {uniqueId: 2, status:"OPEN"},
+ {uniqueId: 3, status:"PENDING"},
+ {uniqueId: 4, status:"BLOCKED"},
+ {uniqueId: 5, status:"CLOSED"},
+ {uniqueId: 6, status:"OPEN"},
+ {uniqueId: 7, status:"PENDING"},
+ {uniqueId: 8, status:"PENDING"},
+ {uniqueId: 10, status:"BLOCKED"},
+ {uniqueId: 12, status:"BLOCKED"},
+ {uniqueId: 11, status:"OPEN"},
+ {uniqueId: 9, status:"CLOSED"}
+ ]
+ }
+ });
+
+
+ store.comparatorMap = {};
+ store.comparatorMap["status"] = function(a,b) {
+ var ret = 0;
+ // We want to map these by what the priority of these items are, not by alphabetical.
+ // So, custom comparator.
+ var enumMap = { OPEN: 3, BLOCKED: 2, PENDING: 1, CLOSED: 0};
+ if (enumMap[a] > enumMap[b]) {
+ ret = 1;
+ }
+ if (enumMap[a] < enumMap[b]) {
+ ret = -1;
+ }
+ return ret;
+ };
+
+ var sortAttributes = [{attribute: "status", descending: true}, { attribute: "uniqueId", descending: true}];
+
+ var d = new doh.Deferred();
+ function completed(items, findResult){
+ var orderedArray = [11,6,2,12,10,4,8,7,3,9,5,1];
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ var value = store.getValue(items[i], "value");
+ if(!(store.getValue(items[i], "uniqueId") === orderedArray[i])){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected sorting order found, sort failure."));
+ }
+ }
+
+ function error(errData, request){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+ return d;
+ }
+ },
+ {
+ name: "Read API: fetch() sortAlphabeticWithUndefined",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test sorting alphabetic ordering.
+ // description:
+ // Function to test sorting alphabetic ordering.
+
+ var store = new datastore({data: { identifier: "uniqueId",
+ items: [ {uniqueId: 0, value:"abc"},
+ {uniqueId: 1, value:"bca"},
+ {uniqueId: 2, value:"abcd"},
+ {uniqueId: 3, value:"abcdefg"},
+ {uniqueId: 4, value:"lmnop"},
+ {uniqueId: 5, value:"foghorn"},
+ {uniqueId: 6, value:"qberty"},
+ {uniqueId: 7, value:"qwerty"},
+ {uniqueId: 8 }, //Deliberate undefined value
+ {uniqueId: 9, value:"seaweed"},
+ {uniqueId: 10, value:"123abc"}
+
+ ]
+ }
+ });
+
+ var d = new doh.Deferred();
+ function completed(items, request){
+ //Output should be in this order...
+ var orderedArray = [10,0,2,3,1,5,4,6,7,9,8];
+ t.assertEqual(items.length, 11);
+ var passed = true;
+ for(var i = 0; i < items.length; i++){
+ if(!(store.getValue(items[i], "uniqueId") === orderedArray[i])){
+ passed=false;
+ break;
+ }
+ }
+ t.assertTrue(passed);
+ if (passed){
+ d.callback(true);
+ }else{
+ d.errback(new Error("Unexpected sorting order found, sort failure."));
+ }
+ }
+
+ function error(error, request) {
+ t.assertTrue(false);
+ d.errback(error);
+ }
+
+ var sortAttributes = [{attribute: "value"}];
+ store.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+ return d;
+ }
+ },
+ {
+ name: "Read API: errorCondition_idCollision_inMemory",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the errors thrown when there is an id collision in the data.
+ // Added because of tracker: #2546
+ // description:
+ // Simple test of the errors thrown when there is an id collision in the data.
+ // Added because of tracker: #2546
+
+ var store = new datastore({ data: { identifier: "uniqueId",
+ items: [{uniqueId: 12345, value:"foo"},
+ {uniqueId: 123456, value:"bar"},
+ {uniqueId: 12345, value:"boom"},
+ {uniqueId: 123457, value:"bit"}
+ ]
+ }
+ });
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ //This is bad if this fires, this case should fail and not call onComplete.
+ t.assertTrue(false);
+ d.callback(false);
+ }
+
+ function reportError(errData, request){
+ //This is good if this fires, it is expected.
+ t.assertTrue(true);
+ d.callback(true);
+ }
+ store.fetch({onComplete: onComplete, onError: reportError});
+ return d;
+ }
+ },
+ {
+ name: "Read API: errorCondition_idCollision_xhr",
+ runTest: function(datastore, t){
+ // summary:
+ // Simple test of the errors thrown when there is an id collision in the data.
+ // Added because of tracker: #2546
+ // description:
+ // Simple test of the errors thrown when there is an id collision in the data.
+ // Added because of tracker: #2546
+
+ if(dojo.isBrowser){
+ var store = new datastore({url: dojo.moduleUrl("tests", "data/countries_idcollision.json").toString() });
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ //This is bad if this fires, this case should fail and not call onComplete.
+ t.assertTrue(false);
+ d.callback(false);
+ }
+
+ function reportError(errData, request){
+ //This is good if this fires, it is expected.
+ t.assertTrue(true);
+ d.callback(true);
+ }
+ store.fetch({onComplete: onComplete, onError: reportError});
+ return d;
+ }
+ }
+ },
+ {
+ name: "Read API: Date_datatype",
+ runTest: function(datastore, t){
+ //var store = new datastore(tests.data.readOnlyItemFileTestTemplates.testFile["countries_withDates"]);
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries_withDates"));
+
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ var independenceDate = store.getValue(item, "independence");
+ t.assertTrue(independenceDate instanceof Date);
+ //Check to see if the value was deserialized properly. Since the store stores in UTC/GMT, it
+ //should also be compared in the UTC/GMT mode
+ t.assertTrue(dojo.date.stamp.toISOString(independenceDate, {zulu:true}) === "1993-05-24T00:00:00Z");
+ d.callback(true);
+ }
+ function onError(errData){
+ t.assertTrue(false);
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity:"er", onItem:onItem, onError:onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Read API: custom_datatype_Color_SimpleMapping",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test using literal values with custom datatypes
+ var dataset = {
+ identifier:'name',
+ items: [
+ { name:'Kermit', species:'frog', color:{_type:'Color', _value:'green'} },
+ { name:'Beaker', hairColor:{_type:'Color', _value:'red'} }
+ ]
+ };
+ var store = new datastore({
+ data:dataset,
+ typeMap:{'Color': dojo.Color}
+ });
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ var beaker = item;
+ var hairColor = store.getValue(beaker, "hairColor");
+ t.assertTrue(hairColor instanceof dojo.Color);
+ t.assertTrue(hairColor.toHex() == "#ff0000");
+ d.callback(true);
+ }
+ function onError(errData){
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity:"Beaker", onItem:onItem, onError:onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Read API: custom_datatype_Color_GeneralMapping",
+ runTest: function(datastore, t){
+ // summary:
+ // Function to test using literal values with custom datatypes
+ var dataset = {
+ identifier:'name',
+ items: [
+ { name:'Kermit', species:'frog', color:{_type:'Color', _value:'green'} },
+ { name:'Beaker', hairColor:{_type:'Color', _value:'red'} }
+ ]
+ };
+ var store = new datastore({
+ data:dataset,
+ typeMap:{'Color': {
+ type: dojo.Color,
+ deserialize: function(value){
+ return new dojo.Color(value);
+ }
+ }
+ }
+ });
+ var d = new doh.Deferred();
+ function onItem(item){
+ t.assertTrue(item !== null);
+ var beaker = item;
+ var hairColor = store.getValue(beaker, "hairColor");
+ t.assertTrue(hairColor instanceof dojo.Color);
+ t.assertTrue(hairColor.toHex() == "#ff0000");
+ d.callback(true);
+ }
+ function onError(errData){
+ d.errback(errData);
+ }
+ store.fetchItemByIdentity({identity:"Beaker", onItem:onItem, onError:onError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Read API: hierarchical_data",
+ runTest: function(datastore, t){
+ //var store = new datastore(tests.data.readOnlyItemFileTestTemplates.testFile["geography_hierarchy_small"]);
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("geography_hierarchy_small"));
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ t.assertEqual(items.length, 1);
+ var northAmerica = items[0];
+ var canada = store.getValue(northAmerica, "countries");
+ var toronto = store.getValue(canada, "cities");
+ t.assertEqual(store.getValue(canada, "name"), "Canada");
+ t.assertEqual(store.getValue(toronto, "name"), "Toronto");
+ d.callback(true);
+ }
+ function onError(errData){
+ d.errback(errData);
+ }
+ store.fetch({
+ query: {name: "North America"},
+ onComplete: onComplete,
+ onError: onError
+ });
+
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Identity API: no_identifier_specified",
+ runTest: function(datastore, t){
+ var arrayOfItems = [
+ {name:"Kermit", color:"green"},
+ {name:"Miss Piggy", likes:"Kermit"},
+ {name:"Beaker", hairColor:"red"}
+ ];
+ var store = new datastore({data:{items:arrayOfItems}});
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ var features = store.getFeatures();
+ var hasIdentityFeature = Boolean(features['dojo.data.api.Identity']);
+ t.assertTrue(hasIdentityFeature);
+ for(var i = 0; i < items.length; ++i){
+ var item = items[i];
+ var identifier = store.getIdentityAttributes(item);
+ t.assertTrue(identifier === null);
+ var identity = store.getIdentity(item);
+ t.assertTrue(typeof identity == "number");
+ }
+ d.callback(true);
+ }
+ function reportError(errData, request){
+ d.errback(true);
+ }
+ store.fetch({onComplete: onComplete, onError: reportError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Identity API: hierarchical_data",
+ runTest: function(datastore, t){
+ var store = new datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("geography_hierarchy_small"));
+ var d = new doh.Deferred();
+ function onComplete(items, request){
+ var features = store.getFeatures();
+ var hasIdentityFeature = Boolean(features['dojo.data.api.Identity']);
+ t.assertTrue(hasIdentityFeature);
+ for(var i = 0; i < items.length; ++i){
+ var item = items[i];
+ var identifier = store.getIdentityAttributes(item);
+ t.assertTrue(identifier === null);
+ var identity = store.getIdentity(item);
+ t.assertTrue(typeof identity == "number");
+ }
+ d.callback(true);
+ }
+ function reportError(errData, request){
+ d.errback(true);
+ }
+ store.fetch({onComplete: onComplete, onError: reportError});
+ return d; // Deferred
+ }
+ },
+ {
+ name: "Read API: functionConformance",
+ runTest: function(datastore, 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 datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+ 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);
+ }
+ },
+ {
+ name: "Identity API: functionConformance",
+ runTest: function(datastore, 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 datastore(tests.data.readOnlyItemFileTestTemplates.getTestData("countries"));
+ 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"){
+ var testStoreMember = testStore[i];
+ if(!(typeof testStoreMember === "function")){
+ passed = false;
+ break;
+ }
+ }
+ }
+ }
+ t.assertTrue(passed);
+ }
+ }
+];
+
+
+}
diff --git a/includes/js/dojo/tests/data/reference_integrity.json b/includes/js/dojo/tests/data/reference_integrity.json
new file mode 100644
index 0000000..bdc6767
--- /dev/null
+++ b/includes/js/dojo/tests/data/reference_integrity.json
@@ -0,0 +1,27 @@
+/*
+{
+ "identifier": "id",
+ "label": "name",
+ "items":[
+ {"id": 1, "name": "Item 1"},
+ {"id": 2, "name": "Item 2"},
+ {"id": 3, "name": "Item 3"},
+ {"id": 4, "name": "Item 4"},
+ {"id": 5, "name": "Item 5"},
+ {"id": 6, "name": "Item 6"},
+ {"id": 7, "name": "Item 7"},
+ {"id": 8, "name": "Item 8"},
+ {"id": 9, "name": "Item 9"},
+ {"id": 10, "name": "Item 10", "friends": [{"_reference": 1},{"_reference": 3},{"_reference": 5}]},
+ {"id": 11, "name": "Item 11", "friends": [{"_reference": 10}], "siblings": [{"_reference": 10}]},
+ {"id": 12, "name": "Item 12", "friends": [{"_reference": 3},{"_reference": 7}], "enemies": [{"_reference": 10}]},
+ {"id": 13, "name": "Item 13", "friends": [{"_reference": 10}]},
+ {"id": 14, "name": "Item 14", "friends": [{"_reference": 11}]},
+ {"id": 15, "name": "item 15", "friends": [{"id": 16, "name": "Item 16"}]}
+ ]
+}
+*/
+
+
+
+
diff --git a/includes/js/dojo/tests/data/runTests.html b/includes/js/dojo/tests/data/runTests.html
new file mode 100644
index 0000000..ee3d473
--- /dev/null
+++ b/includes/js/dojo/tests/data/runTests.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+ <head>
+ <title>dojo.data D.O.H. Unit Test Runner</title>
+ <meta http-equiv="REFRESH" content="0;url=../../../util/doh/runner.html?testModule=tests.data"></HEAD>
+ <BODY>
+ Redirecting to D.O.H runner.
+ </BODY>
+</HTML>
diff --git a/includes/js/dojo/tests/data/utils.js b/includes/js/dojo/tests/data/utils.js
new file mode 100644
index 0000000..8b26037
--- /dev/null
+++ b/includes/js/dojo/tests/data/utils.js
@@ -0,0 +1,203 @@
+if(!dojo._hasResource["tests.data.utils"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.data.utils"] = true;
+dojo.provide("tests.data.utils");
+dojo.require("dojo.data.util.filter");
+dojo.require("dojo.data.util.sorter");
+
+tests.register("tests.data.utils",
+ [
+ function testWildcardFilter_1(t){
+ var pattern = "ca*";
+ var values = ["ca", "california", "Macca", "Macca*b", "Macca\\b"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testWildcardFilter_2(t){
+ var pattern = "*ca";
+ var values = ["ca", "california", "Macca", "Macca*b", "Macca\\b"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testWildcardFilter_3(t){
+ var pattern = "*ca*";
+ var values = ["ca", "california", "Macca", "Macca*b", "Macca\\b"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testWildcardFilter_4(t){
+ //Try and match <anything>c<anything>a*b
+ var pattern = "*c*a\\*b*";
+ var values = ["ca", "california", "Macca", "Macca*b", "Macca\\b"];
+
+ t.assertFalse(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testWildcardFilter_5(t){
+ var pattern = "*c*a\\\\*b";
+ var values = ["ca", "california", "Macca", "Macca*b", "Macca\\b"];
+
+ t.assertFalse(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testWildcardFilter_caseInsensitive(t){
+ var pattern = "ca*";
+ var values = ["CA", "california", "Macca", "Macca*b", "Macca\\b"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern, true))!== null);
+ t.assertTrue(values[1].match(dojo.data.util.filter.patternToRegExp(pattern, true))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern, true))!== null);
+ t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern, true))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern, true))!== null);
+ },
+ function testSingleChar_1(t){
+ var pattern = "bob?le";
+ var values = ["bobble", "boble", "foo", "bobBle", "bar"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testSingleChar_2(t){
+ var pattern = "?ob?le";
+ var values = ["bobble", "cob1le", "foo", "bobBle", "bar"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testBracketChar(t){
+ //Make sure we don't treat this as regexp
+ var pattern = "*[*]*";
+ var values = ["bo[b]ble", "cob1le", "foo", "[bobBle]", "b[]ar"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testBraceChar(t){
+ //Make sure we don't treat this as regexp
+ var pattern = "*{*}*";
+ var values = ["bo{b}ble", "cob1le", "foo", "{bobBle}", "b{}ar"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testParenChar(t){
+ //Make sure we don't treat this as regexp
+ var pattern = "*(*)*";
+ var values = ["bo(b)ble", "cob1le", "foo", "{bobBle}", "b()ar"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testPlusChar(t){
+ //Make sure we don't treat this as regexp, so match anything with a + in it.
+ var pattern = "*+*";
+ var values = ["bo+ble", "cob1le", "foo", "{bobBle}", "b{}ar"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testPeriodChar(t){
+ //Make sure we don't treat this as regexp, so match anything with a period
+ var pattern = "*.*";
+ var values = ["bo.ble", "cob1le", "foo", "{bobBle}", "b{}ar"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testBarChar(t){
+ //Make sure we don't treat this as regexp, so match anything with a pipe bar
+ var pattern = "*|*";
+ var values = ["bo.ble", "cob|le", "foo", "{bobBle}", "b{}ar"];
+
+ t.assertFalse(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testDollarSignChar(t){
+ //Make sure we don't treat this as regexp, so match anything with a $ in it
+ var pattern = "*$*";
+ var values = ["bo$ble", "cob$le", "foo", "{bobBle}", "b{}ar"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testCarrotChar(t){
+ //Make sure we don't treat this as regexp, so match anything with a ^ in it
+ var pattern = "*^*";
+ var values = ["bo$ble", "cob$le", "f^oo", "{bobBle}", "b{}ar"];
+
+ t.assertFalse(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertTrue(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testEscapeChar(t){
+ //Make sure we escape properly, so match this single word.
+ var pattern = "bob\*ble";
+ var values = ["bob*ble", "cob$le", "f^oo", "{bobBle}", "b{}ar"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ },
+ function testAbsoluteMatch(t){
+ var pattern = "bobble";
+ var values = ["bobble", "cob$le", "f^oo", "{bobBle}", "b{}ar"];
+
+ t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+ }
+ ]
+);
+
+
+}
diff --git a/includes/js/dojo/tests/date.js b/includes/js/dojo/tests/date.js
new file mode 100644
index 0000000..57df0fd
--- /dev/null
+++ b/includes/js/dojo/tests/date.js
@@ -0,0 +1,716 @@
+if(!dojo._hasResource["tests.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.date"] = true;
+dojo.provide("tests.date");
+
+dojo.require("dojo.date");
+
+tests.register("tests.date.util",
+ [
+
+/* Informational Functions
+ **************************/
+
+function test_date_getDaysInMonth(t){
+ // months other than February
+ t.is(31, dojo.date.getDaysInMonth(new Date(2006,0,1)));
+ t.is(31, dojo.date.getDaysInMonth(new Date(2006,2,1)));
+ t.is(30, dojo.date.getDaysInMonth(new Date(2006,3,1)));
+ t.is(31, dojo.date.getDaysInMonth(new Date(2006,4,1)));
+ t.is(30, dojo.date.getDaysInMonth(new Date(2006,5,1)));
+ t.is(31, dojo.date.getDaysInMonth(new Date(2006,6,1)));
+ t.is(31, dojo.date.getDaysInMonth(new Date(2006,7,1)));
+ t.is(30, dojo.date.getDaysInMonth(new Date(2006,8,1)));
+ t.is(31, dojo.date.getDaysInMonth(new Date(2006,9,1)));
+ t.is(30, dojo.date.getDaysInMonth(new Date(2006,10,1)));
+ t.is(31, dojo.date.getDaysInMonth(new Date(2006,11,1)));
+
+ // Februarys
+ t.is(28, dojo.date.getDaysInMonth(new Date(2006,1,1)));
+ t.is(29, dojo.date.getDaysInMonth(new Date(2004,1,1)));
+ t.is(29, dojo.date.getDaysInMonth(new Date(2000,1,1)));
+ t.is(28, dojo.date.getDaysInMonth(new Date(1900,1,1)));
+ t.is(28, dojo.date.getDaysInMonth(new Date(1800,1,1)));
+ t.is(28, dojo.date.getDaysInMonth(new Date(1700,1,1)));
+ t.is(29, dojo.date.getDaysInMonth(new Date(1600,1,1)));
+},
+
+function test_date_isLeapYear(t){
+ t.f(dojo.date.isLeapYear(new Date(2006,0,1)));
+ t.t(dojo.date.isLeapYear(new Date(2004,0,1)));
+ t.t(dojo.date.isLeapYear(new Date(2000,0,1)));
+ t.f(dojo.date.isLeapYear(new Date(1900,0,1)));
+ t.f(dojo.date.isLeapYear(new Date(1800,0,1)));
+ t.f(dojo.date.isLeapYear(new Date(1700,0,1)));
+ t.t(dojo.date.isLeapYear(new Date(1600,0,1)));
+},
+
+// The getTimezone function pulls from either the date's toString or
+// toLocaleString method -- it's really just a string-processing
+// function (assuming the Date obj passed in supporting both toString
+// and toLocaleString) and as such can be tested for multiple browsers
+// by manually settting up fake Date objects with the actual strings
+// produced by various browser/OS combinations.
+// FIXME: the function and tests are not localized.
+function test_date_getTimezoneName(t){
+
+ // Create a fake Date object with toString and toLocaleString
+ // results manually set to simulate tests for multiple browsers
+ function FakeDate(str, strLocale){
+ this.str = str || '';
+ this.strLocale = strLocale || '';
+ this.toString = function() {
+ return this.str;
+ };
+ this.toLocaleString = function(){
+ return this.strLocale;
+ };
+ }
+ var dt = new FakeDate();
+
+ // FF 1.5 Ubuntu Linux (Breezy)
+ dt.str = 'Sun Sep 17 2006 22:25:51 GMT-0500 (CDT)';
+ dt.strLocale = 'Sun 17 Sep 2006 10:25:51 PM CDT';
+ t.is('CDT', dojo.date.getTimezoneName(dt));
+
+ // Safari 2.0 Mac OS X 10.4
+ dt.str = 'Sun Sep 17 2006 22:55:01 GMT-0500';
+ dt.strLocale = 'September 17, 2006 10:55:01 PM CDT';
+ t.is('CDT', dojo.date.getTimezoneName(dt));
+
+ // FF 1.5 Mac OS X 10.4
+ dt.str = 'Sun Sep 17 2006 22:57:18 GMT-0500 (CDT)';
+ dt.strLocale = 'Sun Sep 17 22:57:18 2006';
+ t.is('CDT', dojo.date.getTimezoneName(dt));
+
+ // Opera 9 Mac OS X 10.4 -- no TZ data expect empty string return
+ dt.str = 'Sun, 17 Sep 2006 22:58:06 GMT-0500';
+ dt.strLocale = 'Sunday September 17, 22:58:06 GMT-0500 2006';
+ t.is('', dojo.date.getTimezoneName(dt));
+
+ // IE 6 Windows XP
+ dt.str = 'Mon Sep 18 11:21:07 CDT 2006';
+ dt.strLocale = 'Monday, September 18, 2006 11:21:07 AM';
+ t.is('CDT', dojo.date.getTimezoneName(dt));
+
+ // Opera 9 Ubuntu Linux (Breezy) -- no TZ data expect empty string return
+ dt.str = 'Mon, 18 Sep 2006 13:30:32 GMT-0500';
+ dt.strLocale = 'Monday September 18, 13:30:32 GMT-0500 2006';
+ t.is('', dojo.date.getTimezoneName(dt));
+
+ // IE 5.5 Windows 2000
+ dt.str = 'Mon Sep 18 13:49:22 CDT 2006';
+ dt.strLocale = 'Monday, September 18, 2006 1:49:22 PM';
+ t.is('CDT', dojo.date.getTimezoneName(dt));
+}
+ ]
+);
+
+tests.register("tests.date.math",
+ [
+function test_date_compare(t){
+ var d1=new Date();
+ d1.setHours(0);
+ var d2=new Date();
+ d2.setFullYear(2005);
+ d2.setHours(12);
+ t.is(0, dojo.date.compare(d1, d1));
+ t.is(1, dojo.date.compare(d1, d2, "date"));
+ t.is(-1, dojo.date.compare(d2, d1, "date"));
+ t.is(-1, dojo.date.compare(d1, d2, "time"));
+ t.is(1, dojo.date.compare(d1, d2, "datetime"));
+},
+function test_date_add(t){
+ var interv = ''; // Interval (e.g., year, month)
+ var dtA = null; // Date to increment
+ var dtB = null; // Expected result date
+
+ interv = "year";
+ dtA = new Date(2005, 11, 27);
+ dtB = new Date(2006, 11, 27);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2005, 11, 27);
+ dtB = new Date(2004, 11, 27);
+ t.is(dtB, dojo.date.add(dtA, interv, -1));
+
+ dtA = new Date(2000, 1, 29);
+ dtB = new Date(2001, 1, 28);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2000, 1, 29);
+ dtB = new Date(2005, 1, 28);
+ t.is(dtB, dojo.date.add(dtA, interv, 5));
+
+ dtA = new Date(1900, 11, 31);
+ dtB = new Date(1930, 11, 31);
+ t.is(dtB, dojo.date.add(dtA, interv, 30));
+
+ dtA = new Date(1995, 11, 31);
+ dtB = new Date(2030, 11, 31);
+ t.is(dtB, dojo.date.add(dtA, interv, 35));
+
+ interv = "quarter";
+ dtA = new Date(2000, 0, 1);
+ dtB = new Date(2000, 3, 1);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2000, 1, 29);
+ dtB = new Date(2000, 7, 29);
+ t.is(dtB, dojo.date.add(dtA, interv, 2));
+
+ dtA = new Date(2000, 1, 29);
+ dtB = new Date(2001, 1, 28);
+ t.is(dtB, dojo.date.add(dtA, interv, 4));
+
+ interv = "month";
+ dtA = new Date(2000, 0, 1);
+ dtB = new Date(2000, 1, 1);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2000, 0, 31);
+ dtB = new Date(2000, 1, 29);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2000, 1, 29);
+ dtB = new Date(2001, 1, 28);
+ t.is(dtB, dojo.date.add(dtA, interv, 12));
+
+ interv = "week";
+ dtA = new Date(2000, 0, 1);
+ dtB = new Date(2000, 0, 8);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ interv = "day";
+ dtA = new Date(2000, 0, 1);
+ dtB = new Date(2000, 0, 2);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2001, 0, 1);
+ dtB = new Date(2002, 0, 1);
+ t.is(dtB, dojo.date.add(dtA, interv, 365));
+
+ dtA = new Date(2000, 0, 1);
+ dtB = new Date(2001, 0, 1);
+ t.is(dtB, dojo.date.add(dtA, interv, 366));
+
+ dtA = new Date(2000, 1, 28);
+ dtB = new Date(2000, 1, 29);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2001, 1, 28);
+ dtB = new Date(2001, 2, 1);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2000, 2, 1);
+ dtB = new Date(2000, 1, 29);
+ t.is(dtB, dojo.date.add(dtA, interv, -1));
+
+ dtA = new Date(2001, 2, 1);
+ dtB = new Date(2001, 1, 28);
+ t.is(dtB, dojo.date.add(dtA, interv, -1));
+
+ dtA = new Date(2000, 0, 1);
+ dtB = new Date(1999, 11, 31);
+ t.is(dtB, dojo.date.add(dtA, interv, -1));
+
+ interv = "weekday";
+ // Sat, Jan 1
+ dtA = new Date(2000, 0, 1);
+ // Should be Mon, Jan 3
+ dtB = new Date(2000, 0, 3);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ // Sun, Jan 2
+ dtA = new Date(2000, 0, 2);
+ // Should be Mon, Jan 3
+ dtB = new Date(2000, 0, 3);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ // Sun, Jan 2
+ dtA = new Date(2000, 0, 2);
+ // Should be Fri, Jan 7
+ dtB = new Date(2000, 0, 7);
+ t.is(dtB, dojo.date.add(dtA, interv, 5));
+
+ // Sun, Jan 2
+ dtA = new Date(2000, 0, 2);
+ // Should be Mon, Jan 10
+ dtB = new Date(2000, 0, 10);
+ t.is(dtB, dojo.date.add(dtA, interv, 6));
+
+ // Mon, Jan 3
+ dtA = new Date(2000, 0, 3);
+ // Should be Mon, Jan 17
+ dtB = new Date(2000, 0, 17);
+ t.is(dtB, dojo.date.add(dtA, interv, 10));
+
+ // Sat, Jan 8
+ dtA = new Date(2000, 0, 8);
+ // Should be Mon, Jan 3
+ dtB = new Date(2000, 0, 3);
+ t.is(dtB, dojo.date.add(dtA, interv, -5));
+
+ // Sun, Jan 9
+ dtA = new Date(2000, 0, 9);
+ // Should be Wed, Jan 5
+ dtB = new Date(2000, 0, 5);
+ t.is(dtB, dojo.date.add(dtA, interv, -3));
+
+ // Sun, Jan 23
+ dtA = new Date(2000, 0, 23);
+ // Should be Fri, Jan 7
+ dtB = new Date(2000, 0, 7);
+ t.is(dtB, dojo.date.add(dtA, interv, -11));
+
+ interv = "hour";
+ dtA = new Date(2000, 0, 1, 11);
+ dtB = new Date(2000, 0, 1, 12);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2001, 9, 28, 0);
+ dtB = new Date(dtA.getTime() + (60 * 60 * 1000));
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2001, 9, 28, 23);
+ dtB = new Date(2001, 9, 29, 0);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2001, 11, 31, 23);
+ dtB = new Date(2002, 0, 1, 0);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ interv = "minute";
+ dtA = new Date(2000, 11, 31, 23, 59);
+ dtB = new Date(2001, 0, 1, 0, 0);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2000, 11, 27, 12, 2);
+ dtB = new Date(2000, 11, 27, 13, 2);
+ t.is(dtB, dojo.date.add(dtA, interv, 60));
+
+ interv = "second";
+ dtA = new Date(2000, 11, 31, 23, 59, 59);
+ dtB = new Date(2001, 0, 1, 0, 0, 0);
+ t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+ dtA = new Date(2000, 11, 27, 8, 10, 59);
+ dtB = new Date(2000, 11, 27, 8, 11, 59);
+ t.is(dtB, dojo.date.add(dtA, interv, 60));
+
+ // Test environment JS Date doesn't support millisec?
+ //interv = "millisecond";
+ //
+ //dtA = new Date(2000, 11, 31, 23, 59, 59, 999);
+ //dtB = new Date(2001, 0, 1, 0, 0, 0, 0);
+ //t.is(dtB, dojo.date.add(dtA, interv, 1));
+ //
+ //dtA = new Date(2000, 11, 27, 8, 10, 53, 2);
+ //dtB = new Date(2000, 11, 27, 8, 10, 54, 2);
+ //t.is(dtB, dojo.date.add(dtA, interv, 1000));
+},
+function test_date_diff(t){
+ var dtA = null; // First date to compare
+ var dtB = null; // Second date to compare
+ var interv = ''; // Interval to compare on (e.g., year, month)
+
+ interv = "year";
+ dtA = new Date(2005, 11, 27);
+ dtB = new Date(2006, 11, 27);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2000, 11, 31);
+ dtB = new Date(2001, 0, 1);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ interv = "quarter";
+ dtA = new Date(2000, 1, 29);
+ dtB = new Date(2001, 2, 1);
+ t.is(4, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2000, 11, 1);
+ dtB = new Date(2001, 0, 1);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ interv = "month";
+ dtA = new Date(2000, 1, 29);
+ dtB = new Date(2001, 2, 1);
+ t.is(13, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2000, 11, 1);
+ dtB = new Date(2001, 0, 1);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ interv = "week";
+ dtA = new Date(2000, 1, 1);
+ dtB = new Date(2000, 1, 8);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2000, 1, 28);
+ dtB = new Date(2000, 2, 6);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2000, 2, 6);
+ dtB = new Date(2000, 1, 28);
+ t.is(-1, dojo.date.difference(dtA, dtB, interv));
+
+ interv = "day";
+ dtA = new Date(2000, 1, 29);
+ dtB = new Date(2000, 2, 1);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2000, 11, 31);
+ dtB = new Date(2001, 0, 1);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ // DST leap -- check for rounding err
+ // This is dependent on US calendar, but
+ // shouldn't break in other locales
+ dtA = new Date(2005, 3, 3);
+ dtB = new Date(2005, 3, 4);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ interv = "weekday";
+ dtA = new Date(2006, 7, 3);
+ dtB = new Date(2006, 7, 11);
+ t.is(6, dojo.date.difference(dtA, dtB, interv));
+
+ // Positive diffs
+ dtA = new Date(2006, 7, 4);
+ dtB = new Date(2006, 7, 11);
+ t.is(5, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 5);
+ dtB = new Date(2006, 7, 11);
+ t.is(5, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 6);
+ dtB = new Date(2006, 7, 11);
+ t.is(5, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 7);
+ dtB = new Date(2006, 7, 11);
+ t.is(4, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 7);
+ dtB = new Date(2006, 7, 13);
+ t.is(4, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 7);
+ dtB = new Date(2006, 7, 14);
+ t.is(5, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 7);
+ dtB = new Date(2006, 7, 15);
+ t.is(6, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 7);
+ dtB = new Date(2006, 7, 28);
+ t.is(15, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 2, 2);
+ dtB = new Date(2006, 2, 28);
+ t.is(18, dojo.date.difference(dtA, dtB, interv));
+
+ // Negative diffs
+ dtA = new Date(2006, 7, 11);
+ dtB = new Date(2006, 7, 4);
+ t.is(-5, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 11);
+ dtB = new Date(2006, 7, 5);
+ t.is(-4, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 11);
+ dtB = new Date(2006, 7, 6);
+ t.is(-4, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 11);
+ dtB = new Date(2006, 7, 7);
+ t.is(-4, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 13);
+ dtB = new Date(2006, 7, 7);
+ t.is(-5, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 14);
+ dtB = new Date(2006, 7, 7);
+ t.is(-5, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 15);
+ dtB = new Date(2006, 7, 7);
+ t.is(-6, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 7, 28);
+ dtB = new Date(2006, 7, 7);
+ t.is(-15, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2006, 2, 28);
+ dtB = new Date(2006, 2, 2);
+ t.is(-18, dojo.date.difference(dtA, dtB, interv));
+
+ // Two days on the same weekend -- no weekday diff
+ dtA = new Date(2006, 7, 5);
+ dtB = new Date(2006, 7, 6);
+ t.is(0, dojo.date.difference(dtA, dtB, interv));
+
+ interv = "hour";
+ dtA = new Date(2000, 11, 31, 23);
+ dtB = new Date(2001, 0, 1, 0);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2000, 11, 31, 12);
+ dtB = new Date(2001, 0, 1, 0);
+ t.is(12, dojo.date.difference(dtA, dtB, interv));
+
+ interv = "minute";
+ dtA = new Date(2000, 11, 31, 23, 59);
+ dtB = new Date(2001, 0, 1, 0, 0);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2000, 1, 28, 23, 59);
+ dtB = new Date(2000, 1, 29, 0, 0);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ interv = "second";
+ dtA = new Date(2000, 11, 31, 23, 59, 59);
+ dtB = new Date(2001, 0, 1, 0, 0, 0);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ interv = "millisecond";
+ dtA = new Date(2000, 11, 31, 23, 59, 59, 999);
+ dtB = new Date(2001, 0, 1, 0, 0, 0, 0);
+ t.is(1, dojo.date.difference(dtA, dtB, interv));
+
+ dtA = new Date(2000, 11, 31, 23, 59, 59, 0);
+ dtB = new Date(2001, 0, 1, 0, 0, 0, 0);
+ t.is(1000, dojo.date.difference(dtA, dtB, interv));
+},
+function test_date_add_diff_year(t){
+ var interv = ''; // Interval (e.g., year, month)
+ var dtA = null; // Date to increment
+ var dtB = null; // Expected result date
+
+ interv = "year";
+ dtA = new Date(2005, 11, 27);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2005, 11, 27);
+ dtB = dojo.date.add(dtA, interv, -1);
+ t.is(dojo.date.difference(dtA, dtB, interv), -1);
+
+ dtA = new Date(2000, 1, 29);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2000, 1, 29);
+ dtB = dojo.date.add(dtA, interv, 5);
+ t.is(dojo.date.difference(dtA, dtB, interv), 5);
+
+ dtA = new Date(1900, 11, 31);
+ dtB = dojo.date.add(dtA, interv, 30);
+ t.is(dojo.date.difference(dtA, dtB, interv), 30);
+
+ dtA = new Date(1995, 11, 31);
+ dtB = dojo.date.add(dtA, interv, 35);
+ t.is(dojo.date.difference(dtA, dtB, interv), 35);
+},
+function test_date_add_diff_quarter(t){
+ var interv = ''; // Interval (e.g., year, month)
+ var dtA = null; // Date to increment
+ var dtB = null; // Expected result date
+ interv = "quarter";
+ dtA = new Date(2000, 0, 1);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2000, 1, 29);
+ dtB = dojo.date.add(dtA, interv, 2);
+ t.is(dojo.date.difference(dtA, dtB, interv), 2);
+
+ dtA = new Date(2000, 1, 29);
+ dtB = dojo.date.add(dtA, interv, 4);
+ t.is(dojo.date.difference(dtA, dtB, interv), 4);
+},
+function test_date_add_diff_month(t){
+ var interv = ''; // Interval (e.g., year, month)
+ var dtA = null; // Date to increment
+ var dtB = null; // Expected result date
+ interv = "month";
+ dtA = new Date(2000, 0, 1);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2000, 0, 31);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2000, 1, 29);
+ dtB = dojo.date.add(dtA, interv, 12);
+ t.is(dojo.date.difference(dtA, dtB, interv), 12);
+},
+function test_date_add_diff_week(t){
+ var interv = ''; // Interval (e.g., year, month)
+ var dtA = null; // Date to increment
+ var dtB = null; // Expected result date
+ interv = "week";
+ dtA = new Date(2000, 0, 1);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+},
+function test_date_add_diff_day(t){
+ var interv = ''; // Interval (e.g., year, month)
+ var dtA = null; // Date to increment
+ var dtB = null; // Expected result date
+ interv = "day";
+ dtA = new Date(2000, 0, 1);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2001, 0, 1);
+ dtB = dojo.date.add(dtA, interv, 365);
+ t.is(dojo.date.difference(dtA, dtB, interv), 365);
+
+ dtA = new Date(2000, 0, 1);
+ dtB = dojo.date.add(dtA, interv, 366);
+ t.is(dojo.date.difference(dtA, dtB, interv), 366);
+
+ dtA = new Date(2000, 1, 28);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2001, 1, 28);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2000, 2, 1);
+ dtB = dojo.date.add(dtA, interv, -1);
+ t.is(dojo.date.difference(dtA, dtB, interv), -1);
+
+ dtA = new Date(2001, 2, 1);
+ dtB = dojo.date.add(dtA, interv, -1);
+ t.is(dojo.date.difference(dtA, dtB, interv), -1);
+
+ dtA = new Date(2000, 0, 1);
+ dtB = dojo.date.add(dtA, interv, -1);
+ t.is(dojo.date.difference(dtA, dtB, interv), -1);
+},
+function test_date_add_diff_weekday(t){
+ var interv = ''; // Interval (e.g., year, month)
+ var dtA = null; // Date to increment
+ var dtB = null; // Expected result date
+ interv = "weekday";
+ // Sat, Jan 1
+ dtA = new Date(2000, 0, 1);
+ // Should be Mon, Jan 3
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ // Sun, Jan 2
+ dtA = new Date(2000, 0, 2);
+ // Should be Mon, Jan 3
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ // Sun, Jan 2
+ dtA = new Date(2000, 0, 2);
+ // Should be Fri, Jan 7
+ dtB = dojo.date.add(dtA, interv, 5);
+ t.is(dojo.date.difference(dtA, dtB, interv), 5);
+
+ // Sun, Jan 2
+ dtA = new Date(2000, 0, 2);
+ // Should be Mon, Jan 10
+ dtB = dojo.date.add(dtA, interv, 6);
+ t.is(dojo.date.difference(dtA, dtB, interv), 6);
+
+ // Mon, Jan 3
+ dtA = new Date(2000, 0, 3);
+ // Should be Mon, Jan 17
+ dtB = dojo.date.add(dtA, interv, 10);
+ t.is(dojo.date.difference(dtA, dtB, interv), 10);
+
+ // Sat, Jan 8
+ dtA = new Date(2000, 0, 8);
+ // Should be Mon, Jan 3
+ dtB = dojo.date.add(dtA, interv, -5);
+ t.is(dojo.date.difference(dtA, dtB, interv), -5);
+
+ // Sun, Jan 9
+ dtA = new Date(2000, 0, 9);
+ // Should be Wed, Jan 5
+ dtB = dojo.date.add(dtA, interv, -3);
+ t.is(dojo.date.difference(dtA, dtB, interv), -3);
+
+ // Sun, Jan 23
+ dtA = new Date(2000, 0, 23);
+ // Should be Fri, Jan 7
+ dtB = dojo.date.add(dtA, interv, -11);
+ t.is(dojo.date.difference(dtA, dtB, interv), -11);
+},
+function test_date_add_diff_hour(t){
+ var interv = ''; // Interval (e.g., year, month)
+ var dtA = null; // Date to increment
+ var dtB = null; // Expected result date
+ interv = "hour";
+ dtA = new Date(2000, 0, 1, 11);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2001, 9, 28, 0);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2001, 9, 28, 23);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2001, 11, 31, 23);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+},
+function test_date_add_diff_minute(t){
+ var interv = ''; // Interval (e.g., year, month)
+ var dtA = null; // Date to increment
+ var dtB = null; // Expected result date
+ interv = "minute";
+ dtA = new Date(2000, 11, 31, 23, 59);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2000, 11, 27, 12, 2);
+ dtB = dojo.date.add(dtA, interv, 60);
+ t.is(dojo.date.difference(dtA, dtB, interv), 60);
+},
+function test_date_add_diff_second(t){
+ var interv = ''; // Interval (e.g., year, month)
+ var dtA = null; // Date to increment
+ var dtB = null; // Expected result date
+ console.debug("second");
+ interv = "second";
+ dtA = new Date(2000, 11, 31, 23, 59, 59);
+ dtB = dojo.date.add(dtA, interv, 1);
+ t.is(dojo.date.difference(dtA, dtB, interv), 1);
+
+ dtA = new Date(2000, 11, 27, 8, 10, 59);
+ dtB = dojo.date.add(dtA, interv, 60);
+ t.is(dojo.date.difference(dtA, dtB, interv), 60);
+
+ // Test environment JS Date doesn't support millisec?
+ //interv = "millisecond";
+ //
+ //dtA = new Date(2000, 11, 31, 23, 59, 59, 999);
+ //dtB = dojo.date.add(dtA, interv, 1);
+ //t.is(dojo.date.difference(dtA, dtB, interv), 1);
+ //
+ //dtA = new Date(2000, 11, 27, 8, 10, 53, 2);
+ //dtB = dojo.date.add(dtA, interv, 1000);
+ //t.is(dojo.date.difference(dtA, dtB, interv), 1000);
+}
+ ]
+);
+
+dojo.require("tests.date.locale");
+dojo.require("tests.date.stamp");
+
+}
diff --git a/includes/js/dojo/tests/date/locale.js b/includes/js/dojo/tests/date/locale.js
new file mode 100644
index 0000000..77512a0
--- /dev/null
+++ b/includes/js/dojo/tests/date/locale.js
@@ -0,0 +1,398 @@
+if(!dojo._hasResource["tests.date.locale"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.date.locale"] = true;
+dojo.provide("tests.date.locale");
+
+dojo.require("dojo.date.locale");
+
+tests.register("tests.date.locale",
+ [
+ {
+ // Test formatting and parsing of dates in various locales pre-built in dojo.cldr
+ // NOTE: we can't set djConfig.extraLocale before bootstrapping unit tests, so directly
+ // load resources here for specific locales:
+
+ name: "date.locale",
+ setUp: function(){
+ var partLocaleList = ["en-us", "fr-fr", "es", "de-at", "ja-jp", "zh-cn"];
+
+ dojo.forEach(partLocaleList, function(locale){
+ dojo.requireLocalization("dojo.cldr", "gregorian", locale, "zh-cn,zh,en-ca,ko-kr,pt,pt-br,it-it,ROOT,en-gb,de,ja,en,en-au,fr,es,ko,zh-tw,it,es-es");
+ });
+ },
+ runTest: function(t){
+ },
+ tearDown: function(){
+ //Clean up bundles that should not exist if
+ //the test is re-run.
+ delete dojo.cldr.nls.gregorian;
+ }
+ },
+ {
+ name: "isWeekend",
+ runTest: function(t){
+ var thursday = new Date(2006, 8, 21);
+ var friday = new Date(2006, 8, 22);
+ var saturday = new Date(2006, 8, 23);
+ var sunday = new Date(2006, 8, 24);
+ var monday = new Date(2006, 8, 25);
+ t.f(dojo.date.locale.isWeekend(thursday, 'en-us'));
+ t.t(dojo.date.locale.isWeekend(saturday, 'en-us'));
+ t.t(dojo.date.locale.isWeekend(sunday, 'en-us'));
+ t.f(dojo.date.locale.isWeekend(monday, 'en-us'));
+// t.f(dojo.date.locale.isWeekend(saturday, 'en-in'));
+// t.t(dojo.date.locale.isWeekend(sunday, 'en-in'));
+// t.f(dojo.date.locale.isWeekend(monday, 'en-in'));
+// t.t(dojo.date.locale.isWeekend(friday, 'he-il'));
+// t.f(dojo.date.locale.isWeekend(sunday, 'he-il'));
+ }
+ },
+ {
+ name: "format",
+ runTest: function(t){
+
+ var date = new Date(2006, 7, 11, 0, 55, 12, 345);
+
+ t.is("Friday, August 11, 2006", dojo.date.locale.format(date, {formatLength:'full',selector:'date', locale:'en-us'}));
+ t.is("vendredi 11 ao\xFBt 2006", dojo.date.locale.format(date, {formatLength:'full',selector:'date', locale:'fr-fr'}));
+ t.is("Freitag, 11. August 2006", dojo.date.locale.format(date, {formatLength:'full',selector:'date', locale:'de-at'}));
+ t.is("2006\u5E748\u670811\u65E5\u91D1\u66DC\u65E5", dojo.date.locale.format(date, {formatLength:'full',selector:'date', locale:'ja-jp'}));
+
+ t.is("8/11/06", dojo.date.locale.format(date, {formatLength:'short',selector:'date', locale:'en-us'}));
+ t.is("11/08/06", dojo.date.locale.format(date, {formatLength:'short',selector:'date', locale:'fr-fr'}));
+ t.is("11.08.06", dojo.date.locale.format(date, {formatLength:'short',selector:'date', locale:'de-at'}));
+ t.is("06/08/11", dojo.date.locale.format(date, {formatLength:'short',selector:'date', locale:'ja-jp'}));
+
+ t.is("12:55 AM", dojo.date.locale.format(date, {formatLength:'short',selector:'time', locale:'en-us'}));
+ t.is("12:55:12", dojo.date.locale.format(date, {timePattern:'h:m:s',selector:'time'}));
+ t.is("12:55:12.35", dojo.date.locale.format(date, {timePattern:'h:m:s.SS',selector:'time'}));
+ t.is("24:55:12.35", dojo.date.locale.format(date, {timePattern:'k:m:s.SS',selector:'time'}));
+ t.is("0:55:12.35", dojo.date.locale.format(date, {timePattern:'H:m:s.SS',selector:'time'}));
+ t.is("0:55:12.35", dojo.date.locale.format(date, {timePattern:'K:m:s.SS',selector:'time'}));
+
+ t.is("11082006", dojo.date.locale.format(date, {datePattern:"ddMMyyyy", selector:"date"}));
+
+ // compare without timezone
+ t.is("\u4e0a\u534812\u65f655\u520612\u79d2", dojo.date.locale.format(date, {formatLength:'full',selector:'time', locale:'zh-cn'}).split(' ')[0]);
+ }
+ },
+ {
+ name: "parse_dates",
+ runTest: function(t){
+
+ var aug_11_2006 = new Date(2006, 7, 11, 0);
+
+ //en: 'short' fmt: M/d/yy
+ // Tolerate either 8 or 08 for month part.
+ t.is( aug_11_2006, dojo.date.locale.parse("08/11/06", {formatLength:'short', selector:'date', locale:'en'}));
+ t.is( aug_11_2006, dojo.date.locale.parse("8/11/06", {formatLength:'short', selector:'date', locale:'en'}));
+ // Tolerate yyyy input in yy part...
+ t.is( aug_11_2006, dojo.date.locale.parse("8/11/2006", {formatLength:'short', selector:'date', locale:'en'}));
+ // ...but not in strict mode
+ t.f( Boolean(dojo.date.locale.parse("8/11/2006", {formatLength:'short', selector:'date', locale:'en', strict:true})));
+
+ //en: 'medium' fmt: MMM d, yyyy
+ // Tolerate either 8 or 08 for month part.
+ t.is( aug_11_2006, dojo.date.locale.parse("Aug 11, 2006", {formatLength:'medium', selector:'date', locale:'en'}));
+ t.is( aug_11_2006, dojo.date.locale.parse("Aug 11, 2006", {formatLength:'medium', selector:'date', locale:'en'}));
+ // Tolerate abbreviating period in month part...
+ t.is( aug_11_2006, dojo.date.locale.parse("Aug. 11, 2006", {formatLength:'medium', selector:'date', locale:'en'}));
+ // ...but not in strict mode
+ t.f( Boolean(dojo.date.locale.parse("Aug. 11, 2006", {formatLength:'medium', selector:'date', locale:'en', strict:true})));
+
+ // Note: 06 for year part will be translated literally as the year 6 C.E.
+ var aug_11_06CE = new Date(2006, 7, 11, 0);
+ aug_11_06CE.setFullYear(6); //literally the year 6 C.E.
+ t.is( aug_11_06CE, dojo.date.locale.parse("Aug 11, 06", {selector:'date', datePattern:'MMM dd, yyyy', strict:true}));
+
+ //en: 'long' fmt: MMMM d, yyyy
+ t.is( aug_11_2006, dojo.date.locale.parse("August 11, 2006", {formatLength:'long', selector:'date', locale:'en'}));
+
+ //en: 'full' fmt: EEEE, MMMM d, yyyy
+ t.is( aug_11_2006, dojo.date.locale.parse("Friday, August 11, 2006", {formatLength:'full', selector:'date', locale:'en'}));
+ //TODO: wrong day-of-week should fail
+ //t.f( Boolean(dojo.date.locale.parse("Thursday, August 11, 2006", {formatLength:'full', selector:'date', locale:'en'})));
+ //TODO: Whitespace tolerance
+ // t.is( aug_11_2006, dojo.date.locale.parse(" August 11, 2006", {formatLength:'long', selector:'date', locale:'en'}));
+ // t.is( aug_11_2006, dojo.date.locale.parse("August 11, 2006", {formatLength:'long', selector:'date', locale:'en'}));
+ // t.is( aug_11_2006, dojo.date.locale.parse("August 11 , 2006", {formatLength:'long', selector:'date', locale:'en'}));
+ // t.is( aug_11_2006, dojo.date.locale.parse("August 11, 2006", {formatLength:'long', selector:'date', locale:'en'}));
+ // t.is( aug_11_2006, dojo.date.locale.parse("August 11, 2006 ", {formatLength:'long', selector:'date', locale:'en'}));
+
+ //Simple Validation Tests
+ //catch "month" > 12 (note: month/day reversals are common when user expectation isn't met wrt european versus US formats)
+ t.f( Boolean(dojo.date.locale.parse("15/1/2005", {formatLength:'short', selector:'date', locale:'en'})));
+ //day of month typo rolls over to the next month
+ t.f( Boolean(dojo.date.locale.parse("Aug 32, 2006", {formatLength:'medium', selector:'date', locale:'en'})));
+
+ //German (de)
+ t.is( aug_11_2006, dojo.date.locale.parse("11.08.06", {formatLength:'short', selector:'date', locale:'de'}));
+ t.f( Boolean(dojo.date.locale.parse("11.8/06", {formatLength:'short', selector:'date', locale:'de'})));
+ t.f( Boolean(dojo.date.locale.parse("11.8x06", {formatLength:'short', selector:'date', locale:'de'})));
+ t.f( Boolean(dojo.date.locale.parse("11.13.06", {formatLength:'short', selector:'date', locale:'de'})));
+ t.f( Boolean(dojo.date.locale.parse("11.0.06", {formatLength:'short', selector:'date', locale:'de'})));
+ t.f( Boolean(dojo.date.locale.parse("32.08.06", {formatLength:'short', selector:'date', locale:'de'})));
+
+ //Spanish (es)
+ //es: 'short' fmt: d/MM/yy
+ t.is( aug_11_2006, dojo.date.locale.parse("11/08/06", {formatLength:'short', selector:'date', locale:'es'}));
+ t.is( aug_11_2006, dojo.date.locale.parse("11/8/06", {formatLength:'short', selector:'date', locale:'es'}));
+ // Tolerate yyyy input in yy part...
+ t.is( aug_11_2006, dojo.date.locale.parse("11/8/2006", {formatLength:'short', selector:'date', locale:'es'}));
+ // ...but not in strict mode
+ t.f( Boolean(dojo.date.locale.parse("11/8/2006", {formatLength:'short', selector:'date', locale:'es', strict:true})));
+ //es: 'medium' fmt: dd-MMM-yy (not anymore as of CLDR 1.5.1)
+// t.is( aug_11_2006, dojo.date.locale.parse("11-ago-06", {formatLength:'medium', selector:'date', locale:'es'}));
+// t.is( aug_11_2006, dojo.date.locale.parse("11-ago-2006", {formatLength:'medium', selector:'date', locale:'es'}));
+ // Tolerate abbreviating period in month part...
+// t.is( aug_11_2006, dojo.date.locale.parse("11-ago.-2006", {formatLength:'medium', selector:'date', locale:'es'}));
+ // ...but not in strict mode
+// t.f( Boolean(dojo.date.locale.parse("11-ago.-2006", {formatLength:'medium', selector:'date', locale:'es', strict:true})));
+ //es: 'long' fmt: d' de 'MMMM' de 'yyyy
+ t.is( aug_11_2006, dojo.date.locale.parse("11 de agosto de 2006", {formatLength:'long', selector:'date', locale:'es'}));
+ //case-insensitive month...
+ t.is( aug_11_2006, dojo.date.locale.parse("11 de Agosto de 2006", {formatLength:'long', selector:'date', locale:'es'}));
+ //...but not in strict mode
+ t.f( Boolean(dojo.date.locale.parse("11 de Agosto de 2006", {formatLength:'long', selector:'date', locale:'es', strict:true})));
+ //es 'full' fmt: EEEE d' de 'MMMM' de 'yyyy
+ t.is( aug_11_2006, dojo.date.locale.parse("viernes 11 de agosto de 2006", {formatLength:'full', selector:'date', locale:'es'}));
+ //case-insensitive day-of-week...
+ t.is( aug_11_2006, dojo.date.locale.parse("Viernes 11 de agosto de 2006", {formatLength:'full', selector:'date', locale:'es'}));
+ //...but not in strict mode
+ t.f( Boolean(dojo.date.locale.parse("Viernes 11 de agosto de 2006", {formatLength:'full', selector:'date', locale:'es', strict:true})));
+
+ //Japanese (ja)
+ //note: to avoid garbling from non-utf8-aware editors that may touch this file, using the \uNNNN format
+ //for expressing double-byte chars.
+ //toshi (year): \u5e74
+ //getsu (month): \u6708
+ //nichi (day): \u65e5
+ //kinyoubi (Friday): \u91d1\u66dc\u65e5
+ //zenkaku space: \u3000
+
+ //ja: 'short' fmt: yy/MM/dd (note: the "short" fmt isn't actually defined in the CLDR data...)
+ t.is( aug_11_2006, dojo.date.locale.parse("06/08/11", {formatLength:'short', selector:'date', locale:'ja'}));
+ t.is( aug_11_2006, dojo.date.locale.parse("06/8/11", {formatLength:'short', selector:'date', locale:'ja'}));
+ // Tolerate yyyy input in yy part...
+ t.is( aug_11_2006, dojo.date.locale.parse("2006/8/11", {formatLength:'short', selector:'date', locale:'ja'}));
+ // ...but not in strict mode
+ t.f( Boolean(dojo.date.locale.parse("2006/8/11", {formatLength:'short', selector:'date', locale:'ja', strict:true})));
+ //ja: 'medium' fmt: yyyy/MM/dd
+ t.is( aug_11_2006, dojo.date.locale.parse("2006/08/11", {formatLength:'medium', selector:'date', locale:'ja'}));
+ t.is( aug_11_2006, dojo.date.locale.parse("2006/8/11", {formatLength:'medium', selector:'date', locale:'ja'}));
+ //ja: 'long' fmt: yyyy'\u5e74'\u6708'd'\u65e5'
+ t.is( aug_11_2006, dojo.date.locale.parse("2006\u5e748\u670811\u65e5", {formatLength:'long', selector:'date', locale:'ja'}));
+ //ja 'full' fmt: yyyy'\u5e74'M'\u6708'd'\u65e5'EEEE
+ t.is( aug_11_2006, dojo.date.locale.parse("2006\u5e748\u670811\u65e5\u91d1\u66dc\u65e5", {formatLength:'full', selector:'date', locale:'ja'}));
+
+ //TODO: Whitespace tolerance
+ //tolerate ascii space
+ // t.is( aug_11_2006, dojo.date.locale.parse(" 2006\u5e748\u670811\u65e5\u91d1\u66dc\u65e5 ", {formatLength:'full', selector:'date', locale:'ja'}));
+ // t.is( aug_11_2006, dojo.date.locale.parse("2006\u5e74 8\u670811\u65e5 \u91d1\u66dc\u65e5", {formatLength:'full', selector:'date', locale:'ja'}));
+ //tolerate zenkaku space
+ // t.is( aug_11_2006, dojo.date.locale.parse("\u30002006\u5e748\u670811\u65e5\u91d1\u66dc\u65e5\u3000", {formatLength:'full', selector:'date', locale:'ja'}));
+ // t.is( aug_11_2006, dojo.date.locale.parse("2006\u5e74\u30008\u670811\u65e5\u3000\u91d1\u66dc\u65e5", {formatLength:'full', selector:'date', locale:'ja'}));
+
+ var apr_11_2006 = new Date(2006, 3, 11, 0);
+ //Roundtrip
+ var options={formatLength:'medium',selector:'date', locale:'fr-fr'};
+ t.is(0, dojo.date.compare(apr_11_2006, dojo.date.locale.parse(dojo.date.locale.format(apr_11_2006, options), options)));
+
+ //Tolerance for abbreviations
+ t.is(0, dojo.date.compare(apr_11_2006, dojo.date.locale.parse("11 avr 06", options)));
+ }
+ },
+ {
+ name: "parse_dates_neg",
+ runTest: function(t){
+ t.f(Boolean(dojo.date.locale.parse("2/29/2007", {formatLength: 'short', selector: 'date', locale: 'en'})));
+ t.f(Boolean(dojo.date.locale.parse("4/31/2007", {formatLength: 'short', selector: 'date', locale: 'en'})));
+ t.f(Boolean(dojo.date.locale.parse("Decemb 30, 2007", {formatLength: 'long', selector: 'date', locale: 'en'})));
+ }
+ },
+ {
+ name: "parse_datetimes",
+ runTest: function(t){
+
+ var aug_11_2006_12_30_am = new Date(2006, 7, 11, 0, 30);
+ var aug_11_2006_12_30_pm = new Date(2006, 7, 11, 12, 30);
+
+ //en: 'short' datetime fmt: M/d/yy h:mm a
+ //note: this is concatenation of dateFormat-short and timeFormat-short,
+ //cldr provisionally defines datetime fmts as well, but we're not using them at the moment
+ t.is( aug_11_2006_12_30_pm, dojo.date.locale.parse("08/11/06 12:30 PM", {formatLength:'short', locale:'en'}));
+ //case-insensitive
+ t.is( aug_11_2006_12_30_pm, dojo.date.locale.parse("08/11/06 12:30 pm", {formatLength:'short', locale:'en'}));
+ //...but not in strict mode
+ t.f( Boolean(dojo.date.locale.parse("08/11/06 12:30 pm", {formatLength:'short', locale:'en', strict:true})));
+
+ t.is( aug_11_2006_12_30_am, dojo.date.locale.parse("08/11/06 12:30 AM", {formatLength:'short', locale:'en'}));
+
+ t.is( new Date(2006, 7, 11), dojo.date.locale.parse("11082006", {datePattern:"ddMMyyyy", selector:"date"}));
+
+ }
+ },
+ {
+ name: "parse_times",
+ runTest: function(t){
+
+ var time = new Date(2006, 7, 11, 12, 30);
+ var tformat = {selector:'time', strict:true, timePattern:"h:mm a", locale:'en'};
+
+ t.is(time.getHours(), dojo.date.locale.parse("12:30 PM", tformat).getHours());
+ t.is(time.getMinutes(), dojo.date.locale.parse("12:30 PM", tformat).getMinutes());
+ }
+ },
+ {
+ name: "day_of_year",
+ runTest: function(t){
+
+// t.is(23, dojo.date.setDayOfYear(new Date(2006,0,1), 23).getDate());
+ t.is(1, dojo.date.locale._getDayOfYear(new Date(2006,0,1)));
+ t.is(32, dojo.date.locale._getDayOfYear(new Date(2006,1,1)));
+ t.is(72, dojo.date.locale._getDayOfYear(new Date(2007,2,13,0,13)));
+ t.is(72, dojo.date.locale._getDayOfYear(new Date(2007,2,13,1,13)));
+ }
+ },
+ {
+ name: "week_of_year",
+ runTest: function(t){
+ t.is(0, dojo.date.locale._getWeekOfYear(new Date(2000,0,1)));
+ t.is(1, dojo.date.locale._getWeekOfYear(new Date(2000,0,2)));
+ t.is(0, dojo.date.locale._getWeekOfYear(new Date(2000,0,2), 1));
+ t.is(0, dojo.date.locale._getWeekOfYear(new Date(2007,0,1)));
+ t.is(1, dojo.date.locale._getWeekOfYear(new Date(2007,0,1), 1));
+ t.is(27, dojo.date.locale._getWeekOfYear(new Date(2007,6,14)));
+ t.is(28, dojo.date.locale._getWeekOfYear(new Date(2007,6,14), 1));
+ }
+ }
+ ]
+);
+
+/*
+// workaround deprecated methods. Should decide whether we should convert the tests or add a helper method (in dojo.date?) to do this.
+
+dojo_validate_isValidTime = function(str, props){
+ props = props || {};
+ if(!props.format){props.format="h:mm:ss";}
+ if(!props.am){props.am="a.m.";}
+ if(!props.pm){props.pm="p.m.";}
+ var result = false;
+ if(/[hk]/.test(props.format) && props.format.indexOf('a') == -1){
+ result = dojo.date.locale.parse(str, {selector: 'time', timePattern: props.format + " a"});
+ }
+ return Boolean(result || dojo.date.locale.parse(str, {selector: 'time', timePattern: props.format}));
+}
+
+dojo_validate_is12HourTime = function(str){
+ return dojo_validate_isValidTime(str, {format: 'h:mm:ss'}) || dojo_validate_isValidTime(str, {format: 'h:mm'});
+}
+
+dojo_validate_is24HourTime = function(str){
+ return dojo_validate_isValidTime(str, {format: 'H:mm:ss'}) || dojo_validate_isValidTime(str, {format: 'H:mm'});
+}
+
+dojo_validate_isValidDate = function(str, fmt){
+ return Boolean(dojo.date.locale.parse(str, {selector: 'date', datePattern: fmt}));
+}
+
+function test_validate_datetime_isValidTime(){
+ jum.assertTrue("test1", dojo_validate_isValidTime('5:15:05 pm'));
+// FAILURE jum.assertTrue("test2", dojo_validate_isValidTime('5:15:05 p.m.', {pm: "P.M."} ));
+ jum.assertFalse("test3", dojo_validate_isValidTime('5:15:05 f.m.'));
+ jum.assertTrue("test4", dojo_validate_isValidTime('5:15 pm', {format: "h:mm a"} ) );
+ jum.assertFalse("test5", dojo_validate_isValidTime('5:15 fm', {}) );
+ jum.assertTrue("test6", dojo_validate_isValidTime('15:15:00', {format: "H:mm:ss"} ) );
+// FAILURE jum.assertFalse("test7", dojo_validate_isValidTime('15:15:00', {}) );
+ jum.assertTrue("test8", dojo_validate_isValidTime('17:01:30', {format: "H:mm:ss"} ) );
+ jum.assertFalse("test9", dojo_validate_isValidTime('17:1:30', {format: "H:mm:ss"} ) );
+// FAILURE jum.assertFalse("test10", dojo_validate_isValidTime('17:01:30', {format: "H:m:ss"} ) );
+ // Greek
+// FAILURE jum.assertTrue("test11", dojo_validate_isValidTime('5:01:30 \u0924\u0924', {am: "\u0928\u0924", pm: "\u0924\u0924"} ) );
+ // Italian
+ jum.assertTrue("test12", dojo_validate_isValidTime('17.01.30', {format: "H.mm.ss"} ) );
+ // Mexico
+// FAILURE jum.assertTrue("test13", dojo_validate_isValidTime('05:01:30 p.m.', {format: "hh:mm:ss a", am: "a.m.", pm: "p.m."} ) );
+}
+
+
+function test_validate_datetime_is12HourTime(){
+ jum.assertTrue("test1", dojo_validate_is12HourTime('5:15:05 pm'));
+// FAILURE jum.assertFalse("test2", dojo_validate_is12HourTime('05:15:05 pm'));
+ jum.assertFalse("test3", dojo_validate_is12HourTime('5:5:05 pm'));
+ jum.assertFalse("test4", dojo_validate_is12HourTime('5:15:5 pm'));
+// FAILURE jum.assertFalse("test5", dojo_validate_is12HourTime('13:15:05 pm'));
+ jum.assertFalse("test6", dojo_validate_is12HourTime('5:60:05 pm'));
+ jum.assertFalse("test7", dojo_validate_is12HourTime('5:15:60 pm'));
+ jum.assertTrue("test8", dojo_validate_is12HourTime('5:59:05 pm'));
+ jum.assertTrue("test9", dojo_validate_is12HourTime('5:15:59 pm'));
+// FAILURE jum.assertFalse("test10", dojo_validate_is12HourTime('5:15:05'));
+
+ // optional seconds
+ jum.assertTrue("test11", dojo_validate_is12HourTime('5:15 pm'));
+ jum.assertFalse("test12", dojo_validate_is12HourTime('5:15: pm'));
+}
+
+function test_validate_datetime_is24HourTime(){
+ jum.assertTrue("test1", dojo_validate_is24HourTime('00:03:59'));
+ jum.assertTrue("test2", dojo_validate_is24HourTime('22:03:59'));
+//FIXME: fix tests or code?
+// jum.assertFalse("test3", dojo_validate_is24HourTime('22:03:59 pm'));
+// jum.assertFalse("test4", dojo_validate_is24HourTime('2:03:59'));
+ jum.assertFalse("test5", dojo_validate_is24HourTime('0:3:59'));
+ jum.assertFalse("test6", dojo_validate_is24HourTime('00:03:5'));
+ jum.assertFalse("test7", dojo_validate_isValidTime('24:03:59', {format: 'kk:mm:ss'}));
+ jum.assertFalse("test8", dojo_validate_is24HourTime('02:60:59'));
+ jum.assertFalse("test9", dojo_validate_is24HourTime('02:03:60'));
+
+ // optional seconds
+ jum.assertTrue("test10", dojo_validate_is24HourTime('22:53'));
+ jum.assertFalse("test11", dojo_validate_is24HourTime('22:53:'));
+}
+
+function test_validate_datetime_isValidDate(){
+
+ // Month date year
+ jum.assertTrue("test1", dojo_validate_isValidDate("08/06/2005", "MM/dd/yyyy"));
+ jum.assertTrue("test2", dojo_validate_isValidDate("08.06.2005", "MM.dd.yyyy"));
+ jum.assertTrue("test3", dojo_validate_isValidDate("08-06-2005", "MM-dd-yyyy"));
+ jum.assertTrue("test4", dojo_validate_isValidDate("8/6/2005", "M/d/yyyy"));
+ jum.assertTrue("test5", dojo_validate_isValidDate("8/6", "M/d"));
+ jum.assertFalse("test6", dojo_validate_isValidDate("09/31/2005", "MM/dd/yyyy"));
+ jum.assertFalse("test7", dojo_validate_isValidDate("02/29/2005", "MM/dd/yyyy"));
+ jum.assertTrue("test8", dojo_validate_isValidDate("02/29/2004", "MM/dd/yyyy"));
+
+ // year month date
+ jum.assertTrue("test9", dojo_validate_isValidDate("2005-08-06", "yyyy-MM-dd"));
+ jum.assertTrue("test10", dojo_validate_isValidDate("20050806", "yyyyMMdd"));
+
+ // year month
+ jum.assertTrue("test11", dojo_validate_isValidDate("2005-08", "yyyy-MM"));
+ jum.assertTrue("test12", dojo_validate_isValidDate("200508", "yyyyMM"));
+
+ // year
+ jum.assertTrue("test13", dojo_validate_isValidDate("2005", "yyyy"));
+
+ // year week day
+//TODO: need to support 'w'?
+// jum.assertTrue("test14", dojo_validate_isValidDate("2005-W42-3", "yyyy-'W'ww-d"));
+// jum.assertTrue("test15", dojo_validate_isValidDate("2005W423", "yyyy'W'wwd"));
+// jum.assertFalse("test16", dojo_validate_isValidDate("2005-W42-8", "yyyy-'W'ww-d"));
+// jum.assertFalse("test17", dojo_validate_isValidDate("2005-W54-3", "yyyy-'W'ww-d"));
+
+ // year week
+// jum.assertTrue("test18", dojo_validate_isValidDate("2005-W42", "yyyy-'W'ww"));
+// jum.assertTrue("test19", dojo_validate_isValidDate("2005W42", "yyyy'W'ww"));
+
+ // year ordinal-day
+ jum.assertTrue("test20", dojo_validate_isValidDate("2005-292", "yyyy-DDD"));
+ jum.assertTrue("test21", dojo_validate_isValidDate("2005292", "yyyyDDD"));
+ jum.assertFalse("test22", dojo_validate_isValidDate("2005-366", "yyyy-DDD"));
+ jum.assertTrue("test23", dojo_validate_isValidDate("2004-366", "yyyy-DDD"));
+
+ // date month year
+ jum.assertTrue("test24", dojo_validate_isValidDate("19.10.2005", "dd.MM.yyyy"));
+ jum.assertTrue("test25", dojo_validate_isValidDate("19-10-2005", "d-M-yyyy"));
+}
+*/
+
+}
diff --git a/includes/js/dojo/tests/date/stamp.js b/includes/js/dojo/tests/date/stamp.js
new file mode 100644
index 0000000..88cf677
--- /dev/null
+++ b/includes/js/dojo/tests/date/stamp.js
@@ -0,0 +1,94 @@
+if(!dojo._hasResource["tests.date.stamp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.date.stamp"] = true;
+dojo.provide("tests.date.stamp");
+
+dojo.require("dojo.date.stamp");
+
+tests.register("tests.date.stamp",
+ [
+function test_date_iso(t){
+ var rfc = "2005-06-29T08:05:00-07:00";
+ var date = dojo.date.stamp.fromISOString(rfc);
+ t.is(2005,date.getFullYear());
+ t.is(5,date.getMonth());
+ t.is(29,date.getUTCDate());
+ t.is(15,date.getUTCHours());
+ t.is(5,date.getMinutes());
+ t.is(0,date.getSeconds());
+
+ rfc = "2004-02-29";
+ date = dojo.date.stamp.fromISOString(rfc);
+ t.is(2004,date.getFullYear());
+ t.is(1,date.getMonth());
+ t.is(29,date.getDate());
+
+ rfc = "2004-01";
+ date = dojo.date.stamp.fromISOString(rfc);
+ t.is(2004,date.getFullYear());
+ t.is(0,date.getMonth());
+ t.is(1,date.getDate());
+
+ // No TZ info means local time
+ rfc = "2004-02-29T01:23:45";
+ date = dojo.date.stamp.fromISOString(rfc);
+ t.is(2004,date.getFullYear());
+ t.is(1,date.getMonth());
+ t.is(29,date.getDate());
+ t.is(1,date.getHours());
+
+ date = new Date(2005,5,29,8,5,0);
+ rfc = dojo.date.stamp.toISOString(date);
+ //truncate for comparison
+ t.is("2005-06",rfc.substring(0,7));
+
+ date = new Date(101,0,2);
+ date.setFullYear(101);
+ rfc = dojo.date.stamp.toISOString(date);
+ //truncate for comparison
+ t.is("0101-01",rfc.substring(0,7));
+
+ rfc = "0101-01-01";
+ date = dojo.date.stamp.fromISOString(rfc);
+ t.is(101,date.getFullYear());
+ t.is(0,date.getMonth());
+ t.is(1,date.getDate());
+
+ date = dojo.date.stamp.fromISOString("T18:46:39");
+ t.is(18, date.getHours());
+ t.is(46, date.getMinutes());
+ t.is(39, date.getSeconds());
+},
+
+function test_date_iso_tz(t){
+
+ //23:59:59.9942 or 235959.9942
+// var date = dojo.date.stamp.fromISOString("T18:46:39.9942");
+// t.is(18, date.getHours());
+// t.is(46, date.getMinutes());
+// t.is(39, date.getSeconds());
+// t.is(994, date.getMilliseconds());
+
+ //1995-02-04 24:00 = 1995-02-05 00:00
+
+ //timezone tests
+ var offset = new Date().getTimezoneOffset()/60;
+ date = dojo.date.stamp.fromISOString("T18:46:39+07:00");
+ t.is(11, date.getUTCHours());
+
+ date = dojo.date.stamp.fromISOString("T18:46:39+00:00");
+ t.is(18, date.getUTCHours());
+
+ date = dojo.date.stamp.fromISOString("T18:46:39Z");
+ t.is(18, date.getUTCHours());
+
+ date = dojo.date.stamp.fromISOString("T16:46:39-07:00");
+ t.is(23, date.getUTCHours());
+
+ //+hh:mm, +hhmm, or +hh
+
+ //-hh:mm, -hhmm, or -hh
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/dnd/dndDefault.css b/includes/js/dojo/tests/dnd/dndDefault.css
new file mode 100644
index 0000000..eca2ef5
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/dndDefault.css
@@ -0,0 +1,52 @@
+
+.container {
+ border:3px solid #ccc;
+ padding: 1em 3em;
+ cursor: default;
+ radius:8pt;
+ background:#fff;
+ -moz-border-radius:8pt 8pt;
+}
+.dojoDndContainerOver {
+
+ border:3px solid #aaa;
+}
+.dojoDndItem {
+ padding:3px;
+}
+.dojoDndItemOver {
+ background: #ededed;
+ cursor:pointer;
+}
+.dojoDndItemSelected {
+ background: #ccf; color: #444;
+}
+.dojoDndItemAnchor {
+ background: #ccf; color: black;
+}
+.dojoDndItemOver .dojoDndItemSelected {
+ background: #ededed;
+}
+.dojoDndItemOver .dojoDndItemAnchor {
+ background: #ededed;
+}
+.dojoDndItemBefore {
+ border-top: 2px solid #369;
+}
+.dojoDndItemAfter {
+ border-bottom: 2px solid #369;
+}
+.dojoDndAvatar {
+ border:2px solid #ccc;
+ font-size: 75%;
+ -moz-border-radius:8pt 8pt;
+ radius:8pt;
+}
+
+.dojoDndAvatarHeader {
+ background: #aaa;
+}
+.dojoDndAvatarItem {
+ background: #fff;
+ border-bottom:1px solid #666;
+}
diff --git a/includes/js/dojo/tests/dnd/dndDefault.css.commented.css b/includes/js/dojo/tests/dnd/dndDefault.css.commented.css
new file mode 100644
index 0000000..cad410c
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/dndDefault.css.commented.css
@@ -0,0 +1,69 @@
+/*
+
+ there are basically all the classes you can set
+ for the various dojo.dnd states and elements in
+ their simplest form. hacking welcome.
+
+*/
+.container {
+ border:3px solid #ccc;
+ padding: 1em 3em;
+ cursor: default;
+ radius:8pt;
+ background:#fff;
+ -moz-border-radius:8pt 8pt;
+}
+
+.dojoDndContainerOver {
+ /* cursor:pointer; */
+ border:3px solid #aaa;
+}
+
+.dojoDndItem {
+ padding:3px;
+}
+
+.dojoDndItemOver {
+ background: #ededed;
+ cursor:pointer;
+}
+
+.dojoDndItemSelected {
+ background: #ccf; color: #444;
+}
+
+.dojoDndItemAnchor {
+ background: #ccf; color: black;
+}
+
+.dojoDndItemOver .dojoDndItemSelected {
+ background: #ededed;
+}
+
+.dojoDndItemOver .dojoDndItemAnchor {
+ background: #ededed;
+}
+
+.dojoDndItemBefore {
+ border-top: 2px solid #369;
+}
+
+.dojoDndItemAfter {
+ border-bottom: 2px solid #369;
+}
+
+.dojoDndAvatar {
+ border:2px solid #ccc;
+ font-size: 75%;
+ -moz-border-radius:8pt 8pt;
+ radius:8pt;
+}
+
+.dojoDndAvatarHeader {
+ background: #aaa;
+}
+
+.dojoDndAvatarItem {
+ background: #fff;
+ border-bottom:1px solid #666;
+}
diff --git a/includes/js/dojo/tests/dnd/flickr_viewer.html b/includes/js/dojo/tests/dnd/flickr_viewer.html
new file mode 100644
index 0000000..4ede297
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/flickr_viewer.html
@@ -0,0 +1,168 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Sort Flickr images by tags</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ @import "../../resources/dnd.css";
+ body {
+ padding: 1em;
+ }
+
+ /* application-specific settings */
+ #status {font-weight: bold;}
+ .container {padding: 5px; cursor: default; background: #f8f8ff;}
+ .wrap1 {float: left; width: 275px; height: 600px; overflow: auto; margin-right: 1em;}
+ .wrap1 div {min-height: 100px;}
+ .wrap2 {width: 350px; height: 170px; overflow: auto;}
+ .wrap2 div {min-height: 150px;}
+ .container .name {font-weight: bold; padding-right: 4px;}
+ .container .image {padding: 5px;}
+ body.dojoDndCopy, body.dojoDndMove {color: #888;}
+ .dojoDndCopy .container, .dojoDndMove .container {background: #ddf;}
+
+ /* container-specific settings */
+ .dojoDndContainer {border: 1px solid white; color: black;}
+ .dojoDndContainerOver {border: 1px solid black; color: black;}
+ .container.dojoDndTargetDisabled {background: #ccc; color: #888;}
+
+ /* item-specific settings */
+ .dojoDndItemOver {background: #feb;}
+ .dojoDndItemSelected {background: #ccf; color: #444;}
+ .dojoDndItemAnchor {background: #ccf; color: black;}
+ .dojoDndItemOver.dojoDndItemSelected {background: #ec8;}
+ .dojoDndItemOver.dojoDndItemAnchor {background: #ec8;}
+ .dojoDndItemBefore {border-top: 3px solid red;}
+ .dojoDndItemAfter {border-bottom: 3px solid red;}
+ .dojoDndHorizontal .dojoDndItemBefore {border-top: none;}
+ .dojoDndHorizontal .dojoDndItemAfter {border-bottom: none;}
+ .dojoDndHorizontal .dojoDndItemBefore img {border-left: 3px solid red;}
+ .dojoDndHorizontal .dojoDndItemAfter img {border-right: 3px solid red;}
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript" src="../../dnd/common.js"></script>
+ <script type="text/javascript" src="../../dnd/autoscroll.js"></script>
+ <script type="text/javascript" src="../../dnd/Container.js"></script>
+ <script type="text/javascript" src="../../dnd/Selector.js"></script>
+ <script type="text/javascript" src="../../dnd/Source.js"></script>
+ <script type="text/javascript" src="../../dnd/Avatar.js"></script>
+ <script type="text/javascript" src="../../dnd/Manager.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dojo.io.script");
+ dojo.require("dojo.dnd.Source");
+
+ // The main image container creator
+ var main_creator = function(item, hint){
+ var type = [];
+ if(item.tags.search(/cat/i) >= 0){ type.push("cat"); }
+ if(item.tags.search(/dog/i) >= 0){ type.push("dog"); }
+ var node;
+ if(hint == "avatar"){
+ node = dojo.doc.createElement("span");
+ node.innerHTML = "<img src='" + item.media.m.replace(/_m\./, "_s.") + "'/>";
+ }else{
+ var t = ["<table border='0' cellpadding='0' cellspacing='0' width='250'>"];
+ t.push("<tr><td colspan='2' class='image' align='center' width='250'><img src='" +
+ item.media.m + "'/></td></tr>");
+ t.push("<tr><td class='name' valign='top'>Title:</td><td class='value'><a href='" +
+ item.link + "' target='_blank'>" +
+ (item.title ? item.title : "<em>untitled</em>") + "</a></td></tr>");
+ t.push("<tr><td class='name' valign='top'>Author:</td><td class='value'>" +
+ item.author + "</td></tr>");
+ t.push("<tr><td class='name' valign='top'>Tags:</td><td class='value'>" +
+ item.tags + "</td></tr>");
+ t.push("</table>");
+ node = dojo.doc.createElement("div");
+ node.innerHTML = t.join("");
+ }
+ node.id = dojo.dnd.getUniqueId();
+ return {node: node, data: item, type: type};
+ };
+
+ // The band image container creator
+ var band_creator = function(item, hint){
+ var type = [];
+ if(item.tags.search(/cat/i) >= 0){ type.push("cat"); }
+ if(item.tags.search(/dog/i) >= 0){ type.push("dog"); }
+ var src = item.media.m.replace(/_m\./, "_s.");
+ var node = dojo.doc.createElement("span");
+ node.innerHTML = "<img src='" + src + "'/>";
+ node.id = dojo.dnd.getUniqueId();
+ return {node: node, data: item, type: type};
+ };
+
+ // Flickr's JSONP function
+ var jsonFlickrFeed = function(data){
+ if(!data.items || !data.items.length){
+ dojo.byId("status").innerHTML = "Flickr didn't return any images";
+ return;
+ }
+ dojo.byId("status").innerHTML = data.items.length + " images were retrieved";
+ // initialize sources
+ c1.selectAll().deleteSelectedNodes();
+ c2.selectAll().deleteSelectedNodes();
+ c3.selectAll().deleteSelectedNodes();
+ // populate the main source
+ c1.insertNodes(false, data.items);
+ };
+
+ var init = function(){
+ // replace the avatar string to make it more human readable
+ dojo.dnd.Avatar.prototype._generateText = function(){
+ return (this.manager.copy ? "copy" : "mov") +
+ "ing " + this.manager.nodes.length + " item" +
+ (this.manager.nodes.length != 1 ? "s" : "");
+ };
+ // ask Flickr for images
+ var td = dojo.io.script.get({
+ url: "http://api.flickr.com/services/feeds/photos_public.gne",
+ content: {tags: "cat,dog,cow", tagmode: "any", format: "json"},
+ handleAs: "text/javascript",
+ preventCache: true
+ });
+ td.addErrback(function(){
+ dojo.byId("status").innerHTML = "Flickr failed to return images";
+ });
+ };
+
+ dojo.addOnLoad(init);
+ </script>
+</head>
+<body>
+ <h1>Sort Flickr images by tags</h1>
+ <p>This simple web application retrieves public images from Flickr that were tagged either as "cat", "dog", or "cow".
+ You can copy/move images in different containers according to their tags.</p>
+ <p>Following selection modes are supported by default:</p>
+ <ul>
+ <li>Simple click &mdash; selects a single element, all other elements will be unselected.</li>
+ <li>Ctrl+click &mdash; toggles a selection state of an element (use Meta key on Mac).</li>
+ <li>Shift+click &mdash; selects a range of element from the previous anchor to the current element.</li>
+ <li>Ctrl+Shift+click &mdash; adds a range of element from the previous anchor to the current element (use Meta key on Mac).</li>
+ </ul>
+ <p>Following drop modes are supported by default:</p>
+ <ul>
+ <li>Simple drop &mdash; moves elements to the valid target removing them from the source. It can be used to reorganize elements within a single source/target.</li>
+ <li>Ctrl+drop &mdash; copies elements to the valid target (use Meta key on Mac).</li>
+ </ul>
+ <p>Now scroll down and start dragging and dropping, rearrange images using DnD, copy and move them back!</p>
+ <p>Status: <span id="status">retrieving a list of Flickr images...</span></p>
+ <div class="wrap1">
+ <div dojoType="dojo.dnd.Source" jsId="c1" accept="cat, dog, cow" class="container">
+ <script type="dojo/method" event="creator" args="item, hint">return main_creator(item, hint);</script>
+ </div>
+ </div>
+ <p>Tag: cat</p>
+ <div class="wrap2">
+ <div dojoType="dojo.dnd.Source" jsId="c2" accept="cat" horizontal="true" class="container">
+ <script type="dojo/method" event="creator" args="item, hint">return band_creator(item, hint);</script>
+ </div>
+ </div>
+ <p>Tag: dog</p>
+ <div class="wrap2">
+ <div dojoType="dojo.dnd.Source" jsId="c3" accept="dog" horizontal="true" class="container">
+ <script type="dojo/method" event="creator" args="item, hint">return band_creator(item, hint);</script>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_box_constraints.html b/includes/js/dojo/tests/dnd/test_box_constraints.html
new file mode 100644
index 0000000..85a5033
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_box_constraints.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Dojo box constraint test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ @import "dndDefault.css";
+
+ body {
+ padding: 1em;
+ }
+
+ .moveable {
+ background: #FFFFBF;
+ border: 1px solid black;
+ width: 300px;
+ padding: 10px 20px;
+ cursor: pointer;
+ }
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript" src="../../dnd/move.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dojo.dnd.move");
+ var m5, m6;
+ var init = function(){
+ m5 = new dojo.dnd.move.boxConstrainedMoveable("moveable5", {box: {l: 100, t: 100, w: 500, h: 500}});
+ m6 = new dojo.dnd.move.boxConstrainedMoveable("moveable6", {box: {l: 100, t: 100, w: 500, h: 500}, within: true});
+
+ // system-wide topics
+ dojo.subscribe("/dnd/move/start", function(node){
+ console.debug("Start move", node);
+ });
+ dojo.subscribe("/dnd/move/stop", function(node){
+ console.debug("Stop move", node);
+ });
+
+ // watching a particular moveable instance
+ dojo.connect(m5, "onDndMoveStart", function(mover){
+ console.debug("Start moving m5 with this mover:", mover);
+ });
+ dojo.connect(m5, "onDndMoveStop", function(mover){
+ console.debug("Stop moving m5 with this mover:", mover);
+ });
+ };
+ dojo.addOnLoad(init);
+ </script>
+</head>
+<body>
+ <h1>Dojo box constraint test</h1>
+ <p class="moveable" id="moveable5"><strong>Paragraph restricted to (100,100:500,500) box:</strong> Donec ac odio sed pede aliquet auctor. Donec et lectus. Praesent feugiat ultrices enim. Morbi lectus. Donec vestibulum posuere libero. Donec quam enim, nonummy a, auctor vitae, placerat id, massa. Vivamus vulputate luctus nibh. Donec dolor orci, sagittis ac, pretium sed, ornare sit amet, pede. Vestibulum leo justo, pellentesque sit amet, tristique sed, tempor eu, felis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam scelerisque velit vel sem. Curabitur vulputate. Morbi pretium porta dui.</p>
+ <p class="moveable" id="moveable6"><strong>Paragraph restricted to (100,100:500,500) box, it cannot go outside of this box:</strong> In hac habitasse platea dictumst. Etiam rhoncus, leo quis hendrerit vestibulum, ipsum felis porta massa, vitae posuere nunc lorem ac enim. Nam neque turpis, aliquet quis, sollicitudin sit amet, dapibus sed, eros. Duis volutpat porttitor velit. Vivamus nibh metus, iaculis eget, malesuada eget, facilisis id, lorem. Sed turpis. Vestibulum aliquam mauris. Integer malesuada tellus vel neque. In hac habitasse platea dictumst. Aliquam at lectus. Maecenas nonummy cursus nisl. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi imperdiet purus eu ipsum. Curabitur sapien felis, euismod eu, dapibus vel, tempor vitae, pede. Suspendisse blandit. Nulla imperdiet. Duis placerat nulla ultricies sem. In in mi nec ipsum molestie tempor. Sed scelerisque.</p>
+ <p class="moveable" dojoType="dojo.dnd.move.boxConstrainedMoveable" box="{l: 100, t: 100, w: 500, h: 500}"><strong>Marked up paragraph restricted to (100,100:500,500) box:</strong> Donec ac odio sed pede aliquet auctor. Donec et lectus. Praesent feugiat ultrices enim. Morbi lectus. Donec vestibulum posuere libero. Donec quam enim, nonummy a, auctor vitae, placerat id, massa. Vivamus vulputate luctus nibh. Donec dolor orci, sagittis ac, pretium sed, ornare sit amet, pede. Vestibulum leo justo, pellentesque sit amet, tristique sed, tempor eu, felis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam scelerisque velit vel sem. Curabitur vulputate. Morbi pretium porta dui.
+ </p>
+ <p class="moveable" dojoType="dojo.dnd.Moveable"><strong>Marked up paragraph restricted to (100,100:500,500) box, it cannot go outside of this box:</strong> In hac habitasse platea dictumst. Etiam rhoncus, leo quis hendrerit vestibulum, ipsum felis porta massa, vitae posuere nunc lorem ac enim. Nam neque turpis, aliquet quis, sollicitudin sit amet, dapibus sed, eros. Duis volutpat porttitor velit. Vivamus nibh metus, iaculis eget, malesuada eget, facilisis id, lorem. Sed turpis. Vestibulum aliquam mauris. Integer malesuada tellus vel neque. In hac habitasse platea dictumst. Aliquam at lectus. Maecenas nonummy cursus nisl. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi imperdiet purus eu ipsum. Curabitur sapien felis, euismod eu, dapibus vel, tempor vitae, pede. Suspendisse blandit. Nulla imperdiet. Duis placerat nulla ultricies sem. In in mi nec ipsum molestie tempor. Sed scelerisque.
+ <!-- this is the obsolete way to do it -->
+ <script type="dojo/method">this.mover = dojo.dnd.boxConstrainedMover({l: 100, t: 100, w: 500, h: 500}, true);</script>
+ </p>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_container.html b/includes/js/dojo/tests/dnd/test_container.html
new file mode 100644
index 0000000..352aa7a
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_container.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Dojo DnD container test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ @import "dndDefault.css";
+
+ body {
+ padding: 20px;
+ }
+
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript" src="../../dnd/Container.js"></script>
+ <script type="text/javascript">
+ // dojo.require("dojo.dnd.Container");
+ var c1, c2, c3, c4, c5;
+ var init = function(){
+ c1 = new dojo.dnd.Container(dojo.byId("container1"));
+ c2 = new dojo.dnd.Container(dojo.byId("container2"));
+ c3 = new dojo.dnd.Container(dojo.byId("container3"));
+ c4 = new dojo.dnd.Container(dojo.byId("container4"));
+ c5 = new dojo.dnd.Container(dojo.byId("container5"));
+ };
+ dojo.addOnLoad(init);
+ </script>
+</head>
+<body>
+ <h1>Dojo DnD container test</h1>
+ <p>Containers have a notion of a "current container", and one element can be "current".</p>
+ <p>see <a href="dndDefault.css">dndDefault.css</a> for example styling</p>
+ <h2>DIV container</h2>
+ <div id="container1" class="container">
+ <div class="dojoDndItem">Item 1</div>
+ <div class="dojoDndItem">Item 2</div>
+ <div class="dojoDndItem">Item 3</div>
+ </div>
+ <h2>UL container</h2>
+ <ul id="container2" class="container">
+ <li class="dojoDndItem">Item 1</li>
+ <li class="dojoDndItem">Item 2</li>
+ <li class="dojoDndItem">Item 3</li>
+ </ul>
+ <h2>OL container</h2>
+ <ol id="container3" class="container">
+ <li class="dojoDndItem">Item 1</li>
+ <li class="dojoDndItem">Item 2</li>
+ <li class="dojoDndItem">Item 3</li>
+ </ol>
+ <h2>TABLE container</h2>
+ <table id="container4" class="container" border="1px solid black">
+ <tr class="dojoDndItem">
+ <td>A</td>
+ <td>row 1</td>
+ </tr>
+ <tr class="dojoDndItem">
+ <td>B</td>
+ <td>row 2</td>
+ </tr>
+ <tr class="dojoDndItem">
+ <td>C</td>
+ <td>row 3</td>
+ </tr>
+ </table>
+ <h2>P container with SPAN elements</h2>
+ <p>Elements of this container are layed out horizontally.</p>
+ <p id="container5" class="container">
+ <span class="dojoDndItem">&nbsp;Item 1&nbsp;</span>
+ <span class="dojoDndItem">&nbsp;Item 2&nbsp;</span>
+ <span class="dojoDndItem">&nbsp;Item 3&nbsp;</span>
+ </p>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_container_markup.html b/includes/js/dojo/tests/dnd/test_container_markup.html
new file mode 100644
index 0000000..4bde544
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_container_markup.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Dojo DnD markup container test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ @import "dndDefault.css";
+
+ body {
+ padding: 20px;
+ }
+
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript" src="../../dnd/Container.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dojo.dnd.Container");
+ </script>
+</head>
+<body>
+ <h1>Dojo DnD markup container test</h1>
+ <p>This example is functionally equivalent to <a href="test_container.html">test_container.html</a> example but is done using the Dojo markup.</p>
+ <p>Containers have a notion of a "current container", and one element can be "current".</p>
+ <p>See <a href="dndDefault.css">dndDefault.css</a> for example styling</p>
+ <h2>DIV container</h2>
+ <div dojoType="dojo.dnd.Container" jsId="c1" class="container">
+ <div class="dojoDndItem">Item 1</div>
+ <div class="dojoDndItem">Item 2</div>
+ <div class="dojoDndItem">Item 3</div>
+ </div>
+ <h2>UL container</h2>
+ <ul dojoType="dojo.dnd.Container" jsId="c2" class="container">
+ <li class="dojoDndItem">Item 1</li>
+ <li class="dojoDndItem">Item 2</li>
+ <li class="dojoDndItem">Item 3</li>
+ </ul>
+ <h2>OL container</h2>
+ <ol dojoType="dojo.dnd.Container" jsId="c3" class="container">
+ <li class="dojoDndItem">Item 1</li>
+ <li class="dojoDndItem">Item 2</li>
+ <li class="dojoDndItem">Item 3</li>
+ </ol>
+ <h2>TABLE container</h2>
+ <table dojoType="dojo.dnd.Container" jsId="c4" class="container" border="1px solid black">
+ <tr class="dojoDndItem">
+ <td>A</td>
+ <td>row 1</td>
+ </tr>
+ <tr class="dojoDndItem">
+ <td>B</td>
+ <td>row 2</td>
+ </tr>
+ <tr class="dojoDndItem">
+ <td>C</td>
+ <td>row 3</td>
+ </tr>
+ </table>
+ <h2>P container with SPAN elements</h2>
+ <p>Elements of this container are layed out horizontally.</p>
+ <p dojoType="dojo.dnd.Container" jsId="c5" class="container">
+ <span class="dojoDndItem">&nbsp;Item 1&nbsp;</span>
+ <span class="dojoDndItem">&nbsp;Item 2&nbsp;</span>
+ <span class="dojoDndItem">&nbsp;Item 3&nbsp;</span>
+ </p>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_custom_constraints.html b/includes/js/dojo/tests/dnd/test_custom_constraints.html
new file mode 100644
index 0000000..9140914
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_custom_constraints.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Dojo custom constraint test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+
+ body {
+ padding: 1em;
+ }
+
+ .moveable {
+ background: #FFFFBF;
+ border: 1px solid black;
+ width: 300px;
+ padding: 10px 20px;
+ margin: 0px;
+ cursor: pointer;
+ }
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript" src="../../dnd/move.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.dnd.move");
+
+ var STEP = 50;
+
+ var init = function(){
+ // 1st way
+ var m1 = new dojo.dnd.Moveable("moveable1");
+ m1.onMove = function(mover, leftTop){
+ leftTop.l -= leftTop.l % STEP;
+ leftTop.t -= leftTop.t % STEP;
+ dojo.marginBox(mover.node, leftTop);
+ };
+ // 2nd way
+ var m2 = new dojo.dnd.Moveable("moveable2");
+ dojo.connect(m2, "onMoving", function(mover, leftTop){
+ leftTop.l -= leftTop.l % STEP;
+ leftTop.t -= leftTop.t % STEP;
+ });
+ };
+ dojo.addOnLoad(init);
+ </script>
+</head>
+<body>
+ <h1>Dojo custom constraint test</h1>
+ <p class="moveable" id="moveable1"><strong>This paragraph stops at 50x50 grid knots:</strong> Donec ac odio sed pede aliquet auctor. Donec et lectus. Praesent feugiat ultrices enim. Morbi lectus. Donec vestibulum posuere libero. Donec quam enim, nonummy a, auctor vitae, placerat id, massa. Vivamus vulputate luctus nibh. Donec dolor orci, sagittis ac, pretium sed, ornare sit amet, pede. Vestibulum leo justo, pellentesque sit amet, tristique sed, tempor eu, felis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam scelerisque velit vel sem. Curabitur vulputate. Morbi pretium porta dui.</p>
+ <p class="moveable" id="moveable2"><strong>This paragraph stops at 50x50 grid knots:</strong> Donec ac odio sed pede aliquet auctor. Donec et lectus. Praesent feugiat ultrices enim. Morbi lectus. Donec vestibulum posuere libero. Donec quam enim, nonummy a, auctor vitae, placerat id, massa. Vivamus vulputate luctus nibh. Donec dolor orci, sagittis ac, pretium sed, ornare sit amet, pede. Vestibulum leo justo, pellentesque sit amet, tristique sed, tempor eu, felis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam scelerisque velit vel sem. Curabitur vulputate. Morbi pretium porta dui.</p>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_dnd.html b/includes/js/dojo/tests/dnd/test_dnd.html
new file mode 100644
index 0000000..7e2a56a
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_dnd.html
@@ -0,0 +1,130 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Dojo DnD test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ @import "../../resources/dnd.css";
+ @import "dndDefault.css";
+
+ body {
+ padding: 1em;
+ background: #ededed;
+ }
+
+ .container {
+ width: 100px;
+ display: block;
+ }
+
+ .clear {
+ clear: both;
+ }
+ </style>
+
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+
+ <script type="text/javascript" src="../../dnd/Container.js"></script>
+ <script type="text/javascript" src="../../dnd/Selector.js"></script>
+ <script type="text/javascript" src="../../dnd/Source.js"></script>
+ <script type="text/javascript" src="../../dnd/Avatar.js"></script>
+ <script type="text/javascript" src="../../dnd/Manager.js"></script>
+
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dojo.dnd.Source");
+
+ var c1;
+
+ function init(){
+ c1 = new dojo.dnd.Source("container1");
+ c1.insertNodes(false, [1, "A", [1, 2, 3],
+ function(x){ return x + x; },
+ {toString: function(){ return "CUSTOM!"; }},
+ null]);
+
+ // example subscribe to events
+ dojo.subscribe("/dnd/start", function(source){
+ console.debug("Starting the drop", source);
+ });
+ dojo.subscribe("/dnd/drop/before", function(source, nodes, copy, target){
+ if(target == c1){
+ console.debug(copy ? "Copying from" : "Moving from", source, "to", target, "before", target.before);
+ }
+ });
+ dojo.subscribe("/dnd/drop", function(source, nodes, copy, target){
+ if(target == c1){
+ console.debug(copy ? "Copying from" : "Moving from", source, "to", target, "before", target.before);
+ }
+ });
+ dojo.connect(c4, "onDndDrop", function(source, nodes, copy, target){
+ if(target == c4){
+ console.debug(copy ? "Copying from" : "Moving from", source);
+ }
+ });
+ };
+
+ dojo.addOnLoad(init);
+ </script>
+</head>
+<body>
+ <h1 class="testTitle">Dojo DnD test</h1>
+
+ <p>Elements of both sources/targets were created dynamically.</p>
+ <p>Following selection modes are supported by default:</p>
+ <ul>
+ <li>Simple click &mdash; selects a single element, all other elements will be unselected.</li>
+ <li>Ctrl+click &mdash; toggles a selection state of an element (use Meta key on Mac).</li>
+ <li>Shift+click &mdash; selects a range of element from the previous anchor to the current element.</li>
+ <li>Ctrl+Shift+click &mdash; adds a range of element from the previous anchor to the current element (use Meta key on Mac).</li>
+ </ul>
+ <p>Following drop modes are supported by default:</p>
+ <ul>
+ <li>Simple drop &mdash; moves elements to the valid target removing them from the source. It can be used to reorganize elements within a single source/target.</li>
+ <li>Ctrl+drop &mdash; copies elements to the valid target (use Meta key on Mac).</li>
+ </ul>
+
+ <div id="dragLists">
+ <div style="float: left; margin: 5px;">
+ <h3>Source 1</h3>
+ <div id="container1" class="container"></div>
+ </div>
+ <div style="float: left; margin: 5px;">
+ <h3>Source 2</h3>
+ <div dojoType="dojo.dnd.Source" jsId="c2" class="container">
+ <div class="dojoDndItem">Item <strong>X</strong></div>
+ <div class="dojoDndItem">Item <strong>Y</strong></div>
+ <div class="dojoDndItem">Item <strong>Z</strong></div>
+ </div>
+ </div>
+ <div style="float: left; margin: 5px;">
+ <h3>Source 3</h3>
+ <div dojoType="dojo.dnd.Source" jsId="c3" class="container">
+ <script type="dojo/method" event="creator" args="item, hint">
+ // this is custom creator, which changes the avatar representation
+ var node = dojo.doc.createElement("div"), s = String(item);
+ node.id = dojo.dnd.getUniqueId();
+ node.className = "dojoDndItem";
+ node.innerHTML = (hint != "avatar" || s.indexOf("Item") < 0) ?
+ s : "<strong style='color: darkred'>Special</strong> " + s;
+ return {node: node, data: item, type: ["text"]};
+ </script>
+ <div class="dojoDndItem">Item <strong>Alpha</strong></div>
+ <div class="dojoDndItem">Item <strong>Beta</strong></div>
+ <div class="dojoDndItem">Item <strong>Gamma</strong></div>
+ <div class="dojoDndItem">Item <strong>Delta</strong></div>
+ </div>
+ </div>
+ <div style="float: left; margin: 5px;">
+ <h3>Pure Target 4</h3>
+ <div dojoType="dojo.dnd.Target" jsId="c4" class="container">
+ <div class="dojoDndItem">One item</div>
+ </div>
+ </div>
+ <div class="clear"></div>
+ </div>
+
+ <p>HTML after</p>
+
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_dnd_handles.html b/includes/js/dojo/tests/dnd/test_dnd_handles.html
new file mode 100644
index 0000000..bcc58dc
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_dnd_handles.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Dojo DnD with handles test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ @import "../../resources/dnd.css";
+ @import "dndDefault.css";
+
+ body { padding: 1em; background: #ededed; }
+
+ .container { width: 100px; display: block; }
+ .container.handles .dojoDndHandle { background: #fee; }
+ .clear { clear: both; }
+ </style>
+
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+
+ <script type="text/javascript" src="../../dnd/Container.js"></script>
+ <script type="text/javascript" src="../../dnd/Selector.js"></script>
+ <script type="text/javascript" src="../../dnd/Source.js"></script>
+ <script type="text/javascript" src="../../dnd/Avatar.js"></script>
+ <script type="text/javascript" src="../../dnd/Manager.js"></script>
+
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dojo.dnd.Source");
+ </script>
+</head>
+<body>
+ <h1 class="testTitle">Dojo DnD with handles test</h1>
+
+ <p>Following selection modes are supported by default:</p>
+ <ul>
+ <li>Simple click &mdash; selects a single element, all other elements will be unselected.</li>
+ <li>Ctrl+click &mdash; toggles a selection state of an element (use Meta key on Mac).</li>
+ <li>Shift+click &mdash; selects a range of element from the previous anchor to the current element.</li>
+ <li>Ctrl+Shift+click &mdash; adds a range of element from the previous anchor to the current element (use Meta key on Mac).</li>
+ </ul>
+ <p>Following drop modes are supported by default:</p>
+ <ul>
+ <li>Simple drop &mdash; moves elements to the valid target removing them from the source. It can be used to reorganize elements within a single source/target.</li>
+ <li>Ctrl+drop &mdash; copies elements to the valid target (use Meta key on Mac).</li>
+ </ul>
+
+ <p>Source with handles. Items should be draggable by "Item".</p>
+ <div dojoType="dojo.dnd.Source" jsId="c1" withHandles="true" class="container handles">
+ <div class="dojoDndItem"><span class="dojoDndHandle">Item</span> <strong>Alpha</strong></div>
+ <div class="dojoDndItem"><span class="dojoDndHandle">Item</span> <strong>Beta</strong></div>
+ <div class="dojoDndItem"><span class="dojoDndHandle">Item</span> <strong>Gamma</strong></div>
+ <div class="dojoDndItem"><span class="dojoDndHandle">Item</span> <strong>Delta</strong></div>
+ </div>
+
+ <p>Source without handles.</p>
+ <div dojoType="dojo.dnd.Source" jsId="c2" class="container">
+ <div class="dojoDndItem"><span class="dojoDndHandle">Item</span> <strong>Epsilon</strong></div>
+ <div class="dojoDndItem"><span class="dojoDndHandle">Item</span> <strong>Zeta</strong></div>
+ <div class="dojoDndItem"><span class="dojoDndHandle">Item</span> <strong>Eta</strong></div>
+ <div class="dojoDndItem"><span class="dojoDndHandle">Item</span> <strong>Theta</strong></div>
+ </div>
+
+ <p>HTML after</p>
+
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_form.html b/includes/js/dojo/tests/dnd/test_form.html
new file mode 100644
index 0000000..cac46c0
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_form.html
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Dojo DnD form test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ @import "../../resources/dnd.css";
+ @import "dndDefault.css";
+
+ body {
+ padding: 1em;
+ background:#ededed;
+ }
+
+ #container1,#container2 { width:300px; display:block; }
+ .clear { clear:both; }
+
+ </style>
+
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+
+ <script type="text/javascript" src="../../dnd/Container.js"></script>
+ <script type="text/javascript" src="../../dnd/Selector.js"></script>
+ <script type="text/javascript" src="../../dnd/Source.js"></script>
+ <script type="text/javascript" src="../../dnd/Avatar.js"></script>
+ <script type="text/javascript" src="../../dnd/Manager.js"></script>
+
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ //dojo.require("dojo.dnd.Source");
+ //dojo.require("dojo.dnd.Manager");
+
+ var c1, c2;
+
+ function init(){
+
+ c1 = new dojo.dnd.Source("container1");
+ c1.insertNodes(false, [1, 2, 3, 4, 5, 6, [1, 2, 3], function(x){ return x + x; }]);
+ c2 = new dojo.dnd.Target("container2", {accept: ["money"]});
+
+ // example subscribe to events
+ dojo.subscribe("/dnd/start",function(foo){
+ console.debug(foo);
+ });
+
+ };
+ dojo.addOnLoad(init);
+ </script>
+</head>
+<body>
+ <h1 class="testTitle">Dojo DnD form test</h1>
+
+ <p>This is a test to confirm that the DnD container does not interfere with form elements.</p>
+
+ <div id="dragLists">
+
+ <div style="float:left; margin:5px; ">
+ <h3>Target 1</h3>
+ <p id="container1" class="container"></p>
+ </div>
+
+ <div style="float:left; margin:5px; ">
+ <h3>Target 2: form controls galore</h3>
+ <form id="container2" class="container" action="http://dojotoolkit.org">
+ Input text: <input type="text" /><br />
+ Input checkbox: <input type="checkbox" /><br />
+ Input radio: <input type="radio" /><br />
+ Input password: <input type="password" /><br />
+ Input file: <input type="file" /><br />
+ Input button: <input type="button" value="Button" /><br />
+ Input reset: <input type="reset" /><br />
+ Input submit: <input type="submit" /><br />
+ Input image: <input type="image" src="http://dojotoolkit.org/misc/feed.png" /><br />
+ Button: <button>Button</button><br />
+ Select: <select><option>Yes</option><option>No</option></select><br />
+ Textarea: <textarea cols="20" rows="3">Some text.</textarea>
+ </form>
+ </div>
+ <div class="clear"></div>
+ </div>
+
+ <p>&nbsp;</p>
+
+ <div dojoType="dojo.dnd.Source" class="container">
+ <div>Source with <strong>skipForm = false</strong> (by default)</div>
+ <div class="dojoDndItem">Item <strong>X</strong>: <input type="text" value="1" /></div>
+ <div class="dojoDndItem">Item <strong>Y</strong>: <input type="text" value="2" /></div>
+ <div class="dojoDndItem">Item <strong>Z</strong>: <input type="text" value="3" /></div>
+ </div>
+
+ <p>&nbsp;</p>
+
+ <div dojoType="dojo.dnd.Source" class="container" skipForm="true">
+ <div>Source with <strong>skipForm = true</strong></div>
+ <div class="dojoDndItem">Item <strong>A</strong>: <input type="text" value="a" /></div>
+ <div class="dojoDndItem">Item <strong>B</strong>: <input type="text" value="b" /></div>
+ <div class="dojoDndItem">Item <strong>C</strong>: <input type="text" value="c" /></div>
+ </div>
+
+ <p>HTML after</p>
+
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_moveable.html b/includes/js/dojo/tests/dnd/test_moveable.html
new file mode 100644
index 0000000..3f7e2e7
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_moveable.html
@@ -0,0 +1,106 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Dojo Moveable test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ @import "dndDefault.css";
+
+ body {
+ padding: 1em;
+ color:#666;
+ background-color:#dedede;
+ }
+
+ #moveable1 {
+ background: #fff;
+ border: 1px solid black;
+ padding:8px;
+ }
+ #handle1 {
+ background: #333;
+ color: #fff;
+ font-weight: bold;
+ cursor: pointer;
+ border: 1px solid black;
+ }
+ #moveable2 {
+ position: absolute;
+ background: #fff;
+ width: 200px;
+ height: 200px;
+ left: 100px;
+ top: 100px;
+ padding: 10px 20px;
+ margin: 10px 20px;
+ border: 10px solid black;
+ cursor: pointer;
+ radius:8pt;
+ -moz-border-radius:8pt 8pt;
+ }
+ #moveable3 {
+ position: relative;
+ width: 150px;
+ height: 100px;
+ background: #ff8;
+ color: blue;
+ font-weight: bold;
+ }
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript" src="../../dnd/Mover.js"></script>
+ <script type="text/javascript" src="../../dnd/Moveable.js"></script>
+ <script type="text/javascript" src="../../dnd/move.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.dnd.move");
+ var m1, m2;
+ var init = function(){
+ m1 = new dojo.dnd.Moveable("moveable1", {handle: "handle1"});
+ m2 = new dojo.dnd.Moveable("moveable2");
+ m3 = new dojo.dnd.Moveable("moveable3");
+
+ dojo.subscribe("/dnd/move/start", function(mover){
+ console.debug("Start move", mover);
+ });
+ dojo.subscribe("/dnd/move/stop", function(mover){
+ console.debug("Stop move", mover);
+ });
+
+ dojo.connect(m1, "onMoveStart", function(mover){
+ console.debug("Start moving m1", mover);
+ });
+ dojo.connect(m1, "onMoveStop", function(mover){
+ console.debug("Stop moving m1", mover);
+ });
+ };
+ dojo.addOnLoad(init);
+ </script>
+</head>
+<body>
+ <h1>Dojo Moveable test</h1>
+ <h2>1st run</h2>
+ <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Praesent erat. In malesuada ultricies velit. Vestibulum tempor odio vitae diam. Morbi arcu lectus, laoreet eget, nonummy at, elementum a, quam. Pellentesque ac lacus. Cras quis est. Etiam suscipit, quam at eleifend nonummy, elit nunc sollicitudin tellus, at mattis est ligula interdum urna. Vivamus id augue sed mi consectetuer dictum. Suspendisse dapibus elit non urna. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam gravida dapibus ante. Nam viverra ligula in neque. Nullam at metus. Aenean ipsum.</p>
+ <p>Mauris vulputate elit a risus. Praesent pellentesque velit ac neque. Fusce ultrices augue vitae orci. Proin a ante. Nulla consectetuer arcu quis est. Suspendisse potenti. Aliquam erat volutpat. Morbi purus augue, eleifend eu, consectetuer sed, tristique ut, wisi. Cras ac tellus. Phasellus adipiscing, libero ac consequat volutpat, ligula purus mollis lectus, ac porttitor ipsum diam non urna. Donec lorem. Pellentesque diam tortor, posuere et, placerat vitae, iaculis et, sapien. Proin sodales vehicula purus. Quisque bibendum mi ac mauris. Quisque tellus. Morbi sagittis. Integer euismod rhoncus augue. Ut accumsan. Curabitur quis tellus sit amet odio ultricies tristique. Etiam malesuada.</p>
+ <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec est. Cras semper nunc ut metus. Pellentesque blandit pede at erat. Quisque nonummy leo id metus. Donec mi mi, viverra id, adipiscing vitae, consectetuer ut, elit. In lectus augue, porttitor quis, viverra id, dignissim id, leo. Maecenas sapien. Nam adipiscing sem. Aenean ligula. Etiam vel velit. In mollis cursus dolor. Suspendisse ac nibh id leo tempor posuere. Aliquam sapien tellus, elementum non, aliquam sed, luctus eu, augue. Aliquam elementum leo nec enim. Donec ornare sagittis magna. Mauris ac tellus.</p>
+ <p>Duis ac augue rhoncus neque adipiscing feugiat. Donec pulvinar sem vitae neque. Donec commodo metus at ipsum. Cras vel magna vehicula lorem varius consequat. Morbi at enim vitae lectus mollis sodales. Sed tincidunt quam ut mi varius hendrerit. Sed porta arcu non libero. Quisque et wisi. Pellentesque lobortis. Ut enim felis, varius vitae, ornare quis, auctor ut, risus. Ut porta lorem vel quam. Etiam nunc purus, consectetuer non, lobortis eu, fermentum eu, magna. Aenean ultrices ante. Aliquam erat volutpat. Morbi quis velit eu mi sollicitudin lacinia. Suspendisse potenti. Donec lectus.</p>
+ <p>Quisque egestas turpis. Sed id ipsum id libero euismod nonummy. Nam sed dolor. Mauris in turpis. Duis nec wisi eget ante ultrices varius. Ut eget neque. Suspendisse sagittis iaculis tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Phasellus at justo. Donec imperdiet, elit et commodo bibendum, leo augue pellentesque arcu, ac dapibus lorem nulla eget erat. In viverra, tellus eu luctus eleifend, urna nibh lobortis sapien, ac pulvinar massa enim vel turpis. Sed orci neque, sagittis eu, mattis vitae, rutrum condimentum, leo. Fusce wisi odio, convallis at, condimentum vel, imperdiet id, mi. Mauris semper, magna pretium consectetuer sollicitudin, eros enim vehicula risus, eu ultrices turpis quam at wisi. Nam mollis.</p>
+ <table id="moveable1">
+ <tr><td id="handle1" colspan="2">You can drag the table using this handle.</td></tr>
+ <tr><td>1</td><td>Lorem ipsum dolor sit amet...</td></tr>
+ <tr><td>2</td><td>Mauris vulputate elit a risus...</td></tr>
+ <tr><td>3</td><td>Pellentesque habitant morbi tristique senectus...</td></tr>
+ <tr><td>4</td><td>Duis ac augue rhoncus neque...</td></tr>
+ <tr><td>5</td><td>Quisque egestas turpis. Sed id...</td></tr>
+ </table>
+ <h2>2nd run</h2>
+ <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Praesent erat. In malesuada ultricies velit. Vestibulum tempor odio vitae diam. Morbi arcu lectus, laoreet eget, nonummy at, elementum a, quam. Pellentesque ac lacus. Cras quis est. Etiam suscipit, quam at eleifend nonummy, elit nunc sollicitudin tellus, at mattis est ligula interdum urna. Vivamus id augue sed mi consectetuer dictum. Suspendisse dapibus elit non urna. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam gravida dapibus ante. Nam viverra ligula in neque. Nullam at metus. Aenean ipsum.</p>
+ <p>Mauris vulputate elit a risus. Praesent pellentesque velit ac neque. Fusce ultrices augue vitae orci. Proin a ante. Nulla consectetuer arcu quis est. Suspendisse potenti. Aliquam erat volutpat. Morbi purus augue, eleifend eu, consectetuer sed, tristique ut, wisi. Cras ac tellus. Phasellus adipiscing, libero ac consequat volutpat, ligula purus mollis lectus, ac porttitor ipsum diam non urna. Donec lorem. Pellentesque diam tortor, posuere et, placerat vitae, iaculis et, sapien. Proin sodales vehicula purus. Quisque bibendum mi ac mauris. Quisque tellus. Morbi sagittis. Integer euismod rhoncus augue. Ut accumsan. Curabitur quis tellus sit amet odio ultricies tristique. Etiam malesuada.</p>
+ <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec est. Cras semper nunc ut metus. Pellentesque blandit pede at erat. Quisque nonummy leo id metus. Donec mi mi, viverra id, adipiscing vitae, consectetuer ut, elit. In lectus augue, porttitor quis, viverra id, dignissim id, leo. Maecenas sapien. Nam adipiscing sem. Aenean ligula. Etiam vel velit. In mollis cursus dolor. Suspendisse ac nibh id leo tempor posuere. Aliquam sapien tellus, elementum non, aliquam sed, luctus eu, augue. Aliquam elementum leo nec enim. Donec ornare sagittis magna. Mauris ac tellus.</p>
+ <p>Duis ac augue rhoncus neque adipiscing feugiat. Donec pulvinar sem vitae neque. Donec commodo metus at ipsum. Cras vel magna vehicula lorem varius consequat. Morbi at enim vitae lectus mollis sodales. Sed tincidunt quam ut mi varius hendrerit. Sed porta arcu non libero. Quisque et wisi. Pellentesque lobortis. Ut enim felis, varius vitae, ornare quis, auctor ut, risus. Ut porta lorem vel quam. Etiam nunc purus, consectetuer non, lobortis eu, fermentum eu, magna. Aenean ultrices ante. Aliquam erat volutpat. Morbi quis velit eu mi sollicitudin lacinia. Suspendisse potenti. Donec lectus.</p>
+ <p>Quisque egestas turpis. Sed id ipsum id libero euismod nonummy. Nam sed dolor. Mauris in turpis. Duis nec wisi eget ante ultrices varius. Ut eget neque. Suspendisse sagittis iaculis tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Phasellus at justo. Donec imperdiet, elit et commodo bibendum, leo augue pellentesque arcu, ac dapibus lorem nulla eget erat. In viverra, tellus eu luctus eleifend, urna nibh lobortis sapien, ac pulvinar massa enim vel turpis. Sed orci neque, sagittis eu, mattis vitae, rutrum condimentum, leo. Fusce wisi odio, convallis at, condimentum vel, imperdiet id, mi. Mauris semper, magna pretium consectetuer sollicitudin, eros enim vehicula risus, eu ultrices turpis quam at wisi. Nam mollis.</p>
+ <div id="moveable2">
+ <div>You can drag this whole object around.</div>
+ <div id="moveable3">You can move this paragraph. It is relatively positioned.</div>
+ </div>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_moveable_markup.html b/includes/js/dojo/tests/dnd/test_moveable_markup.html
new file mode 100644
index 0000000..1f63d13
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_moveable_markup.html
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Dojo Moveable markup test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ @import "dndDefault.css";
+
+ body {
+ padding: 1em;
+ color:#666;
+ background-color:#dedede;
+ }
+
+ #moveable1 {
+ background: #fff;
+ border: 1px solid black;
+ padding:8px;
+ }
+ #handle1 {
+ background: #333;
+ color: #fff;
+ font-weight:bold;
+ cursor: pointer;
+ border: 1px solid black;
+ }
+ #moveable2 {
+ background: #fff;
+ position: absolute;
+ width: 200px;
+ height: 200px;
+ left: 100px;
+ top: 100px;
+ padding: 10px 20px;
+ margin: 10px 20px;
+ border: 10px solid black;
+ cursor: pointer;
+ radius:8pt;
+ -moz-border-radius:8pt 8pt;
+ }
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript" src="../../dnd/move.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dojo.dnd.move");
+
+ dojo.addOnLoad(function(){
+ dojo.subscribe("/dnd/move/start", function(node){
+ console.debug("Start move", node);
+ });
+
+ dojo.subscribe("/dnd/move/stop", function(node){
+ console.debug("Stop move", node);
+ });
+ });
+ </script>
+</head>
+<body>
+ <h1>Dojo Moveable markup test</h1>
+ <h2>1st run</h2>
+ <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Praesent erat. In malesuada ultricies velit. Vestibulum tempor odio vitae diam. Morbi arcu lectus, laoreet eget, nonummy at, elementum a, quam. Pellentesque ac lacus. Cras quis est. Etiam suscipit, quam at eleifend nonummy, elit nunc sollicitudin tellus, at mattis est ligula interdum urna. Vivamus id augue sed mi consectetuer dictum. Suspendisse dapibus elit non urna. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam gravida dapibus ante. Nam viverra ligula in neque. Nullam at metus. Aenean ipsum.</p>
+ <p>Mauris vulputate elit a risus. Praesent pellentesque velit ac neque. Fusce ultrices augue vitae orci. Proin a ante. Nulla consectetuer arcu quis est. Suspendisse potenti. Aliquam erat volutpat. Morbi purus augue, eleifend eu, consectetuer sed, tristique ut, wisi. Cras ac tellus. Phasellus adipiscing, libero ac consequat volutpat, ligula purus mollis lectus, ac porttitor ipsum diam non urna. Donec lorem. Pellentesque diam tortor, posuere et, placerat vitae, iaculis et, sapien. Proin sodales vehicula purus. Quisque bibendum mi ac mauris. Quisque tellus. Morbi sagittis. Integer euismod rhoncus augue. Ut accumsan. Curabitur quis tellus sit amet odio ultricies tristique. Etiam malesuada.</p>
+ <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec est. Cras semper nunc ut metus. Pellentesque blandit pede at erat. Quisque nonummy leo id metus. Donec mi mi, viverra id, adipiscing vitae, consectetuer ut, elit. In lectus augue, porttitor quis, viverra id, dignissim id, leo. Maecenas sapien. Nam adipiscing sem. Aenean ligula. Etiam vel velit. In mollis cursus dolor. Suspendisse ac nibh id leo tempor posuere. Aliquam sapien tellus, elementum non, aliquam sed, luctus eu, augue. Aliquam elementum leo nec enim. Donec ornare sagittis magna. Mauris ac tellus.</p>
+ <p>Duis ac augue rhoncus neque adipiscing feugiat. Donec pulvinar sem vitae neque. Donec commodo metus at ipsum. Cras vel magna vehicula lorem varius consequat. Morbi at enim vitae lectus mollis sodales. Sed tincidunt quam ut mi varius hendrerit. Sed porta arcu non libero. Quisque et wisi. Pellentesque lobortis. Ut enim felis, varius vitae, ornare quis, auctor ut, risus. Ut porta lorem vel quam. Etiam nunc purus, consectetuer non, lobortis eu, fermentum eu, magna. Aenean ultrices ante. Aliquam erat volutpat. Morbi quis velit eu mi sollicitudin lacinia. Suspendisse potenti. Donec lectus.</p>
+ <p>Quisque egestas turpis. Sed id ipsum id libero euismod nonummy. Nam sed dolor. Mauris in turpis. Duis nec wisi eget ante ultrices varius. Ut eget neque. Suspendisse sagittis iaculis tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Phasellus at justo. Donec imperdiet, elit et commodo bibendum, leo augue pellentesque arcu, ac dapibus lorem nulla eget erat. In viverra, tellus eu luctus eleifend, urna nibh lobortis sapien, ac pulvinar massa enim vel turpis. Sed orci neque, sagittis eu, mattis vitae, rutrum condimentum, leo. Fusce wisi odio, convallis at, condimentum vel, imperdiet id, mi. Mauris semper, magna pretium consectetuer sollicitudin, eros enim vehicula risus, eu ultrices turpis quam at wisi. Nam mollis.</p>
+ <table id="moveable1" dojoType="dojo.dnd.Moveable" handle="handle1">
+ <tr><td id="handle1" colspan="2">You can drag the table using this handle.</td></tr>
+ <tr><td>1</td><td>Lorem ipsum dolor sit amet...</td></tr>
+ <tr><td>2</td><td>Mauris vulputate elit a risus...</td></tr>
+ <tr><td>3</td><td>Pellentesque habitant morbi tristique senectus...</td></tr>
+ <tr><td>4</td><td>Duis ac augue rhoncus neque...</td></tr>
+ <tr><td>5</td><td>Quisque egestas turpis. Sed id...</td></tr>
+ </table>
+ <h2>2nd run</h2>
+ <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Praesent erat. In malesuada ultricies velit. Vestibulum tempor odio vitae diam. Morbi arcu lectus, laoreet eget, nonummy at, elementum a, quam. Pellentesque ac lacus. Cras quis est. Etiam suscipit, quam at eleifend nonummy, elit nunc sollicitudin tellus, at mattis est ligula interdum urna. Vivamus id augue sed mi consectetuer dictum. Suspendisse dapibus elit non urna. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam gravida dapibus ante. Nam viverra ligula in neque. Nullam at metus. Aenean ipsum.</p>
+ <p>Mauris vulputate elit a risus. Praesent pellentesque velit ac neque. Fusce ultrices augue vitae orci. Proin a ante. Nulla consectetuer arcu quis est. Suspendisse potenti. Aliquam erat volutpat. Morbi purus augue, eleifend eu, consectetuer sed, tristique ut, wisi. Cras ac tellus. Phasellus adipiscing, libero ac consequat volutpat, ligula purus mollis lectus, ac porttitor ipsum diam non urna. Donec lorem. Pellentesque diam tortor, posuere et, placerat vitae, iaculis et, sapien. Proin sodales vehicula purus. Quisque bibendum mi ac mauris. Quisque tellus. Morbi sagittis. Integer euismod rhoncus augue. Ut accumsan. Curabitur quis tellus sit amet odio ultricies tristique. Etiam malesuada.</p>
+ <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec est. Cras semper nunc ut metus. Pellentesque blandit pede at erat. Quisque nonummy leo id metus. Donec mi mi, viverra id, adipiscing vitae, consectetuer ut, elit. In lectus augue, porttitor quis, viverra id, dignissim id, leo. Maecenas sapien. Nam adipiscing sem. Aenean ligula. Etiam vel velit. In mollis cursus dolor. Suspendisse ac nibh id leo tempor posuere. Aliquam sapien tellus, elementum non, aliquam sed, luctus eu, augue. Aliquam elementum leo nec enim. Donec ornare sagittis magna. Mauris ac tellus.</p>
+ <p>Duis ac augue rhoncus neque adipiscing feugiat. Donec pulvinar sem vitae neque. Donec commodo metus at ipsum. Cras vel magna vehicula lorem varius consequat. Morbi at enim vitae lectus mollis sodales. Sed tincidunt quam ut mi varius hendrerit. Sed porta arcu non libero. Quisque et wisi. Pellentesque lobortis. Ut enim felis, varius vitae, ornare quis, auctor ut, risus. Ut porta lorem vel quam. Etiam nunc purus, consectetuer non, lobortis eu, fermentum eu, magna. Aenean ultrices ante. Aliquam erat volutpat. Morbi quis velit eu mi sollicitudin lacinia. Suspendisse potenti. Donec lectus.</p>
+ <p>Quisque egestas turpis. Sed id ipsum id libero euismod nonummy. Nam sed dolor. Mauris in turpis. Duis nec wisi eget ante ultrices varius. Ut eget neque. Suspendisse sagittis iaculis tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Phasellus at justo. Donec imperdiet, elit et commodo bibendum, leo augue pellentesque arcu, ac dapibus lorem nulla eget erat. In viverra, tellus eu luctus eleifend, urna nibh lobortis sapien, ac pulvinar massa enim vel turpis. Sed orci neque, sagittis eu, mattis vitae, rutrum condimentum, leo. Fusce wisi odio, convallis at, condimentum vel, imperdiet id, mi. Mauris semper, magna pretium consectetuer sollicitudin, eros enim vehicula risus, eu ultrices turpis quam at wisi. Nam mollis.</p>
+ <div id="moveable2" dojoType="dojo.dnd.Moveable">You can drag this whole paragraph around.</div>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_params.html b/includes/js/dojo/tests/dnd/test_params.html
new file mode 100644
index 0000000..1be540c
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_params.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Dojo DnD optional parameters test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+
+ body {
+ padding: 1em;
+ }
+
+ .moveable {
+ background: #FFFFBF;
+ border: 1px solid black;
+ width: 300px;
+ padding: 10px 20px;
+ cursor: pointer;
+ }
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript" src="../../dnd/move.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.dnd.move");
+ var m1, m2, m3, m4;
+ var init = function(){
+ m1 = new dojo.dnd.Moveable("moveable1");
+ m2 = new dojo.dnd.Moveable("moveable2", {delay: 10});
+ m3 = new dojo.dnd.Moveable("moveable3");
+ m4 = new dojo.dnd.Moveable("moveable4", {skip: true});
+ };
+ dojo.addOnLoad(init);
+ </script>
+</head>
+<body>
+ <h1>Dojo DnD optional parameters test</h1>
+ <p class="moveable" id="moveable1"><strong>Normal paragraph:</strong> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Mauris augue augue, condimentum nec, viverra et, porttitor sit amet, ligula. Cras malesuada sollicitudin risus. Praesent tincidunt nunc ut enim. Aliquam sit amet libero ac lorem ornare vulputate. Nulla a mauris cursus erat rutrum condimentum. Vivamus sit amet pede in felis sodales adipiscing. Curabitur arcu turpis, pharetra ac, porttitor ac, ultrices nec, quam. Donec feugiat purus eu nulla. Aenean mattis tellus vel nulla. Pellentesque vitae quam. Vestibulum scelerisque, eros nec imperdiet interdum, sapien quam accumsan libero, at vestibulum risus purus ut quam. Nam mattis, lorem vel rhoncus pulvinar, augue nibh rhoncus felis, et elementum felis dolor vitae justo. Nullam felis augue, ultricies ac, laoreet sed, lobortis in, neque. Vivamus nunc quam, dictum at, egestas et, fringilla non, magna.</p>
+ <p class="moveable" id="moveable2"><strong>Delayed move by 10px:</strong> Quisque at urna. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Pellentesque ante sem, ullamcorper in, ornare vitae, placerat id, velit. Ut ut tortor vitae lectus dignissim fringilla. Praesent urna enim, laoreet in, lobortis eget, porttitor eget, lacus. Suspendisse et enim. Duis semper nulla a felis. Duis dolor odio, ultrices et, lobortis sed, posuere eu, dolor. Duis est. Nam laoreet. Sed vehicula augue aliquam tortor.</p>
+ <p class="moveable" id="moveable3"><strong>With form elements:</strong>
+ <a href="http://dojotoolkit.org">dojotoolkit</a><br />
+ <input type="button" value="Button" />
+ <input type="text" value="abc" />
+ <input type="checkbox" checked />
+ <input type="radio" />
+ <select>
+ <option value="1">one</option>
+ <option value="2">two</option>
+ </select>
+ </p>
+ <p class="moveable" id="moveable4"><strong>With form elements and skip setting:</strong>
+ <a href="http://dojotoolkit.org">dojotoolkit</a>
+ <input type="button" value="Button" />
+ <input type="text" value="abc" />
+ <input type="checkbox" checked />
+ <input type="radio" />
+ <select>
+ <option value="1">one</option>
+ <option value="2">two</option>
+ </select>
+ </p>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_parent_constraints.html b/includes/js/dojo/tests/dnd/test_parent_constraints.html
new file mode 100644
index 0000000..a814a06
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_parent_constraints.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Dojo parent constraint test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+
+ body {
+ padding: 1em;
+ }
+
+ .moveable {
+ background: #FFFFBF;
+ border: 1px solid black;
+ width: 300px;
+ padding: 10px 20px;
+ cursor: pointer;
+ }
+
+ .parent {
+ background: #BFECFF;
+ border: 10px solid lightblue;
+ width: 500px;
+ height: 500px;
+ padding: 10px;
+ margin: 10px;
+ }
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript" src="../../dnd/move.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.dnd.move");
+ var m1, m2, m3, m4;
+ var init = function(){
+ m1 = new dojo.dnd.move.parentConstrainedMoveable("moveable1", {area: "margin", within: true});
+ m2 = new dojo.dnd.move.parentConstrainedMoveable("moveable2", {area: "border", within: true});
+ m3 = new dojo.dnd.move.parentConstrainedMoveable("moveable3", {area: "padding", within: true});
+ m4 = new dojo.dnd.move.parentConstrainedMoveable("moveable4", {area: "content", within: true});
+ };
+ dojo.addOnLoad(init);
+ </script>
+</head>
+<body>
+ <h1>Dojo parent constraint test</h1>
+ <div class="parent" id="parent">
+ <div><strong>This is the parent element.</strong> All children will be restricted with <strong>within = true</strong>.</div>
+ <div class="moveable" id="moveable1">I am restricted within my parent's margins.</div>
+ <div class="moveable" id="moveable2">I am restricted within my parent's border.</div>
+ <div class="moveable" id="moveable3">I am restricted within my parent's paddings.</div>
+ <div class="moveable" id="moveable4">I am restricted within my parent's content.</div>
+ </div>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_parent_constraints_margins.html b/includes/js/dojo/tests/dnd/test_parent_constraints_margins.html
new file mode 100644
index 0000000..3ee455c
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_parent_constraints_margins.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Dojo parent constraint test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+
+ body {
+ padding: 1em;
+ }
+
+ .moveable {
+ background: #FFFFBF;
+ border: 1px solid black;
+ width: 300px;
+ padding: 10px 20px;
+ cursor: pointer;
+ margin: 20px;
+ }
+
+ .parent {
+ background: #BFECFF;
+ border: 10px solid lightblue;
+ width: 500px;
+ height: 500px;
+ padding: 10px;
+ margin: 10px;
+ overflow: hidden;
+ }
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript" src="../../dnd/move.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.dnd.move");
+ var m7, m8;
+ var init = function(){
+ m7 = new dojo.dnd.move.parentConstrainedMoveable("moveable7", {area: "margin"});
+ m8 = new dojo.dnd.move.parentConstrainedMoveable("moveable8", {area: "margin", within: true});
+ };
+ dojo.addOnLoad(init);
+ </script>
+</head>
+<body>
+ <h1>Dojo parent constraint test</h1>
+ <div class="parent" id="parent">
+ <div><strong>This is the parent element.</strong></div>
+ <div class="moveable" id="moveable7"><strong>Paragraph restricted to its parent element:</strong> Sed hendrerit ornare justo. Maecenas ac urna. Maecenas in leo in tortor tincidunt pellentesque. Vivamus augue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer eget ipsum vitae quam condimentum tempus. Phasellus augue tortor, pretium nec, bibendum eget, eleifend eget, quam. Nam sem mauris, volutpat eget, ultricies in, consequat nec, tortor. Nulla eleifend. Vivamus et purus ultricies turpis vehicula auctor.</div>
+ <div class="moveable" id="moveable8"><strong>Paragraph restricted to its parent element (cannot go outside):</strong> Nam nibh. Mauris neque sem, pharetra ac, gravida ac, ultricies eget, quam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Vivamus scelerisque molestie mi. Duis eget ligula nec justo interdum hendrerit. Curabitur tempor convallis enim. In quis lorem. Proin nonummy consectetuer ligula. Curabitur tempor adipiscing lorem. Maecenas vitae nunc. Aliquam et magna. In vestibulum justo eleifend ante. Nulla pede sem, tempus tincidunt, vehicula ut, tempor et, nisi. Nulla ut lorem. Aliquam erat volutpat. Proin sodales, elit ut molestie dignissim, quam neque vulputate felis, quis scelerisque magna arcu aliquet lacus. Vivamus blandit. Nam eu mi vel augue pharetra semper.</div>
+ </div>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_selector.html b/includes/js/dojo/tests/dnd/test_selector.html
new file mode 100644
index 0000000..bebdca9
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_selector.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Dojo DnD selector test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ @import "dndDefault.css";
+
+ body { padding: 20px; }
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript" src="../../dnd/common.js"></script>
+ <script type="text/javascript" src="../../dnd/Container.js"></script>
+ <script type="text/javascript" src="../../dnd/Selector.js"></script>
+ <script type="text/javascript">
+ //dojo.require("dojo.dnd.Selector");
+ var c1, c2, c3, c4, c5;
+ var init = function(){
+ c1 = new dojo.dnd.Selector(dojo.byId("container1"), {singular: true});
+ c2 = new dojo.dnd.Selector(dojo.byId("container2"));
+ c3 = new dojo.dnd.Selector(dojo.byId("container3"));
+ c4 = new dojo.dnd.Selector(dojo.byId("container4"));
+ c5 = new dojo.dnd.Selector(dojo.byId("container5"));
+ };
+ dojo.addOnLoad(init);
+ </script>
+</head>
+<body>
+ <h1>Dojo DnD selector test</h1>
+ <p>Containers have a notion of a "current container", and one element can be "current". All containers on this page are selectors that allow to select elements.</p>
+ <p>Following selection modes are supported by default:</p>
+ <ul>
+ <li>Simple click &mdash; selects a single element, all other elements will be unselected.</li>
+ <li>Ctrl+click &mdash; toggles a selection state of an element (use Meta key on Mac).</li>
+ <li>Shift+click &mdash; selects a range of elements from the previous anchor to the current element.</li>
+ <li>Ctrl+Shift+click &mdash; adds a range of elements from the previous anchor to the current element (use Meta key on Mac).</li>
+ </ul>
+ <h2>DIV selector</h2>
+ <p>This selector can select just one element a time. It was specified during the creation time.</p>
+ <div id="container1" class="container">
+ <div class="dojoDndItem">Item 1</div>
+ <div class="dojoDndItem">Item 2</div>
+ <div class="dojoDndItem">Item 3</div>
+ </div>
+ <h2>UL selector</h2>
+ <ul id="container2" class="container">
+ <li class="dojoDndItem">Item 1</li>
+ <li class="dojoDndItem">Item 2</li>
+ <li class="dojoDndItem">Item 3</li>
+ </ul>
+ <h2>OL selector</h2>
+ <ol id="container3" class="container">
+ <li class="dojoDndItem">Item 1</li>
+ <li class="dojoDndItem">Item 2</li>
+ <li class="dojoDndItem">Item 3</li>
+ </ol>
+ <h2>TABLE selector</h2>
+ <table id="container4" class="container" border="1px solid black">
+ <tr class="dojoDndItem">
+ <td>A</td>
+ <td>row 1</td>
+ </tr>
+ <tr class="dojoDndItem">
+ <td>B</td>
+ <td>row 2</td>
+ </tr>
+ <tr class="dojoDndItem">
+ <td>C</td>
+ <td>row 3</td>
+ </tr>
+ </table>
+ <h2>P selector with SPAN elements</h2>
+ <p>Elements of this container are layed out horizontally.</p>
+ <p id="container5" class="container">
+ <span class="dojoDndItem">&nbsp;Item 1&nbsp;</span>
+ <span class="dojoDndItem">&nbsp;Item 2&nbsp;</span>
+ <span class="dojoDndItem">&nbsp;Item 3&nbsp;</span>
+ </p>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_selector_markup.html b/includes/js/dojo/tests/dnd/test_selector_markup.html
new file mode 100644
index 0000000..43c8e9c
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_selector_markup.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Dojo DnD markup selector test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ @import "dndDefault.css";
+
+ body { padding: 20px; }
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript" src="../../dnd/Selector.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("dojo.dnd.Selector");
+ </script>
+</head>
+<body>
+ <h1>Dojo DnD markup selector test</h1>
+ <p>This example is functionally equivalent to <a href="test_selector.html">test_selector.html</a> example but is done using the Dojo markup.</p>
+ <p>Containers have a notion of a "current container", and one element can be "current". All containers on this page are selectors that allow to select elements.</p>
+ <p>Following selection modes are supported by default:</p>
+ <ul>
+ <li>Simple click &mdash; selects a single element, all other elements will be unselected.</li>
+ <li>Ctrl+click &mdash; toggles a selection state of an element (use Meta key on Mac).</li>
+ <li>Shift+click &mdash; selects a range of elements from the previous anchor to the current element.</li>
+ <li>Ctrl+Shift+click &mdash; adds a range of elements from the previous anchor to the current element (use Meta key on Mac).</li>
+ </ul>
+ <h2>DIV selector</h2>
+ <p>This selector can select just one element a time. It was specified during the creation time.</p>
+ <div dojoType="dojo.dnd.Selector" jsId="c1" singular="true" class="container">
+ <div class="dojoDndItem">Item 1</div>
+ <div class="dojoDndItem">Item 2</div>
+ <div class="dojoDndItem">Item 3</div>
+ </div>
+ <h2>UL selector</h2>
+ <ul dojoType="dojo.dnd.Selector" jsId="c2" class="container">
+ <li class="dojoDndItem">Item 1</li>
+ <li class="dojoDndItem">Item 2</li>
+ <li class="dojoDndItem">Item 3</li>
+ </ul>
+ <h2>OL selector</h2>
+ <ol dojoType="dojo.dnd.Selector" jsId="c3" class="container">
+ <li class="dojoDndItem">Item 1</li>
+ <li class="dojoDndItem">Item 2</li>
+ <li class="dojoDndItem">Item 3</li>
+ </ol>
+ <h2>TABLE selector</h2>
+ <table dojoType="dojo.dnd.Selector" jsId="c4" class="container" border="1px solid black">
+ <tr class="dojoDndItem">
+ <td>A</td>
+ <td>row 1</td>
+ </tr>
+ <tr class="dojoDndItem">
+ <td>B</td>
+ <td>row 2</td>
+ </tr>
+ <tr class="dojoDndItem">
+ <td>C</td>
+ <td>row 3</td>
+ </tr>
+ </table>
+ <h2>P selector with SPAN elements</h2>
+ <p>Elements of this container are layed out horizontally.</p>
+ <p dojoType="dojo.dnd.Selector" jsId="c5" class="container">
+ <span class="dojoDndItem">&nbsp;Item 1&nbsp;</span>
+ <span class="dojoDndItem">&nbsp;Item 2&nbsp;</span>
+ <span class="dojoDndItem">&nbsp;Item 3&nbsp;</span>
+ </p>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/dnd/test_timed_moveable.html b/includes/js/dojo/tests/dnd/test_timed_moveable.html
new file mode 100644
index 0000000..685067e
--- /dev/null
+++ b/includes/js/dojo/tests/dnd/test_timed_moveable.html
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Dojo TimedMoveable test</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ @import "dndDefault.css";
+
+ body {
+ padding: 1em;
+ color:#666;
+ background-color:#dedede;
+ }
+
+ #moveable1 {
+ background: #fff;
+ border: 1px solid black;
+ padding:8px;
+ }
+ #handle1 {
+ background: #333;
+ color: #fff;
+ font-weight:bold;
+ cursor: pointer;
+ border: 1px solid black;
+ }
+ #moveable2 {
+ background: #fff;
+ position: absolute;
+ width: 200px;
+ height: 200px;
+ left: 100px;
+ top: 100px;
+ padding: 10px 20px;
+ margin: 10px 20px;
+ border: 10px solid black;
+ cursor: pointer;
+ radius:8pt;
+ -moz-border-radius:8pt 8pt;
+ }
+ #moveable3 {
+ background: #fff;
+ position: absolute;
+ width: 200px;
+ height: 200px;
+ left: 350px;
+ top: 350px;
+ padding: 10px 20px;
+ margin: 10px 20px;
+ border: 10px solid green;
+ cursor: pointer;
+ radius:8pt;
+ -moz-border-radius:8pt 8pt;
+ }
+ </style>
+ <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript" src="../../dnd/Mover.js"></script>
+ <script type="text/javascript" src="../../dnd/Moveable.js"></script>
+ <script type="text/javascript" src="../../dnd/TimedMoveable.js"></script>
+ <script type="text/javascript" src="../../dnd/move.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.dnd.TimedMoveable");
+ var m1, m2;
+ var init = function(){
+ m1 = new dojo.dnd.TimedMoveable("moveable1", {handle: "handle1"});
+ m2 = new dojo.dnd.TimedMoveable("moveable2");
+ m3 = new dojo.dnd.TimedMoveable("moveable3", {timeout: 500});
+
+ dojo.subscribe("/dnd/move/start", function(mover){
+ console.debug("Start move", mover);
+ });
+ dojo.subscribe("/dnd/move/stop", function(mover){
+ console.debug("Stop move", mover);
+ });
+
+ dojo.connect(m1, "onMoveStart", function(mover){
+ console.debug("Start moving m1", mover);
+ });
+ dojo.connect(m1, "onMoveStop", function(mover){
+ console.debug("Stop moving m1", mover);
+ });
+ };
+ dojo.addOnLoad(init);
+ </script>
+</head>
+<body>
+ <h1>Dojo TimedMoveable test</h1>
+ <p>One moveable (specially marked) is delayed by 500ms (2 fps). Other two are delayed by 40ms (25 fps) &mdash; this is the default value.</p>
+ <h2>1st run</h2>
+ <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Praesent erat. In malesuada ultricies velit. Vestibulum tempor odio vitae diam. Morbi arcu lectus, laoreet eget, nonummy at, elementum a, quam. Pellentesque ac lacus. Cras quis est. Etiam suscipit, quam at eleifend nonummy, elit nunc sollicitudin tellus, at mattis est ligula interdum urna. Vivamus id augue sed mi consectetuer dictum. Suspendisse dapibus elit non urna. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam gravida dapibus ante. Nam viverra ligula in neque. Nullam at metus. Aenean ipsum.</p>
+ <p>Mauris vulputate elit a risus. Praesent pellentesque velit ac neque. Fusce ultrices augue vitae orci. Proin a ante. Nulla consectetuer arcu quis est. Suspendisse potenti. Aliquam erat volutpat. Morbi purus augue, eleifend eu, consectetuer sed, tristique ut, wisi. Cras ac tellus. Phasellus adipiscing, libero ac consequat volutpat, ligula purus mollis lectus, ac porttitor ipsum diam non urna. Donec lorem. Pellentesque diam tortor, posuere et, placerat vitae, iaculis et, sapien. Proin sodales vehicula purus. Quisque bibendum mi ac mauris. Quisque tellus. Morbi sagittis. Integer euismod rhoncus augue. Ut accumsan. Curabitur quis tellus sit amet odio ultricies tristique. Etiam malesuada.</p>
+ <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec est. Cras semper nunc ut metus. Pellentesque blandit pede at erat. Quisque nonummy leo id metus. Donec mi mi, viverra id, adipiscing vitae, consectetuer ut, elit. In lectus augue, porttitor quis, viverra id, dignissim id, leo. Maecenas sapien. Nam adipiscing sem. Aenean ligula. Etiam vel velit. In mollis cursus dolor. Suspendisse ac nibh id leo tempor posuere. Aliquam sapien tellus, elementum non, aliquam sed, luctus eu, augue. Aliquam elementum leo nec enim. Donec ornare sagittis magna. Mauris ac tellus.</p>
+ <p>Duis ac augue rhoncus neque adipiscing feugiat. Donec pulvinar sem vitae neque. Donec commodo metus at ipsum. Cras vel magna vehicula lorem varius consequat. Morbi at enim vitae lectus mollis sodales. Sed tincidunt quam ut mi varius hendrerit. Sed porta arcu non libero. Quisque et wisi. Pellentesque lobortis. Ut enim felis, varius vitae, ornare quis, auctor ut, risus. Ut porta lorem vel quam. Etiam nunc purus, consectetuer non, lobortis eu, fermentum eu, magna. Aenean ultrices ante. Aliquam erat volutpat. Morbi quis velit eu mi sollicitudin lacinia. Suspendisse potenti. Donec lectus.</p>
+ <p>Quisque egestas turpis. Sed id ipsum id libero euismod nonummy. Nam sed dolor. Mauris in turpis. Duis nec wisi eget ante ultrices varius. Ut eget neque. Suspendisse sagittis iaculis tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Phasellus at justo. Donec imperdiet, elit et commodo bibendum, leo augue pellentesque arcu, ac dapibus lorem nulla eget erat. In viverra, tellus eu luctus eleifend, urna nibh lobortis sapien, ac pulvinar massa enim vel turpis. Sed orci neque, sagittis eu, mattis vitae, rutrum condimentum, leo. Fusce wisi odio, convallis at, condimentum vel, imperdiet id, mi. Mauris semper, magna pretium consectetuer sollicitudin, eros enim vehicula risus, eu ultrices turpis quam at wisi. Nam mollis.</p>
+ <table id="moveable1">
+ <tr><td id="handle1" colspan="2">You can drag the table using this handle.</td></tr>
+ <tr><td>1</td><td>Lorem ipsum dolor sit amet...</td></tr>
+ <tr><td>2</td><td>Mauris vulputate elit a risus...</td></tr>
+ <tr><td>3</td><td>Pellentesque habitant morbi tristique senectus...</td></tr>
+ <tr><td>4</td><td>Duis ac augue rhoncus neque...</td></tr>
+ <tr><td>5</td><td>Quisque egestas turpis. Sed id...</td></tr>
+ </table>
+ <h2>2nd run</h2>
+ <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Praesent erat. In malesuada ultricies velit. Vestibulum tempor odio vitae diam. Morbi arcu lectus, laoreet eget, nonummy at, elementum a, quam. Pellentesque ac lacus. Cras quis est. Etiam suscipit, quam at eleifend nonummy, elit nunc sollicitudin tellus, at mattis est ligula interdum urna. Vivamus id augue sed mi consectetuer dictum. Suspendisse dapibus elit non urna. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam gravida dapibus ante. Nam viverra ligula in neque. Nullam at metus. Aenean ipsum.</p>
+ <p>Mauris vulputate elit a risus. Praesent pellentesque velit ac neque. Fusce ultrices augue vitae orci. Proin a ante. Nulla consectetuer arcu quis est. Suspendisse potenti. Aliquam erat volutpat. Morbi purus augue, eleifend eu, consectetuer sed, tristique ut, wisi. Cras ac tellus. Phasellus adipiscing, libero ac consequat volutpat, ligula purus mollis lectus, ac porttitor ipsum diam non urna. Donec lorem. Pellentesque diam tortor, posuere et, placerat vitae, iaculis et, sapien. Proin sodales vehicula purus. Quisque bibendum mi ac mauris. Quisque tellus. Morbi sagittis. Integer euismod rhoncus augue. Ut accumsan. Curabitur quis tellus sit amet odio ultricies tristique. Etiam malesuada.</p>
+ <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec est. Cras semper nunc ut metus. Pellentesque blandit pede at erat. Quisque nonummy leo id metus. Donec mi mi, viverra id, adipiscing vitae, consectetuer ut, elit. In lectus augue, porttitor quis, viverra id, dignissim id, leo. Maecenas sapien. Nam adipiscing sem. Aenean ligula. Etiam vel velit. In mollis cursus dolor. Suspendisse ac nibh id leo tempor posuere. Aliquam sapien tellus, elementum non, aliquam sed, luctus eu, augue. Aliquam elementum leo nec enim. Donec ornare sagittis magna. Mauris ac tellus.</p>
+ <p>Duis ac augue rhoncus neque adipiscing feugiat. Donec pulvinar sem vitae neque. Donec commodo metus at ipsum. Cras vel magna vehicula lorem varius consequat. Morbi at enim vitae lectus mollis sodales. Sed tincidunt quam ut mi varius hendrerit. Sed porta arcu non libero. Quisque et wisi. Pellentesque lobortis. Ut enim felis, varius vitae, ornare quis, auctor ut, risus. Ut porta lorem vel quam. Etiam nunc purus, consectetuer non, lobortis eu, fermentum eu, magna. Aenean ultrices ante. Aliquam erat volutpat. Morbi quis velit eu mi sollicitudin lacinia. Suspendisse potenti. Donec lectus.</p>
+ <p>Quisque egestas turpis. Sed id ipsum id libero euismod nonummy. Nam sed dolor. Mauris in turpis. Duis nec wisi eget ante ultrices varius. Ut eget neque. Suspendisse sagittis iaculis tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Phasellus at justo. Donec imperdiet, elit et commodo bibendum, leo augue pellentesque arcu, ac dapibus lorem nulla eget erat. In viverra, tellus eu luctus eleifend, urna nibh lobortis sapien, ac pulvinar massa enim vel turpis. Sed orci neque, sagittis eu, mattis vitae, rutrum condimentum, leo. Fusce wisi odio, convallis at, condimentum vel, imperdiet id, mi. Mauris semper, magna pretium consectetuer sollicitudin, eros enim vehicula risus, eu ultrices turpis quam at wisi. Nam mollis.</p>
+ <div id="moveable2">You can drag this whole paragraph around.</div>
+ <div id="moveable3">My move is delayed by 500ms, which corresponds to 2 fps.</div>
+</body>
+</html>
diff --git a/includes/js/dojo/tests/fx.html b/includes/js/dojo/tests/fx.html
new file mode 100644
index 0000000..bd2c9c1
--- /dev/null
+++ b/includes/js/dojo/tests/fx.html
@@ -0,0 +1,310 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Testing dojo.fx</title>
+ <script type="text/javascript" src="../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+ dojo.require("dojo.fx");
+
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ function slideTo(t){
+ var s = dojo.fx.slideTo({
+ node: "foo",
+ duration: 500,
+ left: 500,
+ top: 50
+ }).play();
+ var d = new doh.Deferred();
+ dojo.connect(s, "onEnd", function(){
+ doh.is(dojo.style("foo", "left"), 500);
+ doh.is(dojo.style("foo", "top"), 50);
+ with(dojo.byId("foo").style){
+ position = left = top = "";
+ }
+ d.callback(true);
+ });
+ s.play();
+ return d;
+ },
+
+ function wipeOut(t){
+ dojo.byId("foo").style.height = "";
+ var d = new doh.Deferred();
+ var s = dojo.fx.wipeOut({
+ node: "foo",
+ onEnd: function(){
+ doh.t(dojo.style("foo", "height") < 5);
+ d.callback(true);
+ }
+ }).play();
+ return d;
+ },
+
+ function wipeIn(t){
+ var d = new doh.Deferred();
+ setTimeout(function(){
+ dojo.fx.wipeIn({
+ node: "foo",
+ onEnd: function(){
+ console.debug(dojo.style("foo", "height"));
+ doh.t(dojo.style("foo", "height") > 10);
+ d.callback(true);
+ }
+ }).play();
+ }, 10);
+ return d;
+ },
+
+ {
+ name: "chain",
+ timeout: 1500,
+ runTest: function(t){
+ dojo.byId("foo").style.height = "0px";
+ var d = new doh.Deferred();
+ var w = dojo.fx.wipeIn({
+ node: "foo",
+ duration: 500
+ });
+ var f = dojo.fadeOut({
+ node: "foo",
+ duration: 500
+ });
+ var a = dojo.fx.chain([w,f]);
+ dojo.connect(a, "onEnd", function(){
+ doh.t((w.status()=="stopped"&&f.status()=="stopped"));
+ d.callback(true);
+ });
+ a.play();
+ return d;
+ }
+ },
+
+ {
+ name: "combine",
+ timeout: 1500,
+ runTest: function(t){
+ dojo.byId("foo").style.height = "0px";
+ var d = new doh.Deferred();
+ var w = dojo.fx.wipeIn({
+ node: "foo",
+ duration: 500
+ });
+ var f = dojo.fadeIn({
+ node: "foo",
+ duration: 1000
+ });
+ var a = dojo.fx.combine([w,f]);
+ dojo.connect(a, "onEnd", function(){
+ doh.t((w.status()=="stopped"&&f.status()=="stopped"));
+ d.callback(true);
+ });
+ a.play();
+ return d;
+ }
+ },
+ {
+ name:"combineBeforeBegin",
+ timeout:1500,
+ runTest: function(t){
+ var d = new doh.Deferred();
+ var a = dojo.fadeOut({ node:"foo2", duration:400 });
+ var b = dojo.fadeIn({ node:"foo2", duration:400 });
+ var chain = dojo.fx.combine([a,b]);
+ dojo.connect(chain,"beforeBegin",dojo.hitch(d,"callback",true));
+ chain.play();
+ return d;
+ }
+
+ },
+ {
+ name:"delayTest",
+ timeout:2000,
+ runTest:function(t){
+ var d = new doh.Deferred();
+ var delay = 100;
+ var _anims = [];
+ var nodes = ["a","b","c","d"];
+ dojo.forEach(nodes,function(n){
+ _anims.push(dojo.fadeOut({ node:n, duration:100, delay: delay += 100 }));
+ });
+ var a = dojo.fx.combine(_anims);
+ var timer = (new Date()).getTime();
+ dojo.connect(a,"onEnd",function(){
+ console.warn("delayTest running time:", (new Date()).getTime() - timer, "ms, expected:", a.duration, "ms");
+ d.callback(true);
+ });
+ a.play();
+ return d;
+ }
+ },
+ {
+ name:"delayTestChain",
+ timeout:2200,
+ runTest:function(t){
+ var d = new doh.Deferred();
+ var delay = 100;
+ var _anims = [];
+ var nodes = ["a","b","c","d"];
+ dojo.forEach(nodes,function(n){
+ _anims.push(dojo.fadeIn({ node:n, duration:100, delay: delay += 100 }));
+ });
+ var a = dojo.fx.chain(_anims);
+ var timer = (new Date()).getTime();
+ dojo.connect(a,"onEnd",function(){
+ console.warn("delayTestChain running time:", (new Date()).getTime() - timer, "ms, expected:", a.duration, "ms");
+ d.callback(true);
+ });
+ a.play();
+ return d;
+ }
+ },
+ {
+ name:"combineOnEnd",
+ timeout:1500,
+ runTest: function(t){
+ var d = new doh.Deferred();
+ var a = dojo.fadeOut({ node:"foo2", duration:400 });
+ var b = dojo.fadeIn({ node:"foo2", duration:400 });
+ var combine = dojo.fx.combine([a,b]);
+ dojo.connect(combine,"onEnd",dojo.hitch(d,"callback",true));
+ combine.play();
+ return d;
+ }
+
+ },
+ {
+ name:"combineOnPlay",
+ timeout:1500,
+ runTest: function(t){
+ var d = new doh.Deferred();
+ var a = dojo.fadeOut({ node:"foo2", duration:400 });
+ var b = dojo.fadeIn({ node:"foo2", duration:400 });
+ var combine = dojo.fx.combine([a,b]);
+ dojo.connect(combine,"onPlay",dojo.hitch(d,"callback",true));
+ combine.play();
+ return d;
+ }
+
+ },
+ {
+ name:"chainOnEnd",
+ timeout:1500,
+ runTest: function(t){
+ var d = new doh.Deferred();
+ var a = dojo.fadeOut({ node:"foo2", duration:400 });
+ var b = dojo.fadeIn({ node:"foo2", duration:400 });
+ var chain = dojo.fx.chain([a,b]);
+ dojo.connect(chain,"onEnd",dojo.hitch(d,"callback",true));
+ chain.play();
+ return d;
+ }
+
+ },
+ {
+ name:"chainOnPlay",
+ timeout:1500,
+ runTest: function(t){
+
+ var d = new doh.Deferred();
+ var a = dojo.fadeOut({ node:"foo2", duration:200 });
+ var b = dojo.fadeIn({ node:"foo2", duration:200 });
+ var chain = dojo.fx.chain([a,b]);
+ dojo.connect(chain,"onPlay",dojo.hitch(d,"callback",true));
+ chain.play();
+ return d;
+ }
+
+ },
+
+ function Toggler(){
+ var d = new doh.Deferred();
+ var t = new dojo.fx.Toggler({
+ node: "foo",
+ hideDuration: 100,
+ hideFunc: dojo.fx.wipeOut,
+ showFunc: dojo.fx.wipeIn
+ });
+ t.hide();
+ setTimeout(function(){
+ var sa = t.show();
+ dojo.connect(sa, "onEnd", dojo.hitch(d, "callback", true));
+ }, 50);
+ return d;
+ }
+ ]
+ );
+ doh.run();
+ });
+ </script>
+ <style type="text/css">
+ @import "../resources/dojo.css";
+
+ body {
+ text-shadow: 0px 0px;
+ margin: 1em;
+ background-color: #DEDEDE;
+ }
+
+ .box {
+ color: #292929;
+ /* color: #424242; */
+ /* text-align: left; */
+ width: 300px;
+ border: 1px solid #BABABA;
+ background-color: white;
+ padding-left: 10px;
+ padding-right: 10px;
+ margin-left: 10px;
+ margin-bottom: 1em;
+ -o-border-radius: 10px;
+ -moz-border-radius: 12px;
+ -webkit-border-radius: 10px;
+ -webkit-box-shadow: 0px 3px 7px #adadad;
+ /* -opera-border-radius: 10px; */
+ border-radius: 10px;
+ -moz-box-sizing: border-box;
+ -opera-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -khtml-box-sizing: border-box;
+ box-sizing: border-box;
+ overflow: hidden;
+ /* position: absolute; */
+ }
+ </style>
+ </head>
+ <body>
+ <div class="box" id="a">a</div><div class="box" id="b">b</div>
+ <div class="box" id="c">c</div><div class="box" id="d">d</div>
+
+ <div id="foo" class="box">
+ <p>
+ 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.
+ </p>
+ <p>
+ 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.
+ </p>
+ </div>
+ <div id="foo2">foo2</div>
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/fx.js b/includes/js/dojo/tests/fx.js
new file mode 100644
index 0000000..f5e2cfc
--- /dev/null
+++ b/includes/js/dojo/tests/fx.js
@@ -0,0 +1,9 @@
+if(!dojo._hasResource["tests.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.fx"] = true;
+dojo.provide("tests.fx");
+if(dojo.isBrowser){
+ doh.registerUrl("tests.fx", dojo.moduleUrl("tests", "fx.html"), 30000);
+ doh.registerUrl("tests.NodeList-fx", dojo.moduleUrl("tests", "NodeList-fx.html"));
+}
+
+}
diff --git a/includes/js/dojo/tests/i18n.js b/includes/js/dojo/tests/i18n.js
new file mode 100644
index 0000000..47bb946
--- /dev/null
+++ b/includes/js/dojo/tests/i18n.js
@@ -0,0 +1,88 @@
+if(!dojo._hasResource["tests.i18n"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.i18n"] = true;
+dojo.provide("tests.i18n");
+
+dojo.require("dojo.i18n");
+
+(function(){
+ var setUp = function(locale){
+ return function(){
+ dojo.requireLocalization("tests","salutations",locale, "");
+ }
+ }
+
+ var getTest = function(value, locale){
+ return function(){
+ doh.assertEqual(value, dojo.i18n.getLocalization("tests", "salutations", locale).hello);
+ }
+ }
+
+ var getFixture = function(locale, value){
+ return {
+ name: "salutations-"+locale,
+ setUp: setUp(locale),
+ runTest: getTest(value, locale)
+ };
+ }
+
+ var testSet = [
+ /* needs dojo.string,
+ // This doesn't actually test anything, it just gives an impressive list of translated output to the console
+ // See the 'salutations' test for something verifyable
+ function fun(t){
+ var salutations_default = dojo.i18n.getLocalization("tests", "salutations");
+ console.debug("In the local language: "+salutations_default.hello);
+
+ var salutations_en = dojo.i18n.getLocalization("tests", "salutations", "en");
+
+ for (i in tests.nls.salutations) {
+ var loc = i.replace('_', '-');
+ var salutations = dojo.i18n.getLocalization("tests", "salutations", loc);
+ var language_as_english = salutations_en[loc];
+ var language_as_native = salutations[loc];
+ var hello_dojo = dojo.string.substitute(salutations.hello_dojo, salutations);
+ if (!dojo.i18n.isLeftToRight(loc)) {
+ var RLE = "\u202b";
+ var PDF = "\u202c";
+ hello_dojo = RLE + hello_dojo + PDF;
+ }
+ hello_dojo += "\t[" + loc + "]";
+ if(language_as_english){hello_dojo += " " + language_as_english;}
+ if(language_as_native){hello_dojo += " (" + language_as_native + ")";}
+ console.debug(hello_dojo);
+ }
+
+ t.assertTrue(true);
+ },
+ */
+
+ // Test on-the-fly loading of localized string bundles from different locales, and
+ // the expected inheritance behavior
+
+ // Locale which overrides root translation
+ getFixture("de", "Hallo"),
+ // Locale which does not override root translation
+ getFixture("en", "Hello"),
+ // Locale which overrides its parent
+ getFixture("en-au", "G'day"),
+ // Locale which does not override its parent
+ getFixture("en-us", "Hello"),
+ // Locale which overrides its parent
+ getFixture("en-us-texas", "Howdy"),
+ // 3rd level variant which overrides its parent
+ getFixture("en-us-new_york", "Hello"),
+ // Locale which overrides its grandparent
+ getFixture("en-us-new_york-brooklyn", "Yo"),
+ // Locale which does not have any translation available
+ getFixture("xx", "Hello"),
+ // A double-byte string. Everything should be read in as UTF-8 and treated as unicode within Javascript.
+ getFixture("zh-cn", "\u4f60\u597d")
+ ];
+ testSet[testSet.length-1].tearDown = function(){
+ // Clean up bundles that should not exist if the test is re-run.
+ delete tests.nls.salutations;
+ };
+ tests.register("tests.i18n", testSet);
+})();
+
+}
diff --git a/includes/js/dojo/tests/io/iframe.html b/includes/js/dojo/tests/io/iframe.html
new file mode 100644
index 0000000..c37bcb1
--- /dev/null
+++ b/includes/js/dojo/tests/io/iframe.html
@@ -0,0 +1,124 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Testing dojo.io.iframe</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ src="../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+ dojo.require("dojo.io.iframe");
+
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ function ioIframeGetText(t){
+ var d = new doh.Deferred();
+ var td = dojo.io.iframe.send({
+ url: "iframeResponse.text.html",
+ method: "GET",
+ timeoutSeconds: 5,
+ preventCache: true,
+ handle: function(res, ioArgs){
+ if(!(res instanceof Error) &&
+ t.is("iframe succeeded", res)){
+ d.callback(true);
+ }else{
+ d.errback(false);
+ }
+ }
+ });
+ return d;
+ },
+
+ function ioIframeGetJson(t){
+ var d = new doh.Deferred();
+ var td = dojo.io.iframe.send({
+ url: "iframeResponse.json.html",
+ method: "GET",
+ timeoutSeconds: 5,
+ preventCache: true,
+ handleAs: "json",
+ handle: function(res, ioArgs){
+ if(!(res instanceof Error) &&
+ t.is("blue", res.color)){
+ d.callback(true);
+ }else{
+ d.errback(false);
+ }
+ }
+ });
+ return d;
+ },
+
+ function ioIframeGetJavascript(t){
+ var d = new doh.Deferred();
+ var td = dojo.io.iframe.send({
+ url: "iframeResponse.js.html",
+ method: "GET",
+ timeoutSeconds: 5,
+ preventCache: true,
+ handleAs: "javascript",
+ handle: function(res, ioArgs){
+ console.log("RES: ", res);
+ if(!(res instanceof Error) &&
+ t.is(42, window.iframeTestingFunction())){
+ d.callback(true);
+ }else{
+ d.errback(false);
+ }
+ }
+ });
+ return d;
+ },
+
+ function ioIframeGetHtml(t){
+ var d = new doh.Deferred();
+ var td = dojo.io.iframe.send({
+ url: "iframeResponse.html",
+ method: "GET",
+ timeoutSeconds: 5,
+ preventCache: true,
+ handleAs: "html",
+ handle: function(res, ioArgs){
+ if(!(res instanceof Error) &&
+ t.is("SUCCESSFUL HTML response", res.getElementsByTagName("h1")[0].innerHTML)){
+ d.callback(true);
+ }else{
+ d.errback(false);
+ }
+ }
+ });
+ return d;
+ }
+ ]
+ );
+ doh.run();
+ });
+
+/*
+dojo.addOnLoad(function(){
+ var td = dojo.io.iframe.get({
+ url: "iframeResponse.text.html",
+ timeoutSeconds: 5,
+ preventCache: true,
+ handle: function(res, ioArgs){
+ if(!(res instanceof Error) &&
+ "iframe succeeded" == res){
+ console.debug("OK");
+ }else{
+ console.debug("Error", res);
+ }
+ }
+ });
+});
+*/
+ </script>
+ </head>
+ <body>
+
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/io/iframe.js b/includes/js/dojo/tests/io/iframe.js
new file mode 100644
index 0000000..6e20af5
--- /dev/null
+++ b/includes/js/dojo/tests/io/iframe.js
@@ -0,0 +1,8 @@
+if(!dojo._hasResource["tests.io.iframe"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.io.iframe"] = true;
+dojo.provide("tests.io.iframe");
+if(dojo.isBrowser){
+ doh.registerUrl("tests.io.iframe", dojo.moduleUrl("tests.io", "iframe.html"));
+}
+
+}
diff --git a/includes/js/dojo/tests/io/iframeResponse.html b/includes/js/dojo/tests/io/iframeResponse.html
new file mode 100644
index 0000000..cd26e21
--- /dev/null
+++ b/includes/js/dojo/tests/io/iframeResponse.html
@@ -0,0 +1,8 @@
+<html lang="en">
+ <head>
+ </head>
+ <body>
+ <h1>SUCCESSFUL HTML response</h1>
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/io/iframeResponse.js.html b/includes/js/dojo/tests/io/iframeResponse.js.html
new file mode 100644
index 0000000..50c1855
--- /dev/null
+++ b/includes/js/dojo/tests/io/iframeResponse.js.html
@@ -0,0 +1,7 @@
+<html>
+ <head>
+ </head>
+ <body>
+ <textarea style="width: 100%; height: 100px;">window.iframeTestingFunction = function(){ return 42; };</textarea>
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/io/iframeResponse.json.html b/includes/js/dojo/tests/io/iframeResponse.json.html
new file mode 100644
index 0000000..cb04ed7
--- /dev/null
+++ b/includes/js/dojo/tests/io/iframeResponse.json.html
@@ -0,0 +1,7 @@
+<html>
+ <head>
+ </head>
+ <body>
+ <textarea style="width: 100%; height: 100px;">{ color: "blue", size: 42 }</textarea>
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/io/iframeResponse.text.html b/includes/js/dojo/tests/io/iframeResponse.text.html
new file mode 100644
index 0000000..2a05b83
--- /dev/null
+++ b/includes/js/dojo/tests/io/iframeResponse.text.html
@@ -0,0 +1,7 @@
+<html>
+ <head>
+ </head>
+ <body>
+ <textarea style="width: 100%; height: 100px;">iframe succeeded</textarea>
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/io/iframeUploadTest.html b/includes/js/dojo/tests/io/iframeUploadTest.html
new file mode 100644
index 0000000..6f6db6f
--- /dev/null
+++ b/includes/js/dojo/tests/io/iframeUploadTest.html
@@ -0,0 +1,50 @@
+<html>
+ <head>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ djConfig="isDebug: true, dojoIframeHistoryUrl: '../../resource/blank.html'"
+ src="../../dojo.js"></script>
+
+ <script type="text/javascript">
+ dojo.require("dojo.io.iframe");
+
+ var callCount = 0;
+ var ioResponse;
+
+ function sendIt(){
+ dojo.io.iframe.send({
+ form: dojo.byId("uploadForm"),
+ handleAs: "application/json",
+ content: {
+ increment: callCount++,
+ fileFields: "ul1"
+ },
+ handle: function(response, ioArgs){
+ if(response instanceof Error){
+ console.debug("Request FAILED: ", response);
+ }else{
+ console.debug("Request complete: ", response);
+ }
+ ioResponse = response; // to get at afterwards in debugger.
+ }
+ });
+ }
+ </script>
+ </head>
+ <body>
+ <p>This file tests dojo.io.iframe upload using a form POST with a file upload button.</p>
+
+ <p>
+ <b>Note:</b> This test makes a form POST to upload.cgi. This cgi needs to be made executable for this test to work, and it won't work from local disk.
+ </p>
+ <form action="upload.cgi" id="uploadForm"
+ method="POST" enctype="multipart/form-data">
+ <input type="text" name="foo" value="bar">
+ <input type="file" name="ul1">
+ <input type="button" onclick="sendIt(); return false;" value="send it!">
+ </form>
+ </body>
+</html>
+
diff --git a/includes/js/dojo/tests/io/script.html b/includes/js/dojo/tests/io/script.html
new file mode 100644
index 0000000..db24ac9
--- /dev/null
+++ b/includes/js/dojo/tests/io/script.html
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Testing dojo.io.script</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ src="../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.require("doh.runner");
+ dojo.require("dojo.io.script");
+
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ function ioScriptSimple(t){
+ var d = new doh.Deferred();
+ var td = dojo.io.script.get({
+ url: "scriptSimple.js",
+ checkString: "myTasks"
+ });
+ td.addBoth(function(res){
+ if(typeof(myTasks) != "undefined"
+ && t.is("Do dishes.", myTasks[1])){
+ d.callback(true);
+ }else{
+ d.errback(false);
+ }
+ });
+ return d;
+ },
+ function ioScriptJsonp(t){
+ var d = new doh.Deferred();
+ var td = dojo.io.script.get({
+ url: "scriptJsonp.js",
+ content: { foo: "bar" },
+ callbackParamName: "callback"
+ });
+ td.addBoth(function(res){
+ if(!(res instanceof Error) &&
+ t.is("mammal", res.animalType)){
+ d.callback(true);
+ }else{
+ d.errback(false);
+ }
+ });
+ return d;
+ },
+ function ioScriptJsonpTimeout(t){
+ var d = new doh.Deferred();
+ var td = dojo.io.script.get({
+ url: "../_base/timeout.php",
+ callbackParamName: "callback",
+ content: {Foo: 'Bar'},
+ timeout: 500,
+ handleAs: "json",
+ preventCache: true,
+ handle: function(response, ioArgs){
+ if(response instanceof Error && response.dojoType == "timeout"){
+ console.debug("FOO OK TEST");
+ d.callback(true);
+ }else{
+ console.debug("FOO FAIL TEST");
+ d.errback(false);
+ }
+ }
+ });
+ return d;
+ }
+ ]
+ );
+ doh.run();
+ });
+
+/*
+ dojo.addOnLoad(function(){
+ td = dojo.io.script.get({
+ url: "scriptSimple.js",
+ checkString: "myTasks"
+ });
+ td.addCallback(function(res){
+ alert(myTasks);
+ alert(myTasks[1]);
+ if(typeof(myTasks) != "undefined"
+ && "Do dishes." == myTasks[1]){
+ alert("yeah");
+ }else{
+ alert("boo");
+ }
+ });
+ });
+*/
+
+ </script>
+ </head>
+ <body>
+
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/io/script.js b/includes/js/dojo/tests/io/script.js
new file mode 100644
index 0000000..722a805
--- /dev/null
+++ b/includes/js/dojo/tests/io/script.js
@@ -0,0 +1,8 @@
+if(!dojo._hasResource["tests.io.script"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.io.script"] = true;
+dojo.provide("tests.io.script");
+if(dojo.isBrowser){
+ doh.registerUrl("tests.io.script", dojo.moduleUrl("tests.io", "script.html"));
+}
+
+}
diff --git a/includes/js/dojo/tests/io/scriptJsonp.js b/includes/js/dojo/tests/io/scriptJsonp.js
new file mode 100644
index 0000000..ad1a196
--- /dev/null
+++ b/includes/js/dojo/tests/io/scriptJsonp.js
@@ -0,0 +1,57 @@
+function getJsonpCallback(url){
+ var result = null;
+ var idMatch = url.match(/jsonp=(.*?)(&|$)/);
+ if(idMatch){
+ result = idMatch[1];
+ }else{
+ //jsonp didn't match, so maybe it is the jsonCallback thing.
+ idMatch = url.match(/callback=(.*?)(&|$)/);
+ if(idMatch){
+ result = idMatch[1];
+ }
+ }
+
+ if(result){
+ result = decodeURIComponent(result);
+ }
+ return result;
+}
+
+function findJsonpDone(){
+ var result = false;
+ var scriptUrls = getScriptUrls();
+
+ for(var i = 0; i < scriptUrls.length; i++){
+ var jsonp = getJsonpCallback(scriptUrls[i]);
+ if(jsonp){
+ eval(jsonp + "({animalType: 'mammal'});");
+ result = true;
+ break;
+ }
+ }
+ return result;
+}
+
+function getScriptUrls(){
+ //Get the script tags in the page to figure what state we are in.
+ var scripts = document.getElementsByTagName('script');
+ var scriptUrls = new Array();
+ for(var i = 0; scripts && i < scripts.length; i++){
+ var scriptTag = scripts[i];
+ if(scriptTag.id.indexOf("dojoIoScript") == 0){
+ scriptUrls.push(scriptTag.src);
+ }
+ }
+
+ return scriptUrls;
+}
+
+function doJsonpCallback(){
+ if(!findJsonpDone()){
+ alert('ERROR: Could not jsonp callback!');
+ }
+}
+
+//Set a timeout to do the callback check, since MSIE won't see the SCRIPT tag until
+//we complete processing of this page.
+setTimeout(function(){doJsonpCallback();}, 300);
diff --git a/includes/js/dojo/tests/io/scriptSimple.js b/includes/js/dojo/tests/io/scriptSimple.js
new file mode 100644
index 0000000..8ca316c
--- /dev/null
+++ b/includes/js/dojo/tests/io/scriptSimple.js
@@ -0,0 +1,5 @@
+myTasks = new Array();
+myTasks[0] = 'Take out trash.';
+myTasks[1] = 'Do dishes.';
+myTasks[2] = 'Brush teeth.';
+
diff --git a/includes/js/dojo/tests/io/scriptTimeout.html b/includes/js/dojo/tests/io/scriptTimeout.html
new file mode 100644
index 0000000..563e37c
--- /dev/null
+++ b/includes/js/dojo/tests/io/scriptTimeout.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>Testing dojo.io.script</title>
+ <style type="text/css">
+ @import "../../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ src="../../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.io.script");
+
+ function startTest(){
+ var td = dojo.io.script.get({
+ url: "../_base/timeout.php",
+ callbackParamName: "callback",
+ content: {Foo: 'Bar'},
+ timeout: 500,
+ handleAs: "json",
+ preventCache: true,
+ handle: function(response, ioArgs){
+ if(response instanceof Error && response.dojoType == "timeout"){
+ console.debug("TEST OK. No errors should be seen after this timeout error.");
+ }else{
+ console.debug("TEST FAILED: some other error or response received: ", response);
+ }
+ }
+ });
+ }
+ </script>
+ </head>
+ <body>
+ <h1>Timeout test</h1>
+
+ <p>
+ This test page tests the timeout functionality of dojo.io.script, and to make
+ sure that requests that time out get removed quickly. If the server response
+ is received after the script has been timed out, there should not be weird
+ errors as the browser tries to evaluate the responses after the desired time
+ period.
+ </p>
+
+ <p>This test requires a server running PHP to work.</p>
+
+ <p>
+ <p><strong>Firefox Oddity:</strong> Firefox
+ will print an error after the script response is received from the server:<br />
+ <span style="color: red">dojo.io.script.jsonp_dojoIoScript1 has no properties</span>
+ This is bad because Firefox goes ahead and evaluates the script contents in the page's
+ JavaScript space (this happens even when I turn off Firefox Add-Ons). All other browsers
+ do not evaluate the script (given the weird Opera 9.22 behavior below). You can test this
+ by clicking the <b>Test for SuperXFooBarVariable</b> button after receiving the response
+ for timeout.php (check Firebug Net tab to see when request is received). All other browsers
+ show an error or show the "undefined" value for SuperXFooBarVariable, but Firefox will show its
+ value as being: "Oh no! SuperXFooBarVariable is defined (should not be for timeout case)".
+
+ <p><strong>Opera Oddity:</strong> Opera 9.22 does not seem to trigger the timeout case,
+ but rather it waits for the server to send a response to the script before continuing past the
+ point where the script is added to the DOM? That seems wrong. Dynamic script tags are no longer
+ an async operation?
+ </p>
+
+ <button onclick="startTest()">Start Test</button>
+ <button onclick="alert(SuperXFooBarVariable)">Test for SuperXFooBarVariable</button>
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/io/upload.cgi b/includes/js/dojo/tests/io/upload.cgi
new file mode 100644
index 0000000..a13656f
--- /dev/null
+++ b/includes/js/dojo/tests/io/upload.cgi
@@ -0,0 +1,60 @@
+#!/usr/bin/python
+
+# FROM: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/273844
+
+import cgi
+import cgitb; cgitb.enable()
+import os, sys
+import string
+
+UPLOAD_DIR = "/tmp/upload/"
+form = cgi.FieldStorage()
+
+dbg = []
+
+def debug(dbgstr):
+ dbg.append(str(dbgstr))
+
+def save_uploaded_file(form_field, upload_dir):
+ global form
+ if not form.has_key(form_field):
+ debug("didn't find it! (1)")
+ return
+ fileitem = form[form_field]
+ if not fileitem.file:
+ debug(form.getvalue(form_field, ""))
+ debug(fileitem.__dict__)
+ debug("didn't find it! (2)")
+ return
+ fout = file(os.path.join(upload_dir, fileitem.filename), 'wb')
+ while 1:
+ chunk = fileitem.file.read(100000)
+ if not chunk: break
+ fout.write (chunk)
+ fout.close()
+
+retval = "false";
+fileFields = ""
+
+if form.has_key("fileFields"):
+ fval = str(form.getvalue("fileFields", ""))
+ fileFields = fval.split(",")
+ debug("'fileCount': '" + str(len(fileFields)) + "',")
+ for field in fileFields:
+ debug("'fileField' : '"+field + "',")
+ save_uploaded_file(str(field).strip(), UPLOAD_DIR)
+ retval = "true";
+
+debug("'retval': " + retval)
+
+print """Content-Type: text/html
+
+
+<html>
+ <head>
+ </head>
+ <body>
+ <textarea style="width: 100%; height: 100px;">{ %s }</textarea>
+ </body>
+</html>
+""" % (string.join(dbg, "\n"))
diff --git a/includes/js/dojo/tests/manualTests.html b/includes/js/dojo/tests/manualTests.html
new file mode 100644
index 0000000..26ff163
--- /dev/null
+++ b/includes/js/dojo/tests/manualTests.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+ <head>
+ <title>Dojo Manual Test Runner</title>
+ </head>
+ <body>
+ Redirecting to D.O.H runner
+ <script>
+ window.location.replace("../../util/doh/runner.html?testModule=dojo.tests.manualTests"+window.location.search.replace(/^\?/,"&"));
+ </script>
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/manualTests.js b/includes/js/dojo/tests/manualTests.js
new file mode 100644
index 0000000..d60a01b
--- /dev/null
+++ b/includes/js/dojo/tests/manualTests.js
@@ -0,0 +1,45 @@
+if(!dojo._hasResource["dojo.tests.manualTests"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.tests.manualTests"] = true;
+dojo.provide("dojo.tests.manualTests");
+
+try{
+if(dojo.isBrowser){
+ var userArgs = window.location.search.replace(/[\?&](dojoUrl|testUrl|testModule)=[^&]*/g,"").replace(/^&/,"?");
+ doh.registerUrl("dojo/tests/back-bookmark.html", dojo.moduleUrl("dojo","tests/back-bookmark.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/back.html", dojo.moduleUrl("dojo","tests/back.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/test_FirebugLite.html", dojo.moduleUrl("dojo","tests/test_FirebugLite.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/test_fx.html", dojo.moduleUrl("dojo","tests/test_fx.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/flickr_viewer.html", dojo.moduleUrl("dojo","tests/dnd/flickr_viewer.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_box_constraints.html", dojo.moduleUrl("dojo","tests/dnd/test_box_constraints.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_container.html", dojo.moduleUrl("dojo","tests/dnd/test_container.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_container_markup.html", dojo.moduleUrl("dojo","tests/dnd/test_container_markup.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_custom_constraints.html", dojo.moduleUrl("dojo","tests/dnd/test_custom_constraints.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_dnd.html", dojo.moduleUrl("dojo","tests/dnd/test_dnd.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_dnd_handles.html", dojo.moduleUrl("dojo","tests/dnd/test_dnd_handles.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_form.html", dojo.moduleUrl("dojo","tests/dnd/test_form.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_moveable.html", dojo.moduleUrl("dojo","tests/dnd/test_moveable.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_moveable_markup.html", dojo.moduleUrl("dojo","tests/dnd/test_moveable_markup.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_params.html", dojo.moduleUrl("dojo","tests/dnd/test_params.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_parent_constraints.html", dojo.moduleUrl("dojo","tests/dnd/test_parent_constraints.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_parent_constraints_margins.html", dojo.moduleUrl("dojo","tests/dnd/test_parent_constraints_margins.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_selector.html", dojo.moduleUrl("dojo","tests/dnd/test_selector.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_selector_markup.html", dojo.moduleUrl("dojo","tests/dnd/test_selector_markup.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/dnd/test_timed_moveable.html", dojo.moduleUrl("dojo","tests/dnd/test_timed_moveable.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/io/iframeUploadTest.html", dojo.moduleUrl("dojo","tests/io/iframeUploadTest.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/io/scriptTimeout.html", dojo.moduleUrl("dojo","tests/io/scriptTimeout.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/_base/fx_delay.html", dojo.moduleUrl("dojo","tests/_base/fx_delay.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/_base/_loader/addLoadEvents.html", dojo.moduleUrl("dojo","tests/_base/_loader/addLoadEvents.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/_base/_loader/afterOnLoad.html", dojo.moduleUrl("dojo","tests/_base/_loader/afterOnLoad.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/_base/_loader/744/testEval.html", dojo.moduleUrl("dojo","tests/_base/_loader/744/testEval.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/_base/_loader/scope/scope04.html", dojo.moduleUrl("dojo","tests/_base/_loader/scope/scope04.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/_base/_loader/scope/scopeContained.html", dojo.moduleUrl("dojo","tests/_base/_loader/scope/scopeContained.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/_base/_loader/scope/scopeContainedXd.html", dojo.moduleUrl("dojo","tests/_base/_loader/scope/scopeContainedXd.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/_base/_loader/scope/scopeDjConfig.html", dojo.moduleUrl("dojo","tests/_base/_loader/scope/scopeDjConfig.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/_base/_loader/scope/scopeSingle.html", dojo.moduleUrl("dojo","tests/_base/_loader/scope/scopeSingle.html"+userArgs), 99999999);
+ doh.registerUrl("dojo/tests/_base/_loader/scope/scopeSingleDaac.html", dojo.moduleUrl("dojo","tests/_base/_loader/scope/scopeSingleDaac.html"+userArgs), 99999999);
+}
+}catch(e){
+ doh.debug(e);
+}
+
+}
diff --git a/includes/js/dojo/tests/module.js b/includes/js/dojo/tests/module.js
new file mode 100644
index 0000000..c4995aa
--- /dev/null
+++ b/includes/js/dojo/tests/module.js
@@ -0,0 +1,29 @@
+if(!dojo._hasResource["dojo.tests.module"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.tests.module"] = true;
+dojo.provide("dojo.tests.module");
+
+try{
+ dojo.require("tests._base");
+ dojo.require("tests.i18n");
+ dojo.requireIf(dojo.isBrowser, "tests.back-hash");
+ dojo.require("tests.cldr");
+ dojo.require("tests.data");
+ dojo.require("tests.date");
+ dojo.require("tests.number");
+ dojo.require("tests.currency");
+ dojo.require("tests.AdapterRegistry");
+ dojo.require("tests.io.script");
+ dojo.require("tests.io.iframe");
+ dojo.requireIf(dojo.isBrowser, "tests.rpc");
+ dojo.require("tests.string");
+ dojo.require("tests.behavior");
+ dojo.require("tests.parser");
+ dojo.require("tests.colors");
+ dojo.requireIf(dojo.isBrowser,"tests.cookie");
+ dojo.require("tests.fx");
+ dojo.require("tests.DeferredList");
+}catch(e){
+ doh.debug(e);
+}
+
+}
diff --git a/includes/js/dojo/tests/nls/ar/salutations.js b/includes/js/dojo/tests/nls/ar/salutations.js
new file mode 100644
index 0000000..f6f2cbf
--- /dev/null
+++ b/includes/js/dojo/tests/nls/ar/salutations.js
@@ -0,0 +1 @@
+({"ar":"العربية","hello":"ﺎﺑﺣﺮﻣ","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/cs/salutations.js b/includes/js/dojo/tests/nls/cs/salutations.js
new file mode 100644
index 0000000..0d7b880
--- /dev/null
+++ b/includes/js/dojo/tests/nls/cs/salutations.js
@@ -0,0 +1 @@
+({"hello":"Ahoj","cs":"Äesky","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/de/salutations.js b/includes/js/dojo/tests/nls/de/salutations.js
new file mode 100644
index 0000000..efd62ec
--- /dev/null
+++ b/includes/js/dojo/tests/nls/de/salutations.js
@@ -0,0 +1 @@
+({"de":"Deutsch","hello":"Hallo","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/el/salutations.js b/includes/js/dojo/tests/nls/el/salutations.js
new file mode 100644
index 0000000..10d97c0
--- /dev/null
+++ b/includes/js/dojo/tests/nls/el/salutations.js
@@ -0,0 +1 @@
+({"hello":"Γειά","el":"Ελληνικά","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/en-au/salutations.js b/includes/js/dojo/tests/nls/en-au/salutations.js
new file mode 100644
index 0000000..314ab18
--- /dev/null
+++ b/includes/js/dojo/tests/nls/en-au/salutations.js
@@ -0,0 +1 @@
+({"hello":"G'day","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/en-us-hawaii/salutations.js b/includes/js/dojo/tests/nls/en-us-hawaii/salutations.js
new file mode 100644
index 0000000..dd35331
--- /dev/null
+++ b/includes/js/dojo/tests/nls/en-us-hawaii/salutations.js
@@ -0,0 +1 @@
+({"hello":"Aloha","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/en-us-new_york-brooklyn/salutations.js b/includes/js/dojo/tests/nls/en-us-new_york-brooklyn/salutations.js
new file mode 100644
index 0000000..9deae14
--- /dev/null
+++ b/includes/js/dojo/tests/nls/en-us-new_york-brooklyn/salutations.js
@@ -0,0 +1 @@
+({"hello":"Yo","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/en-us-texas/salutations.js b/includes/js/dojo/tests/nls/en-us-texas/salutations.js
new file mode 100644
index 0000000..410cde8
--- /dev/null
+++ b/includes/js/dojo/tests/nls/en-us-texas/salutations.js
@@ -0,0 +1 @@
+({"hello":"Howdy","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/es/salutations.js b/includes/js/dojo/tests/nls/es/salutations.js
new file mode 100644
index 0000000..c460414
--- /dev/null
+++ b/includes/js/dojo/tests/nls/es/salutations.js
@@ -0,0 +1 @@
+({"es":"Español","hello":"Hola","hello_dojo":"¡${hello}, ${dojo}!","yi":"Yiddish","en-us-texas":"English (Texas)","de":"German","pl":"Polish","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/fa/salutations.js b/includes/js/dojo/tests/nls/fa/salutations.js
new file mode 100644
index 0000000..aaf73ee
--- /dev/null
+++ b/includes/js/dojo/tests/nls/fa/salutations.js
@@ -0,0 +1 @@
+({"hello":"درود","fa":"Ùارسی","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/fr/salutations.js b/includes/js/dojo/tests/nls/fr/salutations.js
new file mode 100644
index 0000000..9f81ca2
--- /dev/null
+++ b/includes/js/dojo/tests/nls/fr/salutations.js
@@ -0,0 +1 @@
+({"fr":"Français","hello":"Bonjour","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/he/salutations.js b/includes/js/dojo/tests/nls/he/salutations.js
new file mode 100644
index 0000000..859fedc
--- /dev/null
+++ b/includes/js/dojo/tests/nls/he/salutations.js
@@ -0,0 +1 @@
+({"he":"עברית","hello":"שלו×","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/hi/salutations.js b/includes/js/dojo/tests/nls/hi/salutations.js
new file mode 100644
index 0000000..12b23a8
--- /dev/null
+++ b/includes/js/dojo/tests/nls/hi/salutations.js
@@ -0,0 +1 @@
+({"hello":"नमसà¥à¤¤à¥‡","hi":"हिनà¥à¤¦à¥€","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/it/salutations.js b/includes/js/dojo/tests/nls/it/salutations.js
new file mode 100644
index 0000000..c3dd9cc
--- /dev/null
+++ b/includes/js/dojo/tests/nls/it/salutations.js
@@ -0,0 +1 @@
+({"it":"italiano","hello":"Ciao","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/ja/salutations.js b/includes/js/dojo/tests/nls/ja/salutations.js
new file mode 100644
index 0000000..5456efe
--- /dev/null
+++ b/includes/js/dojo/tests/nls/ja/salutations.js
@@ -0,0 +1 @@
+({"hello":"ã“ã«ã¡ã¯","ja":"日本語","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/ko/salutations.js b/includes/js/dojo/tests/nls/ko/salutations.js
new file mode 100644
index 0000000..4b43561
--- /dev/null
+++ b/includes/js/dojo/tests/nls/ko/salutations.js
@@ -0,0 +1 @@
+({"hello":"안녕","ko":"한국어","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/pl/salutations.js b/includes/js/dojo/tests/nls/pl/salutations.js
new file mode 100644
index 0000000..e4a9a2b
--- /dev/null
+++ b/includes/js/dojo/tests/nls/pl/salutations.js
@@ -0,0 +1 @@
+({"pl":"Polski","hello":"Dzièn dobry","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/pt/salutations.js b/includes/js/dojo/tests/nls/pt/salutations.js
new file mode 100644
index 0000000..7bc14c0
--- /dev/null
+++ b/includes/js/dojo/tests/nls/pt/salutations.js
@@ -0,0 +1 @@
+({"hello":"Olá","pt":"Português","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/ru/salutations.js b/includes/js/dojo/tests/nls/ru/salutations.js
new file mode 100644
index 0000000..07e53e2
--- /dev/null
+++ b/includes/js/dojo/tests/nls/ru/salutations.js
@@ -0,0 +1 @@
+({"ru":"руÑÑкий","hello":"Привет","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/salutations.js b/includes/js/dojo/tests/nls/salutations.js
new file mode 100644
index 0000000..2ad7c40
--- /dev/null
+++ b/includes/js/dojo/tests/nls/salutations.js
@@ -0,0 +1 @@
+({"yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","hello":"Hello","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/sw/salutations.js b/includes/js/dojo/tests/nls/sw/salutations.js
new file mode 100644
index 0000000..5bde087
--- /dev/null
+++ b/includes/js/dojo/tests/nls/sw/salutations.js
@@ -0,0 +1 @@
+({"hello":"Hujambo","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/th/salutations.js b/includes/js/dojo/tests/nls/th/salutations.js
new file mode 100644
index 0000000..48ff292
--- /dev/null
+++ b/includes/js/dojo/tests/nls/th/salutations.js
@@ -0,0 +1 @@
+({"th":"ქáƒáƒ áƒ—ული ენáƒáƒ¥áƒáƒ áƒ—ული ენáƒáƒ¥áƒáƒ áƒ—ული ენáƒà¸ªà¸§à¸±à¸ªà¸”ีครับ/คะ","hello":"ภาษาไทย","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/tr/salutations.js b/includes/js/dojo/tests/nls/tr/salutations.js
new file mode 100644
index 0000000..785fb02
--- /dev/null
+++ b/includes/js/dojo/tests/nls/tr/salutations.js
@@ -0,0 +1 @@
+({"tr":"Türkçe","hello":"Merhaba","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/yi/salutations.js b/includes/js/dojo/tests/nls/yi/salutations.js
new file mode 100644
index 0000000..76187d9
--- /dev/null
+++ b/includes/js/dojo/tests/nls/yi/salutations.js
@@ -0,0 +1 @@
+({"yi":"ייִדיש","hello":"×Ö· גוטן ט×ָג","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/zh-cn/salutations.js b/includes/js/dojo/tests/nls/zh-cn/salutations.js
new file mode 100644
index 0000000..cf7500d
--- /dev/null
+++ b/includes/js/dojo/tests/nls/zh-cn/salutations.js
@@ -0,0 +1 @@
+({"zh-cn":"汉语","hello":"你好","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","zh-tw":"Chinese (Traditional)","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/nls/zh-tw/salutations.js b/includes/js/dojo/tests/nls/zh-tw/salutations.js
new file mode 100644
index 0000000..1b2a6ad
--- /dev/null
+++ b/includes/js/dojo/tests/nls/zh-tw/salutations.js
@@ -0,0 +1 @@
+({"zh-tw":"漢語","hello":"你好","yi":"Yiddish","en-us-texas":"English (Texas)","es":"Spanish","de":"German","pl":"Polish","hello_dojo":"${hello}, ${dojo}!","fa":"Farsi","pt":"Portugese","sw":"Kiswahili","ar":"Arabic","en-us-new_york-brooklyn":"English (Brooklynese)","ru":"Russian","fr":"French","th":"Thai","it":"Italian","he":"Hebrew","cs":"Czech","hi":"Hindi","en-us-hawaii":"English (US-Hawaii)","file_not_found":"The file you requested, ${0}, is not found.","en-au":"English (Australia)","el":"Greek","ko":"Korean","tr":"Turkish","en":"English","ja":"Japanese","zh-cn":"Chinese (Simplified)","dojo":"Dojo"}) \ No newline at end of file
diff --git a/includes/js/dojo/tests/number.js b/includes/js/dojo/tests/number.js
new file mode 100644
index 0000000..902484a
--- /dev/null
+++ b/includes/js/dojo/tests/number.js
@@ -0,0 +1,966 @@
+if(!dojo._hasResource["tests.number"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.number"] = true;
+dojo.provide("tests.number");
+
+dojo.require("dojo.number");
+
+/**
+ * Refer to ICU4J's NumberFormatTest.expect(...)
+ */
+tests.number.check=function(t,options,sourceInput,expectResult){
+ tests.number.checkFormatParseCycle(t, t,options,sourceInput,expectResult,false);
+ tests.number.checkParse(t, t,options,expectResult,sourceInput);
+}
+
+/**
+ * Perform a single formatting check or a backward check
+ * backward check:number1 -(formatted)-> string1 -(parsed)-> number2 -(formated)-> string2
+ * then number should == number2; string1 should == string2
+ */
+tests.number.checkFormatParseCycle=function(t,options,sourceInput,expectResult,
+ backwardCheck/*boolean,indicates whether need a backward chain check,like formate->parse->format*/){
+ if(null != options){
+ var pattern = options.pattern;
+ var locale = options.locale;
+ //TODO: add more fields
+ }
+
+ //print("\n");
+ var str = null==pattern?"default":pattern;
+ //print("pattern:" + str + "| locale:" + locale);
+ //print("input:" + sourceInput);
+ var result = dojo.number.format(sourceInput,options);
+ //print("result:" + result);
+ if(null != expectResult){
+ t.is(expectResult,result);
+ }
+ if(backwardCheck){
+ var resultParsed = dojo.number.parse(result,options);
+ //print("resultParsed:" + resultParsed);
+ if(!tests.number._decimalNumberDiff(sourceInput,resultParsed)){
+ t.is(sourceInput,resultParsed);
+ }
+ var resultParsedReformatted = dojo.number.format(resultParsed,options);
+ //print("resultParsedReformatted:" + resultParsedReformatted);
+ if(!tests.number._decimalNumberDiff(result,resultParsedReformatted)){
+ t.is(result,resultParsedReformatted);
+ }
+ }
+}
+
+/**
+ * Perform a single parsing check
+ */
+tests.number.checkParse=function(t,options,sourceInput,expectResult){
+ var str = "default";
+ if(null != options && null != options.pattern){
+ str = options.pattern;
+ }
+ //print("input:" + sourceInput);
+ var result = dojo.number.parse(sourceInput,options);
+ //print("result :" + result);
+ if(null != expectResult){
+ t.is(expectResult,result);
+ }
+}
+
+/**
+ * //TODO:Round a given number
+ */
+tests.number.rounding = function(t,number,maxFractionDigits,expected){
+ var pattern="#0.";
+ for(var i=0; i<maxFractionDigits; i++){pattern += "#";}
+ var result = dojo.number.format(number,{pattern:pattern});
+ t.is(expected,result);
+}
+
+/**
+ * Run a batch parsing
+ */
+function runBatchParse(options,dataArray/*array*/,pass/*boolean*/){
+ var exception = null;
+ var result;
+ var i=0;
+ var str = (null==options.pattern)?"default":options.pattern;
+
+ //print("\n");
+ for(; i<dataArray.length; i++){
+ try{
+ //print("["+i+"]"+"input:"+dataArray[i]);
+ result = dojo.number.parse(dataArray[i],options);
+ if(isNaN(result)){
+ throw "\"" + dataArray[i] + "\" is parsed to NaN with pattern " + str;
+ }
+ //print("["+i+"]"+"output:"+result);
+ }catch(e){
+ exception = e;
+ break;
+ }
+ }
+
+ if(!pass && (exception == null)) {
+ throw "runBatchParse() - stric parse failed, no exception when parsing illegal data";
+ }else if(exception != null){
+ if(!pass && i == 0){
+ //strict parsing should fail for all the dataArray elements as expected
+ //pass condition for strict parsing
+ return;
+ }
+ throw "runBatchParse() failed: " + exception;
+ }
+}
+
+/**
+ * Check whether the given two numbers differ under the decimal bound
+ *
+ */
+tests.number._decimalNumberDiff = function(num1,num2){
+ //TODO: should be more accurate when dojo.number finish rounding in the future
+ var diffBound = 1e-3;
+ var diff = num1 - num2;
+ //print("Math.abs(diff) " + Math.abs(diff));
+ if(Math.abs(diff) < diffBound ){
+ return true;
+ }else if(isNaN(Math.abs(diff))){
+ var s = num1.toString().split(num2);
+ s[1] = s[1].replace(",","0");
+ s[1] = s[1].replace('\u066b','0');
+ return (new Number(s[1])< diffBound);
+ }
+ return false;
+}
+
+tests.register("tests.number",
+ [
+ {
+ // Test formatting and parsing of currencies in various locales pre-built in dojo.cldr
+ // NOTE: we can't set djConfig.extraLocale before bootstrapping unit tests, so directly
+ // load resources here for specific locales:
+
+ name: "number",
+ setUp: function(){
+ var partLocaleList = ["en-us", "fr-fr", "de-de"];
+
+ for(var i = 0 ; i < partLocaleList.length; i ++){
+ dojo.requireLocalization("dojo.cldr","number",partLocaleList[i], "zh-cn,zh,ko-kr,pt,en-us,en-gb,de,ja,ja-jp,en,ROOT,en-au,fr,es,ko,zh-tw,it,es-es,de-de");
+ }
+ },
+ runTest: function(t){
+ }
+ },
+ {
+ name: "format", // old tests
+ runTest: function(t){
+
+ t.is("0123", dojo.number.format(123, {pattern: "0000"}));
+ t.is("-12,34,567.890", dojo.number.format(-1234567.89, {pattern: "#,##,##0.000##"}));
+ t.is("-12,34,567.89012", dojo.number.format(-1234567.890123, {pattern: "#,##,##0.000##"}));
+ t.is("(1,234,567.89012)", dojo.number.format(-1234567.890123, {pattern: "#,##0.000##;(#,##0.000##)"}));
+ t.is("(1,234,567.89012)", dojo.number.format(-1234567.890123, {pattern: "#,##0.000##;(#)"}));
+ t.is("50.1%", dojo.number.format(0.501, {pattern: "#0.#%"}));
+ t.is("98", dojo.number.format(1998, {pattern: "00"}));
+ t.is("01998", dojo.number.format(1998, {pattern: "00000"}));
+ t.is("0.13", dojo.number.format(0.125, {pattern: "0.##"})); //NOTE: expects round_half_up, not round_half_even
+ t.is("0.1250", dojo.number.format(0.125, {pattern: "0.0000"}));
+ t.is("0.1", dojo.number.format(0.100004, {pattern: "0.####"}));
+
+ t.is("-12", dojo.number.format(-12.3, {places:0, locale: "en-us"}));
+ t.is("-1,234,567.89", dojo.number.format(-1234567.89, {locale: "en-us"}));
+// t.is("-12,34,567.89", dojo.number.format(-1234567.89, {locale: "en-in"}));
+ t.is("-1,234,568", dojo.number.format(-1234567.89, {places:0, locale: "en-us"}));
+// t.is("-12,34,568", dojo.number.format(-1234567.89, {places:0, locale: "en-in"}));
+ t.is("-1\xa0000,10", dojo.number.format(-1000.1, {places:2, locale: "fr-fr"}));
+ t.is("-1,000.10", dojo.number.format(-1000.1, {places:2, locale: "en-us"}));
+ t.is("-1\xa0000,10", dojo.number.format(-1000.1, {places:2, locale: "fr-fr"}));
+ t.is("-1.234,56", dojo.number.format(-1234.56, {places:2, locale: "de-de"}));
+ t.is("-1,000.10", dojo.number.format(-1000.1, {places:2, locale: "en-us"}));
+ t.is("123.46%", dojo.number.format(1.23456, {places:2, locale: "en-us", type: "percent"}));
+
+ //rounding
+ t.is("-1,234,568", dojo.number.format(-1234567.89, {places:0, locale: "en-us"}));
+// t.is("-12,34,568", dojo.number.format(-1234567.89, {places:0, locale: "en-in"}));
+ t.is("-1,000.11", dojo.number.format(-1000.114, {places:2, locale: "en-us"}));
+ t.is("-1,000.11", dojo.number.format(-1000.115, {places:2, locale: "en-us"}));
+ t.is("-1,000.12", dojo.number.format(-1000.116, {places:2, locale: "en-us"}));
+ t.is("-0.00", dojo.number.format(-0.0001, {places:2, locale: "en-us"}));
+ t.is("0.00", dojo.number.format(0, {places:2, locale: "en-us"}));
+
+ //change decimal places
+ t.is("-1\xa0000,100", dojo.number.format(-1000.1, {places:3, locale: "fr-fr"}));
+ t.is("-1,000.100", dojo.number.format(-1000.1, {places:3, locale: "en-us"}));
+ }
+ },
+ {
+ name: "parse", // old tests
+ runTest: function(t){
+ t.is(1000, dojo.number.parse("1000", {locale: "en-us"}));
+ t.is(1000.123, dojo.number.parse("1000.123", {locale: "en-us"}));
+ t.is(1000, dojo.number.parse("1,000", {locale: "en-us"}));
+ t.is(-1000, dojo.number.parse("-1000", {locale: "en-us"}));
+ t.is(-1000.123, dojo.number.parse("-1000.123", {locale: "en-us"}));
+ t.is(-1234567.89, dojo.number.parse("-1,234,567.89", {locale: "en-us"}));
+ t.is(-1234567.89, dojo.number.parse("-1 234 567,89", {locale: "fr-fr"}));
+ t.t(isNaN(dojo.number.parse("-1 234 567,89", {locale: "en-us"})));
+
+ t.t(isNaN(dojo.number.parse("10,00", {locale: "en-us"})));
+ t.t(isNaN(dojo.number.parse("1000.1", {locale: "fr-fr"})));
+
+ t.t(isNaN(dojo.number.parse("")));
+ t.t(isNaN(dojo.number.parse("abcd")));
+
+ //test whitespace
+// t.is(-1234567, dojo.number.parse(" -1,234,567 ", {locale: "en-us"}));
+
+// t.t(dojo.number.parse("9.1093826E-31"));
+ t.is(0.501, dojo.number.parse("50.1%", {pattern: "#0.#%"}));
+
+ t.is(123.4, dojo.number.parse("123.4", {pattern: "#0.#"}));
+ t.is(-123.4, dojo.number.parse("-123.4", {pattern: "#0.#"}));
+ t.is(123.4, dojo.number.parse("123.4", {pattern: "#0.#;(#0.#)"}));
+ t.is(-123.4, dojo.number.parse("(123.4)", {pattern: "#0.#;(#0.#)"}));
+
+ t.is(null, dojo.number.format("abcd", {pattern: "0000"}));
+
+ t.is(123, dojo.number.parse("123", {places:0}));
+ t.is(123, dojo.number.parse("123", {places:'0'}));
+ t.is(123.4, dojo.number.parse("123.4", {places:1}));
+ t.is(123.45, dojo.number.parse("123.45", {places:'1,3'}));
+ t.is(123.45, dojo.number.parse("123.45", {places:'0,2'}));
+ }
+ },
+ {
+ name: "format_icu4j3_6",
+ runTest: function(t){
+
+/*************************************************************************************************
+ * Evan:The following test cases are referred from ICU4J 3.6 (NumberFormatTest etc.)
+ * see http://icu.sourceforge.net/download/3.6.html#ICU4J
+ *************************************************************************************************/
+
+
+/**
+ * In ICU4J, testing logic for NumberFormat.format() is seperated into
+ * differernt single tese cases. So part of these logic are
+ * collected together in this single method.
+ *
+ * !!Failed cases are as follows:
+ * 1.1234567890987654321234567890987654321 should be formatted as
+ * 1,234,567,890,987,654,321,234,567,890,987,654,321 with all the default parameters,
+ * but got 1.234 instead, may due to the unimplemeted exponent.
+ * 2.\u00a4 and ' are not replaced
+ * with pattern "'*&'' '\u00a4' ''&*' #,##0.00"
+ * 1.0 should be formatted to "*&' Re. '&* 1.00",but got "'*&'' '\u00a4' ''&*' 1.00" instead
+ * etc.
+ *
+ */
+ //print("test_number_format_icu4j3_6() start..............");
+ /* !!Failed case, 1.234 returned instead
+ //refer to ICU4J's NumberFormatTest.TestCoverage()
+ var bigNum = 1234567890987654321234567890987654321;
+ var expectResult = "1,234,567,890,987,654,321,234,567,890,987,654,321";
+ tests.number.checkFormatParseCycle(t, null,bigNum,expectResult,false);
+ */
+
+ //in icu4j should throw out an exception when formatting a string,
+ //but it seems dojo.number.format can deal with strings
+ //return 123,456,789
+ dojo.number.format("123456789");
+
+ //!!Failed case, \u00a4 and ' are not replaced
+ /*
+ var options = {pattern:"'*&'' '\u00a4' ''&*' #,##0.00",locale:"en-us"};
+ tests.number.check(t, options,1.0, "*&' Re. '&* 1.00");
+ tests.number.check(t, options,-2.0, "-*&' Rs. '&* 2.00");
+
+ options = {pattern:"#,##0.00 '*&'' '\u00a4' ''&*'",locale:"en-us"};
+ tests.number.check(t, options,1.0,"1.00 *&' Re. '&*");
+ tests.number.check(t, options,-2.0,"-2.00 *&' Rs. '&*");
+ */
+ //print("test_number_format_icu4j3_6() end..............\n");
+ }
+ },
+ {
+ name: "format_patterns",
+ runTest: function(t){
+
+/**
+ * Refer to ICU4J's NumberFormatTest.TestPatterns() which now only coveres us locale
+ */
+ //print("test_number_format_Patterns() start..............");
+ var patterns = (["#0.#", "#0.", "#.0", "#"]);
+ var patternsLength = patterns.length;
+ var num = (["0","0", "0.0", "0"]);
+ var options;
+ //icu4j result seems doesn't work as:
+ //var num = (["0","0.", ".0", "0"]);
+ for (var i=0; i<patternsLength; ++i)
+ {
+ options = {pattern:patterns[i]};
+ tests.number.checkFormatParseCycle(t, options,0,num[i],false);
+ }
+
+ //!!Failed case
+ //In ICU4J:
+ // unquoted special characters in the suffix are illegal
+ // so "000.000|###" is illegal; "000.000'|###'" is legal
+ //dojo.number.format:
+ // when formatting 1.2 with illegal pattern "000.000|###"
+ // no exception was thrown but got "001.200|###" instead.
+
+ /*
+ patterns = (["000.000|###","000.000'|###'"]);
+ var exception = false;
+ var result;
+ for(var i = 0; i < patterns.length; i ++){
+ try{
+ //"001.200'|###'" is return for "000.000'|###'"
+ //"001.200|###" is return for "000.000|###"
+ result = dojo.number.format(1.2,{pattern:patterns[i]});
+ print("["+i+"] 1.2 is formatted to " + result + " with pattern " + patterns[i]);
+ }catch(e){
+ exception = true;
+ }
+ if(exception && i==1){
+ throw "["+i+"]Failed when formatting 1.2 using legal pattern " + patterns[i];
+ }else if(!exception && i==0){
+ throw "["+i+"]Failed when formatting 1.2 using illegal pattern " + patterns[i];
+ }
+ }*/
+ //print("test_number_format_Patterns() end..............\n");
+ }
+ },
+ {
+ name: "exponential",
+ runTest: function(t){
+/**
+ * TODO: For dojo.number future version
+ * Refer to ICU4J's NumberFormatTest.TestExponential()
+ */
+ }
+ },
+ {
+ name: "format_quotes",
+ runTest: function(t){
+/**
+ * TODO: Failed case
+ * Refer to ICU4J's NumberFormatTest.TestQuotes()
+ */
+ //print("test_number_format_Quotes() start..............");
+ //TODO: add more locales
+
+ //TODO:!!Failed case
+ //Pattern "s'aa''s'c#" should format 6666 to "saa'sc6666", but got s'aa''s'c6666 instead
+ // is this case necessary?
+ /*
+ var pattern = "s'aa''s'c#";
+ var result = dojo.number.format(6666,{pattern:pattern,locale:"en-us"});
+ var expectResult = "saa'sc6666";
+ t.is(expectResult,result);
+ */
+ //print("test_number_format_Quotes() end..............");
+ }
+ },
+ {
+ name: "format_rounding",
+ runTest: function(t){
+/**
+ * Refer to ICU4J's NumberFormatTest.TestRounding487() and NumberFormatTest.TestRounding()
+ */
+ //print("test_number_format_rounding() start..............");
+ tests.number.rounding(t,0.000179999, 5, "0.00018");
+ tests.number.rounding(t,0.00099, 4, "0.001");
+ tests.number.rounding(t,17.6995, 3, "17.7");
+ tests.number.rounding(t,15.3999, 0, "15");
+ tests.number.rounding(t,-29.6, 0, "-30");
+
+ //TODO refer to NumberFormatTest.TestRounding()
+
+ //print("test_number_format_rounding() end..............");
+ }
+ },
+ {
+ name: "format_scientific",
+ runTest: function(t){
+/**
+ * TODO: For dojo.number future version
+ * Refer to ICU4J's NumberFormatTest.TestScientific()- Exponential testing
+ * Refer to ICU4J's NumberFormatTest.TestScientific2()
+ * Refer to ICU4J's NumberFormatTest.TestScientificGrouping()
+ */
+ }
+ },
+ {
+ name: "format_perMill",
+ runTest: function(t){
+/**
+ * TODO: Failed case
+ * Refer to ICU4J's NumberFormatTest.TestPerMill()
+ */
+ //print("test_number_format_PerMill() start..............");
+ var pattern;
+ var result;
+ var expectResult;
+
+ //TODO: !!Failed case - ###.###\u2030(\u2030 is ‰)
+ //Pattern ###.###\u2030 should format 0.4857 as 485.7\u2030,but got 485.700\u2030 instead
+ pattern = "###.###\u2030";
+ expectResult = "485.7\u2030";
+ result = dojo.number.format(0.4857,{pattern:pattern});
+ t.is(expectResult,result);
+
+ //TODO: !!Failed mile percent case - ###.###m
+ //Pattern "###.###m" should format 0.4857 to 485.7m, but got 0.485m instead
+ /*
+ pattern = "###.###m";
+ expectResult = "485.7m";
+ result = dojo.number.format(0.4857,{pattern:pattern,locale:"en"});
+ t.is(expectResult,result);
+ */
+ //print("test_number_format_PerMill() end..............\n");
+ }
+ },
+ {
+ name: "format_grouping",
+ runTest: function(t){
+/**
+ * Only test en-us and en-in
+ * Refer to ICU4J's NumberFormatTest.TestSecondaryGrouping()
+ */
+ //print("test_number_format_Grouping() start..............");
+ //primary grouping
+ var sourceInput = 123456789;
+ var expectResult = "12,34,56,789";
+ var options = {pattern:"#,##,###",locale:"en-us"};
+
+ //step1: 123456789 formated=> 12,34,56,789
+ //step2:12,34,56,789 parsed=> 123456789 => formated => 12,34,56,789
+ tests.number.checkFormatParseCycle(t, options,sourceInput,expectResult,true);
+
+ //TODO: sencondary grouping not implemented yet ?
+ //Pattern "#,###" and secondaryGroupingSize=4 should format 123456789 to "12,3456,789"
+
+ //Special case for "en-in" locale
+ //1876543210 should be formated as 1,87,65,43,210 in "en-in" (India)
+/*
+ sourceInput = 1876543210;
+ expectResult = "1,87,65,43,210";
+ var result = dojo.number.format(sourceInput,{locale:"en-in"});
+ t.is(expectResult,result);
+*/
+ //print("test_number_format_Grouping() end..............\n");
+ }
+ },
+ {
+ name: "format_pad",
+ runTest: function(t){
+/**
+ * TODO:!!Failed cases:
+ * According to ICU4J test criteria:
+ * 1.with pattern "*^##.##":
+ * 0 should be formatted to "^^^^0",but got "*^0" instead,
+ * -1.3 should be formatted to "^-1.3",but got "-*^1.3" instead.
+ *
+ * 2.with pattern "##0.0####*_ 'g-m/s^2'" :
+ * 0 should be formatted to "0.0______ g-m/s^2",but got ":0.0*_ 'g-m/s^2'" instead
+ * 1.0/3 should be formatted to "0.33333__ g-m/s^2",but got "0.33333*_ 'g-m/s^2'" instead
+ *
+ * 3.with pattern "*x#,###,###,##0.0#;*x(###,###,##0.0#)":
+ * -10 should be formatted to "xxxxxxxxxx(10.0)",but got "*x(10.0)" instead.
+ * 10 should be formatted to "xxxxxxxxxxxx10.0",but got "*x10.0" instead.
+ * ......
+ * -1120456.37 should be formatted to "xx(1,120,456.37)",but got "*x(1,120,456.37)" instead.
+ * 1120456.37 should be formatted to "xxxx1,120,456.37",but got "*x1,120,456.37" instead.
+ * -1252045600.37 should be formatted to "(1,252,045,600.37)",but got "*x(1,252,045,600.37)" instead.
+ * 1252045600.37 should be formatted to "10,252,045,600.37",but got "*x10,252,045,600.37" instead.
+ *
+ * 4.with pattern "#,###,###,##0.0#*x;(###,###,##0.0#*x)"
+ * -10 should be formatted to (10.0xxxxxxxxxx),but got "(10.0*x)" instead.
+ * 10 should be formatted to "10.0xxxxxxxxxxxx",but got "10.0*x" instead.
+ * ......
+ * -1120456.37 should be formatted to "(1,120,456.37xx)",but got "(1,120,456.37*x)" instead.
+ * 1120456.37 should be formatted to "xxxx1,120,456.37",but got "1,120,456.37*x" instead.
+ * -1252045600.37 should be formatted to "(1,252,045,600.37)",but got "(1,252,045,600.37*x)" instead.
+ * 1252045600.37 should be formatted to ""10,252,045,600.37"",but got "10,252,045,600.37*x" instead.*
+ *
+ * Refer to ICU4J's NumberFormatTest.TestPad()
+ */
+/*
+function test_number_format_pad(){
+ var locale = "en-us";
+ print("test_number_format_Pad() start..............");
+ var options = {pattern:"*^##.##",locale:locale};
+
+ tests.number.check(t, options,0,"^^^^0");
+ tests.number.check(t, options,-1.3,"^-1.3");
+
+
+ options = {pattern:"##0.0####*_ 'g-m/s^2'",locale:locale};
+ tests.number.check(t, options,0,"0.0______ g-m/s^2");
+ tests.number.checkFormatParseCycle(t, options,1.0/3,"0.33333__ g-m/s^2",true);
+
+ //exponent not implemented
+ //options = {pattern:"##0.0####E0*_ 'g-m/s^2'",locale:locale};
+ //tests.number.check(t, options,0,"0.0E0______ g-m/s^2");
+ //tests.number.checkFormatParseCycle(t, options,1.0/3,"333.333E-3_ g-m/s^2",true);
+
+ // Test padding before a sign
+ options = {pattern:"*x#,###,###,##0.0#;*x(###,###,##0.0#)",locale:locale};
+
+ tests.number.check(t, options,-10,"xxxxxxxxxx(10.0)");
+ tests.number.check(t, options,-1000, "xxxxxxx(1,000.0)");
+ tests.number.check(t, options,-1000000, "xxx(1,000,000.0)");
+ tests.number.check(t, options,-100.37, "xxxxxxxx(100.37)");
+ tests.number.check(t, options,-10456.37, "xxxxx(10,456.37)");
+ tests.number.check(t, options,-1120456.37, "xx(1,120,456.37)");
+ tests.number.check(t, options,-112045600.37, "(112,045,600.37)");
+ tests.number.check(t, options,-1252045600.37, "(1,252,045,600.37)");
+
+
+ tests.number.check(t, options,10, "xxxxxxxxxxxx10.0");
+ tests.number.check(t, options,1000, "xxxxxxxxx1,000.0");
+ tests.number.check(t, options,1000000, "xxxxx1,000,000.0");
+ tests.number.check(t, options,100.37, "xxxxxxxxxx100.37");
+ tests.number.check(t, options,10456.37, "xxxxxxx10,456.37");
+ tests.number.check(t, options,1120456.37, "xxxx1,120,456.37");
+ tests.number.check(t, options,112045600.37, "xx112,045,600.37");
+ tests.number.check(t, options,10252045600.37, "10,252,045,600.37");
+
+ // Test padding between a sign and a number
+ options = {pattern:"#,###,###,##0.0#*x;(###,###,##0.0#*x)",locale:locale};
+ tests.number.check(t, options, -10, "(10.0xxxxxxxxxx)");
+ tests.number.check(t, options, -1000, "(1,000.0xxxxxxx)");
+ tests.number.check(t, options, -1000000, "(1,000,000.0xxx)");
+ tests.number.check(t, options, -100.37, "(100.37xxxxxxxx)");
+ tests.number.check(t, options, -10456.37, "(10,456.37xxxxx)");
+ tests.number.check(t, options, -1120456.37, "(1,120,456.37xx)");
+ tests.number.check(t, options, -112045600.37, "(112,045,600.37)");
+ tests.number.check(t, options, -1252045600.37, "(1,252,045,600.37)");
+
+ tests.number.check(t, options, 10, "10.0xxxxxxxxxxxx");
+ tests.number.check(t, options, 1000, "1,000.0xxxxxxxxx");
+ tests.number.check(t, options, 1000000, "1,000,000.0xxxxx");
+ tests.number.check(t, options, 100.37, "100.37xxxxxxxxxx");
+ tests.number.check(t, options, 10456.37, "10,456.37xxxxxxx");
+ tests.number.check(t, options, 1120456.37, "1,120,456.37xxxx");
+ tests.number.check(t, options, 112045600.37, "112,045,600.37xx");
+ tests.number.check(t, options, 10252045600.37, "10,252,045,600.37");
+
+ //Not implemented yet,refer to NumberFormatTest.TestPatterns2()
+ //For future use - maily test pad patterns
+ print("test_number_format_Pad() end..............");
+}
+*/
+ }
+ },
+ {
+ name: "parse_icu4j3_6",
+ runTest: function(t){
+/**
+ * In ICU4J, testing logic for NumberFormat.parse() is seperated into
+ * differernt single tese cases. So part of these logic are
+ * collected together in this test case. *
+ */
+ //print("test_number_parse_icu4j3_6() start..............");
+ //Refer to ICU4J's NumberFormatTest.TestParse() which is only a rudimentary version
+ var pattern = "00";
+ var str = "0.0";
+ var result = dojo.number.parse(str,{pattern:pattern});
+ //TODO: add more locales
+//FIXME: is this a valid test?
+// t.is(0,result);
+
+ /**************************************** tolerant parse *****************************************
+ * refers to ICU4J's NumberFormatTest.TestStrictParse()??
+ * TODO: Seems dojo.number parses string in a tolerant way.
+ */
+ var options = {locale:"en-us"};
+ /*
+ * TODO: !!Failed case,Should all pass,
+ * but the following elements failed (all parsed to NaN):
+ * [1]-"0 ",[2]-"0.",[3]-"0,",[5]-"0. ",[6]-"0.100,5",
+ * [7]-".00",[9]-"12345, ",[10]-"1,234, ",[12]-"0E"
+ */
+ var passData = ([
+ "0", //[0] single zero before end of text is not leading
+ //"0 ", //[1] single zero at end of number is not leading
+ //"0.", //[2] single zero before period (or decimal, it's ambiguous) is not leading
+ //"0,", //[3] single zero before comma (not group separator) is not leading
+ "0.0", //[4] single zero before decimal followed by digit is not leading
+ //"0. ", //[5] same as above before period (or decimal) is not leading
+ //"0.100,5", //[6] comma stops parse of decimal (no grouping)
+ //".00", //[7] leading decimal is ok, even with zeros
+ "1234567", //[8] group separators are not required
+ //"12345, ", //[9] comma not followed by digit is not a group separator, but end of number
+ //"1,234, ", //[10] if group separator is present, group sizes must be appropriate
+ "1,234,567" //[11] ...secondary too
+ //,"0E" //[12]not implemented yet,an exponnent not followed by zero or digits is not an exponent
+ ]);
+ runBatchParse(options,passData,true/*tolerant parse*/);
+
+ /*
+ * TODO:!!Failed case,should all pass,
+ * but the following failed,
+ * [10]-"1,45 that" implies that we partially parse input
+ */
+ var failData = ([
+ "00", //[0] leading zero before zero
+ "012", //[1] leading zero before digit
+ "0,456", //[2] leading zero before group separator
+ "1,2", //[3] wrong number of digits after group separator
+ ",0", //[4] leading group separator before zero
+ ",1", //[5] leading group separator before digit
+ ",.02", //[6] leading group separator before decimal
+ "1,.02", //[7] group separator before decimal
+ "1,,200", //[8] multiple group separators
+ "1,45", //[9] wrong number of digits in primary group
+ //"1,45 that", //[10] wrong number of digits in primary group
+ "1,45.34", //[11] wrong number of digits in primary group
+ "1234,567", //[12] wrong number of digits in secondary group
+ "12,34,567", //[13] wrong number of digits in secondary group
+ "1,23,456,7890" //[14] wrong number of digits in primary and secondary groups
+ ]);
+ runBatchParse(options,failData,false);
+
+ options = {pattern:"#,##,##0.#",locale:"en-us"};
+ /*
+ * TODO:!!Failed case,shoudl all pass.
+
+ * but [1] [2] and [3] failed
+ * should be parsed to 1234567,but NaN instead
+ */
+ var mixedPassData = ([
+ "12,34,567" //[0]
+ //,"12,34,567," //[1]
+ //"12,34,567, that",//[2]
+ //"12,34,567 that" //[3]
+ ]);
+ runBatchParse(options,mixedPassData,true/*tolerant parse*/);
+
+ /*
+ * TODO:!!Failed case,should all pass,
+ * but actually mixedFailData[2] and mixedFailData[3] passed.
+ * "12,34,56, that " and [3]-"12,34,56 that" should be parsed to 123456,but NaN instead
+ */
+ var mixedFailData = ([
+ "12,34,56", //[0]
+ "12,34,56," //[1]
+ //,"12,34,56, that ",//[2]
+ //"12,34,56 that", //[3]
+ ]);
+ runBatchParse(options,mixedFailData,false);
+
+
+ /**************************************** strict parse ******************************************
+ * TODO:May need to test strict parsing in the future?
+ * e.g. A strict parsing like (with pattern "#,##0.#")
+ * 1.Leading zeros
+ * '00', '0123' fail the parse, but '0' and '0.001' pass
+ * 2.Leading or doubled grouping separators
+ * ',123' and '1,,234" fail
+ * 3.Groups of incorrect length when grouping is used
+ * '1,23' and '1234,567' fail, but '1234' passes
+ * 4.Grouping separators used in numbers followed by exponents
+ * '1,234E5' fails, but '1234E5' and '1,234E' pass
+ */
+ //options={locale:"en",strict:true};
+ //runBatchParse(options,passData,false/*strict parse*/);
+ //runBatchParse(options,failData,false/*strict parse*/);
+
+ //options = {pattern:"#,##,##0.#",locale:"en-us",strict:true};
+ //runBatchParse(options,mixedPassData,false/*strict parse*/);
+ //runBatchParse(options,mixedFailData,false/*strict parse*/);
+
+ //print("test_number_parse_icu4j3_6() end..............\n");
+ }
+ },
+ {
+ name: "parse_whitespace",
+ runTest: function(t){
+/**
+ * TODO:!!Failed case
+ * With pattern "a b#0c ",both "a b3456c " and and "a b1234c " should be parsed to 3456,but got NaN instead.
+ *
+ * Refer to ICU4J's NumberFormatTest.TestWhiteSpaceParsing
+ */
+ /*
+ print("test_number_parse_WhiteSpace() start..............");
+ var pattern = "a b#0c ";
+ var expectResult = 3456;
+ result = dojo.number.parse("a b3456c ",{pattern:pattern,locale:"en-us"});
+ t.is(expectResult,result);
+ result = dojo.number.parse("a b3456c ",{pattern:pattern,locale:"en-us"});
+ t.is(expectResult,result);
+ print("test_number_parse_WhiteSpace() end..............\n");
+ */
+ }
+ },
+/*************************************************************************************************
+ * Regression test cases
+ * These test cases are referred to ICU4J's NumberFormatRegressionTest and NumberFormatRegression.
+ * The regression cases in ICU4J are used as unit test cases for bug fixing,
+ * They are inluced here so that dojo.number may avoid those similar bugs.
+ *************************************************************************************************/
+ {
+ name: "number_regression_1",
+ runTest: function(t){
+/**
+ * Refer to ICU4J's NumberFormatRegressionTest.Test4161100()
+ */
+ tests.number.checkFormatParseCycle(t, {pattern:"#0.#"},-0.09,"-0.1",false);
+ }
+ },
+ {
+ name: "number_regression_2",
+ runTest: function(t){
+/**
+ * !!Failed case,rounding hasn't been implemented yet.
+ * Refer to ICU4J's NumberFormatRegressionTest.Test4408066()
+ */
+ /*
+ var data = ([-3.75, -2.5, -1.5,
+ -1.25, 0, 1.0,
+ 1.25, 1.5, 2.5,
+ 3.75, 10.0, 255.5]);
+ var expected = (["-4", "-2", "-2",
+ "-1", "0", "1",
+ "1", "2", "2",
+ "4", "10", "256"]);
+ var options = {locale:"zh-cn",round:true};
+ for(var i =0; i < data.length; i++){
+ tests.number.checkFormatParseCycle(t, options,data[i],expected[i],false);
+ }
+
+ data = ([ "-3.75", "-2.5", "-1.5",
+ "-1.25", "0", "1.0",
+ "1.25", "1.5", "2.5",
+ "3.75", "10.0", "255.5"]);
+ expected =([ -3, -2, -1,
+ -1, 0, 1,
+ 1, 1, 2,
+ 3, 10, 255]);
+
+ for(var i =0; i < data.length; i++){
+ tests.number.checkParse(t, options,data[i],expected[i]);
+ }
+ */
+ }
+ },
+ {
+ name: "number_regression_3",
+ runTest: function(t){
+/**
+ * Refer to ICU4J's NumberRegression.Test4087535() and Test4243108()
+ */
+ tests.number.checkFormatParseCycle(t, {places:0},0,"0",false);
+ //TODO:in icu4j,0.1 should be formatted to ".1" when minimumIntegerDigits=0
+ tests.number.checkFormatParseCycle(t, {places:0},0.1,"0",false);
+ tests.number.checkParse(t, {pattern:"#0.#####"},123.55456,123.55456);
+//!! fails because default pattern only has 3 decimal places
+// tests.number.checkParse(t, null,123.55456,123.55456);
+
+ //See whether it fails first format 0.0 ,parse "99.99",and then reformat 0.0
+ tests.number.checkFormatParseCycle(t, {pattern:"#.#"},0.0,"0",false);
+ tests.number.checkParse(t, null,"99.99",99.99);
+ tests.number.checkFormatParseCycle(t, {pattern:"#.#"},0.0,"0",false);
+ }
+ },
+ {
+ name: "number_regression_4",
+ runTest: function(t){
+/**
+ * TODO:
+ * In ICU -0.0 and -0.0001 should be formatted to "-0" with FieldPosition(0)
+ * dojo.i18n.number format -0.0 to "-0"; -0.0001 to "-0.000100"
+ *
+ * Refer to ICU4J's NumberRegression.Test4088503() and Test4106658()
+ */
+ tests.number.checkFormatParseCycle(t, {places:0},123,"123",false);
+
+ //TODO: differernt from ICU where -0.0 is formatted to "-0"
+ tests.number.checkFormatParseCycle(t, {locale:"en-us"},-0.0,"0",false);
+
+ //TODO: differernt from ICU where -0.0001 is formatted to "-0"
+ tests.number.checkFormatParseCycle(t, {locale:"en-us",places:6},-0.0001,"-0.000100",false);
+ }
+ },
+ {
+ name: "number_regression_5",
+ runTest: function(t){
+/**
+ * !!Failed case,rounding has not implemented yet.
+ * 0.00159999 should be formatted as 0.0016 but got 0.0015 instead.
+ * Refer to ICU4J's NumberRegression.Test4071492()
+ */
+ //tests.number.checkFormatParseCycle(t, {places:4,round:true},0.00159999,"0.0016",false);
+ }
+ },
+ {
+ name: "number_regression_6",
+ runTest: function(t){
+/**
+ * Refer to ICU4J's NumberRegression.Test4086575()
+ */
+ var pattern = "###.00;(###.00)";
+ var locale = "fr";
+ var options = {pattern:pattern,locale:locale};
+
+ //no group separator
+ tests.number.checkFormatParseCycle(t, options,1234,"1234,00",false);
+ tests.number.checkFormatParseCycle(t, options,-1234,"(1234,00)",false);
+
+ //space as group separator
+ pattern = "#,###.00;(#,###.00)";
+ options = {pattern:pattern,locale:locale};
+ tests.number.checkFormatParseCycle(t, options,1234,"1\u00a0234,00",false);// Expect 1 234,00
+ tests.number.checkFormatParseCycle(t, options,-1234,"(1\u00a0234,00)",false); // Expect (1 234,00)
+ }
+ },
+ {
+ name: "number_regression_7",
+ runTest: function(t){
+/**
+ * !!Failed case - expontent has not implemented yet
+ * shuold format 1.000000000000001E7 to 10000000.00000001, but got 10,000,000.000 instead
+ * Refer to ICU4J's NumberRegression.Test4090489() - loses precision
+ */
+ //tests.number.checkFormatParseCycle(t, null,1.000000000000001E7,"10000000.00000001",false);
+ }
+ },
+ {
+ name: "number_regression_8",
+ runTest: function(t){
+/**
+ * !!Failed case
+ * 1.with pattern "#,#00.00 p''ieces;-#,#00.00 p''ieces"
+ * 3456.78 should be formated to "3,456.78 p'ieces",
+ * but got "3,456.78 p''ieces","''" should be replaced with "'"
+ * 2.with illegal pattern "000.0#0"
+ * no error for the illegal pattern, and 3456.78 is formatted to 456.780
+ * 3.with illegal pattern "0#0.000"
+ * no error for the illegal pattern, and 3456.78 is formatted to 3456.780
+ *
+ * Refer to ICU4J's NumberRegression.Test4092480(),Test4074454()
+ */
+ var patterns = (["#0000","#000","#00","#0","#"]);
+ var expect = (["0042","042","42","42","42"]);
+
+ for(var i =0; i < patterns.length; i ++){
+ tests.number.checkFormatParseCycle(t, {pattern:patterns[i]},42,expect[i],false);
+ tests.number.checkFormatParseCycle(t, {pattern:patterns[i]},-42,"-"+expect[i],false);
+ }
+
+ tests.number.checkFormatParseCycle(t, {pattern:"#,#00.00;-#.#"},3456.78,"3,456.78",false);
+ //!!Failed case
+ //tests.number.checkFormatParseCycle(t, {pattern:"#,#00.00 p''ieces;-#,#00.00 p''ieces"},3456.78,"3,456.78 p'ieces",false);
+ //tests.number.checkFormatParseCycle(t, {pattern:"000.0#0"},3456.78,null,false);
+ //tests.number.checkFormatParseCycle(t, {pattern:"0#0.000"},3456.78,null,false);
+ }
+ },
+ {
+ name: "number_regression_9",
+ runTest: function(t){
+/**
+ * TODO
+ * Refer to ICU4J's NumberRegression.Test4052223()
+ */
+ //TODO:only got NaN,need an illegal pattern exception?
+ tests.number.checkParse(t, {pattern:"#,#00.00"},"abc3");
+
+ //TODO: got NaN instead of 1.222, is it ok?
+ //tests.number.checkParse(t, {pattern:"#,##0.###",locale:"en-us"},"1.222,111",1.222);
+ //tests.number.checkParse(t, {pattern:"#,##0.###",locale:"en-us"},"1.222x111",1.222);
+
+ //got NaN for illeal input,ok
+ tests.number.checkParse(t, null,"hello: ,.#$@^&**10x");
+ }
+ },
+ {
+ name: "number_regression_10",
+ runTest: function(t){
+/**
+ * Refer to ICU4J's NumberRegression.Test4125885()
+ */
+ tests.number.checkFormatParseCycle(t, {pattern:"000.00"},12.34,"012.34",false);
+ tests.number.checkFormatParseCycle(t, {pattern:"+000.00%;-000.00%"},0.1234,"+012.34%",false);
+ tests.number.checkFormatParseCycle(t, {pattern:"##,###,###.00"},9.02,"9.02",false);
+
+ var patterns =(["#.00", "0.00", "00.00", "#0.0#", "#0.00"]);
+ var expect = (["1.20", "1.20", "01.20", "1.2", "1.20" ]);
+ for(var i =0 ; i < patterns.length; i ++){
+ tests.number.checkFormatParseCycle(t, {pattern:patterns[i]},1.2,expect[i],false);
+ }
+ }
+ },
+ {
+ name: "number_regression_11",
+ runTest: function(t){
+/**
+ * TODO:!!Failed case
+ * Make sure that all special characters, when quoted in a suffix or prefix, lose their special meaning.
+ * The detail error info :
+ * for input 123
+ * pattern:'0'#0'0'; expect:"01230"; but got "'3'#0'0'" instead
+ * pattern:','#0','; expect:",123,"; but got "','123','" instead
+ * pattern:'.'#0'.'; expect:".123."; but got "'.'123'.'" instead
+ * pattern:'‰'#0'‰'; expect:"‰123‰"; but got "'‰'123000'‰'" instead
+ * pattern:'%'#0'%'; expect:"%123%"; but got "'%'12300'%'" instead
+ * pattern:'#'#0'#'; expect:"#123#"; but got "'123'#0'#'" instead
+ * pattern:';'#0';'; expect:";123;"; but got "[dojo-test] FATAL exception raised:
+ * unable to find a number expression in pattern: '"
+ * pattern:'E'#0'E'; expect:"E123E"; not implemeted yet
+ * pattern:'*'#0'*'; expect:"*123*"; but got "'*'123'*'" instead
+ * pattern:'+'#0'+'; expect:"+123+"; but got "'+'123'+'" instead
+ * pattern:'-'#0'-'; expect:"-123-"; but got "'-'123'-'" instead
+ *
+ * TODO: is it ok to remain "'" in the formatted result as above??
+ *
+ * Refer to ICU4J's NumberRegression.Test4212072()
+ */
+/*
+ var specials = ([ '0', ',', '.', '\u2030', '%', '#',';', 'E', '*', '+', '-']);
+ var pattern;
+ var expect;
+
+ for(var i=0; i < specials.length; i ++){
+ pattern = "'" + specials[i] + "'#0'" + specials[i] + "'";
+ expect = "" + specials[i] + "123" + specials[i];
+ tests.number.checkFormatParseCycle(t, {pattern:pattern,locale:"en-us"},123,expect,false);
+ }
+*/
+ }
+ },
+ {
+ name: "number_regression_12",
+ runTest: function(t){
+/**
+ * TODO: add more rounding test cases, refer to ICU4J's NumberRegression.Test4071005(),Test4071014() etc..
+ */
+
+/**
+ * TODO:Decimal format doesnt round a double properly when the number is less than 1
+ *
+ * Refer to ICU4J's NumberRegression.test4241880()
+ */
+/*
+ var input = ([ .019, .009, .015, .016, .014,
+ .004, .005, .006, .007, .008,
+ .5, 1.5, .05, .15, .005,
+ .015, .0005, .0015]);
+ var patterns = (["##0%", "##0%", "##0%", "##0%", "##0%",
+ "##0%", "##0%", "##0%", "##0%", "##0%",
+ "#,##0", "#,##0", "#,##0.0", "#,##0.0", "#,##0.00",
+ "#,##0.00", "#,##0.000", "#,##0.000"]);
+ var expect =([ "2%", "1%", "2%", "2%", "1%",
+ "0%", "0%", "1%", "1%", "1%",
+ "0", "2", "0.0", "0.2", "0.00",
+ "0.02", "0.000", "0.002",]);
+ for(var i = 0; i <input.length; i ++){
+ tests.number.checkFormatParseCycle(t, {pattern:patterns[i],round:true},input[i],expect[i],false);
+ }
+*/
+ }
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/parser.html b/includes/js/dojo/tests/parser.html
new file mode 100644
index 0000000..8d7565b
--- /dev/null
+++ b/includes/js/dojo/tests/parser.html
@@ -0,0 +1,241 @@
+<html>
+ <head>
+ <title>Parser Unit Test</title>
+ <style type="text/css">
+ @import "../resources/dojo.css";
+ </style>
+ <script type="text/javascript"
+ src="../dojo.js"
+ djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.parser");
+ dojo.require("doh.runner");
+
+ dojo.declare("tests.parser.Class1", null, {
+ constructor: function(args, node){ dojo.mixin(this, args); },
+ preambleTestProp: 1,
+ preamble: function(){
+ this.preambleTestProp++;
+ },
+ intProp: 1,
+ callCount: 0, // for connect testing
+ callInc: function(){ this.callCount++; },
+ callCount2: 0, // for assignment testing
+ strProp1: "original1",
+ strProp2: "original2",
+ arrProp: [],
+ boolProp1: false,
+ boolProp2: true,
+ boolProp3: false,
+ boolProp4: true,
+ dateProp1: dojo.date.stamp.fromISOString('2007-01-01'),
+ dateProp2: dojo.date.stamp.fromISOString('2007-01-01'),
+ dateProp3: dojo.date.stamp.fromISOString('2007-01-01'),
+ funcProp: function(){},
+ funcProp2: function(){},
+ funcProp3: function(){},
+ onclick: function(){ this.prototypeOnclick=true; }
+ // FIXME: have to test dates!!
+ // FIXME: need to test the args property!!
+ });
+
+ dojo.declare("tests.parser.Class2", null, {
+ constructor: function(){
+ this.fromMarkup = false;
+ },
+ fromMarkup: false,
+ markupFactory: function(args, node, classCtor){
+ var i = new tests.parser.Class2();
+ i.fromMarkup = true;
+ return i;
+ }
+ });
+
+
+ dojo.declare("tests.parser.Class3", tests.parser.Class2, {
+ fromMarkup: false,
+ markupFactory: function(args, node, classCtor){
+ var i = new classCtor();
+ i.classCtor = classCtor;
+ return i;
+ }
+ });
+
+ dojo.declare("tests.parser.inputClass", null, {
+ constructor: function(args, node){ dojo.mixin(this, args); },
+ // these attributes are special in HTML, they don't have a value specified
+ disabled: false,
+ checked: false
+ });
+
+ deepTestProp = {
+ blah: {
+ thinger: 1
+ }
+ };
+
+ dojo.addOnLoad(function(){
+ doh.register("t",
+ [
+ function testJsId(t){
+ // console.debug(obj);
+ t.t(typeof obj == "object");
+ },
+
+ // Attribute parsing tests
+ function testStrProp(t){
+ // normal string parameter
+ t.t(dojo.isString(obj.strProp1));
+ t.is("text", obj.strProp1);
+
+ // make sure that you override a string value like "foo" to a blank value
+ t.t(dojo.isString(obj.strProp2));
+ t.is("", obj.strProp2);
+ },
+ function testIntProp(t){
+ t.is("number", (typeof obj.intProp));
+ t.is(5, obj.intProp);
+ },
+ function testArrProp(t){
+ t.is(3, obj.arrProp.length);
+ t.is(3, obj.arrProp[1].length);
+ t.is(["foo", "bar", "baz"], obj.arrProp);
+ },
+ function testBoolProp(t){
+ // make sure that both true and false get read correctly,
+ // and that unspecified attributes' values don't change
+
+ // boolProp1 specified at true
+ t.is("boolean", (typeof obj.boolProp1));
+ t.t(obj.boolProp1);
+
+ // boolProp2 specified as false
+ t.is("boolean", (typeof obj.boolProp2));
+ t.f(obj.boolProp2);
+
+ // boolProp3 not specified (prototype says false)
+ t.is("boolean", (typeof obj.boolProp3));
+ t.f(obj.boolProp3);
+
+ // boolProp4 not specified (prototype says true)
+ t.is("boolean", (typeof obj.boolProp4));
+ t.t(obj.boolProp4);
+ },
+ function testDateProp(t){
+ // dateProp1 specified as 2006-1-1
+ t.is("2006-01-01", dojo.date.stamp.toISOString(obj.dateProp1, {selector: 'date'}));
+
+ // dateProp2="", should map to NaN (a blank value on DateTextBox)
+ t.t(isNaN(obj.dateProp2));
+
+ // dateProp3="now", should map to current date
+ t.is(dojo.date.stamp.toISOString(new Date(), {selector: 'date'}),
+ dojo.date.stamp.toISOString(obj.dateProp3, {selector: 'date'}));
+ },
+ function testDisabledFlag(t){
+ t.is("boolean", (typeof disabledObj.disabled));
+ t.t(disabledObj.disabled);
+ t.f(disabledObj.checked);
+ },
+ function testCheckedFlag(t){
+ t.is("boolean", (typeof checkedObj.checked));
+ t.f(checkedObj.disabled);
+ t.t(checkedObj.checked);
+ },
+ function testFunctionProp(t){
+ // make sure that unspecified functions (even with common names)
+ // don't get overridden (bug #3074)
+ obj.onclick();
+ t.t(obj.prototypeOnclick);
+
+ // funcProp2="foo"
+ obj.funcProp2();
+ t.t(obj.fooCalled);
+
+ // funcProp3="this.func3Called=true;"
+ obj.funcProp3();
+ t.t(obj.func3Called);
+ },
+
+ // test <script> tags inside innerHTML of source node
+ "t.is(4, obj.preambleTestProp);",
+ "t.is(deepTestProp, obj.deepProp);",
+ function testConnect(t){
+ obj.callInc();
+ t.is(2, obj.callCount);
+ },
+ function testFunctionAssignment(t){
+ obj.callInc2();
+ t.is(1, obj.callCount2);
+ },
+ function testSubNodeParse(t){
+ t.f(dojo.exists("obj2"));
+ var toParse = dojo.byId("toParse");
+ toParse.setAttribute("dojoType", toParse.getAttribute("type"));
+ dojo.parser.parse(toParse.parentNode);
+ t.t(dojo.exists("obj2"));
+ t.is("tests.parser.Class1", obj2.declaredClass);
+ },
+ function testMarkupFactory(t){
+ t.t(dojo.exists("obj3"));
+ t.t(obj3.fromMarkup);
+ },
+ function testMarkupFactoryClass(t){
+ t.t(dojo.exists("obj4"));
+ t.is(obj4.classCtor, tests.parser.Class3);
+ t.t(obj4 instanceof tests.parser.Class3);
+ t.t(obj4 instanceof tests.parser.Class2);
+ },
+ function testDisabledFlag(t){
+ t.t(disabledObj.disabled);
+ t.f(disabledObj.checked);
+ },
+ function testCheckedFlag(t){
+ t.f(checkedObj.disabled);
+ t.t(checkedObj.checked);
+ }
+ ]
+ );
+ doh.run();
+ })
+ </script>
+ </head>
+ <body>
+ <h1>Parser Unit Test</h1>
+ <script>
+ function foo(){ this.fooCalled=true; }
+ </script>
+ <div dojoType="tests.parser.Class1" jsId="obj"
+ strProp1="text" strProp2=""
+ intProp="5"
+ arrProp="foo, bar, baz"
+ boolProp1="true" boolProp2="false"
+ dateProp1="2006-01-01" dateProp2="" dateProp3="now"
+ funcProp2="foo" funcProp3="this.func3Called=true;"
+ >
+ <script type="dojo/method" event="preamble">
+ this.preambleTestProp = 3;
+ </script>
+ <script type="dojo/method">
+ // this should be run immediately
+ this.deepProp = deepTestProp;
+ </script>
+ <script type="dojo/connect" event="callInc">
+ this.callCount++;
+ </script>
+ <script type="dojo/method" event="callInc2">
+ this.callCount2++;
+ </script>
+ </div>
+ <div>
+ <div type="tests.parser.Class1" jsId="obj2" id="toParse">
+ </div>
+ </div>
+ <div dojoType="tests.parser.Class2" jsId="obj3">
+ </div>
+ <div dojoType="tests.parser.Class3" jsId="obj4">
+ </div>
+ <input dojoType="tests.parser.inputClass" jsId="checkedObj" checked type="checkbox">
+ <button dojoType="tests.parser.inputClass" jsId="disabledObj" disabled>hi</button>
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/parser.js b/includes/js/dojo/tests/parser.js
new file mode 100644
index 0000000..3f5028a
--- /dev/null
+++ b/includes/js/dojo/tests/parser.js
@@ -0,0 +1,8 @@
+if(!dojo._hasResource["tests.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.parser"] = true;
+dojo.provide("tests.parser");
+if(dojo.isBrowser){
+ doh.registerUrl("tests.parser", dojo.moduleUrl("tests", "parser.html"));
+}
+
+}
diff --git a/includes/js/dojo/tests/resources/ApplicationState.js b/includes/js/dojo/tests/resources/ApplicationState.js
new file mode 100644
index 0000000..a25e7ff
--- /dev/null
+++ b/includes/js/dojo/tests/resources/ApplicationState.js
@@ -0,0 +1,28 @@
+/*
+ApplicationState is an object that represents the application state.
+It will be given to dojo.undo.browser to represent the current application state.
+*/
+ApplicationState = function(stateData, outputDivId, backForwardOutputDivId, bookmarkValue){
+ this.stateData = stateData;
+ this.outputDivId = outputDivId;
+ this.backForwardOutputDivId = backForwardOutputDivId;
+ this.changeUrl = bookmarkValue;
+}
+
+ApplicationState.prototype.back = function(){
+ this.showBackForwardMessage("BACK for State Data: " + this.stateData);
+ this.showStateData();
+}
+
+ApplicationState.prototype.forward = function(){
+ this.showBackForwardMessage("FORWARD for State Data: " + this.stateData);
+ this.showStateData();
+}
+
+ApplicationState.prototype.showStateData = function(){
+ dojo.byId(this.outputDivId).innerHTML += this.stateData + '<br />';
+}
+
+ApplicationState.prototype.showBackForwardMessage = function(message){
+ dojo.byId(this.backForwardOutputDivId).innerHTML += message + '<br />';
+}
diff --git a/includes/js/dojo/tests/resources/JSON.php b/includes/js/dojo/tests/resources/JSON.php
new file mode 100644
index 0000000..e87e4d0
--- /dev/null
+++ b/includes/js/dojo/tests/resources/JSON.php
@@ -0,0 +1,724 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Converts to and from JSON format.
+ *
+ * JSON (JavaScript Object Notation) is a lightweight data-interchange
+ * format. It is easy for humans to read and write. It is easy for machines
+ * to parse and generate. It is based on a subset of the JavaScript
+ * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
+ * This feature can also be found in Python. JSON is a text format that is
+ * completely language independent but uses conventions that are familiar
+ * to programmers of the C-family of languages, including C, C++, C#, Java,
+ * JavaScript, Perl, TCL, and many others. These properties make JSON an
+ * ideal data-interchange language.
+ *
+ * This package provides a simple encoder and decoder for JSON notation. It
+ * is intended for use with client-side Javascript applications that make
+ * use of HTTPRequest to perform server communication functions - data can
+ * be encoded into JSON notation for use in a client-side javascript, or
+ * decoded from incoming Javascript requests. JSON format is native to
+ * Javascript, and can be directly eval()'ed with no further parsing
+ * overhead
+ *
+ * All strings should be in ASCII or UTF-8 format!
+ *
+ * LICENSE: 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.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ *
+ * @category
+ * @package Services_JSON
+ * @author Michal Migurski <mike-json@teczno.com>
+ * @author Matt Knapp <mdknapp[at]gmail[dot]com>
+ * @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
+ * @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:
+ *
+ * <code>
+ * // 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);
+ * </code>
+ */
+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 $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':
+ // 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/dojo/tests/resources/testClass.php b/includes/js/dojo/tests/resources/testClass.php
new file mode 100644
index 0000000..acf7f16
--- /dev/null
+++ b/includes/js/dojo/tests/resources/testClass.php
@@ -0,0 +1,20 @@
+<?php
+class testClass {
+
+ function myecho ($somestring) {
+ return "<P>" . $somestring . "</P>";
+ }
+
+ function contentB () {
+ return "<P>Content B</P>";
+ }
+
+ function contentC () {
+ return "<P>Content C</P>";
+ }
+
+ function add($x,$y) {
+ return $x + $y;
+ }
+}
+?>
diff --git a/includes/js/dojo/tests/resources/testClass.smd b/includes/js/dojo/tests/resources/testClass.smd
new file mode 100644
index 0000000..9be6988
--- /dev/null
+++ b/includes/js/dojo/tests/resources/testClass.smd
@@ -0,0 +1,40 @@
+{
+ "SMDVersion":".1",
+ "objectName":"testClass",
+ "serviceType":"JSON-RPC",
+ "serviceURL":"../../dojo/tests/resources/test_JsonRPCMediator.php",
+ "methods":[
+ {
+ "name":"myecho",
+ "parameters":[
+ {
+ "name":"somestring",
+ "type":"STRING"
+ }
+ ]
+ },
+ {
+ "name":"contentB"
+ },
+ {
+ "name":"contentC"
+ },
+ {
+ "name":"add",
+ "parameters":[
+ {
+ "name":"x",
+ "type":"STRING"
+ },
+ {
+ "name":"y",
+ "type":"STRING"
+ }
+ ]
+ },
+ {
+ "name":"triggerRpcError"
+ },
+
+ ]
+}
diff --git a/includes/js/dojo/tests/resources/test_JsonRPCMediator.php b/includes/js/dojo/tests/resources/test_JsonRPCMediator.php
new file mode 100644
index 0000000..42a9711
--- /dev/null
+++ b/includes/js/dojo/tests/resources/test_JsonRPCMediator.php
@@ -0,0 +1,43 @@
+<?php
+ require_once("./JSON.php");
+
+ // FIXME: doesn't look like we really need Pear at all
+ // which decreases the testing burden.
+ // Commenting out.the require and the new File() call.
+
+ // NOTE: File.php is installed via Pear using:
+ // %> 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);
+
+ include("./testClass.php");
+ $testObject = new testClass();
+
+ $method = $req->method;
+ if ($method != "triggerRpcError") {
+ $ret = call_user_func_array(array($testObject,$method),$req->params);
+ $results['result'] = $ret;
+ } else {
+ $results['error'] = "Triggered RPC Error test";
+ }
+ $results['id'] = $req->id;
+
+ $encoded = $json->encode($results);
+
+ print $encoded;
+?>
diff --git a/includes/js/dojo/tests/resources/test_css.html b/includes/js/dojo/tests/resources/test_css.html
new file mode 100644
index 0000000..b999f02
--- /dev/null
+++ b/includes/js/dojo/tests/resources/test_css.html
@@ -0,0 +1,100 @@
+<html>
+ <head>
+ <title>Dojo CSS Stylesheet Test</title>
+ <link rel="stylesheet" type="text/css" href="../../resources/dojo.css" />
+ </head>
+ <body>
+ <h1>Lorem ipsum dolor sit amet.</h1>
+ <p>Lorem ipsum dolor sit amet, <a href="">consectetuer adipiscing elit</a>. 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. Nullam consequat iaculis augue. Aliquam pellentesque egestas massa. Curabitur pulvinar, enim vel porta dapibus, ligula lectus vulputate purus, eu tempus ante dolor id quam. Sed luctus fermentum nulla. Donec sollicitudin imperdiet risus. Cras cursus, sapien ac faucibus feugiat, ligula felis laoreet justo, eu sollicitudin purus purus in nibh. Phasellus in nunc.</p>
+ <q>Donec eu nunc vitae lorem egestas convallis <code>var test=null;</code> Nullam at enim id mauris vestibulum ornare. Cras facilisis tellus at risus. Phasellus ut pede at erat posuere vehicula. Donec auctor sodales risus. Maecenas dictum erat at justo. Nullam fringilla dictum orci. Ut vitae erat. Fusce nunc. Duis quis orci. Morbi faucibus. Ut fermentum augue ac nulla. Duis cursus eleifend felis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Mauris tincidunt, justo quis venenatis congue, nisi purus dignissim nisi, ullamcorper tempus dolor nulla at metus.</q>
+ <h2>Donec eu nunc vitae lorem.</h2>
+ <p>Donec eu nunc vitae lorem egestas convallis. Nullam at enim id mauris vestibulum ornare. Cras facilisis tellus at risus. Phasellus ut pede at erat posuere vehicula. Donec auctor sodales risus. Maecenas dictum erat at justo. Nullam fringilla dictum orci. Ut vitae erat. Fusce nunc. Duis quis orci. Morbi faucibus. Ut fermentum augue ac nulla. Duis cursus eleifend felis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Mauris tincidunt, justo quis venenatis congue, nisi purus dignissim nisi, ullamcorper tempus dolor nulla at metus.</p>
+ <p>Vestibulum ultricies bibendum tortor. Nam auctor dignissim neque. Cras vehicula. Nulla facilisi. Duis quis tellus in est aliquet condimentum. Sed elementum, felis vel pharetra bibendum, neque lorem pulvinar nulla, consequat tempor libero enim vel nulla. Nulla eleifend, lorem accumsan convallis lobortis, diam dui eleifend urna, eu imperdiet purus urna nec nibh. Nullam pede odio, molestie eu, interdum sagittis, imperdiet ac, lectus. Sed pede nisl, vulputate at, pellentesque id, consectetuer ac, elit. Duis laoreet, elit sed tempus vehicula, lacus orci pulvinar nibh, non malesuada ante mi in enim. Etiam pulvinar, sapien ut vulputate venenatis, risus lectus sollicitudin sapien, in dapibus felis ligula congue ante. Vivamus sit amet ligula. Morbi pharetra augue egestas massa. Sed a ligula. In ac mi id nibh semper accumsan. Nunc luctus nibh vel magna. Nunc viverra nonummy tortor. Curabitur interdum convallis dui. Integer mollis hendrerit elit. Nam a lorem.</p>
+ <ol>
+ <li>A List item.</li>
+ <li>A List item.</li>
+ <li>A List item.</li>
+ <li>A List item.</li>
+ <li>A List item.</li>
+ <li>A List item.</li>
+ </ol>
+ <h2>Cras pellentesque</h2>
+ <h3>Aliquam dapibus</h3>
+ <pre>
+var test = someVariable;
+function foo(bar){
+ alert(baz);
+} </pre>
+ <p>Cras pellentesque tristique lorem. Aliquam dapibus, massa id posuere volutpat, sem sem nonummy turpis, ut ultricies nibh neque sed dolor. Duis commodo elit et massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed eu urna. Donec sit amet odio sit amet turpis facilisis molestie. In id mi. Nulla consequat ante ut elit. In risus urna, venenatis imperdiet, consequat vel, porttitor et, quam. In hac habitasse platea dictumst. Vestibulum id velit. Donec a eros. Donec quis quam at pede aliquet porta. Donec id ligula mollis turpis pulvinar dapibus. Praesent imperdiet, justo pulvinar accumsan scelerisque, lacus felis bibendum justo, id posuere augue libero eu velit.</p>
+ <h4>An unstyled table.</h4>
+ <table>
+ <thead>
+ <tr>
+ <th>Foo</th>
+ <th>Bar</th>
+ <th>Baz</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>baz</td>
+ <td>foo</td>
+ <td>bar</td>
+ </tr>
+ <tr>
+ <td>bar</td>
+ <td>baz</td>
+ <td>foo</td>
+ </tr>
+ <tr>
+ <td>foo</td>
+ <td>bar</td>
+ <td>baz</td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td>Foo</td>
+ <td>Bar</td>
+ <td>Baz</td>
+ </tr>
+ </tfoot>
+ </table>
+ <h4>The same table, styled with dojoTabular.</h4>
+ <table class="dojoTabular">
+ <thead>
+ <tr>
+ <th>Foo</th>
+ <th>Bar</th>
+ <th>Baz</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>baz</td>
+ <td>foo</td>
+ <td>bar</td>
+ </tr>
+ <tr>
+ <td>bar</td>
+ <td>baz</td>
+ <td>foo</td>
+ </tr>
+ <tr>
+ <td>foo</td>
+ <td>bar</td>
+ <td>baz</td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td>Foo</td>
+ <td>Bar</td>
+ <td>Baz</td>
+ </tr>
+ </tfoot>
+ </table>
+ <blockquote>Donec eu nunc vitae lorem egestas convallis. Nullam at enim id mauris vestibulum ornare. Cras facilisis tellus at risus. Phasellus ut pede at erat posuere vehicula. Donec auctor sodales risus. Maecenas dictum erat at justo. Nullam fringilla dictum orci. Ut vitae erat. Fusce nunc. Duis quis orci. Morbi faucibus. Ut fermentum augue ac nulla. Duis cursus eleifend felis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Mauris tincidunt, justo quis venenatis congue, nisi purus dignissim nisi, ullamcorper tempus dolor nulla at metus.</blockquote>
+ <p>Phasellus quis velit. Curabitur porta dolor in arcu. Maecenas mollis purus. Donec nec erat et tellus laoreet elementum. Pellentesque vitae mi. Aenean pharetra libero ultricies augue. Vestibulum et nibh. Proin nibh quam, rutrum faucibus, auctor eget, mollis vel, orci. Duis tortor quam, tincidunt eu, lacinia id, fermentum at, turpis. Mauris at augue. Nulla facilisi. Pellentesque ut enim.</p>
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/resources/yahoo_smd_v1.smd b/includes/js/dojo/tests/resources/yahoo_smd_v1.smd
new file mode 100644
index 0000000..8f6a1f7
--- /dev/null
+++ b/includes/js/dojo/tests/resources/yahoo_smd_v1.smd
@@ -0,0 +1,268 @@
+{
+ "SMDVersion":".1",
+ "objectName":"yahoo",
+ "serviceType":"JSON-P",
+ "required": {
+ "appid": "dojotoolkit",
+ "output": "json"
+ },
+ "methods":[
+ //
+ // MAPS
+ //
+ {
+ // http://developer.yahoo.com/maps/rest/V1/mapImage.html
+ "name":"mapImage",
+ "serviceURL": "http://api.local.yahoo.com/MapsService/V1/mapImage",
+ "parameters":[
+ { "name":"street", "type":"STRING" },
+ { "name":"city", "type":"STRING" },
+ { "name":"zip", "type":"INTEGER" },
+ { "name":"location", "type":"STRING" },
+ { "name":"longitude", "type":"FLOAT" },
+ { "name":"latitude", "type":"FLOAT" },
+ { "name":"image_type", "type":"STRING" },
+ { "name":"image_width", "type":"INTEGER" },
+ { "name":"image_height", "type":"INTEGER" },
+ { "name":"zoom", "type":"INTEGER" },
+ { "name":"radius", "type":"INTEGER" }
+ ]
+ },
+ {
+ // http://developer.yahoo.com/traffic/rest/V1/index.html
+ "name":"trafficData",
+ "serviceURL": "http://api.local.yahoo.com/MapsService/V1/trafficData",
+ "parameters":[
+ { "name":"street", "type":"STRING" },
+ { "name":"city", "type":"STRING" },
+ { "name":"zip", "type":"INTEGER" },
+ { "name":"location", "type":"STRING" },
+ { "name":"longitude", "type":"FLOAT" },
+ { "name":"latitude", "type":"FLOAT" },
+ { "name":"severity", "type":"INTEGER" },
+ { "name":"include_map", "type":"INTEGER" },
+ { "name":"image_type", "type":"STRING" },
+ { "name":"image_width", "type":"INTEGER" },
+ { "name":"image_height", "type":"INTEGER" },
+ { "name":"zoom", "type":"INTEGER" },
+ { "name":"radius", "type":"INTEGER" }
+ ]
+ },
+ //
+ // LOCAL SEARCH
+ //
+ {
+ // http://developer.yahoo.com/search/local/V3/localSearch.html
+ "name":"localSearch",
+ "serviceURL": "http://api.local.yahoo.com/LocalSearchService/V3/localSearch",
+ "parameters":[
+ { "name":"street", "type":"STRING" },
+ { "name":"city", "type":"STRING" },
+ { "name":"zip", "type":"INTEGER" },
+ { "name":"location", "type":"STRING" },
+ { "name":"listing_id", "type":"STRING" },
+ { "name":"sort", "type":"STRING" }, // "relevence", "title", "distance", or "rating"
+ { "name":"start", "type":"INTEGER" },
+ { "name":"radius", "type":"FLOAT" },
+ { "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
+ { "name":"longitude", "type":"FLOAT" },
+ { "name":"latitude", "type":"FLOAT" },
+ { "name":"category", "type":"INTEGER" },
+ { "name":"omit_category", "type":"INTEGER" },
+ { "name":"minimum_rating", "type":"INTEGER" }
+ ]
+ },
+ //
+ // WEB SEARCH
+ //
+ {
+ // http://developer.yahoo.com/search/web/V1/webSearch.html
+ "name":"webSearch",
+ "serviceURL": "http://api.search.yahoo.com/WebSearchService/V1/webSearch",
+ "parameters":[
+ { "name":"query", "type":"STRING" },
+ { "name":"type", "type":"STRING" }, // defaults to "all"
+ { "name":"region", "type":"STRING" }, // defaults to "us"
+ { "name":"results", "type":"INTEGER" }, // defaults to 10
+ { "name":"start", "type":"INTEGER" }, // defaults to 1
+ { "name":"format", "type":"STRING" }, // defaults to "any", can be "html", "msword", "pdf", "ppt", "rst", "txt", or "xls"
+ { "name":"adult_ok", "type":"INTEGER" }, // defaults to null
+ { "name":"similar_ok", "type":"INTEGER" }, // defaults to null
+ { "name":"language", "type":"STRING" }, // defaults to null
+ { "name":"country", "type":"STRING" }, // defaults to null
+ { "name":"site", "type":"STRING" }, // defaults to null
+ { "name":"subscription", "type":"STRING" }, // defaults to null
+ { "name":"license", "type":"STRING" } // defaults to "any"
+ ]
+ },
+ {
+ // http://developer.yahoo.com/search/web/V1/spellingSuggestion.html
+ "name":"spellingSuggestion",
+ "serviceURL": "http://api.search.yahoo.com/WebSearchService/V1/spellingSuggestion",
+ "parameters":[ { "name":"query", "type":"STRING" } ]
+ },
+ {
+ // http://developer.yahoo.com/search/web/V1/relatedSuggestion.html
+ "name":"spellingSuggestion",
+ "serviceURL": "http://api.search.yahoo.com/WebSearchService/V1/relatedSuggestion",
+ "parameters":[
+ { "name":"query", "type":"STRING" },
+ { "name":"results", "type":"INTEGER" } // 1-50, defaults to 10
+ ]
+ },
+ {
+ // http://developer.yahoo.com/search/content/V1/termExtraction.html
+ "name":"termExtraction",
+ "serviceURL": "http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction",
+ "parameters":[
+ { "name":"query", "type":"STRING" },
+ { "name":"context", "type":"STRING" },
+ { "name":"results", "type":"INTEGER" } // 1-50, defaults to 10
+ ]
+ },
+ {
+ // http://developer.yahoo.com/search/web/V1/contextSearch.html
+ "name":"contextSearch",
+ "serviceURL": "http://search.yahooapis.com/WebSearchService/V1/contextSearch",
+ "parameters":[
+ { "name":"query", "type":"STRING" },
+ { "name":"context", "type":"STRING" },
+ { "name":"type", "type":"STRING" }, // defaults to "all"
+ { "name":"results", "type":"INTEGER" }, // defaults to 10
+ { "name":"start", "type":"INTEGER" }, // defaults to 1
+ { "name":"format", "type":"STRING" }, // defaults to "any", can be "html", "msword", "pdf", "ppt", "rst", "txt", or "xls"
+ { "name":"adult_ok", "type":"INTEGER" }, // defaults to null
+ { "name":"similar_ok", "type":"INTEGER" }, // defaults to null
+ { "name":"language", "type":"STRING" }, // defaults to null
+ { "name":"country", "type":"STRING" }, // defaults to null
+ { "name":"site", "type":"STRING" }, // defaults to null
+ { "name":"license", "type":"STRING" } // defaults to "any", could be "cc_any", "cc_commercial", "cc_modifiable"
+ ]
+ },
+ //
+ // IMAGE SEARCH
+ //
+ {
+ // http://developer.yahoo.com/search/image/V1/imageSearch.html
+ "name":"imageSearch",
+ "serviceURL": "http://api.search.yahoo.com/ImageSearchService/V1/imageSearch",
+ "parameters":[
+ { "name":"query", "type":"STRING" },
+ { "name":"type", "type":"STRING" }, // defaults to "all", can by "any" or "phrase"
+ { "name":"results", "type":"INTEGER" }, // defaults to 10
+ { "name":"start", "type":"INTEGER" }, // defaults to 1
+ { "name":"format", "type":"STRING" }, // defaults to "any", can be "bmp", "gif", "jpeg", or "png"
+ { "name":"adult_ok", "type":"INTEGER" }, // defaults to null
+ { "name":"coloration", "type":"STRING" }, // "any", "color", or "bw"
+ { "name":"site", "type":"STRING" } // defaults to null
+ ]
+ },
+ //
+ // SITE EXPLORER
+ //
+ {
+ // http://developer.yahoo.com/search/siteexplorer/V1/inlinkData.html
+ "name":"inlinkData",
+ "serviceURL": "http://api.search.yahoo.com/SiteExplorerService/V1/inlinkData",
+ "parameters":[
+ { "name":"query", "type":"STRING" },
+ { "name":"type", "type":"STRING" }, // defaults to "all", can by "any" or "phrase"
+ { "name":"entire_site", "type":"INTEGER" }, // defaults to null
+ { "name":"omit_inlinks", "type":"STRING" }, // "domain" or "subdomain", defaults to null
+ { "name":"results", "type":"INTEGER" }, // defaults to 50
+ { "name":"start", "type":"INTEGER" }, // defaults to 1
+ { "name":"site", "type":"STRING" } // defaults to null
+ ]
+ },
+ {
+ // http://developer.yahoo.com/search/siteexplorer/V1/pageData.html
+ "name":"pageData",
+ "serviceURL": "http://api.search.yahoo.com/SiteExplorerService/V1/pageData",
+ "parameters":[
+ { "name":"query", "type":"STRING" },
+ { "name":"type", "type":"STRING" }, // defaults to "all", can by "any" or "phrase"
+ { "name":"domain_only", "type":"INTEGER" }, // defaults to null
+ { "name":"results", "type":"INTEGER" }, // defaults to 50
+ { "name":"start", "type":"INTEGER" }, // defaults to 1
+ { "name":"site", "type":"STRING" } // defaults to null
+ ]
+ },
+ //
+ // MUSIC SEARCH
+ //
+ {
+ // http://developer.yahoo.com/search/audio/V1/artistSearch.html
+ "name":"artistSearch",
+ "serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/artistSearch",
+ "parameters":[
+ { "name":"artist", "type":"STRING" },
+ { "name":"artistid", "type":"STRING" },
+ { "name":"type", "type":"STRING" }, // "all", "any", or "phrase"
+ { "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
+ { "name":"start", "type":"INTEGER" } // defaults to 1
+ ]
+ },
+ {
+ // http://developer.yahoo.com/search/audio/V1/albumSearch.html
+ "name":"albumSearch",
+ "serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/albumSearch",
+ "parameters":[
+ { "name":"artist", "type":"STRING" },
+ { "name":"artistid", "type":"STRING" },
+ { "name":"album", "type":"STRING" },
+ { "name":"type", "type":"STRING" }, // "all", "any", or "phrase"
+ { "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
+ { "name":"start", "type":"INTEGER" } // defaults to 1
+ ]
+ },
+ {
+ // http://developer.yahoo.com/search/audio/V1/songSearch.html
+ "name":"songSearch",
+ "serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/songSearch",
+ "parameters":[
+ { "name":"artist", "type":"STRING" },
+ { "name":"artistid", "type":"STRING" },
+ { "name":"album", "type":"STRING" },
+ { "name":"albumid", "type":"STRING" },
+ { "name":"song", "type":"STRING" },
+ { "name":"songid", "type":"STRING" },
+ { "name":"type", "type":"STRING" }, // "all", "any", or "phrase"
+ { "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
+ { "name":"start", "type":"INTEGER" } // defaults to 1
+ ]
+ },
+ {
+ // http://developer.yahoo.com/search/audio/V1/songDownloadLocation.html
+ "name":"songDownloadLocation",
+ "serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/songDownloadLocation",
+ "parameters":[
+ { "name":"songid", "type":"STRING" },
+ // "source" can contain:
+ // audiolunchbox artistdirect buymusic dmusic
+ // emusic epitonic garageband itunes yahoo
+ // livedownloads mp34u msn musicmatch mapster passalong
+ // rhapsody soundclick theweb
+ { "name":"source", "type":"STRING" },
+ { "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
+ { "name":"start", "type":"INTEGER" } // defaults to 1
+ ]
+ },
+ //
+ // NEWS SEARCH
+ //
+ {
+ // http://developer.yahoo.com/search/news/V1/newsSearch.html
+ "name":"newsSearch",
+ "serviceURL": "http://api.search.yahoo.com/NewsSearchService/V1/newsSearch",
+ "parameters":[
+ { "name":"query", "type":"STRING" },
+ { "name":"type", "type":"STRING" }, // defaults to "all"
+ { "name":"results", "type":"INTEGER" }, // defaults to 10
+ { "name":"start", "type":"INTEGER" }, // defaults to 1
+ { "name":"sort", "type":"STRING" }, // "rank" or "date"
+ { "name":"language", "type":"STRING" }, // defaults to null
+ { "name":"site", "type":"STRING" } // defaults to null
+ ]
+ }
+ ]
+}
diff --git a/includes/js/dojo/tests/rpc.js b/includes/js/dojo/tests/rpc.js
new file mode 100644
index 0000000..09c8ef2
--- /dev/null
+++ b/includes/js/dojo/tests/rpc.js
@@ -0,0 +1,151 @@
+if(!dojo._hasResource["tests.rpc"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.rpc"] = true;
+dojo.provide("tests.rpc");
+
+dojo.require("dojo.rpc.RpcService");
+dojo.require("dojo.rpc.JsonService");
+dojo.require("dojo.rpc.JsonpService");
+
+doh.register("tests.rpc",
+ [
+
+ {
+ name: "JsonRPC-EchoTest",
+ timeout: 2000,
+ setUp: function(){
+
+ var testSmd = {
+ serviceURL:"../../dojo/tests/resources/test_JsonRPCMediator.php",
+ methods:[
+ {
+ name:"myecho",
+ parameters:[
+ {
+ name:"somestring",
+ type:"STRING"
+ }
+ ]
+ }
+ ]
+ }
+
+ this.svc = new dojo.rpc.JsonService(testSmd);
+ },
+ runTest: function(){
+ var d = new doh.Deferred();
+ var td = this.svc.myecho("RPC TEST");
+
+ if (window.location.protocol=="file:") {
+ var err= new Error("This Test requires a webserver and PHP and will fail intentionally if loaded from file://");
+ d.errback(err);
+ return d;
+ }
+
+ td.addCallbacks(function(result) {
+ if(result=="<P>RPC TEST</P>"){
+ return true;
+ }else{
+ return new Error("JsonRpc-EchoTest test failed, resultant content didn't match");
+ }
+ }, function(result){
+ return new Error(result);
+ });
+
+ td.addBoth(d, "callback");
+
+ return d;
+ }
+
+ },
+
+ {
+ name: "JsonRPC-EmptyParamTest",
+ timeout: 2000,
+ setUp: function(){
+ var testSmd={
+ serviceURL:"../../dojo/tests/resources/test_JsonRPCMediator.php",
+ methods:[ { name:"contentB" } ]
+ }
+
+ this.svc = new dojo.rpc.JsonService(testSmd);
+ },
+ runTest: function(){
+ var d = new doh.Deferred();
+ var td = this.svc.contentB();
+
+ if (window.location.protocol=="file:") {
+ var err= new Error("This Test requires a webserver and PHP and will fail intentionally if loaded from file://");
+ d.errback(err);
+ return d;
+ }
+
+ td.addCallbacks(function(result){
+ if(result=="<P>Content B</P>"){
+ return true;
+ }else{
+ return new Error("JsonRpc-EmpytParamTest test failed, resultant content didn't match");
+ }
+ }, function(result){
+ return new Error(result);
+ });
+
+ td.addBoth(d, "callback");
+
+ return d;
+ }
+ },
+
+ {
+ name: "JsonRPC_SMD_Loading_test",
+ setUp: function(){
+ this.svc = new dojo.rpc.JsonService("../../dojo/tests/resources/testClass.smd");
+ },
+ runTest: function(){
+
+ if (this.svc.objectName=="testClass") {
+ return true;
+ } else {
+ return new Error("Error loading and/or parsing an smd file");
+ }
+ }
+ },
+
+ {
+ name: "JsonP_test",
+ timeout: 10000,
+ setUp: function(){
+ this.svc = new dojo.rpc.JsonpService(dojo.moduleUrl("dojo.tests.resources","yahoo_smd_v1.smd"), {appid: "foo"});
+ },
+ 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 td = this.svc.webSearch({query:"dojotoolkit"});
+
+ td.addCallbacks(function(result){
+ return true;
+ if (result["ResultSet"]["Result"][0]["DisplayUrl"]=="dojotoolkit.org/") {
+ return true;
+ }else{
+ return new Error("JsonRpc_SMD_Loading_Test failed, resultant content didn't match");
+ }
+ }, function(result){
+ return new Error(result);
+ });
+
+ td.addBoth(d, "callback");
+
+ return d;
+ }
+ }
+ ]
+);
+
+
+
+}
diff --git a/includes/js/dojo/tests/runTests.html b/includes/js/dojo/tests/runTests.html
new file mode 100644
index 0000000..a83f534
--- /dev/null
+++ b/includes/js/dojo/tests/runTests.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+ <head>
+ <title>Dojo CORE and BASE D.O.H. Unit Test Runner</title>
+ <meta http-equiv="REFRESH" content="0;url=../../util/doh/runner.html?testModule=dojo.tests.module"></HEAD>
+ <BODY>
+ Redirecting to D.O.H runner.
+ </BODY>
+</HTML>
diff --git a/includes/js/dojo/tests/string.js b/includes/js/dojo/tests/string.js
new file mode 100644
index 0000000..2f9c2cb
--- /dev/null
+++ b/includes/js/dojo/tests/string.js
@@ -0,0 +1,31 @@
+if(!dojo._hasResource["tests.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["tests.string"] = true;
+dojo.provide("tests.string");
+
+dojo.require("dojo.string");
+
+tests.register("tests.string",
+ [
+ function test_string_pad(t){
+ t.is("00001", dojo.string.pad("1", 5));
+ t.is("000001", dojo.string.pad("000001", 5));
+ t.is("10000", dojo.string.pad("1", 5, null, true));
+ },
+
+ function test_string_substitute(t){
+ t.is("File 'foo.html' is not found in directory '/temp'.", dojo.string.substitute("File '${0}' is not found in directory '${1}'.", ["foo.html","/temp"]));
+ t.is("File 'foo.html' is not found in directory '/temp'.", dojo.string.substitute("File '${name}' is not found in directory '${info.dir}'.", {name: "foo.html", info: {dir: "/temp"}}));
+ // Verify that an error is thrown!
+ t.assertError(Error, dojo.string, "substitute", ["${x}", {y:1}]);
+ },
+
+ function test_string_trim(t){
+ t.is("astoria", dojo.string.trim(" \f\n\r\t astoria "));
+ t.is("astoria", dojo.string.trim("astoria "));
+ t.is("astoria", dojo.string.trim(" astoria"));
+ t.is("astoria", dojo.string.trim("astoria"));
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojo/tests/test_FirebugLite.html b/includes/js/dojo/tests/test_FirebugLite.html
new file mode 100644
index 0000000..f87f01b
--- /dev/null
+++ b/includes/js/dojo/tests/test_FirebugLite.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <title>Firebug Lite Tests</title>
+ <script type="text/javascript">
+ // enable Lite in Firefox:
+ console = null;
+ var djConfig = {
+ isDebug: true,
+ debugHeight: 100,
+ popup:false
+ };
+ </script>
+
+ <script type="text/javascript" src="../dojo.js"></script>
+ <script type="text/javascript">
+ obj = { // a long object to test scrolling in object inspector
+ mobby:{d:"objectify", e:"erroroneous", f:"functastic", obby:{lilOb:"moOb"}},
+ a:"Dojo",
+ b:2,
+ c:[0,8],
+ id:"MyCoolObject",
+ extra:{d:"objectify2", e:"erroroneous2", f:"functastic2", obby:{lilOb:"moOb2"}},
+ aaa:"Dojo",
+ bbb:22,
+ ccc:[10,18],
+ idDeedYee:"MyCoolObjectie"
+ }
+
+ obj2 = {
+ a:"Dojo",
+ b:2,
+ c:[0,8],
+ id:"MyCoolObject"
+ }
+
+ obj3 = {
+ a:"Dojo",
+ b:2,
+ c:[0,8]
+ }
+
+ outputText = function(){
+ for ( var i = 0; i < 20 ; i++){
+ console.log (i+":: foo");
+ }
+ }
+ doStuff = function(){
+ console.log("FOO! More FOO! Gotta have some FOO MAN!")
+ }
+
+ doStuffLots = function(){
+ for ( var i = 0; i < 5 ; i++){
+ console.log("xxxxxxxx")
+ doStuff();
+ }}
+ dojo.addOnLoad(function(){
+ console.time("foo time")
+ // test objects
+ console.log(obj3, "::", [1,2,3,4,5,6,7,8,9,0]);
+ console.log("Dojo was here", obj, "object over", obj2);
+
+ // test that tracing dom node does not break (due to lack of support)
+ console.log(dojo.byId("foo"))
+
+ // test error functionality
+ console.error( new Error("There was a dummy error") );
+
+ //throws exception:
+ //console.assert(true == false)
+
+ console.group("myGroup");
+ console.log("group me 1");
+ console.log("group me 2");
+ console.log("group me 3");
+ console.groupEnd();
+
+ // testing log styling
+ console.log("foo");
+ console.debug("foo");
+ console.info("foo");
+ console.warn("foo");
+ console.error("foo");
+ //timer end
+ console.timeEnd("foo time")
+ })
+
+ function doCon(){
+ }
+ </script>
+</head>
+<body>
+ <div id="foo" font="Arial" style="display:none;">Dojo was here</div>
+ <button onclick="doStuff()">Do Foo Stuff</button>
+ <button onclick="doStuffLots()">Do Stuff Lots</button>
+ <div id="trc"></div>
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/test_FirebugLitePopup.html b/includes/js/dojo/tests/test_FirebugLitePopup.html
new file mode 100644
index 0000000..926713e
--- /dev/null
+++ b/includes/js/dojo/tests/test_FirebugLitePopup.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <title>Firebug Lite Tests</title>
+ <script type="text/javascript">
+ // enable Lite in Firefox:
+ console = null;
+ var djConfig = {
+ isDebug: true,
+ debugHeight: 100,
+ popup:true // who knew?
+ };
+ </script>
+
+ <script type="text/javascript" src="../dojo.js"></script>
+ <script type="text/javascript">
+ obj = { // a long object to test scrolling in object inspector
+ mobby:{d:"objectify", e:"erroroneous", f:"functastic", obby:{lilOb:"moOb"}},
+ a:"Dojo",
+ b:2,
+ c:[0,8],
+ id:"MyCoolObject",
+ extra:{d:"objectify2", e:"erroroneous2", f:"functastic2", obby:{lilOb:"moOb2"}},
+ aaa:"Dojo",
+ bbb:22,
+ ccc:[10,18],
+ idDeedYee:"MyCoolObjectie"
+ }
+
+ obj2 = {
+ a:"Dojo",
+ b:2,
+ c:[0,8],
+ id:"MyCoolObject"
+ }
+
+ obj3 = {
+ a:"Dojo",
+ b:2,
+ c:[0,8]
+ }
+
+ outputText = function(){
+ for ( var i = 0; i < 20 ; i++){
+ console.log (i+":: foo");
+ }
+ }
+ doStuff = function(){
+ console.log("FOO! More FOO! Gotta have some FOO MAN!")
+ }
+
+ doStuffLots = function(){
+ for ( var i = 0; i < 5 ; i++){
+ console.log("xxxxxxxx")
+ doStuff();
+ }}
+ dojo.addOnLoad(function(){
+ console.time("foo time")
+ // test objects
+ console.log(obj3, "::", [1,2,3,4,5,6,7,8,9,0]);
+ console.log("Dojo was here", obj, "object over", obj2);
+
+ // test that tracing dom node does not break (due to lack of support)
+ console.log(dojo.byId("foo"))
+
+ // test error functionality
+ console.error( new Error("There was a dummy error") );
+
+ //throws exception:
+ //console.assert(true == false)
+
+ console.group("myGroup");
+ console.log("group me 1");
+ console.log("group me 2");
+ console.log("group me 3");
+ console.groupEnd();
+
+ // testing log styling
+ console.log("foo");
+ console.debug("foo");
+ console.info("foo");
+ console.warn("foo");
+ console.error("foo");
+ //timer end
+ console.timeEnd("foo time")
+ })
+
+ function doCon(){
+ }
+ </script>
+</head>
+<body>
+ <h1>test Firebug popup window</h1>
+ <div id="foo" font="Arial" style="display:none;">Dojo was here</div>
+ <button onclick="doStuff()">Do Foo Stuff</button>
+ <button onclick="doStuffLots()">Do Stuff Lots</button>
+ <div id="trc"></div>
+ </body>
+</html>
diff --git a/includes/js/dojo/tests/test_fx.html b/includes/js/dojo/tests/test_fx.html
new file mode 100644
index 0000000..8d9b0de
--- /dev/null
+++ b/includes/js/dojo/tests/test_fx.html
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style type="text/css">
+ @import "../resources/dojo.css";
+ </style>
+ <style type="text/css">
+ @import "../resources/dojo.css";
+
+ body {
+ text-shadow: 0px 0px;
+ margin: 1em;
+ background-color: #DEDEDE;
+ }
+
+ .box {
+ color: #292929;
+ /* color: #424242; */
+ /* text-align: left; */
+ width: 300px;
+ border: 1px solid #BABABA;
+ background-color: white;
+ padding-left: 10px;
+ padding-right: 10px;
+ margin-left: 10px;
+ margin-bottom: 1em;
+ -o-border-radius: 10px;
+ -moz-border-radius: 12px;
+ -webkit-border-radius: 10px;
+ -webkit-box-shadow: 0px 3px 7px #adadad;
+ /* -opera-border-radius: 10px; */
+ border-radius: 10px;
+ -moz-box-sizing: border-box;
+ -opera-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -khtml-box-sizing: border-box;
+ box-sizing: border-box;
+ overflow: hidden;
+ /* position: absolute; */
+ }
+ </style>
+ <script type="text/javascript" src="../dojo.js" djConfig="isDebug: true"></script>
+ <script type="text/javascript" src="../fx.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojo.fx");
+ dojo.addOnLoad(function(){
+ dojo.byId("foo").style.height = "0px";
+ var w1 = dojo.fx.wipeIn({
+ node: "foo",
+ duration: 500
+ });
+ var f1 = dojo.fadeOut({
+ node: "foo",
+ duration: 500
+ });
+ var a1 = dojo.fx.chain([w1, f1]);
+
+ dojo.byId("foo").style.height = "0px";
+ var w2 = dojo.fx.wipeIn({
+ node: "foo",
+ duration: 500
+ });
+ var f2 = dojo.fadeIn({
+ node: "foo",
+ duration: 1000
+ });
+ var a2 = dojo.fx.combine([w2, f2]);
+
+ dojo.connect(a1, "onEnd", function(){
+ console.log("finish1");
+ a2.play();
+ });
+ dojo.connect(a2, "onEnd", function(){
+ console.log("finish2");
+ });
+ a1.play();
+ });
+ </script>
+ </head>
+ <body>
+ <div id="foo" class="box">
+ <p>
+ 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.
+ </p>
+ <p>
+ 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.
+ </p>
+ </div>
+ </body>
+</html> \ No newline at end of file