|
1 /* |
|
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved. |
|
3 Code licensed under the BSD License: |
|
4 http://developer.yahoo.net/yui/license.txt |
|
5 version: 3.0.0b1 |
|
6 build: 1163 |
|
7 */ |
|
8 YUI.add('slider', function(Y) { |
|
9 |
|
10 /** |
|
11 * Create a sliding value range input visualized as a draggable thumb on a |
|
12 * background element. |
|
13 * |
|
14 * @module slider |
|
15 */ |
|
16 |
|
17 var SLIDER = 'slider', |
|
18 RAIL = 'rail', |
|
19 THUMB = 'thumb', |
|
20 VALUE = 'value', |
|
21 MIN = 'min', |
|
22 MAX = 'max', |
|
23 MIN_GUTTER = 'minGutter', |
|
24 MAX_GUTTER = 'maxGutter', |
|
25 THUMB_IMAGE = 'thumbImage', |
|
26 RAIL_SIZE = 'railSize', |
|
27 CONTENT_BOX = 'contentBox', |
|
28 |
|
29 SLIDE_START = 'slideStart', |
|
30 SLIDE_END = 'slideEnd', |
|
31 |
|
32 THUMB_DRAG = 'thumbDrag', |
|
33 SYNC = 'sync', |
|
34 POSITION_THUMB = 'positionThumb', |
|
35 RENDERED = 'rendered', |
|
36 DISABLED = 'disabled', |
|
37 DISABLED_CHANGE = 'disabledChange', |
|
38 |
|
39 DOT = '.', |
|
40 PX = 'px', |
|
41 WIDTH = 'width', |
|
42 HEIGHT = 'height', |
|
43 COMPLETE = 'complete', |
|
44 |
|
45 L = Y.Lang, |
|
46 isBoolean= L.isBoolean, |
|
47 isString = L.isString, |
|
48 isNumber = L.isNumber, |
|
49 |
|
50 getCN = Y.ClassNameManager.getClassName, |
|
51 |
|
52 IMAGE = 'image', |
|
53 C_RAIL = getCN(SLIDER,RAIL), |
|
54 C_THUMB = getCN(SLIDER,THUMB), |
|
55 C_THUMB_IMAGE = getCN(SLIDER,THUMB,IMAGE), |
|
56 C_IMAGE_ERROR = getCN(SLIDER,IMAGE,'error'), |
|
57 |
|
58 M = Math, |
|
59 max = M.max, |
|
60 round = M.round, |
|
61 floor = M.floor; |
|
62 |
|
63 /** |
|
64 * Create a slider to represent an integer value between a given minimum and |
|
65 * maximum. Sliders may be aligned vertically or horizontally, based on the |
|
66 * <code>axis</code> configuration. |
|
67 * |
|
68 * @class Slider |
|
69 * @extends Widget |
|
70 * @param config {Object} Configuration object |
|
71 * @constructor |
|
72 */ |
|
73 function Slider() { |
|
74 Slider.superclass.constructor.apply(this,arguments); |
|
75 } |
|
76 |
|
77 Y.mix(Slider, { |
|
78 |
|
79 /** |
|
80 * The identity of the widget. |
|
81 * |
|
82 * @property Slider.NAME |
|
83 * @type String |
|
84 * @static |
|
85 */ |
|
86 NAME : SLIDER, |
|
87 |
|
88 /** |
|
89 * Object property names used for respective X and Y axis Sliders (e.g. |
|
90 * "left" vs. "top" for placing the thumb according to |
|
91 * its representative value). |
|
92 * |
|
93 * @property Slider.AXIS_KEYS |
|
94 * @type Object |
|
95 * @protected |
|
96 * @static |
|
97 */ |
|
98 AXIS_KEYS : { |
|
99 x : { |
|
100 dim : WIDTH, |
|
101 offAxisDim : HEIGHT, |
|
102 eventPageAxis : 'pageX', |
|
103 ddStick : 'stickX', |
|
104 xyIndex : 0 |
|
105 }, |
|
106 y : { |
|
107 dim : HEIGHT, |
|
108 offAxisDim : WIDTH, |
|
109 eventPageAxis : 'pageY', |
|
110 ddStick : 'stickY', |
|
111 xyIndex : 1 |
|
112 } |
|
113 }, |
|
114 |
|
115 /** |
|
116 * Static Object hash used to capture existing markup for progressive |
|
117 * enhancement. Keys correspond to config attribute names and values |
|
118 * are selectors used to inspect the contentBox for an existing node |
|
119 * structure. |
|
120 * |
|
121 * @property Slider.HTML_PARSER |
|
122 * @type Object |
|
123 * @protected |
|
124 * @static |
|
125 */ |
|
126 HTML_PARSER : { |
|
127 rail : DOT + C_RAIL, |
|
128 thumb : DOT + C_THUMB, |
|
129 thumbImage : DOT + C_THUMB_IMAGE |
|
130 }, |
|
131 |
|
132 /** |
|
133 * Static property used to define the default attribute configuration of |
|
134 * the Widget. |
|
135 * |
|
136 * @property Slider.ATTRS |
|
137 * @type Object |
|
138 * @protected |
|
139 * @static |
|
140 */ |
|
141 ATTRS : { |
|
142 |
|
143 /** |
|
144 * Axis upon which the Slider's thumb moves. "x" for |
|
145 * horizontal, "y" for vertical. |
|
146 * |
|
147 * @attribute axis |
|
148 * @type String |
|
149 * @default "x" |
|
150 * @writeOnce |
|
151 */ |
|
152 axis : { |
|
153 value : 'x', |
|
154 writeOnce : true, |
|
155 validator : function (v) { |
|
156 return this._validateNewAxis(v); |
|
157 }, |
|
158 setter : function (v) { |
|
159 return this._setAxisFn(v); |
|
160 } |
|
161 }, |
|
162 |
|
163 /** |
|
164 * Value associated with the left or top most position of the thumb on |
|
165 * the rail. |
|
166 * |
|
167 * @attribute min |
|
168 * @type Number |
|
169 * @default 0 |
|
170 */ |
|
171 min : { |
|
172 value : 0, |
|
173 validator : function (v) { |
|
174 return this._validateNewMin(v); |
|
175 } |
|
176 }, |
|
177 |
|
178 /** |
|
179 * Value associated with the right or bottom most position of the thumb |
|
180 * on the rail. |
|
181 * |
|
182 * @attribute max |
|
183 * @type Number |
|
184 * @default 100 |
|
185 */ |
|
186 max : { |
|
187 value : 100, |
|
188 validator : function (v) { |
|
189 return this._validateNewMax(v); |
|
190 } |
|
191 }, |
|
192 |
|
193 /** |
|
194 * The current value of the Slider. This value is interpretted into a |
|
195 * position for the thumb along the Slider's rail. |
|
196 * |
|
197 * @attribute value |
|
198 * @type Number |
|
199 * @default 0 |
|
200 */ |
|
201 value : { |
|
202 value : 0, |
|
203 validator : function (v) { |
|
204 return this._validateNewValue(v); |
|
205 }, |
|
206 setter : function (v) { |
|
207 return this._setValueFn(v); |
|
208 } |
|
209 }, |
|
210 |
|
211 /** |
|
212 * The Node representing the Slider's rail, usually visualized as a |
|
213 * bar of some sort using a background image, along which the thumb |
|
214 * moves. This Node contains the thumb Node. |
|
215 * |
|
216 * @attribute rail |
|
217 * @type Node |
|
218 * @default null |
|
219 */ |
|
220 rail : { |
|
221 value : null, |
|
222 validator : function (v) { |
|
223 return this._validateNewRail(v); |
|
224 }, |
|
225 setter : function (v) { |
|
226 return this._setRailFn(v); |
|
227 } |
|
228 }, |
|
229 |
|
230 /** |
|
231 * <p>The Node representing the Slider's thumb, usually visualized as a |
|
232 * pointer using a contained image Node (see thumbImage). The current |
|
233 * value of the Slider is calculated from the centerpoint of this |
|
234 * Node in relation to the rail Node. If provided, the thumbImage |
|
235 * Node is contained within this Node.</p> |
|
236 * |
|
237 * <p>If no thumbImage is provided and the Node passed as the thumb is |
|
238 * an <code>img</code> element, the assigned Node will be allocated to |
|
239 * the thumbImage and the thumb container defaulted.</p> |
|
240 * |
|
241 * @attribute thumb |
|
242 * @type Node |
|
243 * @default null |
|
244 */ |
|
245 thumb : { |
|
246 value : null, |
|
247 validator : function (v) { |
|
248 return this._validateNewThumb(v); |
|
249 }, |
|
250 setter : function (v) { |
|
251 return this._setThumbFn(v); |
|
252 } |
|
253 }, |
|
254 |
|
255 /** |
|
256 * <p>The Node representing the image element to use for the Slider's |
|
257 * thumb.</p> |
|
258 * |
|
259 * <p>Alternately, an image URL can be passed and an <code>img</code> |
|
260 * Node will be generated accordingly.</p> |
|
261 * |
|
262 * <p>If no thumbImage is provided and the Node passed as the thumb is |
|
263 * an <code>img</code> element, the assigned Node will be allocated to |
|
264 * the thumbImage and the thumb container defaulted.</p> |
|
265 * |
|
266 * <p>If thumbImage is provided but its URL resolves to a 404, a default |
|
267 * style will be applied to maintain basic functionality.</p> |
|
268 * |
|
269 * @attribute thumbImage |
|
270 * @type Node|String |
|
271 * @default null |
|
272 */ |
|
273 thumbImage : { |
|
274 value : null, |
|
275 validator : function (v) { |
|
276 return this._validateNewThumbImage(v); |
|
277 }, |
|
278 setter : function (v) { |
|
279 return this._setThumbImageFn(v); |
|
280 } |
|
281 }, |
|
282 |
|
283 /** |
|
284 * <p>The width or height of the rail element representing the physical |
|
285 * space along which the thumb can move. CSS size values (e.g. '30em') |
|
286 * accepted but converted to pixels during render.</p> |
|
287 * |
|
288 * <p>Alternately, but not recommended, this attribute can be left |
|
289 * unassigned in favor of specifying height or width.</p> |
|
290 * |
|
291 * @attribute railSize |
|
292 * @type String |
|
293 * @default '0' |
|
294 */ |
|
295 railSize : { |
|
296 value : '0', |
|
297 validator : function (v) { |
|
298 return this._validateNewRailSize(v); |
|
299 } |
|
300 }, |
|
301 |
|
302 /** |
|
303 * Boolean indicating whether clicking and dragging on the rail will |
|
304 * trigger thumb movement. |
|
305 * |
|
306 * @attribute railEnabled |
|
307 * @type Boolean |
|
308 * @default true |
|
309 */ |
|
310 railEnabled : { |
|
311 value : true, |
|
312 validator : isBoolean |
|
313 }, |
|
314 |
|
315 /** |
|
316 * Like CSS padding, the distance in pixels from the inner top or left |
|
317 * edge of the rail node within which the thumb can travel. Negative |
|
318 * values allow the edge of the thumb to escape the rail node |
|
319 * boundaries. |
|
320 * |
|
321 * @attribute minGutter |
|
322 * @type Number |
|
323 * @default 0 |
|
324 */ |
|
325 minGutter : { |
|
326 value : 0, |
|
327 validator : isNumber |
|
328 }, |
|
329 |
|
330 /** |
|
331 * Like CSS padding, the distance in pixels from the inner bottom or |
|
332 * right edge of the rail node within which the thumb can travel. |
|
333 * Negative values allow the edge of the thumb to escape the rail node |
|
334 * boundaries. |
|
335 * |
|
336 * @attribute maxGutter |
|
337 * @type Number |
|
338 * @default 0 |
|
339 */ |
|
340 maxGutter : { |
|
341 value : 0, |
|
342 validator : isNumber |
|
343 } |
|
344 } |
|
345 }); |
|
346 |
|
347 Y.extend(Slider, Y.Widget, { |
|
348 |
|
349 /** |
|
350 * Collection of object property names from the appropriate hash set in |
|
351 * Slider.AXIS_KEYS. |
|
352 * |
|
353 * @property _key |
|
354 * @type Object |
|
355 * @protected |
|
356 */ |
|
357 _key : null, |
|
358 |
|
359 /** |
|
360 * Factor used to translate positional coordinates (e.g. left or top) to |
|
361 * the Slider's value. |
|
362 * |
|
363 * @property _factor |
|
364 * @type Number |
|
365 * @protected |
|
366 */ |
|
367 _factor : 1, |
|
368 |
|
369 /** |
|
370 * Pixel dimension of the rail Node's width for X axis Sliders or height |
|
371 * for Y axis Sliders. Used with _factor to calculate positional |
|
372 * coordinates for the thumb. |
|
373 * |
|
374 * @property _railSize |
|
375 * @type Number |
|
376 * @protected |
|
377 */ |
|
378 _railSize : null, |
|
379 |
|
380 /** |
|
381 * Pixel dimension of the thumb Node's width for X axis Sliders or height |
|
382 * for Y axis Sliders. Used with _factor to calculate positional |
|
383 * coordinates for the thumb. |
|
384 * |
|
385 * @property _thumbSize |
|
386 * @type Number |
|
387 * @protected |
|
388 */ |
|
389 _thumbSize : null, |
|
390 |
|
391 /** |
|
392 * Pixel offset of the point in the thumb element from its top/left edge |
|
393 * to where the value calculation should take place. By default, this is |
|
394 * calculated to half the width of the thumb, causing the value to be |
|
395 * marked from the center of the thumb. |
|
396 * |
|
397 * @property _thumbOffset |
|
398 * @type Number |
|
399 * @protected |
|
400 */ |
|
401 _thumbOffset : 0, |
|
402 |
|
403 /** |
|
404 * Object returned from temporary subscription to disabledChange event to |
|
405 * defer setting the disabled state while Slider is loading the thumb |
|
406 * image. |
|
407 * |
|
408 * @property _stall |
|
409 * @type Object |
|
410 * @protected |
|
411 */ |
|
412 _stall : false, |
|
413 |
|
414 /** |
|
415 * Deferred value for the disabled attribute when stalled (see _stall |
|
416 * property). |
|
417 * |
|
418 * @property _disabled |
|
419 * @type Boolean |
|
420 * @protected |
|
421 */ |
|
422 _disabled : false, |
|
423 |
|
424 /** |
|
425 * Construction logic executed durint Slider instantiation. Subscribes to |
|
426 * after events for min, max, and railSize. Publishes custom events |
|
427 * including slideStart and slideEnd. |
|
428 * |
|
429 * @method initializer |
|
430 * @protected |
|
431 */ |
|
432 initializer : function () { |
|
433 this._key = Slider.AXIS_KEYS[this.get('axis')]; |
|
434 |
|
435 this.after('minChange', this._afterMinChange); |
|
436 this.after('maxChange', this._afterMaxChange); |
|
437 |
|
438 this.after('railSizeChange', this._afterRailSizeChange); |
|
439 |
|
440 /** |
|
441 * Signals the beginning of a thumb drag operation. Payload includes |
|
442 * the DD.Drag instance's drag:start event under key ddEvent. |
|
443 * |
|
444 * @event slideStart |
|
445 * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added: |
|
446 * <dl> |
|
447 * <dt>ddEvent</dt> |
|
448 * <dd><code>drag:start</code> event from the managed DD.Drag instance</dd> |
|
449 * </dl> |
|
450 */ |
|
451 this.publish(SLIDE_START); |
|
452 |
|
453 /** |
|
454 * Signals the end of a thumb drag operation. Payload includes |
|
455 * the DD.Drag instance's drag:end event under key ddEvent. |
|
456 * |
|
457 * @event slideEnd |
|
458 * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added: |
|
459 * <dl> |
|
460 * <dt>ddEvent</dt> |
|
461 * <dd><code>drag:end</code> event from the managed DD.Drag instance</dd> |
|
462 * </dl> |
|
463 */ |
|
464 this.publish(SLIDE_END); |
|
465 |
|
466 /** |
|
467 * Communicates a request to synchronize the Slider UI with the |
|
468 * attribute state. Links the sync request with the default sync |
|
469 * logic in _defSyncFn. |
|
470 * |
|
471 * @event sync |
|
472 * @param event {Event.Facade} Event Facade object |
|
473 * @preventable _defSyncFn |
|
474 */ |
|
475 this.publish(SYNC, { defaultFn: this._defSyncFn }); |
|
476 |
|
477 /** |
|
478 * Signals a request to reposition the thumb in response to API methods. |
|
479 * Triggers the thumb placement logic in _defPositionThumbFn. |
|
480 * |
|
481 * @event positionThumb |
|
482 * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added: |
|
483 * <dl> |
|
484 * <dt>changeEv</dt> |
|
485 * <dd><code>valueChange</code> event fired in response to the change in the value attribute</dd> |
|
486 * </dl> |
|
487 * @preventable _defPositionThumbFn |
|
488 */ |
|
489 this.publish(POSITION_THUMB, { defaultFn: this._defPositionThumbFn }); |
|
490 }, |
|
491 |
|
492 /** |
|
493 * Create the DOM structure for the Slider. |
|
494 * |
|
495 * @method renderUI |
|
496 * @protected |
|
497 */ |
|
498 renderUI : function () { |
|
499 this._initRail(); |
|
500 this._initThumb(); |
|
501 }, |
|
502 |
|
503 /** |
|
504 * Creates the rail element if not provided and not discovered via |
|
505 * HTML_PARSER. |
|
506 * |
|
507 * @method _initRail |
|
508 * @protected |
|
509 */ |
|
510 _initRail : function () { |
|
511 var cb = this.get(CONTENT_BOX), |
|
512 rail = this.get(RAIL); |
|
513 |
|
514 // Create rail if necessary. Make sure it's in the contentBox |
|
515 if (!rail) { |
|
516 rail = cb.appendChild( |
|
517 Y.Node.create('<div class="'+C_RAIL+'"></div>')); |
|
518 |
|
519 this.set(RAIL,rail); |
|
520 } else if (!cb.contains(rail)) { |
|
521 cb.appendChild(rail); |
|
522 } |
|
523 |
|
524 rail.addClass(C_RAIL); |
|
525 rail.addClass(this.getClassName(RAIL,this.get('axis'))); |
|
526 }, |
|
527 |
|
528 /** |
|
529 * <p>Creates the thumb element (not image) if not provided and not |
|
530 * discovered via HTML_PARSER. If the thumb is an <code>img</code> element |
|
531 * but no thumbImage configured or discovered, reassigns the thumb element |
|
532 * to the thumbImage and defaults the thumb element as a div.</p> |
|
533 * |
|
534 * <p>Makes sure the thumb is a child of the rail element and calls |
|
535 * _initThumbImage if thumbImage is provided.</p> |
|
536 * |
|
537 * @method _initThumb |
|
538 * @protected |
|
539 */ |
|
540 _initThumb : function () { |
|
541 var rail = this.get(RAIL), |
|
542 thumb = this.get(THUMB); |
|
543 |
|
544 // Passed an img element as the thumb |
|
545 if (thumb && !this.get(THUMB_IMAGE) && |
|
546 thumb.get('nodeName').toLowerCase() === 'img') { |
|
547 this.set(THUMB_IMAGE, thumb); |
|
548 this.set(THUMB,null); |
|
549 thumb = null; |
|
550 } |
|
551 |
|
552 if (!thumb) { |
|
553 thumb = Y.Node.create( |
|
554 '<div class="'+C_THUMB+'"></div>'); |
|
555 |
|
556 this.set(THUMB,thumb); |
|
557 } |
|
558 |
|
559 thumb.addClass(C_THUMB); |
|
560 |
|
561 if (!rail.contains(thumb)) { |
|
562 rail.appendChild(thumb); |
|
563 } |
|
564 |
|
565 if (this.get(THUMB_IMAGE)) { |
|
566 this._initThumbImage(); |
|
567 } |
|
568 }, |
|
569 |
|
570 /** |
|
571 * Ensures the thumbImage is a child of the thumb element. |
|
572 * |
|
573 * @method _initThumbImage |
|
574 * @protected |
|
575 */ |
|
576 _initThumbImage : function () { |
|
577 var thumb = this.get(THUMB), |
|
578 img = this.get(THUMB_IMAGE); |
|
579 |
|
580 if (img) { |
|
581 img.replaceClass(C_THUMB,C_THUMB_IMAGE); |
|
582 |
|
583 if (!thumb.contains(img)) { |
|
584 thumb.appendChild(img); |
|
585 } |
|
586 } |
|
587 }, |
|
588 |
|
589 /** |
|
590 * Creates the Y.DD instance used to handle the thumb movement and binds |
|
591 * Slider interaction to the configured value model. |
|
592 * |
|
593 * @method bindUI |
|
594 * @protected |
|
595 */ |
|
596 bindUI : function () { |
|
597 /** |
|
598 * Bridges user interaction with the thumb to the value attribute. |
|
599 * |
|
600 * @event thumbDrag |
|
601 * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added: |
|
602 * <dl> |
|
603 * <dt>ddEvent</dt> |
|
604 * <dd><code>drag:drag</code> event from the managed DD.Drag instance</dd> |
|
605 * </dl> |
|
606 * @preventable _defUpdateValueFromDD |
|
607 */ |
|
608 this.publish(THUMB_DRAG, {defaultFn: this._defUpdateValueFromDD}); |
|
609 |
|
610 this._bindThumbDD(); |
|
611 |
|
612 this.after('valueChange', this._afterValueChange); |
|
613 this.after('thumbImageChange', this._afterThumbImageChange); |
|
614 this.after(DISABLED_CHANGE, this._afterDisabledChange); |
|
615 }, |
|
616 |
|
617 /** |
|
618 * Creates the Y.DD instance used to handle the thumb interaction. |
|
619 * |
|
620 * @method _bindThumbDD |
|
621 * @protected |
|
622 */ |
|
623 _bindThumbDD : function () { |
|
624 var ddConf = { |
|
625 node : this.get(THUMB), |
|
626 bubble : false |
|
627 }, |
|
628 conConf = { |
|
629 constrain2node : this.get(RAIL) |
|
630 }; |
|
631 |
|
632 conConf[this._key.ddStick] = true; |
|
633 |
|
634 this._dd = new Y.DD.Drag(ddConf).plug(Y.Plugin.DDConstrained, conConf); |
|
635 this._dd.on('drag:start', Y.bind(this._onDDStartDrag, this)); |
|
636 this._dd.on('drag:drag', Y.bind(this._onDDDrag, this)); |
|
637 this._dd.on('drag:end', Y.bind(this._onDDEndDrag, this)); |
|
638 |
|
639 this._initRailDD(); |
|
640 }, |
|
641 |
|
642 /** |
|
643 * Subscribes to the rail Node's mousedown event to actuate the thumb when |
|
644 * backgroundEnabled is true. |
|
645 * |
|
646 * @method _initRailDD |
|
647 * @protected |
|
648 */ |
|
649 _initRailDD : function () { |
|
650 this.get(RAIL).on('mousedown',Y.bind(this._handleRailMouseDown,this)); |
|
651 }, |
|
652 |
|
653 /** |
|
654 * If the Slider is not disabled and railEnabled is true, moves the thumb |
|
655 * to the mousedown position and hands control over to DD. |
|
656 * |
|
657 * @method _handleRailMouseDown |
|
658 * @param e {Event} Mousedown event facade |
|
659 * @protected |
|
660 */ |
|
661 _handleRailMouseDown : function (e) { |
|
662 if (this.get('railEnabled') && !this.get(DISABLED)) { |
|
663 var dd = this._dd, |
|
664 xyIndex = this._key.xyIndex, |
|
665 xy; |
|
666 |
|
667 if (dd.get('primaryButtonOnly') && e.button > 1) { |
|
668 Y.log('Mousedown was not produced by the primary button', |
|
669 'warn', 'dd-drag'); |
|
670 return false; |
|
671 } |
|
672 |
|
673 dd._dragThreshMet = true; |
|
674 |
|
675 dd._fixIEMouseDown(); |
|
676 e.halt(); |
|
677 |
|
678 Y.DD.DDM.activeDrag = dd; |
|
679 |
|
680 // Adjust registered starting position by half the thumb's x/y |
|
681 xy = dd.get('dragNode').getXY(); |
|
682 xy[xyIndex] += this._thumbOffset; |
|
683 |
|
684 dd._setStartPosition(xy); |
|
685 dd.set('activeHandle',dd.get('dragNode')); |
|
686 |
|
687 dd.start(); |
|
688 dd._alignNode([e.pageX,e.pageY]); |
|
689 } |
|
690 }, |
|
691 |
|
692 /** |
|
693 * Synchronizes the DOM state with the attribute settings (most notably |
|
694 * railSize and value). If thumbImage is provided and is still loading, |
|
695 * sync is delayed until it is complete, since the image's dimensions are |
|
696 * taken into consideration for calculations. |
|
697 * |
|
698 * @method syncUI |
|
699 */ |
|
700 syncUI : function () { |
|
701 this.get(CONTENT_BOX).removeClass(C_IMAGE_ERROR); |
|
702 |
|
703 var img = this.get(THUMB_IMAGE); |
|
704 |
|
705 if (this._isImageLoading(img)) { |
|
706 Y.log('Thumb image loading. Scheduling sync.','info','slider'); |
|
707 // Schedule the sync for when the image loads/errors |
|
708 this._scheduleSync(); |
|
709 } else { |
|
710 Y.log('No thumb image, or image already loaded. Syncing immediately.','info','slider'); |
|
711 this._ready(img,!this._isImageLoaded(img)); |
|
712 } |
|
713 }, |
|
714 |
|
715 /** |
|
716 * Binds to the load and error event on the thumbImage to sync the DOM |
|
717 * state with the attribute settings when the image resource is resolved. |
|
718 * The Slider is disabled while it waits. |
|
719 * |
|
720 * @method _scheduleSync |
|
721 * @protected |
|
722 */ |
|
723 _scheduleSync : function () { |
|
724 var img, handler; |
|
725 |
|
726 if (!this._stall) { |
|
727 // disable the control until the image is loaded |
|
728 this._disabled = this.get(DISABLED); |
|
729 this.set(DISABLED,true); |
|
730 this._stall = this.on(DISABLED_CHANGE,this._stallDisabledChange); |
|
731 |
|
732 img = this.get(THUMB_IMAGE); |
|
733 handler = Y.bind(this._imageLoaded,this,img); |
|
734 img.on('load', handler); |
|
735 img.on('error',handler); |
|
736 } |
|
737 }, |
|
738 |
|
739 /** |
|
740 * Method subscribed to the disabledChange event when thumbImage is being |
|
741 * loaded. Prevents manually enabling the Slider until the thumbImage |
|
742 * resource is resolved. Intended value is stored during load and set upon |
|
743 * completion. |
|
744 * |
|
745 * @method _stallDisabledChange |
|
746 * @param e {Event} Change event for the disabled attribute |
|
747 * @protected |
|
748 */ |
|
749 _stallDisabledChange : function (e) { |
|
750 this._disabled = e.newVal; |
|
751 e.preventDefault(); |
|
752 }, |
|
753 |
|
754 /** |
|
755 * Event handler assigned to the thumbImage's load and error event if it |
|
756 * was not loaded prior to instantiation. Restores the disabled value. |
|
757 * |
|
758 * @method _imageLoaded |
|
759 * @param img {Node} The thumbImage Node |
|
760 * @param e {Event} load or error event fired by the thumbImage |
|
761 * @protected |
|
762 */ |
|
763 _imageLoaded : function (img,e) { |
|
764 var error = (e.type.toLowerCase().indexOf('error') > -1); |
|
765 |
|
766 if (this._stall) { |
|
767 this._stall.detach(); |
|
768 } |
|
769 |
|
770 Y.log('Thumb image '+e.type+'ed. Syncing','info','slider'); |
|
771 |
|
772 this._stall = false; |
|
773 |
|
774 this._ready(img,error); |
|
775 |
|
776 this.set(DISABLED,this._disabled); |
|
777 }, |
|
778 |
|
779 /** |
|
780 * Applies a class to the content box if the thumbImage failed to resolve, |
|
781 * the fires the internal sync event triggering a sync between UI and |
|
782 * state. |
|
783 * |
|
784 * @method _ready |
|
785 * @param img {Node} the thumbImage Node |
|
786 * @param error {Boolean} Indicates an error while loading the thumbImage |
|
787 * @protected |
|
788 */ |
|
789 _ready : function (img,error) { |
|
790 var method = error ? 'addClass' : 'removeClass'; |
|
791 |
|
792 // If the thumb image url results in 404, assign a class to provide |
|
793 // default thumb dimensions/UI |
|
794 this.get(CONTENT_BOX)[method](C_IMAGE_ERROR); |
|
795 |
|
796 this.fire(SYNC); |
|
797 }, |
|
798 |
|
799 /** |
|
800 * The default synchronization behavior, updating the Slider's DOM state to |
|
801 * match the current attribute values. |
|
802 * |
|
803 * @method _defSyncFn |
|
804 * @param e {Event} Internal sync event |
|
805 * @protected |
|
806 */ |
|
807 _defSyncFn : function (e) { |
|
808 this._uiSetThumbSize(); |
|
809 |
|
810 this._setThumbOffset(); |
|
811 |
|
812 this._uiSetRailSize(); |
|
813 |
|
814 this._setRailOffsetXY(); |
|
815 |
|
816 this._setDDGutter(); |
|
817 |
|
818 this._resetDDCacheRegion(); |
|
819 |
|
820 this._setFactor(); |
|
821 |
|
822 var val = this.get(VALUE); |
|
823 |
|
824 this.fire(POSITION_THUMB, { |
|
825 value : val, |
|
826 offset : this._convertValueToOffset(val) |
|
827 }); |
|
828 |
|
829 // Forces a reflow of the bounding box to address IE8 inline-block |
|
830 // container not expanding correctly. bug 2527905 |
|
831 this.get('boundingBox').toggleClass(''); |
|
832 }, |
|
833 |
|
834 /** |
|
835 * Captures the thumb's pixel height or width (depending on the Slider's |
|
836 * axis) for use in positioning calculations. |
|
837 * |
|
838 * @method _uiSetThumbSize |
|
839 * @protected |
|
840 */ |
|
841 _uiSetThumbSize : function () { |
|
842 var thumb = this.get(THUMB), |
|
843 dim = this._key.dim, |
|
844 img = this.get(THUMB_IMAGE), |
|
845 size; |
|
846 |
|
847 // offsetWidth fails in hidden containers |
|
848 size = parseInt(thumb.getComputedStyle(dim),10); |
|
849 |
|
850 Y.log('thumb '+dim+': '+size+'px','info','slider'); |
|
851 |
|
852 if (img && this._isImageLoaded(img)) { |
|
853 Y.log('using thumbImage '+dim+' ('+img.get(dim)+') for _thumbSize','info','slider'); |
|
854 |
|
855 size = img.get(dim); |
|
856 } |
|
857 |
|
858 this._thumbSize = size; |
|
859 }, |
|
860 |
|
861 /** |
|
862 * Establishes the point in the thumb that should align to the rail |
|
863 * position representing the calculated value. |
|
864 * |
|
865 * @method _setThumbOffset |
|
866 * @protected |
|
867 */ |
|
868 _setThumbOffset : function () { |
|
869 this._thumbOffset = floor(this._thumbSize / 2); |
|
870 Y.log('_thumbOffset calculated to '+this._thumbOffset+'px','info','slider'); |
|
871 }, |
|
872 |
|
873 /** |
|
874 * Stores the rail Node's pixel height or width, depending on the Slider's |
|
875 * axis, for use in calculating thumb position from the value. |
|
876 * |
|
877 * @method _uiSetRailSize |
|
878 * @protected |
|
879 */ |
|
880 _uiSetRailSize : function () { |
|
881 var rail = this.get(RAIL), |
|
882 thumb = this.get(THUMB), |
|
883 img = this.get(THUMB_IMAGE), |
|
884 dim = this._key.dim, |
|
885 size = this.get(RAIL_SIZE), |
|
886 setxy = false; |
|
887 |
|
888 if (parseInt(size,10)) { |
|
889 Y.log('railSize provided: '+size,'info','slider'); |
|
890 |
|
891 // Convert to pixels |
|
892 rail.setStyle(dim,size); |
|
893 size = parseInt(rail.getComputedStyle(dim),10); |
|
894 |
|
895 Y.log('pixel '+dim+' of railSize: '+size+'px', 'info', 'slider'); |
|
896 } else { |
|
897 Y.log('defaulting railSize from max of computed style and configured '+dim+' attribute value', 'info', 'slider'); |
|
898 // Default from height or width (axis respective), or dims assigned |
|
899 // via css to the rail or thumb, whichever is largest. |
|
900 // Dear implementers, please use railSize, not height/width to |
|
901 // set the rail dims |
|
902 size = this.get(dim); |
|
903 if (parseInt(size,10)) { |
|
904 setxy = true; |
|
905 rail.setStyle(dim,size); |
|
906 size = parseInt(rail.getComputedStyle(dim),10); |
|
907 } |
|
908 size = max( |
|
909 size|0, |
|
910 parseInt(thumb.getComputedStyle(dim),10), |
|
911 parseInt(rail.getComputedStyle(dim),10)); |
|
912 |
|
913 Y.log('pixel '+dim+' of rail: '+size+'px', 'info', 'slider'); |
|
914 |
|
915 if (img && this._isImageLoaded(img)) { |
|
916 Y.log('using max of thumbImage '+dim+' ('+img.get(dim)+' and '+size+' for railSize', 'info', 'slider'); |
|
917 |
|
918 size = max(img.get(dim),size); |
|
919 } |
|
920 } |
|
921 |
|
922 rail.setStyle(dim, size + PX); |
|
923 |
|
924 this._railSize = size; |
|
925 |
|
926 // handle the (not recommended) fallback case of setting rail size via |
|
927 // widget height/width params. This is the only case that sets the |
|
928 // off-axis rail dim in the code. |
|
929 if (setxy) { |
|
930 dim = this._key.offAxisDim; |
|
931 size = this.get(dim); |
|
932 if (size) { |
|
933 rail.set(dim,size); |
|
934 } |
|
935 } |
|
936 }, |
|
937 |
|
938 /** |
|
939 * Store the current XY position of the rail Node on the page. For use in |
|
940 * calculating thumb position from value. |
|
941 * |
|
942 * @method _setRailOffsetXY |
|
943 * @protected |
|
944 */ |
|
945 _setRailOffsetXY : function () { |
|
946 this._offsetXY = this.get(RAIL).getXY()[this._key.xyIndex] + |
|
947 this.get(MIN_GUTTER); |
|
948 }, |
|
949 |
|
950 /** |
|
951 * Passes the gutter attribute value to the DDConstrain gutter attribute. |
|
952 * |
|
953 * @method _setDDGutter |
|
954 * @protected |
|
955 */ |
|
956 _setDDGutter : function () { |
|
957 var gutter = this._key.xyIndex ? |
|
958 this.get(MIN_GUTTER) + " 0 " + this.get(MAX_GUTTER) : |
|
959 "0 " + this.get(MAX_GUTTER) + " 0 " + this.get(MIN_GUTTER); |
|
960 |
|
961 Y.log('setting DDConstrain gutter "'+gutter+'"','info','slider'); |
|
962 |
|
963 this._dd.con.set('gutter', gutter); |
|
964 }, |
|
965 |
|
966 /** |
|
967 * Resets the cached region inside the DD constrain instance to support |
|
968 * repositioning the Slider after instantiation. |
|
969 * |
|
970 * @method _resetDDCacheRegion |
|
971 * @protected |
|
972 */ |
|
973 _resetDDCacheRegion : function () { |
|
974 // Workaround for ticket #2527964 |
|
975 this._dd.con._cacheRegion(); |
|
976 }, |
|
977 |
|
978 /** |
|
979 * Calculates the multiplier used to translate the value into a thumb |
|
980 * position. |
|
981 * |
|
982 * @method _setFactor |
|
983 * @protected |
|
984 */ |
|
985 _setFactor : function () { |
|
986 var range = this._railSize - this._thumbSize - |
|
987 this.get(MIN_GUTTER) - this.get(MAX_GUTTER); |
|
988 |
|
989 this._factor = this._railSize ? |
|
990 (this.get(MAX) - this.get(MIN)) / range : |
|
991 1; |
|
992 |
|
993 Y.log('_factor set to '+this._factor,'info','slider'); |
|
994 }, |
|
995 |
|
996 /** |
|
997 * Convenience method for accessing the current value of the Slider. |
|
998 * Equivalent to <code>slider.get("value")</code>. |
|
999 * |
|
1000 * @method getValue |
|
1001 * @return {Number} the value |
|
1002 */ |
|
1003 getValue : function () { |
|
1004 return this.get(VALUE); |
|
1005 }, |
|
1006 |
|
1007 /** |
|
1008 * Convenience method for updating the current value of the Slider. |
|
1009 * Equivalent to <code>slider.set("value",val)</code>. |
|
1010 * |
|
1011 * @method setValue |
|
1012 * @param val {Number} the new value |
|
1013 */ |
|
1014 setValue : function (val) { |
|
1015 this.set(VALUE,val); |
|
1016 }, |
|
1017 |
|
1018 /** |
|
1019 * Validator applied to new values for the axis attribute. Only |
|
1020 * "x" and "y" are permitted. |
|
1021 * |
|
1022 * @method _validateNewAxis |
|
1023 * @param v {String} proposed value for the axis attribute |
|
1024 * @return Boolean |
|
1025 * @protected |
|
1026 */ |
|
1027 _validateNewAxis : function (v) { |
|
1028 return isString(v) && 'xXyY'.indexOf(v.charAt(0)) > -1; |
|
1029 }, |
|
1030 |
|
1031 /** |
|
1032 * Validator applied to the min attribute. |
|
1033 * |
|
1034 * @method _validateNewMin |
|
1035 * @param v {MIXED} proposed value for the min attribute |
|
1036 * @return Boolean |
|
1037 * @protected |
|
1038 */ |
|
1039 _validateNewMin : function (v) { |
|
1040 return isNumber(v); |
|
1041 }, |
|
1042 |
|
1043 /** |
|
1044 * Validator applied to the max attribute. |
|
1045 * |
|
1046 * @method _validateNewMax |
|
1047 * @param v {MIXED} proposed value for the max attribute |
|
1048 * @return Boolean |
|
1049 * @protected |
|
1050 */ |
|
1051 _validateNewMax : function (v) { |
|
1052 return isNumber(v); |
|
1053 }, |
|
1054 |
|
1055 /** |
|
1056 * Validator applied to the value attribute. |
|
1057 * |
|
1058 * @method _validateNewValue |
|
1059 * @param v {MIXED} proposed value for the value attribute |
|
1060 * @return Boolean |
|
1061 * @protected |
|
1062 */ |
|
1063 _validateNewValue : function (v) { |
|
1064 var min = this.get(MIN), |
|
1065 max = this.get(MAX); |
|
1066 |
|
1067 return isNumber(v) && |
|
1068 (min < max ? (v >= min && v <= max) : (v >= max && v <= min)); |
|
1069 }, |
|
1070 |
|
1071 /** |
|
1072 * Validator applied to the rail attribute. Rejects all values after the |
|
1073 * Slider has been rendered. |
|
1074 * |
|
1075 * @method _validateNewRail |
|
1076 * @param v {MIXED} proposed value for the rail attribute |
|
1077 * @return Boolean |
|
1078 * @protected |
|
1079 */ |
|
1080 _validateNewRail : function (v) { |
|
1081 return !this.get(RENDERED) || v; |
|
1082 }, |
|
1083 |
|
1084 /** |
|
1085 * Validator applied to the thumb attribute. Rejects all values after the |
|
1086 * Slider has been rendered. |
|
1087 * |
|
1088 * @method _validateNewThumb |
|
1089 * @param v {MIXED} proposed value for the thumb attribute |
|
1090 * @return Boolean |
|
1091 * @protected |
|
1092 */ |
|
1093 _validateNewThumb : function (v) { |
|
1094 return !this.get(RENDERED) || v; |
|
1095 }, |
|
1096 |
|
1097 /** |
|
1098 * Validator applied to the thumbImage attribute. Rejects all values after |
|
1099 * the Slider has been rendered. |
|
1100 * |
|
1101 * @method _validateNewThumbImage |
|
1102 * @param v {MIXED} proposed value for the thumbImage attribute |
|
1103 * @return Boolean |
|
1104 * @protected |
|
1105 */ |
|
1106 _validateNewThumbImage : function (v) { |
|
1107 return !this.get(RENDERED) || v; |
|
1108 }, |
|
1109 |
|
1110 /** |
|
1111 * Validator applied to the railSize attribute. Only strings of css size |
|
1112 * values (e.g. '200px') are allowed. |
|
1113 * |
|
1114 * @method _validateNewRailSize |
|
1115 * @param v {String} proposed value for the railSize attribute |
|
1116 * @return Boolean |
|
1117 * @protected |
|
1118 */ |
|
1119 _validateNewRailSize : function (v) { |
|
1120 return isString(v) && |
|
1121 (v === '0' || /^\d+(?:p[xtc]|%|e[mx]|in|[mc]m)$/.test(v)); |
|
1122 }, |
|
1123 |
|
1124 /** |
|
1125 * Setter applied to the input when updating the axis attribute. |
|
1126 * |
|
1127 * @method _setAxisFn |
|
1128 * @param v {String} proposed value for the axis attribute |
|
1129 * @return {String} lowercased first character of the input string |
|
1130 * @protected |
|
1131 */ |
|
1132 _setAxisFn : function (v) { |
|
1133 return v.charAt(0).toLowerCase(); |
|
1134 }, |
|
1135 |
|
1136 /** |
|
1137 * Setter applied to the input when updating the value attribute. This is |
|
1138 * just a placeholder for extension. |
|
1139 * |
|
1140 * @method _setValueFn |
|
1141 * @param v {Number} proposed new value for the Slider |
|
1142 * @return {Number} rounded value or configured min if non-number input |
|
1143 * @protected |
|
1144 */ |
|
1145 _setValueFn : function (v) { return v; }, |
|
1146 |
|
1147 /** |
|
1148 * Setter applied to the input when updating the rail attribute. Input can |
|
1149 * be a Node, raw HTMLElement, or a selector string to locate it. |
|
1150 * |
|
1151 * @method _setRailFn |
|
1152 * @param v {Node|String|HTMLElement} The rail element Node or selector |
|
1153 * @return {Node} The Node if found. Otherwise null. |
|
1154 * @protected |
|
1155 */ |
|
1156 _setRailFn : function (v) { |
|
1157 return Y.get(v) || null; |
|
1158 }, |
|
1159 |
|
1160 /** |
|
1161 * Setter applied to the input when updating the thumb attribute. Input can |
|
1162 * be a Node, raw HTMLElement, or a selector string to locate it. |
|
1163 * |
|
1164 * @method _setThumbFn |
|
1165 * @param v {Node|String|HTMLElement} The thumb element Node or selector |
|
1166 * @return {Node} The Node if found. Otherwise null. |
|
1167 * @protected |
|
1168 */ |
|
1169 _setThumbFn : function (v) { |
|
1170 return Y.get(v) || null; |
|
1171 }, |
|
1172 |
|
1173 /** |
|
1174 * Setter applied to the input when updating the thumbImage attribute. |
|
1175 * Input can be a Node, raw HTMLElement, selector string to locate it, or |
|
1176 * the URL for an image resource. |
|
1177 * |
|
1178 * String input will be treated as a selector. If no element is found using |
|
1179 * the selector, an <code>img</code> Node will be created with the string |
|
1180 * used as the <code>src</code> attribute. |
|
1181 * |
|
1182 * @method _setThumbImageFn |
|
1183 * @param v {Node|String|HTMLElement} The thumbImage element Node, selector, |
|
1184 * or image URL |
|
1185 * @return {Node} The Node if found or created. Otherwise null. |
|
1186 * @protected |
|
1187 */ |
|
1188 _setThumbImageFn : function (v) { |
|
1189 return v ? Y.get(v) || |
|
1190 Y.Node.create('<img src="'+v+'" alt="Slider thumb">') : |
|
1191 null; |
|
1192 }, |
|
1193 |
|
1194 |
|
1195 /** |
|
1196 * Caches the current page position of the rail element and fires the |
|
1197 * slideStart event in response to the DD's drag:start. |
|
1198 * |
|
1199 * @method _onDDStartDrag |
|
1200 * @param e {Event} the DD instance's drag:start custom event |
|
1201 * @protected |
|
1202 */ |
|
1203 _onDDStartDrag : function (e) { |
|
1204 Y.log('slide start','info','slider'); |
|
1205 this._setRailOffsetXY(); |
|
1206 this.fire(SLIDE_START,{ ddEvent: e }); |
|
1207 }, |
|
1208 |
|
1209 /** |
|
1210 * Fires the thumbDrag event to queue Slider value update. |
|
1211 * |
|
1212 * @method _onDDDrag |
|
1213 * @param e {Event} the DD instance's drag:drag custom event |
|
1214 * @protected |
|
1215 */ |
|
1216 _onDDDrag : function (e) { |
|
1217 Y.log('thumb drag','info','slider'); |
|
1218 this.fire(THUMB_DRAG, { ddEvent: e }); |
|
1219 }, |
|
1220 |
|
1221 /** |
|
1222 * The default value update behavior in response to Slider thumb |
|
1223 * interaction. Calculates the value using stored offsets, the _factor |
|
1224 * multiplier and the min value. |
|
1225 * |
|
1226 * @method _defUpdateValueFromDD |
|
1227 * @param e {Event} the internal thumbDrag event |
|
1228 * @protected |
|
1229 */ |
|
1230 _defUpdateValueFromDD : function (e) { |
|
1231 var before = this.get(VALUE), |
|
1232 val = e.ddEvent[this._key.eventPageAxis] - this._offsetXY; |
|
1233 |
|
1234 Y.log('setting value from thumb drag: before('+before+') raw('+val+') factored('+round(this.get(MIN) + (val * this._factor))+')', 'info','slider'); |
|
1235 |
|
1236 val = round(this.get(MIN) + (val * this._factor)); |
|
1237 |
|
1238 if (before !== val) { |
|
1239 this.set(VALUE, val, { ddEvent: e.ddEvent }); |
|
1240 } |
|
1241 }, |
|
1242 |
|
1243 /** |
|
1244 * Fires the slideEnd event. |
|
1245 * |
|
1246 * @method _onDDEndDrag |
|
1247 * @param e {Event} the DD instance's drag:end custom event |
|
1248 * @protected |
|
1249 */ |
|
1250 _onDDEndDrag : function (e) { |
|
1251 Y.log('slide end','info','slider'); |
|
1252 this.fire(SLIDE_END,{ ddEvent: e }); |
|
1253 }, |
|
1254 |
|
1255 |
|
1256 |
|
1257 |
|
1258 /** |
|
1259 * Calls _uiPositionThumb with the value of the custom event's |
|
1260 * "offset" property. |
|
1261 * |
|
1262 * @method _defPositionThumbFn |
|
1263 * @param e {Event} the positionThumb custom event |
|
1264 * @protected |
|
1265 */ |
|
1266 _defPositionThumbFn : function (e) { |
|
1267 Y.log('setting thumb offset ('+e.offset+') from value attribute update ('+e.value+')', 'info', 'slider'); |
|
1268 |
|
1269 this._uiPositionThumb(e.offset); |
|
1270 }, |
|
1271 |
|
1272 /** |
|
1273 * Places the thumb at a particular X or Y location based on the configured |
|
1274 * axis. |
|
1275 * |
|
1276 * @method _uiPositionThumb |
|
1277 * @param xy {Number} the desired left or top pixel position of the thumb |
|
1278 * in relation to the rail Node. |
|
1279 * @protected |
|
1280 */ |
|
1281 _uiPositionThumb : function (xy) { |
|
1282 var dd = this._dd, |
|
1283 thumb = dd.get('dragNode'), |
|
1284 hidden = thumb.ancestor(this._isDisplayNone); |
|
1285 |
|
1286 if (!hidden) { |
|
1287 dd._setStartPosition(dd.get('dragNode').getXY()); |
|
1288 |
|
1289 // stickX/stickY config on DD instance will negate off-axis move |
|
1290 dd._alignNode([xy,xy],true); |
|
1291 } |
|
1292 }, |
|
1293 |
|
1294 /** |
|
1295 * Helper function to search up the ancestor axis looking for a node with |
|
1296 * style display: none. This is passed as a function to node.ancestor(..) |
|
1297 * to test if a given node is in the displayed DOM and can get accurate |
|
1298 * positioning information. |
|
1299 * |
|
1300 * @method _isDisplayNone |
|
1301 * @param el {Node} ancestor node as the function walks up the parent axis |
|
1302 * @return {Boolean} true if the node is styled with display: none |
|
1303 * @protected |
|
1304 */ |
|
1305 _isDisplayNone : function (node) { |
|
1306 return node.getComputedStyle('display') === 'none'; |
|
1307 }, |
|
1308 |
|
1309 /** |
|
1310 * Fires the internal positionThumb event in response to a change in the |
|
1311 * value attribute. |
|
1312 * |
|
1313 * @method _afterValueChange |
|
1314 * @param e {Event} valueChange custom event |
|
1315 * @protected |
|
1316 */ |
|
1317 _afterValueChange : function (e) { |
|
1318 if (!e.ddEvent) { |
|
1319 var xy = this._convertValueToOffset(e.newVal); |
|
1320 |
|
1321 Y.log('firing positionThumb to position thumb', 'info', 'slider'); |
|
1322 |
|
1323 this.fire(POSITION_THUMB,{ value: e.newVal, offset: xy }); |
|
1324 } |
|
1325 }, |
|
1326 |
|
1327 /** |
|
1328 * Converts a value to an integer offset for the thumb position on the rail. |
|
1329 * |
|
1330 * @method _convertValueToOffset |
|
1331 * @param v {Number} value between the Slider's min and max |
|
1332 * @protected |
|
1333 */ |
|
1334 _convertValueToOffset : function (v) { |
|
1335 return round((v - this.get(MIN)) / this._factor) + this._offsetXY; |
|
1336 }, |
|
1337 |
|
1338 /** |
|
1339 * Replaces the thumb Node in response to a change in the thumb attribute. |
|
1340 * This only has effect after the Slider is rendered. |
|
1341 * |
|
1342 * @method _afterThumbChange |
|
1343 * @param e {Event} thumbChange custom event |
|
1344 * @protected |
|
1345 */ |
|
1346 _afterThumbChange : function (e) { |
|
1347 var thumb; |
|
1348 |
|
1349 if (this.get(RENDERED)) { |
|
1350 if (e.prevValue) { |
|
1351 e.prevValue.get('parentNode').removeChild(e.prevValue); |
|
1352 } |
|
1353 |
|
1354 this._initThumb(); |
|
1355 |
|
1356 thumb = this.get(THUMB); |
|
1357 this._dd.set('node',thumb); |
|
1358 this._dd.set('dragNode',thumb); |
|
1359 |
|
1360 this.syncUI(); |
|
1361 } |
|
1362 }, |
|
1363 |
|
1364 /** |
|
1365 * Sets or replaces the thumb's contained <code>img</code> Node with the |
|
1366 * new Node in response to a change in the thumbImage attribute. This only |
|
1367 * has effect after the Slider is rendered. |
|
1368 * |
|
1369 * @method _afterThumbImageChange |
|
1370 * @param e {Event} thumbImageChange custom event |
|
1371 * @protected |
|
1372 */ |
|
1373 _afterThumbImageChange : function (e) { |
|
1374 if (this.get(RENDERED)) { |
|
1375 if (e.prevValue) { |
|
1376 e.prevValue.get('parentNode').removeChild(e.prevValue); |
|
1377 } |
|
1378 |
|
1379 this._initThumbImage(); |
|
1380 |
|
1381 this.syncUI(); |
|
1382 } |
|
1383 }, |
|
1384 |
|
1385 /** |
|
1386 * Updates the Slider UI in response to change in the min attribute. |
|
1387 * |
|
1388 * @method _afterMinChange |
|
1389 * @param e {Event} minChange custom event |
|
1390 * @protected |
|
1391 */ |
|
1392 _afterMinChange : function (e) { |
|
1393 this._refresh(e); |
|
1394 }, |
|
1395 |
|
1396 /** |
|
1397 * Updates the Slider UI in response to change in the max attribute. |
|
1398 * |
|
1399 * @method _afterMaxChange |
|
1400 * @param e {Event} maxChange custom event |
|
1401 * @protected |
|
1402 */ |
|
1403 _afterMaxChange : function (e) { |
|
1404 this._refresh(e); |
|
1405 }, |
|
1406 |
|
1407 /** |
|
1408 * Updates the Slider UI in response to change in the railSize attribute. |
|
1409 * |
|
1410 * @method _afterRailSizeChange |
|
1411 * @param e {Event} railSizeChange custom event |
|
1412 * @protected |
|
1413 */ |
|
1414 _afterRailSizeChange : function (e) { |
|
1415 this._refresh(e); |
|
1416 }, |
|
1417 |
|
1418 /** |
|
1419 * Locks or unlocks the DD instance in response to a change in the disabled |
|
1420 * attribute. |
|
1421 * |
|
1422 * @method _afterDisabledChange |
|
1423 * @param e {Event} disabledChange custom event |
|
1424 * @protected |
|
1425 */ |
|
1426 _afterDisabledChange : function (e) { |
|
1427 if (this._dd) { |
|
1428 this._dd.set('lock',e.newVal); |
|
1429 } |
|
1430 }, |
|
1431 |
|
1432 /** |
|
1433 * Common handler to call syncUI in response to change events that occurred |
|
1434 * after the Slider is rendered. |
|
1435 * |
|
1436 * @method _refresh |
|
1437 * @param e {Event} An attribute change event |
|
1438 * @protected |
|
1439 */ |
|
1440 _refresh : function (e) { |
|
1441 if (e.newVal !== e.prevVal && this.get(RENDERED)) { |
|
1442 this.syncUI(); |
|
1443 } |
|
1444 }, |
|
1445 |
|
1446 /** |
|
1447 * Used to determine if there is a current or pending request for the |
|
1448 * thumbImage resource. |
|
1449 * |
|
1450 * @method _isImageLoading |
|
1451 * @param img {Node} <code>img</code> Node |
|
1452 * @return Boolean |
|
1453 * @protected |
|
1454 */ |
|
1455 _isImageLoading : function (img) { |
|
1456 return img && !img.get(COMPLETE); |
|
1457 }, |
|
1458 |
|
1459 /** |
|
1460 * Used to determine if the image resource loaded successfully or there was |
|
1461 * an error. |
|
1462 * |
|
1463 * NOTES: |
|
1464 * <ul> |
|
1465 * <li>img load error fired xbrowser for image resources not yet resolved</li> |
|
1466 * <li>img.complete reports false in IE for images not yet loaded as well as images that failed to load</li> |
|
1467 * <li>img.complete true && img.naturalWidth == 0 in FF and Safari indicate image failed to load</li> |
|
1468 * <li>img.complete && img.width == 0 in Opera indicates image failed to load</li> |
|
1469 * </ul> |
|
1470 * |
|
1471 * @method _isImageLoaded |
|
1472 * @param img {Node} <code>img</code> Node |
|
1473 * @return Boolean |
|
1474 * @protected |
|
1475 */ |
|
1476 _isImageLoaded : function (img) { |
|
1477 if (img) { |
|
1478 var w = img.get('naturalWidth'); |
|
1479 return img.get(COMPLETE) && (!isNumber(w) ? img.get(WIDTH) : w); |
|
1480 } |
|
1481 |
|
1482 return true; |
|
1483 } |
|
1484 |
|
1485 }); |
|
1486 |
|
1487 Y.Slider = Slider; |
|
1488 |
|
1489 |
|
1490 }, '3.0.0b1' ,{requires:['widget','dd-constrain']}); |