You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
9.4 KiB
289 lines
9.4 KiB
dojo.provide("dojox.mobile.app._FormWidget"); |
|
dojo.experimental("dojox.mobile.app._FormWidget"); |
|
|
|
dojo.require("dojo.window"); |
|
|
|
dojo.require("dijit._WidgetBase"); |
|
dojo.require("dijit.focus"); // dijit.focus() |
|
|
|
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); |
|
} |
|
});
|
|
|