From e44a7e37b6c7b5961adaffc62b9042b8d442938e Mon Sep 17 00:00:00 2001 From: mensonge Date: Thu, 13 Nov 2008 09:49:11 +0000 Subject: New feature: basic Ajax suggestion for tags and implementation of Dojo toolkit git-svn-id: https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/trunk@151 b3834d28-1941-0410-a4f8-b48e95affb8f --- includes/js/dojo/AdapterRegistry.js | 99 + includes/js/dojo/DeferredList.js | 88 + includes/js/dojo/LICENSE | 195 + includes/js/dojo/NodeList-fx.js | 137 + includes/js/dojo/OpenAjax.js | 194 + includes/js/dojo/_base.js | 13 + includes/js/dojo/_base/Color.js | 156 + includes/js/dojo/_base/Deferred.js | 408 + includes/js/dojo/_base/NodeList.js | 532 ++ includes/js/dojo/_base/_loader/bootstrap.js | 436 ++ includes/js/dojo/_base/_loader/hostenv_browser.js | 379 + includes/js/dojo/_base/_loader/hostenv_rhino.js | 238 + .../js/dojo/_base/_loader/hostenv_spidermonkey.js | 80 + includes/js/dojo/_base/_loader/loader.js | 690 ++ includes/js/dojo/_base/_loader/loader_debug.js | 61 + includes/js/dojo/_base/_loader/loader_xd.js | 631 ++ includes/js/dojo/_base/array.js | 182 + includes/js/dojo/_base/browser.js | 21 + includes/js/dojo/_base/connect.js | 285 + includes/js/dojo/_base/declare.js | 178 + includes/js/dojo/_base/event.js | 529 ++ includes/js/dojo/_base/fx.js | 584 ++ includes/js/dojo/_base/html.js | 1227 +++ includes/js/dojo/_base/json.js | 137 + includes/js/dojo/_base/lang.js | 257 + includes/js/dojo/_base/query.js | 1191 +++ includes/js/dojo/_base/window.js | 145 + includes/js/dojo/_base/xhr.js | 730 ++ includes/js/dojo/_firebug/LICENSE | 37 + includes/js/dojo/_firebug/errorIcon.png | Bin 0 -> 457 bytes includes/js/dojo/_firebug/firebug.css | 176 + .../js/dojo/_firebug/firebug.css.commented.css | 222 + includes/js/dojo/_firebug/firebug.js | 1103 +++ includes/js/dojo/_firebug/infoIcon.png | Bin 0 -> 524 bytes includes/js/dojo/_firebug/warningIcon.png | Bin 0 -> 516 bytes includes/js/dojo/back.js | 394 + includes/js/dojo/behavior.js | 185 + includes/js/dojo/build.txt | 126 + includes/js/dojo/cldr/LICENSE | 29 + includes/js/dojo/cldr/README | 18 + includes/js/dojo/cldr/monetary.js | 27 + includes/js/dojo/cldr/nls/currency.js | 1 + includes/js/dojo/cldr/nls/de-de/number.js | 1 + includes/js/dojo/cldr/nls/de/currency.js | 1 + includes/js/dojo/cldr/nls/de/gregorian.js | 1 + includes/js/dojo/cldr/nls/de/number.js | 1 + includes/js/dojo/cldr/nls/en-au/currency.js | 1 + includes/js/dojo/cldr/nls/en-au/gregorian.js | 1 + includes/js/dojo/cldr/nls/en-au/number.js | 1 + includes/js/dojo/cldr/nls/en-ca/currency.js | 1 + includes/js/dojo/cldr/nls/en-ca/gregorian.js | 1 + includes/js/dojo/cldr/nls/en-gb/gregorian.js | 1 + includes/js/dojo/cldr/nls/en-gb/number.js | 1 + includes/js/dojo/cldr/nls/en-us/currency.js | 1 + includes/js/dojo/cldr/nls/en-us/number.js | 1 + includes/js/dojo/cldr/nls/en/currency.js | 1 + includes/js/dojo/cldr/nls/en/gregorian.js | 1 + includes/js/dojo/cldr/nls/en/number.js | 1 + includes/js/dojo/cldr/nls/es-es/gregorian.js | 1 + includes/js/dojo/cldr/nls/es-es/number.js | 1 + includes/js/dojo/cldr/nls/es/currency.js | 1 + includes/js/dojo/cldr/nls/es/gregorian.js | 1 + includes/js/dojo/cldr/nls/es/number.js | 1 + includes/js/dojo/cldr/nls/fr/currency.js | 1 + includes/js/dojo/cldr/nls/fr/gregorian.js | 1 + includes/js/dojo/cldr/nls/fr/number.js | 1 + includes/js/dojo/cldr/nls/gregorian.js | 1 + includes/js/dojo/cldr/nls/it-it/gregorian.js | 1 + includes/js/dojo/cldr/nls/it/currency.js | 1 + includes/js/dojo/cldr/nls/it/gregorian.js | 1 + includes/js/dojo/cldr/nls/it/number.js | 1 + includes/js/dojo/cldr/nls/ja-jp/number.js | 1 + includes/js/dojo/cldr/nls/ja/currency.js | 1 + includes/js/dojo/cldr/nls/ja/gregorian.js | 1 + includes/js/dojo/cldr/nls/ja/number.js | 1 + includes/js/dojo/cldr/nls/ko-kr/gregorian.js | 1 + includes/js/dojo/cldr/nls/ko-kr/number.js | 1 + includes/js/dojo/cldr/nls/ko/currency.js | 1 + includes/js/dojo/cldr/nls/ko/gregorian.js | 1 + includes/js/dojo/cldr/nls/ko/number.js | 1 + includes/js/dojo/cldr/nls/number.js | 1 + includes/js/dojo/cldr/nls/pt-br/gregorian.js | 1 + includes/js/dojo/cldr/nls/pt/currency.js | 1 + includes/js/dojo/cldr/nls/pt/gregorian.js | 1 + includes/js/dojo/cldr/nls/pt/number.js | 1 + includes/js/dojo/cldr/nls/zh-cn/gregorian.js | 1 + includes/js/dojo/cldr/nls/zh-cn/number.js | 1 + includes/js/dojo/cldr/nls/zh-tw/currency.js | 1 + includes/js/dojo/cldr/nls/zh-tw/gregorian.js | 1 + includes/js/dojo/cldr/nls/zh-tw/number.js | 1 + includes/js/dojo/cldr/nls/zh/currency.js | 1 + includes/js/dojo/cldr/nls/zh/gregorian.js | 1 + includes/js/dojo/cldr/nls/zh/number.js | 1 + includes/js/dojo/cldr/supplemental.js | 74 + includes/js/dojo/colors.js | 225 + includes/js/dojo/cookie.js | 95 + includes/js/dojo/currency.js | 97 + includes/js/dojo/data/ItemFileReadStore.js | 765 ++ includes/js/dojo/data/ItemFileWriteStore.js | 804 ++ includes/js/dojo/data/api/Identity.js | 107 + includes/js/dojo/data/api/Notification.js | 119 + includes/js/dojo/data/api/Read.js | 506 ++ includes/js/dojo/data/api/Request.js | 32 + includes/js/dojo/data/api/Write.js | 226 + includes/js/dojo/data/util/filter.js | 69 + includes/js/dojo/data/util/simpleFetch.js | 90 + includes/js/dojo/data/util/sorter.js | 81 + includes/js/dojo/date.js | 343 + includes/js/dojo/date/locale.js | 656 ++ includes/js/dojo/date/stamp.js | 141 + includes/js/dojo/dnd/Avatar.js | 82 + includes/js/dojo/dnd/Container.js | 311 + includes/js/dojo/dnd/Manager.js | 180 + includes/js/dojo/dnd/Moveable.js | 130 + includes/js/dojo/dnd/Mover.js | 84 + includes/js/dojo/dnd/Selector.js | 244 + includes/js/dojo/dnd/Source.js | 393 + includes/js/dojo/dnd/TimedMoveable.js | 66 + includes/js/dojo/dnd/autoscroll.js | 103 + includes/js/dojo/dnd/common.js | 35 + includes/js/dojo/dnd/move.js | 202 + includes/js/dojo/dojo.js | 20 + includes/js/dojo/dojo.js.uncompressed.js | 8165 ++++++++++++++++++++ includes/js/dojo/fx.js | 415 + includes/js/dojo/i18n.js | 249 + includes/js/dojo/io/iframe.js | 358 + includes/js/dojo/io/script.js | 211 + includes/js/dojo/jaxer.js | 15 + includes/js/dojo/nls/ar/colors.js | 1 + includes/js/dojo/nls/colors.js | 1 + includes/js/dojo/nls/cs/colors.js | 1 + includes/js/dojo/nls/da/colors.js | 1 + includes/js/dojo/nls/de/colors.js | 1 + includes/js/dojo/nls/el/colors.js | 1 + includes/js/dojo/nls/es/colors.js | 1 + includes/js/dojo/nls/fi/colors.js | 1 + includes/js/dojo/nls/fr/colors.js | 1 + includes/js/dojo/nls/he/colors.js | 1 + includes/js/dojo/nls/hu/colors.js | 1 + includes/js/dojo/nls/it/colors.js | 1 + includes/js/dojo/nls/ja/colors.js | 1 + includes/js/dojo/nls/ko/colors.js | 1 + includes/js/dojo/nls/nb/colors.js | 1 + includes/js/dojo/nls/nl/colors.js | 1 + includes/js/dojo/nls/pl/colors.js | 1 + includes/js/dojo/nls/pt-pt/colors.js | 1 + includes/js/dojo/nls/pt/colors.js | 1 + includes/js/dojo/nls/ru/colors.js | 1 + includes/js/dojo/nls/sv/colors.js | 1 + includes/js/dojo/nls/tr/colors.js | 1 + includes/js/dojo/nls/zh-tw/colors.js | 1 + includes/js/dojo/nls/zh/colors.js | 1 + includes/js/dojo/number.js | 551 ++ includes/js/dojo/parser.js | 277 + includes/js/dojo/regexp.js | 69 + includes/js/dojo/resources/LICENSE | 30 + includes/js/dojo/resources/_modules.js | 36 + includes/js/dojo/resources/blank.gif | Bin 0 -> 43 bytes includes/js/dojo/resources/blank.html | 1 + includes/js/dojo/resources/dnd.css | 9 + includes/js/dojo/resources/dnd.css.commented.css | 9 + includes/js/dojo/resources/dojo.css | 100 + includes/js/dojo/resources/dojo.css.commented.css | 198 + includes/js/dojo/resources/iframe_history.html | 79 + includes/js/dojo/resources/images/dndCopy.png | Bin 0 -> 814 bytes includes/js/dojo/resources/images/dndMove.png | Bin 0 -> 785 bytes includes/js/dojo/resources/images/dndNoCopy.png | Bin 0 -> 756 bytes includes/js/dojo/resources/images/dndNoMove.png | Bin 0 -> 750 bytes includes/js/dojo/rpc/JsonService.js | 83 + includes/js/dojo/rpc/JsonpService.js | 65 + includes/js/dojo/rpc/RpcService.js | 172 + includes/js/dojo/string.js | 84 + includes/js/dojo/tests.js | 12 + includes/js/dojo/tests/AdapterRegistry.js | 75 + includes/js/dojo/tests/DeferredList.js | 206 + includes/js/dojo/tests/NodeList-fx.html | 150 + includes/js/dojo/tests/TODO | 11 + includes/js/dojo/tests/_base.js | 136 + includes/js/dojo/tests/_base/Color.js | 32 + includes/js/dojo/tests/_base/Deferred.js | 76 + includes/js/dojo/tests/_base/NodeList.html | 370 + .../js/dojo/tests/_base/_loader/addLoadEvents.html | 37 + .../js/dojo/tests/_base/_loader/afterOnLoad.html | 56 + includes/js/dojo/tests/_base/_loader/bootstrap.js | 86 + includes/js/dojo/tests/_base/_loader/getText.txt | 1 + .../js/dojo/tests/_base/_loader/hostenv_browser.js | 15 + .../js/dojo/tests/_base/_loader/hostenv_rhino.js | 17 + .../tests/_base/_loader/hostenv_spidermonkey.js | 15 + includes/js/dojo/tests/_base/_loader/loader.js | 52 + .../js/dojo/tests/_base/_loader/scope/scope04.html | 80 + .../tests/_base/_loader/scope/scopeContained.html | 71 + .../_base/_loader/scope/scopeContainedXd.html | 84 + .../tests/_base/_loader/scope/scopeDjConfig.html | 64 + .../tests/_base/_loader/scope/scopeSingle.html | 62 + .../tests/_base/_loader/scope/scopeSingleDaac.html | 63 + includes/js/dojo/tests/_base/array.js | 301 + includes/js/dojo/tests/_base/connect.js | 225 + includes/js/dojo/tests/_base/declare.js | 197 + includes/js/dojo/tests/_base/fx.html | 342 + includes/js/dojo/tests/_base/fx.js | 8 + includes/js/dojo/tests/_base/fx_delay.html | 22 + includes/js/dojo/tests/_base/html.html | 556 ++ includes/js/dojo/tests/_base/html.js | 12 + includes/js/dojo/tests/_base/html_box.html | 207 + includes/js/dojo/tests/_base/html_box_quirks.html | 205 + includes/js/dojo/tests/_base/html_quirks.html | 322 + includes/js/dojo/tests/_base/html_rtl.html | 110 + includes/js/dojo/tests/_base/json.js | 37 + includes/js/dojo/tests/_base/lang.js | 180 + includes/js/dojo/tests/_base/query.html | 154 + includes/js/dojo/tests/_base/query.js | 9 + includes/js/dojo/tests/_base/timeout.php | 7 + includes/js/dojo/tests/_base/xhr.html | 404 + includes/js/dojo/tests/_base/xhr.js | 8 + includes/js/dojo/tests/_base/xhrDummyMethod.php | 7 + includes/js/dojo/tests/back-hash.js | 33 + includes/js/dojo/tests/back.html | 107 + includes/js/dojo/tests/back.js | 8 + includes/js/dojo/tests/behavior.html | 106 + includes/js/dojo/tests/behavior.js | 8 + includes/js/dojo/tests/cldr.js | 19 + includes/js/dojo/tests/colors.js | 48 + includes/js/dojo/tests/cookie.html | 84 + includes/js/dojo/tests/cookie.js | 8 + includes/js/dojo/tests/currency.js | 48 + includes/js/dojo/tests/data.js | 12 + includes/js/dojo/tests/data/ItemFileReadStore.js | 10 + includes/js/dojo/tests/data/ItemFileWriteStore.js | 1402 ++++ includes/js/dojo/tests/data/countries.json | 11 + .../dojo/tests/data/countries_commentFiltered.json | 12 + .../js/dojo/tests/data/countries_idcollision.json | 10 + .../js/dojo/tests/data/countries_references.json | 44 + .../js/dojo/tests/data/countries_withBoolean.json | 11 + .../js/dojo/tests/data/countries_withDates.json | 21 + .../js/dojo/tests/data/countries_withNull.json | 10 + .../js/dojo/tests/data/countries_withoutid.json | 10 + includes/js/dojo/tests/data/data_multitype.json | 18 + .../dojo/tests/data/geography_hierarchy_large.json | 44 + .../dojo/tests/data/geography_hierarchy_small.json | 19 + .../tests/data/readOnlyItemFileTestTemplates.js | 2260 ++++++ .../js/dojo/tests/data/reference_integrity.json | 27 + includes/js/dojo/tests/data/runTests.html | 9 + includes/js/dojo/tests/data/utils.js | 203 + includes/js/dojo/tests/date.js | 716 ++ includes/js/dojo/tests/date/locale.js | 398 + includes/js/dojo/tests/date/stamp.js | 94 + includes/js/dojo/tests/dnd/dndDefault.css | 52 + .../js/dojo/tests/dnd/dndDefault.css.commented.css | 69 + includes/js/dojo/tests/dnd/flickr_viewer.html | 168 + .../js/dojo/tests/dnd/test_box_constraints.html | 61 + includes/js/dojo/tests/dnd/test_container.html | 74 + .../js/dojo/tests/dnd/test_container_markup.html | 67 + .../js/dojo/tests/dnd/test_custom_constraints.html | 51 + includes/js/dojo/tests/dnd/test_dnd.html | 130 + includes/js/dojo/tests/dnd/test_dnd_handles.html | 65 + includes/js/dojo/tests/dnd/test_form.html | 103 + includes/js/dojo/tests/dnd/test_moveable.html | 106 + .../js/dojo/tests/dnd/test_moveable_markup.html | 83 + includes/js/dojo/tests/dnd/test_params.html | 61 + .../js/dojo/tests/dnd/test_parent_constraints.html | 53 + .../tests/dnd/test_parent_constraints_margins.html | 51 + includes/js/dojo/tests/dnd/test_selector.html | 80 + .../js/dojo/tests/dnd/test_selector_markup.html | 71 + .../js/dojo/tests/dnd/test_timed_moveable.html | 112 + includes/js/dojo/tests/fx.html | 310 + includes/js/dojo/tests/fx.js | 9 + includes/js/dojo/tests/i18n.js | 88 + includes/js/dojo/tests/io/iframe.html | 124 + includes/js/dojo/tests/io/iframe.js | 8 + includes/js/dojo/tests/io/iframeResponse.html | 8 + includes/js/dojo/tests/io/iframeResponse.js.html | 7 + includes/js/dojo/tests/io/iframeResponse.json.html | 7 + includes/js/dojo/tests/io/iframeResponse.text.html | 7 + includes/js/dojo/tests/io/iframeUploadTest.html | 50 + includes/js/dojo/tests/io/script.html | 101 + includes/js/dojo/tests/io/script.js | 8 + includes/js/dojo/tests/io/scriptJsonp.js | 57 + includes/js/dojo/tests/io/scriptSimple.js | 5 + includes/js/dojo/tests/io/scriptTimeout.html | 67 + includes/js/dojo/tests/io/upload.cgi | 60 + includes/js/dojo/tests/manualTests.html | 12 + includes/js/dojo/tests/manualTests.js | 45 + includes/js/dojo/tests/module.js | 29 + includes/js/dojo/tests/nls/ar/salutations.js | 1 + includes/js/dojo/tests/nls/cs/salutations.js | 1 + includes/js/dojo/tests/nls/de/salutations.js | 1 + includes/js/dojo/tests/nls/el/salutations.js | 1 + includes/js/dojo/tests/nls/en-au/salutations.js | 1 + .../js/dojo/tests/nls/en-us-hawaii/salutations.js | 1 + .../nls/en-us-new_york-brooklyn/salutations.js | 1 + .../js/dojo/tests/nls/en-us-texas/salutations.js | 1 + includes/js/dojo/tests/nls/es/salutations.js | 1 + includes/js/dojo/tests/nls/fa/salutations.js | 1 + includes/js/dojo/tests/nls/fr/salutations.js | 1 + includes/js/dojo/tests/nls/he/salutations.js | 1 + includes/js/dojo/tests/nls/hi/salutations.js | 1 + includes/js/dojo/tests/nls/it/salutations.js | 1 + includes/js/dojo/tests/nls/ja/salutations.js | 1 + includes/js/dojo/tests/nls/ko/salutations.js | 1 + includes/js/dojo/tests/nls/pl/salutations.js | 1 + includes/js/dojo/tests/nls/pt/salutations.js | 1 + includes/js/dojo/tests/nls/ru/salutations.js | 1 + includes/js/dojo/tests/nls/salutations.js | 1 + includes/js/dojo/tests/nls/sw/salutations.js | 1 + includes/js/dojo/tests/nls/th/salutations.js | 1 + includes/js/dojo/tests/nls/tr/salutations.js | 1 + includes/js/dojo/tests/nls/yi/salutations.js | 1 + includes/js/dojo/tests/nls/zh-cn/salutations.js | 1 + includes/js/dojo/tests/nls/zh-tw/salutations.js | 1 + includes/js/dojo/tests/number.js | 966 +++ includes/js/dojo/tests/parser.html | 241 + includes/js/dojo/tests/parser.js | 8 + .../js/dojo/tests/resources/ApplicationState.js | 28 + includes/js/dojo/tests/resources/JSON.php | 724 ++ includes/js/dojo/tests/resources/testClass.php | 20 + includes/js/dojo/tests/resources/testClass.smd | 40 + .../dojo/tests/resources/test_JsonRPCMediator.php | 43 + includes/js/dojo/tests/resources/test_css.html | 100 + includes/js/dojo/tests/resources/yahoo_smd_v1.smd | 268 + includes/js/dojo/tests/rpc.js | 151 + includes/js/dojo/tests/runTests.html | 9 + includes/js/dojo/tests/string.js | 31 + includes/js/dojo/tests/test_FirebugLite.html | 100 + includes/js/dojo/tests/test_FirebugLitePopup.html | 101 + includes/js/dojo/tests/test_fx.html | 107 + 325 files changed, 45968 insertions(+) create mode 100644 includes/js/dojo/AdapterRegistry.js create mode 100644 includes/js/dojo/DeferredList.js create mode 100644 includes/js/dojo/LICENSE create mode 100644 includes/js/dojo/NodeList-fx.js create mode 100644 includes/js/dojo/OpenAjax.js create mode 100644 includes/js/dojo/_base.js create mode 100644 includes/js/dojo/_base/Color.js create mode 100644 includes/js/dojo/_base/Deferred.js create mode 100644 includes/js/dojo/_base/NodeList.js create mode 100644 includes/js/dojo/_base/_loader/bootstrap.js create mode 100644 includes/js/dojo/_base/_loader/hostenv_browser.js create mode 100644 includes/js/dojo/_base/_loader/hostenv_rhino.js create mode 100644 includes/js/dojo/_base/_loader/hostenv_spidermonkey.js create mode 100644 includes/js/dojo/_base/_loader/loader.js create mode 100644 includes/js/dojo/_base/_loader/loader_debug.js create mode 100644 includes/js/dojo/_base/_loader/loader_xd.js create mode 100644 includes/js/dojo/_base/array.js create mode 100644 includes/js/dojo/_base/browser.js create mode 100644 includes/js/dojo/_base/connect.js create mode 100644 includes/js/dojo/_base/declare.js create mode 100644 includes/js/dojo/_base/event.js create mode 100644 includes/js/dojo/_base/fx.js create mode 100644 includes/js/dojo/_base/html.js create mode 100644 includes/js/dojo/_base/json.js create mode 100644 includes/js/dojo/_base/lang.js create mode 100644 includes/js/dojo/_base/query.js create mode 100644 includes/js/dojo/_base/window.js create mode 100644 includes/js/dojo/_base/xhr.js create mode 100644 includes/js/dojo/_firebug/LICENSE create mode 100644 includes/js/dojo/_firebug/errorIcon.png create mode 100644 includes/js/dojo/_firebug/firebug.css create mode 100644 includes/js/dojo/_firebug/firebug.css.commented.css create mode 100644 includes/js/dojo/_firebug/firebug.js create mode 100644 includes/js/dojo/_firebug/infoIcon.png create mode 100644 includes/js/dojo/_firebug/warningIcon.png create mode 100644 includes/js/dojo/back.js create mode 100644 includes/js/dojo/behavior.js create mode 100644 includes/js/dojo/build.txt create mode 100644 includes/js/dojo/cldr/LICENSE create mode 100644 includes/js/dojo/cldr/README create mode 100644 includes/js/dojo/cldr/monetary.js create mode 100644 includes/js/dojo/cldr/nls/currency.js create mode 100644 includes/js/dojo/cldr/nls/de-de/number.js create mode 100644 includes/js/dojo/cldr/nls/de/currency.js create mode 100644 includes/js/dojo/cldr/nls/de/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/de/number.js create mode 100644 includes/js/dojo/cldr/nls/en-au/currency.js create mode 100644 includes/js/dojo/cldr/nls/en-au/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/en-au/number.js create mode 100644 includes/js/dojo/cldr/nls/en-ca/currency.js create mode 100644 includes/js/dojo/cldr/nls/en-ca/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/en-gb/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/en-gb/number.js create mode 100644 includes/js/dojo/cldr/nls/en-us/currency.js create mode 100644 includes/js/dojo/cldr/nls/en-us/number.js create mode 100644 includes/js/dojo/cldr/nls/en/currency.js create mode 100644 includes/js/dojo/cldr/nls/en/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/en/number.js create mode 100644 includes/js/dojo/cldr/nls/es-es/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/es-es/number.js create mode 100644 includes/js/dojo/cldr/nls/es/currency.js create mode 100644 includes/js/dojo/cldr/nls/es/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/es/number.js create mode 100644 includes/js/dojo/cldr/nls/fr/currency.js create mode 100644 includes/js/dojo/cldr/nls/fr/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/fr/number.js create mode 100644 includes/js/dojo/cldr/nls/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/it-it/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/it/currency.js create mode 100644 includes/js/dojo/cldr/nls/it/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/it/number.js create mode 100644 includes/js/dojo/cldr/nls/ja-jp/number.js create mode 100644 includes/js/dojo/cldr/nls/ja/currency.js create mode 100644 includes/js/dojo/cldr/nls/ja/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/ja/number.js create mode 100644 includes/js/dojo/cldr/nls/ko-kr/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/ko-kr/number.js create mode 100644 includes/js/dojo/cldr/nls/ko/currency.js create mode 100644 includes/js/dojo/cldr/nls/ko/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/ko/number.js create mode 100644 includes/js/dojo/cldr/nls/number.js create mode 100644 includes/js/dojo/cldr/nls/pt-br/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/pt/currency.js create mode 100644 includes/js/dojo/cldr/nls/pt/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/pt/number.js create mode 100644 includes/js/dojo/cldr/nls/zh-cn/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/zh-cn/number.js create mode 100644 includes/js/dojo/cldr/nls/zh-tw/currency.js create mode 100644 includes/js/dojo/cldr/nls/zh-tw/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/zh-tw/number.js create mode 100644 includes/js/dojo/cldr/nls/zh/currency.js create mode 100644 includes/js/dojo/cldr/nls/zh/gregorian.js create mode 100644 includes/js/dojo/cldr/nls/zh/number.js create mode 100644 includes/js/dojo/cldr/supplemental.js create mode 100644 includes/js/dojo/colors.js create mode 100644 includes/js/dojo/cookie.js create mode 100644 includes/js/dojo/currency.js create mode 100644 includes/js/dojo/data/ItemFileReadStore.js create mode 100644 includes/js/dojo/data/ItemFileWriteStore.js create mode 100644 includes/js/dojo/data/api/Identity.js create mode 100644 includes/js/dojo/data/api/Notification.js create mode 100644 includes/js/dojo/data/api/Read.js create mode 100644 includes/js/dojo/data/api/Request.js create mode 100644 includes/js/dojo/data/api/Write.js create mode 100644 includes/js/dojo/data/util/filter.js create mode 100644 includes/js/dojo/data/util/simpleFetch.js create mode 100644 includes/js/dojo/data/util/sorter.js create mode 100644 includes/js/dojo/date.js create mode 100644 includes/js/dojo/date/locale.js create mode 100644 includes/js/dojo/date/stamp.js create mode 100644 includes/js/dojo/dnd/Avatar.js create mode 100644 includes/js/dojo/dnd/Container.js create mode 100644 includes/js/dojo/dnd/Manager.js create mode 100644 includes/js/dojo/dnd/Moveable.js create mode 100644 includes/js/dojo/dnd/Mover.js create mode 100644 includes/js/dojo/dnd/Selector.js create mode 100644 includes/js/dojo/dnd/Source.js create mode 100644 includes/js/dojo/dnd/TimedMoveable.js create mode 100644 includes/js/dojo/dnd/autoscroll.js create mode 100644 includes/js/dojo/dnd/common.js create mode 100644 includes/js/dojo/dnd/move.js create mode 100644 includes/js/dojo/dojo.js create mode 100644 includes/js/dojo/dojo.js.uncompressed.js create mode 100644 includes/js/dojo/fx.js create mode 100644 includes/js/dojo/i18n.js create mode 100644 includes/js/dojo/io/iframe.js create mode 100644 includes/js/dojo/io/script.js create mode 100644 includes/js/dojo/jaxer.js create mode 100644 includes/js/dojo/nls/ar/colors.js create mode 100644 includes/js/dojo/nls/colors.js create mode 100644 includes/js/dojo/nls/cs/colors.js create mode 100644 includes/js/dojo/nls/da/colors.js create mode 100644 includes/js/dojo/nls/de/colors.js create mode 100644 includes/js/dojo/nls/el/colors.js create mode 100644 includes/js/dojo/nls/es/colors.js create mode 100644 includes/js/dojo/nls/fi/colors.js create mode 100644 includes/js/dojo/nls/fr/colors.js create mode 100644 includes/js/dojo/nls/he/colors.js create mode 100644 includes/js/dojo/nls/hu/colors.js create mode 100644 includes/js/dojo/nls/it/colors.js create mode 100644 includes/js/dojo/nls/ja/colors.js create mode 100644 includes/js/dojo/nls/ko/colors.js create mode 100644 includes/js/dojo/nls/nb/colors.js create mode 100644 includes/js/dojo/nls/nl/colors.js create mode 100644 includes/js/dojo/nls/pl/colors.js create mode 100644 includes/js/dojo/nls/pt-pt/colors.js create mode 100644 includes/js/dojo/nls/pt/colors.js create mode 100644 includes/js/dojo/nls/ru/colors.js create mode 100644 includes/js/dojo/nls/sv/colors.js create mode 100644 includes/js/dojo/nls/tr/colors.js create mode 100644 includes/js/dojo/nls/zh-tw/colors.js create mode 100644 includes/js/dojo/nls/zh/colors.js create mode 100644 includes/js/dojo/number.js create mode 100644 includes/js/dojo/parser.js create mode 100644 includes/js/dojo/regexp.js create mode 100644 includes/js/dojo/resources/LICENSE create mode 100644 includes/js/dojo/resources/_modules.js create mode 100644 includes/js/dojo/resources/blank.gif create mode 100644 includes/js/dojo/resources/blank.html create mode 100644 includes/js/dojo/resources/dnd.css create mode 100644 includes/js/dojo/resources/dnd.css.commented.css create mode 100644 includes/js/dojo/resources/dojo.css create mode 100644 includes/js/dojo/resources/dojo.css.commented.css create mode 100644 includes/js/dojo/resources/iframe_history.html create mode 100644 includes/js/dojo/resources/images/dndCopy.png create mode 100644 includes/js/dojo/resources/images/dndMove.png create mode 100644 includes/js/dojo/resources/images/dndNoCopy.png create mode 100644 includes/js/dojo/resources/images/dndNoMove.png create mode 100644 includes/js/dojo/rpc/JsonService.js create mode 100644 includes/js/dojo/rpc/JsonpService.js create mode 100644 includes/js/dojo/rpc/RpcService.js create mode 100644 includes/js/dojo/string.js create mode 100644 includes/js/dojo/tests.js create mode 100644 includes/js/dojo/tests/AdapterRegistry.js create mode 100644 includes/js/dojo/tests/DeferredList.js create mode 100644 includes/js/dojo/tests/NodeList-fx.html create mode 100644 includes/js/dojo/tests/TODO create mode 100644 includes/js/dojo/tests/_base.js create mode 100644 includes/js/dojo/tests/_base/Color.js create mode 100644 includes/js/dojo/tests/_base/Deferred.js create mode 100644 includes/js/dojo/tests/_base/NodeList.html create mode 100644 includes/js/dojo/tests/_base/_loader/addLoadEvents.html create mode 100644 includes/js/dojo/tests/_base/_loader/afterOnLoad.html create mode 100644 includes/js/dojo/tests/_base/_loader/bootstrap.js create mode 100644 includes/js/dojo/tests/_base/_loader/getText.txt create mode 100644 includes/js/dojo/tests/_base/_loader/hostenv_browser.js create mode 100644 includes/js/dojo/tests/_base/_loader/hostenv_rhino.js create mode 100644 includes/js/dojo/tests/_base/_loader/hostenv_spidermonkey.js create mode 100644 includes/js/dojo/tests/_base/_loader/loader.js create mode 100644 includes/js/dojo/tests/_base/_loader/scope/scope04.html create mode 100644 includes/js/dojo/tests/_base/_loader/scope/scopeContained.html create mode 100644 includes/js/dojo/tests/_base/_loader/scope/scopeContainedXd.html create mode 100644 includes/js/dojo/tests/_base/_loader/scope/scopeDjConfig.html create mode 100644 includes/js/dojo/tests/_base/_loader/scope/scopeSingle.html create mode 100644 includes/js/dojo/tests/_base/_loader/scope/scopeSingleDaac.html create mode 100644 includes/js/dojo/tests/_base/array.js create mode 100644 includes/js/dojo/tests/_base/connect.js create mode 100644 includes/js/dojo/tests/_base/declare.js create mode 100644 includes/js/dojo/tests/_base/fx.html create mode 100644 includes/js/dojo/tests/_base/fx.js create mode 100644 includes/js/dojo/tests/_base/fx_delay.html create mode 100644 includes/js/dojo/tests/_base/html.html create mode 100644 includes/js/dojo/tests/_base/html.js create mode 100644 includes/js/dojo/tests/_base/html_box.html create mode 100644 includes/js/dojo/tests/_base/html_box_quirks.html create mode 100644 includes/js/dojo/tests/_base/html_quirks.html create mode 100644 includes/js/dojo/tests/_base/html_rtl.html create mode 100644 includes/js/dojo/tests/_base/json.js create mode 100644 includes/js/dojo/tests/_base/lang.js create mode 100644 includes/js/dojo/tests/_base/query.html create mode 100644 includes/js/dojo/tests/_base/query.js create mode 100644 includes/js/dojo/tests/_base/timeout.php create mode 100644 includes/js/dojo/tests/_base/xhr.html create mode 100644 includes/js/dojo/tests/_base/xhr.js create mode 100644 includes/js/dojo/tests/_base/xhrDummyMethod.php create mode 100644 includes/js/dojo/tests/back-hash.js create mode 100644 includes/js/dojo/tests/back.html create mode 100644 includes/js/dojo/tests/back.js create mode 100644 includes/js/dojo/tests/behavior.html create mode 100644 includes/js/dojo/tests/behavior.js create mode 100644 includes/js/dojo/tests/cldr.js create mode 100644 includes/js/dojo/tests/colors.js create mode 100644 includes/js/dojo/tests/cookie.html create mode 100644 includes/js/dojo/tests/cookie.js create mode 100644 includes/js/dojo/tests/currency.js create mode 100644 includes/js/dojo/tests/data.js create mode 100644 includes/js/dojo/tests/data/ItemFileReadStore.js create mode 100644 includes/js/dojo/tests/data/ItemFileWriteStore.js create mode 100644 includes/js/dojo/tests/data/countries.json create mode 100644 includes/js/dojo/tests/data/countries_commentFiltered.json create mode 100644 includes/js/dojo/tests/data/countries_idcollision.json create mode 100644 includes/js/dojo/tests/data/countries_references.json create mode 100644 includes/js/dojo/tests/data/countries_withBoolean.json create mode 100644 includes/js/dojo/tests/data/countries_withDates.json create mode 100644 includes/js/dojo/tests/data/countries_withNull.json create mode 100644 includes/js/dojo/tests/data/countries_withoutid.json create mode 100644 includes/js/dojo/tests/data/data_multitype.json create mode 100644 includes/js/dojo/tests/data/geography_hierarchy_large.json create mode 100644 includes/js/dojo/tests/data/geography_hierarchy_small.json create mode 100644 includes/js/dojo/tests/data/readOnlyItemFileTestTemplates.js create mode 100644 includes/js/dojo/tests/data/reference_integrity.json create mode 100644 includes/js/dojo/tests/data/runTests.html create mode 100644 includes/js/dojo/tests/data/utils.js create mode 100644 includes/js/dojo/tests/date.js create mode 100644 includes/js/dojo/tests/date/locale.js create mode 100644 includes/js/dojo/tests/date/stamp.js create mode 100644 includes/js/dojo/tests/dnd/dndDefault.css create mode 100644 includes/js/dojo/tests/dnd/dndDefault.css.commented.css create mode 100644 includes/js/dojo/tests/dnd/flickr_viewer.html create mode 100644 includes/js/dojo/tests/dnd/test_box_constraints.html create mode 100644 includes/js/dojo/tests/dnd/test_container.html create mode 100644 includes/js/dojo/tests/dnd/test_container_markup.html create mode 100644 includes/js/dojo/tests/dnd/test_custom_constraints.html create mode 100644 includes/js/dojo/tests/dnd/test_dnd.html create mode 100644 includes/js/dojo/tests/dnd/test_dnd_handles.html create mode 100644 includes/js/dojo/tests/dnd/test_form.html create mode 100644 includes/js/dojo/tests/dnd/test_moveable.html create mode 100644 includes/js/dojo/tests/dnd/test_moveable_markup.html create mode 100644 includes/js/dojo/tests/dnd/test_params.html create mode 100644 includes/js/dojo/tests/dnd/test_parent_constraints.html create mode 100644 includes/js/dojo/tests/dnd/test_parent_constraints_margins.html create mode 100644 includes/js/dojo/tests/dnd/test_selector.html create mode 100644 includes/js/dojo/tests/dnd/test_selector_markup.html create mode 100644 includes/js/dojo/tests/dnd/test_timed_moveable.html create mode 100644 includes/js/dojo/tests/fx.html create mode 100644 includes/js/dojo/tests/fx.js create mode 100644 includes/js/dojo/tests/i18n.js create mode 100644 includes/js/dojo/tests/io/iframe.html create mode 100644 includes/js/dojo/tests/io/iframe.js create mode 100644 includes/js/dojo/tests/io/iframeResponse.html create mode 100644 includes/js/dojo/tests/io/iframeResponse.js.html create mode 100644 includes/js/dojo/tests/io/iframeResponse.json.html create mode 100644 includes/js/dojo/tests/io/iframeResponse.text.html create mode 100644 includes/js/dojo/tests/io/iframeUploadTest.html create mode 100644 includes/js/dojo/tests/io/script.html create mode 100644 includes/js/dojo/tests/io/script.js create mode 100644 includes/js/dojo/tests/io/scriptJsonp.js create mode 100644 includes/js/dojo/tests/io/scriptSimple.js create mode 100644 includes/js/dojo/tests/io/scriptTimeout.html create mode 100644 includes/js/dojo/tests/io/upload.cgi create mode 100644 includes/js/dojo/tests/manualTests.html create mode 100644 includes/js/dojo/tests/manualTests.js create mode 100644 includes/js/dojo/tests/module.js create mode 100644 includes/js/dojo/tests/nls/ar/salutations.js create mode 100644 includes/js/dojo/tests/nls/cs/salutations.js create mode 100644 includes/js/dojo/tests/nls/de/salutations.js create mode 100644 includes/js/dojo/tests/nls/el/salutations.js create mode 100644 includes/js/dojo/tests/nls/en-au/salutations.js create mode 100644 includes/js/dojo/tests/nls/en-us-hawaii/salutations.js create mode 100644 includes/js/dojo/tests/nls/en-us-new_york-brooklyn/salutations.js create mode 100644 includes/js/dojo/tests/nls/en-us-texas/salutations.js create mode 100644 includes/js/dojo/tests/nls/es/salutations.js create mode 100644 includes/js/dojo/tests/nls/fa/salutations.js create mode 100644 includes/js/dojo/tests/nls/fr/salutations.js create mode 100644 includes/js/dojo/tests/nls/he/salutations.js create mode 100644 includes/js/dojo/tests/nls/hi/salutations.js create mode 100644 includes/js/dojo/tests/nls/it/salutations.js create mode 100644 includes/js/dojo/tests/nls/ja/salutations.js create mode 100644 includes/js/dojo/tests/nls/ko/salutations.js create mode 100644 includes/js/dojo/tests/nls/pl/salutations.js create mode 100644 includes/js/dojo/tests/nls/pt/salutations.js create mode 100644 includes/js/dojo/tests/nls/ru/salutations.js create mode 100644 includes/js/dojo/tests/nls/salutations.js create mode 100644 includes/js/dojo/tests/nls/sw/salutations.js create mode 100644 includes/js/dojo/tests/nls/th/salutations.js create mode 100644 includes/js/dojo/tests/nls/tr/salutations.js create mode 100644 includes/js/dojo/tests/nls/yi/salutations.js create mode 100644 includes/js/dojo/tests/nls/zh-cn/salutations.js create mode 100644 includes/js/dojo/tests/nls/zh-tw/salutations.js create mode 100644 includes/js/dojo/tests/number.js create mode 100644 includes/js/dojo/tests/parser.html create mode 100644 includes/js/dojo/tests/parser.js create mode 100644 includes/js/dojo/tests/resources/ApplicationState.js create mode 100644 includes/js/dojo/tests/resources/JSON.php create mode 100644 includes/js/dojo/tests/resources/testClass.php create mode 100644 includes/js/dojo/tests/resources/testClass.smd create mode 100644 includes/js/dojo/tests/resources/test_JsonRPCMediator.php create mode 100644 includes/js/dojo/tests/resources/test_css.html create mode 100644 includes/js/dojo/tests/resources/yahoo_smd_v1.smd create mode 100644 includes/js/dojo/tests/rpc.js create mode 100644 includes/js/dojo/tests/runTests.html create mode 100644 includes/js/dojo/tests/string.js create mode 100644 includes/js/dojo/tests/test_FirebugLite.html create mode 100644 includes/js/dojo/tests/test_FirebugLitePopup.html create mode 100644 includes/js/dojo/tests/test_fx.html (limited to 'includes/js/dojo') 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 . + // 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: + // + // 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: + // + // 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: + // + // 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: + // + // 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: + // + // 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("

