]> git.wh0rd.org - tt-rss.git/blob - lib/dijit/form/_FormWidgetMixin.js.uncompressed.js
update dojo to 1.7.3
[tt-rss.git] / lib / dijit / form / _FormWidgetMixin.js.uncompressed.js
1 define("dijit/form/_FormWidgetMixin", [
2 "dojo/_base/array", // array.forEach
3 "dojo/_base/declare", // declare
4 "dojo/dom-attr", // domAttr.set
5 "dojo/dom-style", // domStyle.get
6 "dojo/_base/lang", // lang.hitch lang.isArray
7 "dojo/mouse", // mouse.isLeft
8 "dojo/_base/sniff", // has("webkit")
9 "dojo/_base/window", // win.body
10 "dojo/window", // winUtils.scrollIntoView
11 "../a11y" // a11y.hasDefaultTabStop
12 ], function(array, declare, domAttr, domStyle, lang, mouse, has, win, winUtils, a11y){
13
14 // module:
15 // dijit/form/_FormWidgetMixin
16 // summary:
17 // Mixin for widgets corresponding to native HTML elements such as <checkbox> or <button>,
18 // which can be children of a <form> node or a `dijit.form.Form` widget.
19
20 return declare("dijit.form._FormWidgetMixin", null, {
21 // summary:
22 // Mixin for widgets corresponding to native HTML elements such as <checkbox> or <button>,
23 // which can be children of a <form> node or a `dijit.form.Form` widget.
24 //
25 // description:
26 // Represents a single HTML element.
27 // All these widgets should have these attributes just like native HTML input elements.
28 // You can set them during widget construction or afterwards, via `dijit._Widget.attr`.
29 //
30 // They also share some common methods.
31
32 // name: [const] String
33 // Name used when submitting form; same as "name" attribute or plain HTML elements
34 name: "",
35
36 // alt: String
37 // Corresponds to the native HTML <input> element's attribute.
38 alt: "",
39
40 // value: String
41 // Corresponds to the native HTML <input> element's attribute.
42 value: "",
43
44 // type: [const] String
45 // Corresponds to the native HTML <input> element's attribute.
46 type: "text",
47
48 // tabIndex: Integer
49 // Order fields are traversed when user hits the tab key
50 tabIndex: "0",
51 _setTabIndexAttr: "focusNode", // force copy even when tabIndex default value, needed since Button is <span>
52
53 // disabled: Boolean
54 // Should this widget respond to user input?
55 // In markup, this is specified as "disabled='disabled'", or just "disabled".
56 disabled: false,
57
58 // intermediateChanges: Boolean
59 // Fires onChange for each value change or only on demand
60 intermediateChanges: false,
61
62 // scrollOnFocus: Boolean
63 // On focus, should this widget scroll into view?
64 scrollOnFocus: true,
65
66 // Override _WidgetBase mapping id to this.domNode, needs to be on focusNode so <label> etc.
67 // works with screen reader
68 _setIdAttr: "focusNode",
69
70 _setDisabledAttr: function(/*Boolean*/ value){
71 this._set("disabled", value);
72 domAttr.set(this.focusNode, 'disabled', value);
73 if(this.valueNode){
74 domAttr.set(this.valueNode, 'disabled', value);
75 }
76 this.focusNode.setAttribute("aria-disabled", value ? "true" : "false");
77
78 if(value){
79 // reset these, because after the domNode is disabled, we can no longer receive
80 // mouse related events, see #4200
81 this._set("hovering", false);
82 this._set("active", false);
83
84 // clear tab stop(s) on this widget's focusable node(s) (ComboBox has two focusable nodes)
85 var attachPointNames = "tabIndex" in this.attributeMap ? this.attributeMap.tabIndex :
86 ("_setTabIndexAttr" in this) ? this._setTabIndexAttr : "focusNode";
87 array.forEach(lang.isArray(attachPointNames) ? attachPointNames : [attachPointNames], function(attachPointName){
88 var node = this[attachPointName];
89 // complex code because tabIndex=-1 on a <div> doesn't work on FF
90 if(has("webkit") || a11y.hasDefaultTabStop(node)){ // see #11064 about webkit bug
91 node.setAttribute('tabIndex', "-1");
92 }else{
93 node.removeAttribute('tabIndex');
94 }
95 }, this);
96 }else{
97 if(this.tabIndex != ""){
98 this.set('tabIndex', this.tabIndex);
99 }
100 }
101 },
102
103 _onFocus: function(/*String*/ by){
104 // If user clicks on the widget, even if the mouse is released outside of it,
105 // this widget's focusNode should get focus (to mimic native browser hehavior).
106 // Browsers often need help to make sure the focus via mouse actually gets to the focusNode.
107 if(by == "mouse" && this.isFocusable()){
108 // IE exhibits strange scrolling behavior when refocusing a node so only do it when !focused.
109 var focusConnector = this.connect(this.focusNode, "onfocus", function(){
110 this.disconnect(mouseUpConnector);
111 this.disconnect(focusConnector);
112 });
113 // Set a global event to handle mouseup, so it fires properly
114 // even if the cursor leaves this.domNode before the mouse up event.
115 var mouseUpConnector = this.connect(win.body(), "onmouseup", function(){
116 this.disconnect(mouseUpConnector);
117 this.disconnect(focusConnector);
118 // if here, then the mousedown did not focus the focusNode as the default action
119 if(this.focused){
120 this.focus();
121 }
122 });
123 }
124 if(this.scrollOnFocus){
125 this.defer(function(){ winUtils.scrollIntoView(this.domNode); }); // without defer, the input caret position can change on mouse click
126 }
127 this.inherited(arguments);
128 },
129
130 isFocusable: function(){
131 // summary:
132 // Tells if this widget is focusable or not. Used internally by dijit.
133 // tags:
134 // protected
135 return !this.disabled && this.focusNode && (domStyle.get(this.domNode, "display") != "none");
136 },
137
138 focus: function(){
139 // summary:
140 // Put focus on this widget
141 if(!this.disabled && this.focusNode.focus){
142 try{ this.focusNode.focus(); }catch(e){}/*squelch errors from hidden nodes*/
143 }
144 },
145
146 compare: function(/*anything*/ val1, /*anything*/ val2){
147 // summary:
148 // Compare 2 values (as returned by get('value') for this widget).
149 // tags:
150 // protected
151 if(typeof val1 == "number" && typeof val2 == "number"){
152 return (isNaN(val1) && isNaN(val2)) ? 0 : val1 - val2;
153 }else if(val1 > val2){
154 return 1;
155 }else if(val1 < val2){
156 return -1;
157 }else{
158 return 0;
159 }
160 },
161
162 onChange: function(/*===== newValue =====*/){
163 // summary:
164 // Callback when this widget's value is changed.
165 // tags:
166 // callback
167 },
168
169 // _onChangeActive: [private] Boolean
170 // Indicates that changes to the value should call onChange() callback.
171 // This is false during widget initialization, to avoid calling onChange()
172 // when the initial value is set.
173 _onChangeActive: false,
174
175 _handleOnChange: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
176 // summary:
177 // Called when the value of the widget is set. Calls onChange() if appropriate
178 // newValue:
179 // the new value
180 // priorityChange:
181 // For a slider, for example, dragging the slider is priorityChange==false,
182 // but on mouse up, it's priorityChange==true. If intermediateChanges==false,
183 // onChange is only called form priorityChange=true events.
184 // tags:
185 // private
186 if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){
187 // this block executes not for a change, but during initialization,
188 // and is used to store away the original value (or for ToggleButton, the original checked state)
189 this._resetValue = this._lastValueReported = newValue;
190 }
191 this._pendingOnChange = this._pendingOnChange
192 || (typeof newValue != typeof this._lastValueReported)
193 || (this.compare(newValue, this._lastValueReported) != 0);
194 if((this.intermediateChanges || priorityChange || priorityChange === undefined) && this._pendingOnChange){
195 this._lastValueReported = newValue;
196 this._pendingOnChange = false;
197 if(this._onChangeActive){
198 if(this._onChangeHandle){
199 this._onChangeHandle.remove();
200 }
201 // defer allows hidden value processing to run and
202 // also the onChange handler can safely adjust focus, etc
203 this._onChangeHandle = this.defer(
204 function(){
205 this._onChangeHandle = null;
206 this.onChange(newValue);
207 }); // try to collapse multiple onChange's fired faster than can be processed
208 }
209 }
210 },
211
212 create: function(){
213 // Overrides _Widget.create()
214 this.inherited(arguments);
215 this._onChangeActive = true;
216 },
217
218 destroy: function(){
219 if(this._onChangeHandle){ // destroy called before last onChange has fired
220 this._onChangeHandle.remove();
221 this.onChange(this._lastValueReported);
222 }
223 this.inherited(arguments);
224 }
225 });
226
227 });