summaryrefslogtreecommitdiff
path: root/js/dojo/dijit/form
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo/dijit/form')
-rw-r--r--js/dojo/dijit/form/Button.js127
-rw-r--r--js/dojo/dijit/form/CheckBox.js121
-rw-r--r--js/dojo/dijit/form/ComboBox.js35
-rw-r--r--js/dojo/dijit/form/ComboBoxMixin.js149
-rw-r--r--js/dojo/dijit/form/ComboButton.js92
-rw-r--r--js/dojo/dijit/form/CurrencyTextBox.js95
-rw-r--r--js/dojo/dijit/form/DataList.js64
-rw-r--r--js/dojo/dijit/form/DateTextBox.js39
-rw-r--r--js/dojo/dijit/form/DropDownButton.js108
-rw-r--r--js/dojo/dijit/form/FilteringSelect.js241
-rw-r--r--js/dojo/dijit/form/Form.js173
-rw-r--r--js/dojo/dijit/form/HorizontalRule.js77
-rw-r--r--js/dojo/dijit/form/HorizontalRuleLabels.js100
-rw-r--r--js/dojo/dijit/form/HorizontalSlider.js360
-rw-r--r--js/dojo/dijit/form/MappedTextBox.js90
-rw-r--r--js/dojo/dijit/form/MultiSelect.js119
-rw-r--r--js/dojo/dijit/form/NumberSpinner.js75
-rw-r--r--js/dojo/dijit/form/NumberTextBox.js287
-rw-r--r--js/dojo/dijit/form/RadioButton.js24
-rw-r--r--js/dojo/dijit/form/RangeBoundTextBox.js144
-rw-r--r--js/dojo/dijit/form/Select.js348
-rw-r--r--js/dojo/dijit/form/SimpleTextarea.js101
-rw-r--r--js/dojo/dijit/form/Slider.js19
-rw-r--r--js/dojo/dijit/form/TextBox.js176
-rw-r--r--js/dojo/dijit/form/Textarea.js50
-rw-r--r--js/dojo/dijit/form/TimeTextBox.js89
-rw-r--r--js/dojo/dijit/form/ToggleButton.js34
-rw-r--r--js/dojo/dijit/form/ValidationTextBox.js297
-rw-r--r--js/dojo/dijit/form/VerticalRule.js35
-rw-r--r--js/dojo/dijit/form/VerticalRuleLabels.js33
-rw-r--r--js/dojo/dijit/form/VerticalSlider.js43
-rw-r--r--js/dojo/dijit/form/_AutoCompleterMixin.js765
-rw-r--r--js/dojo/dijit/form/_ButtonMixin.js86
-rw-r--r--js/dojo/dijit/form/_CheckBoxMixin.js78
-rw-r--r--js/dojo/dijit/form/_ComboBoxMenu.js139
-rw-r--r--js/dojo/dijit/form/_ComboBoxMenuMixin.js192
-rw-r--r--js/dojo/dijit/form/_DateTimeTextBox.js263
-rw-r--r--js/dojo/dijit/form/_ExpandingTextAreaMixin.js122
-rw-r--r--js/dojo/dijit/form/_FormMixin.js476
-rw-r--r--js/dojo/dijit/form/_FormSelectWidget.js596
-rw-r--r--js/dojo/dijit/form/_FormValueMixin.js96
-rw-r--r--js/dojo/dijit/form/_FormValueWidget.js59
-rw-r--r--js/dojo/dijit/form/_FormWidget.js80
-rw-r--r--js/dojo/dijit/form/_FormWidgetMixin.js232
-rw-r--r--js/dojo/dijit/form/_ListBase.js124
-rw-r--r--js/dojo/dijit/form/_ListMouseMixin.js97
-rw-r--r--js/dojo/dijit/form/_RadioButtonMixin.js71
-rw-r--r--js/dojo/dijit/form/_Spinner.js142
-rw-r--r--js/dojo/dijit/form/_TextBoxMixin.js409
-rw-r--r--js/dojo/dijit/form/_ToggleButtonMixin.js52
-rw-r--r--js/dojo/dijit/form/nls/ComboBox.js41
-rw-r--r--js/dojo/dijit/form/nls/Textarea.js44
-rw-r--r--js/dojo/dijit/form/nls/ar/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/ar/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/ar/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/az/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/az/Textarea.js9
-rw-r--r--js/dojo/dijit/form/nls/az/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/ca/ComboBox.js10
-rw-r--r--js/dojo/dijit/form/nls/ca/Textarea.js13
-rw-r--r--js/dojo/dijit/form/nls/ca/validate.js11
-rw-r--r--js/dojo/dijit/form/nls/cs/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/cs/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/cs/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/da/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/da/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/da/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/de/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/de/Textarea.js12
-rw-r--r--js/dojo/dijit/form/nls/de/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/el/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/el/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/el/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/es/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/es/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/es/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/fi/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/fi/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/fi/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/fr/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/fr/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/fr/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/he/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/he/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/he/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/hr/ComboBox.js7
-rw-r--r--js/dojo/dijit/form/nls/hr/Textarea.js10
-rw-r--r--js/dojo/dijit/form/nls/hr/validate.js8
-rw-r--r--js/dojo/dijit/form/nls/hu/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/hu/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/hu/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/it/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/it/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/it/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/ja/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/ja/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/ja/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/kk/ComboBox.js10
-rw-r--r--js/dojo/dijit/form/nls/kk/Textarea.js13
-rw-r--r--js/dojo/dijit/form/nls/kk/validate.js11
-rw-r--r--js/dojo/dijit/form/nls/ko/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/ko/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/ko/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/nb/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/nb/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/nb/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/nl/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/nl/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/nl/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/pl/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/pl/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/pl/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/pt-pt/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/pt-pt/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/pt-pt/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/pt/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/pt/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/pt/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/ro/ComboBox.js10
-rw-r--r--js/dojo/dijit/form/nls/ro/Textarea.js13
-rw-r--r--js/dojo/dijit/form/nls/ro/validate.js11
-rw-r--r--js/dojo/dijit/form/nls/ru/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/ru/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/ru/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/sk/ComboBox.js10
-rw-r--r--js/dojo/dijit/form/nls/sk/Textarea.js13
-rw-r--r--js/dojo/dijit/form/nls/sk/validate.js11
-rw-r--r--js/dojo/dijit/form/nls/sl/ComboBox.js10
-rw-r--r--js/dojo/dijit/form/nls/sl/Textarea.js13
-rw-r--r--js/dojo/dijit/form/nls/sl/validate.js11
-rw-r--r--js/dojo/dijit/form/nls/sv/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/sv/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/sv/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/th/ComboBox.js10
-rw-r--r--js/dojo/dijit/form/nls/th/Textarea.js13
-rw-r--r--js/dojo/dijit/form/nls/th/validate.js11
-rw-r--r--js/dojo/dijit/form/nls/tr/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/tr/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/tr/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/validate.js42
-rw-r--r--js/dojo/dijit/form/nls/zh-tw/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/zh-tw/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/zh-tw/validate.js10
-rw-r--r--js/dojo/dijit/form/nls/zh/ComboBox.js9
-rw-r--r--js/dojo/dijit/form/nls/zh/Textarea.js11
-rw-r--r--js/dojo/dijit/form/nls/zh/validate.js10
-rw-r--r--js/dojo/dijit/form/templates/Button.html17
-rw-r--r--js/dojo/dijit/form/templates/CheckBox.html7
-rw-r--r--js/dojo/dijit/form/templates/ComboButton.html23
-rw-r--r--js/dojo/dijit/form/templates/DropDownBox.html16
-rw-r--r--js/dojo/dijit/form/templates/DropDownButton.html20
-rw-r--r--js/dojo/dijit/form/templates/HorizontalSlider.html37
-rw-r--r--js/dojo/dijit/form/templates/Select.html14
-rw-r--r--js/dojo/dijit/form/templates/Spinner.html27
-rw-r--r--js/dojo/dijit/form/templates/TextBox.html6
-rw-r--r--js/dojo/dijit/form/templates/ValidationTextBox.html10
-rw-r--r--js/dojo/dijit/form/templates/VerticalSlider.html45
157 files changed, 9121 insertions, 0 deletions
diff --git a/js/dojo/dijit/form/Button.js b/js/dojo/dijit/form/Button.js
new file mode 100644
index 0000000..e644829
--- /dev/null
+++ b/js/dojo/dijit/form/Button.js
@@ -0,0 +1,127 @@
+//>>built
+require({cache:{
+'url:dijit/form/templates/Button.html':"<span class=\"dijit dijitReset dijitInline\" role=\"presentation\"\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\n\t\tdata-dojo-attach-event=\"ondijitclick:_onClick\" role=\"presentation\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdata-dojo-attach-point=\"titleNode,focusNode\"\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" data-dojo-attach-point=\"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\tdata-dojo-attach-point=\"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\ttabIndex=\"-1\" role=\"presentation\" data-dojo-attach-point=\"valueNode\"\n/></span>\n"}});
+define("dijit/form/Button", [
+ "require",
+ "dojo/_base/declare", // declare
+ "dojo/dom-class", // domClass.toggle
+ "dojo/_base/kernel", // kernel.deprecated
+ "dojo/_base/lang", // lang.trim
+ "dojo/ready",
+ "./_FormWidget",
+ "./_ButtonMixin",
+ "dojo/text!./templates/Button.html"
+], function(require, declare, domClass, kernel, lang, ready, _FormWidget, _ButtonMixin, template){
+
+/*=====
+ var _FormWidget = dijit.form._FormWidget;
+ var _ButtonMixin = dijit.form._ButtonMixin;
+=====*/
+
+// module:
+// dijit/form/Button
+// summary:
+// Button widget
+
+// Back compat w/1.6, remove for 2.0
+if(!kernel.isAsync){
+ ready(0, function(){
+ var requires = ["dijit/form/DropDownButton", "dijit/form/ComboButton", "dijit/form/ToggleButton"];
+ require(requires); // use indirection so modules not rolled into a build
+ });
+}
+
+return declare("dijit.form.Button", [_FormWidget, _ButtonMixin], {
+ // 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 data-dojo-type="dijit.form.Button" onClick="...">Hello world</button>
+ //
+ // example:
+ // | var button1 = new dijit.form.Button({label: "hello world", onClick: foo});
+ // | dojo.body().appendChild(button1.domNode);
+
+ // 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: "dijitNoIcon",
+ _setIconClassAttr: { node: "iconNode", type: "class" },
+
+ baseClass: "dijitButton",
+
+ templateString: template,
+
+ // Map widget attributes to DOMNode attributes.
+ _setValueAttr: "valueNode",
+
+ _onClick: function(/*Event*/ e){
+ // summary:
+ // Internal function to handle click actions
+ var ok = this.inherited(arguments);
+ if(ok){
+ if(this.valueNode){
+ this.valueNode.click();
+ e.preventDefault(); // cancel BUTTON click and continue with hidden INPUT click
+ // leave ok = true so that subclasses can do what they need to do
+ }
+ }
+ return ok;
+ },
+
+ _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))){
+ var sourceLabel = lang.trim(source.innerHTML);
+ if(sourceLabel){
+ this.label = sourceLabel; // _applyAttributes will be called after buildRendering completes to update the DOM
+ }
+ }
+ },
+
+ _setShowLabelAttr: function(val){
+ if(this.containerNode){
+ domClass.toggle(this.containerNode, "dijitDisplayNone", !val);
+ }
+ this._set("showLabel", val);
+ },
+
+ setLabel: function(/*String*/ content){
+ // summary:
+ // Deprecated. Use set('label', ...) instead.
+ kernel.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.
+ // If the label is hidden (showLabel=false) then and no title has
+ // been specified, then label is also set as title attribute of icon.
+ this.inherited(arguments);
+ if(!this.showLabel && !("title" in this.params)){
+ this.titleNode.title = lang.trim(this.containerNode.innerText || this.containerNode.textContent || '');
+ }
+ }
+});
+
+
+});
+
diff --git a/js/dojo/dijit/form/CheckBox.js b/js/dojo/dijit/form/CheckBox.js
new file mode 100644
index 0000000..2cbb01f
--- /dev/null
+++ b/js/dojo/dijit/form/CheckBox.js
@@ -0,0 +1,121 @@
+//>>built
+require({cache:{
+'url: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\tdata-dojo-attach-point=\"focusNode\"\n\t \tdata-dojo-attach-event=\"onclick:_onClick\"\n/></div>\n"}});
+define("dijit/form/CheckBox", [
+ "require",
+ "dojo/_base/declare", // declare
+ "dojo/dom-attr", // domAttr.set
+ "dojo/_base/kernel",
+ "dojo/query", // query
+ "dojo/ready",
+ "./ToggleButton",
+ "./_CheckBoxMixin",
+ "dojo/text!./templates/CheckBox.html",
+ "dojo/NodeList-dom" // NodeList.addClass/removeClass
+], function(require, declare, domAttr, kernel, query, ready, ToggleButton, _CheckBoxMixin, template){
+
+/*=====
+ var ToggleButton = dijit.form.ToggleButton;
+ var _CheckBoxMixin = dijit.form._CheckBoxMixin;
+=====*/
+
+ // module:
+ // dijit/form/CheckBox
+ // summary:
+ // Checkbox widget
+
+ // Back compat w/1.6, remove for 2.0
+ if(!kernel.isAsync){
+ ready(0, function(){
+ var requires = ["dijit/form/RadioButton"];
+ require(requires); // use indirection so modules not rolled into a build
+ });
+ }
+
+ return declare("dijit.form.CheckBox", [ToggleButton, _CheckBoxMixin], {
+ // 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: template,
+
+ baseClass: "dijitCheckBox",
+
+ _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
+ // data-dojo-type="dijit.CheckBox" value="chicken">)
+ // widget.set('value', string) will check the checkbox and change the value to the
+ // specified string
+ // widget.set('value', boolean) will change the checked state.
+ if(typeof newValue == "string"){
+ this._set("value", newValue);
+ domAttr.set(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 behavior from Button, since we don't have an iconNode
+ _setIconClassAttr: null,
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+
+ // Need to set initial checked state as part of template, so that form submit works.
+ // domAttr.set(node, "checked", bool) doesn't work on IE until node has been attached
+ // to <body>, see #8666
+ this.checkedAttrSetting = this.checked ? "checked" : "";
+ },
+
+ _fillContent: function(){
+ // Override Button::_fillContent() since it doesn't make sense for CheckBox,
+ // since CheckBox doesn't even have a container
+ },
+
+ _onFocus: function(){
+ if(this.id){
+ query("label[for='"+this.id+"']").addClass("dijitFocusedLabel");
+ }
+ this.inherited(arguments);
+ },
+
+ _onBlur: function(){
+ if(this.id){
+ query("label[for='"+this.id+"']").removeClass("dijitFocusedLabel");
+ }
+ this.inherited(arguments);
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/ComboBox.js b/js/dojo/dijit/form/ComboBox.js
new file mode 100644
index 0000000..bf13d02
--- /dev/null
+++ b/js/dojo/dijit/form/ComboBox.js
@@ -0,0 +1,35 @@
+//>>built
+define("dijit/form/ComboBox", [
+ "dojo/_base/declare", // declare
+ "./ValidationTextBox",
+ "./ComboBoxMixin"
+], function(declare, ValidationTextBox, ComboBoxMixin){
+
+/*=====
+ var ValidationTextBox = dijit.form.ValidationTextBox;
+ var ComboBoxMixin = dijit.form.ComboBoxMixin;
+=====*/
+
+ // module:
+ // dijit/form/ComboBox
+ // summary:
+ // Auto-completing text box
+
+ return declare("dijit.form.ComboBox", [ValidationTextBox, ComboBoxMixin], {
+ // summary:
+ // Auto-completing text box
+ //
+ // 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.
+ });
+});
diff --git a/js/dojo/dijit/form/ComboBoxMixin.js b/js/dojo/dijit/form/ComboBoxMixin.js
new file mode 100644
index 0000000..a58131d
--- /dev/null
+++ b/js/dojo/dijit/form/ComboBoxMixin.js
@@ -0,0 +1,149 @@
+//>>built
+require({cache:{
+'url:dijit/form/templates/DropDownBox.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\"\n\tid=\"widget_${id}\"\n\trole=\"combobox\"\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\n\t\tdata-dojo-attach-point=\"_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\tdata-dojo-attach-point=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\n\t/></div\n></div>\n"}});
+define("dijit/form/ComboBoxMixin", [
+ "dojo/_base/declare", // declare
+ "dojo/_base/Deferred",
+ "dojo/_base/kernel", // kernel.deprecated
+ "dojo/_base/lang", // lang.mixin
+ "dojo/store/util/QueryResults", // dojo.store.util.QueryResults
+ "./_AutoCompleterMixin",
+ "./_ComboBoxMenu",
+ "../_HasDropDown",
+ "dojo/text!./templates/DropDownBox.html"
+], function(declare, Deferred, kernel, lang, QueryResults, _AutoCompleterMixin, _ComboBoxMenu, _HasDropDown, template){
+
+/*=====
+ var _AutoCompleterMixin = dijit.form._AutoCompleterMixin;
+ var _ComboBoxMenu = dijit.form._ComboBoxMenu;
+ var _HasDropDown = dijit._HasDropDown;
+=====*/
+
+ // module:
+ // dijit/form/ComboBoxMixin
+ // summary:
+ // Provides main functionality of ComboBox widget
+
+ return declare("dijit.form.ComboBoxMixin", [_HasDropDown, _AutoCompleterMixin], {
+ // summary:
+ // Provides main functionality of ComboBox widget
+
+ // dropDownClass: [protected extension] Function String
+ // Dropdown widget class used to select a date/time.
+ // Subclasses should specify this.
+ dropDownClass: _ComboBoxMenu,
+
+ // hasDownArrow: Boolean
+ // Set this textbox to have a down arrow button, to display the drop down list.
+ // Defaults to true.
+ hasDownArrow: true,
+
+ templateString: template,
+
+ baseClass: "dijitTextBox dijitComboBox",
+
+ /*=====
+ // store: [const] dojo.store.api.Store || dojo.data.api.Read
+ // Reference to data provider object used by this ComboBox.
+ //
+ // Should be dojo.store.api.Store, but dojo.data.api.Read supported
+ // for backwards compatibility.
+ store: null,
+ =====*/
+
+ // Set classes like dijitDownArrowButtonHover depending on
+ // mouse action over button node
+ cssStateNodes: {
+ "_buttonNode": "dijitDownArrowButton"
+ },
+
+ _setHasDownArrowAttr: function(/*Boolean*/ val){
+ this._set("hasDownArrow", val);
+ this._buttonNode.style.display = val ? "" : "none";
+ },
+
+ _showResultList: function(){
+ // hide the tooltip
+ this.displayMessage("");
+ this.inherited(arguments);
+ },
+
+ _setStoreAttr: function(store){
+ // For backwards-compatibility, accept dojo.data store in addition to dojo.store.store. Remove in 2.0.
+ if(!store.get){
+ lang.mixin(store, {
+ _oldAPI: true,
+ get: function(id){
+ // summary:
+ // Retrieves an object by it's identity. This will trigger a fetchItemByIdentity.
+ // Like dojo.store.DataStore.get() except returns native item.
+ var deferred = new Deferred();
+ this.fetchItemByIdentity({
+ identity: id,
+ onItem: function(object){
+ deferred.resolve(object);
+ },
+ onError: function(error){
+ deferred.reject(error);
+ }
+ });
+ return deferred.promise;
+ },
+ query: function(query, options){
+ // summary:
+ // Queries the store for objects. Like dojo.store.DataStore.query()
+ // except returned Deferred contains array of native items.
+ var deferred = new Deferred(function(){ fetchHandle.abort && fetchHandle.abort(); });
+ var fetchHandle = this.fetch(lang.mixin({
+ query: query,
+ onBegin: function(count){
+ deferred.total = count;
+ },
+ onComplete: function(results){
+ deferred.resolve(results);
+ },
+ onError: function(error){
+ deferred.reject(error);
+ }
+ }, options));
+ return QueryResults(deferred);
+ }
+ });
+ }
+ this._set("store", store);
+ },
+
+ postMixInProperties: function(){
+ // Since _setValueAttr() depends on this.store, _setStoreAttr() needs to execute first.
+ // Unfortunately, without special code, it ends up executing second.
+ if(this.params.store){
+ this._setStoreAttr(this.params.store);
+ }
+
+ this.inherited(arguments);
+
+ // User may try to access this.store.getValue() etc. in a custom labelFunc() function.
+ // It's not available with the new data store for handling inline <option> tags, so add it.
+ if(!this.params.store){
+ var clazz = this.declaredClass;
+ lang.mixin(this.store, {
+ getValue: function(item, attr){
+ kernel.deprecated(clazz + ".store.getValue(item, attr) is deprecated for builtin store. Use item.attr directly", "", "2.0");
+ return item[attr];
+ },
+ getLabel: function(item){
+ kernel.deprecated(clazz + ".store.getLabel(item) is deprecated for builtin store. Use item.label directly", "", "2.0");
+ return item.name;
+ },
+ fetch: function(args){
+ kernel.deprecated(clazz + ".store.fetch() is deprecated for builtin store.", "Use store.query()", "2.0");
+ var shim = ["dojo/data/ObjectStore"]; // indirection so it doesn't get rolled into a build
+ require(shim, lang.hitch(this, function(ObjectStore){
+ new ObjectStore({objectStore: this}).fetch(args);
+ }));
+ }
+ });
+ }
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/ComboButton.js b/js/dojo/dijit/form/ComboButton.js
new file mode 100644
index 0000000..ba0f8af
--- /dev/null
+++ b/js/dojo/dijit/form/ComboButton.js
@@ -0,0 +1,92 @@
+//>>built
+require({cache:{
+'url: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\" data-dojo-attach-point=\"buttonNode\" data-dojo-attach-event=\"ondijitclick:_onClick,onkeypress:_onButtonKeyPress\"\n\t\t><div id=\"${id}_button\" class=\"dijitReset dijitButtonContents\"\n\t\t\tdata-dojo-attach-point=\"titleNode\"\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\n\t\t\t><div class=\"dijitReset dijitInline dijitIcon\" data-dojo-attach-point=\"iconNode\" role=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitInline dijitButtonText\" id=\"${id}_label\" data-dojo-attach-point=\"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\tdata-dojo-attach-point=\"_popupStateNode,focusNode,_buttonNode\"\n\t\t\tdata-dojo-attach-event=\"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}\" data-dojo-attach-point=\"valueNode\"\n\t\t/></td></tr></tbody\n></table>\n"}});
+define("dijit/form/ComboButton", [
+ "dojo/_base/declare", // declare
+ "dojo/_base/event", // event.stop
+ "dojo/keys", // keys
+ "../focus", // focus.focus()
+ "./DropDownButton",
+ "dojo/text!./templates/ComboButton.html"
+], function(declare, event, keys, focus, DropDownButton, template){
+
+/*=====
+ var DropDownButton = dijit.form.DropDownButton;
+=====*/
+
+// module:
+// dijit/form/ComboButton
+// summary:
+// A combination button and drop-down button.
+
+return declare("dijit.form.ComboButton", 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 data-dojo-type="dijit.form.ComboButton" onClick="...">
+ // | <span>Hello world</span>
+ // | <div data-dojo-type="dijit.Menu">...</div>
+ // | </button>
+ //
+ // example:
+ // | var button1 = new dijit.form.ComboButton({label: "hello world", onClick: foo, dropDown: "myMenu"});
+ // | dojo.body().appendChild(button1.domNode);
+ //
+
+ templateString: template,
+
+ // Map widget attributes to DOMNode attributes.
+ _setIdAttr: "", // override _FormWidgetMixin which puts id on the focusNode
+ _setTabIndexAttr: ["focusNode", "titleNode"],
+ _setTitleAttr: "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 == keys[this.isLeftToRight() ? "RIGHT_ARROW" : "LEFT_ARROW"]){
+ focus.focus(this._popupStateNode);
+ event.stop(evt);
+ }
+ },
+
+ _onArrowKeyPress: function(/*Event*/ evt){
+ // summary:
+ // Handler for left arrow key when focus is on right part of button
+ if(evt.charOrCode == keys[this.isLeftToRight() ? "LEFT_ARROW" : "RIGHT_ARROW"]){
+ focus.focus(this.titleNode);
+ event.stop(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){
+ focus.focus(position == "start" ? this.titleNode : this._popupStateNode);
+ }
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/CurrencyTextBox.js b/js/dojo/dijit/form/CurrencyTextBox.js
new file mode 100644
index 0000000..9d0f147
--- /dev/null
+++ b/js/dojo/dijit/form/CurrencyTextBox.js
@@ -0,0 +1,95 @@
+//>>built
+define("dijit/form/CurrencyTextBox", [
+ "dojo/currency", // currency._mixInDefaults currency.format currency.parse currency.regexp
+ "dojo/_base/declare", // declare
+ "dojo/_base/lang", // lang.hitch
+ "./NumberTextBox"
+], function(currency, declare, lang, NumberTextBox){
+
+/*=====
+ var NumberTextBox = dijit.form.NumberTextBox;
+=====*/
+
+ // module:
+ // dijit/form/CurrencyTextBox
+ // summary:
+ // A validating currency textbox
+
+
+ /*=====
+ declare(
+ "dijit.form.CurrencyTextBox.__Constraints",
+ [dijit.form.NumberTextBox.__Constraints, currency.__FormatOptions, 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}
+ });
+ =====*/
+
+ return declare("dijit.form.CurrencyTextBox", 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, [ lang.mixin({}, constraints, this.editOptions) ]) + '|' : '')
+ + currency.regexp(constraints) + ')';
+ },
+
+ // Override NumberTextBox._formatter to deal with currencies, ex: converts "123.45" to "$123.45"
+ _formatter: currency.format,
+
+ _parser: 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 = lang.hitch(lang.mixin({}, this, { _parser: NumberTextBox.prototype._parser }), "inherited")(arguments);
+ }
+ return v;
+ },
+
+ _setConstraintsAttr: function(/*Object*/ constraints){
+ if(!constraints.currency && this.currency){
+ constraints.currency = this.currency;
+ }
+ this.inherited(arguments, [ currency._mixInDefaults(lang.mixin(constraints, { exponent: false })) ]); // get places
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/DataList.js b/js/dojo/dijit/form/DataList.js
new file mode 100644
index 0000000..bdb3c5a
--- /dev/null
+++ b/js/dojo/dijit/form/DataList.js
@@ -0,0 +1,64 @@
+//>>built
+define("dijit/form/DataList", [
+ "dojo/_base/declare", // declare
+ "dojo/dom", // dom.byId
+ "dojo/_base/lang", // lang.trim
+ "dojo/query", // query
+ "dojo/store/Memory", // dojo.store.Memory
+ "../registry" // registry.add registry.remove
+], function(declare, dom, lang, query, MemoryStore, registry){
+
+ // module:
+ // dijit/form/DataList
+ // summary:
+ // Inefficient but small data store specialized for inlined data via OPTION tags
+
+ function toItem(/*DOMNode*/ option){
+ // summary:
+ // Convert <option> node to hash
+ return {
+ id: option.value,
+ value: option.value,
+ name: lang.trim(option.innerText || option.textContent || '')
+ };
+ }
+
+ return declare("dijit.form.DataList", MemoryStore, {
+ // summary:
+ // Inefficient but small data store specialized for inlined data via OPTION tags
+ //
+ // description:
+ // Provides a store for inlined data like:
+ //
+ // | <datalist>
+ // | <option value="AL">Alabama</option>
+ // | ...
+
+ constructor: function(/*Object?*/ params, /*DomNode|String*/ srcNodeRef){
+ // store pointer to original DOM tree
+ this.domNode = dom.byId(srcNodeRef);
+
+ lang.mixin(this, params);
+ if(this.id){
+ registry.add(this); // add to registry so it can be easily found by id
+ }
+ this.domNode.style.display = "none";
+
+ this.inherited(arguments, [{
+ data: query("option", this.domNode).map(toItem)
+ }]);
+ },
+
+ destroy: function(){
+ registry.remove(this.id);
+ },
+
+ fetchSelectedItem: function(){
+ // summary:
+ // Get the option marked as selected, like `<option selected>`.
+ // Not part of dojo.data API.
+ var option = query("> option[selected]", this.domNode)[0] || query("> option", this.domNode)[0];
+ return option && toItem(option);
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/DateTextBox.js b/js/dojo/dijit/form/DateTextBox.js
new file mode 100644
index 0000000..ed509b4
--- /dev/null
+++ b/js/dojo/dijit/form/DateTextBox.js
@@ -0,0 +1,39 @@
+//>>built
+define("dijit/form/DateTextBox", [
+ "dojo/_base/declare", // declare
+ "../Calendar",
+ "./_DateTimeTextBox"
+], function(declare, Calendar, _DateTimeTextBox){
+
+/*=====
+ var Calendar = dijit.Calendar;
+ var _DateTimeTextBox = dijit.form._DateTimeTextBox;
+=====*/
+
+ // module:
+ // dijit/form/DateTextBox
+ // summary:
+ // A validating, serializable, range-bound date text box with a drop down calendar
+
+
+ return declare("dijit.form.DateTextBox", _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 data-dojo-type='dijit.form.DateTextBox' value='2009-01-20'>
+
+ baseClass: "dijitTextBox dijitComboBox dijitDateTextBox",
+ popupClass: 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 `stamp.fromISOString`.
+ // set("value", ...) accepts either a Date object or a string.
+ value: new Date("") // value.toString()="NaN"
+ });
+});
diff --git a/js/dojo/dijit/form/DropDownButton.js b/js/dojo/dijit/form/DropDownButton.js
new file mode 100644
index 0000000..739ec98
--- /dev/null
+++ b/js/dojo/dijit/form/DropDownButton.js
@@ -0,0 +1,108 @@
+//>>built
+require({cache:{
+'url:dijit/form/templates/DropDownButton.html':"<span class=\"dijit dijitReset dijitInline\"\n\t><span class='dijitReset dijitInline dijitButtonNode'\n\t\tdata-dojo-attach-event=\"ondijitclick:_onClick\" data-dojo-attach-point=\"_buttonNode\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdata-dojo-attach-point=\"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\tdata-dojo-attach-point=\"iconNode\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tdata-dojo-attach-point=\"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\tdata-dojo-attach-point=\"valueNode\"\n/></span>\n"}});
+define("dijit/form/DropDownButton", [
+ "dojo/_base/declare", // declare
+ "dojo/_base/lang", // hitch
+ "dojo/query", // query
+ "../registry", // registry.byNode
+ "../popup", // dijit.popup2.hide
+ "./Button",
+ "../_Container",
+ "../_HasDropDown",
+ "dojo/text!./templates/DropDownButton.html"
+], function(declare, lang, query, registry, popup, Button, _Container, _HasDropDown, template){
+
+/*=====
+ Button = dijit.form.Button;
+ _Container = dijit._Container;
+ _HasDropDown = dijit._HasDropDown;
+=====*/
+
+// module:
+// dijit/form/DropDownButton
+// summary:
+// A button with a drop down
+
+
+return declare("dijit.form.DropDownButton", [Button, _Container, _HasDropDown], {
+ // summary:
+ // A button with a drop down
+ //
+ // example:
+ // | <button data-dojo-type="dijit.form.DropDownButton">
+ // | Hello world
+ // | <div data-dojo-type="dijit.Menu">...</div>
+ // | </button>
+ //
+ // example:
+ // | var button1 = new dijit.form.DropDownButton({ label: "hi", dropDown: new dijit.Menu(...) });
+ // | win.body().appendChild(button1);
+ //
+
+ baseClass : "dijitDropDownButton",
+
+ templateString: template,
+
+ _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 = query("*", this.srcNodeRef);
+ this.inherited(arguments, [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 = query("[widgetId]", this.dropDownContainer)[0];
+ this.dropDown = registry.byNode(dropDownNode);
+ delete this.dropDownContainer;
+ }
+ if(this.dropDown){
+ 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(/*Function*/ callback){
+ // Default implementation assumes that drop down already exists,
+ // but hasn't loaded it's data (ex: ContentPane w/href).
+ // App must override if the drop down is lazy-created.
+ var dropDown = this.dropDown;
+ var handler = dropDown.on("load", lang.hitch(this, function(){
+ handler.remove();
+ callback();
+ }));
+ dropDown.refresh(); // tell it to load
+ },
+
+ isFocusable: function(){
+ // Overridden so that focus is handled by the _HasDropDown mixin, not by
+ // the _FormWidget mixin.
+ return this.inherited(arguments) && !this._mouseDown;
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/FilteringSelect.js b/js/dojo/dijit/form/FilteringSelect.js
new file mode 100644
index 0000000..7bc59a9
--- /dev/null
+++ b/js/dojo/dijit/form/FilteringSelect.js
@@ -0,0 +1,241 @@
+//>>built
+define("dijit/form/FilteringSelect", [
+ "dojo/data/util/filter", // filter.patternToRegExp
+ "dojo/_base/declare", // declare
+ "dojo/_base/Deferred", // Deferred.when
+ "dojo/_base/lang", // lang.mixin
+ "./MappedTextBox",
+ "./ComboBoxMixin"
+], function(filter, declare, Deferred, lang, MappedTextBox, ComboBoxMixin){
+
+/*=====
+ var MappedTextBox = dijit.form.MappedTextBox;
+ var ComboBoxMixin = dijit.form.ComboBoxMixin;
+=====*/
+
+ // module:
+ // dijit/form/FilteringSelect
+ // summary:
+ // An enhanced version of the HTML SELECT tag, populated dynamically
+
+
+ return declare("dijit.form.FilteringSelect", [MappedTextBox, 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*/ query,
+ /*Object*/ options,
+ /*Boolean?*/ priorityChange){
+ // summary:
+ // Callback from dojo.store 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((query && query[this.searchAttr] !== this._lastQuery) || (!query && 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.set("value", '', priorityChange || (priorityChange === undefined && !this.focused), this.textbox.value, null);
+ }else{
+ this.set('item', result[0], priorityChange);
+ }
+ },
+
+ _openResultList: function(/*Object*/ results, /*Object*/ query, /*Object*/ options){
+ // 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(query[this.searchAttr] !== this._lastQuery){
+ return;
+ }
+ this.inherited(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, /*String?*/ displayedValue, /*item?*/ item){
+ // 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; }
+
+ if(item === undefined){
+ if(value === null || value === ''){
+ value = '';
+ if(!lang.isString(displayedValue)){
+ this._setDisplayedValueAttr(displayedValue||'', priorityChange);
+ return;
+ }
+ }
+
+ var self = this;
+ this._lastQuery = value;
+ Deferred.when(this.store.get(value), function(item){
+ self._callbackSetLabel(item? [item] : [], undefined, undefined, priorityChange);
+ });
+ }else{
+ this.valueNode.value = value;
+ 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
+ this.inherited(arguments);
+ 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 = lang.clone(this.query); // #6196: populate query with user-specifics
+
+ // Generate query
+ var qs = this._getDisplayQueryString(label), q;
+ if(this.store._oldAPI){
+ // remove this branch for 2.0
+ q = qs;
+ }else{
+ // Query on searchAttr is a regex for benefit of dojo.store.Memory,
+ // but with a toString() method to help dojo.store.JsonRest.
+ // Search string like "Co*" converted to regex like /^Co.*$/i.
+ q = filter.patternToRegExp(qs, this.ignoreCase);
+ q.toString = function(){ return qs; };
+ }
+ this._lastQuery = query[this.searchAttr] = q;
+
+ // 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 options = {
+ ignoreCase: this.ignoreCase,
+ deep: true
+ };
+ lang.mixin(options, this.fetchProperties);
+ this._fetchHandle = this.store.query(query, options);
+ Deferred.when(this._fetchHandle, function(result){
+ _this._fetchHandle = null;
+ _this._callbackSetLabel(result || [], query, options, priorityChange);
+ }, function(err){
+ _this._fetchHandle = null;
+ if(!_this._cancelingQuery){ // don't treat canceled query as an error
+ console.error('dijit.form.FilteringSelect: ' + err.toString());
+ }
+ });
+ }
+ },
+
+ undo: function(){
+ this.set('displayedValue', this._lastDisplayedValue);
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/Form.js b/js/dojo/dijit/form/Form.js
new file mode 100644
index 0000000..cd12c47
--- /dev/null
+++ b/js/dojo/dijit/form/Form.js
@@ -0,0 +1,173 @@
+//>>built
+define("dijit/form/Form", [
+ "dojo/_base/declare", // declare
+ "dojo/dom-attr", // domAttr.set
+ "dojo/_base/event", // event.stop
+ "dojo/_base/kernel", // kernel.deprecated
+ "dojo/_base/sniff", // has("ie")
+ "../_Widget",
+ "../_TemplatedMixin",
+ "./_FormMixin",
+ "../layout/_ContentPaneResizeMixin"
+], function(declare, domAttr, event, kernel, has, _Widget, _TemplatedMixin, _FormMixin, _ContentPaneResizeMixin){
+
+/*=====
+ var _Widget = dijit._Widget;
+ var _TemplatedMixin = dijit._TemplatedMixin;
+ var _FormMixin = dijit.form._FormMixin;
+ var _ContentPaneResizeMixin = dijit.layout._ContentPaneResizeMixin;
+=====*/
+
+ // module:
+ // dijit/form/Form
+ // summary:
+ // Widget corresponding to HTML form tag, for validation and serialization
+
+
+ return declare("dijit.form.Form", [_Widget, _TemplatedMixin, _FormMixin, _ContentPaneResizeMixin], {
+ // summary:
+ // Widget corresponding to HTML form tag, for validation and serialization
+ //
+ // example:
+ // | <form data-dojo-type="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 data-dojo-attach-point='containerNode' data-dojo-attach-event='onreset:_onReset,onsubmit:_onSubmit' ${!nameAttrSetting}></form>",
+
+ 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 _setNameAttr 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;
+ domAttr.set(this.domNode, "encType", value);
+ if(has("ie")){ this.domNode.encoding = value; }
+ },
+
+ 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);
+ event.stop(e);
+ return false;
+ },
+
+ _onSubmit: function(e){
+ var fp = this.constructor.prototype;
+ // TODO: remove this if statement beginning with 2.0
+ if(this.execute != fp.execute || this.onExecute != fp.onExecute){
+ kernel.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
+ event.stop(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/js/dojo/dijit/form/HorizontalRule.js b/js/dojo/dijit/form/HorizontalRule.js
new file mode 100644
index 0000000..5c42c08
--- /dev/null
+++ b/js/dojo/dijit/form/HorizontalRule.js
@@ -0,0 +1,77 @@
+//>>built
+define("dijit/form/HorizontalRule", [
+ "dojo/_base/declare", // declare
+ "../_Widget",
+ "../_TemplatedMixin"
+], function(declare, _Widget, _TemplatedMixin){
+
+/*=====
+ var _Widget = dijit._Widget;
+ var _TemplatedMixin = dijit._TemplatedMixin;
+=====*/
+
+// module:
+// dijit/form/HorizontalRule
+// summary:
+// Hash marks for `dijit.form.HorizontalSlider`
+
+
+return declare("dijit.form.HorizontalRule", [_Widget, _TemplatedMixin], {
+ // 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){
+ 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/js/dojo/dijit/form/HorizontalRuleLabels.js b/js/dojo/dijit/form/HorizontalRuleLabels.js
new file mode 100644
index 0000000..be29478
--- /dev/null
+++ b/js/dojo/dijit/form/HorizontalRuleLabels.js
@@ -0,0 +1,100 @@
+//>>built
+define("dijit/form/HorizontalRuleLabels", [
+ "dojo/_base/declare", // declare
+ "dojo/number", // number.format
+ "dojo/query", // query
+ "./HorizontalRule"
+], function(declare, number, query, HorizontalRule){
+
+/*=====
+ var HorizontalRule = dijit.form.HorizontalRule;
+=====*/
+
+// module:
+// dijit/form/HorizontalRuleLabels
+// summary:
+// Labels for `dijit.form.HorizontalSlider`
+
+return declare("dijit.form.HorizontalRuleLabels", 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 = 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)) ? '' : number.format(start, this.constraints));
+ start += inc;
+ }
+ }
+ return labels;
+ },
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this.labels = this.getLabels();
+ this.count = this.labels.length;
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/HorizontalSlider.js b/js/dojo/dijit/form/HorizontalSlider.js
new file mode 100644
index 0000000..307f93f
--- /dev/null
+++ b/js/dojo/dijit/form/HorizontalSlider.js
@@ -0,0 +1,360 @@
+//>>built
+require({cache:{
+'url:dijit/form/templates/HorizontalSlider.html':"<table class=\"dijit dijitReset dijitSlider dijitSliderH\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\" data-dojo-attach-event=\"onkeypress:_onKeyPress,onkeyup:_onKeyUp\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td data-dojo-attach-point=\"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\" data-dojo-attach-point=\"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\" data-dojo-attach-event=\"press:_onClkDecBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><input data-dojo-attach-point=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\n\t\t\t/><div class=\"dijitReset dijitSliderBarContainerH\" role=\"presentation\" data-dojo-attach-point=\"sliderBarContainer\"\n\t\t\t\t><div role=\"presentation\" data-dojo-attach-point=\"progressBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH\" data-dojo-attach-event=\"press:_onBarClick\"\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableH\"\n\t\t\t\t\t\t><div data-dojo-attach-point=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleH\" data-dojo-attach-event=\"press:_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\" data-dojo-attach-point=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderRemainingBar dijitSliderRemainingBarH\" data-dojo-attach-event=\"press:_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\" data-dojo-attach-event=\"press:_onClkIncBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderIncrementIconH\" style=\"display:none\" data-dojo-attach-point=\"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 data-dojo-attach-point=\"containerNode,bottomDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n></table>\n"}});
+define("dijit/form/HorizontalSlider", [
+ "dojo/_base/array", // array.forEach
+ "dojo/_base/declare", // declare
+ "dojo/dnd/move",
+ "dojo/_base/event", // event.stop
+ "dojo/_base/fx", // fx.animateProperty
+ "dojo/dom-geometry", // domGeometry.position
+ "dojo/dom-style", // domStyle.getComputedStyle
+ "dojo/keys", // keys.DOWN_ARROW keys.END keys.HOME keys.LEFT_ARROW keys.PAGE_DOWN keys.PAGE_UP keys.RIGHT_ARROW keys.UP_ARROW
+ "dojo/_base/lang", // lang.hitch
+ "dojo/_base/sniff", // has("ie") has("mozilla")
+ "dojo/dnd/Moveable", // Moveable
+ "dojo/dnd/Mover", // Mover Mover.prototype.destroy.apply
+ "dojo/query", // query
+ "../registry", // registry.findWidgets
+ "../focus", // focus.focus()
+ "../typematic",
+ "./Button",
+ "./_FormValueWidget",
+ "../_Container",
+ "dojo/text!./templates/HorizontalSlider.html"
+], function(array, declare, move, event, fx, domGeometry, domStyle, keys, lang, has, Moveable, Mover, query,
+ registry, focus, typematic, Button, _FormValueWidget, _Container, template){
+
+/*=====
+ var Button = dijit.form.Button;
+ var _FormValueWidget = dijit.form._FormValueWidget;
+ var _Container = dijit._Container;
+=====*/
+
+// module:
+// dijit/form/HorizontalSlider
+// summary:
+// A form widget that allows one to select a value with a horizontally draggable handle
+
+
+var _SliderMover = declare("dijit.form._SliderMover", Mover, {
+ onMouseMove: function(e){
+ var widget = this.widget;
+ var abspos = widget._abspos;
+ if(!abspos){
+ abspos = widget._abspos = domGeometry.position(widget.sliderBarContainer, true);
+ widget._setPixelValue_ = lang.hitch(widget, "_setPixelValue");
+ widget._isReversed_ = widget._isReversed();
+ }
+ var pixelValue = e[widget._mousePixelCoord] - abspos[widget._startingPixelCoord];
+ widget._setPixelValue_(widget._isReversed_ ? (abspos[widget._pixelCount]-pixelValue) : pixelValue, abspos[widget._pixelCount], false);
+ },
+
+ destroy: function(e){
+ Mover.prototype.destroy.apply(this, arguments);
+ var widget = this.widget;
+ widget._abspos = null;
+ widget._setValueAttr(widget.value, true);
+ }
+});
+
+var HorizontalSlider = declare("dijit.form.HorizontalSlider", [_FormValueWidget, _Container], {
+ // summary:
+ // A form widget that allows one to select a value with a horizontally draggable handle
+
+ templateString: template,
+
+ // 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: registry.defaultDuration,
+
+ // Map widget attributes to DOMNode attributes.
+ _setIdAttr: "", // Override _FormWidget which sends id to focusNode
+
+ 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",
+ _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 keys.HOME:
+ this._setValueAttr(this.minimum, false);
+ break;
+ case 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()) ? keys.RIGHT_ARROW : keys.LEFT_ARROW):
+ case (this._descending === false ? keys.DOWN_ARROW : keys.UP_ARROW):
+ case (this._descending === false ? keys.PAGE_DOWN : keys.PAGE_UP):
+ this.increment(e);
+ break;
+ case ((this._descending || this.isLeftToRight()) ? keys.LEFT_ARROW : keys.RIGHT_ARROW):
+ case (this._descending === false ? keys.UP_ARROW : keys.DOWN_ARROW):
+ case (this._descending === false ? keys.PAGE_UP : keys.PAGE_DOWN):
+ this.decrement(e);
+ break;
+ default:
+ return;
+ }
+ event.stop(e);
+ },
+
+ _onHandleClick: function(e){
+ if(this.disabled || this.readOnly){ return; }
+ if(!has("ie")){
+ // 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)
+ focus.focus(this.sliderHandle);
+ }
+ event.stop(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; }
+ focus.focus(this.sliderHandle);
+ event.stop(e);
+ var abspos = domGeometry.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; }
+ var count = this.discreteValues;
+ if(count <= 1 || count == Infinity){ count = maxPixels; }
+ count--;
+ var pixelsPerValue = maxPixels / count;
+ var wholeIncrements = Math.round(pixelValue / pixelsPerValue);
+ this._setValueAttr(Math.max(Math.min((this.maximum-this.minimum)*wholeIncrements/count + this.minimum, this.maximum), this.minimum), priorityChange);
+ },
+
+ _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
+ // summary:
+ // Hook so set('value', value) works.
+ this._set("value", value);
+ this.valueNode.value = value;
+ this.focusNode.setAttribute("aria-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 = fx.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 = domStyle.getComputedStyle(this.sliderBarContainer);
+ var c = domGeometry.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 == keys.PAGE_DOWN ? -this.pageIncrement : -1);
+ },
+
+ increment: function(/*Event*/ e){
+ // summary:
+ // Increment slider
+ // tags:
+ // private
+ this._bumpValue(e.charOrCode == keys.PAGE_UP ? this.pageIncrement : 1);
+ },
+
+ _mouseWheeled: function(/*Event*/ evt){
+ // summary:
+ // Event handler for mousewheel where supported
+ event.stop(evt);
+ var janky = !has("mozilla");
+ 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; }
+
+ array.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 = query('label[for="'+this.id+'"]');
+ if(label.length){
+ label[0].id = (this.id+"_label");
+ this.focusNode.setAttribute("aria-labelledby", label[0].id);
+ }
+
+ this.focusNode.setAttribute("aria-valuemin", this.minimum);
+ this.focusNode.setAttribute("aria-valuemax", this.maximum);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ if(this.showButtons){
+ this._connects.push(typematic.addMouseListener(
+ this.decrementButton, this, "_typematicCallback", 25, 500));
+ this._connects.push(typematic.addMouseListener(
+ this.incrementButton, this, "_typematicCallback", 25, 500));
+ }
+ this.connect(this.domNode, !has("mozilla") ? "onmousewheel" : "DOMMouseScroll", "_mouseWheeled");
+
+ // define a custom constructor for a SliderMover that points back to me
+ var mover = declare(_SliderMover, {
+ widget: this
+ });
+ this._movable = new 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 = registry.findWidgets(this.domNode); // tells destroy about pseudo-child widgets (ruler/labels)
+ this.inherited(arguments);
+ }
+});
+
+HorizontalSlider._Mover = _SliderMover; // for monkey patching
+
+return HorizontalSlider;
+});
diff --git a/js/dojo/dijit/form/MappedTextBox.js b/js/dojo/dijit/form/MappedTextBox.js
new file mode 100644
index 0000000..8571302
--- /dev/null
+++ b/js/dojo/dijit/form/MappedTextBox.js
@@ -0,0 +1,90 @@
+//>>built
+define("dijit/form/MappedTextBox", [
+ "dojo/_base/declare", // declare
+ "dojo/dom-construct", // domConstruct.place
+ "./ValidationTextBox"
+], function(declare, domConstruct, ValidationTextBox){
+
+/*=====
+ var ValidationTextBox = dijit.form.ValidationTextBox;
+=====*/
+
+ // module:
+ // dijit/form/MappedTextBox
+ // 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.
+
+ return declare("dijit.form.MappedTextBox", 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 = "";
+ },
+
+ // Override default behavior to assign name to focusNode
+ _setNameAttr: null,
+
+ serialize: function(val /*=====, 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.
+ // val: anything
+ // options: Object?
+ // 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._TemplatedMixin.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 domConstruct.create() with an attrs argument
+ // to make query(input[name=...]) work on IE. (see #8660)
+ this.valueNode = domConstruct.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);
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/MultiSelect.js b/js/dojo/dijit/form/MultiSelect.js
new file mode 100644
index 0000000..b814220
--- /dev/null
+++ b/js/dojo/dijit/form/MultiSelect.js
@@ -0,0 +1,119 @@
+//>>built
+define("dijit/form/MultiSelect", [
+ "dojo/_base/array", // array.indexOf, array.map
+ "dojo/_base/declare", // declare
+ "dojo/dom-geometry", // domGeometry.setMarginBox
+ "dojo/query", // query
+ "./_FormValueWidget"
+], function(array, declare, domGeometry, query, _FormValueWidget){
+
+/*=====
+ var _FormValueWidget = dijit.form._FormValueWidget;
+=====*/
+
+// module:
+// dijit/form/MultiSelect
+// summary:
+// Widget version of a <select multiple=true> element,
+// for selecting multiple options.
+
+return declare("dijit.form.MultiSelect", _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} data-dojo-attach-point='containerNode,focusNode' data-dojo-attach-event='onchange: _onChange'></select>",
+
+ 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);
+ this._set('value', this.get('value'));
+ },
+
+ getSelected: function(){
+ // summary:
+ // Access the NodeList of the selected options directly
+ return 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.
+
+ // Don't call getSelect.map() because it doesn't return a real array,
+ // and that messes up dojo.toJson() calls like in the Form.html test
+ return array.map(this.getSelected(), function(n){
+ return n.value;
+ });
+ },
+
+ multiple: true, // for Form
+
+ _setValueAttr: function(/*Array*/ values, /*Boolean?*/ priorityChange){
+ // summary:
+ // Hook so set('value', values) works.
+ // description:
+ // Set the value(s) of this Select based on passed values
+ query("option",this.containerNode).forEach(function(n){
+ n.selected = (array.indexOf(values,n.value) != -1);
+ });
+ this.inherited(arguments);
+ },
+
+ invertSelection: function(/*Boolean?*/ onChange){
+ // summary:
+ // Invert the selection
+ // onChange: Boolean
+ // If false, onChange is not fired.
+ var val = [];
+ query("option",this.containerNode).forEach(function(n){
+ if(!n.selected){ val.push(n.value); }
+ });
+ this._setValueAttr(val, !(onChange === false || onChange == null));
+ },
+
+ _onChange: function(/*Event*/){
+ this._handleOnChange(this.get('value'), true);
+ },
+
+ // for layout widgets:
+ resize: function(/*Object*/ size){
+ if(size){
+ domGeometry.setMarginBox(this.domNode, size);
+ }
+ },
+
+ postCreate: function(){
+ this._set('value', this.get('value'));
+ this.inherited(arguments);
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/NumberSpinner.js b/js/dojo/dijit/form/NumberSpinner.js
new file mode 100644
index 0000000..05b3621
--- /dev/null
+++ b/js/dojo/dijit/form/NumberSpinner.js
@@ -0,0 +1,75 @@
+//>>built
+define("dijit/form/NumberSpinner", [
+ "dojo/_base/declare", // declare
+ "dojo/_base/event", // event.stop
+ "dojo/keys", // keys.END keys.HOME
+ "./_Spinner",
+ "./NumberTextBox"
+], function(declare, event, keys, _Spinner, NumberTextBox){
+
+/*=====
+ var _Spinner = dijit.form._Spinner;
+ var NumberTextBox = dijit.form.NumberTextBox;
+=====*/
+
+// module:
+// dijit/form/NumberSpinner
+// summary:
+// Extends NumberTextBox to add up/down arrows and pageup/pagedown for incremental change to the value
+
+
+return declare("dijit.form.NumberSpinner", [_Spinner, NumberTextBox.Mixin], {
+ // 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 == keys.HOME || e.charOrCode == 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 == keys.HOME ? "min" : "max")];
+ if(typeof value == "number"){
+ this._setValueAttr(value, false);
+ }
+ // eat home or end key whether we change the value or not
+ event.stop(e);
+ }
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/NumberTextBox.js b/js/dojo/dijit/form/NumberTextBox.js
new file mode 100644
index 0000000..afd47f2
--- /dev/null
+++ b/js/dojo/dijit/form/NumberTextBox.js
@@ -0,0 +1,287 @@
+//>>built
+define("dijit/form/NumberTextBox", [
+ "dojo/_base/declare", // declare
+ "dojo/_base/lang", // lang.hitch lang.mixin
+ "dojo/number", // number._realNumberRegexp number.format number.parse number.regexp
+ "./RangeBoundTextBox"
+], function(declare, lang, number, RangeBoundTextBox){
+
+/*=====
+ var RangeBoundTextBox = dijit.form.RangeBoundTextBox;
+=====*/
+
+ // module:
+ // dijit/form/NumberTextBox
+ // summary:
+ // A TextBox for entering numbers, with formatting and range checking
+
+
+ /*=====
+ declare(
+ "dijit.form.NumberTextBox.__Constraints",
+ [dijit.form.RangeBoundTextBox.__Constraints, number.__FormatOptions, 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'}
+ });
+ =====*/
+
+ var NumberTextBoxMixin = 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: 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: number.format,
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this._set("type", "text"); // in case type="number" was specified which messes up parse/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 = lang.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: number.parse,
+
+ parse: function(/*String*/ value, /*number.__FormatOptions*/ constraints){
+ // summary:
+ // Replaceable function to convert a formatted string to a number value
+ // tags:
+ // protected extension
+
+ var v = this._parser(value, lang.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 = lang.hitch(lang.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 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 compute a real string value
+ }
+ }else if(!value){ // 0 processed in if branch above, ''|null|undefined flows through 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 unparseable 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("^"+number._realNumberRegexp(lang.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 validation 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;
+ }
+ }
+ }
+ });
+/*=====
+ NumberTextBoxMixin = dijit.form.NumberTextBoxMixin;
+=====*/
+
+ var NumberTextBox = declare("dijit.form.NumberTextBox", [RangeBoundTextBox,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"
+ });
+
+ NumberTextBox.Mixin = NumberTextBoxMixin; // for monkey patching
+
+ return NumberTextBox;
+});
diff --git a/js/dojo/dijit/form/RadioButton.js b/js/dojo/dijit/form/RadioButton.js
new file mode 100644
index 0000000..d6df075
--- /dev/null
+++ b/js/dojo/dijit/form/RadioButton.js
@@ -0,0 +1,24 @@
+//>>built
+define("dijit/form/RadioButton", [
+ "dojo/_base/declare", // declare
+ "./CheckBox",
+ "./_RadioButtonMixin"
+], function(declare, CheckBox, _RadioButtonMixin){
+
+/*=====
+ var CheckBox = dijit.form.CheckBox;
+ var _RadioButtonMixin = dijit.form._RadioButtonMixin;
+=====*/
+
+ // module:
+ // dijit/form/RadioButton
+ // summary:
+ // Radio button widget
+
+ return declare("dijit.form.RadioButton", [CheckBox, _RadioButtonMixin], {
+ // summary:
+ // Same as an HTML radio, but with fancy styling.
+
+ baseClass: "dijitRadio"
+ });
+});
diff --git a/js/dojo/dijit/form/RangeBoundTextBox.js b/js/dojo/dijit/form/RangeBoundTextBox.js
new file mode 100644
index 0000000..9b2604d
--- /dev/null
+++ b/js/dojo/dijit/form/RangeBoundTextBox.js
@@ -0,0 +1,144 @@
+//>>built
+define("dijit/form/RangeBoundTextBox", [
+ "dojo/_base/declare", // declare
+ "dojo/i18n", // i18n.getLocalization
+ "./MappedTextBox"
+], function(declare, i18n, MappedTextBox){
+
+/*=====
+ var MappedTextBox = dijit.form.MappedTextBox;
+=====*/
+
+ // module:
+ // dijit/form/RangeBoundTextBox
+ // summary:
+ // Base class for textbox form widgets which defines a range of valid values.
+
+ /*=====
+ 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;
+ }
+ =====*/
+
+ return declare("dijit.form.RangeBoundTextBox", 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 = 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){
+ this.focusNode.setAttribute("aria-valuemin", this.constraints.min);
+ }else{
+ this.focusNode.removeAttribute("aria-valuemin");
+ }
+ if(this.constraints.max !== undefined){
+ this.focusNode.setAttribute("aria-valuemax", this.constraints.max);
+ }else{
+ this.focusNode.removeAttribute("aria-valuemax");
+ }
+ }
+ },
+
+ _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
+ // summary:
+ // Hook so set('value', ...) works.
+
+ this.focusNode.setAttribute("aria-valuenow", value);
+ this.inherited(arguments);
+ },
+
+ applyTextDir: function(/*===== element, text =====*/){
+ // summary:
+ // The function overridden in the _BidiSupport module,
+ // originally used for setting element.dir according to this.textDir.
+ // In this case does nothing.
+ // element: Object
+ // text: String
+ // tags:
+ // protected.
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/Select.js b/js/dojo/dijit/form/Select.js
new file mode 100644
index 0000000..7682e5b
--- /dev/null
+++ b/js/dojo/dijit/form/Select.js
@@ -0,0 +1,348 @@
+//>>built
+require({cache:{
+'url:dijit/form/templates/Select.html':"<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tdata-dojo-attach-point=\"_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\" data-dojo-attach-point=\"containerNode,_popupStateNode\"></span\n\t\t\t><input type=\"hidden\" ${!nameAttrSetting} data-dojo-attach-point=\"valueNode\" value=\"${value}\" aria-hidden=\"true\"\n\t\t/></td><td class=\"dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\t\tdata-dojo-attach-point=\"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"}});
+define("dijit/form/Select", [
+ "dojo/_base/array", // array.forEach
+ "dojo/_base/declare", // declare
+ "dojo/dom-attr", // domAttr.set
+ "dojo/dom-class", // domClass.add domClass.remove domClass.toggle
+ "dojo/dom-construct", // domConstruct.create
+ "dojo/dom-geometry", // domGeometry.setMarginBox
+ "dojo/_base/event", // event.stop
+ "dojo/i18n", // i18n.getLocalization
+ "dojo/_base/lang", // lang.hitch
+ "./_FormSelectWidget",
+ "../_HasDropDown",
+ "../Menu",
+ "../MenuItem",
+ "../MenuSeparator",
+ "../Tooltip",
+ "dojo/text!./templates/Select.html",
+ "dojo/i18n!./nls/validate"
+], function(array, declare, domAttr, domClass, domConstruct, domGeometry, event, i18n, lang,
+ _FormSelectWidget, _HasDropDown, Menu, MenuItem, MenuSeparator, Tooltip, template){
+
+/*=====
+ var _FormSelectWidget = dijit.form._FormSelectWidget;
+ var _HasDropDown = dijit._HasDropDown;
+ var _FormSelectWidget = dijit._FormSelectWidget;
+ var Menu = dijit.Menu;
+ var MenuItem = dijit.MenuItem;
+ var MenuSeparator = dijit.MenuSeparator;
+ var Tooltip = dijit.Tooltip;
+=====*/
+
+// module:
+// dijit/form/Select
+// summary:
+// This is a "styleable" select box - it is basically a DropDownButton which
+// can take a <select> as its input.
+
+
+var _SelectMenu = declare("dijit.form._SelectMenu", 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 = domConstruct.create("div", {style: {overflowX: "hidden", overflowY: "scroll"}}));
+ if(o.parentNode){
+ o.parentNode.replaceChild(n, o);
+ }
+ domClass.remove(o, "dijitMenuTable");
+ n.className = o.className + " dijitSelectMenu";
+ o.className = "dijitReset dijitMenuTable";
+ o.setAttribute("role", "listbox");
+ n.setAttribute("role", "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", event.stop);
+ },
+
+ 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){
+ domGeometry.setMarginBox(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 Select = declare("dijit.form.Select", [_FormSelectWidget, _HasDropDown], {
+ // summary:
+ // This is a "styleable" select box - it is basically a DropDownButton which
+ // can take a <select> as its input.
+
+ baseClass: "dijitSelect",
+
+ templateString: template,
+
+ // required: Boolean
+ // Can be true or false, default is false.
+ required: false,
+
+ // state: [readonly] String
+ // "Incomplete" if this select is required but unset (i.e. blank value), "" otherwise
+ 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: "&#160;", // &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 _SelectMenu({id: this.id + "_menu"});
+ domClass.add(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 MenuSeparator();
+ }else{
+ // Just a regular menu option
+ var click = lang.hitch(this, "_setValueAttr", option);
+ var item = new MenuItem({
+ option: option,
+ label: option.label || this.emptyLabel,
+ onClick: click,
+ disabled: option.disabled || false
+ });
+ item.focusNode.setAttribute("role", "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)
+ array.forEach(this._getChildren(), function(child){ child.destroyRecursive(); });
+ var item = new MenuItem({label: "&#160;"});
+ 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);
+ domAttr.set(this.valueNode, "value", this.get("value"));
+ this.validate(this.focused); // to update this.state
+ },
+
+ _setDisabledAttr: function(/*Boolean*/ value){
+ this.inherited(arguments);
+ this.validate(this.focused); // to update this.state
+ },
+
+ _setRequiredAttr: function(/*Boolean*/ value){
+ this._set("required", value);
+ this.focusNode.setAttribute("aria-required", value);
+ this.validate(this.focused); // to update this.state
+ },
+
+ _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>';
+ this.focusNode.setAttribute("aria-valuetext", lbl);
+ },
+
+ validate: function(/*Boolean*/ isFocused){
+ // summary:
+ // Called by oninit, onblur, and onkeypress, and whenever required/disabled state changes
+ // 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.disabled || this.isValid(isFocused);
+ this._set("state", isValid ? "" : "Incomplete");
+ this.focusNode.setAttribute("aria-invalid", isValid ? "false" : "true");
+ var message = isValid ? "" : this._missingMsg;
+ if(message && this.focused && this._hasBeenBlurred){
+ Tooltip.show(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
+ }else{
+ Tooltip.hide(this.domNode);
+ }
+ this._set("message", message);
+ 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);
+ Tooltip.hide(this.domNode);
+ this.validate(this.focused); // to update this.state
+ },
+
+ postMixInProperties: function(){
+ // summary:
+ // set the missing message
+ this.inherited(arguments);
+ this._missingMsg = 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", event.stop);
+ },
+
+ _setStyleAttr: function(/*String||Object*/ value){
+ this.inherited(arguments);
+ domClass.toggle(this.domNode, this.baseClass + "FixedWidth", !!this.domNode.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);
+ },
+
+ _onFocus: function(){
+ this.validate(true); // show tooltip if second focus of required tooltip, but no selection
+ this.inherited(arguments);
+ },
+
+ _onBlur: function(){
+ Tooltip.hide(this.domNode);
+ this.inherited(arguments);
+ }
+});
+
+Select._Menu = _SelectMenu; // for monkey patching
+
+return Select;
+});
diff --git a/js/dojo/dijit/form/SimpleTextarea.js b/js/dojo/dijit/form/SimpleTextarea.js
new file mode 100644
index 0000000..8065d79
--- /dev/null
+++ b/js/dojo/dijit/form/SimpleTextarea.js
@@ -0,0 +1,101 @@
+//>>built
+define("dijit/form/SimpleTextarea", [
+ "dojo/_base/declare", // declare
+ "dojo/dom-class", // domClass.add
+ "dojo/_base/sniff", // has("ie") has("opera")
+ "dojo/_base/window", // win.doc.selection win.doc.selection.createRange
+ "./TextBox"
+], function(declare, domClass, has, win, TextBox){
+
+/*=====
+ var TextBox = dijit.form.TextBox;
+=====*/
+
+// module:
+// dijit/form/SimpleTextarea
+// 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.
+
+return declare("dijit.form.SimpleTextarea", 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 data-dojo-type="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",
+
+ // rows: Number
+ // The number of rows of text.
+ rows: "3",
+
+ // rows: Number
+ // The number of characters per line.
+ cols: "20",
+
+ templateString: "<textarea ${!nameAttrSetting} data-dojo-attach-point='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(has("ie") && this.cols){ // attribute selectors is not supported in IE6
+ domClass.add(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);
+ },
+
+ _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){
+ var textarea = this.textbox;
+ if(textarea.selectionStart){
+ var pos = textarea.selectionStart;
+ var cr = 0;
+ if(has("opera")){
+ 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(win.doc.selection){ //IE
+ textarea.focus();
+ var range = win.doc.selection.createRange();
+ // delete overflow characters
+ range.moveStart("character", -overflow);
+ range.text = '';
+ // show cursor
+ range.select();
+ }
+ }
+ }
+ this.inherited(arguments);
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/Slider.js b/js/dojo/dijit/form/Slider.js
new file mode 100644
index 0000000..704bcaa
--- /dev/null
+++ b/js/dojo/dijit/form/Slider.js
@@ -0,0 +1,19 @@
+//>>built
+define("dijit/form/Slider", [
+ "dojo/_base/kernel", // kernel.deprecated
+ "./HorizontalSlider",
+ "./VerticalSlider",
+ "./HorizontalRule",
+ "./VerticalRule",
+ "./HorizontalRuleLabels",
+ "./VerticalRuleLabels"
+], function(kernel){
+
+ // module:
+ // dijit/form/Slider
+ // summary:
+ // Rollup of all the the Slider related widgets
+ // For back-compat, remove for 2.0
+
+ kernel.deprecated("Call require() for HorizontalSlider / VerticalRule, explicitly rather than 'dijit.form.Slider' itself", "", "2.0");
+});
diff --git a/js/dojo/dijit/form/TextBox.js b/js/dojo/dijit/form/TextBox.js
new file mode 100644
index 0000000..3fe0a13
--- /dev/null
+++ b/js/dojo/dijit/form/TextBox.js
@@ -0,0 +1,176 @@
+//>>built
+require({cache:{
+'url: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\" data-dojo-attach-point='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"}});
+define("dijit/form/TextBox", [
+ "dojo/_base/declare", // declare
+ "dojo/dom-construct", // domConstruct.create
+ "dojo/dom-style", // domStyle.getComputedStyle
+ "dojo/_base/kernel", // kernel.deprecated
+ "dojo/_base/lang", // lang.hitch
+ "dojo/_base/sniff", // has("ie") has("mozilla")
+ "dojo/_base/window", // win.doc.selection.createRange
+ "./_FormValueWidget",
+ "./_TextBoxMixin",
+ "dojo/text!./templates/TextBox.html",
+ ".." // to export dijit._setSelectionRange, remove in 2.0
+], function(declare, domConstruct, domStyle, kernel, lang, has, win,
+ _FormValueWidget, _TextBoxMixin, template, dijit){
+
+/*=====
+ var _FormValueWidget = dijit.form._FormValueWidget;
+ var _TextBoxMixin = dijit.form._TextBoxMixin;
+=====*/
+
+ // module:
+ // dijit/form/TextBox
+ // summary:
+ // A base class for textbox form inputs
+
+ var TextBox = declare(/*====="dijit.form.TextBox", =====*/ [_FormValueWidget, _TextBoxMixin], {
+ // summary:
+ // A base class for textbox form inputs
+
+ templateString: template,
+ _singleNodeTemplate: '<input class="dijit dijitReset dijitLeft dijitInputField" data-dojo-attach-point="textbox,focusNode" autocomplete="off" type="${type}" ${!nameAttrSetting} />',
+
+ _buttonInputDisabled: has("ie") ? "disabled" : "", // allows IE to disallow focus, but Firefox cannot be disabled for mousedown events
+
+ baseClass: "dijitTextBox",
+
+ postMixInProperties: function(){
+ var type = this.type.toLowerCase();
+ if(this.templateString && this.templateString.toLowerCase() == "input" || ((type == "hidden" || type == "file") && this.templateString == this.constructor.prototype.templateString)){
+ this.templateString = this._singleNodeTemplate;
+ }
+ this.inherited(arguments);
+ },
+
+ _onInput: function(e){
+ this.inherited(arguments);
+ if(this.intermediateChanges){ // _TextBoxMixin uses onInput
+ var _this = this;
+ // the setTimeout allows the key to post to the widget input box
+ setTimeout(function(){ _this._handleOnChange(_this.get('value'), false); }, 0);
+ }
+ },
+
+ _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 = domConstruct.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";
+ }
+ },
+
+ _setValueAttr: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
+ this.inherited(arguments);
+ this._updatePlaceHolder();
+ },
+
+ getDisplayedValue: function(){
+ // summary:
+ // Deprecated. Use get('displayedValue') instead.
+ // tags:
+ // deprecated
+ kernel.deprecated(this.declaredClass+"::getDisplayedValue() is deprecated. Use set('displayedValue') instead.", "", "2.0");
+ return this.get('displayedValue');
+ },
+
+ setDisplayedValue: function(/*String*/ value){
+ // summary:
+ // Deprecated. Use set('displayedValue', ...) instead.
+ // tags:
+ // deprecated
+ kernel.deprecated(this.declaredClass+"::setDisplayedValue() is deprecated. Use set('displayedValue', ...) instead.", "", "2.0");
+ this.set('displayedValue', value);
+ },
+
+ _onBlur: function(e){
+ if(this.disabled){ return; }
+ this.inherited(arguments);
+ this._updatePlaceHolder();
+ },
+
+ _onFocus: function(/*String*/ by){
+ if(this.disabled || this.readOnly){ return; }
+ this.inherited(arguments);
+ this._updatePlaceHolder();
+ }
+ });
+
+ if(has("ie")){
+ TextBox = declare(/*===== "dijit.form.TextBox.IEMixin", =====*/ TextBox, {
+ declaredClass: "dijit.form.TextBox", // for user code referencing declaredClass
+
+ _isTextSelected: function(){
+ var range = win.doc.selection.createRange();
+ var parent = range.parentElement();
+ return parent == this.textbox && range.text.length == 0;
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ // 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(lang.hitch(this, function(){
+ try{
+ var s = domStyle.getComputedStyle(this.domNode); // can throw an exception if widget is immediately destroyed
+ 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;
+ }
+ }
+ }
+ }
+ }catch(e){/*when used in a Dialog, and this is called before the dialog is
+ shown, s.fontFamily would trigger "Invalid Argument" error.*/}
+ }), 0);
+ }
+ });
+
+ // Overrides definition of _setSelectionRange from _TextBoxMixin (TODO: move to _TextBoxMixin.js?)
+ dijit._setSelectionRange = _TextBoxMixin._setSelectionRange = function(/*DomNode*/ element, /*Number?*/ start, /*Number?*/ stop){
+ 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(has("mozilla")){
+ TextBox = declare(/*===== "dijit.form.TextBox.MozMixin", =====*/TextBox, {
+ declaredClass: "dijit.form.TextBox", // for user code referencing declaredClass
+
+ _onBlur: function(e){
+ this.inherited(arguments);
+ if(this.selectOnClick){
+ // clear selection so that the next mouse click doesn't reselect
+ this.textbox.selectionStart = this.textbox.selectionEnd = undefined;
+ }
+ }
+ });
+ }else{
+ TextBox.prototype.declaredClass = "dijit.form.TextBox";
+ }
+ lang.setObject("dijit.form.TextBox", TextBox); // don't do direct assignment, it confuses API doc parser
+
+ return TextBox;
+});
diff --git a/js/dojo/dijit/form/Textarea.js b/js/dojo/dijit/form/Textarea.js
new file mode 100644
index 0000000..7d8a75b
--- /dev/null
+++ b/js/dojo/dijit/form/Textarea.js
@@ -0,0 +1,50 @@
+//>>built
+define("dijit/form/Textarea", [
+ "dojo/_base/declare", // declare
+ "dojo/dom-style", // domStyle.set
+ "./_ExpandingTextAreaMixin",
+ "./SimpleTextarea"
+], function(declare, domStyle, _ExpandingTextAreaMixin, SimpleTextarea){
+
+/*=====
+ var _ExpandingTextAreaMixin = dijit.form._ExpandingTextAreaMixin;
+ var SimpleTextarea = dijit.form.SimpleTextarea;
+=====*/
+
+// module:
+// dijit/form/Textarea
+// summary:
+// A textarea widget that adjusts it's height according to the amount of data.
+
+
+return declare("dijit.form.Textarea", [SimpleTextarea, _ExpandingTextAreaMixin], {
+ // 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 data-dojo-type="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: "",
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ // tweak textarea style to reduce browser differences
+ domStyle.set(this.textbox, { overflowY: 'hidden', overflowX: 'auto', boxSizing: 'border-box', MsBoxSizing: 'border-box', WebkitBoxSizing: 'border-box', MozBoxSizing: 'border-box' });
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/TimeTextBox.js b/js/dojo/dijit/form/TimeTextBox.js
new file mode 100644
index 0000000..61f0995
--- /dev/null
+++ b/js/dojo/dijit/form/TimeTextBox.js
@@ -0,0 +1,89 @@
+//>>built
+define("dijit/form/TimeTextBox", [
+ "dojo/_base/declare", // declare
+ "dojo/keys", // keys.DOWN_ARROW keys.ENTER keys.ESCAPE keys.TAB keys.UP_ARROW
+ "dojo/_base/lang", // lang.hitch
+ "../_TimePicker",
+ "./_DateTimeTextBox"
+], function(declare, keys, lang, _TimePicker, _DateTimeTextBox){
+
+/*=====
+ var _TimePicker = dijit._TimePicker;
+ var _DateTimeTextBox = dijit.form._DateTimeTextBox;
+=====*/
+
+ // module:
+ // dijit/form/TimeTextBox
+ // summary:
+ // A validating, serializable, range-bound time text box with a drop down time picker
+
+
+ /*=====
+ declare(
+ "dijit.form.TimeTextBox.__Constraints",
+ [dijit.form._DateTimeTextBox.__Constraints, dijit._TimePicker.__Constraints]
+ );
+ =====*/
+
+ return declare("dijit.form.TimeTextBox", _DateTimeTextBox, {
+ // summary:
+ // A validating, serializable, range-bound time text box with a drop down time picker
+
+ baseClass: "dijitTextBox dijitComboBox dijitTimeTextBox",
+ popupClass: _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: stamp.fromISOString("T12:59:59", new Date())})
+ //
+ // When passed to the parser in markup, must be specified according to locale-independent
+ // `stamp.fromISOString` format.
+ //
+ // Example:
+ // | <input data-dojo-type='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){
+ if(this.disabled || this.readOnly){ return; }
+ 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 keys.ENTER:
+ case keys.TAB:
+ case keys.ESCAPE:
+ case keys.DOWN_ARROW:
+ case 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(lang.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/js/dojo/dijit/form/ToggleButton.js b/js/dojo/dijit/form/ToggleButton.js
new file mode 100644
index 0000000..d15e31b
--- /dev/null
+++ b/js/dojo/dijit/form/ToggleButton.js
@@ -0,0 +1,34 @@
+//>>built
+define("dijit/form/ToggleButton", [
+ "dojo/_base/declare", // declare
+ "dojo/_base/kernel", // kernel.deprecated
+ "./Button",
+ "./_ToggleButtonMixin"
+], function(declare, kernel, Button, _ToggleButtonMixin){
+
+/*=====
+ var Button = dijit.form.Button;
+ var _ToggleButtonMixin = dijit.form._ToggleButtonMixin;
+=====*/
+
+ // module:
+ // dijit/form/ToggleButton
+ // summary:
+ // A templated button widget that can be in two states (checked or not).
+
+
+ return declare("dijit.form.ToggleButton", [Button, _ToggleButtonMixin], {
+ // summary:
+ // A templated button widget that can be in two states (checked or not).
+ // Can be base class for things like tabs or checkbox or radio buttons
+
+ baseClass: "dijitToggleButton",
+
+ setChecked: function(/*Boolean*/ checked){
+ // summary:
+ // Deprecated. Use set('checked', true/false) instead.
+ kernel.deprecated("setChecked("+checked+") is deprecated. Use set('checked',"+checked+") instead.", "", "2.0");
+ this.set('checked', checked);
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/ValidationTextBox.js b/js/dojo/dijit/form/ValidationTextBox.js
new file mode 100644
index 0000000..46ee7c9
--- /dev/null
+++ b/js/dojo/dijit/form/ValidationTextBox.js
@@ -0,0 +1,297 @@
+//>>built
+require({cache:{
+'url:dijit/form/templates/ValidationTextBox.html':"<div class=\"dijit dijitReset dijitInline 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\" data-dojo-attach-point='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"}});
+define("dijit/form/ValidationTextBox", [
+ "dojo/_base/declare", // declare
+ "dojo/i18n", // i18n.getLocalization
+ "./TextBox",
+ "../Tooltip",
+ "dojo/text!./templates/ValidationTextBox.html",
+ "dojo/i18n!./nls/validate"
+], function(declare, i18n, TextBox, Tooltip, template){
+
+/*=====
+ var Tooltip = dijit.Tooltip;
+ var TextBox = dijit.form.TextBox;
+=====*/
+
+ // module:
+ // dijit/form/ValidationTextBox
+ // summary:
+ // Base class for textbox widgets with the ability to validate content of various types and provide user feedback.
+
+
+ /*=====
+ 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_ = "";
+ }
+ =====*/
+
+ return declare("dijit.form.ValidationTextBox", TextBox, {
+ // summary:
+ // Base class for textbox widgets with the ability to validate content of various types and provide user feedback.
+ // tags:
+ // protected
+
+ templateString: template,
+ 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"));
+ this.focusNode.setAttribute("aria-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
+ if(message && this.focused){
+ Tooltip.show(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
+ }else{
+ Tooltip.hide(this.domNode);
+ }
+ },
+
+ _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 = 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);
+ this.focusNode.setAttribute("aria-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);
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/VerticalRule.js b/js/dojo/dijit/form/VerticalRule.js
new file mode 100644
index 0000000..a83fb10
--- /dev/null
+++ b/js/dojo/dijit/form/VerticalRule.js
@@ -0,0 +1,35 @@
+//>>built
+define("dijit/form/VerticalRule", [
+ "dojo/_base/declare", // declare
+ "./HorizontalRule"
+], function(declare, HorizontalRule){
+
+/*=====
+ var HorizontalRule = dijit.form.HorizontalRule;
+=====*/
+
+ // module:
+ // dijit/form/VerticalRule
+ // summary:
+ // Hash marks for the `dijit.form.VerticalSlider`
+
+ return declare("dijit.form.VerticalRule", 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/js/dojo/dijit/form/VerticalRuleLabels.js b/js/dojo/dijit/form/VerticalRuleLabels.js
new file mode 100644
index 0000000..8548cef
--- /dev/null
+++ b/js/dojo/dijit/form/VerticalRuleLabels.js
@@ -0,0 +1,33 @@
+//>>built
+define("dijit/form/VerticalRuleLabels", [
+ "dojo/_base/declare", // declare
+ "./HorizontalRuleLabels"
+], function(declare, HorizontalRuleLabels){
+
+/*=====
+ var HorizontalRuleLabels = dijit.form.HorizontalRuleLabels;
+=====*/
+
+ // module:
+ // dijit/form/VerticalRuleLabels
+ // summary:
+ // Labels for the `dijit.form.VerticalSlider`
+
+ return declare("dijit.form.VerticalRuleLabels", 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/js/dojo/dijit/form/VerticalSlider.js b/js/dojo/dijit/form/VerticalSlider.js
new file mode 100644
index 0000000..e6ce381
--- /dev/null
+++ b/js/dojo/dijit/form/VerticalSlider.js
@@ -0,0 +1,43 @@
+//>>built
+require({cache:{
+'url:dijit/form/templates/VerticalSlider.html':"<table class=\"dijit dijitReset dijitSlider dijitSliderV\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\" data-dojo-attach-event=\"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\" data-dojo-attach-point=\"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\" data-dojo-attach-event=\"press:_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 data-dojo-attach-point=\"leftDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationL dijitSliderDecorationV\"></td\n\t\t><td class=\"dijitReset dijitSliderDecorationC\" style=\"height:100%;\"\n\t\t\t><input data-dojo-attach-point=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\n\t\t\t/><center class=\"dijitReset dijitSliderBarContainerV\" role=\"presentation\" data-dojo-attach-point=\"sliderBarContainer\"\n\t\t\t\t><div role=\"presentation\" data-dojo-attach-point=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderRemainingBar dijitSliderRemainingBarV\" data-dojo-attach-event=\"press:_onBarClick\"><!--#5629--></div\n\t\t\t\t><div role=\"presentation\" data-dojo-attach-point=\"progressBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderProgressBar dijitSliderProgressBarV\" data-dojo-attach-event=\"press:_onBarClick\"\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableV\" style=\"vertical-align:top;\"\n\t\t\t\t\t\t><div data-dojo-attach-point=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleV\" data-dojo-attach-event=\"press:_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 data-dojo-attach-point=\"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\" data-dojo-attach-event=\"press:_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\" data-dojo-attach-point=\"incrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n></table>\n"}});
+define("dijit/form/VerticalSlider", [
+ "dojo/_base/declare", // declare
+ "./HorizontalSlider",
+ "dojo/text!./templates/VerticalSlider.html"
+], function(declare, HorizontalSlider, template){
+
+/*=====
+ var HorizontalSlider = dijit.form.HorizontalSlider;
+=====*/
+
+ // module:
+ // dijit/form/VerticalSlider
+ // summary:
+ // A form widget that allows one to select a value with a vertically draggable handle
+
+
+ return declare("dijit.form.VerticalSlider", HorizontalSlider, {
+ // summary:
+ // A form widget that allows one to select a value with a vertically draggable handle
+
+ templateString: template,
+ _mousePixelCoord: "pageY",
+ _pixelCount: "h",
+ _startingPixelCoord: "y",
+ _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/js/dojo/dijit/form/_AutoCompleterMixin.js b/js/dojo/dijit/form/_AutoCompleterMixin.js
new file mode 100644
index 0000000..696076f
--- /dev/null
+++ b/js/dojo/dijit/form/_AutoCompleterMixin.js
@@ -0,0 +1,765 @@
+//>>built
+define("dijit/form/_AutoCompleterMixin", [
+ "dojo/_base/connect", // keys keys.SHIFT
+ "dojo/data/util/filter", // patternToRegExp
+ "dojo/_base/declare", // declare
+ "dojo/_base/Deferred", // Deferred.when
+ "dojo/dom-attr", // domAttr.get
+ "dojo/_base/event", // event.stop
+ "dojo/keys",
+ "dojo/_base/lang", // lang.clone lang.hitch
+ "dojo/query", // query
+ "dojo/regexp", // regexp.escapeString
+ "dojo/_base/sniff", // has("ie")
+ "dojo/string", // string.substitute
+ "dojo/_base/window", // win.doc.selection.createRange
+ "./DataList",
+ "../registry", // registry.byId
+ "./_TextBoxMixin" // defines _TextBoxMixin.selectInputText
+], function(connect, filter, declare, Deferred, domAttr, event, keys, lang, query, regexp, has, string, win,
+ DataList, registry, _TextBoxMixin){
+
+ // module:
+ // dijit/form/_AutoCompleterMixin
+ // summary:
+ // A mixin that implements the base functionality for `dijit.form.ComboBox`/`dijit.form.FilteringSelect`
+
+
+ return declare("dijit.form._AutoCompleterMixin", null, {
+ // summary:
+ // A mixin that implements the base functionality for `dijit.form.ComboBox`/`dijit.form.FilteringSelect`
+ // description:
+ // All widgets that mix in dijit.form._AutoCompleterMixin 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] dojo.store.api.Store
+ // Reference to data provider object used by this ComboBox
+ store: null,
+
+ // fetchProperties: Object
+ // Mixin to the 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,
+
+ // 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(has("ie")){
+ // in the case of a mouse click in a popup being handled,
+ // then the win.doc.selection is not the textarea, but the popup
+ // var r = win.doc.selection.createRange();
+ // hack to get IE 6 to play nice. What a POS browser.
+ var tr = win.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);
+ _TextBoxMixin.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);
+ this.domNode.setAttribute("aria-disabled", value);
+ },
+
+ _abortQuery: function(){
+ // stop in-progress query
+ if(this.searchTimer){
+ clearTimeout(this.searchTimer);
+ this.searchTimer = null;
+ }
+ if(this._fetchHandle){
+ if(this._fetchHandle.cancel){
+ this._cancelingQuery = true;
+ this._fetchHandle.cancel();
+ this._cancelingQuery = false;
+ }
+ this._fetchHandle = null;
+ }
+ },
+
+ _onInput: function(/*Event*/ evt){
+ // summary:
+ // Handles paste events
+ this.inherited(arguments);
+ if(evt.charOrCode == 229){ // IME or cut/paste event
+ this._onKey(evt);
+ }
+ },
+
+ _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 == keys.SHIFT){
+ return; // throw out weird key combinations and spurious events
+ }
+
+ var doSearch = false;
+ var pw = this.dropDown;
+ 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 keys.PAGE_DOWN:
+ case keys.DOWN_ARROW:
+ case keys.PAGE_UP:
+ case keys.UP_ARROW:
+ // Keystroke caused ComboBox_menu to move to a different item.
+ // Copy new item to <input> box.
+ if(this._opened){
+ this._announceOption(highlighted);
+ }
+ event.stop(evt);
+ break;
+
+ case keys.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);
+ event.stop(evt);
+ break;
+ }else if(highlighted == pw.previousButton){
+ this._nextSearch(-1);
+ event.stop(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
+ if(this._opened || this._fetchHandle){
+ event.stop(evt);
+ }
+ // fall through
+
+ case keys.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(highlighted);
+ }
+ // fall through
+
+ case keys.ESCAPE:
+ 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
+ event.stop(evt);
+ this._selectOption(highlighted);
+ this.closeDropDown();
+ }else{
+ // user typed a space into the input box, treat as normal character
+ doSearch = true;
+ }
+ break;
+
+ case keys.DELETE:
+ case keys.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(lang.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
+ _TextBoxMixin.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.autoComplete ? this._getCaretPos(fn) : fn.value.length;
+ // 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
+ _TextBoxMixin.selectInputText(fn, cpos);
+ }
+ }else{
+ // text does not autoComplete; replace the whole value and highlight
+ fn.value = text;
+ _TextBoxMixin.selectInputText(fn);
+ }
+ },
+
+ _openResultList: function(/*Object*/ results, /*Object*/ query, /*Object*/ options){
+ // 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 ||
+ (query[this.searchAttr] !== this._lastQuery) // TODO: better way to avoid getting unwanted notify
+ ){
+ return;
+ }
+ var wasSelected = this.dropDown.getHighlightedOption();
+ this.dropDown.clearResultList();
+ if(!results.length && options.start == 0){ // 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.
+
+ var nodes = this.dropDown.createOptions(
+ results,
+ options,
+ lang.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(options.direction){
+ if(1 == options.direction){
+ this.dropDown.highlightFirstOption();
+ }else if(-1 == options.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(query[this.searchAttr].toString())){
+ 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);
+ this.openDropDown();
+ this.domNode.setAttribute("aria-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);
+ this.domNode.setAttribute("aria-expanded", "false");
+ this.focusNode.removeAttribute("aria-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){
+ this._handleOnChange(this.value, true);
+ }
+ this._refreshState();
+ }
+ },
+
+ _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
+ var value = '';
+ if(item){
+ if(!displayedValue){
+ displayedValue = this.store._oldAPI ? // remove getValue() for 2.0 (old dojo.data API)
+ this.store.getValue(item, this.searchAttr) : item[this.searchAttr];
+ }
+ value = this._getValueField() != this.searchAttr ? this.store.getIdentity(item) : displayedValue;
+ }
+ this.set('value', value, priorityChange, displayedValue, item);
+ },
+
+ _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._oldAPI ? // remove getValue() for 2.0 (old dojo.data API)
+ this.store.getValue(node.item, this.searchAttr) : 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
+ this.focusNode.setAttribute("aria-activedescendant", domAttr.get(node, "id"));
+ // autocomplete the rest of the option to announce change
+ this._autoCompleteText(newValue);
+ },
+
+ _selectOption: function(/*DomNode*/ target){
+ // summary:
+ // Menu callback function, called when an item in the menu is selected.
+ this.closeDropDown();
+ if(target){
+ this._announceOption(target);
+ }
+ this._setCaretPos(this.focusNode, this.focusNode.value.length);
+ this._handleOnChange(this.value, true);
+ },
+
+ _startSearchAll: function(){
+ this._startSearch('');
+ },
+
+ _startSearchFromInput: function(){
+ this._startSearch(this.focusNode.value.replace(/([\\\*\?])/g, "\\$1"));
+ },
+
+ _getQueryString: function(/*String*/ text){
+ return 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 = lang.isString(this.dropDownClass) ?
+ lang.getObject(this.dropDownClass, false) : this.dropDownClass;
+ this.dropDown = new dropDownConstructor({
+ onChange: lang.hitch(this, this._selectOption),
+ id: popupId,
+ dir: this.dir,
+ textDir: this.textDir
+ });
+ this.focusNode.removeAttribute("aria-activedescendant");
+ this.textbox.setAttribute("aria-owns",popupId); // associate popup with textbox
+ }
+ this._lastInput = key; // Store exactly what was entered by the user.
+
+ // Setup parameters to be passed to store.query().
+ // Create a new query to prevent accidentally querying for a hidden
+ // value from FilteringSelect's keyField
+ var query = lang.clone(this.query); // #5970
+ var options = {
+ start: 0,
+ count: this.pageSize,
+ queryOptions: { // remove for 2.0
+ ignoreCase: this.ignoreCase,
+ deep: true
+ }
+ };
+ lang.mixin(options, this.fetchProperties);
+
+ // Generate query
+ var qs = this._getQueryString(key), q;
+ if(this.store._oldAPI){
+ // remove this branch for 2.0
+ q = qs;
+ }else{
+ // Query on searchAttr is a regex for benefit of dojo.store.Memory,
+ // but with a toString() method to help dojo.store.JsonRest.
+ // Search string like "Co*" converted to regex like /^Co.*$/i.
+ q = filter.patternToRegExp(qs, this.ignoreCase);
+ q.toString = function(){ return qs; };
+ }
+ this._lastQuery = query[this.searchAttr] = q;
+
+ // Function to run the query, wait for the results, and then call _openResultList()
+ var _this = this,
+ startQuery = function(){
+ var resPromise = _this._fetchHandle = _this.store.query(query, options);
+ Deferred.when(resPromise, function(res){
+ _this._fetchHandle = null;
+ res.total = resPromise.total;
+ _this._openResultList(res, query, options);
+ }, function(err){
+ _this._fetchHandle = null;
+ if(!_this._cancelingQuery){ // don't treat canceled query as an error
+ console.error(_this.declaredClass + ' ' + err.toString());
+ _this.closeDropDown();
+ }
+ });
+ };
+
+ // #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(lang.hitch(this, function(query, _this){
+ this.searchTimer = null;
+
+ startQuery();
+
+ // Setup method to handle clicking next/previous buttons to page through results
+ this._nextSearch = this.dropDown.onPage = function(direction){
+ options.start += options.count * direction;
+ // tell callback the direction of the paging so the screen
+ // reader knows which menu option to shout
+ options.direction = direction;
+ startQuery();
+ _this.focus();
+ };
+ }, query, this), this.searchDelay);
+ },
+
+ _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;
+ var list = this.list;
+ if(list){
+ this.store = registry.byId(list);
+ }else{
+ // if user didn't specify store, then assume there are option tags
+ this.store = new DataList({}, 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();
+ // remove getValue() for 2.0 (old dojo.data API)
+ this.value = this.store._oldAPI ? this.store.getValue(item, valueField) : 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=query('label[for="'+this.id+'"]');
+ if(label.length){
+ label[0].id = (this.id+"_label");
+ this.domNode.setAttribute("aria-labelledby", label[0].id);
+
+ }
+ this.inherited(arguments);
+ },
+
+ _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 = 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;"); //balance"
+ 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.store.api.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).
+ // Remove getValue() for 2.0 (old dojo.data API)
+ return (store._oldAPI ? store.getValue(item, this.labelAttr || this.searchAttr) :
+ item[this.labelAttr || this.searchAttr]).toString(); // String
+ },
+
+ _setValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange, /*String?*/ displayedValue, /*item?*/ item){
+ // summary:
+ // Hook so set('value', value) works.
+ // description:
+ // Sets the value of the select.
+ this._set("item", item||null); // value not looked up in store
+ if(!value){ value = ''; } // null translates to blank
+ this.inherited(arguments);
+ },
+ _setTextDirAttr: function(/*String*/ textDir){
+ // summary:
+ // Setter for textDir, needed for the dropDown's textDir update.
+ // description:
+ // Users shouldn't call this function; they should be calling
+ // set('textDir', value)
+ // tags:
+ // private
+ this.inherited(arguments);
+ // update the drop down also (_ComboBoxMenuMixin)
+ if(this.dropDown){
+ this.dropDown._set("textDir", textDir);
+ }
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/_ButtonMixin.js b/js/dojo/dijit/form/_ButtonMixin.js
new file mode 100644
index 0000000..c2d06e8
--- /dev/null
+++ b/js/dojo/dijit/form/_ButtonMixin.js
@@ -0,0 +1,86 @@
+//>>built
+define("dijit/form/_ButtonMixin", [
+ "dojo/_base/declare", // declare
+ "dojo/dom", // dom.setSelectable
+ "dojo/_base/event", // event.stop
+ "../registry" // registry.byNode
+], function(declare, dom, event, registry){
+
+// module:
+// dijit/form/_ButtonMixin
+// summary:
+// A mixin to add a thin standard API wrapper to a normal HTML button
+
+return declare("dijit.form._ButtonMixin", null, {
+ // summary:
+ // A mixin to add a thin standard API wrapper to a normal HTML button
+ // description:
+ // A label should always be specified (through innerHTML) or the label attribute.
+ // Attach points:
+ // focusNode (required): this node receives focus
+ // valueNode (optional): this node's value gets submitted with FORM elements
+ // containerNode (optional): this node gets the innerHTML assignment for label
+ // example:
+ // | <button data-dojo-type="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
+ // Content to display in button.
+ label: "",
+
+ // type: [const] String
+ // Type of button (submit, reset, button, checkbox, radio)
+ type: "button",
+
+ _onClick: function(/*Event*/ e){
+ // summary:
+ // Internal function to handle click actions
+ if(this.disabled){
+ event.stop(e);
+ return false;
+ }
+ var preventDefault = this.onClick(e) === false; // user click actions
+ if(!preventDefault && this.type == "submit" && !(this.valueNode||this.focusNode).form){ // see if a non-form widget needs to be signalled
+ for(var node=this.domNode; node.parentNode; node=node.parentNode){
+ var widget=registry.byNode(node);
+ if(widget && typeof widget._onSubmit == "function"){
+ widget._onSubmit(e);
+ preventDefault = true;
+ break;
+ }
+ }
+ }
+ if(preventDefault){
+ e.preventDefault();
+ }
+ return !preventDefault;
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ dom.setSelectable(this.focusNode, false);
+ },
+
+ 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
+ },
+
+ _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||this.focusNode).innerHTML = content;
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/_CheckBoxMixin.js b/js/dojo/dijit/form/_CheckBoxMixin.js
new file mode 100644
index 0000000..66f6010
--- /dev/null
+++ b/js/dojo/dijit/form/_CheckBoxMixin.js
@@ -0,0 +1,78 @@
+//>>built
+define("dijit/form/_CheckBoxMixin", [
+ "dojo/_base/declare", // declare
+ "dojo/dom-attr", // domAttr.set
+ "dojo/_base/event" // event.stop
+], function(declare, domAttr, event){
+
+ // module:
+ // dijit/form/_CheckBoxMixin
+ // summary:
+ // Mixin to provide widget functionality corresponding to an HTML checkbox
+
+ return declare("dijit.form._CheckBoxMixin", null, {
+ // summary:
+ // Mixin to provide widget functionality corresponding to an HTML checkbox
+ //
+ // 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.
+ //
+
+ // 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).
+ 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,
+
+ // aria-pressed for toggle buttons, and aria-checked for checkboxes
+ _aria_attr: "aria-checked",
+
+ _setReadOnlyAttr: function(/*Boolean*/ value){
+ this._set("readOnly", value);
+ domAttr.set(this.focusNode, 'readOnly', value);
+ this.focusNode.setAttribute("aria-readonly", value);
+ },
+
+ // 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";
+ }
+ this.inherited(arguments);
+ },
+
+ reset: function(){
+ this.inherited(arguments);
+ // Handle unlikely event that the <input type=checkbox> value attribute has changed
+ this._set("value", this.params.value || "on");
+ domAttr.set(this.focusNode, 'value', this.value);
+ },
+
+ _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){
+ event.stop(e);
+ return false;
+ }
+ return this.inherited(arguments);
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/_ComboBoxMenu.js b/js/dojo/dijit/form/_ComboBoxMenu.js
new file mode 100644
index 0000000..ffbc4e0
--- /dev/null
+++ b/js/dojo/dijit/form/_ComboBoxMenu.js
@@ -0,0 +1,139 @@
+//>>built
+define("dijit/form/_ComboBoxMenu", [
+ "dojo/_base/declare", // declare
+ "dojo/dom-class", // domClass.add domClass.remove
+ "dojo/dom-construct", // domConstruct.create
+ "dojo/dom-style", // domStyle.get
+ "dojo/keys", // keys.DOWN_ARROW keys.PAGE_DOWN keys.PAGE_UP keys.UP_ARROW
+ "../_WidgetBase",
+ "../_TemplatedMixin",
+ "./_ComboBoxMenuMixin",
+ "./_ListMouseMixin"
+], function(declare, domClass, domConstruct, domStyle, keys,
+ _WidgetBase, _TemplatedMixin, _ComboBoxMenuMixin, _ListMouseMixin){
+
+/*=====
+ var _WidgetBase = dijit._WidgetBase;
+ var _TemplatedMixin = dijit._TemplatedMixin;
+ var _ComboBoxMenuMixin = dijit.form._ComboBoxMenuMixin;
+ var _ListMouseMixin = dijit.form._ListMouseMixin;
+=====*/
+
+ // module:
+ // dijit/form/_ComboBoxMenu
+ // summary:
+ // Focus-less menu for internal use in `dijit.form.ComboBox`
+
+ return declare("dijit.form._ComboBoxMenu",[_WidgetBase, _TemplatedMixin, _ListMouseMixin, _ComboBoxMenuMixin], {
+ // summary:
+ // Focus-less menu for internal use in `dijit.form.ComboBox`
+ // Abstract methods that must be defined externally:
+ // onChange: item was explicitly chosen (mousedown somewhere on the menu and mouseup somewhere on the menu)
+ // onPage: next(1) or previous(-1) button pressed
+ // tags:
+ // private
+
+ templateString: "<div class='dijitReset dijitMenu' data-dojo-attach-point='containerNode' style='overflow: auto; overflow-x: hidden;'>"
+ +"<div class='dijitMenuItem dijitMenuPreviousButton' data-dojo-attach-point='previousButton' role='option'></div>"
+ +"<div class='dijitMenuItem dijitMenuNextButton' data-dojo-attach-point='nextButton' role='option'></div>"
+ +"</div>",
+
+ baseClass: "dijitComboBoxMenu",
+
+ postCreate: function(){
+ this.inherited(arguments);
+ if(!this.isLeftToRight()){
+ domClass.add(this.previousButton, "dijitMenuItemRtl");
+ domClass.add(this.nextButton, "dijitMenuItemRtl");
+ }
+ },
+
+ _createMenuItem: function(){
+ return domConstruct.create("div", {
+ "class": "dijitReset dijitMenuItem" +(this.isLeftToRight() ? "" : " dijitMenuItemRtl"),
+ role: "option"
+ });
+ },
+
+ onHover: function(/*DomNode*/ node){
+ // summary:
+ // Add hover CSS
+ domClass.add(node, "dijitMenuItemHover");
+ },
+
+ onUnhover: function(/*DomNode*/ node){
+ // summary:
+ // Remove hover CSS
+ domClass.remove(node, "dijitMenuItemHover");
+ },
+
+ onSelect: function(/*DomNode*/ node){
+ // summary:
+ // Add selected CSS
+ domClass.add(node, "dijitMenuItemSelected");
+ },
+
+ onDeselect: function(/*DomNode*/ node){
+ // summary:
+ // Remove selected CSS
+ domClass.remove(node, "dijitMenuItemSelected");
+ },
+
+ _page: function(/*Boolean*/ up){
+ // summary:
+ // Handles page-up and page-down keypresses
+
+ var scrollamount = 0;
+ var oldscroll = this.domNode.scrollTop;
+ var height = domStyle.get(this.domNode, "height");
+ // if no item is highlighted, highlight the first option
+ if(!this.getHighlightedOption()){
+ this.selectNextNode();
+ }
+ while(scrollamount<height){
+ var highlighted_option = this.getHighlightedOption();
+ if(up){
+ // stop at option 1
+ if(!highlighted_option.previousSibling ||
+ highlighted_option.previousSibling.style.display == "none"){
+ break;
+ }
+ this.selectPreviousNode();
+ }else{
+ // stop at last option
+ if(!highlighted_option.nextSibling ||
+ highlighted_option.nextSibling.style.display == "none"){
+ break;
+ }
+ this.selectNextNode();
+ }
+ // going backwards
+ var newscroll = this.domNode.scrollTop;
+ scrollamount += (newscroll-oldscroll)*(up ? -1:1);
+ oldscroll = newscroll;
+ }
+ },
+
+ 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 keys.DOWN_ARROW:
+ this.selectNextNode();
+ return false;
+ case keys.PAGE_DOWN:
+ this._page(false);
+ return false;
+ case keys.UP_ARROW:
+ this.selectPreviousNode();
+ return false;
+ case keys.PAGE_UP:
+ this._page(true);
+ return false;
+ default:
+ return true;
+ }
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/_ComboBoxMenuMixin.js b/js/dojo/dijit/form/_ComboBoxMenuMixin.js
new file mode 100644
index 0000000..5a3d687
--- /dev/null
+++ b/js/dojo/dijit/form/_ComboBoxMenuMixin.js
@@ -0,0 +1,192 @@
+//>>built
+define("dijit/form/_ComboBoxMenuMixin", [
+ "dojo/_base/array", // array.forEach
+ "dojo/_base/declare", // declare
+ "dojo/dom-attr", // domAttr.set
+ "dojo/i18n", // i18n.getLocalization
+ "dojo/_base/window", // win.doc.createTextNode
+ "dojo/i18n!./nls/ComboBox"
+], function(array, declare, domAttr, i18n, win){
+
+// module:
+// dijit/form/_ComboBoxMenuMixin
+// summary:
+// Focus-less menu for internal use in `dijit.form.ComboBox`
+
+return declare( "dijit.form._ComboBoxMenuMixin", null, {
+ // summary:
+ // Focus-less menu for internal use in `dijit.form.ComboBox`
+ // tags:
+ // private
+
+ // _messages: Object
+ // Holds "next" and "previous" text for paging buttons on drop down
+ _messages: null,
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this._messages = 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);
+ },
+
+ onClick: function(/*DomNode*/ node){
+ if(node == this.previousButton){
+ this._setSelectedAttr(null);
+ this.onPage(-1);
+ }else if(node == this.nextButton){
+ this._setSelectedAttr(null);
+ this.onPage(1);
+ }else{
+ this.onChange(node);
+ }
+ },
+
+ // stubs
+ onChange: function(/*Number*/ /*===== direction =====*/){
+ // summary:
+ // Notifies ComboBox/FilteringSelect that user selected an option.
+ // 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._setSelectedAttr(null);
+ },
+
+ _createOption: function(/*Object*/ item, labelFunc){
+ // summary:
+ // Creates an option to appear on the popup menu subclassed by
+ // `dijit.form.FilteringSelect`.
+
+ var menuitem = this._createMenuItem();
+ var labelObject = labelFunc(item);
+ if(labelObject.html){
+ menuitem.innerHTML = labelObject.label;
+ }else{
+ menuitem.appendChild(
+ win.doc.createTextNode(labelObject.label)
+ );
+ }
+ // #3250: in blank options, assign a normal height
+ if(menuitem.innerHTML == ""){
+ menuitem.innerHTML = "&#160;"; // &nbsp;
+ }
+
+ // update menuitem.dir if BidiSupport was required
+ this.applyTextDir(menuitem, (menuitem.innerText || menuitem.textContent || ""));
+
+ menuitem.item=item;
+ return menuitem;
+ },
+
+ createOptions: function(results, options, labelFunc){
+ // summary:
+ // Fills in the items in the drop down list
+ // results:
+ // Array of items
+ // options:
+ // The options to the query function of the store
+ //
+ // labelFunc:
+ // Function to produce a label in the drop down list from a dojo.data item
+
+ // display "Previous . . ." button
+ this.previousButton.style.display = (options.start == 0) ? "none" : "";
+ domAttr.set(this.previousButton, "id", this.id + "_prev");
+ // create options using _createOption function defined by parent
+ // ComboBox (or FilteringSelect) class
+ // #2309:
+ // iterate over cache nondestructively
+ array.forEach(results, function(item, i){
+ var menuitem = this._createOption(item, labelFunc);
+ domAttr.set(menuitem, "id", this.id + i);
+ this.nextButton.parentNode.insertBefore(menuitem, this.nextButton);
+ }, this);
+ // display "Next . . ." button
+ var displayMore = false;
+ // Try to determine if we should show 'more'...
+ if(results.total && !results.total.then && results.total != -1){
+ if((options.start + options.count) < results.total){
+ displayMore = true;
+ }else if((options.start + options.count) > results.total && options.count == results.length){
+ // Weird return from a data store, 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(options.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";
+ domAttr.set(this.nextButton,"id", this.id + "_next");
+ return this.containerNode.childNodes;
+ },
+
+ clearResultList: function(){
+ // summary:
+ // Clears the entries in the drop down list, but of course keeps the previous and next buttons.
+ var container = this.containerNode;
+ while(container.childNodes.length > 2){
+ container.removeChild(container.childNodes[container.childNodes.length-2]);
+ }
+ this._setSelectedAttr(null);
+ },
+
+ highlightFirstOption: function(){
+ // summary:
+ // Highlight the first real item in the list (not Previous Choices).
+ this.selectFirstNode();
+ },
+
+ highlightLastOption: function(){
+ // summary:
+ // Highlight the last real item in the list (not More Choices).
+ this.selectLastNode();
+ },
+
+ selectFirstNode: function(){
+ this.inherited(arguments);
+ if(this.getHighlightedOption() == this.previousButton){
+ this.selectNextNode();
+ }
+ },
+
+ selectLastNode: function(){
+ this.inherited(arguments);
+ if(this.getHighlightedOption() == this.nextButton){
+ this.selectPreviousNode();
+ }
+ },
+
+ getHighlightedOption: function(){
+ return this._getSelectedAttr();
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/_DateTimeTextBox.js b/js/dojo/dijit/form/_DateTimeTextBox.js
new file mode 100644
index 0000000..fd55588
--- /dev/null
+++ b/js/dojo/dijit/form/_DateTimeTextBox.js
@@ -0,0 +1,263 @@
+//>>built
+require({cache:{
+'url:dijit/form/templates/DropDownBox.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\"\n\tid=\"widget_${id}\"\n\trole=\"combobox\"\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\n\t\tdata-dojo-attach-point=\"_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\tdata-dojo-attach-point=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\n\t/></div\n></div>\n"}});
+define("dijit/form/_DateTimeTextBox", [
+ "dojo/date", // date date.compare
+ "dojo/date/locale", // locale.regexp
+ "dojo/date/stamp", // stamp.fromISOString stamp.toISOString
+ "dojo/_base/declare", // declare
+ "dojo/_base/lang", // lang.getObject
+ "./RangeBoundTextBox",
+ "../_HasDropDown",
+ "dojo/text!./templates/DropDownBox.html"
+], function(date, locale, stamp, declare, lang, RangeBoundTextBox, _HasDropDown, template){
+
+/*=====
+ var _HasDropDown = dijit._HasDropDown;
+ var RangeBoundTextBox = dijit.form.RangeBoundTextBox;
+=====*/
+
+ // module:
+ // dijit/form/_DateTimeTextBox
+ // summary:
+ // Base class for validating, serializable, range-bound date or time text box.
+
+
+ new Date("X"); // workaround for #11279, new Date("") == NaN
+
+ /*=====
+ declare(
+ "dijit.form._DateTimeTextBox.__Constraints",
+ [RangeBoundTextBox.__Constraints, 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'}
+ });
+ =====*/
+
+ var _DateTimeTextBox = declare("dijit.form._DateTimeTextBox", [RangeBoundTextBox, _HasDropDown], {
+ // summary:
+ // Base class for validating, serializable, range-bound date or time text box.
+
+ templateString: template,
+
+ // 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: locale.regexp,
+
+ // datePackage: String
+ // JavaScript namespace to find calendar routines. Uses Gregorian calendar routines
+ // at dojo.date, by default.
+ datePackage: date,
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this._set("type", "text"); // in case type="date"|"time" was specified which messes up parse/format
+ },
+
+ // 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 : 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 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){
+ this.datePackage = args.datePackage || this.datePackage;
+ this.dateFuncObj = typeof this.datePackage == "string" ?
+ lang.getObject(this.datePackage, false) :// "string" part for back-compat, remove for 2.0
+ this.datePackage;
+ this.dateClassObj = this.dateFuncObj.Date || Date;
+ this.dateLocaleModule = lang.getObject("locale", false, this.dateFuncObj);
+ this.regExpGen = this.dateLocaleModule.regexp;
+ this._invalidDate = this.constructor.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 = 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 = 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.value instanceof Date){
+ this.filterString = "";
+ }
+ 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 = lang.isString(this.popupClass) ? lang.getObject(this.popupClass, false) : this.popupClass,
+ 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
+ textBox.set('value', 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);
+ }
+ });
+
+ return _DateTimeTextBox;
+});
diff --git a/js/dojo/dijit/form/_ExpandingTextAreaMixin.js b/js/dojo/dijit/form/_ExpandingTextAreaMixin.js
new file mode 100644
index 0000000..bf4b82e
--- /dev/null
+++ b/js/dojo/dijit/form/_ExpandingTextAreaMixin.js
@@ -0,0 +1,122 @@
+//>>built
+define("dijit/form/_ExpandingTextAreaMixin", [
+ "dojo/_base/declare", // declare
+ "dojo/dom-construct", // domConstruct.create
+ "dojo/_base/lang", // lang.hitch
+ "dojo/_base/window" // win.body
+], function(declare, domConstruct, lang, win){
+
+ // module:
+ // dijit/form/_ExpandingTextAreaMixin
+ // summary:
+ // Mixin for textarea widgets to add auto-expanding capability
+
+ // feature detection
+ var needsHelpShrinking;
+
+ return declare("dijit.form._ExpandingTextAreaMixin", null, {
+ // summary:
+ // Mixin for textarea widgets to add auto-expanding capability
+
+ _setValueAttr: function(){
+ this.inherited(arguments);
+ this.resize();
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ var textarea = this.textbox;
+
+ if(needsHelpShrinking == undefined){
+ var te = domConstruct.create('textarea', {rows:"5", cols:"20", value: ' ', style: {zoom:1, overflow:'hidden', visibility:'hidden', position:'absolute', border:"0px solid black", padding:"0px"}}, win.body(), "last");
+ needsHelpShrinking = te.scrollHeight >= te.clientHeight;
+ win.body().removeChild(te);
+ }
+ this.connect(textarea, "onscroll", "_resizeLater");
+ this.connect(textarea, "onresize", "_resizeLater");
+ this.connect(textarea, "onfocus", "_resizeLater");
+ textarea.style.overflowY = "hidden";
+ this._estimateHeight();
+ this._resizeLater();
+ },
+
+ _onInput: function(e){
+ this.inherited(arguments);
+ this.resize();
+ },
+
+ _estimateHeight: function(){
+ // 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.
+ //
+ var textarea = this.textbox;
+ 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 + 2;
+ },
+
+ _resizeLater: function(){
+ setTimeout(lang.hitch(this, "resize"), 0);
+ },
+
+ resize: function(){
+ // summary:
+ // Resizes the textarea vertically (should be called after a style/value change)
+ function textareaScrollHeight(){
+ var empty = false;
+ if(textarea.value === ''){
+ textarea.value = ' ';
+ empty = true;
+ }
+ var sh = textarea.scrollHeight;
+ if(empty){ textarea.value = ''; }
+ return sh;
+ }
+
+ var textarea = this.textbox;
+ if(textarea.style.overflowY == "hidden"){ textarea.scrollTop = 0; }
+ if(this.resizeTimer){ clearTimeout(this.resizeTimer); }
+ this.resizeTimer = null;
+ if(this.busyResizing){ return; }
+ this.busyResizing = true;
+ if(textareaScrollHeight() || textarea.offsetHeight){
+ var currentHeight = textarea.style.height;
+ if(!(/px/.test(currentHeight))){
+ currentHeight = textareaScrollHeight();
+ textarea.rows = 1;
+ textarea.style.height = currentHeight + "px";
+ }
+ var newH = Math.max(parseInt(currentHeight) - textarea.clientHeight, 0) + textareaScrollHeight();
+ var newHpx = newH + "px";
+ if(newHpx != textarea.style.height){
+ textarea.rows = 1;
+ textarea.style.height = newHpx;
+ }
+ if(needsHelpShrinking){
+ var scrollHeight = textareaScrollHeight();
+ textarea.style.height = "auto";
+ if(textareaScrollHeight() < scrollHeight){ // scrollHeight can shrink so now try a larger value
+ newHpx = newH - scrollHeight + textareaScrollHeight() + "px";
+ }
+ textarea.style.height = newHpx;
+ }
+ textarea.style.overflowY = textareaScrollHeight() > textarea.clientHeight ? "auto" : "hidden";
+ }else{
+ // hidden content of unknown size
+ this._estimateHeight();
+ }
+ this.busyResizing = false;
+ },
+
+ destroy: function(){
+ if(this.resizeTimer){ clearTimeout(this.resizeTimer); }
+ if(this.shrinkTimer){ clearTimeout(this.shrinkTimer); }
+ this.inherited(arguments);
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/_FormMixin.js b/js/dojo/dijit/form/_FormMixin.js
new file mode 100644
index 0000000..3647d1a
--- /dev/null
+++ b/js/dojo/dijit/form/_FormMixin.js
@@ -0,0 +1,476 @@
+//>>built
+define("dijit/form/_FormMixin", [
+ "dojo/_base/array", // array.every array.filter array.forEach array.indexOf array.map
+ "dojo/_base/declare", // declare
+ "dojo/_base/kernel", // kernel.deprecated
+ "dojo/_base/lang", // lang.hitch lang.isArray
+ "dojo/window" // winUtils.scrollIntoView
+], function(array, declare, kernel, lang, winUtils){
+
+ // module:
+ // dijit/form/_FormMixin
+ // 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)
+
+ return 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}, ...])
+ //
+ //
+
+ _getDescendantFormWidgets: function(/*dijit._WidgetBase[]?*/ children){
+ // summary:
+ // Returns all form widget descendants, searching through non-form child widgets like BorderContainer
+ var res = [];
+ array.forEach(children || this.getChildren(), function(child){
+ if("value" in child){
+ res.push(child);
+ }else{
+ res = res.concat(this._getDescendantFormWidgets(child.getChildren()));
+ }
+ }, this);
+ return res;
+ },
+
+ reset: function(){
+ array.forEach(this._getDescendantFormWidgets(), 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 array.every(array.map(this._getDescendantFormWidgets(), 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
+ winUtils.scrollIntoView(widget.containerNode || widget.domNode);
+ widget.focus();
+ didFocus = true;
+ }
+ return valid;
+ }), function(item){ return item; });
+ },
+
+ setValues: function(val){
+ kernel.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 = { };
+ array.forEach(this._getDescendantFormWidgets(), 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 = lang.getObject(name, false, obj); // list of values for those widgets
+
+ if(values === undefined){
+ continue;
+ }
+ if(!lang.isArray(values)){
+ values = [ values ];
+ }
+ if(typeof widgets[0].checked == 'boolean'){
+ // for checkbox/radio, values is a list of which widgets should be checked
+ array.forEach(widgets, function(w){
+ w.set('value', array.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
+ array.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)
+
+ array.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) &&
+ array.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;
+ array.forEach(element.options, function(option){
+ option.selected = array.some(myObj[name], function(val){ return option.value == val; });
+ });
+ break;
+ case "select-one":
+ element.selectedIndex="0";
+ array.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(){
+ kernel.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 setTimeout(..., 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 = { };
+ array.forEach(this._getDescendantFormWidgets(), 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){
+ lang.setObject(name, value, obj);
+ }else{
+ // give radio widgets a default of null
+ value = lang.getObject(name, false, obj);
+ if(value === undefined){
+ lang.setObject(name, null, obj);
+ }
+ }
+ }else{
+ // checkbox/toggle button
+ var ary=lang.getObject(name, false, obj);
+ if(!ary){
+ ary=[];
+ lang.setObject(name, ary, obj);
+ }
+ if(value !== false){
+ ary.push(value);
+ }
+ }
+ }else{
+ var prev=lang.getObject(name, false, obj);
+ if(typeof prev != "undefined"){
+ if(lang.isArray(prev)){
+ prev.push(value);
+ }else{
+ lang.setObject(name, [prev, value], obj);
+ }
+ }else{
+ // unique name
+ lang.setObject(name, value, obj);
+ }
+ }
+ });
+
+ /***
+ * code for plain input boxes (see also domForm.formToObject, can we use that instead of this code?
+ * but it doesn't understand [] notation, presumably)
+ var obj = { };
+ array.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(/*Boolean*/ /*===== 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 = array.map(this._descendants, function(w){
+ return w.get("state") || "";
+ });
+
+ return array.indexOf(states, "Error") >= 0 ? "Error" :
+ array.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.
+ array.forEach(this._childConnections || [], lang.hitch(this, "disconnect"));
+ array.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._getDescendantFormWidgets();
+
+ // (Re)set this.value and this.state. Send watch() notifications but not on startup.
+ var set = inStartup ? function(name, val){ _this[name] = val; } : lang.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 = []);
+ array.forEach(array.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.
+ array.forEach(["state", "disabled"], function(attr){
+ watches.push(widget.watch(attr, function(){
+ _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);
+ };
+ array.forEach(
+ array.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/js/dojo/dijit/form/_FormSelectWidget.js b/js/dojo/dijit/form/_FormSelectWidget.js
new file mode 100644
index 0000000..8fc94a9
--- /dev/null
+++ b/js/dojo/dijit/form/_FormSelectWidget.js
@@ -0,0 +1,596 @@
+//>>built
+define("dijit/form/_FormSelectWidget", [
+ "dojo/_base/array", // array.filter array.forEach array.map array.some
+ "dojo/aspect", // aspect.after
+ "dojo/data/util/sorter", // util.sorter.createSortFunction
+ "dojo/_base/declare", // declare
+ "dojo/dom", // dom.setSelectable
+ "dojo/dom-class", // domClass.toggle
+ "dojo/_base/kernel", // _scopeName
+ "dojo/_base/lang", // lang.delegate lang.isArray lang.isObject lang.hitch
+ "dojo/query", // query
+ "./_FormValueWidget"
+], function(array, aspect, sorter, declare, dom, domClass, kernel, lang, query, _FormValueWidget){
+
+/*=====
+ var _FormValueWidget = dijit.form._FormValueWidget;
+=====*/
+
+// module:
+// dijit/form/_FormSelectWidget
+// summary:
+// Extends _FormValueWidget in order to provide "select-specific"
+// values - i.e., those values that are unique to <select> elements.
+
+
+/*=====
+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;
+}
+=====*/
+
+return declare("dijit.form._FormSelectWidget", _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 implements 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 further 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(lang.isArray(lookupValue)){
+ return array.map(lookupValue, "return this.getOptions(item);", this); // dijit.form.__SelectOption[]
+ }
+ if(lang.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(!array.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(!lang.isArray(option)){ option = [option]; }
+ array.forEach(option, function(i){
+ if(i && lang.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(!lang.isArray(valueOrIdx)){ valueOrIdx = [valueOrIdx]; }
+ var oldOpts = this.getOptions(valueOrIdx);
+ array.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 = array.filter(this.options, function(node){
+ 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 yield better performance since
+ // the children will only be loaded once.
+ if(!lang.isArray(newOption)){ newOption = [newOption]; }
+ array.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 dojo.data.api.Identity,
+ // and MAY implement dojo.data.api.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
+ var h;
+ while(h = this._notifyConnections.pop()){ h.remove(); }
+
+ if(store && store.getFeatures()["dojo.data.api.Notification"]){
+ this._notifyConnections = [
+ aspect.after(store, "onNew", lang.hitch(this, "_onNewItem"), true),
+ aspect.after(store, "onDelete", lang.hitch(this, "_onDeleteItem"), true),
+ aspect.after(store, "onSet", lang.hitch(this, "_onSetItem"), true)
+ ];
+ }
+ 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(lang.delegate(fetchArgs, {
+ onComplete: function(items, opts){
+ if(this.sortByLabel && !fetchArgs.sort && items.length){
+ items.sort(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
+ array.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(!lang.isArray(newValue)){
+ newValue = [newValue];
+ }
+ array.forEach(newValue, function(i, idx){
+ if(!lang.isObject(i)){
+ i = i + "";
+ }
+ if(typeof i === "string"){
+ newValue[idx] = array.filter(opts, function(node){
+ return node.value === i;
+ })[0] || {value: "", label: ""};
+ }
+ }, this);
+
+ // Make sure some sane default is set
+ newValue = array.filter(newValue, function(i){ return i && i.value; });
+ if(!this.multiple && (!newValue[0] || !newValue[0].value) && opts.length){
+ newValue[0] = opts[0];
+ }
+ array.forEach(opts, function(i){
+ i.selected = array.some(newValue, function(v){ return v.value === i.value; });
+ });
+ var val = array.map(newValue, function(i){ return i.value; }),
+ disp = array.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(!lang.isArray(val)){
+ val = [val];
+ }
+ var ret = array.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; }
+ array.forEach(this._getChildren(), function(child){
+ child.destroyRecursive();
+ });
+ // Add each menu item
+ array.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(!lang.isArray(val)){
+ val = [val];
+ }
+ if(val && val[0]){
+ array.forEach(this._getChildren(), function(child){
+ var isSelected = array.some(val, function(v){
+ return child.option && (v === child.option.value);
+ });
+ domClass.toggle(child.domNode, this.baseClass + "SelectedOption", isSelected);
+ child.domNode.setAttribute("aria-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 = array.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 array.map(array.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, onItem: function(i){
+ this._addOptionForItem(i);
+ },
+ 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;
+ this._notifyConnections = [];
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dom.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 ? query("> *",
+ this.srcNodeRef).map(function(node){
+ if(node.getAttribute("type") === "separator"){
+ return { value: "", label: "", selected: false, disabled: false };
+ }
+ return {
+ value: (node.getAttribute("data-" + kernel._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 = {};
+ array.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
+ var h;
+ while(h = this._notifyConnections.pop()){ h.remove(); }
+ 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
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/_FormValueMixin.js b/js/dojo/dijit/form/_FormValueMixin.js
new file mode 100644
index 0000000..f19ab2e
--- /dev/null
+++ b/js/dojo/dijit/form/_FormValueMixin.js
@@ -0,0 +1,96 @@
+//>>built
+define("dijit/form/_FormValueMixin", [
+ "dojo/_base/declare", // declare
+ "dojo/dom-attr", // domAttr.set
+ "dojo/keys", // keys.ESCAPE
+ "dojo/_base/sniff", // has("ie"), has("quirks")
+ "./_FormWidgetMixin"
+], function(declare, domAttr, keys, has, _FormWidgetMixin){
+
+/*=====
+ var _FormWidgetMixin = dijit.form._FormWidgetMixin;
+=====*/
+
+ // module:
+ // dijit/form/_FormValueMixin
+ // summary:
+ // Mixin for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values.
+
+ return declare("dijit.form._FormValueMixin", _FormWidgetMixin, {
+ // summary:
+ // Mixin for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values.
+ // description:
+ // Each _FormValueMixin 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.
+
+ // 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,
+
+ _setReadOnlyAttr: function(/*Boolean*/ value){
+ domAttr.set(this.focusNode, 'readOnly', value);
+ this.focusNode.setAttribute("aria-readonly", value);
+ this._set("readOnly", value);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ if(has("ie")){ // 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 == keys.ESCAPE && !(e.ctrlKey || e.altKey || e.metaKey)){
+ var te;
+ if(has("ie") < 9 || (has("ie") && has("quirks"))){
+ e.preventDefault(); // default behavior needs to be stopped here since keypress is too late
+ te = document.createEventObject();
+ te.keyCode = keys.ESCAPE;
+ te.shiftKey = e.shiftKey;
+ e.srcElement.fireEvent('onkeypress', te);
+ }
+ }
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/_FormValueWidget.js b/js/dojo/dijit/form/_FormValueWidget.js
new file mode 100644
index 0000000..be82fe2
--- /dev/null
+++ b/js/dojo/dijit/form/_FormValueWidget.js
@@ -0,0 +1,59 @@
+//>>built
+define("dijit/form/_FormValueWidget", [
+ "dojo/_base/declare", // declare
+ "dojo/_base/sniff", // has("ie")
+ "./_FormWidget",
+ "./_FormValueMixin"
+], function(declare, has, _FormWidget, _FormValueMixin){
+
+/*=====
+var _FormWidget = dijit.form._FormWidget;
+var _FormValueMixin = dijit.form._FormValueMixin;
+=====*/
+
+// module:
+// dijit/form/_FormValueWidget
+// summary:
+// FormValueWidget
+
+
+return declare("dijit.form._FormValueWidget", [_FormWidget, _FormValueMixin],
+{
+ // 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.
+
+ _layoutHackIE7: function(){
+ // summary:
+ // Work around table sizing bugs on IE7 by forcing redraw
+
+ if(has("ie") == 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(){
+ _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;
+ }
+ }
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/_FormWidget.js b/js/dojo/dijit/form/_FormWidget.js
new file mode 100644
index 0000000..add8fb8
--- /dev/null
+++ b/js/dojo/dijit/form/_FormWidget.js
@@ -0,0 +1,80 @@
+//>>built
+define("dijit/form/_FormWidget", [
+ "dojo/_base/declare", // declare
+ "dojo/_base/kernel", // kernel.deprecated
+ "dojo/ready",
+ "../_Widget",
+ "../_CssStateMixin",
+ "../_TemplatedMixin",
+ "./_FormWidgetMixin"
+], function(declare, kernel, ready, _Widget, _CssStateMixin, _TemplatedMixin, _FormWidgetMixin){
+
+/*=====
+var _Widget = dijit._Widget;
+var _TemplatedMixin = dijit._TemplatedMixin;
+var _CssStateMixin = dijit._CssStateMixin;
+var _FormWidgetMixin = dijit.form._FormWidgetMixin;
+=====*/
+
+// module:
+// dijit/form/_FormWidget
+// summary:
+// FormWidget
+
+
+// Back compat w/1.6, remove for 2.0
+if(!kernel.isAsync){
+ ready(0, function(){
+ var requires = ["dijit/form/_FormValueWidget"];
+ require(requires); // use indirection so modules not rolled into a build
+ });
+}
+
+return declare("dijit.form._FormWidget", [_Widget, _TemplatedMixin, _CssStateMixin, _FormWidgetMixin], {
+ // 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.
+
+ setDisabled: function(/*Boolean*/ disabled){
+ // summary:
+ // Deprecated. Use set('disabled', ...) instead.
+ kernel.deprecated("setDisabled("+disabled+") is deprecated. Use set('disabled',"+disabled+") instead.", "", "2.0");
+ this.set('disabled', disabled);
+ },
+
+ setValue: function(/*String*/ value){
+ // summary:
+ // Deprecated. Use set('value', ...) instead.
+ kernel.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.
+ kernel.deprecated(this.declaredClass+"::getValue() is deprecated. Use get('value') instead.", "", "2.0");
+ return this.get('value');
+ },
+
+ 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 _setNameAttr to set the name due to IE limitations, see #8484, #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);
+ },
+
+ // Override automatic assigning type --> focusNode, it causes exception on IE.
+ // Instead, type must be specified as ${type} in the template, as part of the original DOM
+ _setTypeAttr: null
+});
+
+});
diff --git a/js/dojo/dijit/form/_FormWidgetMixin.js b/js/dojo/dijit/form/_FormWidgetMixin.js
new file mode 100644
index 0000000..6e49426
--- /dev/null
+++ b/js/dojo/dijit/form/_FormWidgetMixin.js
@@ -0,0 +1,232 @@
+//>>built
+define("dijit/form/_FormWidgetMixin", [
+ "dojo/_base/array", // array.forEach
+ "dojo/_base/declare", // declare
+ "dojo/dom-attr", // domAttr.set
+ "dojo/dom-style", // domStyle.get
+ "dojo/_base/lang", // lang.hitch lang.isArray
+ "dojo/mouse", // mouse.isLeft
+ "dojo/_base/sniff", // has("webkit")
+ "dojo/_base/window", // win.body
+ "dojo/window", // winUtils.scrollIntoView
+ "../a11y" // a11y.hasDefaultTabStop
+], function(array, declare, domAttr, domStyle, lang, mouse, has, win, winUtils, a11y){
+
+// module:
+// dijit/form/_FormWidgetMixin
+// summary:
+// Mixin 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.
+
+return declare("dijit.form._FormWidgetMixin", null, {
+ // summary:
+ // Mixin 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: [const] 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",
+ _setTabIndexAttr: "focusNode", // force copy even when tabIndex default value, needed since Button is <span>
+
+ // 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,
+
+ // Override _WidgetBase mapping id to this.domNode, needs to be on focusNode so <label> etc.
+ // works with screen reader
+ _setIdAttr: "focusNode",
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.connect(this.domNode, "onmousedown", "_onMouseDown");
+ },
+
+ _setDisabledAttr: function(/*Boolean*/ value){
+ this._set("disabled", value);
+ domAttr.set(this.focusNode, 'disabled', value);
+ if(this.valueNode){
+ domAttr.set(this.valueNode, 'disabled', value);
+ }
+ this.focusNode.setAttribute("aria-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 :
+ ("_setTabIndexAttr" in this) ? this._setTabIndexAttr : "focusNode";
+ array.forEach(lang.isArray(attachPointNames) ? attachPointNames : [attachPointNames], function(attachPointName){
+ var node = this[attachPointName];
+ // complex code because tabIndex=-1 on a <div> doesn't work on FF
+ if(has("webkit") || a11y.hasDefaultTabStop(node)){ // see #11064 about webkit bug
+ node.setAttribute('tabIndex', "-1");
+ }else{
+ node.removeAttribute('tabIndex');
+ }
+ }, this);
+ }else{
+ if(this.tabIndex != ""){
+ this.set('tabIndex', this.tabIndex);
+ }
+ }
+ },
+
+ _onFocus: function(e){
+ if(this.scrollOnFocus){
+ winUtils.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 && (domStyle.get(this.domNode, "display") != "none");
+ },
+
+ focus: function(){
+ // summary:
+ // Put focus on this widget
+ if(!this.disabled && this.focusNode.focus){
+ try{ this.focusNode.focus(); }catch(e){}/*squelch errors from hidden nodes*/
+ }
+ },
+
+ 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);
+ }
+ // setTimeout allows hidden value processing to run and
+ // also the onChange handler can safely adjust focus, etc
+ this._onChangeHandle = setTimeout(lang.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);
+ },
+
+ _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.
+ // IE exhibits strange scrolling behavior when focusing a node so only do it when !focused.
+ // FF needs the extra help to make sure the mousedown actually gets to the focusNode
+ if((!this.focused || !has("ie")) && !e.ctrlKey && mouse.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(win.body(), "onmouseup", function(){
+ if(this.isFocusable()){
+ this.focus();
+ }
+ this.disconnect(mouseUpConnector);
+ });
+ }
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/_ListBase.js b/js/dojo/dijit/form/_ListBase.js
new file mode 100644
index 0000000..eaa9826
--- /dev/null
+++ b/js/dojo/dijit/form/_ListBase.js
@@ -0,0 +1,124 @@
+//>>built
+define("dijit/form/_ListBase", [
+ "dojo/_base/declare", // declare
+ "dojo/window" // winUtils.scrollIntoView
+], function(declare, winUtils){
+
+// module:
+// dijit/form/_ListBase
+// summary:
+// Focus-less menu to handle UI events consistently
+
+return declare( "dijit.form._ListBase", null, {
+ // summary:
+ // Focus-less menu to handle UI events consistently
+ // Abstract methods that must be defined externally:
+ // onSelect: item is active (mousedown but not yet mouseup, or keyboard arrow selected but no Enter)
+ // onDeselect: cancels onSelect
+ // tags:
+ // private
+
+ // selected: DOMnode
+ // currently selected node
+ selected: null,
+
+ _getTarget: function(/*Event*/ evt){
+ var tgt = evt.target;
+ var container = this.containerNode;
+ if(tgt == container || tgt == this.domNode){ return null; }
+ while(tgt && tgt.parentNode != container){
+ // recurse to the top
+ tgt = tgt.parentNode;
+ }
+ return tgt;
+ },
+
+ selectFirstNode: function(){
+ // summary:
+ // Select the first displayed item in the list.
+ var first = this.containerNode.firstChild;
+ while(first && first.style.display == "none"){
+ first = first.nextSibling;
+ }
+ this._setSelectedAttr(first);
+ },
+
+ selectLastNode: function(){
+ // summary:
+ // Select the last displayed item in the list
+ var last = this.containerNode.lastChild;
+ while(last && last.style.display == "none"){
+ last = last.previousSibling;
+ }
+ this._setSelectedAttr(last);
+ },
+
+ selectNextNode: function(){
+ // summary:
+ // Select the item just below the current selection.
+ // If nothing selected, select first node.
+ var selectedNode = this._getSelectedAttr();
+ if(!selectedNode){
+ this.selectFirstNode();
+ }else{
+ var next = selectedNode.nextSibling;
+ while(next && next.style.display == "none"){
+ next = next.nextSibling;
+ }
+ if(!next){
+ this.selectFirstNode();
+ }else{
+ this._setSelectedAttr(next);
+ }
+ }
+ },
+
+ selectPreviousNode: function(){
+ // summary:
+ // Select the item just above the current selection.
+ // If nothing selected, select last node (if
+ // you select Previous and try to keep scrolling up the list).
+ var selectedNode = this._getSelectedAttr();
+ if(!selectedNode){
+ this.selectLastNode();
+ }else{
+ var prev = selectedNode.previousSibling;
+ while(prev && prev.style.display == "none"){
+ prev = prev.previousSibling;
+ }
+ if(!prev){
+ this.selectLastNode();
+ }else{
+ this._setSelectedAttr(prev);
+ }
+ }
+ },
+
+ _setSelectedAttr: function(/*DomNode*/ node){
+ // summary:
+ // Does the actual select.
+ if(this.selected != node){
+ var selectedNode = this._getSelectedAttr();
+ if(selectedNode){
+ this.onDeselect(selectedNode);
+ this.selected = null;
+ }
+ if(node && node.parentNode == this.containerNode){
+ this.selected = node;
+ winUtils.scrollIntoView(node);
+ this.onSelect(node);
+ }
+ }else if(node){
+ this.onSelect(node);
+ }
+ },
+
+ _getSelectedAttr: function(){
+ // summary:
+ // Returns the selected node.
+ var v = this.selected;
+ return (v && v.parentNode == this.containerNode) ? v : (this.selected = null);
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/_ListMouseMixin.js b/js/dojo/dijit/form/_ListMouseMixin.js
new file mode 100644
index 0000000..262eed9
--- /dev/null
+++ b/js/dojo/dijit/form/_ListMouseMixin.js
@@ -0,0 +1,97 @@
+//>>built
+define("dijit/form/_ListMouseMixin", [
+ "dojo/_base/declare", // declare
+ "dojo/_base/event", // event.stop
+ "dojo/touch",
+ "./_ListBase"
+], function(declare, event, touch, _ListBase){
+
+/*=====
+var _ListBase = dijit.form._ListBase;
+=====*/
+
+// module:
+// dijit/form/_ListMouseMixin
+// summary:
+// a mixin to handle mouse or touch events for a focus-less menu
+
+return declare( "dijit.form._ListMouseMixin", _ListBase, {
+ // summary:
+ // a Mixin to handle mouse or touch events for a focus-less menu
+ // Abstract methods that must be defined externally:
+ // onClick: item was chosen (mousedown somewhere on the menu and mouseup somewhere on the menu)
+ // tags:
+ // private
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.connect(this.domNode, touch.press, "_onMouseDown");
+ this.connect(this.domNode, touch.release, "_onMouseUp");
+ this.connect(this.domNode, "onmouseover", "_onMouseOver");
+ this.connect(this.domNode, "onmouseout", "_onMouseOut");
+ },
+
+ _onMouseDown: function(/*Event*/ evt){
+ event.stop(evt);
+ if(this._hoveredNode){
+ this.onUnhover(this._hoveredNode);
+ this._hoveredNode = null;
+ }
+ this._isDragging = true;
+ this._setSelectedAttr(this._getTarget(evt));
+ },
+
+ _onMouseUp: function(/*Event*/ evt){
+ event.stop(evt);
+ this._isDragging = false;
+ var selectedNode = this._getSelectedAttr();
+ var target = this._getTarget(evt);
+ var hoveredNode = this._hoveredNode;
+ if(selectedNode && target == selectedNode){
+ this.onClick(selectedNode);
+ }else if(hoveredNode && target == hoveredNode){ // drag to select
+ this._setSelectedAttr(hoveredNode);
+ this.onClick(hoveredNode);
+ }
+ },
+
+ _onMouseOut: function(/*Event*/ /*===== evt ====*/){
+ if(this._hoveredNode){
+ this.onUnhover(this._hoveredNode);
+ if(this._getSelectedAttr() == this._hoveredNode){
+ this.onSelect(this._hoveredNode);
+ }
+ this._hoveredNode = null;
+ }
+ if(this._isDragging){
+ this._cancelDrag = (new Date()).getTime() + 1000; // cancel in 1 second if no _onMouseOver fires
+ }
+ },
+
+ _onMouseOver: function(/*Event*/ evt){
+ if(this._cancelDrag){
+ var time = (new Date()).getTime();
+ if(time > this._cancelDrag){
+ this._isDragging = false;
+ }
+ this._cancelDrag = null;
+ }
+ var node = this._getTarget(evt);
+ if(!node){ return; }
+ if(this._hoveredNode != node){
+ if(this._hoveredNode){
+ this._onMouseOut({ target: this._hoveredNode });
+ }
+ if(node && node.parentNode == this.containerNode){
+ if(this._isDragging){
+ this._setSelectedAttr(node);
+ }else{
+ this._hoveredNode = node;
+ this.onHover(node);
+ }
+ }
+ }
+ }
+});
+
+});
diff --git a/js/dojo/dijit/form/_RadioButtonMixin.js b/js/dojo/dijit/form/_RadioButtonMixin.js
new file mode 100644
index 0000000..0690383
--- /dev/null
+++ b/js/dojo/dijit/form/_RadioButtonMixin.js
@@ -0,0 +1,71 @@
+//>>built
+define("dijit/form/_RadioButtonMixin", [
+ "dojo/_base/array", // array.forEach
+ "dojo/_base/declare", // declare
+ "dojo/dom-attr", // domAttr.set
+ "dojo/_base/event", // event.stop
+ "dojo/_base/lang", // lang.hitch
+ "dojo/query", // query
+ "dojo/_base/window", // win.doc
+ "../registry" // registry.getEnclosingWidget
+], function(array, declare, domAttr, event, lang, query, win, registry){
+
+ // module:
+ // dijit/form/_RadioButtonMixin
+ // summary:
+ // Mixin to provide widget functionality for an HTML radio button
+
+ return declare("dijit.form._RadioButtonMixin", null, {
+ // summary:
+ // Mixin to provide widget functionality for an HTML radio button
+
+ // type: [private] String
+ // type attribute on <input> node.
+ // Users should not change this value.
+ type: "radio",
+
+ _getRelatedWidgets: function(){
+ // Private function needed to help iterate over all radio buttons in a group.
+ var ary = [];
+ query("input[type=radio]", this.focusNode.form || win.doc).forEach( // can't use name= since query doesn't support [] in the name
+ lang.hitch(this, function(inputNode){
+ if(inputNode.name == this.name && inputNode.form == this.focusNode.form){
+ var widget = registry.getEnclosingWidget(inputNode);
+ if(widget){
+ ary.push(widget);
+ }
+ }
+ })
+ );
+ return ary;
+ },
+
+ _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){
+ array.forEach(this._getRelatedWidgets(), lang.hitch(this, function(widget){
+ if(widget != this && widget.checked){
+ widget.set('checked', false);
+ }
+ }));
+ }
+ },
+
+ _onClick: function(/*Event*/ e){
+ if(this.checked || this.disabled){ // nothing to do
+ event.stop(e);
+ return false;
+ }
+ if(this.readOnly){ // ignored by some browsers so we have to resync the DOM elements with widget values
+ event.stop(e);
+ array.forEach(this._getRelatedWidgets(), lang.hitch(this, function(widget){
+ domAttr.set(this.focusNode || this.domNode, 'checked', widget.checked);
+ }));
+ return false;
+ }
+ return this.inherited(arguments);
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/_Spinner.js b/js/dojo/dijit/form/_Spinner.js
new file mode 100644
index 0000000..9dcab8c
--- /dev/null
+++ b/js/dojo/dijit/form/_Spinner.js
@@ -0,0 +1,142 @@
+//>>built
+require({cache:{
+'url:dijit/form/templates/Spinner.html':"<div class=\"dijit dijitReset dijitInline 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\tdata-dojo-attach-point=\"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\tdata-dojo-attach-point=\"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' data-dojo-attach-point=\"textbox,focusNode\" type=\"${type}\" data-dojo-attach-event=\"onkeypress:_onKeyPress\"\n\t\t\trole=\"spinbutton\" autocomplete=\"off\" ${!nameAttrSetting}\n\t/></div\n></div>\n"}});
+define("dijit/form/_Spinner", [
+ "dojo/_base/declare", // declare
+ "dojo/_base/event", // event.stop
+ "dojo/keys", // keys keys.DOWN_ARROW keys.PAGE_DOWN keys.PAGE_UP keys.UP_ARROW
+ "dojo/_base/lang", // lang.hitch
+ "dojo/_base/sniff", // has("mozilla")
+ "dijit/typematic",
+ "./RangeBoundTextBox",
+ "dojo/text!./templates/Spinner.html",
+ "./_TextBoxMixin" // selectInputText
+], function(declare, event, keys, lang, has, typematic, RangeBoundTextBox, template, _TextBoxMixin){
+
+/*=====
+ var RangeBoundTextBox = dijit.form.RangeBoundTextBox;
+=====*/
+
+ // module:
+ // dijit/form/_Spinner
+ // summary:
+ // Mixin for validation widgets with a spinner.
+
+
+ return declare("dijit.form._Spinner", 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: template,
+
+ baseClass: "dijitTextBox dijitSpinner",
+
+ // Set classes like dijitUpArrowButtonHover or dijitDownArrowButtonActive depending on
+ // mouse action over specified node
+ cssStateNodes: {
+ "upArrowNode": "dijitUpArrowButton",
+ "downArrowNode": "dijitDownArrowButton"
+ },
+
+ adjust: function(val /*=====, 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.
+ // val: Object
+ // delta: Number
+ // 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);
+ _TextBoxMixin.selectInputText(this.textbox, this.textbox.value.length);
+ },
+
+ _arrowReleased: function(/*Node*/ /*===== node =====*/){
+ // summary:
+ // Handler for arrow button or arrow key being released
+ this._wheelTimer = null;
+ },
+
+ _typematicCallback: function(/*Number*/ count, /*DOMNode*/ node, /*Event*/ evt){
+ var inc=this.smallDelta;
+ if(node == this.textbox){
+ var key = evt.charOrCode;
+ inc = (key == keys.PAGE_UP || key == keys.PAGE_DOWN) ? this.largeDelta : this.smallDelta;
+ node = (key == keys.UP_ARROW || key == keys.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
+
+ event.stop(evt);
+ // FIXME: Safari bubbles
+
+ // be nice to DOH and scroll as much as the event says to
+ var wheelDelta = evt.wheelDelta / 120;
+ if(Math.floor(wheelDelta) != wheelDelta){
+ // If not an int multiple of 120, then its touchpad scrolling.
+ // This can change very fast so just assume 1 wheel click to make it more manageable.
+ wheelDelta = evt.wheelDelta > 0 ? 1 : -1;
+ }
+ var scrollAmount = evt.detail ? (evt.detail * -1) : wheelDelta;
+ 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(lang.hitch(this,"_arrowReleased",node), 50);
+ }
+
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // extra listeners
+ this.connect(this.domNode, !has("mozilla") ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled");
+ this._connects.push(typematic.addListener(this.upArrowNode, this.textbox, {charOrCode:keys.UP_ARROW,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
+ this._connects.push(typematic.addListener(this.downArrowNode, this.textbox, {charOrCode:keys.DOWN_ARROW,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
+ this._connects.push(typematic.addListener(this.upArrowNode, this.textbox, {charOrCode:keys.PAGE_UP,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
+ this._connects.push(typematic.addListener(this.downArrowNode, this.textbox, {charOrCode:keys.PAGE_DOWN,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
+ }
+ });
+});
diff --git a/js/dojo/dijit/form/_TextBoxMixin.js b/js/dojo/dijit/form/_TextBoxMixin.js
new file mode 100644
index 0000000..2135af6
--- /dev/null
+++ b/js/dojo/dijit/form/_TextBoxMixin.js
@@ -0,0 +1,409 @@
+//>>built
+define("dijit/form/_TextBoxMixin", [
+ "dojo/_base/array", // array.forEach
+ "dojo/_base/declare", // declare
+ "dojo/dom", // dom.byId
+ "dojo/_base/event", // event.stop
+ "dojo/keys", // keys.ALT keys.CAPS_LOCK keys.CTRL keys.META keys.SHIFT
+ "dojo/_base/lang", // lang.mixin
+ ".." // for exporting dijit._setSelectionRange, dijit.selectInputText
+], function(array, declare, dom, event, keys, lang, dijit){
+
+// module:
+// dijit/form/_TextBoxMixin
+// summary:
+// A mixin for textbox form input widgets
+
+var _TextBoxMixin = declare("dijit.form._TextBoxMixin", null, {
+ // summary:
+ // A mixin for textbox form input widgets
+
+ // 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: "",
+
+ _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"));
+ }
+
+ if(this.textDir == "auto"){
+ this.applyTextDir(this.focusNode, formattedValue);
+ }
+
+ 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: "",
+
+ _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);
+ },
+
+ _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'));
+
+ // textDir support
+ if(this.textDir == "auto"){
+ this.applyTextDir(this.focusNode, value);
+ }
+ },
+
+ format: function(value /*=====, constraints =====*/){
+ // summary:
+ // Replaceable function to convert a value to a properly formatted string.
+ // value: String
+ // constraints: Object
+ // tags:
+ // protected extension
+ return ((value == null || value == undefined) ? "" : (value.toString ? value.toString() : value));
+ },
+
+ parse: function(value /*=====, constraints =====*/){
+ // summary:
+ // Replaceable function to convert a formatted string to a value
+ // value: String
+ // constraints: Object
+ // 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(event){
+ // summary:
+ // Connect to this function to receive notifications of various user data-input events.
+ // Return false to cancel the event and prevent it from being processed.
+ // event:
+ // keydown | keypress | cut | paste | input
+ // tags:
+ // callback
+ },
+ =====*/
+ onInput: function(){},
+
+ __skipInputEvent: false,
+ _onInput: function(){
+ // summary:
+ // Called AFTER the input event has happened
+ // set text direction according to textDir that was defined in creation
+ if(this.textDir == "auto"){
+ this.applyTextDir(this.focusNode, this.focusNode.value);
+ }
+
+ this._refreshState();
+
+ // In case someone is watch()'ing for changes to displayedValue
+ this._set("displayedValue", this.get("displayedValue"));
+ },
+
+ postCreate: function(){
+ // setting the value here is needed since value="" in the template causes "undefined"
+ // and setting in the DOM (instead of the JS object) helps with form reset actions
+ this.textbox.setAttribute("value", this.textbox.value); // DOM and JS values should be the same
+
+ this.inherited(arguments);
+
+ // normalize input events to reduce spurious event processing
+ // onkeydown: do not forward modifier keys
+ // set charOrCode to numeric keycode
+ // onkeypress: do not forward numeric charOrCode keys (already sent through onkeydown)
+ // onpaste & oncut: set charOrCode to 229 (IME)
+ // oninput: if primary event not already processed, set charOrCode to 229 (IME), else do not forward
+ var handleEvent = function(e){
+ var charCode = e.charOrCode || e.keyCode || 229;
+ if(e.type == "keydown"){
+ switch(charCode){ // ignore "state" keys
+ case keys.SHIFT:
+ case keys.ALT:
+ case keys.CTRL:
+ case keys.META:
+ case keys.CAPS_LOCK:
+ return;
+ default:
+ if(charCode >= 65 && charCode <= 90){ return; } // keydown for A-Z can be processed with keypress
+ }
+ }
+ if(e.type == "keypress" && typeof charCode != "string"){ return; }
+ if(e.type == "input"){
+ if(this.__skipInputEvent){ // duplicate event
+ this.__skipInputEvent = false;
+ return;
+ }
+ }else{
+ this.__skipInputEvent = true;
+ }
+ // create fake event to set charOrCode and to know if preventDefault() was called
+ var faux = lang.mixin({}, e, {
+ charOrCode: charCode,
+ wasConsumed: false,
+ preventDefault: function(){
+ faux.wasConsumed = true;
+ e.preventDefault();
+ },
+ stopPropagation: function(){ e.stopPropagation(); }
+ });
+ // give web page author a chance to consume the event
+ if(this.onInput(faux) === false){
+ event.stop(faux); // return false means stop
+ }
+ if(faux.wasConsumed){ return; } // if preventDefault was called
+ setTimeout(lang.hitch(this, "_onInput", faux), 0); // widget notification after key has posted
+ };
+ array.forEach([ "onkeydown", "onkeypress", "onpaste", "oncut", "oninput" ], function(event){
+ this.connect(this.textbox, event, handleEvent);
+ }, this);
+ },
+
+ _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 = lang.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);
+ }
+ },
+
+ _isTextSelected: function(){
+ return this.textbox.selectionStart == this.textbox.selectionEnd;
+ },
+
+ _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
+ if(this._isTextSelected()){
+ _TextBoxMixin.selectInputText(this.textbox);
+ }
+ });
+ }
+ // 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);
+ },
+ _setTextDirAttr: function(/*String*/ textDir){
+ // summary:
+ // Setter for textDir.
+ // description:
+ // Users shouldn't call this function; they should be calling
+ // set('textDir', value)
+ // tags:
+ // private
+
+ // only if new textDir is different from the old one
+ // and on widgets creation.
+ if(!this._created
+ || this.textDir != textDir){
+ this._set("textDir", textDir);
+ // so the change of the textDir will take place immediately.
+ this.applyTextDir(this.focusNode, this.focusNode.value);
+ }
+ }
+});
+
+
+_TextBoxMixin._setSelectionRange = dijit._setSelectionRange = function(/*DomNode*/ element, /*Number?*/ start, /*Number?*/ stop){
+ if(element.setSelectionRange){
+ element.setSelectionRange(start, stop);
+ }
+};
+
+_TextBoxMixin.selectInputText = 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?
+ element = dom.byId(element);
+ if(isNaN(start)){ start = 0; }
+ if(isNaN(stop)){ stop = element.value ? element.value.length : 0; }
+ try{
+ element.focus();
+ _TextBoxMixin._setSelectionRange(element, start, stop);
+ }catch(e){ /* squelch random errors (esp. on IE) from unexpected focus changes or DOM nodes being hidden */ }
+};
+
+return _TextBoxMixin;
+});
diff --git a/js/dojo/dijit/form/_ToggleButtonMixin.js b/js/dojo/dijit/form/_ToggleButtonMixin.js
new file mode 100644
index 0000000..2fd8936
--- /dev/null
+++ b/js/dojo/dijit/form/_ToggleButtonMixin.js
@@ -0,0 +1,52 @@
+//>>built
+define("dijit/form/_ToggleButtonMixin", [
+ "dojo/_base/declare", // declare
+ "dojo/dom-attr" // domAttr.set
+], function(declare, domAttr){
+
+// module:
+// dijit/form/_ToggleButtonMixin
+// summary:
+// A mixin to provide functionality to allow a button that can be in two states (checked or not).
+
+return declare("dijit.form._ToggleButtonMixin", null, {
+ // summary:
+ // A mixin to provide functionality to allow a button that can be in two states (checked or not).
+
+ // 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,
+
+ // aria-pressed for toggle buttons, and aria-checked for checkboxes
+ _aria_attr: "aria-pressed",
+
+ _onClick: function(/*Event*/ evt){
+ var original = this.checked;
+ this._set('checked', !original); // partially set the toggled value, assuming the toggle will work, so it can be overridden in the onclick handler
+ var ret = this.inherited(arguments); // the user could reset the value here
+ this.set('checked', ret ? this.checked : original); // officially set the toggled or user value, or reset it back
+ return ret;
+ },
+
+ _setCheckedAttr: function(/*Boolean*/ value, /*Boolean?*/ priorityChange){
+ this._set("checked", value);
+ domAttr.set(this.focusNode || this.domNode, "checked", value);
+ (this.focusNode || this.domNode).setAttribute(this._aria_attr, value ? "true" : "false"); // aria values should be strings
+ this._handleOnChange(value, priorityChange);
+ },
+
+ 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/js/dojo/dijit/form/nls/ComboBox.js b/js/dojo/dijit/form/nls/ComboBox.js
new file mode 100644
index 0000000..80ec651
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ComboBox.js
@@ -0,0 +1,41 @@
+//>>built
+define("dijit/form/nls/ComboBox", { root:
+//begin v1.x content
+({
+ previousMessage: "Previous choices",
+ nextMessage: "More choices"
+})
+//end v1.x content
+,
+"zh": true,
+"zh-tw": true,
+"tr": true,
+"th": true,
+"sv": true,
+"sl": true,
+"sk": true,
+"ru": true,
+"ro": true,
+"pt": true,
+"pt-pt": true,
+"pl": true,
+"nl": true,
+"nb": true,
+"ko": true,
+"kk": true,
+"ja": true,
+"it": true,
+"hu": true,
+"hr": true,
+"he": true,
+"fr": true,
+"fi": true,
+"es": true,
+"el": true,
+"de": true,
+"da": true,
+"cs": true,
+"ca": true,
+"az": true,
+"ar": true
+});
diff --git a/js/dojo/dijit/form/nls/Textarea.js b/js/dojo/dijit/form/nls/Textarea.js
new file mode 100644
index 0000000..e5ce936
--- /dev/null
+++ b/js/dojo/dijit/form/nls/Textarea.js
@@ -0,0 +1,44 @@
+//>>built
+define("dijit/form/nls/Textarea", { root:
+//begin v1.x content
+// used by both the editor and textarea widgets to provide information to screen reader users
+({
+ iframeEditTitle: 'edit area', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'edit area frame' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+,
+"zh": true,
+"zh-tw": true,
+"tr": true,
+"th": true,
+"sv": true,
+"sl": true,
+"sk": true,
+"ru": true,
+"ro": true,
+"pt": true,
+"pt-pt": true,
+"pl": true,
+"nl": true,
+"nb": true,
+"ko": true,
+"kk": true,
+"ja": true,
+"it": true,
+"hu": true,
+"hr": true,
+"he": true,
+"fr": true,
+"fi": true,
+"es": true,
+"el": true,
+"de": true,
+"da": true,
+"cs": true,
+"ca": true,
+"az": true,
+"ar": true
+});
diff --git a/js/dojo/dijit/form/nls/ar/ComboBox.js b/js/dojo/dijit/form/nls/ar/ComboBox.js
new file mode 100644
index 0000000..5f70b7f
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ar/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/ar/ComboBox", //begin v1.x content
+({
+ previousMessage: "الاختيارات السابقة",
+ nextMessage: "مزيد من الاختيارات"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ar/Textarea.js b/js/dojo/dijit/form/nls/ar/Textarea.js
new file mode 100644
index 0000000..6696588
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ar/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/ar/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'مساحة التحرير', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'اطار مساحة التحرير' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ar/validate.js b/js/dojo/dijit/form/nls/ar/validate.js
new file mode 100644
index 0000000..d78f7d6
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ar/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/ar/validate", //begin v1.x content
+({
+ invalidMessage: "القيمة التي تم ادخالها غير صحيحة.",
+ missingMessage: "يجب ادخال هذه القيمة.",
+ rangeMessage: "هذه القيمة ليس بالمدى الصحيح."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/az/ComboBox.js b/js/dojo/dijit/form/nls/az/ComboBox.js
new file mode 100644
index 0000000..de06c85
--- /dev/null
+++ b/js/dojo/dijit/form/nls/az/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/az/ComboBox", //begin v1.x content
+({
+ "previousMessage" : "Əvvəlki variantlar",
+ "nextMessage" : "Başqa variantlar"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/az/Textarea.js b/js/dojo/dijit/form/nls/az/Textarea.js
new file mode 100644
index 0000000..3d4066d
--- /dev/null
+++ b/js/dojo/dijit/form/nls/az/Textarea.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/az/Textarea", //begin v1.x content
+({
+ "iframeEditTitle" : "Redaktə sahəsi",
+ "iframeFocusTitle" : "Redaktə sahəsi çərçivəsi"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/az/validate.js b/js/dojo/dijit/form/nls/az/validate.js
new file mode 100644
index 0000000..94fa9e9
--- /dev/null
+++ b/js/dojo/dijit/form/nls/az/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/az/validate", //begin v1.x content
+({
+ "rangeMessage" : "Bu dəyər aralıq xaricində.",
+ "invalidMessage" : "Girilən dəyər keçərli deyil.",
+ "missingMessage" : "Bu deyər lazımlı."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ca/ComboBox.js b/js/dojo/dijit/form/nls/ca/ComboBox.js
new file mode 100644
index 0000000..37c7330
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ca/ComboBox.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/ca/ComboBox", //begin v1.x content
+({
+ previousMessage: "Opcions anteriors",
+ nextMessage: "Més opcions"
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ca/Textarea.js b/js/dojo/dijit/form/nls/ca/Textarea.js
new file mode 100644
index 0000000..a0264f4
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ca/Textarea.js
@@ -0,0 +1,13 @@
+//>>built
+define(
+"dijit/form/nls/ca/Textarea", //begin v1.x content
+/* used by both the editor and textarea widgets to provide information to screen reader users */
+({
+ iframeEditTitle: 'àrea d\'edició', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'Marc de l\'àrea d\'edició' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ca/validate.js b/js/dojo/dijit/form/nls/ca/validate.js
new file mode 100644
index 0000000..6a5eeb1
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ca/validate.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/ca/validate", //begin v1.x content
+({
+ invalidMessage: "El valor introduït no és vàlid",
+ missingMessage: "Aquest valor és necessari",
+ rangeMessage: "Aquest valor és fora de l'interval"
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/cs/ComboBox.js b/js/dojo/dijit/form/nls/cs/ComboBox.js
new file mode 100644
index 0000000..deb0a47
--- /dev/null
+++ b/js/dojo/dijit/form/nls/cs/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/cs/ComboBox", //begin v1.x content
+({
+ previousMessage: "Předchozí volby",
+ nextMessage: "Další volby"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/cs/Textarea.js b/js/dojo/dijit/form/nls/cs/Textarea.js
new file mode 100644
index 0000000..ba722d4
--- /dev/null
+++ b/js/dojo/dijit/form/nls/cs/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/cs/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'oblast úprav', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'rámec oblasti úprav' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/cs/validate.js b/js/dojo/dijit/form/nls/cs/validate.js
new file mode 100644
index 0000000..1859efd
--- /dev/null
+++ b/js/dojo/dijit/form/nls/cs/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/cs/validate", //begin v1.x content
+({
+ invalidMessage: "Zadaná hodnota není platná.",
+ missingMessage: "Tato hodnota je vyžadována.",
+ rangeMessage: "Tato hodnota je mimo rozsah."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/da/ComboBox.js b/js/dojo/dijit/form/nls/da/ComboBox.js
new file mode 100644
index 0000000..cfca776
--- /dev/null
+++ b/js/dojo/dijit/form/nls/da/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/da/ComboBox", //begin v1.x content
+({
+ previousMessage: "Forrige valg",
+ nextMessage: "Flere valg"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/da/Textarea.js b/js/dojo/dijit/form/nls/da/Textarea.js
new file mode 100644
index 0000000..b40af3b
--- /dev/null
+++ b/js/dojo/dijit/form/nls/da/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/da/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'redigeringsområde', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'ramme om redigeringsområde' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/da/validate.js b/js/dojo/dijit/form/nls/da/validate.js
new file mode 100644
index 0000000..b37bd72
--- /dev/null
+++ b/js/dojo/dijit/form/nls/da/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/da/validate", //begin v1.x content
+({
+ invalidMessage: "Den angivne værdi er ikke gyldig.",
+ missingMessage: "Værdien er påkrævet.",
+ rangeMessage: "Værdien er uden for intervallet."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/de/ComboBox.js b/js/dojo/dijit/form/nls/de/ComboBox.js
new file mode 100644
index 0000000..0e1853a
--- /dev/null
+++ b/js/dojo/dijit/form/nls/de/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/de/ComboBox", //begin v1.x content
+({
+ previousMessage: "Vorherige Auswahl",
+ nextMessage: "Weitere Auswahlmöglichkeiten"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/de/Textarea.js b/js/dojo/dijit/form/nls/de/Textarea.js
new file mode 100644
index 0000000..4225830
--- /dev/null
+++ b/js/dojo/dijit/form/nls/de/Textarea.js
@@ -0,0 +1,12 @@
+//>>built
+define(
+"dijit/form/nls/de/Textarea", //begin v1.x content
+/* used by both the editor and textarea widgets to provide information to screen reader users */
+({
+ iframeEditTitle: 'Editierbereich', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'Rahmen für Editierbereich' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/de/validate.js b/js/dojo/dijit/form/nls/de/validate.js
new file mode 100644
index 0000000..6328a79
--- /dev/null
+++ b/js/dojo/dijit/form/nls/de/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/de/validate", //begin v1.x content
+({
+ invalidMessage: "Der eingegebene Wert ist ungültig. ",
+ missingMessage: "Dieser Wert ist erforderlich.",
+ rangeMessage: "Dieser Wert liegt außerhalb des gültigen Bereichs. "
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/el/ComboBox.js b/js/dojo/dijit/form/nls/el/ComboBox.js
new file mode 100644
index 0000000..af66359
--- /dev/null
+++ b/js/dojo/dijit/form/nls/el/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/el/ComboBox", //begin v1.x content
+({
+ previousMessage: "Προηγούμενες επιλογές",
+ nextMessage: "Περισσότερες επιλογές"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/el/Textarea.js b/js/dojo/dijit/form/nls/el/Textarea.js
new file mode 100644
index 0000000..3894713
--- /dev/null
+++ b/js/dojo/dijit/form/nls/el/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/el/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'περιοχή επεξεργασίας', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'πλαίσιο περιοχής επεξεργασίας' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/el/validate.js b/js/dojo/dijit/form/nls/el/validate.js
new file mode 100644
index 0000000..4e7304d
--- /dev/null
+++ b/js/dojo/dijit/form/nls/el/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/el/validate", //begin v1.x content
+({
+ invalidMessage: "Η τιμή που καταχωρήσατε δεν είναι έγκυρη.",
+ missingMessage: "Η τιμή αυτή πρέπει απαραίτητα να καθοριστεί.",
+ rangeMessage: "Η τιμή αυτή δεν ανήκει στο εύρος έγκυρων τιμών."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/es/ComboBox.js b/js/dojo/dijit/form/nls/es/ComboBox.js
new file mode 100644
index 0000000..f516649
--- /dev/null
+++ b/js/dojo/dijit/form/nls/es/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/es/ComboBox", //begin v1.x content
+({
+ previousMessage: "Opciones anteriores",
+ nextMessage: "Más opciones"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/es/Textarea.js b/js/dojo/dijit/form/nls/es/Textarea.js
new file mode 100644
index 0000000..602aa60
--- /dev/null
+++ b/js/dojo/dijit/form/nls/es/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/es/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'área de edición', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'marco del área de edición' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/es/validate.js b/js/dojo/dijit/form/nls/es/validate.js
new file mode 100644
index 0000000..dd1eaed
--- /dev/null
+++ b/js/dojo/dijit/form/nls/es/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/es/validate", //begin v1.x content
+({
+ invalidMessage: "El valor especificado no es válido.",
+ missingMessage: "Este valor es necesario.",
+ rangeMessage: "Este valor está fuera del intervalo."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/fi/ComboBox.js b/js/dojo/dijit/form/nls/fi/ComboBox.js
new file mode 100644
index 0000000..4341fe0
--- /dev/null
+++ b/js/dojo/dijit/form/nls/fi/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/fi/ComboBox", //begin v1.x content
+({
+ previousMessage: "Edelliset valinnat",
+ nextMessage: "Lisää valintoja"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/fi/Textarea.js b/js/dojo/dijit/form/nls/fi/Textarea.js
new file mode 100644
index 0000000..9b05840
--- /dev/null
+++ b/js/dojo/dijit/form/nls/fi/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/fi/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'muokkausalue', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'muokkausalueen kehys' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/fi/validate.js b/js/dojo/dijit/form/nls/fi/validate.js
new file mode 100644
index 0000000..a7cf725
--- /dev/null
+++ b/js/dojo/dijit/form/nls/fi/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/fi/validate", //begin v1.x content
+({
+ invalidMessage: "Annettu arvo ei kelpaa.",
+ missingMessage: "Tämä arvo on pakollinen.",
+ rangeMessage: "Tämä arvo on sallitun alueen ulkopuolella."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/fr/ComboBox.js b/js/dojo/dijit/form/nls/fr/ComboBox.js
new file mode 100644
index 0000000..ad473b2
--- /dev/null
+++ b/js/dojo/dijit/form/nls/fr/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/fr/ComboBox", //begin v1.x content
+({
+ previousMessage: "Choix précédents",
+ nextMessage: "Plus de choix"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/fr/Textarea.js b/js/dojo/dijit/form/nls/fr/Textarea.js
new file mode 100644
index 0000000..4ef52b8
--- /dev/null
+++ b/js/dojo/dijit/form/nls/fr/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/fr/Textarea", //begin v1.x content
+({
+ iframeEditTitle: "zone d'édition", // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: "cadre de la zone d'édition" // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/fr/validate.js b/js/dojo/dijit/form/nls/fr/validate.js
new file mode 100644
index 0000000..964bd8c
--- /dev/null
+++ b/js/dojo/dijit/form/nls/fr/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/fr/validate", //begin v1.x content
+({
+ invalidMessage: "La valeur indiquée n'est pas correcte.",
+ missingMessage: "Cette valeur est requise.",
+ rangeMessage: "Cette valeur n'est pas comprise dans la plage autorisée."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/he/ComboBox.js b/js/dojo/dijit/form/nls/he/ComboBox.js
new file mode 100644
index 0000000..a1a171b
--- /dev/null
+++ b/js/dojo/dijit/form/nls/he/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/he/ComboBox", //begin v1.x content
+({
+ previousMessage: "האפשרויות הקודמות",
+ nextMessage: "אפשרויות נוספות"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/he/Textarea.js b/js/dojo/dijit/form/nls/he/Textarea.js
new file mode 100644
index 0000000..27d0f99
--- /dev/null
+++ b/js/dojo/dijit/form/nls/he/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/he/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'אזור עריכה', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'מסגרת אזור עריכה' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/he/validate.js b/js/dojo/dijit/form/nls/he/validate.js
new file mode 100644
index 0000000..773d55c
--- /dev/null
+++ b/js/dojo/dijit/form/nls/he/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/he/validate", //begin v1.x content
+({
+ invalidMessage: "הערך שצוין אינו חוקי.",
+ missingMessage: "זהו ערך דרוש.",
+ rangeMessage: "הערך מחוץ לטווח."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/hr/ComboBox.js b/js/dojo/dijit/form/nls/hr/ComboBox.js
new file mode 100644
index 0000000..a578547
--- /dev/null
+++ b/js/dojo/dijit/form/nls/hr/ComboBox.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dijit/form/nls/hr/ComboBox", ({
+ previousMessage: "Prethodni izbori",
+ nextMessage: "Više izbora"
+})
+);
diff --git a/js/dojo/dijit/form/nls/hr/Textarea.js b/js/dojo/dijit/form/nls/hr/Textarea.js
new file mode 100644
index 0000000..14fa2d8
--- /dev/null
+++ b/js/dojo/dijit/form/nls/hr/Textarea.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/hr/Textarea", // used by both the editor and textarea widgets to provide information to screen reader users
+({
+ iframeEditTitle: 'područje uređivanja', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'okvir područja uređivanja' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+);
diff --git a/js/dojo/dijit/form/nls/hr/validate.js b/js/dojo/dijit/form/nls/hr/validate.js
new file mode 100644
index 0000000..78e3f69
--- /dev/null
+++ b/js/dojo/dijit/form/nls/hr/validate.js
@@ -0,0 +1,8 @@
+//>>built
+define(
+"dijit/form/nls/hr/validate", ({
+ invalidMessage: "Unesena vrijednost nije važeća.",
+ missingMessage: "Potrebna je ova vrijednost.",
+ rangeMessage: "Ova vrijednost je izvan raspona."
+})
+);
diff --git a/js/dojo/dijit/form/nls/hu/ComboBox.js b/js/dojo/dijit/form/nls/hu/ComboBox.js
new file mode 100644
index 0000000..399a7f9
--- /dev/null
+++ b/js/dojo/dijit/form/nls/hu/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/hu/ComboBox", //begin v1.x content
+({
+ previousMessage: "Előző menüpontok",
+ nextMessage: "További menüpontok"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/hu/Textarea.js b/js/dojo/dijit/form/nls/hu/Textarea.js
new file mode 100644
index 0000000..a178d6e
--- /dev/null
+++ b/js/dojo/dijit/form/nls/hu/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/hu/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'szerkesztési terület', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'szerkesztési terület keret' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/hu/validate.js b/js/dojo/dijit/form/nls/hu/validate.js
new file mode 100644
index 0000000..6219d94
--- /dev/null
+++ b/js/dojo/dijit/form/nls/hu/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/hu/validate", //begin v1.x content
+({
+ invalidMessage: "A megadott érték érvénytelen.",
+ missingMessage: "Meg kell adni egy értéket.",
+ rangeMessage: "Az érték kívül van a megengedett tartományon."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/it/ComboBox.js b/js/dojo/dijit/form/nls/it/ComboBox.js
new file mode 100644
index 0000000..4f7dfaa
--- /dev/null
+++ b/js/dojo/dijit/form/nls/it/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/it/ComboBox", //begin v1.x content
+({
+ previousMessage: "Scelte precedenti",
+ nextMessage: "Altre scelte"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/it/Textarea.js b/js/dojo/dijit/form/nls/it/Textarea.js
new file mode 100644
index 0000000..1b5579f
--- /dev/null
+++ b/js/dojo/dijit/form/nls/it/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/it/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'modifica area', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'modifica frame area' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/it/validate.js b/js/dojo/dijit/form/nls/it/validate.js
new file mode 100644
index 0000000..796ff16
--- /dev/null
+++ b/js/dojo/dijit/form/nls/it/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/it/validate", //begin v1.x content
+({
+ invalidMessage: "Il valore immesso non è valido.",
+ missingMessage: "Questo valore è obbligatorio.",
+ rangeMessage: "Questo valore non è compreso nell'intervallo."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ja/ComboBox.js b/js/dojo/dijit/form/nls/ja/ComboBox.js
new file mode 100644
index 0000000..9b97e6b
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ja/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/ja/ComboBox", //begin v1.x content
+({
+ previousMessage: "以前の選択項目",
+ nextMessage: "追加の選択項目"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ja/Textarea.js b/js/dojo/dijit/form/nls/ja/Textarea.js
new file mode 100644
index 0000000..3d19ac6
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ja/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/ja/Textarea", //begin v1.x content
+({
+ iframeEditTitle: '編集域', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: '編集域フレーム' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ja/validate.js b/js/dojo/dijit/form/nls/ja/validate.js
new file mode 100644
index 0000000..8156ca7
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ja/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/ja/validate", //begin v1.x content
+({
+ invalidMessage: "入力した値は無効です。",
+ missingMessage: "この値は必須です。",
+ rangeMessage: "この値は範囲外です。"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/kk/ComboBox.js b/js/dojo/dijit/form/nls/kk/ComboBox.js
new file mode 100644
index 0000000..055ba36
--- /dev/null
+++ b/js/dojo/dijit/form/nls/kk/ComboBox.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/kk/ComboBox", //begin v1.x content
+({
+ previousMessage: "Алдыңғы нұсқалар",
+ nextMessage: "Басқа нұсқалар"
+})
+//end v1.x content
+);
+
diff --git a/js/dojo/dijit/form/nls/kk/Textarea.js b/js/dojo/dijit/form/nls/kk/Textarea.js
new file mode 100644
index 0000000..c8ef5c1
--- /dev/null
+++ b/js/dojo/dijit/form/nls/kk/Textarea.js
@@ -0,0 +1,13 @@
+//>>built
+define(
+"dijit/form/nls/kk/Textarea", //begin v1.x content
+/* used by both the editor and textarea widgets to provide information to screen reader users */
+({
+ iframeEditTitle: 'өңдеу аумағы', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'өңдеу аумағының жақтауы' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
+
diff --git a/js/dojo/dijit/form/nls/kk/validate.js b/js/dojo/dijit/form/nls/kk/validate.js
new file mode 100644
index 0000000..bbf8728
--- /dev/null
+++ b/js/dojo/dijit/form/nls/kk/validate.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/kk/validate", //begin v1.x content
+({
+ invalidMessage: "Енгізілген мән жарамды емес.",
+ missingMessage: "Бұл мән міндетті.",
+ rangeMessage: "Бұл мән ауқымнан тыс."
+})
+//end v1.x content
+);
+
diff --git a/js/dojo/dijit/form/nls/ko/ComboBox.js b/js/dojo/dijit/form/nls/ko/ComboBox.js
new file mode 100644
index 0000000..a296954
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ko/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/ko/ComboBox", //begin v1.x content
+({
+ previousMessage: "이전 선택사항",
+ nextMessage: "기타 선택사항"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ko/Textarea.js b/js/dojo/dijit/form/nls/ko/Textarea.js
new file mode 100644
index 0000000..62447a5
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ko/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/ko/Textarea", //begin v1.x content
+({
+ iframeEditTitle: '편집 영역', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: '편집 영역 프레임' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ko/validate.js b/js/dojo/dijit/form/nls/ko/validate.js
new file mode 100644
index 0000000..c55ad35
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ko/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/ko/validate", //begin v1.x content
+({
+ invalidMessage: "입력된 값이 올바르지 않습니다.",
+ missingMessage: "이 값은 필수입니다.",
+ rangeMessage: "이 값은 범위를 벗어납니다."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/nb/ComboBox.js b/js/dojo/dijit/form/nls/nb/ComboBox.js
new file mode 100644
index 0000000..c26b127
--- /dev/null
+++ b/js/dojo/dijit/form/nls/nb/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/nb/ComboBox", //begin v1.x content
+({
+ previousMessage: "Tidligere valg",
+ nextMessage: "Flere valg"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/nb/Textarea.js b/js/dojo/dijit/form/nls/nb/Textarea.js
new file mode 100644
index 0000000..ce22469
--- /dev/null
+++ b/js/dojo/dijit/form/nls/nb/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/nb/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'redigeringsområde', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'ramme for redigeringsområde' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/nb/validate.js b/js/dojo/dijit/form/nls/nb/validate.js
new file mode 100644
index 0000000..97b04ac
--- /dev/null
+++ b/js/dojo/dijit/form/nls/nb/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/nb/validate", //begin v1.x content
+({
+ invalidMessage: "Den angitte verdien er ikke gyldig.",
+ missingMessage: "Denne verdien er obligatorisk.",
+ rangeMessage: "Denne verdien er utenfor gyldig område."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/nl/ComboBox.js b/js/dojo/dijit/form/nls/nl/ComboBox.js
new file mode 100644
index 0000000..7610a15
--- /dev/null
+++ b/js/dojo/dijit/form/nls/nl/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/nl/ComboBox", //begin v1.x content
+({
+ previousMessage: "Eerdere opties",
+ nextMessage: "Meer opties"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/nl/Textarea.js b/js/dojo/dijit/form/nls/nl/Textarea.js
new file mode 100644
index 0000000..8c69e95
--- /dev/null
+++ b/js/dojo/dijit/form/nls/nl/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/nl/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'veld bewerken', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'veldkader bewerken' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/nl/validate.js b/js/dojo/dijit/form/nls/nl/validate.js
new file mode 100644
index 0000000..3f7b545
--- /dev/null
+++ b/js/dojo/dijit/form/nls/nl/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/nl/validate", //begin v1.x content
+({
+ invalidMessage: "De opgegeven waarde is ongeldig.",
+ missingMessage: "Deze waarde is verplicht.",
+ rangeMessage: "Deze waarde is niet toegestaan."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/pl/ComboBox.js b/js/dojo/dijit/form/nls/pl/ComboBox.js
new file mode 100644
index 0000000..921add9
--- /dev/null
+++ b/js/dojo/dijit/form/nls/pl/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/pl/ComboBox", //begin v1.x content
+({
+ previousMessage: "Poprzednie wybory",
+ nextMessage: "Więcej wyborów"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/pl/Textarea.js b/js/dojo/dijit/form/nls/pl/Textarea.js
new file mode 100644
index 0000000..13a877b
--- /dev/null
+++ b/js/dojo/dijit/form/nls/pl/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/pl/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'edycja obszaru', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'edycja ramki obszaru' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/pl/validate.js b/js/dojo/dijit/form/nls/pl/validate.js
new file mode 100644
index 0000000..bc2b5fc
--- /dev/null
+++ b/js/dojo/dijit/form/nls/pl/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/pl/validate", //begin v1.x content
+({
+ invalidMessage: "Wprowadzona wartość jest niepoprawna.",
+ missingMessage: "Ta wartość jest wymagana.",
+ rangeMessage: "Ta wartość jest spoza zakresu."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/pt-pt/ComboBox.js b/js/dojo/dijit/form/nls/pt-pt/ComboBox.js
new file mode 100644
index 0000000..dac814c
--- /dev/null
+++ b/js/dojo/dijit/form/nls/pt-pt/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/pt-pt/ComboBox", //begin v1.x content
+({
+ previousMessage: "Opções anteriores",
+ nextMessage: "Mais opções"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/pt-pt/Textarea.js b/js/dojo/dijit/form/nls/pt-pt/Textarea.js
new file mode 100644
index 0000000..ffe423c
--- /dev/null
+++ b/js/dojo/dijit/form/nls/pt-pt/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/pt-pt/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'área de edição', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'painel da área de edição' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/pt-pt/validate.js b/js/dojo/dijit/form/nls/pt-pt/validate.js
new file mode 100644
index 0000000..6dff684
--- /dev/null
+++ b/js/dojo/dijit/form/nls/pt-pt/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/pt-pt/validate", //begin v1.x content
+({
+ invalidMessage: "O valor introduzido não é válido.",
+ missingMessage: "Este valor é requerido.",
+ rangeMessage: "Este valor encontra-se fora do intervalo."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/pt/ComboBox.js b/js/dojo/dijit/form/nls/pt/ComboBox.js
new file mode 100644
index 0000000..c50743b
--- /dev/null
+++ b/js/dojo/dijit/form/nls/pt/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/pt/ComboBox", //begin v1.x content
+({
+ previousMessage: "Opções anteriores",
+ nextMessage: "Mais opções"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/pt/Textarea.js b/js/dojo/dijit/form/nls/pt/Textarea.js
new file mode 100644
index 0000000..283313f
--- /dev/null
+++ b/js/dojo/dijit/form/nls/pt/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/pt/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'editar área', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'editar quadro da área' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/pt/validate.js b/js/dojo/dijit/form/nls/pt/validate.js
new file mode 100644
index 0000000..fb280a3
--- /dev/null
+++ b/js/dojo/dijit/form/nls/pt/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/pt/validate", //begin v1.x content
+({
+ invalidMessage: "O valor inserido não é válido.",
+ missingMessage: "Este valor é necessário.",
+ rangeMessage: "Este valor está fora do intervalo. "
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ro/ComboBox.js b/js/dojo/dijit/form/nls/ro/ComboBox.js
new file mode 100644
index 0000000..153586b
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ro/ComboBox.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/ro/ComboBox", //begin v1.x content
+({
+ previousMessage: "Alegeri anterioare",
+ nextMessage: "Mai multe alegeri"
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ro/Textarea.js b/js/dojo/dijit/form/nls/ro/Textarea.js
new file mode 100644
index 0000000..18e1daf
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ro/Textarea.js
@@ -0,0 +1,13 @@
+//>>built
+define(
+"dijit/form/nls/ro/Textarea", //begin v1.x content
+/* used by both the editor and textarea widgets to provide information to screen reader users */
+({
+ iframeEditTitle: 'zonă de editare', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'cadru zonă de editare' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ro/validate.js b/js/dojo/dijit/form/nls/ro/validate.js
new file mode 100644
index 0000000..9497a6e
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ro/validate.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/ro/validate", //begin v1.x content
+({
+ invalidMessage: "Valoarea introdusă nu este validă.",
+ missingMessage: "Această valoare este necesară.",
+ rangeMessage: "Această valoare este în afara intervalului. "
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ru/ComboBox.js b/js/dojo/dijit/form/nls/ru/ComboBox.js
new file mode 100644
index 0000000..210a5a1
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ru/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/ru/ComboBox", //begin v1.x content
+({
+ previousMessage: "Предыдущие варианты",
+ nextMessage: "Следующие варианты"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ru/Textarea.js b/js/dojo/dijit/form/nls/ru/Textarea.js
new file mode 100644
index 0000000..fe69285
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ru/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/ru/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'область редактирования', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'фрейм области редактирования' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/ru/validate.js b/js/dojo/dijit/form/nls/ru/validate.js
new file mode 100644
index 0000000..140a6b3
--- /dev/null
+++ b/js/dojo/dijit/form/nls/ru/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/ru/validate", //begin v1.x content
+({
+ invalidMessage: "Указано недопустимое значение.",
+ missingMessage: "Это обязательное значение.",
+ rangeMessage: "Это значение вне диапазона."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/sk/ComboBox.js b/js/dojo/dijit/form/nls/sk/ComboBox.js
new file mode 100644
index 0000000..c16db5d
--- /dev/null
+++ b/js/dojo/dijit/form/nls/sk/ComboBox.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/sk/ComboBox", //begin v1.x content
+({
+ previousMessage: "Predchádzajúce voľby",
+ nextMessage: "Ďalšie voľby"
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/sk/Textarea.js b/js/dojo/dijit/form/nls/sk/Textarea.js
new file mode 100644
index 0000000..9f88719
--- /dev/null
+++ b/js/dojo/dijit/form/nls/sk/Textarea.js
@@ -0,0 +1,13 @@
+//>>built
+define(
+"dijit/form/nls/sk/Textarea", //begin v1.x content
+/* used by both the editor and textarea widgets to provide information to screen reader users */
+({
+ iframeEditTitle: 'upraviť oblasť', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'upraviť rám oblasti' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/sk/validate.js b/js/dojo/dijit/form/nls/sk/validate.js
new file mode 100644
index 0000000..36f98ff
--- /dev/null
+++ b/js/dojo/dijit/form/nls/sk/validate.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/sk/validate", //begin v1.x content
+({
+ invalidMessage: "Zadaná hodnota nie je platná.",
+ missingMessage: "Táto hodnota je vyžadovaná.",
+ rangeMessage: "Táto hodnota je mimo rozsah."
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/sl/ComboBox.js b/js/dojo/dijit/form/nls/sl/ComboBox.js
new file mode 100644
index 0000000..b561d74
--- /dev/null
+++ b/js/dojo/dijit/form/nls/sl/ComboBox.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/sl/ComboBox", //begin v1.x content
+({
+ previousMessage: "Prejšnje izbire",
+ nextMessage: "Dodatne izbire"
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/sl/Textarea.js b/js/dojo/dijit/form/nls/sl/Textarea.js
new file mode 100644
index 0000000..b9a493c
--- /dev/null
+++ b/js/dojo/dijit/form/nls/sl/Textarea.js
@@ -0,0 +1,13 @@
+//>>built
+define(
+"dijit/form/nls/sl/Textarea", //begin v1.x content
+/* used by both the editor and textarea widgets to provide information to screen reader users */
+({
+ iframeEditTitle: 'urejevalno področje', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'okvir urejevalnega področja' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/sl/validate.js b/js/dojo/dijit/form/nls/sl/validate.js
new file mode 100644
index 0000000..d7241c1
--- /dev/null
+++ b/js/dojo/dijit/form/nls/sl/validate.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/sl/validate", //begin v1.x content
+({
+ invalidMessage: "Vnesena vrednost ni veljavna.",
+ missingMessage: "Ta vrednost je zahtevana.",
+ rangeMessage: "Ta vrednost je izven območja."
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/sv/ComboBox.js b/js/dojo/dijit/form/nls/sv/ComboBox.js
new file mode 100644
index 0000000..f37dd72
--- /dev/null
+++ b/js/dojo/dijit/form/nls/sv/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/sv/ComboBox", //begin v1.x content
+({
+ previousMessage: "Föregående alternativ",
+ nextMessage: "Fler alternativ"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/sv/Textarea.js b/js/dojo/dijit/form/nls/sv/Textarea.js
new file mode 100644
index 0000000..a0adb10
--- /dev/null
+++ b/js/dojo/dijit/form/nls/sv/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/sv/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'redigeringsområde', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'redigeringsområdesram' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/sv/validate.js b/js/dojo/dijit/form/nls/sv/validate.js
new file mode 100644
index 0000000..db9ee51
--- /dev/null
+++ b/js/dojo/dijit/form/nls/sv/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/sv/validate", //begin v1.x content
+({
+ invalidMessage: "Det angivna värdet är ogiltigt.",
+ missingMessage: "Värdet är obligatoriskt.",
+ rangeMessage: "Värdet är utanför intervallet."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/th/ComboBox.js b/js/dojo/dijit/form/nls/th/ComboBox.js
new file mode 100644
index 0000000..ff2b2c8
--- /dev/null
+++ b/js/dojo/dijit/form/nls/th/ComboBox.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/th/ComboBox", //begin v1.x content
+({
+ previousMessage: "การเลือกก่อนหน้า",
+ nextMessage: "การเลือกเพิ่มเติม"
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/th/Textarea.js b/js/dojo/dijit/form/nls/th/Textarea.js
new file mode 100644
index 0000000..aa3b6fd
--- /dev/null
+++ b/js/dojo/dijit/form/nls/th/Textarea.js
@@ -0,0 +1,13 @@
+//>>built
+define(
+"dijit/form/nls/th/Textarea", //begin v1.x content
+/* used by both the editor and textarea widgets to provide information to screen reader users */
+({
+ iframeEditTitle: 'แก้ไขพื้นที่', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'แก้ไขกรอบพื้นที่' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/th/validate.js b/js/dojo/dijit/form/nls/th/validate.js
new file mode 100644
index 0000000..2a60162
--- /dev/null
+++ b/js/dojo/dijit/form/nls/th/validate.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/th/validate", //begin v1.x content
+({
+ invalidMessage: "ค่าที่ป้อนไม่ถูกต้อง",
+ missingMessage: "จำเป็นต้องมีค่านี้",
+ rangeMessage: "ค่านี้เกินช่วง"
+})
+
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/tr/ComboBox.js b/js/dojo/dijit/form/nls/tr/ComboBox.js
new file mode 100644
index 0000000..be20da3
--- /dev/null
+++ b/js/dojo/dijit/form/nls/tr/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/tr/ComboBox", //begin v1.x content
+({
+ previousMessage: "Önceki seçenekler",
+ nextMessage: "Diğer seçenekler"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/tr/Textarea.js b/js/dojo/dijit/form/nls/tr/Textarea.js
new file mode 100644
index 0000000..cca3420
--- /dev/null
+++ b/js/dojo/dijit/form/nls/tr/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/tr/Textarea", //begin v1.x content
+({
+ iframeEditTitle: 'düzenleme alanı', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: 'düzenleme alanı çerçevesi' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/tr/validate.js b/js/dojo/dijit/form/nls/tr/validate.js
new file mode 100644
index 0000000..0c4d0d6
--- /dev/null
+++ b/js/dojo/dijit/form/nls/tr/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/tr/validate", //begin v1.x content
+({
+ invalidMessage: "Girilen değer geçersiz.",
+ missingMessage: "Bu değer gerekli.",
+ rangeMessage: "Bu değer aralık dışında."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/validate.js b/js/dojo/dijit/form/nls/validate.js
new file mode 100644
index 0000000..68b1dd7
--- /dev/null
+++ b/js/dojo/dijit/form/nls/validate.js
@@ -0,0 +1,42 @@
+//>>built
+define("dijit/form/nls/validate", { root:
+//begin v1.x content
+({
+ invalidMessage: "The value entered is not valid.",
+ missingMessage: "This value is required.",
+ rangeMessage: "This value is out of range."
+})
+//end v1.x content
+,
+"zh": true,
+"zh-tw": true,
+"tr": true,
+"th": true,
+"sv": true,
+"sl": true,
+"sk": true,
+"ru": true,
+"ro": true,
+"pt": true,
+"pt-pt": true,
+"pl": true,
+"nl": true,
+"nb": true,
+"ko": true,
+"kk": true,
+"ja": true,
+"it": true,
+"hu": true,
+"hr": true,
+"he": true,
+"fr": true,
+"fi": true,
+"es": true,
+"el": true,
+"de": true,
+"da": true,
+"cs": true,
+"ca": true,
+"az": true,
+"ar": true
+});
diff --git a/js/dojo/dijit/form/nls/zh-tw/ComboBox.js b/js/dojo/dijit/form/nls/zh-tw/ComboBox.js
new file mode 100644
index 0000000..73f372c
--- /dev/null
+++ b/js/dojo/dijit/form/nls/zh-tw/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/zh-tw/ComboBox", //begin v1.x content
+({
+ previousMessage: "前一個選擇項",
+ nextMessage: "其他選擇項"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/zh-tw/Textarea.js b/js/dojo/dijit/form/nls/zh-tw/Textarea.js
new file mode 100644
index 0000000..8f2c357
--- /dev/null
+++ b/js/dojo/dijit/form/nls/zh-tw/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/zh-tw/Textarea", //begin v1.x content
+({
+ iframeEditTitle: '編輯區', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: '編輯區框' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/zh-tw/validate.js b/js/dojo/dijit/form/nls/zh-tw/validate.js
new file mode 100644
index 0000000..2997039
--- /dev/null
+++ b/js/dojo/dijit/form/nls/zh-tw/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/zh-tw/validate", //begin v1.x content
+({
+ invalidMessage: "輸入的值無效。",
+ missingMessage: "必須提供此值。",
+ rangeMessage: "此值超出範圍。"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/zh/ComboBox.js b/js/dojo/dijit/form/nls/zh/ComboBox.js
new file mode 100644
index 0000000..14c8f19
--- /dev/null
+++ b/js/dojo/dijit/form/nls/zh/ComboBox.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dijit/form/nls/zh/ComboBox", //begin v1.x content
+({
+ previousMessage: "先前选项",
+ nextMessage: "更多选项"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/zh/Textarea.js b/js/dojo/dijit/form/nls/zh/Textarea.js
new file mode 100644
index 0000000..ef5b8eb
--- /dev/null
+++ b/js/dojo/dijit/form/nls/zh/Textarea.js
@@ -0,0 +1,11 @@
+//>>built
+define(
+"dijit/form/nls/zh/Textarea", //begin v1.x content
+({
+ iframeEditTitle: '编辑区', // primary title for editable IFRAME, for screen readers when focus is in the editing area
+ iframeFocusTitle: '编辑区框架' // secondary title for editable IFRAME when focus is on outer container
+ // to let user know that focus has moved out of editing area and to the
+ // parent element of the editing area
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/nls/zh/validate.js b/js/dojo/dijit/form/nls/zh/validate.js
new file mode 100644
index 0000000..eca4066
--- /dev/null
+++ b/js/dojo/dijit/form/nls/zh/validate.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dijit/form/nls/zh/validate", //begin v1.x content
+({
+ invalidMessage: "输入的值无效。",
+ missingMessage: "此值是必需值。",
+ rangeMessage: "此值超出范围。"
+})
+//end v1.x content
+);
diff --git a/js/dojo/dijit/form/templates/Button.html b/js/dojo/dijit/form/templates/Button.html
new file mode 100644
index 0000000..d167ac0
--- /dev/null
+++ b/js/dojo/dijit/form/templates/Button.html
@@ -0,0 +1,17 @@
+<span class="dijit dijitReset dijitInline" role="presentation"
+ ><span class="dijitReset dijitInline dijitButtonNode"
+ data-dojo-attach-event="ondijitclick:_onClick" role="presentation"
+ ><span class="dijitReset dijitStretch dijitButtonContents"
+ data-dojo-attach-point="titleNode,focusNode"
+ role="button" aria-labelledby="${id}_label"
+ ><span class="dijitReset dijitInline dijitIcon" data-dojo-attach-point="iconNode"></span
+ ><span class="dijitReset dijitToggleButtonIconChar">&#x25CF;</span
+ ><span class="dijitReset dijitInline dijitButtonText"
+ id="${id}_label"
+ data-dojo-attach-point="containerNode"
+ ></span
+ ></span
+ ></span
+ ><input ${!nameAttrSetting} type="${type}" value="${value}" class="dijitOffScreen"
+ tabIndex="-1" role="presentation" data-dojo-attach-point="valueNode"
+/></span>
diff --git a/js/dojo/dijit/form/templates/CheckBox.html b/js/dojo/dijit/form/templates/CheckBox.html
new file mode 100644
index 0000000..fd81fc2
--- /dev/null
+++ b/js/dojo/dijit/form/templates/CheckBox.html
@@ -0,0 +1,7 @@
+<div class="dijit dijitReset dijitInline" role="presentation"
+ ><input
+ ${!nameAttrSetting} type="${type}" ${checkedAttrSetting}
+ class="dijitReset dijitCheckBoxInput"
+ data-dojo-attach-point="focusNode"
+ data-dojo-attach-event="onclick:_onClick"
+/></div>
diff --git a/js/dojo/dijit/form/templates/ComboButton.html b/js/dojo/dijit/form/templates/ComboButton.html
new file mode 100644
index 0000000..49eed10
--- /dev/null
+++ b/js/dojo/dijit/form/templates/ComboButton.html
@@ -0,0 +1,23 @@
+<table class="dijit dijitReset dijitInline dijitLeft"
+ cellspacing='0' cellpadding='0' role="presentation"
+ ><tbody role="presentation"><tr role="presentation"
+ ><td class="dijitReset dijitStretch dijitButtonNode" data-dojo-attach-point="buttonNode" data-dojo-attach-event="ondijitclick:_onClick,onkeypress:_onButtonKeyPress"
+ ><div id="${id}_button" class="dijitReset dijitButtonContents"
+ data-dojo-attach-point="titleNode"
+ role="button" aria-labelledby="${id}_label"
+ ><div class="dijitReset dijitInline dijitIcon" data-dojo-attach-point="iconNode" role="presentation"></div
+ ><div class="dijitReset dijitInline dijitButtonText" id="${id}_label" data-dojo-attach-point="containerNode" role="presentation"></div
+ ></div
+ ></td
+ ><td id="${id}_arrow" class='dijitReset dijitRight dijitButtonNode dijitArrowButton'
+ data-dojo-attach-point="_popupStateNode,focusNode,_buttonNode"
+ data-dojo-attach-event="onkeypress:_onArrowKeyPress"
+ title="${optionsTitle}"
+ role="button" aria-haspopup="true"
+ ><div class="dijitReset dijitArrowButtonInner" role="presentation"></div
+ ><div class="dijitReset dijitArrowButtonChar" role="presentation">&#9660;</div
+ ></td
+ ><td style="display:none !important;"
+ ><input ${!nameAttrSetting} type="${type}" value="${value}" data-dojo-attach-point="valueNode"
+ /></td></tr></tbody
+></table>
diff --git a/js/dojo/dijit/form/templates/DropDownBox.html b/js/dojo/dijit/form/templates/DropDownBox.html
new file mode 100644
index 0000000..0314ad9
--- /dev/null
+++ b/js/dojo/dijit/form/templates/DropDownBox.html
@@ -0,0 +1,16 @@
+<div class="dijit dijitReset dijitInline dijitLeft"
+ id="widget_${id}"
+ role="combobox"
+ ><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'
+ data-dojo-attach-point="_buttonNode, _popupStateNode" role="presentation"
+ ><input class="dijitReset dijitInputField dijitArrowButtonInner" value="&#9660; " type="text" tabIndex="-1" readonly="readonly" role="presentation"
+ ${_buttonInputDisabled}
+ /></div
+ ><div class='dijitReset dijitValidationContainer'
+ ><input class="dijitReset dijitInputField dijitValidationIcon dijitValidationInner" value="&#935; " type="text" tabIndex="-1" readonly="readonly" role="presentation"
+ /></div
+ ><div class="dijitReset dijitInputField dijitInputContainer"
+ ><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type="text" autocomplete="off"
+ data-dojo-attach-point="textbox,focusNode" role="textbox" aria-haspopup="true"
+ /></div
+></div>
diff --git a/js/dojo/dijit/form/templates/DropDownButton.html b/js/dojo/dijit/form/templates/DropDownButton.html
new file mode 100644
index 0000000..56d2618
--- /dev/null
+++ b/js/dojo/dijit/form/templates/DropDownButton.html
@@ -0,0 +1,20 @@
+<span class="dijit dijitReset dijitInline"
+ ><span class='dijitReset dijitInline dijitButtonNode'
+ data-dojo-attach-event="ondijitclick:_onClick" data-dojo-attach-point="_buttonNode"
+ ><span class="dijitReset dijitStretch dijitButtonContents"
+ data-dojo-attach-point="focusNode,titleNode,_arrowWrapperNode"
+ role="button" aria-haspopup="true" aria-labelledby="${id}_label"
+ ><span class="dijitReset dijitInline dijitIcon"
+ data-dojo-attach-point="iconNode"
+ ></span
+ ><span class="dijitReset dijitInline dijitButtonText"
+ data-dojo-attach-point="containerNode,_popupStateNode"
+ id="${id}_label"
+ ></span
+ ><span class="dijitReset dijitInline dijitArrowButtonInner"></span
+ ><span class="dijitReset dijitInline dijitArrowButtonChar">&#9660;</span
+ ></span
+ ></span
+ ><input ${!nameAttrSetting} type="${type}" value="${value}" class="dijitOffScreen" tabIndex="-1"
+ data-dojo-attach-point="valueNode"
+/></span>
diff --git a/js/dojo/dijit/form/templates/HorizontalSlider.html b/js/dojo/dijit/form/templates/HorizontalSlider.html
new file mode 100644
index 0000000..9fd16d4
--- /dev/null
+++ b/js/dojo/dijit/form/templates/HorizontalSlider.html
@@ -0,0 +1,37 @@
+<table class="dijit dijitReset dijitSlider dijitSliderH" cellspacing="0" cellpadding="0" border="0" rules="none" data-dojo-attach-event="onkeypress:_onKeyPress,onkeyup:_onKeyUp"
+ ><tr class="dijitReset"
+ ><td class="dijitReset" colspan="2"></td
+ ><td data-dojo-attach-point="topDecoration" class="dijitReset dijitSliderDecoration dijitSliderDecorationT dijitSliderDecorationH"></td
+ ><td class="dijitReset" colspan="2"></td
+ ></tr
+ ><tr class="dijitReset"
+ ><td class="dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH"
+ ><div class="dijitSliderDecrementIconH" style="display:none" data-dojo-attach-point="decrementButton"><span class="dijitSliderButtonInner">-</span></div
+ ></td
+ ><td class="dijitReset"
+ ><div class="dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderLeftBumper" data-dojo-attach-event="press:_onClkDecBumper"></div
+ ></td
+ ><td class="dijitReset"
+ ><input data-dojo-attach-point="valueNode" type="hidden" ${!nameAttrSetting}
+ /><div class="dijitReset dijitSliderBarContainerH" role="presentation" data-dojo-attach-point="sliderBarContainer"
+ ><div role="presentation" data-dojo-attach-point="progressBar" class="dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH" data-dojo-attach-event="press:_onBarClick"
+ ><div class="dijitSliderMoveable dijitSliderMoveableH"
+ ><div data-dojo-attach-point="sliderHandle,focusNode" class="dijitSliderImageHandle dijitSliderImageHandleH" data-dojo-attach-event="press:_onHandleClick" role="slider" valuemin="${minimum}" valuemax="${maximum}"></div
+ ></div
+ ></div
+ ><div role="presentation" data-dojo-attach-point="remainingBar" class="dijitSliderBar dijitSliderBarH dijitSliderRemainingBar dijitSliderRemainingBarH" data-dojo-attach-event="press:_onBarClick"></div
+ ></div
+ ></td
+ ><td class="dijitReset"
+ ><div class="dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderRightBumper" data-dojo-attach-event="press:_onClkIncBumper"></div
+ ></td
+ ><td class="dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH"
+ ><div class="dijitSliderIncrementIconH" style="display:none" data-dojo-attach-point="incrementButton"><span class="dijitSliderButtonInner">+</span></div
+ ></td
+ ></tr
+ ><tr class="dijitReset"
+ ><td class="dijitReset" colspan="2"></td
+ ><td data-dojo-attach-point="containerNode,bottomDecoration" class="dijitReset dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH"></td
+ ><td class="dijitReset" colspan="2"></td
+ ></tr
+></table>
diff --git a/js/dojo/dijit/form/templates/Select.html b/js/dojo/dijit/form/templates/Select.html
new file mode 100644
index 0000000..9e917ab
--- /dev/null
+++ b/js/dojo/dijit/form/templates/Select.html
@@ -0,0 +1,14 @@
+<table class="dijit dijitReset dijitInline dijitLeft"
+ data-dojo-attach-point="_buttonNode,tableNode,focusNode" cellspacing='0' cellpadding='0'
+ role="combobox" aria-haspopup="true"
+ ><tbody role="presentation"><tr role="presentation"
+ ><td class="dijitReset dijitStretch dijitButtonContents dijitButtonNode" role="presentation"
+ ><span class="dijitReset dijitInline dijitButtonText" data-dojo-attach-point="containerNode,_popupStateNode"></span
+ ><input type="hidden" ${!nameAttrSetting} data-dojo-attach-point="valueNode" value="${value}" aria-hidden="true"
+ /></td><td class="dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton"
+ data-dojo-attach-point="titleNode" role="presentation"
+ ><div class="dijitReset dijitArrowButtonInner" role="presentation"></div
+ ><div class="dijitReset dijitArrowButtonChar" role="presentation">&#9660;</div
+ ></td
+ ></tr></tbody
+></table>
diff --git a/js/dojo/dijit/form/templates/Spinner.html b/js/dojo/dijit/form/templates/Spinner.html
new file mode 100644
index 0000000..468613d
--- /dev/null
+++ b/js/dojo/dijit/form/templates/Spinner.html
@@ -0,0 +1,27 @@
+<div class="dijit dijitReset dijitInline dijitLeft"
+ id="widget_${id}" role="presentation"
+ ><div class="dijitReset dijitButtonNode dijitSpinnerButtonContainer"
+ ><input class="dijitReset dijitInputField dijitSpinnerButtonInner" type="text" tabIndex="-1" readonly="readonly" role="presentation"
+ /><div class="dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitUpArrowButton"
+ data-dojo-attach-point="upArrowNode"
+ ><div class="dijitArrowButtonInner"
+ ><input class="dijitReset dijitInputField" value="&#9650;" type="text" tabIndex="-1" readonly="readonly" role="presentation"
+ ${_buttonInputDisabled}
+ /></div
+ ></div
+ ><div class="dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitDownArrowButton"
+ data-dojo-attach-point="downArrowNode"
+ ><div class="dijitArrowButtonInner"
+ ><input class="dijitReset dijitInputField" value="&#9660;" type="text" tabIndex="-1" readonly="readonly" role="presentation"
+ ${_buttonInputDisabled}
+ /></div
+ ></div
+ ></div
+ ><div class='dijitReset dijitValidationContainer'
+ ><input class="dijitReset dijitInputField dijitValidationIcon dijitValidationInner" value="&#935;" type="text" tabIndex="-1" readonly="readonly" role="presentation"
+ /></div
+ ><div class="dijitReset dijitInputField dijitInputContainer"
+ ><input class='dijitReset dijitInputInner' data-dojo-attach-point="textbox,focusNode" type="${type}" data-dojo-attach-event="onkeypress:_onKeyPress"
+ role="spinbutton" autocomplete="off" ${!nameAttrSetting}
+ /></div
+></div>
diff --git a/js/dojo/dijit/form/templates/TextBox.html b/js/dojo/dijit/form/templates/TextBox.html
new file mode 100644
index 0000000..fd543c6
--- /dev/null
+++ b/js/dojo/dijit/form/templates/TextBox.html
@@ -0,0 +1,6 @@
+<div class="dijit dijitReset dijitInline dijitLeft" id="widget_${id}" role="presentation"
+ ><div class="dijitReset dijitInputField dijitInputContainer"
+ ><input class="dijitReset dijitInputInner" data-dojo-attach-point='textbox,focusNode' autocomplete="off"
+ ${!nameAttrSetting} type='${type}'
+ /></div
+></div>
diff --git a/js/dojo/dijit/form/templates/ValidationTextBox.html b/js/dojo/dijit/form/templates/ValidationTextBox.html
new file mode 100644
index 0000000..d49dd8c
--- /dev/null
+++ b/js/dojo/dijit/form/templates/ValidationTextBox.html
@@ -0,0 +1,10 @@
+<div class="dijit dijitReset dijitInline dijitLeft"
+ id="widget_${id}" role="presentation"
+ ><div class='dijitReset dijitValidationContainer'
+ ><input class="dijitReset dijitInputField dijitValidationIcon dijitValidationInner" value="&#935; " type="text" tabIndex="-1" readonly="readonly" role="presentation"
+ /></div
+ ><div class="dijitReset dijitInputField dijitInputContainer"
+ ><input class="dijitReset dijitInputInner" data-dojo-attach-point='textbox,focusNode' autocomplete="off"
+ ${!nameAttrSetting} type='${type}'
+ /></div
+></div>
diff --git a/js/dojo/dijit/form/templates/VerticalSlider.html b/js/dojo/dijit/form/templates/VerticalSlider.html
new file mode 100644
index 0000000..0c72ed9
--- /dev/null
+++ b/js/dojo/dijit/form/templates/VerticalSlider.html
@@ -0,0 +1,45 @@
+<table class="dijit dijitReset dijitSlider dijitSliderV" cellspacing="0" cellpadding="0" border="0" rules="none" data-dojo-attach-event="onkeypress:_onKeyPress,onkeyup:_onKeyUp"
+ ><tr class="dijitReset"
+ ><td class="dijitReset"></td
+ ><td class="dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV"
+ ><div class="dijitSliderIncrementIconV" style="display:none" data-dojo-attach-point="decrementButton"><span class="dijitSliderButtonInner">+</span></div
+ ></td
+ ><td class="dijitReset"></td
+ ></tr
+ ><tr class="dijitReset"
+ ><td class="dijitReset"></td
+ ><td class="dijitReset"
+ ><center><div class="dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderTopBumper" data-dojo-attach-event="press:_onClkIncBumper"></div></center
+ ></td
+ ><td class="dijitReset"></td
+ ></tr
+ ><tr class="dijitReset"
+ ><td data-dojo-attach-point="leftDecoration" class="dijitReset dijitSliderDecoration dijitSliderDecorationL dijitSliderDecorationV"></td
+ ><td class="dijitReset dijitSliderDecorationC" style="height:100%;"
+ ><input data-dojo-attach-point="valueNode" type="hidden" ${!nameAttrSetting}
+ /><center class="dijitReset dijitSliderBarContainerV" role="presentation" data-dojo-attach-point="sliderBarContainer"
+ ><div role="presentation" data-dojo-attach-point="remainingBar" class="dijitSliderBar dijitSliderBarV dijitSliderRemainingBar dijitSliderRemainingBarV" data-dojo-attach-event="press:_onBarClick"><!--#5629--></div
+ ><div role="presentation" data-dojo-attach-point="progressBar" class="dijitSliderBar dijitSliderBarV dijitSliderProgressBar dijitSliderProgressBarV" data-dojo-attach-event="press:_onBarClick"
+ ><div class="dijitSliderMoveable dijitSliderMoveableV" style="vertical-align:top;"
+ ><div data-dojo-attach-point="sliderHandle,focusNode" class="dijitSliderImageHandle dijitSliderImageHandleV" data-dojo-attach-event="press:_onHandleClick" role="slider" valuemin="${minimum}" valuemax="${maximum}"></div
+ ></div
+ ></div
+ ></center
+ ></td
+ ><td data-dojo-attach-point="containerNode,rightDecoration" class="dijitReset dijitSliderDecoration dijitSliderDecorationR dijitSliderDecorationV"></td
+ ></tr
+ ><tr class="dijitReset"
+ ><td class="dijitReset"></td
+ ><td class="dijitReset"
+ ><center><div class="dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderBottomBumper" data-dojo-attach-event="press:_onClkDecBumper"></div></center
+ ></td
+ ><td class="dijitReset"></td
+ ></tr
+ ><tr class="dijitReset"
+ ><td class="dijitReset"></td
+ ><td class="dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV"
+ ><div class="dijitSliderDecrementIconV" style="display:none" data-dojo-attach-point="incrementButton"><span class="dijitSliderButtonInner">-</span></div
+ ></td
+ ><td class="dijitReset"></td
+ ></tr
+></table>