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