]>
git.wh0rd.org - tt-rss.git/blob - 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
){
15 // dijit/form/_FormWidgetMixin
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.
20 return declare("dijit.form._FormWidgetMixin", null, {
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.
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`.
30 // They also share some common methods.
32 // name: [const] String
33 // Name used when submitting form; same as "name" attribute or plain HTML elements
37 // Corresponds to the native HTML <input> element's attribute.
41 // Corresponds to the native HTML <input> element's attribute.
44 // type: [const] String
45 // Corresponds to the native HTML <input> element's attribute.
49 // Order fields are traversed when user hits the tab key
51 _setTabIndexAttr
: "focusNode", // force copy even when tabIndex default value, needed since Button is <span>
54 // Should this widget respond to user input?
55 // In markup, this is specified as "disabled='disabled'", or just "disabled".
58 // intermediateChanges: Boolean
59 // Fires onChange for each value change or only on demand
60 intermediateChanges
: false,
62 // scrollOnFocus: Boolean
63 // On focus, should this widget scroll into view?
66 // Override _WidgetBase mapping id to this.domNode, needs to be on focusNode so <label> etc.
67 // works with screen reader
68 _setIdAttr
: "focusNode",
70 _setDisabledAttr: function(/*Boolean*/ value
){
71 this._set("disabled", value
);
72 domAttr
.set(this.focusNode
, 'disabled', value
);
74 domAttr
.set(this.valueNode
, 'disabled', value
);
76 this.focusNode
.setAttribute("aria-disabled", value
? "true" : "false");
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);
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");
93 node
.removeAttribute('tabIndex');
97 if(this.tabIndex
!= ""){
98 this.set('tabIndex', this.tabIndex
);
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
);
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
124 if(this.scrollOnFocus
){
125 this.defer(function(){ winUtils
.scrollIntoView(this.domNode
); }); // without defer, the input caret position can change on mouse click
127 this.inherited(arguments
);
130 isFocusable: function(){
132 // Tells if this widget is focusable or not. Used internally by dijit.
135 return !this.disabled
&& this.focusNode
&& (domStyle
.get(this.domNode
, "display") != "none");
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*/
146 compare: function(/*anything*/ val1
, /*anything*/ val2
){
148 // Compare 2 values (as returned by get('value') for this widget).
151 if(typeof val1
== "number" && typeof val2
== "number"){
152 return (isNaN(val1
) && isNaN(val2
)) ? 0 : val1
- val2
;
153 }else if(val1
> val2
){
155 }else if(val1
< val2
){
162 onChange: function(/*===== newValue =====*/){
164 // Callback when this widget's value is changed.
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,
175 _handleOnChange: function(/*anything*/ newValue
, /*Boolean?*/ priorityChange
){
177 // Called when the value of the widget is set. Calls onChange() if appropriate
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.
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
;
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();
201 // defer allows hidden value processing to run and
202 // also the onChange handler can safely adjust focus, etc
203 this._onChangeHandle
= this.defer(
205 this._onChangeHandle
= null;
206 this.onChange(newValue
);
207 }); // try to collapse multiple onChange's fired faster than can be processed
213 // Overrides _Widget.create()
214 this.inherited(arguments
);
215 this._onChangeActive
= true;
219 if(this._onChangeHandle
){ // destroy called before last onChange has fired
220 this._onChangeHandle
.remove();
221 this.onChange(this._lastValueReported
);
223 this.inherited(arguments
);