1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<style scoped>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith .yui3-js-enabled .yui3-checkboxes-loading { display: none; }
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<div class="intro">
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith Using Progressive Enhancement to skin checkboxes with the help of the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith <a href="../../api/Loader.html">Loader</a>,
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith <a href="../../api/module_classnamemanager.html">ClassNameManager
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith Utility</a>, and the Event Utility's <code>focus</code> and
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith <code>blur</code> events and the <code>delegate</code> method.
819e90d415ed17d59af3a247b2ad9d6feb0c21b5Luke Smith<div class="example yui3-skin-sam">
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith {{>focus-example-source}}
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<h2>Challenges</h2>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithThere are a few challenges when trying to skin an HTML checkbox using CSS. To start, most of the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<a href="http://developer.yahoo.com/yui/articles/gbs/#a-grade">A-grade browsers</a> don't provide
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithsupport for CSS properties like <code>border</code> and <code>background</code> on the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<code><input type="checkbox"></code> element. Additionally, IE 6 and IE 7 (Quirks Mode)
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithlack support for attribute selectors — necessary to style the <code>checked</code> and
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<code>disabled</code> states. Additionally, IE 6 and 7 only support the <code>:focus</code> and
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<code>:active</code> pseudo classes on <code><a></code> elements, both of which are needed
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithto style a checkbox when it is focused or depressed.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<h2>Approach</h2>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithDespite the shortcomings in CSS support, with a little extra markup and through the use of
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithJavaScript it is possible to skin an <code><input type="checkbox"></code> element
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithconsistently well in all of the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<a href="http://developer.yahoo.com/yui/articles/gbs/#a-grade">A-grade browsers</a>.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<h4>Markup</h4>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithSince CSS support for the <code><input type="checkbox"></code> element is lacking, wrap
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<code><input type="checkbox"></code> elements in one or more inline elements to provide the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithnecessary hooks for styling. In this example, each <code><input type="checkbox"></code>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithelement is wrapped by two <code><span></code>s.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith <input type="checkbox">
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithTo style each checkbox, a class name of <code>yui3-checkbox</code> will be applied to the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithouttermost <code><span></code> wrapping each <code><input type="checkbox"></code>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithelement. An additional class will be used to represent the various states of each checkbox. The
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithclass name for each state will follow a consistent pattern: <code>yui3-checkbox-[state]</code>.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithFor this example, the following state-based class names will be used:
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith <dt><code>yui3-checkbox-focus</code></dt>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith <dd>The checkbox has focus</dd>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith <dt><code>yui3-checkbox-active</code></dt>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith <dd>The checkbox is active (pressed)</dd>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith <dt><code>yui3-checkbox-checked</code></dt>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith <dd>The checkbox is checked</dd>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithThe styles for each checkbox comes together as follows:
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith.yui3-checkbox {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith display: -moz-inline-stack; /* Gecko < 1.9, since it doesn't support "inline-block" */
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith display: inline-block; /* IE, Opera and Webkit, and Gecko 1.9 */
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith width: 10px;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith height: 10px;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith border: inset 2px #999;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith background-color: #fff; /* Need to set a background color or IE won't get mouse events */
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith Necessary for IE 6 (Quirks and Standards Mode) and IE 7 (Quirks Mode), since
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith they don't support use of negative margins without relative positioning.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith _position: relative;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith.yui3-checkbox span {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith display: block;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith height: 14px;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith width: 12px;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith overflow: hidden;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith /* Position the checkmark for Gecko, Opera and Webkit and IE 7 (Strict Mode). */
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith margin: -5px 0 0 1px;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith /* Position the checkmark for IE 6 (Strict and Quirks Mode) and IE 7 (Quirks Mode).*/
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith _position: absolute;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith/* For Gecko < 1.9: Positions the checkbox on the same line as its corresponding label. */
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith.yui3-checkbox span:after {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith content: ".";
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith visibility: hidden;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith line-height: 2;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith Hide the actual checkbox offscreen so that it is out of view, but still accessible via
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith the keyboard.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith.yui3-checkbox input {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith position: absolute;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith left: -10000px;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith.yui3-checkbox-focus {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith border-color: #39f;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith background-color: #9cf;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith.yui3-checkbox-active {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith background-color: #ccc;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith.yui3-checkbox-checked span {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith /* Draw a custom checkmark for the checked state using a background image. */
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith background: url(checkmark.png) no-repeat;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<h4>JavaScript</h4>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithApplication and removal of the state-based class names will be facilitated by JavaScript event
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithhandlers. Each event handler will track the state of the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<code><input type="checkbox"></code> element, and apply and remove corresponding
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithstate-based class names from its outtermost <code><span></code> —
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithmaking it easy to style each state. And since each JavaScript is required for state management,
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smiththe stylesheet for the skinned checkboxes will only be added to the page when JavaScript is
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithenabled. This will ensure that each checkbox works correctly with and without JavaScript enabled.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithSince there could easily be many instances of a skinned checkbox on the page, all event
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithlisteners will be attached to the containing element for all checkboxes. Each listener will
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithlisten for events as they bubble up from each checkbox. Relying on event bubbling will improve the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithoverall performance of the page by reducing the number of event handlers.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithSince the DOM <code>focus</code> and <code>blur</code> events do not bubble, use the Event Utility's
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<a href="../../api/YUI.html#event_focus"><code>focus</code></a> and
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<a href="../../api/YUI.html#event_focus"><code>blur</code></a> custom events, as an alternative to
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithattaching discrete focus and blur event handlers to the <code><input type="checkbox"></code>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithelement of each skinned checkbox. The
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<a href="../../api/YUI.html#event_focus"><code>focus</code></a> and
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<a href="../../api/YUI.html#event_focus"><code>blur</code></a> custom events leverage
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithcapture-phase DOM event listeners, making it possible to attach a single focus and blur event
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithlistener on the containing element of each checkbox — thereby increasing the performance
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithof the page. The complete script for the example comes together as follows:
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithYUI().use("*", function(Y) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith sCheckboxFocusClass = getClassName("checkbox", "focus"), // Create yui3-checkbox-focus
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith sCheckboxCheckedClass = getClassName("checkbox", "checked"), // Create yui3-checkbox-checked
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith sCheckboxActiveClass = getClassName("checkbox", "active"), // Create yui3-checkbox-active
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith bKeyListenersInitialized = false,
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith bMouseListenersInitialized = false,
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith forAttr = (UA.ie && UA.ie < 8) ? "htmlFor" : "for",
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith bBlockDocumentMouseUp = false,
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith bBlockClearActive = false,
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith bBlockBlur = false,
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oActiveCheckbox;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var initKeyListeners = function () {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith this.delegate("keydown", onCheckboxKeyDown, ".yui3-checkbox");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith this.delegate("click", onCheckboxClick, ".yui3-checkbox");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith this.delegate("blur", onCheckboxBlur, "input[type=checkbox]");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith bKeyListenersInitialized = true;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var initMouseListeners = function () {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith this.delegate("mouseover", onCheckboxMouseOver, ".yui3-checkbox");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith this.delegate("mouseout", onCheckboxMouseOut, ".yui3-checkbox-active");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith this.get("ownerDocument").on("mouseup", onDocumentMouseUp);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith bMouseListenersInitialized = true;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var getCheckbox = function (node) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith return (node.hasClass("yui3-checkbox") ? node : node.ancestor(".yui3-checkbox"));
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var getCheckboxForLabel = function (label) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var sID = label.getAttribute(forAttr),
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oInput = Y.one("#" + sID);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if (oInput) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oCheckbox = getCheckbox(oInput);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith return oCheckbox;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var updateCheckedState = function (input) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var oCheckbox = getCheckbox(input);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if (input.get("checked")) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oCheckbox.addClass(sCheckboxCheckedClass);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oCheckbox.removeClass(sCheckboxCheckedClass);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var setActiveCheckbox = function (checkbox) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith checkbox.addClass(sCheckboxActiveClass);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oActiveCheckbox = checkbox;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var clearActiveCheckbox = function () {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if (oActiveCheckbox) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oActiveCheckbox.removeClass(sCheckboxActiveClass);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oActiveCheckbox = null;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var onCheckboxMouseOver = function (event, matchedEl) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if (oActiveCheckbox && oActiveCheckbox.compareTo(this)) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oActiveCheckbox.addClass(sCheckboxActiveClass);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var onCheckboxMouseOut = function (event) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith this.removeClass(sCheckboxActiveClass);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var onDocumentMouseUp = function (event) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var oCheckbox;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if (!bBlockDocumentMouseUp) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oCheckbox = getCheckbox(event.target);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if ((oCheckbox && !oCheckbox.compareTo(oActiveCheckbox)) || !oCheckbox) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith clearActiveCheckbox();
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith bBlockDocumentMouseUp = false;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var onCheckboxFocus = function (event) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // Remove the focus style from any checkbox that might still have it
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var oCheckbox = Y.one("#checkboxes").one(".yui3-checkbox-focus");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if (oCheckbox) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oCheckbox.removeClass(sCheckboxFocusClass);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // Defer adding key-related and click event listeners until
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // one of the checkboxes is initially focused.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if (!bKeyListenersInitialized) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var oCheckbox = getCheckbox(this);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oCheckbox.addClass(sCheckboxFocusClass);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var onCheckboxBlur = function (event) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if (bBlockBlur) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith bBlockBlur = false;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var oCheckbox = getCheckbox(this);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oCheckbox.removeClass(sCheckboxFocusClass);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if (!bBlockClearActive && oCheckbox.compareTo(oActiveCheckbox)) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith clearActiveCheckbox();
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith bBlockClearActive = false;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var onCheckboxMouseDown = function (event) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // Defer adding mouse-related and click event listeners until
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // the user mouses down on one of the checkboxes.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if (!bMouseListenersInitialized) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var oCheckbox,
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if (this.get("nodeName").toLowerCase() === "label") {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // If the target of the event was the checkbox's label element, the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // label will dispatch a click event to the checkbox, meaning the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // "onCheckboxClick" handler will be called twice. For that reason
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // it is necessary to block the "onDocumentMouseUp" handler from
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // clearing the active state, so that a reference to the active
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // checkbox still exists the second time the "onCheckboxClick"
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // handler is called.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith bBlockDocumentMouseUp = true;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // When the user clicks the label instead of the checkbox itself,
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // the checkbox will be blurred if it has focus. Since the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // "onCheckboxBlur" handler clears the active state it is
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // necessary to block the clearing of the active state when the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // label is clicked instead of the checkbox itself.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith bBlockClearActive = true;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oCheckbox = getCheckboxForLabel(this);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oCheckbox = this;
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // Need to focus the input manually for two reasons:
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // 1) Mousing down on a label in Webkit doesn't focus its
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // associated checkbox
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // 2) By default checkboxes are focused when the user mouses
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // down on them. However, since the actually checkbox is
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // obscurred by the two span elements that are used to
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // style it, the checkbox wont' receive focus as it was
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // never the actual target of the mousedown event.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oInput = oCheckbox.one("input");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // Calling Event.preventDefault won't block the blurring of the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // currently focused element in IE, so we'll use the "bBlockBlur"
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // variable to stop the code in the blur event handler
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // from executing.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith setActiveCheckbox(oCheckbox);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // Need to call preventDefault because by default mousing down on
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // an element will blur the element in the document that currently
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // has focus--in this case, the input element that was
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // just focused.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var onCheckboxClick = function (event) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith if (this.compareTo(oActiveCheckbox)) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith oInput = this.one("input");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // If the click event was fired via the mouse the checked
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // state will have to be manually updated since the input
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // is hidden offscreen and therefore couldn't be the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // target of the click.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith updateCheckedState(oInput);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith clearActiveCheckbox();
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith var onCheckboxKeyDown = function (event) {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // Style the checkbox as being active when the user presses the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // space bar
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith setActiveCheckbox(this);
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith Y.all("#checkboxes>div>span").addClass("yui3-checkbox");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // Remove the "yui3-checkboxes-loading" class used to hide the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // checkboxes now that the checkboxes have been skinned.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith Y.one("#checkboxes").removeClass("yui3-checkboxes-loading");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // Add the minimum number of event listeners needed to start, bind the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // rest when needed
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith Y.delegate("mousedown", onCheckboxMouseDown, "#checkboxes", ".yui3-checkbox,label");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith Y.delegate("focus", onCheckboxFocus, "#checkboxes", "input[type=checkbox]");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<h4>Progressive Enhancement</h4>
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithTo account for the scenario where the user has CSS enabled in their browser but JavaScript
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithis disabled, the CSS used to style the checkboxes will be loaded via JavaScript
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithusing the YUI instance's <a href="http://developer.yahoo.com/yui/3/yui#loader">built-in Loader</a>.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith base: "${buildDirectory}",
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // Load the stylesheet for the skinned checkboxes via JavaScript,
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // since without JavaScript skinning of the checkboxes wouldn't
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith // be possible.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith "checkboxcss": {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith type: "css",
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith fullpath: "${assetsDirectory}checkbox.css"
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith "checkboxjs": {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith fullpath: "${assetsDirectory}checkbox.js",
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith requires: ["classnamemanager", "event-focus", "node-event-delegate", "checkboxcss"]
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith}).use("checkboxjs");
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke SmithTo prevent the user from seeing a flash unstyled content when JavaScript is enabled,
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smitha style rule is created using YUI's <code>yui3-js-enabled</code> class name that will temporarily
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smithhide the markup while the JavaScript and CSS are in the process of loading. For more on using the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<code>yui3-js-enabled</code> class name, see the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<a href="../../widget/#progressive">HIDING PROGRESSIVELY ENHANCED MARKUP</a> section of the
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith<a href="../../widget/">YUI Widget landing page</a>.
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith.yui3-js-enabled .yui3-checkboxes-loading {
350964af8dfc6ab5df9d3fb0f274f7d018986c5bLuke Smith display: none;