summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2011-03-04 19:02:28 +0300
committerAndrew Dolgov <[email protected]>2011-03-04 19:02:59 +0300
commita089699c8915636ba4f158d77dba9b012bc93208 (patch)
treeb2d7d051f1f55d44a6be07d3ee137e5a7ccfcefb
parentcfad9259a6feacfa8194b1312770ae6db1ecce50 (diff)
build custom layer of Dojo to speed up loading of tt-rss (refs #293)
-rw-r--r--lib/dojo-src/.gitignore5
-rw-r--r--lib/dojo-src/profile.js41
-rwxr-xr-xlib/dojo-src/rebuild-dojo.sh23
-rw-r--r--lib/dojo/AdapterRegistry.js125
-rw-r--r--lib/dojo/DeferredList.js119
-rw-r--r--lib/dojo/NodeList-fx.js239
-rw-r--r--lib/dojo/NodeList-html.js48
-rw-r--r--lib/dojo/NodeList-manipulate.js921
-rw-r--r--lib/dojo/NodeList-traverse.js628
-rw-r--r--lib/dojo/OpenAjax.js338
-rw-r--r--lib/dojo/Stateful.js180
-rw-r--r--lib/dojo/_base.js7
-rw-r--r--lib/dojo/_base/Color.js303
-rw-r--r--lib/dojo/_base/Deferred.js446
-rw-r--r--lib/dojo/_base/NodeList.js1222
-rw-r--r--lib/dojo/_base/_loader/bootstrap.js604
-rw-r--r--lib/dojo/_base/_loader/hostenv_browser.js684
-rw-r--r--lib/dojo/_base/_loader/hostenv_ff_ext.js491
-rw-r--r--lib/dojo/_base/_loader/hostenv_rhino.js313
-rw-r--r--lib/dojo/_base/_loader/hostenv_spidermonkey.js101
-rw-r--r--lib/dojo/_base/_loader/loader.js1084
-rw-r--r--lib/dojo/_base/_loader/loader_debug.js123
-rw-r--r--lib/dojo/_base/_loader/loader_xd.js1136
-rw-r--r--lib/dojo/_base/array.js317
-rw-r--r--lib/dojo/_base/browser.js15
-rw-r--r--lib/dojo/_base/connect.js359
-rw-r--r--lib/dojo/_base/declare.js1445
-rw-r--r--lib/dojo/_base/event.js978
-rw-r--r--lib/dojo/_base/fx.js941
-rw-r--r--lib/dojo/_base/html.js2549
-rw-r--r--lib/dojo/_base/json.js211
-rw-r--r--lib/dojo/_base/lang.js518
-rw-r--r--lib/dojo/_base/query-sizzle.js1445
-rw-r--r--lib/dojo/_base/query.js2301
-rw-r--r--lib/dojo/_base/window.js129
-rw-r--r--lib/dojo/_base/xhr.js1348
-rw-r--r--lib/dojo/_firebug/firebug.css5
-rw-r--r--lib/dojo/_firebug/firebug.js2112
-rw-r--r--lib/dojo/back.js648
-rw-r--r--lib/dojo/behavior.js324
-rw-r--r--lib/dojo/build.txt433
-rw-r--r--lib/dojo/cache.js159
-rw-r--r--lib/dojo/cldr/monetary.js40
-rw-r--r--lib/dojo/cldr/supplemental.js100
-rw-r--r--lib/dojo/colors.js288
-rw-r--r--lib/dojo/cookie.js126
-rw-r--r--lib/dojo/currency.js149
-rw-r--r--lib/dojo/data/ItemFileReadStore.js1483
-rw-r--r--lib/dojo/data/ItemFileWriteStore.js1308
-rw-r--r--lib/dojo/data/api/Identity.js120
-rw-r--r--lib/dojo/data/api/Notification.js127
-rw-r--r--lib/dojo/data/api/Read.js548
-rw-r--r--lib/dojo/data/api/Request.js35
-rw-r--r--lib/dojo/data/api/Write.js252
-rw-r--r--lib/dojo/data/util/filter.js108
-rw-r--r--lib/dojo/data/util/simpleFetch.js139
-rw-r--r--lib/dojo/data/util/sorter.js146
-rw-r--r--lib/dojo/date.js530
-rw-r--r--lib/dojo/date/locale.js1074
-rw-r--r--lib/dojo/date/stamp.js208
-rw-r--r--lib/dojo/dnd/Avatar.js160
-rw-r--r--lib/dojo/dnd/Container.js644
-rw-r--r--lib/dojo/dnd/Manager.js322
-rw-r--r--lib/dojo/dnd/Moveable.js235
-rw-r--r--lib/dojo/dnd/Mover.js160
-rw-r--r--lib/dojo/dnd/Selector.js553
-rw-r--r--lib/dojo/dnd/Source.js825
-rw-r--r--lib/dojo/dnd/TimedMoveable.js97
-rw-r--r--lib/dojo/dnd/autoscroll.js191
-rw-r--r--lib/dojo/dnd/common.js43
-rw-r--r--lib/dojo/dnd/move.js351
-rw-r--r--lib/dojo/fx.js634
-rw-r--r--lib/dojo/fx/Toggler.js119
-rw-r--r--lib/dojo/fx/easing.js434
-rw-r--r--lib/dojo/gears.js88
-rw-r--r--lib/dojo/hash.js354
-rw-r--r--lib/dojo/html.js456
-rw-r--r--lib/dojo/i18n.js395
-rw-r--r--lib/dojo/io/iframe.js654
-rw-r--r--lib/dojo/io/script.js356
-rw-r--r--lib/dojo/jaxer.js21
-rw-r--r--lib/dojo/nls/tt-rss-layer_ROOT.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_ar.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_ca.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_cs.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_da.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_de-de.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_de.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_el.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_en-gb.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_en-us.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_en.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_es-es.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_es.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_fi-fi.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_fi.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_fr-fr.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_fr.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_he-il.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_he.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_hu.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_it-it.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_it.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_ja-jp.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_ja.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_ko-kr.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_ko.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_nb.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_nl-nl.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_nl.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_pl.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_pt-br.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_pt-pt.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_pt.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_ru.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_sk.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_sl.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_sv.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_th.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_tr.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_xx.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_zh-cn.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_zh-tw.js1
-rw-r--r--lib/dojo/nls/tt-rss-layer_zh.js1
-rw-r--r--lib/dojo/number.js849
-rw-r--r--lib/dojo/parser.js698
-rw-r--r--lib/dojo/regexp.js83
-rw-r--r--lib/dojo/resources/_modules.js36
-rw-r--r--lib/dojo/resources/dnd.css4
-rw-r--r--lib/dojo/resources/dojo.css98
-rw-r--r--lib/dojo/robot.js244
-rw-r--r--lib/dojo/robotx.js180
-rw-r--r--lib/dojo/rpc/JsonService.js107
-rw-r--r--lib/dojo/rpc/JsonpService.js80
-rw-r--r--lib/dojo/rpc/RpcService.js248
-rw-r--r--lib/dojo/string.js193
-rw-r--r--lib/dojo/tt-rss-layer.js14
-rw-r--r--lib/dojo/tt-rss-layer.js.uncompressed.js26844
-rw-r--r--lib/dojo/uacss.js80
-rw-r--r--lib/dojo/window.js232
-rw-r--r--prefs.js6
-rw-r--r--prefs.php4
-rw-r--r--tt-rss.js8
-rw-r--r--tt-rss.php5
144 files changed, 55604 insertions, 13743 deletions
diff --git a/lib/dojo-src/.gitignore b/lib/dojo-src/.gitignore
new file mode 100644
index 000000000..54650a469
--- /dev/null
+++ b/lib/dojo-src/.gitignore
@@ -0,0 +1,5 @@
+dijit
+dojo
+dojox
+release
+util
diff --git a/lib/dojo-src/profile.js b/lib/dojo-src/profile.js
new file mode 100644
index 000000000..572b94230
--- /dev/null
+++ b/lib/dojo-src/profile.js
@@ -0,0 +1,41 @@
+dependencies = {
+ layers: [
+ {
+ name: "tt-rss-layer.js",
+ resourceName: "tt-rss-layer",
+ dependencies: [
+ "dojo.parser",
+ "dijit.dijit",
+ "dojo.NodeList-fx",
+ "dijit.ColorPalette",
+ "dijit.Dialog",
+ "dijit.form.Button",
+ "dijit.form.CheckBox",
+ "dijit.form.DropDownButton",
+ "dijit.form.FilteringSelect",
+ "dijit.form.Form",
+ "dijit.form.RadioButton",
+ "dijit.form.Select",
+ "dijit.form.SimpleTextarea",
+ "dijit.form.TextBox",
+ "dijit.form.ValidationTextBox",
+ "dijit.InlineEditBox",
+ "dijit.layout.AccordionContainer",
+ "dijit.layout.BorderContainer",
+ "dijit.layout.ContentPane",
+ "dijit.layout.TabContainer",
+ "dijit.Menu",
+ "dijit.ProgressBar",
+ "dijit.ProgressBar",
+ "dijit.Toolbar",
+ "dijit.Tree",
+ "dijit.tree.dndSource",
+ "dojo.data.ItemFileWriteStore",
+ "dojo.parser",
+ ]
+ }
+ ],
+ prefixes: [
+ [ "dijit", "../dijit" ]
+ ]
+}
diff --git a/lib/dojo-src/rebuild-dojo.sh b/lib/dojo-src/rebuild-dojo.sh
new file mode 100755
index 000000000..708627537
--- /dev/null
+++ b/lib/dojo-src/rebuild-dojo.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# This script rebuilds customized layer of Dojo for tt-rss
+# Place unpacked Dojo source release in this directory and run this script.
+# It will automatically replace previous build of Dojo in ../dojo
+
+# Dojo requires Java runtime to build. Further information on rebuilding Dojo
+# is available here: http://dojotoolkit.org/reference-guide/build/index.html
+
+if [ -d util/buildscripts/ ]; then
+ pushd util/buildscripts
+ ./build.sh profileFile=../../profile.js action=clean,release version=1.5.0 releaseName=
+ popd
+
+ if [ -d release/dojo ]; then
+ rm -rf ../dojo
+ cp -r release/dojo ..
+ else
+ echo $0: ERROR: Dojo build seems to have failed.
+ fi
+else
+ echo $0: ERROR: Please unpack Dojo source release into current directory.
+fi
diff --git a/lib/dojo/AdapterRegistry.js b/lib/dojo/AdapterRegistry.js
index 1939cfa98..bb6a60f41 100644
--- a/lib/dojo/AdapterRegistry.js
+++ b/lib/dojo/AdapterRegistry.js
@@ -5,35 +5,102 @@
*/
-if(!dojo._hasResource["dojo.AdapterRegistry"]){
-dojo._hasResource["dojo.AdapterRegistry"]=true;
+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(_1){
-this.pairs=[];
-this.returnWrappers=_1||false;
-};
-dojo.extend(dojo.AdapterRegistry,{register:function(_2,_3,_4,_5,_6){
-this.pairs[((_6)?"unshift":"push")]([_2,_3,_4,_5]);
-},match:function(){
-for(var i=0;i<this.pairs.length;i++){
-var _7=this.pairs[i];
-if(_7[1].apply(this,arguments)){
-if((_7[3])||(this.returnWrappers)){
-return _7[2];
-}else{
-return _7[2].apply(this,arguments);
-}
-}
-}
-throw new Error("No match found");
-},unregister:function(_8){
-for(var i=0;i<this.pairs.length;i++){
-var _9=this.pairs[i];
-if(_9[0]==_8){
-this.pairs.splice(i,1);
-return true;
-}
+
+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
}
-return false;
-}});
+
+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/lib/dojo/DeferredList.js b/lib/dojo/DeferredList.js
index 6a1a1aae6..a8156aba2 100644
--- a/lib/dojo/DeferredList.js
+++ b/lib/dojo/DeferredList.js
@@ -5,54 +5,79 @@
*/
-if(!dojo._hasResource["dojo.DeferredList"]){
-dojo._hasResource["dojo.DeferredList"]=true;
+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.DeferredList=function(_1,_2,_3,_4,_5){
-var _6=[];
-dojo.Deferred.call(this);
-var _7=this;
-if(_1.length===0&&!_2){
-this.resolve([0,[]]);
-}
-var _8=0;
-dojo.forEach(_1,function(_9,i){
-_9.then(function(_a){
-if(_2){
-_7.resolve([i,_a]);
-}else{
-_b(true,_a);
-}
-},function(_c){
-if(_3){
-_7.reject(_c);
-}else{
-_b(false,_c);
-}
-if(_4){
-return null;
-}
-throw _c;
-});
-function _b(_d,_e){
-_6[i]=[_d,_e];
-_8++;
-if(_8===_1.length){
-_7.resolve(_6);
-}
+dojo.DeferredList = 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
+ var resultList = [];
+ dojo.Deferred.call(this);
+ var self = this;
+ if(list.length === 0 && !fireOnOneCallback){
+ this.resolve([0, []]);
+ }
+ var finished = 0;
+ dojo.forEach(list, function(item, i){
+ item.then(function(result){
+ if(fireOnOneCallback){
+ self.resolve([i, result]);
+ }else{
+ addResult(true, result);
+ }
+ },function(error){
+ if(fireOnOneErrback){
+ self.reject(error);
+ }else{
+ addResult(false, error);
+ }
+ if(consumeErrors){
+ return null;
+ }
+ throw error;
+ });
+ function addResult(succeeded, result){
+ resultList[i] = [succeeded, result];
+ finished++;
+ if(finished === list.length){
+ self.resolve(resultList);
+ }
+
+ }
+ });
};
-});
-};
-dojo.DeferredList.prototype=new dojo.Deferred();
-dojo.DeferredList.prototype.gatherResults=function(_f){
-var d=new dojo.DeferredList(_f,false,true,false);
-d.addCallback(function(_10){
-var ret=[];
-dojo.forEach(_10,function(_11){
-ret.push(_11[1]);
-});
-return ret;
-});
-return d;
+dojo.DeferredList.prototype = new dojo.Deferred();
+
+dojo.DeferredList.prototype.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/lib/dojo/NodeList-fx.js b/lib/dojo/NodeList-fx.js
index f08fdcab4..de2cc3255 100644
--- a/lib/dojo/NodeList-fx.js
+++ b/lib/dojo/NodeList-fx.js
@@ -5,37 +5,214 @@
*/
-if(!dojo._hasResource["dojo.NodeList-fx"]){
-dojo._hasResource["dojo.NodeList-fx"]=true;
+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.extend(dojo.NodeList,{_anim:function(_1,_2,_3){
-_3=_3||{};
-var a=dojo.fx.combine(this.map(function(_4){
-var _5={node:_4};
-dojo.mixin(_5,_3);
-return _1[_2](_5);
-}));
-return _3.auto?a.play()&&this:a;
-},wipeIn:function(_6){
-return this._anim(dojo.fx,"wipeIn",_6);
-},wipeOut:function(_7){
-return this._anim(dojo.fx,"wipeOut",_7);
-},slideTo:function(_8){
-return this._anim(dojo.fx,"slideTo",_8);
-},fadeIn:function(_9){
-return this._anim(dojo,"fadeIn",_9);
-},fadeOut:function(_a){
-return this._anim(dojo,"fadeOut",_a);
-},animateProperty:function(_b){
-return this._anim(dojo,"animateProperty",_b);
-},anim:function(_c,_d,_e,_f,_10){
-var _11=dojo.fx.combine(this.map(function(_12){
-return dojo.animateProperty({node:_12,properties:_c,duration:_d||350,easing:_e});
-}));
-if(_f){
-dojo.connect(_11,"onEnd",_f);
-}
-return _11.play(_10||0);
-}});
+
+/*=====
+dojo["NodeList-fx"] = {
+ // summary: Adds dojo.fx animation support to dojo.query()
+};
+=====*/
+
+dojo.extend(dojo.NodeList, {
+ _anim: function(obj, method, args){
+ args = args||{};
+ var a = dojo.fx.combine(
+ this.map(function(item){
+ var tmpArgs = { node: item };
+ dojo.mixin(tmpArgs, args);
+ return obj[method](tmpArgs);
+ })
+ );
+ return args.auto ? a.play() && this : a; // dojo.Animation|dojo.NodeList
+ },
+
+ wipeIn: function(args){
+ // summary:
+ // wipe in all elements of this NodeList via `dojo.fx.wipeIn`
+ //
+ // args: Object?
+ // Additional dojo.Animation arguments to mix into this set with the addition of
+ // an `auto` parameter.
+ //
+ // returns: dojo.Animation|dojo.NodeList
+ // A special args member `auto` can be passed to automatically play the animation.
+ // If args.auto is present, the original dojo.NodeList will be returned for further
+ // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed
+ //
+ // example:
+ // Fade in all tables with class "blah":
+ // | dojo.query("table.blah").wipeIn().play();
+ //
+ // example:
+ // Utilizing `auto` to get the NodeList back:
+ // | dojo.query(".titles").wipeIn({ auto:true }).onclick(someFunction);
+ //
+ return this._anim(dojo.fx, "wipeIn", args); // dojo.Animation|dojo.NodeList
+ },
+
+ wipeOut: function(args){
+ // summary:
+ // wipe out all elements of this NodeList via `dojo.fx.wipeOut`
+ //
+ // args: Object?
+ // Additional dojo.Animation arguments to mix into this set with the addition of
+ // an `auto` parameter.
+ //
+ // returns: dojo.Animation|dojo.NodeList
+ // A special args member `auto` can be passed to automatically play the animation.
+ // If args.auto is present, the original dojo.NodeList will be returned for further
+ // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed
+ //
+ // example:
+ // Wipe out all tables with class "blah":
+ // | dojo.query("table.blah").wipeOut().play();
+ return this._anim(dojo.fx, "wipeOut", args); // dojo.Animation|dojo.NodeList
+ },
+
+ slideTo: function(args){
+ // summary:
+ // slide all elements of the node list to the specified place via `dojo.fx.slideTo`
+ //
+ // args: Object?
+ // Additional dojo.Animation arguments to mix into this set with the addition of
+ // an `auto` parameter.
+ //
+ // returns: dojo.Animation|dojo.NodeList
+ // A special args member `auto` can be passed to automatically play the animation.
+ // If args.auto is present, the original dojo.NodeList will be returned for further
+ // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed
+ //
+ // 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|dojo.NodeList
+ },
+
+
+ fadeIn: function(args){
+ // summary:
+ // fade in all elements of this NodeList via `dojo.fadeIn`
+ //
+ // args: Object?
+ // Additional dojo.Animation arguments to mix into this set with the addition of
+ // an `auto` parameter.
+ //
+ // returns: dojo.Animation|dojo.NodeList
+ // A special args member `auto` can be passed to automatically play the animation.
+ // If args.auto is present, the original dojo.NodeList will be returned for further
+ // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed
+ //
+ // example:
+ // Fade in all tables with class "blah":
+ // | dojo.query("table.blah").fadeIn().play();
+ return this._anim(dojo, "fadeIn", args); // dojo.Animation|dojo.NodeList
+ },
+
+ fadeOut: function(args){
+ // summary:
+ // fade out all elements of this NodeList via `dojo.fadeOut`
+ //
+ // args: Object?
+ // Additional dojo.Animation arguments to mix into this set with the addition of
+ // an `auto` parameter.
+ //
+ // returns: dojo.Animation|dojo.NodeList
+ // A special args member `auto` can be passed to automatically play the animation.
+ // If args.auto is present, the original dojo.NodeList will be returned for further
+ // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed
+ //
+ // 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();
+ // example:
+ // Using `auto`:
+ // | dojo.query("li").fadeOut({ auto:true }).filter(filterFn).forEach(doit);
+ //
+ return this._anim(dojo, "fadeOut", args); // dojo.Animation|dojo.NodeList
+ },
+
+ animateProperty: function(args){
+ // summary:
+ // Animate all elements of this NodeList across the properties specified.
+ // syntax identical to `dojo.animateProperty`
+ //
+ // returns: dojo.Animation|dojo.NodeList
+ // A special args member `auto` can be passed to automatically play the animation.
+ // If args.auto is present, the original dojo.NodeList will be returned for further
+ // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed
+ //
+ // example:
+ // | dojo.query(".zork").animateProperty({
+ // | duration: 500,
+ // | properties: {
+ // | color: { start: "black", end: "white" },
+ // | left: { end: 300 }
+ // | }
+ // | }).play();
+ //
+ // example:
+ // | dojo.query(".grue").animateProperty({
+ // | auto:true,
+ // | properties: {
+ // | height:240
+ // | }
+ // | }).onclick(handler);
+ return this._anim(dojo, "animateProperty", args); // dojo.Animation|dojo.NodeList
+ },
+
+ 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. does NOT support the `auto` parameter like other
+ // NodeList-fx methods.
+ // 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/lib/dojo/NodeList-html.js b/lib/dojo/NodeList-html.js
index ccc6f10ae..e8e0ac220 100644
--- a/lib/dojo/NodeList-html.js
+++ b/lib/dojo/NodeList-html.js
@@ -5,17 +5,45 @@
*/
-if(!dojo._hasResource["dojo.NodeList-html"]){
-dojo._hasResource["dojo.NodeList-html"]=true;
+if(!dojo._hasResource["dojo.NodeList-html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.NodeList-html"] = true;
dojo.provide("dojo.NodeList-html");
dojo.require("dojo.html");
-dojo.extend(dojo.NodeList,{html:function(_1,_2){
-var _3=new dojo.html._ContentSetter(_2||{});
-this.forEach(function(_4){
-_3.node=_4;
-_3.set(_1);
-_3.tearDown();
+
+/*=====
+dojo["NodeList-html"] = {
+ // summary: Adds a chainable html method to dojo.query() / Nodelist instances for setting/replacing node content
+};
+=====*/
+
+dojo.extend(dojo.NodeList, {
+ html: function(content, /* Object? */params){
+ // summary:
+ // see `dojo.html.set()`. Set the content of all elements of this NodeList
+ //
+ // description:
+ // Based around `dojo.html.set()`, set the content of the Elements in a
+ // NodeList to the given content (string/node/nodelist), with optional arguments
+ // to further tune the set content behavior.
+ //
+ // example:
+ // | dojo.query(".thingList").html("<li dojoType='dojo.dnd.Moveable'>1</li><li dojoType='dojo.dnd.Moveable'>2</li><li dojoType='dojo.dnd.Moveable'>3</li>",
+ // | {
+ // | parseContent: true,
+ // | onBegin: function(){
+ // | this.content = this.content.replace(/([0-9])/g, this.id + ": $1");
+ // | this.inherited("onBegin", arguments);
+ // | }
+ // | }).removeClass("notdone").addClass("done");
+
+ var dhs = new dojo.html._ContentSetter(params || {});
+ this.forEach(function(elm){
+ dhs.node = elm;
+ dhs.set(content);
+ dhs.tearDown();
+ });
+ return this; // dojo.NodeList
+ }
});
-return this;
-}});
+
}
diff --git a/lib/dojo/NodeList-manipulate.js b/lib/dojo/NodeList-manipulate.js
index b0b7498a6..171540faf 100644
--- a/lib/dojo/NodeList-manipulate.js
+++ b/lib/dojo/NodeList-manipulate.js
@@ -5,208 +5,727 @@
*/
-if(!dojo._hasResource["dojo.NodeList-manipulate"]){
-dojo._hasResource["dojo.NodeList-manipulate"]=true;
+if(!dojo._hasResource["dojo.NodeList-manipulate"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.NodeList-manipulate"] = true;
dojo.provide("dojo.NodeList-manipulate");
-(function(){
-function _1(_2){
-var _3="",ch=_2.childNodes;
-for(var i=0,n;n=ch[i];i++){
-if(n.nodeType!=8){
-if(n.nodeType==1){
-_3+=_1(n);
-}else{
-_3+=n.nodeValue;
-}
-}
-}
-return _3;
-};
-function _4(_5){
-while(_5.childNodes[0]&&_5.childNodes[0].nodeType==1){
-_5=_5.childNodes[0];
-}
-return _5;
-};
-function _6(_7,_8){
-if(typeof _7=="string"){
-_7=dojo._toDom(_7,(_8&&_8.ownerDocument));
-if(_7.nodeType==11){
-_7=_7.childNodes[0];
-}
-}else{
-if(_7.nodeType==1&&_7.parentNode){
-_7=_7.cloneNode(false);
-}
-}
-return _7;
+
+/*=====
+dojo["NodeList-manipulate"] = {
+ // summary: Adds a chainable methods to dojo.query() / Nodelist instances for manipulating HTML
+ // and DOM nodes and their properties.
};
-dojo.extend(dojo.NodeList,{_placeMultiple:function(_9,_a){
-var _b=typeof _9=="string"||_9.nodeType?dojo.query(_9):_9;
-var _c=[];
-for(var i=0;i<_b.length;i++){
-var _d=_b[i];
-var _e=this.length;
-for(var j=_e-1,_f;_f=this[j];j--){
-if(i>0){
-_f=this._cloneNode(_f);
-_c.unshift(_f);
-}
-if(j==_e-1){
-dojo.place(_f,_d,_a);
-}else{
-_d.parentNode.insertBefore(_f,_d);
-}
-_d=_f;
-}
-}
-if(_c.length){
-_c.unshift(0);
-_c.unshift(this.length-1);
-Array.prototype.splice.apply(this,_c);
-}
-return this;
-},innerHTML:function(_10){
-if(arguments.length){
-return this.addContent(_10,"only");
-}else{
-return this[0].innerHTML;
-}
-},text:function(_11){
-if(arguments.length){
-for(var i=0,_12;_12=this[i];i++){
-if(_12.nodeType==1){
-dojo.empty(_12);
-_12.appendChild(_12.ownerDocument.createTextNode(_11));
-}
-}
-return this;
-}else{
-var _13="";
-for(i=0;_12=this[i];i++){
-_13+=_1(_12);
-}
-return _13;
-}
-},val:function(_14){
-if(arguments.length){
-var _15=dojo.isArray(_14);
-for(var _16=0,_17;_17=this[_16];_16++){
-var _18=_17.nodeName.toUpperCase();
-var _19=_17.type;
-var _1a=_15?_14[_16]:_14;
-if(_18=="SELECT"){
-var _1b=_17.options;
-for(var i=0;i<_1b.length;i++){
-var opt=_1b[i];
-if(_17.multiple){
-opt.selected=(dojo.indexOf(_14,opt.value)!=-1);
-}else{
-opt.selected=(opt.value==_1a);
-}
-}
-}else{
-if(_19=="checkbox"||_19=="radio"){
-_17.checked=(_17.value==_1a);
-}else{
-_17.value=_1a;
-}
-}
-}
-return this;
-}else{
-_17=this[0];
-if(!_17||_17.nodeType!=1){
-return undefined;
-}
-_14=_17.value||"";
-if(_17.nodeName.toUpperCase()=="SELECT"&&_17.multiple){
-_14=[];
-_1b=_17.options;
-for(i=0;i<_1b.length;i++){
-opt=_1b[i];
-if(opt.selected){
-_14.push(opt.value);
-}
-}
-if(!_14.length){
-_14=null;
-}
-}
-return _14;
-}
-},append:function(_1c){
-return this.addContent(_1c,"last");
-},appendTo:function(_1d){
-return this._placeMultiple(_1d,"last");
-},prepend:function(_1e){
-return this.addContent(_1e,"first");
-},prependTo:function(_1f){
-return this._placeMultiple(_1f,"first");
-},after:function(_20){
-return this.addContent(_20,"after");
-},insertAfter:function(_21){
-return this._placeMultiple(_21,"after");
-},before:function(_22){
-return this.addContent(_22,"before");
-},insertBefore:function(_23){
-return this._placeMultiple(_23,"before");
-},remove:dojo.NodeList.prototype.orphan,wrap:function(_24){
-if(this[0]){
-_24=_6(_24,this[0]);
-for(var i=0,_25;_25=this[i];i++){
-var _26=this._cloneNode(_24);
-if(_25.parentNode){
-_25.parentNode.replaceChild(_26,_25);
-}
-var _27=_4(_26);
-_27.appendChild(_25);
-}
-}
-return this;
-},wrapAll:function(_28){
-if(this[0]){
-_28=_6(_28,this[0]);
-this[0].parentNode.replaceChild(_28,this[0]);
-var _29=_4(_28);
-for(var i=0,_2a;_2a=this[i];i++){
-_29.appendChild(_2a);
-}
-}
-return this;
-},wrapInner:function(_2b){
-if(this[0]){
-_2b=_6(_2b,this[0]);
-for(var i=0;i<this.length;i++){
-var _2c=this._cloneNode(_2b);
-this._wrap(dojo._toArray(this[i].childNodes),null,this._NodeListCtor).wrapAll(_2c);
-}
-}
-return this;
-},replaceWith:function(_2d){
-_2d=this._normalize(_2d,this[0]);
-for(var i=0,_2e;_2e=this[i];i++){
-this._place(_2d,_2e,"before",i>0);
-_2e.parentNode.removeChild(_2e);
-}
-return this;
-},replaceAll:function(_2f){
-var nl=dojo.query(_2f);
-var _30=this._normalize(this,this[0]);
-for(var i=0,_31;_31=nl[i];i++){
-this._place(_30,_31,"before",i>0);
-_31.parentNode.removeChild(_31);
-}
-return this;
-},clone:function(){
-var ary=[];
-for(var i=0;i<this.length;i++){
-ary.push(this._cloneNode(this[i]));
-}
-return this._wrap(ary,this,this._NodeListCtor);
-}});
-if(!dojo.NodeList.prototype.html){
-dojo.NodeList.prototype.html=dojo.NodeList.prototype.innerHTML;
-}
+=====*/
+
+//TODO: add a way to parse for widgets in the injected markup?
+
+(function(){
+ function getText(/*DOMNode*/node){
+ // summary:
+ // recursion method for text() to use. Gets text value for a node.
+ // description:
+ // Juse uses nodedValue so things like <br/> tags do not end up in
+ // the text as any sort of line return.
+ var text = "", ch = node.childNodes;
+ for(var i = 0, n; n = ch[i]; i++){
+ //Skip comments.
+ if(n.nodeType != 8){
+ if(n.nodeType == 1){
+ text += getText(n);
+ }else{
+ text += n.nodeValue;
+ }
+ }
+ }
+ return text;
+ }
+
+ function getWrapInsertion(/*DOMNode*/node){
+ // summary:
+ // finds the innermost element to use for wrap insertion.
+
+ //Make it easy, assume single nesting, no siblings.
+ while(node.childNodes[0] && node.childNodes[0].nodeType == 1){
+ node = node.childNodes[0];
+ }
+ return node; //DOMNode
+ }
+
+ function makeWrapNode(/*DOMNode||String*/html, /*DOMNode*/refNode){
+ // summary:
+ // convert HTML into nodes if it is not already a node.
+ if(typeof html == "string"){
+ html = dojo._toDom(html, (refNode && refNode.ownerDocument));
+ if(html.nodeType == 11){
+ //DocumentFragment cannot handle cloneNode, so choose first child.
+ html = html.childNodes[0];
+ }
+ }else if(html.nodeType == 1 && html.parentNode){
+ //This element is already in the DOM clone it, but not its children.
+ html = html.cloneNode(false);
+ }
+ return html; /*DOMNode*/
+ }
+
+ dojo.extend(dojo.NodeList, {
+ _placeMultiple: function(/*String||Node||NodeList*/query, /*String*/position){
+ // summary:
+ // private method for inserting queried nodes into all nodes in this NodeList
+ // at different positions. Differs from NodeList.place because it will clone
+ // the nodes in this NodeList if the query matches more than one element.
+ var nl2 = typeof query == "string" || query.nodeType ? dojo.query(query) : query;
+ var toAdd = [];
+ for(var i = 0; i < nl2.length; i++){
+ //Go backwards in DOM to make dom insertions easier via insertBefore
+ var refNode = nl2[i];
+ var length = this.length;
+ for(var j = length - 1, item; item = this[j]; j--){
+ if(i > 0){
+ //Need to clone the item. This also means
+ //it needs to be added to the current NodeList
+ //so it can also be the target of other chaining operations.
+ item = this._cloneNode(item);
+ toAdd.unshift(item);
+ }
+ if(j == length - 1){
+ dojo.place(item, refNode, position);
+ }else{
+ refNode.parentNode.insertBefore(item, refNode);
+ }
+ refNode = item;
+ }
+ }
+
+ if(toAdd.length){
+ //Add the toAdd items to the current NodeList. Build up list of args
+ //to pass to splice.
+ toAdd.unshift(0);
+ toAdd.unshift(this.length - 1);
+ Array.prototype.splice.apply(this, toAdd);
+ }
+
+ return this; //dojo.NodeList
+ },
+
+ innerHTML: function(/*String?||DOMNode?|NodeList?*/value){
+ // summary:
+ // allows setting the innerHTML of each node in the NodeList,
+ // if there is a value passed in, otherwise, reads the innerHTML value of the first node.
+ // description:
+ // This method is simpler than the dojo.NodeList.html() method provided by
+ // `dojo.NodeList-html`. This method just does proper innerHTML insertion of HTML fragments,
+ // and it allows for the innerHTML to be read for the first node in the node list.
+ // Since dojo.NodeList-html already took the "html" name, this method is called
+ // "innerHTML". However, if dojo.NodeList-html has not been loaded yet, this
+ // module will define an "html" method that can be used instead. Be careful if you
+ // are working in an environment where it is possible that dojo.NodeList-html could
+ // have been loaded, since its definition of "html" will take precedence.
+ // The nodes represented by the value argument will be cloned if more than one
+ // node is in this NodeList. The nodes in this NodeList are returned in the "set"
+ // usage of this method, not the HTML that was inserted.
+ // returns:
+ // if no value is passed, the result is String, the innerHTML of the first node.
+ // If a value is passed, the return is this dojo.NodeList
+ // example:
+ // assume a DOM created by this markup:
+ // | <div id="foo"></div>
+ // | <div id="bar"></div>
+ // This code inserts <p>Hello World</p> into both divs:
+ // | dojo.query("div").innerHTML("<p>Hello World</p>");
+ // example:
+ // assume a DOM created by this markup:
+ // | <div id="foo"><p>Hello Mars</p></div>
+ // | <div id="bar"><p>Hello World</p></div>
+ // This code returns "<p>Hello Mars</p>":
+ // | var message = dojo.query("div").innerHTML();
+ if(arguments.length){
+ return this.addContent(value, "only"); //dojo.NodeList
+ }else{
+ return this[0].innerHTML; //String
+ }
+ },
+
+ /*=====
+ html: function(value){
+ // summary:
+ // see the information for "innerHTML". "html" is an alias for "innerHTML", but is
+ // only defined if dojo.NodeList-html has not been loaded.
+ // description:
+ // An alias for the "innerHTML" method, but only defined if there is not an existing
+ // "html" method on dojo.NodeList. Be careful if you are working in an environment
+ // where it is possible that dojo.NodeList-html could have been loaded, since its
+ // definition of "html" will take precedence. If you are not sure if dojo.NodeList-html
+ // could be loaded, use the "innerHTML" method.
+ // value: String?||DOMNode?||NodeList?
+ // optional. The HTML fragment to use as innerHTML. If value is not passed, then the innerHTML
+ // of the first element in this NodeList is returned.
+ // returns:
+ // if no value is passed, the result is String, the innerHTML of the first node.
+ // If a value is passed, the return is this dojo.NodeList
+ return; // dojo.NodeList
+ return; // String
+ },
+ =====*/
+
+ text: function(/*String*/value){
+ // summary:
+ // allows setting the text value of each node in the NodeList,
+ // if there is a value passed in, otherwise, returns the text value for all the
+ // nodes in the NodeList in one string.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div id="foo"></div>
+ // | <div id="bar"></div>
+ // This code inserts "Hello World" into both divs:
+ // | dojo.query("div").text("Hello World");
+ // example:
+ // assume a DOM created by this markup:
+ // | <div id="foo"><p>Hello Mars <span>today</span></p></div>
+ // | <div id="bar"><p>Hello World</p></div>
+ // This code returns "Hello Mars today":
+ // | var message = dojo.query("div").text();
+ // returns:
+ // if no value is passed, the result is String, the text value of the first node.
+ // If a value is passed, the return is this dojo.NodeList
+ if(arguments.length){
+ for(var i = 0, node; node = this[i]; i++){
+ if(node.nodeType == 1){
+ dojo.empty(node);
+ node.appendChild(node.ownerDocument.createTextNode(value));
+ }
+ }
+ return this; //dojo.NodeList
+ }else{
+ var result = "";
+ for(i = 0; node = this[i]; i++){
+ result += getText(node);
+ }
+ return result; //String
+ }
+ },
+
+ val: function(/*String||Array*/value){
+ // summary:
+ // If a value is passed, allows seting the value property of form elements in this
+ // NodeList, or properly selecting/checking the right value for radio/checkbox/select
+ // elements. If no value is passed, the value of the first node in this NodeList
+ // is returned.
+ // returns:
+ // if no value is passed, the result is String or an Array, for the value of the
+ // first node.
+ // If a value is passed, the return is this dojo.NodeList
+ // example:
+ // assume a DOM created by this markup:
+ // | <input type="text" value="foo">
+ // | <select multiple>
+ // | <option value="red" selected>Red</option>
+ // | <option value="blue">Blue</option>
+ // | <option value="yellow" selected>Yellow</option>
+ // | </select>
+ // This code gets and sets the values for the form fields above:
+ // | dojo.query('[type="text"]').val(); //gets value foo
+ // | dojo.query('[type="text"]').val("bar"); //sets the input's value to "bar"
+ // | dojo.query("select").val() //gets array value ["red", "yellow"]
+ // | dojo.query("select").val(["blue", "yellow"]) //Sets the blue and yellow options to selected.
+
+ //Special work for input elements.
+ if(arguments.length){
+ var isArray = dojo.isArray(value);
+ for(var index = 0, node; node = this[index]; index++){
+ var name = node.nodeName.toUpperCase();
+ var type = node.type;
+ var newValue = isArray ? value[index] : value;
+
+ if(name == "SELECT"){
+ var opts = node.options;
+ for(var i = 0; i < opts.length; i++){
+ var opt = opts[i];
+ if(node.multiple){
+ opt.selected = (dojo.indexOf(value, opt.value) != -1);
+ }else{
+ opt.selected = (opt.value == newValue);
+ }
+ }
+ }else if(type == "checkbox" || type == "radio"){
+ node.checked = (node.value == newValue);
+ }else{
+ node.value = newValue;
+ }
+ }
+ return this; //dojo.NodeList
+ }else{
+ //node already declared above.
+ node = this[0];
+ if(!node || node.nodeType != 1){
+ return undefined;
+ }
+ value = node.value || "";
+ if(node.nodeName.toUpperCase() == "SELECT" && node.multiple){
+ //A multivalued selectbox. Do the pain.
+ value = [];
+ //opts declared above in if block.
+ opts = node.options;
+ //i declared above in if block;
+ for(i = 0; i < opts.length; i++){
+ //opt declared above in if block
+ opt = opts[i];
+ if(opt.selected){
+ value.push(opt.value);
+ }
+ }
+ if(!value.length){
+ value = null;
+ }
+ }
+ return value; //String||Array
+ }
+ },
+
+ append: function(/*String||DOMNode||NodeList*/content){
+ // summary:
+ // appends the content to every node in the NodeList.
+ // description:
+ // The content will be cloned if the length of NodeList
+ // is greater than 1. Only the DOM nodes are cloned, not
+ // any attached event handlers.
+ // returns:
+ // dojo.NodeList, the nodes currently in this NodeList will be returned,
+ // not the appended content.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div id="foo"><p>Hello Mars</p></div>
+ // | <div id="bar"><p>Hello World</p></div>
+ // Running this code:
+ // | dojo.query("div").append("<span>append</span>");
+ // Results in this DOM structure:
+ // | <div id="foo"><p>Hello Mars</p><span>append</span></div>
+ // | <div id="bar"><p>Hello World</p><span>append</span></div>
+ return this.addContent(content, "last"); //dojo.NodeList
+ },
+
+ appendTo: function(/*String*/query){
+ // summary:
+ // appends nodes in this NodeList to the nodes matched by
+ // the query passed to appendTo.
+ // description:
+ // The nodes in this NodeList will be cloned if the query
+ // matches more than one element. Only the DOM nodes are cloned, not
+ // any attached event handlers.
+ // returns:
+ // dojo.NodeList, the nodes currently in this NodeList will be returned,
+ // not the matched nodes from the query.
+ // example:
+ // assume a DOM created by this markup:
+ // | <span>append</span>
+ // | <p>Hello Mars</p>
+ // | <p>Hello World</p>
+ // Running this code:
+ // | dojo.query("span").appendTo("p");
+ // Results in this DOM structure:
+ // | <p>Hello Mars<span>append</span></p>
+ // | <p>Hello World<span>append</span></p>
+ return this._placeMultiple(query, "last"); //dojo.NodeList
+ },
+
+ prepend: function(/*String||DOMNode||NodeList*/content){
+ // summary:
+ // prepends the content to every node in the NodeList.
+ // description:
+ // The content will be cloned if the length of NodeList
+ // is greater than 1. Only the DOM nodes are cloned, not
+ // any attached event handlers.
+ // returns:
+ // dojo.NodeList, the nodes currently in this NodeList will be returned,
+ // not the appended content.
+ // assume a DOM created by this markup:
+ // | <div id="foo"><p>Hello Mars</p></div>
+ // | <div id="bar"><p>Hello World</p></div>
+ // Running this code:
+ // | dojo.query("div").prepend("<span>prepend</span>");
+ // Results in this DOM structure:
+ // | <div id="foo"><span>prepend</span><p>Hello Mars</p></div>
+ // | <div id="bar"><span>prepend</span><p>Hello World</p></div>
+ return this.addContent(content, "first"); //dojo.NodeList
+ },
+
+ prependTo: function(/*String*/query){
+ // summary:
+ // prepends nodes in this NodeList to the nodes matched by
+ // the query passed to prependTo.
+ // description:
+ // The nodes in this NodeList will be cloned if the query
+ // matches more than one element. Only the DOM nodes are cloned, not
+ // any attached event handlers.
+ // returns:
+ // dojo.NodeList, the nodes currently in this NodeList will be returned,
+ // not the matched nodes from the query.
+ // example:
+ // assume a DOM created by this markup:
+ // | <span>prepend</span>
+ // | <p>Hello Mars</p>
+ // | <p>Hello World</p>
+ // Running this code:
+ // | dojo.query("span").prependTo("p");
+ // Results in this DOM structure:
+ // | <p><span>prepend</span>Hello Mars</p>
+ // | <p><span>prepend</span>Hello World</p>
+ return this._placeMultiple(query, "first"); //dojo.NodeList
+ },
+
+ after: function(/*String||Element||NodeList*/content){
+ // summary:
+ // Places the content after every node in the NodeList.
+ // description:
+ // The content will be cloned if the length of NodeList
+ // is greater than 1. Only the DOM nodes are cloned, not
+ // any attached event handlers.
+ // returns:
+ // dojo.NodeList, the nodes currently in this NodeList will be returned,
+ // not the appended content.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div id="foo"><p>Hello Mars</p></div>
+ // | <div id="bar"><p>Hello World</p></div>
+ // Running this code:
+ // | dojo.query("div").after("<span>after</span>");
+ // Results in this DOM structure:
+ // | <div id="foo"><p>Hello Mars</p></div><span>after</span>
+ // | <div id="bar"><p>Hello World</p></div><span>after</span>
+ return this.addContent(content, "after"); //dojo.NodeList
+ },
+
+ insertAfter: function(/*String*/query){
+ // summary:
+ // The nodes in this NodeList will be placed after the nodes
+ // matched by the query passed to insertAfter.
+ // description:
+ // The nodes in this NodeList will be cloned if the query
+ // matches more than one element. Only the DOM nodes are cloned, not
+ // any attached event handlers.
+ // returns:
+ // dojo.NodeList, the nodes currently in this NodeList will be returned,
+ // not the matched nodes from the query.
+ // example:
+ // assume a DOM created by this markup:
+ // | <span>after</span>
+ // | <p>Hello Mars</p>
+ // | <p>Hello World</p>
+ // Running this code:
+ // | dojo.query("span").insertAfter("p");
+ // Results in this DOM structure:
+ // | <p>Hello Mars</p><span>after</span>
+ // | <p>Hello World</p><span>after</span>
+ return this._placeMultiple(query, "after"); //dojo.NodeList
+ },
+
+ before: function(/*String||DOMNode||NodeList*/content){
+ // summary:
+ // Places the content before every node in the NodeList.
+ // description:
+ // The content will be cloned if the length of NodeList
+ // is greater than 1. Only the DOM nodes are cloned, not
+ // any attached event handlers.
+ // returns:
+ // dojo.NodeList, the nodes currently in this NodeList will be returned,
+ // not the appended content.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div id="foo"><p>Hello Mars</p></div>
+ // | <div id="bar"><p>Hello World</p></div>
+ // Running this code:
+ // | dojo.query("div").before("<span>before</span>");
+ // Results in this DOM structure:
+ // | <span>before</span><div id="foo"><p>Hello Mars</p></div>
+ // | <span>before</span><div id="bar"><p>Hello World</p></div>
+ return this.addContent(content, "before"); //dojo.NodeList
+ },
+
+ insertBefore: function(/*String*/query){
+ // summary:
+ // The nodes in this NodeList will be placed after the nodes
+ // matched by the query passed to insertAfter.
+ // description:
+ // The nodes in this NodeList will be cloned if the query
+ // matches more than one element. Only the DOM nodes are cloned, not
+ // any attached event handlers.
+ // returns:
+ // dojo.NodeList, the nodes currently in this NodeList will be returned,
+ // not the matched nodes from the query.
+ // example:
+ // assume a DOM created by this markup:
+ // | <span>before</span>
+ // | <p>Hello Mars</p>
+ // | <p>Hello World</p>
+ // Running this code:
+ // | dojo.query("span").insertBefore("p");
+ // Results in this DOM structure:
+ // | <span>before</span><p>Hello Mars</p>
+ // | <span>before</span><p>Hello World</p>
+ return this._placeMultiple(query, "before"); //dojo.NodeList
+ },
+
+ /*=====
+ remove: function(simpleFilter){
+ // summary:
+ // alias for dojo.NodeList's orphan method. Removes elements
+ // in this list that match the simple filter from their parents
+ // and returns them as a new NodeList.
+ // simpleFilter: String
+ // single-expression CSS rule. For example, ".thinger" or
+ // "#someId[attrName='value']" but not "div > span". In short,
+ // anything which does not invoke a descent to evaluate but
+ // can instead be used to test a single node is acceptable.
+ // returns:
+ // dojo.NodeList
+ return; // dojo.NodeList
+ },
+ =====*/
+ remove: dojo.NodeList.prototype.orphan,
+
+ wrap: function(/*String||DOMNode*/html){
+ // summary:
+ // Wrap each node in the NodeList with html passed to wrap.
+ // description:
+ // html will be cloned if the NodeList has more than one
+ // element. Only DOM nodes are cloned, not any attached
+ // event handlers.
+ // returns:
+ // dojo.NodeList, the nodes in the current NodeList will be returned,
+ // not the nodes from html argument.
+ // example:
+ // assume a DOM created by this markup:
+ // | <b>one</b>
+ // | <b>two</b>
+ // Running this code:
+ // | dojo.query("b").wrap("<div><span></span></div>");
+ // Results in this DOM structure:
+ // | <div><span><b>one</b></span></div>
+ // | <div><span><b>two</b></span></div>
+ if(this[0]){
+ html = makeWrapNode(html, this[0]);
+
+ //Now cycle through the elements and do the insertion.
+ for(var i = 0, node; node = this[i]; i++){
+ //Always clone because if html is used to hold one of
+ //the "this" nodes, then on the clone of html it will contain
+ //that "this" node, and that would be bad.
+ var clone = this._cloneNode(html);
+ if(node.parentNode){
+ node.parentNode.replaceChild(clone, node);
+ }
+ //Find deepest element and insert old node in it.
+ var insertion = getWrapInsertion(clone);
+ insertion.appendChild(node);
+ }
+ }
+ return this; //dojo.NodeList
+ },
+
+ wrapAll: function(/*String||DOMNode*/html){
+ // summary:
+ // Insert html where the first node in this NodeList lives, then place all
+ // nodes in this NodeList as the child of the html.
+ // returns:
+ // dojo.NodeList, the nodes in the current NodeList will be returned,
+ // not the nodes from html argument.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | <div class="blue">Blue One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".red").wrapAll('<div class="allRed"></div>');
+ // Results in this DOM structure:
+ // | <div class="container">
+ // | <div class="allRed">
+ // | <div class="red">Red One</div>
+ // | <div class="red">Red Two</div>
+ // | </div>
+ // | <div class="blue">Blue One</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ if(this[0]){
+ html = makeWrapNode(html, this[0]);
+
+ //Place the wrap HTML in place of the first node.
+ this[0].parentNode.replaceChild(html, this[0]);
+
+ //Now cycle through the elements and move them inside
+ //the wrap.
+ var insertion = getWrapInsertion(html);
+ for(var i = 0, node; node = this[i]; i++){
+ insertion.appendChild(node);
+ }
+ }
+ return this; //dojo.NodeList
+ },
+
+ wrapInner: function(/*String||DOMNode*/html){
+ // summary:
+ // For each node in the NodeList, wrap all its children with the passed in html.
+ // description:
+ // html will be cloned if the NodeList has more than one
+ // element. Only DOM nodes are cloned, not any attached
+ // event handlers.
+ // returns:
+ // dojo.NodeList, the nodes in the current NodeList will be returned,
+ // not the nodes from html argument.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | <div class="blue">Blue One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".red").wrapInner('<span class="special"></span>');
+ // Results in this DOM structure:
+ // | <div class="container">
+ // | <div class="red"><span class="special">Red One</span></div>
+ // | <div class="blue">Blue One</div>
+ // | <div class="red"><span class="special">Red Two</span></div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ if(this[0]){
+ html = makeWrapNode(html, this[0]);
+ for(var i = 0; i < this.length; i++){
+ //Always clone because if html is used to hold one of
+ //the "this" nodes, then on the clone of html it will contain
+ //that "this" node, and that would be bad.
+ var clone = this._cloneNode(html);
+
+ //Need to convert the childNodes to an array since wrapAll modifies the
+ //DOM and can change the live childNodes NodeList.
+ this._wrap(dojo._toArray(this[i].childNodes), null, this._NodeListCtor).wrapAll(clone);
+ }
+ }
+ return this; //dojo.NodeList
+ },
+
+ replaceWith: function(/*String||DOMNode||NodeList*/content){
+ // summary:
+ // Replaces each node in ths NodeList with the content passed to replaceWith.
+ // description:
+ // The content will be cloned if the length of NodeList
+ // is greater than 1. Only the DOM nodes are cloned, not
+ // any attached event handlers.
+ // returns:
+ // The nodes currently in this NodeList will be returned, not the replacing content.
+ // Note that the returned nodes have been removed from the DOM.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | <div class="blue">Blue One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".red").replaceWith('<div class="green">Green</div>');
+ // Results in this DOM structure:
+ // | <div class="container">
+ // | <div class="green">Green</div>
+ // | <div class="blue">Blue One</div>
+ // | <div class="green">Green</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ content = this._normalize(content, this[0]);
+ for(var i = 0, node; node = this[i]; i++){
+ this._place(content, node, "before", i > 0);
+ node.parentNode.removeChild(node);
+ }
+ return this; //dojo.NodeList
+ },
+
+ replaceAll: function(/*String*/query){
+ // summary:
+ // replaces nodes matched by the query passed to replaceAll with the nodes
+ // in this NodeList.
+ // description:
+ // The nodes in this NodeList will be cloned if the query
+ // matches more than one element. Only the DOM nodes are cloned, not
+ // any attached event handlers.
+ // returns:
+ // The nodes currently in this NodeList will be returned, not the matched nodes
+ // from the query. The nodes currently in this NodeLIst could have
+ // been cloned, so the returned NodeList will include the cloned nodes.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="spacer">___</div>
+ // | <div class="red">Red One</div>
+ // | <div class="spacer">___</div>
+ // | <div class="blue">Blue One</div>
+ // | <div class="spacer">___</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="spacer">___</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".red").replaceAll(".blue");
+ // Results in this DOM structure:
+ // | <div class="container">
+ // | <div class="spacer">___</div>
+ // | <div class="spacer">___</div>
+ // | <div class="red">Red One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="spacer">___</div>
+ // | <div class="spacer">___</div>
+ // | <div class="red">Red One</div>
+ // | <div class="red">Red Two</div>
+ // | </div>
+ var nl = dojo.query(query);
+ var content = this._normalize(this, this[0]);
+ for(var i = 0, node; node = nl[i]; i++){
+ this._place(content, node, "before", i > 0);
+ node.parentNode.removeChild(node);
+ }
+ return this; //dojo.NodeList
+ },
+
+ clone: function(){
+ // summary:
+ // Clones all the nodes in this NodeList and returns them as a new NodeList.
+ // description:
+ // Only the DOM nodes are cloned, not any attached event handlers.
+ // returns:
+ // dojo.NodeList, a cloned set of the original nodes.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | <div class="blue">Blue One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".red").clone().appendTo(".container");
+ // Results in this DOM structure:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | <div class="blue">Blue One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue">Blue Two</div>
+ // | <div class="red">Red One</div>
+ // | <div class="red">Red Two</div>
+ // | </div>
+
+ //TODO: need option to clone events?
+ var ary = [];
+ for(var i = 0; i < this.length; i++){
+ ary.push(this._cloneNode(this[i]));
+ }
+ return this._wrap(ary, this, this._NodeListCtor); //dojo.NodeList
+ }
+ });
+
+ //set up html method if one does not exist
+ if(!dojo.NodeList.prototype.html){
+ dojo.NodeList.prototype.html = dojo.NodeList.prototype.innerHTML;
+ }
})();
+
}
diff --git a/lib/dojo/NodeList-traverse.js b/lib/dojo/NodeList-traverse.js
index 4fda2e7ea..b5314eed6 100644
--- a/lib/dojo/NodeList-traverse.js
+++ b/lib/dojo/NodeList-traverse.js
@@ -5,127 +5,513 @@
*/
-if(!dojo._hasResource["dojo.NodeList-traverse"]){
-dojo._hasResource["dojo.NodeList-traverse"]=true;
+if(!dojo._hasResource["dojo.NodeList-traverse"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.NodeList-traverse"] = true;
dojo.provide("dojo.NodeList-traverse");
-dojo.extend(dojo.NodeList,{_buildArrayFromCallback:function(_1){
-var _2=[];
-for(var i=0;i<this.length;i++){
-var _3=_1.call(this[i],this[i],_2);
-if(_3){
-_2=_2.concat(_3);
-}
-}
-return _2;
-},_filterQueryResult:function(_4,_5){
-var _6=dojo.filter(_4,function(_7){
-return dojo.query(_5,_7.parentNode).indexOf(_7)!=-1;
-});
-var _8=this._wrap(_6);
-return _8;
-},_getUniqueAsNodeList:function(_9){
-var _a=[];
-for(var i=0,_b;_b=_9[i];i++){
-if(_b.nodeType==1&&dojo.indexOf(_a,_b)==-1){
-_a.push(_b);
-}
-}
-return this._wrap(_a,null,this._NodeListCtor);
-},_getUniqueNodeListWithParent:function(_c,_d){
-var _e=this._getUniqueAsNodeList(_c);
-_e=(_d?this._filterQueryResult(_e,_d):_e);
-return _e._stash(this);
-},_getRelatedUniqueNodes:function(_f,_10){
-return this._getUniqueNodeListWithParent(this._buildArrayFromCallback(_10),_f);
-},children:function(_11){
-return this._getRelatedUniqueNodes(_11,function(_12,ary){
-return dojo._toArray(_12.childNodes);
-});
-},closest:function(_13){
-var _14=this;
-return this._getRelatedUniqueNodes(_13,function(_15,ary){
-do{
-if(_14._filterQueryResult([_15],_13).length){
-return _15;
-}
-}while((_15=_15.parentNode)&&_15.nodeType==1);
-return null;
-});
-},parent:function(_16){
-return this._getRelatedUniqueNodes(_16,function(_17,ary){
-return _17.parentNode;
-});
-},parents:function(_18){
-return this._getRelatedUniqueNodes(_18,function(_19,ary){
-var _1a=[];
-while(_19.parentNode){
-_19=_19.parentNode;
-_1a.push(_19);
-}
-return _1a;
-});
-},siblings:function(_1b){
-return this._getRelatedUniqueNodes(_1b,function(_1c,ary){
-var _1d=[];
-var _1e=(_1c.parentNode&&_1c.parentNode.childNodes);
-for(var i=0;i<_1e.length;i++){
-if(_1e[i]!=_1c){
-_1d.push(_1e[i]);
-}
-}
-return _1d;
-});
-},next:function(_1f){
-return this._getRelatedUniqueNodes(_1f,function(_20,ary){
-var _21=_20.nextSibling;
-while(_21&&_21.nodeType!=1){
-_21=_21.nextSibling;
-}
-return _21;
-});
-},nextAll:function(_22){
-return this._getRelatedUniqueNodes(_22,function(_23,ary){
-var _24=[];
-var _25=_23;
-while((_25=_25.nextSibling)){
-if(_25.nodeType==1){
-_24.push(_25);
-}
-}
-return _24;
-});
-},prev:function(_26){
-return this._getRelatedUniqueNodes(_26,function(_27,ary){
-var _28=_27.previousSibling;
-while(_28&&_28.nodeType!=1){
-_28=_28.previousSibling;
-}
-return _28;
-});
-},prevAll:function(_29){
-return this._getRelatedUniqueNodes(_29,function(_2a,ary){
-var _2b=[];
-var _2c=_2a;
-while((_2c=_2c.previousSibling)){
-if(_2c.nodeType==1){
-_2b.push(_2c);
-}
-}
-return _2b;
-});
-},andSelf:function(){
-return this.concat(this._parent);
-},first:function(){
-return this._wrap(((this[0]&&[this[0]])||[]),this);
-},last:function(){
-return this._wrap((this.length?[this[this.length-1]]:[]),this);
-},even:function(){
-return this.filter(function(_2d,i){
-return i%2!=0;
-});
-},odd:function(){
-return this.filter(function(_2e,i){
-return i%2==0;
+
+/*=====
+dojo["NodeList-traverse"] = {
+ // summary: Adds a chainable methods to dojo.query() / Nodelist instances for traversing the DOM
+};
+=====*/
+
+dojo.extend(dojo.NodeList, {
+ _buildArrayFromCallback: function(/*Function*/callback){
+ // summary:
+ // builds a new array of possibly differing size based on the input list.
+ // Since the returned array is likely of different size than the input array,
+ // the array's map function cannot be used.
+ var ary = [];
+ for(var i = 0; i < this.length; i++){
+ var items = callback.call(this[i], this[i], ary);
+ if(items){
+ ary = ary.concat(items);
+ }
+ }
+ return ary;
+ },
+
+ _filterQueryResult: function(nodeList, query){
+ // summmary:
+ // Replacement for dojo._filterQueryResult that does a full
+ // query. Slower, but allows for more types of queries.
+ var filter = dojo.filter(nodeList, function(node){
+ return dojo.query(query, node.parentNode).indexOf(node) != -1;
+ });
+ var result = this._wrap(filter);
+ return result;
+ },
+
+ _getUniqueAsNodeList: function(nodes){
+ // summary:
+ // given a list of nodes, make sure only unique
+ // elements are returned as our NodeList object.
+ // Does not call _stash().
+ var ary = [];
+ //Using for loop for better speed.
+ for(var i = 0, node; node = nodes[i]; i++){
+ //Should be a faster way to do this. dojo.query has a private
+ //_zip function that may be inspirational, but there are pathways
+ //in query that force nozip?
+ if(node.nodeType == 1 && dojo.indexOf(ary, node) == -1){
+ ary.push(node);
+ }
+ }
+ return this._wrap(ary, null, this._NodeListCtor); //dojo.NodeList
+ },
+
+ _getUniqueNodeListWithParent: function(nodes, query){
+ // summary:
+ // gets unique element nodes, filters them further
+ // with an optional query and then calls _stash to track parent NodeList.
+ var ary = this._getUniqueAsNodeList(nodes);
+ ary = (query ? this._filterQueryResult(ary, query) : ary);
+ return ary._stash(this); //dojo.NodeList
+ },
+
+ _getRelatedUniqueNodes: function(/*String?*/query, /*Function*/callback){
+ // summary:
+ // cycles over all the nodes and calls a callback
+ // to collect nodes for a possible inclusion in a result.
+ // The callback will get two args: callback(node, ary),
+ // where ary is the array being used to collect the nodes.
+ return this._getUniqueNodeListWithParent(this._buildArrayFromCallback(callback), query); //dojo.NodeList
+ },
+
+ children: function(/*String?*/query){
+ // summary:
+ // Returns all immediate child elements for nodes in this dojo.NodeList.
+ // Optionally takes a query to filter the child elements.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // query:
+ // a CSS selector.
+ // returns:
+ // dojo.NodeList, all immediate child elements for the nodes in this dojo.NodeList.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | Some Text
+ // | <div class="blue">Blue One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".container").children();
+ // returns the four divs that are children of the container div.
+ // Running this code:
+ // | dojo.query(".container").children(".red");
+ // returns the two divs that have the class "red".
+ return this._getRelatedUniqueNodes(query, function(node, ary){
+ return dojo._toArray(node.childNodes);
+ }); //dojo.NodeList
+ },
+
+ closest: function(/*String*/query){
+ // summary:
+ // Returns closest parent that matches query, including current node in this
+ // dojo.NodeList if it matches the query.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // query:
+ // a CSS selector.
+ // returns:
+ // dojo.NodeList, the closest parent that matches the query, including the current
+ // node in this dojo.NodeList if it matches the query.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | Some Text
+ // | <div class="blue">Blue One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".red").closest(".container");
+ // returns the div with class "container".
+ var self = this;
+ return this._getRelatedUniqueNodes(query, function(node, ary){
+ do{
+ if(self._filterQueryResult([node], query).length){
+ return node;
+ }
+ }while((node = node.parentNode) && node.nodeType == 1);
+ return null; //To make rhino strict checking happy.
+ }); //dojo.NodeList
+ },
+
+ parent: function(/*String?*/query){
+ // summary:
+ // Returns immediate parent elements for nodes in this dojo.NodeList.
+ // Optionally takes a query to filter the parent elements.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // query:
+ // a CSS selector.
+ // returns:
+ // dojo.NodeList, immediate parent elements for nodes in this dojo.NodeList.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | <div class="blue first"><span class="text">Blue One</span></div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue"><span class="text">Blue Two</span></div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".text").parent();
+ // returns the two divs with class "blue".
+ // Running this code:
+ // | dojo.query(".text").parent(".first");
+ // returns the one div with class "blue" and "first".
+ return this._getRelatedUniqueNodes(query, function(node, ary){
+ return node.parentNode;
+ }); //dojo.NodeList
+ },
+
+ parents: function(/*String?*/query){
+ // summary:
+ // Returns all parent elements for nodes in this dojo.NodeList.
+ // Optionally takes a query to filter the child elements.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // query:
+ // a CSS selector.
+ // returns:
+ // dojo.NodeList, all parent elements for nodes in this dojo.NodeList.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | <div class="blue first"><span class="text">Blue One</span></div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue"><span class="text">Blue Two</span></div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".text").parents();
+ // returns the two divs with class "blue", the div with class "container",
+ // | the body element and the html element.
+ // Running this code:
+ // | dojo.query(".text").parents(".container");
+ // returns the one div with class "container".
+ return this._getRelatedUniqueNodes(query, function(node, ary){
+ var pary = []
+ while(node.parentNode){
+ node = node.parentNode;
+ pary.push(node);
+ }
+ return pary;
+ }); //dojo.NodeList
+ },
+
+ siblings: function(/*String?*/query){
+ // summary:
+ // Returns all sibling elements for nodes in this dojo.NodeList.
+ // Optionally takes a query to filter the sibling elements.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // query:
+ // a CSS selector.
+ // returns:
+ // dojo.NodeList, all sibling elements for nodes in this dojo.NodeList.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | Some Text
+ // | <div class="blue first">Blue One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".first").siblings();
+ // returns the two divs with class "red" and the other div
+ // | with class "blue" that does not have "first".
+ // Running this code:
+ // | dojo.query(".first").siblings(".red");
+ // returns the two div with class "red".
+ return this._getRelatedUniqueNodes(query, function(node, ary){
+ var pary = []
+ var nodes = (node.parentNode && node.parentNode.childNodes);
+ for(var i = 0; i < nodes.length; i++){
+ if(nodes[i] != node){
+ pary.push(nodes[i]);
+ }
+ }
+ return pary;
+ }); //dojo.NodeList
+ },
+
+ next: function(/*String?*/query){
+ // summary:
+ // Returns the next element for nodes in this dojo.NodeList.
+ // Optionally takes a query to filter the next elements.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // query:
+ // a CSS selector.
+ // returns:
+ // dojo.NodeList, the next element for nodes in this dojo.NodeList.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | Some Text
+ // | <div class="blue first">Blue One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue last">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".first").next();
+ // returns the div with class "red" and has innerHTML of "Red Two".
+ // Running this code:
+ // | dojo.query(".last").next(".red");
+ // does not return any elements.
+ return this._getRelatedUniqueNodes(query, function(node, ary){
+ var next = node.nextSibling;
+ while(next && next.nodeType != 1){
+ next = next.nextSibling;
+ }
+ return next;
+ }); //dojo.NodeList
+ },
+
+ nextAll: function(/*String?*/query){
+ // summary:
+ // Returns all sibling elements that come after the nodes in this dojo.NodeList.
+ // Optionally takes a query to filter the sibling elements.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // query:
+ // a CSS selector.
+ // returns:
+ // dojo.NodeList, all sibling elements that come after the nodes in this dojo.NodeList.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | Some Text
+ // | <div class="blue first">Blue One</div>
+ // | <div class="red next">Red Two</div>
+ // | <div class="blue next">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".first").nextAll();
+ // returns the two divs with class of "next".
+ // Running this code:
+ // | dojo.query(".first").nextAll(".red");
+ // returns the one div with class "red" and innerHTML "Red Two".
+ return this._getRelatedUniqueNodes(query, function(node, ary){
+ var pary = []
+ var next = node;
+ while((next = next.nextSibling)){
+ if(next.nodeType == 1){
+ pary.push(next);
+ }
+ }
+ return pary;
+ }); //dojo.NodeList
+ },
+
+ prev: function(/*String?*/query){
+ // summary:
+ // Returns the previous element for nodes in this dojo.NodeList.
+ // Optionally takes a query to filter the previous elements.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // query:
+ // a CSS selector.
+ // returns:
+ // dojo.NodeList, the previous element for nodes in this dojo.NodeList.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | Some Text
+ // | <div class="blue first">Blue One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".first").prev();
+ // returns the div with class "red" and has innerHTML of "Red One".
+ // Running this code:
+ // | dojo.query(".first").prev(".blue");
+ // does not return any elements.
+ return this._getRelatedUniqueNodes(query, function(node, ary){
+ var prev = node.previousSibling;
+ while(prev && prev.nodeType != 1){
+ prev = prev.previousSibling;
+ }
+ return prev;
+ }); //dojo.NodeList
+ },
+
+ prevAll: function(/*String?*/query){
+ // summary:
+ // Returns all sibling elements that come before the nodes in this dojo.NodeList.
+ // Optionally takes a query to filter the sibling elements.
+ // description:
+ // The returned nodes will be in reverse DOM order -- the first node in the list will
+ // be the node closest to the original node/NodeList.
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // query:
+ // a CSS selector.
+ // returns:
+ // dojo.NodeList, all sibling elements that come before the nodes in this dojo.NodeList.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red prev">Red One</div>
+ // | Some Text
+ // | <div class="blue prev">Blue One</div>
+ // | <div class="red second">Red Two</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".second").prevAll();
+ // returns the two divs with class of "prev".
+ // Running this code:
+ // | dojo.query(".first").prevAll(".red");
+ // returns the one div with class "red prev" and innerHTML "Red One".
+ return this._getRelatedUniqueNodes(query, function(node, ary){
+ var pary = []
+ var prev = node;
+ while((prev = prev.previousSibling)){
+ if(prev.nodeType == 1){
+ pary.push(prev);
+ }
+ }
+ return pary;
+ }); //dojo.NodeList
+ },
+
+ andSelf: function(){
+ // summary:
+ // Adds the nodes from the previous dojo.NodeList to the current dojo.NodeList.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // returns:
+ // dojo.NodeList
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red prev">Red One</div>
+ // | Some Text
+ // | <div class="blue prev">Blue One</div>
+ // | <div class="red second">Red Two</div>
+ // | <div class="blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".second").prevAll().andSelf();
+ // returns the two divs with class of "prev", as well as the div with class "second".
+ return this.concat(this._parent);
+ },
+
+ //Alternate methods for the :first/:last/:even/:odd pseudos.
+ first: function(){
+ // summary:
+ // Returns the first node in this dojo.NodeList as a dojo.NodeList.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // returns:
+ // dojo.NodeList, with the first node in this dojo.NodeList
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | <div class="blue first">Blue One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue last">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".blue").first();
+ // returns the div with class "blue" and "first".
+ return this._wrap(((this[0] && [this[0]]) || []), this); //dojo.NodeList
+ },
+
+ last: function(){
+ // summary:
+ // Returns the last node in this dojo.NodeList as a dojo.NodeList.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // returns:
+ // dojo.NodeList, with the last node in this dojo.NodeList
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="red">Red One</div>
+ // | <div class="blue first">Blue One</div>
+ // | <div class="red">Red Two</div>
+ // | <div class="blue last">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".blue").last();
+ // returns the last div with class "blue",
+ return this._wrap((this.length ? [this[this.length - 1]] : []), this); //dojo.NodeList
+ },
+
+ even: function(){
+ // summary:
+ // Returns the even nodes in this dojo.NodeList as a dojo.NodeList.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // returns:
+ // dojo.NodeList, with the even nodes in this dojo.NodeList
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="interior red">Red One</div>
+ // | <div class="interior blue">Blue One</div>
+ // | <div class="interior red">Red Two</div>
+ // | <div class="interior blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".interior").even();
+ // returns the two divs with class "blue"
+ return this.filter(function(item, i){
+ return i % 2 != 0;
+ }); //dojo.NodeList
+ },
+
+ odd: function(){
+ // summary:
+ // Returns the odd nodes in this dojo.NodeList as a dojo.NodeList.
+ // description:
+ // .end() can be used on the returned dojo.NodeList to get back to the
+ // original dojo.NodeList.
+ // returns:
+ // dojo.NodeList, with the odd nodes in this dojo.NodeList
+ // example:
+ // assume a DOM created by this markup:
+ // | <div class="container">
+ // | <div class="interior red">Red One</div>
+ // | <div class="interior blue">Blue One</div>
+ // | <div class="interior red">Red Two</div>
+ // | <div class="interior blue">Blue Two</div>
+ // | </div>
+ // Running this code:
+ // | dojo.query(".interior").odd();
+ // returns the two divs with class "red"
+ return this.filter(function(item, i){
+ return i % 2 == 0;
+ }); //dojo.NodeList
+ }
});
-}});
+
}
diff --git a/lib/dojo/OpenAjax.js b/lib/dojo/OpenAjax.js
index a33e67d52..c777f3ea8 100644
--- a/lib/dojo/OpenAjax.js
+++ b/lib/dojo/OpenAjax.js
@@ -5,151 +5,197 @@
*/
+/*******************************************************************************
+ * 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(){
-var t=true;
-var f=false;
-var g=window;
-var _1;
-var _2="org.openajax.hub.";
-var h={};
-this.hub=h;
-h.implementer="http://openajax.org";
-h.implVersion="0.6";
-h.specVersion="0.6";
-h.implExtraData={};
-var _1={};
-h.libraries=_1;
-h.registerLibrary=function(_3,_4,_5,_6){
-_1[_3]={prefix:_3,namespaceURI:_4,version:_5,extraData:_6};
-this.publish(_2+"registerLibrary",_1[_3]);
-};
-h.unregisterLibrary=function(_7){
-this.publish(_2+"unregisterLibrary",_1[_7]);
-delete _1[_7];
-};
-h._subscriptions={c:{},s:[]};
-h._cleanup=[];
-h._subIndex=0;
-h._pubDepth=0;
-h.subscribe=function(_8,_9,_a,_b,_c){
-if(!_a){
-_a=window;
-}
-var _d=_8+"."+this._subIndex;
-var _e={scope:_a,cb:_9,fcb:_c,data:_b,sid:this._subIndex++,hdl:_d};
-var _f=_8.split(".");
-this._subscribe(this._subscriptions,_f,0,_e);
-return _d;
-};
-h.publish=function(_10,_11){
-var _12=_10.split(".");
-this._pubDepth++;
-this._publish(this._subscriptions,_12,0,_10,_11);
-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 _13=sub.split(".");
-var sid=_13.pop();
-this._unsubscribe(this._subscriptions,_13,0,sid);
-};
-h._subscribe=function(_14,_15,_16,sub){
-var _17=_15[_16];
-if(_16==_15.length){
-_14.s.push(sub);
-}else{
-if(typeof _14.c=="undefined"){
-_14.c={};
-}
-if(typeof _14.c[_17]=="undefined"){
-_14.c[_17]={c:{},s:[]};
-this._subscribe(_14.c[_17],_15,_16+1,sub);
-}else{
-this._subscribe(_14.c[_17],_15,_16+1,sub);
-}
-}
-};
-h._publish=function(_18,_19,_1a,_1b,msg){
-if(typeof _18!="undefined"){
-var _1c;
-if(_1a==_19.length){
-_1c=_18;
-}else{
-this._publish(_18.c[_19[_1a]],_19,_1a+1,_1b,msg);
-this._publish(_18.c["*"],_19,_1a+1,_1b,msg);
-_1c=_18.c["**"];
-}
-if(typeof _1c!="undefined"){
-var _1d=_1c.s;
-var max=_1d.length;
-for(var i=0;i<max;i++){
-if(_1d[i].cb){
-var sc=_1d[i].scope;
-var cb=_1d[i].cb;
-var fcb=_1d[i].fcb;
-var d=_1d[i].data;
-if(typeof cb=="string"){
-cb=sc[cb];
-}
-if(typeof fcb=="string"){
-fcb=sc[fcb];
-}
-if((!fcb)||(fcb.call(sc,_1b,msg,d))){
-cb.call(sc,_1b,msg,d);
-}
-}
-}
-}
-}
-};
-h._unsubscribe=function(_1e,_1f,_20,sid){
-if(typeof _1e!="undefined"){
-if(_20<_1f.length){
-var _21=_1e.c[_1f[_20]];
-this._unsubscribe(_21,_1f,_20+1,sid);
-if(_21.s.length==0){
-for(var x in _21.c){
-return;
-}
-delete _1e.c[_1f[_20]];
-}
-return;
-}else{
-var _22=_1e.s;
-var max=_22.length;
-for(var i=0;i<max;i++){
-if(sid==_22[i].sid){
-if(this._pubDepth>0){
-_22[i].cb=null;
-this._cleanup.push(_22[i]);
-}else{
-_22.splice(i,1);
-}
-return;
-}
-}
-}
-}
-};
-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;
-};
-};
-OpenAjax.hub.registerLibrary("OpenAjax","http://openajax.org/hub","0.6",{});
+ 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/lib/dojo/Stateful.js b/lib/dojo/Stateful.js
index 136b319c7..e4f406309 100644
--- a/lib/dojo/Stateful.js
+++ b/lib/dojo/Stateful.js
@@ -5,60 +5,130 @@
*/
-if(!dojo._hasResource["dojo.Stateful"]){
-dojo._hasResource["dojo.Stateful"]=true;
+if(!dojo._hasResource["dojo.Stateful"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.Stateful"] = true;
dojo.provide("dojo.Stateful");
-dojo.declare("dojo.Stateful",null,{postscript:function(_1){
-if(_1){
-dojo.mixin(this,_1);
-}
-},get:function(_2){
-return this[_2];
-},set:function(_3,_4){
-if(typeof _3==="object"){
-for(var x in _3){
-this.set(x,_3[x]);
-}
-return this;
-}
-var _5=this[_3];
-this[_3]=_4;
-if(this._watchCallbacks){
-this._watchCallbacks(_3,_5,_4);
-}
-return this;
-},watch:function(_6,_7){
-var _8=this._watchCallbacks;
-if(!_8){
-var _9=this;
-_8=this._watchCallbacks=function(_a,_b,_c,_d){
-var _e=function(_f){
-for(var i=0,l=_f&&_f.length;i<l;i++){
-try{
-_f[i].call(_9,_a,_b,_c);
-}
-catch(e){
-console.error(e);
-}
-}
-};
-_e(_8[_a]);
-if(!_d){
-_e(_8["*"]);
-}
-};
-}
-if(!_7&&typeof _6==="function"){
-_7=_6;
-_6="*";
-}
-var _10=_8[_6];
-if(typeof _10!=="object"){
-_10=_8[_6]=[];
-}
-_10.push(_7);
-return {unwatch:function(){
-_10.splice(dojo.indexOf(_10,_7),1);
-}};
-}});
+
+dojo.declare("dojo.Stateful", null, {
+ // summary:
+ // Base class for objects that provide named properties with optional getter/setter
+ // control and the ability to watch for property changes
+ // example:
+ // | var obj = new dojo.Stateful();
+ // | obj.watch("foo", function(){
+ // | console.log("foo changed to " + this.get("foo"));
+ // | });
+ // | obj.set("foo","bar");
+ postscript: function(mixin){
+ if(mixin){
+ dojo.mixin(this, mixin);
+ }
+ },
+
+ get: function(/*String*/name){
+ // summary:
+ // Get a property on a Stateful instance.
+ // name:
+ // The property to get.
+ // description:
+ // Get a named property on a Stateful object. The property may
+ // potentially be retrieved via a getter method in subclasses. In the base class
+ // this just retrieves the object's property.
+ // For example:
+ // | stateful = new dojo.Stateful({foo: 3});
+ // | stateful.get("foo") // returns 3
+ // | stateful.foo // returns 3
+
+ return this[name];
+ },
+ set: function(/*String*/name, /*Object*/value){
+ // summary:
+ // Set a property on a Stateful instance
+ // name:
+ // The property to set.
+ // value:
+ // The value to set in the property.
+ // description:
+ // Sets named properties on a stateful object and notifies any watchers of
+ // the property. A programmatic setter may be defined in subclasses.
+ // For example:
+ // | stateful = new dojo.Stateful();
+ // | stateful.watch(function(name, oldValue, value){
+ // | // this will be called on the set below
+ // | }
+ // | stateful.set(foo, 5);
+ //
+ // set() may also be called with a hash of name/value pairs, ex:
+ // | myObj.set({
+ // | foo: "Howdy",
+ // | bar: 3
+ // | })
+ // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
+ if(typeof name === "object"){
+ for(var x in name){
+ this.set(x, name[x]);
+ }
+ return this;
+ }
+ var oldValue = this[name];
+ this[name] = value;
+ if(this._watchCallbacks){
+ this._watchCallbacks(name, oldValue, value);
+ }
+ return this;
+ },
+ watch: function(/*String?*/name, /*Function*/callback){
+ // summary:
+ // Watches a property for changes
+ // name:
+ // Indicates the property to watch. This is optional (the callback may be the
+ // only parameter), and if omitted, all the properties will be watched
+ // returns:
+ // An object handle for the watch. The unwatch method of this object
+ // can be used to discontinue watching this property:
+ // | var watchHandle = obj.watch("foo", callback);
+ // | watchHandle.unwatch(); // callback won't be called now
+ // callback:
+ // The function to execute when the property changes. This will be called after
+ // the property has been changed. The callback will be called with the |this|
+ // set to the instance, the first argument as the name of the property, the
+ // second argument as the old value and the third argument as the new value.
+
+ var callbacks = this._watchCallbacks;
+ if(!callbacks){
+ var self = this;
+ callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
+ var notify = function(propertyCallbacks){
+ for(var i = 0, l = propertyCallbacks && propertyCallbacks.length; i < l; i++){
+ try{
+ propertyCallbacks[i].call(self, name, oldValue, value);
+ }catch(e){
+ console.error(e);
+ }
+ }
+ };
+ notify(callbacks[name]);
+ if(!ignoreCatchall){
+ notify(callbacks["*"]); // the catch-all
+ }
+ }; // we use a function instead of an object so it will be ignored by JSON conversion
+ }
+ if(!callback && typeof name === "function"){
+ callback = name;
+ name = "*";
+ }
+ var propertyCallbacks = callbacks[name];
+ if(typeof propertyCallbacks !== "object"){
+ propertyCallbacks = callbacks[name] = [];
+ }
+ propertyCallbacks.push(callback);
+ return {
+ unwatch: function(){
+ propertyCallbacks.splice(dojo.indexOf(propertyCallbacks, callback), 1);
+ }
+ };
+ }
+
+});
+
}
diff --git a/lib/dojo/_base.js b/lib/dojo/_base.js
index 73097400e..c77266788 100644
--- a/lib/dojo/_base.js
+++ b/lib/dojo/_base.js
@@ -5,8 +5,8 @@
*/
-if(!dojo._hasResource["dojo._base"]){
-dojo._hasResource["dojo._base"]=true;
+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.array");
@@ -15,5 +15,6 @@ dojo.require("dojo._base.connect");
dojo.require("dojo._base.Deferred");
dojo.require("dojo._base.json");
dojo.require("dojo._base.Color");
-dojo.requireIf(dojo.isBrowser,"dojo._base.browser");
+dojo.requireIf(dojo.isBrowser, "dojo._base.browser");
+
}
diff --git a/lib/dojo/_base/Color.js b/lib/dojo/_base/Color.js
index 0ee5888d1..5f5c5af9b 100644
--- a/lib/dojo/_base/Color.js
+++ b/lib/dojo/_base/Color.js
@@ -5,98 +5,223 @@
*/
-if(!dojo._hasResource["dojo._base.Color"]){
-dojo._hasResource["dojo._base.Color"]=true;
+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");
+
(function(){
-var d=dojo;
-dojo.Color=function(_1){
-if(_1){
-this.setColor(_1);
-}
-};
-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],transparent:d.config.transparentColor||[255,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(_2){
-if(d.isString(_2)){
-d.colorFromString(_2,this);
-}else{
-if(d.isArray(_2)){
-d.colorFromArray(_2,this);
-}else{
-this._set(_2.r,_2.g,_2.b,_2.a);
-if(!(_2 instanceof d.Color)){
-this.sanitize();
-}
-}
-}
-return this;
-},sanitize:function(){
-return this;
-},toRgb:function(){
-var t=this;
-return [t.r,t.g,t.b];
-},toRgba:function(){
-var t=this;
-return [t.r,t.g,t.b,t.a];
-},toHex:function(){
-var _3=d.map(["r","g","b"],function(x){
-var s=this[x].toString(16);
-return s.length<2?"0"+s:s;
-},this);
-return "#"+_3.join("");
-},toCss:function(_4){
-var t=this,_5=t.r+", "+t.g+", "+t.b;
-return (_4?"rgba("+_5+", "+t.a:"rgb("+_5)+")";
-},toString:function(){
-return this.toCss(true);
-}});
-dojo.blendColors=function(_6,_7,_8,_9){
-var t=_9||new d.Color();
-d.forEach(["r","g","b","a"],function(x){
-t[x]=_6[x]+(_7[x]-_6[x])*_8;
-if(x!="a"){
-t[x]=Math.round(t[x]);
-}
-});
-return t.sanitize();
-};
-dojo.colorFromRgb=function(_a,_b){
-var m=_a.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/);
-return m&&dojo.colorFromArray(m[1].split(/\s*,\s*/),_b);
-};
-dojo.colorFromHex=function(_c,_d){
-var t=_d||new d.Color(),_e=(_c.length==4)?4:8,_f=(1<<_e)-1;
-_c=Number("0x"+_c.substr(1));
-if(isNaN(_c)){
-return null;
-}
-d.forEach(["b","g","r"],function(x){
-var c=_c&_f;
-_c>>=_e;
-t[x]=_e==4?17*c:c;
-});
-t.a=1;
-return t;
-};
-dojo.colorFromArray=function(a,obj){
-var t=obj||new d.Color();
-t._set(Number(a[0]),Number(a[1]),Number(a[2]),Number(a[3]));
-if(isNaN(t.a)){
-t.a=1;
-}
-return t.sanitize();
-};
-dojo.colorFromString=function(str,obj){
-var a=d.Color.named[str];
-return a&&d.colorFromArray(a,obj)||d.colorFromRgb(str,obj)||d.colorFromHex(str,obj);
-};
+
+ var d = dojo;
+
+ 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
+ // and creates a new Color instance to work from.
+ //
+ // example:
+ // Work with a Color instance:
+ // | var c = new dojo.Color();
+ // | c.setColor([0,0,0]); // black
+ // | var hex = c.toHex(); // #000000
+ //
+ // example:
+ // Work with a node's color:
+ // | var color = dojo.style("someNode", "backgroundColor");
+ // | var n = new dojo.Color(color);
+ // | // adjust the color some
+ // | n.r *= .5;
+ // | console.log(n.toString()); // rgb(128, 255, 255);
+ 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],
+ transparent: d.config.transparentColor || [255,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
+ // and sets this color instance to that value.
+ //
+ // example:
+ // | var c = new dojo.Color(); // no color
+ // | c.setColor("#ededed"); // greyish
+ 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:
+ // Ensures the object has correct attributes
+ // description:
+ // the default implementation does nothing, include dojo.colors to
+ // augment it with real checks
+ return this; // dojo.Color
+ },
+ toRgb: function(){
+ // summary:
+ // Returns 3 component array of rgb values
+ // example:
+ // | var c = new dojo.Color("#000000");
+ // | console.log(c.toRgb()); // [0,0,0]
+ var t = this;
+ return [t.r, t.g, t.b]; // Array
+ },
+ toRgba: function(){
+ // summary:
+ // Returns a 4 component array of rgba values from the color
+ // represented by this object.
+ var t = this;
+ return [t.r, t.g, t.b, t.a]; // Array
+ },
+ toHex: function(){
+ // summary:
+ // Returns a CSS color string in hexadecimal representation
+ // example:
+ // | console.log(new dojo.Color([0,0,0]).toHex()); // #000000
+ var arr = d.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
+ // example:
+ // | var c = new dojo.Color("#FFF").toCss();
+ // | console.log(c); // rgb('255','255','255')
+ 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 t = obj || new d.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:
+ // Returns a `dojo.Color` instance from a string of the form
+ // "rgb(...)" or "rgba(...)". Optionally accepts a `dojo.Color`
+ // object to update with the parsed value and return instead of
+ // creating a new object.
+ // returns:
+ // A dojo.Color object. If obj is passed, it will be the return value.
+ 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. Optionally accepts a
+ // `dojo.Color` object to update with the parsed value.
+ //
+ // returns:
+ // A dojo.Color object. If obj is passed, it will be the return value.
+ //
+ // example:
+ // | var thing = dojo.colorFromHex("#ededed"); // grey, longhand
+ //
+ // example:
+ // | var thing = dojo.colorFromHex("#000"); // black, shorthand
+ var 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 `dojo.Color` from a 3 or 4 element array, mapping each
+ // element in sequence to the rgb(a) values of the color.
+ // example:
+ // | var myColor = dojo.colorFromArray([237,237,237,0.5]); // grey, 50% alpha
+ // returns:
+ // A dojo.Color object. If obj is passed, it will be the return value.
+ var t = obj || new d.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. Accepts hex, rgb, and rgba
+ // style color values.
+ // 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 = d.Color.named[str];
+ return a && d.colorFromArray(a, obj) || d.colorFromRgb(str, obj) || d.colorFromHex(str, obj);
+ };
})();
+
}
diff --git a/lib/dojo/_base/Deferred.js b/lib/dojo/_base/Deferred.js
index dfbabc4c0..3193024ab 100644
--- a/lib/dojo/_base/Deferred.js
+++ b/lib/dojo/_base/Deferred.js
@@ -5,126 +5,338 @@
*/
-if(!dojo._hasResource["dojo._base.Deferred"]){
-dojo._hasResource["dojo._base.Deferred"]=true;
+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");
+
(function(){
-var _1=function(){
-};
-var _2=Object.freeze||function(){
-};
-dojo.Deferred=function(_3){
-var _4,_5,_6,_7,_8;
-var _9=this.promise={};
-function _a(_b){
-if(_5){
-throw new Error("This deferred has already been resolved");
-}
-_4=_b;
-_5=true;
-_c();
-};
-function _c(){
-var _d;
-while(!_d&&_8){
-var _e=_8;
-_8=_8.next;
-if(_d=(_e.progress==_1)){
-_5=false;
-}
-var _f=(_6?_e.error:_e.resolved);
-if(_f){
-try{
-var _10=_f(_4);
-if(_10&&typeof _10.then==="function"){
-_10.then(dojo.hitch(_e.deferred,"resolve"),dojo.hitch(_e.deferred,"reject"));
-continue;
-}
-var _11=_d&&_10===undefined;
-_e.deferred[_11&&_6?"reject":"resolve"](_11?_4:_10);
-}
-catch(e){
-_e.deferred.reject(e);
-}
-}else{
-if(_6){
-_e.deferred.reject(_4);
-}else{
-_e.deferred.resolve(_4);
-}
-}
-}
-};
-this.resolve=this.callback=function(_12){
-this.fired=0;
-this.results=[_12,null];
-_a(_12);
-};
-this.reject=this.errback=function(_13){
-_6=true;
-this.fired=1;
-_a(_13);
-this.results=[null,_13];
-if(!_13||_13.log!==false){
-(dojo.config.deferredOnError||function(x){
-console.error(x);
-})(_13);
-}
-};
-this.progress=function(_14){
-var _15=_8;
-while(_15){
-var _16=_15.progress;
-_16&&_16(_14);
-_15=_15.next;
-}
-};
-this.addCallbacks=function(_17,_18){
-this.then(_17,_18,_1);
-return this;
-};
-this.then=_9.then=function(_19,_1a,_1b){
-var _1c=_1b==_1?this:new dojo.Deferred(_9.cancel);
-var _1d={resolved:_19,error:_1a,progress:_1b,deferred:_1c};
-if(_8){
-_7=_7.next=_1d;
-}else{
-_8=_7=_1d;
-}
-if(_5){
-_c();
-}
-return _1c.promise;
-};
-var _1e=this;
-this.cancel=_9.cancel=function(){
-if(!_5){
-var _1f=_3&&_3(_1e);
-if(!_5){
-if(!(_1f instanceof Error)){
-_1f=new Error(_1f);
-}
-_1f.log=false;
-_1e.reject(_1f);
-}
-}
-};
-_2(_9);
-};
-dojo.extend(dojo.Deferred,{addCallback:function(_20){
-return this.addCallbacks(dojo.hitch.apply(dojo,arguments));
-},addErrback:function(_21){
-return this.addCallbacks(null,dojo.hitch.apply(dojo,arguments));
-},addBoth:function(_22){
-var _23=dojo.hitch.apply(dojo,arguments);
-return this.addCallbacks(_23,_23);
-},fired:-1});
+ var mutator = function(){};
+ var freeze = Object.freeze || function(){};
+ // A deferred provides an API for creating and resolving a promise.
+ dojo.Deferred = function(/*Function?*/canceller){
+ // summary:
+ // Deferreds provide a generic means for encapsulating an asynchronous
+ // operation and notifying users of the completion and result of the operation.
+ // description:
+ // The dojo.Deferred API is based on the concept of promises that provide a
+ // generic interface into the eventual completion of an asynchronous action.
+ // The motivation for promises fundamentally is about creating a
+ // separation of concerns that allows one to achieve the same type of
+ // call patterns and logical data flow in asynchronous code as can be
+ // achieved in synchronous code. Promises allows one
+ // to be able to call a function purely with arguments needed for
+ // execution, without conflating the call with concerns of whether it is
+ // sync or async. One shouldn't need to alter a call's arguments if the
+ // implementation switches from sync to async (or vice versa). By having
+ // async functions return promises, the concerns of making the call are
+ // separated from the concerns of asynchronous interaction (which are
+ // handled by the promise).
+ //
+ // The dojo.Deferred is a type of promise that provides methods for fulfilling the
+ // promise with a successful result or an error. The most important method for
+ // working with Dojo's promises is the then() method, which follows the
+ // CommonJS proposed promise API. An example of using a Dojo promise:
+ //
+ // | var resultingPromise = someAsyncOperation.then(function(result){
+ // | ... handle result ...
+ // | },
+ // | function(error){
+ // | ... handle error ...
+ // | });
+ //
+ // The .then() call returns a new promise that represents the result of the
+ // execution of the callback. The callbacks will never affect the original promises value.
+ //
+ // The dojo.Deferred instances also provide the following functions for backwards compatibility:
+ //
+ // * addCallback(handler)
+ // * addErrback(handler)
+ // * callback(result)
+ // * errback(result)
+ //
+ // Callbacks are allowed to return promisesthemselves, 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).then(null, 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).then(null, function(){
+ // | promptUserToRecover();
+ // | });
+ //
+ // Note that the caller doesn't have to change his code at all to
+ // handle the asynchronous case.
+ var result, finished, isError, head, nextListener;
+ var promise = this.promise = {};
+
+ function complete(value){
+ if(finished){
+ throw new Error("This deferred has already been resolved");
+ }
+ result = value;
+ finished = true;
+ notify();
+ }
+ function notify(){
+ var mutated;
+ while(!mutated && nextListener){
+ var listener = nextListener;
+ nextListener = nextListener.next;
+ if(mutated = (listener.progress == mutator)){ // assignment and check
+ finished = false;
+ }
+ var func = (isError ? listener.error : listener.resolved);
+ if (func) {
+ try {
+ var newResult = func(result);
+ if (newResult && typeof newResult.then === "function") {
+ newResult.then(dojo.hitch(listener.deferred, "resolve"), dojo.hitch(listener.deferred, "reject"));
+ continue;
+ }
+ var unchanged = mutated && newResult === undefined;
+ listener.deferred[unchanged && isError ? "reject" : "resolve"](unchanged ? result : newResult);
+ }
+ catch (e) {
+ listener.deferred.reject(e);
+ }
+ }else {
+ if(isError){
+ listener.deferred.reject(result);
+ }else{
+ listener.deferred.resolve(result);
+ }
+ }
+ }
+ }
+ // calling resolve will resolve the promise
+ this.resolve = this.callback = function(value){
+ // summary:
+ // Fulfills the Deferred instance successfully with the provide value
+ this.fired = 0;
+ this.results = [value, null];
+ complete(value);
+ };
+
+
+ // calling error will indicate that the promise failed
+ this.reject = this.errback = function(error){
+ // summary:
+ // Fulfills the Deferred instance as an error with the provided error
+ isError = true;
+ this.fired = 1;
+ complete(error);
+ this.results = [null, error];
+ if(!error || error.log !== false){
+ (dojo.config.deferredOnError || function(x){ console.error(x); })(error);
+ }
+ };
+ // call progress to provide updates on the progress on the completion of the promise
+ this.progress = function(update){
+ // summary
+ // Send progress events to all listeners
+ var listener = nextListener;
+ while(listener){
+ var progress = listener.progress;
+ progress && progress(update);
+ listener = listener.next;
+ }
+ };
+ this.addCallbacks = function(/*Function?*/callback, /*Function?*/errback){
+ this.then(callback, errback, mutator);
+ return this;
+ };
+ // provide the implementation of the promise
+ this.then = promise.then = function(/*Function?*/resolvedCallback, /*Function?*/errorCallback, /*Function?*/progressCallback){
+ // summary
+ // Adds a fulfilledHandler, errorHandler, and progressHandler to be called for
+ // completion of a promise. The fulfilledHandler is called when the promise
+ // is fulfilled. The errorHandler is called when a promise fails. The
+ // progressHandler is called for progress events. All arguments are optional
+ // and non-function values are ignored. The progressHandler is not only an
+ // optional argument, but progress events are purely optional. Promise
+ // providers are not required to ever create progress events.
+ //
+ // This function will return a new promise that is fulfilled when the given
+ // fulfilledHandler or errorHandler callback is finished. This allows promise
+ // operations to be chained together. The value returned from the callback
+ // handler is the fulfillment value for the returned promise. If the callback
+ // throws an error, the returned promise will be moved to failed state.
+ //
+ // example:
+ // An example of using a CommonJS compliant promise:
+ // | asyncComputeTheAnswerToEverything().
+ // | then(addTwo).
+ // | then(printResult, onError);
+ // | >44
+ //
+ var returnDeferred = progressCallback == mutator ? this : new dojo.Deferred(promise.cancel);
+ var listener = {
+ resolved: resolvedCallback,
+ error: errorCallback,
+ progress: progressCallback,
+ deferred: returnDeferred
+ };
+ if(nextListener){
+ head = head.next = listener;
+ }
+ else{
+ nextListener = head = listener;
+ }
+ if(finished){
+ notify();
+ }
+ return returnDeferred.promise;
+ };
+ var deferred = this;
+ this.cancel = promise.cancel = function () {
+ // summary:
+ // Cancels the asynchronous operation
+ if(!finished){
+ var error = canceller && canceller(deferred);
+ if(!finished){
+ if (!(error instanceof Error)) {
+ error = new Error(error);
+ }
+ error.log = false;
+ deferred.reject(error);
+ }
+ }
+ }
+ freeze(promise);
+ };
+ dojo.extend(dojo.Deferred, {
+ addCallback: function (/*Function*/callback) {
+ return this.addCallbacks(dojo.hitch.apply(dojo, arguments));
+ },
+
+ addErrback: function (/*Function*/errback) {
+ return this.addCallbacks(null, dojo.hitch.apply(dojo, arguments));
+ },
+
+ addBoth: function (/*Function*/callback) {
+ var enclosed = dojo.hitch.apply(dojo, arguments);
+ return this.addCallbacks(enclosed, enclosed);
+ },
+ fired: -1
+ });
})();
-dojo.when=function(_24,_25,_26,_27){
-if(_24&&typeof _24.then==="function"){
-return _24.then(_25,_26,_27);
-}
-return _25(_24);
+dojo.when = function(promiseOrValue, /*Function?*/callback, /*Function?*/errback, /*Function?*/progressHandler){
+ // summary:
+ // This provides normalization between normal synchronous values and
+ // asynchronous promises, so you can interact with them in a common way
+ // example:
+ // | function printFirstAndList(items){
+ // | dojo.when(findFirst(items), console.log);
+ // | dojo.when(findLast(items), console.log);
+ // | }
+ // | function findFirst(items){
+ // | return dojo.when(items, function(items){
+ // | return items[0];
+ // | });
+ // | }
+ // | function findLast(items){
+ // | return dojo.when(items, function(items){
+ // | return items[items.length];
+ // | });
+ // | }
+ // And now all three of his functions can be used sync or async.
+ // | printFirstAndLast([1,2,3,4]) will work just as well as
+ // | printFirstAndLast(dojo.xhrGet(...));
+
+ if(promiseOrValue && typeof promiseOrValue.then === "function"){
+ return promiseOrValue.then(callback, errback, progressHandler);
+ }
+ return callback(promiseOrValue);
};
+
}
diff --git a/lib/dojo/_base/NodeList.js b/lib/dojo/_base/NodeList.js
index 6df6db976..12b631a4b 100644
--- a/lib/dojo/_base/NodeList.js
+++ b/lib/dojo/_base/NodeList.js
@@ -5,228 +5,1012 @@
*/
-if(!dojo._hasResource["dojo._base.NodeList"]){
-dojo._hasResource["dojo._base.NodeList"]=true;
+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 ap=Array.prototype,_1=ap.slice,_2=ap.concat;
-var _3=function(a,_4,_5){
-if(!a.sort){
-a=_1.call(a,0);
-}
-var _6=_5||this._NodeListCtor||d._NodeListCtor;
-a.constructor=_6;
-dojo._mixin(a,_6.prototype);
-a._NodeListCtor=_6;
-return _4?a._stash(_4):a;
-};
-var _7=function(f,a,o){
-a=[0].concat(_1.call(a,0));
-o=o||d.global;
-return function(_8){
-a[0]=_8;
-return f.apply(o,a);
-};
-};
-var _9=function(f,o){
-return function(){
-this.forEach(_7(f,arguments,o));
-return this;
-};
-};
-var _a=function(f,o){
-return function(){
-return this.map(_7(f,arguments,o));
-};
-};
-var _b=function(f,o){
-return function(){
-return this.filter(_7(f,arguments,o));
-};
-};
-var _c=function(f,g,o){
-return function(){
-var a=arguments,_d=_7(f,a,o);
-if(g.call(o||d.global,a)){
-return this.map(_d);
-}
-this.forEach(_d);
-return this;
-};
-};
-var _e=function(a){
-return a.length==1&&(typeof a[0]=="string");
-};
-var _f=function(_10){
-var p=_10.parentNode;
-if(p){
-p.removeChild(_10);
-}
-};
-dojo.NodeList=function(){
-return _3(Array.apply(null,arguments));
-};
-d._NodeListCtor=d.NodeList;
-var nl=d.NodeList,nlp=nl.prototype;
-nl._wrap=nlp._wrap=_3;
-nl._adaptAsMap=_a;
-nl._adaptAsForEach=_9;
-nl._adaptAsFilter=_b;
-nl._adaptWithCondition=_c;
-d.forEach(["slice","splice"],function(_11){
-var f=ap[_11];
-nlp[_11]=function(){
-return this._wrap(f.apply(this,arguments),_11=="slice"?this:null);
-};
-});
-d.forEach(["indexOf","lastIndexOf","every","some"],function(_12){
-var f=d[_12];
-nlp[_12]=function(){
-return f.apply(d,[this].concat(_1.call(arguments,0)));
-};
-});
-d.forEach(["attr","style"],function(_13){
-nlp[_13]=_c(d[_13],_e);
-});
-d.forEach(["connect","addClass","removeClass","toggleClass","empty","removeAttr"],function(_14){
-nlp[_14]=_9(d[_14]);
-});
-dojo.extend(dojo.NodeList,{_normalize:function(_15,_16){
-var _17=_15.parse===true?true:false;
-if(typeof _15.template=="string"){
-var _18=_15.templateFunc||(dojo.string&&dojo.string.substitute);
-_15=_18?_18(_15.template,_15):_15;
-}
-var _19=(typeof _15);
-if(_19=="string"||_19=="number"){
-_15=dojo._toDom(_15,(_16&&_16.ownerDocument));
-if(_15.nodeType==11){
-_15=dojo._toArray(_15.childNodes);
-}else{
-_15=[_15];
-}
-}else{
-if(!dojo.isArrayLike(_15)){
-_15=[_15];
-}else{
-if(!dojo.isArray(_15)){
-_15=dojo._toArray(_15);
-}
-}
-}
-if(_17){
-_15._runParse=true;
-}
-return _15;
-},_cloneNode:function(_1a){
-return _1a.cloneNode(true);
-},_place:function(ary,_1b,_1c,_1d){
-if(_1b.nodeType!=1&&_1c=="only"){
-return;
-}
-var _1e=_1b,_1f;
-var _20=ary.length;
-for(var i=_20-1;i>=0;i--){
-var _21=(_1d?this._cloneNode(ary[i]):ary[i]);
-if(ary._runParse&&dojo.parser&&dojo.parser.parse){
-if(!_1f){
-_1f=_1e.ownerDocument.createElement("div");
-}
-_1f.appendChild(_21);
-dojo.parser.parse(_1f);
-_21=_1f.firstChild;
-while(_1f.firstChild){
-_1f.removeChild(_1f.firstChild);
-}
-}
-if(i==_20-1){
-dojo.place(_21,_1e,_1c);
-}else{
-_1e.parentNode.insertBefore(_21,_1e);
-}
-_1e=_21;
-}
-},_stash:function(_22){
-this._parent=_22;
-return this;
-},end:function(){
-if(this._parent){
-return this._parent;
-}else{
-return new this._NodeListCtor();
-}
-},concat:function(_23){
-var t=d.isArray(this)?this:_1.call(this,0),m=d.map(arguments,function(a){
-return a&&!d.isArray(a)&&(typeof NodeList!="undefined"&&a.constructor===NodeList||a.constructor===this._NodeListCtor)?_1.call(a,0):a;
-});
-return this._wrap(_2.apply(t,m),this);
-},map:function(_24,obj){
-return this._wrap(d.map(this,_24,obj),this);
-},forEach:function(_25,_26){
-d.forEach(this,_25,_26);
-return this;
-},coords:_a(d.coords),position:_a(d.position),place:function(_27,_28){
-var _29=d.query(_27)[0];
-return this.forEach(function(_2a){
-d.place(_2a,_29,_28);
-});
-},orphan:function(_2b){
-return (_2b?d._filterQueryResult(this,_2b):this).forEach(_f);
-},adopt:function(_2c,_2d){
-return d.query(_2c).place(this[0],_2d)._stash(this);
-},query:function(_2e){
-if(!_2e){
-return this;
-}
-var ret=this.map(function(_2f){
-return d.query(_2e,_2f).filter(function(_30){
-return _30!==undefined;
-});
-});
-return this._wrap(_2.apply([],ret),this);
-},filter:function(_31){
-var a=arguments,_32=this,_33=0;
-if(typeof _31=="string"){
-_32=d._filterQueryResult(this,a[0]);
-if(a.length==1){
-return _32._stash(this);
-}
-_33=1;
-}
-return this._wrap(d.filter(_32,a[_33],a[_33+1]),this);
-},addContent:function(_34,_35){
-_34=this._normalize(_34,this[0]);
-for(var i=0,_36;_36=this[i];i++){
-this._place(_34,_36,_35,i>0);
-}
-return this;
-},instantiate:function(_37,_38){
-var c=d.isFunction(_37)?_37:d.getObject(_37);
-_38=_38||{};
-return this.forEach(function(_39){
-new c(_38,_39);
-});
-},at:function(){
-var t=new this._NodeListCtor();
-d.forEach(arguments,function(i){
-if(i<0){
-i=this.length+i;
-}
-if(this[i]){
-t.push(this[i]);
-}
-},this);
-return t._stash(this);
-}});
-nl.events=["blur","focus","change","click","error","keydown","keypress","keyup","load","mousedown","mouseenter","mouseleave","mousemove","mouseout","mouseover","mouseup","submit"];
-d.forEach(nl.events,function(evt){
-var _3a="on"+evt;
-nlp[_3a]=function(a,b){
-return this.connect(_3a,a,b);
-};
-});
+
+ var d = dojo;
+
+ var ap = Array.prototype, aps = ap.slice, apc = ap.concat;
+
+ var tnl = function(/*Array*/ a, /*dojo.NodeList?*/ parent, /*Function?*/ NodeListCtor){
+ // summary:
+ // decorate an array to make it look like a `dojo.NodeList`.
+ // a:
+ // Array of nodes to decorate.
+ // parent:
+ // An optional parent NodeList that generated the current
+ // list of nodes. Used to call _stash() so the parent NodeList
+ // can be accessed via end() later.
+ // NodeListCtor:
+ // An optional constructor function to use for any
+ // new NodeList calls. This allows a certain chain of
+ // NodeList calls to use a different object than dojo.NodeList.
+ if(!a.sort){
+ // make sure it's a real array before we pass it on to be wrapped
+ a = aps.call(a, 0);
+ }
+ var ctor = NodeListCtor || this._NodeListCtor || d._NodeListCtor;
+ a.constructor = ctor;
+ dojo._mixin(a, ctor.prototype);
+ a._NodeListCtor = ctor;
+ return parent ? a._stash(parent) : a;
+ };
+
+ var loopBody = function(f, a, o){
+ a = [0].concat(aps.call(a, 0));
+ o = o || d.global;
+ return function(node){
+ a[0] = node;
+ return f.apply(o, a);
+ };
+ };
+
+ // adapters
+
+ var adaptAsForEach = function(f, o){
+ // summary:
+ // adapts a single node function to be used in the forEach-type
+ // actions. The initial object is returned from the specialized
+ // function.
+ // f: Function
+ // a function to adapt
+ // o: Object?
+ // an optional context for f
+ return function(){
+ this.forEach(loopBody(f, arguments, o));
+ return this; // Object
+ };
+ };
+
+ var adaptAsMap = function(f, o){
+ // summary:
+ // adapts a single node function to be used in the map-type
+ // actions. The return is a new array of values, as via `dojo.map`
+ // f: Function
+ // a function to adapt
+ // o: Object?
+ // an optional context for f
+ return function(){
+ return this.map(loopBody(f, arguments, o));
+ };
+ };
+
+ var adaptAsFilter = function(f, o){
+ // summary:
+ // adapts a single node function to be used in the filter-type actions
+ // f: Function
+ // a function to adapt
+ // o: Object?
+ // an optional context for f
+ return function(){
+ return this.filter(loopBody(f, arguments, o));
+ };
+ };
+
+ var adaptWithCondition = function(f, g, o){
+ // summary:
+ // adapts a single node function to be used in the map-type
+ // actions, behaves like forEach() or map() depending on arguments
+ // f: Function
+ // a function to adapt
+ // g: Function
+ // a condition function, if true runs as map(), otherwise runs as forEach()
+ // o: Object?
+ // an optional context for f and g
+ return function(){
+ var a = arguments, body = loopBody(f, a, o);
+ if(g.call(o || d.global, a)){
+ return this.map(body); // self
+ }
+ this.forEach(body);
+ return this; // self
+ };
+ };
+
+ var magicGuard = function(a){
+ // summary:
+ // the guard function for dojo.attr() and dojo.style()
+ return a.length == 1 && (typeof a[0] == "string"); // inline'd type check
+ };
+
+ var orphan = function(node){
+ // summary:
+ // function to orphan nodes
+ var p = node.parentNode;
+ if(p){
+ p.removeChild(node);
+ }
+ };
+ // FIXME: should we move orphan() to dojo.html?
+
+ dojo.NodeList = function(){
+ // summary:
+ // dojo.NodeList is an of Array subclass 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.
+ // description:
+ // dojo.NodeList instances provide many utilities that reflect
+ // core Dojo APIs for Array iteration and manipulation, DOM
+ // manipulation, and event handling. Instead of needing to dig up
+ // functions in the dojo.* namespace, NodeLists generally make the
+ // full power of Dojo available for DOM manipulation tasks in a
+ // simple, chainable way.
+ // example:
+ // create a node list from a node
+ // | new dojo.NodeList(dojo.byId("foo"));
+ // example:
+ // get a NodeList from a CSS query and iterate on it
+ // | var l = dojo.query(".thinger");
+ // | l.forEach(function(node, index, nodeList){
+ // | console.log(index, node.innerHTML);
+ // | });
+ // example:
+ // use native and Dojo-provided array methods to manipulate a
+ // NodeList without needing to use dojo.* functions explicitly:
+ // | var l = dojo.query(".thinger");
+ // | // since NodeLists are real arrays, they have a length
+ // | // property that is both readable and writable and
+ // | // push/pop/shift/unshift methods
+ // | console.log(l.length);
+ // | l.push(dojo.create("span"));
+ // |
+ // | // dojo's normalized array methods work too:
+ // | console.log( l.indexOf(dojo.byId("foo")) );
+ // | // ...including the special "function as string" shorthand
+ // | console.log( l.every("item.nodeType == 1") );
+ // |
+ // | // NodeLists can be [..] indexed, or you can use the at()
+ // | // function to get specific items wrapped in a new NodeList:
+ // | var node = l[3]; // the 4th element
+ // | var newList = l.at(1, 3); // the 2nd and 4th elements
+ // example:
+ // the style functions you expect are all there too:
+ // | // style() as a getter...
+ // | var borders = dojo.query(".thinger").style("border");
+ // | // ...and as a setter:
+ // | dojo.query(".thinger").style("border", "1px solid black");
+ // | // class manipulation
+ // | dojo.query("li:nth-child(even)").addClass("even");
+ // | // even getting the coordinates of all the items
+ // | var coords = dojo.query(".thinger").coords();
+ // example:
+ // DOM manipulation functions from the dojo.* namespace area also
+ // available:
+ // | // remove all of the elements in the list from their
+ // | // parents (akin to "deleting" them from the document)
+ // | dojo.query(".thinger").orphan();
+ // | // place all elements in the list at the front of #foo
+ // | dojo.query(".thinger").place("foo", "first");
+ // example:
+ // Event handling couldn't be easier. `dojo.connect` is mapped in,
+ // and shortcut handlers are provided for most DOM events:
+ // | // like dojo.connect(), but with implicit scope
+ // | dojo.query("li").connect("onclick", console, "log");
+ // |
+ // | // many common event handlers are already available directly:
+ // | dojo.query("li").onclick(console, "log");
+ // | var toggleHovered = dojo.hitch(dojo, "toggleClass", "hovered");
+ // | dojo.query("p")
+ // | .onmouseenter(toggleHovered)
+ // | .onmouseleave(toggleHovered);
+ // example:
+ // chainability is a key advantage of NodeLists:
+ // | dojo.query(".thinger")
+ // | .onclick(function(e){ /* ... */ })
+ // | .at(1, 3, 8) // get a subset
+ // | .style("padding", "5px")
+ // | .forEach(console.log);
+
+ return tnl(Array.apply(null, arguments));
+ };
+
+ //Allow things that new up a NodeList to use a delegated or alternate NodeList implementation.
+ d._NodeListCtor = d.NodeList;
+
+ var nl = d.NodeList, nlp = nl.prototype;
+
+ // expose adapters and the wrapper as private functions
+
+ nl._wrap = nlp._wrap = tnl;
+ nl._adaptAsMap = adaptAsMap;
+ nl._adaptAsForEach = adaptAsForEach;
+ nl._adaptAsFilter = adaptAsFilter;
+ nl._adaptWithCondition = adaptWithCondition;
+
+ // mass assignment
+
+ // add array redirectors
+ d.forEach(["slice", "splice"], function(name){
+ var f = ap[name];
+ //Use a copy of the this array via this.slice() to allow .end() to work right in the splice case.
+ // CANNOT apply ._stash()/end() to splice since it currently modifies
+ // the existing this array -- it would break backward compatibility if we copy the array before
+ // the splice so that we can use .end(). So only doing the stash option to this._wrap for slice.
+ nlp[name] = function(){ return this._wrap(f.apply(this, arguments), name == "slice" ? this : null); };
+ });
+ // concat should be here but some browsers with native NodeList have problems with it
+
+ // add array.js redirectors
+ d.forEach(["indexOf", "lastIndexOf", "every", "some"], function(name){
+ var f = d[name];
+ nlp[name] = function(){ return f.apply(d, [this].concat(aps.call(arguments, 0))); };
+ });
+
+ // add conditional methods
+ d.forEach(["attr", "style"], function(name){
+ nlp[name] = adaptWithCondition(d[name], magicGuard);
+ });
+
+ // add forEach actions
+ d.forEach(["connect", "addClass", "removeClass", "toggleClass", "empty", "removeAttr"], function(name){
+ nlp[name] = adaptAsForEach(d[name]);
+ });
+
+ dojo.extend(dojo.NodeList, {
+ _normalize: function(/*String||Element||Object||NodeList*/content, /*DOMNode?*/refNode){
+ // summary:
+ // normalizes data to an array of items to insert.
+ // description:
+ // If content is an object, it can have special properties "template" and
+ // "parse". If "template" is defined, then the template value is run through
+ // dojo.string.substitute (if dojo.string.substitute has been dojo.required elsewhere),
+ // or if templateFunc is a function on the content, that function will be used to
+ // transform the template into a final string to be used for for passing to dojo._toDom.
+ // If content.parse is true, then it is remembered for later, for when the content
+ // nodes are inserted into the DOM. At that point, the nodes will be parsed for widgets
+ // (if dojo.parser has been dojo.required elsewhere).
+
+ //Wanted to just use a DocumentFragment, but for the array/NodeList
+ //case that meant using cloneNode, but we may not want that.
+ //Cloning should only happen if the node operations span
+ //multiple refNodes. Also, need a real array, not a NodeList from the
+ //DOM since the node movements could change those NodeLists.
+
+ var parse = content.parse === true ? true : false;
+
+ //Do we have an object that needs to be run through a template?
+ if(typeof content.template == "string"){
+ var templateFunc = content.templateFunc || (dojo.string && dojo.string.substitute);
+ content = templateFunc ? templateFunc(content.template, content) : content;
+ }
+
+ var type = (typeof content);
+ if(type == "string" || type == "number"){
+ content = dojo._toDom(content, (refNode && refNode.ownerDocument));
+ if(content.nodeType == 11){
+ //DocumentFragment. It cannot handle cloneNode calls, so pull out the children.
+ content = dojo._toArray(content.childNodes);
+ }else{
+ content = [content];
+ }
+ }else if(!dojo.isArrayLike(content)){
+ content = [content];
+ }else if(!dojo.isArray(content)){
+ //To get to this point, content is array-like, but
+ //not an array, which likely means a DOM NodeList. Convert it now.
+ content = dojo._toArray(content);
+ }
+
+ //Pass around the parse info
+ if(parse){
+ content._runParse = true;
+ }
+ return content; //Array
+ },
+
+ _cloneNode: function(/*DOMNode*/ node){
+ // summary:
+ // private utiltity to clone a node. Not very interesting in the vanilla
+ // dojo.NodeList case, but delegates could do interesting things like
+ // clone event handlers if that is derivable from the node.
+ return node.cloneNode(true);
+ },
+
+ _place: function(/*Array*/ary, /*DOMNode*/refNode, /*String*/position, /*Boolean*/useClone){
+ // summary:
+ // private utility to handle placing an array of nodes relative to another node.
+ // description:
+ // Allows for cloning the nodes in the array, and for
+ // optionally parsing widgets, if ary._runParse is true.
+
+ //Avoid a disallowed operation if trying to do an innerHTML on a non-element node.
+ if(refNode.nodeType != 1 && position == "only"){
+ return;
+ }
+ var rNode = refNode, tempNode;
+
+ //Always cycle backwards in case the array is really a
+ //DOM NodeList and the DOM operations take it out of the live collection.
+ var length = ary.length;
+ for(var i = length - 1; i >= 0; i--){
+ var node = (useClone ? this._cloneNode(ary[i]) : ary[i]);
+
+ //If need widget parsing, use a temp node, instead of waiting after inserting into
+ //real DOM because we need to start widget parsing at one node up from current node,
+ //which could cause some already parsed widgets to be parsed again.
+ if(ary._runParse && dojo.parser && dojo.parser.parse){
+ if(!tempNode){
+ tempNode = rNode.ownerDocument.createElement("div");
+ }
+ tempNode.appendChild(node);
+ dojo.parser.parse(tempNode);
+ node = tempNode.firstChild;
+ while(tempNode.firstChild){
+ tempNode.removeChild(tempNode.firstChild);
+ }
+ }
+
+ if(i == length - 1){
+ dojo.place(node, rNode, position);
+ }else{
+ rNode.parentNode.insertBefore(node, rNode);
+ }
+ rNode = node;
+ }
+ },
+
+ _stash: function(parent){
+ // summary:
+ // private function to hold to a parent NodeList. end() to return the parent NodeList.
+ //
+ // example:
+ // How to make a `dojo.NodeList` method that only returns the third node in
+ // the dojo.NodeList but allows access to the original NodeList by using this._stash:
+ // | dojo.extend(dojo.NodeList, {
+ // | third: function(){
+ // | var newNodeList = dojo.NodeList(this[2]);
+ // | return newNodeList._stash(this);
+ // | }
+ // | });
+ // | // then see how _stash applies a sub-list, to be .end()'ed out of
+ // | dojo.query(".foo")
+ // | .third()
+ // | .addClass("thirdFoo")
+ // | .end()
+ // | // access to the orig .foo list
+ // | .removeClass("foo")
+ // |
+ //
+ this._parent = parent;
+ return this; //dojo.NodeList
+ },
+
+ end: function(){
+ // summary:
+ // Ends use of the current `dojo.NodeList` by returning the previous dojo.NodeList
+ // that generated the current dojo.NodeList.
+ // description:
+ // Returns the `dojo.NodeList` that generated the current `dojo.NodeList`. If there
+ // is no parent dojo.NodeList, an empty dojo.NodeList is returned.
+ // example:
+ // | dojo.query("a")
+ // | .filter(".disabled")
+ // | // operate on the anchors that only have a disabled class
+ // | .style("color", "grey")
+ // | .end()
+ // | // jump back to the list of anchors
+ // | .style(...)
+ //
+ if(this._parent){
+ return this._parent;
+ }else{
+ //Just return empy list.
+ return new this._NodeListCtor();
+ }
+ },
+
+ // 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 Mozilla's (slice
+ // documentation)[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.
+ return this._wrap(a.slice.apply(this, arguments));
+ },
+
+ 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 Mozilla's (splice
+ // documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice]
+ // For backwards compatibility, calling .end() on the spliced NodeList
+ // does not return the original NodeList -- splice alters the NodeList in place.
+ // 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
+ return this._wrap(a.splice.apply(this, arguments));
+ },
+
+ indexOf: function(value, fromIndex){
+ // summary:
+ // see dojo.indexOf(). The primary difference is that the acted-on
+ // array is implicitly this NodeList
+ // value: Object:
+ // The value to search for.
+ // fromIndex: Integer?:
+ // The loction to start searching from. Optional. Defaults to 0.
+ // description:
+ // For more details on the behavior of indexOf, see Mozilla's
+ // (indexOf
+ // docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf]
+ // returns:
+ // Positive Integer or 0 for a match, -1 of not found.
+ return d.indexOf(this, value, fromIndex); // Integer
+ },
+
+ lastIndexOf: function(value, fromIndex){
+ // summary:
+ // see dojo.lastIndexOf(). The primary difference is that the
+ // acted-on array is implicitly this NodeList
+ // description:
+ // For more details on the behavior of lastIndexOf, see
+ // Mozilla's (lastIndexOf
+ // docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf]
+ // value: Object
+ // The value to search for.
+ // fromIndex: Integer?
+ // The loction to start searching from. Optional. Defaults to 0.
+ // returns:
+ // Positive Integer or 0 for a match, -1 of not found.
+ return d.lastIndexOf(this, value, fromIndex); // Integer
+ },
+
+ every: function(callback, thisObject){
+ // summary:
+ // see `dojo.every()` and the (Array.every
+ // docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every].
+ // Takes the same structure of arguments and returns as
+ // dojo.every() with the caveat that the passed array is
+ // implicitly this NodeList
+ // callback: Function: the callback
+ // thisObject: Object?: the context
+ return d.every(this, callback, thisObject); // Boolean
+ },
+
+ some: function(callback, thisObject){
+ // summary:
+ // Takes the same structure of arguments and returns as
+ // `dojo.some()` with the caveat that the passed array is
+ // implicitly this NodeList. See `dojo.some()` and Mozilla's
+ // (Array.some
+ // documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some].
+ // callback: Function: the callback
+ // thisObject: Object?: the context
+ return d.some(this, callback, thisObject); // Boolean
+ },
+ =====*/
+
+ 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 the (Array.concat
+ // docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat]
+ // item: Object?
+ // Any number of optional parameters may be passed in to be
+ // spliced into the NodeList
+ // returns:
+ // dojo.NodeList
+
+ //return this._wrap(apc.apply(this, arguments));
+ // the line above won't work for the native NodeList :-(
+
+ // implementation notes:
+ // 1) Native NodeList is not an array, and cannot be used directly
+ // in concat() --- the latter doesn't recognize it as an array, and
+ // does not inline it, but append as a single entity.
+ // 2) On some browsers (e.g., Safari) the "constructor" property is
+ // read-only and cannot be changed. So we have to test for both
+ // native NodeList and dojo.NodeList in this property to recognize
+ // the node list.
+
+ var t = d.isArray(this) ? this : aps.call(this, 0),
+ m = d.map(arguments, function(a){
+ return a && !d.isArray(a) &&
+ (typeof NodeList != "undefined" && a.constructor === NodeList || a.constructor === this._NodeListCtor) ?
+ aps.call(a, 0) : a;
+ });
+ return this._wrap(apc.apply(t, m), this); // dojo.NodeList
+ },
+
+ 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
+ return this._wrap(d.map(this, func, obj), this); // dojo.NodeList
+ },
+
+ forEach: function(callback, thisObj){
+ // summary:
+ // see `dojo.forEach()`. The primary difference is that the acted-on
+ // array is implicitly this NodeList. If you want the option to break out
+ // of the forEach loop, use every() or some() instead.
+ d.forEach(this, callback, thisObj);
+ // non-standard return to allow easier chaining
+ return this; // dojo.NodeList
+ },
+
+ /*=====
+ coords: function(){
+ // summary:
+ // Returns the box objects of all elements in a node list as
+ // an Array (*not* a NodeList). Acts like `dojo.coords`, though assumes
+ // the node passed is each node in this list.
+
+ return d.map(this, d.coords); // Array
+ },
+
+ position: function(){
+ // summary:
+ // Returns border-box objects (x/y/w/h) of all elements in a node list
+ // as an Array (*not* a NodeList). Acts like `dojo.position`, though
+ // assumes the node passed is each node in this list.
+
+ return d.map(this, d.position); // Array
+ },
+
+ attr: function(property, value){
+ // summary:
+ // gets or sets the DOM attribute for every element in the
+ // NodeList. See also `dojo.attr`
+ // property: String
+ // the attribute to get/set
+ // value: String?
+ // optional. The value to set the property to
+ // returns:
+ // if no value is passed, the result is an array of attribute values
+ // If a value is passed, the return is this NodeList
+ // example:
+ // Make all nodes with a particular class focusable:
+ // | dojo.query(".focusable").attr("tabIndex", -1);
+ // example:
+ // Disable a group of buttons:
+ // | dojo.query("button.group").attr("disabled", true);
+ // example:
+ // innerHTML can be assigned or retreived as well:
+ // | // get the innerHTML (as an array) for each list item
+ // | var ih = dojo.query("li.replaceable").attr("innerHTML");
+ return; // dojo.NodeList
+ return; // Array
+ },
+
+ 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
+ // returns:
+ // if no value is passed, the result is an array of strings.
+ // If a value is passed, the return is this NodeList
+ return; // dojo.NodeList
+ return; // Array
+ },
+
+ addClass: function(className){
+ // summary:
+ // adds the specified class to every node in the list
+ // className: String|Array
+ // A String class name to add, or several space-separated class names,
+ // or an array of class names.
+ return; // dojo.NodeList
+ },
+
+ removeClass: function(className){
+ // summary:
+ // removes the specified class from every node in the list
+ // className: String|Array?
+ // An optional String class name to remove, or several space-separated
+ // class names, or an array of class names. If omitted, all class names
+ // will be deleted.
+ // returns:
+ // dojo.NodeList, this list
+ return; // dojo.NodeList
+ },
+
+ 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
+ },
+
+ 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.log("clicked!");
+ // | });
+ // example:
+ // attach foo.bar() to every odd div's onmouseover
+ // | dojo.query("div:nth-child(odd)").connect("onmouseover", foo, "bar");
+ },
+
+ empty: function(){
+ // summary:
+ // clears all content from each node in the list. Effectively
+ // equivalent to removing all child nodes from every item in
+ // the list.
+ return this.forEach("item.innerHTML='';"); // dojo.NodeList
+ // FIXME: should we be checking for and/or disposing of widgets below these nodes?
+ },
+ =====*/
+
+ // useful html methods
+ coords: adaptAsMap(d.coords),
+ position: adaptAsMap(d.position),
+
+ // FIXME: connectPublisher()? connectRunOnce()?
+
+ /*
+ destroy: function(){
+ // summary:
+ // destroys every item in the list.
+ this.forEach(d.destroy);
+ // FIXME: should we be checking for and/or disposing of widgets below these nodes?
+ },
+ */
+
+ 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. See: `dojo.place`
+ // 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" (default)
+ // | "first"
+ // | "before"
+ // | "after"
+ // | "only"
+ // | "replace"
+ // or an offset in the childNodes property
+ var item = d.query(queryOrNode)[0];
+ return this.forEach(function(node){ d.place(node, item, position); }); // 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 rule. For example, ".thinger" or
+ // "#someId[attrName='value']" but not "div > span". In short,
+ // anything which does not invoke a descent to evaluate but
+ // can instead be used to test a single node is acceptable.
+ // returns:
+ // `dojo.NodeList` containing the orpahned elements
+ return (simpleFilter ? d._filterQueryResult(this, simpleFilter) : this).forEach(orphan); // 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" (default)
+ // | "first"
+ // | "before"
+ // | "after"
+ // | "only"
+ // | "replace"
+ // or an offset in the childNodes property
+ return d.query(queryOrListOrNode).place(this[0], position)._stash(this); // dojo.NodeList
+ },
+
+ // FIXME: do we need this?
+ query: function(/*String*/ queryStr){
+ // summary:
+ // Returns a new list whose memebers match the passed query,
+ // assuming elements of the current NodeList as the root for
+ // each search.
+ // example:
+ // assume a DOM created by this markup:
+ // | <div id="foo">
+ // | <p>
+ // | bacon is tasty, <span>dontcha think?</span>
+ // | </p>
+ // | </div>
+ // | <div id="bar">
+ // | <p>great commedians may not be funny <span>in person</span></p>
+ // | </div>
+ // If we are presented with the following defintion for a NodeList:
+ // | var l = new dojo.NodeList(dojo.byId("foo"), dojo.byId("bar"));
+ // it's possible to find all span elements under paragraphs
+ // contained by these elements with this sub-query:
+ // | var spans = l.query("p span");
+
+ // FIXME: probably slow
+ if(!queryStr){ return this; }
+ var ret = this.map(function(node){
+ // FIXME: why would we ever get undefined here?
+ return d.query(queryStr, node).filter(function(subNode){ return subNode !== undefined; });
+ });
+ return this._wrap(apc.apply([], ret), this); // dojo.NodeList
+ },
+
+ filter: function(/*String|Function*/ simpleFilter){
+ // summary:
+ // "masks" the built-in javascript filter() method (supported
+ // in Dojo via `dojo.filter`) to support passing a simple
+ // string filter in addition to supporting filtering function
+ // objects.
+ // simpleFilter:
+ // If a string, a single-expression CSS rule. For example,
+ // ".thinger" or "#someId[attrName='value']" but not "div >
+ // span". In short, anything which does not invoke a descent
+ // to evaluate but can instead be used to test a single node
+ // is acceptable.
+ // example:
+ // "regular" JS filter syntax as exposed in dojo.filter:
+ // | dojo.query("*").filter(function(item){
+ // | // highlight every paragraph
+ // | return (item.nodeName == "p");
+ // | }).style("backgroundColor", "yellow");
+ // example:
+ // the same filtering using a CSS selector
+ // | dojo.query("*").filter("p").styles("backgroundColor", "yellow");
+
+ var a = arguments, items = this, start = 0;
+ if(typeof simpleFilter == "string"){ // inline'd type check
+ items = d._filterQueryResult(this, a[0]);
+ if(a.length == 1){
+ // if we only got a string query, pass back the filtered results
+ return items._stash(this); // dojo.NodeList
+ }
+ // if we got a callback, run it over the filtered items
+ start = 1;
+ }
+ return this._wrap(d.filter(items, a[start], a[start + 1]), this); // 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||DomNode||Object||dojo.NodeList*/ content, /*String||Integer?*/ position){
+ // summary:
+ // add a node, NodeList 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:
+ // DOM node, HTML in string format, a NodeList or an Object. If a DOM node or
+ // NodeList, the content will be cloned if the current NodeList has more than one
+ // element. Only the DOM nodes are cloned, no event handlers. If it is an Object,
+ // it should be an object with at "template" String property that has the HTML string
+ // to insert. If dojo.string has already been dojo.required, then dojo.string.substitute
+ // will be used on the "template" to generate the final HTML string. Other allowed
+ // properties on the object are: "parse" if the HTML
+ // string should be parsed for widgets (dojo.require("dojo.parser") to get that
+ // option to work), and "templateFunc" if a template function besides dojo.string.substitute
+ // should be used to transform the "template".
+ // position:
+ // can be one of:
+ // | "last"||"end" (default)
+ // | "first||"start"
+ // | "before"
+ // | "after"
+ // | "replace" (replaces nodes in this NodeList with new content)
+ // | "only" (removes other children of the nodes so new content is hte only child)
+ // or an offset in the childNodes property
+ // example:
+ // appends content to the end if the position is ommitted
+ // | dojo.query("h3 > p").addContent("hey there!");
+ // example:
+ // add something to the front of each element that has a
+ // "thinger" property:
+ // | dojo.query("[thinger]").addContent("...", "first");
+ // example:
+ // adds a header before each element of the list
+ // | dojo.query(".note").addContent("<h4>NOTE:</h4>", "before");
+ // example:
+ // add a clone of a DOM node to the end of every element in
+ // the list, removing it from its existing parent.
+ // | dojo.query(".note").addContent(dojo.byId("foo"));
+ // example:
+ // Append nodes from a templatized string.
+ // dojo.require("dojo.string");
+ // dojo.query(".note").addContent({
+ // template: '<b>${id}: </b><span>${name}</span>',
+ // id: "user332",
+ // name: "Mr. Anderson"
+ // });
+ // example:
+ // Append nodes from a templatized string that also has widgets parsed.
+ // dojo.require("dojo.string");
+ // dojo.require("dojo.parser");
+ // var notes = dojo.query(".note").addContent({
+ // template: '<button dojoType="dijit.form.Button">${text}</button>',
+ // parse: true,
+ // text: "Send"
+ // });
+ content = this._normalize(content, this[0]);
+ for(var i = 0, node; node = this[i]; i++){
+ this._place(content, node, position, i > 0);
+ }
+ return this; //dojo.NodeList
+ },
+
+ 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.
+ // example:
+ // Grabs all buttons in the page and converts them to diji.form.Buttons.
+ // | var buttons = dojo.query("button").instantiate("dijit.form.Button", {showLabel: true});
+ var c = d.isFunction(declaredClass) ? declaredClass : d.getObject(declaredClass);
+ properties = properties || {};
+ return this.forEach(function(node){
+ new c(properties, node);
+ }); // dojo.NodeList
+ },
+
+ at: function(/*===== index =====*/){
+ // summary:
+ // Returns a new NodeList comprised of items in this NodeList
+ // at the given index or indices.
+ //
+ // index: Integer...
+ // One or more 0-based indices of items in the current
+ // NodeList. A negative index will start at the end of the
+ // list and go backwards.
+ //
+ // example:
+ // Shorten the list to the first, second, and third elements
+ // | dojo.query("a").at(0, 1, 2).forEach(fn);
+ //
+ // example:
+ // Retrieve the first and last elements of a unordered list:
+ // | dojo.query("ul > li").at(0, -1).forEach(cb);
+ //
+ // example:
+ // Do something for the first element only, but end() out back to
+ // the original list and continue chaining:
+ // | dojo.query("a").at(0).onclick(fn).end().forEach(function(n){
+ // | console.log(n); // all anchors on the page.
+ // | })
+ //
+ // returns:
+ // dojo.NodeList
+ var t = new this._NodeListCtor();
+ d.forEach(arguments, function(i){
+ if(i < 0){ i = this.length + i }
+ if(this[i]){ t.push(this[i]); }
+ }, this);
+ return t._stash(this); // dojo.NodeList
+ }
+
+ });
+
+ nl.events = [
+ // summary: list of all DOM events used in NodeList
+ "blur", "focus", "change", "click", "error", "keydown", "keypress",
+ "keyup", "load", "mousedown", "mouseenter", "mouseleave", "mousemove",
+ "mouseout", "mouseover", "mouseup", "submit"
+ ];
+
+ // FIXME: pseudo-doc the above automatically generated on-event functions
+
+ // syntactic sugar for DOM events
+ d.forEach(nl.events, function(evt){
+ var _oe = "on" + evt;
+ nlp[_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.log(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.log(e); }
+ try{ n[_oe](_e); }catch(e){ console.log(e); }
+ })
+ );
+ */
+ }
+ );
+
})();
+
}
diff --git a/lib/dojo/_base/_loader/bootstrap.js b/lib/dojo/_base/_loader/bootstrap.js
index 7cc168e5d..3ef3012a2 100644
--- a/lib/dojo/_base/_loader/bootstrap.js
+++ b/lib/dojo/_base/_loader/bootstrap.js
@@ -5,116 +5,500 @@
*/
-(function(){
-if(typeof this["loadFirebugConsole"]=="function"){
-this["loadFirebugConsole"]();
-}else{
-this.console=this.console||{};
-var cn=["assert","count","debug","dir","dirxml","error","group","groupEnd","info","profile","profileEnd","time","timeEnd","trace","warn","log"];
-var i=0,tn;
-while((tn=cn[i++])){
-if(!console[tn]){
-(function(){
-var _1=tn+"";
-console[_1]=("log" in console)?function(){
-var a=Array.apply({},arguments);
-a.unshift(_1+":");
-console["log"](a.join(" "));
-}:function(){
-};
-console[_1]._fake=true;
-})();
-}
-}
-}
-if(typeof dojo=="undefined"){
-dojo={_scopeName:"dojo",_scopePrefix:"",_scopePrefixArgs:"",_scopeSuffix:"",_scopeMap:{},_scopeMapRev:{}};
-}
-var d=dojo;
-if(typeof dijit=="undefined"){
-dijit={_scopeName:"dijit"};
-}
-if(typeof dojox=="undefined"){
-dojox={_scopeName:"dojox"};
-}
-if(!d._scopeArgs){
-d._scopeArgs=[dojo,dijit,dojox];
-}
-d.global=this;
-d.config={isDebug:false,debugAtAllCosts:false};
-if(typeof djConfig!="undefined"){
-for(var _2 in djConfig){
-d.config[_2]=djConfig[_2];
-}
-}
-dojo.locale=d.config.locale;
-var _3="$Rev: 22487 $".match(/\d+/);
-dojo.version={major:1,minor:5,patch:0,flag:"",revision:_3?+_3[0]:NaN,toString:function(){
-with(d.version){
-return major+"."+minor+"."+patch+flag+" ("+revision+")";
-}
-}};
-if(typeof OpenAjax!="undefined"){
-OpenAjax.hub.registerLibrary(dojo._scopeName,"http://dojotoolkit.org",d.version.toString());
-}
-var _4,_5,_6={};
-for(var i in {toString:1}){
-_4=[];
-break;
-}
-dojo._extraNames=_4=_4||["hasOwnProperty","valueOf","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","constructor"];
-_5=_4.length;
-dojo._mixin=function(_7,_8){
-var _9,s,i;
-for(_9 in _8){
-s=_8[_9];
-if(!(_9 in _7)||(_7[_9]!==s&&(!(_9 in _6)||_6[_9]!==s))){
-_7[_9]=s;
-}
-}
-if(_5&&_8){
-for(i=0;i<_5;++i){
-_9=_4[i];
-s=_8[_9];
-if(!(_9 in _7)||(_7[_9]!==s&&(!(_9 in _6)||_6[_9]!==s))){
-_7[_9]=s;
-}
-}
-}
-return _7;
-};
-dojo.mixin=function(_a,_b){
-if(!_a){
-_a={};
-}
-for(var i=1,l=arguments.length;i<l;i++){
-d._mixin(_a,arguments[i]);
-}
-return _a;
-};
-dojo._getProp=function(_c,_d,_e){
-var _f=_e||d.global;
-for(var i=0,p;_f&&(p=_c[i]);i++){
-if(i==0&&d._scopeMap[p]){
-p=d._scopeMap[p];
+/*=====
+// 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
+ // extended debugging feedback via Firebug. If Firebug is not available
+ // on your platform, setting `isDebug` to `true` will force Dojo to
+ // pull in (and display) the version of Firebug Lite which is
+ // integrated into the Dojo distribution, thereby always providing a
+ // debugging/logging console when `isDebug` is enabled. Note that
+ // Firebug's `console.*` methods are ALWAYS defined by Dojo. If
+ // `isDebug` is false and you are on a platform without Firebug, these
+ // methods will be defined as no-ops.
+ isDebug: false,
+ // debugAtAllCosts: Boolean
+ // Defaults to `false`. If set to `true`, this triggers an alternate
+ // mode of the package system in which dependencies are detected and
+ // only then are resources evaluated in dependency order via
+ // `<script>` tag inclusion. This may double-request resources and
+ // cause problems with scripts which expect `dojo.require()` to
+ // preform synchronously. `debugAtAllCosts` can be an invaluable
+ // debugging aid, but when using it, ensure that all code which
+ // depends on Dojo modules is wrapped in `dojo.addOnLoad()` handlers.
+ // Due to the somewhat unpredictable side-effects of using
+ // `debugAtAllCosts`, it is strongly recommended that you enable this
+ // flag as a last resort. `debugAtAllCosts` has no effect when loading
+ // resources across domains. For usage information, see the
+ // [Dojo Book](http://dojotoolkit.org/book/book-dojo/part-4-meta-dojo-making-your-dojo-code-run-faster-and-better/debugging-facilities/deb)
+ debugAtAllCosts: false,
+ // locale: String
+ // The locale to assume for loading localized resources in this page,
+ // specified according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt).
+ // Must be specified entirely in lowercase, e.g. `en-us` and `zh-cn`.
+ // See the documentation for `dojo.i18n` and `dojo.requireLocalization`
+ // for details on loading localized resources. If no locale is specified,
+ // Dojo assumes the locale of the user agent, according to `navigator.userLanguage`
+ // or `navigator.language` properties.
+ locale: undefined,
+ // extraLocale: Array
+ // No default value. Specifies additional locales whose
+ // resources should also be loaded alongside the default locale when
+ // calls to `dojo.requireLocalization()` are processed.
+ extraLocale: undefined,
+ // baseUrl: String
+ // The directory in which `dojo.js` is located. Under normal
+ // conditions, Dojo auto-detects the correct location from which it
+ // was loaded. You may need to manually configure `baseUrl` in cases
+ // where you have renamed `dojo.js` or in which `<base>` tags confuse
+ // some browsers (e.g. IE 6). The variable `dojo.baseUrl` is assigned
+ // either the value of `djConfig.baseUrl` if one is provided or the
+ // auto-detected root if not. Other modules are located relative to
+ // this path. The path should end in a slash.
+ baseUrl: undefined,
+ // modulePaths: Object
+ // A map of module names to paths relative to `dojo.baseUrl`. The
+ // key/value pairs correspond directly to the arguments which
+ // `dojo.registerModulePath` accepts. Specifiying
+ // `djConfig.modulePaths = { "foo": "../../bar" }` is the equivalent
+ // of calling `dojo.registerModulePath("foo", "../../bar");`. Multiple
+ // modules may be configured via `djConfig.modulePaths`.
+ modulePaths: {},
+ // afterOnLoad: Boolean
+ // Indicates Dojo was added to the page after the page load. In this case
+ // Dojo will not wait for the page DOMContentLoad/load events and fire
+ // its dojo.addOnLoad callbacks after making sure all outstanding
+ // dojo.required modules have loaded. Only works with a built dojo.js,
+ // it does not work the dojo.js directly from source control.
+ afterOnLoad: false,
+ // addOnLoad: Function or Array
+ // Adds a callback via dojo.addOnLoad. Useful when Dojo is added after
+ // the page loads and djConfig.afterOnLoad is true. Supports the same
+ // arguments as dojo.addOnLoad. When using a function reference, use
+ // `djConfig.addOnLoad = function(){};`. For object with function name use
+ // `djConfig.addOnLoad = [myObject, "functionName"];` and for object with
+ // function reference use
+ // `djConfig.addOnLoad = [myObject, function(){}];`
+ addOnLoad: null,
+ // require: Array
+ // An array of module names to be loaded immediately after dojo.js has been included
+ // in a page.
+ require: [],
+ // defaultDuration: Array
+ // Default duration, in milliseconds, for wipe and fade animations within dijits.
+ // Assigned to dijit.defaultDuration.
+ defaultDuration: 200,
+ // dojoBlankHtmlUrl: String
+ // Used by some modules to configure an empty iframe. Used by dojo.io.iframe and
+ // dojo.back, and dijit popup support in IE where an iframe is needed to make sure native
+ // controls do not bleed through the popups. Normally this configuration variable
+ // does not need to be set, except when using cross-domain/CDN Dojo builds.
+ // Save dojo/resources/blank.html to your domain and set `djConfig.dojoBlankHtmlUrl`
+ // to the path on your domain your copy of blank.html.
+ dojoBlankHtmlUrl: undefined,
+ // ioPublish: Boolean?
+ // Set this to true to enable publishing of topics for the different phases of
+ // IO operations. Publishing is done via dojo.publish. See dojo.__IoPublish for a list
+ // of topics that are published.
+ ioPublish: false,
+ // useCustomLogger: Anything?
+ // If set to a value that evaluates to true such as a string or array and
+ // isDebug is true and Firebug is not available or running, then it bypasses
+ // the creation of Firebug Lite allowing you to define your own console object.
+ useCustomLogger: undefined,
+ // transparentColor: Array
+ // Array containing the r, g, b components used as transparent color in dojo.Color;
+ // if undefined, [255,255,255] (white) will be used.
+ transparentColor: undefined,
+ // skipIeDomLoaded: Boolean
+ // For IE only, skip the DOMContentLoaded hack used. Sometimes it can cause an Operation
+ // Aborted error if the rest of the page triggers script defers before the DOM is ready.
+ // If this is config value is set to true, then dojo.addOnLoad callbacks will not be
+ // triggered until the page load event, which is after images and iframes load. If you
+ // want to trigger the callbacks sooner, you can put a script block in the bottom of
+ // your HTML that calls dojo._loadInit();. If you are using multiversion support, change
+ // "dojo." to the appropriate scope name for dojo.
+ skipIeDomLoaded: false
}
-_f=(p in _f?_f[p]:(_d?_f[p]={}:undefined));
+=====*/
+
+(function(){
+ // firebug stubs
+
+ if(typeof this["loadFirebugConsole"] == "function"){
+ // for Firebug 1.2
+ this["loadFirebugConsole"]();
+ }else{
+ this.console = this.console || {};
+
+ // Be careful to leave 'log' always at the end
+ var cn = [
+ "assert", "count", "debug", "dir", "dirxml", "error", "group",
+ "groupEnd", "info", "profile", "profileEnd", "time", "timeEnd",
+ "trace", "warn", "log"
+ ];
+ var i=0, tn;
+ while((tn=cn[i++])){
+ if(!console[tn]){
+ (function(){
+ var tcn = tn+"";
+ console[tcn] = ('log' in console) ? function(){
+ var a = Array.apply({}, arguments);
+ a.unshift(tcn+":");
+ console["log"](a.join(" "));
+ } : function(){}
+ console[tcn]._fake = true;
+ })();
+ }
+ }
+ }
+
+ //TODOC: HOW TO DOC THIS?
+ // dojo is the root variable of (almost all) our public symbols -- make sure it is defined.
+ if(typeof dojo == "undefined"){
+ dojo = {
+ _scopeName: "dojo",
+ _scopePrefix: "",
+ _scopePrefixArgs: "",
+ _scopeSuffix: "",
+ _scopeMap: {},
+ _scopeMapRev: {}
+ };
+ }
+
+ var d = dojo;
+
+ //Need placeholders for dijit and dojox for scoping code.
+ if(typeof dijit == "undefined"){
+ dijit = {_scopeName: "dijit"};
+ }
+ if(typeof dojox == "undefined"){
+ dojox = {_scopeName: "dojox"};
+ }
+
+ if(!d._scopeArgs){
+ d._scopeArgs = [dojo, dijit, dojox];
+ }
+
+/*=====
+dojo.global = {
+ // summary:
+ // Alias for the global scope
+ // (e.g. the window object in a browser).
+ // description:
+ // Refer to 'dojo.global' rather than referring to window to ensure your
+ // code runs correctly in contexts other than web browsers (e.g. Rhino on a server).
}
-return _f;
-};
-dojo.setObject=function(_10,_11,_12){
-var _13=_10.split("."),p=_13.pop(),obj=d._getProp(_13,true,_12);
-return obj&&p?(obj[p]=_11):undefined;
-};
-dojo.getObject=function(_14,_15,_16){
-return d._getProp(_14.split("."),_15,_16);
-};
-dojo.exists=function(_17,obj){
-return !!d.getObject(_17,false,obj);
-};
-dojo["eval"]=function(_18){
-return d.global.eval?d.global.eval(_18):eval(_18);
-};
-d.deprecated=d.experimental=function(){
-};
+=====*/
+ d.global = this;
+
+ d.config =/*===== djConfig = =====*/{
+ isDebug: false,
+ debugAtAllCosts: false
+ };
+
+ if(typeof djConfig != "undefined"){
+ for(var opt in djConfig){
+ d.config[opt] = djConfig[opt];
+ }
+ }
+
+/*=====
+ // Override locale setting, if specified
+ dojo.locale = {
+ // summary: the locale as defined by Dojo (read-only)
+ };
+=====*/
+ dojo.locale = d.config.locale;
+
+ var rev = "$Rev: 22487 $".match(/\d+/);
+
+/*=====
+ dojo.version = function(){
+ // summary:
+ // Version number of the Dojo Toolkit
+ // major: Integer
+ // Major version. If total version is "1.2.0beta1", will be 1
+ // minor: Integer
+ // Minor version. If total version is "1.2.0beta1", will be 2
+ // patch: Integer
+ // Patch version. If total version is "1.2.0beta1", will be 0
+ // flag: String
+ // Descriptor flag. If total version is "1.2.0beta1", will be "beta1"
+ // revision: Number
+ // The SVN rev from which dojo was pulled
+ this.major = 0;
+ this.minor = 0;
+ this.patch = 0;
+ this.flag = "";
+ this.revision = 0;
+ }
+=====*/
+ dojo.version = {
+ major: 1, minor: 5, patch: 0, flag: "",
+ revision: rev ? +rev[0] : NaN,
+ toString: function(){
+ with(d.version){
+ return major + "." + minor + "." + patch + flag + " (" + revision + ")"; // String
+ }
+ }
+ }
+
+ // Register with the OpenAjax hub
+ if(typeof OpenAjax != "undefined"){
+ OpenAjax.hub.registerLibrary(dojo._scopeName, "http://dojotoolkit.org", d.version.toString());
+ }
+
+ var extraNames, extraLen, empty = {};
+ for(var i in {toString: 1}){ extraNames = []; break; }
+ dojo._extraNames = extraNames = extraNames || ["hasOwnProperty", "valueOf", "isPrototypeOf",
+ "propertyIsEnumerable", "toLocaleString", "toString", "constructor"];
+ extraLen = extraNames.length;
+
+ dojo._mixin = function(/*Object*/ target, /*Object*/ source){
+ // summary:
+ // Adds all properties and methods of source to target. This addition
+ // is "prototype extension safe", so that instances of objects
+ // will not pass along prototype defaults.
+ var name, s, i;
+ for(name in source){
+ // the "tobj" condition avoid copying properties in "source"
+ // inherited from Object.prototype. For example, if target has a custom
+ // toString() method, don't overwrite it with the toString() method
+ // that source inherited from Object.prototype
+ s = source[name];
+ if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){
+ target[name] = s;
+ }
+ }
+ // IE doesn't recognize some custom functions in for..in
+ if(extraLen && source){
+ for(i = 0; i < extraLen; ++i){
+ name = extraNames[i];
+ s = source[name];
+ if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){
+ target[name] = s;
+ }
+ }
+ }
+ return target; // Object
+ }
+
+ dojo.mixin = function(/*Object*/obj, /*Object...*/props){
+ // summary:
+ // Adds all properties and methods of props to obj and returns the
+ // (now modified) obj.
+ // description:
+ // `dojo.mixin` can mix multiple source objects into a
+ // destination object which is then returned. Unlike regular
+ // `for...in` iteration, `dojo.mixin` is also smart about avoiding
+ // extensions which other toolkits may unwisely add to the root
+ // object prototype
+ // obj:
+ // The object to mix properties into. Also the return value.
+ // props:
+ // One or more objects whose values are successively copied into
+ // obj. If more than one of these objects contain the same value,
+ // the one specified last in the function call will "win".
+ // example:
+ // make a shallow copy of an object
+ // | var copy = dojo.mixin({}, source);
+ // example:
+ // many class constructors often take an object which specifies
+ // values to be configured on the object. In this case, it is
+ // often simplest to call `dojo.mixin` on the `this` object:
+ // | dojo.declare("acme.Base", null, {
+ // | constructor: function(properties){
+ // | // property configuration:
+ // | dojo.mixin(this, properties);
+ // |
+ // | console.log(this.quip);
+ // | // ...
+ // | },
+ // | quip: "I wasn't born yesterday, you know - I've seen movies.",
+ // | // ...
+ // | });
+ // |
+ // | // create an instance of the class and configure it
+ // | var b = new acme.Base({quip: "That's what it does!" });
+ // example:
+ // copy in properties from multiple objects
+ // | var flattened = dojo.mixin(
+ // | {
+ // | name: "Frylock",
+ // | braces: true
+ // | },
+ // | {
+ // | name: "Carl Brutanananadilewski"
+ // | }
+ // | );
+ // |
+ // | // will print "Carl Brutanananadilewski"
+ // | console.log(flattened.name);
+ // | // will print "true"
+ // | console.log(flattened.braces);
+ if(!obj){ obj = {}; }
+ for(var i=1, l=arguments.length; i<l; i++){
+ d._mixin(obj, arguments[i]);
+ }
+ return obj; // Object
+ }
+
+ dojo._getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){
+ var obj=context || d.global;
+ for(var i=0, p; obj && (p=parts[i]); i++){
+ if(i == 0 && d._scopeMap[p]){
+ p = d._scopeMap[p];
+ }
+ obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined));
+ }
+ return obj; // mixed
+ }
+
+ dojo.setObject = function(/*String*/name, /*Object*/value, /*Object?*/context){
+ // summary:
+ // Set a property from a dot-separated string, such as "A.B.C"
+ // description:
+ // Useful for longer api chains where you have to test each object in
+ // the chain, or when you have an object reference in string format.
+ // Objects are created as needed along `path`. Returns the passed
+ // value if setting is successful or `undefined` if not.
+ // name:
+ // Path to a property, in the form "A.B.C".
+ // context:
+ // Optional. Object to use as root of path. Defaults to
+ // `dojo.global`.
+ // example:
+ // set the value of `foo.bar.baz`, regardless of whether
+ // intermediate objects already exist:
+ // | dojo.setObject("foo.bar.baz", value);
+ // example:
+ // without `dojo.setObject`, we often see code like this:
+ // | // ensure that intermediate objects are available
+ // | if(!obj["parent"]){ obj.parent = {}; }
+ // | if(!obj.parent["child"]){ obj.parent.child= {}; }
+ // | // now we can safely set the property
+ // | obj.parent.child.prop = "some value";
+ // wheras with `dojo.setObject`, we can shorten that to:
+ // | dojo.setObject("parent.child.prop", "some value", obj);
+ var parts=name.split("."), p=parts.pop(), obj=d._getProp(parts, true, context);
+ return obj && p ? (obj[p]=value) : undefined; // Object
+ }
+
+ dojo.getObject = function(/*String*/name, /*Boolean?*/create, /*Object?*/context){
+ // summary:
+ // Get a property from a dot-separated string, such as "A.B.C"
+ // description:
+ // Useful for longer api chains where you have to test each object in
+ // the chain, or when you have an object reference in string format.
+ // name:
+ // Path to an property, in the form "A.B.C".
+ // create:
+ // Optional. Defaults to `false`. If `true`, Objects will be
+ // created at any point along the 'path' that is undefined.
+ // context:
+ // Optional. Object to use as root of path. Defaults to
+ // 'dojo.global'. Null may be passed.
+ return d._getProp(name.split("."), create, context); // Object
+ }
+
+ dojo.exists = function(/*String*/name, /*Object?*/obj){
+ // summary:
+ // determine if an object supports a given method
+ // description:
+ // useful for longer api chains where you have to test each object in
+ // the chain. Useful only for object and method detection.
+ // Not useful for testing generic properties on an object.
+ // In particular, dojo.exists("foo.bar") when foo.bar = ""
+ // will return false. Use ("bar" in foo) to test for those cases.
+ // name:
+ // Path to an object, in the form "A.B.C".
+ // obj:
+ // Object to use as root of path. Defaults to
+ // 'dojo.global'. Null may be passed.
+ // example:
+ // | // define an object
+ // | var foo = {
+ // | bar: { }
+ // | };
+ // |
+ // | // search the global scope
+ // | dojo.exists("foo.bar"); // true
+ // | dojo.exists("foo.bar.baz"); // false
+ // |
+ // | // search from a particular scope
+ // | dojo.exists("bar", foo); // true
+ // | dojo.exists("bar.baz", foo); // false
+ return !!d.getObject(name, false, obj); // Boolean
+ }
+
+ dojo["eval"] = function(/*String*/ scriptFragment){
+ // summary:
+ // A legacy method created for use exclusively by internal Dojo methods. Do not use
+ // this method directly, the behavior of this eval will differ from the normal
+ // browser eval.
+ // description:
+ // Placed in a separate function to minimize size of trapped
+ // exceptions. Calling eval() directly from some other scope may
+ // complicate tracebacks on some platforms.
+ // returns:
+ // The result of the evaluation. Often `undefined`
+ return d.global.eval ? d.global.eval(scriptFragment) : eval(scriptFragment); // Object
+ }
+
+ /*=====
+ dojo.deprecated = function(behaviour, extra, removal){
+ // summary:
+ // Log a debug message to indicate that a behavior has been
+ // deprecated.
+ // behaviour: String
+ // The API or behavior being deprecated. Usually in the form
+ // of "myApp.someFunction()".
+ // extra: String?
+ // Text to append to the message. Often provides advice on a
+ // new function or facility to achieve the same goal during
+ // the deprecation period.
+ // removal: String?
+ // Text to indicate when in the future the behavior will be
+ // removed. Usually a version number.
+ // example:
+ // | dojo.deprecated("myApp.getTemp()", "use myApp.getLocaleTemp() instead", "1.0");
+ }
+
+ dojo.experimental = function(moduleName, extra){
+ // summary: Marks code as experimental.
+ // description:
+ // This can be used to mark a function, file, or module as
+ // experimental. Experimental code is not ready to be used, and the
+ // APIs are subject to change without notice. Experimental code may be
+ // completed deleted without going through the normal deprecation
+ // process.
+ // moduleName: String
+ // The name of a module, or the name of a module file or a specific
+ // function
+ // extra: String?
+ // some additional message for the user
+ // example:
+ // | dojo.experimental("dojo.data.Result");
+ // example:
+ // | dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA");
+ }
+ =====*/
+
+ //Real functions declared in dojo._firebug.firebug.
+ d.deprecated = d.experimental = function(){};
+
})();
+// vim:ai:ts=4:noet
diff --git a/lib/dojo/_base/_loader/hostenv_browser.js b/lib/dojo/_base/_loader/hostenv_browser.js
index 0d746833e..7d92d70e3 100644
--- a/lib/dojo/_base/_loader/hostenv_browser.js
+++ b/lib/dojo/_base/_loader/hostenv_browser.js
@@ -5,240 +5,470 @@
*/
-if(typeof window!="undefined"){
-dojo.isBrowser=true;
-dojo._name="browser";
-(function(){
-var d=dojo;
-if(document&&document.getElementsByTagName){
-var _1=document.getElementsByTagName("script");
-var _2=/dojo(\.xd)?\.js(\W|$)/i;
-for(var i=0;i<_1.length;i++){
-var _3=_1[i].getAttribute("src");
-if(!_3){
-continue;
-}
-var m=_3.match(_2);
-if(m){
-if(!d.config.baseUrl){
-d.config.baseUrl=_3.substring(0,m.index);
-}
-var _4=_1[i].getAttribute("djConfig");
-if(_4){
-var _5=eval("({ "+_4+" })");
-for(var x in _5){
-dojo.config[x]=_5[x];
-}
-}
-break;
-}
-}
-}
-d.baseUrl=d.config.baseUrl;
-var n=navigator;
-var _6=n.userAgent,_7=n.appVersion,tv=parseFloat(_7);
-if(_6.indexOf("Opera")>=0){
-d.isOpera=tv;
-}
-if(_6.indexOf("AdobeAIR")>=0){
-d.isAIR=1;
-}
-d.isKhtml=(_7.indexOf("Konqueror")>=0)?tv:0;
-d.isWebKit=parseFloat(_6.split("WebKit/")[1])||undefined;
-d.isChrome=parseFloat(_6.split("Chrome/")[1])||undefined;
-d.isMac=_7.indexOf("Macintosh")>=0;
-var _8=Math.max(_7.indexOf("WebKit"),_7.indexOf("Safari"),0);
-if(_8&&!dojo.isChrome){
-d.isSafari=parseFloat(_7.split("Version/")[1]);
-if(!d.isSafari||parseFloat(_7.substr(_8+7))<=419.3){
-d.isSafari=2;
-}
-}
-if(_6.indexOf("Gecko")>=0&&!d.isKhtml&&!d.isWebKit){
-d.isMozilla=d.isMoz=tv;
-}
-if(d.isMoz){
-d.isFF=parseFloat(_6.split("Firefox/")[1]||_6.split("Minefield/")[1])||undefined;
-}
-if(document.all&&!d.isOpera){
-d.isIE=parseFloat(_7.split("MSIE ")[1])||undefined;
-var _9=document.documentMode;
-if(_9&&_9!=5&&Math.floor(d.isIE)!=_9){
-d.isIE=_9;
-}
-}
-if(dojo.isIE&&window.location.protocol==="file:"){
-dojo.config.ieForceActiveXXhr=true;
-}
-d.isQuirks=document.compatMode=="BackCompat";
-d.locale=dojo.config.locale||(d.isIE?n.userLanguage:n.language).toLowerCase();
-d._XMLHTTP_PROGIDS=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"];
-d._xhrObj=function(){
-var _a,_b;
-if(!dojo.isIE||!dojo.config.ieForceActiveXXhr){
-try{
-_a=new XMLHttpRequest();
-}
-catch(e){
-}
-}
-if(!_a){
-for(var i=0;i<3;++i){
-var _c=d._XMLHTTP_PROGIDS[i];
-try{
-_a=new ActiveXObject(_c);
-}
-catch(e){
-_b=e;
-}
-if(_a){
-d._XMLHTTP_PROGIDS=[_c];
-break;
-}
-}
-}
-if(!_a){
-throw new Error("XMLHTTP not available: "+_b);
-}
-return _a;
-};
-d._isDocumentOk=function(_d){
-var _e=_d.status||0,lp=location.protocol;
-return (_e>=200&&_e<300)||_e==304||_e==1223||(!_e&&(lp=="file:"||lp=="chrome:"||lp=="chrome-extension:"||lp=="app:"));
+/*=====
+dojo.isBrowser = {
+ // example:
+ // | if(dojo.isBrowser){ ... }
};
-var _f=window.location+"";
-var _10=document.getElementsByTagName("base");
-var _11=(_10&&_10.length>0);
-d._getText=function(uri,_12){
-var _13=d._xhrObj();
-if(!_11&&dojo._Url){
-uri=(new dojo._Url(_f,uri)).toString();
-}
-if(d.config.cacheBust){
-uri+="";
-uri+=(uri.indexOf("?")==-1?"?":"&")+String(d.config.cacheBust).replace(/\W+/g,"");
-}
-_13.open("GET",uri,false);
-try{
-_13.send(null);
-if(!d._isDocumentOk(_13)){
-var err=Error("Unable to load "+uri+" status:"+_13.status);
-err.status=_13.status;
-err.responseText=_13.responseText;
-throw err;
-}
-}
-catch(e){
-if(_12){
-return null;
-}
-throw e;
-}
-return _13.responseText;
-};
-var _14=window;
-var _15=function(_16,fp){
-var _17=_14.attachEvent||_14.addEventListener;
-_16=_14.attachEvent?_16:_16.substring(2);
-_17(_16,function(){
-fp.apply(_14,arguments);
-},false);
-};
-d._windowUnloaders=[];
-d.windowUnloaded=function(){
-var mll=d._windowUnloaders;
-while(mll.length){
-(mll.pop())();
-}
-d=null;
-};
-var _18=0;
-d.addOnWindowUnload=function(obj,_19){
-d._onto(d._windowUnloaders,obj,_19);
-if(!_18){
-_18=1;
-_15("onunload",d.windowUnloaded);
-}
+
+dojo.isFF = {
+ // example:
+ // | if(dojo.isFF > 1){ ... }
};
-var _1a=0;
-d.addOnUnload=function(obj,_1b){
-d._onto(d._unloaders,obj,_1b);
-if(!_1a){
-_1a=1;
-_15("onbeforeunload",dojo.unloaded);
-}
+
+dojo.isIE = {
+ // example:
+ // | if(dojo.isIE > 6){
+ // | // we are IE7
+ // | }
};
-})();
-dojo._initFired=false;
-dojo._loadInit=function(e){
-if(dojo._scrollIntervalId){
-clearInterval(dojo._scrollIntervalId);
-dojo._scrollIntervalId=0;
-}
-if(!dojo._initFired){
-dojo._initFired=true;
-if(!dojo.config.afterOnLoad&&window.detachEvent){
-window.detachEvent("onload",dojo._loadInit);
-}
-if(dojo._inFlightCount==0){
-dojo._modulesLoaded();
-}
-}
+
+dojo.isSafari = {
+ // example:
+ // | if(dojo.isSafari){ ... }
+ // example:
+ // Detect iPhone:
+ // | if(dojo.isSafari && navigator.userAgent.indexOf("iPhone") != -1){
+ // | // we are iPhone. Note, iPod touch reports "iPod" above and fails this test.
+ // | }
};
-if(!dojo.config.afterOnLoad){
-if(document.addEventListener){
-document.addEventListener("DOMContentLoaded",dojo._loadInit,false);
-window.addEventListener("load",dojo._loadInit,false);
-}else{
-if(window.attachEvent){
-window.attachEvent("onload",dojo._loadInit);
-if(!dojo.config.skipIeDomLoaded&&self===self.top){
-dojo._scrollIntervalId=setInterval(function(){
-try{
-if(document.body){
-document.documentElement.doScroll("left");
-dojo._loadInit();
-}
-}
-catch(e){
-}
-},30);
-}
-}
-}
-}
-if(dojo.isIE){
-try{
-(function(){
-document.namespaces.add("v","urn:schemas-microsoft-com:vml");
-var _1c=["*","group","roundrect","oval","shape","rect","imagedata","path","textpath","text"],i=0,l=1,s=document.createStyleSheet();
-if(dojo.isIE>=8){
-i=1;
-l=_1c.length;
-}
-for(;i<l;++i){
-s.addRule("v\\:"+_1c[i],"behavior:url(#default#VML); display:inline-block");
-}
-})();
-}
-catch(e){
-}
-}
-}
+
+dojo = {
+ // isBrowser: Boolean
+ // True if the client is a web-browser
+ isBrowser: true,
+ // isFF: Number | undefined
+ // Version as a Number if client is FireFox. undefined otherwise. Corresponds to
+ // major detected FireFox version (1.5, 2, 3, etc.)
+ isFF: 2,
+ // isIE: Number | undefined
+ // Version as a Number if client is MSIE(PC). undefined otherwise. Corresponds to
+ // major detected IE version (6, 7, 8, etc.)
+ isIE: 6,
+ // isKhtml: Number | undefined
+ // Version as a Number if client is a KHTML browser. undefined otherwise. Corresponds to major
+ // detected version.
+ isKhtml: 0,
+ // isWebKit: Number | undefined
+ // Version as a Number if client is a WebKit-derived browser (Konqueror,
+ // Safari, Chrome, etc.). undefined otherwise.
+ isWebKit: 0,
+ // isMozilla: Number | undefined
+ // Version as a Number if client is a Mozilla-based browser (Firefox,
+ // SeaMonkey). undefined otherwise. Corresponds to major detected version.
+ isMozilla: 0,
+ // isOpera: Number | undefined
+ // Version as a Number if client is Opera. undefined otherwise. Corresponds to
+ // major detected version.
+ isOpera: 0,
+ // isSafari: Number | undefined
+ // Version as a Number if client is Safari or iPhone. undefined otherwise.
+ isSafari: 0,
+ // isChrome: Number | undefined
+ // Version as a Number if client is Chrome browser. undefined otherwise.
+ isChrome: 0
+ // isMac: Boolean
+ // True if the client runs on Mac
+}
+=====*/
+
+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,
+ dav = n.appVersion,
+ tv = parseFloat(dav);
+
+ if(dua.indexOf("Opera") >= 0){ d.isOpera = tv; }
+ if(dua.indexOf("AdobeAIR") >= 0){ d.isAIR = 1; }
+ d.isKhtml = (dav.indexOf("Konqueror") >= 0) ? tv : 0;
+ d.isWebKit = parseFloat(dua.split("WebKit/")[1]) || undefined;
+ d.isChrome = parseFloat(dua.split("Chrome/")[1]) || undefined;
+ d.isMac = dav.indexOf("Macintosh") >= 0;
+
+ // safari detection derived from:
+ // http://developer.apple.com/internet/safari/faq.html#anchor2
+ // http://developer.apple.com/internet/safari/uamatrix.html
+ var index = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0);
+ if(index && !dojo.isChrome){
+ // try to grab the explicit Safari version first. If we don't get
+ // one, look for less than 419.3 as the indication that we're on something
+ // "Safari 2-ish".
+ d.isSafari = parseFloat(dav.split("Version/")[1]);
+ if(!d.isSafari || parseFloat(dav.substr(index + 7)) <= 419.3){
+ d.isSafari = 2;
+ }
+ }
+
+ if(dua.indexOf("Gecko") >= 0 && !d.isKhtml && !d.isWebKit){ d.isMozilla = d.isMoz = tv; }
+ if(d.isMoz){
+ //We really need to get away from this. Consider a sane isGecko approach for the future.
+ d.isFF = parseFloat(dua.split("Firefox/")[1] || dua.split("Minefield/")[1]) || undefined;
+ }
+ if(document.all && !d.isOpera){
+ d.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined;
+ //In cases where the page has an HTTP header or META tag with
+ //X-UA-Compatible, then it is in emulation mode.
+ //Make sure isIE reflects the desired version.
+ //document.documentMode of 5 means quirks mode.
+ //Only switch the value if documentMode's major version
+ //is different from isIE's major version.
+ var mode = document.documentMode;
+ if(mode && mode != 5 && Math.floor(d.isIE) != mode){
+ d.isIE = mode;
+ }
+ }
+
+ //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;
+ }
+
+ d.isQuirks = document.compatMode == "BackCompat";
+
+ // 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, last_e;
+ 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,
+ lp = location.protocol;
+ return (stat >= 200 && stat < 300) || // Boolean
+ stat == 304 || // allow any 2XX response code
+ stat == 1223 || // get it out of the cache
+ // Internet Explorer mangled the status code OR we're Titanium/browser chrome/chrome extension requesting a local file
+ (!stat && (lp == "file:" || lp == "chrome:" || lp == "chrome-extension:" || lp == "app:") );
+ }
+
+ //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)
+
+ // NOTE: must be declared before scope switches ie. this._xhrObj()
+ var http = d._xhrObj();
+
+ if(!hasBase && dojo._Url){
+ uri = (new dojo._Url(owloc, uri)).toString();
+ }
+
+ if(d.config.cacheBust){
+ //Make sure we have a string before string methods are used on uri
+ uri += "";
+ uri += (uri.indexOf("?") == -1 ? "?" : "&") + String(d.config.cacheBust).replace(/\W+/g,"");
+ }
+
+ http.open('GET', uri, false);
+ try{
+ http.send(null);
+ 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
+ }
+
+
+ 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 _a = _w.attachEvent || _w.addEventListener;
+ evtName = _w.attachEvent ? evtName : evtName.substring(2);
+ _a(evtName, function(){
+ fp.apply(_w, arguments);
+ }, false);
+ };
+
+
+ d._windowUnloaders = [];
+
+ d.windowUnloaded = function(){
+ // summary:
+ // signal fired by impending window destruction. You may use
+ // dojo.addOnWindowUnload() to register a listener for this
+ // event. NOTE: if you wish to dojo.connect() to this method
+ // to perform page/application cleanup, be aware that this
+ // event WILL NOT fire if no handler has been registered with
+ // dojo.addOnWindowUnload. This behavior started in Dojo 1.3.
+ // Previous versions always triggered dojo.windowUnloaded. See
+ // dojo.addOnWindowUnload for more info.
+ var mll = d._windowUnloaders;
+ while(mll.length){
+ (mll.pop())();
+ }
+ d = null;
+ };
+
+ var _onWindowUnloadAttached = 0;
+ d.addOnWindowUnload = function(/*Object?|Function?*/obj, /*String|Function?*/functionName){
+ // summary:
+ // registers a function to be triggered when window.onunload
+ // fires.
+ // description:
+ // The first time that addOnWindowUnload is called Dojo
+ // will register a page listener to trigger your unload
+ // handler with. Note that registering these handlers may
+ // destory "fastback" page caching in browsers that support
+ // it. Be careful trying to modify the DOM or access
+ // JavaScript properties during this phase of page unloading:
+ // they may not always be available. Consider
+ // dojo.addOnUnload() if you need to modify the DOM or do
+ // heavy JavaScript work since it fires at the eqivalent of
+ // the page's "onbeforeunload" event.
+ // example:
+ // | dojo.addOnWindowUnload(functionPointer)
+ // | dojo.addOnWindowUnload(object, "functionName");
+ // | dojo.addOnWindowUnload(object, function(){ /* ... */});
+
+ d._onto(d._windowUnloaders, obj, functionName);
+ if(!_onWindowUnloadAttached){
+ _onWindowUnloadAttached = 1;
+ _handleNodeEvent("onunload", d.windowUnloaded);
+ }
+ };
+
+ var _onUnloadAttached = 0;
+ d.addOnUnload = function(/*Object?|Function?*/obj, /*String|Function?*/functionName){
+ // summary:
+ // registers a function to be triggered when the page unloads.
+ // description:
+ // The first time that addOnUnload is called Dojo will
+ // register a page listener to trigger your unload handler
+ // with.
+ //
+ // In a browser enviroment, the functions will be triggered
+ // during the window.onbeforeunload event. Be careful of doing
+ // too much work in an unload handler. onbeforeunload can be
+ // triggered if a link to download a file is clicked, or if
+ // the link is a javascript: link. In these cases, the
+ // onbeforeunload event fires, but the document is not
+ // actually destroyed. So be careful about doing destructive
+ // operations in a dojo.addOnUnload callback.
+ //
+ // Further note that calling dojo.addOnUnload will prevent
+ // browsers from using a "fast back" cache to make page
+ // loading via back button instantaneous.
+ // example:
+ // | dojo.addOnUnload(functionPointer)
+ // | dojo.addOnUnload(object, "functionName")
+ // | dojo.addOnUnload(object, function(){ /* ... */});
+
+ d._onto(d._unloaders, obj, functionName);
+ if(!_onUnloadAttached){
+ _onUnloadAttached = 1;
+ _handleNodeEvent("onbeforeunload", dojo.unloaded);
+ }
+ };
+
+ })();
+
+ //START DOMContentLoaded
+ dojo._initFired = false;
+ dojo._loadInit = function(e){
+ if(dojo._scrollIntervalId){
+ clearInterval(dojo._scrollIntervalId);
+ dojo._scrollIntervalId = 0;
+ }
+
+ if(!dojo._initFired){
+ dojo._initFired = true;
+
+ //Help out IE to avoid memory leak.
+ if(!dojo.config.afterOnLoad && window.detachEvent){
+ window.detachEvent("onload", dojo._loadInit);
+ }
+
+ if(dojo._inFlightCount == 0){
+ dojo._modulesLoaded();
+ }
+ }
+ }
+
+ if(!dojo.config.afterOnLoad){
+ if(document.addEventListener){
+ //Standards. Hooray! Assumption here that if standards based,
+ //it knows about DOMContentLoaded. It is OK if it does not, the fall through
+ //to window onload should be good enough.
+ document.addEventListener("DOMContentLoaded", dojo._loadInit, false);
+ window.addEventListener("load", dojo._loadInit, false);
+ }else if(window.attachEvent){
+ window.attachEvent("onload", dojo._loadInit);
+
+ //DOMContentLoaded approximation. Diego Perini found this MSDN article
+ //that indicates doScroll is available after DOM ready, so do a setTimeout
+ //to check when it is available.
+ //http://msdn.microsoft.com/en-us/library/ms531426.aspx
+ if(!dojo.config.skipIeDomLoaded && self === self.top){
+ dojo._scrollIntervalId = setInterval(function (){
+ try{
+ //When dojo is loaded into an iframe in an IE HTML Application
+ //(HTA), such as in a selenium test, javascript in the iframe
+ //can't see anything outside of it, so self===self.top is true,
+ //but the iframe is not the top window and doScroll will be
+ //available before document.body is set. Test document.body
+ //before trying the doScroll trick
+ if(document.body){
+ document.documentElement.doScroll("left");
+ dojo._loadInit();
+ }
+ }catch (e){}
+ }, 30);
+ }
+ }
+ }
+
+ if(dojo.isIE){
+ try{
+ (function(){
+ document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
+ var vmlElems = ["*", "group", "roundrect", "oval", "shape", "rect", "imagedata", "path", "textpath", "text"],
+ i = 0, l = 1, s = document.createStyleSheet();
+ if(dojo.isIE >= 8){
+ i = 1;
+ l = vmlElems.length;
+ }
+ for(; i < l; ++i){
+ s.addRule("v\\:" + vmlElems[i], "behavior:url(#default#VML); display:inline-block");
+ }
+ })();
+ }catch(e){}
+ }
+ //END DOMContentLoaded
+
+
+ /*
+ 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 _1d in mp){
-dojo.registerModulePath(_1d,mp[_1d]);
-}
-}
+ 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");
+ 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");
+ dojo.config.useXDomain = true;
+ dojo.require("dojo._base._loader.loader_xd");
+ dojo.require("dojo._base._loader.loader_debug");
+ dojo.require("dojo.i18n");
}
diff --git a/lib/dojo/_base/_loader/hostenv_ff_ext.js b/lib/dojo/_base/_loader/hostenv_ff_ext.js
index 08242393d..94a0a8046 100644
--- a/lib/dojo/_base/_loader/hostenv_ff_ext.js
+++ b/lib/dojo/_base/_loader/hostenv_ff_ext.js
@@ -5,171 +5,334 @@
*/
-if(typeof window!="undefined"){
-dojo.isBrowser=true;
-dojo._name="browser";
-(function(){
-var d=dojo;
-d.baseUrl=d.config.baseUrl;
-var n=navigator;
-var _1=n.userAgent;
-var _2=n.appVersion;
-var tv=parseFloat(_2);
-d.isMozilla=d.isMoz=tv;
-if(d.isMoz){
-d.isFF=parseFloat(_1.split("Firefox/")[1])||undefined;
-}
-d.isQuirks=document.compatMode=="BackCompat";
-d.locale=dojo.config.locale||n.language.toLowerCase();
-d._xhrObj=function(){
-return new XMLHttpRequest();
-};
-var _3=d._loadUri;
-d._loadUri=function(_4,cb){
-var _5=["file:","chrome:","resource:"].some(function(_6){
-return String(_4).indexOf(_6)==0;
-});
-if(_5){
-var l=Components.classes["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader);
-var _7=l.loadSubScript(_4,d.global);
-if(cb){
-cb(_7);
-}
-return true;
-}else{
-return _3.apply(d,arguments);
-}
-};
-d._isDocumentOk=function(_8){
-var _9=_8.status||0;
-return (_9>=200&&_9<300)||_9==304||_9==1223||(!_9&&(location.protocol=="file:"||location.protocol=="chrome:"));
-};
-var _a=false;
-d._getText=function(_b,_c){
-var _d=d._xhrObj();
-if(!_a&&dojo._Url){
-_b=(new dojo._Url(_b)).toString();
-}
-if(d.config.cacheBust){
-_b+="";
-_b+=(_b.indexOf("?")==-1?"?":"&")+String(d.config.cacheBust).replace(/\W+/g,"");
-}
-var _e=["file:","chrome:","resource:"].some(function(_f){
-return String(_b).indexOf(_f)==0;
-});
-if(_e){
-var _10=Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
-var _11=Components.classes["@mozilla.org/scriptableinputstream;1"].getService(Components.interfaces.nsIScriptableInputStream);
-var _12=_10.newChannel(_b,null,null);
-var _13=_12.open();
-_11.init(_13);
-var str=_11.read(_13.available());
-_11.close();
-_13.close();
-return str;
-}else{
-_d.open("GET",_b,false);
-try{
-_d.send(null);
-if(!d._isDocumentOk(_d)){
-var err=Error("Unable to load "+_b+" status:"+_d.status);
-err.status=_d.status;
-err.responseText=_d.responseText;
-throw err;
-}
-}
-catch(e){
-if(_c){
-return null;
-}
-throw e;
-}
-return _d.responseText;
-}
-};
-d._windowUnloaders=[];
-d.windowUnloaded=function(){
-var mll=d._windowUnloaders;
-while(mll.length){
-(mll.pop())();
-}
-};
-d.addOnWindowUnload=function(obj,_14){
-d._onto(d._windowUnloaders,obj,_14);
-};
-var _15=[];
-var _16=null;
-dojo._defaultContext=[window,document];
-dojo.pushContext=function(g,d){
-var old=[dojo.global,dojo.doc];
-_15.push(old);
-var n;
-if(!g&&!d){
-n=dojo._defaultContext;
-}else{
-n=[g,d];
-if(!d&&dojo.isString(g)){
-var t=document.getElementById(g);
-if(t.contentDocument){
-n=[t.contentWindow,t.contentDocument];
-}
-}
-}
-_16=n;
-dojo.setContext.apply(dojo,n);
-return old;
-};
-dojo.popContext=function(){
-var oc=_16;
-if(!_15.length){
-return oc;
-}
-dojo.setContext.apply(dojo,_15.pop());
-return oc;
-};
-dojo._inContext=function(g,d,f){
-var a=dojo._toArray(arguments);
-f=a.pop();
-if(a.length==1){
-d=null;
-}
-dojo.pushContext(g,d);
-var r=f();
-dojo.popContext();
-return r;
-};
-})();
-dojo._initFired=false;
-dojo._loadInit=function(e){
-dojo._initFired=true;
-var _17=(e&&e.type)?e.type.toLowerCase():"load";
-if(arguments.callee.initialized||(_17!="domcontentloaded"&&_17!="load")){
-return;
-}
-arguments.callee.initialized=true;
-if(dojo._inFlightCount==0){
-dojo._modulesLoaded();
-}
-};
-if(!dojo.config.afterOnLoad){
-window.addEventListener("DOMContentLoaded",function(e){
-dojo._loadInit(e);
-},false);
-}
-}
+// a host environment specifically built for Mozilla extensions, but derived
+// from the browser host environment
+if(typeof window != 'undefined'){
+ dojo.isBrowser = true;
+ dojo._name = "browser";
+
+
+ // FIXME: PORTME
+ // http://developer.mozilla.org/en/mozIJSSubScriptLoader
+
+
+ // 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.
+
+ // FIXME: need to probably use a different reference to "document" to get the hosting XUL environment
+
+ 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.isMozilla = d.isMoz = tv;
+ if(d.isMoz){
+ d.isFF = parseFloat(dua.split("Firefox/")[1]) || undefined;
+ }
+
+ // FIXME
+ d.isQuirks = document.compatMode == "BackCompat";
+
+ // FIXME
+ // TODO: is the HTML LANG attribute relevant?
+ d.locale = dojo.config.locale || n.language.toLowerCase();
+
+ d._xhrObj = function(){
+ return new XMLHttpRequest();
+ }
+
+ // monkey-patch _loadUri to handle file://, chrome://, and resource:// url's
+ var oldLoadUri = d._loadUri;
+ d._loadUri = function(uri, cb){
+ var handleLocal = ["file:", "chrome:", "resource:"].some(function(prefix){
+ return String(uri).indexOf(prefix) == 0;
+ });
+ if(handleLocal){
+ // see:
+ // http://developer.mozilla.org/en/mozIJSSubScriptLoader
+ var l = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
+ .getService(Components.interfaces.mozIJSSubScriptLoader);
+ var value = l.loadSubScript(uri, d.global)
+ if(cb){ cb(value); }
+ return true;
+ }else{
+ // otherwise, call the pre-existing version
+ return oldLoadUri.apply(d, arguments);
+ }
+ }
+
+ // FIXME: PORTME
+ 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:") );
+ }
+
+ // FIXME: PORTME
+ // var owloc = window.location+"";
+ // var base = document.getElementsByTagName("base");
+ // var hasBase = (base && base.length > 0);
+ var hasBase = false;
+
+ 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 = d._xhrObj();
+
+ if(!hasBase && dojo._Url){
+ uri = (new dojo._Url(uri)).toString();
+ }
+ if(d.config.cacheBust){
+ //Make sure we have a string before string methods are used on uri
+ uri += "";
+ uri += (uri.indexOf("?") == -1 ? "?" : "&") + String(d.config.cacheBust).replace(/\W+/g,"");
+ }
+ var handleLocal = ["file:", "chrome:", "resource:"].some(function(prefix){
+ return String(uri).indexOf(prefix) == 0;
+ });
+ if(handleLocal){
+ // see:
+ // http://forums.mozillazine.org/viewtopic.php?p=921150#921150
+ var ioService = Components.classes["@mozilla.org/network/io-service;1"]
+ .getService(Components.interfaces.nsIIOService);
+ var scriptableStream=Components
+ .classes["@mozilla.org/scriptableinputstream;1"]
+ .getService(Components.interfaces.nsIScriptableInputStream);
+
+ var channel = ioService.newChannel(uri, null, null);
+ var input = channel.open();
+ scriptableStream.init(input);
+ var str = scriptableStream.read(input.available());
+ scriptableStream.close();
+ input.close();
+ return str;
+ }else{
+ 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
+ }
+ }
+
+ d._windowUnloaders = [];
+
+ // FIXME: PORTME
+ d.windowUnloaded = function(){
+ // summary:
+ // signal fired by impending window destruction. You may use
+ // dojo.addOnWIndowUnload() or dojo.connect() to this method to perform
+ // page/application cleanup methods. See dojo.addOnWindowUnload for more info.
+ var mll = d._windowUnloaders;
+ while(mll.length){
+ (mll.pop())();
+ }
+ }
+
+ // FIXME: PORTME
+ d.addOnWindowUnload = function(/*Object?*/obj, /*String|Function?*/functionName){
+ // summary:
+ // registers a function to be triggered when window.onunload fires.
+ // Be careful trying to modify the DOM or access JavaScript properties
+ // during this phase of page unloading: they may not always be available.
+ // Consider dojo.addOnUnload() if you need to modify the DOM or do heavy
+ // JavaScript work.
+ // example:
+ // | dojo.addOnWindowUnload(functionPointer)
+ // | dojo.addOnWindowUnload(object, "functionName")
+ // | dojo.addOnWindowUnload(object, function(){ /* ... */});
+
+ d._onto(d._windowUnloaders, obj, functionName);
+ }
+
+ // XUL specific APIs
+ var contexts = [];
+ var current = null;
+ dojo._defaultContext = [ window, document ];
+
+ dojo.pushContext = function(/*Object|String?*/g, /*MDocumentElement?*/d){
+ // summary:
+ // causes subsequent calls to Dojo methods to assume the
+ // passed object and, optionally, document as the default
+ // scopes to use. A 2-element array of the previous global and
+ // document are returned.
+ // description:
+ // dojo.pushContext treats contexts as a stack. The
+ // auto-detected contexts which are initially provided using
+ // dojo.setContext() require authors to keep state in order to
+ // "return" to a previous context, whereas the
+ // dojo.pushContext and dojo.popContext methods provide a more
+ // natural way to augment blocks of code to ensure that they
+ // execute in a different window or frame without issue. If
+ // called without any arguments, the default context (the
+ // context when Dojo is first loaded) is instead pushed into
+ // the stack. If only a single string is passed, a node in the
+ // intitial context's document is looked up and its
+ // contextWindow and contextDocument properties are used as
+ // the context to push. This means that iframes can be given
+ // an ID and code can be executed in the scope of the iframe's
+ // document in subsequent calls easily.
+ // g:
+ // The global context. If a string, the id of the frame to
+ // search for a context and document.
+ // d:
+ // The document element to execute subsequent code with.
+ var old = [dojo.global, dojo.doc];
+ contexts.push(old);
+ var n;
+ if(!g && !d){
+ n = dojo._defaultContext;
+ }else{
+ n = [ g, d ];
+ if(!d && dojo.isString(g)){
+ var t = document.getElementById(g);
+ if(t.contentDocument){
+ n = [t.contentWindow, t.contentDocument];
+ }
+ }
+ }
+ current = n;
+ dojo.setContext.apply(dojo, n);
+ return old; // Array
+ };
+
+ dojo.popContext = function(){
+ // summary:
+ // If the context stack contains elements, ensure that
+ // subsequent code executes in the *previous* context to the
+ // current context. The current context set ([global,
+ // document]) is returned.
+ var oc = current;
+ if(!contexts.length){
+ return oc;
+ }
+ dojo.setContext.apply(dojo, contexts.pop());
+ return oc;
+ };
+
+ // FIXME:
+ // don't really like the current arguments and order to
+ // _inContext, so don't make it public until it's right!
+ dojo._inContext = function(g, d, f){
+ var a = dojo._toArray(arguments);
+ f = a.pop();
+ if(a.length == 1){
+ d = null;
+ }
+ dojo.pushContext(g, d);
+ var r = f();
+ dojo.popContext();
+ return r;
+ };
+
+ })();
+
+ 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(dojo._inFlightCount == 0){
+ dojo._modulesLoaded();
+ }
+ }
+
+ /*
+ (function(){
+ var _w = window;
+ var _handleNodeEvent = function(evtName, 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);
+ };
+ };
+ // FIXME: PORT
+ // FIXME: dojo.unloaded requires dojo scope, so using anon function wrapper.
+ _handleNodeEvent("onbeforeunload", function() { dojo.unloaded(); });
+ _handleNodeEvent("onunload", function() { dojo.windowUnloaded(); });
+ })();
+ */
+
+
+ // FIXME: PORTME
+ // this event fires a lot, namely for all plugin XUL overlays and for
+ // all iframes (in addition to window navigations). We only want
+ // Dojo's to fire once..but we might care if pages navigate. We'll
+ // probably need an extension-specific API
+ if(!dojo.config.afterOnLoad){
+ window.addEventListener("DOMContentLoaded",function(e){
+ dojo._loadInit(e);
+ // console.log("DOM content loaded", e);
+ }, false);
+ }
+
+} //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 _18 in mp){
-dojo.registerModulePath(_18,mp[_18]);
-}
-}
+ 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){
-console.log=function(m){
-var s=Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
-s.logStringMessage(m);
-};
-console.debug=function(){
-};
+ // logging stub for extension logging
+ console.log = function(m){
+ var s = Components.classes["@mozilla.org/consoleservice;1"].getService(
+ Components.interfaces.nsIConsoleService
+ );
+ s.logStringMessage(m);
+ }
+ console.debug = function(){
+ console.log(dojo._toArray(arguments).join(" "));
+ }
+ // FIXME: what about the rest of the console.* methods? And is there any way to reach into firebug and log into it directly?
}
diff --git a/lib/dojo/_base/_loader/hostenv_rhino.js b/lib/dojo/_base/_loader/hostenv_rhino.js
index 9cd882713..ee9ad8b43 100644
--- a/lib/dojo/_base/_loader/hostenv_rhino.js
+++ b/lib/dojo/_base/_loader/hostenv_rhino.js
@@ -5,149 +5,204 @@
*/
+/*
+* Rhino host environment
+*/
+
if(dojo.config["baseUrl"]){
-dojo.baseUrl=dojo.config["baseUrl"];
+ dojo.baseUrl = dojo.config["baseUrl"];
}else{
-dojo.baseUrl="./";
+ dojo.baseUrl = "./";
}
-dojo.locale=dojo.locale||String(java.util.Locale.getDefault().toString().replace("_","-").toLowerCase());
-dojo._name="rhino";
-dojo.isRhino=true;
-if(typeof print=="function"){
-console.debug=print;
+
+dojo.locale = dojo.locale || String(java.util.Locale.getDefault().toString().replace('_','-').toLowerCase());
+dojo._name = 'rhino';
+dojo.isRhino = true;
+
+if(typeof print == "function"){
+ console.debug = print;
}
+
if(!("byId" in dojo)){
-dojo.byId=function(id,_1){
-if(id&&(typeof id=="string"||id instanceof String)){
-if(!_1){
-_1=document;
-}
-return _1.getElementById(id);
-}
-return id;
-};
-}
-dojo._isLocalUrl=function(_2){
-var _3=(new java.io.File(_2)).exists();
-if(!_3){
-var _4;
-try{
-_4=(new java.net.URL(_2)).openStream();
-_4.close();
-}
-finally{
-if(_4&&_4.close){
-_4.close();
-}
-}
-}
-return _3;
-};
-dojo._loadUri=function(_5,cb){
-try{
-var _6;
-try{
-_6=dojo._isLocalUrl(_5);
-}
-catch(e){
-return false;
-}
-if(cb){
-var _7=(_6?readText:readUri)(_5,"UTF-8");
-if(!eval("'‏'").length){
-_7=String(_7).replace(/[\u200E\u200F\u202A-\u202E]/g,function(_8){
-return "\\u"+_8.charCodeAt(0).toString(16);
-});
-}
-cb(eval("("+_7+")"));
-}else{
-load(_5);
-}
-return true;
-}
-catch(e){
-return false;
-}
-};
-dojo.exit=function(_9){
-quit(_9);
-};
-function readText(_a,_b){
-_b=_b||"utf-8";
-var jf=new java.io.File(_a);
-var is=new java.io.FileInputStream(jf);
-return dj_readInputStream(is,_b);
-};
-function readUri(_c,_d){
-var _e=(new java.net.URL(_c)).openConnection();
-_d=_d||_e.getContentEncoding()||"utf-8";
-var is=_e.getInputStream();
-return dj_readInputStream(is,_d);
-};
-function dj_readInputStream(is,_f){
-var _10=new java.io.BufferedReader(new java.io.InputStreamReader(is,_f));
-try{
-var sb=new java.lang.StringBuffer();
-var _11="";
-while((_11=_10.readLine())!==null){
-sb.append(_11);
-sb.append(java.lang.System.getProperty("line.separator"));
-}
-return sb.toString();
+ dojo.byId = function(id, doc){
+ if(id && (typeof id == "string" || id instanceof String)){
+ if(!doc){ doc = document; }
+ return doc.getElementById(id);
+ }
+ return id; // assume it's a node
+ }
}
-finally{
-_10.close();
-}
-};
-dojo._getText=function(uri,_12){
-try{
-var _13=dojo._isLocalUrl(uri);
-var _14=(_13?readText:readUri)(uri,"UTF-8");
-if(_14!==null){
-_14+="";
+
+dojo._isLocalUrl = function(/*String*/ uri) {
+ // summary:
+ // determines if URI is local or not.
+
+ var local = (new java.io.File(uri)).exists();
+ if(!local){
+ var stream;
+ //Try remote URL. Allow this method to throw,
+ //but still do cleanup.
+ try{
+ // try it as a file first, URL second
+ stream = (new java.net.URL(uri)).openStream();
+ // close the stream so we don't leak resources
+ stream.close();
+ }finally{
+ if(stream && stream.close){
+ stream.close();
+ }
+ }
+ }
+ return local;
}
-return _14;
+
+// see comments in spidermonkey loadUri
+dojo._loadUri = function(uri, cb){
+ try{
+ var local;
+ try{
+ local = dojo._isLocalUrl(uri);
+ }catch(e){
+ // no debug output; this failure just means the uri was not found.
+ return false;
+ }
+
+ //FIXME: Use Rhino 1.6 native readFile/readUrl if available?
+ if(cb){
+ var contents = (local ? readText : readUri)(uri, "UTF-8");
+
+ // patch up the input to eval until https://bugzilla.mozilla.org/show_bug.cgi?id=471005 is fixed.
+ if(!eval("'\u200f'").length){
+ contents = String(contents).replace(/[\u200E\u200F\u202A-\u202E]/g, function(match){
+ return "\\u" + match.charCodeAt(0).toString(16);
+ })
+ }
+
+ cb(eval('('+contents+')'));
+ }else{
+ load(uri);
+ }
+ return true;
+ }catch(e){
+ console.debug("rhino load('" + uri + "') failed. Exception: " + e);
+ return false;
+ }
}
-catch(e){
-if(_12){
-return null;
-}else{
-throw e;
+
+dojo.exit = function(exitcode){
+ quit(exitcode);
}
+
+// reading a file from disk in Java is a humiliating experience by any measure.
+// Lets avoid that and just get the freaking text
+function readText(path, encoding){
+ encoding = encoding || "utf-8";
+ // NOTE: we intentionally avoid handling exceptions, since the caller will
+ // want to know
+ var jf = new java.io.File(path);
+ var is = new java.io.FileInputStream(jf);
+ return dj_readInputStream(is, encoding);
}
-};
-dojo.doc=typeof document!="undefined"?document:null;
-dojo.body=function(){
-return document.body;
-};
-if(typeof setTimeout=="undefined"||typeof clearTimeout=="undefined"){
-dojo._timeouts=[];
-clearTimeout=function(idx){
-if(!dojo._timeouts[idx]){
-return;
+
+function readUri(uri, encoding){
+ var conn = (new java.net.URL(uri)).openConnection();
+ encoding = encoding || conn.getContentEncoding() || "utf-8";
+ var is = conn.getInputStream();
+ return dj_readInputStream(is, encoding);
}
-dojo._timeouts[idx].stop();
-};
-setTimeout=function(_15,_16){
-var def={sleepTime:_16,hasSlept:false,run:function(){
-if(!this.hasSlept){
-this.hasSlept=true;
-java.lang.Thread.currentThread().sleep(this.sleepTime);
+
+function dj_readInputStream(is, encoding){
+ var input = new java.io.BufferedReader(new java.io.InputStreamReader(is, encoding));
+ try {
+ var sb = new java.lang.StringBuffer();
+ var line = "";
+ while((line = input.readLine()) !== null){
+ sb.append(line);
+ sb.append(java.lang.System.getProperty("line.separator"));
+ }
+ return sb.toString();
+ } finally {
+ input.close();
+ }
}
-try{
-_15();
+
+dojo._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.
+ // 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)
+ try{
+ var local = dojo._isLocalUrl(uri);
+ var text = (local ? readText : readUri)(uri, "UTF-8");
+ if(text !== null){
+ //Force JavaScript string.
+ text += "";
+ }
+ return text;
+ }catch(e){
+ if(fail_ok){
+ return null;
+ }else{
+ throw e;
+ }
+ }
}
-catch(e){
+
+// summary:
+// return the document object associated with the dojo.global
+dojo.doc = typeof document != "undefined" ? document : null;
+
+dojo.body = function(){
+ return document.body;
}
-}};
-var _17=new java.lang.Runnable(def);
-var _18=new java.lang.Thread(_17);
-_18.start();
-return dojo._timeouts.push(_18)-1;
-};
+
+// Supply setTimeout/clearTimeout implementations if they aren't already there
+// Note: this assumes that we define both if one is not provided... there might
+// be a better way to do this if there is a use case where one is defined but
+// not the other
+if(typeof setTimeout == "undefined" || typeof clearTimeout == "undefined"){
+ dojo._timeouts = [];
+ clearTimeout = function(idx){
+ if(!dojo._timeouts[idx]){ return; }
+ dojo._timeouts[idx].stop();
+ }
+
+ setTimeout = function(func, delay){
+ // summary: provides timed callbacks using Java threads
+
+ var def={
+ sleepTime:delay,
+ hasSlept:false,
+
+ run:function(){
+ if(!this.hasSlept){
+ this.hasSlept=true;
+ java.lang.Thread.currentThread().sleep(this.sleepTime);
+ }
+ try{
+ func();
+ }catch(e){
+ console.debug("Error running setTimeout thread:" + e);
+ }
+ }
+ };
+
+ var runnable = new java.lang.Runnable(def);
+ var thread = new java.lang.Thread(runnable);
+ thread.start();
+ return dojo._timeouts.push(thread)-1;
+ }
}
+
+//Register any module paths set up in djConfig. Need to do this
+//in the hostenvs since hostenv_browser can read djConfig from a
+//script tag's attribute.
if(dojo.config["modulePaths"]){
-for(var param in dojo.config["modulePaths"]){
-dojo.registerModulePath(param,dojo.config["modulePaths"][param]);
-}
+ for(var param in dojo.config["modulePaths"]){
+ dojo.registerModulePath(param, dojo.config["modulePaths"][param]);
+ }
}
diff --git a/lib/dojo/_base/_loader/hostenv_spidermonkey.js b/lib/dojo/_base/_loader/hostenv_spidermonkey.js
index ca63f16ce..17b21f5f0 100644
--- a/lib/dojo/_base/_loader/hostenv_spidermonkey.js
+++ b/lib/dojo/_base/_loader/hostenv_spidermonkey.js
@@ -5,46 +5,83 @@
*/
+/*
+ * SpiderMonkey host environment
+ */
+
if(dojo.config["baseUrl"]){
-dojo.baseUrl=dojo.config["baseUrl"];
+ dojo.baseUrl = dojo.config["baseUrl"];
}else{
-dojo.baseUrl="./";
+ dojo.baseUrl = "./";
}
-dojo._name="spidermonkey";
-dojo.isSpidermonkey=true;
-dojo.exit=function(_1){
-quit(_1);
+
+dojo._name = 'spidermonkey';
+
+/*=====
+dojo.isSpidermonkey = {
+ // summary: Detect spidermonkey
};
-if(typeof print=="function"){
-console.debug=print;
-}
-if(typeof line2pc=="undefined"){
-throw new Error("attempt to use SpiderMonkey host environment when no 'line2pc' global");
+=====*/
+
+dojo.isSpidermonkey = true;
+dojo.exit = function(exitcode){
+ quit(exitcode);
}
-dojo._spidermonkeyCurrentFile=function(_2){
-var s="";
-try{
-throw Error("whatever");
+
+if(typeof print == "function"){
+ console.debug = print;
}
-catch(e){
-s=e.stack;
+
+if(typeof line2pc == 'undefined'){
+ throw new Error("attempt to use SpiderMonkey host environment when no 'line2pc' global");
}
-var _3=s.match(/[^@]*\.js/gi);
-if(!_3){
-throw Error("could not parse stack string: '"+s+"'");
+
+dojo._spidermonkeyCurrentFile = function(depth){
+ //
+ // This is a hack that determines the current script file by parsing a
+ // generated stack trace (relying on the non-standard "stack" member variable
+ // of the SpiderMonkey Error object).
+ //
+ // If param depth is passed in, it'll return the script file which is that far down
+ // the stack, but that does require that you know how deep your stack is when you are
+ // calling.
+ //
+ var s = '';
+ try{
+ throw Error("whatever");
+ }catch(e){
+ s = e.stack;
+ }
+ // lines are like: bu_getCurrentScriptURI_spidermonkey("ScriptLoader.js")@burst/Runtime.js:101
+ var matches = s.match(/[^@]*\.js/gi);
+ if(!matches){
+ throw Error("could not parse stack string: '" + s + "'");
+ }
+ var fname = (typeof depth != 'undefined' && depth) ? matches[depth + 1] : matches[matches.length - 1];
+ if(!fname){
+ throw Error("could not find file name in stack string '" + s + "'");
+ }
+ //print("SpiderMonkeyRuntime got fname '" + fname + "' from stack string '" + s + "'");
+ return fname;
}
-var _4=(typeof _2!="undefined"&&_2)?_3[_2+1]:_3[_3.length-1];
-if(!_4){
-throw Error("could not find file name in stack string '"+s+"'");
+
+// print(dojo._spidermonkeyCurrentFile(0));
+
+dojo._loadUri = function(uri){
+ // spidermonkey load() evaluates the contents into the global scope (which
+ // is what we want).
+ // TODO: sigh, load() does not return a useful value.
+ // Perhaps it is returning the value of the last thing evaluated?
+ var ok = load(uri);
+ // console.log("spidermonkey load(", uri, ") returned ", ok);
+ return 1;
}
-return _4;
-};
-dojo._loadUri=function(_5){
-var ok=load(_5);
-return 1;
-};
+
+//Register any module paths set up in djConfig. Need to do this
+//in the hostenvs since hostenv_browser can read djConfig from a
+//script tag's attribute.
if(dojo.config["modulePaths"]){
-for(var param in dojo.config["modulePaths"]){
-dojo.registerModulePath(param,dojo.config["modulePaths"][param]);
-}
+ for(var param in dojo.config["modulePaths"]){
+ dojo.registerModulePath(param, dojo.config["modulePaths"][param]);
+ }
}
diff --git a/lib/dojo/_base/_loader/loader.js b/lib/dojo/_base/_loader/loader.js
index 3f31040a1..9206de888 100644
--- a/lib/dojo/_base/_loader/loader.js
+++ b/lib/dojo/_base/_loader/loader.js
@@ -5,296 +5,800 @@
*/
-if(!dojo._hasResource["dojo.foo"]){
-dojo._hasResource["dojo.foo"]=true;
+if(!dojo._hasResource["dojo.foo"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.foo"] = true;
+/*
+ * loader.js - A bootstrap module. Runs before the hostenv_*.js file. Contains
+ * all of the package loading methods.
+ */
+
(function(){
-var d=dojo;
-d.mixin(d,{_loadedModules:{},_inFlightCount:0,_hasResource:{},_modulePrefixes:{dojo:{name:"dojo",value:"."},doh:{name:"doh",value:"../util/doh"},tests:{name:"tests",value:"tests"}},_moduleHasPrefix:function(_1){
-var mp=d._modulePrefixes;
-return !!(mp[_1]&&mp[_1].value);
-},_getModulePrefix:function(_2){
-var mp=d._modulePrefixes;
-if(d._moduleHasPrefix(_2)){
-return mp[_2].value;
-}
-return _2;
-},_loadedUrls:[],_postLoad:false,_loaders:[],_unloaders:[],_loadNotifying:false});
-dojo._loadPath=function(_3,_4,cb){
-var _5=((_3.charAt(0)=="/"||_3.match(/^\w+:/))?"":d.baseUrl)+_3;
-try{
-return !_4?d._loadUri(_5,cb):d._loadUriAndCheck(_5,_4,cb);
-}
-catch(e){
-console.error(e);
-return false;
-}
-};
-dojo._loadUri=function(_6,cb){
-if(d._loadedUrls[_6]){
-return true;
-}
-d._inFlightCount++;
-var _7=d._getText(_6,true);
-if(_7){
-d._loadedUrls[_6]=true;
-d._loadedUrls.push(_6);
-if(cb){
-_7="("+_7+")";
-}else{
-_7=d._scopePrefix+_7+d._scopeSuffix;
-}
-if(!d.isIE){
-_7+="\r\n//@ sourceURL="+_6;
-}
-var _8=d["eval"](_7);
-if(cb){
-cb(_8);
-}
-}
-if(--d._inFlightCount==0&&d._postLoad&&d._loaders.length){
-setTimeout(function(){
-if(d._inFlightCount==0){
-d._callLoaded();
-}
-},0);
-}
-return !!_7;
-};
-dojo._loadUriAndCheck=function(_9,_a,cb){
-var ok=false;
-try{
-ok=d._loadUri(_9,cb);
-}
-catch(e){
-console.error("failed loading "+_9+" with error: "+e);
-}
-return !!(ok&&d._loadedModules[_a]);
-};
-dojo.loaded=function(){
-d._loadNotifying=true;
-d._postLoad=true;
-var _b=d._loaders;
-d._loaders=[];
-for(var x=0;x<_b.length;x++){
-_b[x]();
-}
-d._loadNotifying=false;
-if(d._postLoad&&d._inFlightCount==0&&_b.length){
-d._callLoaded();
-}
-};
-dojo.unloaded=function(){
-var _c=d._unloaders;
-while(_c.length){
-(_c.pop())();
-}
-};
-d._onto=function(_d,_e,fn){
-if(!fn){
-_d.push(_e);
-}else{
-if(fn){
-var _f=(typeof fn=="string")?_e[fn]:fn;
-_d.push(function(){
-_f.call(_e);
-});
-}
-}
-};
-dojo.ready=dojo.addOnLoad=function(obj,_10){
-d._onto(d._loaders,obj,_10);
-if(d._postLoad&&d._inFlightCount==0&&!d._loadNotifying){
-d._callLoaded();
-}
-};
-var dca=d.config.addOnLoad;
-if(dca){
-d.addOnLoad[(dca instanceof Array?"apply":"call")](d,dca);
-}
-dojo._modulesLoaded=function(){
-if(d._postLoad){
-return;
-}
-if(d._inFlightCount>0){
-console.warn("files still in flight!");
-return;
-}
-d._callLoaded();
-};
-dojo._callLoaded=function(){
-if(typeof setTimeout=="object"||(d.config.useXDomain&&d.isOpera)){
-setTimeout(d.isAIR?function(){
-d.loaded();
-}:d._scopeName+".loaded();",0);
-}else{
-d.loaded();
-}
-};
-dojo._getModuleSymbols=function(_11){
-var _12=_11.split(".");
-for(var i=_12.length;i>0;i--){
-var _13=_12.slice(0,i).join(".");
-if(i==1&&!d._moduleHasPrefix(_13)){
-_12[0]="../"+_12[0];
-}else{
-var _14=d._getModulePrefix(_13);
-if(_14!=_13){
-_12.splice(0,i,_14);
-break;
-}
-}
-}
-return _12;
-};
-dojo._global_omit_module_check=false;
-dojo.loadInit=function(_15){
-_15();
-};
-dojo._loadModule=dojo.require=function(_16,_17){
-_17=d._global_omit_module_check||_17;
-var _18=d._loadedModules[_16];
-if(_18){
-return _18;
-}
-var _19=d._getModuleSymbols(_16).join("/")+".js";
-var _1a=!_17?_16:null;
-var ok=d._loadPath(_19,_1a);
-if(!ok&&!_17){
-throw new Error("Could not load '"+_16+"'; last tried '"+_19+"'");
-}
-if(!_17&&!d._isXDomain){
-_18=d._loadedModules[_16];
-if(!_18){
-throw new Error("symbol '"+_16+"' is not defined after loading '"+_19+"'");
-}
-}
-return _18;
-};
-dojo.provide=function(_1b){
-_1b=_1b+"";
-return (d._loadedModules[_1b]=d.getObject(_1b,true));
-};
-dojo.platformRequire=function(_1c){
-var _1d=_1c.common||[];
-var _1e=_1d.concat(_1c[d._name]||_1c["default"]||[]);
-for(var x=0;x<_1e.length;x++){
-var _1f=_1e[x];
-if(_1f.constructor==Array){
-d._loadModule.apply(d,_1f);
-}else{
-d._loadModule(_1f);
-}
-}
-};
-dojo.requireIf=function(_20,_21){
-if(_20===true){
-var _22=[];
-for(var i=1;i<arguments.length;i++){
-_22.push(arguments[i]);
-}
-d.require.apply(d,_22);
-}
-};
-dojo.requireAfterIf=d.requireIf;
-dojo.registerModulePath=function(_23,_24){
-d._modulePrefixes[_23]={name:_23,value:_24};
-};
-dojo.requireLocalization=function(_25,_26,_27,_28){
-d.require("dojo.i18n");
-d.i18n._requireLocalization.apply(d.hostenv,arguments);
-};
-var ore=new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$"),ire=new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$");
-dojo._Url=function(){
-var n=null,_29=arguments,uri=[_29[0]];
-for(var i=1;i<_29.length;i++){
-if(!_29[i]){
-continue;
-}
-var _2a=new d._Url(_29[i]+""),_2b=new d._Url(uri[0]+"");
-if(_2a.path==""&&!_2a.scheme&&!_2a.authority&&!_2a.query){
-if(_2a.fragment!=n){
-_2b.fragment=_2a.fragment;
-}
-_2a=_2b;
-}else{
-if(!_2a.scheme){
-_2a.scheme=_2b.scheme;
-if(!_2a.authority){
-_2a.authority=_2b.authority;
-if(_2a.path.charAt(0)!="/"){
-var _2c=_2b.path.substring(0,_2b.path.lastIndexOf("/")+1)+_2a.path;
-var _2d=_2c.split("/");
-for(var j=0;j<_2d.length;j++){
-if(_2d[j]=="."){
-if(j==_2d.length-1){
-_2d[j]="";
-}else{
-_2d.splice(j,1);
-j--;
-}
-}else{
-if(j>0&&!(j==1&&_2d[0]=="")&&_2d[j]==".."&&_2d[j-1]!=".."){
-if(j==(_2d.length-1)){
-_2d.splice(j,1);
-_2d[j-1]="";
-}else{
-_2d.splice(j-1,2);
-j-=2;
-}
-}
-}
-}
-_2a.path=_2d.join("/");
-}
-}
-}
-}
-uri=[];
-if(_2a.scheme){
-uri.push(_2a.scheme,":");
-}
-if(_2a.authority){
-uri.push("//",_2a.authority);
-}
-uri.push(_2a.path);
-if(_2a.query){
-uri.push("?",_2a.query);
-}
-if(_2a.fragment){
-uri.push("#",_2a.fragment);
-}
-}
-this.uri=uri.join("");
-var r=this.uri.match(ore);
-this.scheme=r[2]||(r[1]?"":n);
-this.authority=r[4]||(r[3]?"":n);
-this.path=r[5];
-this.query=r[7]||(r[6]?"":n);
-this.fragment=r[9]||(r[8]?"":n);
-if(this.authority!=n){
-r=this.authority.match(ire);
-this.user=r[3]||n;
-this.password=r[4]||n;
-this.host=r[6]||r[7];
-this.port=r[9]||n;
-}
-};
-dojo._Url.prototype.toString=function(){
-return this.uri;
-};
-dojo.moduleUrl=function(_2e,url){
-var loc=d._getModuleSymbols(_2e).join("/");
-if(!loc){
-return null;
-}
-if(loc.lastIndexOf("/")!=loc.length-1){
-loc+="/";
-}
-var _2f=loc.indexOf(":");
-if(loc.charAt(0)!="/"&&(_2f==-1||_2f>loc.indexOf("/"))){
-loc=d.baseUrl+loc;
-}
-return new d._Url(loc,url);
-};
+ var d = dojo;
+
+ d.mixin(d, {
+ _loadedModules: {},
+ _inFlightCount: 0,
+ _hasResource: {},
+
+ _modulePrefixes: {
+ dojo: { name: "dojo", value: "." },
+ // dojox: { name: "dojox", value: "../dojox" },
+ // dijit: { name: "dijit", value: "../dijit" },
+ doh: { name: "doh", value: "../util/doh" },
+ tests: { name: "tests", value: "tests" }
+ },
+
+ _moduleHasPrefix: function(/*String*/module){
+ // summary: checks to see if module has been established
+ var mp = d._modulePrefixes;
+ return !!(mp[module] && mp[module].value); // Boolean
+ },
+
+ _getModulePrefix: function(/*String*/module){
+ // summary: gets the prefix associated with module
+ var mp = d._modulePrefixes;
+ if(d._moduleHasPrefix(module)){
+ return mp[module].value; // String
+ }
+ return module; // String
+ },
+
+ _loadedUrls: [],
+
+ //WARNING:
+ // This variable is referenced by packages outside of bootstrap:
+ // FloatingPane.js and undo/browser.js
+ _postLoad: false,
+
+ //Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
+ _loaders: [],
+ _unloaders: [],
+ _loadNotifying: false
+ });
+
+
+ dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){
+ // summary:
+ // Load a Javascript module given a relative path
+ //
+ // description:
+ // Loads and interprets the script located at relpath, which is
+ // relative to the script root directory. If the script is found but
+ // its interpretation causes a runtime exception, that exception is
+ // not caught by us, so the caller will see it. We return a true
+ // value if and only if the script is found.
+ //
+ // relpath:
+ // A relative path to a script (no leading '/', and typically ending
+ // in '.js').
+ // module:
+ // A module whose existance to check for after loading a path. Can be
+ // used to determine success or failure of the load.
+ // cb:
+ // a callback function to pass the result of evaluating the script
+
+ var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : d.baseUrl) + relpath;
+ try{
+ return !module ? d._loadUri(uri, cb) : d._loadUriAndCheck(uri, module, cb); // Boolean
+ }catch(e){
+ console.error(e);
+ return false; // Boolean
+ }
+ }
+
+ dojo._loadUri = function(/*String*/uri, /*Function?*/cb){
+ // summary:
+ // Loads JavaScript from a URI
+ // description:
+ // Reads the contents of the URI, and evaluates the contents. This is
+ // used to load modules as well as resource bundles. Returns true if
+ // it succeeded. Returns false if the URI reading failed. Throws if
+ // the evaluation throws.
+ // uri: a uri which points at the script to be loaded
+ // cb:
+ // a callback function to process the result of evaluating the script
+ // as an expression, typically used by the resource bundle loader to
+ // load JSON-style resources
+
+ if(d._loadedUrls[uri]){
+ return true; // Boolean
+ }
+ d._inFlightCount++; // block addOnLoad calls that arrive while we're busy downloading
+ var contents = d._getText(uri, true);
+ if(contents){ // not 404, et al
+ d._loadedUrls[uri] = true;
+ d._loadedUrls.push(uri);
+ if(cb){
+ contents = '('+contents+')';
+ }else{
+ //Only do the scoping if no callback. If a callback is specified,
+ //it is most likely the i18n bundle stuff.
+ contents = d._scopePrefix + contents + d._scopeSuffix;
+ }
+ if(!d.isIE){ contents += "\r\n//@ sourceURL=" + uri; } // debugging assist for Firebug
+ var value = d["eval"](contents);
+ if(cb){ cb(value); }
+ }
+ // Check to see if we need to call _callLoaded() due to an addOnLoad() that arrived while we were busy downloading
+ if(--d._inFlightCount == 0 && d._postLoad && d._loaders.length){
+ // We shouldn't be allowed to get here but Firefox allows an event
+ // (mouse, keybd, async xhrGet) to interrupt a synchronous xhrGet.
+ // If the current script block contains multiple require() statements, then after each
+ // require() returns, inFlightCount == 0, but we want to hold the _callLoaded() until
+ // all require()s are done since the out-of-sequence addOnLoad() presumably needs them all.
+ // setTimeout allows the next require() to start (if needed), and then we check this again.
+ setTimeout(function(){
+ // If inFlightCount > 0, then multiple require()s are running sequentially and
+ // the next require() started after setTimeout() was executed but before we got here.
+ if(d._inFlightCount == 0){
+ d._callLoaded();
+ }
+ }, 0);
+ }
+ return !!contents; // Boolean: contents? true : false
+ }
+
+ // FIXME: probably need to add logging to this method
+ dojo._loadUriAndCheck = function(/*String*/uri, /*String*/moduleName, /*Function?*/cb){
+ // summary: calls loadUri then findModule and returns true if both succeed
+ var ok = false;
+ try{
+ ok = d._loadUri(uri, cb);
+ }catch(e){
+ console.error("failed loading " + uri + " with error: " + e);
+ }
+ return !!(ok && d._loadedModules[moduleName]); // Boolean
+ }
+
+ dojo.loaded = function(){
+ // summary:
+ // signal fired when initial environment and package loading is
+ // complete. You should use dojo.addOnLoad() instead of doing a
+ // direct dojo.connect() to this method in order to handle
+ // initialization tasks that require the environment to be
+ // initialized. In a browser host, declarative widgets will
+ // be constructed when this function finishes runing.
+ d._loadNotifying = true;
+ d._postLoad = true;
+ var mll = d._loaders;
+
+ //Clear listeners so new ones can be added
+ //For other xdomain package loads after the initial load.
+ d._loaders = [];
+
+ for(var x = 0; x < mll.length; x++){
+ mll[x]();
+ }
+
+ d._loadNotifying = false;
+
+ //Make sure nothing else got added to the onload queue
+ //after this first run. If something did, and we are not waiting for any
+ //more inflight resources, run again.
+ if(d._postLoad && d._inFlightCount == 0 && mll.length){
+ d._callLoaded();
+ }
+ }
+
+ dojo.unloaded = function(){
+ // summary:
+ // signal fired by impending environment destruction. You should use
+ // dojo.addOnUnload() instead of doing a direct dojo.connect() to this
+ // method to perform page/application cleanup methods. See
+ // dojo.addOnUnload for more info.
+ var mll = d._unloaders;
+ while(mll.length){
+ (mll.pop())();
+ }
+ }
+
+ d._onto = function(arr, obj, fn){
+ if(!fn){
+ arr.push(obj);
+ }else if(fn){
+ var func = (typeof fn == "string") ? obj[fn] : fn;
+ arr.push(function(){ func.call(obj); });
+ }
+ }
+
+ dojo.ready = dojo.addOnLoad = function(/*Object*/obj, /*String|Function?*/functionName){
+ // summary:
+ // Registers a function to be triggered after the DOM and dojo.require() calls
+ // have finished loading.
+ //
+ // description:
+ // Registers a function to be triggered after the DOM has finished
+ // loading and `dojo.require` modules have loaded. Widgets declared in markup
+ // have been instantiated if `djConfig.parseOnLoad` is true when this fires.
+ //
+ // Images and CSS files may or may not have finished downloading when
+ // the specified function is called. (Note that widgets' CSS and HTML
+ // code is guaranteed to be downloaded before said widgets are
+ // instantiated, though including css resouces BEFORE any script elements
+ // is highly recommended).
+ //
+ // example:
+ // Register an anonymous function to run when everything is ready
+ // | dojo.addOnLoad(function(){ doStuff(); });
+ //
+ // example:
+ // Register a function to run when everything is ready by pointer:
+ // | var init = function(){ doStuff(); }
+ // | dojo.addOnLoad(init);
+ //
+ // example:
+ // Register a function to run scoped to `object`, either by name or anonymously:
+ // | dojo.addOnLoad(object, "functionName");
+ // | dojo.addOnLoad(object, function(){ doStuff(); });
+
+ d._onto(d._loaders, obj, functionName);
+
+ //Added for xdomain loading. dojo.addOnLoad is used to
+ //indicate callbacks after doing some dojo.require() statements.
+ //In the xdomain case, if all the requires are loaded (after initial
+ //page load), then immediately call any listeners.
+ if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){
+ d._callLoaded();
+ }
+ }
+
+ //Support calling dojo.addOnLoad via djConfig.addOnLoad. Support all the
+ //call permutations of dojo.addOnLoad. Mainly useful when dojo is added
+ //to the page after the page has loaded.
+ var dca = d.config.addOnLoad;
+ if(dca){
+ d.addOnLoad[(dca instanceof Array ? "apply" : "call")](d, dca);
+ }
+
+ dojo._modulesLoaded = function(){
+ if(d._postLoad){ return; }
+ if(d._inFlightCount > 0){
+ console.warn("files still in flight!");
+ return;
+ }
+ d._callLoaded();
+ }
+
+ dojo._callLoaded = function(){
+
+ // The "object" check is for IE, and the other opera check fixes an
+ // issue in Opera where it could not find the body element in some
+ // widget test cases. For 0.9, maybe route all browsers through the
+ // setTimeout (need protection still for non-browser environments
+ // though). This might also help the issue with FF 2.0 and freezing
+ // issues where we try to do sync xhr while background css images are
+ // being loaded (trac #2572)? Consider for 0.9.
+ if(typeof setTimeout == "object" || (d.config.useXDomain && d.isOpera)){
+ setTimeout(
+ d.isAIR ? function(){ d.loaded(); } : d._scopeName + ".loaded();",
+ 0);
+ }else{
+ d.loaded();
+ }
+ }
+
+ dojo._getModuleSymbols = function(/*String*/modulename){
+ // summary:
+ // Converts a module name in dotted JS notation to an array
+ // representing the path in the source tree
+ var syms = modulename.split(".");
+ for(var i = syms.length; i>0; i--){
+ var parentModule = syms.slice(0, i).join(".");
+ if(i == 1 && !d._moduleHasPrefix(parentModule)){
+ // Support default module directory (sibling of dojo) for top-level modules
+ syms[0] = "../" + syms[0];
+ }else{
+ var parentModulePath = d._getModulePrefix(parentModule);
+ if(parentModulePath != parentModule){
+ syms.splice(0, i, parentModulePath);
+ break;
+ }
+ }
+ }
+ return syms; // Array
+ }
+
+ dojo._global_omit_module_check = false;
+
+ dojo.loadInit = function(/*Function*/init){
+ // summary:
+ // Executes a function that needs to be executed for the loader's dojo.requireIf
+ // resolutions to work. This is needed mostly for the xdomain loader case where
+ // a function needs to be executed to set up the possible values for a dojo.requireIf
+ // call.
+ // init:
+ // a function reference. Executed immediately.
+ // description: This function is mainly a marker for the xdomain loader to know parts of
+ // code that needs be executed outside the function wrappper that is placed around modules.
+ // The init function could be executed more than once, and it should make no assumptions
+ // on what is loaded, or what modules are available. Only the functionality in Dojo Base
+ // is allowed to be used. Avoid using this method. For a valid use case,
+ // see the source for dojox.gfx.
+ init();
+ }
+
+ dojo._loadModule = dojo.require = function(/*String*/moduleName, /*Boolean?*/omitModuleCheck){
+ // summary:
+ // loads a Javascript module from the appropriate URI
+ // moduleName:
+ // module name to load, using periods for separators,
+ // e.g. "dojo.date.locale". Module paths are de-referenced by dojo's
+ // internal mapping of locations to names and are disambiguated by
+ // longest prefix. See `dojo.registerModulePath()` for details on
+ // registering new modules.
+ // omitModuleCheck:
+ // if `true`, omitModuleCheck skips the step of ensuring that the
+ // loaded file actually defines the symbol it is referenced by.
+ // For example if it called as `dojo.require("a.b.c")` and the
+ // file located at `a/b/c.js` does not define an object `a.b.c`,
+ // and exception will be throws whereas no exception is raised
+ // when called as `dojo.require("a.b.c", true)`
+ // description:
+ // Modules are loaded via dojo.require by using one of two loaders: the normal loader
+ // and the xdomain loader. The xdomain loader is used when dojo was built with a
+ // custom build that specified loader=xdomain and the module lives on a modulePath
+ // that is a whole URL, with protocol and a domain. The versions of Dojo that are on
+ // the Google and AOL CDNs use the xdomain loader.
+ //
+ // If the module is loaded via the xdomain loader, it is an asynchronous load, since
+ // the module is added via a dynamically created script tag. This
+ // means that dojo.require() can return before the module has loaded. However, this
+ // should only happen in the case where you do dojo.require calls in the top-level
+ // HTML page, or if you purposely avoid the loader checking for dojo.require
+ // dependencies in your module by using a syntax like dojo["require"] to load the module.
+ //
+ // Sometimes it is useful to not have the loader detect the dojo.require calls in the
+ // module so that you can dynamically load the modules as a result of an action on the
+ // page, instead of right at module load time.
+ //
+ // Also, for script blocks in an HTML page, the loader does not pre-process them, so
+ // it does not know to download the modules before the dojo.require calls occur.
+ //
+ // So, in those two cases, when you want on-the-fly module loading or for script blocks
+ // in the HTML page, special care must be taken if the dojo.required code is loaded
+ // asynchronously. To make sure you can execute code that depends on the dojo.required
+ // modules, be sure to add the code that depends on the modules in a dojo.addOnLoad()
+ // callback. dojo.addOnLoad waits for all outstanding modules to finish loading before
+ // executing. Example:
+ //
+ // | <script type="text/javascript">
+ // | dojo.require("foo");
+ // | dojo.require("bar");
+ // | dojo.addOnLoad(function(){
+ // | //you can now safely do something with foo and bar
+ // | });
+ // | </script>
+ //
+ // This type of syntax works with both xdomain and normal loaders, so it is good
+ // practice to always use this idiom for on-the-fly code loading and in HTML script
+ // blocks. If at some point you change loaders and where the code is loaded from,
+ // it will all still work.
+ //
+ // More on how dojo.require
+ // `dojo.require("A.B")` first checks to see if symbol A.B is
+ // defined. If it is, it is simply returned (nothing to do).
+ //
+ // If it is not defined, it will look for `A/B.js` in the script root
+ // directory.
+ //
+ // `dojo.require` throws an excpetion if it cannot find a file
+ // to load, or if the symbol `A.B` is not defined after loading.
+ //
+ // It returns the object `A.B`, but note the caveats above about on-the-fly loading and
+ // HTML script blocks when the xdomain loader is loading a module.
+ //
+ // `dojo.require()` does nothing about importing symbols into
+ // the current namespace. It is presumed that the caller will
+ // take care of that. For example, to import all symbols into a
+ // local block, you might write:
+ //
+ // | with (dojo.require("A.B")) {
+ // | ...
+ // | }
+ //
+ // And to import just the leaf symbol to a local variable:
+ //
+ // | var B = dojo.require("A.B");
+ // | ...
+ // returns: the required namespace object
+ omitModuleCheck = d._global_omit_module_check || omitModuleCheck;
+
+ //Check if it is already loaded.
+ var module = d._loadedModules[moduleName];
+ if(module){
+ return module;
+ }
+
+ // convert periods to slashes
+ var relpath = d._getModuleSymbols(moduleName).join("/") + '.js';
+
+ var modArg = !omitModuleCheck ? moduleName : null;
+ var ok = d._loadPath(relpath, modArg);
+
+ if(!ok && !omitModuleCheck){
+ throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
+ }
+
+ // check that the symbol was defined
+ // Don't bother if we're doing xdomain (asynchronous) loading.
+ if(!omitModuleCheck && !d._isXDomain){
+ // pass in false so we can give better error
+ module = d._loadedModules[moduleName];
+ if(!module){
+ throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'");
+ }
+ }
+
+ return module;
+ }
+
+ dojo.provide = function(/*String*/ resourceName){
+ // summary:
+ // Register a resource with the package system. Works in conjunction with `dojo.require`
+ //
+ // description:
+ // Each javascript source file is called a resource. When a
+ // resource is loaded by the browser, `dojo.provide()` registers
+ // that it has been loaded.
+ //
+ // Each javascript source file must have at least one
+ // `dojo.provide()` call at the top of the file, corresponding to
+ // the file name. For example, `js/dojo/foo.js` must have
+ // `dojo.provide("dojo.foo");` before any calls to
+ // `dojo.require()` are made.
+ //
+ // For backwards compatibility reasons, in addition to registering
+ // the resource, `dojo.provide()` also ensures that the javascript
+ // object for the module exists. For example,
+ // `dojo.provide("dojox.data.FlickrStore")`, in addition to
+ // registering that `FlickrStore.js` is a resource for the
+ // `dojox.data` module, will ensure that the `dojox.data`
+ // javascript object exists, so that calls like
+ // `dojo.data.foo = function(){ ... }` don't fail.
+ //
+ // In the case of a build where multiple javascript source files
+ // are combined into one bigger file (similar to a .lib or .jar
+ // file), that file may contain multiple dojo.provide() calls, to
+ // note that it includes multiple resources.
+ //
+ // resourceName: String
+ // A dot-sperated string identifying a resource.
+ //
+ // example:
+ // Safely create a `my` object, and make dojo.require("my.CustomModule") work
+ // | dojo.provide("my.CustomModule");
+
+ //Make sure we have a string.
+ resourceName = resourceName + "";
+ return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object
+ }
+
+ //Start of old bootstrap2:
+
+ dojo.platformRequire = function(/*Object*/modMap){
+ // summary:
+ // require one or more modules based on which host environment
+ // Dojo is currently operating in
+ // description:
+ // This method takes a "map" of arrays which one can use to
+ // optionally load dojo modules. The map is indexed by the
+ // possible dojo.name_ values, with two additional values:
+ // "default" and "common". The items in the "default" array will
+ // be loaded if none of the other items have been choosen based on
+ // dojo.name_, set by your host environment. The items in the
+ // "common" array will *always* be loaded, regardless of which
+ // list is chosen.
+ // example:
+ // | dojo.platformRequire({
+ // | browser: [
+ // | "foo.sample", // simple module
+ // | "foo.test",
+ // | ["foo.bar.baz", true] // skip object check in _loadModule (dojo.require)
+ // | ],
+ // | default: [ "foo.sample._base" ],
+ // | common: [ "important.module.common" ]
+ // | });
+
+ var common = modMap.common || [];
+ var result = common.concat(modMap[d._name] || modMap["default"] || []);
+
+ for(var x=0; x<result.length; x++){
+ var curr = result[x];
+ if(curr.constructor == Array){
+ d._loadModule.apply(d, curr);
+ }else{
+ d._loadModule(curr);
+ }
+ }
+ }
+
+ dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){
+ // summary:
+ // If the condition is true then call `dojo.require()` for the specified
+ // resource
+ //
+ // example:
+ // | dojo.requireIf(dojo.isBrowser, "my.special.Module");
+
+ if(condition === true){
+ // FIXME: why do we support chained require()'s here? does the build system?
+ var args = [];
+ for(var i = 1; i < arguments.length; i++){
+ args.push(arguments[i]);
+ }
+ d.require.apply(d, args);
+ }
+ }
+
+ dojo.requireAfterIf = d.requireIf;
+
+ dojo.registerModulePath = function(/*String*/module, /*String*/prefix){
+ // summary:
+ // Maps a module name to a path
+ // description:
+ // An unregistered module is given the default path of ../[module],
+ // relative to Dojo root. For example, module acme is mapped to
+ // ../acme. If you want to use a different module name, use
+ // dojo.registerModulePath.
+ // example:
+ // If your dojo.js is located at this location in the web root:
+ // | /myapp/js/dojo/dojo/dojo.js
+ // and your modules are located at:
+ // | /myapp/js/foo/bar.js
+ // | /myapp/js/foo/baz.js
+ // | /myapp/js/foo/thud/xyzzy.js
+ // Your application can tell Dojo to locate the "foo" namespace by calling:
+ // | dojo.registerModulePath("foo", "../../foo");
+ // At which point you can then use dojo.require() to load the
+ // modules (assuming they provide() the same things which are
+ // required). The full code might be:
+ // | <script type="text/javascript"
+ // | src="/myapp/js/dojo/dojo/dojo.js"></script>
+ // | <script type="text/javascript">
+ // | dojo.registerModulePath("foo", "../../foo");
+ // | dojo.require("foo.bar");
+ // | dojo.require("foo.baz");
+ // | dojo.require("foo.thud.xyzzy");
+ // | </script>
+ d._modulePrefixes[module] = { name: module, value: prefix };
+ }
+
+ dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
+ // summary:
+ // Declares translated resources and loads them if necessary, in the
+ // same style as dojo.require. Contents of the resource bundle are
+ // typically strings, but may be any name/value pair, represented in
+ // JSON format. See also `dojo.i18n.getLocalization`.
+ //
+ // 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.
+ //
+ // 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.
+ //
+ // 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. Using "nls" as a
+ // a bundle name is not supported, since "nls" is the name of the folder
+ // that holds bundles. Using "nls" as the bundle name will cause problems
+ // with the custom build.
+ //
+ // 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.
+ //
+ // 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
+ // | ...
+ //
+
+ d.require("dojo.i18n");
+ d.i18n._requireLocalization.apply(d.hostenv, arguments);
+ };
+
+
+ var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$"),
+ 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,
+ _a = arguments,
+ 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]+""),
+ 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[6] || r[7]; // ipv6 || ipv4
+ this.port = r[9] || 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); // dojo._Url
+ }
})();
+
}
diff --git a/lib/dojo/_base/_loader/loader_debug.js b/lib/dojo/_base/_loader/loader_debug.js
index a28040f58..fa26d8efb 100644
--- a/lib/dojo/_base/_loader/loader_debug.js
+++ b/lib/dojo/_base/_loader/loader_debug.js
@@ -5,55 +5,82 @@
*/
-if(!dojo._hasResource["dojo._base._loader.loader_debug"]){
-dojo._hasResource["dojo._base._loader.loader_debug"]=true;
+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");
-dojo.nonDebugProvide=dojo.provide;
-dojo.provide=function(_1){
-var _2=dojo["_xdDebugQueue"];
-if(_2&&_2.length>0&&_1==_2["currentResourceName"]){
-if(dojo.isAIR){
-window.setTimeout(function(){
-dojo._xdDebugFileLoaded(_1);
-},1);
-}else{
-window.setTimeout(dojo._scopeName+"._xdDebugFileLoaded('"+_1+"')",1);
-}
-}
-return dojo.nonDebugProvide.apply(dojo,arguments);
-};
-dojo._xdDebugFileLoaded=function(_3){
-if(!dojo._xdDebugScopeChecked){
-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]];
-}
-dojo._xdDebugScopeChecked=true;
-}
-var _4=dojo._xdDebugQueue;
-if(_3&&_3==_4.currentResourceName){
-_4.shift();
-}
-if(_4.length==0){
-dojo._xdWatchInFlight();
-}
-if(_4.length==0){
-_4.currentResourceName=null;
-for(var _5 in dojo._xdInFlight){
-if(dojo._xdInFlight[_5]===true){
-return;
-}
-}
-dojo._xdNotifyLoaded();
-}else{
-if(_3==_4.currentResourceName){
-_4.currentResourceName=_4[0].resourceName;
-var _6=document.createElement("script");
-_6.type="text/javascript";
-_6.src=_4[0].resourcePath;
-document.getElementsByTagName("head")[0].appendChild(_6);
+
+//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(!dojo._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]];
+ }
+
+ dojo._xdDebugScopeChecked = true;
+ }
+
+ var dbgQueue = dojo._xdDebugQueue;
+
+ if(resourceName && resourceName == dbgQueue.currentResourceName){
+ dbgQueue.shift();
+ }
+
+ if(dbgQueue.length == 0){
+ //Check for more modules that need debug loading.
+ //dojo._xdWatchInFlight will add more things to the debug
+ //queue if they just recently loaded but it was not detected
+ //between the dojo._xdWatchInFlight intervals.
+ dojo._xdWatchInFlight();
+ }
+
+ if(dbgQueue.length == 0){
+ dbgQueue.currentResourceName = null;
+
+ //Make sure nothing else is in flight.
+ //If something is still in flight, then it still
+ //needs to be added to debug queue after it loads.
+ for(var param in dojo._xdInFlight){
+ if(dojo._xdInFlight[param] === true){
+ return;
+ }
+ }
+
+ dojo._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/lib/dojo/_base/_loader/loader_xd.js b/lib/dojo/_base/_loader/loader_xd.js
index 2ecab3db6..c60b86b05 100644
--- a/lib/dojo/_base/_loader/loader_xd.js
+++ b/lib/dojo/_base/_loader/loader_xd.js
@@ -5,461 +5,719 @@
*/
-if(!dojo._hasResource["dojo._base._loader.loader_xd"]){
-dojo._hasResource["dojo._base._loader.loader_xd"]=true;
+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(){
-dojo._isXDomain=dojo.config.useXDomain||false;
-dojo._xdClearInterval();
-dojo._xdInFlight={};
-dojo._xdOrderedReqs=[];
-dojo._xdDepMap={};
-dojo._xdContents=[];
-dojo._xdDefList=[];
-};
-dojo._xdClearInterval=function(){
-if(dojo._xdTimer){
-clearInterval(dojo._xdTimer);
-dojo._xdTimer=0;
-}
-};
-dojo._xdReset();
-dojo._xdCreateResource=function(_1,_2,_3){
-var _4=_1.replace(/(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg,"");
-var _5=[];
-var _6=/dojo.(require|requireIf|provide|requireAfterIf|platformRequire|requireLocalization)\s*\(([\w\W]*?)\)/mg;
-var _7;
-while((_7=_6.exec(_4))!=null){
-if(_7[1]=="requireLocalization"){
-eval(_7[0]);
-}else{
-_5.push("\""+_7[1]+"\", "+_7[2]);
-}
-}
-var _8=[];
-_8.push(dojo._scopeName+"._xdResourceLoaded(function("+dojo._scopePrefixArgs+"){\n");
-var _9=dojo._xdExtractLoadInits(_1);
-if(_9){
-_1=_9[0];
-for(var i=1;i<_9.length;i++){
-_8.push(_9[i]+";\n");
-}
-}
-_8.push("return {");
-if(_5.length>0){
-_8.push("depends: [");
-for(i=0;i<_5.length;i++){
-if(i>0){
-_8.push(",\n");
-}
-_8.push("["+_5[i]+"]");
-}
-_8.push("],");
-}
-_8.push("\ndefineResource: function("+dojo._scopePrefixArgs+"){");
-if(!dojo.config["debugAtAllCosts"]||_2=="dojo._base._loader.loader_debug"){
-_8.push(_1);
-}
-_8.push("\n}, resourceName: '"+_2+"', resourcePath: '"+_3+"'};});");
-return _8.join("");
-};
-dojo._xdExtractLoadInits=function(_a){
-var _b=/dojo.loadInit\s*\(/g;
-_b.lastIndex=0;
-var _c=/[\(\)]/g;
-_c.lastIndex=0;
-var _d=[];
-var _e;
-while((_e=_b.exec(_a))){
-_c.lastIndex=_b.lastIndex;
-var _f=1;
-var _10;
-while((_10=_c.exec(_a))){
-if(_10[0]==")"){
-_f-=1;
-}else{
-_f+=1;
-}
-if(_f==0){
-break;
-}
-}
-if(_f!=0){
-throw "unmatched paren around character "+_c.lastIndex+" in: "+_a;
-}
-var _11=_b.lastIndex-_e[0].length;
-_d.push(_a.substring(_11,_c.lastIndex));
-var _12=_c.lastIndex-_11;
-_a=_a.substring(0,_11)+_a.substring(_c.lastIndex,_a.length);
-_b.lastIndex=_c.lastIndex-_12;
-_b.lastIndex=_c.lastIndex;
-}
-if(_d.length>0){
-_d.unshift(_a);
-}
-return (_d.length?_d:null);
-};
-dojo._xdIsXDomainPath=function(_13){
-var _14=_13.indexOf(":");
-var _15=_13.indexOf("/");
-if(_14>0&&_14<_15){
-return true;
-}else{
-var url=dojo.baseUrl;
-_14=url.indexOf(":");
-_15=url.indexOf("/");
-if(_14>0&&_14<_15&&(!location.host||url.indexOf("http://"+location.host)!=0)){
-return true;
-}
-}
-return false;
-};
-dojo._loadPath=function(_16,_17,cb){
-var _18=dojo._xdIsXDomainPath(_16);
-dojo._isXDomain|=_18;
-var uri=((_16.charAt(0)=="/"||_16.match(/^\w+:/))?"":dojo.baseUrl)+_16;
-try{
-return ((!_17||dojo._isXDomain)?dojo._loadUri(uri,cb,_18,_17):dojo._loadUriAndCheck(uri,_17,cb));
-}
-catch(e){
-console.error(e);
-return false;
-}
-};
-dojo._xdCharSet="utf-8";
-dojo._loadUri=function(uri,cb,_19,_1a){
-if(dojo._loadedUrls[uri]){
-return 1;
-}
-if(dojo._isXDomain&&_1a&&_1a!="dojo.i18n"){
-dojo._xdOrderedReqs.push(_1a);
-if(_19||uri.indexOf("/nls/")==-1){
-dojo._xdInFlight[_1a]=true;
-dojo._inFlightCount++;
-}
-if(!dojo._xdTimer){
-if(dojo.isAIR){
-dojo._xdTimer=setInterval(function(){
-dojo._xdWatchInFlight();
-},100);
-}else{
-dojo._xdTimer=setInterval(dojo._scopeName+"._xdWatchInFlight();",100);
-}
-}
-dojo._xdStartTime=(new Date()).getTime();
-}
-if(_19){
-var _1b=uri.lastIndexOf(".");
-if(_1b<=0){
-_1b=uri.length-1;
-}
-var _1c=uri.substring(0,_1b)+".xd";
-if(_1b!=uri.length-1){
-_1c+=uri.substring(_1b,uri.length);
-}
-if(dojo.isAIR){
-_1c=_1c.replace("app:/","/");
-}
-var _1d=document.createElement("script");
-_1d.type="text/javascript";
-if(dojo._xdCharSet){
-_1d.charset=dojo._xdCharSet;
-}
-_1d.src=_1c;
-if(!dojo.headElement){
-dojo._headElement=document.getElementsByTagName("head")[0];
-if(!dojo._headElement){
-dojo._headElement=document.getElementsByTagName("html")[0];
-}
-}
-dojo._headElement.appendChild(_1d);
-}else{
-var _1e=dojo._getText(uri,null,true);
-if(_1e==null){
-return 0;
-}
-if(dojo._isXDomain&&uri.indexOf("/nls/")==-1&&_1a!="dojo.i18n"){
-var res=dojo._xdCreateResource(_1e,_1a,uri);
-dojo.eval(res);
-}else{
-if(cb){
-_1e="("+_1e+")";
-}else{
-_1e=dojo._scopePrefix+_1e+dojo._scopeSuffix;
-}
-var _1f=dojo["eval"](_1e+"\r\n//@ sourceURL="+uri);
-if(cb){
-cb(_1f);
-}
-}
-}
-dojo._loadedUrls[uri]=true;
-dojo._loadedUrls.push(uri);
-return true;
-};
-dojo._xdResourceLoaded=function(res){
-res=res.apply(dojo.global,dojo._scopeArgs);
-var _20=res.depends;
-var _21=null;
-var _22=null;
-var _23=[];
-if(_20&&_20.length>0){
-var dep=null;
-var _24=0;
-var _25=false;
-for(var i=0;i<_20.length;i++){
-dep=_20[i];
-if(dep[0]=="provide"){
-_23.push(dep[1]);
-}else{
-if(!_21){
-_21=[];
-}
-if(!_22){
-_22=[];
-}
-var _26=dojo._xdUnpackDependency(dep);
-if(_26.requires){
-_21=_21.concat(_26.requires);
-}
-if(_26.requiresAfter){
-_22=_22.concat(_26.requiresAfter);
-}
-}
-var _27=dep[0];
-var _28=_27.split(".");
-if(_28.length==2){
-dojo[_28[0]][_28[1]].apply(dojo[_28[0]],dep.slice(1));
-}else{
-dojo[_27].apply(dojo,dep.slice(1));
-}
-}
-if(_23.length==1&&_23[0]=="dojo._base._loader.loader_debug"){
-res.defineResource(dojo);
-}else{
-var _29=dojo._xdContents.push({content:res.defineResource,resourceName:res["resourceName"],resourcePath:res["resourcePath"],isDefined:false})-1;
-for(i=0;i<_23.length;i++){
-dojo._xdDepMap[_23[i]]={requires:_21,requiresAfter:_22,contentIndex:_29};
-}
-}
-for(i=0;i<_23.length;i++){
-dojo._xdInFlight[_23[i]]=false;
-}
-}
-};
-dojo._xdLoadFlattenedBundle=function(_2a,_2b,_2c,_2d){
-_2c=_2c||"root";
-var _2e=dojo.i18n.normalizeLocale(_2c).replace("-","_");
-var _2f=[_2a,"nls",_2b].join(".");
-var _30=dojo["provide"](_2f);
-_30[_2e]=_2d;
-var _31=[_2a,_2e,_2b].join(".");
-var _32=dojo._xdBundleMap[_31];
-if(_32){
-for(var _33 in _32){
-_30[_33]=_2d;
-}
-}
-};
-dojo._xdInitExtraLocales=function(){
-var _34=dojo.config.extraLocale;
-if(_34){
-if(!_34 instanceof Array){
-_34=[_34];
-}
-dojo._xdReqLoc=dojo.xdRequireLocalization;
-dojo.xdRequireLocalization=function(m,b,_35,_36){
-dojo._xdReqLoc(m,b,_35,_36);
-if(_35){
-return;
-}
-for(var i=0;i<_34.length;i++){
-dojo._xdReqLoc(m,b,_34[i],_36);
-}
-};
-}
-};
-dojo._xdBundleMap={};
-dojo.xdRequireLocalization=function(_37,_38,_39,_3a){
-if(dojo._xdInitExtraLocales){
-dojo._xdInitExtraLocales();
-dojo._xdInitExtraLocales=null;
-dojo.xdRequireLocalization.apply(dojo,arguments);
-return;
-}
-var _3b=_3a.split(",");
-var _3c=dojo.i18n.normalizeLocale(_39);
-var _3d="";
-for(var i=0;i<_3b.length;i++){
-if(_3c.indexOf(_3b[i])==0){
-if(_3b[i].length>_3d.length){
-_3d=_3b[i];
-}
-}
-}
-var _3e=_3d.replace("-","_");
-var _3f=dojo.getObject([_37,"nls",_38].join("."));
-if(!_3f||!_3f[_3e]){
-var _40=[_37,(_3e||"root"),_38].join(".");
-var _41=dojo._xdBundleMap[_40];
-if(!_41){
-_41=dojo._xdBundleMap[_40]={};
-}
-_41[_3c.replace("-","_")]=true;
-dojo.require(_37+".nls"+(_3d?"."+_3d:"")+"."+_38);
-}
-};
-dojo._xdRealRequireLocalization=dojo.requireLocalization;
-dojo.requireLocalization=function(_42,_43,_44,_45){
-var _46=dojo.moduleUrl(_42).toString();
-if(dojo._xdIsXDomainPath(_46)){
-return dojo.xdRequireLocalization.apply(dojo,arguments);
-}else{
-return dojo._xdRealRequireLocalization.apply(dojo,arguments);
-}
-};
-dojo._xdUnpackDependency=function(dep){
-var _47=null;
-var _48=null;
-switch(dep[0]){
-case "requireIf":
-case "requireAfterIf":
-if(dep[1]===true){
-_47=[{name:dep[2],content:null}];
-}
-break;
-case "platformRequire":
-var _49=dep[1];
-var _4a=_49["common"]||[];
-_47=(_49[dojo.hostenv.name_])?_4a.concat(_49[dojo.hostenv.name_]||[]):_4a.concat(_49["default"]||[]);
-if(_47){
-for(var i=0;i<_47.length;i++){
-if(_47[i] instanceof Array){
-_47[i]={name:_47[i][0],content:null};
-}else{
-_47[i]={name:_47[i],content:null};
-}
-}
-}
-break;
-case "require":
-_47=[{name:dep[1],content:null}];
-break;
-case "i18n._preloadLocalizations":
-dojo.i18n._preloadLocalizations.apply(dojo.i18n._preloadLocalizations,dep.slice(1));
-break;
-}
-if(dep[0]=="requireAfterIf"||dep[0]=="requireIf"){
-_48=_47;
-_47=null;
-}
-return {requires:_47,requiresAfter:_48};
-};
-dojo._xdWalkReqs=function(){
-var _4b=null;
-var req;
-for(var i=0;i<dojo._xdOrderedReqs.length;i++){
-req=dojo._xdOrderedReqs[i];
-if(dojo._xdDepMap[req]){
-_4b=[req];
-_4b[req]=true;
-dojo._xdEvalReqs(_4b);
-}
-}
-};
-dojo._xdEvalReqs=function(_4c){
-while(_4c.length>0){
-var req=_4c[_4c.length-1];
-var res=dojo._xdDepMap[req];
-var i,_4d,_4e;
-if(res){
-_4d=res.requires;
-if(_4d&&_4d.length>0){
-for(i=0;i<_4d.length;i++){
-_4e=_4d[i].name;
-if(_4e&&!_4c[_4e]){
-_4c.push(_4e);
-_4c[_4e]=true;
-dojo._xdEvalReqs(_4c);
-}
+
+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.
+ dojo._isXDomain = dojo.config.useXDomain || false;
+
+ dojo._xdClearInterval();
+ dojo._xdInFlight = {};
+ dojo._xdOrderedReqs = [];
+ dojo._xdDepMap = {};
+ dojo._xdContents = [];
+ dojo._xdDefList = [];
}
+
+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.
+ if(dojo._xdTimer){
+ clearInterval(dojo._xdTimer);
+ dojo._xdTimer = 0;
+ }
}
-var _4f=dojo._xdContents[res.contentIndex];
-if(!_4f.isDefined){
-var _50=_4f.content;
-_50["resourceName"]=_4f["resourceName"];
-_50["resourcePath"]=_4f["resourcePath"];
-dojo._xdDefList.push(_50);
-_4f.isDefined=true;
+
+
+//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)\s*\(([\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(function(" + dojo._scopePrefixArgs + "){\n");
+
+ //See if there are any dojo.loadInit calls
+ var loadInitCalls = dojo._xdExtractLoadInits(contents);
+ if(loadInitCalls){
+ //Adjust fileContents since extractLoadInits removed something.
+ contents = loadInitCalls[0];
+
+ //Add any loadInit calls to the top of the xd file.
+ for(var i = 1; i < loadInitCalls.length; i++){
+ output.push(loadInitCalls[i] + ";\n");
+ }
+ }
+
+ output.push("return {");
+
+ //Add dependencies
+ if(deps.length > 0){
+ output.push("depends: [");
+ for(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._xdDepMap[req]=null;
-_4d=res.requiresAfter;
-if(_4d&&_4d.length>0){
-for(i=0;i<_4d.length;i++){
-_4e=_4d[i].name;
-if(_4e&&!_4c[_4e]){
-_4c.push(_4e);
-_4c[_4e]=true;
-dojo._xdEvalReqs(_4c);
+
+dojo._xdExtractLoadInits = function(/*String*/fileContents){
+ //Extracts
+ var regexp = /dojo.loadInit\s*\(/g;
+ regexp.lastIndex = 0;
+
+ var parenRe = /[\(\)]/g;
+ parenRe.lastIndex = 0;
+
+ var results = [];
+ var matches;
+ while((matches = regexp.exec(fileContents))){
+ //Find end of the call by finding the matching end paren
+ parenRe.lastIndex = regexp.lastIndex;
+ var matchCount = 1;
+ var parenMatch;
+ while((parenMatch = parenRe.exec(fileContents))){
+ if(parenMatch[0] == ")"){
+ matchCount -= 1;
+ }else{
+ matchCount += 1;
+ }
+ if(matchCount == 0){
+ break;
+ }
+ }
+
+ if(matchCount != 0){
+ throw "unmatched paren around character " + parenRe.lastIndex + " in: " + fileContents;
+ }
+
+ //Put the master matching string in the results.
+ var startIndex = regexp.lastIndex - matches[0].length;
+ results.push(fileContents.substring(startIndex, parenRe.lastIndex));
+
+ //Remove the matching section.
+ var remLength = parenRe.lastIndex - startIndex;
+ fileContents = fileContents.substring(0, startIndex) + fileContents.substring(parenRe.lastIndex, fileContents.length);
+
+ //Move the master regexp past the last matching paren point.
+ regexp.lastIndex = parenRe.lastIndex - remLength;
+
+ regexp.lastIndex = parenRe.lastIndex;
+ }
+
+ if(results.length > 0){
+ results.unshift(fileContents);
+ }
+
+ return (results.length ? results : null);
}
+
+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 = dojo.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 = dojo._xdIsXDomainPath(relpath);
+ dojo._isXDomain |= currentIsXDomain;
+
+ var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : dojo.baseUrl) + relpath;
+
+ try{
+ return ((!module || dojo._isXDomain) ? dojo._loadUri(uri, cb, currentIsXDomain, module) : dojo._loadUriAndCheck(uri, module, cb)); //Boolean
+ }catch(e){
+ console.error(e);
+ return false; //Boolean
+ }
}
+
+dojo._xdCharSet = "utf-8";
+
+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(dojo._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(dojo._isXDomain && module && module != "dojo.i18n"){
+ dojo._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){
+ dojo._xdInFlight[module] = true;
+
+ //Increment inFlightCount
+ //This will stop the modulesLoaded from firing all the way.
+ dojo._inFlightCount++;
+ }
+
+ //Start timer
+ if(!dojo._xdTimer){
+ if(dojo.isAIR){
+ dojo._xdTimer = setInterval(function(){dojo._xdWatchInFlight();}, 100);
+ }else{
+ dojo._xdTimer = setInterval(dojo._scopeName + "._xdWatchInFlight();", 100);
+ }
+ }
+ dojo._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";
+ if(dojo._xdCharSet){
+ element.charset = dojo._xdCharSet;
+ }
+ element.src = xdUri;
+ if(!dojo.headElement){
+ dojo._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(!dojo._headElement){
+ dojo._headElement = document.getElementsByTagName("html")[0];
+ }
+ }
+ dojo._headElement.appendChild(element);
+ }else{
+ var contents = dojo._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(dojo._isXDomain
+ && uri.indexOf("/nls/") == -1
+ && module != "dojo.i18n"){
+ var res = dojo._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 = dojo._scopePrefix + contents + dojo._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.
+ dojo._loadedUrls[uri] = true;
+ dojo._loadedUrls.push(uri);
+ return true; //Boolean
}
-_4c.pop();
+
+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.
+
+ //Evaluate the function with scopeArgs for multiversion support.
+ res = res.apply(dojo.global, dojo._scopeArgs);
+
+ //Work through dependencies.
+ 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 = dojo._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 = dojo._xdContents.push({
+ content: res.defineResource,
+ resourceName: res["resourceName"],
+ resourcePath: res["resourcePath"],
+ isDefined: false
+ }) - 1;
+
+ //Add provide/requires to dependency map.
+ for(i = 0; i < provideList.length; i++){
+ dojo._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(i = 0; i < provideList.length; i++){
+ dojo._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._xdWatchInFlight=function(){
-var _51="";
-var _52=(dojo.config.xdWaitSeconds||15)*1000;
-var _53=(dojo._xdStartTime+_52)<(new Date()).getTime();
-for(var _54 in dojo._xdInFlight){
-if(dojo._xdInFlight[_54]===true){
-if(_53){
-_51+=_54+" ";
-}else{
-return;
-}
-}
-}
-dojo._xdClearInterval();
-if(_53){
-throw "Could not load cross-domain resources: "+_51;
-}
-dojo._xdWalkReqs();
-var _55=dojo._xdDefList.length;
-for(var i=0;i<_55;i++){
-var _56=dojo._xdDefList[i];
-if(dojo.config["debugAtAllCosts"]&&_56["resourceName"]){
-if(!dojo["_xdDebugQueue"]){
-dojo._xdDebugQueue=[];
-}
-dojo._xdDebugQueue.push({resourceName:_56.resourceName,resourcePath:_56.resourcePath});
-}else{
-_56.apply(dojo.global,dojo._scopeArgs);
+
+
+dojo._xdInitExtraLocales = function(){
+ // Simulate the extra locale work that dojo.requireLocalization does.
+
+ var extra = dojo.config.extraLocale;
+ if(extra){
+ if(!extra instanceof Array){
+ extra = [extra];
+ }
+
+ dojo._xdReqLoc = dojo.xdRequireLocalization;
+ dojo.xdRequireLocalization = function(m, b, locale, fLocales){
+ dojo._xdReqLoc(m,b,locale, fLocales);
+ if(locale){return;}
+ for(var i=0; i<extra.length; i++){
+ dojo._xdReqLoc(m,b,extra[i], fLocales);
+ }
+ };
+ }
}
+
+dojo._xdBundleMap = {};
+
+dojo.xdRequireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String*/availableFlatLocales){
+ //summary: Internal xd loader function. The xd version of dojo.requireLocalization.
+
+
+ //Account for allowing multiple extra locales. Do this here inside the function
+ //since dojo._xdInitExtraLocales() depends on djConfig being set up, but that only
+ //happens after hostenv_browser runs. loader_xd has to come before hostenv_browser
+ //though since hostenv_browser can do a dojo.require for the debug module.
+ if(dojo._xdInitExtraLocales){
+ dojo._xdInitExtraLocales();
+ dojo._xdInitExtraLocales = null;
+ dojo.xdRequireLocalization.apply(dojo, arguments);
+ return;
+ }
+
+ var locales = availableFlatLocales.split(",");
+
+ //Find the best-match locale to load.
+ //Assumes dojo.i18n has already been loaded. This is true for xdomain builds,
+ //since it is included in dojo.xd.js.
+ var jsLoc = dojo.i18n.normalizeLocale(locale);
+
+ var bestLocale = "";
+ for(var i = 0; i < locales.length; i++){
+ //Locale must match from start of string.
+ if(jsLoc.indexOf(locales[i]) == 0){
+ if(locales[i].length > bestLocale.length){
+ bestLocale = locales[i];
+ }
+ }
+ }
+
+ var fixedBestLocale = bestLocale.replace('-', '_');
+ //See if the bundle we are going to use is already loaded.
+ var bundleResource = dojo.getObject([moduleName, "nls", bundleName].join("."));
+ if(!bundleResource || !bundleResource[fixedBestLocale]){
+ //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);
+ }
}
-for(i=0;i<dojo._xdContents.length;i++){
-var _57=dojo._xdContents[i];
-if(_57.content&&!_57.isDefined){
-_57.content.apply(dojo.global,dojo._scopeArgs);
+
+// 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 = dojo.moduleUrl(moduleName).toString();
+ if (dojo._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"]||[];
+ 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._xdReset();
-if(dojo["_xdDebugQueue"]&&dojo._xdDebugQueue.length>0){
-dojo._xdDebugFileLoaded();
-}else{
-dojo._xdNotifyLoaded();
+
+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 < dojo._xdOrderedReqs.length; i++){
+ req = dojo._xdOrderedReqs[i];
+ if(dojo._xdDepMap[req]){
+ reqChain = [req];
+ reqChain[req] = true; //Allow for fast lookup of the req in the array
+ dojo._xdEvalReqs(reqChain);
+ }
+ }
}
-};
-dojo._xdNotifyLoaded=function(){
-for(var _58 in dojo._xdInFlight){
-if(typeof dojo._xdInFlight[_58]=="boolean"){
-return;
+
+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 = dojo._xdDepMap[req];
+ var i, reqs, nextReq;
+ if(res){
+ //Trace down any requires for this resource.
+ //START dojo._xdTraceReqs() inlining for small Safari 2.0 call stack
+ reqs = res.requires;
+ if(reqs && reqs.length > 0){
+ for(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;
+ dojo._xdEvalReqs(reqChain);
+ }
+ }
+ }
+ //END dojo._xdTraceReqs() inlining for small Safari 2.0 call stack
+
+ //Evaluate the resource.
+ var contents = dojo._xdContents[res.contentIndex];
+ if(!contents.isDefined){
+ var content = contents.content;
+ content["resourceName"] = contents["resourceName"];
+ content["resourcePath"] = contents["resourcePath"];
+ dojo._xdDefList.push(content);
+ contents.isDefined = true;
+ }
+ dojo._xdDepMap[req] = null;
+
+ //Trace down any requireAfters for this resource.
+ //START dojo._xdTraceReqs() inlining for small Safari 2.0 call stack
+ reqs = res.requiresAfter;
+ if(reqs && reqs.length > 0){
+ for(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;
+ dojo._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._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 = (dojo._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 dojo._xdInFlight){
+ if(dojo._xdInFlight[param] === true){
+ if(expired){
+ noLoads += param + " ";
+ }else{
+ return;
+ }
+ }
+ }
+
+ //All done. Clean up and notify.
+ dojo._xdClearInterval();
+
+ if(expired){
+ throw "Could not load cross-domain resources: " + noLoads;
+ }
+
+ dojo._xdWalkReqs();
+
+ var defLength = dojo._xdDefList.length;
+ for(var i= 0; i < defLength; i++){
+ var content = dojo._xdDefList[i];
+ if(dojo.config["debugAtAllCosts"] && content["resourceName"]){
+ if(!dojo["_xdDebugQueue"]){
+ dojo._xdDebugQueue = [];
+ }
+ dojo._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(i = 0; i < dojo._xdContents.length; i++){
+ var current = dojo._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.
+ dojo._xdReset();
+
+ if(dojo["_xdDebugQueue"] && dojo._xdDebugQueue.length > 0){
+ dojo._xdDebugFileLoaded();
+ }else{
+ dojo._xdNotifyLoaded();
+ }
}
-dojo._inFlightCount=0;
-if(dojo._initFired&&!dojo._loadNotifying){
-dojo._callLoaded();
+
+dojo._xdNotifyLoaded = function(){
+ //Clear inflight count so we will finally do finish work.
+
+ //Just having a legitimate status (true or false) for an inflight item
+ //means that it is still being processed. Do the typeof test
+ //to avoid bad JavaScript that might tinker with Object.prototype.
+ for(var prop in dojo._xdInFlight){
+ if(typeof dojo._xdInFlight[prop] == "boolean"){
+ return;
+ }
+ }
+
+ dojo._inFlightCount = 0;
+
+ //Only trigger call loaded if dj_load_init has run.
+ if(dojo._initFired && !dojo._loadNotifying){
+ dojo._callLoaded();
+ }
}
-};
+
}
diff --git a/lib/dojo/_base/array.js b/lib/dojo/_base/array.js
index 83c21c8d8..26fa1900d 100644
--- a/lib/dojo/_base/array.js
+++ b/lib/dojo/_base/array.js
@@ -5,75 +5,258 @@
*/
-if(!dojo._hasResource["dojo._base.array"]){
-dojo._hasResource["dojo._base.array"]=true;
+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 _1=function(_2,_3,cb){
-return [(typeof _2=="string")?_2.split(""):_2,_3||dojo.global,(typeof cb=="string")?new Function("item","index","array",cb):cb];
-};
-var _4=function(_5,_6,_7,_8){
-var _9=_1(_6,_8,_7);
-_6=_9[0];
-for(var i=0,l=_6.length;i<l;++i){
-var _a=!!_9[2].call(_9[1],_6[i],i,_6);
-if(_5^_a){
-return _a;
-}
-}
-return _5;
-};
-dojo.mixin(dojo,{indexOf:function(_b,_c,_d,_e){
-var _f=1,end=_b.length||0,i=0;
-if(_e){
-i=end-1;
-_f=end=-1;
-}
-if(_d!=undefined){
-i=_d;
-}
-if((_e&&i>end)||i<end){
-for(;i!=end;i+=_f){
-if(_b[i]==_c){
-return i;
-}
-}
-}
-return -1;
-},lastIndexOf:function(_10,_11,_12){
-return dojo.indexOf(_10,_11,_12,true);
-},forEach:function(arr,_13,_14){
-if(!arr||!arr.length){
-return;
-}
-var _15=_1(arr,_14,_13);
-arr=_15[0];
-for(var i=0,l=arr.length;i<l;++i){
-_15[2].call(_15[1],arr[i],i,arr);
-}
-},every:function(arr,_16,_17){
-return _4(true,arr,_16,_17);
-},some:function(arr,_18,_19){
-return _4(false,arr,_18,_19);
-},map:function(arr,_1a,_1b){
-var _1c=_1(arr,_1b,_1a);
-arr=_1c[0];
-var _1d=(arguments[3]?(new arguments[3]()):[]);
-for(var i=0,l=arr.length;i<l;++i){
-_1d.push(_1c[2].call(_1c[1],arr[i],i,arr));
-}
-return _1d;
-},filter:function(arr,_1e,_1f){
-var _20=_1(arr,_1f,_1e);
-arr=_20[0];
-var _21=[];
-for(var i=0,l=arr.length;i<l;++i){
-if(_20[2].call(_20[1],arr[i],i,arr)){
-_21.push(arr[i]);
-}
-}
-return _21;
-}});
+ var _getParts = function(arr, obj, cb){
+ return [
+ (typeof arr == "string") ? arr.split("") : arr,
+ obj || dojo.global,
+ // FIXME: cache the anonymous functions we create here?
+ (typeof cb == "string") ? new Function("item", "index", "array", cb) : cb
+ ];
+ };
+
+ var everyOrSome = function(/*Boolean*/every, /*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+ for(var i=0,l=arr.length; i<l; ++i){
+ var result = !!_p[2].call(_p[1], arr[i], i, arr);
+ if(every ^ result){
+ return result; // Boolean
+ }
+ }
+ return every; // Boolean
+ };
+
+ 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:
+ // This method corresponds to the JavaScript 1.6 Array.indexOf method, with one difference: when
+ // run over sparse arrays, the Dojo function invokes the callback for every index whereas JavaScript
+ // 1.6's indexOf skips the holes in the sparse array.
+ // For details on this method, see:
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/indexOf
+
+ var step = 1, end = array.length || 0, i = 0;
+ if(findLast){
+ i = end - 1;
+ step = end = -1;
+ }
+ if(fromIndex != undefined){ i = fromIndex; }
+ if((findLast && i > end) || i < end){
+ for(; i != end; i += step){
+ if(array[i] == value){ return i; }
+ }
+ }
+ return -1; // Number
+ },
+
+ lastIndexOf: function(/*Array*/array, /*Object*/value, /*Integer?*/fromIndex){
+ // summary:
+ // locates the last index of the provided value in the passed
+ // array. If the value is not found, -1 is returned.
+ // description:
+ // This method corresponds to the JavaScript 1.6 Array.lastIndexOf method, with one difference: when
+ // run over sparse arrays, the Dojo function invokes the callback for every index whereas JavaScript
+ // 1.6's lastIndexOf skips the holes in the sparse array.
+ // For details on this method, see:
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/lastIndexOf
+ return dojo.indexOf(array, value, fromIndex, true); // Number
+ },
+
+ forEach: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ // summary:
+ // for every item in arr, callback is invoked. Return values are ignored.
+ // If you want to break out of the loop, consider using dojo.every() or dojo.some().
+ // forEach does not allow breaking out of the loop over the items in arr.
+ // arr:
+ // the array to iterate over. 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, with one difference: when
+ // run over sparse arrays, this implemenation passes the "holes" in the sparse array to
+ // the callback function with a value of undefined. JavaScript 1.6's forEach skips the holes in the sparse array.
+ // For more details, see:
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/forEach
+ // example:
+ // | // log out all members of the array:
+ // | dojo.forEach(
+ // | [ "thinger", "blah", "howdy", 10 ],
+ // | function(item){
+ // | console.log(item);
+ // | }
+ // | );
+ // example:
+ // | // log out the members and their indexes
+ // | dojo.forEach(
+ // | [ "thinger", "blah", "howdy", 10 ],
+ // | function(item, idx, arr){
+ // | console.log(item, "at index:", idx);
+ // | }
+ // | );
+ // example:
+ // | // use a scoped object member as the callback
+ // |
+ // | var obj = {
+ // | prefix: "logged via obj.callback:",
+ // | callback: function(item){
+ // | console.log(this.prefix, item);
+ // | }
+ // | };
+ // |
+ // | // specifying the scope function executes the callback in that scope
+ // | dojo.forEach(
+ // | [ "thinger", "blah", "howdy", 10 ],
+ // | obj.callback,
+ // | obj
+ // | );
+ // |
+ // | // alternately, we can accomplish the same thing with dojo.hitch()
+ // | dojo.forEach(
+ // | [ "thinger", "blah", "howdy", 10 ],
+ // | dojo.hitch(obj, "callback")
+ // | );
+
+ // 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=arr.length; i<l; ++i){
+ _p[2].call(_p[1], arr[i], i, arr);
+ }
+ },
+
+ every: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ // summary:
+ // Determines whether or not every item in arr satisfies the
+ // condition implemented by callback.
+ // arr:
+ // the array to iterate on. If a string, operates on individual characters.
+ // callback:
+ // a function is invoked with three arguments: item, index,
+ // and array and returns true if the condition is met.
+ // thisObject:
+ // may be used to scope the call to callback
+ // description:
+ // This function corresponds to the JavaScript 1.6 Array.every() method, with one difference: when
+ // run over sparse arrays, this implemenation passes the "holes" in the sparse array to
+ // the callback function with a value of undefined. JavaScript 1.6's every skips the holes in the sparse array.
+ // For more details, see:
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/every
+ // example:
+ // | // returns false
+ // | dojo.every([1, 2, 3, 4], function(item){ return item>1; });
+ // example:
+ // | // returns true
+ // | dojo.every([1, 2, 3, 4], function(item){ return item>0; });
+ return 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 over. 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, with one difference: when
+ // run over sparse arrays, this implemenation passes the "holes" in the sparse array to
+ // the callback function with a value of undefined. JavaScript 1.6's some skips the holes in the sparse array.
+ // For more details, see:
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/some
+ // example:
+ // | // is true
+ // | dojo.some([1, 2, 3, 4], function(item){ return item>1; });
+ // example:
+ // | // is false
+ // | dojo.some([1, 2, 3, 4], function(item){ return item<1; });
+ return 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,
+ // 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, with one difference: when
+ // run over sparse arrays, this implemenation passes the "holes" in the sparse array to
+ // the callback function with a value of undefined. JavaScript 1.6's map skips the holes in the sparse array.
+ // For more details, see:
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
+ // example:
+ // | // returns [2, 3, 4, 5]
+ // | dojo.map([1, 2, 3, 4], function(item){ return item+1 });
+
+ var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+ var outArr = (arguments[3] ? (new arguments[3]()) : []);
+ for(var i=0,l=arr.length; i<l; ++i){
+ outArr.push(_p[2].call(_p[1], arr[i], i, arr));
+ }
+ return outArr; // Array
+ },
+
+ filter: function(/*Array*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+ // summary:
+ // Returns a new Array with those items from arr that match the
+ // condition implemented by callback.
+ // arr:
+ // the array to iterate over.
+ // callback:
+ // a function that is invoked with three arguments (item,
+ // index, array). The return of this function is expected to
+ // be a boolean which determines whether the passed-in item
+ // will be included in the returned array.
+ // thisObject:
+ // may be used to scope the call to callback
+ // description:
+ // This function corresponds to the JavaScript 1.6 Array.filter() method, with one difference: when
+ // run over sparse arrays, this implemenation passes the "holes" in the sparse array to
+ // the callback function with a value of undefined. JavaScript 1.6's filter skips the holes in the sparse array.
+ // For more details, see:
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
+ // example:
+ // | // returns [2, 3, 4]
+ // | dojo.filter([1, 2, 3, 4], function(item){ return item>1; });
+
+ var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+ var outArr = [];
+ for(var i=0,l=arr.length; i<l; ++i){
+ if(_p[2].call(_p[1], arr[i], i, arr)){
+ outArr.push(arr[i]);
+ }
+ }
+ return outArr; // Array
+ }
+ });
})();
+/*
+*/
+
}
diff --git a/lib/dojo/_base/browser.js b/lib/dojo/_base/browser.js
index 67c1eef37..496fe46b3 100644
--- a/lib/dojo/_base/browser.js
+++ b/lib/dojo/_base/browser.js
@@ -5,9 +5,10 @@
*/
-if(!dojo._hasResource["dojo._base.browser"]){
-dojo._hasResource["dojo._base.browser"]=true;
+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.connect");
dojo.require("dojo._base.event");
@@ -16,7 +17,13 @@ dojo.require("dojo._base.NodeList");
dojo.require("dojo._base.query");
dojo.require("dojo._base.xhr");
dojo.require("dojo._base.fx");
-dojo.forEach(dojo.config.require,function(i){
-dojo["require"](i);
+
+//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.
+dojo.forEach(dojo.config.require, function(i){
+ dojo["require"](i);
});
+
}
diff --git a/lib/dojo/_base/connect.js b/lib/dojo/_base/connect.js
index 3905d92e7..f37af65b2 100644
--- a/lib/dojo/_base/connect.js
+++ b/lib/dojo/_base/connect.js
@@ -5,81 +5,306 @@
*/
-if(!dojo._hasResource["dojo._base.connect"]){
-dojo._hasResource["dojo._base.connect"]=true;
+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");
-dojo._listener={getDispatcher:function(){
-return function(){
-var ap=Array.prototype,c=arguments.callee,ls=c._listeners,t=c.target;
-var r=t&&t.apply(this,arguments);
-var i,_1;
-_1=[].concat(ls);
-for(i in _1){
-if(!(i in ap)){
-_1[i].apply(this,arguments);
-}
-}
-return r;
+
+// 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);
+ // make local copy of listener array so it is immutable during processing
+ var i, lls;
+ lls = [].concat(ls);
+
+ // invoke listeners after target function
+ for(i in lls){
+ if(!(i in ap)){
+ lls[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];
+ }
+ }
};
-},add:function(_2,_3,_4){
-_2=_2||dojo.global;
-var f=_2[_3];
-if(!f||!f._listeners){
-var d=dojo._listener.getDispatcher();
-d.target=f;
-d._listeners=[];
-f=_2[_3]=d;
+
+// 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:
+ // `dojo.connect` is the core event handling and delegation method in
+ // Dojo. It allows one function to "listen in" on the execution of
+ // any other, triggering the second whenever the first is called. Many
+ // listeners may be attached to a function, and source functions may
+ // be either regular function calls or DOM events.
+ //
+ // description:
+ // Connects listeners to actions, so that after event fires, a
+ // listener is called with the same arguments passed to the original
+ // function.
+ //
+ // Since `dojo.connect` allows the source of events to be either a
+ // "regular" JavaScript function or a DOM event, it provides a uniform
+ // interface for listening to all the types of events that an
+ // application is likely to deal with though a single, unified
+ // interface. DOM programmers may want to think of it as
+ // "addEventListener for everything and anything".
+ //
+ // When setting up a connection, the `event` parameter must be a
+ // string that is the name of the method/event to be listened for. If
+ // `obj` is null, `dojo.global` is assumed, meaning that connections
+ // to global methods are supported but also that you may inadvertently
+ // connect to a global by passing an incorrect object name or invalid
+ // reference.
+ //
+ // `dojo.connect` generally is forgiving. If you pass the name of a
+ // function or method that does not yet exist on `obj`, connect will
+ // not fail, but will instead set up a stub method. Similarly, null
+ // arguments may simply be omitted such that fewer than 4 arguments
+ // may be required to set up a connection See the examples for details.
+ //
+ // 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 omitted
+ args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]);
+ // if the arg-after-next is a String or Function, context was NOT omitted
+ var a1 = a[i+1];
+ args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]);
+ // absorb any additional arguments
+ for(var l=a.length; i<l; i++){ args.push(a[i]); }
+ // do the actual work
+ return dojo._connect.apply(this, args); /*Handle*/
}
-return f._listeners.push(_4);
-},remove:function(_5,_6,_7){
-var f=(_5||dojo.global)[_6];
-if(f&&f._listeners&&_7--){
-delete f._listeners[_7];
+
+// used by non-browser hostenvs. always overriden by event.js
+dojo._connect = function(obj, event, context, method){
+ var l=dojo._listener, h=l.add(obj, event, dojo.hitch(context, method));
+ return [obj, event, h, l]; // Handle
}
-}};
-dojo.connect=function(_8,_9,_a,_b,_c){
-var a=arguments,_d=[],i=0;
-_d.push(dojo.isString(a[0])?null:a[i++],a[i++]);
-var a1=a[i+1];
-_d.push(dojo.isString(a1)||dojo.isFunction(a1)?a[i++]:null,a[i++]);
-for(var l=a.length;i<l;i++){
-_d.push(a[i]);
+
+dojo.disconnect = function(/*Handle*/ handle){
+ // summary:
+ // Remove a link created by dojo.connect.
+ // description:
+ // Removes the connection between event and the method referenced by handle.
+ // handle:
+ // the return value of the dojo.connect call that created the connection.
+ if(handle && handle[0] !== undefined){
+ dojo._disconnect.apply(this, handle);
+ // let's not keep this reference
+ delete handle[0];
+ }
}
-return dojo._connect.apply(this,_d);
-};
-dojo._connect=function(_e,_f,_10,_11){
-var l=dojo._listener,h=l.add(_e,_f,dojo.hitch(_10,_11));
-return [_e,_f,h,l];
-};
-dojo.disconnect=function(_12){
-if(_12&&_12[0]!==undefined){
-dojo._disconnect.apply(this,_12);
-delete _12[0];
+
+dojo._disconnect = function(obj, event, handle, listener){
+ listener.remove(obj, event, handle);
}
-};
-dojo._disconnect=function(obj,_13,_14,_15){
-_15.remove(obj,_13,_14);
-};
-dojo._topics={};
-dojo.subscribe=function(_16,_17,_18){
-return [_16,dojo._listener.add(dojo._topics,_16,dojo.hitch(_17,_18))];
-};
-dojo.unsubscribe=function(_19){
-if(_19){
-dojo._listener.remove(dojo._topics,_19[0],_19[1]);
+
+// topic publish/subscribe
+
+dojo._topics = {};
+
+dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method){
+ // summary:
+ // Attach a listener to a named topic. The listener function is invoked whenever the
+ // named topic is published (see: dojo.publish).
+ // Returns a handle which is needed to unsubscribe this listener.
+ // context:
+ // Scope in which method will be invoked, or null for default scope.
+ // method:
+ // The name of a function in context, or a function reference. This is the function that
+ // is invoked when topic is published.
+ // example:
+ // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); });
+ // | dojo.publish("alerts", [ "read this", "hello world" ]);
+
+ // support for 2 argument invocation (omitting context) depends on hitch
+ return [topic, dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method))]; /*Handle*/
}
-};
-dojo.publish=function(_1a,_1b){
-var f=dojo._topics[_1a];
-if(f){
-f.apply(this,_1b||[]);
+
+dojo.unsubscribe = function(/*Handle*/ handle){
+ // summary:
+ // Remove a topic listener.
+ // handle:
+ // The handle returned from a call to subscribe.
+ // example:
+ // | var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
+ // | ...
+ // | dojo.unsubscribe(alerter);
+ if(handle){
+ dojo._listener.remove(dojo._topics, handle[0], handle[1]);
+ }
}
+
+dojo.publish = function(/*String*/ topic, /*Array*/ args){
+ // summary:
+ // Invoke all listener method subscribed to topic.
+ // topic:
+ // The name of the topic to publish.
+ // args:
+ // An array of arguments. The arguments will be applied
+ // to each topic subscriber (as first class parameters, via apply).
+ // example:
+ // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
+ // | dojo.publish("alerts", [ "read this", "hello world" ]);
+
+ // Note that args is an array, which is more efficient vs variable length
+ // argument list. Ideally, var args would be implemented via Array
+ // throughout the APIs.
+ var f = dojo._topics[topic];
+ if(f){
+ f.apply(this, args||[]);
+ }
+}
+
+dojo.connectPublisher = function( /*String*/ topic,
+ /*Object|null*/ obj,
+ /*String*/ event){
+ // summary:
+ // Ensure that every time obj.event() is called, a message is published
+ // on the topic. Returns a handle which can be passed to
+ // dojo.disconnect() to disable subsequent automatic publication on
+ // the topic.
+ // topic:
+ // The name of the topic to publish.
+ // obj:
+ // The source object for the event function. Defaults to dojo.global
+ // if null.
+ // event:
+ // The name of the event function in obj.
+ // I.e. identifies a property obj[event].
+ // example:
+ // | dojo.connectPublisher("/ajax/start", dojo, "xhrGet");
+ var pf = function(){ dojo.publish(topic, arguments); }
+ return event ? dojo.connect(obj, event, pf) : dojo.connect(obj, pf); //Handle
};
-dojo.connectPublisher=function(_1c,obj,_1d){
-var pf=function(){
-dojo.publish(_1c,arguments);
-};
-return _1d?dojo.connect(obj,_1d,pf):dojo.connect(obj,pf);
-};
+
}
diff --git a/lib/dojo/_base/declare.js b/lib/dojo/_base/declare.js
index f8ce201ec..8e46b12c0 100644
--- a/lib/dojo/_base/declare.js
+++ b/lib/dojo/_base/declare.js
@@ -5,419 +5,1044 @@
*/
-if(!dojo._hasResource["dojo._base.declare"]){
-dojo._hasResource["dojo._base.declare"]=true;
+if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.declare"] = true;
dojo.provide("dojo._base.declare");
+
dojo.require("dojo._base.lang");
dojo.require("dojo._base.array");
+
(function(){
-var d=dojo,_1=d._mixin,op=Object.prototype,_2=op.toString,_3=new Function,_4=0,_5="constructor";
-function _6(_7){
-throw new Error("declare: "+_7);
-};
-function _8(_9){
-var _a=[],_b=[{cls:0,refs:[]}],_c={},_d=1,l=_9.length,i=0,j,_e,_f,top,_10,rec,_11,_12;
-for(;i<l;++i){
-_f=_9[i];
-if(!_f){
-_6("mixin #"+i+" is unknown. Did you use dojo.require to pull it in?");
-}else{
-if(_2.call(_f)!="[object Function]"){
-_6("mixin #"+i+" is not a callable constructor.");
-}
-}
-_e=_f._meta?_f._meta.bases:[_f];
-top=0;
-for(j=_e.length-1;j>=0;--j){
-_10=_e[j].prototype;
-if(!_10.hasOwnProperty("declaredClass")){
-_10.declaredClass="uniqName_"+(_4++);
-}
-_11=_10.declaredClass;
-if(!_c.hasOwnProperty(_11)){
-_c[_11]={count:0,refs:[],cls:_e[j]};
-++_d;
-}
-rec=_c[_11];
-if(top&&top!==rec){
-rec.refs.push(top);
-++top.count;
-}
-top=rec;
-}
-++top.count;
-_b[0].refs.push(top);
-}
-while(_b.length){
-top=_b.pop();
-_a.push(top.cls);
---_d;
-while(_12=top.refs,_12.length==1){
-top=_12[0];
-if(!top||--top.count){
-top=0;
-break;
-}
-_a.push(top.cls);
---_d;
-}
-if(top){
-for(i=0,l=_12.length;i<l;++i){
-top=_12[i];
-if(!--top.count){
-_b.push(top);
-}
-}
-}
-}
-if(_d){
-_6("can't build consistent linearization");
-}
-_f=_9[0];
-_a[0]=_f?_f._meta&&_f===_a[_a.length-_f._meta.bases.length]?_f._meta.bases.length:1:0;
-return _a;
-};
-function _13(_14,a,f){
-var _15,_16,_17,_18,_19,_1a,_1b,opf,pos,_1c=this._inherited=this._inherited||{};
-if(typeof _14=="string"){
-_15=_14;
-_14=a;
-a=f;
-}
-f=0;
-_18=_14.callee;
-_15=_15||_18.nom;
-if(!_15){
-_6("can't deduce a name to call inherited()");
-}
-_19=this.constructor._meta;
-_17=_19.bases;
-pos=_1c.p;
-if(_15!=_5){
-if(_1c.c!==_18){
-pos=0;
-_1a=_17[0];
-_19=_1a._meta;
-if(_19.hidden[_15]!==_18){
-_16=_19.chains;
-if(_16&&typeof _16[_15]=="string"){
-_6("calling chained method with inherited: "+_15);
-}
-do{
-_19=_1a._meta;
-_1b=_1a.prototype;
-if(_19&&(_1b[_15]===_18&&_1b.hasOwnProperty(_15)||_19.hidden[_15]===_18)){
-break;
-}
-}while(_1a=_17[++pos]);
-pos=_1a?pos:-1;
-}
-}
-_1a=_17[++pos];
-if(_1a){
-_1b=_1a.prototype;
-if(_1a._meta&&_1b.hasOwnProperty(_15)){
-f=_1b[_15];
-}else{
-opf=op[_15];
-do{
-_1b=_1a.prototype;
-f=_1b[_15];
-if(f&&(_1a._meta?_1b.hasOwnProperty(_15):f!==opf)){
-break;
-}
-}while(_1a=_17[++pos]);
-}
-}
-f=_1a&&f||op[_15];
-}else{
-if(_1c.c!==_18){
-pos=0;
-_19=_17[0]._meta;
-if(_19&&_19.ctor!==_18){
-_16=_19.chains;
-if(!_16||_16.constructor!=="manual"){
-_6("calling chained constructor with inherited");
-}
-while(_1a=_17[++pos]){
-_19=_1a._meta;
-if(_19&&_19.ctor===_18){
-break;
-}
-}
-pos=_1a?pos:-1;
-}
-}
-while(_1a=_17[++pos]){
-_19=_1a._meta;
-f=_19?_19.ctor:_1a;
-if(f){
-break;
-}
-}
-f=_1a&&f;
-}
-_1c.c=f;
-_1c.p=pos;
-if(f){
-return a===true?f:f.apply(this,a||_14);
-}
-};
-function _1d(_1e,_1f){
-if(typeof _1e=="string"){
-return this.inherited(_1e,_1f,true);
-}
-return this.inherited(_1e,true);
-};
-function _20(cls){
-var _21=this.constructor._meta.bases;
-for(var i=0,l=_21.length;i<l;++i){
-if(_21[i]===cls){
-return true;
-}
-}
-return this instanceof cls;
-};
-function _22(_23,_24){
-var _25,i=0,l=d._extraNames.length;
-for(_25 in _24){
-if(_25!=_5&&_24.hasOwnProperty(_25)){
-_23[_25]=_24[_25];
-}
-}
-for(;i<l;++i){
-_25=d._extraNames[i];
-if(_25!=_5&&_24.hasOwnProperty(_25)){
-_23[_25]=_24[_25];
-}
-}
-};
-function _26(_27,_28){
-var _29,t,i=0,l=d._extraNames.length;
-for(_29 in _28){
-t=_28[_29];
-if((t!==op[_29]||!(_29 in op))&&_29!=_5){
-if(_2.call(t)=="[object Function]"){
-t.nom=_29;
-}
-_27[_29]=t;
-}
-}
-for(;i<l;++i){
-_29=d._extraNames[i];
-t=_28[_29];
-if((t!==op[_29]||!(_29 in op))&&_29!=_5){
-if(_2.call(t)=="[object Function]"){
-t.nom=_29;
-}
-_27[_29]=t;
-}
-}
-return _27;
-};
-function _2a(_2b){
-_26(this.prototype,_2b);
-return this;
-};
-function _2c(_2d,_2e){
-return function(){
-var a=arguments,_2f=a,a0=a[0],f,i,m,l=_2d.length,_30;
-if(!(this instanceof a.callee)){
-return _31(a);
-}
-if(_2e&&(a0&&a0.preamble||this.preamble)){
-_30=new Array(_2d.length);
-_30[0]=a;
-for(i=0;;){
-a0=a[0];
-if(a0){
-f=a0.preamble;
-if(f){
-a=f.apply(this,a)||a;
-}
-}
-f=_2d[i].prototype;
-f=f.hasOwnProperty("preamble")&&f.preamble;
-if(f){
-a=f.apply(this,a)||a;
-}
-if(++i==l){
-break;
-}
-_30[i]=a;
-}
-}
-for(i=l-1;i>=0;--i){
-f=_2d[i];
-m=f._meta;
-f=m?m.ctor:f;
-if(f){
-f.apply(this,_30?_30[i]:a);
-}
-}
-f=this.postscript;
-if(f){
-f.apply(this,_2f);
-}
-};
-};
-function _32(_33,_34){
-return function(){
-var a=arguments,t=a,a0=a[0],f;
-if(!(this instanceof a.callee)){
-return _31(a);
-}
-if(_34){
-if(a0){
-f=a0.preamble;
-if(f){
-t=f.apply(this,t)||t;
-}
-}
-f=this.preamble;
-if(f){
-f.apply(this,t);
-}
-}
-if(_33){
-_33.apply(this,a);
-}
-f=this.postscript;
-if(f){
-f.apply(this,a);
-}
-};
-};
-function _35(_36){
-return function(){
-var a=arguments,i=0,f,m;
-if(!(this instanceof a.callee)){
-return _31(a);
-}
-for(;f=_36[i];++i){
-m=f._meta;
-f=m?m.ctor:f;
-if(f){
-f.apply(this,a);
-break;
-}
-}
-f=this.postscript;
-if(f){
-f.apply(this,a);
-}
-};
-};
-function _37(_38,_39,_3a){
-return function(){
-var b,m,f,i=0,_3b=1;
-if(_3a){
-i=_39.length-1;
-_3b=-1;
-}
-for(;b=_39[i];i+=_3b){
-m=b._meta;
-f=(m?m.hidden:b.prototype)[_38];
-if(f){
-f.apply(this,arguments);
-}
-}
-};
-};
-function _3c(_3d){
-_3.prototype=_3d.prototype;
-var t=new _3;
-_3.prototype=null;
-return t;
-};
-function _31(_3e){
-var _3f=_3e.callee,t=_3c(_3f);
-_3f.apply(t,_3e);
-return t;
-};
-d.declare=function(_40,_41,_42){
-if(typeof _40!="string"){
-_42=_41;
-_41=_40;
-_40="";
-}
-_42=_42||{};
-var _43,i,t,_44,_45,_46,_47,_48=1,_49=_41;
-if(_2.call(_41)=="[object Array]"){
-_46=_8(_41);
-t=_46[0];
-_48=_46.length-t;
-_41=_46[_48];
-}else{
-_46=[0];
-if(_41){
-if(_2.call(_41)=="[object Function]"){
-t=_41._meta;
-_46=_46.concat(t?t.bases:_41);
-}else{
-_6("base class is not a callable constructor.");
-}
-}else{
-if(_41!==null){
-_6("unknown base class. Did you use dojo.require to pull it in?");
-}
-}
-}
-if(_41){
-for(i=_48-1;;--i){
-_43=_3c(_41);
-if(!i){
-break;
-}
-t=_46[i];
-(t._meta?_22:_1)(_43,t.prototype);
-_44=new Function;
-_44.superclass=_41;
-_44.prototype=_43;
-_41=_43.constructor=_44;
-}
-}else{
-_43={};
-}
-_26(_43,_42);
-t=_42.constructor;
-if(t!==op.constructor){
-t.nom=_5;
-_43.constructor=t;
-}
-for(i=_48-1;i;--i){
-t=_46[i]._meta;
-if(t&&t.chains){
-_47=_1(_47||{},t.chains);
-}
-}
-if(_43["-chains-"]){
-_47=_1(_47||{},_43["-chains-"]);
-}
-t=!_47||!_47.hasOwnProperty(_5);
-_46[0]=_44=(_47&&_47.constructor==="manual")?_35(_46):(_46.length==1?_32(_42.constructor,t):_2c(_46,t));
-_44._meta={bases:_46,hidden:_42,chains:_47,parents:_49,ctor:_42.constructor};
-_44.superclass=_41&&_41.prototype;
-_44.extend=_2a;
-_44.prototype=_43;
-_43.constructor=_44;
-_43.getInherited=_1d;
-_43.inherited=_13;
-_43.isInstanceOf=_20;
-if(_40){
-_43.declaredClass=_40;
-d.setObject(_40,_44);
-}
-if(_47){
-for(_45 in _47){
-if(_43[_45]&&typeof _47[_45]=="string"&&_45!=_5){
-t=_43[_45]=_37(_45,_46,_47[_45]==="after");
-t.nom=_45;
-}
-}
-}
-return _44;
-};
-d.safeMixin=_26;
+ var d = dojo, mix = d._mixin, op = Object.prototype, opts = op.toString,
+ xtor = new Function, counter = 0, cname = "constructor";
+
+ function err(msg){ throw new Error("declare: " + msg); }
+
+ // C3 Method Resolution Order (see http://www.python.org/download/releases/2.3/mro/)
+ function c3mro(bases){
+ var result = [], roots = [{cls: 0, refs: []}], nameMap = {}, clsCount = 1,
+ l = bases.length, i = 0, j, lin, base, top, proto, rec, name, refs;
+
+ // build a list of bases naming them if needed
+ for(; i < l; ++i){
+ base = bases[i];
+ if(!base){
+ err("mixin #" + i + " is unknown. Did you use dojo.require to pull it in?");
+ }else if(opts.call(base) != "[object Function]"){
+ err("mixin #" + i + " is not a callable constructor.");
+ }
+ lin = base._meta ? base._meta.bases : [base];
+ top = 0;
+ // add bases to the name map
+ for(j = lin.length - 1; j >= 0; --j){
+ proto = lin[j].prototype;
+ if(!proto.hasOwnProperty("declaredClass")){
+ proto.declaredClass = "uniqName_" + (counter++);
+ }
+ name = proto.declaredClass;
+ if(!nameMap.hasOwnProperty(name)){
+ nameMap[name] = {count: 0, refs: [], cls: lin[j]};
+ ++clsCount;
+ }
+ rec = nameMap[name];
+ if(top && top !== rec){
+ rec.refs.push(top);
+ ++top.count;
+ }
+ top = rec;
+ }
+ ++top.count;
+ roots[0].refs.push(top);
+ }
+
+ // remove classes without external references recursively
+ while(roots.length){
+ top = roots.pop();
+ result.push(top.cls);
+ --clsCount;
+ // optimization: follow a single-linked chain
+ while(refs = top.refs, refs.length == 1){
+ top = refs[0];
+ if(!top || --top.count){
+ // branch or end of chain => do not end to roots
+ top = 0;
+ break;
+ }
+ result.push(top.cls);
+ --clsCount;
+ }
+ if(top){
+ // branch
+ for(i = 0, l = refs.length; i < l; ++i){
+ top = refs[i];
+ if(!--top.count){
+ roots.push(top);
+ }
+ }
+ }
+ }
+ if(clsCount){
+ err("can't build consistent linearization");
+ }
+
+ // calculate the superclass offset
+ base = bases[0];
+ result[0] = base ?
+ base._meta && base === result[result.length - base._meta.bases.length] ?
+ base._meta.bases.length : 1 : 0;
+
+ return result;
+ }
+
+ function inherited(args, a, f){
+ var name, chains, bases, caller, meta, base, proto, opf, pos,
+ cache = this._inherited = this._inherited || {};
+
+ // crack arguments
+ if(typeof args == "string"){
+ name = args;
+ args = a;
+ a = f;
+ }
+ f = 0;
+
+ caller = args.callee;
+ name = name || caller.nom;
+ if(!name){
+ err("can't deduce a name to call inherited()");
+ }
+
+ meta = this.constructor._meta;
+ bases = meta.bases;
+
+ pos = cache.p;
+ if(name != cname){
+ // method
+ if(cache.c !== caller){
+ // cache bust
+ pos = 0;
+ base = bases[0];
+ meta = base._meta;
+ if(meta.hidden[name] !== caller){
+ // error detection
+ chains = meta.chains;
+ if(chains && typeof chains[name] == "string"){
+ err("calling chained method with inherited: " + name);
+ }
+ // find caller
+ do{
+ meta = base._meta;
+ proto = base.prototype;
+ if(meta && (proto[name] === caller && proto.hasOwnProperty(name) || meta.hidden[name] === caller)){
+ break;
+ }
+ }while(base = bases[++pos]); // intentional assignment
+ pos = base ? pos : -1;
+ }
+ }
+ // find next
+ base = bases[++pos];
+ if(base){
+ proto = base.prototype;
+ if(base._meta && proto.hasOwnProperty(name)){
+ f = proto[name];
+ }else{
+ opf = op[name];
+ do{
+ proto = base.prototype;
+ f = proto[name];
+ if(f && (base._meta ? proto.hasOwnProperty(name) : f !== opf)){
+ break;
+ }
+ }while(base = bases[++pos]); // intentional assignment
+ }
+ }
+ f = base && f || op[name];
+ }else{
+ // constructor
+ if(cache.c !== caller){
+ // cache bust
+ pos = 0;
+ meta = bases[0]._meta;
+ if(meta && meta.ctor !== caller){
+ // error detection
+ chains = meta.chains;
+ if(!chains || chains.constructor !== "manual"){
+ err("calling chained constructor with inherited");
+ }
+ // find caller
+ while(base = bases[++pos]){ // intentional assignment
+ meta = base._meta;
+ if(meta && meta.ctor === caller){
+ break;
+ }
+ }
+ pos = base ? pos : -1;
+ }
+ }
+ // find next
+ while(base = bases[++pos]){ // intentional assignment
+ meta = base._meta;
+ f = meta ? meta.ctor : base;
+ if(f){
+ break;
+ }
+ }
+ f = base && f;
+ }
+
+ // cache the found super method
+ cache.c = f;
+ cache.p = pos;
+
+ // now we have the result
+ if(f){
+ return a === true ? f : f.apply(this, a || args);
+ }
+ // intentionally if a super method was not found
+ }
+
+ function getInherited(name, args){
+ if(typeof name == "string"){
+ return this.inherited(name, args, true);
+ }
+ return this.inherited(name, true);
+ }
+
+ // emulation of "instanceof"
+ function isInstanceOf(cls){
+ var bases = this.constructor._meta.bases;
+ for(var i = 0, l = bases.length; i < l; ++i){
+ if(bases[i] === cls){
+ return true;
+ }
+ }
+ return this instanceof cls;
+ }
+
+ function mixOwn(target, source){
+ var name, i = 0, l = d._extraNames.length;
+ // add props adding metadata for incoming functions skipping a constructor
+ for(name in source){
+ if(name != cname && source.hasOwnProperty(name)){
+ target[name] = source[name];
+ }
+ }
+ // process unenumerable methods on IE
+ for(; i < l; ++i){
+ name = d._extraNames[i];
+ if(name != cname && source.hasOwnProperty(name)){
+ target[name] = source[name];
+ }
+ }
+ }
+
+ // implementation of safe mixin function
+ function safeMixin(target, source){
+ var name, t, i = 0, l = d._extraNames.length;
+ // add props adding metadata for incoming functions skipping a constructor
+ for(name in source){
+ t = source[name];
+ if((t !== op[name] || !(name in op)) && name != cname){
+ if(opts.call(t) == "[object Function]"){
+ // non-trivial function method => attach its name
+ t.nom = name;
+ }
+ target[name] = t;
+ }
+ }
+ // process unenumerable methods on IE
+ for(; i < l; ++i){
+ name = d._extraNames[i];
+ t = source[name];
+ if((t !== op[name] || !(name in op)) && name != cname){
+ if(opts.call(t) == "[object Function]"){
+ // non-trivial function method => attach its name
+ t.nom = name;
+ }
+ target[name] = t;
+ }
+ }
+ return target;
+ }
+
+ function extend(source){
+ safeMixin(this.prototype, source);
+ return this;
+ }
+
+ // chained constructor compatible with the legacy dojo.declare()
+ function chainedConstructor(bases, ctorSpecial){
+ return function(){
+ var a = arguments, args = a, a0 = a[0], f, i, m,
+ l = bases.length, preArgs;
+
+ if(!(this instanceof a.callee)){
+ // not called via new, so force it
+ return applyNew(a);
+ }
+
+ //this._inherited = {};
+ // perform the shaman's rituals of the original dojo.declare()
+ // 1) call two types of the preamble
+ if(ctorSpecial && (a0 && a0.preamble || this.preamble)){
+ // full blown ritual
+ preArgs = new Array(bases.length);
+ // prepare parameters
+ preArgs[0] = a;
+ for(i = 0;;){
+ // process the preamble of the 1st argument
+ a0 = a[0];
+ if(a0){
+ f = a0.preamble;
+ if(f){
+ a = f.apply(this, a) || a;
+ }
+ }
+ // process the preamble of this class
+ f = bases[i].prototype;
+ f = f.hasOwnProperty("preamble") && f.preamble;
+ if(f){
+ a = f.apply(this, a) || a;
+ }
+ // one peculiarity of the preamble:
+ // it is called if it is not needed,
+ // e.g., there is no constructor to call
+ // let's watch for the last constructor
+ // (see ticket #9795)
+ if(++i == l){
+ break;
+ }
+ preArgs[i] = a;
+ }
+ }
+ // 2) call all non-trivial constructors using prepared arguments
+ for(i = l - 1; i >= 0; --i){
+ f = bases[i];
+ m = f._meta;
+ f = m ? m.ctor : f;
+ if(f){
+ f.apply(this, preArgs ? preArgs[i] : a);
+ }
+ }
+ // 3) continue the original ritual: call the postscript
+ f = this.postscript;
+ if(f){
+ f.apply(this, args);
+ }
+ };
+ }
+
+
+ // chained constructor compatible with the legacy dojo.declare()
+ function singleConstructor(ctor, ctorSpecial){
+ return function(){
+ var a = arguments, t = a, a0 = a[0], f;
+
+ if(!(this instanceof a.callee)){
+ // not called via new, so force it
+ return applyNew(a);
+ }
+
+ //this._inherited = {};
+ // perform the shaman's rituals of the original dojo.declare()
+ // 1) call two types of the preamble
+ if(ctorSpecial){
+ // full blown ritual
+ if(a0){
+ // process the preamble of the 1st argument
+ f = a0.preamble;
+ if(f){
+ t = f.apply(this, t) || t;
+ }
+ }
+ f = this.preamble;
+ if(f){
+ // process the preamble of this class
+ f.apply(this, t);
+ // one peculiarity of the preamble:
+ // it is called even if it is not needed,
+ // e.g., there is no constructor to call
+ // let's watch for the last constructor
+ // (see ticket #9795)
+ }
+ }
+ // 2) call a constructor
+ if(ctor){
+ ctor.apply(this, a);
+ }
+ // 3) continue the original ritual: call the postscript
+ f = this.postscript;
+ if(f){
+ f.apply(this, a);
+ }
+ };
+ }
+
+ // plain vanilla constructor (can use inherited() to call its base constructor)
+ function simpleConstructor(bases){
+ return function(){
+ var a = arguments, i = 0, f, m;
+
+ if(!(this instanceof a.callee)){
+ // not called via new, so force it
+ return applyNew(a);
+ }
+
+ //this._inherited = {};
+ // perform the shaman's rituals of the original dojo.declare()
+ // 1) do not call the preamble
+ // 2) call the top constructor (it can use this.inherited())
+ for(; f = bases[i]; ++i){ // intentional assignment
+ m = f._meta;
+ f = m ? m.ctor : f;
+ if(f){
+ f.apply(this, a);
+ break;
+ }
+ }
+ // 3) call the postscript
+ f = this.postscript;
+ if(f){
+ f.apply(this, a);
+ }
+ };
+ }
+
+ function chain(name, bases, reversed){
+ return function(){
+ var b, m, f, i = 0, step = 1;
+ if(reversed){
+ i = bases.length - 1;
+ step = -1;
+ }
+ for(; b = bases[i]; i += step){ // intentional assignment
+ m = b._meta;
+ f = (m ? m.hidden : b.prototype)[name];
+ if(f){
+ f.apply(this, arguments);
+ }
+ }
+ };
+ }
+
+ // forceNew(ctor)
+ // return a new object that inherits from ctor.prototype but
+ // without actually running ctor on the object.
+ function forceNew(ctor){
+ // create object with correct prototype using a do-nothing
+ // constructor
+ xtor.prototype = ctor.prototype;
+ var t = new xtor;
+ xtor.prototype = null; // clean up
+ return t;
+ }
+
+ // applyNew(args)
+ // just like 'new ctor()' except that the constructor and its arguments come
+ // from args, which must be an array or an arguments object
+ function applyNew(args){
+ // create an object with ctor's prototype but without
+ // calling ctor on it.
+ var ctor = args.callee, t = forceNew(ctor);
+ // execute the real constructor on the new object
+ ctor.apply(t, args);
+ return t;
+ }
+
+ d.declare = function(className, superclass, props){
+ // crack parameters
+ if(typeof className != "string"){
+ props = superclass;
+ superclass = className;
+ className = "";
+ }
+ props = props || {};
+
+ var proto, i, t, ctor, name, bases, chains, mixins = 1, parents = superclass;
+
+ // build a prototype
+ if(opts.call(superclass) == "[object Array]"){
+ // C3 MRO
+ bases = c3mro(superclass);
+ t = bases[0];
+ mixins = bases.length - t;
+ superclass = bases[mixins];
+ }else{
+ bases = [0];
+ if(superclass){
+ if(opts.call(superclass) == "[object Function]"){
+ t = superclass._meta;
+ bases = bases.concat(t ? t.bases : superclass);
+ }else{
+ err("base class is not a callable constructor.");
+ }
+ }else if(superclass !== null){
+ err("unknown base class. Did you use dojo.require to pull it in?")
+ }
+ }
+ if(superclass){
+ for(i = mixins - 1;; --i){
+ proto = forceNew(superclass);
+ if(!i){
+ // stop if nothing to add (the last base)
+ break;
+ }
+ // mix in properties
+ t = bases[i];
+ (t._meta ? mixOwn : mix)(proto, t.prototype);
+ // chain in new constructor
+ ctor = new Function;
+ ctor.superclass = superclass;
+ ctor.prototype = proto;
+ superclass = proto.constructor = ctor;
+ }
+ }else{
+ proto = {};
+ }
+ // add all properties
+ safeMixin(proto, props);
+ // add constructor
+ t = props.constructor;
+ if(t !== op.constructor){
+ t.nom = cname;
+ proto.constructor = t;
+ }
+
+ // collect chains and flags
+ for(i = mixins - 1; i; --i){ // intentional assignment
+ t = bases[i]._meta;
+ if(t && t.chains){
+ chains = mix(chains || {}, t.chains);
+ }
+ }
+ if(proto["-chains-"]){
+ chains = mix(chains || {}, proto["-chains-"]);
+ }
+
+ // build ctor
+ t = !chains || !chains.hasOwnProperty(cname);
+ bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) :
+ (bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t));
+
+ // add meta information to the constructor
+ ctor._meta = {bases: bases, hidden: props, chains: chains,
+ parents: parents, ctor: props.constructor};
+ ctor.superclass = superclass && superclass.prototype;
+ ctor.extend = extend;
+ ctor.prototype = proto;
+ proto.constructor = ctor;
+
+ // add "standard" methods to the prototype
+ proto.getInherited = getInherited;
+ proto.inherited = inherited;
+ proto.isInstanceOf = isInstanceOf;
+
+ // add name if specified
+ if(className){
+ proto.declaredClass = className;
+ d.setObject(className, ctor);
+ }
+
+ // build chains and add them to the prototype
+ if(chains){
+ for(name in chains){
+ if(proto[name] && typeof chains[name] == "string" && name != cname){
+ t = proto[name] = chain(name, bases, chains[name] === "after");
+ t.nom = name;
+ }
+ }
+ }
+ // chained methods do not return values
+ // no need to chain "invisible" functions
+
+ return ctor; // Function
+ };
+
+ d.safeMixin = safeMixin;
+
+ /*=====
+ dojo.declare = function(className, superclass, props){
+ // summary:
+ // Create a feature-rich constructor from compact notation.
+ // className: String?:
+ // The optional name of the constructor (loosely, a "class")
+ // stored in the "declaredClass" property in the created prototype.
+ // It will be used as a global name for a created constructor.
+ // superclass: Function|Function[]:
+ // May be null, a Function, or an Array of Functions. This argument
+ // specifies a list of bases (the left-most one is the most deepest
+ // base).
+ // props: Object:
+ // An object whose properties are copied to the created prototype.
+ // Add an instance-initialization function by making it a property
+ // named "constructor".
+ // returns:
+ // New constructor function.
+ // description:
+ // Create a constructor using a compact notation for inheritance and
+ // prototype extension.
+ //
+ // 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.
+ //
+ // Ancestors can be compound classes created by this version of
+ // dojo.declare. In complex cases all base classes are going to be
+ // linearized according to C3 MRO algorithm
+ // (see http://www.python.org/download/releases/2.3/mro/ for more
+ // details).
+ //
+ // "className" is cached in "declaredClass" property of the new class,
+ // if it was supplied. The immediate super class will be cached in
+ // "superclass" property of the new class.
+ //
+ // Methods in "props" will be copied and modified: "nom" property
+ // (the declared name of the method) will be added to all copied
+ // functions to help identify them for the internal machinery. Be
+ // very careful, while reusing methods: if you use the same
+ // function under different names, it can produce errors in some
+ // cases.
+ //
+ // It is possible to use constructors created "manually" (without
+ // dojo.declare) as bases. They will be called as usual during the
+ // creation of an instance, their methods will be chained, and even
+ // called by "this.inherited()".
+ //
+ // Special property "-chains-" governs how to chain methods. It is
+ // a dictionary, which uses method names as keys, and hint strings
+ // as values. If a hint string is "after", this method will be
+ // called after methods of its base classes. If a hint string is
+ // "before", this method will be called before methods of its base
+ // classes.
+ //
+ // If "constructor" is not mentioned in "-chains-" property, it will
+ // be chained using the legacy mode: using "after" chaining,
+ // calling preamble() method before each constructor, if available,
+ // and calling postscript() after all constructors were executed.
+ // If the hint is "after", it is chained as a regular method, but
+ // postscript() will be called after the chain of constructors.
+ // "constructor" cannot be chained "before", but it allows
+ // a special hint string: "manual", which means that constructors
+ // are not going to be chained in any way, and programmer will call
+ // them manually using this.inherited(). In the latter case
+ // postscript() will be called after the construction.
+ //
+ // All chaining hints are "inherited" from base classes and
+ // potentially can be overridden. Be very careful when overriding
+ // hints! Make sure that all chained methods can work in a proposed
+ // manner of chaining.
+ //
+ // Once a method was chained, it is impossible to unchain it. The
+ // only exception is "constructor". You don't need to define a
+ // method in order to supply a chaining hint.
+ //
+ // If a method is chained, it cannot use this.inherited() because
+ // all other methods in the hierarchy will be called automatically.
+ //
+ // Usually constructors and initializers of any kind are chained
+ // using "after" and destructors of any kind are chained as
+ // "before". Note that chaining assumes that chained methods do not
+ // return any value: any returned value will be discarded.
+ //
+ // 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();
+ // | }
+ // | });
+ //
+ // example:
+ // | var MyBase = dojo.declare(null, {
+ // | // constructor, properties, and methods go here
+ // | // ...
+ // | });
+ // | var MyClass1 = dojo.declare(MyBase, {
+ // | // constructor, properties, and methods go here
+ // | // ...
+ // | });
+ // | var MyClass2 = dojo.declare(MyBase, {
+ // | // constructor, properties, and methods go here
+ // | // ...
+ // | });
+ // | var MyDiamond = dojo.declare([MyClass1, MyClass2], {
+ // | // constructor, properties, and methods go here
+ // | // ...
+ // | });
+ //
+ // example:
+ // | var F = function(){ console.log("raw constructor"); };
+ // | F.prototype.method = function(){
+ // | console.log("raw method");
+ // | };
+ // | var A = dojo.declare(F, {
+ // | constructor: function(){
+ // | console.log("A.constructor");
+ // | },
+ // | method: function(){
+ // | console.log("before calling F.method...");
+ // | this.inherited(arguments);
+ // | console.log("...back in A");
+ // | }
+ // | });
+ // | new A().method();
+ // | // will print:
+ // | // raw constructor
+ // | // A.constructor
+ // | // before calling F.method...
+ // | // raw method
+ // | // ...back in A
+ //
+ // example:
+ // | var A = dojo.declare(null, {
+ // | "-chains-": {
+ // | destroy: "before"
+ // | }
+ // | });
+ // | var B = dojo.declare(A, {
+ // | constructor: function(){
+ // | console.log("B.constructor");
+ // | },
+ // | destroy: function(){
+ // | console.log("B.destroy");
+ // | }
+ // | });
+ // | var C = dojo.declare(B, {
+ // | constructor: function(){
+ // | console.log("C.constructor");
+ // | },
+ // | destroy: function(){
+ // | console.log("C.destroy");
+ // | }
+ // | });
+ // | new C().destroy();
+ // | // prints:
+ // | // B.constructor
+ // | // C.constructor
+ // | // C.destroy
+ // | // B.destroy
+ //
+ // example:
+ // | var A = dojo.declare(null, {
+ // | "-chains-": {
+ // | constructor: "manual"
+ // | }
+ // | });
+ // | var B = dojo.declare(A, {
+ // | constructor: function(){
+ // | // ...
+ // | // call the base constructor with new parameters
+ // | this.inherited(arguments, [1, 2, 3]);
+ // | // ...
+ // | }
+ // | });
+ //
+ // example:
+ // | var A = dojo.declare(null, {
+ // | "-chains-": {
+ // | m1: "before"
+ // | },
+ // | m1: function(){
+ // | console.log("A.m1");
+ // | },
+ // | m2: function(){
+ // | console.log("A.m2");
+ // | }
+ // | });
+ // | var B = dojo.declare(A, {
+ // | "-chains-": {
+ // | m2: "after"
+ // | },
+ // | m1: function(){
+ // | console.log("B.m1");
+ // | },
+ // | m2: function(){
+ // | console.log("B.m2");
+ // | }
+ // | });
+ // | var x = new B();
+ // | x.m1();
+ // | // prints:
+ // | // B.m1
+ // | // A.m1
+ // | x.m2();
+ // | // prints:
+ // | // A.m2
+ // | // B.m2
+ return new Function(); // Function
+ };
+ =====*/
+
+ /*=====
+ dojo.safeMixin = function(target, source){
+ // summary:
+ // Mix in properties skipping a constructor and decorating functions
+ // like it is done by dojo.declare.
+ // target: Object
+ // Target object to accept new properties.
+ // source: Object
+ // Source object for new properties.
+ // description:
+ // This function is used to mix in properties like dojo._mixin does,
+ // but it skips a constructor property and decorates functions like
+ // dojo.declare does.
+ //
+ // It is meant to be used with classes and objects produced with
+ // dojo.declare. Functions mixed in with dojo.safeMixin can use
+ // this.inherited() like normal methods.
+ //
+ // This function is used to implement extend() method of a constructor
+ // produced with dojo.declare().
+ //
+ // example:
+ // | var A = dojo.declare(null, {
+ // | m1: function(){
+ // | console.log("A.m1");
+ // | },
+ // | m2: function(){
+ // | console.log("A.m2");
+ // | }
+ // | });
+ // | var B = dojo.declare(A, {
+ // | m1: function(){
+ // | this.inherited(arguments);
+ // | console.log("B.m1");
+ // | }
+ // | });
+ // | B.extend({
+ // | m2: function(){
+ // | this.inherited(arguments);
+ // | console.log("B.m2");
+ // | }
+ // | });
+ // | var x = new B();
+ // | dojo.safeMixin(x, {
+ // | m1: function(){
+ // | this.inherited(arguments);
+ // | console.log("X.m1");
+ // | },
+ // | m2: function(){
+ // | this.inherited(arguments);
+ // | console.log("X.m2");
+ // | }
+ // | });
+ // | x.m2();
+ // | // prints:
+ // | // A.m1
+ // | // B.m1
+ // | // X.m1
+ };
+ =====*/
+
+ /*=====
+ Object.inherited = function(name, args, newArgs){
+ // summary:
+ // Calls a super method.
+ // name: String?
+ // The optional method name. Should be the same as the caller's
+ // name. Usually "name" is specified in complex dynamic cases, when
+ // the calling method was dynamically added, undecorated by
+ // dojo.declare, and it cannot be determined.
+ // args: Arguments
+ // The caller supply this argument, which should be the original
+ // "arguments".
+ // newArgs: Object?
+ // If "true", the found function will be returned without
+ // executing it.
+ // If Array, it will be used to call a super method. Otherwise
+ // "args" will be used.
+ // returns:
+ // Whatever is returned by a super method, or a super method itself,
+ // if "true" was specified as newArgs.
+ // description:
+ // This method is used inside method of classes produced with
+ // dojo.declare to call a super method (next in the chain). It is
+ // used for manually controlled chaining. Consider using the regular
+ // chaining, because it is faster. Use "this.inherited()" only in
+ // complex cases.
+ //
+ // This method cannot me called from automatically chained
+ // constructors including the case of a special (legacy)
+ // constructor chaining. It cannot be called from chained methods.
+ //
+ // If "this.inherited()" cannot find the next-in-chain method, it
+ // does nothing and returns "undefined". The last method in chain
+ // can be a default method implemented in Object, which will be
+ // called last.
+ //
+ // If "name" is specified, it is assumed that the method that
+ // received "args" is the parent method for this call. It is looked
+ // up in the chain list and if it is found the next-in-chain method
+ // is called. If it is not found, the first-in-chain method is
+ // called.
+ //
+ // If "name" is not specified, it will be derived from the calling
+ // method (using a methoid property "nom").
+ //
+ // example:
+ // | var B = dojo.declare(A, {
+ // | method1: function(a, b, c){
+ // | this.inherited(arguments);
+ // | },
+ // | method2: function(a, b){
+ // | return this.inherited(arguments, [a + b]);
+ // | }
+ // | });
+ // | // next method is not in the chain list because it is added
+ // | // manually after the class was created.
+ // | B.prototype.method3 = function(){
+ // | console.log("This is a dynamically-added method.");
+ // | this.inherited("method3", arguments);
+ // | };
+ // example:
+ // | var B = dojo.declare(A, {
+ // | method: function(a, b){
+ // | var super = this.inherited(arguments, true);
+ // | // ...
+ // | if(!super){
+ // | console.log("there is no super method");
+ // | return 0;
+ // | }
+ // | return super.apply(this, arguments);
+ // | }
+ // | });
+ return {}; // Object
+ }
+ =====*/
+
+ /*=====
+ Object.getInherited = function(name, args){
+ // summary:
+ // Returns a super method.
+ // name: String?
+ // The optional method name. Should be the same as the caller's
+ // name. Usually "name" is specified in complex dynamic cases, when
+ // the calling method was dynamically added, undecorated by
+ // dojo.declare, and it cannot be determined.
+ // args: Arguments
+ // The caller supply this argument, which should be the original
+ // "arguments".
+ // returns:
+ // Returns a super method (Function) or "undefined".
+ // description:
+ // This method is a convenience method for "this.inherited()".
+ // It uses the same algorithm but instead of executing a super
+ // method, it returns it, or "undefined" if not found.
+ //
+ // example:
+ // | var B = dojo.declare(A, {
+ // | method: function(a, b){
+ // | var super = this.getInherited(arguments);
+ // | // ...
+ // | if(!super){
+ // | console.log("there is no super method");
+ // | return 0;
+ // | }
+ // | return super.apply(this, arguments);
+ // | }
+ // | });
+ return {}; // Object
+ }
+ =====*/
+
+ /*=====
+ Object.isInstanceOf = function(cls){
+ // summary:
+ // Checks the inheritance chain to see if it is inherited from this
+ // class.
+ // cls: Function
+ // Class constructor.
+ // returns:
+ // "true", if this object is inherited from this class, "false"
+ // otherwise.
+ // description:
+ // This method is used with instances of classes produced with
+ // dojo.declare to determine of they support a certain interface or
+ // not. It models "instanceof" operator.
+ //
+ // example:
+ // | var A = dojo.declare(null, {
+ // | // constructor, properties, and methods go here
+ // | // ...
+ // | });
+ // | var B = dojo.declare(null, {
+ // | // constructor, properties, and methods go here
+ // | // ...
+ // | });
+ // | var C = dojo.declare([A, B], {
+ // | // constructor, properties, and methods go here
+ // | // ...
+ // | });
+ // | var D = dojo.declare(A, {
+ // | // constructor, properties, and methods go here
+ // | // ...
+ // | });
+ // |
+ // | var a = new A(), b = new B(), c = new C(), d = new D();
+ // |
+ // | console.log(a.isInstanceOf(A)); // true
+ // | console.log(b.isInstanceOf(A)); // false
+ // | console.log(c.isInstanceOf(A)); // true
+ // | console.log(d.isInstanceOf(A)); // true
+ // |
+ // | console.log(a.isInstanceOf(B)); // false
+ // | console.log(b.isInstanceOf(B)); // true
+ // | console.log(c.isInstanceOf(B)); // true
+ // | console.log(d.isInstanceOf(B)); // false
+ // |
+ // | console.log(a.isInstanceOf(C)); // false
+ // | console.log(b.isInstanceOf(C)); // false
+ // | console.log(c.isInstanceOf(C)); // true
+ // | console.log(d.isInstanceOf(C)); // false
+ // |
+ // | console.log(a.isInstanceOf(D)); // false
+ // | console.log(b.isInstanceOf(D)); // false
+ // | console.log(c.isInstanceOf(D)); // false
+ // | console.log(d.isInstanceOf(D)); // true
+ return {}; // Object
+ }
+ =====*/
+
+ /*=====
+ Object.extend = function(source){
+ // summary:
+ // Adds all properties and methods of source to constructor's
+ // prototype, making them available to all instances created with
+ // constructor. This method is specific to constructors created with
+ // dojo.declare.
+ // source: Object
+ // Source object which properties are going to be copied to the
+ // constructor's prototype.
+ // description:
+ // Adds source properties to the constructor's prototype. It can
+ // override existing properties.
+ //
+ // This method is similar to dojo.extend function, but it is specific
+ // to constructors produced by dojo.declare. It is implemented
+ // using dojo.safeMixin, and it skips a constructor property,
+ // and properly decorates copied functions.
+ //
+ // example:
+ // | var A = dojo.declare(null, {
+ // | m1: function(){},
+ // | s1: "Popokatepetl"
+ // | });
+ // | A.extend({
+ // | m1: function(){},
+ // | m2: function(){},
+ // | f1: true,
+ // | d1: 42
+ // | });
+ };
+ =====*/
})();
+
}
diff --git a/lib/dojo/_base/event.js b/lib/dojo/_base/event.js
index 1e6ef788a..5268c6cff 100644
--- a/lib/dojo/_base/event.js
+++ b/lib/dojo/_base/event.js
@@ -5,355 +5,641 @@
*/
-if(!dojo._hasResource["dojo._base.event"]){
-dojo._hasResource["dojo._base.event"]=true;
+if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.event"] = true;
dojo.provide("dojo._base.event");
dojo.require("dojo._base.connect");
+
+// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
+
(function(){
-var _1=(dojo._event_listener={add:function(_2,_3,fp){
-if(!_2){
-return;
-}
-_3=_1._normalizeEventName(_3);
-fp=_1._fixCallback(_3,fp);
-var _4=_3;
-if(!dojo.isIE&&(_3=="mouseenter"||_3=="mouseleave")){
-var _5=fp;
-_3=(_3=="mouseenter")?"mouseover":"mouseout";
-fp=function(e){
-if(!dojo.isDescendant(e.relatedTarget,_2)){
-return _5.call(this,e);
-}
-};
-}
-_2.addEventListener(_3,fp,false);
-return fp;
-},remove:function(_6,_7,_8){
-if(_6){
-_7=_1._normalizeEventName(_7);
-if(!dojo.isIE&&(_7=="mouseenter"||_7=="mouseleave")){
-_7=(_7=="mouseenter")?"mouseover":"mouseout";
-}
-_6.removeEventListener(_7,_8,false);
-}
-},_normalizeEventName:function(_9){
-return _9.slice(0,2)=="on"?_9.slice(2):_9;
-},_fixCallback:function(_a,fp){
-return _a!="keypress"?fp:function(e){
-return fp.call(this,_1._fixEvent(e,this));
-};
-},_fixEvent:function(_b,_c){
-switch(_b.type){
-case "keypress":
-_1._setKeyChar(_b);
-break;
-}
-return _b;
-},_setKeyChar:function(_d){
-_d.keyChar=_d.charCode?String.fromCharCode(_d.charCode):"";
-_d.charOrCode=_d.keyChar||_d.keyCode;
-},_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}});
-dojo.fixEvent=function(_e,_f){
-return _1._fixEvent(_e,_f);
-};
-dojo.stopEvent=function(evt){
-evt.preventDefault();
-evt.stopPropagation();
-};
-var _10=dojo._listener;
-dojo._connect=function(obj,_11,_12,_13,_14){
-var _15=obj&&(obj.nodeType||obj.attachEvent||obj.addEventListener);
-var lid=_15?(_14?2:1):0,l=[dojo._listener,_1,_10][lid];
-var h=l.add(obj,_11,dojo.hitch(_12,_13));
-return [obj,_11,h,lid];
-};
-dojo._disconnect=function(obj,_16,_17,_18){
-([dojo._listener,_1,_10][_18]).remove(obj,_16,_17);
-};
-dojo.keys={BACKSPACE:8,TAB:9,CLEAR:12,ENTER:13,SHIFT:16,CTRL:17,ALT:18,META:dojo.isSafari?91:224,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,copyKey:dojo.isMac&&!dojo.isAIR?(dojo.isSafari?91:224):17};
-var _19=dojo.isMac?"metaKey":"ctrlKey";
-dojo.isCopyKey=function(e){
-return e[_19];
-};
-if(dojo.isIE){
-dojo.mouseButtons={LEFT:1,MIDDLE:4,RIGHT:2,isButton:function(e,_1a){
-return e.button&_1a;
-},isLeft:function(e){
-return e.button&1;
-},isMiddle:function(e){
-return e.button&4;
-},isRight:function(e){
-return e.button&2;
-}};
-}else{
-dojo.mouseButtons={LEFT:0,MIDDLE:1,RIGHT:2,isButton:function(e,_1b){
-return e.button==_1b;
-},isLeft:function(e){
-return e.button==0;
-},isMiddle:function(e){
-return e.button==1;
-},isRight:function(e){
-return e.button==2;
-}};
-}
-if(dojo.isIE){
-var _1c=function(e,_1d){
-try{
-return (e.keyCode=_1d);
-}
-catch(e){
-return 0;
-}
-};
-var iel=dojo._listener;
-var _1e=(dojo._ieListenersName="_"+dojo._scopeName+"_listeners");
-if(!dojo.config._allow_leaks){
-_10=iel=dojo._ie_listener={handlers:[],add:function(_1f,_20,_21){
-_1f=_1f||dojo.global;
-var f=_1f[_20];
-if(!f||!f[_1e]){
-var d=dojo._getIeDispatcher();
-d.target=f&&(ieh.push(f)-1);
-d[_1e]=[];
-f=_1f[_20]=d;
-}
-return f[_1e].push(ieh.push(_21)-1);
-},remove:function(_22,_23,_24){
-var f=(_22||dojo.global)[_23],l=f&&f[_1e];
-if(f&&l&&_24--){
-delete ieh[l[_24]];
-delete l[_24];
-}
-}};
-var ieh=iel.handlers;
-}
-dojo.mixin(_1,{add:function(_25,_26,fp){
-if(!_25){
-return;
-}
-_26=_1._normalizeEventName(_26);
-if(_26=="onkeypress"){
-var kd=_25.onkeydown;
-if(!kd||!kd[_1e]||!kd._stealthKeydownHandle){
-var h=_1.add(_25,"onkeydown",_1._stealthKeyDown);
-kd=_25.onkeydown;
-kd._stealthKeydownHandle=h;
-kd._stealthKeydownRefs=1;
-}else{
-kd._stealthKeydownRefs++;
-}
-}
-return iel.add(_25,_26,_1._fixCallback(fp));
-},remove:function(_27,_28,_29){
-_28=_1._normalizeEventName(_28);
-iel.remove(_27,_28,_29);
-if(_28=="onkeypress"){
-var kd=_27.onkeydown;
-if(--kd._stealthKeydownRefs<=0){
-iel.remove(_27,"onkeydown",kd._stealthKeydownHandle);
-delete kd._stealthKeydownHandle;
-}
-}
-},_normalizeEventName:function(_2a){
-return _2a.slice(0,2)!="on"?"on"+_2a:_2a;
-},_nop:function(){
-},_fixEvent:function(evt,_2b){
-if(!evt){
-var w=_2b&&(_2b.ownerDocument||_2b.document||_2b).parentWindow||window;
-evt=w.event;
-}
-if(!evt){
-return (evt);
-}
-evt.target=evt.srcElement;
-evt.currentTarget=(_2b||evt.srcElement);
-evt.layerX=evt.offsetX;
-evt.layerY=evt.offsetY;
-var se=evt.srcElement,doc=(se&&se.ownerDocument)||document;
-var _2c=((dojo.isIE<6)||(doc["compatMode"]=="BackCompat"))?doc.body:doc.documentElement;
-var _2d=dojo._getIeDocumentElementOffset();
-evt.pageX=evt.clientX+dojo._fixIeBiDiScrollLeft(_2c.scrollLeft||0)-_2d.x;
-evt.pageY=evt.clientY+(_2c.scrollTop||0)-_2d.y;
-if(evt.type=="mouseover"){
-evt.relatedTarget=evt.fromElement;
-}
-if(evt.type=="mouseout"){
-evt.relatedTarget=evt.toElement;
-}
-evt.stopPropagation=_1._stopPropagation;
-evt.preventDefault=_1._preventDefault;
-return _1._fixKeys(evt);
-},_fixKeys:function(evt){
-switch(evt.type){
-case "keypress":
-var c=("charCode" in evt?evt.charCode:evt.keyCode);
-if(c==10){
-c=0;
-evt.keyCode=13;
-}else{
-if(c==13||c==27){
-c=0;
-}else{
-if(c==3){
-c=99;
-}
-}
-}
-evt.charCode=c;
-_1._setKeyChar(evt);
-break;
-}
-return evt;
-},_stealthKeyDown:function(evt){
-var kp=evt.currentTarget.onkeypress;
-if(!kp||!kp[_1e]){
-return;
-}
-var k=evt.keyCode;
-var _2e=k!=13&&k!=32&&k!=27&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);
-if(_2e||evt.ctrlKey){
-var c=_2e?0:k;
-if(evt.ctrlKey){
-if(k==3||k==13){
-return;
-}else{
-if(c>95&&c<106){
-c-=48;
-}else{
-if((!evt.shiftKey)&&(c>=65&&c<=90)){
-c+=32;
-}else{
-c=_1._punctMap[c]||c;
-}
-}
-}
-}
-var _2f=_1._synthesizeEvent(evt,{type:"keypress",faux:true,charCode:c});
-kp.call(evt.currentTarget,_2f);
-evt.cancelBubble=_2f.cancelBubble;
-evt.returnValue=_2f.returnValue;
-_1c(evt,_2f.keyCode);
-}
-},_stopPropagation:function(){
-this.cancelBubble=true;
-},_preventDefault:function(){
-this.bubbledKeyCode=this.keyCode;
-if(this.ctrlKey){
-_1c(this,0);
-}
-this.returnValue=false;
-}});
-dojo.stopEvent=function(evt){
-evt=evt||window.event;
-_1._stopPropagation.call(evt);
-_1._preventDefault.call(evt);
-};
-}
-_1._synthesizeEvent=function(evt,_30){
-var _31=dojo.mixin({},evt,_30);
-_1._setKeyChar(_31);
-_31.preventDefault=function(){
-evt.preventDefault();
-};
-_31.stopPropagation=function(){
-evt.stopPropagation();
-};
-return _31;
-};
-if(dojo.isOpera){
-dojo.mixin(_1,{_fixEvent:function(evt,_32){
-switch(evt.type){
-case "keypress":
-var c=evt.which;
-if(c==3){
-c=99;
-}
-c=c<41&&!evt.shiftKey?0:c;
-if(evt.ctrlKey&&!evt.shiftKey&&c>=65&&c<=90){
-c+=32;
-}
-return _1._synthesizeEvent(evt,{charCode:c});
-}
-return evt;
-}});
-}
-if(dojo.isWebKit){
-_1._add=_1.add;
-_1._remove=_1.remove;
-dojo.mixin(_1,{add:function(_33,_34,fp){
-if(!_33){
-return;
-}
-var _35=_1._add(_33,_34,fp);
-if(_1._normalizeEventName(_34)=="keypress"){
-_35._stealthKeyDownHandle=_1._add(_33,"keydown",function(evt){
-var k=evt.keyCode;
-var _36=k!=13&&k!=32&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);
-if(_36||evt.ctrlKey){
-var c=_36?0:k;
-if(evt.ctrlKey){
-if(k==3||k==13){
-return;
-}else{
-if(c>95&&c<106){
-c-=48;
-}else{
-if(!evt.shiftKey&&c>=65&&c<=90){
-c+=32;
-}else{
-c=_1._punctMap[c]||c;
-}
-}
-}
-}
-var _37=_1._synthesizeEvent(evt,{type:"keypress",faux:true,charCode:c});
-fp.call(evt.currentTarget,_37);
-}
-});
-}
-return _35;
-},remove:function(_38,_39,_3a){
-if(_38){
-if(_3a._stealthKeyDownHandle){
-_1._remove(_38,"keydown",_3a._stealthKeyDownHandle);
-}
-_1._remove(_38,_39,_3a);
-}
-},_fixEvent:function(evt,_3b){
-switch(evt.type){
-case "keypress":
-if(evt.faux){
-return evt;
-}
-var c=evt.charCode;
-c=c>=32?c:0;
-return _1._synthesizeEvent(evt,{charCode:c,faux:true});
-}
-return evt;
-}});
-}
-})();
+ // 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){
+ 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){
+ event = del._normalizeEventName(event);
+ if(!dojo.isIE && (event == "mouseenter" || event == "mouseleave")){
+ event = (event == "mouseenter") ? "mouseover" : "mouseout";
+ }
+
+ node.removeEventListener(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) : '';
+ evt.charOrCode = evt.keyChar || evt.keyCode;
+ },
+ // For IE and Safari: 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
+ }
+ });
+
+ // 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 ? (dontFix ? 2 : 1) : 0, 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,
+ META: dojo.isSafari ? 91 : 224, // the apple key on macs
+ 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,
+ // virtual key mapping
+ copyKey: dojo.isMac && !dojo.isAIR ? (dojo.isSafari ? 91 : 224 ) : 17
+ };
+
+ var evtCopyKey = dojo.isMac ? "metaKey" : "ctrlKey";
+
+ dojo.isCopyKey = function(e){
+ // summary:
+ // Checks an event for the copy key (meta on Mac, and ctrl anywhere else)
+ // e: Event
+ // Event object to examine
+ return e[evtCopyKey]; // Boolean
+ };
+
+ // Public: decoding mouse buttons from events
+
+/*=====
+ dojo.mouseButtons = {
+ // LEFT: Number
+ // Numeric value of the left mouse button for the platform.
+ LEFT: 0,
+ // MIDDLE: Number
+ // Numeric value of the middle mouse button for the platform.
+ MIDDLE: 1,
+ // RIGHT: Number
+ // Numeric value of the right mouse button for the platform.
+ RIGHT: 2,
+
+ isButton: function(e, button){
+ // summary:
+ // Checks an event object for a pressed button
+ // e: Event
+ // Event object to examine
+ // button: Number
+ // The button value (example: dojo.mouseButton.LEFT)
+ return e.button == button; // Boolean
+ },
+ isLeft: function(e){
+ // summary:
+ // Checks an event object for the pressed left button
+ // e: Event
+ // Event object to examine
+ return e.button == 0; // Boolean
+ },
+ isMiddle: function(e){
+ // summary:
+ // Checks an event object for the pressed middle button
+ // e: Event
+ // Event object to examine
+ return e.button == 1; // Boolean
+ },
+ isRight: function(e){
+ // summary:
+ // Checks an event object for the pressed right button
+ // e: Event
+ // Event object to examine
+ return e.button == 2; // Boolean
+ }
+ };
+=====*/
+
+ if(dojo.isIE){
+ dojo.mouseButtons = {
+ LEFT: 1,
+ MIDDLE: 4,
+ RIGHT: 2,
+ // helper functions
+ isButton: function(e, button){ return e.button & button; },
+ isLeft: function(e){ return e.button & 1; },
+ isMiddle: function(e){ return e.button & 4; },
+ isRight: function(e){ return e.button & 2; }
+ };
+ }else{
+ dojo.mouseButtons = {
+ LEFT: 0,
+ MIDDLE: 1,
+ RIGHT: 2,
+ // helper functions
+ isButton: function(e, button){ return e.button == button; },
+ isLeft: function(e){ return e.button == 0; },
+ isMiddle: function(e){ return e.button == 1; },
+ isRight: function(e){ return e.button == 2; }
+ };
+ }
+
+ // 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;
+ var listenersName = (dojo._ieListenersName = "_" + dojo._scopeName + "_listeners");
+ // 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[listenersName]){
+ 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[listenersName] = [];
+ // redirect source to dispatcher
+ f = source[method] = d;
+ }
+ return f[listenersName].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[listenersName];
+ 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[listenersName] || !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;
+ },
+ _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[listenersName]){ 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;
+ }
+ });
+ }
+
+ // Webkit event normalization
+ if(dojo.isWebKit){
+ del._add = del.add;
+ del._remove = del.remove;
+
+ dojo.mixin(del, {
+ add: function(/*DOMNode*/ node, /*String*/ event, /*Function*/ fp){
+ if(!node){return;} // undefined
+ var handle = del._add(node, event, fp);
+ if(del._normalizeEventName(event) == "keypress"){
+ // we need to listen to onkeydown to synthesize
+ // keypress events that otherwise won't fire
+ // in Safari 3.1+: https://lists.webkit.org/pipermail/webkit-dev/2007-December/002992.html
+ handle._stealthKeyDownHandle = del._add(node, "keydown", function(evt){
+ //A variation on the IE _stealthKeydown function
+ //Synthesize an onkeypress event, but only for unprintable characters.
+ 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<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});
+ fp.call(evt.currentTarget, faux);
+ }
+ });
+ }
+ return handle; /*Handle*/
+ },
+
+ remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){
+ if(node){
+ if(handle._stealthKeyDownHandle){
+ del._remove(node, "keydown", handle._stealthKeyDownHandle);
+ }
+ del._remove(node, event, handle);
+ }
+ },
+ _fixEvent: function(evt, sender){
+ switch(evt.type){
+ case "keypress":
+ if(evt.faux){ return evt; }
+ var c = evt.charCode;
+ c = c>=32 ? c : 0;
+ return del._synthesizeEvent(evt, {charCode: c, faux: true});
+ }
+ return evt;
+ }
+ });
+ }
+ })();
+
if(dojo.isIE){
-dojo._ieDispatcher=function(_3c,_3d){
-var ap=Array.prototype,h=dojo._ie_listener.handlers,c=_3c.callee,ls=c[dojo._ieListenersName],t=h[c.target];
-var r=t&&t.apply(_3d,_3c);
-var lls=[].concat(ls);
-for(var i in lls){
-var f=h[lls[i]];
-if(!(i in ap)&&f){
-f.apply(_3d,_3c);
-}
-}
-return r;
-};
-dojo._getIeDispatcher=function(){
-return new Function(dojo._scopeName+"._ieDispatcher(arguments, this)");
-};
-dojo._event_listener._fixCallback=function(fp){
-var f=dojo._event_listener._fixEvent;
-return function(e){
-return fp.call(this,f(e,this));
-};
-};
+ // 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[dojo._ieListenersName],
+ t = h[c.target];
+ // return value comes from original target function
+ var r = t && t.apply(sender, args);
+ // make local copy of listener array so it's immutable during processing
+ var lls = [].concat(ls);
+ // invoke listeners after target function
+ for(var i in lls){
+ var f = h[lls[i]];
+ if(!(i in ap) && f){
+ f.apply(sender, args);
+ }
+ }
+ return r;
+ }
+ dojo._getIeDispatcher = function(){
+ // ensure the returned function closes over nothing ("new Function" apparently doesn't close)
+ 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/lib/dojo/_base/fx.js b/lib/dojo/_base/fx.js
index 1c589402e..21243c1c9 100644
--- a/lib/dojo/_base/fx.js
+++ b/lib/dojo/_base/fx.js
@@ -5,298 +5,665 @@
*/
-if(!dojo._hasResource["dojo._base.fx"]){
-dojo._hasResource["dojo._base.fx"]=true;
+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.lang");
dojo.require("dojo._base.html");
+
+/*
+ Animation loosely package based on Dan Pupius' work, contributed under CLA:
+ http://pupius.co.uk/js/Toolkit.Drawing.js
+*/
(function(){
-var d=dojo;
-var _1=d._mixin;
-dojo._Line=function(_2,_3){
-this.start=_2;
-this.end=_3;
-};
-dojo._Line.prototype.getValue=function(n){
-return ((this.end-this.start)*n)+this.start;
-};
-dojo.Animation=function(_4){
-_1(this,_4);
-if(d.isArray(this.curve)){
-this.curve=new d._Line(this.curve[0],this.curve[1]);
-}
-};
-d._Animation=d.Animation;
-d.extend(dojo.Animation,{duration:350,repeat:0,rate:20,_percent:0,_startRepeatCount:0,_getStep:function(){
-var _5=this._percent,_6=this.easing;
-return _6?_6(_5):_5;
-},_fire:function(_7,_8){
-var a=_8||[];
-if(this[_7]){
-if(d.config.debugAtAllCosts){
-this[_7].apply(this,a);
-}else{
-try{
-this[_7].apply(this,a);
-}
-catch(e){
-console.error("exception in animation handler for:",_7);
-console.error(e);
-}
-}
-}
-return this;
-},play:function(_9,_a){
-var _b=this;
-if(_b._delayTimer){
-_b._clearTimer();
-}
-if(_a){
-_b._stopTimer();
-_b._active=_b._paused=false;
-_b._percent=0;
-}else{
-if(_b._active&&!_b._paused){
-return _b;
-}
-}
-_b._fire("beforeBegin",[_b.node]);
-var de=_9||_b.delay,_c=dojo.hitch(_b,"_play",_a);
-if(de>0){
-_b._delayTimer=setTimeout(_c,de);
-return _b;
-}
-_c();
-return _b;
-},_play:function(_d){
-var _e=this;
-if(_e._delayTimer){
-_e._clearTimer();
-}
-_e._startTime=new Date().valueOf();
-if(_e._paused){
-_e._startTime-=_e.duration*_e._percent;
-}
-_e._active=true;
-_e._paused=false;
-var _f=_e.curve.getValue(_e._getStep());
-if(!_e._percent){
-if(!_e._startRepeatCount){
-_e._startRepeatCount=_e.repeat;
-}
-_e._fire("onBegin",[_f]);
-}
-_e._fire("onPlay",[_f]);
-_e._cycle();
-return _e;
-},pause:function(){
-var _10=this;
-if(_10._delayTimer){
-_10._clearTimer();
-}
-_10._stopTimer();
-if(!_10._active){
-return _10;
-}
-_10._paused=true;
-_10._fire("onPause",[_10.curve.getValue(_10._getStep())]);
-return _10;
-},gotoPercent:function(_11,_12){
-var _13=this;
-_13._stopTimer();
-_13._active=_13._paused=true;
-_13._percent=_11;
-if(_12){
-_13.play();
-}
-return _13;
-},stop:function(_14){
-var _15=this;
-if(_15._delayTimer){
-_15._clearTimer();
-}
-if(!_15._timer){
-return _15;
-}
-_15._stopTimer();
-if(_14){
-_15._percent=1;
-}
-_15._fire("onStop",[_15.curve.getValue(_15._getStep())]);
-_15._active=_15._paused=false;
-return _15;
-},status:function(){
-if(this._active){
-return this._paused?"paused":"playing";
-}
-return "stopped";
-},_cycle:function(){
-var _16=this;
-if(_16._active){
-var _17=new Date().valueOf();
-var _18=(_17-_16._startTime)/(_16.duration);
-if(_18>=1){
-_18=1;
-}
-_16._percent=_18;
-if(_16.easing){
-_18=_16.easing(_18);
-}
-_16._fire("onAnimate",[_16.curve.getValue(_18)]);
-if(_16._percent<1){
-_16._startTimer();
-}else{
-_16._active=false;
-if(_16.repeat>0){
-_16.repeat--;
-_16.play(null,true);
-}else{
-if(_16.repeat==-1){
-_16.play(null,true);
-}else{
-if(_16._startRepeatCount){
-_16.repeat=_16._startRepeatCount;
-_16._startRepeatCount=0;
-}
-}
-}
-_16._percent=0;
-_16._fire("onEnd",[_16.node]);
-!_16.repeat&&_16._stopTimer();
-}
-}
-return _16;
-},_clearTimer:function(){
-clearTimeout(this._delayTimer);
-delete this._delayTimer;
-}});
-var ctr=0,_19=null,_1a={run:function(){
-}};
-d.extend(d.Animation,{_startTimer:function(){
-if(!this._timer){
-this._timer=d.connect(_1a,"run",this,"_cycle");
-ctr++;
-}
-if(!_19){
-_19=setInterval(d.hitch(_1a,"run"),this.rate);
-}
-},_stopTimer:function(){
-if(this._timer){
-d.disconnect(this._timer);
-this._timer=null;
-ctr--;
-}
-if(ctr<=0){
-clearInterval(_19);
-_19=null;
-ctr=0;
-}
-}});
-var _1b=d.isIE?function(_1c){
-var ns=_1c.style;
-if(!ns.width.length&&d.style(_1c,"width")=="auto"){
-ns.width="auto";
-}
-}:function(){
-};
-dojo._fade=function(_1d){
-_1d.node=d.byId(_1d.node);
-var _1e=_1({properties:{}},_1d),_1f=(_1e.properties.opacity={});
-_1f.start=!("start" in _1e)?function(){
-return +d.style(_1e.node,"opacity")||0;
-}:_1e.start;
-_1f.end=_1e.end;
-var _20=d.animateProperty(_1e);
-d.connect(_20,"beforeBegin",d.partial(_1b,_1e.node));
-return _20;
-};
-dojo.fadeIn=function(_21){
-return d._fade(_1({end:1},_21));
-};
-dojo.fadeOut=function(_22){
-return d._fade(_1({end:0},_22));
-};
-dojo._defaultEasing=function(n){
-return 0.5+((Math.sin((n+1.5)*Math.PI))/2);
-};
-var _23=function(_24){
-this._properties=_24;
-for(var p in _24){
-var _25=_24[p];
-if(_25.start instanceof d.Color){
-_25.tempColor=new d.Color();
-}
-}
-};
-_23.prototype.getValue=function(r){
-var ret={};
-for(var p in this._properties){
-var _26=this._properties[p],_27=_26.start;
-if(_27 instanceof d.Color){
-ret[p]=d.blendColors(_27,_26.end,r,_26.tempColor).toCss();
-}else{
-if(!d.isArray(_27)){
-ret[p]=((_26.end-_27)*r)+_27+(p!="opacity"?_26.units||"px":0);
-}
-}
-}
-return ret;
-};
-dojo.animateProperty=function(_28){
-var n=_28.node=d.byId(_28.node);
-if(!_28.easing){
-_28.easing=d._defaultEasing;
-}
-var _29=new d.Animation(_28);
-d.connect(_29,"beforeBegin",_29,function(){
-var pm={};
-for(var p in this.properties){
-if(p=="width"||p=="height"){
-this.node.display="block";
-}
-var _2a=this.properties[p];
-if(d.isFunction(_2a)){
-_2a=_2a(n);
-}
-_2a=pm[p]=_1({},(d.isObject(_2a)?_2a:{end:_2a}));
-if(d.isFunction(_2a.start)){
-_2a.start=_2a.start(n);
-}
-if(d.isFunction(_2a.end)){
-_2a.end=_2a.end(n);
-}
-var _2b=(p.toLowerCase().indexOf("color")>=0);
-function _2c(_2d,p){
-var v={height:_2d.offsetHeight,width:_2d.offsetWidth}[p];
-if(v!==undefined){
-return v;
-}
-v=d.style(_2d,p);
-return (p=="opacity")?+v:(_2b?v:parseFloat(v));
-};
-if(!("end" in _2a)){
-_2a.end=_2c(n,p);
-}else{
-if(!("start" in _2a)){
-_2a.start=_2c(n,p);
-}
-}
-if(_2b){
-_2a.start=new d.Color(_2a.start);
-_2a.end=new d.Color(_2a.end);
-}else{
-_2a.start=(p=="opacity")?+_2a.start:parseFloat(_2a.start);
-}
-}
-this.curve=new _23(pm);
-});
-d.connect(_29,"onAnimate",d.hitch(d,"style",_29.node));
-return _29;
-};
-dojo.anim=function(_2e,_2f,_30,_31,_32,_33){
-return d.animateProperty({node:_2e,duration:_30||d.Animation.prototype.duration,properties:_2f,easing:_31,onEnd:_32}).play(_33||0);
-};
+ var d = dojo;
+ var _mixin = d._mixin;
+
+ 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;
+ };
+
+ dojo._Line.prototype.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
+ };
+
+ dojo.Animation = function(args){
+ // summary:
+ // A generic animation class that fires callbacks into its handlers
+ // object at various states.
+ // description:
+ // 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.
+ // args: Object
+ // The 'magic argument', mixing all the properties into this
+ // animation instance.
+
+ _mixin(this, args);
+ if(d.isArray(this.curve)){
+ this.curve = new d._Line(this.curve[0], this.curve[1]);
+ }
+
+ };
+
+ // Alias to drop come 2.0:
+ d._Animation = d.Animation;
+
+ d.extend(dojo.Animation, {
+ // 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: 1000/rate = fps)
+ rate: 20 /* 50 fps */,
+
+ /*=====
+ // delay: Integer?
+ // The time in milliseconds to wait before starting animation after it
+ // has been .play()'ed
+ delay: null,
+
+ // 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,
+
+ _getStep: function(){
+ var _p = this._percent,
+ _e = this.easing
+ ;
+ return _e ? _e(_p) : _p;
+ },
+ _fire: function(/*Event*/ evt, /*Array?*/ args){
+ // summary:
+ // Convenience function. Fire event "evt" and pass it the
+ // arguments specified in "args".
+ // description:
+ // Convenience function. Fire event "evt" and pass it the
+ // arguments specified in "args".
+ // Fires the callback in the scope of the `dojo.Animation`
+ // instance.
+ // evt:
+ // The event to fire.
+ // args:
+ // The arguments to pass to the event.
+ var a = args||[];
+ if(this[evt]){
+ if(d.config.debugAtAllCosts){
+ this[evt].apply(this, a);
+ }else{
+ try{
+ this[evt].apply(this, a);
+ }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.
+ // returns: dojo.Animation
+ // The instance to allow chaining.
+
+ var _t = this;
+ if(_t._delayTimer){ _t._clearTimer(); }
+ if(gotoStart){
+ _t._stopTimer();
+ _t._active = _t._paused = false;
+ _t._percent = 0;
+ }else if(_t._active && !_t._paused){
+ return _t;
+ }
+
+ _t._fire("beforeBegin", [_t.node]);
+
+ var de = delay || _t.delay,
+ _p = dojo.hitch(_t, "_play", gotoStart);
+
+ if(de > 0){
+ _t._delayTimer = setTimeout(_p, de);
+ return _t;
+ }
+ _p();
+ return _t;
+ },
+
+ _play: function(gotoStart){
+ var _t = this;
+ if(_t._delayTimer){ _t._clearTimer(); }
+ _t._startTime = new Date().valueOf();
+ if(_t._paused){
+ _t._startTime -= _t.duration * _t._percent;
+ }
+
+ _t._active = true;
+ _t._paused = false;
+ var value = _t.curve.getValue(_t._getStep());
+ 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.
+ var _t = this;
+ if(_t._delayTimer){ _t._clearTimer(); }
+ _t._stopTimer();
+ if(!_t._active){ return _t; /*dojo.Animation*/ }
+ _t._paused = true;
+ _t._fire("onPause", [_t.curve.getValue(_t._getStep())]);
+ return _t; // 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.
+ var _t = this;
+ _t._stopTimer();
+ _t._active = _t._paused = true;
+ _t._percent = percent;
+ if(andPlay){ _t.play(); }
+ return _t; // dojo.Animation
+ },
+
+ stop: function(/*boolean?*/ gotoEnd){
+ // summary: Stops a running animation.
+ // gotoEnd: If true, the animation will end.
+ var _t = this;
+ if(_t._delayTimer){ _t._clearTimer(); }
+ if(!_t._timer){ return _t; /* dojo.Animation */ }
+ _t._stopTimer();
+ if(gotoEnd){
+ _t._percent = 1;
+ }
+ _t._fire("onStop", [_t.curve.getValue(_t._getStep())]);
+ _t._active = _t._paused = false;
+ return _t; // 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.duration);
+
+ 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.node]);
+ !_t.repeat && _t._stopTimer();
+ }
+ }
+ return _t; // dojo.Animation
+ },
+
+ _clearTimer: function(){
+ // summary: Clear the play delay timer
+ clearTimeout(this._delayTimer);
+ delete this._delayTimer;
+ }
+
+ });
+
+ // the local timer, stubbed into all Animation instances
+ var ctr = 0,
+ timer = null,
+ runner = {
+ run: function(){}
+ };
+
+ d.extend(d.Animation, {
+
+ _startTimer: function(){
+ if(!this._timer){
+ this._timer = d.connect(runner, "run", this, "_cycle");
+ ctr++;
+ }
+ if(!timer){
+ timer = setInterval(d.hitch(runner, "run"), this.rate);
+ }
+ },
+
+ _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;
+ // 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 = _mixin({ properties: {} }, args),
+ props = (fArgs.properties.opacity = {});
+
+ props.start = !("start" in fArgs) ?
+ function(){
+ return +d.style(fArgs.node, "opacity")||0;
+ } : 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(_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(_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();
+ }
+ }
+ };
+
+ PropLine.prototype.getValue = function(r){
+ var ret = {};
+ for(var p in this._properties){
+ var prop = this._properties[p],
+ 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" : 0);
+ }
+ }
+ 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 'units' 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. Defaults to 'px' if ommitted.
+ //
+ // example:
+ // Animate width, height, and padding over 2 seconds... the
+ // pedantic way:
+ // | dojo.animateProperty({ node: node, duration:2000,
+ // | properties: {
+ // | width: { start: '200', end: '400', units:"px" },
+ // | height: { start:'200', end: '400', units:"px" },
+ // | paddingTop: { start:'5', end:'50', units:"px" }
+ // | }
+ // | }).play();
+ // Note 'paddingTop' is used over 'padding-top'. Multi-name CSS properties
+ // are written using "mixed case", as the hyphen is illegal as an object key.
+ //
+ // 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(node){
+ // | // called when the animation finishes. The animation
+ // | // target is passed to this function
+ // | }
+ // | }).play(500); // delay playing half a second
+ //
+ // example:
+ // Like all `dojo.Animation`s, animateProperty returns a handle to the
+ // Animation instance, which fires the events common to Dojo FX. Use `dojo.connect`
+ // to access these events outside of the Animation definiton:
+ // | var anim = dojo.animateProperty({
+ // | node:"someId",
+ // | properties:{
+ // | width:400, height:500
+ // | }
+ // | });
+ // | dojo.connect(anim,"onEnd", function(){
+ // | console.log("animation ended");
+ // | });
+ // | // play the animation now:
+ // | anim.play();
+ //
+ // example:
+ // Each property can be a function whose return value is substituted along.
+ // Additionally, each measurement (eg: start, end) can be a function. The node
+ // reference is passed direcly to callbacks.
+ // | dojo.animateProperty({
+ // | node:"mine",
+ // | properties:{
+ // | height:function(node){
+ // | // shrink this node by 50%
+ // | return dojo.position(node).h / 2
+ // | },
+ // | width:{
+ // | start:function(node){ return 100; },
+ // | end:function(node){ return 200; }
+ // | }
+ // | }
+ // | }).play();
+ //
+
+ var n = 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];
+ if(d.isFunction(prop)){
+ prop = prop(n);
+ }
+ prop = pm[p] = _mixin({}, (d.isObject(prop) ? prop: { end: prop }));
+
+ if(d.isFunction(prop.start)){
+ prop.start = prop.start(n);
+ }
+ if(d.isFunction(prop.end)){
+ prop.end = prop.end(n);
+ }
+ 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") ? +v : (isColor ? v : parseFloat(v));
+ }
+ if(!("end" in prop)){
+ prop.end = getStyle(n, p);
+ }else if(!("start" in prop)){
+ prop.start = getStyle(n, p);
+ }
+
+ if(isColor){
+ prop.start = new d.Color(prop.start);
+ prop.end = new d.Color(prop.end);
+ }else{
+ prop.start = (p == "opacity") ? +prop.start : parseFloat(prop.start);
+ }
+ }
+ this.curve = new PropLine(pm);
+ });
+ d.connect(anim, "onAnimate", d.hitch(d, "style", anim.node));
+ 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 `dojo.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({ // dojo.Animation
+ node: node,
+ duration: duration || d.Animation.prototype.duration,
+ properties: properties,
+ easing: easing,
+ onEnd: onEnd
+ }).play(delay || 0);
+ };
})();
+
}
diff --git a/lib/dojo/_base/html.js b/lib/dojo/_base/html.js
index 050841531..be5fd2aaa 100644
--- a/lib/dojo/_base/html.js
+++ b/lib/dojo/_base/html.js
@@ -5,745 +5,1830 @@
*/
-if(!dojo._hasResource["dojo._base.html"]){
-dojo._hasResource["dojo._base.html"]=true;
+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){
+ document.execCommand("BackgroundImageCache", false, true);
+}catch(e){
+ // sane browsers don't have cache "issues"
}
-if(dojo.isIE||dojo.isOpera){
-dojo.byId=function(id,_1){
-if(typeof id!="string"){
-return id;
-}
-var _2=_1||dojo.doc,te=_2.getElementById(id);
-if(te&&(te.attributes.id.value==id||te.id==id)){
-return te;
+
+// =============================
+// DOM Functions
+// =============================
+
+/*=====
+dojo.byId = function(id, doc){
+ // summary:
+ // Returns DOM node with matching `id` attribute or `null`
+ // if not found. 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.
+ //
+ // example:
+ // Look up a node by ID:
+ // | var n = dojo.byId("foo");
+ //
+ // example:
+ // Check if a node exists, and use it.
+ // | var n = dojo.byId("bar");
+ // | if(n){ doStuff() ... }
+ //
+ // example:
+ // Allow string or DomNode references to be passed to a custom function:
+ // | var foo = function(nodeOrId){
+ // | nodeOrId = dojo.byId(nodeOrId);
+ // | // ... more stuff
+ // | }
+=====*/
+
+if(dojo.isIE || dojo.isOpera){
+ dojo.byId = function(id, doc){
+ if(typeof id != "string"){
+ return id;
+ }
+ var _d = doc || dojo.doc, 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 || te.id == id)){
+ return te;
+ }else{
+ var eles = _d.all[id];
+ if(!eles || eles.nodeName){
+ eles = [eles];
+ }
+ // if more than 1, choose first with the correct id
+ var i=0;
+ while((te=eles[i++])){
+ if((te.attributes && te.attributes.id && te.attributes.id.value == id)
+ || te.id == id){
+ return te;
+ }
+ }
+ }
+ };
}else{
-var _3=_2.all[id];
-if(!_3||_3.nodeName){
-_3=[_3];
-}
-var i=0;
-while((te=_3[i++])){
-if((te.attributes&&te.attributes.id&&te.attributes.id.value==id)||te.id==id){
-return te;
-}
-}
+ dojo.byId = function(id, doc){
+ // inline'd type check
+ return (typeof id == "string") ? (doc || dojo.doc).getElementById(id) : id; // DomNode
+ };
}
+/*=====
};
-}else{
-dojo.byId=function(id,_4){
-return (typeof id=="string")?(_4||dojo.doc).getElementById(id):id;
-};
-}
+=====*/
+
(function(){
-var d=dojo;
-var _5=d.byId;
-var _6=null,_7;
-d.addOnWindowUnload(function(){
-_6=null;
-});
-dojo._destroyElement=dojo.destroy=function(_8){
-_8=_5(_8);
-try{
-var _9=_8.ownerDocument;
-if(!_6||_7!=_9){
-_6=_9.createElement("div");
-_7=_9;
-}
-_6.appendChild(_8.parentNode?_8.parentNode.removeChild(_8):_8);
-_6.innerHTML="";
-}
-catch(e){
-}
-};
-dojo.isDescendant=function(_a,_b){
-try{
-_a=_5(_a);
-_b=_5(_b);
-while(_a){
-if(_a==_b){
-return true;
-}
-_a=_a.parentNode;
-}
-}
-catch(e){
-}
-return false;
-};
-dojo.setSelectable=function(_c,_d){
-_c=_5(_c);
-if(d.isMozilla){
-_c.style.MozUserSelect=_d?"":"none";
-}else{
-if(d.isKhtml||d.isWebKit){
-_c.style.KhtmlUserSelect=_d?"auto":"none";
-}else{
-if(d.isIE){
-var v=(_c.unselectable=_d?"":"on");
-d.query("*",_c).forEach("item.unselectable = '"+v+"'");
-}
-}
-}
-};
-var _e=function(_f,ref){
-var _10=ref.parentNode;
-if(_10){
-_10.insertBefore(_f,ref);
-}
-};
-var _11=function(_12,ref){
-var _13=ref.parentNode;
-if(_13){
-if(_13.lastChild==ref){
-_13.appendChild(_12);
-}else{
-_13.insertBefore(_12,ref.nextSibling);
-}
-}
-};
-dojo.place=function(_14,_15,_16){
-_15=_5(_15);
-if(typeof _14=="string"){
-_14=_14.charAt(0)=="<"?d._toDom(_14,_15.ownerDocument):_5(_14);
-}
-if(typeof _16=="number"){
-var cn=_15.childNodes;
-if(!cn.length||cn.length<=_16){
-_15.appendChild(_14);
-}else{
-_e(_14,cn[_16<0?0:_16]);
-}
-}else{
-switch(_16){
-case "before":
-_e(_14,_15);
-break;
-case "after":
-_11(_14,_15);
-break;
-case "replace":
-_15.parentNode.replaceChild(_14,_15);
-break;
-case "only":
-d.empty(_15);
-_15.appendChild(_14);
-break;
-case "first":
-if(_15.firstChild){
-_e(_14,_15.firstChild);
-break;
-}
-default:
-_15.appendChild(_14);
-}
-}
-return _14;
-};
-dojo.boxModel="content-box";
-if(d.isIE){
-d.boxModel=document.compatMode=="BackCompat"?"border-box":"content-box";
-}
-var gcs;
-if(d.isWebKit){
-gcs=function(_17){
-var s;
-if(_17.nodeType==1){
-var dv=_17.ownerDocument.defaultView;
-s=dv.getComputedStyle(_17,null);
-if(!s&&_17.style){
-_17.style.display="";
-s=dv.getComputedStyle(_17,null);
-}
-}
-return s||{};
-};
-}else{
-if(d.isIE){
-gcs=function(_18){
-return _18.nodeType==1?_18.currentStyle:{};
-};
-}else{
-gcs=function(_19){
-return _19.nodeType==1?_19.ownerDocument.defaultView.getComputedStyle(_19,null):{};
-};
-}
-}
-dojo.getComputedStyle=gcs;
-if(!d.isIE){
-d._toPixelValue=function(_1a,_1b){
-return parseFloat(_1b)||0;
-};
-}else{
-d._toPixelValue=function(_1c,_1d){
-if(!_1d){
-return 0;
-}
-if(_1d=="medium"){
-return 4;
-}
-if(_1d.slice&&_1d.slice(-2)=="px"){
-return parseFloat(_1d);
-}
-with(_1c){
-var _1e=style.left;
-var _1f=runtimeStyle.left;
-runtimeStyle.left=currentStyle.left;
-try{
-style.left=_1d;
-_1d=style.pixelLeft;
-}
-catch(e){
-_1d=0;
-}
-style.left=_1e;
-runtimeStyle.left=_1f;
-}
-return _1d;
-};
-}
-var px=d._toPixelValue;
-var _20="DXImageTransform.Microsoft.Alpha";
-var af=function(n,f){
-try{
-return n.filters.item(_20);
-}
-catch(e){
-return f?{}:null;
-}
-};
-dojo._getOpacity=d.isIE?function(_21){
-try{
-return af(_21).Opacity/100;
-}
-catch(e){
-return 1;
-}
-}:function(_22){
-return gcs(_22).opacity;
-};
-dojo._setOpacity=d.isIE?function(_23,_24){
-var ov=_24*100,_25=_24==1;
-_23.style.zoom=_25?"":1;
-if(!af(_23)){
-if(_25){
-return _24;
-}
-_23.style.filter+=" progid:"+_20+"(Opacity="+ov+")";
-}else{
-af(_23,1).Opacity=ov;
-}
-af(_23,1).Enabled=!_25;
-if(_23.nodeName.toLowerCase()=="tr"){
-d.query("> td",_23).forEach(function(i){
-d._setOpacity(i,_24);
-});
-}
-return _24;
-}:function(_26,_27){
-return _26.style.opacity=_27;
-};
-var _28={left:true,top:true};
-var _29=/margin|padding|width|height|max|min|offset/;
-var _2a=function(_2b,_2c,_2d){
-_2c=_2c.toLowerCase();
-if(d.isIE){
-if(_2d=="auto"){
-if(_2c=="height"){
-return _2b.offsetHeight;
-}
-if(_2c=="width"){
-return _2b.offsetWidth;
-}
-}
-if(_2c=="fontweight"){
-switch(_2d){
-case 700:
-return "bold";
-case 400:
-default:
-return "normal";
-}
-}
-}
-if(!(_2c in _28)){
-_28[_2c]=_29.test(_2c);
-}
-return _28[_2c]?px(_2b,_2d):_2d;
-};
-var _2e=d.isIE?"styleFloat":"cssFloat",_2f={"cssFloat":_2e,"styleFloat":_2e,"float":_2e};
-dojo.style=function(_30,_31,_32){
-var n=_5(_30),_33=arguments.length,op=(_31=="opacity");
-_31=_2f[_31]||_31;
-if(_33==3){
-return op?d._setOpacity(n,_32):n.style[_31]=_32;
-}
-if(_33==2&&op){
-return d._getOpacity(n);
-}
-var s=gcs(n);
-if(_33==2&&typeof _31!="string"){
-for(var x in _31){
-d.style(_30,x,_31[x]);
-}
-return s;
-}
-return (_33==1)?s:_2a(n,_31,s[_31]||n.style[_31]);
-};
-dojo._getPadExtents=function(n,_34){
-var s=_34||gcs(n),l=px(n,s.paddingLeft),t=px(n,s.paddingTop);
-return {l:l,t:t,w:l+px(n,s.paddingRight),h:t+px(n,s.paddingBottom)};
-};
-dojo._getBorderExtents=function(n,_35){
-var ne="none",s=_35||gcs(n),bl=(s.borderLeftStyle!=ne?px(n,s.borderLeftWidth):0),bt=(s.borderTopStyle!=ne?px(n,s.borderTopWidth):0);
-return {l:bl,t:bt,w:bl+(s.borderRightStyle!=ne?px(n,s.borderRightWidth):0),h:bt+(s.borderBottomStyle!=ne?px(n,s.borderBottomWidth):0)};
-};
-dojo._getPadBorderExtents=function(n,_36){
-var s=_36||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,_37){
-var s=_37||gcs(n),l=px(n,s.marginLeft),t=px(n,s.marginTop),r=px(n,s.marginRight),b=px(n,s.marginBottom);
-if(d.isWebKit&&(s.position!="absolute")){
-r=l;
-}
-return {l:l,t:t,w:l+r,h:t+b};
-};
-dojo._getMarginBox=function(_38,_39){
-var s=_39||gcs(_38),me=d._getMarginExtents(_38,s);
-var l=_38.offsetLeft-me.l,t=_38.offsetTop-me.t,p=_38.parentNode;
-if(d.isMoz){
-var sl=parseFloat(s.left),st=parseFloat(s.top);
-if(!isNaN(sl)&&!isNaN(st)){
-l=sl,t=st;
-}else{
-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||(d.isIE>7&&!d.isQuirks)){
-if(p){
-be=d._getBorderExtents(p);
-l-=be.l;
-t-=be.t;
-}
-}
-}
-return {l:l,t:t,w:_38.offsetWidth+me.w,h:_38.offsetHeight+me.h};
-};
-dojo._getContentBox=function(_3a,_3b){
-var s=_3b||gcs(_3a),pe=d._getPadExtents(_3a,s),be=d._getBorderExtents(_3a,s),w=_3a.clientWidth,h;
-if(!w){
-w=_3a.offsetWidth,h=_3a.offsetHeight;
-}else{
-h=_3a.clientHeight,be.w=be.h=0;
-}
-if(d.isOpera){
-pe.l+=be.l;
-pe.t+=be.t;
-}
-return {l:pe.l,t:pe.t,w:w-pe.w-be.w,h:h-pe.h-be.h};
-};
-dojo._getBorderBox=function(_3c,_3d){
-var s=_3d||gcs(_3c),pe=d._getPadExtents(_3c,s),cb=d._getContentBox(_3c,s);
-return {l:cb.l-pe.l,t:cb.t-pe.t,w:cb.w+pe.w,h:cb.h+pe.h};
-};
-dojo._setBox=function(_3e,l,t,w,h,u){
-u=u||"px";
-var s=_3e.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._isButtonTag=function(_3f){
-return _3f.tagName=="BUTTON"||_3f.tagName=="INPUT"&&(_3f.getAttribute("type")||"").toUpperCase()=="BUTTON";
-};
-dojo._usesBorderBox=function(_40){
-var n=_40.tagName;
-return d.boxModel=="border-box"||n=="TABLE"||d._isButtonTag(_40);
-};
-dojo._setContentSize=function(_41,_42,_43,_44){
-if(d._usesBorderBox(_41)){
-var pb=d._getPadBorderExtents(_41,_44);
-if(_42>=0){
-_42+=pb.w;
-}
-if(_43>=0){
-_43+=pb.h;
-}
-}
-d._setBox(_41,NaN,NaN,_42,_43);
-};
-dojo._setMarginBox=function(_45,_46,_47,_48,_49,_4a){
-var s=_4a||gcs(_45),bb=d._usesBorderBox(_45),pb=bb?_4b:d._getPadBorderExtents(_45,s);
-if(d.isWebKit){
-if(d._isButtonTag(_45)){
-var ns=_45.style;
-if(_48>=0&&!ns.width){
-ns.width="4px";
-}
-if(_49>=0&&!ns.height){
-ns.height="4px";
-}
-}
-}
-var mb=d._getMarginExtents(_45,s);
-if(_48>=0){
-_48=Math.max(_48-pb.w-mb.w,0);
-}
-if(_49>=0){
-_49=Math.max(_49-pb.h-mb.h,0);
-}
-d._setBox(_45,_46,_47,_48,_49);
-};
-var _4b={l:0,t:0,w:0,h:0};
-dojo.marginBox=function(_4c,box){
-var n=_5(_4c),s=gcs(n),b=box;
-return !b?d._getMarginBox(n,s):d._setMarginBox(n,b.l,b.t,b.w,b.h,s);
-};
-dojo.contentBox=function(_4d,box){
-var n=_5(_4d),s=gcs(n),b=box;
-return !b?d._getContentBox(n,s):d._setContentSize(n,b.w,b.h,s);
-};
-var _4e=function(_4f,_50){
-if(!(_4f=(_4f||0).parentNode)){
-return 0;
-}
-var val,_51=0,_52=d.body();
-while(_4f&&_4f.style){
-if(gcs(_4f).position=="fixed"){
-return 0;
-}
-val=_4f[_50];
-if(val){
-_51+=val-0;
-if(_4f==_52){
-break;
-}
-}
-_4f=_4f.parentNode;
-}
-return _51;
-};
-dojo._docScroll=function(){
-var n=d.global;
-return "pageXOffset" in n?{x:n.pageXOffset,y:n.pageYOffset}:(n=d.doc.documentElement,n.clientHeight?{x:d._fixIeBiDiScrollLeft(n.scrollLeft),y:n.scrollTop}:(n=d.body(),{x:n.scrollLeft||0,y:n.scrollTop||0}));
-};
-dojo._isBodyLtr=function(){
-return "_bodyLtr" in d?d._bodyLtr:d._bodyLtr=(d.body().dir||d.doc.documentElement.dir||"ltr").toLowerCase()=="ltr";
-};
-dojo._getIeDocumentElementOffset=function(){
-var de=d.doc.documentElement;
-if(d.isIE<8){
-var r=de.getBoundingClientRect();
-var l=r.left,t=r.top;
-if(d.isIE<7){
-l+=de.clientLeft;
-t+=de.clientTop;
-}
-return {x:l<0?0:l,y:t<0?0:t};
-}else{
-return {x:0,y:0};
-}
-};
-dojo._fixIeBiDiScrollLeft=function(_53){
-var dd=d.doc;
-if(d.isIE<8&&!d._isBodyLtr()){
-var de=d.isQuirks?dd.body:dd.documentElement;
-return _53+de.clientWidth-de.scrollWidth;
-}
-return _53;
-};
-dojo._abs=dojo.position=function(_54,_55){
-var db=d.body(),dh=db.parentNode,ret;
-_54=_5(_54);
-if(_54["getBoundingClientRect"]){
-ret=_54.getBoundingClientRect();
-ret={x:ret.left,y:ret.top,w:ret.right-ret.left,h:ret.bottom-ret.top};
-if(d.isIE){
-var _56=d._getIeDocumentElementOffset();
-ret.x-=_56.x+(d.isQuirks?db.clientLeft+db.offsetLeft:0);
-ret.y-=_56.y+(d.isQuirks?db.clientTop+db.offsetTop:0);
-}else{
-if(d.isFF==3){
-var cs=gcs(dh);
-ret.x-=px(dh,cs.marginLeft)+px(dh,cs.borderLeftWidth);
-ret.y-=px(dh,cs.marginTop)+px(dh,cs.borderTopWidth);
-}
-}
-}else{
-ret={x:0,y:0,w:_54.offsetWidth,h:_54.offsetHeight};
-if(_54["offsetParent"]){
-ret.x-=_4e(_54,"scrollLeft");
-ret.y-=_4e(_54,"scrollTop");
-var _57=_54;
-do{
-var n=_57.offsetLeft,t=_57.offsetTop;
-ret.x+=isNaN(n)?0:n;
-ret.y+=isNaN(t)?0:t;
-cs=gcs(_57);
-if(_57!=_54){
-if(d.isMoz){
-ret.x+=2*px(_57,cs.borderLeftWidth);
-ret.y+=2*px(_57,cs.borderTopWidth);
-}else{
-ret.x+=px(_57,cs.borderLeftWidth);
-ret.y+=px(_57,cs.borderTopWidth);
-}
-}
-if(d.isMoz&&cs.position=="static"){
-var _58=_57.parentNode;
-while(_58!=_57.offsetParent){
-var pcs=gcs(_58);
-if(pcs.position=="static"){
-ret.x+=px(_57,pcs.borderLeftWidth);
-ret.y+=px(_57,pcs.borderTopWidth);
-}
-_58=_58.parentNode;
-}
-}
-_57=_57.offsetParent;
-}while((_57!=dh)&&_57);
-}else{
-if(_54.x&&_54.y){
-ret.x+=isNaN(_54.x)?0:_54.x;
-ret.y+=isNaN(_54.y)?0:_54.y;
-}
-}
-}
-if(_55){
-var _59=d._docScroll();
-ret.x+=_59.x;
-ret.y+=_59.y;
-}
-return ret;
-};
-dojo.coords=function(_5a,_5b){
-var n=_5(_5a),s=gcs(n),mb=d._getMarginBox(n,s);
-var abs=d.position(n,_5b);
-mb.x=abs.x;
-mb.y=abs.y;
-return mb;
-};
-var _5c={"class":"className","for":"htmlFor",tabindex:"tabIndex",readonly:"readOnly",colspan:"colSpan",frameborder:"frameBorder",rowspan:"rowSpan",valuetype:"valueType"},_5d={classname:"class",htmlfor:"for",tabindex:"tabIndex",readonly:"readOnly"},_5e={innerHTML:1,className:1,htmlFor:d.isIE,value:1};
-var _5f=function(_60){
-return _5d[_60.toLowerCase()]||_60;
-};
-var _61=function(_62,_63){
-var _64=_62.getAttributeNode&&_62.getAttributeNode(_63);
-return _64&&_64.specified;
-};
-dojo.hasAttr=function(_65,_66){
-var lc=_66.toLowerCase();
-return _5e[_5c[lc]||_66]||_61(_5(_65),_5d[lc]||_66);
-};
-var _67={},_68=0,_69=dojo._scopeName+"attrid",_6a={col:1,colgroup:1,table:1,tbody:1,tfoot:1,thead:1,tr:1,title:1};
-dojo.attr=function(_6b,_6c,_6d){
-_6b=_5(_6b);
-var _6e=arguments.length,_6f;
-if(_6e==2&&typeof _6c!="string"){
-for(var x in _6c){
-d.attr(_6b,x,_6c[x]);
-}
-return _6b;
-}
-var lc=_6c.toLowerCase(),_70=_5c[lc]||_6c,_71=_5e[_70],_72=_5d[lc]||_6c;
-if(_6e==3){
-do{
-if(_70=="style"&&typeof _6d!="string"){
-d.style(_6b,_6d);
-break;
-}
-if(_70=="innerHTML"){
-if(d.isIE&&_6b.tagName.toLowerCase() in _6a){
-d.empty(_6b);
-_6b.appendChild(d._toDom(_6d,_6b.ownerDocument));
-}else{
-_6b[_70]=_6d;
-}
-break;
-}
-if(d.isFunction(_6d)){
-var _73=d.attr(_6b,_69);
-if(!_73){
-_73=_68++;
-d.attr(_6b,_69,_73);
-}
-if(!_67[_73]){
-_67[_73]={};
-}
-var h=_67[_73][_70];
-if(h){
-d.disconnect(h);
-}else{
-try{
-delete _6b[_70];
-}
-catch(e){
-}
-}
-_67[_73][_70]=d.connect(_6b,_70,_6d);
-break;
-}
-if(_71||typeof _6d=="boolean"){
-_6b[_70]=_6d;
-break;
-}
-_6b.setAttribute(_72,_6d);
-}while(false);
-return _6b;
-}
-_6d=_6b[_70];
-if(_71&&typeof _6d!="undefined"){
-return _6d;
-}
-if(_70!="href"&&(typeof _6d=="boolean"||d.isFunction(_6d))){
-return _6d;
-}
-return _61(_6b,_72)?_6b.getAttribute(_72):null;
-};
-dojo.removeAttr=function(_74,_75){
-_5(_74).removeAttribute(_5f(_75));
-};
-dojo.getNodeProp=function(_76,_77){
-_76=_5(_76);
-var lc=_77.toLowerCase(),_78=_5c[lc]||_77;
-if((_78 in _76)&&_78!="href"){
-return _76[_78];
-}
-var _79=_5d[lc]||_77;
-return _61(_76,_79)?_76.getAttribute(_79):null;
-};
-dojo.create=function(tag,_7a,_7b,pos){
-var doc=d.doc;
-if(_7b){
-_7b=_5(_7b);
-doc=_7b.ownerDocument;
-}
-if(typeof tag=="string"){
-tag=doc.createElement(tag);
-}
-if(_7a){
-d.attr(tag,_7a);
-}
-if(_7b){
-d.place(tag,_7b,pos);
-}
-return tag;
-};
-d.empty=d.isIE?function(_7c){
-_7c=_5(_7c);
-for(var c;c=_7c.lastChild;){
-d.destroy(c);
-}
-}:function(_7d){
-_5(_7d).innerHTML="";
-};
-var _7e={option:["select"],tbody:["table"],thead:["table"],tfoot:["table"],tr:["table","tbody"],td:["table","tbody","tr"],th:["table","thead","tr"],legend:["fieldset"],caption:["table"],colgroup:["table"],col:["table","colgroup"],li:["ul"]},_7f=/<\s*([\w\:]+)/,_80={},_81=0,_82="__"+d._scopeName+"ToDomId";
-for(var _83 in _7e){
-var tw=_7e[_83];
-tw.pre=_83=="option"?"<select multiple=\"multiple\">":"<"+tw.join("><")+">";
-tw.post="</"+tw.reverse().join("></")+">";
-}
-d._toDom=function(_84,doc){
-doc=doc||d.doc;
-var _85=doc[_82];
-if(!_85){
-doc[_82]=_85=++_81+"";
-_80[_85]=doc.createElement("div");
-}
-_84+="";
-var _86=_84.match(_7f),tag=_86?_86[1].toLowerCase():"",_87=_80[_85],_88,i,fc,df;
-if(_86&&_7e[tag]){
-_88=_7e[tag];
-_87.innerHTML=_88.pre+_84+_88.post;
-for(i=_88.length;i;--i){
-_87=_87.firstChild;
-}
-}else{
-_87.innerHTML=_84;
-}
-if(_87.childNodes.length==1){
-return _87.removeChild(_87.firstChild);
-}
-df=doc.createDocumentFragment();
-while(fc=_87.firstChild){
-df.appendChild(fc);
-}
-return df;
-};
-var _89="className";
-dojo.hasClass=function(_8a,_8b){
-return ((" "+_5(_8a)[_89]+" ").indexOf(" "+_8b+" ")>=0);
-};
-var _8c=/\s+/,a1=[""],_8d=function(s){
-if(typeof s=="string"||s instanceof String){
-if(s.indexOf(" ")<0){
-a1[0]=s;
-return a1;
-}else{
-return s.split(_8c);
-}
-}
-return s||"";
-};
-dojo.addClass=function(_8e,_8f){
-_8e=_5(_8e);
-_8f=_8d(_8f);
-var cls=_8e[_89],_90;
-cls=cls?" "+cls+" ":" ";
-_90=cls.length;
-for(var i=0,len=_8f.length,c;i<len;++i){
-c=_8f[i];
-if(c&&cls.indexOf(" "+c+" ")<0){
-cls+=c+" ";
-}
-}
-if(_90<cls.length){
-_8e[_89]=cls.substr(1,cls.length-2);
-}
-};
-dojo.removeClass=function(_91,_92){
-_91=_5(_91);
-var cls;
-if(_92!==undefined){
-_92=_8d(_92);
-cls=" "+_91[_89]+" ";
-for(var i=0,len=_92.length;i<len;++i){
-cls=cls.replace(" "+_92[i]+" "," ");
-}
-cls=d.trim(cls);
-}else{
-cls="";
-}
-if(_91[_89]!=cls){
-_91[_89]=cls;
-}
-};
-dojo.toggleClass=function(_93,_94,_95){
-if(_95===undefined){
-_95=!d.hasClass(_93,_94);
-}
-d[_95?"addClass":"removeClass"](_93,_94);
-};
+ var d = dojo;
+ var byId = d.byId;
+
+ var _destroyContainer = null,
+ _destroyDoc;
+ d.addOnWindowUnload(function(){
+ _destroyContainer = null; //prevent IE leak
+ });
+
+/*=====
+ dojo._destroyElement = function(node){
+ // summary:
+ // Existing alias for `dojo.destroy`. Deprecated, will be removed
+ // in 2.0
+ }
+=====*/
+ dojo._destroyElement = dojo.destroy = function(/*String|DomNode*/node){
+ // summary:
+ // Removes a node from its parent, clobbering it and all of its
+ // children.
+ //
+ // description:
+ // Removes a node from its parent, clobbering it and all of its
+ // children. Function only works with DomNodes, and returns nothing.
+ //
+ // node:
+ // A String ID or DomNode reference of the element to be destroyed
+ //
+ // example:
+ // Destroy a node byId:
+ // | dojo.destroy("someId");
+ //
+ // example:
+ // Destroy all nodes in a list by reference:
+ // | dojo.query(".someNode").forEach(dojo.destroy);
+
+ node = byId(node);
+ try{
+ var doc = node.ownerDocument;
+ // cannot use _destroyContainer.ownerDocument since this can throw an exception on IE
+ if(!_destroyContainer || _destroyDoc != doc){
+ _destroyContainer = doc.createElement("div");
+ _destroyDoc = doc;
+ }
+ _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: string id or node reference to test
+ // ancestor: string id or node reference of potential parent to test against
+ //
+ // example:
+ // Test is node id="bar" is a descendant of node id="foo"
+ // | if(dojo.isDescendant("bar", "foo")){ ... }
+ try{
+ node = byId(node);
+ ancestor = 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:
+ // state to put the node in. false indicates unselectable, true
+ // allows selection.
+ // example:
+ // Make the node id="bar" unselectable
+ // | dojo.setSelectable("bar");
+ // example:
+ // Make the node id="bar" selectable
+ // | dojo.setSelectable("bar", true);
+ node = byId(node);
+ if(d.isMozilla){
+ node.style.MozUserSelect = selectable ? "" : "none";
+ }else if(d.isKhtml || d.isWebKit){
+ node.style.KhtmlUserSelect = selectable ? "auto" : "none";
+ }else if(d.isIE){
+ var v = (node.unselectable = selectable ? "" : "on");
+ d.query("*", node).forEach("item.unselectable = '"+v+"'");
+ }
+ //FIXME: else? Opera?
+ };
+
+ var _insertBefore = function(/*DomNode*/node, /*DomNode*/ref){
+ var parent = ref.parentNode;
+ if(parent){
+ parent.insertBefore(node, ref);
+ }
+ };
+
+ var _insertAfter = function(/*DomNode*/node, /*DomNode*/ref){
+ // summary:
+ // Try to insert node after ref
+ var parent = ref.parentNode;
+ if(parent){
+ if(parent.lastChild == ref){
+ parent.appendChild(node);
+ }else{
+ parent.insertBefore(node, ref.nextSibling);
+ }
+ }
+ };
+
+ dojo.place = function(node, refNode, position){
+ // summary:
+ // Attempt to insert node into the DOM, choosing from various positioning options.
+ // Returns the first argument resolved to a DOM node.
+ //
+ // node: String|DomNode
+ // id or node reference, or HTML fragment starting with "<" to place relative to refNode
+ //
+ // refNode: String|DomNode
+ // id or node reference to use as basis for placement
+ //
+ // position: String|Number?
+ // 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
+ // | * replace
+ // | * only
+ // | * first
+ // | * last
+ // "first" and "last" indicate positions as children of refNode, "replace" replaces refNode,
+ // "only" replaces all children. position defaults to "last" if not specified
+ //
+ // returns: DomNode
+ // Returned values is the first argument resolved to a DOM node.
+ //
+ // .place() is also a method of `dojo.NodeList`, allowing `dojo.query` node lookups.
+ //
+ // example:
+ // Place a node by string id as the last child of another node by string id:
+ // | dojo.place("someNode", "anotherNode");
+ //
+ // example:
+ // Place a node by string id before another node by string id
+ // | dojo.place("someNode", "anotherNode", "before");
+ //
+ // example:
+ // Create a Node, and place it in the body element (last child):
+ // | dojo.place("<div></div>", dojo.body());
+ //
+ // example:
+ // Put a new LI as the first child of a list by id:
+ // | dojo.place("<li></li>", "someUl", "first");
+
+ refNode = byId(refNode);
+ if(typeof node == "string"){ // inline'd type check
+ node = node.charAt(0) == "<" ? d._toDom(node, refNode.ownerDocument) : byId(node);
+ }
+ if(typeof position == "number"){ // inline'd type check
+ var cn = refNode.childNodes;
+ if(!cn.length || cn.length <= position){
+ refNode.appendChild(node);
+ }else{
+ _insertBefore(node, cn[position < 0 ? 0 : position]);
+ }
+ }else{
+ switch(position){
+ case "before":
+ _insertBefore(node, refNode);
+ break;
+ case "after":
+ _insertAfter(node, refNode);
+ break;
+ case "replace":
+ refNode.parentNode.replaceChild(node, refNode);
+ break;
+ case "only":
+ d.empty(refNode);
+ refNode.appendChild(node);
+ break;
+ case "first":
+ if(refNode.firstChild){
+ _insertBefore(node, refNode.firstChild);
+ break;
+ }
+ // else fallthrough...
+ default: // aka: last
+ refNode.appendChild(node);
+ }
+ }
+ return node; // DomNode
+ }
+
+ // 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*/){
+ // client code may have to adjust if compatMode varies across iframes
+ d.boxModel = document.compatMode == "BackCompat" ? "border-box" : "content-box";
+ }
+
+ // =============================
+ // 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;
+ //
+ // example:
+ // Reusing the returned object, avoiding multiple lookups:
+ // | var cs = dojo.getComputedStyle(dojo.byId("someNode"));
+ // | var w = cs.width, h = cs.height;
+ return; // CSS2Properties
+ }
+=====*/
+
+ // Although we normally eschew argument validation at this
+ // level, here we test argument 'node' for (duck)type,
+ // by testing nodeType, ecause 'document' is the 'parentNode' of 'body'
+ // it is frequently sent to this function even
+ // though it is not Element.
+ var gcs;
+ if(d.isWebKit){
+ gcs = function(/*DomNode*/node){
+ var s;
+ if(node.nodeType == 1){
+ var dv = node.ownerDocument.defaultView;
+ 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){
+ // IE (as of 7) doesn't expose Element like sane browsers
+ return node.nodeType == 1 /* ELEMENT_NODE*/ ? node.currentStyle : {};
+ };
+ }else{
+ gcs = function(node){
+ return node.nodeType == 1 ?
+ node.ownerDocument.defaultView.getComputedStyle(node, null) : {};
+ };
+ }
+ dojo.getComputedStyle = gcs;
+
+ if(!d.isIE){
+ d._toPixelValue = function(element, value){
+ // style values can be floats, client code may want
+ // to round for integer pixels.
+ return parseFloat(value) || 0;
+ };
+ }else{
+ d._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.
+ // returns: Number between 0 and 1
+ return; // Number
+ }
+ =====*/
+
+ var astr = "DXImageTransform.Microsoft.Alpha";
+ var af = function(n, f){
+ try{
+ return n.filters.item(astr);
+ }catch(e){
+ return f ? {} : null;
+ }
+ };
+
+ dojo._getOpacity =
+ d.isIE ? function(node){
+ try{
+ return af(node).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.
+ // returns: Number between 0 and 1
+ return; // Number
+ }
+ =====*/
+
+ dojo._setOpacity =
+ d.isIE ? function(/*DomNode*/node, /*Number*/opacity){
+ var ov = opacity * 100, opaque = opacity == 1;
+ node.style.zoom = opaque ? "" : 1;
+
+ if(!af(node)){
+ if(opaque){
+ return opacity;
+ }
+ node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")";
+ }else{
+ af(node, 1).Opacity = ov;
+ }
+
+ // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so disable it altogether (bug #2661),
+ //but still update the opacity value so we can get a correct reading if it is read later.
+ af(node, 1).Enabled = !opaque;
+
+ if(node.nodeName.toLowerCase() == "tr"){
+ d.query("> td", node).forEach(function(i){
+ d._setOpacity(i, opacity);
+ });
+ }
+ 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(); // FIXME: should we really be doing string case conversion here? Should we cache it? Need to profile!
+ if(d.isIE){
+ if(value == "auto"){
+ if(type == "height"){ return node.offsetHeight; }
+ if(type == "width"){ return node.offsetWidth; }
+ }
+ if(type == "fontweight"){
+ switch(value){
+ case 700: return "bold";
+ case 400:
+ default: return "normal";
+ }
+ }
+ }
+ if(!(type in _pixelNamesCache)){
+ _pixelNamesCache[type] = _pixelRegExp.test(type);
+ }
+ return _pixelNamesCache[type] ? px(node, value) : value;
+ };
+
+ var _floatStyle = d.isIE ? "styleFloat" : "cssFloat",
+ _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.
+ // description:
+ // Getting the style value uses the computed style for the node, so the value
+ // will be a calculated value, not just the immediate node.style value.
+ // Also when getting values, use specific style names,
+ // like "borderBottomWidth" instead of "border" since compound values like
+ // "border" are not necessarily reflected as expected.
+ // If you want to get node dimensions, use `dojo.marginBox()`,
+ // `dojo.contentBox()` or `dojo.position()`.
+ // 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. When setting a pixel value,
+ // be sure to include "px" in the value. For instance, top: "200px".
+ // Otherwise, in some cases, some browsers will not apply the style.
+ // 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": "300px"
+ // | });
+ //
+ // 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 = 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 && typeof style != "string"){ // inline'd type check
+ for(var x in style){
+ d.style(node, x, style[x]);
+ }
+ return s;
+ }
+ return (args == 1) ? s : _toStyleValue(n, style, s[style] || n.style[style]); /* CSS2Properties||String||Number */
+ }
+
+ // =============================
+ // Box Functions
+ // =============================
+
+ dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+ // summary:
+ // Returns object with special values specifically useful for node
+ // fitting.
+ // description:
+ // Returns an object with `w`, `h`, `l`, `t` properties:
+ // | 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.
+ // description:
+ // * 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.
+ // description:
+ // * 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.isWebKit && (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, p = node.parentNode;
+ 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.
+ 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 || (d.isIE > 7 && !d.isQuirks)){
+ // On Opera and IE 8, offsetLeft/Top includes the parent's border
+ if(p){
+ 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:
+ // left offset from parent.
+ // t:
+ // top offset from parent.
+ // w:
+ // width in current box model.
+ // h:
+ // width in current box model.
+ // u:
+ // 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._isButtonTag = function(/*DomNode*/node) {
+ // summary:
+ // True if the node is BUTTON or INPUT.type="button".
+ return node.tagName == "BUTTON"
+ || node.tagName=="INPUT" && (node.getAttribute("type")||'').toUpperCase() == "BUTTON"; // boolean
+ }
+
+ 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.
+
+ // TABLE and BUTTON (and INPUT type=button) are always border-box by default.
+ // If you have assigned a different box to either one via CSS then
+ // box functions will break.
+
+ var n = node.tagName;
+ return d.boxModel=="border-box" || n=="TABLE" || d._isButtonTag(node); // 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.
+ bb = d._usesBorderBox(node),
+ pb = bb ? _nilExtents : d._getPadBorderExtents(node, s)
+ ;
+ if(d.isWebKit){
+ // on Safari (3.1.2), button nodes with no explicit size have a default margin
+ // setting an explicit size eliminates the margin.
+ // We have to swizzle the width to get correct margin reading.
+ if(d._isButtonTag(node)){
+ var ns = node.style;
+ if(widthPx >= 0 && !ns.width) { ns.width = "4px"; }
+ if(heightPx >= 0 && !ns.height) { ns.height = "4px"; }
+ }
+ }
+ var 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:
+ // Getter/setter for the margin-box of node.
+ // 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.
+ // example:
+ // Retrieve the marginbox of a passed node
+ // | var box = dojo.marginBox("someNodeId");
+ // | console.dir(box);
+ //
+ // example:
+ // Set a node's marginbox to the size of another node
+ // | var box = dojo.marginBox("someNodeId");
+ // | dojo.marginBox("someOtherNode", box);
+
+ var n = 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.
+ // While the getter will return top and left values, the
+ // setter only accepts setting the width and height.
+ // 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, but only w (width) and h (height) are supported.
+ // All properties are optional if passed.
+ var n = 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 n = d.global;
+ return "pageXOffset" in n? { x:n.pageXOffset, y:n.pageYOffset } :
+ (n=d.doc.documentElement, n.clientHeight? { x:d._fixIeBiDiScrollLeft(n.scrollLeft), y:n.scrollTop } :
+ (n=d.body(), { x:n.scrollLeft||0, y:n.scrollTop||0 }));
+ };
+
+ dojo._isBodyLtr = function(){
+ return "_bodyLtr" in d? d._bodyLtr :
+ d._bodyLtr = (d.body().dir || d.doc.documentElement.dir || "ltr").toLowerCase() == "ltr"; // Boolean
+ }
+
+ dojo._getIeDocumentElementOffset = function(){
+ // summary:
+ // returns the offset in x and y from the document body to the
+ // visual edge of the page
+ // description:
+ // 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; // only deal with HTML element here, _abs handles body/quirks
+
+ if(d.isIE < 8){
+ var r = de.getBoundingClientRect(); // works well for IE6+
+ //console.debug('rect left,top = ' + r.left+','+r.top + ', html client left/top = ' + de.clientLeft+','+de.clientTop + ', rtl = ' + (!d._isBodyLtr()) + ', quirks = ' + d.isQuirks);
+ var l = r.left,
+ t = r.top;
+ if(d.isIE < 7){
+ l += de.clientLeft; // scrollbar size in strict/RTL, or,
+ t += de.clientTop; // HTML border size in strict
+ }
+ return {
+ x: l < 0? 0 : l, // FRAME element border size can lead to inaccurate negative values
+ y: t < 0? 0 : t
+ };
+ }else{
+ return {
+ x: 0,
+ y: 0
+ };
+ }
+
+ };
+
+ dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){
+ // In RTL direction, scrollLeft should be a negative value, but IE < 8
+ // 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 < 8 && !d._isBodyLtr()){
+ var de = d.isQuirks ? dd.body : dd.documentElement;
+ return scrollLeft + de.clientWidth - de.scrollWidth; // Integer
+ }
+ return scrollLeft; // Integer
+ }
+
+ // FIXME: need a setter for coords or a moveTo!!
+ dojo._abs = dojo.position = function(/*DomNode*/node, /*Boolean?*/includeScroll){
+ // summary:
+ // Gets the position and size of the passed element relative to
+ // the viewport (if includeScroll==false), or relative to the
+ // document root (if includeScroll==true).
+ //
+ // description:
+ // Returns an object of the form:
+ // { x: 100, y: 300, w: 20, h: 15 }
+ // If includeScroll==true, the x and y values will include any
+ // document offsets that may affect the position relative to the
+ // viewport.
+ // Uses the border-box model (inclusive of border and padding but
+ // not margin). Does not act as a setter.
+
+ var db = d.body(), dh = db.parentNode, ret;
+ node = byId(node);
+ if(node["getBoundingClientRect"]){
+ // IE6+, FF3+, super-modern WebKit, and Opera 9.6+ all take this branch
+ ret = node.getBoundingClientRect();
+ ret = { x: ret.left, y: ret.top, w: ret.right - ret.left, h: ret.bottom - ret.top };
+ if(d.isIE){
+ // On IE there's a 2px offset that we need to adjust for, see _getIeDocumentElementOffset()
+ var offset = d._getIeDocumentElementOffset();
+
+ // fixes the position in IE, quirks mode
+ ret.x -= offset.x + (d.isQuirks ? db.clientLeft+db.offsetLeft : 0);
+ ret.y -= offset.y + (d.isQuirks ? db.clientTop+db.offsetTop : 0);
+ }else if(d.isFF == 3){
+ // In FF3 you have to subtract the document element margins.
+ // Fixed in FF3.5 though.
+ var cs = gcs(dh);
+ ret.x -= px(dh, cs.marginLeft) + px(dh, cs.borderLeftWidth);
+ ret.y -= px(dh, cs.marginTop) + px(dh, cs.borderTopWidth);
+ }
+ }else{
+ // FF2 and older WebKit
+ ret = {
+ x: 0,
+ y: 0,
+ w: node.offsetWidth,
+ h: node.offsetHeight
+ };
+ if(node["offsetParent"]){
+ ret.x -= _sumAncestorProperties(node, "scrollLeft");
+ ret.y -= _sumAncestorProperties(node, "scrollTop");
+
+ var curnode = node;
+ do{
+ var n = curnode.offsetLeft,
+ t = curnode.offsetTop;
+ ret.x += isNaN(n) ? 0 : n;
+ ret.y += isNaN(t) ? 0 : t;
+
+ cs = gcs(curnode);
+ if(curnode != node){
+ if(d.isMoz){
+ // tried left+right with differently sized left/right borders
+ // it really is 2xleft border in FF, not left+right, even in RTL!
+ ret.x += 2 * px(curnode,cs.borderLeftWidth);
+ ret.y += 2 * px(curnode,cs.borderTopWidth);
+ }else{
+ ret.x += px(curnode, cs.borderLeftWidth);
+ ret.y += px(curnode, cs.borderTopWidth);
+ }
+ }
+ // static children in a static div in FF2 are affected by the div's border as well
+ // but offsetParent will skip this div!
+ if(d.isMoz && cs.position=="static"){
+ var parent=curnode.parentNode;
+ while(parent!=curnode.offsetParent){
+ var pcs=gcs(parent);
+ if(pcs.position=="static"){
+ ret.x += px(curnode,pcs.borderLeftWidth);
+ ret.y += px(curnode,pcs.borderTopWidth);
+ }
+ parent=parent.parentNode;
+ }
+ }
+ curnode = curnode.offsetParent;
+ }while((curnode != dh) && 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.x += scroll.x;
+ ret.y += scroll.y;
+ }
+
+ return ret; // Object
+ }
+
+ dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){
+ // summary:
+ // Deprecated: Use position() for border-box x/y/w/h
+ // or marginBox() for margin-box w/h/l/t.
+ // Returns an object representing a node's size and position.
+ //
+ // description:
+ // Returns an object that measures margin-box (w)idth/(h)eight
+ // and absolute position x/y of the border-box. Also returned
+ // is computed (l)eft and (t)op values in pixels from the
+ // node's offsetParent as returned from marginBox().
+ // 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.position().
+ var n = byId(node), s = gcs(n), mb = d._getMarginBox(n, s);
+ var abs = d.position(n, includeScroll);
+ mb.x = abs.x;
+ mb.y = abs.y;
+ return mb;
+ }
+
+ // =============================
+ // Element attribute Functions
+ // =============================
+
+ // dojo.attr() should conform to http://www.w3.org/TR/DOM-Level-2-Core/
+
+ var _propNames = {
+ // properties renamed to avoid clashes with reserved words
+ "class": "className",
+ "for": "htmlFor",
+ // properties written as camelCase
+ tabindex: "tabIndex",
+ readonly: "readOnly",
+ colspan: "colSpan",
+ frameborder: "frameBorder",
+ rowspan: "rowSpan",
+ valuetype: "valueType"
+ },
+ _attrNames = {
+ // original attribute names
+ classname: "class",
+ htmlfor: "for",
+ // for IE
+ tabindex: "tabIndex",
+ readonly: "readOnly"
+ },
+ _forcePropNames = {
+ innerHTML: 1,
+ className: 1,
+ htmlFor: d.isIE,
+ value: 1
+ };
+
+ var _fixAttrName = function(/*String*/ name){
+ return _attrNames[name.toLowerCase()] || name;
+ };
+
+ var _hasAttr = function(node, name){
+ var attr = node.getAttributeNode && node.getAttributeNode(name);
+ return attr && attr.specified; // Boolean
+ };
+
+ // There is a difference in the presence of certain properties and their default values
+ // between browsers. For example, on IE "disabled" is present on all elements,
+ // but it is value is "false"; "tabIndex" of <div> returns 0 by default on IE, yet other browsers
+ // can return -1.
+
+ 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 lc = name.toLowerCase();
+ return _forcePropNames[_propNames[lc] || name] || _hasAttr(byId(node), _attrNames[lc] || name); // Boolean
+ }
+
+ var _evtHdlrMap = {}, _ctr = 0,
+ _attrId = dojo._scopeName + "attrid",
+ // the next dictionary lists elements with read-only innerHTML on IE
+ _roInnerHtml = {col: 1, colgroup: 1,
+ // frameset: 1, head: 1, html: 1, style: 1,
+ table: 1, tbody: 1, tfoot: 1, thead: 1, tr: 1, title: 1};
+
+ 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 argument 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 used as a setter, the DOM node
+ //
+ // example:
+ // | // get the current value of the "foo" attribute on a node
+ // | dojo.attr(dojo.byId("nodeId"), "foo");
+ // | // or we can just pass the id:
+ // | dojo.attr("nodeId", "foo");
+ //
+ // example:
+ // | // use attr() to set the tab index
+ // | dojo.attr("nodeId", "tabIndex", 3);
+ // |
+ //
+ // example:
+ // 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" });
+ // | }
+ // | });
+ //
+ // example:
+ // Style is s special case: Only set with an object hash of styles
+ // | dojo.attr("someNode",{
+ // | id:"bar",
+ // | style:{
+ // | width:"200px", height:"100px", color:"#000"
+ // | }
+ // | });
+ //
+ // example:
+ // Again, only set style as an object hash of styles:
+ // | var obj = { color:"#fff", backgroundColor:"#000" };
+ // | dojo.attr("someNode", "style", obj);
+ // |
+ // | // though shorter to use `dojo.style()` in this case:
+ // | dojo.style("someNode", obj);
+
+ node = byId(node);
+ var args = arguments.length, prop;
+ if(args == 2 && typeof name != "string"){ // inline'd type check
+ // the object form of setter: the 2nd argument is a dictionary
+ for(var x in name){
+ d.attr(node, x, name[x]);
+ }
+ return node; // DomNode
+ }
+ var lc = name.toLowerCase(),
+ propName = _propNames[lc] || name,
+ forceProp = _forcePropNames[propName],
+ attrName = _attrNames[lc] || name;
+ if(args == 3){
+ // setter
+ do{
+ if(propName == "style" && typeof value != "string"){ // inline'd type check
+ // special case: setting a style
+ d.style(node, value);
+ break;
+ }
+ if(propName == "innerHTML"){
+ // special case: assigning HTML
+ if(d.isIE && node.tagName.toLowerCase() in _roInnerHtml){
+ d.empty(node);
+ node.appendChild(d._toDom(value, node.ownerDocument));
+ }else{
+ node[propName] = value;
+ }
+ break;
+ }
+ if(d.isFunction(value)){
+ // special case: assigning an event handler
+ // 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][propName];
+ if(h){
+ d.disconnect(h);
+ }else{
+ try{
+ delete node[propName];
+ }catch(e){}
+ }
+ // ensure that event objects are normalized, etc.
+ _evtHdlrMap[attrId][propName] = d.connect(node, propName, value);
+ break;
+ }
+ if(forceProp || typeof value == "boolean"){
+ // special case: forcing assignment to the property
+ // special case: setting boolean to a property instead of attribute
+ node[propName] = value;
+ break;
+ }
+ // node's attribute
+ node.setAttribute(attrName, value);
+ }while(false);
+ return node; // DomNode
+ }
+ // getter
+ // should we access this attribute via a property or
+ // via getAttribute()?
+ value = node[propName];
+ if(forceProp && typeof value != "undefined"){
+ // node's property
+ return value; // Anything
+ }
+ if(propName != "href" && (typeof value == "boolean" || d.isFunction(value))){
+ // node's property
+ return value; // Anything
+ }
+ // node's attribute
+ // we need _hasAttr() here to guard against IE returning a default value
+ return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything
+ }
+
+ 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
+ byId(node).removeAttribute(_fixAttrName(name));
+ }
+
+ dojo.getNodeProp = function(/*DomNode|String*/ node, /*String*/ name){
+ // summary:
+ // Returns an effective value of a property or an attribute.
+ // node:
+ // id or reference to the element to remove the attribute from
+ // name:
+ // the name of the attribute
+ node = byId(node);
+ var lc = name.toLowerCase(),
+ propName = _propNames[lc] || name;
+ if((propName in node) && propName != "href"){
+ // node's property
+ return node[propName]; // Anything
+ }
+ // node's attribute
+ var attrName = _attrNames[lc] || name;
+ return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything
+ }
+
+ dojo.create = function(tag, attrs, refNode, pos){
+ // summary:
+ // Create an element, allowing for optional attribute decoration
+ // and placement.
+ //
+ // description:
+ // A DOM Element creation function. A shorthand method for creating a node or
+ // a fragment, and allowing for a convenient optional attribute setting step,
+ // as well as an optional DOM placement reference.
+ //|
+ // Attributes are set by passing the optional object through `dojo.attr`.
+ // See `dojo.attr` for noted caveats and nuances, and API if applicable.
+ //|
+ // Placement is done via `dojo.place`, assuming the new node to be the action
+ // node, passing along the optional reference node and position.
+ //
+ // tag: String|DomNode
+ // A string of the element to create (eg: "div", "a", "p", "li", "script", "br"),
+ // or an existing DOM node to process.
+ //
+ // attrs: Object
+ // An object-hash of attributes to set on the newly created node.
+ // Can be null, if you don't want to set any attributes/styles.
+ // See: `dojo.attr` for a description of available attributes.
+ //
+ // refNode: String?|DomNode?
+ // Optional reference node. Used by `dojo.place` to place the newly created
+ // node somewhere in the dom relative to refNode. Can be a DomNode reference
+ // or String ID of a node.
+ //
+ // pos: String?
+ // Optional positional reference. Defaults to "last" by way of `dojo.place`,
+ // though can be set to "first","after","before","last", "replace" or "only"
+ // to further control the placement of the new node relative to the refNode.
+ // 'refNode' is required if a 'pos' is specified.
+ //
+ // returns: DomNode
+ //
+ // example:
+ // Create a DIV:
+ // | var n = dojo.create("div");
+ //
+ // example:
+ // Create a DIV with content:
+ // | var n = dojo.create("div", { innerHTML:"<p>hi</p>" });
+ //
+ // example:
+ // Place a new DIV in the BODY, with no attributes set
+ // | var n = dojo.create("div", null, dojo.body());
+ //
+ // example:
+ // Create an UL, and populate it with LI's. Place the list as the first-child of a
+ // node with id="someId":
+ // | var ul = dojo.create("ul", null, "someId", "first");
+ // | var items = ["one", "two", "three", "four"];
+ // | dojo.forEach(items, function(data){
+ // | dojo.create("li", { innerHTML: data }, ul);
+ // | });
+ //
+ // example:
+ // Create an anchor, with an href. Place in BODY:
+ // | dojo.create("a", { href:"foo.html", title:"Goto FOO!" }, dojo.body());
+ //
+ // example:
+ // Create a `dojo.NodeList()` from a new element (for syntatic sugar):
+ // | dojo.query(dojo.create('div'))
+ // | .addClass("newDiv")
+ // | .onclick(function(e){ console.log('clicked', e.target) })
+ // | .place("#someNode"); // redundant, but cleaner.
+
+ var doc = d.doc;
+ if(refNode){
+ refNode = byId(refNode);
+ doc = refNode.ownerDocument;
+ }
+ if(typeof tag == "string"){ // inline'd type check
+ tag = doc.createElement(tag);
+ }
+ if(attrs){ d.attr(tag, attrs); }
+ if(refNode){ d.place(tag, refNode, pos); }
+ return tag; // DomNode
+ }
+
+ /*=====
+ dojo.empty = function(node){
+ // summary:
+ // safely removes all children of the node.
+ // node: DOMNode|String
+ // a reference to a DOM node or an id.
+ // example:
+ // Destroy node's children byId:
+ // | dojo.empty("someId");
+ //
+ // example:
+ // Destroy all nodes' children in a list by reference:
+ // | dojo.query(".someNode").forEach(dojo.empty);
+ }
+ =====*/
+
+ d.empty =
+ d.isIE ? function(node){
+ node = byId(node);
+ for(var c; c = node.lastChild;){ // intentional assignment
+ d.destroy(c);
+ }
+ } :
+ function(node){
+ byId(node).innerHTML = "";
+ };
+
+ /*=====
+ dojo._toDom = function(frag, doc){
+ // summary:
+ // instantiates an HTML fragment returning the corresponding DOM.
+ // frag: String
+ // the HTML fragment
+ // doc: DocumentNode?
+ // optional document to use when creating DOM nodes, defaults to
+ // dojo.doc if not specified.
+ // returns: DocumentFragment
+ //
+ // example:
+ // Create a table row:
+ // | var tr = dojo._toDom("<tr><td>First!</td></tr>");
+ }
+ =====*/
+
+ // support stuff for dojo._toDom
+ var tagWrap = {
+ option: ["select"],
+ tbody: ["table"],
+ thead: ["table"],
+ tfoot: ["table"],
+ tr: ["table", "tbody"],
+ td: ["table", "tbody", "tr"],
+ th: ["table", "thead", "tr"],
+ legend: ["fieldset"],
+ caption: ["table"],
+ colgroup: ["table"],
+ col: ["table", "colgroup"],
+ li: ["ul"]
+ },
+ reTag = /<\s*([\w\:]+)/,
+ masterNode = {}, masterNum = 0,
+ masterName = "__" + d._scopeName + "ToDomId";
+
+ // generate start/end tag strings to use
+ // for the injection for each special tag wrap case.
+ for(var param in tagWrap){
+ var tw = tagWrap[param];
+ tw.pre = param == "option" ? '<select multiple="multiple">' : "<" + tw.join("><") + ">";
+ tw.post = "</" + tw.reverse().join("></") + ">";
+ // the last line is destructive: it reverses the array,
+ // but we don't care at this point
+ }
+
+ d._toDom = function(frag, doc){
+ // summary:
+ // converts HTML string into DOM nodes.
+
+ doc = doc || d.doc;
+ var masterId = doc[masterName];
+ if(!masterId){
+ doc[masterName] = masterId = ++masterNum + "";
+ masterNode[masterId] = doc.createElement("div");
+ }
+
+ // make sure the frag is a string.
+ frag += "";
+
+ // find the starting tag, and get node wrapper
+ var match = frag.match(reTag),
+ tag = match ? match[1].toLowerCase() : "",
+ master = masterNode[masterId],
+ wrap, i, fc, df;
+ if(match && tagWrap[tag]){
+ wrap = tagWrap[tag];
+ master.innerHTML = wrap.pre + frag + wrap.post;
+ for(i = wrap.length; i; --i){
+ master = master.firstChild;
+ }
+ }else{
+ master.innerHTML = frag;
+ }
+
+ // one node shortcut => return the node itself
+ if(master.childNodes.length == 1){
+ return master.removeChild(master.firstChild); // DOMNode
+ }
+
+ // return multiple nodes as a document fragment
+ df = doc.createDocumentFragment();
+ while(fc = master.firstChild){ // intentional assignment
+ df.appendChild(fc);
+ }
+ return df; // DOMNode
+ }
+
+ // =============================
+ // (CSS) Class Functions
+ // =============================
+ var _className = "className";
+
+ 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.
+ //
+ // node:
+ // String ID or DomNode reference to check the class for.
+ //
+ // classStr:
+ // A string class name to look for.
+ //
+ // example:
+ // Do something if a node with id="someNode" has class="aSillyClassName" present
+ // | if(dojo.hasClass("someNode","aSillyClassName")){ ... }
+
+ return ((" "+ byId(node)[_className] +" ").indexOf(" " + classStr + " ") >= 0); // Boolean
+ };
+
+ var spaces = /\s+/, a1 = [""],
+ str2array = function(s){
+ if(typeof s == "string" || s instanceof String){
+ if(s.indexOf(" ") < 0){
+ a1[0] = s;
+ return a1;
+ }else{
+ return s.split(spaces);
+ }
+ }
+ // assumed to be an array
+ return s || "";
+ };
+
+ dojo.addClass = function(/*DomNode|String*/node, /*String|Array*/classStr){
+ // summary:
+ // Adds the specified classes to the end of the class list on the
+ // passed node. Will not re-apply duplicate classes.
+ //
+ // node:
+ // String ID or DomNode reference to add a class string too
+ //
+ // classStr:
+ // A String class name to add, or several space-separated class names,
+ // or an array of class names.
+ //
+ // example:
+ // Add a class to some node:
+ // | dojo.addClass("someNode", "anewClass");
+ //
+ // example:
+ // Add two classes at once:
+ // | dojo.addClass("someNode", "firstClass secondClass");
+ //
+ // example:
+ // Add two classes at once (using array):
+ // | dojo.addClass("someNode", ["firstClass", "secondClass"]);
+ //
+ // example:
+ // Available in `dojo.NodeList` for multiple additions
+ // | dojo.query("ul > li").addClass("firstLevel");
+
+ node = byId(node);
+ classStr = str2array(classStr);
+ var cls = node[_className], oldLen;
+ cls = cls ? " " + cls + " " : " ";
+ oldLen = cls.length;
+ for(var i = 0, len = classStr.length, c; i < len; ++i){
+ c = classStr[i];
+ if(c && cls.indexOf(" " + c + " ") < 0){
+ cls += c + " ";
+ }
+ }
+ if(oldLen < cls.length){
+ node[_className] = cls.substr(1, cls.length - 2);
+ }
+ };
+
+ dojo.removeClass = function(/*DomNode|String*/node, /*String|Array?*/classStr){
+ // summary:
+ // Removes the specified classes from node. No `dojo.hasClass`
+ // check is required.
+ //
+ // node:
+ // String ID or DomNode reference to remove the class from.
+ //
+ // classStr:
+ // An optional String class name to remove, or several space-separated
+ // class names, or an array of class names. If omitted, all class names
+ // will be deleted.
+ //
+ // example:
+ // Remove a class from some node:
+ // | dojo.removeClass("someNode", "firstClass");
+ //
+ // example:
+ // Remove two classes from some node:
+ // | dojo.removeClass("someNode", "firstClass secondClass");
+ //
+ // example:
+ // Remove two classes from some node (using array):
+ // | dojo.removeClass("someNode", ["firstClass", "secondClass"]);
+ //
+ // example:
+ // Remove all classes from some node:
+ // | dojo.removeClass("someNode");
+ //
+ // example:
+ // Available in `dojo.NodeList()` for multiple removal
+ // | dojo.query(".foo").removeClass("foo");
+
+ node = byId(node);
+ var cls;
+ if(classStr !== undefined){
+ classStr = str2array(classStr);
+ cls = " " + node[_className] + " ";
+ for(var i = 0, len = classStr.length; i < len; ++i){
+ cls = cls.replace(" " + classStr[i] + " ", " ");
+ }
+ cls = d.trim(cls);
+ }else{
+ cls = "";
+ }
+ if(node[_className] != cls){ node[_className] = cls; }
+ };
+
+ dojo.toggleClass = function(/*DomNode|String*/node, /*String|Array*/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.
+ //
+ // example:
+ // | dojo.toggleClass("someNode", "hovered");
+ //
+ // example:
+ // Forcefully add a class
+ // | dojo.toggleClass("someNode", "hovered", true);
+ //
+ // example:
+ // Available in `dojo.NodeList()` for multiple toggles
+ // | dojo.query(".toggleMe").toggleClass("toggleMe");
+
+ if(condition === undefined){
+ condition = !d.hasClass(node, classStr);
+ }
+ d[condition ? "addClass" : "removeClass"](node, classStr);
+ };
+
})();
+
}
diff --git a/lib/dojo/_base/json.js b/lib/dojo/_base/json.js
index 7d8c5af65..4d50400c9 100644
--- a/lib/dojo/_base/json.js
+++ b/lib/dojo/_base/json.js
@@ -5,77 +5,150 @@
*/
-if(!dojo._hasResource["dojo._base.json"]){
-dojo._hasResource["dojo._base.json"]=true;
+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(_1){
-return eval("("+_1+")");
-};
-dojo._escapeString=function(_2){
-return ("\""+_2.replace(/(["\\])/g,"\\$1")+"\"").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r");
-};
-dojo.toJsonIndentStr="\t";
-dojo.toJson=function(it,_3,_4){
-if(it===undefined){
-return "undefined";
-}
-var _5=typeof it;
-if(_5=="number"||_5=="boolean"){
-return it+"";
-}
-if(it===null){
-return "null";
-}
-if(dojo.isString(it)){
-return dojo._escapeString(it);
-}
-var _6=arguments.callee;
-var _7;
-_4=_4||"";
-var _8=_3?_4+dojo.toJsonIndentStr:"";
-var tf=it.__json__||it.json;
-if(dojo.isFunction(tf)){
-_7=tf.call(it);
-if(it!==_7){
-return _6(_7,_3,_8);
-}
-}
-if(it.nodeType&&it.cloneNode){
-throw new Error("Can't serialize DOM nodes");
-}
-var _9=_3?" ":"";
-var _a=_3?"\n":"";
-if(dojo.isArray(it)){
-var _b=dojo.map(it,function(_c){
-var _d=_6(_c,_3,_8);
-if(typeof _d!="string"){
-_d="undefined";
-}
-return _a+_8+_d;
-});
-return "["+_b.join(","+_9)+_a+_4+"]";
-}
-if(_5=="function"){
-return null;
-}
-var _e=[],_f;
-for(_f in it){
-var _10,val;
-if(typeof _f=="number"){
-_10="\""+_f+"\"";
-}else{
-if(typeof _f=="string"){
-_10=dojo._escapeString(_f);
-}else{
-continue;
-}
+
+dojo.fromJson = function(/*String*/ json){
+ // summary:
+ // Parses a [JSON](http://json.org) string to return a JavaScript object.
+ // description:
+ // Throws for invalid JSON strings, but it does not use a strict JSON parser. It
+ // delegates to eval(). The content passed to this method must therefore come
+ // from a trusted source.
+ // json:
+ // a string literal of a JSON item, for instance:
+ // `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
+
+ return eval("(" + json + ")"); // Object
}
-val=_6(it[_f],_3,_8);
-if(typeof val!="string"){
-continue;
+
+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
}
-_e.push(_a+_8+_10+":"+_9+val);
+
+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.
+ // example:
+ // simple serialization of a trivial object
+ // | var jsonStr = dojo.toJson({ howdy: "stranger!", isStrange: true });
+ // | doh.is('{"howdy":"stranger!","isStrange":true}', jsonStr);
+ // example:
+ // a custom serializer for an objects of a particular class:
+ // | dojo.declare("Furby", null, {
+ // | furbies: "are strange",
+ // | furbyCount: 10,
+ // | __json__: function(){
+ // | },
+ // | });
+
+ 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);
+ }
+ // 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 : "";
+ var tf = it.__json__||it.json;
+ if(dojo.isFunction(tf)){
+ newObj = tf.call(it);
+ if(it !== newObj){
+ return recurse(newObj, prettyPrint, nextIndent);
+ }
+ }
+ if(it.nodeType && it.cloneNode){ // isNode
+ // we can't seriailize DOM nodes as regular objects because they have cycles
+ // DOM nodes could be serialized with something like outerHTML, but
+ // that can be provided by users in the form of .json or .__json__ function.
+ throw new Error("Can't serialize DOM nodes");
+ }
+
+ 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.log(e);
+ }
+ // it's a function with no adapter, skip it
+ */
+ if(objtype == "function"){
+ return null; // null
+ }
+ // generic object code path
+ var output = [], key;
+ for(key in it){
+ var keyStr, val;
+ 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
}
-return "{"+_e.join(","+_9)+_a+_4+"}";
-};
+
}
diff --git a/lib/dojo/_base/lang.js b/lib/dojo/_base/lang.js
index e7721a352..0e9c7c2f9 100644
--- a/lib/dojo/_base/lang.js
+++ b/lib/dojo/_base/lang.js
@@ -5,144 +5,388 @@
*/
-if(!dojo._hasResource["dojo._base.lang"]){
-dojo._hasResource["dojo._base.lang"]=true;
+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");
+
(function(){
-var d=dojo,_1=Object.prototype.toString;
-dojo.isString=function(it){
-return (typeof it=="string"||it instanceof String);
-};
-dojo.isArray=function(it){
-return it&&(it instanceof Array||typeof it=="array");
-};
-dojo.isFunction=function(it){
-return _1.call(it)==="[object Function]";
-};
-dojo.isObject=function(it){
-return it!==undefined&&(it===null||typeof it=="object"||d.isArray(it)||d.isFunction(it));
-};
-dojo.isArrayLike=function(it){
-return it&&it!==undefined&&!d.isString(it)&&!d.isFunction(it)&&!(it.tagName&&it.tagName.toLowerCase()=="form")&&(d.isArray(it)||isFinite(it.length));
-};
-dojo.isAlien=function(it){
-return it&&!d.isFunction(it)&&/\{\s*\[native code\]\s*\}/.test(String(it));
-};
-dojo.extend=function(_2,_3){
-for(var i=1,l=arguments.length;i<l;i++){
-d._mixin(_2.prototype,arguments[i]);
-}
-return _2;
-};
-dojo._hitchArgs=function(_4,_5){
-var _6=d._toArray(arguments,2);
-var _7=d.isString(_5);
-return function(){
-var _8=d._toArray(arguments);
-var f=_7?(_4||d.global)[_5]:_5;
-return f&&f.apply(_4||this,_6.concat(_8));
-};
-};
-dojo.hitch=function(_9,_a){
-if(arguments.length>2){
-return d._hitchArgs.apply(d,arguments);
-}
-if(!_a){
-_a=_9;
-_9=null;
-}
-if(d.isString(_a)){
-_9=_9||d.global;
-if(!_9[_a]){
-throw (["dojo.hitch: scope[\"",_a,"\"] is null (scope=\"",_9,"\")"].join(""));
-}
-return function(){
-return _9[_a].apply(_9,arguments||[]);
-};
-}
-return !_9?_a:function(){
-return _a.apply(_9,arguments||[]);
-};
-};
-dojo.delegate=dojo._delegate=(function(){
-function _b(){
-};
-return function(_c,_d){
-_b.prototype=_c;
-var _e=new _b();
-_b.prototype=null;
-if(_d){
-d._mixin(_e,_d);
-}
-return _e;
-};
-})();
-var _f=function(obj,_10,_11){
-return (_11||[]).concat(Array.prototype.slice.call(obj,_10||0));
-};
-var _12=function(obj,_13,_14){
-var arr=_14||[];
-for(var x=_13||0;x<obj.length;x++){
-arr.push(obj[x]);
-}
-return arr;
-};
-dojo._toArray=d.isIE?function(obj){
-return ((obj.item)?_12:_f).apply(this,arguments);
-}:_f;
-dojo.partial=function(_15){
-var arr=[null];
-return d.hitch.apply(d,arr.concat(d._toArray(arguments)));
-};
-var _16=d._extraNames,_17=_16.length,_18={};
-dojo.clone=function(o){
-if(!o||typeof o!="object"||d.isFunction(o)){
-return o;
-}
-if(o.nodeType&&"cloneNode" in o){
-return o.cloneNode(true);
-}
-if(o instanceof Date){
-return new Date(o.getTime());
-}
-var r,i,l,s,_19;
-if(d.isArray(o)){
-r=[];
-for(i=0,l=o.length;i<l;++i){
-if(i in o){
-r.push(d.clone(o[i]));
-}
-}
-}else{
-r=o.constructor?new o.constructor():{};
-}
-for(_19 in o){
-s=o[_19];
-if(!(_19 in r)||(r[_19]!==s&&(!(_19 in _18)||_18[_19]!==s))){
-r[_19]=d.clone(s);
-}
-}
-if(_17){
-for(i=0;i<_17;++i){
-_19=_16[i];
-s=o[_19];
-if(!(_19 in r)||(r[_19]!==s&&(!(_19 in _18)||_18[_19]!==s))){
-r[_19]=s;
-}
-}
-}
-return r;
-};
-dojo.trim=String.prototype.trim?function(str){
-return str.trim();
-}:function(str){
-return str.replace(/^\s\s*/,"").replace(/\s\s*$/,"");
-};
-var _1a=/\{([^\}]+)\}/g;
-dojo.replace=function(_1b,map,_1c){
-return _1b.replace(_1c||_1a,d.isFunction(map)?map:function(_1d,k){
-return d.getObject(k,false,map);
-});
-};
+ var d = dojo, opts = Object.prototype.toString;
+
+ // Crockford (ish) functions
+
+ dojo.isString = function(/*anything*/ it){
+ // summary:
+ // Return true if it is a String
+ return (typeof it == "string" || it instanceof String); // Boolean
+ }
+
+ dojo.isArray = function(/*anything*/ it){
+ // summary:
+ // Return true if it is an Array.
+ // Does not work on Arrays created in other windows.
+ return it && (it instanceof Array || typeof it == "array"); // Boolean
+ }
+
+ dojo.isFunction = function(/*anything*/ it){
+ // summary:
+ // Return true if it is a Function
+ return opts.call(it) === "[object Function]";
+ };
+
+ 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" || d.isArray(it) || d.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().
+ // returns:
+ // If it walks like a duck and quacks like a duck, return `true`
+ return it && it !== undefined && // Boolean
+ // 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));
+ }
+
+ 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 && !d.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
+ }
+
+ dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
+ // summary:
+ // Adds all properties and methods of props to constructor's
+ // prototype, making them available to all instances created with
+ // constructor.
+ for(var i=1, l=arguments.length; i<l; i++){
+ d._mixin(constructor.prototype, arguments[i]);
+ }
+ return constructor; // Object
+ }
+
+ dojo._hitchArgs = function(scope, method /*,...*/){
+ var pre = d._toArray(arguments, 2);
+ var named = d.isString(method);
+ return function(){
+ // arrayify arguments
+ var args = d._toArray(arguments);
+ // locate our method
+ var f = named ? (scope||d.global)[method] : method;
+ // invoke with collected args
+ return f && f.apply(scope || this, pre.concat(args)); // mixed
+ } // Function
+ }
+
+ dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){
+ // summary:
+ // Returns a function that will only ever execute in the a given scope.
+ // This allows for easy use of object member functions
+ // in callbacks and other places in which the "this" keyword may
+ // otherwise not reference the expected scope.
+ // Any number of default positional arguments may be passed as parameters
+ // beyond "method".
+ // Each of these values will be used to "placehold" (similar to curry)
+ // for the hitched function.
+ // scope:
+ // The scope to use when method executes. If method is a string,
+ // scope is also the object containing method.
+ // method:
+ // A function to be hitched to scope, or the name of the method in
+ // scope to be hitched.
+ // example:
+ // | dojo.hitch(foo, "bar")();
+ // runs foo.bar() in the scope of foo
+ // example:
+ // | dojo.hitch(foo, myFunction);
+ // returns a function that runs myFunction in the scope of foo
+ // example:
+ // Expansion on the default positional arguments passed along from
+ // hitch. Passed args are mixed first, additional args after.
+ // | var foo = { bar: function(a, b, c){ console.log(a, b, c); } };
+ // | var fn = dojo.hitch(foo, "bar", 1, 2);
+ // | fn(3); // logs "1, 2, 3"
+ // example:
+ // | var foo = { bar: 2 };
+ // | dojo.hitch(foo, function(){ this.bar = 10; })();
+ // execute an anonymous function in scope of foo
+
+ if(arguments.length > 2){
+ return d._hitchArgs.apply(d, arguments); // Function
+ }
+ if(!method){
+ method = scope;
+ scope = null;
+ }
+ if(d.isString(method)){
+ scope = scope || d.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(){
+ // boodman/crockford delegation w/ cornford optimization
+ function TMP(){}
+ return function(obj, props){
+ TMP.prototype = obj;
+ var tmp = new TMP();
+ TMP.prototype = null;
+ if(props){
+ d._mixin(tmp, props);
+ }
+ return tmp; // Object
+ }
+ })();
+
+ /*=====
+ dojo._toArray = function(obj, offset, startWith){
+ // summary:
+ // Converts an array-like object (i.e. arguments, DOMCollection) to an
+ // array. Returns a new Array with the elements of obj.
+ // obj: Object
+ // the object to "arrayify". We expect the object to have, at a
+ // minimum, a length property which corresponds to integer-indexed
+ // properties.
+ // offset: Number?
+ // the location in obj to start iterating from. Defaults to 0.
+ // Optional.
+ // startWith: Array?
+ // 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 efficient = function(obj, offset, startWith){
+ return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0));
+ };
+
+ var slow = function(obj, offset, startWith){
+ var arr = startWith||[];
+ for(var x = offset || 0; x < obj.length; x++){
+ arr.push(obj[x]);
+ }
+ return arr;
+ };
+
+ dojo._toArray =
+ d.isIE ? function(obj){
+ return ((obj.item) ? slow : efficient).apply(this, arguments);
+ } :
+ efficient;
+
+ 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 d.hitch.apply(d, arr.concat(d._toArray(arguments))); // Function
+ }
+
+ var extraNames = d._extraNames, extraLen = extraNames.length, empty = {};
+
+ dojo.clone = function(/*anything*/ o){
+ // summary:
+ // Clones objects (including DOM nodes) and all children.
+ // Warning: do not clone cyclic structures.
+ if(!o || typeof o != "object" || d.isFunction(o)){
+ // null, undefined, any non-object, or function
+ return o; // anything
+ }
+ if(o.nodeType && "cloneNode" in o){
+ // DOM Node
+ return o.cloneNode(true); // Node
+ }
+ if(o instanceof Date){
+ // Date
+ return new Date(o.getTime()); // Date
+ }
+ var r, i, l, s, name;
+ if(d.isArray(o)){
+ // array
+ r = [];
+ for(i = 0, l = o.length; i < l; ++i){
+ if(i in o){
+ r.push(d.clone(o[i]));
+ }
+ }
+// we don't clone functions for performance reasons
+// }else if(d.isFunction(o)){
+// // function
+// r = function(){ return o.apply(this, arguments); };
+ }else{
+ // generic objects
+ r = o.constructor ? new o.constructor() : {};
+ }
+ for(name in o){
+ // the "tobj" condition avoid copying properties in "source"
+ // inherited from Object.prototype. For example, if target has a custom
+ // toString() method, don't overwrite it with the toString() method
+ // that source inherited from Object.prototype
+ s = o[name];
+ if(!(name in r) || (r[name] !== s && (!(name in empty) || empty[name] !== s))){
+ r[name] = d.clone(s);
+ }
+ }
+ // IE doesn't recognize some custom functions in for..in
+ if(extraLen){
+ for(i = 0; i < extraLen; ++i){
+ name = extraNames[i];
+ s = o[name];
+ if(!(name in r) || (r[name] !== s && (!(name in empty) || empty[name] !== s))){
+ r[name] = s; // functions only, we don't clone them
+ }
+ }
+ }
+ return r; // Object
+ }
+
+ /*=====
+ dojo.trim = function(str){
+ // summary:
+ // Trims whitespace from both sides of the string
+ // str: String
+ // String to be trimmed
+ // returns: String
+ // Returns the trimmed 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)
+ // Uses String.prototype.trim instead, if available.
+ // The fastest but longest version of this function is located at
+ // dojo.string.trim()
+ return ""; // String
+ }
+ =====*/
+
+ dojo.trim = String.prototype.trim ?
+ function(str){ return str.trim(); } :
+ function(str){ return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); };
+
+ /*=====
+ dojo.replace = function(tmpl, map, pattern){
+ // summary:
+ // Performs parameterized substitutions on a string. Throws an
+ // exception if any parameter is unmatched.
+ // tmpl: String
+ // String to be used as a template.
+ // map: Object|Function
+ // If an object, it is used as a dictionary to look up substitutions.
+ // If a function, it is called for every substitution with following
+ // parameters: a whole match, a name, an offset, and the whole template
+ // string (see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/String/replace
+ // for more details).
+ // pattern: RegEx?
+ // Optional regular expression objects that overrides the default pattern.
+ // Must be global and match one item. The default is: /\{([^\}]+)\}/g,
+ // which matches patterns like that: "{xxx}", where "xxx" is any sequence
+ // of characters, which doesn't include "}".
+ // returns: String
+ // Returns the substituted string.
+ // example:
+ // | // uses a dictionary for substitutions:
+ // | dojo.replace("Hello, {name.first} {name.last} AKA {nick}!",
+ // | {
+ // | nick: "Bob",
+ // | name: {
+ // | first: "Robert",
+ // | middle: "X",
+ // | last: "Cringely"
+ // | }
+ // | });
+ // | // returns: Hello, Robert Cringely AKA Bob!
+ // example:
+ // | // uses an array for substitutions:
+ // | dojo.replace("Hello, {0} {2}!",
+ // | ["Robert", "X", "Cringely"]);
+ // | // returns: Hello, Robert Cringely!
+ // example:
+ // | // uses a function for substitutions:
+ // | function sum(a){
+ // | var t = 0;
+ // | dojo.forEach(a, function(x){ t += x; });
+ // | return t;
+ // | }
+ // | dojo.replace(
+ // | "{count} payments averaging {avg} USD per payment.",
+ // | dojo.hitch(
+ // | { payments: [11, 16, 12] },
+ // | function(_, key){
+ // | switch(key){
+ // | case "count": return this.payments.length;
+ // | case "min": return Math.min.apply(Math, this.payments);
+ // | case "max": return Math.max.apply(Math, this.payments);
+ // | case "sum": return sum(this.payments);
+ // | case "avg": return sum(this.payments) / this.payments.length;
+ // | }
+ // | }
+ // | )
+ // | );
+ // | // prints: 3 payments averaging 13 USD per payment.
+ // example:
+ // | // uses an alternative PHP-like pattern for substitutions:
+ // | dojo.replace("Hello, ${0} ${2}!",
+ // | ["Robert", "X", "Cringely"], /\$\{([^\}]+)\}/g);
+ // | // returns: Hello, Robert Cringely!
+ return ""; // String
+ }
+ =====*/
+
+ var _pattern = /\{([^\}]+)\}/g;
+ dojo.replace = function(tmpl, map, pattern){
+ return tmpl.replace(pattern || _pattern, d.isFunction(map) ?
+ map : function(_, k){ return d.getObject(k, false, map); });
+ };
})();
+
}
diff --git a/lib/dojo/_base/query-sizzle.js b/lib/dojo/_base/query-sizzle.js
index ac26c1816..5d160ec55 100644
--- a/lib/dojo/_base/query-sizzle.js
+++ b/lib/dojo/_base/query-sizzle.js
@@ -5,624 +5,865 @@
*/
-if(!dojo._hasResource["dojo._base.query"]){
-dojo._hasResource["dojo._base.query"]=true;
-if(typeof dojo!="undefined"){
-dojo.provide("dojo._base.query");
-dojo.require("dojo._base.NodeList");
-dojo.query=function(_1,_2,_3){
-_3=_3||dojo.NodeList;
-if(!_1){
-return new _3();
-}
-if(_1.constructor==_3){
-return _1;
-}
-if(!dojo.isString(_1)){
-return new _3(_1);
-}
-if(dojo.isString(_2)){
-_2=dojo.byId(_2);
-if(!_2){
-return new _3();
-}
-}
-return dojo.Sizzle(_1,_2,new _3());
-};
-dojo._filterQueryResult=function(_4,_5){
-return dojo.Sizzle.filter(_5,_4);
-};
-}
-(function(ns){
-var _6=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|[^[\]]+)+\]|\\.|[^ >+~,(\[]+)+|[>+~])(\s*,\s*)?/g,_7=0,_8=Object.prototype.toString;
-var _9=function(_a,_b,_c,_d){
-_c=_c||[];
-_b=_b||document;
-if(_b.nodeType!==1&&_b.nodeType!==9){
-return [];
-}
-if(!_a||typeof _a!=="string"){
-return _c;
-}
-var _e=[],m,_f,_10,_11,_12,_13,_14=true;
-_6.lastIndex=0;
-while((m=_6.exec(_a))!==null){
-_e.push(m[1]);
-if(m[2]){
-_13=RegExp.rightContext;
-break;
-}
-}
-if(_e.length>1&&_15.match.POS.exec(_a)){
-if(_e.length===2&&_15.relative[_e[0]]){
-var _16="",_17;
-while((_17=_15.match.POS.exec(_a))){
-_16+=_17[0];
-_a=_a.replace(_15.match.POS,"");
-}
-_f=_9.filter(_16,_9(_a,_b));
-}else{
-_f=_15.relative[_e[0]]?[_b]:_9(_e.shift(),_b);
-while(_e.length){
-var _18=[];
-_a=_e.shift();
-if(_15.relative[_a]){
-_a+=_e.shift();
-}
-for(var i=0,l=_f.length;i<l;i++){
-_9(_a,_f[i],_18);
-}
-_f=_18;
-}
-}
-}else{
-var ret=_d?{expr:_e.pop(),set:_19(_d)}:_9.find(_e.pop(),_e.length===1&&_b.parentNode?_b.parentNode:_b);
-_f=_9.filter(ret.expr,ret.set);
-if(_e.length>0){
-_10=_19(_f);
-}else{
-_14=false;
-}
-while(_e.length){
-var cur=_e.pop(),pop=cur;
-if(!_15.relative[cur]){
-cur="";
-}else{
-pop=_e.pop();
-}
-if(pop==null){
-pop=_b;
-}
-_15.relative[cur](_10,pop);
-}
-}
-if(!_10){
-_10=_f;
-}
-if(!_10){
-throw "Syntax error, unrecognized expression: "+(cur||_a);
-}
-if(_8.call(_10)==="[object Array]"){
-if(!_14){
-_c.push.apply(_c,_10);
-}else{
-if(_b.nodeType===1){
-for(var i=0;_10[i]!=null;i++){
-if(_10[i]&&(_10[i]===true||_10[i].nodeType===1&&_1a(_b,_10[i]))){
-_c.push(_f[i]);
-}
-}
-}else{
-for(var i=0;_10[i]!=null;i++){
-if(_10[i]&&_10[i].nodeType===1){
-_c.push(_f[i]);
-}
-}
-}
-}
-}else{
-_19(_10,_c);
-}
-if(_13){
-_9(_13,_b,_c,_d);
+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;
+/*!
+ * Sizzle CSS Selector Engine - v0.9
+ * Copyright 2009, John Resig
+ * Redistributed with the Dojo Toolkit under the terms of the New BSD license.
+ * More information: http://sizzlejs.com/
+ *
+ * This version from github, dated 1/23/2009, commit: e374a73bbffc12ec3b5f252e7f76e593c508dfa5
+ * Modified for dojo loader, and to fit into dojo namespace. This was done by passing
+ * dojo object to anonymous function, then assigning Sizzle to dojo.Sizzle instead of window.Sizzle.
+ * Then an alias for dojo.query and dojo._filterQueryResult(). dojo.psuedos is not mapped.
+ * Finally, dojo.provide/require added.
+ */
+
+//This file gets copied to dojo/_base/query.js, so set the provide accordingly.
+if(typeof dojo != "undefined"){
+ dojo.provide("dojo._base.query");
+ dojo.require("dojo._base.NodeList");
+
+ //Start Dojo mappings.
+ dojo.query = function(/*String*/ query, /*String|DOMNode?*/ root, /*Function?*/listCtor){
+ listCtor = listCtor || dojo.NodeList;
+
+ if(!query){
+ return new listCtor();
+ }
+
+ if(query.constructor == listCtor){
+ return query;
+ }
+ if(!dojo.isString(query)){
+ return new listCtor(query); // dojo.NodeList
+ }
+ if(dojo.isString(root)){
+ root = dojo.byId(root);
+ if(!root){ return new listCtor(); }
+ }
+
+ return dojo.Sizzle(query, root, new listCtor());
+ }
+
+ dojo._filterQueryResult = function(nodeList, simpleFilter){
+ return dojo.Sizzle.filter(simpleFilter, nodeList);
+ }
}
-return _c;
+
+//Main Sizzle code follows...
+//ns argument, added for dojo, used at the end of the file.
+;(function(ns){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|[^[\]]+)+\]|\\.|[^ >+~,(\[]+)+|[>+~])(\s*,\s*)?/g,
+ done = 0,
+ toString = Object.prototype.toString;
+
+var Sizzle = function(selector, context, results, seed) {
+ results = results || [];
+ context = context || document;
+
+ if ( context.nodeType !== 1 && context.nodeType !== 9 )
+ return [];
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ var parts = [], m, set, checkSet, check, mode, extra, prune = true;
+
+ // Reset the position of the chunker regexp (start from head)
+ chunker.lastIndex = 0;
+
+ while ( (m = chunker.exec(selector)) !== null ) {
+ parts.push( m[1] );
+
+ if ( m[2] ) {
+ extra = RegExp.rightContext;
+ break;
+ }
+ }
+
+ if ( parts.length > 1 && Expr.match.POS.exec( selector ) ) {
+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+ var later = "", match;
+
+ // Position selectors must be done after the filter
+ while ( (match = Expr.match.POS.exec( selector )) ) {
+ later += match[0];
+ selector = selector.replace( Expr.match.POS, "" );
+ }
+
+ set = Sizzle.filter( later, Sizzle( selector, context ) );
+ } else {
+ set = Expr.relative[ parts[0] ] ?
+ [ context ] :
+ Sizzle( parts.shift(), context );
+
+ while ( parts.length ) {
+ var tmpSet = [];
+
+ selector = parts.shift();
+ if ( Expr.relative[ selector ] )
+ selector += parts.shift();
+
+ for ( var i = 0, l = set.length; i < l; i++ ) {
+ Sizzle( selector, set[i], tmpSet );
+ }
+
+ set = tmpSet;
+ }
+ }
+ } else {
+ var ret = seed ?
+ { expr: parts.pop(), set: makeArray(seed) } :
+ Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context );
+ set = Sizzle.filter( ret.expr, ret.set );
+
+ if ( parts.length > 0 ) {
+ checkSet = makeArray(set);
+ } else {
+ prune = false;
+ }
+
+ while ( parts.length ) {
+ var cur = parts.pop(), pop = cur;
+
+ if ( !Expr.relative[ cur ] ) {
+ cur = "";
+ } else {
+ pop = parts.pop();
+ }
+
+ if ( pop == null ) {
+ pop = context;
+ }
+
+ Expr.relative[ cur ]( checkSet, pop );
+ }
+ }
+
+ if ( !checkSet ) {
+ checkSet = set;
+ }
+
+ if ( !checkSet ) {
+ throw "Syntax error, unrecognized expression: " + (cur || selector);
+ }
+
+ if ( toString.call(checkSet) === "[object Array]" ) {
+ if ( !prune ) {
+ results.push.apply( results, checkSet );
+ } else if ( context.nodeType === 1 ) {
+ for ( var i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
+ results.push( set[i] );
+ }
+ }
+ } else {
+ for ( var i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+ results.push( set[i] );
+ }
+ }
+ }
+ } else {
+ makeArray( checkSet, results );
+ }
+
+ if ( extra ) {
+ Sizzle( extra, context, results, seed );
+ }
+
+ return results;
};
-_9.matches=function(_1b,set){
-return _9(_1b,null,null,set);
+
+Sizzle.matches = function(expr, set){
+ return Sizzle(expr, null, null, set);
};
-_9.find=function(_1c,_1d){
-var set,_1e;
-if(!_1c){
-return [];
-}
-for(var i=0,l=_15.order.length;i<l;i++){
-var _1f=_15.order[i],_1e;
-if((_1e=_15.match[_1f].exec(_1c))){
-var _20=RegExp.leftContext;
-if(_20.substr(_20.length-1)!=="\\"){
-_1e[1]=(_1e[1]||"").replace(/\\/g,"");
-set=_15.find[_1f](_1e,_1d);
-if(set!=null){
-_1c=_1c.replace(_15.match[_1f],"");
-break;
-}
-}
-}
-}
-if(!set){
-set=_1d.getElementsByTagName("*");
-}
-return {set:set,expr:_1c};
+
+Sizzle.find = function(expr, context){
+ var set, match;
+
+ if ( !expr ) {
+ return [];
+ }
+
+ for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+ var type = Expr.order[i], match;
+
+ if ( (match = Expr.match[ type ].exec( expr )) ) {
+ var left = RegExp.leftContext;
+
+ if ( left.substr( left.length - 1 ) !== "\\" ) {
+ match[1] = (match[1] || "").replace(/\\/g, "");
+ set = Expr.find[ type ]( match, context );
+ if ( set != null ) {
+ expr = expr.replace( Expr.match[ type ], "" );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !set ) {
+ set = context.getElementsByTagName("*");
+ }
+
+ return {set: set, expr: expr};
};
-_9.filter=function(_21,set,_22,not){
-var old=_21,_23=[],_24=set,_25,_26;
-while(_21&&set.length){
-for(var _27 in _15.filter){
-if((_25=_15.match[_27].exec(_21))!=null){
-var _28=_15.filter[_27],_29=null,_2a=0,_2b,_2c;
-_26=false;
-if(_24==_23){
-_23=[];
-}
-if(_15.preFilter[_27]){
-_25=_15.preFilter[_27](_25,_24,_22,_23,not);
-if(!_25){
-_26=_2b=true;
-}else{
-if(_25[0]===true){
-_29=[];
-var _2d=null,_2e;
-for(var i=0;(_2e=_24[i])!==undefined;i++){
-if(_2e&&_2d!==_2e){
-_29.push(_2e);
-_2d=_2e;
-}
-}
-}
-}
-}
-if(_25){
-for(var i=0;(_2c=_24[i])!==undefined;i++){
-if(_2c){
-if(_29&&_2c!=_29[_2a]){
-_2a++;
-}
-_2b=_28(_2c,_25,_2a,_29);
-var _2f=not^!!_2b;
-if(_22&&_2b!=null){
-if(_2f){
-_26=true;
-}else{
-_24[i]=false;
-}
-}else{
-if(_2f){
-_23.push(_2c);
-_26=true;
-}
-}
-}
-}
-}
-if(_2b!==undefined){
-if(!_22){
-_24=_23;
-}
-_21=_21.replace(_15.match[_27],"");
-if(!_26){
-return [];
-}
-break;
-}
-}
-}
-_21=_21.replace(/\s*,\s*/,"");
-if(_21==old){
-if(_26==null){
-throw "Syntax error, unrecognized expression: "+_21;
-}else{
-break;
-}
-}
-old=_21;
-}
-return _24;
+
+Sizzle.filter = function(expr, set, inplace, not){
+ var old = expr, result = [], curLoop = set, match, anyFound;
+
+ while ( expr && set.length ) {
+ for ( var type in Expr.filter ) {
+ if ( (match = Expr.match[ type ].exec( expr )) != null ) {
+ var filter = Expr.filter[ type ], goodArray = null, goodPos = 0, found, item;
+ anyFound = false;
+
+ if ( curLoop == result ) {
+ result = [];
+ }
+
+ if ( Expr.preFilter[ type ] ) {
+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not );
+
+ if ( !match ) {
+ anyFound = found = true;
+ } else if ( match[0] === true ) {
+ goodArray = [];
+ var last = null, elem;
+ for ( var i = 0; (elem = curLoop[i]) !== undefined; i++ ) {
+ if ( elem && last !== elem ) {
+ goodArray.push( elem );
+ last = elem;
+ }
+ }
+ }
+ }
+
+ if ( match ) {
+ for ( var i = 0; (item = curLoop[i]) !== undefined; i++ ) {
+ if ( item ) {
+ if ( goodArray && item != goodArray[goodPos] ) {
+ goodPos++;
+ }
+
+ found = filter( item, match, goodPos, goodArray );
+ var pass = not ^ !!found;
+
+ if ( inplace && found != null ) {
+ if ( pass ) {
+ anyFound = true;
+ } else {
+ curLoop[i] = false;
+ }
+ } else if ( pass ) {
+ result.push( item );
+ anyFound = true;
+ }
+ }
+ }
+ }
+
+ if ( found !== undefined ) {
+ if ( !inplace ) {
+ curLoop = result;
+ }
+
+ expr = expr.replace( Expr.match[ type ], "" );
+
+ if ( !anyFound ) {
+ return [];
+ }
+
+ break;
+ }
+ }
+ }
+
+ expr = expr.replace(/\s*,\s*/, "");
+
+ // Improper expression
+ if ( expr == old ) {
+ if ( anyFound == null ) {
+ throw "Syntax error, unrecognized expression: " + expr;
+ } else {
+ break;
+ }
+ }
+
+ old = expr;
+ }
+
+ return curLoop;
};
-var _15=_9.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u0128-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u0128-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u0128-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[((?:[\w\u0128-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\]/,TAG:/^((?:[\w\u0128-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child\(?(even|odd|[\dn+-]*)\)?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)\(?(\d*)\)?(?:[^-]|$)/,PSEUDO:/:((?:[\w\u0128-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},relative:{"+":function(_30,_31){
-for(var i=0,l=_30.length;i<l;i++){
-var _32=_30[i];
-if(_32){
-var cur=_32.previousSibling;
-while(cur&&cur.nodeType!==1){
-cur=cur.previousSibling;
-}
-_30[i]=typeof _31==="string"?cur||false:cur===_31;
-}
-}
-if(typeof _31==="string"){
-_9.filter(_31,_30,true);
-}
-},">":function(_33,_34){
-if(typeof _34==="string"&&!/\W/.test(_34)){
-_34=_34.toUpperCase();
-for(var i=0,l=_33.length;i<l;i++){
-var _35=_33[i];
-if(_35){
-var _36=_35.parentNode;
-_33[i]=_36.nodeName===_34?_36:false;
-}
-}
-}else{
-for(var i=0,l=_33.length;i<l;i++){
-var _35=_33[i];
-if(_35){
-_33[i]=typeof _34==="string"?_35.parentNode:_35.parentNode===_34;
-}
-}
-if(typeof _34==="string"){
-_9.filter(_34,_33,true);
-}
-}
-},"":function(_37,_38){
-var _39="done"+(_7++),_3a=_3b;
-if(!_38.match(/\W/)){
-var _3c=_38=_38.toUpperCase();
-_3a=_3d;
-}
-_3a("parentNode",_38,_39,_37,_3c);
-},"~":function(_3e,_3f){
-var _40="done"+(_7++),_41=_3b;
-if(typeof _3f==="string"&&!_3f.match(/\W/)){
-var _42=_3f=_3f.toUpperCase();
-_41=_3d;
-}
-_41("previousSibling",_3f,_40,_3e,_42);
-}},find:{ID:function(_43,_44){
-if(_44.getElementById){
-var m=_44.getElementById(_43[1]);
-return m?[m]:[];
-}
-},NAME:function(_45,_46){
-return _46.getElementsByName?_46.getElementsByName(_45[1]):null;
-},TAG:function(_47,_48){
-return _48.getElementsByTagName(_47[1]);
-}},preFilter:{CLASS:function(_49,_4a,_4b,_4c,not){
-_49=" "+_49[1].replace(/\\/g,"")+" ";
-for(var i=0;_4a[i];i++){
-if(not^(" "+_4a[i].className+" ").indexOf(_49)>=0){
-if(!_4b){
-_4c.push(_4a[i]);
-}
-}else{
-if(_4b){
-_4a[i]=false;
-}
-}
-}
-return false;
-},ID:function(_4d){
-return _4d[1];
-},TAG:function(_4e){
-return _4e[1].toUpperCase();
-},CHILD:function(_4f){
-if(_4f[1]=="nth"){
-var _50=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(_4f[2]=="even"&&"2n"||_4f[2]=="odd"&&"2n+1"||!/\D/.test(_4f[2])&&"0n+"+_4f[2]||_4f[2]);
-_4f[2]=(_50[1]+(_50[2]||1))-0;
-_4f[3]=_50[3]-0;
-}
-_4f[0]="done"+(_7++);
-return _4f;
-},ATTR:function(_51){
-var _52=_51[1];
-if(_15.attrMap[_52]){
-_51[1]=_15.attrMap[_52];
-}
-if(_51[2]==="~="){
-_51[4]=" "+_51[4]+" ";
-}
-return _51;
-},PSEUDO:function(_53,_54,_55,_56,not){
-if(_53[1]==="not"){
-if(_53[3].match(_6).length>1){
-_53[3]=_9(_53[3],null,null,_54);
-}else{
-var ret=_9.filter(_53[3],_54,_55,true^not);
-if(!_55){
-_56.push.apply(_56,ret);
-}
-return false;
-}
-}
-return _53;
-},POS:function(_57){
-_57.unshift(true);
-return _57;
-}},filters:{enabled:function(_58){
-return _58.disabled===false&&_58.type!=="hidden";
-},disabled:function(_59){
-return _59.disabled===true;
-},checked:function(_5a){
-return _5a.checked===true;
-},selected:function(_5b){
-_5b.parentNode.selectedIndex;
-return _5b.selected===true;
-},parent:function(_5c){
-return !!_5c.firstChild;
-},empty:function(_5d){
-return !_5d.firstChild;
-},has:function(_5e,i,_5f){
-return !!_9(_5f[3],_5e).length;
-},header:function(_60){
-return /h\d/i.test(_60.nodeName);
-},text:function(_61){
-return "text"===_61.type;
-},radio:function(_62){
-return "radio"===_62.type;
-},checkbox:function(_63){
-return "checkbox"===_63.type;
-},file:function(_64){
-return "file"===_64.type;
-},password:function(_65){
-return "password"===_65.type;
-},submit:function(_66){
-return "submit"===_66.type;
-},image:function(_67){
-return "image"===_67.type;
-},reset:function(_68){
-return "reset"===_68.type;
-},button:function(_69){
-return "button"===_69.type||_69.nodeName.toUpperCase()==="BUTTON";
-},input:function(_6a){
-return /input|select|textarea|button/i.test(_6a.nodeName);
-}},setFilters:{first:function(_6b,i){
-return i===0;
-},last:function(_6c,i,_6d,_6e){
-return i===_6e.length-1;
-},even:function(_6f,i){
-return i%2===0;
-},odd:function(_70,i){
-return i%2===1;
-},lt:function(_71,i,_72){
-return i<_72[3]-0;
-},gt:function(_73,i,_74){
-return i>_74[3]-0;
-},nth:function(_75,i,_76){
-return _76[3]-0==i;
-},eq:function(_77,i,_78){
-return _78[3]-0==i;
-}},filter:{CHILD:function(_79,_7a){
-var _7b=_7a[1],_7c=_79.parentNode;
-var _7d=_7a[0];
-if(_7c&&!_7c[_7d]){
-var _7e=1;
-for(var _7f=_7c.firstChild;_7f;_7f=_7f.nextSibling){
-if(_7f.nodeType==1){
-_7f.nodeIndex=_7e++;
-}
-}
-_7c[_7d]=_7e-1;
-}
-if(_7b=="first"){
-return _79.nodeIndex==1;
-}else{
-if(_7b=="last"){
-return _79.nodeIndex==_7c[_7d];
-}else{
-if(_7b=="only"){
-return _7c[_7d]==1;
-}else{
-if(_7b=="nth"){
-var add=false,_80=_7a[2],_81=_7a[3];
-if(_80==1&&_81==0){
-return true;
-}
-if(_80==0){
-if(_79.nodeIndex==_81){
-add=true;
-}
-}else{
-if((_79.nodeIndex-_81)%_80==0&&(_79.nodeIndex-_81)/_80>=0){
-add=true;
-}
-}
-return add;
-}
-}
-}
-}
-},PSEUDO:function(_82,_83,i,_84){
-var _85=_83[1],_86=_15.filters[_85];
-if(_86){
-return _86(_82,i,_83,_84);
-}else{
-if(_85==="contains"){
-return (_82.textContent||_82.innerText||"").indexOf(_83[3])>=0;
-}else{
-if(_85==="not"){
-var not=_83[3];
-for(var i=0,l=not.length;i<l;i++){
-if(not[i]===_82){
-return false;
-}
-}
-return true;
-}
-}
-}
-},ID:function(_87,_88){
-return _87.nodeType===1&&_87.getAttribute("id")===_88;
-},TAG:function(_89,_8a){
-return (_8a==="*"&&_89.nodeType===1)||_89.nodeName===_8a;
-},CLASS:function(_8b,_8c){
-return _8c.test(_8b.className);
-},ATTR:function(_8d,_8e){
-var _8f=_8d[_8e[1]]||_8d.getAttribute(_8e[1]),_90=_8f+"",_91=_8e[2],_92=_8e[4];
-return _8f==null?false:_91==="="?_90===_92:_91==="*="?_90.indexOf(_92)>=0:_91==="~="?(" "+_90+" ").indexOf(_92)>=0:!_8e[4]?_8f:_91==="!="?_90!=_92:_91==="^="?_90.indexOf(_92)===0:_91==="$="?_90.substr(_90.length-_92.length)===_92:_91==="|="?_90===_92||_90.substr(0,_92.length+1)===_92+"-":false;
-},POS:function(_93,_94,i,_95){
-var _96=_94[2],_97=_15.setFilters[_96];
-if(_97){
-return _97(_93,i,_94,_95);
-}
-}}};
-for(var _98 in _15.match){
-_15.match[_98]=RegExp(_15.match[_98].source+/(?![^\[]*\])(?![^\(]*\))/.source);
-}
-var _19=function(_99,_9a){
-_99=Array.prototype.slice.call(_99);
-if(_9a){
-_9a.push.apply(_9a,_99);
-return _9a;
-}
-return _99;
+
+var Expr = Sizzle.selectors = {
+ order: [ "ID", "NAME", "TAG" ],
+ match: {
+ ID: /#((?:[\w\u0128-\uFFFF_-]|\\.)+)/,
+ CLASS: /\.((?:[\w\u0128-\uFFFF_-]|\\.)+)/,
+ NAME: /\[name=['"]*((?:[\w\u0128-\uFFFF_-]|\\.)+)['"]*\]/,
+ ATTR: /\[((?:[\w\u0128-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\]/,
+ TAG: /^((?:[\w\u0128-\uFFFF\*_-]|\\.)+)/,
+ CHILD: /:(only|nth|last|first)-child\(?(even|odd|[\dn+-]*)\)?/,
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)\(?(\d*)\)?(?:[^-]|$)/,
+ PSEUDO: /:((?:[\w\u0128-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
+ },
+ attrMap: {
+ "class": "className",
+ "for": "htmlFor"
+ },
+ relative: {
+ "+": function(checkSet, part){
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ var cur = elem.previousSibling;
+ while ( cur && cur.nodeType !== 1 ) {
+ cur = cur.previousSibling;
+ }
+ checkSet[i] = typeof part === "string" ?
+ cur || false :
+ cur === part;
+ }
+ }
+
+ if ( typeof part === "string" ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ },
+ ">": function(checkSet, part){
+ if ( typeof part === "string" && !/\W/.test(part) ) {
+ part = part.toUpperCase();
+
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ var parent = elem.parentNode;
+ checkSet[i] = parent.nodeName === part ? parent : false;
+ }
+ }
+ } else {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ checkSet[i] = typeof part === "string" ?
+ elem.parentNode :
+ elem.parentNode === part;
+ }
+ }
+
+ if ( typeof part === "string" ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ }
+ },
+ "": function(checkSet, part){
+ var doneName = "done" + (done++), checkFn = dirCheck;
+
+ if ( !part.match(/\W/) ) {
+ var nodeCheck = part = part.toUpperCase();
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn("parentNode", part, doneName, checkSet, nodeCheck);
+ },
+ "~": function(checkSet, part){
+ var doneName = "done" + (done++), checkFn = dirCheck;
+
+ if ( typeof part === "string" && !part.match(/\W/) ) {
+ var nodeCheck = part = part.toUpperCase();
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn("previousSibling", part, doneName, checkSet, nodeCheck);
+ }
+ },
+ find: {
+ ID: function(match, context){
+ if ( context.getElementById ) {
+ var m = context.getElementById(match[1]);
+ return m ? [m] : [];
+ }
+ },
+ NAME: function(match, context){
+ return context.getElementsByName ? context.getElementsByName(match[1]) : null;
+ },
+ TAG: function(match, context){
+ return context.getElementsByTagName(match[1]);
+ }
+ },
+ preFilter: {
+ CLASS: function(match, curLoop, inplace, result, not){
+ match = " " + match[1].replace(/\\/g, "") + " ";
+
+ for ( var i = 0; curLoop[i]; i++ ) {
+ if ( not ^ (" " + curLoop[i].className + " ").indexOf(match) >= 0 ) {
+ if ( !inplace )
+ result.push( curLoop[i] );
+ } else if ( inplace ) {
+ curLoop[i] = false;
+ }
+ }
+
+ return false;
+ },
+ ID: function(match){
+ return match[1];
+ },
+ TAG: function(match){
+ return match[1].toUpperCase();
+ },
+ CHILD: function(match){
+ if ( match[1] == "nth" ) {
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+ var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
+ match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+ // calculate the numbers (first)n+(last) including if they are negative
+ match[2] = (test[1] + (test[2] || 1)) - 0;
+ match[3] = test[3] - 0;
+ }
+
+ // TODO: Move to normal caching system
+ match[0] = "done" + (done++);
+
+ return match;
+ },
+ ATTR: function(match){
+ var name = match[1];
+
+ if ( Expr.attrMap[name] ) {
+ match[1] = Expr.attrMap[name];
+ }
+
+ if ( match[2] === "~=" ) {
+ match[4] = " " + match[4] + " ";
+ }
+
+ return match;
+ },
+ PSEUDO: function(match, curLoop, inplace, result, not){
+ if ( match[1] === "not" ) {
+ // If we're dealing with a complex expression, or a simple one
+ if ( match[3].match(chunker).length > 1 ) {
+ match[3] = Sizzle(match[3], null, null, curLoop);
+ } else {
+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+ if ( !inplace ) {
+ result.push.apply( result, ret );
+ }
+ return false;
+ }
+ }
+
+ return match;
+ },
+ POS: function(match){
+ match.unshift( true );
+ return match;
+ }
+ },
+ filters: {
+ enabled: function(elem){
+ return elem.disabled === false && elem.type !== "hidden";
+ },
+ disabled: function(elem){
+ return elem.disabled === true;
+ },
+ checked: function(elem){
+ return elem.checked === true;
+ },
+ selected: function(elem){
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ elem.parentNode.selectedIndex;
+ return elem.selected === true;
+ },
+ parent: function(elem){
+ return !!elem.firstChild;
+ },
+ empty: function(elem){
+ return !elem.firstChild;
+ },
+ has: function(elem, i, match){
+ return !!Sizzle( match[3], elem ).length;
+ },
+ header: function(elem){
+ return /h\d/i.test( elem.nodeName );
+ },
+ text: function(elem){
+ return "text" === elem.type;
+ },
+ radio: function(elem){
+ return "radio" === elem.type;
+ },
+ checkbox: function(elem){
+ return "checkbox" === elem.type;
+ },
+ file: function(elem){
+ return "file" === elem.type;
+ },
+ password: function(elem){
+ return "password" === elem.type;
+ },
+ submit: function(elem){
+ return "submit" === elem.type;
+ },
+ image: function(elem){
+ return "image" === elem.type;
+ },
+ reset: function(elem){
+ return "reset" === elem.type;
+ },
+ button: function(elem){
+ return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
+ },
+ input: function(elem){
+ return /input|select|textarea|button/i.test(elem.nodeName);
+ }
+ },
+ setFilters: {
+ first: function(elem, i){
+ return i === 0;
+ },
+ last: function(elem, i, match, array){
+ return i === array.length - 1;
+ },
+ even: function(elem, i){
+ return i % 2 === 0;
+ },
+ odd: function(elem, i){
+ return i % 2 === 1;
+ },
+ lt: function(elem, i, match){
+ return i < match[3] - 0;
+ },
+ gt: function(elem, i, match){
+ return i > match[3] - 0;
+ },
+ nth: function(elem, i, match){
+ return match[3] - 0 == i;
+ },
+ eq: function(elem, i, match){
+ return match[3] - 0 == i;
+ }
+ },
+ filter: {
+ CHILD: function(elem, match){
+ var type = match[1], parent = elem.parentNode;
+
+ var doneName = match[0];
+
+ if ( parent && !parent[ doneName ] ) {
+ var count = 1;
+
+ for ( var node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType == 1 ) {
+ node.nodeIndex = count++;
+ }
+ }
+
+ parent[ doneName ] = count - 1;
+ }
+
+ if ( type == "first" ) {
+ return elem.nodeIndex == 1;
+ } else if ( type == "last" ) {
+ return elem.nodeIndex == parent[ doneName ];
+ } else if ( type == "only" ) {
+ return parent[ doneName ] == 1;
+ } else if ( type == "nth" ) {
+ var add = false, first = match[2], last = match[3];
+
+ if ( first == 1 && last == 0 ) {
+ return true;
+ }
+
+ if ( first == 0 ) {
+ if ( elem.nodeIndex == last ) {
+ add = true;
+ }
+ } else if ( (elem.nodeIndex - last) % first == 0 && (elem.nodeIndex - last) / first >= 0 ) {
+ add = true;
+ }
+
+ return add;
+ }
+ },
+ PSEUDO: function(elem, match, i, array){
+ var name = match[1], filter = Expr.filters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+ } else if ( name === "contains" ) {
+ return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
+ } else if ( name === "not" ) {
+ var not = match[3];
+
+ for ( var i = 0, l = not.length; i < l; i++ ) {
+ if ( not[i] === elem ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ },
+ ID: function(elem, match){
+ return elem.nodeType === 1 && elem.getAttribute("id") === match;
+ },
+ TAG: function(elem, match){
+ return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
+ },
+ CLASS: function(elem, match){
+ return match.test( elem.className );
+ },
+ ATTR: function(elem, match){
+ var result = elem[ match[1] ] || elem.getAttribute( match[1] ), value = result + "", type = match[2], check = match[4];
+ return result == null ?
+ false :
+ type === "=" ?
+ value === check :
+ type === "*=" ?
+ value.indexOf(check) >= 0 :
+ type === "~=" ?
+ (" " + value + " ").indexOf(check) >= 0 :
+ !match[4] ?
+ result :
+ type === "!=" ?
+ value != check :
+ type === "^=" ?
+ value.indexOf(check) === 0 :
+ type === "$=" ?
+ value.substr(value.length - check.length) === check :
+ type === "|=" ?
+ value === check || value.substr(0, check.length + 1) === check + "-" :
+ false;
+ },
+ POS: function(elem, match, i, array){
+ var name = match[2], filter = Expr.setFilters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+ }
+ }
+ }
};
-try{
-Array.prototype.slice.call(document.documentElement.childNodes);
-}
-catch(e){
-_19=function(_9b,_9c){
-var ret=_9c||[];
-if(_8.call(_9b)==="[object Array]"){
-Array.prototype.push.apply(ret,_9b);
-}else{
-if(typeof _9b.length==="number"){
-for(var i=0,l=_9b.length;i<l;i++){
-ret.push(_9b[i]);
-}
-}else{
-for(var i=0;_9b[i];i++){
-ret.push(_9b[i]);
-}
-}
+
+for ( var type in Expr.match ) {
+ Expr.match[ type ] = RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
}
-return ret;
+
+var makeArray = function(array, results) {
+ array = Array.prototype.slice.call( array );
+
+ if ( results ) {
+ results.push.apply( results, array );
+ return results;
+ }
+
+ return array;
};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+try {
+ Array.prototype.slice.call( document.documentElement.childNodes );
+
+// Provide a fallback method if it does not work
+} catch(e){
+ makeArray = function(array, results) {
+ var ret = results || [];
+
+ if ( toString.call(array) === "[object Array]" ) {
+ Array.prototype.push.apply( ret, array );
+ } else {
+ if ( typeof array.length === "number" ) {
+ for ( var i = 0, l = array.length; i < l; i++ ) {
+ ret.push( array[i] );
+ }
+ } else {
+ for ( var i = 0; array[i]; i++ ) {
+ ret.push( array[i] );
+ }
+ }
+ }
+
+ return ret;
+ };
}
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
(function(){
-var _9d=document.createElement("form"),id="script"+(new Date).getTime();
-_9d.innerHTML="<input name='"+id+"'/>";
-var _9e=document.documentElement;
-_9e.insertBefore(_9d,_9e.firstChild);
-if(!!document.getElementById(id)){
-_15.find.ID=function(_9f,_a0){
-if(_a0.getElementById){
-var m=_a0.getElementById(_9f[1]);
-return m?m.id===_9f[1]||m.getAttributeNode&&m.getAttributeNode("id").nodeValue===_9f[1]?[m]:undefined:[];
-}
-};
-_15.filter.ID=function(_a1,_a2){
-var _a3=_a1.getAttributeNode&&_a1.getAttributeNode("id");
-return _a1.nodeType===1&&_a3&&_a3.nodeValue===_a2;
-};
-}
-_9e.removeChild(_9d);
+ // We're going to inject a fake input element with a specified name
+ var form = document.createElement("form"),
+ id = "script" + (new Date).getTime();
+ form.innerHTML = "<input name='" + id + "'/>";
+
+ // Inject it into the root element, check its status, and remove it quickly
+ var root = document.documentElement;
+ root.insertBefore( form, root.firstChild );
+
+ // The workaround has to do additional checks after a getElementById
+ // Which slows things down for other browsers (hence the branching)
+ if ( !!document.getElementById( id ) ) {
+ Expr.find.ID = function(match, context){
+ if ( context.getElementById ) {
+ var m = context.getElementById(match[1]);
+ return m ? m.id === match[1] || m.getAttributeNode && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
+ }
+ };
+
+ Expr.filter.ID = function(elem, match){
+ var node = elem.getAttributeNode && elem.getAttributeNode("id");
+ return elem.nodeType === 1 && node && node.nodeValue === match;
+ };
+ }
+
+ root.removeChild( form );
})();
+
+// Check to see if the browser returns only elements
+// when doing getElementsByTagName("*")
(function(){
-var div=document.createElement("div");
-div.appendChild(document.createComment(""));
-if(div.getElementsByTagName("*").length>0){
-_15.find.TAG=function(_a4,_a5){
-var _a6=_a5.getElementsByTagName(_a4[1]);
-if(_a4[1]==="*"){
-var tmp=[];
-for(var i=0;_a6[i];i++){
-if(_a6[i].nodeType===1){
-tmp.push(_a6[i]);
-}
-}
-_a6=tmp;
-}
-return _a6;
-};
-}
+ // Create a fake element
+ var div = document.createElement("div");
+ div.appendChild( document.createComment("") );
+
+ // Make sure no comments are found
+ if ( div.getElementsByTagName("*").length > 0 ) {
+ Expr.find.TAG = function(match, context){
+ var results = context.getElementsByTagName(match[1]);
+
+ // Filter out possible comments
+ if ( match[1] === "*" ) {
+ var tmp = [];
+
+ for ( var i = 0; results[i]; i++ ) {
+ if ( results[i].nodeType === 1 ) {
+ tmp.push( results[i] );
+ }
+ }
+
+ results = tmp;
+ }
+
+ return results;
+ };
+ }
})();
-if(document.querySelectorAll){
-(function(){
-var _a7=_9;
-_9=function(_a8,_a9,_aa,_ab){
-_a9=_a9||document;
-if(!_ab&&_a9.nodeType===9){
-try{
-return _19(_a9.querySelectorAll(_a8),_aa);
-}
-catch(e){
-}
-}
-return _a7(_a8,_a9,_aa,_ab);
-};
-_9.find=_a7.find;
-_9.filter=_a7.filter;
-_9.selectors=_a7.selectors;
-_9.matches=_a7.matches;
+
+if ( document.querySelectorAll ) (function(){
+ var oldSizzle = Sizzle;
+
+ Sizzle = function(query, context, extra, seed){
+ context = context || document;
+
+ if ( !seed && context.nodeType === 9 ) {
+ try {
+ return makeArray( context.querySelectorAll(query), extra );
+ } catch(e){}
+ }
+
+ return oldSizzle(query, context, extra, seed);
+ };
+
+ Sizzle.find = oldSizzle.find;
+ Sizzle.filter = oldSizzle.filter;
+ Sizzle.selectors = oldSizzle.selectors;
+ Sizzle.matches = oldSizzle.matches;
})();
+
+if ( document.documentElement.getElementsByClassName ) {
+ Expr.order.splice(1, 0, "CLASS");
+ Expr.find.CLASS = function(match, context) {
+ return context.getElementsByClassName(match[1]);
+ };
}
-if(document.documentElement.getElementsByClassName){
-_15.order.splice(1,0,"CLASS");
-_15.find.CLASS=function(_ac,_ad){
-return _ad.getElementsByClassName(_ac[1]);
-};
-}
-function _3d(dir,cur,_ae,_af,_b0){
-for(var i=0,l=_af.length;i<l;i++){
-var _b1=_af[i];
-if(_b1){
-_b1=_b1[dir];
-var _b2=false;
-while(_b1&&_b1.nodeType){
-var _b3=_b1[_ae];
-if(_b3){
-_b2=_af[_b3];
-break;
-}
-if(_b1.nodeType===1){
-_b1[_ae]=i;
-}
-if(_b1.nodeName===cur){
-_b2=_b1;
-break;
-}
-_b1=_b1[dir];
-}
-_af[i]=_b2;
-}
-}
-};
-function _3b(dir,cur,_b4,_b5,_b6){
-for(var i=0,l=_b5.length;i<l;i++){
-var _b7=_b5[i];
-if(_b7){
-_b7=_b7[dir];
-var _b8=false;
-while(_b7&&_b7.nodeType){
-if(_b7[_b4]){
-_b8=_b5[_b7[_b4]];
-break;
-}
-if(_b7.nodeType===1){
-_b7[_b4]=i;
-if(typeof cur!=="string"){
-if(_b7===cur){
-_b8=true;
-break;
-}
-}else{
-if(_9.filter(cur,[_b7]).length>0){
-_b8=_b7;
-break;
-}
-}
-}
-_b7=_b7[dir];
-}
-_b5[i]=_b8;
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ elem = elem[dir];
+ var match = false;
+
+ while ( elem && elem.nodeType ) {
+ var done = elem[doneName];
+ if ( done ) {
+ match = checkSet[ done ];
+ break;
+ }
+
+ if ( elem.nodeType === 1 )
+ elem[doneName] = i;
+
+ if ( elem.nodeName === cur ) {
+ match = elem;
+ break;
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ elem = elem[dir];
+ var match = false;
+
+ while ( elem && elem.nodeType ) {
+ if ( elem[doneName] ) {
+ match = checkSet[ elem[doneName] ];
+ break;
+ }
+
+ if ( elem.nodeType === 1 ) {
+ elem[doneName] = i;
+
+ if ( typeof cur !== "string" ) {
+ if ( elem === cur ) {
+ match = true;
+ break;
+ }
+
+ } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+ match = elem;
+ break;
+ }
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
}
+
+var contains = document.compareDocumentPosition ? function(a, b){
+ return a.compareDocumentPosition(b) & 16;
+} : function(a, b){
+ return a !== b && (a.contains ? a.contains(b) : true);
};
-var _1a=document.compareDocumentPosition?function(a,b){
-return a.compareDocumentPosition(b)&16;
-}:function(a,b){
-return a!==b&&(a.contains?a.contains(b):true);
-};
-(ns||window).Sizzle=_9;
-})(typeof dojo=="undefined"?null:dojo);
+
+// EXPOSE
+
+(ns || window).Sizzle = Sizzle;
+
+})(typeof dojo == "undefined" ? null : dojo);
+
}
diff --git a/lib/dojo/_base/query.js b/lib/dojo/_base/query.js
index ecf84682c..7b9878e47 100644
--- a/lib/dojo/_base/query.js
+++ b/lib/dojo/_base/query.js
@@ -5,793 +5,1520 @@
*/
-if(!dojo._hasResource["dojo._base.query"]){
-dojo._hasResource["dojo._base.query"]=true;
-if(typeof dojo!="undefined"){
-dojo.provide("dojo._base.query");
-dojo.require("dojo._base.NodeList");
-dojo.require("dojo._base.lang");
-}
-(function(d){
-var _1=d.trim;
-var _2=d.forEach;
-var _3=d._NodeListCtor=d.NodeList;
-var _4=function(){
-return d.doc;
-};
-var _5=((d.isWebKit||d.isMozilla)&&((_4().compatMode)=="BackCompat"));
-var _6=!!_4().firstChild["children"]?"children":"childNodes";
-var _7=">~+";
-var _8=false;
-var _9=function(){
-return true;
-};
-var _a=function(_b){
-if(_7.indexOf(_b.slice(-1))>=0){
-_b+=" * ";
-}else{
-_b+=" ";
-}
-var ts=function(s,e){
-return _1(_b.slice(s,e));
-};
-var _c=[];
-var _d=-1,_e=-1,_f=-1,_10=-1,_11=-1,_12=-1,_13=-1,lc="",cc="",_14;
-var x=0,ql=_b.length,_15=null,_16=null;
-var _17=function(){
-if(_13>=0){
-var tv=(_13==x)?null:ts(_13,x);
-_15[(_7.indexOf(tv)<0)?"tag":"oper"]=tv;
-_13=-1;
-}
-};
-var _18=function(){
-if(_12>=0){
-_15.id=ts(_12,x).replace(/\\/g,"");
-_12=-1;
-}
-};
-var _19=function(){
-if(_11>=0){
-_15.classes.push(ts(_11+1,x).replace(/\\/g,""));
-_11=-1;
-}
-};
-var _1a=function(){
-_18();
-_17();
-_19();
-};
-var _1b=function(){
-_1a();
-if(_10>=0){
-_15.pseudos.push({name:ts(_10+1,x)});
-}
-_15.loops=(_15.pseudos.length||_15.attrs.length||_15.classes.length);
-_15.oquery=_15.query=ts(_14,x);
-_15.otag=_15.tag=(_15["oper"])?null:(_15.tag||"*");
-if(_15.tag){
-_15.tag=_15.tag.toUpperCase();
-}
-if(_c.length&&(_c[_c.length-1].oper)){
-_15.infixOper=_c.pop();
-_15.query=_15.infixOper.query+" "+_15.query;
-}
-_c.push(_15);
-_15=null;
-};
-for(;lc=cc,cc=_b.charAt(x),x<ql;x++){
-if(lc=="\\"){
-continue;
-}
-if(!_15){
-_14=x;
-_15={query:null,pseudos:[],attrs:[],classes:[],tag:null,oper:null,id:null,getTag:function(){
-return (_8)?this.otag:this.tag;
-}};
-_13=x;
-}
-if(_d>=0){
-if(cc=="]"){
-if(!_16.attr){
-_16.attr=ts(_d+1,x);
-}else{
-_16.matchFor=ts((_f||_d+1),x);
-}
-var cmf=_16.matchFor;
-if(cmf){
-if((cmf.charAt(0)=="\"")||(cmf.charAt(0)=="'")){
-_16.matchFor=cmf.slice(1,-1);
-}
-}
-_15.attrs.push(_16);
-_16=null;
-_d=_f=-1;
-}else{
-if(cc=="="){
-var _1c=("|~^$*".indexOf(lc)>=0)?lc:"";
-_16.type=_1c+cc;
-_16.attr=ts(_d+1,x-_1c.length);
-_f=x+1;
-}
-}
-}else{
-if(_e>=0){
-if(cc==")"){
-if(_10>=0){
-_16.value=ts(_e+1,x);
-}
-_10=_e=-1;
-}
-}else{
-if(cc=="#"){
-_1a();
-_12=x+1;
-}else{
-if(cc=="."){
-_1a();
-_11=x;
-}else{
-if(cc==":"){
-_1a();
-_10=x;
-}else{
-if(cc=="["){
-_1a();
-_d=x;
-_16={};
-}else{
-if(cc=="("){
-if(_10>=0){
-_16={name:ts(_10+1,x),value:null};
-_15.pseudos.push(_16);
-}
-_e=x;
-}else{
-if((cc==" ")&&(lc!=cc)){
-_1b();
-}
-}
-}
-}
-}
-}
-}
-}
-}
-return _c;
-};
-var _1d=function(_1e,_1f){
-if(!_1e){
-return _1f;
-}
-if(!_1f){
-return _1e;
-}
-return function(){
-return _1e.apply(window,arguments)&&_1f.apply(window,arguments);
-};
-};
-var _20=function(i,arr){
-var r=arr||[];
-if(i){
-r.push(i);
-}
-return r;
-};
-var _21=function(n){
-return (1==n.nodeType);
-};
-var _22="";
-var _23=function(_24,_25){
-if(!_24){
-return _22;
-}
-if(_25=="class"){
-return _24.className||_22;
-}
-if(_25=="for"){
-return _24.htmlFor||_22;
-}
-if(_25=="style"){
-return _24.style.cssText||_22;
-}
-return (_8?_24.getAttribute(_25):_24.getAttribute(_25,2))||_22;
-};
-var _26={"*=":function(_27,_28){
-return function(_29){
-return (_23(_29,_27).indexOf(_28)>=0);
-};
-},"^=":function(_2a,_2b){
-return function(_2c){
-return (_23(_2c,_2a).indexOf(_2b)==0);
-};
-},"$=":function(_2d,_2e){
-var _2f=" "+_2e;
-return function(_30){
-var ea=" "+_23(_30,_2d);
-return (ea.lastIndexOf(_2e)==(ea.length-_2e.length));
-};
-},"~=":function(_31,_32){
-var _33=" "+_32+" ";
-return function(_34){
-var ea=" "+_23(_34,_31)+" ";
-return (ea.indexOf(_33)>=0);
-};
-},"|=":function(_35,_36){
-var _37=" "+_36+"-";
-return function(_38){
-var ea=" "+_23(_38,_35);
-return ((ea==_36)||(ea.indexOf(_37)==0));
-};
-},"=":function(_39,_3a){
-return function(_3b){
-return (_23(_3b,_39)==_3a);
-};
-}};
-var _3c=(typeof _4().firstChild.nextElementSibling=="undefined");
-var _3d=!_3c?"nextElementSibling":"nextSibling";
-var _3e=!_3c?"previousElementSibling":"previousSibling";
-var _3f=(_3c?_21:_9);
-var _40=function(_41){
-while(_41=_41[_3e]){
-if(_3f(_41)){
-return false;
-}
-}
-return true;
-};
-var _42=function(_43){
-while(_43=_43[_3d]){
-if(_3f(_43)){
-return false;
-}
-}
-return true;
-};
-var _44=function(_45){
-var _46=_45.parentNode;
-var i=0,_47=_46[_6],ci=(_45["_i"]||-1),cl=(_46["_l"]||-1);
-if(!_47){
-return -1;
-}
-var l=_47.length;
-if(cl==l&&ci>=0&&cl>=0){
-return ci;
-}
-_46["_l"]=l;
-ci=-1;
-for(var te=_46["firstElementChild"]||_46["firstChild"];te;te=te[_3d]){
-if(_3f(te)){
-te["_i"]=++i;
-if(_45===te){
-ci=i;
-}
-}
-}
-return ci;
-};
-var _48=function(_49){
-return !((_44(_49))%2);
-};
-var _4a=function(_4b){
-return ((_44(_4b))%2);
-};
-var _4c={"checked":function(_4d,_4e){
-return function(_4f){
-return !!("checked" in _4f?_4f.checked:_4f.selected);
-};
-},"first-child":function(){
-return _40;
-},"last-child":function(){
-return _42;
-},"only-child":function(_50,_51){
-return function(_52){
-if(!_40(_52)){
-return false;
-}
-if(!_42(_52)){
-return false;
-}
-return true;
-};
-},"empty":function(_53,_54){
-return function(_55){
-var cn=_55.childNodes;
-var cnl=_55.childNodes.length;
-for(var x=cnl-1;x>=0;x--){
-var nt=cn[x].nodeType;
-if((nt===1)||(nt==3)){
-return false;
-}
-}
-return true;
-};
-},"contains":function(_56,_57){
-var cz=_57.charAt(0);
-if(cz=="\""||cz=="'"){
-_57=_57.slice(1,-1);
-}
-return function(_58){
-return (_58.innerHTML.indexOf(_57)>=0);
-};
-},"not":function(_59,_5a){
-var p=_a(_5a)[0];
-var _5b={el:1};
-if(p.tag!="*"){
-_5b.tag=1;
-}
-if(!p.classes.length){
-_5b.classes=1;
-}
-var ntf=_5c(p,_5b);
-return function(_5d){
-return (!ntf(_5d));
-};
-},"nth-child":function(_5e,_5f){
-var pi=parseInt;
-if(_5f=="odd"){
-return _4a;
-}else{
-if(_5f=="even"){
-return _48;
-}
-}
-if(_5f.indexOf("n")!=-1){
-var _60=_5f.split("n",2);
-var _61=_60[0]?((_60[0]=="-")?-1:pi(_60[0])):1;
-var idx=_60[1]?pi(_60[1]):0;
-var lb=0,ub=-1;
-if(_61>0){
-if(idx<0){
-idx=(idx%_61)&&(_61+(idx%_61));
-}else{
-if(idx>0){
-if(idx>=_61){
-lb=idx-idx%_61;
-}
-idx=idx%_61;
-}
-}
-}else{
-if(_61<0){
-_61*=-1;
-if(idx>0){
-ub=idx;
-idx=idx%_61;
-}
-}
-}
-if(_61>0){
-return function(_62){
-var i=_44(_62);
-return (i>=lb)&&(ub<0||i<=ub)&&((i%_61)==idx);
-};
-}else{
-_5f=idx;
-}
-}
-var _63=pi(_5f);
-return function(_64){
-return (_44(_64)==_63);
-};
-}};
-var _65=(d.isIE)?function(_66){
-var clc=_66.toLowerCase();
-if(clc=="class"){
-_66="className";
-}
-return function(_67){
-return (_8?_67.getAttribute(_66):_67[_66]||_67[clc]);
-};
-}:function(_68){
-return function(_69){
-return (_69&&_69.getAttribute&&_69.hasAttribute(_68));
-};
-};
-var _5c=function(_6a,_6b){
-if(!_6a){
-return _9;
-}
-_6b=_6b||{};
-var ff=null;
-if(!("el" in _6b)){
-ff=_1d(ff,_21);
-}
-if(!("tag" in _6b)){
-if(_6a.tag!="*"){
-ff=_1d(ff,function(_6c){
-return (_6c&&(_6c.tagName==_6a.getTag()));
-});
-}
-}
-if(!("classes" in _6b)){
-_2(_6a.classes,function(_6d,idx,arr){
-var re=new RegExp("(?:^|\\s)"+_6d+"(?:\\s|$)");
-ff=_1d(ff,function(_6e){
-return re.test(_6e.className);
-});
-ff.count=idx;
-});
-}
-if(!("pseudos" in _6b)){
-_2(_6a.pseudos,function(_6f){
-var pn=_6f.name;
-if(_4c[pn]){
-ff=_1d(ff,_4c[pn](pn,_6f.value));
-}
-});
-}
-if(!("attrs" in _6b)){
-_2(_6a.attrs,function(_70){
-var _71;
-var a=_70.attr;
-if(_70.type&&_26[_70.type]){
-_71=_26[_70.type](a,_70.matchFor);
-}else{
-if(a.length){
-_71=_65(a);
-}
-}
-if(_71){
-ff=_1d(ff,_71);
-}
-});
-}
-if(!("id" in _6b)){
-if(_6a.id){
-ff=_1d(ff,function(_72){
-return (!!_72&&(_72.id==_6a.id));
-});
-}
-}
-if(!ff){
-if(!("default" in _6b)){
-ff=_9;
-}
-}
-return ff;
-};
-var _73=function(_74){
-return function(_75,ret,bag){
-while(_75=_75[_3d]){
-if(_3c&&(!_21(_75))){
-continue;
-}
-if((!bag||_76(_75,bag))&&_74(_75)){
-ret.push(_75);
-}
-break;
-}
-return ret;
-};
-};
-var _77=function(_78){
-return function(_79,ret,bag){
-var te=_79[_3d];
-while(te){
-if(_3f(te)){
-if(bag&&!_76(te,bag)){
-break;
-}
-if(_78(te)){
-ret.push(te);
-}
-}
-te=te[_3d];
-}
-return ret;
-};
-};
-var _7a=function(_7b){
-_7b=_7b||_9;
-return function(_7c,ret,bag){
-var te,x=0,_7d=_7c[_6];
-while(te=_7d[x++]){
-if(_3f(te)&&(!bag||_76(te,bag))&&(_7b(te,x))){
-ret.push(te);
-}
-}
-return ret;
-};
-};
-var _7e=function(_7f,_80){
-var pn=_7f.parentNode;
-while(pn){
-if(pn==_80){
-break;
-}
-pn=pn.parentNode;
-}
-return !!pn;
-};
-var _81={};
-var _82=function(_83){
-var _84=_81[_83.query];
-if(_84){
-return _84;
-}
-var io=_83.infixOper;
-var _85=(io?io.oper:"");
-var _86=_5c(_83,{el:1});
-var qt=_83.tag;
-var _87=("*"==qt);
-var ecs=_4()["getElementsByClassName"];
-if(!_85){
-if(_83.id){
-_86=(!_83.loops&&_87)?_9:_5c(_83,{el:1,id:1});
-_84=function(_88,arr){
-var te=d.byId(_83.id,(_88.ownerDocument||_88));
-if(!te||!_86(te)){
-return;
-}
-if(9==_88.nodeType){
-return _20(te,arr);
-}else{
-if(_7e(te,_88)){
-return _20(te,arr);
-}
-}
-};
-}else{
-if(ecs&&/\{\s*\[native code\]\s*\}/.test(String(ecs))&&_83.classes.length&&!_5){
-_86=_5c(_83,{el:1,classes:1,id:1});
-var _89=_83.classes.join(" ");
-_84=function(_8a,arr,bag){
-var ret=_20(0,arr),te,x=0;
-var _8b=_8a.getElementsByClassName(_89);
-while((te=_8b[x++])){
-if(_86(te,_8a)&&_76(te,bag)){
-ret.push(te);
-}
-}
-return ret;
-};
-}else{
-if(!_87&&!_83.loops){
-_84=function(_8c,arr,bag){
-var ret=_20(0,arr),te,x=0;
-var _8d=_8c.getElementsByTagName(_83.getTag());
-while((te=_8d[x++])){
-if(_76(te,bag)){
-ret.push(te);
-}
-}
-return ret;
-};
-}else{
-_86=_5c(_83,{el:1,tag:1,id:1});
-_84=function(_8e,arr,bag){
-var ret=_20(0,arr),te,x=0;
-var _8f=_8e.getElementsByTagName(_83.getTag());
-while((te=_8f[x++])){
-if(_86(te,_8e)&&_76(te,bag)){
-ret.push(te);
-}
-}
-return ret;
-};
-}
-}
-}
-}else{
-var _90={el:1};
-if(_87){
-_90.tag=1;
-}
-_86=_5c(_83,_90);
-if("+"==_85){
-_84=_73(_86);
-}else{
-if("~"==_85){
-_84=_77(_86);
-}else{
-if(">"==_85){
-_84=_7a(_86);
-}
-}
-}
-}
-return _81[_83.query]=_84;
-};
-var _91=function(_92,_93){
-var _94=_20(_92),qp,x,te,qpl=_93.length,bag,ret;
-for(var i=0;i<qpl;i++){
-ret=[];
-qp=_93[i];
-x=_94.length-1;
-if(x>0){
-bag={};
-ret.nozip=true;
-}
-var gef=_82(qp);
-for(var j=0;(te=_94[j]);j++){
-gef(te,ret,bag);
-}
-if(!ret.length){
-break;
-}
-_94=ret;
-}
-return ret;
-};
-var _95={},_96={};
-var _97=function(_98){
-var _99=_a(_1(_98));
-if(_99.length==1){
-var tef=_82(_99[0]);
-return function(_9a){
-var r=tef(_9a,new _3());
-if(r){
-r.nozip=true;
-}
-return r;
-};
-}
-return function(_9b){
-return _91(_9b,_99);
-};
-};
-var nua=navigator.userAgent;
-var wk="WebKit/";
-var _9c=(d.isWebKit&&(nua.indexOf(wk)>0)&&(parseFloat(nua.split(wk)[1])>528));
-var _9d=d.isIE?"commentStrip":"nozip";
-var qsa="querySelectorAll";
-var _9e=(!!_4()[qsa]&&(!d.isSafari||(d.isSafari>3.1)||_9c));
-var _9f=/n\+\d|([^ ])?([>~+])([^ =])?/g;
-var _a0=function(_a1,pre,ch,_a2){
-return ch?(pre?pre+" ":"")+ch+(_a2?" "+_a2:""):_a1;
-};
-var _a3=function(_a4,_a5){
-_a4=_a4.replace(_9f,_a0);
-if(_9e){
-var _a6=_96[_a4];
-if(_a6&&!_a5){
-return _a6;
-}
-}
-var _a7=_95[_a4];
-if(_a7){
-return _a7;
-}
-var qcz=_a4.charAt(0);
-var _a8=(-1==_a4.indexOf(" "));
-if((_a4.indexOf("#")>=0)&&(_a8)){
-_a5=true;
-}
-var _a9=(_9e&&(!_a5)&&(_7.indexOf(qcz)==-1)&&(!d.isIE||(_a4.indexOf(":")==-1))&&(!(_5&&(_a4.indexOf(".")>=0)))&&(_a4.indexOf(":contains")==-1)&&(_a4.indexOf(":checked")==-1)&&(_a4.indexOf("|=")==-1));
-if(_a9){
-var tq=(_7.indexOf(_a4.charAt(_a4.length-1))>=0)?(_a4+" *"):_a4;
-return _96[_a4]=function(_aa){
-try{
-if(!((9==_aa.nodeType)||_a8)){
-throw "";
-}
-var r=_aa[qsa](tq);
-r[_9d]=true;
-return r;
-}
-catch(e){
-return _a3(_a4,true)(_aa);
-}
-};
-}else{
-var _ab=_a4.split(/\s*,\s*/);
-return _95[_a4]=((_ab.length<2)?_97(_a4):function(_ac){
-var _ad=0,ret=[],tp;
-while((tp=_ab[_ad++])){
-ret=ret.concat(_97(tp)(_ac));
-}
-return ret;
-});
-}
-};
-var _ae=0;
-var _af=d.isIE?function(_b0){
-if(_8){
-return (_b0.getAttribute("_uid")||_b0.setAttribute("_uid",++_ae)||_ae);
-}else{
-return _b0.uniqueID;
-}
-}:function(_b1){
-return (_b1._uid||(_b1._uid=++_ae));
-};
-var _76=function(_b2,bag){
-if(!bag){
-return 1;
-}
-var id=_af(_b2);
-if(!bag[id]){
-return bag[id]=1;
-}
-return 0;
-};
-var _b3="_zipIdx";
-var _b4=function(arr){
-if(arr&&arr.nozip){
-return (_3._wrap)?_3._wrap(arr):arr;
-}
-var ret=new _3();
-if(!arr||!arr.length){
-return ret;
-}
-if(arr[0]){
-ret.push(arr[0]);
-}
-if(arr.length<2){
-return ret;
-}
-_ae++;
-if(d.isIE&&_8){
-var _b5=_ae+"";
-arr[0].setAttribute(_b3,_b5);
-for(var x=1,te;te=arr[x];x++){
-if(arr[x].getAttribute(_b3)!=_b5){
-ret.push(te);
-}
-te.setAttribute(_b3,_b5);
-}
-}else{
-if(d.isIE&&arr.commentStrip){
-try{
-for(var x=1,te;te=arr[x];x++){
-if(_21(te)){
-ret.push(te);
-}
-}
-}
-catch(e){
-}
-}else{
-if(arr[0]){
-arr[0][_b3]=_ae;
-}
-for(var x=1,te;te=arr[x];x++){
-if(arr[x][_b3]!=_ae){
-ret.push(te);
-}
-te[_b3]=_ae;
-}
-}
-}
-return ret;
-};
-d.query=function(_b6,_b7){
-_3=d._NodeListCtor;
-if(!_b6){
-return new _3();
-}
-if(_b6.constructor==_3){
-return _b6;
-}
-if(typeof _b6!="string"){
-return new _3(_b6);
-}
-if(typeof _b7=="string"){
-_b7=d.byId(_b7);
-if(!_b7){
-return new _3();
-}
-}
-_b7=_b7||_4();
-var od=_b7.ownerDocument||_b7.documentElement;
-_8=(_b7.contentType&&_b7.contentType=="application/xml")||(d.isOpera&&(_b7.doctype||od.toString()=="[object XMLDocument]"))||(!!od)&&(d.isIE?od.xml:(_b7.xmlVersion||od.xmlVersion));
-var r=_a3(_b6)(_b7);
-if(r&&r.nozip&&!_3._wrap){
-return r;
-}
-return _b4(r);
-};
-d.query.pseudos=_4c;
-d._filterQueryResult=function(_b8,_b9){
-var _ba=new d._NodeListCtor();
-var _bb=_5c(_a(_b9)[0]);
-for(var x=0,te;te=_b8[x];x++){
-if(_bb(te)){
-_ba.push(te);
-}
+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;
+if(typeof dojo != "undefined"){
+ dojo.provide("dojo._base.query");
+ dojo.require("dojo._base.NodeList");
+ dojo.require("dojo._base.lang");
+
}
-return _ba;
-};
+
+/*
+ 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)
+ - native (FF3.1+, Safari 3.1+, IE 8+)
+ 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)
+ 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
+ - for native implementations, this may mean working around spec
+ bugs. So be it.
+ 5.) matched nodes are pruned to ensure they are unique (if necessary)
+*/
+
+;(function(d){
+ // define everything in a closure for compressability reasons. "d" is an
+ // alias to "dojo" (or the toolkit alias object, e.g., "acme").
+
+ ////////////////////////////////////////////////////////////////////////
+ // Toolkit aliases
+ ////////////////////////////////////////////////////////////////////////
+
+ // if you are extracing dojo.query for use in your own system, you will
+ // need to provide these methods and properties. No other porting should be
+ // necessary, save for configuring the system to use a class other than
+ // dojo.NodeList as the return instance instantiator
+ var trim = d.trim;
+ var each = d.forEach;
+ // d.isIE; // float
+ // d.isSafari; // float
+ // d.isOpera; // float
+ // d.isWebKit; // float
+ // d.doc ; // document element
+ var qlc = d._NodeListCtor = d.NodeList;
+
+ var getDoc = function(){ return d.doc; };
+ // NOTE(alex): the spec is idiotic. CSS queries should ALWAYS be case-sensitive, but nooooooo
+ var cssCaseBug = ((d.isWebKit||d.isMozilla) && ((getDoc().compatMode) == "BackCompat"));
+
+ ////////////////////////////////////////////////////////////////////////
+ // Global utilities
+ ////////////////////////////////////////////////////////////////////////
+
+
+ // on browsers that support the "children" collection we can avoid a lot of
+ // iteration on chaff (non-element) nodes.
+ // why.
+ var childNodesName = !!getDoc().firstChild["children"] ? "children" : "childNodes";
+
+ var specials = ">~+";
+
+ // global thunk to determine whether we should treat the current query as
+ // case sensitive or not. This switch is flipped by the query evaluator
+ // based on the document passed as the context to search.
+ var caseSensitive = false;
+
+ // how high?
+ var yesman = function(){ return true; };
+
+ ////////////////////////////////////////////////////////////////////////
+ // Tokenizer
+ ////////////////////////////////////////////////////////////////////////
+
+ var getQueryParts = function(query){
+ // summary:
+ // state machine for query tokenization
+ // description:
+ // instead of using a brittle and slow regex-based CSS parser,
+ // dojo.query implements an AST-style query representation. This
+ // representation is only generated once per query. For example,
+ // the same query run multiple times or under different root nodes
+ // does not re-parse the selector expression but instead uses the
+ // cached data structure. The state machine implemented here
+ // terminates on the last " " (space) charachter and returns an
+ // ordered array of query component structures (or "parts"). Each
+ // part represents an operator or a simple CSS filtering
+ // expression. The structure for parts is documented in the code
+ // below.
+
+
+ // NOTE:
+ // this code is designed to run fast and compress well. Sacrifices
+ // to readibility and maintainability have been made. Your best
+ // bet when hacking the tokenizer is to put The Donnas on *really*
+ // loud (may we recommend their "Spend The Night" release?) and
+ // just assume you're gonna make mistakes. Keep the unit tests
+ // open and run them frequently. Knowing is half the battle ;-)
+ if(specials.indexOf(query.slice(-1)) >= 0){
+ // if we end with a ">", "+", or "~", that means we're implicitly
+ // searching all children, so make it explicit
+ query += " * "
+ }else{
+ // if you have not provided a terminator, one will be provided for
+ // you...
+ query += " ";
+ }
+
+ var ts = function(/*Integer*/ s, /*Integer*/ e){
+ // trim and slice.
+
+ // take an index to start a string slice from and an end position
+ // and return a trimmed copy of that sub-string
+ return trim(query.slice(s, e));
+ }
+
+ // the overall data graph of the full query, as represented by queryPart objects
+ var queryParts = [];
+
+
+ // state keeping vars
+ var inBrackets = -1, inParens = -1, inMatchFor = -1,
+ inPseudo = -1, inClass = -1, inId = -1, inTag = -1,
+ lc = "", cc = "", pStart;
+
+ // iteration vars
+ var x = 0, // index in the query
+ ql = query.length,
+ currentPart = null, // data structure representing the entire clause
+ _cp = null; // the current pseudo or attr matcher
+
+ // several temporary variables are assigned to this structure durring a
+ // potential sub-expression match:
+ // attr:
+ // a string representing the current full attribute match in a
+ // bracket expression
+ // type:
+ // if there's an operator in a bracket expression, this is
+ // used to keep track of it
+ // value:
+ // the internals of parenthetical expression for a pseudo. for
+ // :nth-child(2n+1), value might be "2n+1"
+
+ var endTag = function(){
+ // called when the tokenizer hits the end of a particular tag name.
+ // Re-sets state variables for tag matching and sets up the matcher
+ // to handle the next type of token (tag or operator).
+ if(inTag >= 0){
+ var tv = (inTag == x) ? null : ts(inTag, x); // .toLowerCase();
+ currentPart[ (specials.indexOf(tv) < 0) ? "tag" : "oper" ] = tv;
+ inTag = -1;
+ }
+ }
+
+ var endId = function(){
+ // called when the tokenizer might be at the end of an ID portion of a match
+ if(inId >= 0){
+ currentPart.id = ts(inId, x).replace(/\\/g, "");
+ inId = -1;
+ }
+ }
+
+ var endClass = function(){
+ // called when the tokenizer might be at the end of a class name
+ // match. CSS allows for multiple classes, so we augment the
+ // current item with another class in its list
+ if(inClass >= 0){
+ currentPart.classes.push(ts(inClass+1, x).replace(/\\/g, ""));
+ inClass = -1;
+ }
+ }
+
+ var endAll = function(){
+ // at the end of a simple fragment, so wall off the matches
+ endId(); endTag(); endClass();
+ }
+
+ var endPart = function(){
+ endAll();
+ if(inPseudo >= 0){
+ currentPart.pseudos.push({ name: ts(inPseudo+1, x) });
+ }
+ // hint to the selector engine to tell it whether or not it
+ // needs to do any iteration. Many simple selectors don't, and
+ // we can avoid significant construction-time work by advising
+ // the system to skip them
+ currentPart.loops = (
+ currentPart.pseudos.length ||
+ currentPart.attrs.length ||
+ currentPart.classes.length );
+
+ currentPart.oquery = currentPart.query = ts(pStart, x); // save the full expression as a string
+
+
+ // otag/tag are hints to suggest to the system whether or not
+ // it's an operator or a tag. We save a copy of otag since the
+ // tag name is cast to upper-case in regular HTML matches. The
+ // system has a global switch to figure out if the current
+ // expression needs to be case sensitive or not and it will use
+ // otag or tag accordingly
+ currentPart.otag = currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
+
+ if(currentPart.tag){
+ // if we're in a case-insensitive HTML doc, we likely want
+ // the toUpperCase when matching on element.tagName. If we
+ // do it here, we can skip the string op per node
+ // comparison
+ currentPart.tag = currentPart.tag.toUpperCase();
+ }
+
+ // add the part to the list
+ if(queryParts.length && (queryParts[queryParts.length-1].oper)){
+ // operators are always infix, so we remove them from the
+ // list and attach them to the next match. The evaluator is
+ // responsible for sorting out how to handle them.
+ currentPart.infixOper = queryParts.pop();
+ currentPart.query = currentPart.infixOper.query + " " + currentPart.query;
+ /*
+ console.debug( "swapping out the infix",
+ currentPart.infixOper,
+ "and attaching it to",
+ currentPart);
+ */
+ }
+ queryParts.push(currentPart);
+
+ currentPart = null;
+ }
+
+ // iterate over the query, charachter by charachter, building up a
+ // list of query part objects
+ for(; lc=cc, cc=query.charAt(x), x < ql; x++){
+ // cc: the current character in the match
+ // lc: the last charachter (if any)
+
+ // someone is trying to escape something, so don't try to match any
+ // fragments. We assume we're inside a literal.
+ if(lc == "\\"){ continue; }
+ if(!currentPart){ // a part was just ended or none has yet been created
+ // NOTE: I hate all this alloc, but it's shorter than writing tons of if's
+ pStart = x;
+ // rules describe full CSS sub-expressions, like:
+ // #someId
+ // .className:first-child
+ // but not:
+ // thinger > div.howdy[type=thinger]
+ // the indidual components of the previous query would be
+ // split into 3 parts that would be represented a structure
+ // like:
+ // [
+ // {
+ // query: "thinger",
+ // tag: "thinger",
+ // },
+ // {
+ // query: "div.howdy[type=thinger]",
+ // classes: ["howdy"],
+ // infixOper: {
+ // query: ">",
+ // oper: ">",
+ // }
+ // },
+ // ]
+ currentPart = {
+ query: null, // the full text of the part's rule
+ pseudos: [], // CSS supports multiple pseud-class matches in a single rule
+ attrs: [], // CSS supports multi-attribute match, so we need an array
+ classes: [], // class matches may be additive, e.g.: .thinger.blah.howdy
+ tag: null, // only one tag...
+ oper: null, // ...or operator per component. Note that these wind up being exclusive.
+ id: null, // the id component of a rule
+ getTag: function(){
+ return (caseSensitive) ? this.otag : this.tag;
+ }
+ };
+
+ // if we don't have a part, we assume we're going to start at
+ // the beginning of a match, which should be a tag name. This
+ // might fault a little later on, but we detect that and this
+ // iteration will still be fine.
+ inTag = x;
+ }
+
+ if(inBrackets >= 0){
+ // look for a the close first
+ if(cc == "]"){ // if we're in a [...] clause and we end, do assignment
+ if(!_cp.attr){
+ // no attribute match was previously begun, so we
+ // assume this is an attribute existance match in the
+ // form of [someAttributeName]
+ _cp.attr = ts(inBrackets+1, x);
+ }else{
+ // we had an attribute already, so we know that we're
+ // matching some sort of value, as in [attrName=howdy]
+ _cp.matchFor = ts((inMatchFor||inBrackets+1), x);
+ }
+ var cmf = _cp.matchFor;
+ if(cmf){
+ // try to strip quotes from the matchFor value. We want
+ // [attrName=howdy] to match the same
+ // as [attrName = 'howdy' ]
+ if( (cmf.charAt(0) == '"') || (cmf.charAt(0) == "'") ){
+ _cp.matchFor = cmf.slice(1, -1);
+ }
+ }
+ // end the attribute by adding it to the list of attributes.
+ currentPart.attrs.push(_cp);
+ _cp = null; // necessary?
+ inBrackets = inMatchFor = -1;
+ }else if(cc == "="){
+ // if the last char was an operator prefix, make sure we
+ // record it along with the "=" operator.
+ 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 we're in a parenthetical expression, we need to figure
+ // out if it's attached to a pseduo-selector rule like
+ // :nth-child(1)
+ if(cc == ")"){
+ if(inPseudo >= 0){
+ _cp.value = ts(inParens+1, x);
+ }
+ inPseudo = inParens = -1;
+ }
+ }else if(cc == "#"){
+ // start of an ID match
+ endAll();
+ inId = x+1;
+ }else if(cc == "."){
+ // start of a class match
+ endAll();
+ inClass = x;
+ }else if(cc == ":"){
+ // start of a pseudo-selector match
+ endAll();
+ inPseudo = x;
+ }else if(cc == "["){
+ // start of an attribute match.
+ endAll();
+ inBrackets = x;
+ // provide a new structure for the attribute match to fill-in
+ _cp = {
+ /*=====
+ attr: null, type: null, matchFor: null
+ =====*/
+ };
+ }else if(cc == "("){
+ // we really only care if we've entered a parenthetical
+ // expression if we're already inside a pseudo-selector match
+ if(inPseudo >= 0){
+ // provide a new structure for the pseudo match to fill-in
+ _cp = {
+ name: ts(inPseudo+1, x),
+ value: null
+ }
+ currentPart.pseudos.push(_cp);
+ }
+ inParens = x;
+ }else if(
+ (cc == " ") &&
+ // if it's a space char and the last char is too, consume the
+ // current one without doing more work
+ (lc != cc)
+ ){
+ endPart();
+ }
+ }
+ return queryParts;
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // DOM query infrastructure
+ ////////////////////////////////////////////////////////////////////////
+
+ var agree = function(first, second){
+ // 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. If
+ // either are not possed, the other is used exclusively.
+ if(!first){ return second; }
+ if(!second){ return first; }
+
+ return function(){
+ return first.apply(window, arguments) && second.apply(window, arguments);
+ }
+ };
+
+ var getArr = function(i, arr){
+ // helps us avoid array alloc when we don't need it
+ var r = arr||[]; // FIXME: should this be 'new d._NodeListCtor()' ?
+ if(i){ r.push(i); }
+ return r;
+ };
+
+ var _isElement = function(n){ return (1 == n.nodeType); };
+
+ // FIXME: need to coalesce _getAttr with defaultGetter
+ var blank = "";
+ var _getAttr = function(elem, attr){
+ if(!elem){ return blank; }
+ if(attr == "class"){
+ return elem.className || blank;
+ }
+ if(attr == "for"){
+ return elem.htmlFor || blank;
+ }
+ if(attr == "style"){
+ return elem.style.cssText || blank;
+ }
+ return (caseSensitive ? elem.getAttribute(attr) : 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 = " "+_getAttr(elem, attr);
+ return (
+ (ea == value) ||
+ (ea.indexOf(valueDash)==0)
+ );
+ }
+ },
+ "=": function(attr, value){
+ return function(elem){
+ return (_getAttr(elem, attr) == value);
+ }
+ }
+ };
+
+ // avoid testing for node type if we can. Defining this in the negative
+ // here to avoid negation in the fast path.
+ var _noNES = (typeof getDoc().firstChild.nextElementSibling == "undefined");
+ var _ns = !_noNES ? "nextElementSibling" : "nextSibling";
+ var _ps = !_noNES ? "previousElementSibling" : "previousSibling";
+ var _simpleNodeTest = (_noNES ? _isElement : yesman);
+
+ var _lookLeft = function(node){
+ // look left
+ while(node = node[_ps]){
+ if(_simpleNodeTest(node)){ return false; }
+ }
+ return true;
+ };
+
+ var _lookRight = function(node){
+ // look right
+ while(node = node[_ns]){
+ if(_simpleNodeTest(node)){ return false; }
+ }
+ return true;
+ };
+
+ var getNodeIndex = function(node){
+ var root = node.parentNode;
+ var i = 0,
+ tret = root[childNodesName],
+ ci = (node["_i"]||-1),
+ cl = (root["_l"]||-1);
+
+ if(!tret){ return -1; }
+ var l = tret.length;
+
+ // we calcuate the parent length as a cheap way to invalidate the
+ // cache. It's not 100% accurate, but it's much more honest than what
+ // other libraries do
+ if( cl == l && ci >= 0 && cl >= 0 ){
+ // if it's legit, tag and release
+ return ci;
+ }
+
+ // else re-key things
+ root["_l"] = l;
+ ci = -1;
+ for(var te = root["firstElementChild"]||root["firstChild"]; te; te = te[_ns]){
+ if(_simpleNodeTest(te)){
+ te["_i"] = ++i;
+ if(node === te){
+ // NOTE:
+ // shortcuting the return at this step in indexing works
+ // very well for benchmarking but we avoid it here since
+ // it leads to potential O(n^2) behavior in sequential
+ // getNodexIndex operations on a previously un-indexed
+ // parent. We may revisit this at a later time, but for
+ // now we just want to get the right answer more often
+ // than not.
+ ci = i;
+ }
+ }
+ }
+ return ci;
+ };
+
+ var isEven = function(elem){
+ return !((getNodeIndex(elem)) % 2);
+ };
+
+ var isOdd = function(elem){
+ return ((getNodeIndex(elem)) % 2);
+ };
+
+ var pseudos = {
+ "checked": function(name, condition){
+ return function(elem){
+ return !!("checked" in elem ? elem.checked : elem.selected);
+ }
+ },
+ "first-child": function(){ return _lookLeft; },
+ "last-child": function(){ return _lookRight; },
+ "only-child": function(name, condition){
+ return function(node){
+ if(!_lookLeft(node)){ return false; }
+ if(!_lookRight(node)){ return false; }
+ return true;
+ };
+ },
+ "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){
+ var cz = condition.charAt(0);
+ if( cz == '"' || cz == "'" ){ //remove quote
+ condition = condition.slice(1, -1);
+ }
+ return function(elem){
+ return (elem.innerHTML.indexOf(condition) >= 0);
+ }
+ },
+ "not": function(name, condition){
+ var p = getQueryParts(condition)[0];
+ var ignores = { el: 1 };
+ if(p.tag != "*"){
+ ignores.tag = 1;
+ }
+ if(!p.classes.length){
+ ignores.classes = 1;
+ }
+ var ntf = getSimpleFilterFunc(p, ignores);
+ return function(elem){
+ return (!ntf(elem));
+ }
+ },
+ "nth-child": function(name, condition){
+ var pi = parseInt;
+ // avoid re-defining function objects if we can
+ if(condition == "odd"){
+ return isOdd;
+ }else if(condition == "even"){
+ return isEven;
+ }
+ // FIXME: can we shorten this?
+ if(condition.indexOf("n") != -1){
+ var tparts = condition.split("n", 2);
+ var pred = tparts[0] ? ((tparts[0] == '-') ? -1 : pi(tparts[0])) : 1;
+ var idx = tparts[1] ? pi(tparts[1]) : 0;
+ var lb = 0, ub = -1;
+ if(pred > 0){
+ if(idx < 0){
+ idx = (idx % pred) && (pred + (idx % pred));
+ }else if(idx>0){
+ if(idx >= pred){
+ lb = idx - idx % pred;
+ }
+ idx = idx % pred;
+ }
+ }else if(pred<0){
+ pred *= -1;
+ // idx has to be greater than 0 when pred is negative;
+ // shall we throw an error here?
+ if(idx > 0){
+ ub = idx;
+ idx = idx % pred;
+ }
+ }
+ if(pred > 0){
+ return function(elem){
+ var i = getNodeIndex(elem);
+ return (i>=lb) && (ub<0 || i<=ub) && ((i % pred) == idx);
+ }
+ }else{
+ condition = idx;
+ }
+ }
+ var ncount = pi(condition);
+ return function(elem){
+ return (getNodeIndex(elem) == ncount);
+ }
+ }
+ };
+
+ var defaultGetter = (d.isIE) ? function(cond){
+ var clc = cond.toLowerCase();
+ if(clc == "class"){ cond = "className"; }
+ return function(elem){
+ return (caseSensitive ? elem.getAttribute(cond) : elem[cond]||elem[clc]);
+ }
+ } : function(cond){
+ return function(elem){
+ return (elem && elem.getAttribute && elem.hasAttribute(cond));
+ }
+ };
+
+ var getSimpleFilterFunc = function(query, ignores){
+ // generates a node tester function based on the passed query part. The
+ // query part is one of the structures generatd by the query parser
+ // when it creates the query AST. The "ignores" object specifies which
+ // (if any) tests to skip, allowing the system to avoid duplicating
+ // work where it may have already been taken into account by other
+ // factors such as how the nodes to test were fetched in the first
+ // place
+ if(!query){ return yesman; }
+ ignores = ignores||{};
+
+ var ff = null;
+
+ if(!("el" in ignores)){
+ ff = agree(ff, _isElement);
+ }
+
+ if(!("tag" in ignores)){
+ if(query.tag != "*"){
+ ff = agree(ff, function(elem){
+ return (elem && (elem.tagName == query.getTag()));
+ });
+ }
+ }
+
+ if(!("classes" in ignores)){
+ each(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|$)");
+ */
+ var re = new RegExp("(?:^|\\s)" + cname + "(?:\\s|$)");
+ ff = agree(ff, function(elem){
+ return re.test(elem.className);
+ });
+ ff.count = idx;
+ });
+ }
+
+ if(!("pseudos" in ignores)){
+ each(query.pseudos, function(pseudo){
+ var pn = pseudo.name;
+ if(pseudos[pn]){
+ ff = agree(ff, pseudos[pn](pn, pseudo.value));
+ }
+ });
+ }
+
+ if(!("attrs" in ignores)){
+ each(query.attrs, function(attr){
+ var matcher;
+ var a = attr.attr;
+ // type, attr, matchFor
+ if(attr.type && attrs[attr.type]){
+ matcher = attrs[attr.type](a, attr.matchFor);
+ }else if(a.length){
+ matcher = defaultGetter(a);
+ }
+ if(matcher){
+ ff = agree(ff, matcher);
+ }
+ });
+ }
+
+ if(!("id" in ignores)){
+ if(query.id){
+ ff = agree(ff, function(elem){
+ return (!!elem && (elem.id == query.id));
+ });
+ }
+ }
+
+ if(!ff){
+ if(!("default" in ignores)){
+ ff = yesman;
+ }
+ }
+ return ff;
+ };
+
+ var _nextSibling = function(filterFunc){
+ return function(node, ret, bag){
+ while(node = node[_ns]){
+ if(_noNES && (!_isElement(node))){ continue; }
+ if(
+ (!bag || _isUnique(node, bag)) &&
+ filterFunc(node)
+ ){
+ ret.push(node);
+ }
+ break;
+ }
+ return ret;
+ }
+ };
+
+ var _nextSiblings = function(filterFunc){
+ return function(root, ret, bag){
+ var te = root[_ns];
+ while(te){
+ if(_simpleNodeTest(te)){
+ if(bag && !_isUnique(te, bag)){
+ break;
+ }
+ if(filterFunc(te)){
+ ret.push(te);
+ }
+ }
+ te = te[_ns];
+ }
+ return ret;
+ }
+ };
+
+ // get an array of child *elements*, skipping text and comment nodes
+ var _childElements = function(filterFunc){
+ filterFunc = filterFunc||yesman;
+ return function(root, ret, bag){
+ // get an array of child elements, skipping text and comment nodes
+ var te, x = 0, tret = root[childNodesName];
+ while(te = tret[x++]){
+ if(
+ _simpleNodeTest(te) &&
+ (!bag || _isUnique(te, bag)) &&
+ (filterFunc(te, x))
+ ){
+ ret.push(te);
+ }
+ }
+ return ret;
+ };
+ };
+
+ /*
+ // thanks, Dean!
+ var itemIsAfterRoot = d.isIE ? function(item, root){
+ return (item.sourceIndex > root.sourceIndex);
+ } : function(item, root){
+ return (item.compareDocumentPosition(root) == 2);
+ };
+ */
+
+ // test to see if node is below root
+ var _isDescendant = function(node, root){
+ var pn = node.parentNode;
+ while(pn){
+ if(pn == root){
+ break;
+ }
+ pn = pn.parentNode;
+ }
+ return !!pn;
+ };
+
+ var _getElementsFuncCache = {};
+
+ var getElementsFunc = function(query){
+ var retFunc = _getElementsFuncCache[query.query];
+ // if we've got a cached dispatcher, just use that
+ if(retFunc){ return retFunc; }
+ // else, generate a new on
+
+ // NOTE:
+ // this function returns a function that searches for nodes and
+ // filters them. The search may be specialized by infix operators
+ // (">", "~", or "+") else it will default to searching all
+ // descendants (the " " selector). Once a group of children is
+ // founde, a test function is applied to weed out the ones we
+ // don't want. Many common cases can be fast-pathed. We spend a
+ // lot of cycles to create a dispatcher that doesn't do more work
+ // than necessary at any point since, unlike this function, the
+ // dispatchers will be called every time. The logic of generating
+ // efficient dispatchers looks like this in pseudo code:
+ //
+ // # if it's a purely descendant query (no ">", "+", or "~" modifiers)
+ // if infixOperator == " ":
+ // if only(id):
+ // return def(root):
+ // return d.byId(id, root);
+ //
+ // elif id:
+ // return def(root):
+ // return filter(d.byId(id, root));
+ //
+ // elif cssClass && getElementsByClassName:
+ // return def(root):
+ // return filter(root.getElementsByClassName(cssClass));
+ //
+ // elif only(tag):
+ // return def(root):
+ // return root.getElementsByTagName(tagName);
+ //
+ // else:
+ // # search by tag name, then filter
+ // return def(root):
+ // return filter(root.getElementsByTagName(tagName||"*"));
+ //
+ // elif infixOperator == ">":
+ // # search direct children
+ // return def(root):
+ // return filter(root.children);
+ //
+ // elif infixOperator == "+":
+ // # search next sibling
+ // return def(root):
+ // return filter(root.nextElementSibling);
+ //
+ // elif infixOperator == "~":
+ // # search rightward siblings
+ // return def(root):
+ // return filter(nextSiblings(root));
+
+ var io = query.infixOper;
+ var oper = (io ? io.oper : "");
+ // the default filter func which tests for all conditions in the query
+ // part. This is potentially inefficient, so some optimized paths may
+ // re-define it to test fewer things.
+ var filterFunc = getSimpleFilterFunc(query, { el: 1 });
+ var qt = query.tag;
+ var wildcardTag = ("*" == qt);
+ var ecs = getDoc()["getElementsByClassName"];
+
+ if(!oper){
+ // if there's no infix operator, then it's a descendant query. ID
+ // and "elements by class name" variants can be accelerated so we
+ // call them out explicitly:
+ if(query.id){
+ // testing shows that the overhead of yesman() is acceptable
+ // and can save us some bytes vs. re-defining the function
+ // everywhere.
+ filterFunc = (!query.loops && wildcardTag) ?
+ yesman :
+ getSimpleFilterFunc(query, { el: 1, id: 1 });
+
+ retFunc = function(root, arr){
+ var te = d.byId(query.id, (root.ownerDocument||root));
+ if(!te || !filterFunc(te)){ return; }
+ if(9 == root.nodeType){ // if root's a doc, we just return directly
+ return getArr(te, arr);
+ }else{ // otherwise check ancestry
+ if(_isDescendant(te, root)){
+ return getArr(te, arr);
+ }
+ }
+ }
+ }else if(
+ ecs &&
+ // isAlien check. Workaround for Prototype.js being totally evil/dumb.
+ /\{\s*\[native code\]\s*\}/.test(String(ecs)) &&
+ query.classes.length &&
+ !cssCaseBug
+ ){
+ // it's a class-based query and we've got a fast way to run it.
+
+ // ignore class and ID filters since we will have handled both
+ filterFunc = getSimpleFilterFunc(query, { el: 1, classes: 1, id: 1 });
+ var classesString = query.classes.join(" ");
+ retFunc = function(root, arr, bag){
+ var ret = getArr(0, arr), te, x=0;
+ var tret = root.getElementsByClassName(classesString);
+ while((te = tret[x++])){
+ if(filterFunc(te, root) && _isUnique(te, bag)){
+ ret.push(te);
+ }
+ }
+ return ret;
+ };
+
+ }else if(!wildcardTag && !query.loops){
+ // it's tag only. Fast-path it.
+ retFunc = function(root, arr, bag){
+ var ret = getArr(0, arr), te, x=0;
+ var tret = root.getElementsByTagName(query.getTag());
+ while((te = tret[x++])){
+ if(_isUnique(te, bag)){
+ ret.push(te);
+ }
+ }
+ return ret;
+ };
+ }else{
+ // the common case:
+ // a descendant selector without a fast path. By now it's got
+ // to have a tag selector, even if it's just "*" so we query
+ // by that and filter
+ filterFunc = getSimpleFilterFunc(query, { el: 1, tag: 1, id: 1 });
+ retFunc = function(root, arr, bag){
+ var ret = getArr(0, arr), te, x=0;
+ // we use getTag() to avoid case sensitivity issues
+ var tret = root.getElementsByTagName(query.getTag());
+ while((te = tret[x++])){
+ if(filterFunc(te, root) && _isUnique(te, bag)){
+ ret.push(te);
+ }
+ }
+ return ret;
+ };
+ }
+ }else{
+ // the query is scoped in some way. Instead of querying by tag we
+ // use some other collection to find candidate nodes
+ var skipFilters = { el: 1 };
+ if(wildcardTag){
+ skipFilters.tag = 1;
+ }
+ filterFunc = getSimpleFilterFunc(query, skipFilters);
+ if("+" == oper){
+ retFunc = _nextSibling(filterFunc);
+ }else if("~" == oper){
+ retFunc = _nextSiblings(filterFunc);
+ }else if(">" == oper){
+ retFunc = _childElements(filterFunc);
+ }
+ }
+ // cache it and return
+ return _getElementsFuncCache[query.query] = retFunc;
+ };
+
+ var filterDown = function(root, queryParts){
+ // NOTE:
+ // this is the guts of the DOM query system. It takes a list of
+ // parsed query parts and a root and finds children which match
+ // the selector represented by the parts
+ var candidates = getArr(root), qp, x, te, qpl = queryParts.length, bag, ret;
+
+ for(var i = 0; i < qpl; i++){
+ ret = [];
+ qp = queryParts[i];
+ x = candidates.length - 1;
+ if(x > 0){
+ // if we have more than one root at this level, provide a new
+ // hash to use for checking group membership but tell the
+ // system not to post-filter us since we will already have been
+ // gauranteed to be unique
+ bag = {};
+ ret.nozip = true;
+ }
+ var gef = getElementsFunc(qp);
+ for(var j = 0; (te = candidates[j]); j++){
+ // for every root, get the elements that match the descendant
+ // selector, adding them to the "ret" array and filtering them
+ // via membership in this level's bag. If there are more query
+ // parts, then this level's return will be used as the next
+ // level's candidates
+ gef(te, ret, bag);
+ }
+ if(!ret.length){ break; }
+ candidates = ret;
+ }
+ return ret;
+ };
+
+ ////////////////////////////////////////////////////////////////////////
+ // the query runner
+ ////////////////////////////////////////////////////////////////////////
+
+ // these are the primary caches for full-query results. The query
+ // dispatcher functions are generated then stored here for hash lookup in
+ // the future
+ var _queryFuncCacheDOM = {},
+ _queryFuncCacheQSA = {};
+
+ // 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 getStepQueryFunc = function(query){
+ var qparts = getQueryParts(trim(query));
+
+ // if it's trivial, avoid iteration and zipping costs
+ if(qparts.length == 1){
+ // we optimize this case here to prevent dispatch further down the
+ // chain, potentially slowing things down. We could more elegantly
+ // handle this in filterDown(), but it's slower for simple things
+ // that need to be fast (e.g., "#someId").
+ var tef = getElementsFunc(qparts[0]);
+ return function(root){
+ var r = tef(root, new qlc());
+ if(r){ r.nozip = true; }
+ return r;
+ }
+ }
+
+ // otherwise, break it up and return a runner that iterates over the parts recursively
+ return function(root){
+ return filterDown(root, qparts);
+ }
+ };
+
+ // NOTES:
+ // * we can't trust QSA for anything but document-rooted queries, so
+ // caching is split into DOM query evaluators and QSA query evaluators
+ // * caching query results is dirty and leak-prone (or, at a minimum,
+ // prone to unbounded growth). Other toolkits may go this route, but
+ // they totally destroy their own ability to manage their memory
+ // footprint. If we implement it, it should only ever be with a fixed
+ // total element reference # limit and an LRU-style algorithm since JS
+ // has no weakref support. Caching compiled query evaluators is also
+ // potentially problematic, but even on large documents the size of the
+ // query evaluators is often < 100 function objects per evaluator (and
+ // LRU can be applied if it's ever shown to be an issue).
+ // * since IE's QSA support is currently only for HTML documents and even
+ // then only in IE 8's "standards mode", we have to detect our dispatch
+ // route at query time and keep 2 separate caches. Ugg.
+
+ // we need to determine if we think we can run a given query via
+ // querySelectorAll or if we'll need to fall back on DOM queries to get
+ // there. We need a lot of information about the environment and the query
+ // to make the determiniation (e.g. does it support QSA, does the query in
+ // question work in the native QSA impl, etc.).
+ var nua = navigator.userAgent;
+ // some versions of Safari provided QSA, but it was buggy and crash-prone.
+ // We need te detect the right "internal" webkit version to make this work.
+ var wk = "WebKit/";
+ var is525 = (
+ d.isWebKit &&
+ (nua.indexOf(wk) > 0) &&
+ (parseFloat(nua.split(wk)[1]) > 528)
+ );
+
+ // IE QSA queries may incorrectly include comment nodes, so we throw the
+ // zipping function into "remove" comments mode instead of the normal "skip
+ // it" which every other QSA-clued browser enjoys
+ var noZip = d.isIE ? "commentStrip" : "nozip";
+
+ var qsa = "querySelectorAll";
+ var qsaAvail = (
+ !!getDoc()[qsa] &&
+ // see #5832
+ (!d.isSafari || (d.isSafari > 3.1) || is525 )
+ );
+
+ //Don't bother with n+3 type of matches, IE complains if we modify those.
+ var infixSpaceRe = /n\+\d|([^ ])?([>~+])([^ =])?/g;
+ var infixSpaceFunc = function(match, pre, ch, post) {
+ return ch ? (pre ? pre + " " : "") + ch + (post ? " " + post : "") : /*n+3*/ match;
+ };
+
+ var getQueryFunc = function(query, forceDOM){
+ //Normalize query. The CSS3 selectors spec allows for omitting spaces around
+ //infix operators, >, ~ and +
+ //Do the work here since detection for spaces is used as a simple "not use QSA"
+ //test below.
+ query = query.replace(infixSpaceRe, infixSpaceFunc);
+
+ if(qsaAvail){
+ // if we've got a cached variant and we think we can do it, run it!
+ var qsaCached = _queryFuncCacheQSA[query];
+ if(qsaCached && !forceDOM){ return qsaCached; }
+ }
+
+ // else if we've got a DOM cached variant, assume that we already know
+ // all we need to and use it
+ var domCached = _queryFuncCacheDOM[query];
+ if(domCached){ return domCached; }
+
+ // TODO:
+ // today we're caching DOM and QSA branches separately so we
+ // recalc useQSA every time. If we had a way to tag root+query
+ // efficiently, we'd be in good shape to do a global cache.
+
+ var qcz = query.charAt(0);
+ var nospace = (-1 == query.indexOf(" "));
+
+ // byId searches are wicked fast compared to QSA, even when filtering
+ // is required
+ if( (query.indexOf("#") >= 0) && (nospace) ){
+ forceDOM = true;
+ }
+
+ var useQSA = (
+ qsaAvail && (!forceDOM) &&
+ // as per CSS 3, we can't currently start w/ combinator:
+ // http://www.w3.org/TR/css3-selectors/#w3cselgrammar
+ (specials.indexOf(qcz) == -1) &&
+ // IE's QSA impl sucks on pseudos
+ (!d.isIE || (query.indexOf(":") == -1)) &&
+
+ (!(cssCaseBug && (query.indexOf(".") >= 0))) &&
+
+ // FIXME:
+ // need to tighten up browser rules on ":contains" and "|=" to
+ // figure out which aren't good
+ // Latest webkit (around 531.21.8) does not seem to do well with :checked on option
+ // elements, even though according to spec, selected options should
+ // match :checked. So go nonQSA for it:
+ // http://bugs.dojotoolkit.org/ticket/5179
+ (query.indexOf(":contains") == -1) && (query.indexOf(":checked") == -1) &&
+ (query.indexOf("|=") == -1) // some browsers don't grok it
+ );
+
+ // TODO:
+ // if we've got a descendant query (e.g., "> .thinger" instead of
+ // just ".thinger") in a QSA-able doc, but are passed a child as a
+ // root, it should be possible to give the item a synthetic ID and
+ // trivially rewrite the query to the form "#synid > .thinger" to
+ // use the QSA branch
+
+
+ if(useQSA){
+ var tq = (specials.indexOf(query.charAt(query.length-1)) >= 0) ?
+ (query + " *") : query;
+ return _queryFuncCacheQSA[query] = function(root){
+ try{
+ // the QSA system contains an egregious spec bug which
+ // limits us, effectively, to only running QSA queries over
+ // entire documents. See:
+ // http://ejohn.org/blog/thoughts-on-queryselectorall/
+ // despite this, we can also handle QSA runs on simple
+ // selectors, but we don't want detection to be expensive
+ // so we're just checking for the presence of a space char
+ // right now. Not elegant, but it's cheaper than running
+ // the query parser when we might not need to
+ if(!((9 == root.nodeType) || nospace)){ throw ""; }
+ var r = root[qsa](tq);
+ // skip expensive duplication checks and just wrap in a NodeList
+ r[noZip] = true;
+ return r;
+ }catch(e){
+ // else run the DOM branch on this query, ensuring that we
+ // default that way in the future
+ return getQueryFunc(query, true)(root);
+ }
+ }
+ }else{
+ // DOM branch
+ var parts = query.split(/\s*,\s*/);
+ return _queryFuncCacheDOM[query] = ((parts.length < 2) ?
+ // if not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
+ getStepQueryFunc(query) :
+ // if it *is* a complex query, break it up into its
+ // constituent parts and return a dispatcher that will
+ // merge the parts when run
+ function(root){
+ var pindex = 0, // avoid array alloc for every invocation
+ ret = [],
+ tp;
+ while((tp = parts[pindex++])){
+ ret = ret.concat(getStepQueryFunc(tp)(root));
+ }
+ return ret;
+ }
+ );
+ }
+ };
+
+ var _zipIdx = 0;
+
+ // NOTE:
+ // this function is Moo inspired, but our own impl to deal correctly
+ // with XML in IE
+ var _nodeUID = d.isIE ? function(node){
+ if(caseSensitive){
+ // XML docs don't have uniqueID on their nodes
+ return (node.getAttribute("_uid") || node.setAttribute("_uid", ++_zipIdx) || _zipIdx);
+
+ }else{
+ return node.uniqueID;
+ }
+ } :
+ function(node){
+ return (node._uid || (node._uid = ++_zipIdx));
+ };
+
+ // determine if a node in is unique in a "bag". In this case we don't want
+ // to flatten a list of unique items, but rather just tell if the item in
+ // question is already in the bag. Normally we'd just use hash lookup to do
+ // this for us but IE's DOM is busted so we can't really count on that. On
+ // the upside, it gives us a built in unique ID function.
+ var _isUnique = function(node, bag){
+ if(!bag){ return 1; }
+ var id = _nodeUID(node);
+ if(!bag[id]){ return bag[id] = 1; }
+ return 0;
+ };
+
+ // attempt to efficiently determine if an item in a list is a dupe,
+ // returning a list of "uniques", hopefully in doucment order
+ var _zipIdxName = "_zipIdx";
+ var _zip = function(arr){
+ if(arr && arr.nozip){
+ return (qlc._wrap) ? qlc._wrap(arr) : arr;
+ }
+ // var ret = new d._NodeListCtor();
+ var ret = new qlc();
+ if(!arr || !arr.length){ return ret; }
+ if(arr[0]){
+ ret.push(arr[0]);
+ }
+ if(arr.length < 2){ return ret; }
+
+ _zipIdx++;
+
+ // we have to fork here for IE and XML docs because we can't set
+ // expandos on their nodes (apparently). *sigh*
+ if(d.isIE && caseSensitive){
+ var szidx = _zipIdx+"";
+ arr[0].setAttribute(_zipIdxName, szidx);
+ for(var x = 1, te; te = arr[x]; x++){
+ if(arr[x].getAttribute(_zipIdxName) != szidx){
+ ret.push(te);
+ }
+ te.setAttribute(_zipIdxName, szidx);
+ }
+ }else if(d.isIE && arr.commentStrip){
+ try{
+ for(var x = 1, te; te = arr[x]; x++){
+ if(_isElement(te)){
+ ret.push(te);
+ }
+ }
+ }catch(e){ /* squelch */ }
+ }else{
+ if(arr[0]){ arr[0][_zipIdxName] = _zipIdx; }
+ for(var x = 1, te; te = arr[x]; x++){
+ if(arr[x][_zipIdxName] != _zipIdx){
+ ret.push(te);
+ }
+ te[_zipIdxName] = _zipIdx;
+ }
+ }
+ 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`, and `:only-child` positional selectors
+ // * `:empty` content emtpy selector
+ // * `:checked` pseudo 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
+ // manipulation 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`
+ // * `:*-of-type` pseudo selectors
+ //
+ // dojo.query and XML Documents:
+ // -----------------------------
+ //
+ // `dojo.query` (as of dojo 1.2) supports searching XML documents
+ // in a case-sensitive manner. If an HTML document is served with
+ // a doctype that forces case-sensitivity (e.g., XHTML 1.1
+ // Strict), dojo.query() will detect this and "do the right
+ // thing". Case sensitivity is dependent upon the document being
+ // searched and not the query used. It is therefore possible to
+ // use case-sensitive queries on strict sub-documents (iframes,
+ // etc.) or XML documents while still assuming case-insensitivity
+ // for a host/root document.
+ //
+ // Non-selector Queries:
+ // ---------------------
+ //
+ // If something other than a String is passed for the query,
+ // `dojo.query` will return a new `dojo.NodeList` instance
+ // constructed from that parameter alone and all further
+ // processing will stop. This means that if you have a reference
+ // to a node or NodeList, you can quickly construct a new NodeList
+ // from the original by calling `dojo.query(node)` or
+ // `dojo.query(list)`.
+ //
+ // query:
+ // The CSS3 expression to match against. For details on the syntax of
+ // CSS3 selectors, see <http://www.w3.org/TR/css3-selectors/#selectors>
+ // root:
+ // A DOMNode (or node id) to scope the search from. Optional.
+ // returns: dojo.NodeList
+ // An instance of `dojo.NodeList`. Many methods are available on
+ // NodeLists for searching, iterating, manipulating, and handling
+ // events on the matched nodes in the returned list.
+ // example:
+ // search the entire document for elements with the class "foo":
+ // | dojo.query(".foo");
+ // these elements will match:
+ // | <span class="foo"></span>
+ // | <span class="foo bar"></span>
+ // | <p class="thud foo"></p>
+ // example:
+ // search the entire document for elements with the classes "foo" *and* "bar":
+ // | dojo.query(".foo.bar");
+ // these elements will match:
+ // | <span class="foo bar"></span>
+ // while these will not:
+ // | <span class="foo"></span>
+ // | <p class="thud foo"></p>
+ // example:
+ // find `<span>` elements which are descendants of paragraphs and
+ // which have a "highlighted" class:
+ // | dojo.query("p span.highlighted");
+ // the innermost span in this fragment matches:
+ // | <p class="foo">
+ // | <span>...
+ // | <span class="highlighted foo bar">...</span>
+ // | </span>
+ // | </p>
+ // example:
+ // set an "odd" class on all odd table rows inside of the table
+ // `#tabular_data`, using the `>` (direct child) selector to avoid
+ // affecting any nested tables:
+ // | dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
+ // example:
+ // remove all elements with the class "error" from the document
+ // and store them in a list:
+ // | var errors = dojo.query(".error").orphan();
+ // example:
+ // add an onclick handler to every submit button in the document
+ // which causes the form to be sent via Ajax instead:
+ // | dojo.query("input[type='submit']").onclick(function(e){
+ // | dojo.stopEvent(e); // prevent sending the form
+ // | var btn = e.target;
+ // | dojo.xhrPost({
+ // | form: btn.form,
+ // | load: function(data){
+ // | // replace the form with the response
+ // | var div = dojo.doc.createElement("div");
+ // | dojo.place(div, btn.form, "after");
+ // | div.innerHTML = data;
+ // | dojo.style(btn.form, "display", "none");
+ // | }
+ // | });
+ // | });
+
+ //Set list constructor to desired value. This can change
+ //between calls, so always re-assign here.
+ qlc = d._NodeListCtor;
+
+ if(!query){
+ return new qlc();
+ }
+
+ if(query.constructor == qlc){
+ return query;
+ }
+ if(typeof query != "string"){ // inline'd type check
+ return new qlc(query); // dojo.NodeList
+ }
+ if(typeof root == "string"){ // inline'd type check
+ root = d.byId(root);
+ if(!root){ return new qlc(); }
+ }
+
+ root = root||getDoc();
+ var od = root.ownerDocument||root.documentElement;
+
+ // throw the big case sensitivity switch
+
+ // NOTE:
+ // Opera in XHTML mode doesn't detect case-sensitivity correctly
+ // and it's not clear that there's any way to test for it
+ caseSensitive = (root.contentType && root.contentType=="application/xml") ||
+ (d.isOpera && (root.doctype || od.toString() == "[object XMLDocument]")) ||
+ (!!od) &&
+ (d.isIE ? od.xml : (root.xmlVersion||od.xmlVersion));
+
+ // NOTE:
+ // adding "true" as the 2nd argument to getQueryFunc is useful for
+ // testing the DOM branch without worrying about the
+ // behavior/performance of the QSA branch.
+ var r = getQueryFunc(query)(root);
+
+ // FIXME:
+ // need to investigate this branch WRT #8074 and #8075
+ if(r && r.nozip && !qlc._wrap){
+ return r;
+ }
+ return _zip(r); // dojo.NodeList
+ }
+
+ // FIXME: need to add infrastructure for post-filtering pseudos, ala :last
+ d.query.pseudos = pseudos;
+
+ // one-off function for filtering a NodeList based on a simple selector
+ d._filterQueryResult = function(nodeList, simpleFilter){
+ var tmpNodeList = new d._NodeListCtor();
+ var filterFunc = getSimpleFilterFunc(getQueryParts(simpleFilter)[0]);
+ for(var x = 0, te; te = nodeList[x]; x++){
+ if(filterFunc(te)){ tmpNodeList.push(te); }
+ }
+ return tmpNodeList;
+ }
})(this["queryPortability"]||this["acme"]||dojo);
+
+/*
+*/
+
}
diff --git a/lib/dojo/_base/window.js b/lib/dojo/_base/window.js
index 44239d92c..5c6e2e952 100644
--- a/lib/dojo/_base/window.js
+++ b/lib/dojo/_base/window.js
@@ -5,45 +5,104 @@
*/
-if(!dojo._hasResource["dojo._base.window"]){
-dojo._hasResource["dojo._base.window"]=true;
+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.doc=window["document"]||null;
-dojo.body=function(){
-return dojo.doc.body||dojo.doc.getElementsByTagName("body")[0];
-};
-dojo.setContext=function(_1,_2){
-dojo.global=_1;
-dojo.doc=_2;
-};
-dojo.withGlobal=function(_3,_4,_5,_6){
-var _7=dojo.global;
-try{
-dojo.global=_3;
-return dojo.withDoc.call(null,_3.document,_4,_5,_6);
+
+/*=====
+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'));
}
-finally{
-dojo.global=_7;
+=====*/
+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.withDoc=function(_8,_9,_a,_b){
-var _c=dojo.doc,_d=dojo._bodyLtr,_e=dojo.isQuirks;
-try{
-dojo.doc=_8;
-delete dojo._bodyLtr;
-dojo.isQuirks=dojo.doc.compatMode=="BackCompat";
-if(_a&&typeof _9=="string"){
-_9=_a[_9];
-}
-return _9.apply(_a,_b||[]);
-}
-finally{
-dojo.doc=_c;
-delete dojo._bodyLtr;
-if(_d!==undefined){
-dojo._bodyLtr=_d;
-}
-dojo.isQuirks=_e;
+
+dojo.withGlobal = function( /*Object*/globalObject,
+ /*Function*/callback,
+ /*Object?*/thisObject,
+ /*Array?*/cbArguments){
+ // summary:
+ // Invoke callback with globalObject as dojo.global and
+ // globalObject.document as dojo.doc.
+ // description:
+ // Invoke callback with globalObject as dojo.global and
+ // globalObject.document as dojo.doc. If provided, globalObject
+ // will be executed in the context of object thisObject
+ // When callback() returns or throws an error, the dojo.global
+ // and dojo.doc will be restored to its previous state.
+
+ var oldGlob = dojo.global;
+ try{
+ dojo.global = globalObject;
+ return dojo.withDoc.call(null, globalObject.document, callback, thisObject, cbArguments);
+ }finally{
+ dojo.global = oldGlob;
+ }
}
+
+dojo.withDoc = function( /*DocumentElement*/documentObject,
+ /*Function*/callback,
+ /*Object?*/thisObject,
+ /*Array?*/cbArguments){
+ // summary:
+ // Invoke callback with documentObject as dojo.doc.
+ // description:
+ // Invoke callback with documentObject as dojo.doc. If provided,
+ // callback will be executed in the context of object thisObject
+ // When callback() returns or throws an error, the dojo.doc will
+ // be restored to its previous state.
+
+ var oldDoc = dojo.doc,
+ oldLtr = dojo._bodyLtr,
+ oldQ = dojo.isQuirks;
+
+ try{
+ dojo.doc = documentObject;
+ delete dojo._bodyLtr; // uncache
+ dojo.isQuirks = dojo.doc.compatMode == "BackCompat"; // no need to check for QuirksMode which was Opera 7 only
+
+ if(thisObject && typeof callback == "string"){
+ callback = thisObject[callback];
+ }
+
+ return callback.apply(thisObject, cbArguments || []);
+ }finally{
+ dojo.doc = oldDoc;
+ delete dojo._bodyLtr; // in case it was undefined originally, and set to true/false by the alternate document
+ if(oldLtr !== undefined){ dojo._bodyLtr = oldLtr; }
+ dojo.isQuirks = oldQ;
+ }
};
+
+
}
diff --git a/lib/dojo/_base/xhr.js b/lib/dojo/_base/xhr.js
index 5823371cf..818f8e418 100644
--- a/lib/dojo/_base/xhr.js
+++ b/lib/dojo/_base/xhr.js
@@ -5,433 +5,937 @@
*/
-if(!dojo._hasResource["dojo._base.xhr"]){
-dojo._hasResource["dojo._base.xhr"]=true;
+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 _1=dojo,_2=_1.config;
-function _3(_4,_5,_6){
-if(_6===null){
-return;
-}
-var _7=_4[_5];
-if(typeof _7=="string"){
-_4[_5]=[_7,_6];
-}else{
-if(_1.isArray(_7)){
-_7.push(_6);
-}else{
-_4[_5]=_6;
-}
-}
-};
-dojo.fieldToObject=function(_8){
-var _9=null;
-var _a=_1.byId(_8);
-if(_a){
-var _b=_a.name;
-var _c=(_a.type||"").toLowerCase();
-if(_b&&_c&&!_a.disabled){
-if(_c=="radio"||_c=="checkbox"){
-if(_a.checked){
-_9=_a.value;
-}
-}else{
-if(_a.multiple){
-_9=[];
-_1.query("option",_a).forEach(function(_d){
-if(_d.selected){
-_9.push(_d.value);
-}
-});
-}else{
-_9=_a.value;
-}
-}
-}
-}
-return _9;
-};
-dojo.formToObject=function(_e){
-var _f={};
-var _10="file|submit|image|reset|button|";
-_1.forEach(dojo.byId(_e).elements,function(_11){
-var _12=_11.name;
-var _13=(_11.type||"").toLowerCase();
-if(_12&&_13&&_10.indexOf(_13)==-1&&!_11.disabled){
-_3(_f,_12,_1.fieldToObject(_11));
-if(_13=="image"){
-_f[_12+".x"]=_f[_12+".y"]=_f[_12].x=_f[_12].y=0;
-}
-}
-});
-return _f;
-};
-dojo.objectToQuery=function(map){
-var enc=encodeURIComponent;
-var _14=[];
-var _15={};
-for(var _16 in map){
-var _17=map[_16];
-if(_17!=_15[_16]){
-var _18=enc(_16)+"=";
-if(_1.isArray(_17)){
-for(var i=0;i<_17.length;i++){
-_14.push(_18+enc(_17[i]));
-}
-}else{
-_14.push(_18+enc(_17));
-}
-}
-}
-return _14.join("&");
-};
-dojo.formToQuery=function(_19){
-return _1.objectToQuery(_1.formToObject(_19));
-};
-dojo.formToJson=function(_1a,_1b){
-return _1.toJson(_1.formToObject(_1a),_1b);
-};
-dojo.queryToObject=function(str){
-var ret={};
-var qp=str.split("&");
-var dec=decodeURIComponent;
-_1.forEach(qp,function(_1c){
-if(_1c.length){
-var _1d=_1c.split("=");
-var _1e=dec(_1d.shift());
-var val=dec(_1d.join("="));
-if(typeof ret[_1e]=="string"){
-ret[_1e]=[ret[_1e]];
-}
-if(_1.isArray(ret[_1e])){
-ret[_1e].push(val);
-}else{
-ret[_1e]=val;
-}
-}
-});
-return ret;
-};
-dojo._blockAsync=false;
-var _1f=_1._contentHandlers=dojo.contentHandlers={text:function(xhr){
-return xhr.responseText;
-},json:function(xhr){
-return _1.fromJson(xhr.responseText||null);
-},"json-comment-filtered":function(xhr){
-if(!dojo.config.useCommentedJson){
-console.warn("Consider using the standard mimetype:application/json."+" json-commenting can introduce security issues. To"+" decrease the chances of hijacking, use the standard the 'json' handler and"+" prefix your json with: {}&&\n"+"Use djConfig.useCommentedJson=true to turn off this message.");
-}
-var _20=xhr.responseText;
-var _21=_20.indexOf("/*");
-var _22=_20.lastIndexOf("*/");
-if(_21==-1||_22==-1){
-throw new Error("JSON was not comment filtered");
-}
-return _1.fromJson(_20.substring(_21+2,_22));
-},javascript:function(xhr){
-return _1.eval(xhr.responseText);
-},xml:function(xhr){
-var _23=xhr.responseXML;
-if(_1.isIE&&(!_23||!_23.documentElement)){
-var ms=function(n){
-return "MSXML"+n+".DOMDocument";
-};
-var dp=["Microsoft.XMLDOM",ms(6),ms(4),ms(3),ms(2)];
-_1.some(dp,function(p){
-try{
-var dom=new ActiveXObject(p);
-dom.async=false;
-dom.loadXML(xhr.responseText);
-_23=dom;
-}
-catch(e){
-return false;
-}
-return true;
-});
-}
-return _23;
-},"json-comment-optional":function(xhr){
-if(xhr.responseText&&/^[^{\[]*\/\*/.test(xhr.responseText)){
-return _1f["json-comment-filtered"](xhr);
-}else{
-return _1f["json"](xhr);
-}
-}};
-dojo._ioSetArgs=function(_24,_25,_26,_27){
-var _28={args:_24,url:_24.url};
-var _29=null;
-if(_24.form){
-var _2a=_1.byId(_24.form);
-var _2b=_2a.getAttributeNode("action");
-_28.url=_28.url||(_2b?_2b.value:null);
-_29=_1.formToObject(_2a);
-}
-var _2c=[{}];
-if(_29){
-_2c.push(_29);
-}
-if(_24.content){
-_2c.push(_24.content);
-}
-if(_24.preventCache){
-_2c.push({"dojo.preventCache":new Date().valueOf()});
-}
-_28.query=_1.objectToQuery(_1.mixin.apply(null,_2c));
-_28.handleAs=_24.handleAs||"text";
-var d=new _1.Deferred(_25);
-d.addCallbacks(_26,function(_2d){
-return _27(_2d,d);
-});
-var ld=_24.load;
-if(ld&&_1.isFunction(ld)){
-d.addCallback(function(_2e){
-return ld.call(_24,_2e,_28);
-});
-}
-var err=_24.error;
-if(err&&_1.isFunction(err)){
-d.addErrback(function(_2f){
-return err.call(_24,_2f,_28);
-});
-}
-var _30=_24.handle;
-if(_30&&_1.isFunction(_30)){
-d.addBoth(function(_31){
-return _30.call(_24,_31,_28);
-});
-}
-if(_2.ioPublish&&_1.publish&&_28.args.ioPublish!==false){
-d.addCallbacks(function(res){
-_1.publish("/dojo/io/load",[d,res]);
-return res;
-},function(res){
-_1.publish("/dojo/io/error",[d,res]);
-return res;
-});
-d.addBoth(function(res){
-_1.publish("/dojo/io/done",[d,res]);
-return res;
-});
-}
-d.ioArgs=_28;
-return d;
-};
-var _32=function(dfd){
-dfd.canceled=true;
-var xhr=dfd.ioArgs.xhr;
-var _33=typeof xhr.abort;
-if(_33=="function"||_33=="object"||_33=="unknown"){
-xhr.abort();
-}
-var err=dfd.ioArgs.error;
-if(!err){
-err=new Error("xhr cancelled");
-err.dojoType="cancel";
-}
-return err;
-};
-var _34=function(dfd){
-var ret=_1f[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
-return ret===undefined?null:ret;
-};
-var _35=function(_36,dfd){
-if(!dfd.ioArgs.args.failOk){
-console.error(_36);
-}
-return _36;
-};
-var _37=null;
-var _38=[];
-var _39=0;
-var _3a=function(dfd){
-if(_39<=0){
-_39=0;
-if(_2.ioPublish&&_1.publish&&(!dfd||dfd&&dfd.ioArgs.args.ioPublish!==false)){
-_1.publish("/dojo/io/stop");
-}
-}
-};
-var _3b=function(){
-var now=(new Date()).getTime();
-if(!_1._blockAsync){
-for(var i=0,tif;i<_38.length&&(tif=_38[i]);i++){
-var dfd=tif.dfd;
-var _3c=function(){
-if(!dfd||dfd.canceled||!tif.validCheck(dfd)){
-_38.splice(i--,1);
-_39-=1;
-}else{
-if(tif.ioCheck(dfd)){
-_38.splice(i--,1);
-tif.resHandle(dfd);
-_39-=1;
-}else{
-if(dfd.startTime){
-if(dfd.startTime+(dfd.ioArgs.args.timeout||0)<now){
-_38.splice(i--,1);
-var err=new Error("timeout exceeded");
-err.dojoType="timeout";
-dfd.errback(err);
-dfd.cancel();
-_39-=1;
-}
-}
-}
-}
-};
-if(dojo.config.debugAtAllCosts){
-_3c.call(this);
-}else{
-try{
-_3c.call(this);
-}
-catch(e){
-dfd.errback(e);
-}
-}
-}
-}
-_3a(dfd);
-if(!_38.length){
-clearInterval(_37);
-_37=null;
-return;
-}
-};
-dojo._ioCancelAll=function(){
-try{
-_1.forEach(_38,function(i){
-try{
-i.dfd.cancel();
-}
-catch(e){
-}
-});
-}
-catch(e){
-}
-};
-if(_1.isIE){
-_1.addOnWindowUnload(_1._ioCancelAll);
-}
-_1._ioNotifyStart=function(dfd){
-if(_2.ioPublish&&_1.publish&&dfd.ioArgs.args.ioPublish!==false){
-if(!_39){
-_1.publish("/dojo/io/start");
-}
-_39+=1;
-_1.publish("/dojo/io/send",[dfd]);
-}
-};
-_1._ioWatch=function(dfd,_3d,_3e,_3f){
-var _40=dfd.ioArgs.args;
-if(_40.timeout){
-dfd.startTime=(new Date()).getTime();
-}
-_38.push({dfd:dfd,validCheck:_3d,ioCheck:_3e,resHandle:_3f});
-if(!_37){
-_37=setInterval(_3b,50);
-}
-if(_40.sync){
-_3b();
-}
-};
-var _41="application/x-www-form-urlencoded";
-var _42=function(dfd){
-return dfd.ioArgs.xhr.readyState;
-};
-var _43=function(dfd){
-return 4==dfd.ioArgs.xhr.readyState;
-};
-var _44=function(dfd){
-var xhr=dfd.ioArgs.xhr;
-if(_1._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);
-}
-};
-dojo._ioAddQueryToUrl=function(_45){
-if(_45.query.length){
-_45.url+=(_45.url.indexOf("?")==-1?"?":"&")+_45.query;
-_45.query=null;
-}
-};
-dojo.xhr=function(_46,_47,_48){
-var dfd=_1._ioSetArgs(_47,_32,_34,_35);
-var _49=dfd.ioArgs;
-var xhr=_49.xhr=_1._xhrObj(_49.args);
-if(!xhr){
-dfd.cancel();
-return dfd;
-}
-if("postData" in _47){
-_49.query=_47.postData;
-}else{
-if("putData" in _47){
-_49.query=_47.putData;
-}else{
-if("rawBody" in _47){
-_49.query=_47.rawBody;
-}else{
-if((arguments.length>2&&!_48)||"POST|PUT".indexOf(_46.toUpperCase())==-1){
-_1._ioAddQueryToUrl(_49);
-}
-}
-}
-}
-xhr.open(_46,_49.url,_47.sync!==true,_47.user||undefined,_47.password||undefined);
-if(_47.headers){
-for(var hdr in _47.headers){
-if(hdr.toLowerCase()==="content-type"&&!_47.contentType){
-_47.contentType=_47.headers[hdr];
-}else{
-if(_47.headers[hdr]){
-xhr.setRequestHeader(hdr,_47.headers[hdr]);
-}
-}
-}
-}
-xhr.setRequestHeader("Content-Type",_47.contentType||_41);
-if(!_47.headers||!("X-Requested-With" in _47.headers)){
-xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");
-}
-_1._ioNotifyStart(dfd);
-if(dojo.config.debugAtAllCosts){
-xhr.send(_49.query);
-}else{
-try{
-xhr.send(_49.query);
-}
-catch(e){
-_49.error=e;
-dfd.cancel();
-}
-}
-_1._ioWatch(dfd,_42,_43,_44);
-xhr=null;
-return dfd;
-};
-dojo.xhrGet=function(_4a){
-return _1.xhr("GET",_4a);
-};
-dojo.rawXhrPost=dojo.xhrPost=function(_4b){
-return _1.xhr("POST",_4b,true);
-};
-dojo.rawXhrPut=dojo.xhrPut=function(_4c){
-return _1.xhr("PUT",_4c,true);
-};
-dojo.xhrDelete=function(_4d){
-return _1.xhr("DELETE",_4d);
-};
+ var _d = dojo, cfg = _d.config;
+
+ function setValue(/*Object*/obj, /*String*/name, /*String*/value){
+ //summary:
+ // For the named 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.
+
+ //Skip it if there is no value
+ if(value === null){
+ return;
+ }
+
+ var val = obj[name];
+ if(typeof val == "string"){ // inline'd type check
+ obj[name] = [val, value];
+ }else if(_d.isArray(val)){
+ val.push(value);
+ }else{
+ obj[name] = value;
+ }
+ }
+
+ dojo.fieldToObject = function(/*DOMNode||String*/ inputNode){
+ // summary:
+ // Serialize a form field to a JavaScript object.
+ //
+ // description:
+ // Returns the value encoded in a form field as
+ // as a string or an array of strings. Disabled form elements
+ // and unchecked radio and checkboxes are skipped. Multi-select
+ // elements are returned as an array of string values.
+ var ret = null;
+ var item = _d.byId(inputNode);
+ if(item){
+ var _in = item.name;
+ var type = (item.type||"").toLowerCase();
+ if(_in && type && !item.disabled){
+ if(type == "radio" || type == "checkbox"){
+ if(item.checked){ ret = item.value }
+ }else if(item.multiple){
+ ret = [];
+ _d.query("option", item).forEach(function(opt){
+ if(opt.selected){
+ ret.push(opt.value);
+ }
+ });
+ }else{
+ ret = item.value;
+ }
+ }
+ }
+ return ret; // Object
+ }
+
+ dojo.formToObject = function(/*DOMNode||String*/ formNode){
+ // summary:
+ // Serialize a form node to a JavaScript object.
+ // description:
+ // 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.
+ //
+ // example:
+ // This form:
+ // | <form id="test_form">
+ // | <input type="text" name="blah" value="blah">
+ // | <input type="text" name="no_value" value="blah" disabled>
+ // | <input type="button" name="no_value2" value="blah">
+ // | <select type="select" multiple name="multi" size="5">
+ // | <option value="blah">blah</option>
+ // | <option value="thud" selected>thud</option>
+ // | <option value="thonk" selected>thonk</option>
+ // | </select>
+ // | </form>
+ //
+ // yields this object structure as the result of a call to
+ // formToObject():
+ //
+ // | {
+ // | blah: "blah",
+ // | multi: [
+ // | "thud",
+ // | "thonk"
+ // | ]
+ // | };
+
+ var ret = {};
+ var exclude = "file|submit|image|reset|button|";
+ _d.forEach(dojo.byId(formNode).elements, function(item){
+ var _in = item.name;
+ var type = (item.type||"").toLowerCase();
+ if(_in && type && exclude.indexOf(type) == -1 && !item.disabled){
+ setValue(ret, _in, _d.fieldToObject(item));
+ 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:
+ // Create 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:
+ // Create an object representing a de-serialized query section of a
+ // URL. Query keys with multiple values are returned in an array.
+ //
+ // example:
+ // 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(typeof ret[name] == "string"){ // inline'd type check
+ ret[name] = [ret[name]];
+ }
+
+ if(_d.isArray(ret[name])){
+ ret[name].push(val);
+ }else{
+ ret[name] = val;
+ }
+ }
+ });
+ return ret; // Object
+ }
+
+ // 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;
+
+ // MOW: remove dojo._contentHandlers alias in 2.0
+ var handlers = _d._contentHandlers = dojo.contentHandlers = {
+ // summary:
+ // A map of availble XHR transport handle types. Name matches the
+ // `handleAs` attribute passed to XHR calls.
+ //
+ // description:
+ // A map of availble XHR transport handle types. Name matches the
+ // `handleAs` attribute passed to XHR calls. Each contentHandler is
+ // called, passing the xhr object for manipulation. The return value
+ // from the contentHandler will be passed to the `load` or `handle`
+ // functions defined in the original xhr call.
+ //
+ // example:
+ // Creating a custom content-handler:
+ // | dojo.contentHandlers.makeCaps = function(xhr){
+ // | return xhr.responseText.toUpperCase();
+ // | }
+ // | // and later:
+ // | dojo.xhrGet({
+ // | url:"foo.txt",
+ // | handleAs:"makeCaps",
+ // | load: function(data){ /* data is a toUpper version of foo.txt */ }
+ // | });
+
+ text: function(xhr){
+ // summary: A contentHandler which simply returns the plaintext response data
+ return xhr.responseText;
+ },
+ json: function(xhr){
+ // summary: A contentHandler which returns a JavaScript object created from the response data
+ return _d.fromJson(xhr.responseText || null);
+ },
+ "json-comment-filtered": function(xhr){
+ // summary: A contentHandler which expects comment-filtered JSON.
+ // description:
+ // A contentHandler which expects comment-filtered JSON.
+ // the json-comment-filtered option was implemented to prevent
+ // "JavaScript Hijacking", but it is less secure than standard JSON. Use
+ // standard JSON instead. JSON prefixing can be used to subvert hijacking.
+ //
+ // Will throw a notice suggesting to use application/json mimetype, as
+ // json-commenting can introduce security issues. To decrease the chances of hijacking,
+ // use the standard `json` contentHandler, and prefix your "JSON" with: {}&&
+ //
+ // use djConfig.useCommentedJson = true to turn off the notice
+ if(!dojo.config.useCommentedJson){
+ console.warn("Consider using the standard mimetype:application/json."
+ + " json-commenting can introduce security issues. To"
+ + " decrease the chances of hijacking, use the standard the 'json' handler and"
+ + " prefix your json with: {}&&\n"
+ + "Use djConfig.useCommentedJson=true to turn off this message.");
+ }
+
+ 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 _d.fromJson(value.substring(cStartIdx+2, cEndIdx));
+ },
+ javascript: function(xhr){
+ // summary: A contentHandler which evaluates the response data, expecting it to be valid JavaScript
+
+ // FIXME: try Moz and IE specific eval variants?
+ return _d.eval(xhr.responseText);
+ },
+ xml: function(xhr){
+ // summary: A contentHandler returning an XML Document parsed from the response data
+ var result = xhr.responseXML;
+ if(_d.isIE && (!result || !result.documentElement)){
+ //WARNING: this branch used by the xml handling in dojo.io.iframe,
+ //so be sure to test dojo.io.iframe if making changes below.
+ var ms = function(n){ return "MSXML" + n + ".DOMDocument"; }
+ var dp = ["Microsoft.XMLDOM", ms(6), ms(4), ms(3), ms(2)];
+ _d.some(dp, function(p){
+ try{
+ var dom = new ActiveXObject(p);
+ dom.async = false;
+ dom.loadXML(xhr.responseText);
+ result = dom;
+ }catch(e){ return false; }
+ return true;
+ });
+ }
+ return result; // DOMDocument
+ },
+ "json-comment-optional": function(xhr){
+ // summary: A contentHandler which checks the presence of comment-filtered JSON and
+ // alternates between the `json` and `json-comment-filtered` contentHandlers.
+ if(xhr.responseText && /^[^{\[]*\/\*/.test(xhr.responseText)){
+ return handlers["json-comment-filtered"](xhr);
+ }else{
+ 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).
+ // rawBody: String?
+ // Sets the raw body for an HTTP request. If this is used, then the content
+ // property is ignored. This is mostly useful for HTTP methods that have
+ // a body to their requests, like PUT or POST. This property can be used instead
+ // of postData and putData for dojo.rawXhrPost and dojo.rawXhrPut respectively.
+ // ioPublish: Boolean?
+ // Set this explicitly to false to prevent publishing of topics related to
+ // IO operations. Otherwise, if djConfig.ioPublish is set to true, topics
+ // will be published via dojo.publish for different phases of an IO operation.
+ // See dojo.__IoPublish for a list of topics that are published.
+ // load: Function?
+ // This function will be
+ // called on a successful HTTP response code.
+ // error: Function?
+ // This function will
+ // be called when the request fails due to a network or server error, the url
+ // is invalid, etc. It will also be called if the load or handle callback throws an
+ // exception, unless djConfig.debugAtAllCosts is true. This allows deployed applications
+ // to continue to run even when a logic error happens in the callback, while making
+ // it easier to troubleshoot while in debug mode.
+ // handle: Function?
+ // This function will
+ // be called at the end of every request, whether or not an error occurs.
+ this.url = url;
+ this.content = content;
+ this.timeout = timeout;
+ this.form = form;
+ this.preventCache = preventCache;
+ this.handleAs = handleAs;
+ this.ioPublish = ioPublish;
+ this.load = function(response, ioArgs){
+ // ioArgs: dojo.__IoCallbackArgs
+ // Provides additional information about the request.
+ // response: Object
+ // The response in the format as defined with handleAs.
+ }
+ this.error = function(response, ioArgs){
+ // ioArgs: dojo.__IoCallbackArgs
+ // Provides additional information about the request.
+ // response: Object
+ // The response in the format as defined with handleAs.
+ }
+ this.handle = function(loadOrError, response, ioArgs){
+ // loadOrError: String
+ // Provides a string that tells you whether this function
+ // was called because of success (load) or failure (error).
+ // response: Object
+ // The response in the format as defined with handleAs.
+ // ioArgs: dojo.__IoCallbackArgs
+ // Provides additional information about the request.
+ }
+ }
+ =====*/
+
+ /*=====
+ 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.__IoPublish = function(){
+ // summary:
+ // This is a list of IO topics that can be published
+ // if djConfig.ioPublish is set to true. IO topics can be
+ // published for any Input/Output, network operation. So,
+ // dojo.xhr, dojo.io.script and dojo.io.iframe can all
+ // trigger these topics to be published.
+ // start: String
+ // "/dojo/io/start" is sent when there are no outstanding IO
+ // requests, and a new IO request is started. No arguments
+ // are passed with this topic.
+ // send: String
+ // "/dojo/io/send" is sent whenever a new IO request is started.
+ // It passes the dojo.Deferred for the request with the topic.
+ // load: String
+ // "/dojo/io/load" is sent whenever an IO request has loaded
+ // successfully. It passes the response and the dojo.Deferred
+ // for the request with the topic.
+ // error: String
+ // "/dojo/io/error" is sent whenever an IO request has errored.
+ // It passes the error and the dojo.Deferred
+ // for the request with the topic.
+ // done: String
+ // "/dojo/io/done" is sent whenever an IO request has completed,
+ // either by loading or by erroring. It passes the error and
+ // the dojo.Deferred for the request with the topic.
+ // stop: String
+ // "/dojo/io/stop" is sent when all outstanding IO requests have
+ // finished. No arguments are passed with this topic.
+ this.start = "/dojo/io/start";
+ this.send = "/dojo/io/send";
+ this.load = "/dojo/io/load";
+ this.error = "/dojo/io/error";
+ this.done = "/dojo/io/done";
+ this.stop = "/dojo/io/stop";
+ }
+ =====*/
+
+
+ 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);
+ });
+ }
+
+ //Plug in topic publishing, if dojo.publish is loaded.
+ if(cfg.ioPublish && _d.publish && ioArgs.args.ioPublish !== false){
+ d.addCallbacks(
+ function(res){
+ _d.publish("/dojo/io/load", [d, res]);
+ return res;
+ },
+ function(res){
+ _d.publish("/dojo/io/error", [d, res]);
+ return res;
+ }
+ );
+ d.addBoth(function(res){
+ _d.publish("/dojo/io/done", [d, res]);
+ return res;
+ });
+ }
+
+ 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 == "object" || _at == "unknown"){
+ xhr.abort();
+ }
+ var err = dfd.ioArgs.error;
+ if(!err){
+ err = new Error("xhr cancelled");
+ err.dojoType="cancel";
+ }
+ return err;
+ }
+ var _deferredOk = function(/*Deferred*/dfd){
+ // summary: okHandler function for dojo._ioSetArgs call.
+
+ var ret = handlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
+ return ret === undefined ? null : ret;
+ }
+ var _deferError = function(/*Error*/error, /*Deferred*/dfd){
+ // summary: errHandler function for dojo._ioSetArgs call.
+
+ if(!dfd.ioArgs.args.failOk){
+ console.error(error);
+ }
+ return error;
+ }
+
+ // 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 = [];
+
+
+ //Use a separate count for knowing if we are starting/stopping io calls.
+ //Cannot use _inFlight.length since it can change at a different time than
+ //when we want to do this kind of test. We only want to decrement the count
+ //after a callback/errback has finished, since the callback/errback should be
+ //considered as part of finishing a request.
+ var _pubCount = 0;
+ var _checkPubCount = function(dfd){
+ if(_pubCount <= 0){
+ _pubCount = 0;
+ if(cfg.ioPublish && _d.publish && (!dfd || dfd && dfd.ioArgs.args.ioPublish !== false)){
+ _d.publish("/dojo/io/stop");
+ }
+ }
+ };
+
+ 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;
+ var func = function(){
+ if(!dfd || dfd.canceled || !tif.validCheck(dfd)){
+ _inFlight.splice(i--, 1);
+ _pubCount -= 1;
+ }else if(tif.ioCheck(dfd)){
+ _inFlight.splice(i--, 1);
+ tif.resHandle(dfd);
+ _pubCount -= 1;
+ }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();
+ _pubCount -= 1;
+ }
+ }
+ };
+ if(dojo.config.debugAtAllCosts){
+ func.call(this);
+ }else{
+ try{
+ func.call(this);
+ }catch(e){
+ dfd.errback(e);
+ }
+ }
+ }
+ }
+
+ _checkPubCount(dfd);
+
+ 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){
+ try{
+ i.dfd.cancel();
+ }catch(e){/*squelch*/}
+ });
+ }catch(e){/*squelch*/}
+ }
+
+ //Automatically call cancel all io calls on unload
+ //in IE for trac issue #2357.
+ if(_d.isIE){
+ _d.addOnWindowUnload(_d._ioCancelAll);
+ }
+
+ _d._ioNotifyStart = function(/*Deferred*/dfd){
+ // summary:
+ // If dojo.publish is available, publish topics
+ // about the start of a request queue and/or the
+ // the beginning of request.
+ // description:
+ // Used by IO transports. An IO transport should
+ // call this method before making the network connection.
+ if(cfg.ioPublish && _d.publish && dfd.ioArgs.args.ioPublish !== false){
+ if(!_pubCount){
+ _d.publish("/dojo/io/start");
+ }
+ _pubCount += 1;
+ _d.publish("/dojo/io/send", [dfd]);
+ }
+ }
+
+ _d._ioWatch = function(dfd, validCheck, ioCheck, resHandle){
+ // summary:
+ // Watches the io request represented by dfd to see if it completes.
+ // dfd: Deferred
+ // The Deferred object to watch.
+ // validCheck: Function
+ // Function used to check if the IO request is still valid. Gets the dfd
+ // object as its only argument.
+ // ioCheck: Function
+ // Function used to check if basic IO call worked. Gets the dfd
+ // object as its only argument.
+ // resHandle: Function
+ // Function used to process response. Gets the dfd
+ // object as its only argument.
+ var args = dfd.ioArgs.args;
+ if(args.timeout){
+ dfd.startTime = (new Date()).getTime();
+ }
+
+ _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle});
+ if(!_inFlightIntvl){
+ _inFlightIntvl = setInterval(_watchInFlight, 50);
+ }
+ // handle sync requests
+ //A weakness: async calls in flight
+ //could have their handlers called as part of the
+ //_watchInFlight call, before the sync's callbacks
+ // are called.
+ if(args.sync){
+ _watchInFlight();
+ }
+ }
+
+ 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);
+ }
+ }
+
+ 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. See `dojo.contentHandlers`
+ // 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.
+ // failOk: Boolean?
+ // false is default. Indicates whether a request should be
+ // allowed to fail (and therefore no console error message in
+ // the event of a failure)
+ this.handleAs = handleAs;
+ this.sync = sync;
+ this.headers = headers;
+ this.failOk = failOk;
+ }
+ });
+ =====*/
+
+ dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){
+ // summary:
+ // Sends an HTTP request with the given method.
+ // description:
+ // Sends an HTTP request with the given method.
+ // See also 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.
+ // method:
+ // HTTP method to be used, such as GET, POST, PUT, DELETE. Should be uppercase.
+ // hasBody:
+ // If the request has an HTTP body, then pass true for hasBody.
+
+ //Make the Deferred object for this xhr request.
+ var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError);
+ var ioArgs = dfd.ioArgs;
+
+ //Pass the args to _xhrObj, to allow alternate XHR calls based specific calls, like
+ //the one used for iframe proxies.
+ var xhr = ioArgs.xhr = _d._xhrObj(ioArgs.args);
+ //If XHR factory fails, cancel the deferred.
+ if(!xhr){
+ dfd.cancel();
+ return dfd;
+ }
+
+ //Allow for specifying the HTTP body completely.
+ if("postData" in args){
+ ioArgs.query = args.postData;
+ }else if("putData" in args){
+ ioArgs.query = args.putData;
+ }else if("rawBody" in args){
+ ioArgs.query = args.rawBody;
+ }else if((arguments.length > 2 && !hasBody) || "POST|PUT".indexOf(method.toUpperCase()) == -1){
+ //Check for hasBody being passed. If no hasBody,
+ //then only append query string if not a POST or PUT request.
+ _d._ioAddQueryToUrl(ioArgs);
+ }
+
+ // 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"
+ xhr.open(method, 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 if(args.headers[hdr]){
+ //Only add header if it has a value. This allows for instnace, skipping
+ //insertion of X-Requested-With by specifying empty value.
+ xhr.setRequestHeader(hdr, args.headers[hdr]);
+ }
+ }
+ }
+ // FIXME: is this appropriate for all content types?
+ xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType);
+ if(!args.headers || !("X-Requested-With" in args.headers)){
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+ }
+ // FIXME: set other headers here!
+ _d._ioNotifyStart(dfd);
+ if(dojo.config.debugAtAllCosts){
+ xhr.send(ioArgs.query);
+ }else{
+ try{
+ xhr.send(ioArgs.query);
+ }catch(e){
+ ioArgs.error = e;
+ dfd.cancel();
+ }
+ }
+ _d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);
+ xhr = null;
+ return 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.rawXhrPost = dojo.xhrPost = 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. Send raw data in the body of the POST request.
+ return _d.xhr("POST", args, true); // dojo.Deferred
+ }
+
+ dojo.rawXhrPut = dojo.xhrPut = 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. Send raw data in the body of the PUT request.
+ return _d.xhr("PUT", args, true); // 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/lib/dojo/_firebug/firebug.css b/lib/dojo/_firebug/firebug.css
index 3b6f4f99f..27657ef42 100644
--- a/lib/dojo/_firebug/firebug.css
+++ b/lib/dojo/_firebug/firebug.css
@@ -25,6 +25,7 @@
background:#f0f0f0;
}
+
.firebug #firebugLog, .firebug #objectLog {
overflow: auto;
position: absolute;
@@ -171,6 +172,8 @@
.firebug .propertyName {
font-weight: bold;
}
+
+/* tabs */
#firebugToolbar ul.tabs{
margin:0 !important;
padding:0;
@@ -205,4 +208,4 @@
text-decoration:none;
background:transparent url(tab_rgt_over.png) no-repeat right;
color:#FFFFFF;
-}
+} \ No newline at end of file
diff --git a/lib/dojo/_firebug/firebug.js b/lib/dojo/_firebug/firebug.js
index 7736258b5..d1f112f69 100644
--- a/lib/dojo/_firebug/firebug.js
+++ b/lib/dojo/_firebug/firebug.js
@@ -5,910 +5,1222 @@
*/
-if(!dojo._hasResource["dojo._firebug.firebug"]){
-dojo._hasResource["dojo._firebug.firebug"]=true;
+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(_1,_2,_3){
-var _4="DEPRECATED: "+_1;
-if(_2){
-_4+=" "+_2;
-}
-if(_3){
-_4+=" -- will be removed in version: "+_3;
-}
-console.warn(_4);
+
+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(_5,_6){
-var _7="EXPERIMENTAL: "+_5+" -- APIs subject to change without notice.";
-if(_6){
-_7+=" "+_6;
-}
-console.warn(_7);
+
+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:
+ // FF2: set "console = null" before loading dojo and set djConfig.isDebug=true
+ // FF3: disable Firebug and set djConfig.isDebug=true
+ //
+ // 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 }
+
+
+
(function(){
-var _8=(/Trident/.test(window.navigator.userAgent));
-if(_8){
-var _9=["log","info","debug","warn","error"];
-for(var i=0;i<_9.length;i++){
-var m=_9[i];
-var n="_"+_9[i];
-console[n]=console[m];
-console[m]=(function(){
-var _a=n;
-return function(){
-console[_a](Array.prototype.slice.call(arguments).join(" "));
-};
-})();
-}
-try{
-console.clear();
-}
-catch(e){
-}
-}
-if(!dojo.isFF&&(!dojo.isChrome||dojo.isChrome<3)&&(!dojo.isSafari||dojo.isSafari<4)&&!_8&&!window.firebug&&(typeof console!="undefined"&&!console.firebug)&&!dojo.config.useCustomLogger&&!dojo.isAIR){
-try{
-if(window!=window.parent){
-if(window.parent["console"]){
-window.console=window.parent.console;
-}
-return;
-}
-}
-catch(e){
-}
-var _b=document;
-var _c=window;
-var _d=0;
-var _e=null;
-var _f=null;
-var _10=null;
-var _11=null;
-var _12=null;
-var _13=null;
-var _14=false;
-var _15=[];
-var _16=[];
-var _17={};
-var _18={};
-var _19=null;
-var _1a;
-var _1b;
-var _1c=false;
-var _1d=null;
-var _1e=document.createElement("div");
-var _1f;
-var _20;
-window.console={_connects:[],log:function(){
-_21(arguments,"");
-},debug:function(){
-_21(arguments,"debug");
-},info:function(){
-_21(arguments,"info");
-},warn:function(){
-_21(arguments,"warning");
-},error:function(){
-_21(arguments,"error");
-},assert:function(_22,_23){
-if(!_22){
-var _24=[];
-for(var i=1;i<arguments.length;++i){
-_24.push(arguments[i]);
-}
-_21(_24.length?_24:["Assertion Failure"],"error");
-throw _23?_23:"Assertion Failure";
-}
-},dir:function(obj){
-var str=_25(obj);
-str=str.replace(/\n/g,"<br />");
-str=str.replace(/\t/g,"&nbsp;&nbsp;&nbsp;&nbsp;");
-_26([str],"dir");
-},dirxml:function(_27){
-var _28=[];
-_29(_27,_28);
-_26(_28,"dirxml");
-},group:function(){
-_26(arguments,"group",_2a);
-},groupEnd:function(){
-_26(arguments,"",_2b);
-},time:function(_2c){
-_17[_2c]=new Date().getTime();
-},timeEnd:function(_2d){
-if(_2d in _17){
-var _2e=(new Date()).getTime()-_17[_2d];
-_21([_2d+":",_2e+"ms"]);
-delete _17[_2d];
-}
-},count:function(_2f){
-if(!_18[_2f]){
-_18[_2f]=0;
-}
-_18[_2f]++;
-_21([_2f+": "+_18[_2f]]);
-},trace:function(_30){
-var _31=_30||3;
-var f=console.trace.caller;
-for(var i=0;i<_31;i++){
-var _32=f.toString();
-var _33=[];
-for(var a=0;a<f.arguments.length;a++){
-_33.push(f.arguments[a]);
-}
-if(f.arguments.length){
-}else{
-}
-f=f.caller;
-}
-},profile:function(){
-this.warn(["profile() not supported."]);
-},profileEnd:function(){
-},clear:function(){
-if(_f){
-while(_f.childNodes.length){
-dojo.destroy(_f.firstChild);
-}
-}
-dojo.forEach(this._connects,dojo.disconnect);
-},open:function(){
-_34(true);
-},close:function(){
-if(_14){
-_34();
-}
-},_restoreBorder:function(){
-if(_1f){
-_1f.style.border=_20;
-}
-},openDomInspector:function(){
-_1c=true;
-_f.style.display="none";
-_19.style.display="block";
-_10.style.display="none";
-document.body.style.cursor="pointer";
-_1a=dojo.connect(document,"mousemove",function(evt){
-if(!_1c){
-return;
-}
-if(!_1d){
-_1d=setTimeout(function(){
-_1d=null;
-},50);
-}else{
-return;
-}
-var _35=evt.target;
-if(_35&&(_1f!==_35)){
-var _36=true;
-console._restoreBorder();
-var _37=[];
-_29(_35,_37);
-_19.innerHTML=_37.join("");
-_1f=_35;
-_20=_1f.style.border;
-_1f.style.border="#0000FF 1px solid";
-}
-});
-setTimeout(function(){
-_1b=dojo.connect(document,"click",function(evt){
-document.body.style.cursor="";
-_1c=!_1c;
-dojo.disconnect(_1b);
-});
-},30);
-},_closeDomInspector:function(){
-document.body.style.cursor="";
-dojo.disconnect(_1a);
-dojo.disconnect(_1b);
-_1c=false;
-console._restoreBorder();
-},openConsole:function(){
-_f.style.display="block";
-_19.style.display="none";
-_10.style.display="none";
-console._closeDomInspector();
-},openObjectInspector:function(){
-_f.style.display="none";
-_19.style.display="none";
-_10.style.display="block";
-console._closeDomInspector();
-},recss:function(){
-var i,a,s;
-a=document.getElementsByTagName("link");
-for(i=0;i<a.length;i++){
-s=a[i];
-if(s.rel.toLowerCase().indexOf("stylesheet")>=0&&s.href){
-var h=s.href.replace(/(&|%5C?)forceReload=\d+/,"");
-s.href=h+(h.indexOf("?")>=0?"&":"?")+"forceReload="+new Date().valueOf();
-}
-}
-}};
-function _34(_38){
-_14=_38||!_14;
-if(_e){
-_e.style.display=_14?"block":"none";
-}
-};
-function _39(){
-_34(true);
-if(_12){
-_12.focus();
-}
-};
-function _3a(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);
-}
-_3b(win);
-var _3c=win.document;
-var _3d="<html style=\"height:100%;\"><head><title>Firebug Lite</title></head>\n"+"<body bgColor=\"#ccc\" style=\"height:97%;\" onresize=\"opener.onFirebugResize()\">\n"+"<div id=\"fb\"></div>"+"</body></html>";
-_3c.write(_3d);
-_3c.close();
-return win;
-};
-function _3b(wn){
-var d=new Date();
-d.setTime(d.getTime()+(60*24*60*60*1000));
-d=d.toUTCString();
-var dc=wn.document,_3e;
-if(wn.innerWidth){
-_3e=function(){
-return {w:wn.innerWidth,h:wn.innerHeight};
-};
-}else{
-if(dc.documentElement&&dc.documentElement.clientWidth){
-_3e=function(){
-return {w:dc.documentElement.clientWidth,h:dc.documentElement.clientHeight};
-};
-}else{
-if(dc.body){
-_3e=function(){
-return {w:dc.body.clientWidth,h:dc.body.clientHeight};
-};
-}
-}
-}
-window.onFirebugResize=function(){
-_4c(_3e().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);
-};
-};
-function _3f(){
-if(_e){
-return;
-}
-if(dojo.config.popup){
-var _40="100%";
-var _41=document.cookie.match(/(?:^|; )_firebugPosition=([^;]*)/);
-var p=_41?_41[1].split(","):[2,2,320,480];
-_c=_3a(p[0],p[1],p[2],p[3]);
-_b=_c.document;
-dojo.config.debugContainerId="fb";
-_c.console=window.console;
-_c.dojo=window.dojo;
-}else{
-_b=document;
-_40=(dojo.config.debugHeight||300)+"px";
-}
-var _42=_b.createElement("link");
-_42.href=dojo.moduleUrl("dojo._firebug","firebug.css");
-_42.rel="stylesheet";
-_42.type="text/css";
-var _43=_b.getElementsByTagName("head");
-if(_43){
-_43=_43[0];
-}
-if(!_43){
-_43=_b.getElementsByTagName("html")[0];
-}
-if(dojo.isIE){
-window.setTimeout(function(){
-_43.appendChild(_42);
-},0);
-}else{
-_43.appendChild(_42);
-}
-if(dojo.config.debugContainerId){
-_e=_b.getElementById(dojo.config.debugContainerId);
-}
-if(!_e){
-_e=_b.createElement("div");
-_b.body.appendChild(_e);
-}
-_e.className+=" firebug";
-_e.style.height=_40;
-_e.style.display=(_14?"block":"none");
-var _44=function(_45,_46,_47,_48){
-return "<li class=\""+_48+"\"><a href=\"javascript:void(0);\" onclick=\"console."+_47+"(); return false;\" title=\""+_46+"\">"+_45+"</a></li>";
-};
-_e.innerHTML="<div id=\"firebugToolbar\">"+" <ul id=\"fireBugTabs\" class=\"tabs\">"+_44("Clear","Remove All Console Logs","clear","")+_44("ReCSS","Refresh CSS without reloading page","recss","")+_44("Console","Show Console Logs","openConsole","gap")+_44("DOM","Show DOM Inspector","openDomInspector","")+_44("Object","Show Object Inspector","openObjectInspector","")+((dojo.config.popup)?"":_44("Close","Close the console","close","gap"))+"\t</ul>"+"</div>"+"<input type=\"text\" id=\"firebugCommandLine\" />"+"<div id=\"firebugLog\"></div>"+"<div id=\"objectLog\" style=\"display:none;\">Click on an object in the Log display</div>"+"<div id=\"domInspect\" style=\"display:none;\">Hover over HTML elements in the main page. Click to hold selection.</div>";
-_13=_b.getElementById("firebugToolbar");
-_12=_b.getElementById("firebugCommandLine");
-_49(_12,"keydown",_4a);
-_49(_b,dojo.isIE||dojo.isSafari?"keydown":"keypress",_4b);
-_f=_b.getElementById("firebugLog");
-_10=_b.getElementById("objectLog");
-_19=_b.getElementById("domInspect");
-_11=_b.getElementById("fireBugTabs");
-_4c();
-_4d();
-};
-dojo.addOnLoad(_3f);
-function _4e(){
-_b=null;
-if(_c.console){
-_c.console.clear();
-}
-_c=null;
-_e=null;
-_f=null;
-_10=null;
-_19=null;
-_12=null;
-_15=[];
-_16=[];
-_17={};
-};
-function _4f(){
-var _50=_12.value;
-_12.value="";
-_26(["> ",_50],"command");
-var _51;
-try{
-_51=eval(_50);
-}
-catch(e){
-}
-};
-function _4c(h){
-var _52=25;
-var _53=h?h-(_52+_12.offsetHeight+25+(h*0.01))+"px":(_e.offsetHeight-_52-_12.offsetHeight)+"px";
-_f.style.top=_52+"px";
-_f.style.height=_53;
-_10.style.height=_53;
-_10.style.top=_52+"px";
-_19.style.height=_53;
-_19.style.top=_52+"px";
-_12.style.bottom=0;
-dojo.addOnWindowUnload(_4e);
-};
-function _26(_54,_55,_56){
-if(_f){
-_57(_54,_55,_56);
-}else{
-_15.push([_54,_55,_56]);
-}
-};
-function _4d(){
-var _58=_15;
-_15=[];
-for(var i=0;i<_58.length;++i){
-_57(_58[i][0],_58[i][1],_58[i][2]);
-}
-};
-function _57(_59,_5a,_5b){
-var _5c=_f.scrollTop+_f.offsetHeight>=_f.scrollHeight;
-_5b=_5b||_5d;
-_5b(_59,_5a);
-if(_5c){
-_f.scrollTop=_f.scrollHeight-_f.offsetHeight;
-}
-};
-function _5e(row){
-var _5f=_16.length?_16[_16.length-1]:_f;
-_5f.appendChild(row);
-};
-function _5d(_60,_61){
-var row=_f.ownerDocument.createElement("div");
-row.className="logRow"+(_61?" logRow-"+_61:"");
-row.innerHTML=_60.join("");
-_5e(row);
-};
-function _2a(_62,_63){
-_21(_62,_63);
-var _64=_f.ownerDocument.createElement("div");
-_64.className="logGroupBox";
-_5e(_64);
-_16.push(_64);
-};
-function _2b(){
-_16.pop();
-};
-function _21(_65,_66){
-var _67=[];
-var _68=_65[0];
-var _69=0;
-if(typeof (_68)!="string"){
-_68="";
-_69=-1;
-}
-var _6a=_6b(_68);
-for(var i=0;i<_6a.length;++i){
-var _6c=_6a[i];
-if(_6c&&typeof _6c=="object"){
-_6c.appender(_65[++_69],_67);
-}else{
-_6d(_6c,_67);
-}
-}
-var ids=[];
-var obs=[];
-for(i=_69+1;i<_65.length;++i){
-_6d(" ",_67);
-var _6e=_65[i];
-if(_6e===undefined||_6e===null){
-_6f(_6e,_67);
-}else{
-if(typeof (_6e)=="string"){
-_6d(_6e,_67);
-}else{
-if(_6e instanceof Date){
-_6d(_6e.toString(),_67);
-}else{
-if(_6e.nodeType==9){
-_6d("[ XmlDoc ]",_67);
-}else{
-var id="_a"+_d++;
-ids.push(id);
-obs.push(_6e);
-var str="<a id=\""+id+"\" href=\"javascript:void(0);\">"+_70(_6e)+"</a>";
-_71(str,_67);
-}
-}
-}
-}
-}
-_26(_67,_66);
-for(i=0;i<ids.length;i++){
-var btn=_b.getElementById(ids[i]);
-if(!btn){
-continue;
-}
-btn.obj=obs[i];
-_c.console._connects.push(dojo.connect(btn,"onclick",function(){
-console.openObjectInspector();
-try{
-_25(this.obj);
-}
-catch(e){
-this.obj=e;
-}
-_10.innerHTML="<pre>"+_25(this.obj)+"</pre>";
-}));
-}
-};
-function _6b(_72){
-var _73=[];
-var reg=/((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;
-var _74={s:_6d,d:_75,i:_75,f:_76};
-for(var m=reg.exec(_72);m;m=reg.exec(_72)){
-var _77=m[8]?m[8]:m[5];
-var _78=_77 in _74?_74[_77]:_79;
-var _7a=m[3]?parseInt(m[3]):(m[4]=="."?-1:0);
-_73.push(_72.substr(0,m[0][0]=="%"?m.index:m.index+1));
-_73.push({appender:_78,precision:_7a});
-_72=_72.substr(m.index+m[0].length);
-}
-_73.push(_72);
-return _73;
-};
-function _7b(_7c){
-function _7d(ch){
-switch(ch){
-case "<":
-return "&lt;";
-case ">":
-return "&gt;";
-case "&":
-return "&amp;";
-case "'":
-return "&#39;";
-case "\"":
-return "&quot;";
-}
-return "?";
-};
-return String(_7c).replace(/[<>&"']/g,_7d);
-};
-function _7e(_7f){
-try{
-return _7f+"";
-}
-catch(e){
-return null;
-}
-};
-function _71(_80,_81){
-_81.push(_7e(_80));
-};
-function _6d(_82,_83){
-_83.push(_7b(_7e(_82)));
-};
-function _6f(_84,_85){
-_85.push("<span class=\"objectBox-null\">",_7b(_7e(_84)),"</span>");
-};
-function _86(_87,_88){
-_88.push("<span class=\"objectBox-string\">&quot;",_7b(_7e(_87)),"&quot;</span>");
-};
-function _75(_89,_8a){
-_8a.push("<span class=\"objectBox-number\">",_7b(_7e(_89)),"</span>");
-};
-function _76(_8b,_8c){
-_8c.push("<span class=\"objectBox-number\">",_7b(_7e(_8b)),"</span>");
-};
-function _8d(_8e,_8f){
-_8f.push("<span class=\"objectBox-function\">",_70(_8e),"</span>");
-};
-function _79(_90,_91){
-try{
-if(_90===undefined){
-_6f("undefined",_91);
-}else{
-if(_90===null){
-_6f("null",_91);
-}else{
-if(typeof _90=="string"){
-_86(_90,_91);
-}else{
-if(typeof _90=="number"){
-_75(_90,_91);
-}else{
-if(typeof _90=="function"){
-_8d(_90,_91);
-}else{
-if(_90.nodeType==1){
-_92(_90,_91);
-}else{
-if(typeof _90=="object"){
-_93(_90,_91);
-}else{
-_6d(_90,_91);
-}
-}
-}
-}
-}
-}
-}
-}
-catch(e){
-}
-};
-function _93(_94,_95){
-var _96=_7e(_94);
-var _97=/\[object (.*?)\]/;
-var m=_97.exec(_96);
-_95.push("<span class=\"objectBox-object\">",m?m[1]:_96,"</span>");
-};
-function _92(_98,_99){
-_99.push("<span class=\"objectBox-selector\">");
-_99.push("<span class=\"selectorTag\">",_7b(_98.nodeName.toLowerCase()),"</span>");
-if(_98.id){
-_99.push("<span class=\"selectorId\">#",_7b(_98.id),"</span>");
-}
-if(_98.className){
-_99.push("<span class=\"selectorClass\">.",_7b(_98.className),"</span>");
-}
-_99.push("</span>");
-};
-function _29(_9a,_9b){
-if(_9a.nodeType==1){
-_9b.push("<div class=\"objectBox-element\">","&lt;<span class=\"nodeTag\">",_9a.nodeName.toLowerCase(),"</span>");
-for(var i=0;i<_9a.attributes.length;++i){
-var _9c=_9a.attributes[i];
-if(!_9c.specified){
-continue;
-}
-_9b.push("&nbsp;<span class=\"nodeName\">",_9c.nodeName.toLowerCase(),"</span>=&quot;<span class=\"nodeValue\">",_7b(_9c.nodeValue),"</span>&quot;");
-}
-if(_9a.firstChild){
-_9b.push("&gt;</div><div class=\"nodeChildren\">");
-for(var _9d=_9a.firstChild;_9d;_9d=_9d.nextSibling){
-_29(_9d,_9b);
-}
-_9b.push("</div><div class=\"objectBox-element\">&lt;/<span class=\"nodeTag\">",_9a.nodeName.toLowerCase(),"&gt;</span></div>");
-}else{
-_9b.push("/&gt;</div>");
-}
-}else{
-if(_9a.nodeType==3){
-_9b.push("<div class=\"nodeText\">",_7b(_9a.nodeValue),"</div>");
-}
-}
-};
-function _49(_9e,_9f,_a0){
-if(document.all){
-_9e.attachEvent("on"+_9f,_a0);
-}else{
-_9e.addEventListener(_9f,_a0,false);
-}
-};
-function _a1(_a2,_a3,_a4){
-if(document.all){
-_a2.detachEvent("on"+_a3,_a4);
-}else{
-_a2.removeEventListener(_a3,_a4,false);
-}
-};
-function _a5(_a6){
-if(document.all){
-_a6.cancelBubble=true;
-}else{
-_a6.stopPropagation();
-}
-};
-function _a7(msg,_a8,_a9){
-var _aa=_a8.lastIndexOf("/");
-var _ab=_aa==-1?_a8:_a8.substr(_aa+1);
-var _ac=["<span class=\"errorMessage\">",msg,"</span>","<div class=\"objectBox-sourceLink\">",_ab," (line ",_a9,")</div>"];
-_26(_ac,"error");
-};
-var _ad=new Date().getTime();
-function _4b(_ae){
-var _af=(new Date()).getTime();
-if(_af>_ad+200){
-_ae=dojo.fixEvent(_ae);
-var _b0=dojo.keys;
-var ekc=_ae.keyCode;
-_ad=_af;
-if(ekc==_b0.F12){
-_34();
-}else{
-if((ekc==_b0.NUMPAD_ENTER||ekc==76)&&_ae.shiftKey&&(_ae.metaKey||_ae.ctrlKey)){
-_39();
-}else{
-return;
-}
-}
-_a5(_ae);
-}
-};
-function _4a(e){
-var dk=dojo.keys;
-if(e.keyCode==13&&_12.value){
-_b1(_12.value);
-_4f();
-}else{
-if(e.keyCode==27){
-_12.value="";
-}else{
-if(e.keyCode==dk.UP_ARROW||e.charCode==dk.UP_ARROW){
-_b2("older");
-}else{
-if(e.keyCode==dk.DOWN_ARROW||e.charCode==dk.DOWN_ARROW){
-_b2("newer");
-}else{
-if(e.keyCode==dk.HOME||e.charCode==dk.HOME){
-_b3=1;
-_b2("older");
-}else{
-if(e.keyCode==dk.END||e.charCode==dk.END){
-_b3=999999;
-_b2("newer");
-}
-}
-}
-}
-}
-}
-};
-var _b3=-1;
-var _b4=null;
-function _b1(_b5){
-var _b6=_b7("firebug_history");
-_b6=(_b6)?dojo.fromJson(_b6):[];
-var pos=dojo.indexOf(_b6,_b5);
-if(pos!=-1){
-_b6.splice(pos,1);
-}
-_b6.push(_b5);
-_b7("firebug_history",dojo.toJson(_b6),30);
-while(_b6.length&&!_b7("firebug_history")){
-_b6.shift();
-_b7("firebug_history",dojo.toJson(_b6),30);
-}
-_b4=null;
-_b3=-1;
-};
-function _b2(_b8){
-var _b9=_b7("firebug_history");
-_b9=(_b9)?dojo.fromJson(_b9):[];
-if(!_b9.length){
-return;
-}
-if(_b4===null){
-_b4=_12.value;
-}
-if(_b3==-1){
-_b3=_b9.length;
-}
-if(_b8=="older"){
---_b3;
-if(_b3<0){
-_b3=0;
-}
-}else{
-if(_b8=="newer"){
-++_b3;
-if(_b3>_b9.length){
-_b3=_b9.length;
-}
-}
-}
-if(_b3==_b9.length){
-_12.value=_b4;
-_b4=null;
-}else{
-_12.value=_b9[_b3];
-}
-};
-function _b7(_ba,_bb){
-var c=document.cookie;
-if(arguments.length==1){
-var _bc=c.match(new RegExp("(?:^|; )"+_ba+"=([^;]*)"));
-return _bc?decodeURIComponent(_bc[1]):undefined;
-}else{
-var d=new Date();
-d.setMonth(d.getMonth()+1);
-document.cookie=_ba+"="+encodeURIComponent(_bb)+((d.toUtcString)?"; expires="+d.toUTCString():"");
-}
-};
-function _bd(it){
-return it&&it instanceof Array||typeof it=="array";
-};
-function _be(o){
-var cnt=0;
-for(var nm in o){
-cnt++;
-}
-return cnt;
-};
-function _25(o,i,txt,_bf){
-var ind=" \t";
-txt=txt||"";
-i=i||ind;
-_bf=_bf||[];
-var _c0;
-if(o&&o.nodeType==1){
-var _c1=[];
-_29(o,_c1);
-return _c1.join("");
-}
-var br=",\n",cnt=0,_c2=_be(o);
-if(o instanceof Date){
-return i+o.toString()+br;
-}
-looking:
-for(var nm in o){
-cnt++;
-if(cnt==_c2){
-br="\n";
-}
-if(o[nm]===window||o[nm]===document){
-continue;
-}else{
-if(o[nm]===null){
-txt+=i+nm+" : NULL"+br;
-}else{
-if(o[nm]&&o[nm].nodeType){
-if(o[nm].nodeType==1){
-}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(o[nm] instanceof Date){
-txt+=i+nm+" : "+o[nm].toString()+br;
-}else{
-if(typeof (o[nm])=="object"&&o[nm]){
-for(var j=0,_c3;_c3=_bf[j];j++){
-if(o[nm]===_c3){
-txt+=i+nm+" : RECURSION"+br;
-continue looking;
-}
-}
-_bf.push(o[nm]);
-_c0=(_bd(o[nm]))?["[","]"]:["{","}"];
-txt+=i+nm+" : "+_c0[0]+"\n";
-txt+=_25(o[nm],i+ind,"",_bf);
-txt+=i+_c0[1]+br;
-}else{
-if(typeof o[nm]=="undefined"){
-txt+=i+nm+" : undefined"+br;
-}else{
-if(nm=="toString"&&typeof o[nm]=="function"){
-var _c4=o[nm]();
-if(typeof _c4=="string"&&_c4.match(/function ?(.*?)\(/)){
-_c4=_7b(_70(o[nm]));
-}
-txt+=i+nm+" : "+_c4+br;
-}else{
-txt+=i+nm+" : "+_7b(_70(o[nm]))+br;
-}
-}
-}
-}
-}
-}
-}
-}
-}
-return txt;
-};
-function _70(obj){
-var _c5=(obj instanceof Error);
-if(obj.nodeType==1){
-return _7b("< "+obj.tagName.toLowerCase()+" id=\""+obj.id+"\" />");
-}
-if(obj.nodeType==3){
-return _7b("[TextNode: \""+obj.nodeValue+"\"]");
-}
-var nm=(obj&&(obj.id||obj.name||obj.ObjectID||obj.widgetId));
-if(!_c5&&nm){
-return "{"+nm+"}";
-}
-var _c6=2;
-var _c7=4;
-var cnt=0;
-if(_c5){
-nm="[ Error: "+(obj.message||obj.description||obj)+" ]";
-}else{
-if(_bd(obj)){
-nm="["+obj.slice(0,_c7).join(",");
-if(obj.length>_c7){
-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>_c6){
-break;
-}
-nm+=i+":"+_7b(obj[i])+" ";
-}
-nm+="}";
-}
-}
-}
-}
-return nm;
-};
-_49(document,dojo.isIE||dojo.isSafari?"keydown":"keypress",_4b);
-if((document.documentElement.getAttribute("debug")=="true")||(dojo.config.isDebug)){
-_34(true);
-}
-dojo.addOnWindowUnload(function(){
-_a1(document,dojo.isIE||dojo.isSafari?"keydown":"keypress",_4b);
-window.onFirebugResize=null;
-window.console=null;
-});
+
+ var isNewIE = (/Trident/.test(window.navigator.userAgent));
+ if(isNewIE){
+ // Fixing IE's console
+ // IE doesn't insert space between arguments. How annoying.
+ var calls = ["log", "info", "debug", "warn", "error"];
+ for(var i=0;i<calls.length;i++){
+ var m = calls[i];
+ var n = "_"+calls[i]
+ console[n] = console[m];
+ console[m] = (function(){
+ var type = n;
+ return function(){
+ console[type](Array.prototype.slice.call(arguments).join(" "));
+ }
+ })();
+ }
+ // clear the console on load. This is more than a convenience - too many logs crashes it.
+ // If closed it throws an error
+ try{ console.clear(); }catch(e){}
+ }
+
+ if(
+ !dojo.isFF && // Firefox has Firebug
+ (!dojo.isChrome || dojo.isChrome < 3) &&
+ (!dojo.isSafari || dojo.isSafari < 4) && // Safari 4 has a console
+ !isNewIE && // Has the new IE console
+ !window.firebug && // Testing for mozilla firebug lite
+ (typeof console != "undefined" && !console.firebug) && //A console that is not firebug's
+ !dojo.config.useCustomLogger && // Allow custom loggers
+ !dojo.isAIR // isDebug triggers AIRInsector, not Firebug
+ ){
+
+
+ // don't build firebug 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*/}
+
+ // ***************************************************************************
+ // Placing these variables before the functions that use them to avoid a
+ // shrinksafe bug where variable renaming does not happen correctly otherwise.
+
+ // 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 consoleObjectInspector = null;
+ var fireBugTabs = null;
+ var commandLine = null;
+ var consoleToolbar = null;
+
+ var frameVisible = false;
+ var messageQueue = [];
+ var groupStack = [];
+ var timeMap = {};
+ var countMap = {};
+
+ var consoleDomInspector = null;
+ var _inspectionMoveConnection;
+ var _inspectionClickConnection;
+ var _inspectionEnabled = false;
+ var _inspectionTimer = null;
+ var _inspectTempNode = document.createElement("div");
+
+
+ var _inspectCurrentNode;
+ var _restoreBorderStyle;
+
+ // ***************************************************************************
+
+ 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(obj){
+ var str = printObject( obj );
+ str = str.replace(/\n/g, "<br />");
+ str = str.replace(/\t/g, "&nbsp;&nbsp;&nbsp;&nbsp;");
+ logRow([str], "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(name){
+ // summary:
+ // Not supported
+ if(!countMap[name]) countMap[name] = 0;
+ countMap[name]++;
+ logFormatted([name+": "+countMap[name]]);
+ },
+
+ trace: function(_value){
+ var stackAmt = _value || 3;
+ var f = console.trace.caller; //function that called trace
+ console.log(">>> console.trace(stack)");
+ for(var i=0;i<stackAmt;i++){
+ var func = f.toString();
+ var args=[];
+ for (var a = 0; a < f.arguments.length; a++) {
+ args.push(f.arguments[a])
+ }
+ if(f.arguments.length){
+ console.dir({"function":func, "arguments":args});
+ }else{
+ console.dir({"function":func});
+ }
+
+ f = f.caller;
+ }
+ },
+
+ profile: function(){
+ // summary:
+ // Not supported
+ this.warn(["profile() not supported."]);
+ },
+
+ profileEnd: function(){ },
+
+ clear: function(){
+ // summary:
+ // Clears message console. Do not call this directly
+ if(consoleBody){
+ while(consoleBody.childNodes.length){
+ dojo.destroy(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();
+ }
+ },
+ _restoreBorder: function(){
+ if(_inspectCurrentNode){
+ _inspectCurrentNode.style.border = _restoreBorderStyle;
+ }
+ },
+ openDomInspector: function(){
+ _inspectionEnabled = true;
+ consoleBody.style.display = "none";
+ consoleDomInspector.style.display = "block";
+ consoleObjectInspector.style.display = "none";
+ document.body.style.cursor = "pointer";
+ _inspectionMoveConnection = dojo.connect(document, "mousemove", function(evt){
+ if(!_inspectionEnabled){ return; }
+ if(!_inspectionTimer){
+ _inspectionTimer = setTimeout(function(){ _inspectionTimer = null; }, 50);
+ }else{
+ return;
+ }
+ var node = evt.target;
+ if(node && (_inspectCurrentNode !== node)){
+ var parent = true;
+
+ console._restoreBorder();
+ var html = [];
+ appendNode(node, html);
+ consoleDomInspector.innerHTML = html.join("");
+
+ _inspectCurrentNode = node;
+ _restoreBorderStyle = _inspectCurrentNode.style.border;
+ _inspectCurrentNode.style.border = "#0000FF 1px solid";
+ }
+ });
+ setTimeout(function(){
+ _inspectionClickConnection = dojo.connect(document, "click", function(evt){
+ document.body.style.cursor = "";
+ _inspectionEnabled = !_inspectionEnabled;
+ dojo.disconnect(_inspectionClickConnection);
+ // console._restoreBorder();
+ });
+ }, 30);
+ },
+ _closeDomInspector: function(){
+ document.body.style.cursor = "";
+ dojo.disconnect(_inspectionMoveConnection);
+ dojo.disconnect(_inspectionClickConnection);
+ _inspectionEnabled = false;
+ console._restoreBorder();
+ },
+ openConsole:function(){
+ // summary:
+ // Closes object inspector and opens message console. Do not call this directly
+ consoleBody.style.display = "block";
+ consoleDomInspector.style.display = "none";
+ consoleObjectInspector.style.display = "none";
+ console._closeDomInspector();
+ },
+ openObjectInspector:function(){
+ consoleBody.style.display = "none";
+ consoleDomInspector.style.display = "none";
+ consoleObjectInspector.style.display = "block";
+ console._closeDomInspector();
+ },
+ recss: function(){
+ // http://turtle.dojotoolkit.org/~david/recss.html
+ // this is placed in dojo since the console is most likely
+ // in another window and dojo is easilly accessible
+ var i,a,s;a=document.getElementsByTagName('link');
+ for(i=0;i<a.length;i++){
+ s=a[i];
+ if(s.rel.toLowerCase().indexOf('stylesheet')>=0&&s.href) {
+ var h=s.href.replace(/(&|%5C?)forceReload=\d+/,'');
+ s.href=h+(h.indexOf('?')>=0?'&':'?')+'forceReload='+new Date().valueOf();
+ }
+ }
+ }
+ }
+
+ // ***************************************************************************
+
+ 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
+ var HTMLstring= '<html style="height:100%;"><head><title>Firebug Lite</title></head>\n' +
+ '<body bgColor="#ccc" style="height:97%;" onresize="opener.onFirebugResize()">\n' +
+ '<div id="fb"></div>' +
+ '</body></html>';
+
+ newDoc.write(HTMLstring);
+ newDoc.close();
+ return win;
+ }
+
+ function createResizeHandler(wn){
+ // summary
+ // Creates handle for onresize window. Called from script in popup's body tag (so that it will work with IE).
+ //
+
+ var d = new Date();
+ d.setTime(d.getTime()+(60*24*60*60*1000)); // 60 days
+ d = d.toUTCString();
+
+ var dc = wn.document,
+ getViewport;
+
+ if (wn.innerWidth){
+ getViewport = function(){
+ return{w:wn.innerWidth, h:wn.innerHeight};
+ };
+ }else if (dc.documentElement && dc.documentElement.clientWidth){
+ getViewport = function(){
+ return{w:dc.documentElement.clientWidth, h:dc.documentElement.clientHeight};
+ };
+ }else if (dc.body){
+ getViewport = function(){
+ return{w:dc.body.clientWidth, h:dc.body.clientHeight};
+ };
+ }
+
+
+ window.onFirebugResize = function(){
+
+ //resize the height of the console log body
+ layout(getViewport().h);
+
+ clearInterval(wn._firebugWin_resize);
+ wn._firebugWin_resize = setTimeout(function(){
+ var x = wn.screenLeft,
+ y = wn.screenTop,
+ w = wn.outerWidth || wn.document.body.offsetWidth,
+ h = wn.outerHeight || wn.document.body.offsetHeight;
+
+ document.cookie = "_firebugPosition=" + [x,y,w,h].join(",") + "; expires="+d+"; path=/";
+
+ }, 5000); //can't capture window.onMove - long timeout gives better chance of capturing a resize, then the move
+
+ };
+ }
+
+
+ /*****************************************************************************/
+
+
+ function createFrame(){
+ if(consoleFrame){
+ return;
+ }
+
+ if(dojo.config.popup){
+ var containerHeight = "100%";
+ var cookieMatch = document.cookie.match(/(?:^|; )_firebugPosition=([^;]*)/);
+ var p = cookieMatch ? cookieMatch[1].split(",") : [2,2,320,480];
+
+ _firebugWin = openWin(p[0],p[1],p[2],p[3]); // global
+ _firebugDoc = _firebugWin.document; // global
+
+ dojo.config.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 buildLink = function(label, title, method, _class){
+ return '<li class="'+_class+'"><a href="javascript:void(0);" onclick="console.'+ method +'(); return false;" title="'+title+'">'+label+'</a></li>';
+ };
+ consoleFrame.innerHTML =
+ '<div id="firebugToolbar">'
+ + ' <ul id="fireBugTabs" class="tabs">'
+
+ + buildLink("Clear", "Remove All Console Logs", "clear", "")
+ + buildLink("ReCSS", "Refresh CSS without reloading page", "recss", "")
+
+ + buildLink("Console", "Show Console Logs", "openConsole", "gap")
+ + buildLink("DOM", "Show DOM Inspector", "openDomInspector", "")
+ + buildLink("Object", "Show Object Inspector", "openObjectInspector", "")
+ + ((dojo.config.popup) ? "" : buildLink("Close", "Close the console", "close", "gap"))
+
+ + ' </ul>'
+ + '</div>'
+ + '<input type="text" id="firebugCommandLine" />'
+ + '<div id="firebugLog"></div>'
+ + '<div id="objectLog" style="display:none;">Click on an object in the Log display</div>'
+ + '<div id="domInspect" style="display:none;">Hover over HTML elements in the main page. Click to hold selection.</div>';
+
+
+ consoleToolbar = _firebugDoc.getElementById("firebugToolbar");
+
+ 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");
+ consoleDomInspector = _firebugDoc.getElementById("domInspect");
+ fireBugTabs = _firebugDoc.getElementById("fireBugTabs");
+ layout();
+ flush();
+ }
+
+ dojo.addOnLoad(createFrame);
+
+ function clearFrame(){
+ _firebugDoc = null;
+
+ if(_firebugWin.console){
+ _firebugWin.console.clear();
+ }
+ _firebugWin = null;
+ consoleFrame = null;
+ consoleBody = null;
+ consoleObjectInspector = null;
+ consoleDomInspector = null;
+ commandLine = null;
+ messageQueue = [];
+ groupStack = [];
+ timeMap = {};
+ }
+
+
+ function evalCommandLine(){
+ var text = commandLine.value;
+ commandLine.value = "";
+
+ logRow(["> ", 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 tHeight = 25; //consoleToolbar.offsetHeight; // tab style not ready on load - throws off layout
+ var height = h ?
+ h - (tHeight + commandLine.offsetHeight +25 + (h*.01)) + "px" :
+ (consoleFrame.offsetHeight - tHeight - commandLine.offsetHeight) + "px";
+
+ consoleBody.style.top = tHeight + "px";
+ consoleBody.style.height = height;
+ consoleObjectInspector.style.height = height;
+ consoleObjectInspector.style.top = tHeight + "px";
+ consoleDomInspector.style.height = height;
+ consoleDomInspector.style.top = tHeight + "px";
+ commandLine.style.bottom = 0;
+
+ dojo.addOnWindowUnload(clearFrame)
+ }
+
+ 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 instanceof Date){
+ appendText(object.toString(), html);
+
+ }else if(object.nodeType == 9){
+ appendText("[ XmlDoc ]", html);
+
+ }else{
+ // Create link for object inspector
+ // need to create an ID for this link, since it is currently text
+ var id = "_a" + __consoleAnchorId__++;
+ ids.push(id);
+ // need to save the object, so the arrays line up
+ obs.push(object);
+ var str = '<a id="'+id+'" href="javascript:void(0);">'+getObjectAbbr(object)+'</a>';
+
+ appendLink( str , html);
+ }
+ }
+
+ logRow(html, className);
+
+ // Now that the row is inserted in the DOM, loop through all of the links that were just created
+ for(i=0; i<ids.length; i++){
+ var btn = _firebugDoc.getElementById(ids[i]);
+ if(!btn){ continue; }
+
+ // store the object in the dom btn for reference later
+ // avoid parsing these objects unless necessary
+ btn.obj = obs[i];
+
+ _firebugWin.console._connects.push(dojo.connect(btn, "onclick", function(){
+
+ console.openObjectInspector();
+
+ try{
+ printObject(this.obj);
+ }catch(e){
+ this.obj = e;
+ }
+ consoleObjectInspector.innerHTML = "<pre>" + printObject( this.obj ) + "</pre>";
+ }));
+ }
+ }
+
+ function parseFormat(format){
+ var parts = [];
+
+ var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;
+ var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};
+
+ for(var m = reg.exec(format); m; m = reg.exec(format)){
+ var type = m[8] ? m[8] : m[5];
+ var appender = type in appenderMap ? appenderMap[type] : appendObject;
+ var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
+
+ parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
+ parts.push({appender: appender, precision: precision});
+
+ format = format.substr(m.index+m[0].length);
+ }
+
+ parts.push(format);
+
+ return parts;
+ }
+
+ function escapeHTML(value){
+ function replaceChars(ch){
+ switch(ch){
+ case "<":
+ return "&lt;";
+ case ">":
+ return "&gt;";
+ case "&":
+ return "&amp;";
+ case "'":
+ return "&#39;";
+ case '"':
+ return "&quot;";
+ }
+ return "?";
+ }
+ return String(value).replace(/[<>&"']/g, replaceChars);
+ }
+
+ function objectToString(object){
+ try{
+ return object+"";
+ }catch(e){
+ return null;
+ }
+ }
+
+ // ***************************************************************************
+ function appendLink(object, html){
+ // needed for object links - no HTML escaping
+ html.push( objectToString(object) );
+ }
+
+ function appendText(object, html){
+ html.push(escapeHTML(objectToString(object)));
+ }
+
+ function appendNull(object, html){
+ html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
+ }
+
+ function appendString(object, html){
+ html.push('<span class="objectBox-string">&quot;', escapeHTML(objectToString(object)),
+ '&quot;</span>');
+ }
+
+ function appendInteger(object, html){
+ html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
+ }
+
+ function appendFloat(object, html){
+ html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
+ }
+
+ function appendFunction(object, html){
+ html.push('<span class="objectBox-function">', getObjectAbbr(object), '</span>');
+ }
+
+ function appendObject(object, html){
+ try{
+ if(object === undefined){
+ appendNull("undefined", html);
+ }else if(object === null){
+ appendNull("null", html);
+ }else if(typeof object == "string"){
+ appendString(object, html);
+ }else if(typeof object == "number"){
+ appendInteger(object, html);
+ }else if(typeof object == "function"){
+ appendFunction(object, html);
+ }else if(object.nodeType == 1){
+ appendSelector(object, html);
+ }else if(typeof object == "object"){
+ appendObjectFormatted(object, html);
+ }else{
+ appendText(object, html);
+ }
+ }catch(e){
+ /* squelch */
+ }
+ }
+
+ function appendObjectFormatted(object, html){
+ var text = objectToString(object);
+ var reObject = /\[object (.*?)\]/;
+
+ var m = reObject.exec(text);
+ html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>');
+ }
+
+ function appendSelector(object, html){
+ html.push('<span class="objectBox-selector">');
+
+ html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
+ if(object.id){
+ html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
+ }
+ if(object.className){
+ html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');
+ }
+
+ html.push('</span>');
+ }
+
+ function appendNode(node, html){
+ if(node.nodeType == 1){
+ html.push(
+ '<div class="objectBox-element">',
+ '&lt;<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');
+
+ for(var i = 0; i < node.attributes.length; ++i){
+ var attr = node.attributes[i];
+ if(!attr.specified){ continue; }
+
+ html.push('&nbsp;<span class="nodeName">', attr.nodeName.toLowerCase(),
+ '</span>=&quot;<span class="nodeValue">', escapeHTML(attr.nodeValue),
+ '</span>&quot;');
+ }
+
+ if(node.firstChild){
+ html.push('&gt;</div><div class="nodeChildren">');
+
+ for(var child = node.firstChild; child; child = child.nextSibling){
+ appendNode(child, html);
+ }
+
+ html.push('</div><div class="objectBox-element">&lt;/<span class="nodeTag">',
+ node.nodeName.toLowerCase(), '&gt;</span></div>');
+ }else{
+ html.push('/&gt;</div>');
+ }
+ }else if (node.nodeType == 3){
+ html.push('<div class="nodeText">', escapeHTML(node.nodeValue),
+ '</div>');
+ }
+ }
+
+ // ***************************************************************************
+
+ function addEvent(object, name, handler){
+ if(document.all){
+ object.attachEvent("on"+name, handler);
+ }else{
+ object.addEventListener(name, handler, false);
+ }
+ }
+
+ function removeEvent(object, name, handler){
+ if(document.all){
+ object.detachEvent("on"+name, handler);
+ }else{
+ object.removeEventListener(name, handler, false);
+ }
+ }
+
+ function cancelEvent(event){
+ if(document.all){
+ event.cancelBubble = true;
+ }else{
+ event.stopPropagation();
+ }
+ }
+
+ function onError(msg, href, lineNo){
+ var lastSlash = href.lastIndexOf("/");
+ var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
+
+ var html = [
+ '<span class="errorMessage">', msg, '</span>',
+ '<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
+ ];
+
+ logRow(html, "error");
+ }
+
+
+ //After converting to div instead of iframe, now getting two keydowns right away in IE 6.
+ //Make sure there is a little bit of delay.
+ var onKeyDownTime = new Date().getTime();
+
+ function onKeyDown(event){
+ var timestamp = (new Date()).getTime();
+ if(timestamp > onKeyDownTime + 200){
+ event = dojo.fixEvent(event);
+ var keys = dojo.keys;
+ var ekc = event.keyCode;
+ onKeyDownTime = timestamp;
+ if(ekc == keys.F12){
+ toggleConsole();
+ }else if(
+ (ekc == keys.NUMPAD_ENTER || ekc == 76) &&
+ event.shiftKey &&
+ (event.metaKey || event.ctrlKey)
+ ){
+ focusCommandLine();
+ }else{
+ return;
+ }
+ cancelEvent(event);
+ }
+ }
+
+ function onCommandLineKeyDown(e){
+ var dk = dojo.keys;
+ if(e.keyCode == 13 && commandLine.value){
+ addToHistory(commandLine.value);
+ evalCommandLine();
+ }else if(e.keyCode == 27){
+ commandLine.value = "";
+ }else if(e.keyCode == dk.UP_ARROW || e.charCode == dk.UP_ARROW){
+ navigateHistory("older");
+ }else if(e.keyCode == dk.DOWN_ARROW || e.charCode == dk.DOWN_ARROW){
+ navigateHistory("newer");
+ }else if(e.keyCode == dk.HOME || e.charCode == dk.HOME){
+ historyPosition = 1;
+ navigateHistory("older");
+ }else if(e.keyCode == dk.END || e.charCode == dk.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 objectLength(o){
+ var cnt = 0;
+ for(var nm in o){
+ cnt++
+ }
+ return cnt;
+ }
+
+ function printObject(o, i, txt, used){
+ // Recursively trace object, indenting to represent depth for display in object inspector
+ var ind = " \t";
+ txt = txt || "";
+ i = i || ind;
+ used = used || [];
+ var opnCls;
+
+ if(o && o.nodeType == 1){
+ var html = [];
+ appendNode(o, html);
+ return html.join("");
+ }
+
+ var br=",\n", cnt = 0, length = objectLength(o);
+
+ if(o instanceof Date){
+ return i + o.toString() + br;
+ }
+ looking:
+ for(var nm in o){
+ cnt++;
+ if(cnt==length){br = "\n";}
+ if(o[nm] === window || o[nm] === document){
+ continue;
+ }else if(o[nm] === null){
+ txt += i+nm + " : NULL" + br;
+ }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(o[nm] instanceof Date){
+ txt += i+nm + " : " + o[nm].toString() + 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]);
+
+ opnCls = (isArray(o[nm]))?["[","]"]:["{","}"];
+ txt += i+nm +" : " + opnCls[0] + "\n";//non-standard break, (no comma)
+ txt += printObject(o[nm], i+ind, "", used);
+ txt += i + opnCls[1] + br;
+
+ }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;
+ }
+ }
+ 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);
+ if(obj.nodeType == 1){
+ return escapeHTML('< '+obj.tagName.toLowerCase()+' id=\"'+ obj.id+ '\" />');
+ }
+ if(obj.nodeType == 3){
+ return escapeHTML('[TextNode: "'+obj.nodeValue+'"]');
+ }
+ 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+":"+escapeHTML(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);
+ }
+
+ dojo.addOnWindowUnload(function(){
+ // Erase the globals and event handlers I created, to prevent spurious leak warnings
+ removeEvent(document, dojo.isIE || dojo.isSafari ? "keydown" : "keypress", onKeyDown);
+ window.onFirebugResize = null;
+ window.console = null;
+ });
}
+
})();
+
+
}
diff --git a/lib/dojo/back.js b/lib/dojo/back.js
index a26562872..5e2998c97 100644
--- a/lib/dojo/back.js
+++ b/lib/dojo/back.js
@@ -5,254 +5,406 @@
*/
-if(!dojo._hasResource["dojo.back"]){
-dojo._hasResource["dojo.back"]=true;
+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");
-(function(){
-var _1=dojo.back;
-function _2(){
-var h=window.location.hash;
-if(h.charAt(0)=="#"){
-h=h.substring(1);
-}
-return dojo.isMozilla?h:decodeURIComponent(h);
-};
-function _3(h){
-if(!h){
-h="";
-}
-window.location.hash=encodeURIComponent(h);
-_4=history.length;
-};
-if(dojo.exists("tests.back-hash")){
-_1.getHash=_2;
-_1.setHash=_3;
-}
-var _5=(typeof (window)!=="undefined")?window.location.href:"";
-var _6=(typeof (window)!=="undefined")?_2():"";
-var _7=null;
-var _8=null;
-var _9=null;
-var _a=null;
-var _b=[];
-var _c=[];
-var _d=false;
-var _e=false;
-var _4;
-function _f(){
-var _10=_c.pop();
-if(!_10){
-return;
-}
-var _11=_c[_c.length-1];
-if(!_11&&_c.length==0){
-_11=_7;
-}
-if(_11){
-if(_11.kwArgs["back"]){
-_11.kwArgs["back"]();
-}else{
-if(_11.kwArgs["backButton"]){
-_11.kwArgs["backButton"]();
-}else{
-if(_11.kwArgs["handle"]){
-_11.kwArgs.handle("back");
-}
-}
-}
-}
-_b.push(_10);
-};
-_1.goBack=_f;
-function _12(){
-var _13=_b.pop();
-if(!_13){
-return;
-}
-if(_13.kwArgs["forward"]){
-_13.kwArgs.forward();
-}else{
-if(_13.kwArgs["forwardButton"]){
-_13.kwArgs.forwardButton();
-}else{
-if(_13.kwArgs["handle"]){
-_13.kwArgs.handle("forward");
-}
-}
-}
-_c.push(_13);
-};
-_1.goForward=_12;
-function _14(url,_15,_16){
-return {"url":url,"kwArgs":_15,"urlHash":_16};
-};
-function _17(url){
-var _18=url.split("?");
-if(_18.length<2){
-return null;
-}else{
-return _18[1];
-}
-};
-function _19(){
-var url=(dojo.config["dojoIframeHistoryUrl"]||dojo.moduleUrl("dojo","resources/iframe_history.html"))+"?"+(new Date()).getTime();
-_d=true;
-if(_a){
-dojo.isWebKit?_a.location=url:window.frames[_a.name].location=url;
-}else{
-}
-return url;
-};
-function _1a(){
-if(!_e){
-var hsl=_c.length;
-var _1b=_2();
-if((_1b===_6||window.location.href==_5)&&(hsl==1)){
-_f();
-return;
-}
-if(_b.length>0){
-if(_b[_b.length-1].urlHash===_1b){
-_12();
-return;
-}
-}
-if((hsl>=2)&&(_c[hsl-2])){
-if(_c[hsl-2].urlHash===_1b){
-_f();
-return;
-}
-}
-if(dojo.isSafari&&dojo.isSafari<3){
-var _1c=history.length;
-if(_1c>_4){
-_12();
-}else{
-if(_1c<_4){
-_f();
-}
-}
-_4=_1c;
-}
-}
-};
-_1.init=function(){
-if(dojo.byId("dj_history")){
-return;
-}
-var src=dojo.config["dojoIframeHistoryUrl"]||dojo.moduleUrl("dojo","resources/iframe_history.html");
-if(dojo._postLoad){
-console.error("dojo.back.init() must be called before the DOM has loaded. "+"If using xdomain loading or djConfig.debugAtAllCosts, include dojo.back "+"in a build layer.");
-}else{
-document.write("<iframe style=\"border:0;width:1px;height:1px;position:absolute;visibility:hidden;bottom:0;right:0;\" name=\"dj_history\" id=\"dj_history\" src=\""+src+"\"></iframe>");
-}
-};
-_1.setInitialState=function(_1d){
-_7=_14(_5,_1d,_6);
-};
-_1.addToHistory=function(_1e){
-_b=[];
-var _1f=null;
-var url=null;
-if(!_a){
-if(dojo.config["useXDomain"]&&!dojo.config["dojoIframeHistoryUrl"]){
-console.warn("dojo.back: When using cross-domain Dojo builds,"+" please save iframe_history.html to your domain and set djConfig.dojoIframeHistoryUrl"+" to the path on your domain to iframe_history.html");
-}
-_a=window.frames["dj_history"];
-}
-if(!_9){
-_9=dojo.create("a",{style:{display:"none"}},dojo.body());
-}
-if(_1e["changeUrl"]){
-_1f=""+((_1e["changeUrl"]!==true)?_1e["changeUrl"]:(new Date()).getTime());
-if(_c.length==0&&_7.urlHash==_1f){
-_7=_14(url,_1e,_1f);
-return;
-}else{
-if(_c.length>0&&_c[_c.length-1].urlHash==_1f){
-_c[_c.length-1]=_14(url,_1e,_1f);
-return;
-}
-}
-_e=true;
-setTimeout(function(){
-_3(_1f);
-_e=false;
-},1);
-_9.href=_1f;
-if(dojo.isIE){
-url=_19();
-var _20=_1e["back"]||_1e["backButton"]||_1e["handle"];
-var tcb=function(_21){
-if(_2()!=""){
-setTimeout(function(){
-_3(_1f);
-},1);
-}
-_20.apply(this,[_21]);
-};
-if(_1e["back"]){
-_1e.back=tcb;
-}else{
-if(_1e["backButton"]){
-_1e.backButton=tcb;
-}else{
-if(_1e["handle"]){
-_1e.handle=tcb;
-}
-}
-}
-var _22=_1e["forward"]||_1e["forwardButton"]||_1e["handle"];
-var tfw=function(_23){
-if(_2()!=""){
-_3(_1f);
-}
-if(_22){
-_22.apply(this,[_23]);
-}
-};
-if(_1e["forward"]){
-_1e.forward=tfw;
-}else{
-if(_1e["forwardButton"]){
-_1e.forwardButton=tfw;
-}else{
-if(_1e["handle"]){
-_1e.handle=tfw;
-}
-}
-}
-}else{
-if(!dojo.isIE){
-if(!_8){
-_8=setInterval(_1a,200);
-}
-}
-}
-}else{
-url=_19();
-}
-_c.push(_14(url,_1e,_1f));
-};
-_1._iframeLoaded=function(evt,_24){
-var _25=_17(_24.href);
-if(_25==null){
-if(_c.length==1){
-_f();
-}
-return;
-}
-if(_d){
-_d=false;
-return;
-}
-if(_c.length>=2&&_25==_17(_c[_c.length-2].url)){
-_f();
-}else{
-if(_b.length>0&&_25==_17(_b[_b.length-1].url)){
-_12();
-}
+
+/*=====
+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.
+ 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);
+ }
+
+ back.goBack = handleBackButton;
+
+ function handleForwardButton(){
+ //summary: private method. Do not call this directly.
+ 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);
+ }
+
+ 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.isWebKit ? historyIframe.location = url : window.frames[historyIframe.name].location = url;
+ }else{
+ //console.warn("dojo.back: Not initialised. You need to call dojo.back.init() from a <script> block that lives inside the <body> tag.");
+ }
+ return url; //String
+ }
+
+ function checkLocation(){
+ if(!changingUrl){
+ var hsl = historyStack.length;
+
+ var hash = getHash();
+
+ if((hash === initialHash||window.location.href == initialHref)&&(hsl == 1)){
+ // FIXME: could this ever be a forward button?
+ // we can't clear it because we still need to check for forwards. Ugg.
+ // clearInterval(this.locationTimer);
+ handleBackButton();
+ return;
+ }
+
+ // first check to see if we could have gone forward. We always halt on
+ // a no-hash item.
+ if(forwardStack.length > 0){
+ if(forwardStack[forwardStack.length-1].urlHash === hash){
+ handleForwardButton();
+ return;
+ }
+ }
+
+ // ok, that didn't work, try someplace back in the history stack
+ if((hsl >= 2)&&(historyStack[hsl-2])){
+ if(historyStack[hsl-2].urlHash === hash){
+ handleBackButton();
+ return;
+ }
+ }
+
+ if(dojo.isSafari && dojo.isSafari < 3){
+ var hisLen = history.length;
+ if(hisLen > historyCounter) handleForwardButton();
+ else if(hisLen < historyCounter) handleBackButton();
+ historyCounter = hisLen;
+ }
+ }
+ };
+
+ back.init = function(){
+ //summary: Initializes the undo stack. This must be called from a <script>
+ // block that lives inside the <body> tag to prevent bugs on IE.
+ // description:
+ // Only call this method before the page's DOM is finished loading. Otherwise
+ // it will not work. Be careful with xdomain loading or djConfig.debugAtAllCosts scenarios,
+ // in order for this method to work, dojo.back will need to be part of a build layer.
+ if(dojo.byId("dj_history")){ return; } // prevent reinit
+ var src = dojo.config["dojoIframeHistoryUrl"] || dojo.moduleUrl("dojo", "resources/iframe_history.html");
+ if (dojo._postLoad) {
+ console.error("dojo.back.init() must be called before the DOM has loaded. "
+ + "If using xdomain loading or djConfig.debugAtAllCosts, include dojo.back "
+ + "in a build layer.");
+ } else {
+ document.write('<iframe style="border:0;width:1px;height:1px;position:absolute;visibility:hidden;bottom:0;right:0;" name="dj_history" id="dj_history" src="' + src + '"></iframe>');
+ }
+ };
+
+ back.setInitialState = function(/*Object*/args){
+ //summary:
+ // Sets the state object and back callback for the very first page
+ // that is loaded.
+ //description:
+ // It is recommended that you call this method as part of an event
+ // listener that is registered via dojo.addOnLoad().
+ //args: Object
+ // See the addToHistory() function for the list of valid args properties.
+ initialState = createState(initialHref, args, initialHash);
+ };
+
+ //FIXME: Make these doc comments not be awful. At least they're not wrong.
+ //FIXME: Would like to support arbitrary back/forward jumps. Have to rework iframeLoaded among other things.
+ //FIXME: is there a slight race condition in moz using change URL with the timer check and when
+ // the hash gets set? I think I have seen a back/forward call in quick succession, but not consistent.
+
+
+ /*=====
+ dojo.__backArgs = function(kwArgs){
+ // back: Function?
+ // A function to be called when this state is reached via the user
+ // clicking the back button.
+ // forward: Function?
+ // Upon return to this state from the "back, forward" combination
+ // of navigation steps, this function will be called. Somewhat
+ // analgous to the semantic of an "onRedo" event handler.
+ // changeUrl: Boolean?|String?
+ // Boolean indicating whether or not to create a unique hash for
+ // this state. If a string is passed instead, it is used as the
+ // hash.
+ }
+ =====*/
+
+ back.addToHistory = function(/*dojo.__backArgs*/ args){
+ // summary:
+ // adds a state object (args) to the history list.
+ // description:
+ // To support getting back button notifications, the object
+ // argument should implement a function called either "back",
+ // "backButton", or "handle". The string "back" will be passed as
+ // the first and only argument to this callback.
+ //
+ // To support getting forward button notifications, the object
+ // argument should implement a function called either "forward",
+ // "forwardButton", or "handle". The string "forward" will be
+ // passed as the first and only argument to this callback.
+ //
+ // If you want the browser location string to change, define "changeUrl" on the object. If the
+ // value of "changeUrl" is true, then a unique number will be appended to the URL as a fragment
+ // identifier (http://some.domain.com/path#uniquenumber). If it is any other value that does
+ // not evaluate to false, that value will be used as the fragment identifier. For example,
+ // if changeUrl: 'page1', then the URL will look like: http://some.domain.com/path#page1
+ //
+ // There are problems with using dojo.back with semantically-named fragment identifiers
+ // ("hash values" on an URL). In most browsers it will be hard for dojo.back to know
+ // distinguish a back from a forward event in those cases. For back/forward support to
+ // work best, the fragment ID should always be a unique value (something using new Date().getTime()
+ // for example). If you want to detect hash changes using semantic fragment IDs, then
+ // consider using dojo.hash instead (in Dojo 1.4+).
+ //
+ // example:
+ // | dojo.back.addToHistory({
+ // | back: function(){ console.log('back pressed'); },
+ // | forward: function(){ console.log('forward pressed'); },
+ // | changeUrl: true
+ // | });
+
+ // BROWSER NOTES:
+ // Safari 1.2:
+ // back button "works" fine, however it's not possible to actually
+ // DETECT that you've moved backwards by inspecting window.location.
+ // Unless there is some other means of locating.
+ // FIXME: perhaps we can poll on history.length?
+ // Safari 2.0.3+ (and probably 1.3.2+):
+ // works fine, except when changeUrl is used. When changeUrl is used,
+ // Safari jumps all the way back to whatever page was shown before
+ // the page that uses dojo.undo.browser support.
+ // IE 5.5 SP2:
+ // back button behavior is macro. It does not move back to the
+ // previous hash value, but to the last full page load. This suggests
+ // that the iframe is the correct way to capture the back button in
+ // these cases.
+ // Don't test this page using local disk for MSIE. MSIE will not create
+ // a history list for iframe_history.html if served from a file: URL.
+ // The XML served back from the XHR tests will also not be properly
+ // created if served from local disk. Serve the test pages from a web
+ // server to test in that browser.
+ // IE 6.0:
+ // same behavior as IE 5.5 SP2
+ // Firefox 1.0+:
+ // the back button will return us to the previous hash on the same
+ // page, thereby not requiring an iframe hack, although we do then
+ // need to run a timer to detect inter-page movement.
+
+ //If addToHistory is called, then that means we prune the
+ //forward stack -- the user went back, then wanted to
+ //start a new forward path.
+ forwardStack = [];
+
+ var hash = null;
+ var url = null;
+ if(!historyIframe){
+ if(dojo.config["useXDomain"] && !dojo.config["dojoIframeHistoryUrl"]){
+ console.warn("dojo.back: When using cross-domain Dojo builds,"
+ + " please save iframe_history.html to your domain and set djConfig.dojoIframeHistoryUrl"
+ + " to the path on your domain to iframe_history.html");
+ }
+ historyIframe = window.frames["dj_history"];
+ }
+ if(!bookmarkAnchor){
+ bookmarkAnchor = dojo.create("a", {style: {display: "none"}}, dojo.body());
+ }
+ if(args["changeUrl"]){
+ hash = ""+ ((args["changeUrl"]!==true) ? args["changeUrl"] : (new Date()).getTime());
+
+ //If the current hash matches the new one, just replace the history object with
+ //this new one. It doesn't make sense to track different state objects for the same
+ //logical URL. This matches the browser behavior of only putting in one history
+ //item no matter how many times you click on the same #hash link, at least in Firefox
+ //and Safari, and there is no reliable way in those browsers to know if a #hash link
+ //has been clicked on multiple times. So making this the standard behavior in all browsers
+ //so that dojo.back's behavior is the same in all browsers.
+ if(historyStack.length == 0 && initialState.urlHash == hash){
+ initialState = createState(url, args, hash);
+ return;
+ }else if(historyStack.length > 0 && historyStack[historyStack.length - 1].urlHash == hash){
+ historyStack[historyStack.length - 1] = createState(url, args, hash);
+ return;
+ }
+
+ changingUrl = true;
+ setTimeout(function() {
+ setHash(hash);
+ changingUrl = false;
+ }, 1);
+ bookmarkAnchor.href = hash;
+
+ if(dojo.isIE){
+ url = loadIframeHistory();
+
+ var oldCB = args["back"]||args["backButton"]||args["handle"];
+
+ //The function takes handleName as a parameter, in case the
+ //callback we are overriding was "handle". In that case,
+ //we will need to pass the handle name to handle.
+ var tcb = function(handleName){
+ if(getHash() != ""){
+ setTimeout(function() { setHash(hash); }, 1);
+ }
+ //Use apply to set "this" to args, and to try to avoid memory leaks.
+ oldCB.apply(this, [handleName]);
+ };
+
+ //Set interceptor function in the right place.
+ if(args["back"]){
+ args.back = tcb;
+ }else if(args["backButton"]){
+ args.backButton = tcb;
+ }else if(args["handle"]){
+ args.handle = tcb;
+ }
+
+ var oldFW = args["forward"]||args["forwardButton"]||args["handle"];
+
+ //The function takes handleName as a parameter, in case the
+ //callback we are overriding was "handle". In that case,
+ //we will need to pass the handle name to handle.
+ var tfw = function(handleName){
+ if(getHash() != ""){
+ setHash(hash);
+ }
+ if(oldFW){ // we might not actually have one
+ //Use apply to set "this" to args, and to try to avoid memory leaks.
+ oldFW.apply(this, [handleName]);
+ }
+ };
+
+ //Set interceptor function in the right place.
+ if(args["forward"]){
+ args.forward = tfw;
+ }else if(args["forwardButton"]){
+ args.forwardButton = tfw;
+ }else if(args["handle"]){
+ args.handle = tfw;
+ }
+
+ }else if(!dojo.isIE){
+ // start the timer
+ if(!locationTimer){
+ locationTimer = setInterval(checkLocation, 200);
+ }
+
+ }
+ }else{
+ url = loadIframeHistory();
+ }
+
+ historyStack.push(createState(url, args, hash));
+ };
+
+ back._iframeLoaded = function(evt, ifrLoc){
+ //summary:
+ // private method. Do not call this directly.
+ var query = getUrlQuery(ifrLoc.href);
+ if(query == null){
+ // alert("iframeLoaded");
+ // we hit the end of the history, so we should go back
+ if(historyStack.length == 1){
+ handleBackButton();
+ }
+ return;
+ }
+ if(moveForward){
+ // we were expecting it, so it's not either a forward or backward movement
+ moveForward = false;
+ return;
+ }
+
+ //Check the back stack first, since it is more likely.
+ //Note that only one step back or forward is supported.
+ if(historyStack.length >= 2 && query == getUrlQuery(historyStack[historyStack.length-2].url)){
+ handleBackButton();
+ }else if(forwardStack.length > 0 && query == getUrlQuery(forwardStack[forwardStack.length-1].url)){
+ handleForwardButton();
+ }
+ };
+ })();
+
}
diff --git a/lib/dojo/behavior.js b/lib/dojo/behavior.js
index 3420fec20..15f1f23a3 100644
--- a/lib/dojo/behavior.js
+++ b/lib/dojo/behavior.js
@@ -5,90 +5,246 @@
*/
-if(!dojo._hasResource["dojo.behavior"]){
-dojo._hasResource["dojo.behavior"]=true;
+if(!dojo._hasResource["dojo.behavior"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.behavior"] = true;
dojo.provide("dojo.behavior");
-dojo.behavior=new function(){
-function _1(_2,_3){
-if(!_2[_3]){
-_2[_3]=[];
-}
-return _2[_3];
-};
-var _4=0;
-function _5(_6,_7,_8){
-var _9={};
-for(var x in _6){
-if(typeof _9[x]=="undefined"){
-if(!_8){
-_7(_6[x],x);
-}else{
-_8.call(_7,_6[x],x);
-}
-}
-}
-};
-this._behaviors={};
-this.add=function(_a){
-var _b={};
-_5(_a,this,function(_c,_d){
-var _e=_1(this._behaviors,_d);
-if(typeof _e["id"]!="number"){
-_e.id=_4++;
-}
-var _f=[];
-_e.push(_f);
-if((dojo.isString(_c))||(dojo.isFunction(_c))){
-_c={found:_c};
-}
-_5(_c,function(_10,_11){
-_1(_f,_11).push(_10);
-});
-});
-};
-var _12=function(_13,_14,_15){
-if(dojo.isString(_14)){
-if(_15=="found"){
-dojo.publish(_14,[_13]);
-}else{
-dojo.connect(_13,_15,function(){
-dojo.publish(_14,arguments);
-});
-}
-}else{
-if(dojo.isFunction(_14)){
-if(_15=="found"){
-_14(_13);
-}else{
-dojo.connect(_13,_15,_14);
-}
-}
-}
-};
-this.apply=function(){
-_5(this._behaviors,function(_16,id){
-dojo.query(id).forEach(function(_17){
-var _18=0;
-var bid="_dj_behavior_"+_16.id;
-if(typeof _17[bid]=="number"){
-_18=_17[bid];
-if(_18==(_16.length)){
-return;
-}
-}
-for(var x=_18,_19;_19=_16[x];x++){
-_5(_19,function(_1a,_1b){
-if(dojo.isArray(_1a)){
-dojo.forEach(_1a,function(_1c){
-_12(_17,_1c,_1b);
-});
-}
-});
+
+dojo.behavior = new function(){
+ // summary:
+ // Utility for unobtrusive/progressive event binding, DOM traversal,
+ // and manipulation.
+ //
+ // description:
+ //
+ // A very simple, lightweight mechanism for applying code to
+ // existing documents, based around `dojo.query` (CSS3 selectors) for node selection,
+ // and a simple two-command API: `dojo.behavior.add()` and `dojo.behavior.apply()`;
+ //
+ // Behaviors apply to a given page, and are registered following the syntax
+ // options described by `dojo.behavior.add` to match nodes to actions, or "behaviors".
+ //
+ // Added behaviors are applied to the current DOM when .apply() is called,
+ // matching only new nodes found since .apply() was last called.
+ //
+ function arrIn(obj, name){
+ if(!obj[name]){ obj[name] = []; }
+ return obj[name];
+ }
+
+ var _inc = 0;
+
+ function forIn(obj, scope, func){
+ var tmpObj = {};
+ for(var x in obj){
+ if(typeof tmpObj[x] == "undefined"){
+ if(!func){
+ scope(obj[x], x);
+ }else{
+ func.call(scope, obj[x], x);
+ }
+ }
+ }
+ }
+
+ // FIXME: need a better test so we don't exclude nightly Safari's!
+ this._behaviors = {};
+ this.add = function(/* Object */behaviorObj){
+ // summary:
+ // Add the specified behavior to the list of behaviors, ignoring existing
+ // matches.
+ //
+ // description:
+ // Add the specified behavior to the list of behaviors which will
+ // be applied the next time apply() is called. Calls to add() for
+ // an already existing behavior do not replace the previous rules,
+ // but are instead additive. New nodes which match the rule will
+ // have all add()-ed behaviors applied to them when matched.
+ //
+ // The "found" method is a generalized handler that's called as soon
+ // as the node matches the selector. Rules for values that follow also
+ // apply to the "found" key.
+ //
+ // The "on*" handlers are attached with `dojo.connect()`, using the
+ // matching node
+ //
+ // If the value corresponding to the ID key is a function and not a
+ // list, it's treated as though it was the value of "found".
+ //
+ // dojo.behavior.add() can be called any number of times before
+ // the DOM is ready. `dojo.behavior.apply()` is called automatically
+ // by `dojo.addOnLoad`, though can be called to re-apply previously added
+ // behaviors anytime the DOM changes.
+ //
+ // There are a variety of formats permitted in the behaviorObject
+ //
+ // example:
+ // Simple list of properties. "found" is special. "Found" is assumed if
+ // no property object for a given selector, and property is a function.
+ //
+ // | dojo.behavior.add({
+ // | "#id": {
+ // | "found": function(element){
+ // | // node match found
+ // | },
+ // | "onclick": function(evt){
+ // | // register onclick handler for found node
+ // | }
+ // | },
+ // | "#otherid": function(element){
+ // | // assumes "found" with this syntax
+ // | }
+ // | });
+ //
+ // example:
+ // If property is a string, a dojo.publish will be issued on the channel:
+ //
+ // | dojo.behavior.add({
+ // | // dojo.publish() whenever class="noclick" found on anchors
+ // | "a.noclick": "/got/newAnchor",
+ // | "div.wrapper": {
+ // | "onclick": "/node/wasClicked"
+ // | }
+ // | });
+ // | dojo.subscribe("/got/newAnchor", function(node){
+ // | // handle node finding when dojo.behavior.apply() is called,
+ // | // provided a newly matched node is found.
+ // | });
+ //
+ // example:
+ // Scoping can be accomplished by passing an object as a property to
+ // a connection handle (on*):
+ //
+ // | dojo.behavior.add({
+ // | "#id": {
+ // | // like calling dojo.hitch(foo,"bar"). execute foo.bar() in scope of foo
+ // | "onmouseenter": { targetObj: foo, targetFunc: "bar" },
+ // | "onmouseleave": { targetObj: foo, targetFunc: "baz" }
+ // | }
+ // | });
+ //
+ // example:
+ // Bahaviors match on CSS3 Selectors, powered by dojo.query. Example selectors:
+ //
+ // | dojo.behavior.add({
+ // | // match all direct descendants
+ // | "#id4 > *": function(element){
+ // | // ...
+ // | },
+ // |
+ // | // match the first child node that's an element
+ // | "#id4 > :first-child": { ... },
+ // |
+ // | // match the last child node that's an element
+ // | "#id4 > :last-child": { ... },
+ // |
+ // | // all elements of type tagname
+ // | "tagname": {
+ // | // ...
+ // | },
+ // |
+ // | "tagname1 tagname2 tagname3": {
+ // | // ...
+ // | },
+ // |
+ // | ".classname": {
+ // | // ...
+ // | },
+ // |
+ // | "tagname.classname": {
+ // | // ...
+ // | }
+ // | });
+ //
+
+ var tmpObj = {};
+ forIn(behaviorObj, this, function(behavior, name){
+ var tBehavior = arrIn(this._behaviors, name);
+ if(typeof tBehavior["id"] != "number"){
+ tBehavior.id = _inc++;
+ }
+ var cversion = [];
+ tBehavior.push(cversion);
+ if((dojo.isString(behavior))||(dojo.isFunction(behavior))){
+ behavior = { found: behavior };
+ }
+ forIn(behavior, function(rule, ruleName){
+ arrIn(cversion, ruleName).push(rule);
+ });
+ });
+ }
+
+ var _applyToNode = function(node, action, ruleSetName){
+ if(dojo.isString(action)){
+ if(ruleSetName == "found"){
+ dojo.publish(action, [ node ]);
+ }else{
+ dojo.connect(node, ruleSetName, function(){
+ dojo.publish(action, arguments);
+ });
+ }
+ }else if(dojo.isFunction(action)){
+ if(ruleSetName == "found"){
+ action(node);
+ }else{
+ dojo.connect(node, ruleSetName, action);
+ }
+ }
+ }
+
+ this.apply = function(){
+ // summary:
+ // Applies all currently registered behaviors to the document.
+ //
+ // description:
+ // Applies all currently registered behaviors to the document,
+ // taking care to ensure that only incremental updates are made
+ // since the last time add() or apply() were called.
+ //
+ // If new matching nodes have been added, all rules in a behavior will be
+ // applied to that node. For previously matched nodes, only
+ // behaviors which have been added since the last call to apply()
+ // will be added to the nodes.
+ //
+ // apply() is called once automatically by `dojo.addOnLoad`, so
+ // registering behaviors with `dojo.behavior.add` before the DOM is
+ // ready is acceptable, provided the dojo.behavior module is ready.
+ //
+ // Calling appy() manually after manipulating the DOM is required
+ // to rescan the DOM and apply newly .add()ed behaviors, or to match
+ // nodes that match existing behaviors when those nodes are added to
+ // the DOM.
+ //
+ forIn(this._behaviors, function(tBehavior, id){
+ dojo.query(id).forEach(
+ function(elem){
+ var runFrom = 0;
+ var bid = "_dj_behavior_"+tBehavior.id;
+ if(typeof elem[bid] == "number"){
+ runFrom = elem[bid];
+ if(runFrom == (tBehavior.length)){
+ return;
+ }
+ }
+ // run through the versions, applying newer rules at each step
+
+ for(var x=runFrom, tver; tver = tBehavior[x]; x++){
+ forIn(tver, function(ruleSet, ruleSetName){
+ if(dojo.isArray(ruleSet)){
+ dojo.forEach(ruleSet, function(action){
+ _applyToNode(elem, action, ruleSetName);
+ });
+ }
+ });
+ }
+
+ // ensure that re-application only adds new rules to the node
+ elem[bid] = tBehavior.length;
+ }
+ );
+ });
+ }
}
-_17[bid]=_16.length;
-});
-});
-};
-};
-dojo.addOnLoad(dojo.behavior,"apply");
+
+dojo.addOnLoad(dojo.behavior, "apply");
+
}
diff --git a/lib/dojo/build.txt b/lib/dojo/build.txt
index 5db48dd14..bc58b776f 100644
--- a/lib/dojo/build.txt
+++ b/lib/dojo/build.txt
@@ -5,324 +5,119 @@ dojo.js:
./../../dojo/_base/_loader/bootstrap.js
./../../dojo/_base/_loader/loader.js
./../../dojo/_base/_loader/hostenv_browser.js
-./../../release/dojo-release-1.5.0/dojo/_base/lang.js
-./../../release/dojo-release-1.5.0/dojo/_base/array.js
-./../../release/dojo-release-1.5.0/dojo/_base/declare.js
-./../../release/dojo-release-1.5.0/dojo/_base/connect.js
-./../../release/dojo-release-1.5.0/dojo/_base/Deferred.js
-./../../release/dojo-release-1.5.0/dojo/_base/json.js
-./../../release/dojo-release-1.5.0/dojo/_base/Color.js
-./../../release/dojo-release-1.5.0/dojo/_base.js
-./../../release/dojo-release-1.5.0/dojo/_base/window.js
-./../../release/dojo-release-1.5.0/dojo/_base/event.js
-./../../release/dojo-release-1.5.0/dojo/_base/html.js
-./../../release/dojo-release-1.5.0/dojo/_base/NodeList.js
-./../../release/dojo-release-1.5.0/dojo/_base/query.js
-./../../release/dojo-release-1.5.0/dojo/_base/xhr.js
-./../../release/dojo-release-1.5.0/dojo/_base/fx.js
-./../../release/dojo-release-1.5.0/dojo/_base/browser.js
+./../../release/dojo/_base/lang.js
+./../../release/dojo/_base/array.js
+./../../release/dojo/_base/declare.js
+./../../release/dojo/_base/connect.js
+./../../release/dojo/_base/Deferred.js
+./../../release/dojo/_base/json.js
+./../../release/dojo/_base/Color.js
+./../../release/dojo/_base.js
+./../../release/dojo/_base/window.js
+./../../release/dojo/_base/event.js
+./../../release/dojo/_base/html.js
+./../../release/dojo/_base/NodeList.js
+./../../release/dojo/_base/query.js
+./../../release/dojo/_base/xhr.js
+./../../release/dojo/_base/fx.js
+./../../release/dojo/_base/browser.js
./jslib/dojoGuardEnd.jsfrag
-../dijit/dijit.js:
-./../../release/dojo-release-1.5.0/dojo/window.js
-./../../release/dojo-release-1.5.0/dijit/_base/manager.js
-./../../release/dojo-release-1.5.0/dijit/_base/focus.js
-./../../release/dojo-release-1.5.0/dojo/AdapterRegistry.js
-./../../release/dojo-release-1.5.0/dijit/_base/place.js
-./../../release/dojo-release-1.5.0/dijit/_base/window.js
-./../../release/dojo-release-1.5.0/dijit/_base/popup.js
-./../../release/dojo-release-1.5.0/dijit/_base/scroll.js
-./../../release/dojo-release-1.5.0/dojo/uacss.js
-./../../release/dojo-release-1.5.0/dijit/_base/sniff.js
-./../../release/dojo-release-1.5.0/dijit/_base/typematic.js
-./../../release/dojo-release-1.5.0/dijit/_base/wai.js
-./../../release/dojo-release-1.5.0/dijit/_base.js
-./../../release/dojo-release-1.5.0/dojo/date/stamp.js
-./../../release/dojo-release-1.5.0/dojo/parser.js
-./../../release/dojo-release-1.5.0/dijit/_Widget.js
-./../../release/dojo-release-1.5.0/dojo/string.js
-./../../release/dojo-release-1.5.0/dojo/cache.js
-./../../release/dojo-release-1.5.0/dijit/_Templated.js
-./../../release/dojo-release-1.5.0/dijit/_Container.js
-./../../release/dojo-release-1.5.0/dijit/_Contained.js
-./../../release/dojo-release-1.5.0/dijit/layout/_LayoutWidget.js
-./../../release/dojo-release-1.5.0/dijit/_CssStateMixin.js
-./../../release/dojo-release-1.5.0/dijit/form/_FormWidget.js
-./../../release/dojo-release-1.5.0/dijit/dijit.js
-
-../dijit/dijit-all.js:
-./../../release/dojo-release-1.5.0/dojo/colors.js
-./../../release/dojo-release-1.5.0/dojo/i18n.js
-./../../release/dojo-release-1.5.0/dijit/_PaletteMixin.js
-./../../release/dojo-release-1.5.0/dijit/ColorPalette.js
-./../../release/dojo-release-1.5.0/dijit/Declaration.js
-./../../release/dojo-release-1.5.0/dojo/dnd/common.js
-./../../release/dojo-release-1.5.0/dojo/dnd/autoscroll.js
-./../../release/dojo-release-1.5.0/dojo/dnd/Mover.js
-./../../release/dojo-release-1.5.0/dojo/dnd/Moveable.js
-./../../release/dojo-release-1.5.0/dojo/dnd/move.js
-./../../release/dojo-release-1.5.0/dojo/dnd/TimedMoveable.js
-./../../release/dojo-release-1.5.0/dojo/fx/Toggler.js
-./../../release/dojo-release-1.5.0/dojo/fx.js
-./../../release/dojo-release-1.5.0/dijit/form/_FormMixin.js
-./../../release/dojo-release-1.5.0/dijit/_DialogMixin.js
-./../../release/dojo-release-1.5.0/dijit/DialogUnderlay.js
-./../../release/dojo-release-1.5.0/dojo/html.js
-./../../release/dojo-release-1.5.0/dijit/layout/ContentPane.js
-./../../release/dojo-release-1.5.0/dijit/TooltipDialog.js
-./../../release/dojo-release-1.5.0/dijit/Dialog.js
-./../../release/dojo-release-1.5.0/dijit/_editor/selection.js
-./../../release/dojo-release-1.5.0/dijit/_editor/range.js
-./../../release/dojo-release-1.5.0/dijit/_editor/html.js
-./../../release/dojo-release-1.5.0/dijit/_editor/RichText.js
-./../../release/dojo-release-1.5.0/dijit/_KeyNavContainer.js
-./../../release/dojo-release-1.5.0/dijit/ToolbarSeparator.js
-./../../release/dojo-release-1.5.0/dijit/Toolbar.js
-./../../release/dojo-release-1.5.0/dijit/_HasDropDown.js
-./../../release/dojo-release-1.5.0/dijit/form/Button.js
-./../../release/dojo-release-1.5.0/dijit/_editor/_Plugin.js
-./../../release/dojo-release-1.5.0/dijit/_editor/plugins/EnterKeyHandling.js
-./../../release/dojo-release-1.5.0/dijit/Editor.js
-./../../release/dojo-release-1.5.0/dojo/regexp.js
-./../../release/dojo-release-1.5.0/dojo/data/util/sorter.js
-./../../release/dojo-release-1.5.0/dojo/data/util/simpleFetch.js
-./../../release/dojo-release-1.5.0/dojo/data/util/filter.js
-./../../release/dojo-release-1.5.0/dijit/form/TextBox.js
-./../../release/dojo-release-1.5.0/dijit/Tooltip.js
-./../../release/dojo-release-1.5.0/dijit/form/ValidationTextBox.js
-./../../release/dojo-release-1.5.0/dijit/form/ComboBox.js
-./../../release/dojo-release-1.5.0/dijit/form/FilteringSelect.js
-./../../release/dojo-release-1.5.0/dojo/data/ItemFileReadStore.js
-./../../release/dojo-release-1.5.0/dijit/_editor/plugins/FontChoice.js
-./../../release/dojo-release-1.5.0/dijit/form/_FormSelectWidget.js
-./../../release/dojo-release-1.5.0/dijit/MenuItem.js
-./../../release/dojo-release-1.5.0/dijit/PopupMenuItem.js
-./../../release/dojo-release-1.5.0/dijit/CheckedMenuItem.js
-./../../release/dojo-release-1.5.0/dijit/MenuSeparator.js
-./../../release/dojo-release-1.5.0/dijit/Menu.js
-./../../release/dojo-release-1.5.0/dijit/form/Select.js
-./../../release/dojo-release-1.5.0/dijit/_editor/plugins/LinkDialog.js
-./../../release/dojo-release-1.5.0/dijit/MenuBar.js
-./../../release/dojo-release-1.5.0/dijit/MenuBarItem.js
-./../../release/dojo-release-1.5.0/dijit/PopupMenuBarItem.js
-./../../release/dojo-release-1.5.0/dojo/number.js
-./../../release/dojo-release-1.5.0/dijit/ProgressBar.js
-./../../release/dojo-release-1.5.0/dijit/TitlePane.js
-./../../release/dojo-release-1.5.0/dojo/DeferredList.js
-./../../release/dojo-release-1.5.0/dojo/cookie.js
-./../../release/dojo-release-1.5.0/dijit/tree/TreeStoreModel.js
-./../../release/dojo-release-1.5.0/dijit/tree/ForestStoreModel.js
-./../../release/dojo-release-1.5.0/dijit/Tree.js
-./../../release/dojo-release-1.5.0/dijit/InlineEditBox.js
-./../../release/dojo-release-1.5.0/dijit/form/Form.js
-./../../release/dojo-release-1.5.0/dijit/form/DropDownButton.js
-./../../release/dojo-release-1.5.0/dijit/form/ComboButton.js
-./../../release/dojo-release-1.5.0/dijit/form/ToggleButton.js
-./../../release/dojo-release-1.5.0/dijit/form/CheckBox.js
-./../../release/dojo-release-1.5.0/dijit/form/RadioButton.js
-./../../release/dojo-release-1.5.0/dojo/cldr/monetary.js
-./../../release/dojo-release-1.5.0/dojo/currency.js
-./../../release/dojo-release-1.5.0/dijit/form/NumberTextBox.js
-./../../release/dojo-release-1.5.0/dijit/form/CurrencyTextBox.js
-./../../release/dojo-release-1.5.0/dojo/cldr/supplemental.js
-./../../release/dojo-release-1.5.0/dojo/date.js
-./../../release/dojo-release-1.5.0/dojo/date/locale.js
-./../../release/dojo-release-1.5.0/dijit/Calendar.js
-./../../release/dojo-release-1.5.0/dijit/form/_DateTimeTextBox.js
-./../../release/dojo-release-1.5.0/dijit/form/DateTextBox.js
-./../../release/dojo-release-1.5.0/dijit/form/_Spinner.js
-./../../release/dojo-release-1.5.0/dijit/form/NumberSpinner.js
-./../../release/dojo-release-1.5.0/dijit/form/MultiSelect.js
-./../../release/dojo-release-1.5.0/dijit/form/HorizontalSlider.js
-./../../release/dojo-release-1.5.0/dijit/form/VerticalSlider.js
-./../../release/dojo-release-1.5.0/dijit/form/HorizontalRule.js
-./../../release/dojo-release-1.5.0/dijit/form/VerticalRule.js
-./../../release/dojo-release-1.5.0/dijit/form/HorizontalRuleLabels.js
-./../../release/dojo-release-1.5.0/dijit/form/VerticalRuleLabels.js
-./../../release/dojo-release-1.5.0/dijit/form/SimpleTextarea.js
-./../../release/dojo-release-1.5.0/dijit/form/Textarea.js
-./../../release/dojo-release-1.5.0/dijit/layout/StackController.js
-./../../release/dojo-release-1.5.0/dijit/layout/StackContainer.js
-./../../release/dojo-release-1.5.0/dijit/layout/AccordionPane.js
-./../../release/dojo-release-1.5.0/dijit/layout/AccordionContainer.js
-./../../release/dojo-release-1.5.0/dijit/layout/BorderContainer.js
-./../../release/dojo-release-1.5.0/dijit/layout/LayoutContainer.js
-./../../release/dojo-release-1.5.0/dijit/layout/LinkPane.js
-./../../release/dojo-release-1.5.0/dijit/layout/SplitContainer.js
-./../../release/dojo-release-1.5.0/dijit/layout/_TabContainerBase.js
-./../../release/dojo-release-1.5.0/dijit/layout/TabController.js
-./../../release/dojo-release-1.5.0/dijit/layout/ScrollingTabController.js
-./../../release/dojo-release-1.5.0/dijit/layout/TabContainer.js
-./../../release/dojo-release-1.5.0/dijit/dijit-all.js
-
-../dojox/grid/DataGrid.js:
-./../../release/dojo-release-1.5.0/dojo/window.js
-./../../release/dojo-release-1.5.0/dijit/_base/manager.js
-./../../release/dojo-release-1.5.0/dijit/_base/focus.js
-./../../release/dojo-release-1.5.0/dojo/AdapterRegistry.js
-./../../release/dojo-release-1.5.0/dijit/_base/place.js
-./../../release/dojo-release-1.5.0/dijit/_base/window.js
-./../../release/dojo-release-1.5.0/dijit/_base/popup.js
-./../../release/dojo-release-1.5.0/dijit/_base/scroll.js
-./../../release/dojo-release-1.5.0/dojo/uacss.js
-./../../release/dojo-release-1.5.0/dijit/_base/sniff.js
-./../../release/dojo-release-1.5.0/dijit/_base/typematic.js
-./../../release/dojo-release-1.5.0/dijit/_base/wai.js
-./../../release/dojo-release-1.5.0/dijit/_base.js
-./../../release/dojo-release-1.5.0/dojo/date/stamp.js
-./../../release/dojo-release-1.5.0/dojo/parser.js
-./../../release/dojo-release-1.5.0/dijit/_Widget.js
-./../../release/dojo-release-1.5.0/dojo/string.js
-./../../release/dojo-release-1.5.0/dojo/cache.js
-./../../release/dojo-release-1.5.0/dijit/_Templated.js
-./../../release/dojo-release-1.5.0/dijit/_Container.js
-./../../release/dojo-release-1.5.0/dijit/_Contained.js
-./../../release/dojo-release-1.5.0/dijit/layout/_LayoutWidget.js
-./../../release/dojo-release-1.5.0/dijit/_CssStateMixin.js
-./../../release/dojo-release-1.5.0/dijit/form/_FormWidget.js
-./../../release/dojo-release-1.5.0/dijit/dijit.js
-./../../release/dojo-release-1.5.0/dijit/_KeyNavContainer.js
-./../../release/dojo-release-1.5.0/dijit/MenuItem.js
-./../../release/dojo-release-1.5.0/dijit/PopupMenuItem.js
-./../../release/dojo-release-1.5.0/dijit/CheckedMenuItem.js
-./../../release/dojo-release-1.5.0/dijit/MenuSeparator.js
-./../../release/dojo-release-1.5.0/dijit/Menu.js
-./../../release/dojo-release-1.5.0/dojox/html/metrics.js
-./../../release/dojo-release-1.5.0/dojox/grid/util.js
-./../../release/dojo-release-1.5.0/dojox/grid/_Scroller.js
-./../../release/dojo-release-1.5.0/dojox/grid/cells/_base.js
-./../../release/dojo-release-1.5.0/dojox/grid/cells.js
-./../../release/dojo-release-1.5.0/dojo/dnd/common.js
-./../../release/dojo-release-1.5.0/dojo/dnd/autoscroll.js
-./../../release/dojo-release-1.5.0/dojo/dnd/Mover.js
-./../../release/dojo-release-1.5.0/dojo/dnd/Moveable.js
-./../../release/dojo-release-1.5.0/dojox/grid/_Builder.js
-./../../release/dojo-release-1.5.0/dojo/dnd/Container.js
-./../../release/dojo-release-1.5.0/dojo/dnd/Selector.js
-./../../release/dojo-release-1.5.0/dojo/dnd/Avatar.js
-./../../release/dojo-release-1.5.0/dojo/dnd/Manager.js
-./../../release/dojo-release-1.5.0/dojo/dnd/Source.js
-./../../release/dojo-release-1.5.0/dojox/grid/_View.js
-./../../release/dojo-release-1.5.0/dojox/grid/_RowSelector.js
-./../../release/dojo-release-1.5.0/dojox/grid/_Layout.js
-./../../release/dojo-release-1.5.0/dojox/grid/_ViewManager.js
-./../../release/dojo-release-1.5.0/dojox/grid/_RowManager.js
-./../../release/dojo-release-1.5.0/dojox/grid/_FocusManager.js
-./../../release/dojo-release-1.5.0/dojox/grid/_EditManager.js
-./../../release/dojo-release-1.5.0/dojox/grid/Selection.js
-./../../release/dojo-release-1.5.0/dojox/grid/_Events.js
-./../../release/dojo-release-1.5.0/dojo/i18n.js
-./../../release/dojo-release-1.5.0/dojox/grid/_Grid.js
-./../../release/dojo-release-1.5.0/dojox/grid/DataSelection.js
-./../../release/dojo-release-1.5.0/dojox/grid/DataGrid.js
-
-../dojox/gfx.js:
-./../../release/dojo-release-1.5.0/dojox/gfx/matrix.js
-./../../release/dojo-release-1.5.0/dojox/gfx/_base.js
-./../../release/dojo-release-1.5.0/dojox/gfx.js
-
-../dojox/charting/widget/Chart2D.js:
-./../../release/dojo-release-1.5.0/dojo/window.js
-./../../release/dojo-release-1.5.0/dijit/_base/manager.js
-./../../release/dojo-release-1.5.0/dijit/_base/focus.js
-./../../release/dojo-release-1.5.0/dojo/AdapterRegistry.js
-./../../release/dojo-release-1.5.0/dijit/_base/place.js
-./../../release/dojo-release-1.5.0/dijit/_base/window.js
-./../../release/dojo-release-1.5.0/dijit/_base/popup.js
-./../../release/dojo-release-1.5.0/dijit/_base/scroll.js
-./../../release/dojo-release-1.5.0/dojo/uacss.js
-./../../release/dojo-release-1.5.0/dijit/_base/sniff.js
-./../../release/dojo-release-1.5.0/dijit/_base/typematic.js
-./../../release/dojo-release-1.5.0/dijit/_base/wai.js
-./../../release/dojo-release-1.5.0/dijit/_base.js
-./../../release/dojo-release-1.5.0/dijit/_Widget.js
-./../../release/dojo-release-1.5.0/dojox/gfx/matrix.js
-./../../release/dojo-release-1.5.0/dojox/gfx/_base.js
-./../../release/dojo-release-1.5.0/dojox/gfx.js
-./../../release/dojo-release-1.5.0/dojox/lang/functional/lambda.js
-./../../release/dojo-release-1.5.0/dojox/lang/functional/array.js
-./../../release/dojo-release-1.5.0/dojox/lang/functional/object.js
-./../../release/dojo-release-1.5.0/dojox/lang/functional.js
-./../../release/dojo-release-1.5.0/dojox/lang/functional/fold.js
-./../../release/dojo-release-1.5.0/dojox/lang/functional/reversed.js
-./../../release/dojo-release-1.5.0/dojo/colors.js
-./../../release/dojo-release-1.5.0/dojox/color/_base.js
-./../../release/dojo-release-1.5.0/dojox/color.js
-./../../release/dojo-release-1.5.0/dojox/color/Palette.js
-./../../release/dojo-release-1.5.0/dojox/lang/utils.js
-./../../release/dojo-release-1.5.0/dojox/gfx/gradutils.js
-./../../release/dojo-release-1.5.0/dojox/charting/Theme.js
-./../../release/dojo-release-1.5.0/dojox/charting/Element.js
-./../../release/dojo-release-1.5.0/dojox/charting/Series.js
-./../../release/dojo-release-1.5.0/dojox/charting/scaler/common.js
-./../../release/dojo-release-1.5.0/dojox/charting/scaler/linear.js
-./../../release/dojo-release-1.5.0/dojox/charting/axis2d/common.js
-./../../release/dojo-release-1.5.0/dojox/charting/axis2d/Base.js
-./../../release/dojo-release-1.5.0/dojo/string.js
-./../../release/dojo-release-1.5.0/dojox/charting/axis2d/Invisible.js
-./../../release/dojo-release-1.5.0/dojox/charting/axis2d/Default.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/common.js
-./../../release/dojo-release-1.5.0/dojox/charting/scaler/primitive.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/_PlotEvents.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Base.js
-./../../release/dojo-release-1.5.0/dojox/gfx/fx.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Default.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Lines.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Areas.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Markers.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/MarkersOnly.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Scatter.js
-./../../release/dojo-release-1.5.0/dojox/lang/functional/sequence.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Stacked.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/StackedLines.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/StackedAreas.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Columns.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/StackedColumns.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/ClusteredColumns.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Bars.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/StackedBars.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/ClusteredBars.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Grid.js
-./../../release/dojo-release-1.5.0/dojo/i18n.js
-./../../release/dojo-release-1.5.0/dojo/regexp.js
-./../../release/dojo-release-1.5.0/dojo/number.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Pie.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Bubble.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/Candlesticks.js
-./../../release/dojo-release-1.5.0/dojox/charting/plot2d/OHLC.js
-./../../release/dojo-release-1.5.0/dojox/charting/Chart2D.js
-./../../release/dojo-release-1.5.0/dojo/fx/easing.js
-./../../release/dojo-release-1.5.0/dojox/charting/action2d/Base.js
-./../../release/dojo-release-1.5.0/dojox/charting/action2d/Highlight.js
-./../../release/dojo-release-1.5.0/dojo/fx/Toggler.js
-./../../release/dojo-release-1.5.0/dojo/fx.js
-./../../release/dojo-release-1.5.0/dojox/charting/action2d/Magnify.js
-./../../release/dojo-release-1.5.0/dojox/lang/functional/scan.js
-./../../release/dojo-release-1.5.0/dojox/charting/action2d/MoveSlice.js
-./../../release/dojo-release-1.5.0/dojox/charting/action2d/Shake.js
-./../../release/dojo-release-1.5.0/dojo/date/stamp.js
-./../../release/dojo-release-1.5.0/dojo/parser.js
-./../../release/dojo-release-1.5.0/dojo/cache.js
-./../../release/dojo-release-1.5.0/dijit/_Templated.js
-./../../release/dojo-release-1.5.0/dijit/Tooltip.js
-./../../release/dojo-release-1.5.0/dojox/charting/action2d/Tooltip.js
-./../../release/dojo-release-1.5.0/dojox/charting/widget/Chart2D.js
-./../../release/dojo-release-1.5.0/dojox/charting/themes/ET/greys.js
-./../../release/dojo-release-1.5.0/dojox/charting/widget/Sparkline.js
-./../../release/dojo-release-1.5.0/dojox/charting/widget/Legend.js
-
-../dojox/dtl.js:
-./../../release/dojo-release-1.5.0/dojox/string/Builder.js
-./../../release/dojo-release-1.5.0/dojox/string/tokenize.js
-./../../release/dojo-release-1.5.0/dojox/dtl/_base.js
-./../../release/dojo-release-1.5.0/dojox/dtl.js
-./../../release/dojo-release-1.5.0/dojox/dtl/Context.js
-./../../release/dojo-release-1.5.0/dojox/dtl/tag/logic.js
-./../../release/dojo-release-1.5.0/dojox/dtl/tag/loop.js
-./../../release/dojo-release-1.5.0/dojo/date.js
-./../../release/dojo-release-1.5.0/dojox/date/php.js
-./../../release/dojo-release-1.5.0/dojox/dtl/utils/date.js
-./../../release/dojo-release-1.5.0/dojox/dtl/tag/date.js
-./../../release/dojo-release-1.5.0/dojox/dtl/tag/loader.js
-./../../release/dojo-release-1.5.0/dojox/dtl/tag/misc.js
-./../../release/dojo-release-1.5.0/dojox/dtl/ext-dojo/NodeList.js
+tt-rss-layer.js:
+./../../release/dojo/date/stamp.js
+./../../release/dojo/parser.js
+./../../release/dojo/window.js
+./../../release/dijit/_base/manager.js
+./../../release/dijit/_base/focus.js
+./../../release/dojo/AdapterRegistry.js
+./../../release/dijit/_base/place.js
+./../../release/dijit/_base/window.js
+./../../release/dijit/_base/popup.js
+./../../release/dijit/_base/scroll.js
+./../../release/dojo/uacss.js
+./../../release/dijit/_base/sniff.js
+./../../release/dijit/_base/typematic.js
+./../../release/dijit/_base/wai.js
+./../../release/dijit/_base.js
+./../../release/dijit/_Widget.js
+./../../release/dojo/string.js
+./../../release/dojo/cache.js
+./../../release/dijit/_Templated.js
+./../../release/dijit/_Container.js
+./../../release/dijit/_Contained.js
+./../../release/dijit/layout/_LayoutWidget.js
+./../../release/dijit/_CssStateMixin.js
+./../../release/dijit/form/_FormWidget.js
+./../../release/dijit/dijit.js
+./../../release/dojo/fx/Toggler.js
+./../../release/dojo/fx.js
+./../../release/dojo/NodeList-fx.js
+./../../release/dojo/colors.js
+./../../release/dojo/i18n.js
+./../../release/dijit/_PaletteMixin.js
+./../../release/dijit/ColorPalette.js
+./../../release/dojo/dnd/common.js
+./../../release/dojo/dnd/autoscroll.js
+./../../release/dojo/dnd/Mover.js
+./../../release/dojo/dnd/Moveable.js
+./../../release/dojo/dnd/move.js
+./../../release/dojo/dnd/TimedMoveable.js
+./../../release/dijit/form/_FormMixin.js
+./../../release/dijit/_DialogMixin.js
+./../../release/dijit/DialogUnderlay.js
+./../../release/dojo/html.js
+./../../release/dijit/layout/ContentPane.js
+./../../release/dijit/TooltipDialog.js
+./../../release/dijit/Dialog.js
+./../../release/dijit/_HasDropDown.js
+./../../release/dijit/form/Button.js
+./../../release/dijit/form/ToggleButton.js
+./../../release/dijit/form/CheckBox.js
+./../../release/dijit/form/DropDownButton.js
+./../../release/dojo/regexp.js
+./../../release/dojo/data/util/sorter.js
+./../../release/dojo/data/util/simpleFetch.js
+./../../release/dojo/data/util/filter.js
+./../../release/dijit/form/TextBox.js
+./../../release/dijit/Tooltip.js
+./../../release/dijit/form/ValidationTextBox.js
+./../../release/dijit/form/ComboBox.js
+./../../release/dijit/form/FilteringSelect.js
+./../../release/dijit/form/Form.js
+./../../release/dijit/form/RadioButton.js
+./../../release/dijit/form/_FormSelectWidget.js
+./../../release/dijit/_KeyNavContainer.js
+./../../release/dijit/MenuItem.js
+./../../release/dijit/PopupMenuItem.js
+./../../release/dijit/CheckedMenuItem.js
+./../../release/dijit/MenuSeparator.js
+./../../release/dijit/Menu.js
+./../../release/dijit/form/Select.js
+./../../release/dijit/form/SimpleTextarea.js
+./../../release/dijit/InlineEditBox.js
+./../../release/dojo/cookie.js
+./../../release/dijit/layout/StackController.js
+./../../release/dijit/layout/StackContainer.js
+./../../release/dijit/layout/AccordionPane.js
+./../../release/dijit/layout/AccordionContainer.js
+./../../release/dijit/layout/BorderContainer.js
+./../../release/dijit/layout/_TabContainerBase.js
+./../../release/dijit/layout/TabController.js
+./../../release/dijit/layout/ScrollingTabController.js
+./../../release/dijit/layout/TabContainer.js
+./../../release/dojo/number.js
+./../../release/dijit/ProgressBar.js
+./../../release/dijit/ToolbarSeparator.js
+./../../release/dijit/Toolbar.js
+./../../release/dojo/DeferredList.js
+./../../release/dijit/tree/TreeStoreModel.js
+./../../release/dijit/tree/ForestStoreModel.js
+./../../release/dijit/Tree.js
+./../../release/dojo/dnd/Container.js
+./../../release/dijit/tree/_dndContainer.js
+./../../release/dijit/tree/_dndSelector.js
+./../../release/dojo/dnd/Avatar.js
+./../../release/dojo/dnd/Manager.js
+./../../release/dijit/tree/dndSource.js
+./../../release/dojo/data/ItemFileReadStore.js
+./../../release/dojo/data/ItemFileWriteStore.js
diff --git a/lib/dojo/cache.js b/lib/dojo/cache.js
index 4c2d233da..da237c767 100644
--- a/lib/dojo/cache.js
+++ b/lib/dojo/cache.js
@@ -5,50 +5,123 @@
*/
-if(!dojo._hasResource["dojo.cache"]){
-dojo._hasResource["dojo.cache"]=true;
+if(!dojo._hasResource["dojo.cache"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.cache"] = true;
dojo.provide("dojo.cache");
-(function(){
-var _1={};
-dojo.cache=function(_2,_3,_4){
-if(typeof _2=="string"){
-var _5=dojo.moduleUrl(_2,_3);
-}else{
-_5=_2;
-_4=_3;
-}
-var _6=_5.toString();
-var _7=_4;
-if(_4!=undefined&&!dojo.isString(_4)){
-_7=("value" in _4?_4.value:undefined);
-}
-var _8=_4&&_4.sanitize?true:false;
-if(typeof _7=="string"){
-_7=_1[_6]=_8?dojo.cache._sanitize(_7):_7;
-}else{
-if(_7===null){
-delete _1[_6];
-}else{
-if(!(_6 in _1)){
-_7=dojo._getText(_6);
-_1[_6]=_8?dojo.cache._sanitize(_7):_7;
-}
-_7=_1[_6];
-}
-}
-return _7;
-};
-dojo.cache._sanitize=function(_9){
-if(_9){
-_9=_9.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,"");
-var _a=_9.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
-if(_a){
-_9=_a[1];
-}
-}else{
-_9="";
-}
-return _9;
+
+/*=====
+dojo.cache = {
+ // summary:
+ // A way to cache string content that is fetchable via `dojo.moduleUrl`.
};
+=====*/
+
+(function(){
+ var cache = {};
+ dojo.cache = function(/*String||Object*/module, /*String*/url, /*String||Object?*/value){
+ // summary:
+ // A getter and setter for storing the string content associated with the
+ // module and url arguments.
+ // description:
+ // module and url are used to call `dojo.moduleUrl()` to generate a module URL.
+ // If value is specified, the cache value for the moduleUrl will be set to
+ // that value. Otherwise, dojo.cache will fetch the moduleUrl and store it
+ // in its internal cache and return that cached value for the URL. To clear
+ // a cache value pass null for value. Since XMLHttpRequest (XHR) is used to fetch the
+ // the URL contents, only modules on the same domain of the page can use this capability.
+ // The build system can inline the cache values though, to allow for xdomain hosting.
+ // module: String||Object
+ // If a String, the module name to use for the base part of the URL, similar to module argument
+ // to `dojo.moduleUrl`. If an Object, something that has a .toString() method that
+ // generates a valid path for the cache item. For example, a dojo._Url object.
+ // url: String
+ // The rest of the path to append to the path derived from the module argument. If
+ // module is an object, then this second argument should be the "value" argument instead.
+ // value: String||Object?
+ // If a String, the value to use in the cache for the module/url combination.
+ // If an Object, it can have two properties: value and sanitize. The value property
+ // should be the value to use in the cache, and sanitize can be set to true or false,
+ // to indicate if XML declarations should be removed from the value and if the HTML
+ // inside a body tag in the value should be extracted as the real value. The value argument
+ // or the value property on the value argument are usually only used by the build system
+ // as it inlines cache content.
+ // example:
+ // To ask dojo.cache to fetch content and store it in the cache (the dojo["cache"] style
+ // of call is used to avoid an issue with the build system erroneously trying to intern
+ // this example. To get the build system to intern your dojo.cache calls, use the
+ // "dojo.cache" style of call):
+ // | //If template.html contains "<h1>Hello</h1>" that will be
+ // | //the value for the text variable.
+ // | var text = dojo["cache"]("my.module", "template.html");
+ // example:
+ // To ask dojo.cache to fetch content and store it in the cache, and sanitize the input
+ // (the dojo["cache"] style of call is used to avoid an issue with the build system
+ // erroneously trying to intern this example. To get the build system to intern your
+ // dojo.cache calls, use the "dojo.cache" style of call):
+ // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
+ // | //text variable will contain just "<h1>Hello</h1>".
+ // | var text = dojo["cache"]("my.module", "template.html", {sanitize: true});
+ // example:
+ // Same example as previous, but demostrates how an object can be passed in as
+ // the first argument, then the value argument can then be the second argument.
+ // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
+ // | //text variable will contain just "<h1>Hello</h1>".
+ // | var text = dojo["cache"](new dojo._Url("my/module/template.html"), {sanitize: true});
+
+ //Module could be a string, or an object that has a toString() method
+ //that will return a useful path. If it is an object, then the "url" argument
+ //will actually be the value argument.
+ if(typeof module == "string"){
+ var pathObj = dojo.moduleUrl(module, url);
+ }else{
+ pathObj = module;
+ value = url;
+ }
+ var key = pathObj.toString();
+
+ var val = value;
+ if(value != undefined && !dojo.isString(value)){
+ val = ("value" in value ? value.value : undefined);
+ }
+
+ var sanitize = value && value.sanitize ? true : false;
+
+ if(typeof val == "string"){
+ //We have a string, set cache value
+ val = cache[key] = sanitize ? dojo.cache._sanitize(val) : val;
+ }else if(val === null){
+ //Remove cached value
+ delete cache[key];
+ }else{
+ //Allow cache values to be empty strings. If key property does
+ //not exist, fetch it.
+ if(!(key in cache)){
+ val = dojo._getText(key);
+ cache[key] = sanitize ? dojo.cache._sanitize(val) : val;
+ }
+ val = cache[key];
+ }
+ return val; //String
+ };
+
+ dojo.cache._sanitize = function(/*String*/val){
+ // summary:
+ // Strips <?xml ...?> declarations so that external SVG and XML
+ // documents can be added to a document without worry. Also, if the string
+ // is an HTML document, only the part inside the body tag is returned.
+ // description:
+ // Copied from dijit._Templated._sanitizeTemplateString.
+ if(val){
+ val = val.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
+ var matches = val.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+ if(matches){
+ val = matches[1];
+ }
+ }else{
+ val = "";
+ }
+ return val; //String
+ };
})();
+
}
diff --git a/lib/dojo/cldr/monetary.js b/lib/dojo/cldr/monetary.js
index b5b4c0a22..0380055c4 100644
--- a/lib/dojo/cldr/monetary.js
+++ b/lib/dojo/cldr/monetary.js
@@ -5,19 +5,33 @@
*/
-if(!dojo._hasResource["dojo.cldr.monetary"]){
-dojo._hasResource["dojo.cldr.monetary"]=true;
+if(!dojo._hasResource["dojo.cldr.monetary"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.cldr.monetary"] = true;
dojo.provide("dojo.cldr.monetary");
-dojo.cldr.monetary.getData=function(_1){
-var _2={ADP:0,AFN:0,ALL:0,AMD:0,BHD:3,BIF:0,BYR:0,CLF:0,CLP:0,COP:0,CRC:0,DJF:0,ESP:0,GNF:0,GYD:0,HUF:0,IDR:0,IQD:0,IRR:3,ISK:0,ITL:0,JOD:3,JPY:0,KMF:0,KPW:0,KRW:0,KWD:3,LAK:0,LBP:0,LUF:0,LYD:3,MGA:0,MGF:0,MMK:0,MNT:0,MRO:0,MUR:0,OMR:3,PKR:0,PYG:0,RSD:0,RWF:0,SLL:0,SOS:0,STD:0,SYP:0,TMM:0,TND:3,TRL:0,TZS:0,UGX:0,UZS:0,VND:0,VUV:0,XAF:0,XOF:0,XPF:0,YER:0,ZMK:0,ZWD:0};
-var _3={CHF:5};
-var _4=_2[_1],_5=_3[_1];
-if(typeof _4=="undefined"){
-_4=2;
-}
-if(typeof _5=="undefined"){
-_5=0;
-}
-return {places:_4,round:_5};
+
+dojo.cldr.monetary.getData = function(/*String*/code){
+// summary: A mapping of currency code to currency-specific formatting information. Returns a unique object with properties: places, round.
+// code: an [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code
+
+// from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/currencyData/fractions
+
+ var placesData = {
+ ADP:0,AFN:0,ALL:0,AMD:0,BHD:3,BIF:0,BYR:0,CLF:0,CLP:0,
+ COP:0,CRC:0,DJF:0,ESP:0,GNF:0,GYD:0,HUF:0,IDR:0,IQD:0,
+ IRR:3,ISK:0,ITL:0,JOD:3,JPY:0,KMF:0,KPW:0,KRW:0,KWD:3,
+ LAK:0,LBP:0,LUF:0,LYD:3,MGA:0,MGF:0,MMK:0,MNT:0,MRO:0,
+ MUR:0,OMR:3,PKR:0,PYG:0,RSD:0,RWF:0,SLL:0,SOS:0,STD:0,
+ SYP:0,TMM:0,TND:3,TRL:0,TZS:0,UGX:0,UZS:0,VND:0,VUV:0,
+ XAF:0,XOF:0,XPF:0,YER:0,ZMK:0,ZWD:0
+ };
+
+ var roundingData = {CHF:5};
+
+ var places = placesData[code], round = roundingData[code];
+ if(typeof places == "undefined"){ places = 2; }
+ if(typeof round == "undefined"){ round = 0; }
+
+ return {places: places, round: round}; // Object
};
+
}
diff --git a/lib/dojo/cldr/supplemental.js b/lib/dojo/cldr/supplemental.js
index 011af7e63..f887e3a99 100644
--- a/lib/dojo/cldr/supplemental.js
+++ b/lib/dojo/cldr/supplemental.js
@@ -5,41 +5,77 @@
*/
-if(!dojo._hasResource["dojo.cldr.supplemental"]){
-dojo._hasResource["dojo.cldr.supplemental"]=true;
+if(!dojo._hasResource["dojo.cldr.supplemental"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.cldr.supplemental"] = true;
dojo.provide("dojo.cldr.supplemental");
+
dojo.require("dojo.i18n");
-dojo.cldr.supplemental.getFirstDayOfWeek=function(_1){
-var _2={mv:5,af:6,bh:6,dj:6,dz:6,eg:6,er:6,et:6,iq:6,ir:6,jo:6,ke:6,kw:6,ly:6,ma:6,om:6,qa:6,sa:6,sd:6,so:6,tn:6,ye:6,ar:0,as:0,az:0,bw:0,ca:0,cn:0,fo:0,ge:0,gl:0,gu:0,hk:0,ie:0,il:0,"in":0,is:0,jm:0,jp:0,kg:0,kr:0,la:0,mh:0,mn:0,mo:0,mp:0,mt:0,nz:0,ph:0,pk:0,sg:0,sy:0,th:0,tt:0,tw:0,um:0,us:0,uz:0,vi:0,zw:0};
-var _3=dojo.cldr.supplemental._region(_1);
-var _4=_2[_3];
-return (_4===undefined)?1:_4;
-};
-dojo.cldr.supplemental._region=function(_5){
-_5=dojo.i18n.normalizeLocale(_5);
-var _6=_5.split("-");
-var _7=_6[1];
-if(!_7){
-_7={de:"de",en:"us",es:"es",fi:"fi",fr:"fr",he:"il",hu:"hu",it:"it",ja:"jp",ko:"kr",nl:"nl",pt:"br",sv:"se",zh:"cn"}[_6[0]];
-}else{
-if(_7.length==4){
-_7=_6[2];
-}
-}
-return _7;
+
+dojo.cldr.supplemental.getFirstDayOfWeek = function(/*String?*/locale){
+// summary: Returns a zero-based index for first day of the week
+// description:
+// Returns a zero-based index for first day of the week, as used by the local (Gregorian) calendar.
+// e.g. Sunday (returns 0), or Monday (returns 1)
+
+ // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/firstDay
+ var firstDay = {/*default is 1=Monday*/
+ mv:5,
+ af:6,bh:6,dj:6,dz:6,eg:6,er:6,et:6,iq:6,ir:6,jo:6,ke:6,kw:6,
+ ly:6,ma:6,om:6,qa:6,sa:6,sd:6,so:6,tn:6,ye:6,
+ ar:0,as:0,az:0,bw:0,ca:0,cn:0,fo:0,ge:0,gl:0,gu:0,hk:0,ie:0,
+ il:0,'in':0,is:0,jm:0,jp:0,kg:0,kr:0,la:0,mh:0,mn:0,mo:0,mp:0,
+ mt:0,nz:0,ph:0,pk:0,sg:0,sy:0,th:0,tt:0,tw:0,um:0,us:0,uz:0,
+ vi:0,zw:0
+// variant. do not use? gb:0,
+ };
+
+ var country = dojo.cldr.supplemental._region(locale);
+ var dow = firstDay[country];
+ return (dow === undefined) ? 1 : dow; /*Number*/
};
-dojo.cldr.supplemental.getWeekend=function(_8){
-var _9={"in":0,af:4,dz:4,ir:4,om:4,sa:4,ye:4,ae:5,bh:5,eg:5,il:5,iq:5,jo:5,kw:5,ly:5,ma:5,qa:5,sd:5,sy:5,tn:5};
-var _a={af:5,dz:5,ir:5,om:5,sa:5,ye:5,ae:6,bh:5,eg:6,il:6,iq:6,jo:6,kw:6,ly:6,ma:6,qa:6,sd:6,sy:6,tn:6};
-var _b=dojo.cldr.supplemental._region(_8);
-var _c=_9[_b];
-var _d=_a[_b];
-if(_c===undefined){
-_c=6;
-}
-if(_d===undefined){
-_d=0;
+
+dojo.cldr.supplemental._region = function(/*String?*/locale){
+ locale = dojo.i18n.normalizeLocale(locale);
+ var tags = locale.split('-');
+ var region = tags[1];
+ if(!region){
+ // IE often gives language only (#2269)
+ // Arbitrary mappings of language-only locales to a country:
+ region = {de:"de", en:"us", es:"es", fi:"fi", fr:"fr", he:"il", hu:"hu", it:"it",
+ ja:"jp", ko:"kr", nl:"nl", pt:"br", sv:"se", zh:"cn"}[tags[0]];
+ }else if(region.length == 4){
+ // The ISO 3166 country code is usually in the second position, unless a
+ // 4-letter script is given. See http://www.ietf.org/rfc/rfc4646.txt
+ region = tags[2];
+ }
+ return region;
}
-return {start:_c,end:_d};
+
+dojo.cldr.supplemental.getWeekend = function(/*String?*/locale){
+// summary: Returns a hash containing the start and end days of the weekend
+// description:
+// Returns a hash containing the start and end days of the weekend according to local custom using locale,
+// or by default in the user's locale.
+// e.g. {start:6, end:0}
+
+ // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/weekend{Start,End}
+ var weekendStart = {/*default is 6=Saturday*/
+ 'in':0,
+ af:4,dz:4,ir:4,om:4,sa:4,ye:4,
+ ae:5,bh:5,eg:5,il:5,iq:5,jo:5,kw:5,ly:5,ma:5,qa:5,sd:5,sy:5,tn:5
+ };
+
+ var weekendEnd = {/*default is 0=Sunday*/
+ af:5,dz:5,ir:5,om:5,sa:5,ye:5,
+ ae:6,bh:5,eg:6,il:6,iq:6,jo:6,kw:6,ly:6,ma:6,qa:6,sd:6,sy:6,tn:6
+ };
+
+ var country = dojo.cldr.supplemental._region(locale);
+ var start = weekendStart[country];
+ var end = weekendEnd[country];
+ if(start === undefined){start=6;}
+ if(end === undefined){end=0;}
+ return {start:start, end:end}; /*Object {start,end}*/
};
+
}
diff --git a/lib/dojo/colors.js b/lib/dojo/colors.js
index a5b0da7fd..1f41dc3c7 100644
--- a/lib/dojo/colors.js
+++ b/lib/dojo/colors.js
@@ -5,72 +5,232 @@
*/
-if(!dojo._hasResource["dojo.colors"]){
-dojo._hasResource["dojo.colors"]=true;
+if(!dojo._hasResource["dojo.colors"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.colors"] = true;
dojo.provide("dojo.colors");
-(function(){
-var _1=function(m1,m2,h){
-if(h<0){
-++h;
-}
-if(h>1){
---h;
-}
-var h6=6*h;
-if(h6<1){
-return m1+(m2-m1)*h6;
-}
-if(2*h<1){
-return m2;
-}
-if(3*h<2){
-return m1+(m2-m1)*(2/3-h)*6;
-}
-return m1;
-};
-dojo.colorFromRgb=function(_2,_3){
-var m=_2.toLowerCase().match(/^(rgba?|hsla?)\(([\s\.\-,%0-9]+)\)/);
-if(m){
-var c=m[2].split(/\s*,\s*/),l=c.length,t=m[1],a;
-if((t=="rgb"&&l==3)||(t=="rgba"&&l==4)){
-var r=c[0];
-if(r.charAt(r.length-1)=="%"){
-a=dojo.map(c,function(x){
-return parseFloat(x)*2.56;
-});
-if(l==4){
-a[3]=c[3];
-}
-return dojo.colorFromArray(a,_3);
-}
-return dojo.colorFromArray(c,_3);
-}
-if((t=="hsl"&&l==3)||(t=="hsla"&&l==4)){
-var H=((parseFloat(c[0])%360)+360)%360/360,S=parseFloat(c[1])/100,L=parseFloat(c[2])/100,m2=L<=0.5?L*(S+1):L+S-L*S,m1=2*L-m2;
-a=[_1(m1,m2,H+1/3)*256,_1(m1,m2,H)*256,_1(m1,m2,H-1/3)*256,1];
-if(l==4){
-a[3]=c[3];
-}
-return dojo.colorFromArray(a,_3);
-}
+
+//TODO: this module appears to break naming conventions
+
+/*=====
+dojo.colors = {
+ // summary: Color utilities
}
-return null;
-};
-var _4=function(c,_5,_6){
-c=Number(c);
-return isNaN(c)?_6:c<_5?_5:c>_6?_6:c;
-};
-dojo.Color.prototype.sanitize=function(){
-var t=this;
-t.r=Math.round(_4(t.r,0,255));
-t.g=Math.round(_4(t.g,0,255));
-t.b=Math.round(_4(t.b,0,255));
-t.a=_4(t.a,0,1);
-return this;
-};
+=====*/
+
+(function(){
+ // this is a standard conversion prescribed by the CSS3 Color Module
+ var hue2rgb = function(m1, m2, h){
+ if(h < 0){ ++h; }
+ if(h > 1){ --h; }
+ var h6 = 6 * h;
+ if(h6 < 1){ return m1 + (m2 - m1) * h6; }
+ if(2 * h < 1){ return m2; }
+ if(3 * h < 2){ return m1 + (m2 - m1) * (2 / 3 - h) * 6; }
+ return m1;
+ };
+
+ dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
+ // summary:
+ // get rgb(a) array from css-style color declarations
+ // description:
+ // this function can handle all 4 CSS3 Color Module formats: rgb,
+ // rgba, hsl, hsla, including rgb(a) with percentage values.
+ var m = color.toLowerCase().match(/^(rgba?|hsla?)\(([\s\.\-,%0-9]+)\)/);
+ if(m){
+ var c = m[2].split(/\s*,\s*/), l = c.length, t = m[1], a;
+ if((t == "rgb" && l == 3) || (t == "rgba" && l == 4)){
+ var r = c[0];
+ if(r.charAt(r.length - 1) == "%"){
+ // 3 rgb percentage values
+ a = dojo.map(c, function(x){
+ return parseFloat(x) * 2.56;
+ });
+ if(l == 4){ a[3] = c[3]; }
+ return dojo.colorFromArray(a, obj); // dojo.Color
+ }
+ return dojo.colorFromArray(c, obj); // dojo.Color
+ }
+ if((t == "hsl" && l == 3) || (t == "hsla" && l == 4)){
+ // normalize hsl values
+ var H = ((parseFloat(c[0]) % 360) + 360) % 360 / 360,
+ S = parseFloat(c[1]) / 100,
+ L = parseFloat(c[2]) / 100,
+ // calculate rgb according to the algorithm
+ // recommended by the CSS3 Color Module
+ m2 = L <= 0.5 ? L * (S + 1) : L + S - L * S,
+ m1 = 2 * L - m2;
+ a = [
+ hue2rgb(m1, m2, H + 1 / 3) * 256,
+ hue2rgb(m1, m2, H) * 256,
+ hue2rgb(m1, m2, H - 1 / 3) * 256,
+ 1
+ ];
+ if(l == 4){ a[3] = c[3]; }
+ return dojo.colorFromArray(a, obj); // dojo.Color
+ }
+ }
+ return null; // dojo.Color
+ };
+
+ var confine = function(c, low, high){
+ // summary:
+ // sanitize a color component by making sure it is a number,
+ // and clamping it to valid values
+ c = Number(c);
+ return isNaN(c) ? high : c < low ? low : c > high ? high : c; // Number
+ };
+
+ dojo.Color.prototype.sanitize = function(){
+ // summary: makes sure that the object has correct attributes
+ var t = this;
+ t.r = Math.round(confine(t.r, 0, 255));
+ t.g = Math.round(confine(t.g, 0, 255));
+ t.b = Math.round(confine(t.b, 0, 255));
+ t.a = confine(t.a, 0, 1);
+ return this; // dojo.Color
+ };
})();
-dojo.colors.makeGrey=function(g,a){
-return dojo.colorFromArray([g,g,g,a]);
+
+
+dojo.colors.makeGrey = function(/*Number*/ g, /*Number?*/ a){
+ // summary: creates a greyscale color with an optional alpha
+ return dojo.colorFromArray([g, g, g, a]);
};
-dojo.mixin(dojo.Color.named,{aliceblue:[240,248,255],antiquewhite:[250,235,215],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],blanchedalmond:[255,235,205],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],oldlace:[253,245,230],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],thistle:[216,191,216],tomato:[255,99,71],transparent:[0,0,0,0],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],whitesmoke:[245,245,245],yellowgreen:[154,205,50]});
+
+// mixin all CSS3 named colors not already in _base, along with SVG 1.0 variant spellings
+dojo.mixin(dojo.Color.named, {
+ aliceblue: [240,248,255],
+ antiquewhite: [250,235,215],
+ aquamarine: [127,255,212],
+ azure: [240,255,255],
+ beige: [245,245,220],
+ bisque: [255,228,196],
+ blanchedalmond: [255,235,205],
+ blueviolet: [138,43,226],
+ brown: [165,42,42],
+ burlywood: [222,184,135],
+ cadetblue: [95,158,160],
+ chartreuse: [127,255,0],
+ chocolate: [210,105,30],
+ coral: [255,127,80],
+ cornflowerblue: [100,149,237],
+ cornsilk: [255,248,220],
+ crimson: [220,20,60],
+ cyan: [0,255,255],
+ darkblue: [0,0,139],
+ darkcyan: [0,139,139],
+ darkgoldenrod: [184,134,11],
+ darkgray: [169,169,169],
+ darkgreen: [0,100,0],
+ darkgrey: [169,169,169],
+ darkkhaki: [189,183,107],
+ darkmagenta: [139,0,139],
+ darkolivegreen: [85,107,47],
+ darkorange: [255,140,0],
+ darkorchid: [153,50,204],
+ darkred: [139,0,0],
+ darksalmon: [233,150,122],
+ darkseagreen: [143,188,143],
+ darkslateblue: [72,61,139],
+ darkslategray: [47,79,79],
+ darkslategrey: [47,79,79],
+ darkturquoise: [0,206,209],
+ darkviolet: [148,0,211],
+ deeppink: [255,20,147],
+ deepskyblue: [0,191,255],
+ dimgray: [105,105,105],
+ dimgrey: [105,105,105],
+ dodgerblue: [30,144,255],
+ firebrick: [178,34,34],
+ floralwhite: [255,250,240],
+ forestgreen: [34,139,34],
+ gainsboro: [220,220,220],
+ ghostwhite: [248,248,255],
+ gold: [255,215,0],
+ goldenrod: [218,165,32],
+ greenyellow: [173,255,47],
+ grey: [128,128,128],
+ honeydew: [240,255,240],
+ hotpink: [255,105,180],
+ indianred: [205,92,92],
+ indigo: [75,0,130],
+ ivory: [255,255,240],
+ khaki: [240,230,140],
+ lavender: [230,230,250],
+ lavenderblush: [255,240,245],
+ lawngreen: [124,252,0],
+ lemonchiffon: [255,250,205],
+ lightblue: [173,216,230],
+ lightcoral: [240,128,128],
+ lightcyan: [224,255,255],
+ lightgoldenrodyellow: [250,250,210],
+ lightgray: [211,211,211],
+ lightgreen: [144,238,144],
+ lightgrey: [211,211,211],
+ lightpink: [255,182,193],
+ lightsalmon: [255,160,122],
+ lightseagreen: [32,178,170],
+ lightskyblue: [135,206,250],
+ lightslategray: [119,136,153],
+ lightslategrey: [119,136,153],
+ lightsteelblue: [176,196,222],
+ lightyellow: [255,255,224],
+ limegreen: [50,205,50],
+ linen: [250,240,230],
+ magenta: [255,0,255],
+ mediumaquamarine: [102,205,170],
+ mediumblue: [0,0,205],
+ mediumorchid: [186,85,211],
+ mediumpurple: [147,112,219],
+ mediumseagreen: [60,179,113],
+ mediumslateblue: [123,104,238],
+ mediumspringgreen: [0,250,154],
+ mediumturquoise: [72,209,204],
+ mediumvioletred: [199,21,133],
+ midnightblue: [25,25,112],
+ mintcream: [245,255,250],
+ mistyrose: [255,228,225],
+ moccasin: [255,228,181],
+ navajowhite: [255,222,173],
+ oldlace: [253,245,230],
+ olivedrab: [107,142,35],
+ orange: [255,165,0],
+ orangered: [255,69,0],
+ orchid: [218,112,214],
+ palegoldenrod: [238,232,170],
+ palegreen: [152,251,152],
+ paleturquoise: [175,238,238],
+ palevioletred: [219,112,147],
+ papayawhip: [255,239,213],
+ peachpuff: [255,218,185],
+ peru: [205,133,63],
+ pink: [255,192,203],
+ plum: [221,160,221],
+ powderblue: [176,224,230],
+ rosybrown: [188,143,143],
+ royalblue: [65,105,225],
+ saddlebrown: [139,69,19],
+ salmon: [250,128,114],
+ sandybrown: [244,164,96],
+ seagreen: [46,139,87],
+ seashell: [255,245,238],
+ sienna: [160,82,45],
+ skyblue: [135,206,235],
+ slateblue: [106,90,205],
+ slategray: [112,128,144],
+ slategrey: [112,128,144],
+ snow: [255,250,250],
+ springgreen: [0,255,127],
+ steelblue: [70,130,180],
+ tan: [210,180,140],
+ thistle: [216,191,216],
+ tomato: [255,99,71],
+ transparent: [0, 0, 0, 0],
+ turquoise: [64,224,208],
+ violet: [238,130,238],
+ wheat: [245,222,179],
+ whitesmoke: [245,245,245],
+ yellowgreen: [154,205,50]
+});
+
}
diff --git a/lib/dojo/cookie.js b/lib/dojo/cookie.js
index 0d3b6eac0..67d2cdc6a 100644
--- a/lib/dojo/cookie.js
+++ b/lib/dojo/cookie.js
@@ -5,46 +5,98 @@
*/
-if(!dojo._hasResource["dojo.cookie"]){
-dojo._hasResource["dojo.cookie"]=true;
+if(!dojo._hasResource["dojo.cookie"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.cookie"] = true;
dojo.provide("dojo.cookie");
+
dojo.require("dojo.regexp");
-dojo.cookie=function(_1,_2,_3){
-var c=document.cookie;
-if(arguments.length==1){
-var _4=c.match(new RegExp("(?:^|; )"+dojo.regexp.escapeString(_1)+"=([^;]*)"));
-return _4?decodeURIComponent(_4[1]):undefined;
-}else{
-_3=_3||{};
-var _5=_3.expires;
-if(typeof _5=="number"){
-var d=new Date();
-d.setTime(d.getTime()+_5*24*60*60*1000);
-_5=_3.expires=d;
-}
-if(_5&&_5.toUTCString){
-_3.expires=_5.toUTCString();
-}
-_2=encodeURIComponent(_2);
-var _6=_1+"="+_2,_7;
-for(_7 in _3){
-_6+="; "+_7;
-var _8=_3[_7];
-if(_8!==true){
-_6+="="+_8;
-}
-}
-document.cookie=_6;
+
+/*=====
+dojo.__cookieProps = function(){
+ // expires: Date|String|Number?
+ // If a number, the number of days from today at which the cookie
+ // will expire. If a date, the date past which the cookie will expire.
+ // If expires is in the past, the cookie will be deleted.
+ // If expires is omitted or is 0, the cookie will expire when the browser closes. << FIXME: 0 seems to disappear right away? FF3.
+ // path: String?
+ // The path to use for the cookie.
+ // domain: String?
+ // The domain to use for the cookie.
+ // secure: Boolean?
+ // Whether to only send the cookie on secure connections
+ this.expires = expires;
+ this.path = path;
+ this.domain = domain;
+ this.secure = secure;
}
+=====*/
+
+
+dojo.cookie = function(/*String*/name, /*String?*/value, /*dojo.__cookieProps?*/props){
+ // summary:
+ // Get or set a cookie.
+ // description:
+ // If one argument is passed, returns the value of the cookie
+ // For two or more arguments, acts as a setter.
+ // name:
+ // Name of the cookie
+ // value:
+ // Value for the cookie
+ // props:
+ // Properties for the cookie
+ // example:
+ // set a cookie with the JSON-serialized contents of an object which
+ // will expire 5 days from now:
+ // | dojo.cookie("configObj", dojo.toJson(config), { expires: 5 });
+ //
+ // example:
+ // de-serialize a cookie back into a JavaScript object:
+ // | var config = dojo.fromJson(dojo.cookie("configObj"));
+ //
+ // example:
+ // delete a cookie:
+ // | dojo.cookie("configObj", null, {expires: -1});
+ var c = document.cookie;
+ if(arguments.length == 1){
+ var matches = c.match(new RegExp("(?:^|; )" + dojo.regexp.escapeString(name) + "=([^;]*)"));
+ return matches ? decodeURIComponent(matches[1]) : undefined; // String or undefined
+ }else{
+ props = props || {};
+// FIXME: expires=0 seems to disappear right away, not on close? (FF3) Change docs?
+ var exp = props.expires;
+ if(typeof exp == "number"){
+ var d = new Date();
+ d.setTime(d.getTime() + exp*24*60*60*1000);
+ exp = props.expires = d;
+ }
+ if(exp && exp.toUTCString){ props.expires = exp.toUTCString(); }
+
+ value = encodeURIComponent(value);
+ var updatedCookie = name + "=" + value, propName;
+ for(propName in props){
+ updatedCookie += "; " + propName;
+ var propValue = props[propName];
+ if(propValue !== true){ updatedCookie += "=" + propValue; }
+ }
+ document.cookie = updatedCookie;
+ }
};
-dojo.cookie.isSupported=function(){
-if(!("cookieEnabled" in navigator)){
-this("__djCookieTest__","CookiesAllowed");
-navigator.cookieEnabled=this("__djCookieTest__")=="CookiesAllowed";
-if(navigator.cookieEnabled){
-this("__djCookieTest__","",{expires:-1});
-}
-}
-return navigator.cookieEnabled;
+
+dojo.cookie.isSupported = function(){
+ // summary:
+ // Use to determine if the current browser supports cookies or not.
+ //
+ // Returns true if user allows cookies.
+ // Returns false if user doesn't allow cookies.
+
+ if(!("cookieEnabled" in navigator)){
+ this("__djCookieTest__", "CookiesAllowed");
+ navigator.cookieEnabled = this("__djCookieTest__") == "CookiesAllowed";
+ if(navigator.cookieEnabled){
+ this("__djCookieTest__", "", {expires: -1});
+ }
+ }
+ return navigator.cookieEnabled;
};
+
}
diff --git a/lib/dojo/currency.js b/lib/dojo/currency.js
index 10712660f..53833344d 100644
--- a/lib/dojo/currency.js
+++ b/lib/dojo/currency.js
@@ -5,32 +5,135 @@
*/
-if(!dojo._hasResource["dojo.currency"]){
-dojo._hasResource["dojo.currency"]=true;
+if(!dojo._hasResource["dojo.currency"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.currency"] = true;
dojo.provide("dojo.currency");
+
dojo.require("dojo.number");
dojo.require("dojo.i18n");
-dojo.requireLocalization("dojo.cldr","currency",null,"ROOT,ar,ca,cs,da,de,el,en,en-au,en-ca,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,ru,sk,sl,sv,th,tr,zh,zh-tw");
+dojo.requireLocalization("dojo.cldr", "currency", null, "ROOT,ar,ca,cs,da,de,el,en,en-au,en-ca,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,ru,sk,sl,sv,th,tr,zh,zh-tw");
dojo.require("dojo.cldr.monetary");
-dojo.currency._mixInDefaults=function(_1){
-_1=_1||{};
-_1.type="currency";
-var _2=dojo.i18n.getLocalization("dojo.cldr","currency",_1.locale)||{};
-var _3=_1.currency;
-var _4=dojo.cldr.monetary.getData(_3);
-dojo.forEach(["displayName","symbol","group","decimal"],function(_5){
-_4[_5]=_2[_3+"_"+_5];
+
+/*=====
+dojo.currency = {
+ // summary: localized formatting and parsing routines for currencies
+ //
+ // description: extends dojo.number to provide culturally-appropriate formatting of values
+ // in various world currencies, including use of a currency symbol. The currencies are specified
+ // by a three-letter international symbol in all uppercase, and support for the currencies is
+ // provided by the data in `dojo.cldr`. The scripts generating dojo.cldr specify which
+ // currency support is included. A fixed number of decimal places is determined based
+ // on the currency type and is not determined by the 'pattern' argument. The fractional
+ // portion is optional, by default, and variable length decimals are not supported.
+}
+=====*/
+
+dojo.currency._mixInDefaults = function(options){
+ options = options || {};
+ options.type = "currency";
+
+ // Get locale-dependent currency data, like the symbol
+ var bundle = dojo.i18n.getLocalization("dojo.cldr", "currency", options.locale) || {};
+
+ // Mixin locale-independent currency data, like # of places
+ var iso = options.currency;
+ var data = dojo.cldr.monetary.getData(iso);
+
+ dojo.forEach(["displayName","symbol","group","decimal"], function(prop){
+ data[prop] = bundle[iso+"_"+prop];
+ });
+
+ data.fractional = [true, false];
+
+ // Mixin with provided options
+ return dojo.mixin(data, options);
+}
+
+/*=====
+dojo.declare("dojo.currency.__FormatOptions", [dojo.number.__FormatOptions], {
+ // type: String?
+ // Should not be set. Value is assumed to be "currency".
+ // symbol: String?
+ // localized currency symbol. The default will be looked up in table of supported currencies in `dojo.cldr`
+ // A [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code will be used if not found.
+ // currency: String?
+ // an [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD".
+ // For use with dojo.currency only.
+ // places: Number?
+ // number of decimal places to show. Default is defined based on which currency is used.
+ type: "",
+ symbol: "",
+ currency: "",
+ places: ""
});
-_4.fractional=[true,false];
-return dojo.mixin(_4,_1);
-};
-dojo.currency.format=function(_6,_7){
-return dojo.number.format(_6,dojo.currency._mixInDefaults(_7));
-};
-dojo.currency.regexp=function(_8){
-return dojo.number.regexp(dojo.currency._mixInDefaults(_8));
-};
-dojo.currency.parse=function(_9,_a){
-return dojo.number.parse(_9,dojo.currency._mixInDefaults(_a));
-};
+=====*/
+
+dojo.currency.format = function(/*Number*/value, /*dojo.currency.__FormatOptions?*/options){
+// summary:
+// Format a Number as a currency, using locale-specific settings
+//
+// description:
+// Create a string from a Number using a known, localized pattern.
+// [Formatting patterns](http://www.unicode.org/reports/tr35/#Number_Elements)
+// appropriate to the locale are chosen from the [CLDR](http://unicode.org/cldr)
+// as well as the appropriate symbols and delimiters and number of decimal places.
+//
+// value:
+// the number to be formatted.
+
+ return dojo.number.format(value, dojo.currency._mixInDefaults(options));
+}
+
+dojo.currency.regexp = function(/*dojo.number.__RegexpOptions?*/options){
+//
+// summary:
+// Builds the regular needed to parse a currency value
+//
+// description:
+// Returns regular expression with positive and negative match, group and decimal separators
+// Note: the options.places default, the number of decimal places to accept, is defined by the currency type.
+ return dojo.number.regexp(dojo.currency._mixInDefaults(options)); // String
+}
+
+/*=====
+dojo.declare("dojo.currency.__ParseOptions", [dojo.number.__ParseOptions], {
+ // type: String?
+ // Should not be set. Value is assumed to be currency.
+ // currency: String?
+ // an [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD".
+ // For use with dojo.currency only.
+ // symbol: String?
+ // localized currency symbol. The default will be looked up in table of supported currencies in `dojo.cldr`
+ // A [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code will be used if not found.
+ // places: Number?
+ // fixed number of decimal places to accept. The default is determined based on which currency is used.
+ // fractional: Boolean?|Array?
+ // Whether to include the fractional portion, where the number of decimal places are implied by the currency
+ // or explicit 'places' parameter. The value [true,false] makes the fractional portion optional.
+ // By default for currencies, it the fractional portion is optional.
+ type: "",
+ currency: "",
+ symbol: "",
+ places: "",
+ fractional: ""
+});
+=====*/
+
+dojo.currency.parse = function(/*String*/expression, /*dojo.currency.__ParseOptions?*/options){
+ //
+ // summary:
+ // Convert a properly formatted currency string to a primitive Number,
+ // using locale-specific settings.
+ //
+ // description:
+ // Create a Number from a string using a known, localized pattern.
+ // [Formatting patterns](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // are chosen appropriate to the locale, as well as the appropriate symbols and delimiters
+ // and number of decimal places.
+ //
+ // expression: A string representation of a currency value
+
+ return dojo.number.parse(expression, dojo.currency._mixInDefaults(options));
+}
+
}
diff --git a/lib/dojo/data/ItemFileReadStore.js b/lib/dojo/data/ItemFileReadStore.js
index 01c15ee00..1faed3c7d 100644
--- a/lib/dojo/data/ItemFileReadStore.js
+++ b/lib/dojo/data/ItemFileReadStore.js
@@ -5,558 +5,945 @@
*/
-if(!dojo._hasResource["dojo.data.ItemFileReadStore"]){
-dojo._hasResource["dojo.data.ItemFileReadStore"]=true;
+if(!dojo._hasResource["dojo.data.ItemFileReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.ItemFileReadStore"] = true;
dojo.provide("dojo.data.ItemFileReadStore");
+
dojo.require("dojo.data.util.filter");
dojo.require("dojo.data.util.simpleFetch");
dojo.require("dojo.date.stamp");
-dojo.declare("dojo.data.ItemFileReadStore",null,{constructor:function(_1){
-this._arrayOfAllItems=[];
-this._arrayOfTopLevelItems=[];
-this._loadFinished=false;
-this._jsonFileUrl=_1.url;
-this._ccUrl=_1.url;
-this.url=_1.url;
-this._jsonData=_1.data;
-this.data=null;
-this._datatypeMap=_1.typeMap||{};
-if(!this._datatypeMap["Date"]){
-this._datatypeMap["Date"]={type:Date,deserialize:function(_2){
-return dojo.date.stamp.fromISOString(_2);
-}};
-}
-this._features={"dojo.data.api.Read":true,"dojo.data.api.Identity":true};
-this._itemsByIdentity=null;
-this._storeRefPropName="_S";
-this._itemNumPropName="_0";
-this._rootItemPropName="_RI";
-this._reverseRefMap="_RRM";
-this._loadInProgress=false;
-this._queuedFetches=[];
-if(_1.urlPreventCache!==undefined){
-this.urlPreventCache=_1.urlPreventCache?true:false;
-}
-if(_1.hierarchical!==undefined){
-this.hierarchical=_1.hierarchical?true:false;
-}
-if(_1.clearOnClose){
-this.clearOnClose=true;
-}
-if("failOk" in _1){
-this.failOk=_1.failOk?true:false;
-}
-},url:"",_ccUrl:"",data:null,typeMap:null,clearOnClose:false,urlPreventCache:false,failOk:false,hierarchical:true,_assertIsItem:function(_3){
-if(!this.isItem(_3)){
-throw new Error("dojo.data.ItemFileReadStore: Invalid item argument.");
-}
-},_assertIsAttribute:function(_4){
-if(typeof _4!=="string"){
-throw new Error("dojo.data.ItemFileReadStore: Invalid attribute argument.");
-}
-},getValue:function(_5,_6,_7){
-var _8=this.getValues(_5,_6);
-return (_8.length>0)?_8[0]:_7;
-},getValues:function(_9,_a){
-this._assertIsItem(_9);
-this._assertIsAttribute(_a);
-return (_9[_a]||[]).slice(0);
-},getAttributes:function(_b){
-this._assertIsItem(_b);
-var _c=[];
-for(var _d in _b){
-if((_d!==this._storeRefPropName)&&(_d!==this._itemNumPropName)&&(_d!==this._rootItemPropName)&&(_d!==this._reverseRefMap)){
-_c.push(_d);
-}
-}
-return _c;
-},hasAttribute:function(_e,_f){
-this._assertIsItem(_e);
-this._assertIsAttribute(_f);
-return (_f in _e);
-},containsValue:function(_10,_11,_12){
-var _13=undefined;
-if(typeof _12==="string"){
-_13=dojo.data.util.filter.patternToRegExp(_12,false);
-}
-return this._containsValue(_10,_11,_12,_13);
-},_containsValue:function(_14,_15,_16,_17){
-return dojo.some(this.getValues(_14,_15),function(_18){
-if(_18!==null&&!dojo.isObject(_18)&&_17){
-if(_18.toString().match(_17)){
-return true;
-}
-}else{
-if(_16===_18){
-return true;
-}
-}
-});
-},isItem:function(_19){
-if(_19&&_19[this._storeRefPropName]===this){
-if(this._arrayOfAllItems[_19[this._itemNumPropName]]===_19){
-return true;
-}
-}
-return false;
-},isItemLoaded:function(_1a){
-return this.isItem(_1a);
-},loadItem:function(_1b){
-this._assertIsItem(_1b.item);
-},getFeatures:function(){
-return this._features;
-},getLabel:function(_1c){
-if(this._labelAttr&&this.isItem(_1c)){
-return this.getValue(_1c,this._labelAttr);
-}
-return undefined;
-},getLabelAttributes:function(_1d){
-if(this._labelAttr){
-return [this._labelAttr];
-}
-return null;
-},_fetchItems:function(_1e,_1f,_20){
-var _21=this,_22=function(_23,_24){
-var _25=[],i,key;
-if(_23.query){
-var _26,_27=_23.queryOptions?_23.queryOptions.ignoreCase:false;
-var _28={};
-for(key in _23.query){
-_26=_23.query[key];
-if(typeof _26==="string"){
-_28[key]=dojo.data.util.filter.patternToRegExp(_26,_27);
-}else{
-if(_26 instanceof RegExp){
-_28[key]=_26;
-}
-}
-}
-for(i=0;i<_24.length;++i){
-var _29=true;
-var _2a=_24[i];
-if(_2a===null){
-_29=false;
-}else{
-for(key in _23.query){
-_26=_23.query[key];
-if(!_21._containsValue(_2a,key,_26,_28[key])){
-_29=false;
-}
-}
-}
-if(_29){
-_25.push(_2a);
-}
-}
-_1f(_25,_23);
-}else{
-for(i=0;i<_24.length;++i){
-var _2b=_24[i];
-if(_2b!==null){
-_25.push(_2b);
-}
-}
-_1f(_25,_23);
-}
-};
-if(this._loadFinished){
-_22(_1e,this._getItemsArray(_1e.queryOptions));
-}else{
-if(this._jsonFileUrl!==this._ccUrl){
-dojo.deprecated("dojo.data.ItemFileReadStore: ","To change the url, set the url property of the store,"+" not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
-this._ccUrl=this._jsonFileUrl;
-this.url=this._jsonFileUrl;
-}else{
-if(this.url!==this._ccUrl){
-this._jsonFileUrl=this.url;
-this._ccUrl=this.url;
-}
-}
-if(this.data!=null&&this._jsonData==null){
-this._jsonData=this.data;
-this.data=null;
-}
-if(this._jsonFileUrl){
-if(this._loadInProgress){
-this._queuedFetches.push({args:_1e,filter:_22});
-}else{
-this._loadInProgress=true;
-var _2c={url:_21._jsonFileUrl,handleAs:"json-comment-optional",preventCache:this.urlPreventCache,failOk:this.failOk};
-var _2d=dojo.xhrGet(_2c);
-_2d.addCallback(function(_2e){
-try{
-_21._getItemsFromLoadedData(_2e);
-_21._loadFinished=true;
-_21._loadInProgress=false;
-_22(_1e,_21._getItemsArray(_1e.queryOptions));
-_21._handleQueuedFetches();
-}
-catch(e){
-_21._loadFinished=true;
-_21._loadInProgress=false;
-_20(e,_1e);
-}
-});
-_2d.addErrback(function(_2f){
-_21._loadInProgress=false;
-_20(_2f,_1e);
-});
-var _30=null;
-if(_1e.abort){
-_30=_1e.abort;
-}
-_1e.abort=function(){
-var df=_2d;
-if(df&&df.fired===-1){
-df.cancel();
-df=null;
-}
-if(_30){
-_30.call(_1e);
-}
-};
-}
-}else{
-if(this._jsonData){
-try{
-this._loadFinished=true;
-this._getItemsFromLoadedData(this._jsonData);
-this._jsonData=null;
-_22(_1e,this._getItemsArray(_1e.queryOptions));
-}
-catch(e){
-_20(e,_1e);
-}
-}else{
-_20(new Error("dojo.data.ItemFileReadStore: No JSON source data was provided as either URL or a nested Javascript object."),_1e);
-}
-}
-}
-},_handleQueuedFetches:function(){
-if(this._queuedFetches.length>0){
-for(var i=0;i<this._queuedFetches.length;i++){
-var _31=this._queuedFetches[i],_32=_31.args,_33=_31.filter;
-if(_33){
-_33(_32,this._getItemsArray(_32.queryOptions));
-}else{
-this.fetchItemByIdentity(_32);
-}
-}
-this._queuedFetches=[];
-}
-},_getItemsArray:function(_34){
-if(_34&&_34.deep){
-return this._arrayOfAllItems;
-}
-return this._arrayOfTopLevelItems;
-},close:function(_35){
-if(this.clearOnClose&&this._loadFinished&&!this._loadInProgress){
-if(((this._jsonFileUrl==""||this._jsonFileUrl==null)&&(this.url==""||this.url==null))&&this.data==null){
-}
-this._arrayOfAllItems=[];
-this._arrayOfTopLevelItems=[];
-this._loadFinished=false;
-this._itemsByIdentity=null;
-this._loadInProgress=false;
-this._queuedFetches=[];
-}
-},_getItemsFromLoadedData:function(_36){
-var _37=false,_38=this;
-function _39(_3a){
-var _3b=((_3a!==null)&&(typeof _3a==="object")&&(!dojo.isArray(_3a)||_37)&&(!dojo.isFunction(_3a))&&(_3a.constructor==Object||dojo.isArray(_3a))&&(typeof _3a._reference==="undefined")&&(typeof _3a._type==="undefined")&&(typeof _3a._value==="undefined")&&_38.hierarchical);
-return _3b;
-};
-function _3c(_3d){
-_38._arrayOfAllItems.push(_3d);
-for(var _3e in _3d){
-var _3f=_3d[_3e];
-if(_3f){
-if(dojo.isArray(_3f)){
-var _40=_3f;
-for(var k=0;k<_40.length;++k){
-var _41=_40[k];
-if(_39(_41)){
-_3c(_41);
-}
-}
-}else{
-if(_39(_3f)){
-_3c(_3f);
-}
-}
-}
-}
-};
-this._labelAttr=_36.label;
-var i,_42;
-this._arrayOfAllItems=[];
-this._arrayOfTopLevelItems=_36.items;
-for(i=0;i<this._arrayOfTopLevelItems.length;++i){
-_42=this._arrayOfTopLevelItems[i];
-if(dojo.isArray(_42)){
-_37=true;
-}
-_3c(_42);
-_42[this._rootItemPropName]=true;
-}
-var _43={},key;
-for(i=0;i<this._arrayOfAllItems.length;++i){
-_42=this._arrayOfAllItems[i];
-for(key in _42){
-if(key!==this._rootItemPropName){
-var _44=_42[key];
-if(_44!==null){
-if(!dojo.isArray(_44)){
-_42[key]=[_44];
-}
-}else{
-_42[key]=[null];
-}
-}
-_43[key]=key;
-}
-}
-while(_43[this._storeRefPropName]){
-this._storeRefPropName+="_";
-}
-while(_43[this._itemNumPropName]){
-this._itemNumPropName+="_";
-}
-while(_43[this._reverseRefMap]){
-this._reverseRefMap+="_";
-}
-var _45;
-var _46=_36.identifier;
-if(_46){
-this._itemsByIdentity={};
-this._features["dojo.data.api.Identity"]=_46;
-for(i=0;i<this._arrayOfAllItems.length;++i){
-_42=this._arrayOfAllItems[i];
-_45=_42[_46];
-var _47=_45[0];
-if(!this._itemsByIdentity[_47]){
-this._itemsByIdentity[_47]=_42;
-}else{
-if(this._jsonFileUrl){
-throw new Error("dojo.data.ItemFileReadStore: The json data as specified by: ["+this._jsonFileUrl+"] is malformed. Items within the list have identifier: ["+_46+"]. Value collided: ["+_47+"]");
-}else{
-if(this._jsonData){
-throw new Error("dojo.data.ItemFileReadStore: The json data provided by the creation arguments is malformed. Items within the list have identifier: ["+_46+"]. Value collided: ["+_47+"]");
-}
-}
-}
-}
-}else{
-this._features["dojo.data.api.Identity"]=Number;
-}
-for(i=0;i<this._arrayOfAllItems.length;++i){
-_42=this._arrayOfAllItems[i];
-_42[this._storeRefPropName]=this;
-_42[this._itemNumPropName]=i;
-}
-for(i=0;i<this._arrayOfAllItems.length;++i){
-_42=this._arrayOfAllItems[i];
-for(key in _42){
-_45=_42[key];
-for(var j=0;j<_45.length;++j){
-_44=_45[j];
-if(_44!==null&&typeof _44=="object"){
-if(("_type" in _44)&&("_value" in _44)){
-var _48=_44._type;
-var _49=this._datatypeMap[_48];
-if(!_49){
-throw new Error("dojo.data.ItemFileReadStore: in the typeMap constructor arg, no object class was specified for the datatype '"+_48+"'");
-}else{
-if(dojo.isFunction(_49)){
-_45[j]=new _49(_44._value);
-}else{
-if(dojo.isFunction(_49.deserialize)){
-_45[j]=_49.deserialize(_44._value);
-}else{
-throw new Error("dojo.data.ItemFileReadStore: Value provided in typeMap was neither a constructor, nor a an object with a deserialize function");
-}
-}
-}
-}
-if(_44._reference){
-var _4a=_44._reference;
-if(!dojo.isObject(_4a)){
-_45[j]=this._getItemByIdentity(_4a);
-}else{
-for(var k=0;k<this._arrayOfAllItems.length;++k){
-var _4b=this._arrayOfAllItems[k],_4c=true;
-for(var _4d in _4a){
-if(_4b[_4d]!=_4a[_4d]){
-_4c=false;
-}
-}
-if(_4c){
-_45[j]=_4b;
-}
-}
-}
-if(this.referenceIntegrity){
-var _4e=_45[j];
-if(this.isItem(_4e)){
-this._addReferenceToMap(_4e,_42,key);
-}
-}
-}else{
-if(this.isItem(_44)){
-if(this.referenceIntegrity){
-this._addReferenceToMap(_44,_42,key);
-}
-}
-}
-}
-}
-}
-}
-},_addReferenceToMap:function(_4f,_50,_51){
-},getIdentity:function(_52){
-var _53=this._features["dojo.data.api.Identity"];
-if(_53===Number){
-return _52[this._itemNumPropName];
-}else{
-var _54=_52[_53];
-if(_54){
-return _54[0];
-}
-}
-return null;
-},fetchItemByIdentity:function(_55){
-var _56,_57;
-if(!this._loadFinished){
-var _58=this;
-if(this._jsonFileUrl!==this._ccUrl){
-dojo.deprecated("dojo.data.ItemFileReadStore: ","To change the url, set the url property of the store,"+" not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
-this._ccUrl=this._jsonFileUrl;
-this.url=this._jsonFileUrl;
-}else{
-if(this.url!==this._ccUrl){
-this._jsonFileUrl=this.url;
-this._ccUrl=this.url;
-}
-}
-if(this.data!=null&&this._jsonData==null){
-this._jsonData=this.data;
-this.data=null;
-}
-if(this._jsonFileUrl){
-if(this._loadInProgress){
-this._queuedFetches.push({args:_55});
-}else{
-this._loadInProgress=true;
-var _59={url:_58._jsonFileUrl,handleAs:"json-comment-optional",preventCache:this.urlPreventCache,failOk:this.failOk};
-var _5a=dojo.xhrGet(_59);
-_5a.addCallback(function(_5b){
-var _5c=_55.scope?_55.scope:dojo.global;
-try{
-_58._getItemsFromLoadedData(_5b);
-_58._loadFinished=true;
-_58._loadInProgress=false;
-_56=_58._getItemByIdentity(_55.identity);
-if(_55.onItem){
-_55.onItem.call(_5c,_56);
-}
-_58._handleQueuedFetches();
-}
-catch(error){
-_58._loadInProgress=false;
-if(_55.onError){
-_55.onError.call(_5c,error);
-}
-}
-});
-_5a.addErrback(function(_5d){
-_58._loadInProgress=false;
-if(_55.onError){
-var _5e=_55.scope?_55.scope:dojo.global;
-_55.onError.call(_5e,_5d);
-}
-});
-}
-}else{
-if(this._jsonData){
-_58._getItemsFromLoadedData(_58._jsonData);
-_58._jsonData=null;
-_58._loadFinished=true;
-_56=_58._getItemByIdentity(_55.identity);
-if(_55.onItem){
-_57=_55.scope?_55.scope:dojo.global;
-_55.onItem.call(_57,_56);
-}
-}
-}
-}else{
-_56=this._getItemByIdentity(_55.identity);
-if(_55.onItem){
-_57=_55.scope?_55.scope:dojo.global;
-_55.onItem.call(_57,_56);
-}
-}
-},_getItemByIdentity:function(_5f){
-var _60=null;
-if(this._itemsByIdentity){
-_60=this._itemsByIdentity[_5f];
-}else{
-_60=this._arrayOfAllItems[_5f];
-}
-if(_60===undefined){
-_60=null;
-}
-return _60;
-},getIdentityAttributes:function(_61){
-var _62=this._features["dojo.data.api.Identity"];
-if(_62===Number){
-return null;
-}else{
-return [_62];
-}
-},_forceLoad:function(){
-var _63=this;
-if(this._jsonFileUrl!==this._ccUrl){
-dojo.deprecated("dojo.data.ItemFileReadStore: ","To change the url, set the url property of the store,"+" not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
-this._ccUrl=this._jsonFileUrl;
-this.url=this._jsonFileUrl;
-}else{
-if(this.url!==this._ccUrl){
-this._jsonFileUrl=this.url;
-this._ccUrl=this.url;
-}
-}
-if(this.data!=null&&this._jsonData==null){
-this._jsonData=this.data;
-this.data=null;
-}
-if(this._jsonFileUrl){
-var _64={url:this._jsonFileUrl,handleAs:"json-comment-optional",preventCache:this.urlPreventCache,failOk:this.failOk,sync:true};
-var _65=dojo.xhrGet(_64);
-_65.addCallback(function(_66){
-try{
-if(_63._loadInProgress!==true&&!_63._loadFinished){
-_63._getItemsFromLoadedData(_66);
-_63._loadFinished=true;
-}else{
-if(_63._loadInProgress){
-throw new Error("dojo.data.ItemFileReadStore: Unable to perform a synchronous load, an async load is in progress.");
-}
-}
-}
-catch(e){
-throw e;
-}
-});
-_65.addErrback(function(_67){
-throw _67;
+
+dojo.declare("dojo.data.ItemFileReadStore", null,{
+ // summary:
+ // The ItemFileReadStore implements the dojo.data.api.Read API and reads
+ // data from JSON files that have contents in this format --
+ // { items: [
+ // { name:'Kermit', color:'green', age:12, friends:['Gonzo', {_reference:{name:'Fozzie Bear'}}]},
+ // { name:'Fozzie Bear', wears:['hat', 'tie']},
+ // { name:'Miss Piggy', pets:'Foo-Foo'}
+ // ]}
+ // Note that it can also contain an 'identifer' property that specified which attribute on the items
+ // in the array of items that acts as the unique identifier for that item.
+ //
+ constructor: function(/* Object */ keywordParameters){
+ // summary: constructor
+ // keywordParameters: {url: String}
+ // keywordParameters: {data: jsonObject}
+ // keywordParameters: {typeMap: object)
+ // The structure of the typeMap object is as follows:
+ // {
+ // type0: function || object,
+ // type1: function || object,
+ // ...
+ // typeN: function || object
+ // }
+ // Where if it is a function, it is assumed to be an object constructor that takes the
+ // value of _value as the initialization parameters. If it is an object, then it is assumed
+ // to be an object of general form:
+ // {
+ // type: function, //constructor.
+ // deserialize: function(value) //The function that parses the value and constructs the object defined by type appropriately.
+ // }
+
+ this._arrayOfAllItems = [];
+ this._arrayOfTopLevelItems = [];
+ this._loadFinished = false;
+ this._jsonFileUrl = keywordParameters.url;
+ this._ccUrl = keywordParameters.url;
+ this.url = keywordParameters.url;
+ this._jsonData = keywordParameters.data;
+ this.data = null;
+ this._datatypeMap = keywordParameters.typeMap || {};
+ if(!this._datatypeMap['Date']){
+ //If no default mapping for dates, then set this as default.
+ //We use the dojo.date.stamp here because the ISO format is the 'dojo way'
+ //of generically representing dates.
+ this._datatypeMap['Date'] = {
+ type: Date,
+ deserialize: function(value){
+ return dojo.date.stamp.fromISOString(value);
+ }
+ };
+ }
+ this._features = {'dojo.data.api.Read':true, 'dojo.data.api.Identity':true};
+ this._itemsByIdentity = null;
+ this._storeRefPropName = "_S"; // Default name for the store reference to attach to every item.
+ this._itemNumPropName = "_0"; // Default Item Id for isItem to attach to every item.
+ this._rootItemPropName = "_RI"; // Default Item Id for isItem to attach to every item.
+ this._reverseRefMap = "_RRM"; // Default attribute for constructing a reverse reference map for use with reference integrity
+ this._loadInProgress = false; //Got to track the initial load to prevent duelling loads of the dataset.
+ this._queuedFetches = [];
+ if(keywordParameters.urlPreventCache !== undefined){
+ this.urlPreventCache = keywordParameters.urlPreventCache?true:false;
+ }
+ if(keywordParameters.hierarchical !== undefined){
+ this.hierarchical = keywordParameters.hierarchical?true:false;
+ }
+ if(keywordParameters.clearOnClose){
+ this.clearOnClose = true;
+ }
+ if("failOk" in keywordParameters){
+ this.failOk = keywordParameters.failOk?true:false;
+ }
+ },
+
+ url: "", // use "" rather than undefined for the benefit of the parser (#3539)
+
+ //Internal var, crossCheckUrl. Used so that setting either url or _jsonFileUrl, can still trigger a reload
+ //when clearOnClose and close is used.
+ _ccUrl: "",
+
+ data: null, // define this so that the parser can populate it
+
+ typeMap: null, //Define so parser can populate.
+
+ //Parameter to allow users to specify if a close call should force a reload or not.
+ //By default, it retains the old behavior of not clearing if close is called. But
+ //if set true, the store will be reset to default state. Note that by doing this,
+ //all item handles will become invalid and a new fetch must be issued.
+ clearOnClose: false,
+
+ //Parameter to allow specifying if preventCache should be passed to the xhrGet call or not when loading data from a url.
+ //Note this does not mean the store calls the server on each fetch, only that the data load has preventCache set as an option.
+ //Added for tracker: #6072
+ urlPreventCache: false,
+
+ //Parameter for specifying that it is OK for the xhrGet call to fail silently.
+ failOk: false,
+
+ //Parameter to indicate to process data from the url as hierarchical
+ //(data items can contain other data items in js form). Default is true
+ //for backwards compatibility. False means only root items are processed
+ //as items, all child objects outside of type-mapped objects and those in
+ //specific reference format, are left straight JS data objects.
+ hierarchical: true,
+
+ _assertIsItem: function(/* item */ item){
+ // summary:
+ // This function tests whether the item passed in is indeed an item in the store.
+ // item:
+ // The item to test for being contained by the store.
+ if(!this.isItem(item)){
+ throw new Error("dojo.data.ItemFileReadStore: Invalid item argument.");
+ }
+ },
+
+ _assertIsAttribute: function(/* attribute-name-string */ attribute){
+ // summary:
+ // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
+ // attribute:
+ // The attribute to test for being contained by the store.
+ if(typeof attribute !== "string"){
+ throw new Error("dojo.data.ItemFileReadStore: Invalid attribute argument.");
+ }
+ },
+
+ getValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* value? */ defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ return (values.length > 0)?values[0]:defaultValue; // mixed
+ },
+
+ getValues: function(/* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.getValues()
+
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ // Clone it before returning. refs: #10474
+ return (item[attribute] || []).slice(0); // Array
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ var attributes = [];
+ for(var key in item){
+ // Save off only the real item attributes, not the special id marks for O(1) isItem.
+ if((key !== this._storeRefPropName) && (key !== this._itemNumPropName) && (key !== this._rootItemPropName) && (key !== this._reverseRefMap)){
+ attributes.push(key);
+ }
+ }
+ return attributes; // Array
+ },
+
+ hasAttribute: function( /* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttribute()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ return (attribute in item);
+ },
+
+ containsValue: function(/* item */ item,
+ /* attribute-name-string */ attribute,
+ /* anything */ value){
+ // summary:
+ // See dojo.data.api.Read.containsValue()
+ var regexp = undefined;
+ if(typeof value === "string"){
+ regexp = dojo.data.util.filter.patternToRegExp(value, false);
+ }
+ return this._containsValue(item, attribute, value, regexp); //boolean.
+ },
+
+ _containsValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* anything */ value,
+ /* RegExp?*/ regexp){
+ // summary:
+ // Internal function for looking at the values contained by the item.
+ // description:
+ // Internal function for looking at the values contained by the item. This
+ // function allows for denoting if the comparison should be case sensitive for
+ // strings or not (for handling filtering cases where string case should not matter)
+ //
+ // item:
+ // The data item to examine for attribute values.
+ // attribute:
+ // The attribute to inspect.
+ // value:
+ // The value to match.
+ // regexp:
+ // Optional regular expression generated off value if value was of string type to handle wildcarding.
+ // If present and attribute values are string, then it can be used for comparison instead of 'value'
+ return dojo.some(this.getValues(item, attribute), function(possibleValue){
+ if(possibleValue !== null && !dojo.isObject(possibleValue) && regexp){
+ if(possibleValue.toString().match(regexp)){
+ return true; // Boolean
+ }
+ }else if(value === possibleValue){
+ return true; // Boolean
+ }
+ });
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ if(something && something[this._storeRefPropName] === this){
+ if(this._arrayOfAllItems[something[this._itemNumPropName]] === something){
+ return true;
+ }
+ }
+ return false; // Boolean
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ return this.isItem(something); //boolean
+ },
+
+ loadItem: function(/* object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ this._assertIsItem(keywordArgs.item);
+ },
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return this._features; //Object
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ if(this._labelAttr && this.isItem(item)){
+ return this.getValue(item,this._labelAttr); //String
+ }
+ return undefined; //undefined
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ if(this._labelAttr){
+ return [this._labelAttr]; //array
+ }
+ return null; //null
+ },
+
+ _fetchItems: function( /* Object */ keywordArgs,
+ /* Function */ findCallback,
+ /* Function */ errorCallback){
+ // summary:
+ // See dojo.data.util.simpleFetch.fetch()
+ var self = this,
+ filter = function(requestArgs, arrayOfItems){
+ var items = [],
+ i, key;
+ if(requestArgs.query){
+ var value,
+ ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false;
+
+ //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
+ //same value for each item examined. Much more efficient.
+ var regexpList = {};
+ for(key in requestArgs.query){
+ value = requestArgs.query[key];
+ if(typeof value === "string"){
+ regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
+ }else if(value instanceof RegExp){
+ regexpList[key] = value;
+ }
+ }
+ for(i = 0; i < arrayOfItems.length; ++i){
+ var match = true;
+ var candidateItem = arrayOfItems[i];
+ if(candidateItem === null){
+ match = false;
+ }else{
+ for(key in requestArgs.query){
+ value = requestArgs.query[key];
+ if(!self._containsValue(candidateItem, key, value, regexpList[key])){
+ match = false;
+ }
+ }
+ }
+ if(match){
+ items.push(candidateItem);
+ }
+ }
+ findCallback(items, requestArgs);
+ }else{
+ // We want a copy to pass back in case the parent wishes to sort the array.
+ // We shouldn't allow resort of the internal list, so that multiple callers
+ // can get lists and sort without affecting each other. We also need to
+ // filter out any null values that have been left as a result of deleteItem()
+ // calls in ItemFileWriteStore.
+ for(i = 0; i < arrayOfItems.length; ++i){
+ var item = arrayOfItems[i];
+ if(item !== null){
+ items.push(item);
+ }
+ }
+ findCallback(items, requestArgs);
+ }
+ };
+
+ if(this._loadFinished){
+ filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
+ }else{
+ //Do a check on the JsonFileUrl and crosscheck it.
+ //If it doesn't match the cross-check, it needs to be updated
+ //This allows for either url or _jsonFileUrl to he changed to
+ //reset the store load location. Done this way for backwards
+ //compatibility. People use _jsonFileUrl (even though officially
+ //private.
+ if(this._jsonFileUrl !== this._ccUrl){
+ dojo.deprecated("dojo.data.ItemFileReadStore: ",
+ "To change the url, set the url property of the store," +
+ " not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
+ this._ccUrl = this._jsonFileUrl;
+ this.url = this._jsonFileUrl;
+ }else if(this.url !== this._ccUrl){
+ this._jsonFileUrl = this.url;
+ this._ccUrl = this.url;
+ }
+
+ //See if there was any forced reset of data.
+ if(this.data != null && this._jsonData == null){
+ this._jsonData = this.data;
+ this.data = null;
+ }
+
+ if(this._jsonFileUrl){
+ //If fetches come in before the loading has finished, but while
+ //a load is in progress, we have to defer the fetching to be
+ //invoked in the callback.
+ if(this._loadInProgress){
+ this._queuedFetches.push({args: keywordArgs, filter: filter});
+ }else{
+ this._loadInProgress = true;
+ var getArgs = {
+ url: self._jsonFileUrl,
+ handleAs: "json-comment-optional",
+ preventCache: this.urlPreventCache,
+ failOk: this.failOk
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ try{
+ self._getItemsFromLoadedData(data);
+ self._loadFinished = true;
+ self._loadInProgress = false;
+
+ filter(keywordArgs, self._getItemsArray(keywordArgs.queryOptions));
+ self._handleQueuedFetches();
+ }catch(e){
+ self._loadFinished = true;
+ self._loadInProgress = false;
+ errorCallback(e, keywordArgs);
+ }
+ });
+ getHandler.addErrback(function(error){
+ self._loadInProgress = false;
+ errorCallback(error, keywordArgs);
+ });
+
+ //Wire up the cancel to abort of the request
+ //This call cancel on the deferred if it hasn't been called
+ //yet and then will chain to the simple abort of the
+ //simpleFetch keywordArgs
+ var oldAbort = null;
+ if(keywordArgs.abort){
+ oldAbort = keywordArgs.abort;
+ }
+ keywordArgs.abort = function(){
+ var df = getHandler;
+ if(df && df.fired === -1){
+ df.cancel();
+ df = null;
+ }
+ if(oldAbort){
+ oldAbort.call(keywordArgs);
+ }
+ };
+ }
+ }else if(this._jsonData){
+ try{
+ this._loadFinished = true;
+ this._getItemsFromLoadedData(this._jsonData);
+ this._jsonData = null;
+ filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
+ }catch(e){
+ errorCallback(e, keywordArgs);
+ }
+ }else{
+ errorCallback(new Error("dojo.data.ItemFileReadStore: No JSON source data was provided as either URL or a nested Javascript object."), keywordArgs);
+ }
+ }
+ },
+
+ _handleQueuedFetches: function(){
+ // summary:
+ // Internal function to execute delayed request in the store.
+ //Execute any deferred fetches now.
+ if(this._queuedFetches.length > 0){
+ for(var i = 0; i < this._queuedFetches.length; i++){
+ var fData = this._queuedFetches[i],
+ delayedQuery = fData.args,
+ delayedFilter = fData.filter;
+ if(delayedFilter){
+ delayedFilter(delayedQuery, this._getItemsArray(delayedQuery.queryOptions));
+ }else{
+ this.fetchItemByIdentity(delayedQuery);
+ }
+ }
+ this._queuedFetches = [];
+ }
+ },
+
+ _getItemsArray: function(/*object?*/queryOptions){
+ // summary:
+ // Internal function to determine which list of items to search over.
+ // queryOptions: The query options parameter, if any.
+ if(queryOptions && queryOptions.deep){
+ return this._arrayOfAllItems;
+ }
+ return this._arrayOfTopLevelItems;
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ if(this.clearOnClose &&
+ this._loadFinished &&
+ !this._loadInProgress){
+ //Reset all internalsback to default state. This will force a reload
+ //on next fetch. This also checks that the data or url param was set
+ //so that the store knows it can get data. Without one of those being set,
+ //the next fetch will trigger an error.
+
+ if(((this._jsonFileUrl == "" || this._jsonFileUrl == null) &&
+ (this.url == "" || this.url == null)
+ ) && this.data == null){
+ console.debug("dojo.data.ItemFileReadStore: WARNING! Data reload " +
+ " information has not been provided." +
+ " Please set 'url' or 'data' to the appropriate value before" +
+ " the next fetch");
+ }
+ this._arrayOfAllItems = [];
+ this._arrayOfTopLevelItems = [];
+ this._loadFinished = false;
+ this._itemsByIdentity = null;
+ this._loadInProgress = false;
+ this._queuedFetches = [];
+ }
+ },
+
+ _getItemsFromLoadedData: function(/* Object */ dataObject){
+ // summary:
+ // Function to parse the loaded data into item format and build the internal items array.
+ // description:
+ // Function to parse the loaded data into item format and build the internal items array.
+ //
+ // dataObject:
+ // The JS data object containing the raw data to convery into item format.
+ //
+ // returns: array
+ // Array of items in store item format.
+
+ // First, we define a couple little utility functions...
+ var addingArrays = false,
+ self = this;
+
+ function valueIsAnItem(/* anything */ aValue){
+ // summary:
+ // Given any sort of value that could be in the raw json data,
+ // return true if we should interpret the value as being an
+ // item itself, rather than a literal value or a reference.
+ // example:
+ // | false == valueIsAnItem("Kermit");
+ // | false == valueIsAnItem(42);
+ // | false == valueIsAnItem(new Date());
+ // | false == valueIsAnItem({_type:'Date', _value:'May 14, 1802'});
+ // | false == valueIsAnItem({_reference:'Kermit'});
+ // | true == valueIsAnItem({name:'Kermit', color:'green'});
+ // | true == valueIsAnItem({iggy:'pop'});
+ // | true == valueIsAnItem({foo:42});
+ var isItem = (
+ (aValue !== null) &&
+ (typeof aValue === "object") &&
+ (!dojo.isArray(aValue) || addingArrays) &&
+ (!dojo.isFunction(aValue)) &&
+ (aValue.constructor == Object || dojo.isArray(aValue)) &&
+ (typeof aValue._reference === "undefined") &&
+ (typeof aValue._type === "undefined") &&
+ (typeof aValue._value === "undefined") &&
+ self.hierarchical
+ );
+ return isItem;
+ }
+
+ function addItemAndSubItemsToArrayOfAllItems(/* Item */ anItem){
+ self._arrayOfAllItems.push(anItem);
+ for(var attribute in anItem){
+ var valueForAttribute = anItem[attribute];
+ if(valueForAttribute){
+ if(dojo.isArray(valueForAttribute)){
+ var valueArray = valueForAttribute;
+ for(var k = 0; k < valueArray.length; ++k){
+ var singleValue = valueArray[k];
+ if(valueIsAnItem(singleValue)){
+ addItemAndSubItemsToArrayOfAllItems(singleValue);
+ }
+ }
+ }else{
+ if(valueIsAnItem(valueForAttribute)){
+ addItemAndSubItemsToArrayOfAllItems(valueForAttribute);
+ }
+ }
+ }
+ }
+ }
+
+ this._labelAttr = dataObject.label;
+
+ // We need to do some transformations to convert the data structure
+ // that we read from the file into a format that will be convenient
+ // to work with in memory.
+
+ // Step 1: Walk through the object hierarchy and build a list of all items
+ var i,
+ item;
+ this._arrayOfAllItems = [];
+ this._arrayOfTopLevelItems = dataObject.items;
+
+ for(i = 0; i < this._arrayOfTopLevelItems.length; ++i){
+ item = this._arrayOfTopLevelItems[i];
+ if(dojo.isArray(item)){
+ addingArrays = true;
+ }
+ addItemAndSubItemsToArrayOfAllItems(item);
+ item[this._rootItemPropName]=true;
+ }
+
+ // Step 2: Walk through all the attribute values of all the items,
+ // and replace single values with arrays. For example, we change this:
+ // { name:'Miss Piggy', pets:'Foo-Foo'}
+ // into this:
+ // { name:['Miss Piggy'], pets:['Foo-Foo']}
+ //
+ // We also store the attribute names so we can validate our store
+ // reference and item id special properties for the O(1) isItem
+ var allAttributeNames = {},
+ key;
+
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i];
+ for(key in item){
+ if(key !== this._rootItemPropName){
+ var value = item[key];
+ if(value !== null){
+ if(!dojo.isArray(value)){
+ item[key] = [value];
+ }
+ }else{
+ item[key] = [null];
+ }
+ }
+ allAttributeNames[key]=key;
+ }
+ }
+
+ // Step 3: Build unique property names to use for the _storeRefPropName and _itemNumPropName
+ // This should go really fast, it will generally never even run the loop.
+ while(allAttributeNames[this._storeRefPropName]){
+ this._storeRefPropName += "_";
+ }
+ while(allAttributeNames[this._itemNumPropName]){
+ this._itemNumPropName += "_";
+ }
+ while(allAttributeNames[this._reverseRefMap]){
+ this._reverseRefMap += "_";
+ }
+
+ // Step 4: Some data files specify an optional 'identifier', which is
+ // the name of an attribute that holds the identity of each item.
+ // If this data file specified an identifier attribute, then build a
+ // hash table of items keyed by the identity of the items.
+ var arrayOfValues;
+
+ var identifier = dataObject.identifier;
+ if(identifier){
+ this._itemsByIdentity = {};
+ this._features['dojo.data.api.Identity'] = identifier;
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i];
+ arrayOfValues = item[identifier];
+ var identity = arrayOfValues[0];
+ if(!this._itemsByIdentity[identity]){
+ this._itemsByIdentity[identity] = item;
+ }else{
+ if(this._jsonFileUrl){
+ throw new Error("dojo.data.ItemFileReadStore: The json data as specified by: [" + this._jsonFileUrl + "] is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]");
+ }else if(this._jsonData){
+ throw new Error("dojo.data.ItemFileReadStore: The json data provided by the creation arguments is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]");
+ }
+ }
+ }
+ }else{
+ this._features['dojo.data.api.Identity'] = Number;
+ }
+
+ // Step 5: Walk through all the items, and set each item's properties
+ // for _storeRefPropName and _itemNumPropName, so that store.isItem() will return true.
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i];
+ item[this._storeRefPropName] = this;
+ item[this._itemNumPropName] = i;
+ }
+
+ // Step 6: We walk through all the attribute values of all the items,
+ // looking for type/value literals and item-references.
+ //
+ // We replace item-references with pointers to items. For example, we change:
+ // { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
+ // into this:
+ // { name:['Kermit'], friends:[miss_piggy] }
+ // (where miss_piggy is the object representing the 'Miss Piggy' item).
+ //
+ // We replace type/value pairs with typed-literals. For example, we change:
+ // { name:['Nelson Mandela'], born:[{_type:'Date', _value:'July 18, 1918'}] }
+ // into this:
+ // { name:['Kermit'], born:(new Date('July 18, 1918')) }
+ //
+ // We also generate the associate map for all items for the O(1) isItem function.
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i]; // example: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
+ for(key in item){
+ arrayOfValues = item[key]; // example: [{_reference:{name:'Miss Piggy'}}]
+ for(var j = 0; j < arrayOfValues.length; ++j){
+ value = arrayOfValues[j]; // example: {_reference:{name:'Miss Piggy'}}
+ if(value !== null && typeof value == "object"){
+ if(("_type" in value) && ("_value" in value)){
+ var type = value._type; // examples: 'Date', 'Color', or 'ComplexNumber'
+ var mappingObj = this._datatypeMap[type]; // examples: Date, dojo.Color, foo.math.ComplexNumber, {type: dojo.Color, deserialize(value){ return new dojo.Color(value)}}
+ if(!mappingObj){
+ throw new Error("dojo.data.ItemFileReadStore: in the typeMap constructor arg, no object class was specified for the datatype '" + type + "'");
+ }else if(dojo.isFunction(mappingObj)){
+ arrayOfValues[j] = new mappingObj(value._value);
+ }else if(dojo.isFunction(mappingObj.deserialize)){
+ arrayOfValues[j] = mappingObj.deserialize(value._value);
+ }else{
+ throw new Error("dojo.data.ItemFileReadStore: Value provided in typeMap was neither a constructor, nor a an object with a deserialize function");
+ }
+ }
+ if(value._reference){
+ var referenceDescription = value._reference; // example: {name:'Miss Piggy'}
+ if(!dojo.isObject(referenceDescription)){
+ // example: 'Miss Piggy'
+ // from an item like: { name:['Kermit'], friends:[{_reference:'Miss Piggy'}]}
+ arrayOfValues[j] = this._getItemByIdentity(referenceDescription);
+ }else{
+ // example: {name:'Miss Piggy'}
+ // from an item like: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
+ for(var k = 0; k < this._arrayOfAllItems.length; ++k){
+ var candidateItem = this._arrayOfAllItems[k],
+ found = true;
+ for(var refKey in referenceDescription){
+ if(candidateItem[refKey] != referenceDescription[refKey]){
+ found = false;
+ }
+ }
+ if(found){
+ arrayOfValues[j] = candidateItem;
+ }
+ }
+ }
+ if(this.referenceIntegrity){
+ var refItem = arrayOfValues[j];
+ if(this.isItem(refItem)){
+ this._addReferenceToMap(refItem, item, key);
+ }
+ }
+ }else if(this.isItem(value)){
+ //It's a child item (not one referenced through _reference).
+ //We need to treat this as a referenced item, so it can be cleaned up
+ //in a write store easily.
+ if(this.referenceIntegrity){
+ this._addReferenceToMap(value, item, key);
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+
+ _addReferenceToMap: function(/*item*/ refItem, /*item*/ parentItem, /*string*/ attribute){
+ // summary:
+ // Method to add an reference map entry for an item and attribute.
+ // description:
+ // Method to add an reference map entry for an item and attribute. //
+ // refItem:
+ // The item that is referenced.
+ // parentItem:
+ // The item that holds the new reference to refItem.
+ // attribute:
+ // The attribute on parentItem that contains the new reference.
+
+ //Stub function, does nothing. Real processing is in ItemFileWriteStore.
+ },
+
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ var identifier = this._features['dojo.data.api.Identity'];
+ if(identifier === Number){
+ return item[this._itemNumPropName]; // Number
+ }else{
+ var arrayOfValues = item[identifier];
+ if(arrayOfValues){
+ return arrayOfValues[0]; // Object || String
+ }
+ }
+ return null; // null
+ },
+
+ fetchItemByIdentity: function(/* Object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity()
+
+ // Hasn't loaded yet, we have to trigger the load.
+ var item,
+ scope;
+ if(!this._loadFinished){
+ var self = this;
+ //Do a check on the JsonFileUrl and crosscheck it.
+ //If it doesn't match the cross-check, it needs to be updated
+ //This allows for either url or _jsonFileUrl to he changed to
+ //reset the store load location. Done this way for backwards
+ //compatibility. People use _jsonFileUrl (even though officially
+ //private.
+ if(this._jsonFileUrl !== this._ccUrl){
+ dojo.deprecated("dojo.data.ItemFileReadStore: ",
+ "To change the url, set the url property of the store," +
+ " not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
+ this._ccUrl = this._jsonFileUrl;
+ this.url = this._jsonFileUrl;
+ }else if(this.url !== this._ccUrl){
+ this._jsonFileUrl = this.url;
+ this._ccUrl = this.url;
+ }
+
+ //See if there was any forced reset of data.
+ if(this.data != null && this._jsonData == null){
+ this._jsonData = this.data;
+ this.data = null;
+ }
+
+ if(this._jsonFileUrl){
+
+ if(this._loadInProgress){
+ this._queuedFetches.push({args: keywordArgs});
+ }else{
+ this._loadInProgress = true;
+ var getArgs = {
+ url: self._jsonFileUrl,
+ handleAs: "json-comment-optional",
+ preventCache: this.urlPreventCache,
+ failOk: this.failOk
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ try{
+ self._getItemsFromLoadedData(data);
+ self._loadFinished = true;
+ self._loadInProgress = false;
+ item = self._getItemByIdentity(keywordArgs.identity);
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, item);
+ }
+ self._handleQueuedFetches();
+ }catch(error){
+ self._loadInProgress = false;
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, error);
+ }
+ }
+ });
+ getHandler.addErrback(function(error){
+ self._loadInProgress = false;
+ if(keywordArgs.onError){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onError.call(scope, error);
+ }
+ });
+ }
+
+ }else if(this._jsonData){
+ // Passed in data, no need to xhr.
+ self._getItemsFromLoadedData(self._jsonData);
+ self._jsonData = null;
+ self._loadFinished = true;
+ item = self._getItemByIdentity(keywordArgs.identity);
+ if(keywordArgs.onItem){
+ scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ }else{
+ // Already loaded. We can just look it up and call back.
+ item = this._getItemByIdentity(keywordArgs.identity);
+ if(keywordArgs.onItem){
+ scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ },
+
+ _getItemByIdentity: function(/* Object */ identity){
+ // summary:
+ // Internal function to look an item up by its identity map.
+ var item = null;
+ if(this._itemsByIdentity){
+ item = this._itemsByIdentity[identity];
+ }else{
+ item = this._arrayOfAllItems[identity];
+ }
+ if(item === undefined){
+ item = null;
+ }
+ return item; // Object
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentifierAttributes()
+
+ var identifier = this._features['dojo.data.api.Identity'];
+ if(identifier === Number){
+ // If (identifier === Number) it means getIdentity() just returns
+ // an integer item-number for each item. The dojo.data.api.Identity
+ // spec says we need to return null if the identity is not composed
+ // of attributes
+ return null; // null
+ }else{
+ return [identifier]; // Array
+ }
+ },
+
+ _forceLoad: function(){
+ // summary:
+ // Internal function to force a load of the store if it hasn't occurred yet. This is required
+ // for specific functions to work properly.
+ var self = this;
+ //Do a check on the JsonFileUrl and crosscheck it.
+ //If it doesn't match the cross-check, it needs to be updated
+ //This allows for either url or _jsonFileUrl to he changed to
+ //reset the store load location. Done this way for backwards
+ //compatibility. People use _jsonFileUrl (even though officially
+ //private.
+ if(this._jsonFileUrl !== this._ccUrl){
+ dojo.deprecated("dojo.data.ItemFileReadStore: ",
+ "To change the url, set the url property of the store," +
+ " not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
+ this._ccUrl = this._jsonFileUrl;
+ this.url = this._jsonFileUrl;
+ }else if(this.url !== this._ccUrl){
+ this._jsonFileUrl = this.url;
+ this._ccUrl = this.url;
+ }
+
+ //See if there was any forced reset of data.
+ if(this.data != null && this._jsonData == null){
+ this._jsonData = this.data;
+ this.data = null;
+ }
+
+ if(this._jsonFileUrl){
+ var getArgs = {
+ url: this._jsonFileUrl,
+ handleAs: "json-comment-optional",
+ preventCache: this.urlPreventCache,
+ failOk: this.failOk,
+ sync: true
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ try{
+ //Check to be sure there wasn't another load going on concurrently
+ //So we don't clobber data that comes in on it. If there is a load going on
+ //then do not save this data. It will potentially clobber current data.
+ //We mainly wanted to sync/wait here.
+ //TODO: Revisit the loading scheme of this store to improve multi-initial
+ //request handling.
+ if(self._loadInProgress !== true && !self._loadFinished){
+ self._getItemsFromLoadedData(data);
+ self._loadFinished = true;
+ }else if(self._loadInProgress){
+ //Okay, we hit an error state we can't recover from. A forced load occurred
+ //while an async load was occurring. Since we cannot block at this point, the best
+ //that can be managed is to throw an error.
+ throw new Error("dojo.data.ItemFileReadStore: Unable to perform a synchronous load, an async load is in progress.");
+ }
+ }catch(e){
+ console.log(e);
+ throw e;
+ }
+ });
+ getHandler.addErrback(function(error){
+ throw error;
+ });
+ }else if(this._jsonData){
+ self._getItemsFromLoadedData(self._jsonData);
+ self._jsonData = null;
+ self._loadFinished = true;
+ }
+ }
});
-}else{
-if(this._jsonData){
-_63._getItemsFromLoadedData(_63._jsonData);
-_63._jsonData=null;
-_63._loadFinished=true;
-}
-}
-}});
+//Mix in the simple fetch implementation to this class.
dojo.extend(dojo.data.ItemFileReadStore,dojo.data.util.simpleFetch);
+
}
diff --git a/lib/dojo/data/ItemFileWriteStore.js b/lib/dojo/data/ItemFileWriteStore.js
index c891c14e7..8782dce05 100644
--- a/lib/dojo/data/ItemFileWriteStore.js
+++ b/lib/dojo/data/ItemFileWriteStore.js
@@ -5,507 +5,813 @@
*/
-if(!dojo._hasResource["dojo.data.ItemFileWriteStore"]){
-dojo._hasResource["dojo.data.ItemFileWriteStore"]=true;
+if(!dojo._hasResource["dojo.data.ItemFileWriteStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.ItemFileWriteStore"] = true;
dojo.provide("dojo.data.ItemFileWriteStore");
dojo.require("dojo.data.ItemFileReadStore");
-dojo.declare("dojo.data.ItemFileWriteStore",dojo.data.ItemFileReadStore,{constructor:function(_1){
-this._features["dojo.data.api.Write"]=true;
-this._features["dojo.data.api.Notification"]=true;
-this._pending={_newItems:{},_modifiedItems:{},_deletedItems:{}};
-if(!this._datatypeMap["Date"].serialize){
-this._datatypeMap["Date"].serialize=function(_2){
-return dojo.date.stamp.toISOString(_2,{zulu:true});
-};
-}
-if(_1&&(_1.referenceIntegrity===false)){
-this.referenceIntegrity=false;
-}
-this._saveInProgress=false;
-},referenceIntegrity:true,_assert:function(_3){
-if(!_3){
-throw new Error("assertion failed in ItemFileWriteStore");
-}
-},_getIdentifierAttribute:function(){
-var _4=this.getFeatures()["dojo.data.api.Identity"];
-return _4;
-},newItem:function(_5,_6){
-this._assert(!this._saveInProgress);
-if(!this._loadFinished){
-this._forceLoad();
-}
-if(typeof _5!="object"&&typeof _5!="undefined"){
-throw new Error("newItem() was passed something other than an object");
-}
-var _7=null;
-var _8=this._getIdentifierAttribute();
-if(_8===Number){
-_7=this._arrayOfAllItems.length;
-}else{
-_7=_5[_8];
-if(typeof _7==="undefined"){
-throw new Error("newItem() was not passed an identity for the new item");
-}
-if(dojo.isArray(_7)){
-throw new Error("newItem() was not passed an single-valued identity");
-}
-}
-if(this._itemsByIdentity){
-this._assert(typeof this._itemsByIdentity[_7]==="undefined");
-}
-this._assert(typeof this._pending._newItems[_7]==="undefined");
-this._assert(typeof this._pending._deletedItems[_7]==="undefined");
-var _9={};
-_9[this._storeRefPropName]=this;
-_9[this._itemNumPropName]=this._arrayOfAllItems.length;
-if(this._itemsByIdentity){
-this._itemsByIdentity[_7]=_9;
-_9[_8]=[_7];
-}
-this._arrayOfAllItems.push(_9);
-var _a=null;
-if(_6&&_6.parent&&_6.attribute){
-_a={item:_6.parent,attribute:_6.attribute,oldValue:undefined};
-var _b=this.getValues(_6.parent,_6.attribute);
-if(_b&&_b.length>0){
-var _c=_b.slice(0,_b.length);
-if(_b.length===1){
-_a.oldValue=_b[0];
-}else{
-_a.oldValue=_b.slice(0,_b.length);
-}
-_c.push(_9);
-this._setValueOrValues(_6.parent,_6.attribute,_c,false);
-_a.newValue=this.getValues(_6.parent,_6.attribute);
-}else{
-this._setValueOrValues(_6.parent,_6.attribute,_9,false);
-_a.newValue=_9;
-}
-}else{
-_9[this._rootItemPropName]=true;
-this._arrayOfTopLevelItems.push(_9);
-}
-this._pending._newItems[_7]=_9;
-for(var _d in _5){
-if(_d===this._storeRefPropName||_d===this._itemNumPropName){
-throw new Error("encountered bug in ItemFileWriteStore.newItem");
-}
-var _e=_5[_d];
-if(!dojo.isArray(_e)){
-_e=[_e];
-}
-_9[_d]=_e;
-if(this.referenceIntegrity){
-for(var i=0;i<_e.length;i++){
-var _f=_e[i];
-if(this.isItem(_f)){
-this._addReferenceToMap(_f,_9,_d);
-}
-}
-}
-}
-this.onNew(_9,_a);
-return _9;
-},_removeArrayElement:function(_10,_11){
-var _12=dojo.indexOf(_10,_11);
-if(_12!=-1){
-_10.splice(_12,1);
-return true;
-}
-return false;
-},deleteItem:function(_13){
-this._assert(!this._saveInProgress);
-this._assertIsItem(_13);
-var _14=_13[this._itemNumPropName];
-var _15=this.getIdentity(_13);
-if(this.referenceIntegrity){
-var _16=this.getAttributes(_13);
-if(_13[this._reverseRefMap]){
-_13["backup_"+this._reverseRefMap]=dojo.clone(_13[this._reverseRefMap]);
-}
-dojo.forEach(_16,function(_17){
-dojo.forEach(this.getValues(_13,_17),function(_18){
-if(this.isItem(_18)){
-if(!_13["backupRefs_"+this._reverseRefMap]){
-_13["backupRefs_"+this._reverseRefMap]=[];
-}
-_13["backupRefs_"+this._reverseRefMap].push({id:this.getIdentity(_18),attr:_17});
-this._removeReferenceFromMap(_18,_13,_17);
-}
-},this);
-},this);
-var _19=_13[this._reverseRefMap];
-if(_19){
-for(var _1a in _19){
-var _1b=null;
-if(this._itemsByIdentity){
-_1b=this._itemsByIdentity[_1a];
-}else{
-_1b=this._arrayOfAllItems[_1a];
-}
-if(_1b){
-for(var _1c in _19[_1a]){
-var _1d=this.getValues(_1b,_1c)||[];
-var _1e=dojo.filter(_1d,function(_1f){
-return !(this.isItem(_1f)&&this.getIdentity(_1f)==_15);
-},this);
-this._removeReferenceFromMap(_13,_1b,_1c);
-if(_1e.length<_1d.length){
-this._setValueOrValues(_1b,_1c,_1e,true);
-}
-}
-}
-}
-}
-}
-this._arrayOfAllItems[_14]=null;
-_13[this._storeRefPropName]=null;
-if(this._itemsByIdentity){
-delete this._itemsByIdentity[_15];
-}
-this._pending._deletedItems[_15]=_13;
-if(_13[this._rootItemPropName]){
-this._removeArrayElement(this._arrayOfTopLevelItems,_13);
-}
-this.onDelete(_13);
-return true;
-},setValue:function(_20,_21,_22){
-return this._setValueOrValues(_20,_21,_22,true);
-},setValues:function(_23,_24,_25){
-return this._setValueOrValues(_23,_24,_25,true);
-},unsetAttribute:function(_26,_27){
-return this._setValueOrValues(_26,_27,[],true);
-},_setValueOrValues:function(_28,_29,_2a,_2b){
-this._assert(!this._saveInProgress);
-this._assertIsItem(_28);
-this._assert(dojo.isString(_29));
-this._assert(typeof _2a!=="undefined");
-var _2c=this._getIdentifierAttribute();
-if(_29==_2c){
-throw new Error("ItemFileWriteStore does not have support for changing the value of an item's identifier.");
-}
-var _2d=this._getValueOrValues(_28,_29);
-var _2e=this.getIdentity(_28);
-if(!this._pending._modifiedItems[_2e]){
-var _2f={};
-for(var key in _28){
-if((key===this._storeRefPropName)||(key===this._itemNumPropName)||(key===this._rootItemPropName)){
-_2f[key]=_28[key];
-}else{
-if(key===this._reverseRefMap){
-_2f[key]=dojo.clone(_28[key]);
-}else{
-_2f[key]=_28[key].slice(0,_28[key].length);
-}
-}
-}
-this._pending._modifiedItems[_2e]=_2f;
-}
-var _30=false;
-if(dojo.isArray(_2a)&&_2a.length===0){
-_30=delete _28[_29];
-_2a=undefined;
-if(this.referenceIntegrity&&_2d){
-var _31=_2d;
-if(!dojo.isArray(_31)){
-_31=[_31];
-}
-for(var i=0;i<_31.length;i++){
-var _32=_31[i];
-if(this.isItem(_32)){
-this._removeReferenceFromMap(_32,_28,_29);
-}
-}
-}
-}else{
-var _33;
-if(dojo.isArray(_2a)){
-var _34=_2a;
-_33=_2a.slice(0,_2a.length);
-}else{
-_33=[_2a];
-}
-if(this.referenceIntegrity){
-if(_2d){
-var _31=_2d;
-if(!dojo.isArray(_31)){
-_31=[_31];
-}
-var map={};
-dojo.forEach(_31,function(_35){
-if(this.isItem(_35)){
-var id=this.getIdentity(_35);
-map[id.toString()]=true;
-}
-},this);
-dojo.forEach(_33,function(_36){
-if(this.isItem(_36)){
-var id=this.getIdentity(_36);
-if(map[id.toString()]){
-delete map[id.toString()];
-}else{
-this._addReferenceToMap(_36,_28,_29);
-}
-}
-},this);
-for(var rId in map){
-var _37;
-if(this._itemsByIdentity){
-_37=this._itemsByIdentity[rId];
-}else{
-_37=this._arrayOfAllItems[rId];
-}
-this._removeReferenceFromMap(_37,_28,_29);
-}
-}else{
-for(var i=0;i<_33.length;i++){
-var _32=_33[i];
-if(this.isItem(_32)){
-this._addReferenceToMap(_32,_28,_29);
-}
-}
-}
-}
-_28[_29]=_33;
-_30=true;
-}
-if(_2b){
-this.onSet(_28,_29,_2d,_2a);
-}
-return _30;
-},_addReferenceToMap:function(_38,_39,_3a){
-var _3b=this.getIdentity(_39);
-var _3c=_38[this._reverseRefMap];
-if(!_3c){
-_3c=_38[this._reverseRefMap]={};
-}
-var _3d=_3c[_3b];
-if(!_3d){
-_3d=_3c[_3b]={};
-}
-_3d[_3a]=true;
-},_removeReferenceFromMap:function(_3e,_3f,_40){
-var _41=this.getIdentity(_3f);
-var _42=_3e[this._reverseRefMap];
-var _43;
-if(_42){
-for(_43 in _42){
-if(_43==_41){
-delete _42[_43][_40];
-if(this._isEmpty(_42[_43])){
-delete _42[_43];
-}
-}
-}
-if(this._isEmpty(_42)){
-delete _3e[this._reverseRefMap];
-}
-}
-},_dumpReferenceMap:function(){
-var i;
-for(i=0;i<this._arrayOfAllItems.length;i++){
-var _44=this._arrayOfAllItems[i];
-if(_44&&_44[this._reverseRefMap]){
-}
-}
-},_getValueOrValues:function(_45,_46){
-var _47=undefined;
-if(this.hasAttribute(_45,_46)){
-var _48=this.getValues(_45,_46);
-if(_48.length==1){
-_47=_48[0];
-}else{
-_47=_48;
-}
-}
-return _47;
-},_flatten:function(_49){
-if(this.isItem(_49)){
-var _4a=_49;
-var _4b=this.getIdentity(_4a);
-var _4c={_reference:_4b};
-return _4c;
-}else{
-if(typeof _49==="object"){
-for(var _4d in this._datatypeMap){
-var _4e=this._datatypeMap[_4d];
-if(dojo.isObject(_4e)&&!dojo.isFunction(_4e)){
-if(_49 instanceof _4e.type){
-if(!_4e.serialize){
-throw new Error("ItemFileWriteStore: No serializer defined for type mapping: ["+_4d+"]");
-}
-return {_type:_4d,_value:_4e.serialize(_49)};
-}
-}else{
-if(_49 instanceof _4e){
-return {_type:_4d,_value:_49.toString()};
-}
-}
-}
-}
-return _49;
-}
-},_getNewFileContentString:function(){
-var _4f={};
-var _50=this._getIdentifierAttribute();
-if(_50!==Number){
-_4f.identifier=_50;
-}
-if(this._labelAttr){
-_4f.label=this._labelAttr;
-}
-_4f.items=[];
-for(var i=0;i<this._arrayOfAllItems.length;++i){
-var _51=this._arrayOfAllItems[i];
-if(_51!==null){
-var _52={};
-for(var key in _51){
-if(key!==this._storeRefPropName&&key!==this._itemNumPropName&&key!==this._reverseRefMap&&key!==this._rootItemPropName){
-var _53=key;
-var _54=this.getValues(_51,_53);
-if(_54.length==1){
-_52[_53]=this._flatten(_54[0]);
-}else{
-var _55=[];
-for(var j=0;j<_54.length;++j){
-_55.push(this._flatten(_54[j]));
-_52[_53]=_55;
-}
-}
-}
-}
-_4f.items.push(_52);
-}
-}
-var _56=true;
-return dojo.toJson(_4f,_56);
-},_isEmpty:function(_57){
-var _58=true;
-if(dojo.isObject(_57)){
-var i;
-for(i in _57){
-_58=false;
-break;
-}
-}else{
-if(dojo.isArray(_57)){
-if(_57.length>0){
-_58=false;
-}
-}
-}
-return _58;
-},save:function(_59){
-this._assert(!this._saveInProgress);
-this._saveInProgress=true;
-var _5a=this;
-var _5b=function(){
-_5a._pending={_newItems:{},_modifiedItems:{},_deletedItems:{}};
-_5a._saveInProgress=false;
-if(_59&&_59.onComplete){
-var _5c=_59.scope||dojo.global;
-_59.onComplete.call(_5c);
-}
-};
-var _5d=function(err){
-_5a._saveInProgress=false;
-if(_59&&_59.onError){
-var _5e=_59.scope||dojo.global;
-_59.onError.call(_5e,err);
-}
-};
-if(this._saveEverything){
-var _5f=this._getNewFileContentString();
-this._saveEverything(_5b,_5d,_5f);
-}
-if(this._saveCustom){
-this._saveCustom(_5b,_5d);
-}
-if(!this._saveEverything&&!this._saveCustom){
-_5b();
-}
-},revert:function(){
-this._assert(!this._saveInProgress);
-var _60;
-for(_60 in this._pending._modifiedItems){
-var _61=this._pending._modifiedItems[_60];
-var _62=null;
-if(this._itemsByIdentity){
-_62=this._itemsByIdentity[_60];
-}else{
-_62=this._arrayOfAllItems[_60];
-}
-_61[this._storeRefPropName]=this;
-for(key in _62){
-delete _62[key];
-}
-dojo.mixin(_62,_61);
-}
-var _63;
-for(_60 in this._pending._deletedItems){
-_63=this._pending._deletedItems[_60];
-_63[this._storeRefPropName]=this;
-var _64=_63[this._itemNumPropName];
-if(_63["backup_"+this._reverseRefMap]){
-_63[this._reverseRefMap]=_63["backup_"+this._reverseRefMap];
-delete _63["backup_"+this._reverseRefMap];
-}
-this._arrayOfAllItems[_64]=_63;
-if(this._itemsByIdentity){
-this._itemsByIdentity[_60]=_63;
-}
-if(_63[this._rootItemPropName]){
-this._arrayOfTopLevelItems.push(_63);
-}
-}
-for(_60 in this._pending._deletedItems){
-_63=this._pending._deletedItems[_60];
-if(_63["backupRefs_"+this._reverseRefMap]){
-dojo.forEach(_63["backupRefs_"+this._reverseRefMap],function(_65){
-var _66;
-if(this._itemsByIdentity){
-_66=this._itemsByIdentity[_65.id];
-}else{
-_66=this._arrayOfAllItems[_65.id];
-}
-this._addReferenceToMap(_66,_63,_65.attr);
-},this);
-delete _63["backupRefs_"+this._reverseRefMap];
-}
-}
-for(_60 in this._pending._newItems){
-var _67=this._pending._newItems[_60];
-_67[this._storeRefPropName]=null;
-this._arrayOfAllItems[_67[this._itemNumPropName]]=null;
-if(_67[this._rootItemPropName]){
-this._removeArrayElement(this._arrayOfTopLevelItems,_67);
-}
-if(this._itemsByIdentity){
-delete this._itemsByIdentity[_60];
-}
-}
-this._pending={_newItems:{},_modifiedItems:{},_deletedItems:{}};
-return true;
-},isDirty:function(_68){
-if(_68){
-var _69=this.getIdentity(_68);
-return new Boolean(this._pending._newItems[_69]||this._pending._modifiedItems[_69]||this._pending._deletedItems[_69]).valueOf();
-}else{
-if(!this._isEmpty(this._pending._newItems)||!this._isEmpty(this._pending._modifiedItems)||!this._isEmpty(this._pending._deletedItems)){
-return true;
-}
-return false;
-}
-},onSet:function(_6a,_6b,_6c,_6d){
-},onNew:function(_6e,_6f){
-},onDelete:function(_70){
-},close:function(_71){
-if(this.clearOnClose){
-if(!this.isDirty()){
-this.inherited(arguments);
-}else{
-throw new Error("dojo.data.ItemFileWriteStore: There are unsaved changes present in the store. Please save or revert the changes before invoking close.");
-}
-}
-}});
+
+dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
+ constructor: function(/* object */ keywordParameters){
+ // keywordParameters: {typeMap: object)
+ // The structure of the typeMap object is as follows:
+ // {
+ // type0: function || object,
+ // type1: function || object,
+ // ...
+ // typeN: function || object
+ // }
+ // Where if it is a function, it is assumed to be an object constructor that takes the
+ // value of _value as the initialization parameters. It is serialized assuming object.toString()
+ // serialization. If it is an object, then it is assumed
+ // to be an object of general form:
+ // {
+ // type: function, //constructor.
+ // deserialize: function(value) //The function that parses the value and constructs the object defined by type appropriately.
+ // serialize: function(object) //The function that converts the object back into the proper file format form.
+ // }
+
+ // ItemFileWriteStore extends ItemFileReadStore to implement these additional dojo.data APIs
+ this._features['dojo.data.api.Write'] = true;
+ this._features['dojo.data.api.Notification'] = true;
+
+ // For keeping track of changes so that we can implement isDirty and revert
+ this._pending = {
+ _newItems:{},
+ _modifiedItems:{},
+ _deletedItems:{}
+ };
+
+ if(!this._datatypeMap['Date'].serialize){
+ this._datatypeMap['Date'].serialize = function(obj){
+ return dojo.date.stamp.toISOString(obj, {zulu:true});
+ };
+ }
+ //Disable only if explicitly set to false.
+ if(keywordParameters && (keywordParameters.referenceIntegrity === false)){
+ this.referenceIntegrity = false;
+ }
+
+ // this._saveInProgress is set to true, briefly, from when save() is first called to when it completes
+ this._saveInProgress = false;
+ },
+
+ referenceIntegrity: true, //Flag that defaultly enabled reference integrity tracking. This way it can also be disabled pogrammatially or declaratively.
+
+ _assert: function(/* boolean */ condition){
+ if(!condition){
+ throw new Error("assertion failed in ItemFileWriteStore");
+ }
+ },
+
+ _getIdentifierAttribute: function(){
+ var identifierAttribute = this.getFeatures()['dojo.data.api.Identity'];
+ // this._assert((identifierAttribute === Number) || (dojo.isString(identifierAttribute)));
+ return identifierAttribute;
+ },
+
+
+/* dojo.data.api.Write */
+
+ newItem: function(/* Object? */ keywordArgs, /* Object? */ parentInfo){
+ // summary: See dojo.data.api.Write.newItem()
+
+ this._assert(!this._saveInProgress);
+
+ if(!this._loadFinished){
+ // We need to do this here so that we'll be able to find out what
+ // identifierAttribute was specified in the data file.
+ this._forceLoad();
+ }
+
+ if(typeof keywordArgs != "object" && typeof keywordArgs != "undefined"){
+ throw new Error("newItem() was passed something other than an object");
+ }
+ var newIdentity = null;
+ var identifierAttribute = this._getIdentifierAttribute();
+ if(identifierAttribute === Number){
+ newIdentity = this._arrayOfAllItems.length;
+ }else{
+ newIdentity = keywordArgs[identifierAttribute];
+ if(typeof newIdentity === "undefined"){
+ throw new Error("newItem() was not passed an identity for the new item");
+ }
+ if(dojo.isArray(newIdentity)){
+ throw new Error("newItem() was not passed an single-valued identity");
+ }
+ }
+
+ // make sure this identity is not already in use by another item, if identifiers were
+ // defined in the file. Otherwise it would be the item count,
+ // which should always be unique in this case.
+ if(this._itemsByIdentity){
+ this._assert(typeof this._itemsByIdentity[newIdentity] === "undefined");
+ }
+ this._assert(typeof this._pending._newItems[newIdentity] === "undefined");
+ this._assert(typeof this._pending._deletedItems[newIdentity] === "undefined");
+
+ var newItem = {};
+ newItem[this._storeRefPropName] = this;
+ newItem[this._itemNumPropName] = this._arrayOfAllItems.length;
+ if(this._itemsByIdentity){
+ this._itemsByIdentity[newIdentity] = newItem;
+ //We have to set the identifier now, otherwise we can't look it
+ //up at calls to setValueorValues in parentInfo handling.
+ newItem[identifierAttribute] = [newIdentity];
+ }
+ this._arrayOfAllItems.push(newItem);
+
+ //We need to construct some data for the onNew call too...
+ var pInfo = null;
+
+ // Now we need to check to see where we want to assign this thingm if any.
+ if(parentInfo && parentInfo.parent && parentInfo.attribute){
+ pInfo = {
+ item: parentInfo.parent,
+ attribute: parentInfo.attribute,
+ oldValue: undefined
+ };
+
+ //See if it is multi-valued or not and handle appropriately
+ //Generally, all attributes are multi-valued for this store
+ //So, we only need to append if there are already values present.
+ var values = this.getValues(parentInfo.parent, parentInfo.attribute);
+ if(values && values.length > 0){
+ var tempValues = values.slice(0, values.length);
+ if(values.length === 1){
+ pInfo.oldValue = values[0];
+ }else{
+ pInfo.oldValue = values.slice(0, values.length);
+ }
+ tempValues.push(newItem);
+ this._setValueOrValues(parentInfo.parent, parentInfo.attribute, tempValues, false);
+ pInfo.newValue = this.getValues(parentInfo.parent, parentInfo.attribute);
+ }else{
+ this._setValueOrValues(parentInfo.parent, parentInfo.attribute, newItem, false);
+ pInfo.newValue = newItem;
+ }
+ }else{
+ //Toplevel item, add to both top list as well as all list.
+ newItem[this._rootItemPropName]=true;
+ this._arrayOfTopLevelItems.push(newItem);
+ }
+
+ this._pending._newItems[newIdentity] = newItem;
+
+ //Clone over the properties to the new item
+ for(var key in keywordArgs){
+ if(key === this._storeRefPropName || key === this._itemNumPropName){
+ // Bummer, the user is trying to do something like
+ // newItem({_S:"foo"}). Unfortunately, our superclass,
+ // ItemFileReadStore, is already using _S in each of our items
+ // to hold private info. To avoid a naming collision, we
+ // need to move all our private info to some other property
+ // of all the items/objects. So, we need to iterate over all
+ // the items and do something like:
+ // item.__S = item._S;
+ // item._S = undefined;
+ // But first we have to make sure the new "__S" variable is
+ // not in use, which means we have to iterate over all the
+ // items checking for that.
+ throw new Error("encountered bug in ItemFileWriteStore.newItem");
+ }
+ var value = keywordArgs[key];
+ if(!dojo.isArray(value)){
+ value = [value];
+ }
+ newItem[key] = value;
+ if(this.referenceIntegrity){
+ for(var i = 0; i < value.length; i++){
+ var val = value[i];
+ if(this.isItem(val)){
+ this._addReferenceToMap(val, newItem, key);
+ }
+ }
+ }
+ }
+ this.onNew(newItem, pInfo); // dojo.data.api.Notification call
+ return newItem; // item
+ },
+
+ _removeArrayElement: function(/* Array */ array, /* anything */ element){
+ var index = dojo.indexOf(array, element);
+ if(index != -1){
+ array.splice(index, 1);
+ return true;
+ }
+ return false;
+ },
+
+ deleteItem: function(/* item */ item){
+ // summary: See dojo.data.api.Write.deleteItem()
+ this._assert(!this._saveInProgress);
+ this._assertIsItem(item);
+
+ // Remove this item from the _arrayOfAllItems, but leave a null value in place
+ // of the item, so as not to change the length of the array, so that in newItem()
+ // we can still safely do: newIdentity = this._arrayOfAllItems.length;
+ var indexInArrayOfAllItems = item[this._itemNumPropName];
+ var identity = this.getIdentity(item);
+
+ //If we have reference integrity on, we need to do reference cleanup for the deleted item
+ if(this.referenceIntegrity){
+ //First scan all the attributes of this items for references and clean them up in the map
+ //As this item is going away, no need to track its references anymore.
+
+ //Get the attributes list before we generate the backup so it
+ //doesn't pollute the attributes list.
+ var attributes = this.getAttributes(item);
+
+ //Backup the map, we'll have to restore it potentially, in a revert.
+ if(item[this._reverseRefMap]){
+ item["backup_" + this._reverseRefMap] = dojo.clone(item[this._reverseRefMap]);
+ }
+
+ //TODO: This causes a reversion problem. This list won't be restored on revert since it is
+ //attached to the 'value'. item, not ours. Need to back tese up somehow too.
+ //Maybe build a map of the backup of the entries and attach it to the deleted item to be restored
+ //later. Or just record them and call _addReferenceToMap on them in revert.
+ dojo.forEach(attributes, function(attribute){
+ dojo.forEach(this.getValues(item, attribute), function(value){
+ if(this.isItem(value)){
+ //We have to back up all the references we had to others so they can be restored on a revert.
+ if(!item["backupRefs_" + this._reverseRefMap]){
+ item["backupRefs_" + this._reverseRefMap] = [];
+ }
+ item["backupRefs_" + this._reverseRefMap].push({id: this.getIdentity(value), attr: attribute});
+ this._removeReferenceFromMap(value, item, attribute);
+ }
+ }, this);
+ }, this);
+
+ //Next, see if we have references to this item, if we do, we have to clean them up too.
+ var references = item[this._reverseRefMap];
+ if(references){
+ //Look through all the items noted as references to clean them up.
+ for(var itemId in references){
+ var containingItem = null;
+ if(this._itemsByIdentity){
+ containingItem = this._itemsByIdentity[itemId];
+ }else{
+ containingItem = this._arrayOfAllItems[itemId];
+ }
+ //We have a reference to a containing item, now we have to process the
+ //attributes and clear all references to the item being deleted.
+ if(containingItem){
+ for(var attribute in references[itemId]){
+ var oldValues = this.getValues(containingItem, attribute) || [];
+ var newValues = dojo.filter(oldValues, function(possibleItem){
+ return !(this.isItem(possibleItem) && this.getIdentity(possibleItem) == identity);
+ }, this);
+ //Remove the note of the reference to the item and set the values on the modified attribute.
+ this._removeReferenceFromMap(item, containingItem, attribute);
+ if(newValues.length < oldValues.length){
+ this._setValueOrValues(containingItem, attribute, newValues, true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ this._arrayOfAllItems[indexInArrayOfAllItems] = null;
+
+ item[this._storeRefPropName] = null;
+ if(this._itemsByIdentity){
+ delete this._itemsByIdentity[identity];
+ }
+ this._pending._deletedItems[identity] = item;
+
+ //Remove from the toplevel items, if necessary...
+ if(item[this._rootItemPropName]){
+ this._removeArrayElement(this._arrayOfTopLevelItems, item);
+ }
+ this.onDelete(item); // dojo.data.api.Notification call
+ return true;
+ },
+
+ setValue: function(/* item */ item, /* attribute-name-string */ attribute, /* almost anything */ value){
+ // summary: See dojo.data.api.Write.set()
+ return this._setValueOrValues(item, attribute, value, true); // boolean
+ },
+
+ setValues: function(/* item */ item, /* attribute-name-string */ attribute, /* array */ values){
+ // summary: See dojo.data.api.Write.setValues()
+ return this._setValueOrValues(item, attribute, values, true); // boolean
+ },
+
+ unsetAttribute: function(/* item */ item, /* attribute-name-string */ attribute){
+ // summary: See dojo.data.api.Write.unsetAttribute()
+ return this._setValueOrValues(item, attribute, [], true);
+ },
+
+ _setValueOrValues: function(/* item */ item, /* attribute-name-string */ attribute, /* anything */ newValueOrValues, /*boolean?*/ callOnSet){
+ this._assert(!this._saveInProgress);
+
+ // Check for valid arguments
+ this._assertIsItem(item);
+ this._assert(dojo.isString(attribute));
+ this._assert(typeof newValueOrValues !== "undefined");
+
+ // Make sure the user isn't trying to change the item's identity
+ var identifierAttribute = this._getIdentifierAttribute();
+ if(attribute == identifierAttribute){
+ throw new Error("ItemFileWriteStore does not have support for changing the value of an item's identifier.");
+ }
+
+ // To implement the Notification API, we need to make a note of what
+ // the old attribute value was, so that we can pass that info when
+ // we call the onSet method.
+ var oldValueOrValues = this._getValueOrValues(item, attribute);
+
+ var identity = this.getIdentity(item);
+ if(!this._pending._modifiedItems[identity]){
+ // Before we actually change the item, we make a copy of it to
+ // record the original state, so that we'll be able to revert if
+ // the revert method gets called. If the item has already been
+ // modified then there's no need to do this now, since we already
+ // have a record of the original state.
+ var copyOfItemState = {};
+ for(var key in item){
+ if((key === this._storeRefPropName) || (key === this._itemNumPropName) || (key === this._rootItemPropName)){
+ copyOfItemState[key] = item[key];
+ }else if(key === this._reverseRefMap){
+ copyOfItemState[key] = dojo.clone(item[key]);
+ }else{
+ copyOfItemState[key] = item[key].slice(0, item[key].length);
+ }
+ }
+ // Now mark the item as dirty, and save the copy of the original state
+ this._pending._modifiedItems[identity] = copyOfItemState;
+ }
+
+ // Okay, now we can actually change this attribute on the item
+ var success = false;
+
+ if(dojo.isArray(newValueOrValues) && newValueOrValues.length === 0){
+
+ // If we were passed an empty array as the value, that counts
+ // as "unsetting" the attribute, so we need to remove this
+ // attribute from the item.
+ success = delete item[attribute];
+ newValueOrValues = undefined; // used in the onSet Notification call below
+
+ if(this.referenceIntegrity && oldValueOrValues){
+ var oldValues = oldValueOrValues;
+ if(!dojo.isArray(oldValues)){
+ oldValues = [oldValues];
+ }
+ for(var i = 0; i < oldValues.length; i++){
+ var value = oldValues[i];
+ if(this.isItem(value)){
+ this._removeReferenceFromMap(value, item, attribute);
+ }
+ }
+ }
+ }else{
+ var newValueArray;
+ if(dojo.isArray(newValueOrValues)){
+ var newValues = newValueOrValues;
+ // Unfortunately, it's not safe to just do this:
+ // newValueArray = newValues;
+ // Instead, we need to copy the array, which slice() does very nicely.
+ // This is so that our internal data structure won't
+ // get corrupted if the user mucks with the values array *after*
+ // calling setValues().
+ newValueArray = newValueOrValues.slice(0, newValueOrValues.length);
+ }else{
+ newValueArray = [newValueOrValues];
+ }
+
+ //We need to handle reference integrity if this is on.
+ //In the case of set, we need to see if references were added or removed
+ //and update the reference tracking map accordingly.
+ if(this.referenceIntegrity){
+ if(oldValueOrValues){
+ var oldValues = oldValueOrValues;
+ if(!dojo.isArray(oldValues)){
+ oldValues = [oldValues];
+ }
+ //Use an associative map to determine what was added/removed from the list.
+ //Should be O(n) performant. First look at all the old values and make a list of them
+ //Then for any item not in the old list, we add it. If it was already present, we remove it.
+ //Then we pass over the map and any references left it it need to be removed (IE, no match in
+ //the new values list).
+ var map = {};
+ dojo.forEach(oldValues, function(possibleItem){
+ if(this.isItem(possibleItem)){
+ var id = this.getIdentity(possibleItem);
+ map[id.toString()] = true;
+ }
+ }, this);
+ dojo.forEach(newValueArray, function(possibleItem){
+ if(this.isItem(possibleItem)){
+ var id = this.getIdentity(possibleItem);
+ if(map[id.toString()]){
+ delete map[id.toString()];
+ }else{
+ this._addReferenceToMap(possibleItem, item, attribute);
+ }
+ }
+ }, this);
+ for(var rId in map){
+ var removedItem;
+ if(this._itemsByIdentity){
+ removedItem = this._itemsByIdentity[rId];
+ }else{
+ removedItem = this._arrayOfAllItems[rId];
+ }
+ this._removeReferenceFromMap(removedItem, item, attribute);
+ }
+ }else{
+ //Everything is new (no old values) so we have to just
+ //insert all the references, if any.
+ for(var i = 0; i < newValueArray.length; i++){
+ var value = newValueArray[i];
+ if(this.isItem(value)){
+ this._addReferenceToMap(value, item, attribute);
+ }
+ }
+ }
+ }
+ item[attribute] = newValueArray;
+ success = true;
+ }
+
+ // Now we make the dojo.data.api.Notification call
+ if(callOnSet){
+ this.onSet(item, attribute, oldValueOrValues, newValueOrValues);
+ }
+ return success; // boolean
+ },
+
+ _addReferenceToMap: function(/*item*/ refItem, /*item*/ parentItem, /*string*/ attribute){
+ // summary:
+ // Method to add an reference map entry for an item and attribute.
+ // description:
+ // Method to add an reference map entry for an item and attribute. //
+ // refItem:
+ // The item that is referenced.
+ // parentItem:
+ // The item that holds the new reference to refItem.
+ // attribute:
+ // The attribute on parentItem that contains the new reference.
+
+ var parentId = this.getIdentity(parentItem);
+ var references = refItem[this._reverseRefMap];
+
+ if(!references){
+ references = refItem[this._reverseRefMap] = {};
+ }
+ var itemRef = references[parentId];
+ if(!itemRef){
+ itemRef = references[parentId] = {};
+ }
+ itemRef[attribute] = true;
+ },
+
+ _removeReferenceFromMap: function(/* item */ refItem, /* item */ parentItem, /*strin*/ attribute){
+ // summary:
+ // Method to remove an reference map entry for an item and attribute.
+ // description:
+ // Method to remove an reference map entry for an item and attribute. This will
+ // also perform cleanup on the map such that if there are no more references at all to
+ // the item, its reference object and entry are removed.
+ //
+ // refItem:
+ // The item that is referenced.
+ // parentItem:
+ // The item holding a reference to refItem.
+ // attribute:
+ // The attribute on parentItem that contains the reference.
+ var identity = this.getIdentity(parentItem);
+ var references = refItem[this._reverseRefMap];
+ var itemId;
+ if(references){
+ for(itemId in references){
+ if(itemId == identity){
+ delete references[itemId][attribute];
+ if(this._isEmpty(references[itemId])){
+ delete references[itemId];
+ }
+ }
+ }
+ if(this._isEmpty(references)){
+ delete refItem[this._reverseRefMap];
+ }
+ }
+ },
+
+ _dumpReferenceMap: function(){
+ // summary:
+ // Function to dump the reverse reference map of all items in the store for debug purposes.
+ // description:
+ // Function to dump the reverse reference map of all items in the store for debug purposes.
+ var i;
+ for(i = 0; i < this._arrayOfAllItems.length; i++){
+ var item = this._arrayOfAllItems[i];
+ if(item && item[this._reverseRefMap]){
+ console.log("Item: [" + this.getIdentity(item) + "] is referenced by: " + dojo.toJson(item[this._reverseRefMap]));
+ }
+ }
+ },
+
+ _getValueOrValues: function(/* item */ item, /* attribute-name-string */ attribute){
+ var valueOrValues = undefined;
+ if(this.hasAttribute(item, attribute)){
+ var valueArray = this.getValues(item, attribute);
+ if(valueArray.length == 1){
+ valueOrValues = valueArray[0];
+ }else{
+ valueOrValues = valueArray;
+ }
+ }
+ return valueOrValues;
+ },
+
+ _flatten: function(/* anything */ value){
+ if(this.isItem(value)){
+ var item = value;
+ // Given an item, return an serializable object that provides a
+ // reference to the item.
+ // For example, given kermit:
+ // var kermit = store.newItem({id:2, name:"Kermit"});
+ // we want to return
+ // {_reference:2}
+ var identity = this.getIdentity(item);
+ var referenceObject = {_reference: identity};
+ return referenceObject;
+ }else{
+ if(typeof value === "object"){
+ for(var type in this._datatypeMap){
+ var typeMap = this._datatypeMap[type];
+ if(dojo.isObject(typeMap) && !dojo.isFunction(typeMap)){
+ if(value instanceof typeMap.type){
+ if(!typeMap.serialize){
+ throw new Error("ItemFileWriteStore: No serializer defined for type mapping: [" + type + "]");
+ }
+ return {_type: type, _value: typeMap.serialize(value)};
+ }
+ } else if(value instanceof typeMap){
+ //SImple mapping, therefore, return as a toString serialization.
+ return {_type: type, _value: value.toString()};
+ }
+ }
+ }
+ return value;
+ }
+ },
+
+ _getNewFileContentString: function(){
+ // summary:
+ // Generate a string that can be saved to a file.
+ // The result should look similar to:
+ // http://trac.dojotoolkit.org/browser/dojo/trunk/tests/data/countries.json
+ var serializableStructure = {};
+
+ var identifierAttribute = this._getIdentifierAttribute();
+ if(identifierAttribute !== Number){
+ serializableStructure.identifier = identifierAttribute;
+ }
+ if(this._labelAttr){
+ serializableStructure.label = this._labelAttr;
+ }
+ serializableStructure.items = [];
+ for(var i = 0; i < this._arrayOfAllItems.length; ++i){
+ var item = this._arrayOfAllItems[i];
+ if(item !== null){
+ var serializableItem = {};
+ for(var key in item){
+ if(key !== this._storeRefPropName && key !== this._itemNumPropName && key !== this._reverseRefMap && key !== this._rootItemPropName){
+ var attribute = key;
+ var valueArray = this.getValues(item, attribute);
+ if(valueArray.length == 1){
+ serializableItem[attribute] = this._flatten(valueArray[0]);
+ }else{
+ var serializableArray = [];
+ for(var j = 0; j < valueArray.length; ++j){
+ serializableArray.push(this._flatten(valueArray[j]));
+ serializableItem[attribute] = serializableArray;
+ }
+ }
+ }
+ }
+ serializableStructure.items.push(serializableItem);
+ }
+ }
+ var prettyPrint = true;
+ return dojo.toJson(serializableStructure, prettyPrint);
+ },
+
+ _isEmpty: function(something){
+ // summary:
+ // Function to determine if an array or object has no properties or values.
+ // something:
+ // The array or object to examine.
+ var empty = true;
+ if(dojo.isObject(something)){
+ var i;
+ for(i in something){
+ empty = false;
+ break;
+ }
+ }else if(dojo.isArray(something)){
+ if(something.length > 0){
+ empty = false;
+ }
+ }
+ return empty; //boolean
+ },
+
+ save: function(/* object */ keywordArgs){
+ // summary: See dojo.data.api.Write.save()
+ this._assert(!this._saveInProgress);
+
+ // this._saveInProgress is set to true, briefly, from when save is first called to when it completes
+ this._saveInProgress = true;
+
+ var self = this;
+ var saveCompleteCallback = function(){
+ self._pending = {
+ _newItems:{},
+ _modifiedItems:{},
+ _deletedItems:{}
+ };
+
+ self._saveInProgress = false; // must come after this._pending is cleared, but before any callbacks
+ if(keywordArgs && keywordArgs.onComplete){
+ var scope = keywordArgs.scope || dojo.global;
+ keywordArgs.onComplete.call(scope);
+ }
+ };
+ var saveFailedCallback = function(err){
+ self._saveInProgress = false;
+ if(keywordArgs && keywordArgs.onError){
+ var scope = keywordArgs.scope || dojo.global;
+ keywordArgs.onError.call(scope, err);
+ }
+ };
+
+ if(this._saveEverything){
+ var newFileContentString = this._getNewFileContentString();
+ this._saveEverything(saveCompleteCallback, saveFailedCallback, newFileContentString);
+ }
+ if(this._saveCustom){
+ this._saveCustom(saveCompleteCallback, saveFailedCallback);
+ }
+ if(!this._saveEverything && !this._saveCustom){
+ // Looks like there is no user-defined save-handler function.
+ // That's fine, it just means the datastore is acting as a "mock-write"
+ // store -- changes get saved in memory but don't get saved to disk.
+ saveCompleteCallback();
+ }
+ },
+
+ revert: function(){
+ // summary: See dojo.data.api.Write.revert()
+ this._assert(!this._saveInProgress);
+
+ var identity;
+ for(identity in this._pending._modifiedItems){
+ // find the original item and the modified item that replaced it
+ var copyOfItemState = this._pending._modifiedItems[identity];
+ var modifiedItem = null;
+ if(this._itemsByIdentity){
+ modifiedItem = this._itemsByIdentity[identity];
+ }else{
+ modifiedItem = this._arrayOfAllItems[identity];
+ }
+
+ // Restore the original item into a full-fledged item again, we want to try to
+ // keep the same object instance as if we don't it, causes bugs like #9022.
+ copyOfItemState[this._storeRefPropName] = this;
+ for(key in modifiedItem){
+ delete modifiedItem[key];
+ }
+ dojo.mixin(modifiedItem, copyOfItemState);
+ }
+ var deletedItem;
+ for(identity in this._pending._deletedItems){
+ deletedItem = this._pending._deletedItems[identity];
+ deletedItem[this._storeRefPropName] = this;
+ var index = deletedItem[this._itemNumPropName];
+
+ //Restore the reverse refererence map, if any.
+ if(deletedItem["backup_" + this._reverseRefMap]){
+ deletedItem[this._reverseRefMap] = deletedItem["backup_" + this._reverseRefMap];
+ delete deletedItem["backup_" + this._reverseRefMap];
+ }
+ this._arrayOfAllItems[index] = deletedItem;
+ if(this._itemsByIdentity){
+ this._itemsByIdentity[identity] = deletedItem;
+ }
+ if(deletedItem[this._rootItemPropName]){
+ this._arrayOfTopLevelItems.push(deletedItem);
+ }
+ }
+ //We have to pass through it again and restore the reference maps after all the
+ //undeletes have occurred.
+ for(identity in this._pending._deletedItems){
+ deletedItem = this._pending._deletedItems[identity];
+ if(deletedItem["backupRefs_" + this._reverseRefMap]){
+ dojo.forEach(deletedItem["backupRefs_" + this._reverseRefMap], function(reference){
+ var refItem;
+ if(this._itemsByIdentity){
+ refItem = this._itemsByIdentity[reference.id];
+ }else{
+ refItem = this._arrayOfAllItems[reference.id];
+ }
+ this._addReferenceToMap(refItem, deletedItem, reference.attr);
+ }, this);
+ delete deletedItem["backupRefs_" + this._reverseRefMap];
+ }
+ }
+
+ for(identity in this._pending._newItems){
+ var newItem = this._pending._newItems[identity];
+ newItem[this._storeRefPropName] = null;
+ // null out the new item, but don't change the array index so
+ // so we can keep using _arrayOfAllItems.length.
+ this._arrayOfAllItems[newItem[this._itemNumPropName]] = null;
+ if(newItem[this._rootItemPropName]){
+ this._removeArrayElement(this._arrayOfTopLevelItems, newItem);
+ }
+ if(this._itemsByIdentity){
+ delete this._itemsByIdentity[identity];
+ }
+ }
+
+ this._pending = {
+ _newItems:{},
+ _modifiedItems:{},
+ _deletedItems:{}
+ };
+ return true; // boolean
+ },
+
+ isDirty: function(/* item? */ item){
+ // summary: See dojo.data.api.Write.isDirty()
+ if(item){
+ // return true if the item is dirty
+ var identity = this.getIdentity(item);
+ return new Boolean(this._pending._newItems[identity] ||
+ this._pending._modifiedItems[identity] ||
+ this._pending._deletedItems[identity]).valueOf(); // boolean
+ }else{
+ // return true if the store is dirty -- which means return true
+ // if there are any new items, dirty items, or modified items
+ if(!this._isEmpty(this._pending._newItems) ||
+ !this._isEmpty(this._pending._modifiedItems) ||
+ !this._isEmpty(this._pending._deletedItems)){
+ return true;
+ }
+ return false; // boolean
+ }
+ },
+
+/* dojo.data.api.Notification */
+
+ onSet: function(/* item */ item,
+ /*attribute-name-string*/ attribute,
+ /*object | array*/ oldValue,
+ /*object | array*/ newValue){
+ // summary: See dojo.data.api.Notification.onSet()
+
+ // No need to do anything. This method is here just so that the
+ // client code can connect observers to it.
+ },
+
+ onNew: function(/* item */ newItem, /*object?*/ parentInfo){
+ // summary: See dojo.data.api.Notification.onNew()
+
+ // No need to do anything. This method is here just so that the
+ // client code can connect observers to it.
+ },
+
+ onDelete: function(/* item */ deletedItem){
+ // summary: See dojo.data.api.Notification.onDelete()
+
+ // No need to do anything. This method is here just so that the
+ // client code can connect observers to it.
+ },
+
+ close: function(/* object? */ request){
+ // summary:
+ // Over-ride of base close function of ItemFileReadStore to add in check for store state.
+ // description:
+ // Over-ride of base close function of ItemFileReadStore to add in check for store state.
+ // If the store is still dirty (unsaved changes), then an error will be thrown instead of
+ // clearing the internal state for reload from the url.
+
+ //Clear if not dirty ... or throw an error
+ if(this.clearOnClose){
+ if(!this.isDirty()){
+ this.inherited(arguments);
+ }else{
+ //Only throw an error if the store was dirty and we were loading from a url (cannot reload from url until state is saved).
+ throw new Error("dojo.data.ItemFileWriteStore: There are unsaved changes present in the store. Please save or revert the changes before invoking close.");
+ }
+ }
+ }
+});
+
}
diff --git a/lib/dojo/data/api/Identity.js b/lib/dojo/data/api/Identity.js
index a76dd481c..7a1caeb53 100644
--- a/lib/dojo/data/api/Identity.js
+++ b/lib/dojo/data/api/Identity.js
@@ -5,22 +5,110 @@
*/
-if(!dojo._hasResource["dojo.data.api.Identity"]){
-dojo._hasResource["dojo.data.api.Identity"]=true;
+if(!dojo._hasResource["dojo.data.api.Identity"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.api.Identity"] = true;
dojo.provide("dojo.data.api.Identity");
dojo.require("dojo.data.api.Read");
-dojo.declare("dojo.data.api.Identity",dojo.data.api.Read,{getFeatures:function(){
-return {"dojo.data.api.Read":true,"dojo.data.api.Identity":true};
-},getIdentity:function(_1){
-throw new Error("Unimplemented API: dojo.data.api.Identity.getIdentity");
-var _2=null;
-return _2;
-},getIdentityAttributes:function(_3){
-throw new Error("Unimplemented API: dojo.data.api.Identity.getIdentityAttributes");
-return null;
-},fetchItemByIdentity:function(_4){
-if(!this.isItemLoaded(_4.item)){
-throw new Error("Unimplemented API: dojo.data.api.Identity.fetchItemByIdentity");
-}
-}});
+
+dojo.declare("dojo.data.api.Identity", dojo.data.api.Read, {
+ // summary:
+ // This is an abstract API that data provider implementations conform to.
+ // This file defines methods signatures and intentionally leaves all the
+ // methods unimplemented.
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Identity': true
+ };
+ },
+
+ getIdentity: function(/* item */ item){
+ // summary:
+ // Returns a unique identifier for an item. The return value will be
+ // either a string or something that has a toString() method (such as,
+ // for example, a dojox.uuid.Uuid object).
+ // item:
+ // The item from the store from which to obtain its identifier.
+ // exceptions:
+ // Conforming implementations may throw an exception or return null if
+ // item is not an item.
+ // example:
+ // | var itemId = store.getIdentity(kermit);
+ // | assert(kermit === store.findByIdentity(store.getIdentity(kermit)));
+ throw new Error('Unimplemented API: dojo.data.api.Identity.getIdentity');
+ var itemIdentityString = null;
+ return itemIdentityString; // string
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // Returns an array of attribute names that are used to generate the identity.
+ // For most stores, this is a single attribute, but for some complex stores
+ // such as RDB backed stores that use compound (multi-attribute) identifiers
+ // it can be more than one. If the identity is not composed of attributes
+ // on the item, it will return null. This function is intended to identify
+ // the attributes that comprise the identity so that so that during a render
+ // of all attributes, the UI can hide the the identity information if it
+ // chooses.
+ // item:
+ // The item from the store from which to obtain the array of public attributes that
+ // compose the identifier, if any.
+ // example:
+ // | var itemId = store.getIdentity(kermit);
+ // | var identifiers = store.getIdentityAttributes(itemId);
+ // | assert(typeof identifiers === "array" || identifiers === null);
+ throw new Error('Unimplemented API: dojo.data.api.Identity.getIdentityAttributes');
+ return null; // string
+ },
+
+
+ fetchItemByIdentity: function(/* object */ keywordArgs){
+ // summary:
+ // Given the identity of an item, this method returns the item that has
+ // that identity through the onItem callback. Conforming implementations
+ // should return null if there is no item with the given identity.
+ // Implementations of fetchItemByIdentity() may sometimes return an item
+ // from a local cache and may sometimes fetch an item from a remote server,
+ //
+ // keywordArgs:
+ // An anonymous object that defines the item to locate and callbacks to invoke when the
+ // item has been located and load has completed. The format of the object is as follows:
+ // {
+ // identity: string|object,
+ // onItem: Function,
+ // onError: Function,
+ // scope: object
+ // }
+ // The *identity* parameter.
+ // The identity parameter is the identity of the item you wish to locate and load
+ // This attribute is required. It should be a string or an object that toString()
+ // can be called on.
+ //
+ // The *onItem* parameter.
+ // Function(item)
+ // The onItem parameter is the callback to invoke when the item has been loaded. It takes only one
+ // parameter, the item located, or null if none found.
+ //
+ // The *onError* parameter.
+ // Function(error)
+ // The onError parameter is the callback to invoke when the item load encountered an error. It takes only one
+ // parameter, the error object
+ //
+ // The *scope* parameter.
+ // If a scope object is provided, all of the callback functions (onItem,
+ // onError, etc) will be invoked in the context of the scope object.
+ // In the body of the callback function, the value of the "this"
+ // keyword will be the scope object. If no scope object is provided,
+ // the callback functions will be called in the context of dojo.global.
+ // For example, onItem.call(scope, item, request) vs.
+ // onItem.call(dojo.global, item, request)
+ if(!this.isItemLoaded(keywordArgs.item)){
+ throw new Error('Unimplemented API: dojo.data.api.Identity.fetchItemByIdentity');
+ }
+ }
+});
+
}
diff --git a/lib/dojo/data/api/Notification.js b/lib/dojo/data/api/Notification.js
index d1afacda7..b1abad797 100644
--- a/lib/dojo/data/api/Notification.js
+++ b/lib/dojo/data/api/Notification.js
@@ -5,17 +5,122 @@
*/
-if(!dojo._hasResource["dojo.data.api.Notification"]){
-dojo._hasResource["dojo.data.api.Notification"]=true;
+if(!dojo._hasResource["dojo.data.api.Notification"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.api.Notification"] = true;
dojo.provide("dojo.data.api.Notification");
dojo.require("dojo.data.api.Read");
-dojo.declare("dojo.data.api.Notification",dojo.data.api.Read,{getFeatures:function(){
-return {"dojo.data.api.Read":true,"dojo.data.api.Notification":true};
-},onSet:function(_1,_2,_3,_4){
-throw new Error("Unimplemented API: dojo.data.api.Notification.onSet");
-},onNew:function(_5,_6){
-throw new Error("Unimplemented API: dojo.data.api.Notification.onNew");
-},onDelete:function(_7){
-throw new Error("Unimplemented API: dojo.data.api.Notification.onDelete");
-}});
+
+dojo.declare("dojo.data.api.Notification", dojo.data.api.Read, {
+ // summary:
+ // This is an abstract API that data provider implementations conform to.
+ // This file defines functions signatures and intentionally leaves all the
+ // functions unimplemented.
+ //
+ // description:
+ // This API defines a set of APIs that all datastores that conform to the
+ // Notifications API must implement. In general, most stores will implement
+ // these APIs as no-op functions for users who wish to monitor them to be able
+ // to connect to then via dojo.connect(). For non-users of dojo.connect,
+ // they should be able to just replace the function on the store to obtain
+ // notifications. Both read-only and read-write stores may implement
+ // this feature. In the case of a read-only store, this feature makes sense if
+ // the store itself does internal polling to a back-end server and periodically updates
+ // its cache of items (deletes, adds, and updates).
+ //
+ // example:
+ //
+ // | function onSet(item, attribute, oldValue, newValue) {
+ // | //Do something with the information...
+ // | };
+ // | var store = new some.newStore();
+ // | dojo.connect(store, "onSet", onSet);
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Notification': true
+ };
+ },
+
+ onSet: function(/* item */ item,
+ /* attribute-name-string */ attribute,
+ /* object | array */ oldValue,
+ /* object | array */ newValue){
+ // summary:
+ // This function is called any time an item is modified via setValue, setValues, unsetAttribute, etc.
+ // description:
+ // This function is called any time an item is modified via setValue, setValues, unsetAttribute, etc.
+ // Its purpose is to provide a hook point for those who wish to monitor actions on items in the store
+ // in a simple manner. The general expected usage is to dojo.connect() to the store's
+ // implementation and be called after the store function is called.
+ //
+ // item:
+ // The item being modified.
+ // attribute:
+ // The attribute being changed represented as a string name.
+ // oldValue:
+ // The old value of the attribute. In the case of single value calls, such as setValue, unsetAttribute, etc,
+ // this value will be generally be an atomic value of some sort (string, int, etc, object). In the case of
+ // multi-valued attributes, it will be an array.
+ // newValue:
+ // The new value of the attribute. In the case of single value calls, such as setValue, this value will be
+ // generally be an atomic value of some sort (string, int, etc, object). In the case of multi-valued attributes,
+ // it will be an array. In the case of unsetAttribute, the new value will be 'undefined'.
+ //
+ // returns:
+ // Nothing.
+ throw new Error('Unimplemented API: dojo.data.api.Notification.onSet');
+ },
+
+ onNew: function(/* item */ newItem, /*object?*/ parentInfo){
+ // summary:
+ // This function is called any time a new item is created in the store.
+ // It is called immediately after the store newItem processing has completed.
+ // description:
+ // This function is called any time a new item is created in the store.
+ // It is called immediately after the store newItem processing has completed.
+ //
+ // newItem:
+ // The item created.
+ // parentInfo:
+ // An optional javascript object that is passed when the item created was placed in the store
+ // hierarchy as a value f another item's attribute, instead of a root level item. Note that if this
+ // function is invoked with a value for parentInfo, then onSet is not invoked stating the attribute of
+ // the parent item was modified. This is to avoid getting two notification events occurring when a new item
+ // with a parent is created. The structure passed in is as follows:
+ // {
+ // item: someItem, //The parent item
+ // attribute: "attribute-name-string", //The attribute the new item was assigned to.
+ // oldValue: something //Whatever was the previous value for the attribute.
+ // //If it is a single-value attribute only, then this value will be a single value.
+ // //If it was a multi-valued attribute, then this will be an array of all the values minues the new one.
+ // newValue: something //The new value of the attribute. In the case of single value calls, such as setValue, this value will be
+ // //generally be an atomic value of some sort (string, int, etc, object). In the case of multi-valued attributes,
+ // //it will be an array.
+ // }
+ //
+ // returns:
+ // Nothing.
+ throw new Error('Unimplemented API: dojo.data.api.Notification.onNew');
+ },
+
+ onDelete: function(/* item */ deletedItem){
+ // summary:
+ // This function is called any time an item is deleted from the store.
+ // It is called immediately after the store deleteItem processing has completed.
+ // description:
+ // This function is called any time an item is deleted from the store.
+ // It is called immediately after the store deleteItem processing has completed.
+ //
+ // deletedItem:
+ // The item deleted.
+ //
+ // returns:
+ // Nothing.
+ throw new Error('Unimplemented API: dojo.data.api.Notification.onDelete');
+ }
+});
+
}
diff --git a/lib/dojo/data/api/Read.js b/lib/dojo/data/api/Read.js
index e5e543e98..0a84aa5f9 100644
--- a/lib/dojo/data/api/Read.js
+++ b/lib/dojo/data/api/Read.js
@@ -5,51 +5,509 @@
*/
-if(!dojo._hasResource["dojo.data.api.Read"]){
-dojo._hasResource["dojo.data.api.Read"]=true;
+if(!dojo._hasResource["dojo.data.api.Read"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.api.Read"] = true;
dojo.provide("dojo.data.api.Read");
dojo.require("dojo.data.api.Request");
-dojo.declare("dojo.data.api.Read",null,{getValue:function(_1,_2,_3){
-var _4=null;
-throw new Error("Unimplemented API: dojo.data.api.Read.getValue");
-return _4;
-},getValues:function(_5,_6){
-var _7=[];
-throw new Error("Unimplemented API: dojo.data.api.Read.getValues");
-return _7;
-},getAttributes:function(_8){
-var _9=[];
-throw new Error("Unimplemented API: dojo.data.api.Read.getAttributes");
-return _9;
-},hasAttribute:function(_a,_b){
-throw new Error("Unimplemented API: dojo.data.api.Read.hasAttribute");
-return false;
-},containsValue:function(_c,_d,_e){
-throw new Error("Unimplemented API: dojo.data.api.Read.containsValue");
-return false;
-},isItem:function(_f){
-throw new Error("Unimplemented API: dojo.data.api.Read.isItem");
-return false;
-},isItemLoaded:function(_10){
-throw new Error("Unimplemented API: dojo.data.api.Read.isItemLoaded");
-return false;
-},loadItem:function(_11){
-if(!this.isItemLoaded(_11.item)){
-throw new Error("Unimplemented API: dojo.data.api.Read.loadItem");
-}
-},fetch:function(_12){
-var _13=null;
-throw new Error("Unimplemented API: dojo.data.api.Read.fetch");
-return _13;
-},getFeatures:function(){
-return {"dojo.data.api.Read":true};
-},close:function(_14){
-throw new Error("Unimplemented API: dojo.data.api.Read.close");
-},getLabel:function(_15){
-throw new Error("Unimplemented API: dojo.data.api.Read.getLabel");
-return undefined;
-},getLabelAttributes:function(_16){
-throw new Error("Unimplemented API: dojo.data.api.Read.getLabelAttributes");
-return null;
-}});
+
+dojo.declare("dojo.data.api.Read", null, {
+ // summary:
+ // This is an abstract API that data provider implementations conform to.
+ // This file defines methods signatures and intentionally leaves all the
+ // methods unimplemented. For more information on the dojo.data APIs,
+ // please visit: http://www.dojotoolkit.org/node/98
+
+ getValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* value? */ defaultValue){
+ // summary:
+ // Returns a single attribute value.
+ // Returns defaultValue if and only if *item* does not have a value for *attribute*.
+ // Returns null if and only if null was explicitly set as the attribute value.
+ // Returns undefined if and only if the item does not have a value for the
+ // given attribute (which is the same as saying the item does not have the attribute).
+ // description:
+ // Saying that an "item x does not have a value for an attribute y"
+ // is identical to saying that an "item x does not have attribute y".
+ // It is an oxymoron to say "that attribute is present but has no values"
+ // or "the item has that attribute but does not have any attribute values".
+ // If store.hasAttribute(item, attribute) returns false, then
+ // store.getValue(item, attribute) will return undefined.
+ //
+ // item:
+ // The item to access values on.
+ // attribute:
+ // The attribute to access represented as a string.
+ // defaultValue:
+ // Optional. A default value to use for the getValue return in the attribute does not exist or has no value.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or *attribute* is not a string
+ // example:
+ // | var darthVader = store.getValue(lukeSkywalker, "father");
+ var attributeValue = null;
+ throw new Error('Unimplemented API: dojo.data.api.Read.getValue');
+ return attributeValue; // a literal, an item, null, or undefined (never an array)
+ },
+
+ getValues: function(/* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // This getValues() method works just like the getValue() method, but getValues()
+ // always returns an array rather than a single attribute value. The array
+ // may be empty, may contain a single attribute value, or may contain
+ // many attribute values.
+ // If the item does not have a value for the given attribute, then getValues()
+ // will return an empty array: []. (So, if store.hasAttribute(item, attribute)
+ // has a return of false, then store.getValues(item, attribute) will return [].)
+ //
+ // item:
+ // The item to access values on.
+ // attribute:
+ // The attribute to access represented as a string.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or *attribute* is not a string
+ // example:
+ // | var friendsOfLuke = store.getValues(lukeSkywalker, "friends");
+ var array = [];
+ throw new Error('Unimplemented API: dojo.data.api.Read.getValues');
+ return array; // an array that may contain literals and items
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // Returns an array with all the attributes that this item has. This
+ // method will always return an array; if the item has no attributes
+ // at all, getAttributes() will return an empty array: [].
+ //
+ // item:
+ // The item to access attributes on.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or *attribute* is not a string
+ // example:
+ // | var array = store.getAttributes(kermit);
+ var array = [];
+ throw new Error('Unimplemented API: dojo.data.api.Read.getAttributes');
+ return array; // array
+ },
+
+ hasAttribute: function( /* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // Returns true if the given *item* has a value for the given *attribute*.
+ //
+ // item:
+ // The item to access attributes on.
+ // attribute:
+ // The attribute to access represented as a string.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or *attribute* is not a string
+ // example:
+ // | var trueOrFalse = store.hasAttribute(kermit, "color");
+ throw new Error('Unimplemented API: dojo.data.api.Read.hasAttribute');
+ return false; // boolean
+ },
+
+ containsValue: function(/* item */ item,
+ /* attribute-name-string */ attribute,
+ /* anything */ value){
+ // summary:
+ // Returns true if the given *value* is one of the values that getValues()
+ // would return.
+ //
+ // item:
+ // The item to access values on.
+ // attribute:
+ // The attribute to access represented as a string.
+ // value:
+ // The value to match as a value for the attribute.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or *attribute* is not a string
+ // example:
+ // | var trueOrFalse = store.containsValue(kermit, "color", "green");
+ throw new Error('Unimplemented API: dojo.data.api.Read.containsValue');
+ return false; // boolean
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // Returns true if *something* is an item and came from the store instance.
+ // Returns false if *something* is a literal, an item from another store instance,
+ // or is any object other than an item.
+ //
+ // something:
+ // Can be anything.
+ //
+ // example:
+ // | var yes = store.isItem(store.newItem());
+ // | var no = store.isItem("green");
+ throw new Error('Unimplemented API: dojo.data.api.Read.isItem');
+ return false; // boolean
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // Returns false if isItem(something) is false. Returns false if
+ // if isItem(something) is true but the the item is not yet loaded
+ // in local memory (for example, if the item has not yet been read
+ // from the server).
+ //
+ // something:
+ // Can be anything.
+ //
+ // example:
+ // | var yes = store.isItemLoaded(store.newItem());
+ // | var no = store.isItemLoaded("green");
+ throw new Error('Unimplemented API: dojo.data.api.Read.isItemLoaded');
+ return false; // boolean
+ },
+
+ loadItem: function(/* object */ keywordArgs){
+ // summary:
+ // Given an item, this method loads the item so that a subsequent call
+ // to store.isItemLoaded(item) will return true. If a call to
+ // isItemLoaded() returns true before loadItem() is even called,
+ // then loadItem() need not do any work at all and will not even invoke
+ // the callback handlers. So, before invoking this method, check that
+ // the item has not already been loaded.
+ // keywordArgs:
+ // An anonymous object that defines the item to load and callbacks to invoke when the
+ // load has completed. The format of the object is as follows:
+ // {
+ // item: object,
+ // onItem: Function,
+ // onError: Function,
+ // scope: object
+ // }
+ // The *item* parameter.
+ // The item parameter is an object that represents the item in question that should be
+ // contained by the store. This attribute is required.
+
+ // The *onItem* parameter.
+ // Function(item)
+ // The onItem parameter is the callback to invoke when the item has been loaded. It takes only one
+ // parameter, the fully loaded item.
+ //
+ // The *onError* parameter.
+ // Function(error)
+ // The onError parameter is the callback to invoke when the item load encountered an error. It takes only one
+ // parameter, the error object
+ //
+ // The *scope* parameter.
+ // If a scope object is provided, all of the callback functions (onItem,
+ // onError, etc) will be invoked in the context of the scope object.
+ // In the body of the callback function, the value of the "this"
+ // keyword will be the scope object. If no scope object is provided,
+ // the callback functions will be called in the context of dojo.global().
+ // For example, onItem.call(scope, item, request) vs.
+ // onItem.call(dojo.global(), item, request)
+ if(!this.isItemLoaded(keywordArgs.item)){
+ throw new Error('Unimplemented API: dojo.data.api.Read.loadItem');
+ }
+ },
+
+ fetch: function(/* Object */ keywordArgs){
+ // summary:
+ // Given a query and set of defined options, such as a start and count of items to return,
+ // this method executes the query and makes the results available as data items.
+ // The format and expectations of stores is that they operate in a generally asynchronous
+ // manner, therefore callbacks are always used to return items located by the fetch parameters.
+ //
+ // description:
+ // A Request object will always be returned and is returned immediately.
+ // The basic request is nothing more than the keyword args passed to fetch and
+ // an additional function attached, abort(). The returned request object may then be used
+ // to cancel a fetch. All data items returns are passed through the callbacks defined in the
+ // fetch parameters and are not present on the 'request' object.
+ //
+ // This does not mean that custom stores can not add methods and properties to the request object
+ // returned, only that the API does not require it. For more info about the Request API,
+ // see dojo.data.api.Request
+ //
+ // keywordArgs:
+ // The keywordArgs parameter may either be an instance of
+ // conforming to dojo.data.api.Request or may be a simple anonymous object
+ // that may contain any of the following:
+ // {
+ // query: query-object or query-string,
+ // queryOptions: object,
+ // onBegin: Function,
+ // onItem: Function,
+ // onComplete: Function,
+ // onError: Function,
+ // scope: object,
+ // start: int
+ // count: int
+ // sort: array
+ // }
+ // All implementations should accept keywordArgs objects with any of
+ // the 9 standard properties: query, onBegin, onItem, onComplete, onError
+ // scope, sort, start, and count. Some implementations may accept additional
+ // properties in the keywordArgs object as valid parameters, such as
+ // {includeOutliers:true}.
+ //
+ // The *query* parameter.
+ // The query may be optional in some data store implementations.
+ // The dojo.data.api.Read API does not specify the syntax or semantics
+ // of the query itself -- each different data store implementation
+ // may have its own notion of what a query should look like.
+ // However, as of dojo 0.9, 1.0, and 1.1, all the provided datastores in dojo.data
+ // and dojox.data support an object structure query, where the object is a set of
+ // name/value parameters such as { attrFoo: valueBar, attrFoo1: valueBar1}. Most of the
+ // dijit widgets, such as ComboBox assume this to be the case when working with a datastore
+ // when they dynamically update the query. Therefore, for maximum compatibility with dijit
+ // widgets the recommended query parameter is a key/value object. That does not mean that the
+ // the datastore may not take alternative query forms, such as a simple string, a Date, a number,
+ // or a mix of such. Ultimately, The dojo.data.api.Read API is agnostic about what the query
+ // format.
+ // Further note: In general for query objects that accept strings as attribute
+ // value matches, the store should also support basic filtering capability, such as *
+ // (match any character) and ? (match single character). An example query that is a query object
+ // would be like: { attrFoo: "value*"}. Which generally means match all items where they have
+ // an attribute named attrFoo, with a value that starts with 'value'.
+ //
+ // The *queryOptions* parameter
+ // The queryOptions parameter is an optional parameter used to specify optiosn that may modify
+ // the query in some fashion, such as doing a case insensitive search, or doing a deep search
+ // where all items in a hierarchical representation of data are scanned instead of just the root
+ // items. It currently defines two options that all datastores should attempt to honor if possible:
+ // {
+ // ignoreCase: boolean, //Whether or not the query should match case sensitively or not. Default behaviour is false.
+ // deep: boolean //Whether or not a fetch should do a deep search of items and all child
+ // //items instead of just root-level items in a datastore. Default is false.
+ // }
+ //
+ // The *onBegin* parameter.
+ // function(size, request);
+ // If an onBegin callback function is provided, the callback function
+ // will be called just once, before the first onItem callback is called.
+ // The onBegin callback function will be passed two arguments, the
+ // the total number of items identified and the Request object. If the total number is
+ // unknown, then size will be -1. Note that size is not necessarily the size of the
+ // collection of items returned from the query, as the request may have specified to return only a
+ // subset of the total set of items through the use of the start and count parameters.
+ //
+ // The *onItem* parameter.
+ // function(item, request);
+ // If an onItem callback function is provided, the callback function
+ // will be called as each item in the result is received. The callback
+ // function will be passed two arguments: the item itself, and the
+ // Request object.
+ //
+ // The *onComplete* parameter.
+ // function(items, request);
+ //
+ // If an onComplete callback function is provided, the callback function
+ // will be called just once, after the last onItem callback is called.
+ // Note that if the onItem callback is not present, then onComplete will be passed
+ // an array containing all items which matched the query and the request object.
+ // If the onItem callback is present, then onComplete is called as:
+ // onComplete(null, request).
+ //
+ // The *onError* parameter.
+ // function(errorData, request);
+ // If an onError callback function is provided, the callback function
+ // will be called if there is any sort of error while attempting to
+ // execute the query.
+ // The onError callback function will be passed two arguments:
+ // an Error object and the Request object.
+ //
+ // The *scope* parameter.
+ // If a scope object is provided, all of the callback functions (onItem,
+ // onComplete, onError, etc) will be invoked in the context of the scope
+ // object. In the body of the callback function, the value of the "this"
+ // keyword will be the scope object. If no scope object is provided,
+ // the callback functions will be called in the context of dojo.global().
+ // For example, onItem.call(scope, item, request) vs.
+ // onItem.call(dojo.global(), item, request)
+ //
+ // The *start* parameter.
+ // If a start parameter is specified, this is a indication to the datastore to
+ // only start returning items once the start number of items have been located and
+ // skipped. When this parameter is paired withh 'count', the store should be able
+ // to page across queries with millions of hits by only returning subsets of the
+ // hits for each query
+ //
+ // The *count* parameter.
+ // If a count parameter is specified, this is a indication to the datastore to
+ // only return up to that many items. This allows a fetch call that may have
+ // millions of item matches to be paired down to something reasonable.
+ //
+ // The *sort* parameter.
+ // If a sort parameter is specified, this is a indication to the datastore to
+ // sort the items in some manner before returning the items. The array is an array of
+ // javascript objects that must conform to the following format to be applied to the
+ // fetching of items:
+ // {
+ // attribute: attribute || attribute-name-string,
+ // descending: true|false; // Optional. Default is false.
+ // }
+ // Note that when comparing attributes, if an item contains no value for the attribute
+ // (undefined), then it the default ascending sort logic should push it to the bottom
+ // of the list. In the descending order case, it such items should appear at the top of the list.
+ //
+ // returns:
+ // The fetch() method will return a javascript object conforming to the API
+ // defined in dojo.data.api.Request. In general, it will be the keywordArgs
+ // object returned with the required functions in Request.js attached.
+ // Its general purpose is to provide a convenient way for a caller to abort an
+ // ongoing fetch.
+ //
+ // The Request object may also have additional properties when it is returned
+ // such as request.store property, which is a pointer to the datastore object that
+ // fetch() is a method of.
+ //
+ // exceptions:
+ // Throws an exception if the query is not valid, or if the query
+ // is required but was not supplied.
+ //
+ // example:
+ // Fetch all books identified by the query and call 'showBooks' when complete
+ // | var request = store.fetch({query:"all books", onComplete: showBooks});
+ // example:
+ // Fetch all items in the story and call 'showEverything' when complete.
+ // | var request = store.fetch(onComplete: showEverything);
+ // example:
+ // Fetch only 10 books that match the query 'all books', starting at the fifth book found during the search.
+ // This demonstrates how paging can be done for specific queries.
+ // | var request = store.fetch({query:"all books", start: 4, count: 10, onComplete: showBooks});
+ // example:
+ // Fetch all items that match the query, calling 'callback' each time an item is located.
+ // | var request = store.fetch({query:"foo/bar", onItem:callback});
+ // example:
+ // Fetch the first 100 books by author King, call showKing when up to 100 items have been located.
+ // | var request = store.fetch({query:{author:"King"}, start: 0, count:100, onComplete: showKing});
+ // example:
+ // Locate the books written by Author King, sort it on title and publisher, then return the first 100 items from the sorted items.
+ // | var request = store.fetch({query:{author:"King"}, sort: [{ attribute: "title", descending: true}, {attribute: "publisher"}], ,start: 0, count:100, onComplete: 'showKing'});
+ // example:
+ // Fetch the first 100 books by authors starting with the name King, then call showKing when up to 100 items have been located.
+ // | var request = store.fetch({query:{author:"King*"}, start: 0, count:100, onComplete: showKing});
+ // example:
+ // Fetch the first 100 books by authors ending with 'ing', but only have one character before it (King, Bing, Ling, Sing, etc.), then call showBooks when up to 100 items have been located.
+ // | var request = store.fetch({query:{author:"?ing"}, start: 0, count:100, onComplete: showBooks});
+ // example:
+ // Fetch the first 100 books by author King, where the name may appear as King, king, KING, kInG, and so on, then call showKing when up to 100 items have been located.
+ // | var request = store.fetch({query:{author:"King"}, queryOptions:(ignoreCase: true}, start: 0, count:100, onComplete: showKing});
+ // example:
+ // Paging
+ // | var store = new dojo.data.LargeRdbmsStore({url:"jdbc:odbc:foobar"});
+ // | var fetchArgs = {
+ // | query: {type:"employees", name:"Hillary *"}, // string matching
+ // | sort: [{attribute:"department", descending:true}],
+ // | start: 0,
+ // | count: 20,
+ // | scope: displayer,
+ // | onBegin: showThrobber,
+ // | onItem: displayItem,
+ // | onComplete: stopThrobber,
+ // | onError: handleFetchError,
+ // | };
+ // | store.fetch(fetchArgs);
+ // | ...
+ // and then when the user presses the "Next Page" button...
+ // | fetchArgs.start += 20;
+ // | store.fetch(fetchArgs); // get the next 20 items
+ var request = null;
+ throw new Error('Unimplemented API: dojo.data.api.Read.fetch');
+ return request; // an object conforming to the dojo.data.api.Request API
+ },
+
+ getFeatures: function(){
+ // summary:
+ // The getFeatures() method returns an simple keyword values object
+ // that specifies what interface features the datastore implements.
+ // A simple CsvStore may be read-only, and the only feature it
+ // implements will be the 'dojo.data.api.Read' interface, so the
+ // getFeatures() method will return an object like this one:
+ // {'dojo.data.api.Read': true}.
+ // A more sophisticated datastore might implement a variety of
+ // interface features, like 'dojo.data.api.Read', 'dojo.data.api.Write',
+ // 'dojo.data.api.Identity', and 'dojo.data.api.Attribution'.
+ return {
+ 'dojo.data.api.Read': true
+ };
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // The close() method is intended for instructing the store to 'close' out
+ // any information associated with a particular request.
+ //
+ // description:
+ // The close() method is intended for instructing the store to 'close' out
+ // any information associated with a particular request. In general, this API
+ // expects to recieve as a parameter a request object returned from a fetch.
+ // It will then close out anything associated with that request, such as
+ // clearing any internal datastore caches and closing any 'open' connections.
+ // For some store implementations, this call may be a no-op.
+ //
+ // request:
+ // An instance of a request for the store to use to identify what to close out.
+ // If no request is passed, then the store should clear all internal caches (if any)
+ // and close out all 'open' connections. It does not render the store unusable from
+ // there on, it merely cleans out any current data and resets the store to initial
+ // state.
+ //
+ // example:
+ // | var request = store.fetch({onComplete: doSomething});
+ // | ...
+ // | store.close(request);
+ throw new Error('Unimplemented API: dojo.data.api.Read.close');
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // Method to inspect the item and return a user-readable 'label' for the item
+ // that provides a general/adequate description of what the item is.
+ //
+ // description:
+ // Method to inspect the item and return a user-readable 'label' for the item
+ // that provides a general/adequate description of what the item is. In general
+ // most labels will be a specific attribute value or collection of the attribute
+ // values that combine to label the item in some manner. For example for an item
+ // that represents a person it may return the label as: "firstname lastlame" where
+ // the firstname and lastname are attributes on the item. If the store is unable
+ // to determine an adequate human readable label, it should return undefined. Users that wish
+ // to customize how a store instance labels items should replace the getLabel() function on
+ // their instance of the store, or extend the store and replace the function in
+ // the extension class.
+ //
+ // item:
+ // The item to return the label for.
+ //
+ // returns:
+ // A user-readable string representing the item or undefined if no user-readable label can
+ // be generated.
+ throw new Error('Unimplemented API: dojo.data.api.Read.getLabel');
+ return undefined;
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // Method to inspect the item and return an array of what attributes of the item were used
+ // to generate its label, if any.
+ //
+ // description:
+ // Method to inspect the item and return an array of what attributes of the item were used
+ // to generate its label, if any. This function is to assist UI developers in knowing what
+ // attributes can be ignored out of the attributes an item has when displaying it, in cases
+ // where the UI is using the label as an overall identifer should they wish to hide
+ // redundant information.
+ //
+ // item:
+ // The item to return the list of label attributes for.
+ //
+ // returns:
+ // An array of attribute names that were used to generate the label, or null if public attributes
+ // were not used to generate the label.
+ throw new Error('Unimplemented API: dojo.data.api.Read.getLabelAttributes');
+ return null;
+ }
+});
+
}
diff --git a/lib/dojo/data/api/Request.js b/lib/dojo/data/api/Request.js
index 2d8e0e044..d613c7b11 100644
--- a/lib/dojo/data/api/Request.js
+++ b/lib/dojo/data/api/Request.js
@@ -5,10 +5,35 @@
*/
-if(!dojo._hasResource["dojo.data.api.Request"]){
-dojo._hasResource["dojo.data.api.Request"]=true;
+if(!dojo._hasResource["dojo.data.api.Request"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.api.Request"] = true;
dojo.provide("dojo.data.api.Request");
-dojo.declare("dojo.data.api.Request",null,{abort:function(){
-throw new Error("Unimplemented API: dojo.data.api.Request.abort");
-}});
+
+dojo.declare("dojo.data.api.Request", null, {
+ // summary:
+ // This class defines out the semantics of what a 'Request' object looks like
+ // when returned from a fetch() method. In general, a request object is
+ // nothing more than the original keywordArgs from fetch with an abort function
+ // attached to it to allow users to abort a particular request if they so choose.
+ // No other functions are required on a general Request object return. That does not
+ // inhibit other store implementations from adding extentions to it, of course.
+ //
+ // This is an abstract API that data provider implementations conform to.
+ // This file defines methods signatures and intentionally leaves all the
+ // methods unimplemented.
+ //
+ // For more details on fetch, see dojo.data.api.Read.fetch().
+
+ abort: function(){
+ // summary:
+ // This function is a hook point for stores to provide as a way for
+ // a fetch to be halted mid-processing.
+ // description:
+ // This function is a hook point for stores to provide as a way for
+ // a fetch to be halted mid-processing. For more details on the fetch() api,
+ // please see dojo.data.api.Read.fetch().
+ throw new Error('Unimplemented API: dojo.data.api.Request.abort');
+ }
+});
+
}
diff --git a/lib/dojo/data/api/Write.js b/lib/dojo/data/api/Write.js
index cc9c3e4f4..3fd0b1af0 100644
--- a/lib/dojo/data/api/Write.js
+++ b/lib/dojo/data/api/Write.js
@@ -5,35 +5,229 @@
*/
-if(!dojo._hasResource["dojo.data.api.Write"]){
-dojo._hasResource["dojo.data.api.Write"]=true;
+if(!dojo._hasResource["dojo.data.api.Write"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.api.Write"] = true;
dojo.provide("dojo.data.api.Write");
dojo.require("dojo.data.api.Read");
-dojo.declare("dojo.data.api.Write",dojo.data.api.Read,{getFeatures:function(){
-return {"dojo.data.api.Read":true,"dojo.data.api.Write":true};
-},newItem:function(_1,_2){
-var _3;
-throw new Error("Unimplemented API: dojo.data.api.Write.newItem");
-return _3;
-},deleteItem:function(_4){
-throw new Error("Unimplemented API: dojo.data.api.Write.deleteItem");
-return false;
-},setValue:function(_5,_6,_7){
-throw new Error("Unimplemented API: dojo.data.api.Write.setValue");
-return false;
-},setValues:function(_8,_9,_a){
-throw new Error("Unimplemented API: dojo.data.api.Write.setValues");
-return false;
-},unsetAttribute:function(_b,_c){
-throw new Error("Unimplemented API: dojo.data.api.Write.clear");
-return false;
-},save:function(_d){
-throw new Error("Unimplemented API: dojo.data.api.Write.save");
-},revert:function(){
-throw new Error("Unimplemented API: dojo.data.api.Write.revert");
-return false;
-},isDirty:function(_e){
-throw new Error("Unimplemented API: dojo.data.api.Write.isDirty");
-return false;
-}});
+
+dojo.declare("dojo.data.api.Write", dojo.data.api.Read, {
+ // summary:
+ // This is an abstract API that data provider implementations conform to.
+ // This file defines function signatures and intentionally leaves all the
+ // functionss unimplemented.
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return {
+ 'dojo.data.api.Read': true,
+ 'dojo.data.api.Write': true
+ };
+ },
+
+ newItem: function(/* Object? */ keywordArgs, /*Object?*/ parentInfo){
+ // summary:
+ // Returns a newly created item. Sets the attributes of the new
+ // item based on the *keywordArgs* provided. In general, the attribute
+ // names in the keywords become the attributes in the new item and as for
+ // the attribute values in keywordArgs, they become the values of the attributes
+ // in the new item. In addition, for stores that support hierarchical item
+ // creation, an optional second parameter is accepted that defines what item is the parent
+ // of the new item and what attribute of that item should the new item be assigned to.
+ // In general, this will assume that the attribute targetted is multi-valued and a new item
+ // is appended onto the list of values for that attribute.
+ //
+ // keywordArgs:
+ // A javascript object defining the initial content of the item as a set of JavaScript 'property name: value' pairs.
+ // parentInfo:
+ // An optional javascript object defining what item is the parent of this item (in a hierarchical store. Not all stores do hierarchical items),
+ // and what attribute of that parent to assign the new item to. If this is present, and the attribute specified
+ // is a multi-valued attribute, it will append this item into the array of values for that attribute. The structure
+ // of the object is as follows:
+ // {
+ // parent: someItem,
+ // attribute: "attribute-name-string"
+ // }
+ //
+ // exceptions:
+ // Throws an exception if *keywordArgs* is a string or a number or
+ // anything other than a simple anonymous object.
+ // Throws an exception if the item in parentInfo is not an item from the store
+ // or if the attribute isn't an attribute name string.
+ // example:
+ // | var kermit = store.newItem({name: "Kermit", color:[blue, green]});
+
+ var newItem;
+ throw new Error('Unimplemented API: dojo.data.api.Write.newItem');
+ return newItem; // item
+ },
+
+ deleteItem: function(/* item */ item){
+ // summary:
+ // Deletes an item from the store.
+ //
+ // item:
+ // The item to delete.
+ //
+ // exceptions:
+ // Throws an exception if the argument *item* is not an item
+ // (if store.isItem(item) returns false).
+ // example:
+ // | var success = store.deleteItem(kermit);
+ throw new Error('Unimplemented API: dojo.data.api.Write.deleteItem');
+ return false; // boolean
+ },
+
+ setValue: function( /* item */ item,
+ /* string */ attribute,
+ /* almost anything */ value){
+ // summary:
+ // Sets the value of an attribute on an item.
+ // Replaces any previous value or values.
+ //
+ // item:
+ // The item to modify.
+ // attribute:
+ // The attribute of the item to change represented as a string name.
+ // value:
+ // The value to assign to the item.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or if *attribute*
+ // is neither an attribute object or a string.
+ // Throws an exception if *value* is undefined.
+ // example:
+ // | var success = store.set(kermit, "color", "green");
+ throw new Error('Unimplemented API: dojo.data.api.Write.setValue');
+ return false; // boolean
+ },
+
+ setValues: function(/* item */ item,
+ /* string */ attribute,
+ /* array */ values){
+ // summary:
+ // Adds each value in the *values* array as a value of the given
+ // attribute on the given item.
+ // Replaces any previous value or values.
+ // Calling store.setValues(x, y, []) (with *values* as an empty array) has
+ // the same effect as calling store.unsetAttribute(x, y).
+ //
+ // item:
+ // The item to modify.
+ // attribute:
+ // The attribute of the item to change represented as a string name.
+ // values:
+ // An array of values to assign to the attribute..
+ //
+ // exceptions:
+ // Throws an exception if *values* is not an array, if *item* is not an
+ // item, or if *attribute* is neither an attribute object or a string.
+ // example:
+ // | var success = store.setValues(kermit, "color", ["green", "aqua"]);
+ // | success = store.setValues(kermit, "color", []);
+ // | if (success) {assert(!store.hasAttribute(kermit, "color"));}
+ throw new Error('Unimplemented API: dojo.data.api.Write.setValues');
+ return false; // boolean
+ },
+
+ unsetAttribute: function( /* item */ item,
+ /* string */ attribute){
+ // summary:
+ // Deletes all the values of an attribute on an item.
+ //
+ // item:
+ // The item to modify.
+ // attribute:
+ // The attribute of the item to unset represented as a string.
+ //
+ // exceptions:
+ // Throws an exception if *item* is not an item, or if *attribute*
+ // is neither an attribute object or a string.
+ // example:
+ // | var success = store.unsetAttribute(kermit, "color");
+ // | if (success) {assert(!store.hasAttribute(kermit, "color"));}
+ throw new Error('Unimplemented API: dojo.data.api.Write.clear');
+ return false; // boolean
+ },
+
+ save: function(/* object */ keywordArgs){
+ // summary:
+ // Saves to the server all the changes that have been made locally.
+ // The save operation may take some time and is generally performed
+ // in an asynchronous fashion. The outcome of the save action is
+ // is passed into the set of supported callbacks for the save.
+ //
+ // keywordArgs:
+ // {
+ // onComplete: function
+ // onError: function
+ // scope: object
+ // }
+ //
+ // The *onComplete* parameter.
+ // function();
+ //
+ // If an onComplete callback function is provided, the callback function
+ // will be called just once, after the save has completed. No parameters
+ // are generally passed to the onComplete.
+ //
+ // The *onError* parameter.
+ // function(errorData);
+ //
+ // If an onError callback function is provided, the callback function
+ // will be called if there is any sort of error while attempting to
+ // execute the save. The onError function will be based one parameter, the
+ // error.
+ //
+ // The *scope* parameter.
+ // If a scope object is provided, all of the callback function (
+ // onComplete, onError, etc) will be invoked in the context of the scope
+ // object. In the body of the callback function, the value of the "this"
+ // keyword will be the scope object. If no scope object is provided,
+ // the callback functions will be called in the context of dojo.global.
+ // For example, onComplete.call(scope) vs.
+ // onComplete.call(dojo.global)
+ //
+ // returns:
+ // Nothing. Since the saves are generally asynchronous, there is
+ // no need to return anything. All results are passed via callbacks.
+ // example:
+ // | store.save({onComplete: onSave});
+ // | store.save({scope: fooObj, onComplete: onSave, onError: saveFailed});
+ throw new Error('Unimplemented API: dojo.data.api.Write.save');
+ },
+
+ revert: function(){
+ // summary:
+ // Discards any unsaved changes.
+ // description:
+ // Discards any unsaved changes.
+ //
+ // example:
+ // | var success = store.revert();
+ throw new Error('Unimplemented API: dojo.data.api.Write.revert');
+ return false; // boolean
+ },
+
+ isDirty: function(/* item? */ item){
+ // summary:
+ // Given an item, isDirty() returns true if the item has been modified
+ // since the last save(). If isDirty() is called with no *item* argument,
+ // then this function returns true if any item has been modified since
+ // the last save().
+ //
+ // item:
+ // The item to check.
+ //
+ // exceptions:
+ // Throws an exception if isDirty() is passed an argument and the
+ // argument is not an item.
+ // example:
+ // | var trueOrFalse = store.isDirty(kermit); // true if kermit is dirty
+ // | var trueOrFalse = store.isDirty(); // true if any item is dirty
+ throw new Error('Unimplemented API: dojo.data.api.Write.isDirty');
+ return false; // boolean
+ }
+});
+
}
diff --git a/lib/dojo/data/util/filter.js b/lib/dojo/data/util/filter.js
index dcdc050e6..d23e63ade 100644
--- a/lib/dojo/data/util/filter.js
+++ b/lib/dojo/data/util/filter.js
@@ -5,48 +5,72 @@
*/
-if(!dojo._hasResource["dojo.data.util.filter"]){
-dojo._hasResource["dojo.data.util.filter"]=true;
+if(!dojo._hasResource["dojo.data.util.filter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.util.filter"] = true;
dojo.provide("dojo.data.util.filter");
-dojo.data.util.filter.patternToRegExp=function(_1,_2){
-var _3="^";
-var c=null;
-for(var i=0;i<_1.length;i++){
-c=_1.charAt(i);
-switch(c){
-case "\\":
-_3+=c;
-i++;
-_3+=_1.charAt(i);
-break;
-case "*":
-_3+=".*";
-break;
-case "?":
-_3+=".";
-break;
-case "$":
-case "^":
-case "/":
-case "+":
-case ".":
-case "|":
-case "(":
-case ")":
-case "{":
-case "}":
-case "[":
-case "]":
-_3+="\\";
-default:
-_3+=c;
-}
-}
-_3+="$";
-if(_2){
-return new RegExp(_3,"mi");
-}else{
-return new RegExp(_3,"m");
-}
+
+dojo.data.util.filter.patternToRegExp = function(/*String*/pattern, /*boolean?*/ ignoreCase){
+ // summary:
+ // Helper function to convert a simple pattern to a regular expression for matching.
+ // description:
+ // Returns a regular expression object that conforms to the defined conversion rules.
+ // For example:
+ // ca* -> /^ca.*$/
+ // *ca* -> /^.*ca.*$/
+ // *c\*a* -> /^.*c\*a.*$/
+ // *c\*a?* -> /^.*c\*a..*$/
+ // and so on.
+ //
+ // pattern: string
+ // A simple matching pattern to convert that follows basic rules:
+ // * Means match anything, so ca* means match anything starting with ca
+ // ? Means match single character. So, b?b will match to bob and bab, and so on.
+ // \ is an escape character. So for example, \* means do not treat * as a match, but literal character *.
+ // To use a \ as a character in the string, it must be escaped. So in the pattern it should be
+ // represented by \\ to be treated as an ordinary \ character instead of an escape.
+ //
+ // ignoreCase:
+ // An optional flag to indicate if the pattern matching should be treated as case-sensitive or not when comparing
+ // By default, it is assumed case sensitive.
+
+ var rxp = "^";
+ var c = null;
+ for(var i = 0; i < pattern.length; i++){
+ c = pattern.charAt(i);
+ switch(c){
+ case '\\':
+ rxp += c;
+ i++;
+ rxp += pattern.charAt(i);
+ break;
+ case '*':
+ rxp += ".*"; break;
+ case '?':
+ rxp += "."; break;
+ case '$':
+ case '^':
+ case '/':
+ case '+':
+ case '.':
+ case '|':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ rxp += "\\"; //fallthrough
+ default:
+ rxp += c;
+ }
+ }
+ rxp += "$";
+ if(ignoreCase){
+ return new RegExp(rxp,"mi"); //RegExp
+ }else{
+ return new RegExp(rxp,"m"); //RegExp
+ }
+
};
+
}
diff --git a/lib/dojo/data/util/simpleFetch.js b/lib/dojo/data/util/simpleFetch.js
index b3cc365d1..0bfb19ec3 100644
--- a/lib/dojo/data/util/simpleFetch.js
+++ b/lib/dojo/data/util/simpleFetch.js
@@ -5,60 +5,93 @@
*/
-if(!dojo._hasResource["dojo.data.util.simpleFetch"]){
-dojo._hasResource["dojo.data.util.simpleFetch"]=true;
+if(!dojo._hasResource["dojo.data.util.simpleFetch"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.util.simpleFetch"] = true;
dojo.provide("dojo.data.util.simpleFetch");
dojo.require("dojo.data.util.sorter");
-dojo.data.util.simpleFetch.fetch=function(_1){
-_1=_1||{};
-if(!_1.store){
-_1.store=this;
-}
-var _2=this;
-var _3=function(_4,_5){
-if(_5.onError){
-var _6=_5.scope||dojo.global;
-_5.onError.call(_6,_4,_5);
-}
-};
-var _7=function(_8,_9){
-var _a=_9.abort||null;
-var _b=false;
-var _c=_9.start?_9.start:0;
-var _d=(_9.count&&(_9.count!==Infinity))?(_c+_9.count):_8.length;
-_9.abort=function(){
-_b=true;
-if(_a){
-_a.call(_9);
-}
-};
-var _e=_9.scope||dojo.global;
-if(!_9.store){
-_9.store=_2;
-}
-if(_9.onBegin){
-_9.onBegin.call(_e,_8.length,_9);
-}
-if(_9.sort){
-_8.sort(dojo.data.util.sorter.createSortFunction(_9.sort,_2));
-}
-if(_9.onItem){
-for(var i=_c;(i<_8.length)&&(i<_d);++i){
-var _f=_8[i];
-if(!_b){
-_9.onItem.call(_e,_f,_9);
-}
-}
-}
-if(_9.onComplete&&!_b){
-var _10=null;
-if(!_9.onItem){
-_10=_8.slice(_c,_d);
-}
-_9.onComplete.call(_e,_10,_9);
-}
-};
-this._fetchItems(_1,_7,_3);
-return _1;
+
+dojo.data.util.simpleFetch.fetch = function(/* Object? */ request){
+ // summary:
+ // The simpleFetch mixin is designed to serve as a set of function(s) that can
+ // be mixed into other datastore implementations to accelerate their development.
+ // The simpleFetch mixin should work well for any datastore that can respond to a _fetchItems()
+ // call by returning an array of all the found items that matched the query. The simpleFetch mixin
+ // is not designed to work for datastores that respond to a fetch() call by incrementally
+ // loading items, or sequentially loading partial batches of the result
+ // set. For datastores that mixin simpleFetch, simpleFetch
+ // implements a fetch method that automatically handles eight of the fetch()
+ // arguments -- onBegin, onItem, onComplete, onError, start, count, sort and scope
+ // The class mixing in simpleFetch should not implement fetch(),
+ // but should instead implement a _fetchItems() method. The _fetchItems()
+ // method takes three arguments, the keywordArgs object that was passed
+ // to fetch(), a callback function to be called when the result array is
+ // available, and an error callback to be called if something goes wrong.
+ // The _fetchItems() method should ignore any keywordArgs parameters for
+ // start, count, onBegin, onItem, onComplete, onError, sort, and scope.
+ // The _fetchItems() method needs to correctly handle any other keywordArgs
+ // parameters, including the query parameter and any optional parameters
+ // (such as includeChildren). The _fetchItems() method should create an array of
+ // result items and pass it to the fetchHandler along with the original request object
+ // -- or, the _fetchItems() method may, if it wants to, create an new request object
+ // with other specifics about the request that are specific to the datastore and pass
+ // that as the request object to the handler.
+ //
+ // For more information on this specific function, see dojo.data.api.Read.fetch()
+ request = request || {};
+ if(!request.store){
+ request.store = this;
+ }
+ var self = this;
+
+ var _errorHandler = function(errorData, requestObject){
+ if(requestObject.onError){
+ var scope = requestObject.scope || dojo.global;
+ requestObject.onError.call(scope, errorData, requestObject);
+ }
+ };
+
+ var _fetchHandler = function(items, requestObject){
+ var oldAbortFunction = requestObject.abort || null;
+ var aborted = false;
+
+ var startIndex = requestObject.start?requestObject.start:0;
+ var endIndex = (requestObject.count && (requestObject.count !== Infinity))?(startIndex + requestObject.count):items.length;
+
+ requestObject.abort = function(){
+ aborted = true;
+ if(oldAbortFunction){
+ oldAbortFunction.call(requestObject);
+ }
+ };
+
+ var scope = requestObject.scope || dojo.global;
+ if(!requestObject.store){
+ requestObject.store = self;
+ }
+ if(requestObject.onBegin){
+ requestObject.onBegin.call(scope, items.length, requestObject);
+ }
+ if(requestObject.sort){
+ items.sort(dojo.data.util.sorter.createSortFunction(requestObject.sort, self));
+ }
+ if(requestObject.onItem){
+ for(var i = startIndex; (i < items.length) && (i < endIndex); ++i){
+ var item = items[i];
+ if(!aborted){
+ requestObject.onItem.call(scope, item, requestObject);
+ }
+ }
+ }
+ if(requestObject.onComplete && !aborted){
+ var subset = null;
+ if(!requestObject.onItem){
+ subset = items.slice(startIndex, endIndex);
+ }
+ requestObject.onComplete.call(scope, subset, requestObject);
+ }
+ };
+ this._fetchItems(request, _fetchHandler, _errorHandler);
+ return request; // Object
};
+
}
diff --git a/lib/dojo/data/util/sorter.js b/lib/dojo/data/util/sorter.js
index ace781274..c0261c848 100644
--- a/lib/dojo/data/util/sorter.js
+++ b/lib/dojo/data/util/sorter.js
@@ -5,62 +5,98 @@
*/
-if(!dojo._hasResource["dojo.data.util.sorter"]){
-dojo._hasResource["dojo.data.util.sorter"]=true;
+if(!dojo._hasResource["dojo.data.util.sorter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.util.sorter"] = true;
dojo.provide("dojo.data.util.sorter");
-dojo.data.util.sorter.basicComparator=function(a,b){
-var r=-1;
-if(a===null){
-a=undefined;
-}
-if(b===null){
-b=undefined;
-}
-if(a==b){
-r=0;
-}else{
-if(a>b||a==null){
-r=1;
-}
-}
-return r;
-};
-dojo.data.util.sorter.createSortFunction=function(_1,_2){
-var _3=[];
-function _4(_5,_6,_7,s){
-return function(_8,_9){
-var a=s.getValue(_8,_5);
-var b=s.getValue(_9,_5);
-return _6*_7(a,b);
-};
-};
-var _a;
-var _b=_2.comparatorMap;
-var bc=dojo.data.util.sorter.basicComparator;
-for(var i=0;i<_1.length;i++){
-_a=_1[i];
-var _c=_a.attribute;
-if(_c){
-var _d=(_a.descending)?-1:1;
-var _e=bc;
-if(_b){
-if(typeof _c!=="string"&&("toString" in _c)){
-_c=_c.toString();
-}
-_e=_b[_c]||bc;
-}
-_3.push(_4(_c,_d,_e,_2));
-}
-}
-return function(_f,_10){
-var i=0;
-while(i<_3.length){
-var ret=_3[i++](_f,_10);
-if(ret!==0){
-return ret;
-}
-}
-return 0;
+
+dojo.data.util.sorter.basicComparator = function( /*anything*/ a,
+ /*anything*/ b){
+ // summary:
+ // Basic comparision function that compares if an item is greater or less than another item
+ // description:
+ // returns 1 if a > b, -1 if a < b, 0 if equal.
+ // 'null' values (null, undefined) are treated as larger values so that they're pushed to the end of the list.
+ // And compared to each other, null is equivalent to undefined.
+
+ //null is a problematic compare, so if null, we set to undefined.
+ //Makes the check logic simple, compact, and consistent
+ //And (null == undefined) === true, so the check later against null
+ //works for undefined and is less bytes.
+ var r = -1;
+ if(a === null){
+ a = undefined;
+ }
+ if(b === null){
+ b = undefined;
+ }
+ if(a == b){
+ r = 0;
+ }else if(a > b || a == null){
+ r = 1;
+ }
+ return r; //int {-1,0,1}
};
+
+dojo.data.util.sorter.createSortFunction = function( /* attributes array */sortSpec,
+ /*dojo.data.core.Read*/ store){
+ // summary:
+ // Helper function to generate the sorting function based off the list of sort attributes.
+ // description:
+ // The sort function creation will look for a property on the store called 'comparatorMap'. If it exists
+ // it will look in the mapping for comparisons function for the attributes. If one is found, it will
+ // use it instead of the basic comparator, which is typically used for strings, ints, booleans, and dates.
+ // Returns the sorting function for this particular list of attributes and sorting directions.
+ //
+ // sortSpec: array
+ // A JS object that array that defines out what attribute names to sort on and whether it should be descenting or asending.
+ // The objects should be formatted as follows:
+ // {
+ // attribute: "attributeName-string" || attribute,
+ // descending: true|false; // Default is false.
+ // }
+ // store: object
+ // The datastore object to look up item values from.
+ //
+ var sortFunctions=[];
+
+ function createSortFunction(attr, dir, comp, s){
+ //Passing in comp and s (comparator and store), makes this
+ //function much faster.
+ return function(itemA, itemB){
+ var a = s.getValue(itemA, attr);
+ var b = s.getValue(itemB, attr);
+ return dir * comp(a,b); //int
+ };
+ }
+ var sortAttribute;
+ var map = store.comparatorMap;
+ var bc = dojo.data.util.sorter.basicComparator;
+ for(var i = 0; i < sortSpec.length; i++){
+ sortAttribute = sortSpec[i];
+ var attr = sortAttribute.attribute;
+ if(attr){
+ var dir = (sortAttribute.descending) ? -1 : 1;
+ var comp = bc;
+ if(map){
+ if(typeof attr !== "string" && ("toString" in attr)){
+ attr = attr.toString();
+ }
+ comp = map[attr] || bc;
+ }
+ sortFunctions.push(createSortFunction(attr,
+ dir, comp, store));
+ }
+ }
+ return function(rowA, rowB){
+ var i=0;
+ while(i < sortFunctions.length){
+ var ret = sortFunctions[i++](rowA, rowB);
+ if(ret !== 0){
+ return ret;//int
+ }
+ }
+ return 0; //int
+ }; // Function
};
+
}
diff --git a/lib/dojo/date.js b/lib/dojo/date.js
index dc51853f3..d4fe218d3 100644
--- a/lib/dojo/date.js
+++ b/lib/dojo/date.js
@@ -5,209 +5,345 @@
*/
-if(!dojo._hasResource["dojo.date"]){
-dojo._hasResource["dojo.date"]=true;
+if(!dojo._hasResource["dojo.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.date"] = true;
dojo.provide("dojo.date");
-dojo.date.getDaysInMonth=function(_1){
-var _2=_1.getMonth();
-var _3=[31,28,31,30,31,30,31,31,30,31,30,31];
-if(_2==1&&dojo.date.isLeapYear(_1)){
-return 29;
-}
-return _3[_2];
-};
-dojo.date.isLeapYear=function(_4){
-var _5=_4.getFullYear();
-return !(_5%400)||(!(_5%4)&&!!(_5%100));
-};
-dojo.date.getTimezoneName=function(_6){
-var _7=_6.toString();
-var tz="";
-var _8;
-var _9=_7.indexOf("(");
-if(_9>-1){
-tz=_7.substring(++_9,_7.indexOf(")"));
-}else{
-var _a=/([A-Z\/]+) \d{4}$/;
-if((_8=_7.match(_a))){
-tz=_8[1];
-}else{
-_7=_6.toLocaleString();
-_a=/ ([A-Z\/]+)$/;
-if((_8=_7.match(_a))){
-tz=_8[1];
-}
-}
-}
-return (tz=="AM"||tz=="PM")?"":tz;
-};
-dojo.date.compare=function(_b,_c,_d){
-_b=new Date(+_b);
-_c=new Date(+(_c||new Date()));
-if(_d=="date"){
-_b.setHours(0,0,0,0);
-_c.setHours(0,0,0,0);
-}else{
-if(_d=="time"){
-_b.setFullYear(0,0,0);
-_c.setFullYear(0,0,0);
+
+/*=====
+dojo.date = {
+ // summary: Date manipulation utilities
}
+=====*/
+
+dojo.date.getDaysInMonth = function(/*Date*/dateObject){
+ // summary:
+ // Returns the number of days in the month used by dateObject
+ var month = dateObject.getMonth();
+ var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+ if(month == 1 && dojo.date.isLeapYear(dateObject)){ return 29; } // Number
+ return days[month]; // Number
}
-if(_b>_c){
-return 1;
+
+dojo.date.isLeapYear = function(/*Date*/dateObject){
+ // summary:
+ // Determines if the year of the dateObject is a leap year
+ // description:
+ // Leap years are years with an additional day YYYY-02-29, where the
+ // year number is a multiple of four with the following exception: If
+ // a year is a multiple of 100, then it is only a leap year if it is
+ // also a multiple of 400. For example, 1900 was not a leap year, but
+ // 2000 is one.
+
+ var year = dateObject.getFullYear();
+ return !(year%400) || (!(year%4) && !!(year%100)); // Boolean
}
-if(_b<_c){
-return -1;
+
+// FIXME: This is not localized
+dojo.date.getTimezoneName = function(/*Date*/dateObject){
+ // summary:
+ // Get the user's time zone as provided by the browser
+ // dateObject:
+ // Needed because the timezone may vary with time (daylight savings)
+ // description:
+ // Try to get time zone info from toString or toLocaleString method of
+ // the Date object -- UTC offset is not a time zone. See
+ // http://www.twinsun.com/tz/tz-link.htm Note: results may be
+ // inconsistent across browsers.
+
+ var str = dateObject.toString(); // Start looking in toString
+ var tz = ''; // The result -- return empty string if nothing found
+ var match;
+
+ // First look for something in parentheses -- fast lookup, no regex
+ var pos = str.indexOf('(');
+ if(pos > -1){
+ tz = str.substring(++pos, str.indexOf(')'));
+ }else{
+ // If at first you don't succeed ...
+ // If IE knows about the TZ, it appears before the year
+ // Capital letters or slash before a 4-digit year
+ // at the end of string
+ var pat = /([A-Z\/]+) \d{4}$/;
+ if((match = str.match(pat))){
+ tz = match[1];
+ }else{
+ // Some browsers (e.g. Safari) glue the TZ on the end
+ // of toLocaleString instead of putting it in toString
+ str = dateObject.toLocaleString();
+ // Capital letters or slash -- end of string,
+ // after space
+ pat = / ([A-Z\/]+)$/;
+ if((match = str.match(pat))){
+ tz = match[1];
+ }
+ }
+ }
+
+ // Make sure it doesn't somehow end up return AM or PM
+ return (tz == 'AM' || tz == 'PM') ? '' : tz; // String
}
-return 0;
+
+// Utility methods to do arithmetic calculations with Dates
+
+dojo.date.compare = function(/*Date*/date1, /*Date?*/date2, /*String?*/portion){
+ // summary:
+ // Compare two date objects by date, time, or both.
+ // description:
+ // Returns 0 if equal, positive if a > b, else negative.
+ // date1:
+ // Date object
+ // date2:
+ // Date object. If not specified, the current Date is used.
+ // portion:
+ // A string indicating the "date" or "time" portion of a Date object.
+ // Compares both "date" and "time" by default. One of the following:
+ // "date", "time", "datetime"
+
+ // Extra step required in copy for IE - see #3112
+ date1 = new Date(+date1);
+ date2 = new Date(+(date2 || new Date()));
+
+ if(portion == "date"){
+ // Ignore times and compare dates.
+ date1.setHours(0, 0, 0, 0);
+ date2.setHours(0, 0, 0, 0);
+ }else if(portion == "time"){
+ // Ignore dates and compare times.
+ date1.setFullYear(0, 0, 0);
+ date2.setFullYear(0, 0, 0);
+ }
+
+ if(date1 > date2){ return 1; } // int
+ if(date1 < date2){ return -1; } // int
+ return 0; // int
};
-dojo.date.add=function(_e,_f,_10){
-var sum=new Date(+_e);
-var _11=false;
-var _12="Date";
-switch(_f){
-case "day":
-break;
-case "weekday":
-var _13,_14;
-var mod=_10%5;
-if(!mod){
-_13=(_10>0)?5:-5;
-_14=(_10>0)?((_10-5)/5):((_10+5)/5);
-}else{
-_13=mod;
-_14=parseInt(_10/5);
-}
-var _15=_e.getDay();
-var adj=0;
-if(_15==6&&_10>0){
-adj=1;
-}else{
-if(_15==0&&_10<0){
-adj=-1;
-}
-}
-var _16=_15+_13;
-if(_16==0||_16==6){
-adj=(_10>0)?2:-2;
-}
-_10=(7*_14)+_13+adj;
-break;
-case "year":
-_12="FullYear";
-_11=true;
-break;
-case "week":
-_10*=7;
-break;
-case "quarter":
-_10*=3;
-case "month":
-_11=true;
-_12="Month";
-break;
-default:
-_12="UTC"+_f.charAt(0).toUpperCase()+_f.substring(1)+"s";
-}
-if(_12){
-sum["set"+_12](sum["get"+_12]()+_10);
-}
-if(_11&&(sum.getDate()<_e.getDate())){
-sum.setDate(0);
-}
-return sum;
+
+dojo.date.add = function(/*Date*/date, /*String*/interval, /*int*/amount){
+ // summary:
+ // Add to a Date in intervals of different size, from milliseconds to years
+ // date: Date
+ // Date object to start with
+ // interval:
+ // A string representing the interval. One of the following:
+ // "year", "month", "day", "hour", "minute", "second",
+ // "millisecond", "quarter", "week", "weekday"
+ // amount:
+ // How much to add to the date.
+
+ var sum = new Date(+date); // convert to Number before copying to accomodate IE (#3112)
+ var fixOvershoot = false;
+ var property = "Date";
+
+ switch(interval){
+ case "day":
+ break;
+ case "weekday":
+ //i18n FIXME: assumes Saturday/Sunday weekend, but this is not always true. see dojo.cldr.supplemental
+
+ // Divide the increment time span into weekspans plus leftover days
+ // e.g., 8 days is one 5-day weekspan / and two leftover days
+ // Can't have zero leftover days, so numbers divisible by 5 get
+ // a days value of 5, and the remaining days make up the number of weeks
+ var days, weeks;
+ var mod = amount % 5;
+ if(!mod){
+ days = (amount > 0) ? 5 : -5;
+ weeks = (amount > 0) ? ((amount-5)/5) : ((amount+5)/5);
+ }else{
+ days = mod;
+ weeks = parseInt(amount/5);
+ }
+ // Get weekday value for orig date param
+ var strt = date.getDay();
+ // Orig date is Sat / positive incrementer
+ // Jump over Sun
+ var adj = 0;
+ if(strt == 6 && amount > 0){
+ adj = 1;
+ }else if(strt == 0 && amount < 0){
+ // Orig date is Sun / negative incrementer
+ // Jump back over Sat
+ adj = -1;
+ }
+ // Get weekday val for the new date
+ var trgt = strt + days;
+ // New date is on Sat or Sun
+ if(trgt == 0 || trgt == 6){
+ adj = (amount > 0) ? 2 : -2;
+ }
+ // Increment by number of weeks plus leftover days plus
+ // weekend adjustments
+ amount = (7 * weeks) + days + adj;
+ break;
+ case "year":
+ property = "FullYear";
+ // Keep increment/decrement from 2/29 out of March
+ fixOvershoot = true;
+ break;
+ case "week":
+ amount *= 7;
+ break;
+ case "quarter":
+ // Naive quarter is just three months
+ amount *= 3;
+ // fallthrough...
+ case "month":
+ // Reset to last day of month if you overshoot
+ fixOvershoot = true;
+ property = "Month";
+ break;
+// case "hour":
+// case "minute":
+// case "second":
+// case "millisecond":
+ default:
+ property = "UTC"+interval.charAt(0).toUpperCase() + interval.substring(1) + "s";
+ }
+
+ if(property){
+ sum["set"+property](sum["get"+property]()+amount);
+ }
+
+ if(fixOvershoot && (sum.getDate() < date.getDate())){
+ sum.setDate(0);
+ }
+
+ return sum; // Date
};
-dojo.date.difference=function(_17,_18,_19){
-_18=_18||new Date();
-_19=_19||"day";
-var _1a=_18.getFullYear()-_17.getFullYear();
-var _1b=1;
-switch(_19){
-case "quarter":
-var m1=_17.getMonth();
-var m2=_18.getMonth();
-var q1=Math.floor(m1/3)+1;
-var q2=Math.floor(m2/3)+1;
-q2+=(_1a*4);
-_1b=q2-q1;
-break;
-case "weekday":
-var _1c=Math.round(dojo.date.difference(_17,_18,"day"));
-var _1d=parseInt(dojo.date.difference(_17,_18,"week"));
-var mod=_1c%7;
-if(mod==0){
-_1c=_1d*5;
-}else{
-var adj=0;
-var _1e=_17.getDay();
-var _1f=_18.getDay();
-_1d=parseInt(_1c/7);
-mod=_1c%7;
-var _20=new Date(_17);
-_20.setDate(_20.getDate()+(_1d*7));
-var _21=_20.getDay();
-if(_1c>0){
-switch(true){
-case _1e==6:
-adj=-1;
-break;
-case _1e==0:
-adj=0;
-break;
-case _1f==6:
-adj=-1;
-break;
-case _1f==0:
-adj=-2;
-break;
-case (_21+mod)>5:
-adj=-2;
-}
-}else{
-if(_1c<0){
-switch(true){
-case _1e==6:
-adj=0;
-break;
-case _1e==0:
-adj=1;
-break;
-case _1f==6:
-adj=2;
-break;
-case _1f==0:
-adj=1;
-break;
-case (_21+mod)<0:
-adj=2;
-}
-}
-}
-_1c+=adj;
-_1c-=(_1d*2);
-}
-_1b=_1c;
-break;
-case "year":
-_1b=_1a;
-break;
-case "month":
-_1b=(_18.getMonth()-_17.getMonth())+(_1a*12);
-break;
-case "week":
-_1b=parseInt(dojo.date.difference(_17,_18,"day")/7);
-break;
-case "day":
-_1b/=24;
-case "hour":
-_1b/=60;
-case "minute":
-_1b/=60;
-case "second":
-_1b/=1000;
-case "millisecond":
-_1b*=_18.getTime()-_17.getTime();
-}
-return Math.round(_1b);
+
+dojo.date.difference = function(/*Date*/date1, /*Date?*/date2, /*String?*/interval){
+ // summary:
+ // Get the difference in a specific unit of time (e.g., number of
+ // months, weeks, days, etc.) between two dates, rounded to the
+ // nearest integer.
+ // date1:
+ // Date object
+ // date2:
+ // Date object. If not specified, the current Date is used.
+ // interval:
+ // A string representing the interval. One of the following:
+ // "year", "month", "day", "hour", "minute", "second",
+ // "millisecond", "quarter", "week", "weekday"
+ // Defaults to "day".
+
+ date2 = date2 || new Date();
+ interval = interval || "day";
+ var yearDiff = date2.getFullYear() - date1.getFullYear();
+ var delta = 1; // Integer return value
+
+ switch(interval){
+ case "quarter":
+ var m1 = date1.getMonth();
+ var m2 = date2.getMonth();
+ // Figure out which quarter the months are in
+ var q1 = Math.floor(m1/3) + 1;
+ var q2 = Math.floor(m2/3) + 1;
+ // Add quarters for any year difference between the dates
+ q2 += (yearDiff * 4);
+ delta = q2 - q1;
+ break;
+ case "weekday":
+ var days = Math.round(dojo.date.difference(date1, date2, "day"));
+ var weeks = parseInt(dojo.date.difference(date1, date2, "week"));
+ var mod = days % 7;
+
+ // Even number of weeks
+ if(mod == 0){
+ days = weeks*5;
+ }else{
+ // Weeks plus spare change (< 7 days)
+ var adj = 0;
+ var aDay = date1.getDay();
+ var bDay = date2.getDay();
+
+ weeks = parseInt(days/7);
+ mod = days % 7;
+ // Mark the date advanced by the number of
+ // round weeks (may be zero)
+ var dtMark = new Date(date1);
+ dtMark.setDate(dtMark.getDate()+(weeks*7));
+ var dayMark = dtMark.getDay();
+
+ // Spare change days -- 6 or less
+ if(days > 0){
+ switch(true){
+ // Range starts on Sat
+ case aDay == 6:
+ adj = -1;
+ break;
+ // Range starts on Sun
+ case aDay == 0:
+ adj = 0;
+ break;
+ // Range ends on Sat
+ case bDay == 6:
+ adj = -1;
+ break;
+ // Range ends on Sun
+ case bDay == 0:
+ adj = -2;
+ break;
+ // Range contains weekend
+ case (dayMark + mod) > 5:
+ adj = -2;
+ }
+ }else if(days < 0){
+ switch(true){
+ // Range starts on Sat
+ case aDay == 6:
+ adj = 0;
+ break;
+ // Range starts on Sun
+ case aDay == 0:
+ adj = 1;
+ break;
+ // Range ends on Sat
+ case bDay == 6:
+ adj = 2;
+ break;
+ // Range ends on Sun
+ case bDay == 0:
+ adj = 1;
+ break;
+ // Range contains weekend
+ case (dayMark + mod) < 0:
+ adj = 2;
+ }
+ }
+ days += adj;
+ days -= (weeks*2);
+ }
+ delta = days;
+ break;
+ case "year":
+ delta = yearDiff;
+ break;
+ case "month":
+ delta = (date2.getMonth() - date1.getMonth()) + (yearDiff * 12);
+ break;
+ case "week":
+ // Truncate instead of rounding
+ // Don't use Math.floor -- value may be negative
+ delta = parseInt(dojo.date.difference(date1, date2, "day")/7);
+ break;
+ case "day":
+ delta /= 24;
+ // fallthrough
+ case "hour":
+ delta /= 60;
+ // fallthrough
+ case "minute":
+ delta /= 60;
+ // fallthrough
+ case "second":
+ delta /= 1000;
+ // fallthrough
+ case "millisecond":
+ delta *= date2.getTime() - date1.getTime();
+ }
+
+ // Round for fractional values and DST leaps
+ return Math.round(delta); // Number (integer)
};
+
}
diff --git a/lib/dojo/date/locale.js b/lib/dojo/date/locale.js
index 666468649..c66da2331 100644
--- a/lib/dojo/date/locale.js
+++ b/lib/dojo/date/locale.js
@@ -5,460 +5,670 @@
*/
-if(!dojo._hasResource["dojo.date.locale"]){
-dojo._hasResource["dojo.date.locale"]=true;
+if(!dojo._hasResource["dojo.date.locale"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.date.locale"] = true;
dojo.provide("dojo.date.locale");
+
+// Localization methods for Date. Honor local customs using locale-dependent dojo.cldr data.
+
dojo.require("dojo.date");
dojo.require("dojo.cldr.supplemental");
dojo.require("dojo.regexp");
dojo.require("dojo.string");
dojo.require("dojo.i18n");
-dojo.requireLocalization("dojo.cldr","gregorian",null,"ROOT,ar,ca,cs,da,de,el,en,en-au,en-ca,en-gb,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ru,sk,sl,sv,th,tr,zh,zh-tw");
+
+// Load the bundles containing localization information for
+// names and formats
+dojo.requireLocalization("dojo.cldr", "gregorian", null, "ROOT,ar,ca,cs,da,de,el,en,en-au,en-ca,en-gb,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ru,sk,sl,sv,th,tr,zh,zh-tw");
+
+//NOTE: Everything in this module assumes Gregorian calendars.
+// Other calendars will be implemented in separate modules.
+
(function(){
-function _1(_2,_3,_4,_5){
-return _5.replace(/([a-z])\1*/ig,function(_6){
-var s,_7,c=_6.charAt(0),l=_6.length,_8=["abbr","wide","narrow"];
-switch(c){
-case "G":
-s=_3[(l<4)?"eraAbbr":"eraNames"][_2.getFullYear()<0?0:1];
-break;
-case "y":
-s=_2.getFullYear();
-switch(l){
-case 1:
-break;
-case 2:
-if(!_4.fullYear){
-s=String(s);
-s=s.substr(s.length-2);
-break;
-}
-default:
-_7=true;
-}
-break;
-case "Q":
-case "q":
-s=Math.ceil((_2.getMonth()+1)/3);
-_7=true;
-break;
-case "M":
-var m=_2.getMonth();
-if(l<3){
-s=m+1;
-_7=true;
-}else{
-var _9=["months","format",_8[l-3]].join("-");
-s=_3[_9][m];
-}
-break;
-case "w":
-var _a=0;
-s=dojo.date.locale._getWeekOfYear(_2,_a);
-_7=true;
-break;
-case "d":
-s=_2.getDate();
-_7=true;
-break;
-case "D":
-s=dojo.date.locale._getDayOfYear(_2);
-_7=true;
-break;
-case "E":
-var d=_2.getDay();
-if(l<3){
-s=d+1;
-_7=true;
-}else{
-var _b=["days","format",_8[l-3]].join("-");
-s=_3[_b][d];
-}
-break;
-case "a":
-var _c=(_2.getHours()<12)?"am":"pm";
-s=_3["dayPeriods-format-wide-"+_c];
-break;
-case "h":
-case "H":
-case "K":
-case "k":
-var h=_2.getHours();
-switch(c){
-case "h":
-s=(h%12)||12;
-break;
-case "H":
-s=h;
-break;
-case "K":
-s=(h%12);
-break;
-case "k":
-s=h||24;
-break;
-}
-_7=true;
-break;
-case "m":
-s=_2.getMinutes();
-_7=true;
-break;
-case "s":
-s=_2.getSeconds();
-_7=true;
-break;
-case "S":
-s=Math.round(_2.getMilliseconds()*Math.pow(10,l-3));
-_7=true;
-break;
-case "v":
-case "z":
-s=dojo.date.locale._getZone(_2,true,_4);
-if(s){
-break;
-}
-l=4;
-case "Z":
-var _d=dojo.date.locale._getZone(_2,false,_4);
-var tz=[(_d<=0?"+":"-"),dojo.string.pad(Math.floor(Math.abs(_d)/60),2),dojo.string.pad(Math.abs(_d)%60,2)];
-if(l==4){
-tz.splice(0,0,"GMT");
-tz.splice(3,0,":");
-}
-s=tz.join("");
-break;
-default:
-throw new Error("dojo.date.locale.format: invalid pattern char: "+_5);
-}
-if(_7){
-s=dojo.string.pad(s,l);
-}
-return s;
-});
-};
-dojo.date.locale._getZone=function(_e,_f,_10){
-if(_f){
-return dojo.date.getTimezoneName(_e);
-}else{
-return _e.getTimezoneOffset();
-}
-};
-dojo.date.locale.format=function(_11,_12){
-_12=_12||{};
-var _13=dojo.i18n.normalizeLocale(_12.locale),_14=_12.formatLength||"short",_15=dojo.date.locale._getGregorianBundle(_13),str=[],_16=dojo.hitch(this,_1,_11,_15,_12);
-if(_12.selector=="year"){
-return _17(_15["dateFormatItem-yyyy"]||"yyyy",_16);
-}
-var _18;
-if(_12.selector!="date"){
-_18=_12.timePattern||_15["timeFormat-"+_14];
-if(_18){
-str.push(_17(_18,_16));
-}
-}
-if(_12.selector!="time"){
-_18=_12.datePattern||_15["dateFormat-"+_14];
-if(_18){
-str.push(_17(_18,_16));
-}
-}
-return str.length==1?str[0]:_15["dateTimeFormat-"+_14].replace(/\{(\d+)\}/g,function(_19,key){
-return str[key];
-});
-};
-dojo.date.locale.regexp=function(_1a){
-return dojo.date.locale._parseInfo(_1a).regexp;
+ // Format a pattern without literals
+ function formatPattern(dateObject, bundle, options, pattern){
+ return pattern.replace(/([a-z])\1*/ig, function(match){
+ var s, pad,
+ c = match.charAt(0),
+ l = match.length,
+ widthList = ["abbr", "wide", "narrow"];
+ switch(c){
+ case 'G':
+ s = bundle[(l < 4) ? "eraAbbr" : "eraNames"][dateObject.getFullYear() < 0 ? 0 : 1];
+ break;
+ case 'y':
+ s = dateObject.getFullYear();
+ switch(l){
+ case 1:
+ break;
+ case 2:
+ if(!options.fullYear){
+ s = String(s); s = s.substr(s.length - 2);
+ break;
+ }
+ // fallthrough
+ default:
+ pad = true;
+ }
+ break;
+ case 'Q':
+ case 'q':
+ s = Math.ceil((dateObject.getMonth()+1)/3);
+// switch(l){
+// case 1: case 2:
+ pad = true;
+// break;
+// case 3: case 4: // unimplemented
+// }
+ break;
+ case 'M':
+ var m = dateObject.getMonth();
+ if(l<3){
+ s = m+1; pad = true;
+ }else{
+ var propM = ["months", "format", widthList[l-3]].join("-");
+ s = bundle[propM][m];
+ }
+ break;
+ case 'w':
+ var firstDay = 0;
+ s = dojo.date.locale._getWeekOfYear(dateObject, firstDay); pad = true;
+ break;
+ case 'd':
+ s = dateObject.getDate(); pad = true;
+ break;
+ case 'D':
+ s = dojo.date.locale._getDayOfYear(dateObject); pad = true;
+ break;
+ case 'E':
+ var d = dateObject.getDay();
+ if(l<3){
+ s = d+1; pad = true;
+ }else{
+ var propD = ["days", "format", widthList[l-3]].join("-");
+ s = bundle[propD][d];
+ }
+ break;
+ case 'a':
+ var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm';
+ s = bundle['dayPeriods-format-wide-' + timePeriod];
+ break;
+ case 'h':
+ case 'H':
+ case 'K':
+ case 'k':
+ var h = dateObject.getHours();
+ // strange choices in the date format make it impossible to write this succinctly
+ switch (c){
+ case 'h': // 1-12
+ s = (h % 12) || 12;
+ break;
+ case 'H': // 0-23
+ s = h;
+ break;
+ case 'K': // 0-11
+ s = (h % 12);
+ break;
+ case 'k': // 1-24
+ s = h || 24;
+ break;
+ }
+ pad = true;
+ break;
+ case 'm':
+ s = dateObject.getMinutes(); pad = true;
+ break;
+ case 's':
+ s = dateObject.getSeconds(); pad = true;
+ break;
+ case 'S':
+ s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3)); pad = true;
+ break;
+ case 'v': // FIXME: don't know what this is. seems to be same as z?
+ case 'z':
+ // We only have one timezone to offer; the one from the browser
+ s = dojo.date.locale._getZone(dateObject, true, options);
+ if(s){break;}
+ l=4;
+ // fallthrough... use GMT if tz not available
+ case 'Z':
+ var offset = dojo.date.locale._getZone(dateObject, false, options);
+ var tz = [
+ (offset<=0 ? "+" : "-"),
+ dojo.string.pad(Math.floor(Math.abs(offset)/60), 2),
+ dojo.string.pad(Math.abs(offset)% 60, 2)
+ ];
+ if(l==4){
+ tz.splice(0, 0, "GMT");
+ tz.splice(3, 0, ":");
+ }
+ s = tz.join("");
+ break;
+// case 'Y': case 'u': case 'W': case 'F': case 'g': case 'A': case 'e':
+// console.log(match+" modifier unimplemented");
+ default:
+ throw new Error("dojo.date.locale.format: invalid pattern char: "+pattern);
+ }
+ if(pad){ s = dojo.string.pad(s, l); }
+ return s;
+ });
+ }
+
+/*=====
+ dojo.date.locale.__FormatOptions = function(){
+ // selector: String
+ // choice of 'time','date' (default: date and time)
+ // formatLength: String
+ // choice of long, short, medium or full (plus any custom additions). Defaults to 'short'
+ // datePattern:String
+ // override pattern with this string
+ // timePattern:String
+ // override pattern with this string
+ // am: String
+ // override strings for am in times
+ // pm: String
+ // override strings for pm in times
+ // locale: String
+ // override the locale used to determine formatting rules
+ // fullYear: Boolean
+ // (format only) use 4 digit years whenever 2 digit years are called for
+ // strict: Boolean
+ // (parse only) strict parsing, off by default
+ this.selector = selector;
+ this.formatLength = formatLength;
+ this.datePattern = datePattern;
+ this.timePattern = timePattern;
+ this.am = am;
+ this.pm = pm;
+ this.locale = locale;
+ this.fullYear = fullYear;
+ this.strict = strict;
+ }
+=====*/
+
+dojo.date.locale._getZone = function(/*Date*/dateObject, /*boolean*/getName, /*dojo.date.locale.__FormatOptions?*/options){
+ // summary:
+ // Returns the zone (or offset) for the given date and options. This
+ // is broken out into a separate function so that it can be overridden
+ // by timezone-aware code.
+ //
+ // dateObject:
+ // the date and/or time being formatted.
+ //
+ // getName:
+ // Whether to return the timezone string (if true), or the offset (if false)
+ //
+ // options:
+ // The options being used for formatting
+ if(getName){
+ return dojo.date.getTimezoneName(dateObject);
+ }else{
+ return dateObject.getTimezoneOffset();
+ }
};
-dojo.date.locale._parseInfo=function(_1b){
-_1b=_1b||{};
-var _1c=dojo.i18n.normalizeLocale(_1b.locale),_1d=dojo.date.locale._getGregorianBundle(_1c),_1e=_1b.formatLength||"short",_1f=_1b.datePattern||_1d["dateFormat-"+_1e],_20=_1b.timePattern||_1d["timeFormat-"+_1e],_21;
-if(_1b.selector=="date"){
-_21=_1f;
-}else{
-if(_1b.selector=="time"){
-_21=_20;
-}else{
-_21=_1d["dateTimeFormat-"+_1e].replace(/\{(\d+)\}/g,function(_22,key){
-return [_20,_1f][key];
-});
-}
-}
-var _23=[],re=_17(_21,dojo.hitch(this,_24,_23,_1d,_1b));
-return {regexp:re,tokens:_23,bundle:_1d};
+
+
+dojo.date.locale.format = function(/*Date*/dateObject, /*dojo.date.locale.__FormatOptions?*/options){
+ // summary:
+ // Format a Date object as a String, using locale-specific settings.
+ //
+ // description:
+ // Create a string from a Date object using a known localized pattern.
+ // By default, this method formats both date and time from dateObject.
+ // Formatting patterns are chosen appropriate to the locale. Different
+ // formatting lengths may be chosen, with "full" used by default.
+ // Custom patterns may be used or registered with translations using
+ // the dojo.date.locale.addCustomFormats method.
+ // Formatting patterns are implemented using [the syntax described at
+ // unicode.org](http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns)
+ //
+ // dateObject:
+ // the date and/or time to be formatted. If a time only is formatted,
+ // the values in the year, month, and day fields are irrelevant. The
+ // opposite is true when formatting only dates.
+
+ options = options || {};
+
+ var locale = dojo.i18n.normalizeLocale(options.locale),
+ formatLength = options.formatLength || 'short',
+ bundle = dojo.date.locale._getGregorianBundle(locale),
+ str = [],
+ sauce = dojo.hitch(this, formatPattern, dateObject, bundle, options);
+ if(options.selector == "year"){
+ return _processPattern(bundle["dateFormatItem-yyyy"] || "yyyy", sauce);
+ }
+ var pattern;
+ if(options.selector != "date"){
+ pattern = options.timePattern || bundle["timeFormat-"+formatLength];
+ if(pattern){str.push(_processPattern(pattern, sauce));}
+ }
+ if(options.selector != "time"){
+ pattern = options.datePattern || bundle["dateFormat-"+formatLength];
+ if(pattern){str.push(_processPattern(pattern, sauce));}
+ }
+
+ return str.length == 1 ? str[0] : bundle["dateTimeFormat-"+formatLength].replace(/\{(\d+)\}/g,
+ function(match, key){ return str[key]; }); // String
};
-dojo.date.locale.parse=function(_25,_26){
-var _27=dojo.date.locale._parseInfo(_26),_28=_27.tokens,_29=_27.bundle,re=new RegExp("^"+_27.regexp+"$",_27.strict?"":"i"),_2a=re.exec(_25);
-if(!_2a){
-return null;
-}
-var _2b=["abbr","wide","narrow"],_2c=[1970,0,1,0,0,0,0],_2d="",_2e=dojo.every(_2a,function(v,i){
-if(!i){
-return true;
-}
-var _2f=_28[i-1];
-var l=_2f.length;
-switch(_2f.charAt(0)){
-case "y":
-if(l!=2&&_26.strict){
-_2c[0]=v;
-}else{
-if(v<100){
-v=Number(v);
-var _30=""+new Date().getFullYear(),_31=_30.substring(0,2)*100,_32=Math.min(Number(_30.substring(2,4))+20,99),num=(v<_32)?_31+v:_31-100+v;
-_2c[0]=num;
-}else{
-if(_26.strict){
-return false;
-}
-_2c[0]=v;
-}
-}
-break;
-case "M":
-if(l>2){
-var _33=_29["months-format-"+_2b[l-3]].concat();
-if(!_26.strict){
-v=v.replace(".","").toLowerCase();
-_33=dojo.map(_33,function(s){
-return s.replace(".","").toLowerCase();
-});
-}
-v=dojo.indexOf(_33,v);
-if(v==-1){
-return false;
-}
-}else{
-v--;
-}
-_2c[1]=v;
-break;
-case "E":
-case "e":
-var _34=_29["days-format-"+_2b[l-3]].concat();
-if(!_26.strict){
-v=v.toLowerCase();
-_34=dojo.map(_34,function(d){
-return d.toLowerCase();
-});
-}
-v=dojo.indexOf(_34,v);
-if(v==-1){
-return false;
-}
-break;
-case "D":
-_2c[1]=0;
-case "d":
-_2c[2]=v;
-break;
-case "a":
-var am=_26.am||_29["dayPeriods-format-wide-am"],pm=_26.pm||_29["dayPeriods-format-wide-pm"];
-if(!_26.strict){
-var _35=/\./g;
-v=v.replace(_35,"").toLowerCase();
-am=am.replace(_35,"").toLowerCase();
-pm=pm.replace(_35,"").toLowerCase();
-}
-if(_26.strict&&v!=am&&v!=pm){
-return false;
-}
-_2d=(v==pm)?"p":(v==am)?"a":"";
-break;
-case "K":
-if(v==24){
-v=0;
-}
-case "h":
-case "H":
-case "k":
-if(v>23){
-return false;
-}
-_2c[3]=v;
-break;
-case "m":
-_2c[4]=v;
-break;
-case "s":
-_2c[5]=v;
-break;
-case "S":
-_2c[6]=v;
-}
-return true;
-});
-var _36=+_2c[3];
-if(_2d==="p"&&_36<12){
-_2c[3]=_36+12;
-}else{
-if(_2d==="a"&&_36==12){
-_2c[3]=0;
-}
-}
-var _37=new Date(_2c[0],_2c[1],_2c[2],_2c[3],_2c[4],_2c[5],_2c[6]);
-if(_26.strict){
-_37.setFullYear(_2c[0]);
-}
-var _38=_28.join(""),_39=_38.indexOf("d")!=-1,_3a=_38.indexOf("M")!=-1;
-if(!_2e||(_3a&&_37.getMonth()>_2c[1])||(_39&&_37.getDate()>_2c[2])){
-return null;
-}
-if((_3a&&_37.getMonth()<_2c[1])||(_39&&_37.getDate()<_2c[2])){
-_37=dojo.date.add(_37,"hour",1);
-}
-return _37;
+
+dojo.date.locale.regexp = function(/*dojo.date.locale.__FormatOptions?*/options){
+ // summary:
+ // Builds the regular needed to parse a localized date
+
+ return dojo.date.locale._parseInfo(options).regexp; // String
};
-function _17(_3b,_3c,_3d,_3e){
-var _3f=function(x){
-return x;
+
+dojo.date.locale._parseInfo = function(/*dojo.date.locale.__FormatOptions?*/options){
+ options = options || {};
+ var locale = dojo.i18n.normalizeLocale(options.locale),
+ bundle = dojo.date.locale._getGregorianBundle(locale),
+ formatLength = options.formatLength || 'short',
+ datePattern = options.datePattern || bundle["dateFormat-" + formatLength],
+ timePattern = options.timePattern || bundle["timeFormat-" + formatLength],
+ pattern;
+ if(options.selector == 'date'){
+ pattern = datePattern;
+ }else if(options.selector == 'time'){
+ pattern = timePattern;
+ }else{
+ pattern = bundle["dateTimeFormat-"+formatLength].replace(/\{(\d+)\}/g,
+ function(match, key){ return [timePattern, datePattern][key]; });
+ }
+
+ var tokens = [],
+ re = _processPattern(pattern, dojo.hitch(this, _buildDateTimeRE, tokens, bundle, options));
+ return {regexp: re, tokens: tokens, bundle: bundle};
};
-_3c=_3c||_3f;
-_3d=_3d||_3f;
-_3e=_3e||_3f;
-var _40=_3b.match(/(''|[^'])+/g),_41=_3b.charAt(0)=="'";
-dojo.forEach(_40,function(_42,i){
-if(!_42){
-_40[i]="";
-}else{
-_40[i]=(_41?_3d:_3c)(_42.replace(/''/g,"'"));
-_41=!_41;
-}
-});
-return _3e(_40.join(""));
+
+dojo.date.locale.parse = function(/*String*/value, /*dojo.date.locale.__FormatOptions?*/options){
+ // summary:
+ // Convert a properly formatted string to a primitive Date object,
+ // using locale-specific settings.
+ //
+ // description:
+ // Create a Date object from a string using a known localized pattern.
+ // By default, this method parses looking for both date and time in the string.
+ // Formatting patterns are chosen appropriate to the locale. Different
+ // formatting lengths may be chosen, with "full" used by default.
+ // Custom patterns may be used or registered with translations using
+ // the dojo.date.locale.addCustomFormats method.
+ //
+ // Formatting patterns are implemented using [the syntax described at
+ // unicode.org](http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns)
+ // When two digit years are used, a century is chosen according to a sliding
+ // window of 80 years before and 20 years after present year, for both `yy` and `yyyy` patterns.
+ // year < 100CE requires strict mode.
+ //
+ // value:
+ // A string representation of a date
+
+ var info = dojo.date.locale._parseInfo(options),
+ tokens = info.tokens, bundle = info.bundle,
+ re = new RegExp("^" + info.regexp + "$", info.strict ? "" : "i"),
+ match = re.exec(value);
+
+ if(!match){ return null; } // null
+
+ var widthList = ['abbr', 'wide', 'narrow'],
+ result = [1970,0,1,0,0,0,0], // will get converted to a Date at the end
+ amPm = "",
+ valid = dojo.every(match, function(v, i){
+ if(!i){return true;}
+ var token=tokens[i-1];
+ var l=token.length;
+ switch(token.charAt(0)){
+ case 'y':
+ if(l != 2 && options.strict){
+ //interpret year literally, so '5' would be 5 A.D.
+ result[0] = v;
+ }else{
+ if(v<100){
+ v = Number(v);
+ //choose century to apply, according to a sliding window
+ //of 80 years before and 20 years after present year
+ var year = '' + new Date().getFullYear(),
+ century = year.substring(0, 2) * 100,
+ cutoff = Math.min(Number(year.substring(2, 4)) + 20, 99),
+ num = (v < cutoff) ? century + v : century - 100 + v;
+ result[0] = num;
+ }else{
+ //we expected 2 digits and got more...
+ if(options.strict){
+ return false;
+ }
+ //interpret literally, so '150' would be 150 A.D.
+ //also tolerate '1950', if 'yyyy' input passed to 'yy' format
+ result[0] = v;
+ }
+ }
+ break;
+ case 'M':
+ if(l>2){
+ var months = bundle['months-format-' + widthList[l-3]].concat();
+ if(!options.strict){
+ //Tolerate abbreviating period in month part
+ //Case-insensitive comparison
+ v = v.replace(".","").toLowerCase();
+ months = dojo.map(months, function(s){ return s.replace(".","").toLowerCase(); } );
+ }
+ v = dojo.indexOf(months, v);
+ if(v == -1){
+// console.log("dojo.date.locale.parse: Could not parse month name: '" + v + "'.");
+ return false;
+ }
+ }else{
+ v--;
+ }
+ result[1] = v;
+ break;
+ case 'E':
+ case 'e':
+ var days = bundle['days-format-' + widthList[l-3]].concat();
+ if(!options.strict){
+ //Case-insensitive comparison
+ v = v.toLowerCase();
+ days = dojo.map(days, function(d){return d.toLowerCase();});
+ }
+ v = dojo.indexOf(days, v);
+ if(v == -1){
+// console.log("dojo.date.locale.parse: Could not parse weekday name: '" + v + "'.");
+ return false;
+ }
+
+ //TODO: not sure what to actually do with this input,
+ //in terms of setting something on the Date obj...?
+ //without more context, can't affect the actual date
+ //TODO: just validate?
+ break;
+ case 'D':
+ result[1] = 0;
+ // fallthrough...
+ case 'd':
+ result[2] = v;
+ break;
+ case 'a': //am/pm
+ var am = options.am || bundle['dayPeriods-format-wide-am'],
+ pm = options.pm || bundle['dayPeriods-format-wide-pm'];
+ if(!options.strict){
+ var period = /\./g;
+ v = v.replace(period,'').toLowerCase();
+ am = am.replace(period,'').toLowerCase();
+ pm = pm.replace(period,'').toLowerCase();
+ }
+ if(options.strict && v != am && v != pm){
+// console.log("dojo.date.locale.parse: Could not parse am/pm part.");
+ return false;
+ }
+
+ // we might not have seen the hours field yet, so store the state and apply hour change later
+ amPm = (v == pm) ? 'p' : (v == am) ? 'a' : '';
+ break;
+ case 'K': //hour (1-24)
+ if(v == 24){ v = 0; }
+ // fallthrough...
+ case 'h': //hour (1-12)
+ case 'H': //hour (0-23)
+ case 'k': //hour (0-11)
+ //TODO: strict bounds checking, padding
+ if(v > 23){
+// console.log("dojo.date.locale.parse: Illegal hours value");
+ return false;
+ }
+
+ //in the 12-hour case, adjusting for am/pm requires the 'a' part
+ //which could come before or after the hour, so we will adjust later
+ result[3] = v;
+ break;
+ case 'm': //minutes
+ result[4] = v;
+ break;
+ case 's': //seconds
+ result[5] = v;
+ break;
+ case 'S': //milliseconds
+ result[6] = v;
+// break;
+// case 'w':
+//TODO var firstDay = 0;
+// default:
+//TODO: throw?
+// console.log("dojo.date.locale.parse: unsupported pattern char=" + token.charAt(0));
+ }
+ return true;
+ });
+
+ var hours = +result[3];
+ if(amPm === 'p' && hours < 12){
+ result[3] = hours + 12; //e.g., 3pm -> 15
+ }else if(amPm === 'a' && hours == 12){
+ result[3] = 0; //12am -> 0
+ }
+
+ //TODO: implement a getWeekday() method in order to test
+ //validity of input strings containing 'EEE' or 'EEEE'...
+
+ var dateObject = new Date(result[0], result[1], result[2], result[3], result[4], result[5], result[6]); // Date
+ if(options.strict){
+ dateObject.setFullYear(result[0]);
+ }
+
+ // Check for overflow. The Date() constructor normalizes things like April 32nd...
+ //TODO: why isn't this done for times as well?
+ var allTokens = tokens.join(""),
+ dateToken = allTokens.indexOf('d') != -1,
+ monthToken = allTokens.indexOf('M') != -1;
+
+ if(!valid ||
+ (monthToken && dateObject.getMonth() > result[1]) ||
+ (dateToken && dateObject.getDate() > result[2])){
+ return null;
+ }
+
+ // Check for underflow, due to DST shifts. See #9366
+ // This assumes a 1 hour dst shift correction at midnight
+ // We could compare the timezone offset after the shift and add the difference instead.
+ if((monthToken && dateObject.getMonth() < result[1]) ||
+ (dateToken && dateObject.getDate() < result[2])){
+ dateObject = dojo.date.add(dateObject, "hour", 1);
+ }
+
+ return dateObject; // Date
};
-function _24(_43,_44,_45,_46){
-_46=dojo.regexp.escapeString(_46);
-if(!_45.strict){
-_46=_46.replace(" a"," ?a");
-}
-return _46.replace(/([a-z])\1*/ig,function(_47){
-var s,c=_47.charAt(0),l=_47.length,p2="",p3="";
-if(_45.strict){
-if(l>1){
-p2="0"+"{"+(l-1)+"}";
-}
-if(l>2){
-p3="0"+"{"+(l-2)+"}";
-}
-}else{
-p2="0?";
-p3="0{0,2}";
-}
-switch(c){
-case "y":
-s="\\d{2,4}";
-break;
-case "M":
-s=(l>2)?"\\S+?":p2+"[1-9]|1[0-2]";
-break;
-case "D":
-s=p2+"[1-9]|"+p3+"[1-9][0-9]|[12][0-9][0-9]|3[0-5][0-9]|36[0-6]";
-break;
-case "d":
-s="3[01]|[12]\\d|"+p2+"[1-9]";
-break;
-case "w":
-s=p2+"[1-9]|[1-4][0-9]|5[0-3]";
-break;
-case "E":
-s="\\S+";
-break;
-case "h":
-s=p2+"[1-9]|1[0-2]";
-break;
-case "k":
-s=p2+"\\d|1[01]";
-break;
-case "H":
-s=p2+"\\d|1\\d|2[0-3]";
-break;
-case "K":
-s=p2+"[1-9]|1\\d|2[0-4]";
-break;
-case "m":
-case "s":
-s="[0-5]\\d";
-break;
-case "S":
-s="\\d{"+l+"}";
-break;
-case "a":
-var am=_45.am||_44["dayPeriods-format-wide-am"],pm=_45.pm||_44["dayPeriods-format-wide-pm"];
-if(_45.strict){
-s=am+"|"+pm;
-}else{
-s=am+"|"+pm;
-if(am!=am.toLowerCase()){
-s+="|"+am.toLowerCase();
-}
-if(pm!=pm.toLowerCase()){
-s+="|"+pm.toLowerCase();
-}
-if(s.indexOf(".")!=-1){
-s+="|"+s.replace(/\./g,"");
-}
-}
-s=s.replace(/\./g,"\\.");
-break;
-default:
-s=".*";
+
+function _processPattern(pattern, applyPattern, applyLiteral, applyAll){
+ //summary: Process a pattern with literals in it
+
+ // Break up on single quotes, treat every other one as a literal, except '' which becomes '
+ var identity = function(x){return x;};
+ applyPattern = applyPattern || identity;
+ applyLiteral = applyLiteral || identity;
+ applyAll = applyAll || identity;
+
+ //split on single quotes (which escape literals in date format strings)
+ //but preserve escaped single quotes (e.g., o''clock)
+ var chunks = pattern.match(/(''|[^'])+/g),
+ literal = pattern.charAt(0) == "'";
+
+ dojo.forEach(chunks, function(chunk, i){
+ if(!chunk){
+ chunks[i]='';
+ }else{
+ chunks[i]=(literal ? applyLiteral : applyPattern)(chunk.replace(/''/g, "'"));
+ literal = !literal;
+ }
+ });
+ return applyAll(chunks.join(''));
}
-if(_43){
-_43.push(_47);
+
+function _buildDateTimeRE(tokens, bundle, options, pattern){
+ pattern = dojo.regexp.escapeString(pattern);
+ if(!options.strict){ pattern = pattern.replace(" a", " ?a"); } // kludge to tolerate no space before am/pm
+ return pattern.replace(/([a-z])\1*/ig, function(match){
+ // Build a simple regexp. Avoid captures, which would ruin the tokens list
+ var s,
+ c = match.charAt(0),
+ l = match.length,
+ p2 = '', p3 = '';
+ if(options.strict){
+ if(l > 1){ p2 = '0' + '{'+(l-1)+'}'; }
+ if(l > 2){ p3 = '0' + '{'+(l-2)+'}'; }
+ }else{
+ p2 = '0?'; p3 = '0{0,2}';
+ }
+ switch(c){
+ case 'y':
+ s = '\\d{2,4}';
+ break;
+ case 'M':
+ s = (l>2) ? '\\S+?' : p2+'[1-9]|1[0-2]';
+ break;
+ case 'D':
+ s = p2+'[1-9]|'+p3+'[1-9][0-9]|[12][0-9][0-9]|3[0-5][0-9]|36[0-6]';
+ break;
+ case 'd':
+ s = '3[01]|[12]\\d|'+p2+'[1-9]';
+ break;
+ case 'w':
+ s = p2+'[1-9]|[1-4][0-9]|5[0-3]';
+ break;
+ case 'E':
+ s = '\\S+';
+ break;
+ case 'h': //hour (1-12)
+ s = p2+'[1-9]|1[0-2]';
+ break;
+ case 'k': //hour (0-11)
+ s = p2+'\\d|1[01]';
+ break;
+ case 'H': //hour (0-23)
+ s = p2+'\\d|1\\d|2[0-3]';
+ break;
+ case 'K': //hour (1-24)
+ s = p2+'[1-9]|1\\d|2[0-4]';
+ break;
+ case 'm':
+ case 's':
+ s = '[0-5]\\d';
+ break;
+ case 'S':
+ s = '\\d{'+l+'}';
+ break;
+ case 'a':
+ var am = options.am || bundle['dayPeriods-format-wide-am'],
+ pm = options.pm || bundle['dayPeriods-format-wide-pm'];
+ if(options.strict){
+ s = am + '|' + pm;
+ }else{
+ s = am + '|' + pm;
+ if(am != am.toLowerCase()){ s += '|' + am.toLowerCase(); }
+ if(pm != pm.toLowerCase()){ s += '|' + pm.toLowerCase(); }
+ if(s.indexOf('.') != -1){ s += '|' + s.replace(/\./g, ""); }
+ }
+ s = s.replace(/\./g, "\\.");
+ break;
+ default:
+ // case 'v':
+ // case 'z':
+ // case 'Z':
+ s = ".*";
+// console.log("parse of date format, pattern=" + pattern);
+ }
+
+ if(tokens){ tokens.push(match); }
+
+ return "(" + s + ")"; // add capture
+ }).replace(/[\xa0 ]/g, "[\\s\\xa0]"); // normalize whitespace. Need explicit handling of \xa0 for IE.
}
-return "("+s+")";
-}).replace(/[\xa0 ]/g,"[\\s\\xa0]");
-};
})();
+
(function(){
-var _48=[];
-dojo.date.locale.addCustomFormats=function(_49,_4a){
-_48.push({pkg:_49,name:_4a});
+var _customFormats = [];
+dojo.date.locale.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){
+ // summary:
+ // Add a reference to a bundle containing localized custom formats to be
+ // used by date/time formatting and parsing routines.
+ //
+ // description:
+ // The user may add custom localized formats where the bundle has properties following the
+ // same naming convention used by dojo.cldr: `dateFormat-xxxx` / `timeFormat-xxxx`
+ // The pattern string should match the format used by the CLDR.
+ // See dojo.date.locale.format() for details.
+ // The resources must be loaded by dojo.requireLocalization() prior to use
+
+ _customFormats.push({pkg:packageName,name:bundleName});
};
-dojo.date.locale._getGregorianBundle=function(_4b){
-var _4c={};
-dojo.forEach(_48,function(_4d){
-var _4e=dojo.i18n.getLocalization(_4d.pkg,_4d.name,_4b);
-_4c=dojo.mixin(_4c,_4e);
-},this);
-return _4c;
+
+dojo.date.locale._getGregorianBundle = function(/*String*/locale){
+ var gregorian = {};
+ dojo.forEach(_customFormats, function(desc){
+ var bundle = dojo.i18n.getLocalization(desc.pkg, desc.name, locale);
+ gregorian = dojo.mixin(gregorian, bundle);
+ }, this);
+ return gregorian; /*Object*/
};
})();
+
dojo.date.locale.addCustomFormats("dojo.cldr","gregorian");
-dojo.date.locale.getNames=function(_4f,_50,_51,_52){
-var _53,_54=dojo.date.locale._getGregorianBundle(_52),_55=[_4f,_51,_50];
-if(_51=="standAlone"){
-var key=_55.join("-");
-_53=_54[key];
-if(_53[0]==1){
-_53=undefined;
-}
-}
-_55[1]="format";
-return (_53||_54[_55.join("-")]).concat();
+
+dojo.date.locale.getNames = function(/*String*/item, /*String*/type, /*String?*/context, /*String?*/locale){
+ // summary:
+ // Used to get localized strings from dojo.cldr for day or month names.
+ //
+ // item:
+ // 'months' || 'days'
+ // type:
+ // 'wide' || 'narrow' || 'abbr' (e.g. "Monday", "Mon", or "M" respectively, in English)
+ // context:
+ // 'standAlone' || 'format' (default)
+ // locale:
+ // override locale used to find the names
+
+ var label,
+ lookup = dojo.date.locale._getGregorianBundle(locale),
+ props = [item, context, type];
+ if(context == 'standAlone'){
+ var key = props.join('-');
+ label = lookup[key];
+ // Fall back to 'format' flavor of name
+ if(label[0] == 1){ label = undefined; } // kludge, in the absence of real aliasing support in dojo.cldr
+ }
+ props[1] = 'format';
+
+ // return by copy so changes won't be made accidentally to the in-memory model
+ return (label || lookup[props.join('-')]).concat(); /*Array*/
};
-dojo.date.locale.isWeekend=function(_56,_57){
-var _58=dojo.cldr.supplemental.getWeekend(_57),day=(_56||new Date()).getDay();
-if(_58.end<_58.start){
-_58.end+=7;
-if(day<_58.start){
-day+=7;
-}
-}
-return day>=_58.start&&day<=_58.end;
+
+dojo.date.locale.isWeekend = function(/*Date?*/dateObject, /*String?*/locale){
+ // summary:
+ // Determines if the date falls on a weekend, according to local custom.
+
+ var weekend = dojo.cldr.supplemental.getWeekend(locale),
+ day = (dateObject || new Date()).getDay();
+ if(weekend.end < weekend.start){
+ weekend.end += 7;
+ if(day < weekend.start){ day += 7; }
+ }
+ return day >= weekend.start && day <= weekend.end; // Boolean
};
-dojo.date.locale._getDayOfYear=function(_59){
-return dojo.date.difference(new Date(_59.getFullYear(),0,1,_59.getHours()),_59)+1;
+
+// These are used only by format and strftime. Do they need to be public? Which module should they go in?
+
+dojo.date.locale._getDayOfYear = function(/*Date*/dateObject){
+ // summary: gets the day of the year as represented by dateObject
+ return dojo.date.difference(new Date(dateObject.getFullYear(), 0, 1, dateObject.getHours()), dateObject) + 1; // Number
};
-dojo.date.locale._getWeekOfYear=function(_5a,_5b){
-if(arguments.length==1){
-_5b=0;
-}
-var _5c=new Date(_5a.getFullYear(),0,1).getDay(),adj=(_5c-_5b+7)%7,_5d=Math.floor((dojo.date.locale._getDayOfYear(_5a)+adj-1)/7);
-if(_5c==_5b){
-_5d++;
-}
-return _5d;
+
+dojo.date.locale._getWeekOfYear = function(/*Date*/dateObject, /*Number*/firstDayOfWeek){
+ if(arguments.length == 1){ firstDayOfWeek = 0; } // Sunday
+
+ var firstDayOfYear = new Date(dateObject.getFullYear(), 0, 1).getDay(),
+ adj = (firstDayOfYear - firstDayOfWeek + 7) % 7,
+ week = Math.floor((dojo.date.locale._getDayOfYear(dateObject) + adj - 1) / 7);
+
+ // if year starts on the specified day, start counting weeks at 1
+ if(firstDayOfYear == firstDayOfWeek){ week++; }
+
+ return week; // Number
};
+
}
diff --git a/lib/dojo/date/stamp.js b/lib/dojo/date/stamp.js
index 17c5308d2..968bc40fd 100644
--- a/lib/dojo/date/stamp.js
+++ b/lib/dojo/date/stamp.js
@@ -5,78 +5,144 @@
*/
-if(!dojo._hasResource["dojo.date.stamp"]){
-dojo._hasResource["dojo.date.stamp"]=true;
+if(!dojo._hasResource["dojo.date.stamp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.date.stamp"] = true;
dojo.provide("dojo.date.stamp");
-dojo.date.stamp.fromISOString=function(_1,_2){
-if(!dojo.date.stamp._isoRegExp){
-dojo.date.stamp._isoRegExp=/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/;
-}
-var _3=dojo.date.stamp._isoRegExp.exec(_1),_4=null;
-if(_3){
-_3.shift();
-if(_3[1]){
-_3[1]--;
-}
-if(_3[6]){
-_3[6]*=1000;
-}
-if(_2){
-_2=new Date(_2);
-dojo.forEach(dojo.map(["FullYear","Month","Date","Hours","Minutes","Seconds","Milliseconds"],function(_5){
-return _2["get"+_5]();
-}),function(_6,_7){
-_3[_7]=_3[_7]||_6;
-});
-}
-_4=new Date(_3[0]||1970,_3[1]||0,_3[2]||1,_3[3]||0,_3[4]||0,_3[5]||0,_3[6]||0);
-if(_3[0]<100){
-_4.setFullYear(_3[0]||1970);
-}
-var _8=0,_9=_3[7]&&_3[7].charAt(0);
-if(_9!="Z"){
-_8=((_3[8]||0)*60)+(Number(_3[9])||0);
-if(_9!="-"){
-_8*=-1;
-}
-}
-if(_9){
-_8-=_4.getTimezoneOffset();
-}
-if(_8){
-_4.setTime(_4.getTime()+_8*60000);
-}
-}
-return _4;
-};
-dojo.date.stamp.toISOString=function(_a,_b){
-var _c=function(n){
-return (n<10)?"0"+n:n;
-};
-_b=_b||{};
-var _d=[],_e=_b.zulu?"getUTC":"get",_f="";
-if(_b.selector!="time"){
-var _10=_a[_e+"FullYear"]();
-_f=["0000".substr((_10+"").length)+_10,_c(_a[_e+"Month"]()+1),_c(_a[_e+"Date"]())].join("-");
-}
-_d.push(_f);
-if(_b.selector!="date"){
-var _11=[_c(_a[_e+"Hours"]()),_c(_a[_e+"Minutes"]()),_c(_a[_e+"Seconds"]())].join(":");
-var _12=_a[_e+"Milliseconds"]();
-if(_b.milliseconds){
-_11+="."+(_12<100?"0":"")+_c(_12);
-}
-if(_b.zulu){
-_11+="Z";
-}else{
-if(_b.selector!="time"){
-var _13=_a.getTimezoneOffset();
-var _14=Math.abs(_13);
-_11+=(_13>0?"-":"+")+_c(Math.floor(_14/60))+":"+_c(_14%60);
-}
+
+// Methods to convert dates to or from a wire (string) format using well-known conventions
+
+dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){
+ // summary:
+ // Returns a Date object given a string formatted according to a subset of the ISO-8601 standard.
+ //
+ // description:
+ // Accepts a string formatted according to a profile of ISO8601 as defined by
+ // [RFC3339](http://www.ietf.org/rfc/rfc3339.txt), except that partial input is allowed.
+ // Can also process dates as specified [by the W3C](http://www.w3.org/TR/NOTE-datetime)
+ // The following combinations are valid:
+ //
+ // * dates only
+ // | * yyyy
+ // | * yyyy-MM
+ // | * yyyy-MM-dd
+ // * times only, with an optional time zone appended
+ // | * THH:mm
+ // | * THH:mm:ss
+ // | * THH:mm:ss.SSS
+ // * and "datetimes" which could be any combination of the above
+ //
+ // timezones may be specified as Z (for UTC) or +/- followed by a time expression HH:mm
+ // Assumes the local time zone if not specified. Does not validate. Improperly formatted
+ // input may return null. Arguments which are out of bounds will be handled
+ // by the Date constructor (e.g. January 32nd typically gets resolved to February 1st)
+ // Only years between 100 and 9999 are supported.
+ //
+ // formattedString:
+ // A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00
+ //
+ // defaultTime:
+ // Used for defaults for fields omitted in the formattedString.
+ // Uses 1970-01-01T00:00:00.0Z by default.
+
+ if(!dojo.date.stamp._isoRegExp){
+ dojo.date.stamp._isoRegExp =
+//TODO: could be more restrictive and check for 00-59, etc.
+ /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/;
+ }
+
+ var match = dojo.date.stamp._isoRegExp.exec(formattedString),
+ result = null;
+
+ if(match){
+ match.shift();
+ if(match[1]){match[1]--;} // Javascript Date months are 0-based
+ if(match[6]){match[6] *= 1000;} // Javascript Date expects fractional seconds as milliseconds
+
+ if(defaultTime){
+ // mix in defaultTime. Relatively expensive, so use || operators for the fast path of defaultTime === 0
+ defaultTime = new Date(defaultTime);
+ dojo.forEach(dojo.map(["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"], function(prop){
+ return defaultTime["get" + prop]();
+ }), function(value, index){
+ match[index] = match[index] || value;
+ });
+ }
+ result = new Date(match[0]||1970, match[1]||0, match[2]||1, match[3]||0, match[4]||0, match[5]||0, match[6]||0); //TODO: UTC defaults
+ if(match[0] < 100){
+ result.setFullYear(match[0] || 1970);
+ }
+
+ var offset = 0,
+ zoneSign = match[7] && match[7].charAt(0);
+ if(zoneSign != 'Z'){
+ offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0);
+ if(zoneSign != '-'){ offset *= -1; }
+ }
+ if(zoneSign){
+ offset -= result.getTimezoneOffset();
+ }
+ if(offset){
+ result.setTime(result.getTime() + offset * 60000);
+ }
+ }
+
+ return result; // Date or null
}
-_d.push(_11);
+
+/*=====
+ dojo.date.stamp.__Options = function(){
+ // selector: String
+ // "date" or "time" for partial formatting of the Date object.
+ // Both date and time will be formatted by default.
+ // zulu: Boolean
+ // if true, UTC/GMT is used for a timezone
+ // milliseconds: Boolean
+ // if true, output milliseconds
+ this.selector = selector;
+ this.zulu = zulu;
+ this.milliseconds = milliseconds;
+ }
+=====*/
+
+dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*dojo.date.stamp.__Options?*/options){
+ // summary:
+ // Format a Date object as a string according a subset of the ISO-8601 standard
+ //
+ // description:
+ // When options.selector is omitted, output follows [RFC3339](http://www.ietf.org/rfc/rfc3339.txt)
+ // The local time zone is included as an offset from GMT, except when selector=='time' (time without a date)
+ // Does not check bounds. Only years between 100 and 9999 are supported.
+ //
+ // dateObject:
+ // A Date object
+
+ var _ = function(n){ return (n < 10) ? "0" + n : n; };
+ options = options || {};
+ var formattedDate = [],
+ getter = options.zulu ? "getUTC" : "get",
+ date = "";
+ if(options.selector != "time"){
+ var year = dateObject[getter+"FullYear"]();
+ date = ["0000".substr((year+"").length)+year, _(dateObject[getter+"Month"]()+1), _(dateObject[getter+"Date"]())].join('-');
+ }
+ formattedDate.push(date);
+ if(options.selector != "date"){
+ var time = [_(dateObject[getter+"Hours"]()), _(dateObject[getter+"Minutes"]()), _(dateObject[getter+"Seconds"]())].join(':');
+ var millis = dateObject[getter+"Milliseconds"]();
+ if(options.milliseconds){
+ time += "."+ (millis < 100 ? "0" : "") + _(millis);
+ }
+ if(options.zulu){
+ time += "Z";
+ }else if(options.selector != "time"){
+ var timezoneOffset = dateObject.getTimezoneOffset();
+ var absOffset = Math.abs(timezoneOffset);
+ time += (timezoneOffset > 0 ? "-" : "+") +
+ _(Math.floor(absOffset/60)) + ":" + _(absOffset%60);
+ }
+ formattedDate.push(time);
+ }
+ return formattedDate.join('T'); // String
}
-return _d.join("T");
-};
+
}
diff --git a/lib/dojo/dnd/Avatar.js b/lib/dojo/dnd/Avatar.js
index 057668026..effd253f3 100644
--- a/lib/dojo/dnd/Avatar.js
+++ b/lib/dojo/dnd/Avatar.js
@@ -5,60 +5,112 @@
*/
-if(!dojo._hasResource["dojo.dnd.Avatar"]){
-dojo._hasResource["dojo.dnd.Avatar"]=true;
+if(!dojo._hasResource["dojo.dnd.Avatar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Avatar"] = true;
dojo.provide("dojo.dnd.Avatar");
+
dojo.require("dojo.dnd.common");
-dojo.declare("dojo.dnd.Avatar",null,{constructor:function(_1){
-this.manager=_1;
-this.construct();
-},construct:function(){
-this.isA11y=dojo.hasClass(dojo.body(),"dijit_a11y");
-var a=dojo.create("table",{"class":"dojoDndAvatar",style:{position:"absolute",zIndex:"1999",margin:"0px"}}),_2=this.manager.source,_3,b=dojo.create("tbody",null,a),tr=dojo.create("tr",null,b),td=dojo.create("td",null,tr),_4=this.isA11y?dojo.create("span",{id:"a11yIcon",innerHTML:this.manager.copy?"+":"<"},td):null,_5=dojo.create("span",{innerHTML:_2.generateText?this._generateText():""},td),k=Math.min(5,this.manager.nodes.length),i=0;
-dojo.attr(tr,{"class":"dojoDndAvatarHeader",style:{opacity:0.9}});
-for(;i<k;++i){
-if(_2.creator){
-_3=_2._normalizedCreator(_2.getItem(this.manager.nodes[i].id).data,"avatar").node;
-}else{
-_3=this.manager.nodes[i].cloneNode(true);
-if(_3.tagName.toLowerCase()=="tr"){
-var _6=dojo.create("table"),_7=dojo.create("tbody",null,_6);
-_7.appendChild(_3);
-_3=_6;
-}
-}
-_3.id="";
-tr=dojo.create("tr",null,b);
-td=dojo.create("td",null,tr);
-td.appendChild(_3);
-dojo.attr(tr,{"class":"dojoDndAvatarItem",style:{opacity:(9-i)/10}});
-}
-this.node=a;
-},destroy:function(){
-dojo.destroy(this.node);
-this.node=false;
-},update:function(){
-dojo[(this.manager.canDropFlag?"add":"remove")+"Class"](this.node,"dojoDndAvatarCanDrop");
-if(this.isA11y){
-var _8=dojo.byId("a11yIcon");
-var _9="+";
-if(this.manager.canDropFlag&&!this.manager.copy){
-_9="< ";
-}else{
-if(!this.manager.canDropFlag&&!this.manager.copy){
-_9="o";
-}else{
-if(!this.manager.canDropFlag){
-_9="x";
-}
-}
-}
-_8.innerHTML=_9;
-}
-dojo.query(("tr.dojoDndAvatarHeader td span"+(this.isA11y?" span":"")),this.node).forEach(function(_a){
-_a.innerHTML=this._generateText();
-},this);
-},_generateText:function(){
-return this.manager.nodes.length.toString();
-}});
+
+dojo.declare("dojo.dnd.Avatar", null, {
+ // summary:
+ // Object that represents transferred DnD items visually
+ // manager: Object
+ // a DnD manager object
+
+ constructor: function(manager){
+ this.manager = manager;
+ this.construct();
+ },
+
+ // methods
+ construct: function(){
+ // summary:
+ // constructor function;
+ // it is separate so it can be (dynamically) overwritten in case of need
+ this.isA11y = dojo.hasClass(dojo.body(),"dijit_a11y");
+ var a = dojo.create("table", {
+ "class": "dojoDndAvatar",
+ style: {
+ position: "absolute",
+ zIndex: "1999",
+ margin: "0px"
+ }
+ }),
+ source = this.manager.source, node,
+ b = dojo.create("tbody", null, a),
+ tr = dojo.create("tr", null, b),
+ td = dojo.create("td", null, tr),
+ icon = this.isA11y ? dojo.create("span", {
+ id : "a11yIcon",
+ innerHTML : this.manager.copy ? '+' : "<"
+ }, td) : null,
+ span = dojo.create("span", {
+ innerHTML: source.generateText ? this._generateText() : ""
+ }, td),
+ k = Math.min(5, this.manager.nodes.length), i = 0;
+ // we have to set the opacity on IE only after the node is live
+ dojo.attr(tr, {
+ "class": "dojoDndAvatarHeader",
+ style: {opacity: 0.9}
+ });
+ for(; i < k; ++i){
+ if(source.creator){
+ // create an avatar representation of the node
+ node = source._normalizedCreator(source.getItem(this.manager.nodes[i].id).data, "avatar").node;
+ }else{
+ // or just clone the node and hope it works
+ node = this.manager.nodes[i].cloneNode(true);
+ if(node.tagName.toLowerCase() == "tr"){
+ // insert extra table nodes
+ var table = dojo.create("table"),
+ tbody = dojo.create("tbody", null, table);
+ tbody.appendChild(node);
+ node = table;
+ }
+ }
+ node.id = "";
+ tr = dojo.create("tr", null, b);
+ td = dojo.create("td", null, tr);
+ td.appendChild(node);
+ dojo.attr(tr, {
+ "class": "dojoDndAvatarItem",
+ style: {opacity: (9 - i) / 10}
+ });
+ }
+ this.node = a;
+ },
+ destroy: function(){
+ // summary:
+ // destructor for the avatar; called to remove all references so it can be garbage-collected
+ dojo.destroy(this.node);
+ this.node = false;
+ },
+ update: function(){
+ // summary:
+ // updates the avatar to reflect the current DnD state
+ dojo[(this.manager.canDropFlag ? "add" : "remove") + "Class"](this.node, "dojoDndAvatarCanDrop");
+ if (this.isA11y){
+ var icon = dojo.byId("a11yIcon");
+ var text = '+'; // assume canDrop && copy
+ if (this.manager.canDropFlag && !this.manager.copy) {
+ text = '< '; // canDrop && move
+ }else if (!this.manager.canDropFlag && !this.manager.copy) {
+ text = "o"; //!canDrop && move
+ }else if(!this.manager.canDropFlag){
+ text = 'x'; // !canDrop && copy
+ }
+ icon.innerHTML=text;
+ }
+ // replace text
+ dojo.query(("tr.dojoDndAvatarHeader td span" +(this.isA11y ? " span" : "")), this.node).forEach(
+ function(node){
+ node.innerHTML = this._generateText();
+ }, this);
+ },
+ _generateText: function(){
+ // summary: generates a proper text to reflect copying or moving of items
+ return this.manager.nodes.length.toString();
+ }
+});
+
}
diff --git a/lib/dojo/dnd/Container.js b/lib/dojo/dnd/Container.js
index 01e4ce2d9..6efc6f6fb 100644
--- a/lib/dojo/dnd/Container.js
+++ b/lib/dojo/dnd/Container.js
@@ -5,231 +5,435 @@
*/
-if(!dojo._hasResource["dojo.dnd.Container"]){
-dojo._hasResource["dojo.dnd.Container"]=true;
+if(!dojo._hasResource["dojo.dnd.Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Container"] = true;
dojo.provide("dojo.dnd.Container");
+
dojo.require("dojo.dnd.common");
dojo.require("dojo.parser");
-dojo.declare("dojo.dnd.Container",null,{skipForm:false,constructor:function(_1,_2){
-this.node=dojo.byId(_1);
-if(!_2){
-_2={};
-}
-this.creator=_2.creator||null;
-this.skipForm=_2.skipForm;
-this.parent=_2.dropParent&&dojo.byId(_2.dropParent);
-this.map={};
-this.current=null;
-this.containerState="";
-dojo.addClass(this.node,"dojoDndContainer");
-if(!(_2&&_2._skipStartup)){
-this.startup();
-}
-this.events=[dojo.connect(this.node,"onmouseover",this,"onMouseOver"),dojo.connect(this.node,"onmouseout",this,"onMouseOut"),dojo.connect(this.node,"ondragstart",this,"onSelectStart"),dojo.connect(this.node,"onselectstart",this,"onSelectStart")];
-},creator:function(){
-},getItem:function(_3){
-return this.map[_3];
-},setItem:function(_4,_5){
-this.map[_4]=_5;
-},delItem:function(_6){
-delete this.map[_6];
-},forInItems:function(f,o){
-o=o||dojo.global;
-var m=this.map,e=dojo.dnd._empty;
-for(var i in m){
-if(i in e){
-continue;
-}
-f.call(o,m[i],i,this);
-}
-return o;
-},clearItems:function(){
-this.map={};
-},getAllNodes:function(){
-return dojo.query("> .dojoDndItem",this.parent);
-},sync:function(){
-var _7={};
-this.getAllNodes().forEach(function(_8){
-if(_8.id){
-var _9=this.getItem(_8.id);
-if(_9){
-_7[_8.id]=_9;
-return;
-}
-}else{
-_8.id=dojo.dnd.getUniqueId();
-}
-var _a=_8.getAttribute("dndType"),_b=_8.getAttribute("dndData");
-_7[_8.id]={data:_b||_8.innerHTML,type:_a?_a.split(/\s*,\s*/):["text"]};
-},this);
-this.map=_7;
-return this;
-},insertNodes:function(_c,_d,_e){
-if(!this.parent.firstChild){
-_e=null;
-}else{
-if(_d){
-if(!_e){
-_e=this.parent.firstChild;
-}
-}else{
-if(_e){
-_e=_e.nextSibling;
-}
-}
-}
-if(_e){
-for(var i=0;i<_c.length;++i){
-var t=this._normalizedCreator(_c[i]);
-this.setItem(t.node.id,{data:t.data,type:t.type});
-this.parent.insertBefore(t.node,_e);
-}
-}else{
-for(var i=0;i<_c.length;++i){
-var t=this._normalizedCreator(_c[i]);
-this.setItem(t.node.id,{data:t.data,type:t.type});
-this.parent.appendChild(t.node);
-}
-}
-return this;
-},destroy:function(){
-dojo.forEach(this.events,dojo.disconnect);
-this.clearItems();
-this.node=this.parent=this.current=null;
-},markupFactory:function(_f,_10){
-_f._skipStartup=true;
-return new dojo.dnd.Container(_10,_f);
-},startup:function(){
-if(!this.parent){
-this.parent=this.node;
-if(this.parent.tagName.toLowerCase()=="table"){
-var c=this.parent.getElementsByTagName("tbody");
-if(c&&c.length){
-this.parent=c[0];
-}
-}
-}
-this.defaultCreator=dojo.dnd._defaultCreator(this.parent);
-this.sync();
-},onMouseOver:function(e){
-var n=e.relatedTarget;
-while(n){
-if(n==this.node){
-break;
-}
-try{
-n=n.parentNode;
-}
-catch(x){
-n=null;
-}
-}
-if(!n){
-this._changeState("Container","Over");
-this.onOverEvent();
-}
-n=this._getChildByEvent(e);
-if(this.current==n){
-return;
-}
-if(this.current){
-this._removeItemClass(this.current,"Over");
-}
-if(n){
-this._addItemClass(n,"Over");
-}
-this.current=n;
-},onMouseOut:function(e){
-for(var n=e.relatedTarget;n;){
-if(n==this.node){
-return;
-}
-try{
-n=n.parentNode;
-}
-catch(x){
-n=null;
-}
-}
-if(this.current){
-this._removeItemClass(this.current,"Over");
-this.current=null;
-}
-this._changeState("Container","");
-this.onOutEvent();
-},onSelectStart:function(e){
-if(!this.skipForm||!dojo.dnd.isFormElement(e)){
-dojo.stopEvent(e);
-}
-},onOverEvent:function(){
-},onOutEvent:function(){
-},_changeState:function(_11,_12){
-var _13="dojoDnd"+_11;
-var _14=_11.toLowerCase()+"State";
-dojo.removeClass(this.node,_13+this[_14]);
-dojo.addClass(this.node,_13+_12);
-this[_14]=_12;
-},_addItemClass:function(_15,_16){
-dojo.addClass(_15,"dojoDndItem"+_16);
-},_removeItemClass:function(_17,_18){
-dojo.removeClass(_17,"dojoDndItem"+_18);
-},_getChildByEvent:function(e){
-var _19=e.target;
-if(_19){
-for(var _1a=_19.parentNode;_1a;_19=_1a,_1a=_19.parentNode){
-if(_1a==this.parent&&dojo.hasClass(_19,"dojoDndItem")){
-return _19;
-}
-}
-}
-return null;
-},_normalizedCreator:function(_1b,_1c){
-var t=(this.creator||this.defaultCreator).call(this,_1b,_1c);
-if(!dojo.isArray(t.type)){
-t.type=["text"];
-}
-if(!t.node.id){
-t.node.id=dojo.dnd.getUniqueId();
-}
-dojo.addClass(t.node,"dojoDndItem");
-return t;
-}});
-dojo.dnd._createNode=function(tag){
-if(!tag){
-return dojo.dnd._createSpan;
-}
-return function(_1d){
-return dojo.create(tag,{innerHTML:_1d});
-};
-};
-dojo.dnd._createTrTd=function(_1e){
-var tr=dojo.create("tr");
-dojo.create("td",{innerHTML:_1e},tr);
-return tr;
+
+/*
+ Container states:
+ "" - normal state
+ "Over" - mouse over a container
+ Container item states:
+ "" - normal state
+ "Over" - mouse over a container item
+*/
+
+/*=====
+dojo.declare("dojo.dnd.__ContainerArgs", [], {
+ creator: function(){
+ // summary:
+ // a creator function, which takes a data item, and returns an object like that:
+ // {node: newNode, data: usedData, type: arrayOfStrings}
+ },
+
+ // skipForm: Boolean
+ // don't start the drag operation, if clicked on form elements
+ skipForm: false,
+
+ // dropParent: Node||String
+ // node or node's id to use as the parent node for dropped items
+ // (must be underneath the 'node' parameter in the DOM)
+ dropParent: null,
+
+ // _skipStartup: Boolean
+ // skip startup(), which collects children, for deferred initialization
+ // (this is used in the markup mode)
+ _skipStartup: false
+});
+
+dojo.dnd.Item = function(){
+ // summary:
+ // Represents (one of) the source node(s) being dragged.
+ // Contains (at least) the "type" and "data" attributes.
+ // type: String[]
+ // Type(s) of this item, by default this is ["text"]
+ // data: Object
+ // Logical representation of the object being dragged.
+ // If the drag object's type is "text" then data is a String,
+ // if it's another type then data could be a different Object,
+ // perhaps a name/value hash.
+
+ this.type = type;
+ this.data = data;
+}
+=====*/
+
+dojo.declare("dojo.dnd.Container", null, {
+ // summary:
+ // a Container object, which knows when mouse hovers over it,
+ // and over which element it hovers
+
+ // object attributes (for markup)
+ skipForm: false,
+
+ /*=====
+ // current: DomNode
+ // The DOM node the mouse is currently hovered over
+ current: null,
+
+ // map: Hash<String, dojo.dnd.Item>
+ // Map from an item's id (which is also the DOMNode's id) to
+ // the dojo.dnd.Item itself.
+ map: {},
+ =====*/
+
+ constructor: function(node, params){
+ // summary:
+ // a constructor of the Container
+ // node: Node
+ // node or node's id to build the container on
+ // params: dojo.dnd.__ContainerArgs
+ // a dictionary of parameters
+ this.node = dojo.byId(node);
+ if(!params){ params = {}; }
+ this.creator = params.creator || null;
+ this.skipForm = params.skipForm;
+ this.parent = params.dropParent && dojo.byId(params.dropParent);
+
+ // class-specific variables
+ this.map = {};
+ this.current = null;
+
+ // states
+ this.containerState = "";
+ dojo.addClass(this.node, "dojoDndContainer");
+
+ // mark up children
+ if(!(params && params._skipStartup)){
+ this.startup();
+ }
+
+ // set up events
+ this.events = [
+ dojo.connect(this.node, "onmouseover", this, "onMouseOver"),
+ dojo.connect(this.node, "onmouseout", this, "onMouseOut"),
+ // cancel text selection and text dragging
+ dojo.connect(this.node, "ondragstart", this, "onSelectStart"),
+ dojo.connect(this.node, "onselectstart", this, "onSelectStart")
+ ];
+ },
+
+ // object attributes (for markup)
+ creator: function(){
+ // summary:
+ // creator function, dummy at the moment
+ },
+
+ // abstract access to the map
+ getItem: function(/*String*/ key){
+ // summary:
+ // returns a data item by its key (id)
+ return this.map[key]; // dojo.dnd.Item
+ },
+ setItem: function(/*String*/ key, /*dojo.dnd.Item*/ data){
+ // summary:
+ // associates a data item with its key (id)
+ this.map[key] = data;
+ },
+ delItem: function(/*String*/ key){
+ // summary:
+ // removes a data item from the map by its key (id)
+ delete this.map[key];
+ },
+ forInItems: function(/*Function*/ f, /*Object?*/ o){
+ // summary:
+ // iterates over a data map skipping members that
+ // are present in the empty object (IE and/or 3rd-party libraries).
+ o = o || dojo.global;
+ var m = this.map, e = dojo.dnd._empty;
+ for(var i in m){
+ if(i in e){ continue; }
+ f.call(o, m[i], i, this);
+ }
+ return o; // Object
+ },
+ clearItems: function(){
+ // summary:
+ // removes all data items from the map
+ this.map = {};
+ },
+
+ // methods
+ getAllNodes: function(){
+ // summary:
+ // returns a list (an array) of all valid child nodes
+ return dojo.query("> .dojoDndItem", this.parent); // NodeList
+ },
+ sync: function(){
+ // summary:
+ // sync up the node list with the data map
+ var map = {};
+ this.getAllNodes().forEach(function(node){
+ if(node.id){
+ var item = this.getItem(node.id);
+ if(item){
+ map[node.id] = item;
+ return;
+ }
+ }else{
+ node.id = dojo.dnd.getUniqueId();
+ }
+ var type = node.getAttribute("dndType"),
+ data = node.getAttribute("dndData");
+ map[node.id] = {
+ data: data || node.innerHTML,
+ type: type ? type.split(/\s*,\s*/) : ["text"]
+ };
+ }, this);
+ this.map = map;
+ return this; // self
+ },
+ insertNodes: function(data, before, anchor){
+ // summary:
+ // inserts an array of new nodes before/after an anchor node
+ // data: Array
+ // a list of data items, which should be processed by the creator function
+ // before: Boolean
+ // insert before the anchor, if true, and after the anchor otherwise
+ // anchor: Node
+ // the anchor node to be used as a point of insertion
+ if(!this.parent.firstChild){
+ anchor = null;
+ }else if(before){
+ if(!anchor){
+ anchor = this.parent.firstChild;
+ }
+ }else{
+ if(anchor){
+ anchor = anchor.nextSibling;
+ }
+ }
+ if(anchor){
+ for(var i = 0; i < data.length; ++i){
+ var t = this._normalizedCreator(data[i]);
+ this.setItem(t.node.id, {data: t.data, type: t.type});
+ this.parent.insertBefore(t.node, anchor);
+ }
+ }else{
+ for(var i = 0; i < data.length; ++i){
+ var t = this._normalizedCreator(data[i]);
+ this.setItem(t.node.id, {data: t.data, type: t.type});
+ this.parent.appendChild(t.node);
+ }
+ }
+ return this; // self
+ },
+ destroy: function(){
+ // summary:
+ // prepares this object to be garbage-collected
+ dojo.forEach(this.events, dojo.disconnect);
+ this.clearItems();
+ this.node = this.parent = this.current = null;
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ params._skipStartup = true;
+ return new dojo.dnd.Container(node, params);
+ },
+ startup: function(){
+ // summary:
+ // collects valid child items and populate the map
+
+ // set up the real parent node
+ if(!this.parent){
+ // use the standard algorithm, if not assigned
+ this.parent = this.node;
+ if(this.parent.tagName.toLowerCase() == "table"){
+ var c = this.parent.getElementsByTagName("tbody");
+ if(c && c.length){ this.parent = c[0]; }
+ }
+ }
+ this.defaultCreator = dojo.dnd._defaultCreator(this.parent);
+
+ // process specially marked children
+ this.sync();
+ },
+
+ // mouse events
+ onMouseOver: function(e){
+ // summary:
+ // event processor for onmouseover
+ // e: Event
+ // mouse event
+ var n = e.relatedTarget;
+ while(n){
+ if(n == this.node){ break; }
+ try{
+ n = n.parentNode;
+ }catch(x){
+ n = null;
+ }
+ }
+ if(!n){
+ this._changeState("Container", "Over");
+ this.onOverEvent();
+ }
+ n = this._getChildByEvent(e);
+ if(this.current == n){ return; }
+ if(this.current){ this._removeItemClass(this.current, "Over"); }
+ if(n){ this._addItemClass(n, "Over"); }
+ this.current = n;
+ },
+ onMouseOut: function(e){
+ // summary:
+ // event processor for onmouseout
+ // e: Event
+ // mouse event
+ for(var n = e.relatedTarget; n;){
+ if(n == this.node){ return; }
+ try{
+ n = n.parentNode;
+ }catch(x){
+ n = null;
+ }
+ }
+ if(this.current){
+ this._removeItemClass(this.current, "Over");
+ this.current = null;
+ }
+ this._changeState("Container", "");
+ this.onOutEvent();
+ },
+ onSelectStart: function(e){
+ // summary:
+ // event processor for onselectevent and ondragevent
+ // e: Event
+ // mouse event
+ if(!this.skipForm || !dojo.dnd.isFormElement(e)){
+ dojo.stopEvent(e);
+ }
+ },
+
+ // utilities
+ onOverEvent: function(){
+ // summary:
+ // this function is called once, when mouse is over our container
+ },
+ onOutEvent: function(){
+ // summary:
+ // this function is called once, when mouse is out of our container
+ },
+ _changeState: function(type, newState){
+ // summary:
+ // changes a named state to new state value
+ // type: String
+ // a name of the state to change
+ // newState: String
+ // new state
+ var prefix = "dojoDnd" + type;
+ var state = type.toLowerCase() + "State";
+ //dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
+ dojo.removeClass(this.node, prefix + this[state]);
+ dojo.addClass(this.node, prefix + newState);
+ this[state] = newState;
+ },
+ _addItemClass: function(node, type){
+ // summary:
+ // adds a class with prefix "dojoDndItem"
+ // node: Node
+ // a node
+ // type: String
+ // a variable suffix for a class name
+ dojo.addClass(node, "dojoDndItem" + type);
+ },
+ _removeItemClass: function(node, type){
+ // summary:
+ // removes a class with prefix "dojoDndItem"
+ // node: Node
+ // a node
+ // type: String
+ // a variable suffix for a class name
+ dojo.removeClass(node, "dojoDndItem" + type);
+ },
+ _getChildByEvent: function(e){
+ // summary:
+ // gets a child, which is under the mouse at the moment, or null
+ // e: Event
+ // a mouse event
+ var node = e.target;
+ if(node){
+ for(var parent = node.parentNode; parent; node = parent, parent = node.parentNode){
+ if(parent == this.parent && dojo.hasClass(node, "dojoDndItem")){ return node; }
+ }
+ }
+ return null;
+ },
+ _normalizedCreator: function(/*dojo.dnd.Item*/ item, /*String*/ hint){
+ // summary:
+ // adds all necessary data to the output of the user-supplied creator function
+ var t = (this.creator || this.defaultCreator).call(this, item, hint);
+ if(!dojo.isArray(t.type)){ t.type = ["text"]; }
+ if(!t.node.id){ t.node.id = dojo.dnd.getUniqueId(); }
+ dojo.addClass(t.node, "dojoDndItem");
+ return t;
+ }
+});
+
+dojo.dnd._createNode = function(tag){
+ // summary:
+ // returns a function, which creates an element of given tag
+ // (SPAN by default) and sets its innerHTML to given text
+ // tag: String
+ // a tag name or empty for SPAN
+ if(!tag){ return dojo.dnd._createSpan; }
+ return function(text){ // Function
+ return dojo.create(tag, {innerHTML: text}); // Node
+ };
};
-dojo.dnd._createSpan=function(_1f){
-return dojo.create("span",{innerHTML:_1f});
+
+dojo.dnd._createTrTd = function(text){
+ // summary:
+ // creates a TR/TD structure with given text as an innerHTML of TD
+ // text: String
+ // a text for TD
+ var tr = dojo.create("tr");
+ dojo.create("td", {innerHTML: text}, tr);
+ return tr; // Node
};
-dojo.dnd._defaultCreatorNodes={ul:"li",ol:"li",div:"div",p:"div"};
-dojo.dnd._defaultCreator=function(_20){
-var tag=_20.tagName.toLowerCase();
-var c=tag=="tbody"||tag=="thead"?dojo.dnd._createTrTd:dojo.dnd._createNode(dojo.dnd._defaultCreatorNodes[tag]);
-return function(_21,_22){
-var _23=_21&&dojo.isObject(_21),_24,_25,n;
-if(_23&&_21.tagName&&_21.nodeType&&_21.getAttribute){
-_24=_21.getAttribute("dndData")||_21.innerHTML;
-_25=_21.getAttribute("dndType");
-_25=_25?_25.split(/\s*,\s*/):["text"];
-n=_21;
-}else{
-_24=(_23&&_21.data)?_21.data:_21;
-_25=(_23&&_21.type)?_21.type:["text"];
-n=(_22=="avatar"?dojo.dnd._createSpan:c)(String(_24));
-}
-if(!n.id){
-n.id=dojo.dnd.getUniqueId();
-}
-return {node:n,data:_24,type:_25};
+
+dojo.dnd._createSpan = function(text){
+ // summary:
+ // creates a SPAN element with given text as its innerHTML
+ // text: String
+ // a text for SPAN
+ return dojo.create("span", {innerHTML: text}); // Node
};
+
+// dojo.dnd._defaultCreatorNodes: Object
+// a dictionary that maps container tag names to child tag names
+dojo.dnd._defaultCreatorNodes = {ul: "li", ol: "li", div: "div", p: "div"};
+
+dojo.dnd._defaultCreator = function(node){
+ // summary:
+ // takes a parent node, and returns an appropriate creator function
+ // node: Node
+ // a container node
+ var tag = node.tagName.toLowerCase();
+ var c = tag == "tbody" || tag == "thead" ? dojo.dnd._createTrTd :
+ dojo.dnd._createNode(dojo.dnd._defaultCreatorNodes[tag]);
+ return function(item, hint){ // Function
+ var isObj = item && dojo.isObject(item), data, type, n;
+ if(isObj && item.tagName && item.nodeType && item.getAttribute){
+ // process a DOM node
+ data = item.getAttribute("dndData") || item.innerHTML;
+ type = item.getAttribute("dndType");
+ type = type ? type.split(/\s*,\s*/) : ["text"];
+ n = item; // this node is going to be moved rather than copied
+ }else{
+ // process a DnD item object or a string
+ data = (isObj && item.data) ? item.data : item;
+ type = (isObj && item.type) ? item.type : ["text"];
+ n = (hint == "avatar" ? dojo.dnd._createSpan : c)(String(data));
+ }
+ if(!n.id){
+ n.id = dojo.dnd.getUniqueId();
+ }
+ return {node: n, data: data, type: type};
+ };
};
+
}
diff --git a/lib/dojo/dnd/Manager.js b/lib/dojo/dnd/Manager.js
index c6f91aac3..70754f93f 100644
--- a/lib/dojo/dnd/Manager.js
+++ b/lib/dojo/dnd/Manager.js
@@ -5,124 +5,216 @@
*/
-if(!dojo._hasResource["dojo.dnd.Manager"]){
-dojo._hasResource["dojo.dnd.Manager"]=true;
+if(!dojo._hasResource["dojo.dnd.Manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Manager"] = true;
dojo.provide("dojo.dnd.Manager");
+
dojo.require("dojo.dnd.common");
dojo.require("dojo.dnd.autoscroll");
dojo.require("dojo.dnd.Avatar");
-dojo.declare("dojo.dnd.Manager",null,{constructor:function(){
-this.avatar=null;
-this.source=null;
-this.nodes=[];
-this.copy=true;
-this.target=null;
-this.canDropFlag=false;
-this.events=[];
-},OFFSET_X:16,OFFSET_Y:16,overSource:function(_1){
-if(this.avatar){
-this.target=(_1&&_1.targetState!="Disabled")?_1:null;
-this.canDropFlag=Boolean(this.target);
-this.avatar.update();
-}
-dojo.publish("/dnd/source/over",[_1]);
-},outSource:function(_2){
-if(this.avatar){
-if(this.target==_2){
-this.target=null;
-this.canDropFlag=false;
-this.avatar.update();
-dojo.publish("/dnd/source/over",[null]);
-}
-}else{
-dojo.publish("/dnd/source/over",[null]);
-}
-},startDrag:function(_3,_4,_5){
-this.source=_3;
-this.nodes=_4;
-this.copy=Boolean(_5);
-this.avatar=this.makeAvatar();
-dojo.body().appendChild(this.avatar.node);
-dojo.publish("/dnd/start",[_3,_4,this.copy]);
-this.events=[dojo.connect(dojo.doc,"onmousemove",this,"onMouseMove"),dojo.connect(dojo.doc,"onmouseup",this,"onMouseUp"),dojo.connect(dojo.doc,"onkeydown",this,"onKeyDown"),dojo.connect(dojo.doc,"onkeyup",this,"onKeyUp"),dojo.connect(dojo.doc,"ondragstart",dojo.stopEvent),dojo.connect(dojo.body(),"onselectstart",dojo.stopEvent)];
-var c="dojoDnd"+(_5?"Copy":"Move");
-dojo.addClass(dojo.body(),c);
-},canDrop:function(_6){
-var _7=Boolean(this.target&&_6);
-if(this.canDropFlag!=_7){
-this.canDropFlag=_7;
-this.avatar.update();
-}
-},stopDrag:function(){
-dojo.removeClass(dojo.body(),"dojoDndCopy");
-dojo.removeClass(dojo.body(),"dojoDndMove");
-dojo.forEach(this.events,dojo.disconnect);
-this.events=[];
-this.avatar.destroy();
-this.avatar=null;
-this.source=this.target=null;
-this.nodes=[];
-},makeAvatar:function(){
-return new dojo.dnd.Avatar(this);
-},updateAvatar:function(){
-this.avatar.update();
-},onMouseMove:function(e){
-var a=this.avatar;
-if(a){
-dojo.dnd.autoScrollNodes(e);
-var s=a.node.style;
-s.left=(e.pageX+this.OFFSET_X)+"px";
-s.top=(e.pageY+this.OFFSET_Y)+"px";
-var _8=Boolean(this.source.copyState(dojo.isCopyKey(e)));
-if(this.copy!=_8){
-this._setCopyStatus(_8);
-}
-}
-},onMouseUp:function(e){
-if(this.avatar){
-if(this.target&&this.canDropFlag){
-var _9=Boolean(this.source.copyState(dojo.isCopyKey(e))),_a=[this.source,this.nodes,_9,this.target,e];
-dojo.publish("/dnd/drop/before",_a);
-dojo.publish("/dnd/drop",_a);
-}else{
-dojo.publish("/dnd/cancel");
-}
-this.stopDrag();
-}
-},onKeyDown:function(e){
-if(this.avatar){
-switch(e.keyCode){
-case dojo.keys.CTRL:
-var _b=Boolean(this.source.copyState(true));
-if(this.copy!=_b){
-this._setCopyStatus(_b);
-}
-break;
-case dojo.keys.ESCAPE:
-dojo.publish("/dnd/cancel");
-this.stopDrag();
-break;
-}
-}
-},onKeyUp:function(e){
-if(this.avatar&&e.keyCode==dojo.keys.CTRL){
-var _c=Boolean(this.source.copyState(false));
-if(this.copy!=_c){
-this._setCopyStatus(_c);
-}
-}
-},_setCopyStatus:function(_d){
-this.copy=_d;
-this.source._markDndStatus(this.copy);
-this.updateAvatar();
-dojo.removeClass(dojo.body(),"dojoDnd"+(this.copy?"Move":"Copy"));
-dojo.addClass(dojo.body(),"dojoDnd"+(this.copy?"Copy":"Move"));
-}});
-dojo.dnd._manager=null;
-dojo.dnd.manager=function(){
-if(!dojo.dnd._manager){
-dojo.dnd._manager=new dojo.dnd.Manager();
-}
-return dojo.dnd._manager;
+
+dojo.declare("dojo.dnd.Manager", null, {
+ // summary:
+ // the manager of DnD operations (usually a singleton)
+ constructor: function(){
+ this.avatar = null;
+ this.source = null;
+ this.nodes = [];
+ this.copy = true;
+ this.target = null;
+ this.canDropFlag = false;
+ this.events = [];
+ },
+
+ // avatar's offset from the mouse
+ OFFSET_X: 16,
+ OFFSET_Y: 16,
+
+ // methods
+ overSource: function(source){
+ // summary:
+ // called when a source detected a mouse-over condition
+ // source: Object
+ // the reporter
+ if(this.avatar){
+ this.target = (source && source.targetState != "Disabled") ? source : null;
+ this.canDropFlag = Boolean(this.target);
+ this.avatar.update();
+ }
+ dojo.publish("/dnd/source/over", [source]);
+ },
+ outSource: function(source){
+ // summary:
+ // called when a source detected a mouse-out condition
+ // source: Object
+ // the reporter
+ if(this.avatar){
+ if(this.target == source){
+ this.target = null;
+ this.canDropFlag = false;
+ this.avatar.update();
+ dojo.publish("/dnd/source/over", [null]);
+ }
+ }else{
+ dojo.publish("/dnd/source/over", [null]);
+ }
+ },
+ startDrag: function(source, nodes, copy){
+ // summary:
+ // called to initiate the DnD operation
+ // source: Object
+ // the source which provides items
+ // nodes: Array
+ // the list of transferred items
+ // copy: Boolean
+ // copy items, if true, move items otherwise
+ this.source = source;
+ this.nodes = nodes;
+ this.copy = Boolean(copy); // normalizing to true boolean
+ this.avatar = this.makeAvatar();
+ dojo.body().appendChild(this.avatar.node);
+ dojo.publish("/dnd/start", [source, nodes, this.copy]);
+ this.events = [
+ dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"),
+ dojo.connect(dojo.doc, "onmouseup", this, "onMouseUp"),
+ dojo.connect(dojo.doc, "onkeydown", this, "onKeyDown"),
+ dojo.connect(dojo.doc, "onkeyup", this, "onKeyUp"),
+ // cancel text selection and text dragging
+ dojo.connect(dojo.doc, "ondragstart", dojo.stopEvent),
+ dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent)
+ ];
+ var c = "dojoDnd" + (copy ? "Copy" : "Move");
+ dojo.addClass(dojo.body(), c);
+ },
+ canDrop: function(flag){
+ // summary:
+ // called to notify if the current target can accept items
+ var canDropFlag = Boolean(this.target && flag);
+ if(this.canDropFlag != canDropFlag){
+ this.canDropFlag = canDropFlag;
+ this.avatar.update();
+ }
+ },
+ stopDrag: function(){
+ // summary:
+ // stop the DnD in progress
+ dojo.removeClass(dojo.body(), "dojoDndCopy");
+ dojo.removeClass(dojo.body(), "dojoDndMove");
+ dojo.forEach(this.events, dojo.disconnect);
+ this.events = [];
+ this.avatar.destroy();
+ this.avatar = null;
+ this.source = this.target = null;
+ this.nodes = [];
+ },
+ makeAvatar: function(){
+ // summary:
+ // makes the avatar; it is separate to be overwritten dynamically, if needed
+ return new dojo.dnd.Avatar(this);
+ },
+ updateAvatar: function(){
+ // summary:
+ // updates the avatar; it is separate to be overwritten dynamically, if needed
+ this.avatar.update();
+ },
+
+ // mouse event processors
+ onMouseMove: function(e){
+ // summary:
+ // event processor for onmousemove
+ // e: Event
+ // mouse event
+ var a = this.avatar;
+ if(a){
+ dojo.dnd.autoScrollNodes(e);
+ //dojo.dnd.autoScroll(e);
+ var s = a.node.style;
+ s.left = (e.pageX + this.OFFSET_X) + "px";
+ s.top = (e.pageY + this.OFFSET_Y) + "px";
+ var copy = Boolean(this.source.copyState(dojo.isCopyKey(e)));
+ if(this.copy != copy){
+ this._setCopyStatus(copy);
+ }
+ }
+ },
+ onMouseUp: function(e){
+ // summary:
+ // event processor for onmouseup
+ // e: Event
+ // mouse event
+ if(this.avatar){
+ if(this.target && this.canDropFlag){
+ var copy = Boolean(this.source.copyState(dojo.isCopyKey(e))),
+ params = [this.source, this.nodes, copy, this.target, e];
+ dojo.publish("/dnd/drop/before", params);
+ dojo.publish("/dnd/drop", params);
+ }else{
+ dojo.publish("/dnd/cancel");
+ }
+ this.stopDrag();
+ }
+ },
+
+ // keyboard event processors
+ onKeyDown: function(e){
+ // summary:
+ // event processor for onkeydown:
+ // watching for CTRL for copy/move status, watching for ESCAPE to cancel the drag
+ // e: Event
+ // keyboard event
+ if(this.avatar){
+ switch(e.keyCode){
+ case dojo.keys.CTRL:
+ var copy = Boolean(this.source.copyState(true));
+ if(this.copy != copy){
+ this._setCopyStatus(copy);
+ }
+ break;
+ case dojo.keys.ESCAPE:
+ dojo.publish("/dnd/cancel");
+ this.stopDrag();
+ break;
+ }
+ }
+ },
+ onKeyUp: function(e){
+ // summary:
+ // event processor for onkeyup, watching for CTRL for copy/move status
+ // e: Event
+ // keyboard event
+ if(this.avatar && e.keyCode == dojo.keys.CTRL){
+ var copy = Boolean(this.source.copyState(false));
+ if(this.copy != copy){
+ this._setCopyStatus(copy);
+ }
+ }
+ },
+
+ // utilities
+ _setCopyStatus: function(copy){
+ // summary:
+ // changes the copy status
+ // copy: Boolean
+ // the copy status
+ this.copy = copy;
+ this.source._markDndStatus(this.copy);
+ this.updateAvatar();
+ dojo.removeClass(dojo.body(), "dojoDnd" + (this.copy ? "Move" : "Copy"));
+ dojo.addClass(dojo.body(), "dojoDnd" + (this.copy ? "Copy" : "Move"));
+ }
+});
+
+// dojo.dnd._manager:
+// The manager singleton variable. Can be overwritten if needed.
+dojo.dnd._manager = null;
+
+dojo.dnd.manager = function(){
+ // summary:
+ // Returns the current DnD manager. Creates one if it is not created yet.
+ if(!dojo.dnd._manager){
+ dojo.dnd._manager = new dojo.dnd.Manager();
+ }
+ return dojo.dnd._manager; // Object
};
+
}
diff --git a/lib/dojo/dnd/Moveable.js b/lib/dojo/dnd/Moveable.js
index 17d8d9200..324196582 100644
--- a/lib/dojo/dnd/Moveable.js
+++ b/lib/dojo/dnd/Moveable.js
@@ -5,73 +5,174 @@
*/
-if(!dojo._hasResource["dojo.dnd.Moveable"]){
-dojo._hasResource["dojo.dnd.Moveable"]=true;
+if(!dojo._hasResource["dojo.dnd.Moveable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Moveable"] = true;
dojo.provide("dojo.dnd.Moveable");
+
dojo.require("dojo.dnd.Mover");
-dojo.declare("dojo.dnd.Moveable",null,{handle:"",delay:0,skip:false,constructor:function(_1,_2){
-this.node=dojo.byId(_1);
-if(!_2){
-_2={};
-}
-this.handle=_2.handle?dojo.byId(_2.handle):null;
-if(!this.handle){
-this.handle=this.node;
-}
-this.delay=_2.delay>0?_2.delay:0;
-this.skip=_2.skip;
-this.mover=_2.mover?_2.mover:dojo.dnd.Mover;
-this.events=[dojo.connect(this.handle,"onmousedown",this,"onMouseDown"),dojo.connect(this.handle,"ondragstart",this,"onSelectStart"),dojo.connect(this.handle,"onselectstart",this,"onSelectStart")];
-},markupFactory:function(_3,_4){
-return new dojo.dnd.Moveable(_4,_3);
-},destroy:function(){
-dojo.forEach(this.events,dojo.disconnect);
-this.events=this.node=this.handle=null;
-},onMouseDown:function(e){
-if(this.skip&&dojo.dnd.isFormElement(e)){
-return;
-}
-if(this.delay){
-this.events.push(dojo.connect(this.handle,"onmousemove",this,"onMouseMove"),dojo.connect(this.handle,"onmouseup",this,"onMouseUp"));
-this._lastX=e.pageX;
-this._lastY=e.pageY;
-}else{
-this.onDragDetected(e);
-}
-dojo.stopEvent(e);
-},onMouseMove:function(e){
-if(Math.abs(e.pageX-this._lastX)>this.delay||Math.abs(e.pageY-this._lastY)>this.delay){
-this.onMouseUp(e);
-this.onDragDetected(e);
-}
-dojo.stopEvent(e);
-},onMouseUp:function(e){
-for(var i=0;i<2;++i){
-dojo.disconnect(this.events.pop());
-}
-dojo.stopEvent(e);
-},onSelectStart:function(e){
-if(!this.skip||!dojo.dnd.isFormElement(e)){
-dojo.stopEvent(e);
-}
-},onDragDetected:function(e){
-new this.mover(this.node,e,this);
-},onMoveStart:function(_5){
-dojo.publish("/dnd/move/start",[_5]);
-dojo.addClass(dojo.body(),"dojoMove");
-dojo.addClass(this.node,"dojoMoveItem");
-},onMoveStop:function(_6){
-dojo.publish("/dnd/move/stop",[_6]);
-dojo.removeClass(dojo.body(),"dojoMove");
-dojo.removeClass(this.node,"dojoMoveItem");
-},onFirstMove:function(_7,e){
-},onMove:function(_8,_9,e){
-this.onMoving(_8,_9);
-var s=_8.node.style;
-s.left=_9.l+"px";
-s.top=_9.t+"px";
-this.onMoved(_8,_9);
-},onMoving:function(_a,_b){
-},onMoved:function(_c,_d){
-}});
+
+/*=====
+dojo.declare("dojo.dnd.__MoveableArgs", [], {
+ // handle: Node||String
+ // A node (or node's id), which is used as a mouse handle.
+ // If omitted, the node itself is used as a handle.
+ handle: null,
+
+ // delay: Number
+ // delay move by this number of pixels
+ delay: 0,
+
+ // skip: Boolean
+ // skip move of form elements
+ skip: false,
+
+ // mover: Object
+ // a constructor of custom Mover
+ mover: dojo.dnd.Mover
+});
+=====*/
+
+dojo.declare("dojo.dnd.Moveable", null, {
+ // object attributes (for markup)
+ handle: "",
+ delay: 0,
+ skip: false,
+
+ constructor: function(node, params){
+ // summary:
+ // an object, which makes a node moveable
+ // node: Node
+ // a node (or node's id) to be moved
+ // params: dojo.dnd.__MoveableArgs?
+ // optional parameters
+ this.node = dojo.byId(node);
+ if(!params){ params = {}; }
+ this.handle = params.handle ? dojo.byId(params.handle) : null;
+ if(!this.handle){ this.handle = this.node; }
+ this.delay = params.delay > 0 ? params.delay : 0;
+ this.skip = params.skip;
+ this.mover = params.mover ? params.mover : dojo.dnd.Mover;
+ this.events = [
+ dojo.connect(this.handle, "onmousedown", this, "onMouseDown"),
+ // cancel text selection and text dragging
+ dojo.connect(this.handle, "ondragstart", this, "onSelectStart"),
+ dojo.connect(this.handle, "onselectstart", this, "onSelectStart")
+ ];
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.Moveable(node, params);
+ },
+
+ // methods
+ destroy: function(){
+ // summary:
+ // stops watching for possible move, deletes all references, so the object can be garbage-collected
+ dojo.forEach(this.events, dojo.disconnect);
+ this.events = this.node = this.handle = null;
+ },
+
+ // mouse event processors
+ onMouseDown: function(e){
+ // summary:
+ // event processor for onmousedown, creates a Mover for the node
+ // e: Event
+ // mouse event
+ if(this.skip && dojo.dnd.isFormElement(e)){ return; }
+ if(this.delay){
+ this.events.push(
+ dojo.connect(this.handle, "onmousemove", this, "onMouseMove"),
+ dojo.connect(this.handle, "onmouseup", this, "onMouseUp")
+ );
+ this._lastX = e.pageX;
+ this._lastY = e.pageY;
+ }else{
+ this.onDragDetected(e);
+ }
+ dojo.stopEvent(e);
+ },
+ onMouseMove: function(e){
+ // summary:
+ // event processor for onmousemove, used only for delayed drags
+ // e: Event
+ // mouse event
+ if(Math.abs(e.pageX - this._lastX) > this.delay || Math.abs(e.pageY - this._lastY) > this.delay){
+ this.onMouseUp(e);
+ this.onDragDetected(e);
+ }
+ dojo.stopEvent(e);
+ },
+ onMouseUp: function(e){
+ // summary:
+ // event processor for onmouseup, used only for delayed drags
+ // e: Event
+ // mouse event
+ for(var i = 0; i < 2; ++i){
+ dojo.disconnect(this.events.pop());
+ }
+ dojo.stopEvent(e);
+ },
+ onSelectStart: function(e){
+ // summary:
+ // event processor for onselectevent and ondragevent
+ // e: Event
+ // mouse event
+ if(!this.skip || !dojo.dnd.isFormElement(e)){
+ dojo.stopEvent(e);
+ }
+ },
+
+ // local events
+ onDragDetected: function(/* Event */ e){
+ // summary:
+ // called when the drag is detected;
+ // responsible for creation of the mover
+ new this.mover(this.node, e, this);
+ },
+ onMoveStart: function(/* dojo.dnd.Mover */ mover){
+ // summary:
+ // called before every move operation
+ dojo.publish("/dnd/move/start", [mover]);
+ dojo.addClass(dojo.body(), "dojoMove");
+ dojo.addClass(this.node, "dojoMoveItem");
+ },
+ onMoveStop: function(/* dojo.dnd.Mover */ mover){
+ // summary:
+ // called after every move operation
+ dojo.publish("/dnd/move/stop", [mover]);
+ dojo.removeClass(dojo.body(), "dojoMove");
+ dojo.removeClass(this.node, "dojoMoveItem");
+ },
+ onFirstMove: function(/* dojo.dnd.Mover */ mover, /* Event */ e){
+ // summary:
+ // called during the very first move notification;
+ // can be used to initialize coordinates, can be overwritten.
+
+ // default implementation does nothing
+ },
+ onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop, /* Event */ e){
+ // summary:
+ // called during every move notification;
+ // should actually move the node; can be overwritten.
+ this.onMoving(mover, leftTop);
+ var s = mover.node.style;
+ s.left = leftTop.l + "px";
+ s.top = leftTop.t + "px";
+ this.onMoved(mover, leftTop);
+ },
+ onMoving: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ // summary:
+ // called before every incremental move; can be overwritten.
+
+ // default implementation does nothing
+ },
+ onMoved: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ // summary:
+ // called after every incremental move; can be overwritten.
+
+ // default implementation does nothing
+ }
+});
+
}
diff --git a/lib/dojo/dnd/Mover.js b/lib/dojo/dnd/Mover.js
index 6ea793efc..cdb995c08 100644
--- a/lib/dojo/dnd/Mover.js
+++ b/lib/dojo/dnd/Mover.js
@@ -5,61 +5,113 @@
*/
-if(!dojo._hasResource["dojo.dnd.Mover"]){
-dojo._hasResource["dojo.dnd.Mover"]=true;
+if(!dojo._hasResource["dojo.dnd.Mover"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Mover"] = true;
dojo.provide("dojo.dnd.Mover");
+
dojo.require("dojo.dnd.common");
dojo.require("dojo.dnd.autoscroll");
-dojo.declare("dojo.dnd.Mover",null,{constructor:function(_1,e,_2){
-this.node=dojo.byId(_1);
-this.marginBox={l:e.pageX,t:e.pageY};
-this.mouseButton=e.button;
-var h=this.host=_2,d=_1.ownerDocument,_3=dojo.connect(d,"onmousemove",this,"onFirstMove");
-this.events=[dojo.connect(d,"onmousemove",this,"onMouseMove"),dojo.connect(d,"onmouseup",this,"onMouseUp"),dojo.connect(d,"ondragstart",dojo.stopEvent),dojo.connect(d.body,"onselectstart",dojo.stopEvent),_3];
-if(h&&h.onMoveStart){
-h.onMoveStart(this);
-}
-},onMouseMove:function(e){
-dojo.dnd.autoScroll(e);
-var m=this.marginBox;
-this.host.onMove(this,{l:m.l+e.pageX,t:m.t+e.pageY},e);
-dojo.stopEvent(e);
-},onMouseUp:function(e){
-if(dojo.isWebKit&&dojo.isMac&&this.mouseButton==2?e.button==0:this.mouseButton==e.button){
-this.destroy();
-}
-dojo.stopEvent(e);
-},onFirstMove:function(e){
-var s=this.node.style,l,t,h=this.host;
-switch(s.position){
-case "relative":
-case "absolute":
-l=Math.round(parseFloat(s.left))||0;
-t=Math.round(parseFloat(s.top))||0;
-break;
-default:
-s.position="absolute";
-var m=dojo.marginBox(this.node);
-var b=dojo.doc.body;
-var bs=dojo.getComputedStyle(b);
-var bm=dojo._getMarginBox(b,bs);
-var bc=dojo._getContentBox(b,bs);
-l=m.l-(bc.l-bm.l);
-t=m.t-(bc.t-bm.t);
-break;
-}
-this.marginBox.l=l-this.marginBox.l;
-this.marginBox.t=t-this.marginBox.t;
-if(h&&h.onFirstMove){
-h.onFirstMove(this,e);
-}
-dojo.disconnect(this.events.pop());
-},destroy:function(){
-dojo.forEach(this.events,dojo.disconnect);
-var h=this.host;
-if(h&&h.onMoveStop){
-h.onMoveStop(this);
-}
-this.events=this.node=this.host=null;
-}});
+
+dojo.declare("dojo.dnd.Mover", null, {
+ constructor: function(node, e, host){
+ // summary:
+ // an object, which makes a node follow the mouse.
+ // Used as a default mover, and as a base class for custom movers.
+ // node: Node
+ // a node (or node's id) to be moved
+ // e: Event
+ // a mouse event, which started the move;
+ // only pageX and pageY properties are used
+ // host: Object?
+ // object which implements the functionality of the move,
+ // and defines proper events (onMoveStart and onMoveStop)
+ this.node = dojo.byId(node);
+ this.marginBox = {l: e.pageX, t: e.pageY};
+ this.mouseButton = e.button;
+ var h = this.host = host, d = node.ownerDocument,
+ firstEvent = dojo.connect(d, "onmousemove", this, "onFirstMove");
+ this.events = [
+ dojo.connect(d, "onmousemove", this, "onMouseMove"),
+ dojo.connect(d, "onmouseup", this, "onMouseUp"),
+ // cancel text selection and text dragging
+ dojo.connect(d, "ondragstart", dojo.stopEvent),
+ dojo.connect(d.body, "onselectstart", dojo.stopEvent),
+ firstEvent
+ ];
+ // notify that the move has started
+ if(h && h.onMoveStart){
+ h.onMoveStart(this);
+ }
+ },
+ // mouse event processors
+ onMouseMove: function(e){
+ // summary:
+ // event processor for onmousemove
+ // e: Event
+ // mouse event
+ dojo.dnd.autoScroll(e);
+ var m = this.marginBox;
+ this.host.onMove(this, {l: m.l + e.pageX, t: m.t + e.pageY}, e);
+ dojo.stopEvent(e);
+ },
+ onMouseUp: function(e){
+ if(dojo.isWebKit && dojo.isMac && this.mouseButton == 2 ?
+ e.button == 0 : this.mouseButton == e.button){
+ this.destroy();
+ }
+ dojo.stopEvent(e);
+ },
+ // utilities
+ onFirstMove: function(e){
+ // summary:
+ // makes the node absolute; it is meant to be called only once.
+ // relative and absolutely positioned nodes are assumed to use pixel units
+ var s = this.node.style, l, t, h = this.host;
+ switch(s.position){
+ case "relative":
+ case "absolute":
+ // assume that left and top values are in pixels already
+ l = Math.round(parseFloat(s.left)) || 0;
+ t = Math.round(parseFloat(s.top)) || 0;
+ break;
+ default:
+ s.position = "absolute"; // enforcing the absolute mode
+ var m = dojo.marginBox(this.node);
+ // event.pageX/pageY (which we used to generate the initial
+ // margin box) includes padding and margin set on the body.
+ // However, setting the node's position to absolute and then
+ // doing dojo.marginBox on it *doesn't* take that additional
+ // space into account - so we need to subtract the combined
+ // padding and margin. We use getComputedStyle and
+ // _getMarginBox/_getContentBox to avoid the extra lookup of
+ // the computed style.
+ var b = dojo.doc.body;
+ var bs = dojo.getComputedStyle(b);
+ var bm = dojo._getMarginBox(b, bs);
+ var bc = dojo._getContentBox(b, bs);
+ l = m.l - (bc.l - bm.l);
+ t = m.t - (bc.t - bm.t);
+ break;
+ }
+ this.marginBox.l = l - this.marginBox.l;
+ this.marginBox.t = t - this.marginBox.t;
+ if(h && h.onFirstMove){
+ h.onFirstMove(this, e);
+ }
+ dojo.disconnect(this.events.pop());
+ },
+ destroy: function(){
+ // summary:
+ // stops the move, deletes all references, so the object can be garbage-collected
+ dojo.forEach(this.events, dojo.disconnect);
+ // undo global settings
+ var h = this.host;
+ if(h && h.onMoveStop){
+ h.onMoveStop(this);
+ }
+ // destroy objects
+ this.events = this.node = this.host = null;
+ }
+});
+
}
diff --git a/lib/dojo/dnd/Selector.js b/lib/dojo/dnd/Selector.js
index 95c1bff47..9f13b75a0 100644
--- a/lib/dojo/dnd/Selector.js
+++ b/lib/dojo/dnd/Selector.js
@@ -5,235 +5,332 @@
*/
-if(!dojo._hasResource["dojo.dnd.Selector"]){
-dojo._hasResource["dojo.dnd.Selector"]=true;
+if(!dojo._hasResource["dojo.dnd.Selector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Selector"] = true;
dojo.provide("dojo.dnd.Selector");
+
dojo.require("dojo.dnd.common");
dojo.require("dojo.dnd.Container");
-dojo.declare("dojo.dnd.Selector",dojo.dnd.Container,{constructor:function(_1,_2){
-if(!_2){
-_2={};
-}
-this.singular=_2.singular;
-this.autoSync=_2.autoSync;
-this.selection={};
-this.anchor=null;
-this.simpleSelection=false;
-this.events.push(dojo.connect(this.node,"onmousedown",this,"onMouseDown"),dojo.connect(this.node,"onmouseup",this,"onMouseUp"));
-},singular:false,getSelectedNodes:function(){
-var t=new dojo.NodeList();
-var e=dojo.dnd._empty;
-for(var i in this.selection){
-if(i in e){
-continue;
-}
-t.push(dojo.byId(i));
-}
-return t;
-},selectNone:function(){
-return this._removeSelection()._removeAnchor();
-},selectAll:function(){
-this.forInItems(function(_3,id){
-this._addItemClass(dojo.byId(id),"Selected");
-this.selection[id]=1;
-},this);
-return this._removeAnchor();
-},deleteSelectedNodes:function(){
-var e=dojo.dnd._empty;
-for(var i in this.selection){
-if(i in e){
-continue;
-}
-var n=dojo.byId(i);
-this.delItem(i);
-dojo.destroy(n);
-}
-this.anchor=null;
-this.selection={};
-return this;
-},forInSelectedItems:function(f,o){
-o=o||dojo.global;
-var s=this.selection,e=dojo.dnd._empty;
-for(var i in s){
-if(i in e){
-continue;
-}
-f.call(o,this.getItem(i),i,this);
-}
-},sync:function(){
-dojo.dnd.Selector.superclass.sync.call(this);
-if(this.anchor){
-if(!this.getItem(this.anchor.id)){
-this.anchor=null;
-}
-}
-var t=[],e=dojo.dnd._empty;
-for(var i in this.selection){
-if(i in e){
-continue;
-}
-if(!this.getItem(i)){
-t.push(i);
-}
-}
-dojo.forEach(t,function(i){
-delete this.selection[i];
-},this);
-return this;
-},insertNodes:function(_4,_5,_6,_7){
-var _8=this._normalizedCreator;
-this._normalizedCreator=function(_9,_a){
-var t=_8.call(this,_9,_a);
-if(_4){
-if(!this.anchor){
-this.anchor=t.node;
-this._removeItemClass(t.node,"Selected");
-this._addItemClass(this.anchor,"Anchor");
-}else{
-if(this.anchor!=t.node){
-this._removeItemClass(t.node,"Anchor");
-this._addItemClass(t.node,"Selected");
-}
-}
-this.selection[t.node.id]=1;
-}else{
-this._removeItemClass(t.node,"Selected");
-this._removeItemClass(t.node,"Anchor");
-}
-return t;
-};
-dojo.dnd.Selector.superclass.insertNodes.call(this,_5,_6,_7);
-this._normalizedCreator=_8;
-return this;
-},destroy:function(){
-dojo.dnd.Selector.superclass.destroy.call(this);
-this.selection=this.anchor=null;
-},markupFactory:function(_b,_c){
-_b._skipStartup=true;
-return new dojo.dnd.Selector(_c,_b);
-},onMouseDown:function(e){
-if(this.autoSync){
-this.sync();
-}
-if(!this.current){
-return;
-}
-if(!this.singular&&!dojo.isCopyKey(e)&&!e.shiftKey&&(this.current.id in this.selection)){
-this.simpleSelection=true;
-if(e.button===dojo.mouseButtons.LEFT){
-dojo.stopEvent(e);
-}
-return;
-}
-if(!this.singular&&e.shiftKey){
-if(!dojo.isCopyKey(e)){
-this._removeSelection();
-}
-var c=this.getAllNodes();
-if(c.length){
-if(!this.anchor){
-this.anchor=c[0];
-this._addItemClass(this.anchor,"Anchor");
-}
-this.selection[this.anchor.id]=1;
-if(this.anchor!=this.current){
-var i=0;
-for(;i<c.length;++i){
-var _d=c[i];
-if(_d==this.anchor||_d==this.current){
-break;
-}
-}
-for(++i;i<c.length;++i){
-var _d=c[i];
-if(_d==this.anchor||_d==this.current){
-break;
-}
-this._addItemClass(_d,"Selected");
-this.selection[_d.id]=1;
-}
-this._addItemClass(this.current,"Selected");
-this.selection[this.current.id]=1;
-}
-}
-}else{
-if(this.singular){
-if(this.anchor==this.current){
-if(dojo.isCopyKey(e)){
-this.selectNone();
-}
-}else{
-this.selectNone();
-this.anchor=this.current;
-this._addItemClass(this.anchor,"Anchor");
-this.selection[this.current.id]=1;
-}
-}else{
-if(dojo.isCopyKey(e)){
-if(this.anchor==this.current){
-delete this.selection[this.anchor.id];
-this._removeAnchor();
-}else{
-if(this.current.id in this.selection){
-this._removeItemClass(this.current,"Selected");
-delete this.selection[this.current.id];
-}else{
-if(this.anchor){
-this._removeItemClass(this.anchor,"Anchor");
-this._addItemClass(this.anchor,"Selected");
-}
-this.anchor=this.current;
-this._addItemClass(this.current,"Anchor");
-this.selection[this.current.id]=1;
-}
-}
-}else{
-if(!(this.current.id in this.selection)){
-this.selectNone();
-this.anchor=this.current;
-this._addItemClass(this.current,"Anchor");
-this.selection[this.current.id]=1;
-}
-}
-}
-}
-dojo.stopEvent(e);
-},onMouseUp:function(e){
-if(!this.simpleSelection){
-return;
-}
-this.simpleSelection=false;
-this.selectNone();
-if(this.current){
-this.anchor=this.current;
-this._addItemClass(this.anchor,"Anchor");
-this.selection[this.current.id]=1;
-}
-},onMouseMove:function(e){
-this.simpleSelection=false;
-},onOverEvent:function(){
-this.onmousemoveEvent=dojo.connect(this.node,"onmousemove",this,"onMouseMove");
-},onOutEvent:function(){
-dojo.disconnect(this.onmousemoveEvent);
-delete this.onmousemoveEvent;
-},_removeSelection:function(){
-var e=dojo.dnd._empty;
-for(var i in this.selection){
-if(i in e){
-continue;
-}
-var _e=dojo.byId(i);
-if(_e){
-this._removeItemClass(_e,"Selected");
-}
-}
-this.selection={};
-return this;
-},_removeAnchor:function(){
-if(this.anchor){
-this._removeItemClass(this.anchor,"Anchor");
-this.anchor=null;
-}
-return this;
-}});
+
+/*
+ Container item states:
+ "" - an item is not selected
+ "Selected" - an item is selected
+ "Anchor" - an item is selected, and is an anchor for a "shift" selection
+*/
+
+/*=====
+dojo.declare("dojo.dnd.__SelectorArgs", [dojo.dnd.__ContainerArgs], {
+ // singular: Boolean
+ // allows selection of only one element, if true
+ singular: false,
+
+ // autoSync: Boolean
+ // autosynchronizes the source with its list of DnD nodes,
+ autoSync: false
+});
+=====*/
+
+dojo.declare("dojo.dnd.Selector", dojo.dnd.Container, {
+ // summary:
+ // a Selector object, which knows how to select its children
+
+ /*=====
+ // selection: Set<String>
+ // The set of id's that are currently selected, such that this.selection[id] == 1
+ // if the node w/that id is selected. Can iterate over selected node's id's like:
+ // | for(var id in this.selection)
+ selection: {},
+ =====*/
+
+ constructor: function(node, params){
+ // summary:
+ // constructor of the Selector
+ // node: Node||String
+ // node or node's id to build the selector on
+ // params: dojo.dnd.__SelectorArgs?
+ // a dictionary of parameters
+ if(!params){ params = {}; }
+ this.singular = params.singular;
+ this.autoSync = params.autoSync;
+ // class-specific variables
+ this.selection = {};
+ this.anchor = null;
+ this.simpleSelection = false;
+ // set up events
+ this.events.push(
+ dojo.connect(this.node, "onmousedown", this, "onMouseDown"),
+ dojo.connect(this.node, "onmouseup", this, "onMouseUp"));
+ },
+
+ // object attributes (for markup)
+ singular: false, // is singular property
+
+ // methods
+ getSelectedNodes: function(){
+ // summary:
+ // returns a list (an array) of selected nodes
+ var t = new dojo.NodeList();
+ var e = dojo.dnd._empty;
+ for(var i in this.selection){
+ if(i in e){ continue; }
+ t.push(dojo.byId(i));
+ }
+ return t; // NodeList
+ },
+ selectNone: function(){
+ // summary:
+ // unselects all items
+ return this._removeSelection()._removeAnchor(); // self
+ },
+ selectAll: function(){
+ // summary:
+ // selects all items
+ this.forInItems(function(data, id){
+ this._addItemClass(dojo.byId(id), "Selected");
+ this.selection[id] = 1;
+ }, this);
+ return this._removeAnchor(); // self
+ },
+ deleteSelectedNodes: function(){
+ // summary:
+ // deletes all selected items
+ var e = dojo.dnd._empty;
+ for(var i in this.selection){
+ if(i in e){ continue; }
+ var n = dojo.byId(i);
+ this.delItem(i);
+ dojo.destroy(n);
+ }
+ this.anchor = null;
+ this.selection = {};
+ return this; // self
+ },
+ forInSelectedItems: function(/*Function*/ f, /*Object?*/ o){
+ // summary:
+ // iterates over selected items;
+ // see `dojo.dnd.Container.forInItems()` for details
+ o = o || dojo.global;
+ var s = this.selection, e = dojo.dnd._empty;
+ for(var i in s){
+ if(i in e){ continue; }
+ f.call(o, this.getItem(i), i, this);
+ }
+ },
+ sync: function(){
+ // summary:
+ // sync up the node list with the data map
+
+ dojo.dnd.Selector.superclass.sync.call(this);
+
+ // fix the anchor
+ if(this.anchor){
+ if(!this.getItem(this.anchor.id)){
+ this.anchor = null;
+ }
+ }
+
+ // fix the selection
+ var t = [], e = dojo.dnd._empty;
+ for(var i in this.selection){
+ if(i in e){ continue; }
+ if(!this.getItem(i)){
+ t.push(i);
+ }
+ }
+ dojo.forEach(t, function(i){
+ delete this.selection[i];
+ }, this);
+
+ return this; // self
+ },
+ insertNodes: function(addSelected, data, before, anchor){
+ // summary:
+ // inserts new data items (see `dojo.dnd.Container.insertNodes()` method for details)
+ // addSelected: Boolean
+ // all new nodes will be added to selected items, if true, no selection change otherwise
+ // data: Array
+ // a list of data items, which should be processed by the creator function
+ // before: Boolean
+ // insert before the anchor, if true, and after the anchor otherwise
+ // anchor: Node
+ // the anchor node to be used as a point of insertion
+ var oldCreator = this._normalizedCreator;
+ this._normalizedCreator = function(item, hint){
+ var t = oldCreator.call(this, item, hint);
+ if(addSelected){
+ if(!this.anchor){
+ this.anchor = t.node;
+ this._removeItemClass(t.node, "Selected");
+ this._addItemClass(this.anchor, "Anchor");
+ }else if(this.anchor != t.node){
+ this._removeItemClass(t.node, "Anchor");
+ this._addItemClass(t.node, "Selected");
+ }
+ this.selection[t.node.id] = 1;
+ }else{
+ this._removeItemClass(t.node, "Selected");
+ this._removeItemClass(t.node, "Anchor");
+ }
+ return t;
+ };
+ dojo.dnd.Selector.superclass.insertNodes.call(this, data, before, anchor);
+ this._normalizedCreator = oldCreator;
+ return this; // self
+ },
+ destroy: function(){
+ // summary:
+ // prepares the object to be garbage-collected
+ dojo.dnd.Selector.superclass.destroy.call(this);
+ this.selection = this.anchor = null;
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ params._skipStartup = true;
+ return new dojo.dnd.Selector(node, params);
+ },
+
+ // mouse events
+ onMouseDown: function(e){
+ // summary:
+ // event processor for onmousedown
+ // e: Event
+ // mouse event
+ if(this.autoSync){ this.sync(); }
+ if(!this.current){ return; }
+ if(!this.singular && !dojo.isCopyKey(e) && !e.shiftKey && (this.current.id in this.selection)){
+ this.simpleSelection = true;
+ if(e.button === dojo.mouseButtons.LEFT){
+ // accept the left button and stop the event
+ // for IE we don't stop event when multiple buttons are pressed
+ dojo.stopEvent(e);
+ }
+ return;
+ }
+ if(!this.singular && e.shiftKey){
+ if(!dojo.isCopyKey(e)){
+ this._removeSelection();
+ }
+ var c = this.getAllNodes();
+ if(c.length){
+ if(!this.anchor){
+ this.anchor = c[0];
+ this._addItemClass(this.anchor, "Anchor");
+ }
+ this.selection[this.anchor.id] = 1;
+ if(this.anchor != this.current){
+ var i = 0;
+ for(; i < c.length; ++i){
+ var node = c[i];
+ if(node == this.anchor || node == this.current){ break; }
+ }
+ for(++i; i < c.length; ++i){
+ var node = c[i];
+ if(node == this.anchor || node == this.current){ break; }
+ this._addItemClass(node, "Selected");
+ this.selection[node.id] = 1;
+ }
+ this._addItemClass(this.current, "Selected");
+ this.selection[this.current.id] = 1;
+ }
+ }
+ }else{
+ if(this.singular){
+ if(this.anchor == this.current){
+ if(dojo.isCopyKey(e)){
+ this.selectNone();
+ }
+ }else{
+ this.selectNone();
+ this.anchor = this.current;
+ this._addItemClass(this.anchor, "Anchor");
+ this.selection[this.current.id] = 1;
+ }
+ }else{
+ if(dojo.isCopyKey(e)){
+ if(this.anchor == this.current){
+ delete this.selection[this.anchor.id];
+ this._removeAnchor();
+ }else{
+ if(this.current.id in this.selection){
+ this._removeItemClass(this.current, "Selected");
+ delete this.selection[this.current.id];
+ }else{
+ if(this.anchor){
+ this._removeItemClass(this.anchor, "Anchor");
+ this._addItemClass(this.anchor, "Selected");
+ }
+ this.anchor = this.current;
+ this._addItemClass(this.current, "Anchor");
+ this.selection[this.current.id] = 1;
+ }
+ }
+ }else{
+ if(!(this.current.id in this.selection)){
+ this.selectNone();
+ this.anchor = this.current;
+ this._addItemClass(this.current, "Anchor");
+ this.selection[this.current.id] = 1;
+ }
+ }
+ }
+ }
+ dojo.stopEvent(e);
+ },
+ onMouseUp: function(e){
+ // summary:
+ // event processor for onmouseup
+ // e: Event
+ // mouse event
+ if(!this.simpleSelection){ return; }
+ this.simpleSelection = false;
+ this.selectNone();
+ if(this.current){
+ this.anchor = this.current;
+ this._addItemClass(this.anchor, "Anchor");
+ this.selection[this.current.id] = 1;
+ }
+ },
+ onMouseMove: function(e){
+ // summary
+ // event processor for onmousemove
+ // e: Event
+ // mouse event
+ this.simpleSelection = false;
+ },
+
+ // utilities
+ onOverEvent: function(){
+ // summary:
+ // this function is called once, when mouse is over our container
+ this.onmousemoveEvent = dojo.connect(this.node, "onmousemove", this, "onMouseMove");
+ },
+ onOutEvent: function(){
+ // summary:
+ // this function is called once, when mouse is out of our container
+ dojo.disconnect(this.onmousemoveEvent);
+ delete this.onmousemoveEvent;
+ },
+ _removeSelection: function(){
+ // summary:
+ // unselects all items
+ var e = dojo.dnd._empty;
+ for(var i in this.selection){
+ if(i in e){ continue; }
+ var node = dojo.byId(i);
+ if(node){ this._removeItemClass(node, "Selected"); }
+ }
+ this.selection = {};
+ return this; // self
+ },
+ _removeAnchor: function(){
+ if(this.anchor){
+ this._removeItemClass(this.anchor, "Anchor");
+ this.anchor = null;
+ }
+ return this; // self
+ }
+});
+
}
diff --git a/lib/dojo/dnd/Source.js b/lib/dojo/dnd/Source.js
index fb05eb048..8e5c55dbc 100644
--- a/lib/dojo/dnd/Source.js
+++ b/lib/dojo/dnd/Source.js
@@ -5,294 +5,545 @@
*/
-if(!dojo._hasResource["dojo.dnd.Source"]){
-dojo._hasResource["dojo.dnd.Source"]=true;
+if(!dojo._hasResource["dojo.dnd.Source"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Source"] = true;
dojo.provide("dojo.dnd.Source");
+
dojo.require("dojo.dnd.Selector");
dojo.require("dojo.dnd.Manager");
-dojo.declare("dojo.dnd.Source",dojo.dnd.Selector,{isSource:true,horizontal:false,copyOnly:false,selfCopy:false,selfAccept:true,skipForm:false,withHandles:false,autoSync:false,delay:0,accept:["text"],generateText:true,constructor:function(_1,_2){
-dojo.mixin(this,dojo.mixin({},_2));
-var _3=this.accept;
-if(_3.length){
-this.accept={};
-for(var i=0;i<_3.length;++i){
-this.accept[_3[i]]=1;
-}
-}
-this.isDragging=false;
-this.mouseDown=false;
-this.targetAnchor=null;
-this.targetBox=null;
-this.before=true;
-this._lastX=0;
-this._lastY=0;
-this.sourceState="";
-if(this.isSource){
-dojo.addClass(this.node,"dojoDndSource");
-}
-this.targetState="";
-if(this.accept){
-dojo.addClass(this.node,"dojoDndTarget");
-}
-if(this.horizontal){
-dojo.addClass(this.node,"dojoDndHorizontal");
-}
-this.topics=[dojo.subscribe("/dnd/source/over",this,"onDndSourceOver"),dojo.subscribe("/dnd/start",this,"onDndStart"),dojo.subscribe("/dnd/drop",this,"onDndDrop"),dojo.subscribe("/dnd/cancel",this,"onDndCancel")];
-},checkAcceptance:function(_4,_5){
-if(this==_4){
-return !this.copyOnly||this.selfAccept;
-}
-for(var i=0;i<_5.length;++i){
-var _6=_4.getItem(_5[i].id).type;
-var _7=false;
-for(var j=0;j<_6.length;++j){
-if(_6[j] in this.accept){
-_7=true;
-break;
-}
-}
-if(!_7){
-return false;
-}
-}
-return true;
-},copyState:function(_8,_9){
-if(_8){
-return true;
-}
-if(arguments.length<2){
-_9=this==dojo.dnd.manager().target;
-}
-if(_9){
-if(this.copyOnly){
-return this.selfCopy;
-}
-}else{
-return this.copyOnly;
-}
-return false;
-},destroy:function(){
-dojo.dnd.Source.superclass.destroy.call(this);
-dojo.forEach(this.topics,dojo.unsubscribe);
-this.targetAnchor=null;
-},markupFactory:function(_a,_b){
-_a._skipStartup=true;
-return new dojo.dnd.Source(_b,_a);
-},onMouseMove:function(e){
-if(this.isDragging&&this.targetState=="Disabled"){
-return;
-}
-dojo.dnd.Source.superclass.onMouseMove.call(this,e);
-var m=dojo.dnd.manager();
-if(!this.isDragging){
-if(this.mouseDown&&this.isSource&&(Math.abs(e.pageX-this._lastX)>this.delay||Math.abs(e.pageY-this._lastY)>this.delay)){
-var _c=this.getSelectedNodes();
-if(_c.length){
-m.startDrag(this,_c,this.copyState(dojo.isCopyKey(e),true));
-}
-}
-}
-if(this.isDragging){
-var _d=false;
-if(this.current){
-if(!this.targetBox||this.targetAnchor!=this.current){
-this.targetBox=dojo.position(this.current,true);
-}
-if(this.horizontal){
-_d=(e.pageX-this.targetBox.x)<(this.targetBox.w/2);
-}else{
-_d=(e.pageY-this.targetBox.y)<(this.targetBox.h/2);
-}
-}
-if(this.current!=this.targetAnchor||_d!=this.before){
-this._markTargetAnchor(_d);
-m.canDrop(!this.current||m.source!=this||!(this.current.id in this.selection));
-}
-}
-},onMouseDown:function(e){
-if(!this.mouseDown&&this._legalMouseDown(e)&&(!this.skipForm||!dojo.dnd.isFormElement(e))){
-this.mouseDown=true;
-this._lastX=e.pageX;
-this._lastY=e.pageY;
-dojo.dnd.Source.superclass.onMouseDown.call(this,e);
-}
-},onMouseUp:function(e){
-if(this.mouseDown){
-this.mouseDown=false;
-dojo.dnd.Source.superclass.onMouseUp.call(this,e);
-}
-},onDndSourceOver:function(_e){
-if(this!=_e){
-this.mouseDown=false;
-if(this.targetAnchor){
-this._unmarkTargetAnchor();
-}
-}else{
-if(this.isDragging){
-var m=dojo.dnd.manager();
-m.canDrop(this.targetState!="Disabled"&&(!this.current||m.source!=this||!(this.current.id in this.selection)));
-}
-}
-},onDndStart:function(_f,_10,_11){
-if(this.autoSync){
-this.sync();
-}
-if(this.isSource){
-this._changeState("Source",this==_f?(_11?"Copied":"Moved"):"");
-}
-var _12=this.accept&&this.checkAcceptance(_f,_10);
-this._changeState("Target",_12?"":"Disabled");
-if(this==_f){
-dojo.dnd.manager().overSource(this);
-}
-this.isDragging=true;
-},onDndDrop:function(_13,_14,_15,_16){
-if(this==_16){
-this.onDrop(_13,_14,_15);
-}
-this.onDndCancel();
-},onDndCancel:function(){
-if(this.targetAnchor){
-this._unmarkTargetAnchor();
-this.targetAnchor=null;
-}
-this.before=true;
-this.isDragging=false;
-this.mouseDown=false;
-this._changeState("Source","");
-this._changeState("Target","");
-},onDrop:function(_17,_18,_19){
-if(this!=_17){
-this.onDropExternal(_17,_18,_19);
-}else{
-this.onDropInternal(_18,_19);
-}
-},onDropExternal:function(_1a,_1b,_1c){
-var _1d=this._normalizedCreator;
-if(this.creator){
-this._normalizedCreator=function(_1e,_1f){
-return _1d.call(this,_1a.getItem(_1e.id).data,_1f);
-};
-}else{
-if(_1c){
-this._normalizedCreator=function(_20,_21){
-var t=_1a.getItem(_20.id);
-var n=_20.cloneNode(true);
-n.id=dojo.dnd.getUniqueId();
-return {node:n,data:t.data,type:t.type};
-};
-}else{
-this._normalizedCreator=function(_22,_23){
-var t=_1a.getItem(_22.id);
-_1a.delItem(_22.id);
-return {node:_22,data:t.data,type:t.type};
-};
-}
-}
-this.selectNone();
-if(!_1c&&!this.creator){
-_1a.selectNone();
-}
-this.insertNodes(true,_1b,this.before,this.current);
-if(!_1c&&this.creator){
-_1a.deleteSelectedNodes();
-}
-this._normalizedCreator=_1d;
-},onDropInternal:function(_24,_25){
-var _26=this._normalizedCreator;
-if(this.current&&this.current.id in this.selection){
-return;
-}
-if(_25){
-if(this.creator){
-this._normalizedCreator=function(_27,_28){
-return _26.call(this,this.getItem(_27.id).data,_28);
-};
-}else{
-this._normalizedCreator=function(_29,_2a){
-var t=this.getItem(_29.id);
-var n=_29.cloneNode(true);
-n.id=dojo.dnd.getUniqueId();
-return {node:n,data:t.data,type:t.type};
-};
-}
-}else{
-if(!this.current){
-return;
-}
-this._normalizedCreator=function(_2b,_2c){
-var t=this.getItem(_2b.id);
-return {node:_2b,data:t.data,type:t.type};
-};
-}
-this._removeSelection();
-this.insertNodes(true,_24,this.before,this.current);
-this._normalizedCreator=_26;
-},onDraggingOver:function(){
-},onDraggingOut:function(){
-},onOverEvent:function(){
-dojo.dnd.Source.superclass.onOverEvent.call(this);
-dojo.dnd.manager().overSource(this);
-if(this.isDragging&&this.targetState!="Disabled"){
-this.onDraggingOver();
-}
-},onOutEvent:function(){
-dojo.dnd.Source.superclass.onOutEvent.call(this);
-dojo.dnd.manager().outSource(this);
-if(this.isDragging&&this.targetState!="Disabled"){
-this.onDraggingOut();
-}
-},_markTargetAnchor:function(_2d){
-if(this.current==this.targetAnchor&&this.before==_2d){
-return;
-}
-if(this.targetAnchor){
-this._removeItemClass(this.targetAnchor,this.before?"Before":"After");
-}
-this.targetAnchor=this.current;
-this.targetBox=null;
-this.before=_2d;
-if(this.targetAnchor){
-this._addItemClass(this.targetAnchor,this.before?"Before":"After");
-}
-},_unmarkTargetAnchor:function(){
-if(!this.targetAnchor){
-return;
-}
-this._removeItemClass(this.targetAnchor,this.before?"Before":"After");
-this.targetAnchor=null;
-this.targetBox=null;
-this.before=true;
-},_markDndStatus:function(_2e){
-this._changeState("Source",_2e?"Copied":"Moved");
-},_legalMouseDown:function(e){
-if(!dojo.mouseButtons.isLeft(e)){
-return false;
-}
-if(!this.withHandles){
-return true;
-}
-for(var _2f=e.target;_2f&&_2f!==this.node;_2f=_2f.parentNode){
-if(dojo.hasClass(_2f,"dojoDndHandle")){
-return true;
-}
-if(dojo.hasClass(_2f,"dojoDndItem")||dojo.hasClass(_2f,"dojoDndIgnore")){
-break;
-}
-}
-return false;
-}});
-dojo.declare("dojo.dnd.Target",dojo.dnd.Source,{constructor:function(_30,_31){
-this.isSource=false;
-dojo.removeClass(this.node,"dojoDndSource");
-},markupFactory:function(_32,_33){
-_32._skipStartup=true;
-return new dojo.dnd.Target(_33,_32);
-}});
-dojo.declare("dojo.dnd.AutoSource",dojo.dnd.Source,{constructor:function(_34,_35){
-this.autoSync=true;
-},markupFactory:function(_36,_37){
-_36._skipStartup=true;
-return new dojo.dnd.AutoSource(_37,_36);
-}});
+
+/*
+ Container property:
+ "Horizontal"- if this is the horizontal container
+ Source states:
+ "" - normal state
+ "Moved" - this source is being moved
+ "Copied" - this source is being copied
+ Target states:
+ "" - normal state
+ "Disabled" - the target cannot accept an avatar
+ Target anchor state:
+ "" - item is not selected
+ "Before" - insert point is before the anchor
+ "After" - insert point is after the anchor
+*/
+
+/*=====
+dojo.dnd.__SourceArgs = function(){
+ // summary:
+ // a dict of parameters for DnD Source configuration. Note that any
+ // property on Source elements may be configured, but this is the
+ // short-list
+ // isSource: Boolean?
+ // can be used as a DnD source. Defaults to true.
+ // accept: Array?
+ // list of accepted types (text strings) for a target; defaults to
+ // ["text"]
+ // autoSync: Boolean
+ // if true refreshes the node list on every operation; false by default
+ // copyOnly: Boolean?
+ // copy items, if true, use a state of Ctrl key otherwise,
+ // see selfCopy and selfAccept for more details
+ // delay: Number
+ // the move delay in pixels before detecting a drag; 0 by default
+ // horizontal: Boolean?
+ // a horizontal container, if true, vertical otherwise or when omitted
+ // selfCopy: Boolean?
+ // copy items by default when dropping on itself,
+ // false by default, works only if copyOnly is true
+ // selfAccept: Boolean?
+ // accept its own items when copyOnly is true,
+ // true by default, works only if copyOnly is true
+ // withHandles: Boolean?
+ // allows dragging only by handles, false by default
+ // generateText: Boolean?
+ // generate text node for drag and drop, true by default
+ this.isSource = isSource;
+ this.accept = accept;
+ this.autoSync = autoSync;
+ this.copyOnly = copyOnly;
+ this.delay = delay;
+ this.horizontal = horizontal;
+ this.selfCopy = selfCopy;
+ this.selfAccept = selfAccept;
+ this.withHandles = withHandles;
+ this.generateText = true;
+}
+=====*/
+
+dojo.declare("dojo.dnd.Source", dojo.dnd.Selector, {
+ // summary:
+ // a Source object, which can be used as a DnD source, or a DnD target
+
+ // object attributes (for markup)
+ isSource: true,
+ horizontal: false,
+ copyOnly: false,
+ selfCopy: false,
+ selfAccept: true,
+ skipForm: false,
+ withHandles: false,
+ autoSync: false,
+ delay: 0, // pixels
+ accept: ["text"],
+ generateText: true,
+
+ constructor: function(/*DOMNode|String*/node, /*dojo.dnd.__SourceArgs?*/params){
+ // summary:
+ // a constructor of the Source
+ // node:
+ // node or node's id to build the source on
+ // params:
+ // any property of this class may be configured via the params
+ // object which is mixed-in to the `dojo.dnd.Source` instance
+ dojo.mixin(this, dojo.mixin({}, params));
+ var type = this.accept;
+ if(type.length){
+ this.accept = {};
+ for(var i = 0; i < type.length; ++i){
+ this.accept[type[i]] = 1;
+ }
+ }
+ // class-specific variables
+ this.isDragging = false;
+ this.mouseDown = false;
+ this.targetAnchor = null;
+ this.targetBox = null;
+ this.before = true;
+ this._lastX = 0;
+ this._lastY = 0;
+ // states
+ this.sourceState = "";
+ if(this.isSource){
+ dojo.addClass(this.node, "dojoDndSource");
+ }
+ this.targetState = "";
+ if(this.accept){
+ dojo.addClass(this.node, "dojoDndTarget");
+ }
+ if(this.horizontal){
+ dojo.addClass(this.node, "dojoDndHorizontal");
+ }
+ // set up events
+ this.topics = [
+ dojo.subscribe("/dnd/source/over", this, "onDndSourceOver"),
+ dojo.subscribe("/dnd/start", this, "onDndStart"),
+ dojo.subscribe("/dnd/drop", this, "onDndDrop"),
+ dojo.subscribe("/dnd/cancel", this, "onDndCancel")
+ ];
+ },
+
+ // methods
+ checkAcceptance: function(source, nodes){
+ // summary:
+ // checks if the target can accept nodes from this source
+ // source: Object
+ // the source which provides items
+ // nodes: Array
+ // the list of transferred items
+ if(this == source){
+ return !this.copyOnly || this.selfAccept;
+ }
+ for(var i = 0; i < nodes.length; ++i){
+ var type = source.getItem(nodes[i].id).type;
+ // type instanceof Array
+ var flag = false;
+ for(var j = 0; j < type.length; ++j){
+ if(type[j] in this.accept){
+ flag = true;
+ break;
+ }
+ }
+ if(!flag){
+ return false; // Boolean
+ }
+ }
+ return true; // Boolean
+ },
+ copyState: function(keyPressed, self){
+ // summary:
+ // Returns true if we need to copy items, false to move.
+ // It is separated to be overwritten dynamically, if needed.
+ // keyPressed: Boolean
+ // the "copy" key was pressed
+ // self: Boolean?
+ // optional flag that means that we are about to drop on itself
+
+ if(keyPressed){ return true; }
+ if(arguments.length < 2){
+ self = this == dojo.dnd.manager().target;
+ }
+ if(self){
+ if(this.copyOnly){
+ return this.selfCopy;
+ }
+ }else{
+ return this.copyOnly;
+ }
+ return false; // Boolean
+ },
+ destroy: function(){
+ // summary:
+ // prepares the object to be garbage-collected
+ dojo.dnd.Source.superclass.destroy.call(this);
+ dojo.forEach(this.topics, dojo.unsubscribe);
+ this.targetAnchor = null;
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ params._skipStartup = true;
+ return new dojo.dnd.Source(node, params);
+ },
+
+ // mouse event processors
+ onMouseMove: function(e){
+ // summary:
+ // event processor for onmousemove
+ // e: Event
+ // mouse event
+ if(this.isDragging && this.targetState == "Disabled"){ return; }
+ dojo.dnd.Source.superclass.onMouseMove.call(this, e);
+ var m = dojo.dnd.manager();
+ if(!this.isDragging){
+ if(this.mouseDown && this.isSource &&
+ (Math.abs(e.pageX - this._lastX) > this.delay || Math.abs(e.pageY - this._lastY) > this.delay)){
+ var nodes = this.getSelectedNodes();
+ if(nodes.length){
+ m.startDrag(this, nodes, this.copyState(dojo.isCopyKey(e), true));
+ }
+ }
+ }
+ if(this.isDragging){
+ // calculate before/after
+ var before = false;
+ if(this.current){
+ if(!this.targetBox || this.targetAnchor != this.current){
+ this.targetBox = dojo.position(this.current, true);
+ }
+ if(this.horizontal){
+ before = (e.pageX - this.targetBox.x) < (this.targetBox.w / 2);
+ }else{
+ before = (e.pageY - this.targetBox.y) < (this.targetBox.h / 2);
+ }
+ }
+ if(this.current != this.targetAnchor || before != this.before){
+ this._markTargetAnchor(before);
+ m.canDrop(!this.current || m.source != this || !(this.current.id in this.selection));
+ }
+ }
+ },
+ onMouseDown: function(e){
+ // summary:
+ // event processor for onmousedown
+ // e: Event
+ // mouse event
+ if(!this.mouseDown && this._legalMouseDown(e) && (!this.skipForm || !dojo.dnd.isFormElement(e))){
+ this.mouseDown = true;
+ this._lastX = e.pageX;
+ this._lastY = e.pageY;
+ dojo.dnd.Source.superclass.onMouseDown.call(this, e);
+ }
+ },
+ onMouseUp: function(e){
+ // summary:
+ // event processor for onmouseup
+ // e: Event
+ // mouse event
+ if(this.mouseDown){
+ this.mouseDown = false;
+ dojo.dnd.Source.superclass.onMouseUp.call(this, e);
+ }
+ },
+
+ // topic event processors
+ onDndSourceOver: function(source){
+ // summary:
+ // topic event processor for /dnd/source/over, called when detected a current source
+ // source: Object
+ // the source which has the mouse over it
+ if(this != source){
+ this.mouseDown = false;
+ if(this.targetAnchor){
+ this._unmarkTargetAnchor();
+ }
+ }else if(this.isDragging){
+ var m = dojo.dnd.manager();
+ m.canDrop(this.targetState != "Disabled" && (!this.current || m.source != this || !(this.current.id in this.selection)));
+ }
+ },
+ onDndStart: function(source, nodes, copy){
+ // summary:
+ // topic event processor for /dnd/start, called to initiate the DnD operation
+ // source: Object
+ // the source which provides items
+ // nodes: Array
+ // the list of transferred items
+ // copy: Boolean
+ // copy items, if true, move items otherwise
+ if(this.autoSync){ this.sync(); }
+ if(this.isSource){
+ this._changeState("Source", this == source ? (copy ? "Copied" : "Moved") : "");
+ }
+ var accepted = this.accept && this.checkAcceptance(source, nodes);
+ this._changeState("Target", accepted ? "" : "Disabled");
+ if(this == source){
+ dojo.dnd.manager().overSource(this);
+ }
+ this.isDragging = true;
+ },
+ onDndDrop: function(source, nodes, copy, target){
+ // summary:
+ // topic event processor for /dnd/drop, called to finish the DnD operation
+ // source: Object
+ // the source which provides items
+ // nodes: Array
+ // the list of transferred items
+ // copy: Boolean
+ // copy items, if true, move items otherwise
+ // target: Object
+ // the target which accepts items
+ if(this == target){
+ // this one is for us => move nodes!
+ this.onDrop(source, nodes, copy);
+ }
+ this.onDndCancel();
+ },
+ onDndCancel: function(){
+ // summary:
+ // topic event processor for /dnd/cancel, called to cancel the DnD operation
+ if(this.targetAnchor){
+ this._unmarkTargetAnchor();
+ this.targetAnchor = null;
+ }
+ this.before = true;
+ this.isDragging = false;
+ this.mouseDown = false;
+ this._changeState("Source", "");
+ this._changeState("Target", "");
+ },
+
+ // local events
+ onDrop: function(source, nodes, copy){
+ // summary:
+ // called only on the current target, when drop is performed
+ // source: Object
+ // the source which provides items
+ // nodes: Array
+ // the list of transferred items
+ // copy: Boolean
+ // copy items, if true, move items otherwise
+
+ if(this != source){
+ this.onDropExternal(source, nodes, copy);
+ }else{
+ this.onDropInternal(nodes, copy);
+ }
+ },
+ onDropExternal: function(source, nodes, copy){
+ // summary:
+ // called only on the current target, when drop is performed
+ // from an external source
+ // source: Object
+ // the source which provides items
+ // nodes: Array
+ // the list of transferred items
+ // copy: Boolean
+ // copy items, if true, move items otherwise
+
+ var oldCreator = this._normalizedCreator;
+ // transferring nodes from the source to the target
+ if(this.creator){
+ // use defined creator
+ this._normalizedCreator = function(node, hint){
+ return oldCreator.call(this, source.getItem(node.id).data, hint);
+ };
+ }else{
+ // we have no creator defined => move/clone nodes
+ if(copy){
+ // clone nodes
+ this._normalizedCreator = function(node, hint){
+ var t = source.getItem(node.id);
+ var n = node.cloneNode(true);
+ n.id = dojo.dnd.getUniqueId();
+ return {node: n, data: t.data, type: t.type};
+ };
+ }else{
+ // move nodes
+ this._normalizedCreator = function(node, hint){
+ var t = source.getItem(node.id);
+ source.delItem(node.id);
+ return {node: node, data: t.data, type: t.type};
+ };
+ }
+ }
+ this.selectNone();
+ if(!copy && !this.creator){
+ source.selectNone();
+ }
+ this.insertNodes(true, nodes, this.before, this.current);
+ if(!copy && this.creator){
+ source.deleteSelectedNodes();
+ }
+ this._normalizedCreator = oldCreator;
+ },
+ onDropInternal: function(nodes, copy){
+ // summary:
+ // called only on the current target, when drop is performed
+ // from the same target/source
+ // nodes: Array
+ // the list of transferred items
+ // copy: Boolean
+ // copy items, if true, move items otherwise
+
+ var oldCreator = this._normalizedCreator;
+ // transferring nodes within the single source
+ if(this.current && this.current.id in this.selection){
+ // do nothing
+ return;
+ }
+ if(copy){
+ if(this.creator){
+ // create new copies of data items
+ this._normalizedCreator = function(node, hint){
+ return oldCreator.call(this, this.getItem(node.id).data, hint);
+ };
+ }else{
+ // clone nodes
+ this._normalizedCreator = function(node, hint){
+ var t = this.getItem(node.id);
+ var n = node.cloneNode(true);
+ n.id = dojo.dnd.getUniqueId();
+ return {node: n, data: t.data, type: t.type};
+ };
+ }
+ }else{
+ // move nodes
+ if(!this.current){
+ // do nothing
+ return;
+ }
+ this._normalizedCreator = function(node, hint){
+ var t = this.getItem(node.id);
+ return {node: node, data: t.data, type: t.type};
+ };
+ }
+ this._removeSelection();
+ this.insertNodes(true, nodes, this.before, this.current);
+ this._normalizedCreator = oldCreator;
+ },
+ onDraggingOver: function(){
+ // summary:
+ // called during the active DnD operation, when items
+ // are dragged over this target, and it is not disabled
+ },
+ onDraggingOut: function(){
+ // summary:
+ // called during the active DnD operation, when items
+ // are dragged away from this target, and it is not disabled
+ },
+
+ // utilities
+ onOverEvent: function(){
+ // summary:
+ // this function is called once, when mouse is over our container
+ dojo.dnd.Source.superclass.onOverEvent.call(this);
+ dojo.dnd.manager().overSource(this);
+ if(this.isDragging && this.targetState != "Disabled"){
+ this.onDraggingOver();
+ }
+ },
+ onOutEvent: function(){
+ // summary:
+ // this function is called once, when mouse is out of our container
+ dojo.dnd.Source.superclass.onOutEvent.call(this);
+ dojo.dnd.manager().outSource(this);
+ if(this.isDragging && this.targetState != "Disabled"){
+ this.onDraggingOut();
+ }
+ },
+ _markTargetAnchor: function(before){
+ // summary:
+ // assigns a class to the current target anchor based on "before" status
+ // before: Boolean
+ // insert before, if true, after otherwise
+ if(this.current == this.targetAnchor && this.before == before){ return; }
+ if(this.targetAnchor){
+ this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");
+ }
+ this.targetAnchor = this.current;
+ this.targetBox = null;
+ this.before = before;
+ if(this.targetAnchor){
+ this._addItemClass(this.targetAnchor, this.before ? "Before" : "After");
+ }
+ },
+ _unmarkTargetAnchor: function(){
+ // summary:
+ // removes a class of the current target anchor based on "before" status
+ if(!this.targetAnchor){ return; }
+ this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");
+ this.targetAnchor = null;
+ this.targetBox = null;
+ this.before = true;
+ },
+ _markDndStatus: function(copy){
+ // summary:
+ // changes source's state based on "copy" status
+ this._changeState("Source", copy ? "Copied" : "Moved");
+ },
+ _legalMouseDown: function(e){
+ // summary:
+ // checks if user clicked on "approved" items
+ // e: Event
+ // mouse event
+
+ // accept only the left mouse button
+ if(!dojo.mouseButtons.isLeft(e)){ return false; }
+
+ if(!this.withHandles){ return true; }
+
+ // check for handles
+ for(var node = e.target; node && node !== this.node; node = node.parentNode){
+ if(dojo.hasClass(node, "dojoDndHandle")){ return true; }
+ if(dojo.hasClass(node, "dojoDndItem") || dojo.hasClass(node, "dojoDndIgnore")){ break; }
+ }
+ return false; // Boolean
+ }
+});
+
+dojo.declare("dojo.dnd.Target", dojo.dnd.Source, {
+ // summary: a Target object, which can be used as a DnD target
+
+ constructor: function(node, params){
+ // summary:
+ // a constructor of the Target --- see the `dojo.dnd.Source.constructor` for details
+ this.isSource = false;
+ dojo.removeClass(this.node, "dojoDndSource");
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ params._skipStartup = true;
+ return new dojo.dnd.Target(node, params);
+ }
+});
+
+dojo.declare("dojo.dnd.AutoSource", dojo.dnd.Source, {
+ // summary:
+ // a source that syncs its DnD nodes by default
+
+ constructor: function(node, params){
+ // summary:
+ // constructor of the AutoSource --- see the Source constructor for details
+ this.autoSync = true;
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ params._skipStartup = true;
+ return new dojo.dnd.AutoSource(node, params);
+ }
+});
+
}
diff --git a/lib/dojo/dnd/TimedMoveable.js b/lib/dojo/dnd/TimedMoveable.js
index 05609a379..25a101e20 100644
--- a/lib/dojo/dnd/TimedMoveable.js
+++ b/lib/dojo/dnd/TimedMoveable.js
@@ -5,36 +5,77 @@
*/
-if(!dojo._hasResource["dojo.dnd.TimedMoveable"]){
-dojo._hasResource["dojo.dnd.TimedMoveable"]=true;
+if(!dojo._hasResource["dojo.dnd.TimedMoveable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.TimedMoveable"] = true;
dojo.provide("dojo.dnd.TimedMoveable");
+
dojo.require("dojo.dnd.Moveable");
+
+/*=====
+dojo.declare("dojo.dnd.__TimedMoveableArgs", [dojo.dnd.__MoveableArgs], {
+ // timeout: Number
+ // delay move by this number of ms,
+ // accumulating position changes during the timeout
+ timeout: 0
+});
+=====*/
+
(function(){
-var _1=dojo.dnd.Moveable.prototype.onMove;
-dojo.declare("dojo.dnd.TimedMoveable",dojo.dnd.Moveable,{timeout:40,constructor:function(_2,_3){
-if(!_3){
-_3={};
-}
-if(_3.timeout&&typeof _3.timeout=="number"&&_3.timeout>=0){
-this.timeout=_3.timeout;
-}
-},markupFactory:function(_4,_5){
-return new dojo.dnd.TimedMoveable(_5,_4);
-},onMoveStop:function(_6){
-if(_6._timer){
-clearTimeout(_6._timer);
-_1.call(this,_6,_6._leftTop);
-}
-dojo.dnd.Moveable.prototype.onMoveStop.apply(this,arguments);
-},onMove:function(_7,_8){
-_7._leftTop=_8;
-if(!_7._timer){
-var _9=this;
-_7._timer=setTimeout(function(){
-_7._timer=null;
-_1.call(_9,_7,_7._leftTop);
-},this.timeout);
-}
-}});
+ // precalculate long expressions
+ var oldOnMove = dojo.dnd.Moveable.prototype.onMove;
+
+ dojo.declare("dojo.dnd.TimedMoveable", dojo.dnd.Moveable, {
+ // summary:
+ // A specialized version of Moveable to support an FPS throttling.
+ // This class puts an upper restriction on FPS, which may reduce
+ // the CPU load. The additional parameter "timeout" regulates
+ // the delay before actually moving the moveable object.
+
+ // object attributes (for markup)
+ timeout: 40, // in ms, 40ms corresponds to 25 fps
+
+ constructor: function(node, params){
+ // summary:
+ // an object that makes a node moveable with a timer
+ // node: Node||String
+ // a node (or node's id) to be moved
+ // params: dojo.dnd.__TimedMoveableArgs
+ // object with additional parameters.
+
+ // sanitize parameters
+ if(!params){ params = {}; }
+ if(params.timeout && typeof params.timeout == "number" && params.timeout >= 0){
+ this.timeout = params.timeout;
+ }
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.TimedMoveable(node, params);
+ },
+
+ onMoveStop: function(/* dojo.dnd.Mover */ mover){
+ if(mover._timer){
+ // stop timer
+ clearTimeout(mover._timer)
+ // reflect the last received position
+ oldOnMove.call(this, mover, mover._leftTop)
+ }
+ dojo.dnd.Moveable.prototype.onMoveStop.apply(this, arguments);
+ },
+ onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ mover._leftTop = leftTop;
+ if(!mover._timer){
+ var _t = this; // to avoid using dojo.hitch()
+ mover._timer = setTimeout(function(){
+ // we don't have any pending requests
+ mover._timer = null;
+ // reflect the last received position
+ oldOnMove.call(_t, mover, mover._leftTop);
+ }, this.timeout);
+ }
+ }
+ });
})();
+
}
diff --git a/lib/dojo/dnd/autoscroll.js b/lib/dojo/dnd/autoscroll.js
index 27496c6cd..40daf66a1 100644
--- a/lib/dojo/dnd/autoscroll.js
+++ b/lib/dojo/dnd/autoscroll.js
@@ -5,95 +5,112 @@
*/
-if(!dojo._hasResource["dojo.dnd.autoscroll"]){
-dojo._hasResource["dojo.dnd.autoscroll"]=true;
+if(!dojo._hasResource["dojo.dnd.autoscroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.autoscroll"] = true;
dojo.provide("dojo.dnd.autoscroll");
-dojo.dnd.getViewport=function(){
-var d=dojo.doc,dd=d.documentElement,w=window,b=dojo.body();
-if(dojo.isMozilla){
-return {w:dd.clientWidth,h:w.innerHeight};
-}else{
-if(!dojo.isOpera&&w.innerWidth){
-return {w:w.innerWidth,h:w.innerHeight};
-}else{
-if(!dojo.isOpera&&dd&&dd.clientWidth){
-return {w:dd.clientWidth,h:dd.clientHeight};
-}else{
-if(b.clientWidth){
-return {w:b.clientWidth,h:b.clientHeight};
-}
-}
-}
-}
-return null;
+
+dojo.dnd.getViewport = function(){
+ // summary:
+ // Returns a viewport size (visible part of the window)
+
+ // TODO: remove this when getViewport() moved to dojo core, see #7028
+
+ // FIXME: need more docs!!
+ var d = dojo.doc, dd = d.documentElement, w = window, b = dojo.body();
+ if(dojo.isMozilla){
+ return {w: dd.clientWidth, h: w.innerHeight}; // Object
+ }else if(!dojo.isOpera && w.innerWidth){
+ return {w: w.innerWidth, h: w.innerHeight}; // Object
+ }else if (!dojo.isOpera && dd && dd.clientWidth){
+ return {w: dd.clientWidth, h: dd.clientHeight}; // Object
+ }else if (b.clientWidth){
+ return {w: b.clientWidth, h: b.clientHeight}; // Object
+ }
+ return null; // Object
};
-dojo.dnd.V_TRIGGER_AUTOSCROLL=32;
-dojo.dnd.H_TRIGGER_AUTOSCROLL=32;
-dojo.dnd.V_AUTOSCROLL_VALUE=16;
-dojo.dnd.H_AUTOSCROLL_VALUE=16;
-dojo.dnd.autoScroll=function(e){
-var v=dojo.dnd.getViewport(),dx=0,dy=0;
-if(e.clientX<dojo.dnd.H_TRIGGER_AUTOSCROLL){
-dx=-dojo.dnd.H_AUTOSCROLL_VALUE;
-}else{
-if(e.clientX>v.w-dojo.dnd.H_TRIGGER_AUTOSCROLL){
-dx=dojo.dnd.H_AUTOSCROLL_VALUE;
-}
-}
-if(e.clientY<dojo.dnd.V_TRIGGER_AUTOSCROLL){
-dy=-dojo.dnd.V_AUTOSCROLL_VALUE;
-}else{
-if(e.clientY>v.h-dojo.dnd.V_TRIGGER_AUTOSCROLL){
-dy=dojo.dnd.V_AUTOSCROLL_VALUE;
-}
-}
-window.scrollBy(dx,dy);
+
+dojo.dnd.V_TRIGGER_AUTOSCROLL = 32;
+dojo.dnd.H_TRIGGER_AUTOSCROLL = 32;
+
+dojo.dnd.V_AUTOSCROLL_VALUE = 16;
+dojo.dnd.H_AUTOSCROLL_VALUE = 16;
+
+dojo.dnd.autoScroll = function(e){
+ // summary:
+ // a handler for onmousemove event, which scrolls the window, if
+ // necesary
+ // e: Event
+ // onmousemove event
+
+ // FIXME: needs more docs!
+ var v = dojo.dnd.getViewport(), dx = 0, dy = 0;
+ if(e.clientX < dojo.dnd.H_TRIGGER_AUTOSCROLL){
+ dx = -dojo.dnd.H_AUTOSCROLL_VALUE;
+ }else if(e.clientX > v.w - dojo.dnd.H_TRIGGER_AUTOSCROLL){
+ dx = dojo.dnd.H_AUTOSCROLL_VALUE;
+ }
+ if(e.clientY < dojo.dnd.V_TRIGGER_AUTOSCROLL){
+ dy = -dojo.dnd.V_AUTOSCROLL_VALUE;
+ }else if(e.clientY > v.h - dojo.dnd.V_TRIGGER_AUTOSCROLL){
+ dy = dojo.dnd.V_AUTOSCROLL_VALUE;
+ }
+ window.scrollBy(dx, dy);
};
-dojo.dnd._validNodes={"div":1,"p":1,"td":1};
-dojo.dnd._validOverflow={"auto":1,"scroll":1};
-dojo.dnd.autoScrollNodes=function(e){
-for(var n=e.target;n;){
-if(n.nodeType==1&&(n.tagName.toLowerCase() in dojo.dnd._validNodes)){
-var s=dojo.getComputedStyle(n);
-if(s.overflow.toLowerCase() in dojo.dnd._validOverflow){
-var b=dojo._getContentBox(n,s),t=dojo.position(n,true);
-var w=Math.min(dojo.dnd.H_TRIGGER_AUTOSCROLL,b.w/2),h=Math.min(dojo.dnd.V_TRIGGER_AUTOSCROLL,b.h/2),rx=e.pageX-t.x,ry=e.pageY-t.y,dx=0,dy=0;
-if(dojo.isWebKit||dojo.isOpera){
-rx+=dojo.body().scrollLeft,ry+=dojo.body().scrollTop;
-}
-if(rx>0&&rx<b.w){
-if(rx<w){
-dx=-w;
-}else{
-if(rx>b.w-w){
-dx=w;
-}
-}
-}
-if(ry>0&&ry<b.h){
-if(ry<h){
-dy=-h;
-}else{
-if(ry>b.h-h){
-dy=h;
-}
-}
-}
-var _1=n.scrollLeft,_2=n.scrollTop;
-n.scrollLeft=n.scrollLeft+dx;
-n.scrollTop=n.scrollTop+dy;
-if(_1!=n.scrollLeft||_2!=n.scrollTop){
-return;
-}
-}
-}
-try{
-n=n.parentNode;
-}
-catch(x){
-n=null;
-}
-}
-dojo.dnd.autoScroll(e);
+
+dojo.dnd._validNodes = {"div": 1, "p": 1, "td": 1};
+dojo.dnd._validOverflow = {"auto": 1, "scroll": 1};
+
+dojo.dnd.autoScrollNodes = function(e){
+ // summary:
+ // a handler for onmousemove event, which scrolls the first avaialble
+ // Dom element, it falls back to dojo.dnd.autoScroll()
+ // e: Event
+ // onmousemove event
+
+ // FIXME: needs more docs!
+ for(var n = e.target; n;){
+ if(n.nodeType == 1 && (n.tagName.toLowerCase() in dojo.dnd._validNodes)){
+ var s = dojo.getComputedStyle(n);
+ if(s.overflow.toLowerCase() in dojo.dnd._validOverflow){
+ var b = dojo._getContentBox(n, s), t = dojo.position(n, true);
+ //console.log(b.l, b.t, t.x, t.y, n.scrollLeft, n.scrollTop);
+ var w = Math.min(dojo.dnd.H_TRIGGER_AUTOSCROLL, b.w / 2),
+ h = Math.min(dojo.dnd.V_TRIGGER_AUTOSCROLL, b.h / 2),
+ rx = e.pageX - t.x, ry = e.pageY - t.y, dx = 0, dy = 0;
+ if(dojo.isWebKit || dojo.isOpera){
+ // FIXME: this code should not be here, it should be taken into account
+ // either by the event fixing code, or the dojo.position()
+ // FIXME: this code doesn't work on Opera 9.5 Beta
+ rx += dojo.body().scrollLeft, ry += dojo.body().scrollTop;
+ }
+ if(rx > 0 && rx < b.w){
+ if(rx < w){
+ dx = -w;
+ }else if(rx > b.w - w){
+ dx = w;
+ }
+ }
+ //console.log("ry =", ry, "b.h =", b.h, "h =", h);
+ if(ry > 0 && ry < b.h){
+ if(ry < h){
+ dy = -h;
+ }else if(ry > b.h - h){
+ dy = h;
+ }
+ }
+ var oldLeft = n.scrollLeft, oldTop = n.scrollTop;
+ n.scrollLeft = n.scrollLeft + dx;
+ n.scrollTop = n.scrollTop + dy;
+ if(oldLeft != n.scrollLeft || oldTop != n.scrollTop){ return; }
+ }
+ }
+ try{
+ n = n.parentNode;
+ }catch(x){
+ n = null;
+ }
+ }
+ dojo.dnd.autoScroll(e);
};
+
}
diff --git a/lib/dojo/dnd/common.js b/lib/dojo/dnd/common.js
index d2d18f75a..e49552919 100644
--- a/lib/dojo/dnd/common.js
+++ b/lib/dojo/dnd/common.js
@@ -5,24 +5,33 @@
*/
-if(!dojo._hasResource["dojo.dnd.common"]){
-dojo._hasResource["dojo.dnd.common"]=true;
+if(!dojo._hasResource["dojo.dnd.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.common"] = true;
dojo.provide("dojo.dnd.common");
-dojo.dnd.getCopyKeyState=dojo.isCopyKey;
-dojo.dnd._uniqueId=0;
-dojo.dnd.getUniqueId=function(){
-var id;
-do{
-id=dojo._scopeName+"Unique"+(++dojo.dnd._uniqueId);
-}while(dojo.byId(id));
-return id;
+
+dojo.dnd.getCopyKeyState = dojo.isCopyKey;
+
+dojo.dnd._uniqueId = 0;
+dojo.dnd.getUniqueId = function(){
+ // summary:
+ // returns a unique string for use with any DOM element
+ var id;
+ do{
+ id = dojo._scopeName + "Unique" + (++dojo.dnd._uniqueId);
+ }while(dojo.byId(id));
+ return id;
};
-dojo.dnd._empty={};
-dojo.dnd.isFormElement=function(e){
-var t=e.target;
-if(t.nodeType==3){
-t=t.parentNode;
-}
-return " button textarea input select option ".indexOf(" "+t.tagName.toLowerCase()+" ")>=0;
+
+dojo.dnd._empty = {};
+
+dojo.dnd.isFormElement = function(/*Event*/ e){
+ // summary:
+ // returns true if user clicked on a form element
+ var t = e.target;
+ if(t.nodeType == 3 /*TEXT_NODE*/){
+ t = t.parentNode;
+ }
+ return " button textarea input select option ".indexOf(" " + t.tagName.toLowerCase() + " ") >= 0; // Boolean
};
+
}
diff --git a/lib/dojo/dnd/move.js b/lib/dojo/dnd/move.js
index af7cd98dc..f2abc1b41 100644
--- a/lib/dojo/dnd/move.js
+++ b/lib/dojo/dnd/move.js
@@ -5,121 +5,250 @@
*/
-if(!dojo._hasResource["dojo.dnd.move"]){
-dojo._hasResource["dojo.dnd.move"]=true;
+if(!dojo._hasResource["dojo.dnd.move"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.move"] = true;
dojo.provide("dojo.dnd.move");
+
dojo.require("dojo.dnd.Mover");
dojo.require("dojo.dnd.Moveable");
-dojo.declare("dojo.dnd.move.constrainedMoveable",dojo.dnd.Moveable,{constraints:function(){
-},within:false,markupFactory:function(_1,_2){
-return new dojo.dnd.move.constrainedMoveable(_2,_1);
-},constructor:function(_3,_4){
-if(!_4){
-_4={};
-}
-this.constraints=_4.constraints;
-this.within=_4.within;
-},onFirstMove:function(_5){
-var c=this.constraintBox=this.constraints.call(this,_5);
-c.r=c.l+c.w;
-c.b=c.t+c.h;
-if(this.within){
-var mb=dojo.marginBox(_5.node);
-c.r-=mb.w;
-c.b-=mb.h;
-}
-},onMove:function(_6,_7){
-var c=this.constraintBox,s=_6.node.style;
-s.left=(_7.l<c.l?c.l:c.r<_7.l?c.r:_7.l)+"px";
-s.top=(_7.t<c.t?c.t:c.b<_7.t?c.b:_7.t)+"px";
-}});
-dojo.declare("dojo.dnd.move.boxConstrainedMoveable",dojo.dnd.move.constrainedMoveable,{box:{},markupFactory:function(_8,_9){
-return new dojo.dnd.move.boxConstrainedMoveable(_9,_8);
-},constructor:function(_a,_b){
-var _c=_b&&_b.box;
-this.constraints=function(){
-return _c;
-};
-}});
-dojo.declare("dojo.dnd.move.parentConstrainedMoveable",dojo.dnd.move.constrainedMoveable,{area:"content",markupFactory:function(_d,_e){
-return new dojo.dnd.move.parentConstrainedMoveable(_e,_d);
-},constructor:function(_f,_10){
-var _11=_10&&_10.area;
-this.constraints=function(){
-var n=this.node.parentNode,s=dojo.getComputedStyle(n),mb=dojo._getMarginBox(n,s);
-if(_11=="margin"){
-return mb;
-}
-var t=dojo._getMarginExtents(n,s);
-mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;
-if(_11=="border"){
-return mb;
-}
-t=dojo._getBorderExtents(n,s);
-mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;
-if(_11=="padding"){
-return mb;
-}
-t=dojo._getPadExtents(n,s);
-mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;
-return mb;
-};
-}});
-dojo.dnd.move.constrainedMover=function(fun,_12){
-dojo.deprecated("dojo.dnd.move.constrainedMover, use dojo.dnd.move.constrainedMoveable instead");
-var _13=function(_14,e,_15){
-dojo.dnd.Mover.call(this,_14,e,_15);
-};
-dojo.extend(_13,dojo.dnd.Mover.prototype);
-dojo.extend(_13,{onMouseMove:function(e){
-dojo.dnd.autoScroll(e);
-var m=this.marginBox,c=this.constraintBox,l=m.l+e.pageX,t=m.t+e.pageY;
-l=l<c.l?c.l:c.r<l?c.r:l;
-t=t<c.t?c.t:c.b<t?c.b:t;
-this.host.onMove(this,{l:l,t:t});
-},onFirstMove:function(){
-dojo.dnd.Mover.prototype.onFirstMove.call(this);
-var c=this.constraintBox=fun.call(this);
-c.r=c.l+c.w;
-c.b=c.t+c.h;
-if(_12){
-var mb=dojo.marginBox(this.node);
-c.r-=mb.w;
-c.b-=mb.h;
-}
-}});
-return _13;
-};
-dojo.dnd.move.boxConstrainedMover=function(box,_16){
-dojo.deprecated("dojo.dnd.move.boxConstrainedMover, use dojo.dnd.move.boxConstrainedMoveable instead");
-return dojo.dnd.move.constrainedMover(function(){
-return box;
-},_16);
+
+/*=====
+dojo.declare("dojo.dnd.move.__constrainedMoveableArgs", [dojo.dnd.__MoveableArgs], {
+ // constraints: Function
+ // Calculates a constraint box.
+ // It is called in a context of the moveable object.
+ constraints: function(){},
+
+ // within: Boolean
+ // restrict move within boundaries.
+ within: false
+});
+=====*/
+
+dojo.declare("dojo.dnd.move.constrainedMoveable", dojo.dnd.Moveable, {
+ // object attributes (for markup)
+ constraints: function(){},
+ within: false,
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.move.constrainedMoveable(node, params);
+ },
+
+ constructor: function(node, params){
+ // summary:
+ // an object that makes a node moveable
+ // node: Node
+ // a node (or node's id) to be moved
+ // params: dojo.dnd.move.__constrainedMoveableArgs?
+ // an optional object with additional parameters;
+ // the rest is passed to the base class
+ if(!params){ params = {}; }
+ this.constraints = params.constraints;
+ this.within = params.within;
+ },
+ onFirstMove: function(/* dojo.dnd.Mover */ mover){
+ // summary:
+ // called during the very first move notification;
+ // can be used to initialize coordinates, can be overwritten.
+ var c = this.constraintBox = this.constraints.call(this, mover);
+ c.r = c.l + c.w;
+ c.b = c.t + c.h;
+ if(this.within){
+ var mb = dojo.marginBox(mover.node);
+ c.r -= mb.w;
+ c.b -= mb.h;
+ }
+ },
+ onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ // summary:
+ // called during every move notification;
+ // should actually move the node; can be overwritten.
+ var c = this.constraintBox, s = mover.node.style;
+ s.left = (leftTop.l < c.l ? c.l : c.r < leftTop.l ? c.r : leftTop.l) + "px";
+ s.top = (leftTop.t < c.t ? c.t : c.b < leftTop.t ? c.b : leftTop.t) + "px";
+ }
+});
+
+/*=====
+dojo.declare("dojo.dnd.move.__boxConstrainedMoveableArgs", [dojo.dnd.move.__constrainedMoveableArgs], {
+ // box: Object
+ // a constraint box
+ box: {}
+});
+=====*/
+
+dojo.declare("dojo.dnd.move.boxConstrainedMoveable", dojo.dnd.move.constrainedMoveable, {
+ // box:
+ // object attributes (for markup)
+ box: {},
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.move.boxConstrainedMoveable(node, params);
+ },
+
+ constructor: function(node, params){
+ // summary:
+ // an object, which makes a node moveable
+ // node: Node
+ // a node (or node's id) to be moved
+ // params: dojo.dnd.move.__boxConstrainedMoveableArgs?
+ // an optional object with parameters
+ var box = params && params.box;
+ this.constraints = function(){ return box; };
+ }
+});
+
+/*=====
+dojo.declare("dojo.dnd.move.__parentConstrainedMoveableArgs", [dojo.dnd.move.__constrainedMoveableArgs], {
+ // area: String
+ // A parent's area to restrict the move.
+ // Can be "margin", "border", "padding", or "content".
+ area: ""
+});
+=====*/
+
+dojo.declare("dojo.dnd.move.parentConstrainedMoveable", dojo.dnd.move.constrainedMoveable, {
+ // area:
+ // object attributes (for markup)
+ area: "content",
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.move.parentConstrainedMoveable(node, params);
+ },
+
+ constructor: function(node, params){
+ // summary:
+ // an object, which makes a node moveable
+ // node: Node
+ // a node (or node's id) to be moved
+ // params: dojo.dnd.move.__parentConstrainedMoveableArgs?
+ // an optional object with parameters
+ var area = params && params.area;
+ this.constraints = function(){
+ var n = this.node.parentNode,
+ s = dojo.getComputedStyle(n),
+ mb = dojo._getMarginBox(n, s);
+ if(area == "margin"){
+ return mb; // Object
+ }
+ var t = dojo._getMarginExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ if(area == "border"){
+ return mb; // Object
+ }
+ t = dojo._getBorderExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ if(area == "padding"){
+ return mb; // Object
+ }
+ t = dojo._getPadExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ return mb; // Object
+ };
+ }
+});
+
+// WARNING: below are obsolete objects, instead of custom movers use custom moveables (above)
+
+dojo.dnd.move.constrainedMover = function(fun, within){
+ // summary:
+ // returns a constrained version of dojo.dnd.Mover
+ // description:
+ // this function produces n object, which will put a constraint on
+ // the margin box of dragged object in absolute coordinates
+ // fun: Function
+ // called on drag, and returns a constraint box
+ // within: Boolean
+ // if true, constraints the whole dragged object withtin the rectangle,
+ // otherwise the constraint is applied to the left-top corner
+
+ dojo.deprecated("dojo.dnd.move.constrainedMover, use dojo.dnd.move.constrainedMoveable instead");
+ var mover = function(node, e, notifier){
+ dojo.dnd.Mover.call(this, node, e, notifier);
+ };
+ dojo.extend(mover, dojo.dnd.Mover.prototype);
+ dojo.extend(mover, {
+ onMouseMove: function(e){
+ // summary: event processor for onmousemove
+ // e: Event: mouse event
+ dojo.dnd.autoScroll(e);
+ var m = this.marginBox, c = this.constraintBox,
+ l = m.l + e.pageX, t = m.t + e.pageY;
+ l = l < c.l ? c.l : c.r < l ? c.r : l;
+ t = t < c.t ? c.t : c.b < t ? c.b : t;
+ this.host.onMove(this, {l: l, t: t});
+ },
+ onFirstMove: function(){
+ // summary: called once to initialize things; it is meant to be called only once
+ dojo.dnd.Mover.prototype.onFirstMove.call(this);
+ var c = this.constraintBox = fun.call(this);
+ c.r = c.l + c.w;
+ c.b = c.t + c.h;
+ if(within){
+ var mb = dojo.marginBox(this.node);
+ c.r -= mb.w;
+ c.b -= mb.h;
+ }
+ }
+ });
+ return mover; // Object
};
-dojo.dnd.move.parentConstrainedMover=function(_17,_18){
-dojo.deprecated("dojo.dnd.move.parentConstrainedMover, use dojo.dnd.move.parentConstrainedMoveable instead");
-var fun=function(){
-var n=this.node.parentNode,s=dojo.getComputedStyle(n),mb=dojo._getMarginBox(n,s);
-if(_17=="margin"){
-return mb;
-}
-var t=dojo._getMarginExtents(n,s);
-mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;
-if(_17=="border"){
-return mb;
-}
-t=dojo._getBorderExtents(n,s);
-mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;
-if(_17=="padding"){
-return mb;
-}
-t=dojo._getPadExtents(n,s);
-mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;
-return mb;
+
+dojo.dnd.move.boxConstrainedMover = function(box, within){
+ // summary:
+ // a specialization of dojo.dnd.constrainedMover, which constrains to the specified box
+ // box: Object
+ // a constraint box (l, t, w, h)
+ // within: Boolean
+ // if true, constraints the whole dragged object withtin the rectangle,
+ // otherwise the constraint is applied to the left-top corner
+
+ dojo.deprecated("dojo.dnd.move.boxConstrainedMover, use dojo.dnd.move.boxConstrainedMoveable instead");
+ return dojo.dnd.move.constrainedMover(function(){ return box; }, within); // Object
};
-return dojo.dnd.move.constrainedMover(fun,_18);
+
+dojo.dnd.move.parentConstrainedMover = function(area, within){
+ // summary:
+ // a specialization of dojo.dnd.constrainedMover, which constrains to the parent node
+ // area: String
+ // "margin" to constrain within the parent's margin box, "border" for the border box,
+ // "padding" for the padding box, and "content" for the content box; "content" is the default value.
+ // within: Boolean
+ // if true, constraints the whole dragged object within the rectangle,
+ // otherwise the constraint is applied to the left-top corner
+
+ dojo.deprecated("dojo.dnd.move.parentConstrainedMover, use dojo.dnd.move.parentConstrainedMoveable instead");
+ var fun = function(){
+ var n = this.node.parentNode,
+ s = dojo.getComputedStyle(n),
+ mb = dojo._getMarginBox(n, s);
+ if(area == "margin"){
+ return mb; // Object
+ }
+ var t = dojo._getMarginExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ if(area == "border"){
+ return mb; // Object
+ }
+ t = dojo._getBorderExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ if(area == "padding"){
+ return mb; // Object
+ }
+ t = dojo._getPadExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ return mb; // Object
+ };
+ return dojo.dnd.move.constrainedMover(fun, within); // Object
};
-dojo.dnd.constrainedMover=dojo.dnd.move.constrainedMover;
-dojo.dnd.boxConstrainedMover=dojo.dnd.move.boxConstrainedMover;
-dojo.dnd.parentConstrainedMover=dojo.dnd.move.parentConstrainedMover;
+
+// patching functions one level up for compatibility
+
+dojo.dnd.constrainedMover = dojo.dnd.move.constrainedMover;
+dojo.dnd.boxConstrainedMover = dojo.dnd.move.boxConstrainedMover;
+dojo.dnd.parentConstrainedMover = dojo.dnd.move.parentConstrainedMover;
+
}
diff --git a/lib/dojo/fx.js b/lib/dojo/fx.js
index 39ae253fd..5c70d5b9e 100644
--- a/lib/dojo/fx.js
+++ b/lib/dojo/fx.js
@@ -5,248 +5,400 @@
*/
-if(!dojo._hasResource["dojo.fx"]){
-dojo._hasResource["dojo.fx"]=true;
+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.require("dojo.fx.Toggler");
-(function(){
-var d=dojo,_1={_fire:function(_2,_3){
-if(this[_2]){
-this[_2].apply(this,_3||[]);
-}
-return this;
-}};
-var _4=function(_5){
-this._index=-1;
-this._animations=_5||[];
-this._current=this._onAnimateCtx=this._onEndCtx=null;
-this.duration=0;
-d.forEach(this._animations,function(a){
-this.duration+=a.duration;
-if(a.delay){
-this.duration+=a.delay;
-}
-},this);
-};
-d.extend(_4,{_onAnimate:function(){
-this._fire("onAnimate",arguments);
-},_onEnd:function(){
-d.disconnect(this._onAnimateCtx);
-d.disconnect(this._onEndCtx);
-this._onAnimateCtx=this._onEndCtx=null;
-if(this._index+1==this._animations.length){
-this._fire("onEnd");
-}else{
-this._current=this._animations[++this._index];
-this._onAnimateCtx=d.connect(this._current,"onAnimate",this,"_onAnimate");
-this._onEndCtx=d.connect(this._current,"onEnd",this,"_onEnd");
-this._current.play(0,true);
-}
-},play:function(_6,_7){
-if(!this._current){
-this._current=this._animations[this._index=0];
-}
-if(!_7&&this._current.status()=="playing"){
-return this;
-}
-var _8=d.connect(this._current,"beforeBegin",this,function(){
-this._fire("beforeBegin");
-}),_9=d.connect(this._current,"onBegin",this,function(_a){
-this._fire("onBegin",arguments);
-}),_b=d.connect(this._current,"onPlay",this,function(_c){
-this._fire("onPlay",arguments);
-d.disconnect(_8);
-d.disconnect(_9);
-d.disconnect(_b);
-});
-if(this._onAnimateCtx){
-d.disconnect(this._onAnimateCtx);
-}
-this._onAnimateCtx=d.connect(this._current,"onAnimate",this,"_onAnimate");
-if(this._onEndCtx){
-d.disconnect(this._onEndCtx);
-}
-this._onEndCtx=d.connect(this._current,"onEnd",this,"_onEnd");
-this._current.play.apply(this._current,arguments);
-return this;
-},pause:function(){
-if(this._current){
-var e=d.connect(this._current,"onPause",this,function(_d){
-this._fire("onPause",arguments);
-d.disconnect(e);
-});
-this._current.pause();
-}
-return this;
-},gotoPercent:function(_e,_f){
-this.pause();
-var _10=this.duration*_e;
-this._current=null;
-d.some(this._animations,function(a){
-if(a.duration<=_10){
-this._current=a;
-return true;
-}
-_10-=a.duration;
-return false;
-});
-if(this._current){
-this._current.gotoPercent(_10/this._current.duration,_f);
-}
-return this;
-},stop:function(_11){
-if(this._current){
-if(_11){
-for(;this._index+1<this._animations.length;++this._index){
-this._animations[this._index].stop(true);
-}
-this._current=this._animations[this._index];
-}
-var e=d.connect(this._current,"onStop",this,function(arg){
-this._fire("onStop",arguments);
-d.disconnect(e);
-});
-this._current.stop();
-}
-return this;
-},status:function(){
-return this._current?this._current.status():"stopped";
-},destroy:function(){
-if(this._onAnimateCtx){
-d.disconnect(this._onAnimateCtx);
-}
-if(this._onEndCtx){
-d.disconnect(this._onEndCtx);
-}
-}});
-d.extend(_4,_1);
-dojo.fx.chain=function(_12){
-return new _4(_12);
-};
-var _13=function(_14){
-this._animations=_14||[];
-this._connects=[];
-this._finished=0;
-this.duration=0;
-d.forEach(_14,function(a){
-var _15=a.duration;
-if(a.delay){
-_15+=a.delay;
-}
-if(this.duration<_15){
-this.duration=_15;
-}
-this._connects.push(d.connect(a,"onEnd",this,"_onEnd"));
-},this);
-this._pseudoAnimation=new d.Animation({curve:[0,1],duration:this.duration});
-var _16=this;
-d.forEach(["beforeBegin","onBegin","onPlay","onAnimate","onPause","onStop","onEnd"],function(evt){
-_16._connects.push(d.connect(_16._pseudoAnimation,evt,function(){
-_16._fire(evt,arguments);
-}));
-});
-};
-d.extend(_13,{_doAction:function(_17,_18){
-d.forEach(this._animations,function(a){
-a[_17].apply(a,_18);
-});
-return this;
-},_onEnd:function(){
-if(++this._finished>this._animations.length){
-this._fire("onEnd");
-}
-},_call:function(_19,_1a){
-var t=this._pseudoAnimation;
-t[_19].apply(t,_1a);
-},play:function(_1b,_1c){
-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(_1d,_1e){
-var ms=this.duration*_1d;
-d.forEach(this._animations,function(a){
-a.gotoPercent(a.duration<ms?1:(ms/a.duration),_1e);
-});
-this._call("gotoPercent",arguments);
-return this;
-},stop:function(_1f){
-this._doAction("stop",arguments);
-this._call("stop",arguments);
-return this;
-},status:function(){
-return this._pseudoAnimation.status();
-},destroy:function(){
-d.forEach(this._connects,dojo.disconnect);
-}});
-d.extend(_13,_1);
-dojo.fx.combine=function(_20){
-return new _13(_20);
-};
-dojo.fx.wipeIn=function(_21){
-var _22=_21.node=d.byId(_21.node),s=_22.style,o;
-var _23=d.animateProperty(d.mixin({properties:{height:{start:function(){
-o=s.overflow;
-s.overflow="hidden";
-if(s.visibility=="hidden"||s.display=="none"){
-s.height="1px";
-s.display="";
-s.visibility="";
-return 1;
-}else{
-var _24=d.style(_22,"height");
-return Math.max(_24,1);
-}
-},end:function(){
-return _22.scrollHeight;
-}}}},_21));
-d.connect(_23,"onEnd",function(){
-s.height="auto";
-s.overflow=o;
-});
-return _23;
-};
-dojo.fx.wipeOut=function(_25){
-var _26=_25.node=d.byId(_25.node),s=_26.style,o;
-var _27=d.animateProperty(d.mixin({properties:{height:{end:1}}},_25));
-d.connect(_27,"beforeBegin",function(){
-o=s.overflow;
-s.overflow="hidden";
-s.display="";
-});
-d.connect(_27,"onEnd",function(){
-s.overflow=o;
-s.height="auto";
-s.display="none";
-});
-return _27;
-};
-dojo.fx.slideTo=function(_28){
-var _29=_28.node=d.byId(_28.node),top=null,_2a=null;
-var _2b=(function(n){
-return function(){
-var cs=d.getComputedStyle(n);
-var pos=cs.position;
-top=(pos=="absolute"?n.offsetTop:parseInt(cs.top)||0);
-_2a=(pos=="absolute"?n.offsetLeft:parseInt(cs.left)||0);
-if(pos!="absolute"&&pos!="relative"){
-var ret=d.position(n,true);
-top=ret.y;
-_2a=ret.x;
-n.style.position="absolute";
-n.style.top=top+"px";
-n.style.left=_2a+"px";
-}
-};
-})(_29);
-_2b();
-var _2c=d.animateProperty(d.mixin({properties:{top:_28.top||0,left:_28.left||0}},_28));
-d.connect(_2c,"beforeBegin",_2c,_2b);
-return _2c;
+dojo.require("dojo.fx.Toggler"); // FIXME: remove this back-compat require in 2.0
+/*=====
+dojo.fx = {
+ // summary: Effects library on top of Base animations
};
+=====*/
+(function(){
+
+ var d = dojo,
+ _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;
+ d.forEach(this._animations, function(a){
+ this.duration += a.duration;
+ if(a.delay){ this.duration += a.delay; }
+ }, this);
+ };
+ d.extend(_chain, {
+ _onAnimate: function(){
+ this._fire("onAnimate", arguments);
+ },
+ _onEnd: function(){
+ d.disconnect(this._onAnimateCtx);
+ d.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 = d.connect(this._current, "onAnimate", this, "_onAnimate");
+ this._onEndCtx = d.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 = d.connect(this._current, "beforeBegin", this, function(){
+ this._fire("beforeBegin");
+ }),
+ onBegin = d.connect(this._current, "onBegin", this, function(arg){
+ this._fire("onBegin", arguments);
+ }),
+ onPlay = d.connect(this._current, "onPlay", this, function(arg){
+ this._fire("onPlay", arguments);
+ d.disconnect(beforeBegin);
+ d.disconnect(onBegin);
+ d.disconnect(onPlay);
+ });
+ if(this._onAnimateCtx){
+ d.disconnect(this._onAnimateCtx);
+ }
+ this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
+ if(this._onEndCtx){
+ d.disconnect(this._onEndCtx);
+ }
+ this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
+ this._current.play.apply(this._current, arguments);
+ return this;
+ },
+ pause: function(){
+ if(this._current){
+ var e = d.connect(this._current, "onPause", this, function(arg){
+ this._fire("onPause", arguments);
+ d.disconnect(e);
+ });
+ this._current.pause();
+ }
+ return this;
+ },
+ gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
+ this.pause();
+ var offset = this.duration * percent;
+ this._current = null;
+ d.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 / this._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 = d.connect(this._current, "onStop", this, function(arg){
+ this._fire("onStop", arguments);
+ d.disconnect(e);
+ });
+ this._current.stop();
+ }
+ return this;
+ },
+ status: function(){
+ return this._current ? this._current.status() : "stopped";
+ },
+ destroy: function(){
+ if(this._onAnimateCtx){ d.disconnect(this._onAnimateCtx); }
+ if(this._onEndCtx){ d.disconnect(this._onEndCtx); }
+ }
+ });
+ d.extend(_chain, _baseObj);
+
+ dojo.fx.chain = function(/*dojo.Animation[]*/ animations){
+ // summary:
+ // Chain a list of `dojo.Animation`s to run in sequence
+ //
+ // description:
+ // Return a `dojo.Animation` which will play all passed
+ // `dojo.Animation` instances in sequence, firing its own
+ // synthesized events simulating a single animation. (eg:
+ // onEnd of this animation means the end of the chain,
+ // not the individual animations within)
+ //
+ // example:
+ // Once `node` is faded out, fade in `otherNode`
+ // | 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;
+ d.forEach(animations, function(a){
+ var duration = a.duration;
+ if(a.delay){ duration += a.delay; }
+ if(this.duration < duration){ this.duration = duration; }
+ this._connects.push(d.connect(a, "onEnd", this, "_onEnd"));
+ }, this);
+
+ this._pseudoAnimation = new d.Animation({curve: [0, 1], duration: this.duration});
+ var self = this;
+ d.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"],
+ function(evt){
+ self._connects.push(d.connect(self._pseudoAnimation, evt,
+ function(){ self._fire(evt, arguments); }
+ ));
+ }
+ );
+ };
+ d.extend(_combine, {
+ _doAction: function(action, args){
+ d.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;
+ d.forEach(this._animations, function(a){
+ a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay);
+ });
+ this._call("gotoPercent", 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(){
+ d.forEach(this._connects, dojo.disconnect);
+ }
+ });
+ d.extend(_combine, _baseObj);
+
+ dojo.fx.combine = function(/*dojo.Animation[]*/ animations){
+ // summary:
+ // Combine a list of `dojo.Animation`s to run in parallel
+ //
+ // description:
+ // Combine an array of `dojo.Animation`s to run in parallel,
+ // providing a new `dojo.Animation` instance encompasing each
+ // animation, firing standard animation events.
+ //
+ // example:
+ // Fade out `node` while fading in `otherNode` simultaneously
+ // | dojo.fx.combine([
+ // | dojo.fadeIn({ node:node }),
+ // | dojo.fadeOut({ node:otherNode })
+ // | ]).play();
+ //
+ // example:
+ // When the longest animation ends, execute a function:
+ // | var anim = dojo.fx.combine([
+ // | dojo.fadeIn({ node: n, duration:700 }),
+ // | dojo.fadeOut({ node: otherNode, duration: 300 })
+ // | ]);
+ // | dojo.connect(anim, "onEnd", function(){
+ // | // overall animation is done.
+ // | });
+ // | anim.play(); // play the animation
+ //
+ return new _combine(animations); // dojo.Animation
+ };
+
+ dojo.fx.wipeIn = function(/*Object*/ args){
+ // summary:
+ // Expand a node to it's natural height.
+ //
+ // description:
+ // 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: Object
+ // A hash-map of standard `dojo.Animation` constructor properties
+ // (such as easing: node: duration: and so on)
+ //
+ // example:
+ // | dojo.fx.wipeIn({
+ // | node:"someId"
+ // | }).play()
+ var node = args.node = d.byId(args.node), s = node.style, o;
+
+ var anim = d.animateProperty(d.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
+ o = s.overflow;
+ s.overflow = "hidden";
+ if(s.visibility == "hidden" || s.display == "none"){
+ s.height = "1px";
+ s.display = "";
+ s.visibility = "";
+ return 1;
+ }else{
+ var height = d.style(node, "height");
+ return Math.max(height, 1);
+ }
+ },
+ end: function(){
+ return node.scrollHeight;
+ }
+ }
+ }
+ }, args));
+
+ d.connect(anim, "onEnd", function(){
+ s.height = "auto";
+ s.overflow = o;
+ });
+
+ return anim; // dojo.Animation
+ }
+
+ dojo.fx.wipeOut = function(/*Object*/ args){
+ // summary:
+ // Shrink a node to nothing and hide it.
+ //
+ // description:
+ // Returns an animation that will shrink node defined in "args"
+ // from it's current height to 1px, and then hide it.
+ //
+ // args: Object
+ // A hash-map of standard `dojo.Animation` constructor properties
+ // (such as easing: node: duration: and so on)
+ //
+ // example:
+ // | dojo.fx.wipeOut({ node:"someId" }).play()
+
+ var node = args.node = d.byId(args.node), s = node.style, o;
+
+ var anim = d.animateProperty(d.mixin({
+ properties: {
+ height: {
+ end: 1 // 0 causes IE to display the whole panel
+ }
+ }
+ }, args));
+
+ d.connect(anim, "beforeBegin", function(){
+ o = s.overflow;
+ s.overflow = "hidden";
+ s.display = "";
+ });
+ d.connect(anim, "onEnd", function(){
+ s.overflow = o;
+ s.height = "auto";
+ s.display = "none";
+ });
+
+ return anim; // dojo.Animation
+ }
+
+ dojo.fx.slideTo = function(/*Object*/ args){
+ // summary:
+ // Slide a node to a new top/left position
+ //
+ // description:
+ // Returns an animation that will slide "node"
+ // defined in args Object from its current position to
+ // the position defined by (args.left, args.top).
+ //
+ // args: Object
+ // A hash-map of standard `dojo.Animation` constructor properties
+ // (such as easing: node: duration: and so on). Special args members
+ // are `top` and `left`, which indicate the new position to slide to.
+ //
+ // example:
+ // | dojo.fx.slideTo({ node: node, left:"40", top:"50", units:"px" }).play()
+
+ var node = args.node = d.byId(args.node),
+ top = null, left = null;
+
+ var init = (function(n){
+ return function(){
+ var cs = d.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 = d.position(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 = d.animateProperty(d.mixin({
+ properties: {
+ top: args.top || 0,
+ left: args.left || 0
+ }
+ }, args));
+ d.connect(anim, "beforeBegin", anim, init);
+
+ return anim; // dojo.Animation
+ }
+
})();
+
}
diff --git a/lib/dojo/fx/Toggler.js b/lib/dojo/fx/Toggler.js
index b8bc639ce..ddc3e225d 100644
--- a/lib/dojo/fx/Toggler.js
+++ b/lib/dojo/fx/Toggler.js
@@ -5,26 +5,103 @@
*/
-if(!dojo._hasResource["dojo.fx.Toggler"]){
-dojo._hasResource["dojo.fx.Toggler"]=true;
+if(!dojo._hasResource["dojo.fx.Toggler"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.fx.Toggler"] = true;
dojo.provide("dojo.fx.Toggler");
-dojo.declare("dojo.fx.Toggler",null,{node:null,showFunc:dojo.fadeIn,hideFunc:dojo.fadeOut,showDuration:200,hideDuration:200,constructor:function(_1){
-var _2=this;
-dojo.mixin(_2,_1);
-_2.node=_1.node;
-_2._showArgs=dojo.mixin({},_1);
-_2._showArgs.node=_2.node;
-_2._showArgs.duration=_2.showDuration;
-_2.showAnim=_2.showFunc(_2._showArgs);
-_2._hideArgs=dojo.mixin({},_1);
-_2._hideArgs.node=_2.node;
-_2._hideArgs.duration=_2.hideDuration;
-_2.hideAnim=_2.hideFunc(_2._hideArgs);
-dojo.connect(_2.showAnim,"beforeBegin",dojo.hitch(_2.hideAnim,"stop",true));
-dojo.connect(_2.hideAnim,"beforeBegin",dojo.hitch(_2.showAnim,"stop",true));
-},show:function(_3){
-return this.showAnim.play(_3||0);
-},hide:function(_4){
-return this.hideAnim.play(_4||0);
-}});
+
+dojo.declare("dojo.fx.Toggler", null, {
+ // summary:
+ // A simple `dojo.Animation` toggler API.
+ //
+ // description:
+ // 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. All available members are mixed into
+ // these animations from the constructor (for example, `node`,
+ // `showDuration`, `hideDuration`).
+ //
+ // example:
+ // | var t = new dojo.fx.Toggler({
+ // | node: "nodeId",
+ // | showDuration: 500,
+ // | // hideDuration will default to "200"
+ // | showFunc: dojo.fx.wipeIn,
+ // | // hideFunc will default to "fadeOut"
+ // | });
+ // | t.show(100); // delay showing for 100ms
+ // | // ...time passes...
+ // | t.hide();
+
+ // node: DomNode
+ // the node to target for the showing and hiding animations
+ 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,
+
+ // 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.
+ // FIXME: also would be nice to specify individual showArgs/hideArgs mixed into
+ // each animation individually.
+ // FIXME: also would be nice to have events from the animations exposed/bridged
+
+ /*=====
+ _showArgs: null,
+ _showAnim: null,
+
+ _hideArgs: null,
+ _hideAnim: null,
+
+ _isShowing: false,
+ _isHiding: false,
+ =====*/
+
+ 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));
+ },
+
+ show: function(delay){
+ // summary: Toggle the node to showing
+ // delay: Integer?
+ // Ammount of time to stall playing the show animation
+ return this.showAnim.play(delay || 0);
+ },
+
+ hide: function(delay){
+ // summary: Toggle the node to hidden
+ // delay: Integer?
+ // Ammount of time to stall playing the hide animation
+ return this.hideAnim.play(delay || 0);
+ }
+});
+
}
diff --git a/lib/dojo/fx/easing.js b/lib/dojo/fx/easing.js
index 0de5d5e99..0ce6efbff 100644
--- a/lib/dojo/fx/easing.js
+++ b/lib/dojo/fx/easing.js
@@ -5,162 +5,282 @@
*/
-if(!dojo._hasResource["dojo.fx.easing"]){
-dojo._hasResource["dojo.fx.easing"]=true;
+if(!dojo._hasResource["dojo.fx.easing"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.fx.easing"] = true;
dojo.provide("dojo.fx.easing");
-dojo.fx.easing={linear:function(n){
-return n;
-},quadIn:function(n){
-return Math.pow(n,2);
-},quadOut:function(n){
-return n*(n-2)*-1;
-},quadInOut:function(n){
-n=n*2;
-if(n<1){
-return Math.pow(n,2)/2;
-}
-return -1*((--n)*(n-2)-1)/2;
-},cubicIn:function(n){
-return Math.pow(n,3);
-},cubicOut:function(n){
-return Math.pow(n-1,3)+1;
-},cubicInOut:function(n){
-n=n*2;
-if(n<1){
-return Math.pow(n,3)/2;
-}
-n-=2;
-return (Math.pow(n,3)+2)/2;
-},quartIn:function(n){
-return Math.pow(n,4);
-},quartOut:function(n){
-return -1*(Math.pow(n-1,4)-1);
-},quartInOut:function(n){
-n=n*2;
-if(n<1){
-return Math.pow(n,4)/2;
-}
-n-=2;
-return -1/2*(Math.pow(n,4)-2);
-},quintIn:function(n){
-return Math.pow(n,5);
-},quintOut:function(n){
-return Math.pow(n-1,5)+1;
-},quintInOut:function(n){
-n=n*2;
-if(n<1){
-return Math.pow(n,5)/2;
-}
-n-=2;
-return (Math.pow(n,5)+2)/2;
-},sineIn:function(n){
-return -1*Math.cos(n*(Math.PI/2))+1;
-},sineOut:function(n){
-return Math.sin(n*(Math.PI/2));
-},sineInOut:function(n){
-return -1*(Math.cos(Math.PI*n)-1)/2;
-},expoIn:function(n){
-return (n==0)?0:Math.pow(2,10*(n-1));
-},expoOut:function(n){
-return (n==1)?1:(-1*Math.pow(2,-10*n)+1);
-},expoInOut:function(n){
-if(n==0){
-return 0;
-}
-if(n==1){
-return 1;
-}
-n=n*2;
-if(n<1){
-return Math.pow(2,10*(n-1))/2;
-}
---n;
-return (-1*Math.pow(2,-10*n)+2)/2;
-},circIn:function(n){
-return -1*(Math.sqrt(1-Math.pow(n,2))-1);
-},circOut:function(n){
-n=n-1;
-return Math.sqrt(1-Math.pow(n,2));
-},circInOut:function(n){
-n=n*2;
-if(n<1){
-return -1/2*(Math.sqrt(1-Math.pow(n,2))-1);
-}
-n-=2;
-return 1/2*(Math.sqrt(1-Math.pow(n,2))+1);
-},backIn:function(n){
-var s=1.70158;
-return Math.pow(n,2)*((s+1)*n-s);
-},backOut:function(n){
-n=n-1;
-var s=1.70158;
-return Math.pow(n,2)*((s+1)*n+s)+1;
-},backInOut:function(n){
-var s=1.70158*1.525;
-n=n*2;
-if(n<1){
-return (Math.pow(n,2)*((s+1)*n-s))/2;
-}
-n-=2;
-return (Math.pow(n,2)*((s+1)*n+s)+2)/2;
-},elasticIn:function(n){
-if(n==0||n==1){
-return n;
-}
-var p=0.3;
-var s=p/4;
-n=n-1;
-return -1*Math.pow(2,10*n)*Math.sin((n-s)*(2*Math.PI)/p);
-},elasticOut:function(n){
-if(n==0||n==1){
-return n;
-}
-var p=0.3;
-var s=p/4;
-return Math.pow(2,-10*n)*Math.sin((n-s)*(2*Math.PI)/p)+1;
-},elasticInOut:function(n){
-if(n==0){
-return 0;
-}
-n=n*2;
-if(n==2){
-return 1;
-}
-var p=0.3*1.5;
-var s=p/4;
-if(n<1){
-n-=1;
-return -0.5*(Math.pow(2,10*n)*Math.sin((n-s)*(2*Math.PI)/p));
-}
-n-=1;
-return 0.5*(Math.pow(2,-10*n)*Math.sin((n-s)*(2*Math.PI)/p))+1;
-},bounceIn:function(n){
-return (1-dojo.fx.easing.bounceOut(1-n));
-},bounceOut:function(n){
-var s=7.5625;
-var p=2.75;
-var l;
-if(n<(1/p)){
-l=s*Math.pow(n,2);
-}else{
-if(n<(2/p)){
-n-=(1.5/p);
-l=s*Math.pow(n,2)+0.75;
-}else{
-if(n<(2.5/p)){
-n-=(2.25/p);
-l=s*Math.pow(n,2)+0.9375;
-}else{
-n-=(2.625/p);
-l=s*Math.pow(n,2)+0.984375;
-}
-}
-}
-return l;
-},bounceInOut:function(n){
-if(n<0.5){
-return dojo.fx.easing.bounceIn(n*2)/2;
-}
-return (dojo.fx.easing.bounceOut(n*2-1)/2)+0.5;
-}};
+
+dojo.fx.easing = {
+ // summary:
+ // Collection of easing functions to use beyond the default
+ // `dojo._defaultEasing` function.
+ //
+ // description:
+ //
+ // Easing functions are used to manipulate the iteration through
+ // an `dojo.Animation`s _Line. _Line being the properties of an Animation,
+ // and the easing function progresses through that Line determing
+ // how quickly (or slowly) it should go. Or more accurately: modify
+ // the value of the _Line based on the percentage of animation completed.
+ //
+ // All functions follow a simple naming convention of "ease type" + "when".
+ // If the name of the function ends in Out, the easing described appears
+ // towards the end of the animation. "In" means during the beginning,
+ // and InOut means both ranges of the Animation will applied, both
+ // beginning and end.
+ //
+ // One does not call the easing function directly, it must be passed to
+ // the `easing` property of an animation.
+ //
+ // example:
+ // | dojo.require("dojo.fx.easing");
+ // | var anim = dojo.fadeOut({
+ // | node: 'node',
+ // | duration: 2000,
+ // | // note there is no ()
+ // | easing: dojo.fx.easing.quadIn
+ // | }).play();
+ //
+
+ linear: function(/* Decimal? */n){
+ // summary: A linear easing function
+ return n;
+ },
+
+ quadIn: function(/* Decimal? */n){
+ return Math.pow(n, 2);
+ },
+
+ quadOut: function(/* Decimal? */n){
+ return n * (n - 2) * -1;
+ },
+
+ quadInOut: function(/* Decimal? */n){
+ n = n * 2;
+ if(n < 1){ return Math.pow(n, 2) / 2; }
+ return -1 * ((--n) * (n - 2) - 1) / 2;
+ },
+
+ cubicIn: function(/* Decimal? */n){
+ return Math.pow(n, 3);
+ },
+
+ cubicOut: function(/* Decimal? */n){
+ return Math.pow(n - 1, 3) + 1;
+ },
+
+ cubicInOut: function(/* Decimal? */n){
+ n = n * 2;
+ if(n < 1){ return Math.pow(n, 3) / 2; }
+ n -= 2;
+ return (Math.pow(n, 3) + 2) / 2;
+ },
+
+ quartIn: function(/* Decimal? */n){
+ return Math.pow(n, 4);
+ },
+
+ quartOut: function(/* Decimal? */n){
+ return -1 * (Math.pow(n - 1, 4) - 1);
+ },
+
+ quartInOut: function(/* Decimal? */n){
+ n = n * 2;
+ if(n < 1){ return Math.pow(n, 4) / 2; }
+ n -= 2;
+ return -1 / 2 * (Math.pow(n, 4) - 2);
+ },
+
+ quintIn: function(/* Decimal? */n){
+ return Math.pow(n, 5);
+ },
+
+ quintOut: function(/* Decimal? */n){
+ return Math.pow(n - 1, 5) + 1;
+ },
+
+ quintInOut: function(/* Decimal? */n){
+ n = n * 2;
+ if(n < 1){ return Math.pow(n, 5) / 2; };
+ n -= 2;
+ return (Math.pow(n, 5) + 2) / 2;
+ },
+
+ sineIn: function(/* Decimal? */n){
+ return -1 * Math.cos(n * (Math.PI / 2)) + 1;
+ },
+
+ sineOut: function(/* Decimal? */n){
+ return Math.sin(n * (Math.PI / 2));
+ },
+
+ sineInOut: function(/* Decimal? */n){
+ return -1 * (Math.cos(Math.PI * n) - 1) / 2;
+ },
+
+ expoIn: function(/* Decimal? */n){
+ return (n == 0) ? 0 : Math.pow(2, 10 * (n - 1));
+ },
+
+ expoOut: function(/* Decimal? */n){
+ return (n == 1) ? 1 : (-1 * Math.pow(2, -10 * n) + 1);
+ },
+
+ expoInOut: function(/* Decimal? */n){
+ if(n == 0){ return 0; }
+ if(n == 1){ return 1; }
+ n = n * 2;
+ if(n < 1){ return Math.pow(2, 10 * (n - 1)) / 2; }
+ --n;
+ return (-1 * Math.pow(2, -10 * n) + 2) / 2;
+ },
+
+ circIn: function(/* Decimal? */n){
+ return -1 * (Math.sqrt(1 - Math.pow(n, 2)) - 1);
+ },
+
+ circOut: function(/* Decimal? */n){
+ n = n - 1;
+ return Math.sqrt(1 - Math.pow(n, 2));
+ },
+
+ circInOut: function(/* Decimal? */n){
+ n = n * 2;
+ if(n < 1){ return -1 / 2 * (Math.sqrt(1 - Math.pow(n, 2)) - 1); }
+ n -= 2;
+ return 1 / 2 * (Math.sqrt(1 - Math.pow(n, 2)) + 1);
+ },
+
+ backIn: function(/* Decimal? */n){
+ // summary:
+ // An easing function that starts away from the target,
+ // and quickly accelerates towards the end value.
+ //
+ // Use caution when the easing will cause values to become
+ // negative as some properties cannot be set to negative values.
+ var s = 1.70158;
+ return Math.pow(n, 2) * ((s + 1) * n - s);
+ },
+
+ backOut: function(/* Decimal? */n){
+ // summary:
+ // An easing function that pops past the range briefly, and slowly comes back.
+ //
+ // description:
+ // An easing function that pops past the range briefly, and slowly comes back.
+ //
+ // Use caution when the easing will cause values to become negative as some
+ // properties cannot be set to negative values.
+
+ n = n - 1;
+ var s = 1.70158;
+ return Math.pow(n, 2) * ((s + 1) * n + s) + 1;
+ },
+
+ backInOut: function(/* Decimal? */n){
+ // summary:
+ // An easing function combining the effects of `backIn` and `backOut`
+ //
+ // description:
+ // An easing function combining the effects of `backIn` and `backOut`.
+ // Use caution when the easing will cause values to become negative
+ // as some properties cannot be set to negative values.
+ var s = 1.70158 * 1.525;
+ n = n * 2;
+ if(n < 1){ return (Math.pow(n, 2) * ((s + 1) * n - s)) / 2; }
+ n-=2;
+ return (Math.pow(n, 2) * ((s + 1) * n + s) + 2) / 2;
+ },
+
+ elasticIn: function(/* Decimal? */n){
+ // summary:
+ // An easing function the elastically snaps from the start value
+ //
+ // description:
+ // An easing function the elastically snaps from the start value
+ //
+ // Use caution when the elasticity will cause values to become negative
+ // as some properties cannot be set to negative values.
+ if(n == 0 || n == 1){ return n; }
+ var p = .3;
+ var s = p / 4;
+ n = n - 1;
+ return -1 * Math.pow(2, 10 * n) * Math.sin((n - s) * (2 * Math.PI) / p);
+ },
+
+ elasticOut: function(/* Decimal? */n){
+ // summary:
+ // An easing function that elasticly snaps around the target value,
+ // near the end of the Animation
+ //
+ // description:
+ // An easing function that elasticly snaps around the target value,
+ // near the end of the Animation
+ //
+ // Use caution when the elasticity will cause values to become
+ // negative as some properties cannot be set to negative values.
+ if(n==0 || n == 1){ return n; }
+ var p = .3;
+ var s = p / 4;
+ return Math.pow(2, -10 * n) * Math.sin((n - s) * (2 * Math.PI) / p) + 1;
+ },
+
+ elasticInOut: function(/* Decimal? */n){
+ // summary:
+ // An easing function that elasticly snaps around the value, near
+ // the beginning and end of the Animation.
+ //
+ // description:
+ // An easing function that elasticly snaps around the value, near
+ // the beginning and end of the Animation.
+ //
+ // Use caution when the elasticity will cause values to become
+ // negative as some properties cannot be set to negative values.
+ if(n == 0) return 0;
+ n = n * 2;
+ if(n == 2) return 1;
+ var p = .3 * 1.5;
+ var s = p / 4;
+ if(n < 1){
+ n -= 1;
+ return -.5 * (Math.pow(2, 10 * n) * Math.sin((n - s) * (2 * Math.PI) / p));
+ }
+ n -= 1;
+ return .5 * (Math.pow(2, -10 * n) * Math.sin((n - s) * (2 * Math.PI) / p)) + 1;
+ },
+
+ bounceIn: function(/* Decimal? */n){
+ // summary:
+ // An easing function that 'bounces' near the beginning of an Animation
+ return (1 - dojo.fx.easing.bounceOut(1 - n)); // Decimal
+ },
+
+ bounceOut: function(/* Decimal? */n){
+ // summary:
+ // An easing function that 'bounces' near the end of an Animation
+ var s = 7.5625;
+ var p = 2.75;
+ var l;
+ if(n < (1 / p)){
+ l = s * Math.pow(n, 2);
+ }else if(n < (2 / p)){
+ n -= (1.5 / p);
+ l = s * Math.pow(n, 2) + .75;
+ }else if(n < (2.5 / p)){
+ n -= (2.25 / p);
+ l = s * Math.pow(n, 2) + .9375;
+ }else{
+ n -= (2.625 / p);
+ l = s * Math.pow(n, 2) + .984375;
+ }
+ return l;
+ },
+
+ bounceInOut: function(/* Decimal? */n){
+ // summary:
+ // An easing function that 'bounces' at the beginning and end of the Animation
+ if(n < 0.5){ return dojo.fx.easing.bounceIn(n * 2) / 2; }
+ return (dojo.fx.easing.bounceOut(n * 2 - 1) / 2) + 0.5; // Decimal
+ }
+};
+
}
diff --git a/lib/dojo/gears.js b/lib/dojo/gears.js
index 4b70c14da..aca6c5a4f 100644
--- a/lib/dojo/gears.js
+++ b/lib/dojo/gears.js
@@ -5,41 +5,59 @@
*/
-if(!dojo._hasResource["dojo.gears"]){
-dojo._hasResource["dojo.gears"]=true;
+if(!dojo._hasResource["dojo.gears"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.gears"] = true;
dojo.provide("dojo.gears");
-dojo.gears._gearsObject=function(){
-var _1;
-var _2;
-var _3=dojo.getObject("google.gears");
-if(_3){
-return _3;
-}
-if(typeof GearsFactory!="undefined"){
-_1=new GearsFactory();
-}else{
-if(dojo.isIE){
-try{
-_1=new ActiveXObject("Gears.Factory");
-}
-catch(e){
-}
-}else{
-if(navigator.mimeTypes["application/x-googlegears"]){
-_1=document.createElement("object");
-_1.setAttribute("type","application/x-googlegears");
-_1.setAttribute("width",0);
-_1.setAttribute("height",0);
-_1.style.display="none";
-document.documentElement.appendChild(_1);
-}
-}
-}
-if(!_1){
-return null;
-}
-dojo.setObject("google.gears.factory",_1);
-return dojo.getObject("google.gears");
+
+dojo.gears._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.gears.available=(!!dojo.gears._gearsObject())||0;
+
+/*=====
+dojo.gears.available = {
+ // 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.gears.available = (!!dojo.gears._gearsObject())||0;
+
}
diff --git a/lib/dojo/hash.js b/lib/dojo/hash.js
index b73d37058..6ef74b521 100644
--- a/lib/dojo/hash.js
+++ b/lib/dojo/hash.js
@@ -5,133 +5,235 @@
*/
-if(!dojo._hasResource["dojo.hash"]){
-dojo._hasResource["dojo.hash"]=true;
+if(!dojo._hasResource["dojo.hash"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.hash"] = true;
dojo.provide("dojo.hash");
+//TODOC: where does this go?
+// summary:
+// Methods for monitoring and updating the hash in the browser URL.
+//
+// example:
+// dojo.subscribe("/dojo/hashchange", context, callback);
+//
+// function callback (hashValue){
+// // do something based on the hash value.
+// }
+
(function(){
-dojo.hash=function(_1,_2){
-if(!arguments.length){
-return _3();
-}
-if(_1.charAt(0)=="#"){
-_1=_1.substring(1);
-}
-if(_2){
-_4(_1);
-}else{
-location.href="#"+_1;
-}
-return _1;
-};
-var _5=null,_6=null,_7=dojo.config.hashPollFrequency||100;
-function _8(_9,_a){
-var i=_9.indexOf(_a);
-return (i>=0)?_9.substring(i+1):"";
-};
-function _3(){
-return _8(location.href,"#");
-};
-function _b(){
-dojo.publish("/dojo/hashchange",[_3()]);
-};
-function _c(){
-if(_3()===_5){
-return;
-}
-_5=_3();
-_b();
-};
-function _4(_d){
-if(_6){
-if(_6.isTransitioning()){
-setTimeout(dojo.hitch(null,_4,_d),_7);
-return;
-}
-var _e=_6.iframe.location.href;
-var _f=_e.indexOf("?");
-_6.iframe.location.replace(_e.substring(0,_f)+"?"+_d);
-return;
-}
-location.replace("#"+_d);
-_c();
-};
-function _10(){
-var ifr=document.createElement("iframe"),_11="dojo-hash-iframe",_12=dojo.config.dojoBlankHtmlUrl||dojo.moduleUrl("dojo","resources/blank.html");
-ifr.id=_11;
-ifr.src=_12+"?"+_3();
-ifr.style.display="none";
-document.body.appendChild(ifr);
-this.iframe=dojo.global[_11];
-var _13,_14,_15,_16,_17,_18=this.iframe.location;
-function _19(){
-_5=_3();
-_13=_17?_5:_8(_18.href,"?");
-_14=false;
-_15=null;
-};
-this.isTransitioning=function(){
-return _14;
-};
-this.pollLocation=function(){
-if(!_17){
-try{
-var _1a=_8(_18.href,"?");
-if(document.title!=_16){
-_16=this.iframe.document.title=document.title;
-}
-}
-catch(e){
-_17=true;
-console.error("dojo.hash: Error adding history entry. Server unreachable.");
-}
-}
-var _1b=_3();
-if(_14&&_5===_1b){
-if(_17||_1a===_15){
-_19();
-_b();
-}else{
-setTimeout(dojo.hitch(this,this.pollLocation),0);
-return;
-}
-}else{
-if(_5===_1b&&(_17||_13===_1a)){
-}else{
-if(_5!==_1b){
-_5=_1b;
-_14=true;
-_15=_1b;
-ifr.src=_12+"?"+_15;
-_17=false;
-setTimeout(dojo.hitch(this,this.pollLocation),0);
-return;
-}else{
-if(!_17){
-location.href="#"+_18.search.substring(1);
-_19();
-_b();
-}
-}
-}
-}
-setTimeout(dojo.hitch(this,this.pollLocation),_7);
-};
-_19();
-setTimeout(dojo.hitch(this,this.pollLocation),_7);
-};
-dojo.addOnLoad(function(){
-if("onhashchange" in dojo.global&&(!dojo.isIE||(dojo.isIE>=8&&document.compatMode!="BackCompat"))){
-dojo.connect(dojo.global,"onhashchange",_b);
-}else{
-if(document.addEventListener){
-_5=_3();
-setInterval(_c,_7);
-}else{
-if(document.attachEvent){
-_6=new _10();
-}
-}
-}
-});
+ dojo.hash = function(/* String? */ hash, /* Boolean? */ replace){
+ // summary:
+ // Gets or sets the hash string.
+ // description:
+ // Handles getting and setting of location.hash.
+ // - If no arguments are passed, acts as a getter.
+ // - If a string is passed, acts as a setter.
+ // hash:
+ // String: the hash is set - #string.
+ // replace:
+ // Boolean: If true, updates the hash value in the current history
+ // state instead of creating a new history state.
+ // returns:
+ // when used as a getter, returns the current hash string.
+ // when used as a setter, returns the new hash string.
+
+ // getter
+ if(!arguments.length){
+ return _getHash();
+ }
+ // setter
+ if(hash.charAt(0) == "#"){
+ hash = hash.substring(1);
+ }
+ if(replace){
+ _replace(hash);
+ }else{
+ location.href = "#" + hash;
+ }
+ return hash; // String
+ }
+
+ // Global vars
+ var _recentHash = null,
+ _ieUriMonitor = null,
+ _pollFrequency = dojo.config.hashPollFrequency || 100;
+
+ //Internal functions
+ function _getSegment(str, delimiter){
+ var i = str.indexOf(delimiter);
+ return (i >= 0) ? str.substring(i+1) : "";
+ }
+
+ function _getHash(){
+ return _getSegment(location.href, "#");
+ }
+
+ function _dispatchEvent(){
+ dojo.publish("/dojo/hashchange", [_getHash()]);
+ }
+
+ function _pollLocation(){
+ if(_getHash() === _recentHash){
+ return;
+ }
+ _recentHash = _getHash();
+ _dispatchEvent();
+ }
+
+ function _replace(hash){
+ if(_ieUriMonitor){
+ if(_ieUriMonitor.isTransitioning()){
+ setTimeout(dojo.hitch(null,_replace,hash), _pollFrequency);
+ return;
+ }
+ var href = _ieUriMonitor.iframe.location.href;
+ var index = href.indexOf('?');
+ // main frame will detect and update itself
+ _ieUriMonitor.iframe.location.replace(href.substring(0, index) + "?" + hash);
+ return;
+ }
+ location.replace("#"+hash);
+ _pollLocation();
+ }
+
+ function IEUriMonitor(){
+ // summary:
+ // Determine if the browser's URI has changed or if the user has pressed the
+ // back or forward button. If so, call _dispatchEvent.
+ //
+ // description:
+ // IE doesn't add changes to the URI's hash into the history unless the hash
+ // value corresponds to an actual named anchor in the document. To get around
+ // this IE difference, we use a background IFrame to maintain a back-forward
+ // history, by updating the IFrame's query string to correspond to the
+ // value of the main browser location's hash value.
+ //
+ // E.g. if the value of the browser window's location changes to
+ //
+ // #action=someAction
+ //
+ // ... then we'd update the IFrame's source to:
+ //
+ // ?action=someAction
+ //
+ // This design leads to a somewhat complex state machine, which is
+ // described below:
+ //
+ // s1: Stable state - neither the window's location has changed nor
+ // has the IFrame's location. Note that this is the 99.9% case, so
+ // we optimize for it.
+ // Transitions: s1, s2, s3
+ // s2: Window's location changed - when a user clicks a hyperlink or
+ // code programmatically changes the window's URI.
+ // Transitions: s4
+ // s3: Iframe's location changed as a result of user pressing back or
+ // forward - when the user presses back or forward, the location of
+ // the background's iframe changes to the previous or next value in
+ // its history.
+ // Transitions: s1
+ // s4: IEUriMonitor has programmatically changed the location of the
+ // background iframe, but it's location hasn't yet changed. In this
+ // case we do nothing because we need to wait for the iframe's
+ // location to reflect its actual state.
+ // Transitions: s4, s5
+ // s5: IEUriMonitor has programmatically changed the location of the
+ // background iframe, and the iframe's location has caught up with
+ // reality. In this case we need to transition to s1.
+ // Transitions: s1
+ //
+ // The hashchange event is always dispatched on the transition back to s1.
+ //
+
+ // create and append iframe
+ var ifr = document.createElement("iframe"),
+ IFRAME_ID = "dojo-hash-iframe",
+ ifrSrc = dojo.config.dojoBlankHtmlUrl || dojo.moduleUrl("dojo", "resources/blank.html");
+ ifr.id = IFRAME_ID;
+ ifr.src = ifrSrc + "?" + _getHash();
+ ifr.style.display = "none";
+ document.body.appendChild(ifr);
+
+ this.iframe = dojo.global[IFRAME_ID];
+ var recentIframeQuery, transitioning, expectedIFrameQuery, docTitle, ifrOffline,
+ iframeLoc = this.iframe.location;
+
+ function resetState(){
+ _recentHash = _getHash();
+ recentIframeQuery = ifrOffline ? _recentHash : _getSegment(iframeLoc.href, "?");
+ transitioning = false;
+ expectedIFrameQuery = null;
+ }
+
+ this.isTransitioning = function(){
+ return transitioning;
+ }
+
+ this.pollLocation = function(){
+ if(!ifrOffline) {
+ try{
+ //see if we can access the iframe's location without a permission denied error
+ var iframeSearch = _getSegment(iframeLoc.href, "?");
+ //good, the iframe is same origin (no thrown exception)
+ if(document.title != docTitle){ //sync title of main window with title of iframe.
+ docTitle = this.iframe.document.title = document.title;
+ }
+ }catch(e){
+ //permission denied - server cannot be reached.
+ ifrOffline = true;
+ console.error("dojo.hash: Error adding history entry. Server unreachable.");
+ }
+ }
+ var hash = _getHash();
+ if(transitioning && _recentHash === hash){
+ // we're in an iframe transition (s4 or s5)
+ if(ifrOffline || iframeSearch === expectedIFrameQuery){
+ // s5 (iframe caught up to main window or iframe offline), transition back to s1
+ resetState();
+ _dispatchEvent();
+ }else{
+ // s4 (waiting for iframe to catch up to main window)
+ setTimeout(dojo.hitch(this,this.pollLocation),0);
+ return;
+ }
+ }else if(_recentHash === hash && (ifrOffline || recentIframeQuery === iframeSearch)){
+ // we're in stable state (s1, iframe query == main window hash), do nothing
+ }else{
+ // the user has initiated a URL change somehow.
+ // sync iframe query <-> main window hash
+ if(_recentHash !== hash){
+ // s2 (main window location changed), set iframe url and transition to s4
+ _recentHash = hash;
+ transitioning = true;
+ expectedIFrameQuery = hash;
+ ifr.src = ifrSrc + "?" + expectedIFrameQuery;
+ ifrOffline = false; //we're updating the iframe src - set offline to false so we can check again on next poll.
+ setTimeout(dojo.hitch(this,this.pollLocation),0); //yielded transition to s4 while iframe reloads.
+ return;
+ }else if(!ifrOffline){
+ // s3 (iframe location changed via back/forward button), set main window url and transition to s1.
+ location.href = "#" + iframeLoc.search.substring(1);
+ resetState();
+ _dispatchEvent();
+ }
+ }
+ setTimeout(dojo.hitch(this,this.pollLocation), _pollFrequency);
+ }
+ resetState(); // initialize state (transition to s1)
+ setTimeout(dojo.hitch(this,this.pollLocation), _pollFrequency);
+ }
+ dojo.addOnLoad(function(){
+ if("onhashchange" in dojo.global && (!dojo.isIE || (dojo.isIE >= 8 && document.compatMode != "BackCompat"))){ //need this IE browser test because "onhashchange" exists in IE8 in IE7 mode
+ dojo.connect(dojo.global,"onhashchange",_dispatchEvent);
+ }else{
+ if(document.addEventListener){ // Non-IE
+ _recentHash = _getHash();
+ setInterval(_pollLocation, _pollFrequency); //Poll the window location for changes
+ }else if(document.attachEvent){ // IE7-
+ //Use hidden iframe in versions of IE that don't have onhashchange event
+ _ieUriMonitor = new IEUriMonitor();
+ }
+ // else non-supported browser, do nothing.
+ }
+ });
})();
+
}
diff --git a/lib/dojo/html.js b/lib/dojo/html.js
index 7c15e5812..ec5c4986e 100644
--- a/lib/dojo/html.js
+++ b/lib/dojo/html.js
@@ -5,141 +5,327 @@
*/
-if(!dojo._hasResource["dojo.html"]){
-dojo._hasResource["dojo.html"]=true;
+if(!dojo._hasResource["dojo.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.html"] = true;
dojo.provide("dojo.html");
-dojo.require("dojo.parser");
-(function(){
-var _1=0,d=dojo;
-dojo.html._secureForInnerHtml=function(_2){
-return _2.replace(/(?:\s*<!DOCTYPE\s[^>]+>|<title[^>]*>[\s\S]*?<\/title>)/ig,"");
-};
-dojo.html._emptyNode=dojo.empty;
-dojo.html._setNodeContent=function(_3,_4){
-d.empty(_3);
-if(_4){
-if(typeof _4=="string"){
-_4=d._toDom(_4,_3.ownerDocument);
-}
-if(!_4.nodeType&&d.isArrayLike(_4)){
-for(var _5=_4.length,i=0;i<_4.length;i=_5==_4.length?i+1:0){
-d.place(_4[i],_3,"last");
-}
-}else{
-d.place(_4,_3,"last");
-}
-}
-return _3;
-};
-dojo.declare("dojo.html._ContentSetter",null,{node:"",content:"",id:"",cleanContent:false,extractContent:false,parseContent:false,constructor:function(_6,_7){
-dojo.mixin(this,_6||{});
-_7=this.node=dojo.byId(this.node||_7);
-if(!this.id){
-this.id=["Setter",(_7)?_7.id||_7.tagName:"",_1++].join("_");
-}
-},set:function(_8,_9){
-if(undefined!==_8){
-this.content=_8;
-}
-if(_9){
-this._mixin(_9);
-}
-this.onBegin();
-this.setContent();
-this.onEnd();
-return this.node;
-},setContent:function(){
-var _a=this.node;
-if(!_a){
-throw new Error(this.declaredClass+": setContent given no node");
-}
-try{
-_a=dojo.html._setNodeContent(_a,this.content);
-}
-catch(e){
-var _b=this.onContentError(e);
-try{
-_a.innerHTML=_b;
-}
-catch(e){
-console.error("Fatal "+this.declaredClass+".setContent could not change content due to "+e.message,e);
-}
-}
-this.node=_a;
-},empty:function(){
-if(this.parseResults&&this.parseResults.length){
-dojo.forEach(this.parseResults,function(w){
-if(w.destroy){
-w.destroy();
-}
-});
-delete this.parseResults;
-}
-dojo.html._emptyNode(this.node);
-},onBegin:function(){
-var _c=this.content;
-if(dojo.isString(_c)){
-if(this.cleanContent){
-_c=dojo.html._secureForInnerHtml(_c);
-}
-if(this.extractContent){
-var _d=_c.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
-if(_d){
-_c=_d[1];
-}
-}
-}
-this.empty();
-this.content=_c;
-return this.node;
-},onEnd:function(){
-if(this.parseContent){
-this._parse();
-}
-return this.node;
-},tearDown:function(){
-delete this.parseResults;
-delete this.node;
-delete this.content;
-},onContentError:function(_e){
-return "Error occured setting content: "+_e;
-},_mixin:function(_f){
-var _10={},key;
-for(key in _f){
-if(key in _10){
-continue;
-}
-this[key]=_f[key];
-}
-},_parse:function(){
-var _11=this.node;
-try{
-this.parseResults=dojo.parser.parse({rootNode:_11,dir:this.dir,lang:this.lang});
-}
-catch(e){
-this._onError("Content",e,"Error parsing in _ContentSetter#"+this.id);
-}
-},_onError:function(_12,err,_13){
-var _14=this["on"+_12+"Error"].call(this,err);
-if(_13){
-console.error(_13,err);
-}else{
-if(_14){
-dojo.html._setNodeContent(this.node,_14,true);
-}
-}
-}});
-dojo.html.set=function(_15,_16,_17){
-if(undefined==_16){
-console.warn("dojo.html.set: no cont argument provided, using empty string");
-_16="";
-}
-if(!_17){
-return dojo.html._setNodeContent(_15,_16,true);
-}else{
-var op=new dojo.html._ContentSetter(dojo.mixin(_17,{content:_16,node:_15}));
-return op.set();
-}
-};
+
+// the parser might be needed..
+dojo.require("dojo.parser");
+
+(function(){ // private scope, sort of a namespace
+
+ // idCounter is incremented with each instantiation to allow asignment of a unique id for tracking, logging purposes
+ var idCounter = 0,
+ d = dojo;
+
+ dojo.html._secureForInnerHtml = function(/*String*/ cont){
+ // summary:
+ // removes !DOCTYPE and title elements from the html string.
+ //
+ // khtml is picky about dom faults, you can't attach a style or <title> node as child of body
+ // must go into head, so we need to cut out those tags
+ // cont:
+ // An html string for insertion into the dom
+ //
+ return cont.replace(/(?:\s*<!DOCTYPE\s[^>]+>|<title[^>]*>[\s\S]*?<\/title>)/ig, ""); // String
+ };
+
+/*====
+ dojo.html._emptyNode = function(node){
+ // summary:
+ // removes all child nodes from the given node
+ // node: DOMNode
+ // the parent element
+ };
+=====*/
+ dojo.html._emptyNode = dojo.empty;
+
+ dojo.html._setNodeContent = function(/* DomNode */ node, /* String|DomNode|NodeList */ cont){
+ // summary:
+ // inserts the given content into the given node
+ // node:
+ // the parent element
+ // content:
+ // the content to be set on the parent element.
+ // This can be an html string, a node reference or a NodeList, dojo.NodeList, Array or other enumerable list of nodes
+
+ // always empty
+ d.empty(node);
+
+ if(cont) {
+ if(typeof cont == "string") {
+ cont = d._toDom(cont, node.ownerDocument);
+ }
+ if(!cont.nodeType && d.isArrayLike(cont)) {
+ // handle as enumerable, but it may shrink as we enumerate it
+ for(var startlen=cont.length, i=0; i<cont.length; i=startlen==cont.length ? i+1 : 0) {
+ d.place( cont[i], node, "last");
+ }
+ } else {
+ // pass nodes, documentFragments and unknowns through to dojo.place
+ d.place(cont, node, "last");
+ }
+ }
+
+ // return DomNode
+ return node;
+ };
+
+ // we wrap up the content-setting operation in a object
+ dojo.declare("dojo.html._ContentSetter", null,
+ {
+ // node: DomNode|String
+ // An node which will be the parent element that we set content into
+ node: "",
+
+ // content: String|DomNode|DomNode[]
+ // The content to be placed in the node. Can be an HTML string, a node reference, or a enumerable list of nodes
+ content: "",
+
+ // id: String?
+ // Usually only used internally, and auto-generated with each instance
+ id: "",
+
+ // cleanContent: Boolean
+ // Should the content be treated as a full html document,
+ // and the real content stripped of <html>, <body> wrapper before injection
+ cleanContent: false,
+
+ // extractContent: Boolean
+ // Should the content be treated as a full html document, and the real content stripped of <html>, <body> wrapper before injection
+ extractContent: false,
+
+ // parseContent: Boolean
+ // Should the node by passed to the parser after the new content is set
+ parseContent: false,
+
+ // lifecyle methods
+ constructor: function(/* Object */params, /* String|DomNode */node){
+ // summary:
+ // Provides a configurable, extensible object to wrap the setting on content on a node
+ // call the set() method to actually set the content..
+
+ // the original params are mixed directly into the instance "this"
+ dojo.mixin(this, params || {});
+
+ // give precedence to params.node vs. the node argument
+ // and ensure its a node, not an id string
+ node = this.node = dojo.byId( this.node || node );
+
+ if(!this.id){
+ this.id = [
+ "Setter",
+ (node) ? node.id || node.tagName : "",
+ idCounter++
+ ].join("_");
+ }
+ },
+ set: function(/* String|DomNode|NodeList? */ cont, /* Object? */ params){
+ // summary:
+ // front-end to the set-content sequence
+ // cont:
+ // An html string, node or enumerable list of nodes for insertion into the dom
+ // If not provided, the object's content property will be used
+ if(undefined !== cont){
+ this.content = cont;
+ }
+ // in the re-use scenario, set needs to be able to mixin new configuration
+ if(params){
+ this._mixin(params);
+ }
+
+ this.onBegin();
+ this.setContent();
+ this.onEnd();
+
+ return this.node;
+ },
+ setContent: function(){
+ // summary:
+ // sets the content on the node
+
+ var node = this.node;
+ if(!node) {
+ // can't proceed
+ throw new Error(this.declaredClass + ": setContent given no node");
+ }
+ try{
+ node = dojo.html._setNodeContent(node, this.content);
+ }catch(e){
+ // check if a domfault occurs when we are appending this.errorMessage
+ // like for instance if domNode is a UL and we try append a DIV
+
+ // FIXME: need to allow the user to provide a content error message string
+ var errMess = this.onContentError(e);
+ try{
+ node.innerHTML = errMess;
+ }catch(e){
+ console.error('Fatal ' + this.declaredClass + '.setContent could not change content due to '+e.message, e);
+ }
+ }
+ // always put back the node for the next method
+ this.node = node; // DomNode
+ },
+
+ empty: function() {
+ // summary
+ // cleanly empty out existing content
+
+ // destroy any widgets from a previous run
+ // NOTE: if you dont want this you'll need to empty
+ // the parseResults array property yourself to avoid bad things happenning
+ if(this.parseResults && this.parseResults.length) {
+ dojo.forEach(this.parseResults, function(w) {
+ if(w.destroy){
+ w.destroy();
+ }
+ });
+ delete this.parseResults;
+ }
+ // this is fast, but if you know its already empty or safe, you could
+ // override empty to skip this step
+ dojo.html._emptyNode(this.node);
+ },
+
+ onBegin: function(){
+ // summary
+ // Called after instantiation, but before set();
+ // It allows modification of any of the object properties
+ // - including the node and content provided - before the set operation actually takes place
+ // This default implementation checks for cleanContent and extractContent flags to
+ // optionally pre-process html string content
+ var cont = this.content;
+
+ if(dojo.isString(cont)){
+ if(this.cleanContent){
+ cont = dojo.html._secureForInnerHtml(cont);
+ }
+
+ if(this.extractContent){
+ var match = cont.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+ if(match){ cont = match[1]; }
+ }
+ }
+
+ // clean out the node and any cruft associated with it - like widgets
+ this.empty();
+
+ this.content = cont;
+ return this.node; /* DomNode */
+ },
+
+ onEnd: function(){
+ // summary
+ // Called after set(), when the new content has been pushed into the node
+ // It provides an opportunity for post-processing before handing back the node to the caller
+ // This default implementation checks a parseContent flag to optionally run the dojo parser over the new content
+ if(this.parseContent){
+ // populates this.parseResults if you need those..
+ this._parse();
+ }
+ return this.node; /* DomNode */
+ },
+
+ tearDown: function(){
+ // summary
+ // manually reset the Setter instance if its being re-used for example for another set()
+ // description
+ // tearDown() is not called automatically.
+ // In normal use, the Setter instance properties are simply allowed to fall out of scope
+ // but the tearDown method can be called to explicitly reset this instance.
+ delete this.parseResults;
+ delete this.node;
+ delete this.content;
+ },
+
+ onContentError: function(err){
+ return "Error occured setting content: " + err;
+ },
+
+ _mixin: function(params){
+ // mix properties/methods into the instance
+ // TODO: the intention with tearDown is to put the Setter's state
+ // back to that of the original constructor (vs. deleting/resetting everything regardless of ctor params)
+ // so we could do something here to move the original properties aside for later restoration
+ var empty = {}, key;
+ for(key in params){
+ if(key in empty){ continue; }
+ // TODO: here's our opportunity to mask the properties we dont consider configurable/overridable
+ // .. but history shows we'll almost always guess wrong
+ this[key] = params[key];
+ }
+ },
+ _parse: function(){
+ // summary:
+ // runs the dojo parser over the node contents, storing any results in this.parseResults
+ // Any errors resulting from parsing are passed to _onError for handling
+
+ var rootNode = this.node;
+ try{
+ // store the results (widgets, whatever) for potential retrieval
+ this.parseResults = dojo.parser.parse({
+ rootNode: rootNode,
+ dir: this.dir,
+ lang: this.lang
+ });
+ }catch(e){
+ this._onError('Content', e, "Error parsing in _ContentSetter#"+this.id);
+ }
+ },
+
+ _onError: function(type, err, consoleText){
+ // summary:
+ // shows user the string that is returned by on[type]Error
+ // overide/implement on[type]Error and return your own string to customize
+ var errText = this['on' + type + 'Error'].call(this, err);
+ if(consoleText){
+ console.error(consoleText, err);
+ }else if(errText){ // a empty string won't change current content
+ dojo.html._setNodeContent(this.node, errText, true);
+ }
+ }
+ }); // end dojo.declare()
+
+ dojo.html.set = function(/* DomNode */ node, /* String|DomNode|NodeList */ cont, /* Object? */ params){
+ // summary:
+ // inserts (replaces) the given content into the given node. dojo.place(cont, node, "only")
+ // may be a better choice for simple HTML insertion.
+ // description:
+ // Unless you need to use the params capabilities of this method, you should use
+ // dojo.place(cont, node, "only"). dojo.place() has more robust support for injecting
+ // an HTML string into the DOM, but it only handles inserting an HTML string as DOM
+ // elements, or inserting a DOM node. dojo.place does not handle NodeList insertions
+ // or the other capabilities as defined by the params object for this method.
+ // node:
+ // the parent element that will receive the content
+ // cont:
+ // the content to be set on the parent element.
+ // This can be an html string, a node reference or a NodeList, dojo.NodeList, Array or other enumerable list of nodes
+ // params:
+ // Optional flags/properties to configure the content-setting. See dojo.html._ContentSetter
+ // example:
+ // A safe string/node/nodelist content replacement/injection with hooks for extension
+ // Example Usage:
+ // dojo.html.set(node, "some string");
+ // dojo.html.set(node, contentNode, {options});
+ // dojo.html.set(node, myNode.childNodes, {options});
+ if(undefined == cont){
+ console.warn("dojo.html.set: no cont argument provided, using empty string");
+ cont = "";
+ }
+ if(!params){
+ // simple and fast
+ return dojo.html._setNodeContent(node, cont, true);
+ }else{
+ // more options but slower
+ // note the arguments are reversed in order, to match the convention for instantiation via the parser
+ var op = new dojo.html._ContentSetter(dojo.mixin(
+ params,
+ { content: cont, node: node }
+ ));
+ return op.set();
+ }
+ };
})();
+
}
diff --git a/lib/dojo/i18n.js b/lib/dojo/i18n.js
index e914392a1..d06a8f25e 100644
--- a/lib/dojo/i18n.js
+++ b/lib/dojo/i18n.js
@@ -5,167 +5,254 @@
*/
-if(!dojo._hasResource["dojo.i18n"]){
-dojo._hasResource["dojo.i18n"]=true;
+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.getLocalization=function(_1,_2,_3){
-_3=dojo.i18n.normalizeLocale(_3);
-var _4=_3.split("-");
-var _5=[_1,"nls",_2].join(".");
-var _6=dojo._loadedModules[_5];
-if(_6){
-var _7;
-for(var i=_4.length;i>0;i--){
-var _8=_4.slice(0,i).join("_");
-if(_6[_8]){
-_7=_6[_8];
-break;
-}
-}
-if(!_7){
-_7=_6.ROOT;
-}
-if(_7){
-var _9=function(){
-};
-_9.prototype=_7;
-return new _9();
-}
-}
-throw new Error("Bundle not found: "+_2+" in "+_1+" , locale="+_3);
+
+/*=====
+dojo.i18n = {
+ // summary: Utility classes to enable loading of resources for internationalization (i18n)
};
-dojo.i18n.normalizeLocale=function(_a){
-var _b=_a?_a.toLowerCase():dojo.locale;
-if(_b=="root"){
-_b="ROOT";
-}
-return _b;
+=====*/
+
+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._requireLocalization=function(_c,_d,_e,_f){
-var _10=dojo.i18n.normalizeLocale(_e);
-var _11=[_c,"nls",_d].join(".");
-var _12="";
-if(_f){
-var _13=_f.split(",");
-for(var i=0;i<_13.length;i++){
-if(_10["indexOf"](_13[i])==0){
-if(_13[i].length>_12.length){
-_12=_13[i];
-}
-}
-}
-if(!_12){
-_12="ROOT";
-}
-}
-var _14=_f?_12:_10;
-var _15=dojo._loadedModules[_11];
-var _16=null;
-if(_15){
-if(dojo.config.localizationComplete&&_15._built){
-return;
-}
-var _17=_14.replace(/-/g,"_");
-var _18=_11+"."+_17;
-_16=dojo._loadedModules[_18];
-}
-if(!_16){
-_15=dojo["provide"](_11);
-var _19=dojo._getModuleSymbols(_c);
-var _1a=_19.concat("nls").join("/");
-var _1b;
-dojo.i18n._searchLocalePath(_14,_f,function(loc){
-var _1c=loc.replace(/-/g,"_");
-var _1d=_11+"."+_1c;
-var _1e=false;
-if(!dojo._loadedModules[_1d]){
-dojo["provide"](_1d);
-var _1f=[_1a];
-if(loc!="ROOT"){
-_1f.push(loc);
-}
-_1f.push(_d);
-var _20=_1f.join("/")+".js";
-_1e=dojo._loadPath(_20,null,function(_21){
-var _22=function(){
+
+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
};
-_22.prototype=_1b;
-_15[_1c]=new _22();
-for(var j in _21){
-_15[_1c][j]=_21[j];
-}
-});
-}else{
-_1e=true;
-}
-if(_1e&&_15[_1c]){
-_1b=_15[_1c];
-}else{
-_15[_1c]=_1b;
-}
-if(_f){
-return true;
-}
-});
-}
-if(_f&&_10!=_12){
-_15[_10.replace(/-/g,"_")]=_15[_12.replace(/-/g,"_")];
-}
+
+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.
+ //Using ["indexOf"] so customBase builds do not see
+ //this as a dojo._base.array dependency.
+ 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(){
-var _23=dojo.config.extraLocale;
-if(_23){
-if(!_23 instanceof Array){
-_23=[_23];
-}
-var req=dojo.i18n._requireLocalization;
-dojo.i18n._requireLocalization=function(m,b,_24,_25){
-req(m,b,_24,_25);
-if(_24){
-return;
-}
-for(var i=0;i<_23.length;i++){
-req(m,b,_23[i],_25);
-}
-};
-}
+ // If other locales are used, dojo.requireLocalization should load them as
+ // well, by default.
+ //
+ // Override dojo.requireLocalization to do load the default bundle, then
+ // iterate through the extraLocale list and load those translations as
+ // well, unless a particular locale was requested.
+
+ var extra = dojo.config.extraLocale;
+ if(extra){
+ if(!extra instanceof Array){
+ extra = [extra];
+ }
+
+ var req = dojo.i18n._requireLocalization;
+ dojo.i18n._requireLocalization = function(m, b, locale, availableFlatLocales){
+ req(m,b,locale, availableFlatLocales);
+ if(locale){return;}
+ for(var i=0; i<extra.length; i++){
+ req(m,b,extra[i], availableFlatLocales);
+ }
+ };
+ }
})();
-dojo.i18n._searchLocalePath=function(_26,_27,_28){
-_26=dojo.i18n.normalizeLocale(_26);
-var _29=_26.split("-");
-var _2a=[];
-for(var i=_29.length;i>0;i--){
-_2a.push(_29.slice(0,i).join("-"));
-}
-_2a.push(false);
-if(_27){
-_2a.reverse();
-}
-for(var j=_2a.length-1;j>=0;j--){
-var loc=_2a[j]||"ROOT";
-var _2b=_28(loc);
-if(_2b){
-break;
-}
-}
-};
-dojo.i18n._preloadLocalizations=function(_2c,_2d){
-function _2e(_2f){
-_2f=dojo.i18n.normalizeLocale(_2f);
-dojo.i18n._searchLocalePath(_2f,true,function(loc){
-for(var i=0;i<_2d.length;i++){
-if(_2d[i]==loc){
-dojo["require"](_2c+"_"+loc);
-return true;
-}
-}
-return false;
-});
+
+dojo.i18n._searchLocalePath = function(/*String*/locale, /*Boolean*/down, /*Function*/searchFunc){
+ // summary:
+ // A helper method to assist in searching for locale-based resources.
+ // Will iterate through the variants of a particular locale, either up
+ // or down, executing a callback function. For example, "en-us" and
+ // true will try "en-us" followed by "en" and finally "ROOT".
+
+ locale = dojo.i18n.normalizeLocale(locale);
+
+ var elements = locale.split('-');
+ var searchlist = [];
+ for(var i = elements.length; i > 0; i--){
+ searchlist.push(elements.slice(0, i).join('-'));
+ }
+ searchlist.push(false);
+ if(down){searchlist.reverse();}
+
+ for(var j = searchlist.length - 1; j >= 0; j--){
+ var loc = searchlist[j] || "ROOT";
+ var stop = searchFunc(loc);
+ if(stop){ break; }
+ }
};
-_2e();
-var _30=dojo.config.extraLocale||[];
-for(var i=0;i<_30.length;i++){
-_2e(_30[i]);
-}
+
+dojo.i18n._preloadLocalizations = function(/*String*/bundlePrefix, /*Array*/localesGenerated){
+ // summary:
+ // Load built, flattened resource bundles, if available for all
+ // locales used in the page. Only called by built layer files.
+
+ function preload(locale){
+ locale = dojo.i18n.normalizeLocale(locale);
+ dojo.i18n._searchLocalePath(locale, true, function(loc){
+ for(var i=0; i<localesGenerated.length;i++){
+ if(localesGenerated[i] == loc){
+ dojo["require"](bundlePrefix+"_"+loc);
+ return true; // Boolean
+ }
+ }
+ return false; // Boolean
+ });
+ }
+ preload();
+ var extra = dojo.config.extraLocale||[];
+ for(var i=0; i<extra.length; i++){
+ preload(extra[i]);
+ }
};
+
}
diff --git a/lib/dojo/io/iframe.js b/lib/dojo/io/iframe.js
index 105af1697..5b2af45a1 100644
--- a/lib/dojo/io/iframe.js
+++ b/lib/dojo/io/iframe.js
@@ -5,261 +5,407 @@
*/
-if(!dojo._hasResource["dojo.io.iframe"]){
-dojo._hasResource["dojo.io.iframe"]=true;
+if(!dojo._hasResource["dojo.io.iframe"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.io.iframe"] = true;
dojo.provide("dojo.io.iframe");
-dojo.io.iframe={create:function(_1,_2,_3){
-if(window[_1]){
-return window[_1];
-}
-if(window.frames[_1]){
-return window.frames[_1];
-}
-var _4=null;
-var _5=_3;
-if(!_5){
-if(dojo.config["useXDomain"]&&!dojo.config["dojoBlankHtmlUrl"]){
-console.warn("dojo.io.iframe.create: When using cross-domain Dojo builds,"+" please save dojo/resources/blank.html to your domain and set djConfig.dojoBlankHtmlUrl"+" to the path on your domain to blank.html");
-}
-_5=(dojo.config["dojoBlankHtmlUrl"]||dojo.moduleUrl("dojo","resources/blank.html"));
-}
-var _6=dojo.isIE?"<iframe name=\""+_1+"\" src=\""+_5+"\" onload=\""+_2+"\">":"iframe";
-_4=dojo.doc.createElement(_6);
-with(_4){
-name=_1;
-setAttribute("name",_1);
-id=_1;
-}
-dojo.body().appendChild(_4);
-window[_1]=_4;
-with(_4.style){
-if(!(dojo.isSafari<3)){
-position="absolute";
-}
-left=top="1px";
-height=width="1px";
-visibility="hidden";
-}
-if(!dojo.isIE){
-this.setSrc(_4,_5,true);
-_4.onload=new Function(_2);
-}
-return _4;
-},setSrc:function(_7,_8,_9){
-try{
-if(!_9){
-if(dojo.isWebKit){
-_7.location=_8;
-}else{
-frames[_7.name].location=_8;
-}
-}else{
-var _a;
-if(dojo.isIE||dojo.isWebKit>521){
-_a=_7.contentWindow.document;
-}else{
-if(dojo.isSafari){
-_a=_7.document;
-}else{
-_a=_7.contentWindow;
-}
-}
-if(!_a){
-_7.location=_8;
-return;
-}else{
-_a.location.replace(_8);
-}
-}
-}
-catch(e){
-}
-},doc:function(_b){
-var _c=_b.contentDocument||(((_b.name)&&(_b.document)&&(dojo.doc.getElementsByTagName("iframe")[_b.name].contentWindow)&&(dojo.doc.getElementsByTagName("iframe")[_b.name].contentWindow.document)))||((_b.name)&&(dojo.doc.frames[_b.name])&&(dojo.doc.frames[_b.name].document))||null;
-return _c;
-},send:function(_d){
-if(!this["_frame"]){
-this._frame=this.create(this._iframeName,dojo._scopeName+".io.iframe._iframeOnload();");
-}
-var _e=dojo._ioSetArgs(_d,function(_f){
-_f.canceled=true;
-_f.ioArgs._callNext();
-},function(dfd){
-var _10=null;
-try{
-var _11=dfd.ioArgs;
-var dii=dojo.io.iframe;
-var ifd=dii.doc(dii._frame);
-var _12=_11.handleAs;
-_10=ifd;
-if(_12!="html"){
-if(_12=="xml"){
-if(dojo.isIE){
-dojo.query("a",dii._frame.contentWindow.document.documentElement).orphan();
-var _13=(dii._frame.contentWindow.document).documentElement.innerText;
-_13=_13.replace(/>\s+</g,"><");
-_13=dojo.trim(_13);
-var _14={responseText:_13};
-_10=dojo._contentHandlers["xml"](_14);
-}
-}else{
-_10=ifd.getElementsByTagName("textarea")[0].value;
-if(_12=="json"){
-_10=dojo.fromJson(_10);
-}else{
-if(_12=="javascript"){
-_10=dojo.eval(_10);
-}
-}
-}
-}
-}
-catch(e){
-_10=e;
-}
-finally{
-_11._callNext();
-}
-return _10;
-},function(_15,dfd){
-dfd.ioArgs._hasError=true;
-dfd.ioArgs._callNext();
-return _15;
-});
-_e.ioArgs._callNext=function(){
-if(!this["_calledNext"]){
-this._calledNext=true;
-dojo.io.iframe._currentDfd=null;
-dojo.io.iframe._fireNextRequest();
-}
-};
-this._dfdQueue.push(_e);
-this._fireNextRequest();
-dojo._ioWatch(_e,function(dfd){
-return !dfd.ioArgs["_hasError"];
-},function(dfd){
-return (!!dfd.ioArgs["_finished"]);
-},function(dfd){
-if(dfd.ioArgs._finished){
-dfd.callback(dfd);
-}else{
-dfd.errback(new Error("Invalid dojo.io.iframe request state"));
-}
+
+/*=====
+dojo.declare("dojo.io.iframe.__ioArgs", dojo.__IoArgs, {
+ constructor: function(){
+ // summary:
+ // All the properties described in the dojo.__ioArgs type, apply
+ // to this type. The following additional properties are allowed
+ // for dojo.io.iframe.send():
+ // method: String?
+ // The HTTP method to use. "GET" or "POST" are the only supported
+ // values. It will try to read the value from the form node's
+ // method, then try this argument. If neither one exists, then it
+ // defaults to POST.
+ // handleAs: String?
+ // Specifies what format the result data should be given to the
+ // load/handle callback. Valid values are: text, html, xml, json,
+ // javascript. IMPORTANT: For all values EXCEPT html and xml, The
+ // server response should be an HTML file with a textarea element.
+ // The response data should be inside the textarea element. Using an
+ // HTML document the only reliable, cross-browser way this
+ // transport can know when the response has loaded. For the html
+ // handleAs value, just return a normal HTML document. NOTE: xml
+ // is now supported with this transport (as of 1.1+); a known issue
+ // is if the XML document in question is malformed, Internet Explorer
+ // will throw an uncatchable error.
+ // content: Object?
+ // If "form" is one of the other args properties, then the content
+ // object properties become hidden form form elements. For
+ // instance, a content object of {name1 : "value1"} is converted
+ // to a hidden form element with a name of "name1" and a value of
+ // "value1". If there is not a "form" property, then the content
+ // object is converted into a name=value&name=value string, by
+ // using dojo.objectToQuery().
+ this.method = method;
+ this.handleAs = handleAs;
+ this.content = content;
+ }
});
-return _e;
-},_currentDfd:null,_dfdQueue:[],_iframeName:dojo._scopeName+"IoIframe",_fireNextRequest:function(){
-try{
-if((this._currentDfd)||(this._dfdQueue.length==0)){
-return;
-}
-do{
-var dfd=this._currentDfd=this._dfdQueue.shift();
-}while(dfd&&dfd.canceled&&this._dfdQueue.length);
-if(!dfd||dfd.canceled){
-this._currentDfd=null;
-return;
-}
-var _16=dfd.ioArgs;
-var _17=_16.args;
-_16._contentToClean=[];
-var fn=dojo.byId(_17["form"]);
-var _18=_17["content"]||{};
-if(fn){
-if(_18){
-var _19=function(_1a,_1b){
-var tn;
-if(dojo.isIE){
-tn=dojo.doc.createElement("<input type='hidden' name='"+_1a+"'>");
-}else{
-tn=dojo.doc.createElement("input");
-tn.type="hidden";
-tn.name=_1a;
-}
-tn.value=_1b;
-fn.appendChild(tn);
-_16._contentToClean.push(_1a);
-};
-for(var x in _18){
-var val=_18[x];
-if(dojo.isArray(val)&&val.length>1){
-var i;
-for(i=0;i<val.length;i++){
-_19(x,val[i]);
-}
-}else{
-if(!fn[x]){
-_19(x,val);
-}else{
-fn[x].value=val;
-}
-}
-}
-}
-var _1c=fn.getAttributeNode("action");
-var _1d=fn.getAttributeNode("method");
-var _1e=fn.getAttributeNode("target");
-if(_17["url"]){
-_16._originalAction=_1c?_1c.value:null;
-if(_1c){
-_1c.value=_17.url;
-}else{
-fn.setAttribute("action",_17.url);
-}
-}
-if(!_1d||!_1d.value){
-if(_1d){
-_1d.value=(_17["method"])?_17["method"]:"post";
-}else{
-fn.setAttribute("method",(_17["method"])?_17["method"]:"post");
-}
-}
-_16._originalTarget=_1e?_1e.value:null;
-if(_1e){
-_1e.value=this._iframeName;
-}else{
-fn.setAttribute("target",this._iframeName);
-}
-fn.target=this._iframeName;
-dojo._ioNotifyStart(dfd);
-fn.submit();
-}else{
-var _1f=_17.url+(_17.url.indexOf("?")>-1?"&":"?")+_16.query;
-dojo._ioNotifyStart(dfd);
-this.setSrc(this._frame,_1f,true);
-}
-}
-catch(e){
-dfd.errback(e);
-}
-},_iframeOnload:function(){
-var dfd=this._currentDfd;
-if(!dfd){
-this._fireNextRequest();
-return;
-}
-var _20=dfd.ioArgs;
-var _21=_20.args;
-var _22=dojo.byId(_21.form);
-if(_22){
-var _23=_20._contentToClean;
-for(var i=0;i<_23.length;i++){
-var key=_23[i];
-for(var j=0;j<_22.childNodes.length;j++){
-var _24=_22.childNodes[j];
-if(_24.name==key){
-dojo.destroy(_24);
-break;
-}
-}
-}
-if(_20["_originalAction"]){
-_22.setAttribute("action",_20._originalAction);
-}
-if(_20["_originalTarget"]){
-_22.setAttribute("target",_20._originalTarget);
-_22.target=_20._originalTarget;
-}
+=====*/
+
+dojo.io.iframe = {
+ // summary:
+ // Sends an Ajax I/O call using and Iframe (for instance, to upload files)
+
+ create: function(/*String*/fname, /*String*/onloadstr, /*String?*/uri){
+ // summary:
+ // Creates a hidden iframe in the page. Used mostly for IO
+ // transports. You do not need to call this to start a
+ // dojo.io.iframe request. Just call send().
+ // fname: String
+ // The name of the iframe. Used for the name attribute on the
+ // iframe.
+ // onloadstr: String
+ // A string of JavaScript that will be executed when the content
+ // in the iframe loads.
+ // uri: String
+ // The value of the src attribute on the iframe element. If a
+ // value is not given, then dojo/resources/blank.html will be
+ // used.
+ if(window[fname]){ return window[fname]; }
+ if(window.frames[fname]){ return window.frames[fname]; }
+ var cframe = null;
+ var turi = uri;
+ if(!turi){
+ if(dojo.config["useXDomain"] && !dojo.config["dojoBlankHtmlUrl"]){
+ console.warn("dojo.io.iframe.create: When using cross-domain Dojo builds,"
+ + " please save dojo/resources/blank.html to your domain and set djConfig.dojoBlankHtmlUrl"
+ + " to the path on your domain to blank.html");
+ }
+ turi = (dojo.config["dojoBlankHtmlUrl"]||dojo.moduleUrl("dojo", "resources/blank.html"));
+ }
+ var ifrstr = dojo.isIE ? '<iframe name="'+fname+'" src="'+turi+'" onload="'+onloadstr+'">' : 'iframe';
+ cframe = dojo.doc.createElement(ifrstr);
+ with(cframe){
+ name = fname;
+ setAttribute("name", fname);
+ id = fname;
+ }
+ dojo.body().appendChild(cframe);
+ window[fname] = cframe;
+
+ with(cframe.style){
+ if(!(dojo.isSafari < 3)){
+ //We can't change the src in Safari 2.0.3 if absolute position. Bizarro.
+ position = "absolute";
+ }
+ left = top = "1px";
+ height = width = "1px";
+ visibility = "hidden";
+ }
+
+ if(!dojo.isIE){
+ this.setSrc(cframe, turi, true);
+ cframe.onload = new Function(onloadstr);
+ }
+
+ return cframe;
+ },
+
+ setSrc: function(/*DOMNode*/iframe, /*String*/src, /*Boolean*/replace){
+ //summary:
+ // Sets the URL that is loaded in an IFrame. The replace parameter
+ // indicates whether location.replace() should be used when
+ // changing the location of the iframe.
+ try{
+ if(!replace){
+ if(dojo.isWebKit){
+ iframe.location = src;
+ }else{
+ frames[iframe.name].location = src;
+ }
+ }else{
+ // Fun with DOM 0 incompatibilities!
+ var idoc;
+ //WebKit > 521 corresponds with Safari 3, which started with 522 WebKit version.
+ if(dojo.isIE || dojo.isWebKit > 521){
+ idoc = iframe.contentWindow.document;
+ }else if(dojo.isSafari){
+ idoc = iframe.document;
+ }else{ // if(d.isMozilla){
+ idoc = iframe.contentWindow;
+ }
+
+ //For Safari (at least 2.0.3) and Opera, if the iframe
+ //has just been created but it doesn't have content
+ //yet, then iframe.document may be null. In that case,
+ //use iframe.location and return.
+ if(!idoc){
+ iframe.location = src;
+ return;
+ }else{
+ idoc.location.replace(src);
+ }
+ }
+ }catch(e){
+ console.log("dojo.io.iframe.setSrc: ", e);
+ }
+ },
+
+ doc: function(/*DOMNode*/iframeNode){
+ //summary: Returns the document object associated with the iframe DOM Node argument.
+ var doc = iframeNode.contentDocument || // W3
+ (
+ (
+ (iframeNode.name) && (iframeNode.document) &&
+ (dojo.doc.getElementsByTagName("iframe")[iframeNode.name].contentWindow) &&
+ (dojo.doc.getElementsByTagName("iframe")[iframeNode.name].contentWindow.document)
+ )
+ ) || // IE
+ (
+ (iframeNode.name)&&(dojo.doc.frames[iframeNode.name])&&
+ (dojo.doc.frames[iframeNode.name].document)
+ ) || null;
+ return doc;
+ },
+
+ send: function(/*dojo.io.iframe.__ioArgs*/args){
+ //summary:
+ // Function that sends the request to the server.
+ // This transport can only process one send() request at a time, so if send() is called
+ //multiple times, it will queue up the calls and only process one at a time.
+ if(!this["_frame"]){
+ this._frame = this.create(this._iframeName, dojo._scopeName + ".io.iframe._iframeOnload();");
+ }
+
+ //Set up the deferred.
+ var dfd = dojo._ioSetArgs(
+ args,
+ function(/*Deferred*/dfd){
+ //summary: canceller function for dojo._ioSetArgs call.
+ dfd.canceled = true;
+ dfd.ioArgs._callNext();
+ },
+ function(/*Deferred*/dfd){
+ //summary: okHandler function for dojo._ioSetArgs call.
+ var value = null;
+ try{
+ var ioArgs = dfd.ioArgs;
+ var dii = dojo.io.iframe;
+ var ifd = dii.doc(dii._frame);
+ var handleAs = ioArgs.handleAs;
+
+ //Assign correct value based on handleAs value.
+ value = ifd; //html
+ if(handleAs != "html"){
+ if(handleAs == "xml"){
+ // FF, Saf 3+ and Opera all seem to be fine with ifd being xml. We have to
+ // do it manually for IE. Refs #6334.
+ if(dojo.isIE){
+ dojo.query("a", dii._frame.contentWindow.document.documentElement).orphan();
+ var xmlText=(dii._frame.contentWindow.document).documentElement.innerText;
+ xmlText=xmlText.replace(/>\s+</g, "><");
+ xmlText=dojo.trim(xmlText);
+ //Reusing some code in base dojo for handling XML content. Simpler and keeps
+ //Core from duplicating the effort needed to locate the XML Parser on IE.
+ var fauxXhr = { responseText: xmlText };
+ value = dojo._contentHandlers["xml"](fauxXhr); // DOMDocument
+ }
+ }else{
+ value = ifd.getElementsByTagName("textarea")[0].value; //text
+ if(handleAs == "json"){
+ value = dojo.fromJson(value); //json
+ }else if(handleAs == "javascript"){
+ value = dojo.eval(value); //javascript
+ }
+ }
+ }
+ }catch(e){
+ value = e;
+ }finally{
+ ioArgs._callNext();
+ }
+ return value;
+ },
+ function(/*Error*/error, /*Deferred*/dfd){
+ //summary: errHandler function for dojo._ioSetArgs call.
+ dfd.ioArgs._hasError = true;
+ dfd.ioArgs._callNext();
+ return error;
+ }
+ );
+
+ //Set up a function that will fire the next iframe request. Make sure it only
+ //happens once per deferred.
+ dfd.ioArgs._callNext = function(){
+ if(!this["_calledNext"]){
+ this._calledNext = true;
+ dojo.io.iframe._currentDfd = null;
+ dojo.io.iframe._fireNextRequest();
+ }
+ }
+
+ this._dfdQueue.push(dfd);
+ this._fireNextRequest();
+
+ //Add it the IO watch queue, to get things like timeout support.
+ dojo._ioWatch(
+ dfd,
+ function(/*Deferred*/dfd){
+ //validCheck
+ return !dfd.ioArgs["_hasError"];
+ },
+ function(dfd){
+ //ioCheck
+ return (!!dfd.ioArgs["_finished"]);
+ },
+ function(dfd){
+ //resHandle
+ if(dfd.ioArgs._finished){
+ dfd.callback(dfd);
+ }else{
+ dfd.errback(new Error("Invalid dojo.io.iframe request state"));
+ }
+ }
+ );
+
+ return dfd;
+ },
+
+ _currentDfd: null,
+ _dfdQueue: [],
+ _iframeName: dojo._scopeName + "IoIframe",
+
+ _fireNextRequest: function(){
+ //summary: Internal method used to fire the next request in the bind queue.
+ try{
+ if((this._currentDfd)||(this._dfdQueue.length == 0)){ return; }
+ //Find next deferred, skip the canceled ones.
+ do{
+ var dfd = this._currentDfd = this._dfdQueue.shift();
+ } while(dfd && dfd.canceled && this._dfdQueue.length);
+
+ //If no more dfds, cancel.
+ if(!dfd || dfd.canceled){
+ this._currentDfd = null;
+ return;
+ }
+
+ var ioArgs = dfd.ioArgs;
+ var args = ioArgs.args;
+
+ ioArgs._contentToClean = [];
+ var fn = dojo.byId(args["form"]);
+ var content = args["content"] || {};
+ if(fn){
+ if(content){
+ // if we have things in content, we need to add them to the form
+ // before submission
+ var pHandler = function(name, value) {
+ var tn;
+ if(dojo.isIE){
+ tn = dojo.doc.createElement("<input type='hidden' name='"+name+"'>");
+ }else{
+ tn = dojo.doc.createElement("input");
+ tn.type = "hidden";
+ tn.name = name;
+ }
+ tn.value = value;
+ fn.appendChild(tn);
+ ioArgs._contentToClean.push(name);
+ };
+ for(var x in content){
+ var val = content[x];
+ if(dojo.isArray(val) && val.length > 1){
+ var i;
+ for (i = 0; i < val.length; i++) {
+ pHandler(x,val[i]);
+ }
+ }else{
+ if(!fn[x]){
+ pHandler(x,val);
+ }else{
+ fn[x].value = val;
+ }
+ }
+ }
+ }
+ //IE requires going through getAttributeNode instead of just getAttribute in some form cases,
+ //so use it for all. See #2844
+ var actnNode = fn.getAttributeNode("action");
+ var mthdNode = fn.getAttributeNode("method");
+ var trgtNode = fn.getAttributeNode("target");
+ if(args["url"]){
+ ioArgs._originalAction = actnNode ? actnNode.value : null;
+ if(actnNode){
+ actnNode.value = args.url;
+ }else{
+ fn.setAttribute("action",args.url);
+ }
+ }
+ if(!mthdNode || !mthdNode.value){
+ if(mthdNode){
+ mthdNode.value= (args["method"]) ? args["method"] : "post";
+ }else{
+ fn.setAttribute("method", (args["method"]) ? args["method"] : "post");
+ }
+ }
+ ioArgs._originalTarget = trgtNode ? trgtNode.value: null;
+ if(trgtNode){
+ trgtNode.value = this._iframeName;
+ }else{
+ fn.setAttribute("target", this._iframeName);
+ }
+ fn.target = this._iframeName;
+ dojo._ioNotifyStart(dfd);
+ fn.submit();
+ }else{
+ // otherwise we post a GET string by changing URL location for the
+ // iframe
+ var tmpUrl = args.url + (args.url.indexOf("?") > -1 ? "&" : "?") + ioArgs.query;
+ dojo._ioNotifyStart(dfd);
+ this.setSrc(this._frame, tmpUrl, true);
+ }
+ }catch(e){
+ dfd.errback(e);
+ }
+ },
+
+ _iframeOnload: function(){
+ var dfd = this._currentDfd;
+ if(!dfd){
+ this._fireNextRequest();
+ return;
+ }
+
+ var ioArgs = dfd.ioArgs;
+ var args = ioArgs.args;
+ var fNode = dojo.byId(args.form);
+
+ if(fNode){
+ // remove all the hidden content inputs
+ var toClean = ioArgs._contentToClean;
+ for(var i = 0; i < toClean.length; i++) {
+ var key = toClean[i];
+ //Need to cycle over all nodes since we may have added
+ //an array value which means that more than one node could
+ //have the same .name value.
+ for(var j = 0; j < fNode.childNodes.length; j++){
+ var chNode = fNode.childNodes[j];
+ if(chNode.name == key){
+ dojo.destroy(chNode);
+ break;
+ }
+ }
+ }
+
+ // restore original action + target
+ if(ioArgs["_originalAction"]){
+ fNode.setAttribute("action", ioArgs._originalAction);
+ }
+ if(ioArgs["_originalTarget"]){
+ fNode.setAttribute("target", ioArgs._originalTarget);
+ fNode.target = ioArgs._originalTarget;
+ }
+ }
+
+ ioArgs._finished = true;
+ }
}
-_20._finished=true;
-}};
+
}
diff --git a/lib/dojo/io/script.js b/lib/dojo/io/script.js
index 9a940634d..9730c977d 100644
--- a/lib/dojo/io/script.js
+++ b/lib/dojo/io/script.js
@@ -5,114 +5,256 @@
*/
-if(!dojo._hasResource["dojo.io.script"]){
-dojo._hasResource["dojo.io.script"]=true;
+if(!dojo._hasResource["dojo.io.script"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.io.script"] = true;
dojo.provide("dojo.io.script");
-(function(){
-var _1=dojo.isIE?"onreadystatechange":"load",_2=/complete|loaded/;
-dojo.io.script={get:function(_3){
-var _4=this._makeScriptDeferred(_3);
-var _5=_4.ioArgs;
-dojo._ioAddQueryToUrl(_5);
-dojo._ioNotifyStart(_4);
-if(this._canAttach(_5)){
-var _6=this.attach(_5.id,_5.url,_3.frameDoc);
-if(!_5.jsonp&&!_5.args.checkString){
-var _7=dojo.connect(_6,_1,function(_8){
-if(_8.type=="load"||_2.test(_6.readyState)){
-dojo.disconnect(_7);
-_5.scriptLoaded=_8;
-}
+
+/*=====
+dojo.declare("dojo.io.script.__ioArgs", dojo.__IoArgs, {
+ constructor: function(){
+ // summary:
+ // All the properties described in the dojo.__ioArgs type, apply to this
+ // type as well, EXCEPT "handleAs". It is not applicable to
+ // dojo.io.script.get() calls, since it is implied by the usage of
+ // "jsonp" (response will be a JSONP call returning JSON)
+ // or the response is pure JavaScript defined in
+ // the body of the script that was attached.
+ // callbackParamName: String
+ // Deprecated as of Dojo 1.4 in favor of "jsonp", but still supported for
+ // legacy code. See notes for jsonp property.
+ // jsonp: String
+ // The URL parameter name that indicates the JSONP callback string.
+ // For instance, when using Yahoo JSONP calls it is normally,
+ // jsonp: "callback". For AOL JSONP calls it is normally
+ // jsonp: "c".
+ // checkString: String
+ // A string of JavaScript that when evaluated like so:
+ // "typeof(" + checkString + ") != 'undefined'"
+ // being true means that the script fetched has been loaded.
+ // Do not use this if doing a JSONP type of call (use callbackParamName instead).
+ // frameDoc: Document
+ // The Document object for a child iframe. If this is passed in, the script
+ // will be attached to that document. This can be helpful in some comet long-polling
+ // scenarios with Firefox and Opera.
+ this.callbackParamName = callbackParamName;
+ this.jsonp = jsonp;
+ this.checkString = checkString;
+ this.frameDoc = frameDoc;
+ }
});
-}
-}
-dojo._ioWatch(_4,this._validCheck,this._ioCheck,this._resHandle);
-return _4;
-},attach:function(id,_9,_a){
-var _b=(_a||dojo.doc);
-var _c=_b.createElement("script");
-_c.type="text/javascript";
-_c.src=_9;
-_c.id=id;
-_c.charset="utf-8";
-return _b.getElementsByTagName("head")[0].appendChild(_c);
-},remove:function(id,_d){
-dojo.destroy(dojo.byId(id,_d));
-if(this["jsonp_"+id]){
-delete this["jsonp_"+id];
-}
-},_makeScriptDeferred:function(_e){
-var _f=dojo._ioSetArgs(_e,this._deferredCancel,this._deferredOk,this._deferredError);
-var _10=_f.ioArgs;
-_10.id=dojo._scopeName+"IoScript"+(this._counter++);
-_10.canDelete=false;
-_10.jsonp=_e.callbackParamName||_e.jsonp;
-if(_10.jsonp){
-_10.query=_10.query||"";
-if(_10.query.length>0){
-_10.query+="&";
-}
-_10.query+=_10.jsonp+"="+(_e.frameDoc?"parent.":"")+dojo._scopeName+".io.script.jsonp_"+_10.id+"._jsonpCallback";
-_10.frameDoc=_e.frameDoc;
-_10.canDelete=true;
-_f._jsonpCallback=this._jsonpCallback;
-this["jsonp_"+_10.id]=_f;
-}
-return _f;
-},_deferredCancel:function(dfd){
-dfd.canceled=true;
-if(dfd.ioArgs.canDelete){
-dojo.io.script._addDeadScript(dfd.ioArgs);
-}
-},_deferredOk:function(dfd){
-var _11=dfd.ioArgs;
-if(_11.canDelete){
-dojo.io.script._addDeadScript(_11);
-}
-return _11.json||_11.scriptLoaded||_11;
-},_deferredError:function(_12,dfd){
-if(dfd.ioArgs.canDelete){
-if(_12.dojoType=="timeout"){
-dojo.io.script.remove(dfd.ioArgs.id,dfd.ioArgs.frameDoc);
-}else{
-dojo.io.script._addDeadScript(dfd.ioArgs);
-}
-}
-return _12;
-},_deadScripts:[],_counter:1,_addDeadScript:function(_13){
-dojo.io.script._deadScripts.push({id:_13.id,frameDoc:_13.frameDoc});
-_13.frameDoc=null;
-},_validCheck:function(dfd){
-var _14=dojo.io.script;
-var _15=_14._deadScripts;
-if(_15&&_15.length>0){
-for(var i=0;i<_15.length;i++){
-_14.remove(_15[i].id,_15[i].frameDoc);
-_15[i].frameDoc=null;
-}
-dojo.io.script._deadScripts=[];
-}
-return true;
-},_ioCheck:function(dfd){
-var _16=dfd.ioArgs;
-if(_16.json||(_16.scriptLoaded&&!_16.args.checkString)){
-return true;
-}
-var _17=_16.args.checkString;
-if(_17&&eval("typeof("+_17+") != 'undefined'")){
-return true;
-}
-return false;
-},_resHandle:function(dfd){
-if(dojo.io.script._ioCheck(dfd)){
-dfd.callback(dfd);
-}else{
-dfd.errback(new Error("inconceivable dojo.io.script._resHandle error"));
-}
-},_canAttach:function(_18){
-return true;
-},_jsonpCallback:function(_19){
-this.ioArgs.json=_19;
-}};
+=====*/
+;(function(){
+ var loadEvent = dojo.isIE ? "onreadystatechange" : "load",
+ readyRegExp = /complete|loaded/;
+
+ dojo.io.script = {
+ get: function(/*dojo.io.script.__ioArgs*/args){
+ // summary:
+ // sends a get request using a dynamically created script tag.
+ var dfd = this._makeScriptDeferred(args);
+ var ioArgs = dfd.ioArgs;
+ dojo._ioAddQueryToUrl(ioArgs);
+
+ dojo._ioNotifyStart(dfd);
+
+ if(this._canAttach(ioArgs)){
+ var node = this.attach(ioArgs.id, ioArgs.url, args.frameDoc);
+
+ //If not a jsonp callback or a polling checkString case, bind
+ //to load event on the script tag.
+ if(!ioArgs.jsonp && !ioArgs.args.checkString){
+ var handle = dojo.connect(node, loadEvent, function(evt){
+ if(evt.type == "load" || readyRegExp.test(node.readyState)){
+ dojo.disconnect(handle);
+ ioArgs.scriptLoaded = evt;
+ }
+ });
+ }
+ }
+
+ dojo._ioWatch(dfd, this._validCheck, this._ioCheck, this._resHandle);
+ return dfd;
+ },
+
+ attach: function(/*String*/id, /*String*/url, /*Document?*/frameDocument){
+ // summary:
+ // creates a new <script> tag pointing to the specified URL and
+ // adds it to the document.
+ // description:
+ // Attaches the script element to the DOM. Use this method if you
+ // just want to attach a script to the DOM and do not care when or
+ // if it loads.
+ var doc = (frameDocument || dojo.doc);
+ var element = doc.createElement("script");
+ element.type = "text/javascript";
+ element.src = url;
+ element.id = id;
+ element.charset = "utf-8";
+ return doc.getElementsByTagName("head")[0].appendChild(element);
+ },
+
+ remove: function(/*String*/id, /*Document?*/frameDocument){
+ //summary: removes the script element with the given id, from the given frameDocument.
+ //If no frameDocument is passed, the current document is used.
+ dojo.destroy(dojo.byId(id, frameDocument));
+
+ //Remove the jsonp callback on dojo.io.script, if it exists.
+ if(this["jsonp_" + id]){
+ delete this["jsonp_" + id];
+ }
+ },
+
+ _makeScriptDeferred: function(/*Object*/args){
+ //summary:
+ // sets up a Deferred object for an IO request.
+ var dfd = dojo._ioSetArgs(args, this._deferredCancel, this._deferredOk, this._deferredError);
+
+ var ioArgs = dfd.ioArgs;
+ ioArgs.id = dojo._scopeName + "IoScript" + (this._counter++);
+ ioArgs.canDelete = false;
+
+ //Special setup for jsonp case
+ ioArgs.jsonp = args.callbackParamName || args.jsonp;
+ if(ioArgs.jsonp){
+ //Add the jsonp parameter.
+ ioArgs.query = ioArgs.query || "";
+ if(ioArgs.query.length > 0){
+ ioArgs.query += "&";
+ }
+ ioArgs.query += ioArgs.jsonp
+ + "="
+ + (args.frameDoc ? "parent." : "")
+ + dojo._scopeName + ".io.script.jsonp_" + ioArgs.id + "._jsonpCallback";
+
+ ioArgs.frameDoc = args.frameDoc;
+
+ //Setup the Deferred to have the jsonp callback.
+ ioArgs.canDelete = true;
+ dfd._jsonpCallback = this._jsonpCallback;
+ this["jsonp_" + ioArgs.id] = dfd;
+ }
+ return dfd; // dojo.Deferred
+ },
+
+ _deferredCancel: function(/*Deferred*/dfd){
+ //summary: canceller function for dojo._ioSetArgs call.
+
+ //DO NOT use "this" and expect it to be dojo.io.script.
+ dfd.canceled = true;
+ if(dfd.ioArgs.canDelete){
+ dojo.io.script._addDeadScript(dfd.ioArgs);
+ }
+ },
+
+ _deferredOk: function(/*Deferred*/dfd){
+ //summary: okHandler function for dojo._ioSetArgs call.
+
+ //DO NOT use "this" and expect it to be dojo.io.script.
+ var ioArgs = dfd.ioArgs;
+
+ //Add script to list of things that can be removed.
+ if(ioArgs.canDelete){
+ dojo.io.script._addDeadScript(ioArgs);
+ }
+
+ //Favor JSONP responses, script load events then lastly ioArgs.
+ //The ioArgs are goofy, but cannot return the dfd since that stops
+ //the callback chain in Deferred. The return value is not that important
+ //in that case, probably a checkString case.
+ return ioArgs.json || ioArgs.scriptLoaded || ioArgs;
+ },
+
+ _deferredError: function(/*Error*/error, /*Deferred*/dfd){
+ //summary: errHandler function for dojo._ioSetArgs call.
+
+ if(dfd.ioArgs.canDelete){
+ //DO NOT use "this" and expect it to be dojo.io.script.
+ if(error.dojoType == "timeout"){
+ //For timeouts, remove the script element immediately to
+ //avoid a response from it coming back later and causing trouble.
+ dojo.io.script.remove(dfd.ioArgs.id, dfd.ioArgs.frameDoc);
+ }else{
+ dojo.io.script._addDeadScript(dfd.ioArgs);
+ }
+ }
+ console.log("dojo.io.script error", error);
+ return error;
+ },
+
+ _deadScripts: [],
+ _counter: 1,
+
+ _addDeadScript: function(/*Object*/ioArgs){
+ //summary: sets up an entry in the deadScripts array.
+ dojo.io.script._deadScripts.push({id: ioArgs.id, frameDoc: ioArgs.frameDoc});
+ //Being extra paranoid about leaks:
+ ioArgs.frameDoc = null;
+ },
+
+ _validCheck: function(/*Deferred*/dfd){
+ //summary: inflight check function to see if dfd is still valid.
+
+ //Do script cleanup here. We wait for one inflight pass
+ //to make sure we don't get any weird things by trying to remove a script
+ //tag that is part of the call chain (IE 6 has been known to
+ //crash in that case).
+ var _self = dojo.io.script;
+ var deadScripts = _self._deadScripts;
+ if(deadScripts && deadScripts.length > 0){
+ for(var i = 0; i < deadScripts.length; i++){
+ //Remove the script tag
+ _self.remove(deadScripts[i].id, deadScripts[i].frameDoc);
+ deadScripts[i].frameDoc = null;
+ }
+ dojo.io.script._deadScripts = [];
+ }
+
+ return true;
+ },
+
+ _ioCheck: function(/*Deferred*/dfd){
+ //summary: inflight check function to see if IO finished.
+ var ioArgs = dfd.ioArgs;
+ //Check for finished jsonp
+ if(ioArgs.json || (ioArgs.scriptLoaded && !ioArgs.args.checkString)){
+ return true;
+ }
+
+ //Check for finished "checkString" case.
+ var checkString = ioArgs.args.checkString;
+ if(checkString && eval("typeof(" + checkString + ") != 'undefined'")){
+ return true;
+ }
+
+ return false;
+ },
+
+ _resHandle: function(/*Deferred*/dfd){
+ //summary: inflight function to handle a completed response.
+ if(dojo.io.script._ioCheck(dfd)){
+ dfd.callback(dfd);
+ }else{
+ //This path should never happen since the only way we can get
+ //to _resHandle is if _ioCheck is true.
+ dfd.errback(new Error("inconceivable dojo.io.script._resHandle error"));
+ }
+ },
+
+ _canAttach: function(/*Object*/ioArgs){
+ //summary: A method that can be overridden by other modules
+ //to control when the script attachment occurs.
+ return true;
+ },
+
+ _jsonpCallback: function(/*JSON Object*/json){
+ //summary:
+ // generic handler for jsonp callback. A pointer to this function
+ // is used for all jsonp callbacks. NOTE: the "this" in this
+ // function will be the Deferred object that represents the script
+ // request.
+ this.ioArgs.json = json;
+ }
+ }
})();
+
}
diff --git a/lib/dojo/jaxer.js b/lib/dojo/jaxer.js
index b9cf0dfe2..fdc492f1c 100644
--- a/lib/dojo/jaxer.js
+++ b/lib/dojo/jaxer.js
@@ -5,15 +5,18 @@
*/
-if(!dojo._hasResource["dojo.jaxer"]){
-dojo._hasResource["dojo.jaxer"]=true;
+if(!dojo._hasResource["dojo.jaxer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.jaxer"] = true;
dojo.provide("dojo.jaxer");
-if(typeof print=="function"){
-console.debug=Jaxer.Log.debug;
-console.warn=Jaxer.Log.warn;
-console.error=Jaxer.Log.error;
-console.info=Jaxer.Log.info;
-console.log=Jaxer.Log.warn;
+
+if(typeof print == "function"){
+ console.debug = Jaxer.Log.debug;
+ console.warn = Jaxer.Log.warn;
+ console.error = Jaxer.Log.error;
+ console.info = Jaxer.Log.info;
+ console.log = Jaxer.Log.warn;
}
-onserverload=dojo._loadInit;
+
+onserverload = dojo._loadInit;
+
}
diff --git a/lib/dojo/nls/tt-rss-layer_ROOT.js b/lib/dojo/nls/tt-rss-layer_ROOT.js
new file mode 100644
index 000000000..1b351daf4
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_ROOT.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_ROOT");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.ROOT");dojo.nls.colors.ROOT={"lightsteelblue":"light steel blue","orangered":"orange red","midnightblue":"midnight blue","cadetblue":"cadet blue","seashell":"seashell","slategrey":"slate gray","coral":"coral","darkturquoise":"dark turquoise","antiquewhite":"antique white","mediumspringgreen":"medium spring green","salmon":"salmon","darkgrey":"dark gray","ivory":"ivory","greenyellow":"green-yellow","mistyrose":"misty rose","lightsalmon":"light salmon","silver":"silver","dimgrey":"dim gray","orange":"orange","white":"white","navajowhite":"navajo white","royalblue":"royal blue","deeppink":"deep pink","lime":"lime","oldlace":"old lace","chartreuse":"chartreuse","darkcyan":"dark cyan","yellow":"yellow","linen":"linen","olive":"olive","gold":"gold","lawngreen":"lawn green","lightyellow":"light yellow","tan":"tan","darkviolet":"dark violet","lightslategrey":"light slate gray","grey":"gray","darkkhaki":"dark khaki","green":"green","deepskyblue":"deep sky blue","aqua":"aqua","sienna":"sienna","mintcream":"mint cream","rosybrown":"rosy brown","mediumslateblue":"medium slate blue","magenta":"magenta","lightseagreen":"light sea green","cyan":"cyan","olivedrab":"olive drab","darkgoldenrod":"dark goldenrod","slateblue":"slate blue","mediumaquamarine":"medium aquamarine","lavender":"lavender","mediumseagreen":"medium sea green","maroon":"maroon","darkslategray":"dark slate gray","mediumturquoise":"medium turquoise","ghostwhite":"ghost white","darkblue":"dark blue","mediumvioletred":"medium violet-red","brown":"brown","lightgray":"light gray","sandybrown":"sandy brown","pink":"pink","firebrick":"fire brick","indigo":"indigo","snow":"snow","darkorchid":"dark orchid","turquoise":"turquoise","chocolate":"chocolate","springgreen":"spring green","moccasin":"moccasin","navy":"navy","lemonchiffon":"lemon chiffon","teal":"teal","floralwhite":"floral white","cornflowerblue":"cornflower blue","paleturquoise":"pale turquoise","purple":"purple","gainsboro":"gainsboro","plum":"plum","red":"red","blue":"blue","forestgreen":"forest green","darkgreen":"dark green","honeydew":"honeydew","darkseagreen":"dark sea green","lightcoral":"light coral","palevioletred":"pale violet-red","mediumpurple":"medium purple","saddlebrown":"saddle brown","darkmagenta":"dark magenta","thistle":"thistle","whitesmoke":"white smoke","wheat":"wheat","violet":"violet","lightskyblue":"light sky blue","goldenrod":"goldenrod","mediumblue":"medium blue","skyblue":"sky blue","crimson":"crimson","darksalmon":"dark salmon","darkred":"dark red","darkslategrey":"dark slate gray","peru":"peru","lightgrey":"light gray","lightgoldenrodyellow":"light goldenrod yellow","blanchedalmond":"blanched almond","aliceblue":"alice blue","bisque":"bisque","slategray":"slate gray","palegoldenrod":"pale goldenrod","darkorange":"dark orange","aquamarine":"aquamarine","lightgreen":"light green","burlywood":"burlywood","dodgerblue":"dodger blue","darkgray":"dark gray","lightcyan":"light cyan","powderblue":"powder blue","blueviolet":"blue-violet","orchid":"orchid","dimgray":"dim gray","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavender blush","hotpink":"hot pink","steelblue":"steel blue","tomato":"tomato","lightpink":"light pink","limegreen":"lime green","indianred":"indian red","papayawhip":"papaya whip","lightslategray":"light slate gray","gray":"gray","mediumorchid":"medium orchid","cornsilk":"cornsilk","black":"black","seagreen":"sea green","darkslateblue":"dark slate blue","khaki":"khaki","lightblue":"light blue","palegreen":"pale green","azure":"azure","peachpuff":"peach puff","darkolivegreen":"dark olive green","yellowgreen":"yellow green"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.ROOT");dijit.nls.loading.ROOT={"loadingState":"Loading...","errorState":"Sorry, an error occurred"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.ROOT");dijit.nls.common.ROOT={"buttonOk":"OK","buttonCancel":"Cancel","buttonSave":"Save","itemClose":"Close"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.ROOT");dijit.form.nls.validate.ROOT={"rangeMessage":"This value is out of range.","invalidMessage":"The value entered is not valid.","missingMessage":"This value is required."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.ROOT");dijit.form.nls.ComboBox.ROOT={"previousMessage":"Previous choices","nextMessage":"More choices"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.ROOT");dojo.cldr.nls.number.ROOT={"scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencyFormat":"¤ #,##0.00","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","group":",","percentFormat":"#,##0%","decimalFormat":"#,##0.###","decimal":".","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"};
diff --git a/lib/dojo/nls/tt-rss-layer_ar.js b/lib/dojo/nls/tt-rss-layer_ar.js
new file mode 100644
index 000000000..6a19c6d6a
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_ar.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_ar");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.ar");dojo.nls.colors.ar={"lightsteelblue":"أزرق معدني فاتح","orangered":"أحمر مائل للبرتقالي","midnightblue":"أزرق بحري","cadetblue":"أزرق ملون بالرمادي","seashell":"أبيض مائل للأصفر فاتح","slategrey":"رمادي اردوازي","coral":"مرجاني","darkturquoise":"تركواز داكن","antiquewhite":"أبيض عتيق","mediumspringgreen":"أخضر ربيعي متوسط","salmon":"برتقالي وردي شاحب","darkgrey":"رمادي داكن","ivory":"عاجي","greenyellow":"أخضر مائل للأصفر","mistyrose":"وردي","lightsalmon":"فضي فاتح","silver":"فضي","dimgrey":"رمادي شاحب","orange":"برتقالي","white":"أبيض","navajowhite":"أبيض ملاحي","royalblue":"أزرق ملكي","deeppink":"أحمر وردي غامق","lime":"ليموني","oldlace":"برتقالي مائل للأصفر شاحب","chartreuse":"أخضر مائل للصفرة","darkcyan":"أزرق سماوي داكن","yellow":"أصفر","linen":"كتاني","olive":"أخضر زيتوني داكن","gold":"ذهبي","lawngreen":"أخضر بلون العشب","lightyellow":"أصفر فاتح","tan":"خمري","darkviolet":"بنفسجي داكن","lightslategrey":"رمادي اردوازي فاتح","grey":"رمادي","darkkhaki":"كاكي داكن","green":"أخضر","deepskyblue":"أزرق سماوي غامق","aqua":"أزرق مائي","sienna":"بني محروق","mintcream":"أصفر شاحب مائل للأخضر الزرعي","rosybrown":"بني وردي","mediumslateblue":"أزرق اردوازي متوسط","magenta":"أحمر قرمزي","lightseagreen":"أخضر مائل للأزرق فاتح","cyan":"أزرق سماوي","olivedrab":"أسود فاتح","darkgoldenrod":"أصفر ذهبي داكن","slateblue":"أزرق اردوازي","mediumaquamarine":"أزرق مائل للأخضر (زبرجد) متوسط","lavender":"أرجواني شاحب","mediumseagreen":"أخضر مائل للأزرق متوسط","maroon":"أحمر داكن","darkslategray":"رمادي اردوازي داكن","mediumturquoise":"تركواز متوسط","ghostwhite":"أبيض شفاف","darkblue":"أزرق داكن","mediumvioletred":"أحمر-بنفسجي متوسط","brown":"بني","lightgray":"رمادي فاتح","sandybrown":"بني مائل للصفرة","pink":"وردي","firebrick":"أصفر زاهي","indigo":"نيلي","snow":"أبيض ثلجي","darkorchid":"أرجواني داكن","turquoise":"تركواز","chocolate":"بني غامق","springgreen":"أخضر ربيعي","moccasin":"نحاسي أحمر","navy":"أزرق داكن","lemonchiffon":"أصفر شفاف","teal":"بترولي","floralwhite":"أبيض زهري","cornflowerblue":"أزرق عنبري","paleturquoise":"تركواز شاحب","purple":"ارجواني","gainsboro":"رمادي مائل للأزرق فاتح","plum":"أرجواني داكن","red":"أحمر","blue":"أزرق","forestgreen":"أخضر بلون أشجار الغابات","darkgreen":"أخضر داكن","honeydew":"أبيض مائل للأخضر","darkseagreen":"أخضر مائل للأزرق داكن","lightcoral":"مرجاني فاتح","palevioletred":"أحمر-بنفسجي شاحب","mediumpurple":"قرمزي متوسط","saddlebrown":"بني فاتح","darkmagenta":"قرمزي داكن","thistle":"ارجواني شاحب","whitesmoke":"دخان أبيض","wheat":"أخضر قمحي","violet":"بنفسجي","lightskyblue":"أزرق سماوي فاتح","goldenrod":"أصفر ذهبي","mediumblue":"أزرق متوسط","skyblue":"أزرق سماوي","crimson":"قرمزي","darksalmon":"فضي داكن","darkred":"أحمر داكن","darkslategrey":"رمادي اردوازي داكن","peru":"بني جملي","lightgrey":"رمادي فاتح","lightgoldenrodyellow":"أصفر ذهبي فاتح","blanchedalmond":"أخضر مائل للبياض","aliceblue":"أزرق فاتح","bisque":"أصفر برتقالي الى رمادي مصفر","slategray":"رمادي اردوازي","palegoldenrod":"أصفر ذهبي شاحب","darkorange":"برتقالي داكن","aquamarine":"أزرق مائل للأخضر (زبرجد)","lightgreen":"أخضر فاتح","burlywood":"خشبي","dodgerblue":"أزرق عنبري","darkgray":"رمادي داكن","lightcyan":"سماوي فاتح","powderblue":"أزرق مائل للأصفر","blueviolet":"أزرق-بنفسجي","orchid":"أرجواني فاتح","dimgray":"رمادي شاحب","beige":"بيج","fuchsia":"فوشيا","lavenderblush":"أحمر أرجواني","hotpink":"أحمر وردي زاهي","steelblue":"أزرق معدني","tomato":"أحمر مائل للأصفر","lightpink":"وردي فاتح","limegreen":"أخضر ليموني","indianred":"أحمر هندي","papayawhip":"خوخي فاتح","lightslategray":"رمادي اردوازي فاتح","gray":"رمادي","mediumorchid":"أرجواني متوسط","cornsilk":"حريري","black":"أسود","seagreen":"أخضر مائل للأزرق","darkslateblue":"أزرق اردوازي داكن","khaki":"كاكي","lightblue":"أزرق فاتح","palegreen":"أخضر شاحب","azure":"أزرق سماوي","peachpuff":"خوخي مائل للأصفر","darkolivegreen":"أخضر زيتوني داكن","yellowgreen":"أخضر مائل للأصفر"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.ar");dijit.nls.loading.ar={"loadingState":"جاري التحميل...","errorState":"عفوا، حدث خطأ"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.ar");dijit.nls.common.ar={"buttonOk":"حسنا","buttonCancel":"الغاء","buttonSave":"حفظ","itemClose":"اغلاق"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.ar");dijit.form.nls.validate.ar={"rangeMessage":"هذه القيمة ليس بالمدى الصحيح.","invalidMessage":"القيمة التي تم ادخالها غير صحيحة.","missingMessage":"يجب ادخال هذه القيمة."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.ar");dijit.form.nls.ComboBox.ar={"previousMessage":"الاختيارات السابقة","nextMessage":"مزيد من الاختيارات"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.ar");dojo.cldr.nls.number.ar={"group":"٬","percentSign":"٪","exponential":"اس","list":"؛","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":"٫","nan":"ليس رقم","nativeZeroDigit":"٠","perMille":"؉","decimalFormat":"#,##0.###;#,##0.###-","currencyFormat":"¤ #,##0.00;¤ #,##0.00-","plusSign":"+","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","percentFormat":"#,##0%","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_ca.js b/lib/dojo/nls/tt-rss-layer_ca.js
new file mode 100644
index 000000000..0f56ef882
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_ca.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_ca");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.ca");dojo.nls.colors.ca={"lightsteelblue":"blau acer clar","orangered":"taronja vermellós","midnightblue":"blau mitjanit","cadetblue":"blau marí","seashell":"petxina marina","slategrey":"gris pissarra","coral":"corall","darkturquoise":"turquesa fosc","antiquewhite":"blanc antic","mediumspringgreen":"verd primavera mitjà","salmon":"salmó","darkgrey":"gris fosc","ivory":"marbre","greenyellow":"verd grogós","mistyrose":"rosa dens","lightsalmon":"salmó clar","silver":"argent","dimgrey":"gris fosc","orange":"taronja","white":"blanc","navajowhite":"blanc Navajo","royalblue":"blau marí intens","deeppink":"rosa profund","lime":"verd llimona","oldlace":"rosa cremós","chartreuse":"Llimona pàl·lid","darkcyan":"cian fosc","yellow":"groc","linen":"lli","olive":"oliva","gold":"daurat","lawngreen":"verd gespa","lightyellow":"groc clar","tan":"tan","darkviolet":"violeta fosc","lightslategrey":"gris pissarra clar","grey":"gris","darkkhaki":"caqui fosc","green":"verd","deepskyblue":"blau cel profund","aqua":"aigua","sienna":"siena","mintcream":"menta pàl·lid","rosybrown":"marró rosat","mediumslateblue":"blau pissarra mitjà","magenta":"magenta","lightseagreen":"verd marí clar","cyan":"cian","olivedrab":"gris oliva","darkgoldenrod":"ocre fosc","slateblue":"blau pissarra","mediumaquamarine":"aiguamarina mitjana","lavender":"lavanda","mediumseagreen":"verd marí mitjà","maroon":"marró vermellós","darkslategray":"gris pissarra fosc","mediumturquoise":"turquesa mitjana","ghostwhite":"blanc fantasma","darkblue":"blau fosc","mediumvioletred":"vermell violeta mitjà","brown":"marró","lightgray":"gris clar","sandybrown":"marró arenós","pink":"rosa","firebrick":"maó refractari","indigo":"índigo","snow":"neu","darkorchid":"orquídia fosc","turquoise":"turquesa","chocolate":"xocolata","springgreen":"verd de primavera","moccasin":"mocassí","navy":"blau marí","lemonchiffon":"groc brisa","teal":"verd blavós","floralwhite":"blanc floral","cornflowerblue":"blau blauet","paleturquoise":"turquesa pàl·lid","purple":"porpra","gainsboro":"gainsboro","plum":"pruna","red":"vermell","blue":"blau","forestgreen":"verd bosc","darkgreen":"verd fosc","honeydew":"rosada de mel","darkseagreen":"verd marí fosc","lightcoral":"corall clar","palevioletred":"vermell porpra pàl·lid","mediumpurple":"porpra mitjana","saddlebrown":"marró mitjà","darkmagenta":"magenta fosc","thistle":"card","whitesmoke":"blanc fumat","wheat":"blat","violet":"violeta","lightskyblue":"blau cel clar","goldenrod":"ocre","mediumblue":"blau mitjà","skyblue":"blau cel","crimson":"carmesí","darksalmon":"salmó fosc","darkred":"vermell fosc","darkslategrey":"gris pissarra fosc","peru":"Perú","lightgrey":"gris clar","lightgoldenrodyellow":"groc ocre clar","blanchedalmond":"ametlla pàl·lid","aliceblue":"blau cian clar","bisque":"crema","slategray":"gris pissarra","palegoldenrod":"ocre pàl·lid","darkorange":"taronja fosc","aquamarine":"aiguamarina","lightgreen":"verd clar","burlywood":"marró arenós","dodgerblue":"blau Dodger","darkgray":"gris fosc","lightcyan":"cian clar","powderblue":"blau grisós","blueviolet":"blau violeta","orchid":"orquídia","dimgray":"gris fosc","beige":"beix","fuchsia":"fúcsia","lavenderblush":"lavanda vermellosa","hotpink":"rosa fúcsia","steelblue":"blau acer","tomato":"tomàquet","lightpink":"rosa clar","limegreen":"verd llimona verda","indianred":"vermell indi","papayawhip":"préssec pastel","lightslategray":"gris pissarra clar","gray":"gris","mediumorchid":"orquídia mitjana","cornsilk":"cru","black":"negre","seagreen":"verd marí","darkslateblue":"blau pissarra fosc","khaki":"caqui","lightblue":"blau clar","palegreen":"verd pàl·lid","azure":"atzur","peachpuff":"préssec","darkolivegreen":"verd oliva fosc","yellowgreen":"verd grogós"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.ca");dijit.nls.loading.ca={"loadingState":"S'està carregant...","errorState":"Ens sap greu. S'ha produït un error."};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.ca");dijit.nls.common.ca={"buttonOk":"D'acord","buttonCancel":"Cancel·la","buttonSave":"Desa","itemClose":"Tanca"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.ca");dijit.form.nls.validate.ca={"rangeMessage":"Aquest valor és fora de l'interval","invalidMessage":"El valor introduït no és vàlid","missingMessage":"Aquest valor és necessari"};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.ca");dijit.form.nls.ComboBox.ca={"previousMessage":"Opcions anteriors","nextMessage":"Més opcions"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.ca");dojo.cldr.nls.number.ca={"group":".","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_cs.js b/lib/dojo/nls/tt-rss-layer_cs.js
new file mode 100644
index 000000000..93ed7c8f1
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_cs.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_cs");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.cs");dojo.nls.colors.cs={"lightsteelblue":"světlá ocelová modrá","orangered":"oranžovočervená","midnightblue":"temně modrá","cadetblue":"šedomodrá","seashell":"lasturová","slategrey":"břidlicová šedá","coral":"korálová červená","darkturquoise":"tmavě tyrkysová","antiquewhite":"krémově bílá","mediumspringgreen":"střední jarní zelená","salmon":"lososová","darkgrey":"tmavě šedá","ivory":"slonovinová","greenyellow":"zelenožlutá","mistyrose":"růžovobílá","lightsalmon":"světle lososová","silver":"stříbrná","dimgrey":"kouřově šedá","orange":"oranžová","white":"bílá","navajowhite":"světle krémová","royalblue":"královská modrá","deeppink":"sytě růžová","lime":"limetková","oldlace":"světle béžová","chartreuse":"chartreuska","darkcyan":"tmavě azurová","yellow":"žlutá","linen":"bledě šedobéžová","olive":"olivová","gold":"zlatá","lawngreen":"jasně zelená","lightyellow":"bledě žlutá","tan":"šedobéžová","darkviolet":"tmavě fialová","lightslategrey":"světlá břidlicová šedá","grey":"šedá","darkkhaki":"pískově hnědá","green":"zelená","deepskyblue":"sytá nebeská modrá","aqua":"azurová","sienna":"siena","mintcream":"mentolová","rosybrown":"růžovohnědá","mediumslateblue":"střední břidlicová modrá","magenta":"purpurová","lightseagreen":"světlá mořská zelená","cyan":"azurová","olivedrab":"khaki","darkgoldenrod":"tmavě béžová","slateblue":"břidlicová modrá","mediumaquamarine":"střední akvamarínová","lavender":"levandulová","mediumseagreen":"střední mořská zelená","maroon":"kaštanová","darkslategray":"tmavá břidlicová šedá","mediumturquoise":"středně tyrkysová","ghostwhite":"modravě bílá","darkblue":"tmavě modrá","mediumvioletred":"středně fialovočervená","brown":"červenohnědá","lightgray":"světle šedá","sandybrown":"oranžovohnědá","pink":"růžová","firebrick":"cihlová","indigo":"indigově modrá","snow":"sněhobílá","darkorchid":"tmavě orchidejová","turquoise":"tyrkysová","chocolate":"hnědobéžová","springgreen":"jarní zelená","moccasin":"bledě krémová","navy":"námořnická modrá","lemonchiffon":"světle citrónová","teal":"šedozelená","floralwhite":"květinově bílá","cornflowerblue":"chrpově modrá","paleturquoise":"bledě tyrkysová","purple":"nachová","gainsboro":"bledě šedá","plum":"švestková","red":"červená","blue":"modrá","forestgreen":"lesní zelená","darkgreen":"tmavě zelená","honeydew":"nazelenalá","darkseagreen":"tmavá mořská zelená","lightcoral":"světle korálová","palevioletred":"bledě fialovočervená","mediumpurple":"středně nachová","saddlebrown":"hnědá","darkmagenta":"tmavě purpurová","thistle":"bodláková","whitesmoke":"kouřově bílá","wheat":"zlatohnědá","violet":"fialová","lightskyblue":"světlá nebeská modrá","goldenrod":"béžová","mediumblue":"středně modrá","skyblue":"nebeská modrá","crimson":"karmínová","darksalmon":"tmavě lososová","darkred":"tmavě červená","darkslategrey":"tmavá břidlicová šedá","peru":"karamelová","lightgrey":"světle šedá","lightgoldenrodyellow":"světle žlutá","blanchedalmond":"mandlová","aliceblue":"modravá","bisque":"bledě oranžová","slategray":"břidlicová šedá","palegoldenrod":"bledě písková","darkorange":"tmavě oranžová","aquamarine":"akvamarínová","lightgreen":"světle zelená","burlywood":"krémová","dodgerblue":"jasně modrá","darkgray":"tmavě šedá","lightcyan":"světle azurová","powderblue":"bledě modrá","blueviolet":"modrofialová","orchid":"orchidejová","dimgray":"kouřově šedá","beige":"bledě béžová","fuchsia":"fuchsiová","lavenderblush":"levandulová růžová","hotpink":"jasně růžová","steelblue":"ocelová modrá","tomato":"tomatová","lightpink":"světle růžová","limegreen":"limetkově zelená","indianred":"indiánská červená","papayawhip":"papájová","lightslategray":"světlá břidlicová šedá","gray":"šedá","mediumorchid":"středně orchidejová","cornsilk":"režná","black":"černá","seagreen":"mořská zelená","darkslateblue":"tmavá břidlicová modrá","khaki":"písková","lightblue":"světle modrá","palegreen":"bledě zelená","azure":"bledě azurová","peachpuff":"broskvová","darkolivegreen":"tmavě olivová","yellowgreen":"žlutozelená"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.cs");dijit.nls.loading.cs={"loadingState":"Probíhá načítání...","errorState":"Omlouváme se, došlo k chybě"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.cs");dijit.nls.common.cs={"buttonOk":"OK","buttonCancel":"Storno","buttonSave":"Uložit","itemClose":"Zavřít"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.cs");dijit.form.nls.validate.cs={"rangeMessage":"Tato hodnota je mimo rozsah.","invalidMessage":"Zadaná hodnota není platná.","missingMessage":"Tato hodnota je vyžadována."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.cs");dijit.form.nls.ComboBox.cs={"previousMessage":"Předchozí volby","nextMessage":"Další volby"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.cs");dojo.cldr.nls.number.cs={"group":" ","percentSign":"%","exponential":"E","percentFormat":"#,##0 %","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_da.js b/lib/dojo/nls/tt-rss-layer_da.js
new file mode 100644
index 000000000..7f8be8c68
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_da.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_da");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.da");dojo.nls.colors.da={"lightsteelblue":"lys stålblå","orangered":"orangerød","midnightblue":"midnatsblå","cadetblue":"kadetblå","seashell":"muslingeskal","slategrey":"skifergrå","coral":"koralrød","darkturquoise":"mørk turkis","antiquewhite":"antikhvid","mediumspringgreen":"mellemforårsgrøn","salmon":"laksefarvet","darkgrey":"mørkegrå","ivory":"elfenben","greenyellow":"grøngul","mistyrose":"blegrosa","lightsalmon":"lys laksefarvet","silver":"sølv","dimgrey":"svag grå","orange":"orange","white":"hvid","navajowhite":"navajo-hvid","royalblue":"kongeblå","deeppink":"dyb pink","lime":"lime","oldlace":"kniplingshvid","chartreuse":"chartreuse","darkcyan":"mørk cyan","yellow":"gul","linen":"lærred","olive":"olivengrøn","gold":"guld","lawngreen":"græsgrøn","lightyellow":"lysegul","tan":"tan","darkviolet":"mørkelilla","lightslategrey":"lys skifergrå","grey":"grå","darkkhaki":"mørk khaki","green":"grøn","deepskyblue":"dyb himmelblå","aqua":"akvablå","sienna":"sienna","mintcream":"pebermyntecreme","rosybrown":"rosabrun","mediumslateblue":"mellemskiferblå","magenta":"magenta","lightseagreen":"lys havgrøn","cyan":"cyan","olivedrab":"brungrøn","darkgoldenrod":"mørk gyldenris","slateblue":"skiferblå","mediumaquamarine":"mellem akvamarin","lavender":"lysviolet","mediumseagreen":"mellemhavgrøn","maroon":"rødbrun","darkslategray":"mørk skifergrå","mediumturquoise":"mellemturkis","ghostwhite":"spøgelseshvid","darkblue":"mørkeblå","mediumvioletred":"mellemviolet","brown":"brun","lightgray":"lysegrå","sandybrown":"sandbrun","pink":"pink","firebrick":"chamottesten","indigo":"indigo","snow":"sne","darkorchid":"mørk orkide","turquoise":"turkis","chocolate":"rust","springgreen":"forårsgrøn","moccasin":"fruesko","navy":"marineblå","lemonchiffon":"citronfromage","teal":"blågrøn","floralwhite":"blomsterhvid","cornflowerblue":"kornblomstblå","paleturquoise":"bleg turkis","purple":"lilla","gainsboro":"gainsboro","plum":"blomme","red":"rød","blue":"blå","forestgreen":"skovgrøn","darkgreen":"mørkegrøn","honeydew":"honningdug","darkseagreen":"mørk havgrøn","lightcoral":"lys koralrød","palevioletred":"blegviolet","mediumpurple":"mellemlilla","saddlebrown":"saddelbrun","darkmagenta":"mørk magenta","thistle":"tidsel","whitesmoke":"hvid røg","wheat":"korngul","violet":"lilla","lightskyblue":"lys himmelblå","goldenrod":"gyldenris","mediumblue":"mellemblå","skyblue":"himmelblå","crimson":"blodrød","darksalmon":"mørk laksefarvet","darkred":"mørkerød","darkslategrey":"mørk skifergrå","peru":"peru","lightgrey":"lysegrå","lightgoldenrodyellow":"lys gyldenrisgul","blanchedalmond":"blanceret mandel","aliceblue":"babyblå","bisque":"gulgrå","slategray":"skifergrå","palegoldenrod":"bleg gyldenris","darkorange":"mørk orange","aquamarine":"akvamarin","lightgreen":"lysegrøn","burlywood":"tobak","dodgerblue":"dodgerblå","darkgray":"mørkegrå","lightcyan":"lys cyan","powderblue":"pudderblå","blueviolet":"blåviolet","orchid":"orkide","dimgray":"svag grå","beige":"beige","fuchsia":"lyslilla","lavenderblush":"lavendelrød","hotpink":"mørk rosa","steelblue":"metalblå","tomato":"tomat","lightpink":"lys pink","limegreen":"limegrøn","indianred":"lys rødbrun","papayawhip":"papaya","lightslategray":"lys skifergrå","gray":"grå","mediumorchid":"mellem orkide","cornsilk":"majs","black":"sort","seagreen":"havgrøn","darkslateblue":"mørk skiferblå","khaki":"khaki","lightblue":"lyseblå","palegreen":"bleggrøn","azure":"azurblå","peachpuff":"fersken","darkolivegreen":"mørk olivengrøn","yellowgreen":"gulgrøn"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.da");dijit.nls.loading.da={"loadingState":"Indlæser...","errorState":"Der er opstået en fejl"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.da");dijit.nls.common.da={"buttonOk":"OK","buttonCancel":"Annullér","buttonSave":"Gem","itemClose":"Luk"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.da");dijit.form.nls.validate.da={"rangeMessage":"Værdien er uden for intervallet.","invalidMessage":"Den angivne værdi er ugyldig.","missingMessage":"Værdien er påkrævet."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.da");dijit.form.nls.ComboBox.da={"previousMessage":"Forrige valg","nextMessage":"Flere valg"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.da");dojo.cldr.nls.number.da={"group":".","percentSign":"%","exponential":"E","percentFormat":"#,##0 %","scientificFormat":"#E0","list":",","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_de-de.js b/lib/dojo/nls/tt-rss-layer_de-de.js
new file mode 100644
index 000000000..e5bb92237
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_de-de.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_de-de");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.de_de");dojo.nls.colors.de_de={"lightsteelblue":"Helles Stahlblau","orangered":"Orangerot","midnightblue":"Mitternachtblau","cadetblue":"Kadettenblau","seashell":"Muschelweiß","slategrey":"Schiefergrau","coral":"Koralle","darkturquoise":"Dunkeltürkis","antiquewhite":"Antikweiß","mediumspringgreen":"Mittelfrühlingsgrün","salmon":"Lachs","darkgrey":"Dunkelgrau","ivory":"Elfenbein","greenyellow":"Grüngelb","mistyrose":"Blassrose","lightsalmon":"Helllachs","silver":"Silbergrau","dimgrey":"Blassgrau","orange":"Orange","white":"Weiß","navajowhite":"Navajo-weiß","royalblue":"Königsblau","deeppink":"Tiefrosa","lime":"Limone","oldlace":"Alte Spitze","chartreuse":"Helles Gelbgrün","darkcyan":"Dunkelzyan","yellow":"Gelb","linen":"Leinen","olive":"Oliv","gold":"Gold","lawngreen":"Grasgrün","lightyellow":"Hellgelb","tan":"Hautfarben","darkviolet":"Dunkelviolett","lightslategrey":"Helles Schiefergrau","grey":"Grau","darkkhaki":"Dunkelkhaki","green":"Grün","deepskyblue":"Dunkles Himmelblau","aqua":"Wasserblau","sienna":"Sienna","mintcream":"Mintcreme","rosybrown":"Rosigbraun","mediumslateblue":"Mittelschieferblau ","magenta":"Magenta","lightseagreen":"Helles Meergrün","cyan":"Zyan","olivedrab":"Olivgrau","darkgoldenrod":"Dunkelgoldgelb","slateblue":"Schieferblau","mediumaquamarine":"Mittelaquamarin","lavender":"Lavendelblau","mediumseagreen":"Mittelmeeresgrün","maroon":"Kastanienbraun","darkslategray":"Dunkelschiefergrau","mediumturquoise":"Mitteltürkis ","ghostwhite":"Geisterweiß","darkblue":"Dunkelblau","mediumvioletred":"Mittelviolettrot ","brown":"Braun","lightgray":"Hellgrau","sandybrown":"Sandbraun","pink":"Rosa","firebrick":"Schamottestein","indigo":"Indigoblau","snow":"Schneeweiß","darkorchid":"Dunkelorchidee","turquoise":"Türkis","chocolate":"Schokoladenbraun","springgreen":"Frühlingsgrün","moccasin":"Mokassin","navy":"Marineblau","lemonchiffon":"Zitronenchiffon","teal":"Smaragdgrün","floralwhite":"Blütenweiß","cornflowerblue":"Kornblumenblau","paleturquoise":"Blasstürkis","purple":"Purpurrot","gainsboro":"Gainsboro","plum":"Pflaume","red":"Rot","blue":"Blau","forestgreen":"Forstgrün","darkgreen":"Dunkelgrün","honeydew":"Honigtau","darkseagreen":"Dunkles Meergrün","lightcoral":"Hellkoralle","palevioletred":"Blassviolettrot ","mediumpurple":"Mittelpurpur","saddlebrown":"Sattelbraun","darkmagenta":"Dunkelmagenta","thistle":"Distel","whitesmoke":"Rauchweiß","wheat":"Weizen","violet":"Violett","lightskyblue":"Helles Himmelblau","goldenrod":"Goldgelb","mediumblue":"Mittelblau","skyblue":"Himmelblau","crimson":"Karmesinrot","darksalmon":"Dunkellachs","darkred":"Dunkelrot","darkslategrey":"Dunkelschiefergrau","peru":"Peru","lightgrey":"Hellgrau","lightgoldenrodyellow":"Hellgoldgelb","blanchedalmond":"Mandelweiß","aliceblue":"Alice-blau","bisque":"Bisquit","slategray":"Schiefergrau","palegoldenrod":"Blassgoldgelb","darkorange":"Dunkelorange","aquamarine":"Aquamarin","lightgreen":"Hellgrün","burlywood":"Burlywood","dodgerblue":"Dodger-blau","darkgray":"Dunkelgrau","lightcyan":"Hellzyan","powderblue":"Pulverblau","blueviolet":"Blauviolett","orchid":"Orchidee","dimgray":"Blassgrau","beige":"Beige","fuchsia":"Fuchsia","lavenderblush":"Lavendelhauch","hotpink":"Knallrosa","steelblue":"Stahlblau","tomato":"Tomatenrot","lightpink":"Hellrosa","limegreen":"Limonengrün","indianred":"Indischrot","papayawhip":"Papayacreme","lightslategray":"Helles Schiefergrau","gray":"Grau","mediumorchid":"Mittelorchidee","cornsilk":"Kornseide","black":"Schwarz","seagreen":"Meeresgrün","darkslateblue":"Dunkelschieferblau","khaki":"Khaki","lightblue":"Hellblau","palegreen":"Blassgrün","azure":"Azur","peachpuff":"Pfirsich","darkolivegreen":"Dunkelolivgrün","yellowgreen":"Gelbgrün"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.de_de");dijit.nls.loading.de_de={"loadingState":"Wird geladen...","errorState":"Es ist ein Fehler aufgetreten."};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.de_de");dijit.nls.common.de_de={"buttonOk":"OK","buttonCancel":"Abbrechen","buttonSave":"Speichern","itemClose":"Schließen"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.de_de");dijit.form.nls.validate.de_de={"rangeMessage":"Dieser Wert liegt außerhalb des gültigen Bereichs. ","invalidMessage":"Der eingegebene Wert ist ungültig. ","missingMessage":"Dieser Wert ist erforderlich."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.de_de");dijit.form.nls.ComboBox.de_de={"previousMessage":"Vorherige Auswahl","nextMessage":"Weitere Auswahlmöglichkeiten"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.de_de");dojo.cldr.nls.number.de_de={"group":".","percentSign":"%","exponential":"E","percentFormat":"#,##0 %","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_de.js b/lib/dojo/nls/tt-rss-layer_de.js
new file mode 100644
index 000000000..5500fc19b
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_de.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_de");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.de");dojo.nls.colors.de={"lightsteelblue":"Helles Stahlblau","orangered":"Orangerot","midnightblue":"Mitternachtblau","cadetblue":"Kadettenblau","seashell":"Muschelweiß","slategrey":"Schiefergrau","coral":"Koralle","darkturquoise":"Dunkeltürkis","antiquewhite":"Antikweiß","mediumspringgreen":"Mittelfrühlingsgrün","salmon":"Lachs","darkgrey":"Dunkelgrau","ivory":"Elfenbein","greenyellow":"Grüngelb","mistyrose":"Blassrose","lightsalmon":"Helllachs","silver":"Silbergrau","dimgrey":"Blassgrau","orange":"Orange","white":"Weiß","navajowhite":"Navajo-weiß","royalblue":"Königsblau","deeppink":"Tiefrosa","lime":"Limone","oldlace":"Alte Spitze","chartreuse":"Helles Gelbgrün","darkcyan":"Dunkelzyan","yellow":"Gelb","linen":"Leinen","olive":"Oliv","gold":"Gold","lawngreen":"Grasgrün","lightyellow":"Hellgelb","tan":"Hautfarben","darkviolet":"Dunkelviolett","lightslategrey":"Helles Schiefergrau","grey":"Grau","darkkhaki":"Dunkelkhaki","green":"Grün","deepskyblue":"Dunkles Himmelblau","aqua":"Wasserblau","sienna":"Sienna","mintcream":"Mintcreme","rosybrown":"Rosigbraun","mediumslateblue":"Mittelschieferblau ","magenta":"Magenta","lightseagreen":"Helles Meergrün","cyan":"Zyan","olivedrab":"Olivgrau","darkgoldenrod":"Dunkelgoldgelb","slateblue":"Schieferblau","mediumaquamarine":"Mittelaquamarin","lavender":"Lavendelblau","mediumseagreen":"Mittelmeeresgrün","maroon":"Kastanienbraun","darkslategray":"Dunkelschiefergrau","mediumturquoise":"Mitteltürkis ","ghostwhite":"Geisterweiß","darkblue":"Dunkelblau","mediumvioletred":"Mittelviolettrot ","brown":"Braun","lightgray":"Hellgrau","sandybrown":"Sandbraun","pink":"Rosa","firebrick":"Schamottestein","indigo":"Indigoblau","snow":"Schneeweiß","darkorchid":"Dunkelorchidee","turquoise":"Türkis","chocolate":"Schokoladenbraun","springgreen":"Frühlingsgrün","moccasin":"Mokassin","navy":"Marineblau","lemonchiffon":"Zitronenchiffon","teal":"Smaragdgrün","floralwhite":"Blütenweiß","cornflowerblue":"Kornblumenblau","paleturquoise":"Blasstürkis","purple":"Purpurrot","gainsboro":"Gainsboro","plum":"Pflaume","red":"Rot","blue":"Blau","forestgreen":"Forstgrün","darkgreen":"Dunkelgrün","honeydew":"Honigtau","darkseagreen":"Dunkles Meergrün","lightcoral":"Hellkoralle","palevioletred":"Blassviolettrot ","mediumpurple":"Mittelpurpur","saddlebrown":"Sattelbraun","darkmagenta":"Dunkelmagenta","thistle":"Distel","whitesmoke":"Rauchweiß","wheat":"Weizen","violet":"Violett","lightskyblue":"Helles Himmelblau","goldenrod":"Goldgelb","mediumblue":"Mittelblau","skyblue":"Himmelblau","crimson":"Karmesinrot","darksalmon":"Dunkellachs","darkred":"Dunkelrot","darkslategrey":"Dunkelschiefergrau","peru":"Peru","lightgrey":"Hellgrau","lightgoldenrodyellow":"Hellgoldgelb","blanchedalmond":"Mandelweiß","aliceblue":"Alice-blau","bisque":"Bisquit","slategray":"Schiefergrau","palegoldenrod":"Blassgoldgelb","darkorange":"Dunkelorange","aquamarine":"Aquamarin","lightgreen":"Hellgrün","burlywood":"Burlywood","dodgerblue":"Dodger-blau","darkgray":"Dunkelgrau","lightcyan":"Hellzyan","powderblue":"Pulverblau","blueviolet":"Blauviolett","orchid":"Orchidee","dimgray":"Blassgrau","beige":"Beige","fuchsia":"Fuchsia","lavenderblush":"Lavendelhauch","hotpink":"Knallrosa","steelblue":"Stahlblau","tomato":"Tomatenrot","lightpink":"Hellrosa","limegreen":"Limonengrün","indianred":"Indischrot","papayawhip":"Papayacreme","lightslategray":"Helles Schiefergrau","gray":"Grau","mediumorchid":"Mittelorchidee","cornsilk":"Kornseide","black":"Schwarz","seagreen":"Meeresgrün","darkslateblue":"Dunkelschieferblau","khaki":"Khaki","lightblue":"Hellblau","palegreen":"Blassgrün","azure":"Azur","peachpuff":"Pfirsich","darkolivegreen":"Dunkelolivgrün","yellowgreen":"Gelbgrün"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.de");dijit.nls.loading.de={"loadingState":"Wird geladen...","errorState":"Es ist ein Fehler aufgetreten."};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.de");dijit.nls.common.de={"buttonOk":"OK","buttonCancel":"Abbrechen","buttonSave":"Speichern","itemClose":"Schließen"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.de");dijit.form.nls.validate.de={"rangeMessage":"Dieser Wert liegt außerhalb des gültigen Bereichs. ","invalidMessage":"Der eingegebene Wert ist ungültig. ","missingMessage":"Dieser Wert ist erforderlich."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.de");dijit.form.nls.ComboBox.de={"previousMessage":"Vorherige Auswahl","nextMessage":"Weitere Auswahlmöglichkeiten"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.de");dojo.cldr.nls.number.de={"group":".","percentSign":"%","exponential":"E","percentFormat":"#,##0 %","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_el.js b/lib/dojo/nls/tt-rss-layer_el.js
new file mode 100644
index 000000000..0a4594e3c
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_el.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_el");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.el");dojo.nls.colors.el={"lightsteelblue":"ανοιχτό μπλε ατσαλιού","orangered":"πορτοκαλοκόκκινο","midnightblue":"πολύ σκούρο μπλε","cadetblue":"μπλε του στρατού","seashell":"κοχύλι","slategrey":"μεταλλικό γκρι","coral":"κοραλί","darkturquoise":"σκούρο τυρκουάζ","antiquewhite":"ξεθωριασμένο λευκό","mediumspringgreen":"μεσαίο πράσινο της άνοιξης","salmon":"σομόν","darkgrey":"σκούρο γκρι","ivory":"ιβουάρ","greenyellow":"πρασινοκίτρινο","mistyrose":"τριανταφυλλί","lightsalmon":"ανοιχτό σομόν","silver":"ασημί","dimgrey":"αχνό γκρι","orange":"πορτοκαλί","white":"λευκό","navajowhite":"άσπρο Ναβάχο","royalblue":"έντονο μπλε","deeppink":"βαθύ ροζ","lime":"λαχανί","oldlace":"εκρού","chartreuse":"φωτεινό κιτρινοπράσινο","darkcyan":"σκούρο κυανό","yellow":"κίτρινο","linen":"σπαγγί","olive":"πράσινο λαδί","gold":"χρυσαφί","lawngreen":"σκούρο πράσινο","lightyellow":"ανοιχτό κίτρινο","tan":"ώχρα","darkviolet":"σκούρο βιολετί","lightslategrey":"ανοιχτό μεταλλικό γκρι","grey":"γκρι","darkkhaki":"σκούρο χακί","green":"πράσινο","deepskyblue":"βαθύ μπλε το ουρανού","aqua":"γαλάζιο","sienna":"καφεκίτρινο","mintcream":"βεραμάν","rosybrown":"καστανό","mediumslateblue":"μεσαίο μεταλλικό μπλε","magenta":"ματζέντα","lightseagreen":"ανοιχτό πράσινο της θάλασσας","cyan":"κυανό","olivedrab":"λαδί","darkgoldenrod":"σκούρο χρυσοκίτρινο","slateblue":"μεταλλικό μπλε","mediumaquamarine":"μεσαίο γαλαζοπράσινο","lavender":"λίλα","mediumseagreen":"μεσαίο πράσινο της θάλασσας","maroon":"βυσσινί","darkslategray":"σκούρο μεταλλικό γκρι","mediumturquoise":"μεσαίο τυρκουάζ","ghostwhite":"άσπρο","darkblue":"σκούρο μπλε","mediumvioletred":"μεσαίο κόκκινο βιολετί","brown":"καφέ","lightgray":"ανοιχτό γκρι","sandybrown":"μπεζ της άμμου","pink":"ροζ","firebrick":"κεραμιδί","indigo":"λουλακί","snow":"χιονί","darkorchid":"σκούρα ορχιδέα","turquoise":"τυρκουάζ","chocolate":"σοκολατί","springgreen":"πράσινο της άνοιξης","moccasin":"μόκα","navy":"μπλε του ναυτικού","lemonchiffon":"λεμονί","teal":"πετρόλ","floralwhite":"λευκό των ανθών","cornflowerblue":"μεσαίο μπλε","paleturquoise":"αχνό τυρκουάζ","purple":"μωβ","gainsboro":"γκρι σιέλ","plum":"δαμασκηνί","red":"κόκκινο","blue":"μπλε","forestgreen":"πράσινο του δάσους","darkgreen":"σκούρο πράσινο","honeydew":"μελί","darkseagreen":"σκούρο πράσινο της θάλασσας","lightcoral":"ανοιχτό κοραλί","palevioletred":"αχνό κόκκινο βιολετί","mediumpurple":"μεσαίο μωβ","saddlebrown":"βαθύ καφέ","darkmagenta":"σκούρο ματζέντα","thistle":"μωβ βιολετί","whitesmoke":"λευκός καπνός","wheat":"σταρένιο","violet":"βιολετί","lightskyblue":"ανοιχτό μπλε το ουρανού","goldenrod":"χρυσοκίτρινο","mediumblue":"μεσαίο μπλε","skyblue":"μπλε του ουρανού","crimson":"βαθύ κόκκινο","darksalmon":"σκούρο σομόν","darkred":"σκούρο κόκκινο","darkslategrey":"σκούρο μεταλλικό γκρι","peru":"περού","lightgrey":"ανοιχτό γκρι","lightgoldenrodyellow":"ανοιχτό χρυσοκίτρινο","blanchedalmond":"ζαχαρί","aliceblue":"σιέλ","bisque":"σκούρο κρεμ","slategray":"μεταλλικό γκρι","palegoldenrod":"αχνό χρυσοκίτρινο","darkorange":"σκούρο πορτοκαλί","aquamarine":"γαλαζοπράσινο","lightgreen":"ανοιχτό πράσινο","burlywood":"καφέ του ξύλου","dodgerblue":"σκούρο ελεκτρίκ","darkgray":"σκούρο γκρι","lightcyan":"ανοιχτό κυανό","powderblue":"αχνό μπλε","blueviolet":"βιολετί","orchid":"ορχιδέα","dimgray":"αχνό γκρι","beige":"μπεζ","fuchsia":"φούξια","lavenderblush":"μωβ λεβάντας","hotpink":"έντονο ροζ","steelblue":"μπλε ατσαλιού","tomato":"κόκκινο της ντομάτας","lightpink":"ανοιχτό ροζ","limegreen":"πράσινο λαχανί","indianred":"ινδικό κόκκινο","papayawhip":"αχνό ροζ","lightslategray":"ανοιχτό μεταλλικό γκρι","gray":"γκρι","mediumorchid":"μεσαία ορχιδέα","cornsilk":"ασημί του καλαμποκιού","black":"μαύρο","seagreen":"πράσινο της θάλασσας","darkslateblue":"σκούρο μεταλλικό μπλε","khaki":"χακί","lightblue":"ανοιχτό μπλε","palegreen":"αχνό πράσινο","azure":"μπλε του ουρανού","peachpuff":"ροδακινί","darkolivegreen":"σκούρο πράσινο λαδί","yellowgreen":"κιτρινοπράσινο"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.el");dijit.nls.loading.el={"loadingState":"Φόρτωση...","errorState":"Σας ζητούμε συγνώμη, παρουσιάστηκε σφάλμα"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.el");dijit.nls.common.el={"buttonOk":"ΟΚ","buttonCancel":"Ακύρωση","buttonSave":"Αποθήκευση","itemClose":"Κλείσιμο"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.el");dijit.form.nls.validate.el={"rangeMessage":"Η τιμή αυτή δεν ανήκει στο εύρος έγκυρων τιμών.","invalidMessage":"Η τιμή που καταχωρήσατε δεν είναι έγκυρη.","missingMessage":"Η τιμή αυτή πρέπει απαραίτητα να καθοριστεί."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.el");dijit.form.nls.ComboBox.el={"previousMessage":"Προηγούμενες επιλογές","nextMessage":"Περισσότερες επιλογές"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.el");dojo.cldr.nls.number.el={"group":".","percentSign":"%","exponential":"e","percentFormat":"#,##0%","list":",","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","currencyFormat":"#,##0.00 ¤","plusSign":"+","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","decimalFormat":"#,##0.###","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_en-gb.js b/lib/dojo/nls/tt-rss-layer_en-gb.js
new file mode 100644
index 000000000..382f40413
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_en-gb.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_en-gb");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.en_gb");dojo.nls.colors.en_gb={"lightsteelblue":"light steel blue","orangered":"orange red","midnightblue":"midnight blue","cadetblue":"cadet blue","seashell":"seashell","slategrey":"slate gray","coral":"coral","darkturquoise":"dark turquoise","antiquewhite":"antique white","mediumspringgreen":"medium spring green","salmon":"salmon","darkgrey":"dark gray","ivory":"ivory","greenyellow":"green-yellow","mistyrose":"misty rose","lightsalmon":"light salmon","silver":"silver","dimgrey":"dim gray","orange":"orange","white":"white","navajowhite":"navajo white","royalblue":"royal blue","deeppink":"deep pink","lime":"lime","oldlace":"old lace","chartreuse":"chartreuse","darkcyan":"dark cyan","yellow":"yellow","linen":"linen","olive":"olive","gold":"gold","lawngreen":"lawn green","lightyellow":"light yellow","tan":"tan","darkviolet":"dark violet","lightslategrey":"light slate gray","grey":"gray","darkkhaki":"dark khaki","green":"green","deepskyblue":"deep sky blue","aqua":"aqua","sienna":"sienna","mintcream":"mint cream","rosybrown":"rosy brown","mediumslateblue":"medium slate blue","magenta":"magenta","lightseagreen":"light sea green","cyan":"cyan","olivedrab":"olive drab","darkgoldenrod":"dark goldenrod","slateblue":"slate blue","mediumaquamarine":"medium aquamarine","lavender":"lavender","mediumseagreen":"medium sea green","maroon":"maroon","darkslategray":"dark slate gray","mediumturquoise":"medium turquoise","ghostwhite":"ghost white","darkblue":"dark blue","mediumvioletred":"medium violet-red","brown":"brown","lightgray":"light gray","sandybrown":"sandy brown","pink":"pink","firebrick":"fire brick","indigo":"indigo","snow":"snow","darkorchid":"dark orchid","turquoise":"turquoise","chocolate":"chocolate","springgreen":"spring green","moccasin":"moccasin","navy":"navy","lemonchiffon":"lemon chiffon","teal":"teal","floralwhite":"floral white","cornflowerblue":"cornflower blue","paleturquoise":"pale turquoise","purple":"purple","gainsboro":"gainsboro","plum":"plum","red":"red","blue":"blue","forestgreen":"forest green","darkgreen":"dark green","honeydew":"honeydew","darkseagreen":"dark sea green","lightcoral":"light coral","palevioletred":"pale violet-red","mediumpurple":"medium purple","saddlebrown":"saddle brown","darkmagenta":"dark magenta","thistle":"thistle","whitesmoke":"white smoke","wheat":"wheat","violet":"violet","lightskyblue":"light sky blue","goldenrod":"goldenrod","mediumblue":"medium blue","skyblue":"sky blue","crimson":"crimson","darksalmon":"dark salmon","darkred":"dark red","darkslategrey":"dark slate gray","peru":"peru","lightgrey":"light gray","lightgoldenrodyellow":"light goldenrod yellow","blanchedalmond":"blanched almond","aliceblue":"alice blue","bisque":"bisque","slategray":"slate gray","palegoldenrod":"pale goldenrod","darkorange":"dark orange","aquamarine":"aquamarine","lightgreen":"light green","burlywood":"burlywood","dodgerblue":"dodger blue","darkgray":"dark gray","lightcyan":"light cyan","powderblue":"powder blue","blueviolet":"blue-violet","orchid":"orchid","dimgray":"dim gray","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavender blush","hotpink":"hot pink","steelblue":"steel blue","tomato":"tomato","lightpink":"light pink","limegreen":"lime green","indianred":"indian red","papayawhip":"papaya whip","lightslategray":"light slate gray","gray":"gray","mediumorchid":"medium orchid","cornsilk":"cornsilk","black":"black","seagreen":"sea green","darkslateblue":"dark slate blue","khaki":"khaki","lightblue":"light blue","palegreen":"pale green","azure":"azure","peachpuff":"peach puff","darkolivegreen":"dark olive green","yellowgreen":"yellow green"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.en_gb");dijit.nls.loading.en_gb={"loadingState":"Loading...","errorState":"Sorry, an error occurred"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.en_gb");dijit.nls.common.en_gb={"buttonOk":"OK","buttonCancel":"Cancel","buttonSave":"Save","itemClose":"Close"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.en_gb");dijit.form.nls.validate.en_gb={"rangeMessage":"This value is out of range.","invalidMessage":"The value entered is not valid.","missingMessage":"This value is required."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.en_gb");dijit.form.nls.ComboBox.en_gb={"previousMessage":"Previous choices","nextMessage":"More choices"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.en_gb");dojo.cldr.nls.number.en_gb={"currencyFormat":"¤#,##0.00","group":",","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":".","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_en-us.js b/lib/dojo/nls/tt-rss-layer_en-us.js
new file mode 100644
index 000000000..af4f269ee
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_en-us.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_en-us");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.en_us");dojo.nls.colors.en_us={"lightsteelblue":"light steel blue","orangered":"orange red","midnightblue":"midnight blue","cadetblue":"cadet blue","seashell":"seashell","slategrey":"slate gray","coral":"coral","darkturquoise":"dark turquoise","antiquewhite":"antique white","mediumspringgreen":"medium spring green","salmon":"salmon","darkgrey":"dark gray","ivory":"ivory","greenyellow":"green-yellow","mistyrose":"misty rose","lightsalmon":"light salmon","silver":"silver","dimgrey":"dim gray","orange":"orange","white":"white","navajowhite":"navajo white","royalblue":"royal blue","deeppink":"deep pink","lime":"lime","oldlace":"old lace","chartreuse":"chartreuse","darkcyan":"dark cyan","yellow":"yellow","linen":"linen","olive":"olive","gold":"gold","lawngreen":"lawn green","lightyellow":"light yellow","tan":"tan","darkviolet":"dark violet","lightslategrey":"light slate gray","grey":"gray","darkkhaki":"dark khaki","green":"green","deepskyblue":"deep sky blue","aqua":"aqua","sienna":"sienna","mintcream":"mint cream","rosybrown":"rosy brown","mediumslateblue":"medium slate blue","magenta":"magenta","lightseagreen":"light sea green","cyan":"cyan","olivedrab":"olive drab","darkgoldenrod":"dark goldenrod","slateblue":"slate blue","mediumaquamarine":"medium aquamarine","lavender":"lavender","mediumseagreen":"medium sea green","maroon":"maroon","darkslategray":"dark slate gray","mediumturquoise":"medium turquoise","ghostwhite":"ghost white","darkblue":"dark blue","mediumvioletred":"medium violet-red","brown":"brown","lightgray":"light gray","sandybrown":"sandy brown","pink":"pink","firebrick":"fire brick","indigo":"indigo","snow":"snow","darkorchid":"dark orchid","turquoise":"turquoise","chocolate":"chocolate","springgreen":"spring green","moccasin":"moccasin","navy":"navy","lemonchiffon":"lemon chiffon","teal":"teal","floralwhite":"floral white","cornflowerblue":"cornflower blue","paleturquoise":"pale turquoise","purple":"purple","gainsboro":"gainsboro","plum":"plum","red":"red","blue":"blue","forestgreen":"forest green","darkgreen":"dark green","honeydew":"honeydew","darkseagreen":"dark sea green","lightcoral":"light coral","palevioletred":"pale violet-red","mediumpurple":"medium purple","saddlebrown":"saddle brown","darkmagenta":"dark magenta","thistle":"thistle","whitesmoke":"white smoke","wheat":"wheat","violet":"violet","lightskyblue":"light sky blue","goldenrod":"goldenrod","mediumblue":"medium blue","skyblue":"sky blue","crimson":"crimson","darksalmon":"dark salmon","darkred":"dark red","darkslategrey":"dark slate gray","peru":"peru","lightgrey":"light gray","lightgoldenrodyellow":"light goldenrod yellow","blanchedalmond":"blanched almond","aliceblue":"alice blue","bisque":"bisque","slategray":"slate gray","palegoldenrod":"pale goldenrod","darkorange":"dark orange","aquamarine":"aquamarine","lightgreen":"light green","burlywood":"burlywood","dodgerblue":"dodger blue","darkgray":"dark gray","lightcyan":"light cyan","powderblue":"powder blue","blueviolet":"blue-violet","orchid":"orchid","dimgray":"dim gray","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavender blush","hotpink":"hot pink","steelblue":"steel blue","tomato":"tomato","lightpink":"light pink","limegreen":"lime green","indianred":"indian red","papayawhip":"papaya whip","lightslategray":"light slate gray","gray":"gray","mediumorchid":"medium orchid","cornsilk":"cornsilk","black":"black","seagreen":"sea green","darkslateblue":"dark slate blue","khaki":"khaki","lightblue":"light blue","palegreen":"pale green","azure":"azure","peachpuff":"peach puff","darkolivegreen":"dark olive green","yellowgreen":"yellow green"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.en_us");dijit.nls.loading.en_us={"loadingState":"Loading...","errorState":"Sorry, an error occurred"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.en_us");dijit.nls.common.en_us={"buttonOk":"OK","buttonCancel":"Cancel","buttonSave":"Save","itemClose":"Close"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.en_us");dijit.form.nls.validate.en_us={"rangeMessage":"This value is out of range.","invalidMessage":"The value entered is not valid.","missingMessage":"This value is required."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.en_us");dijit.form.nls.ComboBox.en_us={"previousMessage":"Previous choices","nextMessage":"More choices"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.en_us");dojo.cldr.nls.number.en_us={"group":",","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":".","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"¤#,##0.00;(¤#,##0.00)","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_en.js b/lib/dojo/nls/tt-rss-layer_en.js
new file mode 100644
index 000000000..b1eac5b9d
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_en.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_en");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.en");dojo.nls.colors.en={"lightsteelblue":"light steel blue","orangered":"orange red","midnightblue":"midnight blue","cadetblue":"cadet blue","seashell":"seashell","slategrey":"slate gray","coral":"coral","darkturquoise":"dark turquoise","antiquewhite":"antique white","mediumspringgreen":"medium spring green","salmon":"salmon","darkgrey":"dark gray","ivory":"ivory","greenyellow":"green-yellow","mistyrose":"misty rose","lightsalmon":"light salmon","silver":"silver","dimgrey":"dim gray","orange":"orange","white":"white","navajowhite":"navajo white","royalblue":"royal blue","deeppink":"deep pink","lime":"lime","oldlace":"old lace","chartreuse":"chartreuse","darkcyan":"dark cyan","yellow":"yellow","linen":"linen","olive":"olive","gold":"gold","lawngreen":"lawn green","lightyellow":"light yellow","tan":"tan","darkviolet":"dark violet","lightslategrey":"light slate gray","grey":"gray","darkkhaki":"dark khaki","green":"green","deepskyblue":"deep sky blue","aqua":"aqua","sienna":"sienna","mintcream":"mint cream","rosybrown":"rosy brown","mediumslateblue":"medium slate blue","magenta":"magenta","lightseagreen":"light sea green","cyan":"cyan","olivedrab":"olive drab","darkgoldenrod":"dark goldenrod","slateblue":"slate blue","mediumaquamarine":"medium aquamarine","lavender":"lavender","mediumseagreen":"medium sea green","maroon":"maroon","darkslategray":"dark slate gray","mediumturquoise":"medium turquoise","ghostwhite":"ghost white","darkblue":"dark blue","mediumvioletred":"medium violet-red","brown":"brown","lightgray":"light gray","sandybrown":"sandy brown","pink":"pink","firebrick":"fire brick","indigo":"indigo","snow":"snow","darkorchid":"dark orchid","turquoise":"turquoise","chocolate":"chocolate","springgreen":"spring green","moccasin":"moccasin","navy":"navy","lemonchiffon":"lemon chiffon","teal":"teal","floralwhite":"floral white","cornflowerblue":"cornflower blue","paleturquoise":"pale turquoise","purple":"purple","gainsboro":"gainsboro","plum":"plum","red":"red","blue":"blue","forestgreen":"forest green","darkgreen":"dark green","honeydew":"honeydew","darkseagreen":"dark sea green","lightcoral":"light coral","palevioletred":"pale violet-red","mediumpurple":"medium purple","saddlebrown":"saddle brown","darkmagenta":"dark magenta","thistle":"thistle","whitesmoke":"white smoke","wheat":"wheat","violet":"violet","lightskyblue":"light sky blue","goldenrod":"goldenrod","mediumblue":"medium blue","skyblue":"sky blue","crimson":"crimson","darksalmon":"dark salmon","darkred":"dark red","darkslategrey":"dark slate gray","peru":"peru","lightgrey":"light gray","lightgoldenrodyellow":"light goldenrod yellow","blanchedalmond":"blanched almond","aliceblue":"alice blue","bisque":"bisque","slategray":"slate gray","palegoldenrod":"pale goldenrod","darkorange":"dark orange","aquamarine":"aquamarine","lightgreen":"light green","burlywood":"burlywood","dodgerblue":"dodger blue","darkgray":"dark gray","lightcyan":"light cyan","powderblue":"powder blue","blueviolet":"blue-violet","orchid":"orchid","dimgray":"dim gray","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavender blush","hotpink":"hot pink","steelblue":"steel blue","tomato":"tomato","lightpink":"light pink","limegreen":"lime green","indianred":"indian red","papayawhip":"papaya whip","lightslategray":"light slate gray","gray":"gray","mediumorchid":"medium orchid","cornsilk":"cornsilk","black":"black","seagreen":"sea green","darkslateblue":"dark slate blue","khaki":"khaki","lightblue":"light blue","palegreen":"pale green","azure":"azure","peachpuff":"peach puff","darkolivegreen":"dark olive green","yellowgreen":"yellow green"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.en");dijit.nls.loading.en={"loadingState":"Loading...","errorState":"Sorry, an error occurred"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.en");dijit.nls.common.en={"buttonOk":"OK","buttonCancel":"Cancel","buttonSave":"Save","itemClose":"Close"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.en");dijit.form.nls.validate.en={"rangeMessage":"This value is out of range.","invalidMessage":"The value entered is not valid.","missingMessage":"This value is required."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.en");dijit.form.nls.ComboBox.en={"previousMessage":"Previous choices","nextMessage":"More choices"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.en");dojo.cldr.nls.number.en={"group":",","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":".","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"¤#,##0.00;(¤#,##0.00)","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_es-es.js b/lib/dojo/nls/tt-rss-layer_es-es.js
new file mode 100644
index 000000000..971c82e96
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_es-es.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_es-es");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.es_es");dojo.nls.colors.es_es={"lightsteelblue":"azul acero claro","orangered":"rojo anaranjado","midnightblue":"azul medianoche","cadetblue":"azul cadete","seashell":"blanco marfil","slategrey":"gris pizarra","coral":"coral","darkturquoise":"turquesa oscuro","antiquewhite":"blanco antiguo","mediumspringgreen":"verde primavera medio","salmon":"salmón","darkgrey":"gris oscuro","ivory":"marfil","greenyellow":"amarillo verdoso","mistyrose":"rosa difuminado","lightsalmon":"salmón claro","silver":"plateado","dimgrey":"gris marengo","orange":"naranja","white":"blanco","navajowhite":"blanco navajo","royalblue":"azul real","deeppink":"rosa fuerte","lime":"lima","oldlace":"encaje antiguo","chartreuse":"verde pálido 2","darkcyan":"cian oscuro","yellow":"amarillo","linen":"blanco arena","olive":"verde oliva","gold":"oro","lawngreen":"verde césped","lightyellow":"amarillo claro","tan":"canela","darkviolet":"violeta oscuro","lightslategrey":"gris pizarra claro","grey":"gris","darkkhaki":"caqui oscuro","green":"verde","deepskyblue":"azul cielo fuerte","aqua":"aguamarina","sienna":"siena","mintcream":"crema menta","rosybrown":"marrón rosáceo","mediumslateblue":"azul pizarra medio","magenta":"magenta","lightseagreen":"verde mar claro","cyan":"cian","olivedrab":"verde oliva pardusco","darkgoldenrod":"ocre oscuro","slateblue":"azul pizarra","mediumaquamarine":"aguamarina medio","lavender":"lavanda","mediumseagreen":"verde mar medio","maroon":"granate","darkslategray":"gris pizarra oscuro","mediumturquoise":"turquesa medio","ghostwhite":"blanco ligero","darkblue":"azul oscuro","mediumvioletred":"rojo violáceo medio","brown":"marrón","lightgray":"gris claro","sandybrown":"marrón arcilla","pink":"rosa","firebrick":"teja","indigo":"añil","snow":"nieve","darkorchid":"orquídea oscuro","turquoise":"turquesa","chocolate":"chocolate","springgreen":"verde fuerte","moccasin":"arena","navy":"azul marino","lemonchiffon":"amarillo pastel","teal":"verde azulado","floralwhite":"blanco manteca","cornflowerblue":"azul aciano","paleturquoise":"turquesa pálido","purple":"púrpura","gainsboro":"azul gainsboro","plum":"ciruela","red":"rojo","blue":"azul","forestgreen":"verde pino","darkgreen":"verde oscuro","honeydew":"flor de rocío","darkseagreen":"verde mar oscuro","lightcoral":"coral claro","palevioletred":"rojo violáceo pálido","mediumpurple":"púrpura medio","saddlebrown":"cuero","darkmagenta":"magenta oscuro","thistle":"cardo","whitesmoke":"blanco ahumado","wheat":"trigo","violet":"violeta","lightskyblue":"azul cielo claro","goldenrod":"ocre","mediumblue":"azul medio","skyblue":"azul cielo","crimson":"carmesí","darksalmon":"salmón oscuro","darkred":"rojo oscuro","darkslategrey":"gris pizarra oscuro","peru":"perú","lightgrey":"gris claro","lightgoldenrodyellow":"ocre claro","blanchedalmond":"almendra pálido","aliceblue":"blanco azulado","bisque":"miel","slategray":"gris pizarra","palegoldenrod":"ocre pálido","darkorange":"naranja oscuro","aquamarine":"aguamarina 2","lightgreen":"verde claro","burlywood":"madera","dodgerblue":"azul fuerte","darkgray":"gris oscuro","lightcyan":"cian claro","powderblue":"azul suave","blueviolet":"azul violáceo","orchid":"orquídea","dimgray":"gris marengo","beige":"beige","fuchsia":"fucsia","lavenderblush":"lavanda rosácea","hotpink":"rosa oscuro","steelblue":"azul acero","tomato":"tomate","lightpink":"rosa claro","limegreen":"lima limón","indianred":"rojo teja","papayawhip":"papaya claro","lightslategray":"gris pizarra claro","gray":"gris","mediumorchid":"orquídea medio","cornsilk":"crudo","black":"negro","seagreen":"verde mar","darkslateblue":"azul pizarra oscuro","khaki":"caqui","lightblue":"azul claro","palegreen":"verde pálido","azure":"blanco cielo","peachpuff":"melocotón","darkolivegreen":"verde oliva oscuro","yellowgreen":"verde amarillento"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.es_es");dijit.nls.loading.es_es={"loadingState":"Cargando...","errorState":"Lo siento, se ha producido un error"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.es_es");dijit.nls.common.es_es={"buttonOk":"Aceptar","buttonCancel":"Cancelar","buttonSave":"Guardar","itemClose":"Cerrar"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.es_es");dijit.form.nls.validate.es_es={"rangeMessage":"Este valor está fuera del intervalo.","invalidMessage":"El valor especificado no es válido.","missingMessage":"Este valor es necesario."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.es_es");dijit.form.nls.ComboBox.es_es={"previousMessage":"Opciones anteriores","nextMessage":"Más opciones"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.es_es");dojo.cldr.nls.number.es_es={"group":".","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"¤ #,##0.00","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_es.js b/lib/dojo/nls/tt-rss-layer_es.js
new file mode 100644
index 000000000..d9c37c058
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_es.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_es");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.es");dojo.nls.colors.es={"lightsteelblue":"azul acero claro","orangered":"rojo anaranjado","midnightblue":"azul medianoche","cadetblue":"azul cadete","seashell":"blanco marfil","slategrey":"gris pizarra","coral":"coral","darkturquoise":"turquesa oscuro","antiquewhite":"blanco antiguo","mediumspringgreen":"verde primavera medio","salmon":"salmón","darkgrey":"gris oscuro","ivory":"marfil","greenyellow":"amarillo verdoso","mistyrose":"rosa difuminado","lightsalmon":"salmón claro","silver":"plateado","dimgrey":"gris marengo","orange":"naranja","white":"blanco","navajowhite":"blanco navajo","royalblue":"azul real","deeppink":"rosa fuerte","lime":"lima","oldlace":"encaje antiguo","chartreuse":"verde pálido 2","darkcyan":"cian oscuro","yellow":"amarillo","linen":"blanco arena","olive":"verde oliva","gold":"oro","lawngreen":"verde césped","lightyellow":"amarillo claro","tan":"canela","darkviolet":"violeta oscuro","lightslategrey":"gris pizarra claro","grey":"gris","darkkhaki":"caqui oscuro","green":"verde","deepskyblue":"azul cielo fuerte","aqua":"aguamarina","sienna":"siena","mintcream":"crema menta","rosybrown":"marrón rosáceo","mediumslateblue":"azul pizarra medio","magenta":"magenta","lightseagreen":"verde mar claro","cyan":"cian","olivedrab":"verde oliva pardusco","darkgoldenrod":"ocre oscuro","slateblue":"azul pizarra","mediumaquamarine":"aguamarina medio","lavender":"lavanda","mediumseagreen":"verde mar medio","maroon":"granate","darkslategray":"gris pizarra oscuro","mediumturquoise":"turquesa medio","ghostwhite":"blanco ligero","darkblue":"azul oscuro","mediumvioletred":"rojo violáceo medio","brown":"marrón","lightgray":"gris claro","sandybrown":"marrón arcilla","pink":"rosa","firebrick":"teja","indigo":"añil","snow":"nieve","darkorchid":"orquídea oscuro","turquoise":"turquesa","chocolate":"chocolate","springgreen":"verde fuerte","moccasin":"arena","navy":"azul marino","lemonchiffon":"amarillo pastel","teal":"verde azulado","floralwhite":"blanco manteca","cornflowerblue":"azul aciano","paleturquoise":"turquesa pálido","purple":"púrpura","gainsboro":"azul gainsboro","plum":"ciruela","red":"rojo","blue":"azul","forestgreen":"verde pino","darkgreen":"verde oscuro","honeydew":"flor de rocío","darkseagreen":"verde mar oscuro","lightcoral":"coral claro","palevioletred":"rojo violáceo pálido","mediumpurple":"púrpura medio","saddlebrown":"cuero","darkmagenta":"magenta oscuro","thistle":"cardo","whitesmoke":"blanco ahumado","wheat":"trigo","violet":"violeta","lightskyblue":"azul cielo claro","goldenrod":"ocre","mediumblue":"azul medio","skyblue":"azul cielo","crimson":"carmesí","darksalmon":"salmón oscuro","darkred":"rojo oscuro","darkslategrey":"gris pizarra oscuro","peru":"perú","lightgrey":"gris claro","lightgoldenrodyellow":"ocre claro","blanchedalmond":"almendra pálido","aliceblue":"blanco azulado","bisque":"miel","slategray":"gris pizarra","palegoldenrod":"ocre pálido","darkorange":"naranja oscuro","aquamarine":"aguamarina 2","lightgreen":"verde claro","burlywood":"madera","dodgerblue":"azul fuerte","darkgray":"gris oscuro","lightcyan":"cian claro","powderblue":"azul suave","blueviolet":"azul violáceo","orchid":"orquídea","dimgray":"gris marengo","beige":"beige","fuchsia":"fucsia","lavenderblush":"lavanda rosácea","hotpink":"rosa oscuro","steelblue":"azul acero","tomato":"tomate","lightpink":"rosa claro","limegreen":"lima limón","indianred":"rojo teja","papayawhip":"papaya claro","lightslategray":"gris pizarra claro","gray":"gris","mediumorchid":"orquídea medio","cornsilk":"crudo","black":"negro","seagreen":"verde mar","darkslateblue":"azul pizarra oscuro","khaki":"caqui","lightblue":"azul claro","palegreen":"verde pálido","azure":"blanco cielo","peachpuff":"melocotón","darkolivegreen":"verde oliva oscuro","yellowgreen":"verde amarillento"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.es");dijit.nls.loading.es={"loadingState":"Cargando...","errorState":"Lo siento, se ha producido un error"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.es");dijit.nls.common.es={"buttonOk":"Aceptar","buttonCancel":"Cancelar","buttonSave":"Guardar","itemClose":"Cerrar"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.es");dijit.form.nls.validate.es={"rangeMessage":"Este valor está fuera del intervalo.","invalidMessage":"El valor especificado no es válido.","missingMessage":"Este valor es necesario."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.es");dijit.form.nls.ComboBox.es={"previousMessage":"Opciones anteriores","nextMessage":"Más opciones"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.es");dojo.cldr.nls.number.es={"group":".","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"¤ #,##0.00","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_fi-fi.js b/lib/dojo/nls/tt-rss-layer_fi-fi.js
new file mode 100644
index 000000000..0a78dd3c9
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_fi-fi.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_fi-fi");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.fi_fi");dojo.nls.colors.fi_fi={"lightsteelblue":"light steel blue","orangered":"orange red","midnightblue":"midnight blue","cadetblue":"cadet blue","seashell":"seashell","slategrey":"slate gray","coral":"coral","darkturquoise":"dark turquoise","antiquewhite":"antique white","mediumspringgreen":"medium spring green","salmon":"salmon","darkgrey":"dark gray","ivory":"ivory","greenyellow":"green-yellow","mistyrose":"misty rose","lightsalmon":"light salmon","silver":"silver","dimgrey":"dim gray","orange":"orange","white":"white","navajowhite":"navajo white","royalblue":"royal blue","deeppink":"deep pink","lime":"lime","oldlace":"old lace","chartreuse":"chartreuse","darkcyan":"dark cyan","yellow":"yellow","linen":"linen","olive":"olive","gold":"gold","lawngreen":"lawn green","lightyellow":"light yellow","tan":"tan","darkviolet":"dark violet","lightslategrey":"light slate gray","grey":"gray","darkkhaki":"dark khaki","green":"green","deepskyblue":"deep sky blue","aqua":"aqua","sienna":"sienna","mintcream":"mint cream","rosybrown":"rosy brown","mediumslateblue":"medium slate blue","magenta":"magenta","lightseagreen":"light sea green","cyan":"cyan","olivedrab":"olive drab","darkgoldenrod":"dark goldenrod","slateblue":"slate blue","mediumaquamarine":"medium aquamarine","lavender":"lavender","mediumseagreen":"medium sea green","maroon":"maroon","darkslategray":"dark slate gray","mediumturquoise":"medium turquoise","ghostwhite":"ghost white","darkblue":"dark blue","mediumvioletred":"medium violet-red","brown":"brown","lightgray":"light gray","sandybrown":"sandy brown","pink":"pink","firebrick":"fire brick","indigo":"indigo","snow":"snow","darkorchid":"dark orchid","turquoise":"turquoise","chocolate":"chocolate","springgreen":"spring green","moccasin":"moccasin","navy":"navy","lemonchiffon":"lemon chiffon","teal":"teal","floralwhite":"floral white","cornflowerblue":"cornflower blue","paleturquoise":"pale turquoise","purple":"purple","gainsboro":"gainsboro","plum":"plum","red":"red","blue":"blue","forestgreen":"forest green","darkgreen":"dark green","honeydew":"honeydew","darkseagreen":"dark sea green","lightcoral":"light coral","palevioletred":"pale violet-red","mediumpurple":"medium purple","saddlebrown":"saddle brown","darkmagenta":"dark magenta","thistle":"thistle","whitesmoke":"white smoke","wheat":"wheat","violet":"violet","lightskyblue":"light sky blue","goldenrod":"goldenrod","mediumblue":"medium blue","skyblue":"sky blue","crimson":"crimson","darksalmon":"dark salmon","darkred":"dark red","darkslategrey":"dark slate gray","peru":"peru","lightgrey":"light gray","lightgoldenrodyellow":"light goldenrod yellow","blanchedalmond":"blanched almond","aliceblue":"alice blue","bisque":"bisque","slategray":"slate gray","palegoldenrod":"pale goldenrod","darkorange":"dark orange","aquamarine":"aquamarine","lightgreen":"light green","burlywood":"burlywood","dodgerblue":"dodger blue","darkgray":"dark gray","lightcyan":"light cyan","powderblue":"powder blue","blueviolet":"blue-violet","orchid":"orchid","dimgray":"dim gray","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavender blush","hotpink":"hot pink","steelblue":"steel blue","tomato":"tomato","lightpink":"light pink","limegreen":"lime green","indianred":"indian red","papayawhip":"papaya whip","lightslategray":"light slate gray","gray":"gray","mediumorchid":"medium orchid","cornsilk":"cornsilk","black":"black","seagreen":"sea green","darkslateblue":"dark slate blue","khaki":"khaki","lightblue":"light blue","palegreen":"pale green","azure":"azure","peachpuff":"peach puff","darkolivegreen":"dark olive green","yellowgreen":"yellow green"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.fi_fi");dijit.nls.loading.fi_fi={"loadingState":"Lataus on meneillään...","errorState":"On ilmennyt virhe."};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.fi_fi");dijit.nls.common.fi_fi={"buttonOk":"OK","buttonCancel":"Peruuta","buttonSave":"Tallenna","itemClose":"Sulje"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.fi_fi");dijit.form.nls.validate.fi_fi={"rangeMessage":"Tämä arvo on sallitun alueen ulkopuolella.","invalidMessage":"Annettu arvo ei kelpaa.","missingMessage":"Tämä arvo on pakollinen."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.fi_fi");dijit.form.nls.ComboBox.fi_fi={"previousMessage":"Edelliset valinnat","nextMessage":"Lisää valintoja"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.fi_fi");dojo.cldr.nls.number.fi_fi={"group":" ","percentSign":"%","exponential":"E","percentFormat":"#,##0 %","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"epäluku","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_fi.js b/lib/dojo/nls/tt-rss-layer_fi.js
new file mode 100644
index 000000000..3932b9873
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_fi.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_fi");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.fi");dojo.nls.colors.fi={"lightsteelblue":"light steel blue","orangered":"orange red","midnightblue":"midnight blue","cadetblue":"cadet blue","seashell":"seashell","slategrey":"slate gray","coral":"coral","darkturquoise":"dark turquoise","antiquewhite":"antique white","mediumspringgreen":"medium spring green","salmon":"salmon","darkgrey":"dark gray","ivory":"ivory","greenyellow":"green-yellow","mistyrose":"misty rose","lightsalmon":"light salmon","silver":"silver","dimgrey":"dim gray","orange":"orange","white":"white","navajowhite":"navajo white","royalblue":"royal blue","deeppink":"deep pink","lime":"lime","oldlace":"old lace","chartreuse":"chartreuse","darkcyan":"dark cyan","yellow":"yellow","linen":"linen","olive":"olive","gold":"gold","lawngreen":"lawn green","lightyellow":"light yellow","tan":"tan","darkviolet":"dark violet","lightslategrey":"light slate gray","grey":"gray","darkkhaki":"dark khaki","green":"green","deepskyblue":"deep sky blue","aqua":"aqua","sienna":"sienna","mintcream":"mint cream","rosybrown":"rosy brown","mediumslateblue":"medium slate blue","magenta":"magenta","lightseagreen":"light sea green","cyan":"cyan","olivedrab":"olive drab","darkgoldenrod":"dark goldenrod","slateblue":"slate blue","mediumaquamarine":"medium aquamarine","lavender":"lavender","mediumseagreen":"medium sea green","maroon":"maroon","darkslategray":"dark slate gray","mediumturquoise":"medium turquoise","ghostwhite":"ghost white","darkblue":"dark blue","mediumvioletred":"medium violet-red","brown":"brown","lightgray":"light gray","sandybrown":"sandy brown","pink":"pink","firebrick":"fire brick","indigo":"indigo","snow":"snow","darkorchid":"dark orchid","turquoise":"turquoise","chocolate":"chocolate","springgreen":"spring green","moccasin":"moccasin","navy":"navy","lemonchiffon":"lemon chiffon","teal":"teal","floralwhite":"floral white","cornflowerblue":"cornflower blue","paleturquoise":"pale turquoise","purple":"purple","gainsboro":"gainsboro","plum":"plum","red":"red","blue":"blue","forestgreen":"forest green","darkgreen":"dark green","honeydew":"honeydew","darkseagreen":"dark sea green","lightcoral":"light coral","palevioletred":"pale violet-red","mediumpurple":"medium purple","saddlebrown":"saddle brown","darkmagenta":"dark magenta","thistle":"thistle","whitesmoke":"white smoke","wheat":"wheat","violet":"violet","lightskyblue":"light sky blue","goldenrod":"goldenrod","mediumblue":"medium blue","skyblue":"sky blue","crimson":"crimson","darksalmon":"dark salmon","darkred":"dark red","darkslategrey":"dark slate gray","peru":"peru","lightgrey":"light gray","lightgoldenrodyellow":"light goldenrod yellow","blanchedalmond":"blanched almond","aliceblue":"alice blue","bisque":"bisque","slategray":"slate gray","palegoldenrod":"pale goldenrod","darkorange":"dark orange","aquamarine":"aquamarine","lightgreen":"light green","burlywood":"burlywood","dodgerblue":"dodger blue","darkgray":"dark gray","lightcyan":"light cyan","powderblue":"powder blue","blueviolet":"blue-violet","orchid":"orchid","dimgray":"dim gray","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavender blush","hotpink":"hot pink","steelblue":"steel blue","tomato":"tomato","lightpink":"light pink","limegreen":"lime green","indianred":"indian red","papayawhip":"papaya whip","lightslategray":"light slate gray","gray":"gray","mediumorchid":"medium orchid","cornsilk":"cornsilk","black":"black","seagreen":"sea green","darkslateblue":"dark slate blue","khaki":"khaki","lightblue":"light blue","palegreen":"pale green","azure":"azure","peachpuff":"peach puff","darkolivegreen":"dark olive green","yellowgreen":"yellow green"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.fi");dijit.nls.loading.fi={"loadingState":"Lataus on meneillään...","errorState":"On ilmennyt virhe."};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.fi");dijit.nls.common.fi={"buttonOk":"OK","buttonCancel":"Peruuta","buttonSave":"Tallenna","itemClose":"Sulje"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.fi");dijit.form.nls.validate.fi={"rangeMessage":"Tämä arvo on sallitun alueen ulkopuolella.","invalidMessage":"Annettu arvo ei kelpaa.","missingMessage":"Tämä arvo on pakollinen."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.fi");dijit.form.nls.ComboBox.fi={"previousMessage":"Edelliset valinnat","nextMessage":"Lisää valintoja"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.fi");dojo.cldr.nls.number.fi={"group":" ","percentSign":"%","exponential":"E","percentFormat":"#,##0 %","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"epäluku","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_fr-fr.js b/lib/dojo/nls/tt-rss-layer_fr-fr.js
new file mode 100644
index 000000000..e46a35a24
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_fr-fr.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_fr-fr");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.fr_fr");dojo.nls.colors.fr_fr={"lightsteelblue":"bleu acier clair","orangered":"rouge orangé","midnightblue":"bleu nuit","cadetblue":"bleu pétrole","seashell":"coquillage","slategrey":"gris ardoise","coral":"corail","darkturquoise":"turquoise foncé","antiquewhite":"blanc antique","mediumspringgreen":"vert printemps moyen","salmon":"saumon","darkgrey":"gris foncé","ivory":"ivoire","greenyellow":"vert-jaune","mistyrose":"rose pâle","lightsalmon":"saumon clair","silver":"argent","dimgrey":"gris soutenu","orange":"orange","white":"blanc","navajowhite":"chair","royalblue":"bleu roi","deeppink":"rose soutenu","lime":"vert citron","oldlace":"blanc cassé","chartreuse":"vert vif","darkcyan":"cyan foncé","yellow":"jaune","linen":"écru","olive":"olive","gold":"or","lawngreen":"vert prairie","lightyellow":"jaune clair","tan":"grège","darkviolet":"violet foncé","lightslategrey":"gris ardoise clair","grey":"gris","darkkhaki":"kaki foncé","green":"vert","deepskyblue":"bleu ciel soutenu","aqua":"bleu-vert","sienna":"terre de sienne","mintcream":"crème de menthe","rosybrown":"vieux rose","mediumslateblue":"bleu ardoise moyen","magenta":"magenta","lightseagreen":"vert d'eau clair","cyan":"cyan","olivedrab":"brun verdâtre","darkgoldenrod":"jaune paille foncé","slateblue":"bleu ardoise","mediumaquamarine":"aigue-marine moyen","lavender":"lavande","mediumseagreen":"vert d'eau moyen","maroon":"marron","darkslategray":"gris ardoise foncé","mediumturquoise":"turquoise moyen","ghostwhite":"blanc laiteux","darkblue":"bleu foncé","mediumvioletred":"rouge violacé moyen","brown":"brun","lightgray":"gris clair","sandybrown":"sable","pink":"rose","firebrick":"rouge brique","indigo":"indigo","snow":"neige","darkorchid":"lilas foncé","turquoise":"turquoise","chocolate":"chocolat","springgreen":"vert printemps","moccasin":"chamois","navy":"bleu marine","lemonchiffon":"mousse de citron","teal":"sarcelle","floralwhite":"lys","cornflowerblue":"bleuet","paleturquoise":"turquoise pâle","purple":"pourpre","gainsboro":"gris souris","plum":"prune","red":"rouge","blue":"bleu","forestgreen":"vert sapin","darkgreen":"vert foncé","honeydew":"opalin","darkseagreen":"vert d'eau foncé","lightcoral":"corail clair","palevioletred":"rouge violacé pâle","mediumpurple":"pourpre moyen","saddlebrown":"brun cuir","darkmagenta":"magenta foncé","thistle":"chardon","whitesmoke":"blanc cendré","wheat":"blé","violet":"violet","lightskyblue":"bleu ciel clair","goldenrod":"jaune paille","mediumblue":"bleu moyen","skyblue":"bleu ciel","crimson":"cramoisi","darksalmon":"saumon foncé","darkred":"rouge foncé","darkslategrey":"gris ardoise foncé","peru":"caramel","lightgrey":"gris clair","lightgoldenrodyellow":"jaune paille clair","blanchedalmond":"coquille d'oeuf","aliceblue":"bleu gris","bisque":"beige rosé","slategray":"gris ardoise","palegoldenrod":"jaune paille pâle","darkorange":"orange foncé","aquamarine":"aigue-marine","lightgreen":"vert clair","burlywood":"bois précieux","dodgerblue":"bleu France","darkgray":"gris foncé","lightcyan":"cyan clair","powderblue":"bleu de smalt","blueviolet":"bleu-violet","orchid":"lilas","dimgray":"gris soutenu","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavandin","hotpink":"rose intense","steelblue":"bleu acier","tomato":"tomate","lightpink":"rose clair","limegreen":"citron vert","indianred":"rose indien","papayawhip":"crème de papaye","lightslategray":"gris ardoise clair","gray":"gris","mediumorchid":"lilas moyen","cornsilk":"vanille","black":"noir","seagreen":"vert d'eau","darkslateblue":"bleu ardoise foncé","khaki":"kaki","lightblue":"bleu clair","palegreen":"vert pâle","azure":"bleu azur","peachpuff":"pêche","darkolivegreen":"olive foncé","yellowgreen":"vert jaunâtre"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.fr_fr");dijit.nls.loading.fr_fr={"loadingState":"Chargement...","errorState":"Une erreur est survenue"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.fr_fr");dijit.nls.common.fr_fr={"buttonOk":"OK","buttonCancel":"Annuler","buttonSave":"Sauvegarder","itemClose":"Fermer"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.fr_fr");dijit.form.nls.validate.fr_fr={"rangeMessage":"Cette valeur n'est pas comprise dans la plage autorisée.","invalidMessage":"La valeur indiquée n'est pas correcte.","missingMessage":"Cette valeur est requise."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.fr_fr");dijit.form.nls.ComboBox.fr_fr={"previousMessage":"Choix précédents","nextMessage":"Plus de choix"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.fr_fr");dojo.cldr.nls.number.fr_fr={"group":" ","percentSign":"%","exponential":"E","percentFormat":"#,##0 %","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_fr.js b/lib/dojo/nls/tt-rss-layer_fr.js
new file mode 100644
index 000000000..8595a42d0
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_fr.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_fr");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.fr");dojo.nls.colors.fr={"lightsteelblue":"bleu acier clair","orangered":"rouge orangé","midnightblue":"bleu nuit","cadetblue":"bleu pétrole","seashell":"coquillage","slategrey":"gris ardoise","coral":"corail","darkturquoise":"turquoise foncé","antiquewhite":"blanc antique","mediumspringgreen":"vert printemps moyen","salmon":"saumon","darkgrey":"gris foncé","ivory":"ivoire","greenyellow":"vert-jaune","mistyrose":"rose pâle","lightsalmon":"saumon clair","silver":"argent","dimgrey":"gris soutenu","orange":"orange","white":"blanc","navajowhite":"chair","royalblue":"bleu roi","deeppink":"rose soutenu","lime":"vert citron","oldlace":"blanc cassé","chartreuse":"vert vif","darkcyan":"cyan foncé","yellow":"jaune","linen":"écru","olive":"olive","gold":"or","lawngreen":"vert prairie","lightyellow":"jaune clair","tan":"grège","darkviolet":"violet foncé","lightslategrey":"gris ardoise clair","grey":"gris","darkkhaki":"kaki foncé","green":"vert","deepskyblue":"bleu ciel soutenu","aqua":"bleu-vert","sienna":"terre de sienne","mintcream":"crème de menthe","rosybrown":"vieux rose","mediumslateblue":"bleu ardoise moyen","magenta":"magenta","lightseagreen":"vert d'eau clair","cyan":"cyan","olivedrab":"brun verdâtre","darkgoldenrod":"jaune paille foncé","slateblue":"bleu ardoise","mediumaquamarine":"aigue-marine moyen","lavender":"lavande","mediumseagreen":"vert d'eau moyen","maroon":"marron","darkslategray":"gris ardoise foncé","mediumturquoise":"turquoise moyen","ghostwhite":"blanc laiteux","darkblue":"bleu foncé","mediumvioletred":"rouge violacé moyen","brown":"brun","lightgray":"gris clair","sandybrown":"sable","pink":"rose","firebrick":"rouge brique","indigo":"indigo","snow":"neige","darkorchid":"lilas foncé","turquoise":"turquoise","chocolate":"chocolat","springgreen":"vert printemps","moccasin":"chamois","navy":"bleu marine","lemonchiffon":"mousse de citron","teal":"sarcelle","floralwhite":"lys","cornflowerblue":"bleuet","paleturquoise":"turquoise pâle","purple":"pourpre","gainsboro":"gris souris","plum":"prune","red":"rouge","blue":"bleu","forestgreen":"vert sapin","darkgreen":"vert foncé","honeydew":"opalin","darkseagreen":"vert d'eau foncé","lightcoral":"corail clair","palevioletred":"rouge violacé pâle","mediumpurple":"pourpre moyen","saddlebrown":"brun cuir","darkmagenta":"magenta foncé","thistle":"chardon","whitesmoke":"blanc cendré","wheat":"blé","violet":"violet","lightskyblue":"bleu ciel clair","goldenrod":"jaune paille","mediumblue":"bleu moyen","skyblue":"bleu ciel","crimson":"cramoisi","darksalmon":"saumon foncé","darkred":"rouge foncé","darkslategrey":"gris ardoise foncé","peru":"caramel","lightgrey":"gris clair","lightgoldenrodyellow":"jaune paille clair","blanchedalmond":"coquille d'oeuf","aliceblue":"bleu gris","bisque":"beige rosé","slategray":"gris ardoise","palegoldenrod":"jaune paille pâle","darkorange":"orange foncé","aquamarine":"aigue-marine","lightgreen":"vert clair","burlywood":"bois précieux","dodgerblue":"bleu France","darkgray":"gris foncé","lightcyan":"cyan clair","powderblue":"bleu de smalt","blueviolet":"bleu-violet","orchid":"lilas","dimgray":"gris soutenu","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavandin","hotpink":"rose intense","steelblue":"bleu acier","tomato":"tomate","lightpink":"rose clair","limegreen":"citron vert","indianred":"rose indien","papayawhip":"crème de papaye","lightslategray":"gris ardoise clair","gray":"gris","mediumorchid":"lilas moyen","cornsilk":"vanille","black":"noir","seagreen":"vert d'eau","darkslateblue":"bleu ardoise foncé","khaki":"kaki","lightblue":"bleu clair","palegreen":"vert pâle","azure":"bleu azur","peachpuff":"pêche","darkolivegreen":"olive foncé","yellowgreen":"vert jaunâtre"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.fr");dijit.nls.loading.fr={"loadingState":"Chargement...","errorState":"Une erreur est survenue"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.fr");dijit.nls.common.fr={"buttonOk":"OK","buttonCancel":"Annuler","buttonSave":"Sauvegarder","itemClose":"Fermer"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.fr");dijit.form.nls.validate.fr={"rangeMessage":"Cette valeur n'est pas comprise dans la plage autorisée.","invalidMessage":"La valeur indiquée n'est pas correcte.","missingMessage":"Cette valeur est requise."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.fr");dijit.form.nls.ComboBox.fr={"previousMessage":"Choix précédents","nextMessage":"Plus de choix"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.fr");dojo.cldr.nls.number.fr={"group":" ","percentSign":"%","exponential":"E","percentFormat":"#,##0 %","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_he-il.js b/lib/dojo/nls/tt-rss-layer_he-il.js
new file mode 100644
index 000000000..59bc21f1f
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_he-il.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_he-il");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.he_il");dojo.nls.colors.he_il={"lightsteelblue":"כחול פלדה בהיר","orangered":"כתום אדום","midnightblue":"כחול כהה","cadetblue":"כחול ים","seashell":"צדף","slategrey":"אפור צפחה","coral":"אלמוג","darkturquoise":"טורקיז כהה","antiquewhite":"לבן עתיק","mediumspringgreen":"ירוק אביב בינוני","salmon":"סלמון","darkgrey":"אפור כהה","ivory":"שנהב","greenyellow":"ירוק-צהוב","mistyrose":"ורוד מעורפל","lightsalmon":"סלמון בהיר","silver":"כסף","dimgrey":"אפור עמום","orange":"כתום","white":"לבן","navajowhite":"לבן נוואחו","royalblue":"כחול מלכותי","deeppink":"ורוד עמוק","lime":"לימון","oldlace":"תחרה עתיקה","chartreuse":"ירוק-צהוב","darkcyan":"טורקיז כהה","yellow":"צהוב","linen":"פשתן","olive":"זית","gold":"זהב","lawngreen":"ירוק דשא","lightyellow":"צהוב בהיר","tan":"חום אדמדם","darkviolet":"סגול כהה","lightslategrey":"אפור צפחה בהיר","grey":"אפור","darkkhaki":"חאקי כהה","green":"ירוק","deepskyblue":"כחול שמיים עמוק","aqua":"אקווה","sienna":"סיינה","mintcream":"קרם מנטה","rosybrown":"חום ורדרד","mediumslateblue":"כחול צפחה בינוני","magenta":"בורדו","lightseagreen":"ירוק ים בהיר","cyan":"טורקיז","olivedrab":"זית עמום","darkgoldenrod":"זהוב כהה","slateblue":"כחול צפחה","mediumaquamarine":"כחול בינוני","lavender":"לבנדר","mediumseagreen":"ירוק ים בינוני","maroon":"חום אדמדם","darkslategray":"אפור צפחה כהה","mediumturquoise":"טורקיז בינוני","ghostwhite":"לבן רפאים","darkblue":"כחול כהה","mediumvioletred":"סגול-אדום בינוני","brown":"חום","lightgray":"אפור בהיר","sandybrown":"חום חולי","pink":"ורוד","firebrick":"לבנה שרופה","indigo":"אינדיגו","snow":"שלג","darkorchid":"סחלב כהה","turquoise":"טורקיז","chocolate":"שוקולד","springgreen":"ירוק אביב","moccasin":"מוקסין","navy":"כחול כהה","lemonchiffon":"ירוק לימון","teal":"כחול-ירוק כהה","floralwhite":"לבן פרחוני","cornflowerblue":"כחול דרדר","paleturquoise":"טורקיז בהיר","purple":"סגול","gainsboro":"גיינסבורו","plum":"שזיף","red":"אדום","blue":"כחול","forestgreen":"ירוק יער","darkgreen":"ירוק כהה","honeydew":"ירקרק","darkseagreen":"ירוק ים כהה","lightcoral":"אלמוג בהיר","palevioletred":"סגול-אדום בהיר","mediumpurple":"סגול בינוני","saddlebrown":"חום דהוי","darkmagenta":"בורדו כהה","thistle":"דרדר","whitesmoke":"עשן לבן","wheat":"חיוט","violet":"סגול","lightskyblue":"כחול שמיים בהיר","goldenrod":"זהוב","mediumblue":"תכלת בינוני","skyblue":"כחול שמיים","crimson":"ארגמן","darksalmon":"סלמון כהה","darkred":"אדום כהה","darkslategrey":"אפור צפחה כהה","peru":"פרו","lightgrey":"אפור בהיר","lightgoldenrodyellow":"צהוב בהיר","blanchedalmond":"שקד","aliceblue":"כחול פלדה","bisque":"לבן שקד","slategray":"אפור צפחה","palegoldenrod":"זהוב בהיר","darkorange":"כתום כהה","aquamarine":"אקוומארין","lightgreen":"ירוק בהיר","burlywood":"חום דהוי","dodgerblue":"כחול","darkgray":"אפור כהה","lightcyan":"טורקיז בהיר","powderblue":"כחול חיוור","blueviolet":"כחול-סגול","orchid":"סחלב","dimgray":"אפור עמום","beige":"בז'","fuchsia":"ורוד בהיר","lavenderblush":"סומק לבנדר","hotpink":"ורוד לוהט","steelblue":"כחול פלדה","tomato":"עגבניה","lightpink":"ורוד בהיר","limegreen":"ירוק לימוני","indianred":"אדום דהוי","papayawhip":"פפאיה","lightslategray":"אפור צפחה בהיר","gray":"אפור","mediumorchid":"סחלב בינוני","cornsilk":"צהבהב","black":"שחור","seagreen":"ירוק ים","darkslateblue":"כחול צפחה כהה","khaki":"חאקי","lightblue":"תכלת","palegreen":"ירוק בהיר","azure":"תכלת עז","peachpuff":"קציפת אפרסק","darkolivegreen":"ירוק זית כהה","yellowgreen":"ירוק צהוב"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.he_il");dijit.nls.loading.he_il={"loadingState":"טעינה...‏","errorState":"אירעה שגיאה"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.he_il");dijit.nls.common.he_il={"buttonOk":"אישור","buttonCancel":"ביטול","buttonSave":"שמירה","itemClose":"סגירה"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.he_il");dijit.form.nls.validate.he_il={"rangeMessage":"הערך מחוץ לטווח.","invalidMessage":"הערך שצוין אינו חוקי.","missingMessage":"זהו ערך דרוש."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.he_il");dijit.form.nls.ComboBox.he_il={"previousMessage":"האפשרויות הקודמות","nextMessage":"אפשרויות נוספות"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.he_il");dojo.cldr.nls.number.he_il={"group":",","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":".","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_he.js b/lib/dojo/nls/tt-rss-layer_he.js
new file mode 100644
index 000000000..a30b4434c
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_he.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_he");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.he");dojo.nls.colors.he={"lightsteelblue":"כחול פלדה בהיר","orangered":"כתום אדום","midnightblue":"כחול כהה","cadetblue":"כחול ים","seashell":"צדף","slategrey":"אפור צפחה","coral":"אלמוג","darkturquoise":"טורקיז כהה","antiquewhite":"לבן עתיק","mediumspringgreen":"ירוק אביב בינוני","salmon":"סלמון","darkgrey":"אפור כהה","ivory":"שנהב","greenyellow":"ירוק-צהוב","mistyrose":"ורוד מעורפל","lightsalmon":"סלמון בהיר","silver":"כסף","dimgrey":"אפור עמום","orange":"כתום","white":"לבן","navajowhite":"לבן נוואחו","royalblue":"כחול מלכותי","deeppink":"ורוד עמוק","lime":"לימון","oldlace":"תחרה עתיקה","chartreuse":"ירוק-צהוב","darkcyan":"טורקיז כהה","yellow":"צהוב","linen":"פשתן","olive":"זית","gold":"זהב","lawngreen":"ירוק דשא","lightyellow":"צהוב בהיר","tan":"חום אדמדם","darkviolet":"סגול כהה","lightslategrey":"אפור צפחה בהיר","grey":"אפור","darkkhaki":"חאקי כהה","green":"ירוק","deepskyblue":"כחול שמיים עמוק","aqua":"אקווה","sienna":"סיינה","mintcream":"קרם מנטה","rosybrown":"חום ורדרד","mediumslateblue":"כחול צפחה בינוני","magenta":"בורדו","lightseagreen":"ירוק ים בהיר","cyan":"טורקיז","olivedrab":"זית עמום","darkgoldenrod":"זהוב כהה","slateblue":"כחול צפחה","mediumaquamarine":"כחול בינוני","lavender":"לבנדר","mediumseagreen":"ירוק ים בינוני","maroon":"חום אדמדם","darkslategray":"אפור צפחה כהה","mediumturquoise":"טורקיז בינוני","ghostwhite":"לבן רפאים","darkblue":"כחול כהה","mediumvioletred":"סגול-אדום בינוני","brown":"חום","lightgray":"אפור בהיר","sandybrown":"חום חולי","pink":"ורוד","firebrick":"לבנה שרופה","indigo":"אינדיגו","snow":"שלג","darkorchid":"סחלב כהה","turquoise":"טורקיז","chocolate":"שוקולד","springgreen":"ירוק אביב","moccasin":"מוקסין","navy":"כחול כהה","lemonchiffon":"ירוק לימון","teal":"כחול-ירוק כהה","floralwhite":"לבן פרחוני","cornflowerblue":"כחול דרדר","paleturquoise":"טורקיז בהיר","purple":"סגול","gainsboro":"גיינסבורו","plum":"שזיף","red":"אדום","blue":"כחול","forestgreen":"ירוק יער","darkgreen":"ירוק כהה","honeydew":"ירקרק","darkseagreen":"ירוק ים כהה","lightcoral":"אלמוג בהיר","palevioletred":"סגול-אדום בהיר","mediumpurple":"סגול בינוני","saddlebrown":"חום דהוי","darkmagenta":"בורדו כהה","thistle":"דרדר","whitesmoke":"עשן לבן","wheat":"חיוט","violet":"סגול","lightskyblue":"כחול שמיים בהיר","goldenrod":"זהוב","mediumblue":"תכלת בינוני","skyblue":"כחול שמיים","crimson":"ארגמן","darksalmon":"סלמון כהה","darkred":"אדום כהה","darkslategrey":"אפור צפחה כהה","peru":"פרו","lightgrey":"אפור בהיר","lightgoldenrodyellow":"צהוב בהיר","blanchedalmond":"שקד","aliceblue":"כחול פלדה","bisque":"לבן שקד","slategray":"אפור צפחה","palegoldenrod":"זהוב בהיר","darkorange":"כתום כהה","aquamarine":"אקוומארין","lightgreen":"ירוק בהיר","burlywood":"חום דהוי","dodgerblue":"כחול","darkgray":"אפור כהה","lightcyan":"טורקיז בהיר","powderblue":"כחול חיוור","blueviolet":"כחול-סגול","orchid":"סחלב","dimgray":"אפור עמום","beige":"בז'","fuchsia":"ורוד בהיר","lavenderblush":"סומק לבנדר","hotpink":"ורוד לוהט","steelblue":"כחול פלדה","tomato":"עגבניה","lightpink":"ורוד בהיר","limegreen":"ירוק לימוני","indianred":"אדום דהוי","papayawhip":"פפאיה","lightslategray":"אפור צפחה בהיר","gray":"אפור","mediumorchid":"סחלב בינוני","cornsilk":"צהבהב","black":"שחור","seagreen":"ירוק ים","darkslateblue":"כחול צפחה כהה","khaki":"חאקי","lightblue":"תכלת","palegreen":"ירוק בהיר","azure":"תכלת עז","peachpuff":"קציפת אפרסק","darkolivegreen":"ירוק זית כהה","yellowgreen":"ירוק צהוב"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.he");dijit.nls.loading.he={"loadingState":"טעינה...‏","errorState":"אירעה שגיאה"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.he");dijit.nls.common.he={"buttonOk":"אישור","buttonCancel":"ביטול","buttonSave":"שמירה","itemClose":"סגירה"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.he");dijit.form.nls.validate.he={"rangeMessage":"הערך מחוץ לטווח.","invalidMessage":"הערך שצוין אינו חוקי.","missingMessage":"זהו ערך דרוש."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.he");dijit.form.nls.ComboBox.he={"previousMessage":"האפשרויות הקודמות","nextMessage":"אפשרויות נוספות"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.he");dojo.cldr.nls.number.he={"group":",","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":".","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_hu.js b/lib/dojo/nls/tt-rss-layer_hu.js
new file mode 100644
index 000000000..3e7728585
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_hu.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_hu");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.hu");dojo.nls.colors.hu={"lightsteelblue":"világos acélkék","orangered":"narancsvörös","midnightblue":"éjkék","cadetblue":"kadétkék","seashell":"kagyló","slategrey":"palaszürke","coral":"korall","darkturquoise":"sötét türkizkék","antiquewhite":"antik fehér","mediumspringgreen":"közepes tavaszzöld","salmon":"lazacszín","darkgrey":"sötétszürke","ivory":"elefántcsont","greenyellow":"zöldessárga","mistyrose":"halvány rózsaszín","lightsalmon":"világos lazacszín","silver":"ezüst","dimgrey":"halványszürke","orange":"narancssárga","white":"fehér","navajowhite":"navajo fehér","royalblue":"királykék","deeppink":"sötétrózsaszín","lime":"lime","oldlace":"régi csipke","chartreuse":"chartreuse","darkcyan":"sötét ciánkék","yellow":"sárga","linen":"vászonfehér","olive":"olajzöld","gold":"arany","lawngreen":"fűzöld","lightyellow":"világossárga","tan":"rozsdabarna","darkviolet":"sötét ibolyaszín","lightslategrey":"világos palaszürke","grey":"szürke","darkkhaki":"sötét khakiszín","green":"zöld","deepskyblue":"sötét égszínkék","aqua":"vízszín","sienna":"vörösesbarna","mintcream":"mentaszósz","rosybrown":"barnásrózsaszín","mediumslateblue":"közepes palakék","magenta":"bíbor","lightseagreen":"világos tengerzöld","cyan":"ciánkék","olivedrab":"olajzöld drapp","darkgoldenrod":"sötét aranyvessző","slateblue":"palakék","mediumaquamarine":"közepes akvamarin","lavender":"levendula","mediumseagreen":"közepes tengerzöld","maroon":"gesztenyebarna","darkslategray":"sötét palaszürke","mediumturquoise":"közepes türkizkék","ghostwhite":"szellemfehér","darkblue":"sötétkék","mediumvioletred":"közepes ibolyavörös","brown":"barna","lightgray":"világosszürke","sandybrown":"homokbarna","pink":"rózsaszín","firebrick":"téglavörös","indigo":"indigó","snow":"hó","darkorchid":"sötét orchidea","turquoise":"türkizkék","chocolate":"csokoládé","springgreen":"tavaszzöld","moccasin":"mokkaszín","navy":"tengerészkék","lemonchiffon":"sárga műselyem","teal":"pávakék","floralwhite":"virágfehér","cornflowerblue":"búzavirágkék","paleturquoise":"halvány türkizkék","purple":"lila","gainsboro":"gainsboro","plum":"szilvakék","red":"vörös","blue":"kék","forestgreen":"erdőzöld","darkgreen":"sötétzöld","honeydew":"mézharmat","darkseagreen":"sötét tengerzöld","lightcoral":"világos korall","palevioletred":"halvány ibolyavörös","mediumpurple":"közepes lila","saddlebrown":"nyeregbarna","darkmagenta":"sötétbíbor","thistle":"bogáncs","whitesmoke":"fehér füst","wheat":"búza","violet":"ibolyaszín","lightskyblue":"világos égszínkék","goldenrod":"aranyvessző","mediumblue":"közepes kék","skyblue":"égszínkék","crimson":"karmazsinvörös","darksalmon":"sötét lazacszín","darkred":"sötétvörös","darkslategrey":"sötét palaszürke","peru":"peru","lightgrey":"világosszürke","lightgoldenrodyellow":"világos aranyvessző sárga","blanchedalmond":"hámozott mandula","aliceblue":"Alice kék","bisque":"porcelán","slategray":"palaszürke","palegoldenrod":"halvány aranyvessző","darkorange":"sötét narancssárga","aquamarine":"akvamarin","lightgreen":"világoszöld","burlywood":"nyersfa","dodgerblue":"dodger kék","darkgray":"sötétszürke","lightcyan":"világos ciánkék","powderblue":"púderkék","blueviolet":"ibolyakék","orchid":"orchidea","dimgray":"halványszürke","beige":"bézs","fuchsia":"fukszia","lavenderblush":"pirosas levendula","hotpink":"meleg rózsaszín","steelblue":"acélkék","tomato":"paradicsom","lightpink":"világos rózsaszín","limegreen":"limezöld","indianred":"indiánvörös","papayawhip":"papayahab","lightslategray":"világos palaszürke","gray":"szürke","mediumorchid":"közepes orchidea","cornsilk":"kukoricahaj","black":"fekete","seagreen":"tengerzöld","darkslateblue":"sötét palakék","khaki":"khakiszín","lightblue":"világoskék","palegreen":"halványzöld","azure":"azúrkék","peachpuff":"barackszín","darkolivegreen":"sötét olajzöld","yellowgreen":"sárgászöld"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.hu");dijit.nls.loading.hu={"loadingState":"Betöltés...","errorState":"Sajnálom, hiba történt"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.hu");dijit.nls.common.hu={"buttonOk":"OK","buttonCancel":"Mégse","buttonSave":"Mentés","itemClose":"Bezárás"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.hu");dijit.form.nls.validate.hu={"rangeMessage":"Az érték kívül van a megengedett tartományon.","invalidMessage":"A megadott érték érvénytelen.","missingMessage":"Meg kell adni egy értéket."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.hu");dijit.form.nls.ComboBox.hu={"previousMessage":"Előző menüpontok","nextMessage":"További menüpontok"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.hu");dojo.cldr.nls.number.hu={"group":" ","percentSign":"%","exponential":"E","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","percentFormat":"#,##0%","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_it-it.js b/lib/dojo/nls/tt-rss-layer_it-it.js
new file mode 100644
index 000000000..ad0d6549c
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_it-it.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_it-it");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.it_it");dojo.nls.colors.it_it={"lightsteelblue":"blu acciao chiaro","orangered":"vermiglio","midnightblue":"blu melanzana scuro","cadetblue":"verde acqua","seashell":"sabbia rosa","slategrey":"grigio ardesia","coral":"corallo","darkturquoise":"turchese scuro","antiquewhite":"bianco antico","mediumspringgreen":"verde primavera medio","salmon":"salmone","darkgrey":"grigio scuro","ivory":"avorio","greenyellow":"giallo verde","mistyrose":"rosa pallido","lightsalmon":"salmone chiaro","silver":"grigio 25%","dimgrey":"grigio 80%","orange":"arancione","white":"bianco","navajowhite":"pesca chiaro","royalblue":"blu reale","deeppink":"ciclamino","lime":"verde fluorescente","oldlace":"mandorla","chartreuse":"verde brillante","darkcyan":"ciano scuro","yellow":"giallo","linen":"lino","olive":"verde oliva","gold":"oro","lawngreen":"verde prato","lightyellow":"giallo chiaro","tan":"grigio bruno","darkviolet":"viola scuro","lightslategrey":"grigio ardesia chiaro","grey":"grigio","darkkhaki":"kaki scuro","green":"verde","deepskyblue":"azzurro cielo scuro","aqua":"acqua","sienna":"cuoio","mintcream":"bianco nuvola","rosybrown":"marrone rosato","mediumslateblue":"blu ardesia medio","magenta":"magenta","lightseagreen":"verde mare chiaro","cyan":"ciano","olivedrab":"marrone oliva","darkgoldenrod":"ocra scuro","slateblue":"blu ardesia","mediumaquamarine":"acquamarina medio","lavender":"lavanda","mediumseagreen":"verde mare medio","maroon":"scarlatto","darkslategray":"grigio ardesia scuro","mediumturquoise":"turchese medio","ghostwhite":"bianco gesso","darkblue":"blu scuro","mediumvioletred":"vinaccia","brown":"marrone","lightgray":"grigio chiaro","sandybrown":"marrone sabbia","pink":"rosa","firebrick":"rosso mattone","indigo":"indaco","snow":"neve","darkorchid":"orchidea scuro","turquoise":"turchese","chocolate":"cioccolato","springgreen":"verde primavera","moccasin":"mocassino","navy":"blu notte","lemonchiffon":"caffelatte chiaro","teal":"verde turchese","floralwhite":"bianco giglio","cornflowerblue":"blu fiordaliso","paleturquoise":"turchese pallido","purple":"porpora","gainsboro":"grigio 10%","plum":"prugna","red":"rosso","blue":"blu","forestgreen":"verde foresta","darkgreen":"verde scuro","honeydew":"bianco germoglio","darkseagreen":"verde mare scuro","lightcoral":"rosa corallo","palevioletred":"vinaccia chiaro","mediumpurple":"porpora medio","saddlebrown":"cacao","darkmagenta":"magenta scuro","thistle":"rosa cenere","whitesmoke":"bianco fumo","wheat":"sabbia","violet":"viola","lightskyblue":"azzurro cielo chiaro","goldenrod":"ocra gialla","mediumblue":"blu medio","skyblue":"azzurro cielo","crimson":"cremisi","darksalmon":"salmone scuro","darkred":"rosso scuro","darkslategrey":"grigio ardesia scuro","peru":"marrone terra bruciata","lightgrey":"grigio chiaro","lightgoldenrodyellow":"giallo tenue","blanchedalmond":"mandorla chiaro","aliceblue":"blu alice","bisque":"incarnato","slategray":"grigio ardesia","palegoldenrod":"giallo zolfo chiaro","darkorange":"arancione scuro","aquamarine":"acquamarina","lightgreen":"verde chiaro","burlywood":"tabacco","dodgerblue":"blu d'oriente","darkgray":"grigio scuro","lightcyan":"ciano chiaro","powderblue":"azzurro polvere","blueviolet":"blu violetto","orchid":"orchidea","dimgray":"grigio 80%","beige":"beige","fuchsia":"fucsia","lavenderblush":"bianco rosato","hotpink":"rosa acceso","steelblue":"blu acciao","tomato":"pomodoro","lightpink":"rosa chiaro","limegreen":"verde lime","indianred":"terra indiana","papayawhip":"cipria","lightslategray":"grigio ardesia chiaro","gray":"grigio","mediumorchid":"orchidea medio","cornsilk":"crema","black":"nero","seagreen":"verde mare","darkslateblue":"blu ardesia scuro","khaki":"kaki","lightblue":"azzurro","palegreen":"verde pallido","azure":"azzurro ghiaccio","peachpuff":"pesca","darkolivegreen":"verde oliva scuro","yellowgreen":"giallo verde"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.it_it");dijit.nls.loading.it_it={"loadingState":"Caricamento in corso...","errorState":"Si è verificato un errore"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.it_it");dijit.nls.common.it_it={"buttonOk":"OK","buttonCancel":"Annulla","buttonSave":"Salva","itemClose":"Chiudi"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.it_it");dijit.form.nls.validate.it_it={"rangeMessage":"Questo valore non è compreso nell'intervallo.","invalidMessage":"Il valore immesso non è valido.","missingMessage":"Questo valore è obbligatorio."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.it_it");dijit.form.nls.ComboBox.it_it={"previousMessage":"Scelte precedenti","nextMessage":"Altre scelte"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.it_it");dojo.cldr.nls.number.it_it={"decimalFormat":"#,##0.###","group":".","scientificFormat":"#E0","percentFormat":"#,##0%","currencyFormat":"¤ #,##0.00","decimal":",","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"};
diff --git a/lib/dojo/nls/tt-rss-layer_it.js b/lib/dojo/nls/tt-rss-layer_it.js
new file mode 100644
index 000000000..640baacbc
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_it.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_it");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.it");dojo.nls.colors.it={"lightsteelblue":"blu acciao chiaro","orangered":"vermiglio","midnightblue":"blu melanzana scuro","cadetblue":"verde acqua","seashell":"sabbia rosa","slategrey":"grigio ardesia","coral":"corallo","darkturquoise":"turchese scuro","antiquewhite":"bianco antico","mediumspringgreen":"verde primavera medio","salmon":"salmone","darkgrey":"grigio scuro","ivory":"avorio","greenyellow":"giallo verde","mistyrose":"rosa pallido","lightsalmon":"salmone chiaro","silver":"grigio 25%","dimgrey":"grigio 80%","orange":"arancione","white":"bianco","navajowhite":"pesca chiaro","royalblue":"blu reale","deeppink":"ciclamino","lime":"verde fluorescente","oldlace":"mandorla","chartreuse":"verde brillante","darkcyan":"ciano scuro","yellow":"giallo","linen":"lino","olive":"verde oliva","gold":"oro","lawngreen":"verde prato","lightyellow":"giallo chiaro","tan":"grigio bruno","darkviolet":"viola scuro","lightslategrey":"grigio ardesia chiaro","grey":"grigio","darkkhaki":"kaki scuro","green":"verde","deepskyblue":"azzurro cielo scuro","aqua":"acqua","sienna":"cuoio","mintcream":"bianco nuvola","rosybrown":"marrone rosato","mediumslateblue":"blu ardesia medio","magenta":"magenta","lightseagreen":"verde mare chiaro","cyan":"ciano","olivedrab":"marrone oliva","darkgoldenrod":"ocra scuro","slateblue":"blu ardesia","mediumaquamarine":"acquamarina medio","lavender":"lavanda","mediumseagreen":"verde mare medio","maroon":"scarlatto","darkslategray":"grigio ardesia scuro","mediumturquoise":"turchese medio","ghostwhite":"bianco gesso","darkblue":"blu scuro","mediumvioletred":"vinaccia","brown":"marrone","lightgray":"grigio chiaro","sandybrown":"marrone sabbia","pink":"rosa","firebrick":"rosso mattone","indigo":"indaco","snow":"neve","darkorchid":"orchidea scuro","turquoise":"turchese","chocolate":"cioccolato","springgreen":"verde primavera","moccasin":"mocassino","navy":"blu notte","lemonchiffon":"caffelatte chiaro","teal":"verde turchese","floralwhite":"bianco giglio","cornflowerblue":"blu fiordaliso","paleturquoise":"turchese pallido","purple":"porpora","gainsboro":"grigio 10%","plum":"prugna","red":"rosso","blue":"blu","forestgreen":"verde foresta","darkgreen":"verde scuro","honeydew":"bianco germoglio","darkseagreen":"verde mare scuro","lightcoral":"rosa corallo","palevioletred":"vinaccia chiaro","mediumpurple":"porpora medio","saddlebrown":"cacao","darkmagenta":"magenta scuro","thistle":"rosa cenere","whitesmoke":"bianco fumo","wheat":"sabbia","violet":"viola","lightskyblue":"azzurro cielo chiaro","goldenrod":"ocra gialla","mediumblue":"blu medio","skyblue":"azzurro cielo","crimson":"cremisi","darksalmon":"salmone scuro","darkred":"rosso scuro","darkslategrey":"grigio ardesia scuro","peru":"marrone terra bruciata","lightgrey":"grigio chiaro","lightgoldenrodyellow":"giallo tenue","blanchedalmond":"mandorla chiaro","aliceblue":"blu alice","bisque":"incarnato","slategray":"grigio ardesia","palegoldenrod":"giallo zolfo chiaro","darkorange":"arancione scuro","aquamarine":"acquamarina","lightgreen":"verde chiaro","burlywood":"tabacco","dodgerblue":"blu d'oriente","darkgray":"grigio scuro","lightcyan":"ciano chiaro","powderblue":"azzurro polvere","blueviolet":"blu violetto","orchid":"orchidea","dimgray":"grigio 80%","beige":"beige","fuchsia":"fucsia","lavenderblush":"bianco rosato","hotpink":"rosa acceso","steelblue":"blu acciao","tomato":"pomodoro","lightpink":"rosa chiaro","limegreen":"verde lime","indianred":"terra indiana","papayawhip":"cipria","lightslategray":"grigio ardesia chiaro","gray":"grigio","mediumorchid":"orchidea medio","cornsilk":"crema","black":"nero","seagreen":"verde mare","darkslateblue":"blu ardesia scuro","khaki":"kaki","lightblue":"azzurro","palegreen":"verde pallido","azure":"azzurro ghiaccio","peachpuff":"pesca","darkolivegreen":"verde oliva scuro","yellowgreen":"giallo verde"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.it");dijit.nls.loading.it={"loadingState":"Caricamento in corso...","errorState":"Si è verificato un errore"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.it");dijit.nls.common.it={"buttonOk":"OK","buttonCancel":"Annulla","buttonSave":"Salva","itemClose":"Chiudi"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.it");dijit.form.nls.validate.it={"rangeMessage":"Questo valore non è compreso nell'intervallo.","invalidMessage":"Il valore immesso non è valido.","missingMessage":"Questo valore è obbligatorio."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.it");dijit.form.nls.ComboBox.it={"previousMessage":"Scelte precedenti","nextMessage":"Altre scelte"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.it");dojo.cldr.nls.number.it={"decimalFormat":"#,##0.###","group":".","scientificFormat":"#E0","percentFormat":"#,##0%","currencyFormat":"¤ #,##0.00","decimal":",","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"};
diff --git a/lib/dojo/nls/tt-rss-layer_ja-jp.js b/lib/dojo/nls/tt-rss-layer_ja-jp.js
new file mode 100644
index 000000000..84aa8786b
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_ja-jp.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_ja-jp");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.ja_jp");dojo.nls.colors.ja_jp={"lightsteelblue":"ライト・スチール・ブルー","orangered":"オレンジ・レッド","midnightblue":"ミッドナイト・ブルー","cadetblue":"くすんだ青","seashell":"シーシェル","slategrey":"スレート・グレイ","coral":"珊瑚","darkturquoise":"ダーク・ターコイズ","antiquewhite":"アンティーク・ホワイト","mediumspringgreen":"ミディアム・スプリング・グリーン","salmon":"サーモン","darkgrey":"ダーク・グレイ","ivory":"アイボリー","greenyellow":"緑黄色","mistyrose":"ミスティ・ローズ","lightsalmon":"ライト・サーモン","silver":"銀","dimgrey":"くすんだグレイ","orange":"オレンジ","white":"白","navajowhite":"ナバホ・ホワイト","royalblue":"藤色","deeppink":"濃いピンク","lime":"ライム","oldlace":"オールド・レイス","chartreuse":"淡黄緑","darkcyan":"ダーク・シアン・ブルー","yellow":"黄","linen":"亜麻色","olive":"オリーブ","gold":"金","lawngreen":"ローン・グリーン","lightyellow":"ライト・イエロー","tan":"茶褐色","darkviolet":"ダーク・バイオレット","lightslategrey":"ライト・スレート・グレイ","grey":"グレイ","darkkhaki":"ダーク・カーキー","green":"緑","deepskyblue":"濃い空色","aqua":"アクア","sienna":"黄褐色","mintcream":"ミント・クリーム","rosybrown":"ロージー・ブラウン","mediumslateblue":"ミディアム・スレート・ブルー","magenta":"赤紫","lightseagreen":"ライト・シー・グリーン","cyan":"シアン・ブルー","olivedrab":"濃黄緑","darkgoldenrod":"ダーク・ゴールデン・ロッド","slateblue":"スレート・ブルー","mediumaquamarine":"ミディアム・アクアマリーン","lavender":"ラベンダー","mediumseagreen":"ミディアム・シー・グリーン","maroon":"えび茶","darkslategray":"ダーク・スレート・グレイ","mediumturquoise":"ミディアム・ターコイズ","ghostwhite":"ゴースト・ホワイト","darkblue":"ダーク・ブルー","mediumvioletred":"ミディアム・バイオレット・レッド","brown":"茶","lightgray":"ライト・グレイ","sandybrown":"砂褐色","pink":"ピンク","firebrick":"赤煉瓦色","indigo":"藍色","snow":"雪色","darkorchid":"ダーク・オーキッド","turquoise":"ターコイズ","chocolate":"チョコレート","springgreen":"スプリング・グリーン","moccasin":"モカシン","navy":"濃紺","lemonchiffon":"レモン・シフォン","teal":"ティール","floralwhite":"フローラル・ホワイト","cornflowerblue":"コーンフラワー・ブルー","paleturquoise":"ペイル・ターコイズ","purple":"紫","gainsboro":"ゲインズボーロ","plum":"深紫","red":"赤","blue":"青","forestgreen":"フォレスト・グリーン","darkgreen":"ダーク・グリーン","honeydew":"ハニーデュー","darkseagreen":"ダーク・シー・グリーン","lightcoral":"ライト・コーラル","palevioletred":"ペイル・バイオレット・レッド","mediumpurple":"ミディアム・パープル","saddlebrown":"サドル・ブラウン","darkmagenta":"ダーク・マジェンタ","thistle":"シスル","whitesmoke":"ホワイト・スモーク","wheat":"小麦色","violet":"すみれ色","lightskyblue":"ライト・スカイ・ブルー","goldenrod":"ゴールデン・ロッド","mediumblue":"ミディアム・ブルー","skyblue":"スカイ・ブルー","crimson":"深紅","darksalmon":"ダーク・サーモン","darkred":"ダーク・レッド","darkslategrey":"ダーク・スレート・グレイ","peru":"ペルー","lightgrey":"ライト・グレイ","lightgoldenrodyellow":"ライト・ゴールデン・ロッド・イエロー","blanchedalmond":"皮なしアーモンド","aliceblue":"アリス・ブルー","bisque":"ビスク","slategray":"スレート・グレイ","palegoldenrod":"ペイル・ゴールデン・ロッド","darkorange":"ダーク・オレンジ","aquamarine":"碧緑","lightgreen":"ライト・グリーン","burlywood":"バーリーウッド","dodgerblue":"ドッジャー・ブルー","darkgray":"ダーク・グレイ","lightcyan":"ライト・シアン","powderblue":"淡青","blueviolet":"青紫","orchid":"薄紫","dimgray":"くすんだグレイ","beige":"ベージュ","fuchsia":"紫紅色","lavenderblush":"ラベンダー・ブラッシ","hotpink":"ホット・ピンク","steelblue":"鋼色","tomato":"トマト色","lightpink":"ライト・ピンク","limegreen":"ライム・グリーン","indianred":"インディアン・レッド","papayawhip":"パパイア・ホイップ","lightslategray":"ライト・スレート・グレイ","gray":"グレイ","mediumorchid":"ミディアム・オーキッド","cornsilk":"コーンシルク","black":"黒","seagreen":"シー・グリーン","darkslateblue":"ダーク・スレート・ブルー","khaki":"カーキー","lightblue":"ライト・ブルー","palegreen":"ペイル・グリーン","azure":"薄い空色","peachpuff":"ピーチ・パフ","darkolivegreen":"ダーク・オリーブ・グリーン","yellowgreen":"黄緑"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.ja_jp");dijit.nls.loading.ja_jp={"loadingState":"ロード中...","errorState":"エラーが発生しました。"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.ja_jp");dijit.nls.common.ja_jp={"buttonOk":"OK","buttonCancel":"キャンセル","buttonSave":"保存","itemClose":"閉じる"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.ja_jp");dijit.form.nls.validate.ja_jp={"rangeMessage":"この値は範囲外です。","invalidMessage":"入力した値は無効です。","missingMessage":"この値は必須です。"};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.ja_jp");dijit.form.nls.ComboBox.ja_jp={"previousMessage":"以前の選択項目","nextMessage":"追加の選択項目"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.ja_jp");dojo.cldr.nls.number.ja_jp={"decimalFormat":"#,##0.###","group":",","scientificFormat":"#E0","percentFormat":"#,##0%","currencyFormat":"¤#,##0.00","decimal":".","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"};
diff --git a/lib/dojo/nls/tt-rss-layer_ja.js b/lib/dojo/nls/tt-rss-layer_ja.js
new file mode 100644
index 000000000..d71241d29
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_ja.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_ja");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.ja");dojo.nls.colors.ja={"lightsteelblue":"ライト・スチール・ブルー","orangered":"オレンジ・レッド","midnightblue":"ミッドナイト・ブルー","cadetblue":"くすんだ青","seashell":"シーシェル","slategrey":"スレート・グレイ","coral":"珊瑚","darkturquoise":"ダーク・ターコイズ","antiquewhite":"アンティーク・ホワイト","mediumspringgreen":"ミディアム・スプリング・グリーン","salmon":"サーモン","darkgrey":"ダーク・グレイ","ivory":"アイボリー","greenyellow":"緑黄色","mistyrose":"ミスティ・ローズ","lightsalmon":"ライト・サーモン","silver":"銀","dimgrey":"くすんだグレイ","orange":"オレンジ","white":"白","navajowhite":"ナバホ・ホワイト","royalblue":"藤色","deeppink":"濃いピンク","lime":"ライム","oldlace":"オールド・レイス","chartreuse":"淡黄緑","darkcyan":"ダーク・シアン・ブルー","yellow":"黄","linen":"亜麻色","olive":"オリーブ","gold":"金","lawngreen":"ローン・グリーン","lightyellow":"ライト・イエロー","tan":"茶褐色","darkviolet":"ダーク・バイオレット","lightslategrey":"ライト・スレート・グレイ","grey":"グレイ","darkkhaki":"ダーク・カーキー","green":"緑","deepskyblue":"濃い空色","aqua":"アクア","sienna":"黄褐色","mintcream":"ミント・クリーム","rosybrown":"ロージー・ブラウン","mediumslateblue":"ミディアム・スレート・ブルー","magenta":"赤紫","lightseagreen":"ライト・シー・グリーン","cyan":"シアン・ブルー","olivedrab":"濃黄緑","darkgoldenrod":"ダーク・ゴールデン・ロッド","slateblue":"スレート・ブルー","mediumaquamarine":"ミディアム・アクアマリーン","lavender":"ラベンダー","mediumseagreen":"ミディアム・シー・グリーン","maroon":"えび茶","darkslategray":"ダーク・スレート・グレイ","mediumturquoise":"ミディアム・ターコイズ","ghostwhite":"ゴースト・ホワイト","darkblue":"ダーク・ブルー","mediumvioletred":"ミディアム・バイオレット・レッド","brown":"茶","lightgray":"ライト・グレイ","sandybrown":"砂褐色","pink":"ピンク","firebrick":"赤煉瓦色","indigo":"藍色","snow":"雪色","darkorchid":"ダーク・オーキッド","turquoise":"ターコイズ","chocolate":"チョコレート","springgreen":"スプリング・グリーン","moccasin":"モカシン","navy":"濃紺","lemonchiffon":"レモン・シフォン","teal":"ティール","floralwhite":"フローラル・ホワイト","cornflowerblue":"コーンフラワー・ブルー","paleturquoise":"ペイル・ターコイズ","purple":"紫","gainsboro":"ゲインズボーロ","plum":"深紫","red":"赤","blue":"青","forestgreen":"フォレスト・グリーン","darkgreen":"ダーク・グリーン","honeydew":"ハニーデュー","darkseagreen":"ダーク・シー・グリーン","lightcoral":"ライト・コーラル","palevioletred":"ペイル・バイオレット・レッド","mediumpurple":"ミディアム・パープル","saddlebrown":"サドル・ブラウン","darkmagenta":"ダーク・マジェンタ","thistle":"シスル","whitesmoke":"ホワイト・スモーク","wheat":"小麦色","violet":"すみれ色","lightskyblue":"ライト・スカイ・ブルー","goldenrod":"ゴールデン・ロッド","mediumblue":"ミディアム・ブルー","skyblue":"スカイ・ブルー","crimson":"深紅","darksalmon":"ダーク・サーモン","darkred":"ダーク・レッド","darkslategrey":"ダーク・スレート・グレイ","peru":"ペルー","lightgrey":"ライト・グレイ","lightgoldenrodyellow":"ライト・ゴールデン・ロッド・イエロー","blanchedalmond":"皮なしアーモンド","aliceblue":"アリス・ブルー","bisque":"ビスク","slategray":"スレート・グレイ","palegoldenrod":"ペイル・ゴールデン・ロッド","darkorange":"ダーク・オレンジ","aquamarine":"碧緑","lightgreen":"ライト・グリーン","burlywood":"バーリーウッド","dodgerblue":"ドッジャー・ブルー","darkgray":"ダーク・グレイ","lightcyan":"ライト・シアン","powderblue":"淡青","blueviolet":"青紫","orchid":"薄紫","dimgray":"くすんだグレイ","beige":"ベージュ","fuchsia":"紫紅色","lavenderblush":"ラベンダー・ブラッシ","hotpink":"ホット・ピンク","steelblue":"鋼色","tomato":"トマト色","lightpink":"ライト・ピンク","limegreen":"ライム・グリーン","indianred":"インディアン・レッド","papayawhip":"パパイア・ホイップ","lightslategray":"ライト・スレート・グレイ","gray":"グレイ","mediumorchid":"ミディアム・オーキッド","cornsilk":"コーンシルク","black":"黒","seagreen":"シー・グリーン","darkslateblue":"ダーク・スレート・ブルー","khaki":"カーキー","lightblue":"ライト・ブルー","palegreen":"ペイル・グリーン","azure":"薄い空色","peachpuff":"ピーチ・パフ","darkolivegreen":"ダーク・オリーブ・グリーン","yellowgreen":"黄緑"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.ja");dijit.nls.loading.ja={"loadingState":"ロード中...","errorState":"エラーが発生しました。"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.ja");dijit.nls.common.ja={"buttonOk":"OK","buttonCancel":"キャンセル","buttonSave":"保存","itemClose":"閉じる"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.ja");dijit.form.nls.validate.ja={"rangeMessage":"この値は範囲外です。","invalidMessage":"入力した値は無効です。","missingMessage":"この値は必須です。"};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.ja");dijit.form.nls.ComboBox.ja={"previousMessage":"以前の選択項目","nextMessage":"追加の選択項目"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.ja");dojo.cldr.nls.number.ja={"decimalFormat":"#,##0.###","group":",","scientificFormat":"#E0","percentFormat":"#,##0%","currencyFormat":"¤#,##0.00","decimal":".","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"};
diff --git a/lib/dojo/nls/tt-rss-layer_ko-kr.js b/lib/dojo/nls/tt-rss-layer_ko-kr.js
new file mode 100644
index 000000000..a79a5e02d
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_ko-kr.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_ko-kr");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.ko_kr");dojo.nls.colors.ko_kr={"lightsteelblue":"라이트 스틸 블루(light steel blue)","orangered":"오렌지 레드(orange red)","midnightblue":"미드나잇 블루(midnight blue)","cadetblue":"카뎃 블루(cadet blue)","seashell":"씨쉘(seashell)","slategrey":"슬레이트 그레이(slate gray)","coral":"코랄(coral)","darkturquoise":"다크 터콰즈(dark turquoise)","antiquewhite":"앤틱 화이트(antique white)","mediumspringgreen":"미디엄 스프링 그린(medium spring green)","salmon":"샐몬(salmon)","darkgrey":"다크 그레이(dark gray)","ivory":"아이보리(ivory)","greenyellow":"그린 옐로우(green-yellow)","mistyrose":"미스티 로즈(misty rose)","lightsalmon":"라이트 샐몬(light salmon)","silver":"실버(silver)","dimgrey":"딤 그레이(dim gray)","orange":"오렌지(orange)","white":"화이트(white)","navajowhite":"나바호 화이트(navajo white)","royalblue":"로얄 블루(royal blue)","deeppink":"딥 핑크(deep pink)","lime":"라임(lime)","oldlace":"올드 레이스(old lace)","chartreuse":"샤르트뢰즈(chartreuse)","darkcyan":"다크 시안(dark cyan)","yellow":"옐로우(yellow)","linen":"리넨(linen)","olive":"올리브(olive)","gold":"골드(gold)","lawngreen":"론 그린(lawn green)","lightyellow":"라이트 옐로우(light yellow)","tan":"탠(tan)","darkviolet":"다크 바이올렛(dark violet)","lightslategrey":"라이트 슬레이트 그레이(light slate gray)","grey":"그레이(gray)","darkkhaki":"다크 카키(dark khaki)","green":"그린(green)","deepskyblue":"딥 스카이 블루(deep sky blue)","aqua":"아쿠아(aqua)","sienna":"시에나(sienna)","mintcream":"민트 크림(mint cream)","rosybrown":"로지 브라운(rosy brown)","mediumslateblue":"미디엄 슬레이트 블루(medium slate blue)","magenta":"마젠타(magenta)","lightseagreen":"라이트 씨 그린(light sea green)","cyan":"시안(cyan)","olivedrab":"올리브 드랩(olive drab)","darkgoldenrod":"다크 골든로드(dark goldenrod)","slateblue":"슬레이트 블루(slate blue)","mediumaquamarine":"미디엄 아쿠아마린(medium aquamarine)","lavender":"라벤더(lavender)","mediumseagreen":"미디엄 씨 그린(medium sea green)","maroon":"마룬(maroon)","darkslategray":"다크 슬레이트 그레이(dark slate gray)","mediumturquoise":"미디엄 터콰즈(medium turquoise)","ghostwhite":"고스트 화이트(ghost white)","darkblue":"다크 블루(dark blue)","mediumvioletred":"미디엄 바이올렛 레드(medium violet-red)","brown":"브라운(brown)","lightgray":"라이트 그레이(light gray)","sandybrown":"샌디 브라운(sandy brown)","pink":"핑크(pink)","firebrick":"파이어 브릭(fire brick)","indigo":"인디고(indigo)","snow":"스노우(snow)","darkorchid":"다크 오키드(dark orchid)","turquoise":"터콰즈(turquoise)","chocolate":"초콜렛(chocolate)","springgreen":"스프링 그린(spring green)","moccasin":"모카신(moccasin)","navy":"네이비(navy)","lemonchiffon":"레몬 쉬폰(lemon chiffon)","teal":"틸(teal)","floralwhite":"플로랄 화이트(floral white)","cornflowerblue":"콘플라워 블루(cornflower blue)","paleturquoise":"페일 터콰즈(pale turquoise)","purple":"퍼플(purple)","gainsboro":"게인스브로(gainsboro)","plum":"플럼(plum)","red":"레드(red)","blue":"블루(blue)","forestgreen":"포레스트 그린(forest green)","darkgreen":"다크 그린(dark green)","honeydew":"허니듀(honeydew)","darkseagreen":"다크 씨 그린(dark sea green)","lightcoral":"라이트 코랄(light coral)","palevioletred":"페일 바이올렛 레드(pale violet-red)","mediumpurple":"미디엄 퍼플(medium purple)","saddlebrown":"새들 브라운(saddle brown)","darkmagenta":"다크 마젠타(dark magenta)","thistle":"시슬(thistle)","whitesmoke":"화이트 스모크(white smoke)","wheat":"휘트(wheat)","violet":"바이올렛(violet)","lightskyblue":"라이트 스카이 블루(light sky blue)","goldenrod":"골든로드(goldenrod)","mediumblue":"미디엄 블루(medium blue)","skyblue":"스카이 블루(sky blue)","crimson":"크림슨(crimson)","darksalmon":"다크 샐몬(dark salmon)","darkred":"다크 레드(dark red)","darkslategrey":"다크 슬레이트 그레이(dark slate gray)","peru":"페루(peru)","lightgrey":"라이트 그레이(light gray)","lightgoldenrodyellow":"라이트 골든로드 옐로우(light goldenrod yellow)","blanchedalmond":"블랜치 아몬드(blanched almond)","aliceblue":"앨리스 블루(alice blue)","bisque":"비스크(bisque)","slategray":"슬레이트 그레이(slate gray)","palegoldenrod":"페일 골든로드(pale goldenrod)","darkorange":"다크 오렌지(dark orange)","aquamarine":"아쿠아마린(aquamarine)","lightgreen":"라이트 그린(light green)","burlywood":"벌리우드(burlywood)","dodgerblue":"다저 블루(dodger blue)","darkgray":"다크 그레이(dark gray)","lightcyan":"라이트 시안(light cyan)","powderblue":"파우더 블루(powder blue)","blueviolet":"블루 바이올렛(blue-violet)","orchid":"오키드(orchid)","dimgray":"딤 그레이(dim gray)","beige":"베이지(beige)","fuchsia":"후크샤(fuchsia)","lavenderblush":"라벤더 블러쉬(lavender blush)","hotpink":"핫 핑크(hot pink)","steelblue":"스틸 블루(steel blue)","tomato":"토마토(tomato)","lightpink":"라이트 핑크(light pink)","limegreen":"라임 그린(lime green)","indianred":"인디안 레드(indian red)","papayawhip":"파파야 휩(papaya whip)","lightslategray":"라이트 슬레이트 그레이(light slate gray)","gray":"그레이(gray)","mediumorchid":"미디엄 오키드(medium orchid)","cornsilk":"콘실크(cornsilk)","black":"블랙(black)","seagreen":"씨 그린(sea green)","darkslateblue":"다크 슬레이트 블루(dark slate blue)","khaki":"카키(khaki)","lightblue":"라이트 블루(light blue)","palegreen":"페일 그린(pale green)","azure":"애쥬어(azure)","peachpuff":"피치 퍼프(peach puff)","darkolivegreen":"다크 올리브 그린(dark olive green)","yellowgreen":"옐로우 그린(yellow green)"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.ko_kr");dijit.nls.loading.ko_kr={"loadingState":"로드 중...","errorState":"죄송합니다. 오류가 발생했습니다."};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.ko_kr");dijit.nls.common.ko_kr={"buttonOk":"확인","buttonCancel":"취소","buttonSave":"저장","itemClose":"닫기"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.ko_kr");dijit.form.nls.validate.ko_kr={"rangeMessage":"이 값은 범위를 벗어납니다.","invalidMessage":"입력된 값이 올바르지 않습니다.","missingMessage":"이 값은 필수입니다."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.ko_kr");dijit.form.nls.ComboBox.ko_kr={"previousMessage":"이전 선택사항","nextMessage":"기타 선택사항"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.ko_kr");dojo.cldr.nls.number.ko_kr={"group":",","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":".","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"¤#,##0.00","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_ko.js b/lib/dojo/nls/tt-rss-layer_ko.js
new file mode 100644
index 000000000..da86270d5
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_ko.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_ko");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.ko");dojo.nls.colors.ko={"lightsteelblue":"라이트 스틸 블루(light steel blue)","orangered":"오렌지 레드(orange red)","midnightblue":"미드나잇 블루(midnight blue)","cadetblue":"카뎃 블루(cadet blue)","seashell":"씨쉘(seashell)","slategrey":"슬레이트 그레이(slate gray)","coral":"코랄(coral)","darkturquoise":"다크 터콰즈(dark turquoise)","antiquewhite":"앤틱 화이트(antique white)","mediumspringgreen":"미디엄 스프링 그린(medium spring green)","salmon":"샐몬(salmon)","darkgrey":"다크 그레이(dark gray)","ivory":"아이보리(ivory)","greenyellow":"그린 옐로우(green-yellow)","mistyrose":"미스티 로즈(misty rose)","lightsalmon":"라이트 샐몬(light salmon)","silver":"실버(silver)","dimgrey":"딤 그레이(dim gray)","orange":"오렌지(orange)","white":"화이트(white)","navajowhite":"나바호 화이트(navajo white)","royalblue":"로얄 블루(royal blue)","deeppink":"딥 핑크(deep pink)","lime":"라임(lime)","oldlace":"올드 레이스(old lace)","chartreuse":"샤르트뢰즈(chartreuse)","darkcyan":"다크 시안(dark cyan)","yellow":"옐로우(yellow)","linen":"리넨(linen)","olive":"올리브(olive)","gold":"골드(gold)","lawngreen":"론 그린(lawn green)","lightyellow":"라이트 옐로우(light yellow)","tan":"탠(tan)","darkviolet":"다크 바이올렛(dark violet)","lightslategrey":"라이트 슬레이트 그레이(light slate gray)","grey":"그레이(gray)","darkkhaki":"다크 카키(dark khaki)","green":"그린(green)","deepskyblue":"딥 스카이 블루(deep sky blue)","aqua":"아쿠아(aqua)","sienna":"시에나(sienna)","mintcream":"민트 크림(mint cream)","rosybrown":"로지 브라운(rosy brown)","mediumslateblue":"미디엄 슬레이트 블루(medium slate blue)","magenta":"마젠타(magenta)","lightseagreen":"라이트 씨 그린(light sea green)","cyan":"시안(cyan)","olivedrab":"올리브 드랩(olive drab)","darkgoldenrod":"다크 골든로드(dark goldenrod)","slateblue":"슬레이트 블루(slate blue)","mediumaquamarine":"미디엄 아쿠아마린(medium aquamarine)","lavender":"라벤더(lavender)","mediumseagreen":"미디엄 씨 그린(medium sea green)","maroon":"마룬(maroon)","darkslategray":"다크 슬레이트 그레이(dark slate gray)","mediumturquoise":"미디엄 터콰즈(medium turquoise)","ghostwhite":"고스트 화이트(ghost white)","darkblue":"다크 블루(dark blue)","mediumvioletred":"미디엄 바이올렛 레드(medium violet-red)","brown":"브라운(brown)","lightgray":"라이트 그레이(light gray)","sandybrown":"샌디 브라운(sandy brown)","pink":"핑크(pink)","firebrick":"파이어 브릭(fire brick)","indigo":"인디고(indigo)","snow":"스노우(snow)","darkorchid":"다크 오키드(dark orchid)","turquoise":"터콰즈(turquoise)","chocolate":"초콜렛(chocolate)","springgreen":"스프링 그린(spring green)","moccasin":"모카신(moccasin)","navy":"네이비(navy)","lemonchiffon":"레몬 쉬폰(lemon chiffon)","teal":"틸(teal)","floralwhite":"플로랄 화이트(floral white)","cornflowerblue":"콘플라워 블루(cornflower blue)","paleturquoise":"페일 터콰즈(pale turquoise)","purple":"퍼플(purple)","gainsboro":"게인스브로(gainsboro)","plum":"플럼(plum)","red":"레드(red)","blue":"블루(blue)","forestgreen":"포레스트 그린(forest green)","darkgreen":"다크 그린(dark green)","honeydew":"허니듀(honeydew)","darkseagreen":"다크 씨 그린(dark sea green)","lightcoral":"라이트 코랄(light coral)","palevioletred":"페일 바이올렛 레드(pale violet-red)","mediumpurple":"미디엄 퍼플(medium purple)","saddlebrown":"새들 브라운(saddle brown)","darkmagenta":"다크 마젠타(dark magenta)","thistle":"시슬(thistle)","whitesmoke":"화이트 스모크(white smoke)","wheat":"휘트(wheat)","violet":"바이올렛(violet)","lightskyblue":"라이트 스카이 블루(light sky blue)","goldenrod":"골든로드(goldenrod)","mediumblue":"미디엄 블루(medium blue)","skyblue":"스카이 블루(sky blue)","crimson":"크림슨(crimson)","darksalmon":"다크 샐몬(dark salmon)","darkred":"다크 레드(dark red)","darkslategrey":"다크 슬레이트 그레이(dark slate gray)","peru":"페루(peru)","lightgrey":"라이트 그레이(light gray)","lightgoldenrodyellow":"라이트 골든로드 옐로우(light goldenrod yellow)","blanchedalmond":"블랜치 아몬드(blanched almond)","aliceblue":"앨리스 블루(alice blue)","bisque":"비스크(bisque)","slategray":"슬레이트 그레이(slate gray)","palegoldenrod":"페일 골든로드(pale goldenrod)","darkorange":"다크 오렌지(dark orange)","aquamarine":"아쿠아마린(aquamarine)","lightgreen":"라이트 그린(light green)","burlywood":"벌리우드(burlywood)","dodgerblue":"다저 블루(dodger blue)","darkgray":"다크 그레이(dark gray)","lightcyan":"라이트 시안(light cyan)","powderblue":"파우더 블루(powder blue)","blueviolet":"블루 바이올렛(blue-violet)","orchid":"오키드(orchid)","dimgray":"딤 그레이(dim gray)","beige":"베이지(beige)","fuchsia":"후크샤(fuchsia)","lavenderblush":"라벤더 블러쉬(lavender blush)","hotpink":"핫 핑크(hot pink)","steelblue":"스틸 블루(steel blue)","tomato":"토마토(tomato)","lightpink":"라이트 핑크(light pink)","limegreen":"라임 그린(lime green)","indianred":"인디안 레드(indian red)","papayawhip":"파파야 휩(papaya whip)","lightslategray":"라이트 슬레이트 그레이(light slate gray)","gray":"그레이(gray)","mediumorchid":"미디엄 오키드(medium orchid)","cornsilk":"콘실크(cornsilk)","black":"블랙(black)","seagreen":"씨 그린(sea green)","darkslateblue":"다크 슬레이트 블루(dark slate blue)","khaki":"카키(khaki)","lightblue":"라이트 블루(light blue)","palegreen":"페일 그린(pale green)","azure":"애쥬어(azure)","peachpuff":"피치 퍼프(peach puff)","darkolivegreen":"다크 올리브 그린(dark olive green)","yellowgreen":"옐로우 그린(yellow green)"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.ko");dijit.nls.loading.ko={"loadingState":"로드 중...","errorState":"죄송합니다. 오류가 발생했습니다."};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.ko");dijit.nls.common.ko={"buttonOk":"확인","buttonCancel":"취소","buttonSave":"저장","itemClose":"닫기"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.ko");dijit.form.nls.validate.ko={"rangeMessage":"이 값은 범위를 벗어납니다.","invalidMessage":"입력된 값이 올바르지 않습니다.","missingMessage":"이 값은 필수입니다."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.ko");dijit.form.nls.ComboBox.ko={"previousMessage":"이전 선택사항","nextMessage":"기타 선택사항"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.ko");dojo.cldr.nls.number.ko={"group":",","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":".","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"¤#,##0.00","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_nb.js b/lib/dojo/nls/tt-rss-layer_nb.js
new file mode 100644
index 000000000..c6ca50890
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_nb.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_nb");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.nb");dojo.nls.colors.nb={"lightsteelblue":"lys stålblå","orangered":"rødoransje","midnightblue":"midnattsblå","cadetblue":"mørk grønnblå","seashell":"skjellhvit","slategrey":"skifergrå","coral":"korall","darkturquoise":"mørk turkis","antiquewhite":"antikk hvit","mediumspringgreen":"middels vårgrønn","salmon":"lakserosa","darkgrey":"mørk grå","ivory":"elfenbenshvit","greenyellow":"gulgrønn","mistyrose":"lys rosenrød","lightsalmon":"lys lakserosa","silver":"sølvfarget","dimgrey":"mørk mørkegrå","orange":"oransje","white":"hvit","navajowhite":"gulbrun","royalblue":"kongeblå","deeppink":"dyp rosa","lime":"lime","oldlace":"kniplingshvit","chartreuse":"løvgrønn","darkcyan":"mørk cyan","yellow":"gul","linen":"lin","olive":"oliven","gold":"gull","lawngreen":"plengrønn","lightyellow":"lys gul","tan":"matt mellombrun","darkviolet":"mørk fiolett","lightslategrey":"lys skifergrå","grey":"grå","darkkhaki":"mørk khaki","green":"grønn","deepskyblue":"dyp himmelblå","aqua":"akva","sienna":"nøttebrun","mintcream":"mintkrem","rosybrown":"brunlilla","mediumslateblue":"middels skiferblå","magenta":"magenta","lightseagreen":"lys sjøgrønn","cyan":"cyan","olivedrab":"middels olivengrønn","darkgoldenrod":"mørk gyldenris","slateblue":"skiferblå","mediumaquamarine":"middels akvamarin","lavender":"lavendel","mediumseagreen":"middels sjøgrønn","maroon":"rødbrun","darkslategray":"mørk skifergrå","mediumturquoise":"middels turkis","ghostwhite":"egghvit","darkblue":"mørk blå","mediumvioletred":"middels fiolettrød","brown":"brun","lightgray":"lys grå","sandybrown":"sandbrun","pink":"rosa","firebrick":"mursteinsrød","indigo":"indigo","snow":"snøhvit","darkorchid":"mørk orkide","turquoise":"turkis","chocolate":"sjokolade","springgreen":"vårgrønn","moccasin":"lys gulbrun","navy":"marineblå","lemonchiffon":"ferskenfarget","teal":"mørk grønnblå","floralwhite":"blomsterhvit","cornflowerblue":"kornblå","paleturquoise":"svak turkis","purple":"purpur","gainsboro":"lys lys grå","plum":"plommefarget","red":"rød","blue":"blå","forestgreen":"skoggrønn","darkgreen":"mørk grønn","honeydew":"grønnhvit","darkseagreen":"mørk sjøgrønn","lightcoral":"lys korall","palevioletred":"svak fiolettrød","mediumpurple":"middels purpur","saddlebrown":"mørk nøttebrun","darkmagenta":"mørk magenta","thistle":"lys grålilla","whitesmoke":"røykhvit","wheat":"varm sienna","violet":"fiolett","lightskyblue":"lys himmelblå","goldenrod":"gyldenris","mediumblue":"mellomblå","skyblue":"himmelblå","crimson":"karmosinrødt","darksalmon":"mørk lakserosa","darkred":"mørk rød","darkslategrey":"mørk skifergrå","peru":"lys nøttebrun","lightgrey":"lys grå","lightgoldenrodyellow":"lys gyldenrisgul","blanchedalmond":"lys mandel","aliceblue":"blåhvit","bisque":"gulrosa","slategray":"skifergrå","palegoldenrod":"svak gyldenris","darkorange":"mørk oransje","aquamarine":"akvamarin","lightgreen":"lys grønn","burlywood":"matt mellombrun","dodgerblue":"lys havblå","darkgray":"mørk grå","lightcyan":"lys cyan","powderblue":"lys grønnblå","blueviolet":"blåfiolett","orchid":"orkide","dimgray":"mørk mørkegrå","beige":"beige","fuchsia":"fuksia","lavenderblush":"lillahvit","hotpink":"halvmørk rosa","steelblue":"stålblå","tomato":"tomatrød","lightpink":"lys rosa","limegreen":"limegrønn","indianred":"rustrød","papayawhip":"lys papaya","lightslategray":"lys skifergrå","gray":"grå","mediumorchid":"middels orkide","cornsilk":"cornsilk","black":"svart","seagreen":"sjøgrønn","darkslateblue":"mørk skiferblå","khaki":"khaki","lightblue":"lys blå","palegreen":"svak grønn","azure":"asur","peachpuff":"brunrosa","darkolivegreen":"mørk olivengrønn","yellowgreen":"gulgrønn"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.nb");dijit.nls.loading.nb={"loadingState":"Laster inn...","errorState":"Det oppsto en feil"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.nb");dijit.nls.common.nb={"buttonOk":"OK","buttonCancel":"Avbryt","buttonSave":"Lagre","itemClose":"Lukk"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.nb");dijit.form.nls.validate.nb={"rangeMessage":"Denne verdien er utenfor gyldig område.","invalidMessage":"Den angitte verdien er ikke gyldig.","missingMessage":"Denne verdien er obligatorisk."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.nb");dijit.form.nls.ComboBox.nb={"previousMessage":"Tidligere valg","nextMessage":"Flere valg"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.nb");dojo.cldr.nls.number.nb={"group":" ","percentSign":"%","exponential":"E","percentFormat":"#,##0 %","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"¤ #,##0.00","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_nl-nl.js b/lib/dojo/nls/tt-rss-layer_nl-nl.js
new file mode 100644
index 000000000..bbafa6a2f
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_nl-nl.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_nl-nl");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.nl_nl");dojo.nls.colors.nl_nl={"lightsteelblue":"lichtstaalblauw","orangered":"oranjerood","midnightblue":"nachtblauw","cadetblue":"donkerstaalblauw","seashell":"schelp","slategrey":"leigrijs","coral":"koraalrood","darkturquoise":"donkerturquoise","antiquewhite":"antiekwit","mediumspringgreen":"midlentegroen","salmon":"zalm","darkgrey":"donkergrijs","ivory":"ivoorwit","greenyellow":"groengeel","mistyrose":"matroze","lightsalmon":"lichtzalm","silver":"zilvergrijs","dimgrey":"dofgrijs","orange":"oranje","white":"wit","navajowhite":"navajowit","royalblue":"koningsblauw","deeppink":"donkerroze","lime":"limoen","oldlace":"kant","chartreuse":"groengeel","darkcyan":"donkercyaan","yellow":"geel","linen":"linnen","olive":"olijfgroen","gold":"goud","lawngreen":"grasgroen","lightyellow":"lichtgeel","tan":"geelbruin","darkviolet":"donkerviolet","lightslategrey":"lichtblauwgrijs","grey":"grijs","darkkhaki":"donkerkaki","green":"groen","deepskyblue":"diephemelblauw","aqua":"aqua","sienna":"sienna","mintcream":"mintroomgeel","rosybrown":"roodbruin","mediumslateblue":"midgrijsblauw","magenta":"magenta","lightseagreen":"lichtzeegroen","cyan":"cyaan","olivedrab":"grijsbruin","darkgoldenrod":"donkergoud","slateblue":"leiblauw","mediumaquamarine":"midaquamarijn","lavender":"lavendelblauw","mediumseagreen":"midzeegroen","maroon":"kastanjebruin","darkslategray":"donkerblauwgrijs","mediumturquoise":"midturquoise","ghostwhite":"spierwit","darkblue":"donkerblauw","mediumvioletred":"midvioletrood","brown":"bruin","lightgray":"lichtgrijs","sandybrown":"zandbruin","pink":"roze","firebrick":"vuursteenrood","indigo":"indigo","snow":"sneeuwwit","darkorchid":"donkerorchidee","turquoise":"turquoise","chocolate":"chocoladebruin","springgreen":"lentegroen","moccasin":"moccasin","navy":"marineblauw","lemonchiffon":"citroengeel","teal":"grijsblauw","floralwhite":"rozewit","cornflowerblue":"korenbloemblauw","paleturquoise":"bleekturquoise","purple":"purper","gainsboro":"lichtblauwgrijs","plum":"pruim","red":"rood","blue":"blauw","forestgreen":"bosgroen","darkgreen":"donkergroen","honeydew":"meloen","darkseagreen":"donkerzeegroen","lightcoral":"lichtkoraal","palevioletred":"bleekvioletrood","mediumpurple":"midpurper","saddlebrown":"leerbruin","darkmagenta":"donkermagenta","thistle":"distel","whitesmoke":"rookwit","wheat":"tarwebruin","violet":"violet","lightskyblue":"lichthemelsblauw","goldenrod":"goudbruin","mediumblue":"midblauw","skyblue":"hemelsblauw","crimson":"karmozijnrood","darksalmon":"donkerzalm","darkred":"donkerrood","darkslategrey":"donkerblauwgrijs","peru":"bruin","lightgrey":"lichtgrijs","lightgoldenrodyellow":"lichtgoudgeel","blanchedalmond":"amandel","aliceblue":"lichtblauw","bisque":"oranjegeel","slategray":"leigrijs","palegoldenrod":"bleekgeel","darkorange":"donkeroranje","aquamarine":"aquamarijn","lightgreen":"lichtgroen","burlywood":"lichtbruin","dodgerblue":"helderblauw","darkgray":"donkergrijs","lightcyan":"lichtcyaan","powderblue":"lichtblauw-wit","blueviolet":"violet","orchid":"orchidee","dimgray":"dofgrijs","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavendelblos","hotpink":"acaciaroze","steelblue":"staalblauw","tomato":"tomaat","lightpink":"lichtroze","limegreen":"limoengroen","indianred":"indisch rood","papayawhip":"papajaroze","lightslategray":"lichtblauwgrijs","gray":"grijs","mediumorchid":"midorchidee","cornsilk":"maïsgeel","black":"zwart","seagreen":"zeegroen","darkslateblue":"donkergrijsblauw","khaki":"kaki","lightblue":"lichtblauw","palegreen":"bleekgroen","azure":"azuur","peachpuff":"perzikroze","darkolivegreen":"donkerolijfgroen","yellowgreen":"geelgroen"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.nl_nl");dijit.nls.loading.nl_nl={"loadingState":"Bezig met laden...","errorState":"Er is een fout opgetreden"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.nl_nl");dijit.nls.common.nl_nl={"buttonOk":"OK","buttonCancel":"Annuleren","buttonSave":"Opslaan","itemClose":"Sluiten"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.nl_nl");dijit.form.nls.validate.nl_nl={"rangeMessage":"Deze waarde is niet toegestaan.","invalidMessage":"De opgegeven waarde is ongeldig.","missingMessage":"Deze waarde is verplicht."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.nl_nl");dijit.form.nls.ComboBox.nl_nl={"previousMessage":"Eerdere opties","nextMessage":"Meer opties"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.nl_nl");dojo.cldr.nls.number.nl_nl={"group":".","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"¤ #,##0.00;¤ #,##0.00-","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_nl.js b/lib/dojo/nls/tt-rss-layer_nl.js
new file mode 100644
index 000000000..4ba9f5ee4
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_nl.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_nl");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.nl");dojo.nls.colors.nl={"lightsteelblue":"lichtstaalblauw","orangered":"oranjerood","midnightblue":"nachtblauw","cadetblue":"donkerstaalblauw","seashell":"schelp","slategrey":"leigrijs","coral":"koraalrood","darkturquoise":"donkerturquoise","antiquewhite":"antiekwit","mediumspringgreen":"midlentegroen","salmon":"zalm","darkgrey":"donkergrijs","ivory":"ivoorwit","greenyellow":"groengeel","mistyrose":"matroze","lightsalmon":"lichtzalm","silver":"zilvergrijs","dimgrey":"dofgrijs","orange":"oranje","white":"wit","navajowhite":"navajowit","royalblue":"koningsblauw","deeppink":"donkerroze","lime":"limoen","oldlace":"kant","chartreuse":"groengeel","darkcyan":"donkercyaan","yellow":"geel","linen":"linnen","olive":"olijfgroen","gold":"goud","lawngreen":"grasgroen","lightyellow":"lichtgeel","tan":"geelbruin","darkviolet":"donkerviolet","lightslategrey":"lichtblauwgrijs","grey":"grijs","darkkhaki":"donkerkaki","green":"groen","deepskyblue":"diephemelblauw","aqua":"aqua","sienna":"sienna","mintcream":"mintroomgeel","rosybrown":"roodbruin","mediumslateblue":"midgrijsblauw","magenta":"magenta","lightseagreen":"lichtzeegroen","cyan":"cyaan","olivedrab":"grijsbruin","darkgoldenrod":"donkergoud","slateblue":"leiblauw","mediumaquamarine":"midaquamarijn","lavender":"lavendelblauw","mediumseagreen":"midzeegroen","maroon":"kastanjebruin","darkslategray":"donkerblauwgrijs","mediumturquoise":"midturquoise","ghostwhite":"spierwit","darkblue":"donkerblauw","mediumvioletred":"midvioletrood","brown":"bruin","lightgray":"lichtgrijs","sandybrown":"zandbruin","pink":"roze","firebrick":"vuursteenrood","indigo":"indigo","snow":"sneeuwwit","darkorchid":"donkerorchidee","turquoise":"turquoise","chocolate":"chocoladebruin","springgreen":"lentegroen","moccasin":"moccasin","navy":"marineblauw","lemonchiffon":"citroengeel","teal":"grijsblauw","floralwhite":"rozewit","cornflowerblue":"korenbloemblauw","paleturquoise":"bleekturquoise","purple":"purper","gainsboro":"lichtblauwgrijs","plum":"pruim","red":"rood","blue":"blauw","forestgreen":"bosgroen","darkgreen":"donkergroen","honeydew":"meloen","darkseagreen":"donkerzeegroen","lightcoral":"lichtkoraal","palevioletred":"bleekvioletrood","mediumpurple":"midpurper","saddlebrown":"leerbruin","darkmagenta":"donkermagenta","thistle":"distel","whitesmoke":"rookwit","wheat":"tarwebruin","violet":"violet","lightskyblue":"lichthemelsblauw","goldenrod":"goudbruin","mediumblue":"midblauw","skyblue":"hemelsblauw","crimson":"karmozijnrood","darksalmon":"donkerzalm","darkred":"donkerrood","darkslategrey":"donkerblauwgrijs","peru":"bruin","lightgrey":"lichtgrijs","lightgoldenrodyellow":"lichtgoudgeel","blanchedalmond":"amandel","aliceblue":"lichtblauw","bisque":"oranjegeel","slategray":"leigrijs","palegoldenrod":"bleekgeel","darkorange":"donkeroranje","aquamarine":"aquamarijn","lightgreen":"lichtgroen","burlywood":"lichtbruin","dodgerblue":"helderblauw","darkgray":"donkergrijs","lightcyan":"lichtcyaan","powderblue":"lichtblauw-wit","blueviolet":"violet","orchid":"orchidee","dimgray":"dofgrijs","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavendelblos","hotpink":"acaciaroze","steelblue":"staalblauw","tomato":"tomaat","lightpink":"lichtroze","limegreen":"limoengroen","indianred":"indisch rood","papayawhip":"papajaroze","lightslategray":"lichtblauwgrijs","gray":"grijs","mediumorchid":"midorchidee","cornsilk":"maïsgeel","black":"zwart","seagreen":"zeegroen","darkslateblue":"donkergrijsblauw","khaki":"kaki","lightblue":"lichtblauw","palegreen":"bleekgroen","azure":"azuur","peachpuff":"perzikroze","darkolivegreen":"donkerolijfgroen","yellowgreen":"geelgroen"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.nl");dijit.nls.loading.nl={"loadingState":"Bezig met laden...","errorState":"Er is een fout opgetreden"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.nl");dijit.nls.common.nl={"buttonOk":"OK","buttonCancel":"Annuleren","buttonSave":"Opslaan","itemClose":"Sluiten"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.nl");dijit.form.nls.validate.nl={"rangeMessage":"Deze waarde is niet toegestaan.","invalidMessage":"De opgegeven waarde is ongeldig.","missingMessage":"Deze waarde is verplicht."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.nl");dijit.form.nls.ComboBox.nl={"previousMessage":"Eerdere opties","nextMessage":"Meer opties"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.nl");dojo.cldr.nls.number.nl={"group":".","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"¤ #,##0.00;¤ #,##0.00-","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_pl.js b/lib/dojo/nls/tt-rss-layer_pl.js
new file mode 100644
index 000000000..d69dca84c
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_pl.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_pl");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.pl");dojo.nls.colors.pl={"lightsteelblue":"jasny stalowoniebieski","orangered":"pomarańczowoczerwony","midnightblue":"ciemnogranatowy","cadetblue":"niebieskoszary","seashell":"muszla","slategrey":"łupkowy szary","coral":"koralowy","darkturquoise":"ciemnoturkusowy","antiquewhite":"biel antyczna","mediumspringgreen":"średnia wiosenna zieleń","salmon":"łososiowy","darkgrey":"ciemnoszary","ivory":"kość słoniowa","greenyellow":"zielonożółty","mistyrose":"bladoróżany","lightsalmon":"jasnołososiowy","silver":"srebrny","dimgrey":"przytłumiony szary","orange":"pomarańczowy","white":"biały","navajowhite":"piaskowy","royalblue":"błękit królewski","deeppink":"głęboki różowy","lime":"limetkowy","oldlace":"bladopomarańczowy","chartreuse":"jaskrawozielony","darkcyan":"ciemny cyjan","yellow":"żółty","linen":"lniany","olive":"oliwkowy","gold":"złoty","lawngreen":"trawiasty","lightyellow":"jasnożółty","tan":"kawowy","darkviolet":"ciemnofioletowy","lightslategrey":"jasny łupkowy szary","grey":"szary","darkkhaki":"ciemny khaki","green":"zielony","deepskyblue":"intensywny błękit nieba","aqua":"wodny","sienna":"siena","mintcream":"jasnomiętowy","rosybrown":"różowobrązowy","mediumslateblue":"średni łupkowy niebieski","magenta":"magenta","lightseagreen":"jasna morska zieleń","cyan":"cyjan","olivedrab":"oliwkowa zieleń","darkgoldenrod":"ciemnogliniany","slateblue":"łupkowy niebieski","mediumaquamarine":"średnia akwamaryna","lavender":"lawendowy","mediumseagreen":"średnia morska zieleń","maroon":"bordowy","darkslategray":"ciemny łupkowy szary","mediumturquoise":"średni turkusowy","ghostwhite":"bladobiały","darkblue":"ciemnoniebieski","mediumvioletred":"średni fioletowoczerwony","brown":"brązowy","lightgray":"jasnoszary","sandybrown":"piaskowy brąz","pink":"różowy","firebrick":"ceglasty","indigo":"indygo","snow":"śnieżny","darkorchid":"ciemna orchidea","turquoise":"turkusowy","chocolate":"czekoladowy","springgreen":"wiosenna zieleń","moccasin":"mokasynowy","navy":"granatowy","lemonchiffon":"cytrynowy","teal":"cyrankowy","floralwhite":"kwiatowa biel","cornflowerblue":"chabrowy","paleturquoise":"bladoturkusowy","purple":"purpurowy","gainsboro":"bladoszary","plum":"śliwkowy","red":"czerwony","blue":"niebieski","forestgreen":"leśna zieleń","darkgreen":"ciemnozielony","honeydew":"melon","darkseagreen":"ciemna morska zieleń","lightcoral":"jasnokoralowy","palevioletred":"blady fioletowoczerwony","mediumpurple":"średnia purpura","saddlebrown":"skórzany brązowy","darkmagenta":"ciemna magenta","thistle":"bladofioletowy","whitesmoke":"przydymiony biały","wheat":"pszeniczny","violet":"fioletowy","lightskyblue":"jasny błękit nieba","goldenrod":"gliniany","mediumblue":"średni niebieski","skyblue":"błękit nieba","crimson":"karmazynowy","darksalmon":"ciemnołososiowy","darkred":"ciemnoczerwony","darkslategrey":"ciemny łupkowy szary","peru":"jasnobrązowy","lightgrey":"jasnoszary","lightgoldenrodyellow":"jasnogliniana żółć","blanchedalmond":"migdałowy","aliceblue":"bladoniebieski","bisque":"biszkoptowy","slategray":"łupkowy szary","palegoldenrod":"bladogliniany","darkorange":"ciemnopomarańczowy","aquamarine":"akwamaryna","lightgreen":"jasnozielony","burlywood":"kolor drewna","dodgerblue":"błękit Dodgers","darkgray":"ciemnoszary","lightcyan":"jasny cyjan","powderblue":"pudrowy niebieski","blueviolet":"niebieskofioletowy","orchid":"orchidea","dimgray":"przytłumiony szary","beige":"beżowy","fuchsia":"fuksja","lavenderblush":"lawendoworóżowy","hotpink":"intensywny różowy","steelblue":"stalowy niebieski","tomato":"pomidorowy","lightpink":"jasnoróżowy","limegreen":"limetkowozielony","indianred":"kasztanowy","papayawhip":"papaja","lightslategray":"jasny łupkowy szary","gray":"szary","mediumorchid":"średnia orchidea","cornsilk":"kukurydziany","black":"czarny","seagreen":"morska zieleń","darkslateblue":"ciemny łupkowy niebieski","khaki":"khaki","lightblue":"jasnoniebieski","palegreen":"bladozielony","azure":"lazur","peachpuff":"brzoskwiniowy","darkolivegreen":"ciemnooliwkowy","yellowgreen":"żółtozielony"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.pl");dijit.nls.loading.pl={"loadingState":"Ładowanie...","errorState":"Niestety, wystąpił błąd"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.pl");dijit.nls.common.pl={"buttonOk":"OK","buttonCancel":"Anuluj","buttonSave":"Zapisz","itemClose":"Zamknij"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.pl");dijit.form.nls.validate.pl={"rangeMessage":"Ta wartość jest spoza zakresu.","invalidMessage":"Wprowadzona wartość jest niepoprawna.","missingMessage":"Ta wartość jest wymagana."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.pl");dijit.form.nls.ComboBox.pl={"previousMessage":"Poprzednie wybory","nextMessage":"Więcej wyborów"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.pl");dojo.cldr.nls.number.pl={"group":" ","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_pt-br.js b/lib/dojo/nls/tt-rss-layer_pt-br.js
new file mode 100644
index 000000000..a35c5bb52
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_pt-br.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_pt-br");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.pt_br");dojo.nls.colors.pt_br={"lightsteelblue":"azul-aço claro","orangered":"vermelho alaranjado","midnightblue":"azul meia-noite","cadetblue":"azul cadet","seashell":"seashell","slategrey":"cinza-ardósia","coral":"coral","darkturquoise":"turquesa escuro","antiquewhite":"branco antigo","mediumspringgreen":"verde-primavera médio","salmon":"salmão","darkgrey":"cinza escuro","ivory":"marfim","greenyellow":"amarelo esverdeado","mistyrose":"rosa enevoado","lightsalmon":"salmão claro","silver":"prateado","dimgrey":"cinza turvo","orange":"laranja","white":"branco","navajowhite":"branco navajo","royalblue":"azul royal","deeppink":"rosa profundo","lime":"lima","oldlace":"cadarço velho","chartreuse":"chartreuse","darkcyan":"ciano escuro","yellow":"amarelo","linen":"linho","olive":"oliva","gold":"dourado","lawngreen":"verde grama","lightyellow":"amarelo claro","tan":"tan","darkviolet":"violeta escuro","lightslategrey":"cinza-ardósia claro","grey":"cinza","darkkhaki":"cáqui escuro","green":"verde","deepskyblue":"azul-céu intenso","aqua":"aqua","sienna":"sienna","mintcream":"creme de menta","rosybrown":"marrom rosado","mediumslateblue":"azul-ardósia médio","magenta":"magenta","lightseagreen":"verde marinho claro","cyan":"ciano","olivedrab":"verde oliva","darkgoldenrod":"goldenrod escuro","slateblue":"azul-ardósia","mediumaquamarine":"água-marinha médio","lavender":"lavanda","mediumseagreen":"verde-marinho médio","maroon":"marrom","darkslategray":"cinza-ardósia escuro","mediumturquoise":"turquesa médio","ghostwhite":"branco ghost","darkblue":"azul escuro","mediumvioletred":"vermelho-violeta médio","brown":"marrom","lightgray":"cinza claro","sandybrown":"marrom cor de areia","pink":"rosa","firebrick":"firebrick","indigo":"índigo","snow":"branco neve","darkorchid":"orquídea escuro","turquoise":"turquesa","chocolate":"chocolate","springgreen":"verde primavera","moccasin":"moccasin","navy":"marinho","lemonchiffon":"limão chiffon","teal":"azul esverdeado","floralwhite":"branco floral","cornflowerblue":"azul centaurea","paleturquoise":"turquesa esbranquiçado","purple":"roxo","gainsboro":"gainsboro","plum":"ameixa","red":"vermelho","blue":"azul","forestgreen":"verde floresta","darkgreen":"verde escuro","honeydew":"honeydew","darkseagreen":"verde marinho escuro","lightcoral":"coral claro","palevioletred":"vermelho-violeta esbranquiçado","mediumpurple":"roxo médio","saddlebrown":"marrom saddle","darkmagenta":"magenta escuro","thistle":"thistle","whitesmoke":"fumaça branca","wheat":"trigo","violet":"violeta","lightskyblue":"azul-céu claro","goldenrod":"goldenrod","mediumblue":"azul médio","skyblue":"azul-céu","crimson":"carmesim","darksalmon":"salmão escuro","darkred":"vermelho escuro","darkslategrey":"cinza-ardósia escuro","peru":"peru","lightgrey":"cinza claro","lightgoldenrodyellow":"amarelo goldenrod claro","blanchedalmond":"amêndoa pelada","aliceblue":"azul alice","bisque":"bisque","slategray":"cinza-ardósia","palegoldenrod":"goldenrod esbranquiçado","darkorange":"laranja escuro","aquamarine":"água-marinha","lightgreen":"verde claro","burlywood":"burlywood","dodgerblue":"azul dodger","darkgray":"cinza escuro","lightcyan":"ciano claro","powderblue":"azul-talco","blueviolet":"azul-violeta","orchid":"orquídea","dimgray":"cinza turvo","beige":"bege","fuchsia":"fúcsia","lavenderblush":"lavanda avermelhada","hotpink":"rosa quente","steelblue":"azul-aço","tomato":"tomate","lightpink":"rosa claro","limegreen":"verde-lima","indianred":"vermelho indiano","papayawhip":"creme de papaya","lightslategray":"cinza-ardósia claro","gray":"cinza","mediumorchid":"orquídea médio","cornsilk":"cornsilk","black":"preto","seagreen":"verde-marinho","darkslateblue":"azul-ardósia escuro","khaki":"cáqui","lightblue":"azul claro","palegreen":"verde esbranquiçado","azure":"azul-celeste","peachpuff":"peach puff","darkolivegreen":"verde oliva escuro","yellowgreen":"verde amarelado"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.pt_br");dijit.nls.loading.pt_br={"loadingState":"Carregando...","errorState":"Desculpe, ocorreu um erro"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.pt_br");dijit.nls.common.pt_br={"buttonOk":"OK","buttonCancel":"Cancelar","buttonSave":"Salvar","itemClose":"Fechar"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.pt_br");dijit.form.nls.validate.pt_br={"rangeMessage":"Este valor está fora do intervalo. ","invalidMessage":"O valor inserido não é válido.","missingMessage":"Este valor é necessário."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.pt_br");dijit.form.nls.ComboBox.pt_br={"previousMessage":"Opções anteriores","nextMessage":"Mais opções"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.pt_br");dojo.cldr.nls.number.pt_br={"group":".","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"¤#,##0.00;(¤#,##0.00)","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_pt-pt.js b/lib/dojo/nls/tt-rss-layer_pt-pt.js
new file mode 100644
index 000000000..a54df6dbf
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_pt-pt.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_pt-pt");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.pt_pt");dojo.nls.colors.pt_pt={"lightsteelblue":"azul-aço claro","orangered":"vermelho alaranjado","midnightblue":"azul meia-noite","cadetblue":"azul cadete","seashell":"concha","slategrey":"cinzento ardósia","coral":"coral","darkturquoise":"turquesa escuro","antiquewhite":"branco antigo","mediumspringgreen":"verde primavera médio","salmon":"salmão","darkgrey":"cinzento escuro","ivory":"marfim","greenyellow":"amarelo esverdeado","mistyrose":"rosa pálido","lightsalmon":"salmão claro","silver":"prateado","dimgrey":"cinzento escuro","orange":"laranja","white":"branco","navajowhite":"branco navajo","royalblue":"azul real","deeppink":"rosa profundo","lime":"lima","oldlace":"renda antiga","chartreuse":"amarelo esverdeado","darkcyan":"ciano escuro","yellow":"amarelo","linen":"linho","olive":"azeitona","gold":"dourado","lawngreen":"verde relva","lightyellow":"amarelo claro","tan":"castanho claro","darkviolet":"violeta escuro","lightslategrey":"cinzento ardósia claro","grey":"cinzento","darkkhaki":"caqui escuro","green":"verde","deepskyblue":"azul céu profundo","aqua":"verde-água","sienna":"castanho-avermelhado","mintcream":"creme de menta","rosybrown":"castanho rosado","mediumslateblue":"azul ardósia médio","magenta":"magenta","lightseagreen":"verde marinho claro","cyan":"ciano","olivedrab":"azeitona claro","darkgoldenrod":"ouro velho escuro","slateblue":"azul ardósia","mediumaquamarine":"verde-azulado médio","lavender":"alfazema","mediumseagreen":"verde marinho médio","maroon":"bordeaux","darkslategray":"cinzento ardósia escuro","mediumturquoise":"turquesa médio","ghostwhite":"branco sombreado","darkblue":"azul escuro","mediumvioletred":"violeta avermelhado médio","brown":"castanho","lightgray":"cinzento claro","sandybrown":"castanho areia","pink":"rosa","firebrick":"tijolo fogo","indigo":"índigo","snow":"branco-neve","darkorchid":"orquídea escuro","turquoise":"turquesa","chocolate":"chocolate","springgreen":"verde primavera","moccasin":"mocassim","navy":"azul marinho","lemonchiffon":"limão chiffon","teal":"verde-azulado","floralwhite":"branco floral","cornflowerblue":"azul-violáceo","paleturquoise":"turquesa pálido","purple":"roxo","gainsboro":"cinzento azulado claro","plum":"cor-de-ameixa","red":"vermelho","blue":"azul","forestgreen":"verde floresta","darkgreen":"verde escuro","honeydew":"mel","darkseagreen":"verde marinho escuro","lightcoral":"coral claro","palevioletred":"violeta avermelhado pálido","mediumpurple":"roxo médio","saddlebrown":"castanho sela","darkmagenta":"magenta escuro","thistle":"cardo","whitesmoke":"fumo branco","wheat":"trigo","violet":"violeta","lightskyblue":"azul céu claro","goldenrod":"ouro velho","mediumblue":"azul médio","skyblue":"azul céu","crimson":"carmesim","darksalmon":"salmão escuro","darkred":"vermelho escuro","darkslategrey":"cinzento ardósia escuro","peru":"peru","lightgrey":"cinzento claro","lightgoldenrodyellow":"ouro velho amarelado claro","blanchedalmond":"amêndoa claro","aliceblue":"azul alice","bisque":"rosa-velho","slategray":"cinzento ardósia","palegoldenrod":"ouro velho pálido","darkorange":"laranja escuro","aquamarine":"verde-azulado","lightgreen":"verde claro","burlywood":"castanho pinho","dodgerblue":"azul furtivo","darkgray":"cinzento escuro","lightcyan":"ciano claro","powderblue":"azul de esmalte","blueviolet":"azul violeta","orchid":"orquídea","dimgray":"cinzento escuro","beige":"bege","fuchsia":"fúcsia","lavenderblush":"alfazema rosado","hotpink":"rosa forte","steelblue":"azul-aço","tomato":"vermelho tomate","lightpink":"rosa claro","limegreen":"verde-lima","indianred":"almagre","papayawhip":"creme de papaia","lightslategray":"cinzento ardósia claro","gray":"cinzento","mediumorchid":"orquídea médio","cornsilk":"branco seda","black":"preto","seagreen":"verde marinho","darkslateblue":"azul ardósia escuro","khaki":"caqui","lightblue":"azul claro","palegreen":"verde pálido","azure":"azul-celeste","peachpuff":"pêssego","darkolivegreen":"verde-azeitona escuro","yellowgreen":"verde amarelado"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.pt_pt");dijit.nls.loading.pt_pt={"loadingState":"A carregar...","errorState":"Lamentamos, mas ocorreu um erro"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.pt_pt");dijit.nls.common.pt_pt={"buttonOk":"OK","buttonCancel":"Cancelar","buttonSave":"Guardar","itemClose":"Fechar"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.pt_pt");dijit.form.nls.validate.pt_pt={"rangeMessage":"Este valor encontra-se fora do intervalo.","invalidMessage":"O valor introduzido não é válido.","missingMessage":"Este valor é requerido."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.pt_pt");dijit.form.nls.ComboBox.pt_pt={"previousMessage":"Opções anteriores","nextMessage":"Mais opções"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.pt_pt");dojo.cldr.nls.number.pt_pt={"currencyFormat":"#,##0.00 ¤","group":" ","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_pt.js b/lib/dojo/nls/tt-rss-layer_pt.js
new file mode 100644
index 000000000..2e2d70bbb
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_pt.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_pt");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.pt");dojo.nls.colors.pt={"lightsteelblue":"azul-aço claro","orangered":"vermelho alaranjado","midnightblue":"azul meia-noite","cadetblue":"azul cadet","seashell":"seashell","slategrey":"cinza-ardósia","coral":"coral","darkturquoise":"turquesa escuro","antiquewhite":"branco antigo","mediumspringgreen":"verde-primavera médio","salmon":"salmão","darkgrey":"cinza escuro","ivory":"marfim","greenyellow":"amarelo esverdeado","mistyrose":"rosa enevoado","lightsalmon":"salmão claro","silver":"prateado","dimgrey":"cinza turvo","orange":"laranja","white":"branco","navajowhite":"branco navajo","royalblue":"azul royal","deeppink":"rosa profundo","lime":"lima","oldlace":"cadarço velho","chartreuse":"chartreuse","darkcyan":"ciano escuro","yellow":"amarelo","linen":"linho","olive":"oliva","gold":"dourado","lawngreen":"verde grama","lightyellow":"amarelo claro","tan":"tan","darkviolet":"violeta escuro","lightslategrey":"cinza-ardósia claro","grey":"cinza","darkkhaki":"cáqui escuro","green":"verde","deepskyblue":"azul-céu intenso","aqua":"aqua","sienna":"sienna","mintcream":"creme de menta","rosybrown":"marrom rosado","mediumslateblue":"azul-ardósia médio","magenta":"magenta","lightseagreen":"verde marinho claro","cyan":"ciano","olivedrab":"verde oliva","darkgoldenrod":"goldenrod escuro","slateblue":"azul-ardósia","mediumaquamarine":"água-marinha médio","lavender":"lavanda","mediumseagreen":"verde-marinho médio","maroon":"marrom","darkslategray":"cinza-ardósia escuro","mediumturquoise":"turquesa médio","ghostwhite":"branco ghost","darkblue":"azul escuro","mediumvioletred":"vermelho-violeta médio","brown":"marrom","lightgray":"cinza claro","sandybrown":"marrom cor de areia","pink":"rosa","firebrick":"firebrick","indigo":"índigo","snow":"branco neve","darkorchid":"orquídea escuro","turquoise":"turquesa","chocolate":"chocolate","springgreen":"verde primavera","moccasin":"moccasin","navy":"marinho","lemonchiffon":"limão chiffon","teal":"azul esverdeado","floralwhite":"branco floral","cornflowerblue":"azul centaurea","paleturquoise":"turquesa esbranquiçado","purple":"roxo","gainsboro":"gainsboro","plum":"ameixa","red":"vermelho","blue":"azul","forestgreen":"verde floresta","darkgreen":"verde escuro","honeydew":"honeydew","darkseagreen":"verde marinho escuro","lightcoral":"coral claro","palevioletred":"vermelho-violeta esbranquiçado","mediumpurple":"roxo médio","saddlebrown":"marrom saddle","darkmagenta":"magenta escuro","thistle":"thistle","whitesmoke":"fumaça branca","wheat":"trigo","violet":"violeta","lightskyblue":"azul-céu claro","goldenrod":"goldenrod","mediumblue":"azul médio","skyblue":"azul-céu","crimson":"carmesim","darksalmon":"salmão escuro","darkred":"vermelho escuro","darkslategrey":"cinza-ardósia escuro","peru":"peru","lightgrey":"cinza claro","lightgoldenrodyellow":"amarelo goldenrod claro","blanchedalmond":"amêndoa pelada","aliceblue":"azul alice","bisque":"bisque","slategray":"cinza-ardósia","palegoldenrod":"goldenrod esbranquiçado","darkorange":"laranja escuro","aquamarine":"água-marinha","lightgreen":"verde claro","burlywood":"burlywood","dodgerblue":"azul dodger","darkgray":"cinza escuro","lightcyan":"ciano claro","powderblue":"azul-talco","blueviolet":"azul-violeta","orchid":"orquídea","dimgray":"cinza turvo","beige":"bege","fuchsia":"fúcsia","lavenderblush":"lavanda avermelhada","hotpink":"rosa quente","steelblue":"azul-aço","tomato":"tomate","lightpink":"rosa claro","limegreen":"verde-lima","indianred":"vermelho indiano","papayawhip":"creme de papaya","lightslategray":"cinza-ardósia claro","gray":"cinza","mediumorchid":"orquídea médio","cornsilk":"cornsilk","black":"preto","seagreen":"verde-marinho","darkslateblue":"azul-ardósia escuro","khaki":"cáqui","lightblue":"azul claro","palegreen":"verde esbranquiçado","azure":"azul-celeste","peachpuff":"peach puff","darkolivegreen":"verde oliva escuro","yellowgreen":"verde amarelado"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.pt");dijit.nls.loading.pt={"loadingState":"Carregando...","errorState":"Desculpe, ocorreu um erro"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.pt");dijit.nls.common.pt={"buttonOk":"OK","buttonCancel":"Cancelar","buttonSave":"Salvar","itemClose":"Fechar"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.pt");dijit.form.nls.validate.pt={"rangeMessage":"Este valor está fora do intervalo. ","invalidMessage":"O valor inserido não é válido.","missingMessage":"Este valor é necessário."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.pt");dijit.form.nls.ComboBox.pt={"previousMessage":"Opções anteriores","nextMessage":"Mais opções"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.pt");dojo.cldr.nls.number.pt={"group":".","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"¤#,##0.00;(¤#,##0.00)","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_ru.js b/lib/dojo/nls/tt-rss-layer_ru.js
new file mode 100644
index 000000000..19e4d548b
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_ru.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_ru");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.ru");dojo.nls.colors.ru={"lightsteelblue":"светлый стальной","orangered":"оранжево-красный","midnightblue":"полуночно-синий","cadetblue":"серо-синий","seashell":"морская раковина","slategrey":"грифельно-серый","coral":"коралловый","darkturquoise":"темный бирюзовый","antiquewhite":"белый антик","mediumspringgreen":"нейтральный весенне-зеленый","salmon":"лососевый","darkgrey":"темно-серый","ivory":"слоновой кости","greenyellow":"зелено-желтый","mistyrose":"блекло-розовый","lightsalmon":"светло-лососевый","silver":"серебристый","dimgrey":"тускло-серый","orange":"оранжевый","white":"белый","navajowhite":"белый навахо","royalblue":"королевский голубой","deeppink":"темно-розовый","lime":"лайм","oldlace":"матово-белый","chartreuse":"желто-салатный","darkcyan":"темный циан","yellow":"желтый","linen":"хлопковый","olive":"оливковый","gold":"золотой","lawngreen":"зеленая лужайка","lightyellow":"светло-желтый","tan":"рыжевато-коричневый","darkviolet":"темно-фиолетовый","lightslategrey":"светлый грифельно-серый","grey":"серый","darkkhaki":"темный хаки","green":"зеленый","deepskyblue":"темный небесно-голубой","aqua":"зеленовато-голубой","sienna":"охра","mintcream":"мятно-кремовый","rosybrown":"розово-коричневый","mediumslateblue":"нейтральный грифельно-синий","magenta":"пурпурный","lightseagreen":"светлый морской волны","cyan":"циан","olivedrab":"желтовато-серый","darkgoldenrod":"темно-золотистый","slateblue":"грифельно-синий","mediumaquamarine":"нейтральный аквамарин","lavender":"бледно-лиловый","mediumseagreen":"нейтральный морской волны","maroon":"темно-бордовый","darkslategray":"темный грифельно-серый","mediumturquoise":"нейтральный бирюзовый","ghostwhite":"призрачно-белый","darkblue":"темно-синий","mediumvioletred":"нейтральный фиолетово-красный","brown":"коричневый","lightgray":"светло-серый","sandybrown":"коричнево-песчаный","pink":"розовый","firebrick":"кирпичный","indigo":"индиго","snow":"белоснежный","darkorchid":"темный орсель","turquoise":"бирюзовый","chocolate":"шоколадный","springgreen":"весенний зеленый","moccasin":"мокасин","navy":"темно-синий","lemonchiffon":"бледно-лимонный","teal":"чирок","floralwhite":"цветочно-белый","cornflowerblue":"фиолетово-синий","paleturquoise":"бледно-бирюзовый","purple":"фиолетовый","gainsboro":"бледно-серый","plum":"сливовый","red":"красный","blue":"синий","forestgreen":"зеленый лесной","darkgreen":"темно-зеленый","honeydew":"медовый","darkseagreen":"темный морской волны","lightcoral":"светло-коралловый","palevioletred":"бледный фиолетово-красный","mediumpurple":"нейтральный фиолетовый","saddlebrown":"кожано-коричневый","darkmagenta":"темно-пурпурный","thistle":"чертополох","whitesmoke":"дымчато-белый","wheat":"пшеница","violet":"фиолетовый","lightskyblue":"светлый небесно-голубой","goldenrod":"золотистый","mediumblue":"нейтральный синий","skyblue":"небесно-голубой","crimson":"малиновый","darksalmon":"темно-лососевый","darkred":"темно-красный","darkslategrey":"темный грифельно-серый","peru":"перу","lightgrey":"светло-серый","lightgoldenrodyellow":"светло-золотистый","blanchedalmond":"светло-миндальный","aliceblue":"серо-голубой","bisque":"бисквитный","slategray":"грифельно-серый","palegoldenrod":"бледно-золотистый","darkorange":"темно-оранжевый","aquamarine":"аквамарин","lightgreen":"светло-зеленый","burlywood":"светло-коричневый","dodgerblue":"бледно-синий","darkgray":"темно-серый","lightcyan":"светлый циан","powderblue":"пороховой","blueviolet":"сине-фиолетовый","orchid":"орсель","dimgray":"тускло-серый","beige":"бежевый","fuchsia":"фуксин","lavenderblush":"розовато-лиловый","hotpink":"красно-розовый","steelblue":"стальной","tomato":"помидор","lightpink":"светло-розовый","limegreen":"зеленый лайм","indianred":"индийский красный","papayawhip":"черенок папайи","lightslategray":"светлый грифельно-серый","gray":"серый","mediumorchid":"нейтральный орсель","cornsilk":"шелковый оттенок","black":"черный","seagreen":"морской волны","darkslateblue":"темный грифельно-синий","khaki":"хаки","lightblue":"светло-синий","palegreen":"бледно-зеленый","azure":"лазурный","peachpuff":"персиковый","darkolivegreen":"темно-оливковый","yellowgreen":"желто-зеленый"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.ru");dijit.nls.loading.ru={"loadingState":"Загрузка...","errorState":"Извините, возникла ошибка"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.ru");dijit.nls.common.ru={"buttonOk":"ОК","buttonCancel":"Отмена","buttonSave":"Сохранить","itemClose":"Закрыть"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.ru");dijit.form.nls.validate.ru={"rangeMessage":"Это значение вне диапазона.","invalidMessage":"Указано недопустимое значение.","missingMessage":"Это обязательное значение."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.ru");dijit.form.nls.ComboBox.ru={"previousMessage":"Предыдущие варианты","nextMessage":"Следующие варианты"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.ru");dojo.cldr.nls.number.ru={"group":" ","percentSign":"%","exponential":"E","percentFormat":"#,##0 %","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_sk.js b/lib/dojo/nls/tt-rss-layer_sk.js
new file mode 100644
index 000000000..7b3b6d1a5
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_sk.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_sk");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.sk");dojo.nls.colors.sk={"lightsteelblue":"oceľovo modrá svetlá","orangered":"oranžovo červená","midnightblue":"nočná modrá","cadetblue":"sivomodrá","seashell":"lastúrová","slategrey":"bridlicová sivá","coral":"koralová","darkturquoise":"tyrkysová tmavá","antiquewhite":"antická biela","mediumspringgreen":"jarná zelená stredná","salmon":"lososovo ružová","darkgrey":"tmavosivá","ivory":"slonovinová","greenyellow":"žltozelená","mistyrose":"zahmlená ruža","lightsalmon":"lososovo ružová svetlá","silver":"strieborná","dimgrey":"sivá matná","orange":"oranžová","white":"biela","navajowhite":"navajská biela","royalblue":"kráľovská modrá","deeppink":"hlboká ružová","lime":"lipová","oldlace":"stará čipka","chartreuse":"kartúza","darkcyan":"tmavozelenomodrá","yellow":"žltá","linen":"ľan","olive":"olivovo zelená","gold":"zlatá","lawngreen":"zelená tráva","lightyellow":"svetložltá","tan":"žltohnedá","darkviolet":"tmavofialová","lightslategrey":"bridlicová sivá svetlá","grey":"sivá","darkkhaki":"žltohnedá tmavá","green":"zelená","deepskyblue":"hlboká blankytná modrá","aqua":"svetlá zelenomodrá","sienna":"sienská","mintcream":"mätová krémová","rosybrown":"ružovo hnedá","mediumslateblue":"bridlicová modrá stredná","magenta":"purpurová","lightseagreen":"morská zelená svetlá","cyan":"zelenomodrá","olivedrab":"olivovo zelená fádna","darkgoldenrod":"zlatobyľová tmavá","slateblue":"bridlicová modrá","mediumaquamarine":"akvamarínová stredná","lavender":"levanduľová","mediumseagreen":"morská zelená stredná","maroon":"gaštanovo hnedá","darkslategray":"bridlicová sivá tmavá","mediumturquoise":"tyrkysová stredná","ghostwhite":"biely tieň","darkblue":"tmavomodrá","mediumvioletred":"fialovočervená stredná","brown":"hnedá","lightgray":"svetlosivá","sandybrown":"pieskovo hnedá","pink":"ružová","firebrick":"pálená tehla","indigo":"fialovo modrá","snow":"snehobiela","darkorchid":"orchideovo ružová tmavá","turquoise":"tyrkysová","chocolate":"čokoládovo hnedá","springgreen":"jarná zelená","moccasin":"črievičníková","navy":"vojenská zelená","lemonchiffon":"citrónový šifón","teal":"tyrkysová","floralwhite":"kvetinová biela","cornflowerblue":"nevädzovo modrá","paleturquoise":"bledo tyrkysová","purple":"purpurová","gainsboro":"sivomodrá svetlá","plum":"slivková","red":"červená","blue":"modrá","forestgreen":"lesná zelená","darkgreen":"tmavozelená","honeydew":"ambrózia","darkseagreen":"morská zelená tmavá","lightcoral":"koralová svetlá","palevioletred":"bledá fialovo červená","mediumpurple":"purpurová stredná","saddlebrown":"sedlová hnedá","darkmagenta":"tmavopurpurová","thistle":"bodliaková fialová","whitesmoke":"biely dym","wheat":"pšeničná","violet":"fialová","lightskyblue":"blankytná modrá svetlá","goldenrod":"zlatobyľ","mediumblue":"stredne modrá","skyblue":"blankytná modrá","crimson":"karmínová","darksalmon":"lososovo ružová tmavá","darkred":"tmavočervená","darkslategrey":"bridlicová sivá tmavá","peru":"peru","lightgrey":"svetlosivá","lightgoldenrodyellow":"zlatobyľová svetlá","blanchedalmond":"lúpané mandle","aliceblue":"modrá alice","bisque":"biskvitová","slategray":"bridlicová sivá","palegoldenrod":"bledá zlatobyľová","darkorange":"tmavooranžová","aquamarine":"akvamarínová","lightgreen":"svetlozelená","burlywood":"pieskovo hnedá","dodgerblue":"modrá dodger","darkgray":"tmavosivá","lightcyan":"zelenomodrá svetlá","powderblue":"prášková modrá","blueviolet":"modrofialová","orchid":"orchideovo ružová","dimgray":"sivá matná","beige":"béžová","fuchsia":"purpurová","lavenderblush":"levanduľový rumenec","hotpink":"teplá ružová","steelblue":"oceľovo modrá","tomato":"paradajková červená","lightpink":"svetloružová","limegreen":"lipová zelená","indianred":"indická červená","papayawhip":"papájový krém","lightslategray":"bridlicová sivá svetlá","gray":"sivá","mediumorchid":"orchideovo ružová stredná","cornsilk":"hodvábna žltá","black":"čierna","seagreen":"morská zelená","darkslateblue":"bridlicová modrá tmavá","khaki":"khaki","lightblue":"svetlomodrá","palegreen":"bledozelená","azure":"azúrová","peachpuff":"broskyňová pena","darkolivegreen":"olivovozelená tmavá","yellowgreen":"žltozelená"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.sk");dijit.nls.loading.sk={"loadingState":"Zavádzanie...","errorState":"Nastala chyba"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.sk");dijit.nls.common.sk={"buttonOk":"OK","buttonCancel":"Zrušiť","buttonSave":"Uložiť","itemClose":"Zatvoriť"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.sk");dijit.form.nls.validate.sk={"rangeMessage":"Táto hodnota je mimo rozsah.","invalidMessage":"Zadaná hodnota nie je platná.","missingMessage":"Táto hodnota je vyžadovaná."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.sk");dijit.form.nls.ComboBox.sk={"previousMessage":"Predchádzajúce voľby","nextMessage":"Ďalšie voľby"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.sk");dojo.cldr.nls.number.sk={"currencyFormat":"#,##0.00 ¤","group":" ","decimal":",","scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","percentFormat":"#,##0%","decimalFormat":"#,##0.###","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"};
diff --git a/lib/dojo/nls/tt-rss-layer_sl.js b/lib/dojo/nls/tt-rss-layer_sl.js
new file mode 100644
index 000000000..f76c70841
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_sl.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_sl");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.sl");dojo.nls.colors.sl={"lightsteelblue":"svetlo jeklena modra","orangered":"oranžno-rdeča","midnightblue":"polnočno modra","cadetblue":"zelenkasto modra","seashell":"morska školjka","slategrey":"skrilasto siva","coral":"koralna","darkturquoise":"temno turkizna","antiquewhite":"antično bela","mediumspringgreen":"srednje pomladno zelena","salmon":"lososova","darkgrey":"temno siva","ivory":"slonokoščena","greenyellow":"zeleno-rumena","mistyrose":"megleno rožnata","lightsalmon":"svetlo lososova","silver":"srebrna","dimgrey":"umazano siva","orange":"oranžna","white":"bela","navajowhite":"navajsko bela","royalblue":"kraljevsko modra","deeppink":"temno roza","lime":"rumeno zelena","oldlace":"stara čipka","chartreuse":"svetlo rumena zelena","darkcyan":"temno cijan","yellow":"rumena","linen":"lanena","olive":"olivna","gold":"zlata","lawngreen":"travnato zelena","lightyellow":"svetlo rumena","tan":"kožno rjava","darkviolet":"temno vijolična","lightslategrey":"svetlo skrilasto siva","grey":"siva","darkkhaki":"temno rumenkasto rjava","green":"zelena","deepskyblue":"temno nebesno modra","aqua":"akva","sienna":"siena","mintcream":"mentolno smetanasta","rosybrown":"rožnato rjava","mediumslateblue":"srednje skrilasto modra","magenta":"magenta","lightseagreen":"svetlo morsko zelena","cyan":"cijan","olivedrab":"olivno sivo rjava","darkgoldenrod":"temno zlata rozga","slateblue":"skrilasto modra","mediumaquamarine":"srednje akvamarin","lavender":"sivka","mediumseagreen":"srednje morsko zelena","maroon":"kostanjeva","darkslategray":"temno skrilasto siva","mediumturquoise":"srednje turkizna","ghostwhite":"prosojno bela","darkblue":"temno modra","mediumvioletred":"srednje vijolično-rdeča","brown":"rjava","lightgray":"svetlo siva","sandybrown":"peščeno rjava","pink":"roza","firebrick":"opečnata","indigo":"indigo","snow":"snežena","darkorchid":"temno orhidejna","turquoise":"turkizna","chocolate":"čokoladna","springgreen":"pomladno zelena","moccasin":"mokasinasta","navy":"mornarsko modra","lemonchiffon":"limonina","teal":"zeleno modra","floralwhite":"cvetno bela","cornflowerblue":"plavično modra","paleturquoise":"bledo turkizna","purple":"škrlatna","gainsboro":"pepelnato siva","plum":"slivova","red":"rdeča","blue":"modra","forestgreen":"gozdno zelena","darkgreen":"temno zelena","honeydew":"medena rosa","darkseagreen":"temno morsko zelena","lightcoral":"svetlo koralna","palevioletred":"bledo vijolično-rdeča","mediumpurple":"srednje škrlatna","saddlebrown":"sedlasto rjava","darkmagenta":"temno magenta","thistle":"osatna","whitesmoke":"umazano bela","wheat":"žitna","violet":"vijolična","lightskyblue":"svetlo nebesno modra","goldenrod":"zlata rozga","mediumblue":"srednje modra","skyblue":"nebesno modra","crimson":"karminasta","darksalmon":"temno lososova","darkred":"temno rdeča","darkslategrey":"temno skrilasto siva","peru":"perujska","lightgrey":"svetlo siva","lightgoldenrodyellow":"svetlo rumena zlata rozga","blanchedalmond":"mandljeva","aliceblue":"alice modra","bisque":"porcelanasta","slategray":"skrilasto siva","palegoldenrod":"bleda zlata rozga","darkorange":"temno oranžna","aquamarine":"akvamarin","lightgreen":"svetlo zelena","burlywood":"grčav les","dodgerblue":"koruzno modra","darkgray":"temno siva","lightcyan":"svetlo cijan","powderblue":"smodniško modra","blueviolet":"modro vijolična","orchid":"orhidejna","dimgray":"umazano siva","beige":"bež","fuchsia":"fuksija","lavenderblush":"bleščeča sivka","hotpink":"živo roza","steelblue":"jekleno modra","tomato":"paradižnikova","lightpink":"svetlo roza","limegreen":"citronsko zelena","indianred":"indijansko rdeča","papayawhip":"papaja","lightslategray":"svetlo skrilasto siva","gray":"siva","mediumorchid":"srednje orhidejna","cornsilk":"koruzni laski","black":"črna","seagreen":"morsko zelena","darkslateblue":"temno skrilasto modra","khaki":"rumenkasto rjava","lightblue":"svetlo modra","palegreen":"bledo zelena","azure":"azurna","peachpuff":"breskova","darkolivegreen":"temno olivno zelena","yellowgreen":"rumeno zelena"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.sl");dijit.nls.loading.sl={"loadingState":"Nalaganje...","errorState":"Oprostite, prišlo je do napake."};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.sl");dijit.nls.common.sl={"buttonOk":"V redu","buttonCancel":"Prekliči","buttonSave":"Shrani","itemClose":"Zapri"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.sl");dijit.form.nls.validate.sl={"rangeMessage":"Ta vrednost je zunaj obsega. ","invalidMessage":"Vnesena vrednost ni veljavna.","missingMessage":"Ta vrednost je zahtevana."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.sl");dijit.form.nls.ComboBox.sl={"previousMessage":"Prejšnje možnosti","nextMessage":"Dodatne možnosti"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.sl");dojo.cldr.nls.number.sl={"group":".","percentSign":"%","exponential":"e","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_sv.js b/lib/dojo/nls/tt-rss-layer_sv.js
new file mode 100644
index 000000000..b8ea0caf6
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_sv.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_sv");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.sv");dojo.nls.colors.sv={"lightsteelblue":"ljust stålblått","orangered":"orangerött","midnightblue":"midnattsblått","cadetblue":"kadettblått","seashell":"snäckskal","slategrey":"skiffergrått","coral":"korall","darkturquoise":"mörkturkost","antiquewhite":"antikvitt","mediumspringgreen":"mellanvårgrönt","salmon":"laxfärgat","darkgrey":"mörkgrått","ivory":"elfenbensvitt","greenyellow":"gröngult","mistyrose":"dunkelrosa","lightsalmon":"ljust laxfärgat","silver":"silver","dimgrey":"smutsgrått","orange":"orange","white":"vitt","navajowhite":"navajovitt","royalblue":"kungligt blått","deeppink":"djuprosa","lime":"lime","oldlace":"spetsvitt","chartreuse":"chartreuse","darkcyan":"mörkt cyan","yellow":"gult","linen":"linne","olive":"olivfärgat","gold":"guld","lawngreen":"gräsmattegrönt","lightyellow":"ljusgult","tan":"mellanbrunt","darkviolet":"mörkviolett","lightslategrey":"ljust skiffergrått","grey":"grått","darkkhaki":"mörkt kaki","green":"grönt","deepskyblue":"mörkt himmelsblått","aqua":"akvamarin","sienna":"sienna","mintcream":"mintgrädde","rosybrown":"rosenbrunt","mediumslateblue":"mellanskifferblått","magenta":"magenta","lightseagreen":"ljust havsgrönt","cyan":"cyan","olivedrab":"olivsmutsgult","darkgoldenrod":"mörkt gullris","slateblue":"skifferblått","mediumaquamarine":"mellanakvamarin","lavender":"lavendel","mediumseagreen":"mellanhavsgrönt","maroon":"rödbrunt","darkslategray":"mörkt skiffergrått","mediumturquoise":"mellanturkost","ghostwhite":"spökvitt","darkblue":"mörkblått","mediumvioletred":"mellanviolettrött","brown":"brunt","lightgray":"ljusgrått","sandybrown":"sandbrunt","pink":"rosa","firebrick":"tegelstensrött","indigo":"indigo","snow":"snö","darkorchid":"mörkt orkidé","turquoise":"turkost","chocolate":"choklad","springgreen":"vårgrönt","moccasin":"mockasin","navy":"marinblått","lemonchiffon":"citronchiffong","teal":"blågrönt","floralwhite":"blomvitt","cornflowerblue":"kornblått","paleturquoise":"blekturkost","purple":"lila","gainsboro":"gainsboro","plum":"plommon","red":"rött","blue":"blått","forestgreen":"skogsgrönt","darkgreen":"mörkgrönt","honeydew":"honungsdagg","darkseagreen":"mörkt havsgrönt","lightcoral":"ljuskorall","palevioletred":"blekviolettrött","mediumpurple":"mellanlila","saddlebrown":"sadelbrunt","darkmagenta":"mörk magenta","thistle":"tistel","whitesmoke":"vit rök","wheat":"vete","violet":"violett","lightskyblue":"ljust himmelsblått","goldenrod":"gullris","mediumblue":"mellanblått","skyblue":"himmelsblått","crimson":"karmosinrött","darksalmon":"mörkt laxfärgat","darkred":"mörkrött","darkslategrey":"mörkt skiffergrått","peru":"peru","lightgrey":"ljusgrått","lightgoldenrodyellow":"ljust gullrisgult","blanchedalmond":"skållad mandel","aliceblue":"aliceblå","bisque":"biskvi","slategray":"skiffergrått","palegoldenrod":"blekt gullris","darkorange":"mörkorange","aquamarine":"akvamarin","lightgreen":"ljusgrönt","burlywood":"träfärgat","dodgerblue":"dodgerblått","darkgray":"mörkgrått","lightcyan":"ljust cyan","powderblue":"pulverblått","blueviolet":"blåviolett","orchid":"orkidé","dimgray":"smutsgrått","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavendelskimrande","hotpink":"varmrosa","steelblue":"stålblått","tomato":"tomatrött","lightpink":"ljusrosa","limegreen":"limegrönt","indianred":"indianrött","papayawhip":"papayaröra","lightslategray":"ljust skiffergrått","gray":"grått","mediumorchid":"mellanorkidé","cornsilk":"gulvitt","black":"svart","seagreen":"havsgrönt","darkslateblue":"mörkt skifferblått","khaki":"kaki","lightblue":"ljusblått","palegreen":"blekgrönt","azure":"azurblått","peachpuff":"persika","darkolivegreen":"mörkt olivgrönt","yellowgreen":"gulgrönt"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.sv");dijit.nls.loading.sv={"loadingState":"Läser in...","errorState":"Det uppstod ett fel."};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.sv");dijit.nls.common.sv={"buttonOk":"OK","buttonCancel":"Avbryt","buttonSave":"Spara","itemClose":"Stäng"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.sv");dijit.form.nls.validate.sv={"rangeMessage":"Värdet är utanför intervallet.","invalidMessage":"Det angivna värdet är ogiltigt.","missingMessage":"Värdet är obligatoriskt."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.sv");dijit.form.nls.ComboBox.sv={"previousMessage":"Föregående alternativ","nextMessage":"Fler alternativ"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.sv");dojo.cldr.nls.number.sv={"group":" ","percentSign":"%","exponential":"×10^","percentFormat":"#,##0 %","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"−","decimal":",","nan":"¤¤¤","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_th.js b/lib/dojo/nls/tt-rss-layer_th.js
new file mode 100644
index 000000000..0189c3fb9
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_th.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_th");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.th");dojo.nls.colors.th={"lightsteelblue":"light steel blue","orangered":"ส้มแกมแดง","midnightblue":"midnight blue","cadetblue":"cadet blue","seashell":"seashell","slategrey":"slate gray","coral":"coral","darkturquoise":"dark turquoise","antiquewhite":"antique white","mediumspringgreen":"medium spring green","salmon":"salmon","darkgrey":"เทาเข้ม","ivory":"งาช้าง","greenyellow":"เขียวแกมเหลือง","mistyrose":"misty rose","lightsalmon":"light salmon","silver":"เงิน","dimgrey":"dim gray","orange":"ส้ม","white":"ขาว","navajowhite":"navajo white","royalblue":"royal blue","deeppink":"ชมพูเข้ม","lime":"เหลืองมะนาว","oldlace":"old lace","chartreuse":"chartreuse","darkcyan":"เขียวแกมน้ำเงินเข้ม","yellow":"เหลือง","linen":"linen","olive":"โอลีฟ","gold":"ทอง","lawngreen":"lawn green","lightyellow":"เหลืองอ่อน","tan":"tan","darkviolet":"ม่วงเข้ม","lightslategrey":"light slate gray","grey":"เทา","darkkhaki":"dark khaki","green":"เขียว","deepskyblue":"deep sky blue","aqua":"ฟ้าน้ำทะเล","sienna":"sienna","mintcream":"mint cream","rosybrown":"rosy brown","mediumslateblue":"medium slate blue","magenta":"แดงแกมม่วง","lightseagreen":"light sea green","cyan":"เขียวแกมน้ำเงิน","olivedrab":"olive drab","darkgoldenrod":"dark goldenrod","slateblue":"slate blue","mediumaquamarine":"medium aquamarine","lavender":"ม่วงลาเวนเดอร์","mediumseagreen":"medium sea green","maroon":"น้ำตาลแดง","darkslategray":"dark slate gray","mediumturquoise":"medium turquoise","ghostwhite":"ghost white","darkblue":"น้ำเงินเข้ม","mediumvioletred":"medium violet-red","brown":"น้ำตาล","lightgray":"เทาอ่อน","sandybrown":"sandy brown","pink":"ชมพู","firebrick":"สีอิฐ","indigo":"indigo","snow":"snow","darkorchid":"dark orchid","turquoise":"turquoise","chocolate":"ช็อกโกแลต","springgreen":"spring green","moccasin":"ม็อคค่า","navy":"น้ำเงินเข้ม","lemonchiffon":"lemon chiffon","teal":"teal","floralwhite":"floral white","cornflowerblue":"cornflower blue","paleturquoise":"pale turquoise","purple":"ม่วง","gainsboro":"gainsboro","plum":"plum","red":"แดง","blue":"น้ำเงิน","forestgreen":"forest green","darkgreen":"เขียวเข้ม","honeydew":"honeydew","darkseagreen":"dark sea green","lightcoral":"light coral","palevioletred":"pale violet-red","mediumpurple":"medium purple","saddlebrown":"saddle brown","darkmagenta":"แดงแกมม่วงเข้ม","thistle":"thistle","whitesmoke":"ขาวควัน","wheat":"wheat","violet":"ม่วง","lightskyblue":"ฟ้าอ่อน","goldenrod":"goldenrod","mediumblue":"medium blue","skyblue":"sky blue","crimson":"แดงเลือดหมู","darksalmon":"dark salmon","darkred":"แดงเข้ม","darkslategrey":"dark slate gray","peru":"peru","lightgrey":"เทาอ่อน","lightgoldenrodyellow":"light goldenrod yellow","blanchedalmond":"blanched almond","aliceblue":"alice blue","bisque":"bisque","slategray":"slate gray","palegoldenrod":"pale goldenrod","darkorange":"ส้มเข้ม","aquamarine":"aquamarine","lightgreen":"เขียวอ่อน","burlywood":"burlywood","dodgerblue":"dodger blue","darkgray":"เทาเข้ม","lightcyan":"เขียวแกมน้ำเงินอ่อน","powderblue":"powder blue","blueviolet":"น้ำเงินม่วง","orchid":"orchid","dimgray":"dim gray","beige":"น้ำตาลเบจ","fuchsia":"fuchsia","lavenderblush":"lavender blush","hotpink":"hot pink","steelblue":"steel blue","tomato":"tomato","lightpink":"ชมพูอ่อน","limegreen":"เขียวมะนาว","indianred":"indian red","papayawhip":"papaya whip","lightslategray":"light slate gray","gray":"เทา","mediumorchid":"medium orchid","cornsilk":"cornsilk","black":"ดำ","seagreen":"sea green","darkslateblue":"dark slate blue","khaki":"khaki","lightblue":"น้ำเงินอ่อน","palegreen":"pale green","azure":"น้ำเงินฟ้า","peachpuff":"peach puff","darkolivegreen":"เขียวโอลีฟเข้ม","yellowgreen":"เหลืองแกมเขียว"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.th");dijit.nls.loading.th={"loadingState":"กำลังโหลด...","errorState":"ขออภัย เกิดข้อผิดพลาด"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.th");dijit.nls.common.th={"buttonOk":"ตกลง","buttonCancel":"ยกเลิก","buttonSave":"บันทึก","itemClose":"ปิด"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.th");dijit.form.nls.validate.th={"rangeMessage":"ค่านี้เกินช่วง","invalidMessage":"ค่าที่ป้อนไม่ถูกต้อง","missingMessage":"จำเป็นต้องมีค่านี้"};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.th");dijit.form.nls.ComboBox.th={"previousMessage":"การเลือกก่อนหน้า","nextMessage":"การเลือกเพิ่มเติม"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.th");dojo.cldr.nls.number.th={"group":",","percentSign":"%","exponential":"E","percentFormat":"#,##0%","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":".","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"¤#,##0.00;¤-#,##0.00","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_tr.js b/lib/dojo/nls/tt-rss-layer_tr.js
new file mode 100644
index 000000000..73e5d8126
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_tr.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_tr");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.tr");dojo.nls.colors.tr={"lightsteelblue":"açık metalik mavi","orangered":"turuncu kırmızı","midnightblue":"gece mavisi","cadetblue":"denizci mavisi","seashell":"deniz kabuğu","slategrey":"arduvaz grisi","coral":"mercan","darkturquoise":"koyu turkuaz","antiquewhite":"antik beyaz","mediumspringgreen":"orta bahar yeşili","salmon":"somon","darkgrey":"koyu gri","ivory":"fildişi","greenyellow":"yeşil-sarı","mistyrose":"gülkurusu","lightsalmon":"açık somon","silver":"gümüş","dimgrey":"soluk gri","orange":"turuncu","white":"beyaz","navajowhite":"navajo beyazı","royalblue":"parlak koyu mavi","deeppink":"koyu pembe","lime":"limon yeşili","oldlace":"eski dantel","chartreuse":"chartreuse","darkcyan":"koyu camgöbeği","yellow":"sarı","linen":"keten","olive":"zeytin","gold":"altın","lawngreen":"çimen yeşili","lightyellow":"açık sarı","tan":"güneş yanığı","darkviolet":"koyu eflatun","lightslategrey":"açık arduvaz grisi","grey":"gri","darkkhaki":"koyu haki","green":"yeşil","deepskyblue":"koyu gök mavisi","aqua":"deniz mavisi","sienna":"koyu kahve","mintcream":"naneli krem","rosybrown":"pembemsi kahverengi","mediumslateblue":"orta arduvaz mavisi","magenta":"macenta","lightseagreen":"açık deniz yeşili","cyan":"camgöbeği","olivedrab":"asker yeşili","darkgoldenrod":"koyu sarı","slateblue":"arduvaz mavisi","mediumaquamarine":"orta akuamarin","lavender":"lavanta","mediumseagreen":"orta deniz yeşili","maroon":"kestane","darkslategray":"koyu arduvaz grisi","mediumturquoise":"orta turkuaz","ghostwhite":"silik beyaz","darkblue":"koyu mavi","mediumvioletred":"orta menekşe kırmızısı","brown":"kahverengi","lightgray":"açık gri","sandybrown":"kum rengi","pink":"pembe","firebrick":"canlı kiremit","indigo":"çivit mavisi","snow":"kar","darkorchid":"koyu orkide","turquoise":"turkuaz","chocolate":"çikolata","springgreen":"bahar yeşili","moccasin":"mokosen","navy":"lacivert","lemonchiffon":"limoni","teal":"Teal mavi","floralwhite":"çiçek beyazı","cornflowerblue":"peygamber çiçeği mavisi","paleturquoise":"soluk turkuaz","purple":"mor","gainsboro":"gainsboro","plum":"erik","red":"kırmızı","blue":"mavi","forestgreen":"koyu deniz yeşili","darkgreen":"koyu yeşil","honeydew":"çam sakızı","darkseagreen":"koyu deniz yeşili","lightcoral":"açık mercan","palevioletred":"soluk menekşe kırmızısı","mediumpurple":"orta mor","saddlebrown":"açık kahve","darkmagenta":"koyu mor","thistle":"devedikeni","whitesmoke":"beyaz duman","wheat":"buğday","violet":"eflatun","lightskyblue":"açık gök mavisi","goldenrod":"sarısabır","mediumblue":"orta mavi","skyblue":"gök mavisi","crimson":"crimson","darksalmon":"koyu somon","darkred":"koyu kırmızı","darkslategrey":"koyu arduvaz grisi","peru":"peru","lightgrey":"açık gri","lightgoldenrodyellow":"açık sarısabır","blanchedalmond":"soluk badem","aliceblue":"alice mavisi","bisque":"bisküvi","slategray":"arduvaz grisi","palegoldenrod":"soluk sarısabır","darkorange":"koyu turuncu","aquamarine":"akuamarin","lightgreen":"açık yeşil","burlywood":"sarımsı kahverengi","dodgerblue":"toz mavisi","darkgray":"koyu gri","lightcyan":"açık camgöbeği","powderblue":"pudra mavisi","blueviolet":"mavi-mor","orchid":"orkide","dimgray":"soluk gri","beige":"bej","fuchsia":"fuşya","lavenderblush":"lavanta pembesi","hotpink":"sıcak pembe","steelblue":"metalik mavi","tomato":"domates","lightpink":"açık pembe","limegreen":"küf yeşili","indianred":"kızılderili kırmızısı","papayawhip":"papaya sapı","lightslategray":"açık arduvaz grisi","gray":"gri","mediumorchid":"orta orkide","cornsilk":"mısır rengi","black":"siyah","seagreen":"deniz yeşili","darkslateblue":"koyu arduvaz mavisi","khaki":"haki","lightblue":"açık mavi","palegreen":"soluk yeşil","azure":"azur mavisi","peachpuff":"açık şeftali","darkolivegreen":"koyu zeytin yeşili","yellowgreen":"sarı yeşil"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.tr");dijit.nls.loading.tr={"loadingState":"Yükleniyor...","errorState":"Üzgünüz, bir hata oluştu"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.tr");dijit.nls.common.tr={"buttonOk":"Tamam","buttonCancel":"İptal","buttonSave":"Kaydet","itemClose":"Kapat"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.tr");dijit.form.nls.validate.tr={"rangeMessage":"Bu değer aralık dışında.","invalidMessage":"Girilen değer geçersiz.","missingMessage":"Bu değer gerekli."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.tr");dijit.form.nls.ComboBox.tr={"previousMessage":"Önceki seçenekler","nextMessage":"Diğer seçenekler"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.tr");dojo.cldr.nls.number.tr={"group":".","percentSign":"%","exponential":"E","percentFormat":"% #,##0","scientificFormat":"#E0","list":";","infinity":"∞","patternDigit":"#","minusSign":"-","decimal":",","nan":"NaN","nativeZeroDigit":"0","perMille":"‰","decimalFormat":"#,##0.###","currencyFormat":"#,##0.00 ¤","plusSign":"+","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","currencySpacing-beforeCurrency-insertBetween":" "};
diff --git a/lib/dojo/nls/tt-rss-layer_xx.js b/lib/dojo/nls/tt-rss-layer_xx.js
new file mode 100644
index 000000000..c54e6ea35
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_xx.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_xx");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.xx");dojo.nls.colors.xx={"lightsteelblue":"light steel blue","orangered":"orange red","midnightblue":"midnight blue","cadetblue":"cadet blue","seashell":"seashell","slategrey":"slate gray","coral":"coral","darkturquoise":"dark turquoise","antiquewhite":"antique white","mediumspringgreen":"medium spring green","salmon":"salmon","darkgrey":"dark gray","ivory":"ivory","greenyellow":"green-yellow","mistyrose":"misty rose","lightsalmon":"light salmon","silver":"silver","dimgrey":"dim gray","orange":"orange","white":"white","navajowhite":"navajo white","royalblue":"royal blue","deeppink":"deep pink","lime":"lime","oldlace":"old lace","chartreuse":"chartreuse","darkcyan":"dark cyan","yellow":"yellow","linen":"linen","olive":"olive","gold":"gold","lawngreen":"lawn green","lightyellow":"light yellow","tan":"tan","darkviolet":"dark violet","lightslategrey":"light slate gray","grey":"gray","darkkhaki":"dark khaki","green":"green","deepskyblue":"deep sky blue","aqua":"aqua","sienna":"sienna","mintcream":"mint cream","rosybrown":"rosy brown","mediumslateblue":"medium slate blue","magenta":"magenta","lightseagreen":"light sea green","cyan":"cyan","olivedrab":"olive drab","darkgoldenrod":"dark goldenrod","slateblue":"slate blue","mediumaquamarine":"medium aquamarine","lavender":"lavender","mediumseagreen":"medium sea green","maroon":"maroon","darkslategray":"dark slate gray","mediumturquoise":"medium turquoise","ghostwhite":"ghost white","darkblue":"dark blue","mediumvioletred":"medium violet-red","brown":"brown","lightgray":"light gray","sandybrown":"sandy brown","pink":"pink","firebrick":"fire brick","indigo":"indigo","snow":"snow","darkorchid":"dark orchid","turquoise":"turquoise","chocolate":"chocolate","springgreen":"spring green","moccasin":"moccasin","navy":"navy","lemonchiffon":"lemon chiffon","teal":"teal","floralwhite":"floral white","cornflowerblue":"cornflower blue","paleturquoise":"pale turquoise","purple":"purple","gainsboro":"gainsboro","plum":"plum","red":"red","blue":"blue","forestgreen":"forest green","darkgreen":"dark green","honeydew":"honeydew","darkseagreen":"dark sea green","lightcoral":"light coral","palevioletred":"pale violet-red","mediumpurple":"medium purple","saddlebrown":"saddle brown","darkmagenta":"dark magenta","thistle":"thistle","whitesmoke":"white smoke","wheat":"wheat","violet":"violet","lightskyblue":"light sky blue","goldenrod":"goldenrod","mediumblue":"medium blue","skyblue":"sky blue","crimson":"crimson","darksalmon":"dark salmon","darkred":"dark red","darkslategrey":"dark slate gray","peru":"peru","lightgrey":"light gray","lightgoldenrodyellow":"light goldenrod yellow","blanchedalmond":"blanched almond","aliceblue":"alice blue","bisque":"bisque","slategray":"slate gray","palegoldenrod":"pale goldenrod","darkorange":"dark orange","aquamarine":"aquamarine","lightgreen":"light green","burlywood":"burlywood","dodgerblue":"dodger blue","darkgray":"dark gray","lightcyan":"light cyan","powderblue":"powder blue","blueviolet":"blue-violet","orchid":"orchid","dimgray":"dim gray","beige":"beige","fuchsia":"fuchsia","lavenderblush":"lavender blush","hotpink":"hot pink","steelblue":"steel blue","tomato":"tomato","lightpink":"light pink","limegreen":"lime green","indianred":"indian red","papayawhip":"papaya whip","lightslategray":"light slate gray","gray":"gray","mediumorchid":"medium orchid","cornsilk":"cornsilk","black":"black","seagreen":"sea green","darkslateblue":"dark slate blue","khaki":"khaki","lightblue":"light blue","palegreen":"pale green","azure":"azure","peachpuff":"peach puff","darkolivegreen":"dark olive green","yellowgreen":"yellow green"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.xx");dijit.nls.loading.xx={"loadingState":"Loading...","errorState":"Sorry, an error occurred"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.xx");dijit.nls.common.xx={"buttonOk":"OK","buttonCancel":"Cancel","buttonSave":"Save","itemClose":"Close"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.xx");dijit.form.nls.validate.xx={"rangeMessage":"This value is out of range.","invalidMessage":"The value entered is not valid.","missingMessage":"This value is required."};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.xx");dijit.form.nls.ComboBox.xx={"previousMessage":"Previous choices","nextMessage":"More choices"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.xx");dojo.cldr.nls.number.xx={"scientificFormat":"#E0","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencyFormat":"¤ #,##0.00","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","group":",","percentFormat":"#,##0%","decimalFormat":"#,##0.###","decimal":".","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"};
diff --git a/lib/dojo/nls/tt-rss-layer_zh-cn.js b/lib/dojo/nls/tt-rss-layer_zh-cn.js
new file mode 100644
index 000000000..05243b8ac
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_zh-cn.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_zh-cn");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.zh_cn");dojo.nls.colors.zh_cn={"lightsteelblue":"浅钢蓝色","orangered":"橙红色","midnightblue":"深蓝色","cadetblue":"灰蓝色","seashell":"海贝色","slategrey":"灰石色","coral":"珊瑚色","darkturquoise":"深粉蓝","antiquewhite":"古董白","mediumspringgreen":"间春绿色","salmon":"橙红","darkgrey":"深灰色","ivory":"象牙色","greenyellow":"绿黄色","mistyrose":"浅玫瑰色","lightsalmon":"淡橙色","silver":"银白色","dimgrey":"暗灰色","orange":"橙色","white":"白色","navajowhite":"纳瓦白","royalblue":"品蓝","deeppink":"深粉红色","lime":"淡黄绿色","oldlace":"老白色","chartreuse":"黄绿色","darkcyan":"深青绿","yellow":"黄色","linen":"亚麻色","olive":"橄榄绿","gold":"金黄色","lawngreen":"草绿色","lightyellow":"浅黄色","tan":"棕褐色","darkviolet":"深紫色","lightslategrey":"浅青灰","grey":"灰色","darkkhaki":"深卡其色","green":"绿色","deepskyblue":"深天蓝色","aqua":"浅绿色","sienna":"赭色","mintcream":"薄荷色","rosybrown":"褐玫瑰红","mediumslateblue":"间暗蓝色","magenta":"洋红色","lightseagreen":"浅海藻绿","cyan":"青蓝色","olivedrab":"草绿色","darkgoldenrod":"深金黄","slateblue":"石蓝色","mediumaquamarine":"间绿色","lavender":"淡紫色","mediumseagreen":"间海蓝色","maroon":"栗色","darkslategray":"深青灰","mediumturquoise":"间绿宝石色","ghostwhite":"苍白","darkblue":"深蓝","mediumvioletred":"间紫罗兰色","brown":"棕色","lightgray":"浅灰色","sandybrown":"沙褐色","pink":"粉红色","firebrick":"砖红","indigo":"靛青","snow":"雪白色","darkorchid":"深紫色","turquoise":"绿宝石色","chocolate":"巧克力色","springgreen":"春绿色","moccasin":"鹿皮色","navy":"藏青色","lemonchiffon":"柠檬绸色","teal":"水鸭色","floralwhite":"花白色","cornflowerblue":"浅蓝色","paleturquoise":"苍绿色","purple":"紫色","gainsboro":"淡灰色","plum":"杨李色","red":"红色","blue":"蓝色","forestgreen":"森林绿","darkgreen":"深绿色","honeydew":"蜜汁色","darkseagreen":"深海藻绿","lightcoral":"浅珊瑚色","palevioletred":"苍紫罗兰色","mediumpurple":"间紫色","saddlebrown":"重褐色","darkmagenta":"深洋红色","thistle":"蓟色","whitesmoke":"烟白色","wheat":"浅黄色","violet":"紫色","lightskyblue":"浅天蓝色","goldenrod":"金麒麟色","mediumblue":"间蓝色","skyblue":"天蓝色","crimson":"绯红色","darksalmon":"深橙红","darkred":"深红色","darkslategrey":"深青灰","peru":"秘鲁色","lightgrey":"浅灰色","lightgoldenrodyellow":"浅金黄色","blanchedalmond":"白杏色","aliceblue":"爱丽丝蓝","bisque":"桔黄色","slategray":"灰石色","palegoldenrod":"淡金黄色","darkorange":"深橙色","aquamarine":"碧绿色","lightgreen":"浅绿色","burlywood":"实木色","dodgerblue":"闪蓝色","darkgray":"深灰色","lightcyan":"浅青色","powderblue":"铁蓝","blueviolet":"蓝紫色","orchid":"紫色","dimgray":"暗灰色","beige":"米色","fuchsia":"紫红色","lavenderblush":"淡紫红","hotpink":"深粉红","steelblue":"钢蓝色","tomato":"西红柿色","lightpink":"浅粉红色","limegreen":"橙绿色","indianred":"印度红","papayawhip":"木瓜色","lightslategray":"浅青灰","gray":"灰色","mediumorchid":"间紫色","cornsilk":"米绸色","black":"黑色","seagreen":"海绿色","darkslateblue":"深青蓝","khaki":"卡其色","lightblue":"淡蓝色","palegreen":"淡绿色","azure":"天蓝色","peachpuff":"桃色","darkolivegreen":"深橄榄绿","yellowgreen":"黄绿色"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.zh_cn");dijit.nls.loading.zh_cn={"loadingState":"正在加载...","errorState":"对不起,发生了错误"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.zh_cn");dijit.nls.common.zh_cn={"buttonOk":"确定","buttonCancel":"取消","buttonSave":"保存","itemClose":"关闭"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.zh_cn");dijit.form.nls.validate.zh_cn={"rangeMessage":"此值超出范围。","invalidMessage":"输入的值无效。","missingMessage":"此值是必需值。"};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.zh_cn");dijit.form.nls.ComboBox.zh_cn={"previousMessage":"先前选项","nextMessage":"更多选项"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.zh_cn");dojo.cldr.nls.number.zh_cn={"decimalFormat":"#,##0.###","group":",","scientificFormat":"#E0","percentFormat":"#,##0%","currencyFormat":"¤#,##0.00","decimal":".","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"};
diff --git a/lib/dojo/nls/tt-rss-layer_zh-tw.js b/lib/dojo/nls/tt-rss-layer_zh-tw.js
new file mode 100644
index 000000000..4925db23c
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_zh-tw.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_zh-tw");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.zh_tw");dojo.nls.colors.zh_tw={"lightsteelblue":"淡鐵藍色","orangered":"橙紅色","midnightblue":"午夜藍","cadetblue":"軍服藍","seashell":"海貝色","slategrey":"岩灰色","coral":"珊瑚紅","darkturquoise":"暗松石綠","antiquewhite":"米白色","mediumspringgreen":"中春綠色","salmon":"鮭紅色","darkgrey":"暗灰色","ivory":"象牙色","greenyellow":"綠黃色","mistyrose":"霧玫瑰色","lightsalmon":"淡鮭紅","silver":"銀色","dimgrey":"昏灰色","orange":"橙色","white":"白色","navajowhite":"印地安黃色","royalblue":"品藍色","deeppink":"深粉紅色","lime":"檸檬色","oldlace":"舊蕾絲色","chartreuse":"淡黃綠色","darkcyan":"暗青色","yellow":"黃色","linen":"亞麻色","olive":"橄欖色","gold":"金色","lawngreen":"草綠色","lightyellow":"淡黃色","tan":"皮革色","darkviolet":"暗紫羅蘭色","lightslategrey":"淡岩灰色","grey":"灰色","darkkhaki":"暗卡其色","green":"綠色","deepskyblue":"深天藍色","aqua":"水色","sienna":"黃土赭色","mintcream":"薄荷乳白色","rosybrown":"玫瑰褐","mediumslateblue":"中岩藍色","magenta":"紫紅色","lightseagreen":"淡海綠色","cyan":"青色","olivedrab":"橄欖綠","darkgoldenrod":"暗金菊色","slateblue":"岩藍色","mediumaquamarine":"中碧綠色","lavender":"薰衣草紫","mediumseagreen":"中海綠色","maroon":"栗色","darkslategray":"暗岩灰色","mediumturquoise":"中松石綠","ghostwhite":"幽靈色","darkblue":"暗藍色","mediumvioletred":"中紫羅蘭紅","brown":"褐色","lightgray":"淡灰色","sandybrown":"沙褐色","pink":"粉紅色","firebrick":"紅磚色","indigo":"靛藍色","snow":"雪白色","darkorchid":"暗蘭花色","turquoise":"松石綠","chocolate":"巧克力色","springgreen":"春綠色","moccasin":"鹿皮黃色","navy":"海軍藍","lemonchiffon":"奶油黃","teal":"深藍綠色","floralwhite":"花卉白","cornflowerblue":"矢車菊藍","paleturquoise":"灰松石綠","purple":"紫色","gainsboro":"石板灰","plum":"李紫色","red":"紅色","blue":"藍色","forestgreen":"森綠色","darkgreen":"暗綠色","honeydew":"密瓜色","darkseagreen":"暗海綠色","lightcoral":"淡珊瑚紅","palevioletred":"灰紫羅蘭紅","mediumpurple":"中紫色","saddlebrown":"鞍褐色","darkmagenta":"暗紫紅色","thistle":"薊色","whitesmoke":"白煙色","wheat":"小麥色","violet":"紫羅蘭色","lightskyblue":"淡天藍色","goldenrod":"金菊色","mediumblue":"中藍色","skyblue":"天藍色","crimson":"暗深紅色","darksalmon":"暗鮭紅","darkred":"暗紅色","darkslategrey":"暗岩灰色","peru":"祕魯色","lightgrey":"淡灰色","lightgoldenrodyellow":"淡金菊黃","blanchedalmond":"杏仁白","aliceblue":"愛麗絲藍","bisque":"橘黃色","slategray":"岩灰色","palegoldenrod":"灰金菊色","darkorange":"暗橙色","aquamarine":"碧綠色","lightgreen":"淡綠色","burlywood":"實木色","dodgerblue":"道奇藍","darkgray":"暗灰色","lightcyan":"淡青色","powderblue":"粉藍色","blueviolet":"藍紫色","orchid":"蘭花色","dimgray":"昏灰色","beige":"灰棕色","fuchsia":"海棠紅","lavenderblush":"薰衣草紫紅","hotpink":"暖粉紅色","steelblue":"鐵藍色","tomato":"蕃茄紅","lightpink":"淡粉紅色","limegreen":"檸檬綠","indianred":"印度紅","papayawhip":"番木瓜色","lightslategray":"淡岩灰色","gray":"灰色","mediumorchid":"中蘭紫色","cornsilk":"玉米黃","black":"黑色","seagreen":"海綠色","darkslateblue":"暗岩藍色","khaki":"卡其色","lightblue":"淡藍色","palegreen":"灰綠色","azure":"天藍色","peachpuff":"粉撲桃色","darkolivegreen":"暗橄欖綠","yellowgreen":"黃綠色"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.zh_tw");dijit.nls.loading.zh_tw={"loadingState":"載入中...","errorState":"抱歉,發生錯誤"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.zh_tw");dijit.nls.common.zh_tw={"buttonOk":"確定","buttonCancel":"取消","buttonSave":"儲存","itemClose":"關閉"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.zh_tw");dijit.form.nls.validate.zh_tw={"rangeMessage":"此值超出範圍。","invalidMessage":"輸入的值無效。","missingMessage":"必須提供此值。"};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.zh_tw");dijit.form.nls.ComboBox.zh_tw={"previousMessage":"前一個選擇項","nextMessage":"其他選擇項"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.zh_tw");dojo.cldr.nls.number.zh_tw={"decimalFormat":"#,##0.###","group":",","scientificFormat":"#E0","percentFormat":"#,##0%","currencyFormat":"¤#,##0.00","decimal":".","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"};
diff --git a/lib/dojo/nls/tt-rss-layer_zh.js b/lib/dojo/nls/tt-rss-layer_zh.js
new file mode 100644
index 000000000..ed7ddffdf
--- /dev/null
+++ b/lib/dojo/nls/tt-rss-layer_zh.js
@@ -0,0 +1 @@
+dojo.provide("dojo.nls.tt-rss-layer_zh");dojo.provide("dojo.nls.colors");dojo.nls.colors._built=true;dojo.provide("dojo.nls.colors.zh");dojo.nls.colors.zh={"lightsteelblue":"浅钢蓝色","orangered":"橙红色","midnightblue":"深蓝色","cadetblue":"灰蓝色","seashell":"海贝色","slategrey":"灰石色","coral":"珊瑚色","darkturquoise":"深粉蓝","antiquewhite":"古董白","mediumspringgreen":"间春绿色","salmon":"橙红","darkgrey":"深灰色","ivory":"象牙色","greenyellow":"绿黄色","mistyrose":"浅玫瑰色","lightsalmon":"淡橙色","silver":"银白色","dimgrey":"暗灰色","orange":"橙色","white":"白色","navajowhite":"纳瓦白","royalblue":"品蓝","deeppink":"深粉红色","lime":"淡黄绿色","oldlace":"老白色","chartreuse":"黄绿色","darkcyan":"深青绿","yellow":"黄色","linen":"亚麻色","olive":"橄榄绿","gold":"金黄色","lawngreen":"草绿色","lightyellow":"浅黄色","tan":"棕褐色","darkviolet":"深紫色","lightslategrey":"浅青灰","grey":"灰色","darkkhaki":"深卡其色","green":"绿色","deepskyblue":"深天蓝色","aqua":"浅绿色","sienna":"赭色","mintcream":"薄荷色","rosybrown":"褐玫瑰红","mediumslateblue":"间暗蓝色","magenta":"洋红色","lightseagreen":"浅海藻绿","cyan":"青蓝色","olivedrab":"草绿色","darkgoldenrod":"深金黄","slateblue":"石蓝色","mediumaquamarine":"间绿色","lavender":"淡紫色","mediumseagreen":"间海蓝色","maroon":"栗色","darkslategray":"深青灰","mediumturquoise":"间绿宝石色","ghostwhite":"苍白","darkblue":"深蓝","mediumvioletred":"间紫罗兰色","brown":"棕色","lightgray":"浅灰色","sandybrown":"沙褐色","pink":"粉红色","firebrick":"砖红","indigo":"靛青","snow":"雪白色","darkorchid":"深紫色","turquoise":"绿宝石色","chocolate":"巧克力色","springgreen":"春绿色","moccasin":"鹿皮色","navy":"藏青色","lemonchiffon":"柠檬绸色","teal":"水鸭色","floralwhite":"花白色","cornflowerblue":"浅蓝色","paleturquoise":"苍绿色","purple":"紫色","gainsboro":"淡灰色","plum":"杨李色","red":"红色","blue":"蓝色","forestgreen":"森林绿","darkgreen":"深绿色","honeydew":"蜜汁色","darkseagreen":"深海藻绿","lightcoral":"浅珊瑚色","palevioletred":"苍紫罗兰色","mediumpurple":"间紫色","saddlebrown":"重褐色","darkmagenta":"深洋红色","thistle":"蓟色","whitesmoke":"烟白色","wheat":"浅黄色","violet":"紫色","lightskyblue":"浅天蓝色","goldenrod":"金麒麟色","mediumblue":"间蓝色","skyblue":"天蓝色","crimson":"绯红色","darksalmon":"深橙红","darkred":"深红色","darkslategrey":"深青灰","peru":"秘鲁色","lightgrey":"浅灰色","lightgoldenrodyellow":"浅金黄色","blanchedalmond":"白杏色","aliceblue":"爱丽丝蓝","bisque":"桔黄色","slategray":"灰石色","palegoldenrod":"淡金黄色","darkorange":"深橙色","aquamarine":"碧绿色","lightgreen":"浅绿色","burlywood":"实木色","dodgerblue":"闪蓝色","darkgray":"深灰色","lightcyan":"浅青色","powderblue":"铁蓝","blueviolet":"蓝紫色","orchid":"紫色","dimgray":"暗灰色","beige":"米色","fuchsia":"紫红色","lavenderblush":"淡紫红","hotpink":"深粉红","steelblue":"钢蓝色","tomato":"西红柿色","lightpink":"浅粉红色","limegreen":"橙绿色","indianred":"印度红","papayawhip":"木瓜色","lightslategray":"浅青灰","gray":"灰色","mediumorchid":"间紫色","cornsilk":"米绸色","black":"黑色","seagreen":"海绿色","darkslateblue":"深青蓝","khaki":"卡其色","lightblue":"淡蓝色","palegreen":"淡绿色","azure":"天蓝色","peachpuff":"桃色","darkolivegreen":"深橄榄绿","yellowgreen":"黄绿色"};dojo.provide("dijit.nls.loading");dijit.nls.loading._built=true;dojo.provide("dijit.nls.loading.zh");dijit.nls.loading.zh={"loadingState":"正在加载...","errorState":"对不起,发生了错误"};dojo.provide("dijit.nls.common");dijit.nls.common._built=true;dojo.provide("dijit.nls.common.zh");dijit.nls.common.zh={"buttonOk":"确定","buttonCancel":"取消","buttonSave":"保存","itemClose":"关闭"};dojo.provide("dijit.form.nls.validate");dijit.form.nls.validate._built=true;dojo.provide("dijit.form.nls.validate.zh");dijit.form.nls.validate.zh={"rangeMessage":"此值超出范围。","invalidMessage":"输入的值无效。","missingMessage":"此值是必需值。"};dojo.provide("dijit.form.nls.ComboBox");dijit.form.nls.ComboBox._built=true;dojo.provide("dijit.form.nls.ComboBox.zh");dijit.form.nls.ComboBox.zh={"previousMessage":"先前选项","nextMessage":"更多选项"};dojo.provide("dojo.cldr.nls.number");dojo.cldr.nls.number._built=true;dojo.provide("dojo.cldr.nls.number.zh");dojo.cldr.nls.number.zh={"decimalFormat":"#,##0.###","group":",","scientificFormat":"#E0","percentFormat":"#,##0%","currencyFormat":"¤#,##0.00","decimal":".","currencySpacing-afterCurrency-currencyMatch":"[:letter:]","infinity":"∞","list":";","percentSign":"%","minusSign":"-","currencySpacing-beforeCurrency-surroundingMatch":"[:digit:]","currencySpacing-afterCurrency-insertBetween":" ","nan":"NaN","nativeZeroDigit":"0","plusSign":"+","currencySpacing-afterCurrency-surroundingMatch":"[:digit:]","currencySpacing-beforeCurrency-currencyMatch":"[:letter:]","perMille":"‰","patternDigit":"#","currencySpacing-beforeCurrency-insertBetween":" ","exponential":"E"};
diff --git a/lib/dojo/number.js b/lib/dojo/number.js
index 95a2c5022..33aa6dd52 100644
--- a/lib/dojo/number.js
+++ b/lib/dojo/number.js
@@ -5,307 +5,580 @@
*/
-if(!dojo._hasResource["dojo.number"]){
-dojo._hasResource["dojo.number"]=true;
+if(!dojo._hasResource["dojo.number"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.number"] = true;
dojo.provide("dojo.number");
+
dojo.require("dojo.i18n");
-dojo.requireLocalization("dojo.cldr","number",null,"ROOT,ar,ca,cs,da,de,el,en,en-au,en-gb,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ru,sk,sl,sv,th,tr,zh");
+dojo.requireLocalization("dojo.cldr", "number", null, "ROOT,ar,ca,cs,da,de,el,en,en-au,en-gb,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ru,sk,sl,sv,th,tr,zh");
dojo.require("dojo.string");
dojo.require("dojo.regexp");
-dojo.number.format=function(_1,_2){
-_2=dojo.mixin({},_2||{});
-var _3=dojo.i18n.normalizeLocale(_2.locale),_4=dojo.i18n.getLocalization("dojo.cldr","number",_3);
-_2.customs=_4;
-var _5=_2.pattern||_4[(_2.type||"decimal")+"Format"];
-if(isNaN(_1)||Math.abs(_1)==Infinity){
-return null;
-}
-return dojo.number._applyPattern(_1,_5,_2);
-};
-dojo.number._numberPatternRE=/[#0,]*[#0](?:\.0*#*)?/;
-dojo.number._applyPattern=function(_6,_7,_8){
-_8=_8||{};
-var _9=_8.customs.group,_a=_8.customs.decimal,_b=_7.split(";"),_c=_b[0];
-_7=_b[(_6<0)?1:0]||("-"+_c);
-if(_7.indexOf("%")!=-1){
-_6*=100;
-}else{
-if(_7.indexOf("‰")!=-1){
-_6*=1000;
-}else{
-if(_7.indexOf("¤")!=-1){
-_9=_8.customs.currencyGroup||_9;
-_a=_8.customs.currencyDecimal||_a;
-_7=_7.replace(/\u00a4{1,3}/,function(_d){
-var _e=["symbol","currency","displayName"][_d.length-1];
-return _8[_e]||_8.currency||"";
-});
-}else{
-if(_7.indexOf("E")!=-1){
-throw new Error("exponential notation not supported");
-}
-}
-}
-}
-var _f=dojo.number._numberPatternRE;
-var _10=_c.match(_f);
-if(!_10){
-throw new Error("unable to find a number expression in pattern: "+_7);
-}
-if(_8.fractional===false){
-_8.places=0;
-}
-return _7.replace(_f,dojo.number._formatAbsolute(_6,_10[0],{decimal:_a,group:_9,places:_8.places,round:_8.round}));
-};
-dojo.number.round=function(_11,_12,_13){
-var _14=10/(_13||10);
-return (_14*+_11).toFixed(_12)/_14;
-};
-if((0.9).toFixed()==0){
-(function(){
-var _15=dojo.number.round;
-dojo.number.round=function(v,p,m){
-var d=Math.pow(10,-p||0),a=Math.abs(v);
-if(!v||a>=d||a*Math.pow(10,p+1)<5){
-d=0;
-}
-return _15(v,p,m)+(v>0?d:-d);
-};
-})();
-}
-dojo.number._formatAbsolute=function(_16,_17,_18){
-_18=_18||{};
-if(_18.places===true){
-_18.places=0;
-}
-if(_18.places===Infinity){
-_18.places=6;
-}
-var _19=_17.split("."),_1a=typeof _18.places=="string"&&_18.places.indexOf(","),_1b=_18.places;
-if(_1a){
-_1b=_18.places.substring(_1a+1);
-}else{
-if(!(_1b>=0)){
-_1b=(_19[1]||[]).length;
-}
-}
-if(!(_18.round<0)){
-_16=dojo.number.round(_16,_1b,_18.round);
-}
-var _1c=String(Math.abs(_16)).split("."),_1d=_1c[1]||"";
-if(_19[1]||_18.places){
-if(_1a){
-_18.places=_18.places.substring(0,_1a);
-}
-var pad=_18.places!==undefined?_18.places:(_19[1]&&_19[1].lastIndexOf("0")+1);
-if(pad>_1d.length){
-_1c[1]=dojo.string.pad(_1d,pad,"0",true);
-}
-if(_1b<_1d.length){
-_1c[1]=_1d.substr(0,_1b);
-}
-}else{
-if(_1c[1]){
-_1c.pop();
-}
-}
-var _1e=_19[0].replace(",","");
-pad=_1e.indexOf("0");
-if(pad!=-1){
-pad=_1e.length-pad;
-if(pad>_1c[0].length){
-_1c[0]=dojo.string.pad(_1c[0],pad);
-}
-if(_1e.indexOf("#")==-1){
-_1c[0]=_1c[0].substr(_1c[0].length-pad);
-}
-}
-var _1f=_19[0].lastIndexOf(","),_20,_21;
-if(_1f!=-1){
-_20=_19[0].length-_1f-1;
-var _22=_19[0].substr(0,_1f);
-_1f=_22.lastIndexOf(",");
-if(_1f!=-1){
-_21=_22.length-_1f-1;
-}
-}
-var _23=[];
-for(var _24=_1c[0];_24;){
-var off=_24.length-_20;
-_23.push((off>0)?_24.substr(off):_24);
-_24=(off>0)?_24.slice(0,off):"";
-if(_21){
-_20=_21;
-delete _21;
-}
+
+
+/*=====
+dojo.number = {
+ // summary: localized formatting and parsing routines for Number
}
-_1c[0]=_23.reverse().join(_18.group||",");
-return _1c.join(_18.decimal||".");
-};
-dojo.number.regexp=function(_25){
-return dojo.number._parseInfo(_25).regexp;
+
+dojo.number.__FormatOptions = function(){
+ // pattern: String?
+ // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // with this string. Default value is based on locale. Overriding this property will defeat
+ // localization. Literal characters in patterns are not supported.
+ // type: String?
+ // choose a format type based on the locale from the following:
+ // decimal, scientific (not yet supported), percent, currency. decimal by default.
+ // places: Number?
+ // fixed number of decimal places to show. This overrides any
+ // information in the provided pattern.
+ // round: Number?
+ // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
+ // means do not round.
+ // locale: String?
+ // override the locale used to determine formatting rules
+ // fractional: Boolean?
+ // If false, show no decimal places, overriding places and pattern settings.
+ this.pattern = pattern;
+ this.type = type;
+ this.places = places;
+ this.round = round;
+ this.locale = locale;
+ this.fractional = fractional;
+}
+=====*/
+
+dojo.number.format = function(/*Number*/value, /*dojo.number.__FormatOptions?*/options){
+ // summary:
+ // Format a Number as a String, using locale-specific settings
+ // description:
+ // Create a string from a Number using a known localized pattern.
+ // Formatting patterns appropriate to the locale are chosen from the
+ // [Common Locale Data Repository](http://unicode.org/cldr) as well as the appropriate symbols and
+ // delimiters.
+ // If value is Infinity, -Infinity, or is not a valid JavaScript number, return null.
+ // value:
+ // the number to be formatted
+
+ options = dojo.mixin({}, options || {});
+ var locale = dojo.i18n.normalizeLocale(options.locale),
+ bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale);
+ options.customs = bundle;
+ var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
+ if(isNaN(value) || Math.abs(value) == Infinity){ return null; } // null
+ return dojo.number._applyPattern(value, pattern, options); // String
};
-dojo.number._parseInfo=function(_26){
-_26=_26||{};
-var _27=dojo.i18n.normalizeLocale(_26.locale),_28=dojo.i18n.getLocalization("dojo.cldr","number",_27),_29=_26.pattern||_28[(_26.type||"decimal")+"Format"],_2a=_28.group,_2b=_28.decimal,_2c=1;
-if(_29.indexOf("%")!=-1){
-_2c/=100;
-}else{
-if(_29.indexOf("‰")!=-1){
-_2c/=1000;
-}else{
-var _2d=_29.indexOf("¤")!=-1;
-if(_2d){
-_2a=_28.currencyGroup||_2a;
-_2b=_28.currencyDecimal||_2b;
-}
-}
-}
-var _2e=_29.split(";");
-if(_2e.length==1){
-_2e.push("-"+_2e[0]);
-}
-var re=dojo.regexp.buildGroupRE(_2e,function(_2f){
-_2f="(?:"+dojo.regexp.escapeString(_2f,".")+")";
-return _2f.replace(dojo.number._numberPatternRE,function(_30){
-var _31={signed:false,separator:_26.strict?_2a:[_2a,""],fractional:_26.fractional,decimal:_2b,exponent:false},_32=_30.split("."),_33=_26.places;
-if(_32.length==1&&_2c!=1){
-_32[1]="###";
-}
-if(_32.length==1||_33===0){
-_31.fractional=false;
-}else{
-if(_33===undefined){
-_33=_26.pattern?_32[1].lastIndexOf("0")+1:Infinity;
-}
-if(_33&&_26.fractional==undefined){
-_31.fractional=true;
-}
-if(!_26.places&&(_33<_32[1].length)){
-_33+=","+_32[1].length;
-}
-_31.places=_33;
-}
-var _34=_32[0].split(",");
-if(_34.length>1){
-_31.groupSize=_34.pop().length;
-if(_34.length>1){
-_31.groupSize2=_34.pop().length;
-}
-}
-return "("+dojo.number._realNumberRegexp(_31)+")";
-});
-},true);
-if(_2d){
-re=re.replace(/([\s\xa0]*)(\u00a4{1,3})([\s\xa0]*)/g,function(_35,_36,_37,_38){
-var _39=["symbol","currency","displayName"][_37.length-1],_3a=dojo.regexp.escapeString(_26[_39]||_26.currency||"");
-_36=_36?"[\\s\\xa0]":"";
-_38=_38?"[\\s\\xa0]":"";
-if(!_26.strict){
-if(_36){
-_36+="*";
-}
-if(_38){
-_38+="*";
+
+//dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enough
+dojo.number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enough
+
+dojo.number._applyPattern = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatOptions?*/options){
+ // summary:
+ // Apply pattern to format value as a string using options. Gives no
+ // consideration to local customs.
+ // value:
+ // the number to be formatted.
+ // pattern:
+ // a pattern string as described by
+ // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // options: dojo.number.__FormatOptions?
+ // _applyPattern is usually called via `dojo.number.format()` which
+ // populates an extra property in the options parameter, "customs".
+ // The customs object specifies group and decimal parameters if set.
+
+ //TODO: support escapes
+ options = options || {};
+ var group = options.customs.group,
+ decimal = options.customs.decimal,
+ patternList = pattern.split(';'),
+ positivePattern = patternList[0];
+ pattern = patternList[(value < 0) ? 1 : 0] || ("-" + positivePattern);
+
+ //TODO: only test against unescaped
+ if(pattern.indexOf('%') != -1){
+ value *= 100;
+ }else if(pattern.indexOf('\u2030') != -1){
+ value *= 1000; // per mille
+ }else if(pattern.indexOf('\u00a4') != -1){
+ group = options.customs.currencyGroup || group;//mixins instead?
+ decimal = options.customs.currencyDecimal || decimal;// Should these be mixins instead?
+ pattern = pattern.replace(/\u00a4{1,3}/, function(match){
+ var prop = ["symbol", "currency", "displayName"][match.length-1];
+ return options[prop] || options.currency || "";
+ });
+ }else if(pattern.indexOf('E') != -1){
+ throw new Error("exponential notation not supported");
+ }
+
+ //TODO: support @ sig figs?
+ var numberPatternRE = dojo.number._numberPatternRE;
+ var numberPattern = positivePattern.match(numberPatternRE);
+ if(!numberPattern){
+ throw new Error("unable to find a number expression in pattern: "+pattern);
+ }
+ if(options.fractional === false){ options.places = 0; }
+ return pattern.replace(numberPatternRE,
+ dojo.number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places, round: options.round}));
}
-return "(?:"+_36+_3a+_38+")?";
+
+dojo.number.round = function(/*Number*/value, /*Number?*/places, /*Number?*/increment){
+ // summary:
+ // Rounds to the nearest value with the given number of decimal places, away from zero
+ // description:
+ // Rounds to the nearest value with the given number of decimal places, away from zero if equal.
+ // Similar to Number.toFixed(), but compensates for browser quirks. Rounding can be done by
+ // fractional increments also, such as the nearest quarter.
+ // NOTE: Subject to floating point errors. See dojox.math.round for experimental workaround.
+ // value:
+ // The number to round
+ // places:
+ // The number of decimal places where rounding takes place. Defaults to 0 for whole rounding.
+ // Must be non-negative.
+ // increment:
+ // Rounds next place to nearest value of increment/10. 10 by default.
+ // example:
+ // >>> dojo.number.round(-0.5)
+ // -1
+ // >>> dojo.number.round(162.295, 2)
+ // 162.29 // note floating point error. Should be 162.3
+ // >>> dojo.number.round(10.71, 0, 2.5)
+ // 10.75
+ var factor = 10 / (increment || 10);
+ return (factor * +value).toFixed(places) / factor; // Number
}
-return _36+_3a+_38;
-});
+
+if((0.9).toFixed() == 0){
+ // (isIE) toFixed() bug workaround: Rounding fails on IE when most significant digit
+ // is just after the rounding place and is >=5
+ (function(){
+ var round = dojo.number.round;
+ dojo.number.round = function(v, p, m){
+ var d = Math.pow(10, -p || 0), a = Math.abs(v);
+ if(!v || a >= d || a * Math.pow(10, p + 1) < 5){
+ d = 0;
+ }
+ return round(v, p, m) + (v > 0 ? d : -d);
+ }
+ })();
}
-return {regexp:re.replace(/[\xa0 ]/g,"[\\s\\xa0]"),group:_2a,decimal:_2b,factor:_2c};
+
+/*=====
+dojo.number.__FormatAbsoluteOptions = function(){
+ // decimal: String?
+ // the decimal separator
+ // group: String?
+ // the group separator
+ // places: Number?|String?
+ // number of decimal places. the range "n,m" will format to m places.
+ // round: Number?
+ // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
+ // means don't round.
+ this.decimal = decimal;
+ this.group = group;
+ this.places = places;
+ this.round = round;
+}
+=====*/
+
+dojo.number._formatAbsolute = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatAbsoluteOptions?*/options){
+ // summary:
+ // Apply numeric pattern to absolute value using options. Gives no
+ // consideration to local customs.
+ // value:
+ // the number to be formatted, ignores sign
+ // pattern:
+ // the number portion of a pattern (e.g. `#,##0.00`)
+ options = options || {};
+ if(options.places === true){options.places=0;}
+ if(options.places === Infinity){options.places=6;} // avoid a loop; pick a limit
+
+ var patternParts = pattern.split("."),
+ comma = typeof options.places == "string" && options.places.indexOf(","),
+ maxPlaces = options.places;
+ if(comma){
+ maxPlaces = options.places.substring(comma + 1);
+ }else if(!(maxPlaces >= 0)){
+ maxPlaces = (patternParts[1] || []).length;
+ }
+ if(!(options.round < 0)){
+ value = dojo.number.round(value, maxPlaces, options.round);
+ }
+
+ var valueParts = String(Math.abs(value)).split("."),
+ fractional = valueParts[1] || "";
+ if(patternParts[1] || options.places){
+ if(comma){
+ options.places = options.places.substring(0, comma);
+ }
+ // Pad fractional with trailing zeros
+ var pad = options.places !== undefined ? options.places : (patternParts[1] && patternParts[1].lastIndexOf("0") + 1);
+ if(pad > fractional.length){
+ valueParts[1] = dojo.string.pad(fractional, pad, '0', true);
+ }
+
+ // Truncate fractional
+ if(maxPlaces < fractional.length){
+ valueParts[1] = fractional.substr(0, maxPlaces);
+ }
+ }else{
+ if(valueParts[1]){ valueParts.pop(); }
+ }
+
+ // Pad whole with leading zeros
+ var patternDigits = patternParts[0].replace(',', '');
+ pad = patternDigits.indexOf("0");
+ if(pad != -1){
+ pad = patternDigits.length - pad;
+ if(pad > valueParts[0].length){
+ valueParts[0] = dojo.string.pad(valueParts[0], pad);
+ }
+
+ // Truncate whole
+ if(patternDigits.indexOf("#") == -1){
+ valueParts[0] = valueParts[0].substr(valueParts[0].length - pad);
+ }
+ }
+
+ // Add group separators
+ var index = patternParts[0].lastIndexOf(','),
+ groupSize, groupSize2;
+ if(index != -1){
+ groupSize = patternParts[0].length - index - 1;
+ var remainder = patternParts[0].substr(0, index);
+ index = remainder.lastIndexOf(',');
+ if(index != -1){
+ groupSize2 = remainder.length - index - 1;
+ }
+ }
+ var pieces = [];
+ for(var whole = valueParts[0]; whole;){
+ var off = whole.length - groupSize;
+ pieces.push((off > 0) ? whole.substr(off) : whole);
+ whole = (off > 0) ? whole.slice(0, off) : "";
+ if(groupSize2){
+ groupSize = groupSize2;
+ delete groupSize2;
+ }
+ }
+ valueParts[0] = pieces.reverse().join(options.group || ",");
+
+ return valueParts.join(options.decimal || ".");
};
-dojo.number.parse=function(_3b,_3c){
-var _3d=dojo.number._parseInfo(_3c),_3e=(new RegExp("^"+_3d.regexp+"$")).exec(_3b);
-if(!_3e){
-return NaN;
-}
-var _3f=_3e[1];
-if(!_3e[1]){
-if(!_3e[2]){
-return NaN;
+
+/*=====
+dojo.number.__RegexpOptions = function(){
+ // pattern: String?
+ // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // with this string. Default value is based on locale. Overriding this property will defeat
+ // localization.
+ // type: String?
+ // choose a format type based on the locale from the following:
+ // decimal, scientific (not yet supported), percent, currency. decimal by default.
+ // locale: String?
+ // override the locale used to determine formatting rules
+ // strict: Boolean?
+ // strict parsing, false by default. Strict parsing requires input as produced by the format() method.
+ // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
+ // places: Number|String?
+ // number of decimal places to accept: Infinity, a positive number, or
+ // a range "n,m". Defined by pattern or Infinity if pattern not provided.
+ this.pattern = pattern;
+ this.type = type;
+ this.locale = locale;
+ this.strict = strict;
+ this.places = places;
+}
+=====*/
+dojo.number.regexp = function(/*dojo.number.__RegexpOptions?*/options){
+ // summary:
+ // Builds the regular needed to parse a number
+ // description:
+ // Returns regular expression with positive and negative match, group
+ // and decimal separators
+ return dojo.number._parseInfo(options).regexp; // String
}
-_3f=_3e[2];
-_3d.factor*=-1;
+
+dojo.number._parseInfo = function(/*Object?*/options){
+ options = options || {};
+ var locale = dojo.i18n.normalizeLocale(options.locale),
+ bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale),
+ pattern = options.pattern || bundle[(options.type || "decimal") + "Format"],
+//TODO: memoize?
+ group = bundle.group,
+ decimal = bundle.decimal,
+ factor = 1;
+
+ if(pattern.indexOf('%') != -1){
+ factor /= 100;
+ }else if(pattern.indexOf('\u2030') != -1){
+ factor /= 1000; // per mille
+ }else{
+ var isCurrency = pattern.indexOf('\u00a4') != -1;
+ if(isCurrency){
+ group = bundle.currencyGroup || group;
+ decimal = bundle.currencyDecimal || decimal;
+ }
+ }
+
+ //TODO: handle quoted escapes
+ var patternList = pattern.split(';');
+ if(patternList.length == 1){
+ patternList.push("-" + patternList[0]);
+ }
+
+ var re = dojo.regexp.buildGroupRE(patternList, function(pattern){
+ pattern = "(?:"+dojo.regexp.escapeString(pattern, '.')+")";
+ return pattern.replace(dojo.number._numberPatternRE, function(format){
+ var flags = {
+ signed: false,
+ separator: options.strict ? group : [group,""],
+ fractional: options.fractional,
+ decimal: decimal,
+ exponent: false
+ },
+
+ parts = format.split('.'),
+ places = options.places;
+
+ // special condition for percent (factor != 1)
+ // allow decimal places even if not specified in pattern
+ if(parts.length == 1 && factor != 1){
+ parts[1] = "###";
+ }
+ if(parts.length == 1 || places === 0){
+ flags.fractional = false;
+ }else{
+ if(places === undefined){ places = options.pattern ? parts[1].lastIndexOf('0') + 1 : Infinity; }
+ if(places && options.fractional == undefined){flags.fractional = true;} // required fractional, unless otherwise specified
+ if(!options.places && (places < parts[1].length)){ places += "," + parts[1].length; }
+ flags.places = places;
+ }
+ var groups = parts[0].split(',');
+ if(groups.length > 1){
+ flags.groupSize = groups.pop().length;
+ if(groups.length > 1){
+ flags.groupSize2 = groups.pop().length;
+ }
+ }
+ return "("+dojo.number._realNumberRegexp(flags)+")";
+ });
+ }, true);
+
+ if(isCurrency){
+ // substitute the currency symbol for the placeholder in the pattern
+ re = re.replace(/([\s\xa0]*)(\u00a4{1,3})([\s\xa0]*)/g, function(match, before, target, after){
+ var prop = ["symbol", "currency", "displayName"][target.length-1],
+ symbol = dojo.regexp.escapeString(options[prop] || options.currency || "");
+ before = before ? "[\\s\\xa0]" : "";
+ after = after ? "[\\s\\xa0]" : "";
+ if(!options.strict){
+ if(before){before += "*";}
+ if(after){after += "*";}
+ return "(?:"+before+symbol+after+")?";
+ }
+ return before+symbol+after;
+ });
+ }
+
+//TODO: substitute localized sign/percent/permille/etc.?
+
+ // normalize whitespace and return
+ return {regexp: re.replace(/[\xa0 ]/g, "[\\s\\xa0]"), group: group, decimal: decimal, factor: factor}; // Object
}
-_3f=_3f.replace(new RegExp("["+_3d.group+"\\s\\xa0"+"]","g"),"").replace(_3d.decimal,".");
-return _3f*_3d.factor;
+
+/*=====
+dojo.number.__ParseOptions = function(){
+ // pattern: String?
+ // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // with this string. Default value is based on locale. Overriding this property will defeat
+ // localization. Literal characters in patterns are not supported.
+ // type: String?
+ // choose a format type based on the locale from the following:
+ // decimal, scientific (not yet supported), percent, currency. decimal by default.
+ // locale: String?
+ // override the locale used to determine formatting rules
+ // strict: Boolean?
+ // strict parsing, false by default. Strict parsing requires input as produced by the format() method.
+ // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
+ // fractional: Boolean?|Array?
+ // Whether to include the fractional portion, where the number of decimal places are implied by pattern
+ // or explicit 'places' parameter. The value [true,false] makes the fractional portion optional.
+ this.pattern = pattern;
+ this.type = type;
+ this.locale = locale;
+ this.strict = strict;
+ this.fractional = fractional;
+}
+=====*/
+dojo.number.parse = function(/*String*/expression, /*dojo.number.__ParseOptions?*/options){
+ // summary:
+ // Convert a properly formatted string to a primitive Number, using
+ // locale-specific settings.
+ // description:
+ // Create a Number from a string using a known localized pattern.
+ // Formatting patterns are chosen appropriate to the locale
+ // and follow the syntax described by
+ // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // Note that literal characters in patterns are not supported.
+ // expression:
+ // A string representation of a Number
+ var info = dojo.number._parseInfo(options),
+ results = (new RegExp("^"+info.regexp+"$")).exec(expression);
+ if(!results){
+ return NaN; //NaN
+ }
+ var absoluteMatch = results[1]; // match for the positive expression
+ if(!results[1]){
+ if(!results[2]){
+ return NaN; //NaN
+ }
+ // matched the negative pattern
+ absoluteMatch =results[2];
+ info.factor *= -1;
+ }
+
+ // Transform it to something Javascript can parse as a number. Normalize
+ // decimal point and strip out group separators or alternate forms of whitespace
+ absoluteMatch = absoluteMatch.
+ replace(new RegExp("["+info.group + "\\s\\xa0"+"]", "g"), "").
+ replace(info.decimal, ".");
+ // Adjust for negative sign, percent, etc. as necessary
+ return absoluteMatch * info.factor; //Number
};
-dojo.number._realNumberRegexp=function(_40){
-_40=_40||{};
-if(!("places" in _40)){
-_40.places=Infinity;
-}
-if(typeof _40.decimal!="string"){
-_40.decimal=".";
-}
-if(!("fractional" in _40)||/^0/.test(_40.places)){
-_40.fractional=[true,false];
-}
-if(!("exponent" in _40)){
-_40.exponent=[true,false];
-}
-if(!("eSigned" in _40)){
-_40.eSigned=[true,false];
-}
-var _41=dojo.number._integerRegexp(_40),_42=dojo.regexp.buildGroupRE(_40.fractional,function(q){
-var re="";
-if(q&&(_40.places!==0)){
-re="\\"+_40.decimal;
-if(_40.places==Infinity){
-re="(?:"+re+"\\d+)?";
-}else{
-re+="\\d{"+_40.places+"}";
-}
-}
-return re;
-},true);
-var _43=dojo.regexp.buildGroupRE(_40.exponent,function(q){
-if(q){
-return "([eE]"+dojo.number._integerRegexp({signed:_40.eSigned})+")";
-}
-return "";
-});
-var _44=_41+_42;
-if(_42){
-_44="(?:(?:"+_44+")|(?:"+_42+"))";
-}
-return _44+_43;
+
+/*=====
+dojo.number.__RealNumberRegexpFlags = function(){
+ // places: Number?
+ // The integer number of decimal places or a range given as "n,m". If
+ // not given, the decimal part is optional and the number of places is
+ // unlimited.
+ // decimal: String?
+ // A string for the character used as the decimal point. Default
+ // is ".".
+ // fractional: Boolean?|Array?
+ // Whether decimal places are used. Can be true, false, or [true,
+ // false]. Default is [true, false] which means optional.
+ // exponent: Boolean?|Array?
+ // Express in exponential notation. Can be true, false, or [true,
+ // false]. Default is [true, false], (i.e. will match if the
+ // exponential part is present are not).
+ // eSigned: Boolean?|Array?
+ // The leading plus-or-minus sign on the exponent. Can be true,
+ // false, or [true, false]. Default is [true, false], (i.e. will
+ // match if it is signed or unsigned). flags in regexp.integer can be
+ // applied.
+ this.places = places;
+ this.decimal = decimal;
+ this.fractional = fractional;
+ this.exponent = exponent;
+ this.eSigned = eSigned;
+}
+=====*/
+
+dojo.number._realNumberRegexp = function(/*dojo.number.__RealNumberRegexpFlags?*/flags){
+ // summary:
+ // Builds a regular expression to match a real number in exponential
+ // notation
+
+ // assign default values to missing parameters
+ flags = flags || {};
+ //TODO: use mixin instead?
+ if(!("places" in flags)){ flags.places = Infinity; }
+ if(typeof flags.decimal != "string"){ flags.decimal = "."; }
+ if(!("fractional" in flags) || /^0/.test(flags.places)){ flags.fractional = [true, false]; }
+ if(!("exponent" in flags)){ flags.exponent = [true, false]; }
+ if(!("eSigned" in flags)){ flags.eSigned = [true, false]; }
+
+ var integerRE = dojo.number._integerRegexp(flags),
+ decimalRE = dojo.regexp.buildGroupRE(flags.fractional,
+ function(q){
+ var re = "";
+ if(q && (flags.places!==0)){
+ re = "\\" + flags.decimal;
+ if(flags.places == Infinity){
+ re = "(?:" + re + "\\d+)?";
+ }else{
+ re += "\\d{" + flags.places + "}";
+ }
+ }
+ return re;
+ },
+ true
+ );
+
+ var exponentRE = dojo.regexp.buildGroupRE(flags.exponent,
+ function(q){
+ if(q){ return "([eE]" + dojo.number._integerRegexp({ signed: flags.eSigned}) + ")"; }
+ return "";
+ }
+ );
+
+ var realRE = integerRE + decimalRE;
+ // allow for decimals without integers, e.g. .25
+ if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";}
+ return realRE + exponentRE; // String
};
-dojo.number._integerRegexp=function(_45){
-_45=_45||{};
-if(!("signed" in _45)){
-_45.signed=[true,false];
-}
-if(!("separator" in _45)){
-_45.separator="";
-}else{
-if(!("groupSize" in _45)){
-_45.groupSize=3;
-}
-}
-var _46=dojo.regexp.buildGroupRE(_45.signed,function(q){
-return q?"[-+]":"";
-},true);
-var _47=dojo.regexp.buildGroupRE(_45.separator,function(sep){
-if(!sep){
-return "(?:\\d+)";
-}
-sep=dojo.regexp.escapeString(sep);
-if(sep==" "){
-sep="\\s";
-}else{
-if(sep==" "){
-sep="\\s\\xa0";
-}
-}
-var grp=_45.groupSize,_48=_45.groupSize2;
-if(_48){
-var _49="(?:0|[1-9]\\d{0,"+(_48-1)+"}(?:["+sep+"]\\d{"+_48+"})*["+sep+"]\\d{"+grp+"})";
-return ((grp-_48)>0)?"(?:"+_49+"|(?:0|[1-9]\\d{0,"+(grp-1)+"}))":_49;
+
+/*=====
+dojo.number.__IntegerRegexpFlags = function(){
+ // signed: Boolean?
+ // The leading plus-or-minus sign. Can be true, false, or `[true,false]`.
+ // Default is `[true, false]`, (i.e. will match if it is signed
+ // or unsigned).
+ // separator: String?
+ // The character used as the thousands separator. Default is no
+ // separator. For more than one symbol use an array, e.g. `[",", ""]`,
+ // makes ',' optional.
+ // groupSize: Number?
+ // group size between separators
+ // groupSize2: Number?
+ // second grouping, where separators 2..n have a different interval than the first separator (for India)
+ this.signed = signed;
+ this.separator = separator;
+ this.groupSize = groupSize;
+ this.groupSize2 = groupSize2;
+}
+=====*/
+
+dojo.number._integerRegexp = function(/*dojo.number.__IntegerRegexpFlags?*/flags){
+ // summary:
+ // Builds a regular expression that matches an integer
+
+ // assign default values to missing parameters
+ flags = flags || {};
+ if(!("signed" in flags)){ flags.signed = [true, false]; }
+ if(!("separator" in flags)){
+ flags.separator = "";
+ }else if(!("groupSize" in flags)){
+ flags.groupSize = 3;
+ }
+
+ var signRE = dojo.regexp.buildGroupRE(flags.signed,
+ function(q){ return q ? "[-+]" : ""; },
+ true
+ );
+
+ var numberRE = dojo.regexp.buildGroupRE(flags.separator,
+ function(sep){
+ if(!sep){
+ return "(?:\\d+)";
+ }
+
+ sep = dojo.regexp.escapeString(sep);
+ if(sep == " "){ sep = "\\s"; }
+ else if(sep == "\xa0"){ sep = "\\s\\xa0"; }
+
+ var grp = flags.groupSize, grp2 = flags.groupSize2;
+ //TODO: should we continue to enforce that numbers with separators begin with 1-9? See #6933
+ if(grp2){
+ var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})";
+ return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE;
+ }
+ return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)";
+ },
+ true
+ );
+
+ return signRE + numberRE; // String
}
-return "(?:0|[1-9]\\d{0,"+(grp-1)+"}(?:["+sep+"]\\d{"+grp+"})*)";
-},true);
-return _46+_47;
-};
+
}
diff --git a/lib/dojo/parser.js b/lib/dojo/parser.js
index 245528328..7ae035691 100644
--- a/lib/dojo/parser.js
+++ b/lib/dojo/parser.js
@@ -5,268 +5,448 @@
*/
-if(!dojo._hasResource["dojo.parser"]){
-dojo._hasResource["dojo.parser"]=true;
+if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.parser"] = true;
dojo.provide("dojo.parser");
dojo.require("dojo.date.stamp");
-new Date("X");
-dojo.parser=new function(){
-var d=dojo;
-this._attrName=d._scopeName+"Type";
-this._query="["+this._attrName+"]";
-function _1(_2){
-if(d.isString(_2)){
-return "string";
-}
-if(typeof _2=="number"){
-return "number";
-}
-if(typeof _2=="boolean"){
-return "boolean";
-}
-if(d.isFunction(_2)){
-return "function";
-}
-if(d.isArray(_2)){
-return "array";
-}
-if(_2 instanceof Date){
-return "date";
-}
-if(_2 instanceof d._Url){
-return "url";
-}
-return "object";
-};
-function _3(_4,_5){
-switch(_5){
-case "string":
-return _4;
-case "number":
-return _4.length?Number(_4):NaN;
-case "boolean":
-return typeof _4=="boolean"?_4:!(_4.toLowerCase()=="false");
-case "function":
-if(d.isFunction(_4)){
-_4=_4.toString();
-_4=d.trim(_4.substring(_4.indexOf("{")+1,_4.length-1));
-}
-try{
-if(_4===""||_4.search(/[^\w\.]+/i)!=-1){
-return new Function(_4);
-}else{
-return d.getObject(_4,false)||new Function(_4);
-}
-}
-catch(e){
-return new Function();
-}
-case "array":
-return _4?_4.split(/\s*,\s*/):[];
-case "date":
-switch(_4){
-case "":
-return new Date("");
-case "now":
-return new Date();
-default:
-return d.date.stamp.fromISOString(_4);
-}
-case "url":
-return d.baseUrl+_4;
-default:
-return d.fromJson(_4);
-}
-};
-var _6={};
-dojo.connect(dojo,"extend",function(){
-_6={};
-});
-function _7(_8){
-if(!_6[_8]){
-var _9=d.getObject(_8);
-if(!_9){
-return null;
-}
-var _a=_9.prototype;
-var _b={},_c={};
-for(var _d in _a){
-if(_d.charAt(0)=="_"){
-continue;
-}
-if(_d in _c){
-continue;
-}
-var _e=_a[_d];
-_b[_d]=_1(_e);
-}
-_6[_8]={cls:_9,params:_b};
-}
-return _6[_8];
-};
-this._functionFromScript=function(_f){
-var _10="";
-var _11="";
-var _12=_f.getAttribute("args");
-if(_12){
-d.forEach(_12.split(/\s*,\s*/),function(_13,idx){
-_10+="var "+_13+" = arguments["+idx+"]; ";
-});
-}
-var _14=_f.getAttribute("with");
-if(_14&&_14.length){
-d.forEach(_14.split(/\s*,\s*/),function(_15){
-_10+="with("+_15+"){";
-_11+="}";
-});
-}
-return new Function(_10+_f.innerHTML+_11);
-};
-this.instantiate=function(_16,_17,_18){
-var _19=[],dp=dojo.parser;
-_17=_17||{};
-_18=_18||{};
-d.forEach(_16,function(obj){
-if(!obj){
-return;
-}
-var _1a,_1b,_1c,_1d,_1e;
-if(obj.node){
-_1a=obj.node;
-_1b=obj.type;
-_1c=obj.clsInfo||(_1b&&_7(_1b));
-_1d=_1c&&_1c.cls;
-_1e=obj.scripts;
-}else{
-_1a=obj;
-_1b=dp._attrName in _17?_17[dp._attrName]:_1a.getAttribute(dp._attrName);
-_1c=_1b&&_7(_1b);
-_1d=_1c&&_1c.cls;
-_1e=(_1d&&(_1d._noScript||_1d.prototype._noScript)?[]:d.query("> script[type^='dojo/']",_1a));
-}
-if(!_1c){
-throw new Error("Could not load class '"+_1b);
-}
-var _1f={},_20=_1a.attributes;
-if(_18.defaults){
-dojo.mixin(_1f,_18.defaults);
-}
-if(obj.inherited){
-dojo.mixin(_1f,obj.inherited);
-}
-for(var _21 in _1c.params){
-var _22=_21 in _17?{value:_17[_21],specified:true}:_20.getNamedItem(_21);
-if(!_22||(!_22.specified&&(!dojo.isIE||_21.toLowerCase()!="value"))){
-continue;
-}
-var _23=_22.value;
-switch(_21){
-case "class":
-_23="className" in _17?_17.className:_1a.className;
-break;
-case "style":
-_23="style" in _17?_17.style:(_1a.style&&_1a.style.cssText);
-}
-var _24=_1c.params[_21];
-if(typeof _23=="string"){
-_1f[_21]=_3(_23,_24);
-}else{
-_1f[_21]=_23;
-}
-}
-var _25=[],_26=[];
-d.forEach(_1e,function(_27){
-_1a.removeChild(_27);
-var _28=_27.getAttribute("event"),_1b=_27.getAttribute("type"),nf=d.parser._functionFromScript(_27);
-if(_28){
-if(_1b=="dojo/connect"){
-_25.push({event:_28,func:nf});
-}else{
-_1f[_28]=nf;
-}
-}else{
-_26.push(nf);
-}
-});
-var _29=_1d.markupFactory||_1d.prototype&&_1d.prototype.markupFactory;
-var _2a=_29?_29(_1f,_1a,_1d):new _1d(_1f,_1a);
-_19.push(_2a);
-var _2b=_1a.getAttribute("jsId");
-if(_2b){
-d.setObject(_2b,_2a);
-}
-d.forEach(_25,function(_2c){
-d.connect(_2a,_2c.event,null,_2c.func);
-});
-d.forEach(_26,function(_2d){
-_2d.call(_2a);
-});
-});
-if(!_17._started){
-d.forEach(_19,function(_2e){
-if(!_18.noStart&&_2e&&_2e.startup&&!_2e._started&&(!_2e.getParent||!_2e.getParent())){
-_2e.startup();
-}
-});
-}
-return _19;
-};
-this.parse=function(_2f,_30){
-var _31;
-if(!_30&&_2f&&_2f.rootNode){
-_30=_2f;
-_31=_30.rootNode;
-}else{
-_31=_2f;
-}
-var _32=this._attrName;
-function _33(_34,_35){
-var _36=dojo.clone(_34.inherited);
-dojo.forEach(["dir","lang"],function(_37){
-var val=_34.node.getAttribute(_37);
-if(val){
-_36[_37]=val;
-}
-});
-var _38=_34.scripts;
-var _39=!_34.clsInfo||!_34.clsInfo.cls.prototype.stopParser;
-for(var _3a=_34.node.firstChild;_3a;_3a=_3a.nextSibling){
-if(_3a.nodeType==1){
-var _3b=_39&&_3a.getAttribute(_32);
-if(_3b){
-var _3c={"type":_3b,clsInfo:_7(_3b),node:_3a,scripts:[],inherited:_36};
-_35.push(_3c);
-_33(_3c,_35);
-}else{
-if(_38&&_3a.nodeName.toLowerCase()=="script"){
-_3b=_3a.getAttribute("type");
-if(_3b&&/^dojo\//i.test(_3b)){
-_38.push(_3a);
-}
-}else{
-if(_39){
-_33({node:_3a,inherited:_36},_35);
-}
-}
-}
-}
-}
-};
-var _3d=[];
-_33({node:_31?dojo.byId(_31):dojo.body(),inherited:(_30&&_30.inherited)||{dir:dojo._isBodyLtr()?"ltr":"rtl"}},_3d);
-return this.instantiate(_3d,null,_30);
-};
+
+new Date("X"); // workaround for #11279, new Date("") == NaN
+
+dojo.parser = new function(){
+ // summary: The Dom/Widget parsing package
+
+ var d = dojo;
+ this._attrName = d._scopeName + "Type";
+ this._query = "[" + this._attrName + "]";
+
+ function val2type(/*Object*/ value){
+ // summary:
+ // Returns name of type of given value.
+
+ if(d.isString(value)){ return "string"; }
+ if(typeof value == "number"){ return "number"; }
+ if(typeof value == "boolean"){ return "boolean"; }
+ if(d.isFunction(value)){ return "function"; }
+ if(d.isArray(value)){ return "array"; } // typeof [] == "object"
+ if(value instanceof Date) { return "date"; } // assume timestamp
+ if(value instanceof d._Url){ return "url"; }
+ return "object";
+ }
+
+ function str2obj(/*String*/ value, /*String*/ type){
+ // summary:
+ // Convert given string value to given type
+ switch(type){
+ case "string":
+ return value;
+ case "number":
+ return value.length ? Number(value) : NaN;
+ case "boolean":
+ // for checked/disabled value might be "" or "checked". interpret as true.
+ return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
+ case "function":
+ if(d.isFunction(value)){
+ // IE gives us a function, even when we say something like onClick="foo"
+ // (in which case it gives us an invalid function "function(){ foo }").
+ // Therefore, convert to string
+ value=value.toString();
+ value=d.trim(value.substring(value.indexOf('{')+1, value.length-1));
+ }
+ try{
+ if(value === "" || value.search(/[^\w\.]+/i) != -1){
+ // The user has specified some text for a function like "return x+5"
+ return new Function(value);
+ }else{
+ // The user has specified the name of a function like "myOnClick"
+ // or a single word function "return"
+ return d.getObject(value, false) || new Function(value);
+ }
+ }catch(e){ return new Function(); }
+ case "array":
+ return value ? value.split(/\s*,\s*/) : [];
+ case "date":
+ switch(value){
+ case "": return new Date(""); // the NaN of dates
+ case "now": return new Date(); // current date
+ default: return d.date.stamp.fromISOString(value);
+ }
+ case "url":
+ return d.baseUrl + value;
+ default:
+ return d.fromJson(value);
+ }
+ }
+
+ var instanceClasses = {
+ // map from fully qualified name (like "dijit.Button") to structure like
+ // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
+ };
+
+ // Widgets like BorderContainer add properties to _Widget via dojo.extend().
+ // If BorderContainer is loaded after _Widget's parameter list has been cached,
+ // we need to refresh that parameter list (for _Widget and all widgets that extend _Widget).
+ dojo.connect(dojo, "extend", function(){
+ instanceClasses = {};
+ });
+
+ function getClassInfo(/*String*/ className){
+ // className:
+ // fully qualified name (like "dijit.form.Button")
+ // returns:
+ // structure like
+ // {
+ // cls: dijit.Button,
+ // params: { label: "string", disabled: "boolean"}
+ // }
+
+ if(!instanceClasses[className]){
+ // get pointer to widget class
+ var cls = d.getObject(className);
+ if(!cls){ return null; } // class not defined [yet]
+
+ var proto = cls.prototype;
+
+ // get table of parameter names & types
+ var params = {}, dummyClass = {};
+ for(var name in proto){
+ if(name.charAt(0)=="_"){ continue; } // skip internal properties
+ if(name in dummyClass){ continue; } // skip "constructor" and "toString"
+ var defVal = proto[name];
+ params[name]=val2type(defVal);
+ }
+
+ instanceClasses[className] = { cls: cls, params: params };
+ }
+ return instanceClasses[className];
+ }
+
+ this._functionFromScript = function(script){
+ var preamble = "";
+ var suffix = "";
+ var argsStr = script.getAttribute("args");
+ if(argsStr){
+ d.forEach(argsStr.split(/\s*,\s*/), function(part, idx){
+ preamble += "var "+part+" = arguments["+idx+"]; ";
+ });
+ }
+ var withStr = script.getAttribute("with");
+ if(withStr && withStr.length){
+ d.forEach(withStr.split(/\s*,\s*/), function(part){
+ preamble += "with("+part+"){";
+ suffix += "}";
+ });
+ }
+ return new Function(preamble+script.innerHTML+suffix);
+ }
+
+ this.instantiate = function(/* Array */nodes, /* Object? */mixin, /* Object? */args){
+ // summary:
+ // Takes array of nodes, and turns them into class instances and
+ // potentially calls a startup method to allow them to connect with
+ // any children.
+ // nodes: Array
+ // Array of nodes or objects like
+ // | {
+ // | type: "dijit.form.Button",
+ // | node: DOMNode,
+ // | scripts: [ ... ], // array of <script type="dojo/..."> children of node
+ // | inherited: { ... } // settings inherited from ancestors like dir, theme, etc.
+ // | }
+ // mixin: Object?
+ // An object that will be mixed in with each node in the array.
+ // Values in the mixin will override values in the node, if they
+ // exist.
+ // args: Object?
+ // An object used to hold kwArgs for instantiation.
+ // Supports 'noStart' and inherited.
+ var thelist = [], dp = dojo.parser;
+ mixin = mixin||{};
+ args = args||{};
+
+ d.forEach(nodes, function(obj){
+ if(!obj){ return; }
+
+ // Get pointers to DOMNode, dojoType string, and clsInfo (metadata about the dojoType), etc.s
+ var node, type, clsInfo, clazz, scripts;
+ if(obj.node){
+ // new format of nodes[] array, object w/lots of properties pre-computed for me
+ node = obj.node;
+ type = obj.type;
+ clsInfo = obj.clsInfo || (type && getClassInfo(type));
+ clazz = clsInfo && clsInfo.cls;
+ scripts = obj.scripts;
+ }else{
+ // old (backwards compatible) format of nodes[] array, simple array of DOMNodes
+ node = obj;
+ type = dp._attrName in mixin ? mixin[dp._attrName] : node.getAttribute(dp._attrName);
+ clsInfo = type && getClassInfo(type);
+ clazz = clsInfo && clsInfo.cls;
+ scripts = (clazz && (clazz._noScript || clazz.prototype._noScript) ? [] :
+ d.query("> script[type^='dojo/']", node));
+ }
+ if(!clsInfo){
+ throw new Error("Could not load class '" + type);
+ }
+
+ // Setup hash to hold parameter settings for this widget. Start with the parameter
+ // settings inherited from ancestors ("dir" and "lang").
+ // Inherited setting may later be overridden by explicit settings on node itself.
+ var params = {},
+ attributes = node.attributes;
+ if(args.defaults){
+ // settings for the document itself (or whatever subtree is being parsed)
+ dojo.mixin(params, args.defaults);
+ }
+ if(obj.inherited){
+ // settings from dir=rtl or lang=... on a node above this node
+ dojo.mixin(params, obj.inherited);
+ }
+
+ // read parameters (ie, attributes) specified on DOMNode
+ // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
+ for(var name in clsInfo.params){
+ var item = name in mixin?{value:mixin[name],specified:true}:attributes.getNamedItem(name);
+ if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; }
+ var value = item.value;
+ // Deal with IE quirks for 'class' and 'style'
+ switch(name){
+ case "class":
+ value = "className" in mixin?mixin.className:node.className;
+ break;
+ case "style":
+ value = "style" in mixin?mixin.style:(node.style && node.style.cssText); // FIXME: Opera?
+ }
+ var _type = clsInfo.params[name];
+ if(typeof value == "string"){
+ params[name] = str2obj(value, _type);
+ }else{
+ params[name] = value;
+ }
+ }
+
+ // Process <script type="dojo/*"> script tags
+ // <script type="dojo/method" event="foo"> tags are added to params, and passed to
+ // the widget on instantiation.
+ // <script type="dojo/method"> tags (with no event) are executed after instantiation
+ // <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation
+ // note: dojo/* script tags cannot exist in self closing widgets, like <input />
+ var connects = [], // functions to connect after instantiation
+ calls = []; // functions to call after instantiation
+
+ d.forEach(scripts, function(script){
+ node.removeChild(script);
+ var event = script.getAttribute("event"),
+ type = script.getAttribute("type"),
+ nf = d.parser._functionFromScript(script);
+ if(event){
+ if(type == "dojo/connect"){
+ connects.push({event: event, func: nf});
+ }else{
+ params[event] = nf;
+ }
+ }else{
+ calls.push(nf);
+ }
+ });
+
+ var markupFactory = clazz.markupFactory || clazz.prototype && clazz.prototype.markupFactory;
+ // create the instance
+ var instance = markupFactory ? markupFactory(params, node, clazz) : new clazz(params, node);
+ thelist.push(instance);
+
+ // map it to the JS namespace if that makes sense
+ var jsname = node.getAttribute("jsId");
+ if(jsname){
+ d.setObject(jsname, instance);
+ }
+
+ // process connections and startup functions
+ d.forEach(connects, function(connect){
+ d.connect(instance, connect.event, null, connect.func);
+ });
+ d.forEach(calls, function(func){
+ func.call(instance);
+ });
+ });
+
+ // Call startup on each top level instance if it makes sense (as for
+ // widgets). Parent widgets will recursively call startup on their
+ // (non-top level) children
+ if(!mixin._started){
+ // TODO: for 2.0, when old instantiate() API is desupported, store parent-child
+ // relationships in the nodes[] array so that no getParent() call is needed.
+ // Note that will require a parse() call from ContentPane setting a param that the
+ // ContentPane is the parent widget (so that the parse doesn't call startup() on the
+ // ContentPane's children)
+ d.forEach(thelist, function(instance){
+ if( !args.noStart && instance &&
+ instance.startup &&
+ !instance._started &&
+ (!instance.getParent || !instance.getParent())
+ ){
+ instance.startup();
+ }
+ });
+ }
+ return thelist;
+ };
+
+ this.parse = function(/*DomNode?*/ rootNode, /* Object? */ args){
+ // summary:
+ // Scan the DOM for class instances, and instantiate them.
+ //
+ // description:
+ // Search specified node (or root node) recursively for class instances,
+ // and instantiate them Searches for
+ // dojoType="qualified.class.name"
+ //
+ // rootNode: DomNode?
+ // A default starting root node from which to start the parsing. Can be
+ // omitted, defaulting to the entire document. If omitted, the `args`
+ // object can be passed in this place. If the `args` object has a
+ // `rootNode` member, that is used.
+ //
+ // args:
+ // a kwArgs object passed along to instantiate()
+ //
+ // * noStart: Boolean?
+ // when set will prevent the parser from calling .startup()
+ // when locating the nodes.
+ // * rootNode: DomNode?
+ // identical to the function's `rootNode` argument, though
+ // allowed to be passed in via this `args object.
+ // * inherited: Object
+ // Hash possibly containing dir and lang settings to be applied to
+ // parsed widgets, unless there's another setting on a sub-node that overrides
+ //
+ //
+ // example:
+ // Parse all widgets on a page:
+ // | dojo.parser.parse();
+ //
+ // example:
+ // Parse all classes within the node with id="foo"
+ // | dojo.parser.parse(dojo.byId(foo));
+ //
+ // example:
+ // Parse all classes in a page, but do not call .startup() on any
+ // child
+ // | dojo.parser.parse({ noStart: true })
+ //
+ // example:
+ // Parse all classes in a node, but do not call .startup()
+ // | dojo.parser.parse(someNode, { noStart:true });
+ // | // or
+ // | dojo.parser.parse({ noStart:true, rootNode: someNode });
+
+ // determine the root node based on the passed arguments.
+ var root;
+ if(!args && rootNode && rootNode.rootNode){
+ args = rootNode;
+ root = args.rootNode;
+ }else{
+ root = rootNode;
+ }
+
+ var attrName = this._attrName;
+ function scan(parent, list){
+ // summary:
+ // Parent is an Object representing a DOMNode, with or without a dojoType specified.
+ // Scan parent's children looking for nodes with dojoType specified, storing in list[].
+ // If parent has a dojoType, also collects <script type=dojo/*> children and stores in parent.scripts[].
+ // parent: Object
+ // Object representing the parent node, like
+ // | {
+ // | node: DomNode, // scan children of this node
+ // | inherited: {dir: "rtl"}, // dir/lang setting inherited from above node
+ // |
+ // | // attributes only set if node has dojoType specified
+ // | scripts: [], // empty array, put <script type=dojo/*> in here
+ // | clsInfo: { cls: dijit.form.Button, ...}
+ // | }
+ // list: DomNode[]
+ // Output array of objects (same format as parent) representing nodes to be turned into widgets
+
+ // Effective dir and lang settings on parent node, either set directly or inherited from grandparent
+ var inherited = dojo.clone(parent.inherited);
+ dojo.forEach(["dir", "lang"], function(name){
+ var val = parent.node.getAttribute(name);
+ if(val){
+ inherited[name] = val;
+ }
+ });
+
+ // if parent is a widget, then search for <script type=dojo/*> tags and put them in scripts[].
+ var scripts = parent.scripts;
+
+ // unless parent is a widget with the stopParser flag set, continue search for dojoType, recursively
+ var recurse = !parent.clsInfo || !parent.clsInfo.cls.prototype.stopParser;
+
+ // scan parent's children looking for dojoType and <script type=dojo/*>
+ for(var child = parent.node.firstChild; child; child = child.nextSibling){
+ if(child.nodeType == 1){
+ var type = recurse && child.getAttribute(attrName);
+ if(type){
+ // if dojoType specified, add to output array of nodes to instantiate
+ var params = {
+ "type": type,
+ clsInfo: getClassInfo(type), // note: won't find classes declared via dojo.Declaration
+ node: child,
+ scripts: [], // <script> nodes that are parent's children
+ inherited: inherited // dir & lang attributes inherited from parent
+ };
+ list.push(params);
+
+ // Recurse, collecting <script type="dojo/..."> children, and also looking for
+ // descendant nodes with dojoType specified (unless the widget has the stopParser flag),
+ scan(params, list);
+ }else if(scripts && child.nodeName.toLowerCase() == "script"){
+ // if <script type="dojo/...">, save in scripts[]
+ type = child.getAttribute("type");
+ if (type && /^dojo\//i.test(type)) {
+ scripts.push(child);
+ }
+ }else if(recurse){
+ // Recurse, looking for grandchild nodes with dojoType specified
+ scan({
+ node: child,
+ inherited: inherited
+ }, list);
+ }
+ }
+ }
+ }
+
+ // Make list of all nodes on page w/dojoType specified
+ var list = [];
+ scan({
+ node: root ? dojo.byId(root) : dojo.body(),
+ inherited: (args && args.inherited) || {
+ dir: dojo._isBodyLtr() ? "ltr" : "rtl"
+ }
+ }, list);
+
+ // go build the object instances
+ return this.instantiate(list, null, args); // Array
+ };
}();
+
+//Register the parser callback. It should be the first callback
+//after the a11y test.
+
(function(){
-var _3e=function(){
-if(dojo.config.parseOnLoad){
-dojo.parser.parse();
-}
-};
-if(dojo.exists("dijit.wai.onload")&&(dijit.wai.onload===dojo._loaders[0])){
-dojo._loaders.splice(1,0,_3e);
-}else{
-dojo._loaders.unshift(_3e);
-}
+ var parseRunner = function(){
+ if(dojo.config.parseOnLoad){
+ dojo.parser.parse();
+ }
+ };
+
+ // FIXME: need to clobber cross-dependency!!
+ if(dojo.exists("dijit.wai.onload") && (dijit.wai.onload === dojo._loaders[0])){
+ dojo._loaders.splice(1, 0, parseRunner);
+ }else{
+ dojo._loaders.unshift(parseRunner);
+ }
})();
+
}
diff --git a/lib/dojo/regexp.js b/lib/dojo/regexp.js
index 2c63514f3..1da68f452 100644
--- a/lib/dojo/regexp.js
+++ b/lib/dojo/regexp.js
@@ -5,28 +5,71 @@
*/
-if(!dojo._hasResource["dojo.regexp"]){
-dojo._hasResource["dojo.regexp"]=true;
+if(!dojo._hasResource["dojo.regexp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.regexp"] = true;
dojo.provide("dojo.regexp");
-dojo.regexp.escapeString=function(_1,_2){
-return _1.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g,function(ch){
-if(_2&&_2.indexOf(ch)!=-1){
-return ch;
-}
-return "\\"+ch;
-});
+
+/*=====
+dojo.regexp = {
+ // summary: Regular expressions and Builder resources
};
-dojo.regexp.buildGroupRE=function(_3,re,_4){
-if(!(_3 instanceof Array)){
-return re(_3);
+=====*/
+
+dojo.regexp.escapeString = function(/*String*/str, /*String?*/except){
+ // summary:
+ // Adds escape sequences for special characters in regular expressions
+ // except:
+ // a String with special characters to be left unescaped
+
+ return str.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, function(ch){
+ if(except && except.indexOf(ch) != -1){
+ return ch;
+ }
+ return "\\" + ch;
+ }); // String
}
-var b=[];
-for(var i=0;i<_3.length;i++){
-b.push(re(_3[i]));
+
+dojo.regexp.buildGroupRE = function(/*Object|Array*/arr, /*Function*/re, /*Boolean?*/nonCapture){
+ // summary:
+ // Builds a regular expression that groups subexpressions
+ // description:
+ // A utility function used by some of the RE generators. The
+ // subexpressions are constructed by the function, re, in the second
+ // parameter. re builds one subexpression for each elem in the array
+ // a, in the first parameter. Returns a string for a regular
+ // expression that groups all the subexpressions.
+ // arr:
+ // A single value or an array of values.
+ // re:
+ // A function. Takes one parameter and converts it to a regular
+ // expression.
+ // nonCapture:
+ // If true, uses non-capturing match, otherwise matches are retained
+ // by regular expression. Defaults to false
+
+ // case 1: a is a single value.
+ if(!(arr instanceof Array)){
+ return re(arr); // String
+ }
+
+ // case 2: a is an array
+ var b = [];
+ for(var i = 0; i < arr.length; i++){
+ // convert each elem to a RE
+ b.push(re(arr[i]));
+ }
+
+ // join the REs as alternatives in a RE group.
+ return dojo.regexp.group(b.join("|"), nonCapture); // String
}
-return dojo.regexp.group(b.join("|"),_4);
-};
-dojo.regexp.group=function(_5,_6){
-return "("+(_6?"?:":"")+_5+")";
-};
+
+dojo.regexp.group = function(/*String*/expression, /*Boolean?*/nonCapture){
+ // summary:
+ // adds group match to expression
+ // nonCapture:
+ // If true, uses non-capturing match, otherwise matches are retained
+ // by regular expression.
+ return "(" + (nonCapture ? "?:":"") + expression + ")"; // String
+}
+
}
diff --git a/lib/dojo/resources/_modules.js b/lib/dojo/resources/_modules.js
index 8d3fc5de7..ecfd266c4 100644
--- a/lib/dojo/resources/_modules.js
+++ b/lib/dojo/resources/_modules.js
@@ -5,3 +5,39 @@
*/
+/*=====
+// Supplemental summaries for those hard-to-doc places your conventional doc parser can't reach.
+// Where possible, these summaries should appear inline in the code.
+//
+// this is "package level documentation"
+
+dojo.cldr = {
+ // summary: transformation of relevant pieces of the Unicode.org Common Locale Data Repository
+ // (see http://unicode.org/cldr) to JSON from the original XML with associated utility classes
+};
+
+dojo.data = {
+ // summary: A uniform data access layer
+};
+
+dojo.dnd = {
+ // summary: Drag and Drop resources
+};
+
+dojo.io = {
+ // summary: Additional I/O transports (Ajax)
+};
+
+dojo.rpc = {
+ // summary: Dojo remote-procedure-call resources
+};
+
+// "variables"
+
+dojo.baseUrl = {
+ // summary: The root relative path to dojo.js (as a string)
+ // example:
+ // if(typeof dojo != "undefined"){ console.log(dojo.baseUrl); }
+};
+
+=====*/
diff --git a/lib/dojo/resources/dnd.css b/lib/dojo/resources/dnd.css
index def28fc95..b7f1651f9 100644
--- a/lib/dojo/resources/dnd.css
+++ b/lib/dojo/resources/dnd.css
@@ -1,4 +1,4 @@
-
+/* DnD avatar-specific settings */
.dojoDndAvatar {font-size: 75%; color: black;}
.dojoDndAvatarHeader td {padding-left: 20px; padding-right: 4px;}
.dojoDndAvatarHeader {background: #ccc;}
@@ -7,8 +7,10 @@
.dojoDndCopy .dojoDndAvatarHeader {background-image: url(images/dndNoCopy.png); background-repeat: no-repeat;}
.dojoDndMove .dojoDndAvatarCanDrop .dojoDndAvatarHeader {background-image: url(images/dndMove.png); background-repeat: no-repeat;}
.dojoDndCopy .dojoDndAvatarCanDrop .dojoDndAvatarHeader {background-image: url(images/dndCopy.png); background-repeat: no-repeat;}
+
.dojoDndHandle {cursor: move;}
.dojoDndIgnore {cursor: default;}
+
.dijit_a11y .dojoDndAvatar { font-size: 1em; font-weight:bold;}
.dijit_a11y .dojoDndAvatarHeader td {padding-left:2px !important;}
.dijit_a11y .dojoDndAvatarHeader td span {padding-right: 5px;}
diff --git a/lib/dojo/resources/dojo.css b/lib/dojo/resources/dojo.css
index baf06cb7b..fdaa84223 100644
--- a/lib/dojo/resources/dojo.css
+++ b/lib/dojo/resources/dojo.css
@@ -1,28 +1,101 @@
+/*
+ dojo.css
+ Baseline CSS file for general usage.
+
+ This file is intended to be a "quick and dirty" stylesheet you can use to give
+ a straight-up web page some basic styling without having to do the dirty work
+ yourself. It includes a modified version of YUI's reset.css (we pulled some
+ of the list reset definitions, among other things), and then provides some very
+ basic style rules to be applied to general HTML elements.
+
+ This stylesheet is NOT intended to serve as the foundation for more complex things--
+ including the use of a TABLE for layout purposes. The table definitions in this
+ file make the assumption that you will be using tables for thier declared purpose:
+ displaying tabular data.
+
+ If you are looking for a baseline stylesheet using tables for grid layout, you will
+ need to supply your own layout rules to override the ones in this stylesheet.
+
+ Applications using Dojo will function correctly without including this
+ file, but it should provide sane defaults for many common things that page
+ authors often need to set up manually.
+
+ The Dojo Core uses this stylesheet to quickly style HTML-based tests and demos. Feel
+ free to use it as you will.
+*/
+
+/*****************************************************************************************/
+
+/*
+ The below are borrowed from YUI's reset style sheets for pages and fonts.
+ We've verified w/ the YUI development team that these are entirely
+ copyright Yahoo, written entirely by Nate Koechley and Matt Sweeney without
+ external contributions.
+
+ Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ Code licensed under the BSD License:
+ http://developer.yahoo.net/yui/license.txt
+ version: 2.2.1
+*/
body, div, dl, dt, dd, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, input, textarea, p, blockquote, th, td {
margin: 0;
padding: 0;
}
+
fieldset, img {
border: 0 none;
}
+
address, caption, cite, code, dfn, th, var {
font-style: normal;
font-weight: normal;
}
+
caption, th {
text-align: left;
}
+
q:before, q:after {
content:"";
}
+
abbr, acronym {
border:0;
}
+/* End YUI imported code. */
+
+/*****************************************************************************************/
+
+/*
+ Begin Dojo additions.
+
+ Style definitions, based loosely on the Dijit Tundra theme.
+ Relative unit calculations based on "Compose to a Vertical Rhythm",
+ by Richard Rutter (http://24ways.org/2006/compose-to-a-vertical-rhythm)
+
+ If changing the font size, make sure you do it in both
+ percent and px (% for IE, px for everything else).
+ % value based on default size of 16px (in most browsers).
+ So if you want the default size to be 14px, set the
+ % to 87% (14 / 16 = 0.875).
+
+ Typical values:
+ 10px: 62.5%
+ 11px: 69% (68.75)
+ 12px: 75%
+ 13px: 81.25%
+ 14px: 87.5%
+ 16px: 100%
+
+ Default: 12px
+*/
body {
font: 12px Myriad,Helvetica,Tahoma,Arial,clean,sans-serif;
*font-size: 75%;
}
+
+/* Headings */
h1 {
font-size: 1.5em;
font-weight: normal;
@@ -30,6 +103,7 @@ h1 {
margin-top: 1em;
margin-bottom:0;
}
+
h2 {
font-size: 1.1667em;
font-weight: bold;
@@ -37,6 +111,7 @@ h2 {
margin-top: 1.929em;
margin-bottom:0.643em;
}
+
h3, h4, h5, h6 {
font-size: 1em;
font-weight: bold;
@@ -44,12 +119,15 @@ h3, h4, h5, h6 {
margin-top: 1.5em;
margin-bottom: 0;
}
+
+/* paragraphs, quotes and lists */
p {
font-size: 1em;
margin-top: 1.5em;
margin-bottom: 1.5em;
line-height: 1.5em;
}
+
blockquote {
font-size: 0.916em;
margin-top: 3.272em;
@@ -59,11 +137,14 @@ blockquote {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
+
ol li, ul li {
font-size: 1em;
line-height: 1.5em;
margin: 0;
}
+
+/* pre and code */
pre, code {
font-size:115%;
*font-size:100%;
@@ -71,27 +152,44 @@ pre, code {
background-color: #efefef;
border: 1px solid #ccc;
}
+
pre {
border-width: 1px 0;
padding: 1.5em;
}
+
+/*
+ Tables
+
+ Note that these table definitions make the assumption that you are using tables
+ to display tabular data, and NOT using tables as layout mechanisms. If you are
+ using tables for layout, you will probably want to override these rules with
+ more specific ones.
+
+ These definitions make tabular data look presentable, particularly when presented
+ inline with paragraphs.
+*/
table { font-size:100%; }
+
.dojoTabular {
border-collapse: collapse;
border-spacing: 0;
border: 1px solid #ccc;
margin: 0 1.5em;
}
+
.dojoTabular th {
text-align: center;
font-weight: bold;
}
+
.dojoTabular thead,
.dojoTabular tfoot {
background-color: #efefef;
border: 1px solid #ccc;
border-width: 1px 0;
}
+
.dojoTabular th,
.dojoTabular td {
padding: 0.25em 0.5em;
diff --git a/lib/dojo/robot.js b/lib/dojo/robot.js
index 88af37cef..6cbe0bebc 100644
--- a/lib/dojo/robot.js
+++ b/lib/dojo/robot.js
@@ -5,85 +5,181 @@
*/
-if(!dojo._hasResource["dojo.robot"]){
-dojo._hasResource["dojo.robot"]=true;
+if(!dojo._hasResource["dojo.robot"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.robot"] = true;
dojo.provide("dojo.robot");
dojo.experimental("dojo.robot");
dojo.require("doh.robot");
dojo.require("dojo.window");
+
(function(){
-dojo.mixin(doh.robot,{_resolveNode:function(n){
-if(typeof n=="function"){
-n=n();
-}
-return n?dojo.byId(n):null;
-},_scrollIntoView:function(n){
-var d=dojo,dr=doh.robot,p=null;
-d.forEach(dr._getWindowChain(n),function(w){
-d.withGlobal(w,function(){
-var p2=d.position(n,false),b=d._getPadBorderExtents(n),_1=null;
-if(!p){
-p=p2;
-}else{
-_1=p;
-p={x:p.x+p2.x+b.l,y:p.y+p2.y+b.t,w:p.w,h:p.h};
-}
-dojo.window.scrollIntoView(n,p);
-p2=d.position(n,false);
-if(!_1){
-p=p2;
-}else{
-p={x:_1.x+p2.x+b.l,y:_1.y+p2.y+b.t,w:p.w,h:p.h};
-}
-n=w.frameElement;
-});
-});
-},_position:function(n){
-var d=dojo,p=null,M=Math.max,m=Math.min;
-d.forEach(doh.robot._getWindowChain(n),function(w){
-d.withGlobal(w,function(){
-var p2=d.position(n,false),b=d._getPadBorderExtents(n);
-if(!p){
-p=p2;
-}else{
-var _2;
-d.withGlobal(n.contentWindow,function(){
-_2=dojo.window.getBox();
-});
-p2.r=p2.x+_2.w;
-p2.b=p2.y+_2.h;
-p={x:M(p.x+p2.x,p2.x)+b.l,y:M(p.y+p2.y,p2.y)+b.t,r:m(p.x+p2.x+p.w,p2.r)+b.l,b:m(p.y+p2.y+p.h,p2.b)+b.t};
-p.w=p.r-p.x;
-p.h=p.b-p.y;
-}
-n=w.frameElement;
-});
+// users who use doh+dojo get the added convenience of dojo.mouseMoveAt,
+// instead of computing the absolute coordinates of their elements themselves
+dojo.mixin(doh.robot,{
+
+ _resolveNode: function(/*String||DOMNode||Function*/ n){
+ if(typeof n == "function"){
+ // if the user passed a function returning a node, evaluate it
+ n = n();
+ }
+ return n? dojo.byId(n) : null;
+ },
+
+ _scrollIntoView: function(/*Node*/ n){
+ // scrolls the passed node into view, scrolling all ancester frames/windows as well.
+ // Assumes parent iframes can be made fully visible given the current browser window size
+ var d = dojo,
+ dr = doh.robot,
+ p = null;
+ d.forEach(dr._getWindowChain(n), function(w){
+ d.withGlobal(w, function(){
+ // get the position of the node wrt its parent window
+ // if it is a parent frame, its padding and border extents will get added in
+ var p2 = d.position(n, false),
+ b = d._getPadBorderExtents(n),
+ oldp = null;
+ // if p2 is the position of the original passed node, store the position away as p
+ // otherwise, node is actually an iframe. in this case, add the iframe's position wrt its parent window and also the iframe's padding and border extents
+ if(!p){
+ p = p2;
+ }else{
+ oldp = p;
+ p = {x: p.x+p2.x+b.l,
+ y: p.y+p2.y+b.t,
+ w: p.w,
+ h: p.h};
+
+ }
+ // scroll the parent window so that the node translated into the parent window's coordinate space is in view
+ dojo.window.scrollIntoView(n,p);
+ // adjust position for the new scroll offsets
+ p2 = d.position(n, false);
+ if(!oldp){
+ p = p2;
+ }else{
+ p = {x: oldp.x+p2.x+b.l,
+ y: oldp.y+p2.y+b.t,
+ w: p.w,
+ h: p.h};
+ }
+ // get the parent iframe so it can be scrolled too
+ n = w.frameElement;
+ });
+ });
+ },
+
+ _position: function(/*Node*/ n){
+ // Returns the dojo.position of the passed node wrt the passed window's viewport,
+ // following any parent iframes containing the node and clipping the node to each iframe.
+ // precondition: _scrollIntoView already called
+ var d = dojo, p = null, M = Math.max, m = Math.min;
+ // p: the returned position of the node
+ d.forEach(doh.robot._getWindowChain(n), function(w){
+ d.withGlobal(w, function(){
+ // get the position of the node wrt its parent window
+ // if it is a parent frame, its padding and border extents will get added in
+ var p2 = d.position(n, false), b = d._getPadBorderExtents(n);
+ // if p2 is the position of the original passed node, store the position away as p
+ // otherwise, node is actually an iframe. in this case, add the iframe's position wrt its parent window and also the iframe's padding and border extents
+ if(!p){
+ p = p2;
+ }else{
+ var view;
+ d.withGlobal(n.contentWindow,function(){
+ view=dojo.window.getBox();
+ });
+ p2.r = p2.x+view.w;
+ p2.b = p2.y+view.h;
+ p = {x: M(p.x+p2.x,p2.x)+b.l, // clip left edge of node wrt the iframe
+ y: M(p.y+p2.y,p2.y)+b.t, // top edge
+ r: m(p.x+p2.x+p.w,p2.r)+b.l, // right edge (to compute width)
+ b: m(p.y+p2.y+p.h,p2.b)+b.t}; // bottom edge (to compute height)
+ // save a few bytes by computing width and height from r and b
+ p.w = p.r-p.x;
+ p.h = p.b-p.y;
+ }
+ // the new node is now the old node's parent iframe
+ n=w.frameElement;
+ });
+ });
+ return p;
+ },
+
+ _getWindowChain : function(/*Node*/ n){
+ // Returns an array of windows starting from the passed node's parent window and ending at dojo's window
+ var cW = dojo.window.get(n.ownerDocument);
+ var arr=[cW];
+ var f = cW.frameElement;
+ return (cW == dojo.global || f == null)? arr : arr.concat(doh.robot._getWindowChain(f));
+ },
+
+ scrollIntoView : function(/*String||DOMNode||Function*/ node, /*Number, optional*/ delay){
+ // summary:
+ // Scroll the passed node into view, if it is not.
+ //
+ // node:
+ // The id of the node, or the node itself, to move the mouse to.
+ // If you pass an id or a function that returns a node, the node will not be evaluated until the movement executes.
+ // This is useful if you need to move the mouse to an node that is not yet present.
+ //
+ // delay:
+ // Delay, in milliseconds, to wait before firing.
+ // The delay is a delta with respect to the previous automation call.
+ //
+ doh.robot.sequence(function(){
+ doh.robot._scrollIntoView(doh.robot._resolveNode(node));
+ }, delay);
+ },
+
+ mouseMoveAt : function(/*String||DOMNode||Function*/ node, /*Integer, optional*/ delay, /*Integer, optional*/ duration, /*Number, optional*/ offsetX, /*Number, optional*/ offsetY){
+ // summary:
+ // Moves the mouse over the specified node at the specified relative x,y offset.
+ //
+ // description:
+ // Moves the mouse over the specified node at the specified relative x,y offset.
+ // If you do not specify an offset, mouseMove will default to move to the middle of the node.
+ // Example: to move the mouse over a ComboBox's down arrow node, call doh.mouseMoveAt(dijit.byId('setvaluetest').downArrowNode);
+ //
+ // node:
+ // The id of the node, or the node itself, to move the mouse to.
+ // If you pass an id or a function that returns a node, the node will not be evaluated until the movement executes.
+ // This is useful if you need to move the mouse to an node that is not yet present.
+ //
+ // delay:
+ // Delay, in milliseconds, to wait before firing.
+ // The delay is a delta with respect to the previous automation call.
+ // For example, the following code ends after 600ms:
+ // doh.robot.mouseClick({left:true}, 100) // first call; wait 100ms
+ // doh.robot.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all
+ //
+ // duration:
+ // Approximate time Robot will spend moving the mouse
+ // The default is 100ms.
+ //
+ // offsetX:
+ // x offset relative to the node, in pixels, to move the mouse. The default is half the node's width.
+ //
+ // offsetY:
+ // y offset relative to the node, in pixels, to move the mouse. The default is half the node's height.
+ //
+
+ doh.robot._assertRobot();
+ duration = duration||100;
+ this.sequence(function(){
+ node=doh.robot._resolveNode(node);
+ doh.robot._scrollIntoView(node);
+ var pos = doh.robot._position(node);
+ if(offsetY === undefined){
+ offsetX=pos.w/2;
+ offsetY=pos.h/2;
+ }
+ var x = pos.x+offsetX;
+ var y = pos.y+offsetY;
+ doh.robot._mouseMove(x, y, false, duration);
+ }, delay, duration);
+ }
});
-return p;
-},_getWindowChain:function(n){
-var cW=dojo.window.get(n.ownerDocument);
-var _3=[cW];
-var f=cW.frameElement;
-return (cW==dojo.global||f==null)?_3:_3.concat(doh.robot._getWindowChain(f));
-},scrollIntoView:function(_4,_5){
-doh.robot.sequence(function(){
-doh.robot._scrollIntoView(doh.robot._resolveNode(_4));
-},_5);
-},mouseMoveAt:function(_6,_7,_8,_9,_a){
-doh.robot._assertRobot();
-_8=_8||100;
-this.sequence(function(){
-_6=doh.robot._resolveNode(_6);
-doh.robot._scrollIntoView(_6);
-var _b=doh.robot._position(_6);
-if(_a===undefined){
-_9=_b.w/2;
-_a=_b.h/2;
-}
-var x=_b.x+_9;
-var y=_b.y+_a;
-doh.robot._mouseMove(x,y,false,_8);
-},_7,_8);
-}});
+
})();
+
}
diff --git a/lib/dojo/robotx.js b/lib/dojo/robotx.js
index 5ed39000d..7f49b64a0 100644
--- a/lib/dojo/robotx.js
+++ b/lib/dojo/robotx.js
@@ -5,76 +5,136 @@
*/
-if(!dojo._hasResource["dojo.robotx"]){
-dojo._hasResource["dojo.robotx"]=true;
+if(!dojo._hasResource["dojo.robotx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.robotx"] = true;
dojo.provide("dojo.robotx");
dojo.require("dojo.robot");
dojo.experimental("dojo.robotx");
+
+// loads an external app into an iframe and points dojo.doc to the iframe document, allowing the robot to control it
+// to use: set robotURL in djConfig to the URL you want to load
+// dojo.require this file
+
(function(){
+// have to wait for test page to load before testing!
doh.robot._runsemaphore.lock.push("dojo.robotx.lock");
-var _1=document.getElementById("robotapplication");
-var _2=dojo.connect(doh,"_groupStarted",function(){
-dojo.disconnect(_2);
-_1.style.visibility="visible";
+
+var iframe = document.getElementById('robotapplication');
+
+var groupStarted=dojo.connect(doh, '_groupStarted', function(){
+ dojo.disconnect(groupStarted);
+ iframe.style.visibility="visible";
});
-var _3=function(){
-doh.robot._updateDocument();
-_3=null;
-var _4=(document.compatMode=="BackCompat")?document.body:document.documentElement;
-var _5=document.getElementById("robotconsole").offsetHeight;
-if(_5){
-_1.style.height=(_4.clientHeight-_5)+"px";
-}
-doh.run();
+
+var onIframeLoad=function(){
+ //iframe = document.getElementById('robotapplication');
+ doh.robot._updateDocument();
+ onIframeLoad = null;
+ var scrollRoot = (document.compatMode == 'BackCompat')? document.body : document.documentElement;
+ var consoleHeight = document.getElementById('robotconsole').offsetHeight;
+ if(consoleHeight){
+ iframe.style.height = (scrollRoot.clientHeight - consoleHeight)+"px";
+ }
+ doh.run();
};
-var _6=function(){
-if(_3){
-_3();
-}
-var _7=dojo.connect(dojo.body(),"onunload",function(){
-dojo.global=window;
-dojo.doc=document;
-dojo.disconnect(_7);
-});
+
+var iframeLoad=function(){
+ if(onIframeLoad){
+ onIframeLoad();
+ }
+ var unloadConnect = dojo.connect(dojo.body(), 'onunload', function(){
+ dojo.global = window;
+ dojo.doc = document;
+ dojo.disconnect(unloadConnect);
+ });
};
-dojo.config.debugContainerId="robotconsole";
-dojo.config.debugHeight=dojo.config.debugHeight||200;
-document.write("<div id=\"robotconsole\" style=\"position:absolute;left:0px;bottom:0px;width:100%;\"></div>");
-_1=document.createElement("iframe");
-_1.setAttribute("ALLOWTRANSPARENCY","true");
-_1.scrolling=dojo.isIE?"yes":"auto";
-dojo.style(_1,{visibility:"hidden",border:"0px none",padding:"0px",margin:"0px",position:"absolute",left:"0px",top:"0px",width:"100%",height:"100%"});
-if(_1["attachEvent"]!==undefined){
-_1.attachEvent("onload",_6);
+
+// write the firebug console to a place it will fit
+dojo.config.debugContainerId = "robotconsole";
+dojo.config.debugHeight = dojo.config.debugHeight || 200;
+document.write('<div id="robotconsole" style="position:absolute;left:0px;bottom:0px;width:100%;"></div>');
+
+// write the iframe
+//document.writeln('<iframe id="robotapplication" style="visibility:hidden; border:0px none; padding:0px; margin:0px; position:absolute; left:0px; top:0px; width:100%; height:100%; z-index: 1;" src="'+dojo.config.robotURL+'" onload="iframeLoad();" ></iframe>');
+iframe = document.createElement('iframe');
+iframe.setAttribute("ALLOWTRANSPARENCY","true");
+iframe.scrolling = dojo.isIE? "yes" : "auto";
+dojo.style(iframe,{visibility:'hidden', border:'0px none', padding:'0px', margin:'0px', position:'absolute', left:'0px', top:'0px', width:'100%', height:'100%'});
+if(iframe['attachEvent'] !== undefined){
+ iframe.attachEvent('onload', iframeLoad);
}else{
-dojo.connect(_1,"onload",_6);
-}
-dojo.mixin(doh.robot,{_updateDocument:function(){
-dojo.setContext(_1.contentWindow,_1.contentWindow.document);
-var _8=dojo.global;
-if(_8["dojo"]){
-dojo._topics=_8.dojo._topics;
+ dojo.connect(iframe, 'onload', iframeLoad);
}
-},initRobot:function(_9){
-_1.src=_9;
-dojo.addOnLoad(function(){
-var _a={overflow:dojo.isWebKit?"hidden":"visible",margin:"0px",borderWidth:"0px",height:"100%",width:"100%"};
-dojo.style(document.documentElement,_a);
-dojo.style(document.body,_a);
-document.body.appendChild(_1);
-var _b=document.createElement("base");
-_b.href=_9;
-document.getElementsByTagName("head")[0].appendChild(_b);
+
+dojo.mixin(doh.robot,{
+ _updateDocument: function(){
+ dojo.setContext(iframe.contentWindow, iframe.contentWindow.document);
+ var win = dojo.global;
+ if(win["dojo"]){
+ // allow the tests to subscribe to topics published by the iframe
+ dojo._topics = win.dojo._topics;
+ }
+
+ },
+
+ initRobot: function(/*String*/ url){
+ // summary:
+ // Opens the application at the specified URL for testing, redirecting dojo to point to the application environment instead of the test environment.
+ //
+ // url:
+ // URL to open. Any of the test's dojo.doc calls (e.g. dojo.byId()), and any dijit.registry calls (e.g. dijit.byId()) will point to elements and widgets inside this application.
+ //
+ iframe.src=url;
+ dojo.addOnLoad(function(){
+ var emptyStyle = {
+ overflow: dojo.isWebKit? 'hidden' : 'visible',
+ margin: '0px',
+ borderWidth: '0px',
+ height: '100%',
+ width: '100%'
+ };
+ dojo.style(document.documentElement, emptyStyle);
+ dojo.style(document.body, emptyStyle);
+ document.body.appendChild(iframe);
+ var base=document.createElement('base');
+ base.href=url;
+ document.getElementsByTagName("head")[0].appendChild(base);
+ });
+ },
+
+ waitForPageToLoad: function(/*Function*/ submitActions){
+ // summary:
+ // Notifies DOH that the doh.robot is about to make a page change in the application it is driving,
+ // returning a doh.Deferred object the user should return in their runTest function as part of a DOH test.
+ //
+ // description:
+ // Notifies DOH that the doh.robot is about to make a page change in the application it is driving,
+ // returning a doh.Deferred object the user should return in their runTest function as part of a DOH test.
+ // Example:
+ // runTest:function(){
+ // return waitForPageLoad(function(){ doh.robot.keyPress(dojo.keys.ENTER, 500); });
+ // }
+ //
+ // submitActions:
+ // The doh.robot will execute the actions the test passes into the submitActions argument (like clicking the submit button),
+ // expecting these actions to create a page change (like a form submit).
+ // After these actions execute and the resulting page loads, the next test will start.
+ //
+
+ var d = new doh.Deferred();
+ // create iframe event handler to track submit progress
+ onIframeLoad = function(){
+ onIframeLoad = null;
+ // set dojo.doc on every page change to point to the iframe doc so the robot works
+ doh.robot._updateDocument();
+ d.callback(true);
+ };
+ submitActions();
+ return d;
+ }
+
});
-},waitForPageToLoad:function(_c){
-var d=new doh.Deferred();
-_3=function(){
-_3=null;
-doh.robot._updateDocument();
-d.callback(true);
-};
-_c();
-return d;
-}});
+
})();
+
}
diff --git a/lib/dojo/rpc/JsonService.js b/lib/dojo/rpc/JsonService.js
index b88e5f531..757e328be 100644
--- a/lib/dojo/rpc/JsonService.js
+++ b/lib/dojo/rpc/JsonService.js
@@ -5,33 +5,86 @@
*/
-if(!dojo._hasResource["dojo.rpc.JsonService"]){
-dojo._hasResource["dojo.rpc.JsonService"]=true;
+if(!dojo._hasResource["dojo.rpc.JsonService"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.rpc.JsonService"] = true;
dojo.provide("dojo.rpc.JsonService");
dojo.require("dojo.rpc.RpcService");
-dojo.declare("dojo.rpc.JsonService",dojo.rpc.RpcService,{bustCache:false,contentType:"application/json-rpc",lastSubmissionId:0,callRemote:function(_1,_2){
-var _3=new dojo.Deferred();
-this.bind(_1,_2,_3);
-return _3;
-},bind:function(_4,_5,_6,_7){
-var _8=dojo.rawXhrPost({url:_7||this.serviceUrl,postData:this.createRequest(_4,_5),contentType:this.contentType,timeout:this.timeout,handleAs:"json-comment-optional"});
-_8.addCallbacks(this.resultCallback(_6),this.errorCallback(_6));
-},createRequest:function(_9,_a){
-var _b={"params":_a,"method":_9,"id":++this.lastSubmissionId};
-var _c=dojo.toJson(_b);
-return _c;
-},parseResults:function(_d){
-if(dojo.isObject(_d)){
-if("result" in _d){
-return _d.result;
-}
-if("Result" in _d){
-return _d.Result;
-}
-if("ResultSet" in _d){
-return _d.ResultSet;
-}
-}
-return _d;
-}});
+
+dojo.declare("dojo.rpc.JsonService", dojo.rpc.RpcService, {
+ bustCache: false,
+ contentType: "application/json-rpc",
+ lastSubmissionId: 0,
+
+ callRemote: function(method, params){
+ // summary:
+ // call an arbitrary remote method without requiring it to be
+ // predefined with SMD
+ // method: string
+ // the name of the remote method you want to call.
+ // params: array
+ // array of parameters to pass to method
+
+ var deferred = new dojo.Deferred();
+ this.bind(method, params, deferred);
+ return deferred;
+ },
+
+ bind: function(method, parameters, deferredRequestHandler, url){
+ //summary:
+ // JSON-RPC bind method. Takes remote method, parameters,
+ // deferred, and a url, calls createRequest to make a JSON-RPC
+ // envelope and passes that off with bind.
+ // method: string
+ // The name of the method we are calling
+ // parameters: array
+ // The parameters we are passing off to the method
+ // deferredRequestHandler: deferred
+ // The Deferred object for this particular request
+
+ var def = dojo.rawXhrPost({
+ url: url||this.serviceUrl,
+ postData: this.createRequest(method, parameters),
+ contentType: this.contentType,
+ timeout: this.timeout,
+ handleAs: "json-comment-optional"
+ });
+ def.addCallbacks(this.resultCallback(deferredRequestHandler), this.errorCallback(deferredRequestHandler));
+ },
+
+ createRequest: function(method, params){
+ // summary:
+ // create a JSON-RPC envelope for the request
+ // method: string
+ // The name of the method we are creating the requst for
+ // params: array
+ // The array of parameters for this request;
+
+ var req = { "params": params, "method": method, "id": ++this.lastSubmissionId };
+ var data = dojo.toJson(req);
+ return data;
+ },
+
+ parseResults: function(/*anything*/obj){
+ //summary:
+ // parse the result envelope and pass the results back to
+ // the callback function
+ // obj: Object
+ // Object containing envelope of data we recieve from the server
+
+ if(dojo.isObject(obj)){
+ if("result" in obj){
+ return obj.result;
+ }
+ if("Result" in obj){
+ return obj.Result;
+ }
+ if("ResultSet" in obj){
+ return obj.ResultSet;
+ }
+ }
+ return obj;
+ }
+ }
+);
+
}
diff --git a/lib/dojo/rpc/JsonpService.js b/lib/dojo/rpc/JsonpService.js
index 68c971207..31e95077b 100644
--- a/lib/dojo/rpc/JsonpService.js
+++ b/lib/dojo/rpc/JsonpService.js
@@ -5,28 +5,68 @@
*/
-if(!dojo._hasResource["dojo.rpc.JsonpService"]){
-dojo._hasResource["dojo.rpc.JsonpService"]=true;
+if(!dojo._hasResource["dojo.rpc.JsonpService"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.rpc.JsonpService"] = true;
dojo.provide("dojo.rpc.JsonpService");
dojo.require("dojo.rpc.RpcService");
dojo.require("dojo.io.script");
-dojo.declare("dojo.rpc.JsonpService",dojo.rpc.RpcService,{constructor:function(_1,_2){
-if(this.required){
-if(_2){
-dojo.mixin(this.required,_2);
-}
-dojo.forEach(this.required,function(_3){
-if(_3==""||_3==undefined){
-throw new Error("Required Service Argument not found: "+_3);
-}
+
+dojo.declare("dojo.rpc.JsonpService", dojo.rpc.RpcService, {
+ // summary:
+ // Generic JSONP service. Minimally extends RpcService to allow
+ // easy definition of nearly any JSONP style service. Example
+ // SMD files exist in dojox.data
+
+ constructor: function(args, requiredArgs){
+ if(this.required) {
+ if(requiredArgs){
+ dojo.mixin(this.required, requiredArgs);
+ }
+
+ dojo.forEach(this.required, function(req){
+ if(req=="" || req==undefined){
+ throw new Error("Required Service Argument not found: "+req);
+ }
+ });
+ }
+ },
+
+ strictArgChecks: false,
+
+ bind: function(method, parameters, deferredRequestHandler, url){
+ //summary:
+ // JSONP bind method. Takes remote method, parameters,
+ // deferred, and a url, calls createRequest to make a JSON-RPC
+ // envelope and passes that off with bind.
+ // method: string
+ // The name of the method we are calling
+ // parameters: array
+ // The parameters we are passing off to the method
+ // deferredRequestHandler: deferred
+ // The Deferred object for this particular request
+
+ var def = dojo.io.script.get({
+ url: url||this.serviceUrl,
+ callbackParamName: this.callbackParamName||"callback",
+ content: this.createRequest(parameters),
+ timeout: this.timeout,
+ handleAs: "json",
+ preventCache: true
+ });
+ def.addCallbacks(this.resultCallback(deferredRequestHandler), this.errorCallback(deferredRequestHandler));
+ },
+
+ createRequest: function(parameters){
+ // summary:
+ // create a JSONP req
+ // params: array
+ // The array of parameters for this request;
+
+ var params = (dojo.isArrayLike(parameters) && parameters.length==1) ?
+ parameters[0] : {};
+ dojo.mixin(params,this.required);
+ return params;
+ }
});
-}
-},strictArgChecks:false,bind:function(_4,_5,_6,_7){
-var _8=dojo.io.script.get({url:_7||this.serviceUrl,callbackParamName:this.callbackParamName||"callback",content:this.createRequest(_5),timeout:this.timeout,handleAs:"json",preventCache:true});
-_8.addCallbacks(this.resultCallback(_6),this.errorCallback(_6));
-},createRequest:function(_9){
-var _a=(dojo.isArrayLike(_9)&&_9.length==1)?_9[0]:{};
-dojo.mixin(_a,this.required);
-return _a;
-}});
+
}
diff --git a/lib/dojo/rpc/RpcService.js b/lib/dojo/rpc/RpcService.js
index 03c6a46b6..7ff71415e 100644
--- a/lib/dojo/rpc/RpcService.js
+++ b/lib/dojo/rpc/RpcService.js
@@ -5,85 +5,175 @@
*/
-if(!dojo._hasResource["dojo.rpc.RpcService"]){
-dojo._hasResource["dojo.rpc.RpcService"]=true;
+if(!dojo._hasResource["dojo.rpc.RpcService"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.rpc.RpcService"] = true;
dojo.provide("dojo.rpc.RpcService");
-dojo.declare("dojo.rpc.RpcService",null,{constructor:function(_1){
-if(_1){
-if((dojo.isString(_1))||(_1 instanceof dojo._Url)){
-if(_1 instanceof dojo._Url){
-var _2=_1+"";
-}else{
-_2=_1;
-}
-var _3=dojo.xhrGet({url:_2,handleAs:"json-comment-optional",sync:true});
-_3.addCallback(this,"processSmd");
-_3.addErrback(function(){
-throw new Error("Unable to load SMD from "+_1);
-});
-}else{
-if(_1.smdStr){
-this.processSmd(dojo.eval("("+_1.smdStr+")"));
-}else{
-if(_1.serviceUrl){
-this.serviceUrl=_1.serviceUrl;
-}
-this.timeout=_1.timeout||3000;
-if("strictArgChecks" in _1){
-this.strictArgChecks=_1.strictArgChecks;
-}
-this.processSmd(_1);
-}
-}
-}
-},strictArgChecks:true,serviceUrl:"",parseResults:function(_4){
-return _4;
-},errorCallback:function(_5){
-return function(_6){
-_5.errback(_6.message);
-};
-},resultCallback:function(_7){
-var tf=dojo.hitch(this,function(_8){
-if(_8.error!=null){
-var _9;
-if(typeof _8.error=="object"){
-_9=new Error(_8.error.message);
-_9.code=_8.error.code;
-_9.error=_8.error.error;
-}else{
-_9=new Error(_8.error);
-}
-_9.id=_8.id;
-_9.errorObject=_8;
-_7.errback(_9);
-}else{
-_7.callback(this.parseResults(_8));
-}
-});
-return tf;
-},generateMethod:function(_a,_b,_c){
-return dojo.hitch(this,function(){
-var _d=new dojo.Deferred();
-if((this.strictArgChecks)&&(_b!=null)&&(arguments.length!=_b.length)){
-throw new Error("Invalid number of parameters for remote method.");
-}else{
-this.bind(_a,dojo._toArray(arguments),_d,_c);
-}
-return _d;
+
+dojo.declare("dojo.rpc.RpcService", null, {
+ constructor: function(args){
+ //summary:
+ //Take a string as a url to retrieve an smd or an object that is an smd or partial smd to use
+ //as a definition for the service
+ //
+ // args: object
+ // Takes a number of properties as kwArgs for defining the service. It also
+ // accepts a string. When passed a string, it is treated as a url from
+ // which it should synchronously retrieve an smd file. Otherwise it is a kwArgs
+ // object. It accepts serviceUrl, to manually define a url for the rpc service
+ // allowing the rpc system to be used without an smd definition. strictArgChecks
+ // forces the system to verify that the # of arguments provided in a call
+ // matches those defined in the smd. smdString allows a developer to pass
+ // a jsonString directly, which will be converted into an object or alternatively
+ // smdObject is accepts an smdObject directly.
+ //
+ if(args){
+ //if the arg is a string, we assume it is a url to retrieve an smd definition from
+ if( (dojo.isString(args)) || (args instanceof dojo._Url)){
+ if (args instanceof dojo._Url){
+ var url = args + "";
+ }else{
+ url = args;
+ }
+ var def = dojo.xhrGet({
+ url: url,
+ handleAs: "json-comment-optional",
+ sync: true
+ });
+
+ def.addCallback(this, "processSmd");
+ def.addErrback(function() {
+ throw new Error("Unable to load SMD from " + args);
+ });
+
+ }else if(args.smdStr){
+ this.processSmd(dojo.eval("("+args.smdStr+")"));
+ }else{
+ // otherwise we assume it's an arguments object with the following
+ // (optional) properties:
+ // - serviceUrl
+ // - strictArgChecks
+ // - smdStr
+ // - smdObj
+
+ if(args.serviceUrl){
+ this.serviceUrl = args.serviceUrl;
+ }
+
+ this.timeout = args.timeout || 3000;
+
+ if("strictArgChecks" in args){
+ this.strictArgChecks = args.strictArgChecks;
+ }
+
+ this.processSmd(args);
+ }
+ }
+ },
+
+ strictArgChecks: true,
+ serviceUrl: "",
+
+ parseResults: function(obj){
+ // summary
+ // parse the results coming back from an rpc request. this
+ // base implementation, just returns the full object
+ // subclasses should parse and only return the actual results
+ // obj: Object
+ // Object that is the return results from an rpc request
+ return obj;
+ },
+
+ errorCallback: function(/* dojo.Deferred */ deferredRequestHandler){
+ // summary:
+ // create callback that calls the Deferres errback method
+ // deferredRequestHandler: Deferred
+ // The deferred object handling a request.
+ return function(data){
+ deferredRequestHandler.errback(data.message);
+ };
+ },
+
+ resultCallback: function(/* dojo.Deferred */ deferredRequestHandler){
+ // summary:
+ // create callback that calls the Deferred's callback method
+ // deferredRequestHandler: Deferred
+ // The deferred object handling a request.
+
+ var tf = dojo.hitch(this,
+ function(obj){
+ if(obj.error!=null){
+ var err;
+ if(typeof obj.error == 'object'){
+ err = new Error(obj.error.message);
+ err.code = obj.error.code;
+ err.error = obj.error.error;
+ }else{
+ err = new Error(obj.error);
+ }
+ err.id = obj.id;
+ err.errorObject = obj;
+ deferredRequestHandler.errback(err);
+ }else{
+ deferredRequestHandler.callback(this.parseResults(obj));
+ }
+ }
+ );
+ return tf;
+ },
+
+ generateMethod: function(/*string*/ method, /*array*/ parameters, /*string*/ url){
+ // summary:
+ // generate the local bind methods for the remote object
+ // method: string
+ // The name of the method we are generating
+ // parameters: array
+ // the array of parameters for this call.
+ // url: string
+ // the service url for this call
+
+ return dojo.hitch(this, function(){
+ var deferredRequestHandler = new dojo.Deferred();
+
+ // if params weren't specified, then we can assume it's varargs
+ if( (this.strictArgChecks) &&
+ (parameters != null) &&
+ (arguments.length != parameters.length)
+ ){
+ // put error stuff here, no enough params
+ throw new Error("Invalid number of parameters for remote method.");
+ }else{
+ this.bind(method, dojo._toArray(arguments), deferredRequestHandler, url);
+ }
+
+ return deferredRequestHandler;
+ });
+ },
+
+ processSmd: function(object){
+ // summary:
+ // callback method for reciept of a smd object. Parse the smd
+ // and generate functions based on the description
+ // object:
+ // smd object defining this service.
+
+ if(object.methods){
+ dojo.forEach(object.methods, function(m){
+ if(m && m.name){
+ this[m.name] = this.generateMethod( m.name,
+ m.parameters,
+ m.url||m.serviceUrl||m.serviceURL);
+ if(!dojo.isFunction(this[m.name])){
+ throw new Error("RpcService: Failed to create" + m.name + "()");
+ /*console.log("RpcService: Failed to create", m.name, "()");*/
+ }
+ }
+ }, this);
+ }
+
+ this.serviceUrl = object.serviceUrl||object.serviceURL;
+ this.required = object.required;
+ this.smd = object;
+ }
});
-},processSmd:function(_e){
-if(_e.methods){
-dojo.forEach(_e.methods,function(m){
-if(m&&m.name){
-this[m.name]=this.generateMethod(m.name,m.parameters,m.url||m.serviceUrl||m.serviceURL);
-if(!dojo.isFunction(this[m.name])){
-throw new Error("RpcService: Failed to create"+m.name+"()");
-}
-}
-},this);
-}
-this.serviceUrl=_e.serviceUrl||_e.serviceURL;
-this.required=_e.required;
-this.smd=_e;
-}});
+
}
diff --git a/lib/dojo/string.js b/lib/dojo/string.js
index 076283bee..1eba34043 100644
--- a/lib/dojo/string.js
+++ b/lib/dojo/string.js
@@ -5,53 +5,160 @@
*/
-if(!dojo._hasResource["dojo.string"]){
-dojo._hasResource["dojo.string"]=true;
+if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.string"] = true;
dojo.provide("dojo.string");
-dojo.string.rep=function(_1,_2){
-if(_2<=0||!_1){
-return "";
-}
-var _3=[];
-for(;;){
-if(_2&1){
-_3.push(_1);
-}
-if(!(_2>>=1)){
-break;
-}
-_1+=_1;
-}
-return _3.join("");
+
+/*=====
+dojo.string = {
+ // summary: String utilities for Dojo
};
-dojo.string.pad=function(_4,_5,ch,_6){
-if(!ch){
-ch="0";
-}
-var _7=String(_4),_8=dojo.string.rep(ch,Math.ceil((_5-_7.length)/ch.length));
-return _6?_7+_8:_8+_7;
+=====*/
+
+dojo.string.rep = function(/*String*/str, /*Integer*/num){
+ // summary:
+ // Efficiently replicate a string `n` times.
+ // str:
+ // the string to replicate
+ // num:
+ // number of times to replicate the string
+
+ if(num <= 0 || !str){ return ""; }
+
+ var buf = [];
+ for(;;){
+ if(num & 1){
+ buf.push(str);
+ }
+ if(!(num >>= 1)){ break; }
+ str += str;
+ }
+ return buf.join(""); // String
};
-dojo.string.substitute=function(_9,_a,_b,_c){
-_c=_c||dojo.global;
-_b=_b?dojo.hitch(_c,_b):function(v){
-return v;
+
+dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){
+ // summary:
+ // Pad a string to guarantee that it is at least `size` length by
+ // filling with the character `ch` at either the start or end of the
+ // string. Pads at the start, by default.
+ // text:
+ // the string to pad
+ // size:
+ // length to provide padding
+ // ch:
+ // character to pad, defaults to '0'
+ // end:
+ // adds padding at the end if true, otherwise pads at start
+ // example:
+ // | // Fill the string to length 10 with "+" characters on the right. Yields "Dojo++++++".
+ // | dojo.string.pad("Dojo", 10, "+", true);
+
+ if(!ch){
+ ch = '0';
+ }
+ var out = String(text),
+ pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length));
+ return end ? out + pad : pad + out; // String
};
-return _9.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,function(_d,_e,_f){
-var _10=dojo.getObject(_e,false,_a);
-if(_f){
-_10=dojo.getObject(_f,false,_c).call(_c,_10,_e);
-}
-return _b(_10,_e).toString();
-});
+
+dojo.string.substitute = function( /*String*/ template,
+ /*Object|Array*/map,
+ /*Function?*/ transform,
+ /*Object?*/ thisObject){
+ // summary:
+ // Performs parameterized substitutions on a string. Throws an
+ // exception if any parameter is unmatched.
+ // template:
+ // a string with expressions in the form `${key}` to be replaced or
+ // `${key:format}` which specifies a format function. keys are case-sensitive.
+ // map:
+ // hash to search for substitutions
+ // transform:
+ // a function to process all parameters before substitution takes
+ // place, e.g. mylib.encodeXML
+ // thisObject:
+ // where to look for optional format function; default to the global
+ // namespace
+ // example:
+ // Substitutes two expressions in a string from an Array or Object
+ // | // returns "File 'foo.html' is not found in directory '/temp'."
+ // | // by providing substitution data in an Array
+ // | dojo.string.substitute(
+ // | "File '${0}' is not found in directory '${1}'.",
+ // | ["foo.html","/temp"]
+ // | );
+ // |
+ // | // also returns "File 'foo.html' is not found in directory '/temp'."
+ // | // but provides substitution data in an Object structure. Dotted
+ // | // notation may be used to traverse the structure.
+ // | dojo.string.substitute(
+ // | "File '${name}' is not found in directory '${info.dir}'.",
+ // | { name: "foo.html", info: { dir: "/temp" } }
+ // | );
+ // example:
+ // Use a transform function to modify the values:
+ // | // returns "file 'foo.html' is not found in directory '/temp'."
+ // | dojo.string.substitute(
+ // | "${0} is not found in ${1}.",
+ // | ["foo.html","/temp"],
+ // | function(str){
+ // | // try to figure out the type
+ // | var prefix = (str.charAt(0) == "/") ? "directory": "file";
+ // | return prefix + " '" + str + "'";
+ // | }
+ // | );
+ // example:
+ // Use a formatter
+ // | // returns "thinger -- howdy"
+ // | dojo.string.substitute(
+ // | "${0:postfix}", ["thinger"], null, {
+ // | postfix: function(value, key){
+ // | return value + " -- howdy";
+ // | }
+ // | }
+ // | );
+
+ thisObject = thisObject || dojo.global;
+ transform = transform ?
+ dojo.hitch(thisObject, transform) : function(v){ return v; };
+
+ return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,
+ function(match, key, format){
+ var value = dojo.getObject(key, false, map);
+ if(format){
+ value = dojo.getObject(format, false, thisObject).call(thisObject, value, key);
+ }
+ return transform(value, key).toString();
+ }); // String
};
-dojo.string.trim=String.prototype.trim?dojo.trim:function(str){
-str=str.replace(/^\s+/,"");
-for(var i=str.length-1;i>=0;i--){
-if(/\S/.test(str.charAt(i))){
-str=str.substring(0,i+1);
-break;
-}
+
+/*=====
+dojo.string.trim = function(str){
+ // summary:
+ // Trims whitespace from both sides of the string
+ // str: String
+ // String to be trimmed
+ // returns: String
+ // Returns the trimmed string
+ // description:
+ // This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript).
+ // The short yet performant version of this function is dojo.trim(),
+ // which is part of Dojo base. Uses String.prototype.trim instead, if available.
+ return ""; // String
}
-return str;
-};
+=====*/
+
+dojo.string.trim = String.prototype.trim ?
+ dojo.trim : // aliasing to the native function
+ function(str){
+ str = str.replace(/^\s+/, '');
+ for(var i = str.length - 1; i >= 0; i--){
+ if(/\S/.test(str.charAt(i))){
+ str = str.substring(0, i + 1);
+ break;
+ }
+ }
+ return str;
+ };
+
}
diff --git a/lib/dojo/tt-rss-layer.js b/lib/dojo/tt-rss-layer.js
new file mode 100644
index 000000000..295fd957a
--- /dev/null
+++ b/lib/dojo/tt-rss-layer.js
@@ -0,0 +1,14 @@
+/*
+ Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Available via Academic Free License >= 2.1 OR the modified BSD license.
+ see: http://dojotoolkit.org/license for details
+*/
+
+/*
+ This is an optimized version of Dojo, built for deployment and not for
+ development. To get sources and documentation, please visit:
+
+ http://dojotoolkit.org
+*/
+
+dojo.provide("tt-rss-layer");if(!dojo._hasResource["dojo.date.stamp"]){dojo._hasResource["dojo.date.stamp"]=true;dojo.provide("dojo.date.stamp");dojo.date.stamp.fromISOString=function(_1,_2){if(!dojo.date.stamp._isoRegExp){dojo.date.stamp._isoRegExp=/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/;}var _3=dojo.date.stamp._isoRegExp.exec(_1),_4=null;if(_3){_3.shift();if(_3[1]){_3[1]--;}if(_3[6]){_3[6]*=1000;}if(_2){_2=new Date(_2);dojo.forEach(dojo.map(["FullYear","Month","Date","Hours","Minutes","Seconds","Milliseconds"],function(_5){return _2["get"+_5]();}),function(_6,_7){_3[_7]=_3[_7]||_6;});}_4=new Date(_3[0]||1970,_3[1]||0,_3[2]||1,_3[3]||0,_3[4]||0,_3[5]||0,_3[6]||0);if(_3[0]<100){_4.setFullYear(_3[0]||1970);}var _8=0,_9=_3[7]&&_3[7].charAt(0);if(_9!="Z"){_8=((_3[8]||0)*60)+(Number(_3[9])||0);if(_9!="-"){_8*=-1;}}if(_9){_8-=_4.getTimezoneOffset();}if(_8){_4.setTime(_4.getTime()+_8*60000);}}return _4;};dojo.date.stamp.toISOString=function(_a,_b){var _c=function(n){return (n<10)?"0"+n:n;};_b=_b||{};var _d=[],_e=_b.zulu?"getUTC":"get",_f="";if(_b.selector!="time"){var _10=_a[_e+"FullYear"]();_f=["0000".substr((_10+"").length)+_10,_c(_a[_e+"Month"]()+1),_c(_a[_e+"Date"]())].join("-");}_d.push(_f);if(_b.selector!="date"){var _11=[_c(_a[_e+"Hours"]()),_c(_a[_e+"Minutes"]()),_c(_a[_e+"Seconds"]())].join(":");var _12=_a[_e+"Milliseconds"]();if(_b.milliseconds){_11+="."+(_12<100?"0":"")+_c(_12);}if(_b.zulu){_11+="Z";}else{if(_b.selector!="time"){var _13=_a.getTimezoneOffset();var _14=Math.abs(_13);_11+=(_13>0?"-":"+")+_c(Math.floor(_14/60))+":"+_c(_14%60);}}_d.push(_11);}return _d.join("T");};}if(!dojo._hasResource["dojo.parser"]){dojo._hasResource["dojo.parser"]=true;dojo.provide("dojo.parser");new Date("X");dojo.parser=new function(){var d=dojo;this._attrName=d._scopeName+"Type";this._query="["+this._attrName+"]";function _15(_16){if(d.isString(_16)){return "string";}if(typeof _16=="number"){return "number";}if(typeof _16=="boolean"){return "boolean";}if(d.isFunction(_16)){return "function";}if(d.isArray(_16)){return "array";}if(_16 instanceof Date){return "date";}if(_16 instanceof d._Url){return "url";}return "object";};function _17(_18,_19){switch(_19){case "string":return _18;case "number":return _18.length?Number(_18):NaN;case "boolean":return typeof _18=="boolean"?_18:!(_18.toLowerCase()=="false");case "function":if(d.isFunction(_18)){_18=_18.toString();_18=d.trim(_18.substring(_18.indexOf("{")+1,_18.length-1));}try{if(_18===""||_18.search(/[^\w\.]+/i)!=-1){return new Function(_18);}else{return d.getObject(_18,false)||new Function(_18);}}catch(e){return new Function();}case "array":return _18?_18.split(/\s*,\s*/):[];case "date":switch(_18){case "":return new Date("");case "now":return new Date();default:return d.date.stamp.fromISOString(_18);}case "url":return d.baseUrl+_18;default:return d.fromJson(_18);}};var _1a={};dojo.connect(dojo,"extend",function(){_1a={};});function _1b(_1c){if(!_1a[_1c]){var cls=d.getObject(_1c);if(!cls){return null;}var _1d=cls.prototype;var _1e={},_1f={};for(var _20 in _1d){if(_20.charAt(0)=="_"){continue;}if(_20 in _1f){continue;}var _21=_1d[_20];_1e[_20]=_15(_21);}_1a[_1c]={cls:cls,params:_1e};}return _1a[_1c];};this._functionFromScript=function(_22){var _23="";var _24="";var _25=_22.getAttribute("args");if(_25){d.forEach(_25.split(/\s*,\s*/),function(_26,idx){_23+="var "+_26+" = arguments["+idx+"]; ";});}var _27=_22.getAttribute("with");if(_27&&_27.length){d.forEach(_27.split(/\s*,\s*/),function(_28){_23+="with("+_28+"){";_24+="}";});}return new Function(_23+_22.innerHTML+_24);};this.instantiate=function(_29,_2a,_2b){var _2c=[],dp=dojo.parser;_2a=_2a||{};_2b=_2b||{};d.forEach(_29,function(obj){if(!obj){return;}var _2d,_2e,_2f,_30,_31;if(obj.node){_2d=obj.node;_2e=obj.type;_2f=obj.clsInfo||(_2e&&_1b(_2e));_30=_2f&&_2f.cls;_31=obj.scripts;}else{_2d=obj;_2e=dp._attrName in _2a?_2a[dp._attrName]:_2d.getAttribute(dp._attrName);_2f=_2e&&_1b(_2e);_30=_2f&&_2f.cls;_31=(_30&&(_30._noScript||_30.prototype._noScript)?[]:d.query("> script[type^='dojo/']",_2d));}if(!_2f){throw new Error("Could not load class '"+_2e);}var _32={},_33=_2d.attributes;if(_2b.defaults){dojo.mixin(_32,_2b.defaults);}if(obj.inherited){dojo.mixin(_32,obj.inherited);}for(var _34 in _2f.params){var _35=_34 in _2a?{value:_2a[_34],specified:true}:_33.getNamedItem(_34);if(!_35||(!_35.specified&&(!dojo.isIE||_34.toLowerCase()!="value"))){continue;}var _36=_35.value;switch(_34){case "class":_36="className" in _2a?_2a.className:_2d.className;break;case "style":_36="style" in _2a?_2a.style:(_2d.style&&_2d.style.cssText);}var _37=_2f.params[_34];if(typeof _36=="string"){_32[_34]=_17(_36,_37);}else{_32[_34]=_36;}}var _38=[],_39=[];d.forEach(_31,function(_3a){_2d.removeChild(_3a);var _3b=_3a.getAttribute("event"),_2e=_3a.getAttribute("type"),nf=d.parser._functionFromScript(_3a);if(_3b){if(_2e=="dojo/connect"){_38.push({event:_3b,func:nf});}else{_32[_3b]=nf;}}else{_39.push(nf);}});var _3c=_30.markupFactory||_30.prototype&&_30.prototype.markupFactory;var _3d=_3c?_3c(_32,_2d,_30):new _30(_32,_2d);_2c.push(_3d);var _3e=_2d.getAttribute("jsId");if(_3e){d.setObject(_3e,_3d);}d.forEach(_38,function(_3f){d.connect(_3d,_3f.event,null,_3f.func);});d.forEach(_39,function(_40){_40.call(_3d);});});if(!_2a._started){d.forEach(_2c,function(_41){if(!_2b.noStart&&_41&&_41.startup&&!_41._started&&(!_41.getParent||!_41.getParent())){_41.startup();}});}return _2c;};this.parse=function(_42,_43){var _44;if(!_43&&_42&&_42.rootNode){_43=_42;_44=_43.rootNode;}else{_44=_42;}var _45=this._attrName;function _46(_47,_48){var _49=dojo.clone(_47.inherited);dojo.forEach(["dir","lang"],function(_4a){var val=_47.node.getAttribute(_4a);if(val){_49[_4a]=val;}});var _4b=_47.scripts;var _4c=!_47.clsInfo||!_47.clsInfo.cls.prototype.stopParser;for(var _4d=_47.node.firstChild;_4d;_4d=_4d.nextSibling){if(_4d.nodeType==1){var _4e=_4c&&_4d.getAttribute(_45);if(_4e){var _4f={"type":_4e,clsInfo:_1b(_4e),node:_4d,scripts:[],inherited:_49};_48.push(_4f);_46(_4f,_48);}else{if(_4b&&_4d.nodeName.toLowerCase()=="script"){_4e=_4d.getAttribute("type");if(_4e&&/^dojo\//i.test(_4e)){_4b.push(_4d);}}else{if(_4c){_46({node:_4d,inherited:_49},_48);}}}}}};var _50=[];_46({node:_44?dojo.byId(_44):dojo.body(),inherited:(_43&&_43.inherited)||{dir:dojo._isBodyLtr()?"ltr":"rtl"}},_50);return this.instantiate(_50,null,_43);};}();(function(){var _51=function(){if(dojo.config.parseOnLoad){dojo.parser.parse();}};if(dojo.exists("dijit.wai.onload")&&(dijit.wai.onload===dojo._loaders[0])){dojo._loaders.splice(1,0,_51);}else{dojo._loaders.unshift(_51);}})();}if(!dojo._hasResource["dojo.window"]){dojo._hasResource["dojo.window"]=true;dojo.provide("dojo.window");dojo.window.getBox=function(){var _52=(dojo.doc.compatMode=="BackCompat")?dojo.body():dojo.doc.documentElement;var _53=dojo._docScroll();return {w:_52.clientWidth,h:_52.clientHeight,l:_53.x,t:_53.y};};dojo.window.get=function(doc){if(dojo.isIE&&window!==document.parentWindow){doc.parentWindow.execScript("document._parentWindow = window;","Javascript");var win=doc._parentWindow;doc._parentWindow=null;return win;}return doc.parentWindow||doc.defaultView;};dojo.window.scrollIntoView=function(_54,pos){try{_54=dojo.byId(_54);var doc=_54.ownerDocument||dojo.doc,_55=doc.body||dojo.body(),_56=doc.documentElement||_55.parentNode,_57=dojo.isIE,_58=dojo.isWebKit;if((!(dojo.isMoz||_57||_58||dojo.isOpera)||_54==_55||_54==_56)&&(typeof _54.scrollIntoView!="undefined")){_54.scrollIntoView(false);return;}var _59=doc.compatMode=="BackCompat",_5a=_59?_55:_56,_5b=_58?_55:_5a,_5c=_5a.clientWidth,_5d=_5a.clientHeight,rtl=!dojo._isBodyLtr(),_5e=pos||dojo.position(_54),el=_54.parentNode,_5f=function(el){return ((_57<=6||(_57&&_59))?false:(dojo.style(el,"position").toLowerCase()=="fixed"));};if(_5f(_54)){return;}while(el){if(el==_55){el=_5b;}var _60=dojo.position(el),_61=_5f(el);if(el==_5b){_60.w=_5c;_60.h=_5d;if(_5b==_56&&_57&&rtl){_60.x+=_5b.offsetWidth-_60.w;}if(_60.x<0||!_57){_60.x=0;}if(_60.y<0||!_57){_60.y=0;}}else{var pb=dojo._getPadBorderExtents(el);_60.w-=pb.w;_60.h-=pb.h;_60.x+=pb.l;_60.y+=pb.t;}if(el!=_5b){var _62=el.clientWidth,_63=_60.w-_62;if(_62>0&&_63>0){_60.w=_62;if(_57&&rtl){_60.x+=_63;}}_62=el.clientHeight;_63=_60.h-_62;if(_62>0&&_63>0){_60.h=_62;}}if(_61){if(_60.y<0){_60.h+=_60.y;_60.y=0;}if(_60.x<0){_60.w+=_60.x;_60.x=0;}if(_60.y+_60.h>_5d){_60.h=_5d-_60.y;}if(_60.x+_60.w>_5c){_60.w=_5c-_60.x;}}var l=_5e.x-_60.x,t=_5e.y-Math.max(_60.y,0),r=l+_5e.w-_60.w,bot=t+_5e.h-_60.h;if(r*l>0){var s=Math[l<0?"max":"min"](l,r);_5e.x+=el.scrollLeft;el.scrollLeft+=(_57>=8&&!_59&&rtl)?-s:s;_5e.x-=el.scrollLeft;}if(bot*t>0){_5e.y+=el.scrollTop;el.scrollTop+=Math[t<0?"max":"min"](t,bot);_5e.y-=el.scrollTop;}el=(el!=_5b)&&!_61&&el.parentNode;}}catch(error){console.error("scrollIntoView: "+error);_54.scrollIntoView(false);}};}if(!dojo._hasResource["dijit._base.manager"]){dojo._hasResource["dijit._base.manager"]=true;dojo.provide("dijit._base.manager");dojo.declare("dijit.WidgetSet",null,{constructor:function(){this._hash={};this.length=0;},add:function(_64){if(this._hash[_64.id]){throw new Error("Tried to register widget with id=="+_64.id+" but that id is already registered");}this._hash[_64.id]=_64;this.length++;},remove:function(id){if(this._hash[id]){delete this._hash[id];this.length--;}},forEach:function(_65,_66){_66=_66||dojo.global;var i=0,id;for(id in this._hash){_65.call(_66,this._hash[id],i++,this._hash);}return this;},filter:function(_67,_68){_68=_68||dojo.global;var res=new dijit.WidgetSet(),i=0,id;for(id in this._hash){var w=this._hash[id];if(_67.call(_68,w,i++,this._hash)){res.add(w);}}return res;},byId:function(id){return this._hash[id];},byClass:function(cls){var res=new dijit.WidgetSet(),id,_69;for(id in this._hash){_69=this._hash[id];if(_69.declaredClass==cls){res.add(_69);}}return res;},toArray:function(){var ar=[];for(var id in this._hash){ar.push(this._hash[id]);}return ar;},map:function(_6a,_6b){return dojo.map(this.toArray(),_6a,_6b);},every:function(_6c,_6d){_6d=_6d||dojo.global;var x=0,i;for(i in this._hash){if(!_6c.call(_6d,this._hash[i],x++,this._hash)){return false;}}return true;},some:function(_6e,_6f){_6f=_6f||dojo.global;var x=0,i;for(i in this._hash){if(_6e.call(_6f,this._hash[i],x++,this._hash)){return true;}}return false;}});(function(){dijit.registry=new dijit.WidgetSet();var _70=dijit.registry._hash,_71=dojo.attr,_72=dojo.hasAttr,_73=dojo.style;dijit.byId=function(id){return typeof id=="string"?_70[id]:id;};var _74={};dijit.getUniqueId=function(_75){var id;do{id=_75+"_"+(_75 in _74?++_74[_75]:_74[_75]=0);}while(_70[id]);return dijit._scopeName=="dijit"?id:dijit._scopeName+"_"+id;};dijit.findWidgets=function(_76){var _77=[];function _78(_79){for(var _7a=_79.firstChild;_7a;_7a=_7a.nextSibling){if(_7a.nodeType==1){var _7b=_7a.getAttribute("widgetId");if(_7b){_77.push(_70[_7b]);}else{_78(_7a);}}}};_78(_76);return _77;};dijit._destroyAll=function(){dijit._curFocus=null;dijit._prevFocus=null;dijit._activeStack=[];dojo.forEach(dijit.findWidgets(dojo.body()),function(_7c){if(!_7c._destroyed){if(_7c.destroyRecursive){_7c.destroyRecursive();}else{if(_7c.destroy){_7c.destroy();}}}});};if(dojo.isIE){dojo.addOnWindowUnload(function(){dijit._destroyAll();});}dijit.byNode=function(_7d){return _70[_7d.getAttribute("widgetId")];};dijit.getEnclosingWidget=function(_7e){while(_7e){var id=_7e.getAttribute&&_7e.getAttribute("widgetId");if(id){return _70[id];}_7e=_7e.parentNode;}return null;};var _7f=(dijit._isElementShown=function(_80){var s=_73(_80);return (s.visibility!="hidden")&&(s.visibility!="collapsed")&&(s.display!="none")&&(_71(_80,"type")!="hidden");});dijit.hasDefaultTabStop=function(_81){switch(_81.nodeName.toLowerCase()){case "a":return _72(_81,"href");case "area":case "button":case "input":case "object":case "select":case "textarea":return true;case "iframe":if(dojo.isMoz){try{return _81.contentDocument.designMode=="on";}catch(err){return false;}}else{if(dojo.isWebKit){var doc=_81.contentDocument,_82=doc&&doc.body;return _82&&_82.contentEditable=="true";}else{try{doc=_81.contentWindow.document;_82=doc&&doc.body;return _82&&_82.firstChild&&_82.firstChild.contentEditable=="true";}catch(e){return false;}}}default:return _81.contentEditable=="true";}};var _83=(dijit.isTabNavigable=function(_84){if(_71(_84,"disabled")){return false;}else{if(_72(_84,"tabIndex")){return _71(_84,"tabIndex")>=0;}else{return dijit.hasDefaultTabStop(_84);}}});dijit._getTabNavigable=function(_85){var _86,_87,_88,_89,_8a,_8b;var _8c=function(_8d){dojo.query("> *",_8d).forEach(function(_8e){if((dojo.isIE&&_8e.scopeName!=="HTML")||!_7f(_8e)){return;}if(_83(_8e)){var _8f=_71(_8e,"tabIndex");if(!_72(_8e,"tabIndex")||_8f==0){if(!_86){_86=_8e;}_87=_8e;}else{if(_8f>0){if(!_88||_8f<_89){_89=_8f;_88=_8e;}if(!_8a||_8f>=_8b){_8b=_8f;_8a=_8e;}}}}if(_8e.nodeName.toUpperCase()!="SELECT"){_8c(_8e);}});};if(_7f(_85)){_8c(_85);}return {first:_86,last:_87,lowest:_88,highest:_8a};};dijit.getFirstInTabbingOrder=function(_90){var _91=dijit._getTabNavigable(dojo.byId(_90));return _91.lowest?_91.lowest:_91.first;};dijit.getLastInTabbingOrder=function(_92){var _93=dijit._getTabNavigable(dojo.byId(_92));return _93.last?_93.last:_93.highest;};dijit.defaultDuration=dojo.config["defaultDuration"]||200;})();}if(!dojo._hasResource["dijit._base.focus"]){dojo._hasResource["dijit._base.focus"]=true;dojo.provide("dijit._base.focus");dojo.mixin(dijit,{_curFocus:null,_prevFocus:null,isCollapsed:function(){return dijit.getBookmark().isCollapsed;},getBookmark:function(){var bm,rg,tg,sel=dojo.doc.selection,cf=dijit._curFocus;if(dojo.global.getSelection){sel=dojo.global.getSelection();if(sel){if(sel.isCollapsed){tg=cf?cf.tagName:"";if(tg){tg=tg.toLowerCase();if(tg=="textarea"||(tg=="input"&&(!cf.type||cf.type.toLowerCase()=="text"))){sel={start:cf.selectionStart,end:cf.selectionEnd,node:cf,pRange:true};return {isCollapsed:(sel.end<=sel.start),mark:sel};}}bm={isCollapsed:true};}else{rg=sel.getRangeAt(0);bm={isCollapsed:false,mark:rg.cloneRange()};}}}else{if(sel){tg=cf?cf.tagName:"";tg=tg.toLowerCase();if(cf&&tg&&(tg=="button"||tg=="textarea"||tg=="input")){if(sel.type&&sel.type.toLowerCase()=="none"){return {isCollapsed:true,mark:null};}else{rg=sel.createRange();return {isCollapsed:rg.text&&rg.text.length?false:true,mark:{range:rg,pRange:true}};}}bm={};try{rg=sel.createRange();bm.isCollapsed=!(sel.type=="Text"?rg.htmlText.length:rg.length);}catch(e){bm.isCollapsed=true;return bm;}if(sel.type.toUpperCase()=="CONTROL"){if(rg.length){bm.mark=[];var i=0,len=rg.length;while(i<len){bm.mark.push(rg.item(i++));}}else{bm.isCollapsed=true;bm.mark=null;}}else{bm.mark=rg.getBookmark();}}else{console.warn("No idea how to store the current selection for this browser!");}}return bm;},moveToBookmark:function(_94){var _95=dojo.doc,_96=_94.mark;if(_96){if(dojo.global.getSelection){var sel=dojo.global.getSelection();if(sel&&sel.removeAllRanges){if(_96.pRange){var r=_96;var n=r.node;n.selectionStart=r.start;n.selectionEnd=r.end;}else{sel.removeAllRanges();sel.addRange(_96);}}else{console.warn("No idea how to restore selection for this browser!");}}else{if(_95.selection&&_96){var rg;if(_96.pRange){rg=_96.range;}else{if(dojo.isArray(_96)){rg=_95.body.createControlRange();dojo.forEach(_96,function(n){rg.addElement(n);});}else{rg=_95.body.createTextRange();rg.moveToBookmark(_96);}}rg.select();}}}},getFocus:function(_97,_98){var _99=!dijit._curFocus||(_97&&dojo.isDescendant(dijit._curFocus,_97.domNode))?dijit._prevFocus:dijit._curFocus;return {node:_99,bookmark:(_99==dijit._curFocus)&&dojo.withGlobal(_98||dojo.global,dijit.getBookmark),openedForWindow:_98};},focus:function(_9a){if(!_9a){return;}var _9b="node" in _9a?_9a.node:_9a,_9c=_9a.bookmark,_9d=_9a.openedForWindow,_9e=_9c?_9c.isCollapsed:false;if(_9b){var _9f=(_9b.tagName.toLowerCase()=="iframe")?_9b.contentWindow:_9b;if(_9f&&_9f.focus){try{_9f.focus();}catch(e){}}dijit._onFocusNode(_9b);}if(_9c&&dojo.withGlobal(_9d||dojo.global,dijit.isCollapsed)&&!_9e){if(_9d){_9d.focus();}try{dojo.withGlobal(_9d||dojo.global,dijit.moveToBookmark,null,[_9c]);}catch(e2){}}},_activeStack:[],registerIframe:function(_a0){return dijit.registerWin(_a0.contentWindow,_a0);},unregisterIframe:function(_a1){dijit.unregisterWin(_a1);},registerWin:function(_a2,_a3){var _a4=function(evt){dijit._justMouseDowned=true;setTimeout(function(){dijit._justMouseDowned=false;},0);if(dojo.isIE&&evt&&evt.srcElement&&evt.srcElement.parentNode==null){return;}dijit._onTouchNode(_a3||evt.target||evt.srcElement,"mouse");};var doc=dojo.isIE?_a2.document.documentElement:_a2.document;if(doc){if(dojo.isIE){doc.attachEvent("onmousedown",_a4);var _a5=function(evt){if(evt.srcElement.tagName.toLowerCase()!="#document"&&dijit.isTabNavigable(evt.srcElement)){dijit._onFocusNode(_a3||evt.srcElement);}else{dijit._onTouchNode(_a3||evt.srcElement);}};doc.attachEvent("onactivate",_a5);var _a6=function(evt){dijit._onBlurNode(_a3||evt.srcElement);};doc.attachEvent("ondeactivate",_a6);return function(){doc.detachEvent("onmousedown",_a4);doc.detachEvent("onactivate",_a5);doc.detachEvent("ondeactivate",_a6);doc=null;};}else{doc.addEventListener("mousedown",_a4,true);var _a7=function(evt){dijit._onFocusNode(_a3||evt.target);};doc.addEventListener("focus",_a7,true);var _a8=function(evt){dijit._onBlurNode(_a3||evt.target);};doc.addEventListener("blur",_a8,true);return function(){doc.removeEventListener("mousedown",_a4,true);doc.removeEventListener("focus",_a7,true);doc.removeEventListener("blur",_a8,true);doc=null;};}}},unregisterWin:function(_a9){_a9&&_a9();},_onBlurNode:function(_aa){dijit._prevFocus=dijit._curFocus;dijit._curFocus=null;if(dijit._justMouseDowned){return;}if(dijit._clearActiveWidgetsTimer){clearTimeout(dijit._clearActiveWidgetsTimer);}dijit._clearActiveWidgetsTimer=setTimeout(function(){delete dijit._clearActiveWidgetsTimer;dijit._setStack([]);dijit._prevFocus=null;},100);},_onTouchNode:function(_ab,by){if(dijit._clearActiveWidgetsTimer){clearTimeout(dijit._clearActiveWidgetsTimer);delete dijit._clearActiveWidgetsTimer;}var _ac=[];try{while(_ab){var _ad=dojo.attr(_ab,"dijitPopupParent");if(_ad){_ab=dijit.byId(_ad).domNode;}else{if(_ab.tagName&&_ab.tagName.toLowerCase()=="body"){if(_ab===dojo.body()){break;}_ab=dojo.window.get(_ab.ownerDocument).frameElement;}else{var id=_ab.getAttribute&&_ab.getAttribute("widgetId"),_ae=id&&dijit.byId(id);if(_ae&&!(by=="mouse"&&_ae.get("disabled"))){_ac.unshift(id);}_ab=_ab.parentNode;}}}}catch(e){}dijit._setStack(_ac,by);},_onFocusNode:function(_af){if(!_af){return;}if(_af.nodeType==9){return;}dijit._onTouchNode(_af);if(_af==dijit._curFocus){return;}if(dijit._curFocus){dijit._prevFocus=dijit._curFocus;}dijit._curFocus=_af;dojo.publish("focusNode",[_af]);},_setStack:function(_b0,by){var _b1=dijit._activeStack;dijit._activeStack=_b0;for(var _b2=0;_b2<Math.min(_b1.length,_b0.length);_b2++){if(_b1[_b2]!=_b0[_b2]){break;}}var _b3;for(var i=_b1.length-1;i>=_b2;i--){_b3=dijit.byId(_b1[i]);if(_b3){_b3._focused=false;_b3._hasBeenBlurred=true;if(_b3._onBlur){_b3._onBlur(by);}dojo.publish("widgetBlur",[_b3,by]);}}for(i=_b2;i<_b0.length;i++){_b3=dijit.byId(_b0[i]);if(_b3){_b3._focused=true;if(_b3._onFocus){_b3._onFocus(by);}dojo.publish("widgetFocus",[_b3,by]);}}}});dojo.addOnLoad(function(){var _b4=dijit.registerWin(window);if(dojo.isIE){dojo.addOnWindowUnload(function(){dijit.unregisterWin(_b4);_b4=null;});}});}if(!dojo._hasResource["dojo.AdapterRegistry"]){dojo._hasResource["dojo.AdapterRegistry"]=true;dojo.provide("dojo.AdapterRegistry");dojo.AdapterRegistry=function(_b5){this.pairs=[];this.returnWrappers=_b5||false;};dojo.extend(dojo.AdapterRegistry,{register:function(_b6,_b7,_b8,_b9,_ba){this.pairs[((_ba)?"unshift":"push")]([_b6,_b7,_b8,_b9]);},match:function(){for(var i=0;i<this.pairs.length;i++){var _bb=this.pairs[i];if(_bb[1].apply(this,arguments)){if((_bb[3])||(this.returnWrappers)){return _bb[2];}else{return _bb[2].apply(this,arguments);}}}throw new Error("No match found");},unregister:function(_bc){for(var i=0;i<this.pairs.length;i++){var _bd=this.pairs[i];if(_bd[0]==_bc){this.pairs.splice(i,1);return true;}}return false;}});}if(!dojo._hasResource["dijit._base.place"]){dojo._hasResource["dijit._base.place"]=true;dojo.provide("dijit._base.place");dijit.getViewport=function(){return dojo.window.getBox();};dijit.placeOnScreen=function(_be,pos,_bf,_c0){var _c1=dojo.map(_bf,function(_c2){var c={corner:_c2,pos:{x:pos.x,y:pos.y}};if(_c0){c.pos.x+=_c2.charAt(1)=="L"?_c0.x:-_c0.x;c.pos.y+=_c2.charAt(0)=="T"?_c0.y:-_c0.y;}return c;});return dijit._place(_be,_c1);};dijit._place=function(_c3,_c4,_c5){var _c6=dojo.window.getBox();if(!_c3.parentNode||String(_c3.parentNode.tagName).toLowerCase()!="body"){dojo.body().appendChild(_c3);}var _c7=null;dojo.some(_c4,function(_c8){var _c9=_c8.corner;var pos=_c8.pos;if(_c5){_c5(_c3,_c8.aroundCorner,_c9);}var _ca=_c3.style;var _cb=_ca.display;var _cc=_ca.visibility;_ca.visibility="hidden";_ca.display="";var mb=dojo.marginBox(_c3);_ca.display=_cb;_ca.visibility=_cc;var _cd=Math.max(_c6.l,_c9.charAt(1)=="L"?pos.x:(pos.x-mb.w)),_ce=Math.max(_c6.t,_c9.charAt(0)=="T"?pos.y:(pos.y-mb.h)),_cf=Math.min(_c6.l+_c6.w,_c9.charAt(1)=="L"?(_cd+mb.w):pos.x),_d0=Math.min(_c6.t+_c6.h,_c9.charAt(0)=="T"?(_ce+mb.h):pos.y),_d1=_cf-_cd,_d2=_d0-_ce,_d3=(mb.w-_d1)+(mb.h-_d2);if(_c7==null||_d3<_c7.overflow){_c7={corner:_c9,aroundCorner:_c8.aroundCorner,x:_cd,y:_ce,w:_d1,h:_d2,overflow:_d3};}return !_d3;});_c3.style.left=_c7.x+"px";_c3.style.top=_c7.y+"px";if(_c7.overflow&&_c5){_c5(_c3,_c7.aroundCorner,_c7.corner);}return _c7;};dijit.placeOnScreenAroundNode=function(_d4,_d5,_d6,_d7){_d5=dojo.byId(_d5);var _d8=_d5.style.display;_d5.style.display="";var _d9=dojo.position(_d5,true);_d5.style.display=_d8;return dijit._placeOnScreenAroundRect(_d4,_d9.x,_d9.y,_d9.w,_d9.h,_d6,_d7);};dijit.placeOnScreenAroundRectangle=function(_da,_db,_dc,_dd){return dijit._placeOnScreenAroundRect(_da,_db.x,_db.y,_db.width,_db.height,_dc,_dd);};dijit._placeOnScreenAroundRect=function(_de,x,y,_df,_e0,_e1,_e2){var _e3=[];for(var _e4 in _e1){_e3.push({aroundCorner:_e4,corner:_e1[_e4],pos:{x:x+(_e4.charAt(1)=="L"?0:_df),y:y+(_e4.charAt(0)=="T"?0:_e0)}});}return dijit._place(_de,_e3,_e2);};dijit.placementRegistry=new dojo.AdapterRegistry();dijit.placementRegistry.register("node",function(n,x){return typeof x=="object"&&typeof x.offsetWidth!="undefined"&&typeof x.offsetHeight!="undefined";},dijit.placeOnScreenAroundNode);dijit.placementRegistry.register("rect",function(n,x){return typeof x=="object"&&"x" in x&&"y" in x&&"width" in x&&"height" in x;},dijit.placeOnScreenAroundRectangle);dijit.placeOnScreenAroundElement=function(_e5,_e6,_e7,_e8){return dijit.placementRegistry.match.apply(dijit.placementRegistry,arguments);};dijit.getPopupAroundAlignment=function(_e9,_ea){var _eb={};dojo.forEach(_e9,function(pos){switch(pos){case "after":_eb[_ea?"BR":"BL"]=_ea?"BL":"BR";break;case "before":_eb[_ea?"BL":"BR"]=_ea?"BR":"BL";break;case "below":_eb[_ea?"BL":"BR"]=_ea?"TL":"TR";_eb[_ea?"BR":"BL"]=_ea?"TR":"TL";break;case "above":default:_eb[_ea?"TL":"TR"]=_ea?"BL":"BR";_eb[_ea?"TR":"TL"]=_ea?"BR":"BL";break;}});return _eb;};}if(!dojo._hasResource["dijit._base.window"]){dojo._hasResource["dijit._base.window"]=true;dojo.provide("dijit._base.window");dijit.getDocumentWindow=function(doc){return dojo.window.get(doc);};}if(!dojo._hasResource["dijit._base.popup"]){dojo._hasResource["dijit._base.popup"]=true;dojo.provide("dijit._base.popup");dijit.popup={_stack:[],_beginZIndex:1000,_idGen:1,moveOffScreen:function(_ec){var _ed=_ec.parentNode;if(!_ed||!dojo.hasClass(_ed,"dijitPopup")){_ed=dojo.create("div",{"class":"dijitPopup",style:{visibility:"hidden",top:"-9999px"}},dojo.body());dijit.setWaiRole(_ed,"presentation");_ed.appendChild(_ec);}var s=_ec.style;s.display="";s.visibility="";s.position="";s.top="0px";dojo.style(_ed,{visibility:"hidden",top:"-9999px"});},getTopPopup:function(){var _ee=this._stack;for(var pi=_ee.length-1;pi>0&&_ee[pi].parent===_ee[pi-1].widget;pi--){}return _ee[pi];},open:function(_ef){var _f0=this._stack,_f1=_ef.popup,_f2=_ef.orient||((_ef.parent?_ef.parent.isLeftToRight():dojo._isBodyLtr())?{"BL":"TL","BR":"TR","TL":"BL","TR":"BR"}:{"BR":"TR","BL":"TL","TR":"BR","TL":"BL"}),_f3=_ef.around,id=(_ef.around&&_ef.around.id)?(_ef.around.id+"_dropdown"):("popup_"+this._idGen++);var _f4=_f1.domNode.parentNode;if(!_f4||!dojo.hasClass(_f4,"dijitPopup")){this.moveOffScreen(_f1.domNode);_f4=_f1.domNode.parentNode;}dojo.attr(_f4,{id:id,style:{zIndex:this._beginZIndex+_f0.length},"class":"dijitPopup "+(_f1.baseClass||_f1["class"]||"").split(" ")[0]+"Popup",dijitPopupParent:_ef.parent?_ef.parent.id:""});if(dojo.isIE||dojo.isMoz){var _f5=_f4.childNodes[1];if(!_f5){_f5=new dijit.BackgroundIframe(_f4);}}var _f6=_f3?dijit.placeOnScreenAroundElement(_f4,_f3,_f2,_f1.orient?dojo.hitch(_f1,"orient"):null):dijit.placeOnScreen(_f4,_ef,_f2=="R"?["TR","BR","TL","BL"]:["TL","BL","TR","BR"],_ef.padding);_f4.style.visibility="visible";_f1.domNode.style.visibility="visible";var _f7=[];_f7.push(dojo.connect(_f4,"onkeypress",this,function(evt){if(evt.charOrCode==dojo.keys.ESCAPE&&_ef.onCancel){dojo.stopEvent(evt);_ef.onCancel();}else{if(evt.charOrCode===dojo.keys.TAB){dojo.stopEvent(evt);var _f8=this.getTopPopup();if(_f8&&_f8.onCancel){_f8.onCancel();}}}}));if(_f1.onCancel){_f7.push(dojo.connect(_f1,"onCancel",_ef.onCancel));}_f7.push(dojo.connect(_f1,_f1.onExecute?"onExecute":"onChange",this,function(){var _f9=this.getTopPopup();if(_f9&&_f9.onExecute){_f9.onExecute();}}));_f0.push({wrapper:_f4,iframe:_f5,widget:_f1,parent:_ef.parent,onExecute:_ef.onExecute,onCancel:_ef.onCancel,onClose:_ef.onClose,handlers:_f7});if(_f1.onOpen){_f1.onOpen(_f6);}return _f6;},close:function(_fa){var _fb=this._stack;while(dojo.some(_fb,function(_fc){return _fc.widget==_fa;})){var top=_fb.pop(),_fd=top.wrapper,_fe=top.iframe,_ff=top.widget,_100=top.onClose;if(_ff.onClose){_ff.onClose();}dojo.forEach(top.handlers,dojo.disconnect);if(_ff&&_ff.domNode){this.moveOffScreen(_ff.domNode);}else{dojo.destroy(_fd);}if(_100){_100();}}}};dijit._frames=new function(){var _101=[];this.pop=function(){var _102;if(_101.length){_102=_101.pop();_102.style.display="";}else{if(dojo.isIE){var burl=dojo.config["dojoBlankHtmlUrl"]||(dojo.moduleUrl("dojo","resources/blank.html")+"")||"javascript:\"\"";var html="<iframe src='"+burl+"'"+" style='position: absolute; left: 0px; top: 0px;"+"z-index: -1; filter:Alpha(Opacity=\"0\");'>";_102=dojo.doc.createElement(html);}else{_102=dojo.create("iframe");_102.src="javascript:\"\"";_102.className="dijitBackgroundIframe";dojo.style(_102,"opacity",0.1);}_102.tabIndex=-1;dijit.setWaiRole(_102,"presentation");}return _102;};this.push=function(_103){_103.style.display="none";_101.push(_103);};}();dijit.BackgroundIframe=function(node){if(!node.id){throw new Error("no id");}if(dojo.isIE||dojo.isMoz){var _104=dijit._frames.pop();node.appendChild(_104);if(dojo.isIE<7){this.resize(node);this._conn=dojo.connect(node,"onresize",this,function(){this.resize(node);});}else{dojo.style(_104,{width:"100%",height:"100%"});}this.iframe=_104;}};dojo.extend(dijit.BackgroundIframe,{resize:function(node){if(this.iframe&&dojo.isIE<7){dojo.style(this.iframe,{width:node.offsetWidth+"px",height:node.offsetHeight+"px"});}},destroy:function(){if(this._conn){dojo.disconnect(this._conn);this._conn=null;}if(this.iframe){dijit._frames.push(this.iframe);delete this.iframe;}}});}if(!dojo._hasResource["dijit._base.scroll"]){dojo._hasResource["dijit._base.scroll"]=true;dojo.provide("dijit._base.scroll");dijit.scrollIntoView=function(node,pos){dojo.window.scrollIntoView(node,pos);};}if(!dojo._hasResource["dojo.uacss"]){dojo._hasResource["dojo.uacss"]=true;dojo.provide("dojo.uacss");(function(){var d=dojo,html=d.doc.documentElement,ie=d.isIE,_105=d.isOpera,maj=Math.floor,ff=d.isFF,_106=d.boxModel.replace(/-/,""),_107={dj_ie:ie,dj_ie6:maj(ie)==6,dj_ie7:maj(ie)==7,dj_ie8:maj(ie)==8,dj_quirks:d.isQuirks,dj_iequirks:ie&&d.isQuirks,dj_opera:_105,dj_khtml:d.isKhtml,dj_webkit:d.isWebKit,dj_safari:d.isSafari,dj_chrome:d.isChrome,dj_gecko:d.isMozilla,dj_ff3:maj(ff)==3};_107["dj_"+_106]=true;var _108="";for(var clz in _107){if(_107[clz]){_108+=clz+" ";}}html.className=d.trim(html.className+" "+_108);dojo._loaders.unshift(function(){if(!dojo._isBodyLtr()){var _109="dj_rtl dijitRtl "+_108.replace(/ /g,"-rtl ");html.className=d.trim(html.className+" "+_109);}});})();}if(!dojo._hasResource["dijit._base.sniff"]){dojo._hasResource["dijit._base.sniff"]=true;dojo.provide("dijit._base.sniff");}if(!dojo._hasResource["dijit._base.typematic"]){dojo._hasResource["dijit._base.typematic"]=true;dojo.provide("dijit._base.typematic");dijit.typematic={_fireEventAndReload:function(){this._timer=null;this._callback(++this._count,this._node,this._evt);this._currentTimeout=Math.max(this._currentTimeout<0?this._initialDelay:(this._subsequentDelay>1?this._subsequentDelay:Math.round(this._currentTimeout*this._subsequentDelay)),this._minDelay);this._timer=setTimeout(dojo.hitch(this,"_fireEventAndReload"),this._currentTimeout);},trigger:function(evt,_10a,node,_10b,obj,_10c,_10d,_10e){if(obj!=this._obj){this.stop();this._initialDelay=_10d||500;this._subsequentDelay=_10c||0.9;this._minDelay=_10e||10;this._obj=obj;this._evt=evt;this._node=node;this._currentTimeout=-1;this._count=-1;this._callback=dojo.hitch(_10a,_10b);this._fireEventAndReload();this._evt=dojo.mixin({faux:true},evt);}},stop:function(){if(this._timer){clearTimeout(this._timer);this._timer=null;}if(this._obj){this._callback(-1,this._node,this._evt);this._obj=null;}},addKeyListener:function(node,_10f,_110,_111,_112,_113,_114){if(_10f.keyCode){_10f.charOrCode=_10f.keyCode;dojo.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.","","2.0");}else{if(_10f.charCode){_10f.charOrCode=String.fromCharCode(_10f.charCode);dojo.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.","","2.0");}}return [dojo.connect(node,"onkeypress",this,function(evt){if(evt.charOrCode==_10f.charOrCode&&(_10f.ctrlKey===undefined||_10f.ctrlKey==evt.ctrlKey)&&(_10f.altKey===undefined||_10f.altKey==evt.altKey)&&(_10f.metaKey===undefined||_10f.metaKey==(evt.metaKey||false))&&(_10f.shiftKey===undefined||_10f.shiftKey==evt.shiftKey)){dojo.stopEvent(evt);dijit.typematic.trigger(evt,_110,node,_111,_10f,_112,_113,_114);}else{if(dijit.typematic._obj==_10f){dijit.typematic.stop();}}}),dojo.connect(node,"onkeyup",this,function(evt){if(dijit.typematic._obj==_10f){dijit.typematic.stop();}})];},addMouseListener:function(node,_115,_116,_117,_118,_119){var dc=dojo.connect;return [dc(node,"mousedown",this,function(evt){dojo.stopEvent(evt);dijit.typematic.trigger(evt,_115,node,_116,node,_117,_118,_119);}),dc(node,"mouseup",this,function(evt){dojo.stopEvent(evt);dijit.typematic.stop();}),dc(node,"mouseout",this,function(evt){dojo.stopEvent(evt);dijit.typematic.stop();}),dc(node,"mousemove",this,function(evt){evt.preventDefault();}),dc(node,"dblclick",this,function(evt){dojo.stopEvent(evt);if(dojo.isIE){dijit.typematic.trigger(evt,_115,node,_116,node,_117,_118,_119);setTimeout(dojo.hitch(this,dijit.typematic.stop),50);}})];},addListener:function(_11a,_11b,_11c,_11d,_11e,_11f,_120,_121){return this.addKeyListener(_11b,_11c,_11d,_11e,_11f,_120,_121).concat(this.addMouseListener(_11a,_11d,_11e,_11f,_120,_121));}};}if(!dojo._hasResource["dijit._base.wai"]){dojo._hasResource["dijit._base.wai"]=true;dojo.provide("dijit._base.wai");dijit.wai={onload:function(){var div=dojo.create("div",{id:"a11yTestNode",style:{cssText:"border: 1px solid;"+"border-color:red green;"+"position: absolute;"+"height: 5px;"+"top: -999px;"+"background-image: url(\""+(dojo.config.blankGif||dojo.moduleUrl("dojo","resources/blank.gif"))+"\");"}},dojo.body());var cs=dojo.getComputedStyle(div);if(cs){var _122=cs.backgroundImage;var _123=(cs.borderTopColor==cs.borderRightColor)||(_122!=null&&(_122=="none"||_122=="url(invalid-url:)"));dojo[_123?"addClass":"removeClass"](dojo.body(),"dijit_a11y");if(dojo.isIE){div.outerHTML="";}else{dojo.body().removeChild(div);}}}};if(dojo.isIE||dojo.isMoz){dojo._loaders.unshift(dijit.wai.onload);}dojo.mixin(dijit,{_XhtmlRoles:/banner|contentinfo|definition|main|navigation|search|note|secondary|seealso/,hasWaiRole:function(elem,role){var _124=this.getWaiRole(elem);return role?(_124.indexOf(role)>-1):(_124.length>0);},getWaiRole:function(elem){return dojo.trim((dojo.attr(elem,"role")||"").replace(this._XhtmlRoles,"").replace("wairole:",""));},setWaiRole:function(elem,role){var _125=dojo.attr(elem,"role")||"";if(!this._XhtmlRoles.test(_125)){dojo.attr(elem,"role",role);}else{if((" "+_125+" ").indexOf(" "+role+" ")<0){var _126=dojo.trim(_125.replace(this._XhtmlRoles,""));var _127=dojo.trim(_125.replace(_126,""));dojo.attr(elem,"role",_127+(_127?" ":"")+role);}}},removeWaiRole:function(elem,role){var _128=dojo.attr(elem,"role");if(!_128){return;}if(role){var t=dojo.trim((" "+_128+" ").replace(" "+role+" "," "));dojo.attr(elem,"role",t);}else{elem.removeAttribute("role");}},hasWaiState:function(elem,_129){return elem.hasAttribute?elem.hasAttribute("aria-"+_129):!!elem.getAttribute("aria-"+_129);},getWaiState:function(elem,_12a){return elem.getAttribute("aria-"+_12a)||"";},setWaiState:function(elem,_12b,_12c){elem.setAttribute("aria-"+_12b,_12c);},removeWaiState:function(elem,_12d){elem.removeAttribute("aria-"+_12d);}});}if(!dojo._hasResource["dijit._base"]){dojo._hasResource["dijit._base"]=true;dojo.provide("dijit._base");}if(!dojo._hasResource["dijit._Widget"]){dojo._hasResource["dijit._Widget"]=true;dojo.provide("dijit._Widget");dojo.require("dijit._base");dojo.connect(dojo,"_connect",function(_12e,_12f){if(_12e&&dojo.isFunction(_12e._onConnect)){_12e._onConnect(_12f);}});dijit._connectOnUseEventHandler=function(_130){};dijit._lastKeyDownNode=null;if(dojo.isIE){(function(){var _131=function(evt){dijit._lastKeyDownNode=evt.srcElement;};dojo.doc.attachEvent("onkeydown",_131);dojo.addOnWindowUnload(function(){dojo.doc.detachEvent("onkeydown",_131);});})();}else{dojo.doc.addEventListener("keydown",function(evt){dijit._lastKeyDownNode=evt.target;},true);}(function(){var _132={},_133=function(_134){var dc=_134.declaredClass;if(!_132[dc]){var r=[],_135,_136=_134.constructor.prototype;for(var _137 in _136){if(dojo.isFunction(_136[_137])&&(_135=_137.match(/^_set([a-zA-Z]*)Attr$/))&&_135[1]){r.push(_135[1].charAt(0).toLowerCase()+_135[1].substr(1));}}_132[dc]=r;}return _132[dc]||[];};dojo.declare("dijit._Widget",null,{id:"",lang:"",dir:"","class":"",style:"",title:"",tooltip:"",baseClass:"",srcNodeRef:null,domNode:null,containerNode:null,attributeMap:{id:"",dir:"",lang:"","class":"",style:"",title:""},_deferredConnects:{onClick:"",onDblClick:"",onKeyDown:"",onKeyPress:"",onKeyUp:"",onMouseMove:"",onMouseDown:"",onMouseOut:"",onMouseOver:"",onMouseLeave:"",onMouseEnter:"",onMouseUp:""},onClick:dijit._connectOnUseEventHandler,onDblClick:dijit._connectOnUseEventHandler,onKeyDown:dijit._connectOnUseEventHandler,onKeyPress:dijit._connectOnUseEventHandler,onKeyUp:dijit._connectOnUseEventHandler,onMouseDown:dijit._connectOnUseEventHandler,onMouseMove:dijit._connectOnUseEventHandler,onMouseOut:dijit._connectOnUseEventHandler,onMouseOver:dijit._connectOnUseEventHandler,onMouseLeave:dijit._connectOnUseEventHandler,onMouseEnter:dijit._connectOnUseEventHandler,onMouseUp:dijit._connectOnUseEventHandler,_blankGif:(dojo.config.blankGif||dojo.moduleUrl("dojo","resources/blank.gif")).toString(),postscript:function(_138,_139){this.create(_138,_139);},create:function(_13a,_13b){this.srcNodeRef=dojo.byId(_13b);this._connects=[];this._subscribes=[];this._deferredConnects=dojo.clone(this._deferredConnects);for(var attr in this.attributeMap){delete this._deferredConnects[attr];}for(attr in this._deferredConnects){if(this[attr]!==dijit._connectOnUseEventHandler){delete this._deferredConnects[attr];}}if(this.srcNodeRef&&(typeof this.srcNodeRef.id=="string")){this.id=this.srcNodeRef.id;}if(_13a){this.params=_13a;dojo.mixin(this,_13a);}this.postMixInProperties();if(!this.id){this.id=dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));}dijit.registry.add(this);this.buildRendering();if(this.domNode){this._applyAttributes();var _13c=this.srcNodeRef;if(_13c&&_13c.parentNode){_13c.parentNode.replaceChild(this.domNode,_13c);}for(attr in this.params){this._onConnect(attr);}}if(this.domNode){this.domNode.setAttribute("widgetId",this.id);}this.postCreate();if(this.srcNodeRef&&!this.srcNodeRef.parentNode){delete this.srcNodeRef;}this._created=true;},_applyAttributes:function(){var _13d=function(attr,_13e){if((_13e.params&&attr in _13e.params)||_13e[attr]){_13e.set(attr,_13e[attr]);}};for(var attr in this.attributeMap){_13d(attr,this);}dojo.forEach(_133(this),function(a){if(!(a in this.attributeMap)){_13d(a,this);}},this);},postMixInProperties:function(){},buildRendering:function(){this.domNode=this.srcNodeRef||dojo.create("div");},postCreate:function(){if(this.baseClass){var _13f=this.baseClass.split(" ");if(!this.isLeftToRight()){_13f=_13f.concat(dojo.map(_13f,function(name){return name+"Rtl";}));}dojo.addClass(this.domNode,_13f);}},startup:function(){this._started=true;},destroyRecursive:function(_140){this._beingDestroyed=true;this.destroyDescendants(_140);this.destroy(_140);},destroy:function(_141){this._beingDestroyed=true;this.uninitialize();var d=dojo,dfe=d.forEach,dun=d.unsubscribe;dfe(this._connects,function(_142){dfe(_142,d.disconnect);});dfe(this._subscribes,function(_143){dun(_143);});dfe(this._supportingWidgets||[],function(w){if(w.destroyRecursive){w.destroyRecursive();}else{if(w.destroy){w.destroy();}}});this.destroyRendering(_141);dijit.registry.remove(this.id);this._destroyed=true;},destroyRendering:function(_144){if(this.bgIframe){this.bgIframe.destroy(_144);delete this.bgIframe;}if(this.domNode){if(_144){dojo.removeAttr(this.domNode,"widgetId");}else{dojo.destroy(this.domNode);}delete this.domNode;}if(this.srcNodeRef){if(!_144){dojo.destroy(this.srcNodeRef);}delete this.srcNodeRef;}},destroyDescendants:function(_145){dojo.forEach(this.getChildren(),function(_146){if(_146.destroyRecursive){_146.destroyRecursive(_145);}});},uninitialize:function(){return false;},onFocus:function(){},onBlur:function(){},_onFocus:function(e){this.onFocus();},_onBlur:function(){this.onBlur();},_onConnect:function(_147){if(_147 in this._deferredConnects){var _148=this[this._deferredConnects[_147]||"domNode"];this.connect(_148,_147.toLowerCase(),_147);delete this._deferredConnects[_147];}},_setClassAttr:function(_149){var _14a=this[this.attributeMap["class"]||"domNode"];dojo.removeClass(_14a,this["class"]);this["class"]=_149;dojo.addClass(_14a,_149);},_setStyleAttr:function(_14b){var _14c=this[this.attributeMap.style||"domNode"];if(dojo.isObject(_14b)){dojo.style(_14c,_14b);}else{if(_14c.style.cssText){_14c.style.cssText+="; "+_14b;}else{_14c.style.cssText=_14b;}}this.style=_14b;},setAttribute:function(attr,_14d){dojo.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.","","2.0");this.set(attr,_14d);},_attrToDom:function(attr,_14e){var _14f=this.attributeMap[attr];dojo.forEach(dojo.isArray(_14f)?_14f:[_14f],function(_150){var _151=this[_150.node||_150||"domNode"];var type=_150.type||"attribute";switch(type){case "attribute":if(dojo.isFunction(_14e)){_14e=dojo.hitch(this,_14e);}var _152=_150.attribute?_150.attribute:(/^on[A-Z][a-zA-Z]*$/.test(attr)?attr.toLowerCase():attr);dojo.attr(_151,_152,_14e);break;case "innerText":_151.innerHTML="";_151.appendChild(dojo.doc.createTextNode(_14e));break;case "innerHTML":_151.innerHTML=_14e;break;case "class":dojo.removeClass(_151,this[attr]);dojo.addClass(_151,_14e);break;}},this);this[attr]=_14e;},attr:function(name,_153){if(dojo.config.isDebug){var _154=arguments.callee._ach||(arguments.callee._ach={}),_155=(arguments.callee.caller||"unknown caller").toString();if(!_154[_155]){dojo.deprecated(this.declaredClass+"::attr() is deprecated. Use get() or set() instead, called from "+_155,"","2.0");_154[_155]=true;}}var args=arguments.length;if(args>=2||typeof name==="object"){return this.set.apply(this,arguments);}else{return this.get(name);}},get:function(name){var _156=this._getAttrNames(name);return this[_156.g]?this[_156.g]():this[name];},set:function(name,_157){if(typeof name==="object"){for(var x in name){this.set(x,name[x]);}return this;}var _158=this._getAttrNames(name);if(this[_158.s]){var _159=this[_158.s].apply(this,Array.prototype.slice.call(arguments,1));}else{if(name in this.attributeMap){this._attrToDom(name,_157);}var _15a=this[name];this[name]=_157;}return _159||this;},_attrPairNames:{},_getAttrNames:function(name){var apn=this._attrPairNames;if(apn[name]){return apn[name];}var uc=name.charAt(0).toUpperCase()+name.substr(1);return (apn[name]={n:name+"Node",s:"_set"+uc+"Attr",g:"_get"+uc+"Attr"});},toString:function(){return "[Widget "+this.declaredClass+", "+(this.id||"NO ID")+"]";},getDescendants:function(){return this.containerNode?dojo.query("[widgetId]",this.containerNode).map(dijit.byNode):[];},getChildren:function(){return this.containerNode?dijit.findWidgets(this.containerNode):[];},nodesWithKeyClick:["input","button"],connect:function(obj,_15b,_15c){var d=dojo,dc=d._connect,_15d=[];if(_15b=="ondijitclick"){if(dojo.indexOf(this.nodesWithKeyClick,obj.nodeName.toLowerCase())==-1){var m=d.hitch(this,_15c);_15d.push(dc(obj,"onkeydown",this,function(e){if((e.keyCode==d.keys.ENTER||e.keyCode==d.keys.SPACE)&&!e.ctrlKey&&!e.shiftKey&&!e.altKey&&!e.metaKey){dijit._lastKeyDownNode=e.target;e.preventDefault();}}),dc(obj,"onkeyup",this,function(e){if((e.keyCode==d.keys.ENTER||e.keyCode==d.keys.SPACE)&&e.target===dijit._lastKeyDownNode&&!e.ctrlKey&&!e.shiftKey&&!e.altKey&&!e.metaKey){dijit._lastKeyDownNode=null;return m(e);}}));}_15b="onclick";}_15d.push(dc(obj,_15b,this,_15c));this._connects.push(_15d);return _15d;},disconnect:function(_15e){for(var i=0;i<this._connects.length;i++){if(this._connects[i]==_15e){dojo.forEach(_15e,dojo.disconnect);this._connects.splice(i,1);return;}}},subscribe:function(_15f,_160){var d=dojo,_161=d.subscribe(_15f,this,_160);this._subscribes.push(_161);return _161;},unsubscribe:function(_162){for(var i=0;i<this._subscribes.length;i++){if(this._subscribes[i]==_162){dojo.unsubscribe(_162);this._subscribes.splice(i,1);return;}}},isLeftToRight:function(){return this.dir?(this.dir=="ltr"):dojo._isBodyLtr();},isFocusable:function(){return this.focus&&(dojo.style(this.domNode,"display")!="none");},placeAt:function(_163,_164){if(_163.declaredClass&&_163.addChild){_163.addChild(this,_164);}else{dojo.place(this.domNode,_163,_164);}return this;},_onShow:function(){this.onShow();},onShow:function(){},onHide:function(){},onClose:function(){return true;}});})();}if(!dojo._hasResource["dojo.string"]){dojo._hasResource["dojo.string"]=true;dojo.provide("dojo.string");dojo.string.rep=function(str,num){if(num<=0||!str){return "";}var buf=[];for(;;){if(num&1){buf.push(str);}if(!(num>>=1)){break;}str+=str;}return buf.join("");};dojo.string.pad=function(text,size,ch,end){if(!ch){ch="0";}var out=String(text),pad=dojo.string.rep(ch,Math.ceil((size-out.length)/ch.length));return end?out+pad:pad+out;};dojo.string.substitute=function(_165,map,_166,_167){_167=_167||dojo.global;_166=_166?dojo.hitch(_167,_166):function(v){return v;};return _165.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,function(_168,key,_169){var _16a=dojo.getObject(key,false,map);if(_169){_16a=dojo.getObject(_169,false,_167).call(_167,_16a,key);}return _166(_16a,key).toString();});};dojo.string.trim=String.prototype.trim?dojo.trim:function(str){str=str.replace(/^\s+/,"");for(var i=str.length-1;i>=0;i--){if(/\S/.test(str.charAt(i))){str=str.substring(0,i+1);break;}}return str;};}if(!dojo._hasResource["dojo.cache"]){dojo._hasResource["dojo.cache"]=true;dojo.provide("dojo.cache");(function(){var _16b={};dojo.cache=function(_16c,url,_16d){if(typeof _16c=="string"){var _16e=dojo.moduleUrl(_16c,url);}else{_16e=_16c;_16d=url;}var key=_16e.toString();var val=_16d;if(_16d!=undefined&&!dojo.isString(_16d)){val=("value" in _16d?_16d.value:undefined);}var _16f=_16d&&_16d.sanitize?true:false;if(typeof val=="string"){val=_16b[key]=_16f?dojo.cache._sanitize(val):val;}else{if(val===null){delete _16b[key];}else{if(!(key in _16b)){val=dojo._getText(key);_16b[key]=_16f?dojo.cache._sanitize(val):val;}val=_16b[key];}}return val;};dojo.cache._sanitize=function(val){if(val){val=val.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,"");var _170=val.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);if(_170){val=_170[1];}}else{val="";}return val;};})();}if(!dojo._hasResource["dijit._Templated"]){dojo._hasResource["dijit._Templated"]=true;dojo.provide("dijit._Templated");dojo.declare("dijit._Templated",null,{templateString:null,templatePath:null,widgetsInTemplate:false,_skipNodeCache:false,_earlyTemplatedStartup:false,constructor:function(){this._attachPoints=[];},_stringRepl:function(tmpl){var _171=this.declaredClass,_172=this;return dojo.string.substitute(tmpl,this,function(_173,key){if(key.charAt(0)=="!"){_173=dojo.getObject(key.substr(1),false,_172);}if(typeof _173=="undefined"){throw new Error(_171+" template:"+key);}if(_173==null){return "";}return key.charAt(0)=="!"?_173:_173.toString().replace(/"/g,"&quot;");},this);},buildRendering:function(){var _174=dijit._Templated.getCachedTemplate(this.templatePath,this.templateString,this._skipNodeCache);var node;if(dojo.isString(_174)){node=dojo._toDom(this._stringRepl(_174));if(node.nodeType!=1){throw new Error("Invalid template: "+_174);}}else{node=_174.cloneNode(true);}this.domNode=node;this._attachTemplateNodes(node);if(this.widgetsInTemplate){var _175=dojo.parser,qry,attr;if(_175._query!="[dojoType]"){qry=_175._query;attr=_175._attrName;_175._query="[dojoType]";_175._attrName="dojoType";}var cw=(this._startupWidgets=dojo.parser.parse(node,{noStart:!this._earlyTemplatedStartup,inherited:{dir:this.dir,lang:this.lang}}));if(qry){_175._query=qry;_175._attrName=attr;}this._supportingWidgets=dijit.findWidgets(node);this._attachTemplateNodes(cw,function(n,p){return n[p];});}this._fillContent(this.srcNodeRef);},_fillContent:function(_176){var dest=this.containerNode;if(_176&&dest){while(_176.hasChildNodes()){dest.appendChild(_176.firstChild);}}},_attachTemplateNodes:function(_177,_178){_178=_178||function(n,p){return n.getAttribute(p);};var _179=dojo.isArray(_177)?_177:(_177.all||_177.getElementsByTagName("*"));var x=dojo.isArray(_177)?0:-1;for(;x<_179.length;x++){var _17a=(x==-1)?_177:_179[x];if(this.widgetsInTemplate&&_178(_17a,"dojoType")){continue;}var _17b=_178(_17a,"dojoAttachPoint");if(_17b){var _17c,_17d=_17b.split(/\s*,\s*/);while((_17c=_17d.shift())){if(dojo.isArray(this[_17c])){this[_17c].push(_17a);}else{this[_17c]=_17a;}this._attachPoints.push(_17c);}}var _17e=_178(_17a,"dojoAttachEvent");if(_17e){var _17f,_180=_17e.split(/\s*,\s*/);var trim=dojo.trim;while((_17f=_180.shift())){if(_17f){var _181=null;if(_17f.indexOf(":")!=-1){var _182=_17f.split(":");_17f=trim(_182[0]);_181=trim(_182[1]);}else{_17f=trim(_17f);}if(!_181){_181=_17f;}this.connect(_17a,_17f,_181);}}}var role=_178(_17a,"waiRole");if(role){dijit.setWaiRole(_17a,role);}var _183=_178(_17a,"waiState");if(_183){dojo.forEach(_183.split(/\s*,\s*/),function(_184){if(_184.indexOf("-")!=-1){var pair=_184.split("-");dijit.setWaiState(_17a,pair[0],pair[1]);}});}}},startup:function(){dojo.forEach(this._startupWidgets,function(w){if(w&&!w._started&&w.startup){w.startup();}});this.inherited(arguments);},destroyRendering:function(){dojo.forEach(this._attachPoints,function(_185){delete this[_185];},this);this._attachPoints=[];this.inherited(arguments);}});dijit._Templated._templateCache={};dijit._Templated.getCachedTemplate=function(_186,_187,_188){var _189=dijit._Templated._templateCache;var key=_187||_186;var _18a=_189[key];if(_18a){try{if(!_18a.ownerDocument||_18a.ownerDocument==dojo.doc){return _18a;}}catch(e){}dojo.destroy(_18a);}if(!_187){_187=dojo.cache(_186,{sanitize:true});}_187=dojo.string.trim(_187);if(_188||_187.match(/\$\{([^\}]+)\}/g)){return (_189[key]=_187);}else{var node=dojo._toDom(_187);if(node.nodeType!=1){throw new Error("Invalid template: "+_187);}return (_189[key]=node);}};if(dojo.isIE){dojo.addOnWindowUnload(function(){var _18b=dijit._Templated._templateCache;for(var key in _18b){var _18c=_18b[key];if(typeof _18c=="object"){dojo.destroy(_18c);}delete _18b[key];}});}dojo.extend(dijit._Widget,{dojoAttachEvent:"",dojoAttachPoint:"",waiRole:"",waiState:""});}if(!dojo._hasResource["dijit._Container"]){dojo._hasResource["dijit._Container"]=true;dojo.provide("dijit._Container");dojo.declare("dijit._Container",null,{isContainer:true,buildRendering:function(){this.inherited(arguments);if(!this.containerNode){this.containerNode=this.domNode;}},addChild:function(_18d,_18e){var _18f=this.containerNode;if(_18e&&typeof _18e=="number"){var _190=this.getChildren();if(_190&&_190.length>=_18e){_18f=_190[_18e-1].domNode;_18e="after";}}dojo.place(_18d.domNode,_18f,_18e);if(this._started&&!_18d._started){_18d.startup();}},removeChild:function(_191){if(typeof _191=="number"&&_191>0){_191=this.getChildren()[_191];}if(_191){var node=_191.domNode;if(node&&node.parentNode){node.parentNode.removeChild(node);}}},hasChildren:function(){return this.getChildren().length>0;},destroyDescendants:function(_192){dojo.forEach(this.getChildren(),function(_193){_193.destroyRecursive(_192);});},_getSiblingOfChild:function(_194,dir){var node=_194.domNode,_195=(dir>0?"nextSibling":"previousSibling");do{node=node[_195];}while(node&&(node.nodeType!=1||!dijit.byNode(node)));return node&&dijit.byNode(node);},getIndexOfChild:function(_196){return dojo.indexOf(this.getChildren(),_196);},startup:function(){if(this._started){return;}dojo.forEach(this.getChildren(),function(_197){_197.startup();});this.inherited(arguments);}});}if(!dojo._hasResource["dijit._Contained"]){dojo._hasResource["dijit._Contained"]=true;dojo.provide("dijit._Contained");dojo.declare("dijit._Contained",null,{getParent:function(){var _198=dijit.getEnclosingWidget(this.domNode.parentNode);return _198&&_198.isContainer?_198:null;},_getSibling:function(_199){var node=this.domNode;do{node=node[_199+"Sibling"];}while(node&&node.nodeType!=1);return node&&dijit.byNode(node);},getPreviousSibling:function(){return this._getSibling("previous");},getNextSibling:function(){return this._getSibling("next");},getIndexInParent:function(){var p=this.getParent();if(!p||!p.getIndexOfChild){return -1;}return p.getIndexOfChild(this);}});}if(!dojo._hasResource["dijit.layout._LayoutWidget"]){dojo._hasResource["dijit.layout._LayoutWidget"]=true;dojo.provide("dijit.layout._LayoutWidget");dojo.declare("dijit.layout._LayoutWidget",[dijit._Widget,dijit._Container,dijit._Contained],{baseClass:"dijitLayoutContainer",isLayoutContainer:true,postCreate:function(){dojo.addClass(this.domNode,"dijitContainer");this.inherited(arguments);},startup:function(){if(this._started){return;}this.inherited(arguments);var _19a=this.getParent&&this.getParent();if(!(_19a&&_19a.isLayoutContainer)){this.resize();this.connect(dojo.isIE?this.domNode:dojo.global,"onresize",function(){this.resize();});}},resize:function(_19b,_19c){var node=this.domNode;if(_19b){dojo.marginBox(node,_19b);if(_19b.t){node.style.top=_19b.t+"px";}if(_19b.l){node.style.left=_19b.l+"px";}}var mb=_19c||{};dojo.mixin(mb,_19b||{});if(!("h" in mb)||!("w" in mb)){mb=dojo.mixin(dojo.marginBox(node),mb);}var cs=dojo.getComputedStyle(node);var me=dojo._getMarginExtents(node,cs);var be=dojo._getBorderExtents(node,cs);var bb=(this._borderBox={w:mb.w-(me.w+be.w),h:mb.h-(me.h+be.h)});var pe=dojo._getPadExtents(node,cs);this._contentBox={l:dojo._toPixelValue(node,cs.paddingLeft),t:dojo._toPixelValue(node,cs.paddingTop),w:bb.w-pe.w,h:bb.h-pe.h};this.layout();},layout:function(){},_setupChild:function(_19d){dojo.addClass(_19d.domNode,this.baseClass+"-child");if(_19d.baseClass){dojo.addClass(_19d.domNode,this.baseClass+"-"+_19d.baseClass);}},addChild:function(_19e,_19f){this.inherited(arguments);if(this._started){this._setupChild(_19e);}},removeChild:function(_1a0){dojo.removeClass(_1a0.domNode,this.baseClass+"-child");if(_1a0.baseClass){dojo.removeClass(_1a0.domNode,this.baseClass+"-"+_1a0.baseClass);}this.inherited(arguments);}});dijit.layout.marginBox2contentBox=function(node,mb){var cs=dojo.getComputedStyle(node);var me=dojo._getMarginExtents(node,cs);var pb=dojo._getPadBorderExtents(node,cs);return {l:dojo._toPixelValue(node,cs.paddingLeft),t:dojo._toPixelValue(node,cs.paddingTop),w:mb.w-(me.w+pb.w),h:mb.h-(me.h+pb.h)};};(function(){var _1a1=function(word){return word.substring(0,1).toUpperCase()+word.substring(1);};var size=function(_1a2,dim){_1a2.resize?_1a2.resize(dim):dojo.marginBox(_1a2.domNode,dim);dojo.mixin(_1a2,dojo.marginBox(_1a2.domNode));dojo.mixin(_1a2,dim);};dijit.layout.layoutChildren=function(_1a3,dim,_1a4){dim=dojo.mixin({},dim);dojo.addClass(_1a3,"dijitLayoutContainer");_1a4=dojo.filter(_1a4,function(item){return item.layoutAlign!="client";}).concat(dojo.filter(_1a4,function(item){return item.layoutAlign=="client";}));dojo.forEach(_1a4,function(_1a5){var elm=_1a5.domNode,pos=_1a5.layoutAlign;var _1a6=elm.style;_1a6.left=dim.l+"px";_1a6.top=dim.t+"px";_1a6.bottom=_1a6.right="auto";dojo.addClass(elm,"dijitAlign"+_1a1(pos));if(pos=="top"||pos=="bottom"){size(_1a5,{w:dim.w});dim.h-=_1a5.h;if(pos=="top"){dim.t+=_1a5.h;}else{_1a6.top=dim.t+dim.h+"px";}}else{if(pos=="left"||pos=="right"){size(_1a5,{h:dim.h});dim.w-=_1a5.w;if(pos=="left"){dim.l+=_1a5.w;}else{_1a6.left=dim.l+dim.w+"px";}}else{if(pos=="client"){size(_1a5,dim);}}}});};})();}if(!dojo._hasResource["dijit._CssStateMixin"]){dojo._hasResource["dijit._CssStateMixin"]=true;dojo.provide("dijit._CssStateMixin");dojo.declare("dijit._CssStateMixin",[],{cssStateNodes:{},postCreate:function(){this.inherited(arguments);dojo.forEach(["onmouseenter","onmouseleave","onmousedown"],function(e){this.connect(this.domNode,e,"_cssMouseEvent");},this);this.connect(this,"set",function(name,_1a7){if(arguments.length>=2&&{disabled:true,readOnly:true,checked:true,selected:true}[name]){this._setStateClass();}});dojo.forEach(["_onFocus","_onBlur"],function(ap){this.connect(this,ap,"_setStateClass");},this);for(var ap in this.cssStateNodes){this._trackMouseState(this[ap],this.cssStateNodes[ap]);}this._setStateClass();},_cssMouseEvent:function(_1a8){if(!this.disabled){switch(_1a8.type){case "mouseenter":case "mouseover":this._hovering=true;this._active=this._mouseDown;break;case "mouseleave":case "mouseout":this._hovering=false;this._active=false;break;case "mousedown":this._active=true;this._mouseDown=true;var _1a9=this.connect(dojo.body(),"onmouseup",function(){this._active=false;this._mouseDown=false;this._setStateClass();this.disconnect(_1a9);});break;}this._setStateClass();}},_setStateClass:function(){var _1aa=this.baseClass.split(" ");function _1ab(_1ac){_1aa=_1aa.concat(dojo.map(_1aa,function(c){return c+_1ac;}),"dijit"+_1ac);};if(!this.isLeftToRight()){_1ab("Rtl");}if(this.checked){_1ab("Checked");}if(this.state){_1ab(this.state);}if(this.selected){_1ab("Selected");}if(this.disabled){_1ab("Disabled");}else{if(this.readOnly){_1ab("ReadOnly");}else{if(this._active){_1ab("Active");}else{if(this._hovering){_1ab("Hover");}}}}if(this._focused){_1ab("Focused");}var tn=this.stateNode||this.domNode,_1ad={};dojo.forEach(tn.className.split(" "),function(c){_1ad[c]=true;});if("_stateClasses" in this){dojo.forEach(this._stateClasses,function(c){delete _1ad[c];});}dojo.forEach(_1aa,function(c){_1ad[c]=true;});var _1ae=[];for(var c in _1ad){_1ae.push(c);}tn.className=_1ae.join(" ");this._stateClasses=_1aa;},_trackMouseState:function(node,_1af){var _1b0=false,_1b1=false,_1b2=false;var self=this,cn=dojo.hitch(this,"connect",node);function _1b3(){var _1b4=("disabled" in self&&self.disabled)||("readonly" in self&&self.readonly);dojo.toggleClass(node,_1af+"Hover",_1b0&&!_1b1&&!_1b4);dojo.toggleClass(node,_1af+"Active",_1b1&&!_1b4);dojo.toggleClass(node,_1af+"Focused",_1b2&&!_1b4);};cn("onmouseenter",function(){_1b0=true;_1b3();});cn("onmouseleave",function(){_1b0=false;_1b1=false;_1b3();});cn("onmousedown",function(){_1b1=true;_1b3();});cn("onmouseup",function(){_1b1=false;_1b3();});cn("onfocus",function(){_1b2=true;_1b3();});cn("onblur",function(){_1b2=false;_1b3();});this.connect(this,"set",function(name,_1b5){if(name=="disabled"||name=="readOnly"){_1b3();}});}});}if(!dojo._hasResource["dijit.form._FormWidget"]){dojo._hasResource["dijit.form._FormWidget"]=true;dojo.provide("dijit.form._FormWidget");dojo.declare("dijit.form._FormWidget",[dijit._Widget,dijit._Templated,dijit._CssStateMixin],{name:"",alt:"",value:"",type:"text",tabIndex:"0",disabled:false,intermediateChanges:false,scrollOnFocus:true,attributeMap:dojo.delegate(dijit._Widget.prototype.attributeMap,{value:"focusNode",id:"focusNode",tabIndex:"focusNode",alt:"focusNode",title:"focusNode"}),postMixInProperties:function(){this.nameAttrSetting=this.name?("name=\""+this.name.replace(/'/g,"&quot;")+"\""):"";this.inherited(arguments);},postCreate:function(){this.inherited(arguments);this.connect(this.domNode,"onmousedown","_onMouseDown");},_setDisabledAttr:function(_1b6){this.disabled=_1b6;dojo.attr(this.focusNode,"disabled",_1b6);if(this.valueNode){dojo.attr(this.valueNode,"disabled",_1b6);}dijit.setWaiState(this.focusNode,"disabled",_1b6);if(_1b6){this._hovering=false;this._active=false;var _1b7="tabIndex" in this.attributeMap?this.attributeMap.tabIndex:"focusNode";dojo.forEach(dojo.isArray(_1b7)?_1b7:[_1b7],function(_1b8){var node=this[_1b8];if(dojo.isWebKit||dijit.hasDefaultTabStop(node)){node.setAttribute("tabIndex","-1");}else{node.removeAttribute("tabIndex");}},this);}else{this.focusNode.setAttribute("tabIndex",this.tabIndex);}},setDisabled:function(_1b9){dojo.deprecated("setDisabled("+_1b9+") is deprecated. Use set('disabled',"+_1b9+") instead.","","2.0");this.set("disabled",_1b9);},_onFocus:function(e){if(this.scrollOnFocus){dojo.window.scrollIntoView(this.domNode);}this.inherited(arguments);},isFocusable:function(){return !this.disabled&&!this.readOnly&&this.focusNode&&(dojo.style(this.domNode,"display")!="none");},focus:function(){dijit.focus(this.focusNode);},compare:function(val1,val2){if(typeof val1=="number"&&typeof val2=="number"){return (isNaN(val1)&&isNaN(val2))?0:val1-val2;}else{if(val1>val2){return 1;}else{if(val1<val2){return -1;}else{return 0;}}}},onChange:function(_1ba){},_onChangeActive:false,_handleOnChange:function(_1bb,_1bc){this._lastValue=_1bb;if(this._lastValueReported==undefined&&(_1bc===null||!this._onChangeActive)){this._resetValue=this._lastValueReported=_1bb;}if((this.intermediateChanges||_1bc||_1bc===undefined)&&((typeof _1bb!=typeof this._lastValueReported)||this.compare(_1bb,this._lastValueReported)!=0)){this._lastValueReported=_1bb;if(this._onChangeActive){if(this._onChangeHandle){clearTimeout(this._onChangeHandle);}this._onChangeHandle=setTimeout(dojo.hitch(this,function(){this._onChangeHandle=null;this.onChange(_1bb);}),0);}}},create:function(){this.inherited(arguments);this._onChangeActive=true;},destroy:function(){if(this._onChangeHandle){clearTimeout(this._onChangeHandle);this.onChange(this._lastValueReported);}this.inherited(arguments);},setValue:function(_1bd){dojo.deprecated("dijit.form._FormWidget:setValue("+_1bd+") is deprecated. Use set('value',"+_1bd+") instead.","","2.0");this.set("value",_1bd);},getValue:function(){dojo.deprecated(this.declaredClass+"::getValue() is deprecated. Use get('value') instead.","","2.0");return this.get("value");},_onMouseDown:function(e){if(!e.ctrlKey&&this.isFocusable()){var _1be=this.connect(dojo.body(),"onmouseup",function(){if(this.isFocusable()){this.focus();}this.disconnect(_1be);});}}});dojo.declare("dijit.form._FormValueWidget",dijit.form._FormWidget,{readOnly:false,attributeMap:dojo.delegate(dijit.form._FormWidget.prototype.attributeMap,{value:"",readOnly:"focusNode"}),_setReadOnlyAttr:function(_1bf){this.readOnly=_1bf;dojo.attr(this.focusNode,"readOnly",_1bf);dijit.setWaiState(this.focusNode,"readonly",_1bf);},postCreate:function(){this.inherited(arguments);if(dojo.isIE){this.connect(this.focusNode||this.domNode,"onkeydown",this._onKeyDown);}if(this._resetValue===undefined){this._resetValue=this.value;}},_setValueAttr:function(_1c0,_1c1){this.value=_1c0;this._handleOnChange(_1c0,_1c1);},_getValueAttr:function(){return this._lastValue;},undo:function(){this._setValueAttr(this._lastValueReported,false);},reset:function(){this._hasBeenBlurred=false;this._setValueAttr(this._resetValue,true);},_onKeyDown:function(e){if(e.keyCode==dojo.keys.ESCAPE&&!(e.ctrlKey||e.altKey||e.metaKey)){var te;if(dojo.isIE){e.preventDefault();te=document.createEventObject();te.keyCode=dojo.keys.ESCAPE;te.shiftKey=e.shiftKey;e.srcElement.fireEvent("onkeypress",te);}}},_layoutHackIE7:function(){if(dojo.isIE==7){var _1c2=this.domNode;var _1c3=_1c2.parentNode;var _1c4=_1c2.firstChild||_1c2;var _1c5=_1c4.style.filter;var _1c6=this;while(_1c3&&_1c3.clientHeight==0){(function ping(){var _1c7=_1c6.connect(_1c3,"onscroll",function(e){_1c6.disconnect(_1c7);_1c4.style.filter=(new Date()).getMilliseconds();setTimeout(function(){_1c4.style.filter=_1c5;},0);});})();_1c3=_1c3.parentNode;}}}});}if(!dojo._hasResource["dijit.dijit"]){dojo._hasResource["dijit.dijit"]=true;dojo.provide("dijit.dijit");}if(!dojo._hasResource["dojo.fx.Toggler"]){dojo._hasResource["dojo.fx.Toggler"]=true;dojo.provide("dojo.fx.Toggler");dojo.declare("dojo.fx.Toggler",null,{node:null,showFunc:dojo.fadeIn,hideFunc:dojo.fadeOut,showDuration:200,hideDuration:200,constructor:function(args){var _1c8=this;dojo.mixin(_1c8,args);_1c8.node=args.node;_1c8._showArgs=dojo.mixin({},args);_1c8._showArgs.node=_1c8.node;_1c8._showArgs.duration=_1c8.showDuration;_1c8.showAnim=_1c8.showFunc(_1c8._showArgs);_1c8._hideArgs=dojo.mixin({},args);_1c8._hideArgs.node=_1c8.node;_1c8._hideArgs.duration=_1c8.hideDuration;_1c8.hideAnim=_1c8.hideFunc(_1c8._hideArgs);dojo.connect(_1c8.showAnim,"beforeBegin",dojo.hitch(_1c8.hideAnim,"stop",true));dojo.connect(_1c8.hideAnim,"beforeBegin",dojo.hitch(_1c8.showAnim,"stop",true));},show:function(_1c9){return this.showAnim.play(_1c9||0);},hide:function(_1ca){return this.hideAnim.play(_1ca||0);}});}if(!dojo._hasResource["dojo.fx"]){dojo._hasResource["dojo.fx"]=true;dojo.provide("dojo.fx");(function(){var d=dojo,_1cb={_fire:function(evt,args){if(this[evt]){this[evt].apply(this,args||[]);}return this;}};var _1cc=function(_1cd){this._index=-1;this._animations=_1cd||[];this._current=this._onAnimateCtx=this._onEndCtx=null;this.duration=0;d.forEach(this._animations,function(a){this.duration+=a.duration;if(a.delay){this.duration+=a.delay;}},this);};d.extend(_1cc,{_onAnimate:function(){this._fire("onAnimate",arguments);},_onEnd:function(){d.disconnect(this._onAnimateCtx);d.disconnect(this._onEndCtx);this._onAnimateCtx=this._onEndCtx=null;if(this._index+1==this._animations.length){this._fire("onEnd");}else{this._current=this._animations[++this._index];this._onAnimateCtx=d.connect(this._current,"onAnimate",this,"_onAnimate");this._onEndCtx=d.connect(this._current,"onEnd",this,"_onEnd");this._current.play(0,true);}},play:function(_1ce,_1cf){if(!this._current){this._current=this._animations[this._index=0];}if(!_1cf&&this._current.status()=="playing"){return this;}var _1d0=d.connect(this._current,"beforeBegin",this,function(){this._fire("beforeBegin");}),_1d1=d.connect(this._current,"onBegin",this,function(arg){this._fire("onBegin",arguments);}),_1d2=d.connect(this._current,"onPlay",this,function(arg){this._fire("onPlay",arguments);d.disconnect(_1d0);d.disconnect(_1d1);d.disconnect(_1d2);});if(this._onAnimateCtx){d.disconnect(this._onAnimateCtx);}this._onAnimateCtx=d.connect(this._current,"onAnimate",this,"_onAnimate");if(this._onEndCtx){d.disconnect(this._onEndCtx);}this._onEndCtx=d.connect(this._current,"onEnd",this,"_onEnd");this._current.play.apply(this._current,arguments);return this;},pause:function(){if(this._current){var e=d.connect(this._current,"onPause",this,function(arg){this._fire("onPause",arguments);d.disconnect(e);});this._current.pause();}return this;},gotoPercent:function(_1d3,_1d4){this.pause();var _1d5=this.duration*_1d3;this._current=null;d.some(this._animations,function(a){if(a.duration<=_1d5){this._current=a;return true;}_1d5-=a.duration;return false;});if(this._current){this._current.gotoPercent(_1d5/this._current.duration,_1d4);}return this;},stop:function(_1d6){if(this._current){if(_1d6){for(;this._index+1<this._animations.length;++this._index){this._animations[this._index].stop(true);}this._current=this._animations[this._index];}var e=d.connect(this._current,"onStop",this,function(arg){this._fire("onStop",arguments);d.disconnect(e);});this._current.stop();}return this;},status:function(){return this._current?this._current.status():"stopped";},destroy:function(){if(this._onAnimateCtx){d.disconnect(this._onAnimateCtx);}if(this._onEndCtx){d.disconnect(this._onEndCtx);}}});d.extend(_1cc,_1cb);dojo.fx.chain=function(_1d7){return new _1cc(_1d7);};var _1d8=function(_1d9){this._animations=_1d9||[];this._connects=[];this._finished=0;this.duration=0;d.forEach(_1d9,function(a){var _1da=a.duration;if(a.delay){_1da+=a.delay;}if(this.duration<_1da){this.duration=_1da;}this._connects.push(d.connect(a,"onEnd",this,"_onEnd"));},this);this._pseudoAnimation=new d.Animation({curve:[0,1],duration:this.duration});var self=this;d.forEach(["beforeBegin","onBegin","onPlay","onAnimate","onPause","onStop","onEnd"],function(evt){self._connects.push(d.connect(self._pseudoAnimation,evt,function(){self._fire(evt,arguments);}));});};d.extend(_1d8,{_doAction:function(_1db,args){d.forEach(this._animations,function(a){a[_1db].apply(a,args);});return this;},_onEnd:function(){if(++this._finished>this._animations.length){this._fire("onEnd");}},_call:function(_1dc,args){var t=this._pseudoAnimation;t[_1dc].apply(t,args);},play:function(_1dd,_1de){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(_1df,_1e0){var ms=this.duration*_1df;d.forEach(this._animations,function(a){a.gotoPercent(a.duration<ms?1:(ms/a.duration),_1e0);});this._call("gotoPercent",arguments);return this;},stop:function(_1e1){this._doAction("stop",arguments);this._call("stop",arguments);return this;},status:function(){return this._pseudoAnimation.status();},destroy:function(){d.forEach(this._connects,dojo.disconnect);}});d.extend(_1d8,_1cb);dojo.fx.combine=function(_1e2){return new _1d8(_1e2);};dojo.fx.wipeIn=function(args){var node=args.node=d.byId(args.node),s=node.style,o;var anim=d.animateProperty(d.mixin({properties:{height:{start:function(){o=s.overflow;s.overflow="hidden";if(s.visibility=="hidden"||s.display=="none"){s.height="1px";s.display="";s.visibility="";return 1;}else{var _1e3=d.style(node,"height");return Math.max(_1e3,1);}},end:function(){return node.scrollHeight;}}}},args));d.connect(anim,"onEnd",function(){s.height="auto";s.overflow=o;});return anim;};dojo.fx.wipeOut=function(args){var node=args.node=d.byId(args.node),s=node.style,o;var anim=d.animateProperty(d.mixin({properties:{height:{end:1}}},args));d.connect(anim,"beforeBegin",function(){o=s.overflow;s.overflow="hidden";s.display="";});d.connect(anim,"onEnd",function(){s.overflow=o;s.height="auto";s.display="none";});return anim;};dojo.fx.slideTo=function(args){var node=args.node=d.byId(args.node),top=null,left=null;var init=(function(n){return function(){var cs=d.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=d.position(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=d.animateProperty(d.mixin({properties:{top:args.top||0,left:args.left||0}},args));d.connect(anim,"beforeBegin",anim,init);return anim;};})();}if(!dojo._hasResource["dojo.NodeList-fx"]){dojo._hasResource["dojo.NodeList-fx"]=true;dojo.provide("dojo.NodeList-fx");dojo.extend(dojo.NodeList,{_anim:function(obj,_1e4,args){args=args||{};var a=dojo.fx.combine(this.map(function(item){var _1e5={node:item};dojo.mixin(_1e5,args);return obj[_1e4](_1e5);}));return args.auto?a.play()&&this:a;},wipeIn:function(args){return this._anim(dojo.fx,"wipeIn",args);},wipeOut:function(args){return this._anim(dojo.fx,"wipeOut",args);},slideTo:function(args){return this._anim(dojo.fx,"slideTo",args);},fadeIn:function(args){return this._anim(dojo,"fadeIn",args);},fadeOut:function(args){return this._anim(dojo,"fadeOut",args);},animateProperty:function(args){return this._anim(dojo,"animateProperty",args);},anim:function(_1e6,_1e7,_1e8,_1e9,_1ea){var _1eb=dojo.fx.combine(this.map(function(item){return dojo.animateProperty({node:item,properties:_1e6,duration:_1e7||350,easing:_1e8});}));if(_1e9){dojo.connect(_1eb,"onEnd",_1e9);}return _1eb.play(_1ea||0);}});}if(!dojo._hasResource["dojo.colors"]){dojo._hasResource["dojo.colors"]=true;dojo.provide("dojo.colors");(function(){var _1ec=function(m1,m2,h){if(h<0){++h;}if(h>1){--h;}var h6=6*h;if(h6<1){return m1+(m2-m1)*h6;}if(2*h<1){return m2;}if(3*h<2){return m1+(m2-m1)*(2/3-h)*6;}return m1;};dojo.colorFromRgb=function(_1ed,obj){var m=_1ed.toLowerCase().match(/^(rgba?|hsla?)\(([\s\.\-,%0-9]+)\)/);if(m){var c=m[2].split(/\s*,\s*/),l=c.length,t=m[1],a;if((t=="rgb"&&l==3)||(t=="rgba"&&l==4)){var r=c[0];if(r.charAt(r.length-1)=="%"){a=dojo.map(c,function(x){return parseFloat(x)*2.56;});if(l==4){a[3]=c[3];}return dojo.colorFromArray(a,obj);}return dojo.colorFromArray(c,obj);}if((t=="hsl"&&l==3)||(t=="hsla"&&l==4)){var H=((parseFloat(c[0])%360)+360)%360/360,S=parseFloat(c[1])/100,L=parseFloat(c[2])/100,m2=L<=0.5?L*(S+1):L+S-L*S,m1=2*L-m2;a=[_1ec(m1,m2,H+1/3)*256,_1ec(m1,m2,H)*256,_1ec(m1,m2,H-1/3)*256,1];if(l==4){a[3]=c[3];}return dojo.colorFromArray(a,obj);}}return null;};var _1ee=function(c,low,high){c=Number(c);return isNaN(c)?high:c<low?low:c>high?high:c;};dojo.Color.prototype.sanitize=function(){var t=this;t.r=Math.round(_1ee(t.r,0,255));t.g=Math.round(_1ee(t.g,0,255));t.b=Math.round(_1ee(t.b,0,255));t.a=_1ee(t.a,0,1);return this;};})();dojo.colors.makeGrey=function(g,a){return dojo.colorFromArray([g,g,g,a]);};dojo.mixin(dojo.Color.named,{aliceblue:[240,248,255],antiquewhite:[250,235,215],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],blanchedalmond:[255,235,205],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],oldlace:[253,245,230],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],thistle:[216,191,216],tomato:[255,99,71],transparent:[0,0,0,0],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],whitesmoke:[245,245,245],yellowgreen:[154,205,50]});}if(!dojo._hasResource["dojo.i18n"]){dojo._hasResource["dojo.i18n"]=true;dojo.provide("dojo.i18n");dojo.i18n.getLocalization=function(_1ef,_1f0,_1f1){_1f1=dojo.i18n.normalizeLocale(_1f1);var _1f2=_1f1.split("-");var _1f3=[_1ef,"nls",_1f0].join(".");var _1f4=dojo._loadedModules[_1f3];if(_1f4){var _1f5;for(var i=_1f2.length;i>0;i--){var loc=_1f2.slice(0,i).join("_");if(_1f4[loc]){_1f5=_1f4[loc];break;}}if(!_1f5){_1f5=_1f4.ROOT;}if(_1f5){var _1f6=function(){};_1f6.prototype=_1f5;return new _1f6();}}throw new Error("Bundle not found: "+_1f0+" in "+_1ef+" , locale="+_1f1);};dojo.i18n.normalizeLocale=function(_1f7){var _1f8=_1f7?_1f7.toLowerCase():dojo.locale;if(_1f8=="root"){_1f8="ROOT";}return _1f8;};dojo.i18n._requireLocalization=function(_1f9,_1fa,_1fb,_1fc){var _1fd=dojo.i18n.normalizeLocale(_1fb);var _1fe=[_1f9,"nls",_1fa].join(".");var _1ff="";if(_1fc){var _200=_1fc.split(",");for(var i=0;i<_200.length;i++){if(_1fd["indexOf"](_200[i])==0){if(_200[i].length>_1ff.length){_1ff=_200[i];}}}if(!_1ff){_1ff="ROOT";}}var _201=_1fc?_1ff:_1fd;var _202=dojo._loadedModules[_1fe];var _203=null;if(_202){if(dojo.config.localizationComplete&&_202._built){return;}var _204=_201.replace(/-/g,"_");var _205=_1fe+"."+_204;_203=dojo._loadedModules[_205];}if(!_203){_202=dojo["provide"](_1fe);var syms=dojo._getModuleSymbols(_1f9);var _206=syms.concat("nls").join("/");var _207;dojo.i18n._searchLocalePath(_201,_1fc,function(loc){var _208=loc.replace(/-/g,"_");var _209=_1fe+"."+_208;var _20a=false;if(!dojo._loadedModules[_209]){dojo["provide"](_209);var _20b=[_206];if(loc!="ROOT"){_20b.push(loc);}_20b.push(_1fa);var _20c=_20b.join("/")+".js";_20a=dojo._loadPath(_20c,null,function(hash){var _20d=function(){};_20d.prototype=_207;_202[_208]=new _20d();for(var j in hash){_202[_208][j]=hash[j];}});}else{_20a=true;}if(_20a&&_202[_208]){_207=_202[_208];}else{_202[_208]=_207;}if(_1fc){return true;}});}if(_1fc&&_1fd!=_1ff){_202[_1fd.replace(/-/g,"_")]=_202[_1ff.replace(/-/g,"_")];}};(function(){var _20e=dojo.config.extraLocale;if(_20e){if(!_20e instanceof Array){_20e=[_20e];}var req=dojo.i18n._requireLocalization;dojo.i18n._requireLocalization=function(m,b,_20f,_210){req(m,b,_20f,_210);if(_20f){return;}for(var i=0;i<_20e.length;i++){req(m,b,_20e[i],_210);}};}})();dojo.i18n._searchLocalePath=function(_211,down,_212){_211=dojo.i18n.normalizeLocale(_211);var _213=_211.split("-");var _214=[];for(var i=_213.length;i>0;i--){_214.push(_213.slice(0,i).join("-"));}_214.push(false);if(down){_214.reverse();}for(var j=_214.length-1;j>=0;j--){var loc=_214[j]||"ROOT";var stop=_212(loc);if(stop){break;}}};dojo.i18n._preloadLocalizations=function(_215,_216){function _217(_218){_218=dojo.i18n.normalizeLocale(_218);dojo.i18n._searchLocalePath(_218,true,function(loc){for(var i=0;i<_216.length;i++){if(_216[i]==loc){dojo["require"](_215+"_"+loc);return true;}}return false;});};_217();var _219=dojo.config.extraLocale||[];for(var i=0;i<_219.length;i++){_217(_219[i]);}};}if(!dojo._hasResource["dijit._PaletteMixin"]){dojo._hasResource["dijit._PaletteMixin"]=true;dojo.provide("dijit._PaletteMixin");dojo.declare("dijit._PaletteMixin",[dijit._CssStateMixin],{defaultTimeout:500,timeoutChangeRate:0.9,value:null,_selectedCell:-1,tabIndex:"0",cellClass:"dijitPaletteCell",dyeClass:"",_preparePalette:function(_21a,_21b){this._cells=[];var url=this._blankGif;var _21c=dojo.getObject(this.dyeClass);for(var row=0;row<_21a.length;row++){var _21d=dojo.create("tr",{tabIndex:"-1"},this.gridNode);for(var col=0;col<_21a[row].length;col++){var _21e=_21a[row][col];if(_21e){var _21f=new _21c(_21e);var _220=dojo.create("td",{"class":this.cellClass,tabIndex:"-1",title:_21b[_21e]});_21f.fillCell(_220,url);this.connect(_220,"ondijitclick","_onCellClick");this._trackMouseState(_220,this.cellClass);dojo.place(_220,_21d);_220.index=this._cells.length;this._cells.push({node:_220,dye:_21f});}}}this._xDim=_21a[0].length;this._yDim=_21a.length;var _221={UP_ARROW:-this._xDim,DOWN_ARROW:this._xDim,RIGHT_ARROW:this.isLeftToRight()?1:-1,LEFT_ARROW:this.isLeftToRight()?-1:1};for(var key in _221){this._connects.push(dijit.typematic.addKeyListener(this.domNode,{charOrCode:dojo.keys[key],ctrlKey:false,altKey:false,shiftKey:false},this,function(){var _222=_221[key];return function(_223){this._navigateByKey(_222,_223);};}(),this.timeoutChangeRate,this.defaultTimeout));}},postCreate:function(){this.inherited(arguments);this._setCurrent(this._cells[0].node);},focus:function(){dijit.focus(this._currentFocus);},_onCellClick:function(evt){var _224=evt.currentTarget,_225=this._getDye(_224).getValue();this._setCurrent(_224);setTimeout(dojo.hitch(this,function(){dijit.focus(_224);this._setValueAttr(_225,true);}));dojo.removeClass(_224,"dijitPaletteCellHover");dojo.stopEvent(evt);},_setCurrent:function(node){if("_currentFocus" in this){dojo.attr(this._currentFocus,"tabIndex","-1");}this._currentFocus=node;if(node){dojo.attr(node,"tabIndex",this.tabIndex);}},_setValueAttr:function(_226,_227){this.value=null;if(this._selectedCell>=0){dojo.removeClass(this._cells[this._selectedCell].node,"dijitPaletteCellSelected");}this._selectedCell=-1;if(_226){for(var i=0;i<this._cells.length;i++){if(_226==this._cells[i].dye.getValue()){this._selectedCell=i;this.value=_226;dojo.addClass(this._cells[i].node,"dijitPaletteCellSelected");if(_227||_227===undefined){this.onChange(_226);}break;}}}},onChange:function(_228){},_navigateByKey:function(_229,_22a){if(_22a==-1){return;}var _22b=this._currentFocus.index+_229;if(_22b<this._cells.length&&_22b>-1){var _22c=this._cells[_22b].node;this._setCurrent(_22c);setTimeout(dojo.hitch(dijit,"focus",_22c),0);}},_getDye:function(cell){return this._cells[cell.index].dye;}});}if(!dojo._hasResource["dijit.ColorPalette"]){dojo._hasResource["dijit.ColorPalette"]=true;dojo.provide("dijit.ColorPalette");dojo.declare("dijit.ColorPalette",[dijit._Widget,dijit._Templated,dijit._PaletteMixin],{palette:"7x10",_palettes:{"7x10":[["white","seashell","cornsilk","lemonchiffon","lightyellow","palegreen","paleturquoise","lightcyan","lavender","plum"],["lightgray","pink","bisque","moccasin","khaki","lightgreen","lightseagreen","lightskyblue","cornflowerblue","violet"],["silver","lightcoral","sandybrown","orange","palegoldenrod","chartreuse","mediumturquoise","skyblue","mediumslateblue","orchid"],["gray","red","orangered","darkorange","yellow","limegreen","darkseagreen","royalblue","slateblue","mediumorchid"],["dimgray","crimson","chocolate","coral","gold","forestgreen","seagreen","blue","blueviolet","darkorchid"],["darkslategray","firebrick","saddlebrown","sienna","olive","green","darkcyan","mediumblue","darkslateblue","darkmagenta"],["black","darkred","maroon","brown","darkolivegreen","darkgreen","midnightblue","navy","indigo","purple"]],"3x4":[["white","lime","green","blue"],["silver","yellow","fuchsia","navy"],["gray","red","purple","black"]]},_imagePaths:{"7x10":dojo.moduleUrl("dijit.themes","a11y/colors7x10.png"),"3x4":dojo.moduleUrl("dijit.themes","a11y/colors3x4.png"),"7x10-rtl":dojo.moduleUrl("dijit.themes","a11y/colors7x10-rtl.png"),"3x4-rtl":dojo.moduleUrl("dijit.themes","a11y/colors3x4-rtl.png")},templateString:dojo.cache("dijit","templates/ColorPalette.html","<div class=\"dijitInline dijitColorPalette\">\n\t<img class=\"dijitColorPaletteUnder\" dojoAttachPoint=\"imageNode\" waiRole=\"presentation\" alt=\"\"/>\n\t<table class=\"dijitPaletteTable\" cellSpacing=\"0\" cellPadding=\"0\">\n\t\t<tbody dojoAttachPoint=\"gridNode\"></tbody>\n\t</table>\n</div>\n"),baseClass:"dijitColorPalette",dyeClass:"dijit._Color",buildRendering:function(){this.inherited(arguments);this.imageNode.setAttribute("src",this._imagePaths[this.palette+(this.isLeftToRight()?"":"-rtl")].toString());var _22d=dojo.i18n.getLocalization("dojo","colors",this.lang);this._preparePalette(this._palettes[this.palette],_22d);}});dojo.declare("dijit._Color",dojo.Color,{constructor:function(_22e){this._alias=_22e;this.setColor(dojo.Color.named[_22e]);},getValue:function(){return this.toHex();},fillCell:function(cell,_22f){dojo.create("img",{src:_22f,"class":"dijitPaletteImg",alt:this._alias},cell);}});}if(!dojo._hasResource["dojo.dnd.common"]){dojo._hasResource["dojo.dnd.common"]=true;dojo.provide("dojo.dnd.common");dojo.dnd.getCopyKeyState=dojo.isCopyKey;dojo.dnd._uniqueId=0;dojo.dnd.getUniqueId=function(){var id;do{id=dojo._scopeName+"Unique"+(++dojo.dnd._uniqueId);}while(dojo.byId(id));return id;};dojo.dnd._empty={};dojo.dnd.isFormElement=function(e){var t=e.target;if(t.nodeType==3){t=t.parentNode;}return " button textarea input select option ".indexOf(" "+t.tagName.toLowerCase()+" ")>=0;};}if(!dojo._hasResource["dojo.dnd.autoscroll"]){dojo._hasResource["dojo.dnd.autoscroll"]=true;dojo.provide("dojo.dnd.autoscroll");dojo.dnd.getViewport=function(){var d=dojo.doc,dd=d.documentElement,w=window,b=dojo.body();if(dojo.isMozilla){return {w:dd.clientWidth,h:w.innerHeight};}else{if(!dojo.isOpera&&w.innerWidth){return {w:w.innerWidth,h:w.innerHeight};}else{if(!dojo.isOpera&&dd&&dd.clientWidth){return {w:dd.clientWidth,h:dd.clientHeight};}else{if(b.clientWidth){return {w:b.clientWidth,h:b.clientHeight};}}}}return null;};dojo.dnd.V_TRIGGER_AUTOSCROLL=32;dojo.dnd.H_TRIGGER_AUTOSCROLL=32;dojo.dnd.V_AUTOSCROLL_VALUE=16;dojo.dnd.H_AUTOSCROLL_VALUE=16;dojo.dnd.autoScroll=function(e){var v=dojo.dnd.getViewport(),dx=0,dy=0;if(e.clientX<dojo.dnd.H_TRIGGER_AUTOSCROLL){dx=-dojo.dnd.H_AUTOSCROLL_VALUE;}else{if(e.clientX>v.w-dojo.dnd.H_TRIGGER_AUTOSCROLL){dx=dojo.dnd.H_AUTOSCROLL_VALUE;}}if(e.clientY<dojo.dnd.V_TRIGGER_AUTOSCROLL){dy=-dojo.dnd.V_AUTOSCROLL_VALUE;}else{if(e.clientY>v.h-dojo.dnd.V_TRIGGER_AUTOSCROLL){dy=dojo.dnd.V_AUTOSCROLL_VALUE;}}window.scrollBy(dx,dy);};dojo.dnd._validNodes={"div":1,"p":1,"td":1};dojo.dnd._validOverflow={"auto":1,"scroll":1};dojo.dnd.autoScrollNodes=function(e){for(var n=e.target;n;){if(n.nodeType==1&&(n.tagName.toLowerCase() in dojo.dnd._validNodes)){var s=dojo.getComputedStyle(n);if(s.overflow.toLowerCase() in dojo.dnd._validOverflow){var b=dojo._getContentBox(n,s),t=dojo.position(n,true);var w=Math.min(dojo.dnd.H_TRIGGER_AUTOSCROLL,b.w/2),h=Math.min(dojo.dnd.V_TRIGGER_AUTOSCROLL,b.h/2),rx=e.pageX-t.x,ry=e.pageY-t.y,dx=0,dy=0;if(dojo.isWebKit||dojo.isOpera){rx+=dojo.body().scrollLeft,ry+=dojo.body().scrollTop;}if(rx>0&&rx<b.w){if(rx<w){dx=-w;}else{if(rx>b.w-w){dx=w;}}}if(ry>0&&ry<b.h){if(ry<h){dy=-h;}else{if(ry>b.h-h){dy=h;}}}var _230=n.scrollLeft,_231=n.scrollTop;n.scrollLeft=n.scrollLeft+dx;n.scrollTop=n.scrollTop+dy;if(_230!=n.scrollLeft||_231!=n.scrollTop){return;}}}try{n=n.parentNode;}catch(x){n=null;}}dojo.dnd.autoScroll(e);};}if(!dojo._hasResource["dojo.dnd.Mover"]){dojo._hasResource["dojo.dnd.Mover"]=true;dojo.provide("dojo.dnd.Mover");dojo.declare("dojo.dnd.Mover",null,{constructor:function(node,e,host){this.node=dojo.byId(node);this.marginBox={l:e.pageX,t:e.pageY};this.mouseButton=e.button;var h=this.host=host,d=node.ownerDocument,_232=dojo.connect(d,"onmousemove",this,"onFirstMove");this.events=[dojo.connect(d,"onmousemove",this,"onMouseMove"),dojo.connect(d,"onmouseup",this,"onMouseUp"),dojo.connect(d,"ondragstart",dojo.stopEvent),dojo.connect(d.body,"onselectstart",dojo.stopEvent),_232];if(h&&h.onMoveStart){h.onMoveStart(this);}},onMouseMove:function(e){dojo.dnd.autoScroll(e);var m=this.marginBox;this.host.onMove(this,{l:m.l+e.pageX,t:m.t+e.pageY},e);dojo.stopEvent(e);},onMouseUp:function(e){if(dojo.isWebKit&&dojo.isMac&&this.mouseButton==2?e.button==0:this.mouseButton==e.button){this.destroy();}dojo.stopEvent(e);},onFirstMove:function(e){var s=this.node.style,l,t,h=this.host;switch(s.position){case "relative":case "absolute":l=Math.round(parseFloat(s.left))||0;t=Math.round(parseFloat(s.top))||0;break;default:s.position="absolute";var m=dojo.marginBox(this.node);var b=dojo.doc.body;var bs=dojo.getComputedStyle(b);var bm=dojo._getMarginBox(b,bs);var bc=dojo._getContentBox(b,bs);l=m.l-(bc.l-bm.l);t=m.t-(bc.t-bm.t);break;}this.marginBox.l=l-this.marginBox.l;this.marginBox.t=t-this.marginBox.t;if(h&&h.onFirstMove){h.onFirstMove(this,e);}dojo.disconnect(this.events.pop());},destroy:function(){dojo.forEach(this.events,dojo.disconnect);var h=this.host;if(h&&h.onMoveStop){h.onMoveStop(this);}this.events=this.node=this.host=null;}});}if(!dojo._hasResource["dojo.dnd.Moveable"]){dojo._hasResource["dojo.dnd.Moveable"]=true;dojo.provide("dojo.dnd.Moveable");dojo.declare("dojo.dnd.Moveable",null,{handle:"",delay:0,skip:false,constructor:function(node,_233){this.node=dojo.byId(node);if(!_233){_233={};}this.handle=_233.handle?dojo.byId(_233.handle):null;if(!this.handle){this.handle=this.node;}this.delay=_233.delay>0?_233.delay:0;this.skip=_233.skip;this.mover=_233.mover?_233.mover:dojo.dnd.Mover;this.events=[dojo.connect(this.handle,"onmousedown",this,"onMouseDown"),dojo.connect(this.handle,"ondragstart",this,"onSelectStart"),dojo.connect(this.handle,"onselectstart",this,"onSelectStart")];},markupFactory:function(_234,node){return new dojo.dnd.Moveable(node,_234);},destroy:function(){dojo.forEach(this.events,dojo.disconnect);this.events=this.node=this.handle=null;},onMouseDown:function(e){if(this.skip&&dojo.dnd.isFormElement(e)){return;}if(this.delay){this.events.push(dojo.connect(this.handle,"onmousemove",this,"onMouseMove"),dojo.connect(this.handle,"onmouseup",this,"onMouseUp"));this._lastX=e.pageX;this._lastY=e.pageY;}else{this.onDragDetected(e);}dojo.stopEvent(e);},onMouseMove:function(e){if(Math.abs(e.pageX-this._lastX)>this.delay||Math.abs(e.pageY-this._lastY)>this.delay){this.onMouseUp(e);this.onDragDetected(e);}dojo.stopEvent(e);},onMouseUp:function(e){for(var i=0;i<2;++i){dojo.disconnect(this.events.pop());}dojo.stopEvent(e);},onSelectStart:function(e){if(!this.skip||!dojo.dnd.isFormElement(e)){dojo.stopEvent(e);}},onDragDetected:function(e){new this.mover(this.node,e,this);},onMoveStart:function(_235){dojo.publish("/dnd/move/start",[_235]);dojo.addClass(dojo.body(),"dojoMove");dojo.addClass(this.node,"dojoMoveItem");},onMoveStop:function(_236){dojo.publish("/dnd/move/stop",[_236]);dojo.removeClass(dojo.body(),"dojoMove");dojo.removeClass(this.node,"dojoMoveItem");},onFirstMove:function(_237,e){},onMove:function(_238,_239,e){this.onMoving(_238,_239);var s=_238.node.style;s.left=_239.l+"px";s.top=_239.t+"px";this.onMoved(_238,_239);},onMoving:function(_23a,_23b){},onMoved:function(_23c,_23d){}});}if(!dojo._hasResource["dojo.dnd.move"]){dojo._hasResource["dojo.dnd.move"]=true;dojo.provide("dojo.dnd.move");dojo.declare("dojo.dnd.move.constrainedMoveable",dojo.dnd.Moveable,{constraints:function(){},within:false,markupFactory:function(_23e,node){return new dojo.dnd.move.constrainedMoveable(node,_23e);},constructor:function(node,_23f){if(!_23f){_23f={};}this.constraints=_23f.constraints;this.within=_23f.within;},onFirstMove:function(_240){var c=this.constraintBox=this.constraints.call(this,_240);c.r=c.l+c.w;c.b=c.t+c.h;if(this.within){var mb=dojo.marginBox(_240.node);c.r-=mb.w;c.b-=mb.h;}},onMove:function(_241,_242){var c=this.constraintBox,s=_241.node.style;s.left=(_242.l<c.l?c.l:c.r<_242.l?c.r:_242.l)+"px";s.top=(_242.t<c.t?c.t:c.b<_242.t?c.b:_242.t)+"px";}});dojo.declare("dojo.dnd.move.boxConstrainedMoveable",dojo.dnd.move.constrainedMoveable,{box:{},markupFactory:function(_243,node){return new dojo.dnd.move.boxConstrainedMoveable(node,_243);},constructor:function(node,_244){var box=_244&&_244.box;this.constraints=function(){return box;};}});dojo.declare("dojo.dnd.move.parentConstrainedMoveable",dojo.dnd.move.constrainedMoveable,{area:"content",markupFactory:function(_245,node){return new dojo.dnd.move.parentConstrainedMoveable(node,_245);},constructor:function(node,_246){var area=_246&&_246.area;this.constraints=function(){var n=this.node.parentNode,s=dojo.getComputedStyle(n),mb=dojo._getMarginBox(n,s);if(area=="margin"){return mb;}var t=dojo._getMarginExtents(n,s);mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;if(area=="border"){return mb;}t=dojo._getBorderExtents(n,s);mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;if(area=="padding"){return mb;}t=dojo._getPadExtents(n,s);mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;return mb;};}});dojo.dnd.move.constrainedMover=function(fun,_247){dojo.deprecated("dojo.dnd.move.constrainedMover, use dojo.dnd.move.constrainedMoveable instead");var _248=function(node,e,_249){dojo.dnd.Mover.call(this,node,e,_249);};dojo.extend(_248,dojo.dnd.Mover.prototype);dojo.extend(_248,{onMouseMove:function(e){dojo.dnd.autoScroll(e);var m=this.marginBox,c=this.constraintBox,l=m.l+e.pageX,t=m.t+e.pageY;l=l<c.l?c.l:c.r<l?c.r:l;t=t<c.t?c.t:c.b<t?c.b:t;this.host.onMove(this,{l:l,t:t});},onFirstMove:function(){dojo.dnd.Mover.prototype.onFirstMove.call(this);var c=this.constraintBox=fun.call(this);c.r=c.l+c.w;c.b=c.t+c.h;if(_247){var mb=dojo.marginBox(this.node);c.r-=mb.w;c.b-=mb.h;}}});return _248;};dojo.dnd.move.boxConstrainedMover=function(box,_24a){dojo.deprecated("dojo.dnd.move.boxConstrainedMover, use dojo.dnd.move.boxConstrainedMoveable instead");return dojo.dnd.move.constrainedMover(function(){return box;},_24a);};dojo.dnd.move.parentConstrainedMover=function(area,_24b){dojo.deprecated("dojo.dnd.move.parentConstrainedMover, use dojo.dnd.move.parentConstrainedMoveable instead");var fun=function(){var n=this.node.parentNode,s=dojo.getComputedStyle(n),mb=dojo._getMarginBox(n,s);if(area=="margin"){return mb;}var t=dojo._getMarginExtents(n,s);mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;if(area=="border"){return mb;}t=dojo._getBorderExtents(n,s);mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;if(area=="padding"){return mb;}t=dojo._getPadExtents(n,s);mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;return mb;};return dojo.dnd.move.constrainedMover(fun,_24b);};dojo.dnd.constrainedMover=dojo.dnd.move.constrainedMover;dojo.dnd.boxConstrainedMover=dojo.dnd.move.boxConstrainedMover;dojo.dnd.parentConstrainedMover=dojo.dnd.move.parentConstrainedMover;}if(!dojo._hasResource["dojo.dnd.TimedMoveable"]){dojo._hasResource["dojo.dnd.TimedMoveable"]=true;dojo.provide("dojo.dnd.TimedMoveable");(function(){var _24c=dojo.dnd.Moveable.prototype.onMove;dojo.declare("dojo.dnd.TimedMoveable",dojo.dnd.Moveable,{timeout:40,constructor:function(node,_24d){if(!_24d){_24d={};}if(_24d.timeout&&typeof _24d.timeout=="number"&&_24d.timeout>=0){this.timeout=_24d.timeout;}},markupFactory:function(_24e,node){return new dojo.dnd.TimedMoveable(node,_24e);},onMoveStop:function(_24f){if(_24f._timer){clearTimeout(_24f._timer);_24c.call(this,_24f,_24f._leftTop);}dojo.dnd.Moveable.prototype.onMoveStop.apply(this,arguments);},onMove:function(_250,_251){_250._leftTop=_251;if(!_250._timer){var _252=this;_250._timer=setTimeout(function(){_250._timer=null;_24c.call(_252,_250,_250._leftTop);},this.timeout);}}});})();}if(!dojo._hasResource["dijit.form._FormMixin"]){dojo._hasResource["dijit.form._FormMixin"]=true;dojo.provide("dijit.form._FormMixin");dojo.declare("dijit.form._FormMixin",null,{reset:function(){dojo.forEach(this.getDescendants(),function(_253){if(_253.reset){_253.reset();}});},validate:function(){var _254=false;return dojo.every(dojo.map(this.getDescendants(),function(_255){_255._hasBeenBlurred=true;var _256=_255.disabled||!_255.validate||_255.validate();if(!_256&&!_254){dojo.window.scrollIntoView(_255.containerNode||_255.domNode);_255.focus();_254=true;}return _256;}),function(item){return item;});},setValues:function(val){dojo.deprecated(this.declaredClass+"::setValues() is deprecated. Use set('value', val) instead.","","2.0");return this.set("value",val);},_setValueAttr:function(obj){var map={};dojo.forEach(this.getDescendants(),function(_257){if(!_257.name){return;}var _258=map[_257.name]||(map[_257.name]=[]);_258.push(_257);});for(var name in map){if(!map.hasOwnProperty(name)){continue;}var _259=map[name],_25a=dojo.getObject(name,false,obj);if(_25a===undefined){continue;}if(!dojo.isArray(_25a)){_25a=[_25a];}if(typeof _259[0].checked=="boolean"){dojo.forEach(_259,function(w,i){w.set("value",dojo.indexOf(_25a,w.value)!=-1);});}else{if(_259[0].multiple){_259[0].set("value",_25a);}else{dojo.forEach(_259,function(w,i){w.set("value",_25a[i]);});}}}},getValues:function(){dojo.deprecated(this.declaredClass+"::getValues() is deprecated. Use get('value') instead.","","2.0");return this.get("value");},_getValueAttr:function(){var obj={};dojo.forEach(this.getDescendants(),function(_25b){var name=_25b.name;if(!name||_25b.disabled){return;}var _25c=_25b.get("value");if(typeof _25b.checked=="boolean"){if(/Radio/.test(_25b.declaredClass)){if(_25c!==false){dojo.setObject(name,_25c,obj);}else{_25c=dojo.getObject(name,false,obj);if(_25c===undefined){dojo.setObject(name,null,obj);}}}else{var ary=dojo.getObject(name,false,obj);if(!ary){ary=[];dojo.setObject(name,ary,obj);}if(_25c!==false){ary.push(_25c);}}}else{var prev=dojo.getObject(name,false,obj);if(typeof prev!="undefined"){if(dojo.isArray(prev)){prev.push(_25c);}else{dojo.setObject(name,[prev,_25c],obj);}}else{dojo.setObject(name,_25c,obj);}}});return obj;},isValid:function(){this._invalidWidgets=dojo.filter(this.getDescendants(),function(_25d){return !_25d.disabled&&_25d.isValid&&!_25d.isValid();});return !this._invalidWidgets.length;},onValidStateChange:function(_25e){},_widgetChange:function(_25f){var _260=this._lastValidState;if(!_25f||this._lastValidState===undefined){_260=this.isValid();if(this._lastValidState===undefined){this._lastValidState=_260;}}else{if(_25f.isValid){this._invalidWidgets=dojo.filter(this._invalidWidgets||[],function(w){return (w!=_25f);},this);if(!_25f.isValid()&&!_25f.get("disabled")){this._invalidWidgets.push(_25f);}_260=(this._invalidWidgets.length===0);}}if(_260!==this._lastValidState){this._lastValidState=_260;this.onValidStateChange(_260);}},connectChildren:function(){dojo.forEach(this._changeConnections,dojo.hitch(this,"disconnect"));var _261=this;var _262=(this._changeConnections=[]);dojo.forEach(dojo.filter(this.getDescendants(),function(item){return item.validate;}),function(_263){_262.push(_261.connect(_263,"validate",dojo.hitch(_261,"_widgetChange",_263)));_262.push(_261.connect(_263,"_setDisabledAttr",dojo.hitch(_261,"_widgetChange",_263)));});this._widgetChange(null);},startup:function(){this.inherited(arguments);this._changeConnections=[];this.connectChildren();}});}if(!dojo._hasResource["dijit._DialogMixin"]){dojo._hasResource["dijit._DialogMixin"]=true;dojo.provide("dijit._DialogMixin");dojo.declare("dijit._DialogMixin",null,{attributeMap:dijit._Widget.prototype.attributeMap,execute:function(_264){},onCancel:function(){},onExecute:function(){},_onSubmit:function(){this.onExecute();this.execute(this.get("value"));},_getFocusItems:function(_265){var _266=dijit._getTabNavigable(dojo.byId(_265));this._firstFocusItem=_266.lowest||_266.first||_265;this._lastFocusItem=_266.last||_266.highest||this._firstFocusItem;if(dojo.isMoz&&this._firstFocusItem.tagName.toLowerCase()=="input"&&dojo.getNodeProp(this._firstFocusItem,"type").toLowerCase()=="file"){dojo.attr(_265,"tabIndex","0");this._firstFocusItem=_265;}}});}if(!dojo._hasResource["dijit.DialogUnderlay"]){dojo._hasResource["dijit.DialogUnderlay"]=true;dojo.provide("dijit.DialogUnderlay");dojo.declare("dijit.DialogUnderlay",[dijit._Widget,dijit._Templated],{templateString:"<div class='dijitDialogUnderlayWrapper'><div class='dijitDialogUnderlay' dojoAttachPoint='node'></div></div>",dialogId:"","class":"",attributeMap:{id:"domNode"},_setDialogIdAttr:function(id){dojo.attr(this.node,"id",id+"_underlay");},_setClassAttr:function(_267){this.node.className="dijitDialogUnderlay "+_267;},postCreate:function(){dojo.body().appendChild(this.domNode);},layout:function(){var is=this.node.style,os=this.domNode.style;os.display="none";var _268=dojo.window.getBox();os.top=_268.t+"px";os.left=_268.l+"px";is.width=_268.w+"px";is.height=_268.h+"px";os.display="block";},show:function(){this.domNode.style.display="block";this.layout();this.bgIframe=new dijit.BackgroundIframe(this.domNode);},hide:function(){this.bgIframe.destroy();this.domNode.style.display="none";},uninitialize:function(){if(this.bgIframe){this.bgIframe.destroy();}this.inherited(arguments);}});}if(!dojo._hasResource["dojo.html"]){dojo._hasResource["dojo.html"]=true;dojo.provide("dojo.html");(function(){var _269=0,d=dojo;dojo.html._secureForInnerHtml=function(cont){return cont.replace(/(?:\s*<!DOCTYPE\s[^>]+>|<title[^>]*>[\s\S]*?<\/title>)/ig,"");};dojo.html._emptyNode=dojo.empty;dojo.html._setNodeContent=function(node,cont){d.empty(node);if(cont){if(typeof cont=="string"){cont=d._toDom(cont,node.ownerDocument);}if(!cont.nodeType&&d.isArrayLike(cont)){for(var _26a=cont.length,i=0;i<cont.length;i=_26a==cont.length?i+1:0){d.place(cont[i],node,"last");}}else{d.place(cont,node,"last");}}return node;};dojo.declare("dojo.html._ContentSetter",null,{node:"",content:"",id:"",cleanContent:false,extractContent:false,parseContent:false,constructor:function(_26b,node){dojo.mixin(this,_26b||{});node=this.node=dojo.byId(this.node||node);if(!this.id){this.id=["Setter",(node)?node.id||node.tagName:"",_269++].join("_");}},set:function(cont,_26c){if(undefined!==cont){this.content=cont;}if(_26c){this._mixin(_26c);}this.onBegin();this.setContent();this.onEnd();return this.node;},setContent:function(){var node=this.node;if(!node){throw new Error(this.declaredClass+": setContent given no node");}try{node=dojo.html._setNodeContent(node,this.content);}catch(e){var _26d=this.onContentError(e);try{node.innerHTML=_26d;}catch(e){console.error("Fatal "+this.declaredClass+".setContent could not change content due to "+e.message,e);}}this.node=node;},empty:function(){if(this.parseResults&&this.parseResults.length){dojo.forEach(this.parseResults,function(w){if(w.destroy){w.destroy();}});delete this.parseResults;}dojo.html._emptyNode(this.node);},onBegin:function(){var cont=this.content;if(dojo.isString(cont)){if(this.cleanContent){cont=dojo.html._secureForInnerHtml(cont);}if(this.extractContent){var _26e=cont.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);if(_26e){cont=_26e[1];}}}this.empty();this.content=cont;return this.node;},onEnd:function(){if(this.parseContent){this._parse();}return this.node;},tearDown:function(){delete this.parseResults;delete this.node;delete this.content;},onContentError:function(err){return "Error occured setting content: "+err;},_mixin:function(_26f){var _270={},key;for(key in _26f){if(key in _270){continue;}this[key]=_26f[key];}},_parse:function(){var _271=this.node;try{this.parseResults=dojo.parser.parse({rootNode:_271,dir:this.dir,lang:this.lang});}catch(e){this._onError("Content",e,"Error parsing in _ContentSetter#"+this.id);}},_onError:function(type,err,_272){var _273=this["on"+type+"Error"].call(this,err);if(_272){console.error(_272,err);}else{if(_273){dojo.html._setNodeContent(this.node,_273,true);}}}});dojo.html.set=function(node,cont,_274){if(undefined==cont){console.warn("dojo.html.set: no cont argument provided, using empty string");cont="";}if(!_274){return dojo.html._setNodeContent(node,cont,true);}else{var op=new dojo.html._ContentSetter(dojo.mixin(_274,{content:cont,node:node}));return op.set();}};})();}if(!dojo._hasResource["dijit.layout.ContentPane"]){dojo._hasResource["dijit.layout.ContentPane"]=true;dojo.provide("dijit.layout.ContentPane");dojo.declare("dijit.layout.ContentPane",dijit._Widget,{href:"",extractContent:false,parseOnLoad:true,preventCache:false,preload:false,refreshOnShow:false,loadingMessage:"<span class='dijitContentPaneLoading'>${loadingState}</span>",errorMessage:"<span class='dijitContentPaneError'>${errorState}</span>",isLoaded:false,baseClass:"dijitContentPane",doLayout:true,ioArgs:{},isContainer:true,isLayoutContainer:true,onLoadDeferred:null,attributeMap:dojo.delegate(dijit._Widget.prototype.attributeMap,{title:[]}),postMixInProperties:function(){this.inherited(arguments);var _275=dojo.i18n.getLocalization("dijit","loading",this.lang);this.loadingMessage=dojo.string.substitute(this.loadingMessage,_275);this.errorMessage=dojo.string.substitute(this.errorMessage,_275);if(!this.href&&this.srcNodeRef&&this.srcNodeRef.innerHTML){this.isLoaded=true;}},buildRendering:function(){this.inherited(arguments);if(!this.containerNode){this.containerNode=this.domNode;}},postCreate:function(){this.domNode.title="";if(!dojo.attr(this.domNode,"role")){dijit.setWaiRole(this.domNode,"group");}dojo.addClass(this.domNode,this.baseClass);},startup:function(){if(this._started){return;}var _276=dijit._Contained.prototype.getParent.call(this);this._childOfLayoutWidget=_276&&_276.isLayoutContainer;this._needLayout=!this._childOfLayoutWidget;if(this.isLoaded){dojo.forEach(this.getChildren(),function(_277){_277.startup();});}if(this._isShown()||this.preload){this._onShow();}this.inherited(arguments);},_checkIfSingleChild:function(){var _278=dojo.query("> *",this.containerNode).filter(function(node){return node.tagName!=="SCRIPT";}),_279=_278.filter(function(node){return dojo.hasAttr(node,"dojoType")||dojo.hasAttr(node,"widgetId");}),_27a=dojo.filter(_279.map(dijit.byNode),function(_27b){return _27b&&_27b.domNode&&_27b.resize;});if(_278.length==_279.length&&_27a.length==1){this._singleChild=_27a[0];}else{delete this._singleChild;}dojo.toggleClass(this.containerNode,this.baseClass+"SingleChild",!!this._singleChild);},setHref:function(href){dojo.deprecated("dijit.layout.ContentPane.setHref() is deprecated. Use set('href', ...) instead.","","2.0");return this.set("href",href);},_setHrefAttr:function(href){this.cancel();this.onLoadDeferred=new dojo.Deferred(dojo.hitch(this,"cancel"));this.href=href;if(this._created&&(this.preload||this._isShown())){this._load();}else{this._hrefChanged=true;}return this.onLoadDeferred;},setContent:function(data){dojo.deprecated("dijit.layout.ContentPane.setContent() is deprecated. Use set('content', ...) instead.","","2.0");this.set("content",data);},_setContentAttr:function(data){this.href="";this.cancel();this.onLoadDeferred=new dojo.Deferred(dojo.hitch(this,"cancel"));this._setContent(data||"");this._isDownloaded=false;return this.onLoadDeferred;},_getContentAttr:function(){return this.containerNode.innerHTML;},cancel:function(){if(this._xhrDfd&&(this._xhrDfd.fired==-1)){this._xhrDfd.cancel();}delete this._xhrDfd;this.onLoadDeferred=null;},uninitialize:function(){if(this._beingDestroyed){this.cancel();}this.inherited(arguments);},destroyRecursive:function(_27c){if(this._beingDestroyed){return;}this.inherited(arguments);},resize:function(_27d,_27e){if(!this._wasShown){this._onShow();}this._resizeCalled=true;if(_27d){dojo.marginBox(this.domNode,_27d);}var cn=this.containerNode;if(cn===this.domNode){var mb=_27e||{};dojo.mixin(mb,_27d||{});if(!("h" in mb)||!("w" in mb)){mb=dojo.mixin(dojo.marginBox(cn),mb);}this._contentBox=dijit.layout.marginBox2contentBox(cn,mb);}else{this._contentBox=dojo.contentBox(cn);}this._layoutChildren();},_isShown:function(){if(this._childOfLayoutWidget){if(this._resizeCalled&&"open" in this){return this.open;}return this._resizeCalled;}else{if("open" in this){return this.open;}else{var node=this.domNode;return (node.style.display!="none")&&(node.style.visibility!="hidden")&&!dojo.hasClass(node,"dijitHidden");}}},_onShow:function(){if(this.href){if(!this._xhrDfd&&(!this.isLoaded||this._hrefChanged||this.refreshOnShow)){this.refresh();}}else{if(!this._childOfLayoutWidget&&this._needLayout){this._layoutChildren();}}this.inherited(arguments);this._wasShown=true;},refresh:function(){this.cancel();this.onLoadDeferred=new dojo.Deferred(dojo.hitch(this,"cancel"));this._load();return this.onLoadDeferred;},_load:function(){this._setContent(this.onDownloadStart(),true);var self=this;var _27f={preventCache:(this.preventCache||this.refreshOnShow),url:this.href,handleAs:"text"};if(dojo.isObject(this.ioArgs)){dojo.mixin(_27f,this.ioArgs);}var hand=(this._xhrDfd=(this.ioMethod||dojo.xhrGet)(_27f));hand.addCallback(function(html){try{self._isDownloaded=true;self._setContent(html,false);self.onDownloadEnd();}catch(err){self._onError("Content",err);}delete self._xhrDfd;return html;});hand.addErrback(function(err){if(!hand.canceled){self._onError("Download",err);}delete self._xhrDfd;return err;});delete this._hrefChanged;},_onLoadHandler:function(data){this.isLoaded=true;try{this.onLoadDeferred.callback(data);this.onLoad(data);}catch(e){console.error("Error "+this.widgetId+" running custom onLoad code: "+e.message);}},_onUnloadHandler:function(){this.isLoaded=false;try{this.onUnload();}catch(e){console.error("Error "+this.widgetId+" running custom onUnload code: "+e.message);}},destroyDescendants:function(){if(this.isLoaded){this._onUnloadHandler();}var _280=this._contentSetter;dojo.forEach(this.getChildren(),function(_281){if(_281.destroyRecursive){_281.destroyRecursive();}});if(_280){dojo.forEach(_280.parseResults,function(_282){if(_282.destroyRecursive&&_282.domNode&&_282.domNode.parentNode==dojo.body()){_282.destroyRecursive();}});delete _280.parseResults;}dojo.html._emptyNode(this.containerNode);delete this._singleChild;},_setContent:function(cont,_283){this.destroyDescendants();var _284=this._contentSetter;if(!(_284&&_284 instanceof dojo.html._ContentSetter)){_284=this._contentSetter=new dojo.html._ContentSetter({node:this.containerNode,_onError:dojo.hitch(this,this._onError),onContentError:dojo.hitch(this,function(e){var _285=this.onContentError(e);try{this.containerNode.innerHTML=_285;}catch(e){console.error("Fatal "+this.id+" could not change content due to "+e.message,e);}})});}var _286=dojo.mixin({cleanContent:this.cleanContent,extractContent:this.extractContent,parseContent:this.parseOnLoad,dir:this.dir,lang:this.lang},this._contentSetterParams||{});dojo.mixin(_284,_286);_284.set((dojo.isObject(cont)&&cont.domNode)?cont.domNode:cont);delete this._contentSetterParams;if(!_283){dojo.forEach(this.getChildren(),function(_287){if(!this.parseOnLoad||_287.getParent){_287.startup();}},this);this._scheduleLayout();this._onLoadHandler(cont);}},_onError:function(type,err,_288){this.onLoadDeferred.errback(err);var _289=this["on"+type+"Error"].call(this,err);if(_288){console.error(_288,err);}else{if(_289){this._setContent(_289,true);}}},_scheduleLayout:function(){if(this._isShown()){this._layoutChildren();}else{this._needLayout=true;}},_layoutChildren:function(){if(this.doLayout){this._checkIfSingleChild();}if(this._singleChild&&this._singleChild.resize){var cb=this._contentBox||dojo.contentBox(this.containerNode);this._singleChild.resize({w:cb.w,h:cb.h});}else{dojo.forEach(this.getChildren(),function(_28a){if(_28a.resize){_28a.resize();}});}delete this._needLayout;},onLoad:function(data){},onUnload:function(){},onDownloadStart:function(){return this.loadingMessage;},onContentError:function(_28b){},onDownloadError:function(_28c){return this.errorMessage;},onDownloadEnd:function(){}});}if(!dojo._hasResource["dijit.TooltipDialog"]){dojo._hasResource["dijit.TooltipDialog"]=true;dojo.provide("dijit.TooltipDialog");dojo.declare("dijit.TooltipDialog",[dijit.layout.ContentPane,dijit._Templated,dijit.form._FormMixin,dijit._DialogMixin],{title:"",doLayout:false,autofocus:true,baseClass:"dijitTooltipDialog",_firstFocusItem:null,_lastFocusItem:null,templateString:dojo.cache("dijit","templates/TooltipDialog.html","<div waiRole=\"presentation\">\n\t<div class=\"dijitTooltipContainer\" waiRole=\"presentation\">\n\t\t<div class =\"dijitTooltipContents dijitTooltipFocusNode\" dojoAttachPoint=\"containerNode\" tabindex=\"-1\" waiRole=\"dialog\"></div>\n\t</div>\n\t<div class=\"dijitTooltipConnector\" waiRole=\"presentation\"></div>\n</div>\n"),postCreate:function(){this.inherited(arguments);this.connect(this.containerNode,"onkeypress","_onKey");this.containerNode.title=this.title;},orient:function(node,_28d,_28e){var c=this._currentOrientClass;if(c){dojo.removeClass(this.domNode,c);}c="dijitTooltipAB"+(_28e.charAt(1)=="L"?"Left":"Right")+" dijitTooltip"+(_28e.charAt(0)=="T"?"Below":"Above");dojo.addClass(this.domNode,c);this._currentOrientClass=c;},onOpen:function(pos){this.orient(this.domNode,pos.aroundCorner,pos.corner);this._onShow();if(this.autofocus){this._getFocusItems(this.containerNode);dijit.focus(this._firstFocusItem);}},onClose:function(){this.onHide();},_onKey:function(evt){var node=evt.target;var dk=dojo.keys;if(evt.charOrCode===dk.TAB){this._getFocusItems(this.containerNode);}var _28f=(this._firstFocusItem==this._lastFocusItem);if(evt.charOrCode==dk.ESCAPE){setTimeout(dojo.hitch(this,"onCancel"),0);dojo.stopEvent(evt);}else{if(node==this._firstFocusItem&&evt.shiftKey&&evt.charOrCode===dk.TAB){if(!_28f){dijit.focus(this._lastFocusItem);}dojo.stopEvent(evt);}else{if(node==this._lastFocusItem&&evt.charOrCode===dk.TAB&&!evt.shiftKey){if(!_28f){dijit.focus(this._firstFocusItem);}dojo.stopEvent(evt);}else{if(evt.charOrCode===dk.TAB){evt.stopPropagation();}}}}}});}if(!dojo._hasResource["dijit.Dialog"]){dojo._hasResource["dijit.Dialog"]=true;dojo.provide("dijit.Dialog");dojo.declare("dijit._DialogBase",[dijit._Templated,dijit.form._FormMixin,dijit._DialogMixin,dijit._CssStateMixin],{templateString:dojo.cache("dijit","templates/Dialog.html","<div class=\"dijitDialog\" tabindex=\"-1\" waiRole=\"dialog\" waiState=\"labelledby-${id}_title\">\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\">\n\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\"></span>\n\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" dojoAttachEvent=\"onclick: onCancel\" title=\"${buttonCancel}\">\n\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\n\t</span>\n\t</div>\n\t\t<div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\n</div>\n"),baseClass:"dijitDialog",cssStateNodes:{closeButtonNode:"dijitDialogCloseIcon"},attributeMap:dojo.delegate(dijit._Widget.prototype.attributeMap,{title:[{node:"titleNode",type:"innerHTML"},{node:"titleBar",type:"attribute"}],"aria-describedby":""}),open:false,duration:dijit.defaultDuration,refocus:true,autofocus:true,_firstFocusItem:null,_lastFocusItem:null,doLayout:false,draggable:true,"aria-describedby":"",postMixInProperties:function(){var _290=dojo.i18n.getLocalization("dijit","common");dojo.mixin(this,_290);this.inherited(arguments);},postCreate:function(){dojo.style(this.domNode,{display:"none",position:"absolute"});dojo.body().appendChild(this.domNode);this.inherited(arguments);this.connect(this,"onExecute","hide");this.connect(this,"onCancel","hide");this._modalconnects=[];},onLoad:function(){this._position();if(this.autofocus){this._getFocusItems(this.domNode);dijit.focus(this._firstFocusItem);}this.inherited(arguments);},_endDrag:function(e){if(e&&e.node&&e.node===this.domNode){this._relativePosition=dojo.position(e.node);}},_setup:function(){var node=this.domNode;if(this.titleBar&&this.draggable){this._moveable=(dojo.isIE==6)?new dojo.dnd.TimedMoveable(node,{handle:this.titleBar}):new dojo.dnd.Moveable(node,{handle:this.titleBar,timeout:0});dojo.subscribe("/dnd/move/stop",this,"_endDrag");}else{dojo.addClass(node,"dijitDialogFixed");}this.underlayAttrs={dialogId:this.id,"class":dojo.map(this["class"].split(/\s/),function(s){return s+"_underlay";}).join(" ")};this._fadeIn=dojo.fadeIn({node:node,duration:this.duration,beforeBegin:dojo.hitch(this,function(){var _291=dijit._underlay;if(!_291){_291=dijit._underlay=new dijit.DialogUnderlay(this.underlayAttrs);}else{_291.set(this.underlayAttrs);}var ds=dijit._dialogStack,_292=948+ds.length*2;if(ds.length==1){_291.show();}dojo.style(dijit._underlay.domNode,"zIndex",_292);dojo.style(this.domNode,"zIndex",_292+1);}),onEnd:dojo.hitch(this,function(){if(this.autofocus){this._getFocusItems(this.domNode);dijit.focus(this._firstFocusItem);}})});this._fadeOut=dojo.fadeOut({node:node,duration:this.duration,onEnd:dojo.hitch(this,function(){node.style.display="none";var ds=dijit._dialogStack;if(ds.length==0){dijit._underlay.hide();}else{dojo.style(dijit._underlay.domNode,"zIndex",948+ds.length*2);dijit._underlay.set(ds[ds.length-1].underlayAttrs);}if(this.refocus){var _293=this._savedFocus;if(ds.length>0){var pd=ds[ds.length-1];if(!dojo.isDescendant(_293.node,pd.domNode)){pd._getFocusItems(pd.domNode);_293=pd._firstFocusItem;}}dijit.focus(_293);}})});},uninitialize:function(){var _294=false;if(this._fadeIn&&this._fadeIn.status()=="playing"){_294=true;this._fadeIn.stop();}if(this._fadeOut&&this._fadeOut.status()=="playing"){_294=true;this._fadeOut.stop();}if((this.open||_294)&&!dijit._underlay._destroyed){dijit._underlay.hide();}if(this._moveable){this._moveable.destroy();}this.inherited(arguments);},_size:function(){this._checkIfSingleChild();if(this._singleChild){if(this._singleChildOriginalStyle){this._singleChild.domNode.style.cssText=this._singleChildOriginalStyle;}delete this._singleChildOriginalStyle;}else{dojo.style(this.containerNode,{width:"auto",height:"auto"});}var mb=dojo.marginBox(this.domNode);var _295=dojo.window.getBox();if(mb.w>=_295.w||mb.h>=_295.h){var w=Math.min(mb.w,Math.floor(_295.w*0.75)),h=Math.min(mb.h,Math.floor(_295.h*0.75));if(this._singleChild&&this._singleChild.resize){this._singleChildOriginalStyle=this._singleChild.domNode.style.cssText;this._singleChild.resize({w:w,h:h});}else{dojo.style(this.containerNode,{width:w+"px",height:h+"px",overflow:"auto",position:"relative"});}}else{if(this._singleChild&&this._singleChild.resize){this._singleChild.resize();}}},_position:function(){if(!dojo.hasClass(dojo.body(),"dojoMove")){var node=this.domNode,_296=dojo.window.getBox(),p=this._relativePosition,bb=p?null:dojo._getBorderBox(node),l=Math.floor(_296.l+(p?p.x:(_296.w-bb.w)/2)),t=Math.floor(_296.t+(p?p.y:(_296.h-bb.h)/2));dojo.style(node,{left:l+"px",top:t+"px"});}},_onKey:function(evt){var ds=dijit._dialogStack;if(ds[ds.length-1]!=this){return;}if(evt.charOrCode){var dk=dojo.keys;var node=evt.target;if(evt.charOrCode===dk.TAB){this._getFocusItems(this.domNode);}var _297=(this._firstFocusItem==this._lastFocusItem);if(node==this._firstFocusItem&&evt.shiftKey&&evt.charOrCode===dk.TAB){if(!_297){dijit.focus(this._lastFocusItem);}dojo.stopEvent(evt);}else{if(node==this._lastFocusItem&&evt.charOrCode===dk.TAB&&!evt.shiftKey){if(!_297){dijit.focus(this._firstFocusItem);}dojo.stopEvent(evt);}else{while(node){if(node==this.domNode||dojo.hasClass(node,"dijitPopup")){if(evt.charOrCode==dk.ESCAPE){this.onCancel();}else{return;}}node=node.parentNode;}if(evt.charOrCode!==dk.TAB){dojo.stopEvent(evt);}else{if(!dojo.isOpera){try{this._firstFocusItem.focus();}catch(e){}}}}}}},show:function(){if(this.open){return;}if(!this._alreadyInitialized){this._setup();this._alreadyInitialized=true;}if(this._fadeOut.status()=="playing"){this._fadeOut.stop();}this._modalconnects.push(dojo.connect(window,"onscroll",this,"layout"));this._modalconnects.push(dojo.connect(window,"onresize",this,function(){var _298=dojo.window.getBox();if(!this._oldViewport||_298.h!=this._oldViewport.h||_298.w!=this._oldViewport.w){this.layout();this._oldViewport=_298;}}));this._modalconnects.push(dojo.connect(dojo.doc.documentElement,"onkeypress",this,"_onKey"));dojo.style(this.domNode,{opacity:0,display:""});this.open=true;this._onShow();this._size();this._position();dijit._dialogStack.push(this);this._fadeIn.play();this._savedFocus=dijit.getFocus(this);},hide:function(){var ds=dijit._dialogStack;if(!this._alreadyInitialized||this!=ds[ds.length-1]){return;}if(this._fadeIn.status()=="playing"){this._fadeIn.stop();}ds.pop();this._fadeOut.play();if(this._scrollConnected){this._scrollConnected=false;}dojo.forEach(this._modalconnects,dojo.disconnect);this._modalconnects=[];if(this._relativePosition){delete this._relativePosition;}this.open=false;this.onHide();},layout:function(){if(this.domNode.style.display!="none"){if(dijit._underlay){dijit._underlay.layout();}this._position();}},destroy:function(){dojo.forEach(this._modalconnects,dojo.disconnect);if(this.refocus&&this.open){setTimeout(dojo.hitch(dijit,"focus",this._savedFocus),25);}this.inherited(arguments);}});dojo.declare("dijit.Dialog",[dijit.layout.ContentPane,dijit._DialogBase],{});dijit._dialogStack=[];}if(!dojo._hasResource["dijit._HasDropDown"]){dojo._hasResource["dijit._HasDropDown"]=true;dojo.provide("dijit._HasDropDown");dojo.declare("dijit._HasDropDown",null,{_buttonNode:null,_arrowWrapperNode:null,_popupStateNode:null,_aroundNode:null,dropDown:null,autoWidth:true,forceWidth:false,maxHeight:0,dropDownPosition:["below","above"],_stopClickEvents:true,_onDropDownMouseDown:function(e){if(this.disabled||this.readOnly){return;}this._docHandler=this.connect(dojo.doc,"onmouseup","_onDropDownMouseUp");this.toggleDropDown();},_onDropDownMouseUp:function(e){if(e&&this._docHandler){this.disconnect(this._docHandler);}var _299=this.dropDown,_29a=false;if(e&&this._opened){var c=dojo.position(this._buttonNode,true);if(!(e.pageX>=c.x&&e.pageX<=c.x+c.w)||!(e.pageY>=c.y&&e.pageY<=c.y+c.h)){var t=e.target;while(t&&!_29a){if(dojo.hasClass(t,"dijitPopup")){_29a=true;}else{t=t.parentNode;}}if(_29a){t=e.target;if(_299.onItemClick){var _29b;while(t&&!(_29b=dijit.byNode(t))){t=t.parentNode;}if(_29b&&_29b.onClick&&_29b.getParent){_29b.getParent().onItemClick(_29b,e);}}return;}}}if(this._opened&&_299.focus){window.setTimeout(dojo.hitch(_299,"focus"),1);}},_onDropDownClick:function(e){if(this._stopClickEvents){dojo.stopEvent(e);}},_setupDropdown:function(){this._buttonNode=this._buttonNode||this.focusNode||this.domNode;this._popupStateNode=this._popupStateNode||this.focusNode||this._buttonNode;this._aroundNode=this._aroundNode||this.domNode;this.connect(this._buttonNode,"onmousedown","_onDropDownMouseDown");this.connect(this._buttonNode,"onclick","_onDropDownClick");this.connect(this._buttonNode,"onkeydown","_onDropDownKeydown");this.connect(this._buttonNode,"onkeyup","_onKey");if(this._setStateClass){this.connect(this,"openDropDown","_setStateClass");this.connect(this,"closeDropDown","_setStateClass");}var _29c={"after":this.isLeftToRight()?"Right":"Left","before":this.isLeftToRight()?"Left":"Right","above":"Up","below":"Down","left":"Left","right":"Right"}[this.dropDownPosition[0]]||this.dropDownPosition[0]||"Down";dojo.addClass(this._arrowWrapperNode||this._buttonNode,"dijit"+_29c+"ArrowButton");},postCreate:function(){this._setupDropdown();this.inherited(arguments);},destroyDescendants:function(){if(this.dropDown){if(!this.dropDown._destroyed){this.dropDown.destroyRecursive();}delete this.dropDown;}this.inherited(arguments);},_onDropDownKeydown:function(e){if(e.keyCode==dojo.keys.DOWN_ARROW||e.keyCode==dojo.keys.ENTER||e.keyCode==dojo.keys.SPACE){e.preventDefault();}},_onKey:function(e){if(this.disabled||this.readOnly){return;}var d=this.dropDown;if(d&&this._opened&&d.handleKey){if(d.handleKey(e)===false){return;}}if(d&&this._opened&&e.keyCode==dojo.keys.ESCAPE){this.toggleDropDown();}else{if(d&&!this._opened&&(e.keyCode==dojo.keys.DOWN_ARROW||e.keyCode==dojo.keys.ENTER||e.keyCode==dojo.keys.SPACE)){this.toggleDropDown();if(d.focus){setTimeout(dojo.hitch(d,"focus"),1);}}}},_onBlur:function(){this.closeDropDown();this.inherited(arguments);},isLoaded:function(){return true;},loadDropDown:function(_29d){_29d();},toggleDropDown:function(){if(this.disabled||this.readOnly){return;}this.focus();var _29e=this.dropDown;if(!_29e){return;}if(!this._opened){if(!this.isLoaded()){this.loadDropDown(dojo.hitch(this,"openDropDown"));return;}else{this.openDropDown();}}else{this.closeDropDown();}},openDropDown:function(){var _29f=this.dropDown;var _2a0=_29f.domNode;var self=this;if(!this._preparedNode){dijit.popup.moveOffScreen(_2a0);this._preparedNode=true;if(_2a0.style.width){this._explicitDDWidth=true;}if(_2a0.style.height){this._explicitDDHeight=true;}}if(this.maxHeight||this.forceWidth||this.autoWidth){var _2a1={display:"",visibility:"hidden"};if(!this._explicitDDWidth){_2a1.width="";}if(!this._explicitDDHeight){_2a1.height="";}dojo.style(_2a0,_2a1);var mb=dojo.marginBox(_2a0);var _2a2=(this.maxHeight&&mb.h>this.maxHeight);dojo.style(_2a0,{overflowX:"hidden",overflowY:_2a2?"auto":"hidden"});if(_2a2){mb.h=this.maxHeight;if("w" in mb){mb.w+=16;}}else{delete mb.h;}delete mb.t;delete mb.l;if(this.forceWidth){mb.w=this.domNode.offsetWidth;}else{if(this.autoWidth){mb.w=Math.max(mb.w,this.domNode.offsetWidth);}else{delete mb.w;}}if(dojo.isFunction(_29f.resize)){_29f.resize(mb);}else{dojo.marginBox(_2a0,mb);}}var _2a3=dijit.popup.open({parent:this,popup:_29f,around:this._aroundNode,orient:dijit.getPopupAroundAlignment((this.dropDownPosition&&this.dropDownPosition.length)?this.dropDownPosition:["below"],this.isLeftToRight()),onExecute:function(){self.closeDropDown(true);},onCancel:function(){self.closeDropDown(true);},onClose:function(){dojo.attr(self._popupStateNode,"popupActive",false);dojo.removeClass(self._popupStateNode,"dijitHasDropDownOpen");self._opened=false;self.state="";}});dojo.attr(this._popupStateNode,"popupActive","true");dojo.addClass(self._popupStateNode,"dijitHasDropDownOpen");this._opened=true;this.state="Opened";return _2a3;},closeDropDown:function(_2a4){if(this._opened){if(_2a4){this.focus();}dijit.popup.close(this.dropDown);this._opened=false;this.state="";}}});}if(!dojo._hasResource["dijit.form.Button"]){dojo._hasResource["dijit.form.Button"]=true;dojo.provide("dijit.form.Button");dojo.declare("dijit.form.Button",dijit.form._FormWidget,{label:"",showLabel:true,iconClass:"",type:"button",baseClass:"dijitButton",templateString:dojo.cache("dijit.form","templates/Button.html","<span class=\"dijit dijitReset dijitInline\"\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode,focusNode\"\n\t\t\twaiRole=\"button\" waiState=\"labelledby-${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\"></span\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t\tdojoAttachPoint=\"containerNode\"\n\t\t\t></span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),attributeMap:dojo.delegate(dijit.form._FormWidget.prototype.attributeMap,{value:"valueNode",iconClass:{node:"iconNode",type:"class"}}),_onClick:function(e){if(this.disabled){return false;}this._clicked();return this.onClick(e);},_onButtonClick:function(e){if(this._onClick(e)===false){e.preventDefault();}else{if(this.type=="submit"&&!(this.valueNode||this.focusNode).form){for(var node=this.domNode;node.parentNode;node=node.parentNode){var _2a5=dijit.byNode(node);if(_2a5&&typeof _2a5._onSubmit=="function"){_2a5._onSubmit(e);break;}}}else{if(this.valueNode){this.valueNode.click();e.preventDefault();}}}},_fillContent:function(_2a6){if(_2a6&&(!this.params||!("label" in this.params))){this.set("label",_2a6.innerHTML);}},postCreate:function(){dojo.setSelectable(this.focusNode,false);this.inherited(arguments);},_setShowLabelAttr:function(val){if(this.containerNode){dojo.toggleClass(this.containerNode,"dijitDisplayNone",!val);}this.showLabel=val;},onClick:function(e){return true;},_clicked:function(e){},setLabel:function(_2a7){dojo.deprecated("dijit.form.Button.setLabel() is deprecated. Use set('label', ...) instead.","","2.0");this.set("label",_2a7);},_setLabelAttr:function(_2a8){this.containerNode.innerHTML=this.label=_2a8;if(this.showLabel==false&&!this.params.title){this.titleNode.title=dojo.trim(this.containerNode.innerText||this.containerNode.textContent||"");}}});dojo.declare("dijit.form.DropDownButton",[dijit.form.Button,dijit._Container,dijit._HasDropDown],{baseClass:"dijitDropDownButton",templateString:dojo.cache("dijit.form","templates/DropDownButton.html","<span class=\"dijit dijitReset dijitInline\"\n\t><span class='dijitReset dijitInline dijitButtonNode'\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\" dojoAttachPoint=\"_buttonNode\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"focusNode,titleNode,_arrowWrapperNode\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true,labelledby-${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\"\n\t\t\t\tdojoAttachPoint=\"iconNode\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tdojoAttachPoint=\"containerNode,_popupStateNode\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonInner\"></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonChar\">&#9660;</span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),_fillContent:function(){if(this.srcNodeRef){var _2a9=dojo.query("*",this.srcNodeRef);dijit.form.DropDownButton.superclass._fillContent.call(this,_2a9[0]);this.dropDownContainer=this.srcNodeRef;}},startup:function(){if(this._started){return;}if(!this.dropDown){var _2aa=dojo.query("[widgetId]",this.dropDownContainer)[0];this.dropDown=dijit.byNode(_2aa);delete this.dropDownContainer;}dijit.popup.moveOffScreen(this.dropDown.domNode);this.inherited(arguments);},isLoaded:function(){var _2ab=this.dropDown;return (!_2ab.href||_2ab.isLoaded);},loadDropDown:function(){var _2ac=this.dropDown;if(!_2ac){return;}if(!this.isLoaded()){var _2ad=dojo.connect(_2ac,"onLoad",this,function(){dojo.disconnect(_2ad);this.openDropDown();});_2ac.refresh();}else{this.openDropDown();}},isFocusable:function(){return this.inherited(arguments)&&!this._mouseDown;}});dojo.declare("dijit.form.ComboButton",dijit.form.DropDownButton,{templateString:dojo.cache("dijit.form","templates/ComboButton.html","<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tcellspacing='0' cellpadding='0' waiRole=\"presentation\"\n\t><tbody waiRole=\"presentation\"><tr waiRole=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonNode\" dojoAttachPoint=\"buttonNode\" dojoAttachEvent=\"ondijitclick:_onButtonClick,onkeypress:_onButtonKeyPress\"\n\t\t><div id=\"${id}_button\" class=\"dijitReset dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode\"\n\t\t\twaiRole=\"button\" waiState=\"labelledby-${id}_label\"\n\t\t\t><div class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitInline dijitButtonText\" id=\"${id}_label\" dojoAttachPoint=\"containerNode\" waiRole=\"presentation\"></div\n\t\t></div\n\t\t></td\n\t\t><td id=\"${id}_arrow\" class='dijitReset dijitRight dijitButtonNode dijitArrowButton'\n\t\t\tdojoAttachPoint=\"_popupStateNode,focusNode,_buttonNode\"\n\t\t\tdojoAttachEvent=\"onkeypress:_onArrowKeyPress\"\n\t\t\ttitle=\"${optionsTitle}\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" waiRole=\"presentation\">&#9660;</div\n\t\t></td\n\t\t><td style=\"display:none !important;\"\n\t\t\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" dojoAttachPoint=\"valueNode\"\n\t\t/></td></tr></tbody\n></table>\n"),attributeMap:dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap),{id:"",tabIndex:["focusNode","titleNode"],title:"titleNode"}),optionsTitle:"",baseClass:"dijitComboButton",cssStateNodes:{"buttonNode":"dijitButtonNode","titleNode":"dijitButtonContents","_popupStateNode":"dijitDownArrowButton"},_focusedNode:null,_onButtonKeyPress:function(evt){if(evt.charOrCode==dojo.keys[this.isLeftToRight()?"RIGHT_ARROW":"LEFT_ARROW"]){dijit.focus(this._popupStateNode);dojo.stopEvent(evt);}},_onArrowKeyPress:function(evt){if(evt.charOrCode==dojo.keys[this.isLeftToRight()?"LEFT_ARROW":"RIGHT_ARROW"]){dijit.focus(this.titleNode);dojo.stopEvent(evt);}},focus:function(_2ae){dijit.focus(_2ae=="start"?this.titleNode:this._popupStateNode);}});dojo.declare("dijit.form.ToggleButton",dijit.form.Button,{baseClass:"dijitToggleButton",checked:false,attributeMap:dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap),{checked:"focusNode"}),_clicked:function(evt){this.set("checked",!this.checked);},_setCheckedAttr:function(_2af,_2b0){this.checked=_2af;dojo.attr(this.focusNode||this.domNode,"checked",_2af);dijit.setWaiState(this.focusNode||this.domNode,"pressed",_2af);this._handleOnChange(_2af,_2b0);},setChecked:function(_2b1){dojo.deprecated("setChecked("+_2b1+") is deprecated. Use set('checked',"+_2b1+") instead.","","2.0");this.set("checked",_2b1);},reset:function(){this._hasBeenBlurred=false;this.set("checked",this.params.checked||false);}});}if(!dojo._hasResource["dijit.form.ToggleButton"]){dojo._hasResource["dijit.form.ToggleButton"]=true;dojo.provide("dijit.form.ToggleButton");}if(!dojo._hasResource["dijit.form.CheckBox"]){dojo._hasResource["dijit.form.CheckBox"]=true;dojo.provide("dijit.form.CheckBox");dojo.declare("dijit.form.CheckBox",dijit.form.ToggleButton,{templateString:dojo.cache("dijit.form","templates/CheckBox.html","<div class=\"dijit dijitReset dijitInline\" waiRole=\"presentation\"\n\t><input\n\t \t${!nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\n\t\tdojoAttachPoint=\"focusNode\"\n\t \tdojoAttachEvent=\"onclick:_onClick\"\n/></div>\n"),baseClass:"dijitCheckBox",type:"checkbox",value:"on",readOnly:false,attributeMap:dojo.delegate(dijit.form._FormWidget.prototype.attributeMap,{readOnly:"focusNode"}),_setReadOnlyAttr:function(_2b2){this.readOnly=_2b2;dojo.attr(this.focusNode,"readOnly",_2b2);dijit.setWaiState(this.focusNode,"readonly",_2b2);},_setValueAttr:function(_2b3,_2b4){if(typeof _2b3=="string"){this.value=_2b3;dojo.attr(this.focusNode,"value",_2b3);_2b3=true;}if(this._created){this.set("checked",_2b3,_2b4);}},_getValueAttr:function(){return (this.checked?this.value:false);},_setLabelAttr:undefined,postMixInProperties:function(){if(this.value==""){this.value="on";}this.checkedAttrSetting=this.checked?"checked":"";this.inherited(arguments);},_fillContent:function(_2b5){},reset:function(){this._hasBeenBlurred=false;this.set("checked",this.params.checked||false);this.value=this.params.value||"on";dojo.attr(this.focusNode,"value",this.value);},_onFocus:function(){if(this.id){dojo.query("label[for='"+this.id+"']").addClass("dijitFocusedLabel");}this.inherited(arguments);},_onBlur:function(){if(this.id){dojo.query("label[for='"+this.id+"']").removeClass("dijitFocusedLabel");}this.inherited(arguments);},_onClick:function(e){if(this.readOnly){return false;}return this.inherited(arguments);}});dojo.declare("dijit.form.RadioButton",dijit.form.CheckBox,{type:"radio",baseClass:"dijitRadio",_setCheckedAttr:function(_2b6){this.inherited(arguments);if(!this._created){return;}if(_2b6){var _2b7=this;dojo.query("INPUT[type=radio]",this.focusNode.form||dojo.doc).forEach(function(_2b8){if(_2b8.name==_2b7.name&&_2b8!=_2b7.focusNode&&_2b8.form==_2b7.focusNode.form){var _2b9=dijit.getEnclosingWidget(_2b8);if(_2b9&&_2b9.checked){_2b9.set("checked",false);}}});}},_clicked:function(e){if(!this.checked){this.set("checked",true);}}});}if(!dojo._hasResource["dijit.form.DropDownButton"]){dojo._hasResource["dijit.form.DropDownButton"]=true;dojo.provide("dijit.form.DropDownButton");}if(!dojo._hasResource["dojo.regexp"]){dojo._hasResource["dojo.regexp"]=true;dojo.provide("dojo.regexp");dojo.regexp.escapeString=function(str,_2ba){return str.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g,function(ch){if(_2ba&&_2ba.indexOf(ch)!=-1){return ch;}return "\\"+ch;});};dojo.regexp.buildGroupRE=function(arr,re,_2bb){if(!(arr instanceof Array)){return re(arr);}var b=[];for(var i=0;i<arr.length;i++){b.push(re(arr[i]));}return dojo.regexp.group(b.join("|"),_2bb);};dojo.regexp.group=function(_2bc,_2bd){return "("+(_2bd?"?:":"")+_2bc+")";};}if(!dojo._hasResource["dojo.data.util.sorter"]){dojo._hasResource["dojo.data.util.sorter"]=true;dojo.provide("dojo.data.util.sorter");dojo.data.util.sorter.basicComparator=function(a,b){var r=-1;if(a===null){a=undefined;}if(b===null){b=undefined;}if(a==b){r=0;}else{if(a>b||a==null){r=1;}}return r;};dojo.data.util.sorter.createSortFunction=function(_2be,_2bf){var _2c0=[];function _2c1(attr,dir,comp,s){return function(_2c2,_2c3){var a=s.getValue(_2c2,attr);var b=s.getValue(_2c3,attr);return dir*comp(a,b);};};var _2c4;var map=_2bf.comparatorMap;var bc=dojo.data.util.sorter.basicComparator;for(var i=0;i<_2be.length;i++){_2c4=_2be[i];var attr=_2c4.attribute;if(attr){var dir=(_2c4.descending)?-1:1;var comp=bc;if(map){if(typeof attr!=="string"&&("toString" in attr)){attr=attr.toString();}comp=map[attr]||bc;}_2c0.push(_2c1(attr,dir,comp,_2bf));}}return function(rowA,rowB){var i=0;while(i<_2c0.length){var ret=_2c0[i++](rowA,rowB);if(ret!==0){return ret;}}return 0;};};}if(!dojo._hasResource["dojo.data.util.simpleFetch"]){dojo._hasResource["dojo.data.util.simpleFetch"]=true;dojo.provide("dojo.data.util.simpleFetch");dojo.data.util.simpleFetch.fetch=function(_2c5){_2c5=_2c5||{};if(!_2c5.store){_2c5.store=this;}var self=this;var _2c6=function(_2c7,_2c8){if(_2c8.onError){var _2c9=_2c8.scope||dojo.global;_2c8.onError.call(_2c9,_2c7,_2c8);}};var _2ca=function(_2cb,_2cc){var _2cd=_2cc.abort||null;var _2ce=false;var _2cf=_2cc.start?_2cc.start:0;var _2d0=(_2cc.count&&(_2cc.count!==Infinity))?(_2cf+_2cc.count):_2cb.length;_2cc.abort=function(){_2ce=true;if(_2cd){_2cd.call(_2cc);}};var _2d1=_2cc.scope||dojo.global;if(!_2cc.store){_2cc.store=self;}if(_2cc.onBegin){_2cc.onBegin.call(_2d1,_2cb.length,_2cc);}if(_2cc.sort){_2cb.sort(dojo.data.util.sorter.createSortFunction(_2cc.sort,self));}if(_2cc.onItem){for(var i=_2cf;(i<_2cb.length)&&(i<_2d0);++i){var item=_2cb[i];if(!_2ce){_2cc.onItem.call(_2d1,item,_2cc);}}}if(_2cc.onComplete&&!_2ce){var _2d2=null;if(!_2cc.onItem){_2d2=_2cb.slice(_2cf,_2d0);}_2cc.onComplete.call(_2d1,_2d2,_2cc);}};this._fetchItems(_2c5,_2ca,_2c6);return _2c5;};}if(!dojo._hasResource["dojo.data.util.filter"]){dojo._hasResource["dojo.data.util.filter"]=true;dojo.provide("dojo.data.util.filter");dojo.data.util.filter.patternToRegExp=function(_2d3,_2d4){var rxp="^";var c=null;for(var i=0;i<_2d3.length;i++){c=_2d3.charAt(i);switch(c){case "\\":rxp+=c;i++;rxp+=_2d3.charAt(i);break;case "*":rxp+=".*";break;case "?":rxp+=".";break;case "$":case "^":case "/":case "+":case ".":case "|":case "(":case ")":case "{":case "}":case "[":case "]":rxp+="\\";default:rxp+=c;}}rxp+="$";if(_2d4){return new RegExp(rxp,"mi");}else{return new RegExp(rxp,"m");}};}if(!dojo._hasResource["dijit.form.TextBox"]){dojo._hasResource["dijit.form.TextBox"]=true;dojo.provide("dijit.form.TextBox");dojo.declare("dijit.form.TextBox",dijit.form._FormValueWidget,{trim:false,uppercase:false,lowercase:false,propercase:false,maxLength:"",selectOnClick:false,placeHolder:"",templateString:dojo.cache("dijit.form","templates/TextBox.html","<div class=\"dijit dijitReset dijitInline dijitLeft\" id=\"widget_${id}\" waiRole=\"presentation\"\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),_singleNodeTemplate:"<input class=\"dijit dijitReset dijitLeft dijitInputField\" dojoAttachPoint=\"textbox,focusNode\" autocomplete=\"off\" type=\"${type}\" ${!nameAttrSetting} />",_buttonInputDisabled:dojo.isIE?"disabled":"",baseClass:"dijitTextBox",attributeMap:dojo.delegate(dijit.form._FormValueWidget.prototype.attributeMap,{maxLength:"focusNode"}),postMixInProperties:function(){var type=this.type.toLowerCase();if(this.templateString.toLowerCase()=="input"||((type=="hidden"||type=="file")&&this.templateString==dijit.form.TextBox.prototype.templateString)){this.templateString=this._singleNodeTemplate;}this.inherited(arguments);},_setPlaceHolderAttr:function(v){this.placeHolder=v;if(!this._phspan){this._attachPoints.push("_phspan");this._phspan=dojo.create("span",{className:"dijitPlaceHolder dijitInputField"},this.textbox,"after");}this._phspan.innerHTML="";this._phspan.appendChild(document.createTextNode(v));this._updatePlaceHolder();},_updatePlaceHolder:function(){if(this._phspan){this._phspan.style.display=(this.placeHolder&&!this._focused&&!this.textbox.value)?"":"none";}},_getValueAttr:function(){return this.parse(this.get("displayedValue"),this.constraints);},_setValueAttr:function(_2d5,_2d6,_2d7){var _2d8;if(_2d5!==undefined){_2d8=this.filter(_2d5);if(typeof _2d7!="string"){if(_2d8!==null&&((typeof _2d8!="number")||!isNaN(_2d8))){_2d7=this.filter(this.format(_2d8,this.constraints));}else{_2d7="";}}}if(_2d7!=null&&_2d7!=undefined&&((typeof _2d7)!="number"||!isNaN(_2d7))&&this.textbox.value!=_2d7){this.textbox.value=_2d7;}this._updatePlaceHolder();this.inherited(arguments,[_2d8,_2d6]);},displayedValue:"",getDisplayedValue:function(){dojo.deprecated(this.declaredClass+"::getDisplayedValue() is deprecated. Use set('displayedValue') instead.","","2.0");return this.get("displayedValue");},_getDisplayedValueAttr:function(){return this.filter(this.textbox.value);},setDisplayedValue:function(_2d9){dojo.deprecated(this.declaredClass+"::setDisplayedValue() is deprecated. Use set('displayedValue', ...) instead.","","2.0");this.set("displayedValue",_2d9);},_setDisplayedValueAttr:function(_2da){if(_2da===null||_2da===undefined){_2da="";}else{if(typeof _2da!="string"){_2da=String(_2da);}}this.textbox.value=_2da;this._setValueAttr(this.get("value"),undefined,_2da);},format:function(_2db,_2dc){return ((_2db==null||_2db==undefined)?"":(_2db.toString?_2db.toString():_2db));},parse:function(_2dd,_2de){return _2dd;},_refreshState:function(){},_onInput:function(e){if(e&&e.type&&/key/i.test(e.type)&&e.keyCode){switch(e.keyCode){case dojo.keys.SHIFT:case dojo.keys.ALT:case dojo.keys.CTRL:case dojo.keys.TAB:return;}}if(this.intermediateChanges){var _2df=this;setTimeout(function(){_2df._handleOnChange(_2df.get("value"),false);},0);}this._refreshState();},postCreate:function(){if(dojo.isIE){var s=dojo.getComputedStyle(this.domNode);if(s){var ff=s.fontFamily;if(ff){var _2e0=this.domNode.getElementsByTagName("INPUT");if(_2e0){for(var i=0;i<_2e0.length;i++){_2e0[i].style.fontFamily=ff;}}}}}this.textbox.setAttribute("value",this.textbox.value);this.inherited(arguments);if(dojo.isMoz||dojo.isOpera){this.connect(this.textbox,"oninput",this._onInput);}else{this.connect(this.textbox,"onkeydown",this._onInput);this.connect(this.textbox,"onkeyup",this._onInput);this.connect(this.textbox,"onpaste",this._onInput);this.connect(this.textbox,"oncut",this._onInput);}},_blankValue:"",filter:function(val){if(val===null){return this._blankValue;}if(typeof val!="string"){return val;}if(this.trim){val=dojo.trim(val);}if(this.uppercase){val=val.toUpperCase();}if(this.lowercase){val=val.toLowerCase();}if(this.propercase){val=val.replace(/[^\s]+/g,function(word){return word.substring(0,1).toUpperCase()+word.substring(1);});}return val;},_setBlurValue:function(){this._setValueAttr(this.get("value"),true);},_onBlur:function(e){if(this.disabled){return;}this._setBlurValue();this.inherited(arguments);if(this._selectOnClickHandle){this.disconnect(this._selectOnClickHandle);}if(this.selectOnClick&&dojo.isMoz){this.textbox.selectionStart=this.textbox.selectionEnd=undefined;}this._updatePlaceHolder();},_onFocus:function(by){if(this.disabled||this.readOnly){return;}if(this.selectOnClick&&by=="mouse"){this._selectOnClickHandle=this.connect(this.domNode,"onmouseup",function(){this.disconnect(this._selectOnClickHandle);var _2e1;if(dojo.isIE){var _2e2=dojo.doc.selection.createRange();var _2e3=_2e2.parentElement();_2e1=_2e3==this.textbox&&_2e2.text.length==0;}else{_2e1=this.textbox.selectionStart==this.textbox.selectionEnd;}if(_2e1){dijit.selectInputText(this.textbox);}});}this._updatePlaceHolder();this._refreshState();this.inherited(arguments);},reset:function(){this.textbox.value="";this.inherited(arguments);}});dijit.selectInputText=function(_2e4,_2e5,stop){var _2e6=dojo.global;var _2e7=dojo.doc;_2e4=dojo.byId(_2e4);if(isNaN(_2e5)){_2e5=0;}if(isNaN(stop)){stop=_2e4.value?_2e4.value.length:0;}dijit.focus(_2e4);if(_2e7["selection"]&&dojo.body()["createTextRange"]){if(_2e4.createTextRange){var _2e8=_2e4.createTextRange();with(_2e8){collapse(true);moveStart("character",-99999);moveStart("character",_2e5);moveEnd("character",stop-_2e5);select();}}}else{if(_2e6["getSelection"]){if(_2e4.setSelectionRange){_2e4.setSelectionRange(_2e5,stop);}}}};}if(!dojo._hasResource["dijit.Tooltip"]){dojo._hasResource["dijit.Tooltip"]=true;dojo.provide("dijit.Tooltip");dojo.declare("dijit._MasterTooltip",[dijit._Widget,dijit._Templated],{duration:dijit.defaultDuration,templateString:dojo.cache("dijit","templates/Tooltip.html","<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\">\n\t<div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" waiRole='alert'></div>\n\t<div class=\"dijitTooltipConnector\"></div>\n</div>\n"),postCreate:function(){dojo.body().appendChild(this.domNode);this.bgIframe=new dijit.BackgroundIframe(this.domNode);this.fadeIn=dojo.fadeIn({node:this.domNode,duration:this.duration,onEnd:dojo.hitch(this,"_onShow")});this.fadeOut=dojo.fadeOut({node:this.domNode,duration:this.duration,onEnd:dojo.hitch(this,"_onHide")});},show:function(_2e9,_2ea,_2eb,rtl){if(this.aroundNode&&this.aroundNode===_2ea){return;}if(this.fadeOut.status()=="playing"){this._onDeck=arguments;return;}this.containerNode.innerHTML=_2e9;var pos=dijit.placeOnScreenAroundElement(this.domNode,_2ea,dijit.getPopupAroundAlignment((_2eb&&_2eb.length)?_2eb:dijit.Tooltip.defaultPosition,!rtl),dojo.hitch(this,"orient"));dojo.style(this.domNode,"opacity",0);this.fadeIn.play();this.isShowingNow=true;this.aroundNode=_2ea;},orient:function(node,_2ec,_2ed){node.className="dijitTooltip "+{"BL-TL":"dijitTooltipBelow dijitTooltipABLeft","TL-BL":"dijitTooltipAbove dijitTooltipABLeft","BR-TR":"dijitTooltipBelow dijitTooltipABRight","TR-BR":"dijitTooltipAbove dijitTooltipABRight","BR-BL":"dijitTooltipRight","BL-BR":"dijitTooltipLeft"}[_2ec+"-"+_2ed];},_onShow:function(){if(dojo.isIE){this.domNode.style.filter="";}},hide:function(_2ee){if(this._onDeck&&this._onDeck[1]==_2ee){this._onDeck=null;}else{if(this.aroundNode===_2ee){this.fadeIn.stop();this.isShowingNow=false;this.aroundNode=null;this.fadeOut.play();}else{}}},_onHide:function(){this.domNode.style.cssText="";this.containerNode.innerHTML="";if(this._onDeck){this.show.apply(this,this._onDeck);this._onDeck=null;}}});dijit.showTooltip=function(_2ef,_2f0,_2f1,rtl){if(!dijit._masterTT){dijit._masterTT=new dijit._MasterTooltip();}return dijit._masterTT.show(_2ef,_2f0,_2f1,rtl);};dijit.hideTooltip=function(_2f2){if(!dijit._masterTT){dijit._masterTT=new dijit._MasterTooltip();}return dijit._masterTT.hide(_2f2);};dojo.declare("dijit.Tooltip",dijit._Widget,{label:"",showDelay:400,connectId:[],position:[],constructor:function(){this._nodeConnectionsById={};},_setConnectIdAttr:function(_2f3){for(var _2f4 in this._nodeConnectionsById){this.removeTarget(_2f4);}dojo.forEach(dojo.isArrayLike(_2f3)?_2f3:[_2f3],this.addTarget,this);},_getConnectIdAttr:function(){var ary=[];for(var id in this._nodeConnectionsById){ary.push(id);}return ary;},addTarget:function(id){var node=dojo.byId(id);if(!node){return;}if(node.id in this._nodeConnectionsById){return;}this._nodeConnectionsById[node.id]=[this.connect(node,"onmouseenter","_onTargetMouseEnter"),this.connect(node,"onmouseleave","_onTargetMouseLeave"),this.connect(node,"onfocus","_onTargetFocus"),this.connect(node,"onblur","_onTargetBlur")];},removeTarget:function(node){var id=node.id||node;if(id in this._nodeConnectionsById){dojo.forEach(this._nodeConnectionsById[id],this.disconnect,this);delete this._nodeConnectionsById[id];}},postCreate:function(){dojo.addClass(this.domNode,"dijitTooltipData");},startup:function(){this.inherited(arguments);var ids=this.connectId;dojo.forEach(dojo.isArrayLike(ids)?ids:[ids],this.addTarget,this);},_onTargetMouseEnter:function(e){this._onHover(e);},_onTargetMouseLeave:function(e){this._onUnHover(e);},_onTargetFocus:function(e){this._focus=true;this._onHover(e);},_onTargetBlur:function(e){this._focus=false;this._onUnHover(e);},_onHover:function(e){if(!this._showTimer){var _2f5=e.target;this._showTimer=setTimeout(dojo.hitch(this,function(){this.open(_2f5);}),this.showDelay);}},_onUnHover:function(e){if(this._focus){return;}if(this._showTimer){clearTimeout(this._showTimer);delete this._showTimer;}this.close();},open:function(_2f6){if(this._showTimer){clearTimeout(this._showTimer);delete this._showTimer;}dijit.showTooltip(this.label||this.domNode.innerHTML,_2f6,this.position,!this.isLeftToRight());this._connectNode=_2f6;this.onShow(_2f6,this.position);},close:function(){if(this._connectNode){dijit.hideTooltip(this._connectNode);delete this._connectNode;this.onHide();}if(this._showTimer){clearTimeout(this._showTimer);delete this._showTimer;}},onShow:function(_2f7,_2f8){},onHide:function(){},uninitialize:function(){this.close();this.inherited(arguments);}});dijit.Tooltip.defaultPosition=["after","before"];}if(!dojo._hasResource["dijit.form.ValidationTextBox"]){dojo._hasResource["dijit.form.ValidationTextBox"]=true;dojo.provide("dijit.form.ValidationTextBox");dojo.declare("dijit.form.ValidationTextBox",dijit.form.TextBox,{templateString:dojo.cache("dijit.form","templates/ValidationTextBox.html","<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\" waiRole=\"presentation\"\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&Chi; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),baseClass:"dijitTextBox dijitValidationTextBox",required:false,promptMessage:"",invalidMessage:"$_unset_$",missingMessage:"$_unset_$",constraints:{},regExp:".*",regExpGen:function(_2f9){return this.regExp;},state:"",tooltipPosition:[],_setValueAttr:function(){this.inherited(arguments);this.validate(this._focused);},validator:function(_2fa,_2fb){return (new RegExp("^(?:"+this.regExpGen(_2fb)+")"+(this.required?"":"?")+"$")).test(_2fa)&&(!this.required||!this._isEmpty(_2fa))&&(this._isEmpty(_2fa)||this.parse(_2fa,_2fb)!==undefined);},_isValidSubset:function(){return this.textbox.value.search(this._partialre)==0;},isValid:function(_2fc){return this.validator(this.textbox.value,this.constraints);},_isEmpty:function(_2fd){return /^\s*$/.test(_2fd);},getErrorMessage:function(_2fe){return (this.required&&this._isEmpty(this.textbox.value))?this.missingMessage:this.invalidMessage;},getPromptMessage:function(_2ff){return this.promptMessage;},_maskValidSubsetError:true,validate:function(_300){var _301="";var _302=this.disabled||this.isValid(_300);if(_302){this._maskValidSubsetError=true;}var _303=this._isEmpty(this.textbox.value);var _304=!_302&&!_303&&_300&&this._isValidSubset();this.state=((_302||((!this._hasBeenBlurred||_300)&&_303)||_304)&&this._maskValidSubsetError)?"":"Error";if(this.state=="Error"){this._maskValidSubsetError=_300;}this._setStateClass();dijit.setWaiState(this.focusNode,"invalid",_302?"false":"true");if(_300){if(this.state=="Error"){_301=this.getErrorMessage(true);}else{_301=this.getPromptMessage(true);}this._maskValidSubsetError=true;}this.displayMessage(_301);return _302;},_message:"",displayMessage:function(_305){if(this._message==_305){return;}this._message=_305;dijit.hideTooltip(this.domNode);if(_305){dijit.showTooltip(_305,this.domNode,this.tooltipPosition,!this.isLeftToRight());}},_refreshState:function(){this.validate(this._focused);this.inherited(arguments);},constructor:function(){this.constraints={};},_setConstraintsAttr:function(_306){if(!_306.locale&&this.lang){_306.locale=this.lang;}this.constraints=_306;this._computePartialRE();},_computePartialRE:function(){var p=this.regExpGen(this.constraints);this.regExp=p;var _307="";if(p!=".*"){this.regExp.replace(/\\.|\[\]|\[.*?[^\\]{1}\]|\{.*?\}|\(\?[=:!]|./g,function(re){switch(re.charAt(0)){case "{":case "+":case "?":case "*":case "^":case "$":case "|":case "(":_307+=re;break;case ")":_307+="|$)";break;default:_307+="(?:"+re+"|$)";break;}});}try{"".search(_307);}catch(e){_307=this.regExp;console.warn("RegExp error in "+this.declaredClass+": "+this.regExp);}this._partialre="^(?:"+_307+")$";},postMixInProperties:function(){this.inherited(arguments);this.messages=dojo.i18n.getLocalization("dijit.form","validate",this.lang);if(this.invalidMessage=="$_unset_$"){this.invalidMessage=this.messages.invalidMessage;}if(!this.invalidMessage){this.invalidMessage=this.promptMessage;}if(this.missingMessage=="$_unset_$"){this.missingMessage=this.messages.missingMessage;}if(!this.missingMessage){this.missingMessage=this.invalidMessage;}this._setConstraintsAttr(this.constraints);},_setDisabledAttr:function(_308){this.inherited(arguments);this._refreshState();},_setRequiredAttr:function(_309){this.required=_309;dijit.setWaiState(this.focusNode,"required",_309);this._refreshState();},reset:function(){this._maskValidSubsetError=true;this.inherited(arguments);},_onBlur:function(){this.displayMessage("");this.inherited(arguments);}});dojo.declare("dijit.form.MappedTextBox",dijit.form.ValidationTextBox,{postMixInProperties:function(){this.inherited(arguments);this.nameAttrSetting="";},serialize:function(val,_30a){return val.toString?val.toString():"";},toString:function(){var val=this.filter(this.get("value"));return val!=null?(typeof val=="string"?val:this.serialize(val,this.constraints)):"";},validate:function(){this.valueNode.value=this.toString();return this.inherited(arguments);},buildRendering:function(){this.inherited(arguments);this.valueNode=dojo.place("<input type='hidden'"+(this.name?" name='"+this.name+"'":"")+">",this.textbox,"after");},reset:function(){this.valueNode.value="";this.inherited(arguments);}});dojo.declare("dijit.form.RangeBoundTextBox",dijit.form.MappedTextBox,{rangeMessage:"",rangeCheck:function(_30b,_30c){return ("min" in _30c?(this.compare(_30b,_30c.min)>=0):true)&&("max" in _30c?(this.compare(_30b,_30c.max)<=0):true);},isInRange:function(_30d){return this.rangeCheck(this.get("value"),this.constraints);},_isDefinitelyOutOfRange:function(){var val=this.get("value");var _30e=false;var _30f=false;if("min" in this.constraints){var min=this.constraints.min;min=this.compare(val,((typeof min=="number")&&min>=0&&val!=0)?0:min);_30e=(typeof min=="number")&&min<0;}if("max" in this.constraints){var max=this.constraints.max;max=this.compare(val,((typeof max!="number")||max>0)?max:0);_30f=(typeof max=="number")&&max>0;}return _30e||_30f;},_isValidSubset:function(){return this.inherited(arguments)&&!this._isDefinitelyOutOfRange();},isValid:function(_310){return this.inherited(arguments)&&((this._isEmpty(this.textbox.value)&&!this.required)||this.isInRange(_310));},getErrorMessage:function(_311){var v=this.get("value");if(v!==null&&v!==""&&v!==undefined&&(typeof v!="number"||!isNaN(v))&&!this.isInRange(_311)){return this.rangeMessage;}return this.inherited(arguments);},postMixInProperties:function(){this.inherited(arguments);if(!this.rangeMessage){this.messages=dojo.i18n.getLocalization("dijit.form","validate",this.lang);this.rangeMessage=this.messages.rangeMessage;}},_setConstraintsAttr:function(_312){this.inherited(arguments);if(this.focusNode){if(this.constraints.min!==undefined){dijit.setWaiState(this.focusNode,"valuemin",this.constraints.min);}else{dijit.removeWaiState(this.focusNode,"valuemin");}if(this.constraints.max!==undefined){dijit.setWaiState(this.focusNode,"valuemax",this.constraints.max);}else{dijit.removeWaiState(this.focusNode,"valuemax");}}},_setValueAttr:function(_313,_314){dijit.setWaiState(this.focusNode,"valuenow",_313);this.inherited(arguments);}});}if(!dojo._hasResource["dijit.form.ComboBox"]){dojo._hasResource["dijit.form.ComboBox"]=true;dojo.provide("dijit.form.ComboBox");dojo.declare("dijit.form.ComboBoxMixin",null,{item:null,pageSize:Infinity,store:null,fetchProperties:{},query:{},autoComplete:true,highlightMatch:"first",searchDelay:100,searchAttr:"name",labelAttr:"",labelType:"text",queryExpr:"${0}*",ignoreCase:true,hasDownArrow:true,templateString:dojo.cache("dijit.form","templates/ComboBox.html","<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\"\n\tdojoAttachPoint=\"comboNode\" waiRole=\"combobox\"\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\n\t\tdojoAttachPoint=\"downArrowNode\" waiRole=\"presentation\"\n\t\tdojoAttachEvent=\"onmousedown:_onArrowMouseDown\"\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t\t\t${_buttonInputDisabled}\n\t/></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&Chi; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\n\t\t\tdojoAttachEvent=\"onkeypress:_onKeyPress,compositionend\"\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" waiRole=\"textbox\" waiState=\"haspopup-true,autocomplete-list\"\n\t/></div\n></div>\n"),baseClass:"dijitTextBox dijitComboBox",cssStateNodes:{"downArrowNode":"dijitDownArrowButton"},_getCaretPos:function(_315){var pos=0;if(typeof (_315.selectionStart)=="number"){pos=_315.selectionStart;}else{if(dojo.isIE){var tr=dojo.doc.selection.createRange().duplicate();var ntr=_315.createTextRange();tr.move("character",0);ntr.move("character",0);try{ntr.setEndPoint("EndToEnd",tr);pos=String(ntr.text).replace(/\r/g,"").length;}catch(e){}}}return pos;},_setCaretPos:function(_316,_317){_317=parseInt(_317);dijit.selectInputText(_316,_317,_317);},_setDisabledAttr:function(_318){this.inherited(arguments);dijit.setWaiState(this.comboNode,"disabled",_318);},_abortQuery:function(){if(this.searchTimer){clearTimeout(this.searchTimer);this.searchTimer=null;}if(this._fetchHandle){if(this._fetchHandle.abort){this._fetchHandle.abort();}this._fetchHandle=null;}},_onInput:function(evt){if(!this.searchTimer&&(evt.type=="paste"||evt.type=="input")&&this._lastInput!=this.textbox.value){this.searchTimer=setTimeout(dojo.hitch(this,function(){this._onKeyPress({charOrCode:229});}),100);}this.inherited(arguments);},_onKeyPress:function(evt){var key=evt.charOrCode;if(evt.altKey||((evt.ctrlKey||evt.metaKey)&&(key!="x"&&key!="v"))||key==dojo.keys.SHIFT){return;}var _319=false;var _31a="_startSearchFromInput";var pw=this._popupWidget;var dk=dojo.keys;var _31b=null;this._prev_key_backspace=false;this._abortQuery();if(this._isShowingNow){pw.handleKey(key);_31b=pw.getHighlightedOption();}switch(key){case dk.PAGE_DOWN:case dk.DOWN_ARROW:case dk.PAGE_UP:case dk.UP_ARROW:if(!this._isShowingNow){_319=true;_31a="_startSearchAll";}else{this._announceOption(_31b);}dojo.stopEvent(evt);break;case dk.ENTER:if(_31b){if(_31b==pw.nextButton){this._nextSearch(1);dojo.stopEvent(evt);break;}else{if(_31b==pw.previousButton){this._nextSearch(-1);dojo.stopEvent(evt);break;}}}else{this._setBlurValue();this._setCaretPos(this.focusNode,this.focusNode.value.length);}evt.preventDefault();case dk.TAB:var _31c=this.get("displayedValue");if(pw&&(_31c==pw._messages["previousMessage"]||_31c==pw._messages["nextMessage"])){break;}if(_31b){this._selectOption();}if(this._isShowingNow){this._lastQuery=null;this._hideResultList();}break;case " ":if(_31b){dojo.stopEvent(evt);this._selectOption();this._hideResultList();}else{_319=true;}break;case dk.ESCAPE:if(this._isShowingNow){dojo.stopEvent(evt);this._hideResultList();}break;case dk.DELETE:case dk.BACKSPACE:this._prev_key_backspace=true;_319=true;break;default:_319=typeof key=="string"||key==229;}if(_319){this.item=undefined;this.searchTimer=setTimeout(dojo.hitch(this,_31a),1);}},_autoCompleteText:function(text){var fn=this.focusNode;dijit.selectInputText(fn,fn.value.length);var _31d=this.ignoreCase?"toLowerCase":"substr";if(text[_31d](0).indexOf(this.focusNode.value[_31d](0))==0){var cpos=this._getCaretPos(fn);if((cpos+1)>fn.value.length){fn.value=text;dijit.selectInputText(fn,cpos);}}else{fn.value=text;dijit.selectInputText(fn);}},_openResultList:function(_31e,_31f){this._fetchHandle=null;if(this.disabled||this.readOnly||(_31f.query[this.searchAttr]!=this._lastQuery)){return;}this._popupWidget.clearResultList();if(!_31e.length&&!this._maxOptions){this._hideResultList();return;}_31f._maxOptions=this._maxOptions;var _320=this._popupWidget.createOptions(_31e,_31f,dojo.hitch(this,"_getMenuLabelFromItem"));this._showResultList();if(_31f.direction){if(1==_31f.direction){this._popupWidget.highlightFirstOption();}else{if(-1==_31f.direction){this._popupWidget.highlightLastOption();}}this._announceOption(this._popupWidget.getHighlightedOption());}else{if(this.autoComplete&&!this._prev_key_backspace&&!/^[*]+$/.test(_31f.query[this.searchAttr])){this._announceOption(_320[1]);}}},_showResultList:function(){this._hideResultList();this.displayMessage("");dojo.style(this._popupWidget.domNode,{width:"",height:""});var best=this.open();var _321=dojo.marginBox(this._popupWidget.domNode);this._popupWidget.domNode.style.overflow=((best.h==_321.h)&&(best.w==_321.w))?"hidden":"auto";var _322=best.w;if(best.h<this._popupWidget.domNode.scrollHeight){_322+=16;}dojo.marginBox(this._popupWidget.domNode,{h:best.h,w:Math.max(_322,this.domNode.offsetWidth)});if(_322<this.domNode.offsetWidth){this._popupWidget.domNode.parentNode.style.left=dojo.position(this.domNode,true).x+"px";}dijit.setWaiState(this.comboNode,"expanded","true");},_hideResultList:function(){this._abortQuery();if(this._isShowingNow){dijit.popup.close(this._popupWidget);this._isShowingNow=false;dijit.setWaiState(this.comboNode,"expanded","false");dijit.removeWaiState(this.focusNode,"activedescendant");}},_setBlurValue:function(){var _323=this.get("displayedValue");var pw=this._popupWidget;if(pw&&(_323==pw._messages["previousMessage"]||_323==pw._messages["nextMessage"])){this._setValueAttr(this._lastValueReported,true);}else{if(typeof this.item=="undefined"){this.item=null;this.set("displayedValue",_323);}else{if(this.value!=this._lastValueReported){dijit.form._FormValueWidget.prototype._setValueAttr.call(this,this.value,true);}this._refreshState();}}},_onBlur:function(){this._hideResultList();this.inherited(arguments);},_setItemAttr:function(item,_324,_325){if(!_325){_325=this.labelFunc(item,this.store);}this.value=this._getValueField()!=this.searchAttr?this.store.getIdentity(item):_325;this.item=item;dijit.form.ComboBox.superclass._setValueAttr.call(this,this.value,_324,_325);},_announceOption:function(node){if(!node){return;}var _326;if(node==this._popupWidget.nextButton||node==this._popupWidget.previousButton){_326=node.innerHTML;this.item=undefined;this.value="";}else{_326=this.labelFunc(node.item,this.store);this.set("item",node.item,false,_326);}this.focusNode.value=this.focusNode.value.substring(0,this._lastInput.length);dijit.setWaiState(this.focusNode,"activedescendant",dojo.attr(node,"id"));this._autoCompleteText(_326);},_selectOption:function(evt){if(evt){this._announceOption(evt.target);}this._hideResultList();this._setCaretPos(this.focusNode,this.focusNode.value.length);dijit.form._FormValueWidget.prototype._setValueAttr.call(this,this.value,true);},_onArrowMouseDown:function(evt){if(this.disabled||this.readOnly){return;}dojo.stopEvent(evt);this.focus();if(this._isShowingNow){this._hideResultList();}else{this._startSearchAll();}},_startSearchAll:function(){this._startSearch("");},_startSearchFromInput:function(){this._startSearch(this.focusNode.value.replace(/([\\\*\?])/g,"\\$1"));},_getQueryString:function(text){return dojo.string.substitute(this.queryExpr,[text]);},_startSearch:function(key){if(!this._popupWidget){var _327=this.id+"_popup";this._popupWidget=new dijit.form._ComboBoxMenu({onChange:dojo.hitch(this,this._selectOption),id:_327,dir:this.dir});dijit.removeWaiState(this.focusNode,"activedescendant");dijit.setWaiState(this.textbox,"owns",_327);}var _328=dojo.clone(this.query);this._lastInput=key;this._lastQuery=_328[this.searchAttr]=this._getQueryString(key);this.searchTimer=setTimeout(dojo.hitch(this,function(_329,_32a){this.searchTimer=null;var _32b={queryOptions:{ignoreCase:this.ignoreCase,deep:true},query:_329,onBegin:dojo.hitch(this,"_setMaxOptions"),onComplete:dojo.hitch(this,"_openResultList"),onError:function(_32c){_32a._fetchHandle=null;console.error("dijit.form.ComboBox: "+_32c);dojo.hitch(_32a,"_hideResultList")();},start:0,count:this.pageSize};dojo.mixin(_32b,_32a.fetchProperties);this._fetchHandle=_32a.store.fetch(_32b);var _32d=function(_32e,_32f){_32e.start+=_32e.count*_32f;_32e.direction=_32f;this._fetchHandle=this.store.fetch(_32e);};this._nextSearch=this._popupWidget.onPage=dojo.hitch(this,_32d,this._fetchHandle);},_328,this),this.searchDelay);},_setMaxOptions:function(size,_330){this._maxOptions=size;},_getValueField:function(){return this.searchAttr;},compositionend:function(evt){this._onKeyPress({charOrCode:229});},constructor:function(){this.query={};this.fetchProperties={};},postMixInProperties:function(){if(!this.store){var _331=this.srcNodeRef;this.store=new dijit.form._ComboBoxDataStore(_331);if(!("value" in this.params)){var item=this.store.fetchSelectedItem();if(item){var _332=this._getValueField();this.value=_332!=this.searchAttr?this.store.getValue(item,_332):this.labelFunc(item,this.store);}}}this.inherited(arguments);},postCreate:function(){if(!this.hasDownArrow){this.downArrowNode.style.display="none";}var _333=dojo.query("label[for=\""+this.id+"\"]");if(_333.length){_333[0].id=(this.id+"_label");var cn=this.comboNode;dijit.setWaiState(cn,"labelledby",_333[0].id);}this.inherited(arguments);},uninitialize:function(){if(this._popupWidget&&!this._popupWidget._destroyed){this._hideResultList();this._popupWidget.destroy();}this.inherited(arguments);},_getMenuLabelFromItem:function(item){var _334=this.labelAttr?this.store.getValue(item,this.labelAttr):this.labelFunc(item,this.store);var _335=this.labelType;if(this.highlightMatch!="none"&&this.labelType=="text"&&this._lastInput){_334=this.doHighlight(_334,this._escapeHtml(this._lastInput));_335="html";}return {html:_335=="html",label:_334};},doHighlight:function(_336,find){var _337="i"+(this.highlightMatch=="all"?"g":"");var _338=this._escapeHtml(_336);find=dojo.regexp.escapeString(find);var ret=_338.replace(new RegExp("(^|\\s)("+find+")",_337),"$1<span class=\"dijitComboBoxHighlightMatch\">$2</span>");return ret;},_escapeHtml:function(str){str=String(str).replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;").replace(/"/gm,"&quot;");return str;},open:function(){this._isShowingNow=true;return dijit.popup.open({popup:this._popupWidget,around:this.domNode,parent:this});},reset:function(){this.item=null;this.inherited(arguments);},labelFunc:function(item,_339){return _339.getValue(item,this.searchAttr).toString();}});dojo.declare("dijit.form._ComboBoxMenu",[dijit._Widget,dijit._Templated,dijit._CssStateMixin],{templateString:"<ul class='dijitReset dijitMenu' dojoAttachEvent='onmousedown:_onMouseDown,onmouseup:_onMouseUp,onmouseover:_onMouseOver,onmouseout:_onMouseOut' tabIndex='-1' style='overflow: \"auto\"; overflow-x: \"hidden\";'>"+"<li class='dijitMenuItem dijitMenuPreviousButton' dojoAttachPoint='previousButton' waiRole='option'></li>"+"<li class='dijitMenuItem dijitMenuNextButton' dojoAttachPoint='nextButton' waiRole='option'></li>"+"</ul>",_messages:null,baseClass:"dijitComboBoxMenu",postMixInProperties:function(){this._messages=dojo.i18n.getLocalization("dijit.form","ComboBox",this.lang);this.inherited(arguments);},_setValueAttr:function(_33a){this.value=_33a;this.onChange(_33a);},onChange:function(_33b){},onPage:function(_33c){},postCreate:function(){this.previousButton.innerHTML=this._messages["previousMessage"];this.nextButton.innerHTML=this._messages["nextMessage"];this.inherited(arguments);},onClose:function(){this._blurOptionNode();},_createOption:function(item,_33d){var _33e=_33d(item);var _33f=dojo.doc.createElement("li");dijit.setWaiRole(_33f,"option");if(_33e.html){_33f.innerHTML=_33e.label;}else{_33f.appendChild(dojo.doc.createTextNode(_33e.label));}if(_33f.innerHTML==""){_33f.innerHTML="&nbsp;";}_33f.item=item;return _33f;},createOptions:function(_340,_341,_342){this.previousButton.style.display=(_341.start==0)?"none":"";dojo.attr(this.previousButton,"id",this.id+"_prev");dojo.forEach(_340,function(item,i){var _343=this._createOption(item,_342);_343.className="dijitReset dijitMenuItem"+(this.isLeftToRight()?"":" dijitMenuItemRtl");dojo.attr(_343,"id",this.id+i);this.domNode.insertBefore(_343,this.nextButton);},this);var _344=false;if(_341._maxOptions&&_341._maxOptions!=-1){if((_341.start+_341.count)<_341._maxOptions){_344=true;}else{if((_341.start+_341.count)>_341._maxOptions&&_341.count==_340.length){_344=true;}}}else{if(_341.count==_340.length){_344=true;}}this.nextButton.style.display=_344?"":"none";dojo.attr(this.nextButton,"id",this.id+"_next");return this.domNode.childNodes;},clearResultList:function(){while(this.domNode.childNodes.length>2){this.domNode.removeChild(this.domNode.childNodes[this.domNode.childNodes.length-2]);}},_onMouseDown:function(evt){dojo.stopEvent(evt);},_onMouseUp:function(evt){if(evt.target===this.domNode||!this._highlighted_option){return;}else{if(evt.target==this.previousButton){this.onPage(-1);}else{if(evt.target==this.nextButton){this.onPage(1);}else{var tgt=evt.target;while(!tgt.item){tgt=tgt.parentNode;}this._setValueAttr({target:tgt},true);}}}},_onMouseOver:function(evt){if(evt.target===this.domNode){return;}var tgt=evt.target;if(!(tgt==this.previousButton||tgt==this.nextButton)){while(!tgt.item){tgt=tgt.parentNode;}}this._focusOptionNode(tgt);},_onMouseOut:function(evt){if(evt.target===this.domNode){return;}this._blurOptionNode();},_focusOptionNode:function(node){if(this._highlighted_option!=node){this._blurOptionNode();this._highlighted_option=node;dojo.addClass(this._highlighted_option,"dijitMenuItemSelected");}},_blurOptionNode:function(){if(this._highlighted_option){dojo.removeClass(this._highlighted_option,"dijitMenuItemSelected");this._highlighted_option=null;}},_highlightNextOption:function(){if(!this.getHighlightedOption()){var fc=this.domNode.firstChild;this._focusOptionNode(fc.style.display=="none"?fc.nextSibling:fc);}else{var ns=this._highlighted_option.nextSibling;if(ns&&ns.style.display!="none"){this._focusOptionNode(ns);}else{this.highlightFirstOption();}}dojo.window.scrollIntoView(this._highlighted_option);},highlightFirstOption:function(){var _345=this.domNode.firstChild;var _346=_345.nextSibling;this._focusOptionNode(_346.style.display=="none"?_345:_346);dojo.window.scrollIntoView(this._highlighted_option);},highlightLastOption:function(){this._focusOptionNode(this.domNode.lastChild.previousSibling);dojo.window.scrollIntoView(this._highlighted_option);},_highlightPrevOption:function(){if(!this.getHighlightedOption()){var lc=this.domNode.lastChild;this._focusOptionNode(lc.style.display=="none"?lc.previousSibling:lc);}else{var ps=this._highlighted_option.previousSibling;if(ps&&ps.style.display!="none"){this._focusOptionNode(ps);}else{this.highlightLastOption();}}dojo.window.scrollIntoView(this._highlighted_option);},_page:function(up){var _347=0;var _348=this.domNode.scrollTop;var _349=dojo.style(this.domNode,"height");if(!this.getHighlightedOption()){this._highlightNextOption();}while(_347<_349){if(up){if(!this.getHighlightedOption().previousSibling||this._highlighted_option.previousSibling.style.display=="none"){break;}this._highlightPrevOption();}else{if(!this.getHighlightedOption().nextSibling||this._highlighted_option.nextSibling.style.display=="none"){break;}this._highlightNextOption();}var _34a=this.domNode.scrollTop;_347+=(_34a-_348)*(up?-1:1);_348=_34a;}},pageUp:function(){this._page(true);},pageDown:function(){this._page(false);},getHighlightedOption:function(){var ho=this._highlighted_option;return (ho&&ho.parentNode)?ho:null;},handleKey:function(key){switch(key){case dojo.keys.DOWN_ARROW:this._highlightNextOption();break;case dojo.keys.PAGE_DOWN:this.pageDown();break;case dojo.keys.UP_ARROW:this._highlightPrevOption();break;case dojo.keys.PAGE_UP:this.pageUp();break;}}});dojo.declare("dijit.form.ComboBox",[dijit.form.ValidationTextBox,dijit.form.ComboBoxMixin],{_setValueAttr:function(_34b,_34c,_34d){this.item=null;if(!_34b){_34b="";}dijit.form.ValidationTextBox.prototype._setValueAttr.call(this,_34b,_34c,_34d);}});dojo.declare("dijit.form._ComboBoxDataStore",null,{constructor:function(root){this.root=root;if(root.tagName!="SELECT"&&root.firstChild){root=dojo.query("select",root);if(root.length>0){root=root[0];}else{this.root.innerHTML="<SELECT>"+this.root.innerHTML+"</SELECT>";root=this.root.firstChild;}this.root=root;}dojo.query("> option",root).forEach(function(node){node.innerHTML=dojo.trim(node.innerHTML);});},getValue:function(item,_34e,_34f){return (_34e=="value")?item.value:(item.innerText||item.textContent||"");},isItemLoaded:function(_350){return true;},getFeatures:function(){return {"dojo.data.api.Read":true,"dojo.data.api.Identity":true};},_fetchItems:function(args,_351,_352){if(!args.query){args.query={};}if(!args.query.name){args.query.name="";}if(!args.queryOptions){args.queryOptions={};}var _353=dojo.data.util.filter.patternToRegExp(args.query.name,args.queryOptions.ignoreCase),_354=dojo.query("> option",this.root).filter(function(_355){return (_355.innerText||_355.textContent||"").match(_353);});if(args.sort){_354.sort(dojo.data.util.sorter.createSortFunction(args.sort,this));}_351(_354,args);},close:function(_356){return;},getLabel:function(item){return item.innerHTML;},getIdentity:function(item){return dojo.attr(item,"value");},fetchItemByIdentity:function(args){var item=dojo.query("> option[value='"+args.identity+"']",this.root)[0];args.onItem(item);},fetchSelectedItem:function(){var root=this.root,si=root.selectedIndex;return typeof si=="number"?dojo.query("> option:nth-child("+(si!=-1?si+1:1)+")",root)[0]:null;}});dojo.extend(dijit.form._ComboBoxDataStore,dojo.data.util.simpleFetch);}if(!dojo._hasResource["dijit.form.FilteringSelect"]){dojo._hasResource["dijit.form.FilteringSelect"]=true;dojo.provide("dijit.form.FilteringSelect");dojo.declare("dijit.form.FilteringSelect",[dijit.form.MappedTextBox,dijit.form.ComboBoxMixin],{_isvalid:true,required:true,_lastDisplayedValue:"",isValid:function(){return this._isvalid||(!this.required&&this.get("displayedValue")=="");},_refreshState:function(){if(!this.searchTimer){this.inherited(arguments);}},_callbackSetLabel:function(_357,_358,_359){if((_358&&_358.query[this.searchAttr]!=this._lastQuery)||(!_358&&_357.length&&this.store.getIdentity(_357[0])!=this._lastQuery)){return;}if(!_357.length){this.valueNode.value="";dijit.form.TextBox.superclass._setValueAttr.call(this,"",_359||(_359===undefined&&!this._focused));this._isvalid=false;this.validate(this._focused);this.item=null;}else{this.set("item",_357[0],_359);}},_openResultList:function(_35a,_35b){if(_35b.query[this.searchAttr]!=this._lastQuery){return;}if(this.item===undefined){this._isvalid=_35a.length!=0||this._maxOptions!=0;this.validate(true);}dijit.form.ComboBoxMixin.prototype._openResultList.apply(this,arguments);},_getValueAttr:function(){return this.valueNode.value;},_getValueField:function(){return "value";},_setValueAttr:function(_35c,_35d){if(!this._onChangeActive){_35d=null;}this._lastQuery=_35c;if(_35c===null||_35c===""){this._setDisplayedValueAttr("",_35d);return;}var self=this;this.store.fetchItemByIdentity({identity:_35c,onItem:function(item){self._callbackSetLabel(item?[item]:[],undefined,_35d);}});},_setItemAttr:function(item,_35e,_35f){this._isvalid=true;this.inherited(arguments);this.valueNode.value=this.value;this._lastDisplayedValue=this.textbox.value;},_getDisplayQueryString:function(text){return text.replace(/([\\\*\?])/g,"\\$1");},_setDisplayedValueAttr:function(_360,_361){if(!this._created){_361=false;}if(this.store){this._hideResultList();var _362=dojo.clone(this.query);this._lastQuery=_362[this.searchAttr]=this._getDisplayQueryString(_360);this.textbox.value=_360;this._lastDisplayedValue=_360;var _363=this;var _364={query:_362,queryOptions:{ignoreCase:this.ignoreCase,deep:true},onComplete:function(_365,_366){_363._fetchHandle=null;dojo.hitch(_363,"_callbackSetLabel")(_365,_366,_361);},onError:function(_367){_363._fetchHandle=null;console.error("dijit.form.FilteringSelect: "+_367);dojo.hitch(_363,"_callbackSetLabel")([],undefined,false);}};dojo.mixin(_364,this.fetchProperties);this._fetchHandle=this.store.fetch(_364);}},postMixInProperties:function(){this.inherited(arguments);this._isvalid=!this.required;},undo:function(){this.set("displayedValue",this._lastDisplayedValue);}});}if(!dojo._hasResource["dijit.form.Form"]){dojo._hasResource["dijit.form.Form"]=true;dojo.provide("dijit.form.Form");dojo.declare("dijit.form.Form",[dijit._Widget,dijit._Templated,dijit.form._FormMixin],{name:"",action:"",method:"",encType:"","accept-charset":"",accept:"",target:"",templateString:"<form dojoAttachPoint='containerNode' dojoAttachEvent='onreset:_onReset,onsubmit:_onSubmit' ${!nameAttrSetting}></form>",attributeMap:dojo.delegate(dijit._Widget.prototype.attributeMap,{action:"",method:"",encType:"","accept-charset":"",accept:"",target:""}),postMixInProperties:function(){this.nameAttrSetting=this.name?("name='"+this.name+"'"):"";this.inherited(arguments);},execute:function(_368){},onExecute:function(){},_setEncTypeAttr:function(_369){this.encType=_369;dojo.attr(this.domNode,"encType",_369);if(dojo.isIE){this.domNode.encoding=_369;}},postCreate:function(){if(dojo.isIE&&this.srcNodeRef&&this.srcNodeRef.attributes){var item=this.srcNodeRef.attributes.getNamedItem("encType");if(item&&!item.specified&&(typeof item.value=="string")){this.set("encType",item.value);}}this.inherited(arguments);},reset:function(e){var faux={returnValue:true,preventDefault:function(){this.returnValue=false;},stopPropagation:function(){},currentTarget:e?e.target:this.domNode,target:e?e.target:this.domNode};if(!(this.onReset(faux)===false)&&faux.returnValue){this.inherited(arguments,[]);}},onReset:function(e){return true;},_onReset:function(e){this.reset(e);dojo.stopEvent(e);return false;},_onSubmit:function(e){var fp=dijit.form.Form.prototype;if(this.execute!=fp.execute||this.onExecute!=fp.onExecute){dojo.deprecated("dijit.form.Form:execute()/onExecute() are deprecated. Use onSubmit() instead.","","2.0");this.onExecute();this.execute(this.getValues());}if(this.onSubmit(e)===false){dojo.stopEvent(e);}},onSubmit:function(e){return this.isValid();},submit:function(){if(!(this.onSubmit()===false)){this.containerNode.submit();}}});}if(!dojo._hasResource["dijit.form.RadioButton"]){dojo._hasResource["dijit.form.RadioButton"]=true;dojo.provide("dijit.form.RadioButton");}if(!dojo._hasResource["dijit.form._FormSelectWidget"]){dojo._hasResource["dijit.form._FormSelectWidget"]=true;dojo.provide("dijit.form._FormSelectWidget");dojo.declare("dijit.form._FormSelectWidget",dijit.form._FormValueWidget,{multiple:false,options:null,store:null,query:null,queryOptions:null,onFetch:null,sortByLabel:true,loadChildrenOnOpen:false,getOptions:function(_36a){var _36b=_36a,opts=this.options||[],l=opts.length;if(_36b===undefined){return opts;}if(dojo.isArray(_36b)){return dojo.map(_36b,"return this.getOptions(item);",this);}if(dojo.isObject(_36a)){if(!dojo.some(this.options,function(o,idx){if(o===_36b||(o.value&&o.value===_36b.value)){_36b=idx;return true;}return false;})){_36b=-1;}}if(typeof _36b=="string"){for(var i=0;i<l;i++){if(opts[i].value===_36b){_36b=i;break;}}}if(typeof _36b=="number"&&_36b>=0&&_36b<l){return this.options[_36b];}return null;},addOption:function(_36c){if(!dojo.isArray(_36c)){_36c=[_36c];}dojo.forEach(_36c,function(i){if(i&&dojo.isObject(i)){this.options.push(i);}},this);this._loadChildren();},removeOption:function(_36d){if(!dojo.isArray(_36d)){_36d=[_36d];}var _36e=this.getOptions(_36d);dojo.forEach(_36e,function(i){if(i){this.options=dojo.filter(this.options,function(node,idx){return (node.value!==i.value);});this._removeOptionItem(i);}},this);this._loadChildren();},updateOption:function(_36f){if(!dojo.isArray(_36f)){_36f=[_36f];}dojo.forEach(_36f,function(i){var _370=this.getOptions(i),k;if(_370){for(k in i){_370[k]=i[k];}}},this);this._loadChildren();},setStore:function(_371,_372,_373){var _374=this.store;_373=_373||{};if(_374!==_371){dojo.forEach(this._notifyConnections||[],dojo.disconnect);delete this._notifyConnections;if(_371&&_371.getFeatures()["dojo.data.api.Notification"]){this._notifyConnections=[dojo.connect(_371,"onNew",this,"_onNewItem"),dojo.connect(_371,"onDelete",this,"_onDeleteItem"),dojo.connect(_371,"onSet",this,"_onSetItem")];}this.store=_371;}this._onChangeActive=false;if(this.options&&this.options.length){this.removeOption(this.options);}if(_371){var cb=function(_375){if(this.sortByLabel&&!_373.sort&&_375.length){_375.sort(dojo.data.util.sorter.createSortFunction([{attribute:_371.getLabelAttributes(_375[0])[0]}],_371));}if(_373.onFetch){_375=_373.onFetch(_375);}dojo.forEach(_375,function(i){this._addOptionForItem(i);},this);this._loadingStore=false;this.set("value",(("_pendingValue" in this)?this._pendingValue:_372));delete this._pendingValue;if(!this.loadChildrenOnOpen){this._loadChildren();}else{this._pseudoLoadChildren(_375);}this._fetchedWith=opts;this._lastValueReported=this.multiple?[]:null;this._onChangeActive=true;this.onSetStore();this._handleOnChange(this.value);};var opts=dojo.mixin({onComplete:cb,scope:this},_373);this._loadingStore=true;_371.fetch(opts);}else{delete this._fetchedWith;}return _374;},_setValueAttr:function(_376,_377){if(this._loadingStore){this._pendingValue=_376;return;}var opts=this.getOptions()||[];if(!dojo.isArray(_376)){_376=[_376];}dojo.forEach(_376,function(i,idx){if(!dojo.isObject(i)){i=i+"";}if(typeof i==="string"){_376[idx]=dojo.filter(opts,function(node){return node.value===i;})[0]||{value:"",label:""};}},this);_376=dojo.filter(_376,function(i){return i&&i.value;});if(!this.multiple&&(!_376[0]||!_376[0].value)&&opts.length){_376[0]=opts[0];}dojo.forEach(opts,function(i){i.selected=dojo.some(_376,function(v){return v.value===i.value;});});var val=dojo.map(_376,function(i){return i.value;}),disp=dojo.map(_376,function(i){return i.label;});this.value=this.multiple?val:val[0];this._setDisplay(this.multiple?disp:disp[0]);this._updateSelection();this._handleOnChange(this.value,_377);},_getDisplayedValueAttr:function(){var val=this.get("value");if(!dojo.isArray(val)){val=[val];}var ret=dojo.map(this.getOptions(val),function(v){if(v&&"label" in v){return v.label;}else{if(v){return v.value;}}return null;},this);return this.multiple?ret:ret[0];},_getValueDeprecated:false,getValue:function(){return this._lastValue;},undo:function(){this._setValueAttr(this._lastValueReported,false);},_loadChildren:function(){if(this._loadingStore){return;}dojo.forEach(this._getChildren(),function(_378){_378.destroyRecursive();});dojo.forEach(this.options,this._addOptionItem,this);this._updateSelection();},_updateSelection:function(){this.value=this._getValueFromOpts();var val=this.value;if(!dojo.isArray(val)){val=[val];}if(val&&val[0]){dojo.forEach(this._getChildren(),function(_379){var _37a=dojo.some(val,function(v){return _379.option&&(v===_379.option.value);});dojo.toggleClass(_379.domNode,this.baseClass+"SelectedOption",_37a);dijit.setWaiState(_379.domNode,"selected",_37a);},this);}this._handleOnChange(this.value);},_getValueFromOpts:function(){var opts=this.getOptions()||[];if(!this.multiple&&opts.length){var opt=dojo.filter(opts,function(i){return i.selected;})[0];if(opt&&opt.value){return opt.value;}else{opts[0].selected=true;return opts[0].value;}}else{if(this.multiple){return dojo.map(dojo.filter(opts,function(i){return i.selected;}),function(i){return i.value;})||[];}}return "";},_onNewItem:function(item,_37b){if(!_37b||!_37b.parent){this._addOptionForItem(item);}},_onDeleteItem:function(item){var _37c=this.store;this.removeOption(_37c.getIdentity(item));},_onSetItem:function(item){this.updateOption(this._getOptionObjForItem(item));},_getOptionObjForItem:function(item){var _37d=this.store,_37e=_37d.getLabel(item),_37f=(_37e?_37d.getIdentity(item):null);return {value:_37f,label:_37e,item:item};},_addOptionForItem:function(item){var _380=this.store;if(!_380.isItemLoaded(item)){_380.loadItem({item:item,onComplete:function(i){this._addOptionForItem(item);},scope:this});return;}var _381=this._getOptionObjForItem(item);this.addOption(_381);},constructor:function(_382){this._oValue=(_382||{}).value||null;},_fillContent:function(){var opts=this.options;if(!opts){opts=this.options=this.srcNodeRef?dojo.query(">",this.srcNodeRef).map(function(node){if(node.getAttribute("type")==="separator"){return {value:"",label:"",selected:false,disabled:false};}return {value:node.getAttribute("value"),label:String(node.innerHTML),selected:node.getAttribute("selected")||false,disabled:node.getAttribute("disabled")||false};},this):[];}if(!this.value){this.value=this._getValueFromOpts();}else{if(this.multiple&&typeof this.value=="string"){this.value=this.value.split(",");}}},postCreate:function(){dojo.setSelectable(this.focusNode,false);this.inherited(arguments);this.connect(this,"onChange","_updateSelection");this.connect(this,"startup","_loadChildren");this._setValueAttr(this.value,null);},startup:function(){this.inherited(arguments);var _383=this.store,_384={};dojo.forEach(["query","queryOptions","onFetch"],function(i){if(this[i]){_384[i]=this[i];}delete this[i];},this);if(_383&&_383.getFeatures()["dojo.data.api.Identity"]){this.store=null;this.setStore(_383,this._oValue,_384);}},destroy:function(){dojo.forEach(this._notifyConnections||[],dojo.disconnect);this.inherited(arguments);},_addOptionItem:function(_385){},_removeOptionItem:function(_386){},_setDisplay:function(_387){},_getChildren:function(){return [];},_getSelectedOptionsAttr:function(){return this.getOptions(this.get("value"));},_pseudoLoadChildren:function(_388){},onSetStore:function(){}});}if(!dojo._hasResource["dijit._KeyNavContainer"]){dojo._hasResource["dijit._KeyNavContainer"]=true;dojo.provide("dijit._KeyNavContainer");dojo.declare("dijit._KeyNavContainer",dijit._Container,{tabIndex:"0",_keyNavCodes:{},connectKeyNavHandlers:function(_389,_38a){var _38b=(this._keyNavCodes={});var prev=dojo.hitch(this,this.focusPrev);var next=dojo.hitch(this,this.focusNext);dojo.forEach(_389,function(code){_38b[code]=prev;});dojo.forEach(_38a,function(code){_38b[code]=next;});this.connect(this.domNode,"onkeypress","_onContainerKeypress");this.connect(this.domNode,"onfocus","_onContainerFocus");},startupKeyNavChildren:function(){dojo.forEach(this.getChildren(),dojo.hitch(this,"_startupChild"));},addChild:function(_38c,_38d){dijit._KeyNavContainer.superclass.addChild.apply(this,arguments);this._startupChild(_38c);},focus:function(){this.focusFirstChild();},focusFirstChild:function(){var _38e=this._getFirstFocusableChild();if(_38e){this.focusChild(_38e);}},focusNext:function(){var _38f=this._getNextFocusableChild(this.focusedChild,1);this.focusChild(_38f);},focusPrev:function(){var _390=this._getNextFocusableChild(this.focusedChild,-1);this.focusChild(_390,true);},focusChild:function(_391,last){if(this.focusedChild&&_391!==this.focusedChild){this._onChildBlur(this.focusedChild);}_391.focus(last?"end":"start");this.focusedChild=_391;},_startupChild:function(_392){_392.set("tabIndex","-1");this.connect(_392,"_onFocus",function(){_392.set("tabIndex",this.tabIndex);});this.connect(_392,"_onBlur",function(){_392.set("tabIndex","-1");});},_onContainerFocus:function(evt){if(evt.target!==this.domNode){return;}this.focusFirstChild();dojo.attr(this.domNode,"tabIndex","-1");},_onBlur:function(evt){if(this.tabIndex){dojo.attr(this.domNode,"tabIndex",this.tabIndex);}this.inherited(arguments);},_onContainerKeypress:function(evt){if(evt.ctrlKey||evt.altKey){return;}var func=this._keyNavCodes[evt.charOrCode];if(func){func();dojo.stopEvent(evt);}},_onChildBlur:function(_393){},_getFirstFocusableChild:function(){return this._getNextFocusableChild(null,1);},_getNextFocusableChild:function(_394,dir){if(_394){_394=this._getSiblingOfChild(_394,dir);}var _395=this.getChildren();for(var i=0;i<_395.length;i++){if(!_394){_394=_395[(dir>0)?0:(_395.length-1)];}if(_394.isFocusable()){return _394;}_394=this._getSiblingOfChild(_394,dir);}return null;}});}if(!dojo._hasResource["dijit.MenuItem"]){dojo._hasResource["dijit.MenuItem"]=true;dojo.provide("dijit.MenuItem");dojo.declare("dijit.MenuItem",[dijit._Widget,dijit._Templated,dijit._Contained,dijit._CssStateMixin],{templateString:dojo.cache("dijit","templates/MenuItem.html","<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" waiRole=\"menuitem\" tabIndex=\"-1\"\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" waiRole=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" waiRole=\"presentation\">\n\t\t<div dojoAttachPoint=\"arrowWrapper\" style=\"visibility: hidden\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuExpand\"/>\n\t\t\t<span class=\"dijitMenuExpandA11y\">+</span>\n\t\t</div>\n\t</td>\n</tr>\n"),attributeMap:dojo.delegate(dijit._Widget.prototype.attributeMap,{label:{node:"containerNode",type:"innerHTML"},iconClass:{node:"iconNode",type:"class"}}),baseClass:"dijitMenuItem",label:"",iconClass:"",accelKey:"",disabled:false,_fillContent:function(_396){if(_396&&!("label" in this.params)){this.set("label",_396.innerHTML);}},postCreate:function(){this.inherited(arguments);dojo.setSelectable(this.domNode,false);var _397=this.id+"_text";dojo.attr(this.containerNode,"id",_397);if(this.accelKeyNode){dojo.attr(this.accelKeyNode,"id",this.id+"_accel");_397+=" "+this.id+"_accel";}dijit.setWaiState(this.domNode,"labelledby",_397);},_onHover:function(){this.getParent().onItemHover(this);},_onUnhover:function(){this.getParent().onItemUnhover(this);this._hovering=false;this._setStateClass();},_onClick:function(evt){this.getParent().onItemClick(this,evt);dojo.stopEvent(evt);},onClick:function(evt){},focus:function(){try{if(dojo.isIE==8){this.containerNode.focus();}dijit.focus(this.focusNode);}catch(e){}},_onFocus:function(){this._setSelected(true);this.getParent()._onItemFocus(this);this.inherited(arguments);},_setSelected:function(_398){dojo.toggleClass(this.domNode,"dijitMenuItemSelected",_398);},setLabel:function(_399){dojo.deprecated("dijit.MenuItem.setLabel() is deprecated. Use set('label', ...) instead.","","2.0");this.set("label",_399);},setDisabled:function(_39a){dojo.deprecated("dijit.Menu.setDisabled() is deprecated. Use set('disabled', bool) instead.","","2.0");this.set("disabled",_39a);},_setDisabledAttr:function(_39b){this.disabled=_39b;dijit.setWaiState(this.focusNode,"disabled",_39b?"true":"false");},_setAccelKeyAttr:function(_39c){this.accelKey=_39c;this.accelKeyNode.style.display=_39c?"":"none";this.accelKeyNode.innerHTML=_39c;dojo.attr(this.containerNode,"colSpan",_39c?"1":"2");}});}if(!dojo._hasResource["dijit.PopupMenuItem"]){dojo._hasResource["dijit.PopupMenuItem"]=true;dojo.provide("dijit.PopupMenuItem");dojo.declare("dijit.PopupMenuItem",dijit.MenuItem,{_fillContent:function(){if(this.srcNodeRef){var _39d=dojo.query("*",this.srcNodeRef);dijit.PopupMenuItem.superclass._fillContent.call(this,_39d[0]);this.dropDownContainer=this.srcNodeRef;}},startup:function(){if(this._started){return;}this.inherited(arguments);if(!this.popup){var node=dojo.query("[widgetId]",this.dropDownContainer)[0];this.popup=dijit.byNode(node);}dojo.body().appendChild(this.popup.domNode);this.popup.startup();this.popup.domNode.style.display="none";if(this.arrowWrapper){dojo.style(this.arrowWrapper,"visibility","");}dijit.setWaiState(this.focusNode,"haspopup","true");},destroyDescendants:function(){if(this.popup){if(!this.popup._destroyed){this.popup.destroyRecursive();}delete this.popup;}this.inherited(arguments);}});}if(!dojo._hasResource["dijit.CheckedMenuItem"]){dojo._hasResource["dijit.CheckedMenuItem"]=true;dojo.provide("dijit.CheckedMenuItem");dojo.declare("dijit.CheckedMenuItem",dijit.MenuItem,{templateString:dojo.cache("dijit","templates/CheckedMenuItem.html","<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" waiRole=\"menuitemcheckbox\" tabIndex=\"-1\"\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" waiRole=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuItemIcon dijitCheckedMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\n\t\t<span class=\"dijitCheckedMenuItemIconChar\">&#10003;</span>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode,labelNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" waiRole=\"presentation\">&nbsp;</td>\n</tr>\n"),checked:false,_setCheckedAttr:function(_39e){dojo.toggleClass(this.domNode,"dijitCheckedMenuItemChecked",_39e);dijit.setWaiState(this.domNode,"checked",_39e);this.checked=_39e;},onChange:function(_39f){},_onClick:function(e){if(!this.disabled){this.set("checked",!this.checked);this.onChange(this.checked);}this.inherited(arguments);}});}if(!dojo._hasResource["dijit.MenuSeparator"]){dojo._hasResource["dijit.MenuSeparator"]=true;dojo.provide("dijit.MenuSeparator");dojo.declare("dijit.MenuSeparator",[dijit._Widget,dijit._Templated,dijit._Contained],{templateString:dojo.cache("dijit","templates/MenuSeparator.html","<tr class=\"dijitMenuSeparator\">\n\t<td class=\"dijitMenuSeparatorIconCell\">\n\t\t<div class=\"dijitMenuSeparatorTop\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n\t<td colspan=\"3\" class=\"dijitMenuSeparatorLabelCell\">\n\t\t<div class=\"dijitMenuSeparatorTop dijitMenuSeparatorLabel\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n</tr>\n"),postCreate:function(){dojo.setSelectable(this.domNode,false);},isFocusable:function(){return false;}});}if(!dojo._hasResource["dijit.Menu"]){dojo._hasResource["dijit.Menu"]=true;dojo.provide("dijit.Menu");dojo.declare("dijit._MenuBase",[dijit._Widget,dijit._Templated,dijit._KeyNavContainer],{parentMenu:null,popupDelay:500,startup:function(){if(this._started){return;}dojo.forEach(this.getChildren(),function(_3a0){_3a0.startup();});this.startupKeyNavChildren();this.inherited(arguments);},onExecute:function(){},onCancel:function(_3a1){},_moveToPopup:function(evt){if(this.focusedChild&&this.focusedChild.popup&&!this.focusedChild.disabled){this.focusedChild._onClick(evt);}else{var _3a2=this._getTopMenu();if(_3a2&&_3a2._isMenuBar){_3a2.focusNext();}}},_onPopupHover:function(evt){if(this.currentPopup&&this.currentPopup._pendingClose_timer){var _3a3=this.currentPopup.parentMenu;if(_3a3.focusedChild){_3a3.focusedChild._setSelected(false);}_3a3.focusedChild=this.currentPopup.from_item;_3a3.focusedChild._setSelected(true);this._stopPendingCloseTimer(this.currentPopup);}},onItemHover:function(item){if(this.isActive){this.focusChild(item);if(this.focusedChild.popup&&!this.focusedChild.disabled&&!this.hover_timer){this.hover_timer=setTimeout(dojo.hitch(this,"_openPopup"),this.popupDelay);}}if(this.focusedChild){this.focusChild(item);}this._hoveredChild=item;},_onChildBlur:function(item){this._stopPopupTimer();item._setSelected(false);var _3a4=item.popup;if(_3a4){this._stopPendingCloseTimer(_3a4);_3a4._pendingClose_timer=setTimeout(function(){_3a4._pendingClose_timer=null;if(_3a4.parentMenu){_3a4.parentMenu.currentPopup=null;}dijit.popup.close(_3a4);},this.popupDelay);}},onItemUnhover:function(item){if(this.isActive){this._stopPopupTimer();}if(this._hoveredChild==item){this._hoveredChild=null;}},_stopPopupTimer:function(){if(this.hover_timer){clearTimeout(this.hover_timer);this.hover_timer=null;}},_stopPendingCloseTimer:function(_3a5){if(_3a5._pendingClose_timer){clearTimeout(_3a5._pendingClose_timer);_3a5._pendingClose_timer=null;}},_stopFocusTimer:function(){if(this._focus_timer){clearTimeout(this._focus_timer);this._focus_timer=null;}},_getTopMenu:function(){for(var top=this;top.parentMenu;top=top.parentMenu){}return top;},onItemClick:function(item,evt){if(typeof this.isShowingNow=="undefined"){this._markActive();}this.focusChild(item);if(item.disabled){return false;}if(item.popup){this._openPopup();}else{this.onExecute();item.onClick(evt);}},_openPopup:function(){this._stopPopupTimer();var _3a6=this.focusedChild;if(!_3a6){return;}var _3a7=_3a6.popup;if(_3a7.isShowingNow){return;}if(this.currentPopup){this._stopPendingCloseTimer(this.currentPopup);dijit.popup.close(this.currentPopup);}_3a7.parentMenu=this;_3a7.from_item=_3a6;var self=this;dijit.popup.open({parent:this,popup:_3a7,around:_3a6.domNode,orient:this._orient||(this.isLeftToRight()?{"TR":"TL","TL":"TR","BR":"BL","BL":"BR"}:{"TL":"TR","TR":"TL","BL":"BR","BR":"BL"}),onCancel:function(){self.focusChild(_3a6);self._cleanUp();_3a6._setSelected(true);self.focusedChild=_3a6;},onExecute:dojo.hitch(this,"_cleanUp")});this.currentPopup=_3a7;_3a7.connect(_3a7.domNode,"onmouseenter",dojo.hitch(self,"_onPopupHover"));if(_3a7.focus){_3a7._focus_timer=setTimeout(dojo.hitch(_3a7,function(){this._focus_timer=null;this.focus();}),0);}},_markActive:function(){this.isActive=true;dojo.addClass(this.domNode,"dijitMenuActive");dojo.removeClass(this.domNode,"dijitMenuPassive");},onOpen:function(e){this.isShowingNow=true;this._markActive();},_markInactive:function(){this.isActive=false;dojo.removeClass(this.domNode,"dijitMenuActive");dojo.addClass(this.domNode,"dijitMenuPassive");},onClose:function(){this._stopFocusTimer();this._markInactive();this.isShowingNow=false;this.parentMenu=null;},_closeChild:function(){this._stopPopupTimer();if(this.focusedChild){this.focusedChild._setSelected(false);this.focusedChild._onUnhover();this.focusedChild=null;}if(this.currentPopup){dijit.popup.close(this.currentPopup);this.currentPopup=null;}},_onItemFocus:function(item){if(this._hoveredChild&&this._hoveredChild!=item){this._hoveredChild._onUnhover();}},_onBlur:function(){this._cleanUp();this.inherited(arguments);},_cleanUp:function(){this._closeChild();if(typeof this.isShowingNow=="undefined"){this._markInactive();}}});dojo.declare("dijit.Menu",dijit._MenuBase,{constructor:function(){this._bindings=[];},templateString:dojo.cache("dijit","templates/Menu.html","<table class=\"dijit dijitMenu dijitMenuPassive dijitReset dijitMenuTable\" waiRole=\"menu\" tabIndex=\"${tabIndex}\" dojoAttachEvent=\"onkeypress:_onKeyPress\" cellspacing=0>\n\t<tbody class=\"dijitReset\" dojoAttachPoint=\"containerNode\"></tbody>\n</table>\n"),baseClass:"dijitMenu",targetNodeIds:[],contextMenuForWindow:false,leftClickToOpen:false,refocus:true,postCreate:function(){if(this.contextMenuForWindow){this.bindDomNode(dojo.body());}else{dojo.forEach(this.targetNodeIds,this.bindDomNode,this);}var k=dojo.keys,l=this.isLeftToRight();this._openSubMenuKey=l?k.RIGHT_ARROW:k.LEFT_ARROW;this._closeSubMenuKey=l?k.LEFT_ARROW:k.RIGHT_ARROW;this.connectKeyNavHandlers([k.UP_ARROW],[k.DOWN_ARROW]);},_onKeyPress:function(evt){if(evt.ctrlKey||evt.altKey){return;}switch(evt.charOrCode){case this._openSubMenuKey:this._moveToPopup(evt);dojo.stopEvent(evt);break;case this._closeSubMenuKey:if(this.parentMenu){if(this.parentMenu._isMenuBar){this.parentMenu.focusPrev();}else{this.onCancel(false);}}else{dojo.stopEvent(evt);}break;}},_iframeContentWindow:function(_3a8){var win=dojo.window.get(this._iframeContentDocument(_3a8))||this._iframeContentDocument(_3a8)["__parent__"]||(_3a8.name&&dojo.doc.frames[_3a8.name])||null;return win;},_iframeContentDocument:function(_3a9){var doc=_3a9.contentDocument||(_3a9.contentWindow&&_3a9.contentWindow.document)||(_3a9.name&&dojo.doc.frames[_3a9.name]&&dojo.doc.frames[_3a9.name].document)||null;return doc;},bindDomNode:function(node){node=dojo.byId(node);var cn;if(node.tagName.toLowerCase()=="iframe"){var _3aa=node,win=this._iframeContentWindow(_3aa);cn=dojo.withGlobal(win,dojo.body);}else{cn=(node==dojo.body()?dojo.doc.documentElement:node);}var _3ab={node:node,iframe:_3aa};dojo.attr(node,"_dijitMenu"+this.id,this._bindings.push(_3ab));var _3ac=dojo.hitch(this,function(cn){return [dojo.connect(cn,this.leftClickToOpen?"onclick":"oncontextmenu",this,function(evt){dojo.stopEvent(evt);this._scheduleOpen(evt.target,_3aa,{x:evt.pageX,y:evt.pageY});}),dojo.connect(cn,"onkeydown",this,function(evt){if(evt.shiftKey&&evt.keyCode==dojo.keys.F10){dojo.stopEvent(evt);this._scheduleOpen(evt.target,_3aa);}})];});_3ab.connects=cn?_3ac(cn):[];if(_3aa){_3ab.onloadHandler=dojo.hitch(this,function(){var win=this._iframeContentWindow(_3aa);cn=dojo.withGlobal(win,dojo.body);_3ab.connects=_3ac(cn);});if(_3aa.addEventListener){_3aa.addEventListener("load",_3ab.onloadHandler,false);}else{_3aa.attachEvent("onload",_3ab.onloadHandler);}}},unBindDomNode:function(_3ad){var node;try{node=dojo.byId(_3ad);}catch(e){return;}var _3ae="_dijitMenu"+this.id;if(node&&dojo.hasAttr(node,_3ae)){var bid=dojo.attr(node,_3ae)-1,b=this._bindings[bid];dojo.forEach(b.connects,dojo.disconnect);var _3af=b.iframe;if(_3af){if(_3af.removeEventListener){_3af.removeEventListener("load",b.onloadHandler,false);}else{_3af.detachEvent("onload",b.onloadHandler);}}dojo.removeAttr(node,_3ae);delete this._bindings[bid];}},_scheduleOpen:function(_3b0,_3b1,_3b2){if(!this._openTimer){this._openTimer=setTimeout(dojo.hitch(this,function(){delete this._openTimer;this._openMyself({target:_3b0,iframe:_3b1,coords:_3b2});}),1);}},_openMyself:function(args){var _3b3=args.target,_3b4=args.iframe,_3b5=args.coords;if(_3b5){if(_3b4){var od=_3b3.ownerDocument,ifc=dojo.position(_3b4,true),win=this._iframeContentWindow(_3b4),_3b6=dojo.withGlobal(win,"_docScroll",dojo);var cs=dojo.getComputedStyle(_3b4),tp=dojo._toPixelValue,left=(dojo.isIE&&dojo.isQuirks?0:tp(_3b4,cs.paddingLeft))+(dojo.isIE&&dojo.isQuirks?tp(_3b4,cs.borderLeftWidth):0),top=(dojo.isIE&&dojo.isQuirks?0:tp(_3b4,cs.paddingTop))+(dojo.isIE&&dojo.isQuirks?tp(_3b4,cs.borderTopWidth):0);_3b5.x+=ifc.x+left-_3b6.x;_3b5.y+=ifc.y+top-_3b6.y;}}else{_3b5=dojo.position(_3b3,true);_3b5.x+=10;_3b5.y+=10;}var self=this;var _3b7=dijit.getFocus(this);function _3b8(){if(self.refocus){dijit.focus(_3b7);}dijit.popup.close(self);};dijit.popup.open({popup:this,x:_3b5.x,y:_3b5.y,onExecute:_3b8,onCancel:_3b8,orient:this.isLeftToRight()?"L":"R"});this.focus();this._onBlur=function(){this.inherited("_onBlur",arguments);dijit.popup.close(this);};},uninitialize:function(){dojo.forEach(this._bindings,function(b){if(b){this.unBindDomNode(b.node);}},this);this.inherited(arguments);}});}if(!dojo._hasResource["dijit.form.Select"]){dojo._hasResource["dijit.form.Select"]=true;dojo.provide("dijit.form.Select");dojo.declare("dijit.form._SelectMenu",dijit.Menu,{buildRendering:function(){this.inherited(arguments);var o=(this.menuTableNode=this.domNode);var n=(this.domNode=dojo.create("div",{style:{overflowX:"hidden",overflowY:"scroll"}}));if(o.parentNode){o.parentNode.replaceChild(n,o);}dojo.removeClass(o,"dijitMenuTable");n.className=o.className+" dijitSelectMenu";o.className="dijitReset dijitMenuTable";dijit.setWaiRole(o,"listbox");dijit.setWaiRole(n,"presentation");n.appendChild(o);},resize:function(mb){if(mb){dojo.marginBox(this.domNode,mb);if("w" in mb){this.menuTableNode.style.width="100%";}}}});dojo.declare("dijit.form.Select",[dijit.form._FormSelectWidget,dijit._HasDropDown],{baseClass:"dijitSelect",templateString:dojo.cache("dijit.form","templates/Select.html","<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tdojoAttachPoint=\"_buttonNode,tableNode,focusNode\" cellspacing='0' cellpadding='0'\n\twaiRole=\"combobox\" waiState=\"haspopup-true\"\n\t><tbody waiRole=\"presentation\"><tr waiRole=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonContents dijitButtonNode\" waiRole=\"presentation\"\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\" dojoAttachPoint=\"containerNode,_popupStateNode\"></span\n\t\t\t><input type=\"hidden\" ${!nameAttrSetting} dojoAttachPoint=\"valueNode\" value=\"${value}\" waiState=\"hidden-true\"\n\t\t/></td><td class=\"dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\t\tdojoAttachPoint=\"titleNode\" waiRole=\"presentation\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" waiRole=\"presentation\">&#9660;</div\n\t\t></td\n\t></tr></tbody\n></table>\n"),attributeMap:dojo.mixin(dojo.clone(dijit.form._FormSelectWidget.prototype.attributeMap),{style:"tableNode"}),required:false,state:"",tooltipPosition:[],emptyLabel:"",_isLoaded:false,_childrenLoaded:false,_fillContent:function(){this.inherited(arguments);if(this.options.length&&!this.value&&this.srcNodeRef){var si=this.srcNodeRef.selectedIndex;this.value=this.options[si!=-1?si:0].value;}this.dropDown=new dijit.form._SelectMenu({id:this.id+"_menu"});dojo.addClass(this.dropDown.domNode,this.baseClass+"Menu");},_getMenuItemForOption:function(_3b9){if(!_3b9.value){return new dijit.MenuSeparator();}else{var _3ba=dojo.hitch(this,"_setValueAttr",_3b9);var item=new dijit.MenuItem({option:_3b9,label:_3b9.label,onClick:_3ba,disabled:_3b9.disabled||false});dijit.setWaiRole(item.focusNode,"listitem");return item;}},_addOptionItem:function(_3bb){if(this.dropDown){this.dropDown.addChild(this._getMenuItemForOption(_3bb));}},_getChildren:function(){if(!this.dropDown){return [];}return this.dropDown.getChildren();},_loadChildren:function(_3bc){if(_3bc===true){if(this.dropDown){delete this.dropDown.focusedChild;}if(this.options.length){this.inherited(arguments);}else{dojo.forEach(this._getChildren(),function(_3bd){_3bd.destroyRecursive();});var item=new dijit.MenuItem({label:"&nbsp;"});this.dropDown.addChild(item);}}else{this._updateSelection();}var len=this.options.length;this._isLoaded=false;this._childrenLoaded=true;if(!this._loadingStore){this._setValueAttr(this.value);}},_setValueAttr:function(_3be){this.inherited(arguments);dojo.attr(this.valueNode,"value",this.get("value"));},_setDisplay:function(_3bf){this.containerNode.innerHTML="<span class=\"dijitReset dijitInline "+this.baseClass+"Label\">"+(_3bf||this.emptyLabel||"&nbsp;")+"</span>";dijit.setWaiState(this.focusNode,"valuetext",(_3bf||this.emptyLabel||"&nbsp;"));},validate:function(_3c0){var _3c1=this.isValid(_3c0);this.state=_3c1?"":"Error";this._setStateClass();dijit.setWaiState(this.focusNode,"invalid",_3c1?"false":"true");var _3c2=_3c1?"":this._missingMsg;if(this._message!==_3c2){this._message=_3c2;dijit.hideTooltip(this.domNode);if(_3c2){dijit.showTooltip(_3c2,this.domNode,this.tooltipPosition,!this.isLeftToRight());}}return _3c1;},isValid:function(_3c3){return (!this.required||!(/^\s*$/.test(this.value)));},reset:function(){this.inherited(arguments);dijit.hideTooltip(this.domNode);this.state="";this._setStateClass();delete this._message;},postMixInProperties:function(){this.inherited(arguments);this._missingMsg=dojo.i18n.getLocalization("dijit.form","validate",this.lang).missingMessage;},postCreate:function(){this.inherited(arguments);if(this.tableNode.style.width){dojo.addClass(this.domNode,this.baseClass+"FixedWidth");}},isLoaded:function(){return this._isLoaded;},loadDropDown:function(_3c4){this._loadChildren(true);this._isLoaded=true;_3c4();},closeDropDown:function(){this.inherited(arguments);if(this.dropDown&&this.dropDown.menuTableNode){this.dropDown.menuTableNode.style.width="";}},uninitialize:function(_3c5){if(this.dropDown&&!this.dropDown._destroyed){this.dropDown.destroyRecursive(_3c5);delete this.dropDown;}this.inherited(arguments);}});}if(!dojo._hasResource["dijit.form.SimpleTextarea"]){dojo._hasResource["dijit.form.SimpleTextarea"]=true;dojo.provide("dijit.form.SimpleTextarea");dojo.declare("dijit.form.SimpleTextarea",dijit.form.TextBox,{baseClass:"dijitTextBox dijitTextArea",attributeMap:dojo.delegate(dijit.form._FormValueWidget.prototype.attributeMap,{rows:"textbox",cols:"textbox"}),rows:"3",cols:"20",templateString:"<textarea ${!nameAttrSetting} dojoAttachPoint='focusNode,containerNode,textbox' autocomplete='off'></textarea>",postMixInProperties:function(){if(!this.value&&this.srcNodeRef){this.value=this.srcNodeRef.value;}this.inherited(arguments);},filter:function(_3c6){if(_3c6){_3c6=_3c6.replace(/\r/g,"");}return this.inherited(arguments);},postCreate:function(){this.inherited(arguments);if(dojo.isIE&&this.cols){dojo.addClass(this.textbox,"dijitTextAreaCols");}},_previousValue:"",_onInput:function(e){if(this.maxLength){var _3c7=parseInt(this.maxLength);var _3c8=this.textbox.value.replace(/\r/g,"");var _3c9=_3c8.length-_3c7;if(_3c9>0){if(e){dojo.stopEvent(e);}var _3ca=this.textbox;if(_3ca.selectionStart){var pos=_3ca.selectionStart;var cr=0;if(dojo.isOpera){cr=(this.textbox.value.substring(0,pos).match(/\r/g)||[]).length;}this.textbox.value=_3c8.substring(0,pos-_3c9-cr)+_3c8.substring(pos-cr);_3ca.setSelectionRange(pos-_3c9,pos-_3c9);}else{if(dojo.doc.selection){_3ca.focus();var _3cb=dojo.doc.selection.createRange();_3cb.moveStart("character",-_3c9);_3cb.text="";_3cb.select();}}}this._previousValue=this.textbox.value;}this.inherited(arguments);}});}if(!dojo._hasResource["dijit.InlineEditBox"]){dojo._hasResource["dijit.InlineEditBox"]=true;dojo.provide("dijit.InlineEditBox");dojo.declare("dijit.InlineEditBox",dijit._Widget,{editing:false,autoSave:true,buttonSave:"",buttonCancel:"",renderAsHtml:false,editor:"dijit.form.TextBox",editorWrapper:"dijit._InlineEditor",editorParams:{},onChange:function(_3cc){},onCancel:function(){},width:"100%",value:"",noValueIndicator:dojo.isIE<=6?"<span style='font-family: wingdings; text-decoration: underline;'>&nbsp;&nbsp;&nbsp;&nbsp;&#x270d;&nbsp;&nbsp;&nbsp;&nbsp;</span>":"<span style='text-decoration: underline;'>&nbsp;&nbsp;&nbsp;&nbsp;&#x270d;&nbsp;&nbsp;&nbsp;&nbsp;</span>",constructor:function(){this.editorParams={};},postMixInProperties:function(){this.inherited(arguments);this.displayNode=this.srcNodeRef;var _3cd={ondijitclick:"_onClick",onmouseover:"_onMouseOver",onmouseout:"_onMouseOut",onfocus:"_onMouseOver",onblur:"_onMouseOut"};for(var name in _3cd){this.connect(this.displayNode,name,_3cd[name]);}dijit.setWaiRole(this.displayNode,"button");if(!this.displayNode.getAttribute("tabIndex")){this.displayNode.setAttribute("tabIndex",0);}if(!this.value&&!("value" in this.params)){this.value=dojo.trim(this.renderAsHtml?this.displayNode.innerHTML:(this.displayNode.innerText||this.displayNode.textContent||""));}if(!this.value){this.displayNode.innerHTML=this.noValueIndicator;}dojo.addClass(this.displayNode,"dijitInlineEditBoxDisplayMode");},setDisabled:function(_3ce){dojo.deprecated("dijit.InlineEditBox.setDisabled() is deprecated. Use set('disabled', bool) instead.","","2.0");this.set("disabled",_3ce);},_setDisabledAttr:function(_3cf){this.disabled=_3cf;dijit.setWaiState(this.domNode,"disabled",_3cf);if(_3cf){this.displayNode.removeAttribute("tabIndex");}else{this.displayNode.setAttribute("tabIndex",0);}dojo.toggleClass(this.displayNode,"dijitInlineEditBoxDisplayModeDisabled",_3cf);},_onMouseOver:function(){if(!this.disabled){dojo.addClass(this.displayNode,"dijitInlineEditBoxDisplayModeHover");}},_onMouseOut:function(){dojo.removeClass(this.displayNode,"dijitInlineEditBoxDisplayModeHover");},_onClick:function(e){if(this.disabled){return;}if(e){dojo.stopEvent(e);}this._onMouseOut();setTimeout(dojo.hitch(this,"edit"),0);},edit:function(){if(this.disabled||this.editing){return;}this.editing=true;this._savedPosition=dojo.style(this.displayNode,"position")||"static";this._savedOpacity=dojo.style(this.displayNode,"opacity")||"1";this._savedTabIndex=dojo.attr(this.displayNode,"tabIndex")||"0";if(this.wrapperWidget){var ew=this.wrapperWidget.editWidget;ew.set("displayedValue" in ew?"displayedValue":"value",this.value);}else{var _3d0=dojo.create("span",null,this.domNode,"before");var ewc=dojo.getObject(this.editorWrapper);this.wrapperWidget=new ewc({value:this.value,buttonSave:this.buttonSave,buttonCancel:this.buttonCancel,dir:this.dir,lang:this.lang,tabIndex:this._savedTabIndex,editor:this.editor,inlineEditBox:this,sourceStyle:dojo.getComputedStyle(this.displayNode),save:dojo.hitch(this,"save"),cancel:dojo.hitch(this,"cancel")},_3d0);}var ww=this.wrapperWidget;if(dojo.isIE){dijit.focus(dijit.getFocus());}dojo.style(this.displayNode,{position:"absolute",opacity:"0",display:"none"});dojo.style(ww.domNode,{position:this._savedPosition,visibility:"visible",opacity:"1"});dojo.attr(this.displayNode,"tabIndex","-1");setTimeout(dojo.hitch(this,function(){ww.focus();ww._resetValue=ww.getValue();}),0);},_onBlur:function(){this.inherited(arguments);if(!this.editing){}},destroy:function(){if(this.wrapperWidget){this.wrapperWidget.destroy();delete this.wrapperWidget;}this.inherited(arguments);},_showText:function(_3d1){var ww=this.wrapperWidget;dojo.style(ww.domNode,{position:"absolute",visibility:"hidden",opacity:"0"});dojo.style(this.displayNode,{position:this._savedPosition,opacity:this._savedOpacity,display:""});dojo.attr(this.displayNode,"tabIndex",this._savedTabIndex);if(_3d1){dijit.focus(this.displayNode);}},save:function(_3d2){if(this.disabled||!this.editing){return;}this.editing=false;var ww=this.wrapperWidget;var _3d3=ww.getValue();this.set("value",_3d3);setTimeout(dojo.hitch(this,"onChange",_3d3),0);this._showText(_3d2);},setValue:function(val){dojo.deprecated("dijit.InlineEditBox.setValue() is deprecated. Use set('value', ...) instead.","","2.0");return this.set("value",val);},_setValueAttr:function(val){this.value=val=dojo.trim(val);if(!this.renderAsHtml){val=val.replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;").replace(/"/gm,"&quot;").replace(/\n/g,"<br>");}this.displayNode.innerHTML=val||this.noValueIndicator;},getValue:function(){dojo.deprecated("dijit.InlineEditBox.getValue() is deprecated. Use get('value') instead.","","2.0");return this.get("value");},cancel:function(_3d4){if(this.disabled||!this.editing){return;}this.editing=false;setTimeout(dojo.hitch(this,"onCancel"),0);this._showText(_3d4);}});dojo.declare("dijit._InlineEditor",[dijit._Widget,dijit._Templated],{templateString:dojo.cache("dijit","templates/InlineEditBox.html","<span dojoAttachPoint=\"editNode\" waiRole=\"presentation\" style=\"position: absolute; visibility:hidden\" class=\"dijitReset dijitInline\"\n\tdojoAttachEvent=\"onkeypress: _onKeyPress\"\n\t><span dojoAttachPoint=\"editorPlaceholder\"></span\n\t><span dojoAttachPoint=\"buttonContainer\"\n\t\t><button class='saveButton' dojoAttachPoint=\"saveButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:save\" label=\"${buttonSave}\"></button\n\t\t><button class='cancelButton' dojoAttachPoint=\"cancelButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:cancel\" label=\"${buttonCancel}\"></button\n\t></span\n></span>\n"),widgetsInTemplate:true,postMixInProperties:function(){this.inherited(arguments);this.messages=dojo.i18n.getLocalization("dijit","common",this.lang);dojo.forEach(["buttonSave","buttonCancel"],function(prop){if(!this[prop]){this[prop]=this.messages[prop];}},this);},postCreate:function(){var cls=dojo.getObject(this.editor);var _3d5=this.sourceStyle,_3d6="line-height:"+_3d5.lineHeight+";",_3d7=dojo.getComputedStyle(this.domNode);dojo.forEach(["Weight","Family","Size","Style"],function(prop){var _3d8=_3d5["font"+prop],_3d9=_3d7["font"+prop];if(_3d9!=_3d8){_3d6+="font-"+prop+":"+_3d5["font"+prop]+";";}},this);dojo.forEach(["marginTop","marginBottom","marginLeft","marginRight"],function(prop){this.domNode.style[prop]=_3d5[prop];},this);var _3da=this.inlineEditBox.width;if(_3da=="100%"){_3d6+="width:100%;";this.domNode.style.display="block";}else{_3d6+="width:"+(_3da+(Number(_3da)==_3da?"px":""))+";";}var _3db=dojo.delegate(this.inlineEditBox.editorParams,{style:_3d6,dir:this.dir,lang:this.lang});_3db["displayedValue" in cls.prototype?"displayedValue":"value"]=this.value;var ew=(this.editWidget=new cls(_3db,this.editorPlaceholder));if(this.inlineEditBox.autoSave){dojo.destroy(this.buttonContainer);this.connect(ew,"onChange","_onChange");this.connect(ew,"onKeyPress","_onKeyPress");}else{if("intermediateChanges" in cls.prototype){ew.set("intermediateChanges",true);this.connect(ew,"onChange","_onIntermediateChange");this.saveButton.set("disabled",true);}}},_onIntermediateChange:function(val){this.saveButton.set("disabled",(this.getValue()==this._resetValue)||!this.enableSave());},destroy:function(){this.editWidget.destroy(true);this.inherited(arguments);},getValue:function(){var ew=this.editWidget;return String(ew.get("displayedValue" in ew?"displayedValue":"value"));},_onKeyPress:function(e){if(this.inlineEditBox.autoSave&&this.inlineEditBox.editing){if(e.altKey||e.ctrlKey){return;}if(e.charOrCode==dojo.keys.ESCAPE){dojo.stopEvent(e);this.cancel(true);}else{if(e.charOrCode==dojo.keys.ENTER&&e.target.tagName=="INPUT"){dojo.stopEvent(e);this._onChange();}}}},_onBlur:function(){this.inherited(arguments);if(this.inlineEditBox.autoSave&&this.inlineEditBox.editing){if(this.getValue()==this._resetValue){this.cancel(false);}else{if(this.enableSave()){this.save(false);}}}},_onChange:function(){if(this.inlineEditBox.autoSave&&this.inlineEditBox.editing&&this.enableSave()){dojo.style(this.inlineEditBox.displayNode,{display:""});dijit.focus(this.inlineEditBox.displayNode);}},enableSave:function(){return (this.editWidget.isValid?this.editWidget.isValid():true);},focus:function(){this.editWidget.focus();setTimeout(dojo.hitch(this,function(){if(this.editWidget.focusNode&&this.editWidget.focusNode.tagName=="INPUT"){dijit.selectInputText(this.editWidget.focusNode);}}),0);}});}if(!dojo._hasResource["dojo.cookie"]){dojo._hasResource["dojo.cookie"]=true;dojo.provide("dojo.cookie");dojo.cookie=function(name,_3dc,_3dd){var c=document.cookie;if(arguments.length==1){var _3de=c.match(new RegExp("(?:^|; )"+dojo.regexp.escapeString(name)+"=([^;]*)"));return _3de?decodeURIComponent(_3de[1]):undefined;}else{_3dd=_3dd||{};var exp=_3dd.expires;if(typeof exp=="number"){var d=new Date();d.setTime(d.getTime()+exp*24*60*60*1000);exp=_3dd.expires=d;}if(exp&&exp.toUTCString){_3dd.expires=exp.toUTCString();}_3dc=encodeURIComponent(_3dc);var _3df=name+"="+_3dc,_3e0;for(_3e0 in _3dd){_3df+="; "+_3e0;var _3e1=_3dd[_3e0];if(_3e1!==true){_3df+="="+_3e1;}}document.cookie=_3df;}};dojo.cookie.isSupported=function(){if(!("cookieEnabled" in navigator)){this("__djCookieTest__","CookiesAllowed");navigator.cookieEnabled=this("__djCookieTest__")=="CookiesAllowed";if(navigator.cookieEnabled){this("__djCookieTest__","",{expires:-1});}}return navigator.cookieEnabled;};}if(!dojo._hasResource["dijit.layout.StackController"]){dojo._hasResource["dijit.layout.StackController"]=true;dojo.provide("dijit.layout.StackController");dojo.declare("dijit.layout.StackController",[dijit._Widget,dijit._Templated,dijit._Container],{templateString:"<span wairole='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>",containerId:"",buttonWidget:"dijit.layout._StackButton",postCreate:function(){dijit.setWaiRole(this.domNode,"tablist");this.pane2button={};this.pane2handles={};this.subscribe(this.containerId+"-startup","onStartup");this.subscribe(this.containerId+"-addChild","onAddChild");this.subscribe(this.containerId+"-removeChild","onRemoveChild");this.subscribe(this.containerId+"-selectChild","onSelectChild");this.subscribe(this.containerId+"-containerKeyPress","onContainerKeyPress");},onStartup:function(info){dojo.forEach(info.children,this.onAddChild,this);if(info.selected){this.onSelectChild(info.selected);}},destroy:function(){for(var pane in this.pane2button){this.onRemoveChild(dijit.byId(pane));}this.inherited(arguments);},onAddChild:function(page,_3e2){var cls=dojo.getObject(this.buttonWidget);var _3e3=new cls({id:this.id+"_"+page.id,label:page.title,dir:page.dir,lang:page.lang,showLabel:page.showTitle,iconClass:page.iconClass,closeButton:page.closable,title:page.tooltip});dijit.setWaiState(_3e3.focusNode,"selected","false");this.pane2handles[page.id]=[this.connect(page,"set",function(name,_3e4){var _3e5={title:"label",showTitle:"showLabel",iconClass:"iconClass",closable:"closeButton",tooltip:"title"}[name];if(_3e5){_3e3.set(_3e5,_3e4);}}),this.connect(_3e3,"onClick",dojo.hitch(this,"onButtonClick",page)),this.connect(_3e3,"onClickCloseButton",dojo.hitch(this,"onCloseButtonClick",page))];this.addChild(_3e3,_3e2);this.pane2button[page.id]=_3e3;page.controlButton=_3e3;if(!this._currentChild){_3e3.focusNode.setAttribute("tabIndex","0");dijit.setWaiState(_3e3.focusNode,"selected","true");this._currentChild=page;}if(!this.isLeftToRight()&&dojo.isIE&&this._rectifyRtlTabList){this._rectifyRtlTabList();}},onRemoveChild:function(page){if(this._currentChild===page){this._currentChild=null;}dojo.forEach(this.pane2handles[page.id],this.disconnect,this);delete this.pane2handles[page.id];var _3e6=this.pane2button[page.id];if(_3e6){this.removeChild(_3e6);delete this.pane2button[page.id];_3e6.destroy();}delete page.controlButton;},onSelectChild:function(page){if(!page){return;}if(this._currentChild){var _3e7=this.pane2button[this._currentChild.id];_3e7.set("checked",false);dijit.setWaiState(_3e7.focusNode,"selected","false");_3e7.focusNode.setAttribute("tabIndex","-1");}var _3e8=this.pane2button[page.id];_3e8.set("checked",true);dijit.setWaiState(_3e8.focusNode,"selected","true");this._currentChild=page;_3e8.focusNode.setAttribute("tabIndex","0");var _3e9=dijit.byId(this.containerId);dijit.setWaiState(_3e9.containerNode,"labelledby",_3e8.id);},onButtonClick:function(page){var _3ea=dijit.byId(this.containerId);_3ea.selectChild(page);},onCloseButtonClick:function(page){var _3eb=dijit.byId(this.containerId);_3eb.closeChild(page);if(this._currentChild){var b=this.pane2button[this._currentChild.id];if(b){dijit.focus(b.focusNode||b.domNode);}}},adjacent:function(_3ec){if(!this.isLeftToRight()&&(!this.tabPosition||/top|bottom/.test(this.tabPosition))){_3ec=!_3ec;}var _3ed=this.getChildren();var _3ee=dojo.indexOf(_3ed,this.pane2button[this._currentChild.id]);var _3ef=_3ec?1:_3ed.length-1;return _3ed[(_3ee+_3ef)%_3ed.length];},onkeypress:function(e){if(this.disabled||e.altKey){return;}var _3f0=null;if(e.ctrlKey||!e._djpage){var k=dojo.keys;switch(e.charOrCode){case k.LEFT_ARROW:case k.UP_ARROW:if(!e._djpage){_3f0=false;}break;case k.PAGE_UP:if(e.ctrlKey){_3f0=false;}break;case k.RIGHT_ARROW:case k.DOWN_ARROW:if(!e._djpage){_3f0=true;}break;case k.PAGE_DOWN:if(e.ctrlKey){_3f0=true;}break;case k.DELETE:if(this._currentChild.closable){this.onCloseButtonClick(this._currentChild);}dojo.stopEvent(e);break;default:if(e.ctrlKey){if(e.charOrCode===k.TAB){this.adjacent(!e.shiftKey).onClick();dojo.stopEvent(e);}else{if(e.charOrCode=="w"){if(this._currentChild.closable){this.onCloseButtonClick(this._currentChild);}dojo.stopEvent(e);}}}}if(_3f0!==null){this.adjacent(_3f0).onClick();dojo.stopEvent(e);}}},onContainerKeyPress:function(info){info.e._djpage=info.page;this.onkeypress(info.e);}});dojo.declare("dijit.layout._StackButton",dijit.form.ToggleButton,{tabIndex:"-1",postCreate:function(evt){dijit.setWaiRole((this.focusNode||this.domNode),"tab");this.inherited(arguments);},onClick:function(evt){dijit.focus(this.focusNode);},onClickCloseButton:function(evt){evt.stopPropagation();}});}if(!dojo._hasResource["dijit.layout.StackContainer"]){dojo._hasResource["dijit.layout.StackContainer"]=true;dojo.provide("dijit.layout.StackContainer");dojo.declare("dijit.layout.StackContainer",dijit.layout._LayoutWidget,{doLayout:true,persist:false,baseClass:"dijitStackContainer",postCreate:function(){this.inherited(arguments);dojo.addClass(this.domNode,"dijitLayoutContainer");dijit.setWaiRole(this.containerNode,"tabpanel");this.connect(this.domNode,"onkeypress",this._onKeyPress);},startup:function(){if(this._started){return;}var _3f1=this.getChildren();dojo.forEach(_3f1,this._setupChild,this);if(this.persist){this.selectedChildWidget=dijit.byId(dojo.cookie(this.id+"_selectedChild"));}else{dojo.some(_3f1,function(_3f2){if(_3f2.selected){this.selectedChildWidget=_3f2;}return _3f2.selected;},this);}var _3f3=this.selectedChildWidget;if(!_3f3&&_3f1[0]){_3f3=this.selectedChildWidget=_3f1[0];_3f3.selected=true;}dojo.publish(this.id+"-startup",[{children:_3f1,selected:_3f3}]);this.inherited(arguments);},resize:function(){var _3f4=this.selectedChildWidget;if(_3f4&&!this._hasBeenShown){this._hasBeenShown=true;this._showChild(_3f4);}this.inherited(arguments);},_setupChild:function(_3f5){this.inherited(arguments);dojo.removeClass(_3f5.domNode,"dijitVisible");dojo.addClass(_3f5.domNode,"dijitHidden");_3f5.domNode.title="";},addChild:function(_3f6,_3f7){this.inherited(arguments);if(this._started){dojo.publish(this.id+"-addChild",[_3f6,_3f7]);this.layout();if(!this.selectedChildWidget){this.selectChild(_3f6);}}},removeChild:function(page){this.inherited(arguments);if(this._started){dojo.publish(this.id+"-removeChild",[page]);}if(this._beingDestroyed){return;}if(this.selectedChildWidget===page){this.selectedChildWidget=undefined;if(this._started){var _3f8=this.getChildren();if(_3f8.length){this.selectChild(_3f8[0]);}}}if(this._started){this.layout();}},selectChild:function(page,_3f9){page=dijit.byId(page);if(this.selectedChildWidget!=page){this._transition(page,this.selectedChildWidget,_3f9);this.selectedChildWidget=page;dojo.publish(this.id+"-selectChild",[page]);if(this.persist){dojo.cookie(this.id+"_selectedChild",this.selectedChildWidget.id);}}},_transition:function(_3fa,_3fb){if(_3fb){this._hideChild(_3fb);}this._showChild(_3fa);if(_3fa.resize){if(this.doLayout){_3fa.resize(this._containerContentBox||this._contentBox);}else{_3fa.resize();}}},_adjacent:function(_3fc){var _3fd=this.getChildren();var _3fe=dojo.indexOf(_3fd,this.selectedChildWidget);_3fe+=_3fc?1:_3fd.length-1;return _3fd[_3fe%_3fd.length];},forward:function(){this.selectChild(this._adjacent(true),true);},back:function(){this.selectChild(this._adjacent(false),true);},_onKeyPress:function(e){dojo.publish(this.id+"-containerKeyPress",[{e:e,page:this}]);},layout:function(){if(this.doLayout&&this.selectedChildWidget&&this.selectedChildWidget.resize){this.selectedChildWidget.resize(this._containerContentBox||this._contentBox);}},_showChild:function(page){var _3ff=this.getChildren();page.isFirstChild=(page==_3ff[0]);page.isLastChild=(page==_3ff[_3ff.length-1]);page.selected=true;dojo.removeClass(page.domNode,"dijitHidden");dojo.addClass(page.domNode,"dijitVisible");page._onShow();},_hideChild:function(page){page.selected=false;dojo.removeClass(page.domNode,"dijitVisible");dojo.addClass(page.domNode,"dijitHidden");page.onHide();},closeChild:function(page){var _400=page.onClose(this,page);if(_400){this.removeChild(page);page.destroyRecursive();}},destroyDescendants:function(_401){dojo.forEach(this.getChildren(),function(_402){this.removeChild(_402);_402.destroyRecursive(_401);},this);}});dojo.extend(dijit._Widget,{selected:false,closable:false,iconClass:"",showTitle:true});}if(!dojo._hasResource["dijit.layout.AccordionPane"]){dojo._hasResource["dijit.layout.AccordionPane"]=true;dojo.provide("dijit.layout.AccordionPane");dojo.declare("dijit.layout.AccordionPane",dijit.layout.ContentPane,{constructor:function(){dojo.deprecated("dijit.layout.AccordionPane deprecated, use ContentPane instead","","2.0");},onSelected:function(){}});}if(!dojo._hasResource["dijit.layout.AccordionContainer"]){dojo._hasResource["dijit.layout.AccordionContainer"]=true;dojo.provide("dijit.layout.AccordionContainer");dojo.declare("dijit.layout.AccordionContainer",dijit.layout.StackContainer,{duration:dijit.defaultDuration,buttonWidget:"dijit.layout._AccordionButton",_verticalSpace:0,baseClass:"dijitAccordionContainer",postCreate:function(){this.domNode.style.overflow="hidden";this.inherited(arguments);dijit.setWaiRole(this.domNode,"tablist");},startup:function(){if(this._started){return;}this.inherited(arguments);if(this.selectedChildWidget){var _403=this.selectedChildWidget.containerNode.style;_403.display="";_403.overflow="auto";this.selectedChildWidget._wrapperWidget.set("selected",true);}},_getTargetHeight:function(node){var cs=dojo.getComputedStyle(node);return Math.max(this._verticalSpace-dojo._getPadBorderExtents(node,cs).h-dojo._getMarginExtents(node,cs).h,0);},layout:function(){var _404=this.selectedChildWidget;if(!_404){return;}var _405=_404._wrapperWidget.domNode,_406=dojo._getMarginExtents(_405),_407=dojo._getPadBorderExtents(_405),_408=this._contentBox;var _409=0;dojo.forEach(this.getChildren(),function(_40a){if(_40a!=_404){_409+=dojo.marginBox(_40a._wrapperWidget.domNode).h;}});this._verticalSpace=_408.h-_409-_406.h-_407.h-_404._buttonWidget.getTitleHeight();this._containerContentBox={h:this._verticalSpace,w:this._contentBox.w-_406.w-_407.w};if(_404){_404.resize(this._containerContentBox);}},_setupChild:function(_40b){_40b._wrapperWidget=new dijit.layout._AccordionInnerContainer({contentWidget:_40b,buttonWidget:this.buttonWidget,id:_40b.id+"_wrapper",dir:_40b.dir,lang:_40b.lang,parent:this});this.inherited(arguments);},addChild:function(_40c,_40d){if(this._started){dojo.place(_40c.domNode,this.containerNode,_40d);if(!_40c._started){_40c.startup();}this._setupChild(_40c);dojo.publish(this.id+"-addChild",[_40c,_40d]);this.layout();if(!this.selectedChildWidget){this.selectChild(_40c);}}else{this.inherited(arguments);}},removeChild:function(_40e){_40e._wrapperWidget.destroy();delete _40e._wrapperWidget;dojo.removeClass(_40e.domNode,"dijitHidden");this.inherited(arguments);},getChildren:function(){return dojo.map(this.inherited(arguments),function(_40f){return _40f.declaredClass=="dijit.layout._AccordionInnerContainer"?_40f.contentWidget:_40f;},this);},destroy:function(){dojo.forEach(this.getChildren(),function(_410){_410._wrapperWidget.destroy();});this.inherited(arguments);},_transition:function(_411,_412,_413){if(this._inTransition){return;}var _414=[];var _415=this._verticalSpace;if(_411){_411._wrapperWidget.set("selected",true);this._showChild(_411);if(this.doLayout&&_411.resize){_411.resize(this._containerContentBox);}var _416=_411.domNode;dojo.addClass(_416,"dijitVisible");dojo.removeClass(_416,"dijitHidden");if(_413){var _417=_416.style.overflow;_416.style.overflow="hidden";_414.push(dojo.animateProperty({node:_416,duration:this.duration,properties:{height:{start:1,end:this._getTargetHeight(_416)}},onEnd:function(){_416.style.overflow=_417;if(dojo.isIE){setTimeout(function(){dojo.removeClass(_416.parentNode,"dijitAccordionInnerContainerFocused");setTimeout(function(){dojo.addClass(_416.parentNode,"dijitAccordionInnerContainerFocused");},0);},0);}}}));}}if(_412){_412._wrapperWidget.set("selected",false);var _418=_412.domNode;if(_413){var _419=_418.style.overflow;_418.style.overflow="hidden";_414.push(dojo.animateProperty({node:_418,duration:this.duration,properties:{height:{start:this._getTargetHeight(_418),end:1}},onEnd:function(){dojo.addClass(_418,"dijitHidden");dojo.removeClass(_418,"dijitVisible");_418.style.overflow=_419;if(_412.onHide){_412.onHide();}}}));}else{dojo.addClass(_418,"dijitHidden");dojo.removeClass(_418,"dijitVisible");if(_412.onHide){_412.onHide();}}}if(_413){this._inTransition=true;var _41a=dojo.fx.combine(_414);_41a.onEnd=dojo.hitch(this,function(){delete this._inTransition;});_41a.play();}},_onKeyPress:function(e,_41b){if(this._inTransition||this.disabled||e.altKey||!(_41b||e.ctrlKey)){if(this._inTransition){dojo.stopEvent(e);}return;}var k=dojo.keys,c=e.charOrCode;if((_41b&&(c==k.LEFT_ARROW||c==k.UP_ARROW))||(e.ctrlKey&&c==k.PAGE_UP)){this._adjacent(false)._buttonWidget._onTitleClick();dojo.stopEvent(e);}else{if((_41b&&(c==k.RIGHT_ARROW||c==k.DOWN_ARROW))||(e.ctrlKey&&(c==k.PAGE_DOWN||c==k.TAB))){this._adjacent(true)._buttonWidget._onTitleClick();dojo.stopEvent(e);}}}});dojo.declare("dijit.layout._AccordionInnerContainer",[dijit._Widget,dijit._CssStateMixin],{baseClass:"dijitAccordionInnerContainer",isContainer:true,isLayoutContainer:true,buildRendering:function(){this.domNode=dojo.place("<div class='"+this.baseClass+"'>",this.contentWidget.domNode,"after");var _41c=this.contentWidget,cls=dojo.getObject(this.buttonWidget);this.button=_41c._buttonWidget=(new cls({contentWidget:_41c,label:_41c.title,title:_41c.tooltip,dir:_41c.dir,lang:_41c.lang,iconClass:_41c.iconClass,id:_41c.id+"_button",parent:this.parent})).placeAt(this.domNode);dojo.place(this.contentWidget.domNode,this.domNode);},postCreate:function(){this.inherited(arguments);this.connect(this.contentWidget,"set",function(name,_41d){var _41e={title:"label",tooltip:"title",iconClass:"iconClass"}[name];if(_41e){this.button.set(_41e,_41d);}},this);},_setSelectedAttr:function(_41f){this.selected=_41f;this.button.set("selected",_41f);if(_41f){var cw=this.contentWidget;if(cw.onSelected){cw.onSelected();}}},startup:function(){this.contentWidget.startup();},destroy:function(){this.button.destroyRecursive();delete this.contentWidget._buttonWidget;delete this.contentWidget._wrapperWidget;this.inherited(arguments);},destroyDescendants:function(){this.contentWidget.destroyRecursive();}});dojo.declare("dijit.layout._AccordionButton",[dijit._Widget,dijit._Templated,dijit._CssStateMixin],{templateString:dojo.cache("dijit.layout","templates/AccordionButton.html","<div dojoAttachEvent='onclick:_onTitleClick' class='dijitAccordionTitle'>\n\t<div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='onkeypress:_onTitleKeyPress'\n\t\t\tclass='dijitAccordionTitleFocus' wairole=\"tab\" waiState=\"expanded-false\"\n\t\t><span class='dijitInline dijitAccordionArrow' waiRole=\"presentation\"></span\n\t\t><span class='arrowTextUp' waiRole=\"presentation\">+</span\n\t\t><span class='arrowTextDown' waiRole=\"presentation\">-</span\n\t\t><img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' style=\"vertical-align: middle\" waiRole=\"presentation\"/>\n\t\t<span waiRole=\"presentation\" dojoAttachPoint='titleTextNode' class='dijitAccordionText'></span>\n\t</div>\n</div>\n"),attributeMap:dojo.mixin(dojo.clone(dijit.layout.ContentPane.prototype.attributeMap),{label:{node:"titleTextNode",type:"innerHTML"},title:{node:"titleTextNode",type:"attribute",attribute:"title"},iconClass:{node:"iconNode",type:"class"}}),baseClass:"dijitAccordionTitle",getParent:function(){return this.parent;},postCreate:function(){this.inherited(arguments);dojo.setSelectable(this.domNode,false);var _420=dojo.attr(this.domNode,"id").replace(" ","_");dojo.attr(this.titleTextNode,"id",_420+"_title");dijit.setWaiState(this.focusNode,"labelledby",dojo.attr(this.titleTextNode,"id"));},getTitleHeight:function(){return dojo.marginBox(this.domNode).h;},_onTitleClick:function(){var _421=this.getParent();if(!_421._inTransition){_421.selectChild(this.contentWidget,true);dijit.focus(this.focusNode);}},_onTitleKeyPress:function(evt){return this.getParent()._onKeyPress(evt,this.contentWidget);},_setSelectedAttr:function(_422){this.selected=_422;dijit.setWaiState(this.focusNode,"expanded",_422);dijit.setWaiState(this.focusNode,"selected",_422);this.focusNode.setAttribute("tabIndex",_422?"0":"-1");}});}if(!dojo._hasResource["dijit.layout.BorderContainer"]){dojo._hasResource["dijit.layout.BorderContainer"]=true;dojo.provide("dijit.layout.BorderContainer");dojo.declare("dijit.layout.BorderContainer",dijit.layout._LayoutWidget,{design:"headline",gutters:true,liveSplitters:true,persist:false,baseClass:"dijitBorderContainer",_splitterClass:"dijit.layout._Splitter",postMixInProperties:function(){if(!this.gutters){this.baseClass+="NoGutter";}this.inherited(arguments);},postCreate:function(){this.inherited(arguments);this._splitters={};this._splitterThickness={};},startup:function(){if(this._started){return;}dojo.forEach(this.getChildren(),this._setupChild,this);this.inherited(arguments);},_setupChild:function(_423){var _424=_423.region;if(_424){this.inherited(arguments);dojo.addClass(_423.domNode,this.baseClass+"Pane");var ltr=this.isLeftToRight();if(_424=="leading"){_424=ltr?"left":"right";}if(_424=="trailing"){_424=ltr?"right":"left";}this["_"+_424]=_423.domNode;this["_"+_424+"Widget"]=_423;if((_423.splitter||this.gutters)&&!this._splitters[_424]){var _425=dojo.getObject(_423.splitter?this._splitterClass:"dijit.layout._Gutter");var _426=new _425({id:_423.id+"_splitter",container:this,child:_423,region:_424,live:this.liveSplitters});_426.isSplitter=true;this._splitters[_424]=_426.domNode;dojo.place(this._splitters[_424],_423.domNode,"after");_426.startup();}_423.region=_424;}},_computeSplitterThickness:function(_427){this._splitterThickness[_427]=this._splitterThickness[_427]||dojo.marginBox(this._splitters[_427])[(/top|bottom/.test(_427)?"h":"w")];},layout:function(){for(var _428 in this._splitters){this._computeSplitterThickness(_428);}this._layoutChildren();},addChild:function(_429,_42a){this.inherited(arguments);if(this._started){this.layout();}},removeChild:function(_42b){var _42c=_42b.region;var _42d=this._splitters[_42c];if(_42d){dijit.byNode(_42d).destroy();delete this._splitters[_42c];delete this._splitterThickness[_42c];}this.inherited(arguments);delete this["_"+_42c];delete this["_"+_42c+"Widget"];if(this._started){this._layoutChildren();}dojo.removeClass(_42b.domNode,this.baseClass+"Pane");},getChildren:function(){return dojo.filter(this.inherited(arguments),function(_42e){return !_42e.isSplitter;});},getSplitter:function(_42f){var _430=this._splitters[_42f];return _430?dijit.byNode(_430):null;},resize:function(_431,_432){if(!this.cs||!this.pe){var node=this.domNode;this.cs=dojo.getComputedStyle(node);this.pe=dojo._getPadExtents(node,this.cs);this.pe.r=dojo._toPixelValue(node,this.cs.paddingRight);this.pe.b=dojo._toPixelValue(node,this.cs.paddingBottom);dojo.style(node,"padding","0px");}this.inherited(arguments);},_layoutChildren:function(_433,_434){if(!this._borderBox||!this._borderBox.h){return;}var _435=(this.design=="sidebar");var _436=0,_437=0,_438=0,_439=0;var _43a={},_43b={},_43c={},_43d={},_43e=(this._center&&this._center.style)||{};var _43f=/left|right/.test(_433);var _440=!_433||(!_43f&&!_435);var _441=!_433||(_43f&&_435);if(this._top){_43a=(_433=="top"||_441)&&this._top.style;_436=_433=="top"?_434:dojo.marginBox(this._top).h;}if(this._left){_43b=(_433=="left"||_440)&&this._left.style;_438=_433=="left"?_434:dojo.marginBox(this._left).w;}if(this._right){_43c=(_433=="right"||_440)&&this._right.style;_439=_433=="right"?_434:dojo.marginBox(this._right).w;}if(this._bottom){_43d=(_433=="bottom"||_441)&&this._bottom.style;_437=_433=="bottom"?_434:dojo.marginBox(this._bottom).h;}var _442=this._splitters;var _443=_442.top,_444=_442.bottom,_445=_442.left,_446=_442.right;var _447=this._splitterThickness;var _448=_447.top||0,_449=_447.left||0,_44a=_447.right||0,_44b=_447.bottom||0;if(_449>50||_44a>50){setTimeout(dojo.hitch(this,function(){this._splitterThickness={};for(var _44c in this._splitters){this._computeSplitterThickness(_44c);}this._layoutChildren();}),50);return false;}var pe=this.pe;var _44d={left:(_435?_438+_449:0)+pe.l+"px",right:(_435?_439+_44a:0)+pe.r+"px"};if(_443){dojo.mixin(_443.style,_44d);_443.style.top=_436+pe.t+"px";}if(_444){dojo.mixin(_444.style,_44d);_444.style.bottom=_437+pe.b+"px";}_44d={top:(_435?0:_436+_448)+pe.t+"px",bottom:(_435?0:_437+_44b)+pe.b+"px"};if(_445){dojo.mixin(_445.style,_44d);_445.style.left=_438+pe.l+"px";}if(_446){dojo.mixin(_446.style,_44d);_446.style.right=_439+pe.r+"px";}dojo.mixin(_43e,{top:pe.t+_436+_448+"px",left:pe.l+_438+_449+"px",right:pe.r+_439+_44a+"px",bottom:pe.b+_437+_44b+"px"});var _44e={top:_435?pe.t+"px":_43e.top,bottom:_435?pe.b+"px":_43e.bottom};dojo.mixin(_43b,_44e);dojo.mixin(_43c,_44e);_43b.left=pe.l+"px";_43c.right=pe.r+"px";_43a.top=pe.t+"px";_43d.bottom=pe.b+"px";if(_435){_43a.left=_43d.left=_438+_449+pe.l+"px";_43a.right=_43d.right=_439+_44a+pe.r+"px";}else{_43a.left=_43d.left=pe.l+"px";_43a.right=_43d.right=pe.r+"px";}var _44f=this._borderBox.h-pe.t-pe.b,_450=_44f-(_436+_448+_437+_44b),_451=_435?_44f:_450;var _452=this._borderBox.w-pe.l-pe.r,_453=_452-(_438+_449+_439+_44a),_454=_435?_453:_452;var dim={top:{w:_454,h:_436},bottom:{w:_454,h:_437},left:{w:_438,h:_451},right:{w:_439,h:_451},center:{h:_450,w:_453}};if(_433){var _455=this["_"+_433+"Widget"],mb={};mb[/top|bottom/.test(_433)?"h":"w"]=_434;_455.resize?_455.resize(mb,dim[_455.region]):dojo.marginBox(_455.domNode,mb);}var _456=dojo.isIE<8||(dojo.isIE&&dojo.isQuirks)||dojo.some(this.getChildren(),function(_457){return _457.domNode.tagName=="TEXTAREA"||_457.domNode.tagName=="INPUT";});if(_456){var _458=function(_459,_45a,_45b){if(_459){(_459.resize?_459.resize(_45a,_45b):dojo.marginBox(_459.domNode,_45a));}};if(_445){_445.style.height=_451;}if(_446){_446.style.height=_451;}_458(this._leftWidget,{h:_451},dim.left);_458(this._rightWidget,{h:_451},dim.right);if(_443){_443.style.width=_454;}if(_444){_444.style.width=_454;}_458(this._topWidget,{w:_454},dim.top);_458(this._bottomWidget,{w:_454},dim.bottom);_458(this._centerWidget,dim.center);}else{var _45c=!_433||(/top|bottom/.test(_433)&&this.design!="sidebar"),_45d=!_433||(/left|right/.test(_433)&&this.design=="sidebar"),_45e={center:true,left:_45c,right:_45c,top:_45d,bottom:_45d};dojo.forEach(this.getChildren(),function(_45f){if(_45f.resize&&_45e[_45f.region]){_45f.resize(null,dim[_45f.region]);}},this);}},destroy:function(){for(var _460 in this._splitters){var _461=this._splitters[_460];dijit.byNode(_461).destroy();dojo.destroy(_461);}delete this._splitters;delete this._splitterThickness;this.inherited(arguments);}});dojo.extend(dijit._Widget,{region:"",splitter:false,minSize:0,maxSize:Infinity});dojo.declare("dijit.layout._Splitter",[dijit._Widget,dijit._Templated],{live:true,templateString:"<div class=\"dijitSplitter\" dojoAttachEvent=\"onkeypress:_onKeyPress,onmousedown:_startDrag,onmouseenter:_onMouse,onmouseleave:_onMouse\" tabIndex=\"0\" waiRole=\"separator\"><div class=\"dijitSplitterThumb\"></div></div>",postCreate:function(){this.inherited(arguments);this.horizontal=/top|bottom/.test(this.region);dojo.addClass(this.domNode,"dijitSplitter"+(this.horizontal?"H":"V"));this._factor=/top|left/.test(this.region)?1:-1;this._cookieName=this.container.id+"_"+this.region;if(this.container.persist){var _462=dojo.cookie(this._cookieName);if(_462){this.child.domNode.style[this.horizontal?"height":"width"]=_462;}}},_computeMaxSize:function(){var dim=this.horizontal?"h":"w",_463=this.container._splitterThickness[this.region];var flip={left:"right",right:"left",top:"bottom",bottom:"top",leading:"trailing",trailing:"leading"},_464=this.container["_"+flip[this.region]];var _465=dojo.contentBox(this.container.domNode)[dim]-(_464?dojo.marginBox(_464)[dim]:0)-20-_463*2;return Math.min(this.child.maxSize,_465);},_startDrag:function(e){if(!this.cover){this.cover=dojo.doc.createElement("div");dojo.addClass(this.cover,"dijitSplitterCover");dojo.place(this.cover,this.child.domNode,"after");}dojo.addClass(this.cover,"dijitSplitterCoverActive");if(this.fake){dojo.destroy(this.fake);}if(!(this._resize=this.live)){(this.fake=this.domNode.cloneNode(true)).removeAttribute("id");dojo.addClass(this.domNode,"dijitSplitterShadow");dojo.place(this.fake,this.domNode,"after");}dojo.addClass(this.domNode,"dijitSplitterActive");dojo.addClass(this.domNode,"dijitSplitter"+(this.horizontal?"H":"V")+"Active");if(this.fake){dojo.removeClass(this.fake,"dijitSplitterHover");dojo.removeClass(this.fake,"dijitSplitter"+(this.horizontal?"H":"V")+"Hover");}var _466=this._factor,max=this._computeMaxSize(),min=this.child.minSize||20,_467=this.horizontal,axis=_467?"pageY":"pageX",_468=e[axis],_469=this.domNode.style,dim=_467?"h":"w",_46a=dojo.marginBox(this.child.domNode)[dim],_46b=this.region,_46c=parseInt(this.domNode.style[_46b],10),_46d=this._resize,_46e=this.child.domNode,_46f=dojo.hitch(this.container,this.container._layoutChildren),de=dojo.doc;this._handlers=(this._handlers||[]).concat([dojo.connect(de,"onmousemove",this._drag=function(e,_470){var _471=e[axis]-_468,_472=_466*_471+_46a,_473=Math.max(Math.min(_472,max),min);if(_46d||_470){_46f(_46b,_473);}_469[_46b]=_466*_471+_46c+(_473-_472)+"px";}),dojo.connect(de,"ondragstart",dojo.stopEvent),dojo.connect(dojo.body(),"onselectstart",dojo.stopEvent),dojo.connect(de,"onmouseup",this,"_stopDrag")]);dojo.stopEvent(e);},_onMouse:function(e){var o=(e.type=="mouseover"||e.type=="mouseenter");dojo.toggleClass(this.domNode,"dijitSplitterHover",o);dojo.toggleClass(this.domNode,"dijitSplitter"+(this.horizontal?"H":"V")+"Hover",o);},_stopDrag:function(e){try{if(this.cover){dojo.removeClass(this.cover,"dijitSplitterCoverActive");}if(this.fake){dojo.destroy(this.fake);}dojo.removeClass(this.domNode,"dijitSplitterActive");dojo.removeClass(this.domNode,"dijitSplitter"+(this.horizontal?"H":"V")+"Active");dojo.removeClass(this.domNode,"dijitSplitterShadow");this._drag(e);this._drag(e,true);}finally{this._cleanupHandlers();delete this._drag;}if(this.container.persist){dojo.cookie(this._cookieName,this.child.domNode.style[this.horizontal?"height":"width"],{expires:365});}},_cleanupHandlers:function(){dojo.forEach(this._handlers,dojo.disconnect);delete this._handlers;},_onKeyPress:function(e){this._resize=true;var _474=this.horizontal;var tick=1;var dk=dojo.keys;switch(e.charOrCode){case _474?dk.UP_ARROW:dk.LEFT_ARROW:tick*=-1;case _474?dk.DOWN_ARROW:dk.RIGHT_ARROW:break;default:return;}var _475=dojo.marginBox(this.child.domNode)[_474?"h":"w"]+this._factor*tick;this.container._layoutChildren(this.region,Math.max(Math.min(_475,this._computeMaxSize()),this.child.minSize));dojo.stopEvent(e);},destroy:function(){this._cleanupHandlers();delete this.child;delete this.container;delete this.cover;delete this.fake;this.inherited(arguments);}});dojo.declare("dijit.layout._Gutter",[dijit._Widget,dijit._Templated],{templateString:"<div class=\"dijitGutter\" waiRole=\"presentation\"></div>",postCreate:function(){this.horizontal=/top|bottom/.test(this.region);dojo.addClass(this.domNode,"dijitGutter"+(this.horizontal?"H":"V"));}});}if(!dojo._hasResource["dijit.layout._TabContainerBase"]){dojo._hasResource["dijit.layout._TabContainerBase"]=true;dojo.provide("dijit.layout._TabContainerBase");dojo.declare("dijit.layout._TabContainerBase",[dijit.layout.StackContainer,dijit._Templated],{tabPosition:"top",baseClass:"dijitTabContainer",tabStrip:false,nested:false,templateString:dojo.cache("dijit.layout","templates/TabContainer.html","<div class=\"dijitTabContainer\">\n\t<div class=\"dijitTabListWrapper\" dojoAttachPoint=\"tablistNode\"></div>\n\t<div dojoAttachPoint=\"tablistSpacer\" class=\"dijitTabSpacer ${baseClass}-spacer\"></div>\n\t<div class=\"dijitTabPaneWrapper ${baseClass}-container\" dojoAttachPoint=\"containerNode\"></div>\n</div>\n"),postMixInProperties:function(){this.baseClass+=this.tabPosition.charAt(0).toUpperCase()+this.tabPosition.substr(1).replace(/-.*/,"");this.srcNodeRef&&dojo.style(this.srcNodeRef,"visibility","hidden");this.inherited(arguments);},postCreate:function(){this.inherited(arguments);this.tablist=this._makeController(this.tablistNode);if(!this.doLayout){dojo.addClass(this.domNode,"dijitTabContainerNoLayout");}if(this.nested){dojo.addClass(this.domNode,"dijitTabContainerNested");dojo.addClass(this.tablist.containerNode,"dijitTabContainerTabListNested");dojo.addClass(this.tablistSpacer,"dijitTabContainerSpacerNested");dojo.addClass(this.containerNode,"dijitTabPaneWrapperNested");}else{dojo.addClass(this.domNode,"tabStrip-"+(this.tabStrip?"enabled":"disabled"));}},_setupChild:function(tab){dojo.addClass(tab.domNode,"dijitTabPane");this.inherited(arguments);},startup:function(){if(this._started){return;}this.tablist.startup();this.inherited(arguments);},layout:function(){if(!this._contentBox||typeof (this._contentBox.l)=="undefined"){return;}var sc=this.selectedChildWidget;if(this.doLayout){var _476=this.tabPosition.replace(/-h/,"");this.tablist.layoutAlign=_476;var _477=[this.tablist,{domNode:this.tablistSpacer,layoutAlign:_476},{domNode:this.containerNode,layoutAlign:"client"}];dijit.layout.layoutChildren(this.domNode,this._contentBox,_477);this._containerContentBox=dijit.layout.marginBox2contentBox(this.containerNode,_477[2]);if(sc&&sc.resize){sc.resize(this._containerContentBox);}}else{if(this.tablist.resize){this.tablist.resize({w:dojo.contentBox(this.domNode).w});}if(sc&&sc.resize){sc.resize();}}},destroy:function(){if(this.tablist){this.tablist.destroy();}this.inherited(arguments);}});}if(!dojo._hasResource["dijit.layout.TabController"]){dojo._hasResource["dijit.layout.TabController"]=true;dojo.provide("dijit.layout.TabController");dojo.declare("dijit.layout.TabController",dijit.layout.StackController,{templateString:"<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>",tabPosition:"top",buttonWidget:"dijit.layout._TabButton",_rectifyRtlTabList:function(){if(0>=this.tabPosition.indexOf("-h")){return;}if(!this.pane2button){return;}var _478=0;for(var pane in this.pane2button){var ow=this.pane2button[pane].innerDiv.scrollWidth;_478=Math.max(_478,ow);}for(pane in this.pane2button){this.pane2button[pane].innerDiv.style.width=_478+"px";}}});dojo.declare("dijit.layout._TabButton",dijit.layout._StackButton,{baseClass:"dijitTab",cssStateNodes:{closeNode:"dijitTabCloseButton"},templateString:dojo.cache("dijit.layout","templates/_TabButton.html","<div waiRole=\"presentation\" dojoAttachPoint=\"titleNode\" dojoAttachEvent='onclick:onClick'>\n <div waiRole=\"presentation\" class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>\n <div waiRole=\"presentation\" class='dijitTabContent' dojoAttachPoint='tabContent'>\n \t<div waiRole=\"presentation\" dojoAttachPoint='focusNode'>\n\t\t <img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' />\n\t\t <span dojoAttachPoint='containerNode' class='tabLabel'></span>\n\t\t <span class=\"dijitInline dijitTabCloseButton dijitTabCloseIcon\" dojoAttachPoint='closeNode'\n\t\t \t\tdojoAttachEvent='onclick: onClickCloseButton' waiRole=\"presentation\">\n\t\t <span dojoAttachPoint='closeText' class='dijitTabCloseText'>x</span\n\t\t ></span>\n\t\t\t</div>\n </div>\n </div>\n</div>\n"),scrollOnFocus:false,postMixInProperties:function(){if(!this.iconClass){this.iconClass="dijitTabButtonIcon";}},postCreate:function(){this.inherited(arguments);dojo.setSelectable(this.containerNode,false);if(this.iconNode.className=="dijitTabButtonIcon"){dojo.style(this.iconNode,"width","1px");}},startup:function(){this.inherited(arguments);var n=this.domNode;setTimeout(function(){n.className=n.className;},1);},_setCloseButtonAttr:function(disp){this.closeButton=disp;dojo.toggleClass(this.innerDiv,"dijitClosable",disp);this.closeNode.style.display=disp?"":"none";if(disp){var _479=dojo.i18n.getLocalization("dijit","common");if(this.closeNode){dojo.attr(this.closeNode,"title",_479.itemClose);}var _479=dojo.i18n.getLocalization("dijit","common");this._closeMenu=new dijit.Menu({id:this.id+"_Menu",dir:this.dir,lang:this.lang,targetNodeIds:[this.domNode]});this._closeMenu.addChild(new dijit.MenuItem({label:_479.itemClose,dir:this.dir,lang:this.lang,onClick:dojo.hitch(this,"onClickCloseButton")}));}else{if(this._closeMenu){this._closeMenu.destroyRecursive();delete this._closeMenu;}}},_setLabelAttr:function(_47a){this.inherited(arguments);if(this.showLabel==false&&!this.params.title){this.iconNode.alt=dojo.trim(this.containerNode.innerText||this.containerNode.textContent||"");}},destroy:function(){if(this._closeMenu){this._closeMenu.destroyRecursive();delete this._closeMenu;}this.inherited(arguments);}});}if(!dojo._hasResource["dijit.layout.ScrollingTabController"]){dojo._hasResource["dijit.layout.ScrollingTabController"]=true;dojo.provide("dijit.layout.ScrollingTabController");dojo.declare("dijit.layout.ScrollingTabController",dijit.layout.TabController,{templateString:dojo.cache("dijit.layout","templates/ScrollingTabController.html","<div class=\"dijitTabListContainer-${tabPosition}\" style=\"visibility:hidden\">\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_menuBtn\" iconClass=\"dijitTabStripMenuIcon\"\n\t\t\tdojoAttachPoint=\"_menuBtn\" showLabel=false>&#9660;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_leftBtn\" iconClass=\"dijitTabStripSlideLeftIcon\"\n\t\t\tdojoAttachPoint=\"_leftBtn\" dojoAttachEvent=\"onClick: doSlideLeft\" showLabel=false>&#9664;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_rightBtn\" iconClass=\"dijitTabStripSlideRightIcon\"\n\t\t\tdojoAttachPoint=\"_rightBtn\" dojoAttachEvent=\"onClick: doSlideRight\" showLabel=false>&#9654;</div>\n\t<div class='dijitTabListWrapper' dojoAttachPoint='tablistWrapper'>\n\t\t<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'\n\t\t\t\tdojoAttachPoint='containerNode' class='nowrapTabStrip'></div>\n\t</div>\n</div>\n"),useMenu:true,useSlider:true,tabStripClass:"",widgetsInTemplate:true,_minScroll:5,attributeMap:dojo.delegate(dijit._Widget.prototype.attributeMap,{"class":"containerNode"}),postCreate:function(){this.inherited(arguments);var n=this.domNode;this.scrollNode=this.tablistWrapper;this._initButtons();if(!this.tabStripClass){this.tabStripClass="dijitTabContainer"+this.tabPosition.charAt(0).toUpperCase()+this.tabPosition.substr(1).replace(/-.*/,"")+"None";dojo.addClass(n,"tabStrip-disabled");}dojo.addClass(this.tablistWrapper,this.tabStripClass);},onStartup:function(){this.inherited(arguments);dojo.style(this.domNode,"visibility","visible");this._postStartup=true;},onAddChild:function(page,_47b){this.inherited(arguments);var _47c;if(this.useMenu){var _47d=this.containerId;_47c=new dijit.MenuItem({id:page.id+"_stcMi",label:page.title,dir:page.dir,lang:page.lang,onClick:dojo.hitch(this,function(){var _47e=dijit.byId(_47d);_47e.selectChild(page);})});this._menuChildren[page.id]=_47c;this._menu.addChild(_47c,_47b);}this.pane2handles[page.id].push(this.connect(this.pane2button[page.id],"set",function(name,_47f){if(this._postStartup){if(name=="label"){if(_47c){_47c.set(name,_47f);}if(this._dim){this.resize(this._dim);}}}}));dojo.style(this.containerNode,"width",(dojo.style(this.containerNode,"width")+200)+"px");},onRemoveChild:function(page,_480){var _481=this.pane2button[page.id];if(this._selectedTab===_481.domNode){this._selectedTab=null;}if(this.useMenu&&page&&page.id&&this._menuChildren[page.id]){this._menu.removeChild(this._menuChildren[page.id]);this._menuChildren[page.id].destroy();delete this._menuChildren[page.id];}this.inherited(arguments);},_initButtons:function(){this._menuChildren={};this._btnWidth=0;this._buttons=dojo.query("> .tabStripButton",this.domNode).filter(function(btn){if((this.useMenu&&btn==this._menuBtn.domNode)||(this.useSlider&&(btn==this._rightBtn.domNode||btn==this._leftBtn.domNode))){this._btnWidth+=dojo.marginBox(btn).w;return true;}else{dojo.style(btn,"display","none");return false;}},this);if(this.useMenu){this._menu=new dijit.Menu({id:this.id+"_menu",dir:this.dir,lang:this.lang,targetNodeIds:[this._menuBtn.domNode],leftClickToOpen:true,refocus:false});this._supportingWidgets.push(this._menu);}},_getTabsWidth:function(){var _482=this.getChildren();if(_482.length){var _483=_482[this.isLeftToRight()?0:_482.length-1].domNode,_484=_482[this.isLeftToRight()?_482.length-1:0].domNode;return _484.offsetLeft+dojo.style(_484,"width")-_483.offsetLeft;}else{return 0;}},_enableBtn:function(_485){var _486=this._getTabsWidth();_485=_485||dojo.style(this.scrollNode,"width");return _486>0&&_485<_486;},resize:function(dim){if(this.domNode.offsetWidth==0){return;}this._dim=dim;this.scrollNode.style.height="auto";this._contentBox=dijit.layout.marginBox2contentBox(this.domNode,{h:0,w:dim.w});this._contentBox.h=this.scrollNode.offsetHeight;dojo.contentBox(this.domNode,this._contentBox);var _487=this._enableBtn(this._contentBox.w);this._buttons.style("display",_487?"":"none");this._leftBtn.layoutAlign="left";this._rightBtn.layoutAlign="right";this._menuBtn.layoutAlign=this.isLeftToRight()?"right":"left";dijit.layout.layoutChildren(this.domNode,this._contentBox,[this._menuBtn,this._leftBtn,this._rightBtn,{domNode:this.scrollNode,layoutAlign:"client"}]);if(this._selectedTab){if(this._anim&&this._anim.status()=="playing"){this._anim.stop();}var w=this.scrollNode,sl=this._convertToScrollLeft(this._getScrollForSelectedTab());w.scrollLeft=sl;}this._setButtonClass(this._getScroll());this._postResize=true;},_getScroll:function(){var sl=(this.isLeftToRight()||dojo.isIE<8||(dojo.isIE&&dojo.isQuirks)||dojo.isWebKit)?this.scrollNode.scrollLeft:dojo.style(this.containerNode,"width")-dojo.style(this.scrollNode,"width")+(dojo.isIE==8?-1:1)*this.scrollNode.scrollLeft;return sl;},_convertToScrollLeft:function(val){if(this.isLeftToRight()||dojo.isIE<8||(dojo.isIE&&dojo.isQuirks)||dojo.isWebKit){return val;}else{var _488=dojo.style(this.containerNode,"width")-dojo.style(this.scrollNode,"width");return (dojo.isIE==8?-1:1)*(val-_488);}},onSelectChild:function(page){var tab=this.pane2button[page.id];if(!tab||!page){return;}var node=tab.domNode;if(this._postResize&&node!=this._selectedTab){this._selectedTab=node;var sl=this._getScroll();if(sl>node.offsetLeft||sl+dojo.style(this.scrollNode,"width")<node.offsetLeft+dojo.style(node,"width")){this.createSmoothScroll().play();}}this.inherited(arguments);},_getScrollBounds:function(){var _489=this.getChildren(),_48a=dojo.style(this.scrollNode,"width"),_48b=dojo.style(this.containerNode,"width"),_48c=_48b-_48a,_48d=this._getTabsWidth();if(_489.length&&_48d>_48a){return {min:this.isLeftToRight()?0:_489[_489.length-1].domNode.offsetLeft,max:this.isLeftToRight()?(_489[_489.length-1].domNode.offsetLeft+dojo.style(_489[_489.length-1].domNode,"width"))-_48a:_48c};}else{var _48e=this.isLeftToRight()?0:_48c;return {min:_48e,max:_48e};}},_getScrollForSelectedTab:function(){var w=this.scrollNode,n=this._selectedTab,_48f=dojo.style(this.scrollNode,"width"),_490=this._getScrollBounds();var pos=(n.offsetLeft+dojo.style(n,"width")/2)-_48f/2;pos=Math.min(Math.max(pos,_490.min),_490.max);return pos;},createSmoothScroll:function(x){if(arguments.length>0){var _491=this._getScrollBounds();x=Math.min(Math.max(x,_491.min),_491.max);}else{x=this._getScrollForSelectedTab();}if(this._anim&&this._anim.status()=="playing"){this._anim.stop();}var self=this,w=this.scrollNode,anim=new dojo._Animation({beforeBegin:function(){if(this.curve){delete this.curve;}var oldS=w.scrollLeft,newS=self._convertToScrollLeft(x);anim.curve=new dojo._Line(oldS,newS);},onAnimate:function(val){w.scrollLeft=val;}});this._anim=anim;this._setButtonClass(x);return anim;},_getBtnNode:function(e){var n=e.target;while(n&&!dojo.hasClass(n,"tabStripButton")){n=n.parentNode;}return n;},doSlideRight:function(e){this.doSlide(1,this._getBtnNode(e));},doSlideLeft:function(e){this.doSlide(-1,this._getBtnNode(e));},doSlide:function(_492,node){if(node&&dojo.hasClass(node,"dijitTabDisabled")){return;}var _493=dojo.style(this.scrollNode,"width");var d=(_493*0.75)*_492;var to=this._getScroll()+d;this._setButtonClass(to);this.createSmoothScroll(to).play();},_setButtonClass:function(_494){var _495=this._getScrollBounds();this._leftBtn.set("disabled",_494<=_495.min);this._rightBtn.set("disabled",_494>=_495.max);}});dojo.declare("dijit.layout._ScrollingTabControllerButton",dijit.form.Button,{baseClass:"dijitTab tabStripButton",templateString:dojo.cache("dijit.layout","templates/_ScrollingTabControllerButton.html","<div dojoAttachEvent=\"onclick:_onButtonClick\">\n\t<div waiRole=\"presentation\" class=\"dijitTabInnerDiv\" dojoattachpoint=\"innerDiv,focusNode\">\n\t\t<div waiRole=\"presentation\" class=\"dijitTabContent dijitButtonContents\" dojoattachpoint=\"tabContent\">\n\t\t\t<img waiRole=\"presentation\" alt=\"\" src=\"${_blankGif}\" class=\"dijitTabStripIcon\" dojoAttachPoint=\"iconNode\"/>\n\t\t\t<span dojoAttachPoint=\"containerNode,titleNode\" class=\"dijitButtonText\"></span>\n\t\t</div>\n\t</div>\n</div>\n"),tabIndex:"-1"});}if(!dojo._hasResource["dijit.layout.TabContainer"]){dojo._hasResource["dijit.layout.TabContainer"]=true;dojo.provide("dijit.layout.TabContainer");dojo.declare("dijit.layout.TabContainer",dijit.layout._TabContainerBase,{useMenu:true,useSlider:true,controllerWidget:"",_makeController:function(_496){var cls=this.baseClass+"-tabs"+(this.doLayout?"":" dijitTabNoLayout"),_497=dojo.getObject(this.controllerWidget);return new _497({id:this.id+"_tablist",dir:this.dir,lang:this.lang,tabPosition:this.tabPosition,doLayout:this.doLayout,containerId:this.id,"class":cls,nested:this.nested,useMenu:this.useMenu,useSlider:this.useSlider,tabStripClass:this.tabStrip?this.baseClass+(this.tabStrip?"":"No")+"Strip":null},_496);},postMixInProperties:function(){this.inherited(arguments);if(!this.controllerWidget){this.controllerWidget=(this.tabPosition=="top"||this.tabPosition=="bottom")&&!this.nested?"dijit.layout.ScrollingTabController":"dijit.layout.TabController";}}});}if(!dojo._hasResource["dojo.number"]){dojo._hasResource["dojo.number"]=true;dojo.provide("dojo.number");dojo.number.format=function(_498,_499){_499=dojo.mixin({},_499||{});var _49a=dojo.i18n.normalizeLocale(_499.locale),_49b=dojo.i18n.getLocalization("dojo.cldr","number",_49a);_499.customs=_49b;var _49c=_499.pattern||_49b[(_499.type||"decimal")+"Format"];if(isNaN(_498)||Math.abs(_498)==Infinity){return null;}return dojo.number._applyPattern(_498,_49c,_499);};dojo.number._numberPatternRE=/[#0,]*[#0](?:\.0*#*)?/;dojo.number._applyPattern=function(_49d,_49e,_49f){_49f=_49f||{};var _4a0=_49f.customs.group,_4a1=_49f.customs.decimal,_4a2=_49e.split(";"),_4a3=_4a2[0];_49e=_4a2[(_49d<0)?1:0]||("-"+_4a3);if(_49e.indexOf("%")!=-1){_49d*=100;}else{if(_49e.indexOf("‰")!=-1){_49d*=1000;}else{if(_49e.indexOf("¤")!=-1){_4a0=_49f.customs.currencyGroup||_4a0;_4a1=_49f.customs.currencyDecimal||_4a1;_49e=_49e.replace(/\u00a4{1,3}/,function(_4a4){var prop=["symbol","currency","displayName"][_4a4.length-1];return _49f[prop]||_49f.currency||"";});}else{if(_49e.indexOf("E")!=-1){throw new Error("exponential notation not supported");}}}}var _4a5=dojo.number._numberPatternRE;var _4a6=_4a3.match(_4a5);if(!_4a6){throw new Error("unable to find a number expression in pattern: "+_49e);}if(_49f.fractional===false){_49f.places=0;}return _49e.replace(_4a5,dojo.number._formatAbsolute(_49d,_4a6[0],{decimal:_4a1,group:_4a0,places:_49f.places,round:_49f.round}));};dojo.number.round=function(_4a7,_4a8,_4a9){var _4aa=10/(_4a9||10);return (_4aa*+_4a7).toFixed(_4a8)/_4aa;};if((0.9).toFixed()==0){(function(){var _4ab=dojo.number.round;dojo.number.round=function(v,p,m){var d=Math.pow(10,-p||0),a=Math.abs(v);if(!v||a>=d||a*Math.pow(10,p+1)<5){d=0;}return _4ab(v,p,m)+(v>0?d:-d);};})();}dojo.number._formatAbsolute=function(_4ac,_4ad,_4ae){_4ae=_4ae||{};if(_4ae.places===true){_4ae.places=0;}if(_4ae.places===Infinity){_4ae.places=6;}var _4af=_4ad.split("."),_4b0=typeof _4ae.places=="string"&&_4ae.places.indexOf(","),_4b1=_4ae.places;if(_4b0){_4b1=_4ae.places.substring(_4b0+1);}else{if(!(_4b1>=0)){_4b1=(_4af[1]||[]).length;}}if(!(_4ae.round<0)){_4ac=dojo.number.round(_4ac,_4b1,_4ae.round);}var _4b2=String(Math.abs(_4ac)).split("."),_4b3=_4b2[1]||"";if(_4af[1]||_4ae.places){if(_4b0){_4ae.places=_4ae.places.substring(0,_4b0);}var pad=_4ae.places!==undefined?_4ae.places:(_4af[1]&&_4af[1].lastIndexOf("0")+1);if(pad>_4b3.length){_4b2[1]=dojo.string.pad(_4b3,pad,"0",true);}if(_4b1<_4b3.length){_4b2[1]=_4b3.substr(0,_4b1);}}else{if(_4b2[1]){_4b2.pop();}}var _4b4=_4af[0].replace(",","");pad=_4b4.indexOf("0");if(pad!=-1){pad=_4b4.length-pad;if(pad>_4b2[0].length){_4b2[0]=dojo.string.pad(_4b2[0],pad);}if(_4b4.indexOf("#")==-1){_4b2[0]=_4b2[0].substr(_4b2[0].length-pad);}}var _4b5=_4af[0].lastIndexOf(","),_4b6,_4b7;if(_4b5!=-1){_4b6=_4af[0].length-_4b5-1;var _4b8=_4af[0].substr(0,_4b5);_4b5=_4b8.lastIndexOf(",");if(_4b5!=-1){_4b7=_4b8.length-_4b5-1;}}var _4b9=[];for(var _4ba=_4b2[0];_4ba;){var off=_4ba.length-_4b6;_4b9.push((off>0)?_4ba.substr(off):_4ba);_4ba=(off>0)?_4ba.slice(0,off):"";if(_4b7){_4b6=_4b7;delete _4b7;}}_4b2[0]=_4b9.reverse().join(_4ae.group||",");return _4b2.join(_4ae.decimal||".");};dojo.number.regexp=function(_4bb){return dojo.number._parseInfo(_4bb).regexp;};dojo.number._parseInfo=function(_4bc){_4bc=_4bc||{};var _4bd=dojo.i18n.normalizeLocale(_4bc.locale),_4be=dojo.i18n.getLocalization("dojo.cldr","number",_4bd),_4bf=_4bc.pattern||_4be[(_4bc.type||"decimal")+"Format"],_4c0=_4be.group,_4c1=_4be.decimal,_4c2=1;if(_4bf.indexOf("%")!=-1){_4c2/=100;}else{if(_4bf.indexOf("‰")!=-1){_4c2/=1000;}else{var _4c3=_4bf.indexOf("¤")!=-1;if(_4c3){_4c0=_4be.currencyGroup||_4c0;_4c1=_4be.currencyDecimal||_4c1;}}}var _4c4=_4bf.split(";");if(_4c4.length==1){_4c4.push("-"+_4c4[0]);}var re=dojo.regexp.buildGroupRE(_4c4,function(_4c5){_4c5="(?:"+dojo.regexp.escapeString(_4c5,".")+")";return _4c5.replace(dojo.number._numberPatternRE,function(_4c6){var _4c7={signed:false,separator:_4bc.strict?_4c0:[_4c0,""],fractional:_4bc.fractional,decimal:_4c1,exponent:false},_4c8=_4c6.split("."),_4c9=_4bc.places;if(_4c8.length==1&&_4c2!=1){_4c8[1]="###";}if(_4c8.length==1||_4c9===0){_4c7.fractional=false;}else{if(_4c9===undefined){_4c9=_4bc.pattern?_4c8[1].lastIndexOf("0")+1:Infinity;}if(_4c9&&_4bc.fractional==undefined){_4c7.fractional=true;}if(!_4bc.places&&(_4c9<_4c8[1].length)){_4c9+=","+_4c8[1].length;}_4c7.places=_4c9;}var _4ca=_4c8[0].split(",");if(_4ca.length>1){_4c7.groupSize=_4ca.pop().length;if(_4ca.length>1){_4c7.groupSize2=_4ca.pop().length;}}return "("+dojo.number._realNumberRegexp(_4c7)+")";});},true);if(_4c3){re=re.replace(/([\s\xa0]*)(\u00a4{1,3})([\s\xa0]*)/g,function(_4cb,_4cc,_4cd,_4ce){var prop=["symbol","currency","displayName"][_4cd.length-1],_4cf=dojo.regexp.escapeString(_4bc[prop]||_4bc.currency||"");_4cc=_4cc?"[\\s\\xa0]":"";_4ce=_4ce?"[\\s\\xa0]":"";if(!_4bc.strict){if(_4cc){_4cc+="*";}if(_4ce){_4ce+="*";}return "(?:"+_4cc+_4cf+_4ce+")?";}return _4cc+_4cf+_4ce;});}return {regexp:re.replace(/[\xa0 ]/g,"[\\s\\xa0]"),group:_4c0,decimal:_4c1,factor:_4c2};};dojo.number.parse=function(_4d0,_4d1){var info=dojo.number._parseInfo(_4d1),_4d2=(new RegExp("^"+info.regexp+"$")).exec(_4d0);if(!_4d2){return NaN;}var _4d3=_4d2[1];if(!_4d2[1]){if(!_4d2[2]){return NaN;}_4d3=_4d2[2];info.factor*=-1;}_4d3=_4d3.replace(new RegExp("["+info.group+"\\s\\xa0"+"]","g"),"").replace(info.decimal,".");return _4d3*info.factor;};dojo.number._realNumberRegexp=function(_4d4){_4d4=_4d4||{};if(!("places" in _4d4)){_4d4.places=Infinity;}if(typeof _4d4.decimal!="string"){_4d4.decimal=".";}if(!("fractional" in _4d4)||/^0/.test(_4d4.places)){_4d4.fractional=[true,false];}if(!("exponent" in _4d4)){_4d4.exponent=[true,false];}if(!("eSigned" in _4d4)){_4d4.eSigned=[true,false];}var _4d5=dojo.number._integerRegexp(_4d4),_4d6=dojo.regexp.buildGroupRE(_4d4.fractional,function(q){var re="";if(q&&(_4d4.places!==0)){re="\\"+_4d4.decimal;if(_4d4.places==Infinity){re="(?:"+re+"\\d+)?";}else{re+="\\d{"+_4d4.places+"}";}}return re;},true);var _4d7=dojo.regexp.buildGroupRE(_4d4.exponent,function(q){if(q){return "([eE]"+dojo.number._integerRegexp({signed:_4d4.eSigned})+")";}return "";});var _4d8=_4d5+_4d6;if(_4d6){_4d8="(?:(?:"+_4d8+")|(?:"+_4d6+"))";}return _4d8+_4d7;};dojo.number._integerRegexp=function(_4d9){_4d9=_4d9||{};if(!("signed" in _4d9)){_4d9.signed=[true,false];}if(!("separator" in _4d9)){_4d9.separator="";}else{if(!("groupSize" in _4d9)){_4d9.groupSize=3;}}var _4da=dojo.regexp.buildGroupRE(_4d9.signed,function(q){return q?"[-+]":"";},true);var _4db=dojo.regexp.buildGroupRE(_4d9.separator,function(sep){if(!sep){return "(?:\\d+)";}sep=dojo.regexp.escapeString(sep);if(sep==" "){sep="\\s";}else{if(sep==" "){sep="\\s\\xa0";}}var grp=_4d9.groupSize,grp2=_4d9.groupSize2;if(grp2){var _4dc="(?:0|[1-9]\\d{0,"+(grp2-1)+"}(?:["+sep+"]\\d{"+grp2+"})*["+sep+"]\\d{"+grp+"})";return ((grp-grp2)>0)?"(?:"+_4dc+"|(?:0|[1-9]\\d{0,"+(grp-1)+"}))":_4dc;}return "(?:0|[1-9]\\d{0,"+(grp-1)+"}(?:["+sep+"]\\d{"+grp+"})*)";},true);return _4da+_4db;};}if(!dojo._hasResource["dijit.ProgressBar"]){dojo._hasResource["dijit.ProgressBar"]=true;dojo.provide("dijit.ProgressBar");dojo.declare("dijit.ProgressBar",[dijit._Widget,dijit._Templated],{progress:"0",maximum:100,places:0,indeterminate:false,name:"",templateString:dojo.cache("dijit","templates/ProgressBar.html","<div class=\"dijitProgressBar dijitProgressBarEmpty\"\n\t><div waiRole=\"progressbar\" dojoAttachPoint=\"internalProgress\" class=\"dijitProgressBarFull\"\n\t\t><div class=\"dijitProgressBarTile\"></div\n\t\t><span style=\"visibility:hidden\">&nbsp;</span\n\t></div\n\t><div dojoAttachPoint=\"label\" class=\"dijitProgressBarLabel\" id=\"${id}_label\">&nbsp;</div\n\t><img dojoAttachPoint=\"indeterminateHighContrastImage\" class=\"dijitProgressBarIndeterminateHighContrastImage\" alt=\"\"\n/></div>\n"),_indeterminateHighContrastImagePath:dojo.moduleUrl("dijit","themes/a11y/indeterminate_progress.gif"),postCreate:function(){this.inherited(arguments);this.indeterminateHighContrastImage.setAttribute("src",this._indeterminateHighContrastImagePath.toString());this.update();},update:function(_4dd){dojo.mixin(this,_4dd||{});var tip=this.internalProgress;var _4de=1,_4df;if(this.indeterminate){_4df="addClass";dijit.removeWaiState(tip,"valuenow");dijit.removeWaiState(tip,"valuemin");dijit.removeWaiState(tip,"valuemax");}else{_4df="removeClass";if(String(this.progress).indexOf("%")!=-1){_4de=Math.min(parseFloat(this.progress)/100,1);this.progress=_4de*this.maximum;}else{this.progress=Math.min(this.progress,this.maximum);_4de=this.progress/this.maximum;}var text=this.report(_4de);this.label.firstChild.nodeValue=text;dijit.setWaiState(tip,"describedby",this.label.id);dijit.setWaiState(tip,"valuenow",this.progress);dijit.setWaiState(tip,"valuemin",0);dijit.setWaiState(tip,"valuemax",this.maximum);}dojo[_4df](this.domNode,"dijitProgressBarIndeterminate");tip.style.width=(_4de*100)+"%";this.onChange();},_setValueAttr:function(v){if(v==Infinity){this.update({indeterminate:true});}else{this.update({indeterminate:false,progress:v});}},_getValueAttr:function(){return this.progress;},report:function(_4e0){return dojo.number.format(_4e0,{type:"percent",places:this.places,locale:this.lang});},onChange:function(){}});}if(!dojo._hasResource["dijit.ToolbarSeparator"]){dojo._hasResource["dijit.ToolbarSeparator"]=true;dojo.provide("dijit.ToolbarSeparator");dojo.declare("dijit.ToolbarSeparator",[dijit._Widget,dijit._Templated],{templateString:"<div class=\"dijitToolbarSeparator dijitInline\" waiRole=\"presentation\"></div>",postCreate:function(){dojo.setSelectable(this.domNode,false);},isFocusable:function(){return false;}});}if(!dojo._hasResource["dijit.Toolbar"]){dojo._hasResource["dijit.Toolbar"]=true;dojo.provide("dijit.Toolbar");dojo.declare("dijit.Toolbar",[dijit._Widget,dijit._Templated,dijit._KeyNavContainer],{templateString:"<div class=\"dijit\" waiRole=\"toolbar\" tabIndex=\"${tabIndex}\" dojoAttachPoint=\"containerNode\">"+"</div>",baseClass:"dijitToolbar",postCreate:function(){this.connectKeyNavHandlers(this.isLeftToRight()?[dojo.keys.LEFT_ARROW]:[dojo.keys.RIGHT_ARROW],this.isLeftToRight()?[dojo.keys.RIGHT_ARROW]:[dojo.keys.LEFT_ARROW]);this.inherited(arguments);},startup:function(){if(this._started){return;}this.startupKeyNavChildren();this.inherited(arguments);}});}if(!dojo._hasResource["dojo.DeferredList"]){dojo._hasResource["dojo.DeferredList"]=true;dojo.provide("dojo.DeferredList");dojo.DeferredList=function(list,_4e1,_4e2,_4e3,_4e4){var _4e5=[];dojo.Deferred.call(this);var self=this;if(list.length===0&&!_4e1){this.resolve([0,[]]);}var _4e6=0;dojo.forEach(list,function(item,i){item.then(function(_4e7){if(_4e1){self.resolve([i,_4e7]);}else{_4e8(true,_4e7);}},function(_4e9){if(_4e2){self.reject(_4e9);}else{_4e8(false,_4e9);}if(_4e3){return null;}throw _4e9;});function _4e8(_4ea,_4eb){_4e5[i]=[_4ea,_4eb];_4e6++;if(_4e6===list.length){self.resolve(_4e5);}};});};dojo.DeferredList.prototype=new dojo.Deferred();dojo.DeferredList.prototype.gatherResults=function(_4ec){var d=new dojo.DeferredList(_4ec,false,true,false);d.addCallback(function(_4ed){var ret=[];dojo.forEach(_4ed,function(_4ee){ret.push(_4ee[1]);});return ret;});return d;};}if(!dojo._hasResource["dijit.tree.TreeStoreModel"]){dojo._hasResource["dijit.tree.TreeStoreModel"]=true;dojo.provide("dijit.tree.TreeStoreModel");dojo.declare("dijit.tree.TreeStoreModel",null,{store:null,childrenAttrs:["children"],newItemIdAttr:"id",labelAttr:"",root:null,query:null,deferItemLoadingUntilExpand:false,constructor:function(args){dojo.mixin(this,args);this.connects=[];var _4ef=this.store;if(!_4ef.getFeatures()["dojo.data.api.Identity"]){throw new Error("dijit.Tree: store must support dojo.data.Identity");}if(_4ef.getFeatures()["dojo.data.api.Notification"]){this.connects=this.connects.concat([dojo.connect(_4ef,"onNew",this,"onNewItem"),dojo.connect(_4ef,"onDelete",this,"onDeleteItem"),dojo.connect(_4ef,"onSet",this,"onSetItem")]);}},destroy:function(){dojo.forEach(this.connects,dojo.disconnect);},getRoot:function(_4f0,_4f1){if(this.root){_4f0(this.root);}else{this.store.fetch({query:this.query,onComplete:dojo.hitch(this,function(_4f2){if(_4f2.length!=1){throw new Error(this.declaredClass+": query "+dojo.toJson(this.query)+" returned "+_4f2.length+" items, but must return exactly one item");}this.root=_4f2[0];_4f0(this.root);}),onError:_4f1});}},mayHaveChildren:function(item){return dojo.some(this.childrenAttrs,function(attr){return this.store.hasAttribute(item,attr);},this);},getChildren:function(_4f3,_4f4,_4f5){var _4f6=this.store;if(!_4f6.isItemLoaded(_4f3)){var _4f7=dojo.hitch(this,arguments.callee);_4f6.loadItem({item:_4f3,onItem:function(_4f8){_4f7(_4f8,_4f4,_4f5);},onError:_4f5});return;}var _4f9=[];for(var i=0;i<this.childrenAttrs.length;i++){var vals=_4f6.getValues(_4f3,this.childrenAttrs[i]);_4f9=_4f9.concat(vals);}var _4fa=0;if(!this.deferItemLoadingUntilExpand){dojo.forEach(_4f9,function(item){if(!_4f6.isItemLoaded(item)){_4fa++;}});}if(_4fa==0){_4f4(_4f9);}else{dojo.forEach(_4f9,function(item,idx){if(!_4f6.isItemLoaded(item)){_4f6.loadItem({item:item,onItem:function(item){_4f9[idx]=item;if(--_4fa==0){_4f4(_4f9);}},onError:_4f5});}});}},isItem:function(_4fb){return this.store.isItem(_4fb);},fetchItemByIdentity:function(_4fc){this.store.fetchItemByIdentity(_4fc);},getIdentity:function(item){return this.store.getIdentity(item);},getLabel:function(item){if(this.labelAttr){return this.store.getValue(item,this.labelAttr);}else{return this.store.getLabel(item);}},newItem:function(args,_4fd,_4fe){var _4ff={parent:_4fd,attribute:this.childrenAttrs[0],insertIndex:_4fe};if(this.newItemIdAttr&&args[this.newItemIdAttr]){this.fetchItemByIdentity({identity:args[this.newItemIdAttr],scope:this,onItem:function(item){if(item){this.pasteItem(item,null,_4fd,true,_4fe);}else{this.store.newItem(args,_4ff);}}});}else{this.store.newItem(args,_4ff);}},pasteItem:function(_500,_501,_502,_503,_504){var _505=this.store,_506=this.childrenAttrs[0];if(_501){dojo.forEach(this.childrenAttrs,function(attr){if(_505.containsValue(_501,attr,_500)){if(!_503){var _507=dojo.filter(_505.getValues(_501,attr),function(x){return x!=_500;});_505.setValues(_501,attr,_507);}_506=attr;}});}if(_502){if(typeof _504=="number"){var _508=_505.getValues(_502,_506).slice();_508.splice(_504,0,_500);_505.setValues(_502,_506,_508);}else{_505.setValues(_502,_506,_505.getValues(_502,_506).concat(_500));}}},onChange:function(item){},onChildrenChange:function(_509,_50a){},onDelete:function(_50b,_50c){},onNewItem:function(item,_50d){if(!_50d){return;}this.getChildren(_50d.item,dojo.hitch(this,function(_50e){this.onChildrenChange(_50d.item,_50e);}));},onDeleteItem:function(item){this.onDelete(item);},onSetItem:function(item,_50f,_510,_511){if(dojo.indexOf(this.childrenAttrs,_50f)!=-1){this.getChildren(item,dojo.hitch(this,function(_512){this.onChildrenChange(item,_512);}));}else{this.onChange(item);}}});}if(!dojo._hasResource["dijit.tree.ForestStoreModel"]){dojo._hasResource["dijit.tree.ForestStoreModel"]=true;dojo.provide("dijit.tree.ForestStoreModel");dojo.declare("dijit.tree.ForestStoreModel",dijit.tree.TreeStoreModel,{rootId:"$root$",rootLabel:"ROOT",query:null,constructor:function(_513){this.root={store:this,root:true,id:_513.rootId,label:_513.rootLabel,children:_513.rootChildren};},mayHaveChildren:function(item){return item===this.root||this.inherited(arguments);},getChildren:function(_514,_515,_516){if(_514===this.root){if(this.root.children){_515(this.root.children);}else{this.store.fetch({query:this.query,onComplete:dojo.hitch(this,function(_517){this.root.children=_517;_515(_517);}),onError:_516});}}else{this.inherited(arguments);}},isItem:function(_518){return (_518===this.root)?true:this.inherited(arguments);},fetchItemByIdentity:function(_519){if(_519.identity==this.root.id){var _51a=_519.scope?_519.scope:dojo.global;if(_519.onItem){_519.onItem.call(_51a,this.root);}}else{this.inherited(arguments);}},getIdentity:function(item){return (item===this.root)?this.root.id:this.inherited(arguments);},getLabel:function(item){return (item===this.root)?this.root.label:this.inherited(arguments);},newItem:function(args,_51b,_51c){if(_51b===this.root){this.onNewRootItem(args);return this.store.newItem(args);}else{return this.inherited(arguments);}},onNewRootItem:function(args){},pasteItem:function(_51d,_51e,_51f,_520,_521){if(_51e===this.root){if(!_520){this.onLeaveRoot(_51d);}}dijit.tree.TreeStoreModel.prototype.pasteItem.call(this,_51d,_51e===this.root?null:_51e,_51f===this.root?null:_51f,_520,_521);if(_51f===this.root){this.onAddToRoot(_51d);}},onAddToRoot:function(item){console.log(this,": item ",item," added to root");},onLeaveRoot:function(item){console.log(this,": item ",item," removed from root");},_requeryTop:function(){var _522=this.root.children||[];this.store.fetch({query:this.query,onComplete:dojo.hitch(this,function(_523){this.root.children=_523;if(_522.length!=_523.length||dojo.some(_522,function(item,idx){return _523[idx]!=item;})){this.onChildrenChange(this.root,_523);}})});},onNewItem:function(item,_524){this._requeryTop();this.inherited(arguments);},onDeleteItem:function(item){if(dojo.indexOf(this.root.children,item)!=-1){this._requeryTop();}this.inherited(arguments);}});}if(!dojo._hasResource["dijit.Tree"]){dojo._hasResource["dijit.Tree"]=true;dojo.provide("dijit.Tree");dojo.declare("dijit._TreeNode",[dijit._Widget,dijit._Templated,dijit._Container,dijit._Contained,dijit._CssStateMixin],{item:null,isTreeNode:true,label:"",isExpandable:null,isExpanded:false,state:"UNCHECKED",templateString:dojo.cache("dijit","templates/TreeNode.html","<div class=\"dijitTreeNode\" waiRole=\"presentation\"\n\t><div dojoAttachPoint=\"rowNode\" class=\"dijitTreeRow\" waiRole=\"presentation\" dojoAttachEvent=\"onmouseenter:_onMouseEnter, onmouseleave:_onMouseLeave, onclick:_onClick, ondblclick:_onDblClick\"\n\t\t><img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"expandoNode\" class=\"dijitTreeExpando\" waiRole=\"presentation\"\n\t\t/><span dojoAttachPoint=\"expandoNodeText\" class=\"dijitExpandoText\" waiRole=\"presentation\"\n\t\t></span\n\t\t><span dojoAttachPoint=\"contentNode\"\n\t\t\tclass=\"dijitTreeContent\" waiRole=\"presentation\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"iconNode\" class=\"dijitIcon dijitTreeIcon\" waiRole=\"presentation\"\n\t\t\t/><span dojoAttachPoint=\"labelNode\" class=\"dijitTreeLabel\" wairole=\"treeitem\" tabindex=\"-1\" waiState=\"selected-false\" dojoAttachEvent=\"onfocus:_onLabelFocus\"></span>\n\t\t</span\n\t></div>\n\t<div dojoAttachPoint=\"containerNode\" class=\"dijitTreeContainer\" waiRole=\"presentation\" style=\"display: none;\"></div>\n</div>\n"),baseClass:"dijitTreeNode",cssStateNodes:{rowNode:"dijitTreeRow",labelNode:"dijitTreeLabel"},attributeMap:dojo.delegate(dijit._Widget.prototype.attributeMap,{label:{node:"labelNode",type:"innerText"},tooltip:{node:"rowNode",type:"attribute",attribute:"title"}}),postCreate:function(){this.inherited(arguments);this._setExpando();this._updateItemClasses(this.item);if(this.isExpandable){dijit.setWaiState(this.labelNode,"expanded",this.isExpanded);}},_setIndentAttr:function(_525){this.indent=_525;var _526=(Math.max(_525,0)*this.tree._nodePixelIndent)+"px";dojo.style(this.domNode,"backgroundPosition",_526+" 0px");dojo.style(this.rowNode,this.isLeftToRight()?"paddingLeft":"paddingRight",_526);dojo.forEach(this.getChildren(),function(_527){_527.set("indent",_525+1);});},markProcessing:function(){this.state="LOADING";this._setExpando(true);},unmarkProcessing:function(){this._setExpando(false);},_updateItemClasses:function(item){var tree=this.tree,_528=tree.model;if(tree._v10Compat&&item===_528.root){item=null;}this._applyClassAndStyle(item,"icon","Icon");this._applyClassAndStyle(item,"label","Label");this._applyClassAndStyle(item,"row","Row");},_applyClassAndStyle:function(item,_529,_52a){var _52b="_"+_529+"Class";var _52c=_529+"Node";if(this[_52b]){dojo.removeClass(this[_52c],this[_52b]);}this[_52b]=this.tree["get"+_52a+"Class"](item,this.isExpanded);if(this[_52b]){dojo.addClass(this[_52c],this[_52b]);}dojo.style(this[_52c],this.tree["get"+_52a+"Style"](item,this.isExpanded)||{});},_updateLayout:function(){var _52d=this.getParent();if(!_52d||_52d.rowNode.style.display=="none"){dojo.addClass(this.domNode,"dijitTreeIsRoot");}else{dojo.toggleClass(this.domNode,"dijitTreeIsLast",!this.getNextSibling());}},_setExpando:function(_52e){var _52f=["dijitTreeExpandoLoading","dijitTreeExpandoOpened","dijitTreeExpandoClosed","dijitTreeExpandoLeaf"],_530=["*","-","+","*"],idx=_52e?0:(this.isExpandable?(this.isExpanded?1:2):3);dojo.removeClass(this.expandoNode,_52f);dojo.addClass(this.expandoNode,_52f[idx]);this.expandoNodeText.innerHTML=_530[idx];},expand:function(){if(this._expandDeferred){return this._expandDeferred;}this._wipeOut&&this._wipeOut.stop();this.isExpanded=true;dijit.setWaiState(this.labelNode,"expanded","true");dijit.setWaiRole(this.containerNode,"group");dojo.addClass(this.contentNode,"dijitTreeContentExpanded");this._setExpando();this._updateItemClasses(this.item);if(this==this.tree.rootNode){dijit.setWaiState(this.tree.domNode,"expanded","true");}var def,_531=dojo.fx.wipeIn({node:this.containerNode,duration:dijit.defaultDuration,onEnd:function(){def.callback(true);}});def=(this._expandDeferred=new dojo.Deferred(function(){_531.stop();}));_531.play();return def;},collapse:function(){if(!this.isExpanded){return;}if(this._expandDeferred){this._expandDeferred.cancel();delete this._expandDeferred;}this.isExpanded=false;dijit.setWaiState(this.labelNode,"expanded","false");if(this==this.tree.rootNode){dijit.setWaiState(this.tree.domNode,"expanded","false");}dojo.removeClass(this.contentNode,"dijitTreeContentExpanded");this._setExpando();this._updateItemClasses(this.item);if(!this._wipeOut){this._wipeOut=dojo.fx.wipeOut({node:this.containerNode,duration:dijit.defaultDuration});}this._wipeOut.play();},indent:0,setChildItems:function(_532){var tree=this.tree,_533=tree.model,defs=[];dojo.forEach(this.getChildren(),function(_534){dijit._Container.prototype.removeChild.call(this,_534);},this);this.state="LOADED";if(_532&&_532.length>0){this.isExpandable=true;dojo.forEach(_532,function(item){var id=_533.getIdentity(item),_535=tree._itemNodesMap[id],node;if(_535){for(var i=0;i<_535.length;i++){if(_535[i]&&!_535[i].getParent()){node=_535[i];node.set("indent",this.indent+1);break;}}}if(!node){node=this.tree._createTreeNode({item:item,tree:tree,isExpandable:_533.mayHaveChildren(item),label:tree.getLabel(item),tooltip:tree.getTooltip(item),dir:tree.dir,lang:tree.lang,indent:this.indent+1});if(_535){_535.push(node);}else{tree._itemNodesMap[id]=[node];}}this.addChild(node);if(this.tree.autoExpand||this.tree._state(item)){defs.push(tree._expandNode(node));}},this);dojo.forEach(this.getChildren(),function(_536,idx){_536._updateLayout();});}else{this.isExpandable=false;}if(this._setExpando){this._setExpando(false);}this._updateItemClasses(this.item);if(this==tree.rootNode){var fc=this.tree.showRoot?this:this.getChildren()[0];if(fc){fc.setFocusable(true);tree.lastFocused=fc;}else{tree.domNode.setAttribute("tabIndex","0");}}return new dojo.DeferredList(defs);},removeChild:function(node){this.inherited(arguments);var _537=this.getChildren();if(_537.length==0){this.isExpandable=false;this.collapse();}dojo.forEach(_537,function(_538){_538._updateLayout();});},makeExpandable:function(){this.isExpandable=true;this._setExpando(false);},_onLabelFocus:function(evt){this.tree._onNodeFocus(this);},setSelected:function(_539){dijit.setWaiState(this.labelNode,"selected",_539);dojo.toggleClass(this.rowNode,"dijitTreeRowSelected",_539);},setFocusable:function(_53a){this.labelNode.setAttribute("tabIndex",_53a?"0":"-1");},_onClick:function(evt){this.tree._onClick(this,evt);},_onDblClick:function(evt){this.tree._onDblClick(this,evt);},_onMouseEnter:function(evt){this.tree._onNodeMouseEnter(this,evt);},_onMouseLeave:function(evt){this.tree._onNodeMouseLeave(this,evt);}});dojo.declare("dijit.Tree",[dijit._Widget,dijit._Templated],{store:null,model:null,query:null,label:"",showRoot:true,childrenAttr:["children"],path:[],selectedItem:null,openOnClick:false,openOnDblClick:false,templateString:dojo.cache("dijit","templates/Tree.html","<div class=\"dijitTree dijitTreeContainer\" waiRole=\"tree\"\n\tdojoAttachEvent=\"onkeypress:_onKeyPress\">\n\t<div class=\"dijitInline dijitTreeIndent\" style=\"position: absolute; top: -9999px\" dojoAttachPoint=\"indentDetector\"></div>\n</div>\n"),persist:true,autoExpand:false,dndController:null,dndParams:["onDndDrop","itemCreator","onDndCancel","checkAcceptance","checkItemAcceptance","dragThreshold","betweenThreshold"],onDndDrop:null,itemCreator:null,onDndCancel:null,checkAcceptance:null,checkItemAcceptance:null,dragThreshold:5,betweenThreshold:0,_nodePixelIndent:19,_publish:function(_53b,_53c){dojo.publish(this.id,[dojo.mixin({tree:this,event:_53b},_53c||{})]);},postMixInProperties:function(){this.tree=this;if(this.autoExpand){this.persist=false;}this._itemNodesMap={};if(!this.cookieName){this.cookieName=this.id+"SaveStateCookie";}this._loadDeferred=new dojo.Deferred();this.inherited(arguments);},postCreate:function(){this._initState();if(!this.model){this._store2model();}this.connect(this.model,"onChange","_onItemChange");this.connect(this.model,"onChildrenChange","_onItemChildrenChange");this.connect(this.model,"onDelete","_onItemDelete");this._load();this.inherited(arguments);if(this.dndController){if(dojo.isString(this.dndController)){this.dndController=dojo.getObject(this.dndController);}var _53d={};for(var i=0;i<this.dndParams.length;i++){if(this[this.dndParams[i]]){_53d[this.dndParams[i]]=this[this.dndParams[i]];}}this.dndController=new this.dndController(this,_53d);}},_store2model:function(){this._v10Compat=true;dojo.deprecated("Tree: from version 2.0, should specify a model object rather than a store/query");var _53e={id:this.id+"_ForestStoreModel",store:this.store,query:this.query,childrenAttrs:this.childrenAttr};if(this.params.mayHaveChildren){_53e.mayHaveChildren=dojo.hitch(this,"mayHaveChildren");}if(this.params.getItemChildren){_53e.getChildren=dojo.hitch(this,function(item,_53f,_540){this.getItemChildren((this._v10Compat&&item===this.model.root)?null:item,_53f,_540);});}this.model=new dijit.tree.ForestStoreModel(_53e);this.showRoot=Boolean(this.label);},onLoad:function(){},_load:function(){this.model.getRoot(dojo.hitch(this,function(item){var rn=(this.rootNode=this.tree._createTreeNode({item:item,tree:this,isExpandable:true,label:this.label||this.getLabel(item),indent:this.showRoot?0:-1}));if(!this.showRoot){rn.rowNode.style.display="none";}this.domNode.appendChild(rn.domNode);var _541=this.model.getIdentity(item);if(this._itemNodesMap[_541]){this._itemNodesMap[_541].push(rn);}else{this._itemNodesMap[_541]=[rn];}rn._updateLayout();this._expandNode(rn).addCallback(dojo.hitch(this,function(){this._loadDeferred.callback(true);this.onLoad();}));}),function(err){console.error(this,": error loading root: ",err);});},getNodesByItem:function(item){if(!item){return [];}var _542=dojo.isString(item)?item:this.model.getIdentity(item);return [].concat(this._itemNodesMap[_542]);},_setSelectedItemAttr:function(item){var _543=this.get("selectedItem");var _544=(!item||dojo.isString(item))?item:this.model.getIdentity(item);if(_544==_543?this.model.getIdentity(_543):null){return;}var _545=this._itemNodesMap[_544];this._selectNode((_545&&_545[0])||null);},_getSelectedItemAttr:function(){return this.selectedNode&&this.selectedNode.item;},_setPathAttr:function(path){var d=new dojo.Deferred();this._selectNode(null);if(!path||!path.length){d.resolve(true);return d;}this._loadDeferred.addCallback(dojo.hitch(this,function(){if(!this.rootNode){d.reject(new Error("!this.rootNode"));return;}if(path[0]!==this.rootNode.item&&(dojo.isString(path[0])&&path[0]!=this.model.getIdentity(this.rootNode.item))){d.reject(new Error(this.id+":path[0] doesn't match this.rootNode.item. Maybe you are using the wrong tree."));return;}path.shift();var node=this.rootNode;function _546(){var item=path.shift(),_547=dojo.isString(item)?item:this.model.getIdentity(item);dojo.some(this._itemNodesMap[_547],function(n){if(n.getParent()==node){node=n;return true;}return false;});if(path.length){this._expandNode(node).addCallback(dojo.hitch(this,_546));}else{this._selectNode(node);d.resolve(true);}};this._expandNode(node).addCallback(dojo.hitch(this,_546));}));return d;},_getPathAttr:function(){if(!this.selectedNode){return;}var res=[];var _548=this.selectedNode;while(_548&&_548!==this.rootNode){res.unshift(_548.item);_548=_548.getParent();}res.unshift(this.rootNode.item);return res;},mayHaveChildren:function(item){},getItemChildren:function(_549,_54a){},getLabel:function(item){return this.model.getLabel(item);},getIconClass:function(item,_54b){return (!item||this.model.mayHaveChildren(item))?(_54b?"dijitFolderOpened":"dijitFolderClosed"):"dijitLeaf";},getLabelClass:function(item,_54c){},getRowClass:function(item,_54d){},getIconStyle:function(item,_54e){},getLabelStyle:function(item,_54f){},getRowStyle:function(item,_550){},getTooltip:function(item){return "";},_onKeyPress:function(e){if(e.altKey){return;}var dk=dojo.keys;var _551=dijit.getEnclosingWidget(e.target);if(!_551){return;}var key=e.charOrCode;if(typeof key=="string"){if(!e.altKey&&!e.ctrlKey&&!e.shiftKey&&!e.metaKey){this._onLetterKeyNav({node:_551,key:key.toLowerCase()});dojo.stopEvent(e);}}else{if(this._curSearch){clearTimeout(this._curSearch.timer);delete this._curSearch;}var map=this._keyHandlerMap;if(!map){map={};map[dk.ENTER]="_onEnterKey";map[this.isLeftToRight()?dk.LEFT_ARROW:dk.RIGHT_ARROW]="_onLeftArrow";map[this.isLeftToRight()?dk.RIGHT_ARROW:dk.LEFT_ARROW]="_onRightArrow";map[dk.UP_ARROW]="_onUpArrow";map[dk.DOWN_ARROW]="_onDownArrow";map[dk.HOME]="_onHomeKey";map[dk.END]="_onEndKey";this._keyHandlerMap=map;}if(this._keyHandlerMap[key]){this[this._keyHandlerMap[key]]({node:_551,item:_551.item,evt:e});dojo.stopEvent(e);}}},_onEnterKey:function(_552,evt){this._publish("execute",{item:_552.item,node:_552.node});this._selectNode(_552.node);this.onClick(_552.item,_552.node,evt);},_onDownArrow:function(_553){var node=this._getNextNode(_553.node);if(node&&node.isTreeNode){this.focusNode(node);}},_onUpArrow:function(_554){var node=_554.node;var _555=node.getPreviousSibling();if(_555){node=_555;while(node.isExpandable&&node.isExpanded&&node.hasChildren()){var _556=node.getChildren();node=_556[_556.length-1];}}else{var _557=node.getParent();if(!(!this.showRoot&&_557===this.rootNode)){node=_557;}}if(node&&node.isTreeNode){this.focusNode(node);}},_onRightArrow:function(_558){var node=_558.node;if(node.isExpandable&&!node.isExpanded){this._expandNode(node);}else{if(node.hasChildren()){node=node.getChildren()[0];if(node&&node.isTreeNode){this.focusNode(node);}}}},_onLeftArrow:function(_559){var node=_559.node;if(node.isExpandable&&node.isExpanded){this._collapseNode(node);}else{var _55a=node.getParent();if(_55a&&_55a.isTreeNode&&!(!this.showRoot&&_55a===this.rootNode)){this.focusNode(_55a);}}},_onHomeKey:function(){var node=this._getRootOrFirstNode();if(node){this.focusNode(node);}},_onEndKey:function(_55b){var node=this.rootNode;while(node.isExpanded){var c=node.getChildren();node=c[c.length-1];}if(node&&node.isTreeNode){this.focusNode(node);}},multiCharSearchDuration:250,_onLetterKeyNav:function(_55c){var cs=this._curSearch;if(cs){cs.pattern=cs.pattern+_55c.key;clearTimeout(cs.timer);}else{cs=this._curSearch={pattern:_55c.key,startNode:_55c.node};}var self=this;cs.timer=setTimeout(function(){delete self._curSearch;},this.multiCharSearchDuration);var node=cs.startNode;do{node=this._getNextNode(node);if(!node){node=this._getRootOrFirstNode();}}while(node!==cs.startNode&&(node.label.toLowerCase().substr(0,cs.pattern.length)!=cs.pattern));if(node&&node.isTreeNode){if(node!==cs.startNode){this.focusNode(node);}}},_onClick:function(_55d,e){var _55e=e.target,_55f=(_55e==_55d.expandoNode||_55e==_55d.expandoNodeText);if((this.openOnClick&&_55d.isExpandable)||_55f){if(_55d.isExpandable){this._onExpandoClick({node:_55d});}}else{this._publish("execute",{item:_55d.item,node:_55d,evt:e});this.onClick(_55d.item,_55d,e);this.focusNode(_55d);}if(!_55f){this._selectNode(_55d);}dojo.stopEvent(e);},_onDblClick:function(_560,e){var _561=e.target,_562=(_561==_560.expandoNode||_561==_560.expandoNodeText);if((this.openOnDblClick&&_560.isExpandable)||_562){if(_560.isExpandable){this._onExpandoClick({node:_560});}}else{this._publish("execute",{item:_560.item,node:_560,evt:e});this.onDblClick(_560.item,_560,e);this.focusNode(_560);}if(!_562){this._selectNode(_560);}dojo.stopEvent(e);},_onExpandoClick:function(_563){var node=_563.node;this.focusNode(node);if(node.isExpanded){this._collapseNode(node);}else{this._expandNode(node);}},onClick:function(item,node,evt){},onDblClick:function(item,node,evt){},onOpen:function(item,node){},onClose:function(item,node){},_getNextNode:function(node){if(node.isExpandable&&node.isExpanded&&node.hasChildren()){return node.getChildren()[0];}else{while(node&&node.isTreeNode){var _564=node.getNextSibling();if(_564){return _564;}node=node.getParent();}return null;}},_getRootOrFirstNode:function(){return this.showRoot?this.rootNode:this.rootNode.getChildren()[0];},_collapseNode:function(node){if(node._expandNodeDeferred){delete node._expandNodeDeferred;}if(node.isExpandable){if(node.state=="LOADING"){return;}node.collapse();this.onClose(node.item,node);if(node.item){this._state(node.item,false);this._saveState();}}},_expandNode:function(node,_565){if(node._expandNodeDeferred&&!_565){return node._expandNodeDeferred;}var _566=this.model,item=node.item,_567=this;switch(node.state){case "UNCHECKED":node.markProcessing();var def=(node._expandNodeDeferred=new dojo.Deferred());_566.getChildren(item,function(_568){node.unmarkProcessing();var scid=node.setChildItems(_568);var ed=_567._expandNode(node,true);scid.addCallback(function(){ed.addCallback(function(){def.callback();});});},function(err){console.error(_567,": error loading root children: ",err);});break;default:def=(node._expandNodeDeferred=node.expand());this.onOpen(node.item,node);if(item){this._state(item,true);this._saveState();}}return def;},focusNode:function(node){dijit.focus(node.labelNode);},_selectNode:function(node){if(this.selectedNode&&!this.selectedNode._destroyed){this.selectedNode.setSelected(false);}if(node){node.setSelected(true);}this.selectedNode=node;},_onNodeFocus:function(node){if(node&&node!=this.lastFocused){if(this.lastFocused&&!this.lastFocused._destroyed){this.lastFocused.setFocusable(false);}node.setFocusable(true);this.lastFocused=node;}},_onNodeMouseEnter:function(node){},_onNodeMouseLeave:function(node){},_onItemChange:function(item){var _569=this.model,_56a=_569.getIdentity(item),_56b=this._itemNodesMap[_56a];if(_56b){var _56c=this.getLabel(item),_56d=this.getTooltip(item);dojo.forEach(_56b,function(node){node.set({item:item,label:_56c,tooltip:_56d});node._updateItemClasses(item);});}},_onItemChildrenChange:function(_56e,_56f){var _570=this.model,_571=_570.getIdentity(_56e),_572=this._itemNodesMap[_571];if(_572){dojo.forEach(_572,function(_573){_573.setChildItems(_56f);});}},_onItemDelete:function(item){var _574=this.model,_575=_574.getIdentity(item),_576=this._itemNodesMap[_575];if(_576){dojo.forEach(_576,function(node){var _577=node.getParent();if(_577){_577.removeChild(node);}node.destroyRecursive();});delete this._itemNodesMap[_575];}},_initState:function(){if(this.persist){var _578=dojo.cookie(this.cookieName);this._openedItemIds={};if(_578){dojo.forEach(_578.split(","),function(item){this._openedItemIds[item]=true;},this);}}},_state:function(item,_579){if(!this.persist){return false;}var id=this.model.getIdentity(item);if(arguments.length===1){return this._openedItemIds[id];}if(_579){this._openedItemIds[id]=true;}else{delete this._openedItemIds[id];}},_saveState:function(){if(!this.persist){return;}var ary=[];for(var id in this._openedItemIds){ary.push(id);}dojo.cookie(this.cookieName,ary.join(","),{expires:365});},destroy:function(){if(this._curSearch){clearTimeout(this._curSearch.timer);delete this._curSearch;}if(this.rootNode){this.rootNode.destroyRecursive();}if(this.dndController&&!dojo.isString(this.dndController)){this.dndController.destroy();}this.rootNode=null;this.inherited(arguments);},destroyRecursive:function(){this.destroy();},resize:function(_57a){if(_57a){dojo.marginBox(this.domNode,_57a);dojo.style(this.domNode,"overflow","auto");}this._nodePixelIndent=dojo.marginBox(this.tree.indentDetector).w;if(this.tree.rootNode){this.tree.rootNode.set("indent",this.showRoot?0:-1);}},_createTreeNode:function(args){return new dijit._TreeNode(args);}});}if(!dojo._hasResource["dojo.dnd.Container"]){dojo._hasResource["dojo.dnd.Container"]=true;dojo.provide("dojo.dnd.Container");dojo.declare("dojo.dnd.Container",null,{skipForm:false,constructor:function(node,_57b){this.node=dojo.byId(node);if(!_57b){_57b={};}this.creator=_57b.creator||null;this.skipForm=_57b.skipForm;this.parent=_57b.dropParent&&dojo.byId(_57b.dropParent);this.map={};this.current=null;this.containerState="";dojo.addClass(this.node,"dojoDndContainer");if(!(_57b&&_57b._skipStartup)){this.startup();}this.events=[dojo.connect(this.node,"onmouseover",this,"onMouseOver"),dojo.connect(this.node,"onmouseout",this,"onMouseOut"),dojo.connect(this.node,"ondragstart",this,"onSelectStart"),dojo.connect(this.node,"onselectstart",this,"onSelectStart")];},creator:function(){},getItem:function(key){return this.map[key];},setItem:function(key,data){this.map[key]=data;},delItem:function(key){delete this.map[key];},forInItems:function(f,o){o=o||dojo.global;var m=this.map,e=dojo.dnd._empty;for(var i in m){if(i in e){continue;}f.call(o,m[i],i,this);}return o;},clearItems:function(){this.map={};},getAllNodes:function(){return dojo.query("> .dojoDndItem",this.parent);},sync:function(){var map={};this.getAllNodes().forEach(function(node){if(node.id){var item=this.getItem(node.id);if(item){map[node.id]=item;return;}}else{node.id=dojo.dnd.getUniqueId();}var type=node.getAttribute("dndType"),data=node.getAttribute("dndData");map[node.id]={data:data||node.innerHTML,type:type?type.split(/\s*,\s*/):["text"]};},this);this.map=map;return this;},insertNodes:function(data,_57c,_57d){if(!this.parent.firstChild){_57d=null;}else{if(_57c){if(!_57d){_57d=this.parent.firstChild;}}else{if(_57d){_57d=_57d.nextSibling;}}}if(_57d){for(var i=0;i<data.length;++i){var t=this._normalizedCreator(data[i]);this.setItem(t.node.id,{data:t.data,type:t.type});this.parent.insertBefore(t.node,_57d);}}else{for(var i=0;i<data.length;++i){var t=this._normalizedCreator(data[i]);this.setItem(t.node.id,{data:t.data,type:t.type});this.parent.appendChild(t.node);}}return this;},destroy:function(){dojo.forEach(this.events,dojo.disconnect);this.clearItems();this.node=this.parent=this.current=null;},markupFactory:function(_57e,node){_57e._skipStartup=true;return new dojo.dnd.Container(node,_57e);},startup:function(){if(!this.parent){this.parent=this.node;if(this.parent.tagName.toLowerCase()=="table"){var c=this.parent.getElementsByTagName("tbody");if(c&&c.length){this.parent=c[0];}}}this.defaultCreator=dojo.dnd._defaultCreator(this.parent);this.sync();},onMouseOver:function(e){var n=e.relatedTarget;while(n){if(n==this.node){break;}try{n=n.parentNode;}catch(x){n=null;}}if(!n){this._changeState("Container","Over");this.onOverEvent();}n=this._getChildByEvent(e);if(this.current==n){return;}if(this.current){this._removeItemClass(this.current,"Over");}if(n){this._addItemClass(n,"Over");}this.current=n;},onMouseOut:function(e){for(var n=e.relatedTarget;n;){if(n==this.node){return;}try{n=n.parentNode;}catch(x){n=null;}}if(this.current){this._removeItemClass(this.current,"Over");this.current=null;}this._changeState("Container","");this.onOutEvent();},onSelectStart:function(e){if(!this.skipForm||!dojo.dnd.isFormElement(e)){dojo.stopEvent(e);}},onOverEvent:function(){},onOutEvent:function(){},_changeState:function(type,_57f){var _580="dojoDnd"+type;var _581=type.toLowerCase()+"State";dojo.removeClass(this.node,_580+this[_581]);dojo.addClass(this.node,_580+_57f);this[_581]=_57f;},_addItemClass:function(node,type){dojo.addClass(node,"dojoDndItem"+type);},_removeItemClass:function(node,type){dojo.removeClass(node,"dojoDndItem"+type);},_getChildByEvent:function(e){var node=e.target;if(node){for(var _582=node.parentNode;_582;node=_582,_582=node.parentNode){if(_582==this.parent&&dojo.hasClass(node,"dojoDndItem")){return node;}}}return null;},_normalizedCreator:function(item,hint){var t=(this.creator||this.defaultCreator).call(this,item,hint);if(!dojo.isArray(t.type)){t.type=["text"];}if(!t.node.id){t.node.id=dojo.dnd.getUniqueId();}dojo.addClass(t.node,"dojoDndItem");return t;}});dojo.dnd._createNode=function(tag){if(!tag){return dojo.dnd._createSpan;}return function(text){return dojo.create(tag,{innerHTML:text});};};dojo.dnd._createTrTd=function(text){var tr=dojo.create("tr");dojo.create("td",{innerHTML:text},tr);return tr;};dojo.dnd._createSpan=function(text){return dojo.create("span",{innerHTML:text});};dojo.dnd._defaultCreatorNodes={ul:"li",ol:"li",div:"div",p:"div"};dojo.dnd._defaultCreator=function(node){var tag=node.tagName.toLowerCase();var c=tag=="tbody"||tag=="thead"?dojo.dnd._createTrTd:dojo.dnd._createNode(dojo.dnd._defaultCreatorNodes[tag]);return function(item,hint){var _583=item&&dojo.isObject(item),data,type,n;if(_583&&item.tagName&&item.nodeType&&item.getAttribute){data=item.getAttribute("dndData")||item.innerHTML;type=item.getAttribute("dndType");type=type?type.split(/\s*,\s*/):["text"];n=item;}else{data=(_583&&item.data)?item.data:item;type=(_583&&item.type)?item.type:["text"];n=(hint=="avatar"?dojo.dnd._createSpan:c)(String(data));}if(!n.id){n.id=dojo.dnd.getUniqueId();}return {node:n,data:data,type:type};};};}if(!dojo._hasResource["dijit.tree._dndContainer"]){dojo._hasResource["dijit.tree._dndContainer"]=true;dojo.provide("dijit.tree._dndContainer");dojo.declare("dijit.tree._dndContainer",null,{constructor:function(tree,_584){this.tree=tree;this.node=tree.domNode;dojo.mixin(this,_584);this.map={};this.current=null;this.containerState="";dojo.addClass(this.node,"dojoDndContainer");this.events=[dojo.connect(this.node,"onmouseenter",this,"onOverEvent"),dojo.connect(this.node,"onmouseleave",this,"onOutEvent"),dojo.connect(this.tree,"_onNodeMouseEnter",this,"onMouseOver"),dojo.connect(this.tree,"_onNodeMouseLeave",this,"onMouseOut"),dojo.connect(this.node,"ondragstart",dojo,"stopEvent"),dojo.connect(this.node,"onselectstart",dojo,"stopEvent")];},getItem:function(key){var node=this.selection[key],ret={data:dijit.getEnclosingWidget(node),type:["treeNode"]};return ret;},destroy:function(){dojo.forEach(this.events,dojo.disconnect);this.node=this.parent=null;},onMouseOver:function(_585,evt){this.current=_585.rowNode;this.currentWidget=_585;},onMouseOut:function(_586,evt){this.current=null;this.currentWidget=null;},_changeState:function(type,_587){var _588="dojoDnd"+type;var _589=type.toLowerCase()+"State";dojo.removeClass(this.node,_588+this[_589]);dojo.addClass(this.node,_588+_587);this[_589]=_587;},_addItemClass:function(node,type){dojo.addClass(node,"dojoDndItem"+type);},_removeItemClass:function(node,type){dojo.removeClass(node,"dojoDndItem"+type);},onOverEvent:function(){this._changeState("Container","Over");},onOutEvent:function(){this._changeState("Container","");}});}if(!dojo._hasResource["dijit.tree._dndSelector"]){dojo._hasResource["dijit.tree._dndSelector"]=true;dojo.provide("dijit.tree._dndSelector");dojo.declare("dijit.tree._dndSelector",dijit.tree._dndContainer,{constructor:function(tree,_58a){this.selection={};this.anchor=null;this.simpleSelection=false;this.events.push(dojo.connect(this.tree.domNode,"onmousedown",this,"onMouseDown"),dojo.connect(this.tree.domNode,"onmouseup",this,"onMouseUp"),dojo.connect(this.tree.domNode,"onmousemove",this,"onMouseMove"));},singular:false,getSelectedNodes:function(){return this.selection;},selectNone:function(){return this._removeSelection()._removeAnchor();},destroy:function(){this.inherited(arguments);this.selection=this.anchor=null;},onMouseDown:function(e){if(!this.current){return;}if(e.button==dojo.mouseButtons.RIGHT){return;}var _58b=dijit.getEnclosingWidget(this.current),id=_58b.id+"-dnd";if(!dojo.hasAttr(this.current,"id")){dojo.attr(this.current,"id",id);}if(!this.singular&&!dojo.isCopyKey(e)&&!e.shiftKey&&(this.current.id in this.selection)){this.simpleSelection=true;dojo.stopEvent(e);return;}if(this.singular){if(this.anchor==this.current){if(dojo.isCopyKey(e)){this.selectNone();}}else{this.selectNone();this.anchor=this.current;this._addItemClass(this.anchor,"Anchor");this.selection[this.current.id]=this.current;}}else{if(!this.singular&&e.shiftKey){if(dojo.isCopyKey(e)){}else{}}else{if(dojo.isCopyKey(e)){if(this.anchor==this.current){delete this.selection[this.anchor.id];this._removeAnchor();}else{if(this.current.id in this.selection){this._removeItemClass(this.current,"Selected");delete this.selection[this.current.id];}else{if(this.anchor){this._removeItemClass(this.anchor,"Anchor");this._addItemClass(this.anchor,"Selected");}this.anchor=this.current;this._addItemClass(this.current,"Anchor");this.selection[this.current.id]=this.current;}}}else{if(!(id in this.selection)){this.selectNone();this.anchor=this.current;this._addItemClass(this.current,"Anchor");this.selection[id]=this.current;}}}}dojo.stopEvent(e);},onMouseUp:function(e){if(!this.simpleSelection){return;}this.simpleSelection=false;this.selectNone();if(this.current){this.anchor=this.current;this._addItemClass(this.anchor,"Anchor");this.selection[this.current.id]=this.current;}},onMouseMove:function(e){this.simpleSelection=false;},_removeSelection:function(){var e=dojo.dnd._empty;for(var i in this.selection){if(i in e){continue;}var node=dojo.byId(i);if(node){this._removeItemClass(node,"Selected");}}this.selection={};return this;},_removeAnchor:function(){if(this.anchor){this._removeItemClass(this.anchor,"Anchor");this.anchor=null;}return this;},forInSelectedItems:function(f,o){o=o||dojo.global;for(var id in this.selection){console.log("selected item id: "+id);f.call(o,this.getItem(id),id,this);}}});}if(!dojo._hasResource["dojo.dnd.Avatar"]){dojo._hasResource["dojo.dnd.Avatar"]=true;dojo.provide("dojo.dnd.Avatar");dojo.declare("dojo.dnd.Avatar",null,{constructor:function(_58c){this.manager=_58c;this.construct();},construct:function(){this.isA11y=dojo.hasClass(dojo.body(),"dijit_a11y");var a=dojo.create("table",{"class":"dojoDndAvatar",style:{position:"absolute",zIndex:"1999",margin:"0px"}}),_58d=this.manager.source,node,b=dojo.create("tbody",null,a),tr=dojo.create("tr",null,b),td=dojo.create("td",null,tr),icon=this.isA11y?dojo.create("span",{id:"a11yIcon",innerHTML:this.manager.copy?"+":"<"},td):null,span=dojo.create("span",{innerHTML:_58d.generateText?this._generateText():""},td),k=Math.min(5,this.manager.nodes.length),i=0;dojo.attr(tr,{"class":"dojoDndAvatarHeader",style:{opacity:0.9}});for(;i<k;++i){if(_58d.creator){node=_58d._normalizedCreator(_58d.getItem(this.manager.nodes[i].id).data,"avatar").node;}else{node=this.manager.nodes[i].cloneNode(true);if(node.tagName.toLowerCase()=="tr"){var _58e=dojo.create("table"),_58f=dojo.create("tbody",null,_58e);_58f.appendChild(node);node=_58e;}}node.id="";tr=dojo.create("tr",null,b);td=dojo.create("td",null,tr);td.appendChild(node);dojo.attr(tr,{"class":"dojoDndAvatarItem",style:{opacity:(9-i)/10}});}this.node=a;},destroy:function(){dojo.destroy(this.node);this.node=false;},update:function(){dojo[(this.manager.canDropFlag?"add":"remove")+"Class"](this.node,"dojoDndAvatarCanDrop");if(this.isA11y){var icon=dojo.byId("a11yIcon");var text="+";if(this.manager.canDropFlag&&!this.manager.copy){text="< ";}else{if(!this.manager.canDropFlag&&!this.manager.copy){text="o";}else{if(!this.manager.canDropFlag){text="x";}}}icon.innerHTML=text;}dojo.query(("tr.dojoDndAvatarHeader td span"+(this.isA11y?" span":"")),this.node).forEach(function(node){node.innerHTML=this._generateText();},this);},_generateText:function(){return this.manager.nodes.length.toString();}});}if(!dojo._hasResource["dojo.dnd.Manager"]){dojo._hasResource["dojo.dnd.Manager"]=true;dojo.provide("dojo.dnd.Manager");dojo.declare("dojo.dnd.Manager",null,{constructor:function(){this.avatar=null;this.source=null;this.nodes=[];this.copy=true;this.target=null;this.canDropFlag=false;this.events=[];},OFFSET_X:16,OFFSET_Y:16,overSource:function(_590){if(this.avatar){this.target=(_590&&_590.targetState!="Disabled")?_590:null;this.canDropFlag=Boolean(this.target);this.avatar.update();}dojo.publish("/dnd/source/over",[_590]);},outSource:function(_591){if(this.avatar){if(this.target==_591){this.target=null;this.canDropFlag=false;this.avatar.update();dojo.publish("/dnd/source/over",[null]);}}else{dojo.publish("/dnd/source/over",[null]);}},startDrag:function(_592,_593,copy){this.source=_592;this.nodes=_593;this.copy=Boolean(copy);this.avatar=this.makeAvatar();dojo.body().appendChild(this.avatar.node);dojo.publish("/dnd/start",[_592,_593,this.copy]);this.events=[dojo.connect(dojo.doc,"onmousemove",this,"onMouseMove"),dojo.connect(dojo.doc,"onmouseup",this,"onMouseUp"),dojo.connect(dojo.doc,"onkeydown",this,"onKeyDown"),dojo.connect(dojo.doc,"onkeyup",this,"onKeyUp"),dojo.connect(dojo.doc,"ondragstart",dojo.stopEvent),dojo.connect(dojo.body(),"onselectstart",dojo.stopEvent)];var c="dojoDnd"+(copy?"Copy":"Move");dojo.addClass(dojo.body(),c);},canDrop:function(flag){var _594=Boolean(this.target&&flag);if(this.canDropFlag!=_594){this.canDropFlag=_594;this.avatar.update();}},stopDrag:function(){dojo.removeClass(dojo.body(),"dojoDndCopy");dojo.removeClass(dojo.body(),"dojoDndMove");dojo.forEach(this.events,dojo.disconnect);this.events=[];this.avatar.destroy();this.avatar=null;this.source=this.target=null;this.nodes=[];},makeAvatar:function(){return new dojo.dnd.Avatar(this);},updateAvatar:function(){this.avatar.update();},onMouseMove:function(e){var a=this.avatar;if(a){dojo.dnd.autoScrollNodes(e);var s=a.node.style;s.left=(e.pageX+this.OFFSET_X)+"px";s.top=(e.pageY+this.OFFSET_Y)+"px";var copy=Boolean(this.source.copyState(dojo.isCopyKey(e)));if(this.copy!=copy){this._setCopyStatus(copy);}}},onMouseUp:function(e){if(this.avatar){if(this.target&&this.canDropFlag){var copy=Boolean(this.source.copyState(dojo.isCopyKey(e))),_595=[this.source,this.nodes,copy,this.target,e];dojo.publish("/dnd/drop/before",_595);dojo.publish("/dnd/drop",_595);}else{dojo.publish("/dnd/cancel");}this.stopDrag();}},onKeyDown:function(e){if(this.avatar){switch(e.keyCode){case dojo.keys.CTRL:var copy=Boolean(this.source.copyState(true));if(this.copy!=copy){this._setCopyStatus(copy);}break;case dojo.keys.ESCAPE:dojo.publish("/dnd/cancel");this.stopDrag();break;}}},onKeyUp:function(e){if(this.avatar&&e.keyCode==dojo.keys.CTRL){var copy=Boolean(this.source.copyState(false));if(this.copy!=copy){this._setCopyStatus(copy);}}},_setCopyStatus:function(copy){this.copy=copy;this.source._markDndStatus(this.copy);this.updateAvatar();dojo.removeClass(dojo.body(),"dojoDnd"+(this.copy?"Move":"Copy"));dojo.addClass(dojo.body(),"dojoDnd"+(this.copy?"Copy":"Move"));}});dojo.dnd._manager=null;dojo.dnd.manager=function(){if(!dojo.dnd._manager){dojo.dnd._manager=new dojo.dnd.Manager();}return dojo.dnd._manager;};}if(!dojo._hasResource["dijit.tree.dndSource"]){dojo._hasResource["dijit.tree.dndSource"]=true;dojo.provide("dijit.tree.dndSource");dojo.declare("dijit.tree.dndSource",dijit.tree._dndSelector,{isSource:true,accept:["text","treeNode"],copyOnly:false,dragThreshold:5,betweenThreshold:0,constructor:function(tree,_596){if(!_596){_596={};}dojo.mixin(this,_596);this.isSource=typeof _596.isSource=="undefined"?true:_596.isSource;var type=_596.accept instanceof Array?_596.accept:["text","treeNode"];this.accept=null;if(type.length){this.accept={};for(var i=0;i<type.length;++i){this.accept[type[i]]=1;}}this.isDragging=false;this.mouseDown=false;this.targetAnchor=null;this.targetBox=null;this.dropPosition="";this._lastX=0;this._lastY=0;this.sourceState="";if(this.isSource){dojo.addClass(this.node,"dojoDndSource");}this.targetState="";if(this.accept){dojo.addClass(this.node,"dojoDndTarget");}this.topics=[dojo.subscribe("/dnd/source/over",this,"onDndSourceOver"),dojo.subscribe("/dnd/start",this,"onDndStart"),dojo.subscribe("/dnd/drop",this,"onDndDrop"),dojo.subscribe("/dnd/cancel",this,"onDndCancel")];},checkAcceptance:function(_597,_598){return true;},copyState:function(_599){return this.copyOnly||_599;},destroy:function(){this.inherited("destroy",arguments);dojo.forEach(this.topics,dojo.unsubscribe);this.targetAnchor=null;},_onDragMouse:function(e){var m=dojo.dnd.manager(),_59a=this.targetAnchor,_59b=this.current,_59c=this.currentWidget,_59d=this.dropPosition;var _59e="Over";if(_59b&&this.betweenThreshold>0){if(!this.targetBox||_59a!=_59b){this.targetBox=dojo.position(_59b,true);}if((e.pageY-this.targetBox.y)<=this.betweenThreshold){_59e="Before";}else{if((e.pageY-this.targetBox.y)>=(this.targetBox.h-this.betweenThreshold)){_59e="After";}}}if(_59b!=_59a||_59e!=_59d){if(_59a){this._removeItemClass(_59a,_59d);}if(_59b){this._addItemClass(_59b,_59e);}if(!_59b){m.canDrop(false);}else{if(_59c==this.tree.rootNode&&_59e!="Over"){m.canDrop(false);}else{if(m.source==this&&(_59b.id in this.selection)){m.canDrop(false);}else{if(this.checkItemAcceptance(_59b,m.source,_59e.toLowerCase())&&!this._isParentChildDrop(m.source,_59b)){m.canDrop(true);}else{m.canDrop(false);}}}}this.targetAnchor=_59b;this.dropPosition=_59e;}},onMouseMove:function(e){if(this.isDragging&&this.targetState=="Disabled"){return;}this.inherited(arguments);var m=dojo.dnd.manager();if(this.isDragging){this._onDragMouse(e);}else{if(this.mouseDown&&this.isSource&&(Math.abs(e.pageX-this._lastX)>=this.dragThreshold||Math.abs(e.pageY-this._lastY)>=this.dragThreshold)){var n=this.getSelectedNodes();var _59f=[];for(var i in n){_59f.push(n[i]);}if(_59f.length){m.startDrag(this,_59f,this.copyState(dojo.isCopyKey(e)));}}}},onMouseDown:function(e){this.mouseDown=true;this.mouseButton=e.button;this._lastX=e.pageX;this._lastY=e.pageY;this.inherited("onMouseDown",arguments);},onMouseUp:function(e){if(this.mouseDown){this.mouseDown=false;this.inherited("onMouseUp",arguments);}},onMouseOut:function(){this.inherited(arguments);this._unmarkTargetAnchor();},checkItemAcceptance:function(_5a0,_5a1,_5a2){return true;},onDndSourceOver:function(_5a3){if(this!=_5a3){this.mouseDown=false;this._unmarkTargetAnchor();}else{if(this.isDragging){var m=dojo.dnd.manager();m.canDrop(false);}}},onDndStart:function(_5a4,_5a5,copy){if(this.isSource){this._changeState("Source",this==_5a4?(copy?"Copied":"Moved"):"");}var _5a6=this.checkAcceptance(_5a4,_5a5);this._changeState("Target",_5a6?"":"Disabled");if(this==_5a4){dojo.dnd.manager().overSource(this);}this.isDragging=true;},itemCreator:function(_5a7,_5a8,_5a9){return dojo.map(_5a7,function(node){return {"id":node.id,"name":node.textContent||node.innerText||""};});},onDndDrop:function(_5aa,_5ab,copy){if(this.containerState=="Over"){var tree=this.tree,_5ac=tree.model,_5ad=this.targetAnchor,_5ae=false;this.isDragging=false;var _5af=dijit.getEnclosingWidget(_5ad);var _5b0;var _5b1;_5b0=(_5af&&_5af.item)||tree.item;if(this.dropPosition=="Before"||this.dropPosition=="After"){_5b0=(_5af.getParent()&&_5af.getParent().item)||tree.item;_5b1=_5af.getIndexInParent();if(this.dropPosition=="After"){_5b1=_5af.getIndexInParent()+1;}}else{_5b0=(_5af&&_5af.item)||tree.item;}var _5b2;dojo.forEach(_5ab,function(node,idx){var _5b3=_5aa.getItem(node.id);if(dojo.indexOf(_5b3.type,"treeNode")!=-1){var _5b4=_5b3.data,_5b5=_5b4.item,_5b6=_5b4.getParent().item;}if(_5aa==this){if(typeof _5b1=="number"){if(_5b0==_5b6&&_5b4.getIndexInParent()<_5b1){_5b1-=1;}}_5ac.pasteItem(_5b5,_5b6,_5b0,copy,_5b1);}else{if(_5ac.isItem(_5b5)){_5ac.pasteItem(_5b5,_5b6,_5b0,copy,_5b1);}else{if(!_5b2){_5b2=this.itemCreator(_5ab,_5ad,_5aa);}_5ac.newItem(_5b2[idx],_5b0,_5b1);}}},this);this.tree._expandNode(_5af);}this.onDndCancel();},onDndCancel:function(){this._unmarkTargetAnchor();this.isDragging=false;this.mouseDown=false;delete this.mouseButton;this._changeState("Source","");this._changeState("Target","");},onOverEvent:function(){this.inherited(arguments);dojo.dnd.manager().overSource(this);},onOutEvent:function(){this._unmarkTargetAnchor();var m=dojo.dnd.manager();if(this.isDragging){m.canDrop(false);}m.outSource(this);this.inherited(arguments);},_isParentChildDrop:function(_5b7,_5b8){if(!_5b7.tree||_5b7.tree!=this.tree){return false;}var root=_5b7.tree.domNode;var ids={};for(var x in _5b7.selection){ids[_5b7.selection[x].parentNode.id]=true;}var node=_5b8.parentNode;while(node!=root&&(!node.id||!ids[node.id])){node=node.parentNode;}return node.id&&ids[node.id];},_unmarkTargetAnchor:function(){if(!this.targetAnchor){return;}this._removeItemClass(this.targetAnchor,this.dropPosition);this.targetAnchor=null;this.targetBox=null;this.dropPosition=null;},_markDndStatus:function(copy){this._changeState("Source",copy?"Copied":"Moved");}});}if(!dojo._hasResource["dojo.data.ItemFileReadStore"]){dojo._hasResource["dojo.data.ItemFileReadStore"]=true;dojo.provide("dojo.data.ItemFileReadStore");dojo.declare("dojo.data.ItemFileReadStore",null,{constructor:function(_5b9){this._arrayOfAllItems=[];this._arrayOfTopLevelItems=[];this._loadFinished=false;this._jsonFileUrl=_5b9.url;this._ccUrl=_5b9.url;this.url=_5b9.url;this._jsonData=_5b9.data;this.data=null;this._datatypeMap=_5b9.typeMap||{};if(!this._datatypeMap["Date"]){this._datatypeMap["Date"]={type:Date,deserialize:function(_5ba){return dojo.date.stamp.fromISOString(_5ba);}};}this._features={"dojo.data.api.Read":true,"dojo.data.api.Identity":true};this._itemsByIdentity=null;this._storeRefPropName="_S";this._itemNumPropName="_0";this._rootItemPropName="_RI";this._reverseRefMap="_RRM";this._loadInProgress=false;this._queuedFetches=[];if(_5b9.urlPreventCache!==undefined){this.urlPreventCache=_5b9.urlPreventCache?true:false;}if(_5b9.hierarchical!==undefined){this.hierarchical=_5b9.hierarchical?true:false;}if(_5b9.clearOnClose){this.clearOnClose=true;}if("failOk" in _5b9){this.failOk=_5b9.failOk?true:false;}},url:"",_ccUrl:"",data:null,typeMap:null,clearOnClose:false,urlPreventCache:false,failOk:false,hierarchical:true,_assertIsItem:function(item){if(!this.isItem(item)){throw new Error("dojo.data.ItemFileReadStore: Invalid item argument.");}},_assertIsAttribute:function(_5bb){if(typeof _5bb!=="string"){throw new Error("dojo.data.ItemFileReadStore: Invalid attribute argument.");}},getValue:function(item,_5bc,_5bd){var _5be=this.getValues(item,_5bc);return (_5be.length>0)?_5be[0]:_5bd;},getValues:function(item,_5bf){this._assertIsItem(item);this._assertIsAttribute(_5bf);return (item[_5bf]||[]).slice(0);},getAttributes:function(item){this._assertIsItem(item);var _5c0=[];for(var key in item){if((key!==this._storeRefPropName)&&(key!==this._itemNumPropName)&&(key!==this._rootItemPropName)&&(key!==this._reverseRefMap)){_5c0.push(key);}}return _5c0;},hasAttribute:function(item,_5c1){this._assertIsItem(item);this._assertIsAttribute(_5c1);return (_5c1 in item);},containsValue:function(item,_5c2,_5c3){var _5c4=undefined;if(typeof _5c3==="string"){_5c4=dojo.data.util.filter.patternToRegExp(_5c3,false);}return this._containsValue(item,_5c2,_5c3,_5c4);},_containsValue:function(item,_5c5,_5c6,_5c7){return dojo.some(this.getValues(item,_5c5),function(_5c8){if(_5c8!==null&&!dojo.isObject(_5c8)&&_5c7){if(_5c8.toString().match(_5c7)){return true;}}else{if(_5c6===_5c8){return true;}}});},isItem:function(_5c9){if(_5c9&&_5c9[this._storeRefPropName]===this){if(this._arrayOfAllItems[_5c9[this._itemNumPropName]]===_5c9){return true;}}return false;},isItemLoaded:function(_5ca){return this.isItem(_5ca);},loadItem:function(_5cb){this._assertIsItem(_5cb.item);},getFeatures:function(){return this._features;},getLabel:function(item){if(this._labelAttr&&this.isItem(item)){return this.getValue(item,this._labelAttr);}return undefined;},getLabelAttributes:function(item){if(this._labelAttr){return [this._labelAttr];}return null;},_fetchItems:function(_5cc,_5cd,_5ce){var self=this,_5cf=function(_5d0,_5d1){var _5d2=[],i,key;if(_5d0.query){var _5d3,_5d4=_5d0.queryOptions?_5d0.queryOptions.ignoreCase:false;var _5d5={};for(key in _5d0.query){_5d3=_5d0.query[key];if(typeof _5d3==="string"){_5d5[key]=dojo.data.util.filter.patternToRegExp(_5d3,_5d4);}else{if(_5d3 instanceof RegExp){_5d5[key]=_5d3;}}}for(i=0;i<_5d1.length;++i){var _5d6=true;var _5d7=_5d1[i];if(_5d7===null){_5d6=false;}else{for(key in _5d0.query){_5d3=_5d0.query[key];if(!self._containsValue(_5d7,key,_5d3,_5d5[key])){_5d6=false;}}}if(_5d6){_5d2.push(_5d7);}}_5cd(_5d2,_5d0);}else{for(i=0;i<_5d1.length;++i){var item=_5d1[i];if(item!==null){_5d2.push(item);}}_5cd(_5d2,_5d0);}};if(this._loadFinished){_5cf(_5cc,this._getItemsArray(_5cc.queryOptions));}else{if(this._jsonFileUrl!==this._ccUrl){dojo.deprecated("dojo.data.ItemFileReadStore: ","To change the url, set the url property of the store,"+" not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");this._ccUrl=this._jsonFileUrl;this.url=this._jsonFileUrl;}else{if(this.url!==this._ccUrl){this._jsonFileUrl=this.url;this._ccUrl=this.url;}}if(this.data!=null&&this._jsonData==null){this._jsonData=this.data;this.data=null;}if(this._jsonFileUrl){if(this._loadInProgress){this._queuedFetches.push({args:_5cc,filter:_5cf});}else{this._loadInProgress=true;var _5d8={url:self._jsonFileUrl,handleAs:"json-comment-optional",preventCache:this.urlPreventCache,failOk:this.failOk};var _5d9=dojo.xhrGet(_5d8);_5d9.addCallback(function(data){try{self._getItemsFromLoadedData(data);self._loadFinished=true;self._loadInProgress=false;_5cf(_5cc,self._getItemsArray(_5cc.queryOptions));self._handleQueuedFetches();}catch(e){self._loadFinished=true;self._loadInProgress=false;_5ce(e,_5cc);}});_5d9.addErrback(function(_5da){self._loadInProgress=false;_5ce(_5da,_5cc);});var _5db=null;if(_5cc.abort){_5db=_5cc.abort;}_5cc.abort=function(){var df=_5d9;if(df&&df.fired===-1){df.cancel();df=null;}if(_5db){_5db.call(_5cc);}};}}else{if(this._jsonData){try{this._loadFinished=true;this._getItemsFromLoadedData(this._jsonData);this._jsonData=null;_5cf(_5cc,this._getItemsArray(_5cc.queryOptions));}catch(e){_5ce(e,_5cc);}}else{_5ce(new Error("dojo.data.ItemFileReadStore: No JSON source data was provided as either URL or a nested Javascript object."),_5cc);}}}},_handleQueuedFetches:function(){if(this._queuedFetches.length>0){for(var i=0;i<this._queuedFetches.length;i++){var _5dc=this._queuedFetches[i],_5dd=_5dc.args,_5de=_5dc.filter;if(_5de){_5de(_5dd,this._getItemsArray(_5dd.queryOptions));}else{this.fetchItemByIdentity(_5dd);}}this._queuedFetches=[];}},_getItemsArray:function(_5df){if(_5df&&_5df.deep){return this._arrayOfAllItems;}return this._arrayOfTopLevelItems;},close:function(_5e0){if(this.clearOnClose&&this._loadFinished&&!this._loadInProgress){if(((this._jsonFileUrl==""||this._jsonFileUrl==null)&&(this.url==""||this.url==null))&&this.data==null){console.debug("dojo.data.ItemFileReadStore: WARNING! Data reload "+" information has not been provided."+" Please set 'url' or 'data' to the appropriate value before"+" the next fetch");}this._arrayOfAllItems=[];this._arrayOfTopLevelItems=[];this._loadFinished=false;this._itemsByIdentity=null;this._loadInProgress=false;this._queuedFetches=[];}},_getItemsFromLoadedData:function(_5e1){var _5e2=false,self=this;function _5e3(_5e4){var _5e5=((_5e4!==null)&&(typeof _5e4==="object")&&(!dojo.isArray(_5e4)||_5e2)&&(!dojo.isFunction(_5e4))&&(_5e4.constructor==Object||dojo.isArray(_5e4))&&(typeof _5e4._reference==="undefined")&&(typeof _5e4._type==="undefined")&&(typeof _5e4._value==="undefined")&&self.hierarchical);return _5e5;};function _5e6(_5e7){self._arrayOfAllItems.push(_5e7);for(var _5e8 in _5e7){var _5e9=_5e7[_5e8];if(_5e9){if(dojo.isArray(_5e9)){var _5ea=_5e9;for(var k=0;k<_5ea.length;++k){var _5eb=_5ea[k];if(_5e3(_5eb)){_5e6(_5eb);}}}else{if(_5e3(_5e9)){_5e6(_5e9);}}}}};this._labelAttr=_5e1.label;var i,item;this._arrayOfAllItems=[];this._arrayOfTopLevelItems=_5e1.items;for(i=0;i<this._arrayOfTopLevelItems.length;++i){item=this._arrayOfTopLevelItems[i];if(dojo.isArray(item)){_5e2=true;}_5e6(item);item[this._rootItemPropName]=true;}var _5ec={},key;for(i=0;i<this._arrayOfAllItems.length;++i){item=this._arrayOfAllItems[i];for(key in item){if(key!==this._rootItemPropName){var _5ed=item[key];if(_5ed!==null){if(!dojo.isArray(_5ed)){item[key]=[_5ed];}}else{item[key]=[null];}}_5ec[key]=key;}}while(_5ec[this._storeRefPropName]){this._storeRefPropName+="_";}while(_5ec[this._itemNumPropName]){this._itemNumPropName+="_";}while(_5ec[this._reverseRefMap]){this._reverseRefMap+="_";}var _5ee;var _5ef=_5e1.identifier;if(_5ef){this._itemsByIdentity={};this._features["dojo.data.api.Identity"]=_5ef;for(i=0;i<this._arrayOfAllItems.length;++i){item=this._arrayOfAllItems[i];_5ee=item[_5ef];var _5f0=_5ee[0];if(!this._itemsByIdentity[_5f0]){this._itemsByIdentity[_5f0]=item;}else{if(this._jsonFileUrl){throw new Error("dojo.data.ItemFileReadStore: The json data as specified by: ["+this._jsonFileUrl+"] is malformed. Items within the list have identifier: ["+_5ef+"]. Value collided: ["+_5f0+"]");}else{if(this._jsonData){throw new Error("dojo.data.ItemFileReadStore: The json data provided by the creation arguments is malformed. Items within the list have identifier: ["+_5ef+"]. Value collided: ["+_5f0+"]");}}}}}else{this._features["dojo.data.api.Identity"]=Number;}for(i=0;i<this._arrayOfAllItems.length;++i){item=this._arrayOfAllItems[i];item[this._storeRefPropName]=this;item[this._itemNumPropName]=i;}for(i=0;i<this._arrayOfAllItems.length;++i){item=this._arrayOfAllItems[i];for(key in item){_5ee=item[key];for(var j=0;j<_5ee.length;++j){_5ed=_5ee[j];if(_5ed!==null&&typeof _5ed=="object"){if(("_type" in _5ed)&&("_value" in _5ed)){var type=_5ed._type;var _5f1=this._datatypeMap[type];if(!_5f1){throw new Error("dojo.data.ItemFileReadStore: in the typeMap constructor arg, no object class was specified for the datatype '"+type+"'");}else{if(dojo.isFunction(_5f1)){_5ee[j]=new _5f1(_5ed._value);}else{if(dojo.isFunction(_5f1.deserialize)){_5ee[j]=_5f1.deserialize(_5ed._value);}else{throw new Error("dojo.data.ItemFileReadStore: Value provided in typeMap was neither a constructor, nor a an object with a deserialize function");}}}}if(_5ed._reference){var _5f2=_5ed._reference;if(!dojo.isObject(_5f2)){_5ee[j]=this._getItemByIdentity(_5f2);}else{for(var k=0;k<this._arrayOfAllItems.length;++k){var _5f3=this._arrayOfAllItems[k],_5f4=true;for(var _5f5 in _5f2){if(_5f3[_5f5]!=_5f2[_5f5]){_5f4=false;}}if(_5f4){_5ee[j]=_5f3;}}}if(this.referenceIntegrity){var _5f6=_5ee[j];if(this.isItem(_5f6)){this._addReferenceToMap(_5f6,item,key);}}}else{if(this.isItem(_5ed)){if(this.referenceIntegrity){this._addReferenceToMap(_5ed,item,key);}}}}}}}},_addReferenceToMap:function(_5f7,_5f8,_5f9){},getIdentity:function(item){var _5fa=this._features["dojo.data.api.Identity"];if(_5fa===Number){return item[this._itemNumPropName];}else{var _5fb=item[_5fa];if(_5fb){return _5fb[0];}}return null;},fetchItemByIdentity:function(_5fc){var item,_5fd;if(!this._loadFinished){var self=this;if(this._jsonFileUrl!==this._ccUrl){dojo.deprecated("dojo.data.ItemFileReadStore: ","To change the url, set the url property of the store,"+" not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");this._ccUrl=this._jsonFileUrl;this.url=this._jsonFileUrl;}else{if(this.url!==this._ccUrl){this._jsonFileUrl=this.url;this._ccUrl=this.url;}}if(this.data!=null&&this._jsonData==null){this._jsonData=this.data;this.data=null;}if(this._jsonFileUrl){if(this._loadInProgress){this._queuedFetches.push({args:_5fc});}else{this._loadInProgress=true;var _5fe={url:self._jsonFileUrl,handleAs:"json-comment-optional",preventCache:this.urlPreventCache,failOk:this.failOk};var _5ff=dojo.xhrGet(_5fe);_5ff.addCallback(function(data){var _600=_5fc.scope?_5fc.scope:dojo.global;try{self._getItemsFromLoadedData(data);self._loadFinished=true;self._loadInProgress=false;item=self._getItemByIdentity(_5fc.identity);if(_5fc.onItem){_5fc.onItem.call(_600,item);}self._handleQueuedFetches();}catch(error){self._loadInProgress=false;if(_5fc.onError){_5fc.onError.call(_600,error);}}});_5ff.addErrback(function(_601){self._loadInProgress=false;if(_5fc.onError){var _602=_5fc.scope?_5fc.scope:dojo.global;_5fc.onError.call(_602,_601);}});}}else{if(this._jsonData){self._getItemsFromLoadedData(self._jsonData);self._jsonData=null;self._loadFinished=true;item=self._getItemByIdentity(_5fc.identity);if(_5fc.onItem){_5fd=_5fc.scope?_5fc.scope:dojo.global;_5fc.onItem.call(_5fd,item);}}}}else{item=this._getItemByIdentity(_5fc.identity);if(_5fc.onItem){_5fd=_5fc.scope?_5fc.scope:dojo.global;_5fc.onItem.call(_5fd,item);}}},_getItemByIdentity:function(_603){var item=null;if(this._itemsByIdentity){item=this._itemsByIdentity[_603];}else{item=this._arrayOfAllItems[_603];}if(item===undefined){item=null;}return item;},getIdentityAttributes:function(item){var _604=this._features["dojo.data.api.Identity"];if(_604===Number){return null;}else{return [_604];}},_forceLoad:function(){var self=this;if(this._jsonFileUrl!==this._ccUrl){dojo.deprecated("dojo.data.ItemFileReadStore: ","To change the url, set the url property of the store,"+" not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");this._ccUrl=this._jsonFileUrl;this.url=this._jsonFileUrl;}else{if(this.url!==this._ccUrl){this._jsonFileUrl=this.url;this._ccUrl=this.url;}}if(this.data!=null&&this._jsonData==null){this._jsonData=this.data;this.data=null;}if(this._jsonFileUrl){var _605={url:this._jsonFileUrl,handleAs:"json-comment-optional",preventCache:this.urlPreventCache,failOk:this.failOk,sync:true};var _606=dojo.xhrGet(_605);_606.addCallback(function(data){try{if(self._loadInProgress!==true&&!self._loadFinished){self._getItemsFromLoadedData(data);self._loadFinished=true;}else{if(self._loadInProgress){throw new Error("dojo.data.ItemFileReadStore: Unable to perform a synchronous load, an async load is in progress.");}}}catch(e){console.log(e);throw e;}});_606.addErrback(function(_607){throw _607;});}else{if(this._jsonData){self._getItemsFromLoadedData(self._jsonData);self._jsonData=null;self._loadFinished=true;}}}});dojo.extend(dojo.data.ItemFileReadStore,dojo.data.util.simpleFetch);}if(!dojo._hasResource["dojo.data.ItemFileWriteStore"]){dojo._hasResource["dojo.data.ItemFileWriteStore"]=true;dojo.provide("dojo.data.ItemFileWriteStore");dojo.declare("dojo.data.ItemFileWriteStore",dojo.data.ItemFileReadStore,{constructor:function(_608){this._features["dojo.data.api.Write"]=true;this._features["dojo.data.api.Notification"]=true;this._pending={_newItems:{},_modifiedItems:{},_deletedItems:{}};if(!this._datatypeMap["Date"].serialize){this._datatypeMap["Date"].serialize=function(obj){return dojo.date.stamp.toISOString(obj,{zulu:true});};}if(_608&&(_608.referenceIntegrity===false)){this.referenceIntegrity=false;}this._saveInProgress=false;},referenceIntegrity:true,_assert:function(_609){if(!_609){throw new Error("assertion failed in ItemFileWriteStore");}},_getIdentifierAttribute:function(){var _60a=this.getFeatures()["dojo.data.api.Identity"];return _60a;},newItem:function(_60b,_60c){this._assert(!this._saveInProgress);if(!this._loadFinished){this._forceLoad();}if(typeof _60b!="object"&&typeof _60b!="undefined"){throw new Error("newItem() was passed something other than an object");}var _60d=null;var _60e=this._getIdentifierAttribute();if(_60e===Number){_60d=this._arrayOfAllItems.length;}else{_60d=_60b[_60e];if(typeof _60d==="undefined"){throw new Error("newItem() was not passed an identity for the new item");}if(dojo.isArray(_60d)){throw new Error("newItem() was not passed an single-valued identity");}}if(this._itemsByIdentity){this._assert(typeof this._itemsByIdentity[_60d]==="undefined");}this._assert(typeof this._pending._newItems[_60d]==="undefined");this._assert(typeof this._pending._deletedItems[_60d]==="undefined");var _60f={};_60f[this._storeRefPropName]=this;_60f[this._itemNumPropName]=this._arrayOfAllItems.length;if(this._itemsByIdentity){this._itemsByIdentity[_60d]=_60f;_60f[_60e]=[_60d];}this._arrayOfAllItems.push(_60f);var _610=null;if(_60c&&_60c.parent&&_60c.attribute){_610={item:_60c.parent,attribute:_60c.attribute,oldValue:undefined};var _611=this.getValues(_60c.parent,_60c.attribute);if(_611&&_611.length>0){var _612=_611.slice(0,_611.length);if(_611.length===1){_610.oldValue=_611[0];}else{_610.oldValue=_611.slice(0,_611.length);}_612.push(_60f);this._setValueOrValues(_60c.parent,_60c.attribute,_612,false);_610.newValue=this.getValues(_60c.parent,_60c.attribute);}else{this._setValueOrValues(_60c.parent,_60c.attribute,_60f,false);_610.newValue=_60f;}}else{_60f[this._rootItemPropName]=true;this._arrayOfTopLevelItems.push(_60f);}this._pending._newItems[_60d]=_60f;for(var key in _60b){if(key===this._storeRefPropName||key===this._itemNumPropName){throw new Error("encountered bug in ItemFileWriteStore.newItem");}var _613=_60b[key];if(!dojo.isArray(_613)){_613=[_613];}_60f[key]=_613;if(this.referenceIntegrity){for(var i=0;i<_613.length;i++){var val=_613[i];if(this.isItem(val)){this._addReferenceToMap(val,_60f,key);}}}}this.onNew(_60f,_610);return _60f;},_removeArrayElement:function(_614,_615){var _616=dojo.indexOf(_614,_615);if(_616!=-1){_614.splice(_616,1);return true;}return false;},deleteItem:function(item){this._assert(!this._saveInProgress);this._assertIsItem(item);var _617=item[this._itemNumPropName];var _618=this.getIdentity(item);if(this.referenceIntegrity){var _619=this.getAttributes(item);if(item[this._reverseRefMap]){item["backup_"+this._reverseRefMap]=dojo.clone(item[this._reverseRefMap]);}dojo.forEach(_619,function(_61a){dojo.forEach(this.getValues(item,_61a),function(_61b){if(this.isItem(_61b)){if(!item["backupRefs_"+this._reverseRefMap]){item["backupRefs_"+this._reverseRefMap]=[];}item["backupRefs_"+this._reverseRefMap].push({id:this.getIdentity(_61b),attr:_61a});this._removeReferenceFromMap(_61b,item,_61a);}},this);},this);var _61c=item[this._reverseRefMap];if(_61c){for(var _61d in _61c){var _61e=null;if(this._itemsByIdentity){_61e=this._itemsByIdentity[_61d];}else{_61e=this._arrayOfAllItems[_61d];}if(_61e){for(var _61f in _61c[_61d]){var _620=this.getValues(_61e,_61f)||[];var _621=dojo.filter(_620,function(_622){return !(this.isItem(_622)&&this.getIdentity(_622)==_618);},this);this._removeReferenceFromMap(item,_61e,_61f);if(_621.length<_620.length){this._setValueOrValues(_61e,_61f,_621,true);}}}}}}this._arrayOfAllItems[_617]=null;item[this._storeRefPropName]=null;if(this._itemsByIdentity){delete this._itemsByIdentity[_618];}this._pending._deletedItems[_618]=item;if(item[this._rootItemPropName]){this._removeArrayElement(this._arrayOfTopLevelItems,item);}this.onDelete(item);return true;},setValue:function(item,_623,_624){return this._setValueOrValues(item,_623,_624,true);},setValues:function(item,_625,_626){return this._setValueOrValues(item,_625,_626,true);},unsetAttribute:function(item,_627){return this._setValueOrValues(item,_627,[],true);},_setValueOrValues:function(item,_628,_629,_62a){this._assert(!this._saveInProgress);this._assertIsItem(item);this._assert(dojo.isString(_628));this._assert(typeof _629!=="undefined");var _62b=this._getIdentifierAttribute();if(_628==_62b){throw new Error("ItemFileWriteStore does not have support for changing the value of an item's identifier.");}var _62c=this._getValueOrValues(item,_628);var _62d=this.getIdentity(item);if(!this._pending._modifiedItems[_62d]){var _62e={};for(var key in item){if((key===this._storeRefPropName)||(key===this._itemNumPropName)||(key===this._rootItemPropName)){_62e[key]=item[key];}else{if(key===this._reverseRefMap){_62e[key]=dojo.clone(item[key]);}else{_62e[key]=item[key].slice(0,item[key].length);}}}this._pending._modifiedItems[_62d]=_62e;}var _62f=false;if(dojo.isArray(_629)&&_629.length===0){_62f=delete item[_628];_629=undefined;if(this.referenceIntegrity&&_62c){var _630=_62c;if(!dojo.isArray(_630)){_630=[_630];}for(var i=0;i<_630.length;i++){var _631=_630[i];if(this.isItem(_631)){this._removeReferenceFromMap(_631,item,_628);}}}}else{var _632;if(dojo.isArray(_629)){var _633=_629;_632=_629.slice(0,_629.length);}else{_632=[_629];}if(this.referenceIntegrity){if(_62c){var _630=_62c;if(!dojo.isArray(_630)){_630=[_630];}var map={};dojo.forEach(_630,function(_634){if(this.isItem(_634)){var id=this.getIdentity(_634);map[id.toString()]=true;}},this);dojo.forEach(_632,function(_635){if(this.isItem(_635)){var id=this.getIdentity(_635);if(map[id.toString()]){delete map[id.toString()];}else{this._addReferenceToMap(_635,item,_628);}}},this);for(var rId in map){var _636;if(this._itemsByIdentity){_636=this._itemsByIdentity[rId];}else{_636=this._arrayOfAllItems[rId];}this._removeReferenceFromMap(_636,item,_628);}}else{for(var i=0;i<_632.length;i++){var _631=_632[i];if(this.isItem(_631)){this._addReferenceToMap(_631,item,_628);}}}}item[_628]=_632;_62f=true;}if(_62a){this.onSet(item,_628,_62c,_629);}return _62f;},_addReferenceToMap:function(_637,_638,_639){var _63a=this.getIdentity(_638);var _63b=_637[this._reverseRefMap];if(!_63b){_63b=_637[this._reverseRefMap]={};}var _63c=_63b[_63a];if(!_63c){_63c=_63b[_63a]={};}_63c[_639]=true;},_removeReferenceFromMap:function(_63d,_63e,_63f){var _640=this.getIdentity(_63e);var _641=_63d[this._reverseRefMap];var _642;if(_641){for(_642 in _641){if(_642==_640){delete _641[_642][_63f];if(this._isEmpty(_641[_642])){delete _641[_642];}}}if(this._isEmpty(_641)){delete _63d[this._reverseRefMap];}}},_dumpReferenceMap:function(){var i;for(i=0;i<this._arrayOfAllItems.length;i++){var item=this._arrayOfAllItems[i];if(item&&item[this._reverseRefMap]){console.log("Item: ["+this.getIdentity(item)+"] is referenced by: "+dojo.toJson(item[this._reverseRefMap]));}}},_getValueOrValues:function(item,_643){var _644=undefined;if(this.hasAttribute(item,_643)){var _645=this.getValues(item,_643);if(_645.length==1){_644=_645[0];}else{_644=_645;}}return _644;},_flatten:function(_646){if(this.isItem(_646)){var item=_646;var _647=this.getIdentity(item);var _648={_reference:_647};return _648;}else{if(typeof _646==="object"){for(var type in this._datatypeMap){var _649=this._datatypeMap[type];if(dojo.isObject(_649)&&!dojo.isFunction(_649)){if(_646 instanceof _649.type){if(!_649.serialize){throw new Error("ItemFileWriteStore: No serializer defined for type mapping: ["+type+"]");}return {_type:type,_value:_649.serialize(_646)};}}else{if(_646 instanceof _649){return {_type:type,_value:_646.toString()};}}}}return _646;}},_getNewFileContentString:function(){var _64a={};var _64b=this._getIdentifierAttribute();if(_64b!==Number){_64a.identifier=_64b;}if(this._labelAttr){_64a.label=this._labelAttr;}_64a.items=[];for(var i=0;i<this._arrayOfAllItems.length;++i){var item=this._arrayOfAllItems[i];if(item!==null){var _64c={};for(var key in item){if(key!==this._storeRefPropName&&key!==this._itemNumPropName&&key!==this._reverseRefMap&&key!==this._rootItemPropName){var _64d=key;var _64e=this.getValues(item,_64d);if(_64e.length==1){_64c[_64d]=this._flatten(_64e[0]);}else{var _64f=[];for(var j=0;j<_64e.length;++j){_64f.push(this._flatten(_64e[j]));_64c[_64d]=_64f;}}}}_64a.items.push(_64c);}}var _650=true;return dojo.toJson(_64a,_650);},_isEmpty:function(_651){var _652=true;if(dojo.isObject(_651)){var i;for(i in _651){_652=false;break;}}else{if(dojo.isArray(_651)){if(_651.length>0){_652=false;}}}return _652;},save:function(_653){this._assert(!this._saveInProgress);this._saveInProgress=true;var self=this;var _654=function(){self._pending={_newItems:{},_modifiedItems:{},_deletedItems:{}};self._saveInProgress=false;if(_653&&_653.onComplete){var _655=_653.scope||dojo.global;_653.onComplete.call(_655);}};var _656=function(err){self._saveInProgress=false;if(_653&&_653.onError){var _657=_653.scope||dojo.global;_653.onError.call(_657,err);}};if(this._saveEverything){var _658=this._getNewFileContentString();this._saveEverything(_654,_656,_658);}if(this._saveCustom){this._saveCustom(_654,_656);}if(!this._saveEverything&&!this._saveCustom){_654();}},revert:function(){this._assert(!this._saveInProgress);var _659;for(_659 in this._pending._modifiedItems){var _65a=this._pending._modifiedItems[_659];var _65b=null;if(this._itemsByIdentity){_65b=this._itemsByIdentity[_659];}else{_65b=this._arrayOfAllItems[_659];}_65a[this._storeRefPropName]=this;for(key in _65b){delete _65b[key];}dojo.mixin(_65b,_65a);}var _65c;for(_659 in this._pending._deletedItems){_65c=this._pending._deletedItems[_659];_65c[this._storeRefPropName]=this;var _65d=_65c[this._itemNumPropName];if(_65c["backup_"+this._reverseRefMap]){_65c[this._reverseRefMap]=_65c["backup_"+this._reverseRefMap];delete _65c["backup_"+this._reverseRefMap];}this._arrayOfAllItems[_65d]=_65c;if(this._itemsByIdentity){this._itemsByIdentity[_659]=_65c;}if(_65c[this._rootItemPropName]){this._arrayOfTopLevelItems.push(_65c);}}for(_659 in this._pending._deletedItems){_65c=this._pending._deletedItems[_659];if(_65c["backupRefs_"+this._reverseRefMap]){dojo.forEach(_65c["backupRefs_"+this._reverseRefMap],function(_65e){var _65f;if(this._itemsByIdentity){_65f=this._itemsByIdentity[_65e.id];}else{_65f=this._arrayOfAllItems[_65e.id];}this._addReferenceToMap(_65f,_65c,_65e.attr);},this);delete _65c["backupRefs_"+this._reverseRefMap];}}for(_659 in this._pending._newItems){var _660=this._pending._newItems[_659];_660[this._storeRefPropName]=null;this._arrayOfAllItems[_660[this._itemNumPropName]]=null;if(_660[this._rootItemPropName]){this._removeArrayElement(this._arrayOfTopLevelItems,_660);}if(this._itemsByIdentity){delete this._itemsByIdentity[_659];}}this._pending={_newItems:{},_modifiedItems:{},_deletedItems:{}};return true;},isDirty:function(item){if(item){var _661=this.getIdentity(item);return new Boolean(this._pending._newItems[_661]||this._pending._modifiedItems[_661]||this._pending._deletedItems[_661]).valueOf();}else{if(!this._isEmpty(this._pending._newItems)||!this._isEmpty(this._pending._modifiedItems)||!this._isEmpty(this._pending._deletedItems)){return true;}return false;}},onSet:function(item,_662,_663,_664){},onNew:function(_665,_666){},onDelete:function(_667){},close:function(_668){if(this.clearOnClose){if(!this.isDirty()){this.inherited(arguments);}else{throw new Error("dojo.data.ItemFileWriteStore: There are unsaved changes present in the store. Please save or revert the changes before invoking close.");}}}});}dojo.i18n._preloadLocalizations("dojo.nls.tt-rss-layer",["ROOT","ar","ca","cs","da","de","de-de","el","en","en-gb","en-us","es","es-es","fi","fi-fi","fr","fr-fr","he","he-il","hu","it","it-it","ja","ja-jp","ko","ko-kr","nb","nl","nl-nl","pl","pt","pt-br","pt-pt","ru","sk","sl","sv","th","tr","xx","zh","zh-cn","zh-tw"]);
diff --git a/lib/dojo/tt-rss-layer.js.uncompressed.js b/lib/dojo/tt-rss-layer.js.uncompressed.js
new file mode 100644
index 000000000..fa2e12157
--- /dev/null
+++ b/lib/dojo/tt-rss-layer.js.uncompressed.js
@@ -0,0 +1,26844 @@
+/*
+ Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Available via Academic Free License >= 2.1 OR the modified BSD license.
+ see: http://dojotoolkit.org/license for details
+*/
+
+/*
+ This is an optimized version of Dojo, built for deployment and not for
+ development. To get sources and documentation, please visit:
+
+ http://dojotoolkit.org
+*/
+
+dojo.provide("tt-rss-layer");
+if(!dojo._hasResource["dojo.date.stamp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.date.stamp"] = true;
+dojo.provide("dojo.date.stamp");
+
+// Methods to convert dates to or from a wire (string) format using well-known conventions
+
+dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){
+ // summary:
+ // Returns a Date object given a string formatted according to a subset of the ISO-8601 standard.
+ //
+ // description:
+ // Accepts a string formatted according to a profile of ISO8601 as defined by
+ // [RFC3339](http://www.ietf.org/rfc/rfc3339.txt), except that partial input is allowed.
+ // Can also process dates as specified [by the W3C](http://www.w3.org/TR/NOTE-datetime)
+ // The following combinations are valid:
+ //
+ // * dates only
+ // | * yyyy
+ // | * yyyy-MM
+ // | * yyyy-MM-dd
+ // * times only, with an optional time zone appended
+ // | * THH:mm
+ // | * THH:mm:ss
+ // | * THH:mm:ss.SSS
+ // * and "datetimes" which could be any combination of the above
+ //
+ // timezones may be specified as Z (for UTC) or +/- followed by a time expression HH:mm
+ // Assumes the local time zone if not specified. Does not validate. Improperly formatted
+ // input may return null. Arguments which are out of bounds will be handled
+ // by the Date constructor (e.g. January 32nd typically gets resolved to February 1st)
+ // Only years between 100 and 9999 are supported.
+ //
+ // formattedString:
+ // A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00
+ //
+ // defaultTime:
+ // Used for defaults for fields omitted in the formattedString.
+ // Uses 1970-01-01T00:00:00.0Z by default.
+
+ if(!dojo.date.stamp._isoRegExp){
+ dojo.date.stamp._isoRegExp =
+//TODO: could be more restrictive and check for 00-59, etc.
+ /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/;
+ }
+
+ var match = dojo.date.stamp._isoRegExp.exec(formattedString),
+ result = null;
+
+ if(match){
+ match.shift();
+ if(match[1]){match[1]--;} // Javascript Date months are 0-based
+ if(match[6]){match[6] *= 1000;} // Javascript Date expects fractional seconds as milliseconds
+
+ if(defaultTime){
+ // mix in defaultTime. Relatively expensive, so use || operators for the fast path of defaultTime === 0
+ defaultTime = new Date(defaultTime);
+ dojo.forEach(dojo.map(["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"], function(prop){
+ return defaultTime["get" + prop]();
+ }), function(value, index){
+ match[index] = match[index] || value;
+ });
+ }
+ result = new Date(match[0]||1970, match[1]||0, match[2]||1, match[3]||0, match[4]||0, match[5]||0, match[6]||0); //TODO: UTC defaults
+ if(match[0] < 100){
+ result.setFullYear(match[0] || 1970);
+ }
+
+ var offset = 0,
+ zoneSign = match[7] && match[7].charAt(0);
+ if(zoneSign != 'Z'){
+ offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0);
+ if(zoneSign != '-'){ offset *= -1; }
+ }
+ if(zoneSign){
+ offset -= result.getTimezoneOffset();
+ }
+ if(offset){
+ result.setTime(result.getTime() + offset * 60000);
+ }
+ }
+
+ return result; // Date or null
+}
+
+/*=====
+ dojo.date.stamp.__Options = function(){
+ // selector: String
+ // "date" or "time" for partial formatting of the Date object.
+ // Both date and time will be formatted by default.
+ // zulu: Boolean
+ // if true, UTC/GMT is used for a timezone
+ // milliseconds: Boolean
+ // if true, output milliseconds
+ this.selector = selector;
+ this.zulu = zulu;
+ this.milliseconds = milliseconds;
+ }
+=====*/
+
+dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*dojo.date.stamp.__Options?*/options){
+ // summary:
+ // Format a Date object as a string according a subset of the ISO-8601 standard
+ //
+ // description:
+ // When options.selector is omitted, output follows [RFC3339](http://www.ietf.org/rfc/rfc3339.txt)
+ // The local time zone is included as an offset from GMT, except when selector=='time' (time without a date)
+ // Does not check bounds. Only years between 100 and 9999 are supported.
+ //
+ // dateObject:
+ // A Date object
+
+ var _ = function(n){ return (n < 10) ? "0" + n : n; };
+ options = options || {};
+ var formattedDate = [],
+ getter = options.zulu ? "getUTC" : "get",
+ date = "";
+ if(options.selector != "time"){
+ var year = dateObject[getter+"FullYear"]();
+ date = ["0000".substr((year+"").length)+year, _(dateObject[getter+"Month"]()+1), _(dateObject[getter+"Date"]())].join('-');
+ }
+ formattedDate.push(date);
+ if(options.selector != "date"){
+ var time = [_(dateObject[getter+"Hours"]()), _(dateObject[getter+"Minutes"]()), _(dateObject[getter+"Seconds"]())].join(':');
+ var millis = dateObject[getter+"Milliseconds"]();
+ if(options.milliseconds){
+ time += "."+ (millis < 100 ? "0" : "") + _(millis);
+ }
+ if(options.zulu){
+ time += "Z";
+ }else if(options.selector != "time"){
+ var timezoneOffset = dateObject.getTimezoneOffset();
+ var absOffset = Math.abs(timezoneOffset);
+ time += (timezoneOffset > 0 ? "-" : "+") +
+ _(Math.floor(absOffset/60)) + ":" + _(absOffset%60);
+ }
+ formattedDate.push(time);
+ }
+ return formattedDate.join('T'); // String
+}
+
+}
+
+if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.parser"] = true;
+dojo.provide("dojo.parser");
+
+
+new Date("X"); // workaround for #11279, new Date("") == NaN
+
+dojo.parser = new function(){
+ // summary: The Dom/Widget parsing package
+
+ var d = dojo;
+ this._attrName = d._scopeName + "Type";
+ this._query = "[" + this._attrName + "]";
+
+ function val2type(/*Object*/ value){
+ // summary:
+ // Returns name of type of given value.
+
+ if(d.isString(value)){ return "string"; }
+ if(typeof value == "number"){ return "number"; }
+ if(typeof value == "boolean"){ return "boolean"; }
+ if(d.isFunction(value)){ return "function"; }
+ if(d.isArray(value)){ return "array"; } // typeof [] == "object"
+ if(value instanceof Date) { return "date"; } // assume timestamp
+ if(value instanceof d._Url){ return "url"; }
+ return "object";
+ }
+
+ function str2obj(/*String*/ value, /*String*/ type){
+ // summary:
+ // Convert given string value to given type
+ switch(type){
+ case "string":
+ return value;
+ case "number":
+ return value.length ? Number(value) : NaN;
+ case "boolean":
+ // for checked/disabled value might be "" or "checked". interpret as true.
+ return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
+ case "function":
+ if(d.isFunction(value)){
+ // IE gives us a function, even when we say something like onClick="foo"
+ // (in which case it gives us an invalid function "function(){ foo }").
+ // Therefore, convert to string
+ value=value.toString();
+ value=d.trim(value.substring(value.indexOf('{')+1, value.length-1));
+ }
+ try{
+ if(value === "" || value.search(/[^\w\.]+/i) != -1){
+ // The user has specified some text for a function like "return x+5"
+ return new Function(value);
+ }else{
+ // The user has specified the name of a function like "myOnClick"
+ // or a single word function "return"
+ return d.getObject(value, false) || new Function(value);
+ }
+ }catch(e){ return new Function(); }
+ case "array":
+ return value ? value.split(/\s*,\s*/) : [];
+ case "date":
+ switch(value){
+ case "": return new Date(""); // the NaN of dates
+ case "now": return new Date(); // current date
+ default: return d.date.stamp.fromISOString(value);
+ }
+ case "url":
+ return d.baseUrl + value;
+ default:
+ return d.fromJson(value);
+ }
+ }
+
+ var instanceClasses = {
+ // map from fully qualified name (like "dijit.Button") to structure like
+ // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
+ };
+
+ // Widgets like BorderContainer add properties to _Widget via dojo.extend().
+ // If BorderContainer is loaded after _Widget's parameter list has been cached,
+ // we need to refresh that parameter list (for _Widget and all widgets that extend _Widget).
+ dojo.connect(dojo, "extend", function(){
+ instanceClasses = {};
+ });
+
+ function getClassInfo(/*String*/ className){
+ // className:
+ // fully qualified name (like "dijit.form.Button")
+ // returns:
+ // structure like
+ // {
+ // cls: dijit.Button,
+ // params: { label: "string", disabled: "boolean"}
+ // }
+
+ if(!instanceClasses[className]){
+ // get pointer to widget class
+ var cls = d.getObject(className);
+ if(!cls){ return null; } // class not defined [yet]
+
+ var proto = cls.prototype;
+
+ // get table of parameter names & types
+ var params = {}, dummyClass = {};
+ for(var name in proto){
+ if(name.charAt(0)=="_"){ continue; } // skip internal properties
+ if(name in dummyClass){ continue; } // skip "constructor" and "toString"
+ var defVal = proto[name];
+ params[name]=val2type(defVal);
+ }
+
+ instanceClasses[className] = { cls: cls, params: params };
+ }
+ return instanceClasses[className];
+ }
+
+ this._functionFromScript = function(script){
+ var preamble = "";
+ var suffix = "";
+ var argsStr = script.getAttribute("args");
+ if(argsStr){
+ d.forEach(argsStr.split(/\s*,\s*/), function(part, idx){
+ preamble += "var "+part+" = arguments["+idx+"]; ";
+ });
+ }
+ var withStr = script.getAttribute("with");
+ if(withStr && withStr.length){
+ d.forEach(withStr.split(/\s*,\s*/), function(part){
+ preamble += "with("+part+"){";
+ suffix += "}";
+ });
+ }
+ return new Function(preamble+script.innerHTML+suffix);
+ }
+
+ this.instantiate = function(/* Array */nodes, /* Object? */mixin, /* Object? */args){
+ // summary:
+ // Takes array of nodes, and turns them into class instances and
+ // potentially calls a startup method to allow them to connect with
+ // any children.
+ // nodes: Array
+ // Array of nodes or objects like
+ // | {
+ // | type: "dijit.form.Button",
+ // | node: DOMNode,
+ // | scripts: [ ... ], // array of <script type="dojo/..."> children of node
+ // | inherited: { ... } // settings inherited from ancestors like dir, theme, etc.
+ // | }
+ // mixin: Object?
+ // An object that will be mixed in with each node in the array.
+ // Values in the mixin will override values in the node, if they
+ // exist.
+ // args: Object?
+ // An object used to hold kwArgs for instantiation.
+ // Supports 'noStart' and inherited.
+ var thelist = [], dp = dojo.parser;
+ mixin = mixin||{};
+ args = args||{};
+
+ d.forEach(nodes, function(obj){
+ if(!obj){ return; }
+
+ // Get pointers to DOMNode, dojoType string, and clsInfo (metadata about the dojoType), etc.s
+ var node, type, clsInfo, clazz, scripts;
+ if(obj.node){
+ // new format of nodes[] array, object w/lots of properties pre-computed for me
+ node = obj.node;
+ type = obj.type;
+ clsInfo = obj.clsInfo || (type && getClassInfo(type));
+ clazz = clsInfo && clsInfo.cls;
+ scripts = obj.scripts;
+ }else{
+ // old (backwards compatible) format of nodes[] array, simple array of DOMNodes
+ node = obj;
+ type = dp._attrName in mixin ? mixin[dp._attrName] : node.getAttribute(dp._attrName);
+ clsInfo = type && getClassInfo(type);
+ clazz = clsInfo && clsInfo.cls;
+ scripts = (clazz && (clazz._noScript || clazz.prototype._noScript) ? [] :
+ d.query("> script[type^='dojo/']", node));
+ }
+ if(!clsInfo){
+ throw new Error("Could not load class '" + type);
+ }
+
+ // Setup hash to hold parameter settings for this widget. Start with the parameter
+ // settings inherited from ancestors ("dir" and "lang").
+ // Inherited setting may later be overridden by explicit settings on node itself.
+ var params = {},
+ attributes = node.attributes;
+ if(args.defaults){
+ // settings for the document itself (or whatever subtree is being parsed)
+ dojo.mixin(params, args.defaults);
+ }
+ if(obj.inherited){
+ // settings from dir=rtl or lang=... on a node above this node
+ dojo.mixin(params, obj.inherited);
+ }
+
+ // read parameters (ie, attributes) specified on DOMNode
+ // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
+ for(var name in clsInfo.params){
+ var item = name in mixin?{value:mixin[name],specified:true}:attributes.getNamedItem(name);
+ if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; }
+ var value = item.value;
+ // Deal with IE quirks for 'class' and 'style'
+ switch(name){
+ case "class":
+ value = "className" in mixin?mixin.className:node.className;
+ break;
+ case "style":
+ value = "style" in mixin?mixin.style:(node.style && node.style.cssText); // FIXME: Opera?
+ }
+ var _type = clsInfo.params[name];
+ if(typeof value == "string"){
+ params[name] = str2obj(value, _type);
+ }else{
+ params[name] = value;
+ }
+ }
+
+ // Process <script type="dojo/*"> script tags
+ // <script type="dojo/method" event="foo"> tags are added to params, and passed to
+ // the widget on instantiation.
+ // <script type="dojo/method"> tags (with no event) are executed after instantiation
+ // <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation
+ // note: dojo/* script tags cannot exist in self closing widgets, like <input />
+ var connects = [], // functions to connect after instantiation
+ calls = []; // functions to call after instantiation
+
+ d.forEach(scripts, function(script){
+ node.removeChild(script);
+ var event = script.getAttribute("event"),
+ type = script.getAttribute("type"),
+ nf = d.parser._functionFromScript(script);
+ if(event){
+ if(type == "dojo/connect"){
+ connects.push({event: event, func: nf});
+ }else{
+ params[event] = nf;
+ }
+ }else{
+ calls.push(nf);
+ }
+ });
+
+ var markupFactory = clazz.markupFactory || clazz.prototype && clazz.prototype.markupFactory;
+ // create the instance
+ var instance = markupFactory ? markupFactory(params, node, clazz) : new clazz(params, node);
+ thelist.push(instance);
+
+ // map it to the JS namespace if that makes sense
+ var jsname = node.getAttribute("jsId");
+ if(jsname){
+ d.setObject(jsname, instance);
+ }
+
+ // process connections and startup functions
+ d.forEach(connects, function(connect){
+ d.connect(instance, connect.event, null, connect.func);
+ });
+ d.forEach(calls, function(func){
+ func.call(instance);
+ });
+ });
+
+ // Call startup on each top level instance if it makes sense (as for
+ // widgets). Parent widgets will recursively call startup on their
+ // (non-top level) children
+ if(!mixin._started){
+ // TODO: for 2.0, when old instantiate() API is desupported, store parent-child
+ // relationships in the nodes[] array so that no getParent() call is needed.
+ // Note that will require a parse() call from ContentPane setting a param that the
+ // ContentPane is the parent widget (so that the parse doesn't call startup() on the
+ // ContentPane's children)
+ d.forEach(thelist, function(instance){
+ if( !args.noStart && instance &&
+ instance.startup &&
+ !instance._started &&
+ (!instance.getParent || !instance.getParent())
+ ){
+ instance.startup();
+ }
+ });
+ }
+ return thelist;
+ };
+
+ this.parse = function(/*DomNode?*/ rootNode, /* Object? */ args){
+ // summary:
+ // Scan the DOM for class instances, and instantiate them.
+ //
+ // description:
+ // Search specified node (or root node) recursively for class instances,
+ // and instantiate them Searches for
+ // dojoType="qualified.class.name"
+ //
+ // rootNode: DomNode?
+ // A default starting root node from which to start the parsing. Can be
+ // omitted, defaulting to the entire document. If omitted, the `args`
+ // object can be passed in this place. If the `args` object has a
+ // `rootNode` member, that is used.
+ //
+ // args:
+ // a kwArgs object passed along to instantiate()
+ //
+ // * noStart: Boolean?
+ // when set will prevent the parser from calling .startup()
+ // when locating the nodes.
+ // * rootNode: DomNode?
+ // identical to the function's `rootNode` argument, though
+ // allowed to be passed in via this `args object.
+ // * inherited: Object
+ // Hash possibly containing dir and lang settings to be applied to
+ // parsed widgets, unless there's another setting on a sub-node that overrides
+ //
+ //
+ // example:
+ // Parse all widgets on a page:
+ // | dojo.parser.parse();
+ //
+ // example:
+ // Parse all classes within the node with id="foo"
+ // | dojo.parser.parse(dojo.byId(foo));
+ //
+ // example:
+ // Parse all classes in a page, but do not call .startup() on any
+ // child
+ // | dojo.parser.parse({ noStart: true })
+ //
+ // example:
+ // Parse all classes in a node, but do not call .startup()
+ // | dojo.parser.parse(someNode, { noStart:true });
+ // | // or
+ // | dojo.parser.parse({ noStart:true, rootNode: someNode });
+
+ // determine the root node based on the passed arguments.
+ var root;
+ if(!args && rootNode && rootNode.rootNode){
+ args = rootNode;
+ root = args.rootNode;
+ }else{
+ root = rootNode;
+ }
+
+ var attrName = this._attrName;
+ function scan(parent, list){
+ // summary:
+ // Parent is an Object representing a DOMNode, with or without a dojoType specified.
+ // Scan parent's children looking for nodes with dojoType specified, storing in list[].
+ // If parent has a dojoType, also collects <script type=dojo/*> children and stores in parent.scripts[].
+ // parent: Object
+ // Object representing the parent node, like
+ // | {
+ // | node: DomNode, // scan children of this node
+ // | inherited: {dir: "rtl"}, // dir/lang setting inherited from above node
+ // |
+ // | // attributes only set if node has dojoType specified
+ // | scripts: [], // empty array, put <script type=dojo/*> in here
+ // | clsInfo: { cls: dijit.form.Button, ...}
+ // | }
+ // list: DomNode[]
+ // Output array of objects (same format as parent) representing nodes to be turned into widgets
+
+ // Effective dir and lang settings on parent node, either set directly or inherited from grandparent
+ var inherited = dojo.clone(parent.inherited);
+ dojo.forEach(["dir", "lang"], function(name){
+ var val = parent.node.getAttribute(name);
+ if(val){
+ inherited[name] = val;
+ }
+ });
+
+ // if parent is a widget, then search for <script type=dojo/*> tags and put them in scripts[].
+ var scripts = parent.scripts;
+
+ // unless parent is a widget with the stopParser flag set, continue search for dojoType, recursively
+ var recurse = !parent.clsInfo || !parent.clsInfo.cls.prototype.stopParser;
+
+ // scan parent's children looking for dojoType and <script type=dojo/*>
+ for(var child = parent.node.firstChild; child; child = child.nextSibling){
+ if(child.nodeType == 1){
+ var type = recurse && child.getAttribute(attrName);
+ if(type){
+ // if dojoType specified, add to output array of nodes to instantiate
+ var params = {
+ "type": type,
+ clsInfo: getClassInfo(type), // note: won't find classes declared via dojo.Declaration
+ node: child,
+ scripts: [], // <script> nodes that are parent's children
+ inherited: inherited // dir & lang attributes inherited from parent
+ };
+ list.push(params);
+
+ // Recurse, collecting <script type="dojo/..."> children, and also looking for
+ // descendant nodes with dojoType specified (unless the widget has the stopParser flag),
+ scan(params, list);
+ }else if(scripts && child.nodeName.toLowerCase() == "script"){
+ // if <script type="dojo/...">, save in scripts[]
+ type = child.getAttribute("type");
+ if (type && /^dojo\//i.test(type)) {
+ scripts.push(child);
+ }
+ }else if(recurse){
+ // Recurse, looking for grandchild nodes with dojoType specified
+ scan({
+ node: child,
+ inherited: inherited
+ }, list);
+ }
+ }
+ }
+ }
+
+ // Make list of all nodes on page w/dojoType specified
+ var list = [];
+ scan({
+ node: root ? dojo.byId(root) : dojo.body(),
+ inherited: (args && args.inherited) || {
+ dir: dojo._isBodyLtr() ? "ltr" : "rtl"
+ }
+ }, list);
+
+ // go build the object instances
+ return this.instantiate(list, null, args); // Array
+ };
+}();
+
+//Register the parser callback. It should be the first callback
+//after the a11y test.
+
+(function(){
+ var parseRunner = function(){
+ if(dojo.config.parseOnLoad){
+ dojo.parser.parse();
+ }
+ };
+
+ // FIXME: need to clobber cross-dependency!!
+ if(dojo.exists("dijit.wai.onload") && (dijit.wai.onload === dojo._loaders[0])){
+ dojo._loaders.splice(1, 0, parseRunner);
+ }else{
+ dojo._loaders.unshift(parseRunner);
+ }
+})();
+
+}
+
+if(!dojo._hasResource["dojo.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.window"] = true;
+dojo.provide("dojo.window");
+
+dojo.window.getBox = function(){
+ // summary:
+ // Returns the dimensions and scroll position of the viewable area of a browser window
+
+ var scrollRoot = (dojo.doc.compatMode == 'BackCompat') ? dojo.body() : dojo.doc.documentElement;
+
+ // get scroll position
+ var scroll = dojo._docScroll(); // scrollRoot.scrollTop/Left should work
+ return { w: scrollRoot.clientWidth, h: scrollRoot.clientHeight, l: scroll.x, t: scroll.y };
+};
+
+dojo.window.get = function(doc){
+ // summary:
+ // Get window object associated with document doc
+
+ // In some IE versions (at least 6.0), document.parentWindow does not return a
+ // reference to the real window object (maybe a copy), so we must fix it as well
+ // We use IE specific execScript to attach the real window reference to
+ // document._parentWindow for later use
+ if(dojo.isIE && window !== document.parentWindow){
+ /*
+ In IE 6, only the variable "window" can be used to connect events (others
+ may be only copies).
+ */
+ doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
+ //to prevent memory leak, unset it after use
+ //another possibility is to add an onUnload handler which seems overkill to me (liucougar)
+ var win = doc._parentWindow;
+ doc._parentWindow = null;
+ return win; // Window
+ }
+
+ return doc.parentWindow || doc.defaultView; // Window
+};
+
+dojo.window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
+ // summary:
+ // Scroll the passed node into view, if it is not already.
+
+ // don't rely on node.scrollIntoView working just because the function is there
+
+ try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method
+ node = dojo.byId(node);
+ var doc = node.ownerDocument || dojo.doc,
+ body = doc.body || dojo.body(),
+ html = doc.documentElement || body.parentNode,
+ isIE = dojo.isIE, isWK = dojo.isWebKit;
+ // if an untested browser, then use the native method
+ if((!(dojo.isMoz || isIE || isWK || dojo.isOpera) || node == body || node == html) && (typeof node.scrollIntoView != "undefined")){
+ node.scrollIntoView(false); // short-circuit to native if possible
+ return;
+ }
+ var backCompat = doc.compatMode == 'BackCompat',
+ clientAreaRoot = backCompat? body : html,
+ scrollRoot = isWK ? body : clientAreaRoot,
+ rootWidth = clientAreaRoot.clientWidth,
+ rootHeight = clientAreaRoot.clientHeight,
+ rtl = !dojo._isBodyLtr(),
+ nodePos = pos || dojo.position(node),
+ el = node.parentNode,
+ isFixed = function(el){
+ return ((isIE <= 6 || (isIE && backCompat))? false : (dojo.style(el, 'position').toLowerCase() == "fixed"));
+ };
+ if(isFixed(node)){ return; } // nothing to do
+
+ while(el){
+ if(el == body){ el = scrollRoot; }
+ var elPos = dojo.position(el),
+ fixedPos = isFixed(el);
+
+ if(el == scrollRoot){
+ elPos.w = rootWidth; elPos.h = rootHeight;
+ if(scrollRoot == html && isIE && rtl){ elPos.x += scrollRoot.offsetWidth-elPos.w; } // IE workaround where scrollbar causes negative x
+ if(elPos.x < 0 || !isIE){ elPos.x = 0; } // IE can have values > 0
+ if(elPos.y < 0 || !isIE){ elPos.y = 0; }
+ }else{
+ var pb = dojo._getPadBorderExtents(el);
+ elPos.w -= pb.w; elPos.h -= pb.h; elPos.x += pb.l; elPos.y += pb.t;
+ }
+
+ if(el != scrollRoot){ // body, html sizes already have the scrollbar removed
+ var clientSize = el.clientWidth,
+ scrollBarSize = elPos.w - clientSize;
+ if(clientSize > 0 && scrollBarSize > 0){
+ elPos.w = clientSize;
+ if(isIE && rtl){ elPos.x += scrollBarSize; }
+ }
+ clientSize = el.clientHeight;
+ scrollBarSize = elPos.h - clientSize;
+ if(clientSize > 0 && scrollBarSize > 0){
+ elPos.h = clientSize;
+ }
+ }
+ if(fixedPos){ // bounded by viewport, not parents
+ if(elPos.y < 0){
+ elPos.h += elPos.y; elPos.y = 0;
+ }
+ if(elPos.x < 0){
+ elPos.w += elPos.x; elPos.x = 0;
+ }
+ if(elPos.y + elPos.h > rootHeight){
+ elPos.h = rootHeight - elPos.y;
+ }
+ if(elPos.x + elPos.w > rootWidth){
+ elPos.w = rootWidth - elPos.x;
+ }
+ }
+ // calculate overflow in all 4 directions
+ var l = nodePos.x - elPos.x, // beyond left: < 0
+ t = nodePos.y - Math.max(elPos.y, 0), // beyond top: < 0
+ r = l + nodePos.w - elPos.w, // beyond right: > 0
+ bot = t + nodePos.h - elPos.h; // beyond bottom: > 0
+ if(r * l > 0){
+ var s = Math[l < 0? "max" : "min"](l, r);
+ nodePos.x += el.scrollLeft;
+ el.scrollLeft += (isIE >= 8 && !backCompat && rtl)? -s : s;
+ nodePos.x -= el.scrollLeft;
+ }
+ if(bot * t > 0){
+ nodePos.y += el.scrollTop;
+ el.scrollTop += Math[t < 0? "max" : "min"](t, bot);
+ nodePos.y -= el.scrollTop;
+ }
+ el = (el != scrollRoot) && !fixedPos && el.parentNode;
+ }
+ }catch(error){
+ console.error('scrollIntoView: ' + error);
+ node.scrollIntoView(false);
+ }
+};
+
+}
+
+if(!dojo._hasResource["dijit._base.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.manager"] = true;
+dojo.provide("dijit._base.manager");
+
+dojo.declare("dijit.WidgetSet", null, {
+ // summary:
+ // A set of widgets indexed by id. A default instance of this class is
+ // available as `dijit.registry`
+ //
+ // example:
+ // Create a small list of widgets:
+ // | var ws = new dijit.WidgetSet();
+ // | ws.add(dijit.byId("one"));
+ // | ws.add(dijit.byId("two"));
+ // | // destroy both:
+ // | ws.forEach(function(w){ w.destroy(); });
+ //
+ // example:
+ // Using dijit.registry:
+ // | dijit.registry.forEach(function(w){ /* do something */ });
+
+ constructor: function(){
+ this._hash = {};
+ this.length = 0;
+ },
+
+ add: function(/*dijit._Widget*/ widget){
+ // summary:
+ // Add a widget to this list. If a duplicate ID is detected, a error is thrown.
+ //
+ // widget: dijit._Widget
+ // Any dijit._Widget subclass.
+ if(this._hash[widget.id]){
+ throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered");
+ }
+ this._hash[widget.id] = widget;
+ this.length++;
+ },
+
+ remove: function(/*String*/ id){
+ // summary:
+ // Remove a widget from this WidgetSet. Does not destroy the widget; simply
+ // removes the reference.
+ if(this._hash[id]){
+ delete this._hash[id];
+ this.length--;
+ }
+ },
+
+ forEach: function(/*Function*/ func, /* Object? */thisObj){
+ // summary:
+ // Call specified function for each widget in this set.
+ //
+ // func:
+ // A callback function to run for each item. Is passed the widget, the index
+ // in the iteration, and the full hash, similar to `dojo.forEach`.
+ //
+ // thisObj:
+ // An optional scope parameter
+ //
+ // example:
+ // Using the default `dijit.registry` instance:
+ // | dijit.registry.forEach(function(widget){
+ // | console.log(widget.declaredClass);
+ // | });
+ //
+ // returns:
+ // Returns self, in order to allow for further chaining.
+
+ thisObj = thisObj || dojo.global;
+ var i = 0, id;
+ for(id in this._hash){
+ func.call(thisObj, this._hash[id], i++, this._hash);
+ }
+ return this; // dijit.WidgetSet
+ },
+
+ filter: function(/*Function*/ filter, /* Object? */thisObj){
+ // summary:
+ // Filter down this WidgetSet to a smaller new WidgetSet
+ // Works the same as `dojo.filter` and `dojo.NodeList.filter`
+ //
+ // filter:
+ // Callback function to test truthiness. Is passed the widget
+ // reference and the pseudo-index in the object.
+ //
+ // thisObj: Object?
+ // Option scope to use for the filter function.
+ //
+ // example:
+ // Arbitrary: select the odd widgets in this list
+ // | dijit.registry.filter(function(w, i){
+ // | return i % 2 == 0;
+ // | }).forEach(function(w){ /* odd ones */ });
+
+ thisObj = thisObj || dojo.global;
+ var res = new dijit.WidgetSet(), i = 0, id;
+ for(id in this._hash){
+ var w = this._hash[id];
+ if(filter.call(thisObj, w, i++, this._hash)){
+ res.add(w);
+ }
+ }
+ return res; // dijit.WidgetSet
+ },
+
+ byId: function(/*String*/ id){
+ // summary:
+ // Find a widget in this list by it's id.
+ // example:
+ // Test if an id is in a particular WidgetSet
+ // | var ws = new dijit.WidgetSet();
+ // | ws.add(dijit.byId("bar"));
+ // | var t = ws.byId("bar") // returns a widget
+ // | var x = ws.byId("foo"); // returns undefined
+
+ return this._hash[id]; // dijit._Widget
+ },
+
+ byClass: function(/*String*/ cls){
+ // summary:
+ // Reduce this widgetset to a new WidgetSet of a particular `declaredClass`
+ //
+ // cls: String
+ // The Class to scan for. Full dot-notated string.
+ //
+ // example:
+ // Find all `dijit.TitlePane`s in a page:
+ // | dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); });
+
+ var res = new dijit.WidgetSet(), id, widget;
+ for(id in this._hash){
+ widget = this._hash[id];
+ if(widget.declaredClass == cls){
+ res.add(widget);
+ }
+ }
+ return res; // dijit.WidgetSet
+},
+
+ toArray: function(){
+ // summary:
+ // Convert this WidgetSet into a true Array
+ //
+ // example:
+ // Work with the widget .domNodes in a real Array
+ // | dojo.map(dijit.registry.toArray(), function(w){ return w.domNode; });
+
+ var ar = [];
+ for(var id in this._hash){
+ ar.push(this._hash[id]);
+ }
+ return ar; // dijit._Widget[]
+},
+
+ map: function(/* Function */func, /* Object? */thisObj){
+ // summary:
+ // Create a new Array from this WidgetSet, following the same rules as `dojo.map`
+ // example:
+ // | var nodes = dijit.registry.map(function(w){ return w.domNode; });
+ //
+ // returns:
+ // A new array of the returned values.
+ return dojo.map(this.toArray(), func, thisObj); // Array
+ },
+
+ every: function(func, thisObj){
+ // summary:
+ // A synthetic clone of `dojo.every` acting explicitly on this WidgetSet
+ //
+ // func: Function
+ // A callback function run for every widget in this list. Exits loop
+ // when the first false return is encountered.
+ //
+ // thisObj: Object?
+ // Optional scope parameter to use for the callback
+
+ thisObj = thisObj || dojo.global;
+ var x = 0, i;
+ for(i in this._hash){
+ if(!func.call(thisObj, this._hash[i], x++, this._hash)){
+ return false; // Boolean
+ }
+ }
+ return true; // Boolean
+ },
+
+ some: function(func, thisObj){
+ // summary:
+ // A synthetic clone of `dojo.some` acting explictly on this WidgetSet
+ //
+ // func: Function
+ // A callback function run for every widget in this list. Exits loop
+ // when the first true return is encountered.
+ //
+ // thisObj: Object?
+ // Optional scope parameter to use for the callback
+
+ thisObj = thisObj || dojo.global;
+ var x = 0, i;
+ for(i in this._hash){
+ if(func.call(thisObj, this._hash[i], x++, this._hash)){
+ return true; // Boolean
+ }
+ }
+ return false; // Boolean
+ }
+
+});
+
+(function(){
+
+ /*=====
+ dijit.registry = {
+ // summary:
+ // A list of widgets on a page.
+ // description:
+ // Is an instance of `dijit.WidgetSet`
+ };
+ =====*/
+ dijit.registry = new dijit.WidgetSet();
+
+ var hash = dijit.registry._hash,
+ attr = dojo.attr,
+ hasAttr = dojo.hasAttr,
+ style = dojo.style;
+
+ dijit.byId = function(/*String|dijit._Widget*/ id){
+ // summary:
+ // Returns a widget by it's id, or if passed a widget, no-op (like dojo.byId())
+ return typeof id == "string" ? hash[id] : id; // dijit._Widget
+ };
+
+ var _widgetTypeCtr = {};
+ dijit.getUniqueId = function(/*String*/widgetType){
+ // summary:
+ // Generates a unique id for a given widgetType
+
+ var id;
+ do{
+ id = widgetType + "_" +
+ (widgetType in _widgetTypeCtr ?
+ ++_widgetTypeCtr[widgetType] : _widgetTypeCtr[widgetType] = 0);
+ }while(hash[id]);
+ return dijit._scopeName == "dijit" ? id : dijit._scopeName + "_" + id; // String
+ };
+
+ dijit.findWidgets = function(/*DomNode*/ root){
+ // summary:
+ // Search subtree under root returning widgets found.
+ // Doesn't search for nested widgets (ie, widgets inside other widgets).
+
+ var outAry = [];
+
+ function getChildrenHelper(root){
+ for(var node = root.firstChild; node; node = node.nextSibling){
+ if(node.nodeType == 1){
+ var widgetId = node.getAttribute("widgetId");
+ if(widgetId){
+ outAry.push(hash[widgetId]);
+ }else{
+ getChildrenHelper(node);
+ }
+ }
+ }
+ }
+
+ getChildrenHelper(root);
+ return outAry;
+ };
+
+ dijit._destroyAll = function(){
+ // summary:
+ // Code to destroy all widgets and do other cleanup on page unload
+
+ // Clean up focus manager lingering references to widgets and nodes
+ dijit._curFocus = null;
+ dijit._prevFocus = null;
+ dijit._activeStack = [];
+
+ // Destroy all the widgets, top down
+ dojo.forEach(dijit.findWidgets(dojo.body()), function(widget){
+ // Avoid double destroy of widgets like Menu that are attached to <body>
+ // even though they are logically children of other widgets.
+ if(!widget._destroyed){
+ if(widget.destroyRecursive){
+ widget.destroyRecursive();
+ }else if(widget.destroy){
+ widget.destroy();
+ }
+ }
+ });
+ };
+
+ if(dojo.isIE){
+ // Only run _destroyAll() for IE because we think it's only necessary in that case,
+ // and because it causes problems on FF. See bug #3531 for details.
+ dojo.addOnWindowUnload(function(){
+ dijit._destroyAll();
+ });
+ }
+
+ dijit.byNode = function(/*DOMNode*/ node){
+ // summary:
+ // Returns the widget corresponding to the given DOMNode
+ return hash[node.getAttribute("widgetId")]; // dijit._Widget
+ };
+
+ dijit.getEnclosingWidget = function(/*DOMNode*/ node){
+ // summary:
+ // Returns the widget whose DOM tree contains the specified DOMNode, or null if
+ // the node is not contained within the DOM tree of any widget
+ while(node){
+ var id = node.getAttribute && node.getAttribute("widgetId");
+ if(id){
+ return hash[id];
+ }
+ node = node.parentNode;
+ }
+ return null;
+ };
+
+ var shown = (dijit._isElementShown = function(/*Element*/ elem){
+ var s = style(elem);
+ return (s.visibility != "hidden")
+ && (s.visibility != "collapsed")
+ && (s.display != "none")
+ && (attr(elem, "type") != "hidden");
+ });
+
+ dijit.hasDefaultTabStop = function(/*Element*/ elem){
+ // summary:
+ // Tests if element is tab-navigable even without an explicit tabIndex setting
+
+ // No explicit tabIndex setting, need to investigate node type
+ switch(elem.nodeName.toLowerCase()){
+ case "a":
+ // An <a> w/out a tabindex is only navigable if it has an href
+ return hasAttr(elem, "href");
+ case "area":
+ case "button":
+ case "input":
+ case "object":
+ case "select":
+ case "textarea":
+ // These are navigable by default
+ return true;
+ case "iframe":
+ // If it's an editor <iframe> then it's tab navigable.
+ //TODO: feature detect "designMode" in elem.contentDocument?
+ if(dojo.isMoz){
+ try{
+ return elem.contentDocument.designMode == "on";
+ }catch(err){
+ return false;
+ }
+ }else if(dojo.isWebKit){
+ var doc = elem.contentDocument,
+ body = doc && doc.body;
+ return body && body.contentEditable == 'true';
+ }else{
+ // contentWindow.document isn't accessible within IE7/8
+ // if the iframe.src points to a foreign url and this
+ // page contains an element, that could get focus
+ try{
+ doc = elem.contentWindow.document;
+ body = doc && doc.body;
+ return body && body.firstChild && body.firstChild.contentEditable == 'true';
+ }catch(e){
+ return false;
+ }
+ }
+ default:
+ return elem.contentEditable == 'true';
+ }
+ };
+
+ var isTabNavigable = (dijit.isTabNavigable = function(/*Element*/ elem){
+ // summary:
+ // Tests if an element is tab-navigable
+
+ // TODO: convert (and rename method) to return effective tabIndex; will save time in _getTabNavigable()
+ if(attr(elem, "disabled")){
+ return false;
+ }else if(hasAttr(elem, "tabIndex")){
+ // Explicit tab index setting
+ return attr(elem, "tabIndex") >= 0; // boolean
+ }else{
+ // No explicit tabIndex setting, so depends on node type
+ return dijit.hasDefaultTabStop(elem);
+ }
+ });
+
+ dijit._getTabNavigable = function(/*DOMNode*/ root){
+ // summary:
+ // Finds descendants of the specified root node.
+ //
+ // description:
+ // Finds the following descendants of the specified root node:
+ // * the first tab-navigable element in document order
+ // without a tabIndex or with tabIndex="0"
+ // * the last tab-navigable element in document order
+ // without a tabIndex or with tabIndex="0"
+ // * the first element in document order with the lowest
+ // positive tabIndex value
+ // * the last element in document order with the highest
+ // positive tabIndex value
+ var first, last, lowest, lowestTabindex, highest, highestTabindex;
+ var walkTree = function(/*DOMNode*/parent){
+ dojo.query("> *", parent).forEach(function(child){
+ // Skip hidden elements, and also non-HTML elements (those in custom namespaces) in IE,
+ // since show() invokes getAttribute("type"), which crash on VML nodes in IE.
+ if((dojo.isIE && child.scopeName!=="HTML") || !shown(child)){
+ return;
+ }
+
+ if(isTabNavigable(child)){
+ var tabindex = attr(child, "tabIndex");
+ if(!hasAttr(child, "tabIndex") || tabindex == 0){
+ if(!first){ first = child; }
+ last = child;
+ }else if(tabindex > 0){
+ if(!lowest || tabindex < lowestTabindex){
+ lowestTabindex = tabindex;
+ lowest = child;
+ }
+ if(!highest || tabindex >= highestTabindex){
+ highestTabindex = tabindex;
+ highest = child;
+ }
+ }
+ }
+ if(child.nodeName.toUpperCase() != 'SELECT'){
+ walkTree(child);
+ }
+ });
+ };
+ if(shown(root)){ walkTree(root) }
+ return { first: first, last: last, lowest: lowest, highest: highest };
+ }
+ dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/ root){
+ // summary:
+ // Finds the descendant of the specified root node
+ // that is first in the tabbing order
+ var elems = dijit._getTabNavigable(dojo.byId(root));
+ return elems.lowest ? elems.lowest : elems.first; // DomNode
+ };
+
+ dijit.getLastInTabbingOrder = function(/*String|DOMNode*/ root){
+ // summary:
+ // Finds the descendant of the specified root node
+ // that is last in the tabbing order
+ var elems = dijit._getTabNavigable(dojo.byId(root));
+ return elems.last ? elems.last : elems.highest; // DomNode
+ };
+
+ /*=====
+ dojo.mixin(dijit, {
+ // defaultDuration: Integer
+ // The default animation speed (in ms) to use for all Dijit
+ // transitional animations, unless otherwise specified
+ // on a per-instance basis. Defaults to 200, overrided by
+ // `djConfig.defaultDuration`
+ defaultDuration: 200
+ });
+ =====*/
+
+ dijit.defaultDuration = dojo.config["defaultDuration"] || 200;
+
+})();
+
+}
+
+if(!dojo._hasResource["dijit._base.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.focus"] = true;
+dojo.provide("dijit._base.focus");
+
+
+ // for dijit.isTabNavigable()
+
+// summary:
+// These functions are used to query or set the focus and selection.
+//
+// Also, they trace when widgets become activated/deactivated,
+// so that the widget can fire _onFocus/_onBlur events.
+// "Active" here means something similar to "focused", but
+// "focus" isn't quite the right word because we keep track of
+// a whole stack of "active" widgets. Example: ComboButton --> Menu -->
+// MenuItem. The onBlur event for ComboButton doesn't fire due to focusing
+// on the Menu or a MenuItem, since they are considered part of the
+// ComboButton widget. It only happens when focus is shifted
+// somewhere completely different.
+
+dojo.mixin(dijit, {
+ // _curFocus: DomNode
+ // Currently focused item on screen
+ _curFocus: null,
+
+ // _prevFocus: DomNode
+ // Previously focused item on screen
+ _prevFocus: null,
+
+ isCollapsed: function(){
+ // summary:
+ // Returns true if there is no text selected
+ return dijit.getBookmark().isCollapsed;
+ },
+
+ getBookmark: function(){
+ // summary:
+ // Retrieves a bookmark that can be used with moveToBookmark to return to the same range
+ var bm, rg, tg, sel = dojo.doc.selection, cf = dijit._curFocus;
+
+ if(dojo.global.getSelection){
+ //W3C Range API for selections.
+ sel = dojo.global.getSelection();
+ if(sel){
+ if(sel.isCollapsed){
+ tg = cf? cf.tagName : "";
+ if(tg){
+ //Create a fake rangelike item to restore selections.
+ tg = tg.toLowerCase();
+ if(tg == "textarea" ||
+ (tg == "input" && (!cf.type || cf.type.toLowerCase() == "text"))){
+ sel = {
+ start: cf.selectionStart,
+ end: cf.selectionEnd,
+ node: cf,
+ pRange: true
+ };
+ return {isCollapsed: (sel.end <= sel.start), mark: sel}; //Object.
+ }
+ }
+ bm = {isCollapsed:true};
+ }else{
+ rg = sel.getRangeAt(0);
+ bm = {isCollapsed: false, mark: rg.cloneRange()};
+ }
+ }
+ }else if(sel){
+ // If the current focus was a input of some sort and no selection, don't bother saving
+ // a native bookmark. This is because it causes issues with dialog/page selection restore.
+ // So, we need to create psuedo bookmarks to work with.
+ tg = cf ? cf.tagName : "";
+ tg = tg.toLowerCase();
+ if(cf && tg && (tg == "button" || tg == "textarea" || tg == "input")){
+ if(sel.type && sel.type.toLowerCase() == "none"){
+ return {
+ isCollapsed: true,
+ mark: null
+ }
+ }else{
+ rg = sel.createRange();
+ return {
+ isCollapsed: rg.text && rg.text.length?false:true,
+ mark: {
+ range: rg,
+ pRange: true
+ }
+ };
+ }
+ }
+ bm = {};
+
+ //'IE' way for selections.
+ try{
+ // createRange() throws exception when dojo in iframe
+ //and nothing selected, see #9632
+ rg = sel.createRange();
+ bm.isCollapsed = !(sel.type == 'Text' ? rg.htmlText.length : rg.length);
+ }catch(e){
+ bm.isCollapsed = true;
+ return bm;
+ }
+ if(sel.type.toUpperCase() == 'CONTROL'){
+ if(rg.length){
+ bm.mark=[];
+ var i=0,len=rg.length;
+ while(i<len){
+ bm.mark.push(rg.item(i++));
+ }
+ }else{
+ bm.isCollapsed = true;
+ bm.mark = null;
+ }
+ }else{
+ bm.mark = rg.getBookmark();
+ }
+ }else{
+ console.warn("No idea how to store the current selection for this browser!");
+ }
+ return bm; // Object
+ },
+
+ moveToBookmark: function(/*Object*/bookmark){
+ // summary:
+ // Moves current selection to a bookmark
+ // bookmark:
+ // This should be a returned object from dijit.getBookmark()
+
+ var _doc = dojo.doc,
+ mark = bookmark.mark;
+ if(mark){
+ if(dojo.global.getSelection){
+ //W3C Rangi API (FF, WebKit, Opera, etc)
+ var sel = dojo.global.getSelection();
+ if(sel && sel.removeAllRanges){
+ if(mark.pRange){
+ var r = mark;
+ var n = r.node;
+ n.selectionStart = r.start;
+ n.selectionEnd = r.end;
+ }else{
+ sel.removeAllRanges();
+ sel.addRange(mark);
+ }
+ }else{
+ console.warn("No idea how to restore selection for this browser!");
+ }
+ }else if(_doc.selection && mark){
+ //'IE' way.
+ var rg;
+ if(mark.pRange){
+ rg = mark.range;
+ }else if(dojo.isArray(mark)){
+ rg = _doc.body.createControlRange();
+ //rg.addElement does not have call/apply method, so can not call it directly
+ //rg is not available in "range.addElement(item)", so can't use that either
+ dojo.forEach(mark, function(n){
+ rg.addElement(n);
+ });
+ }else{
+ rg = _doc.body.createTextRange();
+ rg.moveToBookmark(mark);
+ }
+ rg.select();
+ }
+ }
+ },
+
+ getFocus: function(/*Widget?*/ menu, /*Window?*/ openedForWindow){
+ // summary:
+ // Called as getFocus(), this returns an Object showing the current focus
+ // and selected text.
+ //
+ // Called as getFocus(widget), where widget is a (widget representing) a button
+ // that was just pressed, it returns where focus was before that button
+ // was pressed. (Pressing the button may have either shifted focus to the button,
+ // or removed focus altogether.) In this case the selected text is not returned,
+ // since it can't be accurately determined.
+ //
+ // menu: dijit._Widget or {domNode: DomNode} structure
+ // The button that was just pressed. If focus has disappeared or moved
+ // to this button, returns the previous focus. In this case the bookmark
+ // information is already lost, and null is returned.
+ //
+ // openedForWindow:
+ // iframe in which menu was opened
+ //
+ // returns:
+ // A handle to restore focus/selection, to be passed to `dijit.focus`
+ var node = !dijit._curFocus || (menu && dojo.isDescendant(dijit._curFocus, menu.domNode)) ? dijit._prevFocus : dijit._curFocus;
+ return {
+ node: node,
+ bookmark: (node == dijit._curFocus) && dojo.withGlobal(openedForWindow || dojo.global, dijit.getBookmark),
+ openedForWindow: openedForWindow
+ }; // Object
+ },
+
+ focus: function(/*Object || DomNode */ handle){
+ // summary:
+ // Sets the focused node and the selection according to argument.
+ // To set focus to an iframe's content, pass in the iframe itself.
+ // handle:
+ // object returned by get(), or a DomNode
+
+ if(!handle){ return; }
+
+ var node = "node" in handle ? handle.node : handle, // because handle is either DomNode or a composite object
+ bookmark = handle.bookmark,
+ openedForWindow = handle.openedForWindow,
+ collapsed = bookmark ? bookmark.isCollapsed : false;
+
+ // Set the focus
+ // Note that for iframe's we need to use the <iframe> to follow the parentNode chain,
+ // but we need to set focus to iframe.contentWindow
+ if(node){
+ var focusNode = (node.tagName.toLowerCase() == "iframe") ? node.contentWindow : node;
+ if(focusNode && focusNode.focus){
+ try{
+ // Gecko throws sometimes if setting focus is impossible,
+ // node not displayed or something like that
+ focusNode.focus();
+ }catch(e){/*quiet*/}
+ }
+ dijit._onFocusNode(node);
+ }
+
+ // set the selection
+ // do not need to restore if current selection is not empty
+ // (use keyboard to select a menu item) or if previous selection was collapsed
+ // as it may cause focus shift (Esp in IE).
+ if(bookmark && dojo.withGlobal(openedForWindow || dojo.global, dijit.isCollapsed) && !collapsed){
+ if(openedForWindow){
+ openedForWindow.focus();
+ }
+ try{
+ dojo.withGlobal(openedForWindow || dojo.global, dijit.moveToBookmark, null, [bookmark]);
+ }catch(e2){
+ /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
+ }
+ }
+ },
+
+ // _activeStack: dijit._Widget[]
+ // List of currently active widgets (focused widget and it's ancestors)
+ _activeStack: [],
+
+ registerIframe: function(/*DomNode*/ iframe){
+ // summary:
+ // Registers listeners on the specified iframe so that any click
+ // or focus event on that iframe (or anything in it) is reported
+ // as a focus/click event on the <iframe> itself.
+ // description:
+ // Currently only used by editor.
+ // returns:
+ // Handle to pass to unregisterIframe()
+ return dijit.registerWin(iframe.contentWindow, iframe);
+ },
+
+ unregisterIframe: function(/*Object*/ handle){
+ // summary:
+ // Unregisters listeners on the specified iframe created by registerIframe.
+ // After calling be sure to delete or null out the handle itself.
+ // handle:
+ // Handle returned by registerIframe()
+
+ dijit.unregisterWin(handle);
+ },
+
+ registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){
+ // summary:
+ // Registers listeners on the specified window (either the main
+ // window or an iframe's window) to detect when the user has clicked somewhere
+ // or focused somewhere.
+ // description:
+ // Users should call registerIframe() instead of this method.
+ // targetWindow:
+ // If specified this is the window associated with the iframe,
+ // i.e. iframe.contentWindow.
+ // effectiveNode:
+ // If specified, report any focus events inside targetWindow as
+ // an event on effectiveNode, rather than on evt.target.
+ // returns:
+ // Handle to pass to unregisterWin()
+
+ // TODO: make this function private in 2.0; Editor/users should call registerIframe(),
+
+ var mousedownListener = function(evt){
+ dijit._justMouseDowned = true;
+ setTimeout(function(){ dijit._justMouseDowned = false; }, 0);
+
+ // workaround weird IE bug where the click is on an orphaned node
+ // (first time clicking a Select/DropDownButton inside a TooltipDialog)
+ if(dojo.isIE && evt && evt.srcElement && evt.srcElement.parentNode == null){
+ return;
+ }
+
+ dijit._onTouchNode(effectiveNode || evt.target || evt.srcElement, "mouse");
+ };
+ //dojo.connect(targetWindow, "onscroll", ???);
+
+ // Listen for blur and focus events on targetWindow's document.
+ // IIRC, I'm using attachEvent() rather than dojo.connect() because focus/blur events don't bubble
+ // through dojo.connect(), and also maybe to catch the focus events early, before onfocus handlers
+ // fire.
+ // Connect to <html> (rather than document) on IE to avoid memory leaks, but document on other browsers because
+ // (at least for FF) the focus event doesn't fire on <html> or <body>.
+ var doc = dojo.isIE ? targetWindow.document.documentElement : targetWindow.document;
+ if(doc){
+ if(dojo.isIE){
+ doc.attachEvent('onmousedown', mousedownListener);
+ var activateListener = function(evt){
+ // IE reports that nodes like <body> have gotten focus, even though they have tabIndex=-1,
+ // Should consider those more like a mouse-click than a focus....
+ if(evt.srcElement.tagName.toLowerCase() != "#document" &&
+ dijit.isTabNavigable(evt.srcElement)){
+ dijit._onFocusNode(effectiveNode || evt.srcElement);
+ }else{
+ dijit._onTouchNode(effectiveNode || evt.srcElement);
+ }
+ };
+ doc.attachEvent('onactivate', activateListener);
+ var deactivateListener = function(evt){
+ dijit._onBlurNode(effectiveNode || evt.srcElement);
+ };
+ doc.attachEvent('ondeactivate', deactivateListener);
+
+ return function(){
+ doc.detachEvent('onmousedown', mousedownListener);
+ doc.detachEvent('onactivate', activateListener);
+ doc.detachEvent('ondeactivate', deactivateListener);
+ doc = null; // prevent memory leak (apparent circular reference via closure)
+ };
+ }else{
+ doc.addEventListener('mousedown', mousedownListener, true);
+ var focusListener = function(evt){
+ dijit._onFocusNode(effectiveNode || evt.target);
+ };
+ doc.addEventListener('focus', focusListener, true);
+ var blurListener = function(evt){
+ dijit._onBlurNode(effectiveNode || evt.target);
+ };
+ doc.addEventListener('blur', blurListener, true);
+
+ return function(){
+ doc.removeEventListener('mousedown', mousedownListener, true);
+ doc.removeEventListener('focus', focusListener, true);
+ doc.removeEventListener('blur', blurListener, true);
+ doc = null; // prevent memory leak (apparent circular reference via closure)
+ };
+ }
+ }
+ },
+
+ unregisterWin: function(/*Handle*/ handle){
+ // summary:
+ // Unregisters listeners on the specified window (either the main
+ // window or an iframe's window) according to handle returned from registerWin().
+ // After calling be sure to delete or null out the handle itself.
+
+ // Currently our handle is actually a function
+ handle && handle();
+ },
+
+ _onBlurNode: function(/*DomNode*/ node){
+ // summary:
+ // Called when focus leaves a node.
+ // Usually ignored, _unless_ it *isn't* follwed by touching another node,
+ // which indicates that we tabbed off the last field on the page,
+ // in which case every widget is marked inactive
+ dijit._prevFocus = dijit._curFocus;
+ dijit._curFocus = null;
+
+ if(dijit._justMouseDowned){
+ // the mouse down caused a new widget to be marked as active; this blur event
+ // is coming late, so ignore it.
+ return;
+ }
+
+ // if the blur event isn't followed by a focus event then mark all widgets as inactive.
+ if(dijit._clearActiveWidgetsTimer){
+ clearTimeout(dijit._clearActiveWidgetsTimer);
+ }
+ dijit._clearActiveWidgetsTimer = setTimeout(function(){
+ delete dijit._clearActiveWidgetsTimer;
+ dijit._setStack([]);
+ dijit._prevFocus = null;
+ }, 100);
+ },
+
+ _onTouchNode: function(/*DomNode*/ node, /*String*/ by){
+ // summary:
+ // Callback when node is focused or mouse-downed
+ // node:
+ // The node that was touched.
+ // by:
+ // "mouse" if the focus/touch was caused by a mouse down event
+
+ // ignore the recent blurNode event
+ if(dijit._clearActiveWidgetsTimer){
+ clearTimeout(dijit._clearActiveWidgetsTimer);
+ delete dijit._clearActiveWidgetsTimer;
+ }
+
+ // compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem)
+ var newStack=[];
+ try{
+ while(node){
+ var popupParent = dojo.attr(node, "dijitPopupParent");
+ if(popupParent){
+ node=dijit.byId(popupParent).domNode;
+ }else if(node.tagName && node.tagName.toLowerCase() == "body"){
+ // is this the root of the document or just the root of an iframe?
+ if(node === dojo.body()){
+ // node is the root of the main document
+ break;
+ }
+ // otherwise, find the iframe this node refers to (can't access it via parentNode,
+ // need to do this trick instead). window.frameElement is supported in IE/FF/Webkit
+ node=dojo.window.get(node.ownerDocument).frameElement;
+ }else{
+ // if this node is the root node of a widget, then add widget id to stack,
+ // except ignore clicks on disabled widgets (actually focusing a disabled widget still works,
+ // to support MenuItem)
+ var id = node.getAttribute && node.getAttribute("widgetId"),
+ widget = id && dijit.byId(id);
+ if(widget && !(by == "mouse" && widget.get("disabled"))){
+ newStack.unshift(id);
+ }
+ node=node.parentNode;
+ }
+ }
+ }catch(e){ /* squelch */ }
+
+ dijit._setStack(newStack, by);
+ },
+
+ _onFocusNode: function(/*DomNode*/ node){
+ // summary:
+ // Callback when node is focused
+
+ if(!node){
+ return;
+ }
+
+ if(node.nodeType == 9){
+ // Ignore focus events on the document itself. This is here so that
+ // (for example) clicking the up/down arrows of a spinner
+ // (which don't get focus) won't cause that widget to blur. (FF issue)
+ return;
+ }
+
+ dijit._onTouchNode(node);
+
+ if(node == dijit._curFocus){ return; }
+ if(dijit._curFocus){
+ dijit._prevFocus = dijit._curFocus;
+ }
+ dijit._curFocus = node;
+ dojo.publish("focusNode", [node]);
+ },
+
+ _setStack: function(/*String[]*/ newStack, /*String*/ by){
+ // summary:
+ // The stack of active widgets has changed. Send out appropriate events and records new stack.
+ // newStack:
+ // array of widget id's, starting from the top (outermost) widget
+ // by:
+ // "mouse" if the focus/touch was caused by a mouse down event
+
+ var oldStack = dijit._activeStack;
+ dijit._activeStack = newStack;
+
+ // compare old stack to new stack to see how many elements they have in common
+ for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){
+ if(oldStack[nCommon] != newStack[nCommon]){
+ break;
+ }
+ }
+
+ var widget;
+ // for all elements that have gone out of focus, send blur event
+ for(var i=oldStack.length-1; i>=nCommon; i--){
+ widget = dijit.byId(oldStack[i]);
+ if(widget){
+ widget._focused = false;
+ widget._hasBeenBlurred = true;
+ if(widget._onBlur){
+ widget._onBlur(by);
+ }
+ dojo.publish("widgetBlur", [widget, by]);
+ }
+ }
+
+ // for all element that have come into focus, send focus event
+ for(i=nCommon; i<newStack.length; i++){
+ widget = dijit.byId(newStack[i]);
+ if(widget){
+ widget._focused = true;
+ if(widget._onFocus){
+ widget._onFocus(by);
+ }
+ dojo.publish("widgetFocus", [widget, by]);
+ }
+ }
+ }
+});
+
+// register top window and all the iframes it contains
+dojo.addOnLoad(function(){
+ var handle = dijit.registerWin(window);
+ if(dojo.isIE){
+ dojo.addOnWindowUnload(function(){
+ dijit.unregisterWin(handle);
+ handle = null;
+ })
+ }
+});
+
+}
+
+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;
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit._base.place"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.place"] = true;
+dojo.provide("dijit._base.place");
+
+
+
+
+
+dijit.getViewport = function(){
+ // summary:
+ // Returns the dimensions and scroll position of the viewable area of a browser window
+
+ return dojo.window.getBox();
+};
+
+/*=====
+dijit.__Position = function(){
+ // x: Integer
+ // horizontal coordinate in pixels, relative to document body
+ // y: Integer
+ // vertical coordinate in pixels, relative to document body
+
+ thix.x = x;
+ this.y = y;
+}
+=====*/
+
+
+dijit.placeOnScreen = function(
+ /* DomNode */ node,
+ /* dijit.__Position */ pos,
+ /* String[] */ corners,
+ /* dijit.__Position? */ padding){
+ // summary:
+ // Positions one of the node's corners at specified position
+ // such that node is fully visible in viewport.
+ // description:
+ // NOTE: node is assumed to be absolutely or relatively positioned.
+ // pos:
+ // Object like {x: 10, y: 20}
+ // corners:
+ // Array of Strings representing order to try corners in, like ["TR", "BL"].
+ // Possible values are:
+ // * "BL" - bottom left
+ // * "BR" - bottom right
+ // * "TL" - top left
+ // * "TR" - top right
+ // padding:
+ // set padding to put some buffer around the element you want to position.
+ // example:
+ // Try to place node's top right corner at (10,20).
+ // If that makes node go (partially) off screen, then try placing
+ // bottom left corner at (10,20).
+ // | placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"])
+
+ var choices = dojo.map(corners, function(corner){
+ var c = { corner: corner, pos: {x:pos.x,y:pos.y} };
+ if(padding){
+ c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x;
+ c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y;
+ }
+ return c;
+ });
+
+ return dijit._place(node, choices);
+}
+
+dijit._place = function(/*DomNode*/ node, /* Array */ choices, /* Function */ layoutNode){
+ // summary:
+ // Given a list of spots to put node, put it at the first spot where it fits,
+ // of if it doesn't fit anywhere then the place with the least overflow
+ // choices: Array
+ // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
+ // Above example says to put the top-left corner of the node at (10,20)
+ // layoutNode: Function(node, aroundNodeCorner, nodeCorner)
+ // for things like tooltip, they are displayed differently (and have different dimensions)
+ // based on their orientation relative to the parent. This adjusts the popup based on orientation.
+
+ // get {x: 10, y: 10, w: 100, h:100} type obj representing position of
+ // viewport over document
+ var view = dojo.window.getBox();
+
+ // This won't work if the node is inside a <div style="position: relative">,
+ // so reattach it to dojo.doc.body. (Otherwise, the positioning will be wrong
+ // and also it might get cutoff)
+ if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){
+ dojo.body().appendChild(node);
+ }
+
+ var best = null;
+ dojo.some(choices, function(choice){
+ var corner = choice.corner;
+ var pos = choice.pos;
+
+ // configure node to be displayed in given position relative to button
+ // (need to do this in order to get an accurate size for the node, because
+ // a tooltips size changes based on position, due to triangle)
+ if(layoutNode){
+ layoutNode(node, choice.aroundCorner, corner);
+ }
+
+ // get node's size
+ var style = node.style;
+ var oldDisplay = style.display;
+ var oldVis = style.visibility;
+ style.visibility = "hidden";
+ style.display = "";
+ var mb = dojo.marginBox(node);
+ style.display = oldDisplay;
+ style.visibility = oldVis;
+
+ // coordinates and size of node with specified corner placed at pos,
+ // and clipped by viewport
+ var startX = Math.max(view.l, corner.charAt(1) == 'L' ? pos.x : (pos.x - mb.w)),
+ startY = Math.max(view.t, corner.charAt(0) == 'T' ? pos.y : (pos.y - mb.h)),
+ endX = Math.min(view.l + view.w, corner.charAt(1) == 'L' ? (startX + mb.w) : pos.x),
+ endY = Math.min(view.t + view.h, corner.charAt(0) == 'T' ? (startY + mb.h) : pos.y),
+ width = endX - startX,
+ height = endY - startY,
+ overflow = (mb.w - width) + (mb.h - height);
+
+ if(best == null || overflow < best.overflow){
+ best = {
+ corner: corner,
+ aroundCorner: choice.aroundCorner,
+ x: startX,
+ y: startY,
+ w: width,
+ h: height,
+ overflow: overflow
+ };
+ }
+ return !overflow;
+ });
+
+ node.style.left = best.x + "px";
+ node.style.top = best.y + "px";
+ if(best.overflow && layoutNode){
+ layoutNode(node, best.aroundCorner, best.corner);
+ }
+ return best;
+}
+
+dijit.placeOnScreenAroundNode = function(
+ /* DomNode */ node,
+ /* DomNode */ aroundNode,
+ /* Object */ aroundCorners,
+ /* Function? */ layoutNode){
+
+ // summary:
+ // Position node adjacent or kitty-corner to aroundNode
+ // such that it's fully visible in viewport.
+ //
+ // description:
+ // Place node such that corner of node touches a corner of
+ // aroundNode, and that node is fully visible.
+ //
+ // aroundCorners:
+ // Ordered list of pairs of corners to try matching up.
+ // Each pair of corners is represented as a key/value in the hash,
+ // where the key corresponds to the aroundNode's corner, and
+ // the value corresponds to the node's corner:
+ //
+ // | { aroundNodeCorner1: nodeCorner1, aroundNodeCorner2: nodeCorner2, ...}
+ //
+ // The following strings are used to represent the four corners:
+ // * "BL" - bottom left
+ // * "BR" - bottom right
+ // * "TL" - top left
+ // * "TR" - top right
+ //
+ // layoutNode: Function(node, aroundNodeCorner, nodeCorner)
+ // For things like tooltip, they are displayed differently (and have different dimensions)
+ // based on their orientation relative to the parent. This adjusts the popup based on orientation.
+ //
+ // example:
+ // | dijit.placeOnScreenAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'});
+ // This will try to position node such that node's top-left corner is at the same position
+ // as the bottom left corner of the aroundNode (ie, put node below
+ // aroundNode, with left edges aligned). If that fails it will try to put
+ // the bottom-right corner of node where the top right corner of aroundNode is
+ // (ie, put node above aroundNode, with right edges aligned)
+ //
+
+ // get coordinates of aroundNode
+ aroundNode = dojo.byId(aroundNode);
+ var oldDisplay = aroundNode.style.display;
+ aroundNode.style.display="";
+ // #3172: use the slightly tighter border box instead of marginBox
+ var aroundNodePos = dojo.position(aroundNode, true);
+ aroundNode.style.display=oldDisplay;
+
+ // place the node around the calculated rectangle
+ return dijit._placeOnScreenAroundRect(node,
+ aroundNodePos.x, aroundNodePos.y, aroundNodePos.w, aroundNodePos.h, // rectangle
+ aroundCorners, layoutNode);
+};
+
+/*=====
+dijit.__Rectangle = function(){
+ // x: Integer
+ // horizontal offset in pixels, relative to document body
+ // y: Integer
+ // vertical offset in pixels, relative to document body
+ // width: Integer
+ // width in pixels
+ // height: Integer
+ // height in pixels
+
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+}
+=====*/
+
+
+dijit.placeOnScreenAroundRectangle = function(
+ /* DomNode */ node,
+ /* dijit.__Rectangle */ aroundRect,
+ /* Object */ aroundCorners,
+ /* Function */ layoutNode){
+
+ // summary:
+ // Like dijit.placeOnScreenAroundNode(), except that the "around"
+ // parameter is an arbitrary rectangle on the screen (x, y, width, height)
+ // instead of a dom node.
+
+ return dijit._placeOnScreenAroundRect(node,
+ aroundRect.x, aroundRect.y, aroundRect.width, aroundRect.height, // rectangle
+ aroundCorners, layoutNode);
+};
+
+dijit._placeOnScreenAroundRect = function(
+ /* DomNode */ node,
+ /* Number */ x,
+ /* Number */ y,
+ /* Number */ width,
+ /* Number */ height,
+ /* Object */ aroundCorners,
+ /* Function */ layoutNode){
+
+ // summary:
+ // Like dijit.placeOnScreenAroundNode(), except it accepts coordinates
+ // of a rectangle to place node adjacent to.
+
+ // TODO: combine with placeOnScreenAroundRectangle()
+
+ // Generate list of possible positions for node
+ var choices = [];
+ for(var nodeCorner in aroundCorners){
+ choices.push( {
+ aroundCorner: nodeCorner,
+ corner: aroundCorners[nodeCorner],
+ pos: {
+ x: x + (nodeCorner.charAt(1) == 'L' ? 0 : width),
+ y: y + (nodeCorner.charAt(0) == 'T' ? 0 : height)
+ }
+ });
+ }
+
+ return dijit._place(node, choices, layoutNode);
+};
+
+dijit.placementRegistry= new dojo.AdapterRegistry();
+dijit.placementRegistry.register("node",
+ function(n, x){
+ return typeof x == "object" &&
+ typeof x.offsetWidth != "undefined" && typeof x.offsetHeight != "undefined";
+ },
+ dijit.placeOnScreenAroundNode);
+dijit.placementRegistry.register("rect",
+ function(n, x){
+ return typeof x == "object" &&
+ "x" in x && "y" in x && "width" in x && "height" in x;
+ },
+ dijit.placeOnScreenAroundRectangle);
+
+dijit.placeOnScreenAroundElement = function(
+ /* DomNode */ node,
+ /* Object */ aroundElement,
+ /* Object */ aroundCorners,
+ /* Function */ layoutNode){
+
+ // summary:
+ // Like dijit.placeOnScreenAroundNode(), except it accepts an arbitrary object
+ // for the "around" argument and finds a proper processor to place a node.
+
+ return dijit.placementRegistry.match.apply(dijit.placementRegistry, arguments);
+};
+
+dijit.getPopupAroundAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){
+ // summary:
+ // Transforms the passed array of preferred positions into a format suitable for passing as the aroundCorners argument to dijit.placeOnScreenAroundElement.
+ //
+ // position: String[]
+ // This variable controls the position of the drop down.
+ // It's an array of strings with the following values:
+ //
+ // * before: places drop down to the left of the target node/widget, or to the right in
+ // the case of RTL scripts like Hebrew and Arabic
+ // * after: places drop down to the right of the target node/widget, or to the left in
+ // the case of RTL scripts like Hebrew and Arabic
+ // * above: drop down goes above target node
+ // * below: drop down goes below target node
+ //
+ // The list is positions is tried, in order, until a position is found where the drop down fits
+ // within the viewport.
+ //
+ // leftToRight: Boolean
+ // Whether the popup will be displaying in leftToRight mode.
+ //
+ var align = {};
+ dojo.forEach(position, function(pos){
+ switch(pos){
+ case "after":
+ align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR";
+ break;
+ case "before":
+ align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL";
+ break;
+ case "below":
+ // first try to align left borders, next try to align right borders (or reverse for RTL mode)
+ align[leftToRight ? "BL" : "BR"] = leftToRight ? "TL" : "TR";
+ align[leftToRight ? "BR" : "BL"] = leftToRight ? "TR" : "TL";
+ break;
+ case "above":
+ default:
+ // first try to align left borders, next try to align right borders (or reverse for RTL mode)
+ align[leftToRight ? "TL" : "TR"] = leftToRight ? "BL" : "BR";
+ align[leftToRight ? "TR" : "TL"] = leftToRight ? "BR" : "BL";
+ break;
+ }
+ });
+ return align;
+};
+
+}
+
+if(!dojo._hasResource["dijit._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.window"] = true;
+dojo.provide("dijit._base.window");
+
+
+
+dijit.getDocumentWindow = function(doc){
+ return dojo.window.get(doc);
+};
+
+}
+
+if(!dojo._hasResource["dijit._base.popup"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.popup"] = true;
+dojo.provide("dijit._base.popup");
+
+
+
+
+
+/*=====
+dijit.popup.__OpenArgs = function(){
+ // popup: Widget
+ // widget to display
+ // parent: Widget
+ // the button etc. that is displaying this popup
+ // around: DomNode
+ // DOM node (typically a button); place popup relative to this node. (Specify this *or* "x" and "y" parameters.)
+ // x: Integer
+ // Absolute horizontal position (in pixels) to place node at. (Specify this *or* "around" parameter.)
+ // y: Integer
+ // Absolute vertical position (in pixels) to place node at. (Specify this *or* "around" parameter.)
+ // orient: Object|String
+ // When the around parameter is specified, orient should be an
+ // ordered list of tuples of the form (around-node-corner, popup-node-corner).
+ // dijit.popup.open() tries to position the popup according to each tuple in the list, in order,
+ // until the popup appears fully within the viewport.
+ //
+ // The default value is {BL:'TL', TL:'BL'}, which represents a list of two tuples:
+ // 1. (BL, TL)
+ // 2. (TL, BL)
+ // where BL means "bottom left" and "TL" means "top left".
+ // So by default, it first tries putting the popup below the around node, left-aligning them,
+ // and then tries to put it above the around node, still left-aligning them. Note that the
+ // default is horizontally reversed when in RTL mode.
+ //
+ // When an (x,y) position is specified rather than an around node, orient is either
+ // "R" or "L". R (for right) means that it tries to put the popup to the right of the mouse,
+ // specifically positioning the popup's top-right corner at the mouse position, and if that doesn't
+ // fit in the viewport, then it tries, in order, the bottom-right corner, the top left corner,
+ // and the top-right corner.
+ // onCancel: Function
+ // callback when user has canceled the popup by
+ // 1. hitting ESC or
+ // 2. by using the popup widget's proprietary cancel mechanism (like a cancel button in a dialog);
+ // i.e. whenever popupWidget.onCancel() is called, args.onCancel is called
+ // onClose: Function
+ // callback whenever this popup is closed
+ // onExecute: Function
+ // callback when user "executed" on the popup/sub-popup by selecting a menu choice, etc. (top menu only)
+ // padding: dijit.__Position
+ // adding a buffer around the opening position. This is only useful when around is not set.
+ this.popup = popup;
+ this.parent = parent;
+ this.around = around;
+ this.x = x;
+ this.y = y;
+ this.orient = orient;
+ this.onCancel = onCancel;
+ this.onClose = onClose;
+ this.onExecute = onExecute;
+ this.padding = padding;
+}
+=====*/
+
+dijit.popup = {
+ // summary:
+ // This singleton is used to show/hide widgets as popups.
+
+ // _stack: dijit._Widget[]
+ // Stack of currently popped up widgets.
+ // (someone opened _stack[0], and then it opened _stack[1], etc.)
+ _stack: [],
+
+ // _beginZIndex: Number
+ // Z-index of the first popup. (If first popup opens other
+ // popups they get a higher z-index.)
+ _beginZIndex: 1000,
+
+ _idGen: 1,
+
+ moveOffScreen: function(/*DomNode*/ node){
+ // summary:
+ // Initialization for nodes that will be used as popups
+ //
+ // description:
+ // Puts node inside a wrapper <div>, and
+ // positions wrapper div off screen, but not display:none, so that
+ // the widget doesn't appear in the page flow and/or cause a blank
+ // area at the bottom of the viewport (making scrollbar longer), but
+ // initialization of contained widgets works correctly
+
+ var wrapper = node.parentNode;
+
+ // Create a wrapper widget for when this node (in the future) will be used as a popup.
+ // This is done early because of IE bugs where creating/moving DOM nodes causes focus
+ // to go wonky, see tests/robot/Toolbar.html to reproduce
+ if(!wrapper || !dojo.hasClass(wrapper, "dijitPopup")){
+ wrapper = dojo.create("div",{
+ "class":"dijitPopup",
+ style:{
+ visibility:"hidden",
+ top: "-9999px"
+ }
+ }, dojo.body());
+ dijit.setWaiRole(wrapper, "presentation");
+ wrapper.appendChild(node);
+ }
+
+
+ var s = node.style;
+ s.display = "";
+ s.visibility = "";
+ s.position = "";
+ s.top = "0px";
+
+ dojo.style(wrapper, {
+ visibility: "hidden",
+ // prevent transient scrollbar causing misalign (#5776), and initial flash in upper left (#10111)
+ top: "-9999px"
+ });
+ },
+
+ getTopPopup: function(){
+ // summary:
+ // Compute the closest ancestor popup that's *not* a child of another popup.
+ // Ex: For a TooltipDialog with a button that spawns a tree of menus, find the popup of the button.
+ var stack = this._stack;
+ for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--){
+ /* do nothing, just trying to get right value for pi */
+ }
+ return stack[pi];
+ },
+
+ open: function(/*dijit.popup.__OpenArgs*/ args){
+ // summary:
+ // Popup the widget at the specified position
+ //
+ // example:
+ // opening at the mouse position
+ // | dijit.popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY});
+ //
+ // example:
+ // opening the widget as a dropdown
+ // | dijit.popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...}});
+ //
+ // Note that whatever widget called dijit.popup.open() should also listen to its own _onBlur callback
+ // (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed.
+
+ var stack = this._stack,
+ widget = args.popup,
+ orient = args.orient || (
+ (args.parent ? args.parent.isLeftToRight() : dojo._isBodyLtr()) ?
+ {'BL':'TL', 'BR':'TR', 'TL':'BL', 'TR':'BR'} :
+ {'BR':'TR', 'BL':'TL', 'TR':'BR', 'TL':'BL'}
+ ),
+ around = args.around,
+ id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+this._idGen++);
+
+
+ // The wrapper may have already been created, but in case it wasn't, create here
+ var wrapper = widget.domNode.parentNode;
+ if(!wrapper || !dojo.hasClass(wrapper, "dijitPopup")){
+ this.moveOffScreen(widget.domNode);
+ wrapper = widget.domNode.parentNode;
+ }
+
+ dojo.attr(wrapper, {
+ id: id,
+ style: {
+ zIndex: this._beginZIndex + stack.length
+ },
+ "class": "dijitPopup " + (widget.baseClass || widget["class"] || "").split(" ")[0] +"Popup",
+ dijitPopupParent: args.parent ? args.parent.id : ""
+ });
+
+ if(dojo.isIE || dojo.isMoz){
+ var iframe = wrapper.childNodes[1];
+ if(!iframe){
+ iframe = new dijit.BackgroundIframe(wrapper);
+ }
+ }
+
+ // position the wrapper node and make it visible
+ var best = around ?
+ dijit.placeOnScreenAroundElement(wrapper, around, orient, widget.orient ? dojo.hitch(widget, "orient") : null) :
+ dijit.placeOnScreen(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR'], args.padding);
+
+ wrapper.style.visibility = "visible";
+ widget.domNode.style.visibility = "visible"; // counteract effects from _HasDropDown
+
+ var handlers = [];
+
+ // provide default escape and tab key handling
+ // (this will work for any widget, not just menu)
+ handlers.push(dojo.connect(wrapper, "onkeypress", this, function(evt){
+ if(evt.charOrCode == dojo.keys.ESCAPE && args.onCancel){
+ dojo.stopEvent(evt);
+ args.onCancel();
+ }else if(evt.charOrCode === dojo.keys.TAB){
+ dojo.stopEvent(evt);
+ var topPopup = this.getTopPopup();
+ if(topPopup && topPopup.onCancel){
+ topPopup.onCancel();
+ }
+ }
+ }));
+
+ // watch for cancel/execute events on the popup and notify the caller
+ // (for a menu, "execute" means clicking an item)
+ if(widget.onCancel){
+ handlers.push(dojo.connect(widget, "onCancel", args.onCancel));
+ }
+
+ handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", this, function(){
+ var topPopup = this.getTopPopup();
+ if(topPopup && topPopup.onExecute){
+ topPopup.onExecute();
+ }
+ }));
+
+ stack.push({
+ wrapper: wrapper,
+ iframe: iframe,
+ widget: widget,
+ parent: args.parent,
+ onExecute: args.onExecute,
+ onCancel: args.onCancel,
+ onClose: args.onClose,
+ handlers: handlers
+ });
+
+ if(widget.onOpen){
+ // TODO: in 2.0 standardize onShow() (used by StackContainer) and onOpen() (used here)
+ widget.onOpen(best);
+ }
+
+ return best;
+ },
+
+ close: function(/*dijit._Widget*/ popup){
+ // summary:
+ // Close specified popup and any popups that it parented
+
+ var stack = this._stack;
+
+ // Basically work backwards from the top of the stack closing popups
+ // until we hit the specified popup, but IIRC there was some issue where closing
+ // a popup would cause others to close too. Thus if we are trying to close B in [A,B,C]
+ // closing C might close B indirectly and then the while() condition will run where stack==[A]...
+ // so the while condition is constructed defensively.
+ while(dojo.some(stack, function(elem){return elem.widget == popup;})){
+ var top = stack.pop(),
+ wrapper = top.wrapper,
+ iframe = top.iframe,
+ widget = top.widget,
+ onClose = top.onClose;
+
+ if(widget.onClose){
+ // TODO: in 2.0 standardize onHide() (used by StackContainer) and onClose() (used here)
+ widget.onClose();
+ }
+ dojo.forEach(top.handlers, dojo.disconnect);
+
+ // Move the widget plus it's wrapper off screen, unless it has already been destroyed in above onClose() etc.
+ if(widget && widget.domNode){
+ this.moveOffScreen(widget.domNode);
+ }else{
+ dojo.destroy(wrapper);
+ }
+
+ if(onClose){
+ onClose();
+ }
+ }
+ }
+};
+
+dijit._frames = new function(){
+ // summary:
+ // cache of iframes
+ var queue = [];
+
+ this.pop = function(){
+ var iframe;
+ if(queue.length){
+ iframe = queue.pop();
+ iframe.style.display="";
+ }else{
+ if(dojo.isIE){
+ var burl = dojo.config["dojoBlankHtmlUrl"] || (dojo.moduleUrl("dojo", "resources/blank.html")+"") || "javascript:\"\"";
+ var html="<iframe src='" + burl + "'"
+ + " style='position: absolute; left: 0px; top: 0px;"
+ + "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
+ iframe = dojo.doc.createElement(html);
+ }else{
+ iframe = dojo.create("iframe");
+ iframe.src = 'javascript:""';
+ iframe.className = "dijitBackgroundIframe";
+ dojo.style(iframe, "opacity", 0.1);
+ }
+ iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work.
+ dijit.setWaiRole(iframe,"presentation");
+ }
+ return iframe;
+ };
+
+ this.push = function(iframe){
+ iframe.style.display="none";
+ queue.push(iframe);
+ }
+}();
+
+
+dijit.BackgroundIframe = function(/* DomNode */node){
+ // summary:
+ // For IE/FF z-index schenanigans. id attribute is required.
+ //
+ // description:
+ // new dijit.BackgroundIframe(node)
+ // Makes a background iframe as a child of node, that fills
+ // area (and position) of node
+
+ if(!node.id){ throw new Error("no id"); }
+ if(dojo.isIE || dojo.isMoz){
+ var iframe = dijit._frames.pop();
+ node.appendChild(iframe);
+ if(dojo.isIE<7){
+ this.resize(node);
+ this._conn = dojo.connect(node, 'onresize', this, function(){
+ this.resize(node);
+ });
+ }else{
+ dojo.style(iframe, {
+ width: '100%',
+ height: '100%'
+ });
+ }
+ this.iframe = iframe;
+ }
+};
+
+dojo.extend(dijit.BackgroundIframe, {
+ resize: function(node){
+ // summary:
+ // resize the iframe so its the same size as node
+ // description:
+ // this function is a no-op in all browsers except
+ // IE6, which does not support 100% width/height
+ // of absolute positioned iframes
+ if(this.iframe && dojo.isIE<7){
+ dojo.style(this.iframe, {
+ width: node.offsetWidth + 'px',
+ height: node.offsetHeight + 'px'
+ });
+ }
+ },
+ destroy: function(){
+ // summary:
+ // destroy the iframe
+ if(this._conn){
+ dojo.disconnect(this._conn);
+ this._conn = null;
+ }
+ if(this.iframe){
+ dijit._frames.push(this.iframe);
+ delete this.iframe;
+ }
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit._base.scroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.scroll"] = true;
+dojo.provide("dijit._base.scroll");
+
+
+
+dijit.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
+ // summary:
+ // Scroll the passed node into view, if it is not already.
+ // Deprecated, use `dojo.window.scrollIntoView` instead.
+
+ dojo.window.scrollIntoView(node, pos);
+};
+
+}
+
+if(!dojo._hasResource["dojo.uacss"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.uacss"] = true;
+dojo.provide("dojo.uacss");
+
+(function(){
+ // summary:
+ // Applies pre-set CSS classes to the top-level HTML node, based on:
+ // - browser (ex: dj_ie)
+ // - browser version (ex: dj_ie6)
+ // - box model (ex: dj_contentBox)
+ // - text direction (ex: dijitRtl)
+ //
+ // In addition, browser, browser version, and box model are
+ // combined with an RTL flag when browser text is RTL. ex: dj_ie-rtl.
+
+ var d = dojo,
+ html = d.doc.documentElement,
+ ie = d.isIE,
+ opera = d.isOpera,
+ maj = Math.floor,
+ ff = d.isFF,
+ boxModel = d.boxModel.replace(/-/,''),
+
+ classes = {
+ dj_ie: ie,
+ dj_ie6: maj(ie) == 6,
+ dj_ie7: maj(ie) == 7,
+ dj_ie8: maj(ie) == 8,
+ dj_quirks: d.isQuirks,
+ dj_iequirks: ie && d.isQuirks,
+
+ // NOTE: Opera not supported by dijit
+ dj_opera: opera,
+
+ dj_khtml: d.isKhtml,
+
+ dj_webkit: d.isWebKit,
+ dj_safari: d.isSafari,
+ dj_chrome: d.isChrome,
+
+ dj_gecko: d.isMozilla,
+ dj_ff3: maj(ff) == 3
+ }; // no dojo unsupported browsers
+
+ classes["dj_" + boxModel] = true;
+
+ // apply browser, browser version, and box model class names
+ var classStr = "";
+ for(var clz in classes){
+ if(classes[clz]){
+ classStr += clz + " ";
+ }
+ }
+ html.className = d.trim(html.className + " " + classStr);
+
+ // If RTL mode, then add dj_rtl flag plus repeat existing classes with -rtl extension.
+ // We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl).
+ // Unshift() is to run sniff code before the parser.
+ dojo._loaders.unshift(function(){
+ if(!dojo._isBodyLtr()){
+ var rtlClassStr = "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl ")
+ html.className = d.trim(html.className + " " + rtlClassStr);
+ }
+ });
+})();
+
+}
+
+if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.sniff"] = true;
+// summary:
+// Applies pre-set CSS classes to the top-level HTML node, see
+// `dojo.uacss` for details.
+//
+// Simply doing a require on this module will
+// establish this CSS. Modified version of Morris' CSS hack.
+
+dojo.provide("dijit._base.sniff");
+
+
+
+}
+
+if(!dojo._hasResource["dijit._base.typematic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.typematic"] = true;
+dojo.provide("dijit._base.typematic");
+
+dijit.typematic = {
+ // summary:
+ // These functions are used to repetitively call a user specified callback
+ // method when a specific key or mouse click over a specific DOM node is
+ // held down for a specific amount of time.
+ // Only 1 such event is allowed to occur on the browser page at 1 time.
+
+ _fireEventAndReload: function(){
+ this._timer = null;
+ this._callback(++this._count, this._node, this._evt);
+
+ // Schedule next event, timer is at most minDelay (default 10ms) to avoid
+ // browser overload (particularly avoiding starving DOH robot so it never gets to send a mouseup)
+ this._currentTimeout = Math.max(
+ this._currentTimeout < 0 ? this._initialDelay :
+ (this._subsequentDelay > 1 ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay)),
+ this._minDelay);
+ this._timer = setTimeout(dojo.hitch(this, "_fireEventAndReload"), this._currentTimeout);
+ },
+
+ trigger: function(/*Event*/ evt, /*Object*/ _this, /*DOMNode*/ node, /*Function*/ callback, /*Object*/ obj, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
+ // summary:
+ // Start a timed, repeating callback sequence.
+ // If already started, the function call is ignored.
+ // This method is not normally called by the user but can be
+ // when the normal listener code is insufficient.
+ // evt:
+ // key or mouse event object to pass to the user callback
+ // _this:
+ // pointer to the user's widget space.
+ // node:
+ // the DOM node object to pass the the callback function
+ // callback:
+ // function to call until the sequence is stopped called with 3 parameters:
+ // count:
+ // integer representing number of repeated calls (0..n) with -1 indicating the iteration has stopped
+ // node:
+ // the DOM node object passed in
+ // evt:
+ // key or mouse event object
+ // obj:
+ // user space object used to uniquely identify each typematic sequence
+ // subsequentDelay (optional):
+ // if > 1, the number of milliseconds until the 3->n events occur
+ // or else the fractional time multiplier for the next event's delay, default=0.9
+ // initialDelay (optional):
+ // the number of milliseconds until the 2nd event occurs, default=500ms
+ // minDelay (optional):
+ // the maximum delay in milliseconds for event to fire, default=10ms
+ if(obj != this._obj){
+ this.stop();
+ this._initialDelay = initialDelay || 500;
+ this._subsequentDelay = subsequentDelay || 0.90;
+ this._minDelay = minDelay || 10;
+ this._obj = obj;
+ this._evt = evt;
+ this._node = node;
+ this._currentTimeout = -1;
+ this._count = -1;
+ this._callback = dojo.hitch(_this, callback);
+ this._fireEventAndReload();
+ this._evt = dojo.mixin({faux: true}, evt);
+ }
+ },
+
+ stop: function(){
+ // summary:
+ // Stop an ongoing timed, repeating callback sequence.
+ if(this._timer){
+ clearTimeout(this._timer);
+ this._timer = null;
+ }
+ if(this._obj){
+ this._callback(-1, this._node, this._evt);
+ this._obj = null;
+ }
+ },
+
+ addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
+ // summary:
+ // Start listening for a specific typematic key.
+ // See also the trigger method for other parameters.
+ // keyObject:
+ // an object defining the key to listen for:
+ // charOrCode:
+ // the printable character (string) or keyCode (number) to listen for.
+ // keyCode:
+ // (deprecated - use charOrCode) the keyCode (number) to listen for (implies charCode = 0).
+ // charCode:
+ // (deprecated - use charOrCode) the charCode (number) to listen for.
+ // ctrlKey:
+ // desired ctrl key state to initiate the callback sequence:
+ // - pressed (true)
+ // - released (false)
+ // - either (unspecified)
+ // altKey:
+ // same as ctrlKey but for the alt key
+ // shiftKey:
+ // same as ctrlKey but for the shift key
+ // returns:
+ // an array of dojo.connect handles
+ if(keyObject.keyCode){
+ keyObject.charOrCode = keyObject.keyCode;
+ dojo.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
+ }else if(keyObject.charCode){
+ keyObject.charOrCode = String.fromCharCode(keyObject.charCode);
+ dojo.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
+ }
+ return [
+ dojo.connect(node, "onkeypress", this, function(evt){
+ if(evt.charOrCode == keyObject.charOrCode &&
+ (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) &&
+ (keyObject.altKey === undefined || keyObject.altKey == evt.altKey) &&
+ (keyObject.metaKey === undefined || keyObject.metaKey == (evt.metaKey || false)) && // IE doesn't even set metaKey
+ (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.shiftKey)){
+ dojo.stopEvent(evt);
+ dijit.typematic.trigger(evt, _this, node, callback, keyObject, subsequentDelay, initialDelay, minDelay);
+ }else if(dijit.typematic._obj == keyObject){
+ dijit.typematic.stop();
+ }
+ }),
+ dojo.connect(node, "onkeyup", this, function(evt){
+ if(dijit.typematic._obj == keyObject){
+ dijit.typematic.stop();
+ }
+ })
+ ];
+ },
+
+ addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
+ // summary:
+ // Start listening for a typematic mouse click.
+ // See the trigger method for other parameters.
+ // returns:
+ // an array of dojo.connect handles
+ var dc = dojo.connect;
+ return [
+ dc(node, "mousedown", this, function(evt){
+ dojo.stopEvent(evt);
+ dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
+ }),
+ dc(node, "mouseup", this, function(evt){
+ dojo.stopEvent(evt);
+ dijit.typematic.stop();
+ }),
+ dc(node, "mouseout", this, function(evt){
+ dojo.stopEvent(evt);
+ dijit.typematic.stop();
+ }),
+ dc(node, "mousemove", this, function(evt){
+ evt.preventDefault();
+ }),
+ dc(node, "dblclick", this, function(evt){
+ dojo.stopEvent(evt);
+ if(dojo.isIE){
+ dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
+ setTimeout(dojo.hitch(this, dijit.typematic.stop), 50);
+ }
+ })
+ ];
+ },
+
+ addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
+ // summary:
+ // Start listening for a specific typematic key and mouseclick.
+ // This is a thin wrapper to addKeyListener and addMouseListener.
+ // See the addMouseListener and addKeyListener methods for other parameters.
+ // mouseNode:
+ // the DOM node object to listen on for mouse events.
+ // keyNode:
+ // the DOM node object to listen on for key events.
+ // returns:
+ // an array of dojo.connect handles
+ return this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay, minDelay).concat(
+ this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay, minDelay));
+ }
+};
+
+}
+
+if(!dojo._hasResource["dijit._base.wai"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.wai"] = true;
+dojo.provide("dijit._base.wai");
+
+dijit.wai = {
+ onload: function(){
+ // summary:
+ // Detects if we are in high-contrast mode or not
+
+ // This must be a named function and not an anonymous
+ // function, so that the widget parsing code can make sure it
+ // registers its onload function after this function.
+ // DO NOT USE "this" within this function.
+
+ // create div for testing if high contrast mode is on or images are turned off
+ var div = dojo.create("div",{
+ id: "a11yTestNode",
+ style:{
+ cssText:'border: 1px solid;'
+ + 'border-color:red green;'
+ + 'position: absolute;'
+ + 'height: 5px;'
+ + 'top: -999px;'
+ + 'background-image: url("' + (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")) + '");'
+ }
+ }, dojo.body());
+
+ // test it
+ var cs = dojo.getComputedStyle(div);
+ if(cs){
+ var bkImg = cs.backgroundImage;
+ var needsA11y = (cs.borderTopColor == cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" ));
+ dojo[needsA11y ? "addClass" : "removeClass"](dojo.body(), "dijit_a11y");
+ if(dojo.isIE){
+ div.outerHTML = ""; // prevent mixed-content warning, see http://support.microsoft.com/kb/925014
+ }else{
+ dojo.body().removeChild(div);
+ }
+ }
+ }
+};
+
+// Test if computer is in high contrast mode.
+// Make sure the a11y test runs first, before widgets are instantiated.
+if(dojo.isIE || dojo.isMoz){ // NOTE: checking in Safari messes things up
+ dojo._loaders.unshift(dijit.wai.onload);
+}
+
+dojo.mixin(dijit, {
+ _XhtmlRoles: /banner|contentinfo|definition|main|navigation|search|note|secondary|seealso/,
+
+ hasWaiRole: function(/*Element*/ elem, /*String*/ role){
+ // summary:
+ // Determines if an element has a particular non-XHTML role.
+ // returns:
+ // True if elem has the specific non-XHTML role attribute and false if not.
+ // For backwards compatibility if role parameter not provided,
+ // returns true if has non XHTML role
+ var waiRole = this.getWaiRole(elem);
+ return role ? (waiRole.indexOf(role) > -1) : (waiRole.length > 0);
+ },
+
+ getWaiRole: function(/*Element*/ elem){
+ // summary:
+ // Gets the non-XHTML role for an element (which should be a wai role).
+ // returns:
+ // The non-XHTML role of elem or an empty string if elem
+ // does not have a role.
+ return dojo.trim((dojo.attr(elem, "role") || "").replace(this._XhtmlRoles,"").replace("wairole:",""));
+ },
+
+ setWaiRole: function(/*Element*/ elem, /*String*/ role){
+ // summary:
+ // Sets the role on an element.
+ // description:
+ // Replace existing role attribute with new role.
+ // If elem already has an XHTML role, append this role to XHTML role
+ // and remove other ARIA roles.
+
+ var curRole = dojo.attr(elem, "role") || "";
+ if(!this._XhtmlRoles.test(curRole)){
+ dojo.attr(elem, "role", role);
+ }else{
+ if((" "+ curRole +" ").indexOf(" " + role + " ") < 0){
+ var clearXhtml = dojo.trim(curRole.replace(this._XhtmlRoles, ""));
+ var cleanRole = dojo.trim(curRole.replace(clearXhtml, ""));
+ dojo.attr(elem, "role", cleanRole + (cleanRole ? ' ' : '') + role);
+ }
+ }
+ },
+
+ removeWaiRole: function(/*Element*/ elem, /*String*/ role){
+ // summary:
+ // Removes the specified non-XHTML role from an element.
+ // Removes role attribute if no specific role provided (for backwards compat.)
+
+ var roleValue = dojo.attr(elem, "role");
+ if(!roleValue){ return; }
+ if(role){
+ var t = dojo.trim((" " + roleValue + " ").replace(" " + role + " ", " "));
+ dojo.attr(elem, "role", t);
+ }else{
+ elem.removeAttribute("role");
+ }
+ },
+
+ hasWaiState: function(/*Element*/ elem, /*String*/ state){
+ // summary:
+ // Determines if an element has a given state.
+ // description:
+ // Checks for an attribute called "aria-"+state.
+ // returns:
+ // true if elem has a value for the given state and
+ // false if it does not.
+
+ return elem.hasAttribute ? elem.hasAttribute("aria-"+state) : !!elem.getAttribute("aria-"+state);
+ },
+
+ getWaiState: function(/*Element*/ elem, /*String*/ state){
+ // summary:
+ // Gets the value of a state on an element.
+ // description:
+ // Checks for an attribute called "aria-"+state.
+ // returns:
+ // The value of the requested state on elem
+ // or an empty string if elem has no value for state.
+
+ return elem.getAttribute("aria-"+state) || "";
+ },
+
+ setWaiState: function(/*Element*/ elem, /*String*/ state, /*String*/ value){
+ // summary:
+ // Sets a state on an element.
+ // description:
+ // Sets an attribute called "aria-"+state.
+
+ elem.setAttribute("aria-"+state, value);
+ },
+
+ removeWaiState: function(/*Element*/ elem, /*String*/ state){
+ // summary:
+ // Removes a state from an element.
+ // description:
+ // Sets an attribute called "aria-"+state.
+
+ elem.removeAttribute("aria-"+state);
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base"] = true;
+dojo.provide("dijit._base");
+
+
+
+
+
+
+
+
+
+
+
+}
+
+if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._Widget"] = true;
+dojo.provide("dijit._Widget");
+
+dojo.require( "dijit._base" );
+
+
+// This code is to assist deferring dojo.connect() calls in widgets (connecting to events on the widgets'
+// DOM nodes) until someone actually needs to monitor that event.
+dojo.connect(dojo, "_connect",
+ function(/*dijit._Widget*/ widget, /*String*/ event){
+ if(widget && dojo.isFunction(widget._onConnect)){
+ widget._onConnect(event);
+ }
+ });
+
+dijit._connectOnUseEventHandler = function(/*Event*/ event){};
+
+// Keep track of where the last keydown event was, to help avoid generating
+// spurious ondijitclick events when:
+// 1. focus is on a <button> or <a>
+// 2. user presses then releases the ENTER key
+// 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler
+// 4. onkeyup event fires, causing the ondijitclick handler to fire
+dijit._lastKeyDownNode = null;
+if(dojo.isIE){
+ (function(){
+ var keydownCallback = function(evt){
+ dijit._lastKeyDownNode = evt.srcElement;
+ };
+ dojo.doc.attachEvent('onkeydown', keydownCallback);
+ dojo.addOnWindowUnload(function(){
+ dojo.doc.detachEvent('onkeydown', keydownCallback);
+ });
+ })();
+}else{
+ dojo.doc.addEventListener('keydown', function(evt){
+ dijit._lastKeyDownNode = evt.target;
+ }, true);
+}
+
+(function(){
+
+var _attrReg = {}, // cached results from getSetterAttributes
+ getSetterAttributes = function(widget){
+ // summary:
+ // Returns list of attributes with custom setters for specified widget
+ var dc = widget.declaredClass;
+ if(!_attrReg[dc]){
+ var r = [],
+ attrs,
+ proto = widget.constructor.prototype;
+ for(var fxName in proto){
+ if(dojo.isFunction(proto[fxName]) && (attrs = fxName.match(/^_set([a-zA-Z]*)Attr$/)) && attrs[1]){
+ r.push(attrs[1].charAt(0).toLowerCase() + attrs[1].substr(1));
+ }
+ }
+ _attrReg[dc] = r;
+ }
+ return _attrReg[dc] || []; // String[]
+ };
+
+dojo.declare("dijit._Widget", null, {
+ // summary:
+ // Base class for all Dijit widgets.
+
+ // id: [const] String
+ // A unique, opaque ID string that can be assigned by users or by the
+ // system. If the developer passes an ID which is known not to be
+ // unique, the specified ID is ignored and the system-generated ID is
+ // used instead.
+ id: "",
+
+ // lang: [const] String
+ // Rarely used. Overrides the default Dojo locale used to render this widget,
+ // as defined by the [HTML LANG](http://www.w3.org/TR/html401/struct/dirlang.html#adef-lang) attribute.
+ // Value must be among the list of locales specified during by the Dojo bootstrap,
+ // formatted according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt) (like en-us).
+ lang: "",
+
+ // dir: [const] String
+ // Bi-directional support, as defined by the [HTML DIR](http://www.w3.org/TR/html401/struct/dirlang.html#adef-dir)
+ // attribute. Either left-to-right "ltr" or right-to-left "rtl". If undefined, widgets renders in page's
+ // default direction.
+ dir: "",
+
+ // class: String
+ // HTML class attribute
+ "class": "",
+
+ // style: String||Object
+ // HTML style attributes as cssText string or name/value hash
+ style: "",
+
+ // title: String
+ // HTML title attribute.
+ //
+ // For form widgets this specifies a tooltip to display when hovering over
+ // the widget (just like the native HTML title attribute).
+ //
+ // For TitlePane or for when this widget is a child of a TabContainer, AccordionContainer,
+ // etc., it's used to specify the tab label, accordion pane title, etc.
+ title: "",
+
+ // tooltip: String
+ // When this widget's title attribute is used to for a tab label, accordion pane title, etc.,
+ // this specifies the tooltip to appear when the mouse is hovered over that text.
+ tooltip: "",
+
+ // baseClass: [protected] String
+ // Root CSS class of the widget (ex: dijitTextBox), used to construct CSS classes to indicate
+ // widget state.
+ baseClass: "",
+
+ // srcNodeRef: [readonly] DomNode
+ // pointer to original DOM node
+ srcNodeRef: null,
+
+ // domNode: [readonly] DomNode
+ // This is our visible representation of the widget! Other DOM
+ // Nodes may by assigned to other properties, usually through the
+ // template system's dojoAttachPoint syntax, but the domNode
+ // property is the canonical "top level" node in widget UI.
+ domNode: null,
+
+ // containerNode: [readonly] DomNode
+ // Designates where children of the source DOM node will be placed.
+ // "Children" in this case refers to both DOM nodes and widgets.
+ // For example, for myWidget:
+ //
+ // | <div dojoType=myWidget>
+ // | <b> here's a plain DOM node
+ // | <span dojoType=subWidget>and a widget</span>
+ // | <i> and another plain DOM node </i>
+ // | </div>
+ //
+ // containerNode would point to:
+ //
+ // | <b> here's a plain DOM node
+ // | <span dojoType=subWidget>and a widget</span>
+ // | <i> and another plain DOM node </i>
+ //
+ // In templated widgets, "containerNode" is set via a
+ // dojoAttachPoint assignment.
+ //
+ // containerNode must be defined for any widget that accepts innerHTML
+ // (like ContentPane or BorderContainer or even Button), and conversely
+ // is null for widgets that don't, like TextBox.
+ containerNode: null,
+
+/*=====
+ // _started: Boolean
+ // startup() has completed.
+ _started: false,
+=====*/
+
+ // attributeMap: [protected] Object
+ // attributeMap sets up a "binding" between attributes (aka properties)
+ // of the widget and the widget's DOM.
+ // Changes to widget attributes listed in attributeMap will be
+ // reflected into the DOM.
+ //
+ // For example, calling attr('title', 'hello')
+ // on a TitlePane will automatically cause the TitlePane's DOM to update
+ // with the new title.
+ //
+ // attributeMap is a hash where the key is an attribute of the widget,
+ // and the value reflects a binding to a:
+ //
+ // - DOM node attribute
+ // | focus: {node: "focusNode", type: "attribute"}
+ // Maps this.focus to this.focusNode.focus
+ //
+ // - DOM node innerHTML
+ // | title: { node: "titleNode", type: "innerHTML" }
+ // Maps this.title to this.titleNode.innerHTML
+ //
+ // - DOM node innerText
+ // | title: { node: "titleNode", type: "innerText" }
+ // Maps this.title to this.titleNode.innerText
+ //
+ // - DOM node CSS class
+ // | myClass: { node: "domNode", type: "class" }
+ // Maps this.myClass to this.domNode.className
+ //
+ // If the value is an array, then each element in the array matches one of the
+ // formats of the above list.
+ //
+ // There are also some shorthands for backwards compatibility:
+ // - string --> { node: string, type: "attribute" }, for example:
+ // | "focusNode" ---> { node: "focusNode", type: "attribute" }
+ // - "" --> { node: "domNode", type: "attribute" }
+ attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""},
+
+ // _deferredConnects: [protected] Object
+ // attributeMap addendum for event handlers that should be connected only on first use
+ _deferredConnects: {
+ onClick: "",
+ onDblClick: "",
+ onKeyDown: "",
+ onKeyPress: "",
+ onKeyUp: "",
+ onMouseMove: "",
+ onMouseDown: "",
+ onMouseOut: "",
+ onMouseOver: "",
+ onMouseLeave: "",
+ onMouseEnter: "",
+ onMouseUp: ""
+ },
+
+ onClick: dijit._connectOnUseEventHandler,
+ /*=====
+ onClick: function(event){
+ // summary:
+ // Connect to this function to receive notifications of mouse click events.
+ // event:
+ // mouse Event
+ // tags:
+ // callback
+ },
+ =====*/
+ onDblClick: dijit._connectOnUseEventHandler,
+ /*=====
+ onDblClick: function(event){
+ // summary:
+ // Connect to this function to receive notifications of mouse double click events.
+ // event:
+ // mouse Event
+ // tags:
+ // callback
+ },
+ =====*/
+ onKeyDown: dijit._connectOnUseEventHandler,
+ /*=====
+ onKeyDown: function(event){
+ // summary:
+ // Connect to this function to receive notifications of keys being pressed down.
+ // event:
+ // key Event
+ // tags:
+ // callback
+ },
+ =====*/
+ onKeyPress: dijit._connectOnUseEventHandler,
+ /*=====
+ onKeyPress: function(event){
+ // summary:
+ // Connect to this function to receive notifications of printable keys being typed.
+ // event:
+ // key Event
+ // tags:
+ // callback
+ },
+ =====*/
+ onKeyUp: dijit._connectOnUseEventHandler,
+ /*=====
+ onKeyUp: function(event){
+ // summary:
+ // Connect to this function to receive notifications of keys being released.
+ // event:
+ // key Event
+ // tags:
+ // callback
+ },
+ =====*/
+ onMouseDown: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseDown: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse button is pressed down.
+ // event:
+ // mouse Event
+ // tags:
+ // callback
+ },
+ =====*/
+ onMouseMove: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseMove: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget.
+ // event:
+ // mouse Event
+ // tags:
+ // callback
+ },
+ =====*/
+ onMouseOut: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseOut: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget.
+ // event:
+ // mouse Event
+ // tags:
+ // callback
+ },
+ =====*/
+ onMouseOver: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseOver: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget.
+ // event:
+ // mouse Event
+ // tags:
+ // callback
+ },
+ =====*/
+ onMouseLeave: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseLeave: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse moves off of this widget.
+ // event:
+ // mouse Event
+ // tags:
+ // callback
+ },
+ =====*/
+ onMouseEnter: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseEnter: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse moves onto this widget.
+ // event:
+ // mouse Event
+ // tags:
+ // callback
+ },
+ =====*/
+ onMouseUp: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseUp: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse button is released.
+ // event:
+ // mouse Event
+ // tags:
+ // callback
+ },
+ =====*/
+
+ // Constants used in templates
+
+ // _blankGif: [protected] String
+ // Path to a blank 1x1 image.
+ // Used by <img> nodes in templates that really get their image via CSS background-image.
+ _blankGif: (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")).toString(),
+
+ //////////// INITIALIZATION METHODS ///////////////////////////////////////
+
+ postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){
+ // summary:
+ // Kicks off widget instantiation. See create() for details.
+ // tags:
+ // private
+ this.create(params, srcNodeRef);
+ },
+
+ create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){
+ // summary:
+ // Kick off the life-cycle of a widget
+ // params:
+ // Hash of initialization parameters for widget, including
+ // scalar values (like title, duration etc.) and functions,
+ // typically callbacks like onClick.
+ // srcNodeRef:
+ // If a srcNodeRef (DOM node) is specified:
+ // - use srcNodeRef.innerHTML as my contents
+ // - if this is a behavioral widget then apply behavior
+ // to that srcNodeRef
+ // - otherwise, replace srcNodeRef with my generated DOM
+ // tree
+ // description:
+ // Create calls a number of widget methods (postMixInProperties, buildRendering, postCreate,
+ // etc.), some of which of you'll want to override. See http://docs.dojocampus.org/dijit/_Widget
+ // for a discussion of the widget creation lifecycle.
+ //
+ // Of course, adventurous developers could override create entirely, but this should
+ // only be done as a last resort.
+ // tags:
+ // private
+
+ // store pointer to original DOM tree
+ this.srcNodeRef = dojo.byId(srcNodeRef);
+
+ // For garbage collection. An array of handles returned by Widget.connect()
+ // Each handle returned from Widget.connect() is an array of handles from dojo.connect()
+ this._connects = [];
+
+ // For garbage collection. An array of handles returned by Widget.subscribe()
+ // The handle returned from Widget.subscribe() is the handle returned from dojo.subscribe()
+ this._subscribes = [];
+
+ // To avoid double-connects, remove entries from _deferredConnects
+ // that have been setup manually by a subclass (ex, by dojoAttachEvent).
+ // If a subclass has redefined a callback (ex: onClick) then assume it's being
+ // connected to manually.
+ this._deferredConnects = dojo.clone(this._deferredConnects);
+ for(var attr in this.attributeMap){
+ delete this._deferredConnects[attr]; // can't be in both attributeMap and _deferredConnects
+ }
+ for(attr in this._deferredConnects){
+ if(this[attr] !== dijit._connectOnUseEventHandler){
+ delete this._deferredConnects[attr]; // redefined, probably dojoAttachEvent exists
+ }
+ }
+
+ //mixin our passed parameters
+ if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
+ if(params){
+ this.params = params;
+ dojo.mixin(this,params);
+ }
+ this.postMixInProperties();
+
+ // generate an id for the widget if one wasn't specified
+ // (be sure to do this before buildRendering() because that function might
+ // expect the id to be there.)
+ if(!this.id){
+ this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
+ }
+ dijit.registry.add(this);
+
+ this.buildRendering();
+
+ if(this.domNode){
+ // Copy attributes listed in attributeMap into the [newly created] DOM for the widget.
+ this._applyAttributes();
+
+ var source = this.srcNodeRef;
+ if(source && source.parentNode){
+ source.parentNode.replaceChild(this.domNode, source);
+ }
+
+ // If the developer has specified a handler as a widget parameter
+ // (ex: new Button({onClick: ...})
+ // then naturally need to connect from DOM node to that handler immediately,
+ for(attr in this.params){
+ this._onConnect(attr);
+ }
+ }
+
+ if(this.domNode){
+ this.domNode.setAttribute("widgetId", this.id);
+ }
+ this.postCreate();
+
+ // If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC.
+ if(this.srcNodeRef && !this.srcNodeRef.parentNode){
+ delete this.srcNodeRef;
+ }
+
+ this._created = true;
+ },
+
+ _applyAttributes: function(){
+ // summary:
+ // Step during widget creation to copy all widget attributes to the
+ // DOM as per attributeMap and _setXXXAttr functions.
+ // description:
+ // Skips over blank/false attribute values, unless they were explicitly specified
+ // as parameters to the widget, since those are the default anyway,
+ // and setting tabIndex="" is different than not setting tabIndex at all.
+ //
+ // It processes the attributes in the attribute map first, and then
+ // it goes through and processes the attributes for the _setXXXAttr
+ // functions that have been specified
+ // tags:
+ // private
+ var condAttrApply = function(attr, scope){
+ if((scope.params && attr in scope.params) || scope[attr]){
+ scope.set(attr, scope[attr]);
+ }
+ };
+
+ // Do the attributes in attributeMap
+ for(var attr in this.attributeMap){
+ condAttrApply(attr, this);
+ }
+
+ // And also any attributes with custom setters
+ dojo.forEach(getSetterAttributes(this), function(a){
+ if(!(a in this.attributeMap)){
+ condAttrApply(a, this);
+ }
+ }, this);
+ },
+
+ postMixInProperties: function(){
+ // summary:
+ // Called after the parameters to the widget have been read-in,
+ // but before the widget template is instantiated. Especially
+ // useful to set properties that are referenced in the widget
+ // template.
+ // tags:
+ // protected
+ },
+
+ buildRendering: function(){
+ // summary:
+ // Construct the UI for this widget, setting this.domNode
+ // description:
+ // Most widgets will mixin `dijit._Templated`, which implements this
+ // method.
+ // tags:
+ // protected
+ this.domNode = this.srcNodeRef || dojo.create('div');
+ },
+
+ postCreate: function(){
+ // summary:
+ // Processing after the DOM fragment is created
+ // description:
+ // Called after the DOM fragment has been created, but not necessarily
+ // added to the document. Do not include any operations which rely on
+ // node dimensions or placement.
+ // tags:
+ // protected
+
+ // baseClass is a single class name or occasionally a space-separated list of names.
+ // Add those classes to the DOMNod. If RTL mode then also add with Rtl suffix.
+ if(this.baseClass){
+ var classes = this.baseClass.split(" ");
+ if(!this.isLeftToRight()){
+ classes = classes.concat( dojo.map(classes, function(name){ return name+"Rtl"; }));
+ }
+ dojo.addClass(this.domNode, classes);
+ }
+ },
+
+ startup: function(){
+ // summary:
+ // Processing after the DOM fragment is added to the document
+ // description:
+ // Called after a widget and its children have been created and added to the page,
+ // and all related widgets have finished their create() cycle, up through postCreate().
+ // This is useful for composite widgets that need to control or layout sub-widgets.
+ // Many layout widgets can use this as a wiring phase.
+ this._started = true;
+ },
+
+ //////////// DESTROY FUNCTIONS ////////////////////////////////
+
+ destroyRecursive: function(/*Boolean?*/ preserveDom){
+ // summary:
+ // Destroy this widget and its descendants
+ // description:
+ // This is the generic "destructor" function that all widget users
+ // should call to cleanly discard with a widget. Once a widget is
+ // destroyed, it is removed from the manager object.
+ // preserveDom:
+ // If true, this method will leave the original DOM structure
+ // alone of descendant Widgets. Note: This will NOT work with
+ // dijit._Templated widgets.
+
+ this._beingDestroyed = true;
+ this.destroyDescendants(preserveDom);
+ this.destroy(preserveDom);
+ },
+
+ destroy: function(/*Boolean*/ preserveDom){
+ // summary:
+ // Destroy this widget, but not its descendants.
+ // This method will, however, destroy internal widgets such as those used within a template.
+ // preserveDom: Boolean
+ // If true, this method will leave the original DOM structure alone.
+ // Note: This will not yet work with _Templated widgets
+
+ this._beingDestroyed = true;
+ this.uninitialize();
+ var d = dojo,
+ dfe = d.forEach,
+ dun = d.unsubscribe;
+ dfe(this._connects, function(array){
+ dfe(array, d.disconnect);
+ });
+ dfe(this._subscribes, function(handle){
+ dun(handle);
+ });
+
+ // destroy widgets created as part of template, etc.
+ dfe(this._supportingWidgets || [], function(w){
+ if(w.destroyRecursive){
+ w.destroyRecursive();
+ }else if(w.destroy){
+ w.destroy();
+ }
+ });
+
+ this.destroyRendering(preserveDom);
+ dijit.registry.remove(this.id);
+ this._destroyed = true;
+ },
+
+ destroyRendering: function(/*Boolean?*/ preserveDom){
+ // summary:
+ // Destroys the DOM nodes associated with this widget
+ // preserveDom:
+ // If true, this method will leave the original DOM structure alone
+ // during tear-down. Note: this will not work with _Templated
+ // widgets yet.
+ // tags:
+ // protected
+
+ if(this.bgIframe){
+ this.bgIframe.destroy(preserveDom);
+ delete this.bgIframe;
+ }
+
+ if(this.domNode){
+ if(preserveDom){
+ dojo.removeAttr(this.domNode, "widgetId");
+ }else{
+ dojo.destroy(this.domNode);
+ }
+ delete this.domNode;
+ }
+
+ if(this.srcNodeRef){
+ if(!preserveDom){
+ dojo.destroy(this.srcNodeRef);
+ }
+ delete this.srcNodeRef;
+ }
+ },
+
+ destroyDescendants: function(/*Boolean?*/ preserveDom){
+ // summary:
+ // Recursively destroy the children of this widget and their
+ // descendants.
+ // preserveDom:
+ // If true, the preserveDom attribute is passed to all descendant
+ // widget's .destroy() method. Not for use with _Templated
+ // widgets.
+
+ // get all direct descendants and destroy them recursively
+ dojo.forEach(this.getChildren(), function(widget){
+ if(widget.destroyRecursive){
+ widget.destroyRecursive(preserveDom);
+ }
+ });
+ },
+
+
+ uninitialize: function(){
+ // summary:
+ // Stub function. Override to implement custom widget tear-down
+ // behavior.
+ // tags:
+ // protected
+ return false;
+ },
+
+ ////////////////// MISCELLANEOUS METHODS ///////////////////
+
+ onFocus: function(){
+ // summary:
+ // Called when the widget becomes "active" because
+ // it or a widget inside of it either has focus, or has recently
+ // been clicked.
+ // tags:
+ // callback
+ },
+
+ onBlur: function(){
+ // summary:
+ // Called when the widget stops being "active" because
+ // focus moved to something outside of it, or the user
+ // clicked somewhere outside of it, or the widget was
+ // hidden.
+ // tags:
+ // callback
+ },
+
+ _onFocus: function(e){
+ // summary:
+ // This is where widgets do processing for when they are active,
+ // such as changing CSS classes. See onFocus() for more details.
+ // tags:
+ // protected
+ this.onFocus();
+ },
+
+ _onBlur: function(){
+ // summary:
+ // This is where widgets do processing for when they stop being active,
+ // such as changing CSS classes. See onBlur() for more details.
+ // tags:
+ // protected
+ this.onBlur();
+ },
+
+ _onConnect: function(/*String*/ event){
+ // summary:
+ // Called when someone connects to one of my handlers.
+ // "Turn on" that handler if it isn't active yet.
+ //
+ // This is also called for every single initialization parameter
+ // so need to do nothing for parameters like "id".
+ // tags:
+ // private
+ if(event in this._deferredConnects){
+ var mapNode = this[this._deferredConnects[event] || 'domNode'];
+ this.connect(mapNode, event.toLowerCase(), event);
+ delete this._deferredConnects[event];
+ }
+ },
+
+ _setClassAttr: function(/*String*/ value){
+ // summary:
+ // Custom setter for the CSS "class" attribute
+ // tags:
+ // protected
+ var mapNode = this[this.attributeMap["class"] || 'domNode'];
+ dojo.removeClass(mapNode, this["class"])
+ this["class"] = value;
+ dojo.addClass(mapNode, value);
+ },
+
+ _setStyleAttr: function(/*String||Object*/ value){
+ // summary:
+ // Sets the style attribut of the widget according to value,
+ // which is either a hash like {height: "5px", width: "3px"}
+ // or a plain string
+ // description:
+ // Determines which node to set the style on based on style setting
+ // in attributeMap.
+ // tags:
+ // protected
+
+ var mapNode = this[this.attributeMap.style || 'domNode'];
+
+ // Note: technically we should revert any style setting made in a previous call
+ // to his method, but that's difficult to keep track of.
+
+ if(dojo.isObject(value)){
+ dojo.style(mapNode, value);
+ }else{
+ if(mapNode.style.cssText){
+ mapNode.style.cssText += "; " + value;
+ }else{
+ mapNode.style.cssText = value;
+ }
+ }
+
+ this.style = value;
+ },
+
+ setAttribute: function(/*String*/ attr, /*anything*/ value){
+ // summary:
+ // Deprecated. Use set() instead.
+ // tags:
+ // deprecated
+ dojo.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.", "", "2.0");
+ this.set(attr, value);
+ },
+
+ _attrToDom: function(/*String*/ attr, /*String*/ value){
+ // summary:
+ // Reflect a widget attribute (title, tabIndex, duration etc.) to
+ // the widget DOM, as specified in attributeMap.
+ //
+ // description:
+ // Also sets this["attr"] to the new value.
+ // Note some attributes like "type"
+ // cannot be processed this way as they are not mutable.
+ //
+ // tags:
+ // private
+
+ var commands = this.attributeMap[attr];
+ dojo.forEach(dojo.isArray(commands) ? commands : [commands], function(command){
+
+ // Get target node and what we are doing to that node
+ var mapNode = this[command.node || command || "domNode"]; // DOM node
+ var type = command.type || "attribute"; // class, innerHTML, innerText, or attribute
+
+ switch(type){
+ case "attribute":
+ if(dojo.isFunction(value)){ // functions execute in the context of the widget
+ value = dojo.hitch(this, value);
+ }
+
+ // Get the name of the DOM node attribute; usually it's the same
+ // as the name of the attribute in the widget (attr), but can be overridden.
+ // Also maps handler names to lowercase, like onSubmit --> onsubmit
+ var attrName = command.attribute ? command.attribute :
+ (/^on[A-Z][a-zA-Z]*$/.test(attr) ? attr.toLowerCase() : attr);
+
+ dojo.attr(mapNode, attrName, value);
+ break;
+ case "innerText":
+ mapNode.innerHTML = "";
+ mapNode.appendChild(dojo.doc.createTextNode(value));
+ break;
+ case "innerHTML":
+ mapNode.innerHTML = value;
+ break;
+ case "class":
+ dojo.removeClass(mapNode, this[attr]);
+ dojo.addClass(mapNode, value);
+ break;
+ }
+ }, this);
+ this[attr] = value;
+ },
+
+ attr: function(/*String|Object*/name, /*Object?*/value){
+ // summary:
+ // Set or get properties on a widget instance.
+ // name:
+ // The property to get or set. If an object is passed here and not
+ // a string, its keys are used as names of attributes to be set
+ // and the value of the object as values to set in the widget.
+ // value:
+ // Optional. If provided, attr() operates as a setter. If omitted,
+ // the current value of the named property is returned.
+ // description:
+ // This method is deprecated, use get() or set() directly.
+
+ // Print deprecation warning but only once per calling function
+ if(dojo.config.isDebug){
+ var alreadyCalledHash = arguments.callee._ach || (arguments.callee._ach = {}),
+ caller = (arguments.callee.caller || "unknown caller").toString();
+ if(!alreadyCalledHash[caller]){
+ dojo.deprecated(this.declaredClass + "::attr() is deprecated. Use get() or set() instead, called from " +
+ caller, "", "2.0");
+ alreadyCalledHash[caller] = true;
+ }
+ }
+
+ var args = arguments.length;
+ if(args >= 2 || typeof name === "object"){ // setter
+ return this.set.apply(this, arguments);
+ }else{ // getter
+ return this.get(name);
+ }
+ },
+
+ get: function(name){
+ // summary:
+ // Get a property from a widget.
+ // name:
+ // The property to get.
+ // description:
+ // Get a named property from a widget. The property may
+ // potentially be retrieved via a getter method. If no getter is defined, this
+ // just retrieves the object's property.
+ // For example, if the widget has a properties "foo"
+ // and "bar" and a method named "_getFooAttr", calling:
+ // | myWidget.get("foo");
+ // would be equivalent to writing:
+ // | widget._getFooAttr();
+ // and:
+ // | myWidget.get("bar");
+ // would be equivalent to writing:
+ // | widget.bar;
+ var names = this._getAttrNames(name);
+ return this[names.g] ? this[names.g]() : this[name];
+ },
+
+ set: function(name, value){
+ // summary:
+ // Set a property on a widget
+ // name:
+ // The property to set.
+ // value:
+ // The value to set in the property.
+ // description:
+ // Sets named properties on a widget which may potentially be handled by a
+ // setter in the widget.
+ // For example, if the widget has a properties "foo"
+ // and "bar" and a method named "_setFooAttr", calling:
+ // | myWidget.set("foo", "Howdy!");
+ // would be equivalent to writing:
+ // | widget._setFooAttr("Howdy!");
+ // and:
+ // | myWidget.set("bar", 3);
+ // would be equivalent to writing:
+ // | widget.bar = 3;
+ //
+ // set() may also be called with a hash of name/value pairs, ex:
+ // | myWidget.set({
+ // | foo: "Howdy",
+ // | bar: 3
+ // | })
+ // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
+
+ if(typeof name === "object"){
+ for(var x in name){
+ this.set(x, name[x]);
+ }
+ return this;
+ }
+ var names = this._getAttrNames(name);
+ if(this[names.s]){
+ // use the explicit setter
+ var result = this[names.s].apply(this, Array.prototype.slice.call(arguments, 1));
+ }else{
+ // if param is specified as DOM node attribute, copy it
+ if(name in this.attributeMap){
+ this._attrToDom(name, value);
+ }
+ var oldValue = this[name];
+ // FIXME: what about function assignments? Any way to connect() here?
+ this[name] = value;
+ }
+ return result || this;
+ },
+
+ _attrPairNames: {}, // shared between all widgets
+ _getAttrNames: function(name){
+ // summary:
+ // Helper function for get() and set().
+ // Caches attribute name values so we don't do the string ops every time.
+ // tags:
+ // private
+
+ var apn = this._attrPairNames;
+ if(apn[name]){ return apn[name]; }
+ var uc = name.charAt(0).toUpperCase() + name.substr(1);
+ return (apn[name] = {
+ n: name+"Node",
+ s: "_set"+uc+"Attr",
+ g: "_get"+uc+"Attr"
+ });
+ },
+
+ toString: function(){
+ // summary:
+ // Returns a string that represents the widget
+ // description:
+ // When a widget is cast to a string, this method will be used to generate the
+ // output. Currently, it does not implement any sort of reversible
+ // serialization.
+ return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String
+ },
+
+ getDescendants: function(){
+ // summary:
+ // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
+ // This method should generally be avoided as it returns widgets declared in templates, which are
+ // supposed to be internal/hidden, but it's left here for back-compat reasons.
+
+ return this.containerNode ? dojo.query('[widgetId]', this.containerNode).map(dijit.byNode) : []; // dijit._Widget[]
+ },
+
+ getChildren: function(){
+ // summary:
+ // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
+ // Does not return nested widgets, nor widgets that are part of this widget's template.
+ return this.containerNode ? dijit.findWidgets(this.containerNode) : []; // dijit._Widget[]
+ },
+
+ // nodesWithKeyClick: [private] String[]
+ // List of nodes that correctly handle click events via native browser support,
+ // and don't need dijit's help
+ nodesWithKeyClick: ["input", "button"],
+
+ connect: function(
+ /*Object|null*/ obj,
+ /*String|Function*/ event,
+ /*String|Function*/ method){
+ // summary:
+ // Connects specified obj/event to specified method of this object
+ // and registers for disconnect() on widget destroy.
+ // description:
+ // Provide widget-specific analog to dojo.connect, except with the
+ // implicit use of this widget as the target object.
+ // This version of connect also provides a special "ondijitclick"
+ // event which triggers on a click or space or enter keyup
+ // returns:
+ // A handle that can be passed to `disconnect` in order to disconnect before
+ // the widget is destroyed.
+ // example:
+ // | var btn = new dijit.form.Button();
+ // | // when foo.bar() is called, call the listener we're going to
+ // | // provide in the scope of btn
+ // | btn.connect(foo, "bar", function(){
+ // | console.debug(this.toString());
+ // | });
+ // tags:
+ // protected
+
+ var d = dojo,
+ dc = d._connect,
+ handles = [];
+ if(event == "ondijitclick"){
+ // add key based click activation for unsupported nodes.
+ // do all processing onkey up to prevent spurious clicks
+ // for details see comments at top of this file where _lastKeyDownNode is defined
+ if(dojo.indexOf(this.nodesWithKeyClick, obj.nodeName.toLowerCase()) == -1){ // is NOT input or button
+ var m = d.hitch(this, method);
+ handles.push(
+ dc(obj, "onkeydown", this, function(e){
+ //console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
+ if((e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
+ !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
+ // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
+ dijit._lastKeyDownNode = e.target;
+ e.preventDefault(); // stop event to prevent scrolling on space key in IE
+ }
+ }),
+ dc(obj, "onkeyup", this, function(e){
+ //console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
+ if( (e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
+ e.target === dijit._lastKeyDownNode &&
+ !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
+ //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
+ dijit._lastKeyDownNode = null;
+ return m(e);
+ }
+ })
+ );
+ }
+ event = "onclick";
+ }
+ handles.push(dc(obj, event, this, method));
+
+ this._connects.push(handles);
+ return handles; // _Widget.Handle
+ },
+
+ disconnect: function(/* _Widget.Handle */ handles){
+ // summary:
+ // Disconnects handle created by `connect`.
+ // Also removes handle from this widget's list of connects.
+ // tags:
+ // protected
+ for(var i=0; i<this._connects.length; i++){
+ if(this._connects[i] == handles){
+ dojo.forEach(handles, dojo.disconnect);
+ this._connects.splice(i, 1);
+ return;
+ }
+ }
+ },
+
+ subscribe: function(
+ /*String*/ topic,
+ /*String|Function*/ method){
+ // summary:
+ // Subscribes to the specified topic and calls the specified method
+ // of this object and registers for unsubscribe() on widget destroy.
+ // description:
+ // Provide widget-specific analog to dojo.subscribe, except with the
+ // implicit use of this widget as the target object.
+ // example:
+ // | var btn = new dijit.form.Button();
+ // | // when /my/topic is published, this button changes its label to
+ // | // be the parameter of the topic.
+ // | btn.subscribe("/my/topic", function(v){
+ // | this.set("label", v);
+ // | });
+ var d = dojo,
+ handle = d.subscribe(topic, this, method);
+
+ // return handles for Any widget that may need them
+ this._subscribes.push(handle);
+ return handle;
+ },
+
+ unsubscribe: function(/*Object*/ handle){
+ // summary:
+ // Unsubscribes handle created by this.subscribe.
+ // Also removes handle from this widget's list of subscriptions
+ for(var i=0; i<this._subscribes.length; i++){
+ if(this._subscribes[i] == handle){
+ dojo.unsubscribe(handle);
+ this._subscribes.splice(i, 1);
+ return;
+ }
+ }
+ },
+
+ isLeftToRight: function(){
+ // summary:
+ // Return this widget's explicit or implicit orientation (true for LTR, false for RTL)
+ // tags:
+ // protected
+ return this.dir ? (this.dir == "ltr") : dojo._isBodyLtr(); //Boolean
+ },
+
+ isFocusable: function(){
+ // summary:
+ // Return true if this widget can currently be focused
+ // and false if not
+ return this.focus && (dojo.style(this.domNode, "display") != "none");
+ },
+
+ placeAt: function(/* String|DomNode|_Widget */reference, /* String?|Int? */position){
+ // summary:
+ // Place this widget's domNode reference somewhere in the DOM based
+ // on standard dojo.place conventions, or passing a Widget reference that
+ // contains and addChild member.
+ //
+ // description:
+ // A convenience function provided in all _Widgets, providing a simple
+ // shorthand mechanism to put an existing (or newly created) Widget
+ // somewhere in the dom, and allow chaining.
+ //
+ // reference:
+ // The String id of a domNode, a domNode reference, or a reference to a Widget posessing
+ // an addChild method.
+ //
+ // position:
+ // If passed a string or domNode reference, the position argument
+ // accepts a string just as dojo.place does, one of: "first", "last",
+ // "before", or "after".
+ //
+ // If passed a _Widget reference, and that widget reference has an ".addChild" method,
+ // it will be called passing this widget instance into that method, supplying the optional
+ // position index passed.
+ //
+ // returns:
+ // dijit._Widget
+ // Provides a useful return of the newly created dijit._Widget instance so you
+ // can "chain" this function by instantiating, placing, then saving the return value
+ // to a variable.
+ //
+ // example:
+ // | // create a Button with no srcNodeRef, and place it in the body:
+ // | var button = new dijit.form.Button({ label:"click" }).placeAt(dojo.body());
+ // | // now, 'button' is still the widget reference to the newly created button
+ // | dojo.connect(button, "onClick", function(e){ console.log('click'); });
+ //
+ // example:
+ // | // create a button out of a node with id="src" and append it to id="wrapper":
+ // | var button = new dijit.form.Button({},"src").placeAt("wrapper");
+ //
+ // example:
+ // | // place a new button as the first element of some div
+ // | var button = new dijit.form.Button({ label:"click" }).placeAt("wrapper","first");
+ //
+ // example:
+ // | // create a contentpane and add it to a TabContainer
+ // | var tc = dijit.byId("myTabs");
+ // | new dijit.layout.ContentPane({ href:"foo.html", title:"Wow!" }).placeAt(tc)
+
+ if(reference.declaredClass && reference.addChild){
+ reference.addChild(this, position);
+ }else{
+ dojo.place(this.domNode, reference, position);
+ }
+ return this;
+ },
+
+ _onShow: function(){
+ // summary:
+ // Internal method called when this widget is made visible.
+ // See `onShow` for details.
+ this.onShow();
+ },
+
+ onShow: function(){
+ // summary:
+ // Called when this widget becomes the selected pane in a
+ // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
+ // `dijit.layout.AccordionContainer`, etc.
+ //
+ // Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
+ // tags:
+ // callback
+ },
+
+ onHide: function(){
+ // summary:
+ // Called when another widget becomes the selected pane in a
+ // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
+ // `dijit.layout.AccordionContainer`, etc.
+ //
+ // Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
+ // tags:
+ // callback
+ },
+
+ onClose: function(){
+ // summary:
+ // Called when this widget is being displayed as a popup (ex: a Calendar popped
+ // up from a DateTextBox), and it is hidden.
+ // This is called from the dijit.popup code, and should not be called directly.
+ //
+ // Also used as a parameter for children of `dijit.layout.StackContainer` or subclasses.
+ // Callback if a user tries to close the child. Child will be closed if this function returns true.
+ // tags:
+ // extension
+
+ return true; // Boolean
+ }
+});
+
+})();
+
+}
+
+if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.string"] = true;
+dojo.provide("dojo.string");
+
+/*=====
+dojo.string = {
+ // summary: String utilities for Dojo
+};
+=====*/
+
+dojo.string.rep = function(/*String*/str, /*Integer*/num){
+ // summary:
+ // Efficiently replicate a string `n` times.
+ // str:
+ // the string to replicate
+ // num:
+ // number of times to replicate the string
+
+ if(num <= 0 || !str){ return ""; }
+
+ var buf = [];
+ for(;;){
+ if(num & 1){
+ buf.push(str);
+ }
+ if(!(num >>= 1)){ break; }
+ str += str;
+ }
+ return buf.join(""); // String
+};
+
+dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){
+ // summary:
+ // Pad a string to guarantee that it is at least `size` length by
+ // filling with the character `ch` at either the start or end of the
+ // string. Pads at the start, by default.
+ // text:
+ // the string to pad
+ // size:
+ // length to provide padding
+ // ch:
+ // character to pad, defaults to '0'
+ // end:
+ // adds padding at the end if true, otherwise pads at start
+ // example:
+ // | // Fill the string to length 10 with "+" characters on the right. Yields "Dojo++++++".
+ // | dojo.string.pad("Dojo", 10, "+", true);
+
+ if(!ch){
+ ch = '0';
+ }
+ var out = String(text),
+ pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length));
+ return end ? out + pad : pad + out; // String
+};
+
+dojo.string.substitute = function( /*String*/ template,
+ /*Object|Array*/map,
+ /*Function?*/ transform,
+ /*Object?*/ thisObject){
+ // summary:
+ // Performs parameterized substitutions on a string. Throws an
+ // exception if any parameter is unmatched.
+ // template:
+ // a string with expressions in the form `${key}` to be replaced or
+ // `${key:format}` which specifies a format function. keys are case-sensitive.
+ // map:
+ // hash to search for substitutions
+ // transform:
+ // a function to process all parameters before substitution takes
+ // place, e.g. mylib.encodeXML
+ // thisObject:
+ // where to look for optional format function; default to the global
+ // namespace
+ // example:
+ // Substitutes two expressions in a string from an Array or Object
+ // | // returns "File 'foo.html' is not found in directory '/temp'."
+ // | // by providing substitution data in an Array
+ // | dojo.string.substitute(
+ // | "File '${0}' is not found in directory '${1}'.",
+ // | ["foo.html","/temp"]
+ // | );
+ // |
+ // | // also returns "File 'foo.html' is not found in directory '/temp'."
+ // | // but provides substitution data in an Object structure. Dotted
+ // | // notation may be used to traverse the structure.
+ // | dojo.string.substitute(
+ // | "File '${name}' is not found in directory '${info.dir}'.",
+ // | { name: "foo.html", info: { dir: "/temp" } }
+ // | );
+ // example:
+ // Use a transform function to modify the values:
+ // | // returns "file 'foo.html' is not found in directory '/temp'."
+ // | dojo.string.substitute(
+ // | "${0} is not found in ${1}.",
+ // | ["foo.html","/temp"],
+ // | function(str){
+ // | // try to figure out the type
+ // | var prefix = (str.charAt(0) == "/") ? "directory": "file";
+ // | return prefix + " '" + str + "'";
+ // | }
+ // | );
+ // example:
+ // Use a formatter
+ // | // returns "thinger -- howdy"
+ // | dojo.string.substitute(
+ // | "${0:postfix}", ["thinger"], null, {
+ // | postfix: function(value, key){
+ // | return value + " -- howdy";
+ // | }
+ // | }
+ // | );
+
+ thisObject = thisObject || dojo.global;
+ transform = transform ?
+ dojo.hitch(thisObject, transform) : function(v){ return v; };
+
+ return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,
+ function(match, key, format){
+ var value = dojo.getObject(key, false, map);
+ if(format){
+ value = dojo.getObject(format, false, thisObject).call(thisObject, value, key);
+ }
+ return transform(value, key).toString();
+ }); // String
+};
+
+/*=====
+dojo.string.trim = function(str){
+ // summary:
+ // Trims whitespace from both sides of the string
+ // str: String
+ // String to be trimmed
+ // returns: String
+ // Returns the trimmed string
+ // description:
+ // This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript).
+ // The short yet performant version of this function is dojo.trim(),
+ // which is part of Dojo base. Uses String.prototype.trim instead, if available.
+ return ""; // String
+}
+=====*/
+
+dojo.string.trim = String.prototype.trim ?
+ dojo.trim : // aliasing to the native function
+ function(str){
+ str = str.replace(/^\s+/, '');
+ for(var i = str.length - 1; i >= 0; i--){
+ if(/\S/.test(str.charAt(i))){
+ str = str.substring(0, i + 1);
+ break;
+ }
+ }
+ return str;
+ };
+
+}
+
+if(!dojo._hasResource["dojo.cache"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.cache"] = true;
+dojo.provide("dojo.cache");
+
+/*=====
+dojo.cache = {
+ // summary:
+ // A way to cache string content that is fetchable via `dojo.moduleUrl`.
+};
+=====*/
+
+(function(){
+ var cache = {};
+ dojo.cache = function(/*String||Object*/module, /*String*/url, /*String||Object?*/value){
+ // summary:
+ // A getter and setter for storing the string content associated with the
+ // module and url arguments.
+ // description:
+ // module and url are used to call `dojo.moduleUrl()` to generate a module URL.
+ // If value is specified, the cache value for the moduleUrl will be set to
+ // that value. Otherwise, dojo.cache will fetch the moduleUrl and store it
+ // in its internal cache and return that cached value for the URL. To clear
+ // a cache value pass null for value. Since XMLHttpRequest (XHR) is used to fetch the
+ // the URL contents, only modules on the same domain of the page can use this capability.
+ // The build system can inline the cache values though, to allow for xdomain hosting.
+ // module: String||Object
+ // If a String, the module name to use for the base part of the URL, similar to module argument
+ // to `dojo.moduleUrl`. If an Object, something that has a .toString() method that
+ // generates a valid path for the cache item. For example, a dojo._Url object.
+ // url: String
+ // The rest of the path to append to the path derived from the module argument. If
+ // module is an object, then this second argument should be the "value" argument instead.
+ // value: String||Object?
+ // If a String, the value to use in the cache for the module/url combination.
+ // If an Object, it can have two properties: value and sanitize. The value property
+ // should be the value to use in the cache, and sanitize can be set to true or false,
+ // to indicate if XML declarations should be removed from the value and if the HTML
+ // inside a body tag in the value should be extracted as the real value. The value argument
+ // or the value property on the value argument are usually only used by the build system
+ // as it inlines cache content.
+ // example:
+ // To ask dojo.cache to fetch content and store it in the cache (the dojo["cache"] style
+ // of call is used to avoid an issue with the build system erroneously trying to intern
+ // this example. To get the build system to intern your dojo.cache calls, use the
+ // "dojo.cache" style of call):
+ // | //If template.html contains "<h1>Hello</h1>" that will be
+ // | //the value for the text variable.
+ // | var text = dojo["cache"]("my.module", "template.html");
+ // example:
+ // To ask dojo.cache to fetch content and store it in the cache, and sanitize the input
+ // (the dojo["cache"] style of call is used to avoid an issue with the build system
+ // erroneously trying to intern this example. To get the build system to intern your
+ // dojo.cache calls, use the "dojo.cache" style of call):
+ // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
+ // | //text variable will contain just "<h1>Hello</h1>".
+ // | var text = dojo["cache"]("my.module", "template.html", {sanitize: true});
+ // example:
+ // Same example as previous, but demostrates how an object can be passed in as
+ // the first argument, then the value argument can then be the second argument.
+ // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
+ // | //text variable will contain just "<h1>Hello</h1>".
+ // | var text = dojo["cache"](new dojo._Url("my/module/template.html"), {sanitize: true});
+
+ //Module could be a string, or an object that has a toString() method
+ //that will return a useful path. If it is an object, then the "url" argument
+ //will actually be the value argument.
+ if(typeof module == "string"){
+ var pathObj = dojo.moduleUrl(module, url);
+ }else{
+ pathObj = module;
+ value = url;
+ }
+ var key = pathObj.toString();
+
+ var val = value;
+ if(value != undefined && !dojo.isString(value)){
+ val = ("value" in value ? value.value : undefined);
+ }
+
+ var sanitize = value && value.sanitize ? true : false;
+
+ if(typeof val == "string"){
+ //We have a string, set cache value
+ val = cache[key] = sanitize ? dojo.cache._sanitize(val) : val;
+ }else if(val === null){
+ //Remove cached value
+ delete cache[key];
+ }else{
+ //Allow cache values to be empty strings. If key property does
+ //not exist, fetch it.
+ if(!(key in cache)){
+ val = dojo._getText(key);
+ cache[key] = sanitize ? dojo.cache._sanitize(val) : val;
+ }
+ val = cache[key];
+ }
+ return val; //String
+ };
+
+ dojo.cache._sanitize = function(/*String*/val){
+ // summary:
+ // Strips <?xml ...?> declarations so that external SVG and XML
+ // documents can be added to a document without worry. Also, if the string
+ // is an HTML document, only the part inside the body tag is returned.
+ // description:
+ // Copied from dijit._Templated._sanitizeTemplateString.
+ if(val){
+ val = val.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
+ var matches = val.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+ if(matches){
+ val = matches[1];
+ }
+ }else{
+ val = "";
+ }
+ return val; //String
+ };
+})();
+
+}
+
+if(!dojo._hasResource["dijit._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._Templated"] = true;
+dojo.provide("dijit._Templated");
+
+
+
+
+
+
+dojo.declare("dijit._Templated",
+ null,
+ {
+ // summary:
+ // Mixin for widgets that are instantiated from a template
+
+ // templateString: [protected] String
+ // A string that represents the widget template. Pre-empts the
+ // templatePath. In builds that have their strings "interned", the
+ // templatePath is converted to an inline templateString, thereby
+ // preventing a synchronous network call.
+ //
+ // Use in conjunction with dojo.cache() to load from a file.
+ templateString: null,
+
+ // templatePath: [protected deprecated] String
+ // Path to template (HTML file) for this widget relative to dojo.baseUrl.
+ // Deprecated: use templateString with dojo.cache() instead.
+ templatePath: null,
+
+ // widgetsInTemplate: [protected] Boolean
+ // Should we parse the template to find widgets that might be
+ // declared in markup inside it? False by default.
+ widgetsInTemplate: false,
+
+ // skipNodeCache: [protected] Boolean
+ // If using a cached widget template node poses issues for a
+ // particular widget class, it can set this property to ensure
+ // that its template is always re-built from a string
+ _skipNodeCache: false,
+
+ // _earlyTemplatedStartup: Boolean
+ // A fallback to preserve the 1.0 - 1.3 behavior of children in
+ // templates having their startup called before the parent widget
+ // fires postCreate. Defaults to 'false', causing child widgets to
+ // have their .startup() called immediately before a parent widget
+ // .startup(), but always after the parent .postCreate(). Set to
+ // 'true' to re-enable to previous, arguably broken, behavior.
+ _earlyTemplatedStartup: false,
+
+ // _attachPoints: [private] String[]
+ // List of widget attribute names associated with dojoAttachPoint=... in the
+ // template, ex: ["containerNode", "labelNode"]
+/*=====
+ _attachPoints: [],
+ =====*/
+
+ constructor: function(){
+ this._attachPoints = [];
+ },
+
+ _stringRepl: function(tmpl){
+ // summary:
+ // Does substitution of ${foo} type properties in template string
+ // tags:
+ // private
+ var className = this.declaredClass, _this = this;
+ // Cache contains a string because we need to do property replacement
+ // do the property replacement
+ return dojo.string.substitute(tmpl, this, function(value, key){
+ if(key.charAt(0) == '!'){ value = dojo.getObject(key.substr(1), false, _this); }
+ if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide
+ if(value == null){ return ""; }
+
+ // Substitution keys beginning with ! will skip the transform step,
+ // in case a user wishes to insert unescaped markup, e.g. ${!foo}
+ return key.charAt(0) == "!" ? value :
+ // Safer substitution, see heading "Attribute values" in
+ // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
+ value.toString().replace(/"/g,"&quot;"); //TODO: add &amp? use encodeXML method?
+ }, this);
+ },
+
+ // method over-ride
+ buildRendering: function(){
+ // summary:
+ // Construct the UI for this widget from a template, setting this.domNode.
+ // tags:
+ // protected
+
+ // Lookup cached version of template, and download to cache if it
+ // isn't there already. Returns either a DomNode or a string, depending on
+ // whether or not the template contains ${foo} replacement parameters.
+ var cached = dijit._Templated.getCachedTemplate(this.templatePath, this.templateString, this._skipNodeCache);
+
+ var node;
+ if(dojo.isString(cached)){
+ node = dojo._toDom(this._stringRepl(cached));
+ if(node.nodeType != 1){
+ // Flag common problems such as templates with multiple top level nodes (nodeType == 11)
+ throw new Error("Invalid template: " + cached);
+ }
+ }else{
+ // if it's a node, all we have to do is clone it
+ node = cached.cloneNode(true);
+ }
+
+ this.domNode = node;
+
+ // recurse through the node, looking for, and attaching to, our
+ // attachment points and events, which should be defined on the template node.
+ this._attachTemplateNodes(node);
+
+ if(this.widgetsInTemplate){
+ // Make sure dojoType is used for parsing widgets in template.
+ // The dojo.parser.query could be changed from multiversion support.
+ var parser = dojo.parser, qry, attr;
+ if(parser._query != "[dojoType]"){
+ qry = parser._query;
+ attr = parser._attrName;
+ parser._query = "[dojoType]";
+ parser._attrName = "dojoType";
+ }
+
+ // Store widgets that we need to start at a later point in time
+ var cw = (this._startupWidgets = dojo.parser.parse(node, {
+ noStart: !this._earlyTemplatedStartup,
+ inherited: {dir: this.dir, lang: this.lang}
+ }));
+
+ // Restore the query.
+ if(qry){
+ parser._query = qry;
+ parser._attrName = attr;
+ }
+
+ this._supportingWidgets = dijit.findWidgets(node);
+
+ this._attachTemplateNodes(cw, function(n,p){
+ return n[p];
+ });
+ }
+
+ this._fillContent(this.srcNodeRef);
+ },
+
+ _fillContent: function(/*DomNode*/ source){
+ // summary:
+ // Relocate source contents to templated container node.
+ // this.containerNode must be able to receive children, or exceptions will be thrown.
+ // tags:
+ // protected
+ var dest = this.containerNode;
+ if(source && dest){
+ while(source.hasChildNodes()){
+ dest.appendChild(source.firstChild);
+ }
+ }
+ },
+
+ _attachTemplateNodes: function(rootNode, getAttrFunc){
+ // summary:
+ // Iterate through the template and attach functions and nodes accordingly.
+ // description:
+ // Map widget properties and functions to the handlers specified in
+ // the dom node and it's descendants. This function iterates over all
+ // nodes and looks for these properties:
+ // * dojoAttachPoint
+ // * dojoAttachEvent
+ // * waiRole
+ // * waiState
+ // rootNode: DomNode|Array[Widgets]
+ // the node to search for properties. All children will be searched.
+ // getAttrFunc: Function?
+ // a function which will be used to obtain property for a given
+ // DomNode/Widget
+ // tags:
+ // private
+
+ getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); };
+
+ var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*"));
+ var x = dojo.isArray(rootNode) ? 0 : -1;
+ for(; x<nodes.length; x++){
+ var baseNode = (x == -1) ? rootNode : nodes[x];
+ if(this.widgetsInTemplate && getAttrFunc(baseNode, "dojoType")){
+ continue;
+ }
+ // Process dojoAttachPoint
+ var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint");
+ if(attachPoint){
+ var point, points = attachPoint.split(/\s*,\s*/);
+ while((point = points.shift())){
+ if(dojo.isArray(this[point])){
+ this[point].push(baseNode);
+ }else{
+ this[point]=baseNode;
+ }
+ this._attachPoints.push(point);
+ }
+ }
+
+ // Process dojoAttachEvent
+ var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent");
+ if(attachEvent){
+ // NOTE: we want to support attributes that have the form
+ // "domEvent: nativeEvent; ..."
+ var event, events = attachEvent.split(/\s*,\s*/);
+ var trim = dojo.trim;
+ while((event = events.shift())){
+ if(event){
+ var thisFunc = null;
+ if(event.indexOf(":") != -1){
+ // oh, if only JS had tuple assignment
+ var funcNameArr = event.split(":");
+ event = trim(funcNameArr[0]);
+ thisFunc = trim(funcNameArr[1]);
+ }else{
+ event = trim(event);
+ }
+ if(!thisFunc){
+ thisFunc = event;
+ }
+ this.connect(baseNode, event, thisFunc);
+ }
+ }
+ }
+
+ // waiRole, waiState
+ var role = getAttrFunc(baseNode, "waiRole");
+ if(role){
+ dijit.setWaiRole(baseNode, role);
+ }
+ var values = getAttrFunc(baseNode, "waiState");
+ if(values){
+ dojo.forEach(values.split(/\s*,\s*/), function(stateValue){
+ if(stateValue.indexOf('-') != -1){
+ var pair = stateValue.split('-');
+ dijit.setWaiState(baseNode, pair[0], pair[1]);
+ }
+ });
+ }
+ }
+ },
+
+ startup: function(){
+ dojo.forEach(this._startupWidgets, function(w){
+ if(w && !w._started && w.startup){
+ w.startup();
+ }
+ });
+ this.inherited(arguments);
+ },
+
+ destroyRendering: function(){
+ // Delete all attach points to prevent IE6 memory leaks.
+ dojo.forEach(this._attachPoints, function(point){
+ delete this[point];
+ }, this);
+ this._attachPoints = [];
+
+ this.inherited(arguments);
+ }
+ }
+);
+
+// key is either templatePath or templateString; object is either string or DOM tree
+dijit._Templated._templateCache = {};
+
+dijit._Templated.getCachedTemplate = function(templatePath, templateString, alwaysUseString){
+ // summary:
+ // Static method to get a template based on the templatePath or
+ // templateString key
+ // templatePath: String||dojo.uri.Uri
+ // The URL to get the template from.
+ // templateString: String?
+ // a string to use in lieu of fetching the template from a URL. Takes precedence
+ // over templatePath
+ // returns: Mixed
+ // Either string (if there are ${} variables that need to be replaced) or just
+ // a DOM tree (if the node can be cloned directly)
+
+ // is it already cached?
+ var tmplts = dijit._Templated._templateCache;
+ var key = templateString || templatePath;
+ var cached = tmplts[key];
+ if(cached){
+ try{
+ // if the cached value is an innerHTML string (no ownerDocument) or a DOM tree created within the current document, then use the current cached value
+ if(!cached.ownerDocument || cached.ownerDocument == dojo.doc){
+ // string or node of the same document
+ return cached;
+ }
+ }catch(e){ /* squelch */ } // IE can throw an exception if cached.ownerDocument was reloaded
+ dojo.destroy(cached);
+ }
+
+ // If necessary, load template string from template path
+ if(!templateString){
+ templateString = dojo.cache(templatePath, {sanitize: true});
+ }
+ templateString = dojo.string.trim(templateString);
+
+ if(alwaysUseString || templateString.match(/\$\{([^\}]+)\}/g)){
+ // there are variables in the template so all we can do is cache the string
+ return (tmplts[key] = templateString); //String
+ }else{
+ // there are no variables in the template so we can cache the DOM tree
+ var node = dojo._toDom(templateString);
+ if(node.nodeType != 1){
+ throw new Error("Invalid template: " + templateString);
+ }
+ return (tmplts[key] = node); //Node
+ }
+};
+
+if(dojo.isIE){
+ dojo.addOnWindowUnload(function(){
+ var cache = dijit._Templated._templateCache;
+ for(var key in cache){
+ var value = cache[key];
+ if(typeof value == "object"){ // value is either a string or a DOM node template
+ dojo.destroy(value);
+ }
+ delete cache[key];
+ }
+ });
+}
+
+// These arguments can be specified for widgets which are used in templates.
+// Since any widget can be specified as sub widgets in template, mix it
+// into the base widget class. (This is a hack, but it's effective.)
+dojo.extend(dijit._Widget,{
+ dojoAttachEvent: "",
+ dojoAttachPoint: "",
+ waiRole: "",
+ waiState:""
+});
+
+}
+
+if(!dojo._hasResource["dijit._Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._Container"] = true;
+dojo.provide("dijit._Container");
+
+dojo.declare("dijit._Container",
+ null,
+ {
+ // summary:
+ // Mixin for widgets that contain a set of widget children.
+ // description:
+ // Use this mixin for widgets that needs to know about and
+ // keep track of their widget children. Suitable for widgets like BorderContainer
+ // and TabContainer which contain (only) a set of child widgets.
+ //
+ // It's not suitable for widgets like ContentPane
+ // which contains mixed HTML (plain DOM nodes in addition to widgets),
+ // and where contained widgets are not necessarily directly below
+ // this.containerNode. In that case calls like addChild(node, position)
+ // wouldn't make sense.
+
+ // isContainer: [protected] Boolean
+ // Indicates that this widget acts as a "parent" to the descendant widgets.
+ // When the parent is started it will call startup() on the child widgets.
+ // See also `isLayoutContainer`.
+ isContainer: true,
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ if(!this.containerNode){
+ // all widgets with descendants must set containerNode
+ this.containerNode = this.domNode;
+ }
+ },
+
+ addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
+ // summary:
+ // Makes the given widget a child of this widget.
+ // description:
+ // Inserts specified child widget's dom node as a child of this widget's
+ // container node, and possibly does other processing (such as layout).
+
+ var refNode = this.containerNode;
+ if(insertIndex && typeof insertIndex == "number"){
+ var children = this.getChildren();
+ if(children && children.length >= insertIndex){
+ refNode = children[insertIndex-1].domNode;
+ insertIndex = "after";
+ }
+ }
+ dojo.place(widget.domNode, refNode, insertIndex);
+
+ // If I've been started but the child widget hasn't been started,
+ // start it now. Make sure to do this after widget has been
+ // inserted into the DOM tree, so it can see that it's being controlled by me,
+ // so it doesn't try to size itself.
+ if(this._started && !widget._started){
+ widget.startup();
+ }
+ },
+
+ removeChild: function(/*Widget or int*/ widget){
+ // summary:
+ // Removes the passed widget instance from this widget but does
+ // not destroy it. You can also pass in an integer indicating
+ // the index within the container to remove
+
+ if(typeof widget == "number" && widget > 0){
+ widget = this.getChildren()[widget];
+ }
+
+ if(widget){
+ var node = widget.domNode;
+ if(node && node.parentNode){
+ node.parentNode.removeChild(node); // detach but don't destroy
+ }
+ }
+ },
+
+ hasChildren: function(){
+ // summary:
+ // Returns true if widget has children, i.e. if this.containerNode contains something.
+ return this.getChildren().length > 0; // Boolean
+ },
+
+ destroyDescendants: function(/*Boolean*/ preserveDom){
+ // summary:
+ // Destroys all the widgets inside this.containerNode,
+ // but not this widget itself
+ dojo.forEach(this.getChildren(), function(child){ child.destroyRecursive(preserveDom); });
+ },
+
+ _getSiblingOfChild: function(/*dijit._Widget*/ child, /*int*/ dir){
+ // summary:
+ // Get the next or previous widget sibling of child
+ // dir:
+ // if 1, get the next sibling
+ // if -1, get the previous sibling
+ // tags:
+ // private
+ var node = child.domNode,
+ which = (dir>0 ? "nextSibling" : "previousSibling");
+ do{
+ node = node[which];
+ }while(node && (node.nodeType != 1 || !dijit.byNode(node)));
+ return node && dijit.byNode(node); // dijit._Widget
+ },
+
+ getIndexOfChild: function(/*dijit._Widget*/ child){
+ // summary:
+ // Gets the index of the child in this container or -1 if not found
+ return dojo.indexOf(this.getChildren(), child); // int
+ },
+
+ startup: function(){
+ // summary:
+ // Called after all the widgets have been instantiated and their
+ // dom nodes have been inserted somewhere under dojo.doc.body.
+ //
+ // Widgets should override this method to do any initialization
+ // dependent on other widgets existing, and then call
+ // this superclass method to finish things off.
+ //
+ // startup() in subclasses shouldn't do anything
+ // size related because the size of the widget hasn't been set yet.
+
+ if(this._started){ return; }
+
+ // Startup all children of this widget
+ dojo.forEach(this.getChildren(), function(child){ child.startup(); });
+
+ this.inherited(arguments);
+ }
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit._Contained"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._Contained"] = true;
+dojo.provide("dijit._Contained");
+
+dojo.declare("dijit._Contained",
+ null,
+ {
+ // summary:
+ // Mixin for widgets that are children of a container widget
+ //
+ // example:
+ // | // make a basic custom widget that knows about it's parents
+ // | dojo.declare("my.customClass",[dijit._Widget,dijit._Contained],{});
+
+ getParent: function(){
+ // summary:
+ // Returns the parent widget of this widget, assuming the parent
+ // specifies isContainer
+ var parent = dijit.getEnclosingWidget(this.domNode.parentNode);
+ return parent && parent.isContainer ? parent : null;
+ },
+
+ _getSibling: function(/*String*/ which){
+ // summary:
+ // Returns next or previous sibling
+ // which:
+ // Either "next" or "previous"
+ // tags:
+ // private
+ var node = this.domNode;
+ do{
+ node = node[which+"Sibling"];
+ }while(node && node.nodeType != 1);
+ return node && dijit.byNode(node); // dijit._Widget
+ },
+
+ getPreviousSibling: function(){
+ // summary:
+ // Returns null if this is the first child of the parent,
+ // otherwise returns the next element sibling to the "left".
+
+ return this._getSibling("previous"); // dijit._Widget
+ },
+
+ getNextSibling: function(){
+ // summary:
+ // Returns null if this is the last child of the parent,
+ // otherwise returns the next element sibling to the "right".
+
+ return this._getSibling("next"); // dijit._Widget
+ },
+
+ getIndexInParent: function(){
+ // summary:
+ // Returns the index of this widget within its container parent.
+ // It returns -1 if the parent does not exist, or if the parent
+ // is not a dijit._Container
+
+ var p = this.getParent();
+ if(!p || !p.getIndexOfChild){
+ return -1; // int
+ }
+ return p.getIndexOfChild(this); // int
+ }
+ }
+ );
+
+
+}
+
+if(!dojo._hasResource["dijit.layout._LayoutWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout._LayoutWidget"] = true;
+dojo.provide("dijit.layout._LayoutWidget");
+
+
+
+
+
+dojo.declare("dijit.layout._LayoutWidget",
+ [dijit._Widget, dijit._Container, dijit._Contained],
+ {
+ // summary:
+ // Base class for a _Container widget which is responsible for laying out its children.
+ // Widgets which mixin this code must define layout() to manage placement and sizing of the children.
+
+ // baseClass: [protected extension] String
+ // This class name is applied to the widget's domNode
+ // and also may be used to generate names for sub nodes,
+ // for example dijitTabContainer-content.
+ baseClass: "dijitLayoutContainer",
+
+ // isLayoutContainer: [protected] Boolean
+ // Indicates that this widget is going to call resize() on its
+ // children widgets, setting their size, when they become visible.
+ isLayoutContainer: true,
+
+ postCreate: function(){
+ dojo.addClass(this.domNode, "dijitContainer");
+
+ this.inherited(arguments);
+ },
+
+ startup: function(){
+ // summary:
+ // Called after all the widgets have been instantiated and their
+ // dom nodes have been inserted somewhere under dojo.doc.body.
+ //
+ // Widgets should override this method to do any initialization
+ // dependent on other widgets existing, and then call
+ // this superclass method to finish things off.
+ //
+ // startup() in subclasses shouldn't do anything
+ // size related because the size of the widget hasn't been set yet.
+
+ if(this._started){ return; }
+
+ // Need to call inherited first - so that child widgets get started
+ // up correctly
+ this.inherited(arguments);
+
+ // If I am a not being controlled by a parent layout widget...
+ var parent = this.getParent && this.getParent()
+ if(!(parent && parent.isLayoutContainer)){
+ // Do recursive sizing and layout of all my descendants
+ // (passing in no argument to resize means that it has to glean the size itself)
+ this.resize();
+
+ // Since my parent isn't a layout container, and my style *may be* width=height=100%
+ // or something similar (either set directly or via a CSS class),
+ // monitor when my size changes so that I can re-layout.
+ // For browsers where I can't directly monitor when my size changes,
+ // monitor when the viewport changes size, which *may* indicate a size change for me.
+ this.connect(dojo.isIE ? this.domNode : dojo.global, 'onresize', function(){
+ // Using function(){} closure to ensure no arguments to resize.
+ this.resize();
+ });
+ }
+ },
+
+ resize: function(changeSize, resultSize){
+ // summary:
+ // Call this to resize a widget, or after its size has changed.
+ // description:
+ // Change size mode:
+ // When changeSize is specified, changes the marginBox of this widget
+ // and forces it to relayout its contents accordingly.
+ // changeSize may specify height, width, or both.
+ //
+ // If resultSize is specified it indicates the size the widget will
+ // become after changeSize has been applied.
+ //
+ // Notification mode:
+ // When changeSize is null, indicates that the caller has already changed
+ // the size of the widget, or perhaps it changed because the browser
+ // window was resized. Tells widget to relayout its contents accordingly.
+ //
+ // If resultSize is also specified it indicates the size the widget has
+ // become.
+ //
+ // In either mode, this method also:
+ // 1. Sets this._borderBox and this._contentBox to the new size of
+ // the widget. Queries the current domNode size if necessary.
+ // 2. Calls layout() to resize contents (and maybe adjust child widgets).
+ //
+ // changeSize: Object?
+ // Sets the widget to this margin-box size and position.
+ // May include any/all of the following properties:
+ // | {w: int, h: int, l: int, t: int}
+ //
+ // resultSize: Object?
+ // The margin-box size of this widget after applying changeSize (if
+ // changeSize is specified). If caller knows this size and
+ // passes it in, we don't need to query the browser to get the size.
+ // | {w: int, h: int}
+
+ var node = this.domNode;
+
+ // set margin box size, unless it wasn't specified, in which case use current size
+ if(changeSize){
+ dojo.marginBox(node, changeSize);
+
+ // set offset of the node
+ if(changeSize.t){ node.style.top = changeSize.t + "px"; }
+ if(changeSize.l){ node.style.left = changeSize.l + "px"; }
+ }
+
+ // If either height or width wasn't specified by the user, then query node for it.
+ // But note that setting the margin box and then immediately querying dimensions may return
+ // inaccurate results, so try not to depend on it.
+ var mb = resultSize || {};
+ dojo.mixin(mb, changeSize || {}); // changeSize overrides resultSize
+ if( !("h" in mb) || !("w" in mb) ){
+ mb = dojo.mixin(dojo.marginBox(node), mb); // just use dojo.marginBox() to fill in missing values
+ }
+
+ // Compute and save the size of my border box and content box
+ // (w/out calling dojo.contentBox() since that may fail if size was recently set)
+ var cs = dojo.getComputedStyle(node);
+ var me = dojo._getMarginExtents(node, cs);
+ var be = dojo._getBorderExtents(node, cs);
+ var bb = (this._borderBox = {
+ w: mb.w - (me.w + be.w),
+ h: mb.h - (me.h + be.h)
+ });
+ var pe = dojo._getPadExtents(node, cs);
+ this._contentBox = {
+ l: dojo._toPixelValue(node, cs.paddingLeft),
+ t: dojo._toPixelValue(node, cs.paddingTop),
+ w: bb.w - pe.w,
+ h: bb.h - pe.h
+ };
+
+ // Callback for widget to adjust size of its children
+ this.layout();
+ },
+
+ layout: function(){
+ // summary:
+ // Widgets override this method to size and position their contents/children.
+ // When this is called this._contentBox is guaranteed to be set (see resize()).
+ //
+ // This is called after startup(), and also when the widget's size has been
+ // changed.
+ // tags:
+ // protected extension
+ },
+
+ _setupChild: function(/*dijit._Widget*/child){
+ // summary:
+ // Common setup for initial children and children which are added after startup
+ // tags:
+ // protected extension
+
+ dojo.addClass(child.domNode, this.baseClass+"-child");
+ if(child.baseClass){
+ dojo.addClass(child.domNode, this.baseClass+"-"+child.baseClass);
+ }
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ // Overrides _Container.addChild() to call _setupChild()
+ this.inherited(arguments);
+ if(this._started){
+ this._setupChild(child);
+ }
+ },
+
+ removeChild: function(/*dijit._Widget*/ child){
+ // Overrides _Container.removeChild() to remove class added by _setupChild()
+ dojo.removeClass(child.domNode, this.baseClass+"-child");
+ if(child.baseClass){
+ dojo.removeClass(child.domNode, this.baseClass+"-"+child.baseClass);
+ }
+ this.inherited(arguments);
+ }
+ }
+);
+
+dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
+ // summary:
+ // Given the margin-box size of a node, return its content box size.
+ // Functions like dojo.contentBox() but is more reliable since it doesn't have
+ // to wait for the browser to compute sizes.
+ var cs = dojo.getComputedStyle(node);
+ var me = dojo._getMarginExtents(node, cs);
+ var pb = dojo._getPadBorderExtents(node, cs);
+ return {
+ l: dojo._toPixelValue(node, cs.paddingLeft),
+ t: dojo._toPixelValue(node, cs.paddingTop),
+ w: mb.w - (me.w + pb.w),
+ h: mb.h - (me.h + pb.h)
+ };
+};
+
+(function(){
+ var capitalize = function(word){
+ return word.substring(0,1).toUpperCase() + word.substring(1);
+ };
+
+ var size = function(widget, dim){
+ // size the child
+ widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim);
+
+ // record child's size, but favor our own numbers when we have them.
+ // the browser lies sometimes
+ dojo.mixin(widget, dojo.marginBox(widget.domNode));
+ dojo.mixin(widget, dim);
+ };
+
+ dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Object[]*/ children){
+ // summary
+ // Layout a bunch of child dom nodes within a parent dom node
+ // container:
+ // parent node
+ // dim:
+ // {l, t, w, h} object specifying dimensions of container into which to place children
+ // children:
+ // an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]
+
+ // copy dim because we are going to modify it
+ dim = dojo.mixin({}, dim);
+
+ dojo.addClass(container, "dijitLayoutContainer");
+
+ // Move "client" elements to the end of the array for layout. a11y dictates that the author
+ // needs to be able to put them in the document in tab-order, but this algorithm requires that
+ // client be last.
+ children = dojo.filter(children, function(item){ return item.layoutAlign != "client"; })
+ .concat(dojo.filter(children, function(item){ return item.layoutAlign == "client"; }));
+
+ // set positions/sizes
+ dojo.forEach(children, function(child){
+ var elm = child.domNode,
+ pos = child.layoutAlign;
+
+ // set elem to upper left corner of unused space; may move it later
+ var elmStyle = elm.style;
+ elmStyle.left = dim.l+"px";
+ elmStyle.top = dim.t+"px";
+ elmStyle.bottom = elmStyle.right = "auto";
+
+ dojo.addClass(elm, "dijitAlign" + capitalize(pos));
+
+ // set size && adjust record of remaining space.
+ // note that setting the width of a <div> may affect its height.
+ if(pos == "top" || pos == "bottom"){
+ size(child, { w: dim.w });
+ dim.h -= child.h;
+ if(pos == "top"){
+ dim.t += child.h;
+ }else{
+ elmStyle.top = dim.t + dim.h + "px";
+ }
+ }else if(pos == "left" || pos == "right"){
+ size(child, { h: dim.h });
+ dim.w -= child.w;
+ if(pos == "left"){
+ dim.l += child.w;
+ }else{
+ elmStyle.left = dim.l + dim.w + "px";
+ }
+ }else if(pos == "client"){
+ size(child, dim);
+ }
+ });
+ };
+
+})();
+
+}
+
+if(!dojo._hasResource["dijit._CssStateMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._CssStateMixin"] = true;
+dojo.provide("dijit._CssStateMixin");
+
+
+dojo.declare("dijit._CssStateMixin", [], {
+ // summary:
+ // Mixin for widgets to set CSS classes on the widget DOM nodes depending on hover/mouse press/focus
+ // state changes, and also higher-level state changes such becoming disabled or selected.
+ //
+ // description:
+ // By mixing this class into your widget, and setting the this.baseClass attribute, it will automatically
+ // maintain CSS classes on the widget root node (this.domNode) depending on hover,
+ // active, focus, etc. state. Ex: with a baseClass of dijitButton, it will apply the classes
+ // dijitButtonHovered and dijitButtonActive, as the user moves the mouse over the widget and clicks it.
+ //
+ // It also sets CSS like dijitButtonDisabled based on widget semantic state.
+ //
+ // By setting the cssStateNodes attribute, a widget can also track events on subnodes (like buttons
+ // within the widget).
+
+ // cssStateNodes: [protected] Object
+ // List of sub-nodes within the widget that need CSS classes applied on mouse hover/press and focus
+ //.
+ // Each entry in the hash is a an attachpoint names (like "upArrowButton") mapped to a CSS class names
+ // (like "dijitUpArrowButton"). Example:
+ // | {
+ // | "upArrowButton": "dijitUpArrowButton",
+ // | "downArrowButton": "dijitDownArrowButton"
+ // | }
+ // The above will set the CSS class dijitUpArrowButton to the this.upArrowButton DOMNode when it
+ // is hovered, etc.
+ cssStateNodes: {},
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // Automatically monitor mouse events (essentially :hover and :active) on this.domNode
+ dojo.forEach(["onmouseenter", "onmouseleave", "onmousedown"], function(e){
+ this.connect(this.domNode, e, "_cssMouseEvent");
+ }, this);
+
+ // Monitoring changes to disabled, readonly, etc. state, and update CSS class of root node
+ this.connect(this, "set", function(name, value){
+ if(arguments.length >= 2 && {disabled: true, readOnly: true, checked:true, selected:true}[name]){
+ this._setStateClass();
+ }
+ });
+
+ // The widget coming in/out of the focus change affects it's state
+ dojo.forEach(["_onFocus", "_onBlur"], function(ap){
+ this.connect(this, ap, "_setStateClass");
+ }, this);
+
+ // Events on sub nodes within the widget
+ for(var ap in this.cssStateNodes){
+ this._trackMouseState(this[ap], this.cssStateNodes[ap]);
+ }
+ // Set state initially; there's probably no hover/active/focus state but widget might be
+ // disabled/readonly so we want to set CSS classes for those conditions.
+ this._setStateClass();
+ },
+
+ _cssMouseEvent: function(/*Event*/ event){
+ // summary:
+ // Sets _hovering and _active properties depending on mouse state,
+ // then calls _setStateClass() to set appropriate CSS classes for this.domNode.
+
+ if(!this.disabled){
+ switch(event.type){
+ case "mouseenter":
+ case "mouseover": // generated on non-IE browsers even though we connected to mouseenter
+ this._hovering = true;
+ this._active = this._mouseDown;
+ break;
+
+ case "mouseleave":
+ case "mouseout": // generated on non-IE browsers even though we connected to mouseleave
+ this._hovering = false;
+ this._active = false;
+ break;
+
+ case "mousedown" :
+ this._active = true;
+ this._mouseDown = true;
+ // Set a global event to handle mouseup, so it fires properly
+ // even if the cursor leaves this.domNode before the mouse up event.
+ // Alternately could set active=false on mouseout.
+ var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
+ this._active = false;
+ this._mouseDown = false;
+ this._setStateClass();
+ this.disconnect(mouseUpConnector);
+ });
+ break;
+ }
+ this._setStateClass();
+ }
+ },
+
+ _setStateClass: function(){
+ // summary:
+ // Update the visual state of the widget by setting the css classes on this.domNode
+ // (or this.stateNode if defined) by combining this.baseClass with
+ // various suffixes that represent the current widget state(s).
+ //
+ // description:
+ // In the case where a widget has multiple
+ // states, it sets the class based on all possible
+ // combinations. For example, an invalid form widget that is being hovered
+ // will be "dijitInput dijitInputInvalid dijitInputHover dijitInputInvalidHover".
+ //
+ // The widget may have one or more of the following states, determined
+ // by this.state, this.checked, this.valid, and this.selected:
+ // - Error - ValidationTextBox sets this.state to "Error" if the current input value is invalid
+ // - Checked - ex: a checkmark or a ToggleButton in a checked state, will have this.checked==true
+ // - Selected - ex: currently selected tab will have this.selected==true
+ //
+ // In addition, it may have one or more of the following states,
+ // based on this.disabled and flags set in _onMouse (this._active, this._hovering, this._focused):
+ // - Disabled - if the widget is disabled
+ // - Active - if the mouse (or space/enter key?) is being pressed down
+ // - Focused - if the widget has focus
+ // - Hover - if the mouse is over the widget
+
+ // Compute new set of classes
+ var newStateClasses = this.baseClass.split(" ");
+
+ function multiply(modifier){
+ newStateClasses = newStateClasses.concat(dojo.map(newStateClasses, function(c){ return c+modifier; }), "dijit"+modifier);
+ }
+
+ if(!this.isLeftToRight()){
+ // For RTL mode we need to set an addition class like dijitTextBoxRtl.
+ multiply("Rtl");
+ }
+
+ if(this.checked){
+ multiply("Checked");
+ }
+ if(this.state){
+ multiply(this.state);
+ }
+ if(this.selected){
+ multiply("Selected");
+ }
+
+ if(this.disabled){
+ multiply("Disabled");
+ }else if(this.readOnly){
+ multiply("ReadOnly");
+ }else{
+ if(this._active){
+ multiply("Active");
+ }else if(this._hovering){
+ multiply("Hover");
+ }
+ }
+
+ if(this._focused){
+ multiply("Focused");
+ }
+
+ // Remove old state classes and add new ones.
+ // For performance concerns we only write into domNode.className once.
+ var tn = this.stateNode || this.domNode,
+ classHash = {}; // set of all classes (state and otherwise) for node
+
+ dojo.forEach(tn.className.split(" "), function(c){ classHash[c] = true; });
+
+ if("_stateClasses" in this){
+ dojo.forEach(this._stateClasses, function(c){ delete classHash[c]; });
+ }
+
+ dojo.forEach(newStateClasses, function(c){ classHash[c] = true; });
+
+ var newClasses = [];
+ for(var c in classHash){
+ newClasses.push(c);
+ }
+ tn.className = newClasses.join(" ");
+
+ this._stateClasses = newStateClasses;
+ },
+
+ _trackMouseState: function(/*DomNode*/ node, /*String*/ clazz){
+ // summary:
+ // Track mouse/focus events on specified node and set CSS class on that node to indicate
+ // current state. Usually not called directly, but via cssStateNodes attribute.
+ // description:
+ // Given class=foo, will set the following CSS class on the node
+ // - fooActive: if the user is currently pressing down the mouse button while over the node
+ // - fooHover: if the user is hovering the mouse over the node, but not pressing down a button
+ // - fooFocus: if the node is focused
+ //
+ // Note that it won't set any classes if the widget is disabled.
+ // node: DomNode
+ // Should be a sub-node of the widget, not the top node (this.domNode), since the top node
+ // is handled specially and automatically just by mixing in this class.
+ // clazz: String
+ // CSS class name (ex: dijitSliderUpArrow).
+
+ // Current state of node (initially false)
+ // NB: setting specifically to false because dojo.toggleClass() needs true boolean as third arg
+ var hovering=false, active=false, focused=false;
+
+ var self = this,
+ cn = dojo.hitch(this, "connect", node);
+
+ function setClass(){
+ var disabled = ("disabled" in self && self.disabled) || ("readonly" in self && self.readonly);
+ dojo.toggleClass(node, clazz+"Hover", hovering && !active && !disabled);
+ dojo.toggleClass(node, clazz+"Active", active && !disabled);
+ dojo.toggleClass(node, clazz+"Focused", focused && !disabled);
+ }
+
+ // Mouse
+ cn("onmouseenter", function(){
+ hovering = true;
+ setClass();
+ });
+ cn("onmouseleave", function(){
+ hovering = false;
+ active = false;
+ setClass();
+ });
+ cn("onmousedown", function(){
+ active = true;
+ setClass();
+ });
+ cn("onmouseup", function(){
+ active = false;
+ setClass();
+ });
+
+ // Focus
+ cn("onfocus", function(){
+ focused = true;
+ setClass();
+ });
+ cn("onblur", function(){
+ focused = false;
+ setClass();
+ });
+
+ // Just in case widget is enabled/disabled while it has focus/hover/active state.
+ // Maybe this is overkill.
+ this.connect(this, "set", function(name, value){
+ if(name == "disabled" || name == "readOnly"){
+ setClass();
+ }
+ });
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.form._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form._FormWidget"] = true;
+dojo.provide("dijit.form._FormWidget");
+
+
+
+
+
+
+
+dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._CssStateMixin],
+ {
+ // summary:
+ // Base class for widgets corresponding to native HTML elements such as <checkbox> or <button>,
+ // which can be children of a <form> node or a `dijit.form.Form` widget.
+ //
+ // description:
+ // Represents a single HTML element.
+ // All these widgets should have these attributes just like native HTML input elements.
+ // You can set them during widget construction or afterwards, via `dijit._Widget.attr`.
+ //
+ // They also share some common methods.
+
+ // name: String
+ // Name used when submitting form; same as "name" attribute or plain HTML elements
+ name: "",
+
+ // alt: String
+ // Corresponds to the native HTML <input> element's attribute.
+ alt: "",
+
+ // value: String
+ // Corresponds to the native HTML <input> element's attribute.
+ value: "",
+
+ // type: String
+ // Corresponds to the native HTML <input> element's attribute.
+ type: "text",
+
+ // tabIndex: Integer
+ // Order fields are traversed when user hits the tab key
+ tabIndex: "0",
+
+ // disabled: Boolean
+ // Should this widget respond to user input?
+ // In markup, this is specified as "disabled='disabled'", or just "disabled".
+ disabled: false,
+
+ // intermediateChanges: Boolean
+ // Fires onChange for each value change or only on demand
+ intermediateChanges: false,
+
+ // scrollOnFocus: Boolean
+ // On focus, should this widget scroll into view?
+ scrollOnFocus: true,
+
+ // These mixins assume that the focus node is an INPUT, as many but not all _FormWidgets are.
+ attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+ value: "focusNode",
+ id: "focusNode",
+ tabIndex: "focusNode",
+ alt: "focusNode",
+ title: "focusNode"
+ }),
+
+ postMixInProperties: function(){
+ // Setup name=foo string to be referenced from the template (but only if a name has been specified)
+ // Unfortunately we can't use attributeMap to set the name due to IE limitations, see #8660
+ // Regarding escaping, see heading "Attribute values" in
+ // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
+ this.nameAttrSetting = this.name ? ('name="' + this.name.replace(/'/g, "&quot;") + '"') : '';
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.connect(this.domNode, "onmousedown", "_onMouseDown");
+ },
+
+ _setDisabledAttr: function(/*Boolean*/ value){
+ this.disabled = value;
+ dojo.attr(this.focusNode, 'disabled', value);
+ if(this.valueNode){
+ dojo.attr(this.valueNode, 'disabled', value);
+ }
+ dijit.setWaiState(this.focusNode, "disabled", value);
+
+ if(value){
+ // reset these, because after the domNode is disabled, we can no longer receive
+ // mouse related events, see #4200
+ this._hovering = false;
+ this._active = false;
+
+ // clear tab stop(s) on this widget's focusable node(s) (ComboBox has two focusable nodes)
+ var attachPointNames = "tabIndex" in this.attributeMap ? this.attributeMap.tabIndex : "focusNode";
+ dojo.forEach(dojo.isArray(attachPointNames) ? attachPointNames : [attachPointNames], function(attachPointName){
+ var node = this[attachPointName];
+ // complex code because tabIndex=-1 on a <div> doesn't work on FF
+ if(dojo.isWebKit || dijit.hasDefaultTabStop(node)){ // see #11064 about webkit bug
+ node.setAttribute('tabIndex', "-1");
+ }else{
+ node.removeAttribute('tabIndex');
+ }
+ }, this);
+ }else{
+ this.focusNode.setAttribute('tabIndex', this.tabIndex);
+ }
+ },
+
+ setDisabled: function(/*Boolean*/ disabled){
+ // summary:
+ // Deprecated. Use set('disabled', ...) instead.
+ dojo.deprecated("setDisabled("+disabled+") is deprecated. Use set('disabled',"+disabled+") instead.", "", "2.0");
+ this.set('disabled', disabled);
+ },
+
+ _onFocus: function(e){
+ if(this.scrollOnFocus){
+ dojo.window.scrollIntoView(this.domNode);
+ }
+ this.inherited(arguments);
+ },
+
+ isFocusable: function(){
+ // summary:
+ // Tells if this widget is focusable or not. Used internally by dijit.
+ // tags:
+ // protected
+ return !this.disabled && !this.readOnly && this.focusNode && (dojo.style(this.domNode, "display") != "none");
+ },
+
+ focus: function(){
+ // summary:
+ // Put focus on this widget
+ dijit.focus(this.focusNode);
+ },
+
+ compare: function(/*anything*/val1, /*anything*/val2){
+ // summary:
+ // Compare 2 values (as returned by attr('value') for this widget).
+ // tags:
+ // protected
+ if(typeof val1 == "number" && typeof val2 == "number"){
+ return (isNaN(val1) && isNaN(val2)) ? 0 : val1 - val2;
+ }else if(val1 > val2){
+ return 1;
+ }else if(val1 < val2){
+ return -1;
+ }else{
+ return 0;
+ }
+ },
+
+ onChange: function(newValue){
+ // summary:
+ // Callback when this widget's value is changed.
+ // tags:
+ // callback
+ },
+
+ // _onChangeActive: [private] Boolean
+ // Indicates that changes to the value should call onChange() callback.
+ // This is false during widget initialization, to avoid calling onChange()
+ // when the initial value is set.
+ _onChangeActive: false,
+
+ _handleOnChange: function(/*anything*/ newValue, /* Boolean? */ priorityChange){
+ // summary:
+ // Called when the value of the widget is set. Calls onChange() if appropriate
+ // newValue:
+ // the new value
+ // priorityChange:
+ // For a slider, for example, dragging the slider is priorityChange==false,
+ // but on mouse up, it's priorityChange==true. If intermediateChanges==true,
+ // onChange is only called form priorityChange=true events.
+ // tags:
+ // private
+ this._lastValue = newValue;
+ if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){
+ // this block executes not for a change, but during initialization,
+ // and is used to store away the original value (or for ToggleButton, the original checked state)
+ this._resetValue = this._lastValueReported = newValue;
+ }
+ if((this.intermediateChanges || priorityChange || priorityChange === undefined) &&
+ ((typeof newValue != typeof this._lastValueReported) ||
+ this.compare(newValue, this._lastValueReported) != 0)){
+ this._lastValueReported = newValue;
+ if(this._onChangeActive){
+ if(this._onChangeHandle){
+ clearTimeout(this._onChangeHandle);
+ }
+ // setTimout allows hidden value processing to run and
+ // also the onChange handler can safely adjust focus, etc
+ this._onChangeHandle = setTimeout(dojo.hitch(this,
+ function(){
+ this._onChangeHandle = null;
+ this.onChange(newValue);
+ }), 0); // try to collapse multiple onChange's fired faster than can be processed
+ }
+ }
+ },
+
+ create: function(){
+ // Overrides _Widget.create()
+ this.inherited(arguments);
+ this._onChangeActive = true;
+ },
+
+ destroy: function(){
+ if(this._onChangeHandle){ // destroy called before last onChange has fired
+ clearTimeout(this._onChangeHandle);
+ this.onChange(this._lastValueReported);
+ }
+ this.inherited(arguments);
+ },
+
+ setValue: function(/*String*/ value){
+ // summary:
+ // Deprecated. Use set('value', ...) instead.
+ dojo.deprecated("dijit.form._FormWidget:setValue("+value+") is deprecated. Use set('value',"+value+") instead.", "", "2.0");
+ this.set('value', value);
+ },
+
+ getValue: function(){
+ // summary:
+ // Deprecated. Use get('value') instead.
+ dojo.deprecated(this.declaredClass+"::getValue() is deprecated. Use get('value') instead.", "", "2.0");
+ return this.get('value');
+ },
+
+ _onMouseDown: function(e){
+ // If user clicks on the button, even if the mouse is released outside of it,
+ // this button should get focus (to mimics native browser buttons).
+ // This is also needed on chrome because otherwise buttons won't get focus at all,
+ // which leads to bizarre focus restore on Dialog close etc.
+ if(!e.ctrlKey && this.isFocusable()){ // !e.ctrlKey to ignore right-click on mac
+ // Set a global event to handle mouseup, so it fires properly
+ // even if the cursor leaves this.domNode before the mouse up event.
+ var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
+ if (this.isFocusable()) {
+ this.focus();
+ }
+ this.disconnect(mouseUpConnector);
+ });
+ }
+ }
+});
+
+dojo.declare("dijit.form._FormValueWidget", dijit.form._FormWidget,
+{
+ // summary:
+ // Base class for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values.
+ // description:
+ // Each _FormValueWidget represents a single input value, and has a (possibly hidden) <input> element,
+ // to which it serializes it's input value, so that form submission (either normal submission or via FormBind?)
+ // works as expected.
+
+ // Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared
+ // directly in the template as read by the parser in order to function. IE is known to specifically
+ // require the 'name' attribute at element creation time. See #8484, #8660.
+ // TODO: unclear what that {value: ""} is for; FormWidget.attributeMap copies value to focusNode,
+ // so maybe {value: ""} is so the value *doesn't* get copied to focusNode?
+ // Seems like we really want value removed from attributeMap altogether
+ // (although there's no easy way to do that now)
+
+ // readOnly: Boolean
+ // Should this widget respond to user input?
+ // In markup, this is specified as "readOnly".
+ // Similar to disabled except readOnly form values are submitted.
+ readOnly: false,
+
+ attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
+ value: "",
+ readOnly: "focusNode"
+ }),
+
+ _setReadOnlyAttr: function(/*Boolean*/ value){
+ this.readOnly = value;
+ dojo.attr(this.focusNode, 'readOnly', value);
+ dijit.setWaiState(this.focusNode, "readonly", value);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ if(dojo.isIE){ // IE won't stop the event with keypress
+ this.connect(this.focusNode || this.domNode, "onkeydown", this._onKeyDown);
+ }
+ // Update our reset value if it hasn't yet been set (because this.set()
+ // is only called when there *is* a value)
+ if(this._resetValue === undefined){
+ this._resetValue = this.value;
+ }
+ },
+
+ _setValueAttr: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
+ // summary:
+ // Hook so attr('value', value) works.
+ // description:
+ // Sets the value of the widget.
+ // If the value has changed, then fire onChange event, unless priorityChange
+ // is specified as null (or false?)
+ this.value = newValue;
+ this._handleOnChange(newValue, priorityChange);
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // Hook so attr('value') works.
+ return this._lastValue;
+ },
+
+ undo: function(){
+ // summary:
+ // Restore the value to the last value passed to onChange
+ this._setValueAttr(this._lastValueReported, false);
+ },
+
+ reset: function(){
+ // summary:
+ // Reset the widget's value to what it was at initialization time
+ this._hasBeenBlurred = false;
+ this._setValueAttr(this._resetValue, true);
+ },
+
+ _onKeyDown: function(e){
+ if(e.keyCode == dojo.keys.ESCAPE && !(e.ctrlKey || e.altKey || e.metaKey)){
+ var te;
+ if(dojo.isIE){
+ e.preventDefault(); // default behavior needs to be stopped here since keypress is too late
+ te = document.createEventObject();
+ te.keyCode = dojo.keys.ESCAPE;
+ te.shiftKey = e.shiftKey;
+ e.srcElement.fireEvent('onkeypress', te);
+ }
+ }
+ },
+
+ _layoutHackIE7: function(){
+ // summary:
+ // Work around table sizing bugs on IE7 by forcing redraw
+
+ if(dojo.isIE == 7){ // fix IE7 layout bug when the widget is scrolled out of sight
+ var domNode = this.domNode;
+ var parent = domNode.parentNode;
+ var pingNode = domNode.firstChild || domNode; // target node most unlikely to have a custom filter
+ var origFilter = pingNode.style.filter; // save custom filter, most likely nothing
+ var _this = this;
+ while(parent && parent.clientHeight == 0){ // search for parents that haven't rendered yet
+ (function ping(){
+ var disconnectHandle = _this.connect(parent, "onscroll",
+ function(e){
+ _this.disconnect(disconnectHandle); // only call once
+ pingNode.style.filter = (new Date()).getMilliseconds(); // set to anything that's unique
+ setTimeout(function(){ pingNode.style.filter = origFilter }, 0); // restore custom filter, if any
+ }
+ );
+ })();
+ parent = parent.parentNode;
+ }
+ }
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.dijit"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.dijit"] = true;
+dojo.provide("dijit.dijit");
+
+/*=====
+dijit.dijit = {
+ // summary:
+ // A roll-up for common dijit methods
+ // description:
+ // A rollup file for the build system including the core and common
+ // dijit files.
+ //
+ // example:
+ // | <script type="text/javascript" src="js/dojo/dijit/dijit.js"></script>
+ //
+};
+=====*/
+
+// All the stuff in _base (these are the function that are guaranteed available without an explicit dojo.require)
+
+
+// And some other stuff that we tend to pull in all the time anyway
+
+
+
+
+
+
+
+}
+
+if(!dojo._hasResource["dojo.fx.Toggler"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.fx.Toggler"] = true;
+dojo.provide("dojo.fx.Toggler");
+
+dojo.declare("dojo.fx.Toggler", null, {
+ // summary:
+ // A simple `dojo.Animation` toggler API.
+ //
+ // description:
+ // 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. All available members are mixed into
+ // these animations from the constructor (for example, `node`,
+ // `showDuration`, `hideDuration`).
+ //
+ // example:
+ // | var t = new dojo.fx.Toggler({
+ // | node: "nodeId",
+ // | showDuration: 500,
+ // | // hideDuration will default to "200"
+ // | showFunc: dojo.fx.wipeIn,
+ // | // hideFunc will default to "fadeOut"
+ // | });
+ // | t.show(100); // delay showing for 100ms
+ // | // ...time passes...
+ // | t.hide();
+
+ // node: DomNode
+ // the node to target for the showing and hiding animations
+ 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,
+
+ // 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.
+ // FIXME: also would be nice to specify individual showArgs/hideArgs mixed into
+ // each animation individually.
+ // FIXME: also would be nice to have events from the animations exposed/bridged
+
+ /*=====
+ _showArgs: null,
+ _showAnim: null,
+
+ _hideArgs: null,
+ _hideAnim: null,
+
+ _isShowing: false,
+ _isHiding: false,
+ =====*/
+
+ 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));
+ },
+
+ show: function(delay){
+ // summary: Toggle the node to showing
+ // delay: Integer?
+ // Ammount of time to stall playing the show animation
+ return this.showAnim.play(delay || 0);
+ },
+
+ hide: function(delay){
+ // summary: Toggle the node to hidden
+ // delay: Integer?
+ // Ammount of time to stall playing the hide animation
+ return this.hideAnim.play(delay || 0);
+ }
+});
+
+}
+
+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");
+ // FIXME: remove this back-compat require in 2.0
+/*=====
+dojo.fx = {
+ // summary: Effects library on top of Base animations
+};
+=====*/
+(function(){
+
+ var d = dojo,
+ _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;
+ d.forEach(this._animations, function(a){
+ this.duration += a.duration;
+ if(a.delay){ this.duration += a.delay; }
+ }, this);
+ };
+ d.extend(_chain, {
+ _onAnimate: function(){
+ this._fire("onAnimate", arguments);
+ },
+ _onEnd: function(){
+ d.disconnect(this._onAnimateCtx);
+ d.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 = d.connect(this._current, "onAnimate", this, "_onAnimate");
+ this._onEndCtx = d.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 = d.connect(this._current, "beforeBegin", this, function(){
+ this._fire("beforeBegin");
+ }),
+ onBegin = d.connect(this._current, "onBegin", this, function(arg){
+ this._fire("onBegin", arguments);
+ }),
+ onPlay = d.connect(this._current, "onPlay", this, function(arg){
+ this._fire("onPlay", arguments);
+ d.disconnect(beforeBegin);
+ d.disconnect(onBegin);
+ d.disconnect(onPlay);
+ });
+ if(this._onAnimateCtx){
+ d.disconnect(this._onAnimateCtx);
+ }
+ this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
+ if(this._onEndCtx){
+ d.disconnect(this._onEndCtx);
+ }
+ this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
+ this._current.play.apply(this._current, arguments);
+ return this;
+ },
+ pause: function(){
+ if(this._current){
+ var e = d.connect(this._current, "onPause", this, function(arg){
+ this._fire("onPause", arguments);
+ d.disconnect(e);
+ });
+ this._current.pause();
+ }
+ return this;
+ },
+ gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
+ this.pause();
+ var offset = this.duration * percent;
+ this._current = null;
+ d.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 / this._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 = d.connect(this._current, "onStop", this, function(arg){
+ this._fire("onStop", arguments);
+ d.disconnect(e);
+ });
+ this._current.stop();
+ }
+ return this;
+ },
+ status: function(){
+ return this._current ? this._current.status() : "stopped";
+ },
+ destroy: function(){
+ if(this._onAnimateCtx){ d.disconnect(this._onAnimateCtx); }
+ if(this._onEndCtx){ d.disconnect(this._onEndCtx); }
+ }
+ });
+ d.extend(_chain, _baseObj);
+
+ dojo.fx.chain = function(/*dojo.Animation[]*/ animations){
+ // summary:
+ // Chain a list of `dojo.Animation`s to run in sequence
+ //
+ // description:
+ // Return a `dojo.Animation` which will play all passed
+ // `dojo.Animation` instances in sequence, firing its own
+ // synthesized events simulating a single animation. (eg:
+ // onEnd of this animation means the end of the chain,
+ // not the individual animations within)
+ //
+ // example:
+ // Once `node` is faded out, fade in `otherNode`
+ // | 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;
+ d.forEach(animations, function(a){
+ var duration = a.duration;
+ if(a.delay){ duration += a.delay; }
+ if(this.duration < duration){ this.duration = duration; }
+ this._connects.push(d.connect(a, "onEnd", this, "_onEnd"));
+ }, this);
+
+ this._pseudoAnimation = new d.Animation({curve: [0, 1], duration: this.duration});
+ var self = this;
+ d.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"],
+ function(evt){
+ self._connects.push(d.connect(self._pseudoAnimation, evt,
+ function(){ self._fire(evt, arguments); }
+ ));
+ }
+ );
+ };
+ d.extend(_combine, {
+ _doAction: function(action, args){
+ d.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;
+ d.forEach(this._animations, function(a){
+ a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay);
+ });
+ this._call("gotoPercent", 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(){
+ d.forEach(this._connects, dojo.disconnect);
+ }
+ });
+ d.extend(_combine, _baseObj);
+
+ dojo.fx.combine = function(/*dojo.Animation[]*/ animations){
+ // summary:
+ // Combine a list of `dojo.Animation`s to run in parallel
+ //
+ // description:
+ // Combine an array of `dojo.Animation`s to run in parallel,
+ // providing a new `dojo.Animation` instance encompasing each
+ // animation, firing standard animation events.
+ //
+ // example:
+ // Fade out `node` while fading in `otherNode` simultaneously
+ // | dojo.fx.combine([
+ // | dojo.fadeIn({ node:node }),
+ // | dojo.fadeOut({ node:otherNode })
+ // | ]).play();
+ //
+ // example:
+ // When the longest animation ends, execute a function:
+ // | var anim = dojo.fx.combine([
+ // | dojo.fadeIn({ node: n, duration:700 }),
+ // | dojo.fadeOut({ node: otherNode, duration: 300 })
+ // | ]);
+ // | dojo.connect(anim, "onEnd", function(){
+ // | // overall animation is done.
+ // | });
+ // | anim.play(); // play the animation
+ //
+ return new _combine(animations); // dojo.Animation
+ };
+
+ dojo.fx.wipeIn = function(/*Object*/ args){
+ // summary:
+ // Expand a node to it's natural height.
+ //
+ // description:
+ // 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: Object
+ // A hash-map of standard `dojo.Animation` constructor properties
+ // (such as easing: node: duration: and so on)
+ //
+ // example:
+ // | dojo.fx.wipeIn({
+ // | node:"someId"
+ // | }).play()
+ var node = args.node = d.byId(args.node), s = node.style, o;
+
+ var anim = d.animateProperty(d.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
+ o = s.overflow;
+ s.overflow = "hidden";
+ if(s.visibility == "hidden" || s.display == "none"){
+ s.height = "1px";
+ s.display = "";
+ s.visibility = "";
+ return 1;
+ }else{
+ var height = d.style(node, "height");
+ return Math.max(height, 1);
+ }
+ },
+ end: function(){
+ return node.scrollHeight;
+ }
+ }
+ }
+ }, args));
+
+ d.connect(anim, "onEnd", function(){
+ s.height = "auto";
+ s.overflow = o;
+ });
+
+ return anim; // dojo.Animation
+ }
+
+ dojo.fx.wipeOut = function(/*Object*/ args){
+ // summary:
+ // Shrink a node to nothing and hide it.
+ //
+ // description:
+ // Returns an animation that will shrink node defined in "args"
+ // from it's current height to 1px, and then hide it.
+ //
+ // args: Object
+ // A hash-map of standard `dojo.Animation` constructor properties
+ // (such as easing: node: duration: and so on)
+ //
+ // example:
+ // | dojo.fx.wipeOut({ node:"someId" }).play()
+
+ var node = args.node = d.byId(args.node), s = node.style, o;
+
+ var anim = d.animateProperty(d.mixin({
+ properties: {
+ height: {
+ end: 1 // 0 causes IE to display the whole panel
+ }
+ }
+ }, args));
+
+ d.connect(anim, "beforeBegin", function(){
+ o = s.overflow;
+ s.overflow = "hidden";
+ s.display = "";
+ });
+ d.connect(anim, "onEnd", function(){
+ s.overflow = o;
+ s.height = "auto";
+ s.display = "none";
+ });
+
+ return anim; // dojo.Animation
+ }
+
+ dojo.fx.slideTo = function(/*Object*/ args){
+ // summary:
+ // Slide a node to a new top/left position
+ //
+ // description:
+ // Returns an animation that will slide "node"
+ // defined in args Object from its current position to
+ // the position defined by (args.left, args.top).
+ //
+ // args: Object
+ // A hash-map of standard `dojo.Animation` constructor properties
+ // (such as easing: node: duration: and so on). Special args members
+ // are `top` and `left`, which indicate the new position to slide to.
+ //
+ // example:
+ // | dojo.fx.slideTo({ node: node, left:"40", top:"50", units:"px" }).play()
+
+ var node = args.node = d.byId(args.node),
+ top = null, left = null;
+
+ var init = (function(n){
+ return function(){
+ var cs = d.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 = d.position(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 = d.animateProperty(d.mixin({
+ properties: {
+ top: args.top || 0,
+ left: args.left || 0
+ }
+ }, args));
+ d.connect(anim, "beforeBegin", anim, init);
+
+ return anim; // dojo.Animation
+ }
+
+})();
+
+}
+
+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["NodeList-fx"] = {
+ // summary: Adds dojo.fx animation support to dojo.query()
+};
+=====*/
+
+dojo.extend(dojo.NodeList, {
+ _anim: function(obj, method, args){
+ args = args||{};
+ var a = dojo.fx.combine(
+ this.map(function(item){
+ var tmpArgs = { node: item };
+ dojo.mixin(tmpArgs, args);
+ return obj[method](tmpArgs);
+ })
+ );
+ return args.auto ? a.play() && this : a; // dojo.Animation|dojo.NodeList
+ },
+
+ wipeIn: function(args){
+ // summary:
+ // wipe in all elements of this NodeList via `dojo.fx.wipeIn`
+ //
+ // args: Object?
+ // Additional dojo.Animation arguments to mix into this set with the addition of
+ // an `auto` parameter.
+ //
+ // returns: dojo.Animation|dojo.NodeList
+ // A special args member `auto` can be passed to automatically play the animation.
+ // If args.auto is present, the original dojo.NodeList will be returned for further
+ // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed
+ //
+ // example:
+ // Fade in all tables with class "blah":
+ // | dojo.query("table.blah").wipeIn().play();
+ //
+ // example:
+ // Utilizing `auto` to get the NodeList back:
+ // | dojo.query(".titles").wipeIn({ auto:true }).onclick(someFunction);
+ //
+ return this._anim(dojo.fx, "wipeIn", args); // dojo.Animation|dojo.NodeList
+ },
+
+ wipeOut: function(args){
+ // summary:
+ // wipe out all elements of this NodeList via `dojo.fx.wipeOut`
+ //
+ // args: Object?
+ // Additional dojo.Animation arguments to mix into this set with the addition of
+ // an `auto` parameter.
+ //
+ // returns: dojo.Animation|dojo.NodeList
+ // A special args member `auto` can be passed to automatically play the animation.
+ // If args.auto is present, the original dojo.NodeList will be returned for further
+ // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed
+ //
+ // example:
+ // Wipe out all tables with class "blah":
+ // | dojo.query("table.blah").wipeOut().play();
+ return this._anim(dojo.fx, "wipeOut", args); // dojo.Animation|dojo.NodeList
+ },
+
+ slideTo: function(args){
+ // summary:
+ // slide all elements of the node list to the specified place via `dojo.fx.slideTo`
+ //
+ // args: Object?
+ // Additional dojo.Animation arguments to mix into this set with the addition of
+ // an `auto` parameter.
+ //
+ // returns: dojo.Animation|dojo.NodeList
+ // A special args member `auto` can be passed to automatically play the animation.
+ // If args.auto is present, the original dojo.NodeList will be returned for further
+ // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed
+ //
+ // 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|dojo.NodeList
+ },
+
+
+ fadeIn: function(args){
+ // summary:
+ // fade in all elements of this NodeList via `dojo.fadeIn`
+ //
+ // args: Object?
+ // Additional dojo.Animation arguments to mix into this set with the addition of
+ // an `auto` parameter.
+ //
+ // returns: dojo.Animation|dojo.NodeList
+ // A special args member `auto` can be passed to automatically play the animation.
+ // If args.auto is present, the original dojo.NodeList will be returned for further
+ // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed
+ //
+ // example:
+ // Fade in all tables with class "blah":
+ // | dojo.query("table.blah").fadeIn().play();
+ return this._anim(dojo, "fadeIn", args); // dojo.Animation|dojo.NodeList
+ },
+
+ fadeOut: function(args){
+ // summary:
+ // fade out all elements of this NodeList via `dojo.fadeOut`
+ //
+ // args: Object?
+ // Additional dojo.Animation arguments to mix into this set with the addition of
+ // an `auto` parameter.
+ //
+ // returns: dojo.Animation|dojo.NodeList
+ // A special args member `auto` can be passed to automatically play the animation.
+ // If args.auto is present, the original dojo.NodeList will be returned for further
+ // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed
+ //
+ // 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();
+ // example:
+ // Using `auto`:
+ // | dojo.query("li").fadeOut({ auto:true }).filter(filterFn).forEach(doit);
+ //
+ return this._anim(dojo, "fadeOut", args); // dojo.Animation|dojo.NodeList
+ },
+
+ animateProperty: function(args){
+ // summary:
+ // Animate all elements of this NodeList across the properties specified.
+ // syntax identical to `dojo.animateProperty`
+ //
+ // returns: dojo.Animation|dojo.NodeList
+ // A special args member `auto` can be passed to automatically play the animation.
+ // If args.auto is present, the original dojo.NodeList will be returned for further
+ // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed
+ //
+ // example:
+ // | dojo.query(".zork").animateProperty({
+ // | duration: 500,
+ // | properties: {
+ // | color: { start: "black", end: "white" },
+ // | left: { end: 300 }
+ // | }
+ // | }).play();
+ //
+ // example:
+ // | dojo.query(".grue").animateProperty({
+ // | auto:true,
+ // | properties: {
+ // | height:240
+ // | }
+ // | }).onclick(handler);
+ return this._anim(dojo, "animateProperty", args); // dojo.Animation|dojo.NodeList
+ },
+
+ 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. does NOT support the `auto` parameter like other
+ // NodeList-fx methods.
+ // 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
+ }
+});
+
+}
+
+if(!dojo._hasResource["dojo.colors"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.colors"] = true;
+dojo.provide("dojo.colors");
+
+//TODO: this module appears to break naming conventions
+
+/*=====
+dojo.colors = {
+ // summary: Color utilities
+}
+=====*/
+
+(function(){
+ // this is a standard conversion prescribed by the CSS3 Color Module
+ var hue2rgb = function(m1, m2, h){
+ if(h < 0){ ++h; }
+ if(h > 1){ --h; }
+ var h6 = 6 * h;
+ if(h6 < 1){ return m1 + (m2 - m1) * h6; }
+ if(2 * h < 1){ return m2; }
+ if(3 * h < 2){ return m1 + (m2 - m1) * (2 / 3 - h) * 6; }
+ return m1;
+ };
+
+ dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
+ // summary:
+ // get rgb(a) array from css-style color declarations
+ // description:
+ // this function can handle all 4 CSS3 Color Module formats: rgb,
+ // rgba, hsl, hsla, including rgb(a) with percentage values.
+ var m = color.toLowerCase().match(/^(rgba?|hsla?)\(([\s\.\-,%0-9]+)\)/);
+ if(m){
+ var c = m[2].split(/\s*,\s*/), l = c.length, t = m[1], a;
+ if((t == "rgb" && l == 3) || (t == "rgba" && l == 4)){
+ var r = c[0];
+ if(r.charAt(r.length - 1) == "%"){
+ // 3 rgb percentage values
+ a = dojo.map(c, function(x){
+ return parseFloat(x) * 2.56;
+ });
+ if(l == 4){ a[3] = c[3]; }
+ return dojo.colorFromArray(a, obj); // dojo.Color
+ }
+ return dojo.colorFromArray(c, obj); // dojo.Color
+ }
+ if((t == "hsl" && l == 3) || (t == "hsla" && l == 4)){
+ // normalize hsl values
+ var H = ((parseFloat(c[0]) % 360) + 360) % 360 / 360,
+ S = parseFloat(c[1]) / 100,
+ L = parseFloat(c[2]) / 100,
+ // calculate rgb according to the algorithm
+ // recommended by the CSS3 Color Module
+ m2 = L <= 0.5 ? L * (S + 1) : L + S - L * S,
+ m1 = 2 * L - m2;
+ a = [
+ hue2rgb(m1, m2, H + 1 / 3) * 256,
+ hue2rgb(m1, m2, H) * 256,
+ hue2rgb(m1, m2, H - 1 / 3) * 256,
+ 1
+ ];
+ if(l == 4){ a[3] = c[3]; }
+ return dojo.colorFromArray(a, obj); // dojo.Color
+ }
+ }
+ return null; // dojo.Color
+ };
+
+ var confine = function(c, low, high){
+ // summary:
+ // sanitize a color component by making sure it is a number,
+ // and clamping it to valid values
+ c = Number(c);
+ return isNaN(c) ? high : c < low ? low : c > high ? high : c; // Number
+ };
+
+ dojo.Color.prototype.sanitize = function(){
+ // summary: makes sure that the object has correct attributes
+ var t = this;
+ t.r = Math.round(confine(t.r, 0, 255));
+ t.g = Math.round(confine(t.g, 0, 255));
+ t.b = Math.round(confine(t.b, 0, 255));
+ t.a = confine(t.a, 0, 1);
+ return this; // dojo.Color
+ };
+})();
+
+
+dojo.colors.makeGrey = function(/*Number*/ g, /*Number?*/ a){
+ // summary: creates a greyscale color with an optional alpha
+ return dojo.colorFromArray([g, g, g, a]);
+};
+
+// mixin all CSS3 named colors not already in _base, along with SVG 1.0 variant spellings
+dojo.mixin(dojo.Color.named, {
+ aliceblue: [240,248,255],
+ antiquewhite: [250,235,215],
+ aquamarine: [127,255,212],
+ azure: [240,255,255],
+ beige: [245,245,220],
+ bisque: [255,228,196],
+ blanchedalmond: [255,235,205],
+ blueviolet: [138,43,226],
+ brown: [165,42,42],
+ burlywood: [222,184,135],
+ cadetblue: [95,158,160],
+ chartreuse: [127,255,0],
+ chocolate: [210,105,30],
+ coral: [255,127,80],
+ cornflowerblue: [100,149,237],
+ cornsilk: [255,248,220],
+ crimson: [220,20,60],
+ cyan: [0,255,255],
+ darkblue: [0,0,139],
+ darkcyan: [0,139,139],
+ darkgoldenrod: [184,134,11],
+ darkgray: [169,169,169],
+ darkgreen: [0,100,0],
+ darkgrey: [169,169,169],
+ darkkhaki: [189,183,107],
+ darkmagenta: [139,0,139],
+ darkolivegreen: [85,107,47],
+ darkorange: [255,140,0],
+ darkorchid: [153,50,204],
+ darkred: [139,0,0],
+ darksalmon: [233,150,122],
+ darkseagreen: [143,188,143],
+ darkslateblue: [72,61,139],
+ darkslategray: [47,79,79],
+ darkslategrey: [47,79,79],
+ darkturquoise: [0,206,209],
+ darkviolet: [148,0,211],
+ deeppink: [255,20,147],
+ deepskyblue: [0,191,255],
+ dimgray: [105,105,105],
+ dimgrey: [105,105,105],
+ dodgerblue: [30,144,255],
+ firebrick: [178,34,34],
+ floralwhite: [255,250,240],
+ forestgreen: [34,139,34],
+ gainsboro: [220,220,220],
+ ghostwhite: [248,248,255],
+ gold: [255,215,0],
+ goldenrod: [218,165,32],
+ greenyellow: [173,255,47],
+ grey: [128,128,128],
+ honeydew: [240,255,240],
+ hotpink: [255,105,180],
+ indianred: [205,92,92],
+ indigo: [75,0,130],
+ ivory: [255,255,240],
+ khaki: [240,230,140],
+ lavender: [230,230,250],
+ lavenderblush: [255,240,245],
+ lawngreen: [124,252,0],
+ lemonchiffon: [255,250,205],
+ lightblue: [173,216,230],
+ lightcoral: [240,128,128],
+ lightcyan: [224,255,255],
+ lightgoldenrodyellow: [250,250,210],
+ lightgray: [211,211,211],
+ lightgreen: [144,238,144],
+ lightgrey: [211,211,211],
+ lightpink: [255,182,193],
+ lightsalmon: [255,160,122],
+ lightseagreen: [32,178,170],
+ lightskyblue: [135,206,250],
+ lightslategray: [119,136,153],
+ lightslategrey: [119,136,153],
+ lightsteelblue: [176,196,222],
+ lightyellow: [255,255,224],
+ limegreen: [50,205,50],
+ linen: [250,240,230],
+ magenta: [255,0,255],
+ mediumaquamarine: [102,205,170],
+ mediumblue: [0,0,205],
+ mediumorchid: [186,85,211],
+ mediumpurple: [147,112,219],
+ mediumseagreen: [60,179,113],
+ mediumslateblue: [123,104,238],
+ mediumspringgreen: [0,250,154],
+ mediumturquoise: [72,209,204],
+ mediumvioletred: [199,21,133],
+ midnightblue: [25,25,112],
+ mintcream: [245,255,250],
+ mistyrose: [255,228,225],
+ moccasin: [255,228,181],
+ navajowhite: [255,222,173],
+ oldlace: [253,245,230],
+ olivedrab: [107,142,35],
+ orange: [255,165,0],
+ orangered: [255,69,0],
+ orchid: [218,112,214],
+ palegoldenrod: [238,232,170],
+ palegreen: [152,251,152],
+ paleturquoise: [175,238,238],
+ palevioletred: [219,112,147],
+ papayawhip: [255,239,213],
+ peachpuff: [255,218,185],
+ peru: [205,133,63],
+ pink: [255,192,203],
+ plum: [221,160,221],
+ powderblue: [176,224,230],
+ rosybrown: [188,143,143],
+ royalblue: [65,105,225],
+ saddlebrown: [139,69,19],
+ salmon: [250,128,114],
+ sandybrown: [244,164,96],
+ seagreen: [46,139,87],
+ seashell: [255,245,238],
+ sienna: [160,82,45],
+ skyblue: [135,206,235],
+ slateblue: [106,90,205],
+ slategray: [112,128,144],
+ slategrey: [112,128,144],
+ snow: [255,250,250],
+ springgreen: [0,255,127],
+ steelblue: [70,130,180],
+ tan: [210,180,140],
+ thistle: [216,191,216],
+ tomato: [255,99,71],
+ transparent: [0, 0, 0, 0],
+ turquoise: [64,224,208],
+ violet: [238,130,238],
+ wheat: [245,222,179],
+ whitesmoke: [245,245,245],
+ yellowgreen: [154,205,50]
+});
+
+}
+
+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.
+ //Using ["indexOf"] so customBase builds do not see
+ //this as a dojo._base.array dependency.
+ if(targetLocale["indexOf"](flatLocales[i]) == 0){
+ if(flatLocales[i].length > bestLocale.length){
+ bestLocale = flatLocales[i];
+ }
+ }
+ }
+ if(!bestLocale){
+ bestLocale = "ROOT";
+ }
+ }
+
+ //See if the desired locale is already loaded.
+ var tempLocale = availableFlatLocales ? bestLocale : targetLocale;
+ var bundle = dojo._loadedModules[bundlePackage];
+ var localizedBundle = null;
+ if(bundle){
+ if(dojo.config.localizationComplete && bundle._built){return;}
+ var jsLoc = tempLocale.replace(/-/g, '_');
+ var translationPackage = bundlePackage+"."+jsLoc;
+ localizedBundle = dojo._loadedModules[translationPackage];
+ }
+
+ if(!localizedBundle){
+ bundle = dojo["provide"](bundlePackage);
+ var syms = dojo._getModuleSymbols(moduleName);
+ var modpath = syms.concat("nls").join("/");
+ var parent;
+
+ dojo.i18n._searchLocalePath(tempLocale, availableFlatLocales, function(loc){
+ var jsLoc = loc.replace(/-/g, '_');
+ var translationPackage = bundlePackage + "." + jsLoc;
+ var loaded = false;
+ if(!dojo._loadedModules[translationPackage]){
+ // Mark loaded whether it's found or not, so that further load attempts will not be made
+ dojo["provide"](translationPackage);
+ var module = [modpath];
+ if(loc != "ROOT"){module.push(loc);}
+ module.push(bundleName);
+ var filespec = module.join("/") + '.js';
+ loaded = dojo._loadPath(filespec, null, function(hash){
+ // Use singleton with prototype to point to parent bundle, then mix-in result from loadPath
+ var clazz = function(){};
+ clazz.prototype = parent;
+ bundle[jsLoc] = new clazz();
+ for(var j in hash){ bundle[jsLoc][j] = hash[j]; }
+ });
+ }else{
+ loaded = true;
+ }
+ if(loaded && bundle[jsLoc]){
+ parent = bundle[jsLoc];
+ }else{
+ bundle[jsLoc] = parent;
+ }
+
+ if(availableFlatLocales){
+ //Stop the locale path searching if we know the availableFlatLocales, since
+ //the first call to this function will load the only bundle that is needed.
+ return true;
+ }
+ });
+ }
+
+ //Save the best locale bundle as the target locale bundle when we know the
+ //the available bundles.
+ if(availableFlatLocales && targetLocale != bestLocale){
+ bundle[targetLocale.replace(/-/g, '_')] = bundle[bestLocale.replace(/-/g, '_')];
+ }
+};
+
+(function(){
+ // If other locales are used, dojo.requireLocalization should load them as
+ // well, by default.
+ //
+ // Override dojo.requireLocalization to do load the default bundle, then
+ // iterate through the extraLocale list and load those translations as
+ // well, unless a particular locale was requested.
+
+ var extra = dojo.config.extraLocale;
+ if(extra){
+ if(!extra instanceof Array){
+ extra = [extra];
+ }
+
+ var req = dojo.i18n._requireLocalization;
+ dojo.i18n._requireLocalization = function(m, b, locale, availableFlatLocales){
+ req(m,b,locale, availableFlatLocales);
+ if(locale){return;}
+ for(var i=0; i<extra.length; i++){
+ req(m,b,extra[i], availableFlatLocales);
+ }
+ };
+ }
+})();
+
+dojo.i18n._searchLocalePath = function(/*String*/locale, /*Boolean*/down, /*Function*/searchFunc){
+ // summary:
+ // A helper method to assist in searching for locale-based resources.
+ // Will iterate through the variants of a particular locale, either up
+ // or down, executing a callback function. For example, "en-us" and
+ // true will try "en-us" followed by "en" and finally "ROOT".
+
+ locale = dojo.i18n.normalizeLocale(locale);
+
+ var elements = locale.split('-');
+ var searchlist = [];
+ for(var i = elements.length; i > 0; i--){
+ searchlist.push(elements.slice(0, i).join('-'));
+ }
+ searchlist.push(false);
+ if(down){searchlist.reverse();}
+
+ for(var j = searchlist.length - 1; j >= 0; j--){
+ var loc = searchlist[j] || "ROOT";
+ var stop = searchFunc(loc);
+ if(stop){ break; }
+ }
+};
+
+dojo.i18n._preloadLocalizations = function(/*String*/bundlePrefix, /*Array*/localesGenerated){
+ // summary:
+ // Load built, flattened resource bundles, if available for all
+ // locales used in the page. Only called by built layer files.
+
+ function preload(locale){
+ locale = dojo.i18n.normalizeLocale(locale);
+ dojo.i18n._searchLocalePath(locale, true, function(loc){
+ for(var i=0; i<localesGenerated.length;i++){
+ if(localesGenerated[i] == loc){
+ dojo["require"](bundlePrefix+"_"+loc);
+ return true; // Boolean
+ }
+ }
+ return false; // Boolean
+ });
+ }
+ preload();
+ var extra = dojo.config.extraLocale||[];
+ for(var i=0; i<extra.length; i++){
+ preload(extra[i]);
+ }
+};
+
+}
+
+if(!dojo._hasResource["dijit._PaletteMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._PaletteMixin"] = true;
+dojo.provide("dijit._PaletteMixin");
+
+
+dojo.declare("dijit._PaletteMixin",
+ [dijit._CssStateMixin],
+ {
+ // summary:
+ // A keyboard accessible palette, for picking a color/emoticon/etc.
+ // description:
+ // A mixin for a grid showing various entities, so the user can pick a certain entity.
+
+ // defaultTimeout: Number
+ // Number of milliseconds before a held key or button becomes typematic
+ defaultTimeout: 500,
+
+ // timeoutChangeRate: Number
+ // Fraction of time used to change the typematic timer between events
+ // 1.0 means that each typematic event fires at defaultTimeout intervals
+ // < 1.0 means that each typematic event fires at an increasing faster rate
+ timeoutChangeRate: 0.90,
+
+ // value: String
+ // Currently selected color/emoticon/etc.
+ value: null,
+
+ // _selectedCell: [private] Integer
+ // Index of the currently selected cell. Initially, none selected
+ _selectedCell: -1,
+
+ // _currentFocus: [private] DomNode
+ // The currently focused cell (if the palette itself has focus), or otherwise
+ // the cell to be focused when the palette itself gets focus.
+ // Different from value, which represents the selected (i.e. clicked) cell.
+/*=====
+ _currentFocus: null,
+=====*/
+
+ // _xDim: [protected] Integer
+ // This is the number of cells horizontally across.
+/*=====
+ _xDim: null,
+=====*/
+
+ // _yDim: [protected] Integer
+ // This is the number of cells vertically down.
+/*=====
+ _yDim: null,
+=====*/
+
+ // tabIndex: String
+ // Widget tab index.
+ tabIndex: "0",
+
+ // cellClass: [protected] String
+ // CSS class applied to each cell in the palette
+ cellClass: "dijitPaletteCell",
+
+ // dyeClass: [protected] String
+ // Name of javascript class for Object created for each cell of the palette.
+ // dyeClass should implements dijit.Dye interface
+ dyeClass: '',
+
+ _preparePalette: function(choices, titles) {
+ // summary:
+ // Subclass must call _preparePalette() from postCreate(), passing in the tooltip
+ // for each cell
+ // choices: String[][]
+ // id's for each cell of the palette, used to create Dye JS object for each cell
+ // titles: String[]
+ // Localized tooltip for each cell
+
+ this._cells = [];
+ var url = this._blankGif;
+
+ var dyeClassObj = dojo.getObject(this.dyeClass);
+
+ for(var row=0; row < choices.length; row++){
+ var rowNode = dojo.create("tr", {tabIndex: "-1"}, this.gridNode);
+ for(var col=0; col < choices[row].length; col++){
+ var value = choices[row][col];
+ if(value){
+ var cellObject = new dyeClassObj(value);
+
+ var cellNode = dojo.create("td", {
+ "class": this.cellClass,
+ tabIndex: "-1",
+ title: titles[value]
+ });
+
+ // prepare cell inner structure
+ cellObject.fillCell(cellNode, url);
+
+ this.connect(cellNode, "ondijitclick", "_onCellClick");
+ this._trackMouseState(cellNode, this.cellClass);
+
+ dojo.place(cellNode, rowNode);
+
+ cellNode.index = this._cells.length;
+
+ // save cell info into _cells
+ this._cells.push({node:cellNode, dye:cellObject});
+ }
+ }
+ }
+ this._xDim = choices[0].length;
+ this._yDim = choices.length;
+
+ // Now set all events
+ // The palette itself is navigated to with the tab key on the keyboard
+ // Keyboard navigation within the Palette is with the arrow keys
+ // Spacebar selects the cell.
+ // For the up key the index is changed by negative the x dimension.
+
+ var keyIncrementMap = {
+ UP_ARROW: -this._xDim,
+ // The down key the index is increase by the x dimension.
+ DOWN_ARROW: this._xDim,
+ // Right and left move the index by 1.
+ RIGHT_ARROW: this.isLeftToRight() ? 1 : -1,
+ LEFT_ARROW: this.isLeftToRight() ? -1 : 1
+ };
+ for(var key in keyIncrementMap){
+ this._connects.push(
+ dijit.typematic.addKeyListener(
+ this.domNode,
+ {charOrCode:dojo.keys[key], ctrlKey:false, altKey:false, shiftKey:false},
+ this,
+ function(){
+ var increment = keyIncrementMap[key];
+ return function(count){ this._navigateByKey(increment, count); };
+ }(),
+ this.timeoutChangeRate,
+ this.defaultTimeout
+ )
+ );
+ }
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // Set initial navigable node.
+ this._setCurrent(this._cells[0].node);
+ },
+
+ focus: function(){
+ // summary:
+ // Focus this widget. Puts focus on the most recently focused cell.
+
+ // The cell already has tabIndex set, just need to set CSS and focus it
+ dijit.focus(this._currentFocus);
+ },
+
+ _onCellClick: function(/*Event*/ evt){
+ // summary:
+ // Handler for click, enter key & space key. Selects the cell.
+ // evt:
+ // The event.
+ // tags:
+ // private
+
+ var target = evt.currentTarget,
+ value = this._getDye(target).getValue();
+
+ // First focus the clicked cell, and then send onChange() notification.
+ // onChange() (via _setValueAttr) must be after the focus call, because
+ // it may trigger a refocus to somewhere else (like the Editor content area), and that
+ // second focus should win.
+ // Use setTimeout because IE doesn't like changing focus inside of an event handler.
+ this._setCurrent(target);
+ setTimeout(dojo.hitch(this, function(){
+ dijit.focus(target);
+ this._setValueAttr(value, true);
+ }));
+
+ // workaround bug where hover class is not removed on popup because the popup is
+ // closed and then there's no onblur event on the cell
+ dojo.removeClass(target, "dijitPaletteCellHover");
+
+ dojo.stopEvent(evt);
+ },
+
+ _setCurrent: function(/*DomNode*/ node){
+ // summary:
+ // Sets which node is the focused cell.
+ // description:
+ // At any point in time there's exactly one
+ // cell with tabIndex != -1. If focus is inside the palette then
+ // focus is on that cell.
+ //
+ // After calling this method, arrow key handlers and mouse click handlers
+ // should focus the cell in a setTimeout().
+ // tags:
+ // protected
+ if("_currentFocus" in this){
+ // Remove tabIndex on old cell
+ dojo.attr(this._currentFocus, "tabIndex", "-1");
+ }
+
+ // Set tabIndex of new cell
+ this._currentFocus = node;
+ if(node){
+ dojo.attr(node, "tabIndex", this.tabIndex);
+ }
+ },
+
+ _setValueAttr: function(value, priorityChange){
+ // summary:
+ // This selects a cell. It triggers the onChange event.
+ // value: String value of the cell to select
+ // tags:
+ // protected
+ // priorityChange:
+ // Optional parameter used to tell the select whether or not to fire
+ // onChange event.
+
+ // clear old value and selected cell
+ this.value = null;
+ if(this._selectedCell >= 0){
+ dojo.removeClass(this._cells[this._selectedCell].node, "dijitPaletteCellSelected");
+ }
+ this._selectedCell = -1;
+
+ // search for cell matching specified value
+ if(value){
+ for(var i = 0; i < this._cells.length; i++){
+ if(value == this._cells[i].dye.getValue()){
+ this._selectedCell = i;
+ this.value = value;
+
+ dojo.addClass(this._cells[i].node, "dijitPaletteCellSelected");
+
+ if(priorityChange || priorityChange === undefined){
+ this.onChange(value);
+ }
+
+ break;
+ }
+ }
+ }
+ },
+
+ onChange: function(value){
+ // summary:
+ // Callback when a cell is selected.
+ // value: String
+ // Value corresponding to cell.
+ },
+
+ _navigateByKey: function(increment, typeCount){
+ // summary:
+ // This is the callback for typematic.
+ // It changes the focus and the highlighed cell.
+ // increment:
+ // How much the key is navigated.
+ // typeCount:
+ // How many times typematic has fired.
+ // tags:
+ // private
+
+ // typecount == -1 means the key is released.
+ if(typeCount == -1){ return; }
+
+ var newFocusIndex = this._currentFocus.index + increment;
+ if(newFocusIndex < this._cells.length && newFocusIndex > -1){
+ var focusNode = this._cells[newFocusIndex].node;
+ this._setCurrent(focusNode);
+
+ // Actually focus the node, for the benefit of screen readers.
+ // Use setTimeout because IE doesn't like changing focus inside of an event handler
+ setTimeout(dojo.hitch(dijit, "focus", focusNode), 0);
+ }
+ },
+
+ _getDye: function(/*DomNode*/ cell){
+ // summary:
+ // Get JS object for given cell DOMNode
+
+ return this._cells[cell.index].dye;
+ }
+});
+
+/*=====
+dojo.declare("dijit.Dye",
+ null,
+ {
+ // summary:
+ // Interface for the JS Object associated with a palette cell (i.e. DOMNode)
+
+ constructor: function(alias){
+ // summary:
+ // Initialize according to value or alias like "white"
+ // alias: String
+ },
+
+ getValue: function(){
+ // summary:
+ // Return "value" of cell; meaning of "value" varies by subclass.
+ // description:
+ // For example color hex value, emoticon ascii value etc, entity hex value.
+ },
+
+ fillCell: function(cell, blankGif){
+ // summary:
+ // Add cell DOMNode inner structure
+ // cell: DomNode
+ // The surrounding cell
+ // blankGif: String
+ // URL for blank cell image
+ }
+ }
+);
+=====*/
+
+}
+
+if(!dojo._hasResource["dijit.ColorPalette"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.ColorPalette"] = true;
+dojo.provide("dijit.ColorPalette");
+
+
+
+
+
+
+
+
+
+
+dojo.declare("dijit.ColorPalette",
+ [dijit._Widget, dijit._Templated, dijit._PaletteMixin],
+ {
+ // summary:
+ // A keyboard accessible color-picking widget
+ // description:
+ // Grid showing various colors, so the user can pick a certain color.
+ // Can be used standalone, or as a popup.
+ //
+ // example:
+ // | <div dojoType="dijit.ColorPalette"></div>
+ //
+ // example:
+ // | var picker = new dijit.ColorPalette({ },srcNode);
+ // | picker.startup();
+
+
+ // palette: String
+ // Size of grid, either "7x10" or "3x4".
+ palette: "7x10",
+
+ // _palettes: [protected] Map
+ // This represents the value of the colors.
+ // The first level is a hashmap of the different palettes available.
+ // The next two dimensions represent the columns and rows of colors.
+ _palettes: {
+ "7x10": [["white", "seashell", "cornsilk", "lemonchiffon","lightyellow", "palegreen", "paleturquoise", "lightcyan", "lavender", "plum"],
+ ["lightgray", "pink", "bisque", "moccasin", "khaki", "lightgreen", "lightseagreen", "lightskyblue", "cornflowerblue", "violet"],
+ ["silver", "lightcoral", "sandybrown", "orange", "palegoldenrod", "chartreuse", "mediumturquoise", "skyblue", "mediumslateblue","orchid"],
+ ["gray", "red", "orangered", "darkorange", "yellow", "limegreen", "darkseagreen", "royalblue", "slateblue", "mediumorchid"],
+ ["dimgray", "crimson", "chocolate", "coral", "gold", "forestgreen", "seagreen", "blue", "blueviolet", "darkorchid"],
+ ["darkslategray","firebrick","saddlebrown", "sienna", "olive", "green", "darkcyan", "mediumblue","darkslateblue", "darkmagenta" ],
+ ["black", "darkred", "maroon", "brown", "darkolivegreen", "darkgreen", "midnightblue", "navy", "indigo", "purple"]],
+
+ "3x4": [["white", "lime", "green", "blue"],
+ ["silver", "yellow", "fuchsia", "navy"],
+ ["gray", "red", "purple", "black"]]
+ },
+
+ // _imagePaths: [protected] Map
+ // This is stores the path to the palette images
+ _imagePaths: {
+ "7x10": dojo.moduleUrl("dijit.themes", "a11y/colors7x10.png"),
+ "3x4": dojo.moduleUrl("dijit.themes", "a11y/colors3x4.png"),
+ "7x10-rtl": dojo.moduleUrl("dijit.themes", "a11y/colors7x10-rtl.png"),
+ "3x4-rtl": dojo.moduleUrl("dijit.themes", "a11y/colors3x4-rtl.png")
+ },
+
+ // templateString: String
+ // The template of this widget.
+ templateString: dojo.cache("dijit", "templates/ColorPalette.html", "<div class=\"dijitInline dijitColorPalette\">\n\t<img class=\"dijitColorPaletteUnder\" dojoAttachPoint=\"imageNode\" waiRole=\"presentation\" alt=\"\"/>\n\t<table class=\"dijitPaletteTable\" cellSpacing=\"0\" cellPadding=\"0\">\n\t\t<tbody dojoAttachPoint=\"gridNode\"></tbody>\n\t</table>\n</div>\n"),
+
+ baseClass: "dijitColorPalette",
+
+ dyeClass: 'dijit._Color',
+
+ buildRendering: function(){
+ // Instantiate the template, which makes a skeleton into which we'll insert a bunch of
+ // <img> nodes
+
+ this.inherited(arguments);
+
+ this.imageNode.setAttribute("src", this._imagePaths[this.palette + (this.isLeftToRight() ? "" : "-rtl")].toString());
+
+ var i18nColorNames = dojo.i18n.getLocalization("dojo", "colors", this.lang);
+ this._preparePalette(
+ this._palettes[this.palette],
+ i18nColorNames
+ );
+ }
+});
+
+dojo.declare("dijit._Color", dojo.Color,
+ // summary:
+ // Object associated with each cell in a ColorPalette palette.
+ // Implements dijit.Dye.
+ {
+ constructor: function(/*String*/alias){
+ this._alias = alias;
+ this.setColor(dojo.Color.named[alias]);
+ },
+
+ getValue: function(){
+ // summary:
+ // Note that although dijit._Color is initialized with a value like "white" getValue() always
+ // returns a hex value
+ return this.toHex();
+ },
+
+ fillCell: function(/*DOMNode*/ cell, /*String*/ blankGif){
+ dojo.create("img", {
+ src: blankGif,
+ "class": "dijitPaletteImg",
+ alt: this._alias
+ }, cell);
+ }
+ }
+);
+
+}
+
+if(!dojo._hasResource["dojo.dnd.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.common"] = true;
+dojo.provide("dojo.dnd.common");
+
+dojo.dnd.getCopyKeyState = dojo.isCopyKey;
+
+dojo.dnd._uniqueId = 0;
+dojo.dnd.getUniqueId = function(){
+ // summary:
+ // returns a unique string for use with any DOM element
+ var id;
+ do{
+ id = dojo._scopeName + "Unique" + (++dojo.dnd._uniqueId);
+ }while(dojo.byId(id));
+ return id;
+};
+
+dojo.dnd._empty = {};
+
+dojo.dnd.isFormElement = function(/*Event*/ e){
+ // summary:
+ // returns true if user clicked on a form element
+ var t = e.target;
+ if(t.nodeType == 3 /*TEXT_NODE*/){
+ t = t.parentNode;
+ }
+ return " button textarea input select option ".indexOf(" " + t.tagName.toLowerCase() + " ") >= 0; // Boolean
+};
+
+}
+
+if(!dojo._hasResource["dojo.dnd.autoscroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.autoscroll"] = true;
+dojo.provide("dojo.dnd.autoscroll");
+
+dojo.dnd.getViewport = function(){
+ // summary:
+ // Returns a viewport size (visible part of the window)
+
+ // TODO: remove this when getViewport() moved to dojo core, see #7028
+
+ // FIXME: need more docs!!
+ var d = dojo.doc, dd = d.documentElement, w = window, b = dojo.body();
+ if(dojo.isMozilla){
+ return {w: dd.clientWidth, h: w.innerHeight}; // Object
+ }else if(!dojo.isOpera && w.innerWidth){
+ return {w: w.innerWidth, h: w.innerHeight}; // Object
+ }else if (!dojo.isOpera && dd && dd.clientWidth){
+ return {w: dd.clientWidth, h: dd.clientHeight}; // Object
+ }else if (b.clientWidth){
+ return {w: b.clientWidth, h: b.clientHeight}; // Object
+ }
+ return null; // Object
+};
+
+dojo.dnd.V_TRIGGER_AUTOSCROLL = 32;
+dojo.dnd.H_TRIGGER_AUTOSCROLL = 32;
+
+dojo.dnd.V_AUTOSCROLL_VALUE = 16;
+dojo.dnd.H_AUTOSCROLL_VALUE = 16;
+
+dojo.dnd.autoScroll = function(e){
+ // summary:
+ // a handler for onmousemove event, which scrolls the window, if
+ // necesary
+ // e: Event
+ // onmousemove event
+
+ // FIXME: needs more docs!
+ var v = dojo.dnd.getViewport(), dx = 0, dy = 0;
+ if(e.clientX < dojo.dnd.H_TRIGGER_AUTOSCROLL){
+ dx = -dojo.dnd.H_AUTOSCROLL_VALUE;
+ }else if(e.clientX > v.w - dojo.dnd.H_TRIGGER_AUTOSCROLL){
+ dx = dojo.dnd.H_AUTOSCROLL_VALUE;
+ }
+ if(e.clientY < dojo.dnd.V_TRIGGER_AUTOSCROLL){
+ dy = -dojo.dnd.V_AUTOSCROLL_VALUE;
+ }else if(e.clientY > v.h - dojo.dnd.V_TRIGGER_AUTOSCROLL){
+ dy = dojo.dnd.V_AUTOSCROLL_VALUE;
+ }
+ window.scrollBy(dx, dy);
+};
+
+dojo.dnd._validNodes = {"div": 1, "p": 1, "td": 1};
+dojo.dnd._validOverflow = {"auto": 1, "scroll": 1};
+
+dojo.dnd.autoScrollNodes = function(e){
+ // summary:
+ // a handler for onmousemove event, which scrolls the first avaialble
+ // Dom element, it falls back to dojo.dnd.autoScroll()
+ // e: Event
+ // onmousemove event
+
+ // FIXME: needs more docs!
+ for(var n = e.target; n;){
+ if(n.nodeType == 1 && (n.tagName.toLowerCase() in dojo.dnd._validNodes)){
+ var s = dojo.getComputedStyle(n);
+ if(s.overflow.toLowerCase() in dojo.dnd._validOverflow){
+ var b = dojo._getContentBox(n, s), t = dojo.position(n, true);
+ //console.log(b.l, b.t, t.x, t.y, n.scrollLeft, n.scrollTop);
+ var w = Math.min(dojo.dnd.H_TRIGGER_AUTOSCROLL, b.w / 2),
+ h = Math.min(dojo.dnd.V_TRIGGER_AUTOSCROLL, b.h / 2),
+ rx = e.pageX - t.x, ry = e.pageY - t.y, dx = 0, dy = 0;
+ if(dojo.isWebKit || dojo.isOpera){
+ // FIXME: this code should not be here, it should be taken into account
+ // either by the event fixing code, or the dojo.position()
+ // FIXME: this code doesn't work on Opera 9.5 Beta
+ rx += dojo.body().scrollLeft, ry += dojo.body().scrollTop;
+ }
+ if(rx > 0 && rx < b.w){
+ if(rx < w){
+ dx = -w;
+ }else if(rx > b.w - w){
+ dx = w;
+ }
+ }
+ //console.log("ry =", ry, "b.h =", b.h, "h =", h);
+ if(ry > 0 && ry < b.h){
+ if(ry < h){
+ dy = -h;
+ }else if(ry > b.h - h){
+ dy = h;
+ }
+ }
+ var oldLeft = n.scrollLeft, oldTop = n.scrollTop;
+ n.scrollLeft = n.scrollLeft + dx;
+ n.scrollTop = n.scrollTop + dy;
+ if(oldLeft != n.scrollLeft || oldTop != n.scrollTop){ return; }
+ }
+ }
+ try{
+ n = n.parentNode;
+ }catch(x){
+ n = null;
+ }
+ }
+ dojo.dnd.autoScroll(e);
+};
+
+}
+
+if(!dojo._hasResource["dojo.dnd.Mover"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Mover"] = true;
+dojo.provide("dojo.dnd.Mover");
+
+
+
+
+dojo.declare("dojo.dnd.Mover", null, {
+ constructor: function(node, e, host){
+ // summary:
+ // an object, which makes a node follow the mouse.
+ // Used as a default mover, and as a base class for custom movers.
+ // node: Node
+ // a node (or node's id) to be moved
+ // e: Event
+ // a mouse event, which started the move;
+ // only pageX and pageY properties are used
+ // host: Object?
+ // object which implements the functionality of the move,
+ // and defines proper events (onMoveStart and onMoveStop)
+ this.node = dojo.byId(node);
+ this.marginBox = {l: e.pageX, t: e.pageY};
+ this.mouseButton = e.button;
+ var h = this.host = host, d = node.ownerDocument,
+ firstEvent = dojo.connect(d, "onmousemove", this, "onFirstMove");
+ this.events = [
+ dojo.connect(d, "onmousemove", this, "onMouseMove"),
+ dojo.connect(d, "onmouseup", this, "onMouseUp"),
+ // cancel text selection and text dragging
+ dojo.connect(d, "ondragstart", dojo.stopEvent),
+ dojo.connect(d.body, "onselectstart", dojo.stopEvent),
+ firstEvent
+ ];
+ // notify that the move has started
+ if(h && h.onMoveStart){
+ h.onMoveStart(this);
+ }
+ },
+ // mouse event processors
+ onMouseMove: function(e){
+ // summary:
+ // event processor for onmousemove
+ // e: Event
+ // mouse event
+ dojo.dnd.autoScroll(e);
+ var m = this.marginBox;
+ this.host.onMove(this, {l: m.l + e.pageX, t: m.t + e.pageY}, e);
+ dojo.stopEvent(e);
+ },
+ onMouseUp: function(e){
+ if(dojo.isWebKit && dojo.isMac && this.mouseButton == 2 ?
+ e.button == 0 : this.mouseButton == e.button){
+ this.destroy();
+ }
+ dojo.stopEvent(e);
+ },
+ // utilities
+ onFirstMove: function(e){
+ // summary:
+ // makes the node absolute; it is meant to be called only once.
+ // relative and absolutely positioned nodes are assumed to use pixel units
+ var s = this.node.style, l, t, h = this.host;
+ switch(s.position){
+ case "relative":
+ case "absolute":
+ // assume that left and top values are in pixels already
+ l = Math.round(parseFloat(s.left)) || 0;
+ t = Math.round(parseFloat(s.top)) || 0;
+ break;
+ default:
+ s.position = "absolute"; // enforcing the absolute mode
+ var m = dojo.marginBox(this.node);
+ // event.pageX/pageY (which we used to generate the initial
+ // margin box) includes padding and margin set on the body.
+ // However, setting the node's position to absolute and then
+ // doing dojo.marginBox on it *doesn't* take that additional
+ // space into account - so we need to subtract the combined
+ // padding and margin. We use getComputedStyle and
+ // _getMarginBox/_getContentBox to avoid the extra lookup of
+ // the computed style.
+ var b = dojo.doc.body;
+ var bs = dojo.getComputedStyle(b);
+ var bm = dojo._getMarginBox(b, bs);
+ var bc = dojo._getContentBox(b, bs);
+ l = m.l - (bc.l - bm.l);
+ t = m.t - (bc.t - bm.t);
+ break;
+ }
+ this.marginBox.l = l - this.marginBox.l;
+ this.marginBox.t = t - this.marginBox.t;
+ if(h && h.onFirstMove){
+ h.onFirstMove(this, e);
+ }
+ dojo.disconnect(this.events.pop());
+ },
+ destroy: function(){
+ // summary:
+ // stops the move, deletes all references, so the object can be garbage-collected
+ dojo.forEach(this.events, dojo.disconnect);
+ // undo global settings
+ var h = this.host;
+ if(h && h.onMoveStop){
+ h.onMoveStop(this);
+ }
+ // destroy objects
+ this.events = this.node = this.host = null;
+ }
+});
+
+}
+
+if(!dojo._hasResource["dojo.dnd.Moveable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Moveable"] = true;
+dojo.provide("dojo.dnd.Moveable");
+
+
+
+/*=====
+dojo.declare("dojo.dnd.__MoveableArgs", [], {
+ // handle: Node||String
+ // A node (or node's id), which is used as a mouse handle.
+ // If omitted, the node itself is used as a handle.
+ handle: null,
+
+ // delay: Number
+ // delay move by this number of pixels
+ delay: 0,
+
+ // skip: Boolean
+ // skip move of form elements
+ skip: false,
+
+ // mover: Object
+ // a constructor of custom Mover
+ mover: dojo.dnd.Mover
+});
+=====*/
+
+dojo.declare("dojo.dnd.Moveable", null, {
+ // object attributes (for markup)
+ handle: "",
+ delay: 0,
+ skip: false,
+
+ constructor: function(node, params){
+ // summary:
+ // an object, which makes a node moveable
+ // node: Node
+ // a node (or node's id) to be moved
+ // params: dojo.dnd.__MoveableArgs?
+ // optional parameters
+ this.node = dojo.byId(node);
+ if(!params){ params = {}; }
+ this.handle = params.handle ? dojo.byId(params.handle) : null;
+ if(!this.handle){ this.handle = this.node; }
+ this.delay = params.delay > 0 ? params.delay : 0;
+ this.skip = params.skip;
+ this.mover = params.mover ? params.mover : dojo.dnd.Mover;
+ this.events = [
+ dojo.connect(this.handle, "onmousedown", this, "onMouseDown"),
+ // cancel text selection and text dragging
+ dojo.connect(this.handle, "ondragstart", this, "onSelectStart"),
+ dojo.connect(this.handle, "onselectstart", this, "onSelectStart")
+ ];
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.Moveable(node, params);
+ },
+
+ // methods
+ destroy: function(){
+ // summary:
+ // stops watching for possible move, deletes all references, so the object can be garbage-collected
+ dojo.forEach(this.events, dojo.disconnect);
+ this.events = this.node = this.handle = null;
+ },
+
+ // mouse event processors
+ onMouseDown: function(e){
+ // summary:
+ // event processor for onmousedown, creates a Mover for the node
+ // e: Event
+ // mouse event
+ if(this.skip && dojo.dnd.isFormElement(e)){ return; }
+ if(this.delay){
+ this.events.push(
+ dojo.connect(this.handle, "onmousemove", this, "onMouseMove"),
+ dojo.connect(this.handle, "onmouseup", this, "onMouseUp")
+ );
+ this._lastX = e.pageX;
+ this._lastY = e.pageY;
+ }else{
+ this.onDragDetected(e);
+ }
+ dojo.stopEvent(e);
+ },
+ onMouseMove: function(e){
+ // summary:
+ // event processor for onmousemove, used only for delayed drags
+ // e: Event
+ // mouse event
+ if(Math.abs(e.pageX - this._lastX) > this.delay || Math.abs(e.pageY - this._lastY) > this.delay){
+ this.onMouseUp(e);
+ this.onDragDetected(e);
+ }
+ dojo.stopEvent(e);
+ },
+ onMouseUp: function(e){
+ // summary:
+ // event processor for onmouseup, used only for delayed drags
+ // e: Event
+ // mouse event
+ for(var i = 0; i < 2; ++i){
+ dojo.disconnect(this.events.pop());
+ }
+ dojo.stopEvent(e);
+ },
+ onSelectStart: function(e){
+ // summary:
+ // event processor for onselectevent and ondragevent
+ // e: Event
+ // mouse event
+ if(!this.skip || !dojo.dnd.isFormElement(e)){
+ dojo.stopEvent(e);
+ }
+ },
+
+ // local events
+ onDragDetected: function(/* Event */ e){
+ // summary:
+ // called when the drag is detected;
+ // responsible for creation of the mover
+ new this.mover(this.node, e, this);
+ },
+ onMoveStart: function(/* dojo.dnd.Mover */ mover){
+ // summary:
+ // called before every move operation
+ dojo.publish("/dnd/move/start", [mover]);
+ dojo.addClass(dojo.body(), "dojoMove");
+ dojo.addClass(this.node, "dojoMoveItem");
+ },
+ onMoveStop: function(/* dojo.dnd.Mover */ mover){
+ // summary:
+ // called after every move operation
+ dojo.publish("/dnd/move/stop", [mover]);
+ dojo.removeClass(dojo.body(), "dojoMove");
+ dojo.removeClass(this.node, "dojoMoveItem");
+ },
+ onFirstMove: function(/* dojo.dnd.Mover */ mover, /* Event */ e){
+ // summary:
+ // called during the very first move notification;
+ // can be used to initialize coordinates, can be overwritten.
+
+ // default implementation does nothing
+ },
+ onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop, /* Event */ e){
+ // summary:
+ // called during every move notification;
+ // should actually move the node; can be overwritten.
+ this.onMoving(mover, leftTop);
+ var s = mover.node.style;
+ s.left = leftTop.l + "px";
+ s.top = leftTop.t + "px";
+ this.onMoved(mover, leftTop);
+ },
+ onMoving: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ // summary:
+ // called before every incremental move; can be overwritten.
+
+ // default implementation does nothing
+ },
+ onMoved: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ // summary:
+ // called after every incremental move; can be overwritten.
+
+ // default implementation does nothing
+ }
+});
+
+}
+
+if(!dojo._hasResource["dojo.dnd.move"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.move"] = true;
+dojo.provide("dojo.dnd.move");
+
+
+
+
+/*=====
+dojo.declare("dojo.dnd.move.__constrainedMoveableArgs", [dojo.dnd.__MoveableArgs], {
+ // constraints: Function
+ // Calculates a constraint box.
+ // It is called in a context of the moveable object.
+ constraints: function(){},
+
+ // within: Boolean
+ // restrict move within boundaries.
+ within: false
+});
+=====*/
+
+dojo.declare("dojo.dnd.move.constrainedMoveable", dojo.dnd.Moveable, {
+ // object attributes (for markup)
+ constraints: function(){},
+ within: false,
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.move.constrainedMoveable(node, params);
+ },
+
+ constructor: function(node, params){
+ // summary:
+ // an object that makes a node moveable
+ // node: Node
+ // a node (or node's id) to be moved
+ // params: dojo.dnd.move.__constrainedMoveableArgs?
+ // an optional object with additional parameters;
+ // the rest is passed to the base class
+ if(!params){ params = {}; }
+ this.constraints = params.constraints;
+ this.within = params.within;
+ },
+ onFirstMove: function(/* dojo.dnd.Mover */ mover){
+ // summary:
+ // called during the very first move notification;
+ // can be used to initialize coordinates, can be overwritten.
+ var c = this.constraintBox = this.constraints.call(this, mover);
+ c.r = c.l + c.w;
+ c.b = c.t + c.h;
+ if(this.within){
+ var mb = dojo.marginBox(mover.node);
+ c.r -= mb.w;
+ c.b -= mb.h;
+ }
+ },
+ onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ // summary:
+ // called during every move notification;
+ // should actually move the node; can be overwritten.
+ var c = this.constraintBox, s = mover.node.style;
+ s.left = (leftTop.l < c.l ? c.l : c.r < leftTop.l ? c.r : leftTop.l) + "px";
+ s.top = (leftTop.t < c.t ? c.t : c.b < leftTop.t ? c.b : leftTop.t) + "px";
+ }
+});
+
+/*=====
+dojo.declare("dojo.dnd.move.__boxConstrainedMoveableArgs", [dojo.dnd.move.__constrainedMoveableArgs], {
+ // box: Object
+ // a constraint box
+ box: {}
+});
+=====*/
+
+dojo.declare("dojo.dnd.move.boxConstrainedMoveable", dojo.dnd.move.constrainedMoveable, {
+ // box:
+ // object attributes (for markup)
+ box: {},
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.move.boxConstrainedMoveable(node, params);
+ },
+
+ constructor: function(node, params){
+ // summary:
+ // an object, which makes a node moveable
+ // node: Node
+ // a node (or node's id) to be moved
+ // params: dojo.dnd.move.__boxConstrainedMoveableArgs?
+ // an optional object with parameters
+ var box = params && params.box;
+ this.constraints = function(){ return box; };
+ }
+});
+
+/*=====
+dojo.declare("dojo.dnd.move.__parentConstrainedMoveableArgs", [dojo.dnd.move.__constrainedMoveableArgs], {
+ // area: String
+ // A parent's area to restrict the move.
+ // Can be "margin", "border", "padding", or "content".
+ area: ""
+});
+=====*/
+
+dojo.declare("dojo.dnd.move.parentConstrainedMoveable", dojo.dnd.move.constrainedMoveable, {
+ // area:
+ // object attributes (for markup)
+ area: "content",
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.move.parentConstrainedMoveable(node, params);
+ },
+
+ constructor: function(node, params){
+ // summary:
+ // an object, which makes a node moveable
+ // node: Node
+ // a node (or node's id) to be moved
+ // params: dojo.dnd.move.__parentConstrainedMoveableArgs?
+ // an optional object with parameters
+ var area = params && params.area;
+ this.constraints = function(){
+ var n = this.node.parentNode,
+ s = dojo.getComputedStyle(n),
+ mb = dojo._getMarginBox(n, s);
+ if(area == "margin"){
+ return mb; // Object
+ }
+ var t = dojo._getMarginExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ if(area == "border"){
+ return mb; // Object
+ }
+ t = dojo._getBorderExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ if(area == "padding"){
+ return mb; // Object
+ }
+ t = dojo._getPadExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ return mb; // Object
+ };
+ }
+});
+
+// WARNING: below are obsolete objects, instead of custom movers use custom moveables (above)
+
+dojo.dnd.move.constrainedMover = function(fun, within){
+ // summary:
+ // returns a constrained version of dojo.dnd.Mover
+ // description:
+ // this function produces n object, which will put a constraint on
+ // the margin box of dragged object in absolute coordinates
+ // fun: Function
+ // called on drag, and returns a constraint box
+ // within: Boolean
+ // if true, constraints the whole dragged object withtin the rectangle,
+ // otherwise the constraint is applied to the left-top corner
+
+ dojo.deprecated("dojo.dnd.move.constrainedMover, use dojo.dnd.move.constrainedMoveable instead");
+ var mover = function(node, e, notifier){
+ dojo.dnd.Mover.call(this, node, e, notifier);
+ };
+ dojo.extend(mover, dojo.dnd.Mover.prototype);
+ dojo.extend(mover, {
+ onMouseMove: function(e){
+ // summary: event processor for onmousemove
+ // e: Event: mouse event
+ dojo.dnd.autoScroll(e);
+ var m = this.marginBox, c = this.constraintBox,
+ l = m.l + e.pageX, t = m.t + e.pageY;
+ l = l < c.l ? c.l : c.r < l ? c.r : l;
+ t = t < c.t ? c.t : c.b < t ? c.b : t;
+ this.host.onMove(this, {l: l, t: t});
+ },
+ onFirstMove: function(){
+ // summary: called once to initialize things; it is meant to be called only once
+ dojo.dnd.Mover.prototype.onFirstMove.call(this);
+ var c = this.constraintBox = fun.call(this);
+ c.r = c.l + c.w;
+ c.b = c.t + c.h;
+ if(within){
+ var mb = dojo.marginBox(this.node);
+ c.r -= mb.w;
+ c.b -= mb.h;
+ }
+ }
+ });
+ return mover; // Object
+};
+
+dojo.dnd.move.boxConstrainedMover = function(box, within){
+ // summary:
+ // a specialization of dojo.dnd.constrainedMover, which constrains to the specified box
+ // box: Object
+ // a constraint box (l, t, w, h)
+ // within: Boolean
+ // if true, constraints the whole dragged object withtin the rectangle,
+ // otherwise the constraint is applied to the left-top corner
+
+ dojo.deprecated("dojo.dnd.move.boxConstrainedMover, use dojo.dnd.move.boxConstrainedMoveable instead");
+ return dojo.dnd.move.constrainedMover(function(){ return box; }, within); // Object
+};
+
+dojo.dnd.move.parentConstrainedMover = function(area, within){
+ // summary:
+ // a specialization of dojo.dnd.constrainedMover, which constrains to the parent node
+ // area: String
+ // "margin" to constrain within the parent's margin box, "border" for the border box,
+ // "padding" for the padding box, and "content" for the content box; "content" is the default value.
+ // within: Boolean
+ // if true, constraints the whole dragged object within the rectangle,
+ // otherwise the constraint is applied to the left-top corner
+
+ dojo.deprecated("dojo.dnd.move.parentConstrainedMover, use dojo.dnd.move.parentConstrainedMoveable instead");
+ var fun = function(){
+ var n = this.node.parentNode,
+ s = dojo.getComputedStyle(n),
+ mb = dojo._getMarginBox(n, s);
+ if(area == "margin"){
+ return mb; // Object
+ }
+ var t = dojo._getMarginExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ if(area == "border"){
+ return mb; // Object
+ }
+ t = dojo._getBorderExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ if(area == "padding"){
+ return mb; // Object
+ }
+ t = dojo._getPadExtents(n, s);
+ mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
+ return mb; // Object
+ };
+ return dojo.dnd.move.constrainedMover(fun, within); // Object
+};
+
+// patching functions one level up for compatibility
+
+dojo.dnd.constrainedMover = dojo.dnd.move.constrainedMover;
+dojo.dnd.boxConstrainedMover = dojo.dnd.move.boxConstrainedMover;
+dojo.dnd.parentConstrainedMover = dojo.dnd.move.parentConstrainedMover;
+
+}
+
+if(!dojo._hasResource["dojo.dnd.TimedMoveable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.TimedMoveable"] = true;
+dojo.provide("dojo.dnd.TimedMoveable");
+
+
+
+/*=====
+dojo.declare("dojo.dnd.__TimedMoveableArgs", [dojo.dnd.__MoveableArgs], {
+ // timeout: Number
+ // delay move by this number of ms,
+ // accumulating position changes during the timeout
+ timeout: 0
+});
+=====*/
+
+(function(){
+ // precalculate long expressions
+ var oldOnMove = dojo.dnd.Moveable.prototype.onMove;
+
+ dojo.declare("dojo.dnd.TimedMoveable", dojo.dnd.Moveable, {
+ // summary:
+ // A specialized version of Moveable to support an FPS throttling.
+ // This class puts an upper restriction on FPS, which may reduce
+ // the CPU load. The additional parameter "timeout" regulates
+ // the delay before actually moving the moveable object.
+
+ // object attributes (for markup)
+ timeout: 40, // in ms, 40ms corresponds to 25 fps
+
+ constructor: function(node, params){
+ // summary:
+ // an object that makes a node moveable with a timer
+ // node: Node||String
+ // a node (or node's id) to be moved
+ // params: dojo.dnd.__TimedMoveableArgs
+ // object with additional parameters.
+
+ // sanitize parameters
+ if(!params){ params = {}; }
+ if(params.timeout && typeof params.timeout == "number" && params.timeout >= 0){
+ this.timeout = params.timeout;
+ }
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ return new dojo.dnd.TimedMoveable(node, params);
+ },
+
+ onMoveStop: function(/* dojo.dnd.Mover */ mover){
+ if(mover._timer){
+ // stop timer
+ clearTimeout(mover._timer)
+ // reflect the last received position
+ oldOnMove.call(this, mover, mover._leftTop)
+ }
+ dojo.dnd.Moveable.prototype.onMoveStop.apply(this, arguments);
+ },
+ onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+ mover._leftTop = leftTop;
+ if(!mover._timer){
+ var _t = this; // to avoid using dojo.hitch()
+ mover._timer = setTimeout(function(){
+ // we don't have any pending requests
+ mover._timer = null;
+ // reflect the last received position
+ oldOnMove.call(_t, mover, mover._leftTop);
+ }, this.timeout);
+ }
+ }
+ });
+})();
+
+}
+
+if(!dojo._hasResource["dijit.form._FormMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form._FormMixin"] = true;
+dojo.provide("dijit.form._FormMixin");
+
+
+
+dojo.declare("dijit.form._FormMixin", null,
+ {
+ // summary:
+ // Mixin for containers of form widgets (i.e. widgets that represent a single value
+ // and can be children of a <form> node or dijit.form.Form widget)
+ // description:
+ // Can extract all the form widgets
+ // values and combine them into a single javascript object, or alternately
+ // take such an object and set the values for all the contained
+ // form widgets
+
+/*=====
+ // value: Object
+ // Name/value hash for each child widget with a name and value.
+ // Child widgets without names are not part of the hash.
+ //
+ // If there are multiple child widgets w/the same name, value is an array,
+ // unless they are radio buttons in which case value is a scalar (since only
+ // one radio button can be checked at a time).
+ //
+ // If a child widget's name is a dot separated list (like a.b.c.d), it's a nested structure.
+ //
+ // Example:
+ // | { name: "John Smith", interests: ["sports", "movies"] }
+=====*/
+
+ // TODO:
+ // * Repeater
+ // * better handling for arrays. Often form elements have names with [] like
+ // * people[3].sex (for a list of people [{name: Bill, sex: M}, ...])
+ //
+ //
+
+ reset: function(){
+ dojo.forEach(this.getDescendants(), function(widget){
+ if(widget.reset){
+ widget.reset();
+ }
+ });
+ },
+
+ validate: function(){
+ // summary:
+ // returns if the form is valid - same as isValid - but
+ // provides a few additional (ui-specific) features.
+ // 1 - it will highlight any sub-widgets that are not
+ // valid
+ // 2 - it will call focus() on the first invalid
+ // sub-widget
+ var didFocus = false;
+ return dojo.every(dojo.map(this.getDescendants(), function(widget){
+ // Need to set this so that "required" widgets get their
+ // state set.
+ widget._hasBeenBlurred = true;
+ var valid = widget.disabled || !widget.validate || widget.validate();
+ if(!valid && !didFocus){
+ // Set focus of the first non-valid widget
+ dojo.window.scrollIntoView(widget.containerNode || widget.domNode);
+ widget.focus();
+ didFocus = true;
+ }
+ return valid;
+ }), function(item){ return item; });
+ },
+
+ setValues: function(val){
+ dojo.deprecated(this.declaredClass+"::setValues() is deprecated. Use set('value', val) instead.", "", "2.0");
+ return this.set('value', val);
+ },
+ _setValueAttr: function(/*object*/obj){
+ // summary:
+ // Fill in form values from according to an Object (in the format returned by attr('value'))
+
+ // generate map from name --> [list of widgets with that name]
+ var map = { };
+ dojo.forEach(this.getDescendants(), function(widget){
+ if(!widget.name){ return; }
+ var entry = map[widget.name] || (map[widget.name] = [] );
+ entry.push(widget);
+ });
+
+ for(var name in map){
+ if(!map.hasOwnProperty(name)){
+ continue;
+ }
+ var widgets = map[name], // array of widgets w/this name
+ values = dojo.getObject(name, false, obj); // list of values for those widgets
+
+ if(values === undefined){
+ continue;
+ }
+ if(!dojo.isArray(values)){
+ values = [ values ];
+ }
+ if(typeof widgets[0].checked == 'boolean'){
+ // for checkbox/radio, values is a list of which widgets should be checked
+ dojo.forEach(widgets, function(w, i){
+ w.set('value', dojo.indexOf(values, w.value) != -1);
+ });
+ }else if(widgets[0].multiple){
+ // it takes an array (e.g. multi-select)
+ widgets[0].set('value', values);
+ }else{
+ // otherwise, values is a list of values to be assigned sequentially to each widget
+ dojo.forEach(widgets, function(w, i){
+ w.set('value', values[i]);
+ });
+ }
+ }
+
+ /***
+ * TODO: code for plain input boxes (this shouldn't run for inputs that are part of widgets)
+
+ dojo.forEach(this.containerNode.elements, function(element){
+ if(element.name == ''){return}; // like "continue"
+ var namePath = element.name.split(".");
+ var myObj=obj;
+ var name=namePath[namePath.length-1];
+ for(var j=1,len2=namePath.length;j<len2;++j){
+ var p=namePath[j - 1];
+ // repeater support block
+ var nameA=p.split("[");
+ if(nameA.length > 1){
+ if(typeof(myObj[nameA[0]]) == "undefined"){
+ myObj[nameA[0]]=[ ];
+ } // if
+
+ nameIndex=parseInt(nameA[1]);
+ if(typeof(myObj[nameA[0]][nameIndex]) == "undefined"){
+ myObj[nameA[0]][nameIndex] = { };
+ }
+ myObj=myObj[nameA[0]][nameIndex];
+ continue;
+ } // repeater support ends
+
+ if(typeof(myObj[p]) == "undefined"){
+ myObj=undefined;
+ break;
+ };
+ myObj=myObj[p];
+ }
+
+ if(typeof(myObj) == "undefined"){
+ return; // like "continue"
+ }
+ if(typeof(myObj[name]) == "undefined" && this.ignoreNullValues){
+ return; // like "continue"
+ }
+
+ // TODO: widget values (just call attr('value', ...) on the widget)
+
+ // TODO: maybe should call dojo.getNodeProp() instead
+ switch(element.type){
+ case "checkbox":
+ element.checked = (name in myObj) &&
+ dojo.some(myObj[name], function(val){ return val == element.value; });
+ break;
+ case "radio":
+ element.checked = (name in myObj) && myObj[name] == element.value;
+ break;
+ case "select-multiple":
+ element.selectedIndex=-1;
+ dojo.forEach(element.options, function(option){
+ option.selected = dojo.some(myObj[name], function(val){ return option.value == val; });
+ });
+ break;
+ case "select-one":
+ element.selectedIndex="0";
+ dojo.forEach(element.options, function(option){
+ option.selected = option.value == myObj[name];
+ });
+ break;
+ case "hidden":
+ case "text":
+ case "textarea":
+ case "password":
+ element.value = myObj[name] || "";
+ break;
+ }
+ });
+ */
+ },
+
+ getValues: function(){
+ dojo.deprecated(this.declaredClass+"::getValues() is deprecated. Use get('value') instead.", "", "2.0");
+ return this.get('value');
+ },
+ _getValueAttr: function(){
+ // summary:
+ // Returns Object representing form values.
+ // description:
+ // Returns name/value hash for each form element.
+ // If there are multiple elements w/the same name, value is an array,
+ // unless they are radio buttons in which case value is a scalar since only
+ // one can be checked at a time.
+ //
+ // If the name is a dot separated list (like a.b.c.d), creates a nested structure.
+ // Only works on widget form elements.
+ // example:
+ // | { name: "John Smith", interests: ["sports", "movies"] }
+
+ // get widget values
+ var obj = { };
+ dojo.forEach(this.getDescendants(), function(widget){
+ var name = widget.name;
+ if(!name || widget.disabled){ return; }
+
+ // Single value widget (checkbox, radio, or plain <input> type widget
+ var value = widget.get('value');
+
+ // Store widget's value(s) as a scalar, except for checkboxes which are automatically arrays
+ if(typeof widget.checked == 'boolean'){
+ if(/Radio/.test(widget.declaredClass)){
+ // radio button
+ if(value !== false){
+ dojo.setObject(name, value, obj);
+ }else{
+ // give radio widgets a default of null
+ value = dojo.getObject(name, false, obj);
+ if(value === undefined){
+ dojo.setObject(name, null, obj);
+ }
+ }
+ }else{
+ // checkbox/toggle button
+ var ary=dojo.getObject(name, false, obj);
+ if(!ary){
+ ary=[];
+ dojo.setObject(name, ary, obj);
+ }
+ if(value !== false){
+ ary.push(value);
+ }
+ }
+ }else{
+ var prev=dojo.getObject(name, false, obj);
+ if(typeof prev != "undefined"){
+ if(dojo.isArray(prev)){
+ prev.push(value);
+ }else{
+ dojo.setObject(name, [prev, value], obj);
+ }
+ }else{
+ // unique name
+ dojo.setObject(name, value, obj);
+ }
+ }
+ });
+
+ /***
+ * code for plain input boxes (see also dojo.formToObject, can we use that instead of this code?
+ * but it doesn't understand [] notation, presumably)
+ var obj = { };
+ dojo.forEach(this.containerNode.elements, function(elm){
+ if(!elm.name) {
+ return; // like "continue"
+ }
+ var namePath = elm.name.split(".");
+ var myObj=obj;
+ var name=namePath[namePath.length-1];
+ for(var j=1,len2=namePath.length;j<len2;++j){
+ var nameIndex = null;
+ var p=namePath[j - 1];
+ var nameA=p.split("[");
+ if(nameA.length > 1){
+ if(typeof(myObj[nameA[0]]) == "undefined"){
+ myObj[nameA[0]]=[ ];
+ } // if
+ nameIndex=parseInt(nameA[1]);
+ if(typeof(myObj[nameA[0]][nameIndex]) == "undefined"){
+ myObj[nameA[0]][nameIndex] = { };
+ }
+ } else if(typeof(myObj[nameA[0]]) == "undefined"){
+ myObj[nameA[0]] = { }
+ } // if
+
+ if(nameA.length == 1){
+ myObj=myObj[nameA[0]];
+ } else{
+ myObj=myObj[nameA[0]][nameIndex];
+ } // if
+ } // for
+
+ if((elm.type != "select-multiple" && elm.type != "checkbox" && elm.type != "radio") || (elm.type == "radio" && elm.checked)){
+ if(name == name.split("[")[0]){
+ myObj[name]=elm.value;
+ } else{
+ // can not set value when there is no name
+ }
+ } else if(elm.type == "checkbox" && elm.checked){
+ if(typeof(myObj[name]) == 'undefined'){
+ myObj[name]=[ ];
+ }
+ myObj[name].push(elm.value);
+ } else if(elm.type == "select-multiple"){
+ if(typeof(myObj[name]) == 'undefined'){
+ myObj[name]=[ ];
+ }
+ for(var jdx=0,len3=elm.options.length; jdx<len3; ++jdx){
+ if(elm.options[jdx].selected){
+ myObj[name].push(elm.options[jdx].value);
+ }
+ }
+ } // if
+ name=undefined;
+ }); // forEach
+ ***/
+ return obj;
+ },
+
+ // TODO: ComboBox might need time to process a recently input value. This should be async?
+ isValid: function(){
+ // summary:
+ // Returns true if all of the widgets are valid
+
+ // This also populate this._invalidWidgets[] array with list of invalid widgets...
+ // TODO: put that into separate function? It's confusing to have that as a side effect
+ // of a method named isValid().
+
+ this._invalidWidgets = dojo.filter(this.getDescendants(), function(widget){
+ return !widget.disabled && widget.isValid && !widget.isValid();
+ });
+ return !this._invalidWidgets.length;
+ },
+
+
+ onValidStateChange: function(isValid){
+ // summary:
+ // Stub function to connect to if you want to do something
+ // (like disable/enable a submit button) when the valid
+ // state changes on the form as a whole.
+ },
+
+ _widgetChange: function(widget){
+ // summary:
+ // Connected to a widget's onChange function - update our
+ // valid state, if needed.
+ var isValid = this._lastValidState;
+ if(!widget || this._lastValidState === undefined){
+ // We have passed a null widget, or we haven't been validated
+ // yet - let's re-check all our children
+ // This happens when we connect (or reconnect) our children
+ isValid = this.isValid();
+ if(this._lastValidState === undefined){
+ // Set this so that we don't fire an onValidStateChange
+ // the first time
+ this._lastValidState = isValid;
+ }
+ }else if(widget.isValid){
+ this._invalidWidgets = dojo.filter(this._invalidWidgets || [], function(w){
+ return (w != widget);
+ }, this);
+ if(!widget.isValid() && !widget.get("disabled")){
+ this._invalidWidgets.push(widget);
+ }
+ isValid = (this._invalidWidgets.length === 0);
+ }
+ if(isValid !== this._lastValidState){
+ this._lastValidState = isValid;
+ this.onValidStateChange(isValid);
+ }
+ },
+
+ connectChildren: function(){
+ // summary:
+ // Connects to the onChange function of all children to
+ // track valid state changes. You can call this function
+ // directly, ex. in the event that you programmatically
+ // add a widget to the form *after* the form has been
+ // initialized.
+ dojo.forEach(this._changeConnections, dojo.hitch(this, "disconnect"));
+ var _this = this;
+
+ // we connect to validate - so that it better reflects the states
+ // of the widgets - also, we only connect if it has a validate
+ // function (to avoid too many unneeded connections)
+ var conns = (this._changeConnections = []);
+ dojo.forEach(dojo.filter(this.getDescendants(),
+ function(item){ return item.validate; }
+ ),
+ function(widget){
+ // We are interested in whenever the widget is validated - or
+ // whenever the disabled attribute on that widget is changed
+ conns.push(_this.connect(widget, "validate",
+ dojo.hitch(_this, "_widgetChange", widget)));
+ conns.push(_this.connect(widget, "_setDisabledAttr",
+ dojo.hitch(_this, "_widgetChange", widget)));
+ });
+
+ // Call the widget change function to update the valid state, in
+ // case something is different now.
+ this._widgetChange(null);
+ },
+
+ startup: function(){
+ this.inherited(arguments);
+ // Initialize our valid state tracking. Needs to be done in startup
+ // because it's not guaranteed that our children are initialized
+ // yet.
+ this._changeConnections = [];
+ this.connectChildren();
+ }
+ });
+
+}
+
+if(!dojo._hasResource["dijit._DialogMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._DialogMixin"] = true;
+dojo.provide("dijit._DialogMixin");
+
+
+
+dojo.declare("dijit._DialogMixin", null,
+ {
+ // summary:
+ // This provides functions useful to Dialog and TooltipDialog
+
+ attributeMap: dijit._Widget.prototype.attributeMap,
+
+ execute: function(/*Object*/ formContents){
+ // summary:
+ // Callback when the user hits the submit button.
+ // Override this method to handle Dialog execution.
+ // description:
+ // After the user has pressed the submit button, the Dialog
+ // first calls onExecute() to notify the container to hide the
+ // dialog and restore focus to wherever it used to be.
+ //
+ // *Then* this method is called.
+ // type:
+ // callback
+ },
+
+ onCancel: function(){
+ // summary:
+ // Called when user has pressed the Dialog's cancel button, to notify container.
+ // description:
+ // Developer shouldn't override or connect to this method;
+ // it's a private communication device between the TooltipDialog
+ // and the thing that opened it (ex: `dijit.form.DropDownButton`)
+ // type:
+ // protected
+ },
+
+ onExecute: function(){
+ // summary:
+ // Called when user has pressed the dialog's OK button, to notify container.
+ // description:
+ // Developer shouldn't override or connect to this method;
+ // it's a private communication device between the TooltipDialog
+ // and the thing that opened it (ex: `dijit.form.DropDownButton`)
+ // type:
+ // protected
+ },
+
+ _onSubmit: function(){
+ // summary:
+ // Callback when user hits submit button
+ // type:
+ // protected
+ this.onExecute(); // notify container that we are about to execute
+ this.execute(this.get('value'));
+ },
+
+ _getFocusItems: function(/*Node*/ dialogNode){
+ // summary:
+ // Find focusable Items each time a dialog is opened,
+ // setting _firstFocusItem and _lastFocusItem
+ // tags:
+ // protected
+
+ var elems = dijit._getTabNavigable(dojo.byId(dialogNode));
+ this._firstFocusItem = elems.lowest || elems.first || dialogNode;
+ this._lastFocusItem = elems.last || elems.highest || this._firstFocusItem;
+ if(dojo.isMoz && this._firstFocusItem.tagName.toLowerCase() == "input" &&
+ dojo.getNodeProp(this._firstFocusItem, "type").toLowerCase() == "file"){
+ // FF doesn't behave well when first element is input type=file, set first focusable to dialog container
+ dojo.attr(dialogNode, "tabIndex", "0");
+ this._firstFocusItem = dialogNode;
+ }
+ }
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit.DialogUnderlay"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.DialogUnderlay"] = true;
+dojo.provide("dijit.DialogUnderlay");
+
+
+
+
+
+
+dojo.declare(
+ "dijit.DialogUnderlay",
+ [dijit._Widget, dijit._Templated],
+ {
+ // summary:
+ // The component that blocks the screen behind a `dijit.Dialog`
+ //
+ // description:
+ // A component used to block input behind a `dijit.Dialog`. Only a single
+ // instance of this widget is created by `dijit.Dialog`, and saved as
+ // a reference to be shared between all Dialogs as `dijit._underlay`
+ //
+ // The underlay itself can be styled based on and id:
+ // | #myDialog_underlay { background-color:red; }
+ //
+ // In the case of `dijit.Dialog`, this id is based on the id of the Dialog,
+ // suffixed with _underlay.
+
+ // Template has two divs; outer div is used for fade-in/fade-out, and also to hold background iframe.
+ // Inner div has opacity specified in CSS file.
+ templateString: "<div class='dijitDialogUnderlayWrapper'><div class='dijitDialogUnderlay' dojoAttachPoint='node'></div></div>",
+
+ // Parameters on creation or updatable later
+
+ // dialogId: String
+ // Id of the dialog.... DialogUnderlay's id is based on this id
+ dialogId: "",
+
+ // class: String
+ // This class name is used on the DialogUnderlay node, in addition to dijitDialogUnderlay
+ "class": "",
+
+ attributeMap: { id: "domNode" },
+
+ _setDialogIdAttr: function(id){
+ dojo.attr(this.node, "id", id + "_underlay");
+ },
+
+ _setClassAttr: function(clazz){
+ this.node.className = "dijitDialogUnderlay " + clazz;
+ },
+
+ postCreate: function(){
+ // summary:
+ // Append the underlay to the body
+ dojo.body().appendChild(this.domNode);
+ },
+
+ layout: function(){
+ // summary:
+ // Sets the background to the size of the viewport
+ //
+ // description:
+ // Sets the background to the size of the viewport (rather than the size
+ // of the document) since we need to cover the whole browser window, even
+ // if the document is only a few lines long.
+ // tags:
+ // private
+
+ var is = this.node.style,
+ os = this.domNode.style;
+
+ // hide the background temporarily, so that the background itself isn't
+ // causing scrollbars to appear (might happen when user shrinks browser
+ // window and then we are called to resize)
+ os.display = "none";
+
+ // then resize and show
+ var viewport = dojo.window.getBox();
+ os.top = viewport.t + "px";
+ os.left = viewport.l + "px";
+ is.width = viewport.w + "px";
+ is.height = viewport.h + "px";
+ os.display = "block";
+ },
+
+ show: function(){
+ // summary:
+ // Show the dialog underlay
+ this.domNode.style.display = "block";
+ this.layout();
+ this.bgIframe = new dijit.BackgroundIframe(this.domNode);
+ },
+
+ hide: function(){
+ // summary:
+ // Hides the dialog underlay
+ this.bgIframe.destroy();
+ this.domNode.style.display = "none";
+ },
+
+ uninitialize: function(){
+ if(this.bgIframe){
+ this.bgIframe.destroy();
+ }
+ this.inherited(arguments);
+ }
+ }
+);
+
+}
+
+if(!dojo._hasResource["dojo.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.html"] = true;
+dojo.provide("dojo.html");
+
+// the parser might be needed..
+
+
+(function(){ // private scope, sort of a namespace
+
+ // idCounter is incremented with each instantiation to allow asignment of a unique id for tracking, logging purposes
+ var idCounter = 0,
+ d = dojo;
+
+ dojo.html._secureForInnerHtml = function(/*String*/ cont){
+ // summary:
+ // removes !DOCTYPE and title elements from the html string.
+ //
+ // khtml is picky about dom faults, you can't attach a style or <title> node as child of body
+ // must go into head, so we need to cut out those tags
+ // cont:
+ // An html string for insertion into the dom
+ //
+ return cont.replace(/(?:\s*<!DOCTYPE\s[^>]+>|<title[^>]*>[\s\S]*?<\/title>)/ig, ""); // String
+ };
+
+/*====
+ dojo.html._emptyNode = function(node){
+ // summary:
+ // removes all child nodes from the given node
+ // node: DOMNode
+ // the parent element
+ };
+=====*/
+ dojo.html._emptyNode = dojo.empty;
+
+ dojo.html._setNodeContent = function(/* DomNode */ node, /* String|DomNode|NodeList */ cont){
+ // summary:
+ // inserts the given content into the given node
+ // node:
+ // the parent element
+ // content:
+ // the content to be set on the parent element.
+ // This can be an html string, a node reference or a NodeList, dojo.NodeList, Array or other enumerable list of nodes
+
+ // always empty
+ d.empty(node);
+
+ if(cont) {
+ if(typeof cont == "string") {
+ cont = d._toDom(cont, node.ownerDocument);
+ }
+ if(!cont.nodeType && d.isArrayLike(cont)) {
+ // handle as enumerable, but it may shrink as we enumerate it
+ for(var startlen=cont.length, i=0; i<cont.length; i=startlen==cont.length ? i+1 : 0) {
+ d.place( cont[i], node, "last");
+ }
+ } else {
+ // pass nodes, documentFragments and unknowns through to dojo.place
+ d.place(cont, node, "last");
+ }
+ }
+
+ // return DomNode
+ return node;
+ };
+
+ // we wrap up the content-setting operation in a object
+ dojo.declare("dojo.html._ContentSetter", null,
+ {
+ // node: DomNode|String
+ // An node which will be the parent element that we set content into
+ node: "",
+
+ // content: String|DomNode|DomNode[]
+ // The content to be placed in the node. Can be an HTML string, a node reference, or a enumerable list of nodes
+ content: "",
+
+ // id: String?
+ // Usually only used internally, and auto-generated with each instance
+ id: "",
+
+ // cleanContent: Boolean
+ // Should the content be treated as a full html document,
+ // and the real content stripped of <html>, <body> wrapper before injection
+ cleanContent: false,
+
+ // extractContent: Boolean
+ // Should the content be treated as a full html document, and the real content stripped of <html>, <body> wrapper before injection
+ extractContent: false,
+
+ // parseContent: Boolean
+ // Should the node by passed to the parser after the new content is set
+ parseContent: false,
+
+ // lifecyle methods
+ constructor: function(/* Object */params, /* String|DomNode */node){
+ // summary:
+ // Provides a configurable, extensible object to wrap the setting on content on a node
+ // call the set() method to actually set the content..
+
+ // the original params are mixed directly into the instance "this"
+ dojo.mixin(this, params || {});
+
+ // give precedence to params.node vs. the node argument
+ // and ensure its a node, not an id string
+ node = this.node = dojo.byId( this.node || node );
+
+ if(!this.id){
+ this.id = [
+ "Setter",
+ (node) ? node.id || node.tagName : "",
+ idCounter++
+ ].join("_");
+ }
+ },
+ set: function(/* String|DomNode|NodeList? */ cont, /* Object? */ params){
+ // summary:
+ // front-end to the set-content sequence
+ // cont:
+ // An html string, node or enumerable list of nodes for insertion into the dom
+ // If not provided, the object's content property will be used
+ if(undefined !== cont){
+ this.content = cont;
+ }
+ // in the re-use scenario, set needs to be able to mixin new configuration
+ if(params){
+ this._mixin(params);
+ }
+
+ this.onBegin();
+ this.setContent();
+ this.onEnd();
+
+ return this.node;
+ },
+ setContent: function(){
+ // summary:
+ // sets the content on the node
+
+ var node = this.node;
+ if(!node) {
+ // can't proceed
+ throw new Error(this.declaredClass + ": setContent given no node");
+ }
+ try{
+ node = dojo.html._setNodeContent(node, this.content);
+ }catch(e){
+ // check if a domfault occurs when we are appending this.errorMessage
+ // like for instance if domNode is a UL and we try append a DIV
+
+ // FIXME: need to allow the user to provide a content error message string
+ var errMess = this.onContentError(e);
+ try{
+ node.innerHTML = errMess;
+ }catch(e){
+ console.error('Fatal ' + this.declaredClass + '.setContent could not change content due to '+e.message, e);
+ }
+ }
+ // always put back the node for the next method
+ this.node = node; // DomNode
+ },
+
+ empty: function() {
+ // summary
+ // cleanly empty out existing content
+
+ // destroy any widgets from a previous run
+ // NOTE: if you dont want this you'll need to empty
+ // the parseResults array property yourself to avoid bad things happenning
+ if(this.parseResults && this.parseResults.length) {
+ dojo.forEach(this.parseResults, function(w) {
+ if(w.destroy){
+ w.destroy();
+ }
+ });
+ delete this.parseResults;
+ }
+ // this is fast, but if you know its already empty or safe, you could
+ // override empty to skip this step
+ dojo.html._emptyNode(this.node);
+ },
+
+ onBegin: function(){
+ // summary
+ // Called after instantiation, but before set();
+ // It allows modification of any of the object properties
+ // - including the node and content provided - before the set operation actually takes place
+ // This default implementation checks for cleanContent and extractContent flags to
+ // optionally pre-process html string content
+ var cont = this.content;
+
+ if(dojo.isString(cont)){
+ if(this.cleanContent){
+ cont = dojo.html._secureForInnerHtml(cont);
+ }
+
+ if(this.extractContent){
+ var match = cont.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+ if(match){ cont = match[1]; }
+ }
+ }
+
+ // clean out the node and any cruft associated with it - like widgets
+ this.empty();
+
+ this.content = cont;
+ return this.node; /* DomNode */
+ },
+
+ onEnd: function(){
+ // summary
+ // Called after set(), when the new content has been pushed into the node
+ // It provides an opportunity for post-processing before handing back the node to the caller
+ // This default implementation checks a parseContent flag to optionally run the dojo parser over the new content
+ if(this.parseContent){
+ // populates this.parseResults if you need those..
+ this._parse();
+ }
+ return this.node; /* DomNode */
+ },
+
+ tearDown: function(){
+ // summary
+ // manually reset the Setter instance if its being re-used for example for another set()
+ // description
+ // tearDown() is not called automatically.
+ // In normal use, the Setter instance properties are simply allowed to fall out of scope
+ // but the tearDown method can be called to explicitly reset this instance.
+ delete this.parseResults;
+ delete this.node;
+ delete this.content;
+ },
+
+ onContentError: function(err){
+ return "Error occured setting content: " + err;
+ },
+
+ _mixin: function(params){
+ // mix properties/methods into the instance
+ // TODO: the intention with tearDown is to put the Setter's state
+ // back to that of the original constructor (vs. deleting/resetting everything regardless of ctor params)
+ // so we could do something here to move the original properties aside for later restoration
+ var empty = {}, key;
+ for(key in params){
+ if(key in empty){ continue; }
+ // TODO: here's our opportunity to mask the properties we dont consider configurable/overridable
+ // .. but history shows we'll almost always guess wrong
+ this[key] = params[key];
+ }
+ },
+ _parse: function(){
+ // summary:
+ // runs the dojo parser over the node contents, storing any results in this.parseResults
+ // Any errors resulting from parsing are passed to _onError for handling
+
+ var rootNode = this.node;
+ try{
+ // store the results (widgets, whatever) for potential retrieval
+ this.parseResults = dojo.parser.parse({
+ rootNode: rootNode,
+ dir: this.dir,
+ lang: this.lang
+ });
+ }catch(e){
+ this._onError('Content', e, "Error parsing in _ContentSetter#"+this.id);
+ }
+ },
+
+ _onError: function(type, err, consoleText){
+ // summary:
+ // shows user the string that is returned by on[type]Error
+ // overide/implement on[type]Error and return your own string to customize
+ var errText = this['on' + type + 'Error'].call(this, err);
+ if(consoleText){
+ console.error(consoleText, err);
+ }else if(errText){ // a empty string won't change current content
+ dojo.html._setNodeContent(this.node, errText, true);
+ }
+ }
+ }); // end dojo.declare()
+
+ dojo.html.set = function(/* DomNode */ node, /* String|DomNode|NodeList */ cont, /* Object? */ params){
+ // summary:
+ // inserts (replaces) the given content into the given node. dojo.place(cont, node, "only")
+ // may be a better choice for simple HTML insertion.
+ // description:
+ // Unless you need to use the params capabilities of this method, you should use
+ // dojo.place(cont, node, "only"). dojo.place() has more robust support for injecting
+ // an HTML string into the DOM, but it only handles inserting an HTML string as DOM
+ // elements, or inserting a DOM node. dojo.place does not handle NodeList insertions
+ // or the other capabilities as defined by the params object for this method.
+ // node:
+ // the parent element that will receive the content
+ // cont:
+ // the content to be set on the parent element.
+ // This can be an html string, a node reference or a NodeList, dojo.NodeList, Array or other enumerable list of nodes
+ // params:
+ // Optional flags/properties to configure the content-setting. See dojo.html._ContentSetter
+ // example:
+ // A safe string/node/nodelist content replacement/injection with hooks for extension
+ // Example Usage:
+ // dojo.html.set(node, "some string");
+ // dojo.html.set(node, contentNode, {options});
+ // dojo.html.set(node, myNode.childNodes, {options});
+ if(undefined == cont){
+ console.warn("dojo.html.set: no cont argument provided, using empty string");
+ cont = "";
+ }
+ if(!params){
+ // simple and fast
+ return dojo.html._setNodeContent(node, cont, true);
+ }else{
+ // more options but slower
+ // note the arguments are reversed in order, to match the convention for instantiation via the parser
+ var op = new dojo.html._ContentSetter(dojo.mixin(
+ params,
+ { content: cont, node: node }
+ ));
+ return op.set();
+ }
+ };
+})();
+
+}
+
+if(!dojo._hasResource["dijit.layout.ContentPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.ContentPane"] = true;
+dojo.provide("dijit.layout.ContentPane");
+
+
+
+ // for dijit.layout.marginBox2contentBox()
+
+
+
+
+
+
+dojo.declare(
+ "dijit.layout.ContentPane", dijit._Widget,
+{
+ // summary:
+ // A widget that acts as a container for mixed HTML and widgets, and includes an Ajax interface
+ // description:
+ // A widget that can be used as a stand alone widget
+ // or as a base class for other widgets.
+ //
+ // Handles replacement of document fragment using either external uri or javascript
+ // generated markup or DOM content, instantiating widgets within that content.
+ // Don't confuse it with an iframe, it only needs/wants document fragments.
+ // It's useful as a child of LayoutContainer, SplitContainer, or TabContainer.
+ // But note that those classes can contain any widget as a child.
+ // example:
+ // Some quick samples:
+ // To change the innerHTML use .set('content', '<b>new content</b>')
+ //
+ // Or you can send it a NodeList, .set('content', dojo.query('div [class=selected]', userSelection))
+ // please note that the nodes in NodeList will copied, not moved
+ //
+ // To do a ajax update use .set('href', url)
+
+ // href: String
+ // The href of the content that displays now.
+ // Set this at construction if you want to load data externally when the
+ // pane is shown. (Set preload=true to load it immediately.)
+ // Changing href after creation doesn't have any effect; Use set('href', ...);
+ href: "",
+
+/*=====
+ // content: String || DomNode || NodeList || dijit._Widget
+ // The innerHTML of the ContentPane.
+ // Note that the initialization parameter / argument to attr("content", ...)
+ // can be a String, DomNode, Nodelist, or _Widget.
+ content: "",
+=====*/
+
+ // extractContent: Boolean
+ // Extract visible content from inside of <body> .... </body>.
+ // I.e., strip <html> and <head> (and it's contents) from the href
+ extractContent: false,
+
+ // parseOnLoad: Boolean
+ // Parse content and create the widgets, if any.
+ parseOnLoad: true,
+
+ // preventCache: Boolean
+ // Prevent caching of data from href's by appending a timestamp to the href.
+ preventCache: false,
+
+ // preload: Boolean
+ // Force load of data on initialization even if pane is hidden.
+ preload: false,
+
+ // refreshOnShow: Boolean
+ // Refresh (re-download) content when pane goes from hidden to shown
+ refreshOnShow: false,
+
+ // loadingMessage: String
+ // Message that shows while downloading
+ loadingMessage: "<span class='dijitContentPaneLoading'>${loadingState}</span>",
+
+ // errorMessage: String
+ // Message that shows if an error occurs
+ errorMessage: "<span class='dijitContentPaneError'>${errorState}</span>",
+
+ // isLoaded: [readonly] Boolean
+ // True if the ContentPane has data in it, either specified
+ // during initialization (via href or inline content), or set
+ // via attr('content', ...) / attr('href', ...)
+ //
+ // False if it doesn't have any content, or if ContentPane is
+ // still in the process of downloading href.
+ isLoaded: false,
+
+ baseClass: "dijitContentPane",
+
+ // doLayout: Boolean
+ // - false - don't adjust size of children
+ // - true - if there is a single visible child widget, set it's size to
+ // however big the ContentPane is
+ doLayout: true,
+
+ // ioArgs: Object
+ // Parameters to pass to xhrGet() request, for example:
+ // | <div dojoType="dijit.layout.ContentPane" href="./bar" ioArgs="{timeout: 500}">
+ ioArgs: {},
+
+ // isContainer: [protected] Boolean
+ // Indicates that this widget acts as a "parent" to the descendant widgets.
+ // When the parent is started it will call startup() on the child widgets.
+ // See also `isLayoutContainer`.
+ isContainer: true,
+
+ // isLayoutContainer: [protected] Boolean
+ // Indicates that this widget will call resize() on it's child widgets
+ // when they become visible.
+ isLayoutContainer: true,
+
+ // onLoadDeferred: [readonly] dojo.Deferred
+ // This is the `dojo.Deferred` returned by attr('href', ...) and refresh().
+ // Calling onLoadDeferred.addCallback() or addErrback() registers your
+ // callback to be called only once, when the prior attr('href', ...) call or
+ // the initial href parameter to the constructor finishes loading.
+ //
+ // This is different than an onLoad() handler which gets called any time any href is loaded.
+ onLoadDeferred: null,
+
+ // Override _Widget's attributeMap because we don't want the title attribute (used to specify
+ // tab labels) to be copied to ContentPane.domNode... otherwise a tooltip shows up over the
+ // entire pane.
+ attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+ title: []
+ }),
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ var messages = dojo.i18n.getLocalization("dijit", "loading", this.lang);
+ this.loadingMessage = dojo.string.substitute(this.loadingMessage, messages);
+ this.errorMessage = dojo.string.substitute(this.errorMessage, messages);
+
+ // Detect if we were initialized with data
+ if(!this.href && this.srcNodeRef && this.srcNodeRef.innerHTML){
+ this.isLoaded = true;
+ }
+ },
+
+ buildRendering: function(){
+ // Overrides Widget.buildRendering().
+ // Since we have no template we need to set this.containerNode ourselves.
+ // For subclasses of ContentPane do have a template, does nothing.
+ this.inherited(arguments);
+ if(!this.containerNode){
+ // make getDescendants() work
+ this.containerNode = this.domNode;
+ }
+ },
+
+ postCreate: function(){
+ // remove the title attribute so it doesn't show up when hovering
+ // over a node
+ this.domNode.title = "";
+
+ if(!dojo.attr(this.domNode,"role")){
+ dijit.setWaiRole(this.domNode, "group");
+ }
+
+ dojo.addClass(this.domNode, this.baseClass);
+ },
+
+ startup: function(){
+ // summary:
+ // See `dijit.layout._LayoutWidget.startup` for description.
+ // Although ContentPane doesn't extend _LayoutWidget, it does implement
+ // the same API.
+ if(this._started){ return; }
+
+ var parent = dijit._Contained.prototype.getParent.call(this);
+ this._childOfLayoutWidget = parent && parent.isLayoutContainer;
+
+ // I need to call resize() on my child/children (when I become visible), unless
+ // I'm the child of a layout widget in which case my parent will call resize() on me and I'll do it then.
+ this._needLayout = !this._childOfLayoutWidget;
+
+ if(this.isLoaded){
+ dojo.forEach(this.getChildren(), function(child){
+ child.startup();
+ });
+ }
+
+ if(this._isShown() || this.preload){
+ this._onShow();
+ }
+
+ this.inherited(arguments);
+ },
+
+ _checkIfSingleChild: function(){
+ // summary:
+ // Test if we have exactly one visible widget as a child,
+ // and if so assume that we are a container for that widget,
+ // and should propogate startup() and resize() calls to it.
+ // Skips over things like data stores since they aren't visible.
+
+ var childNodes = dojo.query("> *", this.containerNode).filter(function(node){
+ return node.tagName !== "SCRIPT"; // or a regexp for hidden elements like script|area|map|etc..
+ }),
+ childWidgetNodes = childNodes.filter(function(node){
+ return dojo.hasAttr(node, "dojoType") || dojo.hasAttr(node, "widgetId");
+ }),
+ candidateWidgets = dojo.filter(childWidgetNodes.map(dijit.byNode), function(widget){
+ return widget && widget.domNode && widget.resize;
+ });
+
+ if(
+ // all child nodes are widgets
+ childNodes.length == childWidgetNodes.length &&
+
+ // all but one are invisible (like dojo.data)
+ candidateWidgets.length == 1
+ ){
+ this._singleChild = candidateWidgets[0];
+ }else{
+ delete this._singleChild;
+ }
+
+ // So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449)
+ dojo.toggleClass(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild);
+ },
+
+ setHref: function(/*String|Uri*/ href){
+ // summary:
+ // Deprecated. Use set('href', ...) instead.
+ dojo.deprecated("dijit.layout.ContentPane.setHref() is deprecated. Use set('href', ...) instead.", "", "2.0");
+ return this.set("href", href);
+ },
+ _setHrefAttr: function(/*String|Uri*/ href){
+ // summary:
+ // Hook so attr("href", ...) works.
+ // description:
+ // Reset the (external defined) content of this pane and replace with new url
+ // Note: It delays the download until widget is shown if preload is false.
+ // href:
+ // url to the page you want to get, must be within the same domain as your mainpage
+
+ // Cancel any in-flight requests (an attr('href') will cancel any in-flight attr('href', ...))
+ this.cancel();
+
+ this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));
+
+ this.href = href;
+
+ // _setHrefAttr() is called during creation and by the user, after creation.
+ // only in the second case do we actually load the URL; otherwise it's done in startup()
+ if(this._created && (this.preload || this._isShown())){
+ this._load();
+ }else{
+ // Set flag to indicate that href needs to be loaded the next time the
+ // ContentPane is made visible
+ this._hrefChanged = true;
+ }
+
+ return this.onLoadDeferred; // dojo.Deferred
+ },
+
+ setContent: function(/*String|DomNode|Nodelist*/data){
+ // summary:
+ // Deprecated. Use set('content', ...) instead.
+ dojo.deprecated("dijit.layout.ContentPane.setContent() is deprecated. Use set('content', ...) instead.", "", "2.0");
+ this.set("content", data);
+ },
+ _setContentAttr: function(/*String|DomNode|Nodelist*/data){
+ // summary:
+ // Hook to make attr("content", ...) work.
+ // Replaces old content with data content, include style classes from old content
+ // data:
+ // the new Content may be String, DomNode or NodeList
+ //
+ // if data is a NodeList (or an array of nodes) nodes are copied
+ // so you can import nodes from another document implicitly
+
+ // clear href so we can't run refresh and clear content
+ // refresh should only work if we downloaded the content
+ this.href = "";
+
+ // Cancel any in-flight requests (an attr('content') will cancel any in-flight attr('href', ...))
+ this.cancel();
+
+ // Even though user is just setting content directly, still need to define an onLoadDeferred
+ // because the _onLoadHandler() handler is still getting called from setContent()
+ this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));
+
+ this._setContent(data || "");
+
+ this._isDownloaded = false; // mark that content is from a attr('content') not an attr('href')
+
+ return this.onLoadDeferred; // dojo.Deferred
+ },
+ _getContentAttr: function(){
+ // summary:
+ // Hook to make attr("content") work
+ return this.containerNode.innerHTML;
+ },
+
+ cancel: function(){
+ // summary:
+ // Cancels an in-flight download of content
+ if(this._xhrDfd && (this._xhrDfd.fired == -1)){
+ this._xhrDfd.cancel();
+ }
+ delete this._xhrDfd; // garbage collect
+
+ this.onLoadDeferred = null;
+ },
+
+ uninitialize: function(){
+ if(this._beingDestroyed){
+ this.cancel();
+ }
+ this.inherited(arguments);
+ },
+
+ destroyRecursive: function(/*Boolean*/ preserveDom){
+ // summary:
+ // Destroy the ContentPane and its contents
+
+ // if we have multiple controllers destroying us, bail after the first
+ if(this._beingDestroyed){
+ return;
+ }
+ this.inherited(arguments);
+ },
+
+ resize: function(changeSize, resultSize){
+ // summary:
+ // See `dijit.layout._LayoutWidget.resize` for description.
+ // Although ContentPane doesn't extend _LayoutWidget, it does implement
+ // the same API.
+
+ // For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is
+ // never called, so resize() is our trigger to do the initial href download.
+ if(!this._wasShown){
+ this._onShow();
+ }
+
+ this._resizeCalled = true;
+
+ // Set margin box size, unless it wasn't specified, in which case use current size.
+ if(changeSize){
+ dojo.marginBox(this.domNode, changeSize);
+ }
+
+ // Compute content box size of containerNode in case we [later] need to size our single child.
+ var cn = this.containerNode;
+ if(cn === this.domNode){
+ // If changeSize or resultSize was passed to this method and this.containerNode ==
+ // this.domNode then we can compute the content-box size without querying the node,
+ // which is more reliable (similar to LayoutWidget.resize) (see for example #9449).
+ var mb = resultSize || {};
+ dojo.mixin(mb, changeSize || {}); // changeSize overrides resultSize
+ if(!("h" in mb) || !("w" in mb)){
+ mb = dojo.mixin(dojo.marginBox(cn), mb); // just use dojo.marginBox() to fill in missing values
+ }
+ this._contentBox = dijit.layout.marginBox2contentBox(cn, mb);
+ }else{
+ this._contentBox = dojo.contentBox(cn);
+ }
+
+ // Make my children layout, or size my single child widget
+ this._layoutChildren();
+ },
+
+ _isShown: function(){
+ // summary:
+ // Returns true if the content is currently shown.
+ // description:
+ // If I am a child of a layout widget then it actually returns true if I've ever been visible,
+ // not whether I'm currently visible, since that's much faster than tracing up the DOM/widget
+ // tree every call, and at least solves the performance problem on page load by deferring loading
+ // hidden ContentPanes until they are first shown
+
+ if(this._childOfLayoutWidget){
+ // If we are TitlePane, etc - we return that only *IF* we've been resized
+ if(this._resizeCalled && "open" in this){
+ return this.open;
+ }
+ return this._resizeCalled;
+ }else if("open" in this){
+ return this.open; // for TitlePane, etc.
+ }else{
+ // TODO: with _childOfLayoutWidget check maybe this branch no longer necessary?
+ var node = this.domNode;
+ return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !dojo.hasClass(node, "dijitHidden");
+ }
+ },
+
+ _onShow: function(){
+ // summary:
+ // Called when the ContentPane is made visible
+ // description:
+ // For a plain ContentPane, this is called on initialization, from startup().
+ // If the ContentPane is a hidden pane of a TabContainer etc., then it's
+ // called whenever the pane is made visible.
+ //
+ // Does necessary processing, including href download and layout/resize of
+ // child widget(s)
+
+ if(this.href){
+ if(!this._xhrDfd && // if there's an href that isn't already being loaded
+ (!this.isLoaded || this._hrefChanged || this.refreshOnShow)
+ ){
+ this.refresh();
+ }
+ }else{
+ // If we are the child of a layout widget then the layout widget will call resize() on
+ // us, and then we will size our child/children. Otherwise, we need to do it now.
+ if(!this._childOfLayoutWidget && this._needLayout){
+ // If a layout has been scheduled for when we become visible, do it now
+ this._layoutChildren();
+ }
+ }
+
+ this.inherited(arguments);
+
+ // Need to keep track of whether ContentPane has been shown (which is different than
+ // whether or not it's currently visible).
+ this._wasShown = true;
+ },
+
+ refresh: function(){
+ // summary:
+ // [Re]download contents of href and display
+ // description:
+ // 1. cancels any currently in-flight requests
+ // 2. posts "loading..." message
+ // 3. sends XHR to download new data
+
+ // Cancel possible prior in-flight request
+ this.cancel();
+
+ this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));
+ this._load();
+ return this.onLoadDeferred;
+ },
+
+ _load: function(){
+ // summary:
+ // Load/reload the href specified in this.href
+
+ // display loading message
+ this._setContent(this.onDownloadStart(), true);
+
+ var self = this;
+ var getArgs = {
+ preventCache: (this.preventCache || this.refreshOnShow),
+ url: this.href,
+ handleAs: "text"
+ };
+ if(dojo.isObject(this.ioArgs)){
+ dojo.mixin(getArgs, this.ioArgs);
+ }
+
+ var hand = (this._xhrDfd = (this.ioMethod || dojo.xhrGet)(getArgs));
+
+ hand.addCallback(function(html){
+ try{
+ self._isDownloaded = true;
+ self._setContent(html, false);
+ self.onDownloadEnd();
+ }catch(err){
+ self._onError('Content', err); // onContentError
+ }
+ delete self._xhrDfd;
+ return html;
+ });
+
+ hand.addErrback(function(err){
+ if(!hand.canceled){
+ // show error message in the pane
+ self._onError('Download', err); // onDownloadError
+ }
+ delete self._xhrDfd;
+ return err;
+ });
+
+ // Remove flag saying that a load is needed
+ delete this._hrefChanged;
+ },
+
+ _onLoadHandler: function(data){
+ // summary:
+ // This is called whenever new content is being loaded
+ this.isLoaded = true;
+ try{
+ this.onLoadDeferred.callback(data);
+ this.onLoad(data);
+ }catch(e){
+ console.error('Error '+this.widgetId+' running custom onLoad code: ' + e.message);
+ }
+ },
+
+ _onUnloadHandler: function(){
+ // summary:
+ // This is called whenever the content is being unloaded
+ this.isLoaded = false;
+ try{
+ this.onUnload();
+ }catch(e){
+ console.error('Error '+this.widgetId+' running custom onUnload code: ' + e.message);
+ }
+ },
+
+ destroyDescendants: function(){
+ // summary:
+ // Destroy all the widgets inside the ContentPane and empty containerNode
+
+ // Make sure we call onUnload (but only when the ContentPane has real content)
+ if(this.isLoaded){
+ this._onUnloadHandler();
+ }
+
+ // Even if this.isLoaded == false there might still be a "Loading..." message
+ // to erase, so continue...
+
+ // For historical reasons we need to delete all widgets under this.containerNode,
+ // even ones that the user has created manually.
+ var setter = this._contentSetter;
+ dojo.forEach(this.getChildren(), function(widget){
+ if(widget.destroyRecursive){
+ widget.destroyRecursive();
+ }
+ });
+ if(setter){
+ // Most of the widgets in setter.parseResults have already been destroyed, but
+ // things like Menu that have been moved to <body> haven't yet
+ dojo.forEach(setter.parseResults, function(widget){
+ if(widget.destroyRecursive && widget.domNode && widget.domNode.parentNode == dojo.body()){
+ widget.destroyRecursive();
+ }
+ });
+ delete setter.parseResults;
+ }
+
+ // And then clear away all the DOM nodes
+ dojo.html._emptyNode(this.containerNode);
+
+ // Delete any state information we have about current contents
+ delete this._singleChild;
+ },
+
+ _setContent: function(cont, isFakeContent){
+ // summary:
+ // Insert the content into the container node
+
+ // first get rid of child widgets
+ this.destroyDescendants();
+
+ // dojo.html.set will take care of the rest of the details
+ // we provide an override for the error handling to ensure the widget gets the errors
+ // configure the setter instance with only the relevant widget instance properties
+ // NOTE: unless we hook into attr, or provide property setters for each property,
+ // we need to re-configure the ContentSetter with each use
+ var setter = this._contentSetter;
+ if(! (setter && setter instanceof dojo.html._ContentSetter)){
+ setter = this._contentSetter = new dojo.html._ContentSetter({
+ node: this.containerNode,
+ _onError: dojo.hitch(this, this._onError),
+ onContentError: dojo.hitch(this, function(e){
+ // fires if a domfault occurs when we are appending this.errorMessage
+ // like for instance if domNode is a UL and we try append a DIV
+ var errMess = this.onContentError(e);
+ try{
+ this.containerNode.innerHTML = errMess;
+ }catch(e){
+ console.error('Fatal '+this.id+' could not change content due to '+e.message, e);
+ }
+ })/*,
+ _onError */
+ });
+ };
+
+ var setterParams = dojo.mixin({
+ cleanContent: this.cleanContent,
+ extractContent: this.extractContent,
+ parseContent: this.parseOnLoad,
+ dir: this.dir,
+ lang: this.lang
+ }, this._contentSetterParams || {});
+
+ dojo.mixin(setter, setterParams);
+
+ setter.set( (dojo.isObject(cont) && cont.domNode) ? cont.domNode : cont );
+
+ // setter params must be pulled afresh from the ContentPane each time
+ delete this._contentSetterParams;
+
+ if(!isFakeContent){
+ // Startup each top level child widget (and they will start their children, recursively)
+ dojo.forEach(this.getChildren(), function(child){
+ // The parser has already called startup on all widgets *without* a getParent() method
+ if(!this.parseOnLoad || child.getParent){
+ child.startup();
+ }
+ }, this);
+
+ // Call resize() on each of my child layout widgets,
+ // or resize() on my single child layout widget...
+ // either now (if I'm currently visible)
+ // or when I become visible
+ this._scheduleLayout();
+
+ this._onLoadHandler(cont);
+ }
+ },
+
+ _onError: function(type, err, consoleText){
+ this.onLoadDeferred.errback(err);
+
+ // shows user the string that is returned by on[type]Error
+ // overide on[type]Error and return your own string to customize
+ var errText = this['on' + type + 'Error'].call(this, err);
+ if(consoleText){
+ console.error(consoleText, err);
+ }else if(errText){// a empty string won't change current content
+ this._setContent(errText, true);
+ }
+ },
+
+ _scheduleLayout: function(){
+ // summary:
+ // Call resize() on each of my child layout widgets, either now
+ // (if I'm currently visible) or when I become visible
+ if(this._isShown()){
+ this._layoutChildren();
+ }else{
+ this._needLayout = true;
+ }
+ },
+
+ _layoutChildren: function(){
+ // summary:
+ // Since I am a Container widget, each of my children expects me to
+ // call resize() or layout() on them.
+ // description:
+ // Should be called on initialization and also whenever we get new content
+ // (from an href, or from attr('content', ...))... but deferred until
+ // the ContentPane is visible
+
+ if(this.doLayout){
+ this._checkIfSingleChild();
+ }
+
+ if(this._singleChild && this._singleChild.resize){
+ var cb = this._contentBox || dojo.contentBox(this.containerNode);
+
+ // note: if widget has padding this._contentBox will have l and t set,
+ // but don't pass them to resize() or it will doubly-offset the child
+ this._singleChild.resize({w: cb.w, h: cb.h});
+ }else{
+ // All my child widgets are independently sized (rather than matching my size),
+ // but I still need to call resize() on each child to make it layout.
+ dojo.forEach(this.getChildren(), function(widget){
+ if(widget.resize){
+ widget.resize();
+ }
+ });
+ }
+ delete this._needLayout;
+ },
+
+ // EVENT's, should be overide-able
+ onLoad: function(data){
+ // summary:
+ // Event hook, is called after everything is loaded and widgetified
+ // tags:
+ // callback
+ },
+
+ onUnload: function(){
+ // summary:
+ // Event hook, is called before old content is cleared
+ // tags:
+ // callback
+ },
+
+ onDownloadStart: function(){
+ // summary:
+ // Called before download starts.
+ // description:
+ // The string returned by this function will be the html
+ // that tells the user we are loading something.
+ // Override with your own function if you want to change text.
+ // tags:
+ // extension
+ return this.loadingMessage;
+ },
+
+ onContentError: function(/*Error*/ error){
+ // summary:
+ // Called on DOM faults, require faults etc. in content.
+ //
+ // In order to display an error message in the pane, return
+ // the error message from this method, as an HTML string.
+ //
+ // By default (if this method is not overriden), it returns
+ // nothing, so the error message is just printed to the console.
+ // tags:
+ // extension
+ },
+
+ onDownloadError: function(/*Error*/ error){
+ // summary:
+ // Called when download error occurs.
+ //
+ // In order to display an error message in the pane, return
+ // the error message from this method, as an HTML string.
+ //
+ // Default behavior (if this method is not overriden) is to display
+ // the error message inside the pane.
+ // tags:
+ // extension
+ return this.errorMessage;
+ },
+
+ onDownloadEnd: function(){
+ // summary:
+ // Called when download is finished.
+ // tags:
+ // callback
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.TooltipDialog"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.TooltipDialog"] = true;
+dojo.provide("dijit.TooltipDialog");
+
+
+
+
+
+
+dojo.declare(
+ "dijit.TooltipDialog",
+ [dijit.layout.ContentPane, dijit._Templated, dijit.form._FormMixin, dijit._DialogMixin],
+ {
+ // summary:
+ // Pops up a dialog that appears like a Tooltip
+
+ // title: String
+ // Description of tooltip dialog (required for a11y)
+ title: "",
+
+ // doLayout: [protected] Boolean
+ // Don't change this parameter from the default value.
+ // This ContentPane parameter doesn't make sense for TooltipDialog, since TooltipDialog
+ // is never a child of a layout container, nor can you specify the size of
+ // TooltipDialog in order to control the size of an inner widget.
+ doLayout: false,
+
+ // autofocus: Boolean
+ // A Toggle to modify the default focus behavior of a Dialog, which
+ // is to focus on the first dialog element after opening the dialog.
+ // False will disable autofocusing. Default: true
+ autofocus: true,
+
+ // baseClass: [protected] String
+ // The root className to use for the various states of this widget
+ baseClass: "dijitTooltipDialog",
+
+ // _firstFocusItem: [private] [readonly] DomNode
+ // The pointer to the first focusable node in the dialog.
+ // Set by `dijit._DialogMixin._getFocusItems`.
+ _firstFocusItem: null,
+
+ // _lastFocusItem: [private] [readonly] DomNode
+ // The pointer to which node has focus prior to our dialog.
+ // Set by `dijit._DialogMixin._getFocusItems`.
+ _lastFocusItem: null,
+
+ templateString: dojo.cache("dijit", "templates/TooltipDialog.html", "<div waiRole=\"presentation\">\n\t<div class=\"dijitTooltipContainer\" waiRole=\"presentation\">\n\t\t<div class =\"dijitTooltipContents dijitTooltipFocusNode\" dojoAttachPoint=\"containerNode\" tabindex=\"-1\" waiRole=\"dialog\"></div>\n\t</div>\n\t<div class=\"dijitTooltipConnector\" waiRole=\"presentation\"></div>\n</div>\n"),
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.connect(this.containerNode, "onkeypress", "_onKey");
+ this.containerNode.title = this.title;
+ },
+
+ orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ corner){
+ // summary:
+ // Configure widget to be displayed in given position relative to the button.
+ // This is called from the dijit.popup code, and should not be called
+ // directly.
+ // tags:
+ // protected
+ var c = this._currentOrientClass;
+ if(c){
+ dojo.removeClass(this.domNode, c);
+ }
+ c = "dijitTooltipAB"+(corner.charAt(1) == 'L'?"Left":"Right")+" dijitTooltip"+(corner.charAt(0) == 'T' ? "Below" : "Above");
+ dojo.addClass(this.domNode, c);
+ this._currentOrientClass = c;
+ },
+
+ onOpen: function(/*Object*/ pos){
+ // summary:
+ // Called when dialog is displayed.
+ // This is called from the dijit.popup code, and should not be called directly.
+ // tags:
+ // protected
+
+ this.orient(this.domNode,pos.aroundCorner, pos.corner);
+ this._onShow(); // lazy load trigger
+
+ if(this.autofocus){
+ this._getFocusItems(this.containerNode);
+ dijit.focus(this._firstFocusItem);
+ }
+ },
+
+ onClose: function(){
+ // summary:
+ // Called when dialog is hidden.
+ // This is called from the dijit.popup code, and should not be called directly.
+ // tags:
+ // protected
+ this.onHide();
+ },
+
+ _onKey: function(/*Event*/ evt){
+ // summary:
+ // Handler for keyboard events
+ // description:
+ // Keep keyboard focus in dialog; close dialog on escape key
+ // tags:
+ // private
+
+ var node = evt.target;
+ var dk = dojo.keys;
+ if(evt.charOrCode === dk.TAB){
+ this._getFocusItems(this.containerNode);
+ }
+ var singleFocusItem = (this._firstFocusItem == this._lastFocusItem);
+ if(evt.charOrCode == dk.ESCAPE){
+ // Use setTimeout to avoid crash on IE, see #10396.
+ setTimeout(dojo.hitch(this, "onCancel"), 0);
+ dojo.stopEvent(evt);
+ }else if(node == this._firstFocusItem && evt.shiftKey && evt.charOrCode === dk.TAB){
+ if(!singleFocusItem){
+ dijit.focus(this._lastFocusItem); // send focus to last item in dialog
+ }
+ dojo.stopEvent(evt);
+ }else if(node == this._lastFocusItem && evt.charOrCode === dk.TAB && !evt.shiftKey){
+ if(!singleFocusItem){
+ dijit.focus(this._firstFocusItem); // send focus to first item in dialog
+ }
+ dojo.stopEvent(evt);
+ }else if(evt.charOrCode === dk.TAB){
+ // we want the browser's default tab handling to move focus
+ // but we don't want the tab to propagate upwards
+ evt.stopPropagation();
+ }
+ }
+ }
+ );
+
+}
+
+if(!dojo._hasResource["dijit.Dialog"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.Dialog"] = true;
+dojo.provide("dijit.Dialog");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*=====
+dijit._underlay = function(kwArgs){
+ // summary:
+ // A shared instance of a `dijit.DialogUnderlay`
+ //
+ // description:
+ // A shared instance of a `dijit.DialogUnderlay` created and
+ // used by `dijit.Dialog`, though never created until some Dialog
+ // or subclass thereof is shown.
+};
+=====*/
+
+dojo.declare(
+ "dijit._DialogBase",
+ [dijit._Templated, dijit.form._FormMixin, dijit._DialogMixin, dijit._CssStateMixin],
+ {
+ // summary:
+ // A modal dialog Widget
+ //
+ // description:
+ // Pops up a modal dialog window, blocking access to the screen
+ // and also graying out the screen Dialog is extended from
+ // ContentPane so it supports all the same parameters (href, etc.)
+ //
+ // example:
+ // | <div dojoType="dijit.Dialog" href="test.html"></div>
+ //
+ // example:
+ // | var foo = new dijit.Dialog({ title: "test dialog", content: "test content" };
+ // | dojo.body().appendChild(foo.domNode);
+ // | foo.startup();
+
+ templateString: dojo.cache("dijit", "templates/Dialog.html", "<div class=\"dijitDialog\" tabindex=\"-1\" waiRole=\"dialog\" waiState=\"labelledby-${id}_title\">\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\">\n\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\"></span>\n\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" dojoAttachEvent=\"onclick: onCancel\" title=\"${buttonCancel}\">\n\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\n\t</span>\n\t</div>\n\t\t<div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\n</div>\n"),
+
+ baseClass: "dijitDialog",
+
+ cssStateNodes: {
+ closeButtonNode: "dijitDialogCloseIcon"
+ },
+
+ attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+ title: [
+ { node: "titleNode", type: "innerHTML" },
+ { node: "titleBar", type: "attribute" }
+ ],
+ "aria-describedby":""
+ }),
+
+ // open: Boolean
+ // True if Dialog is currently displayed on screen.
+ open: false,
+
+ // duration: Integer
+ // The time in milliseconds it takes the dialog to fade in and out
+ duration: dijit.defaultDuration,
+
+ // refocus: Boolean
+ // A Toggle to modify the default focus behavior of a Dialog, which
+ // is to re-focus the element which had focus before being opened.
+ // False will disable refocusing. Default: true
+ refocus: true,
+
+ // autofocus: Boolean
+ // A Toggle to modify the default focus behavior of a Dialog, which
+ // is to focus on the first dialog element after opening the dialog.
+ // False will disable autofocusing. Default: true
+ autofocus: true,
+
+ // _firstFocusItem: [private] [readonly] DomNode
+ // The pointer to the first focusable node in the dialog.
+ // Set by `dijit._DialogMixin._getFocusItems`.
+ _firstFocusItem: null,
+
+ // _lastFocusItem: [private] [readonly] DomNode
+ // The pointer to which node has focus prior to our dialog.
+ // Set by `dijit._DialogMixin._getFocusItems`.
+ _lastFocusItem: null,
+
+ // doLayout: [protected] Boolean
+ // Don't change this parameter from the default value.
+ // This ContentPane parameter doesn't make sense for Dialog, since Dialog
+ // is never a child of a layout container, nor can you specify the size of
+ // Dialog in order to control the size of an inner widget.
+ doLayout: false,
+
+ // draggable: Boolean
+ // Toggles the moveable aspect of the Dialog. If true, Dialog
+ // can be dragged by it's title. If false it will remain centered
+ // in the viewport.
+ draggable: true,
+
+ //aria-describedby: String
+ // Allows the user to add an aria-describedby attribute onto the dialog. The value should
+ // be the id of the container element of text that describes the dialog purpose (usually
+ // the first text in the dialog).
+ // <div dojoType="dijit.Dialog" aria-describedby="intro" .....>
+ // <div id="intro">Introductory text</div>
+ // <div>rest of dialog contents</div>
+ // </div>
+ "aria-describedby":"",
+
+ postMixInProperties: function(){
+ var _nlsResources = dojo.i18n.getLocalization("dijit", "common");
+ dojo.mixin(this, _nlsResources);
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ dojo.style(this.domNode, {
+ display: "none",
+ position:"absolute"
+ });
+ dojo.body().appendChild(this.domNode);
+
+ this.inherited(arguments);
+
+ this.connect(this, "onExecute", "hide");
+ this.connect(this, "onCancel", "hide");
+ this._modalconnects = [];
+ },
+
+ onLoad: function(){
+ // summary:
+ // Called when data has been loaded from an href.
+ // Unlike most other callbacks, this function can be connected to (via `dojo.connect`)
+ // but should *not* be overriden.
+ // tags:
+ // callback
+
+ // when href is specified we need to reposition the dialog after the data is loaded
+ // and find the focusable elements
+ this._position();
+ if(this.autofocus){
+ this._getFocusItems(this.domNode);
+ dijit.focus(this._firstFocusItem);
+ }
+ this.inherited(arguments);
+ },
+
+ _endDrag: function(e){
+ // summary:
+ // Called after dragging the Dialog. Saves the position of the dialog in the viewport.
+ // tags:
+ // private
+ if(e && e.node && e.node === this.domNode){
+ this._relativePosition = dojo.position(e.node);
+ }
+ },
+
+ _setup: function(){
+ // summary:
+ // Stuff we need to do before showing the Dialog for the first
+ // time (but we defer it until right beforehand, for
+ // performance reasons).
+ // tags:
+ // private
+
+ var node = this.domNode;
+
+ if(this.titleBar && this.draggable){
+ this._moveable = (dojo.isIE == 6) ?
+ new dojo.dnd.TimedMoveable(node, { handle: this.titleBar }) : // prevent overload, see #5285
+ new dojo.dnd.Moveable(node, { handle: this.titleBar, timeout: 0 });
+ dojo.subscribe("/dnd/move/stop",this,"_endDrag");
+ }else{
+ dojo.addClass(node,"dijitDialogFixed");
+ }
+
+ this.underlayAttrs = {
+ dialogId: this.id,
+ "class": dojo.map(this["class"].split(/\s/), function(s){ return s+"_underlay"; }).join(" ")
+ };
+
+ this._fadeIn = dojo.fadeIn({
+ node: node,
+ duration: this.duration,
+ beforeBegin: dojo.hitch(this, function(){
+ var underlay = dijit._underlay;
+ if(!underlay){
+ underlay = dijit._underlay = new dijit.DialogUnderlay(this.underlayAttrs);
+ }else{
+ underlay.set(this.underlayAttrs);
+ }
+
+ var ds = dijit._dialogStack,
+ zIndex = 948 + ds.length*2;
+ if(ds.length == 1){ // first dialog
+ underlay.show();
+ }
+ dojo.style(dijit._underlay.domNode, 'zIndex', zIndex);
+ dojo.style(this.domNode, 'zIndex', zIndex + 1);
+ }),
+ onEnd: dojo.hitch(this, function(){
+ if(this.autofocus){
+ // find focusable Items each time dialog is shown since if dialog contains a widget the
+ // first focusable items can change
+ this._getFocusItems(this.domNode);
+ dijit.focus(this._firstFocusItem);
+ }
+ })
+ });
+
+ this._fadeOut = dojo.fadeOut({
+ node: node,
+ duration: this.duration,
+ onEnd: dojo.hitch(this, function(){
+ node.style.display = "none";
+
+ // Restore the previous dialog in the stack, or if this is the only dialog
+ // then restore to original page
+ var ds = dijit._dialogStack;
+ if(ds.length == 0){
+ dijit._underlay.hide();
+ }else{
+ dojo.style(dijit._underlay.domNode, 'zIndex', 948 + ds.length*2);
+ dijit._underlay.set(ds[ds.length-1].underlayAttrs);
+ }
+
+ // Restore focus to wherever it was before this dialog was displayed
+ if(this.refocus){
+ var focus = this._savedFocus;
+
+ // If we are returning control to a previous dialog but for some reason
+ // that dialog didn't have a focused field, set focus to first focusable item.
+ // This situation could happen if two dialogs appeared at nearly the same time,
+ // since a dialog doesn't set it's focus until the fade-in is finished.
+ if(ds.length > 0){
+ var pd = ds[ds.length-1];
+ if(!dojo.isDescendant(focus.node, pd.domNode)){
+ pd._getFocusItems(pd.domNode);
+ focus = pd._firstFocusItem;
+ }
+ }
+
+ dijit.focus(focus);
+ }
+ })
+ });
+ },
+
+ uninitialize: function(){
+ var wasPlaying = false;
+ if(this._fadeIn && this._fadeIn.status() == "playing"){
+ wasPlaying = true;
+ this._fadeIn.stop();
+ }
+ if(this._fadeOut && this._fadeOut.status() == "playing"){
+ wasPlaying = true;
+ this._fadeOut.stop();
+ }
+
+ // Hide the underlay, unless the underlay widget has already been destroyed
+ // because we are being called during page unload (when all widgets are destroyed)
+ if((this.open || wasPlaying) && !dijit._underlay._destroyed){
+ dijit._underlay.hide();
+ }
+
+ if(this._moveable){
+ this._moveable.destroy();
+ }
+ this.inherited(arguments);
+ },
+
+ _size: function(){
+ // summary:
+ // If necessary, shrink dialog contents so dialog fits in viewport
+ // tags:
+ // private
+
+ this._checkIfSingleChild();
+
+ // If we resized the dialog contents earlier, reset them back to original size, so
+ // that if the user later increases the viewport size, the dialog can display w/out a scrollbar.
+ // Need to do this before the dojo.marginBox(this.domNode) call below.
+ if(this._singleChild){
+ if(this._singleChildOriginalStyle){
+ this._singleChild.domNode.style.cssText = this._singleChildOriginalStyle;
+ }
+ delete this._singleChildOriginalStyle;
+ }else{
+ dojo.style(this.containerNode, {
+ width:"auto",
+ height:"auto"
+ });
+ }
+
+ var mb = dojo.marginBox(this.domNode);
+ var viewport = dojo.window.getBox();
+ if(mb.w >= viewport.w || mb.h >= viewport.h){
+ // Reduce size of dialog contents so that dialog fits in viewport
+
+ var w = Math.min(mb.w, Math.floor(viewport.w * 0.75)),
+ h = Math.min(mb.h, Math.floor(viewport.h * 0.75));
+
+ if(this._singleChild && this._singleChild.resize){
+ this._singleChildOriginalStyle = this._singleChild.domNode.style.cssText;
+ this._singleChild.resize({w: w, h: h});
+ }else{
+ dojo.style(this.containerNode, {
+ width: w + "px",
+ height: h + "px",
+ overflow: "auto",
+ position: "relative" // workaround IE bug moving scrollbar or dragging dialog
+ });
+ }
+ }else{
+ if(this._singleChild && this._singleChild.resize){
+ this._singleChild.resize();
+ }
+ }
+ },
+
+ _position: function(){
+ // summary:
+ // Position modal dialog in the viewport. If no relative offset
+ // in the viewport has been determined (by dragging, for instance),
+ // center the node. Otherwise, use the Dialog's stored relative offset,
+ // and position the node to top: left: values based on the viewport.
+ // tags:
+ // private
+ if(!dojo.hasClass(dojo.body(),"dojoMove")){
+ var node = this.domNode,
+ viewport = dojo.window.getBox(),
+ p = this._relativePosition,
+ bb = p ? null : dojo._getBorderBox(node),
+ l = Math.floor(viewport.l + (p ? p.x : (viewport.w - bb.w) / 2)),
+ t = Math.floor(viewport.t + (p ? p.y : (viewport.h - bb.h) / 2))
+ ;
+ dojo.style(node,{
+ left: l + "px",
+ top: t + "px"
+ });
+ }
+ },
+
+ _onKey: function(/*Event*/ evt){
+ // summary:
+ // Handles the keyboard events for accessibility reasons
+ // tags:
+ // private
+
+ var ds = dijit._dialogStack;
+ if(ds[ds.length-1] != this){
+ // console.debug(this.id + ': skipping because', this, 'is not the active dialog');
+ return;
+ }
+
+ if(evt.charOrCode){
+ var dk = dojo.keys;
+ var node = evt.target;
+ if(evt.charOrCode === dk.TAB){
+ this._getFocusItems(this.domNode);
+ }
+ var singleFocusItem = (this._firstFocusItem == this._lastFocusItem);
+ // see if we are shift-tabbing from first focusable item on dialog
+ if(node == this._firstFocusItem && evt.shiftKey && evt.charOrCode === dk.TAB){
+ if(!singleFocusItem){
+ dijit.focus(this._lastFocusItem); // send focus to last item in dialog
+ }
+ dojo.stopEvent(evt);
+ }else if(node == this._lastFocusItem && evt.charOrCode === dk.TAB && !evt.shiftKey){
+ if(!singleFocusItem){
+ dijit.focus(this._firstFocusItem); // send focus to first item in dialog
+ }
+ dojo.stopEvent(evt);
+ }else{
+ // see if the key is for the dialog
+ while(node){
+ if(node == this.domNode || dojo.hasClass(node, "dijitPopup")){
+ if(evt.charOrCode == dk.ESCAPE){
+ this.onCancel();
+ }else{
+ return; // just let it go
+ }
+ }
+ node = node.parentNode;
+ }
+ // this key is for the disabled document window
+ if(evt.charOrCode !== dk.TAB){ // allow tabbing into the dialog for a11y
+ dojo.stopEvent(evt);
+ // opera won't tab to a div
+ }else if(!dojo.isOpera){
+ try{
+ this._firstFocusItem.focus();
+ }catch(e){ /*squelch*/ }
+ }
+ }
+ }
+ },
+
+ show: function(){
+ // summary:
+ // Display the dialog
+ if(this.open){ return; }
+
+ // first time we show the dialog, there's some initialization stuff to do
+ if(!this._alreadyInitialized){
+ this._setup();
+ this._alreadyInitialized=true;
+ }
+
+ if(this._fadeOut.status() == "playing"){
+ this._fadeOut.stop();
+ }
+
+ this._modalconnects.push(dojo.connect(window, "onscroll", this, "layout"));
+ this._modalconnects.push(dojo.connect(window, "onresize", this, function(){
+ // IE gives spurious resize events and can actually get stuck
+ // in an infinite loop if we don't ignore them
+ var viewport = dojo.window.getBox();
+ if(!this._oldViewport ||
+ viewport.h != this._oldViewport.h ||
+ viewport.w != this._oldViewport.w){
+ this.layout();
+ this._oldViewport = viewport;
+ }
+ }));
+ this._modalconnects.push(dojo.connect(dojo.doc.documentElement, "onkeypress", this, "_onKey"));
+
+ dojo.style(this.domNode, {
+ opacity:0,
+ display:""
+ });
+
+ this.open = true;
+ this._onShow(); // lazy load trigger
+
+ this._size();
+ this._position();
+ dijit._dialogStack.push(this);
+ this._fadeIn.play();
+
+ this._savedFocus = dijit.getFocus(this);
+ },
+
+ hide: function(){
+ // summary:
+ // Hide the dialog
+
+ // if we haven't been initialized yet then we aren't showing and we can just return
+ // or if we aren't the active dialog, don't allow us to close yet
+ var ds = dijit._dialogStack;
+ if(!this._alreadyInitialized || this != ds[ds.length-1]){
+ return;
+ }
+
+ if(this._fadeIn.status() == "playing"){
+ this._fadeIn.stop();
+ }
+
+ // throw away current active dialog from stack -- making the previous dialog or the node on the original page active
+ ds.pop();
+
+ this._fadeOut.play();
+
+ if(this._scrollConnected){
+ this._scrollConnected = false;
+ }
+ dojo.forEach(this._modalconnects, dojo.disconnect);
+ this._modalconnects = [];
+
+ if(this._relativePosition){
+ delete this._relativePosition;
+ }
+ this.open = false;
+
+ this.onHide();
+ },
+
+ layout: function(){
+ // summary:
+ // Position the Dialog and the underlay
+ // tags:
+ // private
+ if(this.domNode.style.display != "none"){
+ if(dijit._underlay){ // avoid race condition during show()
+ dijit._underlay.layout();
+ }
+ this._position();
+ }
+ },
+
+ destroy: function(){
+ dojo.forEach(this._modalconnects, dojo.disconnect);
+ if(this.refocus && this.open){
+ setTimeout(dojo.hitch(dijit,"focus",this._savedFocus), 25);
+ }
+ this.inherited(arguments);
+ }
+ }
+);
+
+dojo.declare(
+ "dijit.Dialog",
+ [dijit.layout.ContentPane, dijit._DialogBase],
+ {}
+);
+
+// Stack of currenctly displayed dialogs, layered on top of each other
+dijit._dialogStack = [];
+
+// For back-compat. TODO: remove in 2.0
+
+
+}
+
+if(!dojo._hasResource["dijit._HasDropDown"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._HasDropDown"] = true;
+dojo.provide("dijit._HasDropDown");
+
+
+
+
+dojo.declare("dijit._HasDropDown",
+ null,
+ {
+ // summary:
+ // Mixin for widgets that need drop down ability.
+
+ // _buttonNode: [protected] DomNode
+ // The button/icon/node to click to display the drop down.
+ // Can be set via a dojoAttachPoint assignment.
+ // If missing, then either focusNode or domNode (if focusNode is also missing) will be used.
+ _buttonNode: null,
+
+ // _arrowWrapperNode: [protected] DomNode
+ // Will set CSS class dijitUpArrow, dijitDownArrow, dijitRightArrow etc. on this node depending
+ // on where the drop down is set to be positioned.
+ // Can be set via a dojoAttachPoint assignment.
+ // If missing, then _buttonNode will be used.
+ _arrowWrapperNode: null,
+
+ // _popupStateNode: [protected] DomNode
+ // The node to set the popupActive class on.
+ // Can be set via a dojoAttachPoint assignment.
+ // If missing, then focusNode or _buttonNode (if focusNode is missing) will be used.
+ _popupStateNode: null,
+
+ // _aroundNode: [protected] DomNode
+ // The node to display the popup around.
+ // Can be set via a dojoAttachPoint assignment.
+ // If missing, then domNode will be used.
+ _aroundNode: null,
+
+ // dropDown: [protected] Widget
+ // The widget to display as a popup. This widget *must* be
+ // defined before the startup function is called.
+ dropDown: null,
+
+ // autoWidth: [protected] Boolean
+ // Set to true to make the drop down at least as wide as this
+ // widget. Set to false if the drop down should just be its
+ // default width
+ autoWidth: true,
+
+ // forceWidth: [protected] Boolean
+ // Set to true to make the drop down exactly as wide as this
+ // widget. Overrides autoWidth.
+ forceWidth: false,
+
+ // maxHeight: [protected] Integer
+ // The max height for our dropdown. Set to 0 for no max height.
+ // any dropdown taller than this will have scrollbars
+ maxHeight: 0,
+
+ // dropDownPosition: [const] String[]
+ // This variable controls the position of the drop down.
+ // It's an array of strings with the following values:
+ //
+ // * before: places drop down to the left of the target node/widget, or to the right in
+ // the case of RTL scripts like Hebrew and Arabic
+ // * after: places drop down to the right of the target node/widget, or to the left in
+ // the case of RTL scripts like Hebrew and Arabic
+ // * above: drop down goes above target node
+ // * below: drop down goes below target node
+ //
+ // The list is positions is tried, in order, until a position is found where the drop down fits
+ // within the viewport.
+ //
+ dropDownPosition: ["below","above"],
+
+ // _stopClickEvents: Boolean
+ // When set to false, the click events will not be stopped, in
+ // case you want to use them in your subwidget
+ _stopClickEvents: true,
+
+ _onDropDownMouseDown: function(/*Event*/ e){
+ // summary:
+ // Callback when the user mousedown's on the arrow icon
+
+ if(this.disabled || this.readOnly){ return; }
+
+ this._docHandler = this.connect(dojo.doc, "onmouseup", "_onDropDownMouseUp");
+
+ this.toggleDropDown();
+ },
+
+ _onDropDownMouseUp: function(/*Event?*/ e){
+ // summary:
+ // Callback when the user lifts their mouse after mouse down on the arrow icon.
+ // If the drop is a simple menu and the mouse is over the menu, we execute it, otherwise, we focus our
+ // dropDown node. If the event is missing, then we are not
+ // a mouseup event.
+ //
+ // This is useful for the common mouse movement pattern
+ // with native browser <select> nodes:
+ // 1. mouse down on the select node (probably on the arrow)
+ // 2. move mouse to a menu item while holding down the mouse button
+ // 3. mouse up. this selects the menu item as though the user had clicked it.
+ if(e && this._docHandler){
+ this.disconnect(this._docHandler);
+ }
+ var dropDown = this.dropDown, overMenu = false;
+
+ if(e && this._opened){
+ // This code deals with the corner-case when the drop down covers the original widget,
+ // because it's so large. In that case mouse-up shouldn't select a value from the menu.
+ // Find out if our target is somewhere in our dropdown widget,
+ // but not over our _buttonNode (the clickable node)
+ var c = dojo.position(this._buttonNode, true);
+ if(!(e.pageX >= c.x && e.pageX <= c.x + c.w) ||
+ !(e.pageY >= c.y && e.pageY <= c.y + c.h)){
+ var t = e.target;
+ while(t && !overMenu){
+ if(dojo.hasClass(t, "dijitPopup")){
+ overMenu = true;
+ }else{
+ t = t.parentNode;
+ }
+ }
+ if(overMenu){
+ t = e.target;
+ if(dropDown.onItemClick){
+ var menuItem;
+ while(t && !(menuItem = dijit.byNode(t))){
+ t = t.parentNode;
+ }
+ if(menuItem && menuItem.onClick && menuItem.getParent){
+ menuItem.getParent().onItemClick(menuItem, e);
+ }
+ }
+ return;
+ }
+ }
+ }
+ if(this._opened && dropDown.focus){
+ // Focus the dropdown widget - do it on a delay so that we
+ // don't steal our own focus.
+ window.setTimeout(dojo.hitch(dropDown, "focus"), 1);
+ }
+ },
+
+ _onDropDownClick: function(/*Event*/ e){
+ // the drop down was already opened on mousedown/keydown; just need to call stopEvent()
+ if(this._stopClickEvents){
+ dojo.stopEvent(e);
+ }
+ },
+
+ _setupDropdown: function(){
+ // summary:
+ // set up nodes and connect our mouse and keypress events
+ this._buttonNode = this._buttonNode || this.focusNode || this.domNode;
+ this._popupStateNode = this._popupStateNode || this.focusNode || this._buttonNode;
+ this._aroundNode = this._aroundNode || this.domNode;
+ this.connect(this._buttonNode, "onmousedown", "_onDropDownMouseDown");
+ this.connect(this._buttonNode, "onclick", "_onDropDownClick");
+ this.connect(this._buttonNode, "onkeydown", "_onDropDownKeydown");
+ this.connect(this._buttonNode, "onkeyup", "_onKey");
+
+ // If we have a _setStateClass function (which happens when
+ // we are a form widget), then we need to connect our open/close
+ // functions to it
+ if(this._setStateClass){
+ this.connect(this, "openDropDown", "_setStateClass");
+ this.connect(this, "closeDropDown", "_setStateClass");
+ }
+
+ // Add a class to the "dijitDownArrowButton" type class to _buttonNode so theme can set direction of arrow
+ // based on where drop down will normally appear
+ var defaultPos = {
+ "after" : this.isLeftToRight() ? "Right" : "Left",
+ "before" : this.isLeftToRight() ? "Left" : "Right",
+ "above" : "Up",
+ "below" : "Down",
+ "left" : "Left",
+ "right" : "Right"
+ }[this.dropDownPosition[0]] || this.dropDownPosition[0] || "Down";
+ dojo.addClass(this._arrowWrapperNode || this._buttonNode, "dijit" + defaultPos + "ArrowButton");
+ },
+
+ postCreate: function(){
+ this._setupDropdown();
+ this.inherited(arguments);
+ },
+
+ destroyDescendants: function(){
+ if(this.dropDown){
+ // Destroy the drop down, unless it's already been destroyed. This can happen because
+ // the drop down is a direct child of <body> even though it's logically my child.
+ if(!this.dropDown._destroyed){
+ this.dropDown.destroyRecursive();
+ }
+ delete this.dropDown;
+ }
+ this.inherited(arguments);
+ },
+
+ _onDropDownKeydown: function(/*Event*/ e){
+ if(e.keyCode == dojo.keys.DOWN_ARROW || e.keyCode == dojo.keys.ENTER || e.keyCode == dojo.keys.SPACE){
+ e.preventDefault(); // stop IE screen jump
+ }
+ },
+
+ _onKey: function(/*Event*/ e){
+ // summary:
+ // Callback when the user presses a key while focused on the button node
+
+ if(this.disabled || this.readOnly){ return; }
+ var d = this.dropDown;
+ if(d && this._opened && d.handleKey){
+ if(d.handleKey(e) === false){ return; }
+ }
+ if(d && this._opened && e.keyCode == dojo.keys.ESCAPE){
+ this.toggleDropDown();
+ }else if(d && !this._opened &&
+ (e.keyCode == dojo.keys.DOWN_ARROW || e.keyCode == dojo.keys.ENTER || e.keyCode == dojo.keys.SPACE)){
+ this.toggleDropDown();
+ if(d.focus){
+ setTimeout(dojo.hitch(d, "focus"), 1);
+ }
+ }
+ },
+
+ _onBlur: function(){
+ // summary:
+ // Called magically when focus has shifted away from this widget and it's dropdown
+
+ this.closeDropDown();
+ // don't focus on button. the user has explicitly focused on something else.
+ this.inherited(arguments);
+ },
+
+ isLoaded: function(){
+ // summary:
+ // Returns whether or not the dropdown is loaded. This can
+ // be overridden in order to force a call to loadDropDown().
+ // tags:
+ // protected
+
+ return true;
+ },
+
+ loadDropDown: function(/* Function */ loadCallback){
+ // summary:
+ // Loads the data for the dropdown, and at some point, calls
+ // the given callback
+ // tags:
+ // protected
+
+ loadCallback();
+ },
+
+ toggleDropDown: function(){
+ // summary:
+ // Toggle the drop-down widget; if it is up, close it, if not, open it
+ // tags:
+ // protected
+
+ if(this.disabled || this.readOnly){ return; }
+ this.focus();
+ var dropDown = this.dropDown;
+ if(!dropDown){ return; }
+ if(!this._opened){
+ // If we aren't loaded, load it first so there isn't a flicker
+ if(!this.isLoaded()){
+ this.loadDropDown(dojo.hitch(this, "openDropDown"));
+ return;
+ }else{
+ this.openDropDown();
+ }
+ }else{
+ this.closeDropDown();
+ }
+ },
+
+ openDropDown: function(){
+ // summary:
+ // Opens the dropdown for this widget - it returns the
+ // return value of dijit.popup.open
+ // tags:
+ // protected
+
+ var dropDown = this.dropDown;
+ var ddNode = dropDown.domNode;
+ var self = this;
+
+ // Prepare our popup's height and honor maxHeight if it exists.
+
+ // TODO: isn't maxHeight dependent on the return value from dijit.popup.open(),
+ // ie, dependent on how much space is available (BK)
+
+ if(!this._preparedNode){
+ dijit.popup.moveOffScreen(ddNode);
+ this._preparedNode = true;
+ // Check if we have explicitly set width and height on the dropdown widget dom node
+ if(ddNode.style.width){
+ this._explicitDDWidth = true;
+ }
+ if(ddNode.style.height){
+ this._explicitDDHeight = true;
+ }
+ }
+
+ // Code for resizing dropdown (height limitation, or increasing width to match my width)
+ if(this.maxHeight || this.forceWidth || this.autoWidth){
+ var myStyle = {
+ display: "",
+ visibility: "hidden"
+ };
+ if(!this._explicitDDWidth){
+ myStyle.width = "";
+ }
+ if(!this._explicitDDHeight){
+ myStyle.height = "";
+ }
+ dojo.style(ddNode, myStyle);
+
+ // Get size of drop down, and determine if vertical scroll bar needed
+ var mb = dojo.marginBox(ddNode);
+ var overHeight = (this.maxHeight && mb.h > this.maxHeight);
+ dojo.style(ddNode, {
+ overflowX: "hidden",
+ overflowY: overHeight ? "auto" : "hidden"
+ });
+ if(overHeight){
+ mb.h = this.maxHeight;
+ if("w" in mb){
+ mb.w += 16; // room for vertical scrollbar
+ }
+ }else{
+ delete mb.h;
+ }
+ delete mb.t;
+ delete mb.l;
+
+ // Adjust dropdown width to match or be larger than my width
+ if(this.forceWidth){
+ mb.w = this.domNode.offsetWidth;
+ }else if(this.autoWidth){
+ mb.w = Math.max(mb.w, this.domNode.offsetWidth);
+ }else{
+ delete mb.w;
+ }
+
+ // And finally, resize the dropdown to calculated height and width
+ if(dojo.isFunction(dropDown.resize)){
+ dropDown.resize(mb);
+ }else{
+ dojo.marginBox(ddNode, mb);
+ }
+ }
+
+ var retVal = dijit.popup.open({
+ parent: this,
+ popup: dropDown,
+ around: this._aroundNode,
+ orient: dijit.getPopupAroundAlignment((this.dropDownPosition && this.dropDownPosition.length) ? this.dropDownPosition : ["below"],this.isLeftToRight()),
+ onExecute: function(){
+ self.closeDropDown(true);
+ },
+ onCancel: function(){
+ self.closeDropDown(true);
+ },
+ onClose: function(){
+ dojo.attr(self._popupStateNode, "popupActive", false);
+ dojo.removeClass(self._popupStateNode, "dijitHasDropDownOpen");
+ self._opened = false;
+ self.state = "";
+ }
+ });
+ dojo.attr(this._popupStateNode, "popupActive", "true");
+ dojo.addClass(self._popupStateNode, "dijitHasDropDownOpen");
+ this._opened=true;
+ this.state="Opened";
+ // TODO: set this.checked and call setStateClass(), to affect button look while drop down is shown
+ return retVal;
+ },
+
+ closeDropDown: function(/*Boolean*/ focus){
+ // summary:
+ // Closes the drop down on this widget
+ // tags:
+ // protected
+
+ if(this._opened){
+ if(focus){ this.focus(); }
+ dijit.popup.close(this.dropDown);
+ this._opened = false;
+ this.state = "";
+ }
+ }
+
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit.form.Button"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.Button"] = true;
+dojo.provide("dijit.form.Button");
+
+
+
+
+
+dojo.declare("dijit.form.Button",
+ dijit.form._FormWidget,
+ {
+ // summary:
+ // Basically the same thing as a normal HTML button, but with special styling.
+ // description:
+ // Buttons can display a label, an icon, or both.
+ // A label should always be specified (through innerHTML) or the label
+ // attribute. It can be hidden via showLabel=false.
+ // example:
+ // | <button dojoType="dijit.form.Button" onClick="...">Hello world</button>
+ //
+ // example:
+ // | var button1 = new dijit.form.Button({label: "hello world", onClick: foo});
+ // | dojo.body().appendChild(button1.domNode);
+
+ // label: HTML String
+ // Text to display in button.
+ // If the label is hidden (showLabel=false) then and no title has
+ // been specified, then label is also set as title attribute of icon.
+ label: "",
+
+ // showLabel: Boolean
+ // Set this to true to hide the label text and display only the icon.
+ // (If showLabel=false then iconClass must be specified.)
+ // Especially useful for toolbars.
+ // If showLabel=true, the label will become the title (a.k.a. tooltip/hint) of the icon.
+ //
+ // The exception case is for computers in high-contrast mode, where the label
+ // will still be displayed, since the icon doesn't appear.
+ showLabel: true,
+
+ // iconClass: String
+ // Class to apply to DOMNode in button to make it display an icon
+ iconClass: "",
+
+ // type: String
+ // Defines the type of button. "button", "submit", or "reset".
+ type: "button",
+
+ baseClass: "dijitButton",
+
+ templateString: dojo.cache("dijit.form", "templates/Button.html", "<span class=\"dijit dijitReset dijitInline\"\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode,focusNode\"\n\t\t\twaiRole=\"button\" waiState=\"labelledby-${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\"></span\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t\tdojoAttachPoint=\"containerNode\"\n\t\t\t></span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),
+
+ attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
+ value: "valueNode",
+ iconClass: { node: "iconNode", type: "class" }
+ }),
+
+
+ _onClick: function(/*Event*/ e){
+ // summary:
+ // Internal function to handle click actions
+ if(this.disabled){
+ return false;
+ }
+ this._clicked(); // widget click actions
+ return this.onClick(e); // user click actions
+ },
+
+ _onButtonClick: function(/*Event*/ e){
+ // summary:
+ // Handler when the user activates the button portion.
+ if(this._onClick(e) === false){ // returning nothing is same as true
+ e.preventDefault(); // needed for checkbox
+ }else if(this.type == "submit" && !(this.valueNode||this.focusNode).form){ // see if a nonform widget needs to be signalled
+ for(var node=this.domNode; node.parentNode/*#5935*/; node=node.parentNode){
+ var widget=dijit.byNode(node);
+ if(widget && typeof widget._onSubmit == "function"){
+ widget._onSubmit(e);
+ break;
+ }
+ }
+ }else if(this.valueNode){
+ this.valueNode.click();
+ e.preventDefault(); // cancel BUTTON click and continue with hidden INPUT click
+ }
+ },
+
+ _fillContent: function(/*DomNode*/ source){
+ // Overrides _Templated._fillContent().
+ // If button label is specified as srcNodeRef.innerHTML rather than
+ // this.params.label, handle it here.
+ if(source && (!this.params || !("label" in this.params))){
+ this.set('label', source.innerHTML);
+ }
+ },
+
+ postCreate: function(){
+ dojo.setSelectable(this.focusNode, false);
+ this.inherited(arguments);
+ },
+
+ _setShowLabelAttr: function(val){
+ if(this.containerNode){
+ dojo.toggleClass(this.containerNode, "dijitDisplayNone", !val);
+ }
+ this.showLabel = val;
+ },
+
+ onClick: function(/*Event*/ e){
+ // summary:
+ // Callback for when button is clicked.
+ // If type="submit", return true to perform submit, or false to cancel it.
+ // type:
+ // callback
+ return true; // Boolean
+ },
+
+ _clicked: function(/*Event*/ e){
+ // summary:
+ // Internal overridable function for when the button is clicked
+ },
+
+ setLabel: function(/*String*/ content){
+ // summary:
+ // Deprecated. Use set('label', ...) instead.
+ dojo.deprecated("dijit.form.Button.setLabel() is deprecated. Use set('label', ...) instead.", "", "2.0");
+ this.set("label", content);
+ },
+
+ _setLabelAttr: function(/*String*/ content){
+ // summary:
+ // Hook for attr('label', ...) to work.
+ // description:
+ // Set the label (text) of the button; takes an HTML string.
+ this.containerNode.innerHTML = this.label = content;
+ if(this.showLabel == false && !this.params.title){
+ this.titleNode.title = dojo.trim(this.containerNode.innerText || this.containerNode.textContent || '');
+ }
+ }
+});
+
+
+dojo.declare("dijit.form.DropDownButton", [dijit.form.Button, dijit._Container, dijit._HasDropDown], {
+ // summary:
+ // A button with a drop down
+ //
+ // example:
+ // | <button dojoType="dijit.form.DropDownButton" label="Hello world">
+ // | <div dojotype="dijit.Menu">...</div>
+ // | </button>
+ //
+ // example:
+ // | var button1 = new dijit.form.DropDownButton({ label: "hi", dropDown: new dijit.Menu(...) });
+ // | dojo.body().appendChild(button1);
+ //
+
+ baseClass : "dijitDropDownButton",
+
+ templateString: dojo.cache("dijit.form", "templates/DropDownButton.html", "<span class=\"dijit dijitReset dijitInline\"\n\t><span class='dijitReset dijitInline dijitButtonNode'\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\" dojoAttachPoint=\"_buttonNode\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"focusNode,titleNode,_arrowWrapperNode\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true,labelledby-${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\"\n\t\t\t\tdojoAttachPoint=\"iconNode\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tdojoAttachPoint=\"containerNode,_popupStateNode\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonInner\"></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonChar\">&#9660;</span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),
+
+ _fillContent: function(){
+ // Overrides Button._fillContent().
+ //
+ // My inner HTML contains both the button contents and a drop down widget, like
+ // <DropDownButton> <span>push me</span> <Menu> ... </Menu> </DropDownButton>
+ // The first node is assumed to be the button content. The widget is the popup.
+
+ if(this.srcNodeRef){ // programatically created buttons might not define srcNodeRef
+ //FIXME: figure out how to filter out the widget and use all remaining nodes as button
+ // content, not just nodes[0]
+ var nodes = dojo.query("*", this.srcNodeRef);
+ dijit.form.DropDownButton.superclass._fillContent.call(this, nodes[0]);
+
+ // save pointer to srcNode so we can grab the drop down widget after it's instantiated
+ this.dropDownContainer = this.srcNodeRef;
+ }
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+
+ // the child widget from srcNodeRef is the dropdown widget. Insert it in the page DOM,
+ // make it invisible, and store a reference to pass to the popup code.
+ if(!this.dropDown){
+ var dropDownNode = dojo.query("[widgetId]", this.dropDownContainer)[0];
+ this.dropDown = dijit.byNode(dropDownNode);
+ delete this.dropDownContainer;
+ }
+ dijit.popup.moveOffScreen(this.dropDown.domNode);
+
+ this.inherited(arguments);
+ },
+
+ isLoaded: function(){
+ // Returns whether or not we are loaded - if our dropdown has an href,
+ // then we want to check that.
+ var dropDown = this.dropDown;
+ return (!dropDown.href || dropDown.isLoaded);
+ },
+
+ loadDropDown: function(){
+ // Loads our dropdown
+ var dropDown = this.dropDown;
+ if(!dropDown){ return; }
+ if(!this.isLoaded()){
+ var handler = dojo.connect(dropDown, "onLoad", this, function(){
+ dojo.disconnect(handler);
+ this.openDropDown();
+ });
+ dropDown.refresh();
+ }else{
+ this.openDropDown();
+ }
+ },
+
+ isFocusable: function(){
+ // Overridden so that focus is handled by the _HasDropDown mixin, not by
+ // the _FormWidget mixin.
+ return this.inherited(arguments) && !this._mouseDown;
+ }
+});
+
+dojo.declare("dijit.form.ComboButton", dijit.form.DropDownButton, {
+ // summary:
+ // A combination button and drop-down button.
+ // Users can click one side to "press" the button, or click an arrow
+ // icon to display the drop down.
+ //
+ // example:
+ // | <button dojoType="dijit.form.ComboButton" onClick="...">
+ // | <span>Hello world</span>
+ // | <div dojoType="dijit.Menu">...</div>
+ // | </button>
+ //
+ // example:
+ // | var button1 = new dijit.form.ComboButton({label: "hello world", onClick: foo, dropDown: "myMenu"});
+ // | dojo.body().appendChild(button1.domNode);
+ //
+
+ templateString: dojo.cache("dijit.form", "templates/ComboButton.html", "<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tcellspacing='0' cellpadding='0' waiRole=\"presentation\"\n\t><tbody waiRole=\"presentation\"><tr waiRole=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonNode\" dojoAttachPoint=\"buttonNode\" dojoAttachEvent=\"ondijitclick:_onButtonClick,onkeypress:_onButtonKeyPress\"\n\t\t><div id=\"${id}_button\" class=\"dijitReset dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode\"\n\t\t\twaiRole=\"button\" waiState=\"labelledby-${id}_label\"\n\t\t\t><div class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitInline dijitButtonText\" id=\"${id}_label\" dojoAttachPoint=\"containerNode\" waiRole=\"presentation\"></div\n\t\t></div\n\t\t></td\n\t\t><td id=\"${id}_arrow\" class='dijitReset dijitRight dijitButtonNode dijitArrowButton'\n\t\t\tdojoAttachPoint=\"_popupStateNode,focusNode,_buttonNode\"\n\t\t\tdojoAttachEvent=\"onkeypress:_onArrowKeyPress\"\n\t\t\ttitle=\"${optionsTitle}\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" waiRole=\"presentation\">&#9660;</div\n\t\t></td\n\t\t><td style=\"display:none !important;\"\n\t\t\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" dojoAttachPoint=\"valueNode\"\n\t\t/></td></tr></tbody\n></table>\n"),
+
+ attributeMap: dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap), {
+ id: "",
+ tabIndex: ["focusNode", "titleNode"],
+ title: "titleNode"
+ }),
+
+ // optionsTitle: String
+ // Text that describes the options menu (accessibility)
+ optionsTitle: "",
+
+ baseClass: "dijitComboButton",
+
+ // Set classes like dijitButtonContentsHover or dijitArrowButtonActive depending on
+ // mouse action over specified node
+ cssStateNodes: {
+ "buttonNode": "dijitButtonNode",
+ "titleNode": "dijitButtonContents",
+ "_popupStateNode": "dijitDownArrowButton"
+ },
+
+ _focusedNode: null,
+
+ _onButtonKeyPress: function(/*Event*/ evt){
+ // summary:
+ // Handler for right arrow key when focus is on left part of button
+ if(evt.charOrCode == dojo.keys[this.isLeftToRight() ? "RIGHT_ARROW" : "LEFT_ARROW"]){
+ dijit.focus(this._popupStateNode);
+ dojo.stopEvent(evt);
+ }
+ },
+
+ _onArrowKeyPress: function(/*Event*/ evt){
+ // summary:
+ // Handler for left arrow key when focus is on right part of button
+ if(evt.charOrCode == dojo.keys[this.isLeftToRight() ? "LEFT_ARROW" : "RIGHT_ARROW"]){
+ dijit.focus(this.titleNode);
+ dojo.stopEvent(evt);
+ }
+ },
+
+ focus: function(/*String*/ position){
+ // summary:
+ // Focuses this widget to according to position, if specified,
+ // otherwise on arrow node
+ // position:
+ // "start" or "end"
+
+ dijit.focus(position == "start" ? this.titleNode : this._popupStateNode);
+ }
+});
+
+dojo.declare("dijit.form.ToggleButton", dijit.form.Button, {
+ // summary:
+ // A button that can be in two states (checked or not).
+ // Can be base class for things like tabs or checkbox or radio buttons
+
+ baseClass: "dijitToggleButton",
+
+ // checked: Boolean
+ // Corresponds to the native HTML <input> element's attribute.
+ // In markup, specified as "checked='checked'" or just "checked".
+ // True if the button is depressed, or the checkbox is checked,
+ // or the radio button is selected, etc.
+ checked: false,
+
+ attributeMap: dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap), {
+ checked:"focusNode"
+ }),
+
+ _clicked: function(/*Event*/ evt){
+ this.set('checked', !this.checked);
+ },
+
+ _setCheckedAttr: function(/*Boolean*/ value, /* Boolean? */ priorityChange){
+ this.checked = value;
+ dojo.attr(this.focusNode || this.domNode, "checked", value);
+ dijit.setWaiState(this.focusNode || this.domNode, "pressed", value);
+ this._handleOnChange(value, priorityChange);
+ },
+
+ setChecked: function(/*Boolean*/ checked){
+ // summary:
+ // Deprecated. Use set('checked', true/false) instead.
+ dojo.deprecated("setChecked("+checked+") is deprecated. Use set('checked',"+checked+") instead.", "", "2.0");
+ this.set('checked', checked);
+ },
+
+ reset: function(){
+ // summary:
+ // Reset the widget's value to what it was at initialization time
+
+ this._hasBeenBlurred = false;
+
+ // set checked state to original setting
+ this.set('checked', this.params.checked || false);
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.form.ToggleButton"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.ToggleButton"] = true;
+dojo.provide("dijit.form.ToggleButton");
+
+
+}
+
+if(!dojo._hasResource["dijit.form.CheckBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.CheckBox"] = true;
+dojo.provide("dijit.form.CheckBox");
+
+
+
+dojo.declare(
+ "dijit.form.CheckBox",
+ dijit.form.ToggleButton,
+ {
+ // summary:
+ // Same as an HTML checkbox, but with fancy styling.
+ //
+ // description:
+ // User interacts with real html inputs.
+ // On onclick (which occurs by mouse click, space-bar, or
+ // using the arrow keys to switch the selected radio button),
+ // we update the state of the checkbox/radio.
+ //
+ // There are two modes:
+ // 1. High contrast mode
+ // 2. Normal mode
+ //
+ // In case 1, the regular html inputs are shown and used by the user.
+ // In case 2, the regular html inputs are invisible but still used by
+ // the user. They are turned quasi-invisible and overlay the background-image.
+
+ templateString: dojo.cache("dijit.form", "templates/CheckBox.html", "<div class=\"dijit dijitReset dijitInline\" waiRole=\"presentation\"\n\t><input\n\t \t${!nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\n\t\tdojoAttachPoint=\"focusNode\"\n\t \tdojoAttachEvent=\"onclick:_onClick\"\n/></div>\n"),
+
+ baseClass: "dijitCheckBox",
+
+ // type: [private] String
+ // type attribute on <input> node.
+ // Overrides `dijit.form.Button.type`. Users should not change this value.
+ type: "checkbox",
+
+ // value: String
+ // As an initialization parameter, equivalent to value field on normal checkbox
+ // (if checked, the value is passed as the value when form is submitted).
+ //
+ // However, attr('value') will return either the string or false depending on
+ // whether or not the checkbox is checked.
+ //
+ // attr('value', string) will check the checkbox and change the value to the
+ // specified string
+ //
+ // attr('value', boolean) will change the checked state.
+ value: "on",
+
+ // readOnly: Boolean
+ // Should this widget respond to user input?
+ // In markup, this is specified as "readOnly".
+ // Similar to disabled except readOnly form values are submitted.
+ readOnly: false,
+
+ // the attributeMap should inherit from dijit.form._FormWidget.prototype.attributeMap
+ // instead of ToggleButton as the icon mapping has no meaning for a CheckBox
+ attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
+ readOnly: "focusNode"
+ }),
+
+ _setReadOnlyAttr: function(/*Boolean*/ value){
+ this.readOnly = value;
+ dojo.attr(this.focusNode, 'readOnly', value);
+ dijit.setWaiState(this.focusNode, "readonly", value);
+ },
+
+ _setValueAttr: function(/*String or Boolean*/ newValue, /*Boolean*/ priorityChange){
+ // summary:
+ // Handler for value= attribute to constructor, and also calls to
+ // attr('value', val).
+ // description:
+ // During initialization, just saves as attribute to the <input type=checkbox>.
+ //
+ // After initialization,
+ // when passed a boolean, controls whether or not the CheckBox is checked.
+ // If passed a string, changes the value attribute of the CheckBox (the one
+ // specified as "value" when the CheckBox was constructed (ex: <input
+ // dojoType="dijit.CheckBox" value="chicken">)
+ if(typeof newValue == "string"){
+ this.value = newValue;
+ dojo.attr(this.focusNode, 'value', newValue);
+ newValue = true;
+ }
+ if(this._created){
+ this.set('checked', newValue, priorityChange);
+ }
+ },
+ _getValueAttr: function(){
+ // summary:
+ // Hook so attr('value') works.
+ // description:
+ // If the CheckBox is checked, returns the value attribute.
+ // Otherwise returns false.
+ return (this.checked ? this.value : false);
+ },
+
+ // Override dijit.form.Button._setLabelAttr() since we don't even have a containerNode.
+ // Normally users won't try to set label, except when CheckBox or RadioButton is the child of a dojox.layout.TabContainer
+ _setLabelAttr: undefined,
+
+ postMixInProperties: function(){
+ if(this.value == ""){
+ this.value = "on";
+ }
+
+ // Need to set initial checked state as part of template, so that form submit works.
+ // dojo.attr(node, "checked", bool) doesn't work on IEuntil node has been attached
+ // to <body>, see #8666
+ this.checkedAttrSetting = this.checked ? "checked" : "";
+
+ this.inherited(arguments);
+ },
+
+ _fillContent: function(/*DomNode*/ source){
+ // Override Button::_fillContent() since it doesn't make sense for CheckBox,
+ // since CheckBox doesn't even have a container
+ },
+
+ reset: function(){
+ // Override ToggleButton.reset()
+
+ this._hasBeenBlurred = false;
+
+ this.set('checked', this.params.checked || false);
+
+ // Handle unlikely event that the <input type=checkbox> value attribute has changed
+ this.value = this.params.value || "on";
+ dojo.attr(this.focusNode, 'value', this.value);
+ },
+
+ _onFocus: function(){
+ if(this.id){
+ dojo.query("label[for='"+this.id+"']").addClass("dijitFocusedLabel");
+ }
+ this.inherited(arguments);
+ },
+
+ _onBlur: function(){
+ if(this.id){
+ dojo.query("label[for='"+this.id+"']").removeClass("dijitFocusedLabel");
+ }
+ this.inherited(arguments);
+ },
+
+ _onClick: function(/*Event*/ e){
+ // summary:
+ // Internal function to handle click actions - need to check
+ // readOnly, since button no longer does that check.
+ if(this.readOnly){
+ return false;
+ }
+ return this.inherited(arguments);
+ }
+ }
+);
+
+dojo.declare(
+ "dijit.form.RadioButton",
+ dijit.form.CheckBox,
+ {
+ // summary:
+ // Same as an HTML radio, but with fancy styling.
+
+ type: "radio",
+ baseClass: "dijitRadio",
+
+ _setCheckedAttr: function(/*Boolean*/ value){
+ // If I am being checked then have to deselect currently checked radio button
+ this.inherited(arguments);
+ if(!this._created){ return; }
+ if(value){
+ var _this = this;
+ // search for radio buttons with the same name that need to be unchecked
+ dojo.query("INPUT[type=radio]", this.focusNode.form || dojo.doc).forEach( // can't use name= since dojo.query doesn't support [] in the name
+ function(inputNode){
+ if(inputNode.name == _this.name && inputNode != _this.focusNode && inputNode.form == _this.focusNode.form){
+ var widget = dijit.getEnclosingWidget(inputNode);
+ if(widget && widget.checked){
+ widget.set('checked', false);
+ }
+ }
+ }
+ );
+ }
+ },
+
+ _clicked: function(/*Event*/ e){
+ if(!this.checked){
+ this.set('checked', true);
+ }
+ }
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit.form.DropDownButton"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.DropDownButton"] = true;
+dojo.provide("dijit.form.DropDownButton");
+
+
+
+}
+
+if(!dojo._hasResource["dojo.regexp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.regexp"] = true;
+dojo.provide("dojo.regexp");
+
+/*=====
+dojo.regexp = {
+ // summary: Regular expressions and Builder resources
+};
+=====*/
+
+dojo.regexp.escapeString = function(/*String*/str, /*String?*/except){
+ // summary:
+ // Adds escape sequences for special characters in regular expressions
+ // except:
+ // a String with special characters to be left unescaped
+
+ return str.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, function(ch){
+ if(except && except.indexOf(ch) != -1){
+ return ch;
+ }
+ return "\\" + ch;
+ }); // String
+}
+
+dojo.regexp.buildGroupRE = function(/*Object|Array*/arr, /*Function*/re, /*Boolean?*/nonCapture){
+ // summary:
+ // Builds a regular expression that groups subexpressions
+ // description:
+ // A utility function used by some of the RE generators. The
+ // subexpressions are constructed by the function, re, in the second
+ // parameter. re builds one subexpression for each elem in the array
+ // a, in the first parameter. Returns a string for a regular
+ // expression that groups all the subexpressions.
+ // arr:
+ // A single value or an array of values.
+ // re:
+ // A function. Takes one parameter and converts it to a regular
+ // expression.
+ // nonCapture:
+ // If true, uses non-capturing match, otherwise matches are retained
+ // by regular expression. Defaults to false
+
+ // case 1: a is a single value.
+ if(!(arr instanceof Array)){
+ return re(arr); // String
+ }
+
+ // case 2: a is an array
+ var b = [];
+ for(var i = 0; i < arr.length; i++){
+ // convert each elem to a RE
+ b.push(re(arr[i]));
+ }
+
+ // join the REs as alternatives in a RE group.
+ return dojo.regexp.group(b.join("|"), nonCapture); // String
+}
+
+dojo.regexp.group = function(/*String*/expression, /*Boolean?*/nonCapture){
+ // summary:
+ // adds group match to expression
+ // nonCapture:
+ // If true, uses non-capturing match, otherwise matches are retained
+ // by regular expression.
+ return "(" + (nonCapture ? "?:":"") + expression + ")"; // String
+}
+
+}
+
+if(!dojo._hasResource["dojo.data.util.sorter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.util.sorter"] = true;
+dojo.provide("dojo.data.util.sorter");
+
+dojo.data.util.sorter.basicComparator = function( /*anything*/ a,
+ /*anything*/ b){
+ // summary:
+ // Basic comparision function that compares if an item is greater or less than another item
+ // description:
+ // returns 1 if a > b, -1 if a < b, 0 if equal.
+ // 'null' values (null, undefined) are treated as larger values so that they're pushed to the end of the list.
+ // And compared to each other, null is equivalent to undefined.
+
+ //null is a problematic compare, so if null, we set to undefined.
+ //Makes the check logic simple, compact, and consistent
+ //And (null == undefined) === true, so the check later against null
+ //works for undefined and is less bytes.
+ var r = -1;
+ if(a === null){
+ a = undefined;
+ }
+ if(b === null){
+ b = undefined;
+ }
+ if(a == b){
+ r = 0;
+ }else if(a > b || a == null){
+ r = 1;
+ }
+ return r; //int {-1,0,1}
+};
+
+dojo.data.util.sorter.createSortFunction = function( /* attributes array */sortSpec,
+ /*dojo.data.core.Read*/ store){
+ // summary:
+ // Helper function to generate the sorting function based off the list of sort attributes.
+ // description:
+ // The sort function creation will look for a property on the store called 'comparatorMap'. If it exists
+ // it will look in the mapping for comparisons function for the attributes. If one is found, it will
+ // use it instead of the basic comparator, which is typically used for strings, ints, booleans, and dates.
+ // Returns the sorting function for this particular list of attributes and sorting directions.
+ //
+ // sortSpec: array
+ // A JS object that array that defines out what attribute names to sort on and whether it should be descenting or asending.
+ // The objects should be formatted as follows:
+ // {
+ // attribute: "attributeName-string" || attribute,
+ // descending: true|false; // Default is false.
+ // }
+ // store: object
+ // The datastore object to look up item values from.
+ //
+ var sortFunctions=[];
+
+ function createSortFunction(attr, dir, comp, s){
+ //Passing in comp and s (comparator and store), makes this
+ //function much faster.
+ return function(itemA, itemB){
+ var a = s.getValue(itemA, attr);
+ var b = s.getValue(itemB, attr);
+ return dir * comp(a,b); //int
+ };
+ }
+ var sortAttribute;
+ var map = store.comparatorMap;
+ var bc = dojo.data.util.sorter.basicComparator;
+ for(var i = 0; i < sortSpec.length; i++){
+ sortAttribute = sortSpec[i];
+ var attr = sortAttribute.attribute;
+ if(attr){
+ var dir = (sortAttribute.descending) ? -1 : 1;
+ var comp = bc;
+ if(map){
+ if(typeof attr !== "string" && ("toString" in attr)){
+ attr = attr.toString();
+ }
+ comp = map[attr] || bc;
+ }
+ sortFunctions.push(createSortFunction(attr,
+ dir, comp, store));
+ }
+ }
+ return function(rowA, rowB){
+ var i=0;
+ while(i < sortFunctions.length){
+ var ret = sortFunctions[i++](rowA, rowB);
+ if(ret !== 0){
+ return ret;//int
+ }
+ }
+ return 0; //int
+ }; // Function
+};
+
+}
+
+if(!dojo._hasResource["dojo.data.util.simpleFetch"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.util.simpleFetch"] = true;
+dojo.provide("dojo.data.util.simpleFetch");
+
+
+dojo.data.util.simpleFetch.fetch = function(/* Object? */ request){
+ // summary:
+ // The simpleFetch mixin is designed to serve as a set of function(s) that can
+ // be mixed into other datastore implementations to accelerate their development.
+ // The simpleFetch mixin should work well for any datastore that can respond to a _fetchItems()
+ // call by returning an array of all the found items that matched the query. The simpleFetch mixin
+ // is not designed to work for datastores that respond to a fetch() call by incrementally
+ // loading items, or sequentially loading partial batches of the result
+ // set. For datastores that mixin simpleFetch, simpleFetch
+ // implements a fetch method that automatically handles eight of the fetch()
+ // arguments -- onBegin, onItem, onComplete, onError, start, count, sort and scope
+ // The class mixing in simpleFetch should not implement fetch(),
+ // but should instead implement a _fetchItems() method. The _fetchItems()
+ // method takes three arguments, the keywordArgs object that was passed
+ // to fetch(), a callback function to be called when the result array is
+ // available, and an error callback to be called if something goes wrong.
+ // The _fetchItems() method should ignore any keywordArgs parameters for
+ // start, count, onBegin, onItem, onComplete, onError, sort, and scope.
+ // The _fetchItems() method needs to correctly handle any other keywordArgs
+ // parameters, including the query parameter and any optional parameters
+ // (such as includeChildren). The _fetchItems() method should create an array of
+ // result items and pass it to the fetchHandler along with the original request object
+ // -- or, the _fetchItems() method may, if it wants to, create an new request object
+ // with other specifics about the request that are specific to the datastore and pass
+ // that as the request object to the handler.
+ //
+ // For more information on this specific function, see dojo.data.api.Read.fetch()
+ request = request || {};
+ if(!request.store){
+ request.store = this;
+ }
+ var self = this;
+
+ var _errorHandler = function(errorData, requestObject){
+ if(requestObject.onError){
+ var scope = requestObject.scope || dojo.global;
+ requestObject.onError.call(scope, errorData, requestObject);
+ }
+ };
+
+ var _fetchHandler = function(items, requestObject){
+ var oldAbortFunction = requestObject.abort || null;
+ var aborted = false;
+
+ var startIndex = requestObject.start?requestObject.start:0;
+ var endIndex = (requestObject.count && (requestObject.count !== Infinity))?(startIndex + requestObject.count):items.length;
+
+ requestObject.abort = function(){
+ aborted = true;
+ if(oldAbortFunction){
+ oldAbortFunction.call(requestObject);
+ }
+ };
+
+ var scope = requestObject.scope || dojo.global;
+ if(!requestObject.store){
+ requestObject.store = self;
+ }
+ if(requestObject.onBegin){
+ requestObject.onBegin.call(scope, items.length, requestObject);
+ }
+ if(requestObject.sort){
+ items.sort(dojo.data.util.sorter.createSortFunction(requestObject.sort, self));
+ }
+ if(requestObject.onItem){
+ for(var i = startIndex; (i < items.length) && (i < endIndex); ++i){
+ var item = items[i];
+ if(!aborted){
+ requestObject.onItem.call(scope, item, requestObject);
+ }
+ }
+ }
+ if(requestObject.onComplete && !aborted){
+ var subset = null;
+ if(!requestObject.onItem){
+ subset = items.slice(startIndex, endIndex);
+ }
+ requestObject.onComplete.call(scope, subset, requestObject);
+ }
+ };
+ this._fetchItems(request, _fetchHandler, _errorHandler);
+ return request; // Object
+};
+
+}
+
+if(!dojo._hasResource["dojo.data.util.filter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.util.filter"] = true;
+dojo.provide("dojo.data.util.filter");
+
+dojo.data.util.filter.patternToRegExp = function(/*String*/pattern, /*boolean?*/ ignoreCase){
+ // summary:
+ // Helper function to convert a simple pattern to a regular expression for matching.
+ // description:
+ // Returns a regular expression object that conforms to the defined conversion rules.
+ // For example:
+ // ca* -> /^ca.*$/
+ // *ca* -> /^.*ca.*$/
+ // *c\*a* -> /^.*c\*a.*$/
+ // *c\*a?* -> /^.*c\*a..*$/
+ // and so on.
+ //
+ // pattern: string
+ // A simple matching pattern to convert that follows basic rules:
+ // * Means match anything, so ca* means match anything starting with ca
+ // ? Means match single character. So, b?b will match to bob and bab, and so on.
+ // \ is an escape character. So for example, \* means do not treat * as a match, but literal character *.
+ // To use a \ as a character in the string, it must be escaped. So in the pattern it should be
+ // represented by \\ to be treated as an ordinary \ character instead of an escape.
+ //
+ // ignoreCase:
+ // An optional flag to indicate if the pattern matching should be treated as case-sensitive or not when comparing
+ // By default, it is assumed case sensitive.
+
+ var rxp = "^";
+ var c = null;
+ for(var i = 0; i < pattern.length; i++){
+ c = pattern.charAt(i);
+ switch(c){
+ case '\\':
+ rxp += c;
+ i++;
+ rxp += pattern.charAt(i);
+ break;
+ case '*':
+ rxp += ".*"; break;
+ case '?':
+ rxp += "."; break;
+ case '$':
+ case '^':
+ case '/':
+ case '+':
+ case '.':
+ case '|':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ rxp += "\\"; //fallthrough
+ default:
+ rxp += c;
+ }
+ }
+ rxp += "$";
+ if(ignoreCase){
+ return new RegExp(rxp,"mi"); //RegExp
+ }else{
+ return new RegExp(rxp,"m"); //RegExp
+ }
+
+};
+
+}
+
+if(!dojo._hasResource["dijit.form.TextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.TextBox"] = true;
+dojo.provide("dijit.form.TextBox");
+
+
+
+dojo.declare(
+ "dijit.form.TextBox",
+ dijit.form._FormValueWidget,
+ {
+ // summary:
+ // A base class for textbox form inputs
+
+ // trim: Boolean
+ // Removes leading and trailing whitespace if true. Default is false.
+ trim: false,
+
+ // uppercase: Boolean
+ // Converts all characters to uppercase if true. Default is false.
+ uppercase: false,
+
+ // lowercase: Boolean
+ // Converts all characters to lowercase if true. Default is false.
+ lowercase: false,
+
+ // propercase: Boolean
+ // Converts the first character of each word to uppercase if true.
+ propercase: false,
+
+ // maxLength: String
+ // HTML INPUT tag maxLength declaration.
+ maxLength: "",
+
+ // selectOnClick: [const] Boolean
+ // If true, all text will be selected when focused with mouse
+ selectOnClick: false,
+
+ // placeHolder: String
+ // Defines a hint to help users fill out the input field (as defined in HTML 5).
+ // This should only contain plain text (no html markup).
+ placeHolder: "",
+
+ templateString: dojo.cache("dijit.form", "templates/TextBox.html", "<div class=\"dijit dijitReset dijitInline dijitLeft\" id=\"widget_${id}\" waiRole=\"presentation\"\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),
+ _singleNodeTemplate: '<input class="dijit dijitReset dijitLeft dijitInputField" dojoAttachPoint="textbox,focusNode" autocomplete="off" type="${type}" ${!nameAttrSetting} />',
+
+ _buttonInputDisabled: dojo.isIE ? "disabled" : "", // allows IE to disallow focus, but Firefox cannot be disabled for mousedown events
+
+ baseClass: "dijitTextBox",
+
+ attributeMap: dojo.delegate(dijit.form._FormValueWidget.prototype.attributeMap, {
+ maxLength: "focusNode"
+ }),
+
+ postMixInProperties: function(){
+ var type = this.type.toLowerCase();
+ if(this.templateString.toLowerCase() == "input" || ((type == "hidden" || type == "file") && this.templateString == dijit.form.TextBox.prototype.templateString)){
+ this.templateString = this._singleNodeTemplate;
+ }
+ this.inherited(arguments);
+ },
+
+ _setPlaceHolderAttr: function(v){
+ this.placeHolder = v;
+ if(!this._phspan){
+ this._attachPoints.push('_phspan');
+ /* dijitInputField class gives placeHolder same padding as the input field
+ * parent node already has dijitInputField class but it doesn't affect this <span>
+ * since it's position: absolute.
+ */
+ this._phspan = dojo.create('span',{className:'dijitPlaceHolder dijitInputField'},this.textbox,'after');
+ }
+ this._phspan.innerHTML="";
+ this._phspan.appendChild(document.createTextNode(v));
+
+ this._updatePlaceHolder();
+ },
+
+ _updatePlaceHolder: function(){
+ if(this._phspan){
+ this._phspan.style.display=(this.placeHolder&&!this._focused&&!this.textbox.value)?"":"none";
+ }
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // Hook so attr('value') works as we like.
+ // description:
+ // For `dijit.form.TextBox` this basically returns the value of the <input>.
+ //
+ // For `dijit.form.MappedTextBox` subclasses, which have both
+ // a "displayed value" and a separate "submit value",
+ // This treats the "displayed value" as the master value, computing the
+ // submit value from it via this.parse().
+ return this.parse(this.get('displayedValue'), this.constraints);
+ },
+
+ _setValueAttr: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
+ // summary:
+ // Hook so attr('value', ...) works.
+ //
+ // description:
+ // Sets the value of the widget to "value" which can be of
+ // any type as determined by the widget.
+ //
+ // value:
+ // The visual element value is also set to a corresponding,
+ // but not necessarily the same, value.
+ //
+ // formattedValue:
+ // If specified, used to set the visual element value,
+ // otherwise a computed visual value is used.
+ //
+ // priorityChange:
+ // If true, an onChange event is fired immediately instead of
+ // waiting for the next blur event.
+
+ var filteredValue;
+ if(value !== undefined){
+ // TODO: this is calling filter() on both the display value and the actual value.
+ // I added a comment to the filter() definition about this, but it should be changed.
+ filteredValue = this.filter(value);
+ if(typeof formattedValue != "string"){
+ if(filteredValue !== null && ((typeof filteredValue != "number") || !isNaN(filteredValue))){
+ formattedValue = this.filter(this.format(filteredValue, this.constraints));
+ }else{ formattedValue = ''; }
+ }
+ }
+ if(formattedValue != null && formattedValue != undefined && ((typeof formattedValue) != "number" || !isNaN(formattedValue)) && this.textbox.value != formattedValue){
+ this.textbox.value = formattedValue;
+ }
+
+ this._updatePlaceHolder();
+
+ this.inherited(arguments, [filteredValue, priorityChange]);
+ },
+
+ // displayedValue: String
+ // For subclasses like ComboBox where the displayed value
+ // (ex: Kentucky) and the serialized value (ex: KY) are different,
+ // this represents the displayed value.
+ //
+ // Setting 'displayedValue' through attr('displayedValue', ...)
+ // updates 'value', and vice-versa. Otherwise 'value' is updated
+ // from 'displayedValue' periodically, like onBlur etc.
+ //
+ // TODO: move declaration to MappedTextBox?
+ // Problem is that ComboBox references displayedValue,
+ // for benefit of FilteringSelect.
+ displayedValue: "",
+
+ getDisplayedValue: function(){
+ // summary:
+ // Deprecated. Use set('displayedValue') instead.
+ // tags:
+ // deprecated
+ dojo.deprecated(this.declaredClass+"::getDisplayedValue() is deprecated. Use set('displayedValue') instead.", "", "2.0");
+ return this.get('displayedValue');
+ },
+
+ _getDisplayedValueAttr: function(){
+ // summary:
+ // Hook so attr('displayedValue') works.
+ // description:
+ // Returns the displayed value (what the user sees on the screen),
+ // after filtering (ie, trimming spaces etc.).
+ //
+ // For some subclasses of TextBox (like ComboBox), the displayed value
+ // is different from the serialized value that's actually
+ // sent to the server (see dijit.form.ValidationTextBox.serialize)
+
+ return this.filter(this.textbox.value);
+ },
+
+ setDisplayedValue: function(/*String*/value){
+ // summary:
+ // Deprecated. Use set('displayedValue', ...) instead.
+ // tags:
+ // deprecated
+ dojo.deprecated(this.declaredClass+"::setDisplayedValue() is deprecated. Use set('displayedValue', ...) instead.", "", "2.0");
+ this.set('displayedValue', value);
+ },
+
+ _setDisplayedValueAttr: function(/*String*/value){
+ // summary:
+ // Hook so attr('displayedValue', ...) works.
+ // description:
+ // Sets the value of the visual element to the string "value".
+ // The widget value is also set to a corresponding,
+ // but not necessarily the same, value.
+
+ if(value === null || value === undefined){ value = '' }
+ else if(typeof value != "string"){ value = String(value) }
+ this.textbox.value = value;
+ this._setValueAttr(this.get('value'), undefined, value);
+ },
+
+ format: function(/* String */ value, /* Object */ constraints){
+ // summary:
+ // Replacable function to convert a value to a properly formatted string.
+ // tags:
+ // protected extension
+ return ((value == null || value == undefined) ? "" : (value.toString ? value.toString() : value));
+ },
+
+ parse: function(/* String */ value, /* Object */ constraints){
+ // summary:
+ // Replacable function to convert a formatted string to a value
+ // tags:
+ // protected extension
+
+ return value; // String
+ },
+
+ _refreshState: function(){
+ // summary:
+ // After the user types some characters, etc., this method is
+ // called to check the field for validity etc. The base method
+ // in `dijit.form.TextBox` does nothing, but subclasses override.
+ // tags:
+ // protected
+ },
+
+ _onInput: function(e){
+ if(e && e.type && /key/i.test(e.type) && e.keyCode){
+ switch(e.keyCode){
+ case dojo.keys.SHIFT:
+ case dojo.keys.ALT:
+ case dojo.keys.CTRL:
+ case dojo.keys.TAB:
+ return;
+ }
+ }
+ if(this.intermediateChanges){
+ var _this = this;
+ // the setTimeout allows the key to post to the widget input box
+ setTimeout(function(){ _this._handleOnChange(_this.get('value'), false); }, 0);
+ }
+ this._refreshState();
+ },
+
+ postCreate: function(){
+ // setting the value here is needed since value="" in the template causes "undefined"
+ // and setting in the DOM (instead of the JS object) helps with form reset actions
+ if(dojo.isIE){ // IE INPUT tag fontFamily has to be set directly using STYLE
+ var s = dojo.getComputedStyle(this.domNode);
+ if(s){
+ var ff = s.fontFamily;
+ if(ff){
+ var inputs = this.domNode.getElementsByTagName("INPUT");
+ if(inputs){
+ for(var i=0; i < inputs.length; i++){
+ inputs[i].style.fontFamily = ff;
+ }
+ }
+ }
+ }
+ }
+ this.textbox.setAttribute("value", this.textbox.value); // DOM and JS values shuld be the same
+ this.inherited(arguments);
+ if(dojo.isMoz || dojo.isOpera){
+ this.connect(this.textbox, "oninput", this._onInput);
+ }else{
+ this.connect(this.textbox, "onkeydown", this._onInput);
+ this.connect(this.textbox, "onkeyup", this._onInput);
+ this.connect(this.textbox, "onpaste", this._onInput);
+ this.connect(this.textbox, "oncut", this._onInput);
+ }
+ },
+
+ _blankValue: '', // if the textbox is blank, what value should be reported
+ filter: function(val){
+ // summary:
+ // Auto-corrections (such as trimming) that are applied to textbox
+ // value on blur or form submit.
+ // description:
+ // For MappedTextBox subclasses, this is called twice
+ // - once with the display value
+ // - once the value as set/returned by attr('value', ...)
+ // and attr('value'), ex: a Number for NumberTextBox.
+ //
+ // In the latter case it does corrections like converting null to NaN. In
+ // the former case the NumberTextBox.filter() method calls this.inherited()
+ // to execute standard trimming code in TextBox.filter().
+ //
+ // TODO: break this into two methods in 2.0
+ //
+ // tags:
+ // protected extension
+ if(val === null){ return this._blankValue; }
+ if(typeof val != "string"){ return val; }
+ if(this.trim){
+ val = dojo.trim(val);
+ }
+ if(this.uppercase){
+ val = val.toUpperCase();
+ }
+ if(this.lowercase){
+ val = val.toLowerCase();
+ }
+ if(this.propercase){
+ val = val.replace(/[^\s]+/g, function(word){
+ return word.substring(0,1).toUpperCase() + word.substring(1);
+ });
+ }
+ return val;
+ },
+
+ _setBlurValue: function(){
+ this._setValueAttr(this.get('value'), true);
+ },
+
+ _onBlur: function(e){
+ if(this.disabled){ return; }
+ this._setBlurValue();
+ this.inherited(arguments);
+
+ if(this._selectOnClickHandle){
+ this.disconnect(this._selectOnClickHandle);
+ }
+ if(this.selectOnClick && dojo.isMoz){
+ this.textbox.selectionStart = this.textbox.selectionEnd = undefined; // clear selection so that the next mouse click doesn't reselect
+ }
+
+ this._updatePlaceHolder();
+ },
+
+ _onFocus: function(/*String*/ by){
+ if(this.disabled || this.readOnly){ return; }
+
+ // Select all text on focus via click if nothing already selected.
+ // Since mouse-up will clear the selection need to defer selection until after mouse-up.
+ // Don't do anything on focus by tabbing into the widget since there's no associated mouse-up event.
+ if(this.selectOnClick && by == "mouse"){
+ this._selectOnClickHandle = this.connect(this.domNode, "onmouseup", function(){
+ // Only select all text on first click; otherwise users would have no way to clear
+ // the selection.
+ this.disconnect(this._selectOnClickHandle);
+
+ // Check if the user selected some text manually (mouse-down, mouse-move, mouse-up)
+ // and if not, then select all the text
+ var textIsNotSelected;
+ if(dojo.isIE){
+ var range = dojo.doc.selection.createRange();
+ var parent = range.parentElement();
+ textIsNotSelected = parent == this.textbox && range.text.length == 0;
+ }else{
+ textIsNotSelected = this.textbox.selectionStart == this.textbox.selectionEnd;
+ }
+ if(textIsNotSelected){
+ dijit.selectInputText(this.textbox);
+ }
+ });
+ }
+
+ this._updatePlaceHolder();
+
+ this._refreshState();
+ this.inherited(arguments);
+ },
+
+ reset: function(){
+ // Overrides dijit._FormWidget.reset().
+ // Additionally resets the displayed textbox value to ''
+ this.textbox.value = '';
+ this.inherited(arguments);
+ }
+ }
+);
+
+dijit.selectInputText = function(/*DomNode*/element, /*Number?*/ start, /*Number?*/ stop){
+ // summary:
+ // Select text in the input element argument, from start (default 0), to stop (default end).
+
+ // TODO: use functions in _editor/selection.js?
+ var _window = dojo.global;
+ var _document = dojo.doc;
+ element = dojo.byId(element);
+ if(isNaN(start)){ start = 0; }
+ if(isNaN(stop)){ stop = element.value ? element.value.length : 0; }
+ dijit.focus(element);
+ if(_document["selection"] && dojo.body()["createTextRange"]){ // IE
+ if(element.createTextRange){
+ var range = element.createTextRange();
+ with(range){
+ collapse(true);
+ moveStart("character", -99999); // move to 0
+ moveStart("character", start); // delta from 0 is the correct position
+ moveEnd("character", stop-start);
+ select();
+ }
+ }
+ }else if(_window["getSelection"]){
+ if(element.setSelectionRange){
+ element.setSelectionRange(start, stop);
+ }
+ }
+};
+
+}
+
+if(!dojo._hasResource["dijit.Tooltip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.Tooltip"] = true;
+dojo.provide("dijit.Tooltip");
+
+
+
+
+dojo.declare(
+ "dijit._MasterTooltip",
+ [dijit._Widget, dijit._Templated],
+ {
+ // summary:
+ // Internal widget that holds the actual tooltip markup,
+ // which occurs once per page.
+ // Called by Tooltip widgets which are just containers to hold
+ // the markup
+ // tags:
+ // protected
+
+ // duration: Integer
+ // Milliseconds to fade in/fade out
+ duration: dijit.defaultDuration,
+
+ templateString: dojo.cache("dijit", "templates/Tooltip.html", "<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\">\n\t<div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" waiRole='alert'></div>\n\t<div class=\"dijitTooltipConnector\"></div>\n</div>\n"),
+
+ postCreate: function(){
+ dojo.body().appendChild(this.domNode);
+
+ this.bgIframe = new dijit.BackgroundIframe(this.domNode);
+
+ // Setup fade-in and fade-out functions.
+ this.fadeIn = dojo.fadeIn({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onShow") });
+ this.fadeOut = dojo.fadeOut({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onHide") });
+
+ },
+
+ show: function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position, /*Boolean*/ rtl){
+ // summary:
+ // Display tooltip w/specified contents to right of specified node
+ // (To left if there's no space on the right, or if rtl == true)
+
+ if(this.aroundNode && this.aroundNode === aroundNode){
+ return;
+ }
+
+ if(this.fadeOut.status() == "playing"){
+ // previous tooltip is being hidden; wait until the hide completes then show new one
+ this._onDeck=arguments;
+ return;
+ }
+ this.containerNode.innerHTML=innerHTML;
+
+ var pos = dijit.placeOnScreenAroundElement(this.domNode, aroundNode, dijit.getPopupAroundAlignment((position && position.length) ? position : dijit.Tooltip.defaultPosition, !rtl), dojo.hitch(this, "orient"));
+
+ // show it
+ dojo.style(this.domNode, "opacity", 0);
+ this.fadeIn.play();
+ this.isShowingNow = true;
+ this.aroundNode = aroundNode;
+ },
+
+ orient: function(/* DomNode */ node, /* String */ aroundCorner, /* String */ tooltipCorner){
+ // summary:
+ // Private function to set CSS for tooltip node based on which position it's in.
+ // This is called by the dijit popup code.
+ // tags:
+ // protected
+
+ node.className = "dijitTooltip " +
+ {
+ "BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
+ "TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
+ "BR-TR": "dijitTooltipBelow dijitTooltipABRight",
+ "TR-BR": "dijitTooltipAbove dijitTooltipABRight",
+ "BR-BL": "dijitTooltipRight",
+ "BL-BR": "dijitTooltipLeft"
+ }[aroundCorner + "-" + tooltipCorner];
+ },
+
+ _onShow: function(){
+ // summary:
+ // Called at end of fade-in operation
+ // tags:
+ // protected
+ if(dojo.isIE){
+ // the arrow won't show up on a node w/an opacity filter
+ this.domNode.style.filter="";
+ }
+ },
+
+ hide: function(aroundNode){
+ // summary:
+ // Hide the tooltip
+ if(this._onDeck && this._onDeck[1] == aroundNode){
+ // this hide request is for a show() that hasn't even started yet;
+ // just cancel the pending show()
+ this._onDeck=null;
+ }else if(this.aroundNode === aroundNode){
+ // this hide request is for the currently displayed tooltip
+ this.fadeIn.stop();
+ this.isShowingNow = false;
+ this.aroundNode = null;
+ this.fadeOut.play();
+ }else{
+ // just ignore the call, it's for a tooltip that has already been erased
+ }
+ },
+
+ _onHide: function(){
+ // summary:
+ // Called at end of fade-out operation
+ // tags:
+ // protected
+
+ this.domNode.style.cssText=""; // to position offscreen again
+ this.containerNode.innerHTML="";
+ if(this._onDeck){
+ // a show request has been queued up; do it now
+ this.show.apply(this, this._onDeck);
+ this._onDeck=null;
+ }
+ }
+
+ }
+);
+
+dijit.showTooltip = function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position, /*Boolean*/ rtl){
+ // summary:
+ // Display tooltip w/specified contents in specified position.
+ // See description of dijit.Tooltip.defaultPosition for details on position parameter.
+ // If position is not specified then dijit.Tooltip.defaultPosition is used.
+ if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); }
+ return dijit._masterTT.show(innerHTML, aroundNode, position, rtl);
+};
+
+dijit.hideTooltip = function(aroundNode){
+ // summary:
+ // Hide the tooltip
+ if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); }
+ return dijit._masterTT.hide(aroundNode);
+};
+
+dojo.declare(
+ "dijit.Tooltip",
+ dijit._Widget,
+ {
+ // summary:
+ // Pops up a tooltip (a help message) when you hover over a node.
+
+ // label: String
+ // Text to display in the tooltip.
+ // Specified as innerHTML when creating the widget from markup.
+ label: "",
+
+ // showDelay: Integer
+ // Number of milliseconds to wait after hovering over/focusing on the object, before
+ // the tooltip is displayed.
+ showDelay: 400,
+
+ // connectId: [const] String[]
+ // Id's of domNodes to attach the tooltip to.
+ // When user hovers over any of the specified dom nodes, the tooltip will appear.
+ //
+ // Note: Currently connectId can only be specified on initialization, it cannot
+ // be changed via attr('connectId', ...)
+ //
+ // Note: in 2.0 this will be renamed to connectIds for less confusion.
+ connectId: [],
+
+ // position: String[]
+ // See description of `dijit.Tooltip.defaultPosition` for details on position parameter.
+ position: [],
+
+ constructor: function(){
+ // Map id's of nodes I'm connected to to a list of the this.connect() handles
+ this._nodeConnectionsById = {};
+ },
+
+ _setConnectIdAttr: function(newIds){
+ for(var oldId in this._nodeConnectionsById){
+ this.removeTarget(oldId);
+ }
+ dojo.forEach(dojo.isArrayLike(newIds) ? newIds : [newIds], this.addTarget, this);
+ },
+
+ _getConnectIdAttr: function(){
+ var ary = [];
+ for(var id in this._nodeConnectionsById){
+ ary.push(id);
+ }
+ return ary;
+ },
+
+ addTarget: function(/*DOMNODE || String*/ id){
+ // summary:
+ // Attach tooltip to specified node, if it's not already connected
+ var node = dojo.byId(id);
+ if(!node){ return; }
+ if(node.id in this._nodeConnectionsById){ return; }//Already connected
+
+ this._nodeConnectionsById[node.id] = [
+ this.connect(node, "onmouseenter", "_onTargetMouseEnter"),
+ this.connect(node, "onmouseleave", "_onTargetMouseLeave"),
+ this.connect(node, "onfocus", "_onTargetFocus"),
+ this.connect(node, "onblur", "_onTargetBlur")
+ ];
+ },
+
+ removeTarget: function(/*DOMNODE || String*/ node){
+ // summary:
+ // Detach tooltip from specified node
+
+ // map from DOMNode back to plain id string
+ var id = node.id || node;
+
+ if(id in this._nodeConnectionsById){
+ dojo.forEach(this._nodeConnectionsById[id], this.disconnect, this);
+ delete this._nodeConnectionsById[id];
+ }
+ },
+
+ postCreate: function(){
+ dojo.addClass(this.domNode,"dijitTooltipData");
+ },
+
+ startup: function(){
+ this.inherited(arguments);
+
+ // If this tooltip was created in a template, or for some other reason the specified connectId[s]
+ // didn't exist during the widget's initialization, then connect now.
+ var ids = this.connectId;
+ dojo.forEach(dojo.isArrayLike(ids) ? ids : [ids], this.addTarget, this);
+ },
+
+ _onTargetMouseEnter: function(/*Event*/ e){
+ // summary:
+ // Handler for mouseenter event on the target node
+ // tags:
+ // private
+ this._onHover(e);
+ },
+
+ _onTargetMouseLeave: function(/*Event*/ e){
+ // summary:
+ // Handler for mouseleave event on the target node
+ // tags:
+ // private
+ this._onUnHover(e);
+ },
+
+ _onTargetFocus: function(/*Event*/ e){
+ // summary:
+ // Handler for focus event on the target node
+ // tags:
+ // private
+
+ this._focus = true;
+ this._onHover(e);
+ },
+
+ _onTargetBlur: function(/*Event*/ e){
+ // summary:
+ // Handler for blur event on the target node
+ // tags:
+ // private
+
+ this._focus = false;
+ this._onUnHover(e);
+ },
+
+ _onHover: function(/*Event*/ e){
+ // summary:
+ // Despite the name of this method, it actually handles both hover and focus
+ // events on the target node, setting a timer to show the tooltip.
+ // tags:
+ // private
+ if(!this._showTimer){
+ var target = e.target;
+ this._showTimer = setTimeout(dojo.hitch(this, function(){this.open(target)}), this.showDelay);
+ }
+ },
+
+ _onUnHover: function(/*Event*/ e){
+ // summary:
+ // Despite the name of this method, it actually handles both mouseleave and blur
+ // events on the target node, hiding the tooltip.
+ // tags:
+ // private
+
+ // keep a tooltip open if the associated element still has focus (even though the
+ // mouse moved away)
+ if(this._focus){ return; }
+
+ if(this._showTimer){
+ clearTimeout(this._showTimer);
+ delete this._showTimer;
+ }
+ this.close();
+ },
+
+ open: function(/*DomNode*/ target){
+ // summary:
+ // Display the tooltip; usually not called directly.
+ // tags:
+ // private
+
+ if(this._showTimer){
+ clearTimeout(this._showTimer);
+ delete this._showTimer;
+ }
+ dijit.showTooltip(this.label || this.domNode.innerHTML, target, this.position, !this.isLeftToRight());
+
+ this._connectNode = target;
+ this.onShow(target, this.position);
+ },
+
+ close: function(){
+ // summary:
+ // Hide the tooltip or cancel timer for show of tooltip
+ // tags:
+ // private
+
+ if(this._connectNode){
+ // if tooltip is currently shown
+ dijit.hideTooltip(this._connectNode);
+ delete this._connectNode;
+ this.onHide();
+ }
+ if(this._showTimer){
+ // if tooltip is scheduled to be shown (after a brief delay)
+ clearTimeout(this._showTimer);
+ delete this._showTimer;
+ }
+ },
+
+ onShow: function(target, position){
+ // summary:
+ // Called when the tooltip is shown
+ // tags:
+ // callback
+ },
+
+ onHide: function(){
+ // summary:
+ // Called when the tooltip is hidden
+ // tags:
+ // callback
+ },
+
+ uninitialize: function(){
+ this.close();
+ this.inherited(arguments);
+ }
+ }
+);
+
+// dijit.Tooltip.defaultPosition: String[]
+// This variable controls the position of tooltips, if the position is not specified to
+// the Tooltip widget or *TextBox widget itself. It's an array of strings with the following values:
+//
+// * before: places tooltip to the left of the target node/widget, or to the right in
+// the case of RTL scripts like Hebrew and Arabic
+// * after: places tooltip to the right of the target node/widget, or to the left in
+// the case of RTL scripts like Hebrew and Arabic
+// * above: tooltip goes above target node
+// * below: tooltip goes below target node
+//
+// The list is positions is tried, in order, until a position is found where the tooltip fits
+// within the viewport.
+//
+// Be careful setting this parameter. A value of "above" may work fine until the user scrolls
+// the screen so that there's no room above the target node. Nodes with drop downs, like
+// DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure
+// that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there
+// is only room below (or above) the target node, but not both.
+dijit.Tooltip.defaultPosition = ["after", "before"];
+
+}
+
+if(!dojo._hasResource["dijit.form.ValidationTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.ValidationTextBox"] = true;
+dojo.provide("dijit.form.ValidationTextBox");
+
+
+
+
+
+
+
+
+/*=====
+ dijit.form.ValidationTextBox.__Constraints = function(){
+ // locale: String
+ // locale used for validation, picks up value from this widget's lang attribute
+ // _flags_: anything
+ // various flags passed to regExpGen function
+ this.locale = "";
+ this._flags_ = "";
+ }
+=====*/
+
+dojo.declare(
+ "dijit.form.ValidationTextBox",
+ dijit.form.TextBox,
+ {
+ // summary:
+ // Base class for textbox widgets with the ability to validate content of various types and provide user feedback.
+ // tags:
+ // protected
+
+ templateString: dojo.cache("dijit.form", "templates/ValidationTextBox.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\" waiRole=\"presentation\"\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&Chi; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),
+ baseClass: "dijitTextBox dijitValidationTextBox",
+
+ // required: Boolean
+ // User is required to enter data into this field.
+ required: false,
+
+ // promptMessage: String
+ // If defined, display this hint string immediately on focus to the textbox, if empty.
+ // Think of this like a tooltip that tells the user what to do, not an error message
+ // that tells the user what they've done wrong.
+ //
+ // Message disappears when user starts typing.
+ promptMessage: "",
+
+ // invalidMessage: String
+ // The message to display if value is invalid.
+ // The translated string value is read from the message file by default.
+ // Set to "" to use the promptMessage instead.
+ invalidMessage: "$_unset_$",
+
+ // missingMessage: String
+ // The message to display if value is empty and the field is required.
+ // The translated string value is read from the message file by default.
+ // Set to "" to use the invalidMessage instead.
+ missingMessage: "$_unset_$",
+
+ // constraints: dijit.form.ValidationTextBox.__Constraints
+ // user-defined object needed to pass parameters to the validator functions
+ constraints: {},
+
+ // regExp: [extension protected] String
+ // regular expression string used to validate the input
+ // Do not specify both regExp and regExpGen
+ regExp: ".*",
+
+ regExpGen: function(/*dijit.form.ValidationTextBox.__Constraints*/constraints){
+ // summary:
+ // Overridable function used to generate regExp when dependent on constraints.
+ // Do not specify both regExp and regExpGen.
+ // tags:
+ // extension protected
+ return this.regExp; // String
+ },
+
+ // state: [readonly] String
+ // Shows current state (ie, validation result) of input (Normal, Warning, or Error)
+ state: "",
+
+ // tooltipPosition: String[]
+ // See description of `dijit.Tooltip.defaultPosition` for details on this parameter.
+ tooltipPosition: [],
+
+ _setValueAttr: function(){
+ // summary:
+ // Hook so attr('value', ...) works.
+ this.inherited(arguments);
+ this.validate(this._focused);
+ },
+
+ validator: function(/*anything*/value, /*dijit.form.ValidationTextBox.__Constraints*/constraints){
+ // summary:
+ // Overridable function used to validate the text input against the regular expression.
+ // tags:
+ // protected
+ return (new RegExp("^(?:" + this.regExpGen(constraints) + ")"+(this.required?"":"?")+"$")).test(value) &&
+ (!this.required || !this._isEmpty(value)) &&
+ (this._isEmpty(value) || this.parse(value, constraints) !== undefined); // Boolean
+ },
+
+ _isValidSubset: function(){
+ // summary:
+ // Returns true if the value is either already valid or could be made valid by appending characters.
+ // This is used for validation while the user [may be] still typing.
+ return this.textbox.value.search(this._partialre) == 0;
+ },
+
+ isValid: function(/*Boolean*/ isFocused){
+ // summary:
+ // Tests if value is valid.
+ // Can override with your own routine in a subclass.
+ // tags:
+ // protected
+ return this.validator(this.textbox.value, this.constraints);
+ },
+
+ _isEmpty: function(value){
+ // summary:
+ // Checks for whitespace
+ return /^\s*$/.test(value); // Boolean
+ },
+
+ getErrorMessage: function(/*Boolean*/ isFocused){
+ // summary:
+ // Return an error message to show if appropriate
+ // tags:
+ // protected
+ return (this.required && this._isEmpty(this.textbox.value)) ? this.missingMessage : this.invalidMessage; // String
+ },
+
+ getPromptMessage: function(/*Boolean*/ isFocused){
+ // summary:
+ // Return a hint message to show when widget is first focused
+ // tags:
+ // protected
+ return this.promptMessage; // String
+ },
+
+ _maskValidSubsetError: true,
+ validate: function(/*Boolean*/ isFocused){
+ // summary:
+ // Called by oninit, onblur, and onkeypress.
+ // description:
+ // Show missing or invalid messages if appropriate, and highlight textbox field.
+ // tags:
+ // protected
+ var message = "";
+ var isValid = this.disabled || this.isValid(isFocused);
+ if(isValid){ this._maskValidSubsetError = true; }
+ var isEmpty = this._isEmpty(this.textbox.value);
+ var isValidSubset = !isValid && !isEmpty && isFocused && this._isValidSubset();
+ this.state = ((isValid || ((!this._hasBeenBlurred || isFocused) && isEmpty) || isValidSubset) && this._maskValidSubsetError) ? "" : "Error";
+ if(this.state == "Error"){ this._maskValidSubsetError = isFocused; } // we want the error to show up afer a blur and refocus
+ this._setStateClass();
+ dijit.setWaiState(this.focusNode, "invalid", isValid ? "false" : "true");
+ if(isFocused){
+ if(this.state == "Error"){
+ message = this.getErrorMessage(true);
+ }else{
+ message = this.getPromptMessage(true); // show the prompt whever there's no error
+ }
+ this._maskValidSubsetError = true; // since we're focused, always mask warnings
+ }
+ this.displayMessage(message);
+ return isValid;
+ },
+
+ // _message: String
+ // Currently displayed message
+ _message: "",
+
+ displayMessage: function(/*String*/ message){
+ // summary:
+ // Overridable method to display validation errors/hints.
+ // By default uses a tooltip.
+ // tags:
+ // extension
+ if(this._message == message){ return; }
+ this._message = message;
+ dijit.hideTooltip(this.domNode);
+ if(message){
+ dijit.showTooltip(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
+ }
+ },
+
+ _refreshState: function(){
+ // Overrides TextBox._refreshState()
+ this.validate(this._focused);
+ this.inherited(arguments);
+ },
+
+ //////////// INITIALIZATION METHODS ///////////////////////////////////////
+
+ constructor: function(){
+ this.constraints = {};
+ },
+
+ _setConstraintsAttr: function(/* Object */ constraints){
+ if(!constraints.locale && this.lang){
+ constraints.locale = this.lang;
+ }
+ this.constraints = constraints;
+ this._computePartialRE();
+ },
+
+ _computePartialRE: function(){
+ var p = this.regExpGen(this.constraints);
+ this.regExp = p;
+ var partialre = "";
+ // parse the regexp and produce a new regexp that matches valid subsets
+ // if the regexp is .* then there's no use in matching subsets since everything is valid
+ if(p != ".*"){ this.regExp.replace(/\\.|\[\]|\[.*?[^\\]{1}\]|\{.*?\}|\(\?[=:!]|./g,
+ function (re){
+ switch(re.charAt(0)){
+ case '{':
+ case '+':
+ case '?':
+ case '*':
+ case '^':
+ case '$':
+ case '|':
+ case '(':
+ partialre += re;
+ break;
+ case ")":
+ partialre += "|$)";
+ break;
+ default:
+ partialre += "(?:"+re+"|$)";
+ break;
+ }
+ }
+ );}
+ try{ // this is needed for now since the above regexp parsing needs more test verification
+ "".search(partialre);
+ }catch(e){ // should never be here unless the original RE is bad or the parsing is bad
+ partialre = this.regExp;
+ console.warn('RegExp error in ' + this.declaredClass + ': ' + this.regExp);
+ } // should never be here unless the original RE is bad or the parsing is bad
+ this._partialre = "^(?:" + partialre + ")$";
+ },
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this.messages = dojo.i18n.getLocalization("dijit.form", "validate", this.lang);
+ if(this.invalidMessage == "$_unset_$"){ this.invalidMessage = this.messages.invalidMessage; }
+ if(!this.invalidMessage){ this.invalidMessage = this.promptMessage; }
+ if(this.missingMessage == "$_unset_$"){ this.missingMessage = this.messages.missingMessage; }
+ if(!this.missingMessage){ this.missingMessage = this.invalidMessage; }
+ this._setConstraintsAttr(this.constraints); // this needs to happen now (and later) due to codependency on _set*Attr calls attachPoints
+ },
+
+ _setDisabledAttr: function(/*Boolean*/ value){
+ this.inherited(arguments); // call FormValueWidget._setDisabledAttr()
+ this._refreshState();
+ },
+
+ _setRequiredAttr: function(/*Boolean*/ value){
+ this.required = value;
+ dijit.setWaiState(this.focusNode, "required", value);
+ this._refreshState();
+ },
+
+ reset:function(){
+ // Overrides dijit.form.TextBox.reset() by also
+ // hiding errors about partial matches
+ this._maskValidSubsetError = true;
+ this.inherited(arguments);
+ },
+
+ _onBlur: function(){
+ this.displayMessage('');
+ this.inherited(arguments);
+ }
+ }
+);
+
+dojo.declare(
+ "dijit.form.MappedTextBox",
+ dijit.form.ValidationTextBox,
+ {
+ // summary:
+ // A dijit.form.ValidationTextBox subclass which provides a base class for widgets that have
+ // a visible formatted display value, and a serializable
+ // value in a hidden input field which is actually sent to the server.
+ // description:
+ // The visible display may
+ // be locale-dependent and interactive. The value sent to the server is stored in a hidden
+ // input field which uses the `name` attribute declared by the original widget. That value sent
+ // to the server is defined by the dijit.form.MappedTextBox.serialize method and is typically
+ // locale-neutral.
+ // tags:
+ // protected
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+
+ // we want the name attribute to go to the hidden <input>, not the displayed <input>,
+ // so override _FormWidget.postMixInProperties() setting of nameAttrSetting
+ this.nameAttrSetting = "";
+ },
+
+ serialize: function(/*anything*/val, /*Object?*/options){
+ // summary:
+ // Overridable function used to convert the attr('value') result to a canonical
+ // (non-localized) string. For example, will print dates in ISO format, and
+ // numbers the same way as they are represented in javascript.
+ // tags:
+ // protected extension
+ return val.toString ? val.toString() : ""; // String
+ },
+
+ toString: function(){
+ // summary:
+ // Returns widget as a printable string using the widget's value
+ // tags:
+ // protected
+ var val = this.filter(this.get('value')); // call filter in case value is nonstring and filter has been customized
+ return val != null ? (typeof val == "string" ? val : this.serialize(val, this.constraints)) : ""; // String
+ },
+
+ validate: function(){
+ // Overrides `dijit.form.TextBox.validate`
+ this.valueNode.value = this.toString();
+ return this.inherited(arguments);
+ },
+
+ buildRendering: function(){
+ // Overrides `dijit._Templated.buildRendering`
+
+ this.inherited(arguments);
+
+ // Create a hidden <input> node with the serialized value used for submit
+ // (as opposed to the displayed value).
+ // Passing in name as markup rather than calling dojo.create() with an attrs argument
+ // to make dojo.query(input[name=...]) work on IE. (see #8660)
+ this.valueNode = dojo.place("<input type='hidden'" + (this.name ? " name='" + this.name + "'" : "") + ">", this.textbox, "after");
+ },
+
+ reset:function(){
+ // Overrides `dijit.form.ValidationTextBox.reset` to
+ // reset the hidden textbox value to ''
+ this.valueNode.value = '';
+ this.inherited(arguments);
+ }
+ }
+);
+
+/*=====
+ dijit.form.RangeBoundTextBox.__Constraints = function(){
+ // min: Number
+ // Minimum signed value. Default is -Infinity
+ // max: Number
+ // Maximum signed value. Default is +Infinity
+ this.min = min;
+ this.max = max;
+ }
+=====*/
+
+dojo.declare(
+ "dijit.form.RangeBoundTextBox",
+ dijit.form.MappedTextBox,
+ {
+ // summary:
+ // Base class for textbox form widgets which defines a range of valid values.
+
+ // rangeMessage: String
+ // The message to display if value is out-of-range
+ rangeMessage: "",
+
+ /*=====
+ // constraints: dijit.form.RangeBoundTextBox.__Constraints
+ constraints: {},
+ ======*/
+
+ rangeCheck: function(/*Number*/ primitive, /*dijit.form.RangeBoundTextBox.__Constraints*/ constraints){
+ // summary:
+ // Overridable function used to validate the range of the numeric input value.
+ // tags:
+ // protected
+ return ("min" in constraints? (this.compare(primitive,constraints.min) >= 0) : true) &&
+ ("max" in constraints? (this.compare(primitive,constraints.max) <= 0) : true); // Boolean
+ },
+
+ isInRange: function(/*Boolean*/ isFocused){
+ // summary:
+ // Tests if the value is in the min/max range specified in constraints
+ // tags:
+ // protected
+ return this.rangeCheck(this.get('value'), this.constraints);
+ },
+
+ _isDefinitelyOutOfRange: function(){
+ // summary:
+ // Returns true if the value is out of range and will remain
+ // out of range even if the user types more characters
+ var val = this.get('value');
+ var isTooLittle = false;
+ var isTooMuch = false;
+ if("min" in this.constraints){
+ var min = this.constraints.min;
+ min = this.compare(val, ((typeof min == "number") && min >= 0 && val !=0) ? 0 : min);
+ isTooLittle = (typeof min == "number") && min < 0;
+ }
+ if("max" in this.constraints){
+ var max = this.constraints.max;
+ max = this.compare(val, ((typeof max != "number") || max > 0) ? max : 0);
+ isTooMuch = (typeof max == "number") && max > 0;
+ }
+ return isTooLittle || isTooMuch;
+ },
+
+ _isValidSubset: function(){
+ // summary:
+ // Overrides `dijit.form.ValidationTextBox._isValidSubset`.
+ // Returns true if the input is syntactically valid, and either within
+ // range or could be made in range by more typing.
+ return this.inherited(arguments) && !this._isDefinitelyOutOfRange();
+ },
+
+ isValid: function(/*Boolean*/ isFocused){
+ // Overrides dijit.form.ValidationTextBox.isValid to check that the value is also in range.
+ return this.inherited(arguments) &&
+ ((this._isEmpty(this.textbox.value) && !this.required) || this.isInRange(isFocused)); // Boolean
+ },
+
+ getErrorMessage: function(/*Boolean*/ isFocused){
+ // Overrides dijit.form.ValidationTextBox.getErrorMessage to print "out of range" message if appropriate
+ var v = this.get('value');
+ if(v !== null && v !== '' && v !== undefined && (typeof v != "number" || !isNaN(v)) && !this.isInRange(isFocused)){ // don't check isInRange w/o a real value
+ return this.rangeMessage; // String
+ }
+ return this.inherited(arguments);
+ },
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ if(!this.rangeMessage){
+ this.messages = dojo.i18n.getLocalization("dijit.form", "validate", this.lang);
+ this.rangeMessage = this.messages.rangeMessage;
+ }
+ },
+
+ _setConstraintsAttr: function(/* Object */ constraints){
+ this.inherited(arguments);
+ if(this.focusNode){ // not set when called from postMixInProperties
+ if(this.constraints.min !== undefined){
+ dijit.setWaiState(this.focusNode, "valuemin", this.constraints.min);
+ }else{
+ dijit.removeWaiState(this.focusNode, "valuemin");
+ }
+ if(this.constraints.max !== undefined){
+ dijit.setWaiState(this.focusNode, "valuemax", this.constraints.max);
+ }else{
+ dijit.removeWaiState(this.focusNode, "valuemax");
+ }
+ }
+ },
+
+ _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
+ // summary:
+ // Hook so attr('value', ...) works.
+
+ dijit.setWaiState(this.focusNode, "valuenow", value);
+ this.inherited(arguments);
+ }
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit.form.ComboBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.ComboBox"] = true;
+dojo.provide("dijit.form.ComboBox");
+
+
+
+
+
+
+
+
+
+
+
+
+dojo.declare(
+ "dijit.form.ComboBoxMixin",
+ null,
+ {
+ // summary:
+ // Implements the base functionality for `dijit.form.ComboBox`/`dijit.form.FilteringSelect`
+ // description:
+ // All widgets that mix in dijit.form.ComboBoxMixin must extend `dijit.form._FormValueWidget`.
+ // tags:
+ // protected
+
+ // item: Object
+ // This is the item returned by the dojo.data.store implementation that
+ // provides the data for this ComboBox, it's the currently selected item.
+ item: null,
+
+ // pageSize: Integer
+ // Argument to data provider.
+ // Specifies number of search results per page (before hitting "next" button)
+ pageSize: Infinity,
+
+ // store: Object
+ // Reference to data provider object used by this ComboBox
+ store: null,
+
+ // fetchProperties: Object
+ // Mixin to the dojo.data store's fetch.
+ // For example, to set the sort order of the ComboBox menu, pass:
+ // | { sort: {attribute:"name",descending: true} }
+ // To override the default queryOptions so that deep=false, do:
+ // | { queryOptions: {ignoreCase: true, deep: false} }
+ fetchProperties:{},
+
+ // query: Object
+ // A query that can be passed to 'store' to initially filter the items,
+ // before doing further filtering based on `searchAttr` and the key.
+ // Any reference to the `searchAttr` is ignored.
+ query: {},
+
+ // autoComplete: Boolean
+ // If user types in a partial string, and then tab out of the `<input>` box,
+ // automatically copy the first entry displayed in the drop down list to
+ // the `<input>` field
+ autoComplete: true,
+
+ // highlightMatch: String
+ // One of: "first", "all" or "none".
+ //
+ // If the ComboBox/FilteringSelect opens with the search results and the searched
+ // string can be found, it will be highlighted. If set to "all"
+ // then will probably want to change `queryExpr` parameter to '*${0}*'
+ //
+ // Highlighting is only performed when `labelType` is "text", so as to not
+ // interfere with any HTML markup an HTML label might contain.
+ highlightMatch: "first",
+
+ // searchDelay: Integer
+ // Delay in milliseconds between when user types something and we start
+ // searching based on that value
+ searchDelay: 100,
+
+ // searchAttr: String
+ // Search for items in the data store where this attribute (in the item)
+ // matches what the user typed
+ searchAttr: "name",
+
+ // labelAttr: String?
+ // The entries in the drop down list come from this attribute in the
+ // dojo.data items.
+ // If not specified, the searchAttr attribute is used instead.
+ labelAttr: "",
+
+ // labelType: String
+ // Specifies how to interpret the labelAttr in the data store items.
+ // Can be "html" or "text".
+ labelType: "text",
+
+ // queryExpr: String
+ // This specifies what query ComboBox/FilteringSelect sends to the data store,
+ // based on what the user has typed. Changing this expression will modify
+ // whether the drop down shows only exact matches, a "starting with" match,
+ // etc. Use it in conjunction with highlightMatch.
+ // dojo.data query expression pattern.
+ // `${0}` will be substituted for the user text.
+ // `*` is used for wildcards.
+ // `${0}*` means "starts with", `*${0}*` means "contains", `${0}` means "is"
+ queryExpr: "${0}*",
+
+ // ignoreCase: Boolean
+ // Set true if the ComboBox/FilteringSelect should ignore case when matching possible items
+ ignoreCase: true,
+
+ // hasDownArrow: [const] Boolean
+ // Set this textbox to have a down arrow button, to display the drop down list.
+ // Defaults to true.
+ hasDownArrow: true,
+
+ templateString: dojo.cache("dijit.form", "templates/ComboBox.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\"\n\tdojoAttachPoint=\"comboNode\" waiRole=\"combobox\"\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\n\t\tdojoAttachPoint=\"downArrowNode\" waiRole=\"presentation\"\n\t\tdojoAttachEvent=\"onmousedown:_onArrowMouseDown\"\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t\t\t${_buttonInputDisabled}\n\t/></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&Chi; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\n\t\t\tdojoAttachEvent=\"onkeypress:_onKeyPress,compositionend\"\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" waiRole=\"textbox\" waiState=\"haspopup-true,autocomplete-list\"\n\t/></div\n></div>\n"),
+
+ baseClass: "dijitTextBox dijitComboBox",
+
+ // Set classes like dijitDownArrowButtonHover depending on
+ // mouse action over button node
+ cssStateNodes: {
+ "downArrowNode": "dijitDownArrowButton"
+ },
+
+ _getCaretPos: function(/*DomNode*/ element){
+ // khtml 3.5.2 has selection* methods as does webkit nightlies from 2005-06-22
+ var pos = 0;
+ if(typeof(element.selectionStart) == "number"){
+ // FIXME: this is totally borked on Moz < 1.3. Any recourse?
+ pos = element.selectionStart;
+ }else if(dojo.isIE){
+ // in the case of a mouse click in a popup being handled,
+ // then the dojo.doc.selection is not the textarea, but the popup
+ // var r = dojo.doc.selection.createRange();
+ // hack to get IE 6 to play nice. What a POS browser.
+ var tr = dojo.doc.selection.createRange().duplicate();
+ var ntr = element.createTextRange();
+ tr.move("character",0);
+ ntr.move("character",0);
+ try{
+ // If control doesnt have focus, you get an exception.
+ // Seems to happen on reverse-tab, but can also happen on tab (seems to be a race condition - only happens sometimes).
+ // There appears to be no workaround for this - googled for quite a while.
+ ntr.setEndPoint("EndToEnd", tr);
+ pos = String(ntr.text).replace(/\r/g,"").length;
+ }catch(e){
+ // If focus has shifted, 0 is fine for caret pos.
+ }
+ }
+ return pos;
+ },
+
+ _setCaretPos: function(/*DomNode*/ element, /*Number*/ location){
+ location = parseInt(location);
+ dijit.selectInputText(element, location, location);
+ },
+
+ _setDisabledAttr: function(/*Boolean*/ value){
+ // Additional code to set disabled state of ComboBox node.
+ // Overrides _FormValueWidget._setDisabledAttr() or ValidationTextBox._setDisabledAttr().
+ this.inherited(arguments);
+ dijit.setWaiState(this.comboNode, "disabled", value);
+ },
+
+ _abortQuery: function(){
+ // stop in-progress query
+ if(this.searchTimer){
+ clearTimeout(this.searchTimer);
+ this.searchTimer = null;
+ }
+ if(this._fetchHandle){
+ if(this._fetchHandle.abort){ this._fetchHandle.abort(); }
+ this._fetchHandle = null;
+ }
+ },
+
+ _onInput: function(/*Event*/ evt){
+ // summary:
+ // Handles paste events
+ if(!this.searchTimer && (evt.type == 'paste'/*IE|WebKit*/ || evt.type == 'input'/*Firefox*/) && this._lastInput != this.textbox.value){
+ this.searchTimer = setTimeout(dojo.hitch(this, function(){
+ this._onKeyPress({charOrCode: 229}); // fake IME key to cause a search
+ }), 100); // long delay that will probably be preempted by keyboard input
+ }
+ this.inherited(arguments);
+ },
+
+ _onKeyPress: function(/*Event*/ evt){
+ // summary:
+ // Handles keyboard events
+ var key = evt.charOrCode;
+ // except for cutting/pasting case - ctrl + x/v
+ if(evt.altKey || ((evt.ctrlKey || evt.metaKey) && (key != 'x' && key != 'v')) || key == dojo.keys.SHIFT){
+ return; // throw out weird key combinations and spurious events
+ }
+ var doSearch = false;
+ var searchFunction = "_startSearchFromInput";
+ var pw = this._popupWidget;
+ var dk = dojo.keys;
+ var highlighted = null;
+ this._prev_key_backspace = false;
+ this._abortQuery();
+ if(this._isShowingNow){
+ pw.handleKey(key);
+ highlighted = pw.getHighlightedOption();
+ }
+ switch(key){
+ case dk.PAGE_DOWN:
+ case dk.DOWN_ARROW:
+ case dk.PAGE_UP:
+ case dk.UP_ARROW:
+ if(!this._isShowingNow){
+ doSearch = true;
+ searchFunction = "_startSearchAll";
+ }else{
+ this._announceOption(highlighted);
+ }
+ dojo.stopEvent(evt);
+ break;
+
+ case dk.ENTER:
+ // prevent submitting form if user presses enter. Also
+ // prevent accepting the value if either Next or Previous
+ // are selected
+ if(highlighted){
+ // only stop event on prev/next
+ if(highlighted == pw.nextButton){
+ this._nextSearch(1);
+ dojo.stopEvent(evt);
+ break;
+ }else if(highlighted == pw.previousButton){
+ this._nextSearch(-1);
+ dojo.stopEvent(evt);
+ break;
+ }
+ }else{
+ // Update 'value' (ex: KY) according to currently displayed text
+ this._setBlurValue(); // set value if needed
+ this._setCaretPos(this.focusNode, this.focusNode.value.length); // move cursor to end and cancel highlighting
+ }
+ // default case:
+ // prevent submit, but allow event to bubble
+ evt.preventDefault();
+ // fall through
+
+ case dk.TAB:
+ var newvalue = this.get('displayedValue');
+ // if the user had More Choices selected fall into the
+ // _onBlur handler
+ if(pw && (
+ newvalue == pw._messages["previousMessage"] ||
+ newvalue == pw._messages["nextMessage"])
+ ){
+ break;
+ }
+ if(highlighted){
+ this._selectOption();
+ }
+ if(this._isShowingNow){
+ this._lastQuery = null; // in case results come back later
+ this._hideResultList();
+ }
+ break;
+
+ case ' ':
+ if(highlighted){
+ dojo.stopEvent(evt);
+ this._selectOption();
+ this._hideResultList();
+ }else{
+ doSearch = true;
+ }
+ break;
+
+ case dk.ESCAPE:
+ if(this._isShowingNow){
+ dojo.stopEvent(evt);
+ this._hideResultList();
+ }
+ break;
+
+ case dk.DELETE:
+ case dk.BACKSPACE:
+ this._prev_key_backspace = true;
+ doSearch = true;
+ break;
+
+ default:
+ // Non char keys (F1-F12 etc..) shouldn't open list.
+ // Ascii characters and IME input (Chinese, Japanese etc.) should.
+ // On IE and safari, IME input produces keycode == 229, and we simulate
+ // it on firefox by attaching to compositionend event (see compositionend method)
+ doSearch = typeof key == 'string' || key == 229;
+ }
+ if(doSearch){
+ // need to wait a tad before start search so that the event
+ // bubbles through DOM and we have value visible
+ this.item = undefined; // undefined means item needs to be set
+ this.searchTimer = setTimeout(dojo.hitch(this, searchFunction),1);
+ }
+ },
+
+ _autoCompleteText: function(/*String*/ text){
+ // summary:
+ // Fill in the textbox with the first item from the drop down
+ // list, and highlight the characters that were
+ // auto-completed. For example, if user typed "CA" and the
+ // drop down list appeared, the textbox would be changed to
+ // "California" and "ifornia" would be highlighted.
+
+ var fn = this.focusNode;
+
+ // IE7: clear selection so next highlight works all the time
+ dijit.selectInputText(fn, fn.value.length);
+ // does text autoComplete the value in the textbox?
+ var caseFilter = this.ignoreCase? 'toLowerCase' : 'substr';
+ if(text[caseFilter](0).indexOf(this.focusNode.value[caseFilter](0)) == 0){
+ var cpos = this._getCaretPos(fn);
+ // only try to extend if we added the last character at the end of the input
+ if((cpos+1) > fn.value.length){
+ // only add to input node as we would overwrite Capitalisation of chars
+ // actually, that is ok
+ fn.value = text;//.substr(cpos);
+ // visually highlight the autocompleted characters
+ dijit.selectInputText(fn, cpos);
+ }
+ }else{
+ // text does not autoComplete; replace the whole value and highlight
+ fn.value = text;
+ dijit.selectInputText(fn);
+ }
+ },
+
+ _openResultList: function(/*Object*/ results, /*Object*/ dataObject){
+ this._fetchHandle = null;
+ if( this.disabled ||
+ this.readOnly ||
+ (dataObject.query[this.searchAttr] != this._lastQuery)
+ ){
+ return;
+ }
+ this._popupWidget.clearResultList();
+ if(!results.length && !this._maxOptions){ // this condition needs to match !this._isvalid set in FilteringSelect::_openResultList
+ this._hideResultList();
+ return;
+ }
+
+
+ // Fill in the textbox with the first item from the drop down list,
+ // and highlight the characters that were auto-completed. For
+ // example, if user typed "CA" and the drop down list appeared, the
+ // textbox would be changed to "California" and "ifornia" would be
+ // highlighted.
+
+ dataObject._maxOptions = this._maxOptions;
+ var nodes = this._popupWidget.createOptions(
+ results,
+ dataObject,
+ dojo.hitch(this, "_getMenuLabelFromItem")
+ );
+
+ // show our list (only if we have content, else nothing)
+ this._showResultList();
+
+ // #4091:
+ // tell the screen reader that the paging callback finished by
+ // shouting the next choice
+ if(dataObject.direction){
+ if(1 == dataObject.direction){
+ this._popupWidget.highlightFirstOption();
+ }else if(-1 == dataObject.direction){
+ this._popupWidget.highlightLastOption();
+ }
+ this._announceOption(this._popupWidget.getHighlightedOption());
+ }else if(this.autoComplete && !this._prev_key_backspace /*&& !dataObject.direction*/
+ // when the user clicks the arrow button to show the full list,
+ // startSearch looks for "*".
+ // it does not make sense to autocomplete
+ // if they are just previewing the options available.
+ && !/^[*]+$/.test(dataObject.query[this.searchAttr])){
+ this._announceOption(nodes[1]); // 1st real item
+ }
+ },
+
+ _showResultList: function(){
+ this._hideResultList();
+ // hide the tooltip
+ this.displayMessage("");
+
+ // Position the list and if it's too big to fit on the screen then
+ // size it to the maximum possible height
+ // Our dear friend IE doesnt take max-height so we need to
+ // calculate that on our own every time
+
+ // TODO: want to redo this, see
+ // http://trac.dojotoolkit.org/ticket/3272
+ // and
+ // http://trac.dojotoolkit.org/ticket/4108
+
+
+ // natural size of the list has changed, so erase old
+ // width/height settings, which were hardcoded in a previous
+ // call to this function (via dojo.marginBox() call)
+ dojo.style(this._popupWidget.domNode, {width: "", height: ""});
+
+ var best = this.open();
+ // #3212:
+ // only set auto scroll bars if necessary prevents issues with
+ // scroll bars appearing when they shouldn't when node is made
+ // wider (fractional pixels cause this)
+ var popupbox = dojo.marginBox(this._popupWidget.domNode);
+ this._popupWidget.domNode.style.overflow =
+ ((best.h == popupbox.h) && (best.w == popupbox.w)) ? "hidden" : "auto";
+ // #4134:
+ // borrow TextArea scrollbar test so content isn't covered by
+ // scrollbar and horizontal scrollbar doesn't appear
+ var newwidth = best.w;
+ if(best.h < this._popupWidget.domNode.scrollHeight){
+ newwidth += 16;
+ }
+ dojo.marginBox(this._popupWidget.domNode, {
+ h: best.h,
+ w: Math.max(newwidth, this.domNode.offsetWidth)
+ });
+
+ // If we increased the width of drop down to match the width of ComboBox.domNode,
+ // then need to reposition the drop down (wrapper) so (all of) the drop down still
+ // appears underneath the ComboBox.domNode
+ if(newwidth < this.domNode.offsetWidth){
+ this._popupWidget.domNode.parentNode.style.left = dojo.position(this.domNode, true).x + "px";
+ }
+
+ dijit.setWaiState(this.comboNode, "expanded", "true");
+ },
+
+ _hideResultList: function(){
+ this._abortQuery();
+ if(this._isShowingNow){
+ dijit.popup.close(this._popupWidget);
+ this._isShowingNow=false;
+ dijit.setWaiState(this.comboNode, "expanded", "false");
+ dijit.removeWaiState(this.focusNode,"activedescendant");
+ }
+ },
+
+ _setBlurValue: function(){
+ // if the user clicks away from the textbox OR tabs away, set the
+ // value to the textbox value
+ // #4617:
+ // if value is now more choices or previous choices, revert
+ // the value
+ var newvalue = this.get('displayedValue');
+ var pw = this._popupWidget;
+ if(pw && (
+ newvalue == pw._messages["previousMessage"] ||
+ newvalue == pw._messages["nextMessage"]
+ )
+ ){
+ this._setValueAttr(this._lastValueReported, true);
+ }else if(typeof this.item == "undefined"){
+ // Update 'value' (ex: KY) according to currently displayed text
+ this.item = null;
+ this.set('displayedValue', newvalue);
+ }else{
+ if(this.value != this._lastValueReported){
+ dijit.form._FormValueWidget.prototype._setValueAttr.call(this, this.value, true);
+ }
+ this._refreshState();
+ }
+ },
+
+ _onBlur: function(){
+ // summary:
+ // Called magically when focus has shifted away from this widget and it's drop down
+ this._hideResultList();
+ this.inherited(arguments);
+ },
+
+ _setItemAttr: function(/*item*/ item, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){
+ // summary:
+ // Set the displayed valued in the input box, and the hidden value
+ // that gets submitted, based on a dojo.data store item.
+ // description:
+ // Users shouldn't call this function; they should be calling
+ // attr('item', value)
+ // tags:
+ // private
+ if(!displayedValue){ displayedValue = this.labelFunc(item, this.store); }
+ this.value = this._getValueField() != this.searchAttr? this.store.getIdentity(item) : displayedValue;
+ this.item = item;
+ dijit.form.ComboBox.superclass._setValueAttr.call(this, this.value, priorityChange, displayedValue);
+ },
+
+ _announceOption: function(/*Node*/ node){
+ // summary:
+ // a11y code that puts the highlighted option in the textbox.
+ // This way screen readers will know what is happening in the
+ // menu.
+
+ if(!node){
+ return;
+ }
+ // pull the text value from the item attached to the DOM node
+ var newValue;
+ if(node == this._popupWidget.nextButton ||
+ node == this._popupWidget.previousButton){
+ newValue = node.innerHTML;
+ this.item = undefined;
+ this.value = '';
+ }else{
+ newValue = this.labelFunc(node.item, this.store);
+ this.set('item', node.item, false, newValue);
+ }
+ // get the text that the user manually entered (cut off autocompleted text)
+ this.focusNode.value = this.focusNode.value.substring(0, this._lastInput.length);
+ // set up ARIA activedescendant
+ dijit.setWaiState(this.focusNode, "activedescendant", dojo.attr(node, "id"));
+ // autocomplete the rest of the option to announce change
+ this._autoCompleteText(newValue);
+ },
+
+ _selectOption: function(/*Event*/ evt){
+ // summary:
+ // Menu callback function, called when an item in the menu is selected.
+ if(evt){
+ this._announceOption(evt.target);
+ }
+ this._hideResultList();
+ this._setCaretPos(this.focusNode, this.focusNode.value.length);
+ dijit.form._FormValueWidget.prototype._setValueAttr.call(this, this.value, true); // set this.value and fire onChange
+ },
+
+ _onArrowMouseDown: function(evt){
+ // summary:
+ // Callback when arrow is clicked
+ if(this.disabled || this.readOnly){
+ return;
+ }
+ dojo.stopEvent(evt);
+ this.focus();
+ if(this._isShowingNow){
+ this._hideResultList();
+ }else{
+ // forces full population of results, if they click
+ // on the arrow it means they want to see more options
+ this._startSearchAll();
+ }
+ },
+
+ _startSearchAll: function(){
+ this._startSearch('');
+ },
+
+ _startSearchFromInput: function(){
+ this._startSearch(this.focusNode.value.replace(/([\\\*\?])/g, "\\$1"));
+ },
+
+ _getQueryString: function(/*String*/ text){
+ return dojo.string.substitute(this.queryExpr, [text]);
+ },
+
+ _startSearch: function(/*String*/ key){
+ if(!this._popupWidget){
+ var popupId = this.id + "_popup";
+ this._popupWidget = new dijit.form._ComboBoxMenu({
+ onChange: dojo.hitch(this, this._selectOption),
+ id: popupId,
+ dir: this.dir
+ });
+ dijit.removeWaiState(this.focusNode,"activedescendant");
+ dijit.setWaiState(this.textbox,"owns",popupId); // associate popup with textbox
+ }
+ // create a new query to prevent accidentally querying for a hidden
+ // value from FilteringSelect's keyField
+ var query = dojo.clone(this.query); // #5970
+ this._lastInput = key; // Store exactly what was entered by the user.
+ this._lastQuery = query[this.searchAttr] = this._getQueryString(key);
+ // #5970: set _lastQuery, *then* start the timeout
+ // otherwise, if the user types and the last query returns before the timeout,
+ // _lastQuery won't be set and their input gets rewritten
+ this.searchTimer=setTimeout(dojo.hitch(this, function(query, _this){
+ this.searchTimer = null;
+ var fetch = {
+ queryOptions: {
+ ignoreCase: this.ignoreCase,
+ deep: true
+ },
+ query: query,
+ onBegin: dojo.hitch(this, "_setMaxOptions"),
+ onComplete: dojo.hitch(this, "_openResultList"),
+ onError: function(errText){
+ _this._fetchHandle = null;
+ console.error('dijit.form.ComboBox: ' + errText);
+ dojo.hitch(_this, "_hideResultList")();
+ },
+ start: 0,
+ count: this.pageSize
+ };
+ dojo.mixin(fetch, _this.fetchProperties);
+ this._fetchHandle = _this.store.fetch(fetch);
+
+ var nextSearch = function(dataObject, direction){
+ dataObject.start += dataObject.count*direction;
+ // #4091:
+ // tell callback the direction of the paging so the screen
+ // reader knows which menu option to shout
+ dataObject.direction = direction;
+ this._fetchHandle = this.store.fetch(dataObject);
+ };
+ this._nextSearch = this._popupWidget.onPage = dojo.hitch(this, nextSearch, this._fetchHandle);
+ }, query, this), this.searchDelay);
+ },
+
+ _setMaxOptions: function(size, request){
+ this._maxOptions = size;
+ },
+
+ _getValueField: function(){
+ // summmary:
+ // Helper for postMixInProperties() to set this.value based on data inlined into the markup.
+ // Returns the attribute name in the item (in dijit.form._ComboBoxDataStore) to use as the value.
+ return this.searchAttr;
+ },
+
+ /////////////// Event handlers /////////////////////
+
+ // FIXME: For 2.0, rename to "_compositionEnd"
+ compositionend: function(/*Event*/ evt){
+ // summary:
+ // When inputting characters using an input method, such as
+ // Asian languages, it will generate this event instead of
+ // onKeyDown event.
+ // Note: this event is only triggered in FF (not in IE/safari)
+ // tags:
+ // private
+
+ // 229 is the code produced by IE and safari while pressing keys during
+ // IME input mode
+ this._onKeyPress({charOrCode: 229});
+ },
+
+ //////////// INITIALIZATION METHODS ///////////////////////////////////////
+
+ constructor: function(){
+ this.query={};
+ this.fetchProperties={};
+ },
+
+ postMixInProperties: function(){
+ if(!this.store){
+ var srcNodeRef = this.srcNodeRef;
+
+ // if user didn't specify store, then assume there are option tags
+ this.store = new dijit.form._ComboBoxDataStore(srcNodeRef);
+
+ // if there is no value set and there is an option list, set
+ // the value to the first value to be consistent with native
+ // Select
+
+ // Firefox and Safari set value
+ // IE6 and Opera set selectedIndex, which is automatically set
+ // by the selected attribute of an option tag
+ // IE6 does not set value, Opera sets value = selectedIndex
+ if(!("value" in this.params)){
+ var item = this.store.fetchSelectedItem();
+ if(item){
+ var valueField = this._getValueField();
+ this.value = valueField != this.searchAttr? this.store.getValue(item, valueField) : this.labelFunc(item, this.store);
+ }
+ }
+ }
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ // summary:
+ // Subclasses must call this method from their postCreate() methods
+ // tags:
+ // protected
+
+ if(!this.hasDownArrow){
+ this.downArrowNode.style.display = "none";
+ }
+
+ // find any associated label element and add to ComboBox node.
+ var label=dojo.query('label[for="'+this.id+'"]');
+ if(label.length){
+ label[0].id = (this.id+"_label");
+ var cn=this.comboNode;
+ dijit.setWaiState(cn, "labelledby", label[0].id);
+
+ }
+ this.inherited(arguments);
+ },
+
+ uninitialize: function(){
+ if(this._popupWidget && !this._popupWidget._destroyed){
+ this._hideResultList();
+ this._popupWidget.destroy();
+ }
+ this.inherited(arguments);
+ },
+
+ _getMenuLabelFromItem: function(/*Item*/ item){
+ var label = this.labelAttr? this.store.getValue(item, this.labelAttr) : this.labelFunc(item, this.store);
+ var labelType = this.labelType;
+ // If labelType is not "text" we don't want to screw any markup ot whatever.
+ if(this.highlightMatch != "none" && this.labelType == "text" && this._lastInput){
+ label = this.doHighlight(label, this._escapeHtml(this._lastInput));
+ labelType = "html";
+ }
+ return {html: labelType == "html", label: label};
+ },
+
+ doHighlight: function(/*String*/label, /*String*/find){
+ // summary:
+ // Highlights the string entered by the user in the menu. By default this
+ // highlights the first occurence found. Override this method
+ // to implement your custom highlighing.
+ // tags:
+ // protected
+
+ // Add greedy when this.highlightMatch == "all"
+ var modifiers = "i"+(this.highlightMatch == "all"?"g":"");
+ var escapedLabel = this._escapeHtml(label);
+ find = dojo.regexp.escapeString(find); // escape regexp special chars
+ var ret = escapedLabel.replace(new RegExp("(^|\\s)("+ find +")", modifiers),
+ '$1<span class="dijitComboBoxHighlightMatch">$2</span>');
+ return ret;// returns String, (almost) valid HTML (entities encoded)
+ },
+
+ _escapeHtml: function(/*string*/str){
+ // TODO Should become dojo.html.entities(), when exists use instead
+ // summary:
+ // Adds escape sequences for special characters in XML: &<>"'
+ str = String(str).replace(/&/gm, "&amp;").replace(/</gm, "&lt;")
+ .replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
+ return str; // string
+ },
+
+ open: function(){
+ // summary:
+ // Opens the drop down menu. TODO: rename to _open.
+ // tags:
+ // private
+ this._isShowingNow=true;
+ return dijit.popup.open({
+ popup: this._popupWidget,
+ around: this.domNode,
+ parent: this
+ });
+ },
+
+ reset: function(){
+ // Overrides the _FormWidget.reset().
+ // Additionally reset the .item (to clean up).
+ this.item = null;
+ this.inherited(arguments);
+ },
+
+ labelFunc: function(/*item*/ item, /*dojo.data.store*/ store){
+ // summary:
+ // Computes the label to display based on the dojo.data store item.
+ // returns:
+ // The label that the ComboBox should display
+ // tags:
+ // private
+
+ // Use toString() because XMLStore returns an XMLItem whereas this
+ // method is expected to return a String (#9354)
+ return store.getValue(item, this.searchAttr).toString(); // String
+ }
+ }
+);
+
+dojo.declare(
+ "dijit.form._ComboBoxMenu",
+ [dijit._Widget, dijit._Templated, dijit._CssStateMixin],
+ {
+ // summary:
+ // Focus-less menu for internal use in `dijit.form.ComboBox`
+ // tags:
+ // private
+
+ templateString: "<ul class='dijitReset dijitMenu' dojoAttachEvent='onmousedown:_onMouseDown,onmouseup:_onMouseUp,onmouseover:_onMouseOver,onmouseout:_onMouseOut' tabIndex='-1' style='overflow: \"auto\"; overflow-x: \"hidden\";'>"
+ +"<li class='dijitMenuItem dijitMenuPreviousButton' dojoAttachPoint='previousButton' waiRole='option'></li>"
+ +"<li class='dijitMenuItem dijitMenuNextButton' dojoAttachPoint='nextButton' waiRole='option'></li>"
+ +"</ul>",
+
+ // _messages: Object
+ // Holds "next" and "previous" text for paging buttons on drop down
+ _messages: null,
+
+ baseClass: "dijitComboBoxMenu",
+
+ postMixInProperties: function(){
+ this._messages = dojo.i18n.getLocalization("dijit.form", "ComboBox", this.lang);
+ this.inherited(arguments);
+ },
+
+ _setValueAttr: function(/*Object*/ value){
+ this.value = value;
+ this.onChange(value);
+ },
+
+ // stubs
+ onChange: function(/*Object*/ value){
+ // summary:
+ // Notifies ComboBox/FilteringSelect that user clicked an option in the drop down menu.
+ // Probably should be called onSelect.
+ // tags:
+ // callback
+ },
+ onPage: function(/*Number*/ direction){
+ // summary:
+ // Notifies ComboBox/FilteringSelect that user clicked to advance to next/previous page.
+ // tags:
+ // callback
+ },
+
+ postCreate: function(){
+ // fill in template with i18n messages
+ this.previousButton.innerHTML = this._messages["previousMessage"];
+ this.nextButton.innerHTML = this._messages["nextMessage"];
+ this.inherited(arguments);
+ },
+
+ onClose: function(){
+ // summary:
+ // Callback from dijit.popup code to this widget, notifying it that it closed
+ // tags:
+ // private
+ this._blurOptionNode();
+ },
+
+ _createOption: function(/*Object*/ item, labelFunc){
+ // summary:
+ // Creates an option to appear on the popup menu subclassed by
+ // `dijit.form.FilteringSelect`.
+
+ var labelObject = labelFunc(item);
+ var menuitem = dojo.doc.createElement("li");
+ dijit.setWaiRole(menuitem, "option");
+ if(labelObject.html){
+ menuitem.innerHTML = labelObject.label;
+ }else{
+ menuitem.appendChild(
+ dojo.doc.createTextNode(labelObject.label)
+ );
+ }
+ // #3250: in blank options, assign a normal height
+ if(menuitem.innerHTML == ""){
+ menuitem.innerHTML = "&nbsp;";
+ }
+ menuitem.item=item;
+ return menuitem;
+ },
+
+ createOptions: function(results, dataObject, labelFunc){
+ // summary:
+ // Fills in the items in the drop down list
+ // results:
+ // Array of dojo.data items
+ // dataObject:
+ // dojo.data store
+ // labelFunc:
+ // Function to produce a label in the drop down list from a dojo.data item
+
+ //this._dataObject=dataObject;
+ //this._dataObject.onComplete=dojo.hitch(comboBox, comboBox._openResultList);
+ // display "Previous . . ." button
+ this.previousButton.style.display = (dataObject.start == 0) ? "none" : "";
+ dojo.attr(this.previousButton, "id", this.id + "_prev");
+ // create options using _createOption function defined by parent
+ // ComboBox (or FilteringSelect) class
+ // #2309:
+ // iterate over cache nondestructively
+ dojo.forEach(results, function(item, i){
+ var menuitem = this._createOption(item, labelFunc);
+ menuitem.className = "dijitReset dijitMenuItem" +
+ (this.isLeftToRight() ? "" : " dijitMenuItemRtl");
+ dojo.attr(menuitem, "id", this.id + i);
+ this.domNode.insertBefore(menuitem, this.nextButton);
+ }, this);
+ // display "Next . . ." button
+ var displayMore = false;
+ //Try to determine if we should show 'more'...
+ if(dataObject._maxOptions && dataObject._maxOptions != -1){
+ if((dataObject.start + dataObject.count) < dataObject._maxOptions){
+ displayMore = true;
+ }else if((dataObject.start + dataObject.count) > dataObject._maxOptions && dataObject.count == results.length){
+ //Weird return from a datastore, where a start + count > maxOptions
+ // implies maxOptions isn't really valid and we have to go into faking it.
+ //And more or less assume more if count == results.length
+ displayMore = true;
+ }
+ }else if(dataObject.count == results.length){
+ //Don't know the size, so we do the best we can based off count alone.
+ //So, if we have an exact match to count, assume more.
+ displayMore = true;
+ }
+
+ this.nextButton.style.display = displayMore ? "" : "none";
+ dojo.attr(this.nextButton,"id", this.id + "_next");
+ return this.domNode.childNodes;
+ },
+
+ clearResultList: function(){
+ // summary:
+ // Clears the entries in the drop down list, but of course keeps the previous and next buttons.
+ while(this.domNode.childNodes.length>2){
+ this.domNode.removeChild(this.domNode.childNodes[this.domNode.childNodes.length-2]);
+ }
+ },
+
+ _onMouseDown: function(/*Event*/ evt){
+ dojo.stopEvent(evt);
+ },
+
+ _onMouseUp: function(/*Event*/ evt){
+ if(evt.target === this.domNode || !this._highlighted_option){
+ return;
+ }else if(evt.target == this.previousButton){
+ this.onPage(-1);
+ }else if(evt.target == this.nextButton){
+ this.onPage(1);
+ }else{
+ var tgt = evt.target;
+ // while the clicked node is inside the div
+ while(!tgt.item){
+ // recurse to the top
+ tgt = tgt.parentNode;
+ }
+ this._setValueAttr({ target: tgt }, true);
+ }
+ },
+
+ _onMouseOver: function(/*Event*/ evt){
+ if(evt.target === this.domNode){ return; }
+ var tgt = evt.target;
+ if(!(tgt == this.previousButton || tgt == this.nextButton)){
+ // while the clicked node is inside the div
+ while(!tgt.item){
+ // recurse to the top
+ tgt = tgt.parentNode;
+ }
+ }
+ this._focusOptionNode(tgt);
+ },
+
+ _onMouseOut: function(/*Event*/ evt){
+ if(evt.target === this.domNode){ return; }
+ this._blurOptionNode();
+ },
+
+ _focusOptionNode: function(/*DomNode*/ node){
+ // summary:
+ // Does the actual highlight.
+ if(this._highlighted_option != node){
+ this._blurOptionNode();
+ this._highlighted_option = node;
+ dojo.addClass(this._highlighted_option, "dijitMenuItemSelected");
+ }
+ },
+
+ _blurOptionNode: function(){
+ // summary:
+ // Removes highlight on highlighted option.
+ if(this._highlighted_option){
+ dojo.removeClass(this._highlighted_option, "dijitMenuItemSelected");
+ this._highlighted_option = null;
+ }
+ },
+
+ _highlightNextOption: function(){
+ // summary:
+ // Highlight the item just below the current selection.
+ // If nothing selected, highlight first option.
+
+ // because each press of a button clears the menu,
+ // the highlighted option sometimes becomes detached from the menu!
+ // test to see if the option has a parent to see if this is the case.
+ if(!this.getHighlightedOption()){
+ var fc = this.domNode.firstChild;
+ this._focusOptionNode(fc.style.display == "none" ? fc.nextSibling : fc);
+ }else{
+ var ns = this._highlighted_option.nextSibling;
+ if(ns && ns.style.display != "none"){
+ this._focusOptionNode(ns);
+ }else{
+ this.highlightFirstOption();
+ }
+ }
+ // scrollIntoView is called outside of _focusOptionNode because in IE putting it inside causes the menu to scroll up on mouseover
+ dojo.window.scrollIntoView(this._highlighted_option);
+ },
+
+ highlightFirstOption: function(){
+ // summary:
+ // Highlight the first real item in the list (not Previous Choices).
+ var first = this.domNode.firstChild;
+ var second = first.nextSibling;
+ this._focusOptionNode(second.style.display == "none" ? first : second); // remotely possible that Previous Choices is the only thing in the list
+ dojo.window.scrollIntoView(this._highlighted_option);
+ },
+
+ highlightLastOption: function(){
+ // summary:
+ // Highlight the last real item in the list (not More Choices).
+ this._focusOptionNode(this.domNode.lastChild.previousSibling);
+ dojo.window.scrollIntoView(this._highlighted_option);
+ },
+
+ _highlightPrevOption: function(){
+ // summary:
+ // Highlight the item just above the current selection.
+ // If nothing selected, highlight last option (if
+ // you select Previous and try to keep scrolling up the list).
+ if(!this.getHighlightedOption()){
+ var lc = this.domNode.lastChild;
+ this._focusOptionNode(lc.style.display == "none" ? lc.previousSibling : lc);
+ }else{
+ var ps = this._highlighted_option.previousSibling;
+ if(ps && ps.style.display != "none"){
+ this._focusOptionNode(ps);
+ }else{
+ this.highlightLastOption();
+ }
+ }
+ dojo.window.scrollIntoView(this._highlighted_option);
+ },
+
+ _page: function(/*Boolean*/ up){
+ // summary:
+ // Handles page-up and page-down keypresses
+
+ var scrollamount = 0;
+ var oldscroll = this.domNode.scrollTop;
+ var height = dojo.style(this.domNode, "height");
+ // if no item is highlighted, highlight the first option
+ if(!this.getHighlightedOption()){
+ this._highlightNextOption();
+ }
+ while(scrollamount<height){
+ if(up){
+ // stop at option 1
+ if(!this.getHighlightedOption().previousSibling ||
+ this._highlighted_option.previousSibling.style.display == "none"){
+ break;
+ }
+ this._highlightPrevOption();
+ }else{
+ // stop at last option
+ if(!this.getHighlightedOption().nextSibling ||
+ this._highlighted_option.nextSibling.style.display == "none"){
+ break;
+ }
+ this._highlightNextOption();
+ }
+ // going backwards
+ var newscroll=this.domNode.scrollTop;
+ scrollamount+=(newscroll-oldscroll)*(up ? -1:1);
+ oldscroll=newscroll;
+ }
+ },
+
+ pageUp: function(){
+ // summary:
+ // Handles pageup keypress.
+ // TODO: just call _page directly from handleKey().
+ // tags:
+ // private
+ this._page(true);
+ },
+
+ pageDown: function(){
+ // summary:
+ // Handles pagedown keypress.
+ // TODO: just call _page directly from handleKey().
+ // tags:
+ // private
+ this._page(false);
+ },
+
+ getHighlightedOption: function(){
+ // summary:
+ // Returns the highlighted option.
+ var ho = this._highlighted_option;
+ return (ho && ho.parentNode) ? ho : null;
+ },
+
+ handleKey: function(key){
+ switch(key){
+ case dojo.keys.DOWN_ARROW:
+ this._highlightNextOption();
+ break;
+ case dojo.keys.PAGE_DOWN:
+ this.pageDown();
+ break;
+ case dojo.keys.UP_ARROW:
+ this._highlightPrevOption();
+ break;
+ case dojo.keys.PAGE_UP:
+ this.pageUp();
+ break;
+ }
+ }
+ }
+);
+
+dojo.declare(
+ "dijit.form.ComboBox",
+ [dijit.form.ValidationTextBox, dijit.form.ComboBoxMixin],
+ {
+ // summary:
+ // Auto-completing text box, and base class for dijit.form.FilteringSelect.
+ //
+ // description:
+ // The drop down box's values are populated from an class called
+ // a data provider, which returns a list of values based on the characters
+ // that the user has typed into the input box.
+ // If OPTION tags are used as the data provider via markup,
+ // then the OPTION tag's child text node is used as the widget value
+ // when selected. The OPTION tag's value attribute is ignored.
+ // To set the default value when using OPTION tags, specify the selected
+ // attribute on 1 of the child OPTION tags.
+ //
+ // Some of the options to the ComboBox are actually arguments to the data
+ // provider.
+
+ _setValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){
+ // summary:
+ // Hook so attr('value', value) works.
+ // description:
+ // Sets the value of the select.
+ this.item = null; // value not looked up in store
+ if(!value){ value = ''; } // null translates to blank
+ dijit.form.ValidationTextBox.prototype._setValueAttr.call(this, value, priorityChange, displayedValue);
+ }
+ }
+);
+
+dojo.declare("dijit.form._ComboBoxDataStore", null, {
+ // summary:
+ // Inefficient but small data store specialized for inlined `dijit.form.ComboBox` data
+ //
+ // description:
+ // Provides a store for inlined data like:
+ //
+ // | <select>
+ // | <option value="AL">Alabama</option>
+ // | ...
+ //
+ // Actually. just implements the subset of dojo.data.Read/Notification
+ // needed for ComboBox and FilteringSelect to work.
+ //
+ // Note that an item is just a pointer to the <option> DomNode.
+
+ constructor: function( /*DomNode*/ root){
+ this.root = root;
+ if(root.tagName != "SELECT" && root.firstChild){
+ root = dojo.query("select", root);
+ if(root.length > 0){ // SELECT is a child of srcNodeRef
+ root = root[0];
+ }else{ // no select, so create 1 to parent the option tags to define selectedIndex
+ this.root.innerHTML = "<SELECT>"+this.root.innerHTML+"</SELECT>";
+ root = this.root.firstChild;
+ }
+ this.root = root;
+ }
+ dojo.query("> option", root).forEach(function(node){
+ // TODO: this was added in #3858 but unclear why/if it's needed; doesn't seem to be.
+ // If it is needed then can we just hide the select itself instead?
+ //node.style.display="none";
+ node.innerHTML = dojo.trim(node.innerHTML);
+ });
+
+ },
+
+ getValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* value? */ defaultValue){
+ return (attribute == "value") ? item.value : (item.innerText || item.textContent || '');
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ return true;
+ },
+
+ getFeatures: function(){
+ return {"dojo.data.api.Read": true, "dojo.data.api.Identity": true};
+ },
+
+ _fetchItems: function( /* Object */ args,
+ /* Function */ findCallback,
+ /* Function */ errorCallback){
+ // summary:
+ // See dojo.data.util.simpleFetch.fetch()
+ if(!args.query){ args.query = {}; }
+ if(!args.query.name){ args.query.name = ""; }
+ if(!args.queryOptions){ args.queryOptions = {}; }
+ var matcher = dojo.data.util.filter.patternToRegExp(args.query.name, args.queryOptions.ignoreCase),
+ items = dojo.query("> option", this.root).filter(function(option){
+ return (option.innerText || option.textContent || '').match(matcher);
+ } );
+ if(args.sort){
+ items.sort(dojo.data.util.sorter.createSortFunction(args.sort, this));
+ }
+ findCallback(items, args);
+ },
+
+ close: function(/*dojo.data.api.Request || args || null */ request){
+ return;
+ },
+
+ getLabel: function(/* item */ item){
+ return item.innerHTML;
+ },
+
+ getIdentity: function(/* item */ item){
+ return dojo.attr(item, "value");
+ },
+
+ fetchItemByIdentity: function(/* Object */ args){
+ // summary:
+ // Given the identity of an item, this method returns the item that has
+ // that identity through the onItem callback.
+ // Refer to dojo.data.api.Identity.fetchItemByIdentity() for more details.
+ //
+ // description:
+ // Given arguments like:
+ //
+ // | {identity: "CA", onItem: function(item){...}
+ //
+ // Call `onItem()` with the DOM node `<option value="CA">California</option>`
+ var item = dojo.query("> option[value='" + args.identity + "']", this.root)[0];
+ args.onItem(item);
+ },
+
+ fetchSelectedItem: function(){
+ // summary:
+ // Get the option marked as selected, like `<option selected>`.
+ // Not part of dojo.data API.
+ var root = this.root,
+ si = root.selectedIndex;
+ return typeof si == "number"
+ ? dojo.query("> option:nth-child(" + (si != -1 ? si+1 : 1) + ")", root)[0]
+ : null; // dojo.data.Item
+ }
+});
+//Mix in the simple fetch implementation to this class.
+dojo.extend(dijit.form._ComboBoxDataStore,dojo.data.util.simpleFetch);
+
+}
+
+if(!dojo._hasResource["dijit.form.FilteringSelect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.FilteringSelect"] = true;
+dojo.provide("dijit.form.FilteringSelect");
+
+
+
+dojo.declare(
+ "dijit.form.FilteringSelect",
+ [dijit.form.MappedTextBox, dijit.form.ComboBoxMixin],
+ {
+ // summary:
+ // An enhanced version of the HTML SELECT tag, populated dynamically
+ //
+ // description:
+ // An enhanced version of the HTML SELECT tag, populated dynamically. It works
+ // very nicely with very large data sets because it can load and page data as needed.
+ // It also resembles ComboBox, but does not allow values outside of the provided ones.
+ // If OPTION tags are used as the data provider via markup, then the
+ // OPTION tag's child text node is used as the displayed value when selected
+ // while the OPTION tag's value attribute is used as the widget value on form submit.
+ // To set the default value when using OPTION tags, specify the selected
+ // attribute on 1 of the child OPTION tags.
+ //
+ // Similar features:
+ // - There is a drop down list of possible values.
+ // - You can only enter a value from the drop down list. (You can't
+ // enter an arbitrary value.)
+ // - The value submitted with the form is the hidden value (ex: CA),
+ // not the displayed value a.k.a. label (ex: California)
+ //
+ // Enhancements over plain HTML version:
+ // - If you type in some text then it will filter down the list of
+ // possible values in the drop down list.
+ // - List can be specified either as a static list or via a javascript
+ // function (that can get the list from a server)
+
+ _isvalid: true,
+
+ // required: Boolean
+ // True (default) if user is required to enter a value into this field.
+ required: true,
+
+ _lastDisplayedValue: "",
+
+ isValid: function(){
+ // Overrides ValidationTextBox.isValid()
+ return this._isvalid || (!this.required && this.get('displayedValue') == ""); // #5974
+ },
+
+ _refreshState: function(){
+ if(!this.searchTimer){ // state will be refreshed after results are returned
+ this.inherited(arguments);
+ }
+ },
+
+ _callbackSetLabel: function( /*Array*/ result,
+ /*Object*/ dataObject,
+ /*Boolean?*/ priorityChange){
+ // summary:
+ // Callback function that dynamically sets the label of the
+ // ComboBox
+
+ // setValue does a synchronous lookup,
+ // so it calls _callbackSetLabel directly,
+ // and so does not pass dataObject
+ // still need to test against _lastQuery in case it came too late
+ if((dataObject && dataObject.query[this.searchAttr] != this._lastQuery) || (!dataObject && result.length && this.store.getIdentity(result[0]) != this._lastQuery)){
+ return;
+ }
+ if(!result.length){
+ //#3268: do nothing on bad input
+ //#3285: change CSS to indicate error
+ this.valueNode.value = "";
+ dijit.form.TextBox.superclass._setValueAttr.call(this, "", priorityChange || (priorityChange === undefined && !this._focused));
+ this._isvalid = false;
+ this.validate(this._focused);
+ this.item = null;
+ }else{
+ this.set('item', result[0], priorityChange);
+ }
+ },
+
+ _openResultList: function(/*Object*/ results, /*Object*/ dataObject){
+ // Overrides ComboBox._openResultList()
+
+ // #3285: tap into search callback to see if user's query resembles a match
+ if(dataObject.query[this.searchAttr] != this._lastQuery){
+ return;
+ }
+ if(this.item === undefined){ // item == undefined for keyboard search
+ this._isvalid = results.length != 0 || this._maxOptions != 0; // result.length==0 && maxOptions != 0 implies the nextChoices item selected but then the datastore returned 0 more entries
+ this.validate(true);
+ }
+ dijit.form.ComboBoxMixin.prototype._openResultList.apply(this, arguments);
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // Hook for attr('value') to work.
+
+ // don't get the textbox value but rather the previously set hidden value.
+ // Use this.valueNode.value which isn't always set for other MappedTextBox widgets until blur
+ return this.valueNode.value;
+ },
+
+ _getValueField: function(){
+ // Overrides ComboBox._getValueField()
+ return "value";
+ },
+
+ _setValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange){
+ // summary:
+ // Hook so attr('value', value) works.
+ // description:
+ // Sets the value of the select.
+ // Also sets the label to the corresponding value by reverse lookup.
+ if(!this._onChangeActive){ priorityChange = null; }
+ this._lastQuery = value;
+
+ if(value === null || value === ''){
+ this._setDisplayedValueAttr('', priorityChange);
+ return;
+ }
+
+ //#3347: fetchItemByIdentity if no keyAttr specified
+ var self = this;
+ this.store.fetchItemByIdentity({
+ identity: value,
+ onItem: function(item){
+ self._callbackSetLabel(item? [item] : [], undefined, priorityChange);
+ }
+ });
+ },
+
+ _setItemAttr: function(/*item*/ item, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){
+ // summary:
+ // Set the displayed valued in the input box, and the hidden value
+ // that gets submitted, based on a dojo.data store item.
+ // description:
+ // Users shouldn't call this function; they should be calling
+ // attr('item', value)
+ // tags:
+ // private
+ this._isvalid = true;
+ this.inherited(arguments);
+ this.valueNode.value = this.value;
+ this._lastDisplayedValue = this.textbox.value;
+ },
+
+ _getDisplayQueryString: function(/*String*/ text){
+ return text.replace(/([\\\*\?])/g, "\\$1");
+ },
+
+ _setDisplayedValueAttr: function(/*String*/ label, /*Boolean?*/ priorityChange){
+ // summary:
+ // Hook so attr('displayedValue', label) works.
+ // description:
+ // Sets textbox to display label. Also performs reverse lookup
+ // to set the hidden value.
+
+ // When this is called during initialization it'll ping the datastore
+ // for reverse lookup, and when that completes (after an XHR request)
+ // will call setValueAttr()... but that shouldn't trigger an onChange()
+ // event, even when it happens after creation has finished
+ if(!this._created){
+ priorityChange = false;
+ }
+
+ if(this.store){
+ this._hideResultList();
+ var query = dojo.clone(this.query); // #6196: populate query with user-specifics
+ // escape meta characters of dojo.data.util.filter.patternToRegExp().
+ this._lastQuery = query[this.searchAttr] = this._getDisplayQueryString(label);
+ // if the label is not valid, the callback will never set it,
+ // so the last valid value will get the warning textbox set the
+ // textbox value now so that the impending warning will make
+ // sense to the user
+ this.textbox.value = label;
+ this._lastDisplayedValue = label;
+ var _this = this;
+ var fetch = {
+ query: query,
+ queryOptions: {
+ ignoreCase: this.ignoreCase,
+ deep: true
+ },
+ onComplete: function(result, dataObject){
+ _this._fetchHandle = null;
+ dojo.hitch(_this, "_callbackSetLabel")(result, dataObject, priorityChange);
+ },
+ onError: function(errText){
+ _this._fetchHandle = null;
+ console.error('dijit.form.FilteringSelect: ' + errText);
+ dojo.hitch(_this, "_callbackSetLabel")([], undefined, false);
+ }
+ };
+ dojo.mixin(fetch, this.fetchProperties);
+ this._fetchHandle = this.store.fetch(fetch);
+ }
+ },
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this._isvalid = !this.required;
+ },
+
+ undo: function(){
+ this.set('displayedValue', this._lastDisplayedValue);
+ }
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit.form.Form"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.Form"] = true;
+dojo.provide("dijit.form.Form");
+
+
+
+
+
+dojo.declare(
+ "dijit.form.Form",
+ [dijit._Widget, dijit._Templated, dijit.form._FormMixin],
+ {
+ // summary:
+ // Widget corresponding to HTML form tag, for validation and serialization
+ //
+ // example:
+ // | <form dojoType="dijit.form.Form" id="myForm">
+ // | Name: <input type="text" name="name" />
+ // | </form>
+ // | myObj = {name: "John Doe"};
+ // | dijit.byId('myForm').set('value', myObj);
+ // |
+ // | myObj=dijit.byId('myForm').get('value');
+
+ // HTML <FORM> attributes
+
+ // name: String?
+ // Name of form for scripting.
+ name: "",
+
+ // action: String?
+ // Server-side form handler.
+ action: "",
+
+ // method: String?
+ // HTTP method used to submit the form, either "GET" or "POST".
+ method: "",
+
+ // encType: String?
+ // Encoding type for the form, ex: application/x-www-form-urlencoded.
+ encType: "",
+
+ // accept-charset: String?
+ // List of supported charsets.
+ "accept-charset": "",
+
+ // accept: String?
+ // List of MIME types for file upload.
+ accept: "",
+
+ // target: String?
+ // Target frame for the document to be opened in.
+ target: "",
+
+ templateString: "<form dojoAttachPoint='containerNode' dojoAttachEvent='onreset:_onReset,onsubmit:_onSubmit' ${!nameAttrSetting}></form>",
+
+ attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+ action: "",
+ method: "",
+ encType: "",
+ "accept-charset": "",
+ accept: "",
+ target: ""
+ }),
+
+ postMixInProperties: function(){
+ // Setup name=foo string to be referenced from the template (but only if a name has been specified)
+ // Unfortunately we can't use attributeMap to set the name due to IE limitations, see #8660
+ this.nameAttrSetting = this.name ? ("name='" + this.name + "'") : "";
+ this.inherited(arguments);
+ },
+
+ execute: function(/*Object*/ formContents){
+ // summary:
+ // Deprecated: use submit()
+ // tags:
+ // deprecated
+ },
+
+ onExecute: function(){
+ // summary:
+ // Deprecated: use onSubmit()
+ // tags:
+ // deprecated
+ },
+
+ _setEncTypeAttr: function(/*String*/ value){
+ this.encType = value;
+ dojo.attr(this.domNode, "encType", value);
+ if(dojo.isIE){ this.domNode.encoding = value; }
+ },
+
+ postCreate: function(){
+ // IE tries to hide encType
+ // TODO: this code should be in parser, not here.
+ if(dojo.isIE && this.srcNodeRef && this.srcNodeRef.attributes){
+ var item = this.srcNodeRef.attributes.getNamedItem('encType');
+ if(item && !item.specified && (typeof item.value == "string")){
+ this.set('encType', item.value);
+ }
+ }
+ this.inherited(arguments);
+ },
+
+ reset: function(/*Event?*/ e){
+ // summary:
+ // restores all widget values back to their init values,
+ // calls onReset() which can cancel the reset by returning false
+
+ // create fake event so we can know if preventDefault() is called
+ var faux = {
+ returnValue: true, // the IE way
+ preventDefault: function(){ // not IE
+ this.returnValue = false;
+ },
+ stopPropagation: function(){},
+ currentTarget: e ? e.target : this.domNode,
+ target: e ? e.target : this.domNode
+ };
+ // if return value is not exactly false, and haven't called preventDefault(), then reset
+ if(!(this.onReset(faux) === false) && faux.returnValue){
+ this.inherited(arguments, []);
+ }
+ },
+
+ onReset: function(/*Event?*/ e){
+ // summary:
+ // Callback when user resets the form. This method is intended
+ // to be over-ridden. When the `reset` method is called
+ // programmatically, the return value from `onReset` is used
+ // to compute whether or not resetting should proceed
+ // tags:
+ // callback
+ return true; // Boolean
+ },
+
+ _onReset: function(e){
+ this.reset(e);
+ dojo.stopEvent(e);
+ return false;
+ },
+
+ _onSubmit: function(e){
+ var fp = dijit.form.Form.prototype;
+ // TODO: remove this if statement beginning with 2.0
+ if(this.execute != fp.execute || this.onExecute != fp.onExecute){
+ dojo.deprecated("dijit.form.Form:execute()/onExecute() are deprecated. Use onSubmit() instead.", "", "2.0");
+ this.onExecute();
+ this.execute(this.getValues());
+ }
+ if(this.onSubmit(e) === false){ // only exactly false stops submit
+ dojo.stopEvent(e);
+ }
+ },
+
+ onSubmit: function(/*Event?*/e){
+ // summary:
+ // Callback when user submits the form.
+ // description:
+ // This method is intended to be over-ridden, but by default it checks and
+ // returns the validity of form elements. When the `submit`
+ // method is called programmatically, the return value from
+ // `onSubmit` is used to compute whether or not submission
+ // should proceed
+ // tags:
+ // extension
+
+ return this.isValid(); // Boolean
+ },
+
+ submit: function(){
+ // summary:
+ // programmatically submit form if and only if the `onSubmit` returns true
+ if(!(this.onSubmit() === false)){
+ this.containerNode.submit();
+ }
+ }
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit.form.RadioButton"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.RadioButton"] = true;
+dojo.provide("dijit.form.RadioButton");
+
+
+// TODO: for 2.0, move the RadioButton code into this file
+
+}
+
+if(!dojo._hasResource["dijit.form._FormSelectWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form._FormSelectWidget"] = true;
+dojo.provide("dijit.form._FormSelectWidget");
+
+
+
+
+/*=====
+dijit.form.__SelectOption = function(){
+ // value: String
+ // The value of the option. Setting to empty (or missing) will
+ // place a separator at that location
+ // label: String
+ // The label for our option. It can contain html tags.
+ // selected: Boolean
+ // Whether or not we are a selected option
+ // disabled: Boolean
+ // Whether or not this specific option is disabled
+ this.value = value;
+ this.label = label;
+ this.selected = selected;
+ this.disabled = disabled;
+}
+=====*/
+
+dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
+ // summary:
+ // Extends _FormValueWidget in order to provide "select-specific"
+ // values - i.e., those values that are unique to <select> elements.
+ // This also provides the mechanism for reading the elements from
+ // a store, if desired.
+
+ // multiple: Boolean
+ // Whether or not we are multi-valued
+ multiple: false,
+
+ // options: dijit.form.__SelectOption[]
+ // The set of options for our select item. Roughly corresponds to
+ // the html <option> tag.
+ options: null,
+
+ // store: dojo.data.api.Identity
+ // A store which, at the very least impelements dojo.data.api.Identity
+ // to use for getting our list of options - rather than reading them
+ // from the <option> html tags.
+ store: null,
+
+ // query: object
+ // A query to use when fetching items from our store
+ query: null,
+
+ // queryOptions: object
+ // Query options to use when fetching from the store
+ queryOptions: null,
+
+ // onFetch: Function
+ // A callback to do with an onFetch - but before any items are actually
+ // iterated over (i.e. to filter even futher what you want to add)
+ onFetch: null,
+
+ // sortByLabel: boolean
+ // Flag to sort the options returned from a store by the label of
+ // the store.
+ sortByLabel: true,
+
+
+ // loadChildrenOnOpen: boolean
+ // By default loadChildren is called when the items are fetched from the
+ // store. This property allows delaying loadChildren (and the creation
+ // of the options/menuitems) until the user opens the click the button.
+ // dropdown
+ loadChildrenOnOpen: false,
+
+ getOptions: function(/* anything */ valueOrIdx){
+ // summary:
+ // Returns a given option (or options).
+ // valueOrIdx:
+ // If passed in as a string, that string is used to look up the option
+ // in the array of options - based on the value property.
+ // (See dijit.form.__SelectOption).
+ //
+ // If passed in a number, then the option with the given index (0-based)
+ // within this select will be returned.
+ //
+ // If passed in a dijit.form.__SelectOption, the same option will be
+ // returned if and only if it exists within this select.
+ //
+ // If passed an array, then an array will be returned with each element
+ // in the array being looked up.
+ //
+ // If not passed a value, then all options will be returned
+ //
+ // returns:
+ // The option corresponding with the given value or index. null
+ // is returned if any of the following are true:
+ // - A string value is passed in which doesn't exist
+ // - An index is passed in which is outside the bounds of the array of options
+ // - A dijit.form.__SelectOption is passed in which is not a part of the select
+
+ // NOTE: the compare for passing in a dijit.form.__SelectOption checks
+ // if the value property matches - NOT if the exact option exists
+ // NOTE: if passing in an array, null elements will be placed in the returned
+ // array when a value is not found.
+ var lookupValue = valueOrIdx, opts = this.options || [], l = opts.length;
+
+ if(lookupValue === undefined){
+ return opts; // dijit.form.__SelectOption[]
+ }
+ if(dojo.isArray(lookupValue)){
+ return dojo.map(lookupValue, "return this.getOptions(item);", this); // dijit.form.__SelectOption[]
+ }
+ if(dojo.isObject(valueOrIdx)){
+ // We were passed an option - so see if it's in our array (directly),
+ // and if it's not, try and find it by value.
+ if(!dojo.some(this.options, function(o, idx){
+ if(o === lookupValue ||
+ (o.value && o.value === lookupValue.value)){
+ lookupValue = idx;
+ return true;
+ }
+ return false;
+ })){
+ lookupValue = -1;
+ }
+ }
+ if(typeof lookupValue == "string"){
+ for(var i=0; i<l; i++){
+ if(opts[i].value === lookupValue){
+ lookupValue = i;
+ break;
+ }
+ }
+ }
+ if(typeof lookupValue == "number" && lookupValue >= 0 && lookupValue < l){
+ return this.options[lookupValue] // dijit.form.__SelectOption
+ }
+ return null; // null
+ },
+
+ addOption: function(/* dijit.form.__SelectOption, dijit.form.__SelectOption[] */ option){
+ // summary:
+ // Adds an option or options to the end of the select. If value
+ // of the option is empty or missing, a separator is created instead.
+ // Passing in an array of options will yield slightly better performance
+ // since the children are only loaded once.
+ if(!dojo.isArray(option)){ option = [option]; }
+ dojo.forEach(option, function(i){
+ if(i && dojo.isObject(i)){
+ this.options.push(i);
+ }
+ }, this);
+ this._loadChildren();
+ },
+
+ removeOption: function(/* string, dijit.form.__SelectOption, number, or array */ valueOrIdx){
+ // summary:
+ // Removes the given option or options. You can remove by string
+ // (in which case the value is removed), number (in which case the
+ // index in the options array is removed), or select option (in
+ // which case, the select option with a matching value is removed).
+ // You can also pass in an array of those values for a slightly
+ // better performance since the children are only loaded once.
+ if(!dojo.isArray(valueOrIdx)){ valueOrIdx = [valueOrIdx]; }
+ var oldOpts = this.getOptions(valueOrIdx);
+ dojo.forEach(oldOpts, function(i){
+ // We can get null back in our array - if our option was not found. In
+ // that case, we don't want to blow up...
+ if(i){
+ this.options = dojo.filter(this.options, function(node, idx){
+ return (node.value !== i.value);
+ });
+ this._removeOptionItem(i);
+ }
+ }, this);
+ this._loadChildren();
+ },
+
+ updateOption: function(/* dijit.form.__SelectOption, dijit.form.__SelectOption[] */ newOption){
+ // summary:
+ // Updates the values of the given option. The option to update
+ // is matched based on the value of the entered option. Passing
+ // in an array of new options will yeild better performance since
+ // the children will only be loaded once.
+ if(!dojo.isArray(newOption)){ newOption = [newOption]; }
+ dojo.forEach(newOption, function(i){
+ var oldOpt = this.getOptions(i), k;
+ if(oldOpt){
+ for(k in i){ oldOpt[k] = i[k]; }
+ }
+ }, this);
+ this._loadChildren();
+ },
+
+ setStore: function(/* dojo.data.api.Identity */ store,
+ /* anything? */ selectedValue,
+ /* Object? */ fetchArgs){
+ // summary:
+ // Sets the store you would like to use with this select widget.
+ // The selected value is the value of the new store to set. This
+ // function returns the original store, in case you want to reuse
+ // it or something.
+ // store: dojo.data.api.Identity
+ // The store you would like to use - it MUST implement Identity,
+ // and MAY implement Notification.
+ // selectedValue: anything?
+ // The value that this widget should set itself to *after* the store
+ // has been loaded
+ // fetchArgs: Object?
+ // The arguments that will be passed to the store's fetch() function
+ var oStore = this.store;
+ fetchArgs = fetchArgs || {};
+ if(oStore !== store){
+ // Our store has changed, so update our notifications
+ dojo.forEach(this._notifyConnections || [], dojo.disconnect);
+ delete this._notifyConnections;
+ if(store && store.getFeatures()["dojo.data.api.Notification"]){
+ this._notifyConnections = [
+ dojo.connect(store, "onNew", this, "_onNewItem"),
+ dojo.connect(store, "onDelete", this, "_onDeleteItem"),
+ dojo.connect(store, "onSet", this, "_onSetItem")
+ ];
+ }
+ this.store = store;
+ }
+
+ // Turn off change notifications while we make all these changes
+ this._onChangeActive = false;
+
+ // Remove existing options (if there are any)
+ if(this.options && this.options.length){
+ this.removeOption(this.options);
+ }
+
+ // Add our new options
+ if(store){
+ var cb = function(items){
+ if(this.sortByLabel && !fetchArgs.sort && items.length){
+ items.sort(dojo.data.util.sorter.createSortFunction([{
+ attribute: store.getLabelAttributes(items[0])[0]
+ }], store));
+ }
+
+ if(fetchArgs.onFetch){
+ items = fetchArgs.onFetch(items);
+ }
+ // TODO: Add these guys as a batch, instead of separately
+ dojo.forEach(items, function(i){
+ this._addOptionForItem(i);
+ }, this);
+
+ // Set our value (which might be undefined), and then tweak
+ // it to send a change event with the real value
+ this._loadingStore = false;
+ this.set("value", (("_pendingValue" in this) ? this._pendingValue : selectedValue));
+ delete this._pendingValue;
+
+ if(!this.loadChildrenOnOpen){
+ this._loadChildren();
+ }else{
+ this._pseudoLoadChildren(items);
+ }
+ this._fetchedWith = opts;
+ this._lastValueReported = this.multiple ? [] : null;
+ this._onChangeActive = true;
+ this.onSetStore();
+ this._handleOnChange(this.value);
+ };
+ var opts = dojo.mixin({onComplete:cb, scope: this}, fetchArgs);
+ this._loadingStore = true;
+ store.fetch(opts);
+ }else{
+ delete this._fetchedWith;
+ }
+ return oStore; // dojo.data.api.Identity
+ },
+
+ _setValueAttr: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
+ // summary:
+ // set the value of the widget.
+ // If a string is passed, then we set our value from looking it up.
+ if(this._loadingStore){
+ // Our store is loading - so save our value, and we'll set it when
+ // we're done
+ this._pendingValue = newValue;
+ return;
+ }
+ var opts = this.getOptions() || [];
+ if(!dojo.isArray(newValue)){
+ newValue = [newValue];
+ }
+ dojo.forEach(newValue, function(i, idx){
+ if(!dojo.isObject(i)){
+ i = i + "";
+ }
+ if(typeof i === "string"){
+ newValue[idx] = dojo.filter(opts, function(node){
+ return node.value === i;
+ })[0] || {value: "", label: ""};
+ }
+ }, this);
+
+ // Make sure some sane default is set
+ newValue = dojo.filter(newValue, function(i){ return i && i.value; });
+ if(!this.multiple && (!newValue[0] || !newValue[0].value) && opts.length){
+ newValue[0] = opts[0];
+ }
+ dojo.forEach(opts, function(i){
+ i.selected = dojo.some(newValue, function(v){ return v.value === i.value; });
+ });
+ var val = dojo.map(newValue, function(i){ return i.value; }),
+ disp = dojo.map(newValue, function(i){ return i.label; });
+
+ this.value = this.multiple ? val : val[0];
+ this._setDisplay(this.multiple ? disp : disp[0]);
+ this._updateSelection();
+ this._handleOnChange(this.value, priorityChange);
+ },
+
+ _getDisplayedValueAttr: function(){
+ // summary:
+ // returns the displayed value of the widget
+ var val = this.get("value");
+ if(!dojo.isArray(val)){
+ val = [val];
+ }
+ var ret = dojo.map(this.getOptions(val), function(v){
+ if(v && "label" in v){
+ return v.label;
+ }else if(v){
+ return v.value;
+ }
+ return null;
+ }, this);
+ return this.multiple ? ret : ret[0];
+ },
+
+ _getValueDeprecated: false, // remove when _FormWidget:getValue is removed
+ getValue: function(){
+ // summary:
+ // get the value of the widget.
+ return this._lastValue;
+ },
+
+ undo: function(){
+ // summary:
+ // restore the value to the last value passed to onChange
+ this._setValueAttr(this._lastValueReported, false);
+ },
+
+ _loadChildren: function(){
+ // summary:
+ // Loads the children represented by this widget's options.
+ // reset the menu to make it "populatable on the next click
+ if(this._loadingStore){ return; }
+ dojo.forEach(this._getChildren(), function(child){
+ child.destroyRecursive();
+ });
+ // Add each menu item
+ dojo.forEach(this.options, this._addOptionItem, this);
+
+ // Update states
+ this._updateSelection();
+ },
+
+ _updateSelection: function(){
+ // summary:
+ // Sets the "selected" class on the item for styling purposes
+ this.value = this._getValueFromOpts();
+ var val = this.value;
+ if(!dojo.isArray(val)){
+ val = [val];
+ }
+ if(val && val[0]){
+ dojo.forEach(this._getChildren(), function(child){
+ var isSelected = dojo.some(val, function(v){
+ return child.option && (v === child.option.value);
+ });
+ dojo.toggleClass(child.domNode, this.baseClass + "SelectedOption", isSelected);
+ dijit.setWaiState(child.domNode, "selected", isSelected);
+ }, this);
+ }
+ this._handleOnChange(this.value);
+ },
+
+ _getValueFromOpts: function(){
+ // summary:
+ // Returns the value of the widget by reading the options for
+ // the selected flag
+ var opts = this.getOptions() || [];
+ if(!this.multiple && opts.length){
+ // Mirror what a select does - choose the first one
+ var opt = dojo.filter(opts, function(i){
+ return i.selected;
+ })[0];
+ if(opt && opt.value){
+ return opt.value
+ }else{
+ opts[0].selected = true;
+ return opts[0].value;
+ }
+ }else if(this.multiple){
+ // Set value to be the sum of all selected
+ return dojo.map(dojo.filter(opts, function(i){
+ return i.selected;
+ }), function(i){
+ return i.value;
+ }) || [];
+ }
+ return "";
+ },
+
+ // Internal functions to call when we have store notifications come in
+ _onNewItem: function(/* item */ item, /* Object? */ parentInfo){
+ if(!parentInfo || !parentInfo.parent){
+ // Only add it if we are top-level
+ this._addOptionForItem(item);
+ }
+ },
+ _onDeleteItem: function(/* item */ item){
+ var store = this.store;
+ this.removeOption(store.getIdentity(item));
+ },
+ _onSetItem: function(/* item */ item){
+ this.updateOption(this._getOptionObjForItem(item));
+ },
+
+ _getOptionObjForItem: function(item){
+ // summary:
+ // Returns an option object based off the given item. The "value"
+ // of the option item will be the identity of the item, the "label"
+ // of the option will be the label of the item. If the item contains
+ // children, the children value of the item will be set
+ var store = this.store, label = store.getLabel(item),
+ value = (label ? store.getIdentity(item) : null);
+ return {value: value, label: label, item:item}; // dijit.form.__SelectOption
+ },
+
+ _addOptionForItem: function(/* item */ item){
+ // summary:
+ // Creates (and adds) the option for the given item
+ var store = this.store;
+ if(!store.isItemLoaded(item)){
+ // We are not loaded - so let's load it and add later
+ store.loadItem({item: item, onComplete: function(i){
+ this._addOptionForItem(item);
+ },
+ scope: this});
+ return;
+ }
+ var newOpt = this._getOptionObjForItem(item);
+ this.addOption(newOpt);
+ },
+
+ constructor: function(/* Object */ keywordArgs){
+ // summary:
+ // Saves off our value, if we have an initial one set so we
+ // can use it if we have a store as well (see startup())
+ this._oValue = (keywordArgs || {}).value || null;
+ },
+
+ _fillContent: function(){
+ // summary:
+ // Loads our options and sets up our dropdown correctly. We
+ // don't want any content, so we don't call any inherit chain
+ // function.
+ var opts = this.options;
+ if(!opts){
+ opts = this.options = this.srcNodeRef ? dojo.query(">",
+ this.srcNodeRef).map(function(node){
+ if(node.getAttribute("type") === "separator"){
+ return { value: "", label: "", selected: false, disabled: false };
+ }
+ return { value: node.getAttribute("value"),
+ label: String(node.innerHTML),
+ selected: node.getAttribute("selected") || false,
+ disabled: node.getAttribute("disabled") || false };
+ }, this) : [];
+ }
+ if(!this.value){
+ this.value = this._getValueFromOpts();
+ }else if(this.multiple && typeof this.value == "string"){
+ this.value = this.value.split(",");
+ }
+ },
+
+ postCreate: function(){
+ // summary:
+ // sets up our event handling that we need for functioning
+ // as a select
+ dojo.setSelectable(this.focusNode, false);
+ this.inherited(arguments);
+
+ // Make our event connections for updating state
+ this.connect(this, "onChange", "_updateSelection");
+ this.connect(this, "startup", "_loadChildren");
+
+ this._setValueAttr(this.value, null);
+ },
+
+ startup: function(){
+ // summary:
+ // Connects in our store, if we have one defined
+ this.inherited(arguments);
+ var store = this.store, fetchArgs = {};
+ dojo.forEach(["query", "queryOptions", "onFetch"], function(i){
+ if(this[i]){
+ fetchArgs[i] = this[i];
+ }
+ delete this[i];
+ }, this);
+ if(store && store.getFeatures()["dojo.data.api.Identity"]){
+ // Temporarily set our store to null so that it will get set
+ // and connected appropriately
+ this.store = null;
+ this.setStore(store, this._oValue, fetchArgs);
+ }
+ },
+
+ destroy: function(){
+ // summary:
+ // Clean up our connections
+ dojo.forEach(this._notifyConnections || [], dojo.disconnect);
+ this.inherited(arguments);
+ },
+
+ _addOptionItem: function(/* dijit.form.__SelectOption */ option){
+ // summary:
+ // User-overridable function which, for the given option, adds an
+ // item to the select. If the option doesn't have a value, then a
+ // separator is added in that place. Make sure to store the option
+ // in the created option widget.
+ },
+
+ _removeOptionItem: function(/* dijit.form.__SelectOption */ option){
+ // summary:
+ // User-overridable function which, for the given option, removes
+ // its item from the select.
+ },
+
+ _setDisplay: function(/*String or String[]*/ newDisplay){
+ // summary:
+ // Overridable function which will set the display for the
+ // widget. newDisplay is either a string (in the case of
+ // single selects) or array of strings (in the case of multi-selects)
+ },
+
+ _getChildren: function(){
+ // summary:
+ // Overridable function to return the children that this widget contains.
+ return [];
+ },
+
+ _getSelectedOptionsAttr: function(){
+ // summary:
+ // hooks into this.attr to provide a mechanism for getting the
+ // option items for the current value of the widget.
+ return this.getOptions(this.get("value"));
+ },
+
+ _pseudoLoadChildren: function(/* item[] */ items){
+ // summary:
+ // a function that will "fake" loading children, if needed, and
+ // if we have set to not load children until the widget opens.
+ // items:
+ // An array of items that will be loaded, when needed
+ },
+
+ onSetStore: function(){
+ // summary:
+ // a function that can be connected to in order to receive a
+ // notification that the store has finished loading and all options
+ // from that store are available
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit._KeyNavContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._KeyNavContainer"] = true;
+dojo.provide("dijit._KeyNavContainer");
+
+
+dojo.declare("dijit._KeyNavContainer",
+ dijit._Container,
+ {
+
+ // summary:
+ // A _Container with keyboard navigation of its children.
+ // description:
+ // To use this mixin, call connectKeyNavHandlers() in
+ // postCreate() and call startupKeyNavChildren() in startup().
+ // It provides normalized keyboard and focusing code for Container
+ // widgets.
+/*=====
+ // focusedChild: [protected] Widget
+ // The currently focused child widget, or null if there isn't one
+ focusedChild: null,
+=====*/
+
+ // tabIndex: Integer
+ // Tab index of the container; same as HTML tabIndex attribute.
+ // Note then when user tabs into the container, focus is immediately
+ // moved to the first item in the container.
+ tabIndex: "0",
+
+ _keyNavCodes: {},
+
+ connectKeyNavHandlers: function(/*dojo.keys[]*/ prevKeyCodes, /*dojo.keys[]*/ nextKeyCodes){
+ // summary:
+ // Call in postCreate() to attach the keyboard handlers
+ // to the container.
+ // preKeyCodes: dojo.keys[]
+ // Key codes for navigating to the previous child.
+ // nextKeyCodes: dojo.keys[]
+ // Key codes for navigating to the next child.
+ // tags:
+ // protected
+
+ var keyCodes = (this._keyNavCodes = {});
+ var prev = dojo.hitch(this, this.focusPrev);
+ var next = dojo.hitch(this, this.focusNext);
+ dojo.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev; });
+ dojo.forEach(nextKeyCodes, function(code){ keyCodes[code] = next; });
+ this.connect(this.domNode, "onkeypress", "_onContainerKeypress");
+ this.connect(this.domNode, "onfocus", "_onContainerFocus");
+ },
+
+ startupKeyNavChildren: function(){
+ // summary:
+ // Call in startup() to set child tabindexes to -1
+ // tags:
+ // protected
+ dojo.forEach(this.getChildren(), dojo.hitch(this, "_startupChild"));
+ },
+
+ addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
+ // summary:
+ // Add a child to our _Container
+ dijit._KeyNavContainer.superclass.addChild.apply(this, arguments);
+ this._startupChild(widget);
+ },
+
+ focus: function(){
+ // summary:
+ // Default focus() implementation: focus the first child.
+ this.focusFirstChild();
+ },
+
+ focusFirstChild: function(){
+ // summary:
+ // Focus the first focusable child in the container.
+ // tags:
+ // protected
+ var child = this._getFirstFocusableChild();
+ if(child){ // edge case: Menu could be empty or hidden
+ this.focusChild(child);
+ }
+ },
+
+ focusNext: function(){
+ // summary:
+ // Focus the next widget
+ // tags:
+ // protected
+ var child = this._getNextFocusableChild(this.focusedChild, 1);
+ this.focusChild(child);
+ },
+
+ focusPrev: function(){
+ // summary:
+ // Focus the last focusable node in the previous widget
+ // (ex: go to the ComboButton icon section rather than button section)
+ // tags:
+ // protected
+ var child = this._getNextFocusableChild(this.focusedChild, -1);
+ this.focusChild(child, true);
+ },
+
+ focusChild: function(/*dijit._Widget*/ widget, /*Boolean*/ last){
+ // summary:
+ // Focus widget.
+ // widget:
+ // Reference to container's child widget
+ // last:
+ // If true and if widget has multiple focusable nodes, focus the
+ // last one instead of the first one
+ // tags:
+ // protected
+
+ if(this.focusedChild && widget !== this.focusedChild){
+ this._onChildBlur(this.focusedChild);
+ }
+ widget.focus(last ? "end" : "start");
+ this.focusedChild = widget;
+ },
+
+ _startupChild: function(/*dijit._Widget*/ widget){
+ // summary:
+ // Setup for each child widget
+ // description:
+ // Sets tabIndex=-1 on each child, so that the tab key will
+ // leave the container rather than visiting each child.
+ // tags:
+ // private
+
+ widget.set("tabIndex", "-1");
+
+ this.connect(widget, "_onFocus", function(){
+ // Set valid tabIndex so tabbing away from widget goes to right place, see #10272
+ widget.set("tabIndex", this.tabIndex);
+ });
+ this.connect(widget, "_onBlur", function(){
+ widget.set("tabIndex", "-1");
+ });
+ },
+
+ _onContainerFocus: function(evt){
+ // summary:
+ // Handler for when the container gets focus
+ // description:
+ // Initially the container itself has a tabIndex, but when it gets
+ // focus, switch focus to first child...
+ // tags:
+ // private
+
+ // Note that we can't use _onFocus() because switching focus from the
+ // _onFocus() handler confuses the focus.js code
+ // (because it causes _onFocusNode() to be called recursively)
+
+ // focus bubbles on Firefox,
+ // so just make sure that focus has really gone to the container
+ if(evt.target !== this.domNode){ return; }
+
+ this.focusFirstChild();
+
+ // and then set the container's tabIndex to -1,
+ // (don't remove as that breaks Safari 4)
+ // so that tab or shift-tab will go to the fields after/before
+ // the container, rather than the container itself
+ dojo.attr(this.domNode, "tabIndex", "-1");
+ },
+
+ _onBlur: function(evt){
+ // When focus is moved away the container, and its descendant (popup) widgets,
+ // then restore the container's tabIndex so that user can tab to it again.
+ // Note that using _onBlur() so that this doesn't happen when focus is shifted
+ // to one of my child widgets (typically a popup)
+ if(this.tabIndex){
+ dojo.attr(this.domNode, "tabIndex", this.tabIndex);
+ }
+ this.inherited(arguments);
+ },
+
+ _onContainerKeypress: function(evt){
+ // summary:
+ // When a key is pressed, if it's an arrow key etc. then
+ // it's handled here.
+ // tags:
+ // private
+ if(evt.ctrlKey || evt.altKey){ return; }
+ var func = this._keyNavCodes[evt.charOrCode];
+ if(func){
+ func();
+ dojo.stopEvent(evt);
+ }
+ },
+
+ _onChildBlur: function(/*dijit._Widget*/ widget){
+ // summary:
+ // Called when focus leaves a child widget to go
+ // to a sibling widget.
+ // tags:
+ // protected
+ },
+
+ _getFirstFocusableChild: function(){
+ // summary:
+ // Returns first child that can be focused
+ return this._getNextFocusableChild(null, 1); // dijit._Widget
+ },
+
+ _getNextFocusableChild: function(child, dir){
+ // summary:
+ // Returns the next or previous focusable child, compared
+ // to "child"
+ // child: Widget
+ // The current widget
+ // dir: Integer
+ // * 1 = after
+ // * -1 = before
+ if(child){
+ child = this._getSiblingOfChild(child, dir);
+ }
+ var children = this.getChildren();
+ for(var i=0; i < children.length; i++){
+ if(!child){
+ child = children[(dir>0) ? 0 : (children.length-1)];
+ }
+ if(child.isFocusable()){
+ return child; // dijit._Widget
+ }
+ child = this._getSiblingOfChild(child, dir);
+ }
+ // no focusable child found
+ return null; // dijit._Widget
+ }
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit.MenuItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.MenuItem"] = true;
+dojo.provide("dijit.MenuItem");
+
+
+
+
+
+
+dojo.declare("dijit.MenuItem",
+ [dijit._Widget, dijit._Templated, dijit._Contained, dijit._CssStateMixin],
+ {
+ // summary:
+ // A line item in a Menu Widget
+
+ // Make 3 columns
+ // icon, label, and expand arrow (BiDi-dependent) indicating sub-menu
+ templateString: dojo.cache("dijit", "templates/MenuItem.html", "<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" waiRole=\"menuitem\" tabIndex=\"-1\"\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" waiRole=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" waiRole=\"presentation\">\n\t\t<div dojoAttachPoint=\"arrowWrapper\" style=\"visibility: hidden\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuExpand\"/>\n\t\t\t<span class=\"dijitMenuExpandA11y\">+</span>\n\t\t</div>\n\t</td>\n</tr>\n"),
+
+ attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+ label: { node: "containerNode", type: "innerHTML" },
+ iconClass: { node: "iconNode", type: "class" }
+ }),
+
+ baseClass: "dijitMenuItem",
+
+ // label: String
+ // Menu text
+ label: '',
+
+ // iconClass: String
+ // Class to apply to DOMNode to make it display an icon.
+ iconClass: "",
+
+ // accelKey: String
+ // Text for the accelerator (shortcut) key combination.
+ // Note that although Menu can display accelerator keys there
+ // is no infrastructure to actually catch and execute these
+ // accelerators.
+ accelKey: "",
+
+ // disabled: Boolean
+ // If true, the menu item is disabled.
+ // If false, the menu item is enabled.
+ disabled: false,
+
+ _fillContent: function(/*DomNode*/ source){
+ // If button label is specified as srcNodeRef.innerHTML rather than
+ // this.params.label, handle it here.
+ if(source && !("label" in this.params)){
+ this.set('label', source.innerHTML);
+ }
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ dojo.setSelectable(this.domNode, false);
+ var label = this.id+"_text";
+ dojo.attr(this.containerNode, "id", label);
+ if(this.accelKeyNode){
+ dojo.attr(this.accelKeyNode, "id", this.id + "_accel");
+ label += " " + this.id + "_accel";
+ }
+ dijit.setWaiState(this.domNode, "labelledby", label);
+ },
+
+ _onHover: function(){
+ // summary:
+ // Handler when mouse is moved onto menu item
+ // tags:
+ // protected
+ this.getParent().onItemHover(this);
+ },
+
+ _onUnhover: function(){
+ // summary:
+ // Handler when mouse is moved off of menu item,
+ // possibly to a child menu, or maybe to a sibling
+ // menuitem or somewhere else entirely.
+ // tags:
+ // protected
+
+ // if we are unhovering the currently selected item
+ // then unselect it
+ this.getParent().onItemUnhover(this);
+
+ // _onUnhover() is called when the menu is hidden (collapsed), due to clicking
+ // a MenuItem and having it execut. When that happens, FF and IE don't generate
+ // an onmouseout event for the MenuItem, so give _CssStateMixin some help
+ this._hovering = false;
+ this._setStateClass();
+ },
+
+ _onClick: function(evt){
+ // summary:
+ // Internal handler for click events on MenuItem.
+ // tags:
+ // private
+ this.getParent().onItemClick(this, evt);
+ dojo.stopEvent(evt);
+ },
+
+ onClick: function(/*Event*/ evt){
+ // summary:
+ // User defined function to handle clicks
+ // tags:
+ // callback
+ },
+
+ focus: function(){
+ // summary:
+ // Focus on this MenuItem
+ try{
+ if(dojo.isIE == 8){
+ // needed for IE8 which won't scroll TR tags into view on focus yet calling scrollIntoView creates flicker (#10275)
+ this.containerNode.focus();
+ }
+ dijit.focus(this.focusNode);
+ }catch(e){
+ // this throws on IE (at least) in some scenarios
+ }
+ },
+
+ _onFocus: function(){
+ // summary:
+ // This is called by the focus manager when focus
+ // goes to this MenuItem or a child menu.
+ // tags:
+ // protected
+ this._setSelected(true);
+ this.getParent()._onItemFocus(this);
+
+ this.inherited(arguments);
+ },
+
+ _setSelected: function(selected){
+ // summary:
+ // Indicate that this node is the currently selected one
+ // tags:
+ // private
+
+ /***
+ * TODO: remove this method and calls to it, when _onBlur() is working for MenuItem.
+ * Currently _onBlur() gets called when focus is moved from the MenuItem to a child menu.
+ * That's not supposed to happen, but the problem is:
+ * In order to allow dijit.popup's getTopPopup() to work,a sub menu's popupParent
+ * points to the parent Menu, bypassing the parent MenuItem... thus the
+ * MenuItem is not in the chain of active widgets and gets a premature call to
+ * _onBlur()
+ */
+
+ dojo.toggleClass(this.domNode, "dijitMenuItemSelected", selected);
+ },
+
+ setLabel: function(/*String*/ content){
+ // summary:
+ // Deprecated. Use set('label', ...) instead.
+ // tags:
+ // deprecated
+ dojo.deprecated("dijit.MenuItem.setLabel() is deprecated. Use set('label', ...) instead.", "", "2.0");
+ this.set("label", content);
+ },
+
+ setDisabled: function(/*Boolean*/ disabled){
+ // summary:
+ // Deprecated. Use set('disabled', bool) instead.
+ // tags:
+ // deprecated
+ dojo.deprecated("dijit.Menu.setDisabled() is deprecated. Use set('disabled', bool) instead.", "", "2.0");
+ this.set('disabled', disabled);
+ },
+ _setDisabledAttr: function(/*Boolean*/ value){
+ // summary:
+ // Hook for attr('disabled', ...) to work.
+ // Enable or disable this menu item.
+ this.disabled = value;
+ dijit.setWaiState(this.focusNode, 'disabled', value ? 'true' : 'false');
+ },
+ _setAccelKeyAttr: function(/*String*/ value){
+ // summary:
+ // Hook for attr('accelKey', ...) to work.
+ // Set accelKey on this menu item.
+ this.accelKey=value;
+
+ this.accelKeyNode.style.display=value?"":"none";
+ this.accelKeyNode.innerHTML=value;
+ //have to use colSpan to make it work in IE
+ dojo.attr(this.containerNode,'colSpan',value?"1":"2");
+ }
+ });
+
+}
+
+if(!dojo._hasResource["dijit.PopupMenuItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.PopupMenuItem"] = true;
+dojo.provide("dijit.PopupMenuItem");
+
+
+
+dojo.declare("dijit.PopupMenuItem",
+ dijit.MenuItem,
+ {
+ _fillContent: function(){
+ // summary:
+ // When Menu is declared in markup, this code gets the menu label and
+ // the popup widget from the srcNodeRef.
+ // description:
+ // srcNodeRefinnerHTML contains both the menu item text and a popup widget
+ // The first part holds the menu item text and the second part is the popup
+ // example:
+ // | <div dojoType="dijit.PopupMenuItem">
+ // | <span>pick me</span>
+ // | <popup> ... </popup>
+ // | </div>
+ // tags:
+ // protected
+
+ if(this.srcNodeRef){
+ var nodes = dojo.query("*", this.srcNodeRef);
+ dijit.PopupMenuItem.superclass._fillContent.call(this, nodes[0]);
+
+ // save pointer to srcNode so we can grab the drop down widget after it's instantiated
+ this.dropDownContainer = this.srcNodeRef;
+ }
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+ this.inherited(arguments);
+
+ // we didn't copy the dropdown widget from the this.srcNodeRef, so it's in no-man's
+ // land now. move it to dojo.doc.body.
+ if(!this.popup){
+ var node = dojo.query("[widgetId]", this.dropDownContainer)[0];
+ this.popup = dijit.byNode(node);
+ }
+ dojo.body().appendChild(this.popup.domNode);
+ this.popup.startup();
+
+ this.popup.domNode.style.display="none";
+ if(this.arrowWrapper){
+ dojo.style(this.arrowWrapper, "visibility", "");
+ }
+ dijit.setWaiState(this.focusNode, "haspopup", "true");
+ },
+
+ destroyDescendants: function(){
+ if(this.popup){
+ // Destroy the popup, unless it's already been destroyed. This can happen because
+ // the popup is a direct child of <body> even though it's logically my child.
+ if(!this.popup._destroyed){
+ this.popup.destroyRecursive();
+ }
+ delete this.popup;
+ }
+ this.inherited(arguments);
+ }
+ });
+
+
+}
+
+if(!dojo._hasResource["dijit.CheckedMenuItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.CheckedMenuItem"] = true;
+dojo.provide("dijit.CheckedMenuItem");
+
+
+
+dojo.declare("dijit.CheckedMenuItem",
+ dijit.MenuItem,
+ {
+ // summary:
+ // A checkbox-like menu item for toggling on and off
+
+ templateString: dojo.cache("dijit", "templates/CheckedMenuItem.html", "<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" waiRole=\"menuitemcheckbox\" tabIndex=\"-1\"\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" waiRole=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuItemIcon dijitCheckedMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\n\t\t<span class=\"dijitCheckedMenuItemIconChar\">&#10003;</span>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode,labelNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" waiRole=\"presentation\">&nbsp;</td>\n</tr>\n"),
+
+ // checked: Boolean
+ // Our checked state
+ checked: false,
+ _setCheckedAttr: function(/*Boolean*/ checked){
+ // summary:
+ // Hook so attr('checked', bool) works.
+ // Sets the class and state for the check box.
+ dojo.toggleClass(this.domNode, "dijitCheckedMenuItemChecked", checked);
+ dijit.setWaiState(this.domNode, "checked", checked);
+ this.checked = checked;
+ },
+
+ onChange: function(/*Boolean*/ checked){
+ // summary:
+ // User defined function to handle check/uncheck events
+ // tags:
+ // callback
+ },
+
+ _onClick: function(/*Event*/ e){
+ // summary:
+ // Clicking this item just toggles its state
+ // tags:
+ // private
+ if(!this.disabled){
+ this.set("checked", !this.checked);
+ this.onChange(this.checked);
+ }
+ this.inherited(arguments);
+ }
+ });
+
+}
+
+if(!dojo._hasResource["dijit.MenuSeparator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.MenuSeparator"] = true;
+dojo.provide("dijit.MenuSeparator");
+
+
+
+
+
+dojo.declare("dijit.MenuSeparator",
+ [dijit._Widget, dijit._Templated, dijit._Contained],
+ {
+ // summary:
+ // A line between two menu items
+
+ templateString: dojo.cache("dijit", "templates/MenuSeparator.html", "<tr class=\"dijitMenuSeparator\">\n\t<td class=\"dijitMenuSeparatorIconCell\">\n\t\t<div class=\"dijitMenuSeparatorTop\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n\t<td colspan=\"3\" class=\"dijitMenuSeparatorLabelCell\">\n\t\t<div class=\"dijitMenuSeparatorTop dijitMenuSeparatorLabel\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n</tr>\n"),
+
+ postCreate: function(){
+ dojo.setSelectable(this.domNode, false);
+ },
+
+ isFocusable: function(){
+ // summary:
+ // Override to always return false
+ // tags:
+ // protected
+
+ return false; // Boolean
+ }
+ });
+
+
+}
+
+if(!dojo._hasResource["dijit.Menu"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.Menu"] = true;
+dojo.provide("dijit.Menu");
+
+
+
+
+
+
+
+dojo.declare("dijit._MenuBase",
+ [dijit._Widget, dijit._Templated, dijit._KeyNavContainer],
+{
+ // summary:
+ // Base class for Menu and MenuBar
+
+ // parentMenu: [readonly] Widget
+ // pointer to menu that displayed me
+ parentMenu: null,
+
+ // popupDelay: Integer
+ // number of milliseconds before hovering (without clicking) causes the popup to automatically open.
+ popupDelay: 500,
+
+ startup: function(){
+ if(this._started){ return; }
+
+ dojo.forEach(this.getChildren(), function(child){ child.startup(); });
+ this.startupKeyNavChildren();
+
+ this.inherited(arguments);
+ },
+
+ onExecute: function(){
+ // summary:
+ // Attach point for notification about when a menu item has been executed.
+ // This is an internal mechanism used for Menus to signal to their parent to
+ // close them, because they are about to execute the onClick handler. In
+ // general developers should not attach to or override this method.
+ // tags:
+ // protected
+ },
+
+ onCancel: function(/*Boolean*/ closeAll){
+ // summary:
+ // Attach point for notification about when the user cancels the current menu
+ // This is an internal mechanism used for Menus to signal to their parent to
+ // close them. In general developers should not attach to or override this method.
+ // tags:
+ // protected
+ },
+
+ _moveToPopup: function(/*Event*/ evt){
+ // summary:
+ // This handles the right arrow key (left arrow key on RTL systems),
+ // which will either open a submenu, or move to the next item in the
+ // ancestor MenuBar
+ // tags:
+ // private
+
+ if(this.focusedChild && this.focusedChild.popup && !this.focusedChild.disabled){
+ this.focusedChild._onClick(evt);
+ }else{
+ var topMenu = this._getTopMenu();
+ if(topMenu && topMenu._isMenuBar){
+ topMenu.focusNext();
+ }
+ }
+ },
+
+ _onPopupHover: function(/*Event*/ evt){
+ // summary:
+ // This handler is called when the mouse moves over the popup.
+ // tags:
+ // private
+
+ // if the mouse hovers over a menu popup that is in pending-close state,
+ // then stop the close operation.
+ // This can't be done in onItemHover since some popup targets don't have MenuItems (e.g. ColorPicker)
+ if(this.currentPopup && this.currentPopup._pendingClose_timer){
+ var parentMenu = this.currentPopup.parentMenu;
+ // highlight the parent menu item pointing to this popup
+ if(parentMenu.focusedChild){
+ parentMenu.focusedChild._setSelected(false);
+ }
+ parentMenu.focusedChild = this.currentPopup.from_item;
+ parentMenu.focusedChild._setSelected(true);
+ // cancel the pending close
+ this._stopPendingCloseTimer(this.currentPopup);
+ }
+ },
+
+ onItemHover: function(/*MenuItem*/ item){
+ // summary:
+ // Called when cursor is over a MenuItem.
+ // tags:
+ // protected
+
+ // Don't do anything unless user has "activated" the menu by:
+ // 1) clicking it
+ // 2) opening it from a parent menu (which automatically focuses it)
+ if(this.isActive){
+ this.focusChild(item);
+ if(this.focusedChild.popup && !this.focusedChild.disabled && !this.hover_timer){
+ this.hover_timer = setTimeout(dojo.hitch(this, "_openPopup"), this.popupDelay);
+ }
+ }
+ // if the user is mixing mouse and keyboard navigation,
+ // then the menu may not be active but a menu item has focus,
+ // but it's not the item that the mouse just hovered over.
+ // To avoid both keyboard and mouse selections, use the latest.
+ if(this.focusedChild){
+ this.focusChild(item);
+ }
+ this._hoveredChild = item;
+ },
+
+ _onChildBlur: function(item){
+ // summary:
+ // Called when a child MenuItem becomes inactive because focus
+ // has been removed from the MenuItem *and* it's descendant menus.
+ // tags:
+ // private
+ this._stopPopupTimer();
+ item._setSelected(false);
+ // Close all popups that are open and descendants of this menu
+ var itemPopup = item.popup;
+ if(itemPopup){
+ this._stopPendingCloseTimer(itemPopup);
+ itemPopup._pendingClose_timer = setTimeout(function(){
+ itemPopup._pendingClose_timer = null;
+ if(itemPopup.parentMenu){
+ itemPopup.parentMenu.currentPopup = null;
+ }
+ dijit.popup.close(itemPopup); // this calls onClose
+ }, this.popupDelay);
+ }
+ },
+
+ onItemUnhover: function(/*MenuItem*/ item){
+ // summary:
+ // Callback fires when mouse exits a MenuItem
+ // tags:
+ // protected
+
+ if(this.isActive){
+ this._stopPopupTimer();
+ }
+ if(this._hoveredChild == item){ this._hoveredChild = null; }
+ },
+
+ _stopPopupTimer: function(){
+ // summary:
+ // Cancels the popup timer because the user has stop hovering
+ // on the MenuItem, etc.
+ // tags:
+ // private
+ if(this.hover_timer){
+ clearTimeout(this.hover_timer);
+ this.hover_timer = null;
+ }
+ },
+
+ _stopPendingCloseTimer: function(/*dijit._Widget*/ popup){
+ // summary:
+ // Cancels the pending-close timer because the close has been preempted
+ // tags:
+ // private
+ if(popup._pendingClose_timer){
+ clearTimeout(popup._pendingClose_timer);
+ popup._pendingClose_timer = null;
+ }
+ },
+
+ _stopFocusTimer: function(){
+ // summary:
+ // Cancels the pending-focus timer because the menu was closed before focus occured
+ // tags:
+ // private
+ if(this._focus_timer){
+ clearTimeout(this._focus_timer);
+ this._focus_timer = null;
+ }
+ },
+
+ _getTopMenu: function(){
+ // summary:
+ // Returns the top menu in this chain of Menus
+ // tags:
+ // private
+ for(var top=this; top.parentMenu; top=top.parentMenu);
+ return top;
+ },
+
+ onItemClick: function(/*dijit._Widget*/ item, /*Event*/ evt){
+ // summary:
+ // Handle clicks on an item.
+ // tags:
+ // private
+
+ // this can't be done in _onFocus since the _onFocus events occurs asynchronously
+ if(typeof this.isShowingNow == 'undefined'){ // non-popup menu
+ this._markActive();
+ }
+
+ this.focusChild(item);
+
+ if(item.disabled){ return false; }
+
+ if(item.popup){
+ this._openPopup();
+ }else{
+ // before calling user defined handler, close hierarchy of menus
+ // and restore focus to place it was when menu was opened
+ this.onExecute();
+
+ // user defined handler for click
+ item.onClick(evt);
+ }
+ },
+
+ _openPopup: function(){
+ // summary:
+ // Open the popup to the side of/underneath the current menu item
+ // tags:
+ // protected
+
+ this._stopPopupTimer();
+ var from_item = this.focusedChild;
+ if(!from_item){ return; } // the focused child lost focus since the timer was started
+ var popup = from_item.popup;
+ if(popup.isShowingNow){ return; }
+ if(this.currentPopup){
+ this._stopPendingCloseTimer(this.currentPopup);
+ dijit.popup.close(this.currentPopup);
+ }
+ popup.parentMenu = this;
+ popup.from_item = from_item; // helps finding the parent item that should be focused for this popup
+ var self = this;
+ dijit.popup.open({
+ parent: this,
+ popup: popup,
+ around: from_item.domNode,
+ orient: this._orient || (this.isLeftToRight() ?
+ {'TR': 'TL', 'TL': 'TR', 'BR': 'BL', 'BL': 'BR'} :
+ {'TL': 'TR', 'TR': 'TL', 'BL': 'BR', 'BR': 'BL'}),
+ onCancel: function(){ // called when the child menu is canceled
+ // set isActive=false (_closeChild vs _cleanUp) so that subsequent hovering will NOT open child menus
+ // which seems aligned with the UX of most applications (e.g. notepad, wordpad, paint shop pro)
+ self.focusChild(from_item); // put focus back on my node
+ self._cleanUp(); // close the submenu (be sure this is done _after_ focus is moved)
+ from_item._setSelected(true); // oops, _cleanUp() deselected the item
+ self.focusedChild = from_item; // and unset focusedChild
+ },
+ onExecute: dojo.hitch(this, "_cleanUp")
+ });
+
+ this.currentPopup = popup;
+ // detect mouseovers to handle lazy mouse movements that temporarily focus other menu items
+ popup.connect(popup.domNode, "onmouseenter", dojo.hitch(self, "_onPopupHover")); // cleaned up when the popped-up widget is destroyed on close
+
+ if(popup.focus){
+ // If user is opening the popup via keyboard (right arrow, or down arrow for MenuBar),
+ // if the cursor happens to collide with the popup, it will generate an onmouseover event
+ // even though the mouse wasn't moved. Use a setTimeout() to call popup.focus so that
+ // our focus() call overrides the onmouseover event, rather than vice-versa. (#8742)
+ popup._focus_timer = setTimeout(dojo.hitch(popup, function(){
+ this._focus_timer = null;
+ this.focus();
+ }), 0);
+ }
+ },
+
+ _markActive: function(){
+ // summary:
+ // Mark this menu's state as active.
+ // Called when this Menu gets focus from:
+ // 1) clicking it (mouse or via space/arrow key)
+ // 2) being opened by a parent menu.
+ // This is not called just from mouse hover.
+ // Focusing a menu via TAB does NOT automatically set isActive
+ // since TAB is a navigation operation and not a selection one.
+ // For Windows apps, pressing the ALT key focuses the menubar
+ // menus (similar to TAB navigation) but the menu is not active
+ // (ie no dropdown) until an item is clicked.
+ this.isActive = true;
+ dojo.addClass(this.domNode, "dijitMenuActive");
+ dojo.removeClass(this.domNode, "dijitMenuPassive");
+ },
+
+ onOpen: function(/*Event*/ e){
+ // summary:
+ // Callback when this menu is opened.
+ // This is called by the popup manager as notification that the menu
+ // was opened.
+ // tags:
+ // private
+
+ this.isShowingNow = true;
+ this._markActive();
+ },
+
+ _markInactive: function(){
+ // summary:
+ // Mark this menu's state as inactive.
+ this.isActive = false; // don't do this in _onBlur since the state is pending-close until we get here
+ dojo.removeClass(this.domNode, "dijitMenuActive");
+ dojo.addClass(this.domNode, "dijitMenuPassive");
+ },
+
+ onClose: function(){
+ // summary:
+ // Callback when this menu is closed.
+ // This is called by the popup manager as notification that the menu
+ // was closed.
+ // tags:
+ // private
+
+ this._stopFocusTimer();
+ this._markInactive();
+ this.isShowingNow = false;
+ this.parentMenu = null;
+ },
+
+ _closeChild: function(){
+ // summary:
+ // Called when submenu is clicked or focus is lost. Close hierarchy of menus.
+ // tags:
+ // private
+ this._stopPopupTimer();
+ if(this.focusedChild){ // unhighlight the focused item
+ this.focusedChild._setSelected(false);
+ this.focusedChild._onUnhover();
+ this.focusedChild = null;
+ }
+ if(this.currentPopup){
+ // Close all popups that are open and descendants of this menu
+ dijit.popup.close(this.currentPopup);
+ this.currentPopup = null;
+ }
+ },
+
+ _onItemFocus: function(/*MenuItem*/ item){
+ // summary:
+ // Called when child of this Menu gets focus from:
+ // 1) clicking it
+ // 2) tabbing into it
+ // 3) being opened by a parent menu.
+ // This is not called just from mouse hover.
+ if(this._hoveredChild && this._hoveredChild != item){
+ this._hoveredChild._onUnhover(); // any previous mouse movement is trumped by focus selection
+ }
+ },
+
+ _onBlur: function(){
+ // summary:
+ // Called when focus is moved away from this Menu and it's submenus.
+ // tags:
+ // protected
+ this._cleanUp();
+ this.inherited(arguments);
+ },
+
+ _cleanUp: function(){
+ // summary:
+ // Called when the user is done with this menu. Closes hierarchy of menus.
+ // tags:
+ // private
+
+ this._closeChild(); // don't call this.onClose since that's incorrect for MenuBar's that never close
+ if(typeof this.isShowingNow == 'undefined'){ // non-popup menu doesn't call onClose
+ this._markInactive();
+ }
+ }
+});
+
+dojo.declare("dijit.Menu",
+ dijit._MenuBase,
+ {
+ // summary
+ // A context menu you can assign to multiple elements
+
+ // TODO: most of the code in here is just for context menu (right-click menu)
+ // support. In retrospect that should have been a separate class (dijit.ContextMenu).
+ // Split them for 2.0
+
+ constructor: function(){
+ this._bindings = [];
+ },
+
+ templateString: dojo.cache("dijit", "templates/Menu.html", "<table class=\"dijit dijitMenu dijitMenuPassive dijitReset dijitMenuTable\" waiRole=\"menu\" tabIndex=\"${tabIndex}\" dojoAttachEvent=\"onkeypress:_onKeyPress\" cellspacing=0>\n\t<tbody class=\"dijitReset\" dojoAttachPoint=\"containerNode\"></tbody>\n</table>\n"),
+
+ baseClass: "dijitMenu",
+
+ // targetNodeIds: [const] String[]
+ // Array of dom node ids of nodes to attach to.
+ // Fill this with nodeIds upon widget creation and it becomes context menu for those nodes.
+ targetNodeIds: [],
+
+ // contextMenuForWindow: [const] Boolean
+ // If true, right clicking anywhere on the window will cause this context menu to open.
+ // If false, must specify targetNodeIds.
+ contextMenuForWindow: false,
+
+ // leftClickToOpen: [const] Boolean
+ // If true, menu will open on left click instead of right click, similiar to a file menu.
+ leftClickToOpen: false,
+
+ // refocus: Boolean
+ // When this menu closes, re-focus the element which had focus before it was opened.
+ refocus: true,
+
+ postCreate: function(){
+ if(this.contextMenuForWindow){
+ this.bindDomNode(dojo.body());
+ }else{
+ // TODO: should have _setTargetNodeIds() method to handle initialization and a possible
+ // later attr('targetNodeIds', ...) call. There's also a problem that targetNodeIds[]
+ // gets stale after calls to bindDomNode()/unBindDomNode() as it still is just the original list (see #9610)
+ dojo.forEach(this.targetNodeIds, this.bindDomNode, this);
+ }
+ var k = dojo.keys, l = this.isLeftToRight();
+ this._openSubMenuKey = l ? k.RIGHT_ARROW : k.LEFT_ARROW;
+ this._closeSubMenuKey = l ? k.LEFT_ARROW : k.RIGHT_ARROW;
+ this.connectKeyNavHandlers([k.UP_ARROW], [k.DOWN_ARROW]);
+ },
+
+ _onKeyPress: function(/*Event*/ evt){
+ // summary:
+ // Handle keyboard based menu navigation.
+ // tags:
+ // protected
+
+ if(evt.ctrlKey || evt.altKey){ return; }
+
+ switch(evt.charOrCode){
+ case this._openSubMenuKey:
+ this._moveToPopup(evt);
+ dojo.stopEvent(evt);
+ break;
+ case this._closeSubMenuKey:
+ if(this.parentMenu){
+ if(this.parentMenu._isMenuBar){
+ this.parentMenu.focusPrev();
+ }else{
+ this.onCancel(false);
+ }
+ }else{
+ dojo.stopEvent(evt);
+ }
+ break;
+ }
+ },
+
+ // thanks burstlib!
+ _iframeContentWindow: function(/* HTMLIFrameElement */iframe_el){
+ // summary:
+ // Returns the window reference of the passed iframe
+ // tags:
+ // private
+ var win = dojo.window.get(this._iframeContentDocument(iframe_el)) ||
+ // Moz. TODO: is this available when defaultView isn't?
+ this._iframeContentDocument(iframe_el)['__parent__'] ||
+ (iframe_el.name && dojo.doc.frames[iframe_el.name]) || null;
+ return win; // Window
+ },
+
+ _iframeContentDocument: function(/* HTMLIFrameElement */iframe_el){
+ // summary:
+ // Returns a reference to the document object inside iframe_el
+ // tags:
+ // protected
+ var doc = iframe_el.contentDocument // W3
+ || (iframe_el.contentWindow && iframe_el.contentWindow.document) // IE
+ || (iframe_el.name && dojo.doc.frames[iframe_el.name] && dojo.doc.frames[iframe_el.name].document)
+ || null;
+ return doc; // HTMLDocument
+ },
+
+ bindDomNode: function(/*String|DomNode*/ node){
+ // summary:
+ // Attach menu to given node
+ node = dojo.byId(node);
+
+ var cn; // Connect node
+
+ // Support context menus on iframes. Rather than binding to the iframe itself we need
+ // to bind to the <body> node inside the iframe.
+ if(node.tagName.toLowerCase() == "iframe"){
+ var iframe = node,
+ win = this._iframeContentWindow(iframe);
+ cn = dojo.withGlobal(win, dojo.body);
+ }else{
+
+ // To capture these events at the top level, attach to <html>, not <body>.
+ // Otherwise right-click context menu just doesn't work.
+ cn = (node == dojo.body() ? dojo.doc.documentElement : node);
+ }
+
+
+ // "binding" is the object to track our connection to the node (ie, the parameter to bindDomNode())
+ var binding = {
+ node: node,
+ iframe: iframe
+ };
+
+ // Save info about binding in _bindings[], and make node itself record index(+1) into
+ // _bindings[] array. Prefix w/_dijitMenu to avoid setting an attribute that may
+ // start with a number, which fails on FF/safari.
+ dojo.attr(node, "_dijitMenu" + this.id, this._bindings.push(binding));
+
+ // Setup the connections to monitor click etc., unless we are connecting to an iframe which hasn't finished
+ // loading yet, in which case we need to wait for the onload event first, and then connect
+ // On linux Shift-F10 produces the oncontextmenu event, but on Windows it doesn't, so
+ // we need to monitor keyboard events in addition to the oncontextmenu event.
+ var doConnects = dojo.hitch(this, function(cn){
+ return [
+ // TODO: when leftClickToOpen is true then shouldn't space/enter key trigger the menu,
+ // rather than shift-F10?
+ dojo.connect(cn, this.leftClickToOpen ? "onclick" : "oncontextmenu", this, function(evt){
+ // Schedule context menu to be opened unless it's already been scheduled from onkeydown handler
+ dojo.stopEvent(evt);
+ this._scheduleOpen(evt.target, iframe, {x: evt.pageX, y: evt.pageY});
+ }),
+ dojo.connect(cn, "onkeydown", this, function(evt){
+ if(evt.shiftKey && evt.keyCode == dojo.keys.F10){
+ dojo.stopEvent(evt);
+ this._scheduleOpen(evt.target, iframe); // no coords - open near target node
+ }
+ })
+ ];
+ });
+ binding.connects = cn ? doConnects(cn) : [];
+
+ if(iframe){
+ // Setup handler to [re]bind to the iframe when the contents are initially loaded,
+ // and every time the contents change.
+ // Need to do this b/c we are actually binding to the iframe's <body> node.
+ // Note: can't use dojo.connect(), see #9609.
+
+ binding.onloadHandler = dojo.hitch(this, function(){
+ // want to remove old connections, but IE throws exceptions when trying to
+ // access the <body> node because it's already gone, or at least in a state of limbo
+
+ var win = this._iframeContentWindow(iframe);
+ cn = dojo.withGlobal(win, dojo.body);
+ binding.connects = doConnects(cn);
+ });
+ if(iframe.addEventListener){
+ iframe.addEventListener("load", binding.onloadHandler, false);
+ }else{
+ iframe.attachEvent("onload", binding.onloadHandler);
+ }
+ }
+ },
+
+ unBindDomNode: function(/*String|DomNode*/ nodeName){
+ // summary:
+ // Detach menu from given node
+
+ var node;
+ try{
+ node = dojo.byId(nodeName);
+ }catch(e){
+ // On IE the dojo.byId() call will get an exception if the attach point was
+ // the <body> node of an <iframe> that has since been reloaded (and thus the
+ // <body> node is in a limbo state of destruction.
+ return;
+ }
+
+ // node["_dijitMenu" + this.id] contains index(+1) into my _bindings[] array
+ var attrName = "_dijitMenu" + this.id;
+ if(node && dojo.hasAttr(node, attrName)){
+ var bid = dojo.attr(node, attrName)-1, b = this._bindings[bid];
+ dojo.forEach(b.connects, dojo.disconnect);
+
+ // Remove listener for iframe onload events
+ var iframe = b.iframe;
+ if(iframe){
+ if(iframe.removeEventListener){
+ iframe.removeEventListener("load", b.onloadHandler, false);
+ }else{
+ iframe.detachEvent("onload", b.onloadHandler);
+ }
+ }
+
+ dojo.removeAttr(node, attrName);
+ delete this._bindings[bid];
+ }
+ },
+
+ _scheduleOpen: function(/*DomNode?*/ target, /*DomNode?*/ iframe, /*Object?*/ coords){
+ // summary:
+ // Set timer to display myself. Using a timer rather than displaying immediately solves
+ // two problems:
+ //
+ // 1. IE: without the delay, focus work in "open" causes the system
+ // context menu to appear in spite of stopEvent.
+ //
+ // 2. Avoid double-shows on linux, where shift-F10 generates an oncontextmenu event
+ // even after a dojo.stopEvent(e). (Shift-F10 on windows doesn't generate the
+ // oncontextmenu event.)
+
+ if(!this._openTimer){
+ this._openTimer = setTimeout(dojo.hitch(this, function(){
+ delete this._openTimer;
+ this._openMyself({
+ target: target,
+ iframe: iframe,
+ coords: coords
+ });
+ }), 1);
+ }
+ },
+
+ _openMyself: function(args){
+ // summary:
+ // Internal function for opening myself when the user does a right-click or something similar.
+ // args:
+ // This is an Object containing:
+ // * target:
+ // The node that is being clicked
+ // * iframe:
+ // If an <iframe> is being clicked, iframe points to that iframe
+ // * coords:
+ // Put menu at specified x/y position in viewport, or if iframe is
+ // specified, then relative to iframe.
+ //
+ // _openMyself() formerly took the event object, and since various code references
+ // evt.target (after connecting to _openMyself()), using an Object for parameters
+ // (so that old code still works).
+
+ var target = args.target,
+ iframe = args.iframe,
+ coords = args.coords;
+
+ // Get coordinates to open menu, either at specified (mouse) position or (if triggered via keyboard)
+ // then near the node the menu is assigned to.
+ if(coords){
+ if(iframe){
+ // Specified coordinates are on <body> node of an <iframe>, convert to match main document
+ var od = target.ownerDocument,
+ ifc = dojo.position(iframe, true),
+ win = this._iframeContentWindow(iframe),
+ scroll = dojo.withGlobal(win, "_docScroll", dojo);
+
+ var cs = dojo.getComputedStyle(iframe),
+ tp = dojo._toPixelValue,
+ left = (dojo.isIE && dojo.isQuirks ? 0 : tp(iframe, cs.paddingLeft)) + (dojo.isIE && dojo.isQuirks ? tp(iframe, cs.borderLeftWidth) : 0),
+ top = (dojo.isIE && dojo.isQuirks ? 0 : tp(iframe, cs.paddingTop)) + (dojo.isIE && dojo.isQuirks ? tp(iframe, cs.borderTopWidth) : 0);
+
+ coords.x += ifc.x + left - scroll.x;
+ coords.y += ifc.y + top - scroll.y;
+ }
+ }else{
+ coords = dojo.position(target, true);
+ coords.x += 10;
+ coords.y += 10;
+ }
+
+ var self=this;
+ var savedFocus = dijit.getFocus(this);
+ function closeAndRestoreFocus(){
+ // user has clicked on a menu or popup
+ if(self.refocus){
+ dijit.focus(savedFocus);
+ }
+ dijit.popup.close(self);
+ }
+ dijit.popup.open({
+ popup: this,
+ x: coords.x,
+ y: coords.y,
+ onExecute: closeAndRestoreFocus,
+ onCancel: closeAndRestoreFocus,
+ orient: this.isLeftToRight() ? 'L' : 'R'
+ });
+ this.focus();
+
+ this._onBlur = function(){
+ this.inherited('_onBlur', arguments);
+ // Usually the parent closes the child widget but if this is a context
+ // menu then there is no parent
+ dijit.popup.close(this);
+ // don't try to restore focus; user has clicked another part of the screen
+ // and set focus there
+ };
+ },
+
+ uninitialize: function(){
+ dojo.forEach(this._bindings, function(b){ if(b){ this.unBindDomNode(b.node); } }, this);
+ this.inherited(arguments);
+ }
+}
+);
+
+// Back-compat (TODO: remove in 2.0)
+
+
+
+
+
+
+}
+
+if(!dojo._hasResource["dijit.form.Select"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.Select"] = true;
+dojo.provide("dijit.form.Select");
+
+
+
+
+
+
+
+
+dojo.declare("dijit.form._SelectMenu", dijit.Menu, {
+ // summary:
+ // An internally-used menu for dropdown that allows us a vertical scrollbar
+ buildRendering: function(){
+ // summary:
+ // Stub in our own changes, so that our domNode is not a table
+ // otherwise, we won't respond correctly to heights/overflows
+ this.inherited(arguments);
+ var o = (this.menuTableNode = this.domNode);
+ var n = (this.domNode = dojo.create("div", {style: {overflowX: "hidden", overflowY: "scroll"}}));
+ if(o.parentNode){
+ o.parentNode.replaceChild(n, o);
+ }
+ dojo.removeClass(o, "dijitMenuTable");
+ n.className = o.className + " dijitSelectMenu";
+ o.className = "dijitReset dijitMenuTable";
+ dijit.setWaiRole(o,"listbox");
+ dijit.setWaiRole(n,"presentation");
+ n.appendChild(o);
+ },
+ resize: function(/*Object*/ mb){
+ // summary:
+ // Overridden so that we are able to handle resizing our
+ // internal widget. Note that this is not a "full" resize
+ // implementation - it only works correctly if you pass it a
+ // marginBox.
+ //
+ // mb: Object
+ // The margin box to set this dropdown to.
+ if(mb){
+ dojo.marginBox(this.domNode, mb);
+ if("w" in mb){
+ // We've explicitly set the wrapper <div>'s width, so set <table> width to match.
+ // 100% is safer than a pixel value because there may be a scroll bar with
+ // browser/OS specific width.
+ this.menuTableNode.style.width = "100%";
+ }
+ }
+ }
+});
+
+dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropDown], {
+ // summary:
+ // This is a "styleable" select box - it is basically a DropDownButton which
+ // can take a <select> as its input.
+
+ baseClass: "dijitSelect",
+
+ templateString: dojo.cache("dijit.form", "templates/Select.html", "<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tdojoAttachPoint=\"_buttonNode,tableNode,focusNode\" cellspacing='0' cellpadding='0'\n\twaiRole=\"combobox\" waiState=\"haspopup-true\"\n\t><tbody waiRole=\"presentation\"><tr waiRole=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonContents dijitButtonNode\" waiRole=\"presentation\"\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\" dojoAttachPoint=\"containerNode,_popupStateNode\"></span\n\t\t\t><input type=\"hidden\" ${!nameAttrSetting} dojoAttachPoint=\"valueNode\" value=\"${value}\" waiState=\"hidden-true\"\n\t\t/></td><td class=\"dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\t\tdojoAttachPoint=\"titleNode\" waiRole=\"presentation\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" waiRole=\"presentation\">&#9660;</div\n\t\t></td\n\t></tr></tbody\n></table>\n"),
+
+ // attributeMap: Object
+ // Add in our style to be applied to the focus node
+ attributeMap: dojo.mixin(dojo.clone(dijit.form._FormSelectWidget.prototype.attributeMap),{style:"tableNode"}),
+
+ // required: Boolean
+ // Can be true or false, default is false.
+ required: false,
+
+ // state: String
+ // Shows current state (ie, validation result) of input (Normal, Warning, or Error)
+ state: "",
+
+ // tooltipPosition: String[]
+ // See description of dijit.Tooltip.defaultPosition for details on this parameter.
+ tooltipPosition: [],
+
+ // emptyLabel: string
+ // What to display in an "empty" dropdown
+ emptyLabel: "",
+
+ // _isLoaded: Boolean
+ // Whether or not we have been loaded
+ _isLoaded: false,
+
+ // _childrenLoaded: Boolean
+ // Whether or not our children have been loaded
+ _childrenLoaded: false,
+
+ _fillContent: function(){
+ // summary:
+ // Set the value to be the first, or the selected index
+ this.inherited(arguments);
+ if(this.options.length && !this.value && this.srcNodeRef){
+ var si = this.srcNodeRef.selectedIndex;
+ this.value = this.options[si != -1 ? si : 0].value;
+ }
+
+ // Create the dropDown widget
+ this.dropDown = new dijit.form._SelectMenu({id: this.id + "_menu"});
+ dojo.addClass(this.dropDown.domNode, this.baseClass + "Menu");
+ },
+
+ _getMenuItemForOption: function(/*dijit.form.__SelectOption*/ option){
+ // summary:
+ // For the given option, return the menu item that should be
+ // used to display it. This can be overridden as needed
+ if(!option.value){
+ // We are a separator (no label set for it)
+ return new dijit.MenuSeparator();
+ }else{
+ // Just a regular menu option
+ var click = dojo.hitch(this, "_setValueAttr", option);
+ var item = new dijit.MenuItem({
+ option: option,
+ label: option.label,
+ onClick: click,
+ disabled: option.disabled || false
+ });
+ dijit.setWaiRole(item.focusNode, "listitem");
+ return item;
+ }
+ },
+
+ _addOptionItem: function(/*dijit.form.__SelectOption*/ option){
+ // summary:
+ // For the given option, add an option to our dropdown.
+ // If the option doesn't have a value, then a separator is added
+ // in that place.
+ if(this.dropDown){
+ this.dropDown.addChild(this._getMenuItemForOption(option));
+ }
+ },
+
+ _getChildren: function(){
+ if(!this.dropDown){
+ return [];
+ }
+ return this.dropDown.getChildren();
+ },
+
+ _loadChildren: function(/*Boolean*/ loadMenuItems){
+ // summary:
+ // Resets the menu and the length attribute of the button - and
+ // ensures that the label is appropriately set.
+ // loadMenuItems: Boolean
+ // actually loads the child menu items - we only do this when we are
+ // populating for showing the dropdown.
+
+ if(loadMenuItems === true){
+ // this.inherited destroys this.dropDown's child widgets (MenuItems).
+ // Avoid this.dropDown (Menu widget) having a pointer to a destroyed widget (which will cause
+ // issues later in _setSelected). (see #10296)
+ if(this.dropDown){
+ delete this.dropDown.focusedChild;
+ }
+ if(this.options.length){
+ this.inherited(arguments);
+ }else{
+ // Drop down menu is blank but add one blank entry just so something appears on the screen
+ // to let users know that they are no choices (mimicing native select behavior)
+ dojo.forEach(this._getChildren(), function(child){ child.destroyRecursive(); });
+ var item = new dijit.MenuItem({label: "&nbsp;"});
+ this.dropDown.addChild(item);
+ }
+ }else{
+ this._updateSelection();
+ }
+
+ var len = this.options.length;
+ this._isLoaded = false;
+ this._childrenLoaded = true;
+
+ if(!this._loadingStore){
+ // Don't call this if we are loading - since we will handle it later
+ this._setValueAttr(this.value);
+ }
+ },
+
+ _setValueAttr: function(value){
+ this.inherited(arguments);
+ dojo.attr(this.valueNode, "value", this.get("value"));
+ },
+
+ _setDisplay: function(/*String*/ newDisplay){
+ // summary:
+ // sets the display for the given value (or values)
+ this.containerNode.innerHTML = '<span class="dijitReset dijitInline ' + this.baseClass + 'Label">' +
+ (newDisplay || this.emptyLabel || "&nbsp;") +
+ '</span>';
+ dijit.setWaiState(this.focusNode, "valuetext", (newDisplay || this.emptyLabel || "&nbsp;") );
+ },
+
+ validate: function(/*Boolean*/ isFocused){
+ // summary:
+ // Called by oninit, onblur, and onkeypress.
+ // description:
+ // Show missing or invalid messages if appropriate, and highlight textbox field.
+ // Used when a select is initially set to no value and the user is required to
+ // set the value.
+
+ var isValid = this.isValid(isFocused);
+ this.state = isValid ? "" : "Error";
+ this._setStateClass();
+ dijit.setWaiState(this.focusNode, "invalid", isValid ? "false" : "true");
+ var message = isValid ? "" : this._missingMsg;
+ if(this._message !== message){
+ this._message = message;
+ dijit.hideTooltip(this.domNode);
+ if(message){
+ dijit.showTooltip(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
+ }
+ }
+ return isValid;
+ },
+
+ isValid: function(/*Boolean*/ isFocused){
+ // summary:
+ // Whether or not this is a valid value. The only way a Select
+ // can be invalid is when it's required but nothing is selected.
+ return (!this.required || !(/^\s*$/.test(this.value)));
+ },
+
+ reset: function(){
+ // summary:
+ // Overridden so that the state will be cleared.
+ this.inherited(arguments);
+ dijit.hideTooltip(this.domNode);
+ this.state = "";
+ this._setStateClass();
+ delete this._message;
+ },
+
+ postMixInProperties: function(){
+ // summary:
+ // set the missing message
+ this.inherited(arguments);
+ this._missingMsg = dojo.i18n.getLocalization("dijit.form", "validate",
+ this.lang).missingMessage;
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ if(this.tableNode.style.width){
+ dojo.addClass(this.domNode, this.baseClass + "FixedWidth");
+ }
+ },
+
+ isLoaded: function(){
+ return this._isLoaded;
+ },
+
+ loadDropDown: function(/*Function*/ loadCallback){
+ // summary:
+ // populates the menu
+ this._loadChildren(true);
+ this._isLoaded = true;
+ loadCallback();
+ },
+
+ closeDropDown: function(){
+ // overriding _HasDropDown.closeDropDown()
+ this.inherited(arguments);
+
+ if(this.dropDown && this.dropDown.menuTableNode){
+ // Erase possible width: 100% setting from _SelectMenu.resize().
+ // Leaving it would interfere with the next openDropDown() call, which
+ // queries the natural size of the drop down.
+ this.dropDown.menuTableNode.style.width = "";
+ }
+ },
+
+ uninitialize: function(preserveDom){
+ if(this.dropDown && !this.dropDown._destroyed){
+ this.dropDown.destroyRecursive(preserveDom);
+ delete this.dropDown;
+ }
+ this.inherited(arguments);
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.form.SimpleTextarea"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.SimpleTextarea"] = true;
+dojo.provide("dijit.form.SimpleTextarea");
+
+
+
+dojo.declare("dijit.form.SimpleTextarea",
+ dijit.form.TextBox,
+ {
+ // summary:
+ // A simple textarea that degrades, and responds to
+ // minimal LayoutContainer usage, and works with dijit.form.Form.
+ // Doesn't automatically size according to input, like Textarea.
+ //
+ // example:
+ // | <textarea dojoType="dijit.form.SimpleTextarea" name="foo" value="bar" rows=30 cols=40></textarea>
+ //
+ // example:
+ // | new dijit.form.SimpleTextarea({ rows:20, cols:30 }, "foo");
+
+ baseClass: "dijitTextBox dijitTextArea",
+
+ attributeMap: dojo.delegate(dijit.form._FormValueWidget.prototype.attributeMap, {
+ rows:"textbox", cols: "textbox"
+ }),
+
+ // rows: Number
+ // The number of rows of text.
+ rows: "3",
+
+ // rows: Number
+ // The number of characters per line.
+ cols: "20",
+
+ templateString: "<textarea ${!nameAttrSetting} dojoAttachPoint='focusNode,containerNode,textbox' autocomplete='off'></textarea>",
+
+ postMixInProperties: function(){
+ // Copy value from srcNodeRef, unless user specified a value explicitly (or there is no srcNodeRef)
+ if(!this.value && this.srcNodeRef){
+ this.value = this.srcNodeRef.value;
+ }
+ this.inherited(arguments);
+ },
+
+ filter: function(/*String*/ value){
+ // Override TextBox.filter to deal with newlines... specifically (IIRC) this is for IE which writes newlines
+ // as \r\n instead of just \n
+ if(value){
+ value = value.replace(/\r/g,"");
+ }
+ return this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ if(dojo.isIE && this.cols){ // attribute selectors is not supported in IE6
+ dojo.addClass(this.textbox, "dijitTextAreaCols");
+ }
+ },
+
+ _previousValue: "",
+ _onInput: function(/*Event?*/ e){
+ // Override TextBox._onInput() to enforce maxLength restriction
+ if(this.maxLength){
+ var maxLength = parseInt(this.maxLength);
+ var value = this.textbox.value.replace(/\r/g,'');
+ var overflow = value.length - maxLength;
+ if(overflow > 0){
+ if(e){ dojo.stopEvent(e); }
+ var textarea = this.textbox;
+ if(textarea.selectionStart){
+ var pos = textarea.selectionStart;
+ var cr = 0;
+ if(dojo.isOpera){
+ cr = (this.textbox.value.substring(0,pos).match(/\r/g) || []).length;
+ }
+ this.textbox.value = value.substring(0,pos-overflow-cr)+value.substring(pos-cr);
+ textarea.setSelectionRange(pos-overflow, pos-overflow);
+ }else if(dojo.doc.selection){ //IE
+ textarea.focus();
+ var range = dojo.doc.selection.createRange();
+ // delete overflow characters
+ range.moveStart("character", -overflow);
+ range.text = '';
+ // show cursor
+ range.select();
+ }
+ }
+ this._previousValue = this.textbox.value;
+ }
+ this.inherited(arguments);
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.InlineEditBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.InlineEditBox"] = true;
+dojo.provide("dijit.InlineEditBox");
+
+
+
+
+
+
+
+
+
+
+dojo.declare("dijit.InlineEditBox",
+ dijit._Widget,
+ {
+ // summary:
+ // An element with in-line edit capabilites
+ //
+ // description:
+ // Behavior for an existing node (`<p>`, `<div>`, `<span>`, etc.) so that
+ // when you click it, an editor shows up in place of the original
+ // text. Optionally, Save and Cancel button are displayed below the edit widget.
+ // When Save is clicked, the text is pulled from the edit
+ // widget and redisplayed and the edit widget is again hidden.
+ // By default a plain Textarea widget is used as the editor (or for
+ // inline values a TextBox), but you can specify an editor such as
+ // dijit.Editor (for editing HTML) or a Slider (for adjusting a number).
+ // An edit widget must support the following API to be used:
+ // - displayedValue or value as initialization parameter,
+ // and available through set('displayedValue') / set('value')
+ // - void focus()
+ // - DOM-node focusNode = node containing editable text
+
+ // editing: [readonly] Boolean
+ // Is the node currently in edit mode?
+ editing: false,
+
+ // autoSave: Boolean
+ // Changing the value automatically saves it; don't have to push save button
+ // (and save button isn't even displayed)
+ autoSave: true,
+
+ // buttonSave: String
+ // Save button label
+ buttonSave: "",
+
+ // buttonCancel: String
+ // Cancel button label
+ buttonCancel: "",
+
+ // renderAsHtml: Boolean
+ // Set this to true if the specified Editor's value should be interpreted as HTML
+ // rather than plain text (ex: `dijit.Editor`)
+ renderAsHtml: false,
+
+ // editor: String
+ // Class name for Editor widget
+ editor: "dijit.form.TextBox",
+
+ // editorWrapper: String
+ // Class name for widget that wraps the editor widget, displaying save/cancel
+ // buttons.
+ editorWrapper: "dijit._InlineEditor",
+
+ // editorParams: Object
+ // Set of parameters for editor, like {required: true}
+ editorParams: {},
+
+ onChange: function(value){
+ // summary:
+ // Set this handler to be notified of changes to value.
+ // tags:
+ // callback
+ },
+
+ onCancel: function(){
+ // summary:
+ // Set this handler to be notified when editing is cancelled.
+ // tags:
+ // callback
+ },
+
+ // width: String
+ // Width of editor. By default it's width=100% (ie, block mode).
+ width: "100%",
+
+ // value: String
+ // The display value of the widget in read-only mode
+ value: "",
+
+ // noValueIndicator: [const] String
+ // The text that gets displayed when there is no value (so that the user has a place to click to edit)
+ noValueIndicator: dojo.isIE <= 6 ? // font-family needed on IE6 but it messes up IE8
+ "<span style='font-family: wingdings; text-decoration: underline;'>&nbsp;&nbsp;&nbsp;&nbsp;&#x270d;&nbsp;&nbsp;&nbsp;&nbsp;</span>" :
+ "<span style='text-decoration: underline;'>&nbsp;&nbsp;&nbsp;&nbsp;&#x270d;&nbsp;&nbsp;&nbsp;&nbsp;</span>",
+
+ constructor: function(){
+ // summary:
+ // Sets up private arrays etc.
+ // tags:
+ // private
+ this.editorParams = {};
+ },
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+
+ // save pointer to original source node, since Widget nulls-out srcNodeRef
+ this.displayNode = this.srcNodeRef;
+
+ // connect handlers to the display node
+ var events = {
+ ondijitclick: "_onClick",
+ onmouseover: "_onMouseOver",
+ onmouseout: "_onMouseOut",
+ onfocus: "_onMouseOver",
+ onblur: "_onMouseOut"
+ };
+ for(var name in events){
+ this.connect(this.displayNode, name, events[name]);
+ }
+ dijit.setWaiRole(this.displayNode, "button");
+ if(!this.displayNode.getAttribute("tabIndex")){
+ this.displayNode.setAttribute("tabIndex", 0);
+ }
+
+ if(!this.value && !("value" in this.params)){ // "" is a good value if specified directly so check params){
+ this.value = dojo.trim(this.renderAsHtml ? this.displayNode.innerHTML :
+ (this.displayNode.innerText||this.displayNode.textContent||""));
+ }
+ if(!this.value){
+ this.displayNode.innerHTML = this.noValueIndicator;
+ }
+
+ dojo.addClass(this.displayNode, 'dijitInlineEditBoxDisplayMode');
+ },
+
+ setDisabled: function(/*Boolean*/ disabled){
+ // summary:
+ // Deprecated. Use set('disabled', ...) instead.
+ // tags:
+ // deprecated
+ dojo.deprecated("dijit.InlineEditBox.setDisabled() is deprecated. Use set('disabled', bool) instead.", "", "2.0");
+ this.set('disabled', disabled);
+ },
+
+ _setDisabledAttr: function(/*Boolean*/ disabled){
+ // summary:
+ // Hook to make set("disabled", ...) work.
+ // Set disabled state of widget.
+ this.disabled = disabled;
+ dijit.setWaiState(this.domNode, "disabled", disabled);
+ if(disabled){
+ this.displayNode.removeAttribute("tabIndex");
+ }else{
+ this.displayNode.setAttribute("tabIndex", 0);
+ }
+ dojo.toggleClass(this.displayNode, "dijitInlineEditBoxDisplayModeDisabled", disabled);
+ },
+
+ _onMouseOver: function(){
+ // summary:
+ // Handler for onmouseover and onfocus event.
+ // tags:
+ // private
+ if(!this.disabled){
+ dojo.addClass(this.displayNode, "dijitInlineEditBoxDisplayModeHover");
+ }
+ },
+
+ _onMouseOut: function(){
+ // summary:
+ // Handler for onmouseout and onblur event.
+ // tags:
+ // private
+ dojo.removeClass(this.displayNode, "dijitInlineEditBoxDisplayModeHover");
+ },
+
+ _onClick: function(/*Event*/ e){
+ // summary:
+ // Handler for onclick event.
+ // tags:
+ // private
+ if(this.disabled){ return; }
+ if(e){ dojo.stopEvent(e); }
+ this._onMouseOut();
+
+ // Since FF gets upset if you move a node while in an event handler for that node...
+ setTimeout(dojo.hitch(this, "edit"), 0);
+ },
+
+ edit: function(){
+ // summary:
+ // Display the editor widget in place of the original (read only) markup.
+ // tags:
+ // private
+
+ if(this.disabled || this.editing){ return; }
+ this.editing = true;
+
+ // save some display node values that can be restored later
+ this._savedPosition = dojo.style(this.displayNode, "position") || "static";
+ this._savedOpacity = dojo.style(this.displayNode, "opacity") || "1";
+ this._savedTabIndex = dojo.attr(this.displayNode, "tabIndex") || "0";
+
+ if(this.wrapperWidget){
+ var ew = this.wrapperWidget.editWidget;
+ ew.set("displayedValue" in ew ? "displayedValue" : "value", this.value);
+ }else{
+ // Placeholder for edit widget
+ // Put place holder (and eventually editWidget) before the display node so that it's positioned correctly
+ // when Calendar dropdown appears, which happens automatically on focus.
+ var placeholder = dojo.create("span", null, this.domNode, "before");
+
+ // Create the editor wrapper (the thing that holds the editor widget and the save/cancel buttons)
+ var ewc = dojo.getObject(this.editorWrapper);
+ this.wrapperWidget = new ewc({
+ value: this.value,
+ buttonSave: this.buttonSave,
+ buttonCancel: this.buttonCancel,
+ dir: this.dir,
+ lang: this.lang,
+ tabIndex: this._savedTabIndex,
+ editor: this.editor,
+ inlineEditBox: this,
+ sourceStyle: dojo.getComputedStyle(this.displayNode),
+ save: dojo.hitch(this, "save"),
+ cancel: dojo.hitch(this, "cancel")
+ }, placeholder);
+ }
+ var ww = this.wrapperWidget;
+
+ if(dojo.isIE){
+ dijit.focus(dijit.getFocus()); // IE (at least 8) needs help with tab order changes
+ }
+ // to avoid screen jitter, we first create the editor with position:absolute, visibility:hidden,
+ // and then when it's finished rendering, we switch from display mode to editor
+ // position:absolute releases screen space allocated to the display node
+ // opacity:0 is the same as visibility:hidden but is still focusable
+ // visiblity:hidden removes focus outline
+
+ dojo.style(this.displayNode, { position: "absolute", opacity: "0", display: "none" }); // makes display node invisible, display style used for focus-ability
+ dojo.style(ww.domNode, { position: this._savedPosition, visibility: "visible", opacity: "1" });
+ dojo.attr(this.displayNode, "tabIndex", "-1"); // needed by WebKit for TAB from editor to skip displayNode
+
+ // Replace the display widget with edit widget, leaving them both displayed for a brief time so that
+ // focus can be shifted without incident. (browser may needs some time to render the editor.)
+ setTimeout(dojo.hitch(this, function(){
+ ww.focus(); // both nodes are showing, so we can switch focus safely
+ ww._resetValue = ww.getValue();
+ }), 0);
+ },
+
+ _onBlur: function(){
+ // summary:
+ // Called when focus moves outside the InlineEditBox.
+ // Performs garbage collection.
+ // tags:
+ // private
+
+ this.inherited(arguments);
+ if(!this.editing){
+ /* causes IE focus problems, see TooltipDialog_a11y.html...
+ setTimeout(dojo.hitch(this, function(){
+ if(this.wrapperWidget){
+ this.wrapperWidget.destroy();
+ delete this.wrapperWidget;
+ }
+ }), 0);
+ */
+ }
+ },
+
+ destroy: function(){
+ if(this.wrapperWidget){
+ this.wrapperWidget.destroy();
+ delete this.wrapperWidget;
+ }
+ this.inherited(arguments);
+ },
+
+ _showText: function(/*Boolean*/ focus){
+ // summary:
+ // Revert to display mode, and optionally focus on display node
+ // tags:
+ // private
+
+ var ww = this.wrapperWidget;
+ dojo.style(ww.domNode, { position: "absolute", visibility: "hidden", opacity: "0" }); // hide the editor from mouse/keyboard events
+ dojo.style(this.displayNode, { position: this._savedPosition, opacity: this._savedOpacity, display: "" }); // make the original text visible
+ dojo.attr(this.displayNode, "tabIndex", this._savedTabIndex);
+ if(focus){
+ dijit.focus(this.displayNode);
+ }
+ },
+
+ save: function(/*Boolean*/ focus){
+ // summary:
+ // Save the contents of the editor and revert to display mode.
+ // focus: Boolean
+ // Focus on the display mode text
+ // tags:
+ // private
+
+ if(this.disabled || !this.editing){ return; }
+ this.editing = false;
+
+ var ww = this.wrapperWidget;
+ var value = ww.getValue();
+ this.set('value', value); // display changed, formatted value
+
+ // tell the world that we have changed
+ setTimeout(dojo.hitch(this, "onChange", value), 0); // setTimeout prevents browser freeze for long-running event handlers
+
+ this._showText(focus); // set focus as needed
+ },
+
+ setValue: function(/*String*/ val){
+ // summary:
+ // Deprecated. Use set('value', ...) instead.
+ // tags:
+ // deprecated
+ dojo.deprecated("dijit.InlineEditBox.setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
+ return this.set("value", val);
+ },
+
+ _setValueAttr: function(/*String*/ val){
+ // summary:
+ // Hook to make set("value", ...) work.
+ // Inserts specified HTML value into this node, or an "input needed" character if node is blank.
+
+ this.value = val = dojo.trim(val);
+ if(!this.renderAsHtml){
+ val = val.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;").replace(/\n/g, "<br>");
+ }
+ this.displayNode.innerHTML = val || this.noValueIndicator;
+ },
+
+ getValue: function(){
+ // summary:
+ // Deprecated. Use get('value') instead.
+ // tags:
+ // deprecated
+ dojo.deprecated("dijit.InlineEditBox.getValue() is deprecated. Use get('value') instead.", "", "2.0");
+ return this.get("value");
+ },
+
+ cancel: function(/*Boolean*/ focus){
+ // summary:
+ // Revert to display mode, discarding any changes made in the editor
+ // tags:
+ // private
+
+ if(this.disabled || !this.editing){ return; }
+ this.editing = false;
+
+ // tell the world that we have no changes
+ setTimeout(dojo.hitch(this, "onCancel"), 0); // setTimeout prevents browser freeze for long-running event handlers
+
+ this._showText(focus);
+ }
+});
+
+dojo.declare(
+ "dijit._InlineEditor",
+ [dijit._Widget, dijit._Templated],
+{
+ // summary:
+ // Internal widget used by InlineEditBox, displayed when in editing mode
+ // to display the editor and maybe save/cancel buttons. Calling code should
+ // connect to save/cancel methods to detect when editing is finished
+ //
+ // Has mainly the same parameters as InlineEditBox, plus these values:
+ //
+ // style: Object
+ // Set of CSS attributes of display node, to replicate in editor
+ //
+ // value: String
+ // Value as an HTML string or plain text string, depending on renderAsHTML flag
+
+ templateString: dojo.cache("dijit", "templates/InlineEditBox.html", "<span dojoAttachPoint=\"editNode\" waiRole=\"presentation\" style=\"position: absolute; visibility:hidden\" class=\"dijitReset dijitInline\"\n\tdojoAttachEvent=\"onkeypress: _onKeyPress\"\n\t><span dojoAttachPoint=\"editorPlaceholder\"></span\n\t><span dojoAttachPoint=\"buttonContainer\"\n\t\t><button class='saveButton' dojoAttachPoint=\"saveButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:save\" label=\"${buttonSave}\"></button\n\t\t><button class='cancelButton' dojoAttachPoint=\"cancelButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:cancel\" label=\"${buttonCancel}\"></button\n\t></span\n></span>\n"),
+ widgetsInTemplate: true,
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this.messages = dojo.i18n.getLocalization("dijit", "common", this.lang);
+ dojo.forEach(["buttonSave", "buttonCancel"], function(prop){
+ if(!this[prop]){ this[prop] = this.messages[prop]; }
+ }, this);
+ },
+
+ postCreate: function(){
+ // Create edit widget in place in the template
+ var cls = dojo.getObject(this.editor);
+
+ // Copy the style from the source
+ // Don't copy ALL properties though, just the necessary/applicable ones.
+ // wrapperStyle/destStyle code is to workaround IE bug where getComputedStyle().fontSize
+ // is a relative value like 200%, rather than an absolute value like 24px, and
+ // the 200% can refer *either* to a setting on the node or it's ancestor (see #11175)
+ var srcStyle = this.sourceStyle,
+ editStyle = "line-height:" + srcStyle.lineHeight + ";",
+ destStyle = dojo.getComputedStyle(this.domNode);
+ dojo.forEach(["Weight","Family","Size","Style"], function(prop){
+ var textStyle = srcStyle["font"+prop],
+ wrapperStyle = destStyle["font"+prop];
+ if(wrapperStyle != textStyle){
+ editStyle += "font-"+prop+":"+srcStyle["font"+prop]+";";
+ }
+ }, this);
+ dojo.forEach(["marginTop","marginBottom","marginLeft", "marginRight"], function(prop){
+ this.domNode.style[prop] = srcStyle[prop];
+ }, this);
+ var width = this.inlineEditBox.width;
+ if(width == "100%"){
+ // block mode
+ editStyle += "width:100%;";
+ this.domNode.style.display = "block";
+ }else{
+ // inline-block mode
+ editStyle += "width:" + (width + (Number(width) == width ? "px" : "")) + ";";
+ }
+ var editorParams = dojo.delegate(this.inlineEditBox.editorParams, {
+ style: editStyle,
+ dir: this.dir,
+ lang: this.lang
+ });
+ editorParams[ "displayedValue" in cls.prototype ? "displayedValue" : "value"] = this.value;
+ var ew = (this.editWidget = new cls(editorParams, this.editorPlaceholder));
+
+ if(this.inlineEditBox.autoSave){
+ // Remove the save/cancel buttons since saving is done by simply tabbing away or
+ // selecting a value from the drop down list
+ dojo.destroy(this.buttonContainer);
+
+ // Selecting a value from a drop down list causes an onChange event and then we save
+ this.connect(ew, "onChange", "_onChange");
+
+ // ESC and TAB should cancel and save. Note that edit widgets do a stopEvent() on ESC key (to
+ // prevent Dialog from closing when the user just wants to revert the value in the edit widget),
+ // so this is the only way we can see the key press event.
+ this.connect(ew, "onKeyPress", "_onKeyPress");
+ }else{
+ // If possible, enable/disable save button based on whether the user has changed the value
+ if("intermediateChanges" in cls.prototype){
+ ew.set("intermediateChanges", true);
+ this.connect(ew, "onChange", "_onIntermediateChange");
+ this.saveButton.set("disabled", true);
+ }
+ }
+ },
+
+ _onIntermediateChange: function(val){
+ // summary:
+ // Called for editor widgets that support the intermediateChanges=true flag as a way
+ // to detect when to enable/disabled the save button
+ this.saveButton.set("disabled", (this.getValue() == this._resetValue) || !this.enableSave());
+ },
+
+ destroy: function(){
+ this.editWidget.destroy(true); // let the parent wrapper widget clean up the DOM
+ this.inherited(arguments);
+ },
+
+ getValue: function(){
+ // summary:
+ // Return the [display] value of the edit widget
+ var ew = this.editWidget;
+ return String(ew.get("displayedValue" in ew ? "displayedValue" : "value"));
+ },
+
+ _onKeyPress: function(e){
+ // summary:
+ // Handler for keypress in the edit box in autoSave mode.
+ // description:
+ // For autoSave widgets, if Esc/Enter, call cancel/save.
+ // tags:
+ // private
+
+ if(this.inlineEditBox.autoSave && this.inlineEditBox.editing){
+ if(e.altKey || e.ctrlKey){ return; }
+ // If Enter/Esc pressed, treat as save/cancel.
+ if(e.charOrCode == dojo.keys.ESCAPE){
+ dojo.stopEvent(e);
+ this.cancel(true); // sets editing=false which short-circuits _onBlur processing
+ }else if(e.charOrCode == dojo.keys.ENTER && e.target.tagName == "INPUT"){
+ dojo.stopEvent(e);
+ this._onChange(); // fire _onBlur and then save
+ }
+
+ // _onBlur will handle TAB automatically by allowing
+ // the TAB to change focus before we mess with the DOM: #6227
+ // Expounding by request:
+ // The current focus is on the edit widget input field.
+ // save() will hide and destroy this widget.
+ // We want the focus to jump from the currently hidden
+ // displayNode, but since it's hidden, it's impossible to
+ // unhide it, focus it, and then have the browser focus
+ // away from it to the next focusable element since each
+ // of these events is asynchronous and the focus-to-next-element
+ // is already queued.
+ // So we allow the browser time to unqueue the move-focus event
+ // before we do all the hide/show stuff.
+ }
+ },
+
+ _onBlur: function(){
+ // summary:
+ // Called when focus moves outside the editor
+ // tags:
+ // private
+
+ this.inherited(arguments);
+ if(this.inlineEditBox.autoSave && this.inlineEditBox.editing){
+ if(this.getValue() == this._resetValue){
+ this.cancel(false);
+ }else if(this.enableSave()){
+ this.save(false);
+ }
+ }
+ },
+
+ _onChange: function(){
+ // summary:
+ // Called when the underlying widget fires an onChange event,
+ // such as when the user selects a value from the drop down list of a ComboBox,
+ // which means that the user has finished entering the value and we should save.
+ // tags:
+ // private
+
+ if(this.inlineEditBox.autoSave && this.inlineEditBox.editing && this.enableSave()){
+ dojo.style(this.inlineEditBox.displayNode, { display: "" });
+ dijit.focus(this.inlineEditBox.displayNode); // fires _onBlur which will save the formatted value
+ }
+ },
+
+ enableSave: function(){
+ // summary:
+ // User overridable function returning a Boolean to indicate
+ // if the Save button should be enabled or not - usually due to invalid conditions
+ // tags:
+ // extension
+ return (
+ this.editWidget.isValid
+ ? this.editWidget.isValid()
+ : true
+ );
+ },
+
+ focus: function(){
+ // summary:
+ // Focus the edit widget.
+ // tags:
+ // protected
+
+ this.editWidget.focus();
+ setTimeout(dojo.hitch(this, function(){
+ if(this.editWidget.focusNode && this.editWidget.focusNode.tagName == "INPUT"){
+ dijit.selectInputText(this.editWidget.focusNode);
+ }
+ }), 0);
+ }
+});
+
+}
+
+if(!dojo._hasResource["dojo.cookie"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.cookie"] = true;
+dojo.provide("dojo.cookie");
+
+
+
+/*=====
+dojo.__cookieProps = function(){
+ // expires: Date|String|Number?
+ // If a number, the number of days from today at which the cookie
+ // will expire. If a date, the date past which the cookie will expire.
+ // If expires is in the past, the cookie will be deleted.
+ // If expires is omitted or is 0, the cookie will expire when the browser closes. << FIXME: 0 seems to disappear right away? FF3.
+ // path: String?
+ // The path to use for the cookie.
+ // domain: String?
+ // The domain to use for the cookie.
+ // secure: Boolean?
+ // Whether to only send the cookie on secure connections
+ this.expires = expires;
+ this.path = path;
+ this.domain = domain;
+ this.secure = secure;
+}
+=====*/
+
+
+dojo.cookie = function(/*String*/name, /*String?*/value, /*dojo.__cookieProps?*/props){
+ // summary:
+ // Get or set a cookie.
+ // description:
+ // If one argument is passed, returns the value of the cookie
+ // For two or more arguments, acts as a setter.
+ // name:
+ // Name of the cookie
+ // value:
+ // Value for the cookie
+ // props:
+ // Properties for the cookie
+ // example:
+ // set a cookie with the JSON-serialized contents of an object which
+ // will expire 5 days from now:
+ // | dojo.cookie("configObj", dojo.toJson(config), { expires: 5 });
+ //
+ // example:
+ // de-serialize a cookie back into a JavaScript object:
+ // | var config = dojo.fromJson(dojo.cookie("configObj"));
+ //
+ // example:
+ // delete a cookie:
+ // | dojo.cookie("configObj", null, {expires: -1});
+ var c = document.cookie;
+ if(arguments.length == 1){
+ var matches = c.match(new RegExp("(?:^|; )" + dojo.regexp.escapeString(name) + "=([^;]*)"));
+ return matches ? decodeURIComponent(matches[1]) : undefined; // String or undefined
+ }else{
+ props = props || {};
+// FIXME: expires=0 seems to disappear right away, not on close? (FF3) Change docs?
+ var exp = props.expires;
+ if(typeof exp == "number"){
+ var d = new Date();
+ d.setTime(d.getTime() + exp*24*60*60*1000);
+ exp = props.expires = d;
+ }
+ if(exp && exp.toUTCString){ props.expires = exp.toUTCString(); }
+
+ value = encodeURIComponent(value);
+ var updatedCookie = name + "=" + value, propName;
+ for(propName in props){
+ updatedCookie += "; " + propName;
+ var propValue = props[propName];
+ if(propValue !== true){ updatedCookie += "=" + propValue; }
+ }
+ document.cookie = updatedCookie;
+ }
+};
+
+dojo.cookie.isSupported = function(){
+ // summary:
+ // Use to determine if the current browser supports cookies or not.
+ //
+ // Returns true if user allows cookies.
+ // Returns false if user doesn't allow cookies.
+
+ if(!("cookieEnabled" in navigator)){
+ this("__djCookieTest__", "CookiesAllowed");
+ navigator.cookieEnabled = this("__djCookieTest__") == "CookiesAllowed";
+ if(navigator.cookieEnabled){
+ this("__djCookieTest__", "", {expires: -1});
+ }
+ }
+ return navigator.cookieEnabled;
+};
+
+}
+
+if(!dojo._hasResource["dijit.layout.StackController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.StackController"] = true;
+dojo.provide("dijit.layout.StackController");
+
+
+
+
+
+
+
+dojo.declare(
+ "dijit.layout.StackController",
+ [dijit._Widget, dijit._Templated, dijit._Container],
+ {
+ // summary:
+ // Set of buttons to select a page in a page list.
+ // description:
+ // Monitors the specified StackContainer, and whenever a page is
+ // added, deleted, or selected, updates itself accordingly.
+
+ templateString: "<span wairole='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>",
+
+ // containerId: [const] String
+ // The id of the page container that I point to
+ containerId: "",
+
+ // buttonWidget: [const] String
+ // The name of the button widget to create to correspond to each page
+ buttonWidget: "dijit.layout._StackButton",
+
+ postCreate: function(){
+ dijit.setWaiRole(this.domNode, "tablist");
+
+ this.pane2button = {}; // mapping from pane id to buttons
+ this.pane2handles = {}; // mapping from pane id to this.connect() handles
+
+ // Listen to notifications from StackContainer
+ this.subscribe(this.containerId+"-startup", "onStartup");
+ this.subscribe(this.containerId+"-addChild", "onAddChild");
+ this.subscribe(this.containerId+"-removeChild", "onRemoveChild");
+ this.subscribe(this.containerId+"-selectChild", "onSelectChild");
+ this.subscribe(this.containerId+"-containerKeyPress", "onContainerKeyPress");
+ },
+
+ onStartup: function(/*Object*/ info){
+ // summary:
+ // Called after StackContainer has finished initializing
+ // tags:
+ // private
+ dojo.forEach(info.children, this.onAddChild, this);
+ if(info.selected){
+ // Show button corresponding to selected pane (unless selected
+ // is null because there are no panes)
+ this.onSelectChild(info.selected);
+ }
+ },
+
+ destroy: function(){
+ for(var pane in this.pane2button){
+ this.onRemoveChild(dijit.byId(pane));
+ }
+ this.inherited(arguments);
+ },
+
+ onAddChild: function(/*dijit._Widget*/ page, /*Integer?*/ insertIndex){
+ // summary:
+ // Called whenever a page is added to the container.
+ // Create button corresponding to the page.
+ // tags:
+ // private
+
+ // create an instance of the button widget
+ var cls = dojo.getObject(this.buttonWidget);
+ var button = new cls({
+ id: this.id + "_" + page.id,
+ label: page.title,
+ dir: page.dir,
+ lang: page.lang,
+ showLabel: page.showTitle,
+ iconClass: page.iconClass,
+ closeButton: page.closable,
+ title: page.tooltip
+ });
+ dijit.setWaiState(button.focusNode,"selected", "false");
+ this.pane2handles[page.id] = [
+ this.connect(page, 'set', function(name, value){
+ var buttonAttr = {
+ title: 'label',
+ showTitle: 'showLabel',
+ iconClass: 'iconClass',
+ closable: 'closeButton',
+ tooltip: 'title'
+ }[name];
+ if(buttonAttr){
+ button.set(buttonAttr, value);
+ }
+ }),
+ this.connect(button, 'onClick', dojo.hitch(this,"onButtonClick", page)),
+ this.connect(button, 'onClickCloseButton', dojo.hitch(this,"onCloseButtonClick", page))
+ ];
+ this.addChild(button, insertIndex);
+ this.pane2button[page.id] = button;
+ page.controlButton = button; // this value might be overwritten if two tabs point to same container
+ if(!this._currentChild){ // put the first child into the tab order
+ button.focusNode.setAttribute("tabIndex", "0");
+ dijit.setWaiState(button.focusNode, "selected", "true");
+ this._currentChild = page;
+ }
+ // make sure all tabs have the same length
+ if(!this.isLeftToRight() && dojo.isIE && this._rectifyRtlTabList){
+ this._rectifyRtlTabList();
+ }
+ },
+
+ onRemoveChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Called whenever a page is removed from the container.
+ // Remove the button corresponding to the page.
+ // tags:
+ // private
+
+ if(this._currentChild === page){ this._currentChild = null; }
+ dojo.forEach(this.pane2handles[page.id], this.disconnect, this);
+ delete this.pane2handles[page.id];
+ var button = this.pane2button[page.id];
+ if(button){
+ this.removeChild(button);
+ delete this.pane2button[page.id];
+ button.destroy();
+ }
+ delete page.controlButton;
+ },
+
+ onSelectChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Called when a page has been selected in the StackContainer, either by me or by another StackController
+ // tags:
+ // private
+
+ if(!page){ return; }
+
+ if(this._currentChild){
+ var oldButton=this.pane2button[this._currentChild.id];
+ oldButton.set('checked', false);
+ dijit.setWaiState(oldButton.focusNode, "selected", "false");
+ oldButton.focusNode.setAttribute("tabIndex", "-1");
+ }
+
+ var newButton=this.pane2button[page.id];
+ newButton.set('checked', true);
+ dijit.setWaiState(newButton.focusNode, "selected", "true");
+ this._currentChild = page;
+ newButton.focusNode.setAttribute("tabIndex", "0");
+ var container = dijit.byId(this.containerId);
+ dijit.setWaiState(container.containerNode, "labelledby", newButton.id);
+ },
+
+ onButtonClick: function(/*dijit._Widget*/ page){
+ // summary:
+ // Called whenever one of my child buttons is pressed in an attempt to select a page
+ // tags:
+ // private
+
+ var container = dijit.byId(this.containerId);
+ container.selectChild(page);
+ },
+
+ onCloseButtonClick: function(/*dijit._Widget*/ page){
+ // summary:
+ // Called whenever one of my child buttons [X] is pressed in an attempt to close a page
+ // tags:
+ // private
+
+ var container = dijit.byId(this.containerId);
+ container.closeChild(page);
+ if(this._currentChild){
+ var b = this.pane2button[this._currentChild.id];
+ if(b){
+ dijit.focus(b.focusNode || b.domNode);
+ }
+ }
+ },
+
+ // TODO: this is a bit redundant with forward, back api in StackContainer
+ adjacent: function(/*Boolean*/ forward){
+ // summary:
+ // Helper for onkeypress to find next/previous button
+ // tags:
+ // private
+
+ if(!this.isLeftToRight() && (!this.tabPosition || /top|bottom/.test(this.tabPosition))){ forward = !forward; }
+ // find currently focused button in children array
+ var children = this.getChildren();
+ var current = dojo.indexOf(children, this.pane2button[this._currentChild.id]);
+ // pick next button to focus on
+ var offset = forward ? 1 : children.length - 1;
+ return children[ (current + offset) % children.length ]; // dijit._Widget
+ },
+
+ onkeypress: function(/*Event*/ e){
+ // summary:
+ // Handle keystrokes on the page list, for advancing to next/previous button
+ // and closing the current page if the page is closable.
+ // tags:
+ // private
+
+ if(this.disabled || e.altKey ){ return; }
+ var forward = null;
+ if(e.ctrlKey || !e._djpage){
+ var k = dojo.keys;
+ switch(e.charOrCode){
+ case k.LEFT_ARROW:
+ case k.UP_ARROW:
+ if(!e._djpage){ forward = false; }
+ break;
+ case k.PAGE_UP:
+ if(e.ctrlKey){ forward = false; }
+ break;
+ case k.RIGHT_ARROW:
+ case k.DOWN_ARROW:
+ if(!e._djpage){ forward = true; }
+ break;
+ case k.PAGE_DOWN:
+ if(e.ctrlKey){ forward = true; }
+ break;
+ case k.DELETE:
+ if(this._currentChild.closable){
+ this.onCloseButtonClick(this._currentChild);
+ }
+ dojo.stopEvent(e);
+ break;
+ default:
+ if(e.ctrlKey){
+ if(e.charOrCode === k.TAB){
+ this.adjacent(!e.shiftKey).onClick();
+ dojo.stopEvent(e);
+ }else if(e.charOrCode == "w"){
+ if(this._currentChild.closable){
+ this.onCloseButtonClick(this._currentChild);
+ }
+ dojo.stopEvent(e); // avoid browser tab closing.
+ }
+ }
+ }
+ // handle page navigation
+ if(forward !== null){
+ this.adjacent(forward).onClick();
+ dojo.stopEvent(e);
+ }
+ }
+ },
+
+ onContainerKeyPress: function(/*Object*/ info){
+ // summary:
+ // Called when there was a keypress on the container
+ // tags:
+ // private
+ info.e._djpage = info.page;
+ this.onkeypress(info.e);
+ }
+ });
+
+
+dojo.declare("dijit.layout._StackButton",
+ dijit.form.ToggleButton,
+ {
+ // summary:
+ // Internal widget used by StackContainer.
+ // description:
+ // The button-like or tab-like object you click to select or delete a page
+ // tags:
+ // private
+
+ // Override _FormWidget.tabIndex.
+ // StackContainer buttons are not in the tab order by default.
+ // Probably we should be calling this.startupKeyNavChildren() instead.
+ tabIndex: "-1",
+
+ postCreate: function(/*Event*/ evt){
+ dijit.setWaiRole((this.focusNode || this.domNode), "tab");
+ this.inherited(arguments);
+ },
+
+ onClick: function(/*Event*/ evt){
+ // summary:
+ // This is for TabContainer where the tabs are <span> rather than button,
+ // so need to set focus explicitly (on some browsers)
+ // Note that you shouldn't override this method, but you can connect to it.
+ dijit.focus(this.focusNode);
+
+ // ... now let StackController catch the event and tell me what to do
+ },
+
+ onClickCloseButton: function(/*Event*/ evt){
+ // summary:
+ // StackContainer connects to this function; if your widget contains a close button
+ // then clicking it should call this function.
+ // Note that you shouldn't override this method, but you can connect to it.
+ evt.stopPropagation();
+ }
+ });
+
+
+}
+
+if(!dojo._hasResource["dijit.layout.StackContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.StackContainer"] = true;
+dojo.provide("dijit.layout.StackContainer");
+
+
+
+
+
+
+dojo.declare(
+ "dijit.layout.StackContainer",
+ dijit.layout._LayoutWidget,
+ {
+ // summary:
+ // A container that has multiple children, but shows only
+ // one child at a time
+ //
+ // description:
+ // A container for widgets (ContentPanes, for example) That displays
+ // only one Widget at a time.
+ //
+ // Publishes topics [widgetId]-addChild, [widgetId]-removeChild, and [widgetId]-selectChild
+ //
+ // Can be base class for container, Wizard, Show, etc.
+
+ // doLayout: Boolean
+ // If true, change the size of my currently displayed child to match my size
+ doLayout: true,
+
+ // persist: Boolean
+ // Remembers the selected child across sessions
+ persist: false,
+
+ baseClass: "dijitStackContainer",
+
+/*=====
+ // selectedChildWidget: [readonly] dijit._Widget
+ // References the currently selected child widget, if any.
+ // Adjust selected child with selectChild() method.
+ selectedChildWidget: null,
+=====*/
+
+ postCreate: function(){
+ this.inherited(arguments);
+ dojo.addClass(this.domNode, "dijitLayoutContainer");
+ dijit.setWaiRole(this.containerNode, "tabpanel");
+ this.connect(this.domNode, "onkeypress", this._onKeyPress);
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+
+ var children = this.getChildren();
+
+ // Setup each page panel to be initially hidden
+ dojo.forEach(children, this._setupChild, this);
+
+ // Figure out which child to initially display, defaulting to first one
+ if(this.persist){
+ this.selectedChildWidget = dijit.byId(dojo.cookie(this.id + "_selectedChild"));
+ }else{
+ dojo.some(children, function(child){
+ if(child.selected){
+ this.selectedChildWidget = child;
+ }
+ return child.selected;
+ }, this);
+ }
+ var selected = this.selectedChildWidget;
+ if(!selected && children[0]){
+ selected = this.selectedChildWidget = children[0];
+ selected.selected = true;
+ }
+
+ // Publish information about myself so any StackControllers can initialize.
+ // This needs to happen before this.inherited(arguments) so that for
+ // TabContainer, this._contentBox doesn't include the space for the tab labels.
+ dojo.publish(this.id+"-startup", [{children: children, selected: selected}]);
+
+ // Startup each child widget, and do initial layout like setting this._contentBox,
+ // then calls this.resize() which does the initial sizing on the selected child.
+ this.inherited(arguments);
+ },
+
+ resize: function(){
+ // Resize is called when we are first made visible (it's called from startup()
+ // if we are initially visible). If this is the first time we've been made
+ // visible then show our first child.
+ var selected = this.selectedChildWidget;
+ if(selected && !this._hasBeenShown){
+ this._hasBeenShown = true;
+ this._showChild(selected);
+ }
+ this.inherited(arguments);
+ },
+
+ _setupChild: function(/*dijit._Widget*/ child){
+ // Overrides _LayoutWidget._setupChild()
+
+ this.inherited(arguments);
+
+ dojo.removeClass(child.domNode, "dijitVisible");
+ dojo.addClass(child.domNode, "dijitHidden");
+
+ // remove the title attribute so it doesn't show up when i hover
+ // over a node
+ child.domNode.title = "";
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ // Overrides _Container.addChild() to do layout and publish events
+
+ this.inherited(arguments);
+
+ if(this._started){
+ dojo.publish(this.id+"-addChild", [child, insertIndex]);
+
+ // in case the tab titles have overflowed from one line to two lines
+ // (or, if this if first child, from zero lines to one line)
+ // TODO: w/ScrollingTabController this is no longer necessary, although
+ // ScrollTabController.resize() does need to get called to show/hide
+ // the navigation buttons as appropriate, but that's handled in ScrollingTabController.onAddChild()
+ this.layout();
+
+ // if this is the first child, then select it
+ if(!this.selectedChildWidget){
+ this.selectChild(child);
+ }
+ }
+ },
+
+ removeChild: function(/*dijit._Widget*/ page){
+ // Overrides _Container.removeChild() to do layout and publish events
+
+ this.inherited(arguments);
+
+ if(this._started){
+ // this will notify any tablists to remove a button; do this first because it may affect sizing
+ dojo.publish(this.id + "-removeChild", [page]);
+ }
+
+ // If we are being destroyed than don't run the code below (to select another page), because we are deleting
+ // every page one by one
+ if(this._beingDestroyed){ return; }
+
+ // Select new page to display, also updating TabController to show the respective tab.
+ // Do this before layout call because it can affect the height of the TabController.
+ if(this.selectedChildWidget === page){
+ this.selectedChildWidget = undefined;
+ if(this._started){
+ var children = this.getChildren();
+ if(children.length){
+ this.selectChild(children[0]);
+ }
+ }
+ }
+
+ if(this._started){
+ // In case the tab titles now take up one line instead of two lines
+ // (note though that ScrollingTabController never overflows to multiple lines),
+ // or the height has changed slightly because of addition/removal of tab which close icon
+ this.layout();
+ }
+ },
+
+ selectChild: function(/*dijit._Widget|String*/ page, /*Boolean*/ animate){
+ // summary:
+ // Show the given widget (which must be one of my children)
+ // page:
+ // Reference to child widget or id of child widget
+
+ page = dijit.byId(page);
+
+ if(this.selectedChildWidget != page){
+ // Deselect old page and select new one
+ this._transition(page, this.selectedChildWidget, animate);
+ this.selectedChildWidget = page;
+ dojo.publish(this.id+"-selectChild", [page]);
+
+ if(this.persist){
+ dojo.cookie(this.id + "_selectedChild", this.selectedChildWidget.id);
+ }
+ }
+ },
+
+ _transition: function(/*dijit._Widget*/newWidget, /*dijit._Widget*/oldWidget){
+ // summary:
+ // Hide the old widget and display the new widget.
+ // Subclasses should override this.
+ // tags:
+ // protected extension
+ if(oldWidget){
+ this._hideChild(oldWidget);
+ }
+ this._showChild(newWidget);
+
+ // Size the new widget, in case this is the first time it's being shown,
+ // or I have been resized since the last time it was shown.
+ // Note that page must be visible for resizing to work.
+ if(newWidget.resize){
+ if(this.doLayout){
+ newWidget.resize(this._containerContentBox || this._contentBox);
+ }else{
+ // the child should pick it's own size but we still need to call resize()
+ // (with no arguments) to let the widget lay itself out
+ newWidget.resize();
+ }
+ }
+ },
+
+ _adjacent: function(/*Boolean*/ forward){
+ // summary:
+ // Gets the next/previous child widget in this container from the current selection.
+ var children = this.getChildren();
+ var index = dojo.indexOf(children, this.selectedChildWidget);
+ index += forward ? 1 : children.length - 1;
+ return children[ index % children.length ]; // dijit._Widget
+ },
+
+ forward: function(){
+ // summary:
+ // Advance to next page.
+ this.selectChild(this._adjacent(true), true);
+ },
+
+ back: function(){
+ // summary:
+ // Go back to previous page.
+ this.selectChild(this._adjacent(false), true);
+ },
+
+ _onKeyPress: function(e){
+ dojo.publish(this.id+"-containerKeyPress", [{ e: e, page: this}]);
+ },
+
+ layout: function(){
+ // Implement _LayoutWidget.layout() virtual method.
+ if(this.doLayout && this.selectedChildWidget && this.selectedChildWidget.resize){
+ this.selectedChildWidget.resize(this._containerContentBox || this._contentBox);
+ }
+ },
+
+ _showChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Show the specified child by changing it's CSS, and call _onShow()/onShow() so
+ // it can do any updates it needs regarding loading href's etc.
+ var children = this.getChildren();
+ page.isFirstChild = (page == children[0]);
+ page.isLastChild = (page == children[children.length-1]);
+ page.selected = true;
+
+ dojo.removeClass(page.domNode, "dijitHidden");
+ dojo.addClass(page.domNode, "dijitVisible");
+
+ page._onShow();
+ },
+
+ _hideChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Hide the specified child by changing it's CSS, and call _onHide() so
+ // it's notified.
+ page.selected=false;
+ dojo.removeClass(page.domNode, "dijitVisible");
+ dojo.addClass(page.domNode, "dijitHidden");
+
+ page.onHide();
+ },
+
+ closeChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Callback when user clicks the [X] to remove a page.
+ // If onClose() returns true then remove and destroy the child.
+ // tags:
+ // private
+ var remove = page.onClose(this, page);
+ if(remove){
+ this.removeChild(page);
+ // makes sure we can clean up executeScripts in ContentPane onUnLoad
+ page.destroyRecursive();
+ }
+ },
+
+ destroyDescendants: function(/*Boolean*/preserveDom){
+ dojo.forEach(this.getChildren(), function(child){
+ this.removeChild(child);
+ child.destroyRecursive(preserveDom);
+ }, this);
+ }
+});
+
+// For back-compat, remove for 2.0
+
+
+
+// These arguments can be specified for the children of a StackContainer.
+// Since any widget can be specified as a StackContainer child, mix them
+// into the base widget class. (This is a hack, but it's effective.)
+dojo.extend(dijit._Widget, {
+ // selected: Boolean
+ // Parameter for children of `dijit.layout.StackContainer` or subclasses.
+ // Specifies that this widget should be the initially displayed pane.
+ // Note: to change the selected child use `dijit.layout.StackContainer.selectChild`
+ selected: false,
+
+ // closable: Boolean
+ // Parameter for children of `dijit.layout.StackContainer` or subclasses.
+ // True if user can close (destroy) this child, such as (for example) clicking the X on the tab.
+ closable: false,
+
+ // iconClass: String
+ // Parameter for children of `dijit.layout.StackContainer` or subclasses.
+ // CSS Class specifying icon to use in label associated with this pane.
+ iconClass: "",
+
+ // showTitle: Boolean
+ // Parameter for children of `dijit.layout.StackContainer` or subclasses.
+ // When true, display title of this widget as tab label etc., rather than just using
+ // icon specified in iconClass
+ showTitle: true
+});
+
+}
+
+if(!dojo._hasResource["dijit.layout.AccordionPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.AccordionPane"] = true;
+dojo.provide("dijit.layout.AccordionPane");
+
+
+
+dojo.declare("dijit.layout.AccordionPane", dijit.layout.ContentPane, {
+ // summary:
+ // Deprecated widget. Use `dijit.layout.ContentPane` instead.
+ // tags:
+ // deprecated
+
+ constructor: function(){
+ dojo.deprecated("dijit.layout.AccordionPane deprecated, use ContentPane instead", "", "2.0");
+ },
+
+ onSelected: function(){
+ // summary:
+ // called when this pane is selected
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.layout.AccordionContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.AccordionContainer"] = true;
+dojo.provide("dijit.layout.AccordionContainer");
+
+
+
+
+
+
+
+
+
+ // for back compat, remove for 2.0
+
+dojo.declare(
+ "dijit.layout.AccordionContainer",
+ dijit.layout.StackContainer,
+ {
+ // summary:
+ // Holds a set of panes where every pane's title is visible, but only one pane's content is visible at a time,
+ // and switching between panes is visualized by sliding the other panes up/down.
+ // example:
+ // | <div dojoType="dijit.layout.AccordionContainer">
+ // | <div dojoType="dijit.layout.ContentPane" title="pane 1">
+ // | </div>
+ // | <div dojoType="dijit.layout.ContentPane" title="pane 2">
+ // | <p>This is some text</p>
+ // | </div>
+ // | </div>
+
+ // duration: Integer
+ // Amount of time (in ms) it takes to slide panes
+ duration: dijit.defaultDuration,
+
+ // buttonWidget: [const] String
+ // The name of the widget used to display the title of each pane
+ buttonWidget: "dijit.layout._AccordionButton",
+
+ // _verticalSpace: Number
+ // Pixels of space available for the open pane
+ // (my content box size minus the cumulative size of all the title bars)
+ _verticalSpace: 0,
+
+ baseClass: "dijitAccordionContainer",
+
+ postCreate: function(){
+ this.domNode.style.overflow = "hidden";
+ this.inherited(arguments);
+ dijit.setWaiRole(this.domNode, "tablist");
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+ this.inherited(arguments);
+ if(this.selectedChildWidget){
+ var style = this.selectedChildWidget.containerNode.style;
+ style.display = "";
+ style.overflow = "auto";
+ this.selectedChildWidget._wrapperWidget.set("selected", true);
+ }
+ },
+
+ _getTargetHeight: function(/* Node */ node){
+ // summary:
+ // For the given node, returns the height that should be
+ // set to achieve our vertical space (subtract any padding
+ // we may have).
+ //
+ // This is used by the animations.
+ //
+ // TODO: I don't think this works correctly in IE quirks when an elements
+ // style.height including padding and borders
+ var cs = dojo.getComputedStyle(node);
+ return Math.max(this._verticalSpace - dojo._getPadBorderExtents(node, cs).h - dojo._getMarginExtents(node, cs).h, 0);
+ },
+
+ layout: function(){
+ // Implement _LayoutWidget.layout() virtual method.
+ // Set the height of the open pane based on what room remains.
+
+ var openPane = this.selectedChildWidget;
+
+ if(!openPane){ return;}
+
+ var openPaneContainer = openPane._wrapperWidget.domNode,
+ openPaneContainerMargin = dojo._getMarginExtents(openPaneContainer),
+ openPaneContainerPadBorder = dojo._getPadBorderExtents(openPaneContainer),
+ mySize = this._contentBox;
+
+ // get cumulative height of all the unselected title bars
+ var totalCollapsedHeight = 0;
+ dojo.forEach(this.getChildren(), function(child){
+ if(child != openPane){
+ totalCollapsedHeight += dojo.marginBox(child._wrapperWidget.domNode).h;
+ }
+ });
+ this._verticalSpace = mySize.h - totalCollapsedHeight - openPaneContainerMargin.h
+ - openPaneContainerPadBorder.h - openPane._buttonWidget.getTitleHeight();
+
+ // Memo size to make displayed child
+ this._containerContentBox = {
+ h: this._verticalSpace,
+ w: this._contentBox.w - openPaneContainerMargin.w - openPaneContainerPadBorder.w
+ };
+
+ if(openPane){
+ openPane.resize(this._containerContentBox);
+ }
+ },
+
+ _setupChild: function(child){
+ // Overrides _LayoutWidget._setupChild().
+ // Put wrapper widget around the child widget, showing title
+
+ child._wrapperWidget = new dijit.layout._AccordionInnerContainer({
+ contentWidget: child,
+ buttonWidget: this.buttonWidget,
+ id: child.id + "_wrapper",
+ dir: child.dir,
+ lang: child.lang,
+ parent: this
+ });
+
+ this.inherited(arguments);
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ if(this._started){
+ // Adding a child to a started Accordion is complicated because children have
+ // wrapper widgets. Default code path (calling this.inherited()) would add
+ // the new child inside another child's wrapper.
+
+ // First add in child as a direct child of this AccordionContainer
+ dojo.place(child.domNode, this.containerNode, insertIndex);
+
+ if(!child._started){
+ child.startup();
+ }
+
+ // Then stick the wrapper widget around the child widget
+ this._setupChild(child);
+
+ // Code below copied from StackContainer
+ dojo.publish(this.id+"-addChild", [child, insertIndex]);
+ this.layout();
+ if(!this.selectedChildWidget){
+ this.selectChild(child);
+ }
+ }else{
+ // We haven't been started yet so just add in the child widget directly,
+ // and the wrapper will be created on startup()
+ this.inherited(arguments);
+ }
+ },
+
+ removeChild: function(child){
+ // Overrides _LayoutWidget.removeChild().
+
+ // destroy wrapper widget first, before StackContainer.getChildren() call
+ child._wrapperWidget.destroy();
+ delete child._wrapperWidget;
+ dojo.removeClass(child.domNode, "dijitHidden");
+
+ this.inherited(arguments);
+ },
+
+ getChildren: function(){
+ // Overrides _Container.getChildren() to return content panes rather than internal AccordionInnerContainer panes
+ return dojo.map(this.inherited(arguments), function(child){
+ return child.declaredClass == "dijit.layout._AccordionInnerContainer" ? child.contentWidget : child;
+ }, this);
+ },
+
+ destroy: function(){
+ dojo.forEach(this.getChildren(), function(child){
+ child._wrapperWidget.destroy();
+ });
+ this.inherited(arguments);
+ },
+
+ _transition: function(/*dijit._Widget?*/newWidget, /*dijit._Widget?*/oldWidget, /*Boolean*/ animate){
+ // Overrides StackContainer._transition() to provide sliding of title bars etc.
+
+//TODO: should be able to replace this with calls to slideIn/slideOut
+ if(this._inTransition){ return; }
+ var animations = [];
+ var paneHeight = this._verticalSpace;
+ if(newWidget){
+ newWidget._wrapperWidget.set("selected", true);
+
+ this._showChild(newWidget); // prepare widget to be slid in
+
+ // Size the new widget, in case this is the first time it's being shown,
+ // or I have been resized since the last time it was shown.
+ // Note that page must be visible for resizing to work.
+ if(this.doLayout && newWidget.resize){
+ newWidget.resize(this._containerContentBox);
+ }
+
+ var newContents = newWidget.domNode;
+ dojo.addClass(newContents, "dijitVisible");
+ dojo.removeClass(newContents, "dijitHidden");
+
+ if(animate){
+ var newContentsOverflow = newContents.style.overflow;
+ newContents.style.overflow = "hidden";
+ animations.push(dojo.animateProperty({
+ node: newContents,
+ duration: this.duration,
+ properties: {
+ height: { start: 1, end: this._getTargetHeight(newContents) }
+ },
+ onEnd: function(){
+ newContents.style.overflow = newContentsOverflow;
+
+ // Kick IE to workaround layout bug, see #11415
+ if(dojo.isIE){
+ setTimeout(function(){
+ dojo.removeClass(newContents.parentNode, "dijitAccordionInnerContainerFocused");
+ setTimeout(function(){
+ dojo.addClass(newContents.parentNode, "dijitAccordionInnerContainerFocused");
+ }, 0);
+ }, 0);
+ }
+ }
+ }));
+ }
+ }
+ if(oldWidget){
+ oldWidget._wrapperWidget.set("selected", false);
+ var oldContents = oldWidget.domNode;
+ if(animate){
+ var oldContentsOverflow = oldContents.style.overflow;
+ oldContents.style.overflow = "hidden";
+ animations.push(dojo.animateProperty({
+ node: oldContents,
+ duration: this.duration,
+ properties: {
+ height: { start: this._getTargetHeight(oldContents), end: 1 }
+ },
+ onEnd: function(){
+ dojo.addClass(oldContents, "dijitHidden");
+ dojo.removeClass(oldContents, "dijitVisible");
+ oldContents.style.overflow = oldContentsOverflow;
+ if(oldWidget.onHide){
+ oldWidget.onHide();
+ }
+ }
+ }));
+ }else{
+ dojo.addClass(oldContents, "dijitHidden");
+ dojo.removeClass(oldContents, "dijitVisible");
+ if(oldWidget.onHide){
+ oldWidget.onHide();
+ }
+ }
+ }
+
+ if(animate){
+ this._inTransition = true;
+ var combined = dojo.fx.combine(animations);
+ combined.onEnd = dojo.hitch(this, function(){
+ delete this._inTransition;
+ });
+ combined.play();
+ }
+ },
+
+ // note: we are treating the container as controller here
+ _onKeyPress: function(/*Event*/ e, /*dijit._Widget*/ fromTitle){
+ // summary:
+ // Handle keypress events
+ // description:
+ // This is called from a handler on AccordionContainer.domNode
+ // (setup in StackContainer), and is also called directly from
+ // the click handler for accordion labels
+ if(this._inTransition || this.disabled || e.altKey || !(fromTitle || e.ctrlKey)){
+ if(this._inTransition){
+ dojo.stopEvent(e);
+ }
+ return;
+ }
+ var k = dojo.keys,
+ c = e.charOrCode;
+ if((fromTitle && (c == k.LEFT_ARROW || c == k.UP_ARROW)) ||
+ (e.ctrlKey && c == k.PAGE_UP)){
+ this._adjacent(false)._buttonWidget._onTitleClick();
+ dojo.stopEvent(e);
+ }else if((fromTitle && (c == k.RIGHT_ARROW || c == k.DOWN_ARROW)) ||
+ (e.ctrlKey && (c == k.PAGE_DOWN || c == k.TAB))){
+ this._adjacent(true)._buttonWidget._onTitleClick();
+ dojo.stopEvent(e);
+ }
+ }
+ }
+);
+
+dojo.declare("dijit.layout._AccordionInnerContainer",
+ [dijit._Widget, dijit._CssStateMixin], {
+ // summary:
+ // Internal widget placed as direct child of AccordionContainer.containerNode.
+ // When other widgets are added as children to an AccordionContainer they are wrapped in
+ // this widget.
+
+ // buttonWidget: String
+ // Name of class to use to instantiate title
+ // (Wish we didn't have a separate widget for just the title but maintaining it
+ // for backwards compatibility, is it worth it?)
+/*=====
+ buttonWidget: null,
+=====*/
+ // contentWidget: dijit._Widget
+ // Pointer to the real child widget
+/*=====
+ contentWidget: null,
+=====*/
+
+ baseClass: "dijitAccordionInnerContainer",
+
+ // tell nested layout widget that we will take care of sizing
+ isContainer: true,
+ isLayoutContainer: true,
+
+ buildRendering: function(){
+ // Create wrapper div, placed where the child is now
+ this.domNode = dojo.place("<div class='" + this.baseClass + "'>", this.contentWidget.domNode, "after");
+
+ // wrapper div's first child is the button widget (ie, the title bar)
+ var child = this.contentWidget,
+ cls = dojo.getObject(this.buttonWidget);
+ this.button = child._buttonWidget = (new cls({
+ contentWidget: child,
+ label: child.title,
+ title: child.tooltip,
+ dir: child.dir,
+ lang: child.lang,
+ iconClass: child.iconClass,
+ id: child.id + "_button",
+ parent: this.parent
+ })).placeAt(this.domNode);
+
+ // and then the actual content widget (changing it from prior-sibling to last-child)
+ dojo.place(this.contentWidget.domNode, this.domNode);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.connect(this.contentWidget, 'set', function(name, value){
+ var mappedName = {title: "label", tooltip: "title", iconClass: "iconClass"}[name];
+ if(mappedName){
+ this.button.set(mappedName, value);
+ }
+ }, this);
+ },
+
+ _setSelectedAttr: function(/*Boolean*/ isSelected){
+ this.selected = isSelected;
+ this.button.set("selected", isSelected);
+ if(isSelected){
+ var cw = this.contentWidget;
+ if(cw.onSelected){ cw.onSelected(); }
+ }
+ },
+
+ startup: function(){
+ // Called by _Container.addChild()
+ this.contentWidget.startup();
+ },
+
+ destroy: function(){
+ this.button.destroyRecursive();
+
+ delete this.contentWidget._buttonWidget;
+ delete this.contentWidget._wrapperWidget;
+
+ this.inherited(arguments);
+ },
+
+ destroyDescendants: function(){
+ // since getChildren isn't working for me, have to code this manually
+ this.contentWidget.destroyRecursive();
+ }
+});
+
+dojo.declare("dijit.layout._AccordionButton",
+ [dijit._Widget, dijit._Templated, dijit._CssStateMixin],
+ {
+ // summary:
+ // The title bar to click to open up an accordion pane.
+ // Internal widget used by AccordionContainer.
+ // tags:
+ // private
+
+ templateString: dojo.cache("dijit.layout", "templates/AccordionButton.html", "<div dojoAttachEvent='onclick:_onTitleClick' class='dijitAccordionTitle'>\n\t<div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='onkeypress:_onTitleKeyPress'\n\t\t\tclass='dijitAccordionTitleFocus' wairole=\"tab\" waiState=\"expanded-false\"\n\t\t><span class='dijitInline dijitAccordionArrow' waiRole=\"presentation\"></span\n\t\t><span class='arrowTextUp' waiRole=\"presentation\">+</span\n\t\t><span class='arrowTextDown' waiRole=\"presentation\">-</span\n\t\t><img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' style=\"vertical-align: middle\" waiRole=\"presentation\"/>\n\t\t<span waiRole=\"presentation\" dojoAttachPoint='titleTextNode' class='dijitAccordionText'></span>\n\t</div>\n</div>\n"),
+ attributeMap: dojo.mixin(dojo.clone(dijit.layout.ContentPane.prototype.attributeMap), {
+ label: {node: "titleTextNode", type: "innerHTML" },
+ title: {node: "titleTextNode", type: "attribute", attribute: "title"},
+ iconClass: { node: "iconNode", type: "class" }
+ }),
+
+ baseClass: "dijitAccordionTitle",
+
+ getParent: function(){
+ // summary:
+ // Returns the AccordionContainer parent.
+ // tags:
+ // private
+ return this.parent;
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ dojo.setSelectable(this.domNode, false);
+ var titleTextNodeId = dojo.attr(this.domNode,'id').replace(' ','_');
+ dojo.attr(this.titleTextNode, "id", titleTextNodeId+"_title");
+ dijit.setWaiState(this.focusNode, "labelledby", dojo.attr(this.titleTextNode, "id"));
+ },
+
+ getTitleHeight: function(){
+ // summary:
+ // Returns the height of the title dom node.
+ return dojo.marginBox(this.domNode).h; // Integer
+ },
+
+ // TODO: maybe the parent should set these methods directly rather than forcing the code
+ // into the button widget?
+ _onTitleClick: function(){
+ // summary:
+ // Callback when someone clicks my title.
+ var parent = this.getParent();
+ if(!parent._inTransition){
+ parent.selectChild(this.contentWidget, true);
+ dijit.focus(this.focusNode);
+ }
+ },
+
+ _onTitleKeyPress: function(/*Event*/ evt){
+ return this.getParent()._onKeyPress(evt, this.contentWidget);
+ },
+
+ _setSelectedAttr: function(/*Boolean*/ isSelected){
+ this.selected = isSelected;
+ dijit.setWaiState(this.focusNode, "expanded", isSelected);
+ dijit.setWaiState(this.focusNode, "selected", isSelected);
+ this.focusNode.setAttribute("tabIndex", isSelected ? "0" : "-1");
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.layout.BorderContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.BorderContainer"] = true;
+dojo.provide("dijit.layout.BorderContainer");
+
+
+
+
+dojo.declare(
+ "dijit.layout.BorderContainer",
+ dijit.layout._LayoutWidget,
+{
+ // summary:
+ // Provides layout in up to 5 regions, a mandatory center with optional borders along its 4 sides.
+ //
+ // description:
+ // A BorderContainer is a box with a specified size, such as style="width: 500px; height: 500px;",
+ // that contains a child widget marked region="center" and optionally children widgets marked
+ // region equal to "top", "bottom", "leading", "trailing", "left" or "right".
+ // Children along the edges will be laid out according to width or height dimensions and may
+ // include optional splitters (splitter="true") to make them resizable by the user. The remaining
+ // space is designated for the center region.
+ //
+ // NOTE: Splitters must not be more than 50 pixels in width.
+ //
+ // The outer size must be specified on the BorderContainer node. Width must be specified for the sides
+ // and height for the top and bottom, respectively. No dimensions should be specified on the center;
+ // it will fill the remaining space. Regions named "leading" and "trailing" may be used just like
+ // "left" and "right" except that they will be reversed in right-to-left environments.
+ //
+ // example:
+ // | <div dojoType="dijit.layout.BorderContainer" design="sidebar" gutters="false"
+ // | style="width: 400px; height: 300px;">
+ // | <div dojoType="ContentPane" region="top">header text</div>
+ // | <div dojoType="ContentPane" region="right" splitter="true" style="width: 200px;">table of contents</div>
+ // | <div dojoType="ContentPane" region="center">client area</div>
+ // | </div>
+
+ // design: String
+ // Which design is used for the layout:
+ // - "headline" (default) where the top and bottom extend
+ // the full width of the container
+ // - "sidebar" where the left and right sides extend from top to bottom.
+ design: "headline",
+
+ // gutters: Boolean
+ // Give each pane a border and margin.
+ // Margin determined by domNode.paddingLeft.
+ // When false, only resizable panes have a gutter (i.e. draggable splitter) for resizing.
+ gutters: true,
+
+ // liveSplitters: Boolean
+ // Specifies whether splitters resize as you drag (true) or only upon mouseup (false)
+ liveSplitters: true,
+
+ // persist: Boolean
+ // Save splitter positions in a cookie.
+ persist: false,
+
+ baseClass: "dijitBorderContainer",
+
+ // _splitterClass: String
+ // Optional hook to override the default Splitter widget used by BorderContainer
+ _splitterClass: "dijit.layout._Splitter",
+
+ postMixInProperties: function(){
+ // change class name to indicate that BorderContainer is being used purely for
+ // layout (like LayoutContainer) rather than for pretty formatting.
+ if(!this.gutters){
+ this.baseClass += "NoGutter";
+ }
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ this._splitters = {};
+ this._splitterThickness = {};
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+ dojo.forEach(this.getChildren(), this._setupChild, this);
+ this.inherited(arguments);
+ },
+
+ _setupChild: function(/*dijit._Widget*/ child){
+ // Override _LayoutWidget._setupChild().
+
+ var region = child.region;
+ if(region){
+ this.inherited(arguments);
+
+ dojo.addClass(child.domNode, this.baseClass+"Pane");
+
+ var ltr = this.isLeftToRight();
+ if(region == "leading"){ region = ltr ? "left" : "right"; }
+ if(region == "trailing"){ region = ltr ? "right" : "left"; }
+
+ //FIXME: redundant?
+ this["_"+region] = child.domNode;
+ this["_"+region+"Widget"] = child;
+
+ // Create draggable splitter for resizing pane,
+ // or alternately if splitter=false but BorderContainer.gutters=true then
+ // insert dummy div just for spacing
+ if((child.splitter || this.gutters) && !this._splitters[region]){
+ var _Splitter = dojo.getObject(child.splitter ? this._splitterClass : "dijit.layout._Gutter");
+ var splitter = new _Splitter({
+ id: child.id + "_splitter",
+ container: this,
+ child: child,
+ region: region,
+ live: this.liveSplitters
+ });
+ splitter.isSplitter = true;
+ this._splitters[region] = splitter.domNode;
+ dojo.place(this._splitters[region], child.domNode, "after");
+
+ // Splitters arent added as Contained children, so we need to call startup explicitly
+ splitter.startup();
+ }
+ child.region = region;
+ }
+ },
+
+ _computeSplitterThickness: function(region){
+ this._splitterThickness[region] = this._splitterThickness[region] ||
+ dojo.marginBox(this._splitters[region])[(/top|bottom/.test(region) ? 'h' : 'w')];
+ },
+
+ layout: function(){
+ // Implement _LayoutWidget.layout() virtual method.
+ for(var region in this._splitters){ this._computeSplitterThickness(region); }
+ this._layoutChildren();
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ // Override _LayoutWidget.addChild().
+ this.inherited(arguments);
+ if(this._started){
+ this.layout(); //OPT
+ }
+ },
+
+ removeChild: function(/*dijit._Widget*/ child){
+ // Override _LayoutWidget.removeChild().
+ var region = child.region;
+ var splitter = this._splitters[region];
+ if(splitter){
+ dijit.byNode(splitter).destroy();
+ delete this._splitters[region];
+ delete this._splitterThickness[region];
+ }
+ this.inherited(arguments);
+ delete this["_"+region];
+ delete this["_" +region+"Widget"];
+ if(this._started){
+ this._layoutChildren();
+ }
+ dojo.removeClass(child.domNode, this.baseClass+"Pane");
+ },
+
+ getChildren: function(){
+ // Override _LayoutWidget.getChildren() to only return real children, not the splitters.
+ return dojo.filter(this.inherited(arguments), function(widget){
+ return !widget.isSplitter;
+ });
+ },
+
+ getSplitter: function(/*String*/region){
+ // summary:
+ // Returns the widget responsible for rendering the splitter associated with region
+ var splitter = this._splitters[region];
+ return splitter ? dijit.byNode(splitter) : null;
+ },
+
+ resize: function(newSize, currentSize){
+ // Overrides _LayoutWidget.resize().
+
+ // resetting potential padding to 0px to provide support for 100% width/height + padding
+ // TODO: this hack doesn't respect the box model and is a temporary fix
+ if(!this.cs || !this.pe){
+ var node = this.domNode;
+ this.cs = dojo.getComputedStyle(node);
+ this.pe = dojo._getPadExtents(node, this.cs);
+ this.pe.r = dojo._toPixelValue(node, this.cs.paddingRight);
+ this.pe.b = dojo._toPixelValue(node, this.cs.paddingBottom);
+
+ dojo.style(node, "padding", "0px");
+ }
+
+ this.inherited(arguments);
+ },
+
+ _layoutChildren: function(/*String?*/changedRegion, /*Number?*/ changedRegionSize){
+ // summary:
+ // This is the main routine for setting size/position of each child.
+ // description:
+ // With no arguments, measures the height of top/bottom panes, the width
+ // of left/right panes, and then sizes all panes accordingly.
+ //
+ // With changedRegion specified (as "left", "top", "bottom", or "right"),
+ // it changes that region's width/height to changedRegionSize and
+ // then resizes other regions that were affected.
+ // changedRegion:
+ // The region should be changed because splitter was dragged.
+ // "left", "right", "top", or "bottom".
+ // changedRegionSize:
+ // The new width/height (in pixels) to make changedRegion
+
+ if(!this._borderBox || !this._borderBox.h){
+ // We are currently hidden, or we haven't been sized by our parent yet.
+ // Abort. Someone will resize us later.
+ return;
+ }
+
+ var sidebarLayout = (this.design == "sidebar");
+ var topHeight = 0, bottomHeight = 0, leftWidth = 0, rightWidth = 0;
+ var topStyle = {}, leftStyle = {}, rightStyle = {}, bottomStyle = {},
+ centerStyle = (this._center && this._center.style) || {};
+
+ var changedSide = /left|right/.test(changedRegion);
+
+ var layoutSides = !changedRegion || (!changedSide && !sidebarLayout);
+ var layoutTopBottom = !changedRegion || (changedSide && sidebarLayout);
+
+ // Ask browser for width/height of side panes.
+ // Would be nice to cache this but height can change according to width
+ // (because words wrap around). I don't think width will ever change though
+ // (except when the user drags a splitter).
+ if(this._top){
+ topStyle = (changedRegion == "top" || layoutTopBottom) && this._top.style;
+ topHeight = changedRegion == "top" ? changedRegionSize : dojo.marginBox(this._top).h;
+ }
+ if(this._left){
+ leftStyle = (changedRegion == "left" || layoutSides) && this._left.style;
+ leftWidth = changedRegion == "left" ? changedRegionSize : dojo.marginBox(this._left).w;
+ }
+ if(this._right){
+ rightStyle = (changedRegion == "right" || layoutSides) && this._right.style;
+ rightWidth = changedRegion == "right" ? changedRegionSize : dojo.marginBox(this._right).w;
+ }
+ if(this._bottom){
+ bottomStyle = (changedRegion == "bottom" || layoutTopBottom) && this._bottom.style;
+ bottomHeight = changedRegion == "bottom" ? changedRegionSize : dojo.marginBox(this._bottom).h;
+ }
+
+ var splitters = this._splitters;
+ var topSplitter = splitters.top, bottomSplitter = splitters.bottom,
+ leftSplitter = splitters.left, rightSplitter = splitters.right;
+ var splitterThickness = this._splitterThickness;
+ var topSplitterThickness = splitterThickness.top || 0,
+ leftSplitterThickness = splitterThickness.left || 0,
+ rightSplitterThickness = splitterThickness.right || 0,
+ bottomSplitterThickness = splitterThickness.bottom || 0;
+
+ // Check for race condition where CSS hasn't finished loading, so
+ // the splitter width == the viewport width (#5824)
+ if(leftSplitterThickness > 50 || rightSplitterThickness > 50){
+ setTimeout(dojo.hitch(this, function(){
+ // Results are invalid. Clear them out.
+ this._splitterThickness = {};
+
+ for(var region in this._splitters){
+ this._computeSplitterThickness(region);
+ }
+ this._layoutChildren();
+ }), 50);
+ return false;
+ }
+
+ var pe = this.pe;
+
+ var splitterBounds = {
+ left: (sidebarLayout ? leftWidth + leftSplitterThickness: 0) + pe.l + "px",
+ right: (sidebarLayout ? rightWidth + rightSplitterThickness: 0) + pe.r + "px"
+ };
+
+ if(topSplitter){
+ dojo.mixin(topSplitter.style, splitterBounds);
+ topSplitter.style.top = topHeight + pe.t + "px";
+ }
+
+ if(bottomSplitter){
+ dojo.mixin(bottomSplitter.style, splitterBounds);
+ bottomSplitter.style.bottom = bottomHeight + pe.b + "px";
+ }
+
+ splitterBounds = {
+ top: (sidebarLayout ? 0 : topHeight + topSplitterThickness) + pe.t + "px",
+ bottom: (sidebarLayout ? 0 : bottomHeight + bottomSplitterThickness) + pe.b + "px"
+ };
+
+ if(leftSplitter){
+ dojo.mixin(leftSplitter.style, splitterBounds);
+ leftSplitter.style.left = leftWidth + pe.l + "px";
+ }
+
+ if(rightSplitter){
+ dojo.mixin(rightSplitter.style, splitterBounds);
+ rightSplitter.style.right = rightWidth + pe.r + "px";
+ }
+
+ dojo.mixin(centerStyle, {
+ top: pe.t + topHeight + topSplitterThickness + "px",
+ left: pe.l + leftWidth + leftSplitterThickness + "px",
+ right: pe.r + rightWidth + rightSplitterThickness + "px",
+ bottom: pe.b + bottomHeight + bottomSplitterThickness + "px"
+ });
+
+ var bounds = {
+ top: sidebarLayout ? pe.t + "px" : centerStyle.top,
+ bottom: sidebarLayout ? pe.b + "px" : centerStyle.bottom
+ };
+ dojo.mixin(leftStyle, bounds);
+ dojo.mixin(rightStyle, bounds);
+ leftStyle.left = pe.l + "px"; rightStyle.right = pe.r + "px"; topStyle.top = pe.t + "px"; bottomStyle.bottom = pe.b + "px";
+ if(sidebarLayout){
+ topStyle.left = bottomStyle.left = leftWidth + leftSplitterThickness + pe.l + "px";
+ topStyle.right = bottomStyle.right = rightWidth + rightSplitterThickness + pe.r + "px";
+ }else{
+ topStyle.left = bottomStyle.left = pe.l + "px";
+ topStyle.right = bottomStyle.right = pe.r + "px";
+ }
+
+ // More calculations about sizes of panes
+ var containerHeight = this._borderBox.h - pe.t - pe.b,
+ middleHeight = containerHeight - ( topHeight + topSplitterThickness + bottomHeight + bottomSplitterThickness),
+ sidebarHeight = sidebarLayout ? containerHeight : middleHeight;
+
+ var containerWidth = this._borderBox.w - pe.l - pe.r,
+ middleWidth = containerWidth - (leftWidth + leftSplitterThickness + rightWidth + rightSplitterThickness),
+ sidebarWidth = sidebarLayout ? middleWidth : containerWidth;
+
+ // New margin-box size of each pane
+ var dim = {
+ top: { w: sidebarWidth, h: topHeight },
+ bottom: { w: sidebarWidth, h: bottomHeight },
+ left: { w: leftWidth, h: sidebarHeight },
+ right: { w: rightWidth, h: sidebarHeight },
+ center: { h: middleHeight, w: middleWidth }
+ };
+
+ if(changedRegion){
+ // Respond to splitter drag event by changing changedRegion's width or height
+ var child = this["_" + changedRegion + "Widget"],
+ mb = {};
+ mb[ /top|bottom/.test(changedRegion) ? "h" : "w"] = changedRegionSize;
+ child.resize ? child.resize(mb, dim[child.region]) : dojo.marginBox(child.domNode, mb);
+ }
+
+ // Nodes in IE<8 don't respond to t/l/b/r, and TEXTAREA doesn't respond in any browser
+ var janky = dojo.isIE < 8 || (dojo.isIE && dojo.isQuirks) || dojo.some(this.getChildren(), function(child){
+ return child.domNode.tagName == "TEXTAREA" || child.domNode.tagName == "INPUT";
+ });
+ if(janky){
+ // Set the size of the children the old fashioned way, by setting
+ // CSS width and height
+
+ var resizeWidget = function(widget, changes, result){
+ if(widget){
+ (widget.resize ? widget.resize(changes, result) : dojo.marginBox(widget.domNode, changes));
+ }
+ };
+
+ if(leftSplitter){ leftSplitter.style.height = sidebarHeight; }
+ if(rightSplitter){ rightSplitter.style.height = sidebarHeight; }
+ resizeWidget(this._leftWidget, {h: sidebarHeight}, dim.left);
+ resizeWidget(this._rightWidget, {h: sidebarHeight}, dim.right);
+
+ if(topSplitter){ topSplitter.style.width = sidebarWidth; }
+ if(bottomSplitter){ bottomSplitter.style.width = sidebarWidth; }
+ resizeWidget(this._topWidget, {w: sidebarWidth}, dim.top);
+ resizeWidget(this._bottomWidget, {w: sidebarWidth}, dim.bottom);
+
+ resizeWidget(this._centerWidget, dim.center);
+ }else{
+ // Calculate which panes need a notification that their size has been changed
+ // (we've already set style.top/bottom/left/right on those other panes).
+ var notifySides = !changedRegion || (/top|bottom/.test(changedRegion) && this.design != "sidebar"),
+ notifyTopBottom = !changedRegion || (/left|right/.test(changedRegion) && this.design == "sidebar"),
+ notifyList = {
+ center: true,
+ left: notifySides,
+ right: notifySides,
+ top: notifyTopBottom,
+ bottom: notifyTopBottom
+ };
+
+ // Send notification to those panes that have changed size
+ dojo.forEach(this.getChildren(), function(child){
+ if(child.resize && notifyList[child.region]){
+ child.resize(null, dim[child.region]);
+ }
+ }, this);
+ }
+ },
+
+ destroy: function(){
+ for(var region in this._splitters){
+ var splitter = this._splitters[region];
+ dijit.byNode(splitter).destroy();
+ dojo.destroy(splitter);
+ }
+ delete this._splitters;
+ delete this._splitterThickness;
+ this.inherited(arguments);
+ }
+});
+
+// This argument can be specified for the children of a BorderContainer.
+// Since any widget can be specified as a LayoutContainer child, mix it
+// into the base widget class. (This is a hack, but it's effective.)
+dojo.extend(dijit._Widget, {
+ // region: [const] String
+ // Parameter for children of `dijit.layout.BorderContainer`.
+ // Values: "top", "bottom", "leading", "trailing", "left", "right", "center".
+ // See the `dijit.layout.BorderContainer` description for details.
+ region: '',
+
+ // splitter: [const] Boolean
+ // Parameter for child of `dijit.layout.BorderContainer` where region != "center".
+ // If true, enables user to resize the widget by putting a draggable splitter between
+ // this widget and the region=center widget.
+ splitter: false,
+
+ // minSize: [const] Number
+ // Parameter for children of `dijit.layout.BorderContainer`.
+ // Specifies a minimum size (in pixels) for this widget when resized by a splitter.
+ minSize: 0,
+
+ // maxSize: [const] Number
+ // Parameter for children of `dijit.layout.BorderContainer`.
+ // Specifies a maximum size (in pixels) for this widget when resized by a splitter.
+ maxSize: Infinity
+});
+
+
+
+dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
+{
+ // summary:
+ // A draggable spacer between two items in a `dijit.layout.BorderContainer`.
+ // description:
+ // This is instantiated by `dijit.layout.BorderContainer`. Users should not
+ // create it directly.
+ // tags:
+ // private
+
+/*=====
+ // container: [const] dijit.layout.BorderContainer
+ // Pointer to the parent BorderContainer
+ container: null,
+
+ // child: [const] dijit.layout._LayoutWidget
+ // Pointer to the pane associated with this splitter
+ child: null,
+
+ // region: String
+ // Region of pane associated with this splitter.
+ // "top", "bottom", "left", "right".
+ region: null,
+=====*/
+
+ // live: [const] Boolean
+ // If true, the child's size changes and the child widget is redrawn as you drag the splitter;
+ // otherwise, the size doesn't change until you drop the splitter (by mouse-up)
+ live: true,
+
+ templateString: '<div class="dijitSplitter" dojoAttachEvent="onkeypress:_onKeyPress,onmousedown:_startDrag,onmouseenter:_onMouse,onmouseleave:_onMouse" tabIndex="0" waiRole="separator"><div class="dijitSplitterThumb"></div></div>',
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.horizontal = /top|bottom/.test(this.region);
+ dojo.addClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V"));
+// dojo.addClass(this.child.domNode, "dijitSplitterPane");
+// dojo.setSelectable(this.domNode, false); //TODO is this necessary?
+
+ this._factor = /top|left/.test(this.region) ? 1 : -1;
+
+ this._cookieName = this.container.id + "_" + this.region;
+ if(this.container.persist){
+ // restore old size
+ var persistSize = dojo.cookie(this._cookieName);
+ if(persistSize){
+ this.child.domNode.style[this.horizontal ? "height" : "width"] = persistSize;
+ }
+ }
+ },
+
+ _computeMaxSize: function(){
+ // summary:
+ // Compute the maximum size that my corresponding pane can be set to
+
+ var dim = this.horizontal ? 'h' : 'w',
+ thickness = this.container._splitterThickness[this.region];
+
+ // Get DOMNode of opposite pane, if an opposite pane exists.
+ // Ex: if I am the _Splitter for the left pane, then get the right pane.
+ var flip = {left:'right', right:'left', top:'bottom', bottom:'top', leading:'trailing', trailing:'leading'},
+ oppNode = this.container["_" + flip[this.region]];
+
+ // I can expand up to the edge of the opposite pane, or if there's no opposite pane, then to
+ // edge of BorderContainer
+ var available = dojo.contentBox(this.container.domNode)[dim] -
+ (oppNode ? dojo.marginBox(oppNode)[dim] : 0) -
+ 20 - thickness * 2;
+
+ return Math.min(this.child.maxSize, available);
+ },
+
+ _startDrag: function(e){
+ if(!this.cover){
+ this.cover = dojo.doc.createElement('div');
+ dojo.addClass(this.cover, "dijitSplitterCover");
+ dojo.place(this.cover, this.child.domNode, "after");
+ }
+ dojo.addClass(this.cover, "dijitSplitterCoverActive");
+
+ // Safeguard in case the stop event was missed. Shouldn't be necessary if we always get the mouse up.
+ if(this.fake){ dojo.destroy(this.fake); }
+ if(!(this._resize = this.live)){ //TODO: disable live for IE6?
+ // create fake splitter to display at old position while we drag
+ (this.fake = this.domNode.cloneNode(true)).removeAttribute("id");
+ dojo.addClass(this.domNode, "dijitSplitterShadow");
+ dojo.place(this.fake, this.domNode, "after");
+ }
+ dojo.addClass(this.domNode, "dijitSplitterActive");
+ dojo.addClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Active");
+ if(this.fake){
+ dojo.removeClass(this.fake, "dijitSplitterHover");
+ dojo.removeClass(this.fake, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover");
+ }
+
+ //Performance: load data info local vars for onmousevent function closure
+ var factor = this._factor,
+ max = this._computeMaxSize(),
+ min = this.child.minSize || 20,
+ isHorizontal = this.horizontal,
+ axis = isHorizontal ? "pageY" : "pageX",
+ pageStart = e[axis],
+ splitterStyle = this.domNode.style,
+ dim = isHorizontal ? 'h' : 'w',
+ childStart = dojo.marginBox(this.child.domNode)[dim],
+ region = this.region,
+ splitterStart = parseInt(this.domNode.style[region], 10),
+ resize = this._resize,
+ childNode = this.child.domNode,
+ layoutFunc = dojo.hitch(this.container, this.container._layoutChildren),
+ de = dojo.doc;
+
+ this._handlers = (this._handlers || []).concat([
+ dojo.connect(de, "onmousemove", this._drag = function(e, forceResize){
+ var delta = e[axis] - pageStart,
+ childSize = factor * delta + childStart,
+ boundChildSize = Math.max(Math.min(childSize, max), min);
+
+ if(resize || forceResize){
+ layoutFunc(region, boundChildSize);
+ }
+ splitterStyle[region] = factor * delta + splitterStart + (boundChildSize - childSize) + "px";
+ }),
+ dojo.connect(de, "ondragstart", dojo.stopEvent),
+ dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent),
+ dojo.connect(de, "onmouseup", this, "_stopDrag")
+ ]);
+ dojo.stopEvent(e);
+ },
+
+ _onMouse: function(e){
+ var o = (e.type == "mouseover" || e.type == "mouseenter");
+ dojo.toggleClass(this.domNode, "dijitSplitterHover", o);
+ dojo.toggleClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover", o);
+ },
+
+ _stopDrag: function(e){
+ try{
+ if(this.cover){
+ dojo.removeClass(this.cover, "dijitSplitterCoverActive");
+ }
+ if(this.fake){ dojo.destroy(this.fake); }
+ dojo.removeClass(this.domNode, "dijitSplitterActive");
+ dojo.removeClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Active");
+ dojo.removeClass(this.domNode, "dijitSplitterShadow");
+ this._drag(e); //TODO: redundant with onmousemove?
+ this._drag(e, true);
+ }finally{
+ this._cleanupHandlers();
+ delete this._drag;
+ }
+
+ if(this.container.persist){
+ dojo.cookie(this._cookieName, this.child.domNode.style[this.horizontal ? "height" : "width"], {expires:365});
+ }
+ },
+
+ _cleanupHandlers: function(){
+ dojo.forEach(this._handlers, dojo.disconnect);
+ delete this._handlers;
+ },
+
+ _onKeyPress: function(/*Event*/ e){
+ // should we apply typematic to this?
+ this._resize = true;
+ var horizontal = this.horizontal;
+ var tick = 1;
+ var dk = dojo.keys;
+ switch(e.charOrCode){
+ case horizontal ? dk.UP_ARROW : dk.LEFT_ARROW:
+ tick *= -1;
+// break;
+ case horizontal ? dk.DOWN_ARROW : dk.RIGHT_ARROW:
+ break;
+ default:
+// this.inherited(arguments);
+ return;
+ }
+ var childSize = dojo.marginBox(this.child.domNode)[ horizontal ? 'h' : 'w' ] + this._factor * tick;
+ this.container._layoutChildren(this.region, Math.max(Math.min(childSize, this._computeMaxSize()), this.child.minSize));
+ dojo.stopEvent(e);
+ },
+
+ destroy: function(){
+ this._cleanupHandlers();
+ delete this.child;
+ delete this.container;
+ delete this.cover;
+ delete this.fake;
+ this.inherited(arguments);
+ }
+});
+
+dojo.declare("dijit.layout._Gutter", [dijit._Widget, dijit._Templated ],
+{
+ // summary:
+ // Just a spacer div to separate side pane from center pane.
+ // Basically a trick to lookup the gutter/splitter width from the theme.
+ // description:
+ // Instantiated by `dijit.layout.BorderContainer`. Users should not
+ // create directly.
+ // tags:
+ // private
+
+ templateString: '<div class="dijitGutter" waiRole="presentation"></div>',
+
+ postCreate: function(){
+ this.horizontal = /top|bottom/.test(this.region);
+ dojo.addClass(this.domNode, "dijitGutter" + (this.horizontal ? "H" : "V"));
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.layout._TabContainerBase"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout._TabContainerBase"] = true;
+dojo.provide("dijit.layout._TabContainerBase");
+
+
+
+
+dojo.declare("dijit.layout._TabContainerBase",
+ [dijit.layout.StackContainer, dijit._Templated],
+ {
+ // summary:
+ // Abstract base class for TabContainer. Must define _makeController() to instantiate
+ // and return the widget that displays the tab labels
+ // description:
+ // A TabContainer is a container that has multiple panes, but shows only
+ // one pane at a time. There are a set of tabs corresponding to each pane,
+ // where each tab has the name (aka title) of the pane, and optionally a close button.
+
+ // tabPosition: String
+ // Defines where tabs go relative to tab content.
+ // "top", "bottom", "left-h", "right-h"
+ tabPosition: "top",
+
+ baseClass: "dijitTabContainer",
+
+ // tabStrip: Boolean
+ // Defines whether the tablist gets an extra class for layouting, putting a border/shading
+ // around the set of tabs.
+ tabStrip: false,
+
+ // nested: Boolean
+ // If true, use styling for a TabContainer nested inside another TabContainer.
+ // For tundra etc., makes tabs look like links, and hides the outer
+ // border since the outer TabContainer already has a border.
+ nested: false,
+
+ templateString: dojo.cache("dijit.layout", "templates/TabContainer.html", "<div class=\"dijitTabContainer\">\n\t<div class=\"dijitTabListWrapper\" dojoAttachPoint=\"tablistNode\"></div>\n\t<div dojoAttachPoint=\"tablistSpacer\" class=\"dijitTabSpacer ${baseClass}-spacer\"></div>\n\t<div class=\"dijitTabPaneWrapper ${baseClass}-container\" dojoAttachPoint=\"containerNode\"></div>\n</div>\n"),
+
+ postMixInProperties: function(){
+ // set class name according to tab position, ex: dijitTabContainerTop
+ this.baseClass += this.tabPosition.charAt(0).toUpperCase() + this.tabPosition.substr(1).replace(/-.*/, "");
+
+ this.srcNodeRef && dojo.style(this.srcNodeRef, "visibility", "hidden");
+
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // Create the tab list that will have a tab (a.k.a. tab button) for each tab panel
+ this.tablist = this._makeController(this.tablistNode);
+
+ if(!this.doLayout){ dojo.addClass(this.domNode, "dijitTabContainerNoLayout"); }
+
+ if(this.nested){
+ /* workaround IE's lack of support for "a > b" selectors by
+ * tagging each node in the template.
+ */
+ dojo.addClass(this.domNode, "dijitTabContainerNested");
+ dojo.addClass(this.tablist.containerNode, "dijitTabContainerTabListNested");
+ dojo.addClass(this.tablistSpacer, "dijitTabContainerSpacerNested");
+ dojo.addClass(this.containerNode, "dijitTabPaneWrapperNested");
+ }else{
+ dojo.addClass(this.domNode, "tabStrip-" + (this.tabStrip ? "enabled" : "disabled"));
+ }
+ },
+
+ _setupChild: function(/*dijit._Widget*/ tab){
+ // Overrides StackContainer._setupChild().
+ dojo.addClass(tab.domNode, "dijitTabPane");
+ this.inherited(arguments);
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+
+ // wire up the tablist and its tabs
+ this.tablist.startup();
+
+ this.inherited(arguments);
+ },
+
+ layout: function(){
+ // Overrides StackContainer.layout().
+ // Configure the content pane to take up all the space except for where the tabs are
+
+ if(!this._contentBox || typeof(this._contentBox.l) == "undefined"){return;}
+
+ var sc = this.selectedChildWidget;
+
+ if(this.doLayout){
+ // position and size the titles and the container node
+ var titleAlign = this.tabPosition.replace(/-h/, "");
+ this.tablist.layoutAlign = titleAlign;
+ var children = [this.tablist, {
+ domNode: this.tablistSpacer,
+ layoutAlign: titleAlign
+ }, {
+ domNode: this.containerNode,
+ layoutAlign: "client"
+ }];
+ dijit.layout.layoutChildren(this.domNode, this._contentBox, children);
+
+ // Compute size to make each of my children.
+ // children[2] is the margin-box size of this.containerNode, set by layoutChildren() call above
+ this._containerContentBox = dijit.layout.marginBox2contentBox(this.containerNode, children[2]);
+
+ if(sc && sc.resize){
+ sc.resize(this._containerContentBox);
+ }
+ }else{
+ // just layout the tab controller, so it can position left/right buttons etc.
+ if(this.tablist.resize){
+ this.tablist.resize({w: dojo.contentBox(this.domNode).w});
+ }
+
+ // and call resize() on the selected pane just to tell it that it's been made visible
+ if(sc && sc.resize){
+ sc.resize();
+ }
+ }
+ },
+
+ destroy: function(){
+ if(this.tablist){
+ this.tablist.destroy();
+ }
+ this.inherited(arguments);
+ }
+});
+
+
+}
+
+if(!dojo._hasResource["dijit.layout.TabController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.TabController"] = true;
+dojo.provide("dijit.layout.TabController");
+
+
+
+// Menu is used for an accessible close button, would be nice to have a lighter-weight solution
+
+
+
+
+
+dojo.declare("dijit.layout.TabController",
+ dijit.layout.StackController,
+{
+ // summary:
+ // Set of tabs (the things with titles and a close button, that you click to show a tab panel).
+ // Used internally by `dijit.layout.TabContainer`.
+ // description:
+ // Lets the user select the currently shown pane in a TabContainer or StackContainer.
+ // TabController also monitors the TabContainer, and whenever a pane is
+ // added or deleted updates itself accordingly.
+ // tags:
+ // private
+
+ templateString: "<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>",
+
+ // tabPosition: String
+ // Defines where tabs go relative to the content.
+ // "top", "bottom", "left-h", "right-h"
+ tabPosition: "top",
+
+ // buttonWidget: String
+ // The name of the tab widget to create to correspond to each page
+ buttonWidget: "dijit.layout._TabButton",
+
+ _rectifyRtlTabList: function(){
+ // summary:
+ // For left/right TabContainer when page is RTL mode, rectify the width of all tabs to be equal, otherwise the tab widths are different in IE
+
+ if(0 >= this.tabPosition.indexOf('-h')){ return; }
+ if(!this.pane2button){ return; }
+
+ var maxWidth = 0;
+ for(var pane in this.pane2button){
+ var ow = this.pane2button[pane].innerDiv.scrollWidth;
+ maxWidth = Math.max(maxWidth, ow);
+ }
+ //unify the length of all the tabs
+ for(pane in this.pane2button){
+ this.pane2button[pane].innerDiv.style.width = maxWidth + 'px';
+ }
+ }
+});
+
+dojo.declare("dijit.layout._TabButton",
+ dijit.layout._StackButton,
+ {
+ // summary:
+ // A tab (the thing you click to select a pane).
+ // description:
+ // Contains the title of the pane, and optionally a close-button to destroy the pane.
+ // This is an internal widget and should not be instantiated directly.
+ // tags:
+ // private
+
+ // baseClass: String
+ // The CSS class applied to the domNode.
+ baseClass: "dijitTab",
+
+ // Apply dijitTabCloseButtonHover when close button is hovered
+ cssStateNodes: {
+ closeNode: "dijitTabCloseButton"
+ },
+
+ templateString: dojo.cache("dijit.layout", "templates/_TabButton.html", "<div waiRole=\"presentation\" dojoAttachPoint=\"titleNode\" dojoAttachEvent='onclick:onClick'>\n <div waiRole=\"presentation\" class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>\n <div waiRole=\"presentation\" class='dijitTabContent' dojoAttachPoint='tabContent'>\n \t<div waiRole=\"presentation\" dojoAttachPoint='focusNode'>\n\t\t <img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' />\n\t\t <span dojoAttachPoint='containerNode' class='tabLabel'></span>\n\t\t <span class=\"dijitInline dijitTabCloseButton dijitTabCloseIcon\" dojoAttachPoint='closeNode'\n\t\t \t\tdojoAttachEvent='onclick: onClickCloseButton' waiRole=\"presentation\">\n\t\t <span dojoAttachPoint='closeText' class='dijitTabCloseText'>x</span\n\t\t ></span>\n\t\t\t</div>\n </div>\n </div>\n</div>\n"),
+
+ // Override _FormWidget.scrollOnFocus.
+ // Don't scroll the whole tab container into view when the button is focused.
+ scrollOnFocus: false,
+
+ postMixInProperties: function(){
+ // Override blank iconClass from Button to do tab height adjustment on IE6,
+ // to make sure that tabs with and w/out close icons are same height
+ if(!this.iconClass){
+ this.iconClass = "dijitTabButtonIcon";
+ }
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ dojo.setSelectable(this.containerNode, false);
+
+ // If a custom icon class has not been set for the
+ // tab icon, set its width to one pixel. This ensures
+ // that the height styling of the tab is maintained,
+ // as it is based on the height of the icon.
+ // TODO: I still think we can just set dijitTabButtonIcon to 1px in CSS <Bill>
+ if(this.iconNode.className == "dijitTabButtonIcon"){
+ dojo.style(this.iconNode, "width", "1px");
+ }
+ },
+
+ startup: function(){
+ this.inherited(arguments);
+ var n = this.domNode;
+
+ // Required to give IE6 a kick, as it initially hides the
+ // tabs until they are focused on.
+ setTimeout(function(){
+ n.className = n.className;
+ }, 1);
+ },
+
+ _setCloseButtonAttr: function(disp){
+ this.closeButton = disp;
+ dojo.toggleClass(this.innerDiv, "dijitClosable", disp);
+ this.closeNode.style.display = disp ? "" : "none";
+ if(disp){
+ var _nlsResources = dojo.i18n.getLocalization("dijit", "common");
+ if(this.closeNode){
+ dojo.attr(this.closeNode,"title", _nlsResources.itemClose);
+ }
+ // add context menu onto title button
+ var _nlsResources = dojo.i18n.getLocalization("dijit", "common");
+ this._closeMenu = new dijit.Menu({
+ id: this.id+"_Menu",
+ dir: this.dir,
+ lang: this.lang,
+ targetNodeIds: [this.domNode]
+ });
+
+ this._closeMenu.addChild(new dijit.MenuItem({
+ label: _nlsResources.itemClose,
+ dir: this.dir,
+ lang: this.lang,
+ onClick: dojo.hitch(this, "onClickCloseButton")
+ }));
+ }else{
+ if(this._closeMenu){
+ this._closeMenu.destroyRecursive();
+ delete this._closeMenu;
+ }
+ }
+ },
+ _setLabelAttr: function(/*String*/ content){
+ // summary:
+ // Hook for attr('label', ...) to work.
+ // description:
+ // takes an HTML string.
+ // Inherited ToggleButton implementation will Set the label (text) of the button;
+ // Need to set the alt attribute of icon on tab buttons if no label displayed
+ this.inherited(arguments);
+ if(this.showLabel == false && !this.params.title){
+ this.iconNode.alt = dojo.trim(this.containerNode.innerText || this.containerNode.textContent || '');
+ }
+ },
+
+ destroy: function(){
+ if(this._closeMenu){
+ this._closeMenu.destroyRecursive();
+ delete this._closeMenu;
+ }
+ this.inherited(arguments);
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.layout.ScrollingTabController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.ScrollingTabController"] = true;
+dojo.provide("dijit.layout.ScrollingTabController");
+
+
+
+
+dojo.declare("dijit.layout.ScrollingTabController",
+ dijit.layout.TabController,
+ {
+ // summary:
+ // Set of tabs with left/right arrow keys and a menu to switch between tabs not
+ // all fitting on a single row.
+ // Works only for horizontal tabs (either above or below the content, not to the left
+ // or right).
+ // tags:
+ // private
+
+ templateString: dojo.cache("dijit.layout", "templates/ScrollingTabController.html", "<div class=\"dijitTabListContainer-${tabPosition}\" style=\"visibility:hidden\">\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_menuBtn\" iconClass=\"dijitTabStripMenuIcon\"\n\t\t\tdojoAttachPoint=\"_menuBtn\" showLabel=false>&#9660;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_leftBtn\" iconClass=\"dijitTabStripSlideLeftIcon\"\n\t\t\tdojoAttachPoint=\"_leftBtn\" dojoAttachEvent=\"onClick: doSlideLeft\" showLabel=false>&#9664;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_rightBtn\" iconClass=\"dijitTabStripSlideRightIcon\"\n\t\t\tdojoAttachPoint=\"_rightBtn\" dojoAttachEvent=\"onClick: doSlideRight\" showLabel=false>&#9654;</div>\n\t<div class='dijitTabListWrapper' dojoAttachPoint='tablistWrapper'>\n\t\t<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'\n\t\t\t\tdojoAttachPoint='containerNode' class='nowrapTabStrip'></div>\n\t</div>\n</div>\n"),
+
+ // useMenu:[const] Boolean
+ // True if a menu should be used to select tabs when they are too
+ // wide to fit the TabContainer, false otherwise.
+ useMenu: true,
+
+ // useSlider: [const] Boolean
+ // True if a slider should be used to select tabs when they are too
+ // wide to fit the TabContainer, false otherwise.
+ useSlider: true,
+
+ // tabStripClass: String
+ // The css class to apply to the tab strip, if it is visible.
+ tabStripClass: "",
+
+ widgetsInTemplate: true,
+
+ // _minScroll: Number
+ // The distance in pixels from the edge of the tab strip which,
+ // if a scroll animation is less than, forces the scroll to
+ // go all the way to the left/right.
+ _minScroll: 5,
+
+ attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+ "class": "containerNode"
+ }),
+
+ postCreate: function(){
+ this.inherited(arguments);
+ var n = this.domNode;
+
+ this.scrollNode = this.tablistWrapper;
+ this._initButtons();
+
+ if(!this.tabStripClass){
+ this.tabStripClass = "dijitTabContainer" +
+ this.tabPosition.charAt(0).toUpperCase() +
+ this.tabPosition.substr(1).replace(/-.*/, "") +
+ "None";
+ dojo.addClass(n, "tabStrip-disabled")
+ }
+
+ dojo.addClass(this.tablistWrapper, this.tabStripClass);
+ },
+
+ onStartup: function(){
+ this.inherited(arguments);
+
+ // Do not show the TabController until the related
+ // StackController has added it's children. This gives
+ // a less visually jumpy instantiation.
+ dojo.style(this.domNode, "visibility", "visible");
+ this._postStartup = true;
+ },
+
+ onAddChild: function(page, insertIndex){
+ this.inherited(arguments);
+ var menuItem;
+ if(this.useMenu){
+ var containerId = this.containerId;
+ menuItem = new dijit.MenuItem({
+ id: page.id + "_stcMi",
+ label: page.title,
+ dir: page.dir,
+ lang: page.lang,
+ onClick: dojo.hitch(this, function(){
+ var container = dijit.byId(containerId);
+ container.selectChild(page);
+ })
+ });
+ this._menuChildren[page.id] = menuItem;
+ this._menu.addChild(menuItem, insertIndex);
+ }
+
+ // update the menuItem label when the button label is updated
+ this.pane2handles[page.id].push(
+ this.connect(this.pane2button[page.id], "set", function(name, value){
+ if(this._postStartup){
+ if(name == "label"){
+ if(menuItem){
+ menuItem.set(name, value);
+ }
+
+ // The changed label will have changed the width of the
+ // buttons, so do a resize
+ if(this._dim){
+ this.resize(this._dim);
+ }
+ }
+ }
+ })
+ );
+
+ // Increment the width of the wrapper when a tab is added
+ // This makes sure that the buttons never wrap.
+ // The value 200 is chosen as it should be bigger than most
+ // Tab button widths.
+ dojo.style(this.containerNode, "width",
+ (dojo.style(this.containerNode, "width") + 200) + "px");
+ },
+
+ onRemoveChild: function(page, insertIndex){
+ // null out _selectedTab because we are about to delete that dom node
+ var button = this.pane2button[page.id];
+ if(this._selectedTab === button.domNode){
+ this._selectedTab = null;
+ }
+
+ // delete menu entry corresponding to pane that was removed from TabContainer
+ if(this.useMenu && page && page.id && this._menuChildren[page.id]){
+ this._menu.removeChild(this._menuChildren[page.id]);
+ this._menuChildren[page.id].destroy();
+ delete this._menuChildren[page.id];
+ }
+
+ this.inherited(arguments);
+ },
+
+ _initButtons: function(){
+ // summary:
+ // Creates the buttons used to scroll to view tabs that
+ // may not be visible if the TabContainer is too narrow.
+ this._menuChildren = {};
+
+ // Make a list of the buttons to display when the tab labels become
+ // wider than the TabContainer, and hide the other buttons.
+ // Also gets the total width of the displayed buttons.
+ this._btnWidth = 0;
+ this._buttons = dojo.query("> .tabStripButton", this.domNode).filter(function(btn){
+ if((this.useMenu && btn == this._menuBtn.domNode) ||
+ (this.useSlider && (btn == this._rightBtn.domNode || btn == this._leftBtn.domNode))){
+ this._btnWidth += dojo.marginBox(btn).w;
+ return true;
+ }else{
+ dojo.style(btn, "display", "none");
+ return false;
+ }
+ }, this);
+
+ if(this.useMenu){
+ // Create the menu that is used to select tabs.
+ this._menu = new dijit.Menu({
+ id: this.id + "_menu",
+ dir: this.dir,
+ lang: this.lang,
+ targetNodeIds: [this._menuBtn.domNode],
+ leftClickToOpen: true,
+ refocus: false // selecting a menu item sets focus to a TabButton
+ });
+ this._supportingWidgets.push(this._menu);
+ }
+ },
+
+ _getTabsWidth: function(){
+ var children = this.getChildren();
+ if(children.length){
+ var leftTab = children[this.isLeftToRight() ? 0 : children.length - 1].domNode,
+ rightTab = children[this.isLeftToRight() ? children.length - 1 : 0].domNode;
+ return rightTab.offsetLeft + dojo.style(rightTab, "width") - leftTab.offsetLeft;
+ }else{
+ return 0;
+ }
+ },
+
+ _enableBtn: function(width){
+ // summary:
+ // Determines if the tabs are wider than the width of the TabContainer, and
+ // thus that we need to display left/right/menu navigation buttons.
+ var tabsWidth = this._getTabsWidth();
+ width = width || dojo.style(this.scrollNode, "width");
+ return tabsWidth > 0 && width < tabsWidth;
+ },
+
+ resize: function(dim){
+ // summary:
+ // Hides or displays the buttons used to scroll the tab list and launch the menu
+ // that selects tabs.
+
+ if(this.domNode.offsetWidth == 0){
+ return;
+ }
+
+ // Save the dimensions to be used when a child is renamed.
+ this._dim = dim;
+
+ // Set my height to be my natural height (tall enough for one row of tab labels),
+ // and my content-box width based on margin-box width specified in dim parameter.
+ // But first reset scrollNode.height in case it was set by layoutChildren() call
+ // in a previous run of this method.
+ this.scrollNode.style.height = "auto";
+ this._contentBox = dijit.layout.marginBox2contentBox(this.domNode, {h: 0, w: dim.w});
+ this._contentBox.h = this.scrollNode.offsetHeight;
+ dojo.contentBox(this.domNode, this._contentBox);
+
+ // Show/hide the left/right/menu navigation buttons depending on whether or not they
+ // are needed.
+ var enable = this._enableBtn(this._contentBox.w);
+ this._buttons.style("display", enable ? "" : "none");
+
+ // Position and size the navigation buttons and the tablist
+ this._leftBtn.layoutAlign = "left";
+ this._rightBtn.layoutAlign = "right";
+ this._menuBtn.layoutAlign = this.isLeftToRight() ? "right" : "left";
+ dijit.layout.layoutChildren(this.domNode, this._contentBox,
+ [this._menuBtn, this._leftBtn, this._rightBtn, {domNode: this.scrollNode, layoutAlign: "client"}]);
+
+ // set proper scroll so that selected tab is visible
+ if(this._selectedTab){
+ if(this._anim && this._anim.status() == "playing"){
+ this._anim.stop();
+ }
+ var w = this.scrollNode,
+ sl = this._convertToScrollLeft(this._getScrollForSelectedTab());
+ w.scrollLeft = sl;
+ }
+
+ // Enable/disabled left right buttons depending on whether or not user can scroll to left or right
+ this._setButtonClass(this._getScroll());
+
+ this._postResize = true;
+ },
+
+ _getScroll: function(){
+ // summary:
+ // Returns the current scroll of the tabs where 0 means
+ // "scrolled all the way to the left" and some positive number, based on #
+ // of pixels of possible scroll (ex: 1000) means "scrolled all the way to the right"
+ var sl = (this.isLeftToRight() || dojo.isIE < 8 || (dojo.isIE && dojo.isQuirks) || dojo.isWebKit) ? this.scrollNode.scrollLeft :
+ dojo.style(this.containerNode, "width") - dojo.style(this.scrollNode, "width")
+ + (dojo.isIE == 8 ? -1 : 1) * this.scrollNode.scrollLeft;
+ return sl;
+ },
+
+ _convertToScrollLeft: function(val){
+ // summary:
+ // Given a scroll value where 0 means "scrolled all the way to the left"
+ // and some positive number, based on # of pixels of possible scroll (ex: 1000)
+ // means "scrolled all the way to the right", return value to set this.scrollNode.scrollLeft
+ // to achieve that scroll.
+ //
+ // This method is to adjust for RTL funniness in various browsers and versions.
+ if(this.isLeftToRight() || dojo.isIE < 8 || (dojo.isIE && dojo.isQuirks) || dojo.isWebKit){
+ return val;
+ }else{
+ var maxScroll = dojo.style(this.containerNode, "width") - dojo.style(this.scrollNode, "width");
+ return (dojo.isIE == 8 ? -1 : 1) * (val - maxScroll);
+ }
+ },
+
+ onSelectChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Smoothly scrolls to a tab when it is selected.
+
+ var tab = this.pane2button[page.id];
+ if(!tab || !page){return;}
+
+ // Scroll to the selected tab, except on startup, when scrolling is handled in resize()
+ var node = tab.domNode;
+ if(this._postResize && node != this._selectedTab){
+ this._selectedTab = node;
+
+ var sl = this._getScroll();
+
+ if(sl > node.offsetLeft ||
+ sl + dojo.style(this.scrollNode, "width") <
+ node.offsetLeft + dojo.style(node, "width")){
+ this.createSmoothScroll().play();
+ }
+ }
+
+ this.inherited(arguments);
+ },
+
+ _getScrollBounds: function(){
+ // summary:
+ // Returns the minimum and maximum scroll setting to show the leftmost and rightmost
+ // tabs (respectively)
+ var children = this.getChildren(),
+ scrollNodeWidth = dojo.style(this.scrollNode, "width"), // about 500px
+ containerWidth = dojo.style(this.containerNode, "width"), // 50,000px
+ maxPossibleScroll = containerWidth - scrollNodeWidth, // scrolling until right edge of containerNode visible
+ tabsWidth = this._getTabsWidth();
+
+ if(children.length && tabsWidth > scrollNodeWidth){
+ // Scrolling should happen
+ return {
+ min: this.isLeftToRight() ? 0 : children[children.length-1].domNode.offsetLeft,
+ max: this.isLeftToRight() ?
+ (children[children.length-1].domNode.offsetLeft + dojo.style(children[children.length-1].domNode, "width")) - scrollNodeWidth :
+ maxPossibleScroll
+ };
+ }else{
+ // No scrolling needed, all tabs visible, we stay either scrolled to far left or far right (depending on dir)
+ var onlyScrollPosition = this.isLeftToRight() ? 0 : maxPossibleScroll;
+ return {
+ min: onlyScrollPosition,
+ max: onlyScrollPosition
+ };
+ }
+ },
+
+ _getScrollForSelectedTab: function(){
+ // summary:
+ // Returns the scroll value setting so that the selected tab
+ // will appear in the center
+ var w = this.scrollNode,
+ n = this._selectedTab,
+ scrollNodeWidth = dojo.style(this.scrollNode, "width"),
+ scrollBounds = this._getScrollBounds();
+
+ // TODO: scroll minimal amount (to either right or left) so that
+ // selected tab is fully visible, and just return if it's already visible?
+ var pos = (n.offsetLeft + dojo.style(n, "width")/2) - scrollNodeWidth/2;
+ pos = Math.min(Math.max(pos, scrollBounds.min), scrollBounds.max);
+
+ // TODO:
+ // If scrolling close to the left side or right side, scroll
+ // all the way to the left or right. See this._minScroll.
+ // (But need to make sure that doesn't scroll the tab out of view...)
+ return pos;
+ },
+
+ createSmoothScroll : function(x){
+ // summary:
+ // Creates a dojo._Animation object that smoothly scrolls the tab list
+ // either to a fixed horizontal pixel value, or to the selected tab.
+ // description:
+ // If an number argument is passed to the function, that horizontal
+ // pixel position is scrolled to. Otherwise the currently selected
+ // tab is scrolled to.
+ // x: Integer?
+ // An optional pixel value to scroll to, indicating distance from left.
+
+ // Calculate position to scroll to
+ if(arguments.length > 0){
+ // position specified by caller, just make sure it's within bounds
+ var scrollBounds = this._getScrollBounds();
+ x = Math.min(Math.max(x, scrollBounds.min), scrollBounds.max);
+ }else{
+ // scroll to center the current tab
+ x = this._getScrollForSelectedTab();
+ }
+
+ if(this._anim && this._anim.status() == "playing"){
+ this._anim.stop();
+ }
+
+ var self = this,
+ w = this.scrollNode,
+ anim = new dojo._Animation({
+ beforeBegin: function(){
+ if(this.curve){ delete this.curve; }
+ var oldS = w.scrollLeft,
+ newS = self._convertToScrollLeft(x);
+ anim.curve = new dojo._Line(oldS, newS);
+ },
+ onAnimate: function(val){
+ w.scrollLeft = val;
+ }
+ });
+ this._anim = anim;
+
+ // Disable/enable left/right buttons according to new scroll position
+ this._setButtonClass(x);
+
+ return anim; // dojo._Animation
+ },
+
+ _getBtnNode: function(e){
+ // summary:
+ // Gets a button DOM node from a mouse click event.
+ // e:
+ // The mouse click event.
+ var n = e.target;
+ while(n && !dojo.hasClass(n, "tabStripButton")){
+ n = n.parentNode;
+ }
+ return n;
+ },
+
+ doSlideRight: function(e){
+ // summary:
+ // Scrolls the menu to the right.
+ // e:
+ // The mouse click event.
+ this.doSlide(1, this._getBtnNode(e));
+ },
+
+ doSlideLeft: function(e){
+ // summary:
+ // Scrolls the menu to the left.
+ // e:
+ // The mouse click event.
+ this.doSlide(-1,this._getBtnNode(e));
+ },
+
+ doSlide: function(direction, node){
+ // summary:
+ // Scrolls the tab list to the left or right by 75% of the widget width.
+ // direction:
+ // If the direction is 1, the widget scrolls to the right, if it is
+ // -1, it scrolls to the left.
+
+ if(node && dojo.hasClass(node, "dijitTabDisabled")){return;}
+
+ var sWidth = dojo.style(this.scrollNode, "width");
+ var d = (sWidth * 0.75) * direction;
+
+ var to = this._getScroll() + d;
+
+ this._setButtonClass(to);
+
+ this.createSmoothScroll(to).play();
+ },
+
+ _setButtonClass: function(scroll){
+ // summary:
+ // Disables the left scroll button if the tabs are scrolled all the way to the left,
+ // or the right scroll button in the opposite case.
+ // scroll: Integer
+ // amount of horizontal scroll
+
+ var scrollBounds = this._getScrollBounds();
+ this._leftBtn.set("disabled", scroll <= scrollBounds.min);
+ this._rightBtn.set("disabled", scroll >= scrollBounds.max);
+ }
+});
+
+dojo.declare("dijit.layout._ScrollingTabControllerButton",
+ dijit.form.Button,
+ {
+ baseClass: "dijitTab tabStripButton",
+
+ templateString: dojo.cache("dijit.layout", "templates/_ScrollingTabControllerButton.html", "<div dojoAttachEvent=\"onclick:_onButtonClick\">\n\t<div waiRole=\"presentation\" class=\"dijitTabInnerDiv\" dojoattachpoint=\"innerDiv,focusNode\">\n\t\t<div waiRole=\"presentation\" class=\"dijitTabContent dijitButtonContents\" dojoattachpoint=\"tabContent\">\n\t\t\t<img waiRole=\"presentation\" alt=\"\" src=\"${_blankGif}\" class=\"dijitTabStripIcon\" dojoAttachPoint=\"iconNode\"/>\n\t\t\t<span dojoAttachPoint=\"containerNode,titleNode\" class=\"dijitButtonText\"></span>\n\t\t</div>\n\t</div>\n</div>\n"),
+
+ // Override inherited tabIndex: 0 from dijit.form.Button, because user shouldn't be
+ // able to tab to the left/right/menu buttons
+ tabIndex: "-1"
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit.layout.TabContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.TabContainer"] = true;
+dojo.provide("dijit.layout.TabContainer");
+
+
+
+
+
+dojo.declare("dijit.layout.TabContainer",
+ dijit.layout._TabContainerBase,
+ {
+ // summary:
+ // A Container with tabs to select each child (only one of which is displayed at a time).
+ // description:
+ // A TabContainer is a container that has multiple panes, but shows only
+ // one pane at a time. There are a set of tabs corresponding to each pane,
+ // where each tab has the name (aka title) of the pane, and optionally a close button.
+
+ // useMenu: [const] Boolean
+ // True if a menu should be used to select tabs when they are too
+ // wide to fit the TabContainer, false otherwise.
+ useMenu: true,
+
+ // useSlider: [const] Boolean
+ // True if a slider should be used to select tabs when they are too
+ // wide to fit the TabContainer, false otherwise.
+ useSlider: true,
+
+ // controllerWidget: String
+ // An optional parameter to override the widget used to display the tab labels
+ controllerWidget: "",
+
+ _makeController: function(/*DomNode*/ srcNode){
+ // summary:
+ // Instantiate tablist controller widget and return reference to it.
+ // Callback from _TabContainerBase.postCreate().
+ // tags:
+ // protected extension
+
+ var cls = this.baseClass + "-tabs" + (this.doLayout ? "" : " dijitTabNoLayout"),
+ TabController = dojo.getObject(this.controllerWidget);
+
+ return new TabController({
+ id: this.id + "_tablist",
+ dir: this.dir,
+ lang: this.lang,
+ tabPosition: this.tabPosition,
+ doLayout: this.doLayout,
+ containerId: this.id,
+ "class": cls,
+ nested: this.nested,
+ useMenu: this.useMenu,
+ useSlider: this.useSlider,
+ tabStripClass: this.tabStrip ? this.baseClass + (this.tabStrip ? "":"No") + "Strip": null
+ }, srcNode);
+ },
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+
+ // Scrolling controller only works for horizontal non-nested tabs
+ if(!this.controllerWidget){
+ this.controllerWidget = (this.tabPosition == "top" || this.tabPosition == "bottom") && !this.nested ?
+ "dijit.layout.ScrollingTabController" : "dijit.layout.TabController";
+ }
+ }
+});
+
+
+}
+
+if(!dojo._hasResource["dojo.number"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.number"] = true;
+dojo.provide("dojo.number");
+
+
+
+
+
+
+
+/*=====
+dojo.number = {
+ // summary: localized formatting and parsing routines for Number
+}
+
+dojo.number.__FormatOptions = function(){
+ // pattern: String?
+ // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // with this string. Default value is based on locale. Overriding this property will defeat
+ // localization. Literal characters in patterns are not supported.
+ // type: String?
+ // choose a format type based on the locale from the following:
+ // decimal, scientific (not yet supported), percent, currency. decimal by default.
+ // places: Number?
+ // fixed number of decimal places to show. This overrides any
+ // information in the provided pattern.
+ // round: Number?
+ // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
+ // means do not round.
+ // locale: String?
+ // override the locale used to determine formatting rules
+ // fractional: Boolean?
+ // If false, show no decimal places, overriding places and pattern settings.
+ this.pattern = pattern;
+ this.type = type;
+ this.places = places;
+ this.round = round;
+ this.locale = locale;
+ this.fractional = fractional;
+}
+=====*/
+
+dojo.number.format = function(/*Number*/value, /*dojo.number.__FormatOptions?*/options){
+ // summary:
+ // Format a Number as a String, using locale-specific settings
+ // description:
+ // Create a string from a Number using a known localized pattern.
+ // Formatting patterns appropriate to the locale are chosen from the
+ // [Common Locale Data Repository](http://unicode.org/cldr) as well as the appropriate symbols and
+ // delimiters.
+ // If value is Infinity, -Infinity, or is not a valid JavaScript number, return null.
+ // value:
+ // the number to be formatted
+
+ options = dojo.mixin({}, options || {});
+ var locale = dojo.i18n.normalizeLocale(options.locale),
+ bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale);
+ options.customs = bundle;
+ var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
+ if(isNaN(value) || Math.abs(value) == Infinity){ return null; } // null
+ return dojo.number._applyPattern(value, pattern, options); // String
+};
+
+//dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enough
+dojo.number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enough
+
+dojo.number._applyPattern = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatOptions?*/options){
+ // summary:
+ // Apply pattern to format value as a string using options. Gives no
+ // consideration to local customs.
+ // value:
+ // the number to be formatted.
+ // pattern:
+ // a pattern string as described by
+ // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // options: dojo.number.__FormatOptions?
+ // _applyPattern is usually called via `dojo.number.format()` which
+ // populates an extra property in the options parameter, "customs".
+ // The customs object specifies group and decimal parameters if set.
+
+ //TODO: support escapes
+ options = options || {};
+ var group = options.customs.group,
+ decimal = options.customs.decimal,
+ patternList = pattern.split(';'),
+ positivePattern = patternList[0];
+ pattern = patternList[(value < 0) ? 1 : 0] || ("-" + positivePattern);
+
+ //TODO: only test against unescaped
+ if(pattern.indexOf('%') != -1){
+ value *= 100;
+ }else if(pattern.indexOf('\u2030') != -1){
+ value *= 1000; // per mille
+ }else if(pattern.indexOf('\u00a4') != -1){
+ group = options.customs.currencyGroup || group;//mixins instead?
+ decimal = options.customs.currencyDecimal || decimal;// Should these be mixins instead?
+ pattern = pattern.replace(/\u00a4{1,3}/, function(match){
+ var prop = ["symbol", "currency", "displayName"][match.length-1];
+ return options[prop] || options.currency || "";
+ });
+ }else if(pattern.indexOf('E') != -1){
+ throw new Error("exponential notation not supported");
+ }
+
+ //TODO: support @ sig figs?
+ var numberPatternRE = dojo.number._numberPatternRE;
+ var numberPattern = positivePattern.match(numberPatternRE);
+ if(!numberPattern){
+ throw new Error("unable to find a number expression in pattern: "+pattern);
+ }
+ if(options.fractional === false){ options.places = 0; }
+ return pattern.replace(numberPatternRE,
+ dojo.number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places, round: options.round}));
+}
+
+dojo.number.round = function(/*Number*/value, /*Number?*/places, /*Number?*/increment){
+ // summary:
+ // Rounds to the nearest value with the given number of decimal places, away from zero
+ // description:
+ // Rounds to the nearest value with the given number of decimal places, away from zero if equal.
+ // Similar to Number.toFixed(), but compensates for browser quirks. Rounding can be done by
+ // fractional increments also, such as the nearest quarter.
+ // NOTE: Subject to floating point errors. See dojox.math.round for experimental workaround.
+ // value:
+ // The number to round
+ // places:
+ // The number of decimal places where rounding takes place. Defaults to 0 for whole rounding.
+ // Must be non-negative.
+ // increment:
+ // Rounds next place to nearest value of increment/10. 10 by default.
+ // example:
+ // >>> dojo.number.round(-0.5)
+ // -1
+ // >>> dojo.number.round(162.295, 2)
+ // 162.29 // note floating point error. Should be 162.3
+ // >>> dojo.number.round(10.71, 0, 2.5)
+ // 10.75
+ var factor = 10 / (increment || 10);
+ return (factor * +value).toFixed(places) / factor; // Number
+}
+
+if((0.9).toFixed() == 0){
+ // (isIE) toFixed() bug workaround: Rounding fails on IE when most significant digit
+ // is just after the rounding place and is >=5
+ (function(){
+ var round = dojo.number.round;
+ dojo.number.round = function(v, p, m){
+ var d = Math.pow(10, -p || 0), a = Math.abs(v);
+ if(!v || a >= d || a * Math.pow(10, p + 1) < 5){
+ d = 0;
+ }
+ return round(v, p, m) + (v > 0 ? d : -d);
+ }
+ })();
+}
+
+/*=====
+dojo.number.__FormatAbsoluteOptions = function(){
+ // decimal: String?
+ // the decimal separator
+ // group: String?
+ // the group separator
+ // places: Number?|String?
+ // number of decimal places. the range "n,m" will format to m places.
+ // round: Number?
+ // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
+ // means don't round.
+ this.decimal = decimal;
+ this.group = group;
+ this.places = places;
+ this.round = round;
+}
+=====*/
+
+dojo.number._formatAbsolute = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatAbsoluteOptions?*/options){
+ // summary:
+ // Apply numeric pattern to absolute value using options. Gives no
+ // consideration to local customs.
+ // value:
+ // the number to be formatted, ignores sign
+ // pattern:
+ // the number portion of a pattern (e.g. `#,##0.00`)
+ options = options || {};
+ if(options.places === true){options.places=0;}
+ if(options.places === Infinity){options.places=6;} // avoid a loop; pick a limit
+
+ var patternParts = pattern.split("."),
+ comma = typeof options.places == "string" && options.places.indexOf(","),
+ maxPlaces = options.places;
+ if(comma){
+ maxPlaces = options.places.substring(comma + 1);
+ }else if(!(maxPlaces >= 0)){
+ maxPlaces = (patternParts[1] || []).length;
+ }
+ if(!(options.round < 0)){
+ value = dojo.number.round(value, maxPlaces, options.round);
+ }
+
+ var valueParts = String(Math.abs(value)).split("."),
+ fractional = valueParts[1] || "";
+ if(patternParts[1] || options.places){
+ if(comma){
+ options.places = options.places.substring(0, comma);
+ }
+ // Pad fractional with trailing zeros
+ var pad = options.places !== undefined ? options.places : (patternParts[1] && patternParts[1].lastIndexOf("0") + 1);
+ if(pad > fractional.length){
+ valueParts[1] = dojo.string.pad(fractional, pad, '0', true);
+ }
+
+ // Truncate fractional
+ if(maxPlaces < fractional.length){
+ valueParts[1] = fractional.substr(0, maxPlaces);
+ }
+ }else{
+ if(valueParts[1]){ valueParts.pop(); }
+ }
+
+ // Pad whole with leading zeros
+ var patternDigits = patternParts[0].replace(',', '');
+ pad = patternDigits.indexOf("0");
+ if(pad != -1){
+ pad = patternDigits.length - pad;
+ if(pad > valueParts[0].length){
+ valueParts[0] = dojo.string.pad(valueParts[0], pad);
+ }
+
+ // Truncate whole
+ if(patternDigits.indexOf("#") == -1){
+ valueParts[0] = valueParts[0].substr(valueParts[0].length - pad);
+ }
+ }
+
+ // Add group separators
+ var index = patternParts[0].lastIndexOf(','),
+ groupSize, groupSize2;
+ if(index != -1){
+ groupSize = patternParts[0].length - index - 1;
+ var remainder = patternParts[0].substr(0, index);
+ index = remainder.lastIndexOf(',');
+ if(index != -1){
+ groupSize2 = remainder.length - index - 1;
+ }
+ }
+ var pieces = [];
+ for(var whole = valueParts[0]; whole;){
+ var off = whole.length - groupSize;
+ pieces.push((off > 0) ? whole.substr(off) : whole);
+ whole = (off > 0) ? whole.slice(0, off) : "";
+ if(groupSize2){
+ groupSize = groupSize2;
+ delete groupSize2;
+ }
+ }
+ valueParts[0] = pieces.reverse().join(options.group || ",");
+
+ return valueParts.join(options.decimal || ".");
+};
+
+/*=====
+dojo.number.__RegexpOptions = function(){
+ // pattern: String?
+ // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // with this string. Default value is based on locale. Overriding this property will defeat
+ // localization.
+ // type: String?
+ // choose a format type based on the locale from the following:
+ // decimal, scientific (not yet supported), percent, currency. decimal by default.
+ // locale: String?
+ // override the locale used to determine formatting rules
+ // strict: Boolean?
+ // strict parsing, false by default. Strict parsing requires input as produced by the format() method.
+ // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
+ // places: Number|String?
+ // number of decimal places to accept: Infinity, a positive number, or
+ // a range "n,m". Defined by pattern or Infinity if pattern not provided.
+ this.pattern = pattern;
+ this.type = type;
+ this.locale = locale;
+ this.strict = strict;
+ this.places = places;
+}
+=====*/
+dojo.number.regexp = function(/*dojo.number.__RegexpOptions?*/options){
+ // summary:
+ // Builds the regular needed to parse a number
+ // description:
+ // Returns regular expression with positive and negative match, group
+ // and decimal separators
+ return dojo.number._parseInfo(options).regexp; // String
+}
+
+dojo.number._parseInfo = function(/*Object?*/options){
+ options = options || {};
+ var locale = dojo.i18n.normalizeLocale(options.locale),
+ bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale),
+ pattern = options.pattern || bundle[(options.type || "decimal") + "Format"],
+//TODO: memoize?
+ group = bundle.group,
+ decimal = bundle.decimal,
+ factor = 1;
+
+ if(pattern.indexOf('%') != -1){
+ factor /= 100;
+ }else if(pattern.indexOf('\u2030') != -1){
+ factor /= 1000; // per mille
+ }else{
+ var isCurrency = pattern.indexOf('\u00a4') != -1;
+ if(isCurrency){
+ group = bundle.currencyGroup || group;
+ decimal = bundle.currencyDecimal || decimal;
+ }
+ }
+
+ //TODO: handle quoted escapes
+ var patternList = pattern.split(';');
+ if(patternList.length == 1){
+ patternList.push("-" + patternList[0]);
+ }
+
+ var re = dojo.regexp.buildGroupRE(patternList, function(pattern){
+ pattern = "(?:"+dojo.regexp.escapeString(pattern, '.')+")";
+ return pattern.replace(dojo.number._numberPatternRE, function(format){
+ var flags = {
+ signed: false,
+ separator: options.strict ? group : [group,""],
+ fractional: options.fractional,
+ decimal: decimal,
+ exponent: false
+ },
+
+ parts = format.split('.'),
+ places = options.places;
+
+ // special condition for percent (factor != 1)
+ // allow decimal places even if not specified in pattern
+ if(parts.length == 1 && factor != 1){
+ parts[1] = "###";
+ }
+ if(parts.length == 1 || places === 0){
+ flags.fractional = false;
+ }else{
+ if(places === undefined){ places = options.pattern ? parts[1].lastIndexOf('0') + 1 : Infinity; }
+ if(places && options.fractional == undefined){flags.fractional = true;} // required fractional, unless otherwise specified
+ if(!options.places && (places < parts[1].length)){ places += "," + parts[1].length; }
+ flags.places = places;
+ }
+ var groups = parts[0].split(',');
+ if(groups.length > 1){
+ flags.groupSize = groups.pop().length;
+ if(groups.length > 1){
+ flags.groupSize2 = groups.pop().length;
+ }
+ }
+ return "("+dojo.number._realNumberRegexp(flags)+")";
+ });
+ }, true);
+
+ if(isCurrency){
+ // substitute the currency symbol for the placeholder in the pattern
+ re = re.replace(/([\s\xa0]*)(\u00a4{1,3})([\s\xa0]*)/g, function(match, before, target, after){
+ var prop = ["symbol", "currency", "displayName"][target.length-1],
+ symbol = dojo.regexp.escapeString(options[prop] || options.currency || "");
+ before = before ? "[\\s\\xa0]" : "";
+ after = after ? "[\\s\\xa0]" : "";
+ if(!options.strict){
+ if(before){before += "*";}
+ if(after){after += "*";}
+ return "(?:"+before+symbol+after+")?";
+ }
+ return before+symbol+after;
+ });
+ }
+
+//TODO: substitute localized sign/percent/permille/etc.?
+
+ // normalize whitespace and return
+ return {regexp: re.replace(/[\xa0 ]/g, "[\\s\\xa0]"), group: group, decimal: decimal, factor: factor}; // Object
+}
+
+/*=====
+dojo.number.__ParseOptions = function(){
+ // pattern: String?
+ // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // with this string. Default value is based on locale. Overriding this property will defeat
+ // localization. Literal characters in patterns are not supported.
+ // type: String?
+ // choose a format type based on the locale from the following:
+ // decimal, scientific (not yet supported), percent, currency. decimal by default.
+ // locale: String?
+ // override the locale used to determine formatting rules
+ // strict: Boolean?
+ // strict parsing, false by default. Strict parsing requires input as produced by the format() method.
+ // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
+ // fractional: Boolean?|Array?
+ // Whether to include the fractional portion, where the number of decimal places are implied by pattern
+ // or explicit 'places' parameter. The value [true,false] makes the fractional portion optional.
+ this.pattern = pattern;
+ this.type = type;
+ this.locale = locale;
+ this.strict = strict;
+ this.fractional = fractional;
+}
+=====*/
+dojo.number.parse = function(/*String*/expression, /*dojo.number.__ParseOptions?*/options){
+ // summary:
+ // Convert a properly formatted string to a primitive Number, using
+ // locale-specific settings.
+ // description:
+ // Create a Number from a string using a known localized pattern.
+ // Formatting patterns are chosen appropriate to the locale
+ // and follow the syntax described by
+ // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // Note that literal characters in patterns are not supported.
+ // expression:
+ // A string representation of a Number
+ var info = dojo.number._parseInfo(options),
+ results = (new RegExp("^"+info.regexp+"$")).exec(expression);
+ if(!results){
+ return NaN; //NaN
+ }
+ var absoluteMatch = results[1]; // match for the positive expression
+ if(!results[1]){
+ if(!results[2]){
+ return NaN; //NaN
+ }
+ // matched the negative pattern
+ absoluteMatch =results[2];
+ info.factor *= -1;
+ }
+
+ // Transform it to something Javascript can parse as a number. Normalize
+ // decimal point and strip out group separators or alternate forms of whitespace
+ absoluteMatch = absoluteMatch.
+ replace(new RegExp("["+info.group + "\\s\\xa0"+"]", "g"), "").
+ replace(info.decimal, ".");
+ // Adjust for negative sign, percent, etc. as necessary
+ return absoluteMatch * info.factor; //Number
+};
+
+/*=====
+dojo.number.__RealNumberRegexpFlags = function(){
+ // places: Number?
+ // The integer number of decimal places or a range given as "n,m". If
+ // not given, the decimal part is optional and the number of places is
+ // unlimited.
+ // decimal: String?
+ // A string for the character used as the decimal point. Default
+ // is ".".
+ // fractional: Boolean?|Array?
+ // Whether decimal places are used. Can be true, false, or [true,
+ // false]. Default is [true, false] which means optional.
+ // exponent: Boolean?|Array?
+ // Express in exponential notation. Can be true, false, or [true,
+ // false]. Default is [true, false], (i.e. will match if the
+ // exponential part is present are not).
+ // eSigned: Boolean?|Array?
+ // The leading plus-or-minus sign on the exponent. Can be true,
+ // false, or [true, false]. Default is [true, false], (i.e. will
+ // match if it is signed or unsigned). flags in regexp.integer can be
+ // applied.
+ this.places = places;
+ this.decimal = decimal;
+ this.fractional = fractional;
+ this.exponent = exponent;
+ this.eSigned = eSigned;
+}
+=====*/
+
+dojo.number._realNumberRegexp = function(/*dojo.number.__RealNumberRegexpFlags?*/flags){
+ // summary:
+ // Builds a regular expression to match a real number in exponential
+ // notation
+
+ // assign default values to missing parameters
+ flags = flags || {};
+ //TODO: use mixin instead?
+ if(!("places" in flags)){ flags.places = Infinity; }
+ if(typeof flags.decimal != "string"){ flags.decimal = "."; }
+ if(!("fractional" in flags) || /^0/.test(flags.places)){ flags.fractional = [true, false]; }
+ if(!("exponent" in flags)){ flags.exponent = [true, false]; }
+ if(!("eSigned" in flags)){ flags.eSigned = [true, false]; }
+
+ var integerRE = dojo.number._integerRegexp(flags),
+ decimalRE = dojo.regexp.buildGroupRE(flags.fractional,
+ function(q){
+ var re = "";
+ if(q && (flags.places!==0)){
+ re = "\\" + flags.decimal;
+ if(flags.places == Infinity){
+ re = "(?:" + re + "\\d+)?";
+ }else{
+ re += "\\d{" + flags.places + "}";
+ }
+ }
+ return re;
+ },
+ true
+ );
+
+ var exponentRE = dojo.regexp.buildGroupRE(flags.exponent,
+ function(q){
+ if(q){ return "([eE]" + dojo.number._integerRegexp({ signed: flags.eSigned}) + ")"; }
+ return "";
+ }
+ );
+
+ var realRE = integerRE + decimalRE;
+ // allow for decimals without integers, e.g. .25
+ if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";}
+ return realRE + exponentRE; // String
+};
+
+/*=====
+dojo.number.__IntegerRegexpFlags = function(){
+ // signed: Boolean?
+ // The leading plus-or-minus sign. Can be true, false, or `[true,false]`.
+ // Default is `[true, false]`, (i.e. will match if it is signed
+ // or unsigned).
+ // separator: String?
+ // The character used as the thousands separator. Default is no
+ // separator. For more than one symbol use an array, e.g. `[",", ""]`,
+ // makes ',' optional.
+ // groupSize: Number?
+ // group size between separators
+ // groupSize2: Number?
+ // second grouping, where separators 2..n have a different interval than the first separator (for India)
+ this.signed = signed;
+ this.separator = separator;
+ this.groupSize = groupSize;
+ this.groupSize2 = groupSize2;
+}
+=====*/
+
+dojo.number._integerRegexp = function(/*dojo.number.__IntegerRegexpFlags?*/flags){
+ // summary:
+ // Builds a regular expression that matches an integer
+
+ // assign default values to missing parameters
+ flags = flags || {};
+ if(!("signed" in flags)){ flags.signed = [true, false]; }
+ if(!("separator" in flags)){
+ flags.separator = "";
+ }else if(!("groupSize" in flags)){
+ flags.groupSize = 3;
+ }
+
+ var signRE = dojo.regexp.buildGroupRE(flags.signed,
+ function(q){ return q ? "[-+]" : ""; },
+ true
+ );
+
+ var numberRE = dojo.regexp.buildGroupRE(flags.separator,
+ function(sep){
+ if(!sep){
+ return "(?:\\d+)";
+ }
+
+ sep = dojo.regexp.escapeString(sep);
+ if(sep == " "){ sep = "\\s"; }
+ else if(sep == "\xa0"){ sep = "\\s\\xa0"; }
+
+ var grp = flags.groupSize, grp2 = flags.groupSize2;
+ //TODO: should we continue to enforce that numbers with separators begin with 1-9? See #6933
+ if(grp2){
+ var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})";
+ return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE;
+ }
+ return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)";
+ },
+ true
+ );
+
+ return signRE + numberRE; // String
+}
+
+}
+
+if(!dojo._hasResource["dijit.ProgressBar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.ProgressBar"] = true;
+dojo.provide("dijit.ProgressBar");
+
+
+
+
+
+
+
+dojo.declare("dijit.ProgressBar", [dijit._Widget, dijit._Templated], {
+ // summary:
+ // A progress indication widget, showing the amount completed
+ // (often the percentage completed) of a task.
+ //
+ // example:
+ // | <div dojoType="ProgressBar"
+ // | places="0"
+ // | progress="..." maximum="...">
+ // | </div>
+ //
+ // description:
+ // Note that the progress bar is updated via (a non-standard)
+ // update() method, rather than via attr() like other widgets.
+
+ // progress: [const] String (Percentage or Number)
+ // Number or percentage indicating amount of task completed.
+ // With "%": percentage value, 0% <= progress <= 100%, or
+ // without "%": absolute value, 0 <= progress <= maximum
+ // TODO: rename to value for 2.0
+ progress: "0",
+
+ // maximum: [const] Float
+ // Max sample number
+ maximum: 100,
+
+ // places: [const] Number
+ // Number of places to show in values; 0 by default
+ places: 0,
+
+ // indeterminate: [const] Boolean
+ // If false: show progress value (number or percentage).
+ // If true: show that a process is underway but that the amount completed is unknown.
+ indeterminate: false,
+
+ // name: String
+ // this is the field name (for a form) if set. This needs to be set if you want to use
+ // this widget in a dijit.form.Form widget (such as dijit.Dialog)
+ name: '',
+
+ templateString: dojo.cache("dijit", "templates/ProgressBar.html", "<div class=\"dijitProgressBar dijitProgressBarEmpty\"\n\t><div waiRole=\"progressbar\" dojoAttachPoint=\"internalProgress\" class=\"dijitProgressBarFull\"\n\t\t><div class=\"dijitProgressBarTile\"></div\n\t\t><span style=\"visibility:hidden\">&nbsp;</span\n\t></div\n\t><div dojoAttachPoint=\"label\" class=\"dijitProgressBarLabel\" id=\"${id}_label\">&nbsp;</div\n\t><img dojoAttachPoint=\"indeterminateHighContrastImage\" class=\"dijitProgressBarIndeterminateHighContrastImage\" alt=\"\"\n/></div>\n"),
+
+ // _indeterminateHighContrastImagePath: [private] dojo._URL
+ // URL to image to use for indeterminate progress bar when display is in high contrast mode
+ _indeterminateHighContrastImagePath:
+ dojo.moduleUrl("dijit", "themes/a11y/indeterminate_progress.gif"),
+
+ // public functions
+ postCreate: function(){
+ this.inherited(arguments);
+ this.indeterminateHighContrastImage.setAttribute("src",
+ this._indeterminateHighContrastImagePath.toString());
+ this.update();
+ },
+
+ update: function(/*Object?*/attributes){
+ // summary:
+ // Change attributes of ProgressBar, similar to attr(hash).
+ //
+ // attributes:
+ // May provide progress and/or maximum properties on this parameter;
+ // see attribute specs for details.
+ //
+ // example:
+ // | myProgressBar.update({'indeterminate': true});
+ // | myProgressBar.update({'progress': 80});
+
+ // TODO: deprecate this method and use set() instead
+
+ dojo.mixin(this, attributes || {});
+ var tip = this.internalProgress;
+ var percent = 1, classFunc;
+ if(this.indeterminate){
+ classFunc = "addClass";
+ dijit.removeWaiState(tip, "valuenow");
+ dijit.removeWaiState(tip, "valuemin");
+ dijit.removeWaiState(tip, "valuemax");
+ }else{
+ classFunc = "removeClass";
+ if(String(this.progress).indexOf("%") != -1){
+ percent = Math.min(parseFloat(this.progress)/100, 1);
+ this.progress = percent * this.maximum;
+ }else{
+ this.progress = Math.min(this.progress, this.maximum);
+ percent = this.progress / this.maximum;
+ }
+ var text = this.report(percent);
+ this.label.firstChild.nodeValue = text;
+ dijit.setWaiState(tip, "describedby", this.label.id);
+ dijit.setWaiState(tip, "valuenow", this.progress);
+ dijit.setWaiState(tip, "valuemin", 0);
+ dijit.setWaiState(tip, "valuemax", this.maximum);
+ }
+ dojo[classFunc](this.domNode, "dijitProgressBarIndeterminate");
+ tip.style.width = (percent * 100) + "%";
+ this.onChange();
+ },
+
+ _setValueAttr: function(v){
+ if(v == Infinity){
+ this.update({indeterminate:true});
+ }else{
+ this.update({indeterminate:false, progress:v});
+ }
+ },
+
+ _getValueAttr: function(){
+ return this.progress;
+ },
+
+ report: function(/*float*/percent){
+ // summary:
+ // Generates message to show inside progress bar (normally indicating amount of task completed).
+ // May be overridden.
+ // tags:
+ // extension
+
+ return dojo.number.format(percent, { type: "percent", places: this.places, locale: this.lang });
+ },
+
+ onChange: function(){
+ // summary:
+ // Callback fired when progress updates.
+ // tags:
+ // progress
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.ToolbarSeparator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.ToolbarSeparator"] = true;
+dojo.provide("dijit.ToolbarSeparator");
+
+
+
+
+dojo.declare("dijit.ToolbarSeparator",
+ [ dijit._Widget, dijit._Templated ],
+ {
+ // summary:
+ // A spacer between two `dijit.Toolbar` items
+ templateString: '<div class="dijitToolbarSeparator dijitInline" waiRole="presentation"></div>',
+ postCreate: function(){ dojo.setSelectable(this.domNode, false); },
+ isFocusable: function(){
+ // summary:
+ // This widget isn't focusable, so pass along that fact.
+ // tags:
+ // protected
+ return false;
+ }
+
+ });
+
+
+
+}
+
+if(!dojo._hasResource["dijit.Toolbar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.Toolbar"] = true;
+dojo.provide("dijit.Toolbar");
+
+
+
+
+
+dojo.declare("dijit.Toolbar",
+ [dijit._Widget, dijit._Templated, dijit._KeyNavContainer],
+ {
+ // summary:
+ // A Toolbar widget, used to hold things like `dijit.Editor` buttons
+
+ templateString:
+ '<div class="dijit" waiRole="toolbar" tabIndex="${tabIndex}" dojoAttachPoint="containerNode">' +
+ // '<table style="table-layout: fixed" class="dijitReset dijitToolbarTable">' + // factor out style
+ // '<tr class="dijitReset" dojoAttachPoint="containerNode"></tr>'+
+ // '</table>' +
+ '</div>',
+
+ baseClass: "dijitToolbar",
+
+ postCreate: function(){
+ this.connectKeyNavHandlers(
+ this.isLeftToRight() ? [dojo.keys.LEFT_ARROW] : [dojo.keys.RIGHT_ARROW],
+ this.isLeftToRight() ? [dojo.keys.RIGHT_ARROW] : [dojo.keys.LEFT_ARROW]
+ );
+ this.inherited(arguments);
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+
+ this.startupKeyNavChildren();
+
+ this.inherited(arguments);
+ }
+}
+);
+
+// For back-compat, remove for 2.0
+
+
+}
+
+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.DeferredList = 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
+ var resultList = [];
+ dojo.Deferred.call(this);
+ var self = this;
+ if(list.length === 0 && !fireOnOneCallback){
+ this.resolve([0, []]);
+ }
+ var finished = 0;
+ dojo.forEach(list, function(item, i){
+ item.then(function(result){
+ if(fireOnOneCallback){
+ self.resolve([i, result]);
+ }else{
+ addResult(true, result);
+ }
+ },function(error){
+ if(fireOnOneErrback){
+ self.reject(error);
+ }else{
+ addResult(false, error);
+ }
+ if(consumeErrors){
+ return null;
+ }
+ throw error;
+ });
+ function addResult(succeeded, result){
+ resultList[i] = [succeeded, result];
+ finished++;
+ if(finished === list.length){
+ self.resolve(resultList);
+ }
+
+ }
+ });
+};
+dojo.DeferredList.prototype = new dojo.Deferred();
+
+dojo.DeferredList.prototype.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;
+};
+
+}
+
+if(!dojo._hasResource["dijit.tree.TreeStoreModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.tree.TreeStoreModel"] = true;
+dojo.provide("dijit.tree.TreeStoreModel");
+
+dojo.declare(
+ "dijit.tree.TreeStoreModel",
+ null,
+ {
+ // summary:
+ // Implements dijit.Tree.model connecting to a store with a single
+ // root item. Any methods passed into the constructor will override
+ // the ones defined here.
+
+ // store: dojo.data.Store
+ // Underlying store
+ store: null,
+
+ // childrenAttrs: String[]
+ // One or more attribute names (attributes in the dojo.data item) that specify that item's children
+ childrenAttrs: ["children"],
+
+ // newItemIdAttr: String
+ // Name of attribute in the Object passed to newItem() that specifies the id.
+ //
+ // If newItemIdAttr is set then it's used when newItem() is called to see if an
+ // item with the same id already exists, and if so just links to the old item
+ // (so that the old item ends up with two parents).
+ //
+ // Setting this to null or "" will make every drop create a new item.
+ newItemIdAttr: "id",
+
+ // labelAttr: String
+ // If specified, get label for tree node from this attribute, rather
+ // than by calling store.getLabel()
+ labelAttr: "",
+
+ // root: [readonly] dojo.data.Item
+ // Pointer to the root item (read only, not a parameter)
+ root: null,
+
+ // query: anything
+ // Specifies datastore query to return the root item for the tree.
+ // Must only return a single item. Alternately can just pass in pointer
+ // to root item.
+ // example:
+ // | {id:'ROOT'}
+ query: null,
+
+ // deferItemLoadingUntilExpand: Boolean
+ // Setting this to true will cause the TreeStoreModel to defer calling loadItem on nodes
+ // until they are expanded. This allows for lazying loading where only one
+ // loadItem (and generally one network call, consequently) per expansion
+ // (rather than one for each child).
+ // This relies on partial loading of the children items; each children item of a
+ // fully loaded item should contain the label and info about having children.
+ deferItemLoadingUntilExpand: false,
+
+ constructor: function(/* Object */ args){
+ // summary:
+ // Passed the arguments listed above (store, etc)
+ // tags:
+ // private
+
+ dojo.mixin(this, args);
+
+ this.connects = [];
+
+ var store = this.store;
+ if(!store.getFeatures()['dojo.data.api.Identity']){
+ throw new Error("dijit.Tree: store must support dojo.data.Identity");
+ }
+
+ // if the store supports Notification, subscribe to the notification events
+ if(store.getFeatures()['dojo.data.api.Notification']){
+ this.connects = this.connects.concat([
+ dojo.connect(store, "onNew", this, "onNewItem"),
+ dojo.connect(store, "onDelete", this, "onDeleteItem"),
+ dojo.connect(store, "onSet", this, "onSetItem")
+ ]);
+ }
+ },
+
+ destroy: function(){
+ dojo.forEach(this.connects, dojo.disconnect);
+ // TODO: should cancel any in-progress processing of getRoot(), getChildren()
+ },
+
+ // =======================================================================
+ // Methods for traversing hierarchy
+
+ getRoot: function(onItem, onError){
+ // summary:
+ // Calls onItem with the root item for the tree, possibly a fabricated item.
+ // Calls onError on error.
+ if(this.root){
+ onItem(this.root);
+ }else{
+ this.store.fetch({
+ query: this.query,
+ onComplete: dojo.hitch(this, function(items){
+ if(items.length != 1){
+ throw new Error(this.declaredClass + ": query " + dojo.toJson(this.query) + " returned " + items.length +
+ " items, but must return exactly one item");
+ }
+ this.root = items[0];
+ onItem(this.root);
+ }),
+ onError: onError
+ });
+ }
+ },
+
+ mayHaveChildren: function(/*dojo.data.Item*/ item){
+ // summary:
+ // Tells if an item has or may have children. Implementing logic here
+ // avoids showing +/- expando icon for nodes that we know don't have children.
+ // (For efficiency reasons we may not want to check if an element actually
+ // has children until user clicks the expando node)
+ return dojo.some(this.childrenAttrs, function(attr){
+ return this.store.hasAttribute(item, attr);
+ }, this);
+ },
+
+ getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete, /*function*/ onError){
+ // summary:
+ // Calls onComplete() with array of child items of given parent item, all loaded.
+
+ var store = this.store;
+ if(!store.isItemLoaded(parentItem)){
+ // The parent is not loaded yet, we must be in deferItemLoadingUntilExpand
+ // mode, so we will load it and just return the children (without loading each
+ // child item)
+ var getChildren = dojo.hitch(this, arguments.callee);
+ store.loadItem({
+ item: parentItem,
+ onItem: function(parentItem){
+ getChildren(parentItem, onComplete, onError);
+ },
+ onError: onError
+ });
+ return;
+ }
+ // get children of specified item
+ var childItems = [];
+ for(var i=0; i<this.childrenAttrs.length; i++){
+ var vals = store.getValues(parentItem, this.childrenAttrs[i]);
+ childItems = childItems.concat(vals);
+ }
+
+ // count how many items need to be loaded
+ var _waitCount = 0;
+ if(!this.deferItemLoadingUntilExpand){
+ dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } });
+ }
+
+ if(_waitCount == 0){
+ // all items are already loaded (or we aren't loading them). proceed...
+ onComplete(childItems);
+ }else{
+ // still waiting for some or all of the items to load
+ dojo.forEach(childItems, function(item, idx){
+ if(!store.isItemLoaded(item)){
+ store.loadItem({
+ item: item,
+ onItem: function(item){
+ childItems[idx] = item;
+ if(--_waitCount == 0){
+ // all nodes have been loaded, send them to the tree
+ onComplete(childItems);
+ }
+ },
+ onError: onError
+ });
+ }
+ });
+ }
+ },
+
+ // =======================================================================
+ // Inspecting items
+
+ isItem: function(/* anything */ something){
+ return this.store.isItem(something); // Boolean
+ },
+
+ fetchItemByIdentity: function(/* object */ keywordArgs){
+ this.store.fetchItemByIdentity(keywordArgs);
+ },
+
+ getIdentity: function(/* item */ item){
+ return this.store.getIdentity(item); // Object
+ },
+
+ getLabel: function(/*dojo.data.Item*/ item){
+ // summary:
+ // Get the label for an item
+ if(this.labelAttr){
+ return this.store.getValue(item,this.labelAttr); // String
+ }else{
+ return this.store.getLabel(item); // String
+ }
+ },
+
+ // =======================================================================
+ // Write interface
+
+ newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
+ // summary:
+ // Creates a new item. See `dojo.data.api.Write` for details on args.
+ // Used in drag & drop when item from external source dropped onto tree.
+ // description:
+ // Developers will need to override this method if new items get added
+ // to parents with multiple children attributes, in order to define which
+ // children attribute points to the new item.
+
+ var pInfo = {parent: parent, attribute: this.childrenAttrs[0], insertIndex: insertIndex};
+
+ if(this.newItemIdAttr && args[this.newItemIdAttr]){
+ // Maybe there's already a corresponding item in the store; if so, reuse it.
+ this.fetchItemByIdentity({identity: args[this.newItemIdAttr], scope: this, onItem: function(item){
+ if(item){
+ // There's already a matching item in store, use it
+ this.pasteItem(item, null, parent, true, insertIndex);
+ }else{
+ // Create new item in the tree, based on the drag source.
+ this.store.newItem(args, pInfo);
+ }
+ }});
+ }else{
+ // [as far as we know] there is no id so we must assume this is a new item
+ this.store.newItem(args, pInfo);
+ }
+ },
+
+ pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
+ // summary:
+ // Move or copy an item from one parent item to another.
+ // Used in drag & drop
+ var store = this.store,
+ parentAttr = this.childrenAttrs[0]; // name of "children" attr in parent item
+
+ // remove child from source item, and record the attribute that child occurred in
+ if(oldParentItem){
+ dojo.forEach(this.childrenAttrs, function(attr){
+ if(store.containsValue(oldParentItem, attr, childItem)){
+ if(!bCopy){
+ var values = dojo.filter(store.getValues(oldParentItem, attr), function(x){
+ return x != childItem;
+ });
+ store.setValues(oldParentItem, attr, values);
+ }
+ parentAttr = attr;
+ }
+ });
+ }
+
+ // modify target item's children attribute to include this item
+ if(newParentItem){
+ if(typeof insertIndex == "number"){
+ // call slice() to avoid modifying the original array, confusing the data store
+ var childItems = store.getValues(newParentItem, parentAttr).slice();
+ childItems.splice(insertIndex, 0, childItem);
+ store.setValues(newParentItem, parentAttr, childItems);
+ }else{
+ store.setValues(newParentItem, parentAttr,
+ store.getValues(newParentItem, parentAttr).concat(childItem));
+ }
+ }
+ },
+
+ // =======================================================================
+ // Callbacks
+
+ onChange: function(/*dojo.data.Item*/ item){
+ // summary:
+ // Callback whenever an item has changed, so that Tree
+ // can update the label, icon, etc. Note that changes
+ // to an item's children or parent(s) will trigger an
+ // onChildrenChange() so you can ignore those changes here.
+ // tags:
+ // callback
+ },
+
+ onChildrenChange: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
+ // summary:
+ // Callback to do notifications about new, updated, or deleted items.
+ // tags:
+ // callback
+ },
+
+ onDelete: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
+ // summary:
+ // Callback when an item has been deleted.
+ // description:
+ // Note that there will also be an onChildrenChange() callback for the parent
+ // of this item.
+ // tags:
+ // callback
+ },
+
+ // =======================================================================
+ // Events from data store
+
+ onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
+ // summary:
+ // Handler for when new items appear in the store, either from a drop operation
+ // or some other way. Updates the tree view (if necessary).
+ // description:
+ // If the new item is a child of an existing item,
+ // calls onChildrenChange() with the new list of children
+ // for that existing item.
+ //
+ // tags:
+ // extension
+
+ // We only care about the new item if it has a parent that corresponds to a TreeNode
+ // we are currently displaying
+ if(!parentInfo){
+ return;
+ }
+
+ // Call onChildrenChange() on parent (ie, existing) item with new list of children
+ // In the common case, the new list of children is simply parentInfo.newValue or
+ // [ parentInfo.newValue ], although if items in the store has multiple
+ // child attributes (see `childrenAttr`), then it's a superset of parentInfo.newValue,
+ // so call getChildren() to be sure to get right answer.
+ this.getChildren(parentInfo.item, dojo.hitch(this, function(children){
+ this.onChildrenChange(parentInfo.item, children);
+ }));
+ },
+
+ onDeleteItem: function(/*Object*/ item){
+ // summary:
+ // Handler for delete notifications from underlying store
+ this.onDelete(item);
+ },
+
+ onSetItem: function(/* item */ item,
+ /* attribute-name-string */ attribute,
+ /* object | array */ oldValue,
+ /* object | array */ newValue){
+ // summary:
+ // Updates the tree view according to changes in the data store.
+ // description:
+ // Handles updates to an item's children by calling onChildrenChange(), and
+ // other updates to an item by calling onChange().
+ //
+ // See `onNewItem` for more details on handling updates to an item's children.
+ // tags:
+ // extension
+
+ if(dojo.indexOf(this.childrenAttrs, attribute) != -1){
+ // item's children list changed
+ this.getChildren(item, dojo.hitch(this, function(children){
+ // See comments in onNewItem() about calling getChildren()
+ this.onChildrenChange(item, children);
+ }));
+ }else{
+ // item's label/icon/etc. changed.
+ this.onChange(item);
+ }
+ }
+ });
+
+
+
+}
+
+if(!dojo._hasResource["dijit.tree.ForestStoreModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.tree.ForestStoreModel"] = true;
+dojo.provide("dijit.tree.ForestStoreModel");
+
+
+
+dojo.declare("dijit.tree.ForestStoreModel", dijit.tree.TreeStoreModel, {
+ // summary:
+ // Interface between Tree and a dojo.store that doesn't have a root item,
+ // i.e. has multiple "top level" items.
+ //
+ // description
+ // Use this class to wrap a dojo.store, making all the items matching the specified query
+ // appear as children of a fabricated "root item". If no query is specified then all the
+ // items returned by fetch() on the underlying store become children of the root item.
+ // It allows dijit.Tree to assume a single root item, even if the store doesn't have one.
+
+ // Parameters to constructor
+
+ // rootId: String
+ // ID of fabricated root item
+ rootId: "$root$",
+
+ // rootLabel: String
+ // Label of fabricated root item
+ rootLabel: "ROOT",
+
+ // query: String
+ // Specifies the set of children of the root item.
+ // example:
+ // | {type:'continent'}
+ query: null,
+
+ // End of parameters to constructor
+
+ constructor: function(params){
+ // summary:
+ // Sets up variables, etc.
+ // tags:
+ // private
+
+ // Make dummy root item
+ this.root = {
+ store: this,
+ root: true,
+ id: params.rootId,
+ label: params.rootLabel,
+ children: params.rootChildren // optional param
+ };
+ },
+
+ // =======================================================================
+ // Methods for traversing hierarchy
+
+ mayHaveChildren: function(/*dojo.data.Item*/ item){
+ // summary:
+ // Tells if an item has or may have children. Implementing logic here
+ // avoids showing +/- expando icon for nodes that we know don't have children.
+ // (For efficiency reasons we may not want to check if an element actually
+ // has children until user clicks the expando node)
+ // tags:
+ // extension
+ return item === this.root || this.inherited(arguments);
+ },
+
+ getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ callback, /*function*/ onError){
+ // summary:
+ // Calls onComplete() with array of child items of given parent item, all loaded.
+ if(parentItem === this.root){
+ if(this.root.children){
+ // already loaded, just return
+ callback(this.root.children);
+ }else{
+ this.store.fetch({
+ query: this.query,
+ onComplete: dojo.hitch(this, function(items){
+ this.root.children = items;
+ callback(items);
+ }),
+ onError: onError
+ });
+ }
+ }else{
+ this.inherited(arguments);
+ }
+ },
+
+ // =======================================================================
+ // Inspecting items
+
+ isItem: function(/* anything */ something){
+ return (something === this.root) ? true : this.inherited(arguments);
+ },
+
+ fetchItemByIdentity: function(/* object */ keywordArgs){
+ if(keywordArgs.identity == this.root.id){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, this.root);
+ }
+ }else{
+ this.inherited(arguments);
+ }
+ },
+
+ getIdentity: function(/* item */ item){
+ return (item === this.root) ? this.root.id : this.inherited(arguments);
+ },
+
+ getLabel: function(/* item */ item){
+ return (item === this.root) ? this.root.label : this.inherited(arguments);
+ },
+
+ // =======================================================================
+ // Write interface
+
+ newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
+ // summary:
+ // Creates a new item. See dojo.data.api.Write for details on args.
+ // Used in drag & drop when item from external source dropped onto tree.
+ if(parent === this.root){
+ this.onNewRootItem(args);
+ return this.store.newItem(args);
+ }else{
+ return this.inherited(arguments);
+ }
+ },
+
+ onNewRootItem: function(args){
+ // summary:
+ // User can override this method to modify a new element that's being
+ // added to the root of the tree, for example to add a flag like root=true
+ },
+
+ pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
+ // summary:
+ // Move or copy an item from one parent item to another.
+ // Used in drag & drop
+ if(oldParentItem === this.root){
+ if(!bCopy){
+ // It's onLeaveRoot()'s responsibility to modify the item so it no longer matches
+ // this.query... thus triggering an onChildrenChange() event to notify the Tree
+ // that this element is no longer a child of the root node
+ this.onLeaveRoot(childItem);
+ }
+ }
+ dijit.tree.TreeStoreModel.prototype.pasteItem.call(this, childItem,
+ oldParentItem === this.root ? null : oldParentItem,
+ newParentItem === this.root ? null : newParentItem,
+ bCopy,
+ insertIndex
+ );
+ if(newParentItem === this.root){
+ // It's onAddToRoot()'s responsibility to modify the item so it matches
+ // this.query... thus triggering an onChildrenChange() event to notify the Tree
+ // that this element is now a child of the root node
+ this.onAddToRoot(childItem);
+ }
+ },
+
+ // =======================================================================
+ // Handling for top level children
+
+ onAddToRoot: function(/* item */ item){
+ // summary:
+ // Called when item added to root of tree; user must override this method
+ // to modify the item so that it matches the query for top level items
+ // example:
+ // | store.setValue(item, "root", true);
+ // tags:
+ // extension
+ console.log(this, ": item ", item, " added to root");
+ },
+
+ onLeaveRoot: function(/* item */ item){
+ // summary:
+ // Called when item removed from root of tree; user must override this method
+ // to modify the item so it doesn't match the query for top level items
+ // example:
+ // | store.unsetAttribute(item, "root");
+ // tags:
+ // extension
+ console.log(this, ": item ", item, " removed from root");
+ },
+
+ // =======================================================================
+ // Events from data store
+
+ _requeryTop: function(){
+ // reruns the query for the children of the root node,
+ // sending out an onSet notification if those children have changed
+ var oldChildren = this.root.children || [];
+ this.store.fetch({
+ query: this.query,
+ onComplete: dojo.hitch(this, function(newChildren){
+ this.root.children = newChildren;
+
+ // If the list of children or the order of children has changed...
+ if(oldChildren.length != newChildren.length ||
+ dojo.some(oldChildren, function(item, idx){ return newChildren[idx] != item;})){
+ this.onChildrenChange(this.root, newChildren);
+ }
+ })
+ });
+ },
+
+ onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
+ // summary:
+ // Handler for when new items appear in the store. Developers should override this
+ // method to be more efficient based on their app/data.
+ // description:
+ // Note that the default implementation requeries the top level items every time
+ // a new item is created, since any new item could be a top level item (even in
+ // addition to being a child of another item, since items can have multiple parents).
+ //
+ // Developers can override this function to do something more efficient if they can
+ // detect which items are possible top level items (based on the item and the
+ // parentInfo parameters). Often all top level items have parentInfo==null, but
+ // that will depend on which store you use and what your data is like.
+ // tags:
+ // extension
+ this._requeryTop();
+
+ this.inherited(arguments);
+ },
+
+ onDeleteItem: function(/*Object*/ item){
+ // summary:
+ // Handler for delete notifications from underlying store
+
+ // check if this was a child of root, and if so send notification that root's children
+ // have changed
+ if(dojo.indexOf(this.root.children, item) != -1){
+ this._requeryTop();
+ }
+
+ this.inherited(arguments);
+ }
+});
+
+
+
+}
+
+if(!dojo._hasResource["dijit.Tree"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.Tree"] = true;
+dojo.provide("dijit.Tree");
+
+
+
+
+
+
+
+
+
+
+
+dojo.declare(
+ "dijit._TreeNode",
+ [dijit._Widget, dijit._Templated, dijit._Container, dijit._Contained, dijit._CssStateMixin],
+{
+ // summary:
+ // Single node within a tree. This class is used internally
+ // by Tree and should not be accessed directly.
+ // tags:
+ // private
+
+ // item: dojo.data.Item
+ // the dojo.data entry this tree represents
+ item: null,
+
+ // isTreeNode: [protected] Boolean
+ // Indicates that this is a TreeNode. Used by `dijit.Tree` only,
+ // should not be accessed directly.
+ isTreeNode: true,
+
+ // label: String
+ // Text of this tree node
+ label: "",
+
+ // isExpandable: [private] Boolean
+ // This node has children, so show the expando node (+ sign)
+ isExpandable: null,
+
+ // isExpanded: [readonly] Boolean
+ // This node is currently expanded (ie, opened)
+ isExpanded: false,
+
+ // state: [private] String
+ // Dynamic loading-related stuff.
+ // When an empty folder node appears, it is "UNCHECKED" first,
+ // then after dojo.data query it becomes "LOADING" and, finally "LOADED"
+ state: "UNCHECKED",
+
+ templateString: dojo.cache("dijit", "templates/TreeNode.html", "<div class=\"dijitTreeNode\" waiRole=\"presentation\"\n\t><div dojoAttachPoint=\"rowNode\" class=\"dijitTreeRow\" waiRole=\"presentation\" dojoAttachEvent=\"onmouseenter:_onMouseEnter, onmouseleave:_onMouseLeave, onclick:_onClick, ondblclick:_onDblClick\"\n\t\t><img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"expandoNode\" class=\"dijitTreeExpando\" waiRole=\"presentation\"\n\t\t/><span dojoAttachPoint=\"expandoNodeText\" class=\"dijitExpandoText\" waiRole=\"presentation\"\n\t\t></span\n\t\t><span dojoAttachPoint=\"contentNode\"\n\t\t\tclass=\"dijitTreeContent\" waiRole=\"presentation\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"iconNode\" class=\"dijitIcon dijitTreeIcon\" waiRole=\"presentation\"\n\t\t\t/><span dojoAttachPoint=\"labelNode\" class=\"dijitTreeLabel\" wairole=\"treeitem\" tabindex=\"-1\" waiState=\"selected-false\" dojoAttachEvent=\"onfocus:_onLabelFocus\"></span>\n\t\t</span\n\t></div>\n\t<div dojoAttachPoint=\"containerNode\" class=\"dijitTreeContainer\" waiRole=\"presentation\" style=\"display: none;\"></div>\n</div>\n"),
+
+ baseClass: "dijitTreeNode",
+
+ // For hover effect for tree node, and focus effect for label
+ cssStateNodes: {
+ rowNode: "dijitTreeRow",
+ labelNode: "dijitTreeLabel"
+ },
+
+ attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+ label: {node: "labelNode", type: "innerText"},
+ tooltip: {node: "rowNode", type: "attribute", attribute: "title"}
+ }),
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // set expand icon for leaf
+ this._setExpando();
+
+ // set icon and label class based on item
+ this._updateItemClasses(this.item);
+
+ if(this.isExpandable){
+ dijit.setWaiState(this.labelNode, "expanded", this.isExpanded);
+ }
+ },
+
+ _setIndentAttr: function(indent){
+ // summary:
+ // Tell this node how many levels it should be indented
+ // description:
+ // 0 for top level nodes, 1 for their children, 2 for their
+ // grandchildren, etc.
+ this.indent = indent;
+
+ // Math.max() is to prevent negative padding on hidden root node (when indent == -1)
+ var pixels = (Math.max(indent, 0) * this.tree._nodePixelIndent) + "px";
+
+ dojo.style(this.domNode, "backgroundPosition", pixels + " 0px");
+ dojo.style(this.rowNode, this.isLeftToRight() ? "paddingLeft" : "paddingRight", pixels);
+
+ dojo.forEach(this.getChildren(), function(child){
+ child.set("indent", indent+1);
+ });
+ },
+
+ markProcessing: function(){
+ // summary:
+ // Visually denote that tree is loading data, etc.
+ // tags:
+ // private
+ this.state = "LOADING";
+ this._setExpando(true);
+ },
+
+ unmarkProcessing: function(){
+ // summary:
+ // Clear markup from markProcessing() call
+ // tags:
+ // private
+ this._setExpando(false);
+ },
+
+ _updateItemClasses: function(item){
+ // summary:
+ // Set appropriate CSS classes for icon and label dom node
+ // (used to allow for item updates to change respective CSS)
+ // tags:
+ // private
+ var tree = this.tree, model = tree.model;
+ if(tree._v10Compat && item === model.root){
+ // For back-compat with 1.0, need to use null to specify root item (TODO: remove in 2.0)
+ item = null;
+ }
+ this._applyClassAndStyle(item, "icon", "Icon");
+ this._applyClassAndStyle(item, "label", "Label");
+ this._applyClassAndStyle(item, "row", "Row");
+ },
+
+ _applyClassAndStyle: function(item, lower, upper){
+ // summary:
+ // Set the appropriate CSS classes and styles for labels, icons and rows.
+ //
+ // item:
+ // The data item.
+ //
+ // lower:
+ // The lower case attribute to use, e.g. 'icon', 'label' or 'row'.
+ //
+ // upper:
+ // The upper case attribute to use, e.g. 'Icon', 'Label' or 'Row'.
+ //
+ // tags:
+ // private
+
+ var clsName = "_" + lower + "Class";
+ var nodeName = lower + "Node";
+
+ if(this[clsName]){
+ dojo.removeClass(this[nodeName], this[clsName]);
+ }
+ this[clsName] = this.tree["get" + upper + "Class"](item, this.isExpanded);
+ if(this[clsName]){
+ dojo.addClass(this[nodeName], this[clsName]);
+ }
+ dojo.style(this[nodeName], this.tree["get" + upper + "Style"](item, this.isExpanded) || {});
+ },
+
+ _updateLayout: function(){
+ // summary:
+ // Set appropriate CSS classes for this.domNode
+ // tags:
+ // private
+ var parent = this.getParent();
+ if(!parent || parent.rowNode.style.display == "none"){
+ /* if we are hiding the root node then make every first level child look like a root node */
+ dojo.addClass(this.domNode, "dijitTreeIsRoot");
+ }else{
+ dojo.toggleClass(this.domNode, "dijitTreeIsLast", !this.getNextSibling());
+ }
+ },
+
+ _setExpando: function(/*Boolean*/ processing){
+ // summary:
+ // Set the right image for the expando node
+ // tags:
+ // private
+
+ var styles = ["dijitTreeExpandoLoading", "dijitTreeExpandoOpened",
+ "dijitTreeExpandoClosed", "dijitTreeExpandoLeaf"],
+ _a11yStates = ["*","-","+","*"],
+ idx = processing ? 0 : (this.isExpandable ? (this.isExpanded ? 1 : 2) : 3);
+
+ // apply the appropriate class to the expando node
+ dojo.removeClass(this.expandoNode, styles);
+ dojo.addClass(this.expandoNode, styles[idx]);
+
+ // provide a non-image based indicator for images-off mode
+ this.expandoNodeText.innerHTML = _a11yStates[idx];
+
+ },
+
+ expand: function(){
+ // summary:
+ // Show my children
+ // returns:
+ // Deferred that fires when expansion is complete
+
+ // If there's already an expand in progress or we are already expanded, just return
+ if(this._expandDeferred){
+ return this._expandDeferred; // dojo.Deferred
+ }
+
+ // cancel in progress collapse operation
+ this._wipeOut && this._wipeOut.stop();
+
+ // All the state information for when a node is expanded, maybe this should be
+ // set when the animation completes instead
+ this.isExpanded = true;
+ dijit.setWaiState(this.labelNode, "expanded", "true");
+ dijit.setWaiRole(this.containerNode, "group");
+ dojo.addClass(this.contentNode,'dijitTreeContentExpanded');
+ this._setExpando();
+ this._updateItemClasses(this.item);
+ if(this == this.tree.rootNode){
+ dijit.setWaiState(this.tree.domNode, "expanded", "true");
+ }
+
+ var def,
+ wipeIn = dojo.fx.wipeIn({
+ node: this.containerNode, duration: dijit.defaultDuration,
+ onEnd: function(){
+ def.callback(true);
+ }
+ });
+
+ // Deferred that fires when expand is complete
+ def = (this._expandDeferred = new dojo.Deferred(function(){
+ // Canceller
+ wipeIn.stop();
+ }));
+
+ wipeIn.play();
+
+ return def; // dojo.Deferred
+ },
+
+ collapse: function(){
+ // summary:
+ // Collapse this node (if it's expanded)
+
+ if(!this.isExpanded){ return; }
+
+ // cancel in progress expand operation
+ if(this._expandDeferred){
+ this._expandDeferred.cancel();
+ delete this._expandDeferred;
+ }
+
+ this.isExpanded = false;
+ dijit.setWaiState(this.labelNode, "expanded", "false");
+ if(this == this.tree.rootNode){
+ dijit.setWaiState(this.tree.domNode, "expanded", "false");
+ }
+ dojo.removeClass(this.contentNode,'dijitTreeContentExpanded');
+ this._setExpando();
+ this._updateItemClasses(this.item);
+
+ if(!this._wipeOut){
+ this._wipeOut = dojo.fx.wipeOut({
+ node: this.containerNode, duration: dijit.defaultDuration
+ });
+ }
+ this._wipeOut.play();
+ },
+
+ // indent: Integer
+ // Levels from this node to the root node
+ indent: 0,
+
+ setChildItems: function(/* Object[] */ items){
+ // summary:
+ // Sets the child items of this node, removing/adding nodes
+ // from current children to match specified items[] array.
+ // Also, if this.persist == true, expands any children that were previously
+ // opened.
+ // returns:
+ // Deferred object that fires after all previously opened children
+ // have been expanded again (or fires instantly if there are no such children).
+
+ var tree = this.tree,
+ model = tree.model,
+ defs = []; // list of deferreds that need to fire before I am complete
+
+
+ // Orphan all my existing children.
+ // If items contains some of the same items as before then we will reattach them.
+ // Don't call this.removeChild() because that will collapse the tree etc.
+ dojo.forEach(this.getChildren(), function(child){
+ dijit._Container.prototype.removeChild.call(this, child);
+ }, this);
+
+ this.state = "LOADED";
+
+ if(items && items.length > 0){
+ this.isExpandable = true;
+
+ // Create _TreeNode widget for each specified tree node, unless one already
+ // exists and isn't being used (presumably it's from a DnD move and was recently
+ // released
+ dojo.forEach(items, function(item){
+ var id = model.getIdentity(item),
+ existingNodes = tree._itemNodesMap[id],
+ node;
+ if(existingNodes){
+ for(var i=0;i<existingNodes.length;i++){
+ if(existingNodes[i] && !existingNodes[i].getParent()){
+ node = existingNodes[i];
+ node.set('indent', this.indent+1);
+ break;
+ }
+ }
+ }
+ if(!node){
+ node = this.tree._createTreeNode({
+ item: item,
+ tree: tree,
+ isExpandable: model.mayHaveChildren(item),
+ label: tree.getLabel(item),
+ tooltip: tree.getTooltip(item),
+ dir: tree.dir,
+ lang: tree.lang,
+ indent: this.indent + 1
+ });
+ if(existingNodes){
+ existingNodes.push(node);
+ }else{
+ tree._itemNodesMap[id] = [node];
+ }
+ }
+ this.addChild(node);
+
+ // If node was previously opened then open it again now (this may trigger
+ // more data store accesses, recursively)
+ if(this.tree.autoExpand || this.tree._state(item)){
+ defs.push(tree._expandNode(node));
+ }
+ }, this);
+
+ // note that updateLayout() needs to be called on each child after
+ // _all_ the children exist
+ dojo.forEach(this.getChildren(), function(child, idx){
+ child._updateLayout();
+ });
+ }else{
+ this.isExpandable=false;
+ }
+
+ if(this._setExpando){
+ // change expando to/from dot or + icon, as appropriate
+ this._setExpando(false);
+ }
+
+ // Set leaf icon or folder icon, as appropriate
+ this._updateItemClasses(this.item);
+
+ // On initial tree show, make the selected TreeNode as either the root node of the tree,
+ // or the first child, if the root node is hidden
+ if(this == tree.rootNode){
+ var fc = this.tree.showRoot ? this : this.getChildren()[0];
+ if(fc){
+ fc.setFocusable(true);
+ tree.lastFocused = fc;
+ }else{
+ // fallback: no nodes in tree so focus on Tree <div> itself
+ tree.domNode.setAttribute("tabIndex", "0");
+ }
+ }
+
+ return new dojo.DeferredList(defs); // dojo.Deferred
+ },
+
+ removeChild: function(/* treeNode */ node){
+ this.inherited(arguments);
+
+ var children = this.getChildren();
+ if(children.length == 0){
+ this.isExpandable = false;
+ this.collapse();
+ }
+
+ dojo.forEach(children, function(child){
+ child._updateLayout();
+ });
+ },
+
+ makeExpandable: function(){
+ // summary:
+ // if this node wasn't already showing the expando node,
+ // turn it into one and call _setExpando()
+
+ // TODO: hmm this isn't called from anywhere, maybe should remove it for 2.0
+
+ this.isExpandable = true;
+ this._setExpando(false);
+ },
+
+ _onLabelFocus: function(evt){
+ // summary:
+ // Called when this row is focused (possibly programatically)
+ // Note that we aren't using _onFocus() builtin to dijit
+ // because it's called when focus is moved to a descendant TreeNode.
+ // tags:
+ // private
+ this.tree._onNodeFocus(this);
+ },
+
+ setSelected: function(/*Boolean*/ selected){
+ // summary:
+ // A Tree has a (single) currently selected node.
+ // Mark that this node is/isn't that currently selected node.
+ // description:
+ // In particular, setting a node as selected involves setting tabIndex
+ // so that when user tabs to the tree, focus will go to that node (only).
+ dijit.setWaiState(this.labelNode, "selected", selected);
+ dojo.toggleClass(this.rowNode, "dijitTreeRowSelected", selected);
+ },
+
+ setFocusable: function(/*Boolean*/ selected){
+ // summary:
+ // A Tree has a (single) node that's focusable.
+ // Mark that this node is/isn't that currently focsuable node.
+ // description:
+ // In particular, setting a node as selected involves setting tabIndex
+ // so that when user tabs to the tree, focus will go to that node (only).
+
+ this.labelNode.setAttribute("tabIndex", selected ? "0" : "-1");
+ },
+
+ _onClick: function(evt){
+ // summary:
+ // Handler for onclick event on a node
+ // tags:
+ // private
+ this.tree._onClick(this, evt);
+ },
+ _onDblClick: function(evt){
+ // summary:
+ // Handler for ondblclick event on a node
+ // tags:
+ // private
+ this.tree._onDblClick(this, evt);
+ },
+
+ _onMouseEnter: function(evt){
+ // summary:
+ // Handler for onmouseenter event on a node
+ // tags:
+ // private
+ this.tree._onNodeMouseEnter(this, evt);
+ },
+
+ _onMouseLeave: function(evt){
+ // summary:
+ // Handler for onmouseenter event on a node
+ // tags:
+ // private
+ this.tree._onNodeMouseLeave(this, evt);
+ }
+});
+
+dojo.declare(
+ "dijit.Tree",
+ [dijit._Widget, dijit._Templated],
+{
+ // summary:
+ // This widget displays hierarchical data from a store.
+
+ // store: [deprecated] String||dojo.data.Store
+ // Deprecated. Use "model" parameter instead.
+ // The store to get data to display in the tree.
+ store: null,
+
+ // model: dijit.Tree.model
+ // Interface to read tree data, get notifications of changes to tree data,
+ // and for handling drop operations (i.e drag and drop onto the tree)
+ model: null,
+
+ // query: [deprecated] anything
+ // Deprecated. User should specify query to the model directly instead.
+ // Specifies datastore query to return the root item or top items for the tree.
+ query: null,
+
+ // label: [deprecated] String
+ // Deprecated. Use dijit.tree.ForestStoreModel directly instead.
+ // Used in conjunction with query parameter.
+ // If a query is specified (rather than a root node id), and a label is also specified,
+ // then a fake root node is created and displayed, with this label.
+ label: "",
+
+ // showRoot: [const] Boolean
+ // Should the root node be displayed, or hidden?
+ showRoot: true,
+
+ // childrenAttr: [deprecated] String[]
+ // Deprecated. This information should be specified in the model.
+ // One ore more attributes that holds children of a tree node
+ childrenAttr: ["children"],
+
+ // path: String[] or Item[]
+ // Full path from rootNode to selected node expressed as array of items or array of ids.
+ // Since setting the path may be asynchronous (because ofwaiting on dojo.data), set("path", ...)
+ // returns a Deferred to indicate when the set is complete.
+ path: [],
+
+ // selectedItem: [readonly] Item
+ // The currently selected item in this tree.
+ // This property can only be set (via set('selectedItem', ...)) when that item is already
+ // visible in the tree. (I.e. the tree has already been expanded to show that node.)
+ // Should generally use `path` attribute to set the selected item instead.
+ selectedItem: null,
+
+ // openOnClick: Boolean
+ // If true, clicking a folder node's label will open it, rather than calling onClick()
+ openOnClick: false,
+
+ // openOnDblClick: Boolean
+ // If true, double-clicking a folder node's label will open it, rather than calling onDblClick()
+ openOnDblClick: false,
+
+ templateString: dojo.cache("dijit", "templates/Tree.html", "<div class=\"dijitTree dijitTreeContainer\" waiRole=\"tree\"\n\tdojoAttachEvent=\"onkeypress:_onKeyPress\">\n\t<div class=\"dijitInline dijitTreeIndent\" style=\"position: absolute; top: -9999px\" dojoAttachPoint=\"indentDetector\"></div>\n</div>\n"),
+
+ // persist: Boolean
+ // Enables/disables use of cookies for state saving.
+ persist: true,
+
+ // autoExpand: Boolean
+ // Fully expand the tree on load. Overrides `persist`
+ autoExpand: false,
+
+ // dndController: [protected] String
+ // Class name to use as as the dnd controller. Specifying this class enables DnD.
+ // Generally you should specify this as "dijit.tree.dndSource".
+ dndController: null,
+
+ // parameters to pull off of the tree and pass on to the dndController as its params
+ dndParams: ["onDndDrop","itemCreator","onDndCancel","checkAcceptance", "checkItemAcceptance", "dragThreshold", "betweenThreshold"],
+
+ //declare the above items so they can be pulled from the tree's markup
+
+ // onDndDrop: [protected] Function
+ // Parameter to dndController, see `dijit.tree.dndSource.onDndDrop`.
+ // Generally this doesn't need to be set.
+ onDndDrop: null,
+
+ /*=====
+ itemCreator: function(nodes, target, source){
+ // summary:
+ // Returns objects passed to `Tree.model.newItem()` based on DnD nodes
+ // dropped onto the tree. Developer must override this method to enable
+ // dropping from external sources onto this Tree, unless the Tree.model's items
+ // happen to look like {id: 123, name: "Apple" } with no other attributes.
+ // description:
+ // For each node in nodes[], which came from source, create a hash of name/value
+ // pairs to be passed to Tree.model.newItem(). Returns array of those hashes.
+ // nodes: DomNode[]
+ // The DOMNodes dragged from the source container
+ // target: DomNode
+ // The target TreeNode.rowNode
+ // source: dojo.dnd.Source
+ // The source container the nodes were dragged from, perhaps another Tree or a plain dojo.dnd.Source
+ // returns: Object[]
+ // Array of name/value hashes for each new item to be added to the Tree, like:
+ // | [
+ // | { id: 123, label: "apple", foo: "bar" },
+ // | { id: 456, label: "pear", zaz: "bam" }
+ // | ]
+ // tags:
+ // extension
+ return [{}];
+ },
+ =====*/
+ itemCreator: null,
+
+ // onDndCancel: [protected] Function
+ // Parameter to dndController, see `dijit.tree.dndSource.onDndCancel`.
+ // Generally this doesn't need to be set.
+ onDndCancel: null,
+
+/*=====
+ checkAcceptance: function(source, nodes){
+ // summary:
+ // Checks if the Tree itself can accept nodes from this source
+ // source: dijit.tree._dndSource
+ // The source which provides items
+ // nodes: DOMNode[]
+ // Array of DOM nodes corresponding to nodes being dropped, dijitTreeRow nodes if
+ // source is a dijit.Tree.
+ // tags:
+ // extension
+ return true; // Boolean
+ },
+=====*/
+ checkAcceptance: null,
+
+/*=====
+ checkItemAcceptance: function(target, source, position){
+ // summary:
+ // Stub function to be overridden if one wants to check for the ability to drop at the node/item level
+ // description:
+ // In the base case, this is called to check if target can become a child of source.
+ // When betweenThreshold is set, position="before" or "after" means that we
+ // are asking if the source node can be dropped before/after the target node.
+ // target: DOMNode
+ // The dijitTreeRoot DOM node inside of the TreeNode that we are dropping on to
+ // Use dijit.getEnclosingWidget(target) to get the TreeNode.
+ // source: dijit.tree.dndSource
+ // The (set of) nodes we are dropping
+ // position: String
+ // "over", "before", or "after"
+ // tags:
+ // extension
+ return true; // Boolean
+ },
+=====*/
+ checkItemAcceptance: null,
+
+ // dragThreshold: Integer
+ // Number of pixels mouse moves before it's considered the start of a drag operation
+ dragThreshold: 5,
+
+ // betweenThreshold: Integer
+ // Set to a positive value to allow drag and drop "between" nodes.
+ //
+ // If during DnD mouse is over a (target) node but less than betweenThreshold
+ // pixels from the bottom edge, dropping the the dragged node will make it
+ // the next sibling of the target node, rather than the child.
+ //
+ // Similarly, if mouse is over a target node but less that betweenThreshold
+ // pixels from the top edge, dropping the dragged node will make it
+ // the target node's previous sibling rather than the target node's child.
+ betweenThreshold: 0,
+
+ // _nodePixelIndent: Integer
+ // Number of pixels to indent tree nodes (relative to parent node).
+ // Default is 19 but can be overridden by setting CSS class dijitTreeIndent
+ // and calling resize() or startup() on tree after it's in the DOM.
+ _nodePixelIndent: 19,
+
+ _publish: function(/*String*/ topicName, /*Object*/ message){
+ // summary:
+ // Publish a message for this widget/topic
+ dojo.publish(this.id, [dojo.mixin({tree: this, event: topicName}, message || {})]);
+ },
+
+ postMixInProperties: function(){
+ this.tree = this;
+
+ if(this.autoExpand){
+ // There's little point in saving opened/closed state of nodes for a Tree
+ // that initially opens all it's nodes.
+ this.persist = false;
+ }
+
+ this._itemNodesMap={};
+
+ if(!this.cookieName){
+ this.cookieName = this.id + "SaveStateCookie";
+ }
+
+ this._loadDeferred = new dojo.Deferred();
+
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ this._initState();
+
+ // Create glue between store and Tree, if not specified directly by user
+ if(!this.model){
+ this._store2model();
+ }
+
+ // monitor changes to items
+ this.connect(this.model, "onChange", "_onItemChange");
+ this.connect(this.model, "onChildrenChange", "_onItemChildrenChange");
+ this.connect(this.model, "onDelete", "_onItemDelete");
+
+ this._load();
+
+ this.inherited(arguments);
+
+ if(this.dndController){
+ if(dojo.isString(this.dndController)){
+ this.dndController = dojo.getObject(this.dndController);
+ }
+ var params={};
+ for(var i=0; i<this.dndParams.length;i++){
+ if(this[this.dndParams[i]]){
+ params[this.dndParams[i]] = this[this.dndParams[i]];
+ }
+ }
+ this.dndController = new this.dndController(this, params);
+ }
+ },
+
+ _store2model: function(){
+ // summary:
+ // User specified a store&query rather than model, so create model from store/query
+ this._v10Compat = true;
+ dojo.deprecated("Tree: from version 2.0, should specify a model object rather than a store/query");
+
+ var modelParams = {
+ id: this.id + "_ForestStoreModel",
+ store: this.store,
+ query: this.query,
+ childrenAttrs: this.childrenAttr
+ };
+
+ // Only override the model's mayHaveChildren() method if the user has specified an override
+ if(this.params.mayHaveChildren){
+ modelParams.mayHaveChildren = dojo.hitch(this, "mayHaveChildren");
+ }
+
+ if(this.params.getItemChildren){
+ modelParams.getChildren = dojo.hitch(this, function(item, onComplete, onError){
+ this.getItemChildren((this._v10Compat && item === this.model.root) ? null : item, onComplete, onError);
+ });
+ }
+ this.model = new dijit.tree.ForestStoreModel(modelParams);
+
+ // For backwards compatibility, the visibility of the root node is controlled by
+ // whether or not the user has specified a label
+ this.showRoot = Boolean(this.label);
+ },
+
+ onLoad: function(){
+ // summary:
+ // Called when tree finishes loading and expanding.
+ // description:
+ // If persist == true the loading may encompass many levels of fetches
+ // from the data store, each asynchronous. Waits for all to finish.
+ // tags:
+ // callback
+ },
+
+ _load: function(){
+ // summary:
+ // Initial load of the tree.
+ // Load root node (possibly hidden) and it's children.
+ this.model.getRoot(
+ dojo.hitch(this, function(item){
+ var rn = (this.rootNode = this.tree._createTreeNode({
+ item: item,
+ tree: this,
+ isExpandable: true,
+ label: this.label || this.getLabel(item),
+ indent: this.showRoot ? 0 : -1
+ }));
+ if(!this.showRoot){
+ rn.rowNode.style.display="none";
+ }
+ this.domNode.appendChild(rn.domNode);
+ var identity = this.model.getIdentity(item);
+ if(this._itemNodesMap[identity]){
+ this._itemNodesMap[identity].push(rn);
+ }else{
+ this._itemNodesMap[identity] = [rn];
+ }
+
+ rn._updateLayout(); // sets "dijitTreeIsRoot" CSS classname
+
+ // load top level children and then fire onLoad() event
+ this._expandNode(rn).addCallback(dojo.hitch(this, function(){
+ this._loadDeferred.callback(true);
+ this.onLoad();
+ }));
+ }),
+ function(err){
+ console.error(this, ": error loading root: ", err);
+ }
+ );
+ },
+
+ getNodesByItem: function(/*dojo.data.Item or id*/ item){
+ // summary:
+ // Returns all tree nodes that refer to an item
+ // returns:
+ // Array of tree nodes that refer to passed item
+
+ if(!item){ return []; }
+ var identity = dojo.isString(item) ? item : this.model.getIdentity(item);
+ // return a copy so widget don't get messed up by changes to returned array
+ return [].concat(this._itemNodesMap[identity]);
+ },
+
+ _setSelectedItemAttr: function(/*dojo.data.Item or id*/ item){
+ // summary:
+ // Select a tree node related to passed item.
+ // WARNING: if model use multi-parented items or desired tree node isn't already loaded
+ // behavior is undefined. Use set('path', ...) instead.
+
+ var oldValue = this.get("selectedItem");
+ var identity = (!item || dojo.isString(item)) ? item : this.model.getIdentity(item);
+ if(identity == oldValue ? this.model.getIdentity(oldValue) : null){ return; }
+ var nodes = this._itemNodesMap[identity];
+ this._selectNode((nodes && nodes[0]) || null); //select the first item
+ },
+
+ _getSelectedItemAttr: function(){
+ // summary:
+ // Return item related to selected tree node.
+ return this.selectedNode && this.selectedNode.item;
+ },
+
+ _setPathAttr: function(/*Item[] || String[]*/ path){
+ // summary:
+ // Select the tree node identified by passed path.
+ // path:
+ // Array of items or item id's
+ // returns:
+ // Deferred to indicate when the set is complete
+
+ var d = new dojo.Deferred();
+
+ this._selectNode(null);
+ if(!path || !path.length){
+ d.resolve(true);
+ return d;
+ }
+
+ // If this is called during initialization, defer running until Tree has finished loading
+ this._loadDeferred.addCallback(dojo.hitch(this, function(){
+ if(!this.rootNode){
+ d.reject(new Error("!this.rootNode"));
+ return;
+ }
+ if(path[0] !== this.rootNode.item && (dojo.isString(path[0]) && path[0] != this.model.getIdentity(this.rootNode.item))){
+ d.reject(new Error(this.id + ":path[0] doesn't match this.rootNode.item. Maybe you are using the wrong tree."));
+ return;
+ }
+ path.shift();
+
+ var node = this.rootNode;
+
+ function advance(){
+ // summary:
+ // Called when "node" has completed loading and expanding. Pop the next item from the path
+ // (which must be a child of "node") and advance to it, and then recurse.
+
+ // Set item and identity to next item in path (node is pointing to the item that was popped
+ // from the path _last_ time.
+ var item = path.shift(),
+ identity = dojo.isString(item) ? item : this.model.getIdentity(item);
+
+ // Change "node" from previous item in path to the item we just popped from path
+ dojo.some(this._itemNodesMap[identity], function(n){
+ if(n.getParent() == node){
+ node = n;
+ return true;
+ }
+ return false;
+ });
+
+ if(path.length){
+ // Need to do more expanding
+ this._expandNode(node).addCallback(dojo.hitch(this, advance));
+ }else{
+ // Final destination node, select it
+ this._selectNode(node);
+
+ // signal that path setting is finished
+ d.resolve(true);
+ }
+ }
+
+ this._expandNode(node).addCallback(dojo.hitch(this, advance));
+ }));
+
+ return d;
+ },
+
+ _getPathAttr: function(){
+ // summary:
+ // Return an array of items that is the path to selected tree node.
+ if(!this.selectedNode){ return; }
+ var res = [];
+ var treeNode = this.selectedNode;
+ while(treeNode && treeNode !== this.rootNode){
+ res.unshift(treeNode.item);
+ treeNode = treeNode.getParent();
+ }
+ res.unshift(this.rootNode.item);
+ return res;
+ },
+
+ ////////////// Data store related functions //////////////////////
+ // These just get passed to the model; they are here for back-compat
+
+ mayHaveChildren: function(/*dojo.data.Item*/ item){
+ // summary:
+ // Deprecated. This should be specified on the model itself.
+ //
+ // Overridable function to tell if an item has or may have children.
+ // Controls whether or not +/- expando icon is shown.
+ // (For efficiency reasons we may not want to check if an element actually
+ // has children until user clicks the expando node)
+ // tags:
+ // deprecated
+ },
+
+ getItemChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete){
+ // summary:
+ // Deprecated. This should be specified on the model itself.
+ //
+ // Overridable function that return array of child items of given parent item,
+ // or if parentItem==null then return top items in tree
+ // tags:
+ // deprecated
+ },
+
+ ///////////////////////////////////////////////////////
+ // Functions for converting an item to a TreeNode
+ getLabel: function(/*dojo.data.Item*/ item){
+ // summary:
+ // Overridable function to get the label for a tree node (given the item)
+ // tags:
+ // extension
+ return this.model.getLabel(item); // String
+ },
+
+ getIconClass: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
+ // summary:
+ // Overridable function to return CSS class name to display icon
+ // tags:
+ // extension
+ return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "dijitLeaf"
+ },
+
+ getLabelClass: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
+ // summary:
+ // Overridable function to return CSS class name to display label
+ // tags:
+ // extension
+ },
+
+ getRowClass: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
+ // summary:
+ // Overridable function to return CSS class name to display row
+ // tags:
+ // extension
+ },
+
+ getIconStyle: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
+ // summary:
+ // Overridable function to return CSS styles to display icon
+ // returns:
+ // Object suitable for input to dojo.style() like {backgroundImage: "url(...)"}
+ // tags:
+ // extension
+ },
+
+ getLabelStyle: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
+ // summary:
+ // Overridable function to return CSS styles to display label
+ // returns:
+ // Object suitable for input to dojo.style() like {color: "red", background: "green"}
+ // tags:
+ // extension
+ },
+
+ getRowStyle: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
+ // summary:
+ // Overridable function to return CSS styles to display row
+ // returns:
+ // Object suitable for input to dojo.style() like {background-color: "#bbb"}
+ // tags:
+ // extension
+ },
+
+ getTooltip: function(/*dojo.data.Item*/ item){
+ // summary:
+ // Overridable function to get the tooltip for a tree node (given the item)
+ // tags:
+ // extension
+ return ""; // String
+ },
+
+ /////////// Keyboard and Mouse handlers ////////////////////
+
+ _onKeyPress: function(/*Event*/ e){
+ // summary:
+ // Translates keypress events into commands for the controller
+ if(e.altKey){ return; }
+ var dk = dojo.keys;
+ var treeNode = dijit.getEnclosingWidget(e.target);
+ if(!treeNode){ return; }
+
+ var key = e.charOrCode;
+ if(typeof key == "string"){ // handle printables (letter navigation)
+ // Check for key navigation.
+ if(!e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey){
+ this._onLetterKeyNav( { node: treeNode, key: key.toLowerCase() } );
+ dojo.stopEvent(e);
+ }
+ }else{ // handle non-printables (arrow keys)
+ // clear record of recent printables (being saved for multi-char letter navigation),
+ // because "a", down-arrow, "b" shouldn't search for "ab"
+ if(this._curSearch){
+ clearTimeout(this._curSearch.timer);
+ delete this._curSearch;
+ }
+
+ var map = this._keyHandlerMap;
+ if(!map){
+ // setup table mapping keys to events
+ map = {};
+ map[dk.ENTER]="_onEnterKey";
+ map[this.isLeftToRight() ? dk.LEFT_ARROW : dk.RIGHT_ARROW]="_onLeftArrow";
+ map[this.isLeftToRight() ? dk.RIGHT_ARROW : dk.LEFT_ARROW]="_onRightArrow";
+ map[dk.UP_ARROW]="_onUpArrow";
+ map[dk.DOWN_ARROW]="_onDownArrow";
+ map[dk.HOME]="_onHomeKey";
+ map[dk.END]="_onEndKey";
+ this._keyHandlerMap = map;
+ }
+ if(this._keyHandlerMap[key]){
+ this[this._keyHandlerMap[key]]( { node: treeNode, item: treeNode.item, evt: e } );
+ dojo.stopEvent(e);
+ }
+ }
+ },
+
+ _onEnterKey: function(/*Object*/ message, /*Event*/ evt){
+ this._publish("execute", { item: message.item, node: message.node } );
+ this._selectNode(message.node);
+ this.onClick(message.item, message.node, evt);
+ },
+
+ _onDownArrow: function(/*Object*/ message){
+ // summary:
+ // down arrow pressed; get next visible node, set focus there
+ var node = this._getNextNode(message.node);
+ if(node && node.isTreeNode){
+ this.focusNode(node);
+ }
+ },
+
+ _onUpArrow: function(/*Object*/ message){
+ // summary:
+ // Up arrow pressed; move to previous visible node
+
+ var node = message.node;
+
+ // if younger siblings
+ var previousSibling = node.getPreviousSibling();
+ if(previousSibling){
+ node = previousSibling;
+ // if the previous node is expanded, dive in deep
+ while(node.isExpandable && node.isExpanded && node.hasChildren()){
+ // move to the last child
+ var children = node.getChildren();
+ node = children[children.length-1];
+ }
+ }else{
+ // if this is the first child, return the parent
+ // unless the parent is the root of a tree with a hidden root
+ var parent = node.getParent();
+ if(!(!this.showRoot && parent === this.rootNode)){
+ node = parent;
+ }
+ }
+
+ if(node && node.isTreeNode){
+ this.focusNode(node);
+ }
+ },
+
+ _onRightArrow: function(/*Object*/ message){
+ // summary:
+ // Right arrow pressed; go to child node
+ var node = message.node;
+
+ // if not expanded, expand, else move to 1st child
+ if(node.isExpandable && !node.isExpanded){
+ this._expandNode(node);
+ }else if(node.hasChildren()){
+ node = node.getChildren()[0];
+ if(node && node.isTreeNode){
+ this.focusNode(node);
+ }
+ }
+ },
+
+ _onLeftArrow: function(/*Object*/ message){
+ // summary:
+ // Left arrow pressed.
+ // If not collapsed, collapse, else move to parent.
+
+ var node = message.node;
+
+ if(node.isExpandable && node.isExpanded){
+ this._collapseNode(node);
+ }else{
+ var parent = node.getParent();
+ if(parent && parent.isTreeNode && !(!this.showRoot && parent === this.rootNode)){
+ this.focusNode(parent);
+ }
+ }
+ },
+
+ _onHomeKey: function(){
+ // summary:
+ // Home key pressed; get first visible node, and set focus there
+ var node = this._getRootOrFirstNode();
+ if(node){
+ this.focusNode(node);
+ }
+ },
+
+ _onEndKey: function(/*Object*/ message){
+ // summary:
+ // End key pressed; go to last visible node.
+
+ var node = this.rootNode;
+ while(node.isExpanded){
+ var c = node.getChildren();
+ node = c[c.length - 1];
+ }
+
+ if(node && node.isTreeNode){
+ this.focusNode(node);
+ }
+ },
+
+ // multiCharSearchDuration: Number
+ // If multiple characters are typed where each keystroke happens within
+ // multiCharSearchDuration of the previous keystroke,
+ // search for nodes matching all the keystrokes.
+ //
+ // For example, typing "ab" will search for entries starting with
+ // "ab" unless the delay between "a" and "b" is greater than multiCharSearchDuration.
+ multiCharSearchDuration: 250,
+
+ _onLetterKeyNav: function(message){
+ // summary:
+ // Called when user presses a prinatable key; search for node starting with recently typed letters.
+ // message: Object
+ // Like { node: TreeNode, key: 'a' } where key is the key the user pressed.
+
+ // Branch depending on whether this key starts a new search, or modifies an existing search
+ var cs = this._curSearch;
+ if(cs){
+ // We are continuing a search. Ex: user has pressed 'a', and now has pressed
+ // 'b', so we want to search for nodes starting w/"ab".
+ cs.pattern = cs.pattern + message.key;
+ clearTimeout(cs.timer);
+ }else{
+ // We are starting a new search
+ cs = this._curSearch = {
+ pattern: message.key,
+ startNode: message.node
+ };
+ }
+
+ // set/reset timer to forget recent keystrokes
+ var self = this;
+ cs.timer = setTimeout(function(){
+ delete self._curSearch;
+ }, this.multiCharSearchDuration);
+
+ // Navigate to TreeNode matching keystrokes [entered so far].
+ var node = cs.startNode;
+ do{
+ node = this._getNextNode(node);
+ //check for last node, jump to first node if necessary
+ if(!node){
+ node = this._getRootOrFirstNode();
+ }
+ }while(node !== cs.startNode && (node.label.toLowerCase().substr(0, cs.pattern.length) != cs.pattern));
+ if(node && node.isTreeNode){
+ // no need to set focus if back where we started
+ if(node !== cs.startNode){
+ this.focusNode(node);
+ }
+ }
+ },
+
+ _onClick: function(/*TreeNode*/ nodeWidget, /*Event*/ e){
+ // summary:
+ // Translates click events into commands for the controller to process
+
+ var domElement = e.target,
+ isExpandoClick = (domElement == nodeWidget.expandoNode || domElement == nodeWidget.expandoNodeText);
+
+ if( (this.openOnClick && nodeWidget.isExpandable) || isExpandoClick ){
+ // expando node was clicked, or label of a folder node was clicked; open it
+ if(nodeWidget.isExpandable){
+ this._onExpandoClick({node:nodeWidget});
+ }
+ }else{
+ this._publish("execute", { item: nodeWidget.item, node: nodeWidget, evt: e } );
+ this.onClick(nodeWidget.item, nodeWidget, e);
+ this.focusNode(nodeWidget);
+ }
+ if(!isExpandoClick){
+ this._selectNode(nodeWidget);
+ }
+ dojo.stopEvent(e);
+ },
+ _onDblClick: function(/*TreeNode*/ nodeWidget, /*Event*/ e){
+ // summary:
+ // Translates double-click events into commands for the controller to process
+
+ var domElement = e.target,
+ isExpandoClick = (domElement == nodeWidget.expandoNode || domElement == nodeWidget.expandoNodeText);
+
+ if( (this.openOnDblClick && nodeWidget.isExpandable) ||isExpandoClick ){
+ // expando node was clicked, or label of a folder node was clicked; open it
+ if(nodeWidget.isExpandable){
+ this._onExpandoClick({node:nodeWidget});
+ }
+ }else{
+ this._publish("execute", { item: nodeWidget.item, node: nodeWidget, evt: e } );
+ this.onDblClick(nodeWidget.item, nodeWidget, e);
+ this.focusNode(nodeWidget);
+ }
+ if(!isExpandoClick){
+ this._selectNode(nodeWidget);
+ }
+ dojo.stopEvent(e);
+ },
+
+ _onExpandoClick: function(/*Object*/ message){
+ // summary:
+ // User clicked the +/- icon; expand or collapse my children.
+ var node = message.node;
+
+ // If we are collapsing, we might be hiding the currently focused node.
+ // Also, clicking the expando node might have erased focus from the current node.
+ // For simplicity's sake just focus on the node with the expando.
+ this.focusNode(node);
+
+ if(node.isExpanded){
+ this._collapseNode(node);
+ }else{
+ this._expandNode(node);
+ }
+ },
+
+ onClick: function(/* dojo.data */ item, /*TreeNode*/ node, /*Event*/ evt){
+ // summary:
+ // Callback when a tree node is clicked
+ // tags:
+ // callback
+ },
+ onDblClick: function(/* dojo.data */ item, /*TreeNode*/ node, /*Event*/ evt){
+ // summary:
+ // Callback when a tree node is double-clicked
+ // tags:
+ // callback
+ },
+ onOpen: function(/* dojo.data */ item, /*TreeNode*/ node){
+ // summary:
+ // Callback when a node is opened
+ // tags:
+ // callback
+ },
+ onClose: function(/* dojo.data */ item, /*TreeNode*/ node){
+ // summary:
+ // Callback when a node is closed
+ // tags:
+ // callback
+ },
+
+ _getNextNode: function(node){
+ // summary:
+ // Get next visible node
+
+ if(node.isExpandable && node.isExpanded && node.hasChildren()){
+ // if this is an expanded node, get the first child
+ return node.getChildren()[0]; // _TreeNode
+ }else{
+ // find a parent node with a sibling
+ while(node && node.isTreeNode){
+ var returnNode = node.getNextSibling();
+ if(returnNode){
+ return returnNode; // _TreeNode
+ }
+ node = node.getParent();
+ }
+ return null;
+ }
+ },
+
+ _getRootOrFirstNode: function(){
+ // summary:
+ // Get first visible node
+ return this.showRoot ? this.rootNode : this.rootNode.getChildren()[0];
+ },
+
+ _collapseNode: function(/*_TreeNode*/ node){
+ // summary:
+ // Called when the user has requested to collapse the node
+
+ if(node._expandNodeDeferred){
+ delete node._expandNodeDeferred;
+ }
+
+ if(node.isExpandable){
+ if(node.state == "LOADING"){
+ // ignore clicks while we are in the process of loading data
+ return;
+ }
+
+ node.collapse();
+ this.onClose(node.item, node);
+
+ if(node.item){
+ this._state(node.item,false);
+ this._saveState();
+ }
+ }
+ },
+
+ _expandNode: function(/*_TreeNode*/ node, /*Boolean?*/ recursive){
+ // summary:
+ // Called when the user has requested to expand the node
+ // recursive:
+ // Internal flag used when _expandNode() calls itself, don't set.
+ // returns:
+ // Deferred that fires when the node is loaded and opened and (if persist=true) all it's descendants
+ // that were previously opened too
+
+ if(node._expandNodeDeferred && !recursive){
+ // there's already an expand in progress (or completed), so just return
+ return node._expandNodeDeferred; // dojo.Deferred
+ }
+
+ var model = this.model,
+ item = node.item,
+ _this = this;
+
+ switch(node.state){
+ case "UNCHECKED":
+ // need to load all the children, and then expand
+ node.markProcessing();
+
+ // Setup deferred to signal when the load and expand are finished.
+ // Save that deferred in this._expandDeferred as a flag that operation is in progress.
+ var def = (node._expandNodeDeferred = new dojo.Deferred());
+
+ // Get the children
+ model.getChildren(
+ item,
+ function(items){
+ node.unmarkProcessing();
+
+ // Display the children and also start expanding any children that were previously expanded
+ // (if this.persist == true). The returned Deferred will fire when those expansions finish.
+ var scid = node.setChildItems(items);
+
+ // Call _expandNode() again but this time it will just to do the animation (default branch).
+ // The returned Deferred will fire when the animation completes.
+ // TODO: seems like I can avoid recursion and just use a deferred to sequence the events?
+ var ed = _this._expandNode(node, true);
+
+ // After the above two tasks (setChildItems() and recursive _expandNode()) finish,
+ // signal that I am done.
+ scid.addCallback(function(){
+ ed.addCallback(function(){
+ def.callback();
+ })
+ });
+ },
+ function(err){
+ console.error(_this, ": error loading root children: ", err);
+ }
+ );
+ break;
+
+ default: // "LOADED"
+ // data is already loaded; just expand node
+ def = (node._expandNodeDeferred = node.expand());
+
+ this.onOpen(node.item, node);
+
+ if(item){
+ this._state(item, true);
+ this._saveState();
+ }
+ }
+
+ return def; // dojo.Deferred
+ },
+
+ ////////////////// Miscellaneous functions ////////////////
+
+ focusNode: function(/* _tree.Node */ node){
+ // summary:
+ // Focus on the specified node (which must be visible)
+ // tags:
+ // protected
+
+ // set focus so that the label will be voiced using screen readers
+ dijit.focus(node.labelNode);
+ },
+
+ _selectNode: function(/*_tree.Node*/ node){
+ // summary:
+ // Mark specified node as select, and unmark currently selected node.
+ // tags:
+ // protected
+
+ if(this.selectedNode && !this.selectedNode._destroyed){
+ this.selectedNode.setSelected(false);
+ }
+ if(node){
+ node.setSelected(true);
+ }
+ this.selectedNode = node;
+ },
+
+ _onNodeFocus: function(/*dijit._Widget*/ node){
+ // summary:
+ // Called when a TreeNode gets focus, either by user clicking
+ // it, or programatically by arrow key handling code.
+ // description:
+ // It marks that the current node is the selected one, and the previously
+ // selected node no longer is.
+
+ if(node && node != this.lastFocused){
+ if(this.lastFocused && !this.lastFocused._destroyed){
+ // mark that the previously focsable node is no longer focusable
+ this.lastFocused.setFocusable(false);
+ }
+
+ // mark that the new node is the currently selected one
+ node.setFocusable(true);
+ this.lastFocused = node;
+ }
+ },
+
+ _onNodeMouseEnter: function(/*dijit._Widget*/ node){
+ // summary:
+ // Called when mouse is over a node (onmouseenter event),
+ // this is monitored by the DND code
+ },
+
+ _onNodeMouseLeave: function(/*dijit._Widget*/ node){
+ // summary:
+ // Called when mouse leaves a node (onmouseleave event),
+ // this is monitored by the DND code
+ },
+
+ //////////////// Events from the model //////////////////////////
+
+ _onItemChange: function(/*Item*/ item){
+ // summary:
+ // Processes notification of a change to an item's scalar values like label
+ var model = this.model,
+ identity = model.getIdentity(item),
+ nodes = this._itemNodesMap[identity];
+
+ if(nodes){
+ var label = this.getLabel(item),
+ tooltip = this.getTooltip(item);
+ dojo.forEach(nodes, function(node){
+ node.set({
+ item: item, // theoretically could be new JS Object representing same item
+ label: label,
+ tooltip: tooltip
+ });
+ node._updateItemClasses(item);
+ });
+ }
+ },
+
+ _onItemChildrenChange: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
+ // summary:
+ // Processes notification of a change to an item's children
+ var model = this.model,
+ identity = model.getIdentity(parent),
+ parentNodes = this._itemNodesMap[identity];
+
+ if(parentNodes){
+ dojo.forEach(parentNodes,function(parentNode){
+ parentNode.setChildItems(newChildrenList);
+ });
+ }
+ },
+
+ _onItemDelete: function(/*Item*/ item){
+ // summary:
+ // Processes notification of a deletion of an item
+ var model = this.model,
+ identity = model.getIdentity(item),
+ nodes = this._itemNodesMap[identity];
+
+ if(nodes){
+ dojo.forEach(nodes,function(node){
+ var parent = node.getParent();
+ if(parent){
+ // if node has not already been orphaned from a _onSetItem(parent, "children", ..) call...
+ parent.removeChild(node);
+ }
+ node.destroyRecursive();
+ });
+ delete this._itemNodesMap[identity];
+ }
+ },
+
+ /////////////// Miscellaneous funcs
+
+ _initState: function(){
+ // summary:
+ // Load in which nodes should be opened automatically
+ if(this.persist){
+ var cookie = dojo.cookie(this.cookieName);
+ this._openedItemIds = {};
+ if(cookie){
+ dojo.forEach(cookie.split(','), function(item){
+ this._openedItemIds[item] = true;
+ }, this);
+ }
+ }
+ },
+ _state: function(item,expanded){
+ // summary:
+ // Query or set expanded state for an item,
+ if(!this.persist){
+ return false;
+ }
+ var id=this.model.getIdentity(item);
+ if(arguments.length === 1){
+ return this._openedItemIds[id];
+ }
+ if(expanded){
+ this._openedItemIds[id] = true;
+ }else{
+ delete this._openedItemIds[id];
+ }
+ },
+ _saveState: function(){
+ // summary:
+ // Create and save a cookie with the currently expanded nodes identifiers
+ if(!this.persist){
+ return;
+ }
+ var ary = [];
+ for(var id in this._openedItemIds){
+ ary.push(id);
+ }
+ dojo.cookie(this.cookieName, ary.join(","), {expires:365});
+ },
+
+ destroy: function(){
+ if(this._curSearch){
+ clearTimeout(this._curSearch.timer);
+ delete this._curSearch;
+ }
+ if(this.rootNode){
+ this.rootNode.destroyRecursive();
+ }
+ if(this.dndController && !dojo.isString(this.dndController)){
+ this.dndController.destroy();
+ }
+ this.rootNode = null;
+ this.inherited(arguments);
+ },
+
+ destroyRecursive: function(){
+ // A tree is treated as a leaf, not as a node with children (like a grid),
+ // but defining destroyRecursive for back-compat.
+ this.destroy();
+ },
+
+ resize: function(changeSize){
+ if(changeSize){
+ dojo.marginBox(this.domNode, changeSize);
+ dojo.style(this.domNode, "overflow", "auto"); // for scrollbars
+ }
+
+ // The only JS sizing involved w/tree is the indentation, which is specified
+ // in CSS and read in through this dummy indentDetector node (tree must be
+ // visible and attached to the DOM to read this)
+ this._nodePixelIndent = dojo.marginBox(this.tree.indentDetector).w;
+
+ if(this.tree.rootNode){
+ // If tree has already loaded, then reset indent for all the nodes
+ this.tree.rootNode.set('indent', this.showRoot ? 0 : -1);
+ }
+ },
+
+ _createTreeNode: function(/*Object*/ args){
+ // summary:
+ // creates a TreeNode
+ // description:
+ // Developers can override this method to define their own TreeNode class;
+ // However it will probably be removed in a future release in favor of a way
+ // of just specifying a widget for the label, rather than one that contains
+ // the children too.
+ return new dijit._TreeNode(args);
+ }
+});
+
+// For back-compat. TODO: remove in 2.0
+
+
+
+}
+
+if(!dojo._hasResource["dojo.dnd.Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Container"] = true;
+dojo.provide("dojo.dnd.Container");
+
+
+
+
+/*
+ Container states:
+ "" - normal state
+ "Over" - mouse over a container
+ Container item states:
+ "" - normal state
+ "Over" - mouse over a container item
+*/
+
+/*=====
+dojo.declare("dojo.dnd.__ContainerArgs", [], {
+ creator: function(){
+ // summary:
+ // a creator function, which takes a data item, and returns an object like that:
+ // {node: newNode, data: usedData, type: arrayOfStrings}
+ },
+
+ // skipForm: Boolean
+ // don't start the drag operation, if clicked on form elements
+ skipForm: false,
+
+ // dropParent: Node||String
+ // node or node's id to use as the parent node for dropped items
+ // (must be underneath the 'node' parameter in the DOM)
+ dropParent: null,
+
+ // _skipStartup: Boolean
+ // skip startup(), which collects children, for deferred initialization
+ // (this is used in the markup mode)
+ _skipStartup: false
+});
+
+dojo.dnd.Item = function(){
+ // summary:
+ // Represents (one of) the source node(s) being dragged.
+ // Contains (at least) the "type" and "data" attributes.
+ // type: String[]
+ // Type(s) of this item, by default this is ["text"]
+ // data: Object
+ // Logical representation of the object being dragged.
+ // If the drag object's type is "text" then data is a String,
+ // if it's another type then data could be a different Object,
+ // perhaps a name/value hash.
+
+ this.type = type;
+ this.data = data;
+}
+=====*/
+
+dojo.declare("dojo.dnd.Container", null, {
+ // summary:
+ // a Container object, which knows when mouse hovers over it,
+ // and over which element it hovers
+
+ // object attributes (for markup)
+ skipForm: false,
+
+ /*=====
+ // current: DomNode
+ // The DOM node the mouse is currently hovered over
+ current: null,
+
+ // map: Hash<String, dojo.dnd.Item>
+ // Map from an item's id (which is also the DOMNode's id) to
+ // the dojo.dnd.Item itself.
+ map: {},
+ =====*/
+
+ constructor: function(node, params){
+ // summary:
+ // a constructor of the Container
+ // node: Node
+ // node or node's id to build the container on
+ // params: dojo.dnd.__ContainerArgs
+ // a dictionary of parameters
+ this.node = dojo.byId(node);
+ if(!params){ params = {}; }
+ this.creator = params.creator || null;
+ this.skipForm = params.skipForm;
+ this.parent = params.dropParent && dojo.byId(params.dropParent);
+
+ // class-specific variables
+ this.map = {};
+ this.current = null;
+
+ // states
+ this.containerState = "";
+ dojo.addClass(this.node, "dojoDndContainer");
+
+ // mark up children
+ if(!(params && params._skipStartup)){
+ this.startup();
+ }
+
+ // set up events
+ this.events = [
+ dojo.connect(this.node, "onmouseover", this, "onMouseOver"),
+ dojo.connect(this.node, "onmouseout", this, "onMouseOut"),
+ // cancel text selection and text dragging
+ dojo.connect(this.node, "ondragstart", this, "onSelectStart"),
+ dojo.connect(this.node, "onselectstart", this, "onSelectStart")
+ ];
+ },
+
+ // object attributes (for markup)
+ creator: function(){
+ // summary:
+ // creator function, dummy at the moment
+ },
+
+ // abstract access to the map
+ getItem: function(/*String*/ key){
+ // summary:
+ // returns a data item by its key (id)
+ return this.map[key]; // dojo.dnd.Item
+ },
+ setItem: function(/*String*/ key, /*dojo.dnd.Item*/ data){
+ // summary:
+ // associates a data item with its key (id)
+ this.map[key] = data;
+ },
+ delItem: function(/*String*/ key){
+ // summary:
+ // removes a data item from the map by its key (id)
+ delete this.map[key];
+ },
+ forInItems: function(/*Function*/ f, /*Object?*/ o){
+ // summary:
+ // iterates over a data map skipping members that
+ // are present in the empty object (IE and/or 3rd-party libraries).
+ o = o || dojo.global;
+ var m = this.map, e = dojo.dnd._empty;
+ for(var i in m){
+ if(i in e){ continue; }
+ f.call(o, m[i], i, this);
+ }
+ return o; // Object
+ },
+ clearItems: function(){
+ // summary:
+ // removes all data items from the map
+ this.map = {};
+ },
+
+ // methods
+ getAllNodes: function(){
+ // summary:
+ // returns a list (an array) of all valid child nodes
+ return dojo.query("> .dojoDndItem", this.parent); // NodeList
+ },
+ sync: function(){
+ // summary:
+ // sync up the node list with the data map
+ var map = {};
+ this.getAllNodes().forEach(function(node){
+ if(node.id){
+ var item = this.getItem(node.id);
+ if(item){
+ map[node.id] = item;
+ return;
+ }
+ }else{
+ node.id = dojo.dnd.getUniqueId();
+ }
+ var type = node.getAttribute("dndType"),
+ data = node.getAttribute("dndData");
+ map[node.id] = {
+ data: data || node.innerHTML,
+ type: type ? type.split(/\s*,\s*/) : ["text"]
+ };
+ }, this);
+ this.map = map;
+ return this; // self
+ },
+ insertNodes: function(data, before, anchor){
+ // summary:
+ // inserts an array of new nodes before/after an anchor node
+ // data: Array
+ // a list of data items, which should be processed by the creator function
+ // before: Boolean
+ // insert before the anchor, if true, and after the anchor otherwise
+ // anchor: Node
+ // the anchor node to be used as a point of insertion
+ if(!this.parent.firstChild){
+ anchor = null;
+ }else if(before){
+ if(!anchor){
+ anchor = this.parent.firstChild;
+ }
+ }else{
+ if(anchor){
+ anchor = anchor.nextSibling;
+ }
+ }
+ if(anchor){
+ for(var i = 0; i < data.length; ++i){
+ var t = this._normalizedCreator(data[i]);
+ this.setItem(t.node.id, {data: t.data, type: t.type});
+ this.parent.insertBefore(t.node, anchor);
+ }
+ }else{
+ for(var i = 0; i < data.length; ++i){
+ var t = this._normalizedCreator(data[i]);
+ this.setItem(t.node.id, {data: t.data, type: t.type});
+ this.parent.appendChild(t.node);
+ }
+ }
+ return this; // self
+ },
+ destroy: function(){
+ // summary:
+ // prepares this object to be garbage-collected
+ dojo.forEach(this.events, dojo.disconnect);
+ this.clearItems();
+ this.node = this.parent = this.current = null;
+ },
+
+ // markup methods
+ markupFactory: function(params, node){
+ params._skipStartup = true;
+ return new dojo.dnd.Container(node, params);
+ },
+ startup: function(){
+ // summary:
+ // collects valid child items and populate the map
+
+ // set up the real parent node
+ if(!this.parent){
+ // use the standard algorithm, if not assigned
+ this.parent = this.node;
+ if(this.parent.tagName.toLowerCase() == "table"){
+ var c = this.parent.getElementsByTagName("tbody");
+ if(c && c.length){ this.parent = c[0]; }
+ }
+ }
+ this.defaultCreator = dojo.dnd._defaultCreator(this.parent);
+
+ // process specially marked children
+ this.sync();
+ },
+
+ // mouse events
+ onMouseOver: function(e){
+ // summary:
+ // event processor for onmouseover
+ // e: Event
+ // mouse event
+ var n = e.relatedTarget;
+ while(n){
+ if(n == this.node){ break; }
+ try{
+ n = n.parentNode;
+ }catch(x){
+ n = null;
+ }
+ }
+ if(!n){
+ this._changeState("Container", "Over");
+ this.onOverEvent();
+ }
+ n = this._getChildByEvent(e);
+ if(this.current == n){ return; }
+ if(this.current){ this._removeItemClass(this.current, "Over"); }
+ if(n){ this._addItemClass(n, "Over"); }
+ this.current = n;
+ },
+ onMouseOut: function(e){
+ // summary:
+ // event processor for onmouseout
+ // e: Event
+ // mouse event
+ for(var n = e.relatedTarget; n;){
+ if(n == this.node){ return; }
+ try{
+ n = n.parentNode;
+ }catch(x){
+ n = null;
+ }
+ }
+ if(this.current){
+ this._removeItemClass(this.current, "Over");
+ this.current = null;
+ }
+ this._changeState("Container", "");
+ this.onOutEvent();
+ },
+ onSelectStart: function(e){
+ // summary:
+ // event processor for onselectevent and ondragevent
+ // e: Event
+ // mouse event
+ if(!this.skipForm || !dojo.dnd.isFormElement(e)){
+ dojo.stopEvent(e);
+ }
+ },
+
+ // utilities
+ onOverEvent: function(){
+ // summary:
+ // this function is called once, when mouse is over our container
+ },
+ onOutEvent: function(){
+ // summary:
+ // this function is called once, when mouse is out of our container
+ },
+ _changeState: function(type, newState){
+ // summary:
+ // changes a named state to new state value
+ // type: String
+ // a name of the state to change
+ // newState: String
+ // new state
+ var prefix = "dojoDnd" + type;
+ var state = type.toLowerCase() + "State";
+ //dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
+ dojo.removeClass(this.node, prefix + this[state]);
+ dojo.addClass(this.node, prefix + newState);
+ this[state] = newState;
+ },
+ _addItemClass: function(node, type){
+ // summary:
+ // adds a class with prefix "dojoDndItem"
+ // node: Node
+ // a node
+ // type: String
+ // a variable suffix for a class name
+ dojo.addClass(node, "dojoDndItem" + type);
+ },
+ _removeItemClass: function(node, type){
+ // summary:
+ // removes a class with prefix "dojoDndItem"
+ // node: Node
+ // a node
+ // type: String
+ // a variable suffix for a class name
+ dojo.removeClass(node, "dojoDndItem" + type);
+ },
+ _getChildByEvent: function(e){
+ // summary:
+ // gets a child, which is under the mouse at the moment, or null
+ // e: Event
+ // a mouse event
+ var node = e.target;
+ if(node){
+ for(var parent = node.parentNode; parent; node = parent, parent = node.parentNode){
+ if(parent == this.parent && dojo.hasClass(node, "dojoDndItem")){ return node; }
+ }
+ }
+ return null;
+ },
+ _normalizedCreator: function(/*dojo.dnd.Item*/ item, /*String*/ hint){
+ // summary:
+ // adds all necessary data to the output of the user-supplied creator function
+ var t = (this.creator || this.defaultCreator).call(this, item, hint);
+ if(!dojo.isArray(t.type)){ t.type = ["text"]; }
+ if(!t.node.id){ t.node.id = dojo.dnd.getUniqueId(); }
+ dojo.addClass(t.node, "dojoDndItem");
+ return t;
+ }
+});
+
+dojo.dnd._createNode = function(tag){
+ // summary:
+ // returns a function, which creates an element of given tag
+ // (SPAN by default) and sets its innerHTML to given text
+ // tag: String
+ // a tag name or empty for SPAN
+ if(!tag){ return dojo.dnd._createSpan; }
+ return function(text){ // Function
+ return dojo.create(tag, {innerHTML: text}); // Node
+ };
+};
+
+dojo.dnd._createTrTd = function(text){
+ // summary:
+ // creates a TR/TD structure with given text as an innerHTML of TD
+ // text: String
+ // a text for TD
+ var tr = dojo.create("tr");
+ dojo.create("td", {innerHTML: text}, tr);
+ return tr; // Node
+};
+
+dojo.dnd._createSpan = function(text){
+ // summary:
+ // creates a SPAN element with given text as its innerHTML
+ // text: String
+ // a text for SPAN
+ return dojo.create("span", {innerHTML: text}); // Node
+};
+
+// dojo.dnd._defaultCreatorNodes: Object
+// a dictionary that maps container tag names to child tag names
+dojo.dnd._defaultCreatorNodes = {ul: "li", ol: "li", div: "div", p: "div"};
+
+dojo.dnd._defaultCreator = function(node){
+ // summary:
+ // takes a parent node, and returns an appropriate creator function
+ // node: Node
+ // a container node
+ var tag = node.tagName.toLowerCase();
+ var c = tag == "tbody" || tag == "thead" ? dojo.dnd._createTrTd :
+ dojo.dnd._createNode(dojo.dnd._defaultCreatorNodes[tag]);
+ return function(item, hint){ // Function
+ var isObj = item && dojo.isObject(item), data, type, n;
+ if(isObj && item.tagName && item.nodeType && item.getAttribute){
+ // process a DOM node
+ data = item.getAttribute("dndData") || item.innerHTML;
+ type = item.getAttribute("dndType");
+ type = type ? type.split(/\s*,\s*/) : ["text"];
+ n = item; // this node is going to be moved rather than copied
+ }else{
+ // process a DnD item object or a string
+ data = (isObj && item.data) ? item.data : item;
+ type = (isObj && item.type) ? item.type : ["text"];
+ n = (hint == "avatar" ? dojo.dnd._createSpan : c)(String(data));
+ }
+ if(!n.id){
+ n.id = dojo.dnd.getUniqueId();
+ }
+ return {node: n, data: data, type: type};
+ };
+};
+
+}
+
+if(!dojo._hasResource["dijit.tree._dndContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.tree._dndContainer"] = true;
+dojo.provide("dijit.tree._dndContainer");
+
+
+
+dojo.declare("dijit.tree._dndContainer",
+ null,
+ {
+
+ // summary:
+ // This is a base class for `dijit.tree._dndSelector`, and isn't meant to be used directly.
+ // It's modeled after `dojo.dnd.Container`.
+ // tags:
+ // protected
+
+ /*=====
+ // current: DomNode
+ // The currently hovered TreeNode.rowNode (which is the DOM node
+ // associated w/a given node in the tree, excluding it's descendants)
+ current: null,
+ =====*/
+
+ constructor: function(tree, params){
+ // summary:
+ // A constructor of the Container
+ // tree: Node
+ // Node or node's id to build the container on
+ // params: dijit.tree.__SourceArgs
+ // A dict of parameters, which gets mixed into the object
+ // tags:
+ // private
+ this.tree = tree;
+ this.node = tree.domNode; // TODO: rename; it's not a TreeNode but the whole Tree
+ dojo.mixin(this, params);
+
+ // class-specific variables
+ this.map = {};
+ this.current = null; // current TreeNode's DOM node
+
+ // states
+ this.containerState = "";
+ dojo.addClass(this.node, "dojoDndContainer");
+
+ // set up events
+ this.events = [
+ // container level events
+ dojo.connect(this.node, "onmouseenter", this, "onOverEvent"),
+ dojo.connect(this.node, "onmouseleave", this, "onOutEvent"),
+
+ // switching between TreeNodes
+ dojo.connect(this.tree, "_onNodeMouseEnter", this, "onMouseOver"),
+ dojo.connect(this.tree, "_onNodeMouseLeave", this, "onMouseOut"),
+
+ // cancel text selection and text dragging
+ dojo.connect(this.node, "ondragstart", dojo, "stopEvent"),
+ dojo.connect(this.node, "onselectstart", dojo, "stopEvent")
+ ];
+ },
+
+ getItem: function(/*String*/ key){
+ // summary:
+ // Returns the dojo.dnd.Item (representing a dragged node) by it's key (id).
+ // Called by dojo.dnd.Source.checkAcceptance().
+ // tags:
+ // protected
+
+ var node = this.selection[key],
+ ret = {
+ data: dijit.getEnclosingWidget(node),
+ type: ["treeNode"]
+ };
+
+ return ret; // dojo.dnd.Item
+ },
+
+ destroy: function(){
+ // summary:
+ // Prepares this object to be garbage-collected
+
+ dojo.forEach(this.events, dojo.disconnect);
+ // this.clearItems();
+ this.node = this.parent = null;
+ },
+
+ // mouse events
+ onMouseOver: function(/*TreeNode*/ widget, /*Event*/ evt){
+ // summary:
+ // Called when mouse is moved over a TreeNode
+ // tags:
+ // protected
+ this.current = widget.rowNode;
+ this.currentWidget = widget;
+ },
+
+ onMouseOut: function(/*TreeNode*/ widget, /*Event*/ evt){
+ // summary:
+ // Called when mouse is moved away from a TreeNode
+ // tags:
+ // protected
+ this.current = null;
+ this.currentWidget = null;
+ },
+
+ _changeState: function(type, newState){
+ // summary:
+ // Changes a named state to new state value
+ // type: String
+ // A name of the state to change
+ // newState: String
+ // new state
+ var prefix = "dojoDnd" + type;
+ var state = type.toLowerCase() + "State";
+ //dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
+ dojo.removeClass(this.node, prefix + this[state]);
+ dojo.addClass(this.node, prefix + newState);
+ this[state] = newState;
+ },
+
+ _addItemClass: function(node, type){
+ // summary:
+ // Adds a class with prefix "dojoDndItem"
+ // node: Node
+ // A node
+ // type: String
+ // A variable suffix for a class name
+ dojo.addClass(node, "dojoDndItem" + type);
+ },
+
+ _removeItemClass: function(node, type){
+ // summary:
+ // Removes a class with prefix "dojoDndItem"
+ // node: Node
+ // A node
+ // type: String
+ // A variable suffix for a class name
+ dojo.removeClass(node, "dojoDndItem" + type);
+ },
+
+ onOverEvent: function(){
+ // summary:
+ // This function is called once, when mouse is over our container
+ // tags:
+ // protected
+ this._changeState("Container", "Over");
+ },
+
+ onOutEvent: function(){
+ // summary:
+ // This function is called once, when mouse is out of our container
+ // tags:
+ // protected
+ this._changeState("Container", "");
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.tree._dndSelector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.tree._dndSelector"] = true;
+dojo.provide("dijit.tree._dndSelector");
+
+
+
+dojo.declare("dijit.tree._dndSelector",
+ dijit.tree._dndContainer,
+ {
+ // summary:
+ // This is a base class for `dijit.tree.dndSource` , and isn't meant to be used directly.
+ // It's based on `dojo.dnd.Selector`.
+ // tags:
+ // protected
+
+ /*=====
+ // selection: Hash<String, DomNode>
+ // (id, DomNode) map for every TreeNode that's currently selected.
+ // The DOMNode is the TreeNode.rowNode.
+ selection: {},
+ =====*/
+
+ constructor: function(tree, params){
+ // summary:
+ // Initialization
+ // tags:
+ // private
+
+ this.selection={};
+ this.anchor = null;
+ this.simpleSelection=false;
+
+ this.events.push(
+ dojo.connect(this.tree.domNode, "onmousedown", this,"onMouseDown"),
+ dojo.connect(this.tree.domNode, "onmouseup", this,"onMouseUp"),
+ dojo.connect(this.tree.domNode, "onmousemove", this,"onMouseMove")
+ );
+ },
+
+ // singular: Boolean
+ // Allows selection of only one element, if true.
+ // Tree hasn't been tested in singular=true mode, unclear if it works.
+ singular: false,
+
+ // methods
+
+ getSelectedNodes: function(){
+ // summary:
+ // Returns the set of selected nodes.
+ // Used by dndSource on the start of a drag.
+ // tags:
+ // protected
+ return this.selection;
+ },
+
+ selectNone: function(){
+ // summary:
+ // Unselects all items
+ // tags:
+ // private
+
+ return this._removeSelection()._removeAnchor(); // self
+ },
+
+ destroy: function(){
+ // summary:
+ // Prepares the object to be garbage-collected
+ this.inherited(arguments);
+ this.selection = this.anchor = null;
+ },
+
+ // mouse events
+ onMouseDown: function(e){
+ // summary:
+ // Event processor for onmousedown
+ // e: Event
+ // mouse event
+ // tags:
+ // protected
+
+ if(!this.current){ return; }
+
+ if(e.button == dojo.mouseButtons.RIGHT){ return; } // ignore right-click
+
+ var treeNode = dijit.getEnclosingWidget(this.current),
+ id = treeNode.id + "-dnd" // so id doesn't conflict w/widget
+
+ if(!dojo.hasAttr(this.current, "id")){
+ dojo.attr(this.current, "id", id);
+ }
+
+ if(!this.singular && !dojo.isCopyKey(e) && !e.shiftKey && (this.current.id in this.selection)){
+ this.simpleSelection = true;
+ dojo.stopEvent(e);
+ return;
+ }
+ if(this.singular){
+ if(this.anchor == this.current){
+ if(dojo.isCopyKey(e)){
+ this.selectNone();
+ }
+ }else{
+ this.selectNone();
+ this.anchor = this.current;
+ this._addItemClass(this.anchor, "Anchor");
+
+ this.selection[this.current.id] = this.current;
+ }
+ }else{
+ if(!this.singular && e.shiftKey){
+ if(dojo.isCopyKey(e)){
+ //TODO add range to selection
+ }else{
+ //TODO select new range from anchor
+ }
+ }else{
+ if(dojo.isCopyKey(e)){
+ if(this.anchor == this.current){
+ delete this.selection[this.anchor.id];
+ this._removeAnchor();
+ }else{
+ if(this.current.id in this.selection){
+ this._removeItemClass(this.current, "Selected");
+ delete this.selection[this.current.id];
+ }else{
+ if(this.anchor){
+ this._removeItemClass(this.anchor, "Anchor");
+ this._addItemClass(this.anchor, "Selected");
+ }
+ this.anchor = this.current;
+ this._addItemClass(this.current, "Anchor");
+ this.selection[this.current.id] = this.current;
+ }
+ }
+ }else{
+ if(!(id in this.selection)){
+ this.selectNone();
+ this.anchor = this.current;
+ this._addItemClass(this.current, "Anchor");
+ this.selection[id] = this.current;
+ }
+ }
+ }
+ }
+
+ dojo.stopEvent(e);
+ },
+
+ onMouseUp: function(e){
+ // summary:
+ // Event processor for onmouseup
+ // e: Event
+ // mouse event
+ // tags:
+ // protected
+
+ // TODO: this code is apparently for handling an edge case when the user is selecting
+ // multiple nodes and then mousedowns on a node by accident... it lets the user keep the
+ // current selection by moving the mouse away (or something like that). It doesn't seem
+ // to work though and requires a lot of plumbing (including this code, the onmousemove
+ // handler, and the this.simpleSelection attribute. Consider getting rid of all of it.
+
+ if(!this.simpleSelection){ return; }
+ this.simpleSelection = false;
+ this.selectNone();
+ if(this.current){
+ this.anchor = this.current;
+ this._addItemClass(this.anchor, "Anchor");
+ this.selection[this.current.id] = this.current;
+ }
+ },
+ onMouseMove: function(e){
+ // summary
+ // event processor for onmousemove
+ // e: Event
+ // mouse event
+ this.simpleSelection = false;
+ },
+
+ _removeSelection: function(){
+ // summary:
+ // Unselects all items
+ // tags:
+ // private
+ var e = dojo.dnd._empty;
+ for(var i in this.selection){
+ if(i in e){ continue; }
+ var node = dojo.byId(i);
+ if(node){ this._removeItemClass(node, "Selected"); }
+ }
+ this.selection = {};
+ return this; // self
+ },
+
+ _removeAnchor: function(){
+ // summary:
+ // Removes the Anchor CSS class from a node.
+ // According to `dojo.dnd.Selector`, anchor means that
+ // "an item is selected, and is an anchor for a 'shift' selection".
+ // It's not relevant for Tree at this point, since we don't support multiple selection.
+ // tags:
+ // private
+ if(this.anchor){
+ this._removeItemClass(this.anchor, "Anchor");
+ this.anchor = null;
+ }
+ return this; // self
+ },
+
+ forInSelectedItems: function(/*Function*/ f, /*Object?*/ o){
+ // summary:
+ // Iterates over selected items;
+ // see `dojo.dnd.Container.forInItems()` for details
+ o = o || dojo.global;
+ for(var id in this.selection){
+ console.log("selected item id: " + id);
+ f.call(o, this.getItem(id), id, this);
+ }
+ }
+});
+
+}
+
+if(!dojo._hasResource["dojo.dnd.Avatar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Avatar"] = true;
+dojo.provide("dojo.dnd.Avatar");
+
+
+
+dojo.declare("dojo.dnd.Avatar", null, {
+ // summary:
+ // Object that represents transferred DnD items visually
+ // manager: Object
+ // a DnD manager object
+
+ constructor: function(manager){
+ this.manager = manager;
+ this.construct();
+ },
+
+ // methods
+ construct: function(){
+ // summary:
+ // constructor function;
+ // it is separate so it can be (dynamically) overwritten in case of need
+ this.isA11y = dojo.hasClass(dojo.body(),"dijit_a11y");
+ var a = dojo.create("table", {
+ "class": "dojoDndAvatar",
+ style: {
+ position: "absolute",
+ zIndex: "1999",
+ margin: "0px"
+ }
+ }),
+ source = this.manager.source, node,
+ b = dojo.create("tbody", null, a),
+ tr = dojo.create("tr", null, b),
+ td = dojo.create("td", null, tr),
+ icon = this.isA11y ? dojo.create("span", {
+ id : "a11yIcon",
+ innerHTML : this.manager.copy ? '+' : "<"
+ }, td) : null,
+ span = dojo.create("span", {
+ innerHTML: source.generateText ? this._generateText() : ""
+ }, td),
+ k = Math.min(5, this.manager.nodes.length), i = 0;
+ // we have to set the opacity on IE only after the node is live
+ dojo.attr(tr, {
+ "class": "dojoDndAvatarHeader",
+ style: {opacity: 0.9}
+ });
+ for(; i < k; ++i){
+ if(source.creator){
+ // create an avatar representation of the node
+ node = source._normalizedCreator(source.getItem(this.manager.nodes[i].id).data, "avatar").node;
+ }else{
+ // or just clone the node and hope it works
+ node = this.manager.nodes[i].cloneNode(true);
+ if(node.tagName.toLowerCase() == "tr"){
+ // insert extra table nodes
+ var table = dojo.create("table"),
+ tbody = dojo.create("tbody", null, table);
+ tbody.appendChild(node);
+ node = table;
+ }
+ }
+ node.id = "";
+ tr = dojo.create("tr", null, b);
+ td = dojo.create("td", null, tr);
+ td.appendChild(node);
+ dojo.attr(tr, {
+ "class": "dojoDndAvatarItem",
+ style: {opacity: (9 - i) / 10}
+ });
+ }
+ this.node = a;
+ },
+ destroy: function(){
+ // summary:
+ // destructor for the avatar; called to remove all references so it can be garbage-collected
+ dojo.destroy(this.node);
+ this.node = false;
+ },
+ update: function(){
+ // summary:
+ // updates the avatar to reflect the current DnD state
+ dojo[(this.manager.canDropFlag ? "add" : "remove") + "Class"](this.node, "dojoDndAvatarCanDrop");
+ if (this.isA11y){
+ var icon = dojo.byId("a11yIcon");
+ var text = '+'; // assume canDrop && copy
+ if (this.manager.canDropFlag && !this.manager.copy) {
+ text = '< '; // canDrop && move
+ }else if (!this.manager.canDropFlag && !this.manager.copy) {
+ text = "o"; //!canDrop && move
+ }else if(!this.manager.canDropFlag){
+ text = 'x'; // !canDrop && copy
+ }
+ icon.innerHTML=text;
+ }
+ // replace text
+ dojo.query(("tr.dojoDndAvatarHeader td span" +(this.isA11y ? " span" : "")), this.node).forEach(
+ function(node){
+ node.innerHTML = this._generateText();
+ }, this);
+ },
+ _generateText: function(){
+ // summary: generates a proper text to reflect copying or moving of items
+ return this.manager.nodes.length.toString();
+ }
+});
+
+}
+
+if(!dojo._hasResource["dojo.dnd.Manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Manager"] = true;
+dojo.provide("dojo.dnd.Manager");
+
+
+
+
+
+dojo.declare("dojo.dnd.Manager", null, {
+ // summary:
+ // the manager of DnD operations (usually a singleton)
+ constructor: function(){
+ this.avatar = null;
+ this.source = null;
+ this.nodes = [];
+ this.copy = true;
+ this.target = null;
+ this.canDropFlag = false;
+ this.events = [];
+ },
+
+ // avatar's offset from the mouse
+ OFFSET_X: 16,
+ OFFSET_Y: 16,
+
+ // methods
+ overSource: function(source){
+ // summary:
+ // called when a source detected a mouse-over condition
+ // source: Object
+ // the reporter
+ if(this.avatar){
+ this.target = (source && source.targetState != "Disabled") ? source : null;
+ this.canDropFlag = Boolean(this.target);
+ this.avatar.update();
+ }
+ dojo.publish("/dnd/source/over", [source]);
+ },
+ outSource: function(source){
+ // summary:
+ // called when a source detected a mouse-out condition
+ // source: Object
+ // the reporter
+ if(this.avatar){
+ if(this.target == source){
+ this.target = null;
+ this.canDropFlag = false;
+ this.avatar.update();
+ dojo.publish("/dnd/source/over", [null]);
+ }
+ }else{
+ dojo.publish("/dnd/source/over", [null]);
+ }
+ },
+ startDrag: function(source, nodes, copy){
+ // summary:
+ // called to initiate the DnD operation
+ // source: Object
+ // the source which provides items
+ // nodes: Array
+ // the list of transferred items
+ // copy: Boolean
+ // copy items, if true, move items otherwise
+ this.source = source;
+ this.nodes = nodes;
+ this.copy = Boolean(copy); // normalizing to true boolean
+ this.avatar = this.makeAvatar();
+ dojo.body().appendChild(this.avatar.node);
+ dojo.publish("/dnd/start", [source, nodes, this.copy]);
+ this.events = [
+ dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"),
+ dojo.connect(dojo.doc, "onmouseup", this, "onMouseUp"),
+ dojo.connect(dojo.doc, "onkeydown", this, "onKeyDown"),
+ dojo.connect(dojo.doc, "onkeyup", this, "onKeyUp"),
+ // cancel text selection and text dragging
+ dojo.connect(dojo.doc, "ondragstart", dojo.stopEvent),
+ dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent)
+ ];
+ var c = "dojoDnd" + (copy ? "Copy" : "Move");
+ dojo.addClass(dojo.body(), c);
+ },
+ canDrop: function(flag){
+ // summary:
+ // called to notify if the current target can accept items
+ var canDropFlag = Boolean(this.target && flag);
+ if(this.canDropFlag != canDropFlag){
+ this.canDropFlag = canDropFlag;
+ this.avatar.update();
+ }
+ },
+ stopDrag: function(){
+ // summary:
+ // stop the DnD in progress
+ dojo.removeClass(dojo.body(), "dojoDndCopy");
+ dojo.removeClass(dojo.body(), "dojoDndMove");
+ dojo.forEach(this.events, dojo.disconnect);
+ this.events = [];
+ this.avatar.destroy();
+ this.avatar = null;
+ this.source = this.target = null;
+ this.nodes = [];
+ },
+ makeAvatar: function(){
+ // summary:
+ // makes the avatar; it is separate to be overwritten dynamically, if needed
+ return new dojo.dnd.Avatar(this);
+ },
+ updateAvatar: function(){
+ // summary:
+ // updates the avatar; it is separate to be overwritten dynamically, if needed
+ this.avatar.update();
+ },
+
+ // mouse event processors
+ onMouseMove: function(e){
+ // summary:
+ // event processor for onmousemove
+ // e: Event
+ // mouse event
+ var a = this.avatar;
+ if(a){
+ dojo.dnd.autoScrollNodes(e);
+ //dojo.dnd.autoScroll(e);
+ var s = a.node.style;
+ s.left = (e.pageX + this.OFFSET_X) + "px";
+ s.top = (e.pageY + this.OFFSET_Y) + "px";
+ var copy = Boolean(this.source.copyState(dojo.isCopyKey(e)));
+ if(this.copy != copy){
+ this._setCopyStatus(copy);
+ }
+ }
+ },
+ onMouseUp: function(e){
+ // summary:
+ // event processor for onmouseup
+ // e: Event
+ // mouse event
+ if(this.avatar){
+ if(this.target && this.canDropFlag){
+ var copy = Boolean(this.source.copyState(dojo.isCopyKey(e))),
+ params = [this.source, this.nodes, copy, this.target, e];
+ dojo.publish("/dnd/drop/before", params);
+ dojo.publish("/dnd/drop", params);
+ }else{
+ dojo.publish("/dnd/cancel");
+ }
+ this.stopDrag();
+ }
+ },
+
+ // keyboard event processors
+ onKeyDown: function(e){
+ // summary:
+ // event processor for onkeydown:
+ // watching for CTRL for copy/move status, watching for ESCAPE to cancel the drag
+ // e: Event
+ // keyboard event
+ if(this.avatar){
+ switch(e.keyCode){
+ case dojo.keys.CTRL:
+ var copy = Boolean(this.source.copyState(true));
+ if(this.copy != copy){
+ this._setCopyStatus(copy);
+ }
+ break;
+ case dojo.keys.ESCAPE:
+ dojo.publish("/dnd/cancel");
+ this.stopDrag();
+ break;
+ }
+ }
+ },
+ onKeyUp: function(e){
+ // summary:
+ // event processor for onkeyup, watching for CTRL for copy/move status
+ // e: Event
+ // keyboard event
+ if(this.avatar && e.keyCode == dojo.keys.CTRL){
+ var copy = Boolean(this.source.copyState(false));
+ if(this.copy != copy){
+ this._setCopyStatus(copy);
+ }
+ }
+ },
+
+ // utilities
+ _setCopyStatus: function(copy){
+ // summary:
+ // changes the copy status
+ // copy: Boolean
+ // the copy status
+ this.copy = copy;
+ this.source._markDndStatus(this.copy);
+ this.updateAvatar();
+ dojo.removeClass(dojo.body(), "dojoDnd" + (this.copy ? "Move" : "Copy"));
+ dojo.addClass(dojo.body(), "dojoDnd" + (this.copy ? "Copy" : "Move"));
+ }
+});
+
+// dojo.dnd._manager:
+// The manager singleton variable. Can be overwritten if needed.
+dojo.dnd._manager = null;
+
+dojo.dnd.manager = function(){
+ // summary:
+ // Returns the current DnD manager. Creates one if it is not created yet.
+ if(!dojo.dnd._manager){
+ dojo.dnd._manager = new dojo.dnd.Manager();
+ }
+ return dojo.dnd._manager; // Object
+};
+
+}
+
+if(!dojo._hasResource["dijit.tree.dndSource"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.tree.dndSource"] = true;
+dojo.provide("dijit.tree.dndSource");
+
+
+
+
+/*=====
+dijit.tree.__SourceArgs = function(){
+ // summary:
+ // A dict of parameters for Tree source configuration.
+ // isSource: Boolean?
+ // Can be used as a DnD source. Defaults to true.
+ // accept: String[]
+ // List of accepted types (text strings) for a target; defaults to
+ // ["text", "treeNode"]
+ // copyOnly: Boolean?
+ // Copy items, if true, use a state of Ctrl key otherwise,
+ // dragThreshold: Number
+ // The move delay in pixels before detecting a drag; 0 by default
+ // betweenThreshold: Integer
+ // Distance from upper/lower edge of node to allow drop to reorder nodes
+ this.isSource = isSource;
+ this.accept = accept;
+ this.autoSync = autoSync;
+ this.copyOnly = copyOnly;
+ this.dragThreshold = dragThreshold;
+ this.betweenThreshold = betweenThreshold;
+}
+=====*/
+
+dojo.declare("dijit.tree.dndSource", dijit.tree._dndSelector, {
+ // summary:
+ // Handles drag and drop operations (as a source or a target) for `dijit.Tree`
+
+ // isSource: [private] Boolean
+ // Can be used as a DnD source.
+ isSource: true,
+
+ // accept: String[]
+ // List of accepted types (text strings) for the Tree; defaults to
+ // ["text"]
+ accept: ["text", "treeNode"],
+
+ // copyOnly: [private] Boolean
+ // Copy items, if true, use a state of Ctrl key otherwise
+ copyOnly: false,
+
+ // dragThreshold: Number
+ // The move delay in pixels before detecting a drag; 5 by default
+ dragThreshold: 5,
+
+ // betweenThreshold: Integer
+ // Distance from upper/lower edge of node to allow drop to reorder nodes
+ betweenThreshold: 0,
+
+ constructor: function(/*dijit.Tree*/ tree, /*dijit.tree.__SourceArgs*/ params){
+ // summary:
+ // a constructor of the Tree DnD Source
+ // tags:
+ // private
+ if(!params){ params = {}; }
+ dojo.mixin(this, params);
+ this.isSource = typeof params.isSource == "undefined" ? true : params.isSource;
+ var type = params.accept instanceof Array ? params.accept : ["text", "treeNode"];
+ this.accept = null;
+ if(type.length){
+ this.accept = {};
+ for(var i = 0; i < type.length; ++i){
+ this.accept[type[i]] = 1;
+ }
+ }
+
+ // class-specific variables
+ this.isDragging = false;
+ this.mouseDown = false;
+ this.targetAnchor = null; // DOMNode corresponding to the currently moused over TreeNode
+ this.targetBox = null; // coordinates of this.targetAnchor
+ this.dropPosition = ""; // whether mouse is over/after/before this.targetAnchor
+ this._lastX = 0;
+ this._lastY = 0;
+
+ // states
+ this.sourceState = "";
+ if(this.isSource){
+ dojo.addClass(this.node, "dojoDndSource");
+ }
+ this.targetState = "";
+ if(this.accept){
+ dojo.addClass(this.node, "dojoDndTarget");
+ }
+
+ // set up events
+ this.topics = [
+ dojo.subscribe("/dnd/source/over", this, "onDndSourceOver"),
+ dojo.subscribe("/dnd/start", this, "onDndStart"),
+ dojo.subscribe("/dnd/drop", this, "onDndDrop"),
+ dojo.subscribe("/dnd/cancel", this, "onDndCancel")
+ ];
+ },
+
+ // methods
+ checkAcceptance: function(source, nodes){
+ // summary:
+ // Checks if the target can accept nodes from this source
+ // source: dijit.tree.dndSource
+ // The source which provides items
+ // nodes: DOMNode[]
+ // Array of DOM nodes corresponding to nodes being dropped, dijitTreeRow nodes if
+ // source is a dijit.Tree.
+ // tags:
+ // extension
+ return true; // Boolean
+ },
+
+ copyState: function(keyPressed){
+ // summary:
+ // Returns true, if we need to copy items, false to move.
+ // It is separated to be overwritten dynamically, if needed.
+ // keyPressed: Boolean
+ // The "copy" control key was pressed
+ // tags:
+ // protected
+ return this.copyOnly || keyPressed; // Boolean
+ },
+ destroy: function(){
+ // summary:
+ // Prepares the object to be garbage-collected.
+ this.inherited("destroy",arguments);
+ dojo.forEach(this.topics, dojo.unsubscribe);
+ this.targetAnchor = null;
+ },
+
+ _onDragMouse: function(e){
+ // summary:
+ // Helper method for processing onmousemove/onmouseover events while drag is in progress.
+ // Keeps track of current drop target.
+
+ var m = dojo.dnd.manager(),
+ oldTarget = this.targetAnchor, // the DOMNode corresponding to TreeNode mouse was previously over
+ newTarget = this.current, // DOMNode corresponding to TreeNode mouse is currently over
+ newTargetWidget = this.currentWidget, // the TreeNode itself
+ oldDropPosition = this.dropPosition; // the previous drop position (over/before/after)
+
+ // calculate if user is indicating to drop the dragged node before, after, or over
+ // (i.e., to become a child of) the target node
+ var newDropPosition = "Over";
+ if(newTarget && this.betweenThreshold > 0){
+ // If mouse is over a new TreeNode, then get new TreeNode's position and size
+ if(!this.targetBox || oldTarget != newTarget){
+ this.targetBox = dojo.position(newTarget, true);
+ }
+ if((e.pageY - this.targetBox.y) <= this.betweenThreshold){
+ newDropPosition = "Before";
+ }else if((e.pageY - this.targetBox.y) >= (this.targetBox.h - this.betweenThreshold)){
+ newDropPosition = "After";
+ }
+ }
+
+ if(newTarget != oldTarget || newDropPosition != oldDropPosition){
+ if(oldTarget){
+ this._removeItemClass(oldTarget, oldDropPosition);
+ }
+ if(newTarget){
+ this._addItemClass(newTarget, newDropPosition);
+ }
+
+ // Check if it's ok to drop the dragged node on/before/after the target node.
+ if(!newTarget){
+ m.canDrop(false);
+ }else if(newTargetWidget == this.tree.rootNode && newDropPosition != "Over"){
+ // Can't drop before or after tree's root node; the dropped node would just disappear (at least visually)
+ m.canDrop(false);
+ }else if(m.source == this && (newTarget.id in this.selection)){
+ // Guard against dropping onto yourself (TODO: guard against dropping onto your descendant, #7140)
+ m.canDrop(false);
+ }else if(this.checkItemAcceptance(newTarget, m.source, newDropPosition.toLowerCase())
+ && !this._isParentChildDrop(m.source, newTarget)){
+ m.canDrop(true);
+ }else{
+ m.canDrop(false);
+ }
+
+ this.targetAnchor = newTarget;
+ this.dropPosition = newDropPosition;
+ }
+ },
+
+ onMouseMove: function(e){
+ // summary:
+ // Called for any onmousemove events over the Tree
+ // e: Event
+ // onmousemouse event
+ // tags:
+ // private
+ if(this.isDragging && this.targetState == "Disabled"){ return; }
+ this.inherited(arguments);
+ var m = dojo.dnd.manager();
+ if(this.isDragging){
+ this._onDragMouse(e);
+ }else{
+ if(this.mouseDown && this.isSource &&
+ (Math.abs(e.pageX-this._lastX)>=this.dragThreshold || Math.abs(e.pageY-this._lastY)>=this.dragThreshold)){
+ var n = this.getSelectedNodes();
+ var nodes=[];
+ for(var i in n){
+ nodes.push(n[i]);
+ }
+ if(nodes.length){
+ m.startDrag(this, nodes, this.copyState(dojo.isCopyKey(e)));
+ }
+ }
+ }
+ },
+
+ onMouseDown: function(e){
+ // summary:
+ // Event processor for onmousedown
+ // e: Event
+ // onmousedown event
+ // tags:
+ // private
+ this.mouseDown = true;
+ this.mouseButton = e.button;
+ this._lastX = e.pageX;
+ this._lastY = e.pageY;
+ this.inherited("onMouseDown",arguments);
+ },
+
+ onMouseUp: function(e){
+ // summary:
+ // Event processor for onmouseup
+ // e: Event
+ // onmouseup event
+ // tags:
+ // private
+ if(this.mouseDown){
+ this.mouseDown = false;
+ this.inherited("onMouseUp",arguments);
+ }
+ },
+
+ onMouseOut: function(){
+ // summary:
+ // Event processor for when mouse is moved away from a TreeNode
+ // tags:
+ // private
+ this.inherited(arguments);
+ this._unmarkTargetAnchor();
+ },
+
+ checkItemAcceptance: function(target, source, position){
+ // summary:
+ // Stub function to be overridden if one wants to check for the ability to drop at the node/item level
+ // description:
+ // In the base case, this is called to check if target can become a child of source.
+ // When betweenThreshold is set, position="before" or "after" means that we
+ // are asking if the source node can be dropped before/after the target node.
+ // target: DOMNode
+ // The dijitTreeRoot DOM node inside of the TreeNode that we are dropping on to
+ // Use dijit.getEnclosingWidget(target) to get the TreeNode.
+ // source: dijit.tree.dndSource
+ // The (set of) nodes we are dropping
+ // position: String
+ // "over", "before", or "after"
+ // tags:
+ // extension
+ return true;
+ },
+
+ // topic event processors
+ onDndSourceOver: function(source){
+ // summary:
+ // Topic event processor for /dnd/source/over, called when detected a current source.
+ // source: Object
+ // The dijit.tree.dndSource / dojo.dnd.Source which has the mouse over it
+ // tags:
+ // private
+ if(this != source){
+ this.mouseDown = false;
+ this._unmarkTargetAnchor();
+ }else if(this.isDragging){
+ var m = dojo.dnd.manager();
+ m.canDrop(false);
+ }
+ },
+ onDndStart: function(source, nodes, copy){
+ // summary:
+ // Topic event processor for /dnd/start, called to initiate the DnD operation
+ // source: Object
+ // The dijit.tree.dndSource / dojo.dnd.Source which is providing the items
+ // nodes: DomNode[]
+ // The list of transferred items, dndTreeNode nodes if dragging from a Tree
+ // copy: Boolean
+ // Copy items, if true, move items otherwise
+ // tags:
+ // private
+
+ if(this.isSource){
+ this._changeState("Source", this == source ? (copy ? "Copied" : "Moved") : "");
+ }
+ var accepted = this.checkAcceptance(source, nodes);
+
+ this._changeState("Target", accepted ? "" : "Disabled");
+
+ if(this == source){
+ dojo.dnd.manager().overSource(this);
+ }
+
+ this.isDragging = true;
+ },
+
+ itemCreator: function(/*DomNode[]*/ nodes, target, /*dojo.dnd.Source*/ source){
+ // summary:
+ // Returns objects passed to `Tree.model.newItem()` based on DnD nodes
+ // dropped onto the tree. Developer must override this method to enable
+ // dropping from external sources onto this Tree, unless the Tree.model's items
+ // happen to look like {id: 123, name: "Apple" } with no other attributes.
+ // description:
+ // For each node in nodes[], which came from source, create a hash of name/value
+ // pairs to be passed to Tree.model.newItem(). Returns array of those hashes.
+ // returns: Object[]
+ // Array of name/value hashes for each new item to be added to the Tree, like:
+ // | [
+ // | { id: 123, label: "apple", foo: "bar" },
+ // | { id: 456, label: "pear", zaz: "bam" }
+ // | ]
+ // tags:
+ // extension
+
+ // TODO: for 2.0 refactor so itemCreator() is called once per drag node, and
+ // make signature itemCreator(sourceItem, node, target) (or similar).
+
+ return dojo.map(nodes, function(node){
+ return {
+ "id": node.id,
+ "name": node.textContent || node.innerText || ""
+ };
+ }); // Object[]
+ },
+
+ onDndDrop: function(source, nodes, copy){
+ // summary:
+ // Topic event processor for /dnd/drop, called to finish the DnD operation.
+ // description:
+ // Updates data store items according to where node was dragged from and dropped
+ // to. The tree will then respond to those data store updates and redraw itself.
+ // source: Object
+ // The dijit.tree.dndSource / dojo.dnd.Source which is providing the items
+ // nodes: DomNode[]
+ // The list of transferred items, dndTreeNode nodes if dragging from a Tree
+ // copy: Boolean
+ // Copy items, if true, move items otherwise
+ // tags:
+ // protected
+ if(this.containerState == "Over"){
+ var tree = this.tree,
+ model = tree.model,
+ target = this.targetAnchor,
+ requeryRoot = false; // set to true iff top level items change
+
+ this.isDragging = false;
+
+ // Compute the new parent item
+ var targetWidget = dijit.getEnclosingWidget(target);
+ var newParentItem;
+ var insertIndex;
+ newParentItem = (targetWidget && targetWidget.item) || tree.item;
+ if(this.dropPosition == "Before" || this.dropPosition == "After"){
+ // TODO: if there is no parent item then disallow the drop.
+ // Actually this should be checked during onMouseMove too, to make the drag icon red.
+ newParentItem = (targetWidget.getParent() && targetWidget.getParent().item) || tree.item;
+ // Compute the insert index for reordering
+ insertIndex = targetWidget.getIndexInParent();
+ if(this.dropPosition == "After"){
+ insertIndex = targetWidget.getIndexInParent() + 1;
+ }
+ }else{
+ newParentItem = (targetWidget && targetWidget.item) || tree.item;
+ }
+
+ // If necessary, use this variable to hold array of hashes to pass to model.newItem()
+ // (one entry in the array for each dragged node).
+ var newItemsParams;
+
+ dojo.forEach(nodes, function(node, idx){
+ // dojo.dnd.Item representing the thing being dropped.
+ // Don't confuse the use of item here (meaning a DnD item) with the
+ // uses below where item means dojo.data item.
+ var sourceItem = source.getItem(node.id);
+
+ // Information that's available if the source is another Tree
+ // (possibly but not necessarily this tree, possibly but not
+ // necessarily the same model as this Tree)
+ if(dojo.indexOf(sourceItem.type, "treeNode") != -1){
+ var childTreeNode = sourceItem.data,
+ childItem = childTreeNode.item,
+ oldParentItem = childTreeNode.getParent().item;
+ }
+
+ if(source == this){
+ // This is a node from my own tree, and we are moving it, not copying.
+ // Remove item from old parent's children attribute.
+ // TODO: dijit.tree.dndSelector should implement deleteSelectedNodes()
+ // and this code should go there.
+
+ if(typeof insertIndex == "number"){
+ if(newParentItem == oldParentItem && childTreeNode.getIndexInParent() < insertIndex){
+ insertIndex -= 1;
+ }
+ }
+ model.pasteItem(childItem, oldParentItem, newParentItem, copy, insertIndex);
+ }else if(model.isItem(childItem)){
+ // Item from same model
+ // (maybe we should only do this branch if the source is a tree?)
+ model.pasteItem(childItem, oldParentItem, newParentItem, copy, insertIndex);
+ }else{
+ // Get the hash to pass to model.newItem(). A single call to
+ // itemCreator() returns an array of hashes, one for each drag source node.
+ if(!newItemsParams){
+ newItemsParams = this.itemCreator(nodes, target, source);
+ }
+
+ // Create new item in the tree, based on the drag source.
+ model.newItem(newItemsParams[idx], newParentItem, insertIndex);
+ }
+ }, this);
+
+ // Expand the target node (if it's currently collapsed) so the user can see
+ // where their node was dropped. In particular since that node is still selected.
+ this.tree._expandNode(targetWidget);
+ }
+ this.onDndCancel();
+ },
+
+ onDndCancel: function(){
+ // summary:
+ // Topic event processor for /dnd/cancel, called to cancel the DnD operation
+ // tags:
+ // private
+ this._unmarkTargetAnchor();
+ this.isDragging = false;
+ this.mouseDown = false;
+ delete this.mouseButton;
+ this._changeState("Source", "");
+ this._changeState("Target", "");
+ },
+
+ // When focus moves in/out of the entire Tree
+ onOverEvent: function(){
+ // summary:
+ // This method is called when mouse is moved over our container (like onmouseenter)
+ // tags:
+ // private
+ this.inherited(arguments);
+ dojo.dnd.manager().overSource(this);
+ },
+ onOutEvent: function(){
+ // summary:
+ // This method is called when mouse is moved out of our container (like onmouseleave)
+ // tags:
+ // private
+ this._unmarkTargetAnchor();
+ var m = dojo.dnd.manager();
+ if(this.isDragging){
+ m.canDrop(false);
+ }
+ m.outSource(this);
+
+ this.inherited(arguments);
+ },
+
+ _isParentChildDrop: function(source, targetRow){
+ // summary:
+ // Checks whether the dragged items are parent rows in the tree which are being
+ // dragged into their own children.
+ //
+ // source:
+ // The DragSource object.
+ //
+ // targetRow:
+ // The tree row onto which the dragged nodes are being dropped.
+ //
+ // tags:
+ // private
+
+ // If the dragged object is not coming from the tree this widget belongs to,
+ // it cannot be invalid.
+ if(!source.tree || source.tree != this.tree){
+ return false;
+ }
+
+
+ var root = source.tree.domNode;
+ var ids = {};
+ for(var x in source.selection){
+ ids[source.selection[x].parentNode.id] = true;
+ }
+
+ var node = targetRow.parentNode;
+
+ // Iterate up the DOM hierarchy from the target drop row,
+ // checking of any of the dragged nodes have the same ID.
+ while(node != root && (!node.id || !ids[node.id])){
+ node = node.parentNode;
+ }
+
+ return node.id && ids[node.id];
+ },
+
+ _unmarkTargetAnchor: function(){
+ // summary:
+ // Removes hover class of the current target anchor
+ // tags:
+ // private
+ if(!this.targetAnchor){ return; }
+ this._removeItemClass(this.targetAnchor, this.dropPosition);
+ this.targetAnchor = null;
+ this.targetBox = null;
+ this.dropPosition = null;
+ },
+
+ _markDndStatus: function(copy){
+ // summary:
+ // Changes source's state based on "copy" status
+ this._changeState("Source", copy ? "Copied" : "Moved");
+ }
+});
+
+}
+
+if(!dojo._hasResource["dojo.data.ItemFileReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.ItemFileReadStore"] = true;
+dojo.provide("dojo.data.ItemFileReadStore");
+
+
+
+
+
+dojo.declare("dojo.data.ItemFileReadStore", null,{
+ // summary:
+ // The ItemFileReadStore implements the dojo.data.api.Read API and reads
+ // data from JSON files that have contents in this format --
+ // { items: [
+ // { name:'Kermit', color:'green', age:12, friends:['Gonzo', {_reference:{name:'Fozzie Bear'}}]},
+ // { name:'Fozzie Bear', wears:['hat', 'tie']},
+ // { name:'Miss Piggy', pets:'Foo-Foo'}
+ // ]}
+ // Note that it can also contain an 'identifer' property that specified which attribute on the items
+ // in the array of items that acts as the unique identifier for that item.
+ //
+ constructor: function(/* Object */ keywordParameters){
+ // summary: constructor
+ // keywordParameters: {url: String}
+ // keywordParameters: {data: jsonObject}
+ // keywordParameters: {typeMap: object)
+ // The structure of the typeMap object is as follows:
+ // {
+ // type0: function || object,
+ // type1: function || object,
+ // ...
+ // typeN: function || object
+ // }
+ // Where if it is a function, it is assumed to be an object constructor that takes the
+ // value of _value as the initialization parameters. If it is an object, then it is assumed
+ // to be an object of general form:
+ // {
+ // type: function, //constructor.
+ // deserialize: function(value) //The function that parses the value and constructs the object defined by type appropriately.
+ // }
+
+ this._arrayOfAllItems = [];
+ this._arrayOfTopLevelItems = [];
+ this._loadFinished = false;
+ this._jsonFileUrl = keywordParameters.url;
+ this._ccUrl = keywordParameters.url;
+ this.url = keywordParameters.url;
+ this._jsonData = keywordParameters.data;
+ this.data = null;
+ this._datatypeMap = keywordParameters.typeMap || {};
+ if(!this._datatypeMap['Date']){
+ //If no default mapping for dates, then set this as default.
+ //We use the dojo.date.stamp here because the ISO format is the 'dojo way'
+ //of generically representing dates.
+ this._datatypeMap['Date'] = {
+ type: Date,
+ deserialize: function(value){
+ return dojo.date.stamp.fromISOString(value);
+ }
+ };
+ }
+ this._features = {'dojo.data.api.Read':true, 'dojo.data.api.Identity':true};
+ this._itemsByIdentity = null;
+ this._storeRefPropName = "_S"; // Default name for the store reference to attach to every item.
+ this._itemNumPropName = "_0"; // Default Item Id for isItem to attach to every item.
+ this._rootItemPropName = "_RI"; // Default Item Id for isItem to attach to every item.
+ this._reverseRefMap = "_RRM"; // Default attribute for constructing a reverse reference map for use with reference integrity
+ this._loadInProgress = false; //Got to track the initial load to prevent duelling loads of the dataset.
+ this._queuedFetches = [];
+ if(keywordParameters.urlPreventCache !== undefined){
+ this.urlPreventCache = keywordParameters.urlPreventCache?true:false;
+ }
+ if(keywordParameters.hierarchical !== undefined){
+ this.hierarchical = keywordParameters.hierarchical?true:false;
+ }
+ if(keywordParameters.clearOnClose){
+ this.clearOnClose = true;
+ }
+ if("failOk" in keywordParameters){
+ this.failOk = keywordParameters.failOk?true:false;
+ }
+ },
+
+ url: "", // use "" rather than undefined for the benefit of the parser (#3539)
+
+ //Internal var, crossCheckUrl. Used so that setting either url or _jsonFileUrl, can still trigger a reload
+ //when clearOnClose and close is used.
+ _ccUrl: "",
+
+ data: null, // define this so that the parser can populate it
+
+ typeMap: null, //Define so parser can populate.
+
+ //Parameter to allow users to specify if a close call should force a reload or not.
+ //By default, it retains the old behavior of not clearing if close is called. But
+ //if set true, the store will be reset to default state. Note that by doing this,
+ //all item handles will become invalid and a new fetch must be issued.
+ clearOnClose: false,
+
+ //Parameter to allow specifying if preventCache should be passed to the xhrGet call or not when loading data from a url.
+ //Note this does not mean the store calls the server on each fetch, only that the data load has preventCache set as an option.
+ //Added for tracker: #6072
+ urlPreventCache: false,
+
+ //Parameter for specifying that it is OK for the xhrGet call to fail silently.
+ failOk: false,
+
+ //Parameter to indicate to process data from the url as hierarchical
+ //(data items can contain other data items in js form). Default is true
+ //for backwards compatibility. False means only root items are processed
+ //as items, all child objects outside of type-mapped objects and those in
+ //specific reference format, are left straight JS data objects.
+ hierarchical: true,
+
+ _assertIsItem: function(/* item */ item){
+ // summary:
+ // This function tests whether the item passed in is indeed an item in the store.
+ // item:
+ // The item to test for being contained by the store.
+ if(!this.isItem(item)){
+ throw new Error("dojo.data.ItemFileReadStore: Invalid item argument.");
+ }
+ },
+
+ _assertIsAttribute: function(/* attribute-name-string */ attribute){
+ // summary:
+ // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
+ // attribute:
+ // The attribute to test for being contained by the store.
+ if(typeof attribute !== "string"){
+ throw new Error("dojo.data.ItemFileReadStore: Invalid attribute argument.");
+ }
+ },
+
+ getValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* value? */ defaultValue){
+ // summary:
+ // See dojo.data.api.Read.getValue()
+ var values = this.getValues(item, attribute);
+ return (values.length > 0)?values[0]:defaultValue; // mixed
+ },
+
+ getValues: function(/* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.getValues()
+
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ // Clone it before returning. refs: #10474
+ return (item[attribute] || []).slice(0); // Array
+ },
+
+ getAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getAttributes()
+ this._assertIsItem(item);
+ var attributes = [];
+ for(var key in item){
+ // Save off only the real item attributes, not the special id marks for O(1) isItem.
+ if((key !== this._storeRefPropName) && (key !== this._itemNumPropName) && (key !== this._rootItemPropName) && (key !== this._reverseRefMap)){
+ attributes.push(key);
+ }
+ }
+ return attributes; // Array
+ },
+
+ hasAttribute: function( /* item */ item,
+ /* attribute-name-string */ attribute){
+ // summary:
+ // See dojo.data.api.Read.hasAttribute()
+ this._assertIsItem(item);
+ this._assertIsAttribute(attribute);
+ return (attribute in item);
+ },
+
+ containsValue: function(/* item */ item,
+ /* attribute-name-string */ attribute,
+ /* anything */ value){
+ // summary:
+ // See dojo.data.api.Read.containsValue()
+ var regexp = undefined;
+ if(typeof value === "string"){
+ regexp = dojo.data.util.filter.patternToRegExp(value, false);
+ }
+ return this._containsValue(item, attribute, value, regexp); //boolean.
+ },
+
+ _containsValue: function( /* item */ item,
+ /* attribute-name-string */ attribute,
+ /* anything */ value,
+ /* RegExp?*/ regexp){
+ // summary:
+ // Internal function for looking at the values contained by the item.
+ // description:
+ // Internal function for looking at the values contained by the item. This
+ // function allows for denoting if the comparison should be case sensitive for
+ // strings or not (for handling filtering cases where string case should not matter)
+ //
+ // item:
+ // The data item to examine for attribute values.
+ // attribute:
+ // The attribute to inspect.
+ // value:
+ // The value to match.
+ // regexp:
+ // Optional regular expression generated off value if value was of string type to handle wildcarding.
+ // If present and attribute values are string, then it can be used for comparison instead of 'value'
+ return dojo.some(this.getValues(item, attribute), function(possibleValue){
+ if(possibleValue !== null && !dojo.isObject(possibleValue) && regexp){
+ if(possibleValue.toString().match(regexp)){
+ return true; // Boolean
+ }
+ }else if(value === possibleValue){
+ return true; // Boolean
+ }
+ });
+ },
+
+ isItem: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItem()
+ if(something && something[this._storeRefPropName] === this){
+ if(this._arrayOfAllItems[something[this._itemNumPropName]] === something){
+ return true;
+ }
+ }
+ return false; // Boolean
+ },
+
+ isItemLoaded: function(/* anything */ something){
+ // summary:
+ // See dojo.data.api.Read.isItemLoaded()
+ return this.isItem(something); //boolean
+ },
+
+ loadItem: function(/* object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Read.loadItem()
+ this._assertIsItem(keywordArgs.item);
+ },
+
+ getFeatures: function(){
+ // summary:
+ // See dojo.data.api.Read.getFeatures()
+ return this._features; //Object
+ },
+
+ getLabel: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabel()
+ if(this._labelAttr && this.isItem(item)){
+ return this.getValue(item,this._labelAttr); //String
+ }
+ return undefined; //undefined
+ },
+
+ getLabelAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Read.getLabelAttributes()
+ if(this._labelAttr){
+ return [this._labelAttr]; //array
+ }
+ return null; //null
+ },
+
+ _fetchItems: function( /* Object */ keywordArgs,
+ /* Function */ findCallback,
+ /* Function */ errorCallback){
+ // summary:
+ // See dojo.data.util.simpleFetch.fetch()
+ var self = this,
+ filter = function(requestArgs, arrayOfItems){
+ var items = [],
+ i, key;
+ if(requestArgs.query){
+ var value,
+ ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false;
+
+ //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
+ //same value for each item examined. Much more efficient.
+ var regexpList = {};
+ for(key in requestArgs.query){
+ value = requestArgs.query[key];
+ if(typeof value === "string"){
+ regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
+ }else if(value instanceof RegExp){
+ regexpList[key] = value;
+ }
+ }
+ for(i = 0; i < arrayOfItems.length; ++i){
+ var match = true;
+ var candidateItem = arrayOfItems[i];
+ if(candidateItem === null){
+ match = false;
+ }else{
+ for(key in requestArgs.query){
+ value = requestArgs.query[key];
+ if(!self._containsValue(candidateItem, key, value, regexpList[key])){
+ match = false;
+ }
+ }
+ }
+ if(match){
+ items.push(candidateItem);
+ }
+ }
+ findCallback(items, requestArgs);
+ }else{
+ // We want a copy to pass back in case the parent wishes to sort the array.
+ // We shouldn't allow resort of the internal list, so that multiple callers
+ // can get lists and sort without affecting each other. We also need to
+ // filter out any null values that have been left as a result of deleteItem()
+ // calls in ItemFileWriteStore.
+ for(i = 0; i < arrayOfItems.length; ++i){
+ var item = arrayOfItems[i];
+ if(item !== null){
+ items.push(item);
+ }
+ }
+ findCallback(items, requestArgs);
+ }
+ };
+
+ if(this._loadFinished){
+ filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
+ }else{
+ //Do a check on the JsonFileUrl and crosscheck it.
+ //If it doesn't match the cross-check, it needs to be updated
+ //This allows for either url or _jsonFileUrl to he changed to
+ //reset the store load location. Done this way for backwards
+ //compatibility. People use _jsonFileUrl (even though officially
+ //private.
+ if(this._jsonFileUrl !== this._ccUrl){
+ dojo.deprecated("dojo.data.ItemFileReadStore: ",
+ "To change the url, set the url property of the store," +
+ " not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
+ this._ccUrl = this._jsonFileUrl;
+ this.url = this._jsonFileUrl;
+ }else if(this.url !== this._ccUrl){
+ this._jsonFileUrl = this.url;
+ this._ccUrl = this.url;
+ }
+
+ //See if there was any forced reset of data.
+ if(this.data != null && this._jsonData == null){
+ this._jsonData = this.data;
+ this.data = null;
+ }
+
+ if(this._jsonFileUrl){
+ //If fetches come in before the loading has finished, but while
+ //a load is in progress, we have to defer the fetching to be
+ //invoked in the callback.
+ if(this._loadInProgress){
+ this._queuedFetches.push({args: keywordArgs, filter: filter});
+ }else{
+ this._loadInProgress = true;
+ var getArgs = {
+ url: self._jsonFileUrl,
+ handleAs: "json-comment-optional",
+ preventCache: this.urlPreventCache,
+ failOk: this.failOk
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ try{
+ self._getItemsFromLoadedData(data);
+ self._loadFinished = true;
+ self._loadInProgress = false;
+
+ filter(keywordArgs, self._getItemsArray(keywordArgs.queryOptions));
+ self._handleQueuedFetches();
+ }catch(e){
+ self._loadFinished = true;
+ self._loadInProgress = false;
+ errorCallback(e, keywordArgs);
+ }
+ });
+ getHandler.addErrback(function(error){
+ self._loadInProgress = false;
+ errorCallback(error, keywordArgs);
+ });
+
+ //Wire up the cancel to abort of the request
+ //This call cancel on the deferred if it hasn't been called
+ //yet and then will chain to the simple abort of the
+ //simpleFetch keywordArgs
+ var oldAbort = null;
+ if(keywordArgs.abort){
+ oldAbort = keywordArgs.abort;
+ }
+ keywordArgs.abort = function(){
+ var df = getHandler;
+ if(df && df.fired === -1){
+ df.cancel();
+ df = null;
+ }
+ if(oldAbort){
+ oldAbort.call(keywordArgs);
+ }
+ };
+ }
+ }else if(this._jsonData){
+ try{
+ this._loadFinished = true;
+ this._getItemsFromLoadedData(this._jsonData);
+ this._jsonData = null;
+ filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
+ }catch(e){
+ errorCallback(e, keywordArgs);
+ }
+ }else{
+ errorCallback(new Error("dojo.data.ItemFileReadStore: No JSON source data was provided as either URL or a nested Javascript object."), keywordArgs);
+ }
+ }
+ },
+
+ _handleQueuedFetches: function(){
+ // summary:
+ // Internal function to execute delayed request in the store.
+ //Execute any deferred fetches now.
+ if(this._queuedFetches.length > 0){
+ for(var i = 0; i < this._queuedFetches.length; i++){
+ var fData = this._queuedFetches[i],
+ delayedQuery = fData.args,
+ delayedFilter = fData.filter;
+ if(delayedFilter){
+ delayedFilter(delayedQuery, this._getItemsArray(delayedQuery.queryOptions));
+ }else{
+ this.fetchItemByIdentity(delayedQuery);
+ }
+ }
+ this._queuedFetches = [];
+ }
+ },
+
+ _getItemsArray: function(/*object?*/queryOptions){
+ // summary:
+ // Internal function to determine which list of items to search over.
+ // queryOptions: The query options parameter, if any.
+ if(queryOptions && queryOptions.deep){
+ return this._arrayOfAllItems;
+ }
+ return this._arrayOfTopLevelItems;
+ },
+
+ close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+ // summary:
+ // See dojo.data.api.Read.close()
+ if(this.clearOnClose &&
+ this._loadFinished &&
+ !this._loadInProgress){
+ //Reset all internalsback to default state. This will force a reload
+ //on next fetch. This also checks that the data or url param was set
+ //so that the store knows it can get data. Without one of those being set,
+ //the next fetch will trigger an error.
+
+ if(((this._jsonFileUrl == "" || this._jsonFileUrl == null) &&
+ (this.url == "" || this.url == null)
+ ) && this.data == null){
+ console.debug("dojo.data.ItemFileReadStore: WARNING! Data reload " +
+ " information has not been provided." +
+ " Please set 'url' or 'data' to the appropriate value before" +
+ " the next fetch");
+ }
+ this._arrayOfAllItems = [];
+ this._arrayOfTopLevelItems = [];
+ this._loadFinished = false;
+ this._itemsByIdentity = null;
+ this._loadInProgress = false;
+ this._queuedFetches = [];
+ }
+ },
+
+ _getItemsFromLoadedData: function(/* Object */ dataObject){
+ // summary:
+ // Function to parse the loaded data into item format and build the internal items array.
+ // description:
+ // Function to parse the loaded data into item format and build the internal items array.
+ //
+ // dataObject:
+ // The JS data object containing the raw data to convery into item format.
+ //
+ // returns: array
+ // Array of items in store item format.
+
+ // First, we define a couple little utility functions...
+ var addingArrays = false,
+ self = this;
+
+ function valueIsAnItem(/* anything */ aValue){
+ // summary:
+ // Given any sort of value that could be in the raw json data,
+ // return true if we should interpret the value as being an
+ // item itself, rather than a literal value or a reference.
+ // example:
+ // | false == valueIsAnItem("Kermit");
+ // | false == valueIsAnItem(42);
+ // | false == valueIsAnItem(new Date());
+ // | false == valueIsAnItem({_type:'Date', _value:'May 14, 1802'});
+ // | false == valueIsAnItem({_reference:'Kermit'});
+ // | true == valueIsAnItem({name:'Kermit', color:'green'});
+ // | true == valueIsAnItem({iggy:'pop'});
+ // | true == valueIsAnItem({foo:42});
+ var isItem = (
+ (aValue !== null) &&
+ (typeof aValue === "object") &&
+ (!dojo.isArray(aValue) || addingArrays) &&
+ (!dojo.isFunction(aValue)) &&
+ (aValue.constructor == Object || dojo.isArray(aValue)) &&
+ (typeof aValue._reference === "undefined") &&
+ (typeof aValue._type === "undefined") &&
+ (typeof aValue._value === "undefined") &&
+ self.hierarchical
+ );
+ return isItem;
+ }
+
+ function addItemAndSubItemsToArrayOfAllItems(/* Item */ anItem){
+ self._arrayOfAllItems.push(anItem);
+ for(var attribute in anItem){
+ var valueForAttribute = anItem[attribute];
+ if(valueForAttribute){
+ if(dojo.isArray(valueForAttribute)){
+ var valueArray = valueForAttribute;
+ for(var k = 0; k < valueArray.length; ++k){
+ var singleValue = valueArray[k];
+ if(valueIsAnItem(singleValue)){
+ addItemAndSubItemsToArrayOfAllItems(singleValue);
+ }
+ }
+ }else{
+ if(valueIsAnItem(valueForAttribute)){
+ addItemAndSubItemsToArrayOfAllItems(valueForAttribute);
+ }
+ }
+ }
+ }
+ }
+
+ this._labelAttr = dataObject.label;
+
+ // We need to do some transformations to convert the data structure
+ // that we read from the file into a format that will be convenient
+ // to work with in memory.
+
+ // Step 1: Walk through the object hierarchy and build a list of all items
+ var i,
+ item;
+ this._arrayOfAllItems = [];
+ this._arrayOfTopLevelItems = dataObject.items;
+
+ for(i = 0; i < this._arrayOfTopLevelItems.length; ++i){
+ item = this._arrayOfTopLevelItems[i];
+ if(dojo.isArray(item)){
+ addingArrays = true;
+ }
+ addItemAndSubItemsToArrayOfAllItems(item);
+ item[this._rootItemPropName]=true;
+ }
+
+ // Step 2: Walk through all the attribute values of all the items,
+ // and replace single values with arrays. For example, we change this:
+ // { name:'Miss Piggy', pets:'Foo-Foo'}
+ // into this:
+ // { name:['Miss Piggy'], pets:['Foo-Foo']}
+ //
+ // We also store the attribute names so we can validate our store
+ // reference and item id special properties for the O(1) isItem
+ var allAttributeNames = {},
+ key;
+
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i];
+ for(key in item){
+ if(key !== this._rootItemPropName){
+ var value = item[key];
+ if(value !== null){
+ if(!dojo.isArray(value)){
+ item[key] = [value];
+ }
+ }else{
+ item[key] = [null];
+ }
+ }
+ allAttributeNames[key]=key;
+ }
+ }
+
+ // Step 3: Build unique property names to use for the _storeRefPropName and _itemNumPropName
+ // This should go really fast, it will generally never even run the loop.
+ while(allAttributeNames[this._storeRefPropName]){
+ this._storeRefPropName += "_";
+ }
+ while(allAttributeNames[this._itemNumPropName]){
+ this._itemNumPropName += "_";
+ }
+ while(allAttributeNames[this._reverseRefMap]){
+ this._reverseRefMap += "_";
+ }
+
+ // Step 4: Some data files specify an optional 'identifier', which is
+ // the name of an attribute that holds the identity of each item.
+ // If this data file specified an identifier attribute, then build a
+ // hash table of items keyed by the identity of the items.
+ var arrayOfValues;
+
+ var identifier = dataObject.identifier;
+ if(identifier){
+ this._itemsByIdentity = {};
+ this._features['dojo.data.api.Identity'] = identifier;
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i];
+ arrayOfValues = item[identifier];
+ var identity = arrayOfValues[0];
+ if(!this._itemsByIdentity[identity]){
+ this._itemsByIdentity[identity] = item;
+ }else{
+ if(this._jsonFileUrl){
+ throw new Error("dojo.data.ItemFileReadStore: The json data as specified by: [" + this._jsonFileUrl + "] is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]");
+ }else if(this._jsonData){
+ throw new Error("dojo.data.ItemFileReadStore: The json data provided by the creation arguments is malformed. Items within the list have identifier: [" + identifier + "]. Value collided: [" + identity + "]");
+ }
+ }
+ }
+ }else{
+ this._features['dojo.data.api.Identity'] = Number;
+ }
+
+ // Step 5: Walk through all the items, and set each item's properties
+ // for _storeRefPropName and _itemNumPropName, so that store.isItem() will return true.
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i];
+ item[this._storeRefPropName] = this;
+ item[this._itemNumPropName] = i;
+ }
+
+ // Step 6: We walk through all the attribute values of all the items,
+ // looking for type/value literals and item-references.
+ //
+ // We replace item-references with pointers to items. For example, we change:
+ // { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
+ // into this:
+ // { name:['Kermit'], friends:[miss_piggy] }
+ // (where miss_piggy is the object representing the 'Miss Piggy' item).
+ //
+ // We replace type/value pairs with typed-literals. For example, we change:
+ // { name:['Nelson Mandela'], born:[{_type:'Date', _value:'July 18, 1918'}] }
+ // into this:
+ // { name:['Kermit'], born:(new Date('July 18, 1918')) }
+ //
+ // We also generate the associate map for all items for the O(1) isItem function.
+ for(i = 0; i < this._arrayOfAllItems.length; ++i){
+ item = this._arrayOfAllItems[i]; // example: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
+ for(key in item){
+ arrayOfValues = item[key]; // example: [{_reference:{name:'Miss Piggy'}}]
+ for(var j = 0; j < arrayOfValues.length; ++j){
+ value = arrayOfValues[j]; // example: {_reference:{name:'Miss Piggy'}}
+ if(value !== null && typeof value == "object"){
+ if(("_type" in value) && ("_value" in value)){
+ var type = value._type; // examples: 'Date', 'Color', or 'ComplexNumber'
+ var mappingObj = this._datatypeMap[type]; // examples: Date, dojo.Color, foo.math.ComplexNumber, {type: dojo.Color, deserialize(value){ return new dojo.Color(value)}}
+ if(!mappingObj){
+ throw new Error("dojo.data.ItemFileReadStore: in the typeMap constructor arg, no object class was specified for the datatype '" + type + "'");
+ }else if(dojo.isFunction(mappingObj)){
+ arrayOfValues[j] = new mappingObj(value._value);
+ }else if(dojo.isFunction(mappingObj.deserialize)){
+ arrayOfValues[j] = mappingObj.deserialize(value._value);
+ }else{
+ throw new Error("dojo.data.ItemFileReadStore: Value provided in typeMap was neither a constructor, nor a an object with a deserialize function");
+ }
+ }
+ if(value._reference){
+ var referenceDescription = value._reference; // example: {name:'Miss Piggy'}
+ if(!dojo.isObject(referenceDescription)){
+ // example: 'Miss Piggy'
+ // from an item like: { name:['Kermit'], friends:[{_reference:'Miss Piggy'}]}
+ arrayOfValues[j] = this._getItemByIdentity(referenceDescription);
+ }else{
+ // example: {name:'Miss Piggy'}
+ // from an item like: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
+ for(var k = 0; k < this._arrayOfAllItems.length; ++k){
+ var candidateItem = this._arrayOfAllItems[k],
+ found = true;
+ for(var refKey in referenceDescription){
+ if(candidateItem[refKey] != referenceDescription[refKey]){
+ found = false;
+ }
+ }
+ if(found){
+ arrayOfValues[j] = candidateItem;
+ }
+ }
+ }
+ if(this.referenceIntegrity){
+ var refItem = arrayOfValues[j];
+ if(this.isItem(refItem)){
+ this._addReferenceToMap(refItem, item, key);
+ }
+ }
+ }else if(this.isItem(value)){
+ //It's a child item (not one referenced through _reference).
+ //We need to treat this as a referenced item, so it can be cleaned up
+ //in a write store easily.
+ if(this.referenceIntegrity){
+ this._addReferenceToMap(value, item, key);
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+
+ _addReferenceToMap: function(/*item*/ refItem, /*item*/ parentItem, /*string*/ attribute){
+ // summary:
+ // Method to add an reference map entry for an item and attribute.
+ // description:
+ // Method to add an reference map entry for an item and attribute. //
+ // refItem:
+ // The item that is referenced.
+ // parentItem:
+ // The item that holds the new reference to refItem.
+ // attribute:
+ // The attribute on parentItem that contains the new reference.
+
+ //Stub function, does nothing. Real processing is in ItemFileWriteStore.
+ },
+
+ getIdentity: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentity()
+ var identifier = this._features['dojo.data.api.Identity'];
+ if(identifier === Number){
+ return item[this._itemNumPropName]; // Number
+ }else{
+ var arrayOfValues = item[identifier];
+ if(arrayOfValues){
+ return arrayOfValues[0]; // Object || String
+ }
+ }
+ return null; // null
+ },
+
+ fetchItemByIdentity: function(/* Object */ keywordArgs){
+ // summary:
+ // See dojo.data.api.Identity.fetchItemByIdentity()
+
+ // Hasn't loaded yet, we have to trigger the load.
+ var item,
+ scope;
+ if(!this._loadFinished){
+ var self = this;
+ //Do a check on the JsonFileUrl and crosscheck it.
+ //If it doesn't match the cross-check, it needs to be updated
+ //This allows for either url or _jsonFileUrl to he changed to
+ //reset the store load location. Done this way for backwards
+ //compatibility. People use _jsonFileUrl (even though officially
+ //private.
+ if(this._jsonFileUrl !== this._ccUrl){
+ dojo.deprecated("dojo.data.ItemFileReadStore: ",
+ "To change the url, set the url property of the store," +
+ " not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
+ this._ccUrl = this._jsonFileUrl;
+ this.url = this._jsonFileUrl;
+ }else if(this.url !== this._ccUrl){
+ this._jsonFileUrl = this.url;
+ this._ccUrl = this.url;
+ }
+
+ //See if there was any forced reset of data.
+ if(this.data != null && this._jsonData == null){
+ this._jsonData = this.data;
+ this.data = null;
+ }
+
+ if(this._jsonFileUrl){
+
+ if(this._loadInProgress){
+ this._queuedFetches.push({args: keywordArgs});
+ }else{
+ this._loadInProgress = true;
+ var getArgs = {
+ url: self._jsonFileUrl,
+ handleAs: "json-comment-optional",
+ preventCache: this.urlPreventCache,
+ failOk: this.failOk
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ try{
+ self._getItemsFromLoadedData(data);
+ self._loadFinished = true;
+ self._loadInProgress = false;
+ item = self._getItemByIdentity(keywordArgs.identity);
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, item);
+ }
+ self._handleQueuedFetches();
+ }catch(error){
+ self._loadInProgress = false;
+ if(keywordArgs.onError){
+ keywordArgs.onError.call(scope, error);
+ }
+ }
+ });
+ getHandler.addErrback(function(error){
+ self._loadInProgress = false;
+ if(keywordArgs.onError){
+ var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onError.call(scope, error);
+ }
+ });
+ }
+
+ }else if(this._jsonData){
+ // Passed in data, no need to xhr.
+ self._getItemsFromLoadedData(self._jsonData);
+ self._jsonData = null;
+ self._loadFinished = true;
+ item = self._getItemByIdentity(keywordArgs.identity);
+ if(keywordArgs.onItem){
+ scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ }else{
+ // Already loaded. We can just look it up and call back.
+ item = this._getItemByIdentity(keywordArgs.identity);
+ if(keywordArgs.onItem){
+ scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+ keywordArgs.onItem.call(scope, item);
+ }
+ }
+ },
+
+ _getItemByIdentity: function(/* Object */ identity){
+ // summary:
+ // Internal function to look an item up by its identity map.
+ var item = null;
+ if(this._itemsByIdentity){
+ item = this._itemsByIdentity[identity];
+ }else{
+ item = this._arrayOfAllItems[identity];
+ }
+ if(item === undefined){
+ item = null;
+ }
+ return item; // Object
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentifierAttributes()
+
+ var identifier = this._features['dojo.data.api.Identity'];
+ if(identifier === Number){
+ // If (identifier === Number) it means getIdentity() just returns
+ // an integer item-number for each item. The dojo.data.api.Identity
+ // spec says we need to return null if the identity is not composed
+ // of attributes
+ return null; // null
+ }else{
+ return [identifier]; // Array
+ }
+ },
+
+ _forceLoad: function(){
+ // summary:
+ // Internal function to force a load of the store if it hasn't occurred yet. This is required
+ // for specific functions to work properly.
+ var self = this;
+ //Do a check on the JsonFileUrl and crosscheck it.
+ //If it doesn't match the cross-check, it needs to be updated
+ //This allows for either url or _jsonFileUrl to he changed to
+ //reset the store load location. Done this way for backwards
+ //compatibility. People use _jsonFileUrl (even though officially
+ //private.
+ if(this._jsonFileUrl !== this._ccUrl){
+ dojo.deprecated("dojo.data.ItemFileReadStore: ",
+ "To change the url, set the url property of the store," +
+ " not _jsonFileUrl. _jsonFileUrl support will be removed in 2.0");
+ this._ccUrl = this._jsonFileUrl;
+ this.url = this._jsonFileUrl;
+ }else if(this.url !== this._ccUrl){
+ this._jsonFileUrl = this.url;
+ this._ccUrl = this.url;
+ }
+
+ //See if there was any forced reset of data.
+ if(this.data != null && this._jsonData == null){
+ this._jsonData = this.data;
+ this.data = null;
+ }
+
+ if(this._jsonFileUrl){
+ var getArgs = {
+ url: this._jsonFileUrl,
+ handleAs: "json-comment-optional",
+ preventCache: this.urlPreventCache,
+ failOk: this.failOk,
+ sync: true
+ };
+ var getHandler = dojo.xhrGet(getArgs);
+ getHandler.addCallback(function(data){
+ try{
+ //Check to be sure there wasn't another load going on concurrently
+ //So we don't clobber data that comes in on it. If there is a load going on
+ //then do not save this data. It will potentially clobber current data.
+ //We mainly wanted to sync/wait here.
+ //TODO: Revisit the loading scheme of this store to improve multi-initial
+ //request handling.
+ if(self._loadInProgress !== true && !self._loadFinished){
+ self._getItemsFromLoadedData(data);
+ self._loadFinished = true;
+ }else if(self._loadInProgress){
+ //Okay, we hit an error state we can't recover from. A forced load occurred
+ //while an async load was occurring. Since we cannot block at this point, the best
+ //that can be managed is to throw an error.
+ throw new Error("dojo.data.ItemFileReadStore: Unable to perform a synchronous load, an async load is in progress.");
+ }
+ }catch(e){
+ console.log(e);
+ throw e;
+ }
+ });
+ getHandler.addErrback(function(error){
+ throw error;
+ });
+ }else if(this._jsonData){
+ self._getItemsFromLoadedData(self._jsonData);
+ self._jsonData = null;
+ self._loadFinished = true;
+ }
+ }
+});
+//Mix in the simple fetch implementation to this class.
+dojo.extend(dojo.data.ItemFileReadStore,dojo.data.util.simpleFetch);
+
+}
+
+if(!dojo._hasResource["dojo.data.ItemFileWriteStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.data.ItemFileWriteStore"] = true;
+dojo.provide("dojo.data.ItemFileWriteStore");
+
+
+dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
+ constructor: function(/* object */ keywordParameters){
+ // keywordParameters: {typeMap: object)
+ // The structure of the typeMap object is as follows:
+ // {
+ // type0: function || object,
+ // type1: function || object,
+ // ...
+ // typeN: function || object
+ // }
+ // Where if it is a function, it is assumed to be an object constructor that takes the
+ // value of _value as the initialization parameters. It is serialized assuming object.toString()
+ // serialization. If it is an object, then it is assumed
+ // to be an object of general form:
+ // {
+ // type: function, //constructor.
+ // deserialize: function(value) //The function that parses the value and constructs the object defined by type appropriately.
+ // serialize: function(object) //The function that converts the object back into the proper file format form.
+ // }
+
+ // ItemFileWriteStore extends ItemFileReadStore to implement these additional dojo.data APIs
+ this._features['dojo.data.api.Write'] = true;
+ this._features['dojo.data.api.Notification'] = true;
+
+ // For keeping track of changes so that we can implement isDirty and revert
+ this._pending = {
+ _newItems:{},
+ _modifiedItems:{},
+ _deletedItems:{}
+ };
+
+ if(!this._datatypeMap['Date'].serialize){
+ this._datatypeMap['Date'].serialize = function(obj){
+ return dojo.date.stamp.toISOString(obj, {zulu:true});
+ };
+ }
+ //Disable only if explicitly set to false.
+ if(keywordParameters && (keywordParameters.referenceIntegrity === false)){
+ this.referenceIntegrity = false;
+ }
+
+ // this._saveInProgress is set to true, briefly, from when save() is first called to when it completes
+ this._saveInProgress = false;
+ },
+
+ referenceIntegrity: true, //Flag that defaultly enabled reference integrity tracking. This way it can also be disabled pogrammatially or declaratively.
+
+ _assert: function(/* boolean */ condition){
+ if(!condition){
+ throw new Error("assertion failed in ItemFileWriteStore");
+ }
+ },
+
+ _getIdentifierAttribute: function(){
+ var identifierAttribute = this.getFeatures()['dojo.data.api.Identity'];
+ // this._assert((identifierAttribute === Number) || (dojo.isString(identifierAttribute)));
+ return identifierAttribute;
+ },
+
+
+/* dojo.data.api.Write */
+
+ newItem: function(/* Object? */ keywordArgs, /* Object? */ parentInfo){
+ // summary: See dojo.data.api.Write.newItem()
+
+ this._assert(!this._saveInProgress);
+
+ if(!this._loadFinished){
+ // We need to do this here so that we'll be able to find out what
+ // identifierAttribute was specified in the data file.
+ this._forceLoad();
+ }
+
+ if(typeof keywordArgs != "object" && typeof keywordArgs != "undefined"){
+ throw new Error("newItem() was passed something other than an object");
+ }
+ var newIdentity = null;
+ var identifierAttribute = this._getIdentifierAttribute();
+ if(identifierAttribute === Number){
+ newIdentity = this._arrayOfAllItems.length;
+ }else{
+ newIdentity = keywordArgs[identifierAttribute];
+ if(typeof newIdentity === "undefined"){
+ throw new Error("newItem() was not passed an identity for the new item");
+ }
+ if(dojo.isArray(newIdentity)){
+ throw new Error("newItem() was not passed an single-valued identity");
+ }
+ }
+
+ // make sure this identity is not already in use by another item, if identifiers were
+ // defined in the file. Otherwise it would be the item count,
+ // which should always be unique in this case.
+ if(this._itemsByIdentity){
+ this._assert(typeof this._itemsByIdentity[newIdentity] === "undefined");
+ }
+ this._assert(typeof this._pending._newItems[newIdentity] === "undefined");
+ this._assert(typeof this._pending._deletedItems[newIdentity] === "undefined");
+
+ var newItem = {};
+ newItem[this._storeRefPropName] = this;
+ newItem[this._itemNumPropName] = this._arrayOfAllItems.length;
+ if(this._itemsByIdentity){
+ this._itemsByIdentity[newIdentity] = newItem;
+ //We have to set the identifier now, otherwise we can't look it
+ //up at calls to setValueorValues in parentInfo handling.
+ newItem[identifierAttribute] = [newIdentity];
+ }
+ this._arrayOfAllItems.push(newItem);
+
+ //We need to construct some data for the onNew call too...
+ var pInfo = null;
+
+ // Now we need to check to see where we want to assign this thingm if any.
+ if(parentInfo && parentInfo.parent && parentInfo.attribute){
+ pInfo = {
+ item: parentInfo.parent,
+ attribute: parentInfo.attribute,
+ oldValue: undefined
+ };
+
+ //See if it is multi-valued or not and handle appropriately
+ //Generally, all attributes are multi-valued for this store
+ //So, we only need to append if there are already values present.
+ var values = this.getValues(parentInfo.parent, parentInfo.attribute);
+ if(values && values.length > 0){
+ var tempValues = values.slice(0, values.length);
+ if(values.length === 1){
+ pInfo.oldValue = values[0];
+ }else{
+ pInfo.oldValue = values.slice(0, values.length);
+ }
+ tempValues.push(newItem);
+ this._setValueOrValues(parentInfo.parent, parentInfo.attribute, tempValues, false);
+ pInfo.newValue = this.getValues(parentInfo.parent, parentInfo.attribute);
+ }else{
+ this._setValueOrValues(parentInfo.parent, parentInfo.attribute, newItem, false);
+ pInfo.newValue = newItem;
+ }
+ }else{
+ //Toplevel item, add to both top list as well as all list.
+ newItem[this._rootItemPropName]=true;
+ this._arrayOfTopLevelItems.push(newItem);
+ }
+
+ this._pending._newItems[newIdentity] = newItem;
+
+ //Clone over the properties to the new item
+ for(var key in keywordArgs){
+ if(key === this._storeRefPropName || key === this._itemNumPropName){
+ // Bummer, the user is trying to do something like
+ // newItem({_S:"foo"}). Unfortunately, our superclass,
+ // ItemFileReadStore, is already using _S in each of our items
+ // to hold private info. To avoid a naming collision, we
+ // need to move all our private info to some other property
+ // of all the items/objects. So, we need to iterate over all
+ // the items and do something like:
+ // item.__S = item._S;
+ // item._S = undefined;
+ // But first we have to make sure the new "__S" variable is
+ // not in use, which means we have to iterate over all the
+ // items checking for that.
+ throw new Error("encountered bug in ItemFileWriteStore.newItem");
+ }
+ var value = keywordArgs[key];
+ if(!dojo.isArray(value)){
+ value = [value];
+ }
+ newItem[key] = value;
+ if(this.referenceIntegrity){
+ for(var i = 0; i < value.length; i++){
+ var val = value[i];
+ if(this.isItem(val)){
+ this._addReferenceToMap(val, newItem, key);
+ }
+ }
+ }
+ }
+ this.onNew(newItem, pInfo); // dojo.data.api.Notification call
+ return newItem; // item
+ },
+
+ _removeArrayElement: function(/* Array */ array, /* anything */ element){
+ var index = dojo.indexOf(array, element);
+ if(index != -1){
+ array.splice(index, 1);
+ return true;
+ }
+ return false;
+ },
+
+ deleteItem: function(/* item */ item){
+ // summary: See dojo.data.api.Write.deleteItem()
+ this._assert(!this._saveInProgress);
+ this._assertIsItem(item);
+
+ // Remove this item from the _arrayOfAllItems, but leave a null value in place
+ // of the item, so as not to change the length of the array, so that in newItem()
+ // we can still safely do: newIdentity = this._arrayOfAllItems.length;
+ var indexInArrayOfAllItems = item[this._itemNumPropName];
+ var identity = this.getIdentity(item);
+
+ //If we have reference integrity on, we need to do reference cleanup for the deleted item
+ if(this.referenceIntegrity){
+ //First scan all the attributes of this items for references and clean them up in the map
+ //As this item is going away, no need to track its references anymore.
+
+ //Get the attributes list before we generate the backup so it
+ //doesn't pollute the attributes list.
+ var attributes = this.getAttributes(item);
+
+ //Backup the map, we'll have to restore it potentially, in a revert.
+ if(item[this._reverseRefMap]){
+ item["backup_" + this._reverseRefMap] = dojo.clone(item[this._reverseRefMap]);
+ }
+
+ //TODO: This causes a reversion problem. This list won't be restored on revert since it is
+ //attached to the 'value'. item, not ours. Need to back tese up somehow too.
+ //Maybe build a map of the backup of the entries and attach it to the deleted item to be restored
+ //later. Or just record them and call _addReferenceToMap on them in revert.
+ dojo.forEach(attributes, function(attribute){
+ dojo.forEach(this.getValues(item, attribute), function(value){
+ if(this.isItem(value)){
+ //We have to back up all the references we had to others so they can be restored on a revert.
+ if(!item["backupRefs_" + this._reverseRefMap]){
+ item["backupRefs_" + this._reverseRefMap] = [];
+ }
+ item["backupRefs_" + this._reverseRefMap].push({id: this.getIdentity(value), attr: attribute});
+ this._removeReferenceFromMap(value, item, attribute);
+ }
+ }, this);
+ }, this);
+
+ //Next, see if we have references to this item, if we do, we have to clean them up too.
+ var references = item[this._reverseRefMap];
+ if(references){
+ //Look through all the items noted as references to clean them up.
+ for(var itemId in references){
+ var containingItem = null;
+ if(this._itemsByIdentity){
+ containingItem = this._itemsByIdentity[itemId];
+ }else{
+ containingItem = this._arrayOfAllItems[itemId];
+ }
+ //We have a reference to a containing item, now we have to process the
+ //attributes and clear all references to the item being deleted.
+ if(containingItem){
+ for(var attribute in references[itemId]){
+ var oldValues = this.getValues(containingItem, attribute) || [];
+ var newValues = dojo.filter(oldValues, function(possibleItem){
+ return !(this.isItem(possibleItem) && this.getIdentity(possibleItem) == identity);
+ }, this);
+ //Remove the note of the reference to the item and set the values on the modified attribute.
+ this._removeReferenceFromMap(item, containingItem, attribute);
+ if(newValues.length < oldValues.length){
+ this._setValueOrValues(containingItem, attribute, newValues, true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ this._arrayOfAllItems[indexInArrayOfAllItems] = null;
+
+ item[this._storeRefPropName] = null;
+ if(this._itemsByIdentity){
+ delete this._itemsByIdentity[identity];
+ }
+ this._pending._deletedItems[identity] = item;
+
+ //Remove from the toplevel items, if necessary...
+ if(item[this._rootItemPropName]){
+ this._removeArrayElement(this._arrayOfTopLevelItems, item);
+ }
+ this.onDelete(item); // dojo.data.api.Notification call
+ return true;
+ },
+
+ setValue: function(/* item */ item, /* attribute-name-string */ attribute, /* almost anything */ value){
+ // summary: See dojo.data.api.Write.set()
+ return this._setValueOrValues(item, attribute, value, true); // boolean
+ },
+
+ setValues: function(/* item */ item, /* attribute-name-string */ attribute, /* array */ values){
+ // summary: See dojo.data.api.Write.setValues()
+ return this._setValueOrValues(item, attribute, values, true); // boolean
+ },
+
+ unsetAttribute: function(/* item */ item, /* attribute-name-string */ attribute){
+ // summary: See dojo.data.api.Write.unsetAttribute()
+ return this._setValueOrValues(item, attribute, [], true);
+ },
+
+ _setValueOrValues: function(/* item */ item, /* attribute-name-string */ attribute, /* anything */ newValueOrValues, /*boolean?*/ callOnSet){
+ this._assert(!this._saveInProgress);
+
+ // Check for valid arguments
+ this._assertIsItem(item);
+ this._assert(dojo.isString(attribute));
+ this._assert(typeof newValueOrValues !== "undefined");
+
+ // Make sure the user isn't trying to change the item's identity
+ var identifierAttribute = this._getIdentifierAttribute();
+ if(attribute == identifierAttribute){
+ throw new Error("ItemFileWriteStore does not have support for changing the value of an item's identifier.");
+ }
+
+ // To implement the Notification API, we need to make a note of what
+ // the old attribute value was, so that we can pass that info when
+ // we call the onSet method.
+ var oldValueOrValues = this._getValueOrValues(item, attribute);
+
+ var identity = this.getIdentity(item);
+ if(!this._pending._modifiedItems[identity]){
+ // Before we actually change the item, we make a copy of it to
+ // record the original state, so that we'll be able to revert if
+ // the revert method gets called. If the item has already been
+ // modified then there's no need to do this now, since we already
+ // have a record of the original state.
+ var copyOfItemState = {};
+ for(var key in item){
+ if((key === this._storeRefPropName) || (key === this._itemNumPropName) || (key === this._rootItemPropName)){
+ copyOfItemState[key] = item[key];
+ }else if(key === this._reverseRefMap){
+ copyOfItemState[key] = dojo.clone(item[key]);
+ }else{
+ copyOfItemState[key] = item[key].slice(0, item[key].length);
+ }
+ }
+ // Now mark the item as dirty, and save the copy of the original state
+ this._pending._modifiedItems[identity] = copyOfItemState;
+ }
+
+ // Okay, now we can actually change this attribute on the item
+ var success = false;
+
+ if(dojo.isArray(newValueOrValues) && newValueOrValues.length === 0){
+
+ // If we were passed an empty array as the value, that counts
+ // as "unsetting" the attribute, so we need to remove this
+ // attribute from the item.
+ success = delete item[attribute];
+ newValueOrValues = undefined; // used in the onSet Notification call below
+
+ if(this.referenceIntegrity && oldValueOrValues){
+ var oldValues = oldValueOrValues;
+ if(!dojo.isArray(oldValues)){
+ oldValues = [oldValues];
+ }
+ for(var i = 0; i < oldValues.length; i++){
+ var value = oldValues[i];
+ if(this.isItem(value)){
+ this._removeReferenceFromMap(value, item, attribute);
+ }
+ }
+ }
+ }else{
+ var newValueArray;
+ if(dojo.isArray(newValueOrValues)){
+ var newValues = newValueOrValues;
+ // Unfortunately, it's not safe to just do this:
+ // newValueArray = newValues;
+ // Instead, we need to copy the array, which slice() does very nicely.
+ // This is so that our internal data structure won't
+ // get corrupted if the user mucks with the values array *after*
+ // calling setValues().
+ newValueArray = newValueOrValues.slice(0, newValueOrValues.length);
+ }else{
+ newValueArray = [newValueOrValues];
+ }
+
+ //We need to handle reference integrity if this is on.
+ //In the case of set, we need to see if references were added or removed
+ //and update the reference tracking map accordingly.
+ if(this.referenceIntegrity){
+ if(oldValueOrValues){
+ var oldValues = oldValueOrValues;
+ if(!dojo.isArray(oldValues)){
+ oldValues = [oldValues];
+ }
+ //Use an associative map to determine what was added/removed from the list.
+ //Should be O(n) performant. First look at all the old values and make a list of them
+ //Then for any item not in the old list, we add it. If it was already present, we remove it.
+ //Then we pass over the map and any references left it it need to be removed (IE, no match in
+ //the new values list).
+ var map = {};
+ dojo.forEach(oldValues, function(possibleItem){
+ if(this.isItem(possibleItem)){
+ var id = this.getIdentity(possibleItem);
+ map[id.toString()] = true;
+ }
+ }, this);
+ dojo.forEach(newValueArray, function(possibleItem){
+ if(this.isItem(possibleItem)){
+ var id = this.getIdentity(possibleItem);
+ if(map[id.toString()]){
+ delete map[id.toString()];
+ }else{
+ this._addReferenceToMap(possibleItem, item, attribute);
+ }
+ }
+ }, this);
+ for(var rId in map){
+ var removedItem;
+ if(this._itemsByIdentity){
+ removedItem = this._itemsByIdentity[rId];
+ }else{
+ removedItem = this._arrayOfAllItems[rId];
+ }
+ this._removeReferenceFromMap(removedItem, item, attribute);
+ }
+ }else{
+ //Everything is new (no old values) so we have to just
+ //insert all the references, if any.
+ for(var i = 0; i < newValueArray.length; i++){
+ var value = newValueArray[i];
+ if(this.isItem(value)){
+ this._addReferenceToMap(value, item, attribute);
+ }
+ }
+ }
+ }
+ item[attribute] = newValueArray;
+ success = true;
+ }
+
+ // Now we make the dojo.data.api.Notification call
+ if(callOnSet){
+ this.onSet(item, attribute, oldValueOrValues, newValueOrValues);
+ }
+ return success; // boolean
+ },
+
+ _addReferenceToMap: function(/*item*/ refItem, /*item*/ parentItem, /*string*/ attribute){
+ // summary:
+ // Method to add an reference map entry for an item and attribute.
+ // description:
+ // Method to add an reference map entry for an item and attribute. //
+ // refItem:
+ // The item that is referenced.
+ // parentItem:
+ // The item that holds the new reference to refItem.
+ // attribute:
+ // The attribute on parentItem that contains the new reference.
+
+ var parentId = this.getIdentity(parentItem);
+ var references = refItem[this._reverseRefMap];
+
+ if(!references){
+ references = refItem[this._reverseRefMap] = {};
+ }
+ var itemRef = references[parentId];
+ if(!itemRef){
+ itemRef = references[parentId] = {};
+ }
+ itemRef[attribute] = true;
+ },
+
+ _removeReferenceFromMap: function(/* item */ refItem, /* item */ parentItem, /*strin*/ attribute){
+ // summary:
+ // Method to remove an reference map entry for an item and attribute.
+ // description:
+ // Method to remove an reference map entry for an item and attribute. This will
+ // also perform cleanup on the map such that if there are no more references at all to
+ // the item, its reference object and entry are removed.
+ //
+ // refItem:
+ // The item that is referenced.
+ // parentItem:
+ // The item holding a reference to refItem.
+ // attribute:
+ // The attribute on parentItem that contains the reference.
+ var identity = this.getIdentity(parentItem);
+ var references = refItem[this._reverseRefMap];
+ var itemId;
+ if(references){
+ for(itemId in references){
+ if(itemId == identity){
+ delete references[itemId][attribute];
+ if(this._isEmpty(references[itemId])){
+ delete references[itemId];
+ }
+ }
+ }
+ if(this._isEmpty(references)){
+ delete refItem[this._reverseRefMap];
+ }
+ }
+ },
+
+ _dumpReferenceMap: function(){
+ // summary:
+ // Function to dump the reverse reference map of all items in the store for debug purposes.
+ // description:
+ // Function to dump the reverse reference map of all items in the store for debug purposes.
+ var i;
+ for(i = 0; i < this._arrayOfAllItems.length; i++){
+ var item = this._arrayOfAllItems[i];
+ if(item && item[this._reverseRefMap]){
+ console.log("Item: [" + this.getIdentity(item) + "] is referenced by: " + dojo.toJson(item[this._reverseRefMap]));
+ }
+ }
+ },
+
+ _getValueOrValues: function(/* item */ item, /* attribute-name-string */ attribute){
+ var valueOrValues = undefined;
+ if(this.hasAttribute(item, attribute)){
+ var valueArray = this.getValues(item, attribute);
+ if(valueArray.length == 1){
+ valueOrValues = valueArray[0];
+ }else{
+ valueOrValues = valueArray;
+ }
+ }
+ return valueOrValues;
+ },
+
+ _flatten: function(/* anything */ value){
+ if(this.isItem(value)){
+ var item = value;
+ // Given an item, return an serializable object that provides a
+ // reference to the item.
+ // For example, given kermit:
+ // var kermit = store.newItem({id:2, name:"Kermit"});
+ // we want to return
+ // {_reference:2}
+ var identity = this.getIdentity(item);
+ var referenceObject = {_reference: identity};
+ return referenceObject;
+ }else{
+ if(typeof value === "object"){
+ for(var type in this._datatypeMap){
+ var typeMap = this._datatypeMap[type];
+ if(dojo.isObject(typeMap) && !dojo.isFunction(typeMap)){
+ if(value instanceof typeMap.type){
+ if(!typeMap.serialize){
+ throw new Error("ItemFileWriteStore: No serializer defined for type mapping: [" + type + "]");
+ }
+ return {_type: type, _value: typeMap.serialize(value)};
+ }
+ } else if(value instanceof typeMap){
+ //SImple mapping, therefore, return as a toString serialization.
+ return {_type: type, _value: value.toString()};
+ }
+ }
+ }
+ return value;
+ }
+ },
+
+ _getNewFileContentString: function(){
+ // summary:
+ // Generate a string that can be saved to a file.
+ // The result should look similar to:
+ // http://trac.dojotoolkit.org/browser/dojo/trunk/tests/data/countries.json
+ var serializableStructure = {};
+
+ var identifierAttribute = this._getIdentifierAttribute();
+ if(identifierAttribute !== Number){
+ serializableStructure.identifier = identifierAttribute;
+ }
+ if(this._labelAttr){
+ serializableStructure.label = this._labelAttr;
+ }
+ serializableStructure.items = [];
+ for(var i = 0; i < this._arrayOfAllItems.length; ++i){
+ var item = this._arrayOfAllItems[i];
+ if(item !== null){
+ var serializableItem = {};
+ for(var key in item){
+ if(key !== this._storeRefPropName && key !== this._itemNumPropName && key !== this._reverseRefMap && key !== this._rootItemPropName){
+ var attribute = key;
+ var valueArray = this.getValues(item, attribute);
+ if(valueArray.length == 1){
+ serializableItem[attribute] = this._flatten(valueArray[0]);
+ }else{
+ var serializableArray = [];
+ for(var j = 0; j < valueArray.length; ++j){
+ serializableArray.push(this._flatten(valueArray[j]));
+ serializableItem[attribute] = serializableArray;
+ }
+ }
+ }
+ }
+ serializableStructure.items.push(serializableItem);
+ }
+ }
+ var prettyPrint = true;
+ return dojo.toJson(serializableStructure, prettyPrint);
+ },
+
+ _isEmpty: function(something){
+ // summary:
+ // Function to determine if an array or object has no properties or values.
+ // something:
+ // The array or object to examine.
+ var empty = true;
+ if(dojo.isObject(something)){
+ var i;
+ for(i in something){
+ empty = false;
+ break;
+ }
+ }else if(dojo.isArray(something)){
+ if(something.length > 0){
+ empty = false;
+ }
+ }
+ return empty; //boolean
+ },
+
+ save: function(/* object */ keywordArgs){
+ // summary: See dojo.data.api.Write.save()
+ this._assert(!this._saveInProgress);
+
+ // this._saveInProgress is set to true, briefly, from when save is first called to when it completes
+ this._saveInProgress = true;
+
+ var self = this;
+ var saveCompleteCallback = function(){
+ self._pending = {
+ _newItems:{},
+ _modifiedItems:{},
+ _deletedItems:{}
+ };
+
+ self._saveInProgress = false; // must come after this._pending is cleared, but before any callbacks
+ if(keywordArgs && keywordArgs.onComplete){
+ var scope = keywordArgs.scope || dojo.global;
+ keywordArgs.onComplete.call(scope);
+ }
+ };
+ var saveFailedCallback = function(err){
+ self._saveInProgress = false;
+ if(keywordArgs && keywordArgs.onError){
+ var scope = keywordArgs.scope || dojo.global;
+ keywordArgs.onError.call(scope, err);
+ }
+ };
+
+ if(this._saveEverything){
+ var newFileContentString = this._getNewFileContentString();
+ this._saveEverything(saveCompleteCallback, saveFailedCallback, newFileContentString);
+ }
+ if(this._saveCustom){
+ this._saveCustom(saveCompleteCallback, saveFailedCallback);
+ }
+ if(!this._saveEverything && !this._saveCustom){
+ // Looks like there is no user-defined save-handler function.
+ // That's fine, it just means the datastore is acting as a "mock-write"
+ // store -- changes get saved in memory but don't get saved to disk.
+ saveCompleteCallback();
+ }
+ },
+
+ revert: function(){
+ // summary: See dojo.data.api.Write.revert()
+ this._assert(!this._saveInProgress);
+
+ var identity;
+ for(identity in this._pending._modifiedItems){
+ // find the original item and the modified item that replaced it
+ var copyOfItemState = this._pending._modifiedItems[identity];
+ var modifiedItem = null;
+ if(this._itemsByIdentity){
+ modifiedItem = this._itemsByIdentity[identity];
+ }else{
+ modifiedItem = this._arrayOfAllItems[identity];
+ }
+
+ // Restore the original item into a full-fledged item again, we want to try to
+ // keep the same object instance as if we don't it, causes bugs like #9022.
+ copyOfItemState[this._storeRefPropName] = this;
+ for(key in modifiedItem){
+ delete modifiedItem[key];
+ }
+ dojo.mixin(modifiedItem, copyOfItemState);
+ }
+ var deletedItem;
+ for(identity in this._pending._deletedItems){
+ deletedItem = this._pending._deletedItems[identity];
+ deletedItem[this._storeRefPropName] = this;
+ var index = deletedItem[this._itemNumPropName];
+
+ //Restore the reverse refererence map, if any.
+ if(deletedItem["backup_" + this._reverseRefMap]){
+ deletedItem[this._reverseRefMap] = deletedItem["backup_" + this._reverseRefMap];
+ delete deletedItem["backup_" + this._reverseRefMap];
+ }
+ this._arrayOfAllItems[index] = deletedItem;
+ if(this._itemsByIdentity){
+ this._itemsByIdentity[identity] = deletedItem;
+ }
+ if(deletedItem[this._rootItemPropName]){
+ this._arrayOfTopLevelItems.push(deletedItem);
+ }
+ }
+ //We have to pass through it again and restore the reference maps after all the
+ //undeletes have occurred.
+ for(identity in this._pending._deletedItems){
+ deletedItem = this._pending._deletedItems[identity];
+ if(deletedItem["backupRefs_" + this._reverseRefMap]){
+ dojo.forEach(deletedItem["backupRefs_" + this._reverseRefMap], function(reference){
+ var refItem;
+ if(this._itemsByIdentity){
+ refItem = this._itemsByIdentity[reference.id];
+ }else{
+ refItem = this._arrayOfAllItems[reference.id];
+ }
+ this._addReferenceToMap(refItem, deletedItem, reference.attr);
+ }, this);
+ delete deletedItem["backupRefs_" + this._reverseRefMap];
+ }
+ }
+
+ for(identity in this._pending._newItems){
+ var newItem = this._pending._newItems[identity];
+ newItem[this._storeRefPropName] = null;
+ // null out the new item, but don't change the array index so
+ // so we can keep using _arrayOfAllItems.length.
+ this._arrayOfAllItems[newItem[this._itemNumPropName]] = null;
+ if(newItem[this._rootItemPropName]){
+ this._removeArrayElement(this._arrayOfTopLevelItems, newItem);
+ }
+ if(this._itemsByIdentity){
+ delete this._itemsByIdentity[identity];
+ }
+ }
+
+ this._pending = {
+ _newItems:{},
+ _modifiedItems:{},
+ _deletedItems:{}
+ };
+ return true; // boolean
+ },
+
+ isDirty: function(/* item? */ item){
+ // summary: See dojo.data.api.Write.isDirty()
+ if(item){
+ // return true if the item is dirty
+ var identity = this.getIdentity(item);
+ return new Boolean(this._pending._newItems[identity] ||
+ this._pending._modifiedItems[identity] ||
+ this._pending._deletedItems[identity]).valueOf(); // boolean
+ }else{
+ // return true if the store is dirty -- which means return true
+ // if there are any new items, dirty items, or modified items
+ if(!this._isEmpty(this._pending._newItems) ||
+ !this._isEmpty(this._pending._modifiedItems) ||
+ !this._isEmpty(this._pending._deletedItems)){
+ return true;
+ }
+ return false; // boolean
+ }
+ },
+
+/* dojo.data.api.Notification */
+
+ onSet: function(/* item */ item,
+ /*attribute-name-string*/ attribute,
+ /*object | array*/ oldValue,
+ /*object | array*/ newValue){
+ // summary: See dojo.data.api.Notification.onSet()
+
+ // No need to do anything. This method is here just so that the
+ // client code can connect observers to it.
+ },
+
+ onNew: function(/* item */ newItem, /*object?*/ parentInfo){
+ // summary: See dojo.data.api.Notification.onNew()
+
+ // No need to do anything. This method is here just so that the
+ // client code can connect observers to it.
+ },
+
+ onDelete: function(/* item */ deletedItem){
+ // summary: See dojo.data.api.Notification.onDelete()
+
+ // No need to do anything. This method is here just so that the
+ // client code can connect observers to it.
+ },
+
+ close: function(/* object? */ request){
+ // summary:
+ // Over-ride of base close function of ItemFileReadStore to add in check for store state.
+ // description:
+ // Over-ride of base close function of ItemFileReadStore to add in check for store state.
+ // If the store is still dirty (unsaved changes), then an error will be thrown instead of
+ // clearing the internal state for reload from the url.
+
+ //Clear if not dirty ... or throw an error
+ if(this.clearOnClose){
+ if(!this.isDirty()){
+ this.inherited(arguments);
+ }else{
+ //Only throw an error if the store was dirty and we were loading from a url (cannot reload from url until state is saved).
+ throw new Error("dojo.data.ItemFileWriteStore: There are unsaved changes present in the store. Please save or revert the changes before invoking close.");
+ }
+ }
+ }
+});
+
+}
+
+
+dojo.i18n._preloadLocalizations("dojo.nls.tt-rss-layer", ["ROOT","ar","ca","cs","da","de","de-de","el","en","en-gb","en-us","es","es-es","fi","fi-fi","fr","fr-fr","he","he-il","hu","it","it-it","ja","ja-jp","ko","ko-kr","nb","nl","nl-nl","pl","pt","pt-br","pt-pt","ru","sk","sl","sv","th","tr","xx","zh","zh-cn","zh-tw"]);
diff --git a/lib/dojo/uacss.js b/lib/dojo/uacss.js
index a7ba89e0b..781ab9c36 100644
--- a/lib/dojo/uacss.js
+++ b/lib/dojo/uacss.js
@@ -5,24 +5,70 @@
*/
-if(!dojo._hasResource["dojo.uacss"]){
-dojo._hasResource["dojo.uacss"]=true;
+if(!dojo._hasResource["dojo.uacss"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.uacss"] = true;
dojo.provide("dojo.uacss");
+
(function(){
-var d=dojo,_1=d.doc.documentElement,ie=d.isIE,_2=d.isOpera,_3=Math.floor,ff=d.isFF,_4=d.boxModel.replace(/-/,""),_5={dj_ie:ie,dj_ie6:_3(ie)==6,dj_ie7:_3(ie)==7,dj_ie8:_3(ie)==8,dj_quirks:d.isQuirks,dj_iequirks:ie&&d.isQuirks,dj_opera:_2,dj_khtml:d.isKhtml,dj_webkit:d.isWebKit,dj_safari:d.isSafari,dj_chrome:d.isChrome,dj_gecko:d.isMozilla,dj_ff3:_3(ff)==3};
-_5["dj_"+_4]=true;
-var _6="";
-for(var _7 in _5){
-if(_5[_7]){
-_6+=_7+" ";
-}
-}
-_1.className=d.trim(_1.className+" "+_6);
-dojo._loaders.unshift(function(){
-if(!dojo._isBodyLtr()){
-var _8="dj_rtl dijitRtl "+_6.replace(/ /g,"-rtl ");
-_1.className=d.trim(_1.className+" "+_8);
-}
-});
+ // summary:
+ // Applies pre-set CSS classes to the top-level HTML node, based on:
+ // - browser (ex: dj_ie)
+ // - browser version (ex: dj_ie6)
+ // - box model (ex: dj_contentBox)
+ // - text direction (ex: dijitRtl)
+ //
+ // In addition, browser, browser version, and box model are
+ // combined with an RTL flag when browser text is RTL. ex: dj_ie-rtl.
+
+ var d = dojo,
+ html = d.doc.documentElement,
+ ie = d.isIE,
+ opera = d.isOpera,
+ maj = Math.floor,
+ ff = d.isFF,
+ boxModel = d.boxModel.replace(/-/,''),
+
+ classes = {
+ dj_ie: ie,
+ dj_ie6: maj(ie) == 6,
+ dj_ie7: maj(ie) == 7,
+ dj_ie8: maj(ie) == 8,
+ dj_quirks: d.isQuirks,
+ dj_iequirks: ie && d.isQuirks,
+
+ // NOTE: Opera not supported by dijit
+ dj_opera: opera,
+
+ dj_khtml: d.isKhtml,
+
+ dj_webkit: d.isWebKit,
+ dj_safari: d.isSafari,
+ dj_chrome: d.isChrome,
+
+ dj_gecko: d.isMozilla,
+ dj_ff3: maj(ff) == 3
+ }; // no dojo unsupported browsers
+
+ classes["dj_" + boxModel] = true;
+
+ // apply browser, browser version, and box model class names
+ var classStr = "";
+ for(var clz in classes){
+ if(classes[clz]){
+ classStr += clz + " ";
+ }
+ }
+ html.className = d.trim(html.className + " " + classStr);
+
+ // If RTL mode, then add dj_rtl flag plus repeat existing classes with -rtl extension.
+ // We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl).
+ // Unshift() is to run sniff code before the parser.
+ dojo._loaders.unshift(function(){
+ if(!dojo._isBodyLtr()){
+ var rtlClassStr = "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl ")
+ html.className = d.trim(html.className + " " + rtlClassStr);
+ }
+ });
})();
+
}
diff --git a/lib/dojo/window.js b/lib/dojo/window.js
index e6750dd70..c36eb4c23 100644
--- a/lib/dojo/window.js
+++ b/lib/dojo/window.js
@@ -5,109 +5,139 @@
*/
-if(!dojo._hasResource["dojo.window"]){
-dojo._hasResource["dojo.window"]=true;
+if(!dojo._hasResource["dojo.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.window"] = true;
dojo.provide("dojo.window");
-dojo.window.getBox=function(){
-var _1=(dojo.doc.compatMode=="BackCompat")?dojo.body():dojo.doc.documentElement;
-var _2=dojo._docScroll();
-return {w:_1.clientWidth,h:_1.clientHeight,l:_2.x,t:_2.y};
-};
-dojo.window.get=function(_3){
-if(dojo.isIE&&window!==document.parentWindow){
-_3.parentWindow.execScript("document._parentWindow = window;","Javascript");
-var _4=_3._parentWindow;
-_3._parentWindow=null;
-return _4;
-}
-return _3.parentWindow||_3.defaultView;
+
+dojo.window.getBox = function(){
+ // summary:
+ // Returns the dimensions and scroll position of the viewable area of a browser window
+
+ var scrollRoot = (dojo.doc.compatMode == 'BackCompat') ? dojo.body() : dojo.doc.documentElement;
+
+ // get scroll position
+ var scroll = dojo._docScroll(); // scrollRoot.scrollTop/Left should work
+ return { w: scrollRoot.clientWidth, h: scrollRoot.clientHeight, l: scroll.x, t: scroll.y };
};
-dojo.window.scrollIntoView=function(_5,_6){
-try{
-_5=dojo.byId(_5);
-var _7=_5.ownerDocument||dojo.doc,_8=_7.body||dojo.body(),_9=_7.documentElement||_8.parentNode,_a=dojo.isIE,_b=dojo.isWebKit;
-if((!(dojo.isMoz||_a||_b||dojo.isOpera)||_5==_8||_5==_9)&&(typeof _5.scrollIntoView!="undefined")){
-_5.scrollIntoView(false);
-return;
-}
-var _c=_7.compatMode=="BackCompat",_d=_c?_8:_9,_e=_b?_8:_d,_f=_d.clientWidth,_10=_d.clientHeight,rtl=!dojo._isBodyLtr(),_11=_6||dojo.position(_5),el=_5.parentNode,_12=function(el){
-return ((_a<=6||(_a&&_c))?false:(dojo.style(el,"position").toLowerCase()=="fixed"));
+
+dojo.window.get = function(doc){
+ // summary:
+ // Get window object associated with document doc
+
+ // In some IE versions (at least 6.0), document.parentWindow does not return a
+ // reference to the real window object (maybe a copy), so we must fix it as well
+ // We use IE specific execScript to attach the real window reference to
+ // document._parentWindow for later use
+ if(dojo.isIE && window !== document.parentWindow){
+ /*
+ In IE 6, only the variable "window" can be used to connect events (others
+ may be only copies).
+ */
+ doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
+ //to prevent memory leak, unset it after use
+ //another possibility is to add an onUnload handler which seems overkill to me (liucougar)
+ var win = doc._parentWindow;
+ doc._parentWindow = null;
+ return win; // Window
+ }
+
+ return doc.parentWindow || doc.defaultView; // Window
};
-if(_12(_5)){
-return;
-}
-while(el){
-if(el==_8){
-el=_e;
-}
-var _13=dojo.position(el),_14=_12(el);
-if(el==_e){
-_13.w=_f;
-_13.h=_10;
-if(_e==_9&&_a&&rtl){
-_13.x+=_e.offsetWidth-_13.w;
-}
-if(_13.x<0||!_a){
-_13.x=0;
-}
-if(_13.y<0||!_a){
-_13.y=0;
-}
-}else{
-var pb=dojo._getPadBorderExtents(el);
-_13.w-=pb.w;
-_13.h-=pb.h;
-_13.x+=pb.l;
-_13.y+=pb.t;
-}
-if(el!=_e){
-var _15=el.clientWidth,_16=_13.w-_15;
-if(_15>0&&_16>0){
-_13.w=_15;
-if(_a&&rtl){
-_13.x+=_16;
-}
-}
-_15=el.clientHeight;
-_16=_13.h-_15;
-if(_15>0&&_16>0){
-_13.h=_15;
-}
-}
-if(_14){
-if(_13.y<0){
-_13.h+=_13.y;
-_13.y=0;
-}
-if(_13.x<0){
-_13.w+=_13.x;
-_13.x=0;
-}
-if(_13.y+_13.h>_10){
-_13.h=_10-_13.y;
-}
-if(_13.x+_13.w>_f){
-_13.w=_f-_13.x;
-}
-}
-var l=_11.x-_13.x,t=_11.y-Math.max(_13.y,0),r=l+_11.w-_13.w,bot=t+_11.h-_13.h;
-if(r*l>0){
-var s=Math[l<0?"max":"min"](l,r);
-_11.x+=el.scrollLeft;
-el.scrollLeft+=(_a>=8&&!_c&&rtl)?-s:s;
-_11.x-=el.scrollLeft;
-}
-if(bot*t>0){
-_11.y+=el.scrollTop;
-el.scrollTop+=Math[t<0?"max":"min"](t,bot);
-_11.y-=el.scrollTop;
-}
-el=(el!=_e)&&!_14&&el.parentNode;
-}
-}
-catch(error){
-console.error("scrollIntoView: "+error);
-_5.scrollIntoView(false);
-}
+
+dojo.window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
+ // summary:
+ // Scroll the passed node into view, if it is not already.
+
+ // don't rely on node.scrollIntoView working just because the function is there
+
+ try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method
+ node = dojo.byId(node);
+ var doc = node.ownerDocument || dojo.doc,
+ body = doc.body || dojo.body(),
+ html = doc.documentElement || body.parentNode,
+ isIE = dojo.isIE, isWK = dojo.isWebKit;
+ // if an untested browser, then use the native method
+ if((!(dojo.isMoz || isIE || isWK || dojo.isOpera) || node == body || node == html) && (typeof node.scrollIntoView != "undefined")){
+ node.scrollIntoView(false); // short-circuit to native if possible
+ return;
+ }
+ var backCompat = doc.compatMode == 'BackCompat',
+ clientAreaRoot = backCompat? body : html,
+ scrollRoot = isWK ? body : clientAreaRoot,
+ rootWidth = clientAreaRoot.clientWidth,
+ rootHeight = clientAreaRoot.clientHeight,
+ rtl = !dojo._isBodyLtr(),
+ nodePos = pos || dojo.position(node),
+ el = node.parentNode,
+ isFixed = function(el){
+ return ((isIE <= 6 || (isIE && backCompat))? false : (dojo.style(el, 'position').toLowerCase() == "fixed"));
+ };
+ if(isFixed(node)){ return; } // nothing to do
+
+ while(el){
+ if(el == body){ el = scrollRoot; }
+ var elPos = dojo.position(el),
+ fixedPos = isFixed(el);
+
+ if(el == scrollRoot){
+ elPos.w = rootWidth; elPos.h = rootHeight;
+ if(scrollRoot == html && isIE && rtl){ elPos.x += scrollRoot.offsetWidth-elPos.w; } // IE workaround where scrollbar causes negative x
+ if(elPos.x < 0 || !isIE){ elPos.x = 0; } // IE can have values > 0
+ if(elPos.y < 0 || !isIE){ elPos.y = 0; }
+ }else{
+ var pb = dojo._getPadBorderExtents(el);
+ elPos.w -= pb.w; elPos.h -= pb.h; elPos.x += pb.l; elPos.y += pb.t;
+ }
+
+ if(el != scrollRoot){ // body, html sizes already have the scrollbar removed
+ var clientSize = el.clientWidth,
+ scrollBarSize = elPos.w - clientSize;
+ if(clientSize > 0 && scrollBarSize > 0){
+ elPos.w = clientSize;
+ if(isIE && rtl){ elPos.x += scrollBarSize; }
+ }
+ clientSize = el.clientHeight;
+ scrollBarSize = elPos.h - clientSize;
+ if(clientSize > 0 && scrollBarSize > 0){
+ elPos.h = clientSize;
+ }
+ }
+ if(fixedPos){ // bounded by viewport, not parents
+ if(elPos.y < 0){
+ elPos.h += elPos.y; elPos.y = 0;
+ }
+ if(elPos.x < 0){
+ elPos.w += elPos.x; elPos.x = 0;
+ }
+ if(elPos.y + elPos.h > rootHeight){
+ elPos.h = rootHeight - elPos.y;
+ }
+ if(elPos.x + elPos.w > rootWidth){
+ elPos.w = rootWidth - elPos.x;
+ }
+ }
+ // calculate overflow in all 4 directions
+ var l = nodePos.x - elPos.x, // beyond left: < 0
+ t = nodePos.y - Math.max(elPos.y, 0), // beyond top: < 0
+ r = l + nodePos.w - elPos.w, // beyond right: > 0
+ bot = t + nodePos.h - elPos.h; // beyond bottom: > 0
+ if(r * l > 0){
+ var s = Math[l < 0? "max" : "min"](l, r);
+ nodePos.x += el.scrollLeft;
+ el.scrollLeft += (isIE >= 8 && !backCompat && rtl)? -s : s;
+ nodePos.x -= el.scrollLeft;
+ }
+ if(bot * t > 0){
+ nodePos.y += el.scrollTop;
+ el.scrollTop += Math[t < 0? "max" : "min"](t, bot);
+ nodePos.y -= el.scrollTop;
+ }
+ el = (el != scrollRoot) && !fixedPos && el.parentNode;
+ }
+ }catch(error){
+ console.error('scrollIntoView: ' + error);
+ node.scrollIntoView(false);
+ }
};
+
}
diff --git a/prefs.js b/prefs.js
index 93f5b06c7..031e7217a 100644
--- a/prefs.js
+++ b/prefs.js
@@ -886,7 +886,7 @@ function init() {
try {
- dojo.require("dijit.layout.TabContainer");
+ /* dojo.require("dijit.layout.TabContainer");
dojo.require("dijit.layout.BorderContainer");
dojo.require("dijit.layout.AccordionContainer");
dojo.require("dijit.layout.ContentPane");
@@ -909,7 +909,7 @@ function init() {
dojo.require("dijit.InlineEditBox");
dojo.require("dijit.ColorPalette");
dojo.require("dijit.ProgressBar");
- dojo.require("dijit.form.SimpleTextarea");
+ dojo.require("dijit.form.SimpleTextarea"); */
dojo.registerModulePath("lib", "..");
dojo.registerModulePath("fox", "../..");
@@ -919,6 +919,8 @@ function init() {
dojo.require("fox.PrefFilterTree");
dojo.require("fox.PrefLabelTree");
+ dojo.parser.parse();
+
dojo.addOnLoad(function() {
loading_set_progress(50);
diff --git a/prefs.php b/prefs.php
index ebde59ddc..417443570 100644
--- a/prefs.php
+++ b/prefs.php
@@ -35,7 +35,9 @@
<script type="text/javascript" src="lib/prototype.js"></script>
<script type="text/javascript" src="lib/position.js"></script>
<script type="text/javascript" src="lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls"></script>
- <script type="text/javascript" src="lib/dojo/dojo.js" djConfig="parseOnLoad: true"></script>
+ <script type="text/javascript" src="lib/dojo/dojo.js"></script>
+ <script type="text/javascript" src="lib/dijit/dijit.js"></script>
+ <script type="text/javascript" src="lib/dojo/tt-rss-layer.js"></script>
<script type="text/javascript" charset="utf-8" src="localized_js.php?<?php echo $dt_add ?>"></script>
diff --git a/tt-rss.js b/tt-rss.js
index 5b4947b4c..690e35bcb 100644
--- a/tt-rss.js
+++ b/tt-rss.js
@@ -276,7 +276,9 @@ function init() {
try {
//Form.disable("main_toolbar_form");
- dojo.require("dijit.layout.BorderContainer");
+ // Our layer takes care of Dojo dependencies.
+
+ /* dojo.require("dijit.layout.BorderContainer");
dojo.require("dijit.layout.TabContainer");
dojo.require("dijit.layout.ContentPane");
dojo.require("dijit.Dialog");
@@ -293,12 +295,14 @@ function init() {
dojo.require("dijit.Toolbar");
dojo.require("dijit.ProgressBar");
dojo.require("dijit.Menu");
- dojo.require("dojo.parser");
+ dojo.require("dojo.parser"); */
dojo.registerModulePath("fox", "../..");
dojo.require("fox.FeedTree");
+ dojo.parser.parse();
+
if (typeof themeBeforeLayout == 'function') {
themeBeforeLayout();
}
diff --git a/tt-rss.php b/tt-rss.php
index 49c882db0..63c922f08 100644
--- a/tt-rss.php
+++ b/tt-rss.php
@@ -35,7 +35,10 @@
<script type="text/javascript" src="lib/prototype.js"></script>
<script type="text/javascript" src="lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls"></script>
- <script type="text/javascript" src="lib/dojo/dojo.js" djConfig="parseOnLoad: true"></script>
+ <script type="text/javascript" src="lib/dojo/dojo.js"></script>
+ <script type="text/javascript" src="lib/dijit/dijit.js"></script>
+ <script type="text/javascript" src="lib/dojo/tt-rss-layer.js"></script>
+
<script type="text/javascript" charset="utf-8" src="localized_js.php?<?php echo $dt_add ?>"></script>
<script type="text/javascript" charset="utf-8" src="tt-rss.js?<?php echo $dt_add ?>"></script>
<script type="text/javascript" charset="utf-8" src="functions.js?<?php echo $dt_add ?>"></script>