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