summaryrefslogtreecommitdiff
path: root/lib/dijit/form
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/form')
-rw-r--r--lib/dijit/form/Button.js463
-rw-r--r--lib/dijit/form/CheckBox.js262
-rw-r--r--lib/dijit/form/ComboBox.js1812
-rw-r--r--lib/dijit/form/ComboButton.js9
-rw-r--r--lib/dijit/form/CurrencyTextBox.js103
-rw-r--r--lib/dijit/form/DateTextBox.js34
-rw-r--r--lib/dijit/form/DropDownButton.js9
-rw-r--r--lib/dijit/form/FilteringSelect.js301
-rw-r--r--lib/dijit/form/Form.js231
-rw-r--r--lib/dijit/form/HorizontalRule.js92
-rw-r--r--lib/dijit/form/HorizontalRuleLabels.js115
-rw-r--r--lib/dijit/form/HorizontalSlider.js526
-rw-r--r--lib/dijit/form/MappedTextBox.js9
-rw-r--r--lib/dijit/form/MultiSelect.js148
-rw-r--r--lib/dijit/form/NumberSpinner.js89
-rw-r--r--lib/dijit/form/NumberTextBox.js370
-rw-r--r--lib/dijit/form/RadioButton.js10
-rw-r--r--lib/dijit/form/RangeBoundTextBox.js9
-rw-r--r--lib/dijit/form/Select.js419
-rw-r--r--lib/dijit/form/SimpleTextarea.js144
-rw-r--r--lib/dijit/form/Slider.js13
-rw-r--r--lib/dijit/form/TextBox.js616
-rw-r--r--lib/dijit/form/Textarea.js252
-rw-r--r--lib/dijit/form/TimeTextBox.js81
-rw-r--r--lib/dijit/form/ToggleButton.js9
-rw-r--r--lib/dijit/form/ValidationTextBox.js675
-rw-r--r--lib/dijit/form/VerticalRule.js30
-rw-r--r--lib/dijit/form/VerticalRuleLabels.js30
-rw-r--r--lib/dijit/form/VerticalSlider.js39
-rw-r--r--lib/dijit/form/_DateTimeTextBox.js374
-rw-r--r--lib/dijit/form/_FormMixin.js601
-rw-r--r--lib/dijit/form/_FormSelectWidget.js867
-rw-r--r--lib/dijit/form/_FormWidget.js515
-rw-r--r--lib/dijit/form/_Spinner.js167
-rw-r--r--lib/dijit/form/nls/da/validate.js2
-rw-r--r--lib/dijit/form/nls/kk/ComboBox.js1
-rw-r--r--lib/dijit/form/nls/kk/Textarea.js1
-rw-r--r--lib/dijit/form/nls/kk/validate.js1
-rw-r--r--lib/dijit/form/nls/pl/Textarea.js2
-rw-r--r--lib/dijit/form/nls/sl/ComboBox.js2
-rw-r--r--lib/dijit/form/nls/sl/Textarea.js2
-rw-r--r--lib/dijit/form/nls/sl/validate.js2
42 files changed, 6581 insertions, 2856 deletions
diff --git a/lib/dijit/form/Button.js b/lib/dijit/form/Button.js
index 741062022..77846776f 100644
--- a/lib/dijit/form/Button.js
+++ b/lib/dijit/form/Button.js
@@ -1,127 +1,360 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.Button"]){
-dojo._hasResource["dijit.form.Button"]=true;
+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.require("dijit.form._FormWidget");
dojo.require("dijit._Container");
dojo.require("dijit._HasDropDown");
-dojo.declare("dijit.form.Button",dijit.form._FormWidget,{label:"",showLabel:true,iconClass:"",type:"button",baseClass:"dijitButton",templateString:dojo.cache("dijit.form","templates/Button.html","<span class=\"dijit dijitReset dijitInline\"\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode,focusNode\"\n\t\t\twaiRole=\"button\" waiState=\"labelledby-${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\"></span\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t\tdojoAttachPoint=\"containerNode\"\n\t\t\t></span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),attributeMap:dojo.delegate(dijit.form._FormWidget.prototype.attributeMap,{value:"valueNode",iconClass:{node:"iconNode",type:"class"}}),_onClick:function(e){
-if(this.disabled){
-return false;
-}
-this._clicked();
-return this.onClick(e);
-},_onButtonClick:function(e){
-if(this._onClick(e)===false){
-e.preventDefault();
-}else{
-if(this.type=="submit"&&!(this.valueNode||this.focusNode).form){
-for(var _1=this.domNode;_1.parentNode;_1=_1.parentNode){
-var _2=dijit.byNode(_1);
-if(_2&&typeof _2._onSubmit=="function"){
-_2._onSubmit(e);
-break;
-}
-}
-}else{
-if(this.valueNode){
-this.valueNode.click();
-e.preventDefault();
-}
-}
-}
-},_fillContent:function(_3){
-if(_3&&(!this.params||!("label" in this.params))){
-this.set("label",_3.innerHTML);
-}
-},postCreate:function(){
-dojo.setSelectable(this.focusNode,false);
-this.inherited(arguments);
-},_setShowLabelAttr:function(_4){
-if(this.containerNode){
-dojo.toggleClass(this.containerNode,"dijitDisplayNone",!_4);
-}
-this.showLabel=_4;
-},onClick:function(e){
-return true;
-},_clicked:function(e){
-},setLabel:function(_5){
-dojo.deprecated("dijit.form.Button.setLabel() is deprecated. Use set('label', ...) instead.","","2.0");
-this.set("label",_5);
-},_setLabelAttr:function(_6){
-this.containerNode.innerHTML=this.label=_6;
-if(this.showLabel==false&&!this.params.title){
-this.titleNode.title=dojo.trim(this.containerNode.innerText||this.containerNode.textContent||"");
-}
-}});
-dojo.declare("dijit.form.DropDownButton",[dijit.form.Button,dijit._Container,dijit._HasDropDown],{baseClass:"dijitDropDownButton",templateString:dojo.cache("dijit.form","templates/DropDownButton.html","<span class=\"dijit dijitReset dijitInline\"\n\t><span class='dijitReset dijitInline dijitButtonNode'\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\" dojoAttachPoint=\"_buttonNode\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"focusNode,titleNode,_arrowWrapperNode\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true,labelledby-${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\"\n\t\t\t\tdojoAttachPoint=\"iconNode\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tdojoAttachPoint=\"containerNode,_popupStateNode\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonInner\"></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonChar\">&#9660;</span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),_fillContent:function(){
-if(this.srcNodeRef){
-var _7=dojo.query("*",this.srcNodeRef);
-dijit.form.DropDownButton.superclass._fillContent.call(this,_7[0]);
-this.dropDownContainer=this.srcNodeRef;
-}
-},startup:function(){
-if(this._started){
-return;
-}
-if(!this.dropDown){
-var _8=dojo.query("[widgetId]",this.dropDownContainer)[0];
-this.dropDown=dijit.byNode(_8);
-delete this.dropDownContainer;
-}
-dijit.popup.moveOffScreen(this.dropDown.domNode);
-this.inherited(arguments);
-},isLoaded:function(){
-var _9=this.dropDown;
-return (!_9.href||_9.isLoaded);
-},loadDropDown:function(){
-var _a=this.dropDown;
-if(!_a){
-return;
-}
-if(!this.isLoaded()){
-var _b=dojo.connect(_a,"onLoad",this,function(){
-dojo.disconnect(_b);
-this.openDropDown();
+
+
+dojo.declare("dijit.form.Button",
+ dijit.form._FormWidget,
+ {
+ // summary:
+ // Basically the same thing as a normal HTML button, but with special styling.
+ // description:
+ // Buttons can display a label, an icon, or both.
+ // A label should always be specified (through innerHTML) or the label
+ // attribute. It can be hidden via showLabel=false.
+ // example:
+ // | <button dojoType="dijit.form.Button" onClick="...">Hello world</button>
+ //
+ // example:
+ // | var button1 = new dijit.form.Button({label: "hello world", onClick: foo});
+ // | dojo.body().appendChild(button1.domNode);
+
+ // label: HTML String
+ // Text to display in button.
+ // If the label is hidden (showLabel=false) then and no title has
+ // been specified, then label is also set as title attribute of icon.
+ label: "",
+
+ // showLabel: Boolean
+ // Set this to true to hide the label text and display only the icon.
+ // (If showLabel=false then iconClass must be specified.)
+ // Especially useful for toolbars.
+ // If showLabel=true, the label will become the title (a.k.a. tooltip/hint) of the icon.
+ //
+ // The exception case is for computers in high-contrast mode, where the label
+ // will still be displayed, since the icon doesn't appear.
+ showLabel: true,
+
+ // iconClass: String
+ // Class to apply to DOMNode in button to make it display an icon
+ iconClass: "",
+
+ // type: String
+ // Defines the type of button. "button", "submit", or "reset".
+ type: "button",
+
+ baseClass: "dijitButton",
+
+ templateString: dojo.cache("dijit.form", "templates/Button.html", "<span class=\"dijit dijitReset dijitInline\"\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode,focusNode\"\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\"></span\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t\tdojoAttachPoint=\"containerNode\"\n\t\t\t></span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\" tabIndex=\"-1\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\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);
+ }
});
-_a.refresh();
-}else{
-this.openDropDown();
-}
-},isFocusable:function(){
-return this.inherited(arguments)&&!this._mouseDown;
-}});
-dojo.declare("dijit.form.ComboButton",dijit.form.DropDownButton,{templateString:dojo.cache("dijit.form","templates/ComboButton.html","<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tcellspacing='0' cellpadding='0' waiRole=\"presentation\"\n\t><tbody waiRole=\"presentation\"><tr waiRole=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonNode\" dojoAttachPoint=\"buttonNode\" dojoAttachEvent=\"ondijitclick:_onButtonClick,onkeypress:_onButtonKeyPress\"\n\t\t><div id=\"${id}_button\" class=\"dijitReset dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode\"\n\t\t\twaiRole=\"button\" waiState=\"labelledby-${id}_label\"\n\t\t\t><div class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitInline dijitButtonText\" id=\"${id}_label\" dojoAttachPoint=\"containerNode\" waiRole=\"presentation\"></div\n\t\t></div\n\t\t></td\n\t\t><td id=\"${id}_arrow\" class='dijitReset dijitRight dijitButtonNode dijitArrowButton'\n\t\t\tdojoAttachPoint=\"_popupStateNode,focusNode,_buttonNode\"\n\t\t\tdojoAttachEvent=\"onkeypress:_onArrowKeyPress\"\n\t\t\ttitle=\"${optionsTitle}\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" waiRole=\"presentation\">&#9660;</div\n\t\t></td\n\t\t><td style=\"display:none !important;\"\n\t\t\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" dojoAttachPoint=\"valueNode\"\n\t\t/></td></tr></tbody\n></table>\n"),attributeMap:dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap),{id:"",tabIndex:["focusNode","titleNode"],title:"titleNode"}),optionsTitle:"",baseClass:"dijitComboButton",cssStateNodes:{"buttonNode":"dijitButtonNode","titleNode":"dijitButtonContents","_popupStateNode":"dijitDownArrowButton"},_focusedNode:null,_onButtonKeyPress:function(_c){
-if(_c.charOrCode==dojo.keys[this.isLeftToRight()?"RIGHT_ARROW":"LEFT_ARROW"]){
-dijit.focus(this._popupStateNode);
-dojo.stopEvent(_c);
-}
-},_onArrowKeyPress:function(_d){
-if(_d.charOrCode==dojo.keys[this.isLeftToRight()?"LEFT_ARROW":"RIGHT_ARROW"]){
-dijit.focus(this.titleNode);
-dojo.stopEvent(_d);
-}
-},focus:function(_e){
-dijit.focus(_e=="start"?this.titleNode:this._popupStateNode);
-}});
-dojo.declare("dijit.form.ToggleButton",dijit.form.Button,{baseClass:"dijitToggleButton",checked:false,attributeMap:dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap),{checked:"focusNode"}),_clicked:function(_f){
-this.set("checked",!this.checked);
-},_setCheckedAttr:function(_10,_11){
-this.checked=_10;
-dojo.attr(this.focusNode||this.domNode,"checked",_10);
-dijit.setWaiState(this.focusNode||this.domNode,"pressed",_10);
-this._handleOnChange(_10,_11);
-},setChecked:function(_12){
-dojo.deprecated("setChecked("+_12+") is deprecated. Use set('checked',"+_12+") instead.","","2.0");
-this.set("checked",_12);
-},reset:function(){
-this._hasBeenBlurred=false;
-this.set("checked",this.params.checked||false);
-}});
+
+
+dojo.declare("dijit.form.DropDownButton", [dijit.form.Button, dijit._Container, dijit._HasDropDown], {
+ // summary:
+ // A button with a drop down
+ //
+ // example:
+ // | <button dojoType="dijit.form.DropDownButton" label="Hello world">
+ // | <div dojotype="dijit.Menu">...</div>
+ // | </button>
+ //
+ // example:
+ // | var button1 = new dijit.form.DropDownButton({ label: "hi", dropDown: new dijit.Menu(...) });
+ // | dojo.body().appendChild(button1);
+ //
+
+ baseClass : "dijitDropDownButton",
+
+ templateString: dojo.cache("dijit.form", "templates/DropDownButton.html", "<span class=\"dijit dijitReset dijitInline\"\n\t><span class='dijitReset dijitInline dijitButtonNode'\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\" dojoAttachPoint=\"_buttonNode\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"focusNode,titleNode,_arrowWrapperNode\"\n\t\t\trole=\"button\" aria-haspopup=\"true\" aria-labelledby=\"${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\"\n\t\t\t\tdojoAttachPoint=\"iconNode\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tdojoAttachPoint=\"containerNode,_popupStateNode\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonInner\"></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonChar\">&#9660;</span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\" tabIndex=\"-1\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),
+
+ _fillContent: function(){
+ // Overrides Button._fillContent().
+ //
+ // My inner HTML contains both the button contents and a drop down widget, like
+ // <DropDownButton> <span>push me</span> <Menu> ... </Menu> </DropDownButton>
+ // The first node is assumed to be the button content. The widget is the popup.
+
+ if(this.srcNodeRef){ // programatically created buttons might not define srcNodeRef
+ //FIXME: figure out how to filter out the widget and use all remaining nodes as button
+ // content, not just nodes[0]
+ var nodes = dojo.query("*", this.srcNodeRef);
+ dijit.form.DropDownButton.superclass._fillContent.call(this, nodes[0]);
+
+ // save pointer to srcNode so we can grab the drop down widget after it's instantiated
+ this.dropDownContainer = this.srcNodeRef;
+ }
+ },
+
+ startup: function(){
+ if(this._started){ return; }
+
+ // the child widget from srcNodeRef is the dropdown widget. Insert it in the page DOM,
+ // make it invisible, and store a reference to pass to the popup code.
+ if(!this.dropDown && 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\"\n\tcellspacing='0' cellpadding='0' role=\"presentation\"\n\t><tbody role=\"presentation\"><tr role=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonNode\" dojoAttachPoint=\"buttonNode\" dojoAttachEvent=\"ondijitclick:_onButtonClick,onkeypress:_onButtonKeyPress\"\n\t\t><div id=\"${id}_button\" class=\"dijitReset dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode\"\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\n\t\t\t><div class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\" role=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitInline dijitButtonText\" id=\"${id}_label\" dojoAttachPoint=\"containerNode\" role=\"presentation\"></div\n\t\t></div\n\t\t></td\n\t\t><td id=\"${id}_arrow\" class='dijitReset dijitRight dijitButtonNode dijitArrowButton'\n\t\t\tdojoAttachPoint=\"_popupStateNode,focusNode,_buttonNode\"\n\t\t\tdojoAttachEvent=\"onkeypress:_onArrowKeyPress\"\n\t\t\ttitle=\"${optionsTitle}\"\n\t\t\trole=\"button\" aria-haspopup=\"true\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" role=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" role=\"presentation\">&#9660;</div\n\t\t></td\n\t\t><td style=\"display:none !important;\"\n\t\t\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" dojoAttachPoint=\"valueNode\"\n\t\t/></td></tr></tbody\n></table>\n"),
+
+ attributeMap: dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap), {
+ id: "",
+ tabIndex: ["focusNode", "titleNode"],
+ title: "titleNode"
+ }),
+
+ // optionsTitle: String
+ // Text that describes the options menu (accessibility)
+ optionsTitle: "",
+
+ baseClass: "dijitComboButton",
+
+ // Set classes like dijitButtonContentsHover or dijitArrowButtonActive depending on
+ // mouse action over specified node
+ cssStateNodes: {
+ "buttonNode": "dijitButtonNode",
+ "titleNode": "dijitButtonContents",
+ "_popupStateNode": "dijitDownArrowButton"
+ },
+
+ _focusedNode: null,
+
+ _onButtonKeyPress: function(/*Event*/ evt){
+ // summary:
+ // Handler for right arrow key when focus is on left part of button
+ if(evt.charOrCode == dojo.keys[this.isLeftToRight() ? "RIGHT_ARROW" : "LEFT_ARROW"]){
+ dijit.focus(this._popupStateNode);
+ dojo.stopEvent(evt);
+ }
+ },
+
+ _onArrowKeyPress: function(/*Event*/ evt){
+ // summary:
+ // Handler for left arrow key when focus is on right part of button
+ if(evt.charOrCode == dojo.keys[this.isLeftToRight() ? "LEFT_ARROW" : "RIGHT_ARROW"]){
+ dijit.focus(this.titleNode);
+ dojo.stopEvent(evt);
+ }
+ },
+
+ focus: function(/*String*/ position){
+ // summary:
+ // Focuses this widget to according to position, if specified,
+ // otherwise on arrow node
+ // position:
+ // "start" or "end"
+ 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);
+ }
+});
+
}
diff --git a/lib/dijit/form/CheckBox.js b/lib/dijit/form/CheckBox.js
index ea5cdd170..939f6e8bb 100644
--- a/lib/dijit/form/CheckBox.js
+++ b/lib/dijit/form/CheckBox.js
@@ -1,76 +1,204 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.CheckBox"]){
-dojo._hasResource["dijit.form.CheckBox"]=true;
+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.require("dijit.form.ToggleButton");
-dojo.declare("dijit.form.CheckBox",dijit.form.ToggleButton,{templateString:dojo.cache("dijit.form","templates/CheckBox.html","<div class=\"dijit dijitReset dijitInline\" waiRole=\"presentation\"\n\t><input\n\t \t${!nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\n\t\tdojoAttachPoint=\"focusNode\"\n\t \tdojoAttachEvent=\"onclick:_onClick\"\n/></div>\n"),baseClass:"dijitCheckBox",type:"checkbox",value:"on",readOnly:false,attributeMap:dojo.delegate(dijit.form._FormWidget.prototype.attributeMap,{readOnly:"focusNode"}),_setReadOnlyAttr:function(_1){
-this.readOnly=_1;
-dojo.attr(this.focusNode,"readOnly",_1);
-dijit.setWaiState(this.focusNode,"readonly",_1);
-},_setValueAttr:function(_2,_3){
-if(typeof _2=="string"){
-this.value=_2;
-dojo.attr(this.focusNode,"value",_2);
-_2=true;
-}
-if(this._created){
-this.set("checked",_2,_3);
-}
-},_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(_4){
-},reset:function(){
-this._hasBeenBlurred=false;
-this.set("checked",this.params.checked||false);
-this.value=this.params.value||"on";
-dojo.attr(this.focusNode,"value",this.value);
-},_onFocus:function(){
-if(this.id){
-dojo.query("label[for='"+this.id+"']").addClass("dijitFocusedLabel");
-}
-this.inherited(arguments);
-},_onBlur:function(){
-if(this.id){
-dojo.query("label[for='"+this.id+"']").removeClass("dijitFocusedLabel");
-}
-this.inherited(arguments);
-},_onClick:function(e){
-if(this.readOnly){
-return false;
-}
-return this.inherited(arguments);
-}});
-dojo.declare("dijit.form.RadioButton",dijit.form.CheckBox,{type:"radio",baseClass:"dijitRadio",_setCheckedAttr:function(_5){
-this.inherited(arguments);
-if(!this._created){
-return;
-}
-if(_5){
-var _6=this;
-dojo.query("INPUT[type=radio]",this.focusNode.form||dojo.doc).forEach(function(_7){
-if(_7.name==_6.name&&_7!=_6.focusNode&&_7.form==_6.focusNode.form){
-var _8=dijit.getEnclosingWidget(_7);
-if(_8&&_8.checked){
-_8.set("checked",false);
-}
-}
-});
-}
-},_clicked:function(e){
-if(!this.checked){
-this.set("checked",true);
-}
-}});
+
+
+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\"\n\t><input\n\t \t${!nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\n\t\tdojoAttachPoint=\"focusNode\"\n\t \tdojoAttachEvent=\"onclick:_onClick\"\n/></div>\n"),
+
+ baseClass: "dijitCheckBox",
+
+ // type: [private] String
+ // type attribute on <input> node.
+ // Overrides `dijit.form.Button.type`. Users should not change this value.
+ type: "checkbox",
+
+ // value: String
+ // As an initialization parameter, equivalent to value field on normal checkbox
+ // (if checked, the value is passed as the value when form is submitted).
+ //
+ // However, 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);
+ }
+ }
+ }
+);
+
}
diff --git a/lib/dijit/form/ComboBox.js b/lib/dijit/form/ComboBox.js
index 694c43ed1..aecc5c4fc 100644
--- a/lib/dijit/form/ComboBox.js
+++ b/lib/dijit/form/ComboBox.js
@@ -1,12 +1,12 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.ComboBox"]){
-dojo._hasResource["dijit.form.ComboBox"]=true;
+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.require("dojo.window");
dojo.require("dojo.regexp");
@@ -15,601 +15,1217 @@ dojo.require("dojo.data.util.filter");
dojo.require("dijit._CssStateMixin");
dojo.require("dijit.form._FormWidget");
dojo.require("dijit.form.ValidationTextBox");
-dojo.requireLocalization("dijit.form","ComboBox",null,"ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
-dojo.declare("dijit.form.ComboBoxMixin",null,{item:null,pageSize:Infinity,store:null,fetchProperties:{},query:{},autoComplete:true,highlightMatch:"first",searchDelay:100,searchAttr:"name",labelAttr:"",labelType:"text",queryExpr:"${0}*",ignoreCase:true,hasDownArrow:true,templateString:dojo.cache("dijit.form","templates/ComboBox.html","<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\"\n\tdojoAttachPoint=\"comboNode\" waiRole=\"combobox\"\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\n\t\tdojoAttachPoint=\"downArrowNode\" waiRole=\"presentation\"\n\t\tdojoAttachEvent=\"onmousedown:_onArrowMouseDown\"\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t\t\t${_buttonInputDisabled}\n\t/></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&Chi; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\n\t\t\tdojoAttachEvent=\"onkeypress:_onKeyPress,compositionend\"\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" waiRole=\"textbox\" waiState=\"haspopup-true,autocomplete-list\"\n\t/></div\n></div>\n"),baseClass:"dijitTextBox dijitComboBox",cssStateNodes:{"downArrowNode":"dijitDownArrowButton"},_getCaretPos:function(_1){
-var _2=0;
-if(typeof (_1.selectionStart)=="number"){
-_2=_1.selectionStart;
-}else{
-if(dojo.isIE){
-var tr=dojo.doc.selection.createRange().duplicate();
-var _3=_1.createTextRange();
-tr.move("character",0);
-_3.move("character",0);
-try{
-_3.setEndPoint("EndToEnd",tr);
-_2=String(_3.text).replace(/\r/g,"").length;
-}
-catch(e){
-}
-}
-}
-return _2;
-},_setCaretPos:function(_4,_5){
-_5=parseInt(_5);
-dijit.selectInputText(_4,_5,_5);
-},_setDisabledAttr:function(_6){
-this.inherited(arguments);
-dijit.setWaiState(this.comboNode,"disabled",_6);
-},_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(_7){
-if(!this.searchTimer&&(_7.type=="paste"||_7.type=="input")&&this._lastInput!=this.textbox.value){
-this.searchTimer=setTimeout(dojo.hitch(this,function(){
-this._onKeyPress({charOrCode:229});
-}),100);
-}
-this.inherited(arguments);
-},_onKeyPress:function(_8){
-var _9=_8.charOrCode;
-if(_8.altKey||((_8.ctrlKey||_8.metaKey)&&(_9!="x"&&_9!="v"))||_9==dojo.keys.SHIFT){
-return;
-}
-var _a=false;
-var _b="_startSearchFromInput";
-var pw=this._popupWidget;
-var dk=dojo.keys;
-var _c=null;
-this._prev_key_backspace=false;
-this._abortQuery();
-if(this._isShowingNow){
-pw.handleKey(_9);
-_c=pw.getHighlightedOption();
-}
-switch(_9){
-case dk.PAGE_DOWN:
-case dk.DOWN_ARROW:
-case dk.PAGE_UP:
-case dk.UP_ARROW:
-if(!this._isShowingNow){
-_a=true;
-_b="_startSearchAll";
-}else{
-this._announceOption(_c);
-}
-dojo.stopEvent(_8);
-break;
-case dk.ENTER:
-if(_c){
-if(_c==pw.nextButton){
-this._nextSearch(1);
-dojo.stopEvent(_8);
-break;
-}else{
-if(_c==pw.previousButton){
-this._nextSearch(-1);
-dojo.stopEvent(_8);
-break;
-}
-}
-}else{
-this._setBlurValue();
-this._setCaretPos(this.focusNode,this.focusNode.value.length);
-}
-_8.preventDefault();
-case dk.TAB:
-var _d=this.get("displayedValue");
-if(pw&&(_d==pw._messages["previousMessage"]||_d==pw._messages["nextMessage"])){
-break;
-}
-if(_c){
-this._selectOption();
-}
-if(this._isShowingNow){
-this._lastQuery=null;
-this._hideResultList();
-}
-break;
-case " ":
-if(_c){
-dojo.stopEvent(_8);
-this._selectOption();
-this._hideResultList();
-}else{
-_a=true;
-}
-break;
-case dk.ESCAPE:
-if(this._isShowingNow){
-dojo.stopEvent(_8);
-this._hideResultList();
-}
-break;
-case dk.DELETE:
-case dk.BACKSPACE:
-this._prev_key_backspace=true;
-_a=true;
-break;
-default:
-_a=typeof _9=="string"||_9==229;
-}
-if(_a){
-this.item=undefined;
-this.searchTimer=setTimeout(dojo.hitch(this,_b),1);
-}
-},_autoCompleteText:function(_e){
-var fn=this.focusNode;
-dijit.selectInputText(fn,fn.value.length);
-var _f=this.ignoreCase?"toLowerCase":"substr";
-if(_e[_f](0).indexOf(this.focusNode.value[_f](0))==0){
-var _10=this._getCaretPos(fn);
-if((_10+1)>fn.value.length){
-fn.value=_e;
-dijit.selectInputText(fn,_10);
-}
-}else{
-fn.value=_e;
-dijit.selectInputText(fn);
-}
-},_openResultList:function(_11,_12){
-this._fetchHandle=null;
-if(this.disabled||this.readOnly||(_12.query[this.searchAttr]!=this._lastQuery)){
-return;
-}
-this._popupWidget.clearResultList();
-if(!_11.length&&!this._maxOptions){
-this._hideResultList();
-return;
-}
-_12._maxOptions=this._maxOptions;
-var _13=this._popupWidget.createOptions(_11,_12,dojo.hitch(this,"_getMenuLabelFromItem"));
-this._showResultList();
-if(_12.direction){
-if(1==_12.direction){
-this._popupWidget.highlightFirstOption();
-}else{
-if(-1==_12.direction){
-this._popupWidget.highlightLastOption();
-}
-}
-this._announceOption(this._popupWidget.getHighlightedOption());
-}else{
-if(this.autoComplete&&!this._prev_key_backspace&&!/^[*]+$/.test(_12.query[this.searchAttr])){
-this._announceOption(_13[1]);
-}
-}
-},_showResultList:function(){
-this._hideResultList();
-this.displayMessage("");
-dojo.style(this._popupWidget.domNode,{width:"",height:""});
-var _14=this.open();
-var _15=dojo.marginBox(this._popupWidget.domNode);
-this._popupWidget.domNode.style.overflow=((_14.h==_15.h)&&(_14.w==_15.w))?"hidden":"auto";
-var _16=_14.w;
-if(_14.h<this._popupWidget.domNode.scrollHeight){
-_16+=16;
-}
-dojo.marginBox(this._popupWidget.domNode,{h:_14.h,w:Math.max(_16,this.domNode.offsetWidth)});
-if(_16<this.domNode.offsetWidth){
-this._popupWidget.domNode.parentNode.style.left=dojo.position(this.domNode,true).x+"px";
-}
-dijit.setWaiState(this.comboNode,"expanded","true");
-},_hideResultList:function(){
-this._abortQuery();
-if(this._isShowingNow){
-dijit.popup.close(this._popupWidget);
-this._isShowingNow=false;
-dijit.setWaiState(this.comboNode,"expanded","false");
-dijit.removeWaiState(this.focusNode,"activedescendant");
-}
-},_setBlurValue:function(){
-var _17=this.get("displayedValue");
-var pw=this._popupWidget;
-if(pw&&(_17==pw._messages["previousMessage"]||_17==pw._messages["nextMessage"])){
-this._setValueAttr(this._lastValueReported,true);
-}else{
-if(typeof this.item=="undefined"){
-this.item=null;
-this.set("displayedValue",_17);
-}else{
-if(this.value!=this._lastValueReported){
-dijit.form._FormValueWidget.prototype._setValueAttr.call(this,this.value,true);
-}
-this._refreshState();
-}
-}
-},_onBlur:function(){
-this._hideResultList();
-this.inherited(arguments);
-},_setItemAttr:function(_18,_19,_1a){
-if(!_1a){
-_1a=this.labelFunc(_18,this.store);
-}
-this.value=this._getValueField()!=this.searchAttr?this.store.getIdentity(_18):_1a;
-this.item=_18;
-dijit.form.ComboBox.superclass._setValueAttr.call(this,this.value,_19,_1a);
-},_announceOption:function(_1b){
-if(!_1b){
-return;
-}
-var _1c;
-if(_1b==this._popupWidget.nextButton||_1b==this._popupWidget.previousButton){
-_1c=_1b.innerHTML;
-this.item=undefined;
-this.value="";
-}else{
-_1c=this.labelFunc(_1b.item,this.store);
-this.set("item",_1b.item,false,_1c);
-}
-this.focusNode.value=this.focusNode.value.substring(0,this._lastInput.length);
-dijit.setWaiState(this.focusNode,"activedescendant",dojo.attr(_1b,"id"));
-this._autoCompleteText(_1c);
-},_selectOption:function(evt){
-if(evt){
-this._announceOption(evt.target);
-}
-this._hideResultList();
-this._setCaretPos(this.focusNode,this.focusNode.value.length);
-dijit.form._FormValueWidget.prototype._setValueAttr.call(this,this.value,true);
-},_onArrowMouseDown:function(evt){
-if(this.disabled||this.readOnly){
-return;
-}
-dojo.stopEvent(evt);
-this.focus();
-if(this._isShowingNow){
-this._hideResultList();
-}else{
-this._startSearchAll();
-}
-},_startSearchAll:function(){
-this._startSearch("");
-},_startSearchFromInput:function(){
-this._startSearch(this.focusNode.value.replace(/([\\\*\?])/g,"\\$1"));
-},_getQueryString:function(_1d){
-return dojo.string.substitute(this.queryExpr,[_1d]);
-},_startSearch:function(key){
-if(!this._popupWidget){
-var _1e=this.id+"_popup";
-this._popupWidget=new dijit.form._ComboBoxMenu({onChange:dojo.hitch(this,this._selectOption),id:_1e,dir:this.dir});
-dijit.removeWaiState(this.focusNode,"activedescendant");
-dijit.setWaiState(this.textbox,"owns",_1e);
-}
-var _1f=dojo.clone(this.query);
-this._lastInput=key;
-this._lastQuery=_1f[this.searchAttr]=this._getQueryString(key);
-this.searchTimer=setTimeout(dojo.hitch(this,function(_20,_21){
-this.searchTimer=null;
-var _22={queryOptions:{ignoreCase:this.ignoreCase,deep:true},query:_20,onBegin:dojo.hitch(this,"_setMaxOptions"),onComplete:dojo.hitch(this,"_openResultList"),onError:function(_23){
-_21._fetchHandle=null;
-console.error("dijit.form.ComboBox: "+_23);
-dojo.hitch(_21,"_hideResultList")();
-},start:0,count:this.pageSize};
-dojo.mixin(_22,_21.fetchProperties);
-this._fetchHandle=_21.store.fetch(_22);
-var _24=function(_25,_26){
-_25.start+=_25.count*_26;
-_25.direction=_26;
-this._fetchHandle=this.store.fetch(_25);
-};
-this._nextSearch=this._popupWidget.onPage=dojo.hitch(this,_24,this._fetchHandle);
-},_1f,this),this.searchDelay);
-},_setMaxOptions:function(_27,_28){
-this._maxOptions=_27;
-},_getValueField:function(){
-return this.searchAttr;
-},compositionend:function(evt){
-this._onKeyPress({charOrCode:229});
-},constructor:function(){
-this.query={};
-this.fetchProperties={};
-},postMixInProperties:function(){
-if(!this.store){
-var _29=this.srcNodeRef;
-this.store=new dijit.form._ComboBoxDataStore(_29);
-if(!("value" in this.params)){
-var _2a=this.store.fetchSelectedItem();
-if(_2a){
-var _2b=this._getValueField();
-this.value=_2b!=this.searchAttr?this.store.getValue(_2a,_2b):this.labelFunc(_2a,this.store);
-}
-}
-}
-this.inherited(arguments);
-},postCreate:function(){
-if(!this.hasDownArrow){
-this.downArrowNode.style.display="none";
-}
-var _2c=dojo.query("label[for=\""+this.id+"\"]");
-if(_2c.length){
-_2c[0].id=(this.id+"_label");
-var cn=this.comboNode;
-dijit.setWaiState(cn,"labelledby",_2c[0].id);
-}
-this.inherited(arguments);
-},uninitialize:function(){
-if(this._popupWidget&&!this._popupWidget._destroyed){
-this._hideResultList();
-this._popupWidget.destroy();
-}
-this.inherited(arguments);
-},_getMenuLabelFromItem:function(_2d){
-var _2e=this.labelAttr?this.store.getValue(_2d,this.labelAttr):this.labelFunc(_2d,this.store);
-var _2f=this.labelType;
-if(this.highlightMatch!="none"&&this.labelType=="text"&&this._lastInput){
-_2e=this.doHighlight(_2e,this._escapeHtml(this._lastInput));
-_2f="html";
-}
-return {html:_2f=="html",label:_2e};
-},doHighlight:function(_30,_31){
-var _32="i"+(this.highlightMatch=="all"?"g":"");
-var _33=this._escapeHtml(_30);
-_31=dojo.regexp.escapeString(_31);
-var ret=_33.replace(new RegExp("(^|\\s)("+_31+")",_32),"$1<span class=\"dijitComboBoxHighlightMatch\">$2</span>");
-return ret;
-},_escapeHtml:function(str){
-str=String(str).replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;").replace(/"/gm,"&quot;");
-return str;
-},open:function(){
-this._isShowingNow=true;
-return dijit.popup.open({popup:this._popupWidget,around:this.domNode,parent:this});
-},reset:function(){
-this.item=null;
-this.inherited(arguments);
-},labelFunc:function(_34,_35){
-return _35.getValue(_34,this.searchAttr).toString();
-}});
-dojo.declare("dijit.form._ComboBoxMenu",[dijit._Widget,dijit._Templated,dijit._CssStateMixin],{templateString:"<ul class='dijitReset dijitMenu' dojoAttachEvent='onmousedown:_onMouseDown,onmouseup:_onMouseUp,onmouseover:_onMouseOver,onmouseout:_onMouseOut' tabIndex='-1' style='overflow: \"auto\"; overflow-x: \"hidden\";'>"+"<li class='dijitMenuItem dijitMenuPreviousButton' dojoAttachPoint='previousButton' waiRole='option'></li>"+"<li class='dijitMenuItem dijitMenuNextButton' dojoAttachPoint='nextButton' waiRole='option'></li>"+"</ul>",_messages:null,baseClass:"dijitComboBoxMenu",postMixInProperties:function(){
-this._messages=dojo.i18n.getLocalization("dijit.form","ComboBox",this.lang);
-this.inherited(arguments);
-},_setValueAttr:function(_36){
-this.value=_36;
-this.onChange(_36);
-},onChange:function(_37){
-},onPage:function(_38){
-},postCreate:function(){
-this.previousButton.innerHTML=this._messages["previousMessage"];
-this.nextButton.innerHTML=this._messages["nextMessage"];
-this.inherited(arguments);
-},onClose:function(){
-this._blurOptionNode();
-},_createOption:function(_39,_3a){
-var _3b=_3a(_39);
-var _3c=dojo.doc.createElement("li");
-dijit.setWaiRole(_3c,"option");
-if(_3b.html){
-_3c.innerHTML=_3b.label;
-}else{
-_3c.appendChild(dojo.doc.createTextNode(_3b.label));
-}
-if(_3c.innerHTML==""){
-_3c.innerHTML="&nbsp;";
-}
-_3c.item=_39;
-return _3c;
-},createOptions:function(_3d,_3e,_3f){
-this.previousButton.style.display=(_3e.start==0)?"none":"";
-dojo.attr(this.previousButton,"id",this.id+"_prev");
-dojo.forEach(_3d,function(_40,i){
-var _41=this._createOption(_40,_3f);
-_41.className="dijitReset dijitMenuItem"+(this.isLeftToRight()?"":" dijitMenuItemRtl");
-dojo.attr(_41,"id",this.id+i);
-this.domNode.insertBefore(_41,this.nextButton);
-},this);
-var _42=false;
-if(_3e._maxOptions&&_3e._maxOptions!=-1){
-if((_3e.start+_3e.count)<_3e._maxOptions){
-_42=true;
-}else{
-if((_3e.start+_3e.count)>_3e._maxOptions&&_3e.count==_3d.length){
-_42=true;
-}
-}
-}else{
-if(_3e.count==_3d.length){
-_42=true;
-}
-}
-this.nextButton.style.display=_42?"":"none";
-dojo.attr(this.nextButton,"id",this.id+"_next");
-return this.domNode.childNodes;
-},clearResultList:function(){
-while(this.domNode.childNodes.length>2){
-this.domNode.removeChild(this.domNode.childNodes[this.domNode.childNodes.length-2]);
-}
-},_onMouseDown:function(evt){
-dojo.stopEvent(evt);
-},_onMouseUp:function(evt){
-if(evt.target===this.domNode||!this._highlighted_option){
-return;
-}else{
-if(evt.target==this.previousButton){
-this.onPage(-1);
-}else{
-if(evt.target==this.nextButton){
-this.onPage(1);
-}else{
-var tgt=evt.target;
-while(!tgt.item){
-tgt=tgt.parentNode;
-}
-this._setValueAttr({target:tgt},true);
-}
-}
-}
-},_onMouseOver:function(evt){
-if(evt.target===this.domNode){
-return;
-}
-var tgt=evt.target;
-if(!(tgt==this.previousButton||tgt==this.nextButton)){
-while(!tgt.item){
-tgt=tgt.parentNode;
-}
-}
-this._focusOptionNode(tgt);
-},_onMouseOut:function(evt){
-if(evt.target===this.domNode){
-return;
-}
-this._blurOptionNode();
-},_focusOptionNode:function(_43){
-if(this._highlighted_option!=_43){
-this._blurOptionNode();
-this._highlighted_option=_43;
-dojo.addClass(this._highlighted_option,"dijitMenuItemSelected");
-}
-},_blurOptionNode:function(){
-if(this._highlighted_option){
-dojo.removeClass(this._highlighted_option,"dijitMenuItemSelected");
-this._highlighted_option=null;
-}
-},_highlightNextOption:function(){
-if(!this.getHighlightedOption()){
-var fc=this.domNode.firstChild;
-this._focusOptionNode(fc.style.display=="none"?fc.nextSibling:fc);
-}else{
-var ns=this._highlighted_option.nextSibling;
-if(ns&&ns.style.display!="none"){
-this._focusOptionNode(ns);
-}else{
-this.highlightFirstOption();
-}
-}
-dojo.window.scrollIntoView(this._highlighted_option);
-},highlightFirstOption:function(){
-var _44=this.domNode.firstChild;
-var _45=_44.nextSibling;
-this._focusOptionNode(_45.style.display=="none"?_44:_45);
-dojo.window.scrollIntoView(this._highlighted_option);
-},highlightLastOption:function(){
-this._focusOptionNode(this.domNode.lastChild.previousSibling);
-dojo.window.scrollIntoView(this._highlighted_option);
-},_highlightPrevOption:function(){
-if(!this.getHighlightedOption()){
-var lc=this.domNode.lastChild;
-this._focusOptionNode(lc.style.display=="none"?lc.previousSibling:lc);
-}else{
-var ps=this._highlighted_option.previousSibling;
-if(ps&&ps.style.display!="none"){
-this._focusOptionNode(ps);
-}else{
-this.highlightLastOption();
-}
-}
-dojo.window.scrollIntoView(this._highlighted_option);
-},_page:function(up){
-var _46=0;
-var _47=this.domNode.scrollTop;
-var _48=dojo.style(this.domNode,"height");
-if(!this.getHighlightedOption()){
-this._highlightNextOption();
-}
-while(_46<_48){
-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 _49=this.domNode.scrollTop;
-_46+=(_49-_47)*(up?-1:1);
-_47=_49;
-}
-},pageUp:function(){
-this._page(true);
-},pageDown:function(){
-this._page(false);
-},getHighlightedOption:function(){
-var ho=this._highlighted_option;
-return (ho&&ho.parentNode)?ho:null;
-},handleKey:function(key){
-switch(key){
-case dojo.keys.DOWN_ARROW:
-this._highlightNextOption();
-break;
-case dojo.keys.PAGE_DOWN:
-this.pageDown();
-break;
-case dojo.keys.UP_ARROW:
-this._highlightPrevOption();
-break;
-case dojo.keys.PAGE_UP:
-this.pageUp();
-break;
-}
-}});
-dojo.declare("dijit.form.ComboBox",[dijit.form.ValidationTextBox,dijit.form.ComboBoxMixin],{_setValueAttr:function(_4a,_4b,_4c){
-this.item=null;
-if(!_4a){
-_4a="";
-}
-dijit.form.ValidationTextBox.prototype._setValueAttr.call(this,_4a,_4b,_4c);
-}});
-dojo.declare("dijit.form._ComboBoxDataStore",null,{constructor:function(_4d){
-this.root=_4d;
-if(_4d.tagName!="SELECT"&&_4d.firstChild){
-_4d=dojo.query("select",_4d);
-if(_4d.length>0){
-_4d=_4d[0];
-}else{
-this.root.innerHTML="<SELECT>"+this.root.innerHTML+"</SELECT>";
-_4d=this.root.firstChild;
-}
-this.root=_4d;
-}
-dojo.query("> option",_4d).forEach(function(_4e){
-_4e.innerHTML=dojo.trim(_4e.innerHTML);
-});
-},getValue:function(_4f,_50,_51){
-return (_50=="value")?_4f.value:(_4f.innerText||_4f.textContent||"");
-},isItemLoaded:function(_52){
-return true;
-},getFeatures:function(){
-return {"dojo.data.api.Read":true,"dojo.data.api.Identity":true};
-},_fetchItems:function(_53,_54,_55){
-if(!_53.query){
-_53.query={};
-}
-if(!_53.query.name){
-_53.query.name="";
-}
-if(!_53.queryOptions){
-_53.queryOptions={};
-}
-var _56=dojo.data.util.filter.patternToRegExp(_53.query.name,_53.queryOptions.ignoreCase),_57=dojo.query("> option",this.root).filter(function(_58){
-return (_58.innerText||_58.textContent||"").match(_56);
+dojo.require("dijit._HasDropDown");
+dojo.requireLocalization("dijit.form", "ComboBox", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
+
+
+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\"\n\tid=\"widget_${id}\"\n\trole=\"combobox\"\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\n\t\tdojoAttachPoint=\"_buttonNode, _popupStateNode\" role=\"presentation\"\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t\t\t${_buttonInputDisabled}\n\t/></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\n\t/></div\n></div>\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,
+
+ // For backwards compatibility let onClick events propagate, even clicks on the down arrow button
+ _stopClickEvents: false,
+
+ _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){
+ displayedValue = this.store.getValue(item, this.searchAttr);
+ }
+ 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 = 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 = this.store.getValue(item, valueField);
+ }
+ }
+ }
+
+ 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);
+ },
+
+ _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
+ }
});
-if(_53.sort){
-_57.sort(dojo.data.util.sorter.createSortFunction(_53.sort,this));
-}
-_54(_57,_53);
-},close:function(_59){
-return;
-},getLabel:function(_5a){
-return _5a.innerHTML;
-},getIdentity:function(_5b){
-return dojo.attr(_5b,"value");
-},fetchItemByIdentity:function(_5c){
-var _5d=dojo.query("> option[value='"+_5c.identity+"']",this.root)[0];
-_5c.onItem(_5d);
-},fetchSelectedItem:function(){
-var _5e=this.root,si=_5e.selectedIndex;
-return typeof si=="number"?dojo.query("> option:nth-child("+(si!=-1?si+1:1)+")",_5e)[0]:null;
-}});
+//Mix in the simple fetch implementation to this class.
dojo.extend(dijit.form._ComboBoxDataStore,dojo.data.util.simpleFetch);
+
}
diff --git a/lib/dijit/form/ComboButton.js b/lib/dijit/form/ComboButton.js
index db2d04aea..d311582ac 100644
--- a/lib/dijit/form/ComboButton.js
+++ b/lib/dijit/form/ComboButton.js
@@ -1,12 +1,15 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.ComboButton"]){
-dojo._hasResource["dijit.form.ComboButton"]=true;
+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");
dojo.require("dijit.form.Button");
+
+
+
}
diff --git a/lib/dijit/form/CurrencyTextBox.js b/lib/dijit/form/CurrencyTextBox.js
index a6519b2a7..cd0d389a0 100644
--- a/lib/dijit/form/CurrencyTextBox.js
+++ b/lib/dijit/form/CurrencyTextBox.js
@@ -1,27 +1,96 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.CurrencyTextBox"]){
-dojo._hasResource["dijit.form.CurrencyTextBox"]=true;
+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.require("dojo.currency");
dojo.require("dijit.form.NumberTextBox");
-dojo.declare("dijit.form.CurrencyTextBox",dijit.form.NumberTextBox,{currency:"",baseClass:"dijitTextBox dijitCurrencyTextBox",regExpGen:function(_1){
-return "("+(this._focused?this.inherited(arguments,[dojo.mixin({},_1,this.editOptions)])+"|":"")+dojo.currency.regexp(_1)+")";
-},_formatter:dojo.currency.format,parse:function(_2,_3){
-var v=dojo.currency.parse(_2,_3);
-if(isNaN(v)&&/\d+/.test(_2)){
-return this.inherited(arguments,[_2,dojo.mixin({},_3,this.editOptions)]);
-}
-return v;
-},_setConstraintsAttr:function(_4){
-if(!_4.currency&&this.currency){
-_4.currency=this.currency;
-}
-this.inherited(arguments,[dojo.currency._mixInDefaults(dojo.mixin(_4,{exponent:false}))]);
-}});
+
+
+/*=====
+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
+ }
+ }
+);
+
}
diff --git a/lib/dijit/form/DateTextBox.js b/lib/dijit/form/DateTextBox.js
index d040be5f8..3d929ae76 100644
--- a/lib/dijit/form/DateTextBox.js
+++ b/lib/dijit/form/DateTextBox.js
@@ -1,14 +1,40 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.DateTextBox"]){
-dojo._hasResource["dijit.form.DateTextBox"]=true;
+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.require("dijit.Calendar");
dojo.require("dijit.form._DateTimeTextBox");
-dojo.declare("dijit.form.DateTextBox",dijit.form._DateTimeTextBox,{baseClass:"dijitTextBox dijitDateTextBox",popupClass:"dijit.Calendar",_selector:"date",value:new Date("")});
+
+
+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"
+ }
+);
+
}
diff --git a/lib/dijit/form/DropDownButton.js b/lib/dijit/form/DropDownButton.js
index 53f66278e..2489a4cdf 100644
--- a/lib/dijit/form/DropDownButton.js
+++ b/lib/dijit/form/DropDownButton.js
@@ -1,12 +1,15 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.DropDownButton"]){
-dojo._hasResource["dijit.form.DropDownButton"]=true;
+if(!dojo._hasResource["dijit.form.DropDownButton"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.DropDownButton"] = true;
dojo.provide("dijit.form.DropDownButton");
dojo.require("dijit.form.Button");
+
+
+
}
diff --git a/lib/dijit/form/FilteringSelect.js b/lib/dijit/form/FilteringSelect.js
index 08703226c..81b44ff3b 100644
--- a/lib/dijit/form/FilteringSelect.js
+++ b/lib/dijit/form/FilteringSelect.js
@@ -1,92 +1,227 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.FilteringSelect"]){
-dojo._hasResource["dijit.form.FilteringSelect"]=true;
+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.require("dijit.form.ComboBox");
-dojo.declare("dijit.form.FilteringSelect",[dijit.form.MappedTextBox,dijit.form.ComboBoxMixin],{_isvalid:true,required:true,_lastDisplayedValue:"",isValid:function(){
-return this._isvalid||(!this.required&&this.get("displayedValue")=="");
-},_refreshState:function(){
-if(!this.searchTimer){
-this.inherited(arguments);
-}
-},_callbackSetLabel:function(_1,_2,_3){
-if((_2&&_2.query[this.searchAttr]!=this._lastQuery)||(!_2&&_1.length&&this.store.getIdentity(_1[0])!=this._lastQuery)){
-return;
-}
-if(!_1.length){
-this.valueNode.value="";
-dijit.form.TextBox.superclass._setValueAttr.call(this,"",_3||(_3===undefined&&!this._focused));
-this._isvalid=false;
-this.validate(this._focused);
-this.item=null;
-}else{
-this.set("item",_1[0],_3);
-}
-},_openResultList:function(_4,_5){
-if(_5.query[this.searchAttr]!=this._lastQuery){
-return;
-}
-if(this.item===undefined){
-this._isvalid=_4.length!=0||this._maxOptions!=0;
-this.validate(true);
-}
-dijit.form.ComboBoxMixin.prototype._openResultList.apply(this,arguments);
-},_getValueAttr:function(){
-return this.valueNode.value;
-},_getValueField:function(){
-return "value";
-},_setValueAttr:function(_6,_7){
-if(!this._onChangeActive){
-_7=null;
-}
-this._lastQuery=_6;
-if(_6===null||_6===""){
-this._setDisplayedValueAttr("",_7);
-return;
-}
-var _8=this;
-this.store.fetchItemByIdentity({identity:_6,onItem:function(_9){
-_8._callbackSetLabel(_9?[_9]:[],undefined,_7);
-}});
-},_setItemAttr:function(_a,_b,_c){
-this._isvalid=true;
-this.inherited(arguments);
-this.valueNode.value=this.value;
-this._lastDisplayedValue=this.textbox.value;
-},_getDisplayQueryString:function(_d){
-return _d.replace(/([\\\*\?])/g,"\\$1");
-},_setDisplayedValueAttr:function(_e,_f){
-if(!this._created){
-_f=false;
-}
-if(this.store){
-this._hideResultList();
-var _10=dojo.clone(this.query);
-this._lastQuery=_10[this.searchAttr]=this._getDisplayQueryString(_e);
-this.textbox.value=_e;
-this._lastDisplayedValue=_e;
-var _11=this;
-var _12={query:_10,queryOptions:{ignoreCase:this.ignoreCase,deep:true},onComplete:function(_13,_14){
-_11._fetchHandle=null;
-dojo.hitch(_11,"_callbackSetLabel")(_13,_14,_f);
-},onError:function(_15){
-_11._fetchHandle=null;
-console.error("dijit.form.FilteringSelect: "+_15);
-dojo.hitch(_11,"_callbackSetLabel")([],undefined,false);
-}};
-dojo.mixin(_12,this.fetchProperties);
-this._fetchHandle=this.store.fetch(_12);
-}
-},postMixInProperties:function(){
-this.inherited(arguments);
-this._isvalid=!this.required;
-},undo:function(){
-this.set("displayedValue",this._lastDisplayedValue);
-}});
+
+
+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. label should corresponding to item.searchAttr.
+
+ 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.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;
+ this._set("displayedValue", label); // for watch("displayedValue") notification
+ 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);
+ }
+ }
+);
+
}
diff --git a/lib/dijit/form/Form.js b/lib/dijit/form/Form.js
index 618700b5d..8eba470b9 100644
--- a/lib/dijit/form/Form.js
+++ b/lib/dijit/form/Form.js
@@ -1,64 +1,189 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.Form"]){
-dojo._hasResource["dijit.form.Form"]=true;
+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.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dijit.form._FormMixin");
-dojo.declare("dijit.form.Form",[dijit._Widget,dijit._Templated,dijit.form._FormMixin],{name:"",action:"",method:"",encType:"","accept-charset":"",accept:"",target:"",templateString:"<form dojoAttachPoint='containerNode' dojoAttachEvent='onreset:_onReset,onsubmit:_onSubmit' ${!nameAttrSetting}></form>",attributeMap:dojo.delegate(dijit._Widget.prototype.attributeMap,{action:"",method:"",encType:"","accept-charset":"",accept:"",target:""}),postMixInProperties:function(){
-this.nameAttrSetting=this.name?("name='"+this.name+"'"):"";
-this.inherited(arguments);
-},execute:function(_1){
-},onExecute:function(){
-},_setEncTypeAttr:function(_2){
-this.encType=_2;
-dojo.attr(this.domNode,"encType",_2);
-if(dojo.isIE){
-this.domNode.encoding=_2;
-}
-},postCreate:function(){
-if(dojo.isIE&&this.srcNodeRef&&this.srcNodeRef.attributes){
-var _3=this.srcNodeRef.attributes.getNamedItem("encType");
-if(_3&&!_3.specified&&(typeof _3.value=="string")){
-this.set("encType",_3.value);
-}
-}
-this.inherited(arguments);
-},reset:function(e){
-var _4={returnValue:true,preventDefault:function(){
-this.returnValue=false;
-},stopPropagation:function(){
-},currentTarget:e?e.target:this.domNode,target:e?e.target:this.domNode};
-if(!(this.onReset(_4)===false)&&_4.returnValue){
-this.inherited(arguments,[]);
-}
-},onReset:function(e){
-return true;
-},_onReset:function(e){
-this.reset(e);
-dojo.stopEvent(e);
-return false;
-},_onSubmit:function(e){
-var fp=dijit.form.Form.prototype;
-if(this.execute!=fp.execute||this.onExecute!=fp.onExecute){
-dojo.deprecated("dijit.form.Form:execute()/onExecute() are deprecated. Use onSubmit() instead.","","2.0");
-this.onExecute();
-this.execute(this.getValues());
-}
-if(this.onSubmit(e)===false){
-dojo.stopEvent(e);
-}
-},onSubmit:function(e){
-return this.isValid();
-},submit:function(){
-if(!(this.onSubmit()===false)){
-this.containerNode.submit();
-}
-}});
+dojo.require("dijit.layout._ContentPaneResizeMixin");
+
+
+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();
+ }
+ }
+ }
+);
+
}
diff --git a/lib/dijit/form/HorizontalRule.js b/lib/dijit/form/HorizontalRule.js
index 944282d80..e81805e6e 100644
--- a/lib/dijit/form/HorizontalRule.js
+++ b/lib/dijit/form/HorizontalRule.js
@@ -1,38 +1,74 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.HorizontalRule"]){
-dojo._hasResource["dijit.form.HorizontalRule"]=true;
+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.require("dijit._Widget");
dojo.require("dijit._Templated");
-dojo.declare("dijit.form.HorizontalRule",[dijit._Widget,dijit._Templated],{templateString:"<div class=\"dijitRuleContainer dijitRuleContainerH\"></div>",count:3,container:"containerNode",ruleStyle:"",_positionPrefix:"<div class=\"dijitRuleMark dijitRuleMarkH\" style=\"left:",_positionSuffix:"%;",_suffix:"\"></div>",_genHTML:function(_1,_2){
-return this._positionPrefix+_1+this._positionSuffix+this.ruleStyle+this._suffix;
-},_isHorizontal:true,postCreate:function(){
-var _3;
-if(this.count==1){
-_3=this._genHTML(50,0);
-}else{
-var i;
-var _4=100/(this.count-1);
-if(!this._isHorizontal||this.isLeftToRight()){
-_3=this._genHTML(0,0);
-for(i=1;i<this.count-1;i++){
-_3+=this._genHTML(_4*i,i);
-}
-_3+=this._genHTML(100,this.count-1);
-}else{
-_3=this._genHTML(100,0);
-for(i=1;i<this.count-1;i++){
-_3+=this._genHTML(100-_4*i,i);
-}
-_3+=this._genHTML(0,this.count-1);
-}
-}
-this.domNode.innerHTML=_3;
-}});
+
+
+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;
+ }
+});
+
}
diff --git a/lib/dijit/form/HorizontalRuleLabels.js b/lib/dijit/form/HorizontalRuleLabels.js
index 6cf6742c5..d923e8081 100644
--- a/lib/dijit/form/HorizontalRuleLabels.js
+++ b/lib/dijit/form/HorizontalRuleLabels.js
@@ -1,38 +1,97 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.HorizontalRuleLabels"]){
-dojo._hasResource["dijit.form.HorizontalRuleLabels"]=true;
+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.require("dijit.form.HorizontalRule");
-dojo.declare("dijit.form.HorizontalRuleLabels",dijit.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(_1){
-return _1;
-},_genHTML:function(_2,_3){
-return this._positionPrefix+this._calcPosition(_2)+this._positionSuffix+this.labelStyle+this._labelPrefix+this.labels[_3]+this._suffix;
-},getLabels:function(){
-var _4=this.labels;
-if(!_4.length){
-_4=dojo.query("> li",this.srcNodeRef).map(function(_5){
-return String(_5.innerHTML);
+
+
+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;
+ }
});
-}
-this.srcNodeRef.innerHTML="";
-if(!_4.length&&this.count>1){
-var _6=this.minimum;
-var _7=(this.maximum-_6)/(this.count-1);
-for(var i=0;i<this.count;i++){
-_4.push((i<this.numericMargin||i>=(this.count-this.numericMargin))?"":dojo.number.format(_6,this.constraints));
-_6+=_7;
-}
-}
-return _4;
-},postMixInProperties:function(){
-this.inherited(arguments);
-this.labels=this.getLabels();
-this.count=this.labels.length;
-}});
+
}
diff --git a/lib/dijit/form/HorizontalSlider.js b/lib/dijit/form/HorizontalSlider.js
index a0cb8cf2b..93dc4a0c2 100644
--- a/lib/dijit/form/HorizontalSlider.js
+++ b/lib/dijit/form/HorizontalSlider.js
@@ -1,209 +1,343 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.HorizontalSlider"]){
-dojo._hasResource["dijit.form.HorizontalSlider"]=true;
+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.require("dijit.form._FormWidget");
dojo.require("dijit._Container");
dojo.require("dojo.dnd.move");
dojo.require("dijit.form.Button");
dojo.require("dojo.number");
-dojo.require("dojo._base.fx");
-dojo.declare("dijit.form.HorizontalSlider",[dijit.form._FormValueWidget,dijit._Container],{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\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td dojoAttachPoint=\"topDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationT dijitSliderDecorationH\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderDecrementIconH\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"decrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderLeftBumper\" dojoAttachEvent=\"onmousedown:_onClkDecBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\n\t\t\t/><div class=\"dijitReset dijitSliderBarContainerH\" waiRole=\"presentation\" dojoAttachPoint=\"sliderBarContainer\"\n\t\t\t\t><div waiRole=\"presentation\" dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH\" dojoAttachEvent=\"onmousedown:_onBarClick\"\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableH\"\n\t\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleH\" dojoAttachEvent=\"onmousedown:_onHandleClick\" waiRole=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t\t><div waiRole=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderRemainingBar dijitSliderRemainingBarH\" dojoAttachEvent=\"onmousedown:_onBarClick\"></div\n\t\t\t></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderRightBumper\" dojoAttachEvent=\"onmousedown:_onClkIncBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderIncrementIconH\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"incrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\n\t\t></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td dojoAttachPoint=\"containerNode,bottomDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n></table>\n"),value:0,showButtons:true,minimum:0,maximum:100,discreteValues:Infinity,pageIncrement:2,clickSelect:true,slideDuration:dijit.defaultDuration,widgetsInTemplate:true,attributeMap:dojo.delegate(dijit.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 dojo.keys.HOME:
-this._setValueAttr(this.minimum,false);
-break;
-case dojo.keys.END:
-this._setValueAttr(this.maximum,false);
-break;
-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){
-dijit.focus(this.sliderHandle);
-}
-dojo.stopEvent(e);
-},_isReversed:function(){
-return !this.isLeftToRight();
-},_onBarClick:function(e){
-if(this.disabled||this.readOnly||!this.clickSelect){
-return;
-}
-dijit.focus(this.sliderHandle);
-dojo.stopEvent(e);
-var _1=dojo.position(this.sliderBarContainer,true);
-var _2=e[this._mousePixelCoord]-_1[this._startingPixelCoord];
-this._setPixelValue(this._isReversed()?(_1[this._pixelCount]-_2):_2,_1[this._pixelCount],true);
-this._movable.onMouseDown(e);
-},_setPixelValue:function(_3,_4,_5){
-if(this.disabled||this.readOnly){
-return;
-}
-_3=_3<0?0:_4<_3?_4:_3;
-var _6=this.discreteValues;
-if(_6<=1||_6==Infinity){
-_6=_4;
-}
-_6--;
-var _7=_4/_6;
-var _8=Math.round(_3/_7);
-this._setValueAttr((this.maximum-this.minimum)*_8/_6+this.minimum,_5);
-},_setValueAttr:function(_9,_a){
-this.valueNode.value=this.value=_9;
-dijit.setWaiState(this.focusNode,"valuenow",_9);
-this.inherited(arguments);
-var _b=(_9-this.minimum)/(this.maximum-this.minimum);
-var _c=(this._descending===false)?this.remainingBar:this.progressBar;
-var _d=(this._descending===false)?this.progressBar:this.remainingBar;
-if(this._inProgressAnim&&this._inProgressAnim.status!="stopped"){
-this._inProgressAnim.stop(true);
-}
-if(_a&&this.slideDuration>0&&_c.style[this._progressPixelSize]){
-var _e=this;
-var _f={};
-var _10=parseFloat(_c.style[this._progressPixelSize]);
-var _11=this.slideDuration*(_b-_10/100);
-if(_11==0){
-return;
-}
-if(_11<0){
-_11=0-_11;
-}
-_f[this._progressPixelSize]={start:_10,end:_b*100,units:"%"};
-this._inProgressAnim=dojo.animateProperty({node:_c,duration:_11,onAnimate:function(v){
-_d.style[_e._progressPixelSize]=(100-parseFloat(v[_e._progressPixelSize]))+"%";
-},onEnd:function(){
-delete _e._inProgressAnim;
-},properties:_f});
-this._inProgressAnim.play();
-}else{
-_c.style[this._progressPixelSize]=(_b*100)+"%";
-_d.style[this._progressPixelSize]=((1-_b)*100)+"%";
-}
-},_bumpValue:function(_12,_13){
-if(this.disabled||this.readOnly){
-return;
-}
-var s=dojo.getComputedStyle(this.sliderBarContainer);
-var c=dojo._getContentBox(this.sliderBarContainer,s);
-var _14=this.discreteValues;
-if(_14<=1||_14==Infinity){
-_14=c[this._pixelCount];
-}
-_14--;
-var _15=(this.value-this.minimum)*_14/(this.maximum-this.minimum)+_12;
-if(_15<0){
-_15=0;
-}
-if(_15>_14){
-_15=_14;
-}
-_15=_15*(this.maximum-this.minimum)/_14+this.minimum;
-this._setValueAttr(_15,_13);
-},_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==dojo.keys.PAGE_DOWN?-this.pageIncrement:-1);
-},increment:function(e){
-this._bumpValue(e.charOrCode==dojo.keys.PAGE_UP?this.pageIncrement:1);
-},_mouseWheeled:function(evt){
-dojo.stopEvent(evt);
-var _16=!dojo.isMozilla;
-var _17=evt[(_16?"wheelDelta":"detail")]*(_16?1:-1);
-this._bumpValue(_17<0?-1:1,true);
-},startup:function(){
-if(this._started){
-return;
-}
-dojo.forEach(this.getChildren(),function(_18){
-if(this[_18.container]!=this.containerNode){
-this[_18.container].appendChild(_18.domNode);
-}
-},this);
-this.inherited(arguments);
-},_typematicCallback:function(_19,_1a,e){
-if(_19==-1){
-this._setValueAttr(this.value,true);
-}else{
-this[(_1a==(this._descending?this.incrementButton:this.decrementButton))?"decrement":"increment"](e);
-}
-},postCreate:function(){
-if(this.showButtons){
-this.incrementButton.style.display="";
-this.decrementButton.style.display="";
-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");
-var _1b=dojo.declare(dijit.form._SliderMover,{widget:this});
-this._movable=new dojo.dnd.Moveable(this.sliderHandle,{mover:_1b});
-var _1c=dojo.query("label[for=\""+this.id+"\"]");
-if(_1c.length){
-_1c[0].id=(this.id+"_label");
-dijit.setWaiState(this.focusNode,"labelledby",_1c[0].id);
-}
-dijit.setWaiState(this.focusNode,"valuemin",this.minimum);
-dijit.setWaiState(this.focusNode,"valuemax",this.maximum);
-this.inherited(arguments);
-this._layoutHackIE7();
-},destroy:function(){
-this._movable.destroy();
-if(this._inProgressAnim&&this._inProgressAnim.status!="stopped"){
-this._inProgressAnim.stop(true);
-}
-this._supportingWidgets=dijit.findWidgets(this.domNode);
-this.inherited(arguments);
-}});
-dojo.declare("dijit.form._SliderMover",dojo.dnd.Mover,{onMouseMove:function(e){
-var _1d=this.widget;
-var _1e=_1d._abspos;
-if(!_1e){
-_1e=_1d._abspos=dojo.position(_1d.sliderBarContainer,true);
-_1d._setPixelValue_=dojo.hitch(_1d,"_setPixelValue");
-_1d._isReversed_=_1d._isReversed();
-}
-var _1f=e[_1d._mousePixelCoord]-_1e[_1d._startingPixelCoord];
-_1d._setPixelValue_(_1d._isReversed_?(_1e[_1d._pixelCount]-_1f):_1f,_1e[_1d._pixelCount],false);
-},destroy:function(e){
-dojo.dnd.Mover.prototype.destroy.apply(this,arguments);
-var _20=this.widget;
-_20._abspos=null;
-_20._setValueAttr(_20.value,true);
-}});
+
+
+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\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td dojoAttachPoint=\"topDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationT dijitSliderDecorationH\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderDecrementIconH\" style=\"display:none\" dojoAttachPoint=\"decrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderLeftBumper\" dojoAttachEvent=\"onmousedown:_onClkDecBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\n\t\t\t/><div class=\"dijitReset dijitSliderBarContainerH\" role=\"presentation\" dojoAttachPoint=\"sliderBarContainer\"\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH\" dojoAttachEvent=\"onmousedown:_onBarClick\"\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableH\"\n\t\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleH\" dojoAttachEvent=\"onmousedown:_onHandleClick\" role=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderRemainingBar dijitSliderRemainingBarH\" dojoAttachEvent=\"onmousedown:_onBarClick\"></div\n\t\t\t></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderRightBumper\" dojoAttachEvent=\"onmousedown:_onClkIncBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderIncrementIconH\" style=\"display:none\" dojoAttachPoint=\"incrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\n\t\t></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td dojoAttachPoint=\"containerNode,bottomDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n></table>\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);
+ }
+});
+
}
diff --git a/lib/dijit/form/MappedTextBox.js b/lib/dijit/form/MappedTextBox.js
index e7dd213c0..ebdaaf15b 100644
--- a/lib/dijit/form/MappedTextBox.js
+++ b/lib/dijit/form/MappedTextBox.js
@@ -1,12 +1,15 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.MappedTextBox"]){
-dojo._hasResource["dijit.form.MappedTextBox"]=true;
+if(!dojo._hasResource["dijit.form.MappedTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.MappedTextBox"] = true;
dojo.provide("dijit.form.MappedTextBox");
dojo.require("dijit.form.ValidationTextBox");
+
+
+
}
diff --git a/lib/dijit/form/MultiSelect.js b/lib/dijit/form/MultiSelect.js
index 8aacb4148..12f3b40e7 100644
--- a/lib/dijit/form/MultiSelect.js
+++ b/lib/dijit/form/MultiSelect.js
@@ -1,49 +1,119 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.MultiSelect"]){
-dojo._hasResource["dijit.form.MultiSelect"]=true;
+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.require("dijit.form._FormWidget");
-dojo.declare("dijit.form.MultiSelect",dijit.form._FormValueWidget,{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(){
-this._hasBeenBlurred=false;
-this._setValueAttr(this._resetValue,true);
-},addSelected:function(_1){
-_1.getSelected().forEach(function(n){
-this.containerNode.appendChild(n);
-this.domNode.scrollTop=this.domNode.offsetHeight;
-var _2=_1.domNode.scrollTop;
-_1.domNode.scrollTop=0;
-_1.domNode.scrollTop=_2;
-},this);
-},getSelected:function(){
-return dojo.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(_3){
-dojo.query("option",this.containerNode).forEach(function(n){
-n.selected=(dojo.indexOf(_3,n.value)!=-1);
-});
-},invertSelection:function(_4){
-dojo.query("option",this.containerNode).forEach(function(n){
-n.selected=!n.selected;
+
+
+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();
+ }
});
-this._handleOnChange(this.get("value"),_4==true);
-},_onChange:function(e){
-this._handleOnChange(this.get("value"),true);
-},resize:function(_5){
-if(_5){
-dojo.marginBox(this.domNode,_5);
-}
-},postCreate:function(){
-this._onChange();
-}});
+
}
diff --git a/lib/dijit/form/NumberSpinner.js b/lib/dijit/form/NumberSpinner.js
index 82a3c4024..ba5a782f5 100644
--- a/lib/dijit/form/NumberSpinner.js
+++ b/lib/dijit/form/NumberSpinner.js
@@ -1,38 +1,71 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.NumberSpinner"]){
-dojo._hasResource["dijit.form.NumberSpinner"]=true;
+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.require("dijit.form._Spinner");
dojo.require("dijit.form.NumberTextBox");
-dojo.declare("dijit.form.NumberSpinner",[dijit.form._Spinner,dijit.form.NumberTextBoxMixin],{adjust:function(_1,_2){
-var tc=this.constraints,v=isNaN(_1),_3=!isNaN(tc.max),_4=!isNaN(tc.min);
-if(v&&_2!=0){
-_1=(_2>0)?_4?tc.min:_3?tc.max:0:_3?this.constraints.max:_4?tc.min:0;
-}
-var _5=_1+_2;
-if(v||isNaN(_5)){
-return _1;
-}
-if(_3&&(_5>tc.max)){
-_5=tc.max;
-}
-if(_4&&(_5<tc.min)){
-_5=tc.min;
-}
-return _5;
-},_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"){
-var _6=this.constraints[(e.charOrCode==dojo.keys.HOME?"min":"max")];
-if(typeof _6=="number"){
-this._setValueAttr(_6,false);
-}
-dojo.stopEvent(e);
-}
-}});
+
+
+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);
+ }
+ }
+});
+
}
diff --git a/lib/dijit/form/NumberTextBox.js b/lib/dijit/form/NumberTextBox.js
index d477d1ba9..4d0d64f99 100644
--- a/lib/dijit/form/NumberTextBox.js
+++ b/lib/dijit/form/NumberTextBox.js
@@ -1,112 +1,278 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.NumberTextBox"]){
-dojo._hasResource["dijit.form.NumberTextBox"]=true;
+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.require("dijit.form.ValidationTextBox");
dojo.require("dojo.number");
-dojo.declare("dijit.form.NumberTextBoxMixin",null,{regExpGen:dojo.number.regexp,value:NaN,editOptions:{pattern:"#.######"},_formatter:dojo.number.format,_setConstraintsAttr:function(_1){
-var _2=typeof _1.places=="number"?_1.places:0;
-if(_2){
-_2++;
-}
-if(typeof _1.max!="number"){
-_1.max=9*Math.pow(10,15-_2);
-}
-if(typeof _1.min!="number"){
-_1.min=-9*Math.pow(10,15-_2);
-}
-this.inherited(arguments,[_1]);
-if(this.focusNode&&this.focusNode.value&&!isNaN(this.value)){
-this.set("value",this.value);
-}
-},_onFocus:function(){
-if(this.disabled){
-return;
-}
-var _3=this.get("value");
-if(typeof _3=="number"&&!isNaN(_3)){
-var _4=this.format(_3,this.constraints);
-if(_4!==undefined){
-this.textbox.value=_4;
-}
-}
-this.inherited(arguments);
-},format:function(_5,_6){
-var _7=String(_5);
-if(typeof _5!="number"){
-return _7;
-}
-if(isNaN(_5)){
-return "";
-}
-if(!("rangeCheck" in this&&this.rangeCheck(_5,_6))&&_6.exponent!==false&&/\de[-+]?\d/i.test(_7)){
-return _7;
-}
-if(this.editOptions&&this._focused){
-_6=dojo.mixin({},_6,this.editOptions);
-}
-return this._formatter(_5,_6);
-},parse:dojo.number.parse,_getDisplayedValueAttr:function(){
-var v=this.inherited(arguments);
-return isNaN(v)?this.textbox.value:v;
-},filter:function(_8){
-return (_8===null||_8===""||_8===undefined)?NaN:this.inherited(arguments);
-},serialize:function(_9,_a){
-return (typeof _9!="number"||isNaN(_9))?"":this.inherited(arguments);
-},_setValueAttr:function(_b,_c,_d){
-if(_b!==undefined&&_d===undefined){
-_d=String(_b);
-if(typeof _b=="number"){
-if(isNaN(_b)){
-_d="";
-}else{
-if(("rangeCheck" in this&&this.rangeCheck(_b,this.constraints))||this.constraints.exponent===false||!/\de[-+]?\d/i.test(_d)){
-_d=undefined;
-}
-}
-}else{
-if(!_b){
-_d="";
-_b=NaN;
-}else{
-_b=undefined;
-}
-}
-}
-this.inherited(arguments,[_b,_c,_d]);
-},_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("^"+dojo.number._realNumberRegexp(dojo.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(_e){
-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;
-}
-}
-}});
-dojo.declare("dijit.form.NumberTextBox",[dijit.form.RangeBoundTextBox,dijit.form.NumberTextBoxMixin],{});
+
+
+/*=====
+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"
+ }
+);
+
}
diff --git a/lib/dijit/form/RadioButton.js b/lib/dijit/form/RadioButton.js
index 154bdd4bc..295ec5ffd 100644
--- a/lib/dijit/form/RadioButton.js
+++ b/lib/dijit/form/RadioButton.js
@@ -1,12 +1,16 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.RadioButton"]){
-dojo._hasResource["dijit.form.RadioButton"]=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");
dojo.require("dijit.form.CheckBox");
+
+
+// TODO: for 2.0, move the RadioButton code into this file
+
}
diff --git a/lib/dijit/form/RangeBoundTextBox.js b/lib/dijit/form/RangeBoundTextBox.js
index b2e2f4ca9..589967f25 100644
--- a/lib/dijit/form/RangeBoundTextBox.js
+++ b/lib/dijit/form/RangeBoundTextBox.js
@@ -1,12 +1,15 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.RangeBoundTextBox"]){
-dojo._hasResource["dijit.form.RangeBoundTextBox"]=true;
+if(!dojo._hasResource["dijit.form.RangeBoundTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.RangeBoundTextBox"] = true;
dojo.provide("dijit.form.RangeBoundTextBox");
dojo.require("dijit.form.ValidationTextBox");
+
+
+
}
diff --git a/lib/dijit/form/Select.js b/lib/dijit/form/Select.js
index 7caf553f2..a681cdf89 100644
--- a/lib/dijit/form/Select.js
+++ b/lib/dijit/form/Select.js
@@ -1,140 +1,305 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.Select"]){
-dojo._hasResource["dijit.form.Select"]=true;
+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.require("dijit.form._FormSelectWidget");
dojo.require("dijit._HasDropDown");
dojo.require("dijit.Menu");
dojo.require("dijit.Tooltip");
-dojo.requireLocalization("dijit.form","validate",null,"ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
-dojo.declare("dijit.form._SelectMenu",dijit.Menu,{buildRendering:function(){
-this.inherited(arguments);
-var o=(this.menuTableNode=this.domNode);
-var n=(this.domNode=dojo.create("div",{style:{overflowX:"hidden",overflowY:"scroll"}}));
-if(o.parentNode){
-o.parentNode.replaceChild(n,o);
-}
-dojo.removeClass(o,"dijitMenuTable");
-n.className=o.className+" dijitSelectMenu";
-o.className="dijitReset dijitMenuTable";
-dijit.setWaiRole(o,"listbox");
-dijit.setWaiRole(n,"presentation");
-n.appendChild(o);
-},resize:function(mb){
-if(mb){
-dojo.marginBox(this.domNode,mb);
-if("w" in mb){
-this.menuTableNode.style.width="100%";
-}
-}
-}});
-dojo.declare("dijit.form.Select",[dijit.form._FormSelectWidget,dijit._HasDropDown],{baseClass:"dijitSelect",templateString:dojo.cache("dijit.form","templates/Select.html","<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tdojoAttachPoint=\"_buttonNode,tableNode,focusNode\" cellspacing='0' cellpadding='0'\n\twaiRole=\"combobox\" waiState=\"haspopup-true\"\n\t><tbody waiRole=\"presentation\"><tr waiRole=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonContents dijitButtonNode\" waiRole=\"presentation\"\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\" dojoAttachPoint=\"containerNode,_popupStateNode\"></span\n\t\t\t><input type=\"hidden\" ${!nameAttrSetting} dojoAttachPoint=\"valueNode\" value=\"${value}\" waiState=\"hidden-true\"\n\t\t/></td><td class=\"dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\t\tdojoAttachPoint=\"titleNode\" waiRole=\"presentation\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" waiRole=\"presentation\">&#9660;</div\n\t\t></td\n\t></tr></tbody\n></table>\n"),attributeMap:dojo.mixin(dojo.clone(dijit.form._FormSelectWidget.prototype.attributeMap),{style:"tableNode"}),required:false,state:"",tooltipPosition:[],emptyLabel:"",_isLoaded:false,_childrenLoaded:false,_fillContent:function(){
-this.inherited(arguments);
-if(this.options.length&&!this.value&&this.srcNodeRef){
-var si=this.srcNodeRef.selectedIndex;
-this.value=this.options[si!=-1?si:0].value;
-}
-this.dropDown=new dijit.form._SelectMenu({id:this.id+"_menu"});
-dojo.addClass(this.dropDown.domNode,this.baseClass+"Menu");
-},_getMenuItemForOption:function(_1){
-if(!_1.value){
-return new dijit.MenuSeparator();
-}else{
-var _2=dojo.hitch(this,"_setValueAttr",_1);
-var _3=new dijit.MenuItem({option:_1,label:_1.label,onClick:_2,disabled:_1.disabled||false});
-dijit.setWaiRole(_3.focusNode,"listitem");
-return _3;
-}
-},_addOptionItem:function(_4){
-if(this.dropDown){
-this.dropDown.addChild(this._getMenuItemForOption(_4));
-}
-},_getChildren:function(){
-if(!this.dropDown){
-return [];
-}
-return this.dropDown.getChildren();
-},_loadChildren:function(_5){
-if(_5===true){
-if(this.dropDown){
-delete this.dropDown.focusedChild;
-}
-if(this.options.length){
-this.inherited(arguments);
-}else{
-dojo.forEach(this._getChildren(),function(_6){
-_6.destroyRecursive();
+dojo.requireLocalization("dijit.form", "validate", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
+
+
+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%";
+ }
+ }
+ }
});
-var _7=new dijit.MenuItem({label:"&nbsp;"});
-this.dropDown.addChild(_7);
-}
-}else{
-this._updateSelection();
-}
-var _8=this.options.length;
-this._isLoaded=false;
-this._childrenLoaded=true;
-if(!this._loadingStore){
-this._setValueAttr(this.value);
-}
-},_setValueAttr:function(_9){
-this.inherited(arguments);
-dojo.attr(this.valueNode,"value",this.get("value"));
-},_setDisplay:function(_a){
-this.containerNode.innerHTML="<span class=\"dijitReset dijitInline "+this.baseClass+"Label\">"+(_a||this.emptyLabel||"&nbsp;")+"</span>";
-dijit.setWaiState(this.focusNode,"valuetext",(_a||this.emptyLabel||"&nbsp;"));
-},validate:function(_b){
-var _c=this.isValid(_b);
-this.state=_c?"":"Error";
-this._setStateClass();
-dijit.setWaiState(this.focusNode,"invalid",_c?"false":"true");
-var _d=_c?"":this._missingMsg;
-if(this._message!==_d){
-this._message=_d;
-dijit.hideTooltip(this.domNode);
-if(_d){
-dijit.showTooltip(_d,this.domNode,this.tooltipPosition,!this.isLeftToRight());
-}
-}
-return _c;
-},isValid:function(_e){
-return (!this.required||!(/^\s*$/.test(this.value)));
-},reset:function(){
-this.inherited(arguments);
-dijit.hideTooltip(this.domNode);
-this.state="";
-this._setStateClass();
-delete this._message;
-},postMixInProperties:function(){
-this.inherited(arguments);
-this._missingMsg=dojo.i18n.getLocalization("dijit.form","validate",this.lang).missingMessage;
-},postCreate:function(){
-this.inherited(arguments);
-if(this.tableNode.style.width){
-dojo.addClass(this.domNode,this.baseClass+"FixedWidth");
-}
-},isLoaded:function(){
-return this._isLoaded;
-},loadDropDown:function(_f){
-this._loadChildren(true);
-this._isLoaded=true;
-_f();
-},closeDropDown:function(){
-this.inherited(arguments);
-if(this.dropDown&&this.dropDown.menuTableNode){
-this.dropDown.menuTableNode.style.width="";
-}
-},uninitialize:function(_10){
-if(this.dropDown&&!this.dropDown._destroyed){
-this.dropDown.destroyRecursive(_10);
-delete this.dropDown;
-}
-this.inherited(arguments);
-}});
+
+dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropDown], {
+ // summary:
+ // This is a "styleable" select box - it is basically a DropDownButton which
+ // can take a <select> as its input.
+
+ baseClass: "dijitSelect",
+
+ templateString: dojo.cache("dijit.form", "templates/Select.html", "<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tdojoAttachPoint=\"_buttonNode,tableNode,focusNode\" cellspacing='0' cellpadding='0'\n\trole=\"combobox\" aria-haspopup=\"true\"\n\t><tbody role=\"presentation\"><tr role=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonContents dijitButtonNode\" role=\"presentation\"\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\" dojoAttachPoint=\"containerNode,_popupStateNode\"></span\n\t\t\t><input type=\"hidden\" ${!nameAttrSetting} dojoAttachPoint=\"valueNode\" value=\"${value}\" aria-hidden=\"true\"\n\t\t/></td><td class=\"dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\t\tdojoAttachPoint=\"titleNode\" role=\"presentation\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" role=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" role=\"presentation\">&#9660;</div\n\t\t></td\n\t></tr></tbody\n></table>\n"),
+
+ // attributeMap: Object
+ // Add in our style to be applied to the focus node
+ attributeMap: dojo.mixin(dojo.clone(dijit.form._FormSelectWidget.prototype.attributeMap),{style:"tableNode"}),
+
+ // required: Boolean
+ // Can be true or false, default is false.
+ required: false,
+
+ // state: String
+ // Shows current state (ie, validation result) of input (Normal, Warning, or Error)
+ state: "",
+
+ // 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);
+ }
+});
+
}
diff --git a/lib/dijit/form/SimpleTextarea.js b/lib/dijit/form/SimpleTextarea.js
index b4824c74e..6ff823105 100644
--- a/lib/dijit/form/SimpleTextarea.js
+++ b/lib/dijit/form/SimpleTextarea.js
@@ -1,59 +1,103 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.SimpleTextarea"]){
-dojo._hasResource["dijit.form.SimpleTextarea"]=true;
+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.require("dijit.form.TextBox");
-dojo.declare("dijit.form.SimpleTextarea",dijit.form.TextBox,{baseClass:"dijitTextBox dijitTextArea",attributeMap:dojo.delegate(dijit.form._FormValueWidget.prototype.attributeMap,{rows:"textbox",cols:"textbox"}),rows:"3",cols:"20",templateString:"<textarea ${!nameAttrSetting} dojoAttachPoint='focusNode,containerNode,textbox' autocomplete='off'></textarea>",postMixInProperties:function(){
-if(!this.value&&this.srcNodeRef){
-this.value=this.srcNodeRef.value;
-}
-this.inherited(arguments);
-},filter:function(_1){
-if(_1){
-_1=_1.replace(/\r/g,"");
-}
-return this.inherited(arguments);
-},postCreate:function(){
-this.inherited(arguments);
-if(dojo.isIE&&this.cols){
-dojo.addClass(this.textbox,"dijitTextAreaCols");
-}
-},_previousValue:"",_onInput:function(e){
-if(this.maxLength){
-var _2=parseInt(this.maxLength);
-var _3=this.textbox.value.replace(/\r/g,"");
-var _4=_3.length-_2;
-if(_4>0){
-if(e){
-dojo.stopEvent(e);
-}
-var _5=this.textbox;
-if(_5.selectionStart){
-var _6=_5.selectionStart;
-var cr=0;
-if(dojo.isOpera){
-cr=(this.textbox.value.substring(0,_6).match(/\r/g)||[]).length;
-}
-this.textbox.value=_3.substring(0,_6-_4-cr)+_3.substring(_6-cr);
-_5.setSelectionRange(_6-_4,_6-_4);
-}else{
-if(dojo.doc.selection){
-_5.focus();
-var _7=dojo.doc.selection.createRange();
-_7.moveStart("character",-_4);
-_7.text="";
-_7.select();
-}
-}
-}
-this._previousValue=this.textbox.value;
-}
-this.inherited(arguments);
-}});
+
+
+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);
+ }
+});
+
}
diff --git a/lib/dijit/form/Slider.js b/lib/dijit/form/Slider.js
index 051d57929..80d4cfa98 100644
--- a/lib/dijit/form/Slider.js
+++ b/lib/dijit/form/Slider.js
@@ -1,18 +1,23 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.Slider"]){
-dojo._hasResource["dijit.form.Slider"]=true;
+if(!dojo._hasResource["dijit.form.Slider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.Slider"] = true;
dojo.provide("dijit.form.Slider");
-dojo.deprecated("Call require() for HorizontalSlider / VerticalRule, explicitly rather than 'dijit.form.Slider' itself","","2.0");
dojo.require("dijit.form.HorizontalSlider");
dojo.require("dijit.form.VerticalSlider");
dojo.require("dijit.form.HorizontalRule");
dojo.require("dijit.form.VerticalRule");
dojo.require("dijit.form.HorizontalRuleLabels");
dojo.require("dijit.form.VerticalRuleLabels");
+
+
+dojo.deprecated("Call require() for HorizontalSlider / VerticalRule, explicitly rather than 'dijit.form.Slider' itself", "", "2.0");
+
+// For back-compat, remove for 2.0
+
}
diff --git a/lib/dijit/form/TextBox.js b/lib/dijit/form/TextBox.js
index 81c9b2a04..38a9c09d4 100644
--- a/lib/dijit/form/TextBox.js
+++ b/lib/dijit/form/TextBox.js
@@ -1,209 +1,427 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.TextBox"]){
-dojo._hasResource["dijit.form.TextBox"]=true;
+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.require("dijit.form._FormWidget");
-dojo.declare("dijit.form.TextBox",dijit.form._FormValueWidget,{trim:false,uppercase:false,lowercase:false,propercase:false,maxLength:"",selectOnClick:false,placeHolder:"",templateString:dojo.cache("dijit.form","templates/TextBox.html","<div class=\"dijit dijitReset dijitInline dijitLeft\" id=\"widget_${id}\" waiRole=\"presentation\"\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),_singleNodeTemplate:"<input class=\"dijit dijitReset dijitLeft dijitInputField\" dojoAttachPoint=\"textbox,focusNode\" autocomplete=\"off\" type=\"${type}\" ${!nameAttrSetting} />",_buttonInputDisabled:dojo.isIE?"disabled":"",baseClass:"dijitTextBox",attributeMap:dojo.delegate(dijit.form._FormValueWidget.prototype.attributeMap,{maxLength:"focusNode"}),postMixInProperties:function(){
-var _1=this.type.toLowerCase();
-if(this.templateString.toLowerCase()=="input"||((_1=="hidden"||_1=="file")&&this.templateString==dijit.form.TextBox.prototype.templateString)){
-this.templateString=this._singleNodeTemplate;
-}
-this.inherited(arguments);
-},_setPlaceHolderAttr:function(v){
-this.placeHolder=v;
-if(!this._phspan){
-this._attachPoints.push("_phspan");
-this._phspan=dojo.create("span",{className:"dijitPlaceHolder dijitInputField"},this.textbox,"after");
-}
-this._phspan.innerHTML="";
-this._phspan.appendChild(document.createTextNode(v));
-this._updatePlaceHolder();
-},_updatePlaceHolder:function(){
-if(this._phspan){
-this._phspan.style.display=(this.placeHolder&&!this._focused&&!this.textbox.value)?"":"none";
-}
-},_getValueAttr:function(){
-return this.parse(this.get("displayedValue"),this.constraints);
-},_setValueAttr:function(_2,_3,_4){
-var _5;
-if(_2!==undefined){
-_5=this.filter(_2);
-if(typeof _4!="string"){
-if(_5!==null&&((typeof _5!="number")||!isNaN(_5))){
-_4=this.filter(this.format(_5,this.constraints));
-}else{
-_4="";
-}
-}
-}
-if(_4!=null&&_4!=undefined&&((typeof _4)!="number"||!isNaN(_4))&&this.textbox.value!=_4){
-this.textbox.value=_4;
-}
-this._updatePlaceHolder();
-this.inherited(arguments,[_5,_3]);
-},displayedValue:"",getDisplayedValue:function(){
-dojo.deprecated(this.declaredClass+"::getDisplayedValue() is deprecated. Use set('displayedValue') instead.","","2.0");
-return this.get("displayedValue");
-},_getDisplayedValueAttr:function(){
-return this.filter(this.textbox.value);
-},setDisplayedValue:function(_6){
-dojo.deprecated(this.declaredClass+"::setDisplayedValue() is deprecated. Use set('displayedValue', ...) instead.","","2.0");
-this.set("displayedValue",_6);
-},_setDisplayedValueAttr:function(_7){
-if(_7===null||_7===undefined){
-_7="";
-}else{
-if(typeof _7!="string"){
-_7=String(_7);
-}
-}
-this.textbox.value=_7;
-this._setValueAttr(this.get("value"),undefined,_7);
-},format:function(_8,_9){
-return ((_8==null||_8==undefined)?"":(_8.toString?_8.toString():_8));
-},parse:function(_a,_b){
-return _a;
-},_refreshState:function(){
-},_onInput:function(e){
-if(e&&e.type&&/key/i.test(e.type)&&e.keyCode){
-switch(e.keyCode){
-case dojo.keys.SHIFT:
-case dojo.keys.ALT:
-case dojo.keys.CTRL:
-case dojo.keys.TAB:
-return;
-}
-}
-if(this.intermediateChanges){
-var _c=this;
-setTimeout(function(){
-_c._handleOnChange(_c.get("value"),false);
-},0);
-}
-this._refreshState();
-},postCreate:function(){
-if(dojo.isIE){
-var s=dojo.getComputedStyle(this.domNode);
-if(s){
-var ff=s.fontFamily;
-if(ff){
-var _d=this.domNode.getElementsByTagName("INPUT");
-if(_d){
-for(var i=0;i<_d.length;i++){
-_d[i].style.fontFamily=ff;
-}
-}
-}
-}
-}
-this.textbox.setAttribute("value",this.textbox.value);
-this.inherited(arguments);
-if(dojo.isMoz||dojo.isOpera){
-this.connect(this.textbox,"oninput",this._onInput);
-}else{
-this.connect(this.textbox,"onkeydown",this._onInput);
-this.connect(this.textbox,"onkeyup",this._onInput);
-this.connect(this.textbox,"onpaste",this._onInput);
-this.connect(this.textbox,"oncut",this._onInput);
-}
-},_blankValue:"",filter:function(_e){
-if(_e===null){
-return this._blankValue;
-}
-if(typeof _e!="string"){
-return _e;
-}
-if(this.trim){
-_e=dojo.trim(_e);
-}
-if(this.uppercase){
-_e=_e.toUpperCase();
-}
-if(this.lowercase){
-_e=_e.toLowerCase();
-}
-if(this.propercase){
-_e=_e.replace(/[^\s]+/g,function(_f){
-return _f.substring(0,1).toUpperCase()+_f.substring(1);
-});
-}
-return _e;
-},_setBlurValue:function(){
-this._setValueAttr(this.get("value"),true);
-},_onBlur:function(e){
-if(this.disabled){
-return;
-}
-this._setBlurValue();
-this.inherited(arguments);
-if(this._selectOnClickHandle){
-this.disconnect(this._selectOnClickHandle);
-}
-if(this.selectOnClick&&dojo.isMoz){
-this.textbox.selectionStart=this.textbox.selectionEnd=undefined;
-}
-this._updatePlaceHolder();
-},_onFocus:function(by){
-if(this.disabled||this.readOnly){
-return;
-}
-if(this.selectOnClick&&by=="mouse"){
-this._selectOnClickHandle=this.connect(this.domNode,"onmouseup",function(){
-this.disconnect(this._selectOnClickHandle);
-var _10;
-if(dojo.isIE){
-var _11=dojo.doc.selection.createRange();
-var _12=_11.parentElement();
-_10=_12==this.textbox&&_11.text.length==0;
-}else{
-_10=this.textbox.selectionStart==this.textbox.selectionEnd;
-}
-if(_10){
-dijit.selectInputText(this.textbox);
-}
-});
-}
-this._updatePlaceHolder();
-this._refreshState();
-this.inherited(arguments);
-},reset:function(){
-this.textbox.value="";
-this.inherited(arguments);
-}});
-dijit.selectInputText=function(_13,_14,_15){
-var _16=dojo.global;
-var _17=dojo.doc;
-_13=dojo.byId(_13);
-if(isNaN(_14)){
-_14=0;
-}
-if(isNaN(_15)){
-_15=_13.value?_13.value.length:0;
-}
-dijit.focus(_13);
-if(_17["selection"]&&dojo.body()["createTextRange"]){
-if(_13.createTextRange){
-var _18=_13.createTextRange();
-with(_18){
-collapse(true);
-moveStart("character",-99999);
-moveStart("character",_14);
-moveEnd("character",_15-_14);
-select();
-}
-}
-}else{
-if(_16["getSelection"]){
-if(_13.setSelectionRange){
-_13.setSelectionRange(_14,_15);
-}
-}
-}
+
+
+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\"\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),
+ _singleNodeTemplate: '<input class="dijit dijitReset dijitLeft dijitInputField" dojoAttachPoint="textbox,focusNode" autocomplete="off" type="${type}" ${!nameAttrSetting} />',
+
+ _buttonInputDisabled: dojo.isIE ? "disabled" : "", // allows IE to disallow focus, but Firefox cannot be disabled for mousedown events
+
+ baseClass: "dijitTextBox",
+
+ attributeMap: dojo.delegate(dijit.form._FormValueWidget.prototype.attributeMap, {
+ maxLength: "focusNode"
+ }),
+
+ postMixInProperties: function(){
+ var type = this.type.toLowerCase();
+ if(this.templateString && 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);
+ }
+ }
};
+
}
diff --git a/lib/dijit/form/Textarea.js b/lib/dijit/form/Textarea.js
index 4dd9cd928..cc1ec917e 100644
--- a/lib/dijit/form/Textarea.js
+++ b/lib/dijit/form/Textarea.js
@@ -1,103 +1,167 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.Textarea"]){
-dojo._hasResource["dijit.form.Textarea"]=true;
+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.require("dijit.form.SimpleTextarea");
-dojo.declare("dijit.form.Textarea",dijit.form.SimpleTextarea,{cols:"",_previousNewlines:0,_strictMode:(dojo.doc.compatMode!="BackCompat"),_getHeight:function(_1){
-var _2=_1.scrollHeight;
-if(dojo.isIE){
-_2+=_1.offsetHeight-_1.clientHeight-((dojo.isIE<8&&this._strictMode)?dojo._getPadBorderExtents(_1).h:0);
-}else{
-if(dojo.isMoz){
-_2+=_1.offsetHeight-_1.clientHeight;
-}else{
-if(dojo.isWebKit&&!(dojo.isSafari<4)){
-_2+=dojo._getBorderExtents(_1).h;
-}else{
-_2+=dojo._getPadBorderExtents(_1).h;
-}
-}
-}
-return _2;
-},_estimateHeight:function(_3){
-_3.style.maxHeight="";
-_3.style.height="auto";
-_3.rows=(_3.value.match(/\n/g)||[]).length+1;
-},_needsHelpShrinking:dojo.isMoz||dojo.isWebKit,_onInput:function(){
-this.inherited(arguments);
-if(this._busyResizing){
-return;
-}
-this._busyResizing=true;
-var _4=this.textbox;
-if(_4.scrollHeight&&_4.offsetHeight&&_4.clientHeight){
-var _5=this._getHeight(_4)+"px";
-if(_4.style.height!=_5){
-_4.style.maxHeight=_4.style.height=_5;
-}
-if(this._needsHelpShrinking){
-if(this._setTimeoutHandle){
-clearTimeout(this._setTimeoutHandle);
-}
-this._setTimeoutHandle=setTimeout(dojo.hitch(this,"_shrink"),0);
-}
-}else{
-this._estimateHeight(_4);
-}
-this._busyResizing=false;
-},_busyResizing:false,_shrink:function(){
-this._setTimeoutHandle=null;
-if(this._needsHelpShrinking&&!this._busyResizing){
-this._busyResizing=true;
-var _6=this.textbox;
-var _7=false;
-if(_6.value==""){
-_6.value=" ";
-_7=true;
-}
-var _8=_6.scrollHeight;
-if(!_8){
-this._estimateHeight(_6);
-}else{
-var _9=_6.style.paddingBottom;
-var _a=dojo._getPadExtents(_6);
-_a=_a.h-_a.t;
-_6.style.paddingBottom=_a+1+"px";
-var _b=this._getHeight(_6)-1+"px";
-if(_6.style.maxHeight!=_b){
-_6.style.paddingBottom=_a+_8+"px";
-_6.scrollTop=0;
-_6.style.maxHeight=this._getHeight(_6)-_8+"px";
-}
-_6.style.paddingBottom=_9;
-}
-if(_7){
-_6.value="";
-}
-this._busyResizing=false;
-}
-},resize:function(){
-this._onInput();
-},_setValueAttr:function(){
-this.inherited(arguments);
-this.resize();
-},postCreate:function(){
-this.inherited(arguments);
-dojo.style(this.textbox,{overflowY:"hidden",overflowX:"auto",boxSizing:"border-box",MsBoxSizing:"border-box",WebkitBoxSizing:"border-box",MozBoxSizing:"border-box"});
-this.connect(this.textbox,"onscroll",this._onInput);
-this.connect(this.textbox,"onresize",this._onInput);
-this.connect(this.textbox,"onfocus",this._onInput);
-this._setTimeoutHandle=setTimeout(dojo.hitch(this,"resize"),0);
-},uninitialize:function(){
-if(this._setTimeoutHandle){
-clearTimeout(this._setTimeoutHandle);
-}
-this.inherited(arguments);
-}});
+
+
+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);
+ }
+});
+
}
diff --git a/lib/dijit/form/TimeTextBox.js b/lib/dijit/form/TimeTextBox.js
index f5e7f99e3..81949c4a1 100644
--- a/lib/dijit/form/TimeTextBox.js
+++ b/lib/dijit/form/TimeTextBox.js
@@ -1,14 +1,87 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.TimeTextBox"]){
-dojo._hasResource["dijit.form.TimeTextBox"]=true;
+if(!dojo._hasResource["dijit.form.TimeTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form.TimeTextBox"] = true;
dojo.provide("dijit.form.TimeTextBox");
dojo.require("dijit._TimePicker");
dojo.require("dijit.form._DateTimeTextBox");
-dojo.declare("dijit.form.TimeTextBox",dijit.form._DateTimeTextBox,{baseClass:"dijitTextBox dijitTimeTextBox",popupClass:"dijit._TimePicker",_selector:"time",value:new Date("")});
+
+
+/*=====
+dojo.declare(
+ "dijit.form.TimeTextBox.__Constraints",
+ [dijit.form._DateTimeTextBox.__Constraints, dijit._TimePicker.__Constraints]
+);
+=====*/
+
+dojo.declare(
+ "dijit.form.TimeTextBox",
+ dijit.form._DateTimeTextBox,
+ {
+ // summary:
+ // A validating, serializable, range-bound time text box with a drop down time picker
+
+ baseClass: "dijitTextBox dijitComboBox dijitTimeTextBox",
+ popupClass: "dijit._TimePicker",
+ _selector: "time",
+
+/*=====
+ // constraints: dijit.form.TimeTextBox.__Constraints
+ constraints:{},
+=====*/
+
+ // value: Date
+ // The value of this widget as a JavaScript Date object. Note that the date portion implies time zone and daylight savings rules.
+ //
+ // Example:
+ // | new dijit.form.TimeTextBox({value: dojo.date.stamp.fromISOString("T12:59:59", new Date())})
+ //
+ // When passed to the parser in markup, must be specified according to locale-independent
+ // `dojo.date.stamp.fromISOString` format.
+ //
+ // Example:
+ // | <input dojotype='dijit.form.TimeTextBox' value='T12:34:00'>
+ value: new Date(""), // value.toString()="NaN"
+ //FIXME: in markup, you have no control over daylight savings
+
+ _onKey: function(evt){
+ this.inherited(arguments);
+
+ // If the user has backspaced or typed some numbers, then filter the result list
+ // by what they typed. Maybe there's a better way to detect this, like _handleOnChange()?
+ switch(evt.keyCode){
+ case dojo.keys.ENTER:
+ case dojo.keys.TAB:
+ case dojo.keys.ESCAPE:
+ case dojo.keys.DOWN_ARROW:
+ case dojo.keys.UP_ARROW:
+ // these keys have special meaning
+ break;
+ default:
+ // setTimeout() because the keystroke hasn't yet appeared in the <input>,
+ // so the get('displayedValue') call below won't give the result we want.
+ setTimeout(dojo.hitch(this, function(){
+ // set this.filterString to the filter to apply to the drop down list;
+ // it will be used in openDropDown()
+ var val = this.get('displayedValue');
+ this.filterString = (val && !this.parse(val, this.constraints)) ? val.toLowerCase() : "";
+
+ // close the drop down and reopen it, in order to filter the items shown in the list
+ // and also since the drop down may need to be repositioned if the number of list items has changed
+ // and it's being displayed above the <input>
+ if(this._opened){
+ this.closeDropDown();
+ }
+ this.openDropDown();
+ }), 0);
+ }
+ }
+ }
+);
+
}
diff --git a/lib/dijit/form/ToggleButton.js b/lib/dijit/form/ToggleButton.js
index f67dd0880..27b836fbd 100644
--- a/lib/dijit/form/ToggleButton.js
+++ b/lib/dijit/form/ToggleButton.js
@@ -1,12 +1,15 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.ToggleButton"]){
-dojo._hasResource["dijit.form.ToggleButton"]=true;
+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");
dojo.require("dijit.form.Button");
+
+
+
}
diff --git a/lib/dijit/form/ValidationTextBox.js b/lib/dijit/form/ValidationTextBox.js
index 2e0f17317..ee4292441 100644
--- a/lib/dijit/form/ValidationTextBox.js
+++ b/lib/dijit/form/ValidationTextBox.js
@@ -1,211 +1,486 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.ValidationTextBox"]){
-dojo._hasResource["dijit.form.ValidationTextBox"]=true;
+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");
dojo.require("dojo.i18n");
dojo.require("dijit.form.TextBox");
dojo.require("dijit.Tooltip");
-dojo.requireLocalization("dijit.form","validate",null,"ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
-dojo.declare("dijit.form.ValidationTextBox",dijit.form.TextBox,{templateString:dojo.cache("dijit.form","templates/ValidationTextBox.html","<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\" waiRole=\"presentation\"\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&Chi; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),baseClass:"dijitTextBox dijitValidationTextBox",required:false,promptMessage:"",invalidMessage:"$_unset_$",missingMessage:"$_unset_$",constraints:{},regExp:".*",regExpGen:function(_1){
-return this.regExp;
-},state:"",tooltipPosition:[],_setValueAttr:function(){
-this.inherited(arguments);
-this.validate(this._focused);
-},validator:function(_2,_3){
-return (new RegExp("^(?:"+this.regExpGen(_3)+")"+(this.required?"":"?")+"$")).test(_2)&&(!this.required||!this._isEmpty(_2))&&(this._isEmpty(_2)||this.parse(_2,_3)!==undefined);
-},_isValidSubset:function(){
-return this.textbox.value.search(this._partialre)==0;
-},isValid:function(_4){
-return this.validator(this.textbox.value,this.constraints);
-},_isEmpty:function(_5){
-return /^\s*$/.test(_5);
-},getErrorMessage:function(_6){
-return (this.required&&this._isEmpty(this.textbox.value))?this.missingMessage:this.invalidMessage;
-},getPromptMessage:function(_7){
-return this.promptMessage;
-},_maskValidSubsetError:true,validate:function(_8){
-var _9="";
-var _a=this.disabled||this.isValid(_8);
-if(_a){
-this._maskValidSubsetError=true;
-}
-var _b=this._isEmpty(this.textbox.value);
-var _c=!_a&&!_b&&_8&&this._isValidSubset();
-this.state=((_a||((!this._hasBeenBlurred||_8)&&_b)||_c)&&this._maskValidSubsetError)?"":"Error";
-if(this.state=="Error"){
-this._maskValidSubsetError=_8;
-}
-this._setStateClass();
-dijit.setWaiState(this.focusNode,"invalid",_a?"false":"true");
-if(_8){
-if(this.state=="Error"){
-_9=this.getErrorMessage(true);
-}else{
-_9=this.getPromptMessage(true);
-}
-this._maskValidSubsetError=true;
-}
-this.displayMessage(_9);
-return _a;
-},_message:"",displayMessage:function(_d){
-if(this._message==_d){
-return;
-}
-this._message=_d;
-dijit.hideTooltip(this.domNode);
-if(_d){
-dijit.showTooltip(_d,this.domNode,this.tooltipPosition,!this.isLeftToRight());
-}
-},_refreshState:function(){
-this.validate(this._focused);
-this.inherited(arguments);
-},constructor:function(){
-this.constraints={};
-},_setConstraintsAttr:function(_e){
-if(!_e.locale&&this.lang){
-_e.locale=this.lang;
-}
-this.constraints=_e;
-this._computePartialRE();
-},_computePartialRE:function(){
-var p=this.regExpGen(this.constraints);
-this.regExp=p;
-var _f="";
-if(p!=".*"){
-this.regExp.replace(/\\.|\[\]|\[.*?[^\\]{1}\]|\{.*?\}|\(\?[=:!]|./g,function(re){
-switch(re.charAt(0)){
-case "{":
-case "+":
-case "?":
-case "*":
-case "^":
-case "$":
-case "|":
-case "(":
-_f+=re;
-break;
-case ")":
-_f+="|$)";
-break;
-default:
-_f+="(?:"+re+"|$)";
-break;
-}
-});
-}
-try{
-"".search(_f);
-}
-catch(e){
-_f=this.regExp;
-console.warn("RegExp error in "+this.declaredClass+": "+this.regExp);
-}
-this._partialre="^(?:"+_f+")$";
-},postMixInProperties:function(){
-this.inherited(arguments);
-this.messages=dojo.i18n.getLocalization("dijit.form","validate",this.lang);
-if(this.invalidMessage=="$_unset_$"){
-this.invalidMessage=this.messages.invalidMessage;
-}
-if(!this.invalidMessage){
-this.invalidMessage=this.promptMessage;
-}
-if(this.missingMessage=="$_unset_$"){
-this.missingMessage=this.messages.missingMessage;
-}
-if(!this.missingMessage){
-this.missingMessage=this.invalidMessage;
-}
-this._setConstraintsAttr(this.constraints);
-},_setDisabledAttr:function(_10){
-this.inherited(arguments);
-this._refreshState();
-},_setRequiredAttr:function(_11){
-this.required=_11;
-dijit.setWaiState(this.focusNode,"required",_11);
-this._refreshState();
-},reset:function(){
-this._maskValidSubsetError=true;
-this.inherited(arguments);
-},_onBlur:function(){
-this.displayMessage("");
-this.inherited(arguments);
-}});
-dojo.declare("dijit.form.MappedTextBox",dijit.form.ValidationTextBox,{postMixInProperties:function(){
-this.inherited(arguments);
-this.nameAttrSetting="";
-},serialize:function(val,_12){
-return val.toString?val.toString():"";
-},toString:function(){
-var val=this.filter(this.get("value"));
-return val!=null?(typeof val=="string"?val:this.serialize(val,this.constraints)):"";
-},validate:function(){
-this.valueNode.value=this.toString();
-return this.inherited(arguments);
-},buildRendering:function(){
-this.inherited(arguments);
-this.valueNode=dojo.place("<input type='hidden'"+(this.name?" name='"+this.name+"'":"")+">",this.textbox,"after");
-},reset:function(){
-this.valueNode.value="";
-this.inherited(arguments);
-}});
-dojo.declare("dijit.form.RangeBoundTextBox",dijit.form.MappedTextBox,{rangeMessage:"",rangeCheck:function(_13,_14){
-return ("min" in _14?(this.compare(_13,_14.min)>=0):true)&&("max" in _14?(this.compare(_13,_14.max)<=0):true);
-},isInRange:function(_15){
-return this.rangeCheck(this.get("value"),this.constraints);
-},_isDefinitelyOutOfRange:function(){
-var val=this.get("value");
-var _16=false;
-var _17=false;
-if("min" in this.constraints){
-var min=this.constraints.min;
-min=this.compare(val,((typeof min=="number")&&min>=0&&val!=0)?0:min);
-_16=(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);
-_17=(typeof max=="number")&&max>0;
-}
-return _16||_17;
-},_isValidSubset:function(){
-return this.inherited(arguments)&&!this._isDefinitelyOutOfRange();
-},isValid:function(_18){
-return this.inherited(arguments)&&((this._isEmpty(this.textbox.value)&&!this.required)||this.isInRange(_18));
-},getErrorMessage:function(_19){
-var v=this.get("value");
-if(v!==null&&v!==""&&v!==undefined&&(typeof v!="number"||!isNaN(v))&&!this.isInRange(_19)){
-return this.rangeMessage;
-}
-return this.inherited(arguments);
-},postMixInProperties:function(){
-this.inherited(arguments);
-if(!this.rangeMessage){
-this.messages=dojo.i18n.getLocalization("dijit.form","validate",this.lang);
-this.rangeMessage=this.messages.rangeMessage;
-}
-},_setConstraintsAttr:function(_1a){
-this.inherited(arguments);
-if(this.focusNode){
-if(this.constraints.min!==undefined){
-dijit.setWaiState(this.focusNode,"valuemin",this.constraints.min);
-}else{
-dijit.removeWaiState(this.focusNode,"valuemin");
-}
-if(this.constraints.max!==undefined){
-dijit.setWaiState(this.focusNode,"valuemax",this.constraints.max);
-}else{
-dijit.removeWaiState(this.focusNode,"valuemax");
-}
-}
-},_setValueAttr:function(_1b,_1c){
-dijit.setWaiState(this.focusNode,"valuenow",_1b);
-this.inherited(arguments);
-}});
+dojo.requireLocalization("dijit.form", "validate", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
+
+
+/*=====
+ dijit.form.ValidationTextBox.__Constraints = function(){
+ // locale: String
+ // locale used for validation, picks up value from this widget's lang attribute
+ // _flags_: anything
+ // various flags passed to regExpGen function
+ this.locale = "";
+ this._flags_ = "";
+ }
+=====*/
+
+dojo.declare(
+ "dijit.form.ValidationTextBox",
+ dijit.form.TextBox,
+ {
+ // summary:
+ // Base class for textbox widgets with the ability to validate content of various types and provide user feedback.
+ // tags:
+ // protected
+
+ templateString: dojo.cache("dijit.form", "templates/ValidationTextBox.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\" role=\"presentation\"\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),
+ baseClass: "dijitTextBox dijitValidationTextBox",
+
+ // required: Boolean
+ // User is required to enter data into this field.
+ required: false,
+
+ // promptMessage: String
+ // If defined, display this hint string immediately on focus to the textbox, if empty.
+ // 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);
+ }
+ }
+);
+
}
diff --git a/lib/dijit/form/VerticalRule.js b/lib/dijit/form/VerticalRule.js
index 13576277f..98f612cf0 100644
--- a/lib/dijit/form/VerticalRule.js
+++ b/lib/dijit/form/VerticalRule.js
@@ -1,13 +1,35 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.VerticalRule"]){
-dojo._hasResource["dijit.form.VerticalRule"]=true;
+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.require("dijit.form.HorizontalRule");
-dojo.declare("dijit.form.VerticalRule",dijit.form.HorizontalRule,{templateString:"<div class=\"dijitRuleContainer dijitRuleContainerV\"></div>",_positionPrefix:"<div class=\"dijitRuleMark dijitRuleMarkV\" style=\"top:",_isHorizontal:false});
+
+
+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
+
+});
+
}
diff --git a/lib/dijit/form/VerticalRuleLabels.js b/lib/dijit/form/VerticalRuleLabels.js
index 9adac9056..57caba8b5 100644
--- a/lib/dijit/form/VerticalRuleLabels.js
+++ b/lib/dijit/form/VerticalRuleLabels.js
@@ -1,15 +1,33 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.VerticalRuleLabels"]){
-dojo._hasResource["dijit.form.VerticalRuleLabels"]=true;
+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.require("dijit.form.HorizontalRuleLabels");
-dojo.declare("dijit.form.VerticalRuleLabels",dijit.form.HorizontalRuleLabels,{templateString:"<div class=\"dijitRuleContainer dijitRuleContainerV dijitRuleLabelsContainer dijitRuleLabelsContainerV\"></div>",_positionPrefix:"<div class=\"dijitRuleLabelContainer dijitRuleLabelContainerV\" style=\"top:",_labelPrefix:"\"><span class=\"dijitRuleLabel dijitRuleLabelV\">",_calcPosition:function(_1){
-return 100-_1;
-},_isHorizontal:false});
+
+
+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
+});
+
}
diff --git a/lib/dijit/form/VerticalSlider.js b/lib/dijit/form/VerticalSlider.js
index 9e98cbe0f..f074c7cd1 100644
--- a/lib/dijit/form/VerticalSlider.js
+++ b/lib/dijit/form/VerticalSlider.js
@@ -1,15 +1,42 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form.VerticalSlider"]){
-dojo._hasResource["dijit.form.VerticalSlider"]=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.require("dijit.form.HorizontalSlider");
-dojo.declare("dijit.form.VerticalSlider",dijit.form.HorizontalSlider,{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\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\n\t\t\t><div class=\"dijitSliderIncrementIconV\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"decrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderTopBumper\" dojoAttachEvent=\"onmousedown:_onClkIncBumper\"></div></center\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td dojoAttachPoint=\"leftDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationL dijitSliderDecorationV\"></td\n\t\t><td class=\"dijitReset\" style=\"height:100%;\"\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\n\t\t\t/><center class=\"dijitReset dijitSliderBarContainerV\" waiRole=\"presentation\" dojoAttachPoint=\"sliderBarContainer\"\n\t\t\t\t><div waiRole=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderRemainingBar dijitSliderRemainingBarV\" dojoAttachEvent=\"onmousedown:_onBarClick\"><!--#5629--></div\n\t\t\t\t><div waiRole=\"presentation\" dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderProgressBar dijitSliderProgressBarV\" dojoAttachEvent=\"onmousedown:_onBarClick\"\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableV\" style=\"vertical-align:top;\"\n\t\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleV\" dojoAttachEvent=\"onmousedown:_onHandleClick\" waiRole=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t></center\n\t\t></td\n\t\t><td dojoAttachPoint=\"containerNode,rightDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationR dijitSliderDecorationV\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderBottomBumper\" dojoAttachEvent=\"onmousedown:_onClkDecBumper\"></div></center\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\n\t\t\t><div class=\"dijitSliderDecrementIconV\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"incrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n></table>\n"),_mousePixelCoord:"pageY",_pixelCount:"h",_startingPixelCoord:"y",_startingPixelCount:"t",_handleOffsetCoord:"top",_progressPixelSize:"height",_descending:true,_isReversed:function(){
-return this._descending;
-}});
+
+
+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\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\n\t\t\t><div class=\"dijitSliderIncrementIconV\" style=\"display:none\" dojoAttachPoint=\"decrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderTopBumper\" dojoAttachEvent=\"onmousedown:_onClkIncBumper\"></div></center\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td dojoAttachPoint=\"leftDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationL dijitSliderDecorationV\"></td\n\t\t><td class=\"dijitReset dijitSliderDecorationC\" style=\"height:100%;\"\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\n\t\t\t/><center class=\"dijitReset dijitSliderBarContainerV\" role=\"presentation\" dojoAttachPoint=\"sliderBarContainer\"\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderRemainingBar dijitSliderRemainingBarV\" dojoAttachEvent=\"onmousedown:_onBarClick\"><!--#5629--></div\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderProgressBar dijitSliderProgressBarV\" dojoAttachEvent=\"onmousedown:_onBarClick\"\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableV\" style=\"vertical-align:top;\"\n\t\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleV\" dojoAttachEvent=\"onmousedown:_onHandleClick\" role=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t></center\n\t\t></td\n\t\t><td dojoAttachPoint=\"containerNode,rightDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationR dijitSliderDecorationV\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderBottomBumper\" dojoAttachEvent=\"onmousedown:_onClkDecBumper\"></div></center\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\n\t\t\t><div class=\"dijitSliderDecrementIconV\" style=\"display:none\" dojoAttachPoint=\"incrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n></table>\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;
+ }
+});
+
}
diff --git a/lib/dijit/form/_DateTimeTextBox.js b/lib/dijit/form/_DateTimeTextBox.js
index 72898e406..9d5c004c8 100644
--- a/lib/dijit/form/_DateTimeTextBox.js
+++ b/lib/dijit/form/_DateTimeTextBox.js
@@ -1,148 +1,250 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form._DateTimeTextBox"]){
-dojo._hasResource["dijit.form._DateTimeTextBox"]=true;
+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");
dojo.require("dojo.date");
dojo.require("dojo.date.locale");
dojo.require("dojo.date.stamp");
dojo.require("dijit.form.ValidationTextBox");
-new Date("X");
-dojo.declare("dijit.form._DateTimeTextBox",dijit.form.RangeBoundTextBox,{regExpGen:dojo.date.locale.regexp,datePackage:"dojo.date",compare:dojo.date.compare,format:function(_1,_2){
-if(!_1){
-return "";
-}
-return this.dateLocaleModule.format(_1,_2);
-},parse:function(_3,_4){
-return this.dateLocaleModule.parse(_3,_4)||(this._isEmpty(_3)?null:undefined);
-},serialize:function(_5,_6){
-if(_5.toGregorian){
-_5=_5.toGregorian();
-}
-return dojo.date.stamp.toISOString(_5,_6);
-},value:new Date(""),_blankValue:null,popupClass:"",_selector:"",constructor:function(_7){
-var _8=_7.datePackage?_7.datePackage+".Date":"Date";
-this.dateClassObj=dojo.getObject(_8,false);
-this.value=new this.dateClassObj("");
-this.datePackage=_7.datePackage||this.datePackage;
-this.dateLocaleModule=dojo.getObject(this.datePackage+".locale",false);
-this.regExpGen=this.dateLocaleModule.regexp;
-},_setConstraintsAttr:function(_9){
-_9.selector=this._selector;
-_9.fullYear=true;
-var _a=dojo.date.stamp.fromISOString;
-if(typeof _9.min=="string"){
-_9.min=_a(_9.min);
-}
-if(typeof _9.max=="string"){
-_9.max=_a(_9.max);
-}
-this.inherited(arguments,[_9]);
-},_onFocus:function(_b){
-this._open();
-this.inherited(arguments);
-},_setValueAttr:function(_c,_d,_e){
-if(_c!==undefined){
-if(!_c||_c.toString()==dijit.form._DateTimeTextBox.prototype.value.toString()){
-_c=null;
-}
-if(_c instanceof Date&&!(this.dateClassObj instanceof Date)){
-_c=new this.dateClassObj(_c);
-}
-}
-this.inherited(arguments,[_c,_d,_e]);
-if(this._picker){
-if(!_c){
-_c=new this.dateClassObj();
-}
-this._picker.set("value",_c);
-}
-},_open:function(){
-if(this.disabled||this.readOnly||!this.popupClass){
-return;
-}
-var _f=this;
-if(!this._picker){
-var _10=dojo.getObject(this.popupClass,false);
-this._picker=new _10({onValueSelected:function(_11){
-if(_f._tabbingAway){
-delete _f._tabbingAway;
-}else{
-_f.focus();
-}
-setTimeout(dojo.hitch(_f,"_close"),1);
-dijit.form._DateTimeTextBox.superclass._setValueAttr.call(_f,_11,true);
-},id:this.id+"_popup",dir:_f.dir,lang:_f.lang,value:this.get("value")||new this.dateClassObj(),constraints:_f.constraints,datePackage:_f.datePackage,isDisabledDate:function(_12){
-var _13=dojo.date.compare;
-var _14=_f.constraints;
-return _14&&((_14.min&&_13(_14.min,_12,_f._selector)>0)||(_14.max&&_13(_14.max,_12,_f._selector)<0));
-}});
-}
-if(!this._opened){
-dijit.popup.open({parent:this,popup:this._picker,orient:{"BL":"TL","TL":"BL"},around:this.domNode,onCancel:dojo.hitch(this,this._close),onClose:function(){
-_f._opened=false;
-}});
-this._opened=true;
-}
-dojo.marginBox(this._picker.domNode,{w:this.domNode.offsetWidth});
-},_close:function(){
-if(this._opened){
-dijit.popup.close(this._picker);
-this._opened=false;
-}
-},_onBlur:function(){
-this._close();
-if(this._picker){
-this._picker.destroy();
-delete this._picker;
-}
-this.inherited(arguments);
-},_getDisplayedValueAttr:function(){
-return this.textbox.value;
-},_setDisplayedValueAttr:function(_15,_16){
-this._setValueAttr(this.parse(_15,this.constraints),_16,_15);
-},destroy:function(){
-if(this._picker){
-this._picker.destroy();
-delete this._picker;
-}
-this.inherited(arguments);
-},postCreate:function(){
-this.inherited(arguments);
-this.connect(this.focusNode,"onkeypress",this._onKeyPress);
-this.connect(this.focusNode,"onclick",this._open);
-},_onKeyPress:function(e){
-var p=this._picker,dk=dojo.keys;
-if(p&&this._opened&&p.handleKey){
-if(p.handleKey(e)===false){
-return;
-}
-}
-if(this._opened&&e.charOrCode==dk.ESCAPE&&!(e.shiftKey||e.ctrlKey||e.altKey||e.metaKey)){
-this._close();
-dojo.stopEvent(e);
-}else{
-if(!this._opened&&e.charOrCode==dk.DOWN_ARROW){
-this._open();
-dojo.stopEvent(e);
-}else{
-if(e.charOrCode===dk.TAB){
-this._tabbingAway=true;
-}else{
-if(this._opened&&(e.keyChar||e.charOrCode===dk.BACKSPACE||e.charOrCode==dk.DELETE)){
-setTimeout(dojo.hitch(this,function(){
-if(this._picker&&this._opened){
-dijit.placeOnScreenAroundElement(p.domNode.parentNode,this.domNode,{"BL":"TL","TL":"BL"},p.orient?dojo.hitch(p,"orient"):null);
-}
-}),1);
-}
-}
-}
-}
-}});
+dojo.require("dijit._HasDropDown");
+
+
+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\"\n\tid=\"widget_${id}\"\n\trole=\"combobox\"\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\n\t\tdojoAttachPoint=\"_buttonNode, _popupStateNode\" role=\"presentation\"\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t\t\t${_buttonInputDisabled}\n\t/></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\n\t/></div\n></div>\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){
+ var isInvalid1 = this._isInvalidDate(val1);
+ var isInvalid2 = this._isInvalidDate(val2);
+ return isInvalid1 ? (isInvalid2 ? 0 : -1) : (isInvalid2 ? 1 : 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);
+ },
+
+ _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);
+ 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.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);
+ }
+ }
+);
+
}
diff --git a/lib/dijit/form/_FormMixin.js b/lib/dijit/form/_FormMixin.js
index 4c52ed9e2..e42702d31 100644
--- a/lib/dijit/form/_FormMixin.js
+++ b/lib/dijit/form/_FormMixin.js
@@ -1,158 +1,461 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form._FormMixin"]){
-dojo._hasResource["dijit.form._FormMixin"]=true;
+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.require("dojo.window");
-dojo.declare("dijit.form._FormMixin",null,{reset:function(){
-dojo.forEach(this.getDescendants(),function(_1){
-if(_1.reset){
-_1.reset();
-}
-});
-},validate:function(){
-var _2=false;
-return dojo.every(dojo.map(this.getDescendants(),function(_3){
-_3._hasBeenBlurred=true;
-var _4=_3.disabled||!_3.validate||_3.validate();
-if(!_4&&!_2){
-dojo.window.scrollIntoView(_3.containerNode||_3.domNode);
-_3.focus();
-_2=true;
-}
-return _4;
-}),function(_5){
-return _5;
-});
-},setValues:function(_6){
-dojo.deprecated(this.declaredClass+"::setValues() is deprecated. Use set('value', val) instead.","","2.0");
-return this.set("value",_6);
-},_setValueAttr:function(_7){
-var _8={};
-dojo.forEach(this.getDescendants(),function(_9){
-if(!_9.name){
-return;
-}
-var _a=_8[_9.name]||(_8[_9.name]=[]);
-_a.push(_9);
-});
-for(var _b in _8){
-if(!_8.hasOwnProperty(_b)){
-continue;
-}
-var _c=_8[_b],_d=dojo.getObject(_b,false,_7);
-if(_d===undefined){
-continue;
-}
-if(!dojo.isArray(_d)){
-_d=[_d];
-}
-if(typeof _c[0].checked=="boolean"){
-dojo.forEach(_c,function(w,i){
-w.set("value",dojo.indexOf(_d,w.value)!=-1);
-});
-}else{
-if(_c[0].multiple){
-_c[0].set("value",_d);
-}else{
-dojo.forEach(_c,function(w,i){
-w.set("value",_d[i]);
-});
-}
-}
-}
-},getValues:function(){
-dojo.deprecated(this.declaredClass+"::getValues() is deprecated. Use get('value') instead.","","2.0");
-return this.get("value");
-},_getValueAttr:function(){
-var _e={};
-dojo.forEach(this.getDescendants(),function(_f){
-var _10=_f.name;
-if(!_10||_f.disabled){
-return;
-}
-var _11=_f.get("value");
-if(typeof _f.checked=="boolean"){
-if(/Radio/.test(_f.declaredClass)){
-if(_11!==false){
-dojo.setObject(_10,_11,_e);
-}else{
-_11=dojo.getObject(_10,false,_e);
-if(_11===undefined){
-dojo.setObject(_10,null,_e);
-}
-}
-}else{
-var ary=dojo.getObject(_10,false,_e);
-if(!ary){
-ary=[];
-dojo.setObject(_10,ary,_e);
-}
-if(_11!==false){
-ary.push(_11);
-}
-}
-}else{
-var _12=dojo.getObject(_10,false,_e);
-if(typeof _12!="undefined"){
-if(dojo.isArray(_12)){
-_12.push(_11);
-}else{
-dojo.setObject(_10,[_12,_11],_e);
-}
-}else{
-dojo.setObject(_10,_11,_e);
-}
-}
-});
-return _e;
-},isValid:function(){
-this._invalidWidgets=dojo.filter(this.getDescendants(),function(_13){
-return !_13.disabled&&_13.isValid&&!_13.isValid();
-});
-return !this._invalidWidgets.length;
-},onValidStateChange:function(_14){
-},_widgetChange:function(_15){
-var _16=this._lastValidState;
-if(!_15||this._lastValidState===undefined){
-_16=this.isValid();
-if(this._lastValidState===undefined){
-this._lastValidState=_16;
-}
-}else{
-if(_15.isValid){
-this._invalidWidgets=dojo.filter(this._invalidWidgets||[],function(w){
-return (w!=_15);
-},this);
-if(!_15.isValid()&&!_15.get("disabled")){
-this._invalidWidgets.push(_15);
-}
-_16=(this._invalidWidgets.length===0);
-}
-}
-if(_16!==this._lastValidState){
-this._lastValidState=_16;
-this.onValidStateChange(_16);
-}
-},connectChildren:function(){
-dojo.forEach(this._changeConnections,dojo.hitch(this,"disconnect"));
-var _17=this;
-var _18=(this._changeConnections=[]);
-dojo.forEach(dojo.filter(this.getDescendants(),function(_19){
-return _19.validate;
-}),function(_1a){
-_18.push(_17.connect(_1a,"validate",dojo.hitch(_17,"_widgetChange",_1a)));
-_18.push(_17.connect(_1a,"_setDisabledAttr",dojo.hitch(_17,"_widgetChange",_1a)));
-});
-this._widgetChange(null);
-},startup:function(){
-this.inherited(arguments);
-this._changeConnections=[];
-this.connectChildren();
-}});
+
+
+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);
+ }
+
+ });
+
}
diff --git a/lib/dijit/form/_FormSelectWidget.js b/lib/dijit/form/_FormSelectWidget.js
index 5905c0aef..fbbf7226b 100644
--- a/lib/dijit/form/_FormSelectWidget.js
+++ b/lib/dijit/form/_FormSelectWidget.js
@@ -1,307 +1,582 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form._FormSelectWidget"]){
-dojo._hasResource["dijit.form._FormSelectWidget"]=true;
+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");
dojo.require("dijit.form._FormWidget");
dojo.require("dojo.data.util.sorter");
-dojo.declare("dijit.form._FormSelectWidget",dijit.form._FormValueWidget,{multiple:false,options:null,store:null,query:null,queryOptions:null,onFetch:null,sortByLabel:true,loadChildrenOnOpen:false,getOptions:function(_1){
-var _2=_1,_3=this.options||[],l=_3.length;
-if(_2===undefined){
-return _3;
-}
-if(dojo.isArray(_2)){
-return dojo.map(_2,"return this.getOptions(item);",this);
-}
-if(dojo.isObject(_1)){
-if(!dojo.some(this.options,function(o,_4){
-if(o===_2||(o.value&&o.value===_2.value)){
-_2=_4;
-return true;
-}
-return false;
-})){
-_2=-1;
-}
-}
-if(typeof _2=="string"){
-for(var i=0;i<l;i++){
-if(_3[i].value===_2){
-_2=i;
-break;
-}
-}
-}
-if(typeof _2=="number"&&_2>=0&&_2<l){
-return this.options[_2];
-}
-return null;
-},addOption:function(_5){
-if(!dojo.isArray(_5)){
-_5=[_5];
-}
-dojo.forEach(_5,function(i){
-if(i&&dojo.isObject(i)){
-this.options.push(i);
-}
-},this);
-this._loadChildren();
-},removeOption:function(_6){
-if(!dojo.isArray(_6)){
-_6=[_6];
-}
-var _7=this.getOptions(_6);
-dojo.forEach(_7,function(i){
-if(i){
-this.options=dojo.filter(this.options,function(_8,_9){
-return (_8.value!==i.value);
-});
-this._removeOptionItem(i);
-}
-},this);
-this._loadChildren();
-},updateOption:function(_a){
-if(!dojo.isArray(_a)){
-_a=[_a];
-}
-dojo.forEach(_a,function(i){
-var _b=this.getOptions(i),k;
-if(_b){
-for(k in i){
-_b[k]=i[k];
-}
-}
-},this);
-this._loadChildren();
-},setStore:function(_c,_d,_e){
-var _f=this.store;
-_e=_e||{};
-if(_f!==_c){
-dojo.forEach(this._notifyConnections||[],dojo.disconnect);
-delete this._notifyConnections;
-if(_c&&_c.getFeatures()["dojo.data.api.Notification"]){
-this._notifyConnections=[dojo.connect(_c,"onNew",this,"_onNewItem"),dojo.connect(_c,"onDelete",this,"_onDeleteItem"),dojo.connect(_c,"onSet",this,"_onSetItem")];
-}
-this.store=_c;
-}
-this._onChangeActive=false;
-if(this.options&&this.options.length){
-this.removeOption(this.options);
-}
-if(_c){
-var cb=function(_10){
-if(this.sortByLabel&&!_e.sort&&_10.length){
-_10.sort(dojo.data.util.sorter.createSortFunction([{attribute:_c.getLabelAttributes(_10[0])[0]}],_c));
-}
-if(_e.onFetch){
-_10=_e.onFetch(_10);
-}
-dojo.forEach(_10,function(i){
-this._addOptionForItem(i);
-},this);
-this._loadingStore=false;
-this.set("value",(("_pendingValue" in this)?this._pendingValue:_d));
-delete this._pendingValue;
-if(!this.loadChildrenOnOpen){
-this._loadChildren();
-}else{
-this._pseudoLoadChildren(_10);
-}
-this._fetchedWith=_11;
-this._lastValueReported=this.multiple?[]:null;
-this._onChangeActive=true;
-this.onSetStore();
-this._handleOnChange(this.value);
-};
-var _11=dojo.mixin({onComplete:cb,scope:this},_e);
-this._loadingStore=true;
-_c.fetch(_11);
-}else{
-delete this._fetchedWith;
-}
-return _f;
-},_setValueAttr:function(_12,_13){
-if(this._loadingStore){
-this._pendingValue=_12;
-return;
-}
-var _14=this.getOptions()||[];
-if(!dojo.isArray(_12)){
-_12=[_12];
-}
-dojo.forEach(_12,function(i,idx){
-if(!dojo.isObject(i)){
-i=i+"";
-}
-if(typeof i==="string"){
-_12[idx]=dojo.filter(_14,function(_15){
-return _15.value===i;
-})[0]||{value:"",label:""};
-}
-},this);
-_12=dojo.filter(_12,function(i){
-return i&&i.value;
-});
-if(!this.multiple&&(!_12[0]||!_12[0].value)&&_14.length){
-_12[0]=_14[0];
-}
-dojo.forEach(_14,function(i){
-i.selected=dojo.some(_12,function(v){
-return v.value===i.value;
-});
-});
-var val=dojo.map(_12,function(i){
-return i.value;
-}),_16=dojo.map(_12,function(i){
-return i.label;
-});
-this.value=this.multiple?val:val[0];
-this._setDisplay(this.multiple?_16:_16[0]);
-this._updateSelection();
-this._handleOnChange(this.value,_13);
-},_getDisplayedValueAttr:function(){
-var val=this.get("value");
-if(!dojo.isArray(val)){
-val=[val];
-}
-var ret=dojo.map(this.getOptions(val),function(v){
-if(v&&"label" in v){
-return v.label;
-}else{
-if(v){
-return v.value;
-}
-}
-return null;
-},this);
-return this.multiple?ret:ret[0];
-},_getValueDeprecated:false,getValue:function(){
-return this._lastValue;
-},undo:function(){
-this._setValueAttr(this._lastValueReported,false);
-},_loadChildren:function(){
-if(this._loadingStore){
-return;
-}
-dojo.forEach(this._getChildren(),function(_17){
-_17.destroyRecursive();
-});
-dojo.forEach(this.options,this._addOptionItem,this);
-this._updateSelection();
-},_updateSelection:function(){
-this.value=this._getValueFromOpts();
-var val=this.value;
-if(!dojo.isArray(val)){
-val=[val];
-}
-if(val&&val[0]){
-dojo.forEach(this._getChildren(),function(_18){
-var _19=dojo.some(val,function(v){
-return _18.option&&(v===_18.option.value);
+
+
+/*=====
+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
+ }
});
-dojo.toggleClass(_18.domNode,this.baseClass+"SelectedOption",_19);
-dijit.setWaiState(_18.domNode,"selected",_19);
-},this);
-}
-this._handleOnChange(this.value);
-},_getValueFromOpts:function(){
-var _1a=this.getOptions()||[];
-if(!this.multiple&&_1a.length){
-var opt=dojo.filter(_1a,function(i){
-return i.selected;
-})[0];
-if(opt&&opt.value){
-return opt.value;
-}else{
-_1a[0].selected=true;
-return _1a[0].value;
-}
-}else{
-if(this.multiple){
-return dojo.map(dojo.filter(_1a,function(i){
-return i.selected;
-}),function(i){
-return i.value;
-})||[];
-}
-}
-return "";
-},_onNewItem:function(_1b,_1c){
-if(!_1c||!_1c.parent){
-this._addOptionForItem(_1b);
-}
-},_onDeleteItem:function(_1d){
-var _1e=this.store;
-this.removeOption(_1e.getIdentity(_1d));
-},_onSetItem:function(_1f){
-this.updateOption(this._getOptionObjForItem(_1f));
-},_getOptionObjForItem:function(_20){
-var _21=this.store,_22=_21.getLabel(_20),_23=(_22?_21.getIdentity(_20):null);
-return {value:_23,label:_22,item:_20};
-},_addOptionForItem:function(_24){
-var _25=this.store;
-if(!_25.isItemLoaded(_24)){
-_25.loadItem({item:_24,onComplete:function(i){
-this._addOptionForItem(_24);
-},scope:this});
-return;
-}
-var _26=this._getOptionObjForItem(_24);
-this.addOption(_26);
-},constructor:function(_27){
-this._oValue=(_27||{}).value||null;
-},_fillContent:function(){
-var _28=this.options;
-if(!_28){
-_28=this.options=this.srcNodeRef?dojo.query(">",this.srcNodeRef).map(function(_29){
-if(_29.getAttribute("type")==="separator"){
-return {value:"",label:"",selected:false,disabled:false};
-}
-return {value:_29.getAttribute("value"),label:String(_29.innerHTML),selected:_29.getAttribute("selected")||false,disabled:_29.getAttribute("disabled")||false};
-},this):[];
-}
-if(!this.value){
-this.value=this._getValueFromOpts();
-}else{
-if(this.multiple&&typeof this.value=="string"){
-this.value=this.value.split(",");
-}
-}
-},postCreate:function(){
-dojo.setSelectable(this.focusNode,false);
-this.inherited(arguments);
-this.connect(this,"onChange","_updateSelection");
-this.connect(this,"startup","_loadChildren");
-this._setValueAttr(this.value,null);
-},startup:function(){
-this.inherited(arguments);
-var _2a=this.store,_2b={};
-dojo.forEach(["query","queryOptions","onFetch"],function(i){
-if(this[i]){
-_2b[i]=this[i];
-}
-delete this[i];
-},this);
-if(_2a&&_2a.getFeatures()["dojo.data.api.Identity"]){
-this.store=null;
-this.setStore(_2a,this._oValue,_2b);
-}
-},destroy:function(){
-dojo.forEach(this._notifyConnections||[],dojo.disconnect);
-this.inherited(arguments);
-},_addOptionItem:function(_2c){
-},_removeOptionItem:function(_2d){
-},_setDisplay:function(_2e){
-},_getChildren:function(){
-return [];
-},_getSelectedOptionsAttr:function(){
-return this.getOptions(this.get("value"));
-},_pseudoLoadChildren:function(_2f){
-},onSetStore:function(){
-}});
+
}
diff --git a/lib/dijit/form/_FormWidget.js b/lib/dijit/form/_FormWidget.js
index eb80ca06b..ebd1cfb18 100644
--- a/lib/dijit/form/_FormWidget.js
+++ b/lib/dijit/form/_FormWidget.js
@@ -1,166 +1,377 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form._FormWidget"]){
-dojo._hasResource["dijit.form._FormWidget"]=true;
+if(!dojo._hasResource["dijit.form._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.form._FormWidget"] = true;
dojo.provide("dijit.form._FormWidget");
dojo.require("dojo.window");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dijit._CssStateMixin");
-dojo.declare("dijit.form._FormWidget",[dijit._Widget,dijit._Templated,dijit._CssStateMixin],{name:"",alt:"",value:"",type:"text",tabIndex:"0",disabled:false,intermediateChanges:false,scrollOnFocus:true,attributeMap:dojo.delegate(dijit._Widget.prototype.attributeMap,{value:"focusNode",id:"focusNode",tabIndex:"focusNode",alt:"focusNode",title:"focusNode"}),postMixInProperties:function(){
-this.nameAttrSetting=this.name?("name=\""+this.name.replace(/'/g,"&quot;")+"\""):"";
-this.inherited(arguments);
-},postCreate:function(){
-this.inherited(arguments);
-this.connect(this.domNode,"onmousedown","_onMouseDown");
-},_setDisabledAttr:function(_1){
-this.disabled=_1;
-dojo.attr(this.focusNode,"disabled",_1);
-if(this.valueNode){
-dojo.attr(this.valueNode,"disabled",_1);
-}
-dijit.setWaiState(this.focusNode,"disabled",_1);
-if(_1){
-this._hovering=false;
-this._active=false;
-var _2="tabIndex" in this.attributeMap?this.attributeMap.tabIndex:"focusNode";
-dojo.forEach(dojo.isArray(_2)?_2:[_2],function(_3){
-var _4=this[_3];
-if(dojo.isWebKit||dijit.hasDefaultTabStop(_4)){
-_4.setAttribute("tabIndex","-1");
-}else{
-_4.removeAttribute("tabIndex");
-}
-},this);
-}else{
-this.focusNode.setAttribute("tabIndex",this.tabIndex);
-}
-},setDisabled:function(_5){
-dojo.deprecated("setDisabled("+_5+") is deprecated. Use set('disabled',"+_5+") instead.","","2.0");
-this.set("disabled",_5);
-},_onFocus:function(e){
-if(this.scrollOnFocus){
-dojo.window.scrollIntoView(this.domNode);
-}
-this.inherited(arguments);
-},isFocusable:function(){
-return !this.disabled&&!this.readOnly&&this.focusNode&&(dojo.style(this.domNode,"display")!="none");
-},focus:function(){
-dijit.focus(this.focusNode);
-},compare:function(_6,_7){
-if(typeof _6=="number"&&typeof _7=="number"){
-return (isNaN(_6)&&isNaN(_7))?0:_6-_7;
-}else{
-if(_6>_7){
-return 1;
-}else{
-if(_6<_7){
-return -1;
-}else{
-return 0;
-}
-}
-}
-},onChange:function(_8){
-},_onChangeActive:false,_handleOnChange:function(_9,_a){
-this._lastValue=_9;
-if(this._lastValueReported==undefined&&(_a===null||!this._onChangeActive)){
-this._resetValue=this._lastValueReported=_9;
-}
-if((this.intermediateChanges||_a||_a===undefined)&&((typeof _9!=typeof this._lastValueReported)||this.compare(_9,this._lastValueReported)!=0)){
-this._lastValueReported=_9;
-if(this._onChangeActive){
-if(this._onChangeHandle){
-clearTimeout(this._onChangeHandle);
-}
-this._onChangeHandle=setTimeout(dojo.hitch(this,function(){
-this._onChangeHandle=null;
-this.onChange(_9);
-}),0);
-}
-}
-},create:function(){
-this.inherited(arguments);
-this._onChangeActive=true;
-},destroy:function(){
-if(this._onChangeHandle){
-clearTimeout(this._onChangeHandle);
-this.onChange(this._lastValueReported);
-}
-this.inherited(arguments);
-},setValue:function(_b){
-dojo.deprecated("dijit.form._FormWidget:setValue("+_b+") is deprecated. Use set('value',"+_b+") instead.","","2.0");
-this.set("value",_b);
-},getValue:function(){
-dojo.deprecated(this.declaredClass+"::getValue() is deprecated. Use get('value') instead.","","2.0");
-return this.get("value");
-},_onMouseDown:function(e){
-if(!e.ctrlKey&&this.isFocusable()){
-var _c=this.connect(dojo.body(),"onmouseup",function(){
-if(this.isFocusable()){
-this.focus();
-}
-this.disconnect(_c);
+
+
+dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._CssStateMixin],
+ {
+ // summary:
+ // Base class for widgets corresponding to native HTML elements such as <checkbox> or <button>,
+ // which can be children of a <form> node or a `dijit.form.Form` widget.
+ //
+ // description:
+ // Represents a single HTML element.
+ // All these widgets should have these attributes just like native HTML input elements.
+ // You can set them during widget construction or afterwards, via `dijit._Widget.attr`.
+ //
+ // They also share some common methods.
+
+ // name: [const] String
+ // Name used when submitting form; same as "name" attribute or plain HTML elements
+ name: "",
+
+ // alt: String
+ // Corresponds to the native HTML <input> element's attribute.
+ alt: "",
+
+ // value: String
+ // Corresponds to the native HTML <input> element's attribute.
+ value: "",
+
+ // type: String
+ // Corresponds to the native HTML <input> element's attribute.
+ type: "text",
+
+ // tabIndex: Integer
+ // Order fields are traversed when user hits the tab key
+ tabIndex: "0",
+
+ // disabled: Boolean
+ // Should this widget respond to user input?
+ // In markup, this is specified as "disabled='disabled'", or just "disabled".
+ disabled: false,
+
+ // intermediateChanges: Boolean
+ // Fires onChange for each value change or only on demand
+ intermediateChanges: false,
+
+ // scrollOnFocus: Boolean
+ // On focus, should this widget scroll into view?
+ scrollOnFocus: true,
+
+ // These mixins assume that the focus node is an INPUT, as many but not all _FormWidgets are.
+ attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+ value: "focusNode",
+ id: "focusNode",
+ tabIndex: "focusNode",
+ alt: "focusNode",
+ title: "focusNode"
+ }),
+
+ postMixInProperties: function(){
+ // Setup name=foo string to be referenced from the template (but only if a name has been specified)
+ // Unfortunately we can't use attributeMap to set the name due to IE limitations, see #8660
+ // Regarding escaping, see heading "Attribute values" in
+ // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
+ this.nameAttrSetting = this.name ? ('name="' + this.name.replace(/'/g, "&quot;") + '"') : '';
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.connect(this.domNode, "onmousedown", "_onMouseDown");
+ },
+
+ _setDisabledAttr: function(/*Boolean*/ value){
+ this._set("disabled", value);
+ dojo.attr(this.focusNode, 'disabled', value);
+ if(this.valueNode){
+ dojo.attr(this.valueNode, 'disabled', value);
+ }
+ dijit.setWaiState(this.focusNode, "disabled", value);
+
+ if(value){
+ // reset these, because after the domNode is disabled, we can no longer receive
+ // mouse related events, see #4200
+ this._set("hovering", false);
+ this._set("active", false);
+
+ // clear tab stop(s) on this widget's focusable node(s) (ComboBox has two focusable nodes)
+ var attachPointNames = "tabIndex" in this.attributeMap ? this.attributeMap.tabIndex : "focusNode";
+ dojo.forEach(dojo.isArray(attachPointNames) ? attachPointNames : [attachPointNames], function(attachPointName){
+ var node = this[attachPointName];
+ // complex code because tabIndex=-1 on a <div> doesn't work on FF
+ if(dojo.isWebKit || dijit.hasDefaultTabStop(node)){ // see #11064 about webkit bug
+ node.setAttribute('tabIndex', "-1");
+ }else{
+ node.removeAttribute('tabIndex');
+ }
+ }, this);
+ }else{
+ if(this.tabIndex != ""){
+ this.focusNode.setAttribute('tabIndex', this.tabIndex);
+ }
+ }
+ },
+
+ setDisabled: function(/*Boolean*/ disabled){
+ // summary:
+ // Deprecated. Use set('disabled', ...) instead.
+ dojo.deprecated("setDisabled("+disabled+") is deprecated. Use set('disabled',"+disabled+") instead.", "", "2.0");
+ this.set('disabled', disabled);
+ },
+
+ _onFocus: function(e){
+ if(this.scrollOnFocus){
+ dojo.window.scrollIntoView(this.domNode);
+ }
+ this.inherited(arguments);
+ },
+
+ isFocusable: function(){
+ // summary:
+ // Tells if this widget is focusable or not. Used internally by dijit.
+ // tags:
+ // protected
+ return !this.disabled && this.focusNode && (dojo.style(this.domNode, "display") != "none");
+ },
+
+ focus: function(){
+ // summary:
+ // Put focus on this widget
+ if(!this.disabled){
+ dijit.focus(this.focusNode);
+ }
+ },
+
+ compare: function(/*anything*/ val1, /*anything*/ val2){
+ // summary:
+ // Compare 2 values (as returned by get('value') for this widget).
+ // tags:
+ // protected
+ if(typeof val1 == "number" && typeof val2 == "number"){
+ return (isNaN(val1) && isNaN(val2)) ? 0 : val1 - val2;
+ }else if(val1 > val2){
+ return 1;
+ }else if(val1 < val2){
+ return -1;
+ }else{
+ return 0;
+ }
+ },
+
+ onChange: function(newValue){
+ // summary:
+ // Callback when this widget's value is changed.
+ // tags:
+ // callback
+ },
+
+ // _onChangeActive: [private] Boolean
+ // Indicates that changes to the value should call onChange() callback.
+ // This is false during widget initialization, to avoid calling onChange()
+ // when the initial value is set.
+ _onChangeActive: false,
+
+ _handleOnChange: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
+ // summary:
+ // Called when the value of the widget is set. Calls onChange() if appropriate
+ // newValue:
+ // the new value
+ // priorityChange:
+ // For a slider, for example, dragging the slider is priorityChange==false,
+ // but on mouse up, it's priorityChange==true. If intermediateChanges==false,
+ // onChange is only called form priorityChange=true events.
+ // tags:
+ // private
+ if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){
+ // this block executes not for a change, but during initialization,
+ // and is used to store away the original value (or for ToggleButton, the original checked state)
+ this._resetValue = this._lastValueReported = newValue;
+ }
+ this._pendingOnChange = this._pendingOnChange
+ || (typeof newValue != typeof this._lastValueReported)
+ || (this.compare(newValue, this._lastValueReported) != 0);
+ if((this.intermediateChanges || priorityChange || priorityChange === undefined) && this._pendingOnChange){
+ this._lastValueReported = newValue;
+ this._pendingOnChange = false;
+ if(this._onChangeActive){
+ if(this._onChangeHandle){
+ clearTimeout(this._onChangeHandle);
+ }
+ // setTimout allows hidden value processing to run and
+ // also the onChange handler can safely adjust focus, etc
+ this._onChangeHandle = setTimeout(dojo.hitch(this,
+ function(){
+ this._onChangeHandle = null;
+ this.onChange(newValue);
+ }), 0); // try to collapse multiple onChange's fired faster than can be processed
+ }
+ }
+ },
+
+ create: function(){
+ // Overrides _Widget.create()
+ this.inherited(arguments);
+ this._onChangeActive = true;
+ },
+
+ destroy: function(){
+ if(this._onChangeHandle){ // destroy called before last onChange has fired
+ clearTimeout(this._onChangeHandle);
+ this.onChange(this._lastValueReported);
+ }
+ this.inherited(arguments);
+ },
+
+ setValue: function(/*String*/ value){
+ // summary:
+ // Deprecated. Use set('value', ...) instead.
+ dojo.deprecated("dijit.form._FormWidget:setValue("+value+") is deprecated. Use set('value',"+value+") instead.", "", "2.0");
+ this.set('value', value);
+ },
+
+ getValue: function(){
+ // summary:
+ // Deprecated. Use get('value') instead.
+ dojo.deprecated(this.declaredClass+"::getValue() is deprecated. Use get('value') instead.", "", "2.0");
+ return this.get('value');
+ },
+
+ _onMouseDown: function(e){
+ // If user clicks on the button, even if the mouse is released outside of it,
+ // this button should get focus (to mimics native browser buttons).
+ // This is also needed on chrome because otherwise buttons won't get focus at all,
+ // which leads to bizarre focus restore on Dialog close etc.
+ if(!e.ctrlKey && dojo.mouseButtons.isLeft(e) && this.isFocusable()){ // !e.ctrlKey to ignore right-click on mac
+ // Set a global event to handle mouseup, so it fires properly
+ // even if the cursor leaves this.domNode before the mouse up event.
+ var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
+ if (this.isFocusable()) {
+ this.focus();
+ }
+ this.disconnect(mouseUpConnector);
+ });
+ }
+ }
});
-}
-}});
-dojo.declare("dijit.form._FormValueWidget",dijit.form._FormWidget,{readOnly:false,attributeMap:dojo.delegate(dijit.form._FormWidget.prototype.attributeMap,{value:"",readOnly:"focusNode"}),_setReadOnlyAttr:function(_d){
-this.readOnly=_d;
-dojo.attr(this.focusNode,"readOnly",_d);
-dijit.setWaiState(this.focusNode,"readonly",_d);
-},postCreate:function(){
-this.inherited(arguments);
-if(dojo.isIE){
-this.connect(this.focusNode||this.domNode,"onkeydown",this._onKeyDown);
-}
-if(this._resetValue===undefined){
-this._resetValue=this.value;
-}
-},_setValueAttr:function(_e,_f){
-this.value=_e;
-this._handleOnChange(_e,_f);
-},_getValueAttr:function(){
-return this._lastValue;
-},undo:function(){
-this._setValueAttr(this._lastValueReported,false);
-},reset:function(){
-this._hasBeenBlurred=false;
-this._setValueAttr(this._resetValue,true);
-},_onKeyDown:function(e){
-if(e.keyCode==dojo.keys.ESCAPE&&!(e.ctrlKey||e.altKey||e.metaKey)){
-var te;
-if(dojo.isIE){
-e.preventDefault();
-te=document.createEventObject();
-te.keyCode=dojo.keys.ESCAPE;
-te.shiftKey=e.shiftKey;
-e.srcElement.fireEvent("onkeypress",te);
-}
-}
-},_layoutHackIE7:function(){
-if(dojo.isIE==7){
-var _10=this.domNode;
-var _11=_10.parentNode;
-var _12=_10.firstChild||_10;
-var _13=_12.style.filter;
-var _14=this;
-while(_11&&_11.clientHeight==0){
-(function ping(){
-var _15=_14.connect(_11,"onscroll",function(e){
-_14.disconnect(_15);
-_12.style.filter=(new Date()).getMilliseconds();
-setTimeout(function(){
-_12.style.filter=_13;
-},0);
+
+dojo.declare("dijit.form._FormValueWidget", dijit.form._FormWidget,
+{
+ // summary:
+ // Base class for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values.
+ // description:
+ // Each _FormValueWidget represents a single input value, and has a (possibly hidden) <input> element,
+ // to which it serializes it's input value, so that form submission (either normal submission or via FormBind?)
+ // works as expected.
+
+ // Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared
+ // directly in the template as read by the parser in order to function. IE is known to specifically
+ // require the 'name' attribute at element creation time. See #8484, #8660.
+ // TODO: unclear what that {value: ""} is for; FormWidget.attributeMap copies value to focusNode,
+ // so maybe {value: ""} is so the value *doesn't* get copied to focusNode?
+ // Seems like we really want value removed from attributeMap altogether
+ // (although there's no easy way to do that now)
+
+ // readOnly: Boolean
+ // Should this widget respond to user input?
+ // In markup, this is specified as "readOnly".
+ // Similar to disabled except readOnly form values are submitted.
+ readOnly: false,
+
+ attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
+ value: "",
+ readOnly: "focusNode"
+ }),
+
+ _setReadOnlyAttr: function(/*Boolean*/ value){
+ dojo.attr(this.focusNode, 'readOnly', value);
+ dijit.setWaiState(this.focusNode, "readonly", value);
+ this._set("readOnly", value);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ if(dojo.isIE < 9 || (dojo.isIE && dojo.isQuirks)){ // IE won't stop the event with keypress
+ this.connect(this.focusNode || this.domNode, "onkeydown", this._onKeyDown);
+ }
+ // Update our reset value if it hasn't yet been set (because this.set()
+ // is only called when there *is* a value)
+ if(this._resetValue === undefined){
+ this._lastValueReported = this._resetValue = this.value;
+ }
+ },
+
+ _setValueAttr: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
+ // summary:
+ // Hook so set('value', value) works.
+ // description:
+ // Sets the value of the widget.
+ // If the value has changed, then fire onChange event, unless priorityChange
+ // is specified as null (or false?)
+ this._handleOnChange(newValue, priorityChange);
+ },
+
+ _handleOnChange: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
+ // summary:
+ // Called when the value of the widget has changed. Saves the new value in this.value,
+ // and calls onChange() if appropriate. See _FormWidget._handleOnChange() for details.
+ this._set("value", newValue);
+ this.inherited(arguments);
+ },
+
+ undo: function(){
+ // summary:
+ // Restore the value to the last value passed to onChange
+ this._setValueAttr(this._lastValueReported, false);
+ },
+
+ reset: function(){
+ // summary:
+ // Reset the widget's value to what it was at initialization time
+ this._hasBeenBlurred = false;
+ this._setValueAttr(this._resetValue, true);
+ },
+
+ _onKeyDown: function(e){
+ if(e.keyCode == dojo.keys.ESCAPE && !(e.ctrlKey || e.altKey || e.metaKey)){
+ var te;
+ if(dojo.isIE){
+ e.preventDefault(); // default behavior needs to be stopped here since keypress is too late
+ te = document.createEventObject();
+ te.keyCode = dojo.keys.ESCAPE;
+ te.shiftKey = e.shiftKey;
+ e.srcElement.fireEvent('onkeypress', te);
+ }
+ }
+ },
+
+ _layoutHackIE7: function(){
+ // summary:
+ // Work around table sizing bugs on IE7 by forcing redraw
+
+ if(dojo.isIE == 7){ // fix IE7 layout bug when the widget is scrolled out of sight
+ var domNode = this.domNode;
+ var parent = domNode.parentNode;
+ var pingNode = domNode.firstChild || domNode; // target node most unlikely to have a custom filter
+ var origFilter = pingNode.style.filter; // save custom filter, most likely nothing
+ var _this = this;
+ while(parent && parent.clientHeight == 0){ // search for parents that haven't rendered yet
+ (function ping(){
+ var disconnectHandle = _this.connect(parent, "onscroll",
+ function(e){
+ _this.disconnect(disconnectHandle); // only call once
+ pingNode.style.filter = (new Date()).getMilliseconds(); // set to anything that's unique
+ setTimeout(function(){ pingNode.style.filter = origFilter }, 0); // restore custom filter, if any
+ }
+ );
+ })();
+ parent = parent.parentNode;
+ }
+ }
+ }
});
-})();
-_11=_11.parentNode;
-}
-}
-}});
+
}
diff --git a/lib/dijit/form/_Spinner.js b/lib/dijit/form/_Spinner.js
index 772f667dc..37750ffb7 100644
--- a/lib/dijit/form/_Spinner.js
+++ b/lib/dijit/form/_Spinner.js
@@ -1,57 +1,128 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ 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
*/
-if(!dojo._hasResource["dijit.form._Spinner"]){
-dojo._hasResource["dijit.form._Spinner"]=true;
+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.require("dijit.form.ValidationTextBox");
-dojo.declare("dijit.form._Spinner",dijit.form.RangeBoundTextBox,{defaultTimeout:500,minimumTimeout:10,timeoutChangeRate:0.9,smallDelta:1,largeDelta:10,templateString:dojo.cache("dijit.form","templates/Spinner.html","<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\" waiRole=\"presentation\"\n\t><div class=\"dijitReset dijitButtonNode dijitSpinnerButtonContainer\"\n\t\t><input class=\"dijitReset dijitInputField dijitSpinnerButtonInner\" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t\t/><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitUpArrowButton\"\n\t\t\tdojoAttachPoint=\"upArrowNode\"\n\t\t\t><div class=\"dijitArrowButtonInner\"\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9650;\" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t\t\t\t\t${_buttonInputDisabled}\n\t\t\t/></div\n\t\t></div\n\t\t><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\tdojoAttachPoint=\"downArrowNode\"\n\t\t\t><div class=\"dijitArrowButtonInner\"\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9660;\" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t\t\t\t\t${_buttonInputDisabled}\n\t\t\t/></div\n\t\t></div\n\t></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&Chi; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' dojoAttachPoint=\"textbox,focusNode\" type=\"${type}\" dojoAttachEvent=\"onkeypress:_onKeyPress\"\n\t\t\twaiRole=\"spinbutton\" autocomplete=\"off\" ${!nameAttrSetting}\n\t/></div\n></div>\n"),baseClass:"dijitTextBox dijitSpinner",cssStateNodes:{"upArrowNode":"dijitUpArrowButton","downArrowNode":"dijitDownArrowButton"},adjust:function(_1,_2){
-return _1;
-},_arrowPressed:function(_3,_4,_5){
-if(this.disabled||this.readOnly){
-return;
-}
-this._setValueAttr(this.adjust(this.get("value"),_4*_5),false);
-dijit.selectInputText(this.textbox,this.textbox.value.length);
-},_arrowReleased:function(_6){
-this._wheelTimer=null;
-if(this.disabled||this.readOnly){
-return;
-}
-},_typematicCallback:function(_7,_8,_9){
-var _a=this.smallDelta;
-if(_8==this.textbox){
-var k=dojo.keys;
-var _b=_9.charOrCode;
-_a=(_b==k.PAGE_UP||_b==k.PAGE_DOWN)?this.largeDelta:this.smallDelta;
-_8=(_b==k.UP_ARROW||_b==k.PAGE_UP)?this.upArrowNode:this.downArrowNode;
-}
-if(_7==-1){
-this._arrowReleased(_8);
-}else{
-this._arrowPressed(_8,(_8==this.upArrowNode)?1:-1,_a);
-}
-},_wheelTimer:null,_mouseWheeled:function(_c){
-dojo.stopEvent(_c);
-var _d=_c.detail?(_c.detail*-1):(_c.wheelDelta/120);
-if(_d!==0){
-var _e=this[(_d>0?"upArrowNode":"downArrowNode")];
-this._arrowPressed(_e,_d,this.smallDelta);
-if(!this._wheelTimer){
-clearTimeout(this._wheelTimer);
-}
-this._wheelTimer=setTimeout(dojo.hitch(this,"_arrowReleased",_e),50);
-}
-},postCreate:function(){
-this.inherited(arguments);
-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));
-}});
+
+
+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\"\n\tid=\"widget_${id}\" role=\"presentation\"\n\t><div class=\"dijitReset dijitButtonNode dijitSpinnerButtonContainer\"\n\t\t><input class=\"dijitReset dijitInputField dijitSpinnerButtonInner\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t\t/><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitUpArrowButton\"\n\t\t\tdojoAttachPoint=\"upArrowNode\"\n\t\t\t><div class=\"dijitArrowButtonInner\"\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9650;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t\t\t\t\t${_buttonInputDisabled}\n\t\t\t/></div\n\t\t></div\n\t\t><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\tdojoAttachPoint=\"downArrowNode\"\n\t\t\t><div class=\"dijitArrowButtonInner\"\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9660;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t\t\t\t\t${_buttonInputDisabled}\n\t\t\t/></div\n\t\t></div\n\t></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935;\" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' dojoAttachPoint=\"textbox,focusNode\" type=\"${type}\" dojoAttachEvent=\"onkeypress:_onKeyPress\"\n\t\t\trole=\"spinbutton\" autocomplete=\"off\" ${!nameAttrSetting}\n\t/></div\n></div>\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));
+ }
+});
+
}
diff --git a/lib/dijit/form/nls/da/validate.js b/lib/dijit/form/nls/da/validate.js
index 2874dd890..b42a99d39 100644
--- a/lib/dijit/form/nls/da/validate.js
+++ b/lib/dijit/form/nls/da/validate.js
@@ -1 +1 @@
-({"rangeMessage":"Værdien er uden for intervallet.","invalidMessage":"Den angivne værdi er ugyldig.","missingMessage":"Værdien er påkrævet."}) \ No newline at end of file
+({"rangeMessage":"Værdien er uden for intervallet.","invalidMessage":"Den angivne værdi er ikke gyldig.","missingMessage":"Værdien er påkrævet."}) \ No newline at end of file
diff --git a/lib/dijit/form/nls/kk/ComboBox.js b/lib/dijit/form/nls/kk/ComboBox.js
new file mode 100644
index 000000000..edb918a9c
--- /dev/null
+++ b/lib/dijit/form/nls/kk/ComboBox.js
@@ -0,0 +1 @@
+({"previousMessage":"Алдыңғы нұсқалар","nextMessage":"Басқа нұсқалар"}) \ No newline at end of file
diff --git a/lib/dijit/form/nls/kk/Textarea.js b/lib/dijit/form/nls/kk/Textarea.js
new file mode 100644
index 000000000..617fcb91e
--- /dev/null
+++ b/lib/dijit/form/nls/kk/Textarea.js
@@ -0,0 +1 @@
+({"iframeEditTitle":"өңдеу аумағы","iframeFocusTitle":"өңдеу аумағының жақтауы"}) \ No newline at end of file
diff --git a/lib/dijit/form/nls/kk/validate.js b/lib/dijit/form/nls/kk/validate.js
new file mode 100644
index 000000000..d67612119
--- /dev/null
+++ b/lib/dijit/form/nls/kk/validate.js
@@ -0,0 +1 @@
+({"rangeMessage":"Бұл мән ауқымнан тыс.","invalidMessage":"Енгізілген мән жарамды емес.","missingMessage":"Бұл мән міндетті."}) \ No newline at end of file
diff --git a/lib/dijit/form/nls/pl/Textarea.js b/lib/dijit/form/nls/pl/Textarea.js
index d918f59e0..33b050a1d 100644
--- a/lib/dijit/form/nls/pl/Textarea.js
+++ b/lib/dijit/form/nls/pl/Textarea.js
@@ -1 +1 @@
-({"iframeEditTitle":"Obszar edycji","iframeFocusTitle":"Ramka obszaru edycji"}) \ No newline at end of file
+({"iframeEditTitle":"edycja obszaru","iframeFocusTitle":"edycja ramki obszaru"}) \ No newline at end of file
diff --git a/lib/dijit/form/nls/sl/ComboBox.js b/lib/dijit/form/nls/sl/ComboBox.js
index e9556880c..61d4469c6 100644
--- a/lib/dijit/form/nls/sl/ComboBox.js
+++ b/lib/dijit/form/nls/sl/ComboBox.js
@@ -1 +1 @@
-({"previousMessage":"Prejšnje možnosti","nextMessage":"Dodatne možnosti"}) \ No newline at end of file
+({"previousMessage":"Prejšnje izbire","nextMessage":"Dodatne izbire"}) \ No newline at end of file
diff --git a/lib/dijit/form/nls/sl/Textarea.js b/lib/dijit/form/nls/sl/Textarea.js
index 912ee3962..0e0d51175 100644
--- a/lib/dijit/form/nls/sl/Textarea.js
+++ b/lib/dijit/form/nls/sl/Textarea.js
@@ -1 +1 @@
-({"iframeEditTitle":"urejanje področja","iframeFocusTitle":"urejanje področja okvirja"}) \ No newline at end of file
+({"iframeEditTitle":"urejevalno področje","iframeFocusTitle":"okvir urejevalnega področja"}) \ No newline at end of file
diff --git a/lib/dijit/form/nls/sl/validate.js b/lib/dijit/form/nls/sl/validate.js
index 763572486..b84b35350 100644
--- a/lib/dijit/form/nls/sl/validate.js
+++ b/lib/dijit/form/nls/sl/validate.js
@@ -1 +1 @@
-({"rangeMessage":"Ta vrednost je zunaj obsega. ","invalidMessage":"Vnesena vrednost ni veljavna.","missingMessage":"Ta vrednost je zahtevana."}) \ No newline at end of file
+({"rangeMessage":"Ta vrednost je izven območja.","invalidMessage":"Vnesena vrednost ni veljavna.","missingMessage":"Ta vrednost je zahtevana."}) \ No newline at end of file