2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
8 YUI.add('slider', function(Y) {
11 * Create a sliding value range input visualized as a draggable thumb on a
17 var SLIDER = 'slider',
23 MIN_GUTTER = 'minGutter',
24 MAX_GUTTER = 'maxGutter',
25 THUMB_IMAGE = 'thumbImage',
26 RAIL_SIZE = 'railSize',
27 CONTENT_BOX = 'contentBox',
29 SLIDE_START = 'slideStart',
30 SLIDE_END = 'slideEnd',
32 THUMB_DRAG = 'thumbDrag',
34 POSITION_THUMB = 'positionThumb',
35 RENDERED = 'rendered',
36 DISABLED = 'disabled',
37 DISABLED_CHANGE = 'disabledChange',
43 COMPLETE = 'complete',
46 isBoolean= L.isBoolean,
47 isString = L.isString,
48 isNumber = L.isNumber,
50 getCN = Y.ClassNameManager.getClassName,
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'),
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.
70 * @param config {Object} Configuration object
74 Slider.superclass.constructor.apply(this,arguments);
80 * The identity of the widget.
82 * @property Slider.NAME
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).
93 * @property Slider._AXIS_KEYS
102 eventPageAxis : 'pageX',
109 eventPageAxis : 'pageY',
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
121 * @property Slider.HTML_PARSER
128 thumb : DOT + C_THUMB,
129 thumbImage : DOT + C_THUMB_IMAGE
133 * Static property used to define the default attribute configuration of
136 * @property Slider.ATTRS
144 * Axis upon which the Slider's thumb moves. "x" for
145 * horizontal, "y" for vertical.
149 * @default "x"
155 validator : function (v) {
156 return this._validateNewAxis(v);
158 setter : function (v) {
159 return this._setAxisFn(v);
164 * Value associated with the left or top most position of the thumb on
173 validator : function (v) {
174 return this._validateNewMin(v);
179 * Value associated with the right or bottom most position of the thumb
188 validator : function (v) {
189 return this._validateNewMax(v);
194 * The current value of the Slider. This value is interpretted into a
195 * position for the thumb along the Slider's rail.
203 validator : function (v) {
204 return this._validateNewValue(v);
209 * The Node representing the Slider's rail, usually visualized as a
210 * bar of some sort using a background image, along which the thumb
211 * moves. This Node contains the thumb Node.
219 validator : function (v) {
220 return this._validateNewRail(v);
222 setter : function (v) {
223 return this._setRailFn(v);
228 * <p>The Node representing the Slider's thumb, usually visualized as a
229 * pointer using a contained image Node (see thumbImage). The current
230 * value of the Slider is calculated from the centerpoint of this
231 * Node in relation to the rail Node. If provided, the thumbImage
232 * Node is contained within this Node.</p>
234 * <p>If no thumbImage is provided and the Node passed as the thumb is
235 * an <code>img</code> element, the assigned Node will be allocated to
236 * the thumbImage and the thumb container defaulted.</p>
244 validator : function (v) {
245 return this._validateNewThumb(v);
247 setter : function (v) {
248 return this._setThumbFn(v);
253 * <p>The Node representing the image element to use for the Slider's
256 * <p>Alternately, an image URL can be passed and an <code>img</code>
257 * Node will be generated accordingly.</p>
259 * <p>If no thumbImage is provided and the Node passed as the thumb is
260 * an <code>img</code> element, the assigned Node will be allocated to
261 * the thumbImage and the thumb container defaulted.</p>
263 * <p>If thumbImage is provided but its URL resolves to a 404, a default
264 * style will be applied to maintain basic functionality.</p>
266 * @attribute thumbImage
272 validator : function (v) {
273 return this._validateNewThumbImage(v);
275 setter : function (v) {
276 return this._setThumbImageFn(v);
281 * <p>The width or height of the rail element representing the physical
282 * space along which the thumb can move. CSS size values (e.g. '30em')
283 * accepted but converted to pixels during render.</p>
285 * <p>Alternately, but not recommended, this attribute can be left
286 * unassigned in favor of specifying height or width.</p>
288 * @attribute railSize
294 validator : function (v) {
295 return this._validateNewRailSize(v);
300 * Boolean indicating whether clicking and dragging on the rail will
301 * trigger thumb movement.
303 * @attribute railEnabled
309 validator : isBoolean
313 * Like CSS padding, the distance in pixels from the inner top or left
314 * edge of the rail node within which the thumb can travel. Negative
315 * values allow the edge of the thumb to escape the rail node
318 * @attribute minGutter
328 * Like CSS padding, the distance in pixels from the inner bottom or
329 * right edge of the rail node within which the thumb can travel.
330 * Negative values allow the edge of the thumb to escape the rail node
333 * @attribute maxGutter
344 Y.extend(Slider, Y.Widget, {
347 * Collection of object property names from the appropriate hash set in
357 * Factor used to translate positional coordinates (e.g. left or top) to
358 * the Slider's value.
367 * Pixel dimension of the rail Node's width for X axis Sliders or height
368 * for Y axis Sliders. Used with _factor to calculate positional
369 * coordinates for the thumb.
371 * @property _railSize
378 * Pixel dimension of the thumb Node's width for X axis Sliders or height
379 * for Y axis Sliders. Used with _factor to calculate positional
380 * coordinates for the thumb.
382 * @property _thumbSize
389 * Pixel offset of the point in the thumb element from its top/left edge
390 * to where the value calculation should take place. By default, this is
391 * calculated to half the width of the thumb, causing the value to be
392 * marked from the center of the thumb.
394 * @property _thumbOffset
401 * Object returned from temporary subscription to disabledChange event to
402 * defer setting the disabled state while Slider is loading the thumb
412 * Deferred value for the disabled attribute when stalled (see _stall
415 * @property _disabled
422 * Construction logic executed durint Slider instantiation. Subscribes to
423 * after events for min, max, and railSize. Publishes custom events
424 * including slideStart and slideEnd.
426 * @method initializer
429 initializer : function () {
430 this._key = Slider._AXIS_KEYS[this.get('axis')];
432 this.after('minChange', this._afterMinChange);
433 this.after('maxChange', this._afterMaxChange);
435 this.after('railSizeChange', this._afterRailSizeChange);
438 * Signals the beginning of a thumb drag operation. Payload includes
439 * the DD.Drag instance's drag:start event under key ddEvent.
442 * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added:
445 * <dd><code>drag:start</code> event from the managed DD.Drag instance</dd>
448 this.publish(SLIDE_START);
451 * Signals the end of a thumb drag operation. Payload includes
452 * the DD.Drag instance's drag:end event under key ddEvent.
455 * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added:
458 * <dd><code>drag:end</code> event from the managed DD.Drag instance</dd>
461 this.publish(SLIDE_END);
464 * Communicates a request to synchronize the Slider UI with the
465 * attribute state. Links the sync request with the default sync
466 * logic in _defSyncFn.
469 * @param event {Event.Facade} Event Facade object
470 * @preventable _defSyncFn
472 this.publish(SYNC, { defaultFn: this._defSyncFn });
475 * Signals a request to reposition the thumb in response to API methods.
476 * Triggers the thumb placement logic in _defPositionThumbFn.
478 * @event positionThumb
479 * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added:
482 * <dd><code>valueChange</code> event fired in response to the change in the value attribute</dd>
484 * @preventable _defPositionThumbFn
486 this.publish(POSITION_THUMB, { defaultFn: this._defPositionThumbFn });
490 * Create the DOM structure for the Slider.
495 renderUI : function () {
501 * Creates the rail element if not provided and not discovered via
507 _initRail : function () {
508 var cb = this.get(CONTENT_BOX),
509 rail = this.get(RAIL);
511 // Create rail if necessary. Make sure it's in the contentBox
513 rail = cb.appendChild(
514 Y.Node.create('<div class="'+C_RAIL+'"></div>'));
517 } else if (!cb.contains(rail)) {
518 cb.appendChild(rail);
521 rail.addClass(C_RAIL);
522 rail.addClass(this.getClassName(RAIL,this.get('axis')));
526 * <p>Creates the thumb element (not image) if not provided and not
527 * discovered via HTML_PARSER. If the thumb is an <code>img</code> element
528 * but no thumbImage configured or discovered, reassigns the thumb element
529 * to the thumbImage and defaults the thumb element as a div.</p>
531 * <p>Makes sure the thumb is a child of the rail element and calls
532 * _initThumbImage if thumbImage is provided.</p>
537 _initThumb : function () {
538 var rail = this.get(RAIL),
539 thumb = this.get(THUMB);
541 // Passed an img element as the thumb
542 if (thumb && !this.get(THUMB_IMAGE) &&
543 thumb.get('nodeName').toLowerCase() === 'img') {
544 this.set(THUMB_IMAGE, thumb);
545 this.set(THUMB,null);
550 thumb = Y.Node.create(
551 '<div class="'+C_THUMB+'"></div>');
553 this.set(THUMB,thumb);
556 thumb.addClass(C_THUMB);
558 if (!rail.contains(thumb)) {
559 rail.appendChild(thumb);
562 if (this.get(THUMB_IMAGE)) {
563 this._initThumbImage();
568 * Ensures the thumbImage is a child of the thumb element.
570 * @method _initThumbImage
573 _initThumbImage : function () {
574 var thumb = this.get(THUMB),
575 img = this.get(THUMB_IMAGE);
578 img.replaceClass(C_THUMB,C_THUMB_IMAGE);
580 if (!thumb.contains(img)) {
581 thumb.appendChild(img);
587 * Creates the Y.DD instance used to handle the thumb movement and binds
588 * Slider interaction to the configured value model.
593 bindUI : function () {
595 * Bridges user interaction with the thumb to the value attribute.
598 * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added:
601 * <dd><code>drag:drag</code> event from the managed DD.Drag instance</dd>
603 * @preventable _defThumbDragFn
605 this.publish(THUMB_DRAG, {defaultFn: this._defThumbDragFn});
609 this.after('valueChange', this._afterValueChange);
610 this.after('thumbImageChange', this._afterThumbImageChange);
611 this.after(DISABLED_CHANGE, this._afterDisabledChange);
615 * Creates the Y.DD instance used to handle the thumb interaction.
617 * @method _bindThumbDD
620 _bindThumbDD : function () {
622 node : this.get(THUMB),
626 constrain2node : this.get(RAIL)
629 conConf[this._key.ddStick] = true;
631 this._dd = new Y.DD.Drag(ddConf).plug(Y.Plugin.DDConstrained, conConf);
632 this._dd.on('drag:start', Y.bind(this._onDDStartDrag, this));
633 this._dd.on('drag:drag', Y.bind(this._onDDDrag, this));
634 this._dd.on('drag:end', Y.bind(this._onDDEndDrag, this));
640 * Subscribes to the rail Node's mousedown event to actuate the thumb when
641 * backgroundEnabled is true.
643 * @method _initRailDD
646 _initRailDD : function () {
647 this.get(RAIL).on('mousedown',Y.bind(this._handleRailMouseDown,this));
651 * If the Slider is not disabled and railEnabled is true, moves the thumb
652 * to the mousedown position and hands control over to DD.
654 * @method _handleRailMouseDown
655 * @param e {Event} Mousedown event facade
658 _handleRailMouseDown : function (e) {
659 if (this.get('railEnabled') && !this.get(DISABLED)) {
661 xyIndex = this._key.xyIndex,
664 if (dd.get('primaryButtonOnly') && e.button > 1) {
668 dd._dragThreshMet = true;
670 dd._fixIEMouseDown();
673 Y.DD.DDM.activeDrag = dd;
675 // Adjust registered starting position by half the thumb's x/y
676 xy = dd.get('dragNode').getXY();
677 xy[xyIndex] += this._thumbOffset;
679 dd._setStartPosition(xy);
680 dd.set('activeHandle',dd.get('dragNode'));
683 dd._alignNode([e.pageX,e.pageY]);
688 * Synchronizes the DOM state with the attribute settings (most notably
689 * railSize and value). If thumbImage is provided and is still loading,
690 * sync is delayed until it is complete, since the image's dimensions are
691 * taken into consideration for calculations.
695 syncUI : function () {
696 this.get(CONTENT_BOX).removeClass(C_IMAGE_ERROR);
698 var img = this.get(THUMB_IMAGE);
700 if (this._isImageLoading(img)) {
701 // Schedule the sync for when the image loads/errors
702 this._scheduleSync();
704 this._ready(img,!this._isImageLoaded(img));
709 * Binds to the load and error event on the thumbImage to sync the DOM
710 * state with the attribute settings when the image resource is resolved.
711 * The Slider is disabled while it waits.
713 * @method _scheduleSync
716 _scheduleSync : function () {
720 // disable the control until the image is loaded
721 this._disabled = this.get(DISABLED);
722 this.set(DISABLED,true);
723 this._stall = this.on(DISABLED_CHANGE,this._stallDisabledChange);
725 img = this.get(THUMB_IMAGE);
726 handler = Y.bind(this._imageLoaded,this,img);
727 img.on('load', handler);
728 img.on('error',handler);
733 * Method subscribed to the disabledChange event when thumbImage is being
734 * loaded. Prevents manually enabling the Slider until the thumbImage
735 * resource is resolved. Intended value is stored during load and set upon
738 * @method _stallDisabledChange
739 * @param e {Event} Change event for the disabled attribute
742 _stallDisabledChange : function (e) {
743 this._disabled = e.newVal;
748 * Event handler assigned to the thumbImage's load and error event if it
749 * was not loaded prior to instantiation. Restores the disabled value.
751 * @method _imageLoaded
752 * @param img {Node} The thumbImage Node
753 * @param e {Event} load or error event fired by the thumbImage
756 _imageLoaded : function (img,e) {
757 var error = (e.type.toLowerCase().indexOf('error') > -1);
759 // Need to execute inside a setTimeout because IE doesn't report
760 // img.complete === true until after the img.onload handler
761 // @TODO: readyState reports correctly in onload. Lose this wrapper
762 // and use that in _isImageLoaded.
763 Y.later(0, this, function () {
765 this._stall.detach();
771 this._ready(img,error);
773 this.set(DISABLED,this._disabled);
778 * Applies a class to the content box if the thumbImage failed to resolve,
779 * the fires the internal sync event triggering a sync between UI and
783 * @param img {Node} the thumbImage Node
784 * @param error {Boolean} Indicates an error while loading the thumbImage
787 _ready : function (img,error) {
788 var method = error ? 'addClass' : 'removeClass';
790 // If the thumb image url results in 404, assign a class to provide
791 // default thumb dimensions/UI
792 this.get(CONTENT_BOX)[method](C_IMAGE_ERROR);
798 * The default synchronization behavior, updating the Slider's DOM state to
799 * match the current attribute values.
802 * @param e {Event} Internal sync event
805 _defSyncFn : function (e) {
806 this._uiSetThumbSize();
808 this._setThumbOffset();
810 this._uiSetRailSize();
812 this._setRailOffsetXY();
816 this._resetDDCacheRegion();
820 var val = this.get(VALUE);
822 this.fire(POSITION_THUMB, {
824 offset : this._convertValueToOffset(val)
827 // Forces a reflow of the bounding box to address IE8 inline-block
828 // container not expanding correctly. bug 2527905
829 this.get('boundingBox').toggleClass('');
833 * Captures the thumb's pixel height or width (depending on the Slider's
834 * axis) for use in positioning calculations.
836 * @method _uiSetThumbSize
839 _uiSetThumbSize : function () {
840 var thumb = this.get(THUMB),
842 img = this.get(THUMB_IMAGE),
845 // offsetWidth fails in hidden containers
846 size = parseInt(thumb.getComputedStyle(dim),10);
849 if (img && this._isImageLoaded(img)) {
854 this._thumbSize = size;
858 * Establishes the point in the thumb that should align to the rail
859 * position representing the calculated value.
861 * @method _setThumbOffset
864 _setThumbOffset : function () {
865 this._thumbOffset = floor(this._thumbSize / 2);
869 * Stores the rail Node's pixel height or width, depending on the Slider's
870 * axis, for use in calculating thumb position from the value.
872 * @method _uiSetRailSize
875 _uiSetRailSize : function () {
876 var rail = this.get(RAIL),
877 thumb = this.get(THUMB),
878 img = this.get(THUMB_IMAGE),
880 size = this.get(RAIL_SIZE),
883 if (parseInt(size,10)) {
886 rail.setStyle(dim,size);
887 size = parseInt(rail.getComputedStyle(dim),10);
890 // Default from height or width (axis respective), or dims assigned
891 // via css to the rail or thumb, whichever is largest.
892 // Dear implementers, please use railSize, not height/width to
894 size = this.get(dim);
895 if (parseInt(size,10)) {
897 rail.setStyle(dim,size);
898 size = parseInt(rail.getComputedStyle(dim),10);
902 parseInt(thumb.getComputedStyle(dim),10),
903 parseInt(rail.getComputedStyle(dim),10));
906 if (img && this._isImageLoaded(img)) {
908 size = max(img.get(dim),size);
912 rail.setStyle(dim, size + PX);
914 this._railSize = size;
916 // handle the (not recommended) fallback case of setting rail size via
917 // widget height/width params. This is the only case that sets the
918 // off-axis rail dim in the code.
920 dim = this._key.offAxisDim;
921 size = this.get(dim);
929 * Store the current XY position of the rail Node on the page. For use in
930 * calculating thumb position from value.
932 * @method _setRailOffsetXY
935 _setRailOffsetXY : function () {
936 this._offsetXY = this.get(RAIL).getXY()[this._key.xyIndex] +
937 this.get(MIN_GUTTER);
941 * Passes the gutter attribute value to the DDConstrain gutter attribute.
943 * @method _setDDGutter
946 _setDDGutter : function () {
947 var gutter = this._key.xyIndex ?
948 this.get(MIN_GUTTER) + " 0 " + this.get(MAX_GUTTER) :
949 "0 " + this.get(MAX_GUTTER) + " 0 " + this.get(MIN_GUTTER);
952 this._dd.con.set('gutter', gutter);
956 * Resets the cached region inside the DD constrain instance to support
957 * repositioning the Slider after instantiation.
959 * @method _resetDDCacheRegion
962 _resetDDCacheRegion : function () {
963 // Workaround for ticket #2527964
964 this._dd.con._cacheRegion();
968 * Calculates the multiplier used to translate the value into a thumb
974 _setFactor : function () {
975 var range = this._railSize - this._thumbSize -
976 this.get(MIN_GUTTER) - this.get(MAX_GUTTER);
978 this._factor = this._railSize ?
979 (this.get(MAX) - this.get(MIN)) / range :
985 * Convenience method for accessing the current value of the Slider.
986 * Equivalent to <code>slider.get("value")</code>.
989 * @return {Number} the value
991 getValue : function () {
992 return this.get(VALUE);
996 * Convenience method for updating the current value of the Slider.
997 * Equivalent to <code>slider.set("value",val)</code>.
1000 * @param val {Number} the new value
1002 setValue : function (val) {
1003 this.set(VALUE,val);
1007 * Validator applied to new values for the axis attribute. Only
1008 * "x" and "y" are permitted.
1010 * @method _validateNewAxis
1011 * @param v {String} proposed value for the axis attribute
1015 _validateNewAxis : function (v) {
1016 return isString(v) && 'xXyY'.indexOf(v.charAt(0)) > -1;
1020 * Validator applied to the min attribute.
1022 * @method _validateNewMin
1023 * @param v {MIXED} proposed value for the min attribute
1027 _validateNewMin : function (v) {
1032 * Validator applied to the max attribute.
1034 * @method _validateNewMax
1035 * @param v {MIXED} proposed value for the max attribute
1039 _validateNewMax : function (v) {
1044 * Validator applied to the value attribute.
1046 * @method _validateNewValue
1047 * @param v {MIXED} proposed value for the value attribute
1051 _validateNewValue : function (v) {
1052 var min = this.get(MIN),
1053 max = this.get(MAX);
1055 return isNumber(v) &&
1056 (min < max ? (v >= min && v <= max) : (v >= max && v <= min));
1060 * Validator applied to the rail attribute. Rejects all values after the
1061 * Slider has been rendered.
1063 * @method _validateNewRail
1064 * @param v {MIXED} proposed value for the rail attribute
1068 _validateNewRail : function (v) {
1069 return !this.get(RENDERED) || v;
1073 * Validator applied to the thumb attribute. Rejects all values after the
1074 * Slider has been rendered.
1076 * @method _validateNewThumb
1077 * @param v {MIXED} proposed value for the thumb attribute
1081 _validateNewThumb : function (v) {
1082 return !this.get(RENDERED) || v;
1086 * Validator applied to the thumbImage attribute. Rejects all values after
1087 * the Slider has been rendered.
1089 * @method _validateNewThumbImage
1090 * @param v {MIXED} proposed value for the thumbImage attribute
1094 _validateNewThumbImage : function (v) {
1095 return !this.get(RENDERED) || v;
1099 * Validator applied to the railSize attribute. Only strings of css size
1100 * values (e.g. '200px') are allowed.
1102 * @method _validateNewRailSize
1103 * @param v {String} proposed value for the railSize attribute
1107 _validateNewRailSize : function (v) {
1108 return isString(v) &&
1109 (v === '0' || /^\d+(?:p[xtc]|%|e[mx]|in|[mc]m)$/.test(v));
1113 * Setter applied to the input when updating the axis attribute.
1115 * @method _setAxisFn
1116 * @param v {String} proposed value for the axis attribute
1117 * @return {String} lowercased first character of the input string
1120 _setAxisFn : function (v) {
1121 return v.charAt(0).toLowerCase();
1125 * Setter applied to the input when updating the rail attribute. Input can
1126 * be a Node, raw HTMLElement, or a selector string to locate it.
1128 * @method _setRailFn
1129 * @param v {Node|String|HTMLElement} The rail element Node or selector
1130 * @return {Node} The Node if found. Otherwise null.
1133 _setRailFn : function (v) {
1134 return Y.get(v) || null;
1138 * Setter applied to the input when updating the thumb attribute. Input can
1139 * be a Node, raw HTMLElement, or a selector string to locate it.
1141 * @method _setThumbFn
1142 * @param v {Node|String|HTMLElement} The thumb element Node or selector
1143 * @return {Node} The Node if found. Otherwise null.
1146 _setThumbFn : function (v) {
1147 return Y.get(v) || null;
1151 * Setter applied to the input when updating the thumbImage attribute.
1152 * Input can be a Node, raw HTMLElement, selector string to locate it, or
1153 * the URL for an image resource.
1155 * String input will be treated as a selector. If no element is found using
1156 * the selector, an <code>img</code> Node will be created with the string
1157 * used as the <code>src</code> attribute.
1159 * @method _setThumbImageFn
1160 * @param v {Node|String|HTMLElement} The thumbImage element Node, selector,
1162 * @return {Node} The Node if found or created. Otherwise null.
1165 _setThumbImageFn : function (v) {
1166 return v ? Y.get(v) ||
1167 Y.Node.create('<img src="'+v+'" alt="Slider thumb">') :
1173 * Caches the current page position of the rail element and fires the
1174 * slideStart event in response to the DD's drag:start.
1176 * @method _onDDStartDrag
1177 * @param e {Event} the DD instance's drag:start custom event
1180 _onDDStartDrag : function (e) {
1181 this._setRailOffsetXY();
1182 this.fire(SLIDE_START,{ ddEvent: e });
1186 * Fires the thumbDrag event to queue Slider value update.
1189 * @param e {Event} the DD instance's drag:drag custom event
1192 _onDDDrag : function (e) {
1193 this.fire(THUMB_DRAG, { ddEvent: e });
1197 * The default value update behavior in response to Slider thumb
1198 * interaction. Calculates the value using stored offsets, the _factor
1199 * multiplier and the min value.
1201 * @method _defThumbDragFn
1202 * @param e {Event} the internal thumbDrag event
1205 _defThumbDragFn : function (e) {
1206 var before = this.get(VALUE),
1207 val = e.ddEvent[this._key.eventPageAxis] - this._offsetXY;
1210 val = this._convertOffsetToValue(val);
1212 if (before !== val) {
1213 this.set(VALUE, val, { ddEvent: e.ddEvent });
1218 * Fires the slideEnd event.
1220 * @method _onDDEndDrag
1221 * @param e {Event} the DD instance's drag:end custom event
1224 _onDDEndDrag : function (e) {
1225 this.fire(SLIDE_END,{ ddEvent: e });
1232 * Calls _uiPositionThumb with the value of the custom event's
1233 * "offset" property.
1235 * @method _defPositionThumbFn
1236 * @param e {Event} the positionThumb custom event
1239 _defPositionThumbFn : function (e) {
1241 this._uiPositionThumb(e.offset);
1245 * Places the thumb at a particular X or Y location based on the configured
1248 * @method _uiPositionThumb
1249 * @param xy {Number} the desired left or top pixel position of the thumb
1250 * in relation to the rail Node.
1253 _uiPositionThumb : function (xy) {
1255 thumb = dd.get('dragNode'),
1256 hidden = thumb.ancestor(this._isDisplayNone);
1259 dd._setStartPosition(dd.get('dragNode').getXY());
1261 // stickX/stickY config on DD instance will negate off-axis move
1262 dd._alignNode([xy,xy],true);
1267 * Helper function to search up the ancestor axis looking for a node with
1268 * style display: none. This is passed as a function to node.ancestor(..)
1269 * to test if a given node is in the displayed DOM and can get accurate
1270 * positioning information.
1272 * @method _isDisplayNone
1273 * @param el {Node} ancestor node as the function walks up the parent axis
1274 * @return {Boolean} true if the node is styled with display: none
1277 _isDisplayNone : function (node) {
1278 return node.getComputedStyle('display') === 'none';
1282 * Fires the internal positionThumb event in response to a change in the
1285 * @method _afterValueChange
1286 * @param e {Event} valueChange custom event
1289 _afterValueChange : function (e) {
1291 var xy = this._convertValueToOffset(e.newVal);
1294 this.fire(POSITION_THUMB,{ value: e.newVal, offset: xy });
1299 * Converts a value to a pixel offset for the thumb position on the rail.
1301 * @method _convertValueToOffset
1302 * @param v {Number} value between the Slider's min and max
1305 _convertValueToOffset : function (v) {
1306 return round((v - this.get(MIN)) / this._factor) + this._offsetXY;
1310 * Converts a pixel offset of the thumb on the rail to a value.
1312 * @method _convertOffsetToValue
1313 * @param v {Number} pixel offset of the thumb on the rail
1316 _convertOffsetToValue : function (v) {
1317 return round(this.get(MIN) + (v * this._factor));
1321 * Replaces the thumb Node in response to a change in the thumb attribute.
1322 * This only has effect after the Slider is rendered.
1324 * @method _afterThumbChange
1325 * @param e {Event} thumbChange custom event
1328 _afterThumbChange : function (e) {
1331 if (this.get(RENDERED)) {
1333 e.prevValue.get('parentNode').removeChild(e.prevValue);
1338 thumb = this.get(THUMB);
1339 this._dd.set('node',thumb);
1340 this._dd.set('dragNode',thumb);
1347 * Sets or replaces the thumb's contained <code>img</code> Node with the
1348 * new Node in response to a change in the thumbImage attribute. This only
1349 * has effect after the Slider is rendered.
1351 * @method _afterThumbImageChange
1352 * @param e {Event} thumbImageChange custom event
1355 _afterThumbImageChange : function (e) {
1356 if (this.get(RENDERED)) {
1358 e.prevValue.get('parentNode').removeChild(e.prevValue);
1361 this._initThumbImage();
1368 * Updates the Slider UI in response to change in the min attribute.
1370 * @method _afterMinChange
1371 * @param e {Event} minChange custom event
1374 _afterMinChange : function (e) {
1379 * Updates the Slider UI in response to change in the max attribute.
1381 * @method _afterMaxChange
1382 * @param e {Event} maxChange custom event
1385 _afterMaxChange : function (e) {
1390 * Updates the Slider UI in response to change in the railSize attribute.
1392 * @method _afterRailSizeChange
1393 * @param e {Event} railSizeChange custom event
1396 _afterRailSizeChange : function (e) {
1401 * Locks or unlocks the DD instance in response to a change in the disabled
1404 * @method _afterDisabledChange
1405 * @param e {Event} disabledChange custom event
1408 _afterDisabledChange : function (e) {
1410 this._dd.set('lock',e.newVal);
1415 * Common handler to call syncUI in response to change events that occurred
1416 * after the Slider is rendered.
1419 * @param e {Event} An attribute change event
1422 _refresh : function (e) {
1423 if (e.newVal !== e.prevVal && this.get(RENDERED)) {
1429 * Used to determine if there is a current or pending request for the
1430 * thumbImage resource.
1432 * @method _isImageLoading
1433 * @param img {Node} <code>img</code> Node
1437 _isImageLoading : function (img) {
1438 return img && !img.get(COMPLETE);
1442 * Used to determine if the image resource loaded successfully or there was
1447 * <li>img load error fired xbrowser for image resources not yet resolved</li>
1448 * <li>img.complete reports false in IE for images not yet loaded as well as images that failed to load</li>
1449 * <li>img.complete true && img.naturalWidth == 0 in FF and Safari indicate image failed to load</li>
1450 * <li>img.complete && img.width == 0 in Opera indicates image failed to load</li>
1453 * @method _isImageLoaded
1454 * @param img {Node} <code>img</code> Node
1458 _isImageLoaded : function (img) {
1460 var w = img.get('naturalWidth');
1461 return img.get(COMPLETE) && (!isNumber(w) ? img.get(WIDTH) : w);
1472 }, '3.0.0' ,{requires:['widget','dd-constrain']});