/* Copyright (c) 2004-2012, 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["dojox.mobile.app._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["dojox.mobile.app._FormWidget"] = true; dojo.provide("dojox.mobile.app._FormWidget"); dojo.experimental("dojox.mobile.app._FormWidget"); dojo.require("dojo.window"); dojo.require("dijit._WidgetBase"); dojo.declare("dojox.mobile.app._FormWidget", dijit._WidgetBase, { // 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 `dojox.mobile.app.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._WidgetBase.attr`. // // They also share some common methods. // name: 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", // 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: false, // These mixins assume that the focus node is an INPUT, as many but not all _FormWidgets are. attributeMap: dojo.delegate(dijit._WidgetBase.prototype.attributeMap, { value: "focusNode", id: "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.disabled = value; dojo.attr(this.focusNode, 'disabled', value); if(this.valueNode){ dojo.attr(this.valueNode, 'disabled', value); } }, _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.readOnly && this.focusNode && (dojo.style(this.domNode, "display") != "none"); }, focus: function(){ // summary: // Put focus on this widget this.focusNode.focus(); }, compare: function(/*anything*/val1, /*anything*/val2){ // summary: // Compare 2 values (as returned by attr('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==true, // onChange is only called form priorityChange=true events. // tags: // private this._lastValue = newValue; 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; } if((this.intermediateChanges || priorityChange || priorityChange === undefined) && ((typeof newValue != typeof this._lastValueReported) || this.compare(newValue, this._lastValueReported) != 0)){ this._lastValueReported = newValue; 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); }, _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(this.isFocusable()){ // 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); }); } }, selectInputText: function(/*DomNode*/element, /*Number?*/ start, /*Number?*/ stop){ // summary: // Select text in the input element argument, from start (default 0), to stop (default end). // TODO: use functions in _editor/selection.js? var _window = dojo.global; var _document = dojo.doc; element = dojo.byId(element); if(isNaN(start)){ start = 0; } if(isNaN(stop)){ stop = element.value ? element.value.length : 0; } dijit.focus(element); if(_window["getSelection"] && element.setSelectionRange){ element.setSelectionRange(start, stop); } } }); dojo.declare("dojox.mobile.app._FormValueWidget", dojox.mobile.app._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(dojox.mobile.app._FormWidget.prototype.attributeMap, { value: "", readOnly: "focusNode" }), _setReadOnlyAttr: function(/*Boolean*/ value){ this.readOnly = value; dojo.attr(this.focusNode, 'readOnly', value); }, postCreate: function(){ this.inherited(arguments); // 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._resetValue = this.value; } }, _setValueAttr: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){ // 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.value = newValue; this._handleOnChange(newValue, priorityChange); }, _getValueAttr: function(){ // summary: // Hook so attr('value') works. return this._lastValue; }, 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); } }); }