--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cm/media/js/lib/yui/yui_3.0.0b1/build/slider/slider.js Mon Nov 23 15:14:29 2009 +0100
@@ -0,0 +1,1469 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0b1
+build: 1163
+*/
+YUI.add('slider', function(Y) {
+
+/**
+ * Create a sliding value range input visualized as a draggable thumb on a
+ * background element.
+ *
+ * @module slider
+ */
+
+var SLIDER = 'slider',
+ RAIL = 'rail',
+ THUMB = 'thumb',
+ VALUE = 'value',
+ MIN = 'min',
+ MAX = 'max',
+ MIN_GUTTER = 'minGutter',
+ MAX_GUTTER = 'maxGutter',
+ THUMB_IMAGE = 'thumbImage',
+ RAIL_SIZE = 'railSize',
+ CONTENT_BOX = 'contentBox',
+
+ SLIDE_START = 'slideStart',
+ SLIDE_END = 'slideEnd',
+
+ THUMB_DRAG = 'thumbDrag',
+ SYNC = 'sync',
+ POSITION_THUMB = 'positionThumb',
+ RENDERED = 'rendered',
+ DISABLED = 'disabled',
+ DISABLED_CHANGE = 'disabledChange',
+
+ DOT = '.',
+ PX = 'px',
+ WIDTH = 'width',
+ HEIGHT = 'height',
+ COMPLETE = 'complete',
+
+ L = Y.Lang,
+ isBoolean= L.isBoolean,
+ isString = L.isString,
+ isNumber = L.isNumber,
+
+ getCN = Y.ClassNameManager.getClassName,
+
+ IMAGE = 'image',
+ C_RAIL = getCN(SLIDER,RAIL),
+ C_THUMB = getCN(SLIDER,THUMB),
+ C_THUMB_IMAGE = getCN(SLIDER,THUMB,IMAGE),
+ C_IMAGE_ERROR = getCN(SLIDER,IMAGE,'error'),
+
+ M = Math,
+ max = M.max,
+ round = M.round,
+ floor = M.floor;
+
+/**
+ * Create a slider to represent an integer value between a given minimum and
+ * maximum. Sliders may be aligned vertically or horizontally, based on the
+ * <code>axis</code> configuration.
+ *
+ * @class Slider
+ * @extends Widget
+ * @param config {Object} Configuration object
+ * @constructor
+ */
+function Slider() {
+ Slider.superclass.constructor.apply(this,arguments);
+}
+
+Y.mix(Slider, {
+
+ /**
+ * The identity of the widget.
+ *
+ * @property Slider.NAME
+ * @type String
+ * @static
+ */
+ NAME : SLIDER,
+
+ /**
+ * Object property names used for respective X and Y axis Sliders (e.g.
+ * "left" vs. "top" for placing the thumb according to
+ * its representative value).
+ *
+ * @property Slider.AXIS_KEYS
+ * @type Object
+ * @protected
+ * @static
+ */
+ AXIS_KEYS : {
+ x : {
+ dim : WIDTH,
+ offAxisDim : HEIGHT,
+ eventPageAxis : 'pageX',
+ ddStick : 'stickX',
+ xyIndex : 0
+ },
+ y : {
+ dim : HEIGHT,
+ offAxisDim : WIDTH,
+ eventPageAxis : 'pageY',
+ ddStick : 'stickY',
+ xyIndex : 1
+ }
+ },
+
+ /**
+ * Static Object hash used to capture existing markup for progressive
+ * enhancement. Keys correspond to config attribute names and values
+ * are selectors used to inspect the contentBox for an existing node
+ * structure.
+ *
+ * @property Slider.HTML_PARSER
+ * @type Object
+ * @protected
+ * @static
+ */
+ HTML_PARSER : {
+ rail : DOT + C_RAIL,
+ thumb : DOT + C_THUMB,
+ thumbImage : DOT + C_THUMB_IMAGE
+ },
+
+ /**
+ * Static property used to define the default attribute configuration of
+ * the Widget.
+ *
+ * @property Slider.ATTRS
+ * @type Object
+ * @protected
+ * @static
+ */
+ ATTRS : {
+
+ /**
+ * Axis upon which the Slider's thumb moves. "x" for
+ * horizontal, "y" for vertical.
+ *
+ * @attribute axis
+ * @type String
+ * @default "x"
+ * @writeOnce
+ */
+ axis : {
+ value : 'x',
+ writeOnce : true,
+ validator : function (v) {
+ return this._validateNewAxis(v);
+ },
+ setter : function (v) {
+ return this._setAxisFn(v);
+ }
+ },
+
+ /**
+ * Value associated with the left or top most position of the thumb on
+ * the rail.
+ *
+ * @attribute min
+ * @type Number
+ * @default 0
+ */
+ min : {
+ value : 0,
+ validator : function (v) {
+ return this._validateNewMin(v);
+ }
+ },
+
+ /**
+ * Value associated with the right or bottom most position of the thumb
+ * on the rail.
+ *
+ * @attribute max
+ * @type Number
+ * @default 100
+ */
+ max : {
+ value : 100,
+ validator : function (v) {
+ return this._validateNewMax(v);
+ }
+ },
+
+ /**
+ * The current value of the Slider. This value is interpretted into a
+ * position for the thumb along the Slider's rail.
+ *
+ * @attribute value
+ * @type Number
+ * @default 0
+ */
+ value : {
+ value : 0,
+ validator : function (v) {
+ return this._validateNewValue(v);
+ },
+ setter : function (v) {
+ return this._setValueFn(v);
+ }
+ },
+
+ /**
+ * The Node representing the Slider's rail, usually visualized as a
+ * bar of some sort using a background image, along which the thumb
+ * moves. This Node contains the thumb Node.
+ *
+ * @attribute rail
+ * @type Node
+ * @default null
+ */
+ rail : {
+ value : null,
+ validator : function (v) {
+ return this._validateNewRail(v);
+ },
+ setter : function (v) {
+ return this._setRailFn(v);
+ }
+ },
+
+ /**
+ * <p>The Node representing the Slider's thumb, usually visualized as a
+ * pointer using a contained image Node (see thumbImage). The current
+ * value of the Slider is calculated from the centerpoint of this
+ * Node in relation to the rail Node. If provided, the thumbImage
+ * Node is contained within this Node.</p>
+ *
+ * <p>If no thumbImage is provided and the Node passed as the thumb is
+ * an <code>img</code> element, the assigned Node will be allocated to
+ * the thumbImage and the thumb container defaulted.</p>
+ *
+ * @attribute thumb
+ * @type Node
+ * @default null
+ */
+ thumb : {
+ value : null,
+ validator : function (v) {
+ return this._validateNewThumb(v);
+ },
+ setter : function (v) {
+ return this._setThumbFn(v);
+ }
+ },
+
+ /**
+ * <p>The Node representing the image element to use for the Slider's
+ * thumb.</p>
+ *
+ * <p>Alternately, an image URL can be passed and an <code>img</code>
+ * Node will be generated accordingly.</p>
+ *
+ * <p>If no thumbImage is provided and the Node passed as the thumb is
+ * an <code>img</code> element, the assigned Node will be allocated to
+ * the thumbImage and the thumb container defaulted.</p>
+ *
+ * <p>If thumbImage is provided but its URL resolves to a 404, a default
+ * style will be applied to maintain basic functionality.</p>
+ *
+ * @attribute thumbImage
+ * @type Node|String
+ * @default null
+ */
+ thumbImage : {
+ value : null,
+ validator : function (v) {
+ return this._validateNewThumbImage(v);
+ },
+ setter : function (v) {
+ return this._setThumbImageFn(v);
+ }
+ },
+
+ /**
+ * <p>The width or height of the rail element representing the physical
+ * space along which the thumb can move. CSS size values (e.g. '30em')
+ * accepted but converted to pixels during render.</p>
+ *
+ * <p>Alternately, but not recommended, this attribute can be left
+ * unassigned in favor of specifying height or width.</p>
+ *
+ * @attribute railSize
+ * @type String
+ * @default '0'
+ */
+ railSize : {
+ value : '0',
+ validator : function (v) {
+ return this._validateNewRailSize(v);
+ }
+ },
+
+ /**
+ * Boolean indicating whether clicking and dragging on the rail will
+ * trigger thumb movement.
+ *
+ * @attribute railEnabled
+ * @type Boolean
+ * @default true
+ */
+ railEnabled : {
+ value : true,
+ validator : isBoolean
+ },
+
+ /**
+ * Like CSS padding, the distance in pixels from the inner top or left
+ * edge of the rail node within which the thumb can travel. Negative
+ * values allow the edge of the thumb to escape the rail node
+ * boundaries.
+ *
+ * @attribute minGutter
+ * @type Number
+ * @default 0
+ */
+ minGutter : {
+ value : 0,
+ validator : isNumber
+ },
+
+ /**
+ * Like CSS padding, the distance in pixels from the inner bottom or
+ * right edge of the rail node within which the thumb can travel.
+ * Negative values allow the edge of the thumb to escape the rail node
+ * boundaries.
+ *
+ * @attribute maxGutter
+ * @type Number
+ * @default 0
+ */
+ maxGutter : {
+ value : 0,
+ validator : isNumber
+ }
+ }
+});
+
+Y.extend(Slider, Y.Widget, {
+
+ /**
+ * Collection of object property names from the appropriate hash set in
+ * Slider.AXIS_KEYS.
+ *
+ * @property _key
+ * @type Object
+ * @protected
+ */
+ _key : null,
+
+ /**
+ * Factor used to translate positional coordinates (e.g. left or top) to
+ * the Slider's value.
+ *
+ * @property _factor
+ * @type Number
+ * @protected
+ */
+ _factor : 1,
+
+ /**
+ * Pixel dimension of the rail Node's width for X axis Sliders or height
+ * for Y axis Sliders. Used with _factor to calculate positional
+ * coordinates for the thumb.
+ *
+ * @property _railSize
+ * @type Number
+ * @protected
+ */
+ _railSize : null,
+
+ /**
+ * Pixel dimension of the thumb Node's width for X axis Sliders or height
+ * for Y axis Sliders. Used with _factor to calculate positional
+ * coordinates for the thumb.
+ *
+ * @property _thumbSize
+ * @type Number
+ * @protected
+ */
+ _thumbSize : null,
+
+ /**
+ * Pixel offset of the point in the thumb element from its top/left edge
+ * to where the value calculation should take place. By default, this is
+ * calculated to half the width of the thumb, causing the value to be
+ * marked from the center of the thumb.
+ *
+ * @property _thumbOffset
+ * @type Number
+ * @protected
+ */
+ _thumbOffset : 0,
+
+ /**
+ * Object returned from temporary subscription to disabledChange event to
+ * defer setting the disabled state while Slider is loading the thumb
+ * image.
+ *
+ * @property _stall
+ * @type Object
+ * @protected
+ */
+ _stall : false,
+
+ /**
+ * Deferred value for the disabled attribute when stalled (see _stall
+ * property).
+ *
+ * @property _disabled
+ * @type Boolean
+ * @protected
+ */
+ _disabled : false,
+
+ /**
+ * Construction logic executed durint Slider instantiation. Subscribes to
+ * after events for min, max, and railSize. Publishes custom events
+ * including slideStart and slideEnd.
+ *
+ * @method initializer
+ * @protected
+ */
+ initializer : function () {
+ this._key = Slider.AXIS_KEYS[this.get('axis')];
+
+ this.after('minChange', this._afterMinChange);
+ this.after('maxChange', this._afterMaxChange);
+
+ this.after('railSizeChange', this._afterRailSizeChange);
+
+ /**
+ * Signals the beginning of a thumb drag operation. Payload includes
+ * the DD.Drag instance's drag:start event under key ddEvent.
+ *
+ * @event slideStart
+ * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added:
+ * <dl>
+ * <dt>ddEvent</dt>
+ * <dd><code>drag:start</code> event from the managed DD.Drag instance</dd>
+ * </dl>
+ */
+ this.publish(SLIDE_START);
+
+ /**
+ * Signals the end of a thumb drag operation. Payload includes
+ * the DD.Drag instance's drag:end event under key ddEvent.
+ *
+ * @event slideEnd
+ * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added:
+ * <dl>
+ * <dt>ddEvent</dt>
+ * <dd><code>drag:end</code> event from the managed DD.Drag instance</dd>
+ * </dl>
+ */
+ this.publish(SLIDE_END);
+
+ /**
+ * Communicates a request to synchronize the Slider UI with the
+ * attribute state. Links the sync request with the default sync
+ * logic in _defSyncFn.
+ *
+ * @event sync
+ * @param event {Event.Facade} Event Facade object
+ * @preventable _defSyncFn
+ */
+ this.publish(SYNC, { defaultFn: this._defSyncFn });
+
+ /**
+ * Signals a request to reposition the thumb in response to API methods.
+ * Triggers the thumb placement logic in _defPositionThumbFn.
+ *
+ * @event positionThumb
+ * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added:
+ * <dl>
+ * <dt>changeEv</dt>
+ * <dd><code>valueChange</code> event fired in response to the change in the value attribute</dd>
+ * </dl>
+ * @preventable _defPositionThumbFn
+ */
+ this.publish(POSITION_THUMB, { defaultFn: this._defPositionThumbFn });
+ },
+
+ /**
+ * Create the DOM structure for the Slider.
+ *
+ * @method renderUI
+ * @protected
+ */
+ renderUI : function () {
+ this._initRail();
+ this._initThumb();
+ },
+
+ /**
+ * Creates the rail element if not provided and not discovered via
+ * HTML_PARSER.
+ *
+ * @method _initRail
+ * @protected
+ */
+ _initRail : function () {
+ var cb = this.get(CONTENT_BOX),
+ rail = this.get(RAIL);
+
+ // Create rail if necessary. Make sure it's in the contentBox
+ if (!rail) {
+ rail = cb.appendChild(
+ Y.Node.create('<div class="'+C_RAIL+'"></div>'));
+
+ this.set(RAIL,rail);
+ } else if (!cb.contains(rail)) {
+ cb.appendChild(rail);
+ }
+
+ rail.addClass(C_RAIL);
+ rail.addClass(this.getClassName(RAIL,this.get('axis')));
+ },
+
+ /**
+ * <p>Creates the thumb element (not image) if not provided and not
+ * discovered via HTML_PARSER. If the thumb is an <code>img</code> element
+ * but no thumbImage configured or discovered, reassigns the thumb element
+ * to the thumbImage and defaults the thumb element as a div.</p>
+ *
+ * <p>Makes sure the thumb is a child of the rail element and calls
+ * _initThumbImage if thumbImage is provided.</p>
+ *
+ * @method _initThumb
+ * @protected
+ */
+ _initThumb : function () {
+ var rail = this.get(RAIL),
+ thumb = this.get(THUMB);
+
+ // Passed an img element as the thumb
+ if (thumb && !this.get(THUMB_IMAGE) &&
+ thumb.get('nodeName').toLowerCase() === 'img') {
+ this.set(THUMB_IMAGE, thumb);
+ this.set(THUMB,null);
+ thumb = null;
+ }
+
+ if (!thumb) {
+ thumb = Y.Node.create(
+ '<div class="'+C_THUMB+'"></div>');
+
+ this.set(THUMB,thumb);
+ }
+
+ thumb.addClass(C_THUMB);
+
+ if (!rail.contains(thumb)) {
+ rail.appendChild(thumb);
+ }
+
+ if (this.get(THUMB_IMAGE)) {
+ this._initThumbImage();
+ }
+ },
+
+ /**
+ * Ensures the thumbImage is a child of the thumb element.
+ *
+ * @method _initThumbImage
+ * @protected
+ */
+ _initThumbImage : function () {
+ var thumb = this.get(THUMB),
+ img = this.get(THUMB_IMAGE);
+
+ if (img) {
+ img.replaceClass(C_THUMB,C_THUMB_IMAGE);
+
+ if (!thumb.contains(img)) {
+ thumb.appendChild(img);
+ }
+ }
+ },
+
+ /**
+ * Creates the Y.DD instance used to handle the thumb movement and binds
+ * Slider interaction to the configured value model.
+ *
+ * @method bindUI
+ * @protected
+ */
+ bindUI : function () {
+ /**
+ * Bridges user interaction with the thumb to the value attribute.
+ *
+ * @event thumbDrag
+ * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added:
+ * <dl>
+ * <dt>ddEvent</dt>
+ * <dd><code>drag:drag</code> event from the managed DD.Drag instance</dd>
+ * </dl>
+ * @preventable _defUpdateValueFromDD
+ */
+ this.publish(THUMB_DRAG, {defaultFn: this._defUpdateValueFromDD});
+
+ this._bindThumbDD();
+
+ this.after('valueChange', this._afterValueChange);
+ this.after('thumbImageChange', this._afterThumbImageChange);
+ this.after(DISABLED_CHANGE, this._afterDisabledChange);
+ },
+
+ /**
+ * Creates the Y.DD instance used to handle the thumb interaction.
+ *
+ * @method _bindThumbDD
+ * @protected
+ */
+ _bindThumbDD : function () {
+ var ddConf = {
+ node : this.get(THUMB),
+ bubble : false
+ },
+ conConf = {
+ constrain2node : this.get(RAIL)
+ };
+
+ conConf[this._key.ddStick] = true;
+
+ this._dd = new Y.DD.Drag(ddConf).plug(Y.Plugin.DDConstrained, conConf);
+ this._dd.on('drag:start', Y.bind(this._onDDStartDrag, this));
+ this._dd.on('drag:drag', Y.bind(this._onDDDrag, this));
+ this._dd.on('drag:end', Y.bind(this._onDDEndDrag, this));
+
+ this._initRailDD();
+ },
+
+ /**
+ * Subscribes to the rail Node's mousedown event to actuate the thumb when
+ * backgroundEnabled is true.
+ *
+ * @method _initRailDD
+ * @protected
+ */
+ _initRailDD : function () {
+ this.get(RAIL).on('mousedown',Y.bind(this._handleRailMouseDown,this));
+ },
+
+ /**
+ * If the Slider is not disabled and railEnabled is true, moves the thumb
+ * to the mousedown position and hands control over to DD.
+ *
+ * @method _handleRailMouseDown
+ * @param e {Event} Mousedown event facade
+ * @protected
+ */
+ _handleRailMouseDown : function (e) {
+ if (this.get('railEnabled') && !this.get(DISABLED)) {
+ var dd = this._dd,
+ xyIndex = this._key.xyIndex,
+ xy;
+
+ if (dd.get('primaryButtonOnly') && e.button > 1) {
+ return false;
+ }
+
+ dd._dragThreshMet = true;
+
+ dd._fixIEMouseDown();
+ e.halt();
+
+ Y.DD.DDM.activeDrag = dd;
+
+ // Adjust registered starting position by half the thumb's x/y
+ xy = dd.get('dragNode').getXY();
+ xy[xyIndex] += this._thumbOffset;
+
+ dd._setStartPosition(xy);
+ dd.set('activeHandle',dd.get('dragNode'));
+
+ dd.start();
+ dd._alignNode([e.pageX,e.pageY]);
+ }
+ },
+
+ /**
+ * Synchronizes the DOM state with the attribute settings (most notably
+ * railSize and value). If thumbImage is provided and is still loading,
+ * sync is delayed until it is complete, since the image's dimensions are
+ * taken into consideration for calculations.
+ *
+ * @method syncUI
+ */
+ syncUI : function () {
+ this.get(CONTENT_BOX).removeClass(C_IMAGE_ERROR);
+
+ var img = this.get(THUMB_IMAGE);
+
+ if (this._isImageLoading(img)) {
+ // Schedule the sync for when the image loads/errors
+ this._scheduleSync();
+ } else {
+ this._ready(img,!this._isImageLoaded(img));
+ }
+ },
+
+ /**
+ * Binds to the load and error event on the thumbImage to sync the DOM
+ * state with the attribute settings when the image resource is resolved.
+ * The Slider is disabled while it waits.
+ *
+ * @method _scheduleSync
+ * @protected
+ */
+ _scheduleSync : function () {
+ var img, handler;
+
+ if (!this._stall) {
+ // disable the control until the image is loaded
+ this._disabled = this.get(DISABLED);
+ this.set(DISABLED,true);
+ this._stall = this.on(DISABLED_CHANGE,this._stallDisabledChange);
+
+ img = this.get(THUMB_IMAGE);
+ handler = Y.bind(this._imageLoaded,this,img);
+ img.on('load', handler);
+ img.on('error',handler);
+ }
+ },
+
+ /**
+ * Method subscribed to the disabledChange event when thumbImage is being
+ * loaded. Prevents manually enabling the Slider until the thumbImage
+ * resource is resolved. Intended value is stored during load and set upon
+ * completion.
+ *
+ * @method _stallDisabledChange
+ * @param e {Event} Change event for the disabled attribute
+ * @protected
+ */
+ _stallDisabledChange : function (e) {
+ this._disabled = e.newVal;
+ e.preventDefault();
+ },
+
+ /**
+ * Event handler assigned to the thumbImage's load and error event if it
+ * was not loaded prior to instantiation. Restores the disabled value.
+ *
+ * @method _imageLoaded
+ * @param img {Node} The thumbImage Node
+ * @param e {Event} load or error event fired by the thumbImage
+ * @protected
+ */
+ _imageLoaded : function (img,e) {
+ var error = (e.type.toLowerCase().indexOf('error') > -1);
+
+ if (this._stall) {
+ this._stall.detach();
+ }
+
+
+ this._stall = false;
+
+ this._ready(img,error);
+
+ this.set(DISABLED,this._disabled);
+ },
+
+ /**
+ * Applies a class to the content box if the thumbImage failed to resolve,
+ * the fires the internal sync event triggering a sync between UI and
+ * state.
+ *
+ * @method _ready
+ * @param img {Node} the thumbImage Node
+ * @param error {Boolean} Indicates an error while loading the thumbImage
+ * @protected
+ */
+ _ready : function (img,error) {
+ var method = error ? 'addClass' : 'removeClass';
+
+ // If the thumb image url results in 404, assign a class to provide
+ // default thumb dimensions/UI
+ this.get(CONTENT_BOX)[method](C_IMAGE_ERROR);
+
+ this.fire(SYNC);
+ },
+
+ /**
+ * The default synchronization behavior, updating the Slider's DOM state to
+ * match the current attribute values.
+ *
+ * @method _defSyncFn
+ * @param e {Event} Internal sync event
+ * @protected
+ */
+ _defSyncFn : function (e) {
+ this._uiSetThumbSize();
+
+ this._setThumbOffset();
+
+ this._uiSetRailSize();
+
+ this._setRailOffsetXY();
+
+ this._setDDGutter();
+
+ this._resetDDCacheRegion();
+
+ this._setFactor();
+
+ var val = this.get(VALUE);
+
+ this.fire(POSITION_THUMB, {
+ value : val,
+ offset : this._convertValueToOffset(val)
+ });
+
+ // Forces a reflow of the bounding box to address IE8 inline-block
+ // container not expanding correctly. bug 2527905
+ this.get('boundingBox').toggleClass('');
+ },
+
+ /**
+ * Captures the thumb's pixel height or width (depending on the Slider's
+ * axis) for use in positioning calculations.
+ *
+ * @method _uiSetThumbSize
+ * @protected
+ */
+ _uiSetThumbSize : function () {
+ var thumb = this.get(THUMB),
+ dim = this._key.dim,
+ img = this.get(THUMB_IMAGE),
+ size;
+
+ // offsetWidth fails in hidden containers
+ size = parseInt(thumb.getComputedStyle(dim),10);
+
+
+ if (img && this._isImageLoaded(img)) {
+
+ size = img.get(dim);
+ }
+
+ this._thumbSize = size;
+ },
+
+ /**
+ * Establishes the point in the thumb that should align to the rail
+ * position representing the calculated value.
+ *
+ * @method _setThumbOffset
+ * @protected
+ */
+ _setThumbOffset : function () {
+ this._thumbOffset = floor(this._thumbSize / 2);
+ },
+
+ /**
+ * Stores the rail Node's pixel height or width, depending on the Slider's
+ * axis, for use in calculating thumb position from the value.
+ *
+ * @method _uiSetRailSize
+ * @protected
+ */
+ _uiSetRailSize : function () {
+ var rail = this.get(RAIL),
+ thumb = this.get(THUMB),
+ img = this.get(THUMB_IMAGE),
+ dim = this._key.dim,
+ size = this.get(RAIL_SIZE),
+ setxy = false;
+
+ if (parseInt(size,10)) {
+
+ // Convert to pixels
+ rail.setStyle(dim,size);
+ size = parseInt(rail.getComputedStyle(dim),10);
+
+ } else {
+ // Default from height or width (axis respective), or dims assigned
+ // via css to the rail or thumb, whichever is largest.
+ // Dear implementers, please use railSize, not height/width to
+ // set the rail dims
+ size = this.get(dim);
+ if (parseInt(size,10)) {
+ setxy = true;
+ rail.setStyle(dim,size);
+ size = parseInt(rail.getComputedStyle(dim),10);
+ }
+ size = max(
+ size|0,
+ parseInt(thumb.getComputedStyle(dim),10),
+ parseInt(rail.getComputedStyle(dim),10));
+
+
+ if (img && this._isImageLoaded(img)) {
+
+ size = max(img.get(dim),size);
+ }
+ }
+
+ rail.setStyle(dim, size + PX);
+
+ this._railSize = size;
+
+ // handle the (not recommended) fallback case of setting rail size via
+ // widget height/width params. This is the only case that sets the
+ // off-axis rail dim in the code.
+ if (setxy) {
+ dim = this._key.offAxisDim;
+ size = this.get(dim);
+ if (size) {
+ rail.set(dim,size);
+ }
+ }
+ },
+
+ /**
+ * Store the current XY position of the rail Node on the page. For use in
+ * calculating thumb position from value.
+ *
+ * @method _setRailOffsetXY
+ * @protected
+ */
+ _setRailOffsetXY : function () {
+ this._offsetXY = this.get(RAIL).getXY()[this._key.xyIndex] +
+ this.get(MIN_GUTTER);
+ },
+
+ /**
+ * Passes the gutter attribute value to the DDConstrain gutter attribute.
+ *
+ * @method _setDDGutter
+ * @protected
+ */
+ _setDDGutter : function () {
+ var gutter = this._key.xyIndex ?
+ this.get(MIN_GUTTER) + " 0 " + this.get(MAX_GUTTER) :
+ "0 " + this.get(MAX_GUTTER) + " 0 " + this.get(MIN_GUTTER);
+
+
+ this._dd.con.set('gutter', gutter);
+ },
+
+ /**
+ * Resets the cached region inside the DD constrain instance to support
+ * repositioning the Slider after instantiation.
+ *
+ * @method _resetDDCacheRegion
+ * @protected
+ */
+ _resetDDCacheRegion : function () {
+ // Workaround for ticket #2527964
+ this._dd.con._cacheRegion();
+ },
+
+ /**
+ * Calculates the multiplier used to translate the value into a thumb
+ * position.
+ *
+ * @method _setFactor
+ * @protected
+ */
+ _setFactor : function () {
+ var range = this._railSize - this._thumbSize -
+ this.get(MIN_GUTTER) - this.get(MAX_GUTTER);
+
+ this._factor = this._railSize ?
+ (this.get(MAX) - this.get(MIN)) / range :
+ 1;
+
+ },
+
+ /**
+ * Convenience method for accessing the current value of the Slider.
+ * Equivalent to <code>slider.get("value")</code>.
+ *
+ * @method getValue
+ * @return {Number} the value
+ */
+ getValue : function () {
+ return this.get(VALUE);
+ },
+
+ /**
+ * Convenience method for updating the current value of the Slider.
+ * Equivalent to <code>slider.set("value",val)</code>.
+ *
+ * @method setValue
+ * @param val {Number} the new value
+ */
+ setValue : function (val) {
+ this.set(VALUE,val);
+ },
+
+ /**
+ * Validator applied to new values for the axis attribute. Only
+ * "x" and "y" are permitted.
+ *
+ * @method _validateNewAxis
+ * @param v {String} proposed value for the axis attribute
+ * @return Boolean
+ * @protected
+ */
+ _validateNewAxis : function (v) {
+ return isString(v) && 'xXyY'.indexOf(v.charAt(0)) > -1;
+ },
+
+ /**
+ * Validator applied to the min attribute.
+ *
+ * @method _validateNewMin
+ * @param v {MIXED} proposed value for the min attribute
+ * @return Boolean
+ * @protected
+ */
+ _validateNewMin : function (v) {
+ return isNumber(v);
+ },
+
+ /**
+ * Validator applied to the max attribute.
+ *
+ * @method _validateNewMax
+ * @param v {MIXED} proposed value for the max attribute
+ * @return Boolean
+ * @protected
+ */
+ _validateNewMax : function (v) {
+ return isNumber(v);
+ },
+
+ /**
+ * Validator applied to the value attribute.
+ *
+ * @method _validateNewValue
+ * @param v {MIXED} proposed value for the value attribute
+ * @return Boolean
+ * @protected
+ */
+ _validateNewValue : function (v) {
+ var min = this.get(MIN),
+ max = this.get(MAX);
+
+ return isNumber(v) &&
+ (min < max ? (v >= min && v <= max) : (v >= max && v <= min));
+ },
+
+ /**
+ * Validator applied to the rail attribute. Rejects all values after the
+ * Slider has been rendered.
+ *
+ * @method _validateNewRail
+ * @param v {MIXED} proposed value for the rail attribute
+ * @return Boolean
+ * @protected
+ */
+ _validateNewRail : function (v) {
+ return !this.get(RENDERED) || v;
+ },
+
+ /**
+ * Validator applied to the thumb attribute. Rejects all values after the
+ * Slider has been rendered.
+ *
+ * @method _validateNewThumb
+ * @param v {MIXED} proposed value for the thumb attribute
+ * @return Boolean
+ * @protected
+ */
+ _validateNewThumb : function (v) {
+ return !this.get(RENDERED) || v;
+ },
+
+ /**
+ * Validator applied to the thumbImage attribute. Rejects all values after
+ * the Slider has been rendered.
+ *
+ * @method _validateNewThumbImage
+ * @param v {MIXED} proposed value for the thumbImage attribute
+ * @return Boolean
+ * @protected
+ */
+ _validateNewThumbImage : function (v) {
+ return !this.get(RENDERED) || v;
+ },
+
+ /**
+ * Validator applied to the railSize attribute. Only strings of css size
+ * values (e.g. '200px') are allowed.
+ *
+ * @method _validateNewRailSize
+ * @param v {String} proposed value for the railSize attribute
+ * @return Boolean
+ * @protected
+ */
+ _validateNewRailSize : function (v) {
+ return isString(v) &&
+ (v === '0' || /^\d+(?:p[xtc]|%|e[mx]|in|[mc]m)$/.test(v));
+ },
+
+ /**
+ * Setter applied to the input when updating the axis attribute.
+ *
+ * @method _setAxisFn
+ * @param v {String} proposed value for the axis attribute
+ * @return {String} lowercased first character of the input string
+ * @protected
+ */
+ _setAxisFn : function (v) {
+ return v.charAt(0).toLowerCase();
+ },
+
+ /**
+ * Setter applied to the input when updating the value attribute. This is
+ * just a placeholder for extension.
+ *
+ * @method _setValueFn
+ * @param v {Number} proposed new value for the Slider
+ * @return {Number} rounded value or configured min if non-number input
+ * @protected
+ */
+ _setValueFn : function (v) { return v; },
+
+ /**
+ * Setter applied to the input when updating the rail attribute. Input can
+ * be a Node, raw HTMLElement, or a selector string to locate it.
+ *
+ * @method _setRailFn
+ * @param v {Node|String|HTMLElement} The rail element Node or selector
+ * @return {Node} The Node if found. Otherwise null.
+ * @protected
+ */
+ _setRailFn : function (v) {
+ return Y.get(v) || null;
+ },
+
+ /**
+ * Setter applied to the input when updating the thumb attribute. Input can
+ * be a Node, raw HTMLElement, or a selector string to locate it.
+ *
+ * @method _setThumbFn
+ * @param v {Node|String|HTMLElement} The thumb element Node or selector
+ * @return {Node} The Node if found. Otherwise null.
+ * @protected
+ */
+ _setThumbFn : function (v) {
+ return Y.get(v) || null;
+ },
+
+ /**
+ * Setter applied to the input when updating the thumbImage attribute.
+ * Input can be a Node, raw HTMLElement, selector string to locate it, or
+ * the URL for an image resource.
+ *
+ * String input will be treated as a selector. If no element is found using
+ * the selector, an <code>img</code> Node will be created with the string
+ * used as the <code>src</code> attribute.
+ *
+ * @method _setThumbImageFn
+ * @param v {Node|String|HTMLElement} The thumbImage element Node, selector,
+ * or image URL
+ * @return {Node} The Node if found or created. Otherwise null.
+ * @protected
+ */
+ _setThumbImageFn : function (v) {
+ return v ? Y.get(v) ||
+ Y.Node.create('<img src="'+v+'" alt="Slider thumb">') :
+ null;
+ },
+
+
+ /**
+ * Caches the current page position of the rail element and fires the
+ * slideStart event in response to the DD's drag:start.
+ *
+ * @method _onDDStartDrag
+ * @param e {Event} the DD instance's drag:start custom event
+ * @protected
+ */
+ _onDDStartDrag : function (e) {
+ this._setRailOffsetXY();
+ this.fire(SLIDE_START,{ ddEvent: e });
+ },
+
+ /**
+ * Fires the thumbDrag event to queue Slider value update.
+ *
+ * @method _onDDDrag
+ * @param e {Event} the DD instance's drag:drag custom event
+ * @protected
+ */
+ _onDDDrag : function (e) {
+ this.fire(THUMB_DRAG, { ddEvent: e });
+ },
+
+ /**
+ * The default value update behavior in response to Slider thumb
+ * interaction. Calculates the value using stored offsets, the _factor
+ * multiplier and the min value.
+ *
+ * @method _defUpdateValueFromDD
+ * @param e {Event} the internal thumbDrag event
+ * @protected
+ */
+ _defUpdateValueFromDD : function (e) {
+ var before = this.get(VALUE),
+ val = e.ddEvent[this._key.eventPageAxis] - this._offsetXY;
+
+
+ val = round(this.get(MIN) + (val * this._factor));
+
+ if (before !== val) {
+ this.set(VALUE, val, { ddEvent: e.ddEvent });
+ }
+ },
+
+ /**
+ * Fires the slideEnd event.
+ *
+ * @method _onDDEndDrag
+ * @param e {Event} the DD instance's drag:end custom event
+ * @protected
+ */
+ _onDDEndDrag : function (e) {
+ this.fire(SLIDE_END,{ ddEvent: e });
+ },
+
+
+
+
+ /**
+ * Calls _uiPositionThumb with the value of the custom event's
+ * "offset" property.
+ *
+ * @method _defPositionThumbFn
+ * @param e {Event} the positionThumb custom event
+ * @protected
+ */
+ _defPositionThumbFn : function (e) {
+
+ this._uiPositionThumb(e.offset);
+ },
+
+ /**
+ * Places the thumb at a particular X or Y location based on the configured
+ * axis.
+ *
+ * @method _uiPositionThumb
+ * @param xy {Number} the desired left or top pixel position of the thumb
+ * in relation to the rail Node.
+ * @protected
+ */
+ _uiPositionThumb : function (xy) {
+ var dd = this._dd,
+ thumb = dd.get('dragNode'),
+ hidden = thumb.ancestor(this._isDisplayNone);
+
+ if (!hidden) {
+ dd._setStartPosition(dd.get('dragNode').getXY());
+
+ // stickX/stickY config on DD instance will negate off-axis move
+ dd._alignNode([xy,xy],true);
+ }
+ },
+
+ /**
+ * Helper function to search up the ancestor axis looking for a node with
+ * style display: none. This is passed as a function to node.ancestor(..)
+ * to test if a given node is in the displayed DOM and can get accurate
+ * positioning information.
+ *
+ * @method _isDisplayNone
+ * @param el {Node} ancestor node as the function walks up the parent axis
+ * @return {Boolean} true if the node is styled with display: none
+ * @protected
+ */
+ _isDisplayNone : function (node) {
+ return node.getComputedStyle('display') === 'none';
+ },
+
+ /**
+ * Fires the internal positionThumb event in response to a change in the
+ * value attribute.
+ *
+ * @method _afterValueChange
+ * @param e {Event} valueChange custom event
+ * @protected
+ */
+ _afterValueChange : function (e) {
+ if (!e.ddEvent) {
+ var xy = this._convertValueToOffset(e.newVal);
+
+
+ this.fire(POSITION_THUMB,{ value: e.newVal, offset: xy });
+ }
+ },
+
+ /**
+ * Converts a value to an integer offset for the thumb position on the rail.
+ *
+ * @method _convertValueToOffset
+ * @param v {Number} value between the Slider's min and max
+ * @protected
+ */
+ _convertValueToOffset : function (v) {
+ return round((v - this.get(MIN)) / this._factor) + this._offsetXY;
+ },
+
+ /**
+ * Replaces the thumb Node in response to a change in the thumb attribute.
+ * This only has effect after the Slider is rendered.
+ *
+ * @method _afterThumbChange
+ * @param e {Event} thumbChange custom event
+ * @protected
+ */
+ _afterThumbChange : function (e) {
+ var thumb;
+
+ if (this.get(RENDERED)) {
+ if (e.prevValue) {
+ e.prevValue.get('parentNode').removeChild(e.prevValue);
+ }
+
+ this._initThumb();
+
+ thumb = this.get(THUMB);
+ this._dd.set('node',thumb);
+ this._dd.set('dragNode',thumb);
+
+ this.syncUI();
+ }
+ },
+
+ /**
+ * Sets or replaces the thumb's contained <code>img</code> Node with the
+ * new Node in response to a change in the thumbImage attribute. This only
+ * has effect after the Slider is rendered.
+ *
+ * @method _afterThumbImageChange
+ * @param e {Event} thumbImageChange custom event
+ * @protected
+ */
+ _afterThumbImageChange : function (e) {
+ if (this.get(RENDERED)) {
+ if (e.prevValue) {
+ e.prevValue.get('parentNode').removeChild(e.prevValue);
+ }
+
+ this._initThumbImage();
+
+ this.syncUI();
+ }
+ },
+
+ /**
+ * Updates the Slider UI in response to change in the min attribute.
+ *
+ * @method _afterMinChange
+ * @param e {Event} minChange custom event
+ * @protected
+ */
+ _afterMinChange : function (e) {
+ this._refresh(e);
+ },
+
+ /**
+ * Updates the Slider UI in response to change in the max attribute.
+ *
+ * @method _afterMaxChange
+ * @param e {Event} maxChange custom event
+ * @protected
+ */
+ _afterMaxChange : function (e) {
+ this._refresh(e);
+ },
+
+ /**
+ * Updates the Slider UI in response to change in the railSize attribute.
+ *
+ * @method _afterRailSizeChange
+ * @param e {Event} railSizeChange custom event
+ * @protected
+ */
+ _afterRailSizeChange : function (e) {
+ this._refresh(e);
+ },
+
+ /**
+ * Locks or unlocks the DD instance in response to a change in the disabled
+ * attribute.
+ *
+ * @method _afterDisabledChange
+ * @param e {Event} disabledChange custom event
+ * @protected
+ */
+ _afterDisabledChange : function (e) {
+ if (this._dd) {
+ this._dd.set('lock',e.newVal);
+ }
+ },
+
+ /**
+ * Common handler to call syncUI in response to change events that occurred
+ * after the Slider is rendered.
+ *
+ * @method _refresh
+ * @param e {Event} An attribute change event
+ * @protected
+ */
+ _refresh : function (e) {
+ if (e.newVal !== e.prevVal && this.get(RENDERED)) {
+ this.syncUI();
+ }
+ },
+
+ /**
+ * Used to determine if there is a current or pending request for the
+ * thumbImage resource.
+ *
+ * @method _isImageLoading
+ * @param img {Node} <code>img</code> Node
+ * @return Boolean
+ * @protected
+ */
+ _isImageLoading : function (img) {
+ return img && !img.get(COMPLETE);
+ },
+
+ /**
+ * Used to determine if the image resource loaded successfully or there was
+ * an error.
+ *
+ * NOTES:
+ * <ul>
+ * <li>img load error fired xbrowser for image resources not yet resolved</li>
+ * <li>img.complete reports false in IE for images not yet loaded as well as images that failed to load</li>
+ * <li>img.complete true && img.naturalWidth == 0 in FF and Safari indicate image failed to load</li>
+ * <li>img.complete && img.width == 0 in Opera indicates image failed to load</li>
+ * </ul>
+ *
+ * @method _isImageLoaded
+ * @param img {Node} <code>img</code> Node
+ * @return Boolean
+ * @protected
+ */
+ _isImageLoaded : function (img) {
+ if (img) {
+ var w = img.get('naturalWidth');
+ return img.get(COMPLETE) && (!isNumber(w) ? img.get(WIDTH) : w);
+ }
+
+ return true;
+ }
+
+});
+
+Y.Slider = Slider;
+
+
+}, '3.0.0b1' ,{requires:['widget','dd-constrain']});