diff options
Diffstat (limited to 'js/dojo/dijit/form')
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\">●</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=\"▼ \" 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=\"Χ \" 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\">▼</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\">▼</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, """) + "'" : "") + "/>", 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\">▼</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: " ", // + + // _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: " "}); + 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=\"Χ \" 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, "&").replace(/</gm, "<") + .replace(/>/gm, ">").replace(/"/gm, """); //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 = " "; // + } + + // 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=\"▼ \" 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=\"Χ \" 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, """) + '"') : ''; + 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=\"▲\" 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=\"▼\" 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=\"Χ\" 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">●</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">▼</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="▼ " type="text" tabIndex="-1" readonly="readonly" role="presentation" + ${_buttonInputDisabled} + /></div + ><div class='dijitReset dijitValidationContainer' + ><input class="dijitReset dijitInputField dijitValidationIcon dijitValidationInner" value="Χ " 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">▼</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">▼</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="▲" 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="▼" type="text" tabIndex="-1" readonly="readonly" role="presentation" + ${_buttonInputDisabled} + /></div + ></div + ></div + ><div class='dijitReset dijitValidationContainer' + ><input class="dijitReset dijitInputField dijitValidationIcon dijitValidationInner" value="Χ" 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="Χ " 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> |
