diff options
author | Andrew Dolgov <[email protected]> | 2011-11-08 20:40:44 +0400 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2011-11-08 20:40:44 +0400 |
commit | 81bea17aefb26859f825b9293c7c99192874806e (patch) | |
tree | fb244408ca271affa2899adb634788802c9a89d8 /lib/dijit/form/_FormWidget.js | |
parent | 870a70e109ac9e80a88047044530de53d0404ec7 (diff) |
upgrade Dojo to 1.6.1
Diffstat (limited to 'lib/dijit/form/_FormWidget.js')
-rw-r--r-- | lib/dijit/form/_FormWidget.js | 515 |
1 files changed, 363 insertions, 152 deletions
diff --git a/lib/dijit/form/_FormWidget.js b/lib/dijit/form/_FormWidget.js index eb80ca06b..ebd1cfb18 100644 --- a/lib/dijit/form/_FormWidget.js +++ b/lib/dijit/form/_FormWidget.js @@ -1,166 +1,377 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit.form._FormWidget"]){ -dojo._hasResource["dijit.form._FormWidget"]=true; +if(!dojo._hasResource["dijit.form._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit.form._FormWidget"] = true; dojo.provide("dijit.form._FormWidget"); dojo.require("dojo.window"); dojo.require("dijit._Widget"); dojo.require("dijit._Templated"); dojo.require("dijit._CssStateMixin"); -dojo.declare("dijit.form._FormWidget",[dijit._Widget,dijit._Templated,dijit._CssStateMixin],{name:"",alt:"",value:"",type:"text",tabIndex:"0",disabled:false,intermediateChanges:false,scrollOnFocus:true,attributeMap:dojo.delegate(dijit._Widget.prototype.attributeMap,{value:"focusNode",id:"focusNode",tabIndex:"focusNode",alt:"focusNode",title:"focusNode"}),postMixInProperties:function(){ -this.nameAttrSetting=this.name?("name=\""+this.name.replace(/'/g,""")+"\""):""; -this.inherited(arguments); -},postCreate:function(){ -this.inherited(arguments); -this.connect(this.domNode,"onmousedown","_onMouseDown"); -},_setDisabledAttr:function(_1){ -this.disabled=_1; -dojo.attr(this.focusNode,"disabled",_1); -if(this.valueNode){ -dojo.attr(this.valueNode,"disabled",_1); -} -dijit.setWaiState(this.focusNode,"disabled",_1); -if(_1){ -this._hovering=false; -this._active=false; -var _2="tabIndex" in this.attributeMap?this.attributeMap.tabIndex:"focusNode"; -dojo.forEach(dojo.isArray(_2)?_2:[_2],function(_3){ -var _4=this[_3]; -if(dojo.isWebKit||dijit.hasDefaultTabStop(_4)){ -_4.setAttribute("tabIndex","-1"); -}else{ -_4.removeAttribute("tabIndex"); -} -},this); -}else{ -this.focusNode.setAttribute("tabIndex",this.tabIndex); -} -},setDisabled:function(_5){ -dojo.deprecated("setDisabled("+_5+") is deprecated. Use set('disabled',"+_5+") instead.","","2.0"); -this.set("disabled",_5); -},_onFocus:function(e){ -if(this.scrollOnFocus){ -dojo.window.scrollIntoView(this.domNode); -} -this.inherited(arguments); -},isFocusable:function(){ -return !this.disabled&&!this.readOnly&&this.focusNode&&(dojo.style(this.domNode,"display")!="none"); -},focus:function(){ -dijit.focus(this.focusNode); -},compare:function(_6,_7){ -if(typeof _6=="number"&&typeof _7=="number"){ -return (isNaN(_6)&&isNaN(_7))?0:_6-_7; -}else{ -if(_6>_7){ -return 1; -}else{ -if(_6<_7){ -return -1; -}else{ -return 0; -} -} -} -},onChange:function(_8){ -},_onChangeActive:false,_handleOnChange:function(_9,_a){ -this._lastValue=_9; -if(this._lastValueReported==undefined&&(_a===null||!this._onChangeActive)){ -this._resetValue=this._lastValueReported=_9; -} -if((this.intermediateChanges||_a||_a===undefined)&&((typeof _9!=typeof this._lastValueReported)||this.compare(_9,this._lastValueReported)!=0)){ -this._lastValueReported=_9; -if(this._onChangeActive){ -if(this._onChangeHandle){ -clearTimeout(this._onChangeHandle); -} -this._onChangeHandle=setTimeout(dojo.hitch(this,function(){ -this._onChangeHandle=null; -this.onChange(_9); -}),0); -} -} -},create:function(){ -this.inherited(arguments); -this._onChangeActive=true; -},destroy:function(){ -if(this._onChangeHandle){ -clearTimeout(this._onChangeHandle); -this.onChange(this._lastValueReported); -} -this.inherited(arguments); -},setValue:function(_b){ -dojo.deprecated("dijit.form._FormWidget:setValue("+_b+") is deprecated. Use set('value',"+_b+") instead.","","2.0"); -this.set("value",_b); -},getValue:function(){ -dojo.deprecated(this.declaredClass+"::getValue() is deprecated. Use get('value') instead.","","2.0"); -return this.get("value"); -},_onMouseDown:function(e){ -if(!e.ctrlKey&&this.isFocusable()){ -var _c=this.connect(dojo.body(),"onmouseup",function(){ -if(this.isFocusable()){ -this.focus(); -} -this.disconnect(_c); + + +dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._CssStateMixin], + { + // summary: + // Base class for widgets corresponding to native HTML elements such as <checkbox> or <button>, + // which can be children of a <form> node or a `dijit.form.Form` widget. + // + // description: + // Represents a single HTML element. + // All these widgets should have these attributes just like native HTML input elements. + // You can set them during widget construction or afterwards, via `dijit._Widget.attr`. + // + // They also share some common methods. + + // name: [const] String + // Name used when submitting form; same as "name" attribute or plain HTML elements + name: "", + + // alt: String + // Corresponds to the native HTML <input> element's attribute. + alt: "", + + // value: String + // Corresponds to the native HTML <input> element's attribute. + value: "", + + // type: String + // Corresponds to the native HTML <input> element's attribute. + type: "text", + + // tabIndex: Integer + // Order fields are traversed when user hits the tab key + tabIndex: "0", + + // disabled: Boolean + // Should this widget respond to user input? + // In markup, this is specified as "disabled='disabled'", or just "disabled". + disabled: false, + + // intermediateChanges: Boolean + // Fires onChange for each value change or only on demand + intermediateChanges: false, + + // scrollOnFocus: Boolean + // On focus, should this widget scroll into view? + scrollOnFocus: true, + + // These mixins assume that the focus node is an INPUT, as many but not all _FormWidgets are. + attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, { + value: "focusNode", + id: "focusNode", + tabIndex: "focusNode", + alt: "focusNode", + title: "focusNode" + }), + + postMixInProperties: function(){ + // Setup name=foo string to be referenced from the template (but only if a name has been specified) + // Unfortunately we can't use attributeMap to set the name due to IE limitations, see #8660 + // Regarding escaping, see heading "Attribute values" in + // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2 + this.nameAttrSetting = this.name ? ('name="' + this.name.replace(/'/g, """) + '"') : ''; + this.inherited(arguments); + }, + + postCreate: function(){ + this.inherited(arguments); + this.connect(this.domNode, "onmousedown", "_onMouseDown"); + }, + + _setDisabledAttr: function(/*Boolean*/ value){ + this._set("disabled", value); + dojo.attr(this.focusNode, 'disabled', value); + if(this.valueNode){ + dojo.attr(this.valueNode, 'disabled', value); + } + dijit.setWaiState(this.focusNode, "disabled", value); + + if(value){ + // reset these, because after the domNode is disabled, we can no longer receive + // mouse related events, see #4200 + this._set("hovering", false); + this._set("active", false); + + // clear tab stop(s) on this widget's focusable node(s) (ComboBox has two focusable nodes) + var attachPointNames = "tabIndex" in this.attributeMap ? this.attributeMap.tabIndex : "focusNode"; + dojo.forEach(dojo.isArray(attachPointNames) ? attachPointNames : [attachPointNames], function(attachPointName){ + var node = this[attachPointName]; + // complex code because tabIndex=-1 on a <div> doesn't work on FF + if(dojo.isWebKit || dijit.hasDefaultTabStop(node)){ // see #11064 about webkit bug + node.setAttribute('tabIndex', "-1"); + }else{ + node.removeAttribute('tabIndex'); + } + }, this); + }else{ + if(this.tabIndex != ""){ + this.focusNode.setAttribute('tabIndex', this.tabIndex); + } + } + }, + + setDisabled: function(/*Boolean*/ disabled){ + // summary: + // Deprecated. Use set('disabled', ...) instead. + dojo.deprecated("setDisabled("+disabled+") is deprecated. Use set('disabled',"+disabled+") instead.", "", "2.0"); + this.set('disabled', disabled); + }, + + _onFocus: function(e){ + if(this.scrollOnFocus){ + dojo.window.scrollIntoView(this.domNode); + } + this.inherited(arguments); + }, + + isFocusable: function(){ + // summary: + // Tells if this widget is focusable or not. Used internally by dijit. + // tags: + // protected + return !this.disabled && this.focusNode && (dojo.style(this.domNode, "display") != "none"); + }, + + focus: function(){ + // summary: + // Put focus on this widget + if(!this.disabled){ + dijit.focus(this.focusNode); + } + }, + + compare: function(/*anything*/ val1, /*anything*/ val2){ + // summary: + // Compare 2 values (as returned by get('value') for this widget). + // tags: + // protected + if(typeof val1 == "number" && typeof val2 == "number"){ + return (isNaN(val1) && isNaN(val2)) ? 0 : val1 - val2; + }else if(val1 > val2){ + return 1; + }else if(val1 < val2){ + return -1; + }else{ + return 0; + } + }, + + onChange: function(newValue){ + // summary: + // Callback when this widget's value is changed. + // tags: + // callback + }, + + // _onChangeActive: [private] Boolean + // Indicates that changes to the value should call onChange() callback. + // This is false during widget initialization, to avoid calling onChange() + // when the initial value is set. + _onChangeActive: false, + + _handleOnChange: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){ + // summary: + // Called when the value of the widget is set. Calls onChange() if appropriate + // newValue: + // the new value + // priorityChange: + // For a slider, for example, dragging the slider is priorityChange==false, + // but on mouse up, it's priorityChange==true. If intermediateChanges==false, + // onChange is only called form priorityChange=true events. + // tags: + // private + if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){ + // this block executes not for a change, but during initialization, + // and is used to store away the original value (or for ToggleButton, the original checked state) + this._resetValue = this._lastValueReported = newValue; + } + this._pendingOnChange = this._pendingOnChange + || (typeof newValue != typeof this._lastValueReported) + || (this.compare(newValue, this._lastValueReported) != 0); + if((this.intermediateChanges || priorityChange || priorityChange === undefined) && this._pendingOnChange){ + this._lastValueReported = newValue; + this._pendingOnChange = false; + if(this._onChangeActive){ + if(this._onChangeHandle){ + clearTimeout(this._onChangeHandle); + } + // setTimout allows hidden value processing to run and + // also the onChange handler can safely adjust focus, etc + this._onChangeHandle = setTimeout(dojo.hitch(this, + function(){ + this._onChangeHandle = null; + this.onChange(newValue); + }), 0); // try to collapse multiple onChange's fired faster than can be processed + } + } + }, + + create: function(){ + // Overrides _Widget.create() + this.inherited(arguments); + this._onChangeActive = true; + }, + + destroy: function(){ + if(this._onChangeHandle){ // destroy called before last onChange has fired + clearTimeout(this._onChangeHandle); + this.onChange(this._lastValueReported); + } + this.inherited(arguments); + }, + + setValue: function(/*String*/ value){ + // summary: + // Deprecated. Use set('value', ...) instead. + dojo.deprecated("dijit.form._FormWidget:setValue("+value+") is deprecated. Use set('value',"+value+") instead.", "", "2.0"); + this.set('value', value); + }, + + getValue: function(){ + // summary: + // Deprecated. Use get('value') instead. + dojo.deprecated(this.declaredClass+"::getValue() is deprecated. Use get('value') instead.", "", "2.0"); + return this.get('value'); + }, + + _onMouseDown: function(e){ + // If user clicks on the button, even if the mouse is released outside of it, + // this button should get focus (to mimics native browser buttons). + // This is also needed on chrome because otherwise buttons won't get focus at all, + // which leads to bizarre focus restore on Dialog close etc. + if(!e.ctrlKey && dojo.mouseButtons.isLeft(e) && this.isFocusable()){ // !e.ctrlKey to ignore right-click on mac + // Set a global event to handle mouseup, so it fires properly + // even if the cursor leaves this.domNode before the mouse up event. + var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){ + if (this.isFocusable()) { + this.focus(); + } + this.disconnect(mouseUpConnector); + }); + } + } }); -} -}}); -dojo.declare("dijit.form._FormValueWidget",dijit.form._FormWidget,{readOnly:false,attributeMap:dojo.delegate(dijit.form._FormWidget.prototype.attributeMap,{value:"",readOnly:"focusNode"}),_setReadOnlyAttr:function(_d){ -this.readOnly=_d; -dojo.attr(this.focusNode,"readOnly",_d); -dijit.setWaiState(this.focusNode,"readonly",_d); -},postCreate:function(){ -this.inherited(arguments); -if(dojo.isIE){ -this.connect(this.focusNode||this.domNode,"onkeydown",this._onKeyDown); -} -if(this._resetValue===undefined){ -this._resetValue=this.value; -} -},_setValueAttr:function(_e,_f){ -this.value=_e; -this._handleOnChange(_e,_f); -},_getValueAttr:function(){ -return this._lastValue; -},undo:function(){ -this._setValueAttr(this._lastValueReported,false); -},reset:function(){ -this._hasBeenBlurred=false; -this._setValueAttr(this._resetValue,true); -},_onKeyDown:function(e){ -if(e.keyCode==dojo.keys.ESCAPE&&!(e.ctrlKey||e.altKey||e.metaKey)){ -var te; -if(dojo.isIE){ -e.preventDefault(); -te=document.createEventObject(); -te.keyCode=dojo.keys.ESCAPE; -te.shiftKey=e.shiftKey; -e.srcElement.fireEvent("onkeypress",te); -} -} -},_layoutHackIE7:function(){ -if(dojo.isIE==7){ -var _10=this.domNode; -var _11=_10.parentNode; -var _12=_10.firstChild||_10; -var _13=_12.style.filter; -var _14=this; -while(_11&&_11.clientHeight==0){ -(function ping(){ -var _15=_14.connect(_11,"onscroll",function(e){ -_14.disconnect(_15); -_12.style.filter=(new Date()).getMilliseconds(); -setTimeout(function(){ -_12.style.filter=_13; -},0); + +dojo.declare("dijit.form._FormValueWidget", dijit.form._FormWidget, +{ + // summary: + // Base class for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values. + // description: + // Each _FormValueWidget represents a single input value, and has a (possibly hidden) <input> element, + // to which it serializes it's input value, so that form submission (either normal submission or via FormBind?) + // works as expected. + + // Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared + // directly in the template as read by the parser in order to function. IE is known to specifically + // require the 'name' attribute at element creation time. See #8484, #8660. + // TODO: unclear what that {value: ""} is for; FormWidget.attributeMap copies value to focusNode, + // so maybe {value: ""} is so the value *doesn't* get copied to focusNode? + // Seems like we really want value removed from attributeMap altogether + // (although there's no easy way to do that now) + + // readOnly: Boolean + // Should this widget respond to user input? + // In markup, this is specified as "readOnly". + // Similar to disabled except readOnly form values are submitted. + readOnly: false, + + attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, { + value: "", + readOnly: "focusNode" + }), + + _setReadOnlyAttr: function(/*Boolean*/ value){ + dojo.attr(this.focusNode, 'readOnly', value); + dijit.setWaiState(this.focusNode, "readonly", value); + this._set("readOnly", value); + }, + + postCreate: function(){ + this.inherited(arguments); + + if(dojo.isIE < 9 || (dojo.isIE && dojo.isQuirks)){ // IE won't stop the event with keypress + this.connect(this.focusNode || this.domNode, "onkeydown", this._onKeyDown); + } + // Update our reset value if it hasn't yet been set (because this.set() + // is only called when there *is* a value) + if(this._resetValue === undefined){ + this._lastValueReported = this._resetValue = this.value; + } + }, + + _setValueAttr: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){ + // summary: + // Hook so set('value', value) works. + // description: + // Sets the value of the widget. + // If the value has changed, then fire onChange event, unless priorityChange + // is specified as null (or false?) + this._handleOnChange(newValue, priorityChange); + }, + + _handleOnChange: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){ + // summary: + // Called when the value of the widget has changed. Saves the new value in this.value, + // and calls onChange() if appropriate. See _FormWidget._handleOnChange() for details. + this._set("value", newValue); + this.inherited(arguments); + }, + + undo: function(){ + // summary: + // Restore the value to the last value passed to onChange + this._setValueAttr(this._lastValueReported, false); + }, + + reset: function(){ + // summary: + // Reset the widget's value to what it was at initialization time + this._hasBeenBlurred = false; + this._setValueAttr(this._resetValue, true); + }, + + _onKeyDown: function(e){ + if(e.keyCode == dojo.keys.ESCAPE && !(e.ctrlKey || e.altKey || e.metaKey)){ + var te; + if(dojo.isIE){ + e.preventDefault(); // default behavior needs to be stopped here since keypress is too late + te = document.createEventObject(); + te.keyCode = dojo.keys.ESCAPE; + te.shiftKey = e.shiftKey; + e.srcElement.fireEvent('onkeypress', te); + } + } + }, + + _layoutHackIE7: function(){ + // summary: + // Work around table sizing bugs on IE7 by forcing redraw + + if(dojo.isIE == 7){ // fix IE7 layout bug when the widget is scrolled out of sight + var domNode = this.domNode; + var parent = domNode.parentNode; + var pingNode = domNode.firstChild || domNode; // target node most unlikely to have a custom filter + var origFilter = pingNode.style.filter; // save custom filter, most likely nothing + var _this = this; + while(parent && parent.clientHeight == 0){ // search for parents that haven't rendered yet + (function ping(){ + var disconnectHandle = _this.connect(parent, "onscroll", + function(e){ + _this.disconnect(disconnectHandle); // only call once + pingNode.style.filter = (new Date()).getMilliseconds(); // set to anything that's unique + setTimeout(function(){ pingNode.style.filter = origFilter }, 0); // restore custom filter, if any + } + ); + })(); + parent = parent.parentNode; + } + } + } }); -})(); -_11=_11.parentNode; -} -} -}}); + } |