1 | define([ |
---|
2 | "dojo/_base/kernel", // kernel.deprecated |
---|
3 | "dojo/_base/declare", // declare |
---|
4 | "dojo/_base/array", // array.indexOf |
---|
5 | "dojo/_base/lang", // lang.isArray, lang.isString |
---|
6 | "dojo/_base/event", // event.stop |
---|
7 | "dojo/query", // query() |
---|
8 | "dojo/dom-attr", // domAttr.set |
---|
9 | "dojo/text!./resources/TriStateCheckBox.html", |
---|
10 | "dijit/form/Button", |
---|
11 | "dijit/form/_ToggleButtonMixin", |
---|
12 | "dojo/NodeList-dom" // NodeList.addClass/removeClass |
---|
13 | ], function(kernel, declare, array, lang, event, query, domAttr, template, Button, _ToggleButtonMixin){ |
---|
14 | |
---|
15 | return declare("dojox.form.TriStateCheckBox", [Button, _ToggleButtonMixin], { |
---|
16 | // summary: |
---|
17 | // Checkbox with three states |
---|
18 | |
---|
19 | templateString: template, |
---|
20 | |
---|
21 | baseClass: "dojoxTriStateCheckBox", |
---|
22 | |
---|
23 | // type: [private] String |
---|
24 | // type attribute on `<input>` node. |
---|
25 | // Overrides `dijit/form/Button.type`. Users should not change this value. |
---|
26 | type: "checkbox", |
---|
27 | |
---|
28 | // states: Array |
---|
29 | // States of TriStateCheckBox. |
---|
30 | // The value of This.checked should be one of these three states: |
---|
31 | // [false, true, "mixed"] |
---|
32 | states: "", |
---|
33 | |
---|
34 | // _stateLabels: Object |
---|
35 | // These characters are used to replace the image to show |
---|
36 | // current state of TriStateCheckBox in high contrast mode. This is an associate array of |
---|
37 | // states with their corresponding replacing characters. State can either be "False", "True" or "Mixed". |
---|
38 | _stateLabels: null, |
---|
39 | |
---|
40 | // stateValues: Object |
---|
41 | // The values of the TriStateCheckBox in corresponding states. This is an associate array of |
---|
42 | // states with their corresponding values. State can either be "False", "True" or "Mixed". |
---|
43 | stateValue: null, |
---|
44 | |
---|
45 | // _currentState: Integer |
---|
46 | // The current state of the TriStateCheckBox |
---|
47 | _currentState: 0, |
---|
48 | |
---|
49 | // _stateType: String |
---|
50 | // The current state type of the TriStateCheckBox |
---|
51 | // Could be "False", "True" or "Mixed" |
---|
52 | _stateType: "False", |
---|
53 | |
---|
54 | // readOnly: Boolean |
---|
55 | // Should this widget respond to user input? |
---|
56 | // In markup, this is specified as "readOnly". |
---|
57 | // Similar to disabled except readOnly form values are submitted. |
---|
58 | readOnly: false, |
---|
59 | |
---|
60 | // checked: Boolean|String |
---|
61 | // Current check state of the check box. |
---|
62 | checked: "", |
---|
63 | |
---|
64 | // aria-pressed for toggle buttons, and aria-checked for checkboxes |
---|
65 | _aria_attr: "aria-checked", |
---|
66 | |
---|
67 | constructor: function(){ |
---|
68 | // summary: |
---|
69 | // Runs on widget initialization to setup arrays etc. |
---|
70 | // tags: |
---|
71 | // private |
---|
72 | this.states = [false, "mixed", true]; |
---|
73 | this.checked = false; |
---|
74 | this._stateLabels = { |
---|
75 | "False": '□', |
---|
76 | "True": '√', |
---|
77 | "Mixed": '■' |
---|
78 | }; |
---|
79 | this.stateValues = { |
---|
80 | "False": false, |
---|
81 | "True": "on", |
---|
82 | "Mixed": "mixed" |
---|
83 | }; |
---|
84 | }, |
---|
85 | |
---|
86 | _fillContent: function(/*DomNode*/ source){ |
---|
87 | // Override Button::_fillContent() since it doesn't make sense for CheckBox, |
---|
88 | // since CheckBox doesn't even have a container |
---|
89 | }, |
---|
90 | |
---|
91 | postCreate: function(){ |
---|
92 | domAttr.set(this.stateLabelNode, 'innerHTML', this._stateLabels[this._stateType]); |
---|
93 | this.inherited(arguments); |
---|
94 | }, |
---|
95 | |
---|
96 | startup: function(){ |
---|
97 | this.set("checked", this.params.checked || this.states[this._currentState]); |
---|
98 | domAttr.set(this.stateLabelNode, 'innerHTML', this._stateLabels[this._stateType]); |
---|
99 | this.inherited(arguments); |
---|
100 | }, |
---|
101 | |
---|
102 | // Override behavior from Button, since we don't have an iconNode |
---|
103 | _setIconClassAttr: null, |
---|
104 | |
---|
105 | _setCheckedAttr: function(/*String|Boolean*/ checked, /*Boolean?*/ priorityChange){ |
---|
106 | // summary: |
---|
107 | // Handler for checked = attribute to constructor, and also calls to |
---|
108 | // set('checked', val). |
---|
109 | // checked: |
---|
110 | // true, false or 'mixed' |
---|
111 | // description: |
---|
112 | // Controls the state of the TriStateCheckBox. Set this.checked, |
---|
113 | // this._currentState, value attribute of the `<input type=checkbox>` |
---|
114 | // according to the value of 'checked'. |
---|
115 | var stateIndex = array.indexOf(this.states, checked), changed = false; |
---|
116 | if(stateIndex >= 0){ |
---|
117 | this._currentState = stateIndex; |
---|
118 | this._stateType = this._getStateType(checked); |
---|
119 | domAttr.set(this.focusNode, "value", this.stateValues[this._stateType]); |
---|
120 | domAttr.set(this.stateLabelNode, 'innerHTML', this._stateLabels[this._stateType]); |
---|
121 | this.inherited(arguments); |
---|
122 | }else{ |
---|
123 | console.warn("Invalid state!"); |
---|
124 | } |
---|
125 | }, |
---|
126 | |
---|
127 | setChecked: function(/*String|Boolean*/ checked){ |
---|
128 | // summary: |
---|
129 | // Deprecated. Use set('checked', true/false) instead. |
---|
130 | kernel.deprecated("setChecked("+checked+") is deprecated. Use set('checked',"+checked+") instead.", "", "2.0"); |
---|
131 | this.set('checked', checked); |
---|
132 | }, |
---|
133 | |
---|
134 | _setStatesAttr: function(/*Array|String*/ states){ |
---|
135 | if(lang.isArray(states)){ |
---|
136 | this._set("states", states); |
---|
137 | }else if(lang.isString(states)){ |
---|
138 | var map = { |
---|
139 | "true": true, |
---|
140 | "false": false, |
---|
141 | "mixed": "mixed" |
---|
142 | }; |
---|
143 | states = states.split(/\s*,\s*/); |
---|
144 | for(var i = 0; i < states.length; i++){ |
---|
145 | states[i] = map[states[i]] !== undefined ? map[states[i]] : false; |
---|
146 | } |
---|
147 | this._set("states", states); |
---|
148 | } |
---|
149 | }, |
---|
150 | |
---|
151 | _setReadOnlyAttr: function(/*Boolean*/ value){ |
---|
152 | this._set("readOnly", value); |
---|
153 | domAttr.set(this.focusNode, "readOnly", value); |
---|
154 | }, |
---|
155 | |
---|
156 | _setValueAttr: function(/*String|Boolean*/ newValue, /*Boolean*/ priorityChange){ |
---|
157 | // summary: |
---|
158 | // Handler for value = attribute to constructor, and also calls to |
---|
159 | // set('value', val). |
---|
160 | // description: |
---|
161 | // During initialization, just saves as attribute to the `<input type=checkbox>`. |
---|
162 | // |
---|
163 | // After initialization, |
---|
164 | // when passed a boolean or the string 'mixed', controls the state of the |
---|
165 | // TriStateCheckBox. |
---|
166 | // If passed a string except 'mixed', changes the value attribute of the |
---|
167 | // TriStateCheckBox. Sets the state of the TriStateCheckBox to checked. |
---|
168 | if(typeof newValue == "string" && (array.indexOf(this.states, newValue) < 0)){ |
---|
169 | if(newValue == ""){ |
---|
170 | newValue = "on"; |
---|
171 | } |
---|
172 | this.stateValues["True"] = newValue; |
---|
173 | newValue = true; |
---|
174 | } |
---|
175 | if(this._created){ |
---|
176 | this._currentState = array.indexOf(this.states, newValue); |
---|
177 | this.set('checked', newValue, priorityChange); |
---|
178 | domAttr.set(this.focusNode, "value", this.stateValues[this._stateType]); |
---|
179 | } |
---|
180 | }, |
---|
181 | |
---|
182 | _setValuesAttr: function(/*Array*/ newValues){ |
---|
183 | // summary: |
---|
184 | // Handler for values = attribute to constructor, and also calls to |
---|
185 | // set('values', val). |
---|
186 | // newValues: |
---|
187 | // If the length of newValues is 1, it will replace the value of |
---|
188 | // the TriStateCheckBox in true state. Otherwise, the values of |
---|
189 | // the TriStateCheckBox in true state and 'mixed' state will be |
---|
190 | // replaced by the first two values in newValues. |
---|
191 | // description: |
---|
192 | // Change the value of the TriStateCheckBox in 'mixed' and true states. |
---|
193 | this.stateValues["True"] = newValues[0] ? newValues[0] : this.stateValues["True"]; |
---|
194 | this.stateValues["Mixed"] = newValues[1] ? newValues[1] : this.stateValues["Mixed"]; |
---|
195 | }, |
---|
196 | |
---|
197 | _getValueAttr: function(){ |
---|
198 | // summary: |
---|
199 | // Hook so get('value') works. |
---|
200 | // description: |
---|
201 | // Returns value according to current state of the TriStateCheckBox. |
---|
202 | return this.stateValues[this._stateType]; |
---|
203 | }, |
---|
204 | |
---|
205 | reset: function(){ |
---|
206 | this._hasBeenBlurred = false; |
---|
207 | this.set("states", this.params.states || [false, "mixed", true]); |
---|
208 | this.stateValues = this.params.stateValues || { |
---|
209 | "False" : false, |
---|
210 | "True" : "on", |
---|
211 | "Mixed" : "mixed" |
---|
212 | }; |
---|
213 | this.set("values", this.params.values || []); |
---|
214 | this.set('checked', this.params.checked || this.states[0]); |
---|
215 | }, |
---|
216 | |
---|
217 | _onFocus: function(){ |
---|
218 | if(this.id){ |
---|
219 | query("label[for='"+this.id+"']").addClass("dijitFocusedLabel"); |
---|
220 | } |
---|
221 | this.inherited(arguments); |
---|
222 | }, |
---|
223 | |
---|
224 | _onBlur: function(){ |
---|
225 | if(this.id){ |
---|
226 | query("label[for='"+this.id+"']").removeClass("dijitFocusedLabel"); |
---|
227 | } |
---|
228 | this.mouseFocus = false; |
---|
229 | this.inherited(arguments); |
---|
230 | }, |
---|
231 | |
---|
232 | _onClick: function(/*Event*/ e){ |
---|
233 | // summary: |
---|
234 | // Internal function to handle click actions - need to check |
---|
235 | // readOnly and disabled |
---|
236 | if(this.readOnly || this.disabled){ |
---|
237 | event.stop(e); |
---|
238 | return false; |
---|
239 | } |
---|
240 | this.click(); |
---|
241 | return this.onClick(e); // user click actions |
---|
242 | }, |
---|
243 | |
---|
244 | click: function(){ |
---|
245 | // summary: |
---|
246 | // Emulate a click on the check box, but will not trigger the |
---|
247 | // onClick method. |
---|
248 | if(this._currentState >= this.states.length - 1){ |
---|
249 | this._currentState = 0; |
---|
250 | }else{ |
---|
251 | if(this._currentState == -1){ |
---|
252 | this.fixState(); |
---|
253 | }else{ |
---|
254 | this._currentState++; |
---|
255 | } |
---|
256 | } |
---|
257 | var oldState = this._currentState; |
---|
258 | this.set("checked", this.states[this._currentState]); |
---|
259 | this._currentState = oldState; |
---|
260 | domAttr.set(this.stateLabelNode, 'innerHTML', this._stateLabels[this._stateType]); |
---|
261 | }, |
---|
262 | |
---|
263 | fixState: function(){ |
---|
264 | // summary: |
---|
265 | // Fix _currentState property if it's out of bound. |
---|
266 | this._currentState = this.states.length - 1; |
---|
267 | }, |
---|
268 | |
---|
269 | _getStateType: function(/*String|Boolean*/ state){ |
---|
270 | // summary: |
---|
271 | // Internal function to return the type of a certain state: |
---|
272 | // |
---|
273 | // - false: False |
---|
274 | // - true: True |
---|
275 | // - "mixed": Mixed |
---|
276 | return state ? (state == "mixed" ? "Mixed" : "True") : "False"; |
---|
277 | }, |
---|
278 | |
---|
279 | _onMouseDown: function(){ |
---|
280 | this.mouseFocus = true; |
---|
281 | } |
---|
282 | }); |
---|
283 | |
---|
284 | }); |
---|