NOTE:

", "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 + // ` + // | + 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 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: + // + + 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: + // + 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: + // + + // 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 + // 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: + // + // 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: + // + // 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 + // 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; i90)&&(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 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= 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=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 + // 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: + // | + // | + // |

+ // example: + // search the entire document for elements with the classes "foo" *and* "bar": + // | dojo.query(".foo.bar"); + // these elements will match: + // | + // while these will not: + // | + // |

+ // example: + // find `` elements which are descendants of paragraphs and + // which have a "highlighted" class: + // | dojo.query("p span.highlighted"); + // the innermost span in this fragment matches: + // |

+ // | ... + // | ... + // | + // |

+ // 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: + // + // |
+ // | + // | + // | + // | + // |
+ // + // 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 Binary files /dev/null and b/includes/js/dojo/_firebug/errorIcon.png 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 = ['']; + for(var i = 0; i < pairs.length; ++i){ + var name = pairs[i][0], value = pairs[i][1]; + + html.push('', + '', ''); + } + html.push('
', + escapeHTML(name), ''); + appendObject(value, html); + html.push('
'); + + 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= 'Firebug Lite\n' + + '\n' + + '
' + + ''; + + 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 ? "" : ' Close'; + consoleFrame.innerHTML = + '
' + + ' Clear' + + ' ' + + closeStr + + ' ' + + '
' + + '' + + '
' + + ''; + + + 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 = ''+getObjectAbbr(object)+''; + + 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" + printObject( this.obj ) + ""; + })); + } + } + + 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 "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + 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('', escapeHTML(objectToString(object)), ''); + } + + function appendString(object, html){ + html.push('"', escapeHTML(objectToString(object)), + '"'); + } + + function appendInteger(object, html){ + html.push('', escapeHTML(objectToString(object)), ''); + } + + function appendFloat(object, html){ + html.push('', escapeHTML(objectToString(object)), ''); + } + + function appendFunction(object, html){ + html.push('', getObjectAbbr(object), ''); + } + + 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('', m ? m[1] : text, ''); + } + + function appendSelector(object, html){ + html.push(''); + + html.push('', escapeHTML(object.nodeName.toLowerCase()), ''); + if(object.id){ + html.push('#', escapeHTML(object.id), ''); + } + if(object.className){ + html.push('.', escapeHTML(object.className), ''); + } + + html.push(''); + } + + function appendNode(node, html){ + if(node.nodeType == 1){ + html.push( + '
', + '<', node.nodeName.toLowerCase(), ''); + + for(var i = 0; i < node.attributes.length; ++i){ + var attr = node.attributes[i]; + if(!attr.specified){ continue; } + + html.push(' ', attr.nodeName.toLowerCase(), + '="', escapeHTML(attr.nodeValue), + '"'); + } + + if(node.firstChild){ + html.push('>
'); + + for(var child = node.firstChild; child; child = child.nextSibling){ + appendNode(child, html); + } + + html.push('
</', + node.nodeName.toLowerCase(), '>
'); + }else{ + html.push('/>'); + } + }else if (node.nodeType == 3){ + html.push('
', escapeHTML(node.nodeValue), + '
'); + } + } + + // *************************************************************************** + + 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 = [ + '', msg, '', + '' + ]; + + 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
... otherwise we'd need a 
+ 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 Binary files /dev/null and b/includes/js/dojo/_firebug/infoIcon.png differ diff --git a/includes/js/dojo/_firebug/warningIcon.png b/includes/js/dojo/_firebug/warningIcon.png new file mode 100644 index 0000000..de51084 Binary files /dev/null and b/includes/js/dojo/_firebug/warningIcon.png 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 + // | + 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('' + + '' + ); + } + + // 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 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. + // 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: + // + + 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: + // + 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: + // + + // 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 + // 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: + // + // 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: + // + // 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 + // 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: + // + // 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: + // + // 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: + // + // 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: + // + // 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: + // + // 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("

NOTE:

", "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= 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=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 + // 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: + // | + // | + // |

+ // example: + // search the entire document for elements with the classes "foo" *and* "bar": + // | dojo.query(".foo.bar"); + // these elements will match: + // | + // while these will not: + // | + // |

+ // example: + // find `` elements which are descendants of paragraphs and + // which have a "highlighted" class: + // | dojo.query("p span.highlighted"); + // the innermost span in this fragment matches: + // |

+ // | ... + // | ... + // | + // |

+ // 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: + // + // |
+ // | + // | + // | + // | + // |
+ // + // 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 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