summaryrefslogtreecommitdiff
path: root/js/dojo/dojox/form
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo/dojox/form')
-rw-r--r--js/dojo/dojox/form/BusyButton.js135
-rw-r--r--js/dojo/dojox/form/CheckedMultiSelect.js557
-rw-r--r--js/dojo/dojox/form/DateTextBox.js196
-rw-r--r--js/dojo/dojox/form/DropDownSelect.js11
-rw-r--r--js/dojo/dojox/form/DropDownStack.js15
-rw-r--r--js/dojo/dojox/form/FileInput.js95
-rw-r--r--js/dojo/dojox/form/FileInputAuto.js224
-rw-r--r--js/dojo/dojox/form/FileInputBlind.js10
-rw-r--r--js/dojo/dojox/form/FilePickerTextBox.js331
-rw-r--r--js/dojo/dojox/form/FileUploader.js1445
-rw-r--r--js/dojo/dojox/form/ListInput.js1017
-rw-r--r--js/dojo/dojox/form/Manager.js55
-rw-r--r--js/dojo/dojox/form/MultiComboBox.js66
-rw-r--r--js/dojo/dojox/form/PasswordValidator.js325
-rw-r--r--js/dojo/dojox/form/README73
-rw-r--r--js/dojo/dojox/form/RadioStack.js14
-rw-r--r--js/dojo/dojox/form/RangeSlider.js388
-rw-r--r--js/dojo/dojox/form/Rating.js105
-rw-r--r--js/dojo/dojox/form/TimeSpinner.js62
-rw-r--r--js/dojo/dojox/form/TriStateCheckBox.js246
-rw-r--r--js/dojo/dojox/form/Uploader.js392
-rw-r--r--js/dojo/dojox/form/_FormSelectWidget.js11
-rw-r--r--js/dojo/dojox/form/_HasDropDown.js11
-rw-r--r--js/dojo/dojox/form/_SelectStackMixin.js222
-rw-r--r--js/dojo/dojox/form/manager/_ClassMixin.js73
-rw-r--r--js/dojo/dojox/form/manager/_DisplayMixin.js66
-rw-r--r--js/dojo/dojox/form/manager/_EnableMixin.js84
-rw-r--r--js/dojo/dojox/form/manager/_FormMixin.js156
-rw-r--r--js/dojo/dojox/form/manager/_Mixin.js498
-rw-r--r--js/dojo/dojox/form/manager/_NodeMixin.js369
-rw-r--r--js/dojo/dojox/form/manager/_ValueMixin.js82
-rw-r--r--js/dojo/dojox/form/nls/CheckedMultiSelect.js37
-rw-r--r--js/dojo/dojox/form/nls/PasswordValidator.js41
-rw-r--r--js/dojo/dojox/form/nls/Uploader.js36
-rw-r--r--js/dojo/dojox/form/nls/ar/PasswordValidator.js9
-rw-r--r--js/dojo/dojox/form/nls/az/PasswordValidator.js9
-rw-r--r--js/dojo/dojox/form/nls/ca/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/ca/PasswordValidator.js9
-rw-r--r--js/dojo/dojox/form/nls/ca/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/cs/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/cs/PasswordValidator.js9
-rw-r--r--js/dojo/dojox/form/nls/cs/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/da/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/da/PasswordValidator.js9
-rw-r--r--js/dojo/dojox/form/nls/da/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/de/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/de/PasswordValidator.js9
-rw-r--r--js/dojo/dojox/form/nls/de/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/el/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/el/PasswordValidator.js9
-rw-r--r--js/dojo/dojox/form/nls/el/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/es/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/es/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/es/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/fi/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/fi/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/fi/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/fr/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/fr/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/fr/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/he/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/hr/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/hr/PasswordValidator.js7
-rw-r--r--js/dojo/dojox/form/nls/hr/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/hu/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/hu/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/hu/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/it/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/it/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/it/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/ja/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/ja/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/ja/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/kk/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/kk/PasswordValidator.js9
-rw-r--r--js/dojo/dojox/form/nls/kk/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/ko/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/ko/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/ko/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/nb/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/nb/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/nb/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/nl/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/nl/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/nl/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/pl/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/pl/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/pl/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/pt-pt/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/pt/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/pt/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/pt/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/ro/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/ro/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/ro/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/ru/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/ru/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/ru/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/sk/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/sk/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/sk/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/sl/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/sl/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/sl/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/sv/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/sv/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/sv/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/th/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/th/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/th/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/tr/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/tr/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/tr/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/zh-tw/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/zh-tw/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/zh-tw/Uploader.js6
-rw-r--r--js/dojo/dojox/form/nls/zh/CheckedMultiSelect.js7
-rw-r--r--js/dojo/dojox/form/nls/zh/PasswordValidator.js10
-rw-r--r--js/dojo/dojox/form/nls/zh/Uploader.js6
-rw-r--r--js/dojo/dojox/form/resources/BusyButton.css13
-rw-r--r--js/dojo/dojox/form/resources/CheckedMultiSelect.css278
-rw-r--r--js/dojo/dojox/form/resources/CheckedMultiSelect.html8
-rw-r--r--js/dojo/dojox/form/resources/FileInput.css128
-rw-r--r--js/dojo/dojox/form/resources/FileInput.html9
-rw-r--r--js/dojo/dojox/form/resources/FileInputAuto.html9
-rw-r--r--js/dojo/dojox/form/resources/FilePickerTextBox.css272
-rw-r--r--js/dojo/dojox/form/resources/FilePickerTextBox.html18
-rw-r--r--js/dojo/dojox/form/resources/FileUploader.css144
-rw-r--r--js/dojo/dojox/form/resources/HorizontalRangeSlider.html39
-rw-r--r--js/dojo/dojox/form/resources/ListInput.css76
-rw-r--r--js/dojo/dojox/form/resources/PasswordValidator.html3
-rw-r--r--js/dojo/dojox/form/resources/RangeSlider.css30
-rw-r--r--js/dojo/dojox/form/resources/Rating.css24
-rw-r--r--js/dojo/dojox/form/resources/RecieveFile.php37
-rw-r--r--js/dojo/dojox/form/resources/TriStateCheckBox.css137
-rw-r--r--js/dojo/dojox/form/resources/TriStateCheckBox.html5
-rw-r--r--js/dojo/dojox/form/resources/Uploader.html18
-rw-r--r--js/dojo/dojox/form/resources/UploaderFileList.css53
-rw-r--r--js/dojo/dojox/form/resources/VerticalRangeSlider.html49
-rw-r--r--js/dojo/dojox/form/resources/_CheckedMultiSelectItem.html5
-rw-r--r--js/dojo/dojox/form/resources/_CheckedMultiSelectMenuItem.html10
-rw-r--r--js/dojo/dojox/form/resources/fileuploader.swfbin0 -> 12844 bytes
-rw-r--r--js/dojo/dojox/form/resources/images/loading_wheel.gifbin0 -> 1266 bytes
-rw-r--r--js/dojo/dojox/form/resources/images/nihiloFolderSprite.gifbin0 -> 331 bytes
-rw-r--r--js/dojo/dojox/form/resources/images/rating_empty.gifbin0 -> 934 bytes
-rw-r--r--js/dojo/dojox/form/resources/images/rating_full.gifbin0 -> 936 bytes
-rw-r--r--js/dojo/dojox/form/resources/images/soriaFolderSprite.gifbin0 -> 335 bytes
-rw-r--r--js/dojo/dojox/form/resources/images/tristatecheckboxStates.pngbin0 -> 1458 bytes
-rw-r--r--js/dojo/dojox/form/resources/images/tundraFolderSprite.gifbin0 -> 318 bytes
-rw-r--r--js/dojo/dojox/form/resources/uploader.swfbin0 -> 11356 bytes
-rw-r--r--js/dojo/dojox/form/uploader/Base.js126
-rw-r--r--js/dojo/dojox/form/uploader/FileList.js202
-rw-r--r--js/dojo/dojox/form/uploader/plugins/Flash.js307
-rw-r--r--js/dojo/dojox/form/uploader/plugins/HTML5.js241
-rw-r--r--js/dojo/dojox/form/uploader/plugins/IFrame.js79
155 files changed, 10418 insertions, 0 deletions
diff --git a/js/dojo/dojox/form/BusyButton.js b/js/dojo/dojox/form/BusyButton.js
new file mode 100644
index 0000000..b3bbd14
--- /dev/null
+++ b/js/dojo/dojox/form/BusyButton.js
@@ -0,0 +1,135 @@
+//>>built
+define("dojox/form/BusyButton", [
+ "dojo/_base/lang",
+ "dojo/dom-attr",
+ "dojo/dom-class",
+ "dijit/form/Button",
+ "dijit/form/DropDownButton",
+ "dijit/form/ComboButton",
+ "dojo/i18n",
+ "dojo/i18n!dijit/nls/loading",
+ "dojo/_base/declare"
+], function(lang, domAttr, domClass, Button, DropDownButton, ComboButton, i18n, nlsLoading, declare){
+ /*=====
+ Button = dijit.form.Button;
+ DropDownButton = dijit.form.DropDownButton;
+ ComboButton = dijit.form.ComboButton;
+ =====*/
+var _BusyButtonMixin = declare("dojox.form._BusyButtonMixin", null, {
+
+ isBusy: false,
+ busyLabel: "", // text while button is busy
+ timeout: null, // timeout, should be controlled by xhr call
+ useIcon: true, // use a busy icon
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ if(!this.busyLabel){
+ this.busyLabel = i18n.getLocalization("dijit", "loading", this.lang).loadingState;
+ }
+ },
+
+ postCreate: function(){
+ // summary:
+ // stores initial label and timeout for reference
+ this.inherited(arguments);
+ this._label = this.containerNode.innerHTML;
+ this._initTimeout = this.timeout;
+
+ // for initial busy buttons
+ if(this.isBusy){
+ this.makeBusy();
+ }
+ },
+
+ makeBusy: function(){
+ // summary:
+ // sets state from idle to busy
+ this.isBusy = true;
+ this.set("disabled", true);
+
+ this.setLabel(this.busyLabel, this.timeout);
+ },
+
+ cancel: function(){
+ // summary:
+ // if no timeout is set or for other reason the user can put the button back
+ // to being idle
+ this.set("disabled", false);
+ this.isBusy = false;
+ this.setLabel(this._label);
+ if(this._timeout){ clearTimeout(this._timeout); }
+ this.timeout = this._initTimeout;
+ },
+
+ resetTimeout: function(/*Int*/ timeout){
+ // summary:
+ // to reset existing timeout and setting a new timeout
+ if(this._timeout){
+ clearTimeout(this._timeout);
+ }
+
+ // new timeout
+ if(timeout){
+ this._timeout = setTimeout(lang.hitch(this, function(){
+ this.cancel();
+ }), timeout);
+ }else if(timeout == undefined || timeout === 0){
+ this.cancel();
+ }
+ },
+
+ setLabel: function(/*String*/ content, /*Int*/ timeout){
+ // summary:
+ // setting a label and optional timeout of the labels state
+
+ // this.inherited(arguments); FIXME: throws an Unknown runtime error
+
+ // Begin IE hack
+ // summary: reset the label (text) of the button; takes an HTML string
+ this.label = content;
+ // remove children
+ while(this.containerNode.firstChild){
+ this.containerNode.removeChild(this.containerNode.firstChild);
+ }
+ this.containerNode.innerHTML = this.label;
+
+ if(this.showLabel == false && !domAttr.get(this.domNode, "title")){
+ this.titleNode.title=lang.trim(this.containerNode.innerText || this.containerNode.textContent || '');
+ }
+ // End IE hack
+
+ // setting timeout
+ if(timeout){
+ this.resetTimeout(timeout);
+ }else{
+ this.timeout = null;
+ }
+
+ // create optional busy image
+ if(this.useIcon && this.isBusy){
+ var node = new Image();
+ node.src = this._blankGif;
+ domAttr.set(node, "id", this.id+"_icon");
+ domClass.add(node, "dojoxBusyButtonIcon");
+ this.containerNode.appendChild(node);
+ }
+ },
+
+ _onClick: function(e){
+ // summary:
+ // on button click the button state gets changed
+
+ // only do something if button is not busy
+ if(!this.isBusy){
+ this.inherited(arguments); // calls onClick()
+ this.makeBusy();
+ }
+ }
+});
+
+var BusyButton = declare("dojox.form.BusyButton", [Button, _BusyButtonMixin], {});
+declare("dojox.form.BusyComboButton", [ComboButton, _BusyButtonMixin], {});
+declare("dojox.form.BusyDropDownButton", [DropDownButton, _BusyButtonMixin], {});
+return BusyButton;
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/CheckedMultiSelect.js b/js/dojo/dojox/form/CheckedMultiSelect.js
new file mode 100644
index 0000000..1462ff3
--- /dev/null
+++ b/js/dojo/dojox/form/CheckedMultiSelect.js
@@ -0,0 +1,557 @@
+//>>built
+require({cache:{
+'url:dojox/form/resources/_CheckedMultiSelectMenuItem.html':"<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" role=\"menuitemcheckbox\" tabIndex=\"-1\"\n\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\"\n\t><td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\"\n\t\t><div src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuItemIcon ${_iconClass}\" dojoAttachPoint=\"iconNode\"\n\t\t\t><input class=\"dojoxCheckedMultiSelectCheckBoxInput\" dojoAttachPoint=\"inputNode\" type=\"${_type.type}\"\n\t\t/></div></td\n\t><td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode,labelNode\"></td\n\t><td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td\n\t><td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">&nbsp;</td\n></tr>",
+'url:dojox/form/resources/_CheckedMultiSelectItem.html':"<div class=\"dijitReset ${baseClass}\"\n\t><input class=\"${baseClass}Box\" data-dojo-type=\"dijit.form.CheckBox\" data-dojo-attach-point=\"checkBox\" \n\t\tdata-dojo-attach-event=\"_onClick:_changeBox\" type=\"${_type.type}\" baseClass=\"${_type.baseClass}\"\n\t/><div class=\"dijitInline ${baseClass}Label\" data-dojo-attach-point=\"labelNode\" data-dojo-attach-event=\"onclick:_onClick\"></div\n></div>\n",
+'url:dojox/form/resources/CheckedMultiSelect.html':"<div class=\"dijit dijitReset dijitInline dijitLeft\" id=\"widget_${id}\"\n\t><div data-dojo-attach-point=\"comboButtonNode\"\n\t></div\n\t><div data-dojo-attach-point=\"selectNode\" class=\"dijit dijitReset dijitInline ${baseClass}Wrapper\" data-dojo-attach-event=\"onmousedown:_onMouseDown,onclick:focus\"\n\t\t><select class=\"${baseClass}Select dojoxCheckedMultiSelectHidden\" multiple=\"true\" data-dojo-attach-point=\"containerNode,focusNode\"></select\n\t\t><div data-dojo-attach-point=\"wrapperDiv\"></div\n\t></div\n></div>"}});
+define("dojox/form/CheckedMultiSelect", [
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojo/_base/event",
+ "dojo/dom-geometry",
+ "dojo/dom-class",
+ "dojo/dom-construct",
+ "dojo/i18n",
+ "dijit/_Widget",
+ "dijit/_TemplatedMixin",
+ "dijit/_WidgetsInTemplateMixin",
+ "dijit/registry",
+ "dijit/Menu",
+ "dijit/MenuItem",
+ "dijit/Tooltip",
+ "dijit/form/_FormSelectWidget",
+ "dijit/form/ComboButton",
+ "dojo/text!dojox/form/resources/_CheckedMultiSelectMenuItem.html",
+ "dojo/text!dojox/form/resources/_CheckedMultiSelectItem.html",
+ "dojo/text!dojox/form/resources/CheckedMultiSelect.html",
+ "dojo/i18n!dojox/form/nls/CheckedMultiSelect",
+ "dijit/form/CheckBox" // template
+], function(declare, lang, array, event, domGeometry, domClass, domConstruct, i18n, Widget, TemplatedMixin, WidgetsInTemplateMixin, registry, Menu, MenuItem, Tooltip, FormSelectWidget, ComboButton, CheckedMultiSelectMenuItem, CheckedMultiSelectItem, CheckedMultiSelect, nlsCheckedMultiSelect){
+
+ // module:
+ // dojox/form/CheckedMultiSelect
+ // summary:
+ // Extends the core dojox.form.CheckedMultiSelect to provide a "checkbox" selector
+ //
+
+ /*=====
+ Widget = dijit._Widget;
+ TemplatedMixin = dijit._TemplatedMixin;
+ WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
+ Menu = dijit.Menu;
+ MenuItem = dijit.MenuItem;
+ FormSelectWidget = dijit.form._FormSelectWidget;
+ =====*/
+var formCheckedMultiSelectItem = declare("dojox.form._CheckedMultiSelectItem", [Widget, TemplatedMixin, WidgetsInTemplateMixin], {
+ // summary:
+ // The individual items for a CheckedMultiSelect
+
+ templateString: CheckedMultiSelectItem,
+
+ baseClass: "dojoxMultiSelectItem",
+
+ // option: dojox.form.__SelectOption
+ // The option that is associated with this item
+ option: null,
+ parent: null,
+
+ // disabled: boolean
+ // Whether or not this widget is disabled
+ disabled: false,
+
+ // readOnly: boolean
+ // Whether or not this widget is readOnly
+ readOnly: false,
+
+ postMixInProperties: function(){
+ // summary:
+ // Set the appropriate _subClass value - based on if we are multi-
+ // or single-select
+ this._type = this.parent.multiple ?
+ {type: "checkbox", baseClass: "dijitCheckBox"} :
+ {type: "radio", baseClass: "dijitRadio"};
+ this.disabled = this.option.disabled = this.option.disabled||false;
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ // summary:
+ // Set innerHTML here - since the template gets messed up sometimes
+ // with rich text
+ this.inherited(arguments);
+ this.labelNode.innerHTML = this.option.label;
+ },
+
+ _changeBox: function(){
+ // summary:
+ // Called to force the select to match the state of the check box
+ // (only on click of the checkbox) Radio-based calls _setValueAttr
+ // instead.
+ if(this.get("disabled") || this.get("readOnly")){ return; }
+ if(this.parent.multiple){
+ this.option.selected = this.checkBox.get('value') && true;
+ }else{
+ this.parent.set('value', this.option.value);
+ }
+ // fire the parent's change
+ this.parent._updateSelection();
+
+ // refocus the parent
+ this.parent.focus();
+ },
+
+ _onClick: function(e){
+ // summary:
+ // Sets the click state (passes through to the check box)
+ if(this.get("disabled") || this.get("readOnly")){
+ event.stop(e);
+ }else{
+ this.checkBox._onClick(e);
+ }
+ },
+
+ _updateBox: function(){
+ // summary:
+ // Called to force the box to match the state of the select
+ this.checkBox.set('value', this.option.selected);
+ },
+
+ _setDisabledAttr: function(value){
+ // summary:
+ // Disables (or enables) all the children as well
+ this.disabled = value||this.option.disabled;
+ this.checkBox.set("disabled", this.disabled);
+ domClass.toggle(this.domNode, "dojoxMultiSelectDisabled", this.disabled);
+ },
+
+ _setReadOnlyAttr: function(value){
+ // summary:
+ // Sets read only (or unsets) all the children as well
+ this.checkBox.set("readOnly", value);
+ this.readOnly = value;
+ }
+});
+
+var formCheckedMultiSelectMenu = declare("dojox.form._CheckedMultiSelectMenu", Menu, {
+ // summary:
+ // An internally-used menu for dropdown that allows us a vertical scrollbar
+ multiple: false,
+
+ // 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),
+ 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 + " dojoxCheckedMultiSelectMenu";
+ o.className = "dijitReset dijitMenuTable";
+ o.setAttribute("role", "listbox");
+ n.setAttribute("role", "presentation");
+ n.appendChild(o);
+ },
+
+ resize: function(/*Object*/ mb){
+ // summary:
+ // Overridden so that we are able to handle resizing our
+ // internal widget. Note that this is not a "full" resize
+ // implementation - it only works correctly if you pass it a
+ // marginBox.
+ //
+ // mb: Object
+ // The margin box to set this dropdown to.
+ if(mb){
+ 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%";
+ }
+ }
+ },
+
+ onClose: function(){
+ this.inherited(arguments);
+ if(this.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.menuTableNode.style.width = "";
+ }
+ },
+
+ onItemClick: function(/*dijit._Widget*/ item, /*Event*/ evt){
+ // summary:
+ // Handle clicks on an item.
+ // tags:
+ // private
+ // this can't be done in _onFocus since the _onFocus events occurs asynchronously
+ if(typeof this.isShowingNow == 'undefined'){ // non-popup menu
+ this._markActive();
+ }
+
+ this.focusChild(item);
+
+ if(item.disabled || item.readOnly){ return false; }
+
+ if(!this.multiple){
+ // before calling user defined handler, close hierarchy of menus
+ // and restore focus to place it was when menu was opened
+ this.onExecute();
+ }
+ // user defined handler for click
+ item.onClick(evt);
+ }
+});
+
+var formCheckedMultiSelectMenuItem = declare("dojox.form._CheckedMultiSelectMenuItem", MenuItem, {
+ // summary:
+ // A checkbox-like menu item for toggling on and off
+
+ templateString: CheckedMultiSelectMenuItem,
+
+ // option: dojox.form.__SelectOption
+ // The option that is associated with this item
+ option: null,
+
+ // reference of dojox.form._CheckedMultiSelectMenu
+ parent: null,
+
+ // icon of the checkbox/radio button
+ _iconClass: "",
+
+ postMixInProperties: function(){
+ // summary:
+ // Set the appropriate _subClass value - based on if we are multi-
+ // or single-select
+ if(this.parent.multiple){
+ this._iconClass = "dojoxCheckedMultiSelectMenuCheckBoxItemIcon";
+ this._type = {type: "checkbox"};
+ }else{
+ this._iconClass = "";
+ this._type = {type: "hidden"};
+ }
+ this.disabled = this.option.disabled;
+ this.checked = this.option.selected;
+ this.label = this.option.label;
+ this.readOnly = this.option.readOnly;
+ this.inherited(arguments);
+ },
+
+ onChange: function(/*Boolean*/ checked){
+ // summary:
+ // User defined function to handle check/uncheck events
+ // tags:
+ // callback
+ },
+
+ _updateBox: function(){
+ // summary:
+ // Called to force the box to match the state of the select
+ domClass.toggle(this.domNode, "dojoxCheckedMultiSelectMenuItemChecked", !!this.option.selected);
+ this.domNode.setAttribute("aria-checked", this.option.selected);
+ this.inputNode.checked = this.option.selected;
+ if(!this.parent.multiple){
+ domClass.toggle(this.domNode, "dijitSelectSelectedOption", !!this.option.selected);
+ }
+ },
+
+ _onClick: function(/*Event*/ e){
+ // summary:
+ // Clicking this item just toggles its state
+ // tags:
+ // private
+ if(!this.disabled && !this.readOnly){
+ if(this.parent.multiple){
+ this.option.selected = !this.option.selected;
+ this.parent.onChange();
+ this.onChange(this.option.selected);
+ }else{
+ if(!this.option.selected){
+ array.forEach(this.parent.getChildren(), function(item){
+ item.option.selected = false;
+ });
+ this.option.selected = true;
+ this.parent.onChange();
+ this.onChange(this.option.selected);
+ }
+ }
+ }
+ this.inherited(arguments);
+ }
+});
+
+var formCheckedMultiSelect = declare("dojox.form.CheckedMultiSelect", FormSelectWidget, {
+ // summary:
+ // Extends the core dijit MultiSelect to provide a "checkbox" selector
+
+ templateString: CheckedMultiSelect,
+
+ baseClass: "dojoxCheckedMultiSelect",
+
+ // required: Boolean
+ // User is required to check at least one item.
+ required: false,
+
+ // invalidMessage: String
+ // The message to display if value is invalid.
+ invalidMessage: "$_unset_$",
+
+ // _message: String
+ // Currently displayed message
+ _message: "",
+
+ // dropDown: Boolean
+ // Drop down version or not
+ dropDown: false,
+
+ // labelText: String
+ // Label of the drop down button
+ labelText: "",
+
+ // tooltipPosition: String[]
+ // See description of `Tooltip.defaultPosition` for details on this parameter.
+ tooltipPosition: [],
+
+ setStore: function(store, selectedValue, fetchArgs){
+ // summary:
+ // If there is any items selected in the store, the value
+ // of the widget will be set to the values of these items.
+ this.inherited(arguments);
+ var setSelectedItems = function(items){
+ var value = array.map(items, function(item){ return item.value[0]; });
+ if(value.length){
+ this.set("value", value);
+ }
+ };
+ this.store.fetch({query:{selected: true}, onComplete: setSelectedItems, scope: this});
+ },
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this._nlsResources = i18n.getLocalization("dojox.form", "CheckedMultiSelect", this.lang);
+ if(this.invalidMessage == "$_unset_$"){ this.invalidMessage = this._nlsResources.invalidMessage; }
+ },
+
+ _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;
+ }
+ if(this.dropDown){
+ domClass.toggle(this.selectNode, "dojoxCheckedMultiSelectHidden");
+ this.dropDownMenu = new formCheckedMultiSelectMenu({
+ id: this.id + "_menu",
+ style: "display: none;",
+ multiple: this.multiple,
+ onChange: lang.hitch(this, "_updateSelection")
+ });
+ }
+ },
+
+ startup: function(){
+ // summary:
+ // Set the value to be the first, or the selected index
+ this.inherited(arguments);
+ if(this.dropDown){
+ this.dropDownButton = new ComboButton({
+ label: this.labelText,
+ dropDown: this.dropDownMenu,
+ baseClass: "dojoxCheckedMultiSelectButton",
+ maxHeight: this.maxHeight
+ }, this.comboButtonNode);
+ }
+ },
+
+ _onMouseDown: function(e){
+ // summary:
+ // Cancels the mousedown event to prevent others from stealing
+ // focus
+ event.stop(e);
+ },
+
+ validator: function(){
+ // summary:
+ // Overridable function used to validate that an item is selected if required =
+ // true.
+ // tags:
+ // protected
+ if(!this.required){ return true; }
+ return array.some(this.getOptions(), function(opt){
+ return opt.selected && opt.value != null && opt.value.toString().length != 0;
+ });
+ },
+
+ validate: function(isFocused){
+ Tooltip.hide(this.domNode);
+ var isValid = this.isValid(isFocused);
+ if(!isValid){ this.displayMessage(this.invalidMessage); }
+ return isValid;
+ },
+
+ isValid: function(/*Boolean*/ isFocused){
+ // summary:
+ // Tests if the required items are selected.
+ // Can override with your own routine in a subclass.
+ // tags:
+ // protected
+ return this.validator();
+ },
+
+ getErrorMessage: function(/*Boolean*/ isFocused){
+ // summary:
+ // Return an error message to show if appropriate
+ // tags:
+ // protected
+ return this.invalidMessage;
+ },
+
+ displayMessage: function(/*String*/ message){
+ // summary:
+ // Overridable method to display validation errors/hints.
+ // By default uses a tooltip.
+ // tags:
+ // extension
+ Tooltip.hide(this.domNode);
+ if(message){
+ Tooltip.show(message, this.domNode, this.tooltipPosition);
+ }
+ },
+
+ onAfterAddOptionItem: function(item, option){
+ // summary:
+ // a function that can be connected to in order to receive a
+ // notification that an item as been added to this dijit.
+ },
+
+ _addOptionItem: function(/* dojox.form.__SelectOption */ option){
+ var item;
+ if(this.dropDown){
+ item = new formCheckedMultiSelectMenuItem({
+ option: option,
+ parent: this.dropDownMenu
+ });
+ this.dropDownMenu.addChild(item);
+ }else{
+ item = new formCheckedMultiSelectItem({
+ option: option,
+ parent: this
+ });
+ this.wrapperDiv.appendChild(item.domNode);
+ }
+ this.onAfterAddOptionItem(item, option);
+ },
+
+ _refreshState: function(){
+ // summary:
+ // Validate if selection changes.
+ this.validate(this.focused);
+ },
+
+ onChange: function(newValue){
+ // summary:
+ // Validate if selection changes.
+ this._refreshState();
+ },
+
+ reset: function(){
+ // summary: Overridden so that the state will be cleared.
+ this.inherited(arguments);
+ Tooltip.hide(this.domNode);
+ },
+
+ _updateSelection: function(){
+ this.inherited(arguments);
+ this._handleOnChange(this.value);
+ array.forEach(this._getChildren(), function(item){
+ item._updateBox();
+ });
+ if(this.dropDown && this.dropDownButton){
+ var i = 0, label = "";
+ array.forEach(this.options, function(option){
+ if(option.selected){
+ i++;
+ label = option.label;
+ }
+ });
+ this.dropDownButton.set("label", this.multiple ?
+ lang.replace(this._nlsResources.multiSelectLabelText, {num: i}) :
+ label);
+ }
+ },
+
+ _getChildren: function(){
+ if(this.dropDown){
+ return this.dropDownMenu.getChildren();
+ }else{
+ return array.map(this.wrapperDiv.childNodes, function(n){
+ return registry.byNode(n);
+ });
+ }
+ },
+
+ invertSelection: function(onChange){
+ // summary: Invert the selection
+ // onChange: Boolean
+ // If null, onChange is not fired.
+ if(this.multiple){
+ array.forEach(this.options, function(i){
+ i.selected = !i.selected;
+ });
+ this._updateSelection();
+ }
+ },
+
+ _setDisabledAttr: function(value){
+ // summary:
+ // Disable (or enable) all the children as well
+ this.inherited(arguments);
+ if(this.dropDown){
+ this.dropDownButton.set("disabled", value);
+ }
+ array.forEach(this._getChildren(), function(node){
+ if(node && node.set){
+ node.set("disabled", value);
+ }
+ });
+ },
+
+ _setReadOnlyAttr: function(value){
+ // summary:
+ // Sets read only (or unsets) all the children as well
+ this.inherited(arguments);
+ if("readOnly" in this.attributeMap){
+ this._attrToDom("readOnly", value);
+ }
+ this.readOnly = value;
+ array.forEach(this._getChildren(), function(node){
+ if(node && node.set){
+ node.set("readOnly", value);
+ }
+ });
+ },
+
+ uninitialize: function(){
+ Tooltip.hide(this.domNode);
+ // Make sure these children are destroyed
+ array.forEach(this._getChildren(), function(child){
+ child.destroyRecursive();
+ });
+ this.inherited(arguments);
+ }
+});
+
+return formCheckedMultiSelect;
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/DateTextBox.js b/js/dojo/dojox/form/DateTextBox.js
new file mode 100644
index 0000000..beda716
--- /dev/null
+++ b/js/dojo/dojox/form/DateTextBox.js
@@ -0,0 +1,196 @@
+//>>built
+define("dojox/form/DateTextBox", [
+ "dojo/_base/kernel",
+ "dojo/_base/lang",
+ "dojo/dom-style",
+ "dojox/widget/Calendar",
+ "dojox/widget/CalendarViews",
+ "dijit/form/_DateTimeTextBox",
+ "dijit/form/TextBox",
+ "dojo/_base/declare"
+], function(kernel, lang, domStyle, Calendar, CalendarViews, _DateTimeTextBox, TextBox, declare){
+kernel.experimental("dojox.form.DateTextBox");
+
+ /*=====
+ _DateTimeTextBox = dijit.form._DateTimeTextBox;
+ =====*/
+var DateTextBox = declare( "dojox.form.DateTextBox", _DateTimeTextBox,
+ {
+ // summary:
+ // A validating, serializable, range-bound date text box with a popup calendar
+
+ // popupClass: String
+ // The popup widget to use. In this case, a calendar with Day, Month and Year views.
+ popupClass: "dojox.widget.Calendar",
+ _selector: "date",
+
+ openDropDown: function(){
+ this.inherited(arguments);
+ domStyle.set(this.dropDown.domNode.parentNode, "position", "absolute");
+ }
+ }
+);
+
+
+declare( "dojox.form.DayTextBox", DateTextBox,
+ {
+ // summary:
+ // A validating, serializable, range-bound date text box with a popup calendar that contains just months.
+
+ // popupClass: String
+ // The popup widget to use. In this case, a calendar with just a Month view.
+ popupClass: "dojox.widget.DailyCalendar",
+
+ parse: function(displayVal){
+ return displayVal;
+ },
+
+ format: function(value){
+ return value.getDate ? value.getDate() : value;
+ },
+ validator: function(value){
+ var num = Number(value);
+ var isInt = /(^-?\d\d*$)/.test(String(value));
+ return value == "" || value == null || (isInt && num >= 1 && num <= 31);
+ },
+
+ _setValueAttr: function(value, priorityChange, formattedValue){
+ if(value){
+ if(value.getDate){
+ value = value.getDate();
+ }
+ }
+ TextBox.prototype._setValueAttr.call(this, value, priorityChange, formattedValue);
+ },
+
+ openDropDown: function(){
+ this.inherited(arguments);
+
+ this.dropDown.onValueSelected = lang.hitch(this, function(value){
+ this.focus(); // focus the textbox before the popup closes to avoid reopening the popup
+ setTimeout(lang.hitch(this, "closeDropDown"), 1); // allow focus time to take
+
+ TextBox.prototype._setValueAttr.call(this, String(value.getDate()), true, String(value.getDate()));
+ });
+ }
+ }
+);
+
+declare( "dojox.form.MonthTextBox", DateTextBox,
+ {
+ // summary:
+ // A validating, serializable, range-bound date text box with a popup calendar that contains only years
+
+ // popupClass: String
+ // The popup widget to use. In this case, a calendar with just a Year view.
+ popupClass: "dojox.widget.MonthlyCalendar",
+
+ selector: "date",
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this.constraints.datePattern = "MM";
+ },
+
+ format: function(value){
+ if(!value && value !== 0){
+ return 1;
+ }
+ if(value.getMonth){
+ return value.getMonth() + 1;
+ }
+ return Number(value) + 1;
+ },
+
+ parse: function(value, constraints){
+ return Number(value) - 1;
+ },
+
+ serialize: function(value, constraints){
+ return String(value);
+ },
+
+ validator: function(value){
+ var num = Number(value);
+ var isInt = /(^-?\d\d*$)/.test(String(value));
+ return value == "" || value == null || (isInt && num >= 1 && num <= 12);
+ },
+
+ _setValueAttr: function(value, priorityChange, formattedValue){
+ if(value){
+ if(value.getMonth){
+ value = value.getMonth();
+ }
+ }
+ TextBox.prototype._setValueAttr.call(this, value, priorityChange, formattedValue);
+ },
+
+ openDropDown: function(){
+ this.inherited(arguments);
+
+ this.dropDown.onValueSelected = lang.hitch(this, function(value){
+ this.focus(); // focus the textbox before the popup closes to avoid reopening the popup
+ setTimeout(lang.hitch(this, "closeDropDown"), 1); // allow focus time to take
+ TextBox.prototype._setValueAttr.call(this, value, true, value);
+ });
+ }
+ }
+);
+
+
+declare( "dojox.form.YearTextBox", DateTextBox,
+ {
+ // summary:
+ // A validating, serializable, range-bound date text box with a popup calendar that contains only years
+
+ popupClass: "dojox.widget.YearlyCalendar",
+
+ format: function(value){
+ //console.log('Year format ' + value);
+ if(typeof value == "string"){
+ return value;
+ }
+ else if(value.getFullYear){
+ return value.getFullYear();
+ }
+ return value;
+ },
+
+ validator: function(value){
+ return value == "" || value == null || /(^-?\d\d*$)/.test(String(value));
+ },
+
+ _setValueAttr: function(value, priorityChange, formattedValue){
+ if(value){
+ if(value.getFullYear){
+ value = value.getFullYear();
+ }
+ }
+ TextBox.prototype._setValueAttr.call(this, value, priorityChange, formattedValue);
+ },
+
+ openDropDown: function(){
+ this.inherited(arguments);
+ //console.log('yearly openDropDown and value = ' + this.get('value'));
+
+ this.dropDown.onValueSelected = lang.hitch(this, function(value){
+ this.focus(); // focus the textbox before the popup closes to avoid reopening the popup
+ setTimeout(lang.hitch(this, "closeDropDown"), 1); // allow focus time to take
+ TextBox.prototype._setValueAttr.call(this,value, true, value);
+ });
+ },
+
+ parse: function(/*String*/value, /*dojo.date.locale.__FormatOptions*/constraints){
+ return value || (this._isEmpty(value) ? null : undefined); // Date
+ },
+
+ filter: function(val){
+ if(val && val.getFullYear){
+ return val.getFullYear().toString();
+ }
+ return this.inherited(arguments);
+ }
+ }
+);
+return DateTextBox;
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/DropDownSelect.js b/js/dojo/dojox/form/DropDownSelect.js
new file mode 100644
index 0000000..7ec2f0a
--- /dev/null
+++ b/js/dojo/dojox/form/DropDownSelect.js
@@ -0,0 +1,11 @@
+//>>built
+define("dojox/form/DropDownSelect", [
+ "dojo/_base/kernel",
+ "dojo/_base/lang",
+ "dijit/form/Select"
+], function(kernel, lang, Select){
+ kernel.deprecated("dojox.form.DropDownSelect", "Use Select instead", "2.0");
+
+ lang.setObject("dojox.form.DropDownSelect", Select);
+ return Select;
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/DropDownStack.js b/js/dojo/dojox/form/DropDownStack.js
new file mode 100644
index 0000000..2c185a4
--- /dev/null
+++ b/js/dojo/dojox/form/DropDownStack.js
@@ -0,0 +1,15 @@
+//>>built
+define("dojox/form/DropDownStack", [
+ "dijit/form/Select",
+ "./_SelectStackMixin",
+ "dojo/_base/declare"
+], function(Select, _SelectStackMixin, declare){
+ /*=====
+ Select = dijit.form.Select;
+ _SelectStackMixin = dojox.form._SelectStackMixin;
+ =====*/
+ return declare("dojox.form.DropDownStack", [ Select, _SelectStackMixin ], {
+ // summary: A dropdown-based select stack.
+
+ });
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/FileInput.js b/js/dojo/dojox/form/FileInput.js
new file mode 100644
index 0000000..97657ea
--- /dev/null
+++ b/js/dojo/dojox/form/FileInput.js
@@ -0,0 +1,95 @@
+//>>built
+require({cache:{
+'url:dojox/form/resources/FileInput.html':"<div class=\"dijitFileInput\">\n\t<input id=\"${id}\" class=\"dijitFileInputReal\" type=\"file\" dojoAttachPoint=\"fileInput\" name=\"${name}\" />\n\t<div class=\"dijitFakeInput\">\n\t\t<input class=\"dijitFileInputVisible\" type=\"text\" dojoAttachPoint=\"focusNode, inputNode\" />\n\t\t<div class=\"dijitInline dijitFileInputText\" dojoAttachPoint=\"titleNode\">${label}</div>\n\t\t<div class=\"dijitInline dijitFileInputButton\" dojoAttachPoint=\"cancelNode\" \n\t\t\tdojoAttachEvent=\"onclick:reset\">${cancelText}</div>\n\t</div>\n</div>\n"}});
+define("dojox/form/FileInput", [
+ "dojo/_base/declare",
+ "dojo/_base/kernel",
+ "dojo/_base/fx",
+ "dojo/dom-attr",
+ "dojo/dom-class",
+ "dojo/text!./resources/FileInput.html",
+ "dijit/form/_FormWidget",
+ "dijit/_Templated"
+],
+function(declare, kernel, fx, domAttr, domClass, template, FormWidget, Templated){
+kernel.experimental("dojox.form.FileInput");
+
+ /*=====
+ FormWidget = dijit.form._FormWidget;
+ =====*/
+declare("dojox.form.FileInput", FormWidget,
+ {
+ // summary: A styled input type="file"
+ //
+ // description: A input type="file" form widget, with a button for uploading to be styled via css,
+ // a cancel button to clear selection, and FormWidget mixin to provide standard dijit.form.Form
+ // support (FIXME: maybe not fully implemented)
+
+ // label: String
+ // the title text of the "Browse" button
+ label: "Browse ...",
+
+ // cancelText: String
+ // the title of the "Cancel" button
+ cancelText: "Cancel",
+
+ // name: String
+ // ugh, this should be pulled from this.domNode
+ name: "uploadFile",
+
+ templateString: template,
+
+ startup: function(){
+ // summary: listen for changes on our real file input
+ this._listener = this.connect(this.fileInput,"onchange","_matchValue");
+ this._keyListener = this.connect(this.fileInput,"onkeyup","_matchValue");
+ },
+
+ //get rid of the this.connect in _FormWidget.postCreate to allow IE to show
+ //the file picker dialog properly
+ postCreate: function(){},
+
+ _matchValue: function(){
+ // summary: set the content of the upper input based on the semi-hidden file input
+ this.inputNode.value = this.fileInput.value;
+ if(this.inputNode.value){
+ this.cancelNode.style.visibility = "visible";
+ fx.fadeIn({ node: this.cancelNode, duration:275 }).play();
+ }
+ },
+
+ setLabel: function(/* String */label,/* String? */cssClass){
+ // summary: method to allow use to change button label
+ this.titleNode.innerHTML = label;
+ },
+
+ reset: function(/* Event */e){
+ // summary: on click of cancel button, since we can't clear the input because of
+ // security reasons, we destroy it, and add a new one in it's place.
+ this.disconnect(this._listener);
+ this.disconnect(this._keyListener);
+ if(this.fileInput){
+ this.domNode.removeChild(this.fileInput);
+ }
+ fx.fadeOut({ node: this.cancelNode, duration:275 }).play();
+
+ // should we use cloneNode()? can we?
+ this.fileInput = document.createElement('input');
+ // domAttr.set(this.fileInput,{
+ // "type":"file", "id":this.id, "name": this.name
+ //});
+ this.fileInput.setAttribute("type","file");
+ this.fileInput.setAttribute("id", this.id);
+ this.fileInput.setAttribute("name", this.name);
+ domClass.add(this.fileInput,"dijitFileInputReal");
+ this.domNode.appendChild(this.fileInput);
+
+ this._keyListener = this.connect(this.fileInput, "onkeyup", "_matchValue");
+ this._listener = this.connect(this.fileInput, "onchange", "_matchValue");
+ this.inputNode.value = "";
+ }
+
+});
+
+return dojox.form.FileInput;
+});
diff --git a/js/dojo/dojox/form/FileInputAuto.js b/js/dojo/dojox/form/FileInputAuto.js
new file mode 100644
index 0000000..545211d
--- /dev/null
+++ b/js/dojo/dojox/form/FileInputAuto.js
@@ -0,0 +1,224 @@
+//>>built
+require({cache:{
+'url:dojox/form/resources/FileInputAuto.html':"<div class=\"dijitFileInput\">\n\t<input id=\"${id}\" name=\"${name}\" class=\"dijitFileInputReal\" type=\"file\" dojoAttachPoint=\"fileInput\" />\n\t<div class=\"dijitFakeInput\" dojoAttachPoint=\"fakeNodeHolder\">\n\t\t<input class=\"dijitFileInputVisible\" type=\"text\" dojoAttachPoint=\"focusNode, inputNode\" />\n\t\t<div class=\"dijitInline dijitFileInputText\" dojoAttachPoint=\"titleNode\">${label}</div>\n\t\t<div class=\"dijitInline dijitFileInputButton\" dojoAttachPoint=\"cancelNode\" dojoAttachEvent=\"onclick:reset\">${cancelText}</div>\n\t</div>\n\t<div class=\"dijitProgressOverlay\" dojoAttachPoint=\"overlay\">&nbsp;</div>\n</div>\n"}});
+define("dojox/form/FileInputAuto", [
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/_base/fx",
+ "dojo/_base/window",
+ "dojo/dom-style",
+ "dojo/_base/sniff",
+ "dojo/text!./resources/FileInputAuto.html",
+ "dojox/form/FileInput",
+ "dojo/io/iframe"
+],
+function(declare, lang, fx, win, domStyle, has, template, FileInput, ioIframe){
+
+ /*=====
+ FileInput = dojox.form.FileInput;
+ =====*/
+var FileInputAuto = declare("dojox.form.FileInputAuto", FileInput,
+ {
+ // summary: An extension on FileInput providing background upload progress
+ //
+ // description: An extended version of FileInput - when the user focuses away from the input
+ // the selected file is posted via ioIframe to the url. example implementation
+ // comes with PHP solution for handling upload, and returning required data.
+ //
+ // notes: the return data from the io.iframe is used to populate the input element with
+ // data regarding the results. it will be a JSON object, like:
+ //
+ // results = { size: "1024", filename: "file.txt" }
+ //
+ // all the parameters allowed to FileInput apply
+
+ // url: String
+ // the URL where our background FileUpload will be sent
+ url: "",
+
+ // blurDelay: Integer
+ // time in ms before an un-focused widget will wait before uploading the file to the url="" specified
+ // default: 2 seconds
+ blurDelay: 2000,
+
+ // duration: Integer
+ // The time in ms to use as the generic timing mechanism for the animations
+ // set to 1 or 0 for "immediate respose"
+ duration: 500,
+
+ // uploadMessage: String
+ //
+ // FIXME: i18n somehow?
+ uploadMessage: "Uploading ...",
+
+ // triggerEvent: String
+ // Event which triggers the upload. Defaults to onblur, sending the file selected
+ // 'blurDelay' milliseconds after losing focus. Set to "onchange" with a low blurDelay
+ // to send files immediately after uploading.
+ triggerEvent: "onblur",
+
+ _sent: false,
+
+ // small template changes, new attachpoint: overlay
+ templateString: template,
+
+ onBeforeSend: function(){
+ // summary: Called immediately before a FileInput sends it's file via io.iframe.send.
+ // The return of this function is passed as the `content` member in the io.iframe IOArgs
+ // object.
+ return {};
+ },
+
+ startup: function(){
+ // summary: add our extra blur listeners
+ this._blurListener = this.connect(this.fileInput, this.triggerEvent, "_onBlur");
+ this._focusListener = this.connect(this.fileInput, "onfocus", "_onFocus");
+ this.inherited(arguments);
+ },
+
+ _onFocus: function(){
+ // summary: clear the upload timer
+ if(this._blurTimer){ clearTimeout(this._blurTimer); }
+ },
+
+ _onBlur: function(){
+ // summary: start the upload timer
+ if(this._blurTimer){ clearTimeout(this._blurTimer); }
+ if(!this._sent){
+ this._blurTimer = setTimeout(lang.hitch(this,"_sendFile"),this.blurDelay);
+ }
+ },
+
+ setMessage: function(/*String*/title){
+ // summary: set the text of the progressbar
+
+ // innerHTML throws errors in IE! so use DOM manipulation instead
+ //this.overlay.innerHTML = title;
+ this.overlay.removeChild(this.overlay.firstChild);
+ this.overlay.appendChild(document.createTextNode(title));
+ },
+
+ _sendFile: function(/* Event */e){
+ // summary: triggers the chain of events needed to upload a file in the background.
+ if(this._sent || this._sending || !this.fileInput.value){ return; }
+
+ this._sending = true;
+
+ domStyle.set(this.fakeNodeHolder,"display","none");
+ domStyle.set(this.overlay,{
+ opacity:0,
+ display:"block"
+ });
+
+ this.setMessage(this.uploadMessage);
+
+ fx.fadeIn({ node: this.overlay, duration:this.duration }).play();
+
+ var _newForm;
+ if(has("ie") < 9 || (has("ie") && has("quirks"))){
+ // just to reiterate, IE is a steaming pile of code.
+ _newForm = document.createElement('<form enctype="multipart/form-data" method="post">');
+ _newForm.encoding = "multipart/form-data";
+
+ }else{
+ // this is how all other sane browsers do it
+ _newForm = document.createElement('form');
+ _newForm.setAttribute("enctype","multipart/form-data");
+ }
+ _newForm.appendChild(this.fileInput);
+ win.body().appendChild(_newForm);
+
+ ioIframe.send({
+ url: this.url,
+ form: _newForm,
+ handleAs: "json",
+ handle: lang.hitch(this,"_handleSend"),
+ content: this.onBeforeSend()
+ });
+ },
+
+ _handleSend: function(data,ioArgs){
+ // summary: The callback to toggle the progressbar, and fire the user-defined callback
+
+ // innerHTML throws errors in IE! so use DOM manipulation instead
+ this.overlay.removeChild(this.overlay.firstChild);
+
+ this._sent = true;
+ this._sending = false;
+ domStyle.set(this.overlay,{
+ opacity:0,
+ border:"none",
+ background:"none"
+ });
+
+ this.overlay.style.backgroundImage = "none";
+ this.fileInput.style.display = "none";
+ this.fakeNodeHolder.style.display = "none";
+ fx.fadeIn({ node:this.overlay, duration:this.duration }).play(250);
+
+ this.disconnect(this._blurListener);
+ this.disconnect(this._focusListener);
+
+ //remove the form used to send the request
+ win.body().removeChild(ioArgs.args.form);
+ this.fileInput = null;
+
+ this.onComplete(data,ioArgs,this);
+ },
+
+ reset: function(e){
+ // summary: accomodate our extra focusListeners
+ if(this._blurTimer){ clearTimeout(this._blurTimer); }
+
+ this.disconnect(this._blurListener);
+ this.disconnect(this._focusListener);
+
+ this.overlay.style.display = "none";
+ this.fakeNodeHolder.style.display = "";
+ this.inherited(arguments);
+ this._sent = false;
+ this._sending = false;
+ this._blurListener = this.connect(this.fileInput, this.triggerEvent,"_onBlur");
+ this._focusListener = this.connect(this.fileInput,"onfocus","_onFocus");
+ },
+
+ onComplete: function(data,ioArgs,widgetRef){
+ // summary: stub function fired when an upload has finished.
+ // data: the raw data found in the first [TEXTAREA] tag of the post url
+ // ioArgs: the Deferred data being passed from the handle: callback
+ // widgetRef: this widget pointer, so you can set this.overlay to a completed/error message easily
+ }
+});
+
+declare("dojox.form.FileInputBlind", FileInputAuto,
+ {
+ // summary: An extended version of dojox.form.FileInputAuto
+ // that does not display an input node, but rather only a button
+ // and otherwise behaves just like FileInputAuto
+
+ startup: function(){
+ // summary: hide our fileInput input field
+ this.inherited(arguments);
+ this._off = domStyle.get(this.inputNode,"width");
+ this.inputNode.style.display = "none";
+ this._fixPosition();
+ },
+
+ _fixPosition: function(){
+ // summary: in this case, set the button under where the visible button is
+ if(has("ie")){
+ domStyle.set(this.fileInput,"width","1px");
+ }else{
+ domStyle.set(this.fileInput,"left","-"+(this._off)+"px");
+ }
+ },
+
+ reset: function(e){
+ // summary: onclick, we need to reposition our newly created input type="file"
+ this.inherited(arguments);
+ this._fixPosition();
+ }
+});
+
+return FileInputAuto;
+});
diff --git a/js/dojo/dojox/form/FileInputBlind.js b/js/dojo/dojox/form/FileInputBlind.js
new file mode 100644
index 0000000..552320b
--- /dev/null
+++ b/js/dojo/dojox/form/FileInputBlind.js
@@ -0,0 +1,10 @@
+//>>built
+define("dojox/form/FileInputBlind", [
+ "dojo/_base/lang",
+ "dojox/form/FileInputAuto"
+], function(lang, FileInputAuto){
+// FIXME: break out code in 2.0. Leave this stub in place until then. Leave FileInputBlind code in Auto.js for
+// backwards compatibility.
+ lang.setObject("dojox.form.FileInputBlind", FileInputAuto);
+ return FileInputAuto;
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/FilePickerTextBox.js b/js/dojo/dojox/form/FilePickerTextBox.js
new file mode 100644
index 0000000..32087a8
--- /dev/null
+++ b/js/dojo/dojox/form/FilePickerTextBox.js
@@ -0,0 +1,331 @@
+//>>built
+require({cache:{
+'url:dojox/form/resources/FilePickerTextBox.html':"<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\"\n\trole=\"combobox\" tabIndex=\"-1\"\n\t><div style=\"overflow:hidden;\"\n\t\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton'\n\t\t\tdojoAttachPoint=\"downArrowNode,_buttonNode,_popupStateNode\" role=\"presentation\"\n\t\t\t><div class=\"dijitArrowButtonInner\">&thinsp;</div\n\t\t\t><div class=\"dijitArrowButtonChar\">&#9660;</div\n\t\t></div\n\t\t><div class=\"dijitReset dijitValidationIcon\"><br></div\n\t\t><div class=\"dijitReset dijitValidationIconText\">&Chi;</div\n\t\t><div class=\"dijitReset dijitInputField\"\n\t\t\t><input type=\"text\" autocomplete=\"off\" ${!nameAttrSetting} class='dijitReset'\n\t\t\t\tdojoAttachEvent='onkeypress:_onKey' \n\t\t\t\tdojoAttachPoint='textbox,focusNode' role=\"textbox\" aria-haspopup=\"true\" aria-autocomplete=\"list\"\n\t\t/></div\n\t></div\n></div>\n"}});
+define("dojox/form/FilePickerTextBox", [
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojo/_base/event",
+ "dojo/window",
+ "dijit/focus",
+ "dijit/registry",
+ "dijit/form/_TextBoxMixin",
+ "dijit/form/ValidationTextBox",
+ "dijit/_HasDropDown",
+ "dojox/widget/FilePicker",
+ "dojo/text!./resources/FilePickerTextBox.html",
+ "dojo/_base/declare",
+ "dojo/keys" // keys
+], function(lang, array, event, windowUtils, focus, registry, _TextBoxMixin, ValidationTextBox, _HasDropDown, FilePicker, template, declare, keys){
+
+ /*=====
+ ValidationTextBox = dijit.form.ValidationTextBox;
+ _HasDropDown = dijit._HasDropDown;
+ =====*/
+return declare( "dojox.form.FilePickerTextBox", [ValidationTextBox, _HasDropDown],
+ {
+ // summary:
+ // A validating text box tied to a file picker popup
+
+ baseClass: "dojoxFilePickerTextBox",
+
+ templateString: template,
+
+ // searchDelay: Integer
+ // Delay in milliseconds between when user types something and we start
+ // searching based on that value
+ searchDelay: 500,
+
+ // valueItem: item
+ // The item, in our store, of the directory relating to our value
+ valueItem: null,
+
+ // numPanes: number
+ // The number of panes to display in our box (if we don't have any
+ // minPaneWidth specified by our constraints)
+ numPanes: 2.25,
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this.dropDown = new FilePicker(this.constraints);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ // Make our connections we want
+ this.connect(this.dropDown, "onChange", this._onWidgetChange);
+ this.connect(this.focusNode, "onblur", "_focusBlur");
+ this.connect(this.focusNode, "onfocus", "_focusFocus");
+ this.connect(this.focusNode, "ondblclick", function(){
+ _TextBoxMixin.selectInputText(this.focusNode);
+ });
+ },
+
+ _setValueAttr: function(/*string*/value, priorityChange, fromWidget){
+ // summary: sets the value of this widget
+ if(!this._searchInProgress){
+ this.inherited(arguments);
+ value = value || "";
+ var tVal = this.dropDown.get("pathValue") || "";
+ if(value !== tVal){
+ this._skip = true;
+ var fx = lang.hitch(this, "_setBlurValue");
+ this.dropDown._setPathValueAttr(value, !fromWidget,
+ this._settingBlurValue ? fx : null);
+ }
+ }
+ },
+
+ _onWidgetChange: function(/*item*/item){
+ // summary: called when the path gets changed in the dropdown
+ if(!item && this.focusNode.value){
+ this._hasValidPath = false;
+ this.focusNode.value = "";
+ }else{
+ this.valueItem = item;
+ var value = this.dropDown._getPathValueAttr(item);
+ if(value){
+ this._hasValidPath = true;
+ }
+ if(!this._skip){
+ this._setValueAttr(value, undefined, true);
+ }
+ delete this._skip;
+ }
+ this.validate();
+ },
+
+ startup: function(){
+ if(!this.dropDown._started){
+ this.dropDown.startup();
+ }
+ this.inherited(arguments);
+ },
+
+ openDropDown: function(){
+ // set width to 0 so that it will resize automatically
+ this.dropDown.domNode.style.width="0px";
+ if(!("minPaneWidth" in (this.constraints||{}))){
+ this.dropDown.set("minPaneWidth", (this.domNode.offsetWidth / this.numPanes));
+ }
+ this.inherited(arguments);
+ },
+
+ toggleDropDown: function(){
+ this.inherited(arguments);
+ // Make sure our display is up-to-date with our value
+ if(this._opened){
+ this.dropDown.set("pathValue", this.get("value"));
+ }
+ },
+
+ _focusBlur: function(/*Event*/ e){
+ // summary: called when the focus node gets blurred
+ if(e.explicitOriginalTarget == this.focusNode && !this._allowBlur){
+ window.setTimeout(lang.hitch(this, function(){
+ if(!this._allowBlur){
+ this.focus();
+ }
+ }), 1);
+ }else if(this._menuFocus){
+ this.dropDown._updateClass(this._menuFocus, "Item", {"Hover": false});
+ delete this._menuFocus;
+ }
+ },
+
+ _focusFocus: function(/*Event*/ e){
+ // summary: called when the focus node gets focus
+ if(this._menuFocus){
+ this.dropDown._updateClass(this._menuFocus, "Item", {"Hover": false});
+ }
+ delete this._menuFocus;
+ var focusNode = focus.curNode;
+ if(focusNode){
+ focusNode = registry.byNode(focusNode);
+ if(focusNode){
+ this._menuFocus = focusNode.domNode;
+ }
+ }
+ if(this._menuFocus){
+ this.dropDown._updateClass(this._menuFocus, "Item", {"Hover": true});
+ }
+ delete this._allowBlur;
+ },
+
+ _onBlur: function(){
+ // summary: called when focus is shifted away from this widget
+ this._allowBlur = true;
+ delete this.dropDown._savedFocus;
+ this.inherited(arguments);
+ },
+
+ _setBlurValue: function(){
+ // summary: sets the value of the widget once focus has left
+ if(this.dropDown && !this._settingBlurValue){
+ this._settingBlurValue = true;
+ this.set("value", this.focusNode.value);
+ }else{
+ delete this._settingBlurValue;
+ this.inherited(arguments);
+ }
+ },
+
+ parse: function(/* String */ value, /* Object */ constraints){
+ // summary:
+ // Function to convert a formatted string to a value - we use
+ // it to verify that it *really* is a valid value
+ if(this._hasValidPath || this._hasSelection){
+ return value;
+ }
+ var dd = this.dropDown, topDir = dd.topDir, sep = dd.pathSeparator;
+ var ddVal = dd.get("pathValue");
+ var norm = function(v){
+ if(topDir.length && v.indexOf(topDir) === 0){
+ v = v.substring(topDir.length);
+ }
+ if(sep && v[v.length - 1] == sep){
+ v = v.substring(0, v.length - 1);
+ }
+ return v;
+ };
+ ddVal = norm(ddVal);
+ var val = norm(value);
+ if(val == ddVal){
+ return value;
+ }
+ return undefined;
+ },
+
+ _startSearchFromInput: function(){
+ // summary: kicks off a search based off the current text value of the widget
+ var dd = this.dropDown, fn = this.focusNode;
+ var val = fn.value, oVal = val, topDir = dd.topDir;
+ if(this._hasSelection){
+ _TextBoxMixin.selectInputText(fn, oVal.length);
+ }
+ this._hasSelection = false;
+ if(topDir.length && val.indexOf(topDir) === 0){
+ val = val.substring(topDir.length);
+ }
+ var dirs = val.split(dd.pathSeparator);
+ var setFromChain = lang.hitch(this, function(idx){
+ var dir = dirs[idx];
+ var child = dd.getChildren()[idx];
+ var conn;
+ this._searchInProgress = true;
+ var _cleanup = lang.hitch(this, function(){
+ delete this._searchInProgress;
+ });
+ if((dir || child) && !this._opened){
+ this.toggleDropDown();
+ }
+ if(dir && child){
+ var fx = lang.hitch(this, function(){
+ if(conn){
+ this.disconnect(conn);
+ }
+ delete conn;
+ var children = child._menu.getChildren();
+ var exact = array.filter(children, function(i){
+ return i.label == dir;
+ })[0];
+ var first = array.filter(children, function(i){
+ return (i.label.indexOf(dir) === 0);
+ })[0];
+ if(exact &&
+ ((dirs.length > idx + 1 && exact.children) ||
+ (!exact.children))){
+ idx++;
+ child._menu.onItemClick(exact, {type: "internal",
+ stopPropagation: function(){},
+ preventDefault: function(){}});
+ if(dirs[idx]){
+ setFromChain(idx);
+ }else{
+ _cleanup();
+ }
+ }else{
+ child._setSelected(null);
+ if(first && dirs.length === idx + 1){
+ dd._setInProgress = true;
+ dd._removeAfter(child);
+ delete dd._setInProgress;
+ var targetString = first.label;
+ if(first.children){
+ targetString += dd.pathSeparator;
+ }
+ targetString = targetString.substring(dir.length);
+ window.setTimeout(function(){
+ windowUtils.scrollIntoView(first.domNode);
+ }, 1);
+ fn.value = oVal + targetString;
+ _TextBoxMixin.selectInputText(fn, oVal.length);
+ this._hasSelection = true;
+ try{first.focusNode.focus();}catch(e){}
+ }else{
+ if(this._menuFocus){
+ this.dropDown._updateClass(this._menuFocus, "Item", {"Hover": false, "Focus": false});
+ }
+ delete this._menuFocus;
+ }
+ _cleanup();
+ }
+ });
+ if(!child.isLoaded){
+ conn = this.connect(child, "onLoad", fx);
+ }else{
+ fx();
+ }
+ }else{
+ if(child){
+ child._setSelected(null);
+ dd._setInProgress = true;
+ dd._removeAfter(child);
+ delete dd._setInProgress;
+ }
+ _cleanup();
+ }
+ });
+ setFromChain(0);
+ },
+
+ _onKey: function(/*Event*/ e){
+ // summary: callback when the user presses a key on menu popup node
+ if(this.disabled || this.readOnly){ return; }
+ var c = e.charOrCode;
+ if(c==keys.DOWN_ARROW){
+ this._allowBlur = true;
+ }
+ if(c==keys.ENTER && this._opened){
+ this.dropDown.onExecute();
+ _TextBoxMixin.selectInputText(this.focusNode, this.focusNode.value.length);
+ this._hasSelection = false;
+ event.stop(e);
+ return;
+ }
+ if((c==keys.RIGHT_ARROW || c==keys.LEFT_ARROW || c==keys.TAB) && this._hasSelection){
+ this._startSearchFromInput();
+ event.stop(e);
+ return;
+ }
+ this.inherited(arguments);
+ var doSearch = false;
+ if((c==keys.BACKSPACE || c==keys.DELETE) && this._hasSelection){
+ this._hasSelection = false;
+ }else if(c==keys.BACKSPACE || c==keys.DELETE || c==" "){
+ doSearch = true;
+ }else{
+ doSearch = e.keyChar !== "";
+ }
+ if(this._searchTimer){
+ window.clearTimeout(this._searchTimer);
+ }
+ delete this._searchTimer;
+ if(doSearch){
+ this._hasValidPath = false;
+ this._hasSelection = false;
+ this._searchTimer = window.setTimeout(lang.hitch(this, "_startSearchFromInput"), this.searchDelay + 1);
+ }
+ }
+ }
+);
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/FileUploader.js b/js/dojo/dojox/form/FileUploader.js
new file mode 100644
index 0000000..fad850e
--- /dev/null
+++ b/js/dojo/dojox/form/FileUploader.js
@@ -0,0 +1,1445 @@
+//>>built
+define("dojox/form/FileUploader", [
+ "dojo/_base/kernel",
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojo/_base/connect",
+ "dojo/_base/window",
+ "dojo/_base/sniff",
+ "dojo/query",
+ "dojo/dom-style",
+ "dojo/dom-geometry",
+ "dojo/dom-attr",
+ "dojo/dom-class",
+ "dojo/dom-construct",
+ "dojo/dom-form",
+ "dojo/_base/config",
+ "dijit/_base/manager",
+ "dojo/io/iframe",
+ "dojo/_base/Color",
+ "dojo/_base/unload",
+ "dijit/_Widget",
+ "dijit/_TemplatedMixin",
+ "dijit/_Contained",
+ "dojox/embed/Flash",
+ "dojox/embed/flashVars",
+ "dojox/html/styles"
+],function(kernel, declare, lang, array, connect, win, has, query, domStyle, domGeometry, domAttr, domClass, domConstruct, domForm, config, manager, ioIframe, Color, unloadUtils, Widget, TemplatedMixin, Contained, embedFlash, embedFlashVars, htmlStyles){
+
+kernel.deprecated("dojox.form.FileUploader", "Use dojox.form.Uploader", "2.0");
+
+ // Usage Notes:
+ // To center text vertically, use vertical-align:middle;
+ // which emulates a boxModel button. Using line-height to center text
+ // can cause height problems in IE6
+
+
+ /*=====
+ Widget = dijit._Widget;
+ TemplatedMixin = dijit._TemplatedMixin;
+ Contained = dijit._Contained;
+ =====*/
+declare("dojox.form.FileUploader", [Widget, TemplatedMixin, Contained], {
+ // version:
+ // 1.5 (deprecated)
+ // summary:
+ // Handles File Uploading to a server (PHP script included for testing)
+ //
+ // FileUploader is now a WIDGET. You do not have to pass a button
+ // in. Passing a button is still supported until version 1.5 to maintain
+ // backwards compatibility, but it is not reccomended. Just create your
+ // uploader like any other widget.
+ //
+ // description:
+ // If the correct version of Flash Player is available (> 9.0) , a SWF
+ // is used. If Flash Player is not installed or is outdated, a typical
+ // html fileInput is used. This process can be overridden with
+ // force:"flash" or force:"html".
+ //
+ // FileUploader works with Flash 10.
+ //
+ // The button styles are now recreated in Flash, so there is no longer
+ // using an invisible Flash movie with wmode=transparent. This way the Flash button
+ // is actually placed inline with the DOM, not floating above it and constantly
+ // resetting its position. The "Windows Firefox clickable bug" should be fixed (and
+ // hopefully some Linux problems).
+ //
+ // The HTML button is created in a new way and it is now inline as is the
+ // FLash button. Styling is much easier and more versatile.
+ //
+ // Dependencies:
+ // FileUploader no longer uses FileInput.css. It now uses FileUploader.css
+ // See requires for JavaScript dependencies.
+ //
+ // NEW FEATURES -
+ // There are a ton of features and fixes in this version.
+ // Disabled: Can be toggled with widget.attr("disable", true|false)
+ // Submit: A convenience method has been added for if the uploader is in a form.
+ // Instead of submitting the form, call uploader.submit(theForm), and the
+ // Uploader will handle all of the form values and post the data.
+ // Selected List: If passing the ID of a container, the Uploaders will populate it
+ // with the selected files.
+ // Deleting Files: You can now delete pending files.
+ // Progress Built in: showProgress:true will change the button to a progress
+ // bar on upload.
+ // Progress Attach: Passing progressWidgetId will tell the Uploader of a progress
+ // widget. If the Progress widget is initially hidden, it will change to
+ // visible and then restored after upload.
+ // A11Y: The Flash button can be accessed with the TAB key. (The HTML cannot due
+ // to browser limtations)
+ // Deferred Uploading: (Flash only) throttles the upload to one file at a time
+ //
+ //
+ // CDN USERS -
+ // FileUpload now works with the CDN but with limitations. The SWF must
+ // be from the same domain as the HTML page. 'swfPath' has been exposed
+ // so that you may link to that file (could of course be the same SWF in
+ // dojox resource folder). The SWF will *NOT* work from the
+ // CDN server. This would require a special XML file that would allow
+ // access to your server, and the logistics to that is impossible.
+ //
+ // LIMITATIONS
+ // - This is not designed to be a part of a form, it contains its own. (See submit())
+ // - Currently does not in a Dialog box or a Tab where it is not initially visible,
+ // - The default style inherits font sizes - but a parent container should have a font size
+ // set somewhere of the results could be inconsistent.
+ //
+ // OPERA USERS -
+ // It works better than the 1.3 version. fileInputs apperantly can't have opacity
+ // set to zero. The Flash uploader works but files are auto-uploaded. Must be a
+ // flashVar problem.
+ //
+ // Safari Bug note:
+ // The bug is in the way Safari handles the connection:
+ // https://bugs.webkit.org/show_bug.cgi?id=5760
+ // I added this to the virtual host in the Apache conf file, and now it
+ // works like a charm:
+ // BrowserMatch Safari nokeepalive
+ //
+ swfPath: config.uploaderPath || require.toUrl("dojox/form/resources/fileuploader.swf"),
+
+
+ templateString:'<div><div dojoAttachPoint="progNode"><div dojoAttachPoint="progTextNode"></div></div><div dojoAttachPoint="insideNode" class="uploaderInsideNode"></div></div>',
+
+ // uploadUrl: String
+ // The url targeted for upload. An absolute URL is preferred. Relative URLs are
+ // changed to absolute.
+ uploadUrl: "",
+ //
+ // isDebug: Boolean
+ // If true, outputs traces from the SWF to console. What exactly gets passed
+ // is very relative, and depends upon what traces have been left in the DEFT SWF.
+ isDebug:false,
+ //
+ // devMode: Boolean.
+ // Re-implemented. devMode increases the logging, adding style tracing from the SWF.
+ devMode:false,
+ //
+ // id: String
+ // The object id, just like any other widget in Dojo. However, this id
+ // is also used as a reference for the SWF
+ // id: "",
+ //
+ // baseClass: String
+ // The name of the class that will style the button in a "normal" state.
+ // If baseClass is not defined, 'class' will be used.
+ // NOTE: By default the uploader will be styled like a dijit buttons and
+ // adhere to the the themes. Tundra, Soria, and Nihilo are supported.
+ // You can cascade the existing style by using 'class' or 'style'. If you
+ // overwrite baseClass, you should overwrite the remaing state classes
+ // that follow) as well.
+ baseClass:"dojoxUploaderNorm",
+ //
+ // hoverClass: String
+ // The name of the class that will style the button in a "hover" state. A specific
+ // class should be made to do this. Do not rely on a target like button:hover{...}
+ hoverClass:"dojoxUploaderHover",
+ //
+ // activeClass: String
+ // The name of the class that will style the button in a "press" state. A specific
+ // class should be made to do this. Do not rely on a target like button:active{...}
+ activeClass:"dojoxUploaderActive",
+ //
+ // disabledClass: String
+ // The name of the class that will style the button when its disabled.
+ disabledClass:"dojoxUploaderDisabled",
+ //
+ // force: String
+ // Use "flash" to always use Flash (and hopefully force the user to download the plugin
+ // if they don't have it). Use "html" to always use the HTML uploader. An empty string
+ // (default) will check for the right version of Flash and use HTML if not available.
+ force:"",
+ //
+ // uploaderType: [readonly] String
+ // Internal. What type of uploader is being used: "flash" or "html"
+ uploaderType:"",
+ //
+ // flashObject: [readonly] dojox.embed.Flash
+ // The object that creates the SWF embed object. Mostly Internal.
+ flashObject: null,
+ //
+ // flashMovie: [readonly] Function
+ // The SWF. Mostly Internal.
+ flashMovie: null,
+ //
+ // insideNode: [readonly] HTMLNode
+ // The div that holds the SWF and form/fileInput
+ insideNode: null,
+ //
+ // deferredUploading: Number (1 - X)
+ // (Flash only) throttles the upload to a certain amount of files at a time.
+ // By default, Flash uploads file one at a time to the server, but in parallel.
+ // Firefox will try to queue all files at once, leading to problems. Set this
+ // to the amount to upload in parallel at a time.
+ // Generally, 1 should work fine, but you can experiment with queuing more than
+ // one at a time.
+ // This is of course ignored if selectMultipleFiles equals false.
+ deferredUploading:1,
+ //
+ // fileListId: String
+ // The id of a dom node to be used as a container for the pending file list.
+ fileListId:"",
+ //
+ // uploadOnChange: Boolean
+ // If true, uploads imediately after a file has been selected. If false,
+ // waits for upload() to be called.
+ uploadOnChange: false,
+ //
+ // selectMultipleFiles: Boolean
+ // If true and flash mode, multiple files may be selected from the dialog.
+ // If html mode, files are not uploaded until upload() is called. The references
+ // to each file is incremented:uploadedfile0, uploadedfile1, uploadedfile2... etc.
+ selectMultipleFiles: true,
+ //
+ // htmlFieldName: String
+ // The name of the field of the fileInput that the server is expecting
+ htmlFieldName:"uploadedfile",
+ //
+ // flashFieldName: String
+ // The name of the field of the flash uploaded files that the server is expecting
+ flashFieldName:"flashUploadFiles",
+ //
+ // fileMask: Array[ Array[Description, FileTypes], Array[...]...]
+ // (an array, or an array of arrays)
+ // Restrict file selection to certain file types
+ // Empty array defaults to "All Files"
+ // example:
+ // fileMask = ["Images", "*.jpg;*.jpeg;*.gif;*.png"]
+ // or
+ // fileMask = [
+ // ["Jpeg File", "*.jpg;*.jpeg"],
+ // ["GIF File", "*.gif"],
+ // ["PNG File", "*.png"],
+ // ["All Images", "*.jpg;*.jpeg;*.gif;*.png"],
+ // ]
+ // NOTE: MacType is not supported, as it does not work very well.
+ // fileMask will work on a Mac, but differently than
+ // Windows.
+ fileMask: null,
+ //
+ // minFlashVersion: Number
+ // The minimum of version of Flash player to target. 0 would always install Flash, 100
+ // would never install it. The Flash Player has supported multiple uploads since
+ // version 8, so it could go as low as that safely.
+ minFlashVersion:9,
+ //
+ // tabIndex: Number|String
+ // The tab order in the DOM. Only supported by Flash. HTML Uploaders have security
+ // protection to prevent you from tabbing to the uploader. Stupid.
+ tabIndex:-1,
+ //
+ // showProgress: Boolean
+ // If true, the button changes to a progress bar during upload.
+ showProgress:false,
+ //
+ // progressMessage: String
+ // The message shown while the button is changed to a progress bar
+ progressMessage:"Loading",
+ //
+ // progressBackgroundUrl: String|Uri
+ // The background image to use for the button-progress
+ progressBackgroundUrl:require.toUrl("dijit/themes/tundra/images/buttonActive.png"),
+ //
+ // progressBackgroundColor: String|Number
+ // The background color to use for the button-progress
+ progressBackgroundColor:"#ededed",
+ //
+ // progressWidgetId:String
+ // The widget id of a Dijit Progress bar. The Uploader will bind to it and update it
+ // automatically.
+ progressWidgetId:"",
+ //
+ // skipServerCheck: Boolean
+ // If true, will not verify that the server was sent the correct format.
+ // This can be safely set to true. The purpose of the server side check
+ // is mainly to show the dev if they've implemented the different returns
+ // correctly.
+ skipServerCheck:false,
+ //
+ // serverTimeout:Number (milliseconds)
+ // The amount of time given to the uploaded file
+ // to wait for a server response. After this amount
+ // of time, the onComplete is fired but with a 'server timeout'
+ // error in the returned item.
+ serverTimeout: 5000,
+
+
+ log: function(){
+ // summary:
+ // Due to the excessive logging necessary to make this code happen,
+ // It's easier to turn it on and off here in one place.
+ // Also helpful if there are multiple uploaders on one page.
+ if(this.isDebug){
+ console["log"](Array.prototype.slice.call(arguments).join(" "));
+ }
+ },
+
+ constructor: function(){
+ this._subs = [];
+ },
+
+ postMixInProperties: function(){
+ // internal stuff:
+ this.fileList = [];
+ this._cons = [];
+ this.fileMask = this.fileMask || [];
+ this.fileInputs = [];
+ this.fileCount = 0;
+ this.flashReady = false;
+ this._disabled = false;
+ this.force = this.force.toLowerCase(); // Pete FTW.
+ this.uploaderType = ((embedFlash.available >= this.minFlashVersion || this.force=="flash") && this.force != "html") ? "flash" : "html";
+ this.deferredUploading = this.deferredUploading===true ? 1 : this.deferredUploading;
+
+ this._refNode = this.srcNodeRef;
+
+ this.getButtonStyle();
+ },
+
+ startup: function(){
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // internal stuff:
+ this.setButtonStyle();
+ var createMethod;
+ if(this.uploaderType == "flash"){
+ createMethod = "createFlashUploader";
+ }else{
+ this.uploaderType = "html";
+ createMethod = "createHtmlUploader";
+
+ }
+
+ this[createMethod]();
+
+ if(this.fileListId){
+ this.connect(dom.byId(this.fileListId), "click", function(evt){
+ var p = evt.target.parentNode.parentNode.parentNode; // in a table
+ if(p.id && p.id.indexOf("file_")>-1){
+ this.removeFile(p.id.split("file_")[1]);
+ }
+ });
+ }
+
+ // cleaning up solves memory leak issues in the HTML version
+ unloadUtils.addOnUnload(this, this.destroy);
+ },
+
+ getHiddenNode: function(/*DomNode*/ node){
+ // summary:
+ // Internal.
+ // If a parent node is styled as display:none,
+ // returns that node. This node will be temporarilly
+ // changed to display:block. Note if the node is in
+ // a widget that has an onShow event, this is
+ // overridden.
+ //
+ if(!node){ return null; }
+ var hidden = null;
+ var p = node.parentNode;
+ while(p && p.tagName.toLowerCase() != "body"){
+ var d = domStyle.get(p, "display");
+ if(d == "none"){
+ hidden = p;
+ break;
+ }
+ p = p.parentNode;
+ }
+ return hidden;
+ },
+
+ getButtonStyle: function(){
+ // summary:
+ // Internal.
+ // Get necessary style information from srcRefNode and
+ // assigned styles
+ //
+
+
+ // TODO:
+ // To call this from postCreate....
+ // could do the style stuff initially, but if hidden they will be bad sizes
+ // could then redo the sizes
+ // alt is to create a genuine button and copy THAT instead of how doing now
+
+ var refNode = this.srcNodeRef;
+ this._hiddenNode = this.getHiddenNode(refNode);
+ if(this._hiddenNode){
+ domStyle.set(this._hiddenNode, "display", "block");
+ }
+
+ if(!refNode && this.button && this.button.domNode){
+ // backwards compat for a Dijit button
+ var isDijitButton = true;
+ var cls = this.button.domNode.className + " dijitButtonNode";
+ var txt = this.getText(query(".dijitButtonText", this.button.domNode)[0]);
+ var domTxt = '<button id="'+this.button.id+'" class="'+cls+'">'+txt+'</button>';
+ refNode = domConstruct.place(domTxt, this.button.domNode, "after"); /// Pete doesn't like this?
+ this.srcNodeRef = refNode;
+ this.button.destroy();
+
+ this.baseClass = "dijitButton";
+ this.hoverClass = "dijitButtonHover";
+ this.pressClass = "dijitButtonActive";
+ this.disabledClass = "dijitButtonDisabled";
+
+ }else if(!this.srcNodeRef && this.button){
+ refNode = this.button;
+ }
+
+ if(domAttr.get(refNode, "class")){
+ this.baseClass += " " + domAttr.get(refNode, "class");
+ }
+ domAttr.set(refNode, "class", this.baseClass);
+
+
+ this.norm = this.getStyle(refNode);
+ this.width = this.norm.w;
+ this.height = this.norm.h;
+
+ if(this.uploaderType == "flash"){
+
+ this.over = this.getTempNodeStyle(refNode, this.baseClass+" "+this.hoverClass, isDijitButton);
+ this.down = this.getTempNodeStyle(refNode, this.baseClass+" "+this.activeClass, isDijitButton);
+ this.dsbl = this.getTempNodeStyle(refNode, this.baseClass+" "+this.disabledClass, isDijitButton);
+
+ this.fhtml = {
+ cn:this.getText(refNode),
+ nr:this.norm,
+ ov:this.over,
+ dn:this.down,
+ ds:this.dsbl
+ };
+ }else{
+ this.fhtml = {
+ cn:this.getText(refNode),
+ nr:this.norm
+ }
+ if(this.norm.va == "middle"){
+ this.norm.lh = this.norm.h;
+ }
+ }
+
+ if(this.devMode){
+ this.log("classes - base:", this.baseClass, " hover:", this.hoverClass, "active:", this.activeClass);
+ this.log("fhtml:", this.fhtml)
+ this.log("norm:", this.norm)
+ this.log("over:", this.over)
+ this.log("down:", this.down)
+
+ }
+ },
+
+ setButtonStyle: function(){
+ // summary:
+ // Internal.
+ // Set up internal dom nodes for button construction.
+ //
+ domStyle.set(this.domNode, {
+ width:this.fhtml.nr.w+"px",
+ height:(this.fhtml.nr.h)+"px",
+ padding:"0px",
+ lineHeight: "normal",
+ position:"relative"
+ });
+ if(this.uploaderType == "html" && this.norm.va == "middle"){
+ domStyle.set(this.domNode, "lineHeight", this.norm.lh + "px");
+ }
+ if(this.showProgress){
+ this.progTextNode.innerHTML = this.progressMessage;
+ domStyle.set(this.progTextNode, {
+ width:this.fhtml.nr.w+"px",
+ height:(this.fhtml.nr.h+0)+"px",
+ padding:"0px",
+ margin:"0px",
+ left:"0px",
+ lineHeight:(this.fhtml.nr.h+0)+"px",
+ position:"absolute"
+ });
+ domStyle.set(this.progNode, {
+ width:this.fhtml.nr.w+"px",
+ height:(this.fhtml.nr.h+0)+"px",
+ padding:"0px",
+ margin:"0px",
+ left:"0px",
+ position:"absolute",
+ display:"none",
+ backgroundImage:"url("+this.progressBackgroundUrl+")",
+ backgroundPosition:"bottom",
+ backgroundRepeat:"repeat-x",
+ backgroundColor:this.progressBackgroundColor
+ });
+ }else{
+ domConstruct.destroy(this.progNode);
+ }
+ domStyle.set(this.insideNode,{
+ position:"absolute",
+ top:"0px",
+ left:"0px",
+ display:""
+ });
+ domClass.add(this.domNode, this.srcNodeRef.className);
+ if(this.fhtml.nr.d.indexOf("inline")>-1){
+ domClass.add(this.domNode, "dijitInline");
+ }
+
+ try{
+ this.insideNode.innerHTML = this.fhtml.cn;
+ }catch(e){
+ // You have got to be kidding me. IE does us he favor of checking that
+ // we aren't inserting the improper type of content with innerHTML into
+ // an inline element. Alert us with an "Unknown Runtime Error". You can't
+ // MAKE this stuff up.
+ //
+ if(this.uploaderType == "flash"){
+ this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode);
+ win.body().appendChild(this.insideNode);
+ this.insideNode.innerHTML = this.fhtml.cn;
+ var c = connect.connect(this, "onReady", this, function(){ connect.disconnect(c);
+ this.insideNode = this.insideNode.parentNode.removeChild(this.insideNode);
+ this.domNode.appendChild(this.insideNode);
+ });
+ }else{
+ this.insideNode.appendChild(document.createTextNode(this.fhtml.cn));
+ }
+ }
+ if(this._hiddenNode){
+ domStyle.set(this._hiddenNode, "display", "none");
+ }
+ },
+
+
+ /*************************
+ * Public Events *
+ *************************/
+
+ // The following events are inherited from _Widget and still may be connected:
+ // onClick
+ // onMouseUp
+ // onMouseDown
+ // onMouseOver
+ // onMouseOut
+
+ onChange: function(dataArray){
+ // summary:
+ // stub to connect
+ // Fires when files are selected
+ // Event is an array of last files selected
+ },
+
+ onProgress: function(dataArray){
+ // summary:
+ // Stub to connect
+ // Fires as progress returns from SWF
+ // Event is an array of all files uploading
+ // Can be connected to for HTML uploader,
+ // but will not return anything.
+ },
+
+ onComplete: function(dataArray){
+ // summary:
+ // stub to connect
+ // Fires when all files have uploaded
+ // Event is an array of all files
+ },
+
+ onCancel: function(){
+ // summary:
+ // Stub to connect
+ // Fires when dialog box has been closed
+ // without a file selection
+ },
+
+ onError: function(/* Object or String */evtObject){
+ // summary:
+ // Fires on errors
+ //
+ //FIXME: Unsure of a standard form for receiving errors
+ },
+
+ onReady: function(/* dojox.form.FileUploader */ uploader){
+ // summary:
+ // Stub - Fired when embedFlash has created the
+ // Flash object, but it has not necessarilly finished
+ // downloading, and is ready to be communicated with.
+ },
+
+ onLoad: function(/* dojox.form.FileUploader */ uploader){
+ // summary:
+ // Stub - SWF has been downloaded 100%.
+ },
+
+ /*************************
+ * Public Methods *
+ *************************/
+ submit: function(/* form node ? */form){
+ // summary:
+ // If FileUploader is in a form, and other data should be sent
+ // along with the files, use this instead of form submit.
+ //
+ var data = form ? domForm.toObject(form) : null;
+ this.upload(data);
+ return false; // Boolean
+ },
+ upload: function(/*Object ? */data){
+ // summary:
+ // When called, begins file upload
+ // data: Object
+ // postData to be sent to server
+ //
+ if(!this.fileList.length){
+ return false;
+ }
+ if(!this.uploadUrl){
+ console.warn("uploadUrl not provided. Aborting.");
+ return false;
+ }
+ if(!this.showProgress){
+ this.set("disabled", true);
+ }
+
+ if(this.progressWidgetId){
+
+ var node = manager.byId(this.progressWidgetId).domNode;
+ if(domStyle.get(node, "display") == "none"){
+ this.restoreProgDisplay = "none";
+ domStyle.set(node, "display", "block");
+ }
+ if(domStyle.get(node, "visibility") == "hidden"){
+ this.restoreProgDisplay = "hidden";
+ domStyle.set(node, "visibility", "visible");
+ }
+ }
+
+ if(data && !data.target){
+ this.postData = data;
+ }
+ this.log("upload type:", this.uploaderType, " - postData:", this.postData);
+
+ for(var i = 0; i < this.fileList.length; i++){
+ var f = this.fileList[i];
+ f.bytesLoaded = 0;
+ f.bytesTotal = f.size || 100000;
+ f.percent = 0;
+ }
+ if(this.uploaderType == "flash"){
+ this.uploadFlash();
+ }else{
+ this.uploadHTML();
+ }
+ // prevent form submit
+ return false;
+ },
+ removeFile: function(/*String*/name, /*Boolean*/noListEdit){
+ // summary:
+ // Removes a file from the pending file list.
+ // Removes pending data from the Flash movie
+ // and fileInputes from the HTML uploader.
+ // If a file container node is bound, the file
+ // will also be removed.
+ // name:String
+ // The name of the file to be removed. Typically the file name,
+ // such as: picture01.png
+ // noListEdit:Boolean
+ // Internal. If true don't remove files from list.
+ //
+ var i;
+ for(i = 0; i < this.fileList.length; i++){
+ if(this.fileList[i].name == name){
+ if(!noListEdit){ // if onComplete, don't do this
+ this.fileList.splice(i,1);
+ }
+ break;
+ }
+ }
+ if(this.uploaderType == "flash"){
+ this.flashMovie.removeFile(name);
+ }else if(!noListEdit){
+ domConstruct.destroy(this.fileInputs[i]);
+ this.fileInputs.splice(i,1);
+ this._renumberInputs();
+ }
+ if(this.fileListId){
+ domConstruct.destroy("file_"+name);
+ }
+ },
+
+ destroy: function(){
+ // summary:
+ // Destroys uploader button
+ if(this.uploaderType == "flash" && !this.flashMovie){
+ this._cons.push(connect.connect(this, "onLoad", this, "destroy"));
+ return;
+ }
+ array.forEach(this._subs, connect.unsubscribe, dojo);
+ array.forEach(this._cons, connect.disconnect, dojo);
+ if(this.scrollConnect){
+ connect.disconnect(this.scrollConnect);
+ }
+ if(this.uploaderType == "flash"){
+ this.flashObject.destroy();
+ delete this.flashObject;
+ }else{
+ domConstruct.destroy(this._fileInput);
+ domConstruct.destroy(this._formNode);
+ }
+ this.inherited(arguments);
+ },
+
+ /*************************
+ * Private Events *
+ *************************/
+ _displayProgress: function(/*Boolean or Number */display){
+ // summary:
+ // Shows and updates the built-in progress bar.
+ //
+ if(display === true){
+ if(this.uploaderType == "flash"){
+ domStyle.set(this.insideNode,"top", "-2500px");
+ }else{
+ domStyle.set(this.insideNode,"display", "none");
+ }
+ domStyle.set(this.progNode,"display","");
+ }else if(display === false){
+ domStyle.set(this.insideNode,{
+ display: "",
+ top: "0"
+ });
+ domStyle.set(this.progNode,"display","none");
+ }else{
+ var w = display * this.fhtml.nr.w;
+ domStyle.set(this.progNode, "width", w + "px");
+ }
+ },
+ _animateProgress: function(){
+ // summary:
+ // Internal. Animated the built-in progress bar
+ this._displayProgress(true);
+ var _uploadDone = false;
+ var c = connect.connect(this, "_complete", function(){
+ connect.disconnect(c);
+ _uploadDone = true;
+ });
+ var w = 0;
+ var interval = setInterval(lang.hitch(this, function(){
+ w+=5;
+ if(w>this.fhtml.nr.w){
+ w = 0;
+ _uploadDone = true;
+ }
+ this._displayProgress(w/this.fhtml.nr.w);
+
+ if(_uploadDone){
+ clearInterval(interval);
+ setTimeout(lang.hitch(this, function(){
+ this._displayProgress(false);
+ }), 500);
+ }
+
+ }),50);
+ },
+
+ _error: function(evt){
+ //var type = evtObject.type ? evtObject.type.toUpperCase() : "ERROR";
+ //var msg = evtObject.msg ? evtObject.msg : evtObject;
+ if(typeof(evt)=="string"){
+ evt = new Error(evt);
+ }
+ this.onError(evt);
+ },
+
+ _addToFileList: function(){
+ // summary:
+ // Internal only. If there is a file list, adds a file to it.
+ // If you need to use a function such as this, connect to
+ // onChange and update outside of this widget.
+ //
+ if(this.fileListId){
+ var str = '';
+ array.forEach(this.fileList, function(d){
+ // have to use tables because of IE. Grumble.
+ str += '<table id="file_'+d.name+'" class="fileToUpload"><tr><td class="fileToUploadClose"></td><td class="fileToUploadName">'+d.name+'</td><td class="fileToUploadSize">'+(d.size ? Math.ceil(d.size*.001) +"kb" : "")+'</td></tr></table>'
+ }, this);
+ dom.byId(this.fileListId).innerHTML = str;
+ }
+ },
+
+ _change: function(dataArray){
+ // summary:
+ // Internal. Updates uploader selection
+ if(has("ie")){
+ //IE6 uses the entire path in the name, which isn't terrible, but much different
+ // than everything else
+ array.forEach(dataArray, function(f){
+ f.name = f.name.split("\\")[f.name.split("\\").length-1];
+ });
+ }
+ if(this.selectMultipleFiles){
+ this.fileList = this.fileList.concat(dataArray);
+ }else{
+ if(this.fileList[0]){
+ this.removeFile(this.fileList[0].name, true);
+ }
+ this.fileList = dataArray;
+ }
+ this._addToFileList();
+ this.onChange(dataArray);
+ if(this.uploadOnChange){
+ if(this.uploaderType == "html"){
+ this._buildFileInput();
+ }
+ this.upload();
+ }else if(this.uploaderType == "html" && this.selectMultipleFiles){
+ this._buildFileInput();
+ this._connectInput();
+ }
+ },
+
+ _complete: function(dataArray){
+ // summary:
+ // Internal. Handles tasks after files have finished uploading
+ //
+ dataArray = lang.isArray(dataArray) ? dataArray : [dataArray];
+
+ // Yes. Yes I do have to do three loops here. ugh.
+ //
+ // Check if one of the files had an error
+ array.forEach(dataArray, function(f){
+ if(f.ERROR){ this._error(f.ERROR); }
+ }, this);
+
+ // Have to be set them all too 100%, because
+ // onProgress does not always fire
+ array.forEach(this.fileList, function(f){
+ f.bytesLoaded = 1;
+ f.bytesTotal = 1;
+ f.percent = 100;
+ this._progress(f);
+ }, this);
+ // we're done. remove files.
+ array.forEach(this.fileList, function(f){
+ this.removeFile(f.name, true);
+ }, this);
+
+ this.onComplete(dataArray);
+
+ this.fileList = [];
+ this._resetHTML();
+ this.set("disabled", false);
+
+
+ if(this.restoreProgDisplay){
+ // using timeout so prog shows on screen for at least a short time
+ setTimeout(lang.hitch(this, function(){
+ domStyle.set(manager.byId(this.progressWidgetId).domNode,
+ this.restoreProgDisplay == "none" ? "display" : "visibility",
+ this.restoreProgDisplay
+ );
+ }), 500);
+ }
+
+ },
+
+ _progress: function(dataObject){
+ // summary:
+ // Internal. Calculate progress
+ var total = 0;
+ var loaded = 0;
+ for(var i = 0; i < this.fileList.length; i++){
+ var f = this.fileList[i];
+ if(f.name == dataObject.name){
+ f.bytesLoaded = dataObject.bytesLoaded;
+ f.bytesTotal = dataObject.bytesTotal;
+ f.percent = Math.ceil(f.bytesLoaded / f.bytesTotal * 100);
+ this.log(f.name, "percent:", f.percent)
+ }
+ loaded += Math.ceil(.001 * f.bytesLoaded);
+ total += Math.ceil(.001 * f.bytesTotal);
+ }
+ var percent = Math.ceil(loaded / total * 100);
+ if(this.progressWidgetId){
+ manager.byId(this.progressWidgetId).update({progress:percent+"%"});
+ }
+ if(this.showProgress){
+ this._displayProgress(percent * .01);
+ }
+ this.onProgress(this.fileList);
+
+ },
+ _getDisabledAttr: function(){
+ // summary:
+ // Internal. To get disabled use: widget.get("disabled");
+ return this._disabled;
+ },
+
+ _setDisabledAttr: function(disabled){
+ // summary:
+ // Internal. To set disabled use: widget.set("disabled", true | false);
+ if(this._disabled == disabled){ return; }
+
+ if(this.uploaderType == "flash"){
+ if(!this.flashReady){
+ var _fc = connect.connect(this, "onLoad", this, function(){
+ connect.disconnect(_fc);
+ this._setDisabledAttr(disabled);
+ });
+ return;
+ }
+ this._disabled = disabled;
+ this.flashMovie.doDisable(disabled);
+ }else{
+ this._disabled = disabled;
+ domStyle.set(this._fileInput, "display", this._disabled ? "none" : "");
+ }
+ domClass.toggle(this.domNode, this.disabledClass, disabled);
+ },
+
+ _onFlashBlur: function(){
+ // summary:
+ // Internal. Detects when Flash movies reliquishes focus.
+ // We have to find all the tabIndexes in the doc and figure
+ // out whom to give focus to next.
+ this.flashMovie.blur();
+ if(!this.nextFocusObject && this.tabIndex){
+ var nodes = query("[tabIndex]");
+ for(var i = 0; i<nodes.length; i++){
+ if(nodes[i].tabIndex >= Number(this.tabIndex)+1){
+ this.nextFocusObject = nodes[i];
+ break;
+ }
+ }
+ }
+ this.nextFocusObject.focus();
+ },
+ _disconnect: function(){
+ // summary:
+ // Internal. Disconnects fileInput in favor of new one.
+ array.forEach(this._cons, connect.disconnect, dojo);
+ },
+
+ /*************************
+ * HTML *
+ *************************/
+ uploadHTML: function(){
+ // summary:
+ // Internal. You could use this, but you should use upload() or submit();
+ // which can also handle the post data.
+ //
+ // NOTE on deferredUploading:
+ // This is not enabled for HTML. Workaround would be to force
+ // singleFile uploads.
+ // TODO:
+ // Investigate removing fileInputs and resending form
+ // multiple times adding each fileInput
+ //
+ if(this.selectMultipleFiles){
+ domConstruct.destroy(this._fileInput);
+ }
+ this._setHtmlPostData();
+ if(this.showProgress){
+ this._animateProgress();
+ }
+ var dfd = ioIframe.send({
+ url: this.uploadUrl.toString(),
+ form: this._formNode,
+ handleAs: "json",
+ error: lang.hitch(this, function(err){
+ this._error("HTML Upload Error:" + err.message);
+ }),
+ load: lang.hitch(this, function(data, ioArgs, widgetRef){
+ this._complete(data);
+ })
+ });
+ },
+
+ createHtmlUploader: function(){
+ // summary:
+ // Internal. Fires of methods to build HTML Uploader.
+ this._buildForm();
+ this._setFormStyle();
+ this._buildFileInput();
+ this._connectInput();
+ this._styleContent();
+ domStyle.set(this.insideNode, "visibility", "visible");
+ this.onReady();
+ },
+
+ _connectInput: function(){
+ // summary:
+ // Internal. HTML Uploader connections. These get disconnected
+ // after upload or if multi upload.
+ this._disconnect();
+ this._cons.push(connect.connect(this._fileInput, "mouseover", this, function(evt){
+ domClass.add(this.domNode, this.hoverClass);
+ this.onMouseOver(evt);
+ }));
+ this._cons.push(connect.connect(this._fileInput, "mouseout", this, function(evt){
+ setTimeout(lang.hitch(this, function(){
+ domClass.remove(this.domNode, this.activeClass);
+ domClass.remove(this.domNode, this.hoverClass);
+ this.onMouseOut(evt);
+ this._checkHtmlCancel("off");
+ }), 0);
+ }));
+ this._cons.push(connect.connect(this._fileInput, "mousedown", this, function(evt){
+ domClass.add(this.domNode, this.activeClass);
+ domClass.remove(this.domNode, this.hoverClass);
+ this.onMouseDown(evt);
+ }));
+ this._cons.push(connect.connect(this._fileInput, "mouseup", this, function(evt){
+ domClass.remove(this.domNode, this.activeClass);
+ this.onMouseUp(evt);
+ this.onClick(evt);
+ this._checkHtmlCancel("up");
+ }));
+ this._cons.push(connect.connect(this._fileInput, "change", this, function(){
+ this._checkHtmlCancel("change");
+ this._change([{
+ name: this._fileInput.value,
+ type: "",
+ size: 0
+ }]);
+ }));
+ if(this.tabIndex>=0){
+ domAttr.set(this.domNode, "tabIndex", this.tabIndex);
+ }
+ },
+
+ _checkHtmlCancel: function(mouseType){
+ // summary:
+ // Internal. Check if the dialog was opened and canceled without file selection.
+ if(mouseType == "change"){
+ this.dialogIsOpen = false;
+ }
+ if(mouseType == "up"){
+ this.dialogIsOpen = true;
+ }
+ if(mouseType == "off"){
+ if(this.dialogIsOpen){
+ this.onCancel();
+ }
+ this.dialogIsOpen = false;
+ }
+ },
+
+ _styleContent: function(){
+ // summary:
+ // Internal.Apply style to node
+ var o = this.fhtml.nr;
+
+ domStyle.set(this.insideNode, {
+ width:o.w+"px",
+ height:o.va == "middle"?o.h+"px":"auto",
+ textAlign:o.ta,
+ paddingTop:o.p[0]+"px",
+ paddingRight:o.p[1]+"px",
+ paddingBottom:o.p[2]+"px",
+ paddingLeft:o.p[3]+"px"
+ });
+
+ try{
+ domStyle.set(this.insideNode, "lineHeight", "inherit");
+ }catch(e){
+ // There are certain cases where IE refuses to set lineHeight.
+ // For the life of me I cannot figure out the combination of
+ // styles that IE doesn't like. Steaming... Pile...
+ }
+
+ },
+ _resetHTML: function(){
+ // summary:
+ // Internal. After upload, this is called to clear the form and build a new
+ // fileInput.
+ if(this.uploaderType == "html" && this._formNode){
+ this.fileInputs = [];
+ query("*", this._formNode).forEach(function(n){
+ domConstruct.destroy(n);
+ });
+ this.fileCount = 0;
+ this._buildFileInput();
+ this._connectInput();
+ }
+ },
+ _buildForm: function(){
+ // summary:
+ // Build the form that holds the fileInput
+ //
+
+ if(this._formNode){ return; }
+
+ if(has("ie") < 9 || (has("ie") && has("quirks"))){
+ this._formNode = document.createElement('<form enctype="multipart/form-data" method="post">');
+ this._formNode.encoding = "multipart/form-data";
+ this._formNode.id = manager.getUniqueId("FileUploaderForm"); // needed for dynamic style
+ this.domNode.appendChild(this._formNode);
+ }else{
+ this._formNode = domConstruct.create('form', {
+ enctype:"multipart/form-data",
+ method:"post",
+ id:manager.getUniqueId("FileUploaderForm")
+ }, this.domNode);
+ }
+ },
+
+ _buildFileInput: function(){
+ // summary:
+ // Build the fileInput field
+ //
+ if(this._fileInput){
+ this._disconnect();
+ // FIXME:
+ // Just hiding it which works, but we lose
+ // reference to it and can't remove it from
+ // the upload list.
+ this._fileInput.id = this._fileInput.id + this.fileCount;
+ domStyle.set(this._fileInput, "display", "none");
+ }
+ this._fileInput = document.createElement('input');
+ this.fileInputs.push(this._fileInput);
+ // server will need to know this variable:
+ var nm = this.htmlFieldName;
+ var _id = this.id;
+ if(this.selectMultipleFiles){
+ nm += this.fileCount;
+ _id += this.fileCount;
+ this.fileCount++;
+ }
+
+ domAttr.set(this._fileInput, {
+ id:this.id,
+ name:nm,
+ type:"file"
+ });
+
+ domClass.add(this._fileInput, "dijitFileInputReal");
+ this._formNode.appendChild(this._fileInput);
+ var real = domGeometry.getMarginBox(this._fileInput);
+ domStyle.set(this._fileInput, {
+ position:"relative",
+ left:(this.fhtml.nr.w - real.w) + "px",
+ opacity:0
+ });
+ },
+
+ _renumberInputs: function(){
+ if(!this.selectMultipleFiles){ return; }
+ var nm;
+ this.fileCount = 0;
+ array.forEach(this.fileInputs, function(inp){
+ nm = this.htmlFieldName + this.fileCount;
+ this.fileCount++;
+ domAttr.set(inp, "name", nm);
+ }, this);
+ },
+
+ _setFormStyle: function(){
+ // summary:
+ // Apply a dynamic style to the form and input
+ var size = Math.max(2, Math.max(Math.ceil(this.fhtml.nr.w / 60), Math.ceil(this.fhtml.nr.h / 15)));
+ // Now create a style associated with the form ID
+ htmlStyles.insertCssRule("#" + this._formNode.id + " input", "font-size:" + size + "em");
+ domStyle.set(this.domNode, {
+ overflow:"hidden",
+ position:"relative"
+ });
+ domStyle.set(this.insideNode, "position", "absolute");
+ },
+
+ _setHtmlPostData: function(){
+ // summary:
+ // Internal.Apply postData to hidden fields in form
+ if(this.postData){
+ for(var nm in this.postData){
+ domConstruct.create("input", {
+ type: "hidden",
+ name: nm,
+ value: this.postData[nm]
+ }, this._formNode);
+ }
+ }
+ },
+
+ /*************************
+ * FLASH *
+ *************************/
+ uploadFlash: function(){
+ // summary:
+ // Internal. You should use upload() or submit();
+ try{
+ if(this.showProgress){
+ this._displayProgress(true);
+ var c = connect.connect(this, "_complete", this, function(){
+ connect.disconnect(c);
+ this._displayProgress(false);
+ });
+ }
+
+ var o = {};
+ for(var nm in this.postData){
+ o[nm] = this.postData[nm];
+ }
+ this.flashMovie.doUpload(o);
+
+ }catch(err){
+ this._error("FileUploader - Sorry, the SWF failed to initialize." + err);
+ }
+ },
+
+ createFlashUploader: function(){
+ // summary:
+ // Internal. Creates Flash Uploader
+ this.uploadUrl = this.uploadUrl.toString();
+ if(this.uploadUrl){
+ if(this.uploadUrl.toLowerCase().indexOf("http")<0 && this.uploadUrl.indexOf("/")!=0){
+ // Appears to be a relative path. Attempt to
+ // convert it to absolute, so it will better
+ //target the SWF.
+ //
+ var loc = window.location.href.split("/");
+ loc.pop();
+ loc = loc.join("/")+"/";
+ this.uploadUrl = loc+this.uploadUrl;
+ this.log("SWF Fixed - Relative loc:", loc, " abs loc:", this.uploadUrl);
+ }else{
+ this.log("SWF URL unmodified:", this.uploadUrl)
+ }
+ }else{
+ console.warn("Warning: no uploadUrl provided.");
+ }
+
+ var w = this.fhtml.nr.w;
+ var h = this.fhtml.nr.h;
+
+ var args = {
+ expressInstall:true,
+ path: this.swfPath.uri || this.swfPath,
+ width: w,
+ height: h,
+ allowScriptAccess:"always",
+ allowNetworking:"all",
+ vars: {
+ uploadDataFieldName: this.flashFieldName,
+ uploadUrl: this.uploadUrl,
+ uploadOnSelect: this.uploadOnChange,
+ deferredUploading:this.deferredUploading || 0,
+ selectMultipleFiles: this.selectMultipleFiles,
+ id: this.id,
+ isDebug: this.isDebug,
+ devMode:this.devMode,
+ flashButton:embedFlashVars.serialize("fh", this.fhtml),
+ fileMask:embedFlashVars.serialize("fm", this.fileMask),
+ noReturnCheck: this.skipServerCheck,
+ serverTimeout:this.serverTimeout
+ },
+ params: {
+ scale:"noscale",
+ wmode:"opaque",
+ allowScriptAccess:"always",
+ allowNetworking:"all"
+ }
+
+ };
+
+ this.flashObject = new embedFlash(args, this.insideNode);
+ this.flashObject.onError = lang.hitch(function(msg){
+ this._error("Flash Error: " + msg);
+ });
+ this.flashObject.onReady = lang.hitch(this, function(){
+ domStyle.set(this.insideNode, "visibility", "visible");
+ this.log("FileUploader flash object ready");
+ this.onReady(this);
+ });
+ this.flashObject.onLoad = lang.hitch(this, function(mov){
+ this.flashMovie = mov;
+ this.flashReady = true;
+
+ this.onLoad(this);
+ });
+ this._connectFlash();
+
+ },
+
+ _connectFlash: function(){
+ // summary:
+ // Subscribing to published topics coming from the
+ // Flash uploader.
+ // description:
+ // Sacrificing some readbilty for compactness. this.id
+ // will be on the beginning of the topic, so more than
+ // one uploader can be on a page and can have unique calls.
+ //
+ this._doSub("/filesSelected", "_change");
+ this._doSub("/filesUploaded", "_complete");
+ this._doSub("/filesProgress", "_progress");
+ this._doSub("/filesError", "_error");
+ this._doSub("/filesCanceled", "onCancel");
+ this._doSub("/stageBlur", "_onFlashBlur");
+ this._doSub("/up", "onMouseUp");
+ this._doSub("/down", "onMouseDown");
+ this._doSub("/over", "onMouseOver");
+ this._doSub("/out", "onMouseOut");
+
+ this.connect(this.domNode, "focus", function(){
+ // TODO: some kind of indicator that the Flash button
+ // is in focus
+ this.flashMovie.focus();
+ this.flashMovie.doFocus();
+ });
+ if(this.tabIndex>=0){
+ domAttr.set(this.domNode, "tabIndex", this.tabIndex);
+ }
+ },
+
+ _doSub: function(subStr, funcStr){
+ // summary:
+ // Internal. Shortcut for subscribes to Flash movie
+ this._subs.push(connect.subscribe(this.id + subStr, this, funcStr));
+ },
+
+ /*************************************
+ * DOM INSPECTION METHODS *
+ *************************************/
+
+ urlencode: function(url){
+ // Using symbols in place of URL chars that will break in Flash serialization.
+ if(!url || url == "none"){
+ return false;
+ }
+ return url.replace(/:/g,"||").replace(/\./g,"^^").replace("url(", "").replace(")","").replace(/'/g,"").replace(/"/g,"");
+ },
+
+ isButton: function(node){
+ // testing if button for styling purposes
+ var tn = node.tagName.toLowerCase();
+ return tn == "button" || tn == "input";
+ },
+
+ getTextStyle: function(node){
+ // getting font info
+ var o = {};
+ o.ff = domStyle.get(node, "fontFamily");
+ if(o.ff){
+ o.ff = o.ff.replace(", ", ","); // remove spaces. IE in Flash no likee
+ o.ff = o.ff.replace(/\"|\'/g, "");
+ o.ff = o.ff == "sans-serif" ? "Arial" : o.ff; // Flash doesn't know what sans-serif is
+ o.fw = domStyle.get(node, "fontWeight");
+ o.fi = domStyle.get(node, "fontStyle");
+ o.fs = parseInt(domStyle.get(node, "fontSize"), 10);
+ if(domStyle.get(node, "fontSize").indexOf("%") > -1){
+ // IE doesn't convert % to px. For god sakes.
+ var n = node;
+ while(n.tagName){
+ if(domStyle.get(n, "fontSize").indexOf("%") == -1){
+ o.fs = parseInt(domStyle.get(n, "fontSize"), 10);
+ break;
+ }
+ if(n.tagName.toLowerCase()=="body"){
+ // if everyting is %, the the font size is 16px * the %
+ o.fs = 16 * .01 * parseInt(domStyle.get(n, "fontSize"), 10);
+ }
+ n = n.parentNode;
+ }
+ }
+ o.fc = new Color(domStyle.get(node, "color")).toHex();
+ o.fc = parseInt(o.fc.substring(1,Infinity),16);
+ }
+ o.lh = domStyle.get(node, "lineHeight");
+ o.ta = domStyle.get(node, "textAlign");
+ o.ta = o.ta == "start" || !o.ta ? "left" : o.ta;
+ o.va = this.isButton(node) ? "middle" : o.lh == o.h ? "middle" : domStyle.get(node, "verticalAlign");
+ return o;
+ },
+
+ getText: function(node){
+ // Get the text of the button. It's possible to use HTML in the Flash Button,
+ // but the results are not spectacular.
+ var cn = lang.trim(node.innerHTML);
+ if(cn.indexOf("<") >- 1){
+ cn = escape(cn);
+ }
+ return cn;
+ },
+
+ getStyle: function(node){
+ // getting the style of a node. Using very abbreviated characters which the
+ // Flash movie understands.
+ var o = {};
+ var dim = domGeometry.getContentBox(node);
+ var pad = domGeometry.getPadExtents(node);
+ o.p = [pad.t, pad.w-pad.l, pad.h-pad.t, pad.l];
+ o.w = dim.w + pad.w;
+ o.h = dim.h + pad.h;
+ o.d = domStyle.get(node, "display");
+ var clr = new Color(domStyle.get(node, "backgroundColor"));
+ // if no color, Safari sets #000000 and alpha=0 since we don't support alpha,
+ // it makes black - make it white
+ o.bc = clr.a == 0 ? "#ffffff" : clr.toHex();
+ o.bc = parseInt(o.bc.substring(1,Infinity),16);
+ var url = this.urlencode(domStyle.get(node, "backgroundImage"));
+ if(url){
+ o.bi = {
+ url:url,
+ rp:domStyle.get(node, "backgroundRepeat"),
+ pos: escape(domStyle.get(node, "backgroundPosition"))
+ };
+ if(!o.bi.pos){
+ // IE does Xpx and Ypx, not "X% Y%"
+ var rx = domStyle.get(node, "backgroundPositionX");
+ var ry = domStyle.get(node, "backgroundPositionY");
+ rx = (rx == "left") ? "0%" : (rx == "right") ? "100%" : rx;
+ ry = (ry == "top") ? "0%" : (ry == "bottom") ? "100%" : ry;
+ o.bi.pos = escape(rx+" "+ry);
+ }
+ }
+ return lang.mixin(o, this.getTextStyle(node));
+ },
+
+ getTempNodeStyle: function(node, _class, isDijitButton){
+ // This sets up a temp node to get the style of the hover, active, and disabled states
+ var temp, style;
+ if(isDijitButton){
+ // backwards compat until dojo 1.5
+ temp = domConstruct.place("<"+node.tagName+"><span>"+node.innerHTML+"</span></"+node.tagName+">", node.parentNode); //+" "+_class+"
+ var first = temp.firstChild;
+ domClass.add(first, node.className);
+ domClass.add(temp, _class);
+ style = this.getStyle(first);
+ }else{
+ temp = domConstruct.place("<"+node.tagName+">"+node.innerHTML+"</"+node.tagName+">", node.parentNode);
+ domClass.add(temp, node.className);
+ domClass.add(temp, _class);
+ temp.id = node.id;
+ style = this.getStyle(temp);
+ }
+ // dev note: comment out this line to see what the
+ // button states look like to the FileUploader
+ domConstruct.destroy(temp);
+ return style;
+ }
+});
+return dojox.form.FileUploader;
+});
diff --git a/js/dojo/dojox/form/ListInput.js b/js/dojo/dojox/form/ListInput.js
new file mode 100644
index 0000000..c4d3eb7
--- /dev/null
+++ b/js/dojo/dojox/form/ListInput.js
@@ -0,0 +1,1017 @@
+//>>built
+define("dojox/form/ListInput", [
+ "dojo/_base/kernel",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojo/_base/json",
+ "dojo/_base/fx",
+ "dojo/_base/window",
+ "dojo/_base/connect",
+ "dojo/dom-class",
+ "dojo/dom-style",
+ "dojo/dom-construct",
+ "dojo/dom-geometry",
+ "dojo/keys",
+ "dijit/_Widget",
+ "dijit/_TemplatedMixin",
+ "dijit/form/_FormValueWidget",
+ "dijit/form/ValidationTextBox",
+ "dijit/InlineEditBox",
+ "dojo/i18n!dijit/nls/common",
+ "dojo/_base/declare"
+], function(kernel, lang, array, jsonUtil, fx, win, connect, domClass, domStyle, domConstruct, domGeometry, keys, Widget, TemplatedMixin, FormValueWidget, ValidationTextBox, InlineEditBox, i18nCommon, declare){
+kernel.experimental("dojox.form.ListInput");
+
+ /*=====
+ Widget = dijit._Widget;
+ Templated = dijit._TemplatedMixin;
+ FormValueWidget = dijit.form._FormValueWidget;
+ ValidationTextBox = dijit.form.ValidationTextBox;
+ =====*/
+var ListInput = declare("dojox.form.ListInput", [FormValueWidget],
+ {
+ // summary:
+ // An automatic list maker
+ // description:
+ // you can add value to list with add method.
+ // you can only remove by clicking close button
+
+ constructor: function(){
+ this._items = [];
+
+
+ if(!lang.isArray(this.delimiter)){
+ this.delimiter=[this.delimiter];
+ }
+ var r="("+this.delimiter.join("|")+")?";
+ this.regExp="^"+this.regExp+r+"$";
+ },
+
+ // inputClass: String
+ // Class which will be used to create the input box. You can implements yours.
+ // It must be a widget, focusNode or domNode must have "onkeydown" event
+ // It must have .attr("value") to get value
+ // It also must impement an (or more) handler for the "onChange" method
+ inputClass: "dojox.form._ListInputInputBox",
+
+ // inputHandler: String || Array
+ // The widget will connect on all handler to check input value
+ // You can use comma separated list
+ inputHandler: "onChange",
+
+ // inputProperties: String || Object
+ // Properties used to create input box
+ // If String, it must be a valid JSON
+ inputProperties: {
+ minWidth:50
+ },
+
+ // submitOnlyValidValue: Boolean
+ // If true, only valid value will be submited with form
+ submitOnlyValidValue:true,
+
+ // useOnBlur: Boolean
+ // If true, onBlur event do a validate (like pressing ENTER)
+ useOnBlur:true,
+
+ // readOnlyInput: Boolean
+ // if false, the list will be editable
+ // Can only be set when instanciate
+ readOnlyInput: false,
+
+ // maxItems: Int
+ // Specify max item the list can have
+ // null = infiny
+ maxItems: null,
+
+ // showCloseButtonWhenValid: Boolean
+ // if true, a close button will be added on valid item
+ showCloseButtonWhenValid: true,
+
+ // showCloseButtonWhenInvalid: Boolean
+ // if true, a close button will be added on invalid item
+ showCloseButtonWhenInvalid: true,
+
+ // regExp: [extension protected] String
+ // regular expression string used to validate the input
+ // Do not specify both regExp and regExpGen
+ regExp: ".*", //"[a-zA-Z.-_]+@[a-zA-Z.-_]+.[a-zA-Z]+",
+
+ // delimiter: String || Array
+ // delimiter for the string. Every match will be splitted
+ // The string can contain only one delimiter
+ delimiter: ",",
+
+ // constraints: ValidationTextBox.__Constraints
+ // user-defined object needed to pass parameters to the validator functions
+ constraints: {},
+
+ baseClass:"dojoxListInput",
+
+ type: "select",
+
+ value: "",
+
+ templateString: "<div dojoAttachPoint=\"focusNode\" class=\"dijit dijitReset dijitLeft dojoxListInput\"><select dojoAttachpoint=\"_selectNode\" multiple=\"multiple\" class=\"dijitHidden\" ${!nameAttrSetting}></select><ul dojoAttachPoint=\"_listInput\"><li dojoAttachEvent=\"onclick: _onClick\" class=\"dijitInputField dojoxListInputNode dijitHidden\" dojoAttachPoint=\"_inputNode\"></li></ul></div>",
+
+ // useAnim: Boolean
+ // If true, then item will use an anime to show hide itself
+ useAnim: true,
+
+ // duration: Integer
+ // Animation duration
+ duration: 500,
+
+ // easingIn: function
+ // function used to easing on fadeIn end
+ easingIn: null,
+
+ // easingOut: function
+ // function used to easing on fadeOut end
+ easingOut: null,
+
+ // readOnlyItem: Boolean
+ // If true, items can be edited
+ // Can only be set when instanciate
+ readOnlyItem: false,
+
+ // useArrowForEdit: Boolean
+ // If true, arraow left and right can be used for editing
+ // Can only be set when instanciate
+ useArrowForEdit: true,
+
+ // _items: Array
+ // Array of widget.
+ // Contain all reference to _ListInputInputItem
+ _items: null,
+
+ // _lastAddedItem: Widget
+ // Contain a reference to the last created item
+ _lastAddedItem: null,
+
+ // _currentItem: Widget
+ // Widget currently in edition
+ _currentItem: null,
+
+ // _input: Widget
+ // Widget use for input box
+ _input: null,
+
+ // _count: Int
+ // Count items
+ _count: 0,
+
+ postCreate: function(){
+ // summary:
+ // If closeButton is used, add a class
+ this.inherited(arguments);
+ this._createInputBox();
+ },
+
+ _setReadOnlyInputAttr: function(/*Boolean*/value){
+ // summary:
+ // Change status and if needed, create the inputbox
+ // tags:
+ // private
+ if(!this._started){ return this._createInputBox(); }
+ this.readOnlyInput = value;
+ this._createInputBox();
+ },
+
+ _setReadOnlyItemAttr: function(/*Boolean*/value){
+ // summary:
+ // set read only items
+ // tags:
+ // private
+ if(!this._started){ return; }
+ for(var i in this._items){
+ this._items[i].set("readOnlyItem", value);
+ }
+ },
+
+ _createInputBox: function(){
+ // summary:
+ // Create the input box
+ // tags:
+ // private
+ domClass.toggle(this._inputNode, "dijitHidden", this.readOnlyInput);
+ if(this.readOnlyInput){ return; }
+ if(this._input){ return; }
+
+ if(this.inputHandler === null){
+ console.warn("you must add some handler to connect to input field");
+ return false;
+ }
+ if(lang.isString(this.inputHandler)){
+ this.inputHandler = this.inputHandler.split(",");
+ }
+ if(lang.isString(this.inputProperties)){
+ this.inputProperties = jsonUtil.fromJson(this.inputProperties);
+ }
+
+
+ var input = lang.getObject(this.inputClass, false);
+
+ this.inputProperties.regExp = this.regExpGen(this.constraints);
+
+ this._input = new input(this.inputProperties);
+ this._input.startup();
+ this._inputNode.appendChild(this._input.domNode);
+ array.forEach(this.inputHandler, function(handler){
+ this.connect(this._input,lang.trim(handler),"_onHandler");
+ },this);
+
+ this.connect(this._input, "onKeyDown", "_inputOnKeyDown");
+ this.connect(this._input, "onBlur", "_inputOnBlur");
+ },
+
+ compare: function(/*Array*/val1,/*Array*/val2){
+ // summary:
+ // Compare 2 values (as returned by attr('value') for this widget).
+ // tags:
+ // protected
+ val1 = val1.join(",");
+ val2 = val2.join(",");
+ if(val1 > val2){
+ return 1;
+ }else if(val1 < val2){
+ return -1;
+ }else{
+ return 0;
+ }
+ },
+
+ add: function(/*String || Array*/values){
+ // summary:
+ // Create new list element
+ if(this._count>=this.maxItems && this.maxItems !== null){return;}
+ this._lastValueReported = this._getValues();
+
+ if(!lang.isArray(values)){
+ values = [values];
+ }
+
+ for(var i in values){
+ var value=values[i];
+ if(value === "" || typeof value != "string"){
+ continue;
+ }
+ this._count++;
+ var re = new RegExp(this.regExpGen(this.constraints));
+
+ this._lastAddedItem = new _ListInputInputItem({
+ "index" : this._items.length,
+ readOnlyItem : this.readOnlyItem,
+ value : value,
+ regExp: this.regExpGen(this.constraints)
+ });
+ this._lastAddedItem.startup();
+
+ this._testItem(this._lastAddedItem,value);
+
+ this._lastAddedItem.onClose = lang.hitch(this,"_onItemClose",this._lastAddedItem);
+ this._lastAddedItem.onChange = lang.hitch(this,"_onItemChange",this._lastAddedItem);
+ this._lastAddedItem.onEdit = lang.hitch(this,"_onItemEdit",this._lastAddedItem);
+ this._lastAddedItem.onKeyDown = lang.hitch(this,"_onItemKeyDown",this._lastAddedItem);
+
+ if(this.useAnim){
+ domStyle.set(this._lastAddedItem.domNode, {opacity:0, display:""});
+ }
+
+ this._placeItem(this._lastAddedItem.domNode);
+
+ if(this.useAnim){
+ var anim = fx.fadeIn({
+ node : this._lastAddedItem.domNode,
+ duration : this.duration,
+ easing : this.easingIn
+ }).play();
+ }
+
+ this._items[this._lastAddedItem.index] = this._lastAddedItem;
+
+ if(this._onChangeActive && this.intermediateChanges){ this.onChange(value); }
+
+ if(this._count>=this.maxItems && this.maxItems !== null){
+ break;
+ }
+ }
+
+ this._updateValues();
+ if(this._lastValueReported.length==0){
+ this._lastValueReported = this.value;
+ }
+
+ if(!this.readOnlyInput){
+ this._input.set("value", "");
+ }
+
+ if(this._onChangeActive){ this.onChange(this.value); }
+
+ this._setReadOnlyWhenMaxItemsReached();
+ },
+
+ _setReadOnlyWhenMaxItemsReached: function(){
+ // summary:
+ // set input to readonly when max is reached
+ // tags:
+ // private
+ this.set("readOnlyInput",(this._count>=this.maxItems && this.maxItems !== null));
+ },
+
+ _setSelectNode: function(){
+ // summary:
+ // put all item in the select (for a submit)
+ // tags:
+ // private
+ this._selectNode.options.length = 0;
+
+ var values=this.submitOnlyValidValue?this.get("MatchedValue"):this.value;
+
+ if(!lang.isArray(values)){
+ return;
+ }
+ array.forEach(values,function(item){
+ this._selectNode.options[this._selectNode.options.length]=new Option(item,item,true,true);
+ },this);
+ },
+
+ _placeItem: function(/*domNode*/node){
+ // summary:
+ // Place item in the list
+ // tags:
+ // private
+ domConstruct.place(node,this._inputNode,"before");
+ },
+
+ _getCursorPos: function(/*domNode*/node){
+ // summary:
+ // get current cursor pos
+ // tags:
+ // private
+ if(typeof node.selectionStart != 'undefined'){
+ return node.selectionStart;
+ }
+
+ // IE Support
+ try{ node.focus(); }catch(e){}
+ var range = node.createTextRange();
+ range.moveToBookmark(win.doc.selection.createRange().getBookmark());
+ range.moveEnd('character', node.value.length);
+ try{
+ return node.value.length - range.text.length;
+ }finally{ range=null; }
+ },
+
+ _onItemClose: function(/*dijit._Widget*/ item){
+ // summary:
+ // Destroy a list element when close button is clicked
+ // tags:
+ // private
+ if(this.disabled){ return; }
+
+ if(this.useAnim){
+ var anim = fx.fadeOut({
+ node : item.domNode,
+ duration : this.duration,
+ easing : this.easingOut,
+ onEnd : lang.hitch(this, "_destroyItem", item)
+ }).play();
+ }else{
+ this._destroyItem(item);
+ }
+ },
+
+ _onItemKeyDown: function(/*dijit._Widget*/ item, /*Event*/ e){
+ // summary:
+ // Call when item get a keypress
+ // tags:
+ // private
+ if(this.readOnlyItem || !this.useArrowForEdit){ return; }
+
+ if(e.keyCode == keys.LEFT_ARROW && this._getCursorPos(e.target)==0){
+ this._editBefore(item);
+ }else if(e.keyCode == keys.RIGHT_ARROW && this._getCursorPos(e.target)==e.target.value.length){
+ this._editAfter(item);
+ }
+ },
+
+ _editBefore: function(/*widget*/item){
+ // summary:
+ // move trough items
+ // tags:
+ // private
+ this._currentItem = this._getPreviousItem(item);
+ if(this._currentItem !== null){
+ this._currentItem.edit();
+ }
+ },
+ _editAfter: function(/*widget*/item){
+ // summary:
+ // move trough items
+ // tags:
+ // private
+ this._currentItem = this._getNextItem(item);
+ if(this._currentItem !== null){
+ this._currentItem.edit();
+ }
+
+ if(!this.readOnlyInput){
+ if(this._currentItem === null){
+ //no more item ?
+ //so edit input (if available)
+ this._focusInput();
+ }
+ }
+ },
+
+ _onItemChange: function(/*dijit._Widget*/ item, /*String*/ value){
+ // summary:
+ // Call when item value change
+ // tags:
+ // private
+
+ value = value || item.get("value");
+
+ //revalidate content
+ this._testItem(item,value);
+
+ //update value
+ this._updateValues();
+ },
+
+ _onItemEdit: function(/*dijit._Widget*/ item){
+ // summary:
+ // Call when item is edited
+ // tags:
+ // private
+ domClass.remove(item.domNode,["dijitError", this.baseClass + "Match", this.baseClass + "Mismatch"]);
+ },
+
+ _testItem: function(/*Object*/item,/*String*/value){
+ // summary:
+ // Change class of item (match, mismatch)
+ // tags:
+ // private
+ var re = new RegExp(this.regExpGen(this.constraints));
+ var match = ('' + value).match(re);
+
+ domClass.remove(item.domNode, this.baseClass + (!match ? "Match" : "Mismatch"));
+ domClass.add(item.domNode, this.baseClass + (match ? "Match" : "Mismatch"));
+ domClass.toggle(item.domNode, "dijitError", !match);
+
+ if((this.showCloseButtonWhenValid && match) ||
+ (this.showCloseButtonWhenInvalid && !match)){
+ domClass.add(item.domNode,this.baseClass+"Closable");
+ }else {
+ domClass.remove(item.domNode,this.baseClass+"Closable");
+ }
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // get all value in then list and return an array
+ // tags:
+ // private
+ return this.value;
+ },
+
+ _setValueAttr: function(/*Array || String*/ newValue){
+ // summary:
+ // Hook so attr('value', value) works.
+ // description:
+ // Sets the value of the widget.
+ // If the value has changed, then fire onChange event, unless priorityChange
+ // is specified as null (or false?)
+ this._destroyAllItems();
+
+ this.add(this._parseValue(newValue));
+ },
+
+ _parseValue: function(/*String*/newValue){
+ // summary:
+ // search for delemiters and split if needed
+ // tags:
+ // private
+ if(typeof newValue == "string"){
+ if(lang.isString(this.delimiter)){
+ this.delimiter = [this.delimiter];
+ }
+ var re = new RegExp("^.*("+this.delimiter.join("|")+").*");
+ if(newValue.match(re)){
+ re = new RegExp(this.delimiter.join("|"));
+ return newValue.split(re);
+ }
+ }
+ return newValue;
+ },
+
+ regExpGen: function(/*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
+ },
+
+ _setDisabledAttr: function(/*Boolean*/ value){
+ // summary:
+ // also enable/disable editable items
+ // tags:
+ // private
+ if(!this.readOnlyItem){
+ for(var i in this._items){
+ this._items[i].set("disabled", value);
+ }
+ }
+
+ if(!this.readOnlyInput){
+ this._input.set("disabled", value);
+ }
+ this.inherited(arguments);
+ },
+
+ _onHandler: function(/*String*/value){
+ // summary:
+ // When handlers of input are fired, this method check input value and (if needed) modify it
+ // tags:
+ // private
+ var parsedValue = this._parseValue(value);
+ if(lang.isArray(parsedValue)){
+ this.add(parsedValue);
+ }
+ },
+
+ _onClick: function(/*event*/e){
+ // summary:
+ // give focus to inputbox
+ // tags:
+ // private
+ this._focusInput();
+ },
+
+ _focusInput: function(){
+ // summary:
+ // give focus to input
+ // tags:
+ // private
+ if(!this.readOnlyInput && this._input.focus){
+ this._input.focus();
+ }
+ },
+
+ _inputOnKeyDown: function(/*event*/e){
+ // summary:
+ // Used to add keybord interactivity
+ // tags:
+ // private
+ this._currentItem = null;
+ var val = this._input.get("value");
+
+ if(e.keyCode == keys.BACKSPACE && val == "" && this.get("lastItem")){
+ this._destroyItem(this.get("lastItem"));
+ }else if(e.keyCode == keys.ENTER && val != ""){
+ this.add(val);
+ }else if(e.keyCode == keys.LEFT_ARROW && this._getCursorPos(this._input.focusNode) == 0 &&
+ !this.readOnlyItem && this.useArrowForEdit){
+ this._editBefore();
+ }
+ },
+
+ _inputOnBlur: function(){
+ // summary:
+ // Remove focus class and act like pressing ENTER key
+ // tags:
+ // private
+ var val = this._input.get('value');
+ if(this.useOnBlur && val != ""){
+ this.add(val);
+ }
+ },
+
+ _getMatchedValueAttr: function(){
+ // summary:
+ // get value that match regexp in then list and return an array
+ // tags:
+ // private
+ return this._getValues(lang.hitch(this,this._matchValidator));
+ },
+
+ _getMismatchedValueAttr: function(){
+ // summary:
+ // get value that mismatch regexp in then list and return an array
+ // tags:
+ // private
+ return this._getValues(lang.hitch(this,this._mismatchValidator));
+ },
+
+ _getValues: function(/*function*/validator){
+ // summary:
+ // return values with comparator constraint
+ // tags:
+ // private
+ var value = [];
+ validator = validator||this._nullValidator;
+ for(var i in this._items){
+ var item = this._items[i];
+ if(item === null){
+ continue;
+ }
+ var itemValue = item.get("value");
+ if(validator(itemValue)){
+ value.push(itemValue);
+ }
+ }
+ return value;
+ },
+
+ _nullValidator: function(/*String*/itemValue){
+ // summary:
+ // return true or false
+ // tags:
+ // private
+ return true;
+ },
+ _matchValidator: function(/*String*/itemValue){
+ // summary:
+ // return true or false
+ // tags:
+ // private
+ var re = new RegExp(this.regExpGen(this.constraints));
+ return itemValue.match(re);
+ },
+ _mismatchValidator: function(/*String*/itemValue){
+ // summary:
+ // return true or false
+ // tags:
+ // private
+ var re = new RegExp(this.regExpGen(this.constraints));
+ return !(itemValue.match(re));
+ },
+
+ _getLastItemAttr: function(){
+ // summary:
+ // return the last item in list
+ // tags:
+ // private
+ return this._getSomeItem();
+ },
+ _getSomeItem: function(/*dijit._Widget*/ item,/*String*/ position){
+ // summary:
+ // return the item before the one in params
+ // tags:
+ // private
+ item=item||false;
+ position=position||"last";
+
+ var lastItem = null;
+ var stop=-1;
+ for(var i in this._items){
+ if(this._items[i] === null){ continue; }
+
+ if(position=="before" && this._items[i] === item){
+ break;
+ }
+
+ lastItem = this._items[i];
+
+ if(position=="first" ||stop==0){
+ stop=1;
+ break;
+ }
+ if(position=="after" && this._items[i] === item){
+ stop=0;
+ }
+ }
+ if(position=="after" && stop==0){
+ lastItem = null;
+ }
+ return lastItem;
+ },
+ _getPreviousItem: function(/*dijit._Widget*/ item){
+ // summary:
+ // return the item before the one in params
+ // tags:
+ // private
+ return this._getSomeItem(item,"before");
+ },
+ _getNextItem: function(/*dijit._Widget*/ item){
+ // summary:
+ // return the item before the one in params
+ // tags:
+ // private
+ return this._getSomeItem(item,"after");
+ },
+
+ _destroyItem: function(/*dijit._Widget*/ item, /*Boolean?*/ updateValue){
+ // summary:
+ // destroy an item
+ // tags:
+ // private
+ this._items[item.index] = null;
+ item.destroy();
+ this._count--;
+ if(updateValue!==false){
+ this._updateValues();
+ this._setReadOnlyWhenMaxItemsReached();
+ }
+ },
+
+ _updateValues: function(){
+ // summary:
+ // update this.value and the select node
+ // tags:
+ // private
+ this.value = this._getValues();
+ this._setSelectNode();
+ },
+
+ _destroyAllItems: function(){
+ // summary:
+ // destroy all items
+ // tags:
+ // private
+ for(var i in this._items){
+ if(this._items[i]==null){ continue; }
+ this._destroyItem(this._items[i],false);
+ }
+ this._items = [];
+ this._count = 0;
+ this.value = null;
+ this._setSelectNode();
+ this._setReadOnlyWhenMaxItemsReached();
+ },
+
+ destroy: function(){
+ // summary:
+ // Destroy all widget
+ this._destroyAllItems();
+ this._lastAddedItem = null;
+
+ if(!this._input){
+ this._input.destroy();
+ }
+
+ this.inherited(arguments);
+ }
+});
+
+var _ListInputInputItem = declare("dojox.form._ListInputInputItem", [Widget, TemplatedMixin],
+ {
+ // summary:
+ // Item created by ListInputInput when delimiter is found
+ // description:
+ // Simple <li> with close button added to ListInputInput when delimiter is found
+
+ templateString: "<li class=\"dijit dijitReset dijitLeft dojoxListInputItem\" dojoAttachEvent=\"onclick: onClick\" ><span dojoAttachPoint=\"labelNode\"></span></li>",
+
+ // closeButtonNode: domNode
+ // ref to the close button node
+ closeButtonNode: null,
+
+ // readOnlyItem: Boolean
+ // if true, item is editable
+ readOnlyItem: true,
+
+ baseClass:"dojoxListInputItem",
+
+ // value: String
+ // value of item
+ value: "",
+
+ // regExp: [extension protected] String
+ // regular expression string used to validate the input
+ // Do not specify both regExp and regExpGen
+ regExp: ".*",
+
+ // _editBox: Widget
+ // inline edit box
+ _editBox: null,
+
+ // _handleKeyDown: handle
+ // handle for the keyDown connect
+ _handleKeyDown: null,
+
+ attributeMap: {
+ value: { node: "labelNode", type: "innerHTML" }
+ },
+
+ postMixInProperties: function(){
+ var _nlsResources = i18nCommon;
+ lang.mixin(this, _nlsResources);
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ // summary:
+ // Create the close button if needed
+ this.inherited(arguments);
+
+ this.closeButtonNode = domConstruct.create("span",{
+ "class" : "dijitButtonNode dijitDialogCloseIcon",
+ title : this.itemClose,
+ onclick: lang.hitch(this, "onClose"),
+ onmouseenter: lang.hitch(this, "_onCloseEnter"),
+ onmouseleave: lang.hitch(this, "_onCloseLeave")
+ }, this.domNode);
+
+ domConstruct.create("span",{
+ "class" : "closeText",
+ title : this.itemClose,
+ innerHTML : "x"
+ }, this.closeButtonNode);
+ },
+
+ startup: function(){
+ // summary:
+ // add the edit box
+ this.inherited(arguments);
+ this._createInlineEditBox();
+ },
+
+ _setReadOnlyItemAttr: function(/*Boolean*/value){
+ // summary:
+ // change the readonly state
+ // tags:
+ // private
+ this.readOnlyItem = value;
+ if(!value){
+ this._createInlineEditBox();
+ }else if(this._editBox){
+ this._editBox.set("disabled", true);
+ }
+ },
+
+ _createInlineEditBox: function(){
+ // summary:
+ // create the inline editbox if needed
+ // tags:
+ // private
+ if(this.readOnlyItem){ return; }
+ if(!this._started){ return; }
+ if(this._editBox){
+ this._editBox.set("disabled",false);
+ return;
+ }
+ this._editBox = new InlineEditBox({
+ value:this.value,
+ editor: "dijit.form.ValidationTextBox",
+ editorParams:{
+ regExp:this.regExp
+ }
+ },this.labelNode);
+ this.connect(this._editBox,"edit","_onEdit");
+ this.connect(this._editBox,"onChange","_onCloseEdit");
+ this.connect(this._editBox,"onCancel","_onCloseEdit");
+ },
+
+ edit: function(){
+ // summary:
+ // enter inline editbox in edit mode
+ if(!this.readOnlyItem){
+ this._editBox.edit();
+ }
+ },
+
+ _onCloseEdit: function(/*String*/value){
+ // summary:
+ // call when inline editor close himself
+ // tags:
+ // private
+ domClass.remove(this.closeButtonNode,this.baseClass + "Edited");
+ connect.disconnect(this._handleKeyDown);
+ this.onChange(value);
+ },
+
+ _onEdit: function(){
+ // summary:
+ // call when inline editor start editing
+ // tags:
+ // private
+ domClass.add(this.closeButtonNode,this.baseClass + "Edited");
+ this._handleKeyDown = connect.connect(this._editBox.editWidget,"_onKeyPress",this,"onKeyDown");
+ this.onEdit();
+ },
+
+ _setDisabledAttr: function(/*Boolean*/value){
+ // summary:
+ // disable inline edit box
+ // tags:
+ // private
+ if(!this.readOnlyItem){
+ this._editBox.set("disabled", value);
+ }
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // return value
+ // tags:
+ // private
+ return (!this.readOnlyItem && this._started ? this._editBox.get("value") : this.value);
+ },
+
+ destroy: function(){
+ // summary:
+ // Destroy the inline editbox
+ if(this._editBox){
+ this._editBox.destroy();
+ }
+ this.inherited(arguments);
+ },
+
+ _onCloseEnter: function(){
+ // summary:
+ // Called when user hovers over close icon
+ // tags:
+ // private
+ domClass.add(this.closeButtonNode, "dijitDialogCloseIcon-hover");
+ },
+
+ _onCloseLeave: function(){
+ // summary:
+ // Called when user stops hovering over close icon
+ // tags:
+ // private
+ domClass.remove(this.closeButtonNode, "dijitDialogCloseIcon-hover");
+ },
+
+ onClose: function(){
+ // summary:
+ // callback when close button is clicked
+ },
+
+ onEdit: function(){
+ // summary:
+ // callback when widget come in edition
+ },
+
+ onClick: function(){
+ // summary:
+ // callback when widget is click
+ },
+
+ onChange: function(/*String*/value){
+ // summary:
+ // callback when widget change its content
+ },
+
+
+ onKeyDown: function(/*String*/value){
+ // summary:
+ // callback when widget get a KeyDown
+ }
+});
+var _ListInputInputBox = declare("dojox.form._ListInputInputBox", [ValidationTextBox],
+ {
+ // summary:
+ // auto-sized text box
+ // description:
+ // Auto sized textbox based on dijit.form.TextBox
+
+ // minWidth: Integer
+ // Min width of the input box
+ minWidth:50,
+
+ // intermediateChanges: Boolean
+ // Fires onChange for each value change or only on demand
+ // Force to true in order to get onChanged called
+ intermediateChanges:true,
+
+ // regExp: [extension protected] String
+ // regular expression string used to validate the input
+ // Do not specify both regExp and regExpGen
+ regExp: ".*",
+
+ // _sizer: DomNode
+ // Used to get size of textbox content
+ _sizer:null,
+
+ onChange: function(/*string*/value){
+ // summary:
+ // compute content width
+ this.inherited(arguments);
+ if(this._sizer === null){
+ this._sizer = domConstruct.create("div",{
+ style : {
+ position : "absolute",
+ left : "-10000px",
+ top : "-10000px"
+ }
+ },win.body());
+ }
+ this._sizer.innerHTML = value;
+ var w = domGeometry.getContentBox(this._sizer).w + this.minWidth;
+ domGeometry.setContentSize(this.domNode,{ w : w });
+ },
+
+ destroy: function(){
+ // summary:
+ // destroy the widget
+ domConstruct.destroy(this._sizer);
+ this.inherited(arguments);
+ }
+});
+return ListInput;
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/Manager.js b/js/dojo/dojox/form/Manager.js
new file mode 100644
index 0000000..8ae1f53
--- /dev/null
+++ b/js/dojo/dojox/form/Manager.js
@@ -0,0 +1,55 @@
+//>>built
+define("dojox/form/Manager", [
+ "dijit/_Widget",
+ "dijit/_TemplatedMixin",
+ "./manager/_Mixin",
+ "./manager/_NodeMixin",
+ "./manager/_FormMixin",
+ "./manager/_ValueMixin",
+ "./manager/_EnableMixin",
+ "./manager/_DisplayMixin",
+ "./manager/_ClassMixin",
+ "dojo/_base/declare"
+], function(_Widget, _TemplatedMixin, _Mixin, _NodeMixin, _FormMixin, _ValueMixin, _EnableMixin, _DisplayMixin, _ClassMixin, declare){
+
+ /*=====
+ _Widget = dijit._Widget;
+ _Mixin = dojox.form.manager._Mixin;
+ _NodeMixin = dojox.form.manager._NodeMixin;
+ _FormMixin = dojox.form.manager._FormMixin;
+ _ValueMixin = dojox.form.manager._ValueMixin;
+ _EnableMixin = dojox.form.manager._EnableMixin;
+ _DisplayMixin = dojox.form.manager._DisplayMixin;
+ _ClassMixin = dojox.form.manager._ClassMixin;
+ =====*/
+return declare("dojox.form.Manager", [ _Widget, _Mixin, _NodeMixin, _FormMixin, _ValueMixin, _EnableMixin, _DisplayMixin, _ClassMixin ], {
+ // summary:
+ // The widget to orchestrate dynamic forms.
+ // description:
+ // This widget hosts dojox.form.manager mixins.
+ // See _Mixin for more info.
+
+ buildRendering: function(){
+ var node = (this.domNode = this.srcNodeRef);
+ if(!this.containerNode){
+ // all widgets with descendants must set containerNode
+ this.containerNode = node;
+ }
+ this.inherited(arguments);
+ this._attachPoints = [];
+ this._attachEvents = [];
+ _TemplatedMixin.prototype._attachTemplateNodes.call(this, node, function(n, p){ return n.getAttribute(p); });
+ },
+
+ destroyRendering: function(preserveDom){
+ // ctm: calling _TemplatedMixin
+ if(!this.__ctm){
+ // avoid recursive call from _TemplatedMixin
+ this.__ctm = true;
+ _TemplatedMixin.prototype.destroyRendering.apply(this, arguments);
+ delete this.__ctm;
+ this.inherited(arguments);
+ }
+ }
+});
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/MultiComboBox.js b/js/dojo/dojox/form/MultiComboBox.js
new file mode 100644
index 0000000..2661cb9
--- /dev/null
+++ b/js/dojo/dojox/form/MultiComboBox.js
@@ -0,0 +1,66 @@
+//>>built
+define("dojox/form/MultiComboBox", [
+ "dojo/_base/kernel",
+ "dijit/form/ValidationTextBox",
+ "dijit/form/ComboBoxMixin",
+ "dojo/_base/declare"
+], function(kernel, ValidationTextBox, ComboBoxMixin, declare){
+kernel.experimental("dojox.form.MultiComboBox");
+
+ /*=====
+ ValidationTextBox = dijit.form.ValidationTextBox;
+ ComboBoxMixin = dijit.form.ComboBoxMixin;
+ =====*/
+return declare("dojox.form.MultiComboBox", [ValidationTextBox, ComboBoxMixin],{
+ // summary:
+ // A ComboBox that accepts multiple inputs on a single line
+
+ // delimiter: String
+ // The character to use to separate items in the ComboBox input
+ delimiter: ",",
+
+ _previousMatches: false,
+
+ _setValueAttr: function(value){
+ if(this.delimiter && value.length != 0){
+ value = value+this.delimiter+" ";
+ arguments[0] = this._addPreviousMatches(value);
+ }
+ this.inherited(arguments);
+ },
+
+ _addPreviousMatches: function(/* String */text){
+ if(this._previousMatches){
+ if(!text.match(new RegExp("^"+this._previousMatches))){
+ text = this._previousMatches+text;
+ }
+ text = this._cleanupDelimiters(text);
+ }
+ return text; // String
+ },
+
+ _cleanupDelimiters: function(/* String */text){
+ if(this.delimiter){
+ text = text.replace(new RegExp(" +"), " ");
+ text = text.replace(new RegExp("^ *"+this.delimiter+"* *"), "");
+ text = text.replace(new RegExp(this.delimiter+" *"+this.delimiter), this.delimiter);
+ }
+ return text;
+ },
+
+ _autoCompleteText: function(/* String */text){
+ arguments[0] = this._addPreviousMatches(text);
+ this.inherited(arguments);
+ },
+
+ _startSearch: function(/* String */text){
+ text = this._cleanupDelimiters(text);
+ var re = new RegExp("^.*"+this.delimiter+" *");
+
+ if((this._previousMatches = text.match(re))){
+ arguments[0] = text.replace(re, "");
+ }
+ this.inherited(arguments);
+ }
+});
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/PasswordValidator.js b/js/dojo/dojox/form/PasswordValidator.js
new file mode 100644
index 0000000..fdc7ac2
--- /dev/null
+++ b/js/dojo/dojox/form/PasswordValidator.js
@@ -0,0 +1,325 @@
+//>>built
+require({cache:{
+'url:dojox/form/resources/PasswordValidator.html':"<div dojoAttachPoint=\"containerNode\">\n\t<input type=\"hidden\" name=\"${name}\" value=\"\" dojoAttachPoint=\"focusNode\" />\n</div>"}});
+define("dojox/form/PasswordValidator", [
+ "dojo/_base/array",
+ "dojo/_base/lang",
+ "dojo/dom-attr",
+ "dojo/i18n",
+ "dojo/query",
+ "dojo/keys",
+ "dijit/form/_FormValueWidget",
+ "dijit/form/ValidationTextBox",
+ "dojo/text!./resources/PasswordValidator.html",
+ "dojo/i18n!./nls/PasswordValidator",
+ "dojo/_base/declare"
+], function(array, lang, domAttr, i18n, query, keys, FormValueWidget, ValidationTextBox, template, formNlsPasswordValidator, declare){
+
+ /*=====
+ FormValueWidget = dijit.form._FormValueWidget;
+ ValidationTextBox = dijit.form.ValidationTextBox;
+ =====*/
+var _ChildTextBox = declare("dojox.form._ChildTextBox", ValidationTextBox, {
+ // summary:
+ // A class that is shared between all our children - extends
+ // ValidationTextBox and provides some shared functionality
+ //
+ // containerWidget: widget
+ // Our parent (the PasswordValidator)
+ containerWidget: null,
+
+ // type: string
+ // Don't override this - we are all "password" types
+ type: "password",
+
+ reset: function(){
+ // summary:
+ // Force-set to empty string (we don't save passwords EVER)...and
+ // since _OldPWBox overrides _setValueAttr to check for empty string,
+ // call our parent class directly (not this.inherited())
+ ValidationTextBox.prototype._setValueAttr.call(this, "", true);
+ this._hasBeenBlurred = false;
+ },
+
+ postCreate: function(){
+ // summary:
+ // We want to remove the "name" attribute from our focus node if
+ // we don't have one set - this prevents all our extra values
+ // from being posted on submit
+ this.inherited(arguments);
+ if(!this.name){
+ domAttr.remove(this.focusNode, "name");
+ }
+ this.connect(this.focusNode, "onkeypress", "_onChildKeyPress");
+ },
+
+ _onChildKeyPress: function(e){
+ // Check if we pressed <enter> - if so, set our blur value so that
+ // the parent widget will be updated correctly.
+ if(e && e.keyCode == keys.ENTER){
+ this._setBlurValue();
+ }
+ }
+});
+
+
+
+var _OldPWBox = declare("dojox.form._OldPWBox", _ChildTextBox, {
+ // summary:
+ // A class representing our "old password" box.
+ //
+ // _isPWValid: boolean
+ // Whether or not the password is valid
+ _isPWValid: false,
+
+ _setValueAttr: function(/* anything */ newVal, /* boolean? */ priority){
+ // summary:
+ // Updates _isPWValid if this isn't our initial update by calling
+ // our PasswordValidator's pwCheck function
+ if(newVal === ""){
+ newVal = _OldPWBox.superclass.attr.call(this, "value");
+ }
+ if(priority !== null){
+ // Priority is passed in as null, explicitly when this is an
+ // update (not initially set). We want to check our password now.
+ this._isPWValid = this.containerWidget.pwCheck(newVal);
+ }
+ this.inherited(arguments);
+ // Trigger the containerWidget to recheck its value, if needed
+ this.containerWidget._childValueAttr(this.containerWidget._inputWidgets[1].get("value"));
+ },
+
+ isValid: function(/* boolean */ isFocused){
+ // Take into account the isPWValid setting
+ return this.inherited("isValid", arguments) && this._isPWValid;
+ },
+
+ _update: function(/* event */ e){
+ // Only call validate() if we've been blurred or else we get popups
+ // too early.
+ if(this._hasBeenBlurred){ this.validate(true); }
+ this._onMouse(e);
+ },
+
+ _getValueAttr: function(){
+ if(this.containerWidget._started && this.containerWidget.isValid()){
+ return this.inherited(arguments);
+ }
+ return "";
+ },
+
+ _setBlurValue: function(){
+ // TextBox._setBlurValue calls this._setValueAttr(this.get('value'), ...)
+ // Because we are overridding _getValueAttr to return "" when the containerWidget
+ // is not valid, TextBox._setBlurValue will cause OldPWBox's value to be set to ""
+ //
+ // So, we directly call ValidationTextBox._getValueAttr to bypass our _getValueAttr
+ var value = ValidationTextBox.prototype._getValueAttr.call(this);
+ this._setValueAttr(value, (this.isValid ? this.isValid() : true));
+ }
+});
+
+
+var _NewPWBox = declare("dojox.form._NewPWBox", _ChildTextBox, {
+ // summary:
+ // A class representing our new password textbox
+
+ // required: boolean
+ // Whether or not this widget is required (default: true)
+ required: true,
+
+ onChange: function(){
+ // summary:
+ // Validates our verify box - to make sure that a change to me is
+ // reflected there
+ this.containerWidget._inputWidgets[2].validate(false);
+ this.inherited(arguments);
+ }
+});
+
+var _VerifyPWBox = declare("dojox.form._VerifyPWBox", _ChildTextBox, {
+ // summary:
+ // A class representing our verify textbox
+
+ isValid: function(isFocused){
+ // summary:
+ // Validates that we match the "real" password
+ return this.inherited("isValid", arguments) &&
+ (this.get("value") == this.containerWidget._inputWidgets[1].get("value"));
+ }
+});
+
+return declare("dojox.form.PasswordValidator", FormValueWidget, {
+ // summary:
+ // A password validation widget that simplifies the "old/new/verify"
+ // style of requesting passwords. You will probably want to override
+ // this class and implement your own pwCheck function.
+
+ // required: boolean
+ // Whether or not it is required for form submission
+ required: true,
+
+ // inputWidgets: TextBox[]
+ // An array of text boxes that are our components
+ _inputWidgets: null,
+
+ // oldName: string?
+ // The name to send our old password as (when form is posted)
+ oldName: "",
+
+ templateString: template,
+
+ _hasBeenBlurred: false,
+
+ isValid: function(/* boolean */ isFocused){
+ // summary: we are valid if ALL our children are valid
+ return array.every(this._inputWidgets, function(i){
+ if(i && i._setStateClass){ i._setStateClass(); }
+ return (!i || i.isValid());
+ });
+ },
+
+ validate: function(/* boolean */ isFocused){
+ // summary: Validating this widget validates all our children
+ return array.every(array.map(this._inputWidgets, function(i){
+ if(i && i.validate){
+ i._hasBeenBlurred = (i._hasBeenBlurred || this._hasBeenBlurred);
+ return i.validate();
+ }
+ return true;
+ }, this), function(item){ return item; });
+ },
+
+ reset: function(){
+ // summary: Resetting this widget resets all our children
+ this._hasBeenBlurred = false;
+ array.forEach(this._inputWidgets, function(i){
+ if(i && i.reset){ i.reset(); }
+ }, this);
+ },
+
+ _createSubWidgets: function(){
+ // summary:
+ // Turns the inputs inside this widget into "real" validation
+ // widgets - and sets up the needed connections.
+ var widgets = this._inputWidgets,
+ msg = i18n.getLocalization("dojox.form", "PasswordValidator", this.lang);
+ array.forEach(widgets, function(i, idx){
+ if(i){
+ var p = {containerWidget: this}, c;
+ if(idx === 0){
+ p.name = this.oldName;
+ p.invalidMessage = msg.badPasswordMessage;
+ c = _OldPWBox;
+ }else if(idx === 1){
+ p.required = this.required;
+ c = _NewPWBox;
+ }else if(idx === 2){
+ p.invalidMessage = msg.nomatchMessage;
+ c = _VerifyPWBox;
+ }
+ widgets[idx] = new c(p, i);
+ }
+ }, this);
+ },
+
+ pwCheck: function(/* string */ password){
+ // summary:
+ // Overridable function for validation of the old password box.
+ //
+ // This function is called and passed the old password. Return
+ // true if it's OK to continue, and false if it is not.
+ //
+ // IMPORTANT SECURITY NOTE: Do NOT EVER EVER EVER check this in
+ // HTML or JavaScript!!!
+ //
+ // You will probably want to override this function to callback
+ // to a server to verify the password (the callback will need to
+ // be syncronous) - and it's probably a good idea to validate
+ // it again on form submission before actually doing
+ // anything destructive - that's why the "oldName" value
+ // is available.
+ //
+ // And don't just fetch the password from the server
+ // either :) Send the test password (probably hashed, for
+ // security) and return from the server a status instead.
+ //
+ // Again - DON'T BE INSECURE!!! Security is left as an exercise
+ // for the reader :)
+ return false;
+ },
+
+ postCreate: function(){
+ // summary:
+ // Sets up the correct widgets. You *MUST* specify one child
+ // text box (a simple HTML <input> element) with pwType="new"
+ // *and* one child text box with pwType="verify". You *MAY*
+ // specify a third child text box with pwType="old" in order to
+ // prompt the user to enter in their old password before the
+ // widget returns that it is valid.
+
+ this.inherited(arguments);
+
+ // Turn my inputs into the correct stuff....
+ var widgets = this._inputWidgets = [];
+ array.forEach(["old","new","verify"], function(i){
+ widgets.push(query("input[pwType=" + i + "]", this.containerNode)[0]);
+ }, this);
+ if(!widgets[1] || !widgets[2]){
+ throw new Error("Need at least pwType=\"new\" and pwType=\"verify\"");
+ }
+ if(this.oldName && !widgets[0]){
+ throw new Error("Need to specify pwType=\"old\" if using oldName");
+ }
+ this.containerNode = this.domNode;
+ this._createSubWidgets();
+ this.connect(this._inputWidgets[1], "_setValueAttr", "_childValueAttr");
+ this.connect(this._inputWidgets[2], "_setValueAttr", "_childValueAttr");
+ },
+
+ _childValueAttr: function(v){
+ this.set("value", this.isValid() ? v : "");
+ },
+
+ _setDisabledAttr: function(value){
+ this.inherited(arguments);
+ array.forEach(this._inputWidgets, function(i){
+ if(i && i.set){ i.set("disabled", value);}
+ });
+ },
+
+ _setRequiredAttribute: function(value){
+ this.required = value;
+ domAttr.set(this.focusNode, "required", value);
+ this.focusNode.setAttribute("aria-required", value);
+ this._refreshState();
+ array.forEach(this._inputWidgets, function(i){
+ if(i && i.set){ i.set("required", value);}
+ });
+ },
+
+ _setValueAttr: function(v){
+ this.inherited(arguments);
+ domAttr.set(this.focusNode, "value", v);
+ },
+
+ _getValueAttr: function(){
+ // Make sure we don't return undefined.... maybe should do conversion in _setValueAttr() instead?
+ return this.value||"";
+ },
+
+ focus: function(){
+ // summary:
+ // places focus on the first invalid input widget - if all
+ // input widgets are valid, the first widget is focused.
+ var f = false;
+ array.forEach(this._inputWidgets, function(i){
+ if(i && !i.isValid() && !f){
+ i.focus();
+ f = true;
+ }
+ });
+ if(!f){ this._inputWidgets[1].focus(); }
+ }
+});
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/README b/js/dojo/dojox/form/README
new file mode 100644
index 0000000..462ca5b
--- /dev/null
+++ b/js/dojo/dojox/form/README
@@ -0,0 +1,73 @@
+-------------------------------------------------------------------------------
+dojox.form Collection
+-------------------------------------------------------------------------------
+Version 1.0
+Release date: 02/26/2008
+-------------------------------------------------------------------------------
+Project state:
+experimental
+-------------------------------------------------------------------------------
+Credits
+ Nathan Toone (toonetown)
+ Peter Higgins (dante)
+ Wolfram Kriesing (wolfram)
+ Mike Wilcox (mwilcox)
+-------------------------------------------------------------------------------
+Project description
+
+ This is a collection of additional widgets that can be used in forms.
+-------------------------------------------------------------------------------
+Dependencies:
+
+ Depends on dojo core and dijit
+
+ dojo.form.FileUploader depends on dojox.embed, and uses Flash movies created
+ in the deft project using Flex OSS 3. You do not need any of the deft code;
+ compiled movies are included with dojox.form in the resources folder.
+ If you want to modify the actual movies, you can look in the deft project
+ (under the package deft.av).
+-------------------------------------------------------------------------------
+Documentation
+
+-------------------------------------------------------------------------------
+Installation instructions
+
+ Install into /dojox/form
+-------------------------------------------------------------------------------
+Additional Notes (Brief widget list):
+
+ * CheckedMultiSelect - an extension to dijit.form.MultiSelect which
+ uses check boxes instead of ctrl-click
+
+ * DropDownSelect - an extension to dijit.form.DropDownButton which is
+ meant to mirror the html <select> drop down
+
+ * DropDownStack/RadioStack - a widget that can toggle parts of a form as
+ "on" or "off" - to allow for different options based on
+ the value selected.
+
+ * FileInput - experimental dijit-like input type="file"
+
+ * FileInputAuto/Blind - extension to FileInput for
+ added flair/automation
+
+ * FilePickerTextBox - a validating text box that can browser server-side
+ files using a dojox.data.FileStore
+ * FileUploader - Allows for Multi-file uploads and file masking. Uses a SWF
+ file created with Deft. Compatible with Flash Player
+ versions 8-10. Degradeable to a multi-file HTML uploader.
+
+ * ListInput - A text-box widget that allows inputting multiple items (similar
+ to the "to" field on many email clients)
+
+ * MultiComboBox - an experimental ComboBox that allows
+ multiple entries bases on a separator character.
+
+ * PasswordValidator - a widget which simplifies the common "old/new/verify"
+ mechanism of specifying passwords
+
+ * Rating - a star-based rating widget
+
+ * TimeSpinner - a number spinner that revolves through
+ time constrainsts
+
diff --git a/js/dojo/dojox/form/RadioStack.js b/js/dojo/dojox/form/RadioStack.js
new file mode 100644
index 0000000..1ab9819
--- /dev/null
+++ b/js/dojo/dojox/form/RadioStack.js
@@ -0,0 +1,14 @@
+//>>built
+define("dojox/form/RadioStack", [
+ "./CheckedMultiSelect",
+ "./_SelectStackMixin",
+ "dojo/_base/declare"
+], function(CheckedMultiSelect, _SelectStackMixin, declare){
+ /*=====
+ CheckedMultiSelect = dojox.form.CheckedMultiSelect;
+ _SelectStackMixin = dojox.form._SelectStackMixin;
+ =====*/
+ return declare("dojox.form.RadioStack", [ CheckedMultiSelect, _SelectStackMixin ], {
+ // summary: A radio-based select stack.
+ });
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/RangeSlider.js b/js/dojo/dojox/form/RangeSlider.js
new file mode 100644
index 0000000..05f8760
--- /dev/null
+++ b/js/dojo/dojox/form/RangeSlider.js
@@ -0,0 +1,388 @@
+//>>built
+require({cache:{
+'url:dojox/form/resources/HorizontalRangeSlider.html':"<table class=\"dijit dijitReset dijitSlider dijitSliderH dojoxRangeSlider\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\" dojoAttachEvent=\"onkeypress:_onKeyPress,onkeyup:_onKeyUp\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td dojoAttachPoint=\"topDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationT dijitSliderDecorationH\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderDecrementIconH\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"decrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderLeftBumper\" dojoAttachEvent=\"onmousedown:_onClkDecBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\n\t\t\t/><div role=\"presentation\" class=\"dojoxRangeSliderBarContainer\" dojoAttachPoint=\"sliderBarContainer\"\n\t\t\t\t><div dojoAttachPoint=\"sliderHandle\" tabIndex=\"${tabIndex}\" class=\"dijitSliderMoveable dijitSliderMoveableH\" dojoAttachEvent=\"onmousedown:_onHandleClick\" role=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"\n\t\t\t\t\t><div class=\"dijitSliderImageHandle dijitSliderImageHandleH\"></div\n\t\t\t\t></div\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"progressBar,focusNode\" class=\"dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH\" dojoAttachEvent=\"onmousedown:_onBarClick\"></div\n\t\t\t\t><div dojoAttachPoint=\"sliderHandleMax,focusNodeMax\" tabIndex=\"${tabIndex}\" class=\"dijitSliderMoveable dijitSliderMoveableH\" dojoAttachEvent=\"onmousedown:_onHandleClickMax\" role=\"sliderMax\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"\n\t\t\t\t\t><div class=\"dijitSliderImageHandle dijitSliderImageHandleH\"></div\n\t\t\t\t></div\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderRemainingBar dijitSliderRemainingBarH\" dojoAttachEvent=\"onmousedown:_onRemainingBarClick\"></div\n\t\t\t></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderRightBumper\" dojoAttachEvent=\"onmousedown:_onClkIncBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderIncrementIconH\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"incrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\n\t\t></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td dojoAttachPoint=\"containerNode,bottomDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n></table>\n",
+'url:dojox/form/resources/VerticalRangeSlider.html':"<table class=\"dijitReset dijitSlider dijitSliderV dojoxRangeSlider\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\n\t\t\t><div class=\"dijitSliderIncrementIconV\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"decrementButton\" dojoAttachEvent=\"onclick: increment\"><span class=\"dijitSliderButtonInner\">+</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderTopBumper\" dojoAttachEvent=\"onclick:_onClkIncBumper\"></div></center\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td dojoAttachPoint=\"leftDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationL dijitSliderDecorationV\" style=\"text-align:center;height:100%;\"></td\n\t\t><td class=\"dijitReset\" style=\"height:100%;\"\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\n\t\t\t/><center role=\"presentation\" style=\"position:relative;height:100%;\" dojoAttachPoint=\"sliderBarContainer\"\n\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarV dijitSliderRemainingBar dijitSliderRemainingBarV\" dojoAttachEvent=\"onmousedown:_onRemainingBarClick\"\n\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle\" tabIndex=\"${tabIndex}\" class=\"dijitSliderMoveable dijitSliderMoveableV\" dojoAttachEvent=\"onkeypress:_onKeyPress,onmousedown:_onHandleClick\" style=\"vertical-align:top;\" role=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"\n\t\t\t\t\t\t><div class=\"dijitSliderImageHandle dijitSliderImageHandleV\"></div\n\t\t\t\t\t></div\n\t\t\t\t\t><div role=\"presentation\" dojoAttachPoint=\"progressBar,focusNode\" tabIndex=\"${tabIndex}\" class=\"dijitSliderBar dijitSliderBarV dijitSliderProgressBar dijitSliderProgressBarV\" dojoAttachEvent=\"onkeypress:_onKeyPress,onmousedown:_onBarClick\"\n\t\t\t\t\t></div\n\t\t\t\t\t><div dojoAttachPoint=\"sliderHandleMax,focusNodeMax\" tabIndex=\"${tabIndex}\" class=\"dijitSliderMoveable dijitSliderMoveableV\" dojoAttachEvent=\"onkeypress:_onKeyPress,onmousedown:_onHandleClickMax\" style=\"vertical-align:top;\" role=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"\n\t\t\t\t\t\t><div class=\"dijitSliderImageHandle dijitSliderImageHandleV\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t></center\n\t\t></td\n\t\t><td dojoAttachPoint=\"containerNode,rightDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationR dijitSliderDecorationV\" style=\"text-align:center;height:100%;\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderBottomBumper\" dojoAttachEvent=\"onclick:_onClkDecBumper\"></div></center\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV\"\n\t\t\t><div class=\"dijitSliderDecrementIconV\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"incrementButton\" dojoAttachEvent=\"onclick: decrement\"><span class=\"dijitSliderButtonInner\">-</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n></table>\n"}});
+define("dojox/form/RangeSlider", [
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojo/_base/fx",
+ "dojo/_base/event",
+ "dojo/_base/sniff",
+ "dojo/dom-style",
+ "dojo/dom-geometry",
+ "dojo/keys",
+ "dijit",
+ "dojo/dnd/Mover",
+ "dojo/dnd/Moveable",
+ "dojo/text!./resources/HorizontalRangeSlider.html",
+ "dojo/text!./resources/VerticalRangeSlider.html",
+ "dijit/form/HorizontalSlider",
+ "dijit/form/VerticalSlider",
+ "dijit/form/_FormValueWidget",
+ "dijit/focus",
+ "dojo/fx",
+ "dojox/fx" // unused?
+], function(declare, lang, array, fx, event, has, domStyle, domGeometry, keys, dijit, Mover, Moveable, hTemplate, vTemplate, HorizontalSlider, VerticalSlider, FormValueWidget, FocusManager, fxUtils){
+
+ // make these functions once:
+ var sortReversed = function(a, b){ return b - a; },
+ sortForward = function(a, b){ return a - b; }
+ ;
+
+ lang.getObject("form", true, dojox);
+
+ /*=====
+ hTemplate = dijit.form.HorizontalSlider;
+ vTemplate = dijit.form.VerticalSlider;
+ =====*/
+ var RangeSliderMixin = declare("dojox.form._RangeSliderMixin", null, {
+
+ value: [0,100],
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this.value = array.map(this.value, function(i){ return parseInt(i, 10); });
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ // we sort the values!
+ // TODO: re-think, how to set the value
+ this.value.sort(this._isReversed() ? sortReversed : sortForward);
+
+ // define a custom constructor for a SliderMoverMax that points back to me
+ var _self = this;
+ var mover = declare(SliderMoverMax, {
+ constructor: function(){
+ this.widget = _self;
+ }
+ });
+
+ this._movableMax = new Moveable(this.sliderHandleMax,{ mover: mover });
+ this.focusNodeMax.setAttribute("aria-valuemin", this.minimum);
+ this.focusNodeMax.setAttribute("aria-valuemax", this.maximum);
+
+ // a dnd for the bar!
+ var barMover = declare(SliderBarMover, {
+ constructor: function(){
+ this.widget = _self;
+ }
+ });
+ this._movableBar = new Moveable(this.progressBar,{ mover: barMover });
+ },
+
+ destroy: function(){
+ this.inherited(arguments);
+ this._movableMax.destroy();
+ this._movableBar.destroy();
+ },
+
+ _onKeyPress: function(/*Event*/ e){
+ if(this.disabled || this.readOnly || e.altKey || e.ctrlKey){ return; }
+
+ var useMaxValue = e.target === this.sliderHandleMax;
+ var barFocus = e.target === this.progressBar;
+ var k = lang.delegate(keys, this.isLeftToRight() ? {PREV_ARROW: keys.LEFT_ARROW, NEXT_ARROW: keys.RIGHT_ARROW}
+ : {PREV_ARROW: keys.RIGHT_ARROW, NEXT_ARROW: keys.LEFT_ARROW});
+ var delta = 0;
+ var down = false;
+
+ switch(e.keyCode){
+ case k.HOME : this._setValueAttr(this.minimum, true, useMaxValue);event.stop(e);return;
+ case k.END : this._setValueAttr(this.maximum, true, useMaxValue);event.stop(e);return;
+ case k.PREV_ARROW :
+ case k.DOWN_ARROW : down = true;
+ case k.NEXT_ARROW :
+ case k.UP_ARROW : delta = 1; break;
+ case k.PAGE_DOWN : down = true;
+ case k.PAGE_UP : delta = this.pageIncrement; break;
+ default : this.inherited(arguments);return;
+ }
+
+ if(down){delta = -delta;}
+
+ if(delta){
+ if(barFocus){
+ this._bumpValue([
+ { change: delta, useMaxValue: false },
+ { change: delta, useMaxValue: true }
+ ]);
+ }else{
+ this._bumpValue(delta, useMaxValue);
+ }
+ event.stop(e);
+ }
+ },
+
+ _onHandleClickMax: 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)
+ FocusManager.focus(this.sliderHandleMax);
+ }
+ event.stop(e);
+ },
+
+ _onClkIncBumper: function(){
+ this._setValueAttr(this._descending === false ? this.minimum : this.maximum, true, true);
+ },
+
+ _bumpValue: function(signedChange, useMaxValue){
+
+ // we pass an array to _setValueAttr when signedChange is an array
+ var value = lang.isArray(signedChange) ? [
+ this._getBumpValue(signedChange[0].change, signedChange[0].useMaxValue),
+ this._getBumpValue(signedChange[1].change, signedChange[1].useMaxValue)
+ ]
+ : this._getBumpValue(signedChange, useMaxValue)
+
+ this._setValueAttr(value, true, useMaxValue);
+ },
+
+ _getBumpValue: function(signedChange, useMaxValue){
+
+ var idx = useMaxValue ? 1 : 0;
+ if(this._isReversed()){
+ idx = 1 - idx;
+ }
+
+ var s = domStyle.getComputedStyle(this.sliderBarContainer),
+ c = domGeometry.getContentBox(this.sliderBarContainer, s),
+ count = this.discreteValues,
+ myValue = this.value[idx]
+ ;
+
+ if(count <= 1 || count == Infinity){ count = c[this._pixelCount]; }
+ count--;
+
+ var value = (myValue - this.minimum) * count / (this.maximum - this.minimum) + signedChange;
+ if(value < 0){ value = 0; }
+ if(value > count){ value = count; }
+
+ return value * (this.maximum - this.minimum) / count + this.minimum;
+ },
+
+ _onBarClick: 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)
+ FocusManager.focus(this.progressBar);
+ }
+ event.stop(e);
+ },
+
+ _onRemainingBarClick: 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)
+ FocusManager.focus(this.progressBar);
+ }
+
+ // now we set the min/max-value of the slider!
+ var abspos = domGeometry.position(this.sliderBarContainer, true),
+ bar = domGeometry.position(this.progressBar, true),
+ relMousePos = e[this._mousePixelCoord] - abspos[this._startingPixelCoord],
+ leftPos = bar[this._startingPixelCoord],
+ rightPos = leftPos + bar[this._pixelCount],
+ isMaxVal = this._isReversed() ? relMousePos <= leftPos : relMousePos >= rightPos,
+ p = this._isReversed() ? abspos[this._pixelCount] - relMousePos : relMousePos
+ ;
+
+ this._setPixelValue(p, abspos[this._pixelCount], true, isMaxVal);
+ event.stop(e);
+ },
+
+ _setPixelValue: function(/*Number*/ pixelValue, /*Number*/ maxPixels, /*Boolean*/ priorityChange, /*Boolean*/ isMaxVal){
+ if(this.disabled || this.readOnly){ return; }
+ var myValue = this._getValueByPixelValue(pixelValue, maxPixels);
+ this._setValueAttr(myValue, priorityChange, isMaxVal);
+ },
+
+ _getValueByPixelValue: function(/*Number*/ pixelValue, /*Number*/ maxPixels){
+ pixelValue = pixelValue < 0 ? 0 : maxPixels < pixelValue ? maxPixels : pixelValue;
+ var count = this.discreteValues;
+ if(count <= 1 || count == Infinity){ count = maxPixels; }
+ count--;
+ var pixelsPerValue = maxPixels / count;
+ var wholeIncrements = Math.round(pixelValue / pixelsPerValue);
+ return (this.maximum-this.minimum)*wholeIncrements/count + this.minimum;
+ },
+
+ _setValueAttr: function(/*Array or Number*/ value, /*Boolean, optional*/ priorityChange, /*Boolean, optional*/ isMaxVal){
+ // we pass an array, when we move the slider with the bar
+ var actValue = this.value;
+ if(!lang.isArray(value)){
+ if(isMaxVal){
+ if(this._isReversed()){
+ actValue[0] = value;
+ }else{
+ actValue[1] = value;
+ }
+ }else{
+ if(this._isReversed()){
+ actValue[1] = value;
+ }else{
+ actValue[0] = value;
+ }
+ }
+ }else{
+ actValue = value;
+ }
+ // we have to reset this values. don't know the reason for that
+ this._lastValueReported = "";
+ this.valueNode.value = this.value = value = actValue;
+ this.focusNode.setAttribute("aria-valuenow", actValue[0]);
+ this.focusNodeMax.setAttribute("aria-valuenow", actValue[1]);
+
+ this.value.sort(this._isReversed() ? sortReversed : sortForward);
+
+ // not calling the _setValueAttr-function of Slider, but the super-super-class (needed for the onchange-event!)
+ FormValueWidget.prototype._setValueAttr.apply(this, arguments);
+ this._printSliderBar(priorityChange, isMaxVal);
+ },
+
+ _printSliderBar: function(priorityChange, isMaxVal){
+ var percentMin = (this.value[0] - this.minimum) / (this.maximum - this.minimum);
+ var percentMax = (this.value[1] - this.minimum) / (this.maximum - this.minimum);
+ var percentMinSave = percentMin;
+ if(percentMin > percentMax){
+ percentMin = percentMax;
+ percentMax = percentMinSave;
+ }
+ var sliderHandleVal = this._isReversed() ? ((1-percentMin)*100) : (percentMin * 100);
+ var sliderHandleMaxVal = this._isReversed() ? ((1-percentMax)*100) : (percentMax * 100);
+ var progressBarVal = this._isReversed() ? ((1-percentMax)*100) : (percentMin * 100);
+ if(priorityChange && this.slideDuration > 0 && this.progressBar.style[this._progressPixelSize]){
+ // animate the slider
+ var percent = isMaxVal ? percentMax : percentMin;
+ var _this = this;
+ var props = {};
+ var start = parseFloat(this.progressBar.style[this._handleOffsetCoord]);
+ var duration = this.slideDuration / 10; // * (percent-start/100);
+ if(duration === 0){ return; }
+ if(duration < 0){ duration = 0 - duration; }
+ var propsHandle = {};
+ var propsHandleMax = {};
+ var propsBar = {};
+ // hui, a lot of animations :-)
+ propsHandle[this._handleOffsetCoord] = { start: this.sliderHandle.style[this._handleOffsetCoord], end: sliderHandleVal, units:"%"};
+ propsHandleMax[this._handleOffsetCoord] = { start: this.sliderHandleMax.style[this._handleOffsetCoord], end: sliderHandleMaxVal, units:"%"};
+ propsBar[this._handleOffsetCoord] = { start: this.progressBar.style[this._handleOffsetCoord], end: progressBarVal, units:"%"};
+ propsBar[this._progressPixelSize] = { start: this.progressBar.style[this._progressPixelSize], end: (percentMax - percentMin) * 100, units:"%"};
+ var animHandle = fx.animateProperty({node: this.sliderHandle,duration: duration, properties: propsHandle});
+ var animHandleMax = fx.animateProperty({node: this.sliderHandleMax,duration: duration, properties: propsHandleMax});
+ var animBar = fx.animateProperty({node: this.progressBar,duration: duration, properties: propsBar});
+ var animCombine = fxUtils.combine([animHandle, animHandleMax, animBar]);
+ animCombine.play();
+ }else{
+ this.sliderHandle.style[this._handleOffsetCoord] = sliderHandleVal + "%";
+ this.sliderHandleMax.style[this._handleOffsetCoord] = sliderHandleMaxVal + "%";
+ this.progressBar.style[this._handleOffsetCoord] = progressBarVal + "%";
+ this.progressBar.style[this._progressPixelSize] = ((percentMax - percentMin) * 100) + "%";
+ }
+ }
+ });
+
+ var SliderMoverMax = declare("dijit.form._SliderMoverMax", dijit.form._SliderMover, {
+
+ 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 coordEvent = e.touches ? e.touches[0] : e; // if multitouch take first touch for coords
+ var pixelValue = coordEvent[widget._mousePixelCoord] - abspos[widget._startingPixelCoord];
+ widget._setPixelValue_(widget._isReversed_ ? (abspos[widget._pixelCount]-pixelValue) : pixelValue, abspos[widget._pixelCount], false, true);
+ },
+
+ destroy: function(e){
+ Mover.prototype.destroy.apply(this, arguments);
+ var widget = this.widget;
+ widget._abspos = null;
+ widget._setValueAttr(widget.value, true);
+ }
+ });
+
+ var SliderBarMover = declare("dijit.form._SliderBarMover", Mover, {
+
+ onMouseMove: function(e){
+ var widget = this.widget;
+ if(widget.disabled || widget.readOnly){ return; }
+ var abspos = widget._abspos;
+ var bar = widget._bar;
+ var mouseOffset = widget._mouseOffset;
+ if(!abspos){
+ abspos = widget._abspos = domGeometry.position(widget.sliderBarContainer, true);
+ widget._setPixelValue_ = lang.hitch(widget, "_setPixelValue");
+ widget._getValueByPixelValue_ = lang.hitch(widget, "_getValueByPixelValue");
+ widget._isReversed_ = widget._isReversed();
+ }
+
+ if(!bar){
+ bar = widget._bar = domGeometry.position(widget.progressBar, true);
+ }
+ var coordEvent = e.touches ? e.touches[0] : e; // if multitouch take first touch for coords
+
+ if(!mouseOffset){
+ mouseOffset = widget._mouseOffset = coordEvent[widget._mousePixelCoord] - abspos[widget._startingPixelCoord] - bar[widget._startingPixelCoord];
+ }
+
+
+ var pixelValueMin = coordEvent[widget._mousePixelCoord] - abspos[widget._startingPixelCoord] - mouseOffset,
+ pixelValueMax = pixelValueMin + bar[widget._pixelCount];
+ // we don't narrow the slider when it reaches the bumper!
+ // maybe there is a simpler way
+ pixelValues = [pixelValueMin, pixelValueMax]
+ ;
+
+ pixelValues.sort(sortForward);
+
+ if(pixelValues[0] <= 0){
+ pixelValues[0] = 0;
+ pixelValues[1] = bar[widget._pixelCount];
+ }
+ if(pixelValues[1] >= abspos[widget._pixelCount]){
+ pixelValues[1] = abspos[widget._pixelCount];
+ pixelValues[0] = abspos[widget._pixelCount] - bar[widget._pixelCount];
+ }
+ // getting the real values by pixel
+ var myValues = [
+ widget._getValueByPixelValue(widget._isReversed_ ? (abspos[widget._pixelCount] - pixelValues[0]) : pixelValues[0], abspos[widget._pixelCount]),
+ widget._getValueByPixelValue(widget._isReversed_ ? (abspos[widget._pixelCount] - pixelValues[1]) : pixelValues[1], abspos[widget._pixelCount])
+ ];
+ // and setting the value of the widget
+ widget._setValueAttr(myValues, false, false);
+ },
+
+ destroy: function(){
+ Mover.prototype.destroy.apply(this, arguments);
+ var widget = this.widget;
+ widget._abspos = null;
+ widget._bar = null;
+ widget._mouseOffset = null;
+ widget._setValueAttr(widget.value, true);
+ }
+ });
+
+ declare("dojox.form.HorizontalRangeSlider", [HorizontalSlider, RangeSliderMixin], {
+ // summary:
+ // A form widget that allows one to select a range with two horizontally draggable images
+ templateString: hTemplate
+ });
+
+ declare("dojox.form.VerticalRangeSlider", [VerticalSlider, RangeSliderMixin], {
+ // summary:
+ // A form widget that allows one to select a range with two vertically draggable images
+ templateString: vTemplate
+ });
+
+ return RangeSliderMixin;
+
+});
diff --git a/js/dojo/dojox/form/Rating.js b/js/dojo/dojox/form/Rating.js
new file mode 100644
index 0000000..6dbfa65
--- /dev/null
+++ b/js/dojo/dojox/form/Rating.js
@@ -0,0 +1,105 @@
+//>>built
+define("dojox/form/Rating", [
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/dom-attr",
+ "dojo/dom-class",
+ "dojo/string",
+ "dojo/query",
+ "dijit/form/_FormWidget"
+], function(declare, lang, domAttr, domClass, string, query, FormWidget){
+
+ /*=====
+ FormWidget = dijit.form._FormWidget;
+ =====*/
+return declare("dojox.form.Rating", FormWidget,{
+ // summary:
+ // A widget for rating using stars.
+ //
+ // required: Boolean
+ // TODO: Can be true or false, default is false.
+ // required: false,
+
+ templateString: null,
+
+ // numStars: Integer/Float
+ // The number of stars to show, default is 3.
+ numStars: 3,
+ // value: Integer/Float
+ // The current value of the Rating
+ value: 0,
+
+ constructor:function(/*Object*/params){
+ // Build the templateString. The number of stars is given by this.numStars,
+ // which is normally an attribute to the widget node.
+ lang.mixin(this, params);
+
+ // TODO actually "dijitInline" should be applied to the surrounding div, but FF2
+ // screws up when we query() for the star nodes, it orders them randomly, because of the use
+ // of display:--moz-inline-box ... very strange bug
+ // Since using ul and li in combintaion with dijitInline this problem doesnt exist anymore.
+
+ // The focusNode is normally used to store the value, i dont know if that is right here, but seems standard for _FormWidgets
+ var tpl = '<div dojoAttachPoint="domNode" class="dojoxRating dijitInline">' +
+ '<input type="hidden" value="0" dojoAttachPoint="focusNode" /><ul>${stars}</ul>' +
+ '</div>';
+ // The value-attribute is used to "read" the value for processing in the widget class
+ var starTpl = '<li class="dojoxRatingStar dijitInline" dojoAttachEvent="onclick:onStarClick,onmouseover:_onMouse,onmouseout:_onMouse" value="${value}"></li>';
+ var rendered = "";
+ for(var i = 0; i < this.numStars; i++){
+ rendered += string.substitute(starTpl, {value:i+1});
+ }
+ this.templateString = string.substitute(tpl, {stars:rendered});
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this._renderStars(this.value);
+ },
+
+ _onMouse: function(evt){
+ if(this.hovering){
+ var hoverValue = +domAttr.get(evt.target, "value");
+ this.onMouseOver(evt, hoverValue);
+ this._renderStars(hoverValue, true);
+ }else{
+ this._renderStars(this.value);
+ }
+ },
+
+ _renderStars: function(value, hover){
+ // summary: Render the stars depending on the value.
+ query(".dojoxRatingStar", this.domNode).forEach(function(star, i){
+ if(i + 1 > value){
+ domClass.remove(star, "dojoxRatingStarHover");
+ domClass.remove(star, "dojoxRatingStarChecked");
+ }else{
+ domClass.remove(star, "dojoxRatingStar" + (hover ? "Checked" : "Hover"));
+ domClass.add(star, "dojoxRatingStar" + (hover ? "Hover" : "Checked"));
+ }
+ });
+ },
+
+ onStarClick:function(/* Event */evt){
+ // summary: Connect on this method to get noticed when a star was clicked.
+ // example: connect(widget, "onStarClick", function(event){ ... })
+ var newVal = +domAttr.get(evt.target, "value");
+ this.setAttribute("value", newVal == this.value ? 0 : newVal);
+ this._renderStars(this.value);
+ this.onChange(this.value); // Do I have to call this by hand?
+ },
+
+ onMouseOver: function(/*evt, value*/){
+ // summary: Connect here, the value is passed to this function as the second parameter!
+ },
+
+ setAttribute: function(/*String*/key, /**/value){
+ // summary: When calling setAttribute("value", 4), set the value and render the stars accordingly.
+ this.set(key, value);
+ if(key=="value"){
+ this._renderStars(this.value);
+ this.onChange(this.value); // Do I really have to call this by hand? :-(
+ }
+ }
+});
+});
diff --git a/js/dojo/dojox/form/TimeSpinner.js b/js/dojo/dojox/form/TimeSpinner.js
new file mode 100644
index 0000000..57bb33f
--- /dev/null
+++ b/js/dojo/dojox/form/TimeSpinner.js
@@ -0,0 +1,62 @@
+//>>built
+define("dojox/form/TimeSpinner", [
+ "dojo/_base/lang",
+ "dojo/_base/event",
+ "dijit/form/_Spinner",
+ "dojo/keys",
+ "dojo/date",
+ "dojo/date/locale",
+ "dojo/date/stamp",
+ "dojo/_base/declare"
+], function(lang, event, Spinner, keys, dateUtil, dateLocale, dateStamp, declare){
+ /*=====
+ Spinner = dijit.form._Spinner;
+ =====*/
+return declare( "dojox.form.TimeSpinner", Spinner,
+{
+ // summary: Time Spinner
+ // description: This widget is the same as a normal NumberSpinner, but for the time component of a date object instead
+
+ required: false,
+
+ adjust: function(/* Object */ val, /*Number*/ delta){
+ return dateUtil.add(val, "minute", delta)
+ },
+
+ //FIXME should we allow for constraints in this widget?
+ isValid: function(){return true;},
+
+ smallDelta: 5,
+
+ largeDelta: 30,
+
+ timeoutChangeRate: 0.50,
+
+ parse: function(time, locale){
+ return dateLocale.parse(time, {selector:"time", formatLength:"short"});
+ },
+
+ format: function(time, locale){
+ if(lang.isString(time)){ return time; }
+ return dateLocale.format(time, {selector:"time", formatLength:"short"});
+ },
+
+ serialize: dateStamp.toISOString,
+
+ value: "12:00 AM",
+
+ _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(value){
+ this._setValueAttr(value,true);
+ }
+ // eat home or end key whether we change the value or not
+ event.stop(e);
+ }
+ }
+
+
+});
+});
diff --git a/js/dojo/dojox/form/TriStateCheckBox.js b/js/dojo/dojox/form/TriStateCheckBox.js
new file mode 100644
index 0000000..04ccff2
--- /dev/null
+++ b/js/dojo/dojox/form/TriStateCheckBox.js
@@ -0,0 +1,246 @@
+//>>built
+require({cache:{
+'url:dojox/form/resources/TriStateCheckBox.html':"<div class=\"dijit dijitReset dijitInline\" role=\"presentation\"\n\t><div class=\"dojoxTriStateCheckBoxInner\" dojoAttachPoint=\"stateLabelNode\"></div\n\t><input ${!nameAttrSetting} type=\"${type}\" dojoAttachPoint=\"focusNode\"\n\tclass=\"dijitReset dojoxTriStateCheckBoxInput\" dojoAttachEvent=\"onclick:_onClick\"\n/></div>"}});
+define("dojox/form/TriStateCheckBox", [
+ "dojo/_base/kernel",
+ "dojo/_base/declare",
+ "dojo/_base/array",
+ "dojo/_base/event",
+ "dojo/query",
+ "dojo/dom-attr",
+ "dojo/text!./resources/TriStateCheckBox.html",
+ "dijit/form/ToggleButton"
+], function(kernel, declare, array, event, query, domAttr, template, ToggleButton){
+// module:
+// dojox/form/TriStateCheckBox
+// summary:
+// Checkbox with three states
+//
+
+ /*=====
+ ToggleButton = dijit.form.ToggleButton;
+ =====*/
+return declare("dojox.form.TriStateCheckBox", ToggleButton,
+ {
+ // summary:
+ // Checkbox with three states
+
+ templateString: template,
+
+ baseClass: "dojoxTriStateCheckBox",
+
+ // type: [private] String
+ // type attribute on <input> node.
+ // Overrides `dijit.form.Button.type`. Users should not change this value.
+ type: "checkbox",
+
+ /*=====
+ // states: Array
+ // States of TriStateCheckBox.
+ // The value of This.checked should be one of these three states.
+ states: [false, true, "mixed"],
+ =====*/
+
+ /*=====
+ // _stateLabels: Object
+ // These characters are used to replace the image to show
+ // current state of TriStateCheckBox in high contrast mode.
+ _stateLabels: {
+ "False": '&#63219',
+ "True": '&#8730;',
+ "Mixed": '&#8801'
+ },
+ =====*/
+
+ /*=====
+ // stateValues: Object
+ // The values of the TriStateCheckBox in corresponding states.
+ stateValues: {
+ "False": "off",
+ "True": "on",
+ "Mixed": "mixed"
+ },
+ =====*/
+
+ // _currentState: Integer
+ // The current state of the TriStateCheckBox
+ _currentState: 0,
+
+ // _stateType: String
+ // The current state type of the TriStateCheckBox
+ // Could be "False", "True" or "Mixed"
+ _stateType: "False",
+
+ // 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,
+
+ constructor: function(){
+ // summary:
+ // Runs on widget initialization to setup arrays etc.
+ // tags:
+ // private
+ this.states = [false, true, "mixed"];
+ this._stateLabels = {
+ "False": '&#63219',
+ "True": '&#8730;',
+ "Mixed": '&#8801'
+ };
+ this.stateValues = {
+ "False": "off",
+ "True": "on",
+ "Mixed": "mixed"
+ };
+ },
+
+ // Override behavior from Button, since we don't have an iconNode
+ _setIconClassAttr: null,
+
+ _setCheckedAttr: function(/*String|Boolean*/ checked, /*Boolean?*/ priorityChange){
+ // summary:
+ // Handler for checked = attribute to constructor, and also calls to
+ // set('checked', val).
+ // checked:
+ // true, false or 'mixed'
+ // description:
+ // Controls the state of the TriStateCheckBox. Set this.checked,
+ // this._currentState, value attribute of the <input type=checkbox>
+ // according to the value of 'checked'.
+ this._set("checked", checked);
+ this._currentState = array.indexOf(this.states, checked);
+ this._stateType = this._getStateType(checked);
+ domAttr.set(this.focusNode || this.domNode, "checked", checked);
+ domAttr.set(this.focusNode, "value", this.stateValues[this._stateType]);
+ (this.focusNode || this.domNode).setAttribute("aria-checked", checked);
+ this._handleOnChange(checked, priorityChange);
+ },
+
+ setChecked: function(/*String|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);
+ },
+
+ _setReadOnlyAttr: function(/*Boolean*/ value){
+ this._set("readOnly", value);
+ domAttr.set(this.focusNode, "readOnly", value);
+ this.focusNode.setAttribute("aria-readonly", value);
+ },
+
+ _setValueAttr: function(/*String|Boolean*/ newValue, /*Boolean*/ priorityChange){
+ // summary:
+ // Handler for value = attribute to constructor, and also calls to
+ // set('value', val).
+ // description:
+ // During initialization, just saves as attribute to the <input type=checkbox>.
+ //
+ // After initialization,
+ // when passed a boolean or the string 'mixed', controls the state of the
+ // TriStateCheckBox.
+ // If passed a string except 'mixed', changes the value attribute of the
+ // TriStateCheckBox. Sets the state of the TriStateCheckBox to checked.
+ if(typeof newValue == "string" && (array.indexOf(this.states, newValue) < 0)){
+ if(newValue == ""){
+ newValue = "on";
+ }
+ this.stateValues["True"] = newValue;
+ newValue = true;
+ }
+ if(this._created){
+ this._currentState = array.indexOf(this.states, newValue);
+ this.set('checked', newValue, priorityChange);
+ domAttr.set(this.focusNode, "value", this.stateValues[this._stateType]);
+ }
+ },
+
+ _setValuesAttr: function(/*Array*/ newValues){
+ // summary:
+ // Handler for values = attribute to constructor, and also calls to
+ // set('values', val).
+ // newValues:
+ // If the length of newValues is 1, it will replace the value of
+ // the TriStateCheckBox in true state. Otherwise, the values of
+ // the TriStateCheckBox in true state and 'mixed' state will be
+ // replaced by the first two values in newValues.
+ // description:
+ // Change the value of the TriStateCheckBox in 'mixed' and true states.
+ this.stateValues["True"] = newValues[0] ? newValues[0] : this.stateValues["True"];
+ this.stateValues["Mixed"] = newValues[1] ? newValues[1] : this.stateValues["False"];
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // Hook so get('value') works.
+ // description:
+ // Returns value according to current state of the TriStateCheckBox.
+ return this.stateValues[this._stateType];
+ },
+
+ startup: function(){
+ this.set("checked", this.params.checked || this.states[this._currentState]);
+ domAttr.set(this.stateLabelNode, 'innerHTML', this._stateLabels[this._stateType]);
+ this.inherited(arguments);
+ },
+
+ _fillContent: function(/*DomNode*/ source){
+ // Override Button::_fillContent() since it doesn't make sense for CheckBox,
+ // since CheckBox doesn't even have a container
+ },
+
+ reset: function(){
+ this._hasBeenBlurred = false;
+ this.stateValues = {
+ "False" : "off",
+ "True" : "on",
+ "Mixed" : "mixed"
+ };
+ this.set('checked', this.params.checked || this.states[0]);
+ },
+
+ _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);
+ },
+
+ _onClick: function(/*Event*/ e){
+ // summary:
+ // Internal function to handle click actions - need to check
+ // readOnly and disabled
+ if(this.readOnly || this.disabled){
+ event.stop(e);
+ return false;
+ }
+ if(this._currentState >= this.states.length - 1){
+ this._currentState = 0;
+ }else{
+ this._currentState++;
+ }
+ this.set("checked", this.states[this._currentState]);
+ domAttr.set(this.stateLabelNode, 'innerHTML', this._stateLabels[this._stateType]);
+ return this.onClick(e); // user click actions
+ },
+
+ _getStateType: function(/*String|Boolean*/ state){
+ // summary:
+ // Internal function to return the type of a certain state
+ // false: False
+ // true: True
+ // "mixed": Mixed
+ return state ? (state == "mixed" ? "Mixed" : "True") : "False";
+ }
+ }
+);
+
+});
diff --git a/js/dojo/dojox/form/Uploader.js b/js/dojo/dojox/form/Uploader.js
new file mode 100644
index 0000000..3580986
--- /dev/null
+++ b/js/dojo/dojox/form/Uploader.js
@@ -0,0 +1,392 @@
+//>>built
+require({cache:{
+'url:dojox/form/resources/Uploader.html':"<span class=\"dijit dijitReset dijitInline\"\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\n\t\tdojoAttachEvent=\"ondijitclick:_onClick\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode,focusNode\"\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\"></span\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t\tdojoAttachPoint=\"containerNode\"\n\t\t\t></span\n\t\t></span\n\t></span\n\t><!--no need to have this for Uploader \n\t<input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\" tabIndex=\"-1\"\n\t\tdojoAttachPoint=\"valueNode\"\n/--></span>\n"}});
+define("dojox/form/Uploader", [
+ "dojo/_base/kernel",
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojo/_base/connect",
+ "dojo/_base/window",
+ "dojo/dom-style",
+ "dojo/dom-geometry",
+ "dojo/dom-attr",
+ "dojo/dom-construct",
+ "dojo/dom-form",
+ "dijit",
+ "dijit/form/Button",
+ "dojox/form/uploader/Base",
+ "dojo/i18n!./nls/Uploader",
+ "dojo/text!./resources/Uploader.html"
+],function(kernel, declare, lang, array, connect, win, domStyle, domGeometry, domAttr, domConstruct, domForm, dijit, Button, uploader, res, template){
+
+ kernel.experimental("dojox.form.Uploader");
+ //
+ // TODO:
+ // i18n
+ // label via innerHTML
+ // Doc and or test what can be extended.
+ // Doc custom file events
+ // Use new FileReader() for thumbnails
+ // flashFieldName should default to Flash
+ // get('value'); and set warning
+ // Make it so URL can change (current set to Flash on build)
+ //
+
+ /*=====
+ uploader = dojox.form.uploader.Base;
+ WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
+ =====*/
+declare("dojox.form.Uploader", [uploader, Button], {
+ //
+ // Version: 1.6
+ //
+ // summary:
+ // A widget that creates a stylable file-input button, with optional multi-file selection,
+ // using only HTML elements. Non-HTML5 browsers have fallback options of Flash or an iframe.
+ //
+ // description:
+ // A bare-bones, stylable file-input button, with optional multi-file selection. The list
+ // of files is not displayed, that is for you to handle by connecting to the onChange
+ // event, or use the dojox.form.uploader.FileList.
+ //
+ // Uploader without plugins does not have any ability to upload - it is for use in forms
+ // where you handle the upload either by a standard POST or with Ajax using an iFrame. This
+ // class is for convenience of multiple files only. No progress events are available.
+ //
+ // If the browser supports a file-input with the "multiple" attribute, that will be used.
+ // If the browser does not support "multiple" (ergo, IE) multiple inputs are used,
+ // one for each selection.
+ //
+ //
+ // uploadOnSelect: Boolean
+ // If true, uploads imediately after a file has been selected. If false,
+ // waits for upload() to be called.
+ uploadOnSelect:false,
+ // tabIndex: Number|String
+ // The tab order in the DOM.
+ tabIndex:0,
+ // multiple: Boolean
+ // If true and flash mode, multiple files may be selected from the dialog.
+ multiple:false,
+ //
+ // label: String
+ // The text used in the button that when clicked, opens a system Browse Dialog.
+ label:res.label,
+ //
+ // url: String
+ // The url targeted for upload. An absolute URL is preferred. Relative URLs are
+ // changed to absolute.
+ url:"",
+ //
+ // name: String
+ // The name attribute needs to end with square brackets: [] as this is the standard way
+ // of handling an attribute "array". This requires a slightly different technique on the
+ // server.
+ name:"uploadedfile",
+ //
+ // flashFieldName: String
+ // If set, this will be the name of the field of the flash uploaded files that the server
+ // is expecting. If not set, "Flash" is appended to the "name" property.
+ flashFieldName:"",
+ //
+ // uploadType: String [readonly]
+ // The type of uploader being used. As an alternative to determining the upload type on the
+ // server based on the fieldName, this property could be sent to the server to help
+ // determine what type of parsing should be used.
+ uploadType:"form",
+ //
+ // showInput: String [const]
+ // Position to show an input which shows selected filename(s). Possible
+ // values are "before", "after", which specifies where the input should
+ // be placed with reference to the containerNode which contains the
+ // label). By default, this is empty string (no such input will be
+ // shown). Specify showInput="before" to mimic the look&feel of a
+ // native file input element.
+ showInput: "",
+
+ _nameIndex:0,
+
+ templateString: template,
+
+ baseClass: 'dijitUploader '+Button.prototype.baseClass,
+
+ postMixInProperties: function(){
+ this._inputs = [];
+ this._cons = [];
+ this.inherited(arguments);
+ },
+ buildRendering: function(){
+ console.warn("buildRendering", this.id)
+ this.inherited(arguments);
+ domStyle.set(this.domNode, {
+ overflow:"hidden",
+ position:"relative"
+ });
+ this._buildDisplay();
+ //change the button node not occupy tabIndex: the real file input
+ //will have tabIndex set
+ domAttr.set(this.titleNode, 'tabIndex', -1);
+ },
+ _buildDisplay: function(){
+ if(this.showInput){
+ this.displayInput = dojo.create('input', {
+ 'class':'dijitUploadDisplayInput',
+ 'tabIndex':-1, 'autocomplete':'off'},
+ this.containerNode, this.showInput);
+ //schedule the attachpoint to be cleaned up on destroy
+ this._attachPoints.push('displayInput');
+ this.connect(this,'onChange', function(files){
+ var i=0,l=files.length, f, r=[];
+ while((f=files[i++])){
+ if(f && f.name){
+ r.push(f.name);
+ }
+ }
+ this.displayInput.value = r.join(', ');
+ });
+ this.connect(this,'reset', function(){
+ this.displayInput.value = '';
+ });
+ }
+ },
+
+ startup: function(){
+ if(this._buildInitialized){
+ return;
+ }
+ this._buildInitialized = true;
+ this._getButtonStyle(this.domNode);
+ this._setButtonStyle();
+ this.inherited(arguments);
+ },
+
+ /*************************
+ * Public Events *
+ *************************/
+
+ onChange: function(/* Array */fileArray){
+ // summary:
+ // stub to connect
+ // Fires when files are selected
+ // Event is an array of last files selected
+ },
+
+ onBegin: function(/* Array */dataArray){
+ // summary:
+ // Fires when upload begins
+ },
+
+ onProgress: function(/* Object */customEvent){
+ // summary:
+ // Stub to connect
+ // Fires on upload progress. Event is a normalized object of common properties
+ // from HTML5 uploaders and the Flash uploader. Will not fire for IFrame.
+ // customEvent:
+ // bytesLoaded: Number
+ // Amount of bytes uploaded so far of entire payload (all files)
+ // bytesTotal: Number
+ // Amount of bytes of entire payload (all files)
+ // type: String
+ // Type of event (progress or load)
+ // timeStamp: Number
+ // Timestamp of when event occurred
+ },
+
+ onComplete: function(/* Object */customEvent){
+ // summary:
+ // stub to connect
+ // Fires when all files have uploaded
+ // Event is an array of all files
+ this.reset();
+ },
+
+ onCancel: function(){
+ // summary:
+ // Stub to connect
+ // Fires when dialog box has been closed
+ // without a file selection
+ },
+
+ onAbort: function(){
+ // summary:
+ // Stub to connect
+ // Fires when upload in progress was canceled
+ },
+
+ onError: function(/* Object or String */evtObject){
+ // summary:
+ // Fires on errors
+ //
+ //FIXME: Unsure of a standard form of error events
+ },
+
+ /*************************
+ * Public Methods *
+ *************************/
+
+ upload: function(/*Object ? */formData){
+ // summary:
+ // When called, begins file upload. Only supported with plugins.
+ },
+
+ submit: function(/* form Node ? */form){
+ // summary:
+ // If Uploader is in a form, and other data should be sent along with the files, use
+ // this instead of form submit.
+ form = !!form ? form.tagName ? form : this.getForm() : this.getForm();
+ var data = domForm.toObject(form);
+ this.upload(data);
+ },
+
+ reset: function(){
+ // summary
+ // Resets entire input, clearing all files.
+ // NOTE:
+ // Removing individual files is not yet supported, because the HTML5 uploaders can't
+ // be edited.
+ // TODO:
+ // Add this ability by effectively, not uploading them
+ //
+ delete this._files;
+ this._disconnectButton();
+ array.forEach(this._inputs, domConstruct.destroy, dojo);
+ this._inputs = [];
+ this._nameIndex = 0;
+ this._createInput();
+ },
+
+ getFileList: function(){
+ // summary:
+ // Returns a list of selected files.
+ //
+ var fileArray = [];
+ if(this.supports("multiple")){
+ array.forEach(this._files, function(f, i){
+ fileArray.push({
+ index:i,
+ name:f.name,
+ size:f.size,
+ type:f.type
+ });
+ }, this);
+ }else{
+ array.forEach(this._inputs, function(n, i){
+ if(n.value){
+ fileArray.push({
+ index:i,
+ name:n.value.substring(n.value.lastIndexOf("\\")+1),
+ size:0,
+ type:n.value.substring(n.value.lastIndexOf(".")+1)
+ });
+ }
+ }, this);
+
+ }
+ return fileArray; // Array
+ },
+
+ /*********************************************
+ * Private Property. Get off my lawn. *
+ *********************************************/
+
+ _getValueAttr: function(){
+ // summary:
+ // Internal. To get disabled use: uploader.get("disabled");
+ return this.getFileList();
+ },
+
+ _setValueAttr: function(disabled){
+ console.error("Uploader value is read only");
+ },
+
+ _setDisabledAttr: function(disabled){
+ // summary:
+ // Internal. To set disabled use: uploader.set("disabled", true);
+ if(this._disabled == disabled){ return; }
+ this.inherited(arguments);
+ domStyle.set(this.inputNode, "display", disabled ? "none" : "");
+ },
+
+ _getButtonStyle: function(node){
+ this.btnSize = {w:domStyle.get(node,'width'), h:domStyle.get(node,'height')};
+ },
+
+ _setButtonStyle: function(){
+ this.inputNodeFontSize = Math.max(2, Math.max(Math.ceil(this.btnSize.w / 60), Math.ceil(this.btnSize.h / 15)));
+ this._createInput();
+ },
+
+ _createInput: function(){
+ if(this._inputs.length){
+ domStyle.set(this.inputNode, {
+ top:"500px"
+ });
+ this._disconnectButton();
+ this._nameIndex++;
+ }
+
+ var name;
+ if(this.supports("multiple")){
+ // FF3.5+, WebKit
+ name = this.name+"s[]";
+ }else{
+ // <=IE8
+ name = this.name + (this.multiple ? this._nameIndex : "");
+ }
+ // reset focusNode to the inputNode, so when the button is clicked,
+ // the focus is properly moved to the input element
+ this.focusNode = this.inputNode = domConstruct.create("input", {type:"file", name:name}, this.domNode, "first");
+ if(this.supports("multiple") && this.multiple){
+ domAttr.set(this.inputNode, "multiple", true);
+ }
+ this._inputs.push(this.inputNode);
+
+ domStyle.set(this.inputNode, {
+ position:"absolute",
+ fontSize:this.inputNodeFontSize+"em",
+ top:"-3px",
+ right:"-3px",
+ opacity:0
+ });
+ this._connectButton();
+ },
+
+ _connectButton: function(){
+ this._cons.push(connect.connect(this.inputNode, "change", this, function(evt){
+ this._files = this.inputNode.files;
+ this.onChange(this.getFileList(evt));
+ if(!this.supports("multiple") && this.multiple) this._createInput();
+ }));
+
+ if(this.tabIndex > -1){
+ this.inputNode.tabIndex = this.tabIndex;
+
+ this._cons.push(connect.connect(this.inputNode, "focus", this, function(){
+ this.titleNode.style.outline= "1px dashed #ccc";
+ }));
+ this._cons.push(connect.connect(this.inputNode, "blur", this, function(){
+ this.titleNode.style.outline = "";
+ }));
+ }
+ },
+
+ _disconnectButton: function(){
+ array.forEach(this._cons, connect.disconnect);
+ this._cons.splice(0,this._cons.length);
+ }
+});
+
+ dojox.form.UploaderOrg = dojox.form.Uploader;
+ var extensions = [dojox.form.UploaderOrg];
+ dojox.form.addUploaderPlugin = function(plug){
+ // summary:
+ // Handle Uploader plugins. When the dojox.form.addUploaderPlugin() function is called,
+ // the dojox.form.Uploader is recreated using the new plugin (mixin).
+ //
+ extensions.push(plug);
+ declare("dojox.form.Uploader", extensions, {});
+ }
+
+ return dojox.form.Uploader;
+});
diff --git a/js/dojo/dojox/form/_FormSelectWidget.js b/js/dojo/dojox/form/_FormSelectWidget.js
new file mode 100644
index 0000000..da4336a
--- /dev/null
+++ b/js/dojo/dojox/form/_FormSelectWidget.js
@@ -0,0 +1,11 @@
+//>>built
+define("dojox/form/_FormSelectWidget", [
+ "dojo/_base/kernel",
+ "dojo/_base/lang",
+ "dijit/form/_FormSelectWidget"
+], function(kernel, lang, _FormSelectWidget){
+ kernel.deprecated("dojox.form._FormSelectWidget", "Use dijit.form._FormSelectWidget instead", "2.0");
+
+ lang.setObject("dojox.form._FormSelectWidget", _FormSelectWidget);
+ return _FormSelectWidget;
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/_HasDropDown.js b/js/dojo/dojox/form/_HasDropDown.js
new file mode 100644
index 0000000..b057f67
--- /dev/null
+++ b/js/dojo/dojox/form/_HasDropDown.js
@@ -0,0 +1,11 @@
+//>>built
+define("dojox/form/_HasDropDown", [
+ "dojo/_base/kernel",
+ "dojo/_base/lang",
+ "dijit/_HasDropDown"
+], function(kernel, _HasDropDown){
+ kernel.deprecated("dojox.form._HasDropDown", "Use dijit._HasDropDown instead", "2.0");
+
+ lang.setObject("dojox.form._HasDropDown", _HasDropDown);
+ return _HasDropDown;
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/_SelectStackMixin.js b/js/dojo/dojox/form/_SelectStackMixin.js
new file mode 100644
index 0000000..4fc6e1c
--- /dev/null
+++ b/js/dojo/dojox/form/_SelectStackMixin.js
@@ -0,0 +1,222 @@
+//>>built
+define("dojox/form/_SelectStackMixin", [
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dijit/_base/manager",
+ "dojo/_base/connect",
+ "dojo/_base/declare"
+], function(lang, array, manager, connect, declare){
+
+return declare("dojox.form._SelectStackMixin", null, {
+ // summary:
+ // Mix this class in to a dijit.form._FormSelectWidget in order to
+ // provide support for "selectable" multiforms. The widget is pointed
+ // to a dijit.layout.StackContainer and will handle displaying and
+ // submitting the values of only the appropriate pane.
+ //
+ // The options for this widget will be automatically set - based on
+ // the panes that are in the stack container. The "title" attribute of
+ // the pane will be used for the display of the option. The "id" attribute
+ // of the pane will be used as the value of the option. In order to
+ // avoid running into unique ID constraint issues, a stackPrefix mechanism
+ // is provided.
+
+ // stackId: string
+ // The id of the stack that this widget is supposed to control
+ stackId: "",
+
+ // stackPrefix: string
+ // A prefix to remove from our stack pane ids when setting our options.
+ // This exists so that we won't run into unique ID constraints. For
+ // example, if stackPrefix is set to "foo_", and there are three panes
+ // in our stack with ids of "foo_a", "foo_b", and "foo_c", then the values
+ // of the options created for the stack controller widget will be "a",
+ // "b", and "c". This allows you to have multiple select stack widgets
+ // with the same values - without having to have the panes require the
+ // same ids.
+ stackPrefix: "",
+
+ _paneIdFromOption: function(/*String*/ oVal){
+ // summary: Gets the pane ID given an option value
+ return (this.stackPrefix || "") + oVal; // String
+ },
+
+ _optionValFromPane: function(/*String*/ id){
+ // summary: Gets the option value given a pane ID
+ var sp = this.stackPrefix;
+ if(sp && id.indexOf(sp) === 0){
+ return id.substring(sp.length); // String
+ }
+ return id; // String
+ },
+
+ _togglePane: function(/*dijit._Widget*/ pane, /*Boolean*/ shown){
+ // summary: called when a pane is either shown or hidden (so that
+ // we can toggle the widgets on it)
+
+ if(pane._shown != undefined && pane._shown == shown){ return; }
+ var widgets = array.filter(pane.getDescendants(), "return item.name;");
+ if(!shown){
+ // We are hiding - save the current state and then disable them
+ savedStates = {};
+ array.forEach(widgets, function(w){
+ savedStates[w.id] = w.disabled;
+ w.set("disabled", true);
+ });
+ pane._savedStates = savedStates;
+ }else{
+ // We are showing - restore our saved states
+ var savedStates = pane._savedStates||{};
+ array.forEach(widgets, function(w){
+ var state = savedStates[w.id];
+ if(state == undefined){
+ state = false;
+ }
+ w.set("disabled", state);
+ });
+ delete pane._savedStates;
+ }
+ pane._shown = shown;
+ },
+
+ _connectTitle: function(/*dijit._Widget*/ pane, /*String*/ value){
+ var fx = lang.hitch(this, function(title){
+ this.updateOption({value: value, label: title});
+ });
+ if(pane._setTitleAttr){
+ this.connect(pane, "_setTitleAttr", fx);
+ }else{
+ this.connect(pane, "attr", function(attr, val){
+ if(attr == "title" && arguments.length > 1){
+ fx(val);
+ }
+ });
+ }
+ },
+
+ onAddChild: function(/*dijit._Widget*/ pane, /*Integer?*/ insertIndex){
+ // summary: Called when the stack container adds a new pane
+ if(!this._panes[pane.id]){
+ this._panes[pane.id] = pane;
+ var v = this._optionValFromPane(pane.id);
+ this.addOption({value: v, label: pane.title});
+ this._connectTitle(pane, v);
+ }
+ if(!pane.onShow || !pane.onHide || pane._shown == undefined){
+ pane.onShow = lang.hitch(this, "_togglePane", pane, true);
+ pane.onHide = lang.hitch(this, "_togglePane", pane, false);
+ pane.onHide();
+ }
+ },
+
+ _setValueAttr: function(v){
+ if("_savedValue" in this){
+ return;
+ }
+ this.inherited(arguments);
+ },
+ attr: function(/*String|Object*/name, /*Object?*/value){
+ if(name == "value" && arguments.length == 2 && "_savedValue" in this){
+ this._savedValue = value;
+ }
+ return this.inherited(arguments);
+ },
+
+ onRemoveChild: function(/*dijit._Widget*/ pane){
+ // summary: Called when the stack container removes a pane
+ if(this._panes[pane.id]){
+ delete this._panes[pane.id];
+ this.removeOption(this._optionValFromPane(pane.id));
+ }
+ },
+
+ onSelectChild: function(/*dijit._Widget*/ pane){
+ // summary: Called when the stack container selects a new pane
+ this._setValueAttr(this._optionValFromPane(pane.id));
+ },
+
+ onStartup: function(/*Object*/ info){
+ // summary: Called when the stack container is started up
+ var selPane = info.selected;
+ this.addOption(array.filter(array.map(info.children, function(c){
+ var v = this._optionValFromPane(c.id);
+ this._connectTitle(c, v);
+ var toAdd = null;
+ if(!this._panes[c.id]){
+ this._panes[c.id] = c;
+ toAdd = {value: v, label: c.title};
+ }
+ if(!c.onShow || !c.onHide || c._shown == undefined){
+ c.onShow = lang.hitch(this, "_togglePane", c, true);
+ c.onHide = lang.hitch(this, "_togglePane", c, false);
+ c.onHide();
+ }
+ if("_savedValue" in this && v === this._savedValue){
+ selPane = c;
+ }
+ return toAdd;
+ }, this), function(i){ return i;}));
+ var _this = this;
+ var fx = function(){
+ // This stuff needs to be run after we show our child, if
+ // the stack is going to show a different child than is
+ // selected - see trac #9396
+ delete _this._savedValue;
+ _this.onSelectChild(selPane);
+ if(!selPane._shown){
+ _this._togglePane(selPane, true);
+ }
+ };
+ if(selPane !== info.selected){
+ var stack = manager.byId(this.stackId);
+ var c = this.connect(stack, "_showChild", function(sel){
+ this.disconnect(c);
+ fx();
+ });
+ }else{
+ fx();
+ }
+ },
+
+ postMixInProperties: function(){
+ this._savedValue = this.value;
+ this.inherited(arguments);
+ this.connect(this, "onChange", "_handleSelfOnChange");
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this._panes = {};
+ this._subscriptions = [
+ connect.subscribe(this.stackId + "-startup", this, "onStartup"),
+ connect.subscribe(this.stackId + "-addChild", this, "onAddChild"),
+ connect.subscribe(this.stackId + "-removeChild", this, "onRemoveChild"),
+ connect.subscribe(this.stackId + "-selectChild", this, "onSelectChild")
+ ];
+ var stack = manager.byId(this.stackId);
+ if(stack && stack._started){
+ // If we have a stack, and it's already started, call our onStartup now
+ this.onStartup({children: stack.getChildren(), selected: stack.selectedChildWidget});
+ }
+ },
+
+ destroy: function(){
+ array.forEach(this._subscriptions, connect.unsubscribe);
+ delete this._panes; // Fixes memory leak in IE
+ this.inherited("destroy", arguments);
+ },
+
+ _handleSelfOnChange: function(/*String*/ val){
+ // summary: Called when form select widget's value has changed
+ var pane = this._panes[this._paneIdFromOption(val)];
+ if(pane){
+ var s = manager.byId(this.stackId);
+ if(pane == s.selectedChildWidget){
+ s._transition(pane);
+ }else{
+ s.selectChild(pane);
+ }
+ }
+ }
+});
+}); \ No newline at end of file
diff --git a/js/dojo/dojox/form/manager/_ClassMixin.js b/js/dojo/dojox/form/manager/_ClassMixin.js
new file mode 100644
index 0000000..81d2b30
--- /dev/null
+++ b/js/dojo/dojox/form/manager/_ClassMixin.js
@@ -0,0 +1,73 @@
+//>>built
+define("dojox/form/manager/_ClassMixin", [
+ "dojo/_base/lang",
+ "dojo/_base/kernel",
+ "dojo/dom-class",
+ "./_Mixin",
+ "dojo/_base/declare"
+], function(lang, dojo, domClass, _Mixin, declare){
+ var fm = lang.getObject("dojox.form.manager", true),
+ aa = fm.actionAdapter,
+ ia = fm.inspectorAdapter;
+
+ return declare("dojox.form.manager._ClassMixin", null, {
+ // summary:
+ // Form manager's mixin for testing/assigning/removing
+ // classes of controlled elements.
+ // description:
+ // This mixin provides unified way to check/add/remove a class
+ // of controlled elements.
+ // It should be used together with dojox.form.manager.Mixin.
+
+ gatherClassState: function(className, names){
+ // summary:
+ // Gather the presence of a certain class in all controlled elements.
+ // className: String:
+ // The class name to test for.
+ // names: Object?:
+ // If it is an array, it is a list of names to be processed.
+ // If it is an object, dictionary keys are names to be processed.
+ // If it is omitted, all known form elements are to be processed.
+
+ var result = this.inspect(ia(function(name, node){
+ return domClass.contains(node, className);
+ }), names);
+
+ return result; // Object
+ },
+
+ addClass: function(className, names){
+ // summary:
+ // Add a class to nodes according to the supplied set of names
+ // className: String:
+ // Class name to add.
+ // names: Object?:
+ // If it is an array, it is a list of names to be processed.
+ // If it is an object, dictionary keys are names to be processed.
+ // If it is omitted, all known form elements are to be processed.
+
+ this.inspect(aa(function(name, node){
+ domClass.add(node, className);
+ }), names);
+
+ return this; // self
+ },
+
+ removeClass: function(className, names){
+ // summary:
+ // Remove a class from nodes according to the supplied set of names
+ // className: String:
+ // Class name to remove.
+ // names: Object?:
+ // If it is an array, it is a list of names to be processed.
+ // If it is an object, dictionary keys are names to be processed.
+ // If it is omitted, all known form elements are to be processed.
+
+ this.inspect(aa(function(name, node){
+ domClass.remove(node, className);
+ }), names);
+
+ return this; // self
+ }
+ });
+});
diff --git a/js/dojo/dojox/form/manager/_DisplayMixin.js b/js/dojo/dojox/form/manager/_DisplayMixin.js
new file mode 100644
index 0000000..ae54494
--- /dev/null
+++ b/js/dojo/dojox/form/manager/_DisplayMixin.js
@@ -0,0 +1,66 @@
+//>>built
+define("dojox/form/manager/_DisplayMixin", [
+ "dojo/_base/kernel",
+ "dojo/dom-style",
+ "dojo/_base/declare"
+], function(dojo, domStyle, declare){
+return declare("dojox.form.manager._DisplayMixin", null, {
+ // summary:
+ // Form manager's mixin for controlling show/hide state of
+ // controlled elements (defined by dojoAttachPoint attributes).
+ // description:
+ // This mixin provides unified show/hide functionality for
+ // controlled elements (indicated by dojoAttachPoint attribute).
+ // Essentially it provides a way to change "style.display"
+ // parameter of controlled nodes.
+ // It should be used together with dojox.form.manager.Mixin.
+
+ gatherDisplayState: function(names){
+ // summary:
+ // Gather display state of all attached elements and return as a dictionary.
+ // names: Object?:
+ // If it is an array, it is a list of names to be processed.
+ // If it is an object, dictionary keys are names to be processed.
+ // If it is omitted, all known attach point nodes are to be processed.
+
+ var result = this.inspectAttachedPoints(function(name, node){
+ return domStyle.get(node, "display") != "none";
+ }, names);
+
+ return result; // Object
+ },
+
+ show: function(state, defaultState){
+ // summary:
+ // Show attached nodes according to the supplied state object.
+ // state: Object?:
+ // Optional. If a name-value dictionary, the value is true
+ // to show and false to hide. If an array, all names in the
+ // array will be set to defaultState. If omitted, all form
+ // elements will be set to defaultState.
+ // defaultState: Boolean?:
+ // The default state (true, if omitted).
+
+ if(arguments.length < 2){
+ defaultState = true;
+ }
+
+ this.inspectAttachedPoints(function(name, node, value){
+ domStyle.set(node, "display", value ? "" : "none");
+ }, state, defaultState);
+
+ return this; // self
+ },
+
+ hide: function(state){
+ // summary:
+ // Hide attached nodes according to the supplied state object.
+ // state: Object?:
+ // Optional. If a name-value dictionary, the value is true
+ // to show and false to hide. If an array, all names in the
+ // array will be hidden. If omitted, all form elements
+ // will be hidden.
+ return this.show(state, false); // self
+ }
+});
+});
diff --git a/js/dojo/dojox/form/manager/_EnableMixin.js b/js/dojo/dojox/form/manager/_EnableMixin.js
new file mode 100644
index 0000000..2b15df4
--- /dev/null
+++ b/js/dojo/dojox/form/manager/_EnableMixin.js
@@ -0,0 +1,84 @@
+//>>built
+define("dojox/form/manager/_EnableMixin", [
+ "dojo/_base/lang",
+ "dojo/_base/kernel",
+ "dojo/dom-attr",
+ "./_Mixin",
+ "dojo/_base/declare"
+], function(lang, dojo, domAttr, _Mixin, declare){
+ var fm = lang.getObject("dojox.form.manager", true),
+ aa = fm.actionAdapter,
+ ia = fm.inspectorAdapter;
+
+ return declare("dojox.form.manager._EnableMixin", null, {
+ // summary:
+ // Form manager's mixin for controlling enable/disable state of
+ // form elements.
+ // description:
+ // This mixin provides unified enable/disable functionality for
+ // form widgets and form elements. It should be used together
+ // with dojox.form.manager.Mixin.
+
+ gatherEnableState: function(names){
+ // summary:
+ // Gather enable state of all form elements and return as a dictionary.
+ // names: Object?:
+ // If it is an array, it is a list of names to be processed.
+ // If it is an object, dictionary keys are names to be processed.
+ // If it is omitted, all known form elements are to be processed.
+
+ var result = this.inspectFormWidgets(ia(function(name, widget){
+ return !widget.get("disabled");
+ }), names);
+
+ if(this.inspectFormNodes){
+ lang.mixin(result, this.inspectFormNodes(ia(function(name, node){
+ return !domAttr.get(node, "disabled");
+ }), names));
+ }
+
+ return result; // Object
+ },
+
+ enable: function(state, defaultState){
+ // summary:
+ // Enable form controls according to the supplied state object.
+ // state: Object?:
+ // Optional. If a name-value dictionary, the value is true
+ // to enable and false to disable. If an array, all names in the
+ // array will be set to defaultState. If omitted, all form
+ // elements will be set to defaultState.
+ // defaultState: Boolean:
+ // The default state (true, if omitted).
+
+ if(arguments.length < 2 || defaultState === undefined){
+ defaultState = true;
+ }
+
+ this.inspectFormWidgets(aa(function(name, widget, value){
+ widget.set("disabled", !value);
+ }), state, defaultState);
+
+ if(this.inspectFormNodes){
+ this.inspectFormNodes(aa(function(name, node, value){
+ domAttr.set(node, "disabled", !value);
+ }), state, defaultState);
+ }
+
+ return this; // self
+ },
+
+ disable: function(state){
+ // summary:
+ // Disable form controls according to the supplied state object
+ // returning the previous state.
+ // state: Object?:
+ // Optional. If a name-value dictionary, the value is true
+ // to enable and false to disable. If an array, all names in the
+ // array will be disabled. If omitted, disables all.
+ var oldState = this.gatherEnableState();
+ this.enable(state, false);
+ return oldState; // Object
+ }
+ });
+});
diff --git a/js/dojo/dojox/form/manager/_FormMixin.js b/js/dojo/dojox/form/manager/_FormMixin.js
new file mode 100644
index 0000000..69a9fa2
--- /dev/null
+++ b/js/dojo/dojox/form/manager/_FormMixin.js
@@ -0,0 +1,156 @@
+//>>built
+define("dojox/form/manager/_FormMixin", [
+ "dojo/_base/lang",
+ "dojo/_base/kernel",
+ "dojo/_base/event",
+ "dojo/window",
+ "./_Mixin",
+ "dojo/_base/declare"
+], function(lang, dojo, event, windowUtils, _Mixin, declare){
+ var fm = lang.getObject("dojox.form.manager", true),
+ aa = fm.actionAdapter;
+
+ return declare("dojox.form.manager._FormMixin", null, {
+ // summary:
+ // Form manager's mixin for form-specific functionality.
+ // description:
+ // This mixin adds automated "onreset", and "onsubmit" event processing
+ // if we are based on a form node, defines onReset(), onSubmit(),
+ // reset(), submit(), and isValid() methods like dijit.form.Form.
+ // It should be used together with dojox.form.manager.Mixin.
+
+ // HTML <FORM> attributes (if we are based on the form element)
+ name: "",
+ action: "",
+ method: "",
+ encType: "",
+ "accept-charset": "",
+ accept: "",
+ target: "",
+
+ startup: function(){
+ this.isForm = this.domNode.tagName.toLowerCase() == "form";
+ if(this.isForm){
+ this.connect(this.domNode, "onreset", "_onReset");
+ this.connect(this.domNode, "onsubmit", "_onSubmit");
+ }
+ this.inherited(arguments);
+ },
+
+ // form-specific functionality
+
+ _onReset: function(evt){
+ // NOTE: this function is taken from dijit.formForm, it works only
+ // for form-based managers.
+
+ // 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: evt.currentTarget, target: evt.target
+ };
+ // if return value is not exactly false, and haven't called preventDefault(), then reset
+ if(!(this.onReset(faux) === false) && faux.returnValue){
+ this.reset();
+ }
+ event.stop(evt);
+ return false;
+ },
+
+ onReset: function(){
+ // 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
+ return true; // Boolean
+ },
+
+ reset: function(){
+ // summary:
+ // Resets form widget values.
+ this.inspectFormWidgets(aa(function(_, widget){
+ if(widget.reset){
+ widget.reset();
+ }
+ }));
+ if(this.isForm){
+ this.domNode.reset();
+ }
+ return this;
+ },
+
+ _onSubmit: function(evt){
+ // NOTE: this function is taken from dijit.formForm, it works only
+ // for form-based managers.
+
+ if(this.onSubmit(evt) === false){ // only exactly false stops submit
+ event.stop(evt);
+ }
+ },
+
+ onSubmit: function(){
+ // summary:
+ // Callback when user submits the form. 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
+
+ return this.isValid(); // Boolean
+ },
+
+ submit: function(){
+ // summary:
+ // programmatically submit form if and only if the `onSubmit` returns true
+ if(this.isForm){
+ if(!(this.onSubmit() === false)){
+ this.domNode.submit();
+ }
+ }
+ },
+
+ isValid: function(){
+ // summary:
+ // Make sure that every widget that has a validator function returns true.
+ for(var name in this.formWidgets){
+ var stop = false;
+ aa(function(_, widget){
+ if(!widget.get("disabled") && widget.isValid && !widget.isValid()){
+ stop = true;
+ }
+ }).call(this, null, this.formWidgets[name].widget);
+ if(stop){
+ return false;
+ }
+ }
+ return true;
+ },
+ validate: function(){
+ var isValid = true,
+ formWidgets = this.formWidgets,
+ didFocus = false, name;
+
+ for(name in formWidgets){
+ aa(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
+ windowUtils.scrollIntoView(widget.containerNode || widget.domNode);
+ widget.focus();
+ didFocus = true;
+ }
+ isValid = isValid && valid;
+ }).call(this, null, formWidgets[name].widget);
+ }
+
+ return isValid;
+ }
+ });
+});
diff --git a/js/dojo/dojox/form/manager/_Mixin.js b/js/dojo/dojox/form/manager/_Mixin.js
new file mode 100644
index 0000000..b64a725
--- /dev/null
+++ b/js/dojo/dojox/form/manager/_Mixin.js
@@ -0,0 +1,498 @@
+//>>built
+define("dojox/form/manager/_Mixin", [
+ "dojo/_base/window",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojo/_base/connect",
+ "dojo/dom-attr",
+ "dojo/dom-class",
+ "dijit/_base/manager",
+ "dijit/_Widget",
+ "dijit/form/_FormWidget",
+ "dijit/form/Button",
+ "dijit/form/CheckBox",
+ "dojo/_base/declare"
+], function(win, lang, array, connect, domAttr, domClass, manager, Widget, FormWidget, Button, CheckBox, declare){
+ // XXX: This class is loading a bunch of extra widgets just to perform isInstanceOf operations,
+ // which is wasteful
+
+ var fm = lang.getObject("dojox.form.manager", true),
+
+ aa = fm.actionAdapter = function(action){
+ // summary:
+ // Adapter that automates application of actions to arrays.
+ // action: Function:
+ // Function that takes three parameters: a name, an object
+ // (usually node or widget), and a value. This action will
+ // be applied to all elements of array.
+ return function(name, elems, value){
+ if(lang.isArray(elems)){
+ array.forEach(elems, function(elem){
+ action.call(this, name, elem, value);
+ }, this);
+ }else{
+ action.apply(this, arguments);
+ }
+ };
+ },
+
+ ia = fm.inspectorAdapter = function(inspector){
+ // summary:
+ // Adapter that applies an inspector only to the first item of the array.
+ // inspector: Function:
+ // Function that takes three parameters: a name, an object
+ // (usually node or widget), and a value.
+ return function(name, elem, value){
+ return inspector.call(this, name, lang.isArray(elem) ? elem[0] : elem, value);
+ };
+ },
+
+ skipNames = {domNode: 1, containerNode: 1, srcNodeRef: 1, bgIframe: 1},
+
+ keys = fm._keys = function(o){
+ // similar to dojox.lang.functional.keys
+ var list = [], key;
+ for(key in o){
+ if(o.hasOwnProperty(key)){
+ list.push(key);
+ }
+ }
+ return list;
+ },
+
+ registerWidget = function(widget){
+ var name = widget.get("name");
+ if(name && widget instanceof FormWidget){
+ if(name in this.formWidgets){
+ var a = this.formWidgets[name].widget;
+ if(lang.isArray(a)){
+ a.push(widget);
+ }else{
+ this.formWidgets[name].widget = [a, widget];
+ }
+ }else{
+ this.formWidgets[name] = {widget: widget, connections: []};
+ }
+ }else{
+ name = null;
+ }
+ return name;
+ },
+
+ getObserversFromWidget = function(name){
+ var observers = {};
+ aa(function(_, w){
+ var o = w.get("observer");
+ if(o && typeof o == "string"){
+ array.forEach(o.split(","), function(o){
+ o = lang.trim(o);
+ if(o && lang.isFunction(this[o])){
+ observers[o] = 1;
+ }
+ }, this);
+ }
+ }).call(this, null, this.formWidgets[name].widget);
+ return keys(observers);
+ },
+
+ connectWidget = function(name, observers){
+ var t = this.formWidgets[name], w = t.widget, c = t.connections;
+ if(c.length){
+ array.forEach(c, connect.disconnect);
+ c = t.connections = [];
+ }
+ if(lang.isArray(w)){
+ // radio buttons
+ array.forEach(w, function(w){
+ array.forEach(observers, function(o){
+ c.push(connect.connect(w, "onChange", this, function(evt){
+ // TODO: for some reason for radio button widgets
+ // w.checked != w.focusNode.checked when value changes.
+ // We test the underlying value to be 100% sure.
+ if(this.watching && domAttr.get(w.focusNode, "checked")){
+ this[o](w.get("value"), name, w, evt);
+ }
+ }));
+ }, this);
+ }, this);
+ }else{
+ // the rest
+ // the next line is a crude workaround for Button that fires onClick instead of onChange
+ var eventName = w.isInstanceOf(Button) ?
+ "onClick" : "onChange";
+ array.forEach(observers, function(o){
+ c.push(connect.connect(w, eventName, this, function(evt){
+ if(this.watching){
+ this[o](w.get("value"), name, w, evt);
+ }
+ }));
+ }, this);
+ }
+ };
+
+ var _Mixin = declare("dojox.form.manager._Mixin", null, {
+ // summary:
+ // Mixin to orchestrate dynamic forms.
+ // description:
+ // This mixin provideas a foundation for an enhanced form
+ // functionality: unified access to individual form elements,
+ // unified "onchange" event processing, general event
+ // processing, I/O orchestration, and common form-related
+ // functionality. See additional mixins in dojox.form.manager
+ // namespace.
+
+ watching: true,
+
+ startup: function(){
+ // summary:
+ // Called after all the widgets have been instantiated and their
+ // dom nodes have been inserted somewhere under win.doc.body.
+
+ if(this._started){ return; }
+
+ this.formWidgets = {};
+ this.formNodes = {};
+ this.registerWidgetDescendants(this);
+
+ this.inherited(arguments);
+ },
+
+ destroy: function(){
+ // summary:
+ // Called when the widget is being destroyed
+
+ for(var name in this.formWidgets){
+ array.forEach(this.formWidgets[name].connections, connect.disconnect);
+ }
+ this.formWidgets = {};
+
+ this.inherited(arguments);
+ },
+
+ // register/unregister widgets and nodes
+
+ registerWidget: function(widget){
+ // summary:
+ // Register a widget with the form manager
+ // widget: String|Node|dijit.form._FormWidget:
+ // A widget, or its widgetId, or its DOM node
+ // returns: Object:
+ // Returns self
+ if(typeof widget == "string"){
+ widget = manager.byId(widget);
+ }else if(widget.tagName && widget.cloneNode){
+ widget = manager.byNode(widget);
+ }
+ var name = registerWidget.call(this, widget);
+ if(name){
+ connectWidget.call(this, name, getObserversFromWidget.call(this, name));
+ }
+ return this;
+ },
+
+ unregisterWidget: function(name){
+ // summary:
+ // Removes the widget by name from internal tables unregistering
+ // connected observers
+ // name: String:
+ // Name of the to unregister
+ // returns: Object:
+ // Returns self
+ if(name in this.formWidgets){
+ array.forEach(this.formWidgets[name].connections, this.disconnect, this);
+ delete this.formWidgets[name];
+ }
+ return this;
+ },
+
+ registerWidgetDescendants: function(widget){
+ // summary:
+ // Register widget's descendants with the form manager
+ // widget: String|Node|dijit._Widget:
+ // A widget, or its widgetId, or its DOM node
+ // returns: Object:
+ // Returns self
+
+ // convert to widget, if required
+ if(typeof widget == "string"){
+ widget = manager.byId(widget);
+ }else if(widget.tagName && widget.cloneNode){
+ widget = manager.byNode(widget);
+ }
+
+ // build the map of widgets
+ var widgets = array.map(widget.getDescendants(), registerWidget, this);
+
+ // process observers for widgets
+ array.forEach(widgets, function(name){
+ if(name){
+ connectWidget.call(this, name, getObserversFromWidget.call(this, name));
+ }
+ }, this);
+
+ // do the same with nodes, if available
+ return this.registerNodeDescendants ?
+ this.registerNodeDescendants(widget.domNode) : this;
+ },
+
+ unregisterWidgetDescendants: function(widget){
+ // summary:
+ // Unregister widget's descendants with the form manager
+ // widget: String|Node|dijit._Widget:
+ // A widget, or its widgetId, or its DOM node
+ // returns: Object:
+ // Returns self
+
+ // convert to widget, if required
+ if(typeof widget == "string"){
+ widget = manager.byId(widget);
+ }else if(widget.tagName && widget.cloneNode){
+ widget = manager.byNode(widget);
+ }
+
+ // unregister widgets by names
+ array.forEach(
+ array.map(
+ widget.getDescendants(),
+ function(w){
+ return w instanceof FormWidget && w.get("name") || null;
+ }
+ ),
+ function(name){
+ if(name){
+ this.unregisterNode(name);
+ }
+ },
+ this
+ );
+
+ // do the same with nodes, if available
+ return this.unregisterNodeDescendants ?
+ this.unregisterNodeDescendants(widget.domNode) : this;
+ },
+
+ // value accessors
+
+ formWidgetValue: function(elem, value){
+ // summary:
+ // Set or get a form widget by name.
+ // elem: String|Object|Array:
+ // Form element's name, widget object, or array or radio widgets.
+ // value: Object?:
+ // Optional. The value to set.
+ // returns: Object:
+ // For a getter it returns the value, for a setter it returns
+ // self. If the elem is not valid, null will be returned.
+
+ var isSetter = arguments.length == 2 && value !== undefined, result;
+
+ if(typeof elem == "string"){
+ elem = this.formWidgets[elem];
+ if(elem){
+ elem = elem.widget;
+ }
+ }
+
+ if(!elem){
+ return null; // Object
+ }
+
+ if(lang.isArray(elem)){
+ // input/radio array of widgets
+ if(isSetter){
+ array.forEach(elem, function(widget){
+ widget.set("checked", false, !this.watching);
+ });
+ array.forEach(elem, function(widget){
+ widget.set("checked", widget.value === value, !this.watching);
+ });
+ return this; // self
+ }
+ // getter
+ array.some(elem, function(widget){
+ // TODO: for some reason for radio button widgets
+ // w.checked != w.focusNode.checked when value changes.
+ // We test the underlying value to be 100% sure.
+ if(domAttr.get(widget.focusNode, "checked")){
+ //if(widget.get("checked")){
+ result = widget;
+ return true;
+ }
+ return false;
+ });
+ return result ? result.get("value") : ""; // String
+ }
+
+ // checkbox widget is a special case :-(
+ if(elem.isInstanceOf && elem.isInstanceOf(CheckBox)){
+ if(isSetter){
+ elem.set("value", Boolean(value), !this.watching);
+ return this; // self
+ }
+ return Boolean(elem.get("value")); // Object
+ }
+
+ // all other elements
+ if(isSetter){
+ elem.set("value", value, !this.watching);
+ return this; // self
+ }
+ return elem.get("value"); // Object
+ },
+
+ formPointValue: function(elem, value){
+ // summary:
+ // Set or get a node context by name (using dojoAttachPoint).
+ // elem: String|Object|Array:
+ // A node.
+ // value: Object?:
+ // Optional. The value to set.
+ // returns: Object:
+ // For a getter it returns the value, for a setter it returns
+ // self. If the elem is not valid, null will be returned.
+
+ if(elem && typeof elem == "string"){
+ elem = this[elem];
+ }
+
+ if(!elem || !elem.tagName || !elem.cloneNode){
+ return null; // Object
+ }
+
+ if(!domClass.contains(elem, "dojoFormValue")){
+ // accessing the value of the attached point not marked with CSS class 'dojoFormValue'
+ return null;
+ }
+
+ if(arguments.length == 2 && value !== undefined){
+ // setter
+ elem.innerHTML = value;
+ return this; // self
+ }
+ // getter
+ return elem.innerHTML; // String
+ },
+
+ // inspectors
+
+ inspectFormWidgets: function(inspector, state, defaultValue){
+ // summary:
+ // Run an inspector function on controlled widgets returning a result object.
+ // inspector: Function:
+ // A function to be called on a widget. Takes three arguments: a name, a widget object
+ // or an array of widget objects, and a supplied value. Runs in the context of
+ // the form manager. Returns a value that will be collected and returned as a state.
+ // state: Object?:
+ // Optional. If a name-value dictionary --- only listed names will be processed.
+ // If an array, all names in the array will be processed with defaultValue.
+ // If omitted or null, all widgets will be processed with defaultValue.
+ // defaultValue: Object?:
+ // Optional. The default state (true, if omitted).
+
+ var name, result = {};
+
+ if(state){
+ if(lang.isArray(state)){
+ array.forEach(state, function(name){
+ if(name in this.formWidgets){
+ result[name] = inspector.call(this, name, this.formWidgets[name].widget, defaultValue);
+ }
+ }, this);
+ }else{
+ for(name in state){
+ if(name in this.formWidgets){
+ result[name] = inspector.call(this, name, this.formWidgets[name].widget, state[name]);
+ }
+ }
+ }
+ }else{
+ for(name in this.formWidgets){
+ result[name] = inspector.call(this, name, this.formWidgets[name].widget, defaultValue);
+ }
+ }
+
+ return result; // Object
+ },
+
+ inspectAttachedPoints: function(inspector, state, defaultValue){
+ // summary:
+ // Run an inspector function on "dojoAttachPoint" nodes returning a result object.
+ // inspector: Function:
+ // A function to be called on a node. Takes three arguments: a name, a node or
+ // an array of nodes, and a supplied value. Runs in the context of the form manager.
+ // Returns a value that will be collected and returned as a state.
+ // state: Object?:
+ // Optional. If a name-value dictionary --- only listed names will be processed.
+ // If an array, all names in the array will be processed with defaultValue.
+ // If omitted or null, all attached point nodes will be processed with defaultValue.
+ // defaultValue: Object?:
+ // Optional. The default state (true, if omitted).
+
+ var name, result = {};
+
+ if(state){
+ if(lang.isArray(state)){
+ array.forEach(state, function(name){
+ var elem = this[name];
+ if(elem && elem.tagName && elem.cloneNode){
+ result[name] = inspector.call(this, name, elem, defaultValue);
+ }
+ }, this);
+ }else{
+ for(name in state){
+ var elem = this[name];
+ if(elem && elem.tagName && elem.cloneNode){
+ result[name] = inspector.call(this, name, elem, state[name]);
+ }
+ }
+ }
+ }else{
+ for(name in this){
+ if(!(name in skipNames)){
+ var elem = this[name];
+ if(elem && elem.tagName && elem.cloneNode){
+ result[name] = inspector.call(this, name, elem, defaultValue);
+ }
+ }
+ }
+ }
+
+ return result; // Object
+ },
+
+ inspect: function(inspector, state, defaultValue){
+ // summary:
+ // Run an inspector function on controlled elements returning a result object.
+ // inspector: Function:
+ // A function to be called on a widget, form element, and an attached node.
+ // Takes three arguments: a name, a node (domNode in the case of widget) or
+ // an array of such objects, and a supplied value. Runs in the context of
+ // the form manager. Returns a value that will be collected and returned as a state.
+ // state: Object?:
+ // Optional. If a name-value dictionary --- only listed names will be processed.
+ // If an array, all names in the array will be processed with defaultValue.
+ // If omitted or null, all controlled elements will be processed with defaultValue.
+ // defaultValue: Object?:
+ // Optional. The default state (true, if omitted).
+
+ var result = this.inspectFormWidgets(function(name, widget, value){
+ if(lang.isArray(widget)){
+ return inspector.call(this, name, array.map(widget, function(w){ return w.domNode; }), value);
+ }
+ return inspector.call(this, name, widget.domNode, value);
+ }, state, defaultValue);
+ if(this.inspectFormNodes){
+ lang.mixin(result, this.inspectFormNodes(inspector, state, defaultValue));
+ }
+ return lang.mixin(result, this.inspectAttachedPoints(inspector, state, defaultValue)); // Object
+ }
+ });
+
+// These arguments can be specified for widgets which are used in forms.
+// Since any widget can be specified as sub widgets, mix it into the base
+// widget class. (This is a hack, but it's effective.)
+lang.extend(Widget, {
+ observer: ""
+});
+return _Mixin;
+});
diff --git a/js/dojo/dojox/form/manager/_NodeMixin.js b/js/dojo/dojox/form/manager/_NodeMixin.js
new file mode 100644
index 0000000..b8a895f
--- /dev/null
+++ b/js/dojo/dojox/form/manager/_NodeMixin.js
@@ -0,0 +1,369 @@
+//>>built
+define("dojox/form/manager/_NodeMixin", [
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojo/_base/connect",
+ "dojo/dom",
+ "dojo/dom-attr",
+ "dojo/query",
+ "./_Mixin",
+ "dijit/form/_FormWidget",
+ "dijit/_base/manager",
+ "dojo/_base/declare"
+], function(lang, array, connect, dom, domAttr, query, _Mixin, _FormWidget, manager, declare){
+ var fm = lang.getObject("dojox.form.manager", true),
+ aa = fm.actionAdapter,
+ keys = fm._keys,
+
+ ce = fm.changeEvent = function(node){
+ // summary:
+ // Function that returns a valid "onchange" event for a given form node.
+ // node: Node:
+ // Form node.
+
+ var eventName = "onclick";
+ switch(node.tagName.toLowerCase()){
+ case "textarea":
+ eventName = "onkeyup";
+ break;
+ case "select":
+ eventName = "onchange";
+ break;
+ case "input":
+ switch(node.type.toLowerCase()){
+ case "text":
+ case "password":
+ eventName = "onkeyup";
+ break;
+ }
+ break;
+ // button, input/button, input/checkbox, input/radio,
+ // input/file, input/image, input/submit, input/reset
+ // use "onclick" (the default)
+ }
+ return eventName; // String
+ },
+
+ registerNode = function(node, groupNode){
+ var name = domAttr.get(node, "name");
+ groupNode = groupNode || this.domNode;
+ if(name && !(name in this.formWidgets)){
+ // verify that it is not part of any widget
+ for(var n = node; n && n !== groupNode; n = n.parentNode){
+ if(domAttr.get(n, "widgetId") && manager.byNode(n).isInstanceOf(_FormWidget)){
+ // this is a child of some widget --- bail out
+ return null;
+ }
+ }
+ // register the node
+ if(node.tagName.toLowerCase() == "input" && node.type.toLowerCase() == "radio"){
+ var a = this.formNodes[name];
+ a = a && a.node;
+ if(a && lang.isArray(a)){
+ a.push(node);
+ }else{
+ this.formNodes[name] = {node: [node], connections: []};
+ }
+ }else{
+ this.formNodes[name] = {node: node, connections: []};
+ }
+ }else{
+ name = null;
+ }
+ return name;
+ },
+
+ getObserversFromNode = function(name){
+ var observers = {};
+ aa(function(_, n){
+ var o = domAttr.get(n, "observer");
+ if(o && typeof o == "string"){
+ array.forEach(o.split(","), function(o){
+ o = lang.trim(o);
+ if(o && lang.isFunction(this[o])){
+ observers[o] = 1;
+ }
+ }, this);
+ }
+ }).call(this, null, this.formNodes[name].node);
+ return keys(observers);
+ },
+
+ connectNode = function(name, observers){
+ var t = this.formNodes[name], c = t.connections;
+ if(c.length){
+ array.forEach(c, connect.disconnect);
+ c = t.connections = [];
+ }
+ aa(function(_, n){
+ // the next line is a crude workaround for Button that fires onClick instead of onChange
+ var eventName = ce(n);
+ array.forEach(observers, function(o){
+ c.push(connect.connect(n, eventName, this, function(evt){
+ if(this.watching){
+ this[o](this.formNodeValue(name), name, n, evt);
+ }
+ }));
+ }, this);
+ }).call(this, null, t.node);
+ };
+
+ return declare("dojox.form.manager._NodeMixin", null, {
+ // summary:
+ // Mixin to orchestrate dynamic forms (works with DOM nodes).
+ // description:
+ // This mixin provideas a foundation for an enhanced form
+ // functionality: unified access to individual form elements,
+ // unified "onchange" event processing, and general event
+ // processing. It complements dojox.form.manager._Mixin
+ // extending the functionality to DOM nodes.
+
+ destroy: function(){
+ // summary:
+ // Called when the widget is being destroyed
+
+ for(var name in this.formNodes){
+ array.forEach(this.formNodes[name].connections, connect.disconnect);
+ }
+ this.formNodes = {};
+
+ this.inherited(arguments);
+ },
+
+ // register/unregister widgets and nodes
+
+ registerNode: function(node){
+ // summary:
+ // Register a node with the form manager
+ // node: String|Node:
+ // A node, or its id
+ // returns: Object:
+ // Returns self
+ if(typeof node == "string"){
+ node = dom.byId(node);
+ }
+ var name = registerNode.call(this, node);
+ if(name){
+ connectNode.call(this, name, getObserversFromNode.call(this, name));
+ }
+ return this;
+ },
+
+ unregisterNode: function(name){
+ // summary:
+ // Removes the node by name from internal tables unregistering
+ // connected observers
+ // name: String:
+ // Name of the to unregister
+ // returns: Object:
+ // Returns self
+ if(name in this.formNodes){
+ array.forEach(this.formNodes[name].connections, this.disconnect, this);
+ delete this.formNodes[name];
+ }
+ return this;
+ },
+
+ registerNodeDescendants: function(node){
+ // summary:
+ // Register node's descendants (form nodes) with the form manager
+ // node: String|Node:
+ // A widget, or its widgetId, or its DOM node
+ // returns: Object:
+ // Returns self
+
+ if(typeof node == "string"){
+ node = dom.byId(node);
+ }
+
+ query("input, select, textarea, button", node).
+ map(function(n){
+ return registerNode.call(this, n, node);
+ }, this).
+ forEach(function(name){
+ if(name){
+ connectNode.call(this, name, getObserversFromNode.call(this, name));
+ }
+ }, this);
+
+ return this;
+ },
+
+ unregisterNodeDescendants: function(node){
+ // summary:
+ // Unregister node's descendants (form nodes) with the form manager
+ // node: String|Node:
+ // A widget, or its widgetId, or its DOM node
+ // returns: Object:
+ // Returns self
+
+ if(typeof node == "string"){
+ node = dom.byId(node);
+ }
+
+ query("input, select, textarea, button", node).
+ map(function(n){ return domAttr.get(node, "name") || null; }).
+ forEach(function(name){
+ if(name){
+ this.unregisterNode(name);
+ }
+ }, this);
+
+ return this;
+ },
+
+ // value accessors
+
+ formNodeValue: function(elem, value){
+ // summary:
+ // Set or get a form element by name.
+ // elem: String|Node|Array:
+ // Form element's name, DOM node, or array or radio nodes.
+ // value: Object?:
+ // Optional. The value to set.
+ // returns: Object:
+ // For a getter it returns the value, for a setter it returns
+ // self. If the elem is not valid, null will be returned.
+
+ var isSetter = arguments.length == 2 && value !== undefined, result;
+
+ if(typeof elem == "string"){
+ elem = this.formNodes[elem];
+ if(elem){
+ elem = elem.node;
+ }
+ }
+
+ if(!elem){
+ return null; // Object
+ }
+
+ if(lang.isArray(elem)){
+ // input/radio array
+ if(isSetter){
+ array.forEach(elem, function(node){
+ node.checked = "";
+ });
+ array.forEach(elem, function(node){
+ node.checked = node.value === value ? "checked" : "";
+ });
+ return this; // self
+ }
+ // getter
+ array.some(elem, function(node){
+ if(node.checked){
+ result = node;
+ return true;
+ }
+ return false;
+ });
+ return result ? result.value : ""; // String
+ }
+ // all other elements
+ switch(elem.tagName.toLowerCase()){
+ case "select":
+ if(elem.multiple){
+ // multiple is allowed
+ if(isSetter){
+ if(lang.isArray(value)){
+ var dict = {};
+ array.forEach(value, function(v){
+ dict[v] = 1;
+ });
+ query("> option", elem).forEach(function(opt){
+ opt.selected = opt.value in dict;
+ });
+ return this; // self
+ }
+ // singular property
+ query("> option", elem).forEach(function(opt){
+ opt.selected = opt.value === value;
+ });
+ return this; // self
+ }
+ // getter
+ var result = query("> option", elem).filter(function(opt){
+ return opt.selected;
+ }).map(function(opt){
+ return opt.value;
+ });
+ return result.length == 1 ? result[0] : result; // Object
+ }
+ // singular
+ if(isSetter){
+ query("> option", elem).forEach(function(opt){
+ opt.selected = opt.value === value;
+ });
+ return this; // self
+ }
+ // getter
+ return elem.value || ""; // String
+ case "button":
+ if(isSetter){
+ elem.innerHTML = "" + value;
+ return this;
+ }
+ // getter
+ return elem.innerHTML;
+ case "input":
+ if(elem.type.toLowerCase() == "checkbox"){
+ // input/checkbox element
+ if(isSetter){
+ elem.checked = value ? "checked" : "";
+ return this;
+ }
+ // getter
+ return Boolean(elem.checked);
+ }
+ }
+ // the rest of inputs
+ if(isSetter){
+ elem.value = "" + value;
+ return this;
+ }
+ // getter
+ return elem.value;
+ },
+
+ // inspectors
+
+ inspectFormNodes: function(inspector, state, defaultValue){
+ // summary:
+ // Run an inspector function on controlled form elements returning a result object.
+ // inspector: Function:
+ // A function to be called on a form element. Takes three arguments: a name, a node or
+ // an array of nodes, and a supplied value. Runs in the context of the form manager.
+ // Returns a value that will be collected and returned as a state.
+ // state: Object?:
+ // Optional. If a name-value dictionary --- only listed names will be processed.
+ // If an array, all names in the array will be processed with defaultValue.
+ // If omitted or null, all form elements will be processed with defaultValue.
+ // defaultValue: Object?:
+ // Optional. The default state (true, if omitted).
+
+ var name, result = {};
+
+ if(state){
+ if(lang.isArray(state)){
+ array.forEach(state, function(name){
+ if(name in this.formNodes){
+ result[name] = inspector.call(this, name, this.formNodes[name].node, defaultValue);
+ }
+ }, this);
+ }else{
+ for(name in state){
+ if(name in this.formNodes){
+ result[name] = inspector.call(this, name, this.formNodes[name].node, state[name]);
+ }
+ }
+ }
+ }else{
+ for(name in this.formNodes){
+ result[name] = inspector.call(this, name, this.formNodes[name].node, defaultValue);
+ }
+ }
+
+ return result; // Object
+ }
+ });
+});
diff --git a/js/dojo/dojox/form/manager/_ValueMixin.js b/js/dojo/dojox/form/manager/_ValueMixin.js
new file mode 100644
index 0000000..785a15f
--- /dev/null
+++ b/js/dojo/dojox/form/manager/_ValueMixin.js
@@ -0,0 +1,82 @@
+//>>built
+define("dojox/form/manager/_ValueMixin", [
+ "dojo/_base/lang",
+ "dojo/_base/kernel",
+ "dojo/_base/declare"
+], function(lang, dojo, declare){
+return declare("dojox.form.manager._ValueMixin", null, {
+ // summary:
+ // Form manager's mixin for getting/setting form values in the unified manner.
+ // description:
+ // This mixin adds unified access to form widgets and form elements
+ // in terms of name-value regardless of the underlying type of
+ // an element. It should be used together with dojox.form.manager.Mixin.
+
+ elementValue: function(name, value){
+ // summary:
+ // Set or get a form widget/element or an attached point node by name.
+ // name: String:
+ // The name.
+ // value: Object?:
+ // Optional. The value to set.
+
+ if(name in this.formWidgets){
+ return this.formWidgetValue(name, value); // Object
+ }
+
+ if(this.formNodes && name in this.formNodes){
+ return this.formNodeValue(name, value); // Object
+ }
+
+ return this.formPointValue(name, value); // Object
+ },
+
+ gatherFormValues: function(names){
+ // summary:
+ // Collect form values.
+ // names: Object?:
+ // If it is an array, it is a list of names of form elements to be collected.
+ // If it is an object, dictionary keys are names to be collected.
+ // If it is omitted, all known form elements are to be collected.
+
+ var result = this.inspectFormWidgets(function(name){
+ return this.formWidgetValue(name);
+ }, names);
+
+ if(this.inspectFormNodes){
+ lang.mixin(result, this.inspectFormNodes(function(name){
+ return this.formNodeValue(name);
+ }, names));
+ }
+
+ lang.mixin(result, this.inspectAttachedPoints(function(name){
+ return this.formPointValue(name);
+ }, names));
+
+ return result; // Object
+ },
+
+ setFormValues: function(values){
+ // summary:
+ // Set values to form elements
+ // values: Object:
+ // A dictionary of key-value pairs.
+ if(values){
+ this.inspectFormWidgets(function(name, widget, value){
+ this.formWidgetValue(name, value);
+ }, values);
+
+ if(this.inspectFormNodes){
+ this.inspectFormNodes(function(name, node, value){
+ this.formNodeValue(name, value);
+ }, values);
+ }
+
+ this.inspectAttachedPoints(function(name, node, value){
+ this.formPointValue(name, value);
+ }, values);
+ }
+ return this;
+ }
+});
+});
diff --git a/js/dojo/dojox/form/nls/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/CheckedMultiSelect.js
new file mode 100644
index 0000000..64a4cc7
--- /dev/null
+++ b/js/dojo/dojox/form/nls/CheckedMultiSelect.js
@@ -0,0 +1,37 @@
+//>>built
+define("dojox/form/nls/CheckedMultiSelect", { root:
+//begin v1.x content
+({
+ invalidMessage: "At least one item must be selected.",
+ multiSelectLabelText: "{num} item(s) selected"
+})
+//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,
+"pl": true,
+"nl": true,
+"nb": true,
+"ko": true,
+"kk": true,
+"ja": true,
+"it": true,
+"hu": true,
+"hr": true,
+"fr": true,
+"fi": true,
+"es": true,
+"el": true,
+"de": true,
+"da": true,
+"cs": true,
+"ca": true
+});
diff --git a/js/dojo/dojox/form/nls/PasswordValidator.js b/js/dojo/dojox/form/nls/PasswordValidator.js
new file mode 100644
index 0000000..84f4c62
--- /dev/null
+++ b/js/dojo/dojox/form/nls/PasswordValidator.js
@@ -0,0 +1,41 @@
+//>>built
+define("dojox/form/nls/PasswordValidator", { root:
+//begin v1.x content
+({
+ nomatchMessage: "Passwords do not match.",
+ badPasswordMessage: "Invalid Password."
+})
+//end v1.x content
+,
+"ar": true,
+"az": true,
+"ca": true,
+"cs": true,
+"da": true,
+"de": true,
+"el": true,
+"es": true,
+"fi": true,
+"fr": true,
+"he": true,
+"hu": true,
+"hr": true,
+"it": true,
+"ja": true,
+"kk": true,
+"ko": true,
+"nb": true,
+"nl": true,
+"pl": true,
+"pt-pt": true,
+"pt": true,
+"ro": true,
+"ru": true,
+"sk": true,
+"sl": true,
+"sv": true,
+"th": true,
+"tr": true,
+"zh": true,
+"zh-tw": true
+});
diff --git a/js/dojo/dojox/form/nls/Uploader.js b/js/dojo/dojox/form/nls/Uploader.js
new file mode 100644
index 0000000..36fbc79
--- /dev/null
+++ b/js/dojo/dojox/form/nls/Uploader.js
@@ -0,0 +1,36 @@
+//>>built
+define("dojox/form/nls/Uploader", { root:
+//begin v1.x content
+({
+ label: "Select Files..."
+})
+//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,
+"pl": true,
+"nl": true,
+"nb": true,
+"ko": true,
+"kk": true,
+"ja": true,
+"it": true,
+"hu": true,
+"hr": true,
+"fr": true,
+"fi": true,
+"es": true,
+"el": true,
+"de": true,
+"da": true,
+"cs": true,
+"ca": true
+});
diff --git a/js/dojo/dojox/form/nls/ar/PasswordValidator.js b/js/dojo/dojox/form/nls/ar/PasswordValidator.js
new file mode 100644
index 0000000..7207f7b
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ar/PasswordValidator.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dojox/form/nls/ar/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "كلمات السرية غير مطابقة.",
+ badPasswordMessage: "كلمة سرية غير صحيحة."
+})
+//end v1.x content
+);
diff --git a/js/dojo/dojox/form/nls/az/PasswordValidator.js b/js/dojo/dojox/form/nls/az/PasswordValidator.js
new file mode 100644
index 0000000..5d815e0
--- /dev/null
+++ b/js/dojo/dojox/form/nls/az/PasswordValidator.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dojox/form/nls/az/PasswordValidator", //begin v1.x content
+({
+ "badPasswordMessage" : "Səhv şifrə.",
+ "nomatchMessage" : "Şifrələr eyni deyil."
+})
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/ca/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/ca/CheckedMultiSelect.js
new file mode 100644
index 0000000..3c0dbe0
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ca/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/ca/CheckedMultiSelect", ({
+ invalidMessage: "Cal seleccionar, com a mínim, un element.",
+ multiSelectLabelText: "{num} element(s) seleccionat(s)"
+})
+);
diff --git a/js/dojo/dojox/form/nls/ca/PasswordValidator.js b/js/dojo/dojox/form/nls/ca/PasswordValidator.js
new file mode 100644
index 0000000..d6553b2
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ca/PasswordValidator.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dojox/form/nls/ca/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Les contrasenyes no coincideixen",
+ badPasswordMessage: "La contrasenya no és correcta"
+})
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/ca/Uploader.js b/js/dojo/dojox/form/nls/ca/Uploader.js
new file mode 100644
index 0000000..3038a0a
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ca/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/ca/Uploader", ({
+ label: "Selecciona fitxers..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/cs/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/cs/CheckedMultiSelect.js
new file mode 100644
index 0000000..fe8c68c
--- /dev/null
+++ b/js/dojo/dojox/form/nls/cs/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/cs/CheckedMultiSelect", ({
+ invalidMessage: "Je třeba vybrat alespoň jednu položku.",
+ multiSelectLabelText: "Počet vybraných položek: {num}"
+})
+);
diff --git a/js/dojo/dojox/form/nls/cs/PasswordValidator.js b/js/dojo/dojox/form/nls/cs/PasswordValidator.js
new file mode 100644
index 0000000..02da8b6
--- /dev/null
+++ b/js/dojo/dojox/form/nls/cs/PasswordValidator.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dojox/form/nls/cs/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Hesla se neshodují.",
+ badPasswordMessage: "Neplatné heslo."
+})
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/cs/Uploader.js b/js/dojo/dojox/form/nls/cs/Uploader.js
new file mode 100644
index 0000000..43f2ee3
--- /dev/null
+++ b/js/dojo/dojox/form/nls/cs/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/cs/Uploader", ({
+ label: "Vybrat soubory..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/da/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/da/CheckedMultiSelect.js
new file mode 100644
index 0000000..022a329
--- /dev/null
+++ b/js/dojo/dojox/form/nls/da/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/da/CheckedMultiSelect", ({
+ invalidMessage: "Du skal vælge mindst ét element.",
+ multiSelectLabelText: "{num} element(er) valgt"
+})
+);
diff --git a/js/dojo/dojox/form/nls/da/PasswordValidator.js b/js/dojo/dojox/form/nls/da/PasswordValidator.js
new file mode 100644
index 0000000..0ef1778
--- /dev/null
+++ b/js/dojo/dojox/form/nls/da/PasswordValidator.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dojox/form/nls/da/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Adgangskoderne stemmer ikke overens.",
+ badPasswordMessage: "Ugyldig adgangskode."
+})
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/da/Uploader.js b/js/dojo/dojox/form/nls/da/Uploader.js
new file mode 100644
index 0000000..92420c4
--- /dev/null
+++ b/js/dojo/dojox/form/nls/da/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/da/Uploader", ({
+ label: "Vælg filer..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/de/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/de/CheckedMultiSelect.js
new file mode 100644
index 0000000..ed33c6d
--- /dev/null
+++ b/js/dojo/dojox/form/nls/de/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/de/CheckedMultiSelect", ({
+ invalidMessage: "Es muss mindestens ein Element ausgewählt werden.",
+ multiSelectLabelText: "{num} Element(e) ausgewählt"
+})
+);
diff --git a/js/dojo/dojox/form/nls/de/PasswordValidator.js b/js/dojo/dojox/form/nls/de/PasswordValidator.js
new file mode 100644
index 0000000..235a252
--- /dev/null
+++ b/js/dojo/dojox/form/nls/de/PasswordValidator.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dojox/form/nls/de/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Die Kennwörter stimmen nicht überein.",
+ badPasswordMessage: "Ungültiges Kennwort."
+})
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/de/Uploader.js b/js/dojo/dojox/form/nls/de/Uploader.js
new file mode 100644
index 0000000..b3a2a90
--- /dev/null
+++ b/js/dojo/dojox/form/nls/de/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/de/Uploader", ({
+ label: "Dateien auswählen..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/el/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/el/CheckedMultiSelect.js
new file mode 100644
index 0000000..85391af
--- /dev/null
+++ b/js/dojo/dojox/form/nls/el/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/el/CheckedMultiSelect", ({
+ invalidMessage: "Πρέπει να επιλέξετε τουλάχιστον ένα στοιχείο.",
+ multiSelectLabelText: "Επιλέχθηκε(-αν) {num} στοιχείο(-α)"
+})
+);
diff --git a/js/dojo/dojox/form/nls/el/PasswordValidator.js b/js/dojo/dojox/form/nls/el/PasswordValidator.js
new file mode 100644
index 0000000..674f4d6
--- /dev/null
+++ b/js/dojo/dojox/form/nls/el/PasswordValidator.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dojox/form/nls/el/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Οι κωδικοί πρόσβασης δεν συμφωνούν.",
+ badPasswordMessage: "Μη έγκυρος κωδικός πρόσβασης."
+})
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/el/Uploader.js b/js/dojo/dojox/form/nls/el/Uploader.js
new file mode 100644
index 0000000..a3f1f1e
--- /dev/null
+++ b/js/dojo/dojox/form/nls/el/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/el/Uploader", ({
+ label: "Επιλογή αρχείων..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/es/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/es/CheckedMultiSelect.js
new file mode 100644
index 0000000..58cd92e
--- /dev/null
+++ b/js/dojo/dojox/form/nls/es/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/es/CheckedMultiSelect", ({
+ invalidMessage: "Se debe seleccionar al menos un elemento.",
+ multiSelectLabelText: "{num} elemento(s) seleccionado(s)"
+})
+);
diff --git a/js/dojo/dojox/form/nls/es/PasswordValidator.js b/js/dojo/dojox/form/nls/es/PasswordValidator.js
new file mode 100644
index 0000000..73dce2b
--- /dev/null
+++ b/js/dojo/dojox/form/nls/es/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/es/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Las contraseñas no coinciden.",
+ badPasswordMessage: "Contraseña no válida."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/es/Uploader.js b/js/dojo/dojox/form/nls/es/Uploader.js
new file mode 100644
index 0000000..fe13193
--- /dev/null
+++ b/js/dojo/dojox/form/nls/es/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/es/Uploader", ({
+ label: "Seleccionar archivos..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/fi/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/fi/CheckedMultiSelect.js
new file mode 100644
index 0000000..7ed6bfb
--- /dev/null
+++ b/js/dojo/dojox/form/nls/fi/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/fi/CheckedMultiSelect", ({
+ invalidMessage: "Ainakin yksi kohde on valittava.",
+ multiSelectLabelText: "{num} kohde(tta) valittu"
+})
+);
diff --git a/js/dojo/dojox/form/nls/fi/PasswordValidator.js b/js/dojo/dojox/form/nls/fi/PasswordValidator.js
new file mode 100644
index 0000000..dafad39
--- /dev/null
+++ b/js/dojo/dojox/form/nls/fi/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/fi/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Salasanat eivät täsmää.",
+ badPasswordMessage: "Salasana ei kelpaa."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/fi/Uploader.js b/js/dojo/dojox/form/nls/fi/Uploader.js
new file mode 100644
index 0000000..84b3399
--- /dev/null
+++ b/js/dojo/dojox/form/nls/fi/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/fi/Uploader", ({
+ label: "Valitse tiedostot..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/fr/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/fr/CheckedMultiSelect.js
new file mode 100644
index 0000000..7e4c2fe
--- /dev/null
+++ b/js/dojo/dojox/form/nls/fr/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/fr/CheckedMultiSelect", ({
+ invalidMessage: "Au moins un des éléments doit être sélectionné.",
+ multiSelectLabelText: "{num} élément(s) sélectionné(s)"
+})
+);
diff --git a/js/dojo/dojox/form/nls/fr/PasswordValidator.js b/js/dojo/dojox/form/nls/fr/PasswordValidator.js
new file mode 100644
index 0000000..96288aa
--- /dev/null
+++ b/js/dojo/dojox/form/nls/fr/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/fr/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Les mots de passe ne correspondent pas.",
+ badPasswordMessage: "Mot de passe incorrect."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/fr/Uploader.js b/js/dojo/dojox/form/nls/fr/Uploader.js
new file mode 100644
index 0000000..4f00a51
--- /dev/null
+++ b/js/dojo/dojox/form/nls/fr/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/fr/Uploader", ({
+ label: "Sélectionner les fichiers..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/he/PasswordValidator.js b/js/dojo/dojox/form/nls/he/PasswordValidator.js
new file mode 100644
index 0000000..7224a94
--- /dev/null
+++ b/js/dojo/dojox/form/nls/he/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/he/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "הסיסמאות אינן זהות.",
+ badPasswordMessage: "סיסמה לא חוקית."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/hr/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/hr/CheckedMultiSelect.js
new file mode 100644
index 0000000..c73a17a
--- /dev/null
+++ b/js/dojo/dojox/form/nls/hr/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/hr/CheckedMultiSelect", ({
+ invalidMessage: "Mora biti izabrana najmanje jedna stavka.",
+ multiSelectLabelText: "{num} stavki je izabrano"
+})
+);
diff --git a/js/dojo/dojox/form/nls/hr/PasswordValidator.js b/js/dojo/dojox/form/nls/hr/PasswordValidator.js
new file mode 100644
index 0000000..83afcc5
--- /dev/null
+++ b/js/dojo/dojox/form/nls/hr/PasswordValidator.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/hr/PasswordValidator", ({
+ nomatchMessage: "Lozinke se ne podudaraju.",
+ badPasswordMessage: "Neispravna lozinka."
+})
+);
diff --git a/js/dojo/dojox/form/nls/hr/Uploader.js b/js/dojo/dojox/form/nls/hr/Uploader.js
new file mode 100644
index 0000000..ca77022
--- /dev/null
+++ b/js/dojo/dojox/form/nls/hr/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/hr/Uploader", ({
+ label: "Izaberite datoteke..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/hu/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/hu/CheckedMultiSelect.js
new file mode 100644
index 0000000..ea3e703
--- /dev/null
+++ b/js/dojo/dojox/form/nls/hu/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/hu/CheckedMultiSelect", ({
+ invalidMessage: "Legalább egy tételt ki kell választani.",
+ multiSelectLabelText: "{num} elem van kiválasztva"
+})
+);
diff --git a/js/dojo/dojox/form/nls/hu/PasswordValidator.js b/js/dojo/dojox/form/nls/hu/PasswordValidator.js
new file mode 100644
index 0000000..303638e
--- /dev/null
+++ b/js/dojo/dojox/form/nls/hu/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/hu/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "A jelszavak nem egyeznek.",
+ badPasswordMessage: "Érvénytelen jelszó."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/hu/Uploader.js b/js/dojo/dojox/form/nls/hu/Uploader.js
new file mode 100644
index 0000000..4af11bf
--- /dev/null
+++ b/js/dojo/dojox/form/nls/hu/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/hu/Uploader", ({
+ label: "Fájlok kiválasztása..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/it/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/it/CheckedMultiSelect.js
new file mode 100644
index 0000000..ecb40e4
--- /dev/null
+++ b/js/dojo/dojox/form/nls/it/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/it/CheckedMultiSelect", ({
+ invalidMessage: "È necessario selezionare almeno un elemento.",
+ multiSelectLabelText: "{num} elementi selezionati"
+})
+);
diff --git a/js/dojo/dojox/form/nls/it/PasswordValidator.js b/js/dojo/dojox/form/nls/it/PasswordValidator.js
new file mode 100644
index 0000000..14f6296
--- /dev/null
+++ b/js/dojo/dojox/form/nls/it/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/it/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Le password non corrispondono.",
+ badPasswordMessage: "Password non valida."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/it/Uploader.js b/js/dojo/dojox/form/nls/it/Uploader.js
new file mode 100644
index 0000000..9aba5f2
--- /dev/null
+++ b/js/dojo/dojox/form/nls/it/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/it/Uploader", ({
+ label: "Seleziona file..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/ja/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/ja/CheckedMultiSelect.js
new file mode 100644
index 0000000..67607fa
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ja/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/ja/CheckedMultiSelect", ({
+ invalidMessage: "少なくとも 1 つの項目を選択しなければなりません。",
+ multiSelectLabelText: "{num} 個の項目が選択されています"
+})
+);
diff --git a/js/dojo/dojox/form/nls/ja/PasswordValidator.js b/js/dojo/dojox/form/nls/ja/PasswordValidator.js
new file mode 100644
index 0000000..17fb434
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ja/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/ja/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "パスワードが一致しません。",
+ badPasswordMessage: "無効なパスワードです。"
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/ja/Uploader.js b/js/dojo/dojox/form/nls/ja/Uploader.js
new file mode 100644
index 0000000..9133478
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ja/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/ja/Uploader", ({
+ label: "ファイルの選択..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/kk/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/kk/CheckedMultiSelect.js
new file mode 100644
index 0000000..511f367
--- /dev/null
+++ b/js/dojo/dojox/form/nls/kk/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/kk/CheckedMultiSelect", ({
+ invalidMessage: "Кемінде бір элемент таңдалуы керек.",
+ multiSelectLabelText: "{num} элемент(тер)і таңдалды"
+})
+);
diff --git a/js/dojo/dojox/form/nls/kk/PasswordValidator.js b/js/dojo/dojox/form/nls/kk/PasswordValidator.js
new file mode 100644
index 0000000..ad19ee1
--- /dev/null
+++ b/js/dojo/dojox/form/nls/kk/PasswordValidator.js
@@ -0,0 +1,9 @@
+//>>built
+define(
+"dojox/form/nls/kk/PasswordValidator", ({
+ nomatchMessage: "Құпия сөздер сәйкес емес.",
+ badPasswordMessage: "Құпия сөз дұрыс емес."
+})
+
+
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/kk/Uploader.js b/js/dojo/dojox/form/nls/kk/Uploader.js
new file mode 100644
index 0000000..9d4fab0
--- /dev/null
+++ b/js/dojo/dojox/form/nls/kk/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/kk/Uploader", ({
+ label: "Файлдарды таңдау..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/ko/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/ko/CheckedMultiSelect.js
new file mode 100644
index 0000000..b6e15ec
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ko/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/ko/CheckedMultiSelect", ({
+ invalidMessage: "최소한 한 가지 항목을 선택해야 합니다.",
+ multiSelectLabelText: "{num} 항목이 선택되었습니다."
+})
+);
diff --git a/js/dojo/dojox/form/nls/ko/PasswordValidator.js b/js/dojo/dojox/form/nls/ko/PasswordValidator.js
new file mode 100644
index 0000000..412e448
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ko/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/ko/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "비밀번호가 일치하지 않습니다.",
+ badPasswordMessage: "올바르지 않은 비밀번호"
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/ko/Uploader.js b/js/dojo/dojox/form/nls/ko/Uploader.js
new file mode 100644
index 0000000..e3db0a1
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ko/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/ko/Uploader", ({
+ label: "파일 선택..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/nb/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/nb/CheckedMultiSelect.js
new file mode 100644
index 0000000..c48f789
--- /dev/null
+++ b/js/dojo/dojox/form/nls/nb/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/nb/CheckedMultiSelect", ({
+ invalidMessage: "Du må velge minst ett element.",
+ multiSelectLabelText: "{num} element(er) valgt"
+})
+);
diff --git a/js/dojo/dojox/form/nls/nb/PasswordValidator.js b/js/dojo/dojox/form/nls/nb/PasswordValidator.js
new file mode 100644
index 0000000..ba4b714
--- /dev/null
+++ b/js/dojo/dojox/form/nls/nb/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/nb/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Passordene samsvarer ikke.",
+ badPasswordMessage: "Ugyldig passord."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/nb/Uploader.js b/js/dojo/dojox/form/nls/nb/Uploader.js
new file mode 100644
index 0000000..fea6e9a
--- /dev/null
+++ b/js/dojo/dojox/form/nls/nb/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/nb/Uploader", ({
+ label: "Velg filer..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/nl/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/nl/CheckedMultiSelect.js
new file mode 100644
index 0000000..6b03055
--- /dev/null
+++ b/js/dojo/dojox/form/nls/nl/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/nl/CheckedMultiSelect", ({
+ invalidMessage: "Er moet te minste één item worden geselecteerd.",
+ multiSelectLabelText: "{num} item(s) geselecteerd"
+})
+);
diff --git a/js/dojo/dojox/form/nls/nl/PasswordValidator.js b/js/dojo/dojox/form/nls/nl/PasswordValidator.js
new file mode 100644
index 0000000..3236d7c
--- /dev/null
+++ b/js/dojo/dojox/form/nls/nl/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/nl/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Wachtwoorden komen niet overeen.",
+ badPasswordMessage: "Ongeldig wachtwoord."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/nl/Uploader.js b/js/dojo/dojox/form/nls/nl/Uploader.js
new file mode 100644
index 0000000..7a12c38
--- /dev/null
+++ b/js/dojo/dojox/form/nls/nl/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/nl/Uploader", ({
+ label: "Bestanden selecteren..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/pl/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/pl/CheckedMultiSelect.js
new file mode 100644
index 0000000..4cb427b
--- /dev/null
+++ b/js/dojo/dojox/form/nls/pl/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/pl/CheckedMultiSelect", ({
+ invalidMessage: "Należy wybrać co najmniej jeden element.",
+ multiSelectLabelText: "Wybrano elementów: {num}"
+})
+);
diff --git a/js/dojo/dojox/form/nls/pl/PasswordValidator.js b/js/dojo/dojox/form/nls/pl/PasswordValidator.js
new file mode 100644
index 0000000..86364e8
--- /dev/null
+++ b/js/dojo/dojox/form/nls/pl/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/pl/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Hasła nie są zgodne.",
+ badPasswordMessage: "Niepoprawne hasło."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/pl/Uploader.js b/js/dojo/dojox/form/nls/pl/Uploader.js
new file mode 100644
index 0000000..d53e003
--- /dev/null
+++ b/js/dojo/dojox/form/nls/pl/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/pl/Uploader", ({
+ label: "Wybierz pliki..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/pt-pt/PasswordValidator.js b/js/dojo/dojox/form/nls/pt-pt/PasswordValidator.js
new file mode 100644
index 0000000..4c58eb6
--- /dev/null
+++ b/js/dojo/dojox/form/nls/pt-pt/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/pt-pt/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "As palavras-passe não correspondem.",
+ badPasswordMessage: "Palavra-passe não válida."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/pt/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/pt/CheckedMultiSelect.js
new file mode 100644
index 0000000..e214022
--- /dev/null
+++ b/js/dojo/dojox/form/nls/pt/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/pt/CheckedMultiSelect", ({
+ invalidMessage: "Ao menos um item deve ser selecionado.",
+ multiSelectLabelText: "{num} item(ns) selecionado(s)"
+})
+);
diff --git a/js/dojo/dojox/form/nls/pt/PasswordValidator.js b/js/dojo/dojox/form/nls/pt/PasswordValidator.js
new file mode 100644
index 0000000..c57487a
--- /dev/null
+++ b/js/dojo/dojox/form/nls/pt/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/pt/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "As senhas não correspondem.",
+ badPasswordMessage: "Senha Inválida."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/pt/Uploader.js b/js/dojo/dojox/form/nls/pt/Uploader.js
new file mode 100644
index 0000000..9d12368
--- /dev/null
+++ b/js/dojo/dojox/form/nls/pt/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/pt/Uploader", ({
+ label: "Selecione Arquivos..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/ro/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/ro/CheckedMultiSelect.js
new file mode 100644
index 0000000..0bdb3e5
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ro/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/ro/CheckedMultiSelect", ({
+ invalidMessage: "Trebuie să selectaţi cel puţin un articol.",
+ multiSelectLabelText: "{num} articole selectate"
+})
+);
diff --git a/js/dojo/dojox/form/nls/ro/PasswordValidator.js b/js/dojo/dojox/form/nls/ro/PasswordValidator.js
new file mode 100644
index 0000000..508badc
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ro/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/ro/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Parolele nu se potrivesc. ",
+ badPasswordMessage: "Parola nu este validă. "
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/ro/Uploader.js b/js/dojo/dojox/form/nls/ro/Uploader.js
new file mode 100644
index 0000000..9f3011b
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ro/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/ro/Uploader", ({
+ label: "Selectare fişiere..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/ru/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/ru/CheckedMultiSelect.js
new file mode 100644
index 0000000..5f21cde
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ru/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/ru/CheckedMultiSelect", ({
+ invalidMessage: "Необходимо выбрать, как минимум, один элемент.",
+ multiSelectLabelText: "Выбрано элементов: {num}"
+})
+);
diff --git a/js/dojo/dojox/form/nls/ru/PasswordValidator.js b/js/dojo/dojox/form/nls/ru/PasswordValidator.js
new file mode 100644
index 0000000..603b250
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ru/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/ru/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Пароли не совпадают.",
+ badPasswordMessage: "Неправильный пароль."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/ru/Uploader.js b/js/dojo/dojox/form/nls/ru/Uploader.js
new file mode 100644
index 0000000..b11934e
--- /dev/null
+++ b/js/dojo/dojox/form/nls/ru/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/ru/Uploader", ({
+ label: "Выберите файлы..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/sk/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/sk/CheckedMultiSelect.js
new file mode 100644
index 0000000..9854861
--- /dev/null
+++ b/js/dojo/dojox/form/nls/sk/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/sk/CheckedMultiSelect", ({
+ invalidMessage: "Musíte vybrať aspoň jednu položku.",
+ multiSelectLabelText: "Vybraté položky: {num}"
+})
+);
diff --git a/js/dojo/dojox/form/nls/sk/PasswordValidator.js b/js/dojo/dojox/form/nls/sk/PasswordValidator.js
new file mode 100644
index 0000000..4caaa32
--- /dev/null
+++ b/js/dojo/dojox/form/nls/sk/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/sk/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Heslá sa nezhodujú.",
+ badPasswordMessage: "Neplatné heslo."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/sk/Uploader.js b/js/dojo/dojox/form/nls/sk/Uploader.js
new file mode 100644
index 0000000..ad53f71
--- /dev/null
+++ b/js/dojo/dojox/form/nls/sk/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/sk/Uploader", ({
+ label: "Vybrať súbory..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/sl/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/sl/CheckedMultiSelect.js
new file mode 100644
index 0000000..f49717b
--- /dev/null
+++ b/js/dojo/dojox/form/nls/sl/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/sl/CheckedMultiSelect", ({
+ invalidMessage: "Izbrati morate vsaj eno postavko.",
+ multiSelectLabelText: "Število izbranih postavk: {num}"
+})
+);
diff --git a/js/dojo/dojox/form/nls/sl/PasswordValidator.js b/js/dojo/dojox/form/nls/sl/PasswordValidator.js
new file mode 100644
index 0000000..8314b23
--- /dev/null
+++ b/js/dojo/dojox/form/nls/sl/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/sl/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Gesli se ne ujemata.",
+ badPasswordMessage: "Neveljavno geslo."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/sl/Uploader.js b/js/dojo/dojox/form/nls/sl/Uploader.js
new file mode 100644
index 0000000..29e0ad5
--- /dev/null
+++ b/js/dojo/dojox/form/nls/sl/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/sl/Uploader", ({
+ label: "Izberite datoteke ..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/sv/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/sv/CheckedMultiSelect.js
new file mode 100644
index 0000000..2aca4db
--- /dev/null
+++ b/js/dojo/dojox/form/nls/sv/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/sv/CheckedMultiSelect", ({
+ invalidMessage: "Du måste välja minst ett objekt.",
+ multiSelectLabelText: "{num} objekt har valts"
+})
+);
diff --git a/js/dojo/dojox/form/nls/sv/PasswordValidator.js b/js/dojo/dojox/form/nls/sv/PasswordValidator.js
new file mode 100644
index 0000000..e3c0d23
--- /dev/null
+++ b/js/dojo/dojox/form/nls/sv/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/sv/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Lösenorden stämmer inte överens.",
+ badPasswordMessage: "Ogiltigt lösenord."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/sv/Uploader.js b/js/dojo/dojox/form/nls/sv/Uploader.js
new file mode 100644
index 0000000..31d3817
--- /dev/null
+++ b/js/dojo/dojox/form/nls/sv/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/sv/Uploader", ({
+ label: "Välj filer..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/th/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/th/CheckedMultiSelect.js
new file mode 100644
index 0000000..685bf9f
--- /dev/null
+++ b/js/dojo/dojox/form/nls/th/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/th/CheckedMultiSelect", ({
+ invalidMessage: "อย่างน้อยหนึ่งรายการต้องถูกเลือก",
+ multiSelectLabelText: "{num} รายการถูกเลือก"
+})
+);
diff --git a/js/dojo/dojox/form/nls/th/PasswordValidator.js b/js/dojo/dojox/form/nls/th/PasswordValidator.js
new file mode 100644
index 0000000..708e270
--- /dev/null
+++ b/js/dojo/dojox/form/nls/th/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/th/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "รหัสผ่านไม่ตรงกัน",
+ badPasswordMessage: "รหัสผ่านไม่ถูกต้อง"
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/th/Uploader.js b/js/dojo/dojox/form/nls/th/Uploader.js
new file mode 100644
index 0000000..1bbdb46
--- /dev/null
+++ b/js/dojo/dojox/form/nls/th/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/th/Uploader", ({
+ label: "เลือกไฟล์..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/tr/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/tr/CheckedMultiSelect.js
new file mode 100644
index 0000000..7ce9767
--- /dev/null
+++ b/js/dojo/dojox/form/nls/tr/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/tr/CheckedMultiSelect", ({
+ invalidMessage: "En az bir öğe seçilmiş olmalı.",
+ multiSelectLabelText: "{num} öğe seçildi"
+})
+);
diff --git a/js/dojo/dojox/form/nls/tr/PasswordValidator.js b/js/dojo/dojox/form/nls/tr/PasswordValidator.js
new file mode 100644
index 0000000..9037164
--- /dev/null
+++ b/js/dojo/dojox/form/nls/tr/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/tr/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "Parolalar eşleşmiyor.",
+ badPasswordMessage: "Geçersiz Parola."
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/tr/Uploader.js b/js/dojo/dojox/form/nls/tr/Uploader.js
new file mode 100644
index 0000000..8374376
--- /dev/null
+++ b/js/dojo/dojox/form/nls/tr/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/tr/Uploader", ({
+ label: "Dosyaları Seç..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/zh-tw/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/zh-tw/CheckedMultiSelect.js
new file mode 100644
index 0000000..14dc63a
--- /dev/null
+++ b/js/dojo/dojox/form/nls/zh-tw/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/zh-tw/CheckedMultiSelect", ({
+ invalidMessage: "至少必須選取一個項目。",
+ multiSelectLabelText: "已選取 {num} 項目"
+})
+);
diff --git a/js/dojo/dojox/form/nls/zh-tw/PasswordValidator.js b/js/dojo/dojox/form/nls/zh-tw/PasswordValidator.js
new file mode 100644
index 0000000..ce35928
--- /dev/null
+++ b/js/dojo/dojox/form/nls/zh-tw/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/zh-tw/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "密碼不符合。",
+ badPasswordMessage: "無效的密碼。"
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/zh-tw/Uploader.js b/js/dojo/dojox/form/nls/zh-tw/Uploader.js
new file mode 100644
index 0000000..fa250bd
--- /dev/null
+++ b/js/dojo/dojox/form/nls/zh-tw/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/zh-tw/Uploader", ({
+ label: "選取檔案..."
+})
+);
diff --git a/js/dojo/dojox/form/nls/zh/CheckedMultiSelect.js b/js/dojo/dojox/form/nls/zh/CheckedMultiSelect.js
new file mode 100644
index 0000000..e9f5d8f
--- /dev/null
+++ b/js/dojo/dojox/form/nls/zh/CheckedMultiSelect.js
@@ -0,0 +1,7 @@
+//>>built
+define(
+"dojox/form/nls/zh/CheckedMultiSelect", ({
+ invalidMessage: "必须至少选择一项。",
+ multiSelectLabelText: "选择了 {num} 个项"
+})
+);
diff --git a/js/dojo/dojox/form/nls/zh/PasswordValidator.js b/js/dojo/dojox/form/nls/zh/PasswordValidator.js
new file mode 100644
index 0000000..687299c
--- /dev/null
+++ b/js/dojo/dojox/form/nls/zh/PasswordValidator.js
@@ -0,0 +1,10 @@
+//>>built
+define(
+"dojox/form/nls/zh/PasswordValidator", //begin v1.x content
+({
+ nomatchMessage: "密码不匹配。",
+ badPasswordMessage: "密码无效。"
+})
+
+//end v1.x content
+); \ No newline at end of file
diff --git a/js/dojo/dojox/form/nls/zh/Uploader.js b/js/dojo/dojox/form/nls/zh/Uploader.js
new file mode 100644
index 0000000..90a05b8
--- /dev/null
+++ b/js/dojo/dojox/form/nls/zh/Uploader.js
@@ -0,0 +1,6 @@
+//>>built
+define(
+"dojox/form/nls/zh/Uploader", ({
+ label: "选择文件..."
+})
+);
diff --git a/js/dojo/dojox/form/resources/BusyButton.css b/js/dojo/dojox/form/resources/BusyButton.css
new file mode 100644
index 0000000..c4be3ee
--- /dev/null
+++ b/js/dojo/dojox/form/resources/BusyButton.css
@@ -0,0 +1,13 @@
+/*
+**----------------------------------------------------------------------------
+** BusyButton
+**----------------------------------------------------------------------------
+*/
+.dojoxBusyButtonIcon {
+ width: 10px;
+ height: 10px;
+ vertical-align: middle;
+ margin-left: 4px;
+ background-image: url('images/loading_wheel.gif');
+ background-repeat: no-repeat;
+} \ No newline at end of file
diff --git a/js/dojo/dojox/form/resources/CheckedMultiSelect.css b/js/dojo/dojox/form/resources/CheckedMultiSelect.css
new file mode 100644
index 0000000..8037ee1
--- /dev/null
+++ b/js/dojo/dojox/form/resources/CheckedMultiSelect.css
@@ -0,0 +1,278 @@
+/*
+**----------------------------------------------------------------------------
+** CheckedMultiSelect
+**----------------------------------------------------------------------------
+*/
+
+.dojoxCheckedMultiSelectHidden{
+ display: none;
+}
+
+.dojoxCheckedMultiSelect .dojoxCheckedMultiSelectWrapper {
+ border: solid black 1px;
+ margin: 1px 0;
+ overflow: scroll;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ height: 100px;
+}
+
+.dj_ie .dojoxCheckedMultiSelectWrapper,
+.dj_webkit .dojoxCheckedMultiSelectWrapper {
+ /* So that the scroll bar doesn't cover stuff up */
+ padding-right: 15px;
+}
+
+.dojoxMultiSelectItem {
+ cursor: default;
+ padding: 0.1em 0.2em;
+ white-space: nowrap;
+}
+
+.dojoxCheckedMultiSelectItem {
+ white-space: nowrap;
+ padding:.1em .2em;
+ cursor:default;
+}
+
+.dojoxCheckedMultiSelectDisabled *,
+.dojoxCheckedMultiSelectReadOnly * {
+ color:gray !important;
+}
+
+.dojoxCheckedMultiSelectItemLabel {
+ margin-left: .2em;
+}
+
+.dojoxCheckedMultiSelect .dojoxCheckedMultiSelectWrapper {
+ margin: 0em 0.1em;
+}
+
+.dojoxCheckedMultiSelectCheckBoxInput {
+ opacity: 0.01;
+}
+
+.dj_ie .dojoxCheckedMultiSelectCheckBoxInput {
+ filter: alpha(opacity=0);
+ width: 15px;
+ height: 16px;
+}
+
+.dijit_a11y .dojoxCheckedMultiSelectCheckBoxInput {
+ opacity: 1;
+ filter: none;
+}
+
+.dojoxCheckedMultiSelectMenu td.dijitMenuArrowCell {
+ display: none;
+}
+
+.dojoxCheckedMultiSelectMenu td.dijitMenuItemLabel {
+ position: static;
+ padding: 2px;
+}
+
+/*
+**----------------------------------------------------------------------------
+** Tundra theme (make look similar to text box)
+**----------------------------------------------------------------------------
+*/
+.tundra .dojoxCheckedMultiSelect .dojoxCheckedMultiSelectWrapper {
+ background:#fff url("../../../dijit/themes/tundra/images/validationInputBg.png") repeat-x top left;
+ #background:#fff url('../../../dijit/themes/tundra/images/validationInputBg.gif') repeat-x top left;
+ border:1px solid #b3b3b3;
+ line-height: normal;
+}
+
+.tundra .dojoxCheckedMultiSelectFocused .dojoxCheckedMultiSelectWrapper {
+ /* input field when focused (ie: typing affects it) */
+ border-color:#406b9b;
+}
+
+/*
+**----------------------------------------------------------------------------
+** Soria theme (make look similar to text box)
+**----------------------------------------------------------------------------
+*/
+.soria .dojoxCheckedMultiSelect .dojoxCheckedMultiSelectWrapper {
+ background:#fff url("../../../dijit/themes/soria/images/validationInputBg.png") repeat-x top left;
+ #background:#fff url('../../../dijit/themes/soria/images/validationInputBg.gif') repeat-x top left;
+ border:1px solid #8ba0bd;
+ line-height: normal;
+}
+
+.soria .dojoxCheckedMultiSelectFocused .dojoxCheckedMultiSelectWrapper {
+ /* input field when focused (ie: typing affects it) */
+ border-color:#406b9b;
+}
+
+/*
+**----------------------------------------------------------------------------
+** Nihilo theme (make look similar to text box)
+**----------------------------------------------------------------------------
+*/
+.nihilo .dojoxCheckedMultiSelect .dojoxCheckedMultiSelectWrapper {
+ background:#fff url("../../../dijit/themes/nihilo/images/validationInputBg.png") repeat-x top left;
+ #background:#fff url('../../../dijit/themes/nihilo/images/validationInputBg.gif') repeat-x top left;
+ border:1px solid #d3d3d3;
+ line-height: normal;
+}
+
+.nihilo .dojoxCheckedMultiSelectFocused .dojoxCheckedMultiSelectWrapper {
+ /* input field when focused (ie: typing affects it) */
+ border-color:#b3b3b3;
+}
+
+/*
+**----------------------------------------------------------------------------
+** Claro theme (make look similar to text box)
+**----------------------------------------------------------------------------
+*/
+.claro .dojoxCheckedMultiSelect .dojoxCheckedMultiSelectWrapper {
+ border: 1px solid #b5bcc7;
+ background-color: #f7fcff;
+ line-height: normal;
+ -webkit-transition-property:background-color, border;
+ -webkit-transition-duration:.35s;
+}
+
+.claro .dojoxCheckedMultiSelectHover .dojoxCheckedMultiSelectWrapper {
+ border-color: #769dc0;
+ background-color: #e9f4fe;
+ background-image: url('../../../dijit/themes/claro/form/images/textBox_back.png');
+ background-repeat: repeat-x;
+ -webkit-transition-duration:.25s;
+}
+
+.claro .dojoxCheckedMultiSelectFocused .dojoxCheckedMultiSelectWrapper {
+ border: 1px solid #769dc0;
+ -webkit-transition-duration:.1s;
+}
+
+.claro .dojoxCheckedMultiSelectMenuCheckBoxItemIcon {
+ background-image: url('../../../dijit/themes/claro/form/images/checkboxRadioButtonStates.png');
+ background-repeat: no-repeat;
+ background-position: -15px;
+ width: 15px;
+ height: 16px;
+}
+
+.claro .dojoxCheckedMultiSelectMenuRadioItemIcon {
+ background-image: url('../../../dijit/themes/claro/form/images/checkboxRadioButtonStates.png');
+ background-repeat: no-repeat;
+ background-position: -105px;
+ width: 15px;
+ height: 16px;
+}
+
+.dj_ie6 .claro .dojoxCheckedMultiSelectMenuItemIcon {
+ background-image: url('../../../dijit/themes/claro/form/images/checkboxRadioButtonStates.png');
+}
+
+.claro .dojoxCheckedMultiSelectMenuItemChecked .dojoxCheckedMultiSelectMenuCheckBoxItemIcon {
+ background-position: 0;
+}
+
+.claro .dojoxCheckedMultiSelectMenuItemChecked .dojoxCheckedMultiSelectMenuRadioItemIcon {
+ background-position: -90px;
+}
+
+/* Drop down button */
+.claro .dojoxCheckedMultiSelect .dojoxCheckedMultiSelectButton .dijitButtonText {
+ padding: 2px;
+}
+
+/* normal status */
+.claro .dojoxCheckedMultiSelectButton {
+ border: 1px solid #b5bcc7;
+ background-color: #ffffff;
+ border-collapse: separate;
+}
+
+.claro .dojoxCheckedMultiSelect .dijitButtonNode {
+ border: 0 solid #b5bcc7;
+ border-width: 0 0 0 0;
+}
+
+.dj_ie6 .claro .dojoxCheckedMultiSelectButton, .dj_ie6 .claro .dojoxCheckedMultiSelect .dojoxCheckedMultiSelectButton .dijitButtonNode {
+ background-image: none;
+}
+
+.claro .dojoxCheckedMultiSelectButton .dijitButtonContents {
+ border: 0 solid #b5bcc7;
+ border-right-width: 1px;
+}
+
+.claro .dojoxCheckedMultiSelectButton .dijitArrowButton {
+ padding: 0;
+ border: 1px solid #ffffff;
+ border-top: none;
+ background-color: #efefef;
+ background-image: url("../../../dijit/themes/claro/form/images/formHighlight.png");
+ background-repeat: repeat-x;
+}
+
+.claro .dojoxCheckedMultiSelectButton .dijitArrowButton .dijitArrowButtonInner {
+ background-image: url("../../../dijit/themes/claro/form/images/commonFormArrows.png");
+ background-position: -35px;
+ background-repeat: no-repeat;
+ width: 16px;
+ height: 16px;
+}
+
+/* hover status */
+.claro .dojoxCheckedMultiSelectButtonHover {
+ border: 1px solid #769dc0;
+ background-color: #e9f4fe;
+ background-image: url('../../../dijit/themes/claro/form/images/textBox_back.png');
+ background-repeat: repeat-x;
+}
+
+.claro .dojoxCheckedMultiSelectButtonHover .dijitButtonContents {
+ border-color: #769dc0;
+}
+
+.claro .dojoxCheckedMultiSelectButtonHover .dijitArrowButton {
+ background-color: #abd6ff;
+}
+
+.claro .dojoxCheckedMultiSelectButtonHover .dijitArrowButton .dijitArrowButtonInner {
+ background-position: -70px ;
+}
+
+/* focused status */
+.claro .dojoxCheckedMultiSelectButtonFocused {
+ border: 1px solid #769dc0;
+}
+
+.claro .dojoxCheckedMultiSelectButtonFocused .dijitButtonContents {
+ border-color: #769dc0;
+}
+
+.claro .dojoxCheckedMultiSelectButtonFocused .dijitArrowButton {
+ background-color: #7dbefa;
+ background-position: 0 -177px;
+ border: none;
+ padding: 0 1px;
+}
+
+.claro .dojoxCheckedMultiSelectButtonFocused .dijitArrowButton .dijitArrowButtonInner {
+ background-position: -70px;
+ margin-bottom: 1px;
+}
+
+/* disable status */
+.claro .dojoxCheckedMultiSelectButtonDisabled {
+ border: 1px solid #d3d3d3;
+ background-color: #efefef;
+ background-image: none;
+ color: #818181;
+}
+
+.claro .dojoxCheckedMultiSelectButtonDisabled .dijitArrowButton {
+ background-color: #efefef;
+}
+
+.claro .dojoxCheckedMultiSelectButtonDisabled .dijitArrowButton .dijitArrowButtonInner {
+ background-position: 0;
+} \ No newline at end of file
diff --git a/js/dojo/dojox/form/resources/CheckedMultiSelect.html b/js/dojo/dojox/form/resources/CheckedMultiSelect.html
new file mode 100644
index 0000000..5e31a21
--- /dev/null
+++ b/js/dojo/dojox/form/resources/CheckedMultiSelect.html
@@ -0,0 +1,8 @@
+<div class="dijit dijitReset dijitInline dijitLeft" id="widget_${id}"
+ ><div data-dojo-attach-point="comboButtonNode"
+ ></div
+ ><div data-dojo-attach-point="selectNode" class="dijit dijitReset dijitInline ${baseClass}Wrapper" data-dojo-attach-event="onmousedown:_onMouseDown,onclick:focus"
+ ><select class="${baseClass}Select dojoxCheckedMultiSelectHidden" multiple="true" data-dojo-attach-point="containerNode,focusNode"></select
+ ><div data-dojo-attach-point="wrapperDiv"></div
+ ></div
+></div> \ No newline at end of file
diff --git a/js/dojo/dojox/form/resources/FileInput.css b/js/dojo/dojox/form/resources/FileInput.css
new file mode 100644
index 0000000..a807bc0
--- /dev/null
+++ b/js/dojo/dojox/form/resources/FileInput.css
@@ -0,0 +1,128 @@
+.dijitFileInput {
+ position:relative;
+ height:1.3em;
+ /*padding:2px;*/
+}
+
+.dijitFileInputReal {
+ position:absolute;
+ z-index:2;
+ filter:alpha(opacity:0);
+ opacity:0;
+ cursor:pointer;
+}
+.dijitFileInputRealBlind {
+ right:0;
+}
+.dijitFileInputReal:hover { cursor:pointer; }
+
+.dijitFileInputButton,
+.dijitFileInputText {
+ border:1px solid #333;
+ padding:2px 12px 2px 12px;
+ cursor:pointer;
+}
+
+.dijitFileInputButton {
+ z-index:3;
+ visibility:hidden;
+}
+.dijitFakeInput { position:absolute; top:0; left:0; z-index:1; white-space: nowrap; }
+
+.dijitProgressOverlay {
+ display:none;
+ width:250px;
+ height:1em;
+ position:absolute;
+ top:0; left:0;
+ border:1px solid #333;
+ background:#cad2de url('../../../dijit/themes/tundra/images/dijitProgressBarAnim.gif') repeat-x top left;
+ padding:2px;
+}
+
+/* tundra */
+.tundra .dijitProgressOverlay {
+ border:1px solid #84a3d1;
+ background-color:#cad2de;
+}
+.tundra .dijitFakeInput input {
+ /*font-size: inherit;*/
+ padding: 0;
+ background:#fff url("../../../dijit/themes/tundra/images/validationInputBg.png") repeat-x top left;
+ border:1px solid #9b9b9b;
+ line-height: normal;
+}
+.tundra .dijitFileInputButton,
+.tundra .dijitFileInputText {
+ border:1px solid #9b9b9b;
+ padding:0px 12px 0px 12px; /* .3em .4em .2em .4em; */
+ background:#e9e9e9 url("../../../dijit/themes/tundra/images/buttonEnabled.png") repeat-x top;
+}
+
+/* Soria */
+.soria .dijitProgressOverlay {
+ border:1px solid #8BA0BD;
+ background-color:#cad2de;
+}
+.soria .dijitFakeInput input {
+ border:1px solid #8BA0BD;
+ background:#fff url("../../../dijit/themes/soria/images/validationInputBg.png") repeat-x top left;
+ line-height:normal;
+ background-position:0 -30px;
+ padding:0.2em 0.3em;
+}
+.soria .dijitFileInputButton,
+.soria .dijitFileInputText {
+ border:1px solid #8BA0BD;
+ padding:2px 12px 2px 12px;
+ background:#b7cdee url('../../../dijit/themes/soria/images/buttonEnabled.png') repeat-x;
+}
+
+/* Nihilo */
+.nihilo .dijitProgressOverlay {
+ border:1px solid #DEDEDE;
+ background-color:#cad2de;
+}
+.nihilo .dijitFakeInput input {
+ border:1px solid #DEDEDE;
+ background:#fff url("../../../dijit/themes/nihilo/images/validationInputBg.png") repeat-x top left;
+ line-height:normal;
+ background-position:0 -30px;
+ padding:0.2em 0.3em;
+}
+.nihilo .dijitFileInputButton,
+.nihilo .dijitFileInputText {
+ border:1px solid #DEDEDE;
+ padding:2px 12px 2px 12px;
+ background:#b7cdee url('../../../dijit/themes/nihilo/images/buttonEnabled.png') repeat-x;
+}
+
+/* Claro */
+.claro .dijitProgressOverlay {
+ border:1px solid #769dc0;
+ background-color:#769dc0;
+}
+.claro .dijitFakeInput input {
+ border: 1px solid #bcc8dd;
+ background-color: #fff;
+ background-repeat: repeat-x;
+ background-position: top left;
+ background-image:url("../../../dijit/themes/claro/form/images/textBox_back.png");
+ line-height:normal;
+ padding:0.2em 0.3em;
+}
+
+.claro .dijitFileInputButton,
+.claro .dijitFileInputText {
+ background-image: url("../../../dijit/themes/claro/form/images/button_back_full.png");
+ background-position: center top;
+ background-repeat: repeat-x;
+ background-color: #cde3f6;
+ border: 1px solid #799ab7;
+ border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ box-shadow:0px 1px 1px rgba(0,0,0,0.2);
+ -webkit-box-shadow:0px 1px 1px rgba(0,0,0,0.2);
+ -moz-box-shadow: 0px 1px 1px rgba(0,0,0,0.2);
+}
diff --git a/js/dojo/dojox/form/resources/FileInput.html b/js/dojo/dojox/form/resources/FileInput.html
new file mode 100644
index 0000000..4ffd120
--- /dev/null
+++ b/js/dojo/dojox/form/resources/FileInput.html
@@ -0,0 +1,9 @@
+<div class="dijitFileInput">
+ <input id="${id}" class="dijitFileInputReal" type="file" dojoAttachPoint="fileInput" name="${name}" />
+ <div class="dijitFakeInput">
+ <input class="dijitFileInputVisible" type="text" dojoAttachPoint="focusNode, inputNode" />
+ <div class="dijitInline dijitFileInputText" dojoAttachPoint="titleNode">${label}</div>
+ <div class="dijitInline dijitFileInputButton" dojoAttachPoint="cancelNode"
+ dojoAttachEvent="onclick:reset">${cancelText}</div>
+ </div>
+</div>
diff --git a/js/dojo/dojox/form/resources/FileInputAuto.html b/js/dojo/dojox/form/resources/FileInputAuto.html
new file mode 100644
index 0000000..12b2148
--- /dev/null
+++ b/js/dojo/dojox/form/resources/FileInputAuto.html
@@ -0,0 +1,9 @@
+<div class="dijitFileInput">
+ <input id="${id}" name="${name}" class="dijitFileInputReal" type="file" dojoAttachPoint="fileInput" />
+ <div class="dijitFakeInput" dojoAttachPoint="fakeNodeHolder">
+ <input class="dijitFileInputVisible" type="text" dojoAttachPoint="focusNode, inputNode" />
+ <div class="dijitInline dijitFileInputText" dojoAttachPoint="titleNode">${label}</div>
+ <div class="dijitInline dijitFileInputButton" dojoAttachPoint="cancelNode" dojoAttachEvent="onclick:reset">${cancelText}</div>
+ </div>
+ <div class="dijitProgressOverlay" dojoAttachPoint="overlay">&nbsp;</div>
+</div>
diff --git a/js/dojo/dojox/form/resources/FilePickerTextBox.css b/js/dojo/dojox/form/resources/FilePickerTextBox.css
new file mode 100644
index 0000000..a2d13d5
--- /dev/null
+++ b/js/dojo/dojox/form/resources/FilePickerTextBox.css
@@ -0,0 +1,272 @@
+@import url("../../widget/FilePicker/FilePicker.css");
+
+.dojoxFilePickerTextBox{
+ width: 30em;
+ vertical-align: middle;
+}
+.dojoxFilePickerTextBox input:focus{
+ outline: none;
+}
+.dojoxFilePickerTextBoxFocused{
+ outline: auto 5px -webkit-focus-ring-color;
+}
+.dojoxFilePickerTextBox INPUT{
+ border-left: solid black 1px;
+ display:inline;
+ position:static !important;
+ border:0 !important;
+ margin:0 !important;
+ vertical-align:top !important;
+ visibility:visible !important;
+ background-color:transparent !important;
+ background-image:none !important;
+ width:100% !important;
+}
+.dijitRtl .dojoxFilePickerTextBox .dijitInputField {
+ border-right-width:1px !important;
+ border-left-width:0 !important;
+}
+
+/* Tundra stylings */
+.tundra .dojoxFilePickerTextBoxDisabled *
+{
+ cursor: not-allowed !important;
+}
+.tundra .dojoxFilePickerTextBox {
+ font-family: sans-serif;
+ font-size: 100%;
+}
+.tundra .dojoxFilePickerTextBox {
+ background:#fff url("../../../dijit/themes/tundra/images/validationInputBg.png") repeat-x top left;
+ #background:#fff url('../../../dijit/themes/tundra/images/validationInputBg.gif') repeat-x top left;
+ border:1px solid #b3b3b3;
+ line-height: normal;
+}
+.tundra .dojoxFilePickerTextBoxDisabled {
+ color: gray;
+}
+.dj_webkit .tundra .dojoxFilePickerTextBoxDisabled {
+ color: #eee;
+}
+.tundra .dojoxFilePickerTextBox .dijitInputField {
+ padding: 1px 0;
+}
+.tundra .dojoxFilePickerTextBox .dijitButtonNode {
+ padding: 1px 0.2em;
+}
+.tundra .dojoxFilePickerTextBox .dijitButtonNode{
+ border-color: #9b9b9b;
+ border-width: 0px 0px 0px 1px;
+ border-style: solid;
+}
+.tundra .dojoxFilePickerTextBoxFocused {
+ border-color:#406b9b;
+}
+.tundra .dojoxFilePickerTextBoxFocused .dijitButtonNode {
+ border-left-color:#366dba;
+}
+.dijitRtl .tundra .dojoxFilePickerTextBox .dijitButtonNode{
+ border-color: #9b9b9b;
+ border-width: 0px 1px 0px 0px;
+}
+.tundra .dojoxFilePickerTextBoxDisabled {
+ border-color: #d5d5d5 #d5d5d5 #bdbdbd #d5d5d5;
+ background:#e4e4e4 url("../../../dijit/themes/tundra/images/buttonDisabled.png") top repeat-x;
+}
+.tundra .dojoxFilePickerTextBoxHover .dijitDownArrowButton {
+ border-color: #a5beda;
+ border-bottom-color:#5c7590;
+ color:#000;
+ background:#fcfdff url("../../../dijit/themes/tundra/images/buttonHover.png") repeat-x bottom;
+}
+.tundra .dojoxFilePickerTextBoxActive .dijitDownArrowButton {
+ border-color:#366dba;
+ background: #ededed url("../../../dijit/themes/tundra/images/buttonActive.png") bottom repeat-x;
+}
+.tundra .dojoxFilePickerTextBox .dijitArrowButton .dijitArrowButtonInner {
+ background-image: url("images/tundraFolderSprite.gif");
+ background-repeat: no-repeat;
+ background-attachment: scroll;
+ background-position: left center;
+ height: auto;
+ width: 16px;
+ font-size: 100%;
+ font-size: inherit;
+}
+.tundra .dojoxFilePickerTextBox .dojoxHasDropDownOpen .dijitArrowButtonInner {
+ background-position: -16px;
+}
+
+.tundra .dojoxFilePickerTextBoxError {
+ background-color:#f9f7ba;
+ background-image:none;
+}
+.dj_ie6 .tundra .dojoxFilePickerTextBoxError INPUT {
+ background-color:#f9f7ba !important;
+}
+.tundra .dojoxFilePickerTextBoxErrorFocused {
+ background-color:#f9f999;
+ background-image:none;
+}
+.dj_ie6 .tundra .dojoxFilePickerTextBoxErrorFocused INPUT {
+ background-color:#f9f999 !important;
+}
+
+/* nihilo theme */
+.nihilo .dojoxFilePickerTextBoxDisabled *
+{
+ cursor: not-allowed !important;
+}
+.nihilo .dojoxFilePickerTextBox{
+ margin: 0em 0.1em;
+}
+.nihilo .dojoxFilePickerTextBox {
+ background:#fff url("../../../dijit/themes/nihilo/images/validationInputBg.png") repeat-x top left;
+ #background:#fff url('../../../dijit/themes/nihilo/images/validationInputBg.gif') repeat-x top left;
+ border:1px solid #d3d3d3;
+ line-height: normal;
+}
+.nihilo .dojoxFilePickerTextBox .dijitButtonNode {
+ padding: 0 0.2em;
+}
+.nihilo .dojoxFilePickerTextBox .dijitButtonNode{
+ border-color: #d3d3d3;
+ border-left: 1px solid #d3d3d3;
+}
+.nihilo .dojoxFilePickerTextBoxDisabled {
+ color: gray;
+}
+.dj_safari .nihilo .dojoxFilePickerTextBoxDisabled {
+ color: #eee;
+}
+.nihilo .dojoxFilePickerTextBoxFocused {
+ border-color:#b3b3b3;
+}
+.nihilo .dojoxFilePickerTextBoxFocused .dijitButtonNode, {
+ border-left-color:#d3d3d3;
+}
+.dijitRtl .nihilo .dojoxFilePickerTextBox .dijitButtonNode {
+ border-color: #8ba0bd;
+ border-left: 0px solid #8ba0bd;
+ border-right: 1px solid #8ba0bd;
+}
+.nihilo .dojoxFilePickerTextBoxDisabled {
+ border-color: #dedede;
+ background:#fafafa url("../../../dijit/themes/nihilo/images/buttonDisabled.png") top repeat-x;
+ opacity: 0.60;
+}
+.nihilo .dojoxFilePickerTextBoxHover .dijitDownArrowButton {
+ color:#000;
+ background:#fcfcfc url("../../../dijit/themes/nihilo/images/buttonHover.png") repeat-x top left;
+}
+.nihilo .dojoxFilePickerTextBoxActive .dijitDownArrowButton {
+ border-color:#dedede;
+ background: #f5f5f5 url("../../../dijit/themes/nihilo/images/buttonActive.png") top left repeat-x;
+}
+.dijitRtl .nihilo .dojoxFilePickerTextBox .dijitButtonNode {
+ border-width: 0px 0px 0px 1px;
+}
+.nihilo .dojoxFilePickerTextBox .dijitArrowButton .dijitArrowButtonInner {
+ background:url("images/nihiloFolderSprite.gif") no-repeat left center;
+ width: 16px;
+}
+.nihilo .dojoxFilePickerTextBox .dojoxHasDropDownOpen .dijitArrowButtonInner {
+ background-position: -16px;
+}
+.nihilo .dojoxFilePickerTextBoxError {
+ border-color:#b3b3b3;
+ background-color:#f9f7ba;
+ background-image:none;
+}
+.dj_ie6 .nihilo .dojoxFilePickerTextBoxError INPUT {
+ background-color:#f9f7ba !important;
+}
+
+.nihilo .dojoxFilePickerTextBoxErrorFocused {
+ background-color:#ff6;
+ background-image:none;
+}
+.dj_ie6 .nihilo .dojoxFilePickerTextBoxErrorFocused INPUT {
+ background-color:#ff6 !important;
+}
+
+/* soria theme */
+.soria .dojoxFilePickerTextBoxDisabled *
+{
+ cursor: not-allowed !important;
+}
+.soria .dojoxFilePickerTextBox{
+ margin: 0em 0.1em;
+}
+.soria .dojoxFilePickerTextBox {
+ background:#fff url("../../../dijit/themes/soria/images/validationInputBg.png") repeat-x top left;
+ #background:#fff url('../../../dijit/themes/soria/images/validationInputBg.gif') repeat-x top left;
+ border:1px solid #8ba0bd;
+ line-height: normal;
+}
+.soria .dojoxFilePickerTextBoxDisabled{
+ color: gray;
+}
+.dj_safari .soria .dojoxFilePickerTextBoxDisabled{
+ color: #eee;
+}
+.soria .dojoxFilePickerTextBox .dijitButtonNode {
+ padding: 0 0.2em;
+}
+.soria .dojoxFilePickerTextBox .dijitButtonNode{
+ border-color: #8ba0bd;
+ border-left: 1px solid #8ba0bd;
+}
+.soria .dojoxFilePickerTextBoxFocused {
+ border-color:#406b9b;
+}
+.soria .dojoxFilePickerTextBoxFocused .dijitButtonNode {
+ border-left-color:#8ba0bd;
+}
+.dijitRtl .soria .dojoxFilePickerTextBox .dijitButtonNode{
+ border-color: #8ba0bd;
+ border-left: 0px solid #8ba0bd;
+ border-right: 1px solid #8ba0bd;
+}
+.soria .dojoxFilePickerTextBox .dijitButtonNode {
+ border-width: 0px 0px 0px 1px;
+}
+.soria .dojoxFilePickerTextBoxDisabled{
+ border-color: #b9bbdd #b9bbdd #b9bbdd #b9bbdd;
+ background:#c3d3e5 url("../../../dijit/themes/soria/buttonDisabled.png") top repeat-x;
+ opacity: 0.60; /* Safari, Opera and Mozilla */
+}
+.soria .dojoxFilePickerTextBoxHover .dijitDownArrowButton{
+ color:#000;
+ background:#acc5e2 url("../../../dijit/themes/soria/images/buttonHover.png") repeat-x top left;
+}
+.soria .dojoxFilePickerTextBoxActive .dijitDownArrowButton {
+ border-color:#657c9c;
+ background: #91b4e5 url("../../../dijit/themes/soria/images/buttonActive.png") top left repeat-x;
+}
+.dijitRtl .soria .dojoxFilePickerTextBox .dijitButtonNode {
+ border-width: 0px 0px 0px 1px;
+}
+.soria .dojoxFilePickerTextBox .dijitArrowButton .dijitArrowButtonInner {
+ background:url("images/soriaFolderSprite.gif") no-repeat left center;
+ width: 16px;
+}
+.soria .dojoxFilePickerTextBox .dojoxHasDropDownOpen .dijitArrowButtonInner {
+ background-position: -16px;
+}
+.soria .dojoxFilePickerTextBoxError {
+ border-color:#f3d118;
+ background-color:#f9f7ba;
+ background-image:none;
+}
+.dj_ie6 .soria .dojoxFilePickerTextBoxError INPUT {
+ background-color:#f9f7ba !important;
+}
+
+.soria .dojoxFilePickerTextBoxErrorFocused {
+ background-color:#ff6;
+ background-image:none;
+}
+.dj_ie6 .soria .dojoxFilePickerTextBoxErrorFocused INPUT {
+ background-color:#ff6 !important;
+}
diff --git a/js/dojo/dojox/form/resources/FilePickerTextBox.html b/js/dojo/dojox/form/resources/FilePickerTextBox.html
new file mode 100644
index 0000000..207dbd4
--- /dev/null
+++ b/js/dojo/dojox/form/resources/FilePickerTextBox.html
@@ -0,0 +1,18 @@
+<div class="dijit dijitReset dijitInlineTable dijitLeft"
+ id="widget_${id}"
+ role="combobox" tabIndex="-1"
+ ><div style="overflow:hidden;"
+ ><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton'
+ dojoAttachPoint="downArrowNode,_buttonNode,_popupStateNode" role="presentation"
+ ><div class="dijitArrowButtonInner">&thinsp;</div
+ ><div class="dijitArrowButtonChar">&#9660;</div
+ ></div
+ ><div class="dijitReset dijitValidationIcon"><br></div
+ ><div class="dijitReset dijitValidationIconText">&Chi;</div
+ ><div class="dijitReset dijitInputField"
+ ><input type="text" autocomplete="off" ${!nameAttrSetting} class='dijitReset'
+ dojoAttachEvent='onkeypress:_onKey'
+ dojoAttachPoint='textbox,focusNode' role="textbox" aria-haspopup="true" aria-autocomplete="list"
+ /></div
+ ></div
+></div>
diff --git a/js/dojo/dojox/form/resources/FileUploader.css b/js/dojo/dojox/form/resources/FileUploader.css
new file mode 100644
index 0000000..2d268b4
--- /dev/null
+++ b/js/dojo/dojox/form/resources/FileUploader.css
@@ -0,0 +1,144 @@
+.dojoxUploaderNorm{
+ font-family:Myriad,Helvetica,Tahoma,Arial,clean,sans-serif;
+ font-size:12px;
+ border: 1px solid #c0c0c0;
+ border-bottom: 1px solid #9b9b9b;
+ padding: 0.1em 0.2em 0.2em 0.2em;
+ background: #fff url("../../../dijit/themes/tundra/images/buttonEnabled.png") repeat-x bottom left;
+
+ vertical-align: middle;
+
+ margin:0;
+ line-height:normal;
+ text-align:center;
+ white-space: nowrap;
+
+ cursor: pointer;
+}
+
+.uploaderInsideNode{
+ visibility:hidden;
+}
+.dojoxUploaderHover{
+ border-color: #a5beda;
+ border-bottom-color:#5c7590;
+ color:#243C5F;
+ background:#fcfdff url("../../../dijit/themes/tundra/images/buttonHover.png") repeat-x bottom;
+}
+.dojoxUploaderActive{
+ border-color:#366dba;
+ background: #ededed url("../../../dijit/themes/tundra/images/buttonActive.png") bottom repeat-x;
+}
+.dojoxUploaderDisabled{
+ color: #7F7F7F;
+ border-color: #d5d5d5 #d5d5d5 #bdbdbd #d5d5d5;
+ background:#e4e4e4 url("../../../dijit/themes/tundra/images/buttonDisabled.png") top repeat-x;
+}
+
+
+.soria .dojoxUploaderNorm {
+ border: 1px solid #8ba0bd;
+ border-bottom:1px solid #657c9c;
+ padding: 0.1em 0.2em 0.2em 0.2em;
+ background: #bcd5f0 url("../../../dijit/themes/soria/images/buttonEnabled.png") repeat-x top left;
+}
+.soria .dojoxUploaderHover{
+ color:#243C5F;
+ background:#acc5e2 url("../../../dijit/themes/soria/images/buttonHover.png") repeat-x top left !important;
+}
+.soria .dojoxUploaderActive{
+ border-color:#657c9c;
+ background: #91b4e5 url("../../../dijit/themes/soria/images/buttonActive.png") top left repeat-x !important;
+}
+.soria .dojoxUploaderDisabled{
+ border-color: #b9bbdd #b9bbdd #b9bbdd #b9bbdd;
+ background:#c3d3e5 url("../../../dijit/themes/soria/images/buttonDisabled.png") top repeat-x !important;
+ opacity: 0.60;
+}
+
+
+.nihilo .dojoxUploaderNorm {
+ border:1px solid #dedede;
+ border-bottom:1px solid #dedede;
+ padding: 0.1em 0.2em 0.2em 0.2em;
+ background: #fff url("../../../dijit/themes/nihilo/images/buttonEnabled.png") repeat-x top left;
+}
+.nihilo .dojoxUploaderHover{
+ color:#243C5F;
+ background:#fcfcfc url("../../../dijit/themes/nihilo/images/buttonHover.png") repeat-x top left !important;
+}
+.nihilo .dojoxUploaderActive{
+ border-color:#dedede;
+ background: #f5f5f5 url("../../../dijit/themes/nihilo/images/buttonActive.png") top left repeat-x !important;
+}
+.nihilo .dojoxUploaderDisabled{
+ border-color: #dedede;
+ background:#fafafa url("../../../dijit/themes/nihilo/images/buttonDisabled.png") top repeat-x !important;
+ opacity: 0.60;
+}
+
+.fileToUpload,
+.fileToUploadClose,
+.fileToUploadName,
+.fileToUploadSize{
+ height:18px;
+ line-height:18px;
+}
+
+.fileToUpload{
+ font-size:12px;
+ font-family:sans-serif;
+ padding:2px;
+ margin:0px;
+ width:100%;
+}
+.fileToUploadName{
+ text-align:left;
+ width:auto !important;
+}
+.fileToUploadSize{
+ width:30px !important;
+ text-align:right;
+}
+.dj_ie .fileToUploadSize{
+ padding-right:20px;
+}
+.fileToUploadClose{
+ background:url(../../../dijit/themes/tundra/images/tabClose.png) no-repeat 2px center;
+ width:18px !important;
+ cursor:pointer;
+}
+.fileToUploadClose:hover{
+ background:url(../../../dijit/themes/tundra/images/tabCloseHover.png) no-repeat 2px center;
+}
+
+
+.thumb{
+ height:50px;
+ padding:3px;
+ border:1px solid #ccc;
+ margin-bottom:3px;
+}
+.thumbPic{
+ width:50px;
+ height:50px;
+ text-align:center;
+ line-height:50px;
+ background-color:#000;
+ float:left;
+}
+.thumbPic img{
+ line-height:50px;
+ margin:auto auto;
+ display:block;
+}
+.thumbText{
+ float:left;
+ margin-left:5px;
+ font-size:10px;
+}
+.dj_ie object{
+ /* When clicking on the object inspector in Firebug Lite, IE
+ sets display:none on (flash) objects. Amazing!! */
+ display:block !important;
+} \ No newline at end of file
diff --git a/js/dojo/dojox/form/resources/HorizontalRangeSlider.html b/js/dojo/dojox/form/resources/HorizontalRangeSlider.html
new file mode 100644
index 0000000..6aafba0
--- /dev/null
+++ b/js/dojo/dojox/form/resources/HorizontalRangeSlider.html
@@ -0,0 +1,39 @@
+<table class="dijit dijitReset dijitSlider dijitSliderH dojoxRangeSlider" cellspacing="0" cellpadding="0" border="0" rules="none" dojoAttachEvent="onkeypress:_onKeyPress,onkeyup:_onKeyUp"
+ ><tr class="dijitReset"
+ ><td class="dijitReset" colspan="2"></td
+ ><td dojoAttachPoint="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" tabIndex="-1" style="display:none" dojoAttachPoint="decrementButton"><span class="dijitSliderButtonInner">-</span></div
+ ></td
+ ><td class="dijitReset"
+ ><div class="dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderLeftBumper" dojoAttachEvent="onmousedown:_onClkDecBumper"></div
+ ></td
+ ><td class="dijitReset"
+ ><input dojoAttachPoint="valueNode" type="hidden" ${!nameAttrSetting}
+ /><div role="presentation" class="dojoxRangeSliderBarContainer" dojoAttachPoint="sliderBarContainer"
+ ><div dojoAttachPoint="sliderHandle" tabIndex="${tabIndex}" class="dijitSliderMoveable dijitSliderMoveableH" dojoAttachEvent="onmousedown:_onHandleClick" role="slider" valuemin="${minimum}" valuemax="${maximum}"
+ ><div class="dijitSliderImageHandle dijitSliderImageHandleH"></div
+ ></div
+ ><div role="presentation" dojoAttachPoint="progressBar,focusNode" class="dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH" dojoAttachEvent="onmousedown:_onBarClick"></div
+ ><div dojoAttachPoint="sliderHandleMax,focusNodeMax" tabIndex="${tabIndex}" class="dijitSliderMoveable dijitSliderMoveableH" dojoAttachEvent="onmousedown:_onHandleClickMax" role="sliderMax" valuemin="${minimum}" valuemax="${maximum}"
+ ><div class="dijitSliderImageHandle dijitSliderImageHandleH"></div
+ ></div
+ ><div role="presentation" dojoAttachPoint="remainingBar" class="dijitSliderBar dijitSliderBarH dijitSliderRemainingBar dijitSliderRemainingBarH" dojoAttachEvent="onmousedown:_onRemainingBarClick"></div
+ ></div
+ ></td
+ ><td class="dijitReset"
+ ><div class="dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderRightBumper" dojoAttachEvent="onmousedown:_onClkIncBumper"></div
+ ></td
+ ><td class="dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH"
+ ><div class="dijitSliderIncrementIconH" tabIndex="-1" style="display:none" dojoAttachPoint="incrementButton"><span class="dijitSliderButtonInner">+</span></div
+ ></td
+ ></tr
+ ><tr class="dijitReset"
+ ><td class="dijitReset" colspan="2"></td
+ ><td dojoAttachPoint="containerNode,bottomDecoration" class="dijitReset dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH"></td
+ ><td class="dijitReset" colspan="2"></td
+ ></tr
+></table>
diff --git a/js/dojo/dojox/form/resources/ListInput.css b/js/dojo/dojox/form/resources/ListInput.css
new file mode 100644
index 0000000..5f4a83b
--- /dev/null
+++ b/js/dojo/dojox/form/resources/ListInput.css
@@ -0,0 +1,76 @@
+.dojoxListInput {
+ border:1px solid #ccc;
+ background-color:#efefef;
+ height:auto !important;
+ max-height:60px;
+ min-height:20px;
+ overflow:auto;
+ position:relative
+}
+.dojoxListInput ul {
+ margin:0;
+ padding:0
+}
+.dijitDialogCloseIcon {
+ display:none;
+}
+.dojoxListInputClosable .dijitDialogCloseIcon{
+ display:inline
+}
+.dojoxListInputClosable {
+ padding-right:18px !important
+}
+.dojoxListInputItem {
+ float:left;
+ list-style-type:none;
+ margin:1px 5px 1px 1px;
+ padding:0
+}
+.dojoxListInputItem .closeText {
+ display:none;
+ position:absolute;
+}
+.dojoxListInputItem .dijitDialogCloseIcon{
+ right:auto !important;
+ border:0 !important;
+ padding:0!important;
+}
+.dojoxListInputMatch {
+ border :1px solid #5EB55E;
+ background-color:#efffef
+}
+.dojoxListInputMismatch {
+ border :1px solid #B55E5E;
+ background-color:#ffefef
+}
+.dojoxListInput.dojoxListInputFocused {
+ border:1px solid #000;
+ border-right:1px solid #ccc;
+ border-bottom:1px solid #ccc;
+ background-color:#fff
+}
+.dojoxListInputNode {
+ cursor:text;
+}
+.dojoxListInput .dijitTextBox {
+ background:#efefef !important;
+
+ border:0 !important;
+}
+.dojoxListInputFocused .dijitTextBox {
+ background: #fff !important;
+ border:0 !important;
+}
+.dojoxListInputItem .dijitTextBox {
+ width:auto !important;
+ border:0 !important;
+}
+.dojoxListInputNode {
+ float:none;
+}
+.dojoxListInputItemEdited{
+ display:none !important
+}
+.dojoxListInputItem .dijitInline{
+ display:inline !important
+}
diff --git a/js/dojo/dojox/form/resources/PasswordValidator.html b/js/dojo/dojox/form/resources/PasswordValidator.html
new file mode 100644
index 0000000..80a55ae
--- /dev/null
+++ b/js/dojo/dojox/form/resources/PasswordValidator.html
@@ -0,0 +1,3 @@
+<div dojoAttachPoint="containerNode">
+ <input type="hidden" name="${name}" value="" dojoAttachPoint="focusNode" />
+</div> \ No newline at end of file
diff --git a/js/dojo/dojox/form/resources/RangeSlider.css b/js/dojo/dojox/form/resources/RangeSlider.css
new file mode 100644
index 0000000..5914467
--- /dev/null
+++ b/js/dojo/dojox/form/resources/RangeSlider.css
@@ -0,0 +1,30 @@
+.dojoxRangeSlider .dijitSliderLeftBumper, .dojoxRangeSlider .dijitSliderBottomBumper {
+ background:#FFFFFF !important;
+}
+
+.dojoxRangeSliderBarContainer {
+ position:relative;
+}
+
+.dojoxRangeSlider .dijitSliderProgressBarV {
+ position:relative !important;
+}
+
+.dojoxRangeSlider .dijitSliderProgressBar {
+ overflow:hidden;
+ cursor:pointer;
+ /* background:yellow !important; */
+}
+
+.dojoxRangeSlider .dijitSliderProgressBarV {
+ position:absolute !important;
+ border-width: 0px;
+}
+
+.dojoxRangeSlider .dijitSliderImageHandleH {
+ left: -50%;
+}
+.dijitSlider .dojoxRangeSliderBarContainer .dijitSliderProgressBarH,
+.dojoxRangeSlider .dijitSliderMoveableH {
+ right:auto !important;
+}
diff --git a/js/dojo/dojox/form/resources/Rating.css b/js/dojo/dojox/form/resources/Rating.css
new file mode 100644
index 0000000..1f2054f
--- /dev/null
+++ b/js/dojo/dojox/form/resources/Rating.css
@@ -0,0 +1,24 @@
+.dojoxRating ul {
+ padding:0;
+ margin:0;
+}
+
+.dojoxRatingStar {
+ display:inline-block;
+ background-image:url(images/rating_empty.gif);
+ background-position:left center;
+ position:relative;
+ height:15px;
+ width:15px;
+ float:left;
+}
+
+.dojoxRatingStarChecked {
+ background-image:url(images/rating_full.gif);
+}
+
+.dojoxRatingStarHover {
+ background-image:url(images/rating_full.gif);
+ opacity:.5;
+}
+
diff --git a/js/dojo/dojox/form/resources/RecieveFile.php b/js/dojo/dojox/form/resources/RecieveFile.php
new file mode 100644
index 0000000..aca541f
--- /dev/null
+++ b/js/dojo/dojox/form/resources/RecieveFile.php
@@ -0,0 +1,37 @@
+<?php
+
+// THIS IS AN EXAMPLE
+// you will obviously need to do more server side work than I am doing here to check and move your upload.
+// API is up for discussion, jump on http://dojotoolkit.org/forums
+
+// JSON.php is available in dojo svn checkout
+require("../../../dojo/tests/resources/JSON.php");
+$json = new Services_JSON();
+
+// fake delay
+sleep(3);
+$name = empty($_REQUEST['name'])? "default" : $_REQUEST['name'];
+if(is_array($_FILES)){
+ $ar = array(
+ // lets just pass lots of stuff back and see what we find.
+ // the _FILES aren't coming through in IE6 (maybe 7)
+ 'status' => "success",
+ 'name' => $name,
+ 'request' => $_REQUEST,
+ 'postvars' => $_POST,
+ 'details' => $_FILES,
+ // and some static subarray just to see
+ 'foo' => array('foo'=>"bar")
+ );
+
+}else{
+ $ar = array(
+ 'status' => "failed",
+ 'details' => ""
+ );
+}
+
+// yeah, seems you have to wrap iframeIO stuff in textareas?
+$foo = $json->encode($ar);
+?>
+<textarea><?php print $foo; ?></textarea>
diff --git a/js/dojo/dojox/form/resources/TriStateCheckBox.css b/js/dojo/dojox/form/resources/TriStateCheckBox.css
new file mode 100644
index 0000000..237f4bf
--- /dev/null
+++ b/js/dojo/dojox/form/resources/TriStateCheckBox.css
@@ -0,0 +1,137 @@
+/* TriStateCheckBox
+ *
+ * Styling TriStateCheckBox mainly includes:
+ *
+ * 1. Containers
+ * .dojoxTriStateCheckBox|.dojoxTriStateCheckBoxIcon - for border, padding, width|height and background image
+ *
+ * 2. Checked state
+ * .dojoxTriStateCheckBoxChecked - for checked background-color|image
+ * .dojoxTriStateCheckBoxMixed - for mixed background-color|image
+ *
+ * 3. Hover state
+ * .dojoxTriStateCheckBoxHover|.dojoxTriStateCheckBoxCheckedHover|.dojoxTriStateCheckBoxMixedHover - for background image
+ *
+ * 4. Disabled state
+ * .dojoxTriStateCheckBoxDisabled|.dojoxTriStateCheckBoxCheckedDisabled|.dojoxTriStateCheckBoxMixedDisabled - for background image
+ */
+.claro .dijitToggleButton .dojoxTriStateCheckBoxIcon {
+ background-image: url('../images/checkmarkNoBorder.png');
+}
+.dj_ie6 .claro .dijitToggleButton .dojoxTriStateCheckBoxIcon {
+ background-image: url('../images/checkmarkNoBorder.gif');
+}
+.claro .dojoxTriStateCheckBox, .claro .dojoxTriStateCheckBoxIcon {
+ background-image: url('images/tristatecheckboxStates.png');
+ /* checkbox sprite image */
+
+ background-repeat: no-repeat;
+ width: 15px;
+ height: 16px;
+ margin: 0 2px 0 0;
+ padding: 0;
+}
+.dj_ie6 .claro .dojoxTriStateCheckBox, .dj_ie6 .claro .dojoxTriStateCheckBoxIcon {
+ background-image: url('images/tristatecheckboxStates.png');
+ /* checkbox sprite image */
+
+}
+.claro .dojoxTriStateCheckBox{
+ /* unchecked */
+
+ background-position: -15px;
+}
+.claro .dojoxTriStateCheckBoxChecked{
+ /* checked */
+
+ background-position: 0px;
+}
+.claro .dojoxTriStateCheckBoxMixed {
+ /* mixed */
+
+ background-position: -30px;
+}
+.claro .dojoxTriStateCheckBoxDisabled {
+ /* disabled and unchecked */
+
+ background-position: -105px;
+}
+.claro .dojoxTriStateCheckBoxCheckedDisabled {
+ /* disabled and checked */
+
+ background-position: -90px;
+}
+.claro .dojoxTriStateCheckBoxMixedDisabled {
+ /* disabled and mixed */
+
+ background-position: -120px;
+}
+.claro .dojoxTriStateCheckBoxHover {
+ /* hovering over and unchecked */
+
+ background-position: -60px;
+}
+.claro .dojoxTriStateCheckBoxCheckedHover {
+ /* hovering over and checked */
+
+ background-position: -45px;
+}
+.claro .dojoxTriStateCheckBoxMixedHover {
+ /* hovering over and mixed */
+
+ background-position: -75px;
+}
+
+.dijit_a11y .dojoxTriStateCheckBoxHover .dojoxTriStateCheckBoxInner,
+.dijit_a11y .dojoxTriStateCheckBoxFocused .dojoxTriStateCheckBoxInner{
+ /* focused or hovering over */
+ border: dashed;
+}
+
+.dijit_a11y .dojoxTriStateCheckBoxHover .dojoxTriStateCheckBoxInner,
+.dijit_a11y .dojoxTriStateCheckBoxFocused .dojoxTriStateCheckBoxInner{
+ /* focused or hovering over */
+ border: solid;
+}
+
+.dijit_a11y .dojoxTriStateCheckBoxDisabled .dojoxTriStateCheckBoxInner{
+ /* focused or hovering over */
+ opacity: 0.5;
+}
+
+.dj_ie .dijit_a11y .dojoxTriStateCheckBoxDisabled .dojoxTriStateCheckBoxInner{
+ /* disabled */
+}
+
+
+.dojoxTriStateCheckBoxInner{
+ /* inner text */
+
+ visibility: hidden;
+ display: none;
+ position: absolute;
+ text-align: center;
+}
+
+.dijit_a11y .dojoxTriStateCheckBoxInner{
+ /* inner text */
+
+ visibility: visible;
+ display: block;
+}
+
+.dojoxTriStateCheckBoxInput {
+ /* place the actual input on top, but all-but-invisible */
+ opacity: 0.01;
+ padding: 0;
+ margin: 0,
+ border: 0;
+ width: 15px;
+ height: 16px;
+ background-position:center center;
+ background-repeat:no-repeat;
+}
+
+.dj_ie .dojoxTriStateCheckBoxInput {
+ filter: alpha(opacity=0);
+}
diff --git a/js/dojo/dojox/form/resources/TriStateCheckBox.html b/js/dojo/dojox/form/resources/TriStateCheckBox.html
new file mode 100644
index 0000000..5605128
--- /dev/null
+++ b/js/dojo/dojox/form/resources/TriStateCheckBox.html
@@ -0,0 +1,5 @@
+<div class="dijit dijitReset dijitInline" role="presentation"
+ ><div class="dojoxTriStateCheckBoxInner" dojoAttachPoint="stateLabelNode"></div
+ ><input ${!nameAttrSetting} type="${type}" dojoAttachPoint="focusNode"
+ class="dijitReset dojoxTriStateCheckBoxInput" dojoAttachEvent="onclick:_onClick"
+/></div> \ No newline at end of file
diff --git a/js/dojo/dojox/form/resources/Uploader.html b/js/dojo/dojox/form/resources/Uploader.html
new file mode 100644
index 0000000..449b2a1
--- /dev/null
+++ b/js/dojo/dojox/form/resources/Uploader.html
@@ -0,0 +1,18 @@
+<span class="dijit dijitReset dijitInline"
+ ><span class="dijitReset dijitInline dijitButtonNode"
+ dojoAttachEvent="ondijitclick:_onClick"
+ ><span class="dijitReset dijitStretch dijitButtonContents"
+ dojoAttachPoint="titleNode,focusNode"
+ role="button" aria-labelledby="${id}_label"
+ ><span class="dijitReset dijitInline dijitIcon" dojoAttachPoint="iconNode"></span
+ ><span class="dijitReset dijitToggleButtonIconChar">&#x25CF;</span
+ ><span class="dijitReset dijitInline dijitButtonText"
+ id="${id}_label"
+ dojoAttachPoint="containerNode"
+ ></span
+ ></span
+ ></span
+ ><!--no need to have this for Uploader
+ <input ${!nameAttrSetting} type="${type}" value="${value}" class="dijitOffScreen" tabIndex="-1"
+ dojoAttachPoint="valueNode"
+/--></span>
diff --git a/js/dojo/dojox/form/resources/UploaderFileList.css b/js/dojo/dojox/form/resources/UploaderFileList.css
new file mode 100644
index 0000000..b2a9c98
--- /dev/null
+++ b/js/dojo/dojox/form/resources/UploaderFileList.css
@@ -0,0 +1,53 @@
+.dojoxUploaderFileList{
+ border:1px solid #ccc;
+ min-height:50px;
+}
+.dojoxUploaderFileListTable{
+ width:100%;
+ border-collapse:collapse;
+ margin-top:5px;
+}
+.dojoxUploaderFileListHeader th{
+ background-color:#eee;
+ padding:3px;
+}
+.dojoxUploaderFileListRow{
+
+}
+.dojoxUploaderIndex{
+ width:20px;
+}
+.dojoxUploaderIcon{
+ width:50px;
+}
+.dojoxUploaderFileName{
+
+}
+.dojoxUploaderSize{
+ width:70px;
+}
+.dojoxUploaderFileListContent{
+ width:100%;
+}
+.dojoxUploaderFileListProgress{
+ border:1px solid #666;
+ height:15px;
+ position:relative;
+ background:#fff;
+ overflow:hidden;
+}
+.dojoxUploaderFileListPercentText{
+ position:absolute;
+ right:3px;
+ top:3px;
+ font-size:10px;
+ text-align:right;
+}
+.dojoxUploaderFileListProgressBar{
+ position:absolute;
+ top:0px;
+ left:0px;
+ height:15px;
+ width:0%;
+ background:#bfe1fd;
+}
diff --git a/js/dojo/dojox/form/resources/VerticalRangeSlider.html b/js/dojo/dojox/form/resources/VerticalRangeSlider.html
new file mode 100644
index 0000000..55b0d22
--- /dev/null
+++ b/js/dojo/dojox/form/resources/VerticalRangeSlider.html
@@ -0,0 +1,49 @@
+<table class="dijitReset dijitSlider dijitSliderV dojoxRangeSlider" cellspacing="0" cellpadding="0" border="0" rules="none"
+ ><tr class="dijitReset"
+ ><td class="dijitReset"></td
+ ><td class="dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV"
+ ><div class="dijitSliderIncrementIconV" tabIndex="-1" style="display:none" dojoAttachPoint="decrementButton" dojoAttachEvent="onclick: increment"><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" dojoAttachEvent="onclick:_onClkIncBumper"></div></center
+ ></td
+ ><td class="dijitReset"></td
+ ></tr
+ ><tr class="dijitReset"
+ ><td dojoAttachPoint="leftDecoration" class="dijitReset dijitSliderDecoration dijitSliderDecorationL dijitSliderDecorationV" style="text-align:center;height:100%;"></td
+ ><td class="dijitReset" style="height:100%;"
+ ><input dojoAttachPoint="valueNode" type="hidden" ${!nameAttrSetting}
+ /><center role="presentation" style="position:relative;height:100%;" dojoAttachPoint="sliderBarContainer"
+ ><div role="presentation" dojoAttachPoint="remainingBar" class="dijitSliderBar dijitSliderBarV dijitSliderRemainingBar dijitSliderRemainingBarV" dojoAttachEvent="onmousedown:_onRemainingBarClick"
+ ><div dojoAttachPoint="sliderHandle" tabIndex="${tabIndex}" class="dijitSliderMoveable dijitSliderMoveableV" dojoAttachEvent="onkeypress:_onKeyPress,onmousedown:_onHandleClick" style="vertical-align:top;" role="slider" valuemin="${minimum}" valuemax="${maximum}"
+ ><div class="dijitSliderImageHandle dijitSliderImageHandleV"></div
+ ></div
+ ><div role="presentation" dojoAttachPoint="progressBar,focusNode" tabIndex="${tabIndex}" class="dijitSliderBar dijitSliderBarV dijitSliderProgressBar dijitSliderProgressBarV" dojoAttachEvent="onkeypress:_onKeyPress,onmousedown:_onBarClick"
+ ></div
+ ><div dojoAttachPoint="sliderHandleMax,focusNodeMax" tabIndex="${tabIndex}" class="dijitSliderMoveable dijitSliderMoveableV" dojoAttachEvent="onkeypress:_onKeyPress,onmousedown:_onHandleClickMax" style="vertical-align:top;" role="slider" valuemin="${minimum}" valuemax="${maximum}"
+ ><div class="dijitSliderImageHandle dijitSliderImageHandleV"></div
+ ></div
+ ></div
+ ></center
+ ></td
+ ><td dojoAttachPoint="containerNode,rightDecoration" class="dijitReset dijitSliderDecoration dijitSliderDecorationR dijitSliderDecorationV" style="text-align:center;height:100%;"></td
+ ></tr
+ ><tr class="dijitReset"
+ ><td class="dijitReset"></td
+ ><td class="dijitReset"
+ ><center><div class="dijitSliderBar dijitSliderBumper dijitSliderBumperV dijitSliderBottomBumper" dojoAttachEvent="onclick:_onClkDecBumper"></div></center
+ ></td
+ ><td class="dijitReset"></td
+ ></tr
+ ><tr class="dijitReset"
+ ><td class="dijitReset"></td
+ ><td class="dijitReset dijitSliderButtonContainer dijitSliderButtonContainerV"
+ ><div class="dijitSliderDecrementIconV" tabIndex="-1" style="display:none" dojoAttachPoint="incrementButton" dojoAttachEvent="onclick: decrement"><span class="dijitSliderButtonInner">-</span></div
+ ></td
+ ><td class="dijitReset"></td
+ ></tr
+></table>
diff --git a/js/dojo/dojox/form/resources/_CheckedMultiSelectItem.html b/js/dojo/dojox/form/resources/_CheckedMultiSelectItem.html
new file mode 100644
index 0000000..709b450
--- /dev/null
+++ b/js/dojo/dojox/form/resources/_CheckedMultiSelectItem.html
@@ -0,0 +1,5 @@
+<div class="dijitReset ${baseClass}"
+ ><input class="${baseClass}Box" data-dojo-type="dijit.form.CheckBox" data-dojo-attach-point="checkBox"
+ data-dojo-attach-event="_onClick:_changeBox" type="${_type.type}" baseClass="${_type.baseClass}"
+ /><div class="dijitInline ${baseClass}Label" data-dojo-attach-point="labelNode" data-dojo-attach-event="onclick:_onClick"></div
+></div>
diff --git a/js/dojo/dojox/form/resources/_CheckedMultiSelectMenuItem.html b/js/dojo/dojox/form/resources/_CheckedMultiSelectMenuItem.html
new file mode 100644
index 0000000..23a5064
--- /dev/null
+++ b/js/dojo/dojox/form/resources/_CheckedMultiSelectMenuItem.html
@@ -0,0 +1,10 @@
+<tr class="dijitReset dijitMenuItem" dojoAttachPoint="focusNode" role="menuitemcheckbox" tabIndex="-1"
+ dojoAttachEvent="onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick"
+ ><td class="dijitReset dijitMenuItemIconCell" role="presentation"
+ ><div src="${_blankGif}" alt="" class="dijitMenuItemIcon ${_iconClass}" dojoAttachPoint="iconNode"
+ ><input class="dojoxCheckedMultiSelectCheckBoxInput" dojoAttachPoint="inputNode" type="${_type.type}"
+ /></div></td
+ ><td class="dijitReset dijitMenuItemLabel" colspan="2" dojoAttachPoint="containerNode,labelNode"></td
+ ><td class="dijitReset dijitMenuItemAccelKey" style="display: none" dojoAttachPoint="accelKeyNode"></td
+ ><td class="dijitReset dijitMenuArrowCell" role="presentation">&nbsp;</td
+></tr> \ No newline at end of file
diff --git a/js/dojo/dojox/form/resources/fileuploader.swf b/js/dojo/dojox/form/resources/fileuploader.swf
new file mode 100644
index 0000000..f774e17
--- /dev/null
+++ b/js/dojo/dojox/form/resources/fileuploader.swf
Binary files differ
diff --git a/js/dojo/dojox/form/resources/images/loading_wheel.gif b/js/dojo/dojox/form/resources/images/loading_wheel.gif
new file mode 100644
index 0000000..901a7e3
--- /dev/null
+++ b/js/dojo/dojox/form/resources/images/loading_wheel.gif
Binary files differ
diff --git a/js/dojo/dojox/form/resources/images/nihiloFolderSprite.gif b/js/dojo/dojox/form/resources/images/nihiloFolderSprite.gif
new file mode 100644
index 0000000..0034b54
--- /dev/null
+++ b/js/dojo/dojox/form/resources/images/nihiloFolderSprite.gif
Binary files differ
diff --git a/js/dojo/dojox/form/resources/images/rating_empty.gif b/js/dojo/dojox/form/resources/images/rating_empty.gif
new file mode 100644
index 0000000..8662c43
--- /dev/null
+++ b/js/dojo/dojox/form/resources/images/rating_empty.gif
Binary files differ
diff --git a/js/dojo/dojox/form/resources/images/rating_full.gif b/js/dojo/dojox/form/resources/images/rating_full.gif
new file mode 100644
index 0000000..6fe24bf
--- /dev/null
+++ b/js/dojo/dojox/form/resources/images/rating_full.gif
Binary files differ
diff --git a/js/dojo/dojox/form/resources/images/soriaFolderSprite.gif b/js/dojo/dojox/form/resources/images/soriaFolderSprite.gif
new file mode 100644
index 0000000..19e35c1
--- /dev/null
+++ b/js/dojo/dojox/form/resources/images/soriaFolderSprite.gif
Binary files differ
diff --git a/js/dojo/dojox/form/resources/images/tristatecheckboxStates.png b/js/dojo/dojox/form/resources/images/tristatecheckboxStates.png
new file mode 100644
index 0000000..dde030f
--- /dev/null
+++ b/js/dojo/dojox/form/resources/images/tristatecheckboxStates.png
Binary files differ
diff --git a/js/dojo/dojox/form/resources/images/tundraFolderSprite.gif b/js/dojo/dojox/form/resources/images/tundraFolderSprite.gif
new file mode 100644
index 0000000..6cf8c09
--- /dev/null
+++ b/js/dojo/dojox/form/resources/images/tundraFolderSprite.gif
Binary files differ
diff --git a/js/dojo/dojox/form/resources/uploader.swf b/js/dojo/dojox/form/resources/uploader.swf
new file mode 100644
index 0000000..78233e4
--- /dev/null
+++ b/js/dojo/dojox/form/resources/uploader.swf
Binary files differ
diff --git a/js/dojo/dojox/form/uploader/Base.js b/js/dojo/dojox/form/uploader/Base.js
new file mode 100644
index 0000000..4587c76
--- /dev/null
+++ b/js/dojo/dojox/form/uploader/Base.js
@@ -0,0 +1,126 @@
+//>>built
+define("dojox/form/uploader/Base", [
+ "dojo/dom-form",
+ "dojo/dom-style",
+ "dojo/dom-construct",
+ "dojo/dom-attr",
+ "dojo/has",
+ "dojo/_base/declare",
+ "dojo/_base/event",
+ "dijit/_Widget",
+ "dijit/_TemplatedMixin",
+ "dijit/_WidgetsInTemplateMixin"
+],function(domForm, domStyle, domConstruct, domAttr, has, declare, event, Widget, TemplatedMixin, WidgetsInTemplateMixin){
+
+has.add('FormData', function(){return !!window.FormData;});
+has.add("xhr-sendAsBinary", function(){var xhr=window.XMLHttpRequest && new window.XMLHttpRequest(); return xhr && !!xhr.sendAsBinary;});
+has.add("file-multiple", function(){return !!({'true':1,'false':1}[domAttr.get(document.createElement('input',{type:"file"}), 'multiple')]);});
+
+ /*=====
+ Widget = dijit._Widget;
+ TemplatedMixin = dijit._TemplatedMixin;
+ WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
+ =====*/
+return declare("dojox.form.uploader.Base", [Widget, TemplatedMixin, WidgetsInTemplateMixin], {
+ //
+ // Version: 1.6
+ //
+ // summary:
+ // The Base class used for dojox.form.Uploader and dojox.form.uploader.FileList.
+ //
+ // description:
+ // Should not be used as a standalone. To be mixed in with other classes.
+ //
+
+ getForm: function(){
+ // summary:
+ // Finds the parent form of the Uploader, if it exists.
+ //
+ if(!this.form){
+ var n = this.domNode;
+ while(n && n.tagName && n !== document.body){
+ if(n.tagName.toLowerCase() == "form"){
+ this.form = n;
+ break;
+ }
+ n = n.parentNode;
+ }
+ }
+ return this.form // Node;
+ },
+
+ getUrl: function(){
+ // summary:
+ // Finds the URL to upload to, whether it be the action in the parent form, this.url or
+ // this.uploadUrl
+ //
+ if(this.uploadUrl) this.url = this.uploadUrl;
+ if(this.url) return this.url;
+ if(this.getForm()) this.url = this.form.action;
+ return this.url; // String
+ },
+
+
+ connectForm: function(){
+ // summary:
+ // Internal. Connects to form if there is one.
+ //
+ this.url = this.getUrl();
+ if(!this._fcon && !!this.getForm()){
+ this._fcon = true;
+ this.connect(this.form, "onsubmit", function(evt){
+ event.stop(evt);
+ this.submit(this.form);
+ });
+ }
+ },
+
+ supports: function(what){
+ // summary:
+ // Does feature testing for uploader capabilities. (No browser sniffing - yay)
+ //
+ switch(what){
+ case "multiple":
+ if(this.force == "flash" || this.force == "iframe") return false;
+ return has("file-multiple");
+ case "FormData":
+ return has(what);
+ case "sendAsBinary":
+ return has("xhr-sendAsBinary");
+ }
+ return false; // Boolean
+ },
+ getMimeType: function(){
+ // summary:
+ // Returns the mime type that should be used in an HTML5 upload form. Return result
+ // may change as the current use is very generic.
+ //
+ return "application/octet-stream"; //image/gif
+ },
+ getFileType: function(/* String */name){
+ // summary:
+ // Gets the extension of a file
+ return name.substring(name.lastIndexOf(".")+1).toUpperCase(); // String
+ },
+ convertBytes: function(bytes){
+ // summary:
+ // Converts bytes. Returns an object with all conversions. The "value" property is
+ // considered the most likely desired result.
+ //
+ var kb = Math.round(bytes/1024*100000)/100000;
+ var mb = Math.round(bytes/1048576*100000)/100000;
+ var gb = Math.round(bytes/1073741824*100000)/100000;
+ var value = bytes;
+ if(kb>1) value = kb.toFixed(1)+" kb";
+ if(mb>1) value = mb.toFixed(1)+" mb";
+ if(gb>1) value = gb.toFixed(1)+" gb";
+ return {
+ kb:kb,
+ mb:mb,
+ gb:gb,
+ bytes:bytes,
+ value: value
+ }; // Object
+ }
+});
+});
diff --git a/js/dojo/dojox/form/uploader/FileList.js b/js/dojo/dojox/form/uploader/FileList.js
new file mode 100644
index 0000000..ed17c33
--- /dev/null
+++ b/js/dojo/dojox/form/uploader/FileList.js
@@ -0,0 +1,202 @@
+//>>built
+define("dojox/form/uploader/FileList", [
+ "dojo/_base/fx",
+ "dojo/dom-style",
+ "dojo/dom-class",
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dijit/_base/manager",
+ "dojox/form/uploader/Base"
+],function(fx, domStyle, domClass, declare, lang, array, manager, formUploaderBase){
+
+ /*=====
+ formUploaderBase = dojox.form.uploader.Base;
+ =====*/
+return declare("dojox.form.uploader.FileList", [formUploaderBase], {
+ //
+ // Version: 1.6
+ //
+ // summary:
+ // A simple widget that provides a list of the files currently selected by
+ // dojox.form.Uploader
+ //
+ // description:
+ // There is a required CSS file: resources/UploaderFileList.css.
+ // This is a very simple widget, and not beautifully styled. It is here mainly for test
+ // cases, but could very easily be used, extended, modified, or copied.
+ //
+ // uploaderId: String
+ // The id of the dojox.form.Uploader to connect to.
+ uploaderId:"",
+ // uploader: dojox.form.Uploader
+ // The dojox.form.Uploader to connect to. Use either this property of unploaderId. This
+ // property is populated if uploaderId is used.
+ //
+ uploader:null,
+ // headerIndex: String
+ // The label for the index column.
+ //
+ headerIndex:"#",
+ // headerType: String
+ // The label for the file type column.
+ //
+ headerType:"Type",
+ // headerFilename: String
+ // The label for the file name column.
+ //
+ headerFilename:"File Name",
+ // headerFilesize: String
+ // The label for the file size column.
+ //
+ headerFilesize:"Size",
+
+ _upCheckCnt:0,
+ rowAmt:0,
+
+ templateString: '<div class="dojoxUploaderFileList">' +
+ '<div dojoAttachPoint="progressNode" class="dojoxUploaderFileListProgress"><div dojoAttachPoint="percentBarNode" class="dojoxUploaderFileListProgressBar"></div><div dojoAttachPoint="percentTextNode" class="dojoxUploaderFileListPercentText">0%</div></div>' +
+ '<table class="dojoxUploaderFileListTable">'+
+ '<thead><tr class="dojoxUploaderFileListHeader"><th class="dojoxUploaderIndex">${headerIndex}</th><th class="dojoxUploaderIcon">${headerType}</th><th class="dojoxUploaderFileName">${headerFilename}</th><th class="dojoxUploaderFileSize" dojoAttachPoint="sizeHeader">${headerFilesize}</th></tr></thead>'+
+ '<tbody class="dojoxUploaderFileListContent" dojoAttachPoint="listNode">'+
+ '</tbody>'+
+ '</table>'+
+ '<div>'
+ ,
+
+ postCreate: function(){
+ this.setUploader();
+ this.hideProgress();
+ },
+
+ reset: function(){
+ // summary:
+ // Clears all rows of items. Happens automatically if Uploader is reset, but you
+ // could call this directly.
+ //
+ for(var i=0;i<this.rowAmt;i++){
+ this.listNode.deleteRow(0);
+ }
+ this.rowAmt = 0;
+ },
+
+ setUploader: function(){
+ // summary:
+ // Connects to the Uploader based on the uploader or the uploaderId properties.
+ //
+ if(!this.uploaderId && !this.uploader){
+ console.warn("uploaderId not passed to UploaderFileList");
+ }else if(this.uploaderId && !this.uploader){
+ this.uploader = manager.byId(this.uploaderId);
+ }else if(this._upCheckCnt>4){
+ console.warn("uploader not found for ID ", this.uploaderId);
+ return;
+ }
+ if(this.uploader){
+ this.connect(this.uploader, "onChange", "_onUploaderChange");
+ this.connect(this.uploader, "reset", "reset");
+ this.connect(this.uploader, "onBegin", function(){
+ this.showProgress(true);
+ });
+ this.connect(this.uploader, "onProgress", "_progress");
+ this.connect(this.uploader, "onComplete", function(){
+ setTimeout(lang.hitch(this, function(){
+ this.hideProgress(true);
+ }), 1250);
+ });
+ if(!(this._fileSizeAvail = {'html5':1,'flash':1}[this.uploader.uploadType])){
+ //if uploadType is neither html5 nor flash, file size is not available
+ //hide the size header
+ this.sizeHeader.style.display="none";
+ }
+ }else{
+ this._upCheckCnt++;
+ setTimeout(lang.hitch(this, "setUploader"), 250);
+ }
+ },
+
+ hideProgress: function(/* Boolean */animate){
+ var o = animate ? {
+ ani:true,
+ endDisp:"none",
+ beg:15,
+ end:0
+ } : {
+ endDisp:"none",
+ ani:false
+ };
+ this._hideShowProgress(o);
+ },
+
+ showProgress: function(/* Boolean */animate){
+ var o = animate ? {
+ ani:true,
+ endDisp:"block",
+ beg:0,
+ end:15
+ } : {
+ endDisp:"block",
+ ani:false
+ };
+ this._hideShowProgress(o);
+ },
+
+ _progress: function(/* Object */ customEvent){
+ this.percentTextNode.innerHTML = customEvent.percent;
+ domStyle.set(this.percentBarNode, "width", customEvent.percent);
+ },
+
+ _hideShowProgress: function(o){
+ var node = this.progressNode;
+ var onEnd = function(){
+ domStyle.set(node, "display", o.endDisp);
+ }
+ if(o.ani){
+ domStyle.set(node, "display", "block");
+ fx.animateProperty({
+ node: node,
+ properties:{
+ height:{
+ start:o.beg,
+ end:o.end,
+ units:"px"
+ }
+ },
+ onEnd:onEnd
+ }).play();
+ }else{
+ onEnd();
+ }
+ },
+
+ _onUploaderChange: function(fileArray){
+ this.reset();
+ array.forEach(fileArray, function(f, i){
+ this._addRow(i+1, this.getFileType(f.name), f.name, f.size);
+ }, this)
+ },
+
+ _addRow: function(index, type, name, size){
+
+ var c, r = this.listNode.insertRow(-1);
+ c = r.insertCell(-1);
+ domClass.add(c, "dojoxUploaderIndex");
+ c.innerHTML = index;
+
+ c = r.insertCell(-1);
+ domClass.add(c, "dojoxUploaderIcon");
+ c.innerHTML = type;
+
+ c = r.insertCell(-1);
+ domClass.add(c, "dojoxUploaderFileName");
+ c.innerHTML = name;
+ if(this._fileSizeAvail){
+ c = r.insertCell(-1);
+ domClass.add(c, "dojoxUploaderSize");
+ c.innerHTML = this.convertBytes(size).value;
+ }
+
+ this.rowAmt++;
+ }
+});
+});
diff --git a/js/dojo/dojox/form/uploader/plugins/Flash.js b/js/dojo/dojox/form/uploader/plugins/Flash.js
new file mode 100644
index 0000000..473410b
--- /dev/null
+++ b/js/dojo/dojox/form/uploader/plugins/Flash.js
@@ -0,0 +1,307 @@
+//>>built
+define("dojox/form/uploader/plugins/Flash", [
+ "dojo/dom-form",
+ "dojo/dom-style",
+ "dojo/dom-construct",
+ "dojo/dom-attr",
+ "dojo/_base/declare",
+ "dojo/_base/config",
+ "dojo/_base/connect",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojox/form/uploader/plugins/HTML5",
+ "dojox/embed/Flash"
+],function(domForm, domStyle, domConstruct, domAttr, declare, config, connect, lang, array, formUploaderPluginsHTML5, embedFlash){
+
+
+var pluginsFlash = declare("dojox.form.uploader.plugins.Flash", [], {
+ //
+ // Version: 1.6
+ //
+ // summary:
+ // A plugin for dojox.form.Uploader that utilizes a Flash SWF for handling to upload in IE.
+ // All other browsers will use the HTML5 plugin, unless force="flash" is used, then Flash
+ // will be used in all browsers. force="flash" is provided because Flash has some features
+ // that HTML5 does not yet have. But it is still not recommended because of the many problems
+ // that Firefox and Webkit have with the Flash plugin.
+ //
+ // description:
+ // Inherits all properties from dojox.form.Uploader and formUploaderPluginsHTML5.
+ // All properties and methods listed here are specific to the Flash plugin only.
+ //
+ // swfPath:String
+ // Path to SWF. Can be overwritten or provided in djConfig.
+ swfPath:config.uploaderPath || require.toUrl("dojox/form/resources/uploader.swf"),
+ //
+ // skipServerCheck: Boolean
+ // If true, will not verify that the server was sent the correct format.
+ // This can be safely set to true. The purpose of the server side check
+ // is mainly to show the dev if they've implemented the different returns
+ // correctly.
+ skipServerCheck:true,
+ //
+ // serverTimeout:Number (milliseconds)
+ // The amount of time given to the uploaded file
+ // to wait for a server response. After this amount
+ // of time, the onComplete is fired but with a 'server timeout'
+ // error in the returned item.
+ serverTimeout: 2000,
+ //
+ // isDebug: Boolean
+ // If true, outputs traces from the SWF to console. What exactly gets passed
+ // is very relative, and depends upon what traces have been left in the DEFT SWF.
+ isDebug:false,
+ //
+ // devMode: Boolean.
+ // Re-implemented. devMode increases the logging, adding style tracing from the SWF.
+ devMode:false,
+ //
+ // deferredUploading: Number (1 - X)
+ // (Flash only) throttles the upload to a certain amount of files at a time.
+ // By default, Flash uploads file one at a time to the server, but in parallel.
+ // Firefox will try to queue all files at once, leading to problems. Set this
+ // to the amount to upload in parallel at a time.
+ // Generally, 1 should work fine, but you can experiment with queuing more than
+ // one at a time.
+ // This is of course ignored if selectMultipleFiles equals false.
+ deferredUploading:0,
+ //
+ // force: String
+ // Use "flash" to always use Flash (and hopefully force the user to download the plugin
+ // if they don't have it).
+ force:"",
+
+ postMixInProperties: function(){
+ if(!this.supports("multiple")){
+ // Flash will only be used in IE6-8 unless force="flash"
+ this.uploadType = "flash";
+ this._files = [];
+ this._fileMap = {};
+ this._createInput = this._createFlashUploader;
+ this.getFileList = this.getFlashFileList;
+ this.reset = this.flashReset;
+ this.upload = this.uploadFlash;
+ this.fieldname = "flashUploadFiles"; ///////////////////// this.name
+ }
+ this.inherited(arguments);
+ },
+
+ /*************************
+ * Public Events *
+ *************************/
+
+ onReady: function(/* dojox.form.FileUploader */ uploader){
+ // summary:
+ // Stub - Fired when embedFlash has created the
+ // Flash object, but it has not necessarilly finished
+ // downloading, and is ready to be communicated with.
+ },
+
+ onLoad: function(/* dojox.form.FileUploader */ uploader){
+ // summary:
+ // Stub - SWF has been downloaded 100%.
+ },
+
+ onFileChange: function(fileArray){
+ // summary:
+ // Stub - Flash-specific event. Fires on each selection of files
+ // and only provides the files selected on that event - not all files
+ // selected, as with HTML5
+ },
+
+ onFileProgress: function(fileArray){
+ // summary:
+ // Stub - Flash-specific event. Fires on progress of upload
+ // and only provides a file-specific event
+ },
+
+
+ /*************************
+ * Public Methods *
+ *************************/
+
+ getFlashFileList: function(){
+ // summary:
+ // Returns list of currently selected files
+ return this._files; // Array
+ },
+
+ flashReset: function(){
+ this.flashMovie.reset();
+ this._files = [];
+ },
+
+ /*************************
+ * Private Methods *
+ *************************/
+
+ uploadFlash: function(/*Object ? */formData){
+ // summary:
+ // Uploads selected files. Alias "upload()" should be used instead.
+ // tags:
+ // private
+ this.onBegin(this.getFileList());
+ this.flashMovie.doUpload(formData);
+ },
+
+ _change: function(fileArray){
+ this._files = this._files.concat(fileArray);
+ array.forEach(fileArray, function(f){
+ f.bytesLoaded = 0;
+ f.bytesTotal = f.size;
+ this._fileMap[f.name+"_"+f.size] = f;
+ }, this);
+ this.onChange(this._files);
+ this.onFileChange(fileArray);
+ },
+ _complete: function(fileArray){
+ var o = this._getCustomEvent();
+ o.type = "load";
+ this.onComplete(fileArray);
+ },
+ _progress: function(f){
+ this._fileMap[f.name+"_"+f.bytesTotal].bytesLoaded = f.bytesLoaded;
+ var o = this._getCustomEvent();
+ this.onFileProgress(f);
+ this.onProgress(o);
+ },
+ _error: function(err){
+ this.onError(err);
+ },
+ _onFlashBlur: function(fileArray){
+ //console.log("UploaderFlash._onFlashBlur");
+ },
+
+ _getCustomEvent: function(){
+ var o = {
+ bytesLoaded:0,
+ bytesTotal:0,
+ type:"progress",
+ timeStamp:new Date().getTime()
+ };
+
+
+ for(var nm in this._fileMap){
+ o.bytesTotal += this._fileMap[nm].bytesTotal;
+ o.bytesLoaded += this._fileMap[nm].bytesLoaded;
+ }
+ o.decimal = o.bytesLoaded / o.bytesTotal;
+ o.percent = Math.ceil((o.bytesLoaded / o.bytesTotal)*100)+"%";
+ return o; // Object
+ },
+
+ _connectFlash: function(){
+ // summary:
+ // Subscribing to published topics coming from the
+ // Flash uploader.
+ // description:
+ // Sacrificing some readbilty for compactness. this.id
+ // will be on the beginning of the topic, so more than
+ // one uploader can be on a page and can have unique calls.
+ //
+
+ this._subs = [];
+ this._cons = [];
+
+ var doSub = lang.hitch(this, function(s, funcStr){
+ this._subs.push(connect.subscribe(this.id + s, this, funcStr));
+ });
+
+ doSub("/filesSelected", "_change");
+ doSub("/filesUploaded", "_complete");
+ doSub("/filesProgress", "_progress");
+ doSub("/filesError", "_error");
+ doSub("/filesCanceled", "onCancel");
+ doSub("/stageBlur", "_onFlashBlur");
+
+ this.connect(this.domNode, "focus", function(){
+ // TODO: some kind of indicator that the Flash button
+ // is in focus
+ this.flashMovie.focus();
+ this.flashMovie.doFocus();
+ });
+ if(this.tabIndex>=0){
+ domAttr.set(this.domNode, "tabIndex", this.tabIndex);
+ }
+ },
+ _createFlashUploader: function(){
+ // summary:
+ // Internal. Creates Flash Uploader
+ //
+ var url = this.getUrl();
+ if(url){
+ if(url.toLowerCase().indexOf("http")<0 && url.indexOf("/")!=0){
+ // Appears to be a relative path. Attempt to
+ // convert it to absolute, so it will better
+ //target the SWF.
+ //
+ var loc = window.location.href.split("/");
+ loc.pop();
+ loc = loc.join("/")+"/";
+ url = loc+url;
+ }
+ }else{
+ console.warn("Warning: no uploadUrl provided.");
+ }
+
+ this.inputNode = domConstruct.create("div", {className:"dojoxFlashNode"}, this.domNode, "first");
+ domStyle.set(this.inputNode, {
+ position:"absolute",
+ top:"-2px",
+ width:this.btnSize.w+"px",
+ height:this.btnSize.h+"px",
+ opacity:0
+ });
+
+ var w = this.btnSize.w;
+ var h = this.btnSize.h;
+
+ var args = {
+ expressInstall:true,
+ path: (this.swfPath.uri || this.swfPath) + "?cb_" + (new Date().getTime()),
+ width: w,
+ height: h,
+ allowScriptAccess:"always",
+ allowNetworking:"all",
+ vars: {
+ uploadDataFieldName: this.flashFieldName || this.name+"Flash",
+ uploadUrl: url,
+ uploadOnSelect: this.uploadOnSelect,
+ deferredUploading:this.deferredUploading || 0,
+ selectMultipleFiles: this.multiple,
+ id: this.id,
+ isDebug: this.isDebug,
+ noReturnCheck: this.skipServerCheck,
+ serverTimeout:this.serverTimeout
+ },
+ params: {
+ scale:"noscale",
+ wmode:"transparent",
+ wmode:"opaque",
+ allowScriptAccess:"always",
+ allowNetworking:"all"
+ }
+
+ };
+
+ this.flashObject = new embedFlash(args, this.inputNode);
+ this.flashObject.onError = lang.hitch(function(msg){
+ console.error("Flash Error: " + msg);
+ });
+ this.flashObject.onReady = lang.hitch(this, function(){
+ this.onReady(this);
+ });
+ this.flashObject.onLoad = lang.hitch(this, function(mov){
+ this.flashMovie = mov;
+ this.flashReady = true;
+
+ this.onLoad(this);
+ });
+ this._connectFlash();
+ }
+});
+dojox.form.addUploaderPlugin(pluginsFlash);
+
+
+return pluginsFlash;
+});
diff --git a/js/dojo/dojox/form/uploader/plugins/HTML5.js b/js/dojo/dojox/form/uploader/plugins/HTML5.js
new file mode 100644
index 0000000..cf16ccc
--- /dev/null
+++ b/js/dojo/dojox/form/uploader/plugins/HTML5.js
@@ -0,0 +1,241 @@
+//>>built
+define("dojox/form/uploader/plugins/HTML5", [
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojo"
+],function(declare, lang, array, dojo){
+
+var pluginsHTML5 = declare("dojox.form.uploader.plugins.HTML5", [], {
+ //
+ // Version: 1.6
+ //
+ // summary:
+ // A plugin for dojox.form.Uploader that adds HTML5 multiple-file upload capabilities and
+ // progress events.
+ //
+ // description:
+ // Add this plugin to have HTML5 capabilities in the Uploader. Note that it does not add
+ // these capabilities to browsers that don't support them. For IE or older browsers, add
+ // additional plugins: IFrame or Flash.
+ //
+ errMsg:"Error uploading files. Try checking permissions",
+
+ // Overwrites "form" and could possibly be overwritten again by iframe or flash plugin.
+ uploadType:"html5",
+
+ postCreate: function(){
+ this.connectForm();
+ this.inherited(arguments);
+ if(this.uploadOnSelect){
+ this.connect(this, "onChange", function(data){
+ this.upload(data[0]);
+ });
+ }
+ },
+
+ _drop: function(e){
+ dojo.stopEvent(e);
+ var dt = e.dataTransfer;
+ this._files = dt.files;
+ this.onChange(this.getFileList());
+ },
+ /*************************
+ * Public Methods *
+ *************************/
+
+ upload: function(/*Object ? */formData){
+ // summary:
+ // See: dojox.form.Uploader.upload
+ //
+ this.onBegin(this.getFileList());
+ if(this.supports("FormData")){
+ this.uploadWithFormData(formData);
+ }else if(this.supports("sendAsBinary")){
+ this.sendAsBinary(formData);
+ }
+ },
+
+ addDropTarget: function(node, /*Boolean?*/onlyConnectDrop){
+ // summary:
+ // Add a dom node which will act as the drop target area so user
+ // can drop files to this node.
+ // description:
+ // If onlyConnectDrop is true, dragenter/dragover/dragleave events
+ // won't be connected to dojo.stopEvent, and they need to be
+ // canceled by user code to allow DnD files to happen.
+ // This API is only available in HTML5 plugin (only HTML5 allows
+ // DnD files).
+ if(!onlyConnectDrop){
+ this.connect(node, 'dragenter', dojo.stopEvent);
+ this.connect(node, 'dragover', dojo.stopEvent);
+ this.connect(node, 'dragleave', dojo.stopEvent);
+ }
+ this.connect(node, 'drop', '_drop');
+ },
+
+ sendAsBinary: function(/* Object */data){
+ // summary:
+ // Used primarily in FF < 4.0. Sends files and form object as binary data, written to
+ // still enable use of $_FILES in PHP (or equivalent).
+ // tags:
+ // private
+ //
+ if(!this.getUrl()){
+ console.error("No upload url found.", this); return;
+ }
+
+ // The date/number doesn't matter but amount of dashes do. The actual boundary
+ // will have two more dashes than this one which is used in the header.
+ var boundary = "---------------------------" + (new Date).getTime();
+ var xhr = this.createXhr();
+
+ xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
+
+ // finally send the request as binary data
+ // still accessed as $_FILES
+ var msg = this._buildRequestBody(data, boundary);
+ if(!msg){
+ this.onError(this.errMsg);
+ }else{
+ console.log("msg:", msg)
+ console.log("xhr:", xhr)
+
+ xhr.sendAsBinary(msg);
+ }
+ },
+ uploadWithFormData: function(/* Object */data){
+ // summary
+ // Used with WebKit and Firefox 4+
+ // Upload files using the much friendlier FormData browser object.
+ // tags:
+ // private
+ //
+ if(!this.getUrl()){
+ console.error("No upload url found.", this); return;
+ }
+ var fd = new FormData();
+ array.forEach(this._files, function(f, i){
+ fd.append(this.name+"s[]", f);
+ }, this);
+
+ if(data){
+ for(var nm in data){
+ fd.append(nm, data[nm]);
+ }
+ }
+
+ var xhr = this.createXhr();
+ xhr.send(fd);
+ },
+
+ _xhrProgress: function(evt){
+ if(evt.lengthComputable){
+ var o = {
+ bytesLoaded:evt.loaded,
+ bytesTotal:evt.total,
+ type:evt.type,
+ timeStamp:evt.timeStamp
+ };
+ if(evt.type == "load"){
+ // 100%
+ o.percent = "100%",
+ o.decimal = 1;
+ }else{
+ o.decimal = evt.loaded / evt.total;
+ o.percent = Math.ceil((evt.loaded / evt.total)*100)+"%";
+ }
+ this.onProgress(o);
+ }
+ },
+
+ createXhr: function(){
+ var xhr = new XMLHttpRequest();
+ var timer;
+ xhr.upload.addEventListener("progress", lang.hitch(this, "_xhrProgress"), false);
+ xhr.addEventListener("load", lang.hitch(this, "_xhrProgress"), false);
+ xhr.addEventListener("error", lang.hitch(this, function(evt){
+ this.onError(evt);
+ clearInterval(timer);
+ }), false);
+ xhr.addEventListener("abort", lang.hitch(this, function(evt){
+ this.onAbort(evt);
+ clearInterval(timer);
+ }), false);
+ xhr.onreadystatechange = lang.hitch(this, function(){
+ if(xhr.readyState === 4){
+// console.info("COMPLETE")
+ clearInterval(timer);
+ this.onComplete(JSON.parse(xhr.responseText.replace(/^\{\}&&/,'')));
+ }
+ });
+ xhr.open("POST", this.getUrl());
+
+ timer = setInterval(lang.hitch(this, function(){
+ try{
+ if(typeof(xhr.statusText)){} // accessing this error throws an error. Awesomeness.
+ }catch(e){
+ //this.onError("Error uploading file."); // not always an error.
+ clearInterval(timer);
+ }
+ }),250);
+
+ return xhr;
+ },
+
+ _buildRequestBody : function(data, boundary){
+ var EOL = "\r\n";
+ var part = "";
+ boundary = "--" + boundary;
+
+ var filesInError = [], files = this._files;
+ array.forEach(files, function(f, i){
+ var fieldName = this.name+"s[]";//+i;
+ var fileName = f.fileName;
+ var binary;
+
+ try{
+ binary = f.getAsBinary() + EOL;
+ part += boundary + EOL;
+ part += 'Content-Disposition: form-data; ';
+ part += 'name="' + fieldName + '"; ';
+ part += 'filename="'+ fileName + '"' + EOL;
+ part += "Content-Type: " + this.getMimeType() + EOL + EOL;
+ part += binary;
+ }catch(e){
+ filesInError.push({index:i, name:fileName});
+ }
+ }, this);
+
+ if(filesInError.length){
+ if(filesInError.length >= files.length){
+ // all files were bad. Nothing to upload.
+ this.onError({
+ message:this.errMsg,
+ filesInError:filesInError
+ });
+ part = false;
+ }
+ }
+
+ if(!part) return false;
+
+ if(data){
+ for(var nm in data){
+ part += boundary + EOL;
+ part += 'Content-Disposition: form-data; ';
+ part += 'name="' + nm + '"' + EOL + EOL;
+ part += data[nm] + EOL;
+ }
+ }
+
+
+ part += boundary + "--" + EOL;
+ return part;
+ }
+
+});
+dojox.form.addUploaderPlugin(pluginsHTML5);
+
+return pluginsHTML5;
+});
diff --git a/js/dojo/dojox/form/uploader/plugins/IFrame.js b/js/dojo/dojox/form/uploader/plugins/IFrame.js
new file mode 100644
index 0000000..93f5e7e
--- /dev/null
+++ b/js/dojo/dojox/form/uploader/plugins/IFrame.js
@@ -0,0 +1,79 @@
+//>>built
+define("dojox/form/uploader/plugins/IFrame", [
+ "dojo/dom-construct",
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojo/io/iframe",
+ "dojox/form/uploader/plugins/HTML5"
+],function(domConstruct, declare, lang, array, ioIframe, formUploaderPluginsHTML5){
+
+
+var pluginsIFrame = declare("dojox.form.uploader.plugins.IFrame", [], {
+ //
+ // Version: 1.6
+ //
+ // summary:
+ // A plugin for dojox.form.Uploader that adds Ajax upload capabilities.
+ //
+ // description:
+ // Only supported by IE, due to the specifc iFrame hack used. The
+ // formUploaderPluginsHTML5 plugin should be used along with this to add HTML5
+ // capabilities to browsers that support them. Progress events are not supported.
+ // Inherits all properties from dojox.form.Uploader and formUploaderPluginsHTML5.
+ //
+
+ force:"",
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ if(!this.supports("multiple") || this.force =="iframe"){
+ this.uploadType = "iframe";
+ this.upload = this.uploadIFrame;
+ }
+ },
+
+ uploadIFrame: function(data){
+ // summary:
+ // Internal. You could use this, but you should use upload() or submit();
+ // which can also handle the post data.
+ //
+ var form, destroyAfter = false;
+ if(!this.getForm()){
+ //enctype can't be changed once a form element is created
+ form = domConstruct.place('<form enctype="multipart/form-data" method="post"></form>', this.domNode);
+ array.forEach(this._inputs, function(n, i){
+ if(n.value) form.appendChild(n);
+ }, this);
+ destroyAfter = true;
+ }else{
+ form = this.form;
+ }
+
+ var url = this.getUrl();
+
+ var dfd = ioIframe.send({
+ url: url,
+ form: form,
+ handleAs: "json",
+ content: data,
+ error: lang.hitch(this, function(err){
+ if(destroyAfter){ domConstruct.destroy(form); }
+ this.onError(err);
+ }),
+ load: lang.hitch(this, function(data, ioArgs, widgetRef){
+ if(destroyAfter){ domConstruct.destroy(form); }
+ if(data["ERROR"] || data["error"]){
+ this.onError(data);
+ }else{
+ this.onComplete(data);
+ }
+ })
+ });
+ }
+});
+
+dojox.form.addUploaderPlugin(pluginsIFrame);
+
+return pluginsIFrame;
+});