summaryrefslogtreecommitdiff
path: root/js/dojo-1.6/dijit/dijit-all.xd.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/dojo-1.6/dijit/dijit-all.xd.js14
-rw-r--r--js/dojo-1.6/dijit/dijit-all.xd.js.uncompressed.js30112
2 files changed, 30126 insertions, 0 deletions
diff --git a/js/dojo-1.6/dijit/dijit-all.xd.js b/js/dojo-1.6/dijit/dijit-all.xd.js
new file mode 100644
index 0000000..8c3f81e
--- /dev/null
+++ b/js/dojo-1.6/dijit/dijit-all.xd.js
@@ -0,0 +1,14 @@
+/*
+ Copyright (c) 2004-2011, 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._xdResourceLoaded(function(_1,_2,_3){return {depends:[["provide","dojo.colors"],["provide","dijit._PaletteMixin"],["provide","dijit.ColorPalette"],["provide","dijit.Declaration"],["provide","dojo.dnd.common"],["provide","dojo.dnd.autoscroll"],["provide","dojo.dnd.Mover"],["provide","dojo.dnd.Moveable"],["provide","dojo.dnd.move"],["provide","dojo.dnd.TimedMoveable"],["provide","dojo.fx.Toggler"],["provide","dojo.fx"],["provide","dijit.form._FormMixin"],["provide","dijit._DialogMixin"],["provide","dijit.DialogUnderlay"],["provide","dijit.layout._ContentPaneResizeMixin"],["provide","dojo.html"],["provide","dijit.layout.ContentPane"],["provide","dijit.TooltipDialog"],["provide","dijit.Dialog"],["provide","dijit._editor.selection"],["provide","dijit._editor.range"],["provide","dijit._editor.html"],["provide","dijit._editor.RichText"],["provide","dijit._KeyNavContainer"],["provide","dijit.ToolbarSeparator"],["provide","dijit.Toolbar"],["provide","dijit._HasDropDown"],["provide","dijit.form.Button"],["provide","dijit._editor._Plugin"],["provide","dijit._editor.plugins.EnterKeyHandling"],["provide","dijit.Editor"],["provide","dojo.regexp"],["provide","dojo.data.util.sorter"],["provide","dojo.data.util.simpleFetch"],["provide","dojo.data.util.filter"],["provide","dijit.form.TextBox"],["provide","dijit.Tooltip"],["provide","dijit.form.ValidationTextBox"],["provide","dijit.form.ComboBox"],["provide","dijit.form.FilteringSelect"],["provide","dojo.data.ItemFileReadStore"],["provide","dijit._editor.plugins.FontChoice"],["provide","dijit.form._FormSelectWidget"],["provide","dijit.MenuItem"],["provide","dijit.PopupMenuItem"],["provide","dijit.CheckedMenuItem"],["provide","dijit.MenuSeparator"],["provide","dijit.Menu"],["provide","dijit.form.Select"],["provide","dijit._editor.plugins.LinkDialog"],["provide","dijit.MenuBar"],["provide","dijit.MenuBarItem"],["provide","dijit.PopupMenuBarItem"],["provide","dojo.number"],["provide","dijit.ProgressBar"],["provide","dijit.TitlePane"],["provide","dojo.DeferredList"],["provide","dojo.cookie"],["provide","dijit.tree.TreeStoreModel"],["provide","dijit.tree.ForestStoreModel"],["provide","dojo.dnd.Container"],["provide","dijit.tree._dndContainer"],["provide","dijit.tree._dndSelector"],["provide","dijit.Tree"],["provide","dijit.InlineEditBox"],["provide","dijit.form.Form"],["provide","dijit.form.DropDownButton"],["provide","dijit.form.ComboButton"],["provide","dijit.form.ToggleButton"],["provide","dijit.form.CheckBox"],["provide","dijit.form.RadioButton"],["provide","dojo.cldr.monetary"],["provide","dojo.currency"],["provide","dijit.form.NumberTextBox"],["provide","dijit.form.CurrencyTextBox"],["provide","dojo.cldr.supplemental"],["provide","dojo.date"],["provide","dojo.date.locale"],["provide","dijit.Calendar"],["provide","dijit.form._DateTimeTextBox"],["provide","dijit.form.DateTextBox"],["provide","dijit.form._Spinner"],["provide","dijit.form.NumberSpinner"],["provide","dijit.form.MultiSelect"],["provide","dijit.form.HorizontalSlider"],["provide","dijit.form.VerticalSlider"],["provide","dijit.form.HorizontalRule"],["provide","dijit.form.VerticalRule"],["provide","dijit.form.HorizontalRuleLabels"],["provide","dijit.form.VerticalRuleLabels"],["provide","dijit.form.SimpleTextarea"],["provide","dijit.form.Textarea"],["provide","dijit.layout.StackController"],["provide","dijit.layout.StackContainer"],["provide","dijit.layout.AccordionPane"],["provide","dijit.layout.AccordionContainer"],["provide","dijit.layout.BorderContainer"],["provide","dijit.layout.LayoutContainer"],["provide","dijit.layout.LinkPane"],["provide","dijit.layout.SplitContainer"],["provide","dijit.layout._TabContainerBase"],["provide","dijit.layout.TabController"],["provide","dijit.layout.ScrollingTabController"],["provide","dijit.layout.TabContainer"],["provide","dijit.dijit-all"],["i18n._preloadLocalizations","dijit.nls.dijit-all",["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"]]],defineResource:function(_4,_5,_6){if(!_4._hasResource["dojo.colors"]){_4._hasResource["dojo.colors"]=true;_4.provide("dojo.colors");_4.getObject("colors",true,_4);(function(){var _7=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;};_4.colorFromRgb=function(_8,_9){var m=_8.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=_4.map(c,function(x){return parseFloat(x)*2.56;});if(l==4){a[3]=c[3];}return _4.colorFromArray(a,_9);}return _4.colorFromArray(c,_9);}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=[_7(m1,m2,H+1/3)*256,_7(m1,m2,H)*256,_7(m1,m2,H-1/3)*256,1];if(l==4){a[3]=c[3];}return _4.colorFromArray(a,_9);}}return null;};var _a=function(c,_b,_c){c=Number(c);return isNaN(c)?_c:c<_b?_b:c>_c?_c:c;};_4.Color.prototype.sanitize=function(){var t=this;t.r=Math.round(_a(t.r,0,255));t.g=Math.round(_a(t.g,0,255));t.b=Math.round(_a(t.b,0,255));t.a=_a(t.a,0,1);return this;};})();_4.colors.makeGrey=function(g,a){return _4.colorFromArray([g,g,g,a]);};_4.mixin(_4.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(!_4._hasResource["dijit._PaletteMixin"]){_4._hasResource["dijit._PaletteMixin"]=true;_4.provide("dijit._PaletteMixin");_4.declare("dijit._PaletteMixin",[_5._CssStateMixin],{defaultTimeout:500,timeoutChangeRate:0.9,value:null,_selectedCell:-1,tabIndex:"0",cellClass:"dijitPaletteCell",dyeClass:"",_preparePalette:function(_d,_e){this._cells=[];var _f=this._blankGif;var _10=_4.getObject(this.dyeClass);for(var row=0;row<_d.length;row++){var _11=_4.create("tr",{tabIndex:"-1"},this.gridNode);for(var col=0;col<_d[row].length;col++){var _12=_d[row][col];if(_12){var _13=new _10(_12);var _14=_4.create("td",{"class":this.cellClass,tabIndex:"-1",title:_e[_12]});_13.fillCell(_14,_f);this.connect(_14,"ondijitclick","_onCellClick");this._trackMouseState(_14,this.cellClass);_4.place(_14,_11);_14.index=this._cells.length;this._cells.push({node:_14,dye:_13});}}}this._xDim=_d[0].length;this._yDim=_d.length;var _15={UP_ARROW:-this._xDim,DOWN_ARROW:this._xDim,RIGHT_ARROW:this.isLeftToRight()?1:-1,LEFT_ARROW:this.isLeftToRight()?-1:1};for(var key in _15){this._connects.push(_5.typematic.addKeyListener(this.domNode,{charOrCode:_4.keys[key],ctrlKey:false,altKey:false,shiftKey:false},this,function(){var _16=_15[key];return function(_17){this._navigateByKey(_16,_17);};}(),this.timeoutChangeRate,this.defaultTimeout));}},postCreate:function(){this.inherited(arguments);this._setCurrent(this._cells[0].node);},focus:function(){_5.focus(this._currentFocus);},_onCellClick:function(evt){var _18=evt.currentTarget,_19=this._getDye(_18).getValue();this._setCurrent(_18);setTimeout(_4.hitch(this,function(){_5.focus(_18);this._setValueAttr(_19,true);}));_4.removeClass(_18,"dijitPaletteCellHover");_4.stopEvent(evt);},_setCurrent:function(_1a){if("_currentFocus" in this){_4.attr(this._currentFocus,"tabIndex","-1");}this._currentFocus=_1a;if(_1a){_4.attr(_1a,"tabIndex",this.tabIndex);}},_setValueAttr:function(_1b,_1c){if(this._selectedCell>=0){_4.removeClass(this._cells[this._selectedCell].node,"dijitPaletteCellSelected");}this._selectedCell=-1;if(_1b){for(var i=0;i<this._cells.length;i++){if(_1b==this._cells[i].dye.getValue()){this._selectedCell=i;_4.addClass(this._cells[i].node,"dijitPaletteCellSelected");if(_1c||_1c===undefined){this.onChange(_1b);}break;}}}this._set("value",this._selectedCell>=0?_1b:null);},onChange:function(_1d){},_navigateByKey:function(_1e,_1f){if(_1f==-1){return;}var _20=this._currentFocus.index+_1e;if(_20<this._cells.length&&_20>-1){var _21=this._cells[_20].node;this._setCurrent(_21);setTimeout(_4.hitch(_5,"focus",_21),0);}},_getDye:function(_22){return this._cells[_22.index].dye;}});}if(!_4._hasResource["dijit.ColorPalette"]){_4._hasResource["dijit.ColorPalette"]=true;_4.provide("dijit.ColorPalette");_4.declare("dijit.ColorPalette",[_5._Widget,_5._Templated,_5._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":_4.moduleUrl("dijit.themes","a11y/colors7x10.png"),"3x4":_4.moduleUrl("dijit.themes","a11y/colors3x4.png"),"7x10-rtl":_4.moduleUrl("dijit.themes","a11y/colors7x10-rtl.png"),"3x4-rtl":_4.moduleUrl("dijit.themes","a11y/colors3x4-rtl.png")},templateString:_4.cache("dijit","templates/ColorPalette.html","<div class=\"dijitInline dijitColorPalette\">\r\n\t<img class=\"dijitColorPaletteUnder\" dojoAttachPoint=\"imageNode\" role=\"presentation\" alt=\"\"/>\r\n\t<table class=\"dijitPaletteTable\" cellSpacing=\"0\" cellPadding=\"0\">\r\n\t\t<tbody dojoAttachPoint=\"gridNode\"></tbody>\r\n\t</table>\r\n</div>\r\n"),baseClass:"dijitColorPalette",dyeClass:"dijit._Color",buildRendering:function(){this.inherited(arguments);this.imageNode.setAttribute("src",this._imagePaths[this.palette+(this.isLeftToRight()?"":"-rtl")].toString());var _23=_4.i18n.getLocalization("dojo","colors",this.lang);this._preparePalette(this._palettes[this.palette],_23);}});_4.declare("dijit._Color",_4.Color,{constructor:function(_24){this._alias=_24;this.setColor(_4.Color.named[_24]);},getValue:function(){return this.toHex();},fillCell:function(_25,_26){_4.create("img",{src:_26,"class":"dijitPaletteImg",alt:this._alias},_25);}});}if(!_4._hasResource["dijit.Declaration"]){_4._hasResource["dijit.Declaration"]=true;_4.provide("dijit.Declaration");_4.declare("dijit.Declaration",_5._Widget,{_noScript:true,stopParser:true,widgetClass:"",defaults:null,mixins:[],buildRendering:function(){var src=this.srcNodeRef.parentNode.removeChild(this.srcNodeRef),_27=_4.query("> script[type^='dojo/method']",src).orphan(),_28=_4.query("> script[type^='dojo/connect']",src).orphan(),_29=src.nodeName;var _2a=this.defaults||{};_4.forEach(_27,function(s){var evt=s.getAttribute("event")||s.getAttribute("data-dojo-event"),_2b=_4.parser._functionFromScript(s);if(evt){_2a[evt]=_2b;}else{_28.push(s);}});this.mixins=this.mixins.length?_4.map(this.mixins,function(_2c){return _4.getObject(_2c);}):[_5._Widget,_5._Templated];_2a.widgetsInTemplate=true;_2a._skipNodeCache=true;_2a.templateString="<"+_29+" class='"+src.className+"' dojoAttachPoint='"+(src.getAttribute("dojoAttachPoint")||"")+"' dojoAttachEvent='"+(src.getAttribute("dojoAttachEvent")||"")+"' >"+src.innerHTML.replace(/\%7B/g,"{").replace(/\%7D/g,"}")+"</"+_29+">";_4.query("[dojoType]",src).forEach(function(_2d){_2d.removeAttribute("dojoType");});var wc=_4.declare(this.widgetClass,this.mixins,_2a);_4.forEach(_28,function(s){var evt=s.getAttribute("event")||s.getAttribute("data-dojo-event")||"postscript",_2e=_4.parser._functionFromScript(s);_4.connect(wc.prototype,evt,_2e);});}});}if(!_4._hasResource["dojo.dnd.common"]){_4._hasResource["dojo.dnd.common"]=true;_4.provide("dojo.dnd.common");_4.getObject("dnd",true,_4);_4.dnd.getCopyKeyState=_4.isCopyKey;_4.dnd._uniqueId=0;_4.dnd.getUniqueId=function(){var id;do{id=_4._scopeName+"Unique"+(++_4.dnd._uniqueId);}while(_4.byId(id));return id;};_4.dnd._empty={};_4.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(!_4._hasResource["dojo.dnd.autoscroll"]){_4._hasResource["dojo.dnd.autoscroll"]=true;_4.provide("dojo.dnd.autoscroll");_4.getObject("dnd",true,_4);_4.dnd.getViewport=_4.window.getBox;_4.dnd.V_TRIGGER_AUTOSCROLL=32;_4.dnd.H_TRIGGER_AUTOSCROLL=32;_4.dnd.V_AUTOSCROLL_VALUE=16;_4.dnd.H_AUTOSCROLL_VALUE=16;_4.dnd.autoScroll=function(e){var v=_4.window.getBox(),dx=0,dy=0;if(e.clientX<_4.dnd.H_TRIGGER_AUTOSCROLL){dx=-_4.dnd.H_AUTOSCROLL_VALUE;}else{if(e.clientX>v.w-_4.dnd.H_TRIGGER_AUTOSCROLL){dx=_4.dnd.H_AUTOSCROLL_VALUE;}}if(e.clientY<_4.dnd.V_TRIGGER_AUTOSCROLL){dy=-_4.dnd.V_AUTOSCROLL_VALUE;}else{if(e.clientY>v.h-_4.dnd.V_TRIGGER_AUTOSCROLL){dy=_4.dnd.V_AUTOSCROLL_VALUE;}}window.scrollBy(dx,dy);};_4.dnd._validNodes={"div":1,"p":1,"td":1};_4.dnd._validOverflow={"auto":1,"scroll":1};_4.dnd.autoScrollNodes=function(e){for(var n=e.target;n;){if(n.nodeType==1&&(n.tagName.toLowerCase() in _4.dnd._validNodes)){var s=_4.getComputedStyle(n);if(s.overflow.toLowerCase() in _4.dnd._validOverflow){var b=_4._getContentBox(n,s),t=_4.position(n,true);var w=Math.min(_4.dnd.H_TRIGGER_AUTOSCROLL,b.w/2),h=Math.min(_4.dnd.V_TRIGGER_AUTOSCROLL,b.h/2),rx=e.pageX-t.x,ry=e.pageY-t.y,dx=0,dy=0;if(_4.isWebKit||_4.isOpera){rx+=_4.body().scrollLeft;ry+=_4.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 _2f=n.scrollLeft,_30=n.scrollTop;n.scrollLeft=n.scrollLeft+dx;n.scrollTop=n.scrollTop+dy;if(_2f!=n.scrollLeft||_30!=n.scrollTop){return;}}}try{n=n.parentNode;}catch(x){n=null;}}_4.dnd.autoScroll(e);};}if(!_4._hasResource["dojo.dnd.Mover"]){_4._hasResource["dojo.dnd.Mover"]=true;_4.provide("dojo.dnd.Mover");_4.declare("dojo.dnd.Mover",null,{constructor:function(_31,e,_32){this.node=_4.byId(_31);var pos=e.touches?e.touches[0]:e;this.marginBox={l:pos.pageX,t:pos.pageY};this.mouseButton=e.button;var h=(this.host=_32),d=_31.ownerDocument;this.events=[_4.connect(d,"onmousemove",this,"onFirstMove"),_4.connect(d,"ontouchmove",this,"onFirstMove"),_4.connect(d,"onmousemove",this,"onMouseMove"),_4.connect(d,"ontouchmove",this,"onMouseMove"),_4.connect(d,"onmouseup",this,"onMouseUp"),_4.connect(d,"ontouchend",this,"onMouseUp"),_4.connect(d,"ondragstart",_4.stopEvent),_4.connect(d.body,"onselectstart",_4.stopEvent)];if(h&&h.onMoveStart){h.onMoveStart(this);}},onMouseMove:function(e){_4.dnd.autoScroll(e);var m=this.marginBox,pos=e.touches?e.touches[0]:e;this.host.onMove(this,{l:m.l+pos.pageX,t:m.t+pos.pageY},e);_4.stopEvent(e);},onMouseUp:function(e){if(_4.isWebKit&&_4.isMac&&this.mouseButton==2?e.button==0:this.mouseButton==e.button){this.destroy();}_4.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=_4.marginBox(this.node);var b=_4.doc.body;var bs=_4.getComputedStyle(b);var bm=_4._getMarginBox(b,bs);var bc=_4._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);}_4.disconnect(this.events.shift());_4.disconnect(this.events.shift());},destroy:function(){_4.forEach(this.events,_4.disconnect);var h=this.host;if(h&&h.onMoveStop){h.onMoveStop(this);}this.events=this.node=this.host=null;}});}if(!_4._hasResource["dojo.dnd.Moveable"]){_4._hasResource["dojo.dnd.Moveable"]=true;_4.provide("dojo.dnd.Moveable");_4.declare("dojo.dnd.Moveable",null,{handle:"",delay:0,skip:false,constructor:function(_33,_34){this.node=_4.byId(_33);if(!_34){_34={};}this.handle=_34.handle?_4.byId(_34.handle):null;if(!this.handle){this.handle=this.node;}this.delay=_34.delay>0?_34.delay:0;this.skip=_34.skip;this.mover=_34.mover?_34.mover:_4.dnd.Mover;this.events=[_4.connect(this.handle,"onmousedown",this,"onMouseDown"),_4.connect(this.handle,"ontouchstart",this,"onMouseDown"),_4.connect(this.handle,"ondragstart",this,"onSelectStart"),_4.connect(this.handle,"onselectstart",this,"onSelectStart")];},markupFactory:function(_35,_36){return new _4.dnd.Moveable(_36,_35);},destroy:function(){_4.forEach(this.events,_4.disconnect);this.events=this.node=this.handle=null;},onMouseDown:function(e){if(this.skip&&_4.dnd.isFormElement(e)){return;}if(this.delay){this.events.push(_4.connect(this.handle,"onmousemove",this,"onMouseMove"),_4.connect(this.handle,"ontouchmove",this,"onMouseMove"),_4.connect(this.handle,"onmouseup",this,"onMouseUp"),_4.connect(this.handle,"ontouchend",this,"onMouseUp"));var pos=e.touches?e.touches[0]:e;this._lastX=pos.pageX;this._lastY=pos.pageY;}else{this.onDragDetected(e);}_4.stopEvent(e);},onMouseMove:function(e){var pos=e.touches?e.touches[0]:e;if(Math.abs(pos.pageX-this._lastX)>this.delay||Math.abs(pos.pageY-this._lastY)>this.delay){this.onMouseUp(e);this.onDragDetected(e);}_4.stopEvent(e);},onMouseUp:function(e){for(var i=0;i<2;++i){_4.disconnect(this.events.pop());}_4.stopEvent(e);},onSelectStart:function(e){if(!this.skip||!_4.dnd.isFormElement(e)){_4.stopEvent(e);}},onDragDetected:function(e){new this.mover(this.node,e,this);},onMoveStart:function(_37){_4.publish("/dnd/move/start",[_37]);_4.addClass(_4.body(),"dojoMove");_4.addClass(this.node,"dojoMoveItem");},onMoveStop:function(_38){_4.publish("/dnd/move/stop",[_38]);_4.removeClass(_4.body(),"dojoMove");_4.removeClass(this.node,"dojoMoveItem");},onFirstMove:function(_39,e){},onMove:function(_3a,_3b,e){this.onMoving(_3a,_3b);var s=_3a.node.style;s.left=_3b.l+"px";s.top=_3b.t+"px";this.onMoved(_3a,_3b);},onMoving:function(_3c,_3d){},onMoved:function(_3e,_3f){}});}if(!_4._hasResource["dojo.dnd.move"]){_4._hasResource["dojo.dnd.move"]=true;_4.provide("dojo.dnd.move");_4.declare("dojo.dnd.move.constrainedMoveable",_4.dnd.Moveable,{constraints:function(){},within:false,markupFactory:function(_40,_41){return new _4.dnd.move.constrainedMoveable(_41,_40);},constructor:function(_42,_43){if(!_43){_43={};}this.constraints=_43.constraints;this.within=_43.within;},onFirstMove:function(_44){var c=this.constraintBox=this.constraints.call(this,_44);c.r=c.l+c.w;c.b=c.t+c.h;if(this.within){var mb=_4._getMarginSize(_44.node);c.r-=mb.w;c.b-=mb.h;}},onMove:function(_45,_46){var c=this.constraintBox,s=_45.node.style;this.onMoving(_45,_46);_46.l=_46.l<c.l?c.l:c.r<_46.l?c.r:_46.l;_46.t=_46.t<c.t?c.t:c.b<_46.t?c.b:_46.t;s.left=_46.l+"px";s.top=_46.t+"px";this.onMoved(_45,_46);}});_4.declare("dojo.dnd.move.boxConstrainedMoveable",_4.dnd.move.constrainedMoveable,{box:{},markupFactory:function(_47,_48){return new _4.dnd.move.boxConstrainedMoveable(_48,_47);},constructor:function(_49,_4a){var box=_4a&&_4a.box;this.constraints=function(){return box;};}});_4.declare("dojo.dnd.move.parentConstrainedMoveable",_4.dnd.move.constrainedMoveable,{area:"content",markupFactory:function(_4b,_4c){return new _4.dnd.move.parentConstrainedMoveable(_4c,_4b);},constructor:function(_4d,_4e){var _4f=_4e&&_4e.area;this.constraints=function(){var n=this.node.parentNode,s=_4.getComputedStyle(n),mb=_4._getMarginBox(n,s);if(_4f=="margin"){return mb;}var t=_4._getMarginExtents(n,s);mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;if(_4f=="border"){return mb;}t=_4._getBorderExtents(n,s);mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;if(_4f=="padding"){return mb;}t=_4._getPadExtents(n,s);mb.l+=t.l,mb.t+=t.t,mb.w-=t.w,mb.h-=t.h;return mb;};}});_4.dnd.constrainedMover=_4.dnd.move.constrainedMover;_4.dnd.boxConstrainedMover=_4.dnd.move.boxConstrainedMover;_4.dnd.parentConstrainedMover=_4.dnd.move.parentConstrainedMover;}if(!_4._hasResource["dojo.dnd.TimedMoveable"]){_4._hasResource["dojo.dnd.TimedMoveable"]=true;_4.provide("dojo.dnd.TimedMoveable");(function(){var _50=_4.dnd.Moveable.prototype.onMove;_4.declare("dojo.dnd.TimedMoveable",_4.dnd.Moveable,{timeout:40,constructor:function(_51,_52){if(!_52){_52={};}if(_52.timeout&&typeof _52.timeout=="number"&&_52.timeout>=0){this.timeout=_52.timeout;}},markupFactory:function(_53,_54){return new _4.dnd.TimedMoveable(_54,_53);},onMoveStop:function(_55){if(_55._timer){clearTimeout(_55._timer);_50.call(this,_55,_55._leftTop);}_4.dnd.Moveable.prototype.onMoveStop.apply(this,arguments);},onMove:function(_56,_57){_56._leftTop=_57;if(!_56._timer){var _58=this;_56._timer=setTimeout(function(){_56._timer=null;_50.call(_58,_56,_56._leftTop);},this.timeout);}}});})();}if(!_4._hasResource["dojo.fx.Toggler"]){_4._hasResource["dojo.fx.Toggler"]=true;_4.provide("dojo.fx.Toggler");_4.declare("dojo.fx.Toggler",null,{node:null,showFunc:_4.fadeIn,hideFunc:_4.fadeOut,showDuration:200,hideDuration:200,constructor:function(_59){var _5a=this;_4.mixin(_5a,_59);_5a.node=_59.node;_5a._showArgs=_4.mixin({},_59);_5a._showArgs.node=_5a.node;_5a._showArgs.duration=_5a.showDuration;_5a.showAnim=_5a.showFunc(_5a._showArgs);_5a._hideArgs=_4.mixin({},_59);_5a._hideArgs.node=_5a.node;_5a._hideArgs.duration=_5a.hideDuration;_5a.hideAnim=_5a.hideFunc(_5a._hideArgs);_4.connect(_5a.showAnim,"beforeBegin",_4.hitch(_5a.hideAnim,"stop",true));_4.connect(_5a.hideAnim,"beforeBegin",_4.hitch(_5a.showAnim,"stop",true));},show:function(_5b){return this.showAnim.play(_5b||0);},hide:function(_5c){return this.hideAnim.play(_5c||0);}});}if(!_4._hasResource["dojo.fx"]){_4._hasResource["dojo.fx"]=true;_4.provide("dojo.fx");(function(){var d=_4,_5d={_fire:function(evt,_5e){if(this[evt]){this[evt].apply(this,_5e||[]);}return this;}};var _5f=function(_60){this._index=-1;this._animations=_60||[];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(_5f,{_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(_61,_62){if(!this._current){this._current=this._animations[this._index=0];}if(!_62&&this._current.status()=="playing"){return this;}var _63=d.connect(this._current,"beforeBegin",this,function(){this._fire("beforeBegin");}),_64=d.connect(this._current,"onBegin",this,function(arg){this._fire("onBegin",arguments);}),_65=d.connect(this._current,"onPlay",this,function(arg){this._fire("onPlay",arguments);d.disconnect(_63);d.disconnect(_64);d.disconnect(_65);});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(_66,_67){this.pause();var _68=this.duration*_66;this._current=null;d.some(this._animations,function(a){if(a.duration<=_68){this._current=a;return true;}_68-=a.duration;return false;});if(this._current){this._current.gotoPercent(_68/this._current.duration,_67);}return this;},stop:function(_69){if(this._current){if(_69){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(_5f,_5d);_4.fx.chain=function(_6a){return new _5f(_6a);};var _6b=function(_6c){this._animations=_6c||[];this._connects=[];this._finished=0;this.duration=0;d.forEach(_6c,function(a){var _6d=a.duration;if(a.delay){_6d+=a.delay;}if(this.duration<_6d){this.duration=_6d;}this._connects.push(d.connect(a,"onEnd",this,"_onEnd"));},this);this._pseudoAnimation=new d.Animation({curve:[0,1],duration:this.duration});var _6e=this;d.forEach(["beforeBegin","onBegin","onPlay","onAnimate","onPause","onStop","onEnd"],function(evt){_6e._connects.push(d.connect(_6e._pseudoAnimation,evt,function(){_6e._fire(evt,arguments);}));});};d.extend(_6b,{_doAction:function(_6f,_70){d.forEach(this._animations,function(a){a[_6f].apply(a,_70);});return this;},_onEnd:function(){if(++this._finished>this._animations.length){this._fire("onEnd");}},_call:function(_71,_72){var t=this._pseudoAnimation;t[_71].apply(t,_72);},play:function(_73,_74){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(_75,_76){var ms=this.duration*_75;d.forEach(this._animations,function(a){a.gotoPercent(a.duration<ms?1:(ms/a.duration),_76);});this._call("gotoPercent",arguments);return this;},stop:function(_77){this._doAction("stop",arguments);this._call("stop",arguments);return this;},status:function(){return this._pseudoAnimation.status();},destroy:function(){d.forEach(this._connects,_4.disconnect);}});d.extend(_6b,_5d);_4.fx.combine=function(_78){return new _6b(_78);};_4.fx.wipeIn=function(_79){var _7a=_79.node=d.byId(_79.node),s=_7a.style,o;var _7b=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 _7c=d.style(_7a,"height");return Math.max(_7c,1);}},end:function(){return _7a.scrollHeight;}}}},_79));d.connect(_7b,"onEnd",function(){s.height="auto";s.overflow=o;});return _7b;};_4.fx.wipeOut=function(_7d){var _7e=_7d.node=d.byId(_7d.node),s=_7e.style,o;var _7f=d.animateProperty(d.mixin({properties:{height:{end:1}}},_7d));d.connect(_7f,"beforeBegin",function(){o=s.overflow;s.overflow="hidden";s.display="";});d.connect(_7f,"onEnd",function(){s.overflow=o;s.height="auto";s.display="none";});return _7f;};_4.fx.slideTo=function(_80){var _81=_80.node=d.byId(_80.node),top=null,_82=null;var _83=(function(n){return function(){var cs=d.getComputedStyle(n);var pos=cs.position;top=(pos=="absolute"?n.offsetTop:parseInt(cs.top)||0);_82=(pos=="absolute"?n.offsetLeft:parseInt(cs.left)||0);if(pos!="absolute"&&pos!="relative"){var ret=d.position(n,true);top=ret.y;_82=ret.x;n.style.position="absolute";n.style.top=top+"px";n.style.left=_82+"px";}};})(_81);_83();var _84=d.animateProperty(d.mixin({properties:{top:_80.top||0,left:_80.left||0}},_80));d.connect(_84,"beforeBegin",_84,_83);return _84;};})();}if(!_4._hasResource["dijit.form._FormMixin"]){_4._hasResource["dijit.form._FormMixin"]=true;_4.provide("dijit.form._FormMixin");_4.declare("dijit.form._FormMixin",null,{state:"",reset:function(){_4.forEach(this.getDescendants(),function(_85){if(_85.reset){_85.reset();}});},validate:function(){var _86=false;return _4.every(_4.map(this.getDescendants(),function(_87){_87._hasBeenBlurred=true;var _88=_87.disabled||!_87.validate||_87.validate();if(!_88&&!_86){_4.window.scrollIntoView(_87.containerNode||_87.domNode);_87.focus();_86=true;}return _88;}),function(_89){return _89;});},setValues:function(val){_4.deprecated(this.declaredClass+"::setValues() is deprecated. Use set('value', val) instead.","","2.0");return this.set("value",val);},_setValueAttr:function(obj){var map={};_4.forEach(this.getDescendants(),function(_8a){if(!_8a.name){return;}var _8b=map[_8a.name]||(map[_8a.name]=[]);_8b.push(_8a);});for(var _8c in map){if(!map.hasOwnProperty(_8c)){continue;}var _8d=map[_8c],_8e=_4.getObject(_8c,false,obj);if(_8e===undefined){continue;}if(!_4.isArray(_8e)){_8e=[_8e];}if(typeof _8d[0].checked=="boolean"){_4.forEach(_8d,function(w,i){w.set("value",_4.indexOf(_8e,w.value)!=-1);});}else{if(_8d[0].multiple){_8d[0].set("value",_8e);}else{_4.forEach(_8d,function(w,i){w.set("value",_8e[i]);});}}}},getValues:function(){_4.deprecated(this.declaredClass+"::getValues() is deprecated. Use get('value') instead.","","2.0");return this.get("value");},_getValueAttr:function(){var obj={};_4.forEach(this.getDescendants(),function(_8f){var _90=_8f.name;if(!_90||_8f.disabled){return;}var _91=_8f.get("value");if(typeof _8f.checked=="boolean"){if(/Radio/.test(_8f.declaredClass)){if(_91!==false){_4.setObject(_90,_91,obj);}else{_91=_4.getObject(_90,false,obj);if(_91===undefined){_4.setObject(_90,null,obj);}}}else{var ary=_4.getObject(_90,false,obj);if(!ary){ary=[];_4.setObject(_90,ary,obj);}if(_91!==false){ary.push(_91);}}}else{var _92=_4.getObject(_90,false,obj);if(typeof _92!="undefined"){if(_4.isArray(_92)){_92.push(_91);}else{_4.setObject(_90,[_92,_91],obj);}}else{_4.setObject(_90,_91,obj);}}});return obj;},isValid:function(){return this.state=="";},onValidStateChange:function(_93){},_getState:function(){var _94=_4.map(this._descendants,function(w){return w.get("state")||"";});return _4.indexOf(_94,"Error")>=0?"Error":_4.indexOf(_94,"Incomplete")>=0?"Incomplete":"";},disconnectChildren:function(){_4.forEach(this._childConnections||[],_4.hitch(this,"disconnect"));_4.forEach(this._childWatches||[],function(w){w.unwatch();});},connectChildren:function(_95){var _96=this;this.disconnectChildren();this._descendants=this.getDescendants();var set=_95?function(_97,val){_96[_97]=val;}:_4.hitch(this,"_set");set("value",this.get("value"));set("state",this._getState());var _98=(this._childConnections=[]),_99=(this._childWatches=[]);_4.forEach(_4.filter(this._descendants,function(_9a){return _9a.validate;}),function(_9b){_4.forEach(["state","disabled"],function(_9c){_99.push(_9b.watch(_9c,function(_9d,_9e,_9f){_96.set("state",_96._getState());}));});});var _a0=function(){if(_96._onChangeDelayTimer){clearTimeout(_96._onChangeDelayTimer);}_96._onChangeDelayTimer=setTimeout(function(){delete _96._onChangeDelayTimer;_96._set("value",_96.get("value"));},10);};_4.forEach(_4.filter(this._descendants,function(_a1){return _a1.onChange;}),function(_a2){_98.push(_96.connect(_a2,"onChange",_a0));_99.push(_a2.watch("disabled",_a0));});},startup:function(){this.inherited(arguments);this.connectChildren(true);this.watch("state",function(_a3,_a4,_a5){this.onValidStateChange(_a5=="");});},destroy:function(){this.disconnectChildren();this.inherited(arguments);}});}if(!_4._hasResource["dijit._DialogMixin"]){_4._hasResource["dijit._DialogMixin"]=true;_4.provide("dijit._DialogMixin");_4.declare("dijit._DialogMixin",null,{attributeMap:_5._Widget.prototype.attributeMap,execute:function(_a6){},onCancel:function(){},onExecute:function(){},_onSubmit:function(){this.onExecute();this.execute(this.get("value"));},_getFocusItems:function(){var _a7=_5._getTabNavigable(this.containerNode);this._firstFocusItem=_a7.lowest||_a7.first||this.closeButtonNode||this.domNode;this._lastFocusItem=_a7.last||_a7.highest||this._firstFocusItem;}});}if(!_4._hasResource["dijit.DialogUnderlay"]){_4._hasResource["dijit.DialogUnderlay"]=true;_4.provide("dijit.DialogUnderlay");_4.declare("dijit.DialogUnderlay",[_5._Widget,_5._Templated],{templateString:"<div class='dijitDialogUnderlayWrapper'><div class='dijitDialogUnderlay' dojoAttachPoint='node'></div></div>",dialogId:"","class":"",attributeMap:{id:"domNode"},_setDialogIdAttr:function(id){_4.attr(this.node,"id",id+"_underlay");this._set("dialogId",id);},_setClassAttr:function(_a8){this.node.className="dijitDialogUnderlay "+_a8;this._set("class",_a8);},postCreate:function(){_4.body().appendChild(this.domNode);},layout:function(){var is=this.node.style,os=this.domNode.style;os.display="none";var _a9=_4.window.getBox();os.top=_a9.t+"px";os.left=_a9.l+"px";is.width=_a9.w+"px";is.height=_a9.h+"px";os.display="block";},show:function(){this.domNode.style.display="block";this.layout();this.bgIframe=new _5.BackgroundIframe(this.domNode);},hide:function(){this.bgIframe.destroy();delete this.bgIframe;this.domNode.style.display="none";}});}if(!_4._hasResource["dijit.layout._ContentPaneResizeMixin"]){_4._hasResource["dijit.layout._ContentPaneResizeMixin"]=true;_4.provide("dijit.layout._ContentPaneResizeMixin");_4.declare("dijit.layout._ContentPaneResizeMixin",null,{doLayout:true,isContainer:true,isLayoutContainer:true,_startChildren:function(){_4.forEach(this.getChildren(),function(_aa){_aa.startup();_aa._started=true;});},startup:function(){if(this._started){return;}var _ab=_5._Contained.prototype.getParent.call(this);this._childOfLayoutWidget=_ab&&_ab.isLayoutContainer;this._needLayout=!this._childOfLayoutWidget;this.inherited(arguments);this._startChildren();},_checkIfSingleChild:function(){var _ac=_4.query("> *",this.containerNode).filter(function(_ad){return _ad.tagName!=="SCRIPT";}),_ae=_ac.filter(function(_af){return _4.hasAttr(_af,"data-dojo-type")||_4.hasAttr(_af,"dojoType")||_4.hasAttr(_af,"widgetId");}),_b0=_4.filter(_ae.map(_5.byNode),function(_b1){return _b1&&_b1.domNode&&_b1.resize;});if(_ac.length==_ae.length&&_b0.length==1){this._singleChild=_b0[0];}else{delete this._singleChild;}_4.toggleClass(this.containerNode,this.baseClass+"SingleChild",!!this._singleChild);},resize:function(_b2,_b3){this._layout(_b2,_b3);},_layout:function(_b4,_b5){if(_b4){_4.marginBox(this.domNode,_b4);}var cn=this.containerNode;if(cn===this.domNode){var mb=_b5||{};_4.mixin(mb,_b4||{});if(!("h" in mb)||!("w" in mb)){mb=_4.mixin(_4.marginBox(cn),mb);}this._contentBox=_5.layout.marginBox2contentBox(cn,mb);}else{this._contentBox=_4.contentBox(cn);}this._layoutChildren();delete this._needLayout;},_layoutChildren:function(){if(this.doLayout){this._checkIfSingleChild();}if(this._singleChild&&this._singleChild.resize){var cb=this._contentBox||_4.contentBox(this.containerNode);this._singleChild.resize({w:cb.w,h:cb.h});}else{_4.forEach(this.getChildren(),function(_b6){if(_b6.resize){_b6.resize();}});}}});}if(!_4._hasResource["dojo.html"]){_4._hasResource["dojo.html"]=true;_4.provide("dojo.html");_4.getObject("html",true,_4);(function(){var _b7=0,d=_4;_4.html._secureForInnerHtml=function(_b8){return _b8.replace(/(?:\s*<!DOCTYPE\s[^>]+>|<title[^>]*>[\s\S]*?<\/title>)/ig,"");};_4.html._emptyNode=_4.empty;_4.html._setNodeContent=function(_b9,_ba){d.empty(_b9);if(_ba){if(typeof _ba=="string"){_ba=d._toDom(_ba,_b9.ownerDocument);}if(!_ba.nodeType&&d.isArrayLike(_ba)){for(var _bb=_ba.length,i=0;i<_ba.length;i=_bb==_ba.length?i+1:0){d.place(_ba[i],_b9,"last");}}else{d.place(_ba,_b9,"last");}}return _b9;};_4.declare("dojo.html._ContentSetter",null,{node:"",content:"",id:"",cleanContent:false,extractContent:false,parseContent:false,parserScope:_4._scopeName,startup:true,constructor:function(_bc,_bd){_4.mixin(this,_bc||{});_bd=this.node=_4.byId(this.node||_bd);if(!this.id){this.id=["Setter",(_bd)?_bd.id||_bd.tagName:"",_b7++].join("_");}},set:function(_be,_bf){if(undefined!==_be){this.content=_be;}if(_bf){this._mixin(_bf);}this.onBegin();this.setContent();this.onEnd();return this.node;},setContent:function(){var _c0=this.node;if(!_c0){throw new Error(this.declaredClass+": setContent given no node");}try{_c0=_4.html._setNodeContent(_c0,this.content);}catch(e){var _c1=this.onContentError(e);try{_c0.innerHTML=_c1;}catch(e){console.error("Fatal "+this.declaredClass+".setContent could not change content due to "+e.message,e);}}this.node=_c0;},empty:function(){if(this.parseResults&&this.parseResults.length){_4.forEach(this.parseResults,function(w){if(w.destroy){w.destroy();}});delete this.parseResults;}_4.html._emptyNode(this.node);},onBegin:function(){var _c2=this.content;if(_4.isString(_c2)){if(this.cleanContent){_c2=_4.html._secureForInnerHtml(_c2);}if(this.extractContent){var _c3=_c2.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);if(_c3){_c2=_c3[1];}}}this.empty();this.content=_c2;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(_c4){var _c5={},key;for(key in _c4){if(key in _c5){continue;}this[key]=_c4[key];}},_parse:function(){var _c6=this.node;try{this.parseResults=_4.parser.parse({rootNode:_c6,noStart:!this.startup,inherited:{dir:this.dir,lang:this.lang},scope:this.parserScope});}catch(e){this._onError("Content",e,"Error parsing in _ContentSetter#"+this.id);}},_onError:function(_c7,err,_c8){var _c9=this["on"+_c7+"Error"].call(this,err);if(_c8){console.error(_c8,err);}else{if(_c9){_4.html._setNodeContent(this.node,_c9,true);}}}});_4.html.set=function(_ca,_cb,_cc){if(undefined==_cb){console.warn("dojo.html.set: no cont argument provided, using empty string");_cb="";}if(!_cc){return _4.html._setNodeContent(_ca,_cb,true);}else{var op=new _4.html._ContentSetter(_4.mixin(_cc,{content:_cb,node:_ca}));return op.set();}};})();}if(!_4._hasResource["dijit.layout.ContentPane"]){_4._hasResource["dijit.layout.ContentPane"]=true;_4.provide("dijit.layout.ContentPane");_4.declare("dijit.layout.ContentPane",[_5._Widget,_5.layout._ContentPaneResizeMixin],{href:"",extractContent:false,parseOnLoad:true,parserScope:_4._scopeName,preventCache:false,preload:false,refreshOnShow:false,loadingMessage:"<span class='dijitContentPaneLoading'>${loadingState}</span>",errorMessage:"<span class='dijitContentPaneError'>${errorState}</span>",isLoaded:false,baseClass:"dijitContentPane",ioArgs:{},onLoadDeferred:null,attributeMap:_4.delegate(_5._Widget.prototype.attributeMap,{title:[]}),stopParser:true,template:false,create:function(_cd,_ce){if((!_cd||!_cd.template)&&_ce&&!("href" in _cd)&&!("content" in _cd)){var df=_4.doc.createDocumentFragment();_ce=_4.byId(_ce);while(_ce.firstChild){df.appendChild(_ce.firstChild);}_cd=_4.delegate(_cd,{content:df});}this.inherited(arguments,[_cd,_ce]);},postMixInProperties:function(){this.inherited(arguments);var _cf=_4.i18n.getLocalization("dijit","loading",this.lang);this.loadingMessage=_4.string.substitute(this.loadingMessage,_cf);this.errorMessage=_4.string.substitute(this.errorMessage,_cf);},buildRendering:function(){this.inherited(arguments);if(!this.containerNode){this.containerNode=this.domNode;}this.domNode.title="";if(!_4.attr(this.domNode,"role")){_5.setWaiRole(this.domNode,"group");}},_startChildren:function(){this.inherited(arguments);if(this._contentSetter){_4.forEach(this._contentSetter.parseResults,function(obj){if(!obj._started&&!obj._destroyed&&_4.isFunction(obj.startup)){obj.startup();obj._started=true;}},this);}},startup:function(){if(this._started){return;}this.inherited(arguments);if(this._isShown()){this._onShow();}},setHref:function(_d0){_4.deprecated("dijit.layout.ContentPane.setHref() is deprecated. Use set('href', ...) instead.","","2.0");return this.set("href",_d0);},_setHrefAttr:function(_d1){this.cancel();this.onLoadDeferred=new _4.Deferred(_4.hitch(this,"cancel"));this.onLoadDeferred.addCallback(_4.hitch(this,"onLoad"));this._set("href",_d1);if(this.preload||(this._created&&this._isShown())){this._load();}else{this._hrefChanged=true;}return this.onLoadDeferred;},setContent:function(_d2){_4.deprecated("dijit.layout.ContentPane.setContent() is deprecated. Use set('content', ...) instead.","","2.0");this.set("content",_d2);},_setContentAttr:function(_d3){this._set("href","");this.cancel();this.onLoadDeferred=new _4.Deferred(_4.hitch(this,"cancel"));if(this._created){this.onLoadDeferred.addCallback(_4.hitch(this,"onLoad"));}this._setContent(_d3||"");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(_d4){if(this._beingDestroyed){return;}this.inherited(arguments);},resize:function(_d5,_d6){if(!this._wasShown&&this.open!==false){this._onShow();}this._resizeCalled=true;this._scheduleLayout(_d5,_d6);},_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 _d7=this.domNode,_d8=this.domNode.parentNode;return (_d7.style.display!="none")&&(_d7.style.visibility!="hidden")&&!_4.hasClass(_d7,"dijitHidden")&&_d8&&_d8.style&&(_d8.style.display!="none");}}},_onShow:function(){if(this.href){if(!this._xhrDfd&&(!this.isLoaded||this._hrefChanged||this.refreshOnShow)){var d=this.refresh();}}else{if(this._needLayout){this._layout(this._changeSize,this._resultSize);}}this.inherited(arguments);this._wasShown=true;return d;},refresh:function(){this.cancel();this.onLoadDeferred=new _4.Deferred(_4.hitch(this,"cancel"));this.onLoadDeferred.addCallback(_4.hitch(this,"onLoad"));this._load();return this.onLoadDeferred;},_load:function(){this._setContent(this.onDownloadStart(),true);var _d9=this;var _da={preventCache:(this.preventCache||this.refreshOnShow),url:this.href,handleAs:"text"};if(_4.isObject(this.ioArgs)){_4.mixin(_da,this.ioArgs);}var _db=(this._xhrDfd=(this.ioMethod||_4.xhrGet)(_da));_db.addCallback(function(_dc){try{_d9._isDownloaded=true;_d9._setContent(_dc,false);_d9.onDownloadEnd();}catch(err){_d9._onError("Content",err);}delete _d9._xhrDfd;return _dc;});_db.addErrback(function(err){if(!_db.canceled){_d9._onError("Download",err);}delete _d9._xhrDfd;return err;});delete this._hrefChanged;},_onLoadHandler:function(_dd){this._set("isLoaded",true);try{this.onLoadDeferred.callback(_dd);}catch(e){console.error("Error "+this.widgetId+" running custom onLoad code: "+e.message);}},_onUnloadHandler:function(){this._set("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 _de=this._contentSetter;_4.forEach(this.getChildren(),function(_df){if(_df.destroyRecursive){_df.destroyRecursive();}});if(_de){_4.forEach(_de.parseResults,function(_e0){if(_e0.destroyRecursive&&_e0.domNode&&_e0.domNode.parentNode==_4.body()){_e0.destroyRecursive();}});delete _de.parseResults;}_4.html._emptyNode(this.containerNode);delete this._singleChild;},_setContent:function(_e1,_e2){this.destroyDescendants();var _e3=this._contentSetter;if(!(_e3&&_e3 instanceof _4.html._ContentSetter)){_e3=this._contentSetter=new _4.html._ContentSetter({node:this.containerNode,_onError:_4.hitch(this,this._onError),onContentError:_4.hitch(this,function(e){var _e4=this.onContentError(e);try{this.containerNode.innerHTML=_e4;}catch(e){console.error("Fatal "+this.id+" could not change content due to "+e.message,e);}})});}var _e5=_4.mixin({cleanContent:this.cleanContent,extractContent:this.extractContent,parseContent:this.parseOnLoad,parserScope:this.parserScope,startup:false,dir:this.dir,lang:this.lang},this._contentSetterParams||{});_e3.set((_4.isObject(_e1)&&_e1.domNode)?_e1.domNode:_e1,_e5);delete this._contentSetterParams;if(this.doLayout){this._checkIfSingleChild();}if(!_e2){if(this._started){this._startChildren();this._scheduleLayout();}this._onLoadHandler(_e1);}},_onError:function(_e6,err,_e7){this.onLoadDeferred.errback(err);var _e8=this["on"+_e6+"Error"].call(this,err);if(_e7){console.error(_e7,err);}else{if(_e8){this._setContent(_e8,true);}}},_scheduleLayout:function(_e9,_ea){if(this._isShown()){this._layout(_e9,_ea);}else{this._needLayout=true;this._changeSize=_e9;this._resultSize=_ea;}},onLoad:function(_eb){},onUnload:function(){},onDownloadStart:function(){return this.loadingMessage;},onContentError:function(_ec){},onDownloadError:function(_ed){return this.errorMessage;},onDownloadEnd:function(){}});}if(!_4._hasResource["dijit.TooltipDialog"]){_4._hasResource["dijit.TooltipDialog"]=true;_4.provide("dijit.TooltipDialog");_4.declare("dijit.TooltipDialog",[_5.layout.ContentPane,_5._Templated,_5.form._FormMixin,_5._DialogMixin],{title:"",doLayout:false,autofocus:true,baseClass:"dijitTooltipDialog",_firstFocusItem:null,_lastFocusItem:null,templateString:_4.cache("dijit","templates/TooltipDialog.html","<div role=\"presentation\" tabIndex=\"-1\">\r\n\t<div class=\"dijitTooltipContainer\" role=\"presentation\">\r\n\t\t<div class =\"dijitTooltipContents dijitTooltipFocusNode\" dojoAttachPoint=\"containerNode\" role=\"dialog\"></div>\r\n\t</div>\r\n\t<div class=\"dijitTooltipConnector\" role=\"presentation\"></div>\r\n</div>\r\n"),_setTitleAttr:function(_ee){this.containerNode.title=_ee;this._set("title",_ee);},postCreate:function(){this.inherited(arguments);this.connect(this.containerNode,"onkeypress","_onKey");},orient:function(_ef,_f0,_f1){var _f2="dijitTooltipAB"+(_f1.charAt(1)=="L"?"Left":"Right")+" dijitTooltip"+(_f1.charAt(0)=="T"?"Below":"Above");_4.replaceClass(this.domNode,_f2,this._currentOrientClass||"");this._currentOrientClass=_f2;},focus:function(){this._getFocusItems(this.containerNode);_5.focus(this._firstFocusItem);},onOpen:function(pos){this.orient(this.domNode,pos.aroundCorner,pos.corner);this._onShow();},onClose:function(){this.onHide();},_onKey:function(evt){var _f3=evt.target;var dk=_4.keys;if(evt.charOrCode===dk.TAB){this._getFocusItems(this.containerNode);}var _f4=(this._firstFocusItem==this._lastFocusItem);if(evt.charOrCode==dk.ESCAPE){setTimeout(_4.hitch(this,"onCancel"),0);_4.stopEvent(evt);}else{if(_f3==this._firstFocusItem&&evt.shiftKey&&evt.charOrCode===dk.TAB){if(!_f4){_5.focus(this._lastFocusItem);}_4.stopEvent(evt);}else{if(_f3==this._lastFocusItem&&evt.charOrCode===dk.TAB&&!evt.shiftKey){if(!_f4){_5.focus(this._firstFocusItem);}_4.stopEvent(evt);}else{if(evt.charOrCode===dk.TAB){evt.stopPropagation();}}}}}});}if(!_4._hasResource["dijit.Dialog"]){_4._hasResource["dijit.Dialog"]=true;_4.provide("dijit.Dialog");_4.declare("dijit._DialogBase",[_5._Templated,_5.form._FormMixin,_5._DialogMixin,_5._CssStateMixin],{templateString:_4.cache("dijit","templates/Dialog.html","<div class=\"dijitDialog\" role=\"dialog\" aria-labelledby=\"${id}_title\">\r\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\">\r\n\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\"></span>\r\n\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" dojoAttachEvent=\"ondijitclick: onCancel\" title=\"${buttonCancel}\" role=\"button\" tabIndex=\"-1\">\r\n\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\r\n\t</span>\r\n\t</div>\r\n\t\t<div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\r\n</div>\r\n"),baseClass:"dijitDialog",cssStateNodes:{closeButtonNode:"dijitDialogCloseIcon"},attributeMap:_4.delegate(_5._Widget.prototype.attributeMap,{title:[{node:"titleNode",type:"innerHTML"},{node:"titleBar",type:"attribute"}],"aria-describedby":""}),open:false,duration:_5.defaultDuration,refocus:true,autofocus:true,_firstFocusItem:null,_lastFocusItem:null,doLayout:false,draggable:true,"aria-describedby":"",postMixInProperties:function(){var _f5=_4.i18n.getLocalization("dijit","common");_4.mixin(this,_f5);this.inherited(arguments);},postCreate:function(){_4.style(this.domNode,{display:"none",position:"absolute"});_4.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&&_5._DialogLevelManager.isTop(this)){this._getFocusItems(this.domNode);_5.focus(this._firstFocusItem);}this.inherited(arguments);},_endDrag:function(e){if(e&&e.node&&e.node===this.domNode){this._relativePosition=_4.position(e.node);}},_setup:function(){var _f6=this.domNode;if(this.titleBar&&this.draggable){this._moveable=(_4.isIE==6)?new _4.dnd.TimedMoveable(_f6,{handle:this.titleBar}):new _4.dnd.Moveable(_f6,{handle:this.titleBar,timeout:0});this._dndListener=_4.subscribe("/dnd/move/stop",this,"_endDrag");}else{_4.addClass(_f6,"dijitDialogFixed");}this.underlayAttrs={dialogId:this.id,"class":_4.map(this["class"].split(/\s/),function(s){return s+"_underlay";}).join(" ")};},_size:function(){this._checkIfSingleChild();if(this._singleChild){if(this._singleChildOriginalStyle){this._singleChild.domNode.style.cssText=this._singleChildOriginalStyle;}delete this._singleChildOriginalStyle;}else{_4.style(this.containerNode,{width:"auto",height:"auto"});}var mb=_4._getMarginSize(this.domNode);var _f7=_4.window.getBox();if(mb.w>=_f7.w||mb.h>=_f7.h){var w=Math.min(mb.w,Math.floor(_f7.w*0.75)),h=Math.min(mb.h,Math.floor(_f7.h*0.75));if(this._singleChild&&this._singleChild.resize){this._singleChildOriginalStyle=this._singleChild.domNode.style.cssText;this._singleChild.resize({w:w,h:h});}else{_4.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(!_4.hasClass(_4.body(),"dojoMove")){var _f8=this.domNode,_f9=_4.window.getBox(),p=this._relativePosition,bb=p?null:_4._getBorderBox(_f8),l=Math.floor(_f9.l+(p?p.x:(_f9.w-bb.w)/2)),t=Math.floor(_f9.t+(p?p.y:(_f9.h-bb.h)/2));_4.style(_f8,{left:l+"px",top:t+"px"});}},_onKey:function(evt){if(evt.charOrCode){var dk=_4.keys;var _fa=evt.target;if(evt.charOrCode===dk.TAB){this._getFocusItems(this.domNode);}var _fb=(this._firstFocusItem==this._lastFocusItem);if(_fa==this._firstFocusItem&&evt.shiftKey&&evt.charOrCode===dk.TAB){if(!_fb){_5.focus(this._lastFocusItem);}_4.stopEvent(evt);}else{if(_fa==this._lastFocusItem&&evt.charOrCode===dk.TAB&&!evt.shiftKey){if(!_fb){_5.focus(this._firstFocusItem);}_4.stopEvent(evt);}else{while(_fa){if(_fa==this.domNode||_4.hasClass(_fa,"dijitPopup")){if(evt.charOrCode==dk.ESCAPE){this.onCancel();}else{return;}}_fa=_fa.parentNode;}if(evt.charOrCode!==dk.TAB){_4.stopEvent(evt);}else{if(!_4.isOpera){try{this._firstFocusItem.focus();}catch(e){}}}}}}},show:function(){if(this.open){return;}if(!this._started){this.startup();}if(!this._alreadyInitialized){this._setup();this._alreadyInitialized=true;}if(this._fadeOutDeferred){this._fadeOutDeferred.cancel();}this._modalconnects.push(_4.connect(window,"onscroll",this,"layout"));this._modalconnects.push(_4.connect(window,"onresize",this,function(){var _fc=_4.window.getBox();if(!this._oldViewport||_fc.h!=this._oldViewport.h||_fc.w!=this._oldViewport.w){this.layout();this._oldViewport=_fc;}}));this._modalconnects.push(_4.connect(this.domNode,"onkeypress",this,"_onKey"));_4.style(this.domNode,{opacity:0,display:""});this._set("open",true);this._onShow();this._size();this._position();var _fd;this._fadeInDeferred=new _4.Deferred(_4.hitch(this,function(){_fd.stop();delete this._fadeInDeferred;}));_fd=_4.fadeIn({node:this.domNode,duration:this.duration,beforeBegin:_4.hitch(this,function(){_5._DialogLevelManager.show(this,this.underlayAttrs);}),onEnd:_4.hitch(this,function(){if(this.autofocus&&_5._DialogLevelManager.isTop(this)){this._getFocusItems(this.domNode);_5.focus(this._firstFocusItem);}this._fadeInDeferred.callback(true);delete this._fadeInDeferred;})}).play();return this._fadeInDeferred;},hide:function(){if(!this._alreadyInitialized){return;}if(this._fadeInDeferred){this._fadeInDeferred.cancel();}var _fe;this._fadeOutDeferred=new _4.Deferred(_4.hitch(this,function(){_fe.stop();delete this._fadeOutDeferred;}));_fe=_4.fadeOut({node:this.domNode,duration:this.duration,onEnd:_4.hitch(this,function(){this.domNode.style.display="none";_5._DialogLevelManager.hide(this);this.onHide();this._fadeOutDeferred.callback(true);delete this._fadeOutDeferred;})}).play();if(this._scrollConnected){this._scrollConnected=false;}_4.forEach(this._modalconnects,_4.disconnect);this._modalconnects=[];if(this._relativePosition){delete this._relativePosition;}this._set("open",false);return this._fadeOutDeferred;},layout:function(){if(this.domNode.style.display!="none"){if(_5._underlay){_5._underlay.layout();}this._position();}},destroy:function(){if(this._fadeInDeferred){this._fadeInDeferred.cancel();}if(this._fadeOutDeferred){this._fadeOutDeferred.cancel();}if(this._moveable){this._moveable.destroy();}if(this._dndListener){_4.unsubscribe(this._dndListener);}_4.forEach(this._modalconnects,_4.disconnect);_5._DialogLevelManager.hide(this);this.inherited(arguments);}});_4.declare("dijit.Dialog",[_5.layout.ContentPane,_5._DialogBase],{});_5._DialogLevelManager={show:function(_ff,_100){var ds=_5._dialogStack;ds[ds.length-1].focus=_5.getFocus(_ff);var _101=_5._underlay;if(!_101||_101._destroyed){_101=_5._underlay=new _5.DialogUnderlay(_100);}else{_101.set(_ff.underlayAttrs);}var _102=ds[ds.length-1].dialog?ds[ds.length-1].zIndex+2:950;if(ds.length==1){_101.show();}_4.style(_5._underlay.domNode,"zIndex",_102-1);_4.style(_ff.domNode,"zIndex",_102);ds.push({dialog:_ff,underlayAttrs:_100,zIndex:_102});},hide:function(_103){var ds=_5._dialogStack;if(ds[ds.length-1].dialog==_103){ds.pop();var pd=ds[ds.length-1];if(ds.length==1){if(!_5._underlay._destroyed){_5._underlay.hide();}}else{_4.style(_5._underlay.domNode,"zIndex",pd.zIndex-1);_5._underlay.set(pd.underlayAttrs);}if(_103.refocus){var _104=pd.focus;if(!_104||(pd.dialog&&!_4.isDescendant(_104.node,pd.dialog.domNode))){pd.dialog._getFocusItems(pd.dialog.domNode);_104=pd.dialog._firstFocusItem;}try{_5.focus(_104);}catch(e){}}}else{var idx=_4.indexOf(_4.map(ds,function(elem){return elem.dialog;}),_103);if(idx!=-1){ds.splice(idx,1);}}},isTop:function(_105){var ds=_5._dialogStack;return ds[ds.length-1].dialog==_105;}};_5._dialogStack=[{dialog:null,focus:null,underlayAttrs:null}];}if(!_4._hasResource["dijit._editor.selection"]){_4._hasResource["dijit._editor.selection"]=true;_4.provide("dijit._editor.selection");_4.getObject("_editor.selection",true,_5);_4.mixin(_5._editor.selection,{getType:function(){if(_4.isIE){return _4.doc.selection.type.toLowerCase();}else{var _106="text";var oSel;try{oSel=_4.global.getSelection();}catch(e){}if(oSel&&oSel.rangeCount==1){var _107=oSel.getRangeAt(0);if((_107.startContainer==_107.endContainer)&&((_107.endOffset-_107.startOffset)==1)&&(_107.startContainer.nodeType!=3)){_106="control";}}return _106;}},getSelectedText:function(){if(_4.isIE){if(_5._editor.selection.getType()=="control"){return null;}return _4.doc.selection.createRange().text;}else{var _108=_4.global.getSelection();if(_108){return _108.toString();}}return "";},getSelectedHtml:function(){if(_4.isIE){if(_5._editor.selection.getType()=="control"){return null;}return _4.doc.selection.createRange().htmlText;}else{var _109=_4.global.getSelection();if(_109&&_109.rangeCount){var i;var html="";for(i=0;i<_109.rangeCount;i++){var frag=_109.getRangeAt(i).cloneContents();var div=_4.doc.createElement("div");div.appendChild(frag);html+=div.innerHTML;}return html;}return null;}},getSelectedElement:function(){if(_5._editor.selection.getType()=="control"){if(_4.isIE){var _10a=_4.doc.selection.createRange();if(_10a&&_10a.item){return _4.doc.selection.createRange().item(0);}}else{var _10b=_4.global.getSelection();return _10b.anchorNode.childNodes[_10b.anchorOffset];}}return null;},getParentElement:function(){if(_5._editor.selection.getType()=="control"){var p=this.getSelectedElement();if(p){return p.parentNode;}}else{if(_4.isIE){var r=_4.doc.selection.createRange();r.collapse(true);return r.parentElement();}else{var _10c=_4.global.getSelection();if(_10c){var node=_10c.anchorNode;while(node&&(node.nodeType!=1)){node=node.parentNode;}return node;}}}return null;},hasAncestorElement:function(_10d){return this.getAncestorElement.apply(this,arguments)!=null;},getAncestorElement:function(_10e){var node=this.getSelectedElement()||this.getParentElement();return this.getParentOfType(node,arguments);},isTag:function(node,tags){if(node&&node.tagName){var _10f=node.tagName.toLowerCase();for(var i=0;i<tags.length;i++){var _110=String(tags[i]).toLowerCase();if(_10f==_110){return _110;}}}return "";},getParentOfType:function(node,tags){while(node){if(this.isTag(node,tags).length){return node;}node=node.parentNode;}return null;},collapse:function(_111){if(window.getSelection){var _112=_4.global.getSelection();if(_112.removeAllRanges){if(_111){_112.collapseToStart();}else{_112.collapseToEnd();}}else{_112.collapse(_111);}}else{if(_4.isIE){var _113=_4.doc.selection.createRange();_113.collapse(_111);_113.select();}}},remove:function(){var sel=_4.doc.selection;if(_4.isIE){if(sel.type.toLowerCase()!="none"){sel.clear();}return sel;}else{sel=_4.global.getSelection();sel.deleteFromDocument();return sel;}},selectElementChildren:function(_114,_115){var win=_4.global;var doc=_4.doc;var _116;_114=_4.byId(_114);if(doc.selection&&_4.isIE&&_4.body().createTextRange){_116=_114.ownerDocument.body.createTextRange();_116.moveToElementText(_114);if(!_115){try{_116.select();}catch(e){}}}else{if(win.getSelection){var _117=_4.global.getSelection();if(_4.isOpera){if(_117.rangeCount){_116=_117.getRangeAt(0);}else{_116=doc.createRange();}_116.setStart(_114,0);_116.setEnd(_114,(_114.nodeType==3)?_114.length:_114.childNodes.length);_117.addRange(_116);}else{_117.selectAllChildren(_114);}}}},selectElement:function(_118,_119){var _11a;var doc=_4.doc;var win=_4.global;_118=_4.byId(_118);if(_4.isIE&&_4.body().createTextRange){try{_11a=_4.body().createControlRange();_11a.addElement(_118);if(!_119){_11a.select();}}catch(e){this.selectElementChildren(_118,_119);}}else{if(_4.global.getSelection){var _11b=win.getSelection();_11a=doc.createRange();if(_11b.removeAllRanges){if(_4.isOpera){if(_11b.getRangeAt(0)){_11a=_11b.getRangeAt(0);}}_11a.selectNode(_118);_11b.removeAllRanges();_11b.addRange(_11a);}}}},inSelection:function(node){if(node){var _11c;var doc=_4.doc;var _11d;if(_4.global.getSelection){var sel=_4.global.getSelection();if(sel&&sel.rangeCount>0){_11d=sel.getRangeAt(0);}if(_11d&&_11d.compareBoundaryPoints&&doc.createRange){try{_11c=doc.createRange();_11c.setStart(node,0);if(_11d.compareBoundaryPoints(_11d.START_TO_END,_11c)===1){return true;}}catch(e){}}}else{if(doc.selection){_11d=doc.selection.createRange();try{_11c=node.ownerDocument.body.createControlRange();if(_11c){_11c.addElement(node);}}catch(e1){try{_11c=node.ownerDocument.body.createTextRange();_11c.moveToElementText(node);}catch(e2){}}if(_11d&&_11c){if(_11d.compareEndPoints("EndToStart",_11c)===1){return true;}}}}}return false;}});}if(!_4._hasResource["dijit._editor.range"]){_4._hasResource["dijit._editor.range"]=true;_4.provide("dijit._editor.range");_5.range={};_5.range.getIndex=function(node,_11e){var ret=[],retR=[];var stop=_11e;var _11f=node;var _120,n;while(node!=stop){var i=0;_120=node.parentNode;while((n=_120.childNodes[i++])){if(n===node){--i;break;}}ret.unshift(i);retR.unshift(i-_120.childNodes.length);node=_120;}if(ret.length>0&&_11f.nodeType==3){n=_11f.previousSibling;while(n&&n.nodeType==3){ret[ret.length-1]--;n=n.previousSibling;}n=_11f.nextSibling;while(n&&n.nodeType==3){retR[retR.length-1]++;n=n.nextSibling;}}return {o:ret,r:retR};};_5.range.getNode=function(_121,_122){if(!_4.isArray(_121)||_121.length==0){return _122;}var node=_122;_4.every(_121,function(i){if(i>=0&&i<node.childNodes.length){node=node.childNodes[i];}else{node=null;return false;}return true;});return node;};_5.range.getCommonAncestor=function(n1,n2,root){root=root||n1.ownerDocument.body;var _123=function(n){var as=[];while(n){as.unshift(n);if(n!==root){n=n.parentNode;}else{break;}}return as;};var n1as=_123(n1);var n2as=_123(n2);var m=Math.min(n1as.length,n2as.length);var com=n1as[0];for(var i=1;i<m;i++){if(n1as[i]===n2as[i]){com=n1as[i];}else{break;}}return com;};_5.range.getAncestor=function(node,_124,root){root=root||node.ownerDocument.body;while(node&&node!==root){var name=node.nodeName.toUpperCase();if(_124.test(name)){return node;}node=node.parentNode;}return null;};_5.range.BlockTagNames=/^(?:P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|DT|DE)$/;_5.range.getBlockAncestor=function(node,_125,root){root=root||node.ownerDocument.body;_125=_125||_5.range.BlockTagNames;var _126=null,_127;while(node&&node!==root){var name=node.nodeName.toUpperCase();if(!_126&&_125.test(name)){_126=node;}if(!_127&&(/^(?:BODY|TD|TH|CAPTION)$/).test(name)){_127=node;}node=node.parentNode;}return {blockNode:_126,blockContainer:_127||node.ownerDocument.body};};_5.range.atBeginningOfContainer=function(_128,node,_129){var _12a=false;var _12b=(_129==0);if(!_12b&&node.nodeType==3){if(/^[\s\xA0]+$/.test(node.nodeValue.substr(0,_129))){_12b=true;}}if(_12b){var _12c=node;_12a=true;while(_12c&&_12c!==_128){if(_12c.previousSibling){_12a=false;break;}_12c=_12c.parentNode;}}return _12a;};_5.range.atEndOfContainer=function(_12d,node,_12e){var _12f=false;var _130=(_12e==(node.length||node.childNodes.length));if(!_130&&node.nodeType==3){if(/^[\s\xA0]+$/.test(node.nodeValue.substr(_12e))){_130=true;}}if(_130){var _131=node;_12f=true;while(_131&&_131!==_12d){if(_131.nextSibling){_12f=false;break;}_131=_131.parentNode;}}return _12f;};_5.range.adjacentNoneTextNode=function(_132,next){var node=_132;var len=(0-_132.length)||0;var prop=next?"nextSibling":"previousSibling";while(node){if(node.nodeType!=3){break;}len+=node.length;node=node[prop];}return [node,len];};_5.range._w3c=Boolean(window["getSelection"]);_5.range.create=function(win){if(_5.range._w3c){return (win||_4.global).document.createRange();}else{return new _5.range.W3CRange;}};_5.range.getSelection=function(win,_133){if(_5.range._w3c){return win.getSelection();}else{var s=new _5.range.ie.selection(win);if(!_133){s._getCurrentSelection();}return s;}};if(!_5.range._w3c){_5.range.ie={cachedSelection:{},selection:function(win){this._ranges=[];this.addRange=function(r,_134){this._ranges.push(r);if(!_134){r._select();}this.rangeCount=this._ranges.length;};this.removeAllRanges=function(){this._ranges=[];this.rangeCount=0;};var _135=function(){var r=win.document.selection.createRange();var type=win.document.selection.type.toUpperCase();if(type=="CONTROL"){return new _5.range.W3CRange(_5.range.ie.decomposeControlRange(r));}else{return new _5.range.W3CRange(_5.range.ie.decomposeTextRange(r));}};this.getRangeAt=function(i){return this._ranges[i];};this._getCurrentSelection=function(){this.removeAllRanges();var r=_135();if(r){this.addRange(r,true);}};},decomposeControlRange:function(_136){var _137=_136.item(0),_138=_136.item(_136.length-1);var _139=_137.parentNode,_13a=_138.parentNode;var _13b=_5.range.getIndex(_137,_139).o;var _13c=_5.range.getIndex(_138,_13a).o+1;return [_139,_13b,_13a,_13c];},getEndPoint:function(_13d,end){var _13e=_13d.duplicate();_13e.collapse(!end);var _13f="EndTo"+(end?"End":"Start");var _140=_13e.parentElement();var _141,_142,_143;if(_140.childNodes.length>0){_4.every(_140.childNodes,function(node,i){var _144;if(node.nodeType!=3){_13e.moveToElementText(node);if(_13e.compareEndPoints(_13f,_13d)>0){if(_143&&_143.nodeType==3){_141=_143;_144=true;}else{_141=_140;_142=i;return false;}}else{if(i==_140.childNodes.length-1){_141=_140;_142=_140.childNodes.length;return false;}}}else{if(i==_140.childNodes.length-1){_141=node;_144=true;}}if(_144&&_141){var _145=_5.range.adjacentNoneTextNode(_141)[0];if(_145){_141=_145.nextSibling;}else{_141=_140.firstChild;}var _146=_5.range.adjacentNoneTextNode(_141);_145=_146[0];var _147=_146[1];if(_145){_13e.moveToElementText(_145);_13e.collapse(false);}else{_13e.moveToElementText(_140);}_13e.setEndPoint(_13f,_13d);_142=_13e.text.length-_147;return false;}_143=node;return true;});}else{_141=_140;_142=0;}if(!end&&_141.nodeType==1&&_142==_141.childNodes.length){var _148=_141.nextSibling;if(_148&&_148.nodeType==3){_141=_148;_142=0;}}return [_141,_142];},setEndPoint:function(_149,_14a,_14b){var _14c=_149.duplicate(),node,len;if(_14a.nodeType!=3){if(_14b>0){node=_14a.childNodes[_14b-1];if(node){if(node.nodeType==3){_14a=node;_14b=node.length;}else{if(node.nextSibling&&node.nextSibling.nodeType==3){_14a=node.nextSibling;_14b=0;}else{_14c.moveToElementText(node.nextSibling?node:_14a);var _14d=node.parentNode;var _14e=_14d.insertBefore(node.ownerDocument.createTextNode(" "),node.nextSibling);_14c.collapse(false);_14d.removeChild(_14e);}}}}else{_14c.moveToElementText(_14a);_14c.collapse(true);}}if(_14a.nodeType==3){var _14f=_5.range.adjacentNoneTextNode(_14a);var _150=_14f[0];len=_14f[1];if(_150){_14c.moveToElementText(_150);_14c.collapse(false);if(_150.contentEditable!="inherit"){len++;}}else{_14c.moveToElementText(_14a.parentNode);_14c.collapse(true);}_14b+=len;if(_14b>0){if(_14c.move("character",_14b)!=_14b){console.error("Error when moving!");}}}return _14c;},decomposeTextRange:function(_151){var _152=_5.range.ie.getEndPoint(_151);var _153=_152[0],_154=_152[1];var _155=_152[0],_156=_152[1];if(_151.htmlText.length){if(_151.htmlText==_151.text){_156=_154+_151.text.length;}else{_152=_5.range.ie.getEndPoint(_151,true);_155=_152[0],_156=_152[1];}}return [_153,_154,_155,_156];},setRange:function(_157,_158,_159,_15a,_15b,_15c){var _15d=_5.range.ie.setEndPoint(_157,_158,_159);_157.setEndPoint("StartToStart",_15d);if(!_15c){var end=_5.range.ie.setEndPoint(_157,_15a,_15b);}_157.setEndPoint("EndToEnd",end||_15d);return _157;}};_4.declare("dijit.range.W3CRange",null,{constructor:function(){if(arguments.length>0){this.setStart(arguments[0][0],arguments[0][1]);this.setEnd(arguments[0][2],arguments[0][3]);}else{this.commonAncestorContainer=null;this.startContainer=null;this.startOffset=0;this.endContainer=null;this.endOffset=0;this.collapsed=true;}},_updateInternal:function(){if(this.startContainer!==this.endContainer){this.commonAncestorContainer=_5.range.getCommonAncestor(this.startContainer,this.endContainer);}else{this.commonAncestorContainer=this.startContainer;}this.collapsed=(this.startContainer===this.endContainer)&&(this.startOffset==this.endOffset);},setStart:function(node,_15e){_15e=parseInt(_15e);if(this.startContainer===node&&this.startOffset==_15e){return;}delete this._cachedBookmark;this.startContainer=node;this.startOffset=_15e;if(!this.endContainer){this.setEnd(node,_15e);}else{this._updateInternal();}},setEnd:function(node,_15f){_15f=parseInt(_15f);if(this.endContainer===node&&this.endOffset==_15f){return;}delete this._cachedBookmark;this.endContainer=node;this.endOffset=_15f;if(!this.startContainer){this.setStart(node,_15f);}else{this._updateInternal();}},setStartAfter:function(node,_160){this._setPoint("setStart",node,_160,1);},setStartBefore:function(node,_161){this._setPoint("setStart",node,_161,0);},setEndAfter:function(node,_162){this._setPoint("setEnd",node,_162,1);},setEndBefore:function(node,_163){this._setPoint("setEnd",node,_163,0);},_setPoint:function(what,node,_164,ext){var _165=_5.range.getIndex(node,node.parentNode).o;this[what](node.parentNode,_165.pop()+ext);},_getIERange:function(){var r=(this._body||this.endContainer.ownerDocument.body).createTextRange();_5.range.ie.setRange(r,this.startContainer,this.startOffset,this.endContainer,this.endOffset,this.collapsed);return r;},getBookmark:function(body){this._getIERange();return this._cachedBookmark;},_select:function(){var r=this._getIERange();r.select();},deleteContents:function(){var r=this._getIERange();r.pasteHTML("");this.endContainer=this.startContainer;this.endOffset=this.startOffset;this.collapsed=true;},cloneRange:function(){var r=new _5.range.W3CRange([this.startContainer,this.startOffset,this.endContainer,this.endOffset]);r._body=this._body;return r;},detach:function(){this._body=null;this.commonAncestorContainer=null;this.startContainer=null;this.startOffset=0;this.endContainer=null;this.endOffset=0;this.collapsed=true;}});}}if(!_4._hasResource["dijit._editor.html"]){_4._hasResource["dijit._editor.html"]=true;_4.provide("dijit._editor.html");_4.getObject("_editor",true,_5);_5._editor.escapeXml=function(str,_166){str=str.replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;").replace(/"/gm,"&quot;");if(!_166){str=str.replace(/'/gm,"&#39;");}return str;};_5._editor.getNodeHtml=function(node){var _167;switch(node.nodeType){case 1:var _168=node.nodeName.toLowerCase();if(!_168||_168.charAt(0)=="/"){return "";}_167="<"+_168;var _169=[];var attr;if(_4.isIE&&node.outerHTML){var s=node.outerHTML;s=s.substr(0,s.indexOf(">")).replace(/(['"])[^"']*\1/g,"");var reg=/(\b\w+)\s?=/g;var m,key;while((m=reg.exec(s))){key=m[1];if(key.substr(0,3)!="_dj"){if(key=="src"||key=="href"){if(node.getAttribute("_djrealurl")){_169.push([key,node.getAttribute("_djrealurl")]);continue;}}var val,_16a;switch(key){case "style":val=node.style.cssText.toLowerCase();break;case "class":val=node.className;break;case "width":if(_168==="img"){_16a=/width=(\S+)/i.exec(s);if(_16a){val=_16a[1];}break;}case "height":if(_168==="img"){_16a=/height=(\S+)/i.exec(s);if(_16a){val=_16a[1];}break;}default:val=node.getAttribute(key);}if(val!=null){_169.push([key,val.toString()]);}}}}else{var i=0;while((attr=node.attributes[i++])){var n=attr.name;if(n.substr(0,3)!="_dj"){var v=attr.value;if(n=="src"||n=="href"){if(node.getAttribute("_djrealurl")){v=node.getAttribute("_djrealurl");}}_169.push([n,v]);}}}_169.sort(function(a,b){return a[0]<b[0]?-1:(a[0]==b[0]?0:1);});var j=0;while((attr=_169[j++])){_167+=" "+attr[0]+"=\""+(_4.isString(attr[1])?_5._editor.escapeXml(attr[1],true):attr[1])+"\"";}if(_168==="script"){_167+=">"+node.innerHTML+"</"+_168+">";}else{if(node.childNodes.length){_167+=">"+_5._editor.getChildrenHtml(node)+"</"+_168+">";}else{switch(_168){case "br":case "hr":case "img":case "input":case "base":case "meta":case "area":case "basefont":_167+=" />";break;default:_167+="></"+_168+">";}}}break;case 4:case 3:_167=_5._editor.escapeXml(node.nodeValue,true);break;case 8:_167="<!--"+_5._editor.escapeXml(node.nodeValue,true)+"-->";break;default:_167="<!-- Element not recognized - Type: "+node.nodeType+" Name: "+node.nodeName+"-->";}return _167;};_5._editor.getChildrenHtml=function(dom){var out="";if(!dom){return out;}var _16b=dom["childNodes"]||dom;var _16c=!_4.isIE||_16b!==dom;var node,i=0;while((node=_16b[i++])){if(!_16c||node.parentNode==dom){out+=_5._editor.getNodeHtml(node);}}return out;};}if(!_4._hasResource["dijit._editor.RichText"]){_4._hasResource["dijit._editor.RichText"]=true;_4.provide("dijit._editor.RichText");if(!_4.config["useXDomain"]||_4.config["allowXdRichTextSave"]){if(_4._postLoad){(function(){var _16d=_4.doc.createElement("textarea");_16d.id=_5._scopeName+"._editor.RichText.value";_4.style(_16d,{display:"none",position:"absolute",top:"-100px",height:"3px",width:"3px"});_4.body().appendChild(_16d);})();}else{try{_4.doc.write("<textarea id=\""+_5._scopeName+"._editor.RichText.value\" "+"style=\"display:none;position:absolute;top:-100px;left:-100px;height:3px;width:3px;overflow:hidden;\"></textarea>");}catch(e){}}}_4.declare("dijit._editor.RichText",[_5._Widget,_5._CssStateMixin],{constructor:function(_16e){this.contentPreFilters=[];this.contentPostFilters=[];this.contentDomPreFilters=[];this.contentDomPostFilters=[];this.editingAreaStyleSheets=[];this.events=[].concat(this.events);this._keyHandlers={};if(_16e&&_4.isString(_16e.value)){this.value=_16e.value;}this.onLoadDeferred=new _4.Deferred();},baseClass:"dijitEditor",inheritWidth:false,focusOnLoad:false,name:"",styleSheets:"",height:"300px",minHeight:"1em",isClosed:true,isLoaded:false,_SEPARATOR:"@@**%%__RICHTEXTBOUNDRY__%%**@@",_NAME_CONTENT_SEP:"@@**%%:%%**@@",onLoadDeferred:null,isTabIndent:false,disableSpellCheck:false,postCreate:function(){if("textarea"==this.domNode.tagName.toLowerCase()){console.warn("RichText should not be used with the TEXTAREA tag. See dijit._editor.RichText docs.");}this.contentPreFilters=[_4.hitch(this,"_preFixUrlAttributes")].concat(this.contentPreFilters);if(_4.isMoz){this.contentPreFilters=[this._normalizeFontStyle].concat(this.contentPreFilters);this.contentPostFilters=[this._removeMozBogus].concat(this.contentPostFilters);}if(_4.isWebKit){this.contentPreFilters=[this._removeWebkitBogus].concat(this.contentPreFilters);this.contentPostFilters=[this._removeWebkitBogus].concat(this.contentPostFilters);}if(_4.isIE){this.contentPostFilters=[this._normalizeFontStyle].concat(this.contentPostFilters);}this.inherited(arguments);_4.publish(_5._scopeName+"._editor.RichText::init",[this]);this.open();this.setupDefaultShortcuts();},setupDefaultShortcuts:function(){var exec=_4.hitch(this,function(cmd,arg){return function(){return !this.execCommand(cmd,arg);};});var _16f={b:exec("bold"),i:exec("italic"),u:exec("underline"),a:exec("selectall"),s:function(){this.save(true);},m:function(){this.isTabIndent=!this.isTabIndent;},"1":exec("formatblock","h1"),"2":exec("formatblock","h2"),"3":exec("formatblock","h3"),"4":exec("formatblock","h4"),"\\":exec("insertunorderedlist")};if(!_4.isIE){_16f.Z=exec("redo");}for(var key in _16f){this.addKeyHandler(key,true,false,_16f[key]);}},events:["onKeyPress","onKeyDown","onKeyUp"],captureEvents:[],_editorCommandsLocalized:false,_localizeEditorCommands:function(){if(this._editorCommandsLocalized){return;}this._editorCommandsLocalized=true;var _170=["div","p","pre","h1","h2","h3","h4","h5","h6","ol","ul","address"];var _171="",_172,i=0;while((_172=_170[i++])){if(_172.charAt(1)!="l"){_171+="<"+_172+"><span>content</span></"+_172+"><br/>";}else{_171+="<"+_172+"><li>content</li></"+_172+"><br/>";}}var div=_4.doc.createElement("div");_4.style(div,{position:"absolute",top:"-2000px"});_4.doc.body.appendChild(div);div.innerHTML=_171;var node=div.firstChild;while(node){_5._editor.selection.selectElement(node.firstChild);_4.withGlobal(this.window,"selectElement",_5._editor.selection,[node.firstChild]);var _173=node.tagName.toLowerCase();this._local2NativeFormatNames[_173]=document.queryCommandValue("formatblock");this._native2LocalFormatNames[this._local2NativeFormatNames[_173]]=_173;node=node.nextSibling.nextSibling;}_4.body().removeChild(div);},open:function(_174){if(!this.onLoadDeferred||this.onLoadDeferred.fired>=0){this.onLoadDeferred=new _4.Deferred();}if(!this.isClosed){this.close();}_4.publish(_5._scopeName+"._editor.RichText::open",[this]);if(arguments.length==1&&_174.nodeName){this.domNode=_174;}var dn=this.domNode;var html;if(_4.isString(this.value)){html=this.value;delete this.value;dn.innerHTML="";}else{if(dn.nodeName&&dn.nodeName.toLowerCase()=="textarea"){var ta=(this.textarea=dn);this.name=ta.name;html=ta.value;dn=this.domNode=_4.doc.createElement("div");dn.setAttribute("widgetId",this.id);ta.removeAttribute("widgetId");dn.cssText=ta.cssText;dn.className+=" "+ta.className;_4.place(dn,ta,"before");var _175=_4.hitch(this,function(){_4.style(ta,{display:"block",position:"absolute",top:"-1000px"});if(_4.isIE){var s=ta.style;this.__overflow=s.overflow;s.overflow="hidden";}});if(_4.isIE){setTimeout(_175,10);}else{_175();}if(ta.form){var _176=ta.value;this.reset=function(){var _177=this.getValue();if(_177!=_176){this.replaceValue(_176);}};_4.connect(ta.form,"onsubmit",this,function(){_4.attr(ta,"disabled",this.disabled);ta.value=this.getValue();});}}else{html=_5._editor.getChildrenHtml(dn);dn.innerHTML="";}}var _178=_4.contentBox(dn);this._oldHeight=_178.h;this._oldWidth=_178.w;this.value=html;if(dn.nodeName&&dn.nodeName=="LI"){dn.innerHTML=" <br>";}this.header=dn.ownerDocument.createElement("div");dn.appendChild(this.header);this.editingArea=dn.ownerDocument.createElement("div");dn.appendChild(this.editingArea);this.footer=dn.ownerDocument.createElement("div");dn.appendChild(this.footer);if(!this.name){this.name=this.id+"_AUTOGEN";}if(this.name!==""&&(!_4.config["useXDomain"]||_4.config["allowXdRichTextSave"])){var _179=_4.byId(_5._scopeName+"._editor.RichText.value");if(_179&&_179.value!==""){var _17a=_179.value.split(this._SEPARATOR),i=0,dat;while((dat=_17a[i++])){var data=dat.split(this._NAME_CONTENT_SEP);if(data[0]==this.name){html=data[1];_17a=_17a.splice(i,1);_179.value=_17a.join(this._SEPARATOR);break;}}}if(!_5._editor._globalSaveHandler){_5._editor._globalSaveHandler={};_4.addOnUnload(function(){var id;for(id in _5._editor._globalSaveHandler){var f=_5._editor._globalSaveHandler[id];if(_4.isFunction(f)){f();}}});}_5._editor._globalSaveHandler[this.id]=_4.hitch(this,"_saveContent");}this.isClosed=false;var ifr=(this.editorObject=this.iframe=_4.doc.createElement("iframe"));ifr.id=this.id+"_iframe";this._iframeSrc=this._getIframeDocTxt();ifr.style.border="none";ifr.style.width="100%";if(this._layoutMode){ifr.style.height="100%";}else{if(_4.isIE>=7){if(this.height){ifr.style.height=this.height;}if(this.minHeight){ifr.style.minHeight=this.minHeight;}}else{ifr.style.height=this.height?this.height:this.minHeight;}}ifr.frameBorder=0;ifr._loadFunc=_4.hitch(this,function(win){this.window=win;this.document=this.window.document;if(_4.isIE){this._localizeEditorCommands();}this.onLoad(html);});var s="javascript:parent."+_5._scopeName+".byId(\""+this.id+"\")._iframeSrc";ifr.setAttribute("src",s);this.editingArea.appendChild(ifr);if(_4.isSafari<=4){var src=ifr.getAttribute("src");if(!src||src.indexOf("javascript")==-1){setTimeout(function(){ifr.setAttribute("src",s);},0);}}if(dn.nodeName=="LI"){dn.lastChild.style.marginTop="-1.2em";}_4.addClass(this.domNode,this.baseClass);},_local2NativeFormatNames:{},_native2LocalFormatNames:{},_getIframeDocTxt:function(){var _17b=_4.getComputedStyle(this.domNode);var html="";var _17c=true;if(_4.isIE||_4.isWebKit||(!this.height&&!_4.isMoz)){html="<div id='dijitEditorBody'></div>";_17c=false;}else{if(_4.isMoz){this._cursorToStart=true;html="&nbsp;";}}var font=[_17b.fontWeight,_17b.fontSize,_17b.fontFamily].join(" ");var _17d=_17b.lineHeight;if(_17d.indexOf("px")>=0){_17d=parseFloat(_17d)/parseFloat(_17b.fontSize);}else{if(_17d.indexOf("em")>=0){_17d=parseFloat(_17d);}else{_17d="normal";}}var _17e="";var self=this;this.style.replace(/(^|;)\s*(line-|font-?)[^;]+/ig,function(_17f){_17f=_17f.replace(/^;/ig,"")+";";var s=_17f.split(":")[0];if(s){s=_4.trim(s);s=s.toLowerCase();var i;var sC="";for(i=0;i<s.length;i++){var c=s.charAt(i);switch(c){case "-":i++;c=s.charAt(i).toUpperCase();default:sC+=c;}}_4.style(self.domNode,sC,"");}_17e+=_17f+";";});var _180=_4.query("label[for=\""+this.id+"\"]");return [this.isLeftToRight()?"<html>\n<head>\n":"<html dir='rtl'>\n<head>\n",(_4.isMoz&&_180.length?"<title>"+_180[0].innerHTML+"</title>\n":""),"<meta http-equiv='Content-Type' content='text/html'>\n","<style>\n","\tbody,html {\n","\t\tbackground:transparent;\n","\t\tpadding: 1px 0 0 0;\n","\t\tmargin: -1px 0 0 0;\n",((_4.isWebKit)?"\t\twidth: 100%;\n":""),((_4.isWebKit)?"\t\theight: 100%;\n":""),"\t}\n","\tbody{\n","\t\ttop:0px;\n","\t\tleft:0px;\n","\t\tright:0px;\n","\t\tfont:",font,";\n",((this.height||_4.isOpera)?"":"\t\tposition: fixed;\n"),"\t\tmin-height:",this.minHeight,";\n","\t\tline-height:",_17d,";\n","\t}\n","\tp{ margin: 1em 0; }\n",(!_17c&&!this.height?"\tbody,html {overflow-y: hidden;}\n":""),"\t#dijitEditorBody{overflow-x: auto; overflow-y:"+(this.height?"auto;":"hidden;")+" outline: 0px;}\n","\tli > ul:-moz-first-node, li > ol:-moz-first-node{ padding-top: 1.2em; }\n","\tli{ min-height:1.2em; }\n","</style>\n",this._applyEditingAreaStyleSheets(),"\n","</head>\n<body ",(_17c?"id='dijitEditorBody' ":""),"onload='frameElement._loadFunc(window,document)' style='"+_17e+"'>",html,"</body>\n</html>"].join("");},_applyEditingAreaStyleSheets:function(){var _181=[];if(this.styleSheets){_181=this.styleSheets.split(";");this.styleSheets="";}_181=_181.concat(this.editingAreaStyleSheets);this.editingAreaStyleSheets=[];var text="",i=0,url;while((url=_181[i++])){var _182=(new _4._Url(_4.global.location,url)).toString();this.editingAreaStyleSheets.push(_182);text+="<link rel=\"stylesheet\" type=\"text/css\" href=\""+_182+"\"/>";}return text;},addStyleSheet:function(uri){var url=uri.toString();if(url.charAt(0)=="."||(url.charAt(0)!="/"&&!uri.host)){url=(new _4._Url(_4.global.location,url)).toString();}if(_4.indexOf(this.editingAreaStyleSheets,url)>-1){return;}this.editingAreaStyleSheets.push(url);this.onLoadDeferred.addCallback(_4.hitch(this,function(){if(this.document.createStyleSheet){this.document.createStyleSheet(url);}else{var head=this.document.getElementsByTagName("head")[0];var _183=this.document.createElement("link");_183.rel="stylesheet";_183.type="text/css";_183.href=url;head.appendChild(_183);}}));},removeStyleSheet:function(uri){var url=uri.toString();if(url.charAt(0)=="."||(url.charAt(0)!="/"&&!uri.host)){url=(new _4._Url(_4.global.location,url)).toString();}var _184=_4.indexOf(this.editingAreaStyleSheets,url);if(_184==-1){return;}delete this.editingAreaStyleSheets[_184];_4.withGlobal(this.window,"query",_4,["link:[href=\""+url+"\"]"]).orphan();},disabled:false,_mozSettingProps:{"styleWithCSS":false},_setDisabledAttr:function(_185){_185=!!_185;this._set("disabled",_185);if(!this.isLoaded){return;}if(_4.isIE||_4.isWebKit||_4.isOpera){var _186=_4.isIE&&(this.isLoaded||!this.focusOnLoad);if(_186){this.editNode.unselectable="on";}this.editNode.contentEditable=!_185;if(_186){var _187=this;setTimeout(function(){_187.editNode.unselectable="off";},0);}}else{try{this.document.designMode=(_185?"off":"on");}catch(e){return;}if(!_185&&this._mozSettingProps){var ps=this._mozSettingProps;for(var n in ps){if(ps.hasOwnProperty(n)){try{this.document.execCommand(n,false,ps[n]);}catch(e2){}}}}}this._disabledOK=true;},onLoad:function(html){if(!this.window.__registeredWindow){this.window.__registeredWindow=true;this._iframeRegHandle=_5.registerIframe(this.iframe);}if(!_4.isIE&&!_4.isWebKit&&(this.height||_4.isMoz)){this.editNode=this.document.body;}else{this.editNode=this.document.body.firstChild;var _188=this;if(_4.isIE){this.tabStop=_4.create("div",{tabIndex:-1},this.editingArea);this.iframe.onfocus=function(){_188.editNode.setActive();};}}this.focusNode=this.editNode;var _189=this.events.concat(this.captureEvents);var ap=this.iframe?this.document:this.editNode;_4.forEach(_189,function(item){this.connect(ap,item.toLowerCase(),item);},this);this.connect(ap,"onmouseup","onClick");if(_4.isIE){this.connect(this.document,"onmousedown","_onIEMouseDown");this.editNode.style.zoom=1;}else{this.connect(this.document,"onmousedown",function(){delete this._cursorToStart;});}if(_4.isWebKit){this._webkitListener=this.connect(this.document,"onmouseup","onDisplayChanged");this.connect(this.document,"onmousedown",function(e){var t=e.target;if(t&&(t===this.document.body||t===this.document)){setTimeout(_4.hitch(this,"placeCursorAtEnd"),0);}});}if(_4.isIE){try{this.document.execCommand("RespectVisibilityInDesign",true,null);}catch(e){}}this.isLoaded=true;this.set("disabled",this.disabled);var _18a=_4.hitch(this,function(){this.setValue(html);if(this.onLoadDeferred){this.onLoadDeferred.callback(true);}this.onDisplayChanged();if(this.focusOnLoad){_4.addOnLoad(_4.hitch(this,function(){setTimeout(_4.hitch(this,"focus"),this.updateInterval);}));}this.value=this.getValue(true);});if(this.setValueDeferred){this.setValueDeferred.addCallback(_18a);}else{_18a();}},onKeyDown:function(e){if(e.keyCode===_4.keys.TAB&&this.isTabIndent){_4.stopEvent(e);if(this.queryCommandEnabled((e.shiftKey?"outdent":"indent"))){this.execCommand((e.shiftKey?"outdent":"indent"));}}if(_4.isIE){if(e.keyCode==_4.keys.TAB&&!this.isTabIndent){if(e.shiftKey&&!e.ctrlKey&&!e.altKey){this.iframe.focus();}else{if(!e.shiftKey&&!e.ctrlKey&&!e.altKey){this.tabStop.focus();}}}else{if(e.keyCode===_4.keys.BACKSPACE&&this.document.selection.type==="Control"){_4.stopEvent(e);this.execCommand("delete");}else{if((65<=e.keyCode&&e.keyCode<=90)||(e.keyCode>=37&&e.keyCode<=40)){e.charCode=e.keyCode;this.onKeyPress(e);}}}}return true;},onKeyUp:function(e){return;},setDisabled:function(_18b){_4.deprecated("dijit.Editor::setDisabled is deprecated","use dijit.Editor::attr(\"disabled\",boolean) instead",2);this.set("disabled",_18b);},_setValueAttr:function(_18c){this.setValue(_18c);},_setDisableSpellCheckAttr:function(_18d){if(this.document){_4.attr(this.document.body,"spellcheck",!_18d);}else{this.onLoadDeferred.addCallback(_4.hitch(this,function(){_4.attr(this.document.body,"spellcheck",!_18d);}));}this._set("disableSpellCheck",_18d);},onKeyPress:function(e){var c=(e.keyChar&&e.keyChar.toLowerCase())||e.keyCode,_18e=this._keyHandlers[c],args=arguments;if(_18e&&!e.altKey){_4.some(_18e,function(h){if(!(h.shift^e.shiftKey)&&!(h.ctrl^(e.ctrlKey||e.metaKey))){if(!h.handler.apply(this,args)){e.preventDefault();}return true;}},this);}if(!this._onKeyHitch){this._onKeyHitch=_4.hitch(this,"onKeyPressed");}setTimeout(this._onKeyHitch,1);return true;},addKeyHandler:function(key,ctrl,_18f,_190){if(!_4.isArray(this._keyHandlers[key])){this._keyHandlers[key]=[];}this._keyHandlers[key].push({shift:_18f||false,ctrl:ctrl||false,handler:_190});},onKeyPressed:function(){this.onDisplayChanged();},onClick:function(e){this.onDisplayChanged(e);},_onIEMouseDown:function(e){if(!this._focused&&!this.disabled){this.focus();}},_onBlur:function(e){this.inherited(arguments);var _191=this.getValue(true);if(_191!=this.value){this.onChange(_191);}this._set("value",_191);},_onFocus:function(e){if(!this.disabled){if(!this._disabledOK){this.set("disabled",false);}this.inherited(arguments);}},blur:function(){if(!_4.isIE&&this.window.document.documentElement&&this.window.document.documentElement.focus){this.window.document.documentElement.focus();}else{if(_4.doc.body.focus){_4.doc.body.focus();}}},focus:function(){if(!this.isLoaded){this.focusOnLoad=true;return;}if(this._cursorToStart){delete this._cursorToStart;if(this.editNode.childNodes){this.placeCursorAtStart();return;}}if(!_4.isIE){_5.focus(this.iframe);}else{if(this.editNode&&this.editNode.focus){this.iframe.fireEvent("onfocus",document.createEventObject());}}},updateInterval:200,_updateTimer:null,onDisplayChanged:function(e){if(this._updateTimer){clearTimeout(this._updateTimer);}if(!this._updateHandler){this._updateHandler=_4.hitch(this,"onNormalizedDisplayChanged");}this._updateTimer=setTimeout(this._updateHandler,this.updateInterval);},onNormalizedDisplayChanged:function(){delete this._updateTimer;},onChange:function(_192){},_normalizeCommand:function(cmd,_193){var _194=cmd.toLowerCase();if(_194=="formatblock"){if(_4.isSafari&&_193===undefined){_194="heading";}}else{if(_194=="hilitecolor"&&!_4.isMoz){_194="backcolor";}}return _194;},_qcaCache:{},queryCommandAvailable:function(_195){var ca=this._qcaCache[_195];if(ca!==undefined){return ca;}return (this._qcaCache[_195]=this._queryCommandAvailable(_195));},_queryCommandAvailable:function(_196){var ie=1;var _197=1<<1;var _198=1<<2;var _199=1<<3;function _19a(_19b){return {ie:Boolean(_19b&ie),mozilla:Boolean(_19b&_197),webkit:Boolean(_19b&_198),opera:Boolean(_19b&_199)};};var _19c=null;switch(_196.toLowerCase()){case "bold":case "italic":case "underline":case "subscript":case "superscript":case "fontname":case "fontsize":case "forecolor":case "hilitecolor":case "justifycenter":case "justifyfull":case "justifyleft":case "justifyright":case "delete":case "selectall":case "toggledir":_19c=_19a(_197|ie|_198|_199);break;case "createlink":case "unlink":case "removeformat":case "inserthorizontalrule":case "insertimage":case "insertorderedlist":case "insertunorderedlist":case "indent":case "outdent":case "formatblock":case "inserthtml":case "undo":case "redo":case "strikethrough":case "tabindent":_19c=_19a(_197|ie|_199|_198);break;case "blockdirltr":case "blockdirrtl":case "dirltr":case "dirrtl":case "inlinedirltr":case "inlinedirrtl":_19c=_19a(ie);break;case "cut":case "copy":case "paste":_19c=_19a(ie|_197|_198);break;case "inserttable":_19c=_19a(_197|ie);break;case "insertcell":case "insertcol":case "insertrow":case "deletecells":case "deletecols":case "deleterows":case "mergecells":case "splitcell":_19c=_19a(ie|_197);break;default:return false;}return (_4.isIE&&_19c.ie)||(_4.isMoz&&_19c.mozilla)||(_4.isWebKit&&_19c.webkit)||(_4.isOpera&&_19c.opera);},execCommand:function(_19d,_19e){var _19f;this.focus();_19d=this._normalizeCommand(_19d,_19e);if(_19e!==undefined){if(_19d=="heading"){throw new Error("unimplemented");}else{if((_19d=="formatblock")&&_4.isIE){_19e="<"+_19e+">";}}}var _1a0="_"+_19d+"Impl";if(this[_1a0]){_19f=this[_1a0](_19e);}else{_19e=arguments.length>1?_19e:null;if(_19e||_19d!="createlink"){_19f=this.document.execCommand(_19d,false,_19e);}}this.onDisplayChanged();return _19f;},queryCommandEnabled:function(_1a1){if(this.disabled||!this._disabledOK){return false;}_1a1=this._normalizeCommand(_1a1);if(_4.isMoz||_4.isWebKit){if(_1a1=="unlink"){return this._sCall("hasAncestorElement",["a"]);}else{if(_1a1=="inserttable"){return true;}}}if(_4.isWebKit){if(_1a1=="cut"||_1a1=="copy"){var sel=this.window.getSelection();if(sel){sel=sel.toString();}return !!sel;}else{if(_1a1=="paste"){return true;}}}var elem=_4.isIE?this.document.selection.createRange():this.document;try{return elem.queryCommandEnabled(_1a1);}catch(e){return false;}},queryCommandState:function(_1a2){if(this.disabled||!this._disabledOK){return false;}_1a2=this._normalizeCommand(_1a2);try{return this.document.queryCommandState(_1a2);}catch(e){return false;}},queryCommandValue:function(_1a3){if(this.disabled||!this._disabledOK){return false;}var r;_1a3=this._normalizeCommand(_1a3);if(_4.isIE&&_1a3=="formatblock"){r=this._native2LocalFormatNames[this.document.queryCommandValue(_1a3)];}else{if(_4.isMoz&&_1a3==="hilitecolor"){var _1a4;try{_1a4=this.document.queryCommandValue("styleWithCSS");}catch(e){_1a4=false;}this.document.execCommand("styleWithCSS",false,true);r=this.document.queryCommandValue(_1a3);this.document.execCommand("styleWithCSS",false,_1a4);}else{r=this.document.queryCommandValue(_1a3);}}return r;},_sCall:function(name,args){return _4.withGlobal(this.window,name,_5._editor.selection,args);},placeCursorAtStart:function(){this.focus();var _1a5=false;if(_4.isMoz){var _1a6=this.editNode.firstChild;while(_1a6){if(_1a6.nodeType==3){if(_1a6.nodeValue.replace(/^\s+|\s+$/g,"").length>0){_1a5=true;this._sCall("selectElement",[_1a6]);break;}}else{if(_1a6.nodeType==1){_1a5=true;var tg=_1a6.tagName?_1a6.tagName.toLowerCase():"";if(/br|input|img|base|meta|area|basefont|hr|link/.test(tg)){this._sCall("selectElement",[_1a6]);}else{this._sCall("selectElementChildren",[_1a6]);}break;}}_1a6=_1a6.nextSibling;}}else{_1a5=true;this._sCall("selectElementChildren",[this.editNode]);}if(_1a5){this._sCall("collapse",[true]);}},placeCursorAtEnd:function(){this.focus();var _1a7=false;if(_4.isMoz){var last=this.editNode.lastChild;while(last){if(last.nodeType==3){if(last.nodeValue.replace(/^\s+|\s+$/g,"").length>0){_1a7=true;this._sCall("selectElement",[last]);break;}}else{if(last.nodeType==1){_1a7=true;if(last.lastChild){this._sCall("selectElement",[last.lastChild]);}else{this._sCall("selectElement",[last]);}break;}}last=last.previousSibling;}}else{_1a7=true;this._sCall("selectElementChildren",[this.editNode]);}if(_1a7){this._sCall("collapse",[false]);}},getValue:function(_1a8){if(this.textarea){if(this.isClosed||!this.isLoaded){return this.textarea.value;}}return this._postFilterContent(null,_1a8);},_getValueAttr:function(){return this.getValue(true);},setValue:function(html){if(!this.isLoaded){this.onLoadDeferred.addCallback(_4.hitch(this,function(){this.setValue(html);}));return;}this._cursorToStart=true;if(this.textarea&&(this.isClosed||!this.isLoaded)){this.textarea.value=html;}else{html=this._preFilterContent(html);var node=this.isClosed?this.domNode:this.editNode;if(html&&_4.isMoz&&html.toLowerCase()=="<p></p>"){html="<p>&nbsp;</p>";}if(!html&&_4.isWebKit){html="&nbsp;";}node.innerHTML=html;this._preDomFilterContent(node);}this.onDisplayChanged();this._set("value",this.getValue(true));},replaceValue:function(html){if(this.isClosed){this.setValue(html);}else{if(this.window&&this.window.getSelection&&!_4.isMoz){this.setValue(html);}else{if(this.window&&this.window.getSelection){html=this._preFilterContent(html);this.execCommand("selectall");if(!html){this._cursorToStart=true;html="&nbsp;";}this.execCommand("inserthtml",html);this._preDomFilterContent(this.editNode);}else{if(this.document&&this.document.selection){this.setValue(html);}}}}this._set("value",this.getValue(true));},_preFilterContent:function(html){var ec=html;_4.forEach(this.contentPreFilters,function(ef){if(ef){ec=ef(ec);}});return ec;},_preDomFilterContent:function(dom){dom=dom||this.editNode;_4.forEach(this.contentDomPreFilters,function(ef){if(ef&&_4.isFunction(ef)){ef(dom);}},this);},_postFilterContent:function(dom,_1a9){var ec;if(!_4.isString(dom)){dom=dom||this.editNode;if(this.contentDomPostFilters.length){if(_1a9){dom=_4.clone(dom);}_4.forEach(this.contentDomPostFilters,function(ef){dom=ef(dom);});}ec=_5._editor.getChildrenHtml(dom);}else{ec=dom;}if(!_4.trim(ec.replace(/^\xA0\xA0*/,"").replace(/\xA0\xA0*$/,"")).length){ec="";}_4.forEach(this.contentPostFilters,function(ef){ec=ef(ec);});return ec;},_saveContent:function(e){var _1aa=_4.byId(_5._scopeName+"._editor.RichText.value");if(_1aa.value){_1aa.value+=this._SEPARATOR;}_1aa.value+=this.name+this._NAME_CONTENT_SEP+this.getValue(true);},escapeXml:function(str,_1ab){str=str.replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;").replace(/"/gm,"&quot;");if(!_1ab){str=str.replace(/'/gm,"&#39;");}return str;},getNodeHtml:function(node){_4.deprecated("dijit.Editor::getNodeHtml is deprecated","use dijit._editor.getNodeHtml instead",2);return _5._editor.getNodeHtml(node);},getNodeChildrenHtml:function(dom){_4.deprecated("dijit.Editor::getNodeChildrenHtml is deprecated","use dijit._editor.getChildrenHtml instead",2);return _5._editor.getChildrenHtml(dom);},close:function(save){if(this.isClosed){return;}if(!arguments.length){save=true;}if(save){this._set("value",this.getValue(true));}if(this.interval){clearInterval(this.interval);}if(this._webkitListener){this.disconnect(this._webkitListener);delete this._webkitListener;}if(_4.isIE){this.iframe.onfocus=null;}this.iframe._loadFunc=null;if(this._iframeRegHandle){_5.unregisterIframe(this._iframeRegHandle);delete this._iframeRegHandle;}if(this.textarea){var s=this.textarea.style;s.position="";s.left=s.top="";if(_4.isIE){s.overflow=this.__overflow;this.__overflow=null;}this.textarea.value=this.value;_4.destroy(this.domNode);this.domNode=this.textarea;}else{this.domNode.innerHTML=this.value;}delete this.iframe;_4.removeClass(this.domNode,this.baseClass);this.isClosed=true;this.isLoaded=false;delete this.editNode;delete this.focusNode;if(this.window&&this.window._frameElement){this.window._frameElement=null;}this.window=null;this.document=null;this.editingArea=null;this.editorObject=null;},destroy:function(){if(!this.isClosed){this.close(false);}this.inherited(arguments);if(_5._editor._globalSaveHandler){delete _5._editor._globalSaveHandler[this.id];}},_removeMozBogus:function(html){return html.replace(/\stype="_moz"/gi,"").replace(/\s_moz_dirty=""/gi,"").replace(/_moz_resizing="(true|false)"/gi,"");},_removeWebkitBogus:function(html){html=html.replace(/\sclass="webkit-block-placeholder"/gi,"");html=html.replace(/\sclass="apple-style-span"/gi,"");html=html.replace(/<meta charset=\"utf-8\" \/>/gi,"");return html;},_normalizeFontStyle:function(html){return html.replace(/<(\/)?strong([ \>])/gi,"<$1b$2").replace(/<(\/)?em([ \>])/gi,"<$1i$2");},_preFixUrlAttributes:function(html){return html.replace(/(?:(<a(?=\s).*?\shref=)("|')(.*?)\2)|(?:(<a\s.*?href=)([^"'][^ >]+))/gi,"$1$4$2$3$5$2 _djrealurl=$2$3$5$2").replace(/(?:(<img(?=\s).*?\ssrc=)("|')(.*?)\2)|(?:(<img\s.*?src=)([^"'][^ >]+))/gi,"$1$4$2$3$5$2 _djrealurl=$2$3$5$2");},_inserthorizontalruleImpl:function(_1ac){if(_4.isIE){return this._inserthtmlImpl("<hr>");}return this.document.execCommand("inserthorizontalrule",false,_1ac);},_unlinkImpl:function(_1ad){if((this.queryCommandEnabled("unlink"))&&(_4.isMoz||_4.isWebKit)){var a=this._sCall("getAncestorElement",["a"]);this._sCall("selectElement",[a]);return this.document.execCommand("unlink",false,null);}return this.document.execCommand("unlink",false,_1ad);},_hilitecolorImpl:function(_1ae){var _1af;if(_4.isMoz){this.document.execCommand("styleWithCSS",false,true);_1af=this.document.execCommand("hilitecolor",false,_1ae);this.document.execCommand("styleWithCSS",false,false);}else{_1af=this.document.execCommand("hilitecolor",false,_1ae);}return _1af;},_backcolorImpl:function(_1b0){if(_4.isIE){_1b0=_1b0?_1b0:null;}return this.document.execCommand("backcolor",false,_1b0);},_forecolorImpl:function(_1b1){if(_4.isIE){_1b1=_1b1?_1b1:null;}return this.document.execCommand("forecolor",false,_1b1);},_inserthtmlImpl:function(_1b2){_1b2=this._preFilterContent(_1b2);var rv=true;if(_4.isIE){var _1b3=this.document.selection.createRange();if(this.document.selection.type.toUpperCase()=="CONTROL"){var n=_1b3.item(0);while(_1b3.length){_1b3.remove(_1b3.item(0));}n.outerHTML=_1b2;}else{_1b3.pasteHTML(_1b2);}_1b3.select();}else{if(_4.isMoz&&!_1b2.length){this._sCall("remove");}else{rv=this.document.execCommand("inserthtml",false,_1b2);}}return rv;},_boldImpl:function(_1b4){if(_4.isIE){this._adaptIESelection();}return this.document.execCommand("bold",false,_1b4);},_italicImpl:function(_1b5){if(_4.isIE){this._adaptIESelection();}return this.document.execCommand("italic",false,_1b5);},_underlineImpl:function(_1b6){if(_4.isIE){this._adaptIESelection();}return this.document.execCommand("underline",false,_1b6);},_strikethroughImpl:function(_1b7){if(_4.isIE){this._adaptIESelection();}return this.document.execCommand("strikethrough",false,_1b7);},getHeaderHeight:function(){return this._getNodeChildrenHeight(this.header);},getFooterHeight:function(){return this._getNodeChildrenHeight(this.footer);},_getNodeChildrenHeight:function(node){var h=0;if(node&&node.childNodes){var i;for(i=0;i<node.childNodes.length;i++){var size=_4.position(node.childNodes[i]);h+=size.h;}}return h;},_isNodeEmpty:function(node,_1b8){if(node.nodeType==1){if(node.childNodes.length>0){return this._isNodeEmpty(node.childNodes[0],_1b8);}return true;}else{if(node.nodeType==3){return (node.nodeValue.substring(_1b8)=="");}}return false;},_removeStartingRangeFromRange:function(node,_1b9){if(node.nextSibling){_1b9.setStart(node.nextSibling,0);}else{var _1ba=node.parentNode;while(_1ba&&_1ba.nextSibling==null){_1ba=_1ba.parentNode;}if(_1ba){_1b9.setStart(_1ba.nextSibling,0);}}return _1b9;},_adaptIESelection:function(){var _1bb=_5.range.getSelection(this.window);if(_1bb&&_1bb.rangeCount){var _1bc=_1bb.getRangeAt(0);var _1bd=_1bc.startContainer;var _1be=_1bc.startOffset;while(_1bd.nodeType==3&&_1be>=_1bd.length&&_1bd.nextSibling){_1be=_1be-_1bd.length;_1bd=_1bd.nextSibling;}var _1bf=null;while(this._isNodeEmpty(_1bd,_1be)&&_1bd!=_1bf){_1bf=_1bd;_1bc=this._removeStartingRangeFromRange(_1bd,_1bc);_1bd=_1bc.startContainer;_1be=0;}_1bb.removeAllRanges();_1bb.addRange(_1bc);}}});}if(!_4._hasResource["dijit._KeyNavContainer"]){_4._hasResource["dijit._KeyNavContainer"]=true;_4.provide("dijit._KeyNavContainer");_4.declare("dijit._KeyNavContainer",_5._Container,{tabIndex:"0",_keyNavCodes:{},connectKeyNavHandlers:function(_1c0,_1c1){var _1c2=(this._keyNavCodes={});var prev=_4.hitch(this,this.focusPrev);var next=_4.hitch(this,this.focusNext);_4.forEach(_1c0,function(code){_1c2[code]=prev;});_4.forEach(_1c1,function(code){_1c2[code]=next;});_1c2[_4.keys.HOME]=_4.hitch(this,"focusFirstChild");_1c2[_4.keys.END]=_4.hitch(this,"focusLastChild");this.connect(this.domNode,"onkeypress","_onContainerKeypress");this.connect(this.domNode,"onfocus","_onContainerFocus");},startupKeyNavChildren:function(){_4.forEach(this.getChildren(),_4.hitch(this,"_startupChild"));},addChild:function(_1c3,_1c4){_5._KeyNavContainer.superclass.addChild.apply(this,arguments);this._startupChild(_1c3);},focus:function(){this.focusFirstChild();},focusFirstChild:function(){var _1c5=this._getFirstFocusableChild();if(_1c5){this.focusChild(_1c5);}},focusLastChild:function(){var _1c6=this._getLastFocusableChild();if(_1c6){this.focusChild(_1c6);}},focusNext:function(){var _1c7=this._getNextFocusableChild(this.focusedChild,1);this.focusChild(_1c7);},focusPrev:function(){var _1c8=this._getNextFocusableChild(this.focusedChild,-1);this.focusChild(_1c8,true);},focusChild:function(_1c9,last){if(this.focusedChild&&_1c9!==this.focusedChild){this._onChildBlur(this.focusedChild);}_1c9.focus(last?"end":"start");this._set("focusedChild",_1c9);},_startupChild:function(_1ca){_1ca.set("tabIndex","-1");this.connect(_1ca,"_onFocus",function(){_1ca.set("tabIndex",this.tabIndex);});this.connect(_1ca,"_onBlur",function(){_1ca.set("tabIndex","-1");});},_onContainerFocus:function(evt){if(evt.target!==this.domNode){return;}this.focusFirstChild();_4.attr(this.domNode,"tabIndex","-1");},_onBlur:function(evt){if(this.tabIndex){_4.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();_4.stopEvent(evt);}},_onChildBlur:function(_1cb){},_getFirstFocusableChild:function(){return this._getNextFocusableChild(null,1);},_getLastFocusableChild:function(){return this._getNextFocusableChild(null,-1);},_getNextFocusableChild:function(_1cc,dir){if(_1cc){_1cc=this._getSiblingOfChild(_1cc,dir);}var _1cd=this.getChildren();for(var i=0;i<_1cd.length;i++){if(!_1cc){_1cc=_1cd[(dir>0)?0:(_1cd.length-1)];}if(_1cc.isFocusable()){return _1cc;}_1cc=this._getSiblingOfChild(_1cc,dir);}return null;}});}if(!_4._hasResource["dijit.ToolbarSeparator"]){_4._hasResource["dijit.ToolbarSeparator"]=true;_4.provide("dijit.ToolbarSeparator");_4.declare("dijit.ToolbarSeparator",[_5._Widget,_5._Templated],{templateString:"<div class=\"dijitToolbarSeparator dijitInline\" role=\"presentation\"></div>",buildRendering:function(){this.inherited(arguments);_4.setSelectable(this.domNode,false);},isFocusable:function(){return false;}});}if(!_4._hasResource["dijit.Toolbar"]){_4._hasResource["dijit.Toolbar"]=true;_4.provide("dijit.Toolbar");_4.declare("dijit.Toolbar",[_5._Widget,_5._Templated,_5._KeyNavContainer],{templateString:"<div class=\"dijit\" role=\"toolbar\" tabIndex=\"${tabIndex}\" dojoAttachPoint=\"containerNode\">"+"</div>",baseClass:"dijitToolbar",postCreate:function(){this.inherited(arguments);this.connectKeyNavHandlers(this.isLeftToRight()?[_4.keys.LEFT_ARROW]:[_4.keys.RIGHT_ARROW],this.isLeftToRight()?[_4.keys.RIGHT_ARROW]:[_4.keys.LEFT_ARROW]);},startup:function(){if(this._started){return;}this.startupKeyNavChildren();this.inherited(arguments);}});}if(!_4._hasResource["dijit._HasDropDown"]){_4._hasResource["dijit._HasDropDown"]=true;_4.provide("dijit._HasDropDown");_4.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(_4.doc,"onmouseup","_onDropDownMouseUp");this.toggleDropDown();},_onDropDownMouseUp:function(e){if(e&&this._docHandler){this.disconnect(this._docHandler);}var _1ce=this.dropDown,_1cf=false;if(e&&this._opened){var c=_4.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&&!_1cf){if(_4.hasClass(t,"dijitPopup")){_1cf=true;}else{t=t.parentNode;}}if(_1cf){t=e.target;if(_1ce.onItemClick){var _1d0;while(t&&!(_1d0=_5.byNode(t))){t=t.parentNode;}if(_1d0&&_1d0.onClick&&_1d0.getParent){_1d0.getParent().onItemClick(_1d0,e);}}return;}}}if(this._opened&&_1ce.focus&&_1ce.autoFocus!==false){window.setTimeout(_4.hitch(_1ce,"focus"),1);}},_onDropDownClick:function(e){if(this._stopClickEvents){_4.stopEvent(e);}},buildRendering:function(){this.inherited(arguments);this._buttonNode=this._buttonNode||this.focusNode||this.domNode;this._popupStateNode=this._popupStateNode||this.focusNode||this._buttonNode;var _1d1={"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";_4.addClass(this._arrowWrapperNode||this._buttonNode,"dijit"+_1d1+"ArrowButton");},postCreate:function(){this.inherited(arguments);this.connect(this._buttonNode,"onmousedown","_onDropDownMouseDown");this.connect(this._buttonNode,"onclick","_onDropDownClick");this.connect(this.focusNode,"onkeypress","_onKey");},destroy:function(){if(this.dropDown){if(!this.dropDown._destroyed){this.dropDown.destroyRecursive();}delete this.dropDown;}this.inherited(arguments);},_onKey:function(e){if(this.disabled||this.readOnly){return;}var d=this.dropDown,_1d2=e.target;if(d&&this._opened&&d.handleKey){if(d.handleKey(e)===false){_4.stopEvent(e);return;}}if(d&&this._opened&&e.charOrCode==_4.keys.ESCAPE){this.closeDropDown();_4.stopEvent(e);}else{if(!this._opened&&(e.charOrCode==_4.keys.DOWN_ARROW||((e.charOrCode==_4.keys.ENTER||e.charOrCode==" ")&&((_1d2.tagName||"").toLowerCase()!=="input"||(_1d2.type&&_1d2.type.toLowerCase()!=="text"))))){this.toggleDropDown();d=this.dropDown;if(d&&d.focus){setTimeout(_4.hitch(d,"focus"),1);}_4.stopEvent(e);}}},_onBlur:function(){var _1d3=_5._curFocus&&this.dropDown&&_4.isDescendant(_5._curFocus,this.dropDown.domNode);this.closeDropDown(_1d3);this.inherited(arguments);},isLoaded:function(){return true;},loadDropDown:function(_1d4){_1d4();},toggleDropDown:function(){if(this.disabled||this.readOnly){return;}if(!this._opened){if(!this.isLoaded()){this.loadDropDown(_4.hitch(this,"openDropDown"));return;}else{this.openDropDown();}}else{this.closeDropDown();}},openDropDown:function(){var _1d5=this.dropDown,_1d6=_1d5.domNode,_1d7=this._aroundNode||this.domNode,self=this;if(!this._preparedNode){this._preparedNode=true;if(_1d6.style.width){this._explicitDDWidth=true;}if(_1d6.style.height){this._explicitDDHeight=true;}}if(this.maxHeight||this.forceWidth||this.autoWidth){var _1d8={display:"",visibility:"hidden"};if(!this._explicitDDWidth){_1d8.width="";}if(!this._explicitDDHeight){_1d8.height="";}_4.style(_1d6,_1d8);var _1d9=this.maxHeight;if(_1d9==-1){var _1da=_4.window.getBox(),_1db=_4.position(_1d7,false);_1d9=Math.floor(Math.max(_1db.y,_1da.h-(_1db.y+_1db.h)));}if(_1d5.startup&&!_1d5._started){_1d5.startup();}_5.popup.moveOffScreen(_1d5);var mb=_4._getMarginSize(_1d6);var _1dc=(_1d9&&mb.h>_1d9);_4.style(_1d6,{overflowX:"hidden",overflowY:_1dc?"auto":"hidden"});if(_1dc){mb.h=_1d9;if("w" in mb){mb.w+=16;}}else{delete mb.h;}if(this.forceWidth){mb.w=_1d7.offsetWidth;}else{if(this.autoWidth){mb.w=Math.max(mb.w,_1d7.offsetWidth);}else{delete mb.w;}}if(_4.isFunction(_1d5.resize)){_1d5.resize(mb);}else{_4.marginBox(_1d6,mb);}}var _1dd=_5.popup.open({parent:this,popup:_1d5,around:_1d7,orient:_5.getPopupAroundAlignment((this.dropDownPosition&&this.dropDownPosition.length)?this.dropDownPosition:["below"],this.isLeftToRight()),onExecute:function(){self.closeDropDown(true);},onCancel:function(){self.closeDropDown(true);},onClose:function(){_4.attr(self._popupStateNode,"popupActive",false);_4.removeClass(self._popupStateNode,"dijitHasDropDownOpen");self._opened=false;}});_4.attr(this._popupStateNode,"popupActive","true");_4.addClass(self._popupStateNode,"dijitHasDropDownOpen");this._opened=true;return _1dd;},closeDropDown:function(_1de){if(this._opened){if(_1de){this.focus();}_5.popup.close(this.dropDown);this._opened=false;}}});}if(!_4._hasResource["dijit.form.Button"]){_4._hasResource["dijit.form.Button"]=true;_4.provide("dijit.form.Button");_4.declare("dijit.form.Button",_5.form._FormWidget,{label:"",showLabel:true,iconClass:"",type:"button",baseClass:"dijitButton",templateString:_4.cache("dijit.form","templates/Button.html","<span class=\"dijit dijitReset dijitInline\"\r\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\r\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\"\r\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\r\n\t\t\tdojoAttachPoint=\"titleNode,focusNode\"\r\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\r\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\"></span\r\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\r\n\t\t\t\tid=\"${id}_label\"\r\n\t\t\t\tdojoAttachPoint=\"containerNode\"\r\n\t\t\t></span\r\n\t\t></span\r\n\t></span\r\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\r\n\t\tdojoAttachPoint=\"valueNode\"\r\n/></span>\r\n"),attributeMap:_4.delegate(_5.form._FormWidget.prototype.attributeMap,{value:"valueNode"}),_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 _1df=_5.byNode(node);if(_1df&&typeof _1df._onSubmit=="function"){_1df._onSubmit(e);break;}}}else{if(this.valueNode){this.valueNode.click();e.preventDefault();}}}},buildRendering:function(){this.inherited(arguments);_4.setSelectable(this.focusNode,false);},_fillContent:function(_1e0){if(_1e0&&(!this.params||!("label" in this.params))){this.set("label",_1e0.innerHTML);}},_setShowLabelAttr:function(val){if(this.containerNode){_4.toggleClass(this.containerNode,"dijitDisplayNone",!val);}this._set("showLabel",val);},onClick:function(e){return true;},_clicked:function(e){},setLabel:function(_1e1){_4.deprecated("dijit.form.Button.setLabel() is deprecated. Use set('label', ...) instead.","","2.0");this.set("label",_1e1);},_setLabelAttr:function(_1e2){this._set("label",_1e2);this.containerNode.innerHTML=_1e2;if(this.showLabel==false&&!this.params.title){this.titleNode.title=_4.trim(this.containerNode.innerText||this.containerNode.textContent||"");}},_setIconClassAttr:function(val){var _1e3=this.iconClass||"dijitNoIcon",_1e4=val||"dijitNoIcon";_4.replaceClass(this.iconNode,_1e4,_1e3);this._set("iconClass",val);}});_4.declare("dijit.form.DropDownButton",[_5.form.Button,_5._Container,_5._HasDropDown],{baseClass:"dijitDropDownButton",templateString:_4.cache("dijit.form","templates/DropDownButton.html","<span class=\"dijit dijitReset dijitInline\"\r\n\t><span class='dijitReset dijitInline dijitButtonNode'\r\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\" dojoAttachPoint=\"_buttonNode\"\r\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\r\n\t\t\tdojoAttachPoint=\"focusNode,titleNode,_arrowWrapperNode\"\r\n\t\t\trole=\"button\" aria-haspopup=\"true\" aria-labelledby=\"${id}_label\"\r\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\"\r\n\t\t\t\tdojoAttachPoint=\"iconNode\"\r\n\t\t\t></span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\r\n\t\t\t\tdojoAttachPoint=\"containerNode,_popupStateNode\"\r\n\t\t\t\tid=\"${id}_label\"\r\n\t\t\t></span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonInner\"></span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonChar\">&#9660;</span\r\n\t\t></span\r\n\t></span\r\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\r\n\t\tdojoAttachPoint=\"valueNode\"\r\n/></span>\r\n"),_fillContent:function(){if(this.srcNodeRef){var _1e5=_4.query("*",this.srcNodeRef);_5.form.DropDownButton.superclass._fillContent.call(this,_1e5[0]);this.dropDownContainer=this.srcNodeRef;}},startup:function(){if(this._started){return;}if(!this.dropDown&&this.dropDownContainer){var _1e6=_4.query("[widgetId]",this.dropDownContainer)[0];this.dropDown=_5.byNode(_1e6);delete this.dropDownContainer;}if(this.dropDown){_5.popup.hide(this.dropDown);}this.inherited(arguments);},isLoaded:function(){var _1e7=this.dropDown;return (!!_1e7&&(!_1e7.href||_1e7.isLoaded));},loadDropDown:function(){var _1e8=this.dropDown;if(!_1e8){return;}if(!this.isLoaded()){var _1e9=_4.connect(_1e8,"onLoad",this,function(){_4.disconnect(_1e9);this.openDropDown();});_1e8.refresh();}else{this.openDropDown();}},isFocusable:function(){return this.inherited(arguments)&&!this._mouseDown;}});_4.declare("dijit.form.ComboButton",_5.form.DropDownButton,{templateString:_4.cache("dijit.form","templates/ComboButton.html","<table class=\"dijit dijitReset dijitInline dijitLeft\"\r\n\tcellspacing='0' cellpadding='0' role=\"presentation\"\r\n\t><tbody role=\"presentation\"><tr role=\"presentation\"\r\n\t\t><td class=\"dijitReset dijitStretch dijitButtonNode\" dojoAttachPoint=\"buttonNode\" dojoAttachEvent=\"ondijitclick:_onButtonClick,onkeypress:_onButtonKeyPress\"\r\n\t\t><div id=\"${id}_button\" class=\"dijitReset dijitButtonContents\"\r\n\t\t\tdojoAttachPoint=\"titleNode\"\r\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\r\n\t\t\t><div class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\" role=\"presentation\"></div\r\n\t\t\t><div class=\"dijitReset dijitInline dijitButtonText\" id=\"${id}_label\" dojoAttachPoint=\"containerNode\" role=\"presentation\"></div\r\n\t\t></div\r\n\t\t></td\r\n\t\t><td id=\"${id}_arrow\" class='dijitReset dijitRight dijitButtonNode dijitArrowButton'\r\n\t\t\tdojoAttachPoint=\"_popupStateNode,focusNode,_buttonNode\"\r\n\t\t\tdojoAttachEvent=\"onkeypress:_onArrowKeyPress\"\r\n\t\t\ttitle=\"${optionsTitle}\"\r\n\t\t\trole=\"button\" aria-haspopup=\"true\"\r\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" role=\"presentation\"></div\r\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" role=\"presentation\">&#9660;</div\r\n\t\t></td\r\n\t\t><td style=\"display:none !important;\"\r\n\t\t\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" dojoAttachPoint=\"valueNode\"\r\n\t\t/></td></tr></tbody\r\n></table>\r\n"),attributeMap:_4.mixin(_4.clone(_5.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==_4.keys[this.isLeftToRight()?"RIGHT_ARROW":"LEFT_ARROW"]){_5.focus(this._popupStateNode);_4.stopEvent(evt);}},_onArrowKeyPress:function(evt){if(evt.charOrCode==_4.keys[this.isLeftToRight()?"LEFT_ARROW":"RIGHT_ARROW"]){_5.focus(this.titleNode);_4.stopEvent(evt);}},focus:function(_1ea){if(!this.disabled){_5.focus(_1ea=="start"?this.titleNode:this._popupStateNode);}}});_4.declare("dijit.form.ToggleButton",_5.form.Button,{baseClass:"dijitToggleButton",checked:false,attributeMap:_4.mixin(_4.clone(_5.form.Button.prototype.attributeMap),{checked:"focusNode"}),_clicked:function(evt){this.set("checked",!this.checked);},_setCheckedAttr:function(_1eb,_1ec){this._set("checked",_1eb);_4.attr(this.focusNode||this.domNode,"checked",_1eb);_5.setWaiState(this.focusNode||this.domNode,"pressed",_1eb);this._handleOnChange(_1eb,_1ec);},setChecked:function(_1ed){_4.deprecated("setChecked("+_1ed+") is deprecated. Use set('checked',"+_1ed+") instead.","","2.0");this.set("checked",_1ed);},reset:function(){this._hasBeenBlurred=false;this.set("checked",this.params.checked||false);}});}if(!_4._hasResource["dijit._editor._Plugin"]){_4._hasResource["dijit._editor._Plugin"]=true;_4.provide("dijit._editor._Plugin");_4.declare("dijit._editor._Plugin",null,{constructor:function(args,node){this.params=args||{};_4.mixin(this,this.params);this._connects=[];this._attrPairNames={};},editor:null,iconClassPrefix:"dijitEditorIcon",button:null,command:"",useDefaultCommand:true,buttonClass:_5.form.Button,disabled:false,getLabel:function(key){return this.editor.commands[key];},_initButton:function(){if(this.command.length){var _1ee=this.getLabel(this.command),_1ef=this.editor,_1f0=this.iconClassPrefix+" "+this.iconClassPrefix+this.command.charAt(0).toUpperCase()+this.command.substr(1);if(!this.button){var _1f1=_4.mixin({label:_1ee,dir:_1ef.dir,lang:_1ef.lang,showLabel:false,iconClass:_1f0,dropDown:this.dropDown,tabIndex:"-1"},this.params||{});this.button=new this.buttonClass(_1f1);}}if(this.get("disabled")&&this.button){this.button.set("disabled",this.get("disabled"));}},destroy:function(){_4.forEach(this._connects,_4.disconnect);if(this.dropDown){this.dropDown.destroyRecursive();}},connect:function(o,f,tf){this._connects.push(_4.connect(o,f,this,tf));},updateState:function(){var e=this.editor,c=this.command,_1f2,_1f3;if(!e||!e.isLoaded||!c.length){return;}var _1f4=this.get("disabled");if(this.button){try{_1f3=!_1f4&&e.queryCommandEnabled(c);if(this.enabled!==_1f3){this.enabled=_1f3;this.button.set("disabled",!_1f3);}if(typeof this.button.checked=="boolean"){_1f2=e.queryCommandState(c);if(this.checked!==_1f2){this.checked=_1f2;this.button.set("checked",e.queryCommandState(c));}}}catch(e){}}},setEditor:function(_1f5){this.editor=_1f5;this._initButton();if(this.button&&this.useDefaultCommand){if(this.editor.queryCommandAvailable(this.command)){this.connect(this.button,"onClick",_4.hitch(this.editor,"execCommand",this.command,this.commandArg));}else{this.button.domNode.style.display="none";}}this.connect(this.editor,"onNormalizedDisplayChanged","updateState");},setToolbar:function(_1f6){if(this.button){_1f6.addChild(this.button);}},set:function(name,_1f7){if(typeof name==="object"){for(var x in name){this.set(x,name[x]);}return this;}var _1f8=this._getAttrNames(name);if(this[_1f8.s]){var _1f9=this[_1f8.s].apply(this,Array.prototype.slice.call(arguments,1));}else{this._set(name,_1f7);}return _1f9||this;},get:function(name){var _1fa=this._getAttrNames(name);return this[_1fa.g]?this[_1fa.g]():this[name];},_setDisabledAttr:function(_1fb){this.disabled=_1fb;this.updateState();},_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]={s:"_set"+uc+"Attr",g:"_get"+uc+"Attr"});},_set:function(name,_1fc){var _1fd=this[name];this[name]=_1fc;}});}if(!_4._hasResource["dijit._editor.plugins.EnterKeyHandling"]){_4._hasResource["dijit._editor.plugins.EnterKeyHandling"]=true;_4.provide("dijit._editor.plugins.EnterKeyHandling");_4.declare("dijit._editor.plugins.EnterKeyHandling",_5._editor._Plugin,{blockNodeForEnter:"BR",constructor:function(args){if(args){if("blockNodeForEnter" in args){args.blockNodeForEnter=args.blockNodeForEnter.toUpperCase();}_4.mixin(this,args);}},setEditor:function(_1fe){if(this.editor===_1fe){return;}this.editor=_1fe;if(this.blockNodeForEnter=="BR"){this.editor.customUndo=true;_1fe.onLoadDeferred.addCallback(_4.hitch(this,function(d){this.connect(_1fe.document,"onkeypress",function(e){if(e.charOrCode==_4.keys.ENTER){var ne=_4.mixin({},e);ne.shiftKey=true;if(!this.handleEnterKey(ne)){_4.stopEvent(e);}}});return d;}));}else{if(this.blockNodeForEnter){var h=_4.hitch(this,this.handleEnterKey);_1fe.addKeyHandler(13,0,0,h);_1fe.addKeyHandler(13,0,1,h);this.connect(this.editor,"onKeyPressed","onKeyPressed");}}},onKeyPressed:function(e){if(this._checkListLater){if(_4.withGlobal(this.editor.window,"isCollapsed",_5)){var _1ff=_4.withGlobal(this.editor.window,"getAncestorElement",_5._editor.selection,["LI"]);if(!_1ff){_5._editor.RichText.prototype.execCommand.call(this.editor,"formatblock",this.blockNodeForEnter);var _200=_4.withGlobal(this.editor.window,"getAncestorElement",_5._editor.selection,[this.blockNodeForEnter]);if(_200){_200.innerHTML=this.bogusHtmlContent;if(_4.isIE){var r=this.editor.document.selection.createRange();r.move("character",-1);r.select();}}else{console.error("onKeyPressed: Cannot find the new block node");}}else{if(_4.isMoz){if(_1ff.parentNode.parentNode.nodeName=="LI"){_1ff=_1ff.parentNode.parentNode;}}var fc=_1ff.firstChild;if(fc&&fc.nodeType==1&&(fc.nodeName=="UL"||fc.nodeName=="OL")){_1ff.insertBefore(fc.ownerDocument.createTextNode(" "),fc);var _201=_5.range.create(this.editor.window);_201.setStart(_1ff.firstChild,0);var _202=_5.range.getSelection(this.editor.window,true);_202.removeAllRanges();_202.addRange(_201);}}}this._checkListLater=false;}if(this._pressedEnterInBlock){if(this._pressedEnterInBlock.previousSibling){this.removeTrailingBr(this._pressedEnterInBlock.previousSibling);}delete this._pressedEnterInBlock;}},bogusHtmlContent:"&nbsp;",blockNodes:/^(?:P|H1|H2|H3|H4|H5|H6|LI)$/,handleEnterKey:function(e){var _203,_204,_205,doc=this.editor.document,br,rs,txt;if(e.shiftKey){var _206=_4.withGlobal(this.editor.window,"getParentElement",_5._editor.selection);var _207=_5.range.getAncestor(_206,this.blockNodes);if(_207){if(_207.tagName=="LI"){return true;}_203=_5.range.getSelection(this.editor.window);_204=_203.getRangeAt(0);if(!_204.collapsed){_204.deleteContents();_203=_5.range.getSelection(this.editor.window);_204=_203.getRangeAt(0);}if(_5.range.atBeginningOfContainer(_207,_204.startContainer,_204.startOffset)){br=doc.createElement("br");_205=_5.range.create(this.editor.window);_207.insertBefore(br,_207.firstChild);_205.setStartBefore(br.nextSibling);_203.removeAllRanges();_203.addRange(_205);}else{if(_5.range.atEndOfContainer(_207,_204.startContainer,_204.startOffset)){_205=_5.range.create(this.editor.window);br=doc.createElement("br");_207.appendChild(br);_207.appendChild(doc.createTextNode(" "));_205.setStart(_207.lastChild,0);_203.removeAllRanges();_203.addRange(_205);}else{rs=_204.startContainer;if(rs&&rs.nodeType==3){txt=rs.nodeValue;_4.withGlobal(this.editor.window,function(){var _208=doc.createTextNode(txt.substring(0,_204.startOffset));var _209=doc.createTextNode(txt.substring(_204.startOffset));var _20a=doc.createElement("br");if(_209.nodeValue==""&&_4.isWebKit){_209=doc.createTextNode(" ");}_4.place(_208,rs,"after");_4.place(_20a,_208,"after");_4.place(_209,_20a,"after");_4.destroy(rs);_205=_5.range.create(_4.gobal);_205.setStart(_209,0);_203.removeAllRanges();_203.addRange(_205);});return false;}return true;}}}else{_203=_5.range.getSelection(this.editor.window);if(_203.rangeCount){_204=_203.getRangeAt(0);if(_204&&_204.startContainer){if(!_204.collapsed){_204.deleteContents();_203=_5.range.getSelection(this.editor.window);_204=_203.getRangeAt(0);}rs=_204.startContainer;var _20b,_20c,_20d;if(rs&&rs.nodeType==3){_4.withGlobal(this.editor.window,_4.hitch(this,function(){var _20e=false;var _20f=_204.startOffset;if(rs.length<_20f){ret=this._adjustNodeAndOffset(rs,_20f);rs=ret.node;_20f=ret.offset;}txt=rs.nodeValue;_20b=doc.createTextNode(txt.substring(0,_20f));_20c=doc.createTextNode(txt.substring(_20f));_20d=doc.createElement("br");if(!_20c.length){_20c=doc.createTextNode(" ");_20e=true;}if(_20b.length){_4.place(_20b,rs,"after");}else{_20b=rs;}_4.place(_20d,_20b,"after");_4.place(_20c,_20d,"after");_4.destroy(rs);_205=_5.range.create(_4.gobal);_205.setStart(_20c,0);_205.setEnd(_20c,_20c.length);_203.removeAllRanges();_203.addRange(_205);if(_20e&&!_4.isWebKit){_5._editor.selection.remove();}else{_5._editor.selection.collapse(true);}}));}else{_4.withGlobal(this.editor.window,_4.hitch(this,function(){var _210=doc.createElement("br");rs.appendChild(_210);var _211=doc.createTextNode(" ");rs.appendChild(_211);_205=_5.range.create(_4.global);_205.setStart(_211,0);_205.setEnd(_211,_211.length);_203.removeAllRanges();_203.addRange(_205);_5._editor.selection.collapse(true);}));}}}else{_5._editor.RichText.prototype.execCommand.call(this.editor,"inserthtml","<br>");}}return false;}var _212=true;_203=_5.range.getSelection(this.editor.window);_204=_203.getRangeAt(0);if(!_204.collapsed){_204.deleteContents();_203=_5.range.getSelection(this.editor.window);_204=_203.getRangeAt(0);}var _213=_5.range.getBlockAncestor(_204.endContainer,null,this.editor.editNode);var _214=_213.blockNode;if((this._checkListLater=(_214&&(_214.nodeName=="LI"||_214.parentNode.nodeName=="LI")))){if(_4.isMoz){this._pressedEnterInBlock=_214;}if(/^(\s|&nbsp;|\xA0|<span\b[^>]*\bclass=['"]Apple-style-span['"][^>]*>(\s|&nbsp;|\xA0)<\/span>)?(<br>)?$/.test(_214.innerHTML)){_214.innerHTML="";if(_4.isWebKit){_205=_5.range.create(this.editor.window);_205.setStart(_214,0);_203.removeAllRanges();_203.addRange(_205);}this._checkListLater=false;}return true;}if(!_213.blockNode||_213.blockNode===this.editor.editNode){try{_5._editor.RichText.prototype.execCommand.call(this.editor,"formatblock",this.blockNodeForEnter);}catch(e2){}_213={blockNode:_4.withGlobal(this.editor.window,"getAncestorElement",_5._editor.selection,[this.blockNodeForEnter]),blockContainer:this.editor.editNode};if(_213.blockNode){if(_213.blockNode!=this.editor.editNode&&(!(_213.blockNode.textContent||_213.blockNode.innerHTML).replace(/^\s+|\s+$/g,"").length)){this.removeTrailingBr(_213.blockNode);return false;}}else{_213.blockNode=this.editor.editNode;}_203=_5.range.getSelection(this.editor.window);_204=_203.getRangeAt(0);}var _215=doc.createElement(this.blockNodeForEnter);_215.innerHTML=this.bogusHtmlContent;this.removeTrailingBr(_213.blockNode);var _216=_204.endOffset;var node=_204.endContainer;if(node.length<_216){var ret=this._adjustNodeAndOffset(node,_216);node=ret.node;_216=ret.offset;}if(_5.range.atEndOfContainer(_213.blockNode,node,_216)){if(_213.blockNode===_213.blockContainer){_213.blockNode.appendChild(_215);}else{_4.place(_215,_213.blockNode,"after");}_212=false;_205=_5.range.create(this.editor.window);_205.setStart(_215,0);_203.removeAllRanges();_203.addRange(_205);if(this.editor.height){_4.window.scrollIntoView(_215);}}else{if(_5.range.atBeginningOfContainer(_213.blockNode,_204.startContainer,_204.startOffset)){_4.place(_215,_213.blockNode,_213.blockNode===_213.blockContainer?"first":"before");if(_215.nextSibling&&this.editor.height){_205=_5.range.create(this.editor.window);_205.setStart(_215.nextSibling,0);_203.removeAllRanges();_203.addRange(_205);_4.window.scrollIntoView(_215.nextSibling);}_212=false;}else{if(_213.blockNode===_213.blockContainer){_213.blockNode.appendChild(_215);}else{_4.place(_215,_213.blockNode,"after");}_212=false;if(_213.blockNode.style){if(_215.style){if(_213.blockNode.style.cssText){_215.style.cssText=_213.blockNode.style.cssText;}}}rs=_204.startContainer;if(rs&&rs.nodeType==3){var _217,_218;_216=_204.endOffset;if(rs.length<_216){ret=this._adjustNodeAndOffset(rs,_216);rs=ret.node;_216=ret.offset;}txt=rs.nodeValue;var _20b=doc.createTextNode(txt.substring(0,_216));var _20c=doc.createTextNode(txt.substring(_216,txt.length));_4.place(_20b,rs,"before");_4.place(_20c,rs,"after");_4.destroy(rs);var _219=_20b.parentNode;while(_219!==_213.blockNode){var tg=_219.tagName;var _21a=doc.createElement(tg);if(_219.style){if(_21a.style){if(_219.style.cssText){_21a.style.cssText=_219.style.cssText;}}}_217=_20c;while(_217){_218=_217.nextSibling;_21a.appendChild(_217);_217=_218;}_4.place(_21a,_219,"after");_20b=_219;_20c=_21a;_219=_219.parentNode;}_217=_20c;if(_217.nodeType==1||(_217.nodeType==3&&_217.nodeValue)){_215.innerHTML="";}while(_217){_218=_217.nextSibling;_215.appendChild(_217);_217=_218;}}_205=_5.range.create(this.editor.window);_205.setStart(_215,0);_203.removeAllRanges();_203.addRange(_205);if(this.editor.height){_5.scrollIntoView(_215);}if(_4.isMoz){this._pressedEnterInBlock=_213.blockNode;}}}return _212;},_adjustNodeAndOffset:function(node,_21b){while(node.length<_21b&&node.nextSibling&&node.nextSibling.nodeType==3){_21b=_21b-node.length;node=node.nextSibling;}var ret={"node":node,"offset":_21b};return ret;},removeTrailingBr:function(_21c){var para=/P|DIV|LI/i.test(_21c.tagName)?_21c:_5._editor.selection.getParentOfType(_21c,["P","DIV","LI"]);if(!para){return;}if(para.lastChild){if((para.childNodes.length>1&&para.lastChild.nodeType==3&&/^[\s\xAD]*$/.test(para.lastChild.nodeValue))||para.lastChild.tagName=="BR"){_4.destroy(para.lastChild);}}if(!para.childNodes.length){para.innerHTML=this.bogusHtmlContent;}}});}if(!_4._hasResource["dijit.Editor"]){_4._hasResource["dijit.Editor"]=true;_4.provide("dijit.Editor");_4.declare("dijit.Editor",_5._editor.RichText,{plugins:null,extraPlugins:null,constructor:function(){if(!_4.isArray(this.plugins)){this.plugins=["undo","redo","|","cut","copy","paste","|","bold","italic","underline","strikethrough","|","insertOrderedList","insertUnorderedList","indent","outdent","|","justifyLeft","justifyRight","justifyCenter","justifyFull","dijit._editor.plugins.EnterKeyHandling"];}this._plugins=[];this._editInterval=this.editActionInterval*1000;if(_4.isIE){this.events.push("onBeforeDeactivate");this.events.push("onBeforeActivate");}},postMixInProperties:function(){this.setValueDeferred=new _4.Deferred();this.inherited(arguments);},postCreate:function(){this._steps=this._steps.slice(0);this._undoedSteps=this._undoedSteps.slice(0);if(_4.isArray(this.extraPlugins)){this.plugins=this.plugins.concat(this.extraPlugins);}this.inherited(arguments);this.commands=_4.i18n.getLocalization("dijit._editor","commands",this.lang);if(!this.toolbar){this.toolbar=new _5.Toolbar({dir:this.dir,lang:this.lang});this.header.appendChild(this.toolbar.domNode);}_4.forEach(this.plugins,this.addPlugin,this);this.setValueDeferred.callback(true);_4.addClass(this.iframe.parentNode,"dijitEditorIFrameContainer");_4.addClass(this.iframe,"dijitEditorIFrame");_4.attr(this.iframe,"allowTransparency",true);if(_4.isWebKit){_4.style(this.domNode,"KhtmlUserSelect","none");}this.toolbar.startup();this.onNormalizedDisplayChanged();},destroy:function(){_4.forEach(this._plugins,function(p){if(p&&p.destroy){p.destroy();}});this._plugins=[];this.toolbar.destroyRecursive();delete this.toolbar;this.inherited(arguments);},addPlugin:function(_21d,_21e){var args=_4.isString(_21d)?{name:_21d}:_21d;if(!args.setEditor){var o={"args":args,"plugin":null,"editor":this};_4.publish(_5._scopeName+".Editor.getPlugin",[o]);if(!o.plugin){var pc=_4.getObject(args.name);if(pc){o.plugin=new pc(args);}}if(!o.plugin){console.warn("Cannot find plugin",_21d);return;}_21d=o.plugin;}if(arguments.length>1){this._plugins[_21e]=_21d;}else{this._plugins.push(_21d);}_21d.setEditor(this);if(_4.isFunction(_21d.setToolbar)){_21d.setToolbar(this.toolbar);}},startup:function(){},resize:function(size){if(size){_5.layout._LayoutWidget.prototype.resize.apply(this,arguments);}},layout:function(){var _21f=(this._contentBox.h-(this.getHeaderHeight()+this.getFooterHeight()+_4._getPadBorderExtents(this.iframe.parentNode).h+_4._getMarginExtents(this.iframe.parentNode).h));this.editingArea.style.height=_21f+"px";if(this.iframe){this.iframe.style.height="100%";}this._layoutMode=true;},_onIEMouseDown:function(e){var _220;var b=this.document.body;var _221=b.clientWidth;var _222=b.clientHeight;var _223=b.clientLeft;var _224=b.offsetWidth;var _225=b.offsetHeight;var _226=b.offsetLeft;bodyDir=b.dir?b.dir.toLowerCase():"";if(bodyDir!="rtl"){if(_221<_224&&e.x>_221&&e.x<_224){_220=true;}}else{if(e.x<_223&&e.x>_226){_220=true;}}if(!_220){if(_222<_225&&e.y>_222&&e.y<_225){_220=true;}}if(!_220){delete this._cursorToStart;delete this._savedSelection;if(e.target.tagName=="BODY"){setTimeout(_4.hitch(this,"placeCursorAtEnd"),0);}this.inherited(arguments);}},onBeforeActivate:function(e){this._restoreSelection();},onBeforeDeactivate:function(e){if(this.customUndo){this.endEditing(true);}if(e.target.tagName!="BODY"){this._saveSelection();}},customUndo:true,editActionInterval:3,beginEditing:function(cmd){if(!this._inEditing){this._inEditing=true;this._beginEditing(cmd);}if(this.editActionInterval>0){if(this._editTimer){clearTimeout(this._editTimer);}this._editTimer=setTimeout(_4.hitch(this,this.endEditing),this._editInterval);}},_steps:[],_undoedSteps:[],execCommand:function(cmd){if(this.customUndo&&(cmd=="undo"||cmd=="redo")){return this[cmd]();}else{if(this.customUndo){this.endEditing();this._beginEditing();}var r;var _227=/copy|cut|paste/.test(cmd);try{r=this.inherited(arguments);if(_4.isWebKit&&_227&&!r){throw {code:1011};}}catch(e){if(e.code==1011&&_227){var sub=_4.string.substitute,_228={cut:"X",copy:"C",paste:"V"};alert(sub(this.commands.systemShortcut,[this.commands[cmd],sub(this.commands[_4.isMac?"appleKey":"ctrlKey"],[_228[cmd]])]));}r=false;}if(this.customUndo){this._endEditing();}return r;}},queryCommandEnabled:function(cmd){if(this.customUndo&&(cmd=="undo"||cmd=="redo")){return cmd=="undo"?(this._steps.length>1):(this._undoedSteps.length>0);}else{return this.inherited(arguments);}},_moveToBookmark:function(b){var _229=b.mark;var mark=b.mark;var col=b.isCollapsed;var r,_22a,_22b,sel;if(mark){if(_4.isIE){if(_4.isArray(mark)){_229=[];_4.forEach(mark,function(n){_229.push(_5.range.getNode(n,this.editNode));},this);_4.withGlobal(this.window,"moveToBookmark",_5,[{mark:_229,isCollapsed:col}]);}else{if(mark.startContainer&&mark.endContainer){sel=_5.range.getSelection(this.window);if(sel&&sel.removeAllRanges){sel.removeAllRanges();r=_5.range.create(this.window);_22a=_5.range.getNode(mark.startContainer,this.editNode);_22b=_5.range.getNode(mark.endContainer,this.editNode);if(_22a&&_22b){r.setStart(_22a,mark.startOffset);r.setEnd(_22b,mark.endOffset);sel.addRange(r);}}}}}else{sel=_5.range.getSelection(this.window);if(sel&&sel.removeAllRanges){sel.removeAllRanges();r=_5.range.create(this.window);_22a=_5.range.getNode(mark.startContainer,this.editNode);_22b=_5.range.getNode(mark.endContainer,this.editNode);if(_22a&&_22b){r.setStart(_22a,mark.startOffset);r.setEnd(_22b,mark.endOffset);sel.addRange(r);}}}}},_changeToStep:function(from,to){this.setValue(to.text);var b=to.bookmark;if(!b){return;}this._moveToBookmark(b);},undo:function(){var ret=false;if(!this._undoRedoActive){this._undoRedoActive=true;this.endEditing(true);var s=this._steps.pop();if(s&&this._steps.length>0){this.focus();this._changeToStep(s,this._steps[this._steps.length-1]);this._undoedSteps.push(s);this.onDisplayChanged();delete this._undoRedoActive;ret=true;}delete this._undoRedoActive;}return ret;},redo:function(){var ret=false;if(!this._undoRedoActive){this._undoRedoActive=true;this.endEditing(true);var s=this._undoedSteps.pop();if(s&&this._steps.length>0){this.focus();this._changeToStep(this._steps[this._steps.length-1],s);this._steps.push(s);this.onDisplayChanged();ret=true;}delete this._undoRedoActive;}return ret;},endEditing:function(_22c){if(this._editTimer){clearTimeout(this._editTimer);}if(this._inEditing){this._endEditing(_22c);this._inEditing=false;}},_getBookmark:function(){var b=_4.withGlobal(this.window,_5.getBookmark);var tmp=[];if(b&&b.mark){var mark=b.mark;if(_4.isIE){var sel=_5.range.getSelection(this.window);if(!_4.isArray(mark)){if(sel){var _22d;if(sel.rangeCount){_22d=sel.getRangeAt(0);}if(_22d){b.mark=_22d.cloneRange();}else{b.mark=_4.withGlobal(this.window,_5.getBookmark);}}}else{_4.forEach(b.mark,function(n){tmp.push(_5.range.getIndex(n,this.editNode).o);},this);b.mark=tmp;}}try{if(b.mark&&b.mark.startContainer){tmp=_5.range.getIndex(b.mark.startContainer,this.editNode).o;b.mark={startContainer:tmp,startOffset:b.mark.startOffset,endContainer:b.mark.endContainer===b.mark.startContainer?tmp:_5.range.getIndex(b.mark.endContainer,this.editNode).o,endOffset:b.mark.endOffset};}}catch(e){b.mark=null;}}return b;},_beginEditing:function(cmd){if(this._steps.length===0){this._steps.push({"text":_5._editor.getChildrenHtml(this.editNode),"bookmark":this._getBookmark()});}},_endEditing:function(_22e){var v=_5._editor.getChildrenHtml(this.editNode);this._undoedSteps=[];this._steps.push({text:v,bookmark:this._getBookmark()});},onKeyDown:function(e){if(!_4.isIE&&!this.iframe&&e.keyCode==_4.keys.TAB&&!this.tabIndent){this._saveSelection();}if(!this.customUndo){this.inherited(arguments);return;}var k=e.keyCode,ks=_4.keys;if(e.ctrlKey&&!e.altKey){if(k==90||k==122){_4.stopEvent(e);this.undo();return;}else{if(k==89||k==121){_4.stopEvent(e);this.redo();return;}}}this.inherited(arguments);switch(k){case ks.ENTER:case ks.BACKSPACE:case ks.DELETE:this.beginEditing();break;case 88:case 86:if(e.ctrlKey&&!e.altKey&&!e.metaKey){this.endEditing();if(e.keyCode==88){this.beginEditing("cut");setTimeout(_4.hitch(this,this.endEditing),1);}else{this.beginEditing("paste");setTimeout(_4.hitch(this,this.endEditing),1);}break;}default:if(!e.ctrlKey&&!e.altKey&&!e.metaKey&&(e.keyCode<_4.keys.F1||e.keyCode>_4.keys.F15)){this.beginEditing();break;}case ks.ALT:this.endEditing();break;case ks.UP_ARROW:case ks.DOWN_ARROW:case ks.LEFT_ARROW:case ks.RIGHT_ARROW:case ks.HOME:case ks.END:case ks.PAGE_UP:case ks.PAGE_DOWN:this.endEditing(true);break;case ks.CTRL:case ks.SHIFT:case ks.TAB:break;}},_onBlur:function(){this.inherited(arguments);this.endEditing(true);},_saveSelection:function(){try{this._savedSelection=this._getBookmark();}catch(e){}},_restoreSelection:function(){if(this._savedSelection){delete this._cursorToStart;if(_4.withGlobal(this.window,"isCollapsed",_5)){this._moveToBookmark(this._savedSelection);}delete this._savedSelection;}},onClick:function(){this.endEditing(true);this.inherited(arguments);},replaceValue:function(html){if(!this.customUndo){this.inherited(arguments);}else{if(this.isClosed){this.setValue(html);}else{this.beginEditing();if(!html){html="&nbsp;";}this.setValue(html);this.endEditing();}}},_setDisabledAttr:function(_22f){var _230=_4.hitch(this,function(){if((!this.disabled&&_22f)||(!this._buttonEnabledPlugins&&_22f)){_4.forEach(this._plugins,function(p){p.set("disabled",true);});}else{if(this.disabled&&!_22f){_4.forEach(this._plugins,function(p){p.set("disabled",false);});}}});this.setValueDeferred.addCallback(_230);this.inherited(arguments);},_setStateClass:function(){try{this.inherited(arguments);if(this.document&&this.document.body){_4.style(this.document.body,"color",_4.style(this.iframe,"color"));}}catch(e){}}});_4.subscribe(_5._scopeName+".Editor.getPlugin",null,function(o){if(o.plugin){return;}var args=o.args,p;var _231=_5._editor._Plugin;var name=args.name;switch(name){case "undo":case "redo":case "cut":case "copy":case "paste":case "insertOrderedList":case "insertUnorderedList":case "indent":case "outdent":case "justifyCenter":case "justifyFull":case "justifyLeft":case "justifyRight":case "delete":case "selectAll":case "removeFormat":case "unlink":case "insertHorizontalRule":p=new _231({command:name});break;case "bold":case "italic":case "underline":case "strikethrough":case "subscript":case "superscript":p=new _231({buttonClass:_5.form.ToggleButton,command:name});break;case "|":p=new _231({button:new _5.ToolbarSeparator(),setEditor:function(_232){this.editor=_232;}});}o.plugin=p;});}if(!_4._hasResource["dojo.regexp"]){_4._hasResource["dojo.regexp"]=true;_4.provide("dojo.regexp");_4.getObject("regexp",true,_4);_4.regexp.escapeString=function(str,_233){return str.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g,function(ch){if(_233&&_233.indexOf(ch)!=-1){return ch;}return "\\"+ch;});};_4.regexp.buildGroupRE=function(arr,re,_234){if(!(arr instanceof Array)){return re(arr);}var b=[];for(var i=0;i<arr.length;i++){b.push(re(arr[i]));}return _4.regexp.group(b.join("|"),_234);};_4.regexp.group=function(_235,_236){return "("+(_236?"?:":"")+_235+")";};}if(!_4._hasResource["dojo.data.util.sorter"]){_4._hasResource["dojo.data.util.sorter"]=true;_4.provide("dojo.data.util.sorter");_4.getObject("data.util.sorter",true,_4);_4.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;};_4.data.util.sorter.createSortFunction=function(_237,_238){var _239=[];function _23a(attr,dir,comp,s){return function(_23b,_23c){var a=s.getValue(_23b,attr);var b=s.getValue(_23c,attr);return dir*comp(a,b);};};var _23d;var map=_238.comparatorMap;var bc=_4.data.util.sorter.basicComparator;for(var i=0;i<_237.length;i++){_23d=_237[i];var attr=_23d.attribute;if(attr){var dir=(_23d.descending)?-1:1;var comp=bc;if(map){if(typeof attr!=="string"&&("toString" in attr)){attr=attr.toString();}comp=map[attr]||bc;}_239.push(_23a(attr,dir,comp,_238));}}return function(rowA,rowB){var i=0;while(i<_239.length){var ret=_239[i++](rowA,rowB);if(ret!==0){return ret;}}return 0;};};}if(!_4._hasResource["dojo.data.util.simpleFetch"]){_4._hasResource["dojo.data.util.simpleFetch"]=true;_4.provide("dojo.data.util.simpleFetch");_4.getObject("data.util.simpleFetch",true,_4);_4.data.util.simpleFetch.fetch=function(_23e){_23e=_23e||{};if(!_23e.store){_23e.store=this;}var self=this;var _23f=function(_240,_241){if(_241.onError){var _242=_241.scope||_4.global;_241.onError.call(_242,_240,_241);}};var _243=function(_244,_245){var _246=_245.abort||null;var _247=false;var _248=_245.start?_245.start:0;var _249=(_245.count&&(_245.count!==Infinity))?(_248+_245.count):_244.length;_245.abort=function(){_247=true;if(_246){_246.call(_245);}};var _24a=_245.scope||_4.global;if(!_245.store){_245.store=self;}if(_245.onBegin){_245.onBegin.call(_24a,_244.length,_245);}if(_245.sort){_244.sort(_4.data.util.sorter.createSortFunction(_245.sort,self));}if(_245.onItem){for(var i=_248;(i<_244.length)&&(i<_249);++i){var item=_244[i];if(!_247){_245.onItem.call(_24a,item,_245);}}}if(_245.onComplete&&!_247){var _24b=null;if(!_245.onItem){_24b=_244.slice(_248,_249);}_245.onComplete.call(_24a,_24b,_245);}};this._fetchItems(_23e,_243,_23f);return _23e;};}if(!_4._hasResource["dojo.data.util.filter"]){_4._hasResource["dojo.data.util.filter"]=true;_4.provide("dojo.data.util.filter");_4.getObject("data.util.filter",true,_4);_4.data.util.filter.patternToRegExp=function(_24c,_24d){var rxp="^";var c=null;for(var i=0;i<_24c.length;i++){c=_24c.charAt(i);switch(c){case "\\":rxp+=c;i++;rxp+=_24c.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(_24d){return new RegExp(rxp,"mi");}else{return new RegExp(rxp,"m");}};}if(!_4._hasResource["dijit.form.TextBox"]){_4._hasResource["dijit.form.TextBox"]=true;_4.provide("dijit.form.TextBox");_4.declare("dijit.form.TextBox",_5.form._FormValueWidget,{trim:false,uppercase:false,lowercase:false,propercase:false,maxLength:"",selectOnClick:false,placeHolder:"",templateString:_4.cache("dijit.form","templates/TextBox.html","<div class=\"dijit dijitReset dijitInline dijitLeft\" id=\"widget_${id}\" role=\"presentation\"\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\r\n\t\t\t${!nameAttrSetting} type='${type}'\r\n\t/></div\r\n></div>\r\n"),_singleNodeTemplate:"<input class=\"dijit dijitReset dijitLeft dijitInputField\" dojoAttachPoint=\"textbox,focusNode\" autocomplete=\"off\" type=\"${type}\" ${!nameAttrSetting} />",_buttonInputDisabled:_4.isIE?"disabled":"",baseClass:"dijitTextBox",attributeMap:_4.delegate(_5.form._FormValueWidget.prototype.attributeMap,{maxLength:"focusNode"}),postMixInProperties:function(){var type=this.type.toLowerCase();if(this.templateString&&this.templateString.toLowerCase()=="input"||((type=="hidden"||type=="file")&&this.templateString==_5.form.TextBox.prototype.templateString)){this.templateString=this._singleNodeTemplate;}this.inherited(arguments);},_setPlaceHolderAttr:function(v){this._set("placeHolder",v);if(!this._phspan){this._attachPoints.push("_phspan");this._phspan=_4.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(_24e,_24f,_250){var _251;if(_24e!==undefined){_251=this.filter(_24e);if(typeof _250!="string"){if(_251!==null&&((typeof _251!="number")||!isNaN(_251))){_250=this.filter(this.format(_251,this.constraints));}else{_250="";}}}if(_250!=null&&_250!=undefined&&((typeof _250)!="number"||!isNaN(_250))&&this.textbox.value!=_250){this.textbox.value=_250;this._set("displayedValue",this.get("displayedValue"));}this._updatePlaceHolder();this.inherited(arguments,[_251,_24f]);},displayedValue:"",getDisplayedValue:function(){_4.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(_252){_4.deprecated(this.declaredClass+"::setDisplayedValue() is deprecated. Use set('displayedValue', ...) instead.","","2.0");this.set("displayedValue",_252);},_setDisplayedValueAttr:function(_253){if(_253===null||_253===undefined){_253="";}else{if(typeof _253!="string"){_253=String(_253);}}this.textbox.value=_253;this._setValueAttr(this.get("value"),undefined);this._set("displayedValue",this.get("displayedValue"));},format:function(_254,_255){return ((_254==null||_254==undefined)?"":(_254.toString?_254.toString():_254));},parse:function(_256,_257){return _256;},_refreshState:function(){},_onInput:function(e){if(e&&e.type&&/key/i.test(e.type)&&e.keyCode){switch(e.keyCode){case _4.keys.SHIFT:case _4.keys.ALT:case _4.keys.CTRL:case _4.keys.TAB:return;}}if(this.intermediateChanges){var _258=this;setTimeout(function(){_258._handleOnChange(_258.get("value"),false);},0);}this._refreshState();this._set("displayedValue",this.get("displayedValue"));},postCreate:function(){if(_4.isIE){setTimeout(_4.hitch(this,function(){var s=_4.getComputedStyle(this.domNode);if(s){var ff=s.fontFamily;if(ff){var _259=this.domNode.getElementsByTagName("INPUT");if(_259){for(var i=0;i<_259.length;i++){_259[i].style.fontFamily=ff;}}}}}),0);}this.textbox.setAttribute("value",this.textbox.value);this.inherited(arguments);if(_4.isMoz||_4.isOpera){this.connect(this.textbox,"oninput","_onInput");}else{this.connect(this.textbox,"onkeydown","_onInput");this.connect(this.textbox,"onkeyup","_onInput");this.connect(this.textbox,"onpaste","_onInput");this.connect(this.textbox,"oncut","_onInput");}},_blankValue:"",filter:function(val){if(val===null){return this._blankValue;}if(typeof val!="string"){return val;}if(this.trim){val=_4.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&&_4.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 _25a;if(_4.isIE){var _25b=_4.doc.selection.createRange();var _25c=_25b.parentElement();_25a=_25c==this.textbox&&_25b.text.length==0;}else{_25a=this.textbox.selectionStart==this.textbox.selectionEnd;}if(_25a){_5.selectInputText(this.textbox);}});}this._updatePlaceHolder();this.inherited(arguments);this._refreshState();},reset:function(){this.textbox.value="";this.inherited(arguments);}});_5.selectInputText=function(_25d,_25e,stop){var _25f=_4.global;var _260=_4.doc;_25d=_4.byId(_25d);if(isNaN(_25e)){_25e=0;}if(isNaN(stop)){stop=_25d.value?_25d.value.length:0;}_5.focus(_25d);if(_260["selection"]&&_4.body()["createTextRange"]){if(_25d.createTextRange){var r=_25d.createTextRange();r.collapse(true);r.moveStart("character",-99999);r.moveStart("character",_25e);r.moveEnd("character",stop-_25e);r.select();}}else{if(_25f["getSelection"]){if(_25d.setSelectionRange){_25d.setSelectionRange(_25e,stop);}}}};}if(!_4._hasResource["dijit.Tooltip"]){_4._hasResource["dijit.Tooltip"]=true;_4.provide("dijit.Tooltip");_4.declare("dijit._MasterTooltip",[_5._Widget,_5._Templated],{duration:_5.defaultDuration,templateString:_4.cache("dijit","templates/Tooltip.html","<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\"\r\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" role='alert'></div\r\n\t><div class=\"dijitTooltipConnector\" dojoAttachPoint=\"connectorNode\"></div\r\n></div>\r\n"),postCreate:function(){_4.body().appendChild(this.domNode);this.bgIframe=new _5.BackgroundIframe(this.domNode);this.fadeIn=_4.fadeIn({node:this.domNode,duration:this.duration,onEnd:_4.hitch(this,"_onShow")});this.fadeOut=_4.fadeOut({node:this.domNode,duration:this.duration,onEnd:_4.hitch(this,"_onHide")});},show:function(_261,_262,_263,rtl){if(this.aroundNode&&this.aroundNode===_262){return;}this.domNode.width="auto";if(this.fadeOut.status()=="playing"){this._onDeck=arguments;return;}this.containerNode.innerHTML=_261;var pos=_5.placeOnScreenAroundElement(this.domNode,_262,_5.getPopupAroundAlignment((_263&&_263.length)?_263:_5.Tooltip.defaultPosition,!rtl),_4.hitch(this,"orient"));_4.style(this.domNode,"opacity",0);this.fadeIn.play();this.isShowingNow=true;this.aroundNode=_262;},orient:function(node,_264,_265,_266,_267){this.connectorNode.style.top="";var _268=_266.w-this.connectorNode.offsetWidth;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"}[_264+"-"+_265];this.domNode.style.width="auto";var size=_4.contentBox(this.domNode);var _269=Math.min((Math.max(_268,1)),size.w);var _26a=_269<size.w;this.domNode.style.width=_269+"px";if(_26a){this.containerNode.style.overflow="auto";var _26b=this.containerNode.scrollWidth;this.containerNode.style.overflow="visible";if(_26b>_269){_26b=_26b+_4.style(this.domNode,"paddingLeft")+_4.style(this.domNode,"paddingRight");this.domNode.style.width=_26b+"px";}}if(_265.charAt(0)=="B"&&_264.charAt(0)=="B"){var mb=_4.marginBox(node);var _26c=this.connectorNode.offsetHeight;if(mb.h>_266.h){var _26d=_266.h-(_267.h/2)-(_26c/2);this.connectorNode.style.top=_26d+"px";this.connectorNode.style.bottom="";}else{this.connectorNode.style.bottom=Math.min(Math.max(_267.h/2-_26c/2,0),mb.h-_26c)+"px";this.connectorNode.style.top="";}}else{this.connectorNode.style.top="";this.connectorNode.style.bottom="";}return Math.max(0,size.w-_268);},_onShow:function(){if(_4.isIE){this.domNode.style.filter="";}},hide:function(_26e){if(this._onDeck&&this._onDeck[1]==_26e){this._onDeck=null;}else{if(this.aroundNode===_26e){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;}}});_5.showTooltip=function(_26f,_270,_271,rtl){if(!_5._masterTT){_5._masterTT=new _5._MasterTooltip();}return _5._masterTT.show(_26f,_270,_271,rtl);};_5.hideTooltip=function(_272){if(!_5._masterTT){_5._masterTT=new _5._MasterTooltip();}return _5._masterTT.hide(_272);};_4.declare("dijit.Tooltip",_5._Widget,{label:"",showDelay:400,connectId:[],position:[],_setConnectIdAttr:function(_273){_4.forEach(this._connections||[],function(_274){_4.forEach(_274,_4.hitch(this,"disconnect"));},this);var ary=_4.isArrayLike(_273)?_273:(_273?[_273]:[]);this._connections=_4.map(ary,function(id){var node=_4.byId(id);return node?[this.connect(node,"onmouseenter","_onTargetMouseEnter"),this.connect(node,"onmouseleave","_onTargetMouseLeave"),this.connect(node,"onfocus","_onTargetFocus"),this.connect(node,"onblur","_onTargetBlur")]:[];},this);this._set("connectId",_273);this._connectIds=ary;},addTarget:function(node){var id=node.id||node;if(_4.indexOf(this._connectIds,id)==-1){this.set("connectId",this._connectIds.concat(id));}},removeTarget:function(node){var id=node.id||node,idx=_4.indexOf(this._connectIds,id);if(idx>=0){this._connectIds.splice(idx,1);this.set("connectId",this._connectIds);}},buildRendering:function(){this.inherited(arguments);_4.addClass(this.domNode,"dijitTooltipData");},startup:function(){this.inherited(arguments);var ids=this.connectId;_4.forEach(_4.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 _275=e.target;this._showTimer=setTimeout(_4.hitch(this,function(){this.open(_275);}),this.showDelay);}},_onUnHover:function(e){if(this._focus){return;}if(this._showTimer){clearTimeout(this._showTimer);delete this._showTimer;}this.close();},open:function(_276){if(this._showTimer){clearTimeout(this._showTimer);delete this._showTimer;}_5.showTooltip(this.label||this.domNode.innerHTML,_276,this.position,!this.isLeftToRight());this._connectNode=_276;this.onShow(_276,this.position);},close:function(){if(this._connectNode){_5.hideTooltip(this._connectNode);delete this._connectNode;this.onHide();}if(this._showTimer){clearTimeout(this._showTimer);delete this._showTimer;}},onShow:function(_277,_278){},onHide:function(){},uninitialize:function(){this.close();this.inherited(arguments);}});_5.Tooltip.defaultPosition=["after","before"];}if(!_4._hasResource["dijit.form.ValidationTextBox"]){_4._hasResource["dijit.form.ValidationTextBox"]=true;_4.provide("dijit.form.ValidationTextBox");_4.declare("dijit.form.ValidationTextBox",_5.form.TextBox,{templateString:_4.cache("dijit.form","templates/ValidationTextBox.html","<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\r\n\tid=\"widget_${id}\" role=\"presentation\"\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\r\n\t\t\t${!nameAttrSetting} type='${type}'\r\n\t/></div\r\n></div>\r\n"),baseClass:"dijitTextBox dijitValidationTextBox",required:false,promptMessage:"",invalidMessage:"$_unset_$",missingMessage:"$_unset_$",message:"",constraints:{},regExp:".*",regExpGen:function(_279){return this.regExp;},state:"",tooltipPosition:[],_setValueAttr:function(){this.inherited(arguments);this.validate(this._focused);},validator:function(_27a,_27b){return (new RegExp("^(?:"+this.regExpGen(_27b)+")"+(this.required?"":"?")+"$")).test(_27a)&&(!this.required||!this._isEmpty(_27a))&&(this._isEmpty(_27a)||this.parse(_27a,_27b)!==undefined);},_isValidSubset:function(){return this.textbox.value.search(this._partialre)==0;},isValid:function(_27c){return this.validator(this.textbox.value,this.constraints);},_isEmpty:function(_27d){return (this.trim?/^\s*$/:/^$/).test(_27d);},getErrorMessage:function(_27e){return (this.required&&this._isEmpty(this.textbox.value))?this.missingMessage:this.invalidMessage;},getPromptMessage:function(_27f){return this.promptMessage;},_maskValidSubsetError:true,validate:function(_280){var _281="";var _282=this.disabled||this.isValid(_280);if(_282){this._maskValidSubsetError=true;}var _283=this._isEmpty(this.textbox.value);var _284=!_282&&_280&&this._isValidSubset();this._set("state",_282?"":(((((!this._hasBeenBlurred||_280)&&_283)||_284)&&this._maskValidSubsetError)?"Incomplete":"Error"));_5.setWaiState(this.focusNode,"invalid",_282?"false":"true");if(this.state=="Error"){this._maskValidSubsetError=_280&&_284;_281=this.getErrorMessage(_280);}else{if(this.state=="Incomplete"){_281=this.getPromptMessage(_280);this._maskValidSubsetError=!this._hasBeenBlurred||_280;}else{if(_283){_281=this.getPromptMessage(_280);}}}this.set("message",_281);return _282;},displayMessage:function(_285){_5.hideTooltip(this.domNode);if(_285&&this._focused){_5.showTooltip(_285,this.domNode,this.tooltipPosition,!this.isLeftToRight());}},_refreshState:function(){this.validate(this._focused);this.inherited(arguments);},constructor:function(){this.constraints={};},_setConstraintsAttr:function(_286){if(!_286.locale&&this.lang){_286.locale=this.lang;}this._set("constraints",_286);this._computePartialRE();},_computePartialRE:function(){var p=this.regExpGen(this.constraints);this.regExp=p;var _287="";if(p!=".*"){this.regExp.replace(/\\.|\[\]|\[.*?[^\\]{1}\]|\{.*?\}|\(\?[=:!]|./g,function(re){switch(re.charAt(0)){case "{":case "+":case "?":case "*":case "^":case "$":case "|":case "(":_287+=re;break;case ")":_287+="|$)";break;default:_287+="(?:"+re+"|$)";break;}});}try{"".search(_287);}catch(e){_287=this.regExp;console.warn("RegExp error in "+this.declaredClass+": "+this.regExp);}this._partialre="^(?:"+_287+")$";},postMixInProperties:function(){this.inherited(arguments);this.messages=_4.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(_288){this.inherited(arguments);this._refreshState();},_setRequiredAttr:function(_289){this._set("required",_289);_5.setWaiState(this.focusNode,"required",_289);this._refreshState();},_setMessageAttr:function(_28a){this._set("message",_28a);this.displayMessage(_28a);},reset:function(){this._maskValidSubsetError=true;this.inherited(arguments);},_onBlur:function(){this.displayMessage("");this.inherited(arguments);}});_4.declare("dijit.form.MappedTextBox",_5.form.ValidationTextBox,{postMixInProperties:function(){this.inherited(arguments);this.nameAttrSetting="";},serialize:function(val,_28b){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=_4.place("<input type='hidden'"+(this.name?" name='"+this.name.replace(/'/g,"&quot;")+"'":"")+"/>",this.textbox,"after");},reset:function(){this.valueNode.value="";this.inherited(arguments);}});_4.declare("dijit.form.RangeBoundTextBox",_5.form.MappedTextBox,{rangeMessage:"",rangeCheck:function(_28c,_28d){return ("min" in _28d?(this.compare(_28c,_28d.min)>=0):true)&&("max" in _28d?(this.compare(_28c,_28d.max)<=0):true);},isInRange:function(_28e){return this.rangeCheck(this.get("value"),this.constraints);},_isDefinitelyOutOfRange:function(){var val=this.get("value");var _28f=false;var _290=false;if("min" in this.constraints){var min=this.constraints.min;min=this.compare(val,((typeof min=="number")&&min>=0&&val!=0)?0:min);_28f=(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);_290=(typeof max=="number")&&max>0;}return _28f||_290;},_isValidSubset:function(){return this.inherited(arguments)&&!this._isDefinitelyOutOfRange();},isValid:function(_291){return this.inherited(arguments)&&((this._isEmpty(this.textbox.value)&&!this.required)||this.isInRange(_291));},getErrorMessage:function(_292){var v=this.get("value");if(v!==null&&v!==""&&v!==undefined&&(typeof v!="number"||!isNaN(v))&&!this.isInRange(_292)){return this.rangeMessage;}return this.inherited(arguments);},postMixInProperties:function(){this.inherited(arguments);if(!this.rangeMessage){this.messages=_4.i18n.getLocalization("dijit.form","validate",this.lang);this.rangeMessage=this.messages.rangeMessage;}},_setConstraintsAttr:function(_293){this.inherited(arguments);if(this.focusNode){if(this.constraints.min!==undefined){_5.setWaiState(this.focusNode,"valuemin",this.constraints.min);}else{_5.removeWaiState(this.focusNode,"valuemin");}if(this.constraints.max!==undefined){_5.setWaiState(this.focusNode,"valuemax",this.constraints.max);}else{_5.removeWaiState(this.focusNode,"valuemax");}}},_setValueAttr:function(_294,_295){_5.setWaiState(this.focusNode,"valuenow",_294);this.inherited(arguments);}});}if(!_4._hasResource["dijit.form.ComboBox"]){_4._hasResource["dijit.form.ComboBox"]=true;_4.provide("dijit.form.ComboBox");_4.declare("dijit.form.ComboBoxMixin",_5._HasDropDown,{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:_4.cache("dijit.form","templates/DropDownBox.html","<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\r\n\tid=\"widget_${id}\"\r\n\trole=\"combobox\"\r\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\r\n\t\tdojoAttachPoint=\"_buttonNode, _popupStateNode\" role=\"presentation\"\r\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t${_buttonInputDisabled}\r\n\t/></div\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\r\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\r\n\t/></div\r\n></div>\r\n"),baseClass:"dijitTextBox dijitComboBox",dropDownClass:"dijit.form._ComboBoxMenu",cssStateNodes:{"_buttonNode":"dijitDownArrowButton"},maxHeight:-1,_getCaretPos:function(_296){var pos=0;if(typeof (_296.selectionStart)=="number"){pos=_296.selectionStart;}else{if(_4.isIE){var tr=_4.doc.selection.createRange().duplicate();var ntr=_296.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(_297,_298){_298=parseInt(_298);_5.selectInputText(_297,_298,_298);},_setDisabledAttr:function(_299){this.inherited(arguments);_5.setWaiState(this.domNode,"disabled",_299);},_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(_4.hitch(this,function(){this._onKey({charOrCode:229});}),100);}this.inherited(arguments);},_onKey:function(evt){var key=evt.charOrCode;if(evt.altKey||((evt.ctrlKey||evt.metaKey)&&(key!="x"&&key!="v"))||key==_4.keys.SHIFT){return;}var _29a=false;var pw=this.dropDown;var dk=_4.keys;var _29b=null;this._prev_key_backspace=false;this._abortQuery();this.inherited(arguments);if(this._opened){_29b=pw.getHighlightedOption();}switch(key){case dk.PAGE_DOWN:case dk.DOWN_ARROW:case dk.PAGE_UP:case dk.UP_ARROW:if(this._opened){this._announceOption(_29b);}_4.stopEvent(evt);break;case dk.ENTER:if(_29b){if(_29b==pw.nextButton){this._nextSearch(1);_4.stopEvent(evt);break;}else{if(_29b==pw.previousButton){this._nextSearch(-1);_4.stopEvent(evt);break;}}}else{this._setBlurValue();this._setCaretPos(this.focusNode,this.focusNode.value.length);}if(this._opened||this._fetchHandle){evt.preventDefault();}case dk.TAB:var _29c=this.get("displayedValue");if(pw&&(_29c==pw._messages["previousMessage"]||_29c==pw._messages["nextMessage"])){break;}if(_29b){this._selectOption();}if(this._opened){this._lastQuery=null;this.closeDropDown();}break;case " ":if(_29b){_4.stopEvent(evt);this._selectOption();this.closeDropDown();}else{_29a=true;}break;case dk.DELETE:case dk.BACKSPACE:this._prev_key_backspace=true;_29a=true;break;default:_29a=typeof key=="string"||key==229;}if(_29a){this.item=undefined;this.searchTimer=setTimeout(_4.hitch(this,"_startSearchFromInput"),1);}},_autoCompleteText:function(text){var fn=this.focusNode;_5.selectInputText(fn,fn.value.length);var _29d=this.ignoreCase?"toLowerCase":"substr";if(text[_29d](0).indexOf(this.focusNode.value[_29d](0))==0){var cpos=this._getCaretPos(fn);if((cpos+1)>fn.value.length){fn.value=text;_5.selectInputText(fn,cpos);}}else{fn.value=text;_5.selectInputText(fn);}},_openResultList:function(_29e,_29f){this._fetchHandle=null;if(this.disabled||this.readOnly||(_29f.query[this.searchAttr]!=this._lastQuery)){return;}var _2a0=this.dropDown._highlighted_option&&_4.hasClass(this.dropDown._highlighted_option,"dijitMenuItemSelected");this.dropDown.clearResultList();if(!_29e.length&&!this._maxOptions){this.closeDropDown();return;}_29f._maxOptions=this._maxOptions;var _2a1=this.dropDown.createOptions(_29e,_29f,_4.hitch(this,"_getMenuLabelFromItem"));this._showResultList();if(_29f.direction){if(1==_29f.direction){this.dropDown.highlightFirstOption();}else{if(-1==_29f.direction){this.dropDown.highlightLastOption();}}if(_2a0){this._announceOption(this.dropDown.getHighlightedOption());}}else{if(this.autoComplete&&!this._prev_key_backspace&&!/^[*]+$/.test(_29f.query[this.searchAttr])){this._announceOption(_2a1[1]);}}},_showResultList:function(){this.closeDropDown(true);this.displayMessage("");this.openDropDown();_5.setWaiState(this.domNode,"expanded","true");},loadDropDown:function(_2a2){this._startSearchAll();},isLoaded:function(){return false;},closeDropDown:function(){this._abortQuery();if(this._opened){this.inherited(arguments);_5.setWaiState(this.domNode,"expanded","false");_5.removeWaiState(this.focusNode,"activedescendant");}},_setBlurValue:function(){var _2a3=this.get("displayedValue");var pw=this.dropDown;if(pw&&(_2a3==pw._messages["previousMessage"]||_2a3==pw._messages["nextMessage"])){this._setValueAttr(this._lastValueReported,true);}else{if(typeof this.item=="undefined"){this.item=null;this.set("displayedValue",_2a3);}else{if(this.value!=this._lastValueReported){_5.form._FormValueWidget.prototype._setValueAttr.call(this,this.value,true);}this._refreshState();}}},_onBlur:function(){this.closeDropDown();this.inherited(arguments);},_setItemAttr:function(item,_2a4,_2a5){if(!_2a5){var _2a6=this.labelFunc(item,this.store);if(this.labelType=="html"){var span=this._helperSpan;span.innerHTML=_2a6;_2a5=span.innerText||span.textContent;}else{_2a5=_2a6;}}var _2a7=this._getValueField()!=this.searchAttr?this.store.getIdentity(item):_2a5;this._set("item",item);_5.form.ComboBox.superclass._setValueAttr.call(this,_2a7,_2a4,_2a5);},_announceOption:function(node){if(!node){return;}var _2a8;if(node==this.dropDown.nextButton||node==this.dropDown.previousButton){_2a8=node.innerHTML;this.item=undefined;this.value="";}else{_2a8=node.innerText||node.textContent||"";this.set("item",node.item,false,_2a8);}this.focusNode.value=this.focusNode.value.substring(0,this._lastInput.length);_5.setWaiState(this.focusNode,"activedescendant",_4.attr(node,"id"));this._autoCompleteText(_2a8);},_selectOption:function(evt){if(evt){this._announceOption(evt.target);}this.closeDropDown();this._setCaretPos(this.focusNode,this.focusNode.value.length);_5.form._FormValueWidget.prototype._setValueAttr.call(this,this.value,true);},_startSearchAll:function(){this._startSearch("");},_startSearchFromInput:function(){this._startSearch(this.focusNode.value.replace(/([\\\*\?])/g,"\\$1"));},_getQueryString:function(text){return _4.string.substitute(this.queryExpr,[text]);},_startSearch:function(key){if(!this.dropDown){var _2a9=this.id+"_popup",_2aa=_4.getObject(this.dropDownClass,false);this.dropDown=new _2aa({onChange:_4.hitch(this,this._selectOption),id:_2a9,dir:this.dir});_5.removeWaiState(this.focusNode,"activedescendant");_5.setWaiState(this.textbox,"owns",_2a9);}var _2ab=_4.clone(this.query);this._lastInput=key;this._lastQuery=_2ab[this.searchAttr]=this._getQueryString(key);this.searchTimer=setTimeout(_4.hitch(this,function(_2ac,_2ad){this.searchTimer=null;var _2ae={queryOptions:{ignoreCase:this.ignoreCase,deep:true},query:_2ac,onBegin:_4.hitch(this,"_setMaxOptions"),onComplete:_4.hitch(this,"_openResultList"),onError:function(_2af){_2ad._fetchHandle=null;console.error("dijit.form.ComboBox: "+_2af);_2ad.closeDropDown();},start:0,count:this.pageSize};_4.mixin(_2ae,_2ad.fetchProperties);this._fetchHandle=_2ad.store.fetch(_2ae);var _2b0=function(_2b1,_2b2){_2b1.start+=_2b1.count*_2b2;_2b1.direction=_2b2;this._fetchHandle=this.store.fetch(_2b1);this.focus();};this._nextSearch=this.dropDown.onPage=_4.hitch(this,_2b0,this._fetchHandle);},_2ab,this),this.searchDelay);},_setMaxOptions:function(size,_2b3){this._maxOptions=size;},_getValueField:function(){return this.searchAttr;},constructor:function(){this.query={};this.fetchProperties={};},postMixInProperties:function(){if(!this.store){var _2b4=this.srcNodeRef;this.store=new _5.form._ComboBoxDataStore(_2b4);if(!("value" in this.params)){var item=(this.item=this.store.fetchSelectedItem());if(item){var _2b5=this._getValueField();this.value=_2b5!=this.searchAttr?this.store.getValue(item,_2b5):this.labelFunc(item,this.store);}}}this._helperSpan=_4.create("span");this.inherited(arguments);},postCreate:function(){var _2b6=_4.query("label[for=\""+this.id+"\"]");if(_2b6.length){_2b6[0].id=(this.id+"_label");_5.setWaiState(this.domNode,"labelledby",_2b6[0].id);}this.inherited(arguments);},destroy:function(){_4.destroy(this._helperSpan);this.inherited(arguments);},_setHasDownArrowAttr:function(val){this.hasDownArrow=val;this._buttonNode.style.display=val?"":"none";},_getMenuLabelFromItem:function(item){var _2b7=this.labelFunc(item,this.store),_2b8=this.labelType;if(this.highlightMatch!="none"&&this.labelType=="text"&&this._lastInput){_2b7=this.doHighlight(_2b7,this._escapeHtml(this._lastInput));_2b8="html";}return {html:_2b8=="html",label:_2b7};},doHighlight:function(_2b9,find){var _2ba=(this.ignoreCase?"i":"")+(this.highlightMatch=="all"?"g":""),i=this.queryExpr.indexOf("${0}");find=_4.regexp.escapeString(find);return this._escapeHtml(_2b9).replace(new RegExp((i==0?"^":"")+"("+find+")"+(i==(this.queryExpr.length-4)?"$":""),_2ba),"<span class=\"dijitComboBoxHighlightMatch\">$1</span>");},_escapeHtml:function(str){str=String(str).replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;").replace(/"/gm,"&quot;");return str;},reset:function(){this.item=null;this.inherited(arguments);},labelFunc:function(item,_2bb){return _2bb.getValue(item,this.labelAttr||this.searchAttr).toString();}});_4.declare("dijit.form._ComboBoxMenu",[_5._Widget,_5._Templated,_5._CssStateMixin],{templateString:"<ul class='dijitReset dijitMenu' dojoAttachEvent='onmousedown:_onMouseDown,onmouseup:_onMouseUp,onmouseover:_onMouseOver,onmouseout:_onMouseOut' style='overflow: \"auto\"; overflow-x: \"hidden\";'>"+"<li class='dijitMenuItem dijitMenuPreviousButton' dojoAttachPoint='previousButton' role='option'></li>"+"<li class='dijitMenuItem dijitMenuNextButton' dojoAttachPoint='nextButton' role='option'></li>"+"</ul>",_messages:null,baseClass:"dijitComboBoxMenu",postMixInProperties:function(){this.inherited(arguments);this._messages=_4.i18n.getLocalization("dijit.form","ComboBox",this.lang);},buildRendering:function(){this.inherited(arguments);this.previousButton.innerHTML=this._messages["previousMessage"];this.nextButton.innerHTML=this._messages["nextMessage"];},_setValueAttr:function(_2bc){this.value=_2bc;this.onChange(_2bc);},onChange:function(_2bd){},onPage:function(_2be){},onClose:function(){this._blurOptionNode();},_createOption:function(item,_2bf){var _2c0=_4.create("li",{"class":"dijitReset dijitMenuItem"+(this.isLeftToRight()?"":" dijitMenuItemRtl"),role:"option"});var _2c1=_2bf(item);if(_2c1.html){_2c0.innerHTML=_2c1.label;}else{_2c0.appendChild(_4.doc.createTextNode(_2c1.label));}if(_2c0.innerHTML==""){_2c0.innerHTML="&nbsp;";}_2c0.item=item;return _2c0;},createOptions:function(_2c2,_2c3,_2c4){this.previousButton.style.display=(_2c3.start==0)?"none":"";_4.attr(this.previousButton,"id",this.id+"_prev");_4.forEach(_2c2,function(item,i){var _2c5=this._createOption(item,_2c4);_4.attr(_2c5,"id",this.id+i);this.domNode.insertBefore(_2c5,this.nextButton);},this);var _2c6=false;if(_2c3._maxOptions&&_2c3._maxOptions!=-1){if((_2c3.start+_2c3.count)<_2c3._maxOptions){_2c6=true;}else{if((_2c3.start+_2c3.count)>_2c3._maxOptions&&_2c3.count==_2c2.length){_2c6=true;}}}else{if(_2c3.count==_2c2.length){_2c6=true;}}this.nextButton.style.display=_2c6?"":"none";_4.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]);}this._blurOptionNode();},_onMouseDown:function(evt){_4.stopEvent(evt);},_onMouseUp:function(evt){if(evt.target===this.domNode||!this._highlighted_option){return;}else{if(evt.target==this.previousButton){this._blurOptionNode();this.onPage(-1);}else{if(evt.target==this.nextButton){this._blurOptionNode();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;_4.addClass(this._highlighted_option,"dijitMenuItemSelected");}},_blurOptionNode:function(){if(this._highlighted_option){_4.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();}}_4.window.scrollIntoView(this._highlighted_option);},highlightFirstOption:function(){var _2c7=this.domNode.firstChild;var _2c8=_2c7.nextSibling;this._focusOptionNode(_2c8.style.display=="none"?_2c7:_2c8);_4.window.scrollIntoView(this._highlighted_option);},highlightLastOption:function(){this._focusOptionNode(this.domNode.lastChild.previousSibling);_4.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();}}_4.window.scrollIntoView(this._highlighted_option);},_page:function(up){var _2c9=0;var _2ca=this.domNode.scrollTop;var _2cb=_4.style(this.domNode,"height");if(!this.getHighlightedOption()){this._highlightNextOption();}while(_2c9<_2cb){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 _2cc=this.domNode.scrollTop;_2c9+=(_2cc-_2ca)*(up?-1:1);_2ca=_2cc;}},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(evt){switch(evt.charOrCode){case _4.keys.DOWN_ARROW:this._highlightNextOption();return false;case _4.keys.PAGE_DOWN:this.pageDown();return false;case _4.keys.UP_ARROW:this._highlightPrevOption();return false;case _4.keys.PAGE_UP:this.pageUp();return false;default:return true;}}});_4.declare("dijit.form.ComboBox",[_5.form.ValidationTextBox,_5.form.ComboBoxMixin],{_setValueAttr:function(_2cd,_2ce,_2cf){this._set("item",null);if(!_2cd){_2cd="";}_5.form.ValidationTextBox.prototype._setValueAttr.call(this,_2cd,_2ce,_2cf);}});_4.declare("dijit.form._ComboBoxDataStore",null,{constructor:function(root){this.root=root;if(root.tagName!="SELECT"&&root.firstChild){root=_4.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;}_4.query("> option",root).forEach(function(node){node.innerHTML=_4.trim(node.innerHTML);});},getValue:function(item,_2d0,_2d1){return (_2d0=="value")?item.value:(item.innerText||item.textContent||"");},isItemLoaded:function(_2d2){return true;},getFeatures:function(){return {"dojo.data.api.Read":true,"dojo.data.api.Identity":true};},_fetchItems:function(args,_2d3,_2d4){if(!args.query){args.query={};}if(!args.query.name){args.query.name="";}if(!args.queryOptions){args.queryOptions={};}var _2d5=_4.data.util.filter.patternToRegExp(args.query.name,args.queryOptions.ignoreCase),_2d6=_4.query("> option",this.root).filter(function(_2d7){return (_2d7.innerText||_2d7.textContent||"").match(_2d5);});if(args.sort){_2d6.sort(_4.data.util.sorter.createSortFunction(args.sort,this));}_2d3(_2d6,args);},close:function(_2d8){return;},getLabel:function(item){return item.innerHTML;},getIdentity:function(item){return _4.attr(item,"value");},fetchItemByIdentity:function(args){var item=_4.query("> option[value='"+args.identity+"']",this.root)[0];args.onItem(item);},fetchSelectedItem:function(){var root=this.root,si=root.selectedIndex;return typeof si=="number"?_4.query("> option:nth-child("+(si!=-1?si+1:1)+")",root)[0]:null;}});_4.extend(_5.form._ComboBoxDataStore,_4.data.util.simpleFetch);}if(!_4._hasResource["dijit.form.FilteringSelect"]){_4._hasResource["dijit.form.FilteringSelect"]=true;_4.provide("dijit.form.FilteringSelect");_4.declare("dijit.form.FilteringSelect",[_5.form.MappedTextBox,_5.form.ComboBoxMixin],{required:true,_lastDisplayedValue:"",_isValidSubset:function(){return this._opened;},isValid:function(){return this.item||(!this.required&&this.get("displayedValue")=="");},_refreshState:function(){if(!this.searchTimer){this.inherited(arguments);}},_callbackSetLabel:function(_2d9,_2da,_2db){if((_2da&&_2da.query[this.searchAttr]!=this._lastQuery)||(!_2da&&_2d9.length&&this.store.getIdentity(_2d9[0])!=this._lastQuery)){return;}if(!_2d9.length){this.valueNode.value="";_5.form.TextBox.superclass._setValueAttr.call(this,"",_2db||(_2db===undefined&&!this._focused));this._set("item",null);this.validate(this._focused);}else{this.set("item",_2d9[0],_2db);}},_openResultList:function(_2dc,_2dd){if(_2dd.query[this.searchAttr]!=this._lastQuery){return;}_5.form.ComboBoxMixin.prototype._openResultList.apply(this,arguments);if(this.item===undefined){this.validate(true);}},_getValueAttr:function(){return this.valueNode.value;},_getValueField:function(){return "value";},_setValueAttr:function(_2de,_2df){if(!this._onChangeActive){_2df=null;}this._lastQuery=_2de;if(_2de===null||_2de===""){this._setDisplayedValueAttr("",_2df);return;}var self=this;this.store.fetchItemByIdentity({identity:_2de,onItem:function(item){self._callbackSetLabel(item?[item]:[],undefined,_2df);}});},_setItemAttr:function(item,_2e0,_2e1){this.inherited(arguments);this.valueNode.value=this.value;this._lastDisplayedValue=this.textbox.value;},_getDisplayQueryString:function(text){return text.replace(/([\\\*\?])/g,"\\$1");},_setDisplayedValueAttr:function(_2e2,_2e3){if(_2e2==null){_2e2="";}if(!this._created){if(!("displayedValue" in this.params)){return;}_2e3=false;}if(this.store){this.closeDropDown();var _2e4=_4.clone(this.query);this._lastQuery=_2e4[this.labelAttr||this.searchAttr]=this._getDisplayQueryString(_2e2);this.textbox.value=_2e2;this._lastDisplayedValue=_2e2;var _2e5=this;var _2e6={query:_2e4,queryOptions:{ignoreCase:this.ignoreCase,deep:true},onComplete:function(_2e7,_2e8){_2e5._fetchHandle=null;_4.hitch(_2e5,"_callbackSetLabel")(_2e7,_2e8,_2e3);},onError:function(_2e9){_2e5._fetchHandle=null;console.error("dijit.form.FilteringSelect: "+_2e9);_4.hitch(_2e5,"_callbackSetLabel")([],undefined,false);}};_4.mixin(_2e6,this.fetchProperties);this._fetchHandle=this.store.fetch(_2e6);}},undo:function(){this.set("displayedValue",this._lastDisplayedValue);}});}if(!_4._hasResource["dojo.data.ItemFileReadStore"]){_4._hasResource["dojo.data.ItemFileReadStore"]=true;_4.provide("dojo.data.ItemFileReadStore");_4.declare("dojo.data.ItemFileReadStore",null,{constructor:function(_2ea){this._arrayOfAllItems=[];this._arrayOfTopLevelItems=[];this._loadFinished=false;this._jsonFileUrl=_2ea.url;this._ccUrl=_2ea.url;this.url=_2ea.url;this._jsonData=_2ea.data;this.data=null;this._datatypeMap=_2ea.typeMap||{};if(!this._datatypeMap["Date"]){this._datatypeMap["Date"]={type:Date,deserialize:function(_2eb){return _4.date.stamp.fromISOString(_2eb);}};}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(_2ea.urlPreventCache!==undefined){this.urlPreventCache=_2ea.urlPreventCache?true:false;}if(_2ea.hierarchical!==undefined){this.hierarchical=_2ea.hierarchical?true:false;}if(_2ea.clearOnClose){this.clearOnClose=true;}if("failOk" in _2ea){this.failOk=_2ea.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(_2ec){if(typeof _2ec!=="string"){throw new Error("dojo.data.ItemFileReadStore: Invalid attribute argument.");}},getValue:function(item,_2ed,_2ee){var _2ef=this.getValues(item,_2ed);return (_2ef.length>0)?_2ef[0]:_2ee;},getValues:function(item,_2f0){this._assertIsItem(item);this._assertIsAttribute(_2f0);return (item[_2f0]||[]).slice(0);},getAttributes:function(item){this._assertIsItem(item);var _2f1=[];for(var key in item){if((key!==this._storeRefPropName)&&(key!==this._itemNumPropName)&&(key!==this._rootItemPropName)&&(key!==this._reverseRefMap)){_2f1.push(key);}}return _2f1;},hasAttribute:function(item,_2f2){this._assertIsItem(item);this._assertIsAttribute(_2f2);return (_2f2 in item);},containsValue:function(item,_2f3,_2f4){var _2f5=undefined;if(typeof _2f4==="string"){_2f5=_4.data.util.filter.patternToRegExp(_2f4,false);}return this._containsValue(item,_2f3,_2f4,_2f5);},_containsValue:function(item,_2f6,_2f7,_2f8){return _4.some(this.getValues(item,_2f6),function(_2f9){if(_2f9!==null&&!_4.isObject(_2f9)&&_2f8){if(_2f9.toString().match(_2f8)){return true;}}else{if(_2f7===_2f9){return true;}}});},isItem:function(_2fa){if(_2fa&&_2fa[this._storeRefPropName]===this){if(this._arrayOfAllItems[_2fa[this._itemNumPropName]]===_2fa){return true;}}return false;},isItemLoaded:function(_2fb){return this.isItem(_2fb);},loadItem:function(_2fc){this._assertIsItem(_2fc.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(_2fd,_2fe,_2ff){var self=this,_300=function(_301,_302){var _303=[],i,key;if(_301.query){var _304,_305=_301.queryOptions?_301.queryOptions.ignoreCase:false;var _306={};for(key in _301.query){_304=_301.query[key];if(typeof _304==="string"){_306[key]=_4.data.util.filter.patternToRegExp(_304,_305);}else{if(_304 instanceof RegExp){_306[key]=_304;}}}for(i=0;i<_302.length;++i){var _307=true;var _308=_302[i];if(_308===null){_307=false;}else{for(key in _301.query){_304=_301.query[key];if(!self._containsValue(_308,key,_304,_306[key])){_307=false;}}}if(_307){_303.push(_308);}}_2fe(_303,_301);}else{for(i=0;i<_302.length;++i){var item=_302[i];if(item!==null){_303.push(item);}}_2fe(_303,_301);}};if(this._loadFinished){_300(_2fd,this._getItemsArray(_2fd.queryOptions));}else{if(this._jsonFileUrl!==this._ccUrl){_4.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=this.data;this.data=null;}if(this._jsonFileUrl){if(this._loadInProgress){this._queuedFetches.push({args:_2fd,filter:_300});}else{this._loadInProgress=true;var _309={url:self._jsonFileUrl,handleAs:"json-comment-optional",preventCache:this.urlPreventCache,failOk:this.failOk};var _30a=_4.xhrGet(_309);_30a.addCallback(function(data){try{self._getItemsFromLoadedData(data);self._loadFinished=true;self._loadInProgress=false;_300(_2fd,self._getItemsArray(_2fd.queryOptions));self._handleQueuedFetches();}catch(e){self._loadFinished=true;self._loadInProgress=false;_2ff(e,_2fd);}});_30a.addErrback(function(_30b){self._loadInProgress=false;_2ff(_30b,_2fd);});var _30c=null;if(_2fd.abort){_30c=_2fd.abort;}_2fd.abort=function(){var df=_30a;if(df&&df.fired===-1){df.cancel();df=null;}if(_30c){_30c.call(_2fd);}};}}else{if(this._jsonData){try{this._loadFinished=true;this._getItemsFromLoadedData(this._jsonData);this._jsonData=null;_300(_2fd,this._getItemsArray(_2fd.queryOptions));}catch(e){_2ff(e,_2fd);}}else{_2ff(new Error("dojo.data.ItemFileReadStore: No JSON source data was provided as either URL or a nested Javascript object."),_2fd);}}}},_handleQueuedFetches:function(){if(this._queuedFetches.length>0){for(var i=0;i<this._queuedFetches.length;i++){var _30d=this._queuedFetches[i],_30e=_30d.args,_30f=_30d.filter;if(_30f){_30f(_30e,this._getItemsArray(_30e.queryOptions));}else{this.fetchItemByIdentity(_30e);}}this._queuedFetches=[];}},_getItemsArray:function(_310){if(_310&&_310.deep){return this._arrayOfAllItems;}return this._arrayOfTopLevelItems;},close:function(_311){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(_312){var _313=false,self=this;function _314(_315){var _316=((_315!==null)&&(typeof _315==="object")&&(!_4.isArray(_315)||_313)&&(!_4.isFunction(_315))&&(_315.constructor==Object||_4.isArray(_315))&&(typeof _315._reference==="undefined")&&(typeof _315._type==="undefined")&&(typeof _315._value==="undefined")&&self.hierarchical);return _316;};function _317(_318){self._arrayOfAllItems.push(_318);for(var _319 in _318){var _31a=_318[_319];if(_31a){if(_4.isArray(_31a)){var _31b=_31a;for(var k=0;k<_31b.length;++k){var _31c=_31b[k];if(_314(_31c)){_317(_31c);}}}else{if(_314(_31a)){_317(_31a);}}}}};this._labelAttr=_312.label;var i,item;this._arrayOfAllItems=[];this._arrayOfTopLevelItems=_312.items;for(i=0;i<this._arrayOfTopLevelItems.length;++i){item=this._arrayOfTopLevelItems[i];if(_4.isArray(item)){_313=true;}_317(item);item[this._rootItemPropName]=true;}var _31d={},key;for(i=0;i<this._arrayOfAllItems.length;++i){item=this._arrayOfAllItems[i];for(key in item){if(key!==this._rootItemPropName){var _31e=item[key];if(_31e!==null){if(!_4.isArray(_31e)){item[key]=[_31e];}}else{item[key]=[null];}}_31d[key]=key;}}while(_31d[this._storeRefPropName]){this._storeRefPropName+="_";}while(_31d[this._itemNumPropName]){this._itemNumPropName+="_";}while(_31d[this._reverseRefMap]){this._reverseRefMap+="_";}var _31f;var _320=_312.identifier;if(_320){this._itemsByIdentity={};this._features["dojo.data.api.Identity"]=_320;for(i=0;i<this._arrayOfAllItems.length;++i){item=this._arrayOfAllItems[i];_31f=item[_320];var _321=_31f[0];if(!Object.hasOwnProperty.call(this._itemsByIdentity,_321)){this._itemsByIdentity[_321]=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: ["+_320+"]. Value collided: ["+_321+"]");}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: ["+_320+"]. Value collided: ["+_321+"]");}}}}}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){_31f=item[key];for(var j=0;j<_31f.length;++j){_31e=_31f[j];if(_31e!==null&&typeof _31e=="object"){if(("_type" in _31e)&&("_value" in _31e)){var type=_31e._type;var _322=this._datatypeMap[type];if(!_322){throw new Error("dojo.data.ItemFileReadStore: in the typeMap constructor arg, no object class was specified for the datatype '"+type+"'");}else{if(_4.isFunction(_322)){_31f[j]=new _322(_31e._value);}else{if(_4.isFunction(_322.deserialize)){_31f[j]=_322.deserialize(_31e._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(_31e._reference){var _323=_31e._reference;if(!_4.isObject(_323)){_31f[j]=this._getItemByIdentity(_323);}else{for(var k=0;k<this._arrayOfAllItems.length;++k){var _324=this._arrayOfAllItems[k],_325=true;for(var _326 in _323){if(_324[_326]!=_323[_326]){_325=false;}}if(_325){_31f[j]=_324;}}}if(this.referenceIntegrity){var _327=_31f[j];if(this.isItem(_327)){this._addReferenceToMap(_327,item,key);}}}else{if(this.isItem(_31e)){if(this.referenceIntegrity){this._addReferenceToMap(_31e,item,key);}}}}}}}},_addReferenceToMap:function(_328,_329,_32a){},getIdentity:function(item){var _32b=this._features["dojo.data.api.Identity"];if(_32b===Number){return item[this._itemNumPropName];}else{var _32c=item[_32b];if(_32c){return _32c[0];}}return null;},fetchItemByIdentity:function(_32d){var item,_32e;if(!this._loadFinished){var self=this;if(this._jsonFileUrl!==this._ccUrl){_4.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:_32d});}else{this._loadInProgress=true;var _32f={url:self._jsonFileUrl,handleAs:"json-comment-optional",preventCache:this.urlPreventCache,failOk:this.failOk};var _330=_4.xhrGet(_32f);_330.addCallback(function(data){var _331=_32d.scope?_32d.scope:_4.global;try{self._getItemsFromLoadedData(data);self._loadFinished=true;self._loadInProgress=false;item=self._getItemByIdentity(_32d.identity);if(_32d.onItem){_32d.onItem.call(_331,item);}self._handleQueuedFetches();}catch(error){self._loadInProgress=false;if(_32d.onError){_32d.onError.call(_331,error);}}});_330.addErrback(function(_332){self._loadInProgress=false;if(_32d.onError){var _333=_32d.scope?_32d.scope:_4.global;_32d.onError.call(_333,_332);}});}}else{if(this._jsonData){self._getItemsFromLoadedData(self._jsonData);self._jsonData=null;self._loadFinished=true;item=self._getItemByIdentity(_32d.identity);if(_32d.onItem){_32e=_32d.scope?_32d.scope:_4.global;_32d.onItem.call(_32e,item);}}}}else{item=this._getItemByIdentity(_32d.identity);if(_32d.onItem){_32e=_32d.scope?_32d.scope:_4.global;_32d.onItem.call(_32e,item);}}},_getItemByIdentity:function(_334){var item=null;if(this._itemsByIdentity&&Object.hasOwnProperty.call(this._itemsByIdentity,_334)){item=this._itemsByIdentity[_334];}else{if(Object.hasOwnProperty.call(this._arrayOfAllItems,_334)){item=this._arrayOfAllItems[_334];}}if(item===undefined){item=null;}return item;},getIdentityAttributes:function(item){var _335=this._features["dojo.data.api.Identity"];if(_335===Number){return null;}else{return [_335];}},_forceLoad:function(){var self=this;if(this._jsonFileUrl!==this._ccUrl){_4.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=this.data;this.data=null;}if(this._jsonFileUrl){var _336={url:this._jsonFileUrl,handleAs:"json-comment-optional",preventCache:this.urlPreventCache,failOk:this.failOk,sync:true};var _337=_4.xhrGet(_336);_337.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){throw e;}});_337.addErrback(function(_338){throw _338;});}else{if(this._jsonData){self._getItemsFromLoadedData(self._jsonData);self._jsonData=null;self._loadFinished=true;}}}});_4.extend(_4.data.ItemFileReadStore,_4.data.util.simpleFetch);}if(!_4._hasResource["dijit._editor.plugins.FontChoice"]){_4._hasResource["dijit._editor.plugins.FontChoice"]=true;_4.provide("dijit._editor.plugins.FontChoice");_4.declare("dijit._editor.plugins._FontDropDown",[_5._Widget,_5._Templated],{label:"",widgetsInTemplate:true,plainText:false,templateString:"<span style='white-space: nowrap' class='dijit dijitReset dijitInline'>"+"<label class='dijitLeft dijitInline' for='${selectId}'>${label}</label>"+"<input dojoType='dijit.form.FilteringSelect' required='false' labelType='html' labelAttr='label' searchAttr='name' "+"tabIndex='-1' id='${selectId}' dojoAttachPoint='select' value=''/>"+"</span>",postMixInProperties:function(){this.inherited(arguments);this.strings=_4.i18n.getLocalization("dijit._editor","FontChoice");this.label=this.strings[this.command];this.id=_5.getUniqueId(this.declaredClass.replace(/\./g,"_"));this.selectId=this.id+"_select";this.inherited(arguments);},postCreate:function(){var _339=_4.map(this.values,function(_33a){var name=this.strings[_33a]||_33a;return {label:this.getLabel(_33a,name),name:name,value:_33a};},this);this.select.store=new _4.data.ItemFileReadStore({data:{identifier:"value",items:_339}});this.select.set("value","",false);this.disabled=this.select.get("disabled");},_setValueAttr:function(_33b,_33c){_33c=_33c!==false?true:false;this.select.set("value",_4.indexOf(this.values,_33b)<0?"":_33b,_33c);if(!_33c){this.select._lastValueReported=null;}},_getValueAttr:function(){return this.select.get("value");},focus:function(){this.select.focus();},_setDisabledAttr:function(_33d){this.disabled=_33d;this.select.set("disabled",_33d);}});_4.declare("dijit._editor.plugins._FontNameDropDown",_5._editor.plugins._FontDropDown,{generic:false,command:"fontName",postMixInProperties:function(){if(!this.values){this.values=this.generic?["serif","sans-serif","monospace","cursive","fantasy"]:["Arial","Times New Roman","Comic Sans MS","Courier New"];}this.inherited(arguments);},getLabel:function(_33e,name){if(this.plainText){return name;}else{return "<div style='font-family: "+_33e+"'>"+name+"</div>";}},_setValueAttr:function(_33f,_340){_340=_340!==false?true:false;if(this.generic){var map={"Arial":"sans-serif","Helvetica":"sans-serif","Myriad":"sans-serif","Times":"serif","Times New Roman":"serif","Comic Sans MS":"cursive","Apple Chancery":"cursive","Courier":"monospace","Courier New":"monospace","Papyrus":"fantasy"};_33f=map[_33f]||_33f;}this.inherited(arguments,[_33f,_340]);}});_4.declare("dijit._editor.plugins._FontSizeDropDown",_5._editor.plugins._FontDropDown,{command:"fontSize",values:[1,2,3,4,5,6,7],getLabel:function(_341,name){if(this.plainText){return name;}else{return "<font size="+_341+"'>"+name+"</font>";}},_setValueAttr:function(_342,_343){_343=_343!==false?true:false;if(_342.indexOf&&_342.indexOf("px")!=-1){var _344=parseInt(_342,10);_342={10:1,13:2,16:3,18:4,24:5,32:6,48:7}[_344]||_342;}this.inherited(arguments,[_342,_343]);}});_4.declare("dijit._editor.plugins._FormatBlockDropDown",_5._editor.plugins._FontDropDown,{command:"formatBlock",values:["noFormat","p","h1","h2","h3","pre"],postCreate:function(){this.inherited(arguments);this.set("value","noFormat",false);},getLabel:function(_345,name){if(this.plainText||_345=="noFormat"){return name;}else{return "<"+_345+">"+name+"</"+_345+">";}},_execCommand:function(_346,_347,_348){if(_348==="noFormat"){var _349;var end;var sel=_5.range.getSelection(_346.window);if(sel&&sel.rangeCount>0){var _34a=sel.getRangeAt(0);var node,tag;if(_34a){_349=_34a.startContainer;end=_34a.endContainer;while(_349&&_349!==_346.editNode&&_349!==_346.document.body&&_349.nodeType!==1){_349=_349.parentNode;}while(end&&end!==_346.editNode&&end!==_346.document.body&&end.nodeType!==1){end=end.parentNode;}var _34b=_4.hitch(this,function(node,_34c){if(node.childNodes&&node.childNodes.length){var i;for(i=0;i<node.childNodes.length;i++){var c=node.childNodes[i];if(c.nodeType==1){if(_4.withGlobal(_346.window,"inSelection",_5._editor.selection,[c])){var tag=c.tagName?c.tagName.toLowerCase():"";if(_4.indexOf(this.values,tag)!==-1){_34c.push(c);}_34b(c,_34c);}}}}});var _34d=_4.hitch(this,function(_34e){if(_34e&&_34e.length){_346.beginEditing();while(_34e.length){this._removeFormat(_346,_34e.pop());}_346.endEditing();}});var _34f=[];if(_349==end){var _350;node=_349;while(node&&node!==_346.editNode&&node!==_346.document.body){if(node.nodeType==1){tag=node.tagName?node.tagName.toLowerCase():"";if(_4.indexOf(this.values,tag)!==-1){_350=node;break;}}node=node.parentNode;}_34b(_349,_34f);if(_350){_34f=[_350].concat(_34f);}_34d(_34f);}else{node=_349;while(_4.withGlobal(_346.window,"inSelection",_5._editor.selection,[node])){if(node.nodeType==1){tag=node.tagName?node.tagName.toLowerCase():"";if(_4.indexOf(this.values,tag)!==-1){_34f.push(node);}_34b(node,_34f);}node=node.nextSibling;}_34d(_34f);}_346.onDisplayChanged();}}}else{_346.execCommand(_347,_348);}},_removeFormat:function(_351,node){if(_351.customUndo){while(node.firstChild){_4.place(node.firstChild,node,"before");}node.parentNode.removeChild(node);}else{_4.withGlobal(_351.window,"selectElementChildren",_5._editor.selection,[node]);var html=_4.withGlobal(_351.window,"getSelectedHtml",_5._editor.selection,[null]);_4.withGlobal(_351.window,"selectElement",_5._editor.selection,[node]);_351.execCommand("inserthtml",html||"");}}});_4.declare("dijit._editor.plugins.FontChoice",_5._editor._Plugin,{useDefaultCommand:false,_initButton:function(){var _352={fontName:_5._editor.plugins._FontNameDropDown,fontSize:_5._editor.plugins._FontSizeDropDown,formatBlock:_5._editor.plugins._FormatBlockDropDown}[this.command],_353=this.params;if(this.params.custom){_353.values=this.params.custom;}var _354=this.editor;this.button=new _352(_4.delegate({dir:_354.dir,lang:_354.lang},_353));this.connect(this.button.select,"onChange",function(_355){this.editor.focus();if(this.command=="fontName"&&_355.indexOf(" ")!=-1){_355="'"+_355+"'";}if(this.button._execCommand){this.button._execCommand(this.editor,this.command,_355);}else{this.editor.execCommand(this.command,_355);}});},updateState:function(){var _356=this.editor;var _357=this.command;if(!_356||!_356.isLoaded||!_357.length){return;}if(this.button){var _358=this.get("disabled");this.button.set("disabled",_358);if(_358){return;}var _359;try{_359=_356.queryCommandValue(_357)||"";}catch(e){_359="";}var _35a=_4.isString(_359)&&_359.match(/'([^']*)'/);if(_35a){_359=_35a[1];}if(_357==="formatBlock"){if(!_359||_359=="p"){_359=null;var elem;var sel=_5.range.getSelection(this.editor.window);if(sel&&sel.rangeCount>0){var _35b=sel.getRangeAt(0);if(_35b){elem=_35b.endContainer;}}while(elem&&elem!==_356.editNode&&elem!==_356.document){var tg=elem.tagName?elem.tagName.toLowerCase():"";if(tg&&_4.indexOf(this.button.values,tg)>-1){_359=tg;break;}elem=elem.parentNode;}if(!_359){_359="noFormat";}}else{if(_4.indexOf(this.button.values,_359)<0){_359="noFormat";}}}if(_359!==this.button.get("value")){this.button.set("value",_359,false);}}}});_4.subscribe(_5._scopeName+".Editor.getPlugin",null,function(o){if(o.plugin){return;}switch(o.args.name){case "fontName":case "fontSize":case "formatBlock":o.plugin=new _5._editor.plugins.FontChoice({command:o.args.name,plainText:o.args.plainText?o.args.plainText:false});}});}if(!_4._hasResource["dijit.form._FormSelectWidget"]){_4._hasResource["dijit.form._FormSelectWidget"]=true;_4.provide("dijit.form._FormSelectWidget");_4.declare("dijit.form._FormSelectWidget",_5.form._FormValueWidget,{multiple:false,options:null,store:null,query:null,queryOptions:null,onFetch:null,sortByLabel:true,loadChildrenOnOpen:false,getOptions:function(_35c){var _35d=_35c,opts=this.options||[],l=opts.length;if(_35d===undefined){return opts;}if(_4.isArray(_35d)){return _4.map(_35d,"return this.getOptions(item);",this);}if(_4.isObject(_35c)){if(!_4.some(this.options,function(o,idx){if(o===_35d||(o.value&&o.value===_35d.value)){_35d=idx;return true;}return false;})){_35d=-1;}}if(typeof _35d=="string"){for(var i=0;i<l;i++){if(opts[i].value===_35d){_35d=i;break;}}}if(typeof _35d=="number"&&_35d>=0&&_35d<l){return this.options[_35d];}return null;},addOption:function(_35e){if(!_4.isArray(_35e)){_35e=[_35e];}_4.forEach(_35e,function(i){if(i&&_4.isObject(i)){this.options.push(i);}},this);this._loadChildren();},removeOption:function(_35f){if(!_4.isArray(_35f)){_35f=[_35f];}var _360=this.getOptions(_35f);_4.forEach(_360,function(i){if(i){this.options=_4.filter(this.options,function(node,idx){return (node.value!==i.value||node.label!==i.label);});this._removeOptionItem(i);}},this);this._loadChildren();},updateOption:function(_361){if(!_4.isArray(_361)){_361=[_361];}_4.forEach(_361,function(i){var _362=this.getOptions(i),k;if(_362){for(k in i){_362[k]=i[k];}}},this);this._loadChildren();},setStore:function(_363,_364,_365){var _366=this.store;_365=_365||{};if(_366!==_363){_4.forEach(this._notifyConnections||[],_4.disconnect);delete this._notifyConnections;if(_363&&_363.getFeatures()["dojo.data.api.Notification"]){this._notifyConnections=[_4.connect(_363,"onNew",this,"_onNewItem"),_4.connect(_363,"onDelete",this,"_onDeleteItem"),_4.connect(_363,"onSet",this,"_onSetItem")];}this._set("store",_363);}this._onChangeActive=false;if(this.options&&this.options.length){this.removeOption(this.options);}if(_363){this._loadingStore=true;_363.fetch(_4.delegate(_365,{onComplete:function(_367,opts){if(this.sortByLabel&&!_365.sort&&_367.length){_367.sort(_4.data.util.sorter.createSortFunction([{attribute:_363.getLabelAttributes(_367[0])[0]}],_363));}if(_365.onFetch){_367=_365.onFetch.call(this,_367,opts);}_4.forEach(_367,function(i){this._addOptionForItem(i);},this);this._loadingStore=false;this.set("value","_pendingValue" in this?this._pendingValue:_364);delete this._pendingValue;if(!this.loadChildrenOnOpen){this._loadChildren();}else{this._pseudoLoadChildren(_367);}this._fetchedWith=opts;this._lastValueReported=this.multiple?[]:null;this._onChangeActive=true;this.onSetStore();this._handleOnChange(this.value);},scope:this}));}else{delete this._fetchedWith;}return _366;},_setValueAttr:function(_368,_369){if(this._loadingStore){this._pendingValue=_368;return;}var opts=this.getOptions()||[];if(!_4.isArray(_368)){_368=[_368];}_4.forEach(_368,function(i,idx){if(!_4.isObject(i)){i=i+"";}if(typeof i==="string"){_368[idx]=_4.filter(opts,function(node){return node.value===i;})[0]||{value:"",label:""};}},this);_368=_4.filter(_368,function(i){return i&&i.value;});if(!this.multiple&&(!_368[0]||!_368[0].value)&&opts.length){_368[0]=opts[0];}_4.forEach(opts,function(i){i.selected=_4.some(_368,function(v){return v.value===i.value;});});var val=_4.map(_368,function(i){return i.value;}),disp=_4.map(_368,function(i){return i.label;});this._set("value",this.multiple?val:val[0]);this._setDisplay(this.multiple?disp:disp[0]);this._updateSelection();this._handleOnChange(this.value,_369);},_getDisplayedValueAttr:function(){var val=this.get("value");if(!_4.isArray(val)){val=[val];}var ret=_4.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];},_loadChildren:function(){if(this._loadingStore){return;}_4.forEach(this._getChildren(),function(_36a){_36a.destroyRecursive();});_4.forEach(this.options,this._addOptionItem,this);this._updateSelection();},_updateSelection:function(){this._set("value",this._getValueFromOpts());var val=this.value;if(!_4.isArray(val)){val=[val];}if(val&&val[0]){_4.forEach(this._getChildren(),function(_36b){var _36c=_4.some(val,function(v){return _36b.option&&(v===_36b.option.value);});_4.toggleClass(_36b.domNode,this.baseClass+"SelectedOption",_36c);_5.setWaiState(_36b.domNode,"selected",_36c);},this);}},_getValueFromOpts:function(){var opts=this.getOptions()||[];if(!this.multiple&&opts.length){var opt=_4.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 _4.map(_4.filter(opts,function(i){return i.selected;}),function(i){return i.value;})||[];}}return "";},_onNewItem:function(item,_36d){if(!_36d||!_36d.parent){this._addOptionForItem(item);}},_onDeleteItem:function(item){var _36e=this.store;this.removeOption(_36e.getIdentity(item));},_onSetItem:function(item){this.updateOption(this._getOptionObjForItem(item));},_getOptionObjForItem:function(item){var _36f=this.store,_370=_36f.getLabel(item),_371=(_370?_36f.getIdentity(item):null);return {value:_371,label:_370,item:item};},_addOptionForItem:function(item){var _372=this.store;if(!_372.isItemLoaded(item)){_372.loadItem({item:item,onComplete:function(i){this._addOptionForItem(item);},scope:this});return;}var _373=this._getOptionObjForItem(item);this.addOption(_373);},constructor:function(_374){this._oValue=(_374||{}).value||null;},buildRendering:function(){this.inherited(arguments);_4.setSelectable(this.focusNode,false);},_fillContent:function(){var opts=this.options;if(!opts){opts=this.options=this.srcNodeRef?_4.query(">",this.srcNodeRef).map(function(node){if(node.getAttribute("type")==="separator"){return {value:"",label:"",selected:false,disabled:false};}return {value:(node.getAttribute("data-"+_4._scopeName+"-value")||node.getAttribute("value")),label:String(node.innerHTML),selected:node.getAttribute("selected")||false,disabled:node.getAttribute("disabled")||false};},this):[];}if(!this.value){this._set("value",this._getValueFromOpts());}else{if(this.multiple&&typeof this.value=="string"){this_set("value",this.value.split(","));}}},postCreate:function(){this.inherited(arguments);this.connect(this,"onChange","_updateSelection");this.connect(this,"startup","_loadChildren");this._setValueAttr(this.value,null);},startup:function(){this.inherited(arguments);var _375=this.store,_376={};_4.forEach(["query","queryOptions","onFetch"],function(i){if(this[i]){_376[i]=this[i];}delete this[i];},this);if(_375&&_375.getFeatures()["dojo.data.api.Identity"]){this.store=null;this.setStore(_375,this._oValue,_376);}},destroy:function(){_4.forEach(this._notifyConnections||[],_4.disconnect);this.inherited(arguments);},_addOptionItem:function(_377){},_removeOptionItem:function(_378){},_setDisplay:function(_379){},_getChildren:function(){return [];},_getSelectedOptionsAttr:function(){return this.getOptions(this.get("value"));},_pseudoLoadChildren:function(_37a){},onSetStore:function(){}});}if(!_4._hasResource["dijit.MenuItem"]){_4._hasResource["dijit.MenuItem"]=true;_4.provide("dijit.MenuItem");_4.declare("dijit.MenuItem",[_5._Widget,_5._Templated,_5._Contained,_5._CssStateMixin],{templateString:_4.cache("dijit","templates/MenuItem.html","<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" role=\"menuitem\" tabIndex=\"-1\"\r\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\r\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\r\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\r\n\t</td>\r\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">\r\n\t\t<div dojoAttachPoint=\"arrowWrapper\" style=\"visibility: hidden\">\r\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuExpand\"/>\r\n\t\t\t<span class=\"dijitMenuExpandA11y\">+</span>\r\n\t\t</div>\r\n\t</td>\r\n</tr>\r\n"),attributeMap:_4.delegate(_5._Widget.prototype.attributeMap,{label:{node:"containerNode",type:"innerHTML"},iconClass:{node:"iconNode",type:"class"}}),baseClass:"dijitMenuItem",label:"",iconClass:"",accelKey:"",disabled:false,_fillContent:function(_37b){if(_37b&&!("label" in this.params)){this.set("label",_37b.innerHTML);}},buildRendering:function(){this.inherited(arguments);var _37c=this.id+"_text";_4.attr(this.containerNode,"id",_37c);if(this.accelKeyNode){_4.attr(this.accelKeyNode,"id",this.id+"_accel");_37c+=" "+this.id+"_accel";}_5.setWaiState(this.domNode,"labelledby",_37c);_4.setSelectable(this.domNode,false);},_onHover:function(){this.getParent().onItemHover(this);},_onUnhover:function(){this.getParent().onItemUnhover(this);this._set("hovering",false);},_onClick:function(evt){this.getParent().onItemClick(this,evt);_4.stopEvent(evt);},onClick:function(evt){},focus:function(){try{if(_4.isIE==8){this.containerNode.focus();}_5.focus(this.focusNode);}catch(e){}},_onFocus:function(){this._setSelected(true);this.getParent()._onItemFocus(this);this.inherited(arguments);},_setSelected:function(_37d){_4.toggleClass(this.domNode,"dijitMenuItemSelected",_37d);},setLabel:function(_37e){_4.deprecated("dijit.MenuItem.setLabel() is deprecated. Use set('label', ...) instead.","","2.0");this.set("label",_37e);},setDisabled:function(_37f){_4.deprecated("dijit.Menu.setDisabled() is deprecated. Use set('disabled', bool) instead.","","2.0");this.set("disabled",_37f);},_setDisabledAttr:function(_380){_5.setWaiState(this.focusNode,"disabled",_380?"true":"false");this._set("disabled",_380);},_setAccelKeyAttr:function(_381){this.accelKeyNode.style.display=_381?"":"none";this.accelKeyNode.innerHTML=_381;_4.attr(this.containerNode,"colSpan",_381?"1":"2");this._set("accelKey",_381);}});}if(!_4._hasResource["dijit.PopupMenuItem"]){_4._hasResource["dijit.PopupMenuItem"]=true;_4.provide("dijit.PopupMenuItem");_4.declare("dijit.PopupMenuItem",_5.MenuItem,{_fillContent:function(){if(this.srcNodeRef){var _382=_4.query("*",this.srcNodeRef);_5.PopupMenuItem.superclass._fillContent.call(this,_382[0]);this.dropDownContainer=this.srcNodeRef;}},startup:function(){if(this._started){return;}this.inherited(arguments);if(!this.popup){var node=_4.query("[widgetId]",this.dropDownContainer)[0];this.popup=_5.byNode(node);}_4.body().appendChild(this.popup.domNode);this.popup.startup();this.popup.domNode.style.display="none";if(this.arrowWrapper){_4.style(this.arrowWrapper,"visibility","");}_5.setWaiState(this.focusNode,"haspopup","true");},destroyDescendants:function(){if(this.popup){if(!this.popup._destroyed){this.popup.destroyRecursive();}delete this.popup;}this.inherited(arguments);}});}if(!_4._hasResource["dijit.CheckedMenuItem"]){_4._hasResource["dijit.CheckedMenuItem"]=true;_4.provide("dijit.CheckedMenuItem");_4.declare("dijit.CheckedMenuItem",_5.MenuItem,{templateString:_4.cache("dijit","templates/CheckedMenuItem.html","<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" role=\"menuitemcheckbox\" tabIndex=\"-1\"\r\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\r\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\r\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuItemIcon dijitCheckedMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\r\n\t\t<span class=\"dijitCheckedMenuItemIconChar\">&#10003;</span>\r\n\t</td>\r\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode,labelNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">&nbsp;</td>\r\n</tr>\r\n"),checked:false,_setCheckedAttr:function(_383){_4.toggleClass(this.domNode,"dijitCheckedMenuItemChecked",_383);_5.setWaiState(this.domNode,"checked",_383);this._set("checked",_383);},onChange:function(_384){},_onClick:function(e){if(!this.disabled){this.set("checked",!this.checked);this.onChange(this.checked);}this.inherited(arguments);}});}if(!_4._hasResource["dijit.MenuSeparator"]){_4._hasResource["dijit.MenuSeparator"]=true;_4.provide("dijit.MenuSeparator");_4.declare("dijit.MenuSeparator",[_5._Widget,_5._Templated,_5._Contained],{templateString:_4.cache("dijit","templates/MenuSeparator.html","<tr class=\"dijitMenuSeparator\">\r\n\t<td class=\"dijitMenuSeparatorIconCell\">\r\n\t\t<div class=\"dijitMenuSeparatorTop\"></div>\r\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\r\n\t</td>\r\n\t<td colspan=\"3\" class=\"dijitMenuSeparatorLabelCell\">\r\n\t\t<div class=\"dijitMenuSeparatorTop dijitMenuSeparatorLabel\"></div>\r\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\r\n\t</td>\r\n</tr>\r\n"),buildRendering:function(){this.inherited(arguments);_4.setSelectable(this.domNode,false);},isFocusable:function(){return false;}});}if(!_4._hasResource["dijit.Menu"]){_4._hasResource["dijit.Menu"]=true;_4.provide("dijit.Menu");_4.declare("dijit._MenuBase",[_5._Widget,_5._Templated,_5._KeyNavContainer],{parentMenu:null,popupDelay:500,startup:function(){if(this._started){return;}_4.forEach(this.getChildren(),function(_385){_385.startup();});this.startupKeyNavChildren();this.inherited(arguments);},onExecute:function(){},onCancel:function(_386){},_moveToPopup:function(evt){if(this.focusedChild&&this.focusedChild.popup&&!this.focusedChild.disabled){this.focusedChild._onClick(evt);}else{var _387=this._getTopMenu();if(_387&&_387._isMenuBar){_387.focusNext();}}},_onPopupHover:function(evt){if(this.currentPopup&&this.currentPopup._pendingClose_timer){var _388=this.currentPopup.parentMenu;if(_388.focusedChild){_388.focusedChild._setSelected(false);}_388.focusedChild=this.currentPopup.from_item;_388.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(_4.hitch(this,"_openPopup"),this.popupDelay);}}if(this.focusedChild){this.focusChild(item);}this._hoveredChild=item;},_onChildBlur:function(item){this._stopPopupTimer();item._setSelected(false);var _389=item.popup;if(_389){this._stopPendingCloseTimer(_389);_389._pendingClose_timer=setTimeout(function(){_389._pendingClose_timer=null;if(_389.parentMenu){_389.parentMenu.currentPopup=null;}_5.popup.close(_389);},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(_38a){if(_38a._pendingClose_timer){clearTimeout(_38a._pendingClose_timer);_38a._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 _38b=this.focusedChild;if(!_38b){return;}var _38c=_38b.popup;if(_38c.isShowingNow){return;}if(this.currentPopup){this._stopPendingCloseTimer(this.currentPopup);_5.popup.close(this.currentPopup);}_38c.parentMenu=this;_38c.from_item=_38b;var self=this;_5.popup.open({parent:this,popup:_38c,around:_38b.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(_38b);self._cleanUp();_38b._setSelected(true);self.focusedChild=_38b;},onExecute:_4.hitch(this,"_cleanUp")});this.currentPopup=_38c;_38c.connect(_38c.domNode,"onmouseenter",_4.hitch(self,"_onPopupHover"));if(_38c.focus){_38c._focus_timer=setTimeout(_4.hitch(_38c,function(){this._focus_timer=null;this.focus();}),0);}},_markActive:function(){this.isActive=true;_4.replaceClass(this.domNode,"dijitMenuActive","dijitMenuPassive");},onOpen:function(e){this.isShowingNow=true;this._markActive();},_markInactive:function(){this.isActive=false;_4.replaceClass(this.domNode,"dijitMenuPassive","dijitMenuActive");},onClose:function(){this._stopFocusTimer();this._markInactive();this.isShowingNow=false;this.parentMenu=null;},_closeChild:function(){this._stopPopupTimer();var _38d=this.focusedChild&&this.focusedChild.from_item;if(this.currentPopup){if(_5._curFocus&&_4.isDescendant(_5._curFocus,this.currentPopup.domNode)){this.focusedChild.focusNode.focus();}_5.popup.close(this.currentPopup);this.currentPopup=null;}if(this.focusedChild){this.focusedChild._setSelected(false);this.focusedChild._onUnhover();this.focusedChild=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();}}});_4.declare("dijit.Menu",_5._MenuBase,{constructor:function(){this._bindings=[];},templateString:_4.cache("dijit","templates/Menu.html","<table class=\"dijit dijitMenu dijitMenuPassive dijitReset dijitMenuTable\" role=\"menu\" tabIndex=\"${tabIndex}\" dojoAttachEvent=\"onkeypress:_onKeyPress\" cellspacing=\"0\">\r\n\t<tbody class=\"dijitReset\" dojoAttachPoint=\"containerNode\"></tbody>\r\n</table>\r\n"),baseClass:"dijitMenu",targetNodeIds:[],contextMenuForWindow:false,leftClickToOpen:false,refocus:true,postCreate:function(){if(this.contextMenuForWindow){this.bindDomNode(_4.body());}else{_4.forEach(this.targetNodeIds,this.bindDomNode,this);}var k=_4.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);_4.stopEvent(evt);break;case this._closeSubMenuKey:if(this.parentMenu){if(this.parentMenu._isMenuBar){this.parentMenu.focusPrev();}else{this.onCancel(false);}}else{_4.stopEvent(evt);}break;}},_iframeContentWindow:function(_38e){var win=_4.window.get(this._iframeContentDocument(_38e))||this._iframeContentDocument(_38e)["__parent__"]||(_38e.name&&_4.doc.frames[_38e.name])||null;return win;},_iframeContentDocument:function(_38f){var doc=_38f.contentDocument||(_38f.contentWindow&&_38f.contentWindow.document)||(_38f.name&&_4.doc.frames[_38f.name]&&_4.doc.frames[_38f.name].document)||null;return doc;},bindDomNode:function(node){node=_4.byId(node);var cn;if(node.tagName.toLowerCase()=="iframe"){var _390=node,win=this._iframeContentWindow(_390);cn=_4.withGlobal(win,_4.body);}else{cn=(node==_4.body()?_4.doc.documentElement:node);}var _391={node:node,iframe:_390};_4.attr(node,"_dijitMenu"+this.id,this._bindings.push(_391));var _392=_4.hitch(this,function(cn){return [_4.connect(cn,this.leftClickToOpen?"onclick":"oncontextmenu",this,function(evt){_4.stopEvent(evt);this._scheduleOpen(evt.target,_390,{x:evt.pageX,y:evt.pageY});}),_4.connect(cn,"onkeydown",this,function(evt){if(evt.shiftKey&&evt.keyCode==_4.keys.F10){_4.stopEvent(evt);this._scheduleOpen(evt.target,_390);}})];});_391.connects=cn?_392(cn):[];if(_390){_391.onloadHandler=_4.hitch(this,function(){var win=this._iframeContentWindow(_390);cn=_4.withGlobal(win,_4.body);_391.connects=_392(cn);});if(_390.addEventListener){_390.addEventListener("load",_391.onloadHandler,false);}else{_390.attachEvent("onload",_391.onloadHandler);}}},unBindDomNode:function(_393){var node;try{node=_4.byId(_393);}catch(e){return;}var _394="_dijitMenu"+this.id;if(node&&_4.hasAttr(node,_394)){var bid=_4.attr(node,_394)-1,b=this._bindings[bid];_4.forEach(b.connects,_4.disconnect);var _395=b.iframe;if(_395){if(_395.removeEventListener){_395.removeEventListener("load",b.onloadHandler,false);}else{_395.detachEvent("onload",b.onloadHandler);}}_4.removeAttr(node,_394);delete this._bindings[bid];}},_scheduleOpen:function(_396,_397,_398){if(!this._openTimer){this._openTimer=setTimeout(_4.hitch(this,function(){delete this._openTimer;this._openMyself({target:_396,iframe:_397,coords:_398});}),1);}},_openMyself:function(args){var _399=args.target,_39a=args.iframe,_39b=args.coords;if(_39b){if(_39a){var od=_399.ownerDocument,ifc=_4.position(_39a,true),win=this._iframeContentWindow(_39a),_39c=_4.withGlobal(win,"_docScroll",_4);var cs=_4.getComputedStyle(_39a),tp=_4._toPixelValue,left=(_4.isIE&&_4.isQuirks?0:tp(_39a,cs.paddingLeft))+(_4.isIE&&_4.isQuirks?tp(_39a,cs.borderLeftWidth):0),top=(_4.isIE&&_4.isQuirks?0:tp(_39a,cs.paddingTop))+(_4.isIE&&_4.isQuirks?tp(_39a,cs.borderTopWidth):0);_39b.x+=ifc.x+left-_39c.x;_39b.y+=ifc.y+top-_39c.y;}}else{_39b=_4.position(_399,true);_39b.x+=10;_39b.y+=10;}var self=this;var _39d=_5.getFocus(this);function _39e(){if(self.refocus){_5.focus(_39d);}_5.popup.close(self);};_5.popup.open({popup:this,x:_39b.x,y:_39b.y,onExecute:_39e,onCancel:_39e,orient:this.isLeftToRight()?"L":"R"});this.focus();this._onBlur=function(){this.inherited("_onBlur",arguments);_5.popup.close(this);};},uninitialize:function(){_4.forEach(this._bindings,function(b){if(b){this.unBindDomNode(b.node);}},this);this.inherited(arguments);}});}if(!_4._hasResource["dijit.form.Select"]){_4._hasResource["dijit.form.Select"]=true;_4.provide("dijit.form.Select");_4.declare("dijit.form._SelectMenu",_5.Menu,{buildRendering:function(){this.inherited(arguments);var o=(this.menuTableNode=this.domNode);var n=(this.domNode=_4.create("div",{style:{overflowX:"hidden",overflowY:"scroll"}}));if(o.parentNode){o.parentNode.replaceChild(n,o);}_4.removeClass(o,"dijitMenuTable");n.className=o.className+" dijitSelectMenu";o.className="dijitReset dijitMenuTable";_5.setWaiRole(o,"listbox");_5.setWaiRole(n,"presentation");n.appendChild(o);},postCreate:function(){this.inherited(arguments);this.connect(this.domNode,"onmousemove",_4.stopEvent);},resize:function(mb){if(mb){_4.marginBox(this.domNode,mb);if("w" in mb){this.menuTableNode.style.width="100%";}}}});_4.declare("dijit.form.Select",[_5.form._FormSelectWidget,_5._HasDropDown],{baseClass:"dijitSelect",templateString:_4.cache("dijit.form","templates/Select.html","<table class=\"dijit dijitReset dijitInline dijitLeft\"\r\n\tdojoAttachPoint=\"_buttonNode,tableNode,focusNode\" cellspacing='0' cellpadding='0'\r\n\trole=\"combobox\" aria-haspopup=\"true\"\r\n\t><tbody role=\"presentation\"><tr role=\"presentation\"\r\n\t\t><td class=\"dijitReset dijitStretch dijitButtonContents dijitButtonNode\" role=\"presentation\"\r\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\" dojoAttachPoint=\"containerNode,_popupStateNode\"></span\r\n\t\t\t><input type=\"hidden\" ${!nameAttrSetting} dojoAttachPoint=\"valueNode\" value=\"${value}\" aria-hidden=\"true\"\r\n\t\t/></td><td class=\"dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton\"\r\n\t\t\t\tdojoAttachPoint=\"titleNode\" role=\"presentation\"\r\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" role=\"presentation\"></div\r\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" role=\"presentation\">&#9660;</div\r\n\t\t></td\r\n\t></tr></tbody\r\n></table>\r\n"),attributeMap:_4.mixin(_4.clone(_5.form._FormSelectWidget.prototype.attributeMap),{style:"tableNode"}),required:false,state:"",message:"",tooltipPosition:[],emptyLabel:"&nbsp;",_isLoaded:false,_childrenLoaded:false,_fillContent:function(){this.inherited(arguments);if(this.options.length&&!this.value&&this.srcNodeRef){var si=this.srcNodeRef.selectedIndex||0;this.value=this.options[si>=0?si:0].value;}this.dropDown=new _5.form._SelectMenu({id:this.id+"_menu"});_4.addClass(this.dropDown.domNode,this.baseClass+"Menu");},_getMenuItemForOption:function(_39f){if(!_39f.value&&!_39f.label){return new _5.MenuSeparator();}else{var _3a0=_4.hitch(this,"_setValueAttr",_39f);var item=new _5.MenuItem({option:_39f,label:_39f.label||this.emptyLabel,onClick:_3a0,disabled:_39f.disabled||false});_5.setWaiRole(item.focusNode,"listitem");return item;}},_addOptionItem:function(_3a1){if(this.dropDown){this.dropDown.addChild(this._getMenuItemForOption(_3a1));}},_getChildren:function(){if(!this.dropDown){return [];}return this.dropDown.getChildren();},_loadChildren:function(_3a2){if(_3a2===true){if(this.dropDown){delete this.dropDown.focusedChild;}if(this.options.length){this.inherited(arguments);}else{_4.forEach(this._getChildren(),function(_3a3){_3a3.destroyRecursive();});var item=new _5.MenuItem({label:"&nbsp;"});this.dropDown.addChild(item);}}else{this._updateSelection();}this._isLoaded=false;this._childrenLoaded=true;if(!this._loadingStore){this._setValueAttr(this.value);}},_setValueAttr:function(_3a4){this.inherited(arguments);_4.attr(this.valueNode,"value",this.get("value"));},_setDisplay:function(_3a5){var lbl=_3a5||this.emptyLabel;this.containerNode.innerHTML="<span class=\"dijitReset dijitInline "+this.baseClass+"Label\">"+lbl+"</span>";_5.setWaiState(this.focusNode,"valuetext",lbl);},validate:function(_3a6){var _3a7=this.isValid(_3a6);this._set("state",_3a7?"":"Error");_5.setWaiState(this.focusNode,"invalid",_3a7?"false":"true");var _3a8=_3a7?"":this._missingMsg;if(this.message!==_3a8){this._set("message",_3a8);_5.hideTooltip(this.domNode);if(_3a8){_5.showTooltip(_3a8,this.domNode,this.tooltipPosition,!this.isLeftToRight());}}return _3a7;},isValid:function(_3a9){return (!this.required||this.value===0||!(/^\s*$/.test(this.value||"")));},reset:function(){this.inherited(arguments);_5.hideTooltip(this.domNode);this._set("state","");this._set("message","");},postMixInProperties:function(){this.inherited(arguments);this._missingMsg=_4.i18n.getLocalization("dijit.form","validate",this.lang).missingMessage;},postCreate:function(){this.inherited(arguments);this.connect(this.domNode,"onmousemove",_4.stopEvent);},_setStyleAttr:function(_3aa){this.inherited(arguments);_4.toggleClass(this.domNode,this.baseClass+"FixedWidth",!!this.tableNode.style.width);},isLoaded:function(){return this._isLoaded;},loadDropDown:function(_3ab){this._loadChildren(true);this._isLoaded=true;_3ab();},closeDropDown:function(){this.inherited(arguments);if(this.dropDown&&this.dropDown.menuTableNode){this.dropDown.menuTableNode.style.width="";}},uninitialize:function(_3ac){if(this.dropDown&&!this.dropDown._destroyed){this.dropDown.destroyRecursive(_3ac);delete this.dropDown;}this.inherited(arguments);}});}if(!_4._hasResource["dijit._editor.plugins.LinkDialog"]){_4._hasResource["dijit._editor.plugins.LinkDialog"]=true;_4.provide("dijit._editor.plugins.LinkDialog");_4.declare("dijit._editor.plugins.LinkDialog",_5._editor._Plugin,{buttonClass:_5.form.DropDownButton,useDefaultCommand:false,urlRegExp:"((https?|ftps?|file)\\://|./|/|)(/[a-zA-Z]{1,1}:/|)(((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)*(?:[a-zA-Z](?:[-\\da-zA-Z]{0,80}[\\da-zA-Z])?)\\.?)|(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])|(0[xX]0*[\\da-fA-F]?[\\da-fA-F]\\.){3}0[xX]0*[\\da-fA-F]?[\\da-fA-F]|(0+[0-3][0-7][0-7]\\.){3}0+[0-3][0-7][0-7]|(0|[1-9]\\d{0,8}|[1-3]\\d{9}|4[01]\\d{8}|42[0-8]\\d{7}|429[0-3]\\d{6}|4294[0-8]\\d{5}|42949[0-5]\\d{4}|429496[0-6]\\d{3}|4294967[01]\\d{2}|42949672[0-8]\\d|429496729[0-5])|0[xX]0*[\\da-fA-F]{1,8}|([\\da-fA-F]{1,4}\\:){7}[\\da-fA-F]{1,4}|([\\da-fA-F]{1,4}\\:){6}((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])))(\\:\\d+)?(/(?:[^?#\\s/]+/)*(?:[^?#\\s/]{0,}(?:\\?[^?#\\s/]*)?(?:#.*)?)?)?",emailRegExp:"<?(mailto\\:)([!#-'*+\\-\\/-9=?A-Z^-~]+[.])*[!#-'*+\\-\\/-9=?A-Z^-~]+"+"@"+"((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)+(?:[a-zA-Z](?:[-\\da-zA-Z]{0,6}[\\da-zA-Z])?)\\.?)|localhost|^[^-][a-zA-Z0-9_-]*>?",htmlTemplate:"<a href=\"${urlInput}\" _djrealurl=\"${urlInput}\""+" target=\"${targetSelect}\""+">${textInput}</a>",tag:"a",_hostRxp:new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$"),_userAtRxp:new RegExp("^([!#-'*+\\-\\/-9=?A-Z^-~]+[.])*[!#-'*+\\-\\/-9=?A-Z^-~]+@","i"),linkDialogTemplate:["<table><tr><td>","<label for='${id}_urlInput'>${url}</label>","</td><td>","<input dojoType='dijit.form.ValidationTextBox' required='true' "+"id='${id}_urlInput' name='urlInput' intermediateChanges='true'/>","</td></tr><tr><td>","<label for='${id}_textInput'>${text}</label>","</td><td>","<input dojoType='dijit.form.ValidationTextBox' required='true' id='${id}_textInput' "+"name='textInput' intermediateChanges='true'/>","</td></tr><tr><td>","<label for='${id}_targetSelect'>${target}</label>","</td><td>","<select id='${id}_targetSelect' name='targetSelect' dojoType='dijit.form.Select'>","<option selected='selected' value='_self'>${currentWindow}</option>","<option value='_blank'>${newWindow}</option>","<option value='_top'>${topWindow}</option>","<option value='_parent'>${parentWindow}</option>","</select>","</td></tr><tr><td colspan='2'>","<button dojoType='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>","<button dojoType='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>","</td></tr></table>"].join(""),_initButton:function(){var _3ad=this;this.tag=this.command=="insertImage"?"img":"a";var _3ae=_4.mixin(_4.i18n.getLocalization("dijit","common",this.lang),_4.i18n.getLocalization("dijit._editor","LinkDialog",this.lang));var _3af=(this.dropDown=new _5.TooltipDialog({title:_3ae[this.command+"Title"],execute:_4.hitch(this,"setValue"),onOpen:function(){_3ad._onOpenDialog();_5.TooltipDialog.prototype.onOpen.apply(this,arguments);},onCancel:function(){setTimeout(_4.hitch(_3ad,"_onCloseDialog"),0);}}));_3ae.urlRegExp=this.urlRegExp;_3ae.id=_5.getUniqueId(this.editor.id);this._uniqueId=_3ae.id;this._setContent(_3af.title+"<div style='border-bottom: 1px black solid;padding-bottom:2pt;margin-bottom:4pt'></div>"+_4.string.substitute(this.linkDialogTemplate,_3ae));_3af.startup();this._urlInput=_5.byId(this._uniqueId+"_urlInput");this._textInput=_5.byId(this._uniqueId+"_textInput");this._setButton=_5.byId(this._uniqueId+"_setButton");this.connect(_5.byId(this._uniqueId+"_cancelButton"),"onClick",function(){this.dropDown.onCancel();});if(this._urlInput){this.connect(this._urlInput,"onChange","_checkAndFixInput");}if(this._textInput){this.connect(this._textInput,"onChange","_checkAndFixInput");}this._urlRegExp=new RegExp("^"+this.urlRegExp+"$","i");this._emailRegExp=new RegExp("^"+this.emailRegExp+"$","i");this._urlInput.isValid=_4.hitch(this,function(){var _3b0=this._urlInput.get("value");return this._urlRegExp.test(_3b0)||this._emailRegExp.test(_3b0);});this._connectTagEvents();this.inherited(arguments);},_checkAndFixInput:function(){var self=this;var url=this._urlInput.get("value");var _3b1=function(url){var _3b2=false;var _3b3=false;if(url&&url.length>1){url=_4.trim(url);if(url.indexOf("mailto:")!==0){if(url.indexOf("/")>0){if(url.indexOf("://")===-1){if(url.charAt(0)!=="/"&&url.indexOf("./")!==0){if(self._hostRxp.test(url)){_3b2=true;}}}}else{if(self._userAtRxp.test(url)){_3b3=true;}}}}if(_3b2){self._urlInput.set("value","http://"+url);}if(_3b3){self._urlInput.set("value","mailto:"+url);}self._setButton.set("disabled",!self._isValid());};if(this._delayedCheck){clearTimeout(this._delayedCheck);this._delayedCheck=null;}this._delayedCheck=setTimeout(function(){_3b1(url);},250);},_connectTagEvents:function(){this.editor.onLoadDeferred.addCallback(_4.hitch(this,function(){this.connect(this.editor.editNode,"ondblclick",this._onDblClick);}));},_isValid:function(){return this._urlInput.isValid()&&this._textInput.isValid();},_setContent:function(_3b4){this.dropDown.set({parserScope:"dojo",content:_3b4});},_checkValues:function(args){if(args&&args.urlInput){args.urlInput=args.urlInput.replace(/"/g,"&quot;");}return args;},setValue:function(args){this._onCloseDialog();if(_4.isIE){var sel=_5.range.getSelection(this.editor.window);var _3b5=sel.getRangeAt(0);var a=_3b5.endContainer;if(a.nodeType===3){a=a.parentNode;}if(a&&(a.nodeName&&a.nodeName.toLowerCase()!==this.tag)){a=_4.withGlobal(this.editor.window,"getSelectedElement",_5._editor.selection,[this.tag]);}if(a&&(a.nodeName&&a.nodeName.toLowerCase()===this.tag)){if(this.editor.queryCommandEnabled("unlink")){_4.withGlobal(this.editor.window,"selectElementChildren",_5._editor.selection,[a]);this.editor.execCommand("unlink");}}}args=this._checkValues(args);this.editor.execCommand("inserthtml",_4.string.substitute(this.htmlTemplate,args));},_onCloseDialog:function(){this.editor.focus();},_getCurrentValues:function(a){var url,text,_3b6;if(a&&a.tagName.toLowerCase()===this.tag){url=a.getAttribute("_djrealurl")||a.getAttribute("href");_3b6=a.getAttribute("target")||"_self";text=a.textContent||a.innerText;_4.withGlobal(this.editor.window,"selectElement",_5._editor.selection,[a,true]);}else{text=_4.withGlobal(this.editor.window,_5._editor.selection.getSelectedText);}return {urlInput:url||"",textInput:text||"",targetSelect:_3b6||""};},_onOpenDialog:function(){var a;if(_4.isIE){var sel=_5.range.getSelection(this.editor.window);var _3b7=sel.getRangeAt(0);a=_3b7.endContainer;if(a.nodeType===3){a=a.parentNode;}if(a&&(a.nodeName&&a.nodeName.toLowerCase()!==this.tag)){a=_4.withGlobal(this.editor.window,"getSelectedElement",_5._editor.selection,[this.tag]);}}else{a=_4.withGlobal(this.editor.window,"getAncestorElement",_5._editor.selection,[this.tag]);}this.dropDown.reset();this._setButton.set("disabled",true);this.dropDown.set("value",this._getCurrentValues(a));},_onDblClick:function(e){if(e&&e.target){var t=e.target;var tg=t.tagName?t.tagName.toLowerCase():"";if(tg===this.tag&&_4.attr(t,"href")){_4.withGlobal(this.editor.window,"selectElement",_5._editor.selection,[t]);this.editor.onDisplayChanged();setTimeout(_4.hitch(this,function(){this.button.set("disabled",false);this.button.openDropDown();}),10);}}}});_4.declare("dijit._editor.plugins.ImgLinkDialog",[_5._editor.plugins.LinkDialog],{linkDialogTemplate:["<table><tr><td>","<label for='${id}_urlInput'>${url}</label>","</td><td>","<input dojoType='dijit.form.ValidationTextBox' regExp='${urlRegExp}' "+"required='true' id='${id}_urlInput' name='urlInput' intermediateChanges='true'/>","</td></tr><tr><td>","<label for='${id}_textInput'>${text}</label>","</td><td>","<input dojoType='dijit.form.ValidationTextBox' required='false' id='${id}_textInput' "+"name='textInput' intermediateChanges='true'/>","</td></tr><tr><td>","</td><td>","</td></tr><tr><td colspan='2'>","<button dojoType='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>","<button dojoType='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>","</td></tr></table>"].join(""),htmlTemplate:"<img src=\"${urlInput}\" _djrealurl=\"${urlInput}\" alt=\"${textInput}\" />",tag:"img",_getCurrentValues:function(img){var url,text;if(img&&img.tagName.toLowerCase()===this.tag){url=img.getAttribute("_djrealurl")||img.getAttribute("src");text=img.getAttribute("alt");_4.withGlobal(this.editor.window,"selectElement",_5._editor.selection,[img,true]);}else{text=_4.withGlobal(this.editor.window,_5._editor.selection.getSelectedText);}return {urlInput:url||"",textInput:text||""};},_isValid:function(){return this._urlInput.isValid();},_connectTagEvents:function(){this.inherited(arguments);this.editor.onLoadDeferred.addCallback(_4.hitch(this,function(){this.connect(this.editor.editNode,"onmousedown",this._selectTag);}));},_selectTag:function(e){if(e&&e.target){var t=e.target;var tg=t.tagName?t.tagName.toLowerCase():"";if(tg===this.tag){_4.withGlobal(this.editor.window,"selectElement",_5._editor.selection,[t]);}}},_checkValues:function(args){if(args&&args.urlInput){args.urlInput=args.urlInput.replace(/"/g,"&quot;");}if(args&&args.textInput){args.textInput=args.textInput.replace(/"/g,"&quot;");}return args;},_onDblClick:function(e){if(e&&e.target){var t=e.target;var tg=t.tagName?t.tagName.toLowerCase():"";if(tg===this.tag&&_4.attr(t,"src")){_4.withGlobal(this.editor.window,"selectElement",_5._editor.selection,[t]);this.editor.onDisplayChanged();setTimeout(_4.hitch(this,function(){this.button.set("disabled",false);this.button.openDropDown();}),10);}}}});_4.subscribe(_5._scopeName+".Editor.getPlugin",null,function(o){if(o.plugin){return;}switch(o.args.name){case "createLink":o.plugin=new _5._editor.plugins.LinkDialog({command:o.args.name});break;case "insertImage":o.plugin=new _5._editor.plugins.ImgLinkDialog({command:o.args.name});break;}});}if(!_4._hasResource["dijit.MenuBar"]){_4._hasResource["dijit.MenuBar"]=true;_4.provide("dijit.MenuBar");_4.declare("dijit.MenuBar",_5._MenuBase,{templateString:_4.cache("dijit","templates/MenuBar.html","<div class=\"dijitMenuBar dijitMenuPassive\" dojoAttachPoint=\"containerNode\" role=\"menubar\" tabIndex=\"${tabIndex}\" dojoAttachEvent=\"onkeypress: _onKeyPress\"></div>\r\n"),baseClass:"dijitMenuBar",_isMenuBar:true,postCreate:function(){var k=_4.keys,l=this.isLeftToRight();this.connectKeyNavHandlers(l?[k.LEFT_ARROW]:[k.RIGHT_ARROW],l?[k.RIGHT_ARROW]:[k.LEFT_ARROW]);this._orient=this.isLeftToRight()?{BL:"TL"}:{BR:"TR"};},focusChild:function(item){var _3b8=this.focusedChild,_3b9=_3b8&&_3b8.popup&&_3b8.popup.isShowingNow;this.inherited(arguments);if(_3b9&&item.popup&&!item.disabled){this._openPopup();}},_onKeyPress:function(evt){if(evt.ctrlKey||evt.altKey){return;}switch(evt.charOrCode){case _4.keys.DOWN_ARROW:this._moveToPopup(evt);_4.stopEvent(evt);}},onItemClick:function(item,evt){if(item.popup&&item.popup.isShowingNow){item.popup.onCancel();}else{this.inherited(arguments);}}});}if(!_4._hasResource["dijit.MenuBarItem"]){_4._hasResource["dijit.MenuBarItem"]=true;_4.provide("dijit.MenuBarItem");_4.declare("dijit._MenuBarItemMixin",null,{templateString:_4.cache("dijit","templates/MenuBarItem.html","<div class=\"dijitReset dijitInline dijitMenuItem dijitMenuItemLabel\" dojoAttachPoint=\"focusNode\" role=\"menuitem\" tabIndex=\"-1\"\r\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\r\n\t<span dojoAttachPoint=\"containerNode\"></span>\r\n</div>\r\n"),attributeMap:_4.delegate(_5._Widget.prototype.attributeMap,{label:{node:"containerNode",type:"innerHTML"}})});_4.declare("dijit.MenuBarItem",[_5.MenuItem,_5._MenuBarItemMixin],{});}if(!_4._hasResource["dijit.PopupMenuBarItem"]){_4._hasResource["dijit.PopupMenuBarItem"]=true;_4.provide("dijit.PopupMenuBarItem");_4.declare("dijit.PopupMenuBarItem",[_5.PopupMenuItem,_5._MenuBarItemMixin],{});}if(!_4._hasResource["dojo.number"]){_4._hasResource["dojo.number"]=true;_4.provide("dojo.number");_4.getObject("number",true,_4);_4.number.format=function(_3ba,_3bb){_3bb=_4.mixin({},_3bb||{});var _3bc=_4.i18n.normalizeLocale(_3bb.locale),_3bd=_4.i18n.getLocalization("dojo.cldr","number",_3bc);_3bb.customs=_3bd;var _3be=_3bb.pattern||_3bd[(_3bb.type||"decimal")+"Format"];if(isNaN(_3ba)||Math.abs(_3ba)==Infinity){return null;}return _4.number._applyPattern(_3ba,_3be,_3bb);};_4.number._numberPatternRE=/[#0,]*[#0](?:\.0*#*)?/;_4.number._applyPattern=function(_3bf,_3c0,_3c1){_3c1=_3c1||{};var _3c2=_3c1.customs.group,_3c3=_3c1.customs.decimal,_3c4=_3c0.split(";"),_3c5=_3c4[0];_3c0=_3c4[(_3bf<0)?1:0]||("-"+_3c5);if(_3c0.indexOf("%")!=-1){_3bf*=100;}else{if(_3c0.indexOf("‰")!=-1){_3bf*=1000;}else{if(_3c0.indexOf("¤")!=-1){_3c2=_3c1.customs.currencyGroup||_3c2;_3c3=_3c1.customs.currencyDecimal||_3c3;_3c0=_3c0.replace(/\u00a4{1,3}/,function(_3c6){var prop=["symbol","currency","displayName"][_3c6.length-1];return _3c1[prop]||_3c1.currency||"";});}else{if(_3c0.indexOf("E")!=-1){throw new Error("exponential notation not supported");}}}}var _3c7=_4.number._numberPatternRE;var _3c8=_3c5.match(_3c7);if(!_3c8){throw new Error("unable to find a number expression in pattern: "+_3c0);}if(_3c1.fractional===false){_3c1.places=0;}return _3c0.replace(_3c7,_4.number._formatAbsolute(_3bf,_3c8[0],{decimal:_3c3,group:_3c2,places:_3c1.places,round:_3c1.round}));};_4.number.round=function(_3c9,_3ca,_3cb){var _3cc=10/(_3cb||10);return (_3cc*+_3c9).toFixed(_3ca)/_3cc;};if((0.9).toFixed()==0){(function(){var _3cd=_4.number.round;_4.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 _3cd(v,p,m)+(v>0?d:-d);};})();}_4.number._formatAbsolute=function(_3ce,_3cf,_3d0){_3d0=_3d0||{};if(_3d0.places===true){_3d0.places=0;}if(_3d0.places===Infinity){_3d0.places=6;}var _3d1=_3cf.split("."),_3d2=typeof _3d0.places=="string"&&_3d0.places.indexOf(","),_3d3=_3d0.places;if(_3d2){_3d3=_3d0.places.substring(_3d2+1);}else{if(!(_3d3>=0)){_3d3=(_3d1[1]||[]).length;}}if(!(_3d0.round<0)){_3ce=_4.number.round(_3ce,_3d3,_3d0.round);}var _3d4=String(Math.abs(_3ce)).split("."),_3d5=_3d4[1]||"";if(_3d1[1]||_3d0.places){if(_3d2){_3d0.places=_3d0.places.substring(0,_3d2);}var pad=_3d0.places!==undefined?_3d0.places:(_3d1[1]&&_3d1[1].lastIndexOf("0")+1);if(pad>_3d5.length){_3d4[1]=_4.string.pad(_3d5,pad,"0",true);}if(_3d3<_3d5.length){_3d4[1]=_3d5.substr(0,_3d3);}}else{if(_3d4[1]){_3d4.pop();}}var _3d6=_3d1[0].replace(",","");pad=_3d6.indexOf("0");if(pad!=-1){pad=_3d6.length-pad;if(pad>_3d4[0].length){_3d4[0]=_4.string.pad(_3d4[0],pad);}if(_3d6.indexOf("#")==-1){_3d4[0]=_3d4[0].substr(_3d4[0].length-pad);}}var _3d7=_3d1[0].lastIndexOf(","),_3d8,_3d9;if(_3d7!=-1){_3d8=_3d1[0].length-_3d7-1;var _3da=_3d1[0].substr(0,_3d7);_3d7=_3da.lastIndexOf(",");if(_3d7!=-1){_3d9=_3da.length-_3d7-1;}}var _3db=[];for(var _3dc=_3d4[0];_3dc;){var off=_3dc.length-_3d8;_3db.push((off>0)?_3dc.substr(off):_3dc);_3dc=(off>0)?_3dc.slice(0,off):"";if(_3d9){_3d8=_3d9;delete _3d9;}}_3d4[0]=_3db.reverse().join(_3d0.group||",");return _3d4.join(_3d0.decimal||".");};_4.number.regexp=function(_3dd){return _4.number._parseInfo(_3dd).regexp;};_4.number._parseInfo=function(_3de){_3de=_3de||{};var _3df=_4.i18n.normalizeLocale(_3de.locale),_3e0=_4.i18n.getLocalization("dojo.cldr","number",_3df),_3e1=_3de.pattern||_3e0[(_3de.type||"decimal")+"Format"],_3e2=_3e0.group,_3e3=_3e0.decimal,_3e4=1;if(_3e1.indexOf("%")!=-1){_3e4/=100;}else{if(_3e1.indexOf("‰")!=-1){_3e4/=1000;}else{var _3e5=_3e1.indexOf("¤")!=-1;if(_3e5){_3e2=_3e0.currencyGroup||_3e2;_3e3=_3e0.currencyDecimal||_3e3;}}}var _3e6=_3e1.split(";");if(_3e6.length==1){_3e6.push("-"+_3e6[0]);}var re=_4.regexp.buildGroupRE(_3e6,function(_3e7){_3e7="(?:"+_4.regexp.escapeString(_3e7,".")+")";return _3e7.replace(_4.number._numberPatternRE,function(_3e8){var _3e9={signed:false,separator:_3de.strict?_3e2:[_3e2,""],fractional:_3de.fractional,decimal:_3e3,exponent:false},_3ea=_3e8.split("."),_3eb=_3de.places;if(_3ea.length==1&&_3e4!=1){_3ea[1]="###";}if(_3ea.length==1||_3eb===0){_3e9.fractional=false;}else{if(_3eb===undefined){_3eb=_3de.pattern?_3ea[1].lastIndexOf("0")+1:Infinity;}if(_3eb&&_3de.fractional==undefined){_3e9.fractional=true;}if(!_3de.places&&(_3eb<_3ea[1].length)){_3eb+=","+_3ea[1].length;}_3e9.places=_3eb;}var _3ec=_3ea[0].split(",");if(_3ec.length>1){_3e9.groupSize=_3ec.pop().length;if(_3ec.length>1){_3e9.groupSize2=_3ec.pop().length;}}return "("+_4.number._realNumberRegexp(_3e9)+")";});},true);if(_3e5){re=re.replace(/([\s\xa0]*)(\u00a4{1,3})([\s\xa0]*)/g,function(_3ed,_3ee,_3ef,_3f0){var prop=["symbol","currency","displayName"][_3ef.length-1],_3f1=_4.regexp.escapeString(_3de[prop]||_3de.currency||"");_3ee=_3ee?"[\\s\\xa0]":"";_3f0=_3f0?"[\\s\\xa0]":"";if(!_3de.strict){if(_3ee){_3ee+="*";}if(_3f0){_3f0+="*";}return "(?:"+_3ee+_3f1+_3f0+")?";}return _3ee+_3f1+_3f0;});}return {regexp:re.replace(/[\xa0 ]/g,"[\\s\\xa0]"),group:_3e2,decimal:_3e3,factor:_3e4};};_4.number.parse=function(_3f2,_3f3){var info=_4.number._parseInfo(_3f3),_3f4=(new RegExp("^"+info.regexp+"$")).exec(_3f2);if(!_3f4){return NaN;}var _3f5=_3f4[1];if(!_3f4[1]){if(!_3f4[2]){return NaN;}_3f5=_3f4[2];info.factor*=-1;}_3f5=_3f5.replace(new RegExp("["+info.group+"\\s\\xa0"+"]","g"),"").replace(info.decimal,".");return _3f5*info.factor;};_4.number._realNumberRegexp=function(_3f6){_3f6=_3f6||{};if(!("places" in _3f6)){_3f6.places=Infinity;}if(typeof _3f6.decimal!="string"){_3f6.decimal=".";}if(!("fractional" in _3f6)||/^0/.test(_3f6.places)){_3f6.fractional=[true,false];}if(!("exponent" in _3f6)){_3f6.exponent=[true,false];}if(!("eSigned" in _3f6)){_3f6.eSigned=[true,false];}var _3f7=_4.number._integerRegexp(_3f6),_3f8=_4.regexp.buildGroupRE(_3f6.fractional,function(q){var re="";if(q&&(_3f6.places!==0)){re="\\"+_3f6.decimal;if(_3f6.places==Infinity){re="(?:"+re+"\\d+)?";}else{re+="\\d{"+_3f6.places+"}";}}return re;},true);var _3f9=_4.regexp.buildGroupRE(_3f6.exponent,function(q){if(q){return "([eE]"+_4.number._integerRegexp({signed:_3f6.eSigned})+")";}return "";});var _3fa=_3f7+_3f8;if(_3f8){_3fa="(?:(?:"+_3fa+")|(?:"+_3f8+"))";}return _3fa+_3f9;};_4.number._integerRegexp=function(_3fb){_3fb=_3fb||{};if(!("signed" in _3fb)){_3fb.signed=[true,false];}if(!("separator" in _3fb)){_3fb.separator="";}else{if(!("groupSize" in _3fb)){_3fb.groupSize=3;}}var _3fc=_4.regexp.buildGroupRE(_3fb.signed,function(q){return q?"[-+]":"";},true);var _3fd=_4.regexp.buildGroupRE(_3fb.separator,function(sep){if(!sep){return "(?:\\d+)";}sep=_4.regexp.escapeString(sep);if(sep==" "){sep="\\s";}else{if(sep==" "){sep="\\s\\xa0";}}var grp=_3fb.groupSize,grp2=_3fb.groupSize2;if(grp2){var _3fe="(?:0|[1-9]\\d{0,"+(grp2-1)+"}(?:["+sep+"]\\d{"+grp2+"})*["+sep+"]\\d{"+grp+"})";return ((grp-grp2)>0)?"(?:"+_3fe+"|(?:0|[1-9]\\d{0,"+(grp-1)+"}))":_3fe;}return "(?:0|[1-9]\\d{0,"+(grp-1)+"}(?:["+sep+"]\\d{"+grp+"})*)";},true);return _3fc+_3fd;};}if(!_4._hasResource["dijit.ProgressBar"]){_4._hasResource["dijit.ProgressBar"]=true;_4.provide("dijit.ProgressBar");_4.declare("dijit.ProgressBar",[_5._Widget,_5._Templated],{progress:"0",value:"",maximum:100,places:0,indeterminate:false,label:"",name:"",templateString:_4.cache("dijit","templates/ProgressBar.html","<div class=\"dijitProgressBar dijitProgressBarEmpty\" role=\"progressbar\"\r\n\t><div dojoAttachPoint=\"internalProgress\" class=\"dijitProgressBarFull\"\r\n\t\t><div class=\"dijitProgressBarTile\" role=\"presentation\"></div\r\n\t\t><span style=\"visibility:hidden\">&nbsp;</span\r\n\t></div\r\n\t><div dojoAttachPoint=\"labelNode\" class=\"dijitProgressBarLabel\" id=\"${id}_label\"></div\r\n\t><img dojoAttachPoint=\"indeterminateHighContrastImage\" class=\"dijitProgressBarIndeterminateHighContrastImage\" alt=\"\"\r\n/></div>\r\n"),_indeterminateHighContrastImagePath:_4.moduleUrl("dijit","themes/a11y/indeterminate_progress.gif"),postMixInProperties:function(){this.inherited(arguments);if(!("value" in this.params)){this.value=this.indeterminate?Infinity:this.progress;}},buildRendering:function(){this.inherited(arguments);this.indeterminateHighContrastImage.setAttribute("src",this._indeterminateHighContrastImagePath.toString());this.update();},update:function(_3ff){_4.mixin(this,_3ff||{});var tip=this.internalProgress,ap=this.domNode;var _400=1;if(this.indeterminate){_5.removeWaiState(ap,"valuenow");_5.removeWaiState(ap,"valuemin");_5.removeWaiState(ap,"valuemax");}else{if(String(this.progress).indexOf("%")!=-1){_400=Math.min(parseFloat(this.progress)/100,1);this.progress=_400*this.maximum;}else{this.progress=Math.min(this.progress,this.maximum);_400=this.progress/this.maximum;}_5.setWaiState(ap,"describedby",this.labelNode.id);_5.setWaiState(ap,"valuenow",this.progress);_5.setWaiState(ap,"valuemin",0);_5.setWaiState(ap,"valuemax",this.maximum);}this.labelNode.innerHTML=this.report(_400);_4.toggleClass(this.domNode,"dijitProgressBarIndeterminate",this.indeterminate);tip.style.width=(_400*100)+"%";this.onChange();},_setValueAttr:function(v){this._set("value",v);if(v==Infinity){this.update({indeterminate:true});}else{this.update({indeterminate:false,progress:v});}},_setLabelAttr:function(_401){this._set("label",_401);this.update();},_setIndeterminateAttr:function(_402){this.indeterminate=_402;this.update();},report:function(_403){return this.label?this.label:(this.indeterminate?"&nbsp;":_4.number.format(_403,{type:"percent",places:this.places,locale:this.lang}));},onChange:function(){}});}if(!_4._hasResource["dijit.TitlePane"]){_4._hasResource["dijit.TitlePane"]=true;_4.provide("dijit.TitlePane");_4.declare("dijit.TitlePane",[_5.layout.ContentPane,_5._Templated,_5._CssStateMixin],{title:"",open:true,toggleable:true,tabIndex:"0",duration:_5.defaultDuration,baseClass:"dijitTitlePane",templateString:_4.cache("dijit","templates/TitlePane.html","<div>\r\n\t<div dojoAttachEvent=\"onclick:_onTitleClick, onkeypress:_onTitleKey\"\r\n\t\t\tclass=\"dijitTitlePaneTitle\" dojoAttachPoint=\"titleBarNode\">\r\n\t\t<div class=\"dijitTitlePaneTitleFocus\" dojoAttachPoint=\"focusNode\">\r\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"arrowNode\" class=\"dijitArrowNode\" role=\"presentation\"\r\n\t\t\t/><span dojoAttachPoint=\"arrowNodeInner\" class=\"dijitArrowNodeInner\"></span\r\n\t\t\t><span dojoAttachPoint=\"titleNode\" class=\"dijitTitlePaneTextNode\"></span>\r\n\t\t</div>\r\n\t</div>\r\n\t<div class=\"dijitTitlePaneContentOuter\" dojoAttachPoint=\"hideNode\" role=\"presentation\">\r\n\t\t<div class=\"dijitReset\" dojoAttachPoint=\"wipeNode\" role=\"presentation\">\r\n\t\t\t<div class=\"dijitTitlePaneContentInner\" dojoAttachPoint=\"containerNode\" role=\"region\" id=\"${id}_pane\">\r\n\t\t\t\t<!-- nested divs because wipeIn()/wipeOut() doesn't work right on node w/padding etc. Put padding on inner div. -->\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n</div>\r\n"),attributeMap:_4.delegate(_5.layout.ContentPane.prototype.attributeMap,{title:{node:"titleNode",type:"innerHTML"},tooltip:{node:"focusNode",type:"attribute",attribute:"title"},id:""}),buildRendering:function(){this.inherited(arguments);_4.setSelectable(this.titleNode,false);},postCreate:function(){this.inherited(arguments);if(this.toggleable){this._trackMouseState(this.titleBarNode,"dijitTitlePaneTitle");}var _404=this.hideNode,_405=this.wipeNode;this._wipeIn=_4.fx.wipeIn({node:this.wipeNode,duration:this.duration,beforeBegin:function(){_404.style.display="";}});this._wipeOut=_4.fx.wipeOut({node:this.wipeNode,duration:this.duration,onEnd:function(){_404.style.display="none";}});},_setOpenAttr:function(open,_406){_4.forEach([this._wipeIn,this._wipeOut],function(_407){if(_407&&_407.status()=="playing"){_407.stop();}});if(_406){var anim=this[open?"_wipeIn":"_wipeOut"];anim.play();}else{this.hideNode.style.display=this.wipeNode.style.display=open?"":"none";}if(this._started){if(open){this._onShow();}else{this.onHide();}}this.arrowNodeInner.innerHTML=open?"-":"+";_5.setWaiState(this.containerNode,"hidden",open?"false":"true");_5.setWaiState(this.focusNode,"pressed",open?"true":"false");this._set("open",open);this._setCss();},_setToggleableAttr:function(_408){_5.setWaiRole(this.focusNode,_408?"button":"heading");if(_408){_5.setWaiState(this.focusNode,"controls",this.id+"_pane");_4.attr(this.focusNode,"tabIndex",this.tabIndex);}else{_4.removeAttr(this.focusNode,"tabIndex");}this._set("toggleable",_408);this._setCss();},_setContentAttr:function(_409){if(!this.open||!this._wipeOut||this._wipeOut.status()=="playing"){this.inherited(arguments);}else{if(this._wipeIn&&this._wipeIn.status()=="playing"){this._wipeIn.stop();}_4.marginBox(this.wipeNode,{h:_4.marginBox(this.wipeNode).h});this.inherited(arguments);if(this._wipeIn){this._wipeIn.play();}else{this.hideNode.style.display="";}}},toggle:function(){this._setOpenAttr(!this.open,true);},_setCss:function(){var node=this.titleBarNode||this.focusNode;var _40a=this._titleBarClass;this._titleBarClass="dijit"+(this.toggleable?"":"Fixed")+(this.open?"Open":"Closed");_4.replaceClass(node,this._titleBarClass,_40a||"");this.arrowNodeInner.innerHTML=this.open?"-":"+";},_onTitleKey:function(e){if(e.charOrCode==_4.keys.ENTER||e.charOrCode==" "){if(this.toggleable){this.toggle();}_4.stopEvent(e);}else{if(e.charOrCode==_4.keys.DOWN_ARROW&&this.open){this.containerNode.focus();e.preventDefault();}}},_onTitleClick:function(){if(this.toggleable){this.toggle();}},setTitle:function(_40b){_4.deprecated("dijit.TitlePane.setTitle() is deprecated. Use set('title', ...) instead.","","2.0");this.set("title",_40b);}});}if(!_4._hasResource["dojo.DeferredList"]){_4._hasResource["dojo.DeferredList"]=true;_4.provide("dojo.DeferredList");_4.DeferredList=function(list,_40c,_40d,_40e,_40f){var _410=[];_4.Deferred.call(this);var self=this;if(list.length===0&&!_40c){this.resolve([0,[]]);}var _411=0;_4.forEach(list,function(item,i){item.then(function(_412){if(_40c){self.resolve([i,_412]);}else{_413(true,_412);}},function(_414){if(_40d){self.reject(_414);}else{_413(false,_414);}if(_40e){return null;}throw _414;});function _413(_415,_416){_410[i]=[_415,_416];_411++;if(_411===list.length){self.resolve(_410);}};});};_4.DeferredList.prototype=new _4.Deferred();_4.DeferredList.prototype.gatherResults=function(_417){var d=new _4.DeferredList(_417,false,true,false);d.addCallback(function(_418){var ret=[];_4.forEach(_418,function(_419){ret.push(_419[1]);});return ret;});return d;};}if(!_4._hasResource["dojo.cookie"]){_4._hasResource["dojo.cookie"]=true;_4.provide("dojo.cookie");_4.cookie=function(name,_41a,_41b){var c=document.cookie;if(arguments.length==1){var _41c=c.match(new RegExp("(?:^|; )"+_4.regexp.escapeString(name)+"=([^;]*)"));return _41c?decodeURIComponent(_41c[1]):undefined;}else{_41b=_41b||{};var exp=_41b.expires;if(typeof exp=="number"){var d=new Date();d.setTime(d.getTime()+exp*24*60*60*1000);exp=_41b.expires=d;}if(exp&&exp.toUTCString){_41b.expires=exp.toUTCString();}_41a=encodeURIComponent(_41a);var _41d=name+"="+_41a,_41e;for(_41e in _41b){_41d+="; "+_41e;var _41f=_41b[_41e];if(_41f!==true){_41d+="="+_41f;}}document.cookie=_41d;}};_4.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(!_4._hasResource["dijit.tree.TreeStoreModel"]){_4._hasResource["dijit.tree.TreeStoreModel"]=true;_4.provide("dijit.tree.TreeStoreModel");_4.declare("dijit.tree.TreeStoreModel",null,{store:null,childrenAttrs:["children"],newItemIdAttr:"id",labelAttr:"",root:null,query:null,deferItemLoadingUntilExpand:false,constructor:function(args){_4.mixin(this,args);this.connects=[];var _420=this.store;if(!_420.getFeatures()["dojo.data.api.Identity"]){throw new Error("dijit.Tree: store must support dojo.data.Identity");}if(_420.getFeatures()["dojo.data.api.Notification"]){this.connects=this.connects.concat([_4.connect(_420,"onNew",this,"onNewItem"),_4.connect(_420,"onDelete",this,"onDeleteItem"),_4.connect(_420,"onSet",this,"onSetItem")]);}},destroy:function(){_4.forEach(this.connects,_4.disconnect);},getRoot:function(_421,_422){if(this.root){_421(this.root);}else{this.store.fetch({query:this.query,onComplete:_4.hitch(this,function(_423){if(_423.length!=1){throw new Error(this.declaredClass+": query "+_4.toJson(this.query)+" returned "+_423.length+" items, but must return exactly one item");}this.root=_423[0];_421(this.root);}),onError:_422});}},mayHaveChildren:function(item){return _4.some(this.childrenAttrs,function(attr){return this.store.hasAttribute(item,attr);},this);},getChildren:function(_424,_425,_426){var _427=this.store;if(!_427.isItemLoaded(_424)){var _428=_4.hitch(this,arguments.callee);_427.loadItem({item:_424,onItem:function(_429){_428(_429,_425,_426);},onError:_426});return;}var _42a=[];for(var i=0;i<this.childrenAttrs.length;i++){var vals=_427.getValues(_424,this.childrenAttrs[i]);_42a=_42a.concat(vals);}var _42b=0;if(!this.deferItemLoadingUntilExpand){_4.forEach(_42a,function(item){if(!_427.isItemLoaded(item)){_42b++;}});}if(_42b==0){_425(_42a);}else{_4.forEach(_42a,function(item,idx){if(!_427.isItemLoaded(item)){_427.loadItem({item:item,onItem:function(item){_42a[idx]=item;if(--_42b==0){_425(_42a);}},onError:_426});}});}},isItem:function(_42c){return this.store.isItem(_42c);},fetchItemByIdentity:function(_42d){this.store.fetchItemByIdentity(_42d);},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,_42e,_42f){var _430={parent:_42e,attribute:this.childrenAttrs[0]},_431;if(this.newItemIdAttr&&args[this.newItemIdAttr]){this.fetchItemByIdentity({identity:args[this.newItemIdAttr],scope:this,onItem:function(item){if(item){this.pasteItem(item,null,_42e,true,_42f);}else{_431=this.store.newItem(args,_430);if(_431&&(_42f!=undefined)){this.pasteItem(_431,_42e,_42e,false,_42f);}}}});}else{_431=this.store.newItem(args,_430);if(_431&&(_42f!=undefined)){this.pasteItem(_431,_42e,_42e,false,_42f);}}},pasteItem:function(_432,_433,_434,_435,_436){var _437=this.store,_438=this.childrenAttrs[0];if(_433){_4.forEach(this.childrenAttrs,function(attr){if(_437.containsValue(_433,attr,_432)){if(!_435){var _439=_4.filter(_437.getValues(_433,attr),function(x){return x!=_432;});_437.setValues(_433,attr,_439);}_438=attr;}});}if(_434){if(typeof _436=="number"){var _43a=_437.getValues(_434,_438).slice();_43a.splice(_436,0,_432);_437.setValues(_434,_438,_43a);}else{_437.setValues(_434,_438,_437.getValues(_434,_438).concat(_432));}}},onChange:function(item){},onChildrenChange:function(_43b,_43c){},onDelete:function(_43d,_43e){},onNewItem:function(item,_43f){if(!_43f){return;}this.getChildren(_43f.item,_4.hitch(this,function(_440){this.onChildrenChange(_43f.item,_440);}));},onDeleteItem:function(item){this.onDelete(item);},onSetItem:function(item,_441,_442,_443){if(_4.indexOf(this.childrenAttrs,_441)!=-1){this.getChildren(item,_4.hitch(this,function(_444){this.onChildrenChange(item,_444);}));}else{this.onChange(item);}}});}if(!_4._hasResource["dijit.tree.ForestStoreModel"]){_4._hasResource["dijit.tree.ForestStoreModel"]=true;_4.provide("dijit.tree.ForestStoreModel");_4.declare("dijit.tree.ForestStoreModel",_5.tree.TreeStoreModel,{rootId:"$root$",rootLabel:"ROOT",query:null,constructor:function(_445){this.root={store:this,root:true,id:_445.rootId,label:_445.rootLabel,children:_445.rootChildren};},mayHaveChildren:function(item){return item===this.root||this.inherited(arguments);},getChildren:function(_446,_447,_448){if(_446===this.root){if(this.root.children){_447(this.root.children);}else{this.store.fetch({query:this.query,onComplete:_4.hitch(this,function(_449){this.root.children=_449;_447(_449);}),onError:_448});}}else{this.inherited(arguments);}},isItem:function(_44a){return (_44a===this.root)?true:this.inherited(arguments);},fetchItemByIdentity:function(_44b){if(_44b.identity==this.root.id){var _44c=_44b.scope?_44b.scope:_4.global;if(_44b.onItem){_44b.onItem.call(_44c,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,_44d,_44e){if(_44d===this.root){this.onNewRootItem(args);return this.store.newItem(args);}else{return this.inherited(arguments);}},onNewRootItem:function(args){},pasteItem:function(_44f,_450,_451,_452,_453){if(_450===this.root){if(!_452){this.onLeaveRoot(_44f);}}_5.tree.TreeStoreModel.prototype.pasteItem.call(this,_44f,_450===this.root?null:_450,_451===this.root?null:_451,_452,_453);if(_451===this.root){this.onAddToRoot(_44f);}},onAddToRoot:function(item){},onLeaveRoot:function(item){},_requeryTop:function(){var _454=this.root.children||[];this.store.fetch({query:this.query,onComplete:_4.hitch(this,function(_455){this.root.children=_455;if(_454.length!=_455.length||_4.some(_454,function(item,idx){return _455[idx]!=item;})){this.onChildrenChange(this.root,_455);}})});},onNewItem:function(item,_456){this._requeryTop();this.inherited(arguments);},onDeleteItem:function(item){if(_4.indexOf(this.root.children,item)!=-1){this._requeryTop();}this.inherited(arguments);},onSetItem:function(item,_457,_458,_459){this._requeryTop();this.inherited(arguments);}});}if(!_4._hasResource["dojo.dnd.Container"]){_4._hasResource["dojo.dnd.Container"]=true;_4.provide("dojo.dnd.Container");_4.declare("dojo.dnd.Container",null,{skipForm:false,constructor:function(node,_45a){this.node=_4.byId(node);if(!_45a){_45a={};}this.creator=_45a.creator||null;this.skipForm=_45a.skipForm;this.parent=_45a.dropParent&&_4.byId(_45a.dropParent);this.map={};this.current=null;this.containerState="";_4.addClass(this.node,"dojoDndContainer");if(!(_45a&&_45a._skipStartup)){this.startup();}this.events=[_4.connect(this.node,"onmouseover",this,"onMouseOver"),_4.connect(this.node,"onmouseout",this,"onMouseOut"),_4.connect(this.node,"ondragstart",this,"onSelectStart"),_4.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||_4.global;var m=this.map,e=_4.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 _4.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=_4.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,_45b,_45c){if(!this.parent.firstChild){_45c=null;}else{if(_45b){if(!_45c){_45c=this.parent.firstChild;}}else{if(_45c){_45c=_45c.nextSibling;}}}if(_45c){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,_45c);}}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(){_4.forEach(this.events,_4.disconnect);this.clearItems();this.node=this.parent=this.current=null;},markupFactory:function(_45d,node){_45d._skipStartup=true;return new _4.dnd.Container(node,_45d);},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=_4.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||!_4.dnd.isFormElement(e)){_4.stopEvent(e);}},onOverEvent:function(){},onOutEvent:function(){},_changeState:function(type,_45e){var _45f="dojoDnd"+type;var _460=type.toLowerCase()+"State";_4.replaceClass(this.node,_45f+_45e,_45f+this[_460]);this[_460]=_45e;},_addItemClass:function(node,type){_4.addClass(node,"dojoDndItem"+type);},_removeItemClass:function(node,type){_4.removeClass(node,"dojoDndItem"+type);},_getChildByEvent:function(e){var node=e.target;if(node){for(var _461=node.parentNode;_461;node=_461,_461=node.parentNode){if(_461==this.parent&&_4.hasClass(node,"dojoDndItem")){return node;}}}return null;},_normalizedCreator:function(item,hint){var t=(this.creator||this.defaultCreator).call(this,item,hint);if(!_4.isArray(t.type)){t.type=["text"];}if(!t.node.id){t.node.id=_4.dnd.getUniqueId();}_4.addClass(t.node,"dojoDndItem");return t;}});_4.dnd._createNode=function(tag){if(!tag){return _4.dnd._createSpan;}return function(text){return _4.create(tag,{innerHTML:text});};};_4.dnd._createTrTd=function(text){var tr=_4.create("tr");_4.create("td",{innerHTML:text},tr);return tr;};_4.dnd._createSpan=function(text){return _4.create("span",{innerHTML:text});};_4.dnd._defaultCreatorNodes={ul:"li",ol:"li",div:"div",p:"div"};_4.dnd._defaultCreator=function(node){var tag=node.tagName.toLowerCase();var c=tag=="tbody"||tag=="thead"?_4.dnd._createTrTd:_4.dnd._createNode(_4.dnd._defaultCreatorNodes[tag]);return function(item,hint){var _462=item&&_4.isObject(item),data,type,n;if(_462&&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=(_462&&item.data)?item.data:item;type=(_462&&item.type)?item.type:["text"];n=(hint=="avatar"?_4.dnd._createSpan:c)(String(data));}if(!n.id){n.id=_4.dnd.getUniqueId();}return {node:n,data:data,type:type};};};}if(!_4._hasResource["dijit.tree._dndContainer"]){_4._hasResource["dijit.tree._dndContainer"]=true;_4.provide("dijit.tree._dndContainer");_4.getObject("tree",true,_4);_5.tree._compareNodes=function(n1,n2){if(n1===n2){return 0;}if("sourceIndex" in document.documentElement){return n1.sourceIndex-n2.sourceIndex;}else{if("compareDocumentPosition" in document.documentElement){return n1.compareDocumentPosition(n2)&2?1:-1;}else{if(document.createRange){var r1=doc.createRange();r1.setStartBefore(n1);var r2=doc.createRange();r2.setStartBefore(n2);return r1.compareBoundaryPoints(r1.END_TO_END,r2);}else{throw Error("dijit.tree._compareNodes don't know how to compare two different nodes in this browser");}}}};_4.declare("dijit.tree._dndContainer",null,{constructor:function(tree,_463){this.tree=tree;this.node=tree.domNode;_4.mixin(this,_463);this.map={};this.current=null;this.containerState="";_4.addClass(this.node,"dojoDndContainer");this.events=[_4.connect(this.node,"onmouseenter",this,"onOverEvent"),_4.connect(this.node,"onmouseleave",this,"onOutEvent"),_4.connect(this.tree,"_onNodeMouseEnter",this,"onMouseOver"),_4.connect(this.tree,"_onNodeMouseLeave",this,"onMouseOut"),_4.connect(this.node,"ondragstart",_4,"stopEvent"),_4.connect(this.node,"onselectstart",_4,"stopEvent")];},getItem:function(key){var _464=this.selection[key],ret={data:_464,type:["treeNode"]};return ret;},destroy:function(){_4.forEach(this.events,_4.disconnect);this.node=this.parent=null;},onMouseOver:function(_465,evt){this.current=_465;},onMouseOut:function(_466,evt){this.current=null;},_changeState:function(type,_467){var _468="dojoDnd"+type;var _469=type.toLowerCase()+"State";_4.replaceClass(this.node,_468+_467,_468+this[_469]);this[_469]=_467;},_addItemClass:function(node,type){_4.addClass(node,"dojoDndItem"+type);},_removeItemClass:function(node,type){_4.removeClass(node,"dojoDndItem"+type);},onOverEvent:function(){this._changeState("Container","Over");},onOutEvent:function(){this._changeState("Container","");}});}if(!_4._hasResource["dijit.tree._dndSelector"]){_4._hasResource["dijit.tree._dndSelector"]=true;_4.provide("dijit.tree._dndSelector");_4.declare("dijit.tree._dndSelector",_5.tree._dndContainer,{constructor:function(tree,_46a){this.selection={};this.anchor=null;_5.setWaiState(this.tree.domNode,"multiselect",!this.singular);this.events.push(_4.connect(this.tree.domNode,"onmousedown",this,"onMouseDown"),_4.connect(this.tree.domNode,"onmouseup",this,"onMouseUp"),_4.connect(this.tree.domNode,"onmousemove",this,"onMouseMove"));},singular:false,getSelectedTreeNodes:function(){var _46b=[],sel=this.selection;for(var i in sel){_46b.push(sel[i]);}return _46b;},selectNone:function(){this.setSelection([]);return this;},destroy:function(){this.inherited(arguments);this.selection=this.anchor=null;},addTreeNode:function(node,_46c){this.setSelection(this.getSelectedTreeNodes().concat([node]));if(_46c){this.anchor=node;}return node;},removeTreeNode:function(node){this.setSelection(this._setDifference(this.getSelectedTreeNodes(),[node]));return node;},isTreeNodeSelected:function(node){return node.id&&!!this.selection[node.id];},setSelection:function(_46d){var _46e=this.getSelectedTreeNodes();_4.forEach(this._setDifference(_46e,_46d),_4.hitch(this,function(node){node.setSelected(false);if(this.anchor==node){delete this.anchor;}delete this.selection[node.id];}));_4.forEach(this._setDifference(_46d,_46e),_4.hitch(this,function(node){node.setSelected(true);this.selection[node.id]=node;}));this._updateSelectionProperties();},_setDifference:function(xs,ys){_4.forEach(ys,function(y){y.__exclude__=true;});var ret=_4.filter(xs,function(x){return !x.__exclude__;});_4.forEach(ys,function(y){delete y["__exclude__"];});return ret;},_updateSelectionProperties:function(){var _46f=this.getSelectedTreeNodes();var _470=[],_471=[];_4.forEach(_46f,function(node){_471.push(node);_470.push(node.getTreePath());});var _472=_4.map(_471,function(node){return node.item;});this.tree._set("paths",_470);this.tree._set("path",_470[0]||[]);this.tree._set("selectedNodes",_471);this.tree._set("selectedNode",_471[0]||null);this.tree._set("selectedItems",_472);this.tree._set("selectedItem",_472[0]||null);},onMouseDown:function(e){if(!this.current||this.tree.isExpandoNode(e.target,this.current)){return;}if(e.button==_4.mouseButtons.RIGHT){return;}_4.stopEvent(e);var _473=this.current,copy=_4.isCopyKey(e),id=_473.id;if(!this.singular&&!e.shiftKey&&this.selection[id]){this._doDeselect=true;return;}else{this._doDeselect=false;}this.userSelect(_473,copy,e.shiftKey);},onMouseUp:function(e){if(!this._doDeselect){return;}this._doDeselect=false;this.userSelect(this.current,_4.isCopyKey(e),e.shiftKey);},onMouseMove:function(e){this._doDeselect=false;},userSelect:function(node,_474,_475){if(this.singular){if(this.anchor==node&&_474){this.selectNone();}else{this.setSelection([node]);this.anchor=node;}}else{if(_475&&this.anchor){var cr=_5.tree._compareNodes(this.anchor.rowNode,node.rowNode),_476,end,_477=this.anchor;if(cr<0){_476=_477;end=node;}else{_476=node;end=_477;}nodes=[];while(_476!=end){nodes.push(_476);_476=this.tree._getNextNode(_476);}nodes.push(end);this.setSelection(nodes);}else{if(this.selection[node.id]&&_474){this.removeTreeNode(node);}else{if(_474){this.addTreeNode(node,true);}else{this.setSelection([node]);this.anchor=node;}}}}},forInSelectedItems:function(f,o){o=o||_4.global;for(var id in this.selection){f.call(o,this.getItem(id),id,this);}}});}if(!_4._hasResource["dijit.Tree"]){_4._hasResource["dijit.Tree"]=true;_4.provide("dijit.Tree");_4.declare("dijit._TreeNode",[_5._Widget,_5._Templated,_5._Container,_5._Contained,_5._CssStateMixin],{item:null,isTreeNode:true,label:"",isExpandable:null,isExpanded:false,state:"UNCHECKED",templateString:_4.cache("dijit","templates/TreeNode.html","<div class=\"dijitTreeNode\" role=\"presentation\"\r\n\t><div dojoAttachPoint=\"rowNode\" class=\"dijitTreeRow\" role=\"presentation\" dojoAttachEvent=\"onmouseenter:_onMouseEnter, onmouseleave:_onMouseLeave, onclick:_onClick, ondblclick:_onDblClick\"\r\n\t\t><img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"expandoNode\" class=\"dijitTreeExpando\" role=\"presentation\"\r\n\t\t/><span dojoAttachPoint=\"expandoNodeText\" class=\"dijitExpandoText\" role=\"presentation\"\r\n\t\t></span\r\n\t\t><span dojoAttachPoint=\"contentNode\"\r\n\t\t\tclass=\"dijitTreeContent\" role=\"presentation\">\r\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"iconNode\" class=\"dijitIcon dijitTreeIcon\" role=\"presentation\"\r\n\t\t\t/><span dojoAttachPoint=\"labelNode\" class=\"dijitTreeLabel\" role=\"treeitem\" tabindex=\"-1\" aria-selected=\"false\" dojoAttachEvent=\"onfocus:_onLabelFocus\"></span>\r\n\t\t</span\r\n\t></div>\r\n\t<div dojoAttachPoint=\"containerNode\" class=\"dijitTreeContainer\" role=\"presentation\" style=\"display: none;\"></div>\r\n</div>\r\n"),baseClass:"dijitTreeNode",cssStateNodes:{rowNode:"dijitTreeRow",labelNode:"dijitTreeLabel"},attributeMap:_4.delegate(_5._Widget.prototype.attributeMap,{label:{node:"labelNode",type:"innerText"},tooltip:{node:"rowNode",type:"attribute",attribute:"title"}}),buildRendering:function(){this.inherited(arguments);this._setExpando();this._updateItemClasses(this.item);if(this.isExpandable){_5.setWaiState(this.labelNode,"expanded",this.isExpanded);}this.setSelected(false);},_setIndentAttr:function(_478){var _479=(Math.max(_478,0)*this.tree._nodePixelIndent)+"px";_4.style(this.domNode,"backgroundPosition",_479+" 0px");_4.style(this.rowNode,this.isLeftToRight()?"paddingLeft":"paddingRight",_479);_4.forEach(this.getChildren(),function(_47a){_47a.set("indent",_478+1);});this._set("indent",_478);},markProcessing:function(){this.state="LOADING";this._setExpando(true);},unmarkProcessing:function(){this._setExpando(false);},_updateItemClasses:function(item){var tree=this.tree,_47b=tree.model;if(tree._v10Compat&&item===_47b.root){item=null;}this._applyClassAndStyle(item,"icon","Icon");this._applyClassAndStyle(item,"label","Label");this._applyClassAndStyle(item,"row","Row");},_applyClassAndStyle:function(item,_47c,_47d){var _47e="_"+_47c+"Class";var _47f=_47c+"Node";var _480=this[_47e];this[_47e]=this.tree["get"+_47d+"Class"](item,this.isExpanded);_4.replaceClass(this[_47f],this[_47e]||"",_480||"");_4.style(this[_47f],this.tree["get"+_47d+"Style"](item,this.isExpanded)||{});},_updateLayout:function(){var _481=this.getParent();if(!_481||_481.rowNode.style.display=="none"){_4.addClass(this.domNode,"dijitTreeIsRoot");}else{_4.toggleClass(this.domNode,"dijitTreeIsLast",!this.getNextSibling());}},_setExpando:function(_482){var _483=["dijitTreeExpandoLoading","dijitTreeExpandoOpened","dijitTreeExpandoClosed","dijitTreeExpandoLeaf"],_484=["*","-","+","*"],idx=_482?0:(this.isExpandable?(this.isExpanded?1:2):3);_4.replaceClass(this.expandoNode,_483[idx],_483);this.expandoNodeText.innerHTML=_484[idx];},expand:function(){if(this._expandDeferred){return this._expandDeferred;}this._wipeOut&&this._wipeOut.stop();this.isExpanded=true;_5.setWaiState(this.labelNode,"expanded","true");if(this.tree.showRoot||this!==this.tree.rootNode){_5.setWaiRole(this.containerNode,"group");}_4.addClass(this.contentNode,"dijitTreeContentExpanded");this._setExpando();this._updateItemClasses(this.item);if(this==this.tree.rootNode){_5.setWaiState(this.tree.domNode,"expanded","true");}var def,_485=_4.fx.wipeIn({node:this.containerNode,duration:_5.defaultDuration,onEnd:function(){def.callback(true);}});def=(this._expandDeferred=new _4.Deferred(function(){_485.stop();}));_485.play();return def;},collapse:function(){if(!this.isExpanded){return;}if(this._expandDeferred){this._expandDeferred.cancel();delete this._expandDeferred;}this.isExpanded=false;_5.setWaiState(this.labelNode,"expanded","false");if(this==this.tree.rootNode){_5.setWaiState(this.tree.domNode,"expanded","false");}_4.removeClass(this.contentNode,"dijitTreeContentExpanded");this._setExpando();this._updateItemClasses(this.item);if(!this._wipeOut){this._wipeOut=_4.fx.wipeOut({node:this.containerNode,duration:_5.defaultDuration});}this._wipeOut.play();},indent:0,setChildItems:function(_486){var tree=this.tree,_487=tree.model,defs=[];_4.forEach(this.getChildren(),function(_488){_5._Container.prototype.removeChild.call(this,_488);},this);this.state="LOADED";if(_486&&_486.length>0){this.isExpandable=true;_4.forEach(_486,function(item){var id=_487.getIdentity(item),_489=tree._itemNodesMap[id],node;if(_489){for(var i=0;i<_489.length;i++){if(_489[i]&&!_489[i].getParent()){node=_489[i];node.set("indent",this.indent+1);break;}}}if(!node){node=this.tree._createTreeNode({item:item,tree:tree,isExpandable:_487.mayHaveChildren(item),label:tree.getLabel(item),tooltip:tree.getTooltip(item),dir:tree.dir,lang:tree.lang,indent:this.indent+1});if(_489){_489.push(node);}else{tree._itemNodesMap[id]=[node];}}this.addChild(node);if(this.tree.autoExpand||this.tree._state(item)){defs.push(tree._expandNode(node));}},this);_4.forEach(this.getChildren(),function(_48a,idx){_48a._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 _4.DeferredList(defs);},getTreePath:function(){var node=this;var path=[];while(node&&node!==this.tree.rootNode){path.unshift(node.item);node=node.getParent();}path.unshift(this.tree.rootNode.item);return path;},getIdentity:function(){return this.tree.model.getIdentity(this.item);},removeChild:function(node){this.inherited(arguments);var _48b=this.getChildren();if(_48b.length==0){this.isExpandable=false;this.collapse();}_4.forEach(_48b,function(_48c){_48c._updateLayout();});},makeExpandable:function(){this.isExpandable=true;this._setExpando(false);},_onLabelFocus:function(evt){this.tree._onNodeFocus(this);},setSelected:function(_48d){_5.setWaiState(this.labelNode,"selected",_48d);_4.toggleClass(this.rowNode,"dijitTreeRowSelected",_48d);},setFocusable:function(_48e){this.labelNode.setAttribute("tabIndex",_48e?"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);}});_4.declare("dijit.Tree",[_5._Widget,_5._Templated],{store:null,model:null,query:null,label:"",showRoot:true,childrenAttr:["children"],paths:[],path:[],selectedItems:null,selectedItem:null,openOnClick:false,openOnDblClick:false,templateString:_4.cache("dijit","templates/Tree.html","<div class=\"dijitTree dijitTreeContainer\" role=\"tree\"\r\n\tdojoAttachEvent=\"onkeypress:_onKeyPress\">\r\n\t<div class=\"dijitInline dijitTreeIndent\" style=\"position: absolute; top: -9999px\" dojoAttachPoint=\"indentDetector\"></div>\r\n</div>\r\n"),persist:true,autoExpand:false,dndController:"dijit.tree._dndSelector",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(_48f,_490){_4.publish(this.id,[_4.mixin({tree:this,event:_48f},_490||{})]);},postMixInProperties:function(){this.tree=this;if(this.autoExpand){this.persist=false;}this._itemNodesMap={};if(!this.cookieName){this.cookieName=this.id+"SaveStateCookie";}this._loadDeferred=new _4.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(_4.isString(this.dndController)){this.dndController=_4.getObject(this.dndController);}var _491={};for(var i=0;i<this.dndParams.length;i++){if(this[this.dndParams[i]]){_491[this.dndParams[i]]=this[this.dndParams[i]];}}this.dndController=new this.dndController(this,_491);}},_store2model:function(){this._v10Compat=true;_4.deprecated("Tree: from version 2.0, should specify a model object rather than a store/query");var _492={id:this.id+"_ForestStoreModel",store:this.store,query:this.query,childrenAttrs:this.childrenAttr};if(this.params.mayHaveChildren){_492.mayHaveChildren=_4.hitch(this,"mayHaveChildren");}if(this.params.getItemChildren){_492.getChildren=_4.hitch(this,function(item,_493,_494){this.getItemChildren((this._v10Compat&&item===this.model.root)?null:item,_493,_494);});}this.model=new _5.tree.ForestStoreModel(_492);this.showRoot=Boolean(this.label);},onLoad:function(){},_load:function(){this.model.getRoot(_4.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";_5.setWaiRole(this.domNode,"presentation");_5.setWaiRole(rn.labelNode,"presentation");_5.setWaiRole(rn.containerNode,"tree");}this.domNode.appendChild(rn.domNode);var _495=this.model.getIdentity(item);if(this._itemNodesMap[_495]){this._itemNodesMap[_495].push(rn);}else{this._itemNodesMap[_495]=[rn];}rn._updateLayout();this._expandNode(rn).addCallback(_4.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 _496=_4.isString(item)?item:this.model.getIdentity(item);return [].concat(this._itemNodesMap[_496]);},_setSelectedItemAttr:function(item){this.set("selectedItems",[item]);},_setSelectedItemsAttr:function(_497){var tree=this;this._loadDeferred.addCallback(_4.hitch(this,function(){var _498=_4.map(_497,function(item){return (!item||_4.isString(item))?item:tree.model.getIdentity(item);});var _499=[];_4.forEach(_498,function(id){_499=_499.concat(tree._itemNodesMap[id]||[]);});this.set("selectedNodes",_499);}));},_setPathAttr:function(path){if(path.length){return this.set("paths",[path]);}else{return this.set("paths",[]);}},_setPathsAttr:function(_49a){var tree=this;return new _4.DeferredList(_4.map(_49a,function(path){var d=new _4.Deferred();path=_4.map(path,function(item){return _4.isString(item)?item:tree.model.getIdentity(item);});if(path.length){tree._loadDeferred.addCallback(function(){_49b(path,[tree.rootNode],d);});}else{d.errback("Empty path");}return d;})).addCallback(_49c);function _49b(path,_49d,def){var _49e=path.shift();var _49f=_4.filter(_49d,function(node){return node.getIdentity()==_49e;})[0];if(!!_49f){if(path.length){tree._expandNode(_49f).addCallback(function(){_49b(path,_49f.getChildren(),def);});}else{def.callback(_49f);}}else{def.errback("Could not expand path at "+_49e);}};function _49c(_4a0){tree.set("selectedNodes",_4.map(_4.filter(_4a0,function(x){return x[0];}),function(x){return x[1];}));};},_setSelectedNodeAttr:function(node){this.set("selectedNodes",[node]);},_setSelectedNodesAttr:function(_4a1){this._loadDeferred.addCallback(_4.hitch(this,function(){this.dndController.setSelection(_4a1);}));},mayHaveChildren:function(item){},getItemChildren:function(_4a2,_4a3){},getLabel:function(item){return this.model.getLabel(item);},getIconClass:function(item,_4a4){return (!item||this.model.mayHaveChildren(item))?(_4a4?"dijitFolderOpened":"dijitFolderClosed"):"dijitLeaf";},getLabelClass:function(item,_4a5){},getRowClass:function(item,_4a6){},getIconStyle:function(item,_4a7){},getLabelStyle:function(item,_4a8){},getRowStyle:function(item,_4a9){},getTooltip:function(item){return "";},_onKeyPress:function(e){if(e.altKey){return;}var dk=_4.keys;var _4aa=_5.getEnclosingWidget(e.target);if(!_4aa){return;}var key=e.charOrCode;if(typeof key=="string"&&key!=" "){if(!e.altKey&&!e.ctrlKey&&!e.shiftKey&&!e.metaKey){this._onLetterKeyNav({node:_4aa,key:key.toLowerCase()});_4.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[dk.SPACE]=map[" "]="_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:_4aa,item:_4aa.item,evt:e});_4.stopEvent(e);}}},_onEnterKey:function(_4ab){this._publish("execute",{item:_4ab.item,node:_4ab.node});this.dndController.userSelect(_4ab.node,_4.isCopyKey(_4ab.evt),_4ab.evt.shiftKey);this.onClick(_4ab.item,_4ab.node,_4ab.evt);},_onDownArrow:function(_4ac){var node=this._getNextNode(_4ac.node);if(node&&node.isTreeNode){this.focusNode(node);}},_onUpArrow:function(_4ad){var node=_4ad.node;var _4ae=node.getPreviousSibling();if(_4ae){node=_4ae;while(node.isExpandable&&node.isExpanded&&node.hasChildren()){var _4af=node.getChildren();node=_4af[_4af.length-1];}}else{var _4b0=node.getParent();if(!(!this.showRoot&&_4b0===this.rootNode)){node=_4b0;}}if(node&&node.isTreeNode){this.focusNode(node);}},_onRightArrow:function(_4b1){var node=_4b1.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(_4b2){var node=_4b2.node;if(node.isExpandable&&node.isExpanded){this._collapseNode(node);}else{var _4b3=node.getParent();if(_4b3&&_4b3.isTreeNode&&!(!this.showRoot&&_4b3===this.rootNode)){this.focusNode(_4b3);}}},_onHomeKey:function(){var node=this._getRootOrFirstNode();if(node){this.focusNode(node);}},_onEndKey:function(_4b4){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(_4b5){var cs=this._curSearch;if(cs){cs.pattern=cs.pattern+_4b5.key;clearTimeout(cs.timer);}else{cs=this._curSearch={pattern:_4b5.key,startNode:_4b5.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);}}},isExpandoNode:function(node,_4b6){return _4.isDescendant(node,_4b6.expandoNode);},_onClick:function(_4b7,e){var _4b8=e.target,_4b9=this.isExpandoNode(_4b8,_4b7);if((this.openOnClick&&_4b7.isExpandable)||_4b9){if(_4b7.isExpandable){this._onExpandoClick({node:_4b7});}}else{this._publish("execute",{item:_4b7.item,node:_4b7,evt:e});this.onClick(_4b7.item,_4b7,e);this.focusNode(_4b7);}_4.stopEvent(e);},_onDblClick:function(_4ba,e){var _4bb=e.target,_4bc=(_4bb==_4ba.expandoNode||_4bb==_4ba.expandoNodeText);if((this.openOnDblClick&&_4ba.isExpandable)||_4bc){if(_4ba.isExpandable){this._onExpandoClick({node:_4ba});}}else{this._publish("execute",{item:_4ba.item,node:_4ba,evt:e});this.onDblClick(_4ba.item,_4ba,e);this.focusNode(_4ba);}_4.stopEvent(e);},_onExpandoClick:function(_4bd){var node=_4bd.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 _4be=node.getNextSibling();if(_4be){return _4be;}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,_4bf){if(node._expandNodeDeferred&&!_4bf){return node._expandNodeDeferred;}var _4c0=this.model,item=node.item,_4c1=this;switch(node.state){case "UNCHECKED":node.markProcessing();var def=(node._expandNodeDeferred=new _4.Deferred());_4c0.getChildren(item,function(_4c2){node.unmarkProcessing();var scid=node.setChildItems(_4c2);var ed=_4c1._expandNode(node,true);scid.addCallback(function(){ed.addCallback(function(){def.callback();});});},function(err){console.error(_4c1,": 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){_5.focus(node.labelNode);},_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 _4c3=this.model,_4c4=_4c3.getIdentity(item),_4c5=this._itemNodesMap[_4c4];if(_4c5){var _4c6=this.getLabel(item),_4c7=this.getTooltip(item);_4.forEach(_4c5,function(node){node.set({item:item,label:_4c6,tooltip:_4c7});node._updateItemClasses(item);});}},_onItemChildrenChange:function(_4c8,_4c9){var _4ca=this.model,_4cb=_4ca.getIdentity(_4c8),_4cc=this._itemNodesMap[_4cb];if(_4cc){_4.forEach(_4cc,function(_4cd){_4cd.setChildItems(_4c9);});}},_onItemDelete:function(item){var _4ce=this.model,_4cf=_4ce.getIdentity(item),_4d0=this._itemNodesMap[_4cf];if(_4d0){_4.forEach(_4d0,function(node){var _4d1=node.getParent();if(_4d1){_4d1.removeChild(node);}node.destroyRecursive();});delete this._itemNodesMap[_4cf];}},_initState:function(){if(this.persist){var _4d2=_4.cookie(this.cookieName);this._openedItemIds={};if(_4d2){_4.forEach(_4d2.split(","),function(item){this._openedItemIds[item]=true;},this);}}},_state:function(item,_4d3){if(!this.persist){return false;}var id=this.model.getIdentity(item);if(arguments.length===1){return this._openedItemIds[id];}if(_4d3){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);}_4.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&&!_4.isString(this.dndController)){this.dndController.destroy();}this.rootNode=null;this.inherited(arguments);},destroyRecursive:function(){this.destroy();},resize:function(_4d4){if(_4d4){_4.marginBox(this.domNode,_4d4);}this._nodePixelIndent=_4._getMarginSize(this.tree.indentDetector).w;if(this.tree.rootNode){this.tree.rootNode.set("indent",this.showRoot?0:-1);}},_createTreeNode:function(args){return new _5._TreeNode(args);}});}if(!_4._hasResource["dijit.InlineEditBox"]){_4._hasResource["dijit.InlineEditBox"]=true;_4.provide("dijit.InlineEditBox");_4.declare("dijit.InlineEditBox",_5._Widget,{editing:false,autoSave:true,buttonSave:"",buttonCancel:"",renderAsHtml:false,editor:"dijit.form.TextBox",editorWrapper:"dijit._InlineEditor",editorParams:{},disabled:false,onChange:function(_4d5){},onCancel:function(){},width:"100%",value:"",noValueIndicator:_4.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 _4d6={ondijitclick:"_onClick",onmouseover:"_onMouseOver",onmouseout:"_onMouseOut",onfocus:"_onMouseOver",onblur:"_onMouseOut"};for(var name in _4d6){this.connect(this.displayNode,name,_4d6[name]);}_5.setWaiRole(this.displayNode,"button");if(!this.displayNode.getAttribute("tabIndex")){this.displayNode.setAttribute("tabIndex",0);}if(!this.value&&!("value" in this.params)){this.value=_4.trim(this.renderAsHtml?this.displayNode.innerHTML:(this.displayNode.innerText||this.displayNode.textContent||""));}if(!this.value){this.displayNode.innerHTML=this.noValueIndicator;}_4.addClass(this.displayNode,"dijitInlineEditBoxDisplayMode");},setDisabled:function(_4d7){_4.deprecated("dijit.InlineEditBox.setDisabled() is deprecated. Use set('disabled', bool) instead.","","2.0");this.set("disabled",_4d7);},_setDisabledAttr:function(_4d8){_5.setWaiState(this.domNode,"disabled",_4d8);if(_4d8){this.displayNode.removeAttribute("tabIndex");}else{this.displayNode.setAttribute("tabIndex",0);}_4.toggleClass(this.displayNode,"dijitInlineEditBoxDisplayModeDisabled",_4d8);this._set("disabled",_4d8);},_onMouseOver:function(){if(!this.disabled){_4.addClass(this.displayNode,"dijitInlineEditBoxDisplayModeHover");}},_onMouseOut:function(){_4.removeClass(this.displayNode,"dijitInlineEditBoxDisplayModeHover");},_onClick:function(e){if(this.disabled){return;}if(e){_4.stopEvent(e);}this._onMouseOut();setTimeout(_4.hitch(this,"edit"),0);},edit:function(){if(this.disabled||this.editing){return;}this.editing=true;this._savedPosition=_4.style(this.displayNode,"position")||"static";this._savedOpacity=_4.style(this.displayNode,"opacity")||"1";this._savedTabIndex=_4.attr(this.displayNode,"tabIndex")||"0";if(this.wrapperWidget){var ew=this.wrapperWidget.editWidget;ew.set("displayedValue" in ew?"displayedValue":"value",this.value);}else{var _4d9=_4.create("span",null,this.domNode,"before");var ewc=typeof this.editorWrapper=="string"?_4.getObject(this.editorWrapper):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:_4.getComputedStyle(this.displayNode),save:_4.hitch(this,"save"),cancel:_4.hitch(this,"cancel")},_4d9);}var ww=this.wrapperWidget;if(_4.isIE){_5.focus(_5.getFocus());}_4.style(this.displayNode,{position:"absolute",opacity:"0",display:"none"});_4.style(ww.domNode,{position:this._savedPosition,visibility:"visible",opacity:"1"});_4.attr(this.displayNode,"tabIndex","-1");setTimeout(_4.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._destroyed){this.wrapperWidget.destroy();delete this.wrapperWidget;}this.inherited(arguments);},_showText:function(_4da){var ww=this.wrapperWidget;_4.style(ww.domNode,{position:"absolute",visibility:"hidden",opacity:"0"});_4.style(this.displayNode,{position:this._savedPosition,opacity:this._savedOpacity,display:""});_4.attr(this.displayNode,"tabIndex",this._savedTabIndex);if(_4da){_5.focus(this.displayNode);}},save:function(_4db){if(this.disabled||!this.editing){return;}this.editing=false;var ww=this.wrapperWidget;var _4dc=ww.getValue();this.set("value",_4dc);this._showText(_4db);},setValue:function(val){_4.deprecated("dijit.InlineEditBox.setValue() is deprecated. Use set('value', ...) instead.","","2.0");return this.set("value",val);},_setValueAttr:function(val){val=_4.trim(val);var _4dd=this.renderAsHtml?val:val.replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;").replace(/"/gm,"&quot;").replace(/\n/g,"<br>");this.displayNode.innerHTML=_4dd||this.noValueIndicator;this._set("value",val);if(this._started){setTimeout(_4.hitch(this,"onChange",val),0);}},getValue:function(){_4.deprecated("dijit.InlineEditBox.getValue() is deprecated. Use get('value') instead.","","2.0");return this.get("value");},cancel:function(_4de){if(this.disabled||!this.editing){return;}this.editing=false;setTimeout(_4.hitch(this,"onCancel"),0);this._showText(_4de);}});_4.declare("dijit._InlineEditor",[_5._Widget,_5._Templated],{templateString:_4.cache("dijit","templates/InlineEditBox.html","<span data-dojo-attach-point=\"editNode\" role=\"presentation\" style=\"position: absolute; visibility:hidden\" class=\"dijitReset dijitInline\"\r\n\tdata-dojo-attach-event=\"onkeypress: _onKeyPress\"\r\n\t><span data-dojo-attach-point=\"editorPlaceholder\"></span\r\n\t><span data-dojo-attach-point=\"buttonContainer\"\r\n\t\t><button data-dojo-type=\"dijit.form.Button\" data-dojo-props=\"label: '${buttonSave}', 'class': 'saveButton'\"\r\n\t\t\tdata-dojo-attach-point=\"saveButton\" data-dojo-attach-event=\"onClick:save\"></button\r\n\t\t><button data-dojo-type=\"dijit.form.Button\" data-dojo-props=\"label: '${buttonCancel}', 'class': 'cancelButton'\"\r\n\t\t\tdata-dojo-attach-point=\"cancelButton\" data-dojo-attach-event=\"onClick:cancel\"></button\r\n\t></span\r\n></span>\r\n"),widgetsInTemplate:true,postMixInProperties:function(){this.inherited(arguments);this.messages=_4.i18n.getLocalization("dijit","common",this.lang);_4.forEach(["buttonSave","buttonCancel"],function(prop){if(!this[prop]){this[prop]=this.messages[prop];}},this);},buildRendering:function(){this.inherited(arguments);var cls=typeof this.editor=="string"?_4.getObject(this.editor):this.editor;var _4df=this.sourceStyle,_4e0="line-height:"+_4df.lineHeight+";",_4e1=_4.getComputedStyle(this.domNode);_4.forEach(["Weight","Family","Size","Style"],function(prop){var _4e2=_4df["font"+prop],_4e3=_4e1["font"+prop];if(_4e3!=_4e2){_4e0+="font-"+prop+":"+_4df["font"+prop]+";";}},this);_4.forEach(["marginTop","marginBottom","marginLeft","marginRight"],function(prop){this.domNode.style[prop]=_4df[prop];},this);var _4e4=this.inlineEditBox.width;if(_4e4=="100%"){_4e0+="width:100%;";this.domNode.style.display="block";}else{_4e0+="width:"+(_4e4+(Number(_4e4)==_4e4?"px":""))+";";}var _4e5=_4.delegate(this.inlineEditBox.editorParams,{style:_4e0,dir:this.dir,lang:this.lang});_4e5["displayedValue" in cls.prototype?"displayedValue":"value"]=this.value;this.editWidget=new cls(_4e5,this.editorPlaceholder);if(this.inlineEditBox.autoSave){_4.destroy(this.buttonContainer);}},postCreate:function(){this.inherited(arguments);var ew=this.editWidget;if(this.inlineEditBox.autoSave){this.connect(ew,"onChange","_onChange");this.connect(ew,"onKeyPress","_onKeyPress");}else{if("intermediateChanges" in ew){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==_4.keys.ESCAPE){_4.stopEvent(e);this.cancel(true);}else{if(e.charOrCode==_4.keys.ENTER&&e.target.tagName=="INPUT"){_4.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()){_4.style(this.inlineEditBox.displayNode,{display:""});_5.focus(this.inlineEditBox.displayNode);}},enableSave:function(){return (this.editWidget.isValid?this.editWidget.isValid():true);},focus:function(){this.editWidget.focus();setTimeout(_4.hitch(this,function(){if(this.editWidget.focusNode&&this.editWidget.focusNode.tagName=="INPUT"){_5.selectInputText(this.editWidget.focusNode);}}),0);}});}if(!_4._hasResource["dijit.form.Form"]){_4._hasResource["dijit.form.Form"]=true;_4.provide("dijit.form.Form");_4.declare("dijit.form.Form",[_5._Widget,_5._Templated,_5.form._FormMixin,_5.layout._ContentPaneResizeMixin],{name:"",action:"",method:"",encType:"","accept-charset":"",accept:"",target:"",templateString:"<form dojoAttachPoint='containerNode' dojoAttachEvent='onreset:_onReset,onsubmit:_onSubmit' ${!nameAttrSetting}></form>",attributeMap:_4.delegate(_5._Widget.prototype.attributeMap,{action:"",method:"",encType:"","accept-charset":"",accept:"",target:""}),postMixInProperties:function(){this.nameAttrSetting=this.name?("name='"+this.name+"'"):"";this.inherited(arguments);},execute:function(_4e6){},onExecute:function(){},_setEncTypeAttr:function(_4e7){this.encType=_4e7;_4.attr(this.domNode,"encType",_4e7);if(_4.isIE){this.domNode.encoding=_4e7;}},postCreate:function(){if(_4.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);_4.stopEvent(e);return false;},_onSubmit:function(e){var fp=_5.form.Form.prototype;if(this.execute!=fp.execute||this.onExecute!=fp.onExecute){_4.deprecated("dijit.form.Form:execute()/onExecute() are deprecated. Use onSubmit() instead.","","2.0");this.onExecute();this.execute(this.getValues());}if(this.onSubmit(e)===false){_4.stopEvent(e);}},onSubmit:function(e){return this.isValid();},submit:function(){if(!(this.onSubmit()===false)){this.containerNode.submit();}}});}if(!_4._hasResource["dijit.form.DropDownButton"]){_4._hasResource["dijit.form.DropDownButton"]=true;_4.provide("dijit.form.DropDownButton");}if(!_4._hasResource["dijit.form.ComboButton"]){_4._hasResource["dijit.form.ComboButton"]=true;_4.provide("dijit.form.ComboButton");}if(!_4._hasResource["dijit.form.ToggleButton"]){_4._hasResource["dijit.form.ToggleButton"]=true;_4.provide("dijit.form.ToggleButton");}if(!_4._hasResource["dijit.form.CheckBox"]){_4._hasResource["dijit.form.CheckBox"]=true;_4.provide("dijit.form.CheckBox");_4.declare("dijit.form.CheckBox",_5.form.ToggleButton,{templateString:_4.cache("dijit.form","templates/CheckBox.html","<div class=\"dijit dijitReset dijitInline\" role=\"presentation\"\r\n\t><input\r\n\t \t${!nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\r\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\r\n\t\tdojoAttachPoint=\"focusNode\"\r\n\t \tdojoAttachEvent=\"onclick:_onClick\"\r\n/></div>\r\n"),baseClass:"dijitCheckBox",type:"checkbox",value:"on",readOnly:false,attributeMap:_4.delegate(_5.form._FormWidget.prototype.attributeMap,{readOnly:"focusNode"}),_setReadOnlyAttr:function(_4e8){this._set("readOnly",_4e8);_4.attr(this.focusNode,"readOnly",_4e8);_5.setWaiState(this.focusNode,"readonly",_4e8);},_setValueAttr:function(_4e9,_4ea){if(typeof _4e9=="string"){this._set("value",_4e9);_4.attr(this.focusNode,"value",_4e9);_4e9=true;}if(this._created){this.set("checked",_4e9,_4ea);}},_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(_4eb){},reset:function(){this._hasBeenBlurred=false;this.set("checked",this.params.checked||false);this._set("value",this.params.value||"on");_4.attr(this.focusNode,"value",this.value);},_onFocus:function(){if(this.id){_4.query("label[for='"+this.id+"']").addClass("dijitFocusedLabel");}this.inherited(arguments);},_onBlur:function(){if(this.id){_4.query("label[for='"+this.id+"']").removeClass("dijitFocusedLabel");}this.inherited(arguments);},_onClick:function(e){if(this.readOnly){_4.stopEvent(e);return false;}return this.inherited(arguments);}});_4.declare("dijit.form.RadioButton",_5.form.CheckBox,{type:"radio",baseClass:"dijitRadio",_setCheckedAttr:function(_4ec){this.inherited(arguments);if(!this._created){return;}if(_4ec){var _4ed=this;_4.query("INPUT[type=radio]",this.focusNode.form||_4.doc).forEach(function(_4ee){if(_4ee.name==_4ed.name&&_4ee!=_4ed.focusNode&&_4ee.form==_4ed.focusNode.form){var _4ef=_5.getEnclosingWidget(_4ee);if(_4ef&&_4ef.checked){_4ef.set("checked",false);}}});}},_clicked:function(e){if(!this.checked){this.set("checked",true);}}});}if(!_4._hasResource["dijit.form.RadioButton"]){_4._hasResource["dijit.form.RadioButton"]=true;_4.provide("dijit.form.RadioButton");}if(!_4._hasResource["dojo.cldr.monetary"]){_4._hasResource["dojo.cldr.monetary"]=true;_4.provide("dojo.cldr.monetary");_4.getObject("cldr.monetary",true,_4);_4.cldr.monetary.getData=function(code){var _4f0={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 _4f1={CHF:5};var _4f2=_4f0[code],_4f3=_4f1[code];if(typeof _4f2=="undefined"){_4f2=2;}if(typeof _4f3=="undefined"){_4f3=0;}return {places:_4f2,round:_4f3};};}if(!_4._hasResource["dojo.currency"]){_4._hasResource["dojo.currency"]=true;_4.provide("dojo.currency");_4.getObject("currency",true,_4);_4.currency._mixInDefaults=function(_4f4){_4f4=_4f4||{};_4f4.type="currency";var _4f5=_4.i18n.getLocalization("dojo.cldr","currency",_4f4.locale)||{};var iso=_4f4.currency;var data=_4.cldr.monetary.getData(iso);_4.forEach(["displayName","symbol","group","decimal"],function(prop){data[prop]=_4f5[iso+"_"+prop];});data.fractional=[true,false];return _4.mixin(data,_4f4);};_4.currency.format=function(_4f6,_4f7){return _4.number.format(_4f6,_4.currency._mixInDefaults(_4f7));};_4.currency.regexp=function(_4f8){return _4.number.regexp(_4.currency._mixInDefaults(_4f8));};_4.currency.parse=function(_4f9,_4fa){return _4.number.parse(_4f9,_4.currency._mixInDefaults(_4fa));};}if(!_4._hasResource["dijit.form.NumberTextBox"]){_4._hasResource["dijit.form.NumberTextBox"]=true;_4.provide("dijit.form.NumberTextBox");_4.declare("dijit.form.NumberTextBoxMixin",null,{regExpGen:_4.number.regexp,value:NaN,editOptions:{pattern:"#.######"},_formatter:_4.number.format,_setConstraintsAttr:function(_4fb){var _4fc=typeof _4fb.places=="number"?_4fb.places:0;if(_4fc){_4fc++;}if(typeof _4fb.max!="number"){_4fb.max=9*Math.pow(10,15-_4fc);}if(typeof _4fb.min!="number"){_4fb.min=-9*Math.pow(10,15-_4fc);}this.inherited(arguments,[_4fb]);if(this.focusNode&&this.focusNode.value&&!isNaN(this.value)){this.set("value",this.value);}},_onFocus:function(){if(this.disabled){return;}var val=this.get("value");if(typeof val=="number"&&!isNaN(val)){var _4fd=this.format(val,this.constraints);if(_4fd!==undefined){this.textbox.value=_4fd;}}this.inherited(arguments);},format:function(_4fe,_4ff){var _500=String(_4fe);if(typeof _4fe!="number"){return _500;}if(isNaN(_4fe)){return "";}if(!("rangeCheck" in this&&this.rangeCheck(_4fe,_4ff))&&_4ff.exponent!==false&&/\de[-+]?\d/i.test(_500)){return _500;}if(this.editOptions&&this._focused){_4ff=_4.mixin({},_4ff,this.editOptions);}return this._formatter(_4fe,_4ff);},_parser:_4.number.parse,parse:function(_501,_502){var v=this._parser(_501,_4.mixin({},_502,(this.editOptions&&this._focused)?this.editOptions:{}));if(this.editOptions&&this._focused&&isNaN(v)){v=this._parser(_501,_502);}return v;},_getDisplayedValueAttr:function(){var v=this.inherited(arguments);return isNaN(v)?this.textbox.value:v;},filter:function(_503){return (_503===null||_503===""||_503===undefined)?NaN:this.inherited(arguments);},serialize:function(_504,_505){return (typeof _504!="number"||isNaN(_504))?"":this.inherited(arguments);},_setBlurValue:function(){var val=_4.hitch(_4.mixin({},this,{_focused:true}),"get")("value");this._setValueAttr(val,true);},_setValueAttr:function(_506,_507,_508){if(_506!==undefined&&_508===undefined){_508=String(_506);if(typeof _506=="number"){if(isNaN(_506)){_508="";}else{if(("rangeCheck" in this&&this.rangeCheck(_506,this.constraints))||this.constraints.exponent===false||!/\de[-+]?\d/i.test(_508)){_508=undefined;}}}else{if(!_506){_508="";_506=NaN;}else{_506=undefined;}}}this.inherited(arguments,[_506,_507,_508]);},_getValueAttr:function(){var v=this.inherited(arguments);if(isNaN(v)&&this.textbox.value!==""){if(this.constraints.exponent!==false&&/\de[-+]?\d/i.test(this.textbox.value)&&(new RegExp("^"+_4.number._realNumberRegexp(_4.mixin({},this.constraints))+"$").test(this.textbox.value))){var n=Number(this.textbox.value);return isNaN(n)?undefined:n;}else{return undefined;}}else{return v;}},isValid:function(_509){if(!this._focused||this._isEmpty(this.textbox.value)){return this.inherited(arguments);}else{var v=this.get("value");if(!isNaN(v)&&this.rangeCheck(v,this.constraints)){if(this.constraints.exponent!==false&&/\de[-+]?\d/i.test(this.textbox.value)){return true;}else{return this.inherited(arguments);}}else{return false;}}}});_4.declare("dijit.form.NumberTextBox",[_5.form.RangeBoundTextBox,_5.form.NumberTextBoxMixin],{baseClass:"dijitTextBox dijitNumberTextBox"});}if(!_4._hasResource["dijit.form.CurrencyTextBox"]){_4._hasResource["dijit.form.CurrencyTextBox"]=true;_4.provide("dijit.form.CurrencyTextBox");_4.declare("dijit.form.CurrencyTextBox",_5.form.NumberTextBox,{currency:"",baseClass:"dijitTextBox dijitCurrencyTextBox",regExpGen:function(_50a){return "("+(this._focused?this.inherited(arguments,[_4.mixin({},_50a,this.editOptions)])+"|":"")+_4.currency.regexp(_50a)+")";},_formatter:_4.currency.format,_parser:_4.currency.parse,parse:function(_50b,_50c){var v=this.inherited(arguments);if(isNaN(v)&&/\d+/.test(_50b)){v=_4.hitch(_4.mixin({},this,{_parser:_5.form.NumberTextBox.prototype._parser}),"inherited")(arguments);}return v;},_setConstraintsAttr:function(_50d){if(!_50d.currency&&this.currency){_50d.currency=this.currency;}this.inherited(arguments,[_4.currency._mixInDefaults(_4.mixin(_50d,{exponent:false}))]);}});}if(!_4._hasResource["dojo.cldr.supplemental"]){_4._hasResource["dojo.cldr.supplemental"]=true;_4.provide("dojo.cldr.supplemental");_4.getObject("cldr.supplemental",true,_4);_4.cldr.supplemental.getFirstDayOfWeek=function(_50e){var _50f={mv:5,ae:6,af:6,bh:6,dj:6,dz:6,eg:6,er:6,et:6,iq:6,ir:6,jo:6,ke:6,kw:6,ly:6,ma:6,om:6,qa:6,sa:6,sd:6,so:6,sy: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,il:0,"in":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,th:0,tt:0,tw:0,um:0,us:0,uz:0,vi:0,zw:0};var _510=_4.cldr.supplemental._region(_50e);var dow=_50f[_510];return (dow===undefined)?1:dow;};_4.cldr.supplemental._region=function(_511){_511=_4.i18n.normalizeLocale(_511);var tags=_511.split("-");var _512=tags[1];if(!_512){_512={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(_512.length==4){_512=tags[2];}}return _512;};_4.cldr.supplemental.getWeekend=function(_513){var _514={"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 _515={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 _516=_4.cldr.supplemental._region(_513);var _517=_514[_516];var end=_515[_516];if(_517===undefined){_517=6;}if(end===undefined){end=0;}return {start:_517,end:end};};}if(!_4._hasResource["dojo.date"]){_4._hasResource["dojo.date"]=true;_4.provide("dojo.date");_4.getObject("date",true,_4);_4.date.getDaysInMonth=function(_518){var _519=_518.getMonth();var days=[31,28,31,30,31,30,31,31,30,31,30,31];if(_519==1&&_4.date.isLeapYear(_518)){return 29;}return days[_519];};_4.date.isLeapYear=function(_51a){var year=_51a.getFullYear();return !(year%400)||(!(year%4)&&!!(year%100));};_4.date.getTimezoneName=function(_51b){var str=_51b.toString();var tz="";var _51c;var pos=str.indexOf("(");if(pos>-1){tz=str.substring(++pos,str.indexOf(")"));}else{var pat=/([A-Z\/]+) \d{4}$/;if((_51c=str.match(pat))){tz=_51c[1];}else{str=_51b.toLocaleString();pat=/ ([A-Z\/]+)$/;if((_51c=str.match(pat))){tz=_51c[1];}}}return (tz=="AM"||tz=="PM")?"":tz;};_4.date.compare=function(_51d,_51e,_51f){_51d=new Date(+_51d);_51e=new Date(+(_51e||new Date()));if(_51f=="date"){_51d.setHours(0,0,0,0);_51e.setHours(0,0,0,0);}else{if(_51f=="time"){_51d.setFullYear(0,0,0);_51e.setFullYear(0,0,0);}}if(_51d>_51e){return 1;}if(_51d<_51e){return -1;}return 0;};_4.date.add=function(date,_520,_521){var sum=new Date(+date);var _522=false;var _523="Date";switch(_520){case "day":break;case "weekday":var days,_524;var mod=_521%5;if(!mod){days=(_521>0)?5:-5;_524=(_521>0)?((_521-5)/5):((_521+5)/5);}else{days=mod;_524=parseInt(_521/5);}var strt=date.getDay();var adj=0;if(strt==6&&_521>0){adj=1;}else{if(strt==0&&_521<0){adj=-1;}}var trgt=strt+days;if(trgt==0||trgt==6){adj=(_521>0)?2:-2;}_521=(7*_524)+days+adj;break;case "year":_523="FullYear";_522=true;break;case "week":_521*=7;break;case "quarter":_521*=3;case "month":_522=true;_523="Month";break;default:_523="UTC"+_520.charAt(0).toUpperCase()+_520.substring(1)+"s";}if(_523){sum["set"+_523](sum["get"+_523]()+_521);}if(_522&&(sum.getDate()<date.getDate())){sum.setDate(0);}return sum;};_4.date.difference=function(_525,_526,_527){_526=_526||new Date();_527=_527||"day";var _528=_526.getFullYear()-_525.getFullYear();var _529=1;switch(_527){case "quarter":var m1=_525.getMonth();var m2=_526.getMonth();var q1=Math.floor(m1/3)+1;var q2=Math.floor(m2/3)+1;q2+=(_528*4);_529=q2-q1;break;case "weekday":var days=Math.round(_4.date.difference(_525,_526,"day"));var _52a=parseInt(_4.date.difference(_525,_526,"week"));var mod=days%7;if(mod==0){days=_52a*5;}else{var adj=0;var aDay=_525.getDay();var bDay=_526.getDay();_52a=parseInt(days/7);mod=days%7;var _52b=new Date(_525);_52b.setDate(_52b.getDate()+(_52a*7));var _52c=_52b.getDay();if(days>0){switch(true){case aDay==6:adj=-1;break;case aDay==0:adj=0;break;case bDay==6:adj=-1;break;case bDay==0:adj=-2;break;case (_52c+mod)>5:adj=-2;}}else{if(days<0){switch(true){case aDay==6:adj=0;break;case aDay==0:adj=1;break;case bDay==6:adj=2;break;case bDay==0:adj=1;break;case (_52c+mod)<0:adj=2;}}}days+=adj;days-=(_52a*2);}_529=days;break;case "year":_529=_528;break;case "month":_529=(_526.getMonth()-_525.getMonth())+(_528*12);break;case "week":_529=parseInt(_4.date.difference(_525,_526,"day")/7);break;case "day":_529/=24;case "hour":_529/=60;case "minute":_529/=60;case "second":_529/=1000;case "millisecond":_529*=_526.getTime()-_525.getTime();}return Math.round(_529);};}if(!_4._hasResource["dojo.date.locale"]){_4._hasResource["dojo.date.locale"]=true;_4.provide("dojo.date.locale");_4.getObject("date.locale",true,_4);(function(){function _52d(_52e,_52f,_530,_531){return _531.replace(/([a-z])\1*/ig,function(_532){var s,pad,c=_532.charAt(0),l=_532.length,_533=["abbr","wide","narrow"];switch(c){case "G":s=_52f[(l<4)?"eraAbbr":"eraNames"][_52e.getFullYear()<0?0:1];break;case "y":s=_52e.getFullYear();switch(l){case 1:break;case 2:if(!_530.fullYear){s=String(s);s=s.substr(s.length-2);break;}default:pad=true;}break;case "Q":case "q":s=Math.ceil((_52e.getMonth()+1)/3);pad=true;break;case "M":var m=_52e.getMonth();if(l<3){s=m+1;pad=true;}else{var _534=["months","format",_533[l-3]].join("-");s=_52f[_534][m];}break;case "w":var _535=0;s=_4.date.locale._getWeekOfYear(_52e,_535);pad=true;break;case "d":s=_52e.getDate();pad=true;break;case "D":s=_4.date.locale._getDayOfYear(_52e);pad=true;break;case "E":var d=_52e.getDay();if(l<3){s=d+1;pad=true;}else{var _536=["days","format",_533[l-3]].join("-");s=_52f[_536][d];}break;case "a":var _537=(_52e.getHours()<12)?"am":"pm";s=_530[_537]||_52f["dayPeriods-format-wide-"+_537];break;case "h":case "H":case "K":case "k":var h=_52e.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;}pad=true;break;case "m":s=_52e.getMinutes();pad=true;break;case "s":s=_52e.getSeconds();pad=true;break;case "S":s=Math.round(_52e.getMilliseconds()*Math.pow(10,l-3));pad=true;break;case "v":case "z":s=_4.date.locale._getZone(_52e,true,_530);if(s){break;}l=4;case "Z":var _538=_4.date.locale._getZone(_52e,false,_530);var tz=[(_538<=0?"+":"-"),_4.string.pad(Math.floor(Math.abs(_538)/60),2),_4.string.pad(Math.abs(_538)%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: "+_531);}if(pad){s=_4.string.pad(s,l);}return s;});};_4.date.locale._getZone=function(_539,_53a,_53b){if(_53a){return _4.date.getTimezoneName(_539);}else{return _539.getTimezoneOffset();}};_4.date.locale.format=function(_53c,_53d){_53d=_53d||{};var _53e=_4.i18n.normalizeLocale(_53d.locale),_53f=_53d.formatLength||"short",_540=_4.date.locale._getGregorianBundle(_53e),str=[],_541=_4.hitch(this,_52d,_53c,_540,_53d);if(_53d.selector=="year"){return _542(_540["dateFormatItem-yyyy"]||"yyyy",_541);}var _543;if(_53d.selector!="date"){_543=_53d.timePattern||_540["timeFormat-"+_53f];if(_543){str.push(_542(_543,_541));}}if(_53d.selector!="time"){_543=_53d.datePattern||_540["dateFormat-"+_53f];if(_543){str.push(_542(_543,_541));}}return str.length==1?str[0]:_540["dateTimeFormat-"+_53f].replace(/\{(\d+)\}/g,function(_544,key){return str[key];});};_4.date.locale.regexp=function(_545){return _4.date.locale._parseInfo(_545).regexp;};_4.date.locale._parseInfo=function(_546){_546=_546||{};var _547=_4.i18n.normalizeLocale(_546.locale),_548=_4.date.locale._getGregorianBundle(_547),_549=_546.formatLength||"short",_54a=_546.datePattern||_548["dateFormat-"+_549],_54b=_546.timePattern||_548["timeFormat-"+_549],_54c;if(_546.selector=="date"){_54c=_54a;}else{if(_546.selector=="time"){_54c=_54b;}else{_54c=_548["dateTimeFormat-"+_549].replace(/\{(\d+)\}/g,function(_54d,key){return [_54b,_54a][key];});}}var _54e=[],re=_542(_54c,_4.hitch(this,_54f,_54e,_548,_546));return {regexp:re,tokens:_54e,bundle:_548};};_4.date.locale.parse=function(_550,_551){var _552=/[\u200E\u200F\u202A\u202E]/g,info=_4.date.locale._parseInfo(_551),_553=info.tokens,_554=info.bundle,re=new RegExp("^"+info.regexp.replace(_552,"")+"$",info.strict?"":"i"),_555=re.exec(_550&&_550.replace(_552,""));if(!_555){return null;}var _556=["abbr","wide","narrow"],_557=[1970,0,1,0,0,0,0],amPm="",_558=_4.every(_555,function(v,i){if(!i){return true;}var _559=_553[i-1];var l=_559.length;switch(_559.charAt(0)){case "y":if(l!=2&&_551.strict){_557[0]=v;}else{if(v<100){v=Number(v);var year=""+new Date().getFullYear(),_55a=year.substring(0,2)*100,_55b=Math.min(Number(year.substring(2,4))+20,99),num=(v<_55b)?_55a+v:_55a-100+v;_557[0]=num;}else{if(_551.strict){return false;}_557[0]=v;}}break;case "M":if(l>2){var _55c=_554["months-format-"+_556[l-3]].concat();if(!_551.strict){v=v.replace(".","").toLowerCase();_55c=_4.map(_55c,function(s){return s.replace(".","").toLowerCase();});}v=_4.indexOf(_55c,v);if(v==-1){return false;}}else{v--;}_557[1]=v;break;case "E":case "e":var days=_554["days-format-"+_556[l-3]].concat();if(!_551.strict){v=v.toLowerCase();days=_4.map(days,function(d){return d.toLowerCase();});}v=_4.indexOf(days,v);if(v==-1){return false;}break;case "D":_557[1]=0;case "d":_557[2]=v;break;case "a":var am=_551.am||_554["dayPeriods-format-wide-am"],pm=_551.pm||_554["dayPeriods-format-wide-pm"];if(!_551.strict){var _55d=/\./g;v=v.replace(_55d,"").toLowerCase();am=am.replace(_55d,"").toLowerCase();pm=pm.replace(_55d,"").toLowerCase();}if(_551.strict&&v!=am&&v!=pm){return false;}amPm=(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;}_557[3]=v;break;case "m":_557[4]=v;break;case "s":_557[5]=v;break;case "S":_557[6]=v;}return true;});var _55e=+_557[3];if(amPm==="p"&&_55e<12){_557[3]=_55e+12;}else{if(amPm==="a"&&_55e==12){_557[3]=0;}}var _55f=new Date(_557[0],_557[1],_557[2],_557[3],_557[4],_557[5],_557[6]);if(_551.strict){_55f.setFullYear(_557[0]);}var _560=_553.join(""),_561=_560.indexOf("d")!=-1,_562=_560.indexOf("M")!=-1;if(!_558||(_562&&_55f.getMonth()>_557[1])||(_561&&_55f.getDate()>_557[2])){return null;}if((_562&&_55f.getMonth()<_557[1])||(_561&&_55f.getDate()<_557[2])){_55f=_4.date.add(_55f,"hour",1);}return _55f;};function _542(_563,_564,_565,_566){var _567=function(x){return x;};_564=_564||_567;_565=_565||_567;_566=_566||_567;var _568=_563.match(/(''|[^'])+/g),_569=_563.charAt(0)=="'";_4.forEach(_568,function(_56a,i){if(!_56a){_568[i]="";}else{_568[i]=(_569?_565:_564)(_56a.replace(/''/g,"'"));_569=!_569;}});return _566(_568.join(""));};function _54f(_56b,_56c,_56d,_56e){_56e=_4.regexp.escapeString(_56e);if(!_56d.strict){_56e=_56e.replace(" a"," ?a");}return _56e.replace(/([a-z])\1*/ig,function(_56f){var s,c=_56f.charAt(0),l=_56f.length,p2="",p3="";if(_56d.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=_56d.am||_56c["dayPeriods-format-wide-am"],pm=_56d.pm||_56c["dayPeriods-format-wide-pm"];if(_56d.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=".*";}if(_56b){_56b.push(_56f);}return "("+s+")";}).replace(/[\xa0 ]/g,"[\\s\\xa0]");};})();(function(){var _570=[];_4.date.locale.addCustomFormats=function(_571,_572){_570.push({pkg:_571,name:_572});};_4.date.locale._getGregorianBundle=function(_573){var _574={};_4.forEach(_570,function(desc){var _575=_4.i18n.getLocalization(desc.pkg,desc.name,_573);_574=_4.mixin(_574,_575);},this);return _574;};})();_4.date.locale.addCustomFormats("dojo.cldr","gregorian");_4.date.locale.getNames=function(item,type,_576,_577){var _578,_579=_4.date.locale._getGregorianBundle(_577),_57a=[item,_576,type];if(_576=="standAlone"){var key=_57a.join("-");_578=_579[key];if(_578[0]==1){_578=undefined;}}_57a[1]="format";return (_578||_579[_57a.join("-")]).concat();};_4.date.locale.isWeekend=function(_57b,_57c){var _57d=_4.cldr.supplemental.getWeekend(_57c),day=(_57b||new Date()).getDay();if(_57d.end<_57d.start){_57d.end+=7;if(day<_57d.start){day+=7;}}return day>=_57d.start&&day<=_57d.end;};_4.date.locale._getDayOfYear=function(_57e){return _4.date.difference(new Date(_57e.getFullYear(),0,1,_57e.getHours()),_57e)+1;};_4.date.locale._getWeekOfYear=function(_57f,_580){if(arguments.length==1){_580=0;}var _581=new Date(_57f.getFullYear(),0,1).getDay(),adj=(_581-_580+7)%7,week=Math.floor((_4.date.locale._getDayOfYear(_57f)+adj-1)/7);if(_581==_580){week++;}return week;};}if(!_4._hasResource["dijit.Calendar"]){_4._hasResource["dijit.Calendar"]=true;_4.provide("dijit.Calendar");_4.declare("dijit.Calendar",[_5._Widget,_5._Templated,_5._CssStateMixin],{templateString:_4.cache("dijit","templates/Calendar.html","<table cellspacing=\"0\" cellpadding=\"0\" class=\"dijitCalendarContainer\" role=\"grid\" dojoAttachEvent=\"onkeypress: _onKeyPress\" aria-labelledby=\"${id}_year\">\r\n\t<thead>\r\n\t\t<tr class=\"dijitReset dijitCalendarMonthContainer\" valign=\"top\">\r\n\t\t\t<th class='dijitReset dijitCalendarArrow' dojoAttachPoint=\"decrementMonth\">\r\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarDecrease\" role=\"presentation\"/>\r\n\t\t\t\t<span dojoAttachPoint=\"decreaseArrowNode\" class=\"dijitA11ySideArrow\">-</span>\r\n\t\t\t</th>\r\n\t\t\t<th class='dijitReset' colspan=\"5\">\r\n\t\t\t\t<div dojoType=\"dijit.form.DropDownButton\" dojoAttachPoint=\"monthDropDownButton\"\r\n\t\t\t\t\tid=\"${id}_mddb\" tabIndex=\"-1\">\r\n\t\t\t\t</div>\r\n\t\t\t</th>\r\n\t\t\t<th class='dijitReset dijitCalendarArrow' dojoAttachPoint=\"incrementMonth\">\r\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarIncrease\" role=\"presentation\"/>\r\n\t\t\t\t<span dojoAttachPoint=\"increaseArrowNode\" class=\"dijitA11ySideArrow\">+</span>\r\n\t\t\t</th>\r\n\t\t</tr>\r\n\t\t<tr>\r\n\t\t\t<th class=\"dijitReset dijitCalendarDayLabelTemplate\" role=\"columnheader\"><span class=\"dijitCalendarDayLabel\"></span></th>\r\n\t\t</tr>\r\n\t</thead>\r\n\t<tbody dojoAttachEvent=\"onclick: _onDayClick, onmouseover: _onDayMouseOver, onmouseout: _onDayMouseOut, onmousedown: _onDayMouseDown, onmouseup: _onDayMouseUp\" class=\"dijitReset dijitCalendarBodyContainer\">\r\n\t\t<tr class=\"dijitReset dijitCalendarWeekTemplate\" role=\"row\">\r\n\t\t\t<td class=\"dijitReset dijitCalendarDateTemplate\" role=\"gridcell\"><span class=\"dijitCalendarDateLabel\"></span></td>\r\n\t\t</tr>\r\n\t</tbody>\r\n\t<tfoot class=\"dijitReset dijitCalendarYearContainer\">\r\n\t\t<tr>\r\n\t\t\t<td class='dijitReset' valign=\"top\" colspan=\"7\">\r\n\t\t\t\t<h3 class=\"dijitCalendarYearLabel\">\r\n\t\t\t\t\t<span dojoAttachPoint=\"previousYearLabelNode\" class=\"dijitInline dijitCalendarPreviousYear\"></span>\r\n\t\t\t\t\t<span dojoAttachPoint=\"currentYearLabelNode\" class=\"dijitInline dijitCalendarSelectedYear\" id=\"${id}_year\"></span>\r\n\t\t\t\t\t<span dojoAttachPoint=\"nextYearLabelNode\" class=\"dijitInline dijitCalendarNextYear\"></span>\r\n\t\t\t\t</h3>\r\n\t\t\t</td>\r\n\t\t</tr>\r\n\t</tfoot>\r\n</table>\r\n"),widgetsInTemplate:true,value:new Date(""),datePackage:"dojo.date",dayWidth:"narrow",tabIndex:"0",currentFocus:new Date(),baseClass:"dijitCalendar",cssStateNodes:{"decrementMonth":"dijitCalendarArrow","incrementMonth":"dijitCalendarArrow","previousYearLabelNode":"dijitCalendarPreviousYear","nextYearLabelNode":"dijitCalendarNextYear"},_isValidDate:function(_582){return _582&&!isNaN(_582)&&typeof _582=="object"&&_582.toString()!=this.constructor.prototype.value.toString();},setValue:function(_583){_4.deprecated("dijit.Calendar:setValue() is deprecated. Use set('value', ...) instead.","","2.0");this.set("value",_583);},_getValueAttr:function(){var _584=new this.dateClassObj(this.value);_584.setHours(0,0,0,0);if(_584.getDate()<this.value.getDate()){_584=this.dateFuncObj.add(_584,"hour",1);}return _584;},_setValueAttr:function(_585,_586){if(_585){_585=new this.dateClassObj(_585);}if(this._isValidDate(_585)){if(!this._isValidDate(this.value)||this.dateFuncObj.compare(_585,this.value)){_585.setHours(1,0,0,0);if(!this.isDisabledDate(_585,this.lang)){this._set("value",_585);this.set("currentFocus",_585);if(_586||typeof _586=="undefined"){this.onChange(this.get("value"));this.onValueSelected(this.get("value"));}}}}else{this._set("value",null);this.set("currentFocus",this.currentFocus);}},_setText:function(node,text){while(node.firstChild){node.removeChild(node.firstChild);}node.appendChild(_4.doc.createTextNode(text));},_populateGrid:function(){var _587=new this.dateClassObj(this.currentFocus);_587.setDate(1);var _588=_587.getDay(),_589=this.dateFuncObj.getDaysInMonth(_587),_58a=this.dateFuncObj.getDaysInMonth(this.dateFuncObj.add(_587,"month",-1)),_58b=new this.dateClassObj(),_58c=_4.cldr.supplemental.getFirstDayOfWeek(this.lang);if(_58c>_588){_58c-=7;}_4.query(".dijitCalendarDateTemplate",this.domNode).forEach(function(_58d,i){i+=_58c;var date=new this.dateClassObj(_587),_58e,_58f="dijitCalendar",adj=0;if(i<_588){_58e=_58a-_588+i+1;adj=-1;_58f+="Previous";}else{if(i>=(_588+_589)){_58e=i-_588-_589+1;adj=1;_58f+="Next";}else{_58e=i-_588+1;_58f+="Current";}}if(adj){date=this.dateFuncObj.add(date,"month",adj);}date.setDate(_58e);if(!this.dateFuncObj.compare(date,_58b,"date")){_58f="dijitCalendarCurrentDate "+_58f;}if(this._isSelectedDate(date,this.lang)){_58f="dijitCalendarSelectedDate "+_58f;}if(this.isDisabledDate(date,this.lang)){_58f="dijitCalendarDisabledDate "+_58f;}var _590=this.getClassForDate(date,this.lang);if(_590){_58f=_590+" "+_58f;}_58d.className=_58f+"Month dijitCalendarDateTemplate";_58d.dijitDateValue=date.valueOf();_4.attr(_58d,"dijitDateValue",date.valueOf());var _591=_4.query(".dijitCalendarDateLabel",_58d)[0],text=date.getDateLocalized?date.getDateLocalized(this.lang):date.getDate();this._setText(_591,text);},this);var _592=this.dateLocaleModule.getNames("months","wide","standAlone",this.lang,_587);this.monthDropDownButton.dropDown.set("months",_592);this.monthDropDownButton.containerNode.innerHTML=(_4.isIE==6?"":"<div class='dijitSpacer'>"+this.monthDropDownButton.dropDown.domNode.innerHTML+"</div>")+"<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>"+_592[_587.getMonth()]+"</div>";var y=_587.getFullYear()-1;var d=new this.dateClassObj();_4.forEach(["previous","current","next"],function(name){d.setFullYear(y++);this._setText(this[name+"YearLabelNode"],this.dateLocaleModule.format(d,{selector:"year",locale:this.lang}));},this);},goToToday:function(){this.set("value",new this.dateClassObj());},constructor:function(args){var _593=(args.datePackage&&(args.datePackage!="dojo.date"))?args.datePackage+".Date":"Date";this.dateClassObj=_4.getObject(_593,false);this.datePackage=args.datePackage||this.datePackage;this.dateFuncObj=_4.getObject(this.datePackage,false);this.dateLocaleModule=_4.getObject(this.datePackage+".locale",false);},postMixInProperties:function(){if(isNaN(this.value)){delete this.value;}this.inherited(arguments);},buildRendering:function(){this.inherited(arguments);_4.setSelectable(this.domNode,false);var _594=_4.hitch(this,function(_595,n){var _596=_4.query(_595,this.domNode)[0];for(var i=0;i<n;i++){_596.parentNode.appendChild(_596.cloneNode(true));}});_594(".dijitCalendarDayLabelTemplate",6);_594(".dijitCalendarDateTemplate",6);_594(".dijitCalendarWeekTemplate",5);var _597=this.dateLocaleModule.getNames("days",this.dayWidth,"standAlone",this.lang);var _598=_4.cldr.supplemental.getFirstDayOfWeek(this.lang);_4.query(".dijitCalendarDayLabel",this.domNode).forEach(function(_599,i){this._setText(_599,_597[(i+_598)%7]);},this);var _59a=new this.dateClassObj(this.currentFocus);this.monthDropDownButton.dropDown=new _5.Calendar._MonthDropDown({id:this.id+"_mdd",onChange:_4.hitch(this,"_onMonthSelect")});this.set("currentFocus",_59a,false);var _59b=this;var _59c=function(_59d,_59e,adj){_59b._connects.push(_5.typematic.addMouseListener(_59b[_59d],_59b,function(_59f){if(_59f>=0){_59b._adjustDisplay(_59e,adj);}},0.8,500));};_59c("incrementMonth","month",1);_59c("decrementMonth","month",-1);_59c("nextYearLabelNode","year",1);_59c("previousYearLabelNode","year",-1);},_adjustDisplay:function(part,_5a0){this._setCurrentFocusAttr(this.dateFuncObj.add(this.currentFocus,part,_5a0));},_setCurrentFocusAttr:function(date,_5a1){var _5a2=this.currentFocus,_5a3=_5a2?_4.query("[dijitDateValue="+_5a2.valueOf()+"]",this.domNode)[0]:null;date=new this.dateClassObj(date);date.setHours(1,0,0,0);this._set("currentFocus",date);this._populateGrid();var _5a4=_4.query("[dijitDateValue="+date.valueOf()+"]",this.domNode)[0];_5a4.setAttribute("tabIndex",this.tabIndex);if(this._focused||_5a1){_5a4.focus();}if(_5a3&&_5a3!=_5a4){if(_4.isWebKit){_5a3.setAttribute("tabIndex","-1");}else{_5a3.removeAttribute("tabIndex");}}},focus:function(){this._setCurrentFocusAttr(this.currentFocus,true);},_onMonthSelect:function(_5a5){this.currentFocus=this.dateFuncObj.add(this.currentFocus,"month",_5a5-this.currentFocus.getMonth());this._populateGrid();},_onDayClick:function(evt){_4.stopEvent(evt);for(var node=evt.target;node&&!node.dijitDateValue;node=node.parentNode){}if(node&&!_4.hasClass(node,"dijitCalendarDisabledDate")){this.set("value",node.dijitDateValue);}},_onDayMouseOver:function(evt){var node=_4.hasClass(evt.target,"dijitCalendarDateLabel")?evt.target.parentNode:evt.target;if(node&&(node.dijitDateValue||node==this.previousYearLabelNode||node==this.nextYearLabelNode)){_4.addClass(node,"dijitCalendarHoveredDate");this._currentNode=node;}},_onDayMouseOut:function(evt){if(!this._currentNode){return;}if(evt.relatedTarget&&evt.relatedTarget.parentNode==this._currentNode){return;}var cls="dijitCalendarHoveredDate";if(_4.hasClass(this._currentNode,"dijitCalendarActiveDate")){cls+=" dijitCalendarActiveDate";}_4.removeClass(this._currentNode,cls);this._currentNode=null;},_onDayMouseDown:function(evt){var node=evt.target.parentNode;if(node&&node.dijitDateValue){_4.addClass(node,"dijitCalendarActiveDate");this._currentNode=node;}},_onDayMouseUp:function(evt){var node=evt.target.parentNode;if(node&&node.dijitDateValue){_4.removeClass(node,"dijitCalendarActiveDate");}},handleKey:function(evt){var dk=_4.keys,_5a6=-1,_5a7,_5a8=this.currentFocus;switch(evt.keyCode){case dk.RIGHT_ARROW:_5a6=1;case dk.LEFT_ARROW:_5a7="day";if(!this.isLeftToRight()){_5a6*=-1;}break;case dk.DOWN_ARROW:_5a6=1;case dk.UP_ARROW:_5a7="week";break;case dk.PAGE_DOWN:_5a6=1;case dk.PAGE_UP:_5a7=evt.ctrlKey||evt.altKey?"year":"month";break;case dk.END:_5a8=this.dateFuncObj.add(_5a8,"month",1);_5a7="day";case dk.HOME:_5a8=new this.dateClassObj(_5a8);_5a8.setDate(1);break;case dk.ENTER:case dk.SPACE:this.set("value",this.currentFocus);break;default:return true;}if(_5a7){_5a8=this.dateFuncObj.add(_5a8,_5a7,_5a6);}this._setCurrentFocusAttr(_5a8);return false;},_onKeyPress:function(evt){if(!this.handleKey(evt)){_4.stopEvent(evt);}},onValueSelected:function(date){},onChange:function(date){},_isSelectedDate:function(_5a9,_5aa){return this._isValidDate(this.value)&&!this.dateFuncObj.compare(_5a9,this.value,"date");},isDisabledDate:function(_5ab,_5ac){},getClassForDate:function(_5ad,_5ae){}});_4.declare("dijit.Calendar._MonthDropDown",[_5._Widget,_5._Templated],{months:[],templateString:"<div class='dijitCalendarMonthMenu dijitMenu' "+"dojoAttachEvent='onclick:_onClick,onmouseover:_onMenuHover,onmouseout:_onMenuHover'></div>",_setMonthsAttr:function(_5af){this.domNode.innerHTML=_4.map(_5af,function(_5b0,idx){return _5b0?"<div class='dijitCalendarMonthLabel' month='"+idx+"'>"+_5b0+"</div>":"";}).join("");},_onClick:function(evt){this.onChange(_4.attr(evt.target,"month"));},onChange:function(_5b1){},_onMenuHover:function(evt){_4.toggleClass(evt.target,"dijitCalendarMonthLabelHover",evt.type=="mouseover");}});}if(!_4._hasResource["dijit.form._DateTimeTextBox"]){_4._hasResource["dijit.form._DateTimeTextBox"]=true;_4.provide("dijit.form._DateTimeTextBox");new Date("X");_4.declare("dijit.form._DateTimeTextBox",[_5.form.RangeBoundTextBox,_5._HasDropDown],{templateString:_4.cache("dijit.form","templates/DropDownBox.html","<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\r\n\tid=\"widget_${id}\"\r\n\trole=\"combobox\"\r\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\r\n\t\tdojoAttachPoint=\"_buttonNode, _popupStateNode\" role=\"presentation\"\r\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t${_buttonInputDisabled}\r\n\t/></div\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\r\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\r\n\t/></div\r\n></div>\r\n"),hasDownArrow:true,openOnClick:true,regExpGen:_4.date.locale.regexp,datePackage:"dojo.date",compare:function(val1,val2){return _4.date.compare(val1,val2,this._selector);},forceWidth:true,format:function(_5b2,_5b3){if(!_5b2){return "";}return this.dateLocaleModule.format(_5b2,_5b3);},"parse":function(_5b4,_5b5){return this.dateLocaleModule.parse(_5b4,_5b5)||(this._isEmpty(_5b4)?null:undefined);},serialize:function(val,_5b6){if(val.toGregorian){val=val.toGregorian();}return _4.date.stamp.toISOString(val,_5b6);},dropDownDefaultValue:new Date(),value:new Date(""),_blankValue:null,popupClass:"",_selector:"",constructor:function(args){var _5b7=args.datePackage?args.datePackage+".Date":"Date";this.dateClassObj=_4.getObject(_5b7,false);this.value=new this.dateClassObj("");this.datePackage=args.datePackage||this.datePackage;this.dateLocaleModule=_4.getObject(this.datePackage+".locale",false);this.regExpGen=this.dateLocaleModule.regexp;this._invalidDate=_5.form._DateTimeTextBox.prototype.value.toString();},buildRendering:function(){this.inherited(arguments);if(!this.hasDownArrow){this._buttonNode.style.display="none";}if(this.openOnClick||!this.hasDownArrow){this._buttonNode=this.domNode;this.baseClass+=" dijitComboBoxOpenOnClick";}},_setConstraintsAttr:function(_5b8){_5b8.selector=this._selector;_5b8.fullYear=true;var _5b9=_4.date.stamp.fromISOString;if(typeof _5b8.min=="string"){_5b8.min=_5b9(_5b8.min);}if(typeof _5b8.max=="string"){_5b8.max=_5b9(_5b8.max);}this.inherited(arguments,[_5b8]);},_isInvalidDate:function(_5ba){return !_5ba||isNaN(_5ba)||typeof _5ba!="object"||_5ba.toString()==this._invalidDate;},_setValueAttr:function(_5bb,_5bc,_5bd){if(_5bb!==undefined){if(typeof _5bb=="string"){_5bb=_4.date.stamp.fromISOString(_5bb);}if(this._isInvalidDate(_5bb)){_5bb=null;}if(_5bb instanceof Date&&!(this.dateClassObj instanceof Date)){_5bb=new this.dateClassObj(_5bb);}}this.inherited(arguments,[_5bb,_5bc,_5bd]);if(this.dropDown){this.dropDown.set("value",_5bb,false);}},_set:function(attr,_5be){if(attr=="value"&&this.value instanceof Date&&((this._isInvalidDate(this.value)&&this._isInvalidDate(_5be))||this.compare(_5be,this.value)==0)){return;}this.inherited(arguments);},_setDropDownDefaultValueAttr:function(val){if(this._isInvalidDate(val)){val=new this.dateClassObj();}this.dropDownDefaultValue=val;},openDropDown:function(_5bf){if(this.dropDown){this.dropDown.destroy();}var _5c0=_4.getObject(this.popupClass,false),_5c1=this,_5c2=this.get("value");this.dropDown=new _5c0({onChange:function(_5c3){_5.form._DateTimeTextBox.superclass._setValueAttr.call(_5c1,_5c3,true);},id:this.id+"_popup",dir:_5c1.dir,lang:_5c1.lang,value:_5c2,currentFocus:!this._isInvalidDate(_5c2)?_5c2:this.dropDownDefaultValue,constraints:_5c1.constraints,filterString:_5c1.filterString,datePackage:_5c1.datePackage,isDisabledDate:function(date){return !_5c1.rangeCheck(date,_5c1.constraints);}});this.inherited(arguments);},_getDisplayedValueAttr:function(){return this.textbox.value;},_setDisplayedValueAttr:function(_5c4,_5c5){this._setValueAttr(this.parse(_5c4,this.constraints),_5c5,_5c4);}});}if(!_4._hasResource["dijit.form.DateTextBox"]){_4._hasResource["dijit.form.DateTextBox"]=true;_4.provide("dijit.form.DateTextBox");_4.declare("dijit.form.DateTextBox",_5.form._DateTimeTextBox,{baseClass:"dijitTextBox dijitComboBox dijitDateTextBox",popupClass:"dijit.Calendar",_selector:"date",value:new Date("")});}if(!_4._hasResource["dijit.form._Spinner"]){_4._hasResource["dijit.form._Spinner"]=true;_4.provide("dijit.form._Spinner");_4.declare("dijit.form._Spinner",_5.form.RangeBoundTextBox,{defaultTimeout:500,minimumTimeout:10,timeoutChangeRate:0.9,smallDelta:1,largeDelta:10,templateString:_4.cache("dijit.form","templates/Spinner.html","<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\r\n\tid=\"widget_${id}\" role=\"presentation\"\r\n\t><div class=\"dijitReset dijitButtonNode dijitSpinnerButtonContainer\"\r\n\t\t><input class=\"dijitReset dijitInputField dijitSpinnerButtonInner\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t/><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitUpArrowButton\"\r\n\t\t\tdojoAttachPoint=\"upArrowNode\"\r\n\t\t\t><div class=\"dijitArrowButtonInner\"\r\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9650;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t\t\t${_buttonInputDisabled}\r\n\t\t\t/></div\r\n\t\t></div\r\n\t\t><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitDownArrowButton\"\r\n\t\t\tdojoAttachPoint=\"downArrowNode\"\r\n\t\t\t><div class=\"dijitArrowButtonInner\"\r\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9660;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t\t\t${_buttonInputDisabled}\r\n\t\t\t/></div\r\n\t\t></div\r\n\t></div\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class='dijitReset dijitInputInner' dojoAttachPoint=\"textbox,focusNode\" type=\"${type}\" dojoAttachEvent=\"onkeypress:_onKeyPress\"\r\n\t\t\trole=\"spinbutton\" autocomplete=\"off\" ${!nameAttrSetting}\r\n\t/></div\r\n></div>\r\n"),baseClass:"dijitTextBox dijitSpinner",cssStateNodes:{"upArrowNode":"dijitUpArrowButton","downArrowNode":"dijitDownArrowButton"},adjust:function(val,_5c6){return val;},_arrowPressed:function(_5c7,_5c8,_5c9){if(this.disabled||this.readOnly){return;}this._setValueAttr(this.adjust(this.get("value"),_5c8*_5c9),false);_5.selectInputText(this.textbox,this.textbox.value.length);},_arrowReleased:function(node){this._wheelTimer=null;if(this.disabled||this.readOnly){return;}},_typematicCallback:function(_5ca,node,evt){var inc=this.smallDelta;if(node==this.textbox){var k=_4.keys;var key=evt.charOrCode;inc=(key==k.PAGE_UP||key==k.PAGE_DOWN)?this.largeDelta:this.smallDelta;node=(key==k.UP_ARROW||key==k.PAGE_UP)?this.upArrowNode:this.downArrowNode;}if(_5ca==-1){this._arrowReleased(node);}else{this._arrowPressed(node,(node==this.upArrowNode)?1:-1,inc);}},_wheelTimer:null,_mouseWheeled:function(evt){_4.stopEvent(evt);var _5cb=evt.detail?(evt.detail*-1):(evt.wheelDelta/120);if(_5cb!==0){var node=this[(_5cb>0?"upArrowNode":"downArrowNode")];this._arrowPressed(node,_5cb,this.smallDelta);if(!this._wheelTimer){clearTimeout(this._wheelTimer);}this._wheelTimer=setTimeout(_4.hitch(this,"_arrowReleased",node),50);}},postCreate:function(){this.inherited(arguments);this.connect(this.domNode,!_4.isMozilla?"onmousewheel":"DOMMouseScroll","_mouseWheeled");this._connects.push(_5.typematic.addListener(this.upArrowNode,this.textbox,{charOrCode:_4.keys.UP_ARROW,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false},this,"_typematicCallback",this.timeoutChangeRate,this.defaultTimeout,this.minimumTimeout));this._connects.push(_5.typematic.addListener(this.downArrowNode,this.textbox,{charOrCode:_4.keys.DOWN_ARROW,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false},this,"_typematicCallback",this.timeoutChangeRate,this.defaultTimeout,this.minimumTimeout));this._connects.push(_5.typematic.addListener(this.upArrowNode,this.textbox,{charOrCode:_4.keys.PAGE_UP,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false},this,"_typematicCallback",this.timeoutChangeRate,this.defaultTimeout,this.minimumTimeout));this._connects.push(_5.typematic.addListener(this.downArrowNode,this.textbox,{charOrCode:_4.keys.PAGE_DOWN,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false},this,"_typematicCallback",this.timeoutChangeRate,this.defaultTimeout,this.minimumTimeout));}});}if(!_4._hasResource["dijit.form.NumberSpinner"]){_4._hasResource["dijit.form.NumberSpinner"]=true;_4.provide("dijit.form.NumberSpinner");_4.declare("dijit.form.NumberSpinner",[_5.form._Spinner,_5.form.NumberTextBoxMixin],{adjust:function(val,_5cc){var tc=this.constraints,v=isNaN(val),_5cd=!isNaN(tc.max),_5ce=!isNaN(tc.min);if(v&&_5cc!=0){val=(_5cc>0)?_5ce?tc.min:_5cd?tc.max:0:_5cd?this.constraints.max:_5ce?tc.min:0;}var _5cf=val+_5cc;if(v||isNaN(_5cf)){return val;}if(_5cd&&(_5cf>tc.max)){_5cf=tc.max;}if(_5ce&&(_5cf<tc.min)){_5cf=tc.min;}return _5cf;},_onKeyPress:function(e){if((e.charOrCode==_4.keys.HOME||e.charOrCode==_4.keys.END)&&!(e.ctrlKey||e.altKey||e.metaKey)&&typeof this.get("value")!="undefined"){var _5d0=this.constraints[(e.charOrCode==_4.keys.HOME?"min":"max")];if(typeof _5d0=="number"){this._setValueAttr(_5d0,false);}_4.stopEvent(e);}}});}if(!_4._hasResource["dijit.form.MultiSelect"]){_4._hasResource["dijit.form.MultiSelect"]=true;_4.provide("dijit.form.MultiSelect");_4.declare("dijit.form.MultiSelect",_5.form._FormValueWidget,{size:7,templateString:"<select multiple='true' ${!nameAttrSetting} dojoAttachPoint='containerNode,focusNode' dojoAttachEvent='onchange: _onChange'></select>",attributeMap:_4.delegate(_5.form._FormWidget.prototype.attributeMap,{size:"focusNode"}),reset:function(){this._hasBeenBlurred=false;this._setValueAttr(this._resetValue,true);},addSelected:function(_5d1){_5d1.getSelected().forEach(function(n){this.containerNode.appendChild(n);this.domNode.scrollTop=this.domNode.offsetHeight;var _5d2=_5d1.domNode.scrollTop;_5d1.domNode.scrollTop=0;_5d1.domNode.scrollTop=_5d2;},this);},getSelected:function(){return _4.query("option",this.containerNode).filter(function(n){return n.selected;});},_getValueAttr:function(){return this.getSelected().map(function(n){return n.value;});},multiple:true,_setValueAttr:function(_5d3){_4.query("option",this.containerNode).forEach(function(n){n.selected=(_4.indexOf(_5d3,n.value)!=-1);});},invertSelection:function(_5d4){_4.query("option",this.containerNode).forEach(function(n){n.selected=!n.selected;});this._handleOnChange(this.get("value"),_5d4==true);},_onChange:function(e){this._handleOnChange(this.get("value"),true);},resize:function(size){if(size){_4.marginBox(this.domNode,size);}},postCreate:function(){this._onChange();}});}if(!_4._hasResource["dijit.form.HorizontalSlider"]){_4._hasResource["dijit.form.HorizontalSlider"]=true;_4.provide("dijit.form.HorizontalSlider");_4.declare("dijit.form.HorizontalSlider",[_5.form._FormValueWidget,_5._Container],{templateString:_4.cache("dijit.form","templates/HorizontalSlider.html","<table class=\"dijit dijitReset dijitSlider dijitSliderH\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\" dojoAttachEvent=\"onkeypress:_onKeyPress,onkeyup:_onKeyUp\"\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t\t><td dojoAttachPoint=\"topDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationT dijitSliderDecorationH\"></td\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\r\n\t\t\t><div class=\"dijitSliderDecrementIconH\" style=\"display:none\" dojoAttachPoint=\"decrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderLeftBumper\" dojoAttachEvent=\"onmousedown:_onClkDecBumper\"></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\r\n\t\t\t/><div class=\"dijitReset dijitSliderBarContainerH\" role=\"presentation\" dojoAttachPoint=\"sliderBarContainer\"\r\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH\" dojoAttachEvent=\"onmousedown:_onBarClick\"\r\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableH\"\r\n\t\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleH\" dojoAttachEvent=\"onmousedown:_onHandleClick\" role=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"></div\r\n\t\t\t\t\t></div\r\n\t\t\t\t></div\r\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderRemainingBar dijitSliderRemainingBarH\" dojoAttachEvent=\"onmousedown:_onBarClick\"></div\r\n\t\t\t></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderRightBumper\" dojoAttachEvent=\"onmousedown:_onClkIncBumper\"></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\r\n\t\t\t><div class=\"dijitSliderIncrementIconH\" style=\"display:none\" dojoAttachPoint=\"incrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\r\n\t\t></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t\t><td dojoAttachPoint=\"containerNode,bottomDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH\"></td\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t></tr\r\n></table>\r\n"),value:0,showButtons:true,minimum:0,maximum:100,discreteValues:Infinity,pageIncrement:2,clickSelect:true,slideDuration:_5.defaultDuration,widgetsInTemplate:true,attributeMap:_4.delegate(_5.form._FormWidget.prototype.attributeMap,{id:""}),baseClass:"dijitSlider",cssStateNodes:{incrementButton:"dijitSliderIncrementButton",decrementButton:"dijitSliderDecrementButton",focusNode:"dijitSliderThumb"},_mousePixelCoord:"pageX",_pixelCount:"w",_startingPixelCoord:"x",_startingPixelCount:"l",_handleOffsetCoord:"left",_progressPixelSize:"width",_onKeyUp:function(e){if(this.disabled||this.readOnly||e.altKey||e.ctrlKey||e.metaKey){return;}this._setValueAttr(this.value,true);},_onKeyPress:function(e){if(this.disabled||this.readOnly||e.altKey||e.ctrlKey||e.metaKey){return;}switch(e.charOrCode){case _4.keys.HOME:this._setValueAttr(this.minimum,false);break;case _4.keys.END:this._setValueAttr(this.maximum,false);break;case ((this._descending||this.isLeftToRight())?_4.keys.RIGHT_ARROW:_4.keys.LEFT_ARROW):case (this._descending===false?_4.keys.DOWN_ARROW:_4.keys.UP_ARROW):case (this._descending===false?_4.keys.PAGE_DOWN:_4.keys.PAGE_UP):this.increment(e);break;case ((this._descending||this.isLeftToRight())?_4.keys.LEFT_ARROW:_4.keys.RIGHT_ARROW):case (this._descending===false?_4.keys.UP_ARROW:_4.keys.DOWN_ARROW):case (this._descending===false?_4.keys.PAGE_UP:_4.keys.PAGE_DOWN):this.decrement(e);break;default:return;}_4.stopEvent(e);},_onHandleClick:function(e){if(this.disabled||this.readOnly){return;}if(!_4.isIE){_5.focus(this.sliderHandle);}_4.stopEvent(e);},_isReversed:function(){return !this.isLeftToRight();},_onBarClick:function(e){if(this.disabled||this.readOnly||!this.clickSelect){return;}_5.focus(this.sliderHandle);_4.stopEvent(e);var _5d5=_4.position(this.sliderBarContainer,true);var _5d6=e[this._mousePixelCoord]-_5d5[this._startingPixelCoord];this._setPixelValue(this._isReversed()?(_5d5[this._pixelCount]-_5d6):_5d6,_5d5[this._pixelCount],true);this._movable.onMouseDown(e);},_setPixelValue:function(_5d7,_5d8,_5d9){if(this.disabled||this.readOnly){return;}_5d7=_5d7<0?0:_5d8<_5d7?_5d8:_5d7;var _5da=this.discreteValues;if(_5da<=1||_5da==Infinity){_5da=_5d8;}_5da--;var _5db=_5d8/_5da;var _5dc=Math.round(_5d7/_5db);this._setValueAttr((this.maximum-this.minimum)*_5dc/_5da+this.minimum,_5d9);},_setValueAttr:function(_5dd,_5de){this._set("value",_5dd);this.valueNode.value=_5dd;_5.setWaiState(this.focusNode,"valuenow",_5dd);this.inherited(arguments);var _5df=(_5dd-this.minimum)/(this.maximum-this.minimum);var _5e0=(this._descending===false)?this.remainingBar:this.progressBar;var _5e1=(this._descending===false)?this.progressBar:this.remainingBar;if(this._inProgressAnim&&this._inProgressAnim.status!="stopped"){this._inProgressAnim.stop(true);}if(_5de&&this.slideDuration>0&&_5e0.style[this._progressPixelSize]){var _5e2=this;var _5e3={};var _5e4=parseFloat(_5e0.style[this._progressPixelSize]);var _5e5=this.slideDuration*(_5df-_5e4/100);if(_5e5==0){return;}if(_5e5<0){_5e5=0-_5e5;}_5e3[this._progressPixelSize]={start:_5e4,end:_5df*100,units:"%"};this._inProgressAnim=_4.animateProperty({node:_5e0,duration:_5e5,onAnimate:function(v){_5e1.style[_5e2._progressPixelSize]=(100-parseFloat(v[_5e2._progressPixelSize]))+"%";},onEnd:function(){delete _5e2._inProgressAnim;},properties:_5e3});this._inProgressAnim.play();}else{_5e0.style[this._progressPixelSize]=(_5df*100)+"%";_5e1.style[this._progressPixelSize]=((1-_5df)*100)+"%";}},_bumpValue:function(_5e6,_5e7){if(this.disabled||this.readOnly){return;}var s=_4.getComputedStyle(this.sliderBarContainer);var c=_4._getContentBox(this.sliderBarContainer,s);var _5e8=this.discreteValues;if(_5e8<=1||_5e8==Infinity){_5e8=c[this._pixelCount];}_5e8--;var _5e9=(this.value-this.minimum)*_5e8/(this.maximum-this.minimum)+_5e6;if(_5e9<0){_5e9=0;}if(_5e9>_5e8){_5e9=_5e8;}_5e9=_5e9*(this.maximum-this.minimum)/_5e8+this.minimum;this._setValueAttr(_5e9,_5e7);},_onClkBumper:function(val){if(this.disabled||this.readOnly||!this.clickSelect){return;}this._setValueAttr(val,true);},_onClkIncBumper:function(){this._onClkBumper(this._descending===false?this.minimum:this.maximum);},_onClkDecBumper:function(){this._onClkBumper(this._descending===false?this.maximum:this.minimum);},decrement:function(e){this._bumpValue(e.charOrCode==_4.keys.PAGE_DOWN?-this.pageIncrement:-1);},increment:function(e){this._bumpValue(e.charOrCode==_4.keys.PAGE_UP?this.pageIncrement:1);},_mouseWheeled:function(evt){_4.stopEvent(evt);var _5ea=!_4.isMozilla;var _5eb=evt[(_5ea?"wheelDelta":"detail")]*(_5ea?1:-1);this._bumpValue(_5eb<0?-1:1,true);},startup:function(){if(this._started){return;}_4.forEach(this.getChildren(),function(_5ec){if(this[_5ec.container]!=this.containerNode){this[_5ec.container].appendChild(_5ec.domNode);}},this);this.inherited(arguments);},_typematicCallback:function(_5ed,_5ee,e){if(_5ed==-1){this._setValueAttr(this.value,true);}else{this[(_5ee==(this._descending?this.incrementButton:this.decrementButton))?"decrement":"increment"](e);}},buildRendering:function(){this.inherited(arguments);if(this.showButtons){this.incrementButton.style.display="";this.decrementButton.style.display="";}var _5ef=_4.query("label[for=\""+this.id+"\"]");if(_5ef.length){_5ef[0].id=(this.id+"_label");_5.setWaiState(this.focusNode,"labelledby",_5ef[0].id);}_5.setWaiState(this.focusNode,"valuemin",this.minimum);_5.setWaiState(this.focusNode,"valuemax",this.maximum);},postCreate:function(){this.inherited(arguments);if(this.showButtons){this._connects.push(_5.typematic.addMouseListener(this.decrementButton,this,"_typematicCallback",25,500));this._connects.push(_5.typematic.addMouseListener(this.incrementButton,this,"_typematicCallback",25,500));}this.connect(this.domNode,!_4.isMozilla?"onmousewheel":"DOMMouseScroll","_mouseWheeled");var _5f0=_4.declare(_5.form._SliderMover,{widget:this});this._movable=new _4.dnd.Moveable(this.sliderHandle,{mover:_5f0});this._layoutHackIE7();},destroy:function(){this._movable.destroy();if(this._inProgressAnim&&this._inProgressAnim.status!="stopped"){this._inProgressAnim.stop(true);}this._supportingWidgets=_5.findWidgets(this.domNode);this.inherited(arguments);}});_4.declare("dijit.form._SliderMover",_4.dnd.Mover,{onMouseMove:function(e){var _5f1=this.widget;var _5f2=_5f1._abspos;if(!_5f2){_5f2=_5f1._abspos=_4.position(_5f1.sliderBarContainer,true);_5f1._setPixelValue_=_4.hitch(_5f1,"_setPixelValue");_5f1._isReversed_=_5f1._isReversed();}var _5f3=e.touches?e.touches[0]:e,_5f4=_5f3[_5f1._mousePixelCoord]-_5f2[_5f1._startingPixelCoord];_5f1._setPixelValue_(_5f1._isReversed_?(_5f2[_5f1._pixelCount]-_5f4):_5f4,_5f2[_5f1._pixelCount],false);},destroy:function(e){_4.dnd.Mover.prototype.destroy.apply(this,arguments);var _5f5=this.widget;_5f5._abspos=null;_5f5._setValueAttr(_5f5.value,true);}});}if(!_4._hasResource["dijit.form.VerticalSlider"]){_4._hasResource["dijit.form.VerticalSlider"]=true;_4.provide("dijit.form.VerticalSlider");_4.declare("dijit.form.VerticalSlider",_5.form.HorizontalSlider,{templateString:_4.cache("dijit.form","templates/VerticalSlider.html","<table class=\"dijit dijitReset dijitSlider dijitSliderV\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\" dojoAttachEvent=\"onkeypress:_onKeyPress,onkeyup:_onKeyUp\"\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\"></td\r\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\r\n\t\t\t><div class=\"dijitSliderIncrementIconV\" style=\"display:none\" dojoAttachPoint=\"decrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\"></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderTopBumper\" dojoAttachEvent=\"onmousedown:_onClkIncBumper\"></div></center\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td dojoAttachPoint=\"leftDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationL dijitSliderDecorationV\"></td\r\n\t\t><td class=\"dijitReset dijitSliderDecorationC\" style=\"height:100%;\"\r\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\r\n\t\t\t/><center class=\"dijitReset dijitSliderBarContainerV\" role=\"presentation\" dojoAttachPoint=\"sliderBarContainer\"\r\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderRemainingBar dijitSliderRemainingBarV\" dojoAttachEvent=\"onmousedown:_onBarClick\"><!--#5629--></div\r\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderProgressBar dijitSliderProgressBarV\" dojoAttachEvent=\"onmousedown:_onBarClick\"\r\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableV\" style=\"vertical-align:top;\"\r\n\t\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleV\" dojoAttachEvent=\"onmousedown:_onHandleClick\" role=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"></div\r\n\t\t\t\t\t></div\r\n\t\t\t\t></div\r\n\t\t\t></center\r\n\t\t></td\r\n\t\t><td dojoAttachPoint=\"containerNode,rightDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationR dijitSliderDecorationV\"></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\"></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderBottomBumper\" dojoAttachEvent=\"onmousedown:_onClkDecBumper\"></div></center\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\"></td\r\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\r\n\t\t\t><div class=\"dijitSliderDecrementIconV\" style=\"display:none\" dojoAttachPoint=\"incrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"></td\r\n\t></tr\r\n></table>\r\n"),_mousePixelCoord:"pageY",_pixelCount:"h",_startingPixelCoord:"y",_startingPixelCount:"t",_handleOffsetCoord:"top",_progressPixelSize:"height",_descending:true,_isReversed:function(){return this._descending;}});}if(!_4._hasResource["dijit.form.HorizontalRule"]){_4._hasResource["dijit.form.HorizontalRule"]=true;_4.provide("dijit.form.HorizontalRule");_4.declare("dijit.form.HorizontalRule",[_5._Widget,_5._Templated],{templateString:"<div class=\"dijitRuleContainer dijitRuleContainerH\"></div>",count:3,container:"containerNode",ruleStyle:"",_positionPrefix:"<div class=\"dijitRuleMark dijitRuleMarkH\" style=\"left:",_positionSuffix:"%;",_suffix:"\"></div>",_genHTML:function(pos,ndx){return this._positionPrefix+pos+this._positionSuffix+this.ruleStyle+this._suffix;},_isHorizontal:true,buildRendering:function(){this.inherited(arguments);var _5f6;if(this.count==1){_5f6=this._genHTML(50,0);}else{var i;var _5f7=100/(this.count-1);if(!this._isHorizontal||this.isLeftToRight()){_5f6=this._genHTML(0,0);for(i=1;i<this.count-1;i++){_5f6+=this._genHTML(_5f7*i,i);}_5f6+=this._genHTML(100,this.count-1);}else{_5f6=this._genHTML(100,0);for(i=1;i<this.count-1;i++){_5f6+=this._genHTML(100-_5f7*i,i);}_5f6+=this._genHTML(0,this.count-1);}}this.domNode.innerHTML=_5f6;}});}if(!_4._hasResource["dijit.form.VerticalRule"]){_4._hasResource["dijit.form.VerticalRule"]=true;_4.provide("dijit.form.VerticalRule");_4.declare("dijit.form.VerticalRule",_5.form.HorizontalRule,{templateString:"<div class=\"dijitRuleContainer dijitRuleContainerV\"></div>",_positionPrefix:"<div class=\"dijitRuleMark dijitRuleMarkV\" style=\"top:",_isHorizontal:false});}if(!_4._hasResource["dijit.form.HorizontalRuleLabels"]){_4._hasResource["dijit.form.HorizontalRuleLabels"]=true;_4.provide("dijit.form.HorizontalRuleLabels");_4.declare("dijit.form.HorizontalRuleLabels",_5.form.HorizontalRule,{templateString:"<div class=\"dijitRuleContainer dijitRuleContainerH dijitRuleLabelsContainer dijitRuleLabelsContainerH\"></div>",labelStyle:"",labels:[],numericMargin:0,minimum:0,maximum:1,constraints:{pattern:"#%"},_positionPrefix:"<div class=\"dijitRuleLabelContainer dijitRuleLabelContainerH\" style=\"left:",_labelPrefix:"\"><div class=\"dijitRuleLabel dijitRuleLabelH\">",_suffix:"</div></div>",_calcPosition:function(pos){return pos;},_genHTML:function(pos,ndx){return this._positionPrefix+this._calcPosition(pos)+this._positionSuffix+this.labelStyle+this._labelPrefix+this.labels[ndx]+this._suffix;},getLabels:function(){var _5f8=this.labels;if(!_5f8.length){_5f8=_4.query("> li",this.srcNodeRef).map(function(node){return String(node.innerHTML);});}this.srcNodeRef.innerHTML="";if(!_5f8.length&&this.count>1){var _5f9=this.minimum;var inc=(this.maximum-_5f9)/(this.count-1);for(var i=0;i<this.count;i++){_5f8.push((i<this.numericMargin||i>=(this.count-this.numericMargin))?"":_4.number.format(_5f9,this.constraints));_5f9+=inc;}}return _5f8;},postMixInProperties:function(){this.inherited(arguments);this.labels=this.getLabels();this.count=this.labels.length;}});}if(!_4._hasResource["dijit.form.VerticalRuleLabels"]){_4._hasResource["dijit.form.VerticalRuleLabels"]=true;_4.provide("dijit.form.VerticalRuleLabels");_4.declare("dijit.form.VerticalRuleLabels",_5.form.HorizontalRuleLabels,{templateString:"<div class=\"dijitRuleContainer dijitRuleContainerV dijitRuleLabelsContainer dijitRuleLabelsContainerV\"></div>",_positionPrefix:"<div class=\"dijitRuleLabelContainer dijitRuleLabelContainerV\" style=\"top:",_labelPrefix:"\"><span class=\"dijitRuleLabel dijitRuleLabelV\">",_calcPosition:function(pos){return 100-pos;},_isHorizontal:false});}if(!_4._hasResource["dijit.form.SimpleTextarea"]){_4._hasResource["dijit.form.SimpleTextarea"]=true;_4.provide("dijit.form.SimpleTextarea");_4.declare("dijit.form.SimpleTextarea",_5.form.TextBox,{baseClass:"dijitTextBox dijitTextArea",attributeMap:_4.delegate(_5.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);},buildRendering:function(){this.inherited(arguments);if(_4.isIE&&this.cols){_4.addClass(this.textbox,"dijitTextAreaCols");}},filter:function(_5fa){if(_5fa){_5fa=_5fa.replace(/\r/g,"");}return this.inherited(arguments);},_previousValue:"",_onInput:function(e){if(this.maxLength){var _5fb=parseInt(this.maxLength);var _5fc=this.textbox.value.replace(/\r/g,"");var _5fd=_5fc.length-_5fb;if(_5fd>0){if(e){_4.stopEvent(e);}var _5fe=this.textbox;if(_5fe.selectionStart){var pos=_5fe.selectionStart;var cr=0;if(_4.isOpera){cr=(this.textbox.value.substring(0,pos).match(/\r/g)||[]).length;}this.textbox.value=_5fc.substring(0,pos-_5fd-cr)+_5fc.substring(pos-cr);_5fe.setSelectionRange(pos-_5fd,pos-_5fd);}else{if(_4.doc.selection){_5fe.focus();var _5ff=_4.doc.selection.createRange();_5ff.moveStart("character",-_5fd);_5ff.text="";_5ff.select();}}}this._previousValue=this.textbox.value;}this.inherited(arguments);}});}if(!_4._hasResource["dijit.form.Textarea"]){_4._hasResource["dijit.form.Textarea"]=true;_4.provide("dijit.form.Textarea");_4.declare("dijit.form.Textarea",_5.form.SimpleTextarea,{baseClass:"dijitTextBox dijitTextArea dijitExpandingTextArea",cols:"",_previousNewlines:0,_strictMode:(_4.doc.compatMode!="BackCompat"),_getHeight:function(_600){var newH=_600.scrollHeight;if(_4.isIE){newH+=_600.offsetHeight-_600.clientHeight-((_4.isIE<8&&this._strictMode)?_4._getPadBorderExtents(_600).h:0);}else{if(_4.isMoz){newH+=_600.offsetHeight-_600.clientHeight;}else{if(_4.isWebKit){newH+=_4._getBorderExtents(_600).h;}else{newH+=_4._getPadBorderExtents(_600).h;}}}return newH;},_estimateHeight:function(_601){_601.style.maxHeight="";_601.style.height="auto";_601.rows=(_601.value.match(/\n/g)||[]).length+1;},_needsHelpShrinking:_4.isMoz||_4.isWebKit,_onInput:function(){this.inherited(arguments);if(this._busyResizing){return;}this._busyResizing=true;var _602=this.textbox;if(_602.scrollHeight&&_602.offsetHeight&&_602.clientHeight){var newH=this._getHeight(_602)+"px";if(_602.style.height!=newH){_602.style.maxHeight=_602.style.height=newH;}if(this._needsHelpShrinking){if(this._setTimeoutHandle){clearTimeout(this._setTimeoutHandle);}this._setTimeoutHandle=setTimeout(_4.hitch(this,"_shrink"),0);}}else{this._estimateHeight(_602);}this._busyResizing=false;},_busyResizing:false,_shrink:function(){this._setTimeoutHandle=null;if(this._needsHelpShrinking&&!this._busyResizing){this._busyResizing=true;var _603=this.textbox;var _604=false;if(_603.value==""){_603.value=" ";_604=true;}var _605=_603.scrollHeight;if(!_605){this._estimateHeight(_603);}else{var _606=_603.style.paddingBottom;var _607=_4._getPadExtents(_603);_607=_607.h-_607.t;_603.style.paddingBottom=_607+1+"px";var newH=this._getHeight(_603)-1+"px";if(_603.style.maxHeight!=newH){_603.style.paddingBottom=_607+_605+"px";_603.scrollTop=0;_603.style.maxHeight=this._getHeight(_603)-_605+"px";}_603.style.paddingBottom=_606;}if(_604){_603.value="";}this._busyResizing=false;}},resize:function(){this._onInput();},_setValueAttr:function(){this.inherited(arguments);this.resize();},buildRendering:function(){this.inherited(arguments);_4.style(this.textbox,{overflowY:"hidden",overflowX:"auto",boxSizing:"border-box",MsBoxSizing:"border-box",WebkitBoxSizing:"border-box",MozBoxSizing:"border-box"});},postCreate:function(){this.inherited(arguments);this.connect(this.textbox,"onscroll","_onInput");this.connect(this.textbox,"onresize","_onInput");this.connect(this.textbox,"onfocus","_onInput");this._setTimeoutHandle=setTimeout(_4.hitch(this,"resize"),0);},uninitialize:function(){if(this._setTimeoutHandle){clearTimeout(this._setTimeoutHandle);}this.inherited(arguments);}});}if(!_4._hasResource["dijit.layout.StackController"]){_4._hasResource["dijit.layout.StackController"]=true;_4.provide("dijit.layout.StackController");_4.declare("dijit.layout.StackController",[_5._Widget,_5._Templated,_5._Container],{templateString:"<span role='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>",containerId:"",buttonWidget:"dijit.layout._StackButton",constructor:function(){this.pane2button={};this.pane2connects={};this.pane2watches={};},buildRendering:function(){this.inherited(arguments);_5.setWaiRole(this.domNode,"tablist");},postCreate:function(){this.inherited(arguments);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){_4.forEach(info.children,this.onAddChild,this);if(info.selected){this.onSelectChild(info.selected);}},destroy:function(){for(var pane in this.pane2button){this.onRemoveChild(_5.byId(pane));}this.inherited(arguments);},onAddChild:function(page,_608){var cls=_4.getObject(this.buttonWidget);var _609=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});_5.setWaiState(_609.focusNode,"selected","false");var _60a=["title","showTitle","iconClass","closable","tooltip"],_60b=["label","showLabel","iconClass","closeButton","title"];this.pane2watches[page.id]=_4.map(_60a,function(_60c,idx){return page.watch(_60c,function(name,_60d,_60e){_609.set(_60b[idx],_60e);});});this.pane2connects[page.id]=[this.connect(_609,"onClick",_4.hitch(this,"onButtonClick",page)),this.connect(_609,"onClickCloseButton",_4.hitch(this,"onCloseButtonClick",page))];this.addChild(_609,_608);this.pane2button[page.id]=_609;page.controlButton=_609;if(!this._currentChild){_609.focusNode.setAttribute("tabIndex","0");_5.setWaiState(_609.focusNode,"selected","true");this._currentChild=page;}if(!this.isLeftToRight()&&_4.isIE&&this._rectifyRtlTabList){this._rectifyRtlTabList();}},onRemoveChild:function(page){if(this._currentChild===page){this._currentChild=null;}_4.forEach(this.pane2connects[page.id],_4.hitch(this,"disconnect"));delete this.pane2connects[page.id];_4.forEach(this.pane2watches[page.id],function(w){w.unwatch();});delete this.pane2watches[page.id];var _60f=this.pane2button[page.id];if(_60f){this.removeChild(_60f);delete this.pane2button[page.id];_60f.destroy();}delete page.controlButton;},onSelectChild:function(page){if(!page){return;}if(this._currentChild){var _610=this.pane2button[this._currentChild.id];_610.set("checked",false);_5.setWaiState(_610.focusNode,"selected","false");_610.focusNode.setAttribute("tabIndex","-1");}var _611=this.pane2button[page.id];_611.set("checked",true);_5.setWaiState(_611.focusNode,"selected","true");this._currentChild=page;_611.focusNode.setAttribute("tabIndex","0");var _612=_5.byId(this.containerId);_5.setWaiState(_612.containerNode,"labelledby",_611.id);},onButtonClick:function(page){var _613=_5.byId(this.containerId);_613.selectChild(page);},onCloseButtonClick:function(page){var _614=_5.byId(this.containerId);_614.closeChild(page);if(this._currentChild){var b=this.pane2button[this._currentChild.id];if(b){_5.focus(b.focusNode||b.domNode);}}},adjacent:function(_615){if(!this.isLeftToRight()&&(!this.tabPosition||/top|bottom/.test(this.tabPosition))){_615=!_615;}var _616=this.getChildren();var _617=_4.indexOf(_616,this.pane2button[this._currentChild.id]);var _618=_615?1:_616.length-1;return _616[(_617+_618)%_616.length];},onkeypress:function(e){if(this.disabled||e.altKey){return;}var _619=null;if(e.ctrlKey||!e._djpage){var k=_4.keys;switch(e.charOrCode){case k.LEFT_ARROW:case k.UP_ARROW:if(!e._djpage){_619=false;}break;case k.PAGE_UP:if(e.ctrlKey){_619=false;}break;case k.RIGHT_ARROW:case k.DOWN_ARROW:if(!e._djpage){_619=true;}break;case k.PAGE_DOWN:if(e.ctrlKey){_619=true;}break;case k.HOME:case k.END:var _61a=this.getChildren();if(_61a&&_61a.length){_61a[e.charOrCode==k.HOME?0:_61a.length-1].onClick();}_4.stopEvent(e);break;case k.DELETE:if(this._currentChild.closable){this.onCloseButtonClick(this._currentChild);}_4.stopEvent(e);break;default:if(e.ctrlKey){if(e.charOrCode===k.TAB){this.adjacent(!e.shiftKey).onClick();_4.stopEvent(e);}else{if(e.charOrCode=="w"){if(this._currentChild.closable){this.onCloseButtonClick(this._currentChild);}_4.stopEvent(e);}}}}if(_619!==null){this.adjacent(_619).onClick();_4.stopEvent(e);}}},onContainerKeyPress:function(info){info.e._djpage=info.page;this.onkeypress(info.e);}});_4.declare("dijit.layout._StackButton",_5.form.ToggleButton,{tabIndex:"-1",buildRendering:function(evt){this.inherited(arguments);_5.setWaiRole((this.focusNode||this.domNode),"tab");},onClick:function(evt){_5.focus(this.focusNode);},onClickCloseButton:function(evt){evt.stopPropagation();}});}if(!_4._hasResource["dijit.layout.StackContainer"]){_4._hasResource["dijit.layout.StackContainer"]=true;_4.provide("dijit.layout.StackContainer");_4.declare("dijit.layout.StackContainer",_5.layout._LayoutWidget,{doLayout:true,persist:false,baseClass:"dijitStackContainer",buildRendering:function(){this.inherited(arguments);_4.addClass(this.domNode,"dijitLayoutContainer");_5.setWaiRole(this.containerNode,"tabpanel");},postCreate:function(){this.inherited(arguments);this.connect(this.domNode,"onkeypress",this._onKeyPress);},startup:function(){if(this._started){return;}var _61b=this.getChildren();_4.forEach(_61b,this._setupChild,this);if(this.persist){this.selectedChildWidget=_5.byId(_4.cookie(this.id+"_selectedChild"));}else{_4.some(_61b,function(_61c){if(_61c.selected){this.selectedChildWidget=_61c;}return _61c.selected;},this);}var _61d=this.selectedChildWidget;if(!_61d&&_61b[0]){_61d=this.selectedChildWidget=_61b[0];_61d.selected=true;}_4.publish(this.id+"-startup",[{children:_61b,selected:_61d}]);this.inherited(arguments);},resize:function(){var _61e=this.selectedChildWidget;if(_61e&&!this._hasBeenShown){this._hasBeenShown=true;this._showChild(_61e);}this.inherited(arguments);},_setupChild:function(_61f){this.inherited(arguments);_4.replaceClass(_61f.domNode,"dijitHidden","dijitVisible");_61f.domNode.title="";},addChild:function(_620,_621){this.inherited(arguments);if(this._started){_4.publish(this.id+"-addChild",[_620,_621]);this.layout();if(!this.selectedChildWidget){this.selectChild(_620);}}},removeChild:function(page){this.inherited(arguments);if(this._started){_4.publish(this.id+"-removeChild",[page]);}if(this._beingDestroyed){return;}if(this.selectedChildWidget===page){this.selectedChildWidget=undefined;if(this._started){var _622=this.getChildren();if(_622.length){this.selectChild(_622[0]);}}}if(this._started){this.layout();}},selectChild:function(page,_623){page=_5.byId(page);if(this.selectedChildWidget!=page){var d=this._transition(page,this.selectedChildWidget,_623);this._set("selectedChildWidget",page);_4.publish(this.id+"-selectChild",[page]);if(this.persist){_4.cookie(this.id+"_selectedChild",this.selectedChildWidget.id);}}return d;},_transition:function(_624,_625,_626){if(_625){this._hideChild(_625);}var d=this._showChild(_624);if(_624.resize){if(this.doLayout){_624.resize(this._containerContentBox||this._contentBox);}else{_624.resize();}}return d;},_adjacent:function(_627){var _628=this.getChildren();var _629=_4.indexOf(_628,this.selectedChildWidget);_629+=_627?1:_628.length-1;return _628[_629%_628.length];},forward:function(){return this.selectChild(this._adjacent(true),true);},back:function(){return this.selectChild(this._adjacent(false),true);},_onKeyPress:function(e){_4.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 _62a=this.getChildren();page.isFirstChild=(page==_62a[0]);page.isLastChild=(page==_62a[_62a.length-1]);page._set("selected",true);_4.replaceClass(page.domNode,"dijitVisible","dijitHidden");return page._onShow()||true;},_hideChild:function(page){page._set("selected",false);_4.replaceClass(page.domNode,"dijitHidden","dijitVisible");page.onHide();},closeChild:function(page){var _62b=page.onClose(this,page);if(_62b){this.removeChild(page);page.destroyRecursive();}},destroyDescendants:function(_62c){_4.forEach(this.getChildren(),function(_62d){this.removeChild(_62d);_62d.destroyRecursive(_62c);},this);}});_4.extend(_5._Widget,{selected:false,closable:false,iconClass:"",showTitle:true});}if(!_4._hasResource["dijit.layout.AccordionPane"]){_4._hasResource["dijit.layout.AccordionPane"]=true;_4.provide("dijit.layout.AccordionPane");_4.declare("dijit.layout.AccordionPane",_5.layout.ContentPane,{constructor:function(){_4.deprecated("dijit.layout.AccordionPane deprecated, use ContentPane instead","","2.0");},onSelected:function(){}});}if(!_4._hasResource["dijit.layout.AccordionContainer"]){_4._hasResource["dijit.layout.AccordionContainer"]=true;_4.provide("dijit.layout.AccordionContainer");_4.declare("dijit.layout.AccordionContainer",_5.layout.StackContainer,{duration:_5.defaultDuration,buttonWidget:"dijit.layout._AccordionButton",baseClass:"dijitAccordionContainer",buildRendering:function(){this.inherited(arguments);this.domNode.style.overflow="hidden";_5.setWaiRole(this.domNode,"tablist");},startup:function(){if(this._started){return;}this.inherited(arguments);if(this.selectedChildWidget){var _62e=this.selectedChildWidget.containerNode.style;_62e.display="";_62e.overflow="auto";this.selectedChildWidget._wrapperWidget.set("selected",true);}},layout:function(){var _62f=this.selectedChildWidget;if(!_62f){return;}var _630=_62f._wrapperWidget.domNode,_631=_4._getMarginExtents(_630),_632=_4._getPadBorderExtents(_630),_633=_62f._wrapperWidget.containerNode,_634=_4._getMarginExtents(_633),_635=_4._getPadBorderExtents(_633),_636=this._contentBox;var _637=0;_4.forEach(this.getChildren(),function(_638){if(_638!=_62f){_637+=_4._getMarginSize(_638._wrapperWidget.domNode).h;}});this._verticalSpace=_636.h-_637-_631.h-_632.h-_634.h-_635.h-_62f._buttonWidget.getTitleHeight();this._containerContentBox={h:this._verticalSpace,w:this._contentBox.w-_631.w-_632.w-_634.w-_635.w};if(_62f){_62f.resize(this._containerContentBox);}},_setupChild:function(_639){_639._wrapperWidget=new _5.layout._AccordionInnerContainer({contentWidget:_639,buttonWidget:this.buttonWidget,id:_639.id+"_wrapper",dir:_639.dir,lang:_639.lang,parent:this});this.inherited(arguments);},addChild:function(_63a,_63b){if(this._started){_4.place(_63a.domNode,this.containerNode,_63b);if(!_63a._started){_63a.startup();}this._setupChild(_63a);_4.publish(this.id+"-addChild",[_63a,_63b]);this.layout();if(!this.selectedChildWidget){this.selectChild(_63a);}}else{this.inherited(arguments);}},removeChild:function(_63c){if(_63c._wrapperWidget){_4.place(_63c.domNode,_63c._wrapperWidget.domNode,"after");_63c._wrapperWidget.destroy();delete _63c._wrapperWidget;}_4.removeClass(_63c.domNode,"dijitHidden");this.inherited(arguments);},getChildren:function(){return _4.map(this.inherited(arguments),function(_63d){return _63d.declaredClass=="dijit.layout._AccordionInnerContainer"?_63d.contentWidget:_63d;},this);},destroy:function(){if(this._animation){this._animation.stop();}_4.forEach(this.getChildren(),function(_63e){if(_63e._wrapperWidget){_63e._wrapperWidget.destroy();}else{_63e.destroyRecursive();}});this.inherited(arguments);},_showChild:function(_63f){_63f._wrapperWidget.containerNode.style.display="block";return this.inherited(arguments);},_hideChild:function(_640){_640._wrapperWidget.containerNode.style.display="none";this.inherited(arguments);},_transition:function(_641,_642,_643){if(_4.isIE<8){_643=false;}if(this._animation){this._animation.stop(true);delete this._animation;}var self=this;if(_641){_641._wrapperWidget.set("selected",true);var d=this._showChild(_641);if(this.doLayout&&_641.resize){_641.resize(this._containerContentBox);}}if(_642){_642._wrapperWidget.set("selected",false);if(!_643){this._hideChild(_642);}}if(_643){var _644=_641._wrapperWidget.containerNode,_645=_642._wrapperWidget.containerNode;var _646=_641._wrapperWidget.containerNode,_647=_4._getMarginExtents(_646),_648=_4._getPadBorderExtents(_646),_649=_647.h+_648.h;_645.style.height=(self._verticalSpace-_649)+"px";this._animation=new _4.Animation({node:_644,duration:this.duration,curve:[1,this._verticalSpace-_649-1],onAnimate:function(_64a){_64a=Math.floor(_64a);_644.style.height=_64a+"px";_645.style.height=(self._verticalSpace-_649-_64a)+"px";},onEnd:function(){delete self._animation;_644.style.height="auto";_642._wrapperWidget.containerNode.style.display="none";_645.style.height="auto";self._hideChild(_642);}});this._animation.onStop=this._animation.onEnd;this._animation.play();}return d;},_onKeyPress:function(e,_64b){if(this.disabled||e.altKey||!(_64b||e.ctrlKey)){return;}var k=_4.keys,c=e.charOrCode;if((_64b&&(c==k.LEFT_ARROW||c==k.UP_ARROW))||(e.ctrlKey&&c==k.PAGE_UP)){this._adjacent(false)._buttonWidget._onTitleClick();_4.stopEvent(e);}else{if((_64b&&(c==k.RIGHT_ARROW||c==k.DOWN_ARROW))||(e.ctrlKey&&(c==k.PAGE_DOWN||c==k.TAB))){this._adjacent(true)._buttonWidget._onTitleClick();_4.stopEvent(e);}}}});_4.declare("dijit.layout._AccordionInnerContainer",[_5._Widget,_5._CssStateMixin],{baseClass:"dijitAccordionInnerContainer",isContainer:true,isLayoutContainer:true,buildRendering:function(){this.domNode=_4.place("<div class='"+this.baseClass+"'>",this.contentWidget.domNode,"after");var _64c=this.contentWidget,cls=_4.getObject(this.buttonWidget);this.button=_64c._buttonWidget=(new cls({contentWidget:_64c,label:_64c.title,title:_64c.tooltip,dir:_64c.dir,lang:_64c.lang,iconClass:_64c.iconClass,id:_64c.id+"_button",parent:this.parent})).placeAt(this.domNode);this.containerNode=_4.place("<div class='dijitAccordionChildWrapper' style='display:none'>",this.domNode);_4.place(this.contentWidget.domNode,this.containerNode);},postCreate:function(){this.inherited(arguments);var _64d=this.button;this._contentWidgetWatches=[this.contentWidget.watch("title",_4.hitch(this,function(name,_64e,_64f){_64d.set("label",_64f);})),this.contentWidget.watch("tooltip",_4.hitch(this,function(name,_650,_651){_64d.set("title",_651);})),this.contentWidget.watch("iconClass",_4.hitch(this,function(name,_652,_653){_64d.set("iconClass",_653);}))];},_setSelectedAttr:function(_654){this._set("selected",_654);this.button.set("selected",_654);if(_654){var cw=this.contentWidget;if(cw.onSelected){cw.onSelected();}}},startup:function(){this.contentWidget.startup();},destroy:function(){this.button.destroyRecursive();_4.forEach(this._contentWidgetWatches||[],function(w){w.unwatch();});delete this.contentWidget._buttonWidget;delete this.contentWidget._wrapperWidget;this.inherited(arguments);},destroyDescendants:function(){this.contentWidget.destroyRecursive();}});_4.declare("dijit.layout._AccordionButton",[_5._Widget,_5._Templated,_5._CssStateMixin],{templateString:_4.cache("dijit.layout","templates/AccordionButton.html","<div dojoAttachEvent='onclick:_onTitleClick' class='dijitAccordionTitle'>\r\n\t<div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='onkeypress:_onTitleKeyPress'\r\n\t\t\tclass='dijitAccordionTitleFocus' role=\"tab\" aria-expanded=\"false\"\r\n\t\t><span class='dijitInline dijitAccordionArrow' role=\"presentation\"></span\r\n\t\t><span class='arrowTextUp' role=\"presentation\">+</span\r\n\t\t><span class='arrowTextDown' role=\"presentation\">-</span\r\n\t\t><img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' style=\"vertical-align: middle\" role=\"presentation\"/>\r\n\t\t<span role=\"presentation\" dojoAttachPoint='titleTextNode' class='dijitAccordionText'></span>\r\n\t</div>\r\n</div>\r\n"),attributeMap:_4.mixin(_4.clone(_5.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;},buildRendering:function(){this.inherited(arguments);var _655=this.id.replace(" ","_");_4.attr(this.titleTextNode,"id",_655+"_title");_5.setWaiState(this.focusNode,"labelledby",_4.attr(this.titleTextNode,"id"));_4.setSelectable(this.domNode,false);},getTitleHeight:function(){return _4._getMarginSize(this.domNode).h;},_onTitleClick:function(){var _656=this.getParent();_656.selectChild(this.contentWidget,true);_5.focus(this.focusNode);},_onTitleKeyPress:function(evt){return this.getParent()._onKeyPress(evt,this.contentWidget);},_setSelectedAttr:function(_657){this._set("selected",_657);_5.setWaiState(this.focusNode,"expanded",_657);_5.setWaiState(this.focusNode,"selected",_657);this.focusNode.setAttribute("tabIndex",_657?"0":"-1");}});}if(!_4._hasResource["dijit.layout.BorderContainer"]){_4._hasResource["dijit.layout.BorderContainer"]=true;_4.provide("dijit.layout.BorderContainer");_4.declare("dijit.layout.BorderContainer",_5.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);},startup:function(){if(this._started){return;}_4.forEach(this.getChildren(),this._setupChild,this);this.inherited(arguments);},_setupChild:function(_658){var _659=_658.region;if(_659){this.inherited(arguments);_4.addClass(_658.domNode,this.baseClass+"Pane");var ltr=this.isLeftToRight();if(_659=="leading"){_659=ltr?"left":"right";}if(_659=="trailing"){_659=ltr?"right":"left";}if(_659!="center"&&(_658.splitter||this.gutters)&&!_658._splitterWidget){var _65a=_4.getObject(_658.splitter?this._splitterClass:"dijit.layout._Gutter");var _65b=new _65a({id:_658.id+"_splitter",container:this,child:_658,region:_659,live:this.liveSplitters});_65b.isSplitter=true;_658._splitterWidget=_65b;_4.place(_65b.domNode,_658.domNode,"after");_65b.startup();}_658.region=_659;}},layout:function(){this._layoutChildren();},addChild:function(_65c,_65d){this.inherited(arguments);if(this._started){this.layout();}},removeChild:function(_65e){var _65f=_65e.region;var _660=_65e._splitterWidget;if(_660){_660.destroy();delete _65e._splitterWidget;}this.inherited(arguments);if(this._started){this._layoutChildren();}_4.removeClass(_65e.domNode,this.baseClass+"Pane");_4.style(_65e.domNode,{top:"auto",bottom:"auto",left:"auto",right:"auto",position:"static"});_4.style(_65e.domNode,_65f=="top"||_65f=="bottom"?"width":"height","auto");},getChildren:function(){return _4.filter(this.inherited(arguments),function(_661){return !_661.isSplitter;});},getSplitter:function(_662){return _4.filter(this.getChildren(),function(_663){return _663.region==_662;})[0]._splitterWidget;},resize:function(_664,_665){if(!this.cs||!this.pe){var node=this.domNode;this.cs=_4.getComputedStyle(node);this.pe=_4._getPadExtents(node,this.cs);this.pe.r=_4._toPixelValue(node,this.cs.paddingRight);this.pe.b=_4._toPixelValue(node,this.cs.paddingBottom);_4.style(node,"padding","0px");}this.inherited(arguments);},_layoutChildren:function(_666,_667){if(!this._borderBox||!this._borderBox.h){return;}var _668=_4.map(this.getChildren(),function(_669,idx){return {pane:_669,weight:[_669.region=="center"?Infinity:0,_669.layoutPriority,(this.design=="sidebar"?1:-1)*(/top|bottom/.test(_669.region)?1:-1),idx]};},this);_668.sort(function(a,b){var aw=a.weight,bw=b.weight;for(var i=0;i<aw.length;i++){if(aw[i]!=bw[i]){return aw[i]-bw[i];}}return 0;});var _66a=[];_4.forEach(_668,function(_66b){var pane=_66b.pane;_66a.push(pane);if(pane._splitterWidget){_66a.push(pane._splitterWidget);}});var dim={l:this.pe.l,t:this.pe.t,w:this._borderBox.w-this.pe.w,h:this._borderBox.h-this.pe.h};_5.layout.layoutChildren(this.domNode,dim,_66a,_666,_667);},destroyRecursive:function(){_4.forEach(this.getChildren(),function(_66c){var _66d=_66c._splitterWidget;if(_66d){_66d.destroy();}delete _66c._splitterWidget;});this.inherited(arguments);}});_4.extend(_5._Widget,{region:"",layoutPriority:0,splitter:false,minSize:0,maxSize:Infinity});_4.declare("dijit.layout._Splitter",[_5._Widget,_5._Templated],{live:true,templateString:"<div class=\"dijitSplitter\" dojoAttachEvent=\"onkeypress:_onKeyPress,onmousedown:_startDrag,onmouseenter:_onMouse,onmouseleave:_onMouse\" tabIndex=\"0\" role=\"separator\"><div class=\"dijitSplitterThumb\"></div></div>",postMixInProperties:function(){this.inherited(arguments);this.horizontal=/top|bottom/.test(this.region);this._factor=/top|left/.test(this.region)?1:-1;this._cookieName=this.container.id+"_"+this.region;},buildRendering:function(){this.inherited(arguments);_4.addClass(this.domNode,"dijitSplitter"+(this.horizontal?"H":"V"));if(this.container.persist){var _66e=_4.cookie(this._cookieName);if(_66e){this.child.domNode.style[this.horizontal?"height":"width"]=_66e;}}},_computeMaxSize:function(){var dim=this.horizontal?"h":"w",_66f=_4.marginBox(this.child.domNode)[dim],_670=_4.filter(this.container.getChildren(),function(_671){return _671.region=="center";})[0],_672=_4.marginBox(_670.domNode)[dim];return Math.min(this.child.maxSize,_66f+_672);},_startDrag:function(e){if(!this.cover){this.cover=_4.doc.createElement("div");_4.addClass(this.cover,"dijitSplitterCover");_4.place(this.cover,this.child.domNode,"after");}_4.addClass(this.cover,"dijitSplitterCoverActive");if(this.fake){_4.destroy(this.fake);}if(!(this._resize=this.live)){(this.fake=this.domNode.cloneNode(true)).removeAttribute("id");_4.addClass(this.domNode,"dijitSplitterShadow");_4.place(this.fake,this.domNode,"after");}_4.addClass(this.domNode,"dijitSplitterActive dijitSplitter"+(this.horizontal?"H":"V")+"Active");if(this.fake){_4.removeClass(this.fake,"dijitSplitterHover dijitSplitter"+(this.horizontal?"H":"V")+"Hover");}var _673=this._factor,_674=this.horizontal,axis=_674?"pageY":"pageX",_675=e[axis],_676=this.domNode.style,dim=_674?"h":"w",_677=_4.marginBox(this.child.domNode)[dim],max=this._computeMaxSize(),min=this.child.minSize||20,_678=this.region,_679=_678=="top"||_678=="bottom"?"top":"left",_67a=parseInt(_676[_679],10),_67b=this._resize,_67c=_4.hitch(this.container,"_layoutChildren",this.child.id),de=_4.doc;this._handlers=(this._handlers||[]).concat([_4.connect(de,"onmousemove",this._drag=function(e,_67d){var _67e=e[axis]-_675,_67f=_673*_67e+_677,_680=Math.max(Math.min(_67f,max),min);if(_67b||_67d){_67c(_680);}_676[_679]=_67e+_67a+_673*(_680-_67f)+"px";}),_4.connect(de,"ondragstart",_4.stopEvent),_4.connect(_4.body(),"onselectstart",_4.stopEvent),_4.connect(de,"onmouseup",this,"_stopDrag")]);_4.stopEvent(e);},_onMouse:function(e){var o=(e.type=="mouseover"||e.type=="mouseenter");_4.toggleClass(this.domNode,"dijitSplitterHover",o);_4.toggleClass(this.domNode,"dijitSplitter"+(this.horizontal?"H":"V")+"Hover",o);},_stopDrag:function(e){try{if(this.cover){_4.removeClass(this.cover,"dijitSplitterCoverActive");}if(this.fake){_4.destroy(this.fake);}_4.removeClass(this.domNode,"dijitSplitterActive dijitSplitter"+(this.horizontal?"H":"V")+"Active dijitSplitterShadow");this._drag(e);this._drag(e,true);}finally{this._cleanupHandlers();delete this._drag;}if(this.container.persist){_4.cookie(this._cookieName,this.child.domNode.style[this.horizontal?"height":"width"],{expires:365});}},_cleanupHandlers:function(){_4.forEach(this._handlers,_4.disconnect);delete this._handlers;},_onKeyPress:function(e){this._resize=true;var _681=this.horizontal;var tick=1;var dk=_4.keys;switch(e.charOrCode){case _681?dk.UP_ARROW:dk.LEFT_ARROW:tick*=-1;case _681?dk.DOWN_ARROW:dk.RIGHT_ARROW:break;default:return;}var _682=_4._getMarginSize(this.child.domNode)[_681?"h":"w"]+this._factor*tick;this.container._layoutChildren(this.child.id,Math.max(Math.min(_682,this._computeMaxSize()),this.child.minSize));_4.stopEvent(e);},destroy:function(){this._cleanupHandlers();delete this.child;delete this.container;delete this.cover;delete this.fake;this.inherited(arguments);}});_4.declare("dijit.layout._Gutter",[_5._Widget,_5._Templated],{templateString:"<div class=\"dijitGutter\" role=\"presentation\"></div>",postMixInProperties:function(){this.inherited(arguments);this.horizontal=/top|bottom/.test(this.region);},buildRendering:function(){this.inherited(arguments);_4.addClass(this.domNode,"dijitGutter"+(this.horizontal?"H":"V"));}});}if(!_4._hasResource["dijit.layout.LayoutContainer"]){_4._hasResource["dijit.layout.LayoutContainer"]=true;_4.provide("dijit.layout.LayoutContainer");_4.declare("dijit.layout.LayoutContainer",_5.layout._LayoutWidget,{baseClass:"dijitLayoutContainer",constructor:function(){_4.deprecated("dijit.layout.LayoutContainer is deprecated","use BorderContainer instead",2);},layout:function(){_5.layout.layoutChildren(this.domNode,this._contentBox,this.getChildren());},addChild:function(_683,_684){this.inherited(arguments);if(this._started){_5.layout.layoutChildren(this.domNode,this._contentBox,this.getChildren());}},removeChild:function(_685){this.inherited(arguments);if(this._started){_5.layout.layoutChildren(this.domNode,this._contentBox,this.getChildren());}}});_4.extend(_5._Widget,{layoutAlign:"none"});}if(!_4._hasResource["dijit.layout.LinkPane"]){_4._hasResource["dijit.layout.LinkPane"]=true;_4.provide("dijit.layout.LinkPane");_4.declare("dijit.layout.LinkPane",[_5.layout.ContentPane,_5._Templated],{templateString:"<div class=\"dijitLinkPane\" dojoAttachPoint=\"containerNode\"></div>",postMixInProperties:function(){if(this.srcNodeRef){this.title+=this.srcNodeRef.innerHTML;}this.inherited(arguments);},_fillContent:function(_686){}});}if(!_4._hasResource["dijit.layout.SplitContainer"]){_4._hasResource["dijit.layout.SplitContainer"]=true;_4.provide("dijit.layout.SplitContainer");_4.declare("dijit.layout.SplitContainer",_5.layout._LayoutWidget,{constructor:function(){_4.deprecated("dijit.layout.SplitContainer is deprecated","use BorderContainer with splitter instead",2);},activeSizing:false,sizerWidth:7,orientation:"horizontal",persist:true,baseClass:"dijitSplitContainer",postMixInProperties:function(){this.inherited("postMixInProperties",arguments);this.isHorizontal=(this.orientation=="horizontal");},postCreate:function(){this.inherited(arguments);this.sizers=[];if(_4.isMozilla){this.domNode.style.overflow="-moz-scrollbars-none";}if(typeof this.sizerWidth=="object"){try{this.sizerWidth=parseInt(this.sizerWidth.toString());}catch(e){this.sizerWidth=7;}}var _687=_4.doc.createElement("div");this.virtualSizer=_687;_687.style.position="relative";_687.style.zIndex=10;_687.className=this.isHorizontal?"dijitSplitContainerVirtualSizerH":"dijitSplitContainerVirtualSizerV";this.domNode.appendChild(_687);_4.setSelectable(_687,false);},destroy:function(){delete this.virtualSizer;_4.forEach(this._ownconnects,_4.disconnect);this.inherited(arguments);},startup:function(){if(this._started){return;}_4.forEach(this.getChildren(),function(_688,i,_689){this._setupChild(_688);if(i<_689.length-1){this._addSizer();}},this);if(this.persist){this._restoreState();}this.inherited(arguments);},_setupChild:function(_68a){this.inherited(arguments);_68a.domNode.style.position="absolute";_4.addClass(_68a.domNode,"dijitSplitPane");},_onSizerMouseDown:function(e){if(e.target.id){for(var i=0;i<this.sizers.length;i++){if(this.sizers[i].id==e.target.id){break;}}if(i<this.sizers.length){this.beginSizing(e,i);}}},_addSizer:function(_68b){_68b=_68b===undefined?this.sizers.length:_68b;var _68c=_4.doc.createElement("div");_68c.id=_5.getUniqueId("dijit_layout_SplitterContainer_Splitter");this.sizers.splice(_68b,0,_68c);this.domNode.appendChild(_68c);_68c.className=this.isHorizontal?"dijitSplitContainerSizerH":"dijitSplitContainerSizerV";var _68d=_4.doc.createElement("div");_68d.className="thumb";_68c.appendChild(_68d);this.connect(_68c,"onmousedown","_onSizerMouseDown");_4.setSelectable(_68c,false);},removeChild:function(_68e){if(this.sizers.length){var i=_4.indexOf(this.getChildren(),_68e);if(i!=-1){if(i==this.sizers.length){i--;}_4.destroy(this.sizers[i]);this.sizers.splice(i,1);}}this.inherited(arguments);if(this._started){this.layout();}},addChild:function(_68f,_690){this.inherited(arguments);if(this._started){var _691=this.getChildren();if(_691.length>1){this._addSizer(_690);}this.layout();}},layout:function(){this.paneWidth=this._contentBox.w;this.paneHeight=this._contentBox.h;var _692=this.getChildren();if(!_692.length){return;}var _693=this.isHorizontal?this.paneWidth:this.paneHeight;if(_692.length>1){_693-=this.sizerWidth*(_692.length-1);}var _694=0;_4.forEach(_692,function(_695){_694+=_695.sizeShare;});var _696=_693/_694;var _697=0;_4.forEach(_692.slice(0,_692.length-1),function(_698){var size=Math.round(_696*_698.sizeShare);_698.sizeActual=size;_697+=size;});_692[_692.length-1].sizeActual=_693-_697;this._checkSizes();var pos=0;var size=_692[0].sizeActual;this._movePanel(_692[0],pos,size);_692[0].position=pos;pos+=size;if(!this.sizers){return;}_4.some(_692.slice(1),function(_699,i){if(!this.sizers[i]){return true;}this._moveSlider(this.sizers[i],pos,this.sizerWidth);this.sizers[i].position=pos;pos+=this.sizerWidth;size=_699.sizeActual;this._movePanel(_699,pos,size);_699.position=pos;pos+=size;},this);},_movePanel:function(_69a,pos,size){if(this.isHorizontal){_69a.domNode.style.left=pos+"px";_69a.domNode.style.top=0;var box={w:size,h:this.paneHeight};if(_69a.resize){_69a.resize(box);}else{_4.marginBox(_69a.domNode,box);}}else{_69a.domNode.style.left=0;_69a.domNode.style.top=pos+"px";var box={w:this.paneWidth,h:size};if(_69a.resize){_69a.resize(box);}else{_4.marginBox(_69a.domNode,box);}}},_moveSlider:function(_69b,pos,size){if(this.isHorizontal){_69b.style.left=pos+"px";_69b.style.top=0;_4.marginBox(_69b,{w:size,h:this.paneHeight});}else{_69b.style.left=0;_69b.style.top=pos+"px";_4.marginBox(_69b,{w:this.paneWidth,h:size});}},_growPane:function(_69c,pane){if(_69c>0){if(pane.sizeActual>pane.sizeMin){if((pane.sizeActual-pane.sizeMin)>_69c){pane.sizeActual=pane.sizeActual-_69c;_69c=0;}else{_69c-=pane.sizeActual-pane.sizeMin;pane.sizeActual=pane.sizeMin;}}}return _69c;},_checkSizes:function(){var _69d=0;var _69e=0;var _69f=this.getChildren();_4.forEach(_69f,function(_6a0){_69e+=_6a0.sizeActual;_69d+=_6a0.sizeMin;});if(_69d<=_69e){var _6a1=0;_4.forEach(_69f,function(_6a2){if(_6a2.sizeActual<_6a2.sizeMin){_6a1+=_6a2.sizeMin-_6a2.sizeActual;_6a2.sizeActual=_6a2.sizeMin;}});if(_6a1>0){var list=this.isDraggingLeft?_69f.reverse():_69f;_4.forEach(list,function(_6a3){_6a1=this._growPane(_6a1,_6a3);},this);}}else{_4.forEach(_69f,function(_6a4){_6a4.sizeActual=Math.round(_69e*(_6a4.sizeMin/_69d));});}},beginSizing:function(e,i){var _6a5=this.getChildren();this.paneBefore=_6a5[i];this.paneAfter=_6a5[i+1];this.isSizing=true;this.sizingSplitter=this.sizers[i];if(!this.cover){this.cover=_4.create("div",{style:{position:"absolute",zIndex:5,top:0,left:0,width:"100%",height:"100%"}},this.domNode);}else{this.cover.style.zIndex=5;}this.sizingSplitter.style.zIndex=6;this.originPos=_4.position(_6a5[0].domNode,true);if(this.isHorizontal){var _6a6=e.layerX||e.offsetX||0;var _6a7=e.pageX;this.originPos=this.originPos.x;}else{var _6a6=e.layerY||e.offsetY||0;var _6a7=e.pageY;this.originPos=this.originPos.y;}this.startPoint=this.lastPoint=_6a7;this.screenToClientOffset=_6a7-_6a6;this.dragOffset=this.lastPoint-this.paneBefore.sizeActual-this.originPos-this.paneBefore.position;if(!this.activeSizing){this._showSizingLine();}this._ownconnects=[];this._ownconnects.push(_4.connect(_4.doc.documentElement,"onmousemove",this,"changeSizing"));this._ownconnects.push(_4.connect(_4.doc.documentElement,"onmouseup",this,"endSizing"));_4.stopEvent(e);},changeSizing:function(e){if(!this.isSizing){return;}this.lastPoint=this.isHorizontal?e.pageX:e.pageY;this.movePoint();if(this.activeSizing){this._updateSize();}else{this._moveSizingLine();}_4.stopEvent(e);},endSizing:function(e){if(!this.isSizing){return;}if(this.cover){this.cover.style.zIndex=-1;}if(!this.activeSizing){this._hideSizingLine();}this._updateSize();this.isSizing=false;if(this.persist){this._saveState(this);}_4.forEach(this._ownconnects,_4.disconnect);},movePoint:function(){var p=this.lastPoint-this.screenToClientOffset;var a=p-this.dragOffset;a=this.legaliseSplitPoint(a);p=a+this.dragOffset;this.lastPoint=p+this.screenToClientOffset;},legaliseSplitPoint:function(a){a+=this.sizingSplitter.position;this.isDraggingLeft=!!(a>0);if(!this.activeSizing){var min=this.paneBefore.position+this.paneBefore.sizeMin;if(a<min){a=min;}var max=this.paneAfter.position+(this.paneAfter.sizeActual-(this.sizerWidth+this.paneAfter.sizeMin));if(a>max){a=max;}}a-=this.sizingSplitter.position;this._checkSizes();return a;},_updateSize:function(){var pos=this.lastPoint-this.dragOffset-this.originPos;var _6a8=this.paneBefore.position;var _6a9=this.paneAfter.position+this.paneAfter.sizeActual;this.paneBefore.sizeActual=pos-_6a8;this.paneAfter.position=pos+this.sizerWidth;this.paneAfter.sizeActual=_6a9-this.paneAfter.position;_4.forEach(this.getChildren(),function(_6aa){_6aa.sizeShare=_6aa.sizeActual;});if(this._started){this.layout();}},_showSizingLine:function(){this._moveSizingLine();_4.marginBox(this.virtualSizer,this.isHorizontal?{w:this.sizerWidth,h:this.paneHeight}:{w:this.paneWidth,h:this.sizerWidth});this.virtualSizer.style.display="block";},_hideSizingLine:function(){this.virtualSizer.style.display="none";},_moveSizingLine:function(){var pos=(this.lastPoint-this.startPoint)+this.sizingSplitter.position;_4.style(this.virtualSizer,(this.isHorizontal?"left":"top"),pos+"px");},_getCookieName:function(i){return this.id+"_"+i;},_restoreState:function(){_4.forEach(this.getChildren(),function(_6ab,i){var _6ac=this._getCookieName(i);var _6ad=_4.cookie(_6ac);if(_6ad){var pos=parseInt(_6ad);if(typeof pos=="number"){_6ab.sizeShare=pos;}}},this);},_saveState:function(){if(!this.persist){return;}_4.forEach(this.getChildren(),function(_6ae,i){_4.cookie(this._getCookieName(i),_6ae.sizeShare,{expires:365});},this);}});_4.extend(_5._Widget,{sizeMin:10,sizeShare:10});}if(!_4._hasResource["dijit.layout._TabContainerBase"]){_4._hasResource["dijit.layout._TabContainerBase"]=true;_4.provide("dijit.layout._TabContainerBase");_4.declare("dijit.layout._TabContainerBase",[_5.layout.StackContainer,_5._Templated],{tabPosition:"top",baseClass:"dijitTabContainer",tabStrip:false,nested:false,templateString:_4.cache("dijit.layout","templates/TabContainer.html","<div class=\"dijitTabContainer\">\r\n\t<div class=\"dijitTabListWrapper\" dojoAttachPoint=\"tablistNode\"></div>\r\n\t<div dojoAttachPoint=\"tablistSpacer\" class=\"dijitTabSpacer ${baseClass}-spacer\"></div>\r\n\t<div class=\"dijitTabPaneWrapper ${baseClass}-container\" dojoAttachPoint=\"containerNode\"></div>\r\n</div>\r\n"),postMixInProperties:function(){this.baseClass+=this.tabPosition.charAt(0).toUpperCase()+this.tabPosition.substr(1).replace(/-.*/,"");this.srcNodeRef&&_4.style(this.srcNodeRef,"visibility","hidden");this.inherited(arguments);},buildRendering:function(){this.inherited(arguments);this.tablist=this._makeController(this.tablistNode);if(!this.doLayout){_4.addClass(this.domNode,"dijitTabContainerNoLayout");}if(this.nested){_4.addClass(this.domNode,"dijitTabContainerNested");_4.addClass(this.tablist.containerNode,"dijitTabContainerTabListNested");_4.addClass(this.tablistSpacer,"dijitTabContainerSpacerNested");_4.addClass(this.containerNode,"dijitTabPaneWrapperNested");}else{_4.addClass(this.domNode,"tabStrip-"+(this.tabStrip?"enabled":"disabled"));}},_setupChild:function(tab){_4.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 _6af=this.tabPosition.replace(/-h/,"");this.tablist.layoutAlign=_6af;var _6b0=[this.tablist,{domNode:this.tablistSpacer,layoutAlign:_6af},{domNode:this.containerNode,layoutAlign:"client"}];_5.layout.layoutChildren(this.domNode,this._contentBox,_6b0);this._containerContentBox=_5.layout.marginBox2contentBox(this.containerNode,_6b0[2]);if(sc&&sc.resize){sc.resize(this._containerContentBox);}}else{if(this.tablist.resize){var s=this.tablist.domNode.style;s.width="0";var _6b1=_4.contentBox(this.domNode).w;s.width="";this.tablist.resize({w:_6b1});}if(sc&&sc.resize){sc.resize();}}},destroy:function(){if(this.tablist){this.tablist.destroy();}this.inherited(arguments);}});}if(!_4._hasResource["dijit.layout.TabController"]){_4._hasResource["dijit.layout.TabController"]=true;_4.provide("dijit.layout.TabController");_4.declare("dijit.layout.TabController",_5.layout.StackController,{templateString:"<div role='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 _6b2=0;for(var pane in this.pane2button){var ow=this.pane2button[pane].innerDiv.scrollWidth;_6b2=Math.max(_6b2,ow);}for(pane in this.pane2button){this.pane2button[pane].innerDiv.style.width=_6b2+"px";}}});_4.declare("dijit.layout._TabButton",_5.layout._StackButton,{baseClass:"dijitTab",cssStateNodes:{closeNode:"dijitTabCloseButton"},templateString:_4.cache("dijit.layout","templates/_TabButton.html","<div role=\"presentation\" dojoAttachPoint=\"titleNode\" dojoAttachEvent='onclick:onClick'>\r\n <div role=\"presentation\" class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>\r\n <div role=\"presentation\" class='dijitTabContent' dojoAttachPoint='tabContent'>\r\n \t<div role=\"presentation\" dojoAttachPoint='focusNode'>\r\n\t\t <img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitTabButtonIcon\" dojoAttachPoint='iconNode' />\r\n\t\t <span dojoAttachPoint='containerNode' class='tabLabel'></span>\r\n\t\t <span class=\"dijitInline dijitTabCloseButton dijitTabCloseIcon\" dojoAttachPoint='closeNode'\r\n\t\t \t\tdojoAttachEvent='onclick: onClickCloseButton' role=\"presentation\">\r\n\t\t <span dojoAttachPoint='closeText' class='dijitTabCloseText'>[x]</span\r\n\t\t ></span>\r\n\t\t\t</div>\r\n </div>\r\n </div>\r\n</div>\r\n"),scrollOnFocus:false,buildRendering:function(){this.inherited(arguments);_4.setSelectable(this.containerNode,false);},startup:function(){this.inherited(arguments);var n=this.domNode;setTimeout(function(){n.className=n.className;},1);},_setCloseButtonAttr:function(disp){this._set("closeButton",disp);_4.toggleClass(this.innerDiv,"dijitClosable",disp);this.closeNode.style.display=disp?"":"none";if(disp){var _6b3=_4.i18n.getLocalization("dijit","common");if(this.closeNode){_4.attr(this.closeNode,"title",_6b3.itemClose);}var _6b3=_4.i18n.getLocalization("dijit","common");this._closeMenu=new _5.Menu({id:this.id+"_Menu",dir:this.dir,lang:this.lang,targetNodeIds:[this.domNode]});this._closeMenu.addChild(new _5.MenuItem({label:_6b3.itemClose,dir:this.dir,lang:this.lang,onClick:_4.hitch(this,"onClickCloseButton")}));}else{if(this._closeMenu){this._closeMenu.destroyRecursive();delete this._closeMenu;}}},_setLabelAttr:function(_6b4){this.inherited(arguments);if(this.showLabel==false&&!this.params.title){this.iconNode.alt=_4.trim(this.containerNode.innerText||this.containerNode.textContent||"");}},destroy:function(){if(this._closeMenu){this._closeMenu.destroyRecursive();delete this._closeMenu;}this.inherited(arguments);}});}if(!_4._hasResource["dijit.layout.ScrollingTabController"]){_4._hasResource["dijit.layout.ScrollingTabController"]=true;_4.provide("dijit.layout.ScrollingTabController");_4.declare("dijit.layout.ScrollingTabController",_5.layout.TabController,{templateString:_4.cache("dijit.layout","templates/ScrollingTabController.html","<div class=\"dijitTabListContainer-${tabPosition}\" style=\"visibility:hidden\">\r\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerMenuButton\"\r\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\r\n\t\t\tid=\"${id}_menuBtn\" containerId=\"${containerId}\" iconClass=\"dijitTabStripMenuIcon\"\r\n\t\t\tdropDownPosition=\"below-alt, above-alt\"\r\n\t\t\tdojoAttachPoint=\"_menuBtn\" showLabel=false>&#9660;</div>\r\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\r\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\r\n\t\t\tid=\"${id}_leftBtn\" iconClass=\"dijitTabStripSlideLeftIcon\"\r\n\t\t\tdojoAttachPoint=\"_leftBtn\" dojoAttachEvent=\"onClick: doSlideLeft\" showLabel=false>&#9664;</div>\r\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\r\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\r\n\t\t\tid=\"${id}_rightBtn\" iconClass=\"dijitTabStripSlideRightIcon\"\r\n\t\t\tdojoAttachPoint=\"_rightBtn\" dojoAttachEvent=\"onClick: doSlideRight\" showLabel=false>&#9654;</div>\r\n\t<div class='dijitTabListWrapper' dojoAttachPoint='tablistWrapper'>\r\n\t\t<div role='tablist' dojoAttachEvent='onkeypress:onkeypress'\r\n\t\t\t\tdojoAttachPoint='containerNode' class='nowrapTabStrip'></div>\r\n\t</div>\r\n</div>\r\n"),useMenu:true,useSlider:true,tabStripClass:"",widgetsInTemplate:true,_minScroll:5,attributeMap:_4.delegate(_5._Widget.prototype.attributeMap,{"class":"containerNode"}),buildRendering: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";_4.addClass(n,"tabStrip-disabled");}_4.addClass(this.tablistWrapper,this.tabStripClass);},onStartup:function(){this.inherited(arguments);_4.style(this.domNode,"visibility","visible");this._postStartup=true;},onAddChild:function(page,_6b5){this.inherited(arguments);_4.forEach(["label","iconClass"],function(attr){this.pane2watches[page.id].push(this.pane2button[page.id].watch(attr,_4.hitch(this,function(name,_6b6,_6b7){if(this._postStartup&&this._dim){this.resize(this._dim);}})));},this);_4.style(this.containerNode,"width",(_4.style(this.containerNode,"width")+200)+"px");},onRemoveChild:function(page,_6b8){var _6b9=this.pane2button[page.id];if(this._selectedTab===_6b9.domNode){this._selectedTab=null;}this.inherited(arguments);},_initButtons:function(){this._btnWidth=0;this._buttons=_4.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+=_4._getMarginSize(btn).w;return true;}else{_4.style(btn,"display","none");return false;}},this);},_getTabsWidth:function(){var _6ba=this.getChildren();if(_6ba.length){var _6bb=_6ba[this.isLeftToRight()?0:_6ba.length-1].domNode,_6bc=_6ba[this.isLeftToRight()?_6ba.length-1:0].domNode;return _6bc.offsetLeft+_4.style(_6bc,"width")-_6bb.offsetLeft;}else{return 0;}},_enableBtn:function(_6bd){var _6be=this._getTabsWidth();_6bd=_6bd||_4.style(this.scrollNode,"width");return _6be>0&&_6bd<_6be;},resize:function(dim){if(this.domNode.offsetWidth==0){return;}this._dim=dim;this.scrollNode.style.height="auto";this._contentBox=_5.layout.marginBox2contentBox(this.domNode,{h:0,w:dim.w});this._contentBox.h=this.scrollNode.offsetHeight;_4.contentBox(this.domNode,this._contentBox);var _6bf=this._enableBtn(this._contentBox.w);this._buttons.style("display",_6bf?"":"none");this._leftBtn.layoutAlign="left";this._rightBtn.layoutAlign="right";this._menuBtn.layoutAlign=this.isLeftToRight()?"right":"left";_5.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()||_4.isIE<8||(_4.isIE&&_4.isQuirks)||_4.isWebKit)?this.scrollNode.scrollLeft:_4.style(this.containerNode,"width")-_4.style(this.scrollNode,"width")+(_4.isIE==8?-1:1)*this.scrollNode.scrollLeft;return sl;},_convertToScrollLeft:function(val){if(this.isLeftToRight()||_4.isIE<8||(_4.isIE&&_4.isQuirks)||_4.isWebKit){return val;}else{var _6c0=_4.style(this.containerNode,"width")-_4.style(this.scrollNode,"width");return (_4.isIE==8?-1:1)*(val-_6c0);}},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+_4.style(this.scrollNode,"width")<node.offsetLeft+_4.style(node,"width")){this.createSmoothScroll().play();}}this.inherited(arguments);},_getScrollBounds:function(){var _6c1=this.getChildren(),_6c2=_4.style(this.scrollNode,"width"),_6c3=_4.style(this.containerNode,"width"),_6c4=_6c3-_6c2,_6c5=this._getTabsWidth();if(_6c1.length&&_6c5>_6c2){return {min:this.isLeftToRight()?0:_6c1[_6c1.length-1].domNode.offsetLeft,max:this.isLeftToRight()?(_6c1[_6c1.length-1].domNode.offsetLeft+_4.style(_6c1[_6c1.length-1].domNode,"width"))-_6c2:_6c4};}else{var _6c6=this.isLeftToRight()?0:_6c4;return {min:_6c6,max:_6c6};}},_getScrollForSelectedTab:function(){var w=this.scrollNode,n=this._selectedTab,_6c7=_4.style(this.scrollNode,"width"),_6c8=this._getScrollBounds();var pos=(n.offsetLeft+_4.style(n,"width")/2)-_6c7/2;pos=Math.min(Math.max(pos,_6c8.min),_6c8.max);return pos;},createSmoothScroll:function(x){if(arguments.length>0){var _6c9=this._getScrollBounds();x=Math.min(Math.max(x,_6c9.min),_6c9.max);}else{x=this._getScrollForSelectedTab();}if(this._anim&&this._anim.status()=="playing"){this._anim.stop();}var self=this,w=this.scrollNode,anim=new _4._Animation({beforeBegin:function(){if(this.curve){delete this.curve;}var oldS=w.scrollLeft,newS=self._convertToScrollLeft(x);anim.curve=new _4._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&&!_4.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(_6ca,node){if(node&&_4.hasClass(node,"dijitTabDisabled")){return;}var _6cb=_4.style(this.scrollNode,"width");var d=(_6cb*0.75)*_6ca;var to=this._getScroll()+d;this._setButtonClass(to);this.createSmoothScroll(to).play();},_setButtonClass:function(_6cc){var _6cd=this._getScrollBounds();this._leftBtn.set("disabled",_6cc<=_6cd.min);this._rightBtn.set("disabled",_6cc>=_6cd.max);}});_4.declare("dijit.layout._ScrollingTabControllerButtonMixin",null,{baseClass:"dijitTab tabStripButton",templateString:_4.cache("dijit.layout","templates/_ScrollingTabControllerButton.html","<div dojoAttachEvent=\"onclick:_onButtonClick\">\r\n\t<div role=\"presentation\" class=\"dijitTabInnerDiv\" dojoattachpoint=\"innerDiv,focusNode\">\r\n\t\t<div role=\"presentation\" class=\"dijitTabContent dijitButtonContents\" dojoattachpoint=\"tabContent\">\r\n\t\t\t<img role=\"presentation\" alt=\"\" src=\"${_blankGif}\" class=\"dijitTabStripIcon\" dojoAttachPoint=\"iconNode\"/>\r\n\t\t\t<span dojoAttachPoint=\"containerNode,titleNode\" class=\"dijitButtonText\"></span>\r\n\t\t</div>\r\n\t</div>\r\n</div>\r\n"),tabIndex:"",isFocusable:function(){return false;}});_4.declare("dijit.layout._ScrollingTabControllerButton",[_5.form.Button,_5.layout._ScrollingTabControllerButtonMixin]);_4.declare("dijit.layout._ScrollingTabControllerMenuButton",[_5.form.Button,_5._HasDropDown,_5.layout._ScrollingTabControllerButtonMixin],{containerId:"",tabIndex:"-1",isLoaded:function(){return false;},loadDropDown:function(_6ce){this.dropDown=new _5.Menu({id:this.containerId+"_menu",dir:this.dir,lang:this.lang});var _6cf=_5.byId(this.containerId);_4.forEach(_6cf.getChildren(),function(page){var _6d0=new _5.MenuItem({id:page.id+"_stcMi",label:page.title,iconClass:page.iconClass,dir:page.dir,lang:page.lang,onClick:function(){_6cf.selectChild(page);}});this.dropDown.addChild(_6d0);},this);_6ce();},closeDropDown:function(_6d1){this.inherited(arguments);if(this.dropDown){this.dropDown.destroyRecursive();delete this.dropDown;}}});}if(!_4._hasResource["dijit.layout.TabContainer"]){_4._hasResource["dijit.layout.TabContainer"]=true;_4.provide("dijit.layout.TabContainer");_4.declare("dijit.layout.TabContainer",_5.layout._TabContainerBase,{useMenu:true,useSlider:true,controllerWidget:"",_makeController:function(_6d2){var cls=this.baseClass+"-tabs"+(this.doLayout?"":" dijitTabNoLayout"),_6d3=_4.getObject(this.controllerWidget);return new _6d3({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},_6d2);},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(!_4._hasResource["dijit.dijit-all"]){_4._hasResource["dijit.dijit-all"]=true;_4.provide("dijit.dijit-all");console.warn("dijit-all may include much more code than your application actually requires. We strongly recommend that you investigate a custom build or the web build tool");}}};});
diff --git a/js/dojo-1.6/dijit/dijit-all.xd.js.uncompressed.js b/js/dojo-1.6/dijit/dijit-all.xd.js.uncompressed.js
new file mode 100644
index 0000000..6152185
--- /dev/null
+++ b/js/dojo-1.6/dijit/dijit-all.xd.js.uncompressed.js
@@ -0,0 +1,30112 @@
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojo.colors"],
+["provide", "dijit._PaletteMixin"],
+["provide", "dijit.ColorPalette"],
+["provide", "dijit.Declaration"],
+["provide", "dojo.dnd.common"],
+["provide", "dojo.dnd.autoscroll"],
+["provide", "dojo.dnd.Mover"],
+["provide", "dojo.dnd.Moveable"],
+["provide", "dojo.dnd.move"],
+["provide", "dojo.dnd.TimedMoveable"],
+["provide", "dojo.fx.Toggler"],
+["provide", "dojo.fx"],
+["provide", "dijit.form._FormMixin"],
+["provide", "dijit._DialogMixin"],
+["provide", "dijit.DialogUnderlay"],
+["provide", "dijit.layout._ContentPaneResizeMixin"],
+["provide", "dojo.html"],
+["provide", "dijit.layout.ContentPane"],
+["provide", "dijit.TooltipDialog"],
+["provide", "dijit.Dialog"],
+["provide", "dijit._editor.selection"],
+["provide", "dijit._editor.range"],
+["provide", "dijit._editor.html"],
+["provide", "dijit._editor.RichText"],
+["provide", "dijit._KeyNavContainer"],
+["provide", "dijit.ToolbarSeparator"],
+["provide", "dijit.Toolbar"],
+["provide", "dijit._HasDropDown"],
+["provide", "dijit.form.Button"],
+["provide", "dijit._editor._Plugin"],
+["provide", "dijit._editor.plugins.EnterKeyHandling"],
+["provide", "dijit.Editor"],
+["provide", "dojo.regexp"],
+["provide", "dojo.data.util.sorter"],
+["provide", "dojo.data.util.simpleFetch"],
+["provide", "dojo.data.util.filter"],
+["provide", "dijit.form.TextBox"],
+["provide", "dijit.Tooltip"],
+["provide", "dijit.form.ValidationTextBox"],
+["provide", "dijit.form.ComboBox"],
+["provide", "dijit.form.FilteringSelect"],
+["provide", "dojo.data.ItemFileReadStore"],
+["provide", "dijit._editor.plugins.FontChoice"],
+["provide", "dijit.form._FormSelectWidget"],
+["provide", "dijit.MenuItem"],
+["provide", "dijit.PopupMenuItem"],
+["provide", "dijit.CheckedMenuItem"],
+["provide", "dijit.MenuSeparator"],
+["provide", "dijit.Menu"],
+["provide", "dijit.form.Select"],
+["provide", "dijit._editor.plugins.LinkDialog"],
+["provide", "dijit.MenuBar"],
+["provide", "dijit.MenuBarItem"],
+["provide", "dijit.PopupMenuBarItem"],
+["provide", "dojo.number"],
+["provide", "dijit.ProgressBar"],
+["provide", "dijit.TitlePane"],
+["provide", "dojo.DeferredList"],
+["provide", "dojo.cookie"],
+["provide", "dijit.tree.TreeStoreModel"],
+["provide", "dijit.tree.ForestStoreModel"],
+["provide", "dojo.dnd.Container"],
+["provide", "dijit.tree._dndContainer"],
+["provide", "dijit.tree._dndSelector"],
+["provide", "dijit.Tree"],
+["provide", "dijit.InlineEditBox"],
+["provide", "dijit.form.Form"],
+["provide", "dijit.form.DropDownButton"],
+["provide", "dijit.form.ComboButton"],
+["provide", "dijit.form.ToggleButton"],
+["provide", "dijit.form.CheckBox"],
+["provide", "dijit.form.RadioButton"],
+["provide", "dojo.cldr.monetary"],
+["provide", "dojo.currency"],
+["provide", "dijit.form.NumberTextBox"],
+["provide", "dijit.form.CurrencyTextBox"],
+["provide", "dojo.cldr.supplemental"],
+["provide", "dojo.date"],
+["provide", "dojo.date.locale"],
+["provide", "dijit.Calendar"],
+["provide", "dijit.form._DateTimeTextBox"],
+["provide", "dijit.form.DateTextBox"],
+["provide", "dijit.form._Spinner"],
+["provide", "dijit.form.NumberSpinner"],
+["provide", "dijit.form.MultiSelect"],
+["provide", "dijit.form.HorizontalSlider"],
+["provide", "dijit.form.VerticalSlider"],
+["provide", "dijit.form.HorizontalRule"],
+["provide", "dijit.form.VerticalRule"],
+["provide", "dijit.form.HorizontalRuleLabels"],
+["provide", "dijit.form.VerticalRuleLabels"],
+["provide", "dijit.form.SimpleTextarea"],
+["provide", "dijit.form.Textarea"],
+["provide", "dijit.layout.StackController"],
+["provide", "dijit.layout.StackContainer"],
+["provide", "dijit.layout.AccordionPane"],
+["provide", "dijit.layout.AccordionContainer"],
+["provide", "dijit.layout.BorderContainer"],
+["provide", "dijit.layout.LayoutContainer"],
+["provide", "dijit.layout.LinkPane"],
+["provide", "dijit.layout.SplitContainer"],
+["provide", "dijit.layout._TabContainerBase"],
+["provide", "dijit.layout.TabController"],
+["provide", "dijit.layout.ScrollingTabController"],
+["provide", "dijit.layout.TabContainer"],
+["provide", "dijit.dijit-all"],
+["i18n._preloadLocalizations", "dijit.nls.dijit-all", ["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"]]],
+defineResource: function(dojo, dijit, dojox){/*
+ Copyright (c) 2004-2011, 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
+*/
+
+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");
+
+
+dojo.getObject("colors", true, dojo);
+
+//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["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 selected cell
+ 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;
+
+ dojo.addClass(this._cells[i].node, "dijitPaletteCellSelected");
+
+ if(priorityChange || priorityChange === undefined){
+ this.onChange(value);
+ }
+
+ break;
+ }
+ }
+ }
+
+ // record new value, or null if no matching cell
+ this._set("value", this._selectedCell >= 0 ? value : null);
+ },
+
+ 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: [const] 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\">\r\n\t<img class=\"dijitColorPaletteUnder\" dojoAttachPoint=\"imageNode\" role=\"presentation\" alt=\"\"/>\r\n\t<table class=\"dijitPaletteTable\" cellSpacing=\"0\" cellPadding=\"0\">\r\n\t\t<tbody dojoAttachPoint=\"gridNode\"></tbody>\r\n\t</table>\r\n</div>\r\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["dijit.Declaration"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.Declaration"] = true;
+dojo.provide("dijit.Declaration");
+
+
+
+
+
+dojo.declare(
+ "dijit.Declaration",
+ dijit._Widget,
+ {
+ // summary:
+ // The Declaration widget allows a developer to declare new widget
+ // classes directly from a snippet of markup.
+
+ // _noScript: [private] Boolean
+ // Flag to parser to leave alone the script tags contained inside of me
+ _noScript: true,
+
+ // stopParser: [private] Boolean
+ // Flag to parser to not try and parse widgets declared inside of me
+ stopParser: true,
+
+ // widgetClass: [const] String
+ // Name of class being declared, ex: "acme.myWidget"
+ widgetClass: "",
+
+ // propList: [const] Object
+ // Set of attributes for this widget along with default values, ex:
+ // {delay: 100, title: "hello world"}
+ defaults: null,
+
+ // mixins: [const] String[]
+ // List containing the prototype for this widget, and also any mixins,
+ // ex: ["dijit._Widget", "dijit._Container"]
+ mixins: [],
+
+ buildRendering: function(){
+ var src = this.srcNodeRef.parentNode.removeChild(this.srcNodeRef),
+ methods = dojo.query("> script[type^='dojo/method']", src).orphan(),
+ connects = dojo.query("> script[type^='dojo/connect']", src).orphan(),
+ srcType = src.nodeName;
+
+ var propList = this.defaults || {};
+
+ // For all methods defined like <script type="dojo/method" data-dojo-event="foo">,
+ // add that method to prototype.
+ // If there's no "event" specified then it's code to run on instantiation,
+ // so it becomes a connection to "postscript" (handled below).
+ dojo.forEach(methods, function(s){
+ var evt = s.getAttribute("event") || s.getAttribute("data-dojo-event"),
+ func = dojo.parser._functionFromScript(s);
+ if(evt){
+ propList[evt] = func;
+ }else{
+ connects.push(s);
+ }
+ });
+
+ // map array of strings like [ "dijit.form.Button" ] to array of mixin objects
+ // (note that dojo.map(this.mixins, dojo.getObject) doesn't work because it passes
+ // a bogus third argument to getObject(), confusing it)
+ this.mixins = this.mixins.length ?
+ dojo.map(this.mixins, function(name){ return dojo.getObject(name); } ) :
+ [ dijit._Widget, dijit._Templated ];
+
+ propList.widgetsInTemplate = true;
+ propList._skipNodeCache = true;
+ propList.templateString = "<"+srcType+" class='"+src.className+"' dojoAttachPoint='"+(src.getAttribute("dojoAttachPoint") || '')+"' dojoAttachEvent='"+(src.getAttribute("dojoAttachEvent") || '')+"' >"+src.innerHTML.replace(/\%7B/g,"{").replace(/\%7D/g,"}")+"</"+srcType+">";
+
+ // strip things so we don't create stuff under us in the initial setup phase
+ dojo.query("[dojoType]", src).forEach(function(node){
+ node.removeAttribute("dojoType");
+ });
+
+ // create the new widget class
+ var wc = dojo.declare(
+ this.widgetClass,
+ this.mixins,
+ propList
+ );
+
+ // Handle <script> blocks of form:
+ // <script type="dojo/connect" data-dojo-event="foo">
+ // and
+ // <script type="dojo/method">
+ // (Note that the second one is just shorthand for a dojo/connect to postscript)
+ // Since this is a connect in the declaration, we are actually connection to the method
+ // in the _prototype_.
+ dojo.forEach(connects, function(s){
+ var evt = s.getAttribute("event") || s.getAttribute("data-dojo-event") || "postscript",
+ func = dojo.parser._functionFromScript(s);
+ dojo.connect(wc.prototype, evt, func);
+ });
+ }
+ }
+);
+
+}
+
+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.getObject("dnd", true, dojo);
+
+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.getObject("dnd", true, dojo);
+
+dojo.dnd.getViewport = dojo.window.getBox;
+
+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.window.getBox(), 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, or touch-drag on touch devices.
+ // 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);
+ var pos = e.touches ? e.touches[0] : e;
+ this.marginBox = {l: pos.pageX, t: pos.pageY};
+ this.mouseButton = e.button;
+ var h = (this.host = host), d = node.ownerDocument;
+ this.events = [
+ // At the start of a drag, onFirstMove is called, and then the following two
+ // connects are disconnected
+ dojo.connect(d, "onmousemove", this, "onFirstMove"),
+ dojo.connect(d, "ontouchmove", this, "onFirstMove"),
+
+ // These are called continually during the drag
+ dojo.connect(d, "onmousemove", this, "onMouseMove"),
+ dojo.connect(d, "ontouchmove", this, "onMouseMove"),
+
+ // And these are called at the end of the drag
+ dojo.connect(d, "onmouseup", this, "onMouseUp"),
+ dojo.connect(d, "ontouchend", this, "onMouseUp"),
+
+ // cancel text selection and text dragging
+ dojo.connect(d, "ondragstart", dojo.stopEvent),
+ dojo.connect(d.body, "onselectstart", dojo.stopEvent)
+ ];
+ // notify that the move has started
+ if(h && h.onMoveStart){
+ h.onMoveStart(this);
+ }
+ },
+ // mouse event processors
+ onMouseMove: function(e){
+ // summary:
+ // event processor for onmousemove/ontouchmove
+ // e: Event
+ // mouse/touch event
+ dojo.dnd.autoScroll(e);
+ var m = this.marginBox,
+ pos = e.touches ? e.touches[0] : e;
+ this.host.onMove(this, {l: m.l + pos.pageX, t: m.t + pos.pageY}, e);
+ dojo.stopEvent(e);
+ },
+ onMouseUp: function(e){
+ if(dojo.isWebKit && dojo.isMac && this.mouseButton == 2 ?
+ e.button == 0 : this.mouseButton == e.button){ // TODO Should condition be met for touch devices, too?
+ 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);
+ }
+
+ // Disconnect onmousemove and ontouchmove events that call this function
+ dojo.disconnect(this.events.shift());
+ dojo.disconnect(this.events.shift());
+ },
+ 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"),
+ dojo.connect(this.handle, "ontouchstart", 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/ontouchstart, creates a Mover for the node
+ // e: Event
+ // mouse/touch 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, "ontouchmove", this, "onMouseMove"),
+ dojo.connect(this.handle, "onmouseup", this, "onMouseUp"),
+ dojo.connect(this.handle, "ontouchend", this, "onMouseUp")
+ );
+ var pos = e.touches ? e.touches[0] : e;
+ this._lastX = pos.pageX;
+ this._lastY = pos.pageY;
+ }else{
+ this.onDragDetected(e);
+ }
+ dojo.stopEvent(e);
+ },
+ onMouseMove: function(e){
+ // summary:
+ // event processor for onmousemove/ontouchmove, used only for delayed drags
+ // e: Event
+ // mouse/touch event
+ var pos = e.touches ? e.touches[0] : e;
+ if(Math.abs(pos.pageX - this._lastX) > this.delay || Math.abs(pos.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._getMarginSize(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;
+ this.onMoving(mover, leftTop);
+ leftTop.l = leftTop.l < c.l ? c.l : c.r < leftTop.l ? c.r : leftTop.l;
+ leftTop.t = leftTop.t < c.t ? c.t : c.b < leftTop.t ? c.b : leftTop.t;
+ s.left = leftTop.l + "px";
+ s.top = leftTop.t + "px";
+ this.onMoved(mover, leftTop);
+ }
+});
+
+/*=====
+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
+ };
+ }
+});
+
+// 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["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");
+
+
+
+
+/*=====
+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["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"] }
+=====*/
+
+ // state: [readonly] String
+ // Will be "Error" if one or more of the child widgets has an invalid value,
+ // "Incomplete" if not all of the required child widgets are filled in. Otherwise, "",
+ // which indicates that the form is ready to be submitted.
+ state: "",
+
+ // 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 get('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 set('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;
+ }
+ });
+ */
+
+ // Note: no need to call this._set("value", ...) as the child updates will trigger onChange events
+ // which I am monitoring.
+ },
+
+ 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. See description of `value` for details.
+ // description:
+
+ // The value is updated into this.value every time a child has an onChange event,
+ // so in the common case this function could just return this.value. However,
+ // that wouldn't work when:
+ //
+ // 1. User presses return key to submit a form. That doesn't fire an onchange event,
+ // and even if it did it would come too late due to the setTimout(..., 0) in _handleOnChange()
+ //
+ // 2. app for some reason calls this.get("value") while the user is typing into a
+ // form field. Not sure if that case needs to be supported or not.
+
+ // 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;
+ },
+
+ isValid: function(){
+ // summary:
+ // Returns true if all of the widgets are valid.
+ // Deprecated, will be removed in 2.0. Use get("state") instead.
+
+ return this.state == "";
+ },
+
+ 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.
+ //
+ // Deprecated. Will be removed in 2.0. Use watch("state", ...) instead.
+ },
+
+ _getState: function(){
+ // summary:
+ // Compute what this.state should be based on state of children
+ var states = dojo.map(this._descendants, function(w){
+ return w.get("state") || "";
+ });
+
+ return dojo.indexOf(states, "Error") >= 0 ? "Error" :
+ dojo.indexOf(states, "Incomplete") >= 0 ? "Incomplete" : "";
+ },
+
+ disconnectChildren: function(){
+ // summary:
+ // Remove connections to monitor changes to children's value, error state, and disabled state,
+ // in order to update Form.value and Form.state.
+ dojo.forEach(this._childConnections || [], dojo.hitch(this, "disconnect"));
+ dojo.forEach(this._childWatches || [], function(w){ w.unwatch(); });
+ },
+
+ connectChildren: function(/*Boolean*/ inStartup){
+ // summary:
+ // Setup connections to monitor changes to children's value, error state, and disabled state,
+ // in order to update Form.value and Form.state.
+ //
+ // 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.
+
+ var _this = this;
+
+ // Remove old connections, if any
+ this.disconnectChildren();
+
+ this._descendants = this.getDescendants();
+
+ // (Re)set this.value and this.state. Send watch() notifications but not on startup.
+ var set = inStartup ? function(name, val){ _this[name] = val; } : dojo.hitch(this, "_set");
+ set("value", this.get("value"));
+ set("state", this._getState());
+
+ // Monitor changes to error state and disabled state in order to update
+ // Form.state
+ var conns = (this._childConnections = []),
+ watches = (this._childWatches = []);
+ dojo.forEach(dojo.filter(this._descendants,
+ function(item){ return item.validate; }
+ ),
+ function(widget){
+ // We are interested in whenever the widget changes validity state - or
+ // whenever the disabled attribute on that widget is changed.
+ dojo.forEach(["state", "disabled"], function(attr){
+ watches.push(widget.watch(attr, function(attr, oldVal, newVal){
+ _this.set("state", _this._getState());
+ }));
+ });
+ });
+
+ // And monitor calls to child.onChange so we can update this.value
+ var onChange = function(){
+ // summary:
+ // Called when child's value or disabled state changes
+
+ // Use setTimeout() to collapse value changes in multiple children into a single
+ // update to my value. Multiple updates will occur on:
+ // 1. Form.set()
+ // 2. Form.reset()
+ // 3. user selecting a radio button (which will de-select another radio button,
+ // causing two onChange events)
+ if(_this._onChangeDelayTimer){
+ clearTimeout(_this._onChangeDelayTimer);
+ }
+ _this._onChangeDelayTimer = setTimeout(function(){
+ delete _this._onChangeDelayTimer;
+ _this._set("value", _this.get("value"));
+ }, 10);
+ };
+ dojo.forEach(
+ dojo.filter(this._descendants, function(item){ return item.onChange; } ),
+ function(widget){
+ // When a child widget's value changes,
+ // the efficient thing to do is to just update that one attribute in this.value,
+ // but that gets a little complicated when a checkbox is checked/unchecked
+ // since this.value["checkboxName"] contains an array of all the checkboxes w/the same name.
+ // Doing simple thing for now.
+ conns.push(_this.connect(widget, "onChange", onChange));
+
+ // Disabling/enabling a child widget should remove it's value from this.value.
+ // Again, this code could be more efficient, doing simple thing for now.
+ watches.push(widget.watch("disabled", onChange));
+ }
+ );
+ },
+
+ startup: function(){
+ this.inherited(arguments);
+
+ // Initialize value and valid/invalid state tracking. Needs to be done in startup()
+ // so that children are initialized.
+ this.connectChildren(true);
+
+ // Make state change call onValidStateChange(), will be removed in 2.0
+ this.watch("state", function(attr, oldVal, newVal){ this.onValidStateChange(newVal == ""); });
+ },
+
+ destroy: function(){
+ this.disconnectChildren();
+ this.inherited(arguments);
+ }
+
+ });
+
+}
+
+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(){
+ // summary:
+ // Finds focusable items in dialog,
+ // and sets this._firstFocusItem and this._lastFocusItem
+ // tags:
+ // protected
+
+ var elems = dijit._getTabNavigable(this.containerNode);
+ this._firstFocusItem = elems.lowest || elems.first || this.closeButtonNode || this.domNode;
+ this._lastFocusItem = elems.last || elems.highest || this._firstFocusItem;
+ }
+ }
+);
+
+}
+
+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");
+ this._set("dialogId", id);
+ },
+
+ _setClassAttr: function(clazz){
+ this.node.className = "dijitDialogUnderlay " + clazz;
+ this._set("class", 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();
+ delete this.bgIframe;
+ this.domNode.style.display = "none";
+ }
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit.layout._ContentPaneResizeMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout._ContentPaneResizeMixin"] = true;
+dojo.provide("dijit.layout._ContentPaneResizeMixin");
+
+
+
+
+dojo.declare("dijit.layout._ContentPaneResizeMixin", null, {
+ // summary:
+ // Resize() functionality of ContentPane. If there's a single layout widget
+ // child then it will call resize() with the same dimensions as the ContentPane.
+ // Otherwise just calls resize on each child.
+ //
+ // Also implements basic startup() functionality, where starting the parent
+ // will start the children
+
+ // 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,
+
+ // 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,
+
+ _startChildren: function(){
+ // summary:
+ // Call startup() on all children including non _Widget ones like dojo.dnd.Source objects
+
+ // This starts all the widgets
+ dojo.forEach(this.getChildren(), function(child){
+ child.startup();
+ child._started = true;
+ });
+ },
+
+ 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;
+
+ this.inherited(arguments);
+
+ this._startChildren();
+ },
+
+ _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 propagate 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, "data-dojo-type") || 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);
+ },
+
+ resize: function(changeSize, resultSize){
+ // summary:
+ // See `dijit.layout._LayoutWidget.resize` for description.
+ // Although ContentPane doesn't extend _LayoutWidget, it does implement
+ // the same API.
+ this._layout(changeSize, resultSize);
+ },
+
+ _layout: function(changeSize, resultSize){
+ // summary:
+ // Resize myself according to optional changeSize/resultSize parameters, like a layout widget.
+ // Also, since I am a Container widget, each of my children expects me to
+ // call resize() or layout() on them.
+ //
+ // Should be called on initialization and also whenever we get new content
+ // (from an href, or from set('content', ...))... but deferred until
+ // the ContentPane is visible
+
+ // 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);
+ }
+
+ this._layoutChildren();
+
+ delete this._needLayout;
+ },
+
+ _layoutChildren: function(){
+ // Call _checkIfSingleChild() again in case app has manually mucked w/the content
+ // of the ContentPane (rather than changing it through the set("content", ...) API.
+ 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();
+ }
+ });
+ }
+ }
+});
+
+}
+
+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.getObject("html", true, dojo);
+
+// 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,
+
+ // parserScope: String
+ // Flag passed to parser. Root for attribute names to search for. If scopeName is dojo,
+ // will search for data-dojo-type (or dojoType). For backwards compatibility
+ // reasons defaults to dojo._scopeName (which is "dojo" except when
+ // multi-version support is used, when it will be something like dojo16, dojo20, etc.)
+ parserScope: dojo._scopeName,
+
+ // startup: Boolean
+ // Start the child widgets after parsing them. Only obeyed if parseContent is true.
+ startup: true,
+
+ // 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,
+ noStart: !this.startup,
+ inherited: {
+ dir: this.dir,
+ lang: this.lang
+ },
+ scope: this.parserScope
+ });
+ }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");
+
+
+
+
+
+
+
+
+
+dojo.declare(
+ "dijit.layout.ContentPane", [dijit._Widget, dijit.layout._ContentPaneResizeMixin],
+{
+ // summary:
+ // A widget containing an HTML fragment, specified inline
+ // or by uri. Fragment may include widgets.
+ //
+ // description:
+ // This widget embeds a document fragment in the page, specified
+ // either by uri, javascript generated markup or DOM reference.
+ // Any widgets within this content are instantiated and managed,
+ // but laid out according to the HTML structure. Unlike IFRAME,
+ // ContentPane embeds a document fragment as would be found
+ // inside the BODY tag of a full HTML document. It should not
+ // contain the HTML, HEAD, or BODY tags.
+ // For more advanced functionality with scripts and
+ // stylesheets, see dojox.layout.ContentPane. This widget may be
+ // used stand alone or as a base class for other widgets.
+ // ContentPane is useful as a child of other layout containers
+ // such as BorderContainer or TabContainer, but note that those
+ // widgets can contain any widget as a child.
+ //
+ // example:
+ // Some quick samples:
+ // To change the innerHTML: cp.set('content', '<b>new content</b>')
+ //
+ // Or you can send it a NodeList: cp.set('content', dojo.query('div [class=selected]', userSelection))
+ //
+ // To do an ajax update: cp.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 set("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,
+
+ // parserScope: String
+ // Flag passed to parser. Root for attribute names to search for. If scopeName is dojo,
+ // will search for data-dojo-type (or dojoType). For backwards compatibility
+ // reasons defaults to dojo._scopeName (which is "dojo" except when
+ // multi-version support is used, when it will be something like dojo16, dojo20, etc.)
+ parserScope: dojo._scopeName,
+
+ // 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 set('content', ...) / set('href', ...)
+ //
+ // False if it doesn't have any content, or if ContentPane is
+ // still in the process of downloading href.
+ isLoaded: false,
+
+ baseClass: "dijitContentPane",
+
+ // ioArgs: Object
+ // Parameters to pass to xhrGet() request, for example:
+ // | <div dojoType="dijit.layout.ContentPane" href="./bar" ioArgs="{timeout: 500}">
+ ioArgs: {},
+
+ // onLoadDeferred: [readonly] dojo.Deferred
+ // This is the `dojo.Deferred` returned by set('href', ...) and refresh().
+ // Calling onLoadDeferred.addCallback() or addErrback() registers your
+ // callback to be called only once, when the prior set('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
+ // or content 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: []
+ }),
+
+ // Flag to parser that I'll parse my contents, so it shouldn't.
+ stopParser: true,
+
+ // template: [private] Boolean
+ // Flag from the parser that this ContentPane is inside a template
+ // so the contents are pre-parsed.
+ // (TODO: this declaration can be commented out in 2.0)
+ template: false,
+
+ create: function(params, srcNodeRef){
+ // Convert a srcNodeRef argument into a content parameter, so that the original contents are
+ // processed in the same way as contents set via set("content", ...), calling the parser etc.
+ // Avoid modifying original params object since that breaks NodeList instantiation, see #11906.
+ if((!params || !params.template) && srcNodeRef && !("href" in params) && !("content" in params)){
+ var df = dojo.doc.createDocumentFragment();
+ srcNodeRef = dojo.byId(srcNodeRef)
+ while(srcNodeRef.firstChild){
+ df.appendChild(srcNodeRef.firstChild);
+ }
+ params = dojo.delegate(params, {content: df});
+ }
+ this.inherited(arguments, [params, srcNodeRef]);
+ },
+
+ 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);
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ // Since we have no template we need to set this.containerNode ourselves, to make getChildren() work.
+ // For subclasses of ContentPane that do have a template, does nothing.
+ if(!this.containerNode){
+ this.containerNode = this.domNode;
+ }
+
+ // remove the title attribute so it doesn't show up when hovering
+ // over a node (TODO: remove in 2.0, no longer needed after #11490)
+ this.domNode.title = "";
+
+ if(!dojo.attr(this.domNode,"role")){
+ dijit.setWaiRole(this.domNode, "group");
+ }
+ },
+
+ _startChildren: function(){
+ // summary:
+ // Call startup() on all children including non _Widget ones like dojo.dnd.Source objects
+
+ // This starts all the widgets
+ this.inherited(arguments);
+
+ // And this catches stuff like dojo.dnd.Source
+ if(this._contentSetter){
+ dojo.forEach(this._contentSetter.parseResults, function(obj){
+ if(!obj._started && !obj._destroyed && dojo.isFunction(obj.startup)){
+ obj.startup();
+ obj._started = true;
+ }
+ }, this);
+ }
+ },
+
+ 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; }
+
+ this.inherited(arguments);
+
+ if(this._isShown()){
+ this._onShow();
+ }
+ },
+
+ 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 set("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 (a set('href', ...) will cancel any in-flight set('href', ...))
+ this.cancel();
+
+ this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));
+ this.onLoadDeferred.addCallback(dojo.hitch(this, "onLoad"));
+
+ this._set("href", href);
+
+ // _setHrefAttr() is called during creation and by the user, after creation.
+ // Assuming preload == false, only in the second case do we actually load the URL;
+ // otherwise it's done in startup(), and only if this widget is shown.
+ if(this.preload || (this._created && 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 set("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._set("href", "");
+
+ // Cancel any in-flight requests (a set('content', ...) will cancel any in-flight set('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"));
+ if(this._created){
+ // For back-compat reasons, call onLoad() for set('content', ...)
+ // calls but not for content specified in srcNodeRef (ie: <div dojoType=ContentPane>...</div>)
+ // or as initialization parameter (ie: new ContentPane({content: ...})
+ this.onLoadDeferred.addCallback(dojo.hitch(this, "onLoad"));
+ }
+
+ this._setContent(data || "");
+
+ this._isDownloaded = false; // mark that content is from a set('content') not a set('href')
+
+ return this.onLoadDeferred; // dojo.Deferred
+ },
+ _getContentAttr: function(){
+ // summary:
+ // Hook to make get("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 (see [20099]).
+ // However, don't load href for closed TitlePanes.
+ if(!this._wasShown && this.open !== false){
+ this._onShow();
+ }
+
+ this._resizeCalled = true;
+
+ this._scheduleLayout(changeSize, resultSize);
+ },
+
+ _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{
+ var node = this.domNode, parent = this.domNode.parentNode;
+ return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !dojo.hasClass(node, "dijitHidden") &&
+ parent && parent.style && (parent.style.display != 'none');
+ }
+ },
+
+ _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)
+ ){
+ var d = this.refresh();
+ }
+ }else{
+ if(this._needLayout){
+ // If a layout has been scheduled for when we become visible, do it now
+ this._layout(this._changeSize, this._resultSize);
+ }
+ }
+
+ 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;
+
+ return d; // If child has an href, promise that fires when the load is complete
+ },
+
+ 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.onLoadDeferred.addCallback(dojo.hitch(this, "onLoad"));
+ this._load();
+ return this.onLoadDeferred; // If child has an href, promise that fires when refresh is complete
+ },
+
+ _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._set("isLoaded", true);
+ try{
+ this.onLoadDeferred.callback(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._set("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(/*String|DocumentFragment*/ cont, /*Boolean*/ 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,
+ parserScope: this.parserScope,
+ startup: false,
+ dir: this.dir,
+ lang: this.lang
+ }, this._contentSetterParams || {});
+
+ setter.set( (dojo.isObject(cont) && cont.domNode) ? cont.domNode : cont, setterParams );
+
+ // setter params must be pulled afresh from the ContentPane each time
+ delete this._contentSetterParams;
+
+ if(this.doLayout){
+ this._checkIfSingleChild();
+ }
+
+ if(!isFakeContent){
+ if(this._started){
+ // Startup each top level child widget (and they will start their children, recursively)
+ this._startChildren();
+
+ // 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
+ // override 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(changeSize, resultSize){
+ // summary:
+ // Resize myself, and 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._layout(changeSize, resultSize);
+ }else{
+ this._needLayout = true;
+ this._changeSize = changeSize;
+ this._resultSize = resultSize;
+ }
+ },
+
+ // 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 role=\"presentation\" tabIndex=\"-1\">\r\n\t<div class=\"dijitTooltipContainer\" role=\"presentation\">\r\n\t\t<div class =\"dijitTooltipContents dijitTooltipFocusNode\" dojoAttachPoint=\"containerNode\" role=\"dialog\"></div>\r\n\t</div>\r\n\t<div class=\"dijitTooltipConnector\" role=\"presentation\"></div>\r\n</div>\r\n"),
+
+ _setTitleAttr: function(/*String*/ title){
+ this.containerNode.title = title;
+ this._set("title", title)
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.connect(this.containerNode, "onkeypress", "_onKey");
+ },
+
+ 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 newC = "dijitTooltipAB" + (corner.charAt(1) == 'L' ? "Left" : "Right")
+ + " dijitTooltip"
+ + (corner.charAt(0) == 'T' ? "Below" : "Above");
+
+ dojo.replaceClass(this.domNode, newC, this._currentOrientClass || "");
+ this._currentOrientClass = newC;
+ },
+
+ focus: function(){
+ // summary:
+ // Focus on first field
+ this._getFocusItems(this.containerNode);
+ dijit.focus(this._firstFocusItem);
+ },
+
+ 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
+ },
+
+ 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/TooltipDialog required for back-compat. TODO: remove in 2.0
+
+/*=====
+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\" role=\"dialog\" aria-labelledby=\"${id}_title\">\r\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\">\r\n\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\"></span>\r\n\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" dojoAttachEvent=\"ondijitclick: onCancel\" title=\"${buttonCancel}\" role=\"button\" tabIndex=\"-1\">\r\n\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\r\n\t</span>\r\n\t</div>\r\n\t\t<div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\r\n</div>\r\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: [readonly] 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 overridden.
+ // 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 && dijit._DialogLevelManager.isTop(this)){
+ 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 });
+ this._dndListener = 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(" ")
+ };
+ },
+
+ _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._getMarginSize(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
+
+ 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
+ // returns: dojo.Deferred
+ // Deferred object that resolves when the display animation is complete
+
+ if(this.open){ return; }
+
+ if(!this._started){
+ this.startup();
+ }
+
+ // first time we show the dialog, there's some initialization stuff to do
+ if(!this._alreadyInitialized){
+ this._setup();
+ this._alreadyInitialized=true;
+ }
+
+ if(this._fadeOutDeferred){
+ this._fadeOutDeferred.cancel();
+ }
+
+ 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(this.domNode, "onkeypress", this, "_onKey"));
+
+ dojo.style(this.domNode, {
+ opacity:0,
+ display:""
+ });
+
+ this._set("open", true);
+ this._onShow(); // lazy load trigger
+
+ this._size();
+ this._position();
+
+ // fade-in Animation object, setup below
+ var fadeIn;
+
+ this._fadeInDeferred = new dojo.Deferred(dojo.hitch(this, function(){
+ fadeIn.stop();
+ delete this._fadeInDeferred;
+ }));
+
+ fadeIn = dojo.fadeIn({
+ node: this.domNode,
+ duration: this.duration,
+ beforeBegin: dojo.hitch(this, function(){
+ dijit._DialogLevelManager.show(this, this.underlayAttrs);
+ }),
+ onEnd: dojo.hitch(this, function(){
+ if(this.autofocus && dijit._DialogLevelManager.isTop(this)){
+ // 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._fadeInDeferred.callback(true);
+ delete this._fadeInDeferred;
+ })
+ }).play();
+
+ return this._fadeInDeferred;
+ },
+
+ hide: function(){
+ // summary:
+ // Hide the dialog
+ // returns: dojo.Deferred
+ // Deferred object that resolves when the hide animation is complete
+
+ // if we haven't been initialized yet then we aren't showing and we can just return
+ if(!this._alreadyInitialized){
+ return;
+ }
+ if(this._fadeInDeferred){
+ this._fadeInDeferred.cancel();
+ }
+
+ // fade-in Animation object, setup below
+ var fadeOut;
+
+ this._fadeOutDeferred = new dojo.Deferred(dojo.hitch(this, function(){
+ fadeOut.stop();
+ delete this._fadeOutDeferred;
+ }));
+
+ fadeOut = dojo.fadeOut({
+ node: this.domNode,
+ duration: this.duration,
+ onEnd: dojo.hitch(this, function(){
+ this.domNode.style.display = "none";
+ dijit._DialogLevelManager.hide(this);
+ this.onHide();
+ this._fadeOutDeferred.callback(true);
+ delete this._fadeOutDeferred;
+ })
+ }).play();
+
+ if(this._scrollConnected){
+ this._scrollConnected = false;
+ }
+ dojo.forEach(this._modalconnects, dojo.disconnect);
+ this._modalconnects = [];
+
+ if(this._relativePosition){
+ delete this._relativePosition;
+ }
+ this._set("open", false);
+
+ return this._fadeOutDeferred;
+ },
+
+ 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(){
+ if(this._fadeInDeferred){
+ this._fadeInDeferred.cancel();
+ }
+ if(this._fadeOutDeferred){
+ this._fadeOutDeferred.cancel();
+ }
+ if(this._moveable){
+ this._moveable.destroy();
+ }
+ if(this._dndListener){
+ dojo.unsubscribe(this._dndListener);
+ }
+ dojo.forEach(this._modalconnects, dojo.disconnect);
+
+ dijit._DialogLevelManager.hide(this);
+
+ this.inherited(arguments);
+ }
+ }
+);
+
+dojo.declare(
+ "dijit.Dialog",
+ [dijit.layout.ContentPane, dijit._DialogBase],
+ {}
+);
+
+dijit._DialogLevelManager = {
+ // summary:
+ // Controls the various active "levels" on the page, starting with the
+ // stuff initially visible on the page (at z-index 0), and then having an entry for
+ // each Dialog shown.
+
+ show: function(/*dijit._Widget*/ dialog, /*Object*/ underlayAttrs){
+ // summary:
+ // Call right before fade-in animation for new dialog.
+ // Saves current focus, displays/adjusts underlay for new dialog,
+ // and sets the z-index of the dialog itself.
+ //
+ // New dialog will be displayed on top of all currently displayed dialogs.
+ //
+ // Caller is responsible for setting focus in new dialog after the fade-in
+ // animation completes.
+
+ var ds = dijit._dialogStack;
+
+ // Save current focus
+ ds[ds.length-1].focus = dijit.getFocus(dialog);
+
+ // Display the underlay, or if already displayed then adjust for this new dialog
+ var underlay = dijit._underlay;
+ if(!underlay || underlay._destroyed){
+ underlay = dijit._underlay = new dijit.DialogUnderlay(underlayAttrs);
+ }else{
+ underlay.set(dialog.underlayAttrs);
+ }
+
+ // Set z-index a bit above previous dialog
+ var zIndex = ds[ds.length-1].dialog ? ds[ds.length-1].zIndex + 2 : 950;
+ if(ds.length == 1){ // first dialog
+ underlay.show();
+ }
+ dojo.style(dijit._underlay.domNode, 'zIndex', zIndex - 1);
+
+ // Dialog
+ dojo.style(dialog.domNode, 'zIndex', zIndex);
+
+ ds.push({dialog: dialog, underlayAttrs: underlayAttrs, zIndex: zIndex});
+ },
+
+ hide: function(/*dijit._Widget*/ dialog){
+ // summary:
+ // Called when the specified dialog is hidden/destroyed, after the fade-out
+ // animation ends, in order to reset page focus, fix the underlay, etc.
+ // If the specified dialog isn't open then does nothing.
+ //
+ // Caller is responsible for either setting display:none on the dialog domNode,
+ // or calling dijit.popup.hide(), or removing it from the page DOM.
+
+ var ds = dijit._dialogStack;
+
+ if(ds[ds.length-1].dialog == dialog){
+ // Removing the top (or only) dialog in the stack, return focus
+ // to previous dialog
+
+ ds.pop();
+
+ var pd = ds[ds.length-1]; // the new active dialog (or the base page itself)
+
+ // Adjust underlay
+ if(ds.length == 1){
+ // Returning to original page.
+ // 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(!dijit._underlay._destroyed){
+ dijit._underlay.hide();
+ }
+ }else{
+ // Popping back to previous dialog, adjust underlay
+ dojo.style(dijit._underlay.domNode, 'zIndex', pd.zIndex - 1);
+ dijit._underlay.set(pd.underlayAttrs);
+ }
+
+ // Adjust focus
+ if(dialog.refocus){
+ // 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.
+ var focus = pd.focus;
+ if(!focus || (pd.dialog && !dojo.isDescendant(focus.node, pd.dialog.domNode))){
+ pd.dialog._getFocusItems(pd.dialog.domNode);
+ focus = pd.dialog._firstFocusItem;
+ }
+
+ try{
+ dijit.focus(focus);
+ }catch(e){
+ /* focus() will fail if user opened the dialog by clicking a non-focusable element */
+ }
+ }
+ }else{
+ // Removing a dialog out of order (#9944, #10705).
+ // Don't need to mess with underlay or z-index or anything.
+ var idx = dojo.indexOf(dojo.map(ds, function(elem){return elem.dialog}), dialog);
+ if(idx != -1){
+ ds.splice(idx, 1);
+ }
+ }
+ },
+
+ isTop: function(/*dijit._Widget*/ dialog){
+ // summary:
+ // Returns true if specified Dialog is the top in the task
+ var ds = dijit._dialogStack;
+ return ds[ds.length-1].dialog == dialog;
+ }
+};
+
+// Stack representing the various active "levels" on the page, starting with the
+// stuff initially visible on the page (at z-index 0), and then having an entry for
+// each Dialog shown.
+// Each element in stack has form {
+// dialog: dialogWidget,
+// focus: returnFromGetFocus(),
+// underlayAttrs: attributes to set on underlay (when this widget is active)
+// }
+dijit._dialogStack = [
+ {dialog: null, focus: null, underlayAttrs: null} // entry for stuff at z-index: 0
+];
+
+}
+
+if(!dojo._hasResource["dijit._editor.selection"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._editor.selection"] = true;
+dojo.provide("dijit._editor.selection");
+
+
+
+dojo.getObject("_editor.selection", true, dijit);
+
+// FIXME:
+// all of these methods branch internally for IE. This is probably
+// sub-optimal in terms of runtime performance. We should investigate the
+// size difference for differentiating at definition time.
+
+dojo.mixin(dijit._editor.selection, {
+ getType: function(){
+ // summary:
+ // Get the selection type (like dojo.doc.select.type in IE).
+ if(dojo.isIE){
+ return dojo.doc.selection.type.toLowerCase();
+ }else{
+ var stype = "text";
+
+ // Check if the actual selection is a CONTROL (IMG, TABLE, HR, etc...).
+ var oSel;
+ try{
+ oSel = dojo.global.getSelection();
+ }catch(e){ /*squelch*/ }
+
+ if(oSel && oSel.rangeCount == 1){
+ var oRange = oSel.getRangeAt(0);
+ if( (oRange.startContainer == oRange.endContainer) &&
+ ((oRange.endOffset - oRange.startOffset) == 1) &&
+ (oRange.startContainer.nodeType != 3 /* text node*/)
+ ){
+ stype = "control";
+ }
+ }
+ return stype; //String
+ }
+ },
+
+ getSelectedText: function(){
+ // summary:
+ // Return the text (no html tags) included in the current selection or null if no text is selected
+ if(dojo.isIE){
+ if(dijit._editor.selection.getType() == 'control'){
+ return null;
+ }
+ return dojo.doc.selection.createRange().text;
+ }else{
+ var selection = dojo.global.getSelection();
+ if(selection){
+ return selection.toString(); //String
+ }
+ }
+ return '';
+ },
+
+ getSelectedHtml: function(){
+ // summary:
+ // Return the html text of the current selection or null if unavailable
+ if(dojo.isIE){
+ if(dijit._editor.selection.getType() == 'control'){
+ return null;
+ }
+ return dojo.doc.selection.createRange().htmlText;
+ }else{
+ var selection = dojo.global.getSelection();
+ if(selection && selection.rangeCount){
+ var i;
+ var html = "";
+ for(i = 0; i < selection.rangeCount; i++){
+ //Handle selections spanning ranges, such as Opera
+ var frag = selection.getRangeAt(i).cloneContents();
+ var div = dojo.doc.createElement("div");
+ div.appendChild(frag);
+ html += div.innerHTML;
+ }
+ return html; //String
+ }
+ return null;
+ }
+ },
+
+ getSelectedElement: function(){
+ // summary:
+ // Retrieves the selected element (if any), just in the case that
+ // a single element (object like and image or a table) is
+ // selected.
+ if(dijit._editor.selection.getType() == "control"){
+ if(dojo.isIE){
+ var range = dojo.doc.selection.createRange();
+ if(range && range.item){
+ return dojo.doc.selection.createRange().item(0);
+ }
+ }else{
+ var selection = dojo.global.getSelection();
+ return selection.anchorNode.childNodes[ selection.anchorOffset ];
+ }
+ }
+ return null;
+ },
+
+ getParentElement: function(){
+ // summary:
+ // Get the parent element of the current selection
+ if(dijit._editor.selection.getType() == "control"){
+ var p = this.getSelectedElement();
+ if(p){ return p.parentNode; }
+ }else{
+ if(dojo.isIE){
+ var r = dojo.doc.selection.createRange();
+ r.collapse(true);
+ return r.parentElement();
+ }else{
+ var selection = dojo.global.getSelection();
+ if(selection){
+ var node = selection.anchorNode;
+ while(node && (node.nodeType != 1)){ // not an element
+ node = node.parentNode;
+ }
+ return node;
+ }
+ }
+ }
+ return null;
+ },
+
+ hasAncestorElement: function(/*String*/tagName /* ... */){
+ // summary:
+ // Check whether current selection has a parent element which is
+ // of type tagName (or one of the other specified tagName)
+ // tagName: String
+ // The tag name to determine if it has an ancestor of.
+ return this.getAncestorElement.apply(this, arguments) != null; //Boolean
+ },
+
+ getAncestorElement: function(/*String*/tagName /* ... */){
+ // summary:
+ // Return the parent element of the current selection which is of
+ // type tagName (or one of the other specified tagName)
+ // tagName: String
+ // The tag name to determine if it has an ancestor of.
+ var node = this.getSelectedElement() || this.getParentElement();
+ return this.getParentOfType(node, arguments); //DOMNode
+ },
+
+ isTag: function(/*DomNode*/ node, /*String[]*/ tags){
+ // summary:
+ // Function to determine if a node is one of an array of tags.
+ // node:
+ // The node to inspect.
+ // tags:
+ // An array of tag name strings to check to see if the node matches.
+ if(node && node.tagName){
+ var _nlc = node.tagName.toLowerCase();
+ for(var i=0; i<tags.length; i++){
+ var _tlc = String(tags[i]).toLowerCase();
+ if(_nlc == _tlc){
+ return _tlc; // String
+ }
+ }
+ }
+ return "";
+ },
+
+ getParentOfType: function(/*DomNode*/ node, /*String[]*/ tags){
+ // summary:
+ // Function to locate a parent node that matches one of a set of tags
+ // node:
+ // The node to inspect.
+ // tags:
+ // An array of tag name strings to check to see if the node matches.
+ while(node){
+ if(this.isTag(node, tags).length){
+ return node; // DOMNode
+ }
+ node = node.parentNode;
+ }
+ return null;
+ },
+
+ collapse: function(/*Boolean*/beginning){
+ // summary:
+ // Function to collapse (clear), the current selection
+ // beginning: Boolean
+ // Boolean to indicate whether to collapse the cursor to the beginning of the selection or end.
+ if(window.getSelection){
+ var selection = dojo.global.getSelection();
+ if(selection.removeAllRanges){ // Mozilla
+ if(beginning){
+ selection.collapseToStart();
+ }else{
+ selection.collapseToEnd();
+ }
+ }else{ // Safari
+ // pulled from WebCore/ecma/kjs_window.cpp, line 2536
+ selection.collapse(beginning);
+ }
+ }else if(dojo.isIE){ // IE
+ var range = dojo.doc.selection.createRange();
+ range.collapse(beginning);
+ range.select();
+ }
+ },
+
+ remove: function(){
+ // summary:
+ // Function to delete the currently selected content from the document.
+ var sel = dojo.doc.selection;
+ if(dojo.isIE){
+ if(sel.type.toLowerCase() != "none"){
+ sel.clear();
+ }
+ return sel; //Selection
+ }else{
+ sel = dojo.global.getSelection();
+ sel.deleteFromDocument();
+ return sel; //Selection
+ }
+ },
+
+ selectElementChildren: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
+ // summary:
+ // clear previous selection and select the content of the node
+ // (excluding the node itself)
+ // element: DOMNode
+ // The element you wish to select the children content of.
+ // nochangefocus: Boolean
+ // Boolean to indicate if the foxus should change or not.
+ var win = dojo.global;
+ var doc = dojo.doc;
+ var range;
+ element = dojo.byId(element);
+ if(doc.selection && dojo.isIE && dojo.body().createTextRange){ // IE
+ range = element.ownerDocument.body.createTextRange();
+ range.moveToElementText(element);
+ if(!nochangefocus){
+ try{
+ range.select(); // IE throws an exception here if the widget is hidden. See #5439
+ }catch(e){ /* squelch */}
+ }
+ }else if(win.getSelection){
+ var selection = dojo.global.getSelection();
+ if(dojo.isOpera){
+ //Opera's selectAllChildren doesn't seem to work right
+ //against <body> nodes and possibly others ... so
+ //we use the W3C range API
+ if(selection.rangeCount){
+ range = selection.getRangeAt(0);
+ }else{
+ range = doc.createRange();
+ }
+ range.setStart(element, 0);
+ range.setEnd(element,(element.nodeType == 3)?element.length:element.childNodes.length);
+ selection.addRange(range);
+ }else{
+ selection.selectAllChildren(element);
+ }
+ }
+ },
+
+ selectElement: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
+ // summary:
+ // clear previous selection and select element (including all its children)
+ // element: DOMNode
+ // The element to select.
+ // nochangefocus: Boolean
+ // Boolean indicating if the focus should be changed. IE only.
+ var range;
+ var doc = dojo.doc;
+ var win = dojo.global;
+ element = dojo.byId(element);
+ if(dojo.isIE && dojo.body().createTextRange){
+ try{
+ range = dojo.body().createControlRange();
+ range.addElement(element);
+ if(!nochangefocus){
+ range.select();
+ }
+ }catch(e){
+ this.selectElementChildren(element,nochangefocus);
+ }
+ }else if(dojo.global.getSelection){
+ var selection = win.getSelection();
+ range = doc.createRange();
+ if(selection.removeAllRanges){ // Mozilla
+ // FIXME: does this work on Safari?
+ if(dojo.isOpera){
+ //Opera works if you use the current range on
+ //the selection if present.
+ if(selection.getRangeAt(0)){
+ range = selection.getRangeAt(0);
+ }
+ }
+ range.selectNode(element);
+ selection.removeAllRanges();
+ selection.addRange(range);
+ }
+ }
+ },
+
+ inSelection: function(node){
+ // summary:
+ // This function determines if 'node' is
+ // in the current selection.
+ // tags:
+ // public
+ if(node){
+ var newRange;
+ var doc = dojo.doc;
+ var range;
+
+ if(dojo.global.getSelection){
+ //WC3
+ var sel = dojo.global.getSelection();
+ if(sel && sel.rangeCount > 0){
+ range = sel.getRangeAt(0);
+ }
+ if(range && range.compareBoundaryPoints && doc.createRange){
+ try{
+ newRange = doc.createRange();
+ newRange.setStart(node, 0);
+ if(range.compareBoundaryPoints(range.START_TO_END, newRange) === 1){
+ return true;
+ }
+ }catch(e){ /* squelch */}
+ }
+ }else if(doc.selection){
+ // Probably IE, so we can't use the range object as the pseudo
+ // range doesn't implement the boundry checking, we have to
+ // use IE specific crud.
+ range = doc.selection.createRange();
+ try{
+ newRange = node.ownerDocument.body.createControlRange();
+ if(newRange){
+ newRange.addElement(node);
+ }
+ }catch(e1){
+ try{
+ newRange = node.ownerDocument.body.createTextRange();
+ newRange.moveToElementText(node);
+ }catch(e2){/* squelch */}
+ }
+ if(range && newRange){
+ // We can finally compare similar to W3C
+ if(range.compareEndPoints("EndToStart", newRange) === 1){
+ return true;
+ }
+ }
+ }
+ }
+ return false; // boolean
+ }
+
+});
+
+}
+
+if(!dojo._hasResource["dijit._editor.range"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._editor.range"] = true;
+dojo.provide("dijit._editor.range");
+
+
+
+dijit.range={};
+
+dijit.range.getIndex=function(/*DomNode*/node, /*DomNode*/parent){
+// dojo.profile.start("dijit.range.getIndex");
+ var ret=[], retR=[];
+ var stop = parent;
+ var onode = node;
+
+ var pnode, n;
+ while(node != stop){
+ var i = 0;
+ pnode = node.parentNode;
+ while((n=pnode.childNodes[i++])){
+ if(n === node){
+ --i;
+ break;
+ }
+ }
+ //if(i>=pnode.childNodes.length){
+ //dojo.debug("Error finding index of a node in dijit.range.getIndex");
+ //}
+ ret.unshift(i);
+ retR.unshift(i-pnode.childNodes.length);
+ node = pnode;
+ }
+
+ //normalized() can not be called so often to prevent
+ //invalidating selection/range, so we have to detect
+ //here that any text nodes in a row
+ if(ret.length > 0 && onode.nodeType == 3){
+ n = onode.previousSibling;
+ while(n && n.nodeType == 3){
+ ret[ret.length-1]--;
+ n = n.previousSibling;
+ }
+ n = onode.nextSibling;
+ while(n && n.nodeType == 3){
+ retR[retR.length-1]++;
+ n = n.nextSibling;
+ }
+ }
+// dojo.profile.end("dijit.range.getIndex");
+ return {o: ret, r:retR};
+}
+
+dijit.range.getNode = function(/*Array*/index, /*DomNode*/parent){
+ if(!dojo.isArray(index) || index.length == 0){
+ return parent;
+ }
+ var node = parent;
+// if(!node)debugger
+ dojo.every(index, function(i){
+ if(i >= 0 && i < node.childNodes.length){
+ node = node.childNodes[i];
+ }else{
+ node = null;
+ //console.debug('Error: can not find node with index',index,'under parent node',parent );
+ return false; //terminate dojo.every
+ }
+ return true; //carry on the every loop
+ });
+
+ return node;
+}
+
+dijit.range.getCommonAncestor = function(n1,n2,root){
+ root = root||n1.ownerDocument.body;
+ var getAncestors = function(n){
+ var as=[];
+ while(n){
+ as.unshift(n);
+ if(n !== root){
+ n = n.parentNode;
+ }else{
+ break;
+ }
+ }
+ return as;
+ };
+ var n1as = getAncestors(n1);
+ var n2as = getAncestors(n2);
+
+ var m = Math.min(n1as.length,n2as.length);
+ var com = n1as[0]; //at least, one element should be in the array: the root (BODY by default)
+ for(var i=1;i<m;i++){
+ if(n1as[i] === n2as[i]){
+ com = n1as[i]
+ }else{
+ break;
+ }
+ }
+ return com;
+}
+
+dijit.range.getAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){
+ root = root || node.ownerDocument.body;
+ while(node && node !== root){
+ var name = node.nodeName.toUpperCase() ;
+ if(regex.test(name)){
+ return node;
+ }
+
+ node = node.parentNode;
+ }
+ return null;
+}
+
+dijit.range.BlockTagNames = /^(?:P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|DT|DE)$/;
+dijit.range.getBlockAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){
+ root = root || node.ownerDocument.body;
+ regex = regex || dijit.range.BlockTagNames;
+ var block=null, blockContainer;
+ while(node && node !== root){
+ var name = node.nodeName.toUpperCase() ;
+ if(!block && regex.test(name)){
+ block = node;
+ }
+ if(!blockContainer && (/^(?:BODY|TD|TH|CAPTION)$/).test(name)){
+ blockContainer = node;
+ }
+
+ node = node.parentNode;
+ }
+ return {blockNode:block, blockContainer:blockContainer || node.ownerDocument.body};
+}
+
+dijit.range.atBeginningOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){
+ var atBeginning = false;
+ var offsetAtBeginning = (offset == 0);
+ if(!offsetAtBeginning && node.nodeType == 3){ //if this is a text node, check whether the left part is all space
+ if(/^[\s\xA0]+$/.test(node.nodeValue.substr(0,offset))){
+ offsetAtBeginning = true;
+ }
+ }
+ if(offsetAtBeginning){
+ var cnode = node;
+ atBeginning = true;
+ while(cnode && cnode !== container){
+ if(cnode.previousSibling){
+ atBeginning = false;
+ break;
+ }
+ cnode = cnode.parentNode;
+ }
+ }
+ return atBeginning;
+}
+
+dijit.range.atEndOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){
+ var atEnd = false;
+ var offsetAtEnd = (offset == (node.length || node.childNodes.length));
+ if(!offsetAtEnd && node.nodeType == 3){ //if this is a text node, check whether the right part is all space
+ if(/^[\s\xA0]+$/.test(node.nodeValue.substr(offset))){
+ offsetAtEnd = true;
+ }
+ }
+ if(offsetAtEnd){
+ var cnode = node;
+ atEnd = true;
+ while(cnode && cnode !== container){
+ if(cnode.nextSibling){
+ atEnd = false;
+ break;
+ }
+ cnode = cnode.parentNode;
+ }
+ }
+ return atEnd;
+}
+
+dijit.range.adjacentNoneTextNode=function(startnode, next){
+ var node = startnode;
+ var len = (0-startnode.length) || 0;
+ var prop = next?'nextSibling':'previousSibling';
+ while(node){
+ if(node.nodeType!=3){
+ break;
+ }
+ len += node.length
+ node = node[prop];
+ }
+ return [node,len];
+}
+
+dijit.range._w3c = Boolean(window['getSelection']);
+dijit.range.create = function(/*Window?*/win){
+ if(dijit.range._w3c){
+ return (win || dojo.global).document.createRange();
+ }else{//IE
+ return new dijit.range.W3CRange;
+ }
+}
+
+dijit.range.getSelection = function(/*Window*/win, /*Boolean?*/ignoreUpdate){
+ if(dijit.range._w3c){
+ return win.getSelection();
+ }else{//IE
+ var s = new dijit.range.ie.selection(win);
+ if(!ignoreUpdate){
+ s._getCurrentSelection();
+ }
+ return s;
+ }
+}
+
+if(!dijit.range._w3c){
+ dijit.range.ie={
+ cachedSelection: {},
+ selection: function(win){
+ this._ranges = [];
+ this.addRange = function(r, /*boolean*/internal){
+ this._ranges.push(r);
+ if(!internal){
+ r._select();
+ }
+ this.rangeCount = this._ranges.length;
+ };
+ this.removeAllRanges = function(){
+ //don't detach, the range may be used later
+// for(var i=0;i<this._ranges.length;i++){
+// this._ranges[i].detach();
+// }
+ this._ranges = [];
+ this.rangeCount = 0;
+ };
+ var _initCurrentRange = function(){
+ var r = win.document.selection.createRange();
+ var type=win.document.selection.type.toUpperCase();
+ if(type == "CONTROL"){
+ //TODO: multiple range selection(?)
+ return new dijit.range.W3CRange(dijit.range.ie.decomposeControlRange(r));
+ }else{
+ return new dijit.range.W3CRange(dijit.range.ie.decomposeTextRange(r));
+ }
+ };
+ this.getRangeAt = function(i){
+ return this._ranges[i];
+ };
+ this._getCurrentSelection = function(){
+ this.removeAllRanges();
+ var r=_initCurrentRange();
+ if(r){
+ this.addRange(r, true);
+ }
+ };
+ },
+ decomposeControlRange: function(range){
+ var firstnode = range.item(0), lastnode = range.item(range.length-1);
+ var startContainer = firstnode.parentNode, endContainer = lastnode.parentNode;
+ var startOffset = dijit.range.getIndex(firstnode, startContainer).o;
+ var endOffset = dijit.range.getIndex(lastnode, endContainer).o+1;
+ return [startContainer, startOffset,endContainer, endOffset];
+ },
+ getEndPoint: function(range, end){
+ var atmrange = range.duplicate();
+ atmrange.collapse(!end);
+ var cmpstr = 'EndTo' + (end?'End':'Start');
+ var parentNode = atmrange.parentElement();
+
+ var startnode, startOffset, lastNode;
+ if(parentNode.childNodes.length>0){
+ dojo.every(parentNode.childNodes, function(node,i){
+ var calOffset;
+ if(node.nodeType != 3){
+ atmrange.moveToElementText(node);
+
+ if(atmrange.compareEndPoints(cmpstr,range) > 0){
+ //startnode = node.previousSibling;
+ if(lastNode && lastNode.nodeType == 3){
+ //where shall we put the start? in the text node or after?
+ startnode = lastNode;
+ calOffset = true;
+ }else{
+ startnode = parentNode;
+ startOffset = i;
+ return false;
+ }
+ }else{
+ if(i == parentNode.childNodes.length-1){
+ startnode = parentNode;
+ startOffset = parentNode.childNodes.length;
+ return false;
+ }
+ }
+ }else{
+ if(i == parentNode.childNodes.length-1){//at the end of this node
+ startnode = node;
+ calOffset = true;
+ }
+ }
+ // try{
+ if(calOffset && startnode){
+ var prevnode = dijit.range.adjacentNoneTextNode(startnode)[0];
+ if(prevnode){
+ startnode = prevnode.nextSibling;
+ }else{
+ startnode = parentNode.firstChild; //firstChild must be a text node
+ }
+ var prevnodeobj = dijit.range.adjacentNoneTextNode(startnode);
+ prevnode = prevnodeobj[0];
+ var lenoffset = prevnodeobj[1];
+ if(prevnode){
+ atmrange.moveToElementText(prevnode);
+ atmrange.collapse(false);
+ }else{
+ atmrange.moveToElementText(parentNode);
+ }
+ atmrange.setEndPoint(cmpstr, range);
+ startOffset = atmrange.text.length-lenoffset;
+
+ return false;
+ }
+ // }catch(e){ debugger }
+ lastNode = node;
+ return true;
+ });
+ }else{
+ startnode = parentNode;
+ startOffset = 0;
+ }
+
+ //if at the end of startnode and we are dealing with start container, then
+ //move the startnode to nextSibling if it is a text node
+ //TODO: do this for end container?
+ if(!end && startnode.nodeType == 1 && startOffset == startnode.childNodes.length){
+ var nextnode=startnode.nextSibling;
+ if(nextnode && nextnode.nodeType == 3){
+ startnode = nextnode;
+ startOffset = 0;
+ }
+ }
+ return [startnode, startOffset];
+ },
+ setEndPoint: function(range, container, offset){
+ //text node
+ var atmrange = range.duplicate(), node, len;
+ if(container.nodeType!=3){ //normal node
+ if(offset > 0){
+ node = container.childNodes[offset-1];
+ if(node){
+ if(node.nodeType == 3){
+ container = node;
+ offset = node.length;
+ //pass through
+ }else{
+ if(node.nextSibling && node.nextSibling.nodeType == 3){
+ container=node.nextSibling;
+ offset=0;
+ //pass through
+ }else{
+ atmrange.moveToElementText(node.nextSibling?node:container);
+ var parent = node.parentNode;
+ var tempNode = parent.insertBefore(node.ownerDocument.createTextNode(' '), node.nextSibling);
+ atmrange.collapse(false);
+ parent.removeChild(tempNode);
+ }
+ }
+ }
+ }else{
+ atmrange.moveToElementText(container);
+ atmrange.collapse(true);
+ }
+ }
+ if(container.nodeType == 3){
+ var prevnodeobj = dijit.range.adjacentNoneTextNode(container);
+ var prevnode = prevnodeobj[0];
+ len = prevnodeobj[1];
+ if(prevnode){
+ atmrange.moveToElementText(prevnode);
+ atmrange.collapse(false);
+ //if contentEditable is not inherit, the above collapse won't make the end point
+ //in the correctly position: it always has a -1 offset, so compensate it
+ if(prevnode.contentEditable!='inherit'){
+ len++;
+ }
+ }else{
+ atmrange.moveToElementText(container.parentNode);
+ atmrange.collapse(true);
+ }
+
+ offset += len;
+ if(offset>0){
+ if(atmrange.move('character',offset) != offset){
+ console.error('Error when moving!');
+ }
+ }
+ }
+
+ return atmrange;
+ },
+ decomposeTextRange: function(range){
+ var tmpary = dijit.range.ie.getEndPoint(range);
+ var startContainer = tmpary[0], startOffset = tmpary[1];
+ var endContainer = tmpary[0], endOffset = tmpary[1];
+
+ if(range.htmlText.length){
+ if(range.htmlText == range.text){ //in the same text node
+ endOffset = startOffset+range.text.length;
+ }else{
+ tmpary = dijit.range.ie.getEndPoint(range,true);
+ endContainer = tmpary[0], endOffset = tmpary[1];
+// if(startContainer.tagName == "BODY"){
+// startContainer = startContainer.firstChild;
+// }
+ }
+ }
+ return [startContainer, startOffset, endContainer, endOffset];
+ },
+ setRange: function(range, startContainer,
+ startOffset, endContainer, endOffset, collapsed){
+ var start=dijit.range.ie.setEndPoint(range, startContainer, startOffset);
+
+ range.setEndPoint('StartToStart',start);
+ if(!collapsed){
+ var end=dijit.range.ie.setEndPoint(range, endContainer, endOffset);
+ }
+ range.setEndPoint('EndToEnd',end || start);
+
+ return range;
+ }
+ }
+
+dojo.declare("dijit.range.W3CRange",null, {
+ constructor: function(){
+ if(arguments.length>0){
+ this.setStart(arguments[0][0],arguments[0][1]);
+ this.setEnd(arguments[0][2],arguments[0][3]);
+ }else{
+ this.commonAncestorContainer = null;
+ this.startContainer = null;
+ this.startOffset = 0;
+ this.endContainer = null;
+ this.endOffset = 0;
+ this.collapsed = true;
+ }
+ },
+ _updateInternal: function(){
+ if(this.startContainer !== this.endContainer){
+ this.commonAncestorContainer = dijit.range.getCommonAncestor(this.startContainer, this.endContainer);
+ }else{
+ this.commonAncestorContainer = this.startContainer;
+ }
+ this.collapsed = (this.startContainer === this.endContainer) && (this.startOffset == this.endOffset);
+ },
+ setStart: function(node, offset){
+ offset=parseInt(offset);
+ if(this.startContainer === node && this.startOffset == offset){
+ return;
+ }
+ delete this._cachedBookmark;
+
+ this.startContainer = node;
+ this.startOffset = offset;
+ if(!this.endContainer){
+ this.setEnd(node, offset);
+ }else{
+ this._updateInternal();
+ }
+ },
+ setEnd: function(node, offset){
+ offset=parseInt(offset);
+ if(this.endContainer === node && this.endOffset == offset){
+ return;
+ }
+ delete this._cachedBookmark;
+
+ this.endContainer = node;
+ this.endOffset = offset;
+ if(!this.startContainer){
+ this.setStart(node, offset);
+ }else{
+ this._updateInternal();
+ }
+ },
+ setStartAfter: function(node, offset){
+ this._setPoint('setStart', node, offset, 1);
+ },
+ setStartBefore: function(node, offset){
+ this._setPoint('setStart', node, offset, 0);
+ },
+ setEndAfter: function(node, offset){
+ this._setPoint('setEnd', node, offset, 1);
+ },
+ setEndBefore: function(node, offset){
+ this._setPoint('setEnd', node, offset, 0);
+ },
+ _setPoint: function(what, node, offset, ext){
+ var index = dijit.range.getIndex(node, node.parentNode).o;
+ this[what](node.parentNode, index.pop()+ext);
+ },
+ _getIERange: function(){
+ var r = (this._body || this.endContainer.ownerDocument.body).createTextRange();
+ dijit.range.ie.setRange(r, this.startContainer, this.startOffset, this.endContainer, this.endOffset, this.collapsed);
+ return r;
+ },
+ getBookmark: function(body){
+ this._getIERange();
+ return this._cachedBookmark;
+ },
+ _select: function(){
+ var r = this._getIERange();
+ r.select();
+ },
+ deleteContents: function(){
+ var r = this._getIERange();
+ r.pasteHTML('');
+ this.endContainer = this.startContainer;
+ this.endOffset = this.startOffset;
+ this.collapsed = true;
+ },
+ cloneRange: function(){
+ var r = new dijit.range.W3CRange([this.startContainer,this.startOffset,
+ this.endContainer,this.endOffset]);
+ r._body = this._body;
+ return r;
+ },
+ detach: function(){
+ this._body = null;
+ this.commonAncestorContainer = null;
+ this.startContainer = null;
+ this.startOffset = 0;
+ this.endContainer = null;
+ this.endOffset = 0;
+ this.collapsed = true;
+}
+});
+} //if(!dijit.range._w3c)
+
+}
+
+if(!dojo._hasResource["dijit._editor.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._editor.html"] = true;
+dojo.provide("dijit._editor.html");
+
+
+dojo.getObject("_editor", true, dijit);
+
+dijit._editor.escapeXml=function(/*String*/str, /*Boolean?*/noSingleQuotes){
+ // summary:
+ // Adds escape sequences for special characters in XML: &<>"'
+ // Optionally skips escapes for single quotes
+ str = str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
+ if(!noSingleQuotes){
+ str = str.replace(/'/gm, "&#39;");
+ }
+ return str; // string
+};
+
+dijit._editor.getNodeHtml=function(/* DomNode */node){
+ var output;
+ switch(node.nodeType){
+ case 1: //element node
+ var lName = node.nodeName.toLowerCase();
+ if(!lName || lName.charAt(0) == "/"){
+ // IE does some strange things with malformed HTML input, like
+ // treating a close tag </span> without an open tag <span>, as
+ // a new tag with tagName of /span. Corrupts output HTML, remove
+ // them. Other browsers don't prefix tags that way, so will
+ // never show up.
+ return "";
+ }
+ output = '<' + lName;
+
+ //store the list of attributes and sort it to have the
+ //attributes appear in the dictionary order
+ var attrarray = [];
+ var attr;
+ if(dojo.isIE && node.outerHTML){
+ var s = node.outerHTML;
+ s = s.substr(0, s.indexOf('>'))
+ .replace(/(['"])[^"']*\1/g, ''); //to make the following regexp safe
+ var reg = /(\b\w+)\s?=/g;
+ var m, key;
+ while((m = reg.exec(s))){
+ key = m[1];
+ if(key.substr(0,3) != '_dj'){
+ if(key == 'src' || key == 'href'){
+ if(node.getAttribute('_djrealurl')){
+ attrarray.push([key,node.getAttribute('_djrealurl')]);
+ continue;
+ }
+ }
+ var val, match;
+ switch(key){
+ case 'style':
+ val = node.style.cssText.toLowerCase();
+ break;
+ case 'class':
+ val = node.className;
+ break;
+ case 'width':
+ if(lName === "img"){
+ // This somehow gets lost on IE for IMG tags and the like
+ // and we have to find it in outerHTML, known IE oddity.
+ match=/width=(\S+)/i.exec(s);
+ if(match){
+ val = match[1];
+ }
+ break;
+ }
+ case 'height':
+ if(lName === "img"){
+ // This somehow gets lost on IE for IMG tags and the like
+ // and we have to find it in outerHTML, known IE oddity.
+ match=/height=(\S+)/i.exec(s);
+ if(match){
+ val = match[1];
+ }
+ break;
+ }
+ default:
+ val = node.getAttribute(key);
+ }
+ if(val != null){
+ attrarray.push([key, val.toString()]);
+ }
+ }
+ }
+ }else{
+ var i = 0;
+ while((attr = node.attributes[i++])){
+ //ignore all attributes starting with _dj which are
+ //internal temporary attributes used by the editor
+ var n = attr.name;
+ if(n.substr(0,3) != '_dj' /*&&
+ (attr.specified == undefined || attr.specified)*/){
+ var v = attr.value;
+ if(n == 'src' || n == 'href'){
+ if(node.getAttribute('_djrealurl')){
+ v = node.getAttribute('_djrealurl');
+ }
+ }
+ attrarray.push([n,v]);
+ }
+ }
+ }
+ attrarray.sort(function(a,b){
+ return a[0] < b[0] ? -1 : (a[0] == b[0] ? 0 : 1);
+ });
+ var j = 0;
+ while((attr = attrarray[j++])){
+ output += ' ' + attr[0] + '="' +
+ (dojo.isString(attr[1]) ? dijit._editor.escapeXml(attr[1], true) : attr[1]) + '"';
+ }
+ if(lName === "script"){
+ // Browsers handle script tags differently in how you get content,
+ // but innerHTML always seems to work, so insert its content that way
+ // Yes, it's bad to allow script tags in the editor code, but some people
+ // seem to want to do it, so we need to at least return them right.
+ // other plugins/filters can strip them.
+ output += '>' + node.innerHTML +'</' + lName + '>';
+ }else{
+ if(node.childNodes.length){
+ output += '>' + dijit._editor.getChildrenHtml(node)+'</' + lName +'>';
+ }else{
+ switch(lName){
+ case 'br':
+ case 'hr':
+ case 'img':
+ case 'input':
+ case 'base':
+ case 'meta':
+ case 'area':
+ case 'basefont':
+ // These should all be singly closed
+ output += ' />';
+ break;
+ default:
+ // Assume XML style separate closure for everything else.
+ output += '></' + lName + '>';
+ }
+ }
+ }
+ break;
+ case 4: // cdata
+ case 3: // text
+ // FIXME:
+ output = dijit._editor.escapeXml(node.nodeValue, true);
+ break;
+ case 8: //comment
+ // FIXME:
+ output = '<!--' + dijit._editor.escapeXml(node.nodeValue, true) + '-->';
+ break;
+ default:
+ output = "<!-- Element not recognized - Type: " + node.nodeType + " Name: " + node.nodeName + "-->";
+ }
+ return output;
+};
+
+dijit._editor.getChildrenHtml = function(/* DomNode */dom){
+ // summary:
+ // Returns the html content of a DomNode and children
+ var out = "";
+ if(!dom){ return out; }
+ var nodes = dom["childNodes"] || dom;
+
+ //IE issue.
+ //If we have an actual node we can check parent relationships on for IE,
+ //We should check, as IE sometimes builds invalid DOMS. If no parent, we can't check
+ //And should just process it and hope for the best.
+ var checkParent = !dojo.isIE || nodes !== dom;
+
+ var node, i = 0;
+ while((node = nodes[i++])){
+ //IE is broken. DOMs are supposed to be a tree. But in the case of malformed HTML, IE generates a graph
+ //meaning one node ends up with multiple references (multiple parents). This is totally wrong and invalid, but
+ //such is what it is. We have to keep track and check for this because otherise the source output HTML will have dups.
+ //No other browser generates a graph. Leave it to IE to break a fundamental DOM rule. So, we check the parent if we can
+ //If we can't, nothing more we can do other than walk it.
+ if(!checkParent || node.parentNode == dom){
+ out += dijit._editor.getNodeHtml(node);
+ }
+ }
+ return out; // String
+};
+
+}
+
+if(!dojo._hasResource["dijit._editor.RichText"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._editor.RichText"] = true;
+dojo.provide("dijit._editor.RichText");
+
+
+
+
+
+
+
+
+// used to restore content when user leaves this page then comes back
+// but do not try doing dojo.doc.write if we are using xd loading.
+// dojo.doc.write will only work if RichText.js is included in the dojo.js
+// file. If it is included in dojo.js and you want to allow rich text saving
+// for back/forward actions, then set dojo.config.allowXdRichTextSave = true.
+if(!dojo.config["useXDomain"] || dojo.config["allowXdRichTextSave"]){
+ if(dojo._postLoad){
+ (function(){
+ var savetextarea = dojo.doc.createElement('textarea');
+ savetextarea.id = dijit._scopeName + "._editor.RichText.value";
+ dojo.style(savetextarea, {
+ display:'none',
+ position:'absolute',
+ top:"-100px",
+ height:"3px",
+ width:"3px"
+ });
+ dojo.body().appendChild(savetextarea);
+ })();
+ }else{
+ //dojo.body() is not available before onLoad is fired
+ try{
+ dojo.doc.write('<textarea id="' + dijit._scopeName + '._editor.RichText.value" ' +
+ 'style="display:none;position:absolute;top:-100px;left:-100px;height:3px;width:3px;overflow:hidden;"></textarea>');
+ }catch(e){ }
+ }
+}
+
+dojo.declare("dijit._editor.RichText", [dijit._Widget, dijit._CssStateMixin], {
+ constructor: function(params){
+ // summary:
+ // dijit._editor.RichText is the core of dijit.Editor, which provides basic
+ // WYSIWYG editing features.
+ //
+ // description:
+ // dijit._editor.RichText is the core of dijit.Editor, which provides basic
+ // WYSIWYG editing features. It also encapsulates the differences
+ // of different js engines for various browsers. Do not use this widget
+ // with an HTML &lt;TEXTAREA&gt; tag, since the browser unescapes XML escape characters,
+ // like &lt;. This can have unexpected behavior and lead to security issues
+ // such as scripting attacks.
+ //
+ // tags:
+ // private
+
+ // contentPreFilters: Function(String)[]
+ // Pre content filter function register array.
+ // these filters will be executed before the actual
+ // editing area gets the html content.
+ this.contentPreFilters = [];
+
+ // contentPostFilters: Function(String)[]
+ // post content filter function register array.
+ // These will be used on the resulting html
+ // from contentDomPostFilters. The resulting
+ // content is the final html (returned by getValue()).
+ this.contentPostFilters = [];
+
+ // contentDomPreFilters: Function(DomNode)[]
+ // Pre content dom filter function register array.
+ // These filters are applied after the result from
+ // contentPreFilters are set to the editing area.
+ this.contentDomPreFilters = [];
+
+ // contentDomPostFilters: Function(DomNode)[]
+ // Post content dom filter function register array.
+ // These filters are executed on the editing area dom.
+ // The result from these will be passed to contentPostFilters.
+ this.contentDomPostFilters = [];
+
+ // editingAreaStyleSheets: dojo._URL[]
+ // array to store all the stylesheets applied to the editing area
+ this.editingAreaStyleSheets = [];
+
+ // Make a copy of this.events before we start writing into it, otherwise we
+ // will modify the prototype which leads to bad things on pages w/multiple editors
+ this.events = [].concat(this.events);
+
+ this._keyHandlers = {};
+
+ if(params && dojo.isString(params.value)){
+ this.value = params.value;
+ }
+
+ this.onLoadDeferred = new dojo.Deferred();
+ },
+
+ baseClass: "dijitEditor",
+
+ // inheritWidth: Boolean
+ // whether to inherit the parent's width or simply use 100%
+ inheritWidth: false,
+
+ // focusOnLoad: [deprecated] Boolean
+ // Focus into this widget when the page is loaded
+ focusOnLoad: false,
+
+ // name: String?
+ // Specifies the name of a (hidden) <textarea> node on the page that's used to save
+ // the editor content on page leave. Used to restore editor contents after navigating
+ // to a new page and then hitting the back button.
+ name: "",
+
+ // styleSheets: [const] String
+ // semicolon (";") separated list of css files for the editing area
+ styleSheets: "",
+
+ // height: String
+ // Set height to fix the editor at a specific height, with scrolling.
+ // By default, this is 300px. If you want to have the editor always
+ // resizes to accommodate the content, use AlwaysShowToolbar plugin
+ // and set height="". If this editor is used within a layout widget,
+ // set height="100%".
+ height: "300px",
+
+ // minHeight: String
+ // The minimum height that the editor should have.
+ minHeight: "1em",
+
+ // isClosed: [private] Boolean
+ isClosed: true,
+
+ // isLoaded: [private] Boolean
+ isLoaded: false,
+
+ // _SEPARATOR: [private] String
+ // Used to concat contents from multiple editors into a single string,
+ // so they can be saved into a single <textarea> node. See "name" attribute.
+ _SEPARATOR: "@@**%%__RICHTEXTBOUNDRY__%%**@@",
+
+ // _NAME_CONTENT_SEP: [private] String
+ // USed to separate name from content. Just a colon isn't safe.
+ _NAME_CONTENT_SEP: "@@**%%:%%**@@",
+
+ // onLoadDeferred: [readonly] dojo.Deferred
+ // Deferred which is fired when the editor finishes loading.
+ // Call myEditor.onLoadDeferred.then(callback) it to be informed
+ // when the rich-text area initialization is finalized.
+ onLoadDeferred: null,
+
+ // isTabIndent: Boolean
+ // Make tab key and shift-tab indent and outdent rather than navigating.
+ // Caution: sing this makes web pages inaccessible to users unable to use a mouse.
+ isTabIndent: false,
+
+ // disableSpellCheck: [const] Boolean
+ // When true, disables the browser's native spell checking, if supported.
+ // Works only in Firefox.
+ disableSpellCheck: false,
+
+ postCreate: function(){
+ if("textarea" == this.domNode.tagName.toLowerCase()){
+ console.warn("RichText should not be used with the TEXTAREA tag. See dijit._editor.RichText docs.");
+ }
+
+ // Push in the builtin filters now, making them the first executed, but not over-riding anything
+ // users passed in. See: #6062
+ this.contentPreFilters = [dojo.hitch(this, "_preFixUrlAttributes")].concat(this.contentPreFilters);
+ if(dojo.isMoz){
+ this.contentPreFilters = [this._normalizeFontStyle].concat(this.contentPreFilters);
+ this.contentPostFilters = [this._removeMozBogus].concat(this.contentPostFilters);
+ }
+ if(dojo.isWebKit){
+ // Try to clean up WebKit bogus artifacts. The inserted classes
+ // made by WebKit sometimes messes things up.
+ this.contentPreFilters = [this._removeWebkitBogus].concat(this.contentPreFilters);
+ this.contentPostFilters = [this._removeWebkitBogus].concat(this.contentPostFilters);
+ }
+ if(dojo.isIE){
+ // IE generates <strong> and <em> but we want to normalize to <b> and <i>
+ this.contentPostFilters = [this._normalizeFontStyle].concat(this.contentPostFilters);
+ }
+ this.inherited(arguments);
+
+ dojo.publish(dijit._scopeName + "._editor.RichText::init", [this]);
+ this.open();
+ this.setupDefaultShortcuts();
+ },
+
+ setupDefaultShortcuts: function(){
+ // summary:
+ // Add some default key handlers
+ // description:
+ // Overwrite this to setup your own handlers. The default
+ // implementation does not use Editor commands, but directly
+ // executes the builtin commands within the underlying browser
+ // support.
+ // tags:
+ // protected
+ var exec = dojo.hitch(this, function(cmd, arg){
+ return function(){
+ return !this.execCommand(cmd,arg);
+ };
+ });
+
+ var ctrlKeyHandlers = {
+ b: exec("bold"),
+ i: exec("italic"),
+ u: exec("underline"),
+ a: exec("selectall"),
+ s: function(){ this.save(true); },
+ m: function(){ this.isTabIndent = !this.isTabIndent; },
+
+ "1": exec("formatblock", "h1"),
+ "2": exec("formatblock", "h2"),
+ "3": exec("formatblock", "h3"),
+ "4": exec("formatblock", "h4"),
+
+ "\\": exec("insertunorderedlist")
+ };
+
+ if(!dojo.isIE){
+ ctrlKeyHandlers.Z = exec("redo"); //FIXME: undo?
+ }
+
+ for(var key in ctrlKeyHandlers){
+ this.addKeyHandler(key, true, false, ctrlKeyHandlers[key]);
+ }
+ },
+
+ // events: [private] String[]
+ // events which should be connected to the underlying editing area
+ events: ["onKeyPress", "onKeyDown", "onKeyUp"], // onClick handled specially
+
+ // captureEvents: [deprecated] String[]
+ // Events which should be connected to the underlying editing
+ // area, events in this array will be addListener with
+ // capture=true.
+ // TODO: looking at the code I don't see any distinction between events and captureEvents,
+ // so get rid of this for 2.0 if not sooner
+ captureEvents: [],
+
+ _editorCommandsLocalized: false,
+ _localizeEditorCommands: function(){
+ // summary:
+ // When IE is running in a non-English locale, the API actually changes,
+ // so that we have to say (for example) danraku instead of p (for paragraph).
+ // Handle that here.
+ // tags:
+ // private
+ if(this._editorCommandsLocalized){
+ return;
+ }
+ this._editorCommandsLocalized = true;
+
+ //in IE, names for blockformat is locale dependent, so we cache the values here
+
+ //if the normal way fails, we try the hard way to get the list
+
+ //do not use _cacheLocalBlockFormatNames here, as it will
+ //trigger security warning in IE7
+
+ //put p after div, so if IE returns Normal, we show it as paragraph
+ //We can distinguish p and div if IE returns Normal, however, in order to detect that,
+ //we have to call this.document.selection.createRange().parentElement() or such, which
+ //could slow things down. Leave it as it is for now
+ var formats = ['div', 'p', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', 'address'];
+ var localhtml = "", format, i=0;
+ while((format=formats[i++])){
+ //append a <br> after each element to separate the elements more reliably
+ if(format.charAt(1) != 'l'){
+ localhtml += "<"+format+"><span>content</span></"+format+"><br/>";
+ }else{
+ localhtml += "<"+format+"><li>content</li></"+format+"><br/>";
+ }
+ }
+ //queryCommandValue returns empty if we hide editNode, so move it out of screen temporary
+ var div = dojo.doc.createElement('div');
+ dojo.style(div, {
+ position: "absolute",
+ top: "-2000px"
+ });
+ dojo.doc.body.appendChild(div);
+ div.innerHTML = localhtml;
+ var node = div.firstChild;
+ while(node){
+ dijit._editor.selection.selectElement(node.firstChild);
+ dojo.withGlobal(this.window, "selectElement", dijit._editor.selection, [node.firstChild]);
+ var nativename = node.tagName.toLowerCase();
+ this._local2NativeFormatNames[nativename] = document.queryCommandValue("formatblock");
+ //this.queryCommandValue("formatblock");
+ this._native2LocalFormatNames[this._local2NativeFormatNames[nativename]] = nativename;
+ node = node.nextSibling.nextSibling;
+ }
+ dojo.body().removeChild(div);
+ },
+
+ open: function(/*DomNode?*/ element){
+ // summary:
+ // Transforms the node referenced in this.domNode into a rich text editing
+ // node.
+ // description:
+ // Sets up the editing area asynchronously. This will result in
+ // the creation and replacement with an iframe.
+ // tags:
+ // private
+
+ if(!this.onLoadDeferred || this.onLoadDeferred.fired >= 0){
+ this.onLoadDeferred = new dojo.Deferred();
+ }
+
+ if(!this.isClosed){ this.close(); }
+ dojo.publish(dijit._scopeName + "._editor.RichText::open", [ this ]);
+
+ if(arguments.length == 1 && element.nodeName){ // else unchanged
+ this.domNode = element;
+ }
+
+ var dn = this.domNode;
+
+ // "html" will hold the innerHTML of the srcNodeRef and will be used to
+ // initialize the editor.
+ var html;
+
+ if(dojo.isString(this.value)){
+ // Allow setting the editor content programmatically instead of
+ // relying on the initial content being contained within the target
+ // domNode.
+ html = this.value;
+ delete this.value;
+ dn.innerHTML = "";
+ }else if(dn.nodeName && dn.nodeName.toLowerCase() == "textarea"){
+ // if we were created from a textarea, then we need to create a
+ // new editing harness node.
+ var ta = (this.textarea = dn);
+ this.name = ta.name;
+ html = ta.value;
+ dn = this.domNode = dojo.doc.createElement("div");
+ dn.setAttribute('widgetId', this.id);
+ ta.removeAttribute('widgetId');
+ dn.cssText = ta.cssText;
+ dn.className += " " + ta.className;
+ dojo.place(dn, ta, "before");
+ var tmpFunc = dojo.hitch(this, function(){
+ //some browsers refuse to submit display=none textarea, so
+ //move the textarea off screen instead
+ dojo.style(ta, {
+ display: "block",
+ position: "absolute",
+ top: "-1000px"
+ });
+
+ if(dojo.isIE){ //nasty IE bug: abnormal formatting if overflow is not hidden
+ var s = ta.style;
+ this.__overflow = s.overflow;
+ s.overflow = "hidden";
+ }
+ });
+ if(dojo.isIE){
+ setTimeout(tmpFunc, 10);
+ }else{
+ tmpFunc();
+ }
+
+ if(ta.form){
+ var resetValue = ta.value;
+ this.reset = function(){
+ var current = this.getValue();
+ if(current != resetValue){
+ this.replaceValue(resetValue);
+ }
+ };
+ dojo.connect(ta.form, "onsubmit", this, function(){
+ // Copy value to the <textarea> so it gets submitted along with form.
+ // FIXME: should we be calling close() here instead?
+ dojo.attr(ta, 'disabled', this.disabled); // don't submit the value if disabled
+ ta.value = this.getValue();
+ });
+ }
+ }else{
+ html = dijit._editor.getChildrenHtml(dn);
+ dn.innerHTML = "";
+ }
+
+ var content = dojo.contentBox(dn);
+ this._oldHeight = content.h;
+ this._oldWidth = content.w;
+
+ this.value = html;
+
+ // If we're a list item we have to put in a blank line to force the
+ // bullet to nicely align at the top of text
+ if(dn.nodeName && dn.nodeName == "LI"){
+ dn.innerHTML = " <br>";
+ }
+
+ // Construct the editor div structure.
+ this.header = dn.ownerDocument.createElement("div");
+ dn.appendChild(this.header);
+ this.editingArea = dn.ownerDocument.createElement("div");
+ dn.appendChild(this.editingArea);
+ this.footer = dn.ownerDocument.createElement("div");
+ dn.appendChild(this.footer);
+
+ if(!this.name){
+ this.name = this.id + "_AUTOGEN";
+ }
+
+ // User has pressed back/forward button so we lost the text in the editor, but it's saved
+ // in a hidden <textarea> (which contains the data for all the editors on this page),
+ // so get editor value from there
+ if(this.name !== "" && (!dojo.config["useXDomain"] || dojo.config["allowXdRichTextSave"])){
+ var saveTextarea = dojo.byId(dijit._scopeName + "._editor.RichText.value");
+ if(saveTextarea && saveTextarea.value !== ""){
+ var datas = saveTextarea.value.split(this._SEPARATOR), i=0, dat;
+ while((dat=datas[i++])){
+ var data = dat.split(this._NAME_CONTENT_SEP);
+ if(data[0] == this.name){
+ html = data[1];
+ datas = datas.splice(i, 1);
+ saveTextarea.value = datas.join(this._SEPARATOR);
+ break;
+ }
+ }
+ }
+
+ if(!dijit._editor._globalSaveHandler){
+ dijit._editor._globalSaveHandler = {};
+ dojo.addOnUnload(function() {
+ var id;
+ for(id in dijit._editor._globalSaveHandler){
+ var f = dijit._editor._globalSaveHandler[id];
+ if(dojo.isFunction(f)){
+ f();
+ }
+ }
+ });
+ }
+ dijit._editor._globalSaveHandler[this.id] = dojo.hitch(this, "_saveContent");
+ }
+
+ this.isClosed = false;
+
+ var ifr = (this.editorObject = this.iframe = dojo.doc.createElement('iframe'));
+ ifr.id = this.id+"_iframe";
+ this._iframeSrc = this._getIframeDocTxt();
+ ifr.style.border = "none";
+ ifr.style.width = "100%";
+ if(this._layoutMode){
+ // iframe should be 100% height, thus getting it's height from surrounding
+ // <div> (which has the correct height set by Editor)
+ ifr.style.height = "100%";
+ }else{
+ if(dojo.isIE >= 7){
+ if(this.height){
+ ifr.style.height = this.height;
+ }
+ if(this.minHeight){
+ ifr.style.minHeight = this.minHeight;
+ }
+ }else{
+ ifr.style.height = this.height ? this.height : this.minHeight;
+ }
+ }
+ ifr.frameBorder = 0;
+ ifr._loadFunc = dojo.hitch( this, function(win){
+ this.window = win;
+ this.document = this.window.document;
+
+ if(dojo.isIE){
+ this._localizeEditorCommands();
+ }
+
+ // Do final setup and set initial contents of editor
+ this.onLoad(html);
+ });
+
+ // Set the iframe's initial (blank) content.
+ var s = 'javascript:parent.' + dijit._scopeName + '.byId("'+this.id+'")._iframeSrc';
+ ifr.setAttribute('src', s);
+ this.editingArea.appendChild(ifr);
+
+ if(dojo.isSafari <= 4){
+ var src = ifr.getAttribute("src");
+ if(!src || src.indexOf("javascript") == -1){
+ // Safari 4 and earlier sometimes act oddly
+ // So we have to set it again.
+ setTimeout(function(){ifr.setAttribute('src', s);},0);
+ }
+ }
+
+ // TODO: this is a guess at the default line-height, kinda works
+ if(dn.nodeName == "LI"){
+ dn.lastChild.style.marginTop = "-1.2em";
+ }
+
+ dojo.addClass(this.domNode, this.baseClass);
+ },
+
+ //static cache variables shared among all instance of this class
+ _local2NativeFormatNames: {},
+ _native2LocalFormatNames: {},
+
+ _getIframeDocTxt: function(){
+ // summary:
+ // Generates the boilerplate text of the document inside the iframe (ie, <html><head>...</head><body/></html>).
+ // Editor content (if not blank) should be added afterwards.
+ // tags:
+ // private
+ var _cs = dojo.getComputedStyle(this.domNode);
+
+ // The contents inside of <body>. The real contents are set later via a call to setValue().
+ var html = "";
+ var setBodyId = true;
+ if(dojo.isIE || dojo.isWebKit || (!this.height && !dojo.isMoz)){
+ // In auto-expand mode, need a wrapper div for AlwaysShowToolbar plugin to correctly
+ // expand/contract the editor as the content changes.
+ html = "<div id='dijitEditorBody'></div>";
+ setBodyId = false;
+ }else if(dojo.isMoz){
+ // workaround bug where can't select then delete text (until user types something
+ // into the editor)... and/or issue where typing doesn't erase selected text
+ this._cursorToStart = true;
+ html = "&nbsp;";
+ }
+
+ var font = [ _cs.fontWeight, _cs.fontSize, _cs.fontFamily ].join(" ");
+
+ // line height is tricky - applying a units value will mess things up.
+ // if we can't get a non-units value, bail out.
+ var lineHeight = _cs.lineHeight;
+ if(lineHeight.indexOf("px") >= 0){
+ lineHeight = parseFloat(lineHeight)/parseFloat(_cs.fontSize);
+ // console.debug(lineHeight);
+ }else if(lineHeight.indexOf("em")>=0){
+ lineHeight = parseFloat(lineHeight);
+ }else{
+ // If we can't get a non-units value, just default
+ // it to the CSS spec default of 'normal'. Seems to
+ // work better, esp on IE, than '1.0'
+ lineHeight = "normal";
+ }
+ var userStyle = "";
+ var self = this;
+ this.style.replace(/(^|;)\s*(line-|font-?)[^;]+/ig, function(match){
+ match = match.replace(/^;/ig,"") + ';';
+ var s = match.split(":")[0];
+ if(s){
+ s = dojo.trim(s);
+ s = s.toLowerCase();
+ var i;
+ var sC = "";
+ for(i = 0; i < s.length; i++){
+ var c = s.charAt(i);
+ switch(c){
+ case "-":
+ i++;
+ c = s.charAt(i).toUpperCase();
+ default:
+ sC += c;
+ }
+ }
+ dojo.style(self.domNode, sC, "");
+ }
+ userStyle += match + ';';
+ });
+
+
+ // need to find any associated label element and update iframe document title
+ var label=dojo.query('label[for="'+this.id+'"]');
+
+ return [
+ this.isLeftToRight() ? "<html>\n<head>\n" : "<html dir='rtl'>\n<head>\n",
+ (dojo.isMoz && label.length ? "<title>" + label[0].innerHTML + "</title>\n" : ""),
+ "<meta http-equiv='Content-Type' content='text/html'>\n",
+ "<style>\n",
+ "\tbody,html {\n",
+ "\t\tbackground:transparent;\n",
+ "\t\tpadding: 1px 0 0 0;\n",
+ "\t\tmargin: -1px 0 0 0;\n", // remove extraneous vertical scrollbar on safari and firefox
+
+ // Set the html/body sizing. Webkit always needs this, other browsers
+ // only set it when height is defined (not auto-expanding), otherwise
+ // scrollers do not appear.
+ ((dojo.isWebKit)?"\t\twidth: 100%;\n":""),
+ ((dojo.isWebKit)?"\t\theight: 100%;\n":""),
+ "\t}\n",
+
+ // TODO: left positioning will cause contents to disappear out of view
+ // if it gets too wide for the visible area
+ "\tbody{\n",
+ "\t\ttop:0px;\n",
+ "\t\tleft:0px;\n",
+ "\t\tright:0px;\n",
+ "\t\tfont:", font, ";\n",
+ ((this.height||dojo.isOpera) ? "" : "\t\tposition: fixed;\n"),
+ // FIXME: IE 6 won't understand min-height?
+ "\t\tmin-height:", this.minHeight, ";\n",
+ "\t\tline-height:", lineHeight,";\n",
+ "\t}\n",
+ "\tp{ margin: 1em 0; }\n",
+
+ // Determine how scrollers should be applied. In autoexpand mode (height = "") no scrollers on y at all.
+ // But in fixed height mode we want both x/y scrollers. Also, if it's using wrapping div and in auto-expand
+ // (Mainly IE) we need to kill the y scroller on body and html.
+ (!setBodyId && !this.height ? "\tbody,html {overflow-y: hidden;}\n" : ""),
+ "\t#dijitEditorBody{overflow-x: auto; overflow-y:" + (this.height ? "auto;" : "hidden;") + " outline: 0px;}\n",
+ "\tli > ul:-moz-first-node, li > ol:-moz-first-node{ padding-top: 1.2em; }\n",
+ "\tli{ min-height:1.2em; }\n",
+ "</style>\n",
+ this._applyEditingAreaStyleSheets(),"\n",
+ "</head>\n<body ",
+ (setBodyId?"id='dijitEditorBody' ":""),
+ "onload='frameElement._loadFunc(window,document)' style='"+userStyle+"'>", html, "</body>\n</html>"
+ ].join(""); // String
+ },
+
+ _applyEditingAreaStyleSheets: function(){
+ // summary:
+ // apply the specified css files in styleSheets
+ // tags:
+ // private
+ var files = [];
+ if(this.styleSheets){
+ files = this.styleSheets.split(';');
+ this.styleSheets = '';
+ }
+
+ //empty this.editingAreaStyleSheets here, as it will be filled in addStyleSheet
+ files = files.concat(this.editingAreaStyleSheets);
+ this.editingAreaStyleSheets = [];
+
+ var text='', i=0, url;
+ while((url=files[i++])){
+ var abstring = (new dojo._Url(dojo.global.location, url)).toString();
+ this.editingAreaStyleSheets.push(abstring);
+ text += '<link rel="stylesheet" type="text/css" href="'+abstring+'"/>';
+ }
+ return text;
+ },
+
+ addStyleSheet: function(/*dojo._Url*/ uri){
+ // summary:
+ // add an external stylesheet for the editing area
+ // uri:
+ // A dojo.uri.Uri pointing to the url of the external css file
+ var url=uri.toString();
+
+ //if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
+ if(url.charAt(0) == '.' || (url.charAt(0) != '/' && !uri.host)){
+ url = (new dojo._Url(dojo.global.location, url)).toString();
+ }
+
+ if(dojo.indexOf(this.editingAreaStyleSheets, url) > -1){
+// console.debug("dijit._editor.RichText.addStyleSheet: Style sheet "+url+" is already applied");
+ return;
+ }
+
+ this.editingAreaStyleSheets.push(url);
+ this.onLoadDeferred.addCallback(dojo.hitch(this, function(){
+ if(this.document.createStyleSheet){ //IE
+ this.document.createStyleSheet(url);
+ }else{ //other browser
+ var head = this.document.getElementsByTagName("head")[0];
+ var stylesheet = this.document.createElement("link");
+ stylesheet.rel="stylesheet";
+ stylesheet.type="text/css";
+ stylesheet.href=url;
+ head.appendChild(stylesheet);
+ }
+ }));
+ },
+
+ removeStyleSheet: function(/*dojo._Url*/ uri){
+ // summary:
+ // remove an external stylesheet for the editing area
+ var url=uri.toString();
+ //if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
+ if(url.charAt(0) == '.' || (url.charAt(0) != '/' && !uri.host)){
+ url = (new dojo._Url(dojo.global.location, url)).toString();
+ }
+ var index = dojo.indexOf(this.editingAreaStyleSheets, url);
+ if(index == -1){
+// console.debug("dijit._editor.RichText.removeStyleSheet: Style sheet "+url+" has not been applied");
+ return;
+ }
+ delete this.editingAreaStyleSheets[index];
+ dojo.withGlobal(this.window,'query', dojo, ['link:[href="'+url+'"]']).orphan();
+ },
+
+ // disabled: Boolean
+ // The editor is disabled; the text cannot be changed.
+ disabled: false,
+
+ _mozSettingProps: {'styleWithCSS':false},
+ _setDisabledAttr: function(/*Boolean*/ value){
+ value = !!value;
+ this._set("disabled", value);
+ if(!this.isLoaded){ return; } // this method requires init to be complete
+ if(dojo.isIE || dojo.isWebKit || dojo.isOpera){
+ var preventIEfocus = dojo.isIE && (this.isLoaded || !this.focusOnLoad);
+ if(preventIEfocus){ this.editNode.unselectable = "on"; }
+ this.editNode.contentEditable = !value;
+ if(preventIEfocus){
+ var _this = this;
+ setTimeout(function(){ _this.editNode.unselectable = "off"; }, 0);
+ }
+ }else{ //moz
+ try{
+ this.document.designMode=(value?'off':'on');
+ }catch(e){ return; } // ! _disabledOK
+ if(!value && this._mozSettingProps){
+ var ps = this._mozSettingProps;
+ for(var n in ps){
+ if(ps.hasOwnProperty(n)){
+ try{
+ this.document.execCommand(n,false,ps[n]);
+ }catch(e2){}
+ }
+ }
+ }
+// this.document.execCommand('contentReadOnly', false, value);
+// if(value){
+// this.blur(); //to remove the blinking caret
+// }
+ }
+ this._disabledOK = true;
+ },
+
+/* Event handlers
+ *****************/
+
+ onLoad: function(/*String*/ html){
+ // summary:
+ // Handler after the iframe finishes loading.
+ // html: String
+ // Editor contents should be set to this value
+ // tags:
+ // protected
+
+ // TODO: rename this to _onLoad, make empty public onLoad() method, deprecate/make protected onLoadDeferred handler?
+
+ if(!this.window.__registeredWindow){
+ this.window.__registeredWindow = true;
+ this._iframeRegHandle = dijit.registerIframe(this.iframe);
+ }
+ if(!dojo.isIE && !dojo.isWebKit && (this.height || dojo.isMoz)){
+ this.editNode=this.document.body;
+ }else{
+ // there's a wrapper div around the content, see _getIframeDocTxt().
+ this.editNode=this.document.body.firstChild;
+ var _this = this;
+ if(dojo.isIE){ // #4996 IE wants to focus the BODY tag
+ this.tabStop = dojo.create('div', { tabIndex: -1 }, this.editingArea);
+ this.iframe.onfocus = function(){ _this.editNode.setActive(); };
+ }
+ }
+ this.focusNode = this.editNode; // for InlineEditBox
+
+
+ var events = this.events.concat(this.captureEvents);
+ var ap = this.iframe ? this.document : this.editNode;
+ dojo.forEach(events, function(item){
+ this.connect(ap, item.toLowerCase(), item);
+ }, this);
+
+ this.connect(ap, "onmouseup", "onClick"); // mouseup in the margin does not generate an onclick event
+
+ if(dojo.isIE){ // IE contentEditable
+ this.connect(this.document, "onmousedown", "_onIEMouseDown"); // #4996 fix focus
+
+ // give the node Layout on IE
+ // TODO: this may no longer be needed, since we've reverted IE to using an iframe,
+ // not contentEditable. Removing it would also probably remove the need for creating
+ // the extra <div> in _getIframeDocTxt()
+ this.editNode.style.zoom = 1.0;
+ }else{
+ this.connect(this.document, "onmousedown", function(){
+ // Clear the moveToStart focus, as mouse
+ // down will set cursor point. Required to properly
+ // work with selection/position driven plugins and clicks in
+ // the window. refs: #10678
+ delete this._cursorToStart;
+ });
+ }
+
+ if(dojo.isWebKit){
+ //WebKit sometimes doesn't fire right on selections, so the toolbar
+ //doesn't update right. Therefore, help it out a bit with an additional
+ //listener. A mouse up will typically indicate a display change, so fire this
+ //and get the toolbar to adapt. Reference: #9532
+ this._webkitListener = this.connect(this.document, "onmouseup", "onDisplayChanged");
+ this.connect(this.document, "onmousedown", function(e){
+ var t = e.target;
+ if(t && (t === this.document.body || t === this.document)){
+ // Since WebKit uses the inner DIV, we need to check and set position.
+ // See: #12024 as to why the change was made.
+ setTimeout(dojo.hitch(this, "placeCursorAtEnd"), 0);
+ }
+ });
+ }
+
+ if(dojo.isIE){
+ // Try to make sure 'hidden' elements aren't visible in edit mode (like browsers other than IE
+ // do). See #9103
+ try{
+ this.document.execCommand('RespectVisibilityInDesign', true, null);
+ }catch(e){/* squelch */}
+ }
+
+ this.isLoaded = true;
+
+ this.set('disabled', this.disabled); // initialize content to editable (or not)
+
+ // Note that setValue() call will only work after isLoaded is set to true (above)
+
+ // Set up a function to allow delaying the setValue until a callback is fired
+ // This ensures extensions like dijit.Editor have a way to hold the value set
+ // until plugins load (and do things like register filters).
+ var setContent = dojo.hitch(this, function(){
+ this.setValue(html);
+ if(this.onLoadDeferred){
+ this.onLoadDeferred.callback(true);
+ }
+ this.onDisplayChanged();
+ if(this.focusOnLoad){
+ // after the document loads, then set focus after updateInterval expires so that
+ // onNormalizedDisplayChanged has run to avoid input caret issues
+ dojo.addOnLoad(dojo.hitch(this, function(){ setTimeout(dojo.hitch(this, "focus"), this.updateInterval); }));
+ }
+ // Save off the initial content now
+ this.value = this.getValue(true);
+ });
+ if(this.setValueDeferred){
+ this.setValueDeferred.addCallback(setContent);
+ }else{
+ setContent();
+ }
+
+ },
+
+ onKeyDown: function(/* Event */ e){
+ // summary:
+ // Handler for onkeydown event
+ // tags:
+ // protected
+
+ // we need this event at the moment to get the events from control keys
+ // such as the backspace. It might be possible to add this to Dojo, so that
+ // keyPress events can be emulated by the keyDown and keyUp detection.
+
+ if(e.keyCode === dojo.keys.TAB && this.isTabIndent ){
+ dojo.stopEvent(e); //prevent tab from moving focus out of editor
+
+ // FIXME: this is a poor-man's indent/outdent. It would be
+ // better if it added 4 "&nbsp;" chars in an undoable way.
+ // Unfortunately pasteHTML does not prove to be undoable
+ if(this.queryCommandEnabled((e.shiftKey ? "outdent" : "indent"))){
+ this.execCommand((e.shiftKey ? "outdent" : "indent"));
+ }
+ }
+ if(dojo.isIE){
+ if(e.keyCode == dojo.keys.TAB && !this.isTabIndent){
+ if(e.shiftKey && !e.ctrlKey && !e.altKey){
+ // focus the BODY so the browser will tab away from it instead
+ this.iframe.focus();
+ }else if(!e.shiftKey && !e.ctrlKey && !e.altKey){
+ // focus the BODY so the browser will tab away from it instead
+ this.tabStop.focus();
+ }
+ }else if(e.keyCode === dojo.keys.BACKSPACE && this.document.selection.type === "Control"){
+ // IE has a bug where if a non-text object is selected in the editor,
+ // hitting backspace would act as if the browser's back button was
+ // clicked instead of deleting the object. see #1069
+ dojo.stopEvent(e);
+ this.execCommand("delete");
+ }else if((65 <= e.keyCode && e.keyCode <= 90) ||
+ (e.keyCode>=37 && e.keyCode<=40) // FIXME: get this from connect() instead!
+ ){ //arrow keys
+ e.charCode = e.keyCode;
+ this.onKeyPress(e);
+ }
+ }
+ return true;
+ },
+
+ onKeyUp: function(e){
+ // summary:
+ // Handler for onkeyup event
+ // tags:
+ // callback
+ return;
+ },
+
+ setDisabled: function(/*Boolean*/ disabled){
+ // summary:
+ // Deprecated, use set('disabled', ...) instead.
+ // tags:
+ // deprecated
+ dojo.deprecated('dijit.Editor::setDisabled is deprecated','use dijit.Editor::attr("disabled",boolean) instead', 2.0);
+ this.set('disabled',disabled);
+ },
+ _setValueAttr: function(/*String*/ value){
+ // summary:
+ // Registers that attr("value", foo) should call setValue(foo)
+ this.setValue(value);
+ },
+ _setDisableSpellCheckAttr: function(/*Boolean*/ disabled){
+ if(this.document){
+ dojo.attr(this.document.body, "spellcheck", !disabled);
+ }else{
+ // try again after the editor is finished loading
+ this.onLoadDeferred.addCallback(dojo.hitch(this, function(){
+ dojo.attr(this.document.body, "spellcheck", !disabled);
+ }));
+ }
+ this._set("disableSpellCheck", disabled);
+ },
+
+ onKeyPress: function(e){
+ // summary:
+ // Handle the various key events
+ // tags:
+ // protected
+
+ var c = (e.keyChar && e.keyChar.toLowerCase()) || e.keyCode,
+ handlers = this._keyHandlers[c],
+ args = arguments;
+
+ if(handlers && !e.altKey){
+ dojo.some(handlers, function(h){
+ // treat meta- same as ctrl-, for benefit of mac users
+ if(!(h.shift ^ e.shiftKey) && !(h.ctrl ^ (e.ctrlKey||e.metaKey))){
+ if(!h.handler.apply(this, args)){
+ e.preventDefault();
+ }
+ return true;
+ }
+ }, this);
+ }
+
+ // function call after the character has been inserted
+ if(!this._onKeyHitch){
+ this._onKeyHitch = dojo.hitch(this, "onKeyPressed");
+ }
+ setTimeout(this._onKeyHitch, 1);
+ return true;
+ },
+
+ addKeyHandler: function(/*String*/ key, /*Boolean*/ ctrl, /*Boolean*/ shift, /*Function*/ handler){
+ // summary:
+ // Add a handler for a keyboard shortcut
+ // description:
+ // The key argument should be in lowercase if it is a letter character
+ // tags:
+ // protected
+ if(!dojo.isArray(this._keyHandlers[key])){
+ this._keyHandlers[key] = [];
+ }
+ //TODO: would be nice to make this a hash instead of an array for quick lookups
+ this._keyHandlers[key].push({
+ shift: shift || false,
+ ctrl: ctrl || false,
+ handler: handler
+ });
+ },
+
+ onKeyPressed: function(){
+ // summary:
+ // Handler for after the user has pressed a key, and the display has been updated.
+ // (Runs on a timer so that it runs after the display is updated)
+ // tags:
+ // private
+ this.onDisplayChanged(/*e*/); // can't pass in e
+ },
+
+ onClick: function(/*Event*/ e){
+ // summary:
+ // Handler for when the user clicks.
+ // tags:
+ // private
+
+ // console.info('onClick',this._tryDesignModeOn);
+ this.onDisplayChanged(e);
+ },
+
+ _onIEMouseDown: function(/*Event*/ e){
+ // summary:
+ // IE only to prevent 2 clicks to focus
+ // tags:
+ // protected
+
+ if(!this._focused && !this.disabled){
+ this.focus();
+ }
+ },
+
+ _onBlur: function(e){
+ // summary:
+ // Called from focus manager when focus has moved away from this editor
+ // tags:
+ // protected
+
+ // console.info('_onBlur')
+
+ this.inherited(arguments);
+
+ var newValue = this.getValue(true);
+ if(newValue != this.value){
+ this.onChange(newValue);
+ }
+ this._set("value", newValue);
+ },
+
+ _onFocus: function(/*Event*/ e){
+ // summary:
+ // Called from focus manager when focus has moved into this editor
+ // tags:
+ // protected
+
+ // console.info('_onFocus')
+ if(!this.disabled){
+ if(!this._disabledOK){
+ this.set('disabled', false);
+ }
+ this.inherited(arguments);
+ }
+ },
+
+ // TODO: remove in 2.0
+ blur: function(){
+ // summary:
+ // Remove focus from this instance.
+ // tags:
+ // deprecated
+ if(!dojo.isIE && this.window.document.documentElement && this.window.document.documentElement.focus){
+ this.window.document.documentElement.focus();
+ }else if(dojo.doc.body.focus){
+ dojo.doc.body.focus();
+ }
+ },
+
+ focus: function(){
+ // summary:
+ // Move focus to this editor
+ if(!this.isLoaded){
+ this.focusOnLoad = true;
+ return;
+ }
+ if(this._cursorToStart){
+ delete this._cursorToStart;
+ if(this.editNode.childNodes){
+ this.placeCursorAtStart(); // this calls focus() so return
+ return;
+ }
+ }
+ if(!dojo.isIE){
+ dijit.focus(this.iframe);
+ }else if(this.editNode && this.editNode.focus){
+ // editNode may be hidden in display:none div, lets just punt in this case
+ //this.editNode.focus(); -> causes IE to scroll always (strict and quirks mode) to the top the Iframe
+ // if we fire the event manually and let the browser handle the focusing, the latest
+ // cursor position is focused like in FF
+ this.iframe.fireEvent('onfocus', document.createEventObject()); // createEventObject only in IE
+ // }else{
+ // TODO: should we throw here?
+ // console.debug("Have no idea how to focus into the editor!");
+ }
+ },
+
+ // _lastUpdate: 0,
+ updateInterval: 200,
+ _updateTimer: null,
+ onDisplayChanged: function(/*Event*/ e){
+ // summary:
+ // This event will be fired everytime the display context
+ // changes and the result needs to be reflected in the UI.
+ // description:
+ // If you don't want to have update too often,
+ // onNormalizedDisplayChanged should be used instead
+ // tags:
+ // private
+
+ // var _t=new Date();
+ if(this._updateTimer){
+ clearTimeout(this._updateTimer);
+ }
+ if(!this._updateHandler){
+ this._updateHandler = dojo.hitch(this,"onNormalizedDisplayChanged");
+ }
+ this._updateTimer = setTimeout(this._updateHandler, this.updateInterval);
+
+ // Technically this should trigger a call to watch("value", ...) registered handlers,
+ // but getValue() is too slow to call on every keystroke so we don't.
+ },
+ onNormalizedDisplayChanged: function(){
+ // summary:
+ // This event is fired every updateInterval ms or more
+ // description:
+ // If something needs to happen immediately after a
+ // user change, please use onDisplayChanged instead.
+ // tags:
+ // private
+ delete this._updateTimer;
+ },
+ onChange: function(newContent){
+ // summary:
+ // This is fired if and only if the editor loses focus and
+ // the content is changed.
+ },
+ _normalizeCommand: function(/*String*/ cmd, /*Anything?*/argument){
+ // summary:
+ // Used as the advice function by dojo.connect to map our
+ // normalized set of commands to those supported by the target
+ // browser.
+ // tags:
+ // private
+
+ var command = cmd.toLowerCase();
+ if(command == "formatblock"){
+ if(dojo.isSafari && argument === undefined){ command = "heading"; }
+ }else if(command == "hilitecolor" && !dojo.isMoz){
+ command = "backcolor";
+ }
+
+ return command;
+ },
+
+ _qcaCache: {},
+ queryCommandAvailable: function(/*String*/ command){
+ // summary:
+ // Tests whether a command is supported by the host. Clients
+ // SHOULD check whether a command is supported before attempting
+ // to use it, behaviour for unsupported commands is undefined.
+ // command:
+ // The command to test for
+ // tags:
+ // private
+
+ // memoizing version. See _queryCommandAvailable for computing version
+ var ca = this._qcaCache[command];
+ if(ca !== undefined){ return ca; }
+ return (this._qcaCache[command] = this._queryCommandAvailable(command));
+ },
+
+ _queryCommandAvailable: function(/*String*/ command){
+ // summary:
+ // See queryCommandAvailable().
+ // tags:
+ // private
+
+ var ie = 1;
+ var mozilla = 1 << 1;
+ var webkit = 1 << 2;
+ var opera = 1 << 3;
+
+ function isSupportedBy(browsers){
+ return {
+ ie: Boolean(browsers & ie),
+ mozilla: Boolean(browsers & mozilla),
+ webkit: Boolean(browsers & webkit),
+ opera: Boolean(browsers & opera)
+ };
+ }
+
+ var supportedBy = null;
+
+ switch(command.toLowerCase()){
+ case "bold": case "italic": case "underline":
+ case "subscript": case "superscript":
+ case "fontname": case "fontsize":
+ case "forecolor": case "hilitecolor":
+ case "justifycenter": case "justifyfull": case "justifyleft":
+ case "justifyright": case "delete": case "selectall": case "toggledir":
+ supportedBy = isSupportedBy(mozilla | ie | webkit | opera);
+ break;
+
+ case "createlink": case "unlink": case "removeformat":
+ case "inserthorizontalrule": case "insertimage":
+ case "insertorderedlist": case "insertunorderedlist":
+ case "indent": case "outdent": case "formatblock":
+ case "inserthtml": case "undo": case "redo": case "strikethrough": case "tabindent":
+ supportedBy = isSupportedBy(mozilla | ie | opera | webkit);
+ break;
+
+ case "blockdirltr": case "blockdirrtl":
+ case "dirltr": case "dirrtl":
+ case "inlinedirltr": case "inlinedirrtl":
+ supportedBy = isSupportedBy(ie);
+ break;
+ case "cut": case "copy": case "paste":
+ supportedBy = isSupportedBy( ie | mozilla | webkit);
+ break;
+
+ case "inserttable":
+ supportedBy = isSupportedBy(mozilla | ie);
+ break;
+
+ case "insertcell": case "insertcol": case "insertrow":
+ case "deletecells": case "deletecols": case "deleterows":
+ case "mergecells": case "splitcell":
+ supportedBy = isSupportedBy(ie | mozilla);
+ break;
+
+ default: return false;
+ }
+
+ return (dojo.isIE && supportedBy.ie) ||
+ (dojo.isMoz && supportedBy.mozilla) ||
+ (dojo.isWebKit && supportedBy.webkit) ||
+ (dojo.isOpera && supportedBy.opera); // Boolean return true if the command is supported, false otherwise
+ },
+
+ execCommand: function(/*String*/ command, argument){
+ // summary:
+ // Executes a command in the Rich Text area
+ // command:
+ // The command to execute
+ // argument:
+ // An optional argument to the command
+ // tags:
+ // protected
+ var returnValue;
+
+ //focus() is required for IE to work
+ //In addition, focus() makes sure after the execution of
+ //the command, the editor receives the focus as expected
+ this.focus();
+
+ command = this._normalizeCommand(command, argument);
+
+ if(argument !== undefined){
+ if(command == "heading"){
+ throw new Error("unimplemented");
+ }else if((command == "formatblock") && dojo.isIE){
+ argument = '<'+argument+'>';
+ }
+ }
+
+ //Check to see if we have any over-rides for commands, they will be functions on this
+ //widget of the form _commandImpl. If we don't, fall through to the basic native
+ //exec command of the browser.
+ var implFunc = "_" + command + "Impl";
+ if(this[implFunc]){
+ returnValue = this[implFunc](argument);
+ }else{
+ argument = arguments.length > 1 ? argument : null;
+ if(argument || command!="createlink"){
+ returnValue = this.document.execCommand(command, false, argument);
+ }
+ }
+
+ this.onDisplayChanged();
+ return returnValue;
+ },
+
+ queryCommandEnabled: function(/*String*/ command){
+ // summary:
+ // Check whether a command is enabled or not.
+ // tags:
+ // protected
+ if(this.disabled || !this._disabledOK){ return false; }
+ command = this._normalizeCommand(command);
+ if(dojo.isMoz || dojo.isWebKit){
+ if(command == "unlink"){ // mozilla returns true always
+ // console.debug(this._sCall("hasAncestorElement", ['a']));
+ return this._sCall("hasAncestorElement", ["a"]);
+ }else if(command == "inserttable"){
+ return true;
+ }
+ }
+ //see #4109
+ if(dojo.isWebKit){
+ if(command == "cut" || command == "copy") {
+ // WebKit deems clipboard activity as a security threat and natively would return false
+ var sel = this.window.getSelection();
+ if(sel){ sel = sel.toString(); }
+ return !!sel;
+ }else if(command == "paste"){
+ return true;
+ }
+ }
+
+ var elem = dojo.isIE ? this.document.selection.createRange() : this.document;
+ try{
+ return elem.queryCommandEnabled(command);
+ }catch(e){
+ //Squelch, occurs if editor is hidden on FF 3 (and maybe others.)
+ return false;
+ }
+
+ },
+
+ queryCommandState: function(command){
+ // summary:
+ // Check the state of a given command and returns true or false.
+ // tags:
+ // protected
+
+ if(this.disabled || !this._disabledOK){ return false; }
+ command = this._normalizeCommand(command);
+ try{
+ return this.document.queryCommandState(command);
+ }catch(e){
+ //Squelch, occurs if editor is hidden on FF 3 (and maybe others.)
+ return false;
+ }
+ },
+
+ queryCommandValue: function(command){
+ // summary:
+ // Check the value of a given command. This matters most for
+ // custom selections and complex values like font value setting.
+ // tags:
+ // protected
+
+ if(this.disabled || !this._disabledOK){ return false; }
+ var r;
+ command = this._normalizeCommand(command);
+ if(dojo.isIE && command == "formatblock"){
+ r = this._native2LocalFormatNames[this.document.queryCommandValue(command)];
+ }else if(dojo.isMoz && command === "hilitecolor"){
+ var oldValue;
+ try{
+ oldValue = this.document.queryCommandValue("styleWithCSS");
+ }catch(e){
+ oldValue = false;
+ }
+ this.document.execCommand("styleWithCSS", false, true);
+ r = this.document.queryCommandValue(command);
+ this.document.execCommand("styleWithCSS", false, oldValue);
+ }else{
+ r = this.document.queryCommandValue(command);
+ }
+ return r;
+ },
+
+ // Misc.
+
+ _sCall: function(name, args){
+ // summary:
+ // Run the named method of dijit._editor.selection over the
+ // current editor instance's window, with the passed args.
+ // tags:
+ // private
+ return dojo.withGlobal(this.window, name, dijit._editor.selection, args);
+ },
+
+ // FIXME: this is a TON of code duplication. Why?
+
+ placeCursorAtStart: function(){
+ // summary:
+ // Place the cursor at the start of the editing area.
+ // tags:
+ // private
+
+ this.focus();
+
+ //see comments in placeCursorAtEnd
+ var isvalid=false;
+ if(dojo.isMoz){
+ // TODO: Is this branch even necessary?
+ var first=this.editNode.firstChild;
+ while(first){
+ if(first.nodeType == 3){
+ if(first.nodeValue.replace(/^\s+|\s+$/g, "").length>0){
+ isvalid=true;
+ this._sCall("selectElement", [ first ]);
+ break;
+ }
+ }else if(first.nodeType == 1){
+ isvalid=true;
+ var tg = first.tagName ? first.tagName.toLowerCase() : "";
+ // Collapse before childless tags.
+ if(/br|input|img|base|meta|area|basefont|hr|link/.test(tg)){
+ this._sCall("selectElement", [ first ]);
+ }else{
+ // Collapse inside tags with children.
+ this._sCall("selectElementChildren", [ first ]);
+ }
+ break;
+ }
+ first = first.nextSibling;
+ }
+ }else{
+ isvalid=true;
+ this._sCall("selectElementChildren", [ this.editNode ]);
+ }
+ if(isvalid){
+ this._sCall("collapse", [ true ]);
+ }
+ },
+
+ placeCursorAtEnd: function(){
+ // summary:
+ // Place the cursor at the end of the editing area.
+ // tags:
+ // private
+
+ this.focus();
+
+ //In mozilla, if last child is not a text node, we have to use
+ // selectElementChildren on this.editNode.lastChild otherwise the
+ // cursor would be placed at the end of the closing tag of
+ //this.editNode.lastChild
+ var isvalid=false;
+ if(dojo.isMoz){
+ var last=this.editNode.lastChild;
+ while(last){
+ if(last.nodeType == 3){
+ if(last.nodeValue.replace(/^\s+|\s+$/g, "").length>0){
+ isvalid=true;
+ this._sCall("selectElement", [ last ]);
+ break;
+ }
+ }else if(last.nodeType == 1){
+ isvalid=true;
+ if(last.lastChild){
+ this._sCall("selectElement", [ last.lastChild ]);
+ }else{
+ this._sCall("selectElement", [ last ]);
+ }
+ break;
+ }
+ last = last.previousSibling;
+ }
+ }else{
+ isvalid=true;
+ this._sCall("selectElementChildren", [ this.editNode ]);
+ }
+ if(isvalid){
+ this._sCall("collapse", [ false ]);
+ }
+ },
+
+ getValue: function(/*Boolean?*/ nonDestructive){
+ // summary:
+ // Return the current content of the editing area (post filters
+ // are applied). Users should call get('value') instead.
+ // nonDestructive:
+ // defaults to false. Should the post-filtering be run over a copy
+ // of the live DOM? Most users should pass "true" here unless they
+ // *really* know that none of the installed filters are going to
+ // mess up the editing session.
+ // tags:
+ // private
+ if(this.textarea){
+ if(this.isClosed || !this.isLoaded){
+ return this.textarea.value;
+ }
+ }
+
+ return this._postFilterContent(null, nonDestructive);
+ },
+ _getValueAttr: function(){
+ // summary:
+ // Hook to make attr("value") work
+ return this.getValue(true);
+ },
+
+ setValue: function(/*String*/ html){
+ // summary:
+ // This function sets the content. No undo history is preserved.
+ // Users should use set('value', ...) instead.
+ // tags:
+ // deprecated
+
+ // TODO: remove this and getValue() for 2.0, and move code to _setValueAttr()
+
+ if(!this.isLoaded){
+ // try again after the editor is finished loading
+ this.onLoadDeferred.addCallback(dojo.hitch(this, function(){
+ this.setValue(html);
+ }));
+ return;
+ }
+ this._cursorToStart = true;
+ if(this.textarea && (this.isClosed || !this.isLoaded)){
+ this.textarea.value=html;
+ }else{
+ html = this._preFilterContent(html);
+ var node = this.isClosed ? this.domNode : this.editNode;
+ if(html && dojo.isMoz && html.toLowerCase() == "<p></p>"){
+ html = "<p>&nbsp;</p>";
+ }
+
+ // Use &nbsp; to avoid webkit problems where editor is disabled until the user clicks it
+ if(!html && dojo.isWebKit){
+ html = "&nbsp;";
+ }
+ node.innerHTML = html;
+ this._preDomFilterContent(node);
+ }
+
+ this.onDisplayChanged();
+ this._set("value", this.getValue(true));
+ },
+
+ replaceValue: function(/*String*/ html){
+ // summary:
+ // This function set the content while trying to maintain the undo stack
+ // (now only works fine with Moz, this is identical to setValue in all
+ // other browsers)
+ // tags:
+ // protected
+
+ if(this.isClosed){
+ this.setValue(html);
+ }else if(this.window && this.window.getSelection && !dojo.isMoz){ // Safari
+ // look ma! it's a totally f'd browser!
+ this.setValue(html);
+ }else if(this.window && this.window.getSelection){ // Moz
+ html = this._preFilterContent(html);
+ this.execCommand("selectall");
+ if(!html){
+ this._cursorToStart = true;
+ html = "&nbsp;";
+ }
+ this.execCommand("inserthtml", html);
+ this._preDomFilterContent(this.editNode);
+ }else if(this.document && this.document.selection){//IE
+ //In IE, when the first element is not a text node, say
+ //an <a> tag, when replacing the content of the editing
+ //area, the <a> tag will be around all the content
+ //so for now, use setValue for IE too
+ this.setValue(html);
+ }
+
+ this._set("value", this.getValue(true));
+ },
+
+ _preFilterContent: function(/*String*/ html){
+ // summary:
+ // Filter the input before setting the content of the editing
+ // area. DOM pre-filtering may happen after this
+ // string-based filtering takes place but as of 1.2, this is not
+ // guaranteed for operations such as the inserthtml command.
+ // tags:
+ // private
+
+ var ec = html;
+ dojo.forEach(this.contentPreFilters, function(ef){ if(ef){ ec = ef(ec); } });
+ return ec;
+ },
+ _preDomFilterContent: function(/*DomNode*/ dom){
+ // summary:
+ // filter the input's live DOM. All filter operations should be
+ // considered to be "live" and operating on the DOM that the user
+ // will be interacting with in their editing session.
+ // tags:
+ // private
+ dom = dom || this.editNode;
+ dojo.forEach(this.contentDomPreFilters, function(ef){
+ if(ef && dojo.isFunction(ef)){
+ ef(dom);
+ }
+ }, this);
+ },
+
+ _postFilterContent: function(
+ /*DomNode|DomNode[]|String?*/ dom,
+ /*Boolean?*/ nonDestructive){
+ // summary:
+ // filter the output after getting the content of the editing area
+ //
+ // description:
+ // post-filtering allows plug-ins and users to specify any number
+ // of transforms over the editor's content, enabling many common
+ // use-cases such as transforming absolute to relative URLs (and
+ // vice-versa), ensuring conformance with a particular DTD, etc.
+ // The filters are registered in the contentDomPostFilters and
+ // contentPostFilters arrays. Each item in the
+ // contentDomPostFilters array is a function which takes a DOM
+ // Node or array of nodes as its only argument and returns the
+ // same. It is then passed down the chain for further filtering.
+ // The contentPostFilters array behaves the same way, except each
+ // member operates on strings. Together, the DOM and string-based
+ // filtering allow the full range of post-processing that should
+ // be necessaray to enable even the most agressive of post-editing
+ // conversions to take place.
+ //
+ // If nonDestructive is set to "true", the nodes are cloned before
+ // filtering proceeds to avoid potentially destructive transforms
+ // to the content which may still needed to be edited further.
+ // Once DOM filtering has taken place, the serialized version of
+ // the DOM which is passed is run through each of the
+ // contentPostFilters functions.
+ //
+ // dom:
+ // a node, set of nodes, which to filter using each of the current
+ // members of the contentDomPostFilters and contentPostFilters arrays.
+ //
+ // nonDestructive:
+ // defaults to "false". If true, ensures that filtering happens on
+ // a clone of the passed-in content and not the actual node
+ // itself.
+ //
+ // tags:
+ // private
+
+ var ec;
+ if(!dojo.isString(dom)){
+ dom = dom || this.editNode;
+ if(this.contentDomPostFilters.length){
+ if(nonDestructive){
+ dom = dojo.clone(dom);
+ }
+ dojo.forEach(this.contentDomPostFilters, function(ef){
+ dom = ef(dom);
+ });
+ }
+ ec = dijit._editor.getChildrenHtml(dom);
+ }else{
+ ec = dom;
+ }
+
+ if(!dojo.trim(ec.replace(/^\xA0\xA0*/, '').replace(/\xA0\xA0*$/, '')).length){
+ ec = "";
+ }
+
+ // if(dojo.isIE){
+ // //removing appended <P>&nbsp;</P> for IE
+ // ec = ec.replace(/(?:<p>&nbsp;</p>[\n\r]*)+$/i,"");
+ // }
+ dojo.forEach(this.contentPostFilters, function(ef){
+ ec = ef(ec);
+ });
+
+ return ec;
+ },
+
+ _saveContent: function(/*Event*/ e){
+ // summary:
+ // Saves the content in an onunload event if the editor has not been closed
+ // tags:
+ // private
+
+ var saveTextarea = dojo.byId(dijit._scopeName + "._editor.RichText.value");
+ if(saveTextarea.value){
+ saveTextarea.value += this._SEPARATOR;
+ }
+ saveTextarea.value += this.name + this._NAME_CONTENT_SEP + this.getValue(true);
+ },
+
+
+ escapeXml: function(/*String*/ str, /*Boolean*/ noSingleQuotes){
+ // summary:
+ // Adds escape sequences for special characters in XML.
+ // Optionally skips escapes for single quotes
+ // tags:
+ // private
+
+ str = str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
+ if(!noSingleQuotes){
+ str = str.replace(/'/gm, "&#39;");
+ }
+ return str; // string
+ },
+
+ getNodeHtml: function(/* DomNode */ node){
+ // summary:
+ // Deprecated. Use dijit._editor._getNodeHtml() instead.
+ // tags:
+ // deprecated
+ dojo.deprecated('dijit.Editor::getNodeHtml is deprecated','use dijit._editor.getNodeHtml instead', 2);
+ return dijit._editor.getNodeHtml(node); // String
+ },
+
+ getNodeChildrenHtml: function(/* DomNode */ dom){
+ // summary:
+ // Deprecated. Use dijit._editor.getChildrenHtml() instead.
+ // tags:
+ // deprecated
+ dojo.deprecated('dijit.Editor::getNodeChildrenHtml is deprecated','use dijit._editor.getChildrenHtml instead', 2);
+ return dijit._editor.getChildrenHtml(dom);
+ },
+
+ close: function(/*Boolean?*/ save){
+ // summary:
+ // Kills the editor and optionally writes back the modified contents to the
+ // element from which it originated.
+ // save:
+ // Whether or not to save the changes. If false, the changes are discarded.
+ // tags:
+ // private
+
+ if(this.isClosed){ return; }
+
+ if(!arguments.length){ save = true; }
+ if(save){
+ this._set("value", this.getValue(true));
+ }
+
+ // line height is squashed for iframes
+ // FIXME: why was this here? if (this.iframe){ this.domNode.style.lineHeight = null; }
+
+ if(this.interval){ clearInterval(this.interval); }
+
+ if(this._webkitListener){
+ //Cleaup of WebKit fix: #9532
+ this.disconnect(this._webkitListener);
+ delete this._webkitListener;
+ }
+
+ // Guard against memory leaks on IE (see #9268)
+ if(dojo.isIE){
+ this.iframe.onfocus = null;
+ }
+ this.iframe._loadFunc = null;
+
+ if(this._iframeRegHandle){
+ dijit.unregisterIframe(this._iframeRegHandle);
+ delete this._iframeRegHandle;
+ }
+
+ if(this.textarea){
+ var s = this.textarea.style;
+ s.position = "";
+ s.left = s.top = "";
+ if(dojo.isIE){
+ s.overflow = this.__overflow;
+ this.__overflow = null;
+ }
+ this.textarea.value = this.value;
+ dojo.destroy(this.domNode);
+ this.domNode = this.textarea;
+ }else{
+ // Note that this destroys the iframe
+ this.domNode.innerHTML = this.value;
+ }
+ delete this.iframe;
+
+ dojo.removeClass(this.domNode, this.baseClass);
+ this.isClosed = true;
+ this.isLoaded = false;
+
+ delete this.editNode;
+ delete this.focusNode;
+
+ if(this.window && this.window._frameElement){
+ this.window._frameElement = null;
+ }
+
+ this.window = null;
+ this.document = null;
+ this.editingArea = null;
+ this.editorObject = null;
+ },
+
+ destroy: function(){
+ if(!this.isClosed){ this.close(false); }
+ this.inherited(arguments);
+ if(dijit._editor._globalSaveHandler){
+ delete dijit._editor._globalSaveHandler[this.id];
+ }
+ },
+
+ _removeMozBogus: function(/* String */ html){
+ // summary:
+ // Post filter to remove unwanted HTML attributes generated by mozilla
+ // tags:
+ // private
+ return html.replace(/\stype="_moz"/gi, '').replace(/\s_moz_dirty=""/gi, '').replace(/_moz_resizing="(true|false)"/gi,''); // String
+ },
+ _removeWebkitBogus: function(/* String */ html){
+ // summary:
+ // Post filter to remove unwanted HTML attributes generated by webkit
+ // tags:
+ // private
+ html = html.replace(/\sclass="webkit-block-placeholder"/gi, '');
+ html = html.replace(/\sclass="apple-style-span"/gi, '');
+ // For some reason copy/paste sometime adds extra meta tags for charset on
+ // webkit (chrome) on mac.They need to be removed. See: #12007"
+ html = html.replace(/<meta charset=\"utf-8\" \/>/gi, '');
+ return html; // String
+ },
+ _normalizeFontStyle: function(/* String */ html){
+ // summary:
+ // Convert 'strong' and 'em' to 'b' and 'i'.
+ // description:
+ // Moz can not handle strong/em tags correctly, so to help
+ // mozilla and also to normalize output, convert them to 'b' and 'i'.
+ //
+ // Note the IE generates 'strong' and 'em' rather than 'b' and 'i'
+ // tags:
+ // private
+ return html.replace(/<(\/)?strong([ \>])/gi, '<$1b$2')
+ .replace(/<(\/)?em([ \>])/gi, '<$1i$2' ); // String
+ },
+
+ _preFixUrlAttributes: function(/* String */ html){
+ // summary:
+ // Pre-filter to do fixing to href attributes on <a> and <img> tags
+ // tags:
+ // private
+ return html.replace(/(?:(<a(?=\s).*?\shref=)("|')(.*?)\2)|(?:(<a\s.*?href=)([^"'][^ >]+))/gi,
+ '$1$4$2$3$5$2 _djrealurl=$2$3$5$2')
+ .replace(/(?:(<img(?=\s).*?\ssrc=)("|')(.*?)\2)|(?:(<img\s.*?src=)([^"'][^ >]+))/gi,
+ '$1$4$2$3$5$2 _djrealurl=$2$3$5$2'); // String
+ },
+
+ /*****************************************************************************
+ The following functions implement HTML manipulation commands for various
+ browser/contentEditable implementations. The goal of them is to enforce
+ standard behaviors of them.
+ ******************************************************************************/
+
+ _inserthorizontalruleImpl: function(argument){
+ // summary:
+ // This function implements the insertion of HTML 'HR' tags.
+ // into a point on the page. IE doesn't to it right, so
+ // we have to use an alternate form
+ // argument:
+ // arguments to the exec command, if any.
+ // tags:
+ // protected
+ if(dojo.isIE){
+ return this._inserthtmlImpl("<hr>");
+ }
+ return this.document.execCommand("inserthorizontalrule", false, argument);
+ },
+
+ _unlinkImpl: function(argument){
+ // summary:
+ // This function implements the unlink of an 'a' tag.
+ // argument:
+ // arguments to the exec command, if any.
+ // tags:
+ // protected
+ if((this.queryCommandEnabled("unlink")) && (dojo.isMoz || dojo.isWebKit)){
+ var a = this._sCall("getAncestorElement", [ "a" ]);
+ this._sCall("selectElement", [ a ]);
+ return this.document.execCommand("unlink", false, null);
+ }
+ return this.document.execCommand("unlink", false, argument);
+ },
+
+ _hilitecolorImpl: function(argument){
+ // summary:
+ // This function implements the hilitecolor command
+ // argument:
+ // arguments to the exec command, if any.
+ // tags:
+ // protected
+ var returnValue;
+ if(dojo.isMoz){
+ // mozilla doesn't support hilitecolor properly when useCSS is
+ // set to false (bugzilla #279330)
+ this.document.execCommand("styleWithCSS", false, true);
+ returnValue = this.document.execCommand("hilitecolor", false, argument);
+ this.document.execCommand("styleWithCSS", false, false);
+ }else{
+ returnValue = this.document.execCommand("hilitecolor", false, argument);
+ }
+ return returnValue;
+ },
+
+ _backcolorImpl: function(argument){
+ // summary:
+ // This function implements the backcolor command
+ // argument:
+ // arguments to the exec command, if any.
+ // tags:
+ // protected
+ if(dojo.isIE){
+ // Tested under IE 6 XP2, no problem here, comment out
+ // IE weirdly collapses ranges when we exec these commands, so prevent it
+ // var tr = this.document.selection.createRange();
+ argument = argument ? argument : null;
+ }
+ return this.document.execCommand("backcolor", false, argument);
+ },
+
+ _forecolorImpl: function(argument){
+ // summary:
+ // This function implements the forecolor command
+ // argument:
+ // arguments to the exec command, if any.
+ // tags:
+ // protected
+ if(dojo.isIE){
+ // Tested under IE 6 XP2, no problem here, comment out
+ // IE weirdly collapses ranges when we exec these commands, so prevent it
+ // var tr = this.document.selection.createRange();
+ argument = argument? argument : null;
+ }
+ return this.document.execCommand("forecolor", false, argument);
+ },
+
+ _inserthtmlImpl: function(argument){
+ // summary:
+ // This function implements the insertion of HTML content into
+ // a point on the page.
+ // argument:
+ // The content to insert, if any.
+ // tags:
+ // protected
+ argument = this._preFilterContent(argument);
+ var rv = true;
+ if(dojo.isIE){
+ var insertRange = this.document.selection.createRange();
+ if(this.document.selection.type.toUpperCase() == 'CONTROL'){
+ var n=insertRange.item(0);
+ while(insertRange.length){
+ insertRange.remove(insertRange.item(0));
+ }
+ n.outerHTML=argument;
+ }else{
+ insertRange.pasteHTML(argument);
+ }
+ insertRange.select();
+ //insertRange.collapse(true);
+ }else if(dojo.isMoz && !argument.length){
+ //mozilla can not inserthtml an empty html to delete current selection
+ //so we delete the selection instead in this case
+ this._sCall("remove"); // FIXME
+ }else{
+ rv = this.document.execCommand("inserthtml", false, argument);
+ }
+ return rv;
+ },
+
+ _boldImpl: function(argument){
+ // summary:
+ // This function implements an over-ride of the bold command.
+ // argument:
+ // Not used, operates by selection.
+ // tags:
+ // protected
+ if(dojo.isIE){
+ this._adaptIESelection()
+ }
+ return this.document.execCommand("bold", false, argument);
+ },
+
+ _italicImpl: function(argument){
+ // summary:
+ // This function implements an over-ride of the italic command.
+ // argument:
+ // Not used, operates by selection.
+ // tags:
+ // protected
+ if(dojo.isIE){
+ this._adaptIESelection()
+ }
+ return this.document.execCommand("italic", false, argument);
+ },
+
+ _underlineImpl: function(argument){
+ // summary:
+ // This function implements an over-ride of the underline command.
+ // argument:
+ // Not used, operates by selection.
+ // tags:
+ // protected
+ if(dojo.isIE){
+ this._adaptIESelection()
+ }
+ return this.document.execCommand("underline", false, argument);
+ },
+
+ _strikethroughImpl: function(argument){
+ // summary:
+ // This function implements an over-ride of the strikethrough command.
+ // argument:
+ // Not used, operates by selection.
+ // tags:
+ // protected
+ if(dojo.isIE){
+ this._adaptIESelection()
+ }
+ return this.document.execCommand("strikethrough", false, argument);
+ },
+
+ getHeaderHeight: function(){
+ // summary:
+ // A function for obtaining the height of the header node
+ return this._getNodeChildrenHeight(this.header); // Number
+ },
+
+ getFooterHeight: function(){
+ // summary:
+ // A function for obtaining the height of the footer node
+ return this._getNodeChildrenHeight(this.footer); // Number
+ },
+
+ _getNodeChildrenHeight: function(node){
+ // summary:
+ // An internal function for computing the cumulative height of all child nodes of 'node'
+ // node:
+ // The node to process the children of;
+ var h = 0;
+ if(node && node.childNodes){
+ // IE didn't compute it right when position was obtained on the node directly is some cases,
+ // so we have to walk over all the children manually.
+ var i;
+ for(i = 0; i < node.childNodes.length; i++){
+ var size = dojo.position(node.childNodes[i]);
+ h += size.h;
+ }
+ }
+ return h; // Number
+ },
+
+ _isNodeEmpty: function(node, startOffset){
+ // summary:
+ // Function to test if a node is devoid of real content.
+ // node:
+ // The node to check.
+ // tags:
+ // private.
+ if(node.nodeType == 1/*element*/){
+ if(node.childNodes.length > 0){
+ return this._isNodeEmpty(node.childNodes[0], startOffset);
+ }
+ return true;
+ }else if(node.nodeType == 3/*text*/){
+ return (node.nodeValue.substring(startOffset) == "");
+ }
+ return false;
+ },
+
+ _removeStartingRangeFromRange: function(node, range){
+ // summary:
+ // Function to adjust selection range by removing the current
+ // start node.
+ // node:
+ // The node to remove from the starting range.
+ // range:
+ // The range to adapt.
+ // tags:
+ // private
+ if(node.nextSibling){
+ range.setStart(node.nextSibling,0);
+ }else{
+ var parent = node.parentNode;
+ while(parent && parent.nextSibling == null){
+ //move up the tree until we find a parent that has another node, that node will be the next node
+ parent = parent.parentNode;
+ }
+ if(parent){
+ range.setStart(parent.nextSibling,0);
+ }
+ }
+ return range;
+ },
+
+ _adaptIESelection: function(){
+ // summary:
+ // Function to adapt the IE range by removing leading 'newlines'
+ // Needed to fix issue with bold/italics/underline not working if
+ // range included leading 'newlines'.
+ // In IE, if a user starts a selection at the very end of a line,
+ // then the native browser commands will fail to execute correctly.
+ // To work around the issue, we can remove all empty nodes from
+ // the start of the range selection.
+ var selection = dijit.range.getSelection(this.window);
+ if(selection && selection.rangeCount){
+ var range = selection.getRangeAt(0);
+ var firstNode = range.startContainer;
+ var startOffset = range.startOffset;
+
+ while(firstNode.nodeType == 3/*text*/ && startOffset >= firstNode.length && firstNode.nextSibling){
+ //traverse the text nodes until we get to the one that is actually highlighted
+ startOffset = startOffset - firstNode.length;
+ firstNode = firstNode.nextSibling;
+ }
+
+ //Remove the starting ranges until the range does not start with an empty node.
+ var lastNode=null;
+ while(this._isNodeEmpty(firstNode, startOffset) && firstNode != lastNode){
+ lastNode =firstNode; //this will break the loop in case we can't find the next sibling
+ range = this._removeStartingRangeFromRange(firstNode, range); //move the start container to the next node in the range
+ firstNode = range.startContainer;
+ startOffset = 0; //start at the beginning of the new starting range
+ }
+ selection.removeAllRanges();// this will work as long as users cannot select multiple ranges. I have not been able to do that in the editor.
+ selection.addRange(range);
+ }
+ }
+});
+
+}
+
+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; });
+ keyCodes[dojo.keys.HOME] = dojo.hitch(this, "focusFirstChild");
+ keyCodes[dojo.keys.END] = dojo.hitch(this, "focusLastChild");
+ 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);
+ }
+ },
+
+ focusLastChild: function(){
+ // summary:
+ // Focus the last focusable child in the container.
+ // tags:
+ // protected
+ var child = this._getLastFocusableChild();
+ 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._set("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
+ },
+
+ _getLastFocusableChild: function(){
+ // summary:
+ // Returns last 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.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" role="presentation"></div>',
+ buildRendering: function(){
+ this.inherited(arguments);
+ 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");
+
+
+
+
+
+
+
+// Note: require of ToolbarSeparator is for back-compat, remove for 2.0
+
+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" role="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.inherited(arguments);
+
+ this.connectKeyNavHandlers(
+ this.isLeftToRight() ? [dojo.keys.LEFT_ARROW] : [dojo.keys.RIGHT_ARROW],
+ this.isLeftToRight() ? [dojo.keys.RIGHT_ARROW] : [dojo.keys.LEFT_ARROW]
+ );
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+
+ this.startupKeyNavChildren();
+
+ this.inherited(arguments);
+ }
+}
+);
+
+}
+
+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.
+ // Any dropdown taller than this will have scrollbars.
+ // Set to 0 for no max height, or -1 to limit height to available space in viewport
+ 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 && dropDown.autoFocus !== false){
+ // 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);
+ }
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ this._buttonNode = this._buttonNode || this.focusNode || this.domNode;
+ this._popupStateNode = this._popupStateNode || this.focusNode || this._buttonNode;
+
+ // 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(){
+ // summary:
+ // set up nodes and connect our mouse and keypress events
+
+ this.inherited(arguments);
+
+ this.connect(this._buttonNode, "onmousedown", "_onDropDownMouseDown");
+ this.connect(this._buttonNode, "onclick", "_onDropDownClick");
+ this.connect(this.focusNode, "onkeypress", "_onKey");
+ },
+
+ destroy: 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);
+ },
+
+ _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, target = e.target;
+ if(d && this._opened && d.handleKey){
+ if(d.handleKey(e) === false){
+ /* false return code means that the drop down handled the key */
+ dojo.stopEvent(e);
+ return;
+ }
+ }
+ if(d && this._opened && e.charOrCode == dojo.keys.ESCAPE){
+ this.closeDropDown();
+ dojo.stopEvent(e);
+ }else if(!this._opened &&
+ (e.charOrCode == dojo.keys.DOWN_ARROW ||
+ ( (e.charOrCode == dojo.keys.ENTER || e.charOrCode == " ") &&
+ //ignore enter and space if the event is for a text input
+ ((target.tagName || "").toLowerCase() !== 'input' ||
+ (target.type && target.type.toLowerCase() !== 'text'))))){
+ this.toggleDropDown();
+ d = this.dropDown; // drop down may not exist until toggleDropDown() call
+ if(d && d.focus){
+ setTimeout(dojo.hitch(d, "focus"), 1);
+ }
+ dojo.stopEvent(e);
+ }
+ },
+
+ _onBlur: function(){
+ // summary:
+ // Called magically when focus has shifted away from this widget and it's dropdown
+
+ // Don't focus on button if the user has explicitly focused on something else (happens
+ // when user clicks another control causing the current popup to close)..
+ // But if focus is inside of the drop down then reset focus to me, because IE doesn't like
+ // it when you display:none a node with focus.
+ var focusMe = dijit._curFocus && this.dropDown && dojo.isDescendant(dijit._curFocus, this.dropDown.domNode);
+
+ this.closeDropDown(focusMe);
+
+ 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. This is basically a callback when the
+ // user presses the down arrow button to open the drop down.
+ // tags:
+ // protected
+
+ loadCallback();
+ },
+
+ toggleDropDown: function(){
+ // summary:
+ // Callback when the user presses the down arrow button or presses
+ // the down arrow key to open/close the drop down.
+ // Toggle the drop-down widget; if it is up, close it, if not, open it
+ // tags:
+ // protected
+
+ if(this.disabled || this.readOnly){ 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. To be called only when this.dropDown
+ // has been created and is ready to display (ie, it's data is loaded).
+ // returns:
+ // return value of dijit.popup.open()
+ // tags:
+ // protected
+
+ var dropDown = this.dropDown,
+ ddNode = dropDown.domNode,
+ aroundNode = this._aroundNode || this.domNode,
+ 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){
+ 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);
+
+ // Figure out maximum height allowed (if there is a height restriction)
+ var maxHeight = this.maxHeight;
+ if(maxHeight == -1){
+ // limit height to space available in viewport either above or below my domNode
+ // (whichever side has more room)
+ var viewport = dojo.window.getBox(),
+ position = dojo.position(aroundNode, false);
+ maxHeight = Math.floor(Math.max(position.y, viewport.h - (position.y + position.h)));
+ }
+
+ // Attach dropDown to DOM and make make visibility:hidden rather than display:none
+ // so we call startup() and also get the size
+ if(dropDown.startup && !dropDown._started){
+ dropDown.startup();
+ }
+
+ dijit.popup.moveOffScreen(dropDown);
+ // Get size of drop down, and determine if vertical scroll bar needed
+ var mb = dojo._getMarginSize(ddNode);
+ var overHeight = (maxHeight && mb.h > maxHeight);
+ dojo.style(ddNode, {
+ overflowX: "hidden",
+ overflowY: overHeight ? "auto" : "hidden"
+ });
+ if(overHeight){
+ mb.h = maxHeight;
+ if("w" in mb){
+ mb.w += 16; // room for vertical scrollbar
+ }
+ }else{
+ delete mb.h;
+ }
+
+ // Adjust dropdown width to match or be larger than my width
+ if(this.forceWidth){
+ mb.w = aroundNode.offsetWidth;
+ }else if(this.autoWidth){
+ mb.w = Math.max(mb.w, aroundNode.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: 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;
+ }
+ });
+ dojo.attr(this._popupStateNode, "popupActive", "true");
+ dojo.addClass(self._popupStateNode, "dijitHasDropDownOpen");
+ this._opened=true;
+
+ // 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
+ // focus:
+ // If true, refocuses the button widget
+ // tags:
+ // protected
+
+ if(this._opened){
+ if(focus){ this.focus(); }
+ dijit.popup.close(this.dropDown);
+ this._opened = false;
+ }
+ }
+
+ }
+);
+
+}
+
+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\"\r\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\r\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\"\r\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\r\n\t\t\tdojoAttachPoint=\"titleNode,focusNode\"\r\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\r\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\"></span\r\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\r\n\t\t\t\tid=\"${id}_label\"\r\n\t\t\t\tdojoAttachPoint=\"containerNode\"\r\n\t\t\t></span\r\n\t\t></span\r\n\t></span\r\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\r\n\t\tdojoAttachPoint=\"valueNode\"\r\n/></span>\r\n"),
+
+ attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
+ value: "valueNode"
+ }),
+
+ _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
+ }
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dojo.setSelectable(this.focusNode, false);
+ },
+
+ _fillContent: function(/*DomNode*/ source){
+ // Overrides _Templated._fillContent().
+ // If button label is specified as srcNodeRef.innerHTML rather than
+ // this.params.label, handle it here.
+ // TODO: remove the method in 2.0, parser will do it all for me
+ if(source && (!this.params || !("label" in this.params))){
+ this.set('label', source.innerHTML);
+ }
+ },
+
+ _setShowLabelAttr: function(val){
+ if(this.containerNode){
+ dojo.toggleClass(this.containerNode, "dijitDisplayNone", !val);
+ }
+ this._set("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 set('label', ...) to work.
+ // description:
+ // Set the label (text) of the button; takes an HTML string.
+ this._set("label", content);
+ this.containerNode.innerHTML = content;
+ if(this.showLabel == false && !this.params.title){
+ this.titleNode.title = dojo.trim(this.containerNode.innerText || this.containerNode.textContent || '');
+ }
+ },
+
+ _setIconClassAttr: function(/*String*/ val){
+ // Custom method so that icon node is hidden when not in use, to avoid excess padding/margin
+ // appearing around it (even if it's a 0x0 sized <img> node)
+
+ var oldVal = this.iconClass || "dijitNoIcon",
+ newVal = val || "dijitNoIcon";
+ dojo.replaceClass(this.iconNode, newVal, oldVal);
+ this._set("iconClass", val);
+ }
+});
+
+
+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\"\r\n\t><span class='dijitReset dijitInline dijitButtonNode'\r\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\" dojoAttachPoint=\"_buttonNode\"\r\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\r\n\t\t\tdojoAttachPoint=\"focusNode,titleNode,_arrowWrapperNode\"\r\n\t\t\trole=\"button\" aria-haspopup=\"true\" aria-labelledby=\"${id}_label\"\r\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\"\r\n\t\t\t\tdojoAttachPoint=\"iconNode\"\r\n\t\t\t></span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\r\n\t\t\t\tdojoAttachPoint=\"containerNode,_popupStateNode\"\r\n\t\t\t\tid=\"${id}_label\"\r\n\t\t\t></span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonInner\"></span\r\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonChar\">&#9660;</span\r\n\t\t></span\r\n\t></span\r\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\r\n\t\tdojoAttachPoint=\"valueNode\"\r\n/></span>\r\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 && this.dropDownContainer){
+ var dropDownNode = dojo.query("[widgetId]", this.dropDownContainer)[0];
+ this.dropDown = dijit.byNode(dropDownNode);
+ delete this.dropDownContainer;
+ }
+ if(this.dropDown){
+ dijit.popup.hide(this.dropDown);
+ }
+
+ 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 && (!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\"\r\n\tcellspacing='0' cellpadding='0' role=\"presentation\"\r\n\t><tbody role=\"presentation\"><tr role=\"presentation\"\r\n\t\t><td class=\"dijitReset dijitStretch dijitButtonNode\" dojoAttachPoint=\"buttonNode\" dojoAttachEvent=\"ondijitclick:_onButtonClick,onkeypress:_onButtonKeyPress\"\r\n\t\t><div id=\"${id}_button\" class=\"dijitReset dijitButtonContents\"\r\n\t\t\tdojoAttachPoint=\"titleNode\"\r\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\r\n\t\t\t><div class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\" role=\"presentation\"></div\r\n\t\t\t><div class=\"dijitReset dijitInline dijitButtonText\" id=\"${id}_label\" dojoAttachPoint=\"containerNode\" role=\"presentation\"></div\r\n\t\t></div\r\n\t\t></td\r\n\t\t><td id=\"${id}_arrow\" class='dijitReset dijitRight dijitButtonNode dijitArrowButton'\r\n\t\t\tdojoAttachPoint=\"_popupStateNode,focusNode,_buttonNode\"\r\n\t\t\tdojoAttachEvent=\"onkeypress:_onArrowKeyPress\"\r\n\t\t\ttitle=\"${optionsTitle}\"\r\n\t\t\trole=\"button\" aria-haspopup=\"true\"\r\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" role=\"presentation\"></div\r\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" role=\"presentation\">&#9660;</div\r\n\t\t></td\r\n\t\t><td style=\"display:none !important;\"\r\n\t\t\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" dojoAttachPoint=\"valueNode\"\r\n\t\t/></td></tr></tbody\r\n></table>\r\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"
+ if(!this.disabled){
+ 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._set("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._editor._Plugin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._editor._Plugin"] = true;
+dojo.provide("dijit._editor._Plugin");
+
+
+
+
+
+dojo.declare("dijit._editor._Plugin", null, {
+ // summary
+ // Base class for a "plugin" to the editor, which is usually
+ // a single button on the Toolbar and some associated code
+
+ constructor: function(/*Object?*/args, /*DomNode?*/node){
+ this.params = args || {};
+ dojo.mixin(this, this.params);
+ this._connects=[];
+ this._attrPairNames = {};
+ },
+
+ // editor: [const] dijit.Editor
+ // Points to the parent editor
+ editor: null,
+
+ // iconClassPrefix: [const] String
+ // The CSS class name for the button node is formed from `iconClassPrefix` and `command`
+ iconClassPrefix: "dijitEditorIcon",
+
+ // button: dijit._Widget?
+ // Pointer to `dijit.form.Button` or other widget (ex: `dijit.form.FilteringSelect`)
+ // that is added to the toolbar to control this plugin.
+ // If not specified, will be created on initialization according to `buttonClass`
+ button: null,
+
+ // command: String
+ // String like "insertUnorderedList", "outdent", "justifyCenter", etc. that represents an editor command.
+ // Passed to editor.execCommand() if `useDefaultCommand` is true.
+ command: "",
+
+ // useDefaultCommand: Boolean
+ // If true, this plugin executes by calling Editor.execCommand() with the argument specified in `command`.
+ useDefaultCommand: true,
+
+ // buttonClass: Widget Class
+ // Class of widget (ex: dijit.form.Button or dijit.form.FilteringSelect)
+ // that is added to the toolbar to control this plugin.
+ // This is used to instantiate the button, unless `button` itself is specified directly.
+ buttonClass: dijit.form.Button,
+
+ // disabled: Boolean
+ // Flag to indicate if this plugin has been disabled and should do nothing
+ // helps control button state, among other things. Set via the setter api.
+ disabled: false,
+
+ getLabel: function(/*String*/key){
+ // summary:
+ // Returns the label to use for the button
+ // tags:
+ // private
+ return this.editor.commands[key]; // String
+ },
+
+ _initButton: function(){
+ // summary:
+ // Initialize the button or other widget that will control this plugin.
+ // This code only works for plugins controlling built-in commands in the editor.
+ // tags:
+ // protected extension
+ if(this.command.length){
+ var label = this.getLabel(this.command),
+ editor = this.editor,
+ className = this.iconClassPrefix+" "+this.iconClassPrefix + this.command.charAt(0).toUpperCase() + this.command.substr(1);
+ if(!this.button){
+ var props = dojo.mixin({
+ label: label,
+ dir: editor.dir,
+ lang: editor.lang,
+ showLabel: false,
+ iconClass: className,
+ dropDown: this.dropDown,
+ tabIndex: "-1"
+ }, this.params || {});
+ this.button = new this.buttonClass(props);
+ }
+ }
+ if(this.get("disabled") && this.button){
+ this.button.set("disabled", this.get("disabled"));
+ }
+ },
+
+ destroy: function(){
+ // summary:
+ // Destroy this plugin
+
+ dojo.forEach(this._connects, dojo.disconnect);
+ if(this.dropDown){
+ this.dropDown.destroyRecursive();
+ }
+ },
+
+ connect: function(o, f, tf){
+ // summary:
+ // Make a dojo.connect() that is automatically disconnected when this plugin is destroyed.
+ // Similar to `dijit._Widget.connect`.
+ // tags:
+ // protected
+ this._connects.push(dojo.connect(o, f, this, tf));
+ },
+
+ updateState: function(){
+ // summary:
+ // Change state of the plugin to respond to events in the editor.
+ // description:
+ // This is called on meaningful events in the editor, such as change of selection
+ // or caret position (but not simple typing of alphanumeric keys). It gives the
+ // plugin a chance to update the CSS of its button.
+ //
+ // For example, the "bold" plugin will highlight/unhighlight the bold button depending on whether the
+ // characters next to the caret are bold or not.
+ //
+ // Only makes sense when `useDefaultCommand` is true, as it calls Editor.queryCommandEnabled(`command`).
+ var e = this.editor,
+ c = this.command,
+ checked, enabled;
+ if(!e || !e.isLoaded || !c.length){ return; }
+ var disabled = this.get("disabled");
+ if(this.button){
+ try{
+ enabled = !disabled && e.queryCommandEnabled(c);
+ if(this.enabled !== enabled){
+ this.enabled = enabled;
+ this.button.set('disabled', !enabled);
+ }
+ if(typeof this.button.checked == 'boolean'){
+ checked = e.queryCommandState(c);
+ if(this.checked !== checked){
+ this.checked = checked;
+ this.button.set('checked', e.queryCommandState(c));
+ }
+ }
+ }catch(e){
+ console.log(e); // FIXME: we shouldn't have debug statements in our code. Log as an error?
+ }
+ }
+ },
+
+ setEditor: function(/*dijit.Editor*/ editor){
+ // summary:
+ // Tell the plugin which Editor it is associated with.
+
+ // TODO: refactor code to just pass editor to constructor.
+
+ // FIXME: detach from previous editor!!
+ this.editor = editor;
+
+ // FIXME: prevent creating this if we don't need to (i.e., editor can't handle our command)
+ this._initButton();
+
+ // Processing for buttons that execute by calling editor.execCommand()
+ if(this.button && this.useDefaultCommand){
+ if(this.editor.queryCommandAvailable(this.command)){
+ this.connect(this.button, "onClick",
+ dojo.hitch(this.editor, "execCommand", this.command, this.commandArg)
+ );
+ }else{
+ // hide button because editor doesn't support command (due to browser limitations)
+ this.button.domNode.style.display = "none";
+ }
+ }
+
+ this.connect(this.editor, "onNormalizedDisplayChanged", "updateState");
+ },
+
+ setToolbar: function(/*dijit.Toolbar*/ toolbar){
+ // summary:
+ // Tell the plugin to add it's controller widget (often a button)
+ // to the toolbar. Does nothing if there is no controller widget.
+
+ // TODO: refactor code to just pass toolbar to constructor.
+
+ if(this.button){
+ toolbar.addChild(this.button);
+ }
+ // console.debug("adding", this.button, "to:", toolbar);
+ },
+
+ set: function(/* attribute */ name, /* anything */ value){
+ // summary:
+ // Set a property on a plugin
+ // name:
+ // The property to set.
+ // value:
+ // The value to set in the property.
+ // description:
+ // Sets named properties on a plugin which may potentially be handled by a
+ // setter in the plugin.
+ // For example, if the plugin has a properties "foo"
+ // and "bar" and a method named "_setFooAttr", calling:
+ // | plugin.set("foo", "Howdy!");
+ // would be equivalent to writing:
+ // | plugin._setFooAttr("Howdy!");
+ // and:
+ // | plugin.set("bar", 3);
+ // would be equivalent to writing:
+ // | plugin.bar = 3;
+ //
+ // set() may also be called with a hash of name/value pairs, ex:
+ // | plugin.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{
+ this._set(name, value);
+ }
+ return result || this;
+ },
+
+ get: function(name){
+ // summary:
+ // Get a property from a plugin.
+ // name:
+ // The property to get.
+ // description:
+ // Get a named property from a plugin. 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 plugin has a properties "foo"
+ // and "bar" and a method named "_getFooAttr", calling:
+ // | plugin.get("foo");
+ // would be equivalent to writing:
+ // | plugin._getFooAttr();
+ // and:
+ // | plugin.get("bar");
+ // would be equivalent to writing:
+ // | plugin.bar;
+ var names = this._getAttrNames(name);
+ return this[names.g] ? this[names.g]() : this[name];
+ },
+
+ _setDisabledAttr: function(disabled){
+ // summary:
+ // Function to set the plugin state and call updateState to make sure the
+ // button is updated appropriately.
+ this.disabled = disabled;
+ this.updateState();
+ },
+
+ _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] = {
+ s: "_set"+uc+"Attr",
+ g: "_get"+uc+"Attr"
+ });
+ },
+
+ _set: function(/*String*/ name, /*anything*/ value){
+ // summary:
+ // Helper function to set new value for specified attribute
+ var oldValue = this[name];
+ this[name] = value;
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit._editor.plugins.EnterKeyHandling"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._editor.plugins.EnterKeyHandling"] = true;
+dojo.provide("dijit._editor.plugins.EnterKeyHandling");
+
+
+
+
+
+
+dojo.declare("dijit._editor.plugins.EnterKeyHandling", dijit._editor._Plugin, {
+ // summary:
+ // This plugin tries to make all browsers behave consistently with regard to
+ // how ENTER behaves in the editor window. It traps the ENTER key and alters
+ // the way DOM is constructed in certain cases to try to commonize the generated
+ // DOM and behaviors across browsers.
+ //
+ // description:
+ // This plugin has three modes:
+ //
+ // * blockModeForEnter=BR
+ // * blockModeForEnter=DIV
+ // * blockModeForEnter=P
+ //
+ // In blockModeForEnter=P, the ENTER key starts a new
+ // paragraph, and shift-ENTER starts a new line in the current paragraph.
+ // For example, the input:
+ //
+ // | first paragraph <shift-ENTER>
+ // | second line of first paragraph <ENTER>
+ // | second paragraph
+ //
+ // will generate:
+ //
+ // | <p>
+ // | first paragraph
+ // | <br/>
+ // | second line of first paragraph
+ // | </p>
+ // | <p>
+ // | second paragraph
+ // | </p>
+ //
+ // In BR and DIV mode, the ENTER key conceptually goes to a new line in the
+ // current paragraph, and users conceptually create a new paragraph by pressing ENTER twice.
+ // For example, if the user enters text into an editor like this:
+ //
+ // | one <ENTER>
+ // | two <ENTER>
+ // | three <ENTER>
+ // | <ENTER>
+ // | four <ENTER>
+ // | five <ENTER>
+ // | six <ENTER>
+ //
+ // It will appear on the screen as two 'paragraphs' of three lines each. Markupwise, this generates:
+ //
+ // BR:
+ // | one<br/>
+ // | two<br/>
+ // | three<br/>
+ // | <br/>
+ // | four<br/>
+ // | five<br/>
+ // | six<br/>
+ //
+ // DIV:
+ // | <div>one</div>
+ // | <div>two</div>
+ // | <div>three</div>
+ // | <div>&nbsp;</div>
+ // | <div>four</div>
+ // | <div>five</div>
+ // | <div>six</div>
+
+ // blockNodeForEnter: String
+ // This property decides the behavior of Enter key. It can be either P,
+ // DIV, BR, or empty (which means disable this feature). Anything else
+ // will trigger errors. The default is 'BR'
+ //
+ // See class description for more details.
+ blockNodeForEnter: 'BR',
+
+ constructor: function(args){
+ if(args){
+ if("blockNodeForEnter" in args){
+ args.blockNodeForEnter = args.blockNodeForEnter.toUpperCase();
+ }
+ dojo.mixin(this,args);
+ }
+ },
+
+ setEditor: function(editor){
+ // Overrides _Plugin.setEditor().
+ if(this.editor === editor) { return; }
+ this.editor = editor;
+ if(this.blockNodeForEnter == 'BR'){
+ // While Moz has a mode tht mostly works, it's still a little different,
+ // So, try to just have a common mode and be consistent. Which means
+ // we need to enable customUndo, if not already enabled.
+ this.editor.customUndo = true;
+ editor.onLoadDeferred.addCallback(dojo.hitch(this,function(d){
+ this.connect(editor.document, "onkeypress", function(e){
+ if(e.charOrCode == dojo.keys.ENTER){
+ // Just do it manually. The handleEnterKey has a shift mode that
+ // Always acts like <br>, so just use it.
+ var ne = dojo.mixin({},e);
+ ne.shiftKey = true;
+ if(!this.handleEnterKey(ne)){
+ dojo.stopEvent(e);
+ }
+ }
+ });
+ return d;
+ }));
+ }else if(this.blockNodeForEnter){
+ // add enter key handler
+ // FIXME: need to port to the new event code!!
+ var h = dojo.hitch(this,this.handleEnterKey);
+ editor.addKeyHandler(13, 0, 0, h); //enter
+ editor.addKeyHandler(13, 0, 1, h); //shift+enter
+ this.connect(this.editor,'onKeyPressed','onKeyPressed');
+ }
+ },
+ onKeyPressed: function(e){
+ // summary:
+ // Handler for keypress events.
+ // tags:
+ // private
+ if(this._checkListLater){
+ if(dojo.withGlobal(this.editor.window, 'isCollapsed', dijit)){
+ var liparent=dojo.withGlobal(this.editor.window, 'getAncestorElement', dijit._editor.selection, ['LI']);
+ if(!liparent){
+ // circulate the undo detection code by calling RichText::execCommand directly
+ dijit._editor.RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter);
+ // set the innerHTML of the new block node
+ var block = dojo.withGlobal(this.editor.window, 'getAncestorElement', dijit._editor.selection, [this.blockNodeForEnter]);
+ if(block){
+ block.innerHTML=this.bogusHtmlContent;
+ if(dojo.isIE){
+ // move to the start by moving backwards one char
+ var r = this.editor.document.selection.createRange();
+ r.move('character',-1);
+ r.select();
+ }
+ }else{
+ console.error('onKeyPressed: Cannot find the new block node'); // FIXME
+ }
+ }else{
+ if(dojo.isMoz){
+ if(liparent.parentNode.parentNode.nodeName == 'LI'){
+ liparent=liparent.parentNode.parentNode;
+ }
+ }
+ var fc=liparent.firstChild;
+ if(fc && fc.nodeType == 1 && (fc.nodeName == 'UL' || fc.nodeName == 'OL')){
+ liparent.insertBefore(fc.ownerDocument.createTextNode('\xA0'),fc);
+ var newrange = dijit.range.create(this.editor.window);
+ newrange.setStart(liparent.firstChild,0);
+ var selection = dijit.range.getSelection(this.editor.window, true);
+ selection.removeAllRanges();
+ selection.addRange(newrange);
+ }
+ }
+ }
+ this._checkListLater = false;
+ }
+ if(this._pressedEnterInBlock){
+ // the new created is the original current P, so we have previousSibling below
+ if(this._pressedEnterInBlock.previousSibling){
+ this.removeTrailingBr(this._pressedEnterInBlock.previousSibling);
+ }
+ delete this._pressedEnterInBlock;
+ }
+ },
+
+ // bogusHtmlContent: [private] String
+ // HTML to stick into a new empty block
+ bogusHtmlContent: '&nbsp;',
+
+ // blockNodes: [private] Regex
+ // Regex for testing if a given tag is a block level (display:block) tag
+ blockNodes: /^(?:P|H1|H2|H3|H4|H5|H6|LI)$/,
+
+ handleEnterKey: function(e){
+ // summary:
+ // Handler for enter key events when blockModeForEnter is DIV or P.
+ // description:
+ // Manually handle enter key event to make the behavior consistent across
+ // all supported browsers. See class description for details.
+ // tags:
+ // private
+
+ var selection, range, newrange, doc=this.editor.document,br,rs,txt;
+ if(e.shiftKey){ // shift+enter always generates <br>
+ var parent = dojo.withGlobal(this.editor.window, "getParentElement", dijit._editor.selection);
+ var header = dijit.range.getAncestor(parent,this.blockNodes);
+ if(header){
+ if(header.tagName == 'LI'){
+ return true; // let browser handle
+ }
+ selection = dijit.range.getSelection(this.editor.window);
+ range = selection.getRangeAt(0);
+ if(!range.collapsed){
+ range.deleteContents();
+ selection = dijit.range.getSelection(this.editor.window);
+ range = selection.getRangeAt(0);
+ }
+ if(dijit.range.atBeginningOfContainer(header, range.startContainer, range.startOffset)){
+ br=doc.createElement('br');
+ newrange = dijit.range.create(this.editor.window);
+ header.insertBefore(br,header.firstChild);
+ newrange.setStartBefore(br.nextSibling);
+ selection.removeAllRanges();
+ selection.addRange(newrange);
+ }else if(dijit.range.atEndOfContainer(header, range.startContainer, range.startOffset)){
+ newrange = dijit.range.create(this.editor.window);
+ br=doc.createElement('br');
+ header.appendChild(br);
+ header.appendChild(doc.createTextNode('\xA0'));
+ newrange.setStart(header.lastChild,0);
+ selection.removeAllRanges();
+ selection.addRange(newrange);
+ }else{
+ rs = range.startContainer;
+ if(rs && rs.nodeType == 3){
+ // Text node, we have to split it.
+ txt = rs.nodeValue;
+ dojo.withGlobal(this.editor.window, function(){
+ var startNode = doc.createTextNode(txt.substring(0, range.startOffset));
+ var endNode = doc.createTextNode(txt.substring(range.startOffset));
+ var brNode = doc.createElement("br");
+
+ if(endNode.nodeValue == "" && dojo.isWebKit){
+ endNode = doc.createTextNode('\xA0')
+ }
+ dojo.place(startNode, rs, "after");
+ dojo.place(brNode, startNode, "after");
+ dojo.place(endNode, brNode, "after");
+ dojo.destroy(rs);
+ newrange = dijit.range.create(dojo.gobal);
+ newrange.setStart(endNode,0);
+ selection.removeAllRanges();
+ selection.addRange(newrange);
+ });
+ return false;
+ }
+ return true; // let browser handle
+ }
+ }else{
+ selection = dijit.range.getSelection(this.editor.window);
+ if(selection.rangeCount){
+ range = selection.getRangeAt(0);
+ if(range && range.startContainer){
+ if(!range.collapsed){
+ range.deleteContents();
+ selection = dijit.range.getSelection(this.editor.window);
+ range = selection.getRangeAt(0);
+ }
+ rs = range.startContainer;
+ var startNode, endNode, brNode;
+ if(rs && rs.nodeType == 3){
+ // Text node, we have to split it.
+ dojo.withGlobal(this.editor.window, dojo.hitch(this, function(){
+ var endEmpty = false;
+
+ var offset = range.startOffset;
+ if(rs.length < offset){
+ //We are not splitting the right node, try to locate the correct one
+ ret = this._adjustNodeAndOffset(rs, offset);
+ rs = ret.node;
+ offset = ret.offset;
+ }
+ txt = rs.nodeValue;
+
+ startNode = doc.createTextNode(txt.substring(0, offset));
+ endNode = doc.createTextNode(txt.substring(offset));
+ brNode = doc.createElement("br");
+
+ if(!endNode.length){
+ endNode = doc.createTextNode('\xA0');
+ endEmpty = true;
+ }
+
+ if(startNode.length){
+ dojo.place(startNode, rs, "after");
+ }else{
+ startNode = rs;
+ }
+ dojo.place(brNode, startNode, "after");
+ dojo.place(endNode, brNode, "after");
+ dojo.destroy(rs);
+ newrange = dijit.range.create(dojo.gobal);
+ newrange.setStart(endNode,0);
+ newrange.setEnd(endNode, endNode.length);
+ selection.removeAllRanges();
+ selection.addRange(newrange);
+ if(endEmpty && !dojo.isWebKit){
+ dijit._editor.selection.remove();
+ }else{
+ dijit._editor.selection.collapse(true);
+ }
+ }));
+ }else{
+ dojo.withGlobal(this.editor.window, dojo.hitch(this, function(){
+ var brNode = doc.createElement("br");
+ rs.appendChild(brNode);
+ var endNode = doc.createTextNode('\xA0');
+ rs.appendChild(endNode);
+ newrange = dijit.range.create(dojo.global);
+ newrange.setStart(endNode,0);
+ newrange.setEnd(endNode, endNode.length);
+ selection.removeAllRanges();
+ selection.addRange(newrange);
+ dijit._editor.selection.collapse(true);
+ }));
+ }
+ }
+ }else{
+ // don't change this: do not call this.execCommand, as that may have other logic in subclass
+ dijit._editor.RichText.prototype.execCommand.call(this.editor, 'inserthtml', '<br>');
+ }
+ }
+ return false;
+ }
+ var _letBrowserHandle = true;
+
+ // first remove selection
+ selection = dijit.range.getSelection(this.editor.window);
+ range = selection.getRangeAt(0);
+ if(!range.collapsed){
+ range.deleteContents();
+ selection = dijit.range.getSelection(this.editor.window);
+ range = selection.getRangeAt(0);
+ }
+
+ var block = dijit.range.getBlockAncestor(range.endContainer, null, this.editor.editNode);
+ var blockNode = block.blockNode;
+
+ // if this is under a LI or the parent of the blockNode is LI, just let browser to handle it
+ if((this._checkListLater = (blockNode && (blockNode.nodeName == 'LI' || blockNode.parentNode.nodeName == 'LI')))){
+ if(dojo.isMoz){
+ // press enter in middle of P may leave a trailing <br/>, let's remove it later
+ this._pressedEnterInBlock = blockNode;
+ }
+ // if this li only contains spaces, set the content to empty so the browser will outdent this item
+ if(/^(\s|&nbsp;|\xA0|<span\b[^>]*\bclass=['"]Apple-style-span['"][^>]*>(\s|&nbsp;|\xA0)<\/span>)?(<br>)?$/.test(blockNode.innerHTML)){
+ // empty LI node
+ blockNode.innerHTML = '';
+ if(dojo.isWebKit){ // WebKit tosses the range when innerHTML is reset
+ newrange = dijit.range.create(this.editor.window);
+ newrange.setStart(blockNode, 0);
+ selection.removeAllRanges();
+ selection.addRange(newrange);
+ }
+ this._checkListLater = false; // nothing to check since the browser handles outdent
+ }
+ return true;
+ }
+
+ // text node directly under body, let's wrap them in a node
+ if(!block.blockNode || block.blockNode===this.editor.editNode){
+ try{
+ dijit._editor.RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter);
+ }catch(e2){ /*squelch FF3 exception bug when editor content is a single BR*/ }
+ // get the newly created block node
+ // FIXME
+ block = {blockNode:dojo.withGlobal(this.editor.window, "getAncestorElement", dijit._editor.selection, [this.blockNodeForEnter]),
+ blockContainer: this.editor.editNode};
+ if(block.blockNode){
+ if(block.blockNode != this.editor.editNode &&
+ (!(block.blockNode.textContent || block.blockNode.innerHTML).replace(/^\s+|\s+$/g, "").length)){
+ this.removeTrailingBr(block.blockNode);
+ return false;
+ }
+ }else{ // we shouldn't be here if formatblock worked
+ block.blockNode = this.editor.editNode;
+ }
+ selection = dijit.range.getSelection(this.editor.window);
+ range = selection.getRangeAt(0);
+ }
+
+ var newblock = doc.createElement(this.blockNodeForEnter);
+ newblock.innerHTML=this.bogusHtmlContent;
+ this.removeTrailingBr(block.blockNode);
+ var endOffset = range.endOffset;
+ var node = range.endContainer;
+ if(node.length < endOffset){
+ //We are not checking the right node, try to locate the correct one
+ var ret = this._adjustNodeAndOffset(node, endOffset);
+ node = ret.node;
+ endOffset = ret.offset;
+ }
+ if(dijit.range.atEndOfContainer(block.blockNode, node, endOffset)){
+ if(block.blockNode === block.blockContainer){
+ block.blockNode.appendChild(newblock);
+ }else{
+ dojo.place(newblock, block.blockNode, "after");
+ }
+ _letBrowserHandle = false;
+ // lets move caret to the newly created block
+ newrange = dijit.range.create(this.editor.window);
+ newrange.setStart(newblock, 0);
+ selection.removeAllRanges();
+ selection.addRange(newrange);
+ if(this.editor.height){
+ dojo.window.scrollIntoView(newblock);
+ }
+ }else if(dijit.range.atBeginningOfContainer(block.blockNode,
+ range.startContainer, range.startOffset)){
+ dojo.place(newblock, block.blockNode, block.blockNode === block.blockContainer ? "first" : "before");
+ if(newblock.nextSibling && this.editor.height){
+ // position input caret - mostly WebKit needs this
+ newrange = dijit.range.create(this.editor.window);
+ newrange.setStart(newblock.nextSibling, 0);
+ selection.removeAllRanges();
+ selection.addRange(newrange);
+ // browser does not scroll the caret position into view, do it manually
+ dojo.window.scrollIntoView(newblock.nextSibling);
+ }
+ _letBrowserHandle = false;
+ }else{ //press enter in the middle of P/DIV/Whatever/
+ if(block.blockNode === block.blockContainer){
+ block.blockNode.appendChild(newblock);
+ }else{
+ dojo.place(newblock, block.blockNode, "after");
+ }
+ _letBrowserHandle = false;
+
+ // Clone any block level styles.
+ if(block.blockNode.style){
+ if(newblock.style){
+ if(block.blockNode.style.cssText){
+ newblock.style.cssText = block.blockNode.style.cssText;
+ }
+ }
+ }
+
+ // Okay, we probably have to split.
+ rs = range.startContainer;
+ if(rs && rs.nodeType == 3){
+ // Text node, we have to split it.
+ var nodeToMove, tNode;
+ endOffset = range.endOffset;
+ if(rs.length < endOffset){
+ //We are not splitting the right node, try to locate the correct one
+ ret = this._adjustNodeAndOffset(rs, endOffset);
+ rs = ret.node;
+ endOffset = ret.offset;
+ }
+
+ txt = rs.nodeValue;
+ var startNode = doc.createTextNode(txt.substring(0, endOffset));
+ var endNode = doc.createTextNode(txt.substring(endOffset, txt.length));
+
+ // Place the split, then remove original nodes.
+ dojo.place(startNode, rs, "before");
+ dojo.place(endNode, rs, "after");
+ dojo.destroy(rs);
+
+ // Okay, we split the text. Now we need to see if we're
+ // parented to the block element we're splitting and if
+ // not, we have to split all the way up. Ugh.
+ var parentC = startNode.parentNode;
+ while(parentC !== block.blockNode){
+ var tg = parentC.tagName;
+ var newTg = doc.createElement(tg);
+ // Clone over any 'style' data.
+ if(parentC.style){
+ if(newTg.style){
+ if(parentC.style.cssText){
+ newTg.style.cssText = parentC.style.cssText;
+ }
+ }
+ }
+
+ nodeToMove = endNode;
+ while(nodeToMove){
+ tNode = nodeToMove.nextSibling;
+ newTg.appendChild(nodeToMove);
+ nodeToMove = tNode;
+ }
+ dojo.place(newTg, parentC, "after");
+ startNode = parentC;
+ endNode = newTg;
+ parentC = parentC.parentNode;
+ }
+
+ // Lastly, move the split out tags to the new block.
+ // as they should now be split properly.
+ nodeToMove = endNode;
+ if(nodeToMove.nodeType == 1 || (nodeToMove.nodeType == 3 && nodeToMove.nodeValue)){
+ // Non-blank text and non-text nodes need to clear out that blank space
+ // before moving the contents.
+ newblock.innerHTML = "";
+ }
+ while(nodeToMove){
+ tNode = nodeToMove.nextSibling;
+ newblock.appendChild(nodeToMove);
+ nodeToMove = tNode;
+ }
+ }
+
+ //lets move caret to the newly created block
+ newrange = dijit.range.create(this.editor.window);
+ newrange.setStart(newblock, 0);
+ selection.removeAllRanges();
+ selection.addRange(newrange);
+ if(this.editor.height){
+ dijit.scrollIntoView(newblock);
+ }
+ if(dojo.isMoz){
+ // press enter in middle of P may leave a trailing <br/>, let's remove it later
+ this._pressedEnterInBlock = block.blockNode;
+ }
+ }
+ return _letBrowserHandle;
+ },
+
+ _adjustNodeAndOffset: function(/*DomNode*/node, /*Int*/offset){
+ // summary:
+ // In the case there are multiple text nodes in a row the offset may not be within the node. If the offset is larger than the node length, it will attempt to find
+ // the next text sibling until it locates the text node in which the offset refers to
+ // node:
+ // The node to check.
+ // offset:
+ // The position to find within the text node
+ // tags:
+ // private.
+ while(node.length < offset && node.nextSibling && node.nextSibling.nodeType==3){
+ //Adjust the offset and node in the case of multiple text nodes in a row
+ offset = offset - node.length;
+ node = node.nextSibling;
+ }
+ var ret = {"node": node, "offset": offset};
+ return ret;
+ },
+
+ removeTrailingBr: function(container){
+ // summary:
+ // If last child of container is a <br>, then remove it.
+ // tags:
+ // private
+ var para = /P|DIV|LI/i.test(container.tagName) ?
+ container : dijit._editor.selection.getParentOfType(container,['P','DIV','LI']);
+
+ if(!para){ return; }
+ if(para.lastChild){
+ if((para.childNodes.length > 1 && para.lastChild.nodeType == 3 && /^[\s\xAD]*$/.test(para.lastChild.nodeValue)) ||
+ para.lastChild.tagName=='BR'){
+
+ dojo.destroy(para.lastChild);
+ }
+ }
+ if(!para.childNodes.length){
+ para.innerHTML=this.bogusHtmlContent;
+ }
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.Editor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.Editor"] = true;
+dojo.provide("dijit.Editor");
+
+
+
+
+
+
+
+
+
+
+
+
+
+dojo.declare(
+ "dijit.Editor",
+ dijit._editor.RichText,
+ {
+ // summary:
+ // A rich text Editing widget
+ //
+ // description:
+ // This widget provides basic WYSIWYG editing features, based on the browser's
+ // underlying rich text editing capability, accompanied by a toolbar (`dijit.Toolbar`).
+ // A plugin model is available to extend the editor's capabilities as well as the
+ // the options available in the toolbar. Content generation may vary across
+ // browsers, and clipboard operations may have different results, to name
+ // a few limitations. Note: this widget should not be used with the HTML
+ // &lt;TEXTAREA&gt; tag -- see dijit._editor.RichText for details.
+
+ // plugins: [const] Object[]
+ // A list of plugin names (as strings) or instances (as objects)
+ // for this widget.
+ //
+ // When declared in markup, it might look like:
+ // | plugins="['bold',{name:'dijit._editor.plugins.FontChoice', command:'fontName', generic:true}]"
+ plugins: null,
+
+ // extraPlugins: [const] Object[]
+ // A list of extra plugin names which will be appended to plugins array
+ extraPlugins: null,
+
+ constructor: function(){
+ // summary:
+ // Runs on widget initialization to setup arrays etc.
+ // tags:
+ // private
+
+ if(!dojo.isArray(this.plugins)){
+ this.plugins=["undo","redo","|","cut","copy","paste","|","bold","italic","underline","strikethrough","|",
+ "insertOrderedList","insertUnorderedList","indent","outdent","|","justifyLeft","justifyRight","justifyCenter","justifyFull",
+ "dijit._editor.plugins.EnterKeyHandling" /*, "createLink"*/];
+ }
+
+ this._plugins=[];
+ this._editInterval = this.editActionInterval * 1000;
+
+ //IE will always lose focus when other element gets focus, while for FF and safari,
+ //when no iframe is used, focus will be lost whenever another element gets focus.
+ //For IE, we can connect to onBeforeDeactivate, which will be called right before
+ //the focus is lost, so we can obtain the selected range. For other browsers,
+ //no equivelent of onBeforeDeactivate, so we need to do two things to make sure
+ //selection is properly saved before focus is lost: 1) when user clicks another
+ //element in the page, in which case we listen to mousedown on the entire page and
+ //see whether user clicks out of a focus editor, if so, save selection (focus will
+ //only lost after onmousedown event is fired, so we can obtain correct caret pos.)
+ //2) when user tabs away from the editor, which is handled in onKeyDown below.
+ if(dojo.isIE){
+ this.events.push("onBeforeDeactivate");
+ this.events.push("onBeforeActivate");
+ }
+ },
+
+ postMixInProperties: function() {
+ // summary:
+ // Extension to make sure a deferred is in place before certain functions
+ // execute, like making sure all the plugins are properly inserted.
+
+ // Set up a deferred so that the value isn't applied to the editor
+ // until all the plugins load, needed to avoid timing condition
+ // reported in #10537.
+ this.setValueDeferred = new dojo.Deferred();
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ //for custom undo/redo, if enabled.
+ this._steps=this._steps.slice(0);
+ this._undoedSteps=this._undoedSteps.slice(0);
+
+ if(dojo.isArray(this.extraPlugins)){
+ this.plugins=this.plugins.concat(this.extraPlugins);
+ }
+
+ this.inherited(arguments);
+
+ this.commands = dojo.i18n.getLocalization("dijit._editor", "commands", this.lang);
+
+ if(!this.toolbar){
+ // if we haven't been assigned a toolbar, create one
+ this.toolbar = new dijit.Toolbar({
+ dir: this.dir,
+ lang: this.lang
+ });
+ this.header.appendChild(this.toolbar.domNode);
+ }
+
+ dojo.forEach(this.plugins, this.addPlugin, this);
+
+ // Okay, denote the value can now be set.
+ this.setValueDeferred.callback(true);
+
+ dojo.addClass(this.iframe.parentNode, "dijitEditorIFrameContainer");
+ dojo.addClass(this.iframe, "dijitEditorIFrame");
+ dojo.attr(this.iframe, "allowTransparency", true);
+
+ if(dojo.isWebKit){
+ // Disable selecting the entire editor by inadvertant double-clicks.
+ // on buttons, title bar, etc. Otherwise clicking too fast on
+ // a button such as undo/redo selects the entire editor.
+ dojo.style(this.domNode, "KhtmlUserSelect", "none");
+ }
+ this.toolbar.startup();
+ this.onNormalizedDisplayChanged(); //update toolbar button status
+ },
+ destroy: function(){
+ dojo.forEach(this._plugins, function(p){
+ if(p && p.destroy){
+ p.destroy();
+ }
+ });
+ this._plugins=[];
+ this.toolbar.destroyRecursive();
+ delete this.toolbar;
+ this.inherited(arguments);
+ },
+ addPlugin: function(/*String||Object*/plugin, /*Integer?*/index){
+ // summary:
+ // takes a plugin name as a string or a plugin instance and
+ // adds it to the toolbar and associates it with this editor
+ // instance. The resulting plugin is added to the Editor's
+ // plugins array. If index is passed, it's placed in the plugins
+ // array at that index. No big magic, but a nice helper for
+ // passing in plugin names via markup.
+ //
+ // plugin: String, args object or plugin instance
+ //
+ // args:
+ // This object will be passed to the plugin constructor
+ //
+ // index: Integer
+ // Used when creating an instance from
+ // something already in this.plugins. Ensures that the new
+ // instance is assigned to this.plugins at that index.
+ var args=dojo.isString(plugin)?{name:plugin}:plugin;
+ if(!args.setEditor){
+ var o={"args":args,"plugin":null,"editor":this};
+ dojo.publish(dijit._scopeName + ".Editor.getPlugin",[o]);
+ if(!o.plugin){
+ var pc = dojo.getObject(args.name);
+ if(pc){
+ o.plugin=new pc(args);
+ }
+ }
+ if(!o.plugin){
+ console.warn('Cannot find plugin',plugin);
+ return;
+ }
+ plugin=o.plugin;
+ }
+ if(arguments.length > 1){
+ this._plugins[index] = plugin;
+ }else{
+ this._plugins.push(plugin);
+ }
+ plugin.setEditor(this);
+ if(dojo.isFunction(plugin.setToolbar)){
+ plugin.setToolbar(this.toolbar);
+ }
+ },
+ //the following 3 functions are required to make the editor play nice under a layout widget, see #4070
+ startup: function(){
+ // summary:
+ // Exists to make Editor work as a child of a layout widget.
+ // Developers don't need to call this method.
+ // tags:
+ // protected
+ //console.log('startup',arguments);
+ },
+ resize: function(size){
+ // summary:
+ // Resize the editor to the specified size, see `dijit.layout._LayoutWidget.resize`
+ if(size){
+ // we've been given a height/width for the entire editor (toolbar + contents), calls layout()
+ // to split the allocated size between the toolbar and the contents
+ dijit.layout._LayoutWidget.prototype.resize.apply(this, arguments);
+ }
+ /*
+ else{
+ // do nothing, the editor is already laid out correctly. The user has probably specified
+ // the height parameter, which was used to set a size on the iframe
+ }
+ */
+ },
+ layout: function(){
+ // summary:
+ // Called from `dijit.layout._LayoutWidget.resize`. This shouldn't be called directly
+ // tags:
+ // protected
+
+ // Converts the iframe (or rather the <div> surrounding it) to take all the available space
+ // except what's needed for the header (toolbars) and footer (breadcrumbs, etc).
+ // A class was added to the iframe container and some themes style it, so we have to
+ // calc off the added margins and padding too. See tracker: #10662
+ var areaHeight = (this._contentBox.h -
+ (this.getHeaderHeight() + this.getFooterHeight() +
+ dojo._getPadBorderExtents(this.iframe.parentNode).h +
+ dojo._getMarginExtents(this.iframe.parentNode).h));
+ this.editingArea.style.height = areaHeight + "px";
+ if(this.iframe){
+ this.iframe.style.height="100%";
+ }
+ this._layoutMode = true;
+ },
+ _onIEMouseDown: function(/*Event*/ e){
+ // summary:
+ // IE only to prevent 2 clicks to focus
+ // tags:
+ // private
+ var outsideClientArea;
+ // IE 8's componentFromPoint is broken, which is a shame since it
+ // was smaller code, but oh well. We have to do this brute force
+ // to detect if the click was scroller or not.
+ var b = this.document.body;
+ var clientWidth = b.clientWidth;
+ var clientHeight = b.clientHeight;
+ var clientLeft = b.clientLeft;
+ var offsetWidth = b.offsetWidth;
+ var offsetHeight = b.offsetHeight;
+ var offsetLeft = b.offsetLeft;
+
+ //Check for vertical scroller click.
+ bodyDir = b.dir ? b.dir.toLowerCase() : "";
+ if(bodyDir != "rtl"){
+ if(clientWidth < offsetWidth && e.x > clientWidth && e.x < offsetWidth){
+ // Check the click was between width and offset width, if so, scroller
+ outsideClientArea = true;
+ }
+ }else{
+ // RTL mode, we have to go by the left offsets.
+ if(e.x < clientLeft && e.x > offsetLeft){
+ // Check the click was between width and offset width, if so, scroller
+ outsideClientArea = true;
+ }
+ }
+ if(!outsideClientArea){
+ // Okay, might be horiz scroller, check that.
+ if(clientHeight < offsetHeight && e.y > clientHeight && e.y < offsetHeight){
+ // Horizontal scroller.
+ outsideClientArea = true;
+ }
+ }
+ if(!outsideClientArea){
+ delete this._cursorToStart; // Remove the force to cursor to start position.
+ delete this._savedSelection; // new mouse position overrides old selection
+ if(e.target.tagName == "BODY"){
+ setTimeout(dojo.hitch(this, "placeCursorAtEnd"), 0);
+ }
+ this.inherited(arguments);
+ }
+ },
+ onBeforeActivate: function(e){
+ this._restoreSelection();
+ },
+ onBeforeDeactivate: function(e){
+ // summary:
+ // Called on IE right before focus is lost. Saves the selected range.
+ // tags:
+ // private
+ if(this.customUndo){
+ this.endEditing(true);
+ }
+ //in IE, the selection will be lost when other elements get focus,
+ //let's save focus before the editor is deactivated
+ if(e.target.tagName != "BODY"){
+ this._saveSelection();
+ }
+ //console.log('onBeforeDeactivate',this);
+ },
+
+ /* beginning of custom undo/redo support */
+
+ // customUndo: Boolean
+ // Whether we shall use custom undo/redo support instead of the native
+ // browser support. By default, we now use custom undo. It works better
+ // than native browser support and provides a consistent behavior across
+ // browsers with a minimal performance hit. We already had the hit on
+ // the slowest browser, IE, anyway.
+ customUndo: true,
+
+ // editActionInterval: Integer
+ // When using customUndo, not every keystroke will be saved as a step.
+ // Instead typing (including delete) will be grouped together: after
+ // a user stops typing for editActionInterval seconds, a step will be
+ // saved; if a user resume typing within editActionInterval seconds,
+ // the timeout will be restarted. By default, editActionInterval is 3
+ // seconds.
+ editActionInterval: 3,
+
+ beginEditing: function(cmd){
+ // summary:
+ // Called to note that the user has started typing alphanumeric characters, if it's not already noted.
+ // Deals with saving undo; see editActionInterval parameter.
+ // tags:
+ // private
+ if(!this._inEditing){
+ this._inEditing=true;
+ this._beginEditing(cmd);
+ }
+ if(this.editActionInterval>0){
+ if(this._editTimer){
+ clearTimeout(this._editTimer);
+ }
+ this._editTimer = setTimeout(dojo.hitch(this, this.endEditing), this._editInterval);
+ }
+ },
+
+ // TODO: declaring these in the prototype is meaningless, just create in the constructor/postCreate
+ _steps:[],
+ _undoedSteps:[],
+
+ execCommand: function(cmd){
+ // summary:
+ // Main handler for executing any commands to the editor, like paste, bold, etc.
+ // Called by plugins, but not meant to be called by end users.
+ // tags:
+ // protected
+ if(this.customUndo && (cmd == 'undo' || cmd == 'redo')){
+ return this[cmd]();
+ }else{
+ if(this.customUndo){
+ this.endEditing();
+ this._beginEditing();
+ }
+ var r;
+ var isClipboard = /copy|cut|paste/.test(cmd);
+ try{
+ r = this.inherited(arguments);
+ if(dojo.isWebKit && isClipboard && !r){ //see #4598: webkit does not guarantee clipboard support from js
+ throw { code: 1011 }; // throw an object like Mozilla's error
+ }
+ }catch(e){
+ //TODO: when else might we get an exception? Do we need the Mozilla test below?
+ if(e.code == 1011 /* Mozilla: service denied */ && isClipboard){
+ // Warn user of platform limitation. Cannot programmatically access clipboard. See ticket #4136
+ var sub = dojo.string.substitute,
+ accel = {cut:'X', copy:'C', paste:'V'};
+ alert(sub(this.commands.systemShortcut,
+ [this.commands[cmd], sub(this.commands[dojo.isMac ? 'appleKey' : 'ctrlKey'], [accel[cmd]])]));
+ }
+ r = false;
+ }
+ if(this.customUndo){
+ this._endEditing();
+ }
+ return r;
+ }
+ },
+ queryCommandEnabled: function(cmd){
+ // summary:
+ // Returns true if specified editor command is enabled.
+ // Used by the plugins to know when to highlight/not highlight buttons.
+ // tags:
+ // protected
+ if(this.customUndo && (cmd == 'undo' || cmd == 'redo')){
+ return cmd == 'undo' ? (this._steps.length > 1) : (this._undoedSteps.length > 0);
+ }else{
+ return this.inherited(arguments);
+ }
+ },
+ _moveToBookmark: function(b){
+ // summary:
+ // Selects the text specified in bookmark b
+ // tags:
+ // private
+ var bookmark = b.mark;
+ var mark = b.mark;
+ var col = b.isCollapsed;
+ var r, sNode, eNode, sel;
+ if(mark){
+ if(dojo.isIE){
+ if(dojo.isArray(mark)){
+ //IE CONTROL, have to use the native bookmark.
+ bookmark = [];
+ dojo.forEach(mark,function(n){
+ bookmark.push(dijit.range.getNode(n,this.editNode));
+ },this);
+ dojo.withGlobal(this.window,'moveToBookmark',dijit,[{mark: bookmark, isCollapsed: col}]);
+ }else{
+ if(mark.startContainer && mark.endContainer){
+ // Use the pseudo WC3 range API. This works better for positions
+ // than the IE native bookmark code.
+ sel = dijit.range.getSelection(this.window);
+ if(sel && sel.removeAllRanges){
+ sel.removeAllRanges();
+ r = dijit.range.create(this.window);
+ sNode = dijit.range.getNode(mark.startContainer,this.editNode);
+ eNode = dijit.range.getNode(mark.endContainer,this.editNode);
+ if(sNode && eNode){
+ // Okay, we believe we found the position, so add it into the selection
+ // There are cases where it may not be found, particularly in undo/redo, when
+ // IE changes the underlying DOM on us (wraps text in a <p> tag or similar.
+ // So, in those cases, don't bother restoring selection.
+ r.setStart(sNode,mark.startOffset);
+ r.setEnd(eNode,mark.endOffset);
+ sel.addRange(r);
+ }
+ }
+ }
+ }
+ }else{//w3c range
+ sel = dijit.range.getSelection(this.window);
+ if(sel && sel.removeAllRanges){
+ sel.removeAllRanges();
+ r = dijit.range.create(this.window);
+ sNode = dijit.range.getNode(mark.startContainer,this.editNode);
+ eNode = dijit.range.getNode(mark.endContainer,this.editNode);
+ if(sNode && eNode){
+ // Okay, we believe we found the position, so add it into the selection
+ // There are cases where it may not be found, particularly in undo/redo, when
+ // formatting as been done and so on, so don't restore selection then.
+ r.setStart(sNode,mark.startOffset);
+ r.setEnd(eNode,mark.endOffset);
+ sel.addRange(r);
+ }
+ }
+ }
+ }
+ },
+ _changeToStep: function(from, to){
+ // summary:
+ // Reverts editor to "to" setting, from the undo stack.
+ // tags:
+ // private
+ this.setValue(to.text);
+ var b=to.bookmark;
+ if(!b){ return; }
+ this._moveToBookmark(b);
+ },
+ undo: function(){
+ // summary:
+ // Handler for editor undo (ex: ctrl-z) operation
+ // tags:
+ // private
+ //console.log('undo');
+ var ret = false;
+ if(!this._undoRedoActive){
+ this._undoRedoActive = true;
+ this.endEditing(true);
+ var s=this._steps.pop();
+ if(s && this._steps.length>0){
+ this.focus();
+ this._changeToStep(s,this._steps[this._steps.length-1]);
+ this._undoedSteps.push(s);
+ this.onDisplayChanged();
+ delete this._undoRedoActive;
+ ret = true;
+ }
+ delete this._undoRedoActive;
+ }
+ return ret;
+ },
+ redo: function(){
+ // summary:
+ // Handler for editor redo (ex: ctrl-y) operation
+ // tags:
+ // private
+ //console.log('redo');
+ var ret = false;
+ if(!this._undoRedoActive){
+ this._undoRedoActive = true;
+ this.endEditing(true);
+ var s=this._undoedSteps.pop();
+ if(s && this._steps.length>0){
+ this.focus();
+ this._changeToStep(this._steps[this._steps.length-1],s);
+ this._steps.push(s);
+ this.onDisplayChanged();
+ ret = true;
+ }
+ delete this._undoRedoActive;
+ }
+ return ret;
+ },
+ endEditing: function(ignore_caret){
+ // summary:
+ // Called to note that the user has stopped typing alphanumeric characters, if it's not already noted.
+ // Deals with saving undo; see editActionInterval parameter.
+ // tags:
+ // private
+ if(this._editTimer){
+ clearTimeout(this._editTimer);
+ }
+ if(this._inEditing){
+ this._endEditing(ignore_caret);
+ this._inEditing=false;
+ }
+ },
+
+ _getBookmark: function(){
+ // summary:
+ // Get the currently selected text
+ // tags:
+ // protected
+ var b=dojo.withGlobal(this.window,dijit.getBookmark);
+ var tmp=[];
+ if(b && b.mark){
+ var mark = b.mark;
+ if(dojo.isIE){
+ // Try to use the pseudo range API on IE for better accuracy.
+ var sel = dijit.range.getSelection(this.window);
+ if(!dojo.isArray(mark)){
+ if(sel){
+ var range;
+ if(sel.rangeCount){
+ range = sel.getRangeAt(0);
+ }
+ if(range){
+ b.mark = range.cloneRange();
+ }else{
+ b.mark = dojo.withGlobal(this.window,dijit.getBookmark);
+ }
+ }
+ }else{
+ // Control ranges (img, table, etc), handle differently.
+ dojo.forEach(b.mark,function(n){
+ tmp.push(dijit.range.getIndex(n,this.editNode).o);
+ },this);
+ b.mark = tmp;
+ }
+ }
+ try{
+ if(b.mark && b.mark.startContainer){
+ tmp=dijit.range.getIndex(b.mark.startContainer,this.editNode).o;
+ b.mark={startContainer:tmp,
+ startOffset:b.mark.startOffset,
+ endContainer:b.mark.endContainer===b.mark.startContainer?tmp:dijit.range.getIndex(b.mark.endContainer,this.editNode).o,
+ endOffset:b.mark.endOffset};
+ }
+ }catch(e){
+ b.mark = null;
+ }
+ }
+ return b;
+ },
+ _beginEditing: function(cmd){
+ // summary:
+ // Called when the user starts typing alphanumeric characters.
+ // Deals with saving undo; see editActionInterval parameter.
+ // tags:
+ // private
+ if(this._steps.length === 0){
+ // You want to use the editor content without post filtering
+ // to make sure selection restores right for the 'initial' state.
+ // and undo is called. So not using this.value, as it was 'processed'
+ // and the line-up for selections may have been altered.
+ this._steps.push({'text':dijit._editor.getChildrenHtml(this.editNode),'bookmark':this._getBookmark()});
+ }
+ },
+ _endEditing: function(ignore_caret){
+ // summary:
+ // Called when the user stops typing alphanumeric characters.
+ // Deals with saving undo; see editActionInterval parameter.
+ // tags:
+ // private
+ // Avoid filtering to make sure selections restore.
+ var v = dijit._editor.getChildrenHtml(this.editNode);
+
+ this._undoedSteps=[];//clear undoed steps
+ this._steps.push({text: v, bookmark: this._getBookmark()});
+ },
+ onKeyDown: function(e){
+ // summary:
+ // Handler for onkeydown event.
+ // tags:
+ // private
+
+ //We need to save selection if the user TAB away from this editor
+ //no need to call _saveSelection for IE, as that will be taken care of in onBeforeDeactivate
+ if(!dojo.isIE && !this.iframe && e.keyCode == dojo.keys.TAB && !this.tabIndent){
+ this._saveSelection();
+ }
+ if(!this.customUndo){
+ this.inherited(arguments);
+ return;
+ }
+ var k = e.keyCode, ks = dojo.keys;
+ if(e.ctrlKey && !e.altKey){//undo and redo only if the special right Alt + z/y are not pressed #5892
+ if(k == 90 || k == 122){ //z
+ dojo.stopEvent(e);
+ this.undo();
+ return;
+ }else if(k == 89 || k == 121){ //y
+ dojo.stopEvent(e);
+ this.redo();
+ return;
+ }
+ }
+ this.inherited(arguments);
+
+ switch(k){
+ case ks.ENTER:
+ case ks.BACKSPACE:
+ case ks.DELETE:
+ this.beginEditing();
+ break;
+ case 88: //x
+ case 86: //v
+ if(e.ctrlKey && !e.altKey && !e.metaKey){
+ this.endEditing();//end current typing step if any
+ if(e.keyCode == 88){
+ this.beginEditing('cut');
+ //use timeout to trigger after the cut is complete
+ setTimeout(dojo.hitch(this, this.endEditing), 1);
+ }else{
+ this.beginEditing('paste');
+ //use timeout to trigger after the paste is complete
+ setTimeout(dojo.hitch(this, this.endEditing), 1);
+ }
+ break;
+ }
+ //pass through
+ default:
+ if(!e.ctrlKey && !e.altKey && !e.metaKey && (e.keyCode<dojo.keys.F1 || e.keyCode>dojo.keys.F15)){
+ this.beginEditing();
+ break;
+ }
+ //pass through
+ case ks.ALT:
+ this.endEditing();
+ break;
+ case ks.UP_ARROW:
+ case ks.DOWN_ARROW:
+ case ks.LEFT_ARROW:
+ case ks.RIGHT_ARROW:
+ case ks.HOME:
+ case ks.END:
+ case ks.PAGE_UP:
+ case ks.PAGE_DOWN:
+ this.endEditing(true);
+ break;
+ //maybe ctrl+backspace/delete, so don't endEditing when ctrl is pressed
+ case ks.CTRL:
+ case ks.SHIFT:
+ case ks.TAB:
+ break;
+ }
+ },
+ _onBlur: function(){
+ // summary:
+ // Called from focus manager when focus has moved away from this editor
+ // tags:
+ // protected
+
+ //this._saveSelection();
+ this.inherited(arguments);
+ this.endEditing(true);
+ },
+ _saveSelection: function(){
+ // summary:
+ // Save the currently selected text in _savedSelection attribute
+ // tags:
+ // private
+ try{
+ this._savedSelection=this._getBookmark();
+ }catch(e){ /* Squelch any errors that occur if selection save occurs due to being hidden simultaniously. */}
+ },
+ _restoreSelection: function(){
+ // summary:
+ // Re-select the text specified in _savedSelection attribute;
+ // see _saveSelection().
+ // tags:
+ // private
+ if(this._savedSelection){
+ // Clear off cursor to start, we're deliberately going to a selection.
+ delete this._cursorToStart;
+ // only restore the selection if the current range is collapsed
+ // if not collapsed, then it means the editor does not lose
+ // selection and there is no need to restore it
+ if(dojo.withGlobal(this.window,'isCollapsed',dijit)){
+ this._moveToBookmark(this._savedSelection);
+ }
+ delete this._savedSelection;
+ }
+ },
+
+ onClick: function(){
+ // summary:
+ // Handler for when editor is clicked
+ // tags:
+ // protected
+ this.endEditing(true);
+ this.inherited(arguments);
+ },
+
+ replaceValue: function(/*String*/ html){
+ // summary:
+ // over-ride of replaceValue to support custom undo and stack maintainence.
+ // tags:
+ // protected
+ if(!this.customUndo){
+ this.inherited(arguments);
+ }else{
+ if(this.isClosed){
+ this.setValue(html);
+ }else{
+ this.beginEditing();
+ if(!html){
+ html = "&nbsp;"
+ }
+ this.setValue(html);
+ this.endEditing();
+ }
+ }
+ },
+
+ _setDisabledAttr: function(/*Boolean*/ value){
+ var disableFunc = dojo.hitch(this, function(){
+ if((!this.disabled && value) || (!this._buttonEnabledPlugins && value)){
+ // Disable editor: disable all enabled buttons and remember that list
+ dojo.forEach(this._plugins, function(p){
+ p.set("disabled", true);
+ });
+ }else if(this.disabled && !value){
+ // Restore plugins to being active.
+ dojo.forEach(this._plugins, function(p){
+ p.set("disabled", false);
+ });
+ }
+ });
+ this.setValueDeferred.addCallback(disableFunc);
+ this.inherited(arguments);
+ },
+
+ _setStateClass: function(){
+ try{
+ this.inherited(arguments);
+
+ // Let theme set the editor's text color based on editor enabled/disabled state.
+ // We need to jump through hoops because the main document (where the theme CSS is)
+ // is separate from the iframe's document.
+ if(this.document && this.document.body){
+ dojo.style(this.document.body, "color", dojo.style(this.iframe, "color"));
+ }
+ }catch(e){ /* Squelch any errors caused by focus change if hidden during a state change */}
+ }
+ }
+);
+
+// Register the "default plugins", ie, the built-in editor commands
+dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
+ if(o.plugin){ return; }
+ var args = o.args, p;
+ var _p = dijit._editor._Plugin;
+ var name = args.name;
+ switch(name){
+ case "undo": case "redo": case "cut": case "copy": case "paste": case "insertOrderedList":
+ case "insertUnorderedList": case "indent": case "outdent": case "justifyCenter":
+ case "justifyFull": case "justifyLeft": case "justifyRight": case "delete":
+ case "selectAll": case "removeFormat": case "unlink":
+ case "insertHorizontalRule":
+ p = new _p({ command: name });
+ break;
+
+ case "bold": case "italic": case "underline": case "strikethrough":
+ case "subscript": case "superscript":
+ p = new _p({ buttonClass: dijit.form.ToggleButton, command: name });
+ break;
+ case "|":
+ p = new _p({ button: new dijit.ToolbarSeparator(), setEditor: function(editor) {this.editor = editor;} });
+ }
+// console.log('name',name,p);
+ o.plugin=p;
+});
+
+}
+
+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.getObject("regexp", true, dojo);
+
+/*=====
+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.getObject("data.util.sorter", true, dojo);
+
+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.getObject("data.util.simpleFetch", true, dojo);
+
+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.getObject("data.util.filter", true, dojo);
+
+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}\" role=\"presentation\"\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\r\n\t\t\t${!nameAttrSetting} type='${type}'\r\n\t/></div\r\n></div>\r\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 && 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._set("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 get('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 set('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._set("displayedValue", this.get("displayedValue"));
+ }
+
+ 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 set('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 get('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 get('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)
+
+ // TODO: maybe we should update this.displayedValue on every keystroke so that we don't need
+ // this method
+ // TODO: this isn't really the displayed value when the user is typing
+ 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 set('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;
+
+ // sets the serialized value to something corresponding to specified displayedValue
+ // (if possible), and also updates the textbox.value, for example converting "123"
+ // to "123.00"
+ this._setValueAttr(this.get('value'), undefined);
+
+ this._set("displayedValue", this.get('displayedValue'));
+ },
+
+ 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();
+
+ // In case someone is watch()'ing for changes to displayedValue
+ this._set("displayedValue", this.get("displayedValue"));
+ },
+
+ postCreate: function(){
+ if(dojo.isIE){ // IE INPUT tag fontFamily has to be set directly using STYLE
+ // the setTimeout gives IE a chance to render the TextBox and to deal with font inheritance
+ setTimeout(dojo.hitch(this, function(){
+ 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;
+ }
+ }
+ }
+ }
+ }), 0);
+ }
+
+ // 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
+ this.textbox.setAttribute("value", this.textbox.value); // DOM and JS values should be the same
+
+ this.inherited(arguments);
+
+ if(dojo.isMoz || dojo.isOpera){
+ this.connect(this.textbox, "oninput", "_onInput");
+ }else{
+ this.connect(this.textbox, "onkeydown", "_onInput");
+ this.connect(this.textbox, "onkeyup", "_onInput");
+ this.connect(this.textbox, "onpaste", "_onInput");
+ this.connect(this.textbox, "oncut", "_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 set('value', ...)
+ // and get('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();
+
+ // call this.inherited() before refreshState(), since this.inherited() will possibly scroll the viewport
+ // (to scroll the TextBox into view), which will affect how _refreshState() positions the tooltip
+ this.inherited(arguments);
+
+ this._refreshState();
+ },
+
+ 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 r = element.createTextRange();
+ r.collapse(true);
+ r.moveStart("character", -99999); // move to 0
+ r.moveStart("character", start); // delta from 0 is the correct position
+ r.moveEnd("character", stop-start);
+ r.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\"\r\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" role='alert'></div\r\n\t><div class=\"dijitTooltipConnector\" dojoAttachPoint=\"connectorNode\"></div\r\n></div>\r\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;
+ }
+
+ // reset width; it may have been set by orient() on a previous tooltip show()
+ this.domNode.width = "auto";
+
+ 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, /*Object*/ spaceAvailable, /*Object*/ aroundNodeCoords){
+ // summary:
+ // Private function to set CSS for tooltip node based on which position it's in.
+ // This is called by the dijit popup code. It will also reduce the tooltip's
+ // width to whatever width is available
+ // tags:
+ // protected
+ this.connectorNode.style.top = ""; //reset to default
+
+ //Adjust the spaceAvailable width, without changing the spaceAvailable object
+ var tooltipSpaceAvaliableWidth = spaceAvailable.w - this.connectorNode.offsetWidth;
+
+ 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];
+
+ // reduce tooltip's width to the amount of width available, so that it doesn't overflow screen
+ this.domNode.style.width = "auto";
+ var size = dojo.contentBox(this.domNode);
+
+ var width = Math.min((Math.max(tooltipSpaceAvaliableWidth,1)), size.w);
+ var widthWasReduced = width < size.w;
+
+ this.domNode.style.width = width+"px";
+
+ //Adjust width for tooltips that have a really long word or a nowrap setting
+ if(widthWasReduced){
+ this.containerNode.style.overflow = "auto"; //temp change to overflow to detect if our tooltip needs to be wider to support the content
+ var scrollWidth = this.containerNode.scrollWidth;
+ this.containerNode.style.overflow = "visible"; //change it back
+ if(scrollWidth > width){
+ scrollWidth = scrollWidth + dojo.style(this.domNode,"paddingLeft") + dojo.style(this.domNode,"paddingRight");
+ this.domNode.style.width = scrollWidth + "px";
+ }
+ }
+
+ // Reposition the tooltip connector.
+ if(tooltipCorner.charAt(0) == 'B' && aroundCorner.charAt(0) == 'B'){
+ var mb = dojo.marginBox(node);
+ var tooltipConnectorHeight = this.connectorNode.offsetHeight;
+ if(mb.h > spaceAvailable.h){
+ // The tooltip starts at the top of the page and will extend past the aroundNode
+ var aroundNodePlacement = spaceAvailable.h - (aroundNodeCoords.h / 2) - (tooltipConnectorHeight / 2);
+ this.connectorNode.style.top = aroundNodePlacement + "px";
+ this.connectorNode.style.bottom = "";
+ }else{
+ // Align center of connector with center of aroundNode, except don't let bottom
+ // of connector extend below bottom of tooltip content, or top of connector
+ // extend past top of tooltip content
+ this.connectorNode.style.bottom = Math.min(
+ Math.max(aroundNodeCoords.h/2 - tooltipConnectorHeight/2, 0),
+ mb.h - tooltipConnectorHeight) + "px";
+ this.connectorNode.style.top = "";
+ }
+ }else{
+ // reset the tooltip back to the defaults
+ this.connectorNode.style.top = "";
+ this.connectorNode.style.bottom = "";
+ }
+
+ return Math.max(0, size.w - tooltipSpaceAvaliableWidth);
+ },
+
+ _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: String|String[]
+ // Id of domNode(s) to attach the tooltip to.
+ // When user hovers over specified dom node, the tooltip will appear.
+ connectId: [],
+
+ // position: String[]
+ // See description of `dijit.Tooltip.defaultPosition` for details on position parameter.
+ position: [],
+
+ _setConnectIdAttr: function(/*String*/ newId){
+ // summary:
+ // Connect to node(s) (specified by id)
+
+ // Remove connections to old nodes (if there are any)
+ dojo.forEach(this._connections || [], function(nested){
+ dojo.forEach(nested, dojo.hitch(this, "disconnect"));
+ }, this);
+
+ // Make connections to nodes in newIds.
+ var ary = dojo.isArrayLike(newId) ? newId : (newId ? [newId] : []);
+ this._connections = dojo.map(ary, function(id){
+ var node = dojo.byId(id);
+ return node ? [
+ this.connect(node, "onmouseenter", "_onTargetMouseEnter"),
+ this.connect(node, "onmouseleave", "_onTargetMouseLeave"),
+ this.connect(node, "onfocus", "_onTargetFocus"),
+ this.connect(node, "onblur", "_onTargetBlur")
+ ] : [];
+ }, this);
+
+ this._set("connectId", newId);
+
+ this._connectIds = ary; // save as array
+ },
+
+ addTarget: function(/*DOMNODE || String*/ node){
+ // summary:
+ // Attach tooltip to specified node if it's not already connected
+
+ // TODO: remove in 2.0 and just use set("connectId", ...) interface
+
+ var id = node.id || node;
+ if(dojo.indexOf(this._connectIds, id) == -1){
+ this.set("connectId", this._connectIds.concat(id));
+ }
+ },
+
+ removeTarget: function(/*DOMNODE || String*/ node){
+ // summary:
+ // Detach tooltip from specified node
+
+ // TODO: remove in 2.0 and just use set("connectId", ...) interface
+
+ var id = node.id || node, // map from DOMNode back to plain id string
+ idx = dojo.indexOf(this._connectIds, id);
+ if(idx >= 0){
+ // remove id (modifies original this._connectIds but that's OK in this case)
+ this._connectIds.splice(idx, 1);
+ this.set("connectId", this._connectIds);
+ }
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ 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\"\r\n\tid=\"widget_${id}\" role=\"presentation\"\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\r\n\t\t\t${!nameAttrSetting} type='${type}'\r\n\t/></div\r\n></div>\r\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.
+ // Also displays if the textbox value is Incomplete (not yet valid but will be with additional input).
+ // 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_$",
+
+ // message: String
+ // Currently error/prompt message.
+ // When using the default tooltip implementation, this will only be
+ // displayed when the field is focused.
+ message: "",
+
+ // 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, Incomplete, or Error)
+ state: "",
+
+ // tooltipPosition: String[]
+ // See description of `dijit.Tooltip.defaultPosition` for details on this parameter.
+ tooltipPosition: [],
+
+ _setValueAttr: function(){
+ // summary:
+ // Hook so set('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 (this.trim ? /^\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 && isFocused && this._isValidSubset();
+ this._set("state", isValid ? "" : (((((!this._hasBeenBlurred || isFocused) && isEmpty) || isValidSubset) && this._maskValidSubsetError) ? "Incomplete" : "Error"));
+ dijit.setWaiState(this.focusNode, "invalid", isValid ? "false" : "true");
+
+ if(this.state == "Error"){
+ this._maskValidSubsetError = isFocused && isValidSubset; // we want the error to show up after a blur and refocus
+ message = this.getErrorMessage(isFocused);
+ }else if(this.state == "Incomplete"){
+ message = this.getPromptMessage(isFocused); // show the prompt whenever the value is not yet complete
+ this._maskValidSubsetError = !this._hasBeenBlurred || isFocused; // no Incomplete warnings while focused
+ }else if(isEmpty){
+ message = this.getPromptMessage(isFocused); // show the prompt whenever there's no error and no text
+ }
+ this.set("message", message);
+
+ return isValid;
+ },
+
+ displayMessage: function(/*String*/ message){
+ // summary:
+ // Overridable method to display validation errors/hints.
+ // By default uses a tooltip.
+ // tags:
+ // extension
+ dijit.hideTooltip(this.domNode);
+ if(message && this._focused){
+ 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._set("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._set("required", value);
+ dijit.setWaiState(this.focusNode, "required", value);
+ this._refreshState();
+ },
+
+ _setMessageAttr: function(/*String*/ message){
+ this._set("message", message);
+ this.displayMessage(message);
+ },
+
+ reset:function(){
+ // Overrides dijit.form.TextBox.reset() by also
+ // hiding errors about partial matches
+ this._maskValidSubsetError = true;
+ this.inherited(arguments);
+ },
+
+ _onBlur: function(){
+ // the message still exists but for back-compat, and to erase the tooltip
+ // (if the message is being displayed as a tooltip), call displayMessage('')
+ 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 get('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.replace(/'/g, "&quot;") + "'" : "") + "/>", 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 set('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",
+ dijit._HasDropDown,
+ {
+ // 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: [const] 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: 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/DropDownBox.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\r\n\tid=\"widget_${id}\"\r\n\trole=\"combobox\"\r\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\r\n\t\tdojoAttachPoint=\"_buttonNode, _popupStateNode\" role=\"presentation\"\r\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t${_buttonInputDisabled}\r\n\t/></div\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\r\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\r\n\t/></div\r\n></div>\r\n"),
+
+ baseClass: "dijitTextBox dijitComboBox",
+
+ // dropDownClass: [protected extension] String
+ // Name of the dropdown widget class used to select a date/time.
+ // Subclasses should specify this.
+ dropDownClass: "dijit.form._ComboBoxMenu",
+
+ // Set classes like dijitDownArrowButtonHover depending on
+ // mouse action over button node
+ cssStateNodes: {
+ "_buttonNode": "dijitDownArrowButton"
+ },
+
+ // Flags to _HasDropDown to limit height of drop down to make it fit in viewport
+ maxHeight: -1,
+
+ _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 doesn't 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.domNode, "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._onKey({charOrCode: 229}); // fake IME key to cause a search
+ }), 100); // long delay that will probably be preempted by keyboard input
+ }
+ this.inherited(arguments);
+ },
+
+ _onKey: 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 pw = this.dropDown;
+ var dk = dojo.keys;
+ var highlighted = null;
+ this._prev_key_backspace = false;
+ this._abortQuery();
+
+ // _HasDropDown will do some of the work:
+ // 1. when drop down is not yet shown:
+ // - if user presses the down arrow key, call loadDropDown()
+ // 2. when drop down is already displayed:
+ // - on ESC key, call closeDropDown()
+ // - otherwise, call dropDown.handleKey() to process the keystroke
+ this.inherited(arguments);
+
+ if(this._opened){
+ highlighted = pw.getHighlightedOption();
+ }
+ switch(key){
+ case dk.PAGE_DOWN:
+ case dk.DOWN_ARROW:
+ case dk.PAGE_UP:
+ case dk.UP_ARROW:
+ // Keystroke caused ComboBox_menu to move to a different item.
+ // Copy new item to <input> box.
+ if(this._opened){
+ 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:
+ // if enter pressed while drop down is open, or for FilteringSelect,
+ // if we are in the middle of a query to convert a directly typed in value to an item,
+ // prevent submit, but allow event to bubble
+ if(this._opened || this._fetchHandle){
+ 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._opened){
+ this._lastQuery = null; // in case results come back later
+ this.closeDropDown();
+ }
+ break;
+
+ case ' ':
+ if(highlighted){
+ // user is effectively clicking a choice in the drop down menu
+ dojo.stopEvent(evt);
+ this._selectOption();
+ this.closeDropDown();
+ }else{
+ // user typed a space into the input box, treat as normal character
+ doSearch = true;
+ }
+ 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.
+ //IME input produces keycode == 229.
+ 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, "_startSearchFromInput"),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){
+ // summary:
+ // Callback when a search completes.
+ // description:
+ // 1. generates drop-down list and calls _showResultList() to display it
+ // 2. if this result list is from user pressing "more choices"/"previous choices"
+ // then tell screen reader to announce new option
+ this._fetchHandle = null;
+ if( this.disabled ||
+ this.readOnly ||
+ (dataObject.query[this.searchAttr] != this._lastQuery)
+ ){
+ return;
+ }
+ var wasSelected = this.dropDown._highlighted_option && dojo.hasClass(this.dropDown._highlighted_option, "dijitMenuItemSelected");
+ this.dropDown.clearResultList();
+ if(!results.length && !this._maxOptions){ // if no results and not just the previous choices button
+ this.closeDropDown();
+ 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.dropDown.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.dropDown.highlightFirstOption();
+ }else if(-1 == dataObject.direction){
+ this.dropDown.highlightLastOption();
+ }
+ if(wasSelected){
+ this._announceOption(this.dropDown.getHighlightedOption());
+ }
+ }else if(this.autoComplete && !this._prev_key_backspace
+ // 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(){
+ // summary:
+ // Display the drop down if not already displayed, or if it is displayed, then
+ // reposition it if necessary (reposition may be necessary if drop down's height changed).
+
+ this.closeDropDown(true);
+
+ // hide the tooltip
+ this.displayMessage("");
+
+ this.openDropDown();
+
+ dijit.setWaiState(this.domNode, "expanded", "true");
+ },
+
+ loadDropDown: function(/*Function*/ callback){
+ // Overrides _HasDropDown.loadDropDown().
+ // This is called when user has pressed button icon or pressed the down arrow key
+ // to open the drop down.
+
+ this._startSearchAll();
+ },
+
+ isLoaded: function(){
+ // signal to _HasDropDown that it needs to call loadDropDown() to load the
+ // drop down asynchronously before displaying it
+ return false;
+ },
+
+ closeDropDown: function(){
+ // Overrides _HasDropDown.closeDropDown(). Closes the drop down (assuming that it's open).
+ // This method is the callback when the user types ESC or clicking
+ // the button icon while the drop down is open. It's also called by other code.
+ this._abortQuery();
+ if(this._opened){
+ this.inherited(arguments);
+ dijit.setWaiState(this.domNode, "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.dropDown;
+ 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.closeDropDown();
+ 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
+ // set('item', value)
+ // tags:
+ // private
+ if(!displayedValue){
+ // Use labelFunc() to get displayedValue. But it may return HTML so need to convert to plain text.
+ var label = this.labelFunc(item, this.store);
+ if(this.labelType == "html"){
+ var span = this._helperSpan;
+ span.innerHTML = label;
+ displayedValue = span.innerText || span.textContent;
+ }else{
+ displayedValue = label;
+ }
+ }
+ var value = this._getValueField() != this.searchAttr? this.store.getIdentity(item) : displayedValue;
+ this._set("item", item);
+ dijit.form.ComboBox.superclass._setValueAttr.call(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.dropDown.nextButton ||
+ node == this.dropDown.previousButton){
+ newValue = node.innerHTML;
+ this.item = undefined;
+ this.value = '';
+ }else{
+ newValue = node.innerText || node.textContent || "";
+ // newValue = this.store.getValue(node.item, this.searchAttr).toString();
+ 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.closeDropDown();
+ this._setCaretPos(this.focusNode, this.focusNode.value.length);
+ dijit.form._FormValueWidget.prototype._setValueAttr.call(this, this.value, true); // set this.value and fire onChange
+ },
+
+ _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){
+ // summary:
+ // Starts a search for elements matching key (key=="" means to return all items),
+ // and calls _openResultList() when the search completes, to display the results.
+ if(!this.dropDown){
+ var popupId = this.id + "_popup",
+ dropDownConstructor = dojo.getObject(this.dropDownClass, false);
+ this.dropDown = new dropDownConstructor({
+ 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);
+ _this.closeDropDown();
+ },
+ 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.focus();
+ };
+ this._nextSearch = this.dropDown.onPage = dojo.hitch(this, nextSearch, this._fetchHandle);
+ }, query, this), this.searchDelay);
+ },
+
+ _setMaxOptions: function(size, request){
+ this._maxOptions = size;
+ },
+
+ _getValueField: function(){
+ // summary:
+ // 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;
+ },
+
+ //////////// 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.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);
+ }
+ }
+ }
+
+ // used to convert HTML to plain text
+ this._helperSpan = dojo.create("span");
+
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ // summary:
+ // Subclasses must call this method from their postCreate() methods
+ // tags:
+ // protected
+
+ // 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");
+ dijit.setWaiState(this.domNode, "labelledby", label[0].id);
+
+ }
+ this.inherited(arguments);
+ },
+
+ destroy: function(){
+ dojo.destroy(this._helperSpan);
+ this.inherited(arguments);
+ },
+
+ _setHasDownArrowAttr: function(val){
+ this.hasDownArrow = val;
+ this._buttonNode.style.display = val ? "" : "none";
+ },
+
+ _getMenuLabelFromItem: function(/*Item*/ item){
+ var label = this.labelFunc(item, this.store),
+ 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 occurrence found. Override this method
+ // to implement your custom highlighting.
+ // tags:
+ // protected
+
+ var
+ // Add (g)lobal modifier when this.highlightMatch == "all" and (i)gnorecase when this.ignoreCase == true
+ modifiers = (this.ignoreCase ? "i" : "") + (this.highlightMatch == "all" ? "g" : ""),
+ i = this.queryExpr.indexOf("${0}");
+ find = dojo.regexp.escapeString(find); // escape regexp special chars
+ return this._escapeHtml(label).replace(
+ // prepend ^ when this.queryExpr == "${0}*" and append $ when this.queryExpr == "*${0}"
+ new RegExp((i == 0 ? "^" : "") + "("+ find +")" + (i == (this.queryExpr.length - 4) ? "$" : ""), modifiers),
+ '<span class="dijitComboBoxHighlightMatch">$1</span>'
+ ); // 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
+ },
+
+ 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.labelAttr || 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' style='overflow: \"auto\"; overflow-x: \"hidden\";'>"
+ +"<li class='dijitMenuItem dijitMenuPreviousButton' dojoAttachPoint='previousButton' role='option'></li>"
+ +"<li class='dijitMenuItem dijitMenuNextButton' dojoAttachPoint='nextButton' role='option'></li>"
+ +"</ul>",
+
+ // _messages: Object
+ // Holds "next" and "previous" text for paging buttons on drop down
+ _messages: null,
+
+ baseClass: "dijitComboBoxMenu",
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this._messages = dojo.i18n.getLocalization("dijit.form", "ComboBox", this.lang);
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ // fill in template with i18n messages
+ this.previousButton.innerHTML = this._messages["previousMessage"];
+ this.nextButton.innerHTML = this._messages["nextMessage"];
+ },
+
+ _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
+ },
+
+ 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 menuitem = dojo.create("li", {
+ "class": "dijitReset dijitMenuItem" +(this.isLeftToRight() ? "" : " dijitMenuItemRtl"),
+ role: "option"
+ });
+ var labelObject = labelFunc(item);
+ 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);
+ 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]);
+ }
+ this._blurOptionNode();
+ },
+
+ _onMouseDown: function(/*Event*/ evt){
+ dojo.stopEvent(evt);
+ },
+
+ _onMouseUp: function(/*Event*/ evt){
+ if(evt.target === this.domNode || !this._highlighted_option){
+ // !this._highlighted_option check to prevent immediate selection when menu appears on top
+ // of <input>, see #9898. Note that _HasDropDown also has code to prevent this.
+ return;
+ }else if(evt.target == this.previousButton){
+ this._blurOptionNode();
+ this.onPage(-1);
+ }else if(evt.target == this.nextButton){
+ this._blurOptionNode();
+ 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(evt){
+ // summary:
+ // Handle keystroke event forwarded from ComboBox, returning false if it's
+ // a keystroke I recognize and process, true otherwise.
+ switch(evt.charOrCode){
+ case dojo.keys.DOWN_ARROW:
+ this._highlightNextOption();
+ return false;
+ case dojo.keys.PAGE_DOWN:
+ this.pageDown();
+ return false;
+ case dojo.keys.UP_ARROW:
+ this._highlightPrevOption();
+ return false;
+ case dojo.keys.PAGE_UP:
+ this.pageUp();
+ return false;
+ default:
+ return true;
+ }
+ }
+ }
+);
+
+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 set('value', value) works.
+ // description:
+ // Sets the value of the select.
+ this._set("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)
+
+ // required: Boolean
+ // True (default) if user is required to enter a value into this field.
+ required: true,
+
+ _lastDisplayedValue: "",
+
+ _isValidSubset: function(){
+ return this._opened;
+ },
+
+ isValid: function(){
+ // Overrides ValidationTextBox.isValid()
+ return this.item || (!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 from dojo.data after lookup of user entered value finishes
+
+ // 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: don't modify display value 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._set("item", null);
+ this.validate(this._focused);
+ }else{
+ this.set('item', result[0], priorityChange);
+ }
+ },
+
+ _openResultList: function(/*Object*/ results, /*Object*/ dataObject){
+ // Callback when a data store query completes.
+ // 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;
+ }
+ dijit.form.ComboBoxMixin.prototype._openResultList.apply(this, arguments);
+
+ if(this.item === undefined){ // item == undefined for keyboard search
+ // If the search returned no items that means that the user typed
+ // in something invalid (and they can't make it valid by typing more characters),
+ // so flag the FilteringSelect as being in an invalid state
+ this.validate(true);
+ }
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // Hook for get('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 set('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
+ // set('item', value)
+ // tags:
+ // private
+ 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 set('displayedValue', label) works.
+ // description:
+ // Sets textbox to display label. Also performs reverse lookup
+ // to set the hidden value.
+ //
+ // Doesn't work as expected when the FilteringSelect has a custom labelFunc(), since in that case
+ // it's impossible to do a reverse lookup (from label --> item) without a full data store scan.
+ // App must call set("displayedValue", ...) with the intended item.searchAttr, rather than
+ // labelFunc(item).
+
+ if(label == null){ label = ''; }
+
+ // This is called at initialization along with every custom setter.
+ // Usually (or always?) the call can be ignored. If it needs to be
+ // processed then at least make sure that the XHR request doesn't trigger an onChange()
+ // event, even if it returns after creation has finished
+ if(!this._created){
+ if(!("displayedValue" in this.params)){
+ return;
+ }
+ priorityChange = false;
+ }
+
+ // Do a reverse lookup to map the specified displayedValue to the hidden value.
+ // Note that if there's a custom labelFunc() this code
+ if(this.store){
+ this.closeDropDown();
+ 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.labelAttr || 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);
+ }
+ },
+
+ undo: function(){
+ this.set('displayedValue', this._lastDisplayedValue);
+ }
+ }
+);
+
+}
+
+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 = 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:'1802-05-14'});
+ // | 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(!Object.hasOwnProperty.call(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:'1918-07-18'}] }
+ // into this:
+ // { name:['Kermit'], born:(new Date(1918, 6, 18)) }
+ //
+ // 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 &&
+ Object.hasOwnProperty.call(this._itemsByIdentity, identity)){
+ item = this._itemsByIdentity[identity];
+ }else if (Object.hasOwnProperty.call(this._arrayOfAllItems, identity)){
+ item = this._arrayOfAllItems[identity];
+ }
+ if(item === undefined){
+ item = null;
+ }
+ return item; // Object
+ },
+
+ getIdentityAttributes: function(/* item */ item){
+ // summary:
+ // See dojo.data.api.Identity.getIdentityAttributes()
+
+ 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 = 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["dijit._editor.plugins.FontChoice"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._editor.plugins.FontChoice"] = true;
+dojo.provide("dijit._editor.plugins.FontChoice");
+
+
+
+
+
+
+
+
+
+
+dojo.declare("dijit._editor.plugins._FontDropDown",
+ [dijit._Widget, dijit._Templated],{
+ // summary:
+ // Base class for widgets that contains a label (like "Font:")
+ // and a FilteringSelect drop down to pick a value.
+ // Used as Toolbar entry.
+
+ // label: [public] String
+ // The label to apply to this particular FontDropDown.
+ label: "",
+
+ // widgetsInTemplate: [public] boolean
+ // Over-ride denoting the template has widgets to parse.
+ widgetsInTemplate: true,
+
+ // plainText: [public] boolean
+ // Flag to indicate that the returned label should be plain text
+ // instead of an example.
+ plainText: false,
+
+ // templateString: [public] String
+ // The template used to construct the labeled dropdown.
+ templateString:
+ "<span style='white-space: nowrap' class='dijit dijitReset dijitInline'>" +
+ "<label class='dijitLeft dijitInline' for='${selectId}'>${label}</label>" +
+ "<input dojoType='dijit.form.FilteringSelect' required='false' labelType='html' labelAttr='label' searchAttr='name' " +
+ "tabIndex='-1' id='${selectId}' dojoAttachPoint='select' value=''/>" +
+ "</span>",
+
+ postMixInProperties: function(){
+ // summary:
+ // Over-ride to set specific properties.
+ this.inherited(arguments);
+
+ this.strings = dojo.i18n.getLocalization("dijit._editor", "FontChoice");
+
+ // Set some substitution variables used in the template
+ this.label = this.strings[this.command];
+ this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
+ this.selectId = this.id + "_select";
+
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ // summary:
+ // Over-ride for the default postCreate action
+ // This establishes the filtering selects and the like.
+
+ // Initialize the list of items in the drop down by creating data store with items like:
+ // {value: 1, name: "xx-small", label: "<font size=1>xx-small</font-size>" }
+ var items = dojo.map(this.values, function(value){
+ var name = this.strings[value] || value;
+ return {
+ label: this.getLabel(value, name),
+ name: name,
+ value: value
+ };
+ }, this);
+
+ this.select.store = new dojo.data.ItemFileReadStore({
+ data: {
+ identifier: "value",
+ items: items
+ }
+ });
+
+ this.select.set("value", "", false);
+ this.disabled = this.select.get("disabled");
+ },
+
+ _setValueAttr: function(value, priorityChange){
+ // summary:
+ // Over-ride for the default action of setting the
+ // widget value, maps the input to known values
+ // value: Object|String
+ // The value to set in the select.
+ // priorityChange:
+ // Optional parameter used to tell the select whether or not to fire
+ // onChange event.
+
+ //if the value is not a permitted value, just set empty string to prevent showing the warning icon
+ priorityChange = priorityChange !== false?true:false;
+ this.select.set('value', dojo.indexOf(this.values,value) < 0 ? "" : value, priorityChange);
+ if(!priorityChange){
+ // Clear the last state in case of updateState calls. Ref: #10466
+ this.select._lastValueReported=null;
+ }
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // Allow retreiving the value from the composite select on
+ // call to button.get("value");
+ return this.select.get('value');
+ },
+
+ focus: function(){
+ // summary:
+ // Over-ride for focus control of this widget. Delegates focus down to the
+ // filtering select.
+ this.select.focus();
+ },
+
+ _setDisabledAttr: function(value){
+ // summary:
+ // Over-ride for the button's 'disabled' attribute so that it can be
+ // disabled programmatically.
+
+ // Save off ths disabled state so the get retrieves it correctly
+ //without needing to have a function proxy it.
+ this.disabled = value;
+ this.select.set("disabled", value);
+ }
+});
+
+
+dojo.declare("dijit._editor.plugins._FontNameDropDown", dijit._editor.plugins._FontDropDown, {
+ // summary:
+ // Dropdown to select a font; goes in editor toolbar.
+
+ // generic: Boolean
+ // Use generic (web standard) font names
+ generic: false,
+
+ // command: [public] String
+ // The editor 'command' implemented by this plugin.
+ command: "fontName",
+
+ postMixInProperties: function(){
+ // summary:
+ // Over-ride for the default posr mixin control
+ if(!this.values){
+ this.values = this.generic ?
+ ["serif", "sans-serif", "monospace", "cursive", "fantasy"] : // CSS font-family generics
+ ["Arial", "Times New Roman", "Comic Sans MS", "Courier New"];
+ }
+ this.inherited(arguments);
+ },
+
+ getLabel: function(value, name){
+ // summary:
+ // Function used to generate the labels of the format dropdown
+ // will return a formatted, or plain label based on the value
+ // of the plainText option.
+ // value: String
+ // The 'insert value' associated with a name
+ // name: String
+ // The text name of the value
+ if(this.plainText){
+ return name;
+ }else{
+ return "<div style='font-family: "+value+"'>" + name + "</div>";
+ }
+ },
+
+ _setValueAttr: function(value, priorityChange){
+ // summary:
+ // Over-ride for the default action of setting the
+ // widget value, maps the input to known values
+
+ priorityChange = priorityChange !== false?true:false;
+ if(this.generic){
+ var map = {
+ "Arial": "sans-serif",
+ "Helvetica": "sans-serif",
+ "Myriad": "sans-serif",
+ "Times": "serif",
+ "Times New Roman": "serif",
+ "Comic Sans MS": "cursive",
+ "Apple Chancery": "cursive",
+ "Courier": "monospace",
+ "Courier New": "monospace",
+ "Papyrus": "fantasy"
+// ,"????": "fantasy" TODO: IE doesn't map fantasy font-family?
+ };
+ value = map[value] || value;
+ }
+ this.inherited(arguments, [value, priorityChange]);
+ }
+});
+
+dojo.declare("dijit._editor.plugins._FontSizeDropDown", dijit._editor.plugins._FontDropDown, {
+ // summary:
+ // Dropdown to select a font size; goes in editor toolbar.
+
+ // command: [public] String
+ // The editor 'command' implemented by this plugin.
+ command: "fontSize",
+
+ // values: [public] Number[]
+ // The HTML font size values supported by this plugin
+ values: [1,2,3,4,5,6,7], // sizes according to the old HTML FONT SIZE
+
+ getLabel: function(value, name){
+ // summary:
+ // Function used to generate the labels of the format dropdown
+ // will return a formatted, or plain label based on the value
+ // of the plainText option.
+ // We're stuck using the deprecated FONT tag to correspond
+ // with the size measurements used by the editor
+ // value: String
+ // The 'insert value' associated with a name
+ // name: String
+ // The text name of the value
+ if(this.plainText){
+ return name;
+ }else{
+ return "<font size=" + value + "'>" + name + "</font>";
+ }
+ },
+
+ _setValueAttr: function(value, priorityChange){
+ // summary:
+ // Over-ride for the default action of setting the
+ // widget value, maps the input to known values
+ priorityChange = priorityChange !== false?true:false;
+ if(value.indexOf && value.indexOf("px") != -1){
+ var pixels = parseInt(value, 10);
+ value = {10:1, 13:2, 16:3, 18:4, 24:5, 32:6, 48:7}[pixels] || value;
+ }
+
+ this.inherited(arguments, [value, priorityChange]);
+ }
+});
+
+
+dojo.declare("dijit._editor.plugins._FormatBlockDropDown", dijit._editor.plugins._FontDropDown, {
+ // summary:
+ // Dropdown to select a format (like paragraph or heading); goes in editor toolbar.
+
+ // command: [public] String
+ // The editor 'command' implemented by this plugin.
+ command: "formatBlock",
+
+ // values: [public] Array
+ // The HTML format tags supported by this plugin
+ values: ["noFormat", "p", "h1", "h2", "h3", "pre"],
+
+ postCreate: function(){
+ // Init and set the default value to no formatting. Update state will adjust it
+ // as needed.
+ this.inherited(arguments);
+ this.set("value", "noFormat", false);
+ },
+
+ getLabel: function(value, name){
+ // summary:
+ // Function used to generate the labels of the format dropdown
+ // will return a formatted, or plain label based on the value
+ // of the plainText option.
+ // value: String
+ // The 'insert value' associated with a name
+ // name: String
+ // The text name of the value
+ if(this.plainText || value == "noFormat"){
+ return name;
+ }else{
+ return "<" + value + ">" + name + "</" + value + ">";
+ }
+ },
+
+ _execCommand: function(editor, command, choice){
+ // summary:
+ // Over-ride for default exec-command label.
+ // Allows us to treat 'none' as special.
+ if(choice === "noFormat"){
+ var start;
+ var end;
+ var sel = dijit.range.getSelection(editor.window);
+ if(sel && sel.rangeCount > 0){
+ var range = sel.getRangeAt(0);
+ var node, tag;
+ if(range){
+ start = range.startContainer;
+ end = range.endContainer;
+
+ // find containing nodes of start/end.
+ while(start && start !== editor.editNode &&
+ start !== editor.document.body &&
+ start.nodeType !== 1){
+ start = start.parentNode;
+ }
+
+ while(end && end !== editor.editNode &&
+ end !== editor.document.body &&
+ end.nodeType !== 1){
+ end = end.parentNode;
+ }
+
+ var processChildren = dojo.hitch(this, function(node, array){
+ if(node.childNodes && node.childNodes.length){
+ var i;
+ for(i = 0; i < node.childNodes.length; i++){
+ var c = node.childNodes[i];
+ if(c.nodeType == 1){
+ if(dojo.withGlobal(editor.window, "inSelection", dijit._editor.selection, [c])){
+ var tag = c.tagName? c.tagName.toLowerCase(): "";
+ if(dojo.indexOf(this.values, tag) !== -1){
+ array.push(c);
+ }
+ processChildren(c,array);
+ }
+ }
+ }
+ }
+ });
+
+ var unformatNodes = dojo.hitch(this, function(nodes){
+ // summary:
+ // Internal function to clear format nodes.
+ // nodes:
+ // The array of nodes to strip formatting from.
+ if(nodes && nodes.length){
+ editor.beginEditing();
+ while(nodes.length){
+ this._removeFormat(editor, nodes.pop());
+ }
+ editor.endEditing();
+ }
+ });
+
+ var clearNodes = [];
+ if(start == end){
+ //Contained within the same block, may be collapsed, but who cares, see if we
+ // have a block element to remove.
+ var block;
+ node = start;
+ while(node && node !== editor.editNode && node !== editor.document.body){
+ if(node.nodeType == 1){
+ tag = node.tagName? node.tagName.toLowerCase(): "";
+ if(dojo.indexOf(this.values, tag) !== -1){
+ block = node;
+ break;
+ }
+ }
+ node = node.parentNode;
+ }
+
+ //Also look for all child nodes in the selection that may need to be
+ //cleared of formatting
+ processChildren(start, clearNodes);
+ if(block) { clearNodes = [block].concat(clearNodes); }
+ unformatNodes(clearNodes);
+ }else{
+ // Probably a multi select, so we have to process it. Whee.
+ node = start;
+ while(dojo.withGlobal(editor.window, "inSelection", dijit._editor.selection, [node])){
+ if(node.nodeType == 1){
+ tag = node.tagName? node.tagName.toLowerCase(): "";
+ if(dojo.indexOf(this.values, tag) !== -1){
+ clearNodes.push(node);
+ }
+ processChildren(node,clearNodes);
+ }
+ node = node.nextSibling;
+ }
+ unformatNodes(clearNodes);
+ }
+ editor.onDisplayChanged();
+ }
+ }
+ }else{
+ editor.execCommand(command, choice);
+ }
+ },
+
+ _removeFormat: function(editor, node){
+ // summary:
+ // function to remove the block format node.
+ // node:
+ // The block format node to remove (and leave the contents behind)
+ if(editor.customUndo){
+ // So of course IE doesn't work right with paste-overs.
+ // We have to do this manually, which is okay since IE already uses
+ // customUndo and we turned it on for WebKit. WebKit pasted funny,
+ // so couldn't use the execCommand approach
+ while(node.firstChild){
+ dojo.place(node.firstChild, node, "before");
+ }
+ node.parentNode.removeChild(node);
+ }else{
+ // Everyone else works fine this way, a paste-over and is native
+ // undo friendly.
+ dojo.withGlobal(editor.window,
+ "selectElementChildren", dijit._editor.selection, [node]);
+ var html = dojo.withGlobal(editor.window,
+ "getSelectedHtml", dijit._editor.selection, [null]);
+ dojo.withGlobal(editor.window,
+ "selectElement", dijit._editor.selection, [node]);
+ editor.execCommand("inserthtml", html||"");
+ }
+ }
+});
+
+// TODO: for 2.0, split into FontChoice plugin into three separate classes,
+// one for each command (and change registry below)
+dojo.declare("dijit._editor.plugins.FontChoice", dijit._editor._Plugin,{
+ // summary:
+ // This plugin provides three drop downs for setting style in the editor
+ // (font, font size, and format block), as controlled by command.
+ //
+ // description:
+ // The commands provided by this plugin are:
+ //
+ // * fontName
+ // | Provides a drop down to select from a list of font names
+ // * fontSize
+ // | Provides a drop down to select from a list of font sizes
+ // * formatBlock
+ // | Provides a drop down to select from a list of block styles
+ // |
+ //
+ // which can easily be added to an editor by including one or more of the above commands
+ // in the `plugins` attribute as follows:
+ //
+ // | plugins="['fontName','fontSize',...]"
+ //
+ // It is possible to override the default dropdown list by providing an Array for the `custom` property when
+ // instantiating this plugin, e.g.
+ //
+ // | plugins="[{name:'dijit._editor.plugins.FontChoice', command:'fontName', custom:['Verdana','Myriad','Garamond']},...]"
+ //
+ // Alternatively, for `fontName` only, `generic:true` may be specified to provide a dropdown with
+ // [CSS generic font families](http://www.w3.org/TR/REC-CSS2/fonts.html#generic-font-families)
+ //
+ // Note that the editor is often unable to properly handle font styling information defined outside
+ // the context of the current editor instance, such as pre-populated HTML.
+
+ // useDefaultCommand: [protected] booleam
+ // Override _Plugin.useDefaultCommand...
+ // processing is handled by this plugin, not by dijit.Editor.
+ useDefaultCommand: false,
+
+ _initButton: function(){
+ // summary:
+ // Overrides _Plugin._initButton(), to initialize the FilteringSelect+label in toolbar,
+ // rather than a simple button.
+ // tags:
+ // protected
+
+ // Create the widget to go into the toolbar (the so-called "button")
+ var clazz = {
+ fontName: dijit._editor.plugins._FontNameDropDown,
+ fontSize: dijit._editor.plugins._FontSizeDropDown,
+ formatBlock: dijit._editor.plugins._FormatBlockDropDown
+ }[this.command],
+ params = this.params;
+
+ // For back-compat reasons support setting custom values via "custom" parameter
+ // rather than "values" parameter
+ if(this.params.custom){
+ params.values = this.params.custom;
+ }
+
+ var editor = this.editor;
+ this.button = new clazz(dojo.delegate({dir: editor.dir, lang: editor.lang}, params));
+
+ // Reflect changes to the drop down in the editor
+ this.connect(this.button.select, "onChange", function(choice){
+ // User invoked change, since all internal updates set priorityChange to false and will
+ // not trigger an onChange event.
+ this.editor.focus();
+
+ if(this.command == "fontName" && choice.indexOf(" ") != -1){ choice = "'" + choice + "'"; }
+
+ // Invoke, the editor already normalizes commands called through its
+ // execCommand.
+ if(this.button._execCommand){
+ this.button._execCommand(this.editor, this.command, choice);
+ }else{
+ this.editor.execCommand(this.command, choice);
+ }
+ });
+ },
+
+ updateState: function(){
+ // summary:
+ // Overrides _Plugin.updateState(). This controls updating the menu
+ // options to the right values on state changes in the document (that trigger a
+ // test of the actions.)
+ // It set value of drop down in toolbar to reflect font/font size/format block
+ // of text at current caret position.
+ // tags:
+ // protected
+ var _e = this.editor;
+ var _c = this.command;
+ if(!_e || !_e.isLoaded || !_c.length){ return; }
+
+ if(this.button){
+ var disabled = this.get("disabled");
+ this.button.set("disabled", disabled);
+ if(disabled){ return; }
+ var value;
+ try{
+ value = _e.queryCommandValue(_c) || "";
+ }catch(e){
+ //Firefox may throw error above if the editor is just loaded, ignore it
+ value = "";
+ }
+
+ // strip off single quotes, if any
+ var quoted = dojo.isString(value) && value.match(/'([^']*)'/);
+ if(quoted){ value = quoted[1]; }
+
+ if(_c === "formatBlock"){
+ if(!value || value == "p"){
+ // Some browsers (WebKit) doesn't actually get the tag info right.
+ // and IE returns paragraph when in a DIV!, so incorrect a lot,
+ // so we have double-check it.
+ value = null;
+ var elem;
+ // Try to find the current element where the caret is.
+ var sel = dijit.range.getSelection(this.editor.window);
+ if(sel && sel.rangeCount > 0){
+ var range = sel.getRangeAt(0);
+ if(range){
+ elem = range.endContainer;
+ }
+ }
+
+ // Okay, now see if we can find one of the formatting types we're in.
+ while(elem && elem !== _e.editNode && elem !== _e.document){
+ var tg = elem.tagName?elem.tagName.toLowerCase():"";
+ if(tg && dojo.indexOf(this.button.values, tg) > -1){
+ value = tg;
+ break;
+ }
+ elem = elem.parentNode;
+ }
+ if(!value){
+ // Still no value, so lets select 'none'.
+ value = "noFormat";
+ }
+ }else{
+ // Check that the block format is one allowed, if not,
+ // null it so that it gets set to empty.
+ if(dojo.indexOf(this.button.values, value) < 0){
+ value = "noFormat";
+ }
+ }
+ }
+ if(value !== this.button.get("value")){
+ // Set the value, but denote it is not a priority change, so no
+ // onchange fires.
+ this.button.set('value', value, false);
+ }
+ }
+ }
+});
+
+// Register this plugin.
+dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
+ if(o.plugin){ return; }
+ switch(o.args.name){
+ case "fontName": case "fontSize": case "formatBlock":
+ o.plugin = new dijit._editor.plugins.FontChoice({
+ command: o.args.name,
+ plainText: o.args.plainText?o.args.plainText:false
+ });
+ }
+});
+
+}
+
+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: [const] 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 clicks the button to open the
+ // 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|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 || node.label !== i.label);
+ });
+ 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._set("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){
+ this._loadingStore = true;
+ store.fetch(dojo.delegate(fetchArgs, {
+ onComplete: function(items, opts){
+ 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.call(this, items, opts);
+ }
+ // 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);
+ },
+ scope: this
+ }));
+ }else{
+ delete this._fetchedWith;
+ }
+ return oStore; // dojo.data.api.Identity
+ },
+
+ // TODO: implement set() and watch() for store and query, although not sure how to handle
+ // setting them individually rather than together (as in setStore() above)
+
+ _setValueAttr: function(/*anything*/ newValue, /*Boolean?*/ 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._set("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];
+ },
+
+ _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._set("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);
+ }
+ },
+
+ _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;
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dojo.setSelectable(this.focusNode, false);
+ },
+
+ _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("data-" + dojo._scopeName + "-value") || node.getAttribute("value")),
+ label: String(node.innerHTML),
+ // FIXME: disabled and selected are not valid on complex markup children (which is why we're
+ // looking for data-dojo-value above. perhaps we should data-dojo-props="" this whole thing?)
+ // decide before 1.6
+ selected: node.getAttribute("selected") || false,
+ disabled: node.getAttribute("disabled") || false
+ };
+ }, this) : [];
+ }
+ if(!this.value){
+ this._set("value", this._getValueFromOpts());
+ }else if(this.multiple && typeof this.value == "string"){
+ this_set("value", this.value.split(","));
+ }
+ },
+
+ postCreate: function(){
+ // summary:
+ // sets up our event handling that we need for functioning
+ // as a select
+ this.inherited(arguments);
+
+ // Make our event connections for updating state
+ 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.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\" role=\"menuitem\" tabIndex=\"-1\"\r\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\r\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\r\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\r\n\t</td>\r\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">\r\n\t\t<div dojoAttachPoint=\"arrowWrapper\" style=\"visibility: hidden\">\r\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuExpand\"/>\r\n\t\t\t<span class=\"dijitMenuExpandA11y\">+</span>\r\n\t\t</div>\r\n\t</td>\r\n</tr>\r\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);
+ }
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ 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);
+ dojo.setSelectable(this.domNode, false);
+ },
+
+ _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);
+
+ // When menu is hidden (collapsed) due to clicking a MenuItem and having it execute,
+ // FF and IE don't generate an onmouseout event for the MenuItem.
+ // So, help out _CssStateMixin in this case.
+ this._set("hovering", false);
+ },
+
+ _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.
+
+ dijit.setWaiState(this.focusNode, 'disabled', value ? 'true' : 'false');
+ this._set("disabled", value);
+ },
+ _setAccelKeyAttr: function(/*String*/ value){
+ // summary:
+ // Hook for attr('accelKey', ...) to work.
+ // Set accelKey on this menu item.
+
+ 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");
+
+ this._set("accelKey", value);
+ }
+ });
+
+}
+
+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\" role=\"menuitemcheckbox\" tabIndex=\"-1\"\r\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\r\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\r\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuItemIcon dijitCheckedMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\r\n\t\t<span class=\"dijitCheckedMenuItemIconChar\">&#10003;</span>\r\n\t</td>\r\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode,labelNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\r\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">&nbsp;</td>\r\n</tr>\r\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._set("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\">\r\n\t<td class=\"dijitMenuSeparatorIconCell\">\r\n\t\t<div class=\"dijitMenuSeparatorTop\"></div>\r\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\r\n\t</td>\r\n\t<td colspan=\"3\" class=\"dijitMenuSeparatorLabelCell\">\r\n\t\t<div class=\"dijitMenuSeparatorTop dijitMenuSeparatorLabel\"></div>\r\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\r\n\t</td>\r\n</tr>\r\n"),
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ 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");
+
+
+
+
+
+
+
+
+
+
+
+// "dijit/MenuItem", "dijit/PopupMenuItem", "dijit/CheckedMenuItem", "dijit/MenuSeparator" for Back-compat (TODO: remove in 2.0)
+
+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.replaceClass(this.domNode, "dijitMenuActive", "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.replaceClass(this.domNode, "dijitMenuPassive", "dijitMenuActive");
+ },
+
+ 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();
+
+ var fromItem = this.focusedChild && this.focusedChild.from_item;
+
+ if(this.currentPopup){
+ // If focus is on my child menu then move focus to me,
+ // because IE doesn't like it when you display:none a node with focus
+ if(dijit._curFocus && dojo.isDescendant(dijit._curFocus, this.currentPopup.domNode)){
+ this.focusedChild.focusNode.focus();
+ }
+ // Close all popups that are open and descendants of this menu
+ dijit.popup.close(this.currentPopup);
+ this.currentPopup = null;
+ }
+
+ if(this.focusedChild){ // unhighlight the focused item
+ this.focusedChild._setSelected(false);
+ this.focusedChild._onUnhover();
+ this.focusedChild = 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\" role=\"menu\" tabIndex=\"${tabIndex}\" dojoAttachEvent=\"onkeypress:_onKeyPress\" cellspacing=\"0\">\r\n\t<tbody class=\"dijitReset\" dojoAttachPoint=\"containerNode\"></tbody>\r\n</table>\r\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 set('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);
+ }
+}
+);
+
+}
+
+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);
+ },
+
+ postCreate: function(){
+ // summary:
+ // stop mousemove from selecting text on IE to be consistent with other browsers
+
+ this.inherited(arguments);
+
+ this.connect(this.domNode, "onmousemove", dojo.stopEvent);
+ },
+
+ 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\"\r\n\tdojoAttachPoint=\"_buttonNode,tableNode,focusNode\" cellspacing='0' cellpadding='0'\r\n\trole=\"combobox\" aria-haspopup=\"true\"\r\n\t><tbody role=\"presentation\"><tr role=\"presentation\"\r\n\t\t><td class=\"dijitReset dijitStretch dijitButtonContents dijitButtonNode\" role=\"presentation\"\r\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\" dojoAttachPoint=\"containerNode,_popupStateNode\"></span\r\n\t\t\t><input type=\"hidden\" ${!nameAttrSetting} dojoAttachPoint=\"valueNode\" value=\"${value}\" aria-hidden=\"true\"\r\n\t\t/></td><td class=\"dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton\"\r\n\t\t\t\tdojoAttachPoint=\"titleNode\" role=\"presentation\"\r\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" role=\"presentation\"></div\r\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" role=\"presentation\">&#9660;</div\r\n\t\t></td\r\n\t></tr></tbody\r\n></table>\r\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: "",
+
+ // message: String
+ // Currently displayed error/prompt message
+ message: "",
+
+ // tooltipPosition: String[]
+ // See description of dijit.Tooltip.defaultPosition for details on this parameter.
+ tooltipPosition: [],
+
+ // emptyLabel: string
+ // What to display in an "empty" dropdown
+ emptyLabel: "&nbsp;",
+
+ // _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);
+ // set value from selected option
+ if(this.options.length && !this.value && this.srcNodeRef){
+ var si = this.srcNodeRef.selectedIndex || 0; // || 0 needed for when srcNodeRef is not a SELECT
+ this.value = this.options[si >= 0 ? 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 && !option.label){
+ // 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 || this.emptyLabel,
+ 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();
+ }
+
+ 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)
+ var lbl = newDisplay || this.emptyLabel;
+ this.containerNode.innerHTML = '<span class="dijitReset dijitInline ' + this.baseClass + 'Label">' + lbl + '</span>';
+ dijit.setWaiState(this.focusNode, "valuetext", lbl);
+ },
+
+ 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._set("state", isValid ? "" : "Error");
+ dijit.setWaiState(this.focusNode, "invalid", isValid ? "false" : "true");
+ var message = isValid ? "" : this._missingMsg;
+ if(this.message !== message){
+ this._set("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 || this.value === 0 || !(/^\s*$/.test(this.value || ""))); // handle value is null or undefined
+ },
+
+ reset: function(){
+ // summary:
+ // Overridden so that the state will be cleared.
+ this.inherited(arguments);
+ dijit.hideTooltip(this.domNode);
+ this._set("state", "");
+ this._set("message", "")
+ },
+
+ postMixInProperties: function(){
+ // summary:
+ // set the missing message
+ this.inherited(arguments);
+ this._missingMsg = dojo.i18n.getLocalization("dijit.form", "validate",
+ this.lang).missingMessage;
+ },
+
+ postCreate: function(){
+ // summary:
+ // stop mousemove from selecting text on IE to be consistent with other browsers
+
+ this.inherited(arguments);
+
+ this.connect(this.domNode, "onmousemove", dojo.stopEvent);
+ },
+
+ _setStyleAttr: function(/*String||Object*/ value){
+ this.inherited(arguments);
+ dojo.toggleClass(this.domNode, this.baseClass + "FixedWidth", !!this.tableNode.style.width);
+ },
+
+ 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._editor.plugins.LinkDialog"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._editor.plugins.LinkDialog"] = true;
+dojo.provide("dijit._editor.plugins.LinkDialog");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+dojo.declare("dijit._editor.plugins.LinkDialog", dijit._editor._Plugin, {
+ // summary:
+ // This plugin provides the basis for an 'anchor' (link) dialog and an extension of it
+ // provides the image link dialog.
+ //
+ // description:
+ // The command provided by this plugin is:
+ // * createLink
+
+ // Override _Plugin.buttonClass. This plugin is controlled by a DropDownButton
+ // (which triggers a TooltipDialog).
+ buttonClass: dijit.form.DropDownButton,
+
+ // Override _Plugin.useDefaultCommand... processing is handled by this plugin, not by dijit.Editor.
+ useDefaultCommand: false,
+
+ // urlRegExp: [protected] String
+ // Used for validating input as correct URL. While file:// urls are not terribly
+ // useful, they are technically valid.
+ urlRegExp: "((https?|ftps?|file)\\://|\./|/|)(/[a-zA-Z]{1,1}:/|)(((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)*(?:[a-zA-Z](?:[-\\da-zA-Z]{0,80}[\\da-zA-Z])?)\\.?)|(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])|(0[xX]0*[\\da-fA-F]?[\\da-fA-F]\\.){3}0[xX]0*[\\da-fA-F]?[\\da-fA-F]|(0+[0-3][0-7][0-7]\\.){3}0+[0-3][0-7][0-7]|(0|[1-9]\\d{0,8}|[1-3]\\d{9}|4[01]\\d{8}|42[0-8]\\d{7}|429[0-3]\\d{6}|4294[0-8]\\d{5}|42949[0-5]\\d{4}|429496[0-6]\\d{3}|4294967[01]\\d{2}|42949672[0-8]\\d|429496729[0-5])|0[xX]0*[\\da-fA-F]{1,8}|([\\da-fA-F]{1,4}\\:){7}[\\da-fA-F]{1,4}|([\\da-fA-F]{1,4}\\:){6}((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])))(\\:\\d+)?(/(?:[^?#\\s/]+/)*(?:[^?#\\s/]{0,}(?:\\?[^?#\\s/]*)?(?:#.*)?)?)?",
+
+ // emailRegExp: [protected] String
+ // Used for validating input as correct email address. Taken from dojox.validate
+ emailRegExp: "<?(mailto\\:)([!#-'*+\\-\\/-9=?A-Z^-~]+[.])*[!#-'*+\\-\\/-9=?A-Z^-~]+" /*username*/ + "@" +
+ "((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)+(?:[a-zA-Z](?:[-\\da-zA-Z]{0,6}[\\da-zA-Z])?)\\.?)|localhost|^[^-][a-zA-Z0-9_-]*>?", // host.
+
+ // htmlTemplate: [protected] String
+ // String used for templating the HTML to insert at the desired point.
+ htmlTemplate: "<a href=\"${urlInput}\" _djrealurl=\"${urlInput}\"" +
+ " target=\"${targetSelect}\"" +
+ ">${textInput}</a>",
+
+ // tag: [protected] String
+ // Tag used for the link type.
+ tag: "a",
+
+ // _hostRxp [private] RegExp
+ // Regular expression used to validate url fragments (ip address, hostname, etc)
+ _hostRxp: new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$"),
+
+ // _userAtRxp [private] RegExp
+ // Regular expression used to validate e-mail address fragment.
+ _userAtRxp: new RegExp("^([!#-'*+\\-\\/-9=?A-Z^-~]+[.])*[!#-'*+\\-\\/-9=?A-Z^-~]+@", "i"),
+
+ // linkDialogTemplate: [protected] String
+ // Template for contents of TooltipDialog to pick URL
+ linkDialogTemplate: [
+ "<table><tr><td>",
+ "<label for='${id}_urlInput'>${url}</label>",
+ "</td><td>",
+ "<input dojoType='dijit.form.ValidationTextBox' required='true' " +
+ "id='${id}_urlInput' name='urlInput' intermediateChanges='true'/>",
+ "</td></tr><tr><td>",
+ "<label for='${id}_textInput'>${text}</label>",
+ "</td><td>",
+ "<input dojoType='dijit.form.ValidationTextBox' required='true' id='${id}_textInput' " +
+ "name='textInput' intermediateChanges='true'/>",
+ "</td></tr><tr><td>",
+ "<label for='${id}_targetSelect'>${target}</label>",
+ "</td><td>",
+ "<select id='${id}_targetSelect' name='targetSelect' dojoType='dijit.form.Select'>",
+ "<option selected='selected' value='_self'>${currentWindow}</option>",
+ "<option value='_blank'>${newWindow}</option>",
+ "<option value='_top'>${topWindow}</option>",
+ "<option value='_parent'>${parentWindow}</option>",
+ "</select>",
+ "</td></tr><tr><td colspan='2'>",
+ "<button dojoType='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>",
+ "<button dojoType='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>",
+ "</td></tr></table>"
+ ].join(""),
+
+ _initButton: function(){
+ // Override _Plugin._initButton() to initialize DropDownButton and TooltipDialog.
+ var _this = this;
+ this.tag = this.command == 'insertImage' ? 'img' : 'a';
+ var messages = dojo.mixin(dojo.i18n.getLocalization("dijit", "common", this.lang),
+ dojo.i18n.getLocalization("dijit._editor", "LinkDialog", this.lang));
+ var dropDown = (this.dropDown = new dijit.TooltipDialog({
+ title: messages[this.command + "Title"],
+ execute: dojo.hitch(this, "setValue"),
+ onOpen: function(){
+ _this._onOpenDialog();
+ dijit.TooltipDialog.prototype.onOpen.apply(this, arguments);
+ },
+ onCancel: function(){
+ setTimeout(dojo.hitch(_this, "_onCloseDialog"),0);
+ }
+ }));
+ messages.urlRegExp = this.urlRegExp;
+ messages.id = dijit.getUniqueId(this.editor.id);
+ this._uniqueId = messages.id;
+ this._setContent(dropDown.title +
+ "<div style='border-bottom: 1px black solid;padding-bottom:2pt;margin-bottom:4pt'></div>" +
+ dojo.string.substitute(this.linkDialogTemplate, messages));
+ dropDown.startup();
+ this._urlInput = dijit.byId(this._uniqueId + "_urlInput");
+ this._textInput = dijit.byId(this._uniqueId + "_textInput");
+ this._setButton = dijit.byId(this._uniqueId + "_setButton");
+ this.connect(dijit.byId(this._uniqueId + "_cancelButton"), "onClick", function(){
+ this.dropDown.onCancel();
+ });
+ if(this._urlInput){
+ this.connect(this._urlInput, "onChange", "_checkAndFixInput");
+ }
+ if(this._textInput){
+ this.connect(this._textInput, "onChange", "_checkAndFixInput");
+ }
+
+ // Build up the dual check for http/https/file:, and mailto formats.
+ this._urlRegExp = new RegExp("^" + this.urlRegExp + "$", "i");
+ this._emailRegExp = new RegExp("^" + this.emailRegExp + "$", "i");
+ this._urlInput.isValid = dojo.hitch(this, function(){
+ // Function over-ride of isValid to test if the input matches a url or a mailto style link.
+ var value = this._urlInput.get("value");
+ return this._urlRegExp.test(value) || this._emailRegExp.test(value);
+ });
+
+ this._connectTagEvents();
+ this.inherited(arguments);
+ },
+
+ _checkAndFixInput: function(){
+ // summary:
+ // A function to listen for onChange events and test the input contents
+ // for valid information, such as valid urls with http/https/ftp and if
+ // not present, try and guess if the input url is relative or not, and if
+ // not, append http:// to it. Also validates other fields as determined by
+ // the internal _isValid function.
+ var self = this;
+ var url = this._urlInput.get("value");
+ var fixupUrl = function(url){
+ var appendHttp = false;
+ var appendMailto = false;
+ if(url && url.length > 1){
+ url = dojo.trim(url);
+ if(url.indexOf("mailto:") !== 0){
+ if(url.indexOf("/") > 0){
+ if(url.indexOf("://") === -1){
+ // Check that it doesn't start with / or ./, which would
+ // imply 'target server relativeness'
+ if(url.charAt(0) !== '/' && url.indexOf("./") !== 0){
+ if(self._hostRxp.test(url)){
+ appendHttp = true;
+ }
+ }
+ }
+ }else if(self._userAtRxp.test(url)){
+ // If it looks like a foo@, append a mailto.
+ appendMailto = true;
+ }
+ }
+ }
+ if(appendHttp){
+ self._urlInput.set("value", "http://" + url);
+ }
+ if(appendMailto){
+ self._urlInput.set("value", "mailto:" + url);
+ }
+ self._setButton.set("disabled", !self._isValid());
+ };
+ if(this._delayedCheck){
+ clearTimeout(this._delayedCheck);
+ this._delayedCheck = null;
+ }
+ this._delayedCheck = setTimeout(function(){
+ fixupUrl(url);
+ }, 250);
+ },
+
+ _connectTagEvents: function(){
+ // summary:
+ // Over-ridable function that connects tag specific events.
+ this.editor.onLoadDeferred.addCallback(dojo.hitch(this, function(){
+ this.connect(this.editor.editNode, "ondblclick", this._onDblClick);
+ }));
+ },
+
+ _isValid: function(){
+ // summary:
+ // Internal function to allow validating of the inputs
+ // for a link to determine if set should be disabled or not
+ // tags:
+ // protected
+ return this._urlInput.isValid() && this._textInput.isValid();
+ },
+
+ _setContent: function(staticPanel){
+ // summary:
+ // Helper for _initButton above. Not sure why it's a separate method.
+ this.dropDown.set({
+ parserScope: "dojo", // make parser search for dojoType/data-dojo-type even if page is multi-version
+ content: staticPanel
+ });
+ },
+
+ _checkValues: function(args){
+ // summary:
+ // Function to check the values in args and 'fix' them up as needed.
+ // args: Object
+ // Content being set.
+ // tags:
+ // protected
+ if(args && args.urlInput){
+ args.urlInput = args.urlInput.replace(/"/g, "&quot;");
+ }
+ return args;
+ },
+
+ setValue: function(args){
+ // summary:
+ // Callback from the dialog when user presses "set" button.
+ // tags:
+ // private
+ //TODO: prevent closing popup if the text is empty
+ this._onCloseDialog();
+ if(dojo.isIE){ //see #4151
+ var sel = dijit.range.getSelection(this.editor.window);
+ var range = sel.getRangeAt(0);
+ var a = range.endContainer;
+ if(a.nodeType === 3){
+ // Text node, may be the link contents, so check parent.
+ // This plugin doesn't really support nested HTML elements
+ // in the link, it assumes all link content is text.
+ a = a.parentNode;
+ }
+ if(a && (a.nodeName && a.nodeName.toLowerCase() !== this.tag)){
+ // Stll nothing, one last thing to try on IE, as it might be 'img'
+ // and thus considered a control.
+ a = dojo.withGlobal(this.editor.window,
+ "getSelectedElement", dijit._editor.selection, [this.tag]);
+ }
+ if(a && (a.nodeName && a.nodeName.toLowerCase() === this.tag)){
+ // Okay, we do have a match. IE, for some reason, sometimes pastes before
+ // instead of removing the targetted paste-over element, so we unlink the
+ // old one first. If we do not the <a> tag remains, but it has no content,
+ // so isn't readily visible (but is wrong for the action).
+ if(this.editor.queryCommandEnabled("unlink")){
+ // Select all the link childent, then unlink. The following insert will
+ // then replace the selected text.
+ dojo.withGlobal(this.editor.window,
+ "selectElementChildren", dijit._editor.selection, [a]);
+ this.editor.execCommand("unlink");
+ }
+ }
+ }
+ // make sure values are properly escaped, etc.
+ args = this._checkValues(args);
+ this.editor.execCommand('inserthtml',
+ dojo.string.substitute(this.htmlTemplate, args));
+ },
+
+ _onCloseDialog: function(){
+ // summary:
+ // Handler for close event on the dialog
+ this.editor.focus();
+ },
+
+ _getCurrentValues: function(a){
+ // summary:
+ // Over-ride for getting the values to set in the dropdown.
+ // a:
+ // The anchor/link to process for data for the dropdown.
+ // tags:
+ // protected
+ var url, text, target;
+ if(a && a.tagName.toLowerCase() === this.tag){
+ url = a.getAttribute('_djrealurl') || a.getAttribute('href');
+ target = a.getAttribute('target') || "_self";
+ text = a.textContent || a.innerText;
+ dojo.withGlobal(this.editor.window, "selectElement", dijit._editor.selection, [a, true]);
+ }else{
+ text = dojo.withGlobal(this.editor.window, dijit._editor.selection.getSelectedText);
+ }
+ return {urlInput: url || '', textInput: text || '', targetSelect: target || ''}; //Object;
+ },
+
+ _onOpenDialog: function(){
+ // summary:
+ // Handler for when the dialog is opened.
+ // If the caret is currently in a URL then populate the URL's info into the dialog.
+ var a;
+ if(dojo.isIE){
+ // IE is difficult to select the element in, using the range unified
+ // API seems to work reasonably well.
+ var sel = dijit.range.getSelection(this.editor.window);
+ var range = sel.getRangeAt(0);
+ a = range.endContainer;
+ if(a.nodeType === 3){
+ // Text node, may be the link contents, so check parent.
+ // This plugin doesn't really support nested HTML elements
+ // in the link, it assumes all link content is text.
+ a = a.parentNode;
+ }
+ if(a && (a.nodeName && a.nodeName.toLowerCase() !== this.tag)){
+ // Stll nothing, one last thing to try on IE, as it might be 'img'
+ // and thus considered a control.
+ a = dojo.withGlobal(this.editor.window,
+ "getSelectedElement", dijit._editor.selection, [this.tag]);
+ }
+ }else{
+ a = dojo.withGlobal(this.editor.window,
+ "getAncestorElement", dijit._editor.selection, [this.tag]);
+ }
+ this.dropDown.reset();
+ this._setButton.set("disabled", true);
+ this.dropDown.set("value", this._getCurrentValues(a));
+ },
+
+ _onDblClick: function(e){
+ // summary:
+ // Function to define a behavior on double clicks on the element
+ // type this dialog edits to select it and pop up the editor
+ // dialog.
+ // e: Object
+ // The double-click event.
+ // tags:
+ // protected.
+ if(e && e.target){
+ var t = e.target;
+ var tg = t.tagName? t.tagName.toLowerCase() : "";
+ if(tg === this.tag && dojo.attr(t,"href")){
+ dojo.withGlobal(this.editor.window,
+ "selectElement",
+ dijit._editor.selection, [t]);
+ this.editor.onDisplayChanged();
+ setTimeout(dojo.hitch(this, function(){
+ // Focus shift outside the event handler.
+ // IE doesn't like focus changes in event handles.
+ this.button.set("disabled", false);
+ this.button.openDropDown();
+ }), 10);
+ }
+ }
+ }
+});
+
+dojo.declare("dijit._editor.plugins.ImgLinkDialog", [dijit._editor.plugins.LinkDialog], {
+ // summary:
+ // This plugin extends LinkDialog and adds in a plugin for handling image links.
+ // provides the image link dialog.
+ //
+ // description:
+ // The command provided by this plugin is:
+ // * insertImage
+
+ // linkDialogTemplate: [protected] String
+ // Over-ride for template since img dialog doesn't need target that anchor tags may.
+ linkDialogTemplate: [
+ "<table><tr><td>",
+ "<label for='${id}_urlInput'>${url}</label>",
+ "</td><td>",
+ "<input dojoType='dijit.form.ValidationTextBox' regExp='${urlRegExp}' " +
+ "required='true' id='${id}_urlInput' name='urlInput' intermediateChanges='true'/>",
+ "</td></tr><tr><td>",
+ "<label for='${id}_textInput'>${text}</label>",
+ "</td><td>",
+ "<input dojoType='dijit.form.ValidationTextBox' required='false' id='${id}_textInput' " +
+ "name='textInput' intermediateChanges='true'/>",
+ "</td></tr><tr><td>",
+ "</td><td>",
+ "</td></tr><tr><td colspan='2'>",
+ "<button dojoType='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>",
+ "<button dojoType='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>",
+ "</td></tr></table>"
+ ].join(""),
+
+ // htmlTemplate: [protected] String
+ // String used for templating the <img> HTML to insert at the desired point.
+ htmlTemplate: "<img src=\"${urlInput}\" _djrealurl=\"${urlInput}\" alt=\"${textInput}\" />",
+
+ // tag: [protected] String
+ // Tag used for the link type (img).
+ tag: "img",
+
+ _getCurrentValues: function(img){
+ // summary:
+ // Over-ride for getting the values to set in the dropdown.
+ // a:
+ // The anchor/link to process for data for the dropdown.
+ // tags:
+ // protected
+ var url, text;
+ if(img && img.tagName.toLowerCase() === this.tag){
+ url = img.getAttribute('_djrealurl') || img.getAttribute('src');
+ text = img.getAttribute('alt');
+ dojo.withGlobal(this.editor.window,
+ "selectElement", dijit._editor.selection, [img, true]);
+ }else{
+ text = dojo.withGlobal(this.editor.window, dijit._editor.selection.getSelectedText);
+ }
+ return {urlInput: url || '', textInput: text || ''}; //Object;
+ },
+
+ _isValid: function(){
+ // summary:
+ // Over-ride for images. You can have alt text of blank, it is valid.
+ // tags:
+ // protected
+ return this._urlInput.isValid();
+ },
+
+ _connectTagEvents: function(){
+ // summary:
+ // Over-ridable function that connects tag specific events.
+ this.inherited(arguments);
+ this.editor.onLoadDeferred.addCallback(dojo.hitch(this, function(){
+ // Use onmousedown instead of onclick. Seems that IE eats the first onclick
+ // to wrap it in a selector box, then the second one acts as onclick. See #10420
+ this.connect(this.editor.editNode, "onmousedown", this._selectTag);
+ }));
+ },
+
+ _selectTag: function(e){
+ // summary:
+ // A simple event handler that lets me select an image if it is clicked on.
+ // makes it easier to select images in a standard way across browsers. Otherwise
+ // selecting an image for edit becomes difficult.
+ // e: Event
+ // The mousedown event.
+ // tags:
+ // private
+ if(e && e.target){
+ var t = e.target;
+ var tg = t.tagName? t.tagName.toLowerCase() : "";
+ if(tg === this.tag){
+ dojo.withGlobal(this.editor.window,
+ "selectElement",
+ dijit._editor.selection, [t]);
+ }
+ }
+ },
+
+ _checkValues: function(args){
+ // summary:
+ // Function to check the values in args and 'fix' them up as needed
+ // (special characters in the url or alt text)
+ // args: Object
+ // Content being set.
+ // tags:
+ // protected
+ if(args && args.urlInput){
+ args.urlInput = args.urlInput.replace(/"/g, "&quot;");
+ }
+ if(args && args.textInput){
+ args.textInput = args.textInput.replace(/"/g, "&quot;");
+ }
+ return args;
+ },
+
+ _onDblClick: function(e){
+ // summary:
+ // Function to define a behavior on double clicks on the element
+ // type this dialog edits to select it and pop up the editor
+ // dialog.
+ // e: Object
+ // The double-click event.
+ // tags:
+ // protected.
+ if(e && e.target){
+ var t = e.target;
+ var tg = t.tagName? t.tagName.toLowerCase() : "";
+ if(tg === this.tag && dojo.attr(t,"src")){
+ dojo.withGlobal(this.editor.window,
+ "selectElement",
+ dijit._editor.selection, [t]);
+ this.editor.onDisplayChanged();
+ setTimeout(dojo.hitch(this, function(){
+ // Focus shift outside the event handler.
+ // IE doesn't like focus changes in event handles.
+ this.button.set("disabled", false);
+ this.button.openDropDown();
+ }), 10);
+ }
+ }
+ }
+});
+
+// Register this plugin.
+dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
+ if(o.plugin){ return; }
+ switch(o.args.name){
+ case "createLink":
+ o.plugin = new dijit._editor.plugins.LinkDialog({command: o.args.name});
+ break;
+ case "insertImage":
+ o.plugin = new dijit._editor.plugins.ImgLinkDialog({command: o.args.name});
+ break;
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.MenuBar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.MenuBar"] = true;
+dojo.provide("dijit.MenuBar");
+
+
+
+
+dojo.declare("dijit.MenuBar", dijit._MenuBase, {
+ // summary:
+ // A menu bar, listing menu choices horizontally, like the "File" menu in most desktop applications
+
+ templateString: dojo.cache("dijit", "templates/MenuBar.html", "<div class=\"dijitMenuBar dijitMenuPassive\" dojoAttachPoint=\"containerNode\" role=\"menubar\" tabIndex=\"${tabIndex}\" dojoAttachEvent=\"onkeypress: _onKeyPress\"></div>\r\n"),
+
+ baseClass: "dijitMenuBar",
+
+ // _isMenuBar: [protected] Boolean
+ // This is a MenuBar widget, not a (vertical) Menu widget.
+ _isMenuBar: true,
+
+ postCreate: function(){
+ var k = dojo.keys, l = this.isLeftToRight();
+ this.connectKeyNavHandlers(
+ l ? [k.LEFT_ARROW] : [k.RIGHT_ARROW],
+ l ? [k.RIGHT_ARROW] : [k.LEFT_ARROW]
+ );
+
+ // parameter to dijit.popup.open() about where to put popup (relative to this.domNode)
+ this._orient = this.isLeftToRight() ? {BL: 'TL'} : {BR: 'TR'};
+ },
+
+ focusChild: function(item){
+ // overload focusChild so that whenever the focus is moved to a new item,
+ // check the previous focused whether it has its popup open, if so, after
+ // focusing the new item, open its submenu immediately
+ var prev_item = this.focusedChild,
+ showpopup = prev_item && prev_item.popup && prev_item.popup.isShowingNow;
+ this.inherited(arguments);
+ if(showpopup && item.popup && !item.disabled){
+ this._openPopup(); // TODO: on down arrow, _openPopup() is called here and in onItemClick()
+ }
+ },
+
+ _onKeyPress: function(/*Event*/ evt){
+ // summary:
+ // Handle keyboard based menu navigation.
+ // tags:
+ // protected
+
+ if(evt.ctrlKey || evt.altKey){ return; }
+
+ switch(evt.charOrCode){
+ case dojo.keys.DOWN_ARROW:
+ this._moveToPopup(evt);
+ dojo.stopEvent(evt);
+ }
+ },
+
+ onItemClick: function(/*dijit._Widget*/ item, /*Event*/ evt){
+ // summary:
+ // Handle clicks on an item. Cancels a dropdown if already open.
+ // tags:
+ // private
+ if(item.popup && item.popup.isShowingNow){
+ item.popup.onCancel();
+ }else{
+ this.inherited(arguments);
+ }
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.MenuBarItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.MenuBarItem"] = true;
+dojo.provide("dijit.MenuBarItem");
+
+
+
+
+dojo.declare("dijit._MenuBarItemMixin", null, {
+ templateString: dojo.cache("dijit", "templates/MenuBarItem.html", "<div class=\"dijitReset dijitInline dijitMenuItem dijitMenuItemLabel\" dojoAttachPoint=\"focusNode\" role=\"menuitem\" tabIndex=\"-1\"\r\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\r\n\t<span dojoAttachPoint=\"containerNode\"></span>\r\n</div>\r\n"),
+
+ // overriding attributeMap because we don't have icon
+ attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+ label: { node: "containerNode", type: "innerHTML" }
+ })
+});
+
+dojo.declare("dijit.MenuBarItem", [dijit.MenuItem, dijit._MenuBarItemMixin], {
+ // summary:
+ // Item in a MenuBar that's clickable, and doesn't spawn a submenu when pressed (or hovered)
+
+});
+
+}
+
+if(!dojo._hasResource["dijit.PopupMenuBarItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.PopupMenuBarItem"] = true;
+dojo.provide("dijit.PopupMenuBarItem");
+
+
+
+
+
+dojo.declare("dijit.PopupMenuBarItem", [dijit.PopupMenuItem, dijit._MenuBarItemMixin], {
+ // summary:
+ // Item in a MenuBar like "File" or "Edit", that spawns a submenu when pressed (or hovered)
+});
+
+}
+
+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.getObject("number", true, dojo);
+
+/*=====
+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"
+ // | value="..." maximum="...">
+ // | </div>
+
+ // progress: [const] String (Percentage or Number)
+ // Number or percentage indicating amount of task completed.
+ // Deprecated. Use "value" instead.
+ progress: "0",
+
+ // value: 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.
+ // Infinity means that the progress bar is indeterminate.
+ value: "",
+
+ // 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.
+ // Deprecated. Use "value" instead.
+ indeterminate: false,
+
+ // label: String?
+ // Label on progress bar. Defaults to percentage for determinate progress bar and
+ // blank for indeterminate progress bar.
+ label:"",
+
+ // 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\" role=\"progressbar\"\r\n\t><div dojoAttachPoint=\"internalProgress\" class=\"dijitProgressBarFull\"\r\n\t\t><div class=\"dijitProgressBarTile\" role=\"presentation\"></div\r\n\t\t><span style=\"visibility:hidden\">&nbsp;</span\r\n\t></div\r\n\t><div dojoAttachPoint=\"labelNode\" class=\"dijitProgressBarLabel\" id=\"${id}_label\"></div\r\n\t><img dojoAttachPoint=\"indeterminateHighContrastImage\" class=\"dijitProgressBarIndeterminateHighContrastImage\" alt=\"\"\r\n/></div>\r\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"),
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ if(!("value" in this.params)){
+ this.value = this.indeterminate ? Infinity : this.progress;
+ }
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ this.indeterminateHighContrastImage.setAttribute("src",
+ this._indeterminateHighContrastImagePath.toString());
+ this.update();
+ },
+
+ update: function(/*Object?*/attributes){
+ // summary:
+ // Internal method to change attributes of ProgressBar, similar to set(hash). Users should call
+ // set("value", ...) rather than calling this method directly.
+ // 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});
+ // | myProgressBar.update({'indeterminate': true, label:"Loading ..." })
+ // tags:
+ // private
+
+ // TODO: deprecate this method and use set() instead
+
+ dojo.mixin(this, attributes || {});
+ var tip = this.internalProgress, ap = this.domNode;
+ var percent = 1;
+ if(this.indeterminate){
+ dijit.removeWaiState(ap, "valuenow");
+ dijit.removeWaiState(ap, "valuemin");
+ dijit.removeWaiState(ap, "valuemax");
+ }else{
+ 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;
+ }
+
+ dijit.setWaiState(ap, "describedby", this.labelNode.id);
+ dijit.setWaiState(ap, "valuenow", this.progress);
+ dijit.setWaiState(ap, "valuemin", 0);
+ dijit.setWaiState(ap, "valuemax", this.maximum);
+ }
+ this.labelNode.innerHTML = this.report(percent);
+
+ dojo.toggleClass(this.domNode, "dijitProgressBarIndeterminate", this.indeterminate);
+ tip.style.width = (percent * 100) + "%";
+ this.onChange();
+ },
+
+ _setValueAttr: function(v){
+ this._set("value", v);
+ if(v == Infinity){
+ this.update({indeterminate:true});
+ }else{
+ this.update({indeterminate:false, progress:v});
+ }
+ },
+
+ _setLabelAttr: function(label){
+ this._set("label", label);
+ this.update();
+ },
+
+ _setIndeterminateAttr: function(indeterminate){
+ // Deprecated, use set("value", ...) instead
+ this.indeterminate = indeterminate;
+ this.update();
+ },
+
+ report: function(/*float*/percent){
+ // summary:
+ // Generates message to show inside progress bar (normally indicating amount of task completed).
+ // May be overridden.
+ // tags:
+ // extension
+
+ return this.label ? this.label :
+ (this.indeterminate ? "&nbsp;" : dojo.number.format(percent, { type: "percent", places: this.places, locale: this.lang }));
+ },
+
+ onChange: function(){
+ // summary:
+ // Callback fired when progress updates.
+ // tags:
+ // extension
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.TitlePane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.TitlePane"] = true;
+dojo.provide("dijit.TitlePane");
+
+
+
+
+
+
+
+dojo.declare(
+ "dijit.TitlePane",
+ [dijit.layout.ContentPane, dijit._Templated, dijit._CssStateMixin],
+{
+ // summary:
+ // A pane with a title on top, that can be expanded or collapsed.
+ //
+ // description:
+ // An accessible container with a title Heading, and a content
+ // section that slides open and closed. TitlePane is an extension to
+ // `dijit.layout.ContentPane`, providing all the useful content-control aspects from it.
+ //
+ // example:
+ // | // load a TitlePane from remote file:
+ // | var foo = new dijit.TitlePane({ href: "foobar.html", title:"Title" });
+ // | foo.startup();
+ //
+ // example:
+ // | <!-- markup href example: -->
+ // | <div dojoType="dijit.TitlePane" href="foobar.html" title="Title"></div>
+ //
+ // example:
+ // | <!-- markup with inline data -->
+ // | <div dojoType="dijit.TitlePane" title="Title">
+ // | <p>I am content</p>
+ // | </div>
+
+ // title: String
+ // Title of the pane
+ title: "",
+
+ // open: Boolean
+ // Whether pane is opened or closed.
+ open: true,
+
+ // toggleable: Boolean
+ // Whether pane can be opened or closed by clicking the title bar.
+ toggleable: true,
+
+ // tabIndex: String
+ // Tabindex setting for the title (so users can tab to the title then
+ // use space/enter to open/close the title pane)
+ tabIndex: "0",
+
+ // duration: Integer
+ // Time in milliseconds to fade in/fade out
+ duration: dijit.defaultDuration,
+
+ // baseClass: [protected] String
+ // The root className to be placed on this widget's domNode.
+ baseClass: "dijitTitlePane",
+
+ templateString: dojo.cache("dijit", "templates/TitlePane.html", "<div>\r\n\t<div dojoAttachEvent=\"onclick:_onTitleClick, onkeypress:_onTitleKey\"\r\n\t\t\tclass=\"dijitTitlePaneTitle\" dojoAttachPoint=\"titleBarNode\">\r\n\t\t<div class=\"dijitTitlePaneTitleFocus\" dojoAttachPoint=\"focusNode\">\r\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"arrowNode\" class=\"dijitArrowNode\" role=\"presentation\"\r\n\t\t\t/><span dojoAttachPoint=\"arrowNodeInner\" class=\"dijitArrowNodeInner\"></span\r\n\t\t\t><span dojoAttachPoint=\"titleNode\" class=\"dijitTitlePaneTextNode\"></span>\r\n\t\t</div>\r\n\t</div>\r\n\t<div class=\"dijitTitlePaneContentOuter\" dojoAttachPoint=\"hideNode\" role=\"presentation\">\r\n\t\t<div class=\"dijitReset\" dojoAttachPoint=\"wipeNode\" role=\"presentation\">\r\n\t\t\t<div class=\"dijitTitlePaneContentInner\" dojoAttachPoint=\"containerNode\" role=\"region\" id=\"${id}_pane\">\r\n\t\t\t\t<!-- nested divs because wipeIn()/wipeOut() doesn't work right on node w/padding etc. Put padding on inner div. -->\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n</div>\r\n"),
+
+ attributeMap: dojo.delegate(dijit.layout.ContentPane.prototype.attributeMap, {
+ title: { node: "titleNode", type: "innerHTML" },
+ tooltip: {node: "focusNode", type: "attribute", attribute: "title"}, // focusNode spans the entire width, titleNode doesn't
+ id:""
+ }),
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dojo.setSelectable(this.titleNode, false);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // Hover and focus effect on title bar, except for non-toggleable TitlePanes
+ // This should really be controlled from _setToggleableAttr() but _CssStateMixin
+ // doesn't provide a way to disconnect a previous _trackMouseState() call
+ if(this.toggleable){
+ this._trackMouseState(this.titleBarNode, "dijitTitlePaneTitle");
+ }
+
+ // setup open/close animations
+ var hideNode = this.hideNode, wipeNode = this.wipeNode;
+ this._wipeIn = dojo.fx.wipeIn({
+ node: this.wipeNode,
+ duration: this.duration,
+ beforeBegin: function(){
+ hideNode.style.display="";
+ }
+ });
+ this._wipeOut = dojo.fx.wipeOut({
+ node: this.wipeNode,
+ duration: this.duration,
+ onEnd: function(){
+ hideNode.style.display="none";
+ }
+ });
+ },
+
+ _setOpenAttr: function(/*Boolean*/ open, /*Boolean*/ animate){
+ // summary:
+ // Hook to make set("open", boolean) control the open/closed state of the pane.
+ // open: Boolean
+ // True if you want to open the pane, false if you want to close it.
+
+ dojo.forEach([this._wipeIn, this._wipeOut], function(animation){
+ if(animation && animation.status() == "playing"){
+ animation.stop();
+ }
+ });
+
+ if(animate){
+ var anim = this[open ? "_wipeIn" : "_wipeOut"];
+ anim.play();
+ }else{
+ this.hideNode.style.display = this.wipeNode.style.display = open ? "" : "none";
+ }
+
+ // load content (if this is the first time we are opening the TitlePane
+ // and content is specified as an href, or href was set when hidden)
+ if(this._started){
+ if(open){
+ this._onShow();
+ }else{
+ this.onHide();
+ }
+ }
+
+ this.arrowNodeInner.innerHTML = open ? "-" : "+";
+
+ dijit.setWaiState(this.containerNode,"hidden", open ? "false" : "true");
+ dijit.setWaiState(this.focusNode, "pressed", open ? "true" : "false");
+
+ this._set("open", open);
+
+ this._setCss();
+ },
+
+ _setToggleableAttr: function(/*Boolean*/ canToggle){
+ // summary:
+ // Hook to make set("toggleable", boolean) work.
+ // canToggle: Boolean
+ // True to allow user to open/close pane by clicking title bar.
+
+ dijit.setWaiRole(this.focusNode, canToggle ? "button" : "heading");
+ if(canToggle){
+ // TODO: if canToggle is switched from true to false shouldn't we remove this setting?
+ dijit.setWaiState(this.focusNode, "controls", this.id+"_pane");
+ dojo.attr(this.focusNode, "tabIndex", this.tabIndex);
+ }else{
+ dojo.removeAttr(this.focusNode, "tabIndex");
+ }
+
+ this._set("toggleable", canToggle);
+
+ this._setCss();
+ },
+
+ _setContentAttr: function(/*String|DomNode|Nodelist*/ content){
+ // summary:
+ // Hook to make set("content", ...) work.
+ // Typically called when an href is loaded. Our job is to make the animation smooth.
+
+ if(!this.open || !this._wipeOut || this._wipeOut.status() == "playing"){
+ // we are currently *closing* the pane (or the pane is closed), so just let that continue
+ this.inherited(arguments);
+ }else{
+ if(this._wipeIn && this._wipeIn.status() == "playing"){
+ this._wipeIn.stop();
+ }
+
+ // freeze container at current height so that adding new content doesn't make it jump
+ dojo.marginBox(this.wipeNode, { h: dojo.marginBox(this.wipeNode).h });
+
+ // add the new content (erasing the old content, if any)
+ this.inherited(arguments);
+
+ // call _wipeIn.play() to animate from current height to new height
+ if(this._wipeIn){
+ this._wipeIn.play();
+ }else{
+ this.hideNode.style.display = "";
+ }
+ }
+ },
+
+ toggle: function(){
+ // summary:
+ // Switches between opened and closed state
+ // tags:
+ // private
+
+ this._setOpenAttr(!this.open, true);
+ },
+
+ _setCss: function(){
+ // summary:
+ // Set the open/close css state for the TitlePane
+ // tags:
+ // private
+
+ var node = this.titleBarNode || this.focusNode;
+ var oldCls = this._titleBarClass;
+ this._titleBarClass = "dijit" + (this.toggleable ? "" : "Fixed") + (this.open ? "Open" : "Closed");
+ dojo.replaceClass(node, this._titleBarClass, oldCls || "");
+
+ this.arrowNodeInner.innerHTML = this.open ? "-" : "+";
+ },
+
+ _onTitleKey: function(/*Event*/ e){
+ // summary:
+ // Handler for when user hits a key
+ // tags:
+ // private
+
+ if(e.charOrCode == dojo.keys.ENTER || e.charOrCode == ' '){
+ if(this.toggleable){
+ this.toggle();
+ }
+ dojo.stopEvent(e);
+ }else if(e.charOrCode == dojo.keys.DOWN_ARROW && this.open){
+ this.containerNode.focus();
+ e.preventDefault();
+ }
+ },
+
+ _onTitleClick: function(){
+ // summary:
+ // Handler when user clicks the title bar
+ // tags:
+ // private
+ if(this.toggleable){
+ this.toggle();
+ }
+ },
+
+ setTitle: function(/*String*/ title){
+ // summary:
+ // Deprecated. Use set('title', ...) instead.
+ // tags:
+ // deprecated
+ dojo.deprecated("dijit.TitlePane.setTitle() is deprecated. Use set('title', ...) instead.", "", "2.0");
+ this.set("title", title);
+ }
+});
+
+}
+
+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["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.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]}, LnewItem;
+
+ 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.
+ LnewItem=this.store.newItem(args, pInfo);
+ if (LnewItem && (insertIndex!=undefined)){
+ // Move new item to desired position
+ this.pasteItem(LnewItem, parent, parent, false, insertIndex);
+ }
+ }
+ }});
+ }else{
+ // [as far as we know] there is no id so we must assume this is a new item
+ LnewItem=this.store.newItem(args, pInfo);
+ if (LnewItem && (insertIndex!=undefined)){
+ // Move new item to desired position
+ this.pasteItem(LnewItem, parent, parent, false, insertIndex);
+ }
+ }
+ },
+
+ 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 a dijit.Tree and a dojo.data store that doesn't have a root item,
+ // a.k.a. a store that has multiple "top level" items.
+ //
+ // description
+ // Use this class to wrap a dojo.data 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.
+ // This class allows dijit.Tree to assume a single root item, even if the store doesn't have one.
+ //
+ // When using this class the developer must override a number of methods according to their app and
+ // data, including:
+ // - onNewRootItem
+ // - onAddToRoot
+ // - onLeaveRoot
+ // - onNewItem
+ // - onSetItem
+
+ // 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).
+ //
+ // If developers can detect which items are possible top level items (based on the item and the
+ // parentInfo parameters), they should override this method to only call _requeryTop() for top
+ // level items. 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);
+ },
+
+ onSetItem: function(/* item */ item,
+ /* attribute-name-string */ attribute,
+ /* object | array */ oldValue,
+ /* object | array */ newValue){
+ // summary:
+ // Updates the tree view according to changes to an item in the data store.
+ // Developers should override this method to be more efficient based on their app/data.
+ // description:
+ // Handles updates to an item's children by calling onChildrenChange(), and
+ // other updates to an item by calling onChange().
+ //
+ // Also, any change to any item re-executes the query for the tree's top-level items,
+ // since this modified item may have started/stopped matching the query for top level items.
+ //
+ // If possible, developers should override this function to only call _requeryTop() when
+ // the change to the item has caused it to stop/start being a top level item in the tree.
+ // tags:
+ // extension
+
+ this._requeryTop();
+ this.inherited(arguments);
+ }
+
+});
+
+}
+
+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.replaceClass(this.node, prefix + newState, prefix + this[state]);
+ 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.getObject("tree", true, dojo);
+
+dijit.tree._compareNodes = function(n1, n2){
+ if(n1 === n2){
+ return 0;
+ }
+
+ if('sourceIndex' in document.documentElement){ //IE
+ //TODO: does not yet work if n1 and/or n2 is a text node
+ return n1.sourceIndex - n2.sourceIndex;
+ }else if('compareDocumentPosition' in document.documentElement){ //FF, Opera
+ return n1.compareDocumentPosition(n2) & 2 ? 1: -1;
+ }else if(document.createRange){ //Webkit
+ var r1 = doc.createRange();
+ r1.setStartBefore(n1);
+
+ var r2 = doc.createRange();
+ r2.setStartBefore(n2);
+
+ return r1.compareBoundaryPoints(r1.END_TO_END, r2);
+ }else{
+ throw Error("dijit.tree._compareNodes don't know how to compare two different nodes in this browser");
+ }
+};
+
+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 widget = this.selection[key],
+ ret = {
+ data: widget,
+ 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;
+ },
+
+ onMouseOut: function(/*TreeNode*/ widget, /*Event*/ evt){
+ // summary:
+ // Called when mouse is moved away from a TreeNode
+ // tags:
+ // protected
+ this.current = 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.replaceClass(this.node, prefix + newState, prefix + this[state]);
+ 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;
+
+ dijit.setWaiState(this.tree.domNode, "multiselect", !this.singular);
+
+ 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
+ getSelectedTreeNodes: function(){
+ // summary:
+ // Returns a list of selected node(s).
+ // Used by dndSource on the start of a drag.
+ // tags:
+ // protected
+ var nodes=[], sel = this.selection;
+ for(var i in sel){
+ nodes.push(sel[i]);
+ }
+ return nodes;
+ },
+
+ selectNone: function(){
+ // summary:
+ // Unselects all items
+ // tags:
+ // private
+
+ this.setSelection([]);
+ return this; // self
+ },
+
+ destroy: function(){
+ // summary:
+ // Prepares the object to be garbage-collected
+ this.inherited(arguments);
+ this.selection = this.anchor = null;
+ },
+ addTreeNode: function(/*dijit._TreeNode*/node, /*Boolean?*/isAnchor){
+ // summary
+ // add node to current selection
+ // node: Node
+ // node to add
+ // isAnchor: Boolean
+ // Whether the node should become anchor.
+
+ this.setSelection(this.getSelectedTreeNodes().concat( [node] ));
+ if(isAnchor){ this.anchor = node; }
+ return node;
+ },
+ removeTreeNode: function(/*dijit._TreeNode*/node){
+ // summary
+ // remove node from current selection
+ // node: Node
+ // node to remove
+ this.setSelection(this._setDifference(this.getSelectedTreeNodes(), [node]))
+ return node;
+ },
+ isTreeNodeSelected: function(/*dijit._TreeNode*/node){
+ // summary
+ // return true if node is currently selected
+ // node: Node
+ // the node to check whether it's in the current selection
+
+ return node.id && !!this.selection[node.id];
+ },
+ setSelection: function(/*dijit._treeNode[]*/ newSelection){
+ // summary
+ // set the list of selected nodes to be exactly newSelection. All changes to the
+ // selection should be passed through this function, which ensures that derived
+ // attributes are kept up to date. Anchor will be deleted if it has been removed
+ // from the selection, but no new anchor will be added by this function.
+ // newSelection: Node[]
+ // list of tree nodes to make selected
+ var oldSelection = this.getSelectedTreeNodes();
+ dojo.forEach(this._setDifference(oldSelection, newSelection), dojo.hitch(this, function(node){
+ node.setSelected(false);
+ if(this.anchor == node){
+ delete this.anchor;
+ }
+ delete this.selection[node.id];
+ }));
+ dojo.forEach(this._setDifference(newSelection, oldSelection), dojo.hitch(this, function(node){
+ node.setSelected(true);
+ this.selection[node.id] = node;
+ }));
+ this._updateSelectionProperties();
+ },
+ _setDifference: function(xs,ys){
+ // summary
+ // Returns a copy of xs which lacks any objects
+ // occurring in ys. Checks for membership by
+ // modifying and then reading the object, so it will
+ // not properly handle sets of numbers or strings.
+
+ dojo.forEach(ys, function(y){ y.__exclude__ = true; });
+ var ret = dojo.filter(xs, function(x){ return !x.__exclude__; });
+
+ // clean up after ourselves.
+ dojo.forEach(ys, function(y){ delete y['__exclude__'] });
+ return ret;
+ },
+ _updateSelectionProperties: function() {
+ // summary
+ // Update the following tree properties from the current selection:
+ // path[s], selectedItem[s], selectedNode[s]
+
+ var selected = this.getSelectedTreeNodes();
+ var paths = [], nodes = [];
+ dojo.forEach(selected, function(node) {
+ nodes.push(node);
+ paths.push(node.getTreePath());
+ });
+ var items = dojo.map(nodes,function(node) { return node.item; });
+ this.tree._set("paths", paths);
+ this.tree._set("path", paths[0] || []);
+ this.tree._set("selectedNodes", nodes);
+ this.tree._set("selectedNode", nodes[0] || null);
+ this.tree._set("selectedItems", items);
+ this.tree._set("selectedItem", items[0] || null);
+ },
+ // mouse events
+ onMouseDown: function(e){
+ // summary:
+ // Event processor for onmousedown
+ // e: Event
+ // mouse event
+ // tags:
+ // protected
+
+ // ignore click on expando node
+ if(!this.current || this.tree.isExpandoNode( e.target, this.current)){ return; }
+
+ if(e.button == dojo.mouseButtons.RIGHT){ return; } // ignore right-click
+
+ dojo.stopEvent(e);
+
+ var treeNode = this.current,
+ copy = dojo.isCopyKey(e), id = treeNode.id;
+
+ // if shift key is not pressed, and the node is already in the selection,
+ // delay deselection until onmouseup so in the case of DND, deselection
+ // will be canceled by onmousemove.
+ if(!this.singular && !e.shiftKey && this.selection[id]){
+ this._doDeselect = true;
+ return;
+ }else{
+ this._doDeselect = false;
+ }
+ this.userSelect(treeNode, copy, e.shiftKey);
+ },
+
+ onMouseUp: function(e){
+ // summary:
+ // Event processor for onmouseup
+ // e: Event
+ // mouse event
+ // tags:
+ // protected
+
+ // _doDeselect is the flag to indicate that the user wants to either ctrl+click on
+ // a already selected item (to deselect the item), or click on a not-yet selected item
+ // (which should remove all current selection, and add the clicked item). This can not
+ // be done in onMouseDown, because the user may start a drag after mousedown. By moving
+ // the deselection logic here, the user can drags an already selected item.
+ if(!this._doDeselect){ return; }
+ this._doDeselect = false;
+ this.userSelect(this.current, dojo.isCopyKey( e ), e.shiftKey);
+ },
+ onMouseMove: function(e){
+ // summary
+ // event processor for onmousemove
+ // e: Event
+ // mouse event
+ this._doDeselect = false;
+ },
+
+ userSelect: function(node, multi, range){
+ // summary:
+ // Add or remove the given node from selection, responding
+ // to a user action such as a click or keypress.
+ // multi: Boolean
+ // Indicates whether this is meant to be a multi-select action (e.g. ctrl-click)
+ // range: Boolean
+ // Indicates whether this is meant to be a ranged action (e.g. shift-click)
+ // tags:
+ // protected
+
+ if(this.singular){
+ if(this.anchor == node && multi){
+ this.selectNone();
+ }else{
+ this.setSelection([node]);
+ this.anchor = node;
+ }
+ }else{
+ if(range && this.anchor){
+ var cr = dijit.tree._compareNodes(this.anchor.rowNode, node.rowNode),
+ begin, end, anchor = this.anchor;
+
+ if(cr < 0){ //current is after anchor
+ begin = anchor;
+ end = node;
+ }else{ //current is before anchor
+ begin = node;
+ end = anchor;
+ }
+ nodes = [];
+ //add everything betweeen begin and end inclusively
+ while(begin != end) {
+ nodes.push(begin)
+ begin = this.tree._getNextNode(begin);
+ }
+ nodes.push(end)
+
+ this.setSelection(nodes);
+ }else{
+ if( this.selection[ node.id ] && multi ) {
+ this.removeTreeNode( node );
+ } else if(multi) {
+ this.addTreeNode(node, true);
+ } else {
+ this.setSelection([node]);
+ this.anchor = node;
+ }
+ }
+ }
+ },
+
+ 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["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: [const] 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\" role=\"presentation\"\r\n\t><div dojoAttachPoint=\"rowNode\" class=\"dijitTreeRow\" role=\"presentation\" dojoAttachEvent=\"onmouseenter:_onMouseEnter, onmouseleave:_onMouseLeave, onclick:_onClick, ondblclick:_onDblClick\"\r\n\t\t><img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"expandoNode\" class=\"dijitTreeExpando\" role=\"presentation\"\r\n\t\t/><span dojoAttachPoint=\"expandoNodeText\" class=\"dijitExpandoText\" role=\"presentation\"\r\n\t\t></span\r\n\t\t><span dojoAttachPoint=\"contentNode\"\r\n\t\t\tclass=\"dijitTreeContent\" role=\"presentation\">\r\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"iconNode\" class=\"dijitIcon dijitTreeIcon\" role=\"presentation\"\r\n\t\t\t/><span dojoAttachPoint=\"labelNode\" class=\"dijitTreeLabel\" role=\"treeitem\" tabindex=\"-1\" aria-selected=\"false\" dojoAttachEvent=\"onfocus:_onLabelFocus\"></span>\r\n\t\t</span\r\n\t></div>\r\n\t<div dojoAttachPoint=\"containerNode\" class=\"dijitTreeContainer\" role=\"presentation\" style=\"display: none;\"></div>\r\n</div>\r\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"}
+ }),
+
+ buildRendering: 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);
+ }
+
+ //aria-selected should be false on all selectable elements.
+ this.setSelected(false);
+ },
+
+ _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.
+
+ // 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);
+ });
+
+ this._set("indent", indent);
+ },
+
+ 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";
+ var oldCls = this[clsName];
+
+ this[clsName] = this.tree["get" + upper + "Class"](item, this.isExpanded);
+ dojo.replaceClass(this[nodeName], this[clsName] || "", oldCls || "");
+
+ 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.replaceClass(this.expandoNode, styles[idx], styles);
+
+ // 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");
+ if(this.tree.showRoot || this !== this.tree.rootNode){
+ 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
+ },
+
+ getTreePath: function(){
+ var node = this;
+ var path = [];
+ while(node && node !== this.tree.rootNode){
+ path.unshift(node.item);
+ node = node.getParent();
+ }
+ path.unshift(this.tree.rootNode.item);
+
+ return path;
+ },
+
+ getIdentity: function() {
+ return this.tree.model.getIdentity(this.item);
+ },
+
+ 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"],
+
+ // paths: String[][] or Item[][]
+ // Full paths from rootNode to selected nodes expressed as array of items or array of ids.
+ // Since setting the paths may be asynchronous (because ofwaiting on dojo.data), set("paths", ...)
+ // returns a Deferred to indicate when the set is complete.
+ paths: [],
+
+ // path: String[] or Item[]
+ // Backward compatible singular variant of paths.
+ path: [],
+
+ // selectedItems: [readonly] Item[]
+ // The currently selected items in this tree.
+ // This property can only be set (via set('selectedItems', ...)) when that item is already
+ // visible in the tree. (I.e. the tree has already been expanded to show that node.)
+ // Should generally use `paths` attribute to set the selected items instead.
+ selectedItems: null,
+
+ // selectedItem: [readonly] Item
+ // Backward compatible singular variant of selectedItems.
+ 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\" role=\"tree\"\r\n\tdojoAttachEvent=\"onkeypress:_onKeyPress\">\r\n\t<div class=\"dijitInline dijitTreeIndent\" style=\"position: absolute; top: -9999px\" dojoAttachPoint=\"indentDetector\"></div>\r\n</div>\r\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".
+ // Default of "dijit.tree._dndSelector" handles selection only (no actual DnD).
+ dndController: "dijit.tree._dndSelector",
+
+ // 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";
+ // if root is not visible, move tree role to the invisible
+ // root node's containerNode, see #12135
+ dijit.setWaiRole(this.domNode, 'presentation');
+
+ dijit.setWaiRole(rn.labelNode, 'presentation');
+ dijit.setWaiRole(rn.containerNode, 'tree');
+ }
+ 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){
+ this.set('selectedItems', [item]);
+ },
+
+ _setSelectedItemsAttr: function(/*dojo.data.Items or ids*/ items){
+ // summary:
+ // Select tree nodes related to passed items.
+ // WARNING: if model use multi-parented items or desired tree node isn't already loaded
+ // behavior is undefined. Use set('paths', ...) instead.
+ var tree = this;
+ this._loadDeferred.addCallback( dojo.hitch(this, function(){
+ var identities = dojo.map(items, function(item){
+ return (!item || dojo.isString(item)) ? item : tree.model.getIdentity(item);
+ });
+ var nodes = [];
+ dojo.forEach(identities, function(id){
+ nodes = nodes.concat(tree._itemNodesMap[id] || []);
+ });
+ this.set('selectedNodes', nodes);
+ }));
+ },
+
+ _setPathAttr: function(/*Item[] || String[]*/ path){
+ // summary:
+ // Singular variant of _setPathsAttr
+ if(path.length) {
+ return this.set("paths", [path]);
+ } else {
+ //Empty list is interpreted as "select nothing"
+ return this.set("paths", []);
+ }
+ },
+
+ _setPathsAttr: function(/*Item[][] || String[][]*/ paths){
+ // summary:
+ // Select the tree nodes identified by passed paths.
+ // paths:
+ // Array of arrays of items or item id's
+ // returns:
+ // Deferred to indicate when the set is complete
+ var tree = this;
+
+ // We may need to wait for some nodes to expand, so setting
+ // each path will involve a Deferred. We bring those deferreds
+ // together witha DeferredList.
+ return new dojo.DeferredList(dojo.map(paths, function(path){
+ var d = new dojo.Deferred();
+
+ // normalize path to use identity
+ path = dojo.map(path, function(item){
+ return dojo.isString(item) ? item : tree.model.getIdentity(item);
+ });
+
+ if(path.length){
+ // Wait for the tree to load, if it hasn't already.
+ tree._loadDeferred.addCallback(function(){ selectPath(path, [tree.rootNode], d); });
+ }else{
+ d.errback("Empty path");
+ }
+ return d;
+ })).addCallback(setNodes);
+
+ function selectPath(path, nodes, def){
+ // Traverse path; the next path component should be among "nodes".
+ var nextPath = path.shift();
+ var nextNode = dojo.filter(nodes, function(node){
+ return node.getIdentity() == nextPath;
+ })[0];
+ if(!!nextNode){
+ if(path.length){
+ tree._expandNode(nextNode).addCallback(function(){ selectPath(path, nextNode.getChildren(), def); });
+ }else{
+ //Successfully reached the end of this path
+ def.callback(nextNode);
+ }
+ } else {
+ def.errback("Could not expand path at " + nextPath);
+ }
+ }
+
+ function setNodes(newNodes){
+ //After all expansion is finished, set the selection to
+ //the set of nodes successfully found.
+ tree.set("selectedNodes", dojo.map(
+ dojo.filter(newNodes,function(x){return x[0];}),
+ function(x){return x[1];}));
+ }
+ },
+
+ _setSelectedNodeAttr: function(node){
+ this.set('selectedNodes', [node]);
+ },
+ _setSelectedNodesAttr: function(nodes){
+ this._loadDeferred.addCallback( dojo.hitch(this, function(){
+ this.dndController.setSelection(nodes);
+ }));
+ },
+
+
+ ////////////// 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" && key != " "){ // 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";
+ //On WebKit based browsers, the combination ctrl-enter
+ //does not get passed through. To allow accessible
+ //multi-select on those browsers, the space key is
+ //also used for selection.
+ map[dk.SPACE]= map[" "] = "_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){
+ this._publish("execute", { item: message.item, node: message.node } );
+ this.dndController.userSelect(message.node, dojo.isCopyKey( message.evt ), message.evt.shiftKey);
+ this.onClick(message.item, message.node, message.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);
+ }
+ }
+ },
+
+ isExpandoNode: function(node, widget){
+ // summary:
+ // check whether a dom node is the expandoNode for a particular TreeNode widget
+ return dojo.isDescendant(node, widget.expandoNode);
+ },
+ _onClick: function(/*TreeNode*/ nodeWidget, /*Event*/ e){
+ // summary:
+ // Translates click events into commands for the controller to process
+
+ var domElement = e.target,
+ isExpandoClick = this.isExpandoNode(domElement, nodeWidget);
+
+ 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);
+ }
+ 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);
+ }
+ 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);
+ },
+
+ _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);
+ }
+
+ // 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._getMarginSize(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["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|Function
+ // Class name (or reference to the Class) for Editor widget
+ editor: "dijit.form.TextBox",
+
+ // editorWrapper: String|Function
+ // Class name (or reference to the Class) 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: {},
+
+ // disabled: Boolean
+ // If true, clicking the InlineEditBox to edit it will have no effect.
+ disabled: false,
+
+ 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.
+ dijit.setWaiState(this.domNode, "disabled", disabled);
+ if(disabled){
+ this.displayNode.removeAttribute("tabIndex");
+ }else{
+ this.displayNode.setAttribute("tabIndex", 0);
+ }
+ dojo.toggleClass(this.displayNode, "dijitInlineEditBoxDisplayModeDisabled", disabled);
+ this._set("disabled", 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 = typeof this.editorWrapper == "string" ? dojo.getObject(this.editorWrapper) : 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._destroyed){
+ 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
+
+ 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.
+
+ val = dojo.trim(val);
+ var renderVal = this.renderAsHtml ? val : val.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;").replace(/\n/g, "<br>");
+ this.displayNode.innerHTML = renderVal || this.noValueIndicator;
+ this._set("value", val);
+
+ if(this._started){
+ // tell the world that we have changed
+ setTimeout(dojo.hitch(this, "onChange", val), 0); // setTimeout prevents browser freeze for long-running event handlers
+ }
+ },
+
+ 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 data-dojo-attach-point=\"editNode\" role=\"presentation\" style=\"position: absolute; visibility:hidden\" class=\"dijitReset dijitInline\"\r\n\tdata-dojo-attach-event=\"onkeypress: _onKeyPress\"\r\n\t><span data-dojo-attach-point=\"editorPlaceholder\"></span\r\n\t><span data-dojo-attach-point=\"buttonContainer\"\r\n\t\t><button data-dojo-type=\"dijit.form.Button\" data-dojo-props=\"label: '${buttonSave}', 'class': 'saveButton'\"\r\n\t\t\tdata-dojo-attach-point=\"saveButton\" data-dojo-attach-event=\"onClick:save\"></button\r\n\t\t><button data-dojo-type=\"dijit.form.Button\" data-dojo-props=\"label: '${buttonCancel}', 'class': 'cancelButton'\"\r\n\t\t\tdata-dojo-attach-point=\"cancelButton\" data-dojo-attach-event=\"onClick:cancel\"></button\r\n\t></span\r\n></span>\r\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);
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ // Create edit widget in place in the template
+ var cls = typeof this.editor == "string" ? dojo.getObject(this.editor) : 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;
+ 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);
+ }
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ var ew = this.editWidget;
+
+ if(this.inlineEditBox.autoSave){
+ // 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 ew){
+ 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["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, dijit.layout._ContentPaneResizeMixin],
+ {
+ // 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: remove in 2.0, no longer necessary with data-dojo-params
+ 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.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["dijit.form.ComboButton"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.ComboButton"] = true;
+dojo.provide("dijit.form.ComboButton");
+
+
+
+
+}
+
+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\" role=\"presentation\"\r\n\t><input\r\n\t \t${!nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\r\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\r\n\t\tdojoAttachPoint=\"focusNode\"\r\n\t \tdojoAttachEvent=\"onclick:_onClick\"\r\n/></div>\r\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, get('value') will return either the string or false depending on
+ // whether or not the checkbox is checked.
+ //
+ // set('value', string) will check the checkbox and change the value to the
+ // specified string
+ //
+ // set('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._set("readOnly", value);
+ dojo.attr(this.focusNode, 'readOnly', value);
+ dijit.setWaiState(this.focusNode, "readonly", value);
+ },
+
+ _setValueAttr: function(/*String|Boolean*/ newValue, /*Boolean*/ priorityChange){
+ // summary:
+ // Handler for value= attribute to constructor, and also calls to
+ // set('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._set("value", newValue);
+ dojo.attr(this.focusNode, 'value', newValue);
+ newValue = true;
+ }
+ if(this._created){
+ this.set('checked', newValue, priorityChange);
+ }
+ },
+ _getValueAttr: function(){
+ // summary:
+ // Hook so get('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._set("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){
+ dojo.stopEvent(e);
+ 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.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["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.getObject("cldr.monetary", true, dojo);
+
+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
+};
+
+}
+
+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.getObject("currency", true, dojo);
+
+/*=====
+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: ""
+});
+=====*/
+
+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));
+};
+
+}
+
+if(!dojo._hasResource["dijit.form.NumberTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.NumberTextBox"] = true;
+dojo.provide("dijit.form.NumberTextBox");
+
+
+
+
+
+/*=====
+dojo.declare(
+ "dijit.form.NumberTextBox.__Constraints",
+ [dijit.form.RangeBoundTextBox.__Constraints, dojo.number.__FormatOptions, dojo.number.__ParseOptions], {
+ // summary:
+ // Specifies both the rules on valid/invalid values (minimum, maximum,
+ // number of required decimal places), and also formatting options for
+ // displaying the value when the field is not focused.
+ // example:
+ // Minimum/maximum:
+ // To specify a field between 0 and 120:
+ // | {min:0,max:120}
+ // To specify a field that must be an integer:
+ // | {fractional:false}
+ // To specify a field where 0 to 3 decimal places are allowed on input:
+ // | {places:'0,3'}
+});
+=====*/
+
+dojo.declare("dijit.form.NumberTextBoxMixin",
+ null,
+ {
+ // summary:
+ // A mixin for all number textboxes
+ // tags:
+ // protected
+
+ // Override ValidationTextBox.regExpGen().... we use a reg-ex generating function rather
+ // than a straight regexp to deal with locale (plus formatting options too?)
+ regExpGen: dojo.number.regexp,
+
+ /*=====
+ // constraints: dijit.form.NumberTextBox.__Constraints
+ // Despite the name, this parameter specifies both constraints on the input
+ // (including minimum/maximum allowed values) as well as
+ // formatting options like places (the number of digits to display after
+ // the decimal point). See `dijit.form.NumberTextBox.__Constraints` for details.
+ constraints: {},
+ ======*/
+
+ // value: Number
+ // The value of this NumberTextBox as a Javascript Number (i.e., not a String).
+ // If the displayed value is blank, the value is NaN, and if the user types in
+ // an gibberish value (like "hello world"), the value is undefined
+ // (i.e. get('value') returns undefined).
+ //
+ // Symmetrically, set('value', NaN) will clear the displayed value,
+ // whereas set('value', undefined) will have no effect.
+ value: NaN,
+
+ // editOptions: [protected] Object
+ // Properties to mix into constraints when the value is being edited.
+ // This is here because we edit the number in the format "12345", which is
+ // different than the display value (ex: "12,345")
+ editOptions: { pattern: '#.######' },
+
+ /*=====
+ _formatter: function(value, options){
+ // summary:
+ // _formatter() is called by format(). It's the base routine for formatting a number,
+ // as a string, for example converting 12345 into "12,345".
+ // value: Number
+ // The number to be converted into a string.
+ // options: dojo.number.__FormatOptions?
+ // Formatting options
+ // tags:
+ // protected extension
+
+ return "12345"; // String
+ },
+ =====*/
+ _formatter: dojo.number.format,
+
+ _setConstraintsAttr: function(/*Object*/ constraints){
+ var places = typeof constraints.places == "number"? constraints.places : 0;
+ if(places){ places++; } // decimal rounding errors take away another digit of precision
+ if(typeof constraints.max != "number"){
+ constraints.max = 9 * Math.pow(10, 15-places);
+ }
+ if(typeof constraints.min != "number"){
+ constraints.min = -9 * Math.pow(10, 15-places);
+ }
+ this.inherited(arguments, [ constraints ]);
+ if(this.focusNode && this.focusNode.value && !isNaN(this.value)){
+ this.set('value', this.value);
+ }
+ },
+
+ _onFocus: function(){
+ if(this.disabled){ return; }
+ var val = this.get('value');
+ if(typeof val == "number" && !isNaN(val)){
+ var formattedValue = this.format(val, this.constraints);
+ if(formattedValue !== undefined){
+ this.textbox.value = formattedValue;
+ }
+ }
+ this.inherited(arguments);
+ },
+
+ format: function(/*Number*/ value, /*dojo.number.__FormatOptions*/ constraints){
+ // summary:
+ // Formats the value as a Number, according to constraints.
+ // tags:
+ // protected
+
+ var formattedValue = String(value);
+ if(typeof value != "number"){ return formattedValue; }
+ if(isNaN(value)){ return ""; }
+ // check for exponential notation that dojo.number.format chokes on
+ if(!("rangeCheck" in this && this.rangeCheck(value, constraints)) && constraints.exponent !== false && /\de[-+]?\d/i.test(formattedValue)){
+ return formattedValue;
+ }
+ if(this.editOptions && this._focused){
+ constraints = dojo.mixin({}, constraints, this.editOptions);
+ }
+ return this._formatter(value, constraints);
+ },
+
+ /*=====
+ _parser: function(value, constraints){
+ // summary:
+ // Parses the string value as a Number, according to constraints.
+ // value: String
+ // String representing a number
+ // constraints: dojo.number.__ParseOptions
+ // Formatting options
+ // tags:
+ // protected
+
+ return 123.45; // Number
+ },
+ =====*/
+ _parser: dojo.number.parse,
+
+ parse: function(/*String*/ value, /*dojo.number.__FormatOptions*/ constraints){
+ // summary:
+ // Replacable function to convert a formatted string to a number value
+ // tags:
+ // protected extension
+
+ var v = this._parser(value, dojo.mixin({}, constraints, (this.editOptions && this._focused) ? this.editOptions : {}));
+ if(this.editOptions && this._focused && isNaN(v)){
+ v = this._parser(value, constraints); // parse w/o editOptions: not technically needed but is nice for the user
+ }
+ return v;
+ },
+
+ _getDisplayedValueAttr: function(){
+ var v = this.inherited(arguments);
+ return isNaN(v) ? this.textbox.value : v;
+ },
+
+ filter: function(/*Number*/ value){
+ // summary:
+ // This is called with both the display value (string), and the actual value (a number).
+ // When called with the actual value it does corrections so that '' etc. are represented as NaN.
+ // Otherwise it dispatches to the superclass's filter() method.
+ //
+ // See `dijit.form.TextBox.filter` for more details.
+ return (value === null || value === '' || value === undefined) ? NaN : this.inherited(arguments); // set('value', null||''||undefined) should fire onChange(NaN)
+ },
+
+ serialize: function(/*Number*/ value, /*Object?*/ options){
+ // summary:
+ // Convert value (a Number) into a canonical string (ie, how the number literal is written in javascript/java/C/etc.)
+ // tags:
+ // protected
+ return (typeof value != "number" || isNaN(value)) ? '' : this.inherited(arguments);
+ },
+
+ _setBlurValue: function(){
+ var val = dojo.hitch(dojo.mixin({}, this, { _focused: true }), "get")('value'); // parse with editOptions
+ this._setValueAttr(val, true);
+ },
+
+ _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
+ // summary:
+ // Hook so set('value', ...) works.
+ if(value !== undefined && formattedValue === undefined){
+ formattedValue = String(value);
+ if(typeof value == "number"){
+ if(isNaN(value)){ formattedValue = '' }
+ // check for exponential notation that dojo.number.format chokes on
+ else if(("rangeCheck" in this && this.rangeCheck(value, this.constraints)) || this.constraints.exponent === false || !/\de[-+]?\d/i.test(formattedValue)){
+ formattedValue = undefined; // lets format comnpute a real string value
+ }
+ }else if(!value){ // 0 processed in if branch above, ''|null|undefined flow thru here
+ formattedValue = '';
+ value = NaN;
+ }else{ // non-numeric values
+ value = undefined;
+ }
+ }
+ this.inherited(arguments, [value, priorityChange, formattedValue]);
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // Hook so get('value') works.
+ // Returns Number, NaN for '', or undefined for unparsable text
+ var v = this.inherited(arguments); // returns Number for all values accepted by parse() or NaN for all other displayed values
+
+ // If the displayed value of the textbox is gibberish (ex: "hello world"), this.inherited() above
+ // returns NaN; this if() branch converts the return value to undefined.
+ // Returning undefined prevents user text from being overwritten when doing _setValueAttr(_getValueAttr()).
+ // A blank displayed value is still returned as NaN.
+ if(isNaN(v) && this.textbox.value !== ''){
+ if(this.constraints.exponent !== false && /\de[-+]?\d/i.test(this.textbox.value) && (new RegExp("^"+dojo.number._realNumberRegexp(dojo.mixin({}, this.constraints))+"$").test(this.textbox.value))){ // check for exponential notation that parse() rejected (erroneously?)
+ var n = Number(this.textbox.value);
+ return isNaN(n) ? undefined : n; // return exponential Number or undefined for random text (may not be possible to do with the above RegExp check)
+ }else{
+ return undefined; // gibberish
+ }
+ }else{
+ return v; // Number or NaN for ''
+ }
+ },
+
+ isValid: function(/*Boolean*/ isFocused){
+ // Overrides dijit.form.RangeBoundTextBox.isValid to check that the editing-mode value is valid since
+ // it may not be formatted according to the regExp vaidation rules
+ if(!this._focused || this._isEmpty(this.textbox.value)){
+ return this.inherited(arguments);
+ }else{
+ var v = this.get('value');
+ if(!isNaN(v) && this.rangeCheck(v, this.constraints)){
+ if(this.constraints.exponent !== false && /\de[-+]?\d/i.test(this.textbox.value)){ // exponential, parse doesn't like it
+ return true; // valid exponential number in range
+ }else{
+ return this.inherited(arguments);
+ }
+ }else{
+ return false;
+ }
+ }
+ }
+ }
+);
+
+dojo.declare("dijit.form.NumberTextBox",
+ [dijit.form.RangeBoundTextBox,dijit.form.NumberTextBoxMixin],
+ {
+ // summary:
+ // A TextBox for entering numbers, with formatting and range checking
+ // description:
+ // NumberTextBox is a textbox for entering and displaying numbers, supporting
+ // the following main features:
+ //
+ // 1. Enforce minimum/maximum allowed values (as well as enforcing that the user types
+ // a number rather than a random string)
+ // 2. NLS support (altering roles of comma and dot as "thousands-separator" and "decimal-point"
+ // depending on locale).
+ // 3. Separate modes for editing the value and displaying it, specifically that
+ // the thousands separator character (typically comma) disappears when editing
+ // but reappears after the field is blurred.
+ // 4. Formatting and constraints regarding the number of places (digits after the decimal point)
+ // allowed on input, and number of places displayed when blurred (see `constraints` parameter).
+
+ baseClass: "dijitTextBox dijitNumberTextBox"
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit.form.CurrencyTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.CurrencyTextBox"] = true;
+dojo.provide("dijit.form.CurrencyTextBox");
+
+
+
+
+
+/*=====
+dojo.declare(
+ "dijit.form.CurrencyTextBox.__Constraints",
+ [dijit.form.NumberTextBox.__Constraints, dojo.currency.__FormatOptions, dojo.currency.__ParseOptions], {
+ // summary:
+ // Specifies both the rules on valid/invalid values (minimum, maximum,
+ // number of required decimal places), and also formatting options for
+ // displaying the value when the field is not focused (currency symbol,
+ // etc.)
+ // description:
+ // Follows the pattern of `dijit.form.NumberTextBox.constraints`.
+ // In general developers won't need to set this parameter
+ // example:
+ // To ensure that the user types in the cents (for example, 1.00 instead of just 1):
+ // | {fractional:true}
+});
+=====*/
+
+dojo.declare(
+ "dijit.form.CurrencyTextBox",
+ dijit.form.NumberTextBox,
+ {
+ // summary:
+ // A validating currency textbox
+ // description:
+ // CurrencyTextBox is similar to `dijit.form.NumberTextBox` but has a few
+ // extra features related to currency:
+ //
+ // 1. After specifying the currency type (american dollars, euros, etc.) it automatically
+ // sets parse/format options such as how many decimal places to show.
+ // 2. The currency mark (dollar sign, euro mark, etc.) is displayed when the field is blurred
+ // but erased during editing, so that the user can just enter a plain number.
+
+ // currency: [const] String
+ // the [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD"
+ currency: "",
+
+ /*=====
+ // constraints: dijit.form.CurrencyTextBox.__Constraints
+ // Despite the name, this parameter specifies both constraints on the input
+ // (including minimum/maximum allowed values) as well as
+ // formatting options. See `dijit.form.CurrencyTextBox.__Constraints` for details.
+ constraints: {},
+ ======*/
+
+ baseClass: "dijitTextBox dijitCurrencyTextBox",
+
+ // Override regExpGen ValidationTextBox.regExpGen().... we use a reg-ex generating function rather
+ // than a straight regexp to deal with locale (plus formatting options too?)
+ regExpGen: function(constraints){
+ // if focused, accept either currency data or NumberTextBox format
+ return '(' + (this._focused? this.inherited(arguments, [ dojo.mixin({}, constraints, this.editOptions) ]) + '|' : '')
+ + dojo.currency.regexp(constraints) + ')';
+ },
+
+ // Override NumberTextBox._formatter to deal with currencies, ex: converts "123.45" to "$123.45"
+ _formatter: dojo.currency.format,
+
+ _parser: dojo.currency.parse,
+
+ parse: function(/*String*/ value, /*Object*/ constraints){
+ // summary:
+ // Parses string value as a Currency, according to the constraints object
+ // tags:
+ // protected extension
+ var v = this.inherited(arguments);
+ if(isNaN(v) && /\d+/.test(value)){ // currency parse failed, but it could be because they are using NumberTextBox format so try its parse
+ v = dojo.hitch(dojo.mixin({}, this, { _parser: dijit.form.NumberTextBox.prototype._parser }), "inherited")(arguments);
+ }
+ return v;
+ },
+
+ _setConstraintsAttr: function(/*Object*/ constraints){
+ if(!constraints.currency && this.currency){
+ constraints.currency = this.currency;
+ }
+ this.inherited(arguments, [ dojo.currency._mixInDefaults(dojo.mixin(constraints, { exponent: false })) ]); // get places
+ }
+ }
+);
+
+}
+
+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.getObject("cldr.supplemental", true, dojo);
+
+dojo.cldr.supplemental.getFirstDayOfWeek = function(/*String?*/locale){
+// summary: Returns a zero-based index for first day of the week
+// description:
+// Returns a zero-based index for first day of the week, as used by the local (Gregorian) calendar.
+// e.g. Sunday (returns 0), or Monday (returns 1)
+
+ // from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/firstDay
+ var firstDay = {/*default is 1=Monday*/
+ mv:5,
+ ae:6,af:6,bh:6,dj:6,dz:6,eg:6,er:6,et:6,iq:6,ir:6,jo:6,ke:6,kw:6,
+ ly:6,ma:6,om:6,qa:6,sa:6,sd:6,so:6,sy: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,
+ il:0,'in':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,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._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;
+};
+
+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}*/
+};
+
+}
+
+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.getObject("date", true, dojo);
+
+/*=====
+dojo.date = {
+ // summary: Date manipulation utilities
+}
+=====*/
+
+dojo.date.getDaysInMonth = function(/*Date*/dateObject){
+ // summary:
+ // Returns the number of days in the month used by dateObject
+ var month = dateObject.getMonth();
+ var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+ if(month == 1 && dojo.date.isLeapYear(dateObject)){ return 29; } // Number
+ return days[month]; // Number
+};
+
+dojo.date.isLeapYear = function(/*Date*/dateObject){
+ // summary:
+ // Determines if the year of the dateObject is a leap year
+ // description:
+ // Leap years are years with an additional day YYYY-02-29, where the
+ // year number is a multiple of four with the following exception: If
+ // a year is a multiple of 100, then it is only a leap year if it is
+ // also a multiple of 400. For example, 1900 was not a leap year, but
+ // 2000 is one.
+
+ var year = dateObject.getFullYear();
+ return !(year%400) || (!(year%4) && !!(year%100)); // Boolean
+};
+
+// FIXME: This is not localized
+dojo.date.getTimezoneName = function(/*Date*/dateObject){
+ // summary:
+ // Get the user's time zone as provided by the browser
+ // dateObject:
+ // Needed because the timezone may vary with time (daylight savings)
+ // description:
+ // Try to get time zone info from toString or toLocaleString method of
+ // the Date object -- UTC offset is not a time zone. See
+ // http://www.twinsun.com/tz/tz-link.htm Note: results may be
+ // inconsistent across browsers.
+
+ var str = dateObject.toString(); // Start looking in toString
+ var tz = ''; // The result -- return empty string if nothing found
+ var match;
+
+ // First look for something in parentheses -- fast lookup, no regex
+ var pos = str.indexOf('(');
+ if(pos > -1){
+ tz = str.substring(++pos, str.indexOf(')'));
+ }else{
+ // If at first you don't succeed ...
+ // If IE knows about the TZ, it appears before the year
+ // Capital letters or slash before a 4-digit year
+ // at the end of string
+ var pat = /([A-Z\/]+) \d{4}$/;
+ if((match = str.match(pat))){
+ tz = match[1];
+ }else{
+ // Some browsers (e.g. Safari) glue the TZ on the end
+ // of toLocaleString instead of putting it in toString
+ str = dateObject.toLocaleString();
+ // Capital letters or slash -- end of string,
+ // after space
+ pat = / ([A-Z\/]+)$/;
+ if((match = str.match(pat))){
+ tz = match[1];
+ }
+ }
+ }
+
+ // Make sure it doesn't somehow end up return AM or PM
+ return (tz == 'AM' || tz == 'PM') ? '' : tz; // String
+};
+
+// Utility methods to do arithmetic calculations with Dates
+
+dojo.date.compare = function(/*Date*/date1, /*Date?*/date2, /*String?*/portion){
+ // summary:
+ // Compare two date objects by date, time, or both.
+ // description:
+ // Returns 0 if equal, positive if a > b, else negative.
+ // date1:
+ // Date object
+ // date2:
+ // Date object. If not specified, the current Date is used.
+ // portion:
+ // A string indicating the "date" or "time" portion of a Date object.
+ // Compares both "date" and "time" by default. One of the following:
+ // "date", "time", "datetime"
+
+ // Extra step required in copy for IE - see #3112
+ date1 = new Date(+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(/*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(/*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)
+};
+
+}
+
+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");
+
+
+
+
+
+
+
+
+dojo.getObject("date.locale", true, dojo);
+
+// Localization methods for Date. Honor local customs using locale-dependent dojo.cldr data.
+
+
+// Load the bundles containing localization information for
+// names and formats
+
+//NOTE: Everything in this module assumes Gregorian calendars.
+// Other calendars will be implemented in separate modules.
+
+(function(){
+ // Format a pattern without literals
+ function formatPattern(dateObject, bundle, 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 = options[timePeriod] || 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.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.regexp = function(/*dojo.date.locale.__FormatOptions?*/options){
+ // summary:
+ // Builds the regular needed to parse a localized date
+
+ return dojo.date.locale._parseInfo(options).regexp; // String
+};
+
+dojo.date.locale._parseInfo = function(/*dojo.date.locale.__FormatOptions?*/options){
+ options = options || {};
+ var locale = dojo.i18n.normalizeLocale(options.locale),
+ 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};
+};
+
+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
+
+ // remove non-printing bidi control chars from input and pattern
+ var controlChars = /[\u200E\u200F\u202A\u202E]/g,
+ info = dojo.date.locale._parseInfo(options),
+ tokens = info.tokens, bundle = info.bundle,
+ re = new RegExp("^" + info.regexp.replace(controlChars, "") + "$",
+ info.strict ? "" : "i"),
+ match = re.exec(value && value.replace(controlChars, ""));
+
+ 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 _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(''));
+}
+
+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.
+}
+})();
+
+(function(){
+var _customFormats = [];
+dojo.date.locale.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){
+ // summary:
+ // Add a reference to a bundle containing localized custom formats to be
+ // used by date/time formatting and parsing routines.
+ //
+ // description:
+ // The user may add custom localized formats where the bundle has properties following the
+ // same naming convention used by dojo.cldr: `dateFormat-xxxx` / `timeFormat-xxxx`
+ // The pattern string should match the format used by the CLDR.
+ // See dojo.date.locale.format() for details.
+ // The resources must be loaded by prior to use
+
+ _customFormats.push({pkg:packageName,name:bundleName});
+};
+
+dojo.date.locale._getGregorianBundle = function(/*String*/locale){
+ var gregorian = {};
+ dojo.forEach(_customFormats, function(desc){
+ var bundle = dojo.i18n.getLocalization(desc.pkg, desc.name, locale);
+ gregorian = dojo.mixin(gregorian, bundle);
+ }, this);
+ return gregorian; /*Object*/
+};
+})();
+
+dojo.date.locale.addCustomFormats("dojo.cldr","gregorian");
+
+dojo.date.locale.getNames = function(/*String*/item, /*String*/type, /*String?*/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(/*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
+};
+
+// 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(/*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
+};
+
+}
+
+if(!dojo._hasResource["dijit.Calendar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.Calendar"] = true;
+dojo.provide("dijit.Calendar");
+
+
+
+
+
+
+
+
+
+
+dojo.declare(
+ "dijit.Calendar",
+ [dijit._Widget, dijit._Templated, dijit._CssStateMixin],
+ {
+ // summary:
+ // A simple GUI for choosing a date in the context of a monthly calendar.
+ //
+ // description:
+ // A simple GUI for choosing a date in the context of a monthly calendar.
+ // This widget can't be used in a form because it doesn't serialize the date to an
+ // `<input>` field. For a form element, use dijit.form.DateTextBox instead.
+ //
+ // Note that the parser takes all dates attributes passed in the
+ // [RFC 3339 format](http://www.faqs.org/rfcs/rfc3339.html), e.g. `2005-06-30T08:05:00-07:00`
+ // so that they are serializable and locale-independent.
+ //
+ // example:
+ // | var calendar = new dijit.Calendar({}, dojo.byId("calendarNode"));
+ //
+ // example:
+ // | <div dojoType="dijit.Calendar"></div>
+
+ templateString: dojo.cache("dijit", "templates/Calendar.html", "<table cellspacing=\"0\" cellpadding=\"0\" class=\"dijitCalendarContainer\" role=\"grid\" dojoAttachEvent=\"onkeypress: _onKeyPress\" aria-labelledby=\"${id}_year\">\r\n\t<thead>\r\n\t\t<tr class=\"dijitReset dijitCalendarMonthContainer\" valign=\"top\">\r\n\t\t\t<th class='dijitReset dijitCalendarArrow' dojoAttachPoint=\"decrementMonth\">\r\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarDecrease\" role=\"presentation\"/>\r\n\t\t\t\t<span dojoAttachPoint=\"decreaseArrowNode\" class=\"dijitA11ySideArrow\">-</span>\r\n\t\t\t</th>\r\n\t\t\t<th class='dijitReset' colspan=\"5\">\r\n\t\t\t\t<div dojoType=\"dijit.form.DropDownButton\" dojoAttachPoint=\"monthDropDownButton\"\r\n\t\t\t\t\tid=\"${id}_mddb\" tabIndex=\"-1\">\r\n\t\t\t\t</div>\r\n\t\t\t</th>\r\n\t\t\t<th class='dijitReset dijitCalendarArrow' dojoAttachPoint=\"incrementMonth\">\r\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarIncrease\" role=\"presentation\"/>\r\n\t\t\t\t<span dojoAttachPoint=\"increaseArrowNode\" class=\"dijitA11ySideArrow\">+</span>\r\n\t\t\t</th>\r\n\t\t</tr>\r\n\t\t<tr>\r\n\t\t\t<th class=\"dijitReset dijitCalendarDayLabelTemplate\" role=\"columnheader\"><span class=\"dijitCalendarDayLabel\"></span></th>\r\n\t\t</tr>\r\n\t</thead>\r\n\t<tbody dojoAttachEvent=\"onclick: _onDayClick, onmouseover: _onDayMouseOver, onmouseout: _onDayMouseOut, onmousedown: _onDayMouseDown, onmouseup: _onDayMouseUp\" class=\"dijitReset dijitCalendarBodyContainer\">\r\n\t\t<tr class=\"dijitReset dijitCalendarWeekTemplate\" role=\"row\">\r\n\t\t\t<td class=\"dijitReset dijitCalendarDateTemplate\" role=\"gridcell\"><span class=\"dijitCalendarDateLabel\"></span></td>\r\n\t\t</tr>\r\n\t</tbody>\r\n\t<tfoot class=\"dijitReset dijitCalendarYearContainer\">\r\n\t\t<tr>\r\n\t\t\t<td class='dijitReset' valign=\"top\" colspan=\"7\">\r\n\t\t\t\t<h3 class=\"dijitCalendarYearLabel\">\r\n\t\t\t\t\t<span dojoAttachPoint=\"previousYearLabelNode\" class=\"dijitInline dijitCalendarPreviousYear\"></span>\r\n\t\t\t\t\t<span dojoAttachPoint=\"currentYearLabelNode\" class=\"dijitInline dijitCalendarSelectedYear\" id=\"${id}_year\"></span>\r\n\t\t\t\t\t<span dojoAttachPoint=\"nextYearLabelNode\" class=\"dijitInline dijitCalendarNextYear\"></span>\r\n\t\t\t\t</h3>\r\n\t\t\t</td>\r\n\t\t</tr>\r\n\t</tfoot>\r\n</table>\r\n"),
+ widgetsInTemplate: true,
+
+ // value: Date
+ // The currently selected Date, initially set to invalid date to indicate no selection.
+ value: new Date(""),
+ // TODO: for 2.0 make this a string (ISO format) rather than a Date
+
+ // datePackage: String
+ // JavaScript namespace to find Calendar routines. Uses Gregorian Calendar routines
+ // at dojo.date by default.
+ datePackage: "dojo.date",
+
+ // dayWidth: String
+ // How to represent the days of the week in the calendar header. See dojo.date.locale
+ dayWidth: "narrow",
+
+ // tabIndex: Integer
+ // Order fields are traversed when user hits the tab key
+ tabIndex: "0",
+
+ // currentFocus: Date
+ // Date object containing the currently focused date, or the date which would be focused
+ // if the calendar itself was focused. Also indicates which year and month to display,
+ // i.e. the current "page" the calendar is on.
+ currentFocus: new Date(),
+
+ baseClass:"dijitCalendar",
+
+ // Set node classes for various mouse events, see dijit._CssStateMixin for more details
+ cssStateNodes: {
+ "decrementMonth": "dijitCalendarArrow",
+ "incrementMonth": "dijitCalendarArrow",
+ "previousYearLabelNode": "dijitCalendarPreviousYear",
+ "nextYearLabelNode": "dijitCalendarNextYear"
+ },
+
+ _isValidDate: function(/*Date*/ value){
+ // summary:
+ // Runs various tests on the value, checking that it's a valid date, rather
+ // than blank or NaN.
+ // tags:
+ // private
+ return value && !isNaN(value) && typeof value == "object" &&
+ value.toString() != this.constructor.prototype.value.toString();
+ },
+
+ setValue: function(/*Date*/ value){
+ // summary:
+ // Deprecated. Use set('value', ...) instead.
+ // tags:
+ // deprecated
+ dojo.deprecated("dijit.Calendar:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
+ this.set('value', value);
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // Support get('value')
+
+ // this.value is set to 1AM, but return midnight, local time for back-compat
+ var value = new this.dateClassObj(this.value);
+ value.setHours(0, 0, 0, 0);
+
+ // If daylight savings pushes midnight to the previous date, fix the Date
+ // object to point at 1am so it will represent the correct day. See #9366
+ if(value.getDate() < this.value.getDate()){
+ value = this.dateFuncObj.add(value, "hour", 1);
+ }
+ return value;
+ },
+
+ _setValueAttr: function(/*Date|Number*/ value, /*Boolean*/ priorityChange){
+ // summary:
+ // Support set("value", ...)
+ // description:
+ // Set the current date and update the UI. If the date is disabled, the value will
+ // not change, but the display will change to the corresponding month.
+ // value:
+ // Either a Date or the number of seconds since 1970.
+ // tags:
+ // protected
+ if(value){
+ // convert from Number to Date, or make copy of Date object so that setHours() call below
+ // doesn't affect original value
+ value = new this.dateClassObj(value);
+ }
+ if(this._isValidDate(value)){
+ if(!this._isValidDate(this.value) || this.dateFuncObj.compare(value, this.value)){
+ value.setHours(1, 0, 0, 0); // round to nearest day (1am to avoid issues when DST shift occurs at midnight, see #8521, #9366)
+
+ if(!this.isDisabledDate(value, this.lang)){
+ this._set("value", value);
+
+ // Set focus cell to the new value. Arguably this should only happen when there isn't a current
+ // focus point. This will also repopulate the grid, showing the new selected value (and possibly
+ // new month/year).
+ this.set("currentFocus", value);
+
+ if(priorityChange || typeof priorityChange == "undefined"){
+ this.onChange(this.get('value'));
+ this.onValueSelected(this.get('value')); // remove in 2.0
+ }
+ }
+ }
+ }else{
+ // clear value, and repopulate grid (to deselect the previously selected day) without changing currentFocus
+ this._set("value", null);
+ this.set("currentFocus", this.currentFocus);
+ }
+ },
+
+ _setText: function(node, text){
+ // summary:
+ // This just sets the content of node to the specified text.
+ // Can't do "node.innerHTML=text" because of an IE bug w/tables, see #3434.
+ // tags:
+ // private
+ while(node.firstChild){
+ node.removeChild(node.firstChild);
+ }
+ node.appendChild(dojo.doc.createTextNode(text));
+ },
+
+ _populateGrid: function(){
+ // summary:
+ // Fills in the calendar grid with each day (1-31)
+ // tags:
+ // private
+
+ var month = new this.dateClassObj(this.currentFocus);
+ month.setDate(1);
+
+ var firstDay = month.getDay(),
+ daysInMonth = this.dateFuncObj.getDaysInMonth(month),
+ daysInPreviousMonth = this.dateFuncObj.getDaysInMonth(this.dateFuncObj.add(month, "month", -1)),
+ today = new this.dateClassObj(),
+ dayOffset = dojo.cldr.supplemental.getFirstDayOfWeek(this.lang);
+ if(dayOffset > firstDay){ dayOffset -= 7; }
+
+ // Iterate through dates in the calendar and fill in date numbers and style info
+ dojo.query(".dijitCalendarDateTemplate", this.domNode).forEach(function(template, i){
+ i += dayOffset;
+ var date = new this.dateClassObj(month),
+ number, clazz = "dijitCalendar", adj = 0;
+
+ if(i < firstDay){
+ number = daysInPreviousMonth - firstDay + i + 1;
+ adj = -1;
+ clazz += "Previous";
+ }else if(i >= (firstDay + daysInMonth)){
+ number = i - firstDay - daysInMonth + 1;
+ adj = 1;
+ clazz += "Next";
+ }else{
+ number = i - firstDay + 1;
+ clazz += "Current";
+ }
+
+ if(adj){
+ date = this.dateFuncObj.add(date, "month", adj);
+ }
+ date.setDate(number);
+
+ if(!this.dateFuncObj.compare(date, today, "date")){
+ clazz = "dijitCalendarCurrentDate " + clazz;
+ }
+
+ if(this._isSelectedDate(date, this.lang)){
+ clazz = "dijitCalendarSelectedDate " + clazz;
+ }
+
+ if(this.isDisabledDate(date, this.lang)){
+ clazz = "dijitCalendarDisabledDate " + clazz;
+ }
+
+ var clazz2 = this.getClassForDate(date, this.lang);
+ if(clazz2){
+ clazz = clazz2 + " " + clazz;
+ }
+
+ template.className = clazz + "Month dijitCalendarDateTemplate";
+ template.dijitDateValue = date.valueOf(); // original code
+ dojo.attr(template, "dijitDateValue", date.valueOf()); // so I can dojo.query() it
+ var label = dojo.query(".dijitCalendarDateLabel", template)[0],
+ text = date.getDateLocalized ? date.getDateLocalized(this.lang) : date.getDate();
+ this._setText(label, text);
+ }, this);
+
+ // Repopulate month drop down list based on current year.
+ // Need to do this to hide leap months in Hebrew calendar.
+ var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month);
+ this.monthDropDownButton.dropDown.set("months", monthNames);
+
+ // Set name of current month and also fill in spacer element with all the month names
+ // (invisible) so that the maximum width will affect layout. But not on IE6 because then
+ // the center <TH> overlaps the right <TH> (due to a browser bug).
+ this.monthDropDownButton.containerNode.innerHTML =
+ (dojo.isIE == 6 ? "" : "<div class='dijitSpacer'>" + this.monthDropDownButton.dropDown.domNode.innerHTML + "</div>") +
+ "<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>" + monthNames[month.getMonth()] + "</div>";
+
+ // Fill in localized prev/current/next years
+ var y = month.getFullYear() - 1;
+ var d = new this.dateClassObj();
+ dojo.forEach(["previous", "current", "next"], function(name){
+ d.setFullYear(y++);
+ this._setText(this[name+"YearLabelNode"],
+ this.dateLocaleModule.format(d, {selector:'year', locale:this.lang}));
+ }, this);
+ },
+
+ goToToday: function(){
+ // summary:
+ // Sets calendar's value to today's date
+ this.set('value', new this.dateClassObj());
+ },
+
+ constructor: function(/*Object*/args){
+ var dateClass = (args.datePackage && (args.datePackage != "dojo.date"))? args.datePackage + ".Date" : "Date";
+ this.dateClassObj = dojo.getObject(dateClass, false);
+ this.datePackage = args.datePackage || this.datePackage;
+ this.dateFuncObj = dojo.getObject(this.datePackage, false);
+ this.dateLocaleModule = dojo.getObject(this.datePackage + ".locale", false);
+ },
+
+ postMixInProperties: function(){
+ // Parser.instantiate sometimes passes in NaN for IE. Use default value in prototype instead.
+ // TODO: remove this for 2.0 (thanks to #11511)
+ if(isNaN(this.value)){ delete this.value; }
+
+ this.inherited(arguments);
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dojo.setSelectable(this.domNode, false);
+
+ var cloneClass = dojo.hitch(this, function(clazz, n){
+ var template = dojo.query(clazz, this.domNode)[0];
+ for(var i=0; i<n; i++){
+ template.parentNode.appendChild(template.cloneNode(true));
+ }
+ });
+
+ // clone the day label and calendar day templates 6 times to make 7 columns
+ cloneClass(".dijitCalendarDayLabelTemplate", 6);
+ cloneClass(".dijitCalendarDateTemplate", 6);
+
+ // now make 6 week rows
+ cloneClass(".dijitCalendarWeekTemplate", 5);
+
+ // insert localized day names in the header
+ var dayNames = this.dateLocaleModule.getNames('days', this.dayWidth, 'standAlone', this.lang);
+ var dayOffset = dojo.cldr.supplemental.getFirstDayOfWeek(this.lang);
+ dojo.query(".dijitCalendarDayLabel", this.domNode).forEach(function(label, i){
+ this._setText(label, dayNames[(i + dayOffset) % 7]);
+ }, this);
+
+ var dateObj = new this.dateClassObj(this.currentFocus);
+
+ this.monthDropDownButton.dropDown = new dijit.Calendar._MonthDropDown({
+ id: this.id + "_mdd",
+ onChange: dojo.hitch(this, "_onMonthSelect")
+ });
+
+ this.set('currentFocus', dateObj, false); // draw the grid to the month specified by currentFocus
+
+ // Set up repeating mouse behavior for increment/decrement of months/years
+ var _this = this;
+ var typematic = function(nodeProp, dateProp, adj){
+ _this._connects.push(
+ dijit.typematic.addMouseListener(_this[nodeProp], _this, function(count){
+ if(count >= 0){ _this._adjustDisplay(dateProp, adj); }
+ }, 0.8, 500)
+ );
+ };
+ typematic("incrementMonth", "month", 1);
+ typematic("decrementMonth", "month", -1);
+ typematic("nextYearLabelNode", "year", 1);
+ typematic("previousYearLabelNode", "year", -1);
+ },
+
+ _adjustDisplay: function(/*String*/ part, /*int*/ amount){
+ // summary:
+ // Moves calendar forwards or backwards by months or years
+ // part:
+ // "month" or "year"
+ // amount:
+ // Number of months or years
+ // tags:
+ // private
+ this._setCurrentFocusAttr(this.dateFuncObj.add(this.currentFocus, part, amount));
+ },
+
+ _setCurrentFocusAttr: function(/*Date*/ date, /*Boolean*/ forceFocus){
+ // summary:
+ // If the calendar currently has focus, then focuses specified date,
+ // changing the currently displayed month/year if necessary.
+ // If the calendar doesn't have focus, updates currently
+ // displayed month/year, and sets the cell that will get focus.
+ // forceFocus:
+ // If true, will focus() the cell even if calendar itself doesn't have focus
+
+ var oldFocus = this.currentFocus,
+ oldCell = oldFocus ? dojo.query("[dijitDateValue=" + oldFocus.valueOf() + "]", this.domNode)[0] : null;
+
+ // round specified value to nearest day (1am to avoid issues when DST shift occurs at midnight, see #8521, #9366)
+ date = new this.dateClassObj(date);
+ date.setHours(1, 0, 0, 0);
+
+ this._set("currentFocus", date);
+
+ // TODO: only re-populate grid when month/year has changed
+ this._populateGrid();
+
+ // set tabIndex=0 on new cell, and focus it (but only if Calendar itself is focused)
+ var newCell = dojo.query("[dijitDateValue=" + date.valueOf() + "]", this.domNode)[0];
+ newCell.setAttribute("tabIndex", this.tabIndex);
+ if(this._focused || forceFocus){
+ newCell.focus();
+ }
+
+ // set tabIndex=-1 on old focusable cell
+ if(oldCell && oldCell != newCell){
+ if(dojo.isWebKit){ // see #11064 about webkit bug
+ oldCell.setAttribute("tabIndex", "-1");
+ }else{
+ oldCell.removeAttribute("tabIndex");
+ }
+ }
+ },
+
+ focus: function(){
+ // summary:
+ // Focus the calendar by focusing one of the calendar cells
+ this._setCurrentFocusAttr(this.currentFocus, true);
+ },
+
+ _onMonthSelect: function(/*Number*/ newMonth){
+ // summary:
+ // Handler for when user selects a month from the drop down list
+ // tags:
+ // protected
+
+ // move to selected month, bounding by the number of days in the month
+ // (ex: dec 31 --> jan 28, not jan 31)
+ this.currentFocus = this.dateFuncObj.add(this.currentFocus, "month",
+ newMonth - this.currentFocus.getMonth());
+ this._populateGrid();
+ },
+
+ _onDayClick: function(/*Event*/ evt){
+ // summary:
+ // Handler for day clicks, selects the date if appropriate
+ // tags:
+ // protected
+ dojo.stopEvent(evt);
+ for(var node = evt.target; node && !node.dijitDateValue; node = node.parentNode);
+ if(node && !dojo.hasClass(node, "dijitCalendarDisabledDate")){
+ this.set('value', node.dijitDateValue);
+ }
+ },
+
+ _onDayMouseOver: function(/*Event*/ evt){
+ // summary:
+ // Handler for mouse over events on days, sets hovered style
+ // tags:
+ // protected
+
+ // event can occur on <td> or the <span> inside the td,
+ // set node to the <td>.
+ var node =
+ dojo.hasClass(evt.target, "dijitCalendarDateLabel") ?
+ evt.target.parentNode :
+ evt.target;
+
+ if(node && (node.dijitDateValue || node == this.previousYearLabelNode || node == this.nextYearLabelNode) ){
+ dojo.addClass(node, "dijitCalendarHoveredDate");
+ this._currentNode = node;
+ }
+ },
+
+ _onDayMouseOut: function(/*Event*/ evt){
+ // summary:
+ // Handler for mouse out events on days, clears hovered style
+ // tags:
+ // protected
+
+ if(!this._currentNode){ return; }
+
+ // if mouse out occurs moving from <td> to <span> inside <td>, ignore it
+ if(evt.relatedTarget && evt.relatedTarget.parentNode == this._currentNode){ return; }
+ var cls = "dijitCalendarHoveredDate";
+ if(dojo.hasClass(this._currentNode, "dijitCalendarActiveDate")) {
+ cls += " dijitCalendarActiveDate";
+ }
+ dojo.removeClass(this._currentNode, cls);
+ this._currentNode = null;
+ },
+
+ _onDayMouseDown: function(/*Event*/ evt){
+ var node = evt.target.parentNode;
+ if(node && node.dijitDateValue){
+ dojo.addClass(node, "dijitCalendarActiveDate");
+ this._currentNode = node;
+ }
+ },
+
+ _onDayMouseUp: function(/*Event*/ evt){
+ var node = evt.target.parentNode;
+ if(node && node.dijitDateValue){
+ dojo.removeClass(node, "dijitCalendarActiveDate");
+ }
+ },
+
+//TODO: use typematic
+ handleKey: function(/*Event*/ evt){
+ // summary:
+ // Provides keyboard navigation of calendar.
+ // description:
+ // Called from _onKeyPress() to handle keypress on a stand alone Calendar,
+ // and also from `dijit.form._DateTimeTextBox` to pass a keypress event
+ // from the `dijit.form.DateTextBox` to be handled in this widget
+ // returns:
+ // False if the key was recognized as a navigation key,
+ // to indicate that the event was handled by Calendar and shouldn't be propogated
+ // tags:
+ // protected
+ var dk = dojo.keys,
+ increment = -1,
+ interval,
+ newValue = this.currentFocus;
+ switch(evt.keyCode){
+ case dk.RIGHT_ARROW:
+ increment = 1;
+ //fallthrough...
+ case dk.LEFT_ARROW:
+ interval = "day";
+ if(!this.isLeftToRight()){ increment *= -1; }
+ break;
+ case dk.DOWN_ARROW:
+ increment = 1;
+ //fallthrough...
+ case dk.UP_ARROW:
+ interval = "week";
+ break;
+ case dk.PAGE_DOWN:
+ increment = 1;
+ //fallthrough...
+ case dk.PAGE_UP:
+ interval = evt.ctrlKey || evt.altKey ? "year" : "month";
+ break;
+ case dk.END:
+ // go to the next month
+ newValue = this.dateFuncObj.add(newValue, "month", 1);
+ // subtract a day from the result when we're done
+ interval = "day";
+ //fallthrough...
+ case dk.HOME:
+ newValue = new this.dateClassObj(newValue);
+ newValue.setDate(1);
+ break;
+ case dk.ENTER:
+ case dk.SPACE:
+ this.set("value", this.currentFocus);
+ break;
+ default:
+ return true;
+ }
+
+ if(interval){
+ newValue = this.dateFuncObj.add(newValue, interval, increment);
+ }
+
+ this._setCurrentFocusAttr(newValue);
+
+ return false;
+ },
+
+ _onKeyPress: function(/*Event*/ evt){
+ // summary:
+ // For handling keypress events on a stand alone calendar
+ if(!this.handleKey(evt)){
+ dojo.stopEvent(evt);
+ }
+ },
+
+ onValueSelected: function(/*Date*/ date){
+ // summary:
+ // Notification that a date cell was selected. It may be the same as the previous value.
+ // description:
+ // Formerly used by `dijit.form._DateTimeTextBox` (and thus `dijit.form.DateTextBox`)
+ // to get notification when the user has clicked a date. Now onExecute() (above) is used.
+ // tags:
+ // protected
+ },
+
+ onChange: function(/*Date*/ date){
+ // summary:
+ // Called only when the selected date has changed
+ },
+
+ _isSelectedDate: function(/*Date*/ dateObject, /*String?*/ locale){
+ // summary:
+ // Extension point so developers can subclass Calendar to
+ // support multiple (concurrently) selected dates
+ // tags:
+ // protected extension
+ return this._isValidDate(this.value) && !this.dateFuncObj.compare(dateObject, this.value, "date")
+ },
+
+ isDisabledDate: function(/*Date*/ dateObject, /*String?*/ locale){
+ // summary:
+ // May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend`
+ // tags:
+ // extension
+/*=====
+ return false; // Boolean
+=====*/
+ },
+
+ getClassForDate: function(/*Date*/ dateObject, /*String?*/ locale){
+ // summary:
+ // May be overridden to return CSS classes to associate with the date entry for the given dateObject,
+ // for example to indicate a holiday in specified locale.
+ // tags:
+ // extension
+
+/*=====
+ return ""; // String
+=====*/
+ }
+ }
+);
+
+dojo.declare("dijit.Calendar._MonthDropDown", [dijit._Widget, dijit._Templated], {
+ // summary:
+ // The month drop down
+
+ // months: String[]
+ // List of names of months, possibly w/some undefined entries for Hebrew leap months
+ // (ex: ["January", "February", undefined, "April", ...])
+ months: [],
+
+ templateString: "<div class='dijitCalendarMonthMenu dijitMenu' " +
+ "dojoAttachEvent='onclick:_onClick,onmouseover:_onMenuHover,onmouseout:_onMenuHover'></div>",
+
+ _setMonthsAttr: function(/*String[]*/ months){
+ this.domNode.innerHTML = dojo.map(months, function(month, idx){
+ return month ? "<div class='dijitCalendarMonthLabel' month='" + idx +"'>" + month + "</div>" : "";
+ }).join("");
+ },
+
+ _onClick: function(/*Event*/ evt){
+ this.onChange(dojo.attr(evt.target, "month"));
+ },
+
+ onChange: function(/*Number*/ month){
+ // summary:
+ // Callback when month is selected from drop down
+ },
+
+ _onMenuHover: function(evt){
+ dojo.toggleClass(evt.target, "dijitCalendarMonthLabelHover", evt.type == "mouseover");
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.form._DateTimeTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form._DateTimeTextBox"] = true;
+dojo.provide("dijit.form._DateTimeTextBox");
+
+
+
+
+
+
+
+
+new Date("X"); // workaround for #11279, new Date("") == NaN
+
+/*=====
+dojo.declare(
+ "dijit.form._DateTimeTextBox.__Constraints",
+ [dijit.form.RangeBoundTextBox.__Constraints, dojo.date.locale.__FormatOptions], {
+ // summary:
+ // Specifies both the rules on valid/invalid values (first/last date/time allowed),
+ // and also formatting options for how the date/time is displayed.
+ // example:
+ // To restrict to dates within 2004, displayed in a long format like "December 25, 2005":
+ // | {min:'2004-01-01',max:'2004-12-31', formatLength:'long'}
+});
+=====*/
+
+dojo.declare(
+ "dijit.form._DateTimeTextBox",
+ [ dijit.form.RangeBoundTextBox, dijit._HasDropDown ],
+ {
+ // summary:
+ // Base class for validating, serializable, range-bound date or time text box.
+
+ templateString: dojo.cache("dijit.form", "templates/DropDownBox.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\r\n\tid=\"widget_${id}\"\r\n\trole=\"combobox\"\r\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\r\n\t\tdojoAttachPoint=\"_buttonNode, _popupStateNode\" role=\"presentation\"\r\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t${_buttonInputDisabled}\r\n\t/></div\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\r\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\r\n\t/></div\r\n></div>\r\n"),
+
+ // hasDownArrow: [const] Boolean
+ // Set this textbox to display a down arrow button, to open the drop down list.
+ hasDownArrow: true,
+
+ // openOnClick: [const] Boolean
+ // Set to true to open drop down upon clicking anywhere on the textbox.
+ openOnClick: true,
+
+ /*=====
+ // constraints: dijit.form._DateTimeTextBox.__Constraints
+ // Despite the name, this parameter specifies both constraints on the input
+ // (including starting/ending dates/times allowed) as well as
+ // formatting options like whether the date is displayed in long (ex: December 25, 2005)
+ // or short (ex: 12/25/2005) format. See `dijit.form._DateTimeTextBox.__Constraints` for details.
+ constraints: {},
+ ======*/
+
+ // Override ValidationTextBox.regExpGen().... we use a reg-ex generating function rather
+ // than a straight regexp to deal with locale (plus formatting options too?)
+ regExpGen: dojo.date.locale.regexp,
+
+ // datePackage: String
+ // JavaScript namespace to find calendar routines. Uses Gregorian calendar routines
+ // at dojo.date, by default.
+ datePackage: "dojo.date",
+
+ // Override _FormWidget.compare() to work for dates/times
+ compare: function(/*Date*/ val1, /*Date*/ val2){
+ return dojo.date.compare(val1, val2, this._selector);
+ },
+
+ // flag to _HasDropDown to make drop down Calendar width == <input> width
+ forceWidth: true,
+
+ format: function(/*Date*/ value, /*dojo.date.locale.__FormatOptions*/ constraints){
+ // summary:
+ // Formats the value as a Date, according to specified locale (second argument)
+ // tags:
+ // protected
+ if(!value){ return ''; }
+ return this.dateLocaleModule.format(value, constraints);
+ },
+
+ "parse": function(/*String*/ value, /*dojo.date.locale.__FormatOptions*/ constraints){
+ // summary:
+ // Parses as string as a Date, according to constraints
+ // tags:
+ // protected
+
+ return this.dateLocaleModule.parse(value, constraints) || (this._isEmpty(value) ? null : undefined); // Date
+ },
+
+ // Overrides ValidationTextBox.serialize() to serialize a date in canonical ISO format.
+ serialize: function(/*anything*/ val, /*Object?*/ options){
+ if(val.toGregorian){
+ val = val.toGregorian();
+ }
+ return dojo.date.stamp.toISOString(val, options);
+ },
+
+ // dropDownDefaultValue: Date
+ // The default value to focus in the popupClass widget when the textbox value is empty.
+ dropDownDefaultValue : new Date(),
+
+ // value: Date
+ // The value of this widget as a JavaScript Date object. Use get("value") / set("value", val) to manipulate.
+ // When passed to the parser in markup, must be specified according to `dojo.date.stamp.fromISOString`
+ value: new Date(""), // value.toString()="NaN"
+
+ _blankValue: null, // used by filter() when the textbox is blank
+
+ // popupClass: [protected extension] String
+ // Name of the popup widget class used to select a date/time.
+ // Subclasses should specify this.
+ popupClass: "", // default is no popup = text only
+
+
+ // _selector: [protected extension] String
+ // Specifies constraints.selector passed to dojo.date functions, should be either
+ // "date" or "time".
+ // Subclass must specify this.
+ _selector: "",
+
+ constructor: function(/*Object*/ args){
+ var dateClass = args.datePackage ? args.datePackage + ".Date" : "Date";
+ this.dateClassObj = dojo.getObject(dateClass, false);
+ this.value = new this.dateClassObj("");
+
+ this.datePackage = args.datePackage || this.datePackage;
+ this.dateLocaleModule = dojo.getObject(this.datePackage + ".locale", false);
+ this.regExpGen = this.dateLocaleModule.regexp;
+ this._invalidDate = dijit.form._DateTimeTextBox.prototype.value.toString();
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ if(!this.hasDownArrow){
+ this._buttonNode.style.display = "none";
+ }
+
+ // If openOnClick is true, we basically just want to treat the whole widget as the
+ // button. We need to do that also if the actual drop down button will be hidden,
+ // so that there's a mouse method for opening the drop down.
+ if(this.openOnClick || !this.hasDownArrow){
+ this._buttonNode = this.domNode;
+ this.baseClass += " dijitComboBoxOpenOnClick";
+ }
+ },
+
+ _setConstraintsAttr: function(/*Object*/ constraints){
+ constraints.selector = this._selector;
+ constraints.fullYear = true; // see #5465 - always format with 4-digit years
+ var fromISO = dojo.date.stamp.fromISOString;
+ if(typeof constraints.min == "string"){ constraints.min = fromISO(constraints.min); }
+ if(typeof constraints.max == "string"){ constraints.max = fromISO(constraints.max); }
+ this.inherited(arguments, [constraints]);
+ },
+
+ _isInvalidDate: function(/*Date*/ value){
+ // summary:
+ // Runs various tests on the value, checking for invalid conditions
+ // tags:
+ // private
+ return !value || isNaN(value) || typeof value != "object" || value.toString() == this._invalidDate;
+ },
+
+ _setValueAttr: function(/*Date|String*/ value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
+ // summary:
+ // Sets the date on this textbox. Note: value can be a JavaScript Date literal or a string to be parsed.
+ if(value !== undefined){
+ if(typeof value == "string"){
+ value = dojo.date.stamp.fromISOString(value);
+ }
+ if(this._isInvalidDate(value)){
+ value = null;
+ }
+ if(value instanceof Date && !(this.dateClassObj instanceof Date)){
+ value = new this.dateClassObj(value);
+ }
+ }
+ this.inherited(arguments, [value, priorityChange, formattedValue]);
+ if(this.dropDown){
+ this.dropDown.set('value', value, false);
+ }
+ },
+
+ _set: function(attr, value){
+ // Avoid spurious watch() notifications when value is changed to new Date object w/the same value
+ if(attr == "value"
+ && this.value instanceof Date
+ && ((this._isInvalidDate(this.value) && this._isInvalidDate(value))
+ || this.compare(value, this.value) == 0)){
+ return;
+ }
+ this.inherited(arguments);
+ },
+
+ _setDropDownDefaultValueAttr: function(/*Date*/ val){
+ if(this._isInvalidDate(val)){
+ // convert null setting into today's date, since there needs to be *some* default at all times.
+ val = new this.dateClassObj()
+ }
+ this.dropDownDefaultValue = val;
+ },
+
+ openDropDown: function(/*Function*/ callback){
+ // rebuild drop down every time, so that constraints get copied (#6002)
+ if(this.dropDown){
+ this.dropDown.destroy();
+ }
+ var PopupProto = dojo.getObject(this.popupClass, false),
+ textBox = this,
+ value = this.get("value");
+ this.dropDown = new PopupProto({
+ onChange: function(value){
+ // this will cause InlineEditBox and other handlers to do stuff so make sure it's last
+ dijit.form._DateTimeTextBox.superclass._setValueAttr.call(textBox, value, true);
+ },
+ id: this.id + "_popup",
+ dir: textBox.dir,
+ lang: textBox.lang,
+ value: value,
+ currentFocus: !this._isInvalidDate(value) ? value : this.dropDownDefaultValue,
+ constraints: textBox.constraints,
+ filterString: textBox.filterString, // for TimeTextBox, to filter times shown
+
+ datePackage: textBox.datePackage,
+
+ isDisabledDate: function(/*Date*/ date){
+ // summary:
+ // disables dates outside of the min/max of the _DateTimeTextBox
+ return !textBox.rangeCheck(date, textBox.constraints);
+ }
+ });
+
+ this.inherited(arguments);
+ },
+
+ _getDisplayedValueAttr: function(){
+ return this.textbox.value;
+ },
+
+ _setDisplayedValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange){
+ this._setValueAttr(this.parse(value, this.constraints), priorityChange, value);
+ }
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit.form.DateTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.DateTextBox"] = true;
+dojo.provide("dijit.form.DateTextBox");
+
+
+
+
+
+dojo.declare(
+ "dijit.form.DateTextBox",
+ dijit.form._DateTimeTextBox,
+ {
+ // summary:
+ // A validating, serializable, range-bound date text box with a drop down calendar
+ //
+ // Example:
+ // | new dijit.form.DateTextBox({value: new Date(2009, 0, 20)})
+ //
+ // Example:
+ // | <input dojotype='dijit.form.DateTextBox' value='2009-01-20'>
+
+ baseClass: "dijitTextBox dijitComboBox dijitDateTextBox",
+ popupClass: "dijit.Calendar",
+ _selector: "date",
+
+ // value: Date
+ // The value of this widget as a JavaScript Date object, with only year/month/day specified.
+ // If specified in markup, use the format specified in `dojo.date.stamp.fromISOString`.
+ // set("value", ...) accepts either a Date object or a string.
+ value: new Date("") // value.toString()="NaN"
+ }
+);
+
+}
+
+if(!dojo._hasResource["dijit.form._Spinner"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form._Spinner"] = true;
+dojo.provide("dijit.form._Spinner");
+
+
+
+
+dojo.declare(
+ "dijit.form._Spinner",
+ dijit.form.RangeBoundTextBox,
+ {
+ // summary:
+ // Mixin for validation widgets with a spinner.
+ // description:
+ // This class basically (conceptually) extends `dijit.form.ValidationTextBox`.
+ // It modifies the template to have up/down arrows, and provides related handling code.
+
+ // defaultTimeout: Number
+ // Number of milliseconds before a held arrow key or up/down button becomes typematic
+ defaultTimeout: 500,
+
+ // minimumTimeout: Number
+ // minimum number of milliseconds that typematic event fires when held key or button is held
+ minimumTimeout: 10,
+
+ // 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,
+
+ // smallDelta: Number
+ // Adjust the value by this much when spinning using the arrow keys/buttons
+ smallDelta: 1,
+
+ // largeDelta: Number
+ // Adjust the value by this much when spinning using the PgUp/Dn keys
+ largeDelta: 10,
+
+ templateString: dojo.cache("dijit.form", "templates/Spinner.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\r\n\tid=\"widget_${id}\" role=\"presentation\"\r\n\t><div class=\"dijitReset dijitButtonNode dijitSpinnerButtonContainer\"\r\n\t\t><input class=\"dijitReset dijitInputField dijitSpinnerButtonInner\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t/><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitUpArrowButton\"\r\n\t\t\tdojoAttachPoint=\"upArrowNode\"\r\n\t\t\t><div class=\"dijitArrowButtonInner\"\r\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9650;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t\t\t${_buttonInputDisabled}\r\n\t\t\t/></div\r\n\t\t></div\r\n\t\t><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitDownArrowButton\"\r\n\t\t\tdojoAttachPoint=\"downArrowNode\"\r\n\t\t\t><div class=\"dijitArrowButtonInner\"\r\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9660;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t\t\t\t\t${_buttonInputDisabled}\r\n\t\t\t/></div\r\n\t\t></div\r\n\t></div\r\n\t><div class='dijitReset dijitValidationContainer'\r\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\r\n\t/></div\r\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\r\n\t\t><input class='dijitReset dijitInputInner' dojoAttachPoint=\"textbox,focusNode\" type=\"${type}\" dojoAttachEvent=\"onkeypress:_onKeyPress\"\r\n\t\t\trole=\"spinbutton\" autocomplete=\"off\" ${!nameAttrSetting}\r\n\t/></div\r\n></div>\r\n"),
+
+ baseClass: "dijitTextBox dijitSpinner",
+
+ // Set classes like dijitUpArrowButtonHover or dijitDownArrowButtonActive depending on
+ // mouse action over specified node
+ cssStateNodes: {
+ "upArrowNode": "dijitUpArrowButton",
+ "downArrowNode": "dijitDownArrowButton"
+ },
+
+ adjust: function(/*Object*/ val, /*Number*/ delta){
+ // summary:
+ // Overridable function used to adjust a primitive value(Number/Date/...) by the delta amount specified.
+ // The val is adjusted in a way that makes sense to the object type.
+ // tags:
+ // protected extension
+ return val;
+ },
+
+ _arrowPressed: function(/*Node*/ nodePressed, /*Number*/ direction, /*Number*/ increment){
+ // summary:
+ // Handler for arrow button or arrow key being pressed
+ if(this.disabled || this.readOnly){ return; }
+ this._setValueAttr(this.adjust(this.get('value'), direction*increment), false);
+ dijit.selectInputText(this.textbox, this.textbox.value.length);
+ },
+
+ _arrowReleased: function(/*Node*/ node){
+ // summary:
+ // Handler for arrow button or arrow key being released
+ this._wheelTimer = null;
+ if(this.disabled || this.readOnly){ return; }
+ },
+
+ _typematicCallback: function(/*Number*/ count, /*DOMNode*/ node, /*Event*/ evt){
+ var inc=this.smallDelta;
+ if(node == this.textbox){
+ var k=dojo.keys;
+ var key = evt.charOrCode;
+ inc = (key == k.PAGE_UP || key == k.PAGE_DOWN) ? this.largeDelta : this.smallDelta;
+ node = (key == k.UP_ARROW || key == k.PAGE_UP) ? this.upArrowNode : this.downArrowNode;
+ }
+ if(count == -1){ this._arrowReleased(node); }
+ else{ this._arrowPressed(node, (node == this.upArrowNode) ? 1 : -1, inc); }
+ },
+
+ _wheelTimer: null,
+ _mouseWheeled: function(/*Event*/ evt){
+ // summary:
+ // Mouse wheel listener where supported
+
+ dojo.stopEvent(evt);
+ // FIXME: Safari bubbles
+
+ // be nice to DOH and scroll as much as the event says to
+ var scrollAmount = evt.detail ? (evt.detail * -1) : (evt.wheelDelta / 120);
+ if(scrollAmount !== 0){
+ var node = this[(scrollAmount > 0 ? "upArrowNode" : "downArrowNode" )];
+
+ this._arrowPressed(node, scrollAmount, this.smallDelta);
+
+ if(!this._wheelTimer){
+ clearTimeout(this._wheelTimer);
+ }
+ this._wheelTimer = setTimeout(dojo.hitch(this,"_arrowReleased",node), 50);
+ }
+
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // extra listeners
+ this.connect(this.domNode, !dojo.isMozilla ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled");
+ this._connects.push(dijit.typematic.addListener(this.upArrowNode, this.textbox, {charOrCode:dojo.keys.UP_ARROW,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
+ this._connects.push(dijit.typematic.addListener(this.downArrowNode, this.textbox, {charOrCode:dojo.keys.DOWN_ARROW,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
+ this._connects.push(dijit.typematic.addListener(this.upArrowNode, this.textbox, {charOrCode:dojo.keys.PAGE_UP,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
+ this._connects.push(dijit.typematic.addListener(this.downArrowNode, this.textbox, {charOrCode:dojo.keys.PAGE_DOWN,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.form.NumberSpinner"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.NumberSpinner"] = true;
+dojo.provide("dijit.form.NumberSpinner");
+
+
+
+
+
+dojo.declare("dijit.form.NumberSpinner",
+ [dijit.form._Spinner, dijit.form.NumberTextBoxMixin],
+ {
+ // summary:
+ // Extends NumberTextBox to add up/down arrows and pageup/pagedown for incremental change to the value
+ //
+ // description:
+ // A `dijit.form.NumberTextBox` extension to provide keyboard accessible value selection
+ // as well as icons for spinning direction. When using the keyboard, the typematic rules
+ // apply, meaning holding the key will gradually increase or decrease the value and
+ // accelerate.
+ //
+ // example:
+ // | new dijit.form.NumberSpinner({ constraints:{ max:300, min:100 }}, "someInput");
+
+ adjust: function(/*Object*/ val, /*Number*/ delta){
+ // summary:
+ // Change Number val by the given amount
+ // tags:
+ // protected
+
+ var tc = this.constraints,
+ v = isNaN(val),
+ gotMax = !isNaN(tc.max),
+ gotMin = !isNaN(tc.min)
+ ;
+ if(v && delta != 0){ // blank or invalid value and they want to spin, so create defaults
+ val = (delta > 0) ?
+ gotMin ? tc.min : gotMax ? tc.max : 0 :
+ gotMax ? this.constraints.max : gotMin ? tc.min : 0
+ ;
+ }
+ var newval = val + delta;
+ if(v || isNaN(newval)){ return val; }
+ if(gotMax && (newval > tc.max)){
+ newval = tc.max;
+ }
+ if(gotMin && (newval < tc.min)){
+ newval = tc.min;
+ }
+ return newval;
+ },
+
+ _onKeyPress: function(e){
+ if((e.charOrCode == dojo.keys.HOME || e.charOrCode == dojo.keys.END) && !(e.ctrlKey || e.altKey || e.metaKey)
+ && typeof this.get('value') != 'undefined' /* gibberish, so HOME and END are default editing keys*/){
+ var value = this.constraints[(e.charOrCode == dojo.keys.HOME ? "min" : "max")];
+ if(typeof value == "number"){
+ this._setValueAttr(value, false);
+ }
+ // eat home or end key whether we change the value or not
+ dojo.stopEvent(e);
+ }
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.form.MultiSelect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.MultiSelect"] = true;
+dojo.provide("dijit.form.MultiSelect");
+
+
+
+
+dojo.declare("dijit.form.MultiSelect", dijit.form._FormValueWidget, {
+ // summary:
+ // Widget version of a <select multiple=true> element,
+ // for selecting multiple options.
+
+ // size: Number
+ // Number of elements to display on a page
+ // NOTE: may be removed in version 2.0, since elements may have variable height;
+ // set the size via style="..." or CSS class names instead.
+ size: 7,
+
+ templateString: "<select multiple='true' ${!nameAttrSetting} dojoAttachPoint='containerNode,focusNode' dojoAttachEvent='onchange: _onChange'></select>",
+
+ attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
+ size: "focusNode"
+ }),
+
+ reset: function(){
+ // summary:
+ // Reset the widget's value to what it was at initialization time
+
+ // TODO: once we inherit from FormValueWidget this won't be needed
+ this._hasBeenBlurred = false;
+ this._setValueAttr(this._resetValue, true);
+ },
+
+ addSelected: function(/*dijit.form.MultiSelect*/ select){
+ // summary:
+ // Move the selected nodes of a passed Select widget
+ // instance to this Select widget.
+ //
+ // example:
+ // | // move all the selected values from "bar" to "foo"
+ // | dijit.byId("foo").addSelected(dijit.byId("bar"));
+
+ select.getSelected().forEach(function(n){
+ this.containerNode.appendChild(n);
+ // scroll to bottom to see item
+ // cannot use scrollIntoView since <option> tags don't support all attributes
+ // does not work on IE due to a bug where <select> always shows scrollTop = 0
+ this.domNode.scrollTop = this.domNode.offsetHeight; // overshoot will be ignored
+ // scrolling the source select is trickier esp. on safari who forgets to change the scrollbar size
+ var oldscroll = select.domNode.scrollTop;
+ select.domNode.scrollTop = 0;
+ select.domNode.scrollTop = oldscroll;
+ },this);
+ },
+
+ getSelected: function(){
+ // summary:
+ // Access the NodeList of the selected options directly
+ return dojo.query("option",this.containerNode).filter(function(n){
+ return n.selected; // Boolean
+ }); // dojo.NodeList
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // Hook so get('value') works.
+ // description:
+ // Returns an array of the selected options' values.
+ return this.getSelected().map(function(n){
+ return n.value;
+ });
+ },
+
+ multiple: true, // for Form
+
+ _setValueAttr: function(/*Array*/ values){
+ // summary:
+ // Hook so set('value', values) works.
+ // description:
+ // Set the value(s) of this Select based on passed values
+ dojo.query("option",this.containerNode).forEach(function(n){
+ n.selected = (dojo.indexOf(values,n.value) != -1);
+ });
+ },
+
+ invertSelection: function(onChange){
+ // summary:
+ // Invert the selection
+ // onChange: Boolean
+ // If null, onChange is not fired.
+ dojo.query("option",this.containerNode).forEach(function(n){
+ n.selected = !n.selected;
+ });
+ this._handleOnChange(this.get('value'), onChange == true);
+ },
+
+ _onChange: function(/*Event*/ e){
+ this._handleOnChange(this.get('value'), true);
+ },
+
+ // for layout widgets:
+ resize: function(/*Object*/ size){
+ if(size){
+ dojo.marginBox(this.domNode, size);
+ }
+ },
+
+ postCreate: function(){
+ this._onChange();
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.form.HorizontalSlider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.HorizontalSlider"] = true;
+dojo.provide("dijit.form.HorizontalSlider");
+
+
+
+
+
+
+
+
+dojo.declare(
+ "dijit.form.HorizontalSlider",
+ [dijit.form._FormValueWidget, dijit._Container],
+{
+ // summary:
+ // A form widget that allows one to select a value with a horizontally draggable handle
+
+ templateString: dojo.cache("dijit.form", "templates/HorizontalSlider.html", "<table class=\"dijit dijitReset dijitSlider dijitSliderH\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\" dojoAttachEvent=\"onkeypress:_onKeyPress,onkeyup:_onKeyUp\"\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t\t><td dojoAttachPoint=\"topDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationT dijitSliderDecorationH\"></td\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\r\n\t\t\t><div class=\"dijitSliderDecrementIconH\" style=\"display:none\" dojoAttachPoint=\"decrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderLeftBumper\" dojoAttachEvent=\"onmousedown:_onClkDecBumper\"></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\r\n\t\t\t/><div class=\"dijitReset dijitSliderBarContainerH\" role=\"presentation\" dojoAttachPoint=\"sliderBarContainer\"\r\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH\" dojoAttachEvent=\"onmousedown:_onBarClick\"\r\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableH\"\r\n\t\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleH\" dojoAttachEvent=\"onmousedown:_onHandleClick\" role=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"></div\r\n\t\t\t\t\t></div\r\n\t\t\t\t></div\r\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderRemainingBar dijitSliderRemainingBarH\" dojoAttachEvent=\"onmousedown:_onBarClick\"></div\r\n\t\t\t></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderRightBumper\" dojoAttachEvent=\"onmousedown:_onClkIncBumper\"></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\r\n\t\t\t><div class=\"dijitSliderIncrementIconH\" style=\"display:none\" dojoAttachPoint=\"incrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\r\n\t\t></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t\t><td dojoAttachPoint=\"containerNode,bottomDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH\"></td\r\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\r\n\t></tr\r\n></table>\r\n"),
+
+ // Overrides FormValueWidget.value to indicate numeric value
+ value: 0,
+
+ // showButtons: [const] Boolean
+ // Show increment/decrement buttons at the ends of the slider?
+ showButtons: true,
+
+ // minimum:: [const] Integer
+ // The minimum value the slider can be set to.
+ minimum: 0,
+
+ // maximum: [const] Integer
+ // The maximum value the slider can be set to.
+ maximum: 100,
+
+ // discreteValues: Integer
+ // If specified, indicates that the slider handle has only 'discreteValues' possible positions,
+ // and that after dragging the handle, it will snap to the nearest possible position.
+ // Thus, the slider has only 'discreteValues' possible values.
+ //
+ // For example, if minimum=10, maxiumum=30, and discreteValues=3, then the slider handle has
+ // three possible positions, representing values 10, 20, or 30.
+ //
+ // If discreteValues is not specified or if it's value is higher than the number of pixels
+ // in the slider bar, then the slider handle can be moved freely, and the slider's value will be
+ // computed/reported based on pixel position (in this case it will likely be fractional,
+ // such as 123.456789).
+ discreteValues: Infinity,
+
+ // pageIncrement: Integer
+ // If discreteValues is also specified, this indicates the amount of clicks (ie, snap positions)
+ // that the slider handle is moved via pageup/pagedown keys.
+ // If discreteValues is not specified, it indicates the number of pixels.
+ pageIncrement: 2,
+
+ // clickSelect: Boolean
+ // If clicking the slider bar changes the value or not
+ clickSelect: true,
+
+ // slideDuration: Number
+ // The time in ms to take to animate the slider handle from 0% to 100%,
+ // when clicking the slider bar to make the handle move.
+ slideDuration: dijit.defaultDuration,
+
+ // Flag to _Templated (TODO: why is this here? I see no widgets in the template.)
+ widgetsInTemplate: true,
+
+ attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
+ id: ""
+ }),
+
+ baseClass: "dijitSlider",
+
+ // Apply CSS classes to up/down arrows and handle per mouse state
+ cssStateNodes: {
+ incrementButton: "dijitSliderIncrementButton",
+ decrementButton: "dijitSliderDecrementButton",
+ focusNode: "dijitSliderThumb"
+ },
+
+ _mousePixelCoord: "pageX",
+ _pixelCount: "w",
+ _startingPixelCoord: "x",
+ _startingPixelCount: "l",
+ _handleOffsetCoord: "left",
+ _progressPixelSize: "width",
+
+ _onKeyUp: function(/*Event*/ e){
+ if(this.disabled || this.readOnly || e.altKey || e.ctrlKey || e.metaKey){ return; }
+ this._setValueAttr(this.value, true);
+ },
+
+ _onKeyPress: function(/*Event*/ e){
+ if(this.disabled || this.readOnly || e.altKey || e.ctrlKey || e.metaKey){ return; }
+ switch(e.charOrCode){
+ case dojo.keys.HOME:
+ this._setValueAttr(this.minimum, false);
+ break;
+ case dojo.keys.END:
+ this._setValueAttr(this.maximum, false);
+ break;
+ // this._descending === false: if ascending vertical (min on top)
+ // (this._descending || this.isLeftToRight()): if left-to-right horizontal or descending vertical
+ case ((this._descending || this.isLeftToRight()) ? dojo.keys.RIGHT_ARROW : dojo.keys.LEFT_ARROW):
+ case (this._descending === false ? dojo.keys.DOWN_ARROW : dojo.keys.UP_ARROW):
+ case (this._descending === false ? dojo.keys.PAGE_DOWN : dojo.keys.PAGE_UP):
+ this.increment(e);
+ break;
+ case ((this._descending || this.isLeftToRight()) ? dojo.keys.LEFT_ARROW : dojo.keys.RIGHT_ARROW):
+ case (this._descending === false ? dojo.keys.UP_ARROW : dojo.keys.DOWN_ARROW):
+ case (this._descending === false ? dojo.keys.PAGE_UP : dojo.keys.PAGE_DOWN):
+ this.decrement(e);
+ break;
+ default:
+ return;
+ }
+ dojo.stopEvent(e);
+ },
+
+ _onHandleClick: function(e){
+ if(this.disabled || this.readOnly){ return; }
+ if(!dojo.isIE){
+ // make sure you get focus when dragging the handle
+ // (but don't do on IE because it causes a flicker on mouse up (due to blur then focus)
+ dijit.focus(this.sliderHandle);
+ }
+ dojo.stopEvent(e);
+ },
+
+ _isReversed: function(){
+ // summary:
+ // Returns true if direction is from right to left
+ // tags:
+ // protected extension
+ return !this.isLeftToRight();
+ },
+
+ _onBarClick: function(e){
+ if(this.disabled || this.readOnly || !this.clickSelect){ return; }
+ dijit.focus(this.sliderHandle);
+ dojo.stopEvent(e);
+ var abspos = dojo.position(this.sliderBarContainer, true);
+ var pixelValue = e[this._mousePixelCoord] - abspos[this._startingPixelCoord];
+ this._setPixelValue(this._isReversed() ? (abspos[this._pixelCount] - pixelValue) : pixelValue, abspos[this._pixelCount], true);
+ this._movable.onMouseDown(e);
+ },
+
+ _setPixelValue: function(/*Number*/ pixelValue, /*Number*/ maxPixels, /*Boolean?*/ priorityChange){
+ if(this.disabled || this.readOnly){ return; }
+ pixelValue = pixelValue < 0 ? 0 : maxPixels < pixelValue ? maxPixels : pixelValue;
+ var count = this.discreteValues;
+ if(count <= 1 || count == Infinity){ count = maxPixels; }
+ count--;
+ var pixelsPerValue = maxPixels / count;
+ var wholeIncrements = Math.round(pixelValue / pixelsPerValue);
+ this._setValueAttr((this.maximum-this.minimum)*wholeIncrements/count + this.minimum, priorityChange);
+ },
+
+ _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
+ // summary:
+ // Hook so set('value', value) works.
+ this._set("value", value);
+ this.valueNode.value = value;
+ dijit.setWaiState(this.focusNode, "valuenow", value);
+ this.inherited(arguments);
+ var percent = (value - this.minimum) / (this.maximum - this.minimum);
+ var progressBar = (this._descending === false) ? this.remainingBar : this.progressBar;
+ var remainingBar = (this._descending === false) ? this.progressBar : this.remainingBar;
+ if(this._inProgressAnim && this._inProgressAnim.status != "stopped"){
+ this._inProgressAnim.stop(true);
+ }
+ if(priorityChange && this.slideDuration > 0 && progressBar.style[this._progressPixelSize]){
+ // animate the slider
+ var _this = this;
+ var props = {};
+ var start = parseFloat(progressBar.style[this._progressPixelSize]);
+ var duration = this.slideDuration * (percent-start/100);
+ if(duration == 0){ return; }
+ if(duration < 0){ duration = 0 - duration; }
+ props[this._progressPixelSize] = { start: start, end: percent*100, units:"%" };
+ this._inProgressAnim = dojo.animateProperty({ node: progressBar, duration: duration,
+ onAnimate: function(v){ remainingBar.style[_this._progressPixelSize] = (100-parseFloat(v[_this._progressPixelSize])) + "%"; },
+ onEnd: function(){ delete _this._inProgressAnim; },
+ properties: props
+ })
+ this._inProgressAnim.play();
+ }else{
+ progressBar.style[this._progressPixelSize] = (percent*100) + "%";
+ remainingBar.style[this._progressPixelSize] = ((1-percent)*100) + "%";
+ }
+ },
+
+ _bumpValue: function(signedChange, /*Boolean?*/ priorityChange){
+ if(this.disabled || this.readOnly){ return; }
+ var s = dojo.getComputedStyle(this.sliderBarContainer);
+ var c = dojo._getContentBox(this.sliderBarContainer, s);
+ var count = this.discreteValues;
+ if(count <= 1 || count == Infinity){ count = c[this._pixelCount]; }
+ count--;
+ var value = (this.value - this.minimum) * count / (this.maximum - this.minimum) + signedChange;
+ if(value < 0){ value = 0; }
+ if(value > count){ value = count; }
+ value = value * (this.maximum - this.minimum) / count + this.minimum;
+ this._setValueAttr(value, priorityChange);
+ },
+
+ _onClkBumper: function(val){
+ if(this.disabled || this.readOnly || !this.clickSelect){ return; }
+ this._setValueAttr(val, true);
+ },
+
+ _onClkIncBumper: function(){
+ this._onClkBumper(this._descending === false ? this.minimum : this.maximum);
+ },
+
+ _onClkDecBumper: function(){
+ this._onClkBumper(this._descending === false ? this.maximum : this.minimum);
+ },
+
+ decrement: function(/*Event*/ e){
+ // summary:
+ // Decrement slider
+ // tags:
+ // private
+ this._bumpValue(e.charOrCode == dojo.keys.PAGE_DOWN ? -this.pageIncrement : -1);
+ },
+
+ increment: function(/*Event*/ e){
+ // summary:
+ // Increment slider
+ // tags:
+ // private
+ this._bumpValue(e.charOrCode == dojo.keys.PAGE_UP ? this.pageIncrement : 1);
+ },
+
+ _mouseWheeled: function(/*Event*/ evt){
+ // summary:
+ // Event handler for mousewheel where supported
+ dojo.stopEvent(evt);
+ var janky = !dojo.isMozilla;
+ var scroll = evt[(janky ? "wheelDelta" : "detail")] * (janky ? 1 : -1);
+ this._bumpValue(scroll < 0 ? -1 : 1, true); // negative scroll acts like a decrement
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+
+ dojo.forEach(this.getChildren(), function(child){
+ if(this[child.container] != this.containerNode){
+ this[child.container].appendChild(child.domNode);
+ }
+ }, this);
+
+ this.inherited(arguments);
+ },
+
+ _typematicCallback: function(/*Number*/ count, /*Object*/ button, /*Event*/ e){
+ if(count == -1){
+ this._setValueAttr(this.value, true);
+ }else{
+ this[(button == (this._descending? this.incrementButton : this.decrementButton)) ? "decrement" : "increment"](e);
+ }
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ if(this.showButtons){
+ this.incrementButton.style.display="";
+ this.decrementButton.style.display="";
+ }
+
+ // find any associated label element and add to slider focusnode.
+ var label = dojo.query('label[for="'+this.id+'"]');
+ if(label.length){
+ label[0].id = (this.id+"_label");
+ dijit.setWaiState(this.focusNode, "labelledby", label[0].id);
+ }
+
+ dijit.setWaiState(this.focusNode, "valuemin", this.minimum);
+ dijit.setWaiState(this.focusNode, "valuemax", this.maximum);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ if(this.showButtons){
+ this._connects.push(dijit.typematic.addMouseListener(
+ this.decrementButton, this, "_typematicCallback", 25, 500));
+ this._connects.push(dijit.typematic.addMouseListener(
+ this.incrementButton, this, "_typematicCallback", 25, 500));
+ }
+ this.connect(this.domNode, !dojo.isMozilla ? "onmousewheel" : "DOMMouseScroll", "_mouseWheeled");
+
+ // define a custom constructor for a SliderMover that points back to me
+ var mover = dojo.declare(dijit.form._SliderMover, {
+ widget: this
+ });
+ this._movable = new dojo.dnd.Moveable(this.sliderHandle, {mover: mover});
+
+ this._layoutHackIE7();
+ },
+
+ destroy: function(){
+ this._movable.destroy();
+ if(this._inProgressAnim && this._inProgressAnim.status != "stopped"){
+ this._inProgressAnim.stop(true);
+ }
+ this._supportingWidgets = dijit.findWidgets(this.domNode); // tells destroy about pseudo-child widgets (ruler/labels)
+ this.inherited(arguments);
+ }
+});
+
+dojo.declare("dijit.form._SliderMover",
+ dojo.dnd.Mover,
+{
+ onMouseMove: function(e){
+ var widget = this.widget;
+ var abspos = widget._abspos;
+ if(!abspos){
+ abspos = widget._abspos = dojo.position(widget.sliderBarContainer, true);
+ widget._setPixelValue_ = dojo.hitch(widget, "_setPixelValue");
+ widget._isReversed_ = widget._isReversed();
+ }
+ var coordEvent = e.touches ? e.touches[0] : e, // if multitouch take first touch for coords
+ pixelValue = coordEvent[widget._mousePixelCoord] - abspos[widget._startingPixelCoord];
+ widget._setPixelValue_(widget._isReversed_ ? (abspos[widget._pixelCount]-pixelValue) : pixelValue, abspos[widget._pixelCount], false);
+ },
+
+ destroy: function(e){
+ dojo.dnd.Mover.prototype.destroy.apply(this, arguments);
+ var widget = this.widget;
+ widget._abspos = null;
+ widget._setValueAttr(widget.value, true);
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.form.VerticalSlider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.VerticalSlider"] = true;
+dojo.provide("dijit.form.VerticalSlider");
+
+
+
+
+dojo.declare(
+ "dijit.form.VerticalSlider",
+ dijit.form.HorizontalSlider,
+{
+ // summary:
+ // A form widget that allows one to select a value with a vertically draggable handle
+
+ templateString: dojo.cache("dijit.form", "templates/VerticalSlider.html", "<table class=\"dijit dijitReset dijitSlider dijitSliderV\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\" dojoAttachEvent=\"onkeypress:_onKeyPress,onkeyup:_onKeyUp\"\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\"></td\r\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\r\n\t\t\t><div class=\"dijitSliderIncrementIconV\" style=\"display:none\" dojoAttachPoint=\"decrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\"></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderTopBumper\" dojoAttachEvent=\"onmousedown:_onClkIncBumper\"></div></center\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td dojoAttachPoint=\"leftDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationL dijitSliderDecorationV\"></td\r\n\t\t><td class=\"dijitReset dijitSliderDecorationC\" style=\"height:100%;\"\r\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\r\n\t\t\t/><center class=\"dijitReset dijitSliderBarContainerV\" role=\"presentation\" dojoAttachPoint=\"sliderBarContainer\"\r\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderRemainingBar dijitSliderRemainingBarV\" dojoAttachEvent=\"onmousedown:_onBarClick\"><!--#5629--></div\r\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderProgressBar dijitSliderProgressBarV\" dojoAttachEvent=\"onmousedown:_onBarClick\"\r\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableV\" style=\"vertical-align:top;\"\r\n\t\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleV\" dojoAttachEvent=\"onmousedown:_onHandleClick\" role=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"></div\r\n\t\t\t\t\t></div\r\n\t\t\t\t></div\r\n\t\t\t></center\r\n\t\t></td\r\n\t\t><td dojoAttachPoint=\"containerNode,rightDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationR dijitSliderDecorationV\"></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\"></td\r\n\t\t><td class=\"dijitReset\"\r\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderBottomBumper\" dojoAttachEvent=\"onmousedown:_onClkDecBumper\"></div></center\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"></td\r\n\t></tr\r\n\t><tr class=\"dijitReset\"\r\n\t\t><td class=\"dijitReset\"></td\r\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\r\n\t\t\t><div class=\"dijitSliderDecrementIconV\" style=\"display:none\" dojoAttachPoint=\"incrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\r\n\t\t></td\r\n\t\t><td class=\"dijitReset\"></td\r\n\t></tr\r\n></table>\r\n"),
+ _mousePixelCoord: "pageY",
+ _pixelCount: "h",
+ _startingPixelCoord: "y",
+ _startingPixelCount: "t",
+ _handleOffsetCoord: "top",
+ _progressPixelSize: "height",
+
+ // _descending: Boolean
+ // Specifies if the slider values go from high-on-top (true), or low-on-top (false)
+ // TODO: expose this in 1.2 - the css progress/remaining bar classes need to be reversed
+ _descending: true,
+
+ _isReversed: function(){
+ // summary:
+ // Overrides HorizontalSlider._isReversed.
+ // Indicates if values are high on top (with low numbers on the bottom).
+ return this._descending;
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.form.HorizontalRule"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.HorizontalRule"] = true;
+dojo.provide("dijit.form.HorizontalRule");
+
+
+
+
+
+dojo.declare("dijit.form.HorizontalRule", [dijit._Widget, dijit._Templated],
+{
+ // summary:
+ // Hash marks for `dijit.form.HorizontalSlider`
+
+ templateString: '<div class="dijitRuleContainer dijitRuleContainerH"></div>',
+
+ // count: Integer
+ // Number of hash marks to generate
+ count: 3,
+
+ // container: String
+ // For HorizontalSlider, this is either "topDecoration" or "bottomDecoration",
+ // and indicates whether this rule goes above or below the slider.
+ container: "containerNode",
+
+ // ruleStyle: String
+ // CSS style to apply to individual hash marks
+ ruleStyle: "",
+
+ _positionPrefix: '<div class="dijitRuleMark dijitRuleMarkH" style="left:',
+ _positionSuffix: '%;',
+ _suffix: '"></div>',
+
+ _genHTML: function(pos, ndx){
+ return this._positionPrefix + pos + this._positionSuffix + this.ruleStyle + this._suffix;
+ },
+
+ // _isHorizontal: [protected extension] Boolean
+ // VerticalRule will override this...
+ _isHorizontal: true,
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ var innerHTML;
+ if(this.count == 1){
+ innerHTML = this._genHTML(50, 0);
+ }else{
+ var i;
+ var interval = 100 / (this.count-1);
+ if(!this._isHorizontal || this.isLeftToRight()){
+ innerHTML = this._genHTML(0, 0);
+ for(i=1; i < this.count-1; i++){
+ innerHTML += this._genHTML(interval*i, i);
+ }
+ innerHTML += this._genHTML(100, this.count-1);
+ }else{
+ innerHTML = this._genHTML(100, 0);
+ for(i=1; i < this.count-1; i++){
+ innerHTML += this._genHTML(100-interval*i, i);
+ }
+ innerHTML += this._genHTML(0, this.count-1);
+ }
+ }
+ this.domNode.innerHTML = innerHTML;
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.form.VerticalRule"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.VerticalRule"] = true;
+dojo.provide("dijit.form.VerticalRule");
+
+
+
+
+dojo.declare("dijit.form.VerticalRule", dijit.form.HorizontalRule,
+{
+ // summary:
+ // Hash marks for the `dijit.form.VerticalSlider`
+
+ templateString: '<div class="dijitRuleContainer dijitRuleContainerV"></div>',
+ _positionPrefix: '<div class="dijitRuleMark dijitRuleMarkV" style="top:',
+
+/*=====
+ // container: String
+ // This is either "leftDecoration" or "rightDecoration",
+ // to indicate whether this rule goes to the left or to the right of the slider.
+ // Note that on RTL system, "leftDecoration" would actually go to the right, and vice-versa.
+ container: "",
+=====*/
+
+ // Overrides HorizontalRule._isHorizontal
+ _isHorizontal: false
+
+});
+
+}
+
+if(!dojo._hasResource["dijit.form.HorizontalRuleLabels"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.HorizontalRuleLabels"] = true;
+dojo.provide("dijit.form.HorizontalRuleLabels");
+
+
+
+
+dojo.declare("dijit.form.HorizontalRuleLabels", dijit.form.HorizontalRule,
+{
+ // summary:
+ // Labels for `dijit.form.HorizontalSlider`
+
+ templateString: '<div class="dijitRuleContainer dijitRuleContainerH dijitRuleLabelsContainer dijitRuleLabelsContainerH"></div>',
+
+ // labelStyle: String
+ // CSS style to apply to individual text labels
+ labelStyle: "",
+
+ // labels: String[]?
+ // Array of text labels to render - evenly spaced from left-to-right or bottom-to-top.
+ // Alternately, minimum and maximum can be specified, to get numeric labels.
+ labels: [],
+
+ // numericMargin: Integer
+ // Number of generated numeric labels that should be rendered as '' on the ends when labels[] are not specified
+ numericMargin: 0,
+
+ // numericMinimum: Integer
+ // Leftmost label value for generated numeric labels when labels[] are not specified
+ minimum: 0,
+
+ // numericMaximum: Integer
+ // Rightmost label value for generated numeric labels when labels[] are not specified
+ maximum: 1,
+
+ // constraints: Object
+ // pattern, places, lang, et al (see dojo.number) for generated numeric labels when labels[] are not specified
+ constraints: {pattern:"#%"},
+
+ _positionPrefix: '<div class="dijitRuleLabelContainer dijitRuleLabelContainerH" style="left:',
+ _labelPrefix: '"><div class="dijitRuleLabel dijitRuleLabelH">',
+ _suffix: '</div></div>',
+
+ _calcPosition: function(pos){
+ // summary:
+ // Returns the value to be used in HTML for the label as part of the left: attribute
+ // tags:
+ // protected extension
+ return pos;
+ },
+
+ _genHTML: function(pos, ndx){
+ return this._positionPrefix + this._calcPosition(pos) + this._positionSuffix + this.labelStyle + this._labelPrefix + this.labels[ndx] + this._suffix;
+ },
+
+ getLabels: function(){
+ // summary:
+ // Overridable function to return array of labels to use for this slider.
+ // Can specify a getLabels() method instead of a labels[] array, or min/max attributes.
+ // tags:
+ // protected extension
+
+ // if the labels array was not specified directly, then see if <li> children were
+ var labels = this.labels;
+ if(!labels.length){
+ // for markup creation, labels are specified as child elements
+ labels = dojo.query("> li", this.srcNodeRef).map(function(node){
+ return String(node.innerHTML);
+ });
+ }
+ this.srcNodeRef.innerHTML = '';
+ // if the labels were not specified directly and not as <li> children, then calculate numeric labels
+ if(!labels.length && this.count > 1){
+ var start = this.minimum;
+ var inc = (this.maximum - start) / (this.count-1);
+ for(var i=0; i < this.count; i++){
+ labels.push((i < this.numericMargin || i >= (this.count-this.numericMargin)) ? '' : dojo.number.format(start, this.constraints));
+ start += inc;
+ }
+ }
+ return labels;
+ },
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this.labels = this.getLabels();
+ this.count = this.labels.length;
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.form.VerticalRuleLabels"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.VerticalRuleLabels"] = true;
+dojo.provide("dijit.form.VerticalRuleLabels");
+
+
+
+
+dojo.declare("dijit.form.VerticalRuleLabels", dijit.form.HorizontalRuleLabels,
+{
+ // summary:
+ // Labels for the `dijit.form.VerticalSlider`
+
+ templateString: '<div class="dijitRuleContainer dijitRuleContainerV dijitRuleLabelsContainer dijitRuleLabelsContainerV"></div>',
+
+ _positionPrefix: '<div class="dijitRuleLabelContainer dijitRuleLabelContainerV" style="top:',
+ _labelPrefix: '"><span class="dijitRuleLabel dijitRuleLabelV">',
+
+ _calcPosition: function(pos){
+ // Overrides HorizontalRuleLabel._calcPosition()
+ return 100-pos;
+ },
+
+ // needed to prevent labels from being reversed in RTL mode
+ _isHorizontal: false
+});
+
+}
+
+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)
+ // TODO: parser will handle this in 2.0
+ if(!this.value && this.srcNodeRef){
+ this.value = this.srcNodeRef.value;
+ }
+ this.inherited(arguments);
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ if(dojo.isIE && this.cols){ // attribute selectors is not supported in IE6
+ dojo.addClass(this.textbox, "dijitTextAreaCols");
+ }
+ },
+
+ 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);
+ },
+
+ _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.form.Textarea"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.Textarea"] = true;
+dojo.provide("dijit.form.Textarea");
+
+
+
+
+dojo.declare(
+ "dijit.form.Textarea",
+ dijit.form.SimpleTextarea,
+ {
+ // summary:
+ // A textarea widget that adjusts it's height according to the amount of data.
+ //
+ // description:
+ // A textarea that dynamically expands/contracts (changing it's height) as
+ // the user types, to display all the text without requiring a scroll bar.
+ //
+ // Takes nearly all the parameters (name, value, etc.) that a vanilla textarea takes.
+ // Rows is not supported since this widget adjusts the height.
+ //
+ // example:
+ // | <textarea dojoType="dijit.form.TextArea">...</textarea>
+
+
+ // TODO: for 2.0, rename this to ExpandingTextArea, and rename SimpleTextarea to Textarea
+
+ baseClass: "dijitTextBox dijitTextArea dijitExpandingTextArea",
+
+ // Override SimpleTextArea.cols to default to width:100%, for backward compatibility
+ cols: "",
+
+ _previousNewlines: 0,
+ _strictMode: (dojo.doc.compatMode != 'BackCompat'), // not the same as !dojo.isQuirks
+
+ _getHeight: function(textarea){
+ var newH = textarea.scrollHeight;
+ if(dojo.isIE){
+ newH += textarea.offsetHeight - textarea.clientHeight - ((dojo.isIE < 8 && this._strictMode) ? dojo._getPadBorderExtents(textarea).h : 0);
+ }else if(dojo.isMoz){
+ newH += textarea.offsetHeight - textarea.clientHeight; // creates room for horizontal scrollbar
+ }else if(dojo.isWebKit){
+ newH += dojo._getBorderExtents(textarea).h;
+ }else{ // Opera 9.6 (TODO: test if this is still needed)
+ newH += dojo._getPadBorderExtents(textarea).h;
+ }
+ return newH;
+ },
+
+ _estimateHeight: function(textarea){
+ // summary:
+ // Approximate the height when the textarea is invisible with the number of lines in the text.
+ // Fails when someone calls setValue with a long wrapping line, but the layout fixes itself when the user clicks inside so . . .
+ // In IE, the resize event is supposed to fire when the textarea becomes visible again and that will correct the size automatically.
+ //
+ textarea.style.maxHeight = "";
+ textarea.style.height = "auto";
+ // #rows = #newlines+1
+ // Note: on Moz, the following #rows appears to be 1 too many.
+ // Actually, Moz is reserving room for the scrollbar.
+ // If you increase the font size, this behavior becomes readily apparent as the last line gets cut off without the +1.
+ textarea.rows = (textarea.value.match(/\n/g) || []).length + 1;
+ },
+
+ _needsHelpShrinking: dojo.isMoz || dojo.isWebKit,
+
+ _onInput: function(){
+ // Override SimpleTextArea._onInput() to deal with height adjustment
+ this.inherited(arguments);
+ if(this._busyResizing){ return; }
+ this._busyResizing = true;
+ var textarea = this.textbox;
+ if(textarea.scrollHeight && textarea.offsetHeight && textarea.clientHeight){
+ var newH = this._getHeight(textarea) + "px";
+ if(textarea.style.height != newH){
+ textarea.style.maxHeight = textarea.style.height = newH;
+ }
+ if(this._needsHelpShrinking){
+ if(this._setTimeoutHandle){
+ clearTimeout(this._setTimeoutHandle);
+ }
+ this._setTimeoutHandle = setTimeout(dojo.hitch(this, "_shrink"), 0); // try to collapse multiple shrinks into 1
+ }
+ }else{
+ // hidden content of unknown size
+ this._estimateHeight(textarea);
+ }
+ this._busyResizing = false;
+ },
+
+ _busyResizing: false,
+ _shrink: function(){
+ // grow paddingBottom to see if scrollHeight shrinks (when it is unneccesarily big)
+ this._setTimeoutHandle = null;
+ if(this._needsHelpShrinking && !this._busyResizing){
+ this._busyResizing = true;
+ var textarea = this.textbox;
+ var empty = false;
+ if(textarea.value == ''){
+ textarea.value = ' '; // prevent collapse all the way back to 0
+ empty = true;
+ }
+ var scrollHeight = textarea.scrollHeight;
+ if(!scrollHeight){
+ this._estimateHeight(textarea);
+ }else{
+ var oldPadding = textarea.style.paddingBottom;
+ var newPadding = dojo._getPadExtents(textarea);
+ newPadding = newPadding.h - newPadding.t;
+ textarea.style.paddingBottom = newPadding + 1 + "px"; // tweak padding to see if height can be reduced
+ var newH = this._getHeight(textarea) - 1 + "px"; // see if the height changed by the 1px added
+ if(textarea.style.maxHeight != newH){ // if can be reduced, so now try a big chunk
+ textarea.style.paddingBottom = newPadding + scrollHeight + "px";
+ textarea.scrollTop = 0;
+ textarea.style.maxHeight = this._getHeight(textarea) - scrollHeight + "px"; // scrollHeight is the added padding
+ }
+ textarea.style.paddingBottom = oldPadding;
+ }
+ if(empty){
+ textarea.value = '';
+ }
+ this._busyResizing = false;
+ }
+ },
+
+ resize: function(){
+ // summary:
+ // Resizes the textarea vertically (should be called after a style/value change)
+ this._onInput();
+ },
+
+ _setValueAttr: function(){
+ this.inherited(arguments);
+ this.resize();
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ // tweak textarea style to reduce browser differences
+ dojo.style(this.textbox, { overflowY: 'hidden', overflowX: 'auto', boxSizing: 'border-box', MsBoxSizing: 'border-box', WebkitBoxSizing: 'border-box', MozBoxSizing: 'border-box' });
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ this.connect(this.textbox, "onscroll", "_onInput");
+ this.connect(this.textbox, "onresize", "_onInput");
+ this.connect(this.textbox, "onfocus", "_onInput"); // useful when a previous estimate was off a bit
+ this._setTimeoutHandle = setTimeout(dojo.hitch(this, "resize"), 0);
+ },
+
+ uninitialize: function(){
+ if(this._setTimeoutHandle){
+ clearTimeout(this._setTimeoutHandle);
+ }
+ this.inherited(arguments);
+ }
+});
+
+}
+
+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 role='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",
+
+ constructor: function(){
+ this.pane2button = {}; // mapping from pane id to buttons
+ this.pane2connects = {}; // mapping from pane id to this.connect() handles
+ this.pane2watches = {}; // mapping from pane id to watch() handles
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dijit.setWaiRole(this.domNode, "tablist"); // TODO: unneeded? it's in template above.
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // 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");
+
+
+ // map from page attribute to corresponding tab button attribute
+ var pageAttrList = ["title", "showTitle", "iconClass", "closable", "tooltip"],
+ buttonAttrList = ["label", "showLabel", "iconClass", "closeButton", "title"];
+
+ // watch() so events like page title changes are reflected in tab button
+ this.pane2watches[page.id] = dojo.map(pageAttrList, function(pageAttr, idx){
+ return page.watch(pageAttr, function(name, oldVal, newVal){
+ button.set(buttonAttrList[idx], newVal);
+ });
+ });
+
+ // connections so that clicking a tab button selects the corresponding page
+ this.pane2connects[page.id] = [
+ 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; }
+
+ // disconnect/unwatch connections/watches related to page being removed
+ dojo.forEach(this.pane2connects[page.id], dojo.hitch(this, "disconnect"));
+ delete this.pane2connects[page.id];
+ dojo.forEach(this.pane2watches[page.id], function(w){ w.unwatch(); });
+ delete this.pane2watches[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.HOME:
+ case k.END:
+ var children = this.getChildren();
+ if(children && children.length){
+ children[e.charOrCode == k.HOME ? 0 : children.length-1].onClick();
+ }
+ dojo.stopEvent(e);
+ 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 next/previous page navigation (left/right arrow, etc.)
+ 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",
+
+ buildRendering: function(/*Event*/ evt){
+ this.inherited(arguments);
+ dijit.setWaiRole((this.focusNode || this.domNode), "tab");
+ },
+
+ 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,
+=====*/
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dojo.addClass(this.domNode, "dijitLayoutContainer");
+ dijit.setWaiRole(this.containerNode, "tabpanel");
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ 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.replaceClass(child.domNode, "dijitHidden", "dijitVisible");
+
+ // 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
+ var d = this._transition(page, this.selectedChildWidget, animate);
+ this._set("selectedChildWidget", page);
+ dojo.publish(this.id+"-selectChild", [page]);
+
+ if(this.persist){
+ dojo.cookie(this.id + "_selectedChild", this.selectedChildWidget.id);
+ }
+ }
+
+ return d; // If child has an href, promise that fires when the child's href finishes loading
+ },
+
+ _transition: function(/*dijit._Widget*/ newWidget, /*dijit._Widget*/ oldWidget, /*Boolean*/ animate){
+ // summary:
+ // Hide the old widget and display the new widget.
+ // Subclasses should override this.
+ // tags:
+ // protected extension
+ if(oldWidget){
+ this._hideChild(oldWidget);
+ }
+ var d = 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();
+ }
+ }
+
+ return d; // If child has an href, promise that fires when the child's href finishes loading
+ },
+
+ _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.
+ return this.selectChild(this._adjacent(true), true);
+ },
+
+ back: function(){
+ // summary:
+ // Go back to previous page.
+ return 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.
+ // returns:
+ // Promise that fires when page has finished showing, or true if there's no href
+ var children = this.getChildren();
+ page.isFirstChild = (page == children[0]);
+ page.isLastChild = (page == children[children.length-1]);
+ page._set("selected", true);
+
+ dojo.replaceClass(page.domNode, "dijitVisible", "dijitHidden");
+
+ return page._onShow() || true;
+ },
+
+ _hideChild: function(/*dijit._Widget*/ page){
+ // summary:
+ // Hide the specified child by changing it's CSS, and call _onHide() so
+ // it's notified.
+ page._set("selected", false);
+ dojo.replaceClass(page.domNode, "dijitHidden", "dijitVisible");
+
+ 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");
+
+
+
+
+
+
+
+
+
+//dojo.require("dijit.layout.AccordionPane "); // for back compat, remove for 2.0
+
+// Design notes:
+//
+// An AccordionContainer is a StackContainer, but each child (typically ContentPane)
+// is wrapped in a _AccordionInnerContainer. This is hidden from the caller.
+//
+// The resulting markup will look like:
+//
+// <div class=dijitAccordionContainer>
+// <div class=dijitAccordionInnerContainer> (one pane)
+// <div class=dijitAccordionTitle> (title bar) ... </div>
+// <div class=dijtAccordionChildWrapper> (content pane) </div>
+// </div>
+// </div>
+//
+// Normally the dijtAccordionChildWrapper is hidden for all but one child (the shown
+// child), so the space for the content pane is all the title bars + the one dijtAccordionChildWrapper,
+// which on claro has a 1px border plus a 2px bottom margin.
+//
+// During animation there are two dijtAccordionChildWrapper's shown, so we need
+// to compensate for that.
+
+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",
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ this.domNode.style.overflow = "hidden"; // TODO: put this in dijit.css
+ dijit.setWaiRole(this.domNode, "tablist"); // TODO: put this in template
+ },
+
+ 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);
+ }
+ },
+
+ 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;}
+
+ // space taken up by title, plus wrapper div (with border/margin) for open pane
+ var wrapperDomNode = openPane._wrapperWidget.domNode,
+ wrapperDomNodeMargin = dojo._getMarginExtents(wrapperDomNode),
+ wrapperDomNodePadBorder = dojo._getPadBorderExtents(wrapperDomNode),
+ wrapperContainerNode = openPane._wrapperWidget.containerNode,
+ wrapperContainerNodeMargin = dojo._getMarginExtents(wrapperContainerNode),
+ wrapperContainerNodePadBorder = dojo._getPadBorderExtents(wrapperContainerNode),
+ 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._getMarginSize(child._wrapperWidget.domNode).h;
+ }
+ });
+ this._verticalSpace = mySize.h - totalCollapsedHeight - wrapperDomNodeMargin.h
+ - wrapperDomNodePadBorder.h - wrapperContainerNodeMargin.h - wrapperContainerNodePadBorder.h
+ - openPane._buttonWidget.getTitleHeight();
+
+ // Memo size to make displayed child
+ this._containerContentBox = {
+ h: this._verticalSpace,
+ w: this._contentBox.w - wrapperDomNodeMargin.w - wrapperDomNodePadBorder.w
+ - wrapperContainerNodeMargin.w - wrapperContainerNodePadBorder.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.
+ // Replace wrapper widget with true child widget (ContentPane etc.).
+ // This step only happens if the AccordionContainer has been started; otherwise there's no wrapper.
+ if(child._wrapperWidget){
+ dojo.place(child.domNode, child._wrapperWidget.domNode, "after");
+ 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(){
+ if(this._animation){
+ this._animation.stop();
+ }
+ dojo.forEach(this.getChildren(), function(child){
+ // If AccordionContainer has been started, then each child has a wrapper widget which
+ // also needs to be destroyed.
+ if(child._wrapperWidget){
+ child._wrapperWidget.destroy();
+ }else{
+ child.destroyRecursive();
+ }
+ });
+ this.inherited(arguments);
+ },
+
+ _showChild: function(child){
+ // Override StackContainer._showChild() to set visibility of _wrapperWidget.containerNode
+ child._wrapperWidget.containerNode.style.display="block";
+ return this.inherited(arguments);
+ },
+
+ _hideChild: function(child){
+ // Override StackContainer._showChild() to set visibility of _wrapperWidget.containerNode
+ child._wrapperWidget.containerNode.style.display="none";
+ this.inherited(arguments);
+ },
+
+ _transition: function(/*dijit._Widget?*/ newWidget, /*dijit._Widget?*/ oldWidget, /*Boolean*/ animate){
+ // Overrides StackContainer._transition() to provide sliding of title bars etc.
+
+ if(dojo.isIE < 8){
+ // workaround animation bugs by not animating; not worth supporting animation for IE6 & 7
+ animate = false;
+ }
+
+ if(this._animation){
+ // there's an in-progress animation. speedily end it so we can do the newly requested one
+ this._animation.stop(true);
+ delete this._animation;
+ }
+
+ var self = this;
+
+ if(newWidget){
+ newWidget._wrapperWidget.set("selected", true);
+
+ var d = 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);
+ }
+ }
+
+ if(oldWidget){
+ oldWidget._wrapperWidget.set("selected", false);
+ if(!animate){
+ this._hideChild(oldWidget);
+ }
+ }
+
+ if(animate){
+ var newContents = newWidget._wrapperWidget.containerNode,
+ oldContents = oldWidget._wrapperWidget.containerNode;
+
+ // During the animation we will be showing two dijitAccordionChildWrapper nodes at once,
+ // which on claro takes up 4px extra space (compared to stable AccordionContainer).
+ // Have to compensate for that by immediately shrinking the pane being closed.
+ var wrapperContainerNode = newWidget._wrapperWidget.containerNode,
+ wrapperContainerNodeMargin = dojo._getMarginExtents(wrapperContainerNode),
+ wrapperContainerNodePadBorder = dojo._getPadBorderExtents(wrapperContainerNode),
+ animationHeightOverhead = wrapperContainerNodeMargin.h + wrapperContainerNodePadBorder.h;
+
+ oldContents.style.height = (self._verticalSpace - animationHeightOverhead) + "px";
+
+ this._animation = new dojo.Animation({
+ node: newContents,
+ duration: this.duration,
+ curve: [1, this._verticalSpace - animationHeightOverhead - 1],
+ onAnimate: function(value){
+ value = Math.floor(value); // avoid fractional values
+ newContents.style.height = value + "px";
+ oldContents.style.height = (self._verticalSpace - animationHeightOverhead - value) + "px";
+ },
+ onEnd: function(){
+ delete self._animation;
+ newContents.style.height = "auto";
+ oldWidget._wrapperWidget.containerNode.style.display = "none";
+ oldContents.style.height = "auto";
+ self._hideChild(oldWidget);
+ }
+ });
+ this._animation.onStop = this._animation.onEnd;
+ this._animation.play();
+ }
+
+ return d; // If child has an href, promise that fires when the widget has finished loading
+ },
+
+ // 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.disabled || e.altKey || !(fromTitle || e.ctrlKey)){
+ 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(){
+ // Builds a template like:
+ // <div class=dijitAccordionInnerContainer>
+ // Button
+ // <div class=dijitAccordionChildWrapper>
+ // ContentPane
+ // </div>
+ // </div>
+
+ // 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),
+ // wrapped by a <div class=dijitAccordionChildWrapper>
+ this.containerNode = dojo.place("<div class='dijitAccordionChildWrapper' style='display:none'>", this.domNode);
+ dojo.place(this.contentWidget.domNode, this.containerNode);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // Map changes in content widget's title etc. to changes in the button
+ var button = this.button;
+ this._contentWidgetWatches = [
+ this.contentWidget.watch('title', dojo.hitch(this, function(name, oldValue, newValue){
+ button.set("label", newValue);
+ })),
+ this.contentWidget.watch('tooltip', dojo.hitch(this, function(name, oldValue, newValue){
+ button.set("title", newValue);
+ })),
+ this.contentWidget.watch('iconClass', dojo.hitch(this, function(name, oldValue, newValue){
+ button.set("iconClass", newValue);
+ }))
+ ];
+ },
+
+ _setSelectedAttr: function(/*Boolean*/ isSelected){
+ this._set("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();
+
+ dojo.forEach(this._contentWidgetWatches || [], function(w){ w.unwatch(); });
+
+ 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'>\r\n\t<div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='onkeypress:_onTitleKeyPress'\r\n\t\t\tclass='dijitAccordionTitleFocus' role=\"tab\" aria-expanded=\"false\"\r\n\t\t><span class='dijitInline dijitAccordionArrow' role=\"presentation\"></span\r\n\t\t><span class='arrowTextUp' role=\"presentation\">+</span\r\n\t\t><span class='arrowTextDown' role=\"presentation\">-</span\r\n\t\t><img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' style=\"vertical-align: middle\" role=\"presentation\"/>\r\n\t\t<span role=\"presentation\" dojoAttachPoint='titleTextNode' class='dijitAccordionText'></span>\r\n\t</div>\r\n</div>\r\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;
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ var titleTextNodeId = this.id.replace(' ','_');
+ dojo.attr(this.titleTextNode, "id", titleTextNodeId+"_title");
+ dijit.setWaiState(this.focusNode, "labelledby", dojo.attr(this.titleTextNode, "id"));
+ dojo.setSelectable(this.domNode, false);
+ },
+
+ getTitleHeight: function(){
+ // summary:
+ // Returns the height of the title dom node.
+ return dojo._getMarginSize(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();
+ 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._set("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.
+ //
+ // 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.
+ //
+ // For complex layouts, multiple children can be specified for a single region. In this case, the
+ // layoutPriority flag on the children determines which child is closer to the edge (low layoutPriority)
+ // and which child is closer to the center (high layoutPriority). layoutPriority can also be used
+ // instead of the design attribute to conrol layout precedence of horizontal vs. vertical panes.
+ // example:
+ // | <div dojoType="dijit.layout.BorderContainer" design="sidebar" gutters="false"
+ // | style="width: 400px; height: 300px;">
+ // | <div dojoType="dijit.layout.ContentPane" region="top">header text</div>
+ // | <div dojoType="dijit.layout.ContentPane" region="right" splitter="true" style="width: 200px;">table of contents</div>
+ // | <div dojoType="dijit.layout.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: [const] 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: [const] 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);
+ },
+
+ 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"; }
+
+ // Create draggable splitter for resizing pane,
+ // or alternately if splitter=false but BorderContainer.gutters=true then
+ // insert dummy div just for spacing
+ if(region != "center" && (child.splitter || this.gutters) && !child._splitterWidget){
+ 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;
+ child._splitterWidget = splitter;
+
+ dojo.place(splitter.domNode, child.domNode, "after");
+
+ // Splitters aren't added as Contained children, so we need to call startup explicitly
+ splitter.startup();
+ }
+ child.region = region; // TODO: technically wrong since it overwrites "trailing" with "left" etc.
+ }
+ },
+
+ layout: function(){
+ // Implement _LayoutWidget.layout() virtual method.
+ 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 = child._splitterWidget
+ if(splitter){
+ splitter.destroy();
+ delete child._splitterWidget;
+ }
+ this.inherited(arguments);
+
+ if(this._started){
+ this._layoutChildren();
+ }
+ // Clean up whatever style changes we made to the child pane.
+ // Unclear how height and width should be handled.
+ dojo.removeClass(child.domNode, this.baseClass+"Pane");
+ dojo.style(child.domNode, {
+ top: "auto",
+ bottom: "auto",
+ left: "auto",
+ right: "auto",
+ position: "static"
+ });
+ dojo.style(child.domNode, region == "top" || region == "bottom" ? "width" : "height", "auto");
+ },
+
+ getChildren: function(){
+ // Override _LayoutWidget.getChildren() to only return real children, not the splitters.
+ return dojo.filter(this.inherited(arguments), function(widget){
+ return !widget.isSplitter;
+ });
+ },
+
+ // TODO: remove in 2.0
+ getSplitter: function(/*String*/region){
+ // summary:
+ // Returns the widget responsible for rendering the splitter associated with region
+ // tags:
+ // deprecated
+ return dojo.filter(this.getChildren(), function(child){
+ return child.region == region;
+ })[0]._splitterWidget;
+ },
+
+ 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?*/ changedChildId, /*Number?*/ changedChildSize){
+ // 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.
+ // changedChildId:
+ // Id of the child which should be resized because splitter was dragged.
+ // changedChildSize:
+ // The new width/height (in pixels) to make specified child
+
+ 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;
+ }
+
+ // Generate list of wrappers of my children in the order that I want layoutChildren()
+ // to process them (i.e. from the outside to the inside)
+ var wrappers = dojo.map(this.getChildren(), function(child, idx){
+ return {
+ pane: child,
+ weight: [
+ child.region == "center" ? Infinity : 0,
+ child.layoutPriority,
+ (this.design == "sidebar" ? 1 : -1) * (/top|bottom/.test(child.region) ? 1 : -1),
+ idx
+ ]
+ };
+ }, this);
+ wrappers.sort(function(a, b){
+ var aw = a.weight, bw = b.weight;
+ for(var i=0; i<aw.length; i++){
+ if(aw[i] != bw[i]){
+ return aw[i] - bw[i];
+ }
+ }
+ return 0;
+ });
+
+ // Make new list, combining the externally specified children with splitters and gutters
+ var childrenAndSplitters = [];
+ dojo.forEach(wrappers, function(wrapper){
+ var pane = wrapper.pane;
+ childrenAndSplitters.push(pane);
+ if(pane._splitterWidget){
+ childrenAndSplitters.push(pane._splitterWidget);
+ }
+ });
+
+ // Compute the box in which to lay out my children
+ var dim = {
+ l: this.pe.l,
+ t: this.pe.t,
+ w: this._borderBox.w - this.pe.w,
+ h: this._borderBox.h - this.pe.h
+ };
+
+ // Layout the children, possibly changing size due to a splitter drag
+ dijit.layout.layoutChildren(this.domNode, dim, childrenAndSplitters,
+ changedChildId, changedChildSize);
+ },
+
+ destroyRecursive: function(){
+ // Destroy splitters first, while getChildren() still works
+ dojo.forEach(this.getChildren(), function(child){
+ var splitter = child._splitterWidget;
+ if(splitter){
+ splitter.destroy();
+ }
+ delete child._splitterWidget;
+ });
+
+ // Then destroy the real children, and myself
+ 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: '',
+
+ // layoutPriority: [const] Number
+ // Parameter for children of `dijit.layout.BorderContainer`.
+ // Children with a higher layoutPriority will be placed closer to the BorderContainer center,
+ // between children with a lower layoutPriority.
+ layoutPriority: 0,
+
+ // 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: [const] 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" role="separator"><div class="dijitSplitterThumb"></div></div>',
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+
+ this.horizontal = /top|bottom/.test(this.region);
+ this._factor = /top|left/.test(this.region) ? 1 : -1;
+ this._cookieName = this.container.id + "_" + this.region;
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ dojo.addClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V"));
+
+ 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:
+ // Return the maximum size that my corresponding pane can be set to
+
+ var dim = this.horizontal ? 'h' : 'w',
+ childSize = dojo.marginBox(this.child.domNode)[dim],
+ center = dojo.filter(this.container.getChildren(), function(child){ return child.region == "center";})[0],
+ spaceAvailable = dojo.marginBox(center.domNode)[dim]; // can expand until center is crushed to 0
+
+ return Math.min(this.child.maxSize, childSize + spaceAvailable);
+ },
+
+ _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 dijitSplitter" + (this.horizontal ? "H" : "V") + "Active");
+ if(this.fake){
+ dojo.removeClass(this.fake, "dijitSplitterHover dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover");
+ }
+
+ //Performance: load data info local vars for onmousevent function closure
+ var factor = this._factor,
+ 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],
+ max = this._computeMaxSize(),
+ min = this.child.minSize || 20,
+ region = this.region,
+ splitterAttr = region == "top" || region == "bottom" ? "top" : "left", // style attribute of splitter to adjust
+ splitterStart = parseInt(splitterStyle[splitterAttr], 10),
+ resize = this._resize,
+ layoutFunc = dojo.hitch(this.container, "_layoutChildren", this.child.id),
+ 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(boundChildSize);
+ }
+ // TODO: setting style directly (usually) sets content box size, need to set margin box size
+ splitterStyle[splitterAttr] = delta + splitterStart + factor*(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 dijitSplitter"
+ + (this.horizontal ? "H" : "V") + "Active 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._getMarginSize(this.child.domNode)[ horizontal ? 'h' : 'w' ] + this._factor * tick;
+ this.container._layoutChildren(this.child.id, 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" role="presentation"></div>',
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this.horizontal = /top|bottom/.test(this.region);
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dojo.addClass(this.domNode, "dijitGutter" + (this.horizontal ? "H" : "V"));
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.layout.LayoutContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.LayoutContainer"] = true;
+dojo.provide("dijit.layout.LayoutContainer");
+
+
+
+
+dojo.declare("dijit.layout.LayoutContainer",
+ dijit.layout._LayoutWidget,
+ {
+ // summary:
+ // Deprecated. Use `dijit.layout.BorderContainer` instead.
+ //
+ // description:
+ // Provides Delphi-style panel layout semantics.
+ //
+ // A LayoutContainer is a box with a specified size (like style="width: 500px; height: 500px;"),
+ // that contains children widgets marked with "layoutAlign" of "left", "right", "bottom", "top", and "client".
+ // It takes it's children marked as left/top/bottom/right, and lays them out along the edges of the box,
+ // and then it takes the child marked "client" and puts it into the remaining space in the middle.
+ //
+ // Left/right positioning is similar to CSS's "float: left" and "float: right",
+ // and top/bottom positioning would be similar to "float: top" and "float: bottom", if there were such
+ // CSS.
+ //
+ // Note that there can only be one client element, but there can be multiple left, right, top,
+ // or bottom elements.
+ //
+ // example:
+ // | <style>
+ // | html, body{ height: 100%; width: 100%; }
+ // | </style>
+ // | <div dojoType="dijit.layout.LayoutContainer" style="width: 100%; height: 100%">
+ // | <div dojoType="dijit.layout.ContentPane" layoutAlign="top">header text</div>
+ // | <div dojoType="dijit.layout.ContentPane" layoutAlign="left" style="width: 200px;">table of contents</div>
+ // | <div dojoType="dijit.layout.ContentPane" layoutAlign="client">client area</div>
+ // | </div>
+ //
+ // Lays out each child in the natural order the children occur in.
+ // Basically each child is laid out into the "remaining space", where "remaining space" is initially
+ // the content area of this widget, but is reduced to a smaller rectangle each time a child is added.
+ // tags:
+ // deprecated
+
+ baseClass: "dijitLayoutContainer",
+
+ constructor: function(){
+ dojo.deprecated("dijit.layout.LayoutContainer is deprecated", "use BorderContainer instead", 2.0);
+ },
+
+ layout: function(){
+ dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ this.inherited(arguments);
+ if(this._started){
+ dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
+ }
+ },
+
+ removeChild: function(/*dijit._Widget*/ widget){
+ this.inherited(arguments);
+ if(this._started){
+ dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
+ }
+ }
+});
+
+// This argument can be specified for the children of a LayoutContainer.
+// 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, {
+ // layoutAlign: String
+ // "none", "left", "right", "bottom", "top", and "client".
+ // See the LayoutContainer description for details on this parameter.
+ layoutAlign: 'none'
+});
+
+}
+
+if(!dojo._hasResource["dijit.layout.LinkPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.LinkPane"] = true;
+dojo.provide("dijit.layout.LinkPane");
+
+
+
+
+
+dojo.declare("dijit.layout.LinkPane",
+ [dijit.layout.ContentPane, dijit._Templated],
+ {
+ // summary:
+ // A ContentPane with an href where (when declared in markup)
+ // the title is specified as innerHTML rather than as a title attribute.
+ // description:
+ // LinkPane is just a ContentPane that is declared in markup similarly
+ // to an anchor. The anchor's body (the words between `<a>` and `</a>`)
+ // become the title of the widget (used for TabContainer, AccordionContainer, etc.)
+ // example:
+ // | <a href="foo.html">my title</a>
+
+ // I'm using a template because the user may specify the input as
+ // <a href="foo.html">title</a>, in which case we need to get rid of the
+ // <a> because we don't want a link.
+ templateString: '<div class="dijitLinkPane" dojoAttachPoint="containerNode"></div>',
+
+ postMixInProperties: function(){
+ // If user has specified node contents, they become the title
+ // (the link must be plain text)
+ if(this.srcNodeRef){
+ this.title += this.srcNodeRef.innerHTML;
+ }
+ this.inherited(arguments);
+ },
+
+ _fillContent: function(/*DomNode*/ source){
+ // Overrides _Templated._fillContent().
+
+ // _Templated._fillContent() relocates srcNodeRef innerHTML to templated container node,
+ // but in our case the srcNodeRef innerHTML is the title, so shouldn't be
+ // copied
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit.layout.SplitContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout.SplitContainer"] = true;
+dojo.provide("dijit.layout.SplitContainer");
+
+
+
+
+
+//
+// FIXME: make it prettier
+// FIXME: active dragging upwards doesn't always shift other bars (direction calculation is wrong in this case)
+//
+
+
+dojo.declare("dijit.layout.SplitContainer",
+ dijit.layout._LayoutWidget,
+ {
+ // summary:
+ // Deprecated. Use `dijit.layout.BorderContainer` instead.
+ // description:
+ // A Container widget with sizing handles in-between each child.
+ // Contains multiple children widgets, all of which are displayed side by side
+ // (either horizontally or vertically); there's a bar between each of the children,
+ // and you can adjust the relative size of each child by dragging the bars.
+ //
+ // You must specify a size (width and height) for the SplitContainer.
+ // tags:
+ // deprecated
+
+ constructor: function(){
+ dojo.deprecated("dijit.layout.SplitContainer is deprecated", "use BorderContainer with splitter instead", 2.0);
+ },
+
+ // activeSizing: Boolean
+ // If true, the children's size changes as you drag the bar;
+ // otherwise, the sizes don't change until you drop the bar (by mouse-up)
+ activeSizing: false,
+
+ // sizerWidth: Integer
+ // Size in pixels of the bar between each child
+ sizerWidth: 7, // FIXME: this should be a CSS attribute (at 7 because css wants it to be 7 until we fix to css)
+
+ // orientation: String
+ // either 'horizontal' or vertical; indicates whether the children are
+ // arranged side-by-side or up/down.
+ orientation: 'horizontal',
+
+ // persist: Boolean
+ // Save splitter positions in a cookie
+ persist: true,
+
+ baseClass: "dijitSplitContainer",
+
+ postMixInProperties: function(){
+ this.inherited("postMixInProperties",arguments);
+ this.isHorizontal = (this.orientation == 'horizontal');
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.sizers = [];
+
+ // overflow has to be explicitly hidden for splitContainers using gekko (trac #1435)
+ // to keep other combined css classes from inadvertantly making the overflow visible
+ if(dojo.isMozilla){
+ this.domNode.style.overflow = '-moz-scrollbars-none'; // hidden doesn't work
+ }
+
+ // create the fake dragger
+ if(typeof this.sizerWidth == "object"){
+ try{ //FIXME: do this without a try/catch
+ this.sizerWidth = parseInt(this.sizerWidth.toString());
+ }catch(e){ this.sizerWidth = 7; }
+ }
+ var sizer = dojo.doc.createElement('div');
+ this.virtualSizer = sizer;
+ sizer.style.position = 'relative';
+
+ // #1681: work around the dreaded 'quirky percentages in IE' layout bug
+ // If the splitcontainer's dimensions are specified in percentages, it
+ // will be resized when the virtualsizer is displayed in _showSizingLine
+ // (typically expanding its bounds unnecessarily). This happens because
+ // we use position: relative for .dijitSplitContainer.
+ // The workaround: instead of changing the display style attribute,
+ // switch to changing the zIndex (bring to front/move to back)
+
+ sizer.style.zIndex = 10;
+ sizer.className = this.isHorizontal ? 'dijitSplitContainerVirtualSizerH' : 'dijitSplitContainerVirtualSizerV';
+ this.domNode.appendChild(sizer);
+ dojo.setSelectable(sizer, false);
+ },
+
+ destroy: function(){
+ delete this.virtualSizer;
+ dojo.forEach(this._ownconnects, dojo.disconnect);
+ this.inherited(arguments);
+ },
+ startup: function(){
+ if(this._started){ return; }
+
+ dojo.forEach(this.getChildren(), function(child, i, children){
+ // attach the children and create the draggers
+ this._setupChild(child);
+
+ if(i < children.length-1){
+ this._addSizer();
+ }
+ }, this);
+
+ if(this.persist){
+ this._restoreState();
+ }
+
+ this.inherited(arguments);
+ },
+
+ _setupChild: function(/*dijit._Widget*/ child){
+ this.inherited(arguments);
+ child.domNode.style.position = "absolute";
+ dojo.addClass(child.domNode, "dijitSplitPane");
+ },
+
+ _onSizerMouseDown: function(e){
+ if(e.target.id){
+ for(var i=0;i<this.sizers.length;i++){
+ if(this.sizers[i].id == e.target.id){
+ break;
+ }
+ }
+ if(i<this.sizers.length){
+ this.beginSizing(e,i);
+ }
+ }
+ },
+ _addSizer: function(index){
+ index = index === undefined ? this.sizers.length : index;
+
+ // TODO: use a template for this!!!
+ var sizer = dojo.doc.createElement('div');
+ sizer.id=dijit.getUniqueId('dijit_layout_SplitterContainer_Splitter');
+ this.sizers.splice(index,0,sizer);
+ this.domNode.appendChild(sizer);
+
+ sizer.className = this.isHorizontal ? 'dijitSplitContainerSizerH' : 'dijitSplitContainerSizerV';
+
+ // add the thumb div
+ var thumb = dojo.doc.createElement('div');
+ thumb.className = 'thumb';
+ sizer.appendChild(thumb);
+
+ // FIXME: are you serious? why aren't we using mover start/stop combo?
+ this.connect(sizer, "onmousedown", '_onSizerMouseDown');
+
+ dojo.setSelectable(sizer, false);
+ },
+
+ removeChild: function(widget){
+ // summary:
+ // Remove sizer, but only if widget is really our child and
+ // we have at least one sizer to throw away
+ if(this.sizers.length){
+ var i=dojo.indexOf(this.getChildren(), widget)
+ if(i != -1){
+ if(i == this.sizers.length){
+ i--;
+ }
+ dojo.destroy(this.sizers[i]);
+ this.sizers.splice(i,1);
+ }
+ }
+
+ // Remove widget and repaint
+ this.inherited(arguments);
+ if(this._started){
+ this.layout();
+ }
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ // summary:
+ // Add a child widget to the container
+ // child:
+ // a widget to add
+ // insertIndex:
+ // postion in the "stack" to add the child widget
+
+ this.inherited(arguments);
+
+ if(this._started){
+ // Do the stuff that startup() does for each widget
+ var children = this.getChildren();
+ if(children.length > 1){
+ this._addSizer(insertIndex);
+ }
+
+ // and then reposition (ie, shrink) every pane to make room for the new guy
+ this.layout();
+ }
+ },
+
+ layout: function(){
+ // summary:
+ // Do layout of panels
+
+ // base class defines this._contentBox on initial creation and also
+ // on resize
+ this.paneWidth = this._contentBox.w;
+ this.paneHeight = this._contentBox.h;
+
+ var children = this.getChildren();
+ if(!children.length){ return; }
+
+ //
+ // calculate space
+ //
+
+ var space = this.isHorizontal ? this.paneWidth : this.paneHeight;
+ if(children.length > 1){
+ space -= this.sizerWidth * (children.length - 1);
+ }
+
+ //
+ // calculate total of SizeShare values
+ //
+ var outOf = 0;
+ dojo.forEach(children, function(child){
+ outOf += child.sizeShare;
+ });
+
+ //
+ // work out actual pixels per sizeshare unit
+ //
+ var pixPerUnit = space / outOf;
+
+ //
+ // set the SizeActual member of each pane
+ //
+ var totalSize = 0;
+ dojo.forEach(children.slice(0, children.length - 1), function(child){
+ var size = Math.round(pixPerUnit * child.sizeShare);
+ child.sizeActual = size;
+ totalSize += size;
+ });
+
+ children[children.length-1].sizeActual = space - totalSize;
+
+ //
+ // make sure the sizes are ok
+ //
+ this._checkSizes();
+
+ //
+ // now loop, positioning each pane and letting children resize themselves
+ //
+
+ var pos = 0;
+ var size = children[0].sizeActual;
+ this._movePanel(children[0], pos, size);
+ children[0].position = pos;
+ pos += size;
+
+ // if we don't have any sizers, our layout method hasn't been called yet
+ // so bail until we are called..TODO: REVISIT: need to change the startup
+ // algorithm to guaranteed the ordering of calls to layout method
+ if(!this.sizers){
+ return;
+ }
+
+ dojo.some(children.slice(1), function(child, i){
+ // error-checking
+ if(!this.sizers[i]){
+ return true;
+ }
+ // first we position the sizing handle before this pane
+ this._moveSlider(this.sizers[i], pos, this.sizerWidth);
+ this.sizers[i].position = pos;
+ pos += this.sizerWidth;
+
+ size = child.sizeActual;
+ this._movePanel(child, pos, size);
+ child.position = pos;
+ pos += size;
+ }, this);
+ },
+
+ _movePanel: function(panel, pos, size){
+ if(this.isHorizontal){
+ panel.domNode.style.left = pos + 'px'; // TODO: resize() takes l and t parameters too, don't need to set manually
+ panel.domNode.style.top = 0;
+ var box = {w: size, h: this.paneHeight};
+ if(panel.resize){
+ panel.resize(box);
+ }else{
+ dojo.marginBox(panel.domNode, box);
+ }
+ }else{
+ panel.domNode.style.left = 0; // TODO: resize() takes l and t parameters too, don't need to set manually
+ panel.domNode.style.top = pos + 'px';
+ var box = {w: this.paneWidth, h: size};
+ if(panel.resize){
+ panel.resize(box);
+ }else{
+ dojo.marginBox(panel.domNode, box);
+ }
+ }
+ },
+
+ _moveSlider: function(slider, pos, size){
+ if(this.isHorizontal){
+ slider.style.left = pos + 'px';
+ slider.style.top = 0;
+ dojo.marginBox(slider, { w: size, h: this.paneHeight });
+ }else{
+ slider.style.left = 0;
+ slider.style.top = pos + 'px';
+ dojo.marginBox(slider, { w: this.paneWidth, h: size });
+ }
+ },
+
+ _growPane: function(growth, pane){
+ if(growth > 0){
+ if(pane.sizeActual > pane.sizeMin){
+ if((pane.sizeActual - pane.sizeMin) > growth){
+
+ // stick all the growth in this pane
+ pane.sizeActual = pane.sizeActual - growth;
+ growth = 0;
+ }else{
+ // put as much growth in here as we can
+ growth -= pane.sizeActual - pane.sizeMin;
+ pane.sizeActual = pane.sizeMin;
+ }
+ }
+ }
+ return growth;
+ },
+
+ _checkSizes: function(){
+
+ var totalMinSize = 0;
+ var totalSize = 0;
+ var children = this.getChildren();
+
+ dojo.forEach(children, function(child){
+ totalSize += child.sizeActual;
+ totalMinSize += child.sizeMin;
+ });
+
+ // only make adjustments if we have enough space for all the minimums
+
+ if(totalMinSize <= totalSize){
+
+ var growth = 0;
+
+ dojo.forEach(children, function(child){
+ if(child.sizeActual < child.sizeMin){
+ growth += child.sizeMin - child.sizeActual;
+ child.sizeActual = child.sizeMin;
+ }
+ });
+
+ if(growth > 0){
+ var list = this.isDraggingLeft ? children.reverse() : children;
+ dojo.forEach(list, function(child){
+ growth = this._growPane(growth, child);
+ }, this);
+ }
+ }else{
+ dojo.forEach(children, function(child){
+ child.sizeActual = Math.round(totalSize * (child.sizeMin / totalMinSize));
+ });
+ }
+ },
+
+ beginSizing: function(e, i){
+ var children = this.getChildren();
+ this.paneBefore = children[i];
+ this.paneAfter = children[i+1];
+
+ this.isSizing = true;
+ this.sizingSplitter = this.sizers[i];
+
+ if(!this.cover){
+ this.cover = dojo.create('div', {
+ style: {
+ position:'absolute',
+ zIndex:5,
+ top: 0,
+ left: 0,
+ width: "100%",
+ height: "100%"
+ }
+ }, this.domNode);
+ }else{
+ this.cover.style.zIndex = 5;
+ }
+ this.sizingSplitter.style.zIndex = 6;
+
+ // TODO: REVISIT - we want MARGIN_BOX and core hasn't exposed that yet (but can't we use it anyway if we pay attention? we do elsewhere.)
+ this.originPos = dojo.position(children[0].domNode, true);
+ if(this.isHorizontal){
+ var client = e.layerX || e.offsetX || 0;
+ var screen = e.pageX;
+ this.originPos = this.originPos.x;
+ }else{
+ var client = e.layerY || e.offsetY || 0;
+ var screen = e.pageY;
+ this.originPos = this.originPos.y;
+ }
+ this.startPoint = this.lastPoint = screen;
+ this.screenToClientOffset = screen - client;
+ this.dragOffset = this.lastPoint - this.paneBefore.sizeActual - this.originPos - this.paneBefore.position;
+
+ if(!this.activeSizing){
+ this._showSizingLine();
+ }
+
+ //
+ // attach mouse events
+ //
+ this._ownconnects = [];
+ this._ownconnects.push(dojo.connect(dojo.doc.documentElement, "onmousemove", this, "changeSizing"));
+ this._ownconnects.push(dojo.connect(dojo.doc.documentElement, "onmouseup", this, "endSizing"));
+
+ dojo.stopEvent(e);
+ },
+
+ changeSizing: function(e){
+ if(!this.isSizing){ return; }
+ this.lastPoint = this.isHorizontal ? e.pageX : e.pageY;
+ this.movePoint();
+ if(this.activeSizing){
+ this._updateSize();
+ }else{
+ this._moveSizingLine();
+ }
+ dojo.stopEvent(e);
+ },
+
+ endSizing: function(e){
+ if(!this.isSizing){ return; }
+ if(this.cover){
+ this.cover.style.zIndex = -1;
+ }
+ if(!this.activeSizing){
+ this._hideSizingLine();
+ }
+
+ this._updateSize();
+
+ this.isSizing = false;
+
+ if(this.persist){
+ this._saveState(this);
+ }
+
+ dojo.forEach(this._ownconnects, dojo.disconnect);
+ },
+
+ movePoint: function(){
+
+ // make sure lastPoint is a legal point to drag to
+ var p = this.lastPoint - this.screenToClientOffset;
+
+ var a = p - this.dragOffset;
+ a = this.legaliseSplitPoint(a);
+ p = a + this.dragOffset;
+
+ this.lastPoint = p + this.screenToClientOffset;
+ },
+
+ legaliseSplitPoint: function(a){
+
+ a += this.sizingSplitter.position;
+
+ this.isDraggingLeft = !!(a > 0);
+
+ if(!this.activeSizing){
+ var min = this.paneBefore.position + this.paneBefore.sizeMin;
+ if(a < min){
+ a = min;
+ }
+
+ var max = this.paneAfter.position + (this.paneAfter.sizeActual - (this.sizerWidth + this.paneAfter.sizeMin));
+ if(a > max){
+ a = max;
+ }
+ }
+
+ a -= this.sizingSplitter.position;
+
+ this._checkSizes();
+
+ return a;
+ },
+
+ _updateSize: function(){
+ //FIXME: sometimes this.lastPoint is NaN
+ var pos = this.lastPoint - this.dragOffset - this.originPos;
+
+ var start_region = this.paneBefore.position;
+ var end_region = this.paneAfter.position + this.paneAfter.sizeActual;
+
+ this.paneBefore.sizeActual = pos - start_region;
+ this.paneAfter.position = pos + this.sizerWidth;
+ this.paneAfter.sizeActual = end_region - this.paneAfter.position;
+
+ dojo.forEach(this.getChildren(), function(child){
+ child.sizeShare = child.sizeActual;
+ });
+
+ if(this._started){
+ this.layout();
+ }
+ },
+
+ _showSizingLine: function(){
+
+ this._moveSizingLine();
+
+ dojo.marginBox(this.virtualSizer,
+ this.isHorizontal ? { w: this.sizerWidth, h: this.paneHeight } : { w: this.paneWidth, h: this.sizerWidth });
+
+ this.virtualSizer.style.display = 'block';
+ },
+
+ _hideSizingLine: function(){
+ this.virtualSizer.style.display = 'none';
+ },
+
+ _moveSizingLine: function(){
+ var pos = (this.lastPoint - this.startPoint) + this.sizingSplitter.position;
+ dojo.style(this.virtualSizer,(this.isHorizontal ? "left" : "top"),pos+"px");
+ // this.virtualSizer.style[ this.isHorizontal ? "left" : "top" ] = pos + 'px'; // FIXME: remove this line if the previous is better
+ },
+
+ _getCookieName: function(i){
+ return this.id + "_" + i;
+ },
+
+ _restoreState: function(){
+ dojo.forEach(this.getChildren(), function(child, i){
+ var cookieName = this._getCookieName(i);
+ var cookieValue = dojo.cookie(cookieName);
+ if(cookieValue){
+ var pos = parseInt(cookieValue);
+ if(typeof pos == "number"){
+ child.sizeShare = pos;
+ }
+ }
+ }, this);
+ },
+
+ _saveState: function(){
+ if(!this.persist){
+ return;
+ }
+ dojo.forEach(this.getChildren(), function(child, i){
+ dojo.cookie(this._getCookieName(i), child.sizeShare, {expires:365});
+ }, this);
+ }
+});
+
+// These arguments can be specified for the children of a SplitContainer.
+// Since any widget can be specified as a SplitContainer child, mix them
+// into the base widget class. (This is a hack, but it's effective.)
+dojo.extend(dijit._Widget, {
+ // sizeMin: [deprecated] Integer
+ // Deprecated. Parameter for children of `dijit.layout.SplitContainer`.
+ // Minimum size (width or height) of a child of a SplitContainer.
+ // The value is relative to other children's sizeShare properties.
+ sizeMin: 10,
+
+ // sizeShare: [deprecated] Integer
+ // Deprecated. Parameter for children of `dijit.layout.SplitContainer`.
+ // Size (width or height) of a child of a SplitContainer.
+ // The value is relative to other children's sizeShare properties.
+ // For example, if there are two children and each has sizeShare=10, then
+ // each takes up 50% of the available space.
+ sizeShare: 10
+});
+
+}
+
+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: [const] Boolean
+ // Defines whether the tablist gets an extra class for layouting, putting a border/shading
+ // around the set of tabs. Not supported by claro theme.
+ tabStrip: false,
+
+ // nested: [const] 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\">\r\n\t<div class=\"dijitTabListWrapper\" dojoAttachPoint=\"tablistNode\"></div>\r\n\t<div dojoAttachPoint=\"tablistSpacer\" class=\"dijitTabSpacer ${baseClass}-spacer\"></div>\r\n\t<div class=\"dijitTabPaneWrapper ${baseClass}-container\" dojoAttachPoint=\"containerNode\"></div>\r\n</div>\r\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);
+ },
+
+ buildRendering: 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){
+ //make the tabs zero width so that they don't interfere with width calc, then reset
+ var s = this.tablist.domNode.style;
+ s.width="0";
+ var width = dojo.contentBox(this.domNode).w;
+ s.width="";
+ this.tablist.resize({w: width});
+ }
+
+ // 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 role='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 role=\"presentation\" dojoAttachPoint=\"titleNode\" dojoAttachEvent='onclick:onClick'>\r\n <div role=\"presentation\" class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>\r\n <div role=\"presentation\" class='dijitTabContent' dojoAttachPoint='tabContent'>\r\n \t<div role=\"presentation\" dojoAttachPoint='focusNode'>\r\n\t\t <img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitTabButtonIcon\" dojoAttachPoint='iconNode' />\r\n\t\t <span dojoAttachPoint='containerNode' class='tabLabel'></span>\r\n\t\t <span class=\"dijitInline dijitTabCloseButton dijitTabCloseIcon\" dojoAttachPoint='closeNode'\r\n\t\t \t\tdojoAttachEvent='onclick: onClickCloseButton' role=\"presentation\">\r\n\t\t <span dojoAttachPoint='closeText' class='dijitTabCloseText'>[x]</span\r\n\t\t ></span>\r\n\t\t\t</div>\r\n </div>\r\n </div>\r\n</div>\r\n"),
+
+ // Override _FormWidget.scrollOnFocus.
+ // Don't scroll the whole tab container into view when the button is focused.
+ scrollOnFocus: false,
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ dojo.setSelectable(this.containerNode, false);
+ },
+
+ 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(/*Boolean*/ disp){
+ // summary:
+ // Hide/show close button
+ this._set("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 set('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\">\r\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerMenuButton\"\r\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\r\n\t\t\tid=\"${id}_menuBtn\" containerId=\"${containerId}\" iconClass=\"dijitTabStripMenuIcon\"\r\n\t\t\tdropDownPosition=\"below-alt, above-alt\"\r\n\t\t\tdojoAttachPoint=\"_menuBtn\" showLabel=false>&#9660;</div>\r\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\r\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\r\n\t\t\tid=\"${id}_leftBtn\" iconClass=\"dijitTabStripSlideLeftIcon\"\r\n\t\t\tdojoAttachPoint=\"_leftBtn\" dojoAttachEvent=\"onClick: doSlideLeft\" showLabel=false>&#9664;</div>\r\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\r\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\r\n\t\t\tid=\"${id}_rightBtn\" iconClass=\"dijitTabStripSlideRightIcon\"\r\n\t\t\tdojoAttachPoint=\"_rightBtn\" dojoAttachEvent=\"onClick: doSlideRight\" showLabel=false>&#9654;</div>\r\n\t<div class='dijitTabListWrapper' dojoAttachPoint='tablistWrapper'>\r\n\t\t<div role='tablist' dojoAttachEvent='onkeypress:onkeypress'\r\n\t\t\t\tdojoAttachPoint='containerNode' class='nowrapTabStrip'></div>\r\n\t</div>\r\n</div>\r\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: [const] 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"
+ }),
+
+ buildRendering: 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);
+
+ // changes to the tab button label or iconClass will have changed the width of the
+ // buttons, so do a resize
+ dojo.forEach(["label", "iconClass"], function(attr){
+ this.pane2watches[page.id].push(
+ this.pane2button[page.id].watch(attr, dojo.hitch(this, function(name, oldValue, newValue){
+ if(this._postStartup && this._dim){
+ this.resize(this._dim);
+ }
+ }))
+ );
+ }, this);
+
+ // 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;
+ }
+
+ 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.
+
+ // 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._getMarginSize(btn).w;
+ return true;
+ }else{
+ dojo.style(btn, "display", "none");
+ return false;
+ }
+ }, this);
+ },
+
+ _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(/*Event*/ 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(/*Event*/ e){
+ // summary:
+ // Scrolls the menu to the right.
+ // e:
+ // The mouse click event.
+ this.doSlide(1, this._getBtnNode(e));
+ },
+
+ doSlideLeft: function(/*Event*/ e){
+ // summary:
+ // Scrolls the menu to the left.
+ // e:
+ // The mouse click event.
+ this.doSlide(-1,this._getBtnNode(e));
+ },
+
+ doSlide: function(/*Number*/ direction, /*DomNode*/ 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(/*Number*/ 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._ScrollingTabControllerButtonMixin", null, {
+ baseClass: "dijitTab tabStripButton",
+
+ templateString: dojo.cache("dijit.layout", "templates/_ScrollingTabControllerButton.html", "<div dojoAttachEvent=\"onclick:_onButtonClick\">\r\n\t<div role=\"presentation\" class=\"dijitTabInnerDiv\" dojoattachpoint=\"innerDiv,focusNode\">\r\n\t\t<div role=\"presentation\" class=\"dijitTabContent dijitButtonContents\" dojoattachpoint=\"tabContent\">\r\n\t\t\t<img role=\"presentation\" alt=\"\" src=\"${_blankGif}\" class=\"dijitTabStripIcon\" dojoAttachPoint=\"iconNode\"/>\r\n\t\t\t<span dojoAttachPoint=\"containerNode,titleNode\" class=\"dijitButtonText\"></span>\r\n\t\t</div>\r\n\t</div>\r\n</div>\r\n"),
+
+ // Override inherited tabIndex: 0 from dijit.form.Button, because user shouldn't be
+ // able to tab to the left/right/menu buttons
+ tabIndex: "",
+
+ // Similarly, override FormWidget.isFocusable() because clicking a button shouldn't focus it
+ // either (this override avoids focus() call in FormWidget.js)
+ isFocusable: function(){ return false; }
+});
+
+dojo.declare("dijit.layout._ScrollingTabControllerButton",
+ [dijit.form.Button, dijit.layout._ScrollingTabControllerButtonMixin]);
+
+dojo.declare(
+ "dijit.layout._ScrollingTabControllerMenuButton",
+ [dijit.form.Button, dijit._HasDropDown, dijit.layout._ScrollingTabControllerButtonMixin],
+{
+ // id of the TabContainer itself
+ containerId: "",
+
+ // -1 so user can't tab into the button, but so that button can still be focused programatically.
+ // Because need to move focus to the button (or somewhere) before the menu is hidden or IE6 will crash.
+ tabIndex: "-1",
+
+ isLoaded: function(){
+ // recreate menu every time, in case the TabContainer's list of children (or their icons/labels) have changed
+ return false;
+ },
+
+ loadDropDown: function(callback){
+ this.dropDown = new dijit.Menu({
+ id: this.containerId + "_menu",
+ dir: this.dir,
+ lang: this.lang
+ });
+ var container = dijit.byId(this.containerId);
+ dojo.forEach(container.getChildren(), function(page){
+ var menuItem = new dijit.MenuItem({
+ id: page.id + "_stcMi",
+ label: page.title,
+ iconClass: page.iconClass,
+ dir: page.dir,
+ lang: page.lang,
+ onClick: function(){
+ container.selectChild(page);
+ }
+ });
+ this.dropDown.addChild(menuItem);
+ }, this);
+ callback();
+ },
+
+ closeDropDown: function(/*Boolean*/ focus){
+ this.inherited(arguments);
+ if(this.dropDown){
+ this.dropDown.destroyRecursive();
+ delete this.dropDown;
+ }
+ }
+});
+
+}
+
+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["dijit.dijit-all"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.dijit-all"] = true;
+dojo.provide("dijit.dijit-all");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+console.warn("dijit-all may include much more code than your application actually requires. We strongly recommend that you investigate a custom build or the web build tool");
+
+/*=====
+dijit["dijit-all"] = {
+ // summary:
+ // A rollup that includes every dijit. You probably don't need this.
+};
+=====*/
+
+}
+
+
+;
+
+}};});