123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- /*
- 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["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],
- {
- // 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,
- {
- // 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;
- }
- }
- }
- });
- }
|