diff options
Diffstat (limited to 'js/dojo/dojox/form')
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\"> </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\"> </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\"> </div\n\t\t\t><div class=\"dijitArrowButtonChar\">▼</div\n\t\t></div\n\t\t><div class=\"dijitReset dijitValidationIcon\"><br></div\n\t\t><div class=\"dijitReset dijitValidationIconText\">Χ</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": '', + "True": '√', + "Mixed": '≡' + }, + =====*/ + + /*===== + // 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": '', + "True": '√', + "Mixed": '≡' + }; + 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\">●</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"> </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"> </div + ><div class="dijitArrowButtonChar">▼</div + ></div + ><div class="dijitReset dijitValidationIcon"><br></div + ><div class="dijitReset dijitValidationIconText">Χ</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">●</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"> </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 Binary files differnew file mode 100644 index 0000000..f774e17 --- /dev/null +++ b/js/dojo/dojox/form/resources/fileuploader.swf diff --git a/js/dojo/dojox/form/resources/images/loading_wheel.gif b/js/dojo/dojox/form/resources/images/loading_wheel.gif Binary files differnew file mode 100644 index 0000000..901a7e3 --- /dev/null +++ b/js/dojo/dojox/form/resources/images/loading_wheel.gif diff --git a/js/dojo/dojox/form/resources/images/nihiloFolderSprite.gif b/js/dojo/dojox/form/resources/images/nihiloFolderSprite.gif Binary files differnew file mode 100644 index 0000000..0034b54 --- /dev/null +++ b/js/dojo/dojox/form/resources/images/nihiloFolderSprite.gif diff --git a/js/dojo/dojox/form/resources/images/rating_empty.gif b/js/dojo/dojox/form/resources/images/rating_empty.gif Binary files differnew file mode 100644 index 0000000..8662c43 --- /dev/null +++ b/js/dojo/dojox/form/resources/images/rating_empty.gif diff --git a/js/dojo/dojox/form/resources/images/rating_full.gif b/js/dojo/dojox/form/resources/images/rating_full.gif Binary files differnew file mode 100644 index 0000000..6fe24bf --- /dev/null +++ b/js/dojo/dojox/form/resources/images/rating_full.gif diff --git a/js/dojo/dojox/form/resources/images/soriaFolderSprite.gif b/js/dojo/dojox/form/resources/images/soriaFolderSprite.gif Binary files differnew file mode 100644 index 0000000..19e35c1 --- /dev/null +++ b/js/dojo/dojox/form/resources/images/soriaFolderSprite.gif diff --git a/js/dojo/dojox/form/resources/images/tristatecheckboxStates.png b/js/dojo/dojox/form/resources/images/tristatecheckboxStates.png Binary files differnew file mode 100644 index 0000000..dde030f --- /dev/null +++ b/js/dojo/dojox/form/resources/images/tristatecheckboxStates.png diff --git a/js/dojo/dojox/form/resources/images/tundraFolderSprite.gif b/js/dojo/dojox/form/resources/images/tundraFolderSprite.gif Binary files differnew file mode 100644 index 0000000..6cf8c09 --- /dev/null +++ b/js/dojo/dojox/form/resources/images/tundraFolderSprite.gif diff --git a/js/dojo/dojox/form/resources/uploader.swf b/js/dojo/dojox/form/resources/uploader.swf Binary files differnew file mode 100644 index 0000000..78233e4 --- /dev/null +++ b/js/dojo/dojox/form/resources/uploader.swf 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; +}); |
