[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/2in3/2.9.0/build/yui2-slider/ -> yui2-slider.js (source)

   1  YUI.add('yui2-slider', function(Y) {
   2      var YAHOO    = Y.YUI2;
   3      /*
   4  Copyright (c) 2011, Yahoo! Inc. All rights reserved.
   5  Code licensed under the BSD License:
   6  http://developer.yahoo.com/yui/license.html
   7  version: 2.9.0
   8  */
   9  /**
  10   * The Slider component is a UI control that enables the user to adjust 
  11   * values in a finite range along one or two axes. Typically, the Slider 
  12   * control is used in a web application as a rich, visual replacement 
  13   * for an input box that takes a number as input. The Slider control can 
  14   * also easily accommodate a second dimension, providing x,y output for 
  15   * a selection point chosen from a rectangular region.
  16   *
  17   * @module    slider
  18   * @title     Slider Widget
  19   * @namespace YAHOO.widget
  20   * @requires  yahoo,dom,dragdrop,event
  21   * @optional  animation
  22   */
  23   (function () {
  24  
  25  var getXY = YAHOO.util.Dom.getXY,
  26      Event = YAHOO.util.Event,
  27      _AS   = Array.prototype.slice;
  28  
  29  /**
  30   * A DragDrop implementation that can be used as a background for a
  31   * slider.  It takes a reference to the thumb instance 
  32   * so it can delegate some of the events to it.  The goal is to make the 
  33   * thumb jump to the location on the background when the background is 
  34   * clicked.  
  35   *
  36   * @class Slider
  37   * @extends YAHOO.util.DragDrop
  38   * @uses YAHOO.util.EventProvider
  39   * @constructor
  40   * @param {String}      id     The id of the element linked to this instance
  41   * @param {String}      sGroup The group of related DragDrop items
  42   * @param {SliderThumb} oThumb The thumb for this slider
  43   * @param {String}      sType  The type of slider (horiz, vert, region)
  44   */
  45  function Slider(sElementId, sGroup, oThumb, sType) {
  46  
  47      Slider.ANIM_AVAIL = (!YAHOO.lang.isUndefined(YAHOO.util.Anim));
  48  
  49      if (sElementId) {
  50          this.init(sElementId, sGroup, true);
  51          this.initSlider(sType);
  52          this.initThumb(oThumb);
  53      }
  54  }
  55  
  56  YAHOO.lang.augmentObject(Slider,{
  57      /**
  58       * Factory method for creating a horizontal slider
  59       * @method YAHOO.widget.Slider.getHorizSlider
  60       * @static
  61       * @param {String} sBGElId the id of the slider's background element
  62       * @param {String} sHandleElId the id of the thumb element
  63       * @param {int} iLeft the number of pixels the element can move left
  64       * @param {int} iRight the number of pixels the element can move right
  65       * @param {int} iTickSize optional parameter for specifying that the element 
  66       * should move a certain number pixels at a time.
  67       * @return {Slider} a horizontal slider control
  68       */
  69      getHorizSlider : 
  70          function (sBGElId, sHandleElId, iLeft, iRight, iTickSize) {
  71              return new Slider(sBGElId, sBGElId, 
  72                  new YAHOO.widget.SliderThumb(sHandleElId, sBGElId, 
  73                                     iLeft, iRight, 0, 0, iTickSize), "horiz");
  74      },
  75  
  76      /**
  77       * Factory method for creating a vertical slider
  78       * @method YAHOO.widget.Slider.getVertSlider
  79       * @static
  80       * @param {String} sBGElId the id of the slider's background element
  81       * @param {String} sHandleElId the id of the thumb element
  82       * @param {int} iUp the number of pixels the element can move up
  83       * @param {int} iDown the number of pixels the element can move down
  84       * @param {int} iTickSize optional parameter for specifying that the element 
  85       * should move a certain number pixels at a time.
  86       * @return {Slider} a vertical slider control
  87       */
  88      getVertSlider :
  89          function (sBGElId, sHandleElId, iUp, iDown, iTickSize) {
  90              return new Slider(sBGElId, sBGElId, 
  91                  new YAHOO.widget.SliderThumb(sHandleElId, sBGElId, 0, 0, 
  92                                     iUp, iDown, iTickSize), "vert");
  93      },
  94  
  95      /**
  96       * Factory method for creating a slider region like the one in the color
  97       * picker example
  98       * @method YAHOO.widget.Slider.getSliderRegion
  99       * @static
 100       * @param {String} sBGElId the id of the slider's background element
 101       * @param {String} sHandleElId the id of the thumb element
 102       * @param {int} iLeft the number of pixels the element can move left
 103       * @param {int} iRight the number of pixels the element can move right
 104       * @param {int} iUp the number of pixels the element can move up
 105       * @param {int} iDown the number of pixels the element can move down
 106       * @param {int} iTickSize optional parameter for specifying that the element 
 107       * should move a certain number pixels at a time.
 108       * @return {Slider} a slider region control
 109       */
 110      getSliderRegion : 
 111          function (sBGElId, sHandleElId, iLeft, iRight, iUp, iDown, iTickSize) {
 112              return new Slider(sBGElId, sBGElId, 
 113                  new YAHOO.widget.SliderThumb(sHandleElId, sBGElId, iLeft, iRight, 
 114                                     iUp, iDown, iTickSize), "region");
 115      },
 116  
 117      /**
 118       * Constant for valueChangeSource, indicating that the user clicked or
 119       * dragged the slider to change the value.
 120       * @property Slider.SOURCE_UI_EVENT
 121       * @final
 122       * @static
 123       * @default 1
 124       */
 125      SOURCE_UI_EVENT : 1,
 126  
 127      /**
 128       * Constant for valueChangeSource, indicating that the value was altered
 129       * by a programmatic call to setValue/setRegionValue.
 130       * @property Slider.SOURCE_SET_VALUE
 131       * @final
 132       * @static
 133       * @default 2
 134       */
 135      SOURCE_SET_VALUE : 2,
 136  
 137      /**
 138       * Constant for valueChangeSource, indicating that the value was altered
 139       * by hitting any of the supported keyboard characters.
 140       * @property Slider.SOURCE_KEY_EVENT
 141       * @final
 142       * @static
 143       * @default 2
 144       */
 145      SOURCE_KEY_EVENT : 3,
 146  
 147      /**
 148       * By default, animation is available if the animation utility is detected.
 149       * @property Slider.ANIM_AVAIL
 150       * @static
 151       * @type boolean
 152       */
 153      ANIM_AVAIL : false
 154  },true);
 155  
 156  YAHOO.extend(Slider, YAHOO.util.DragDrop, {
 157  
 158      /**
 159       * Tracks the state of the mouse button to aid in when events are fired.
 160       *
 161       * @property _mouseDown
 162       * @type boolean
 163       * @default false
 164       * @private
 165       */
 166      _mouseDown : false,
 167  
 168      /**
 169       * Override the default setting of dragOnly to true.
 170       * @property dragOnly
 171       * @type boolean
 172       * @default true
 173       */
 174      dragOnly : true,
 175  
 176      /**
 177       * Initializes the slider.  Executed in the constructor
 178       * @method initSlider
 179       * @param {string} sType the type of slider (horiz, vert, region)
 180       */
 181      initSlider: function(sType) {
 182  
 183          /**
 184           * The type of the slider (horiz, vert, region)
 185           * @property type
 186           * @type string
 187           */
 188          this.type = sType;
 189  
 190          //this.removeInvalidHandleType("A");
 191  
 192  
 193          /**
 194           * Event the fires when the value of the control changes.  If 
 195           * the control is animated the event will fire every point
 196           * along the way.
 197           * @event change
 198           * @param {int} newOffset|x the new offset for normal sliders, or the new
 199           *                          x offset for region sliders
 200           * @param {int} y the number of pixels the thumb has moved on the y axis
 201           *                (region sliders only)
 202           */
 203          this.createEvent("change", this);
 204  
 205          /**
 206           * Event that fires at the beginning of a slider thumb move.
 207           * @event slideStart
 208           */
 209          this.createEvent("slideStart", this);
 210  
 211          /**
 212           * Event that fires at the end of a slider thumb move
 213           * @event slideEnd
 214           */
 215          this.createEvent("slideEnd", this);
 216  
 217          /**
 218           * Overrides the isTarget property in YAHOO.util.DragDrop
 219           * @property isTarget
 220           * @private
 221           */
 222          this.isTarget = false;
 223      
 224          /**
 225           * Flag that determines if the thumb will animate when moved
 226           * @property animate
 227           * @type boolean
 228           */
 229          this.animate = Slider.ANIM_AVAIL;
 230  
 231          /**
 232           * Set to false to disable a background click thumb move
 233           * @property backgroundEnabled
 234           * @type boolean
 235           */
 236          this.backgroundEnabled = true;
 237  
 238          /**
 239           * Adjustment factor for tick animation, the more ticks, the
 240           * faster the animation (by default)
 241           * @property tickPause
 242           * @type int
 243           */
 244          this.tickPause = 40;
 245  
 246          /**
 247           * Enables the arrow, home and end keys, defaults to true.
 248           * @property enableKeys
 249           * @type boolean
 250           */
 251          this.enableKeys = true;
 252  
 253          /**
 254           * Specifies the number of pixels the arrow keys will move the slider.
 255           * Default is 20.
 256           * @property keyIncrement
 257           * @type int
 258           */
 259          this.keyIncrement = 20;
 260  
 261          /**
 262           * moveComplete is set to true when the slider has moved to its final
 263           * destination.  For animated slider, this value can be checked in 
 264           * the onChange handler to make it possible to execute logic only
 265           * when the move is complete rather than at all points along the way.
 266           * Deprecated because this flag is only useful when the background is
 267           * clicked and the slider is animated.  If the user drags the thumb,
 268           * the flag is updated when the drag is over ... the final onDrag event
 269           * fires before the mouseup the ends the drag, so the implementer will
 270           * never see it.
 271           *
 272           * @property moveComplete
 273           * @type Boolean
 274           * @deprecated use the slideEnd event instead
 275           */
 276          this.moveComplete = true;
 277  
 278          /**
 279           * If animation is configured, specifies the length of the animation
 280           * in seconds.
 281           * @property animationDuration
 282           * @type int
 283           * @default 0.2
 284           */
 285          this.animationDuration = 0.2;
 286  
 287          /**
 288           * Constant for valueChangeSource, indicating that the user clicked or
 289           * dragged the slider to change the value.
 290           * @property SOURCE_UI_EVENT
 291           * @final
 292           * @default 1
 293           * @deprecated use static Slider.SOURCE_UI_EVENT
 294           */
 295          this.SOURCE_UI_EVENT = 1;
 296  
 297          /**
 298           * Constant for valueChangeSource, indicating that the value was altered
 299           * by a programmatic call to setValue/setRegionValue.
 300           * @property SOURCE_SET_VALUE
 301           * @final
 302           * @default 2
 303           * @deprecated use static Slider.SOURCE_SET_VALUE
 304           */
 305          this.SOURCE_SET_VALUE = 2;
 306  
 307          /**
 308           * When the slider value changes, this property is set to identify where
 309           * the update came from.  This will be either 1, meaning the slider was
 310           * clicked or dragged, or 2, meaning that it was set via a setValue() call.
 311           * This can be used within event handlers to apply some of the logic only
 312           * when dealing with one source or another.
 313           * @property valueChangeSource
 314           * @type int
 315           * @since 2.3.0
 316           */
 317          this.valueChangeSource = 0;
 318  
 319          /**
 320           * Indicates whether or not events will be supressed for the current
 321           * slide operation
 322           * @property _silent
 323           * @type boolean
 324           * @private
 325           */
 326          this._silent = false;
 327  
 328          /**
 329           * Saved offset used to protect against NaN problems when slider is
 330           * set to display:none
 331           * @property lastOffset
 332           * @type [int, int]
 333           */
 334          this.lastOffset = [0,0];
 335      },
 336  
 337      /**
 338       * Initializes the slider's thumb. Executed in the constructor.
 339       * @method initThumb
 340       * @param {YAHOO.widget.SliderThumb} t the slider thumb
 341       */
 342      initThumb: function(t) {
 343  
 344          var self = this;
 345  
 346          /**
 347           * A YAHOO.widget.SliderThumb instance that we will use to 
 348           * reposition the thumb when the background is clicked
 349           * @property thumb
 350           * @type YAHOO.widget.SliderThumb
 351           */
 352          this.thumb = t;
 353  
 354          t.cacheBetweenDrags = true;
 355  
 356          if (t._isHoriz && t.xTicks && t.xTicks.length) {
 357              this.tickPause = Math.round(360 / t.xTicks.length);
 358          } else if (t.yTicks && t.yTicks.length) {
 359              this.tickPause = Math.round(360 / t.yTicks.length);
 360          }
 361  
 362  
 363          // delegate thumb methods
 364          t.onAvailable = function() { 
 365                  return self.setStartSliderState(); 
 366              };
 367          t.onMouseDown = function () { 
 368                  self._mouseDown = true;
 369                  return self.focus(); 
 370              };
 371          t.startDrag = function() { 
 372                  self._slideStart(); 
 373              };
 374          t.onDrag = function() { 
 375                  self.fireEvents(true); 
 376              };
 377          t.onMouseUp = function() { 
 378                  self.thumbMouseUp(); 
 379              };
 380  
 381      },
 382  
 383      /**
 384       * Executed when the slider element is available
 385       * @method onAvailable
 386       */
 387      onAvailable: function() {
 388          this._bindKeyEvents();
 389      },
 390   
 391      /**
 392       * Sets up the listeners for keydown and key press events.
 393       *
 394       * @method _bindKeyEvents
 395       * @protected
 396       */
 397      _bindKeyEvents : function () {
 398          Event.on(this.id, "keydown",  this.handleKeyDown,  this, true);
 399          Event.on(this.id, "keypress", this.handleKeyPress, this, true);
 400      },
 401  
 402      /**
 403       * Executed when a keypress event happens with the control focused.
 404       * Prevents the default behavior for navigation keys.  The actual
 405       * logic for moving the slider thumb in response to a key event
 406       * happens in handleKeyDown.
 407       * @param {Event} e the keypress event
 408       */
 409      handleKeyPress: function(e) {
 410          if (this.enableKeys) {
 411              var kc = Event.getCharCode(e);
 412  
 413              switch (kc) {
 414                  case 0x25: // left
 415                  case 0x26: // up
 416                  case 0x27: // right
 417                  case 0x28: // down
 418                  case 0x24: // home
 419                  case 0x23: // end
 420                      Event.preventDefault(e);
 421                      break;
 422                  default:
 423              }
 424          }
 425      },
 426  
 427      /**
 428       * Executed when a keydown event happens with the control focused.
 429       * Updates the slider value and display when the keypress is an
 430       * arrow key, home, or end as long as enableKeys is set to true.
 431       * @param {Event} e the keydown event
 432       */
 433      handleKeyDown: function(e) {
 434          if (this.enableKeys) {
 435              var kc = Event.getCharCode(e),
 436                  t  = this.thumb,
 437                  h  = this.getXValue(),
 438                  v  = this.getYValue(),
 439                  changeValue = true;
 440  
 441              switch (kc) {
 442  
 443                  // left
 444                  case 0x25: h -= this.keyIncrement; break;
 445  
 446                  // up
 447                  case 0x26: v -= this.keyIncrement; break;
 448  
 449                  // right
 450                  case 0x27: h += this.keyIncrement; break;
 451  
 452                  // down
 453                  case 0x28: v += this.keyIncrement; break;
 454  
 455                  // home
 456                  case 0x24: h = t.leftConstraint;    
 457                             v = t.topConstraint;    
 458                             break;
 459  
 460                  // end
 461                  case 0x23: h = t.rightConstraint; 
 462                             v = t.bottomConstraint;    
 463                             break;
 464  
 465                  default:   changeValue = false;
 466              }
 467  
 468              if (changeValue) {
 469                  if (t._isRegion) {
 470                      this._setRegionValue(Slider.SOURCE_KEY_EVENT, h, v, true);
 471                  } else {
 472                      this._setValue(Slider.SOURCE_KEY_EVENT,
 473                          (t._isHoriz ? h : v), true);
 474                  }
 475                  Event.stopEvent(e);
 476              }
 477  
 478          }
 479      },
 480  
 481      /**
 482       * Initialization that sets up the value offsets once the elements are ready
 483       * @method setStartSliderState
 484       */
 485      setStartSliderState: function() {
 486  
 487  
 488          this.setThumbCenterPoint();
 489  
 490          /**
 491           * The basline position of the background element, used
 492           * to determine if the background has moved since the last
 493           * operation.
 494           * @property baselinePos
 495           * @type [int, int]
 496           */
 497          this.baselinePos = getXY(this.getEl());
 498  
 499          this.thumb.startOffset = this.thumb.getOffsetFromParent(this.baselinePos);
 500  
 501          if (this.thumb._isRegion) {
 502              if (this.deferredSetRegionValue) {
 503                  this._setRegionValue.apply(this, this.deferredSetRegionValue);
 504                  this.deferredSetRegionValue = null;
 505              } else {
 506                  this.setRegionValue(0, 0, true, true, true);
 507              }
 508          } else {
 509              if (this.deferredSetValue) {
 510                  this._setValue.apply(this, this.deferredSetValue);
 511                  this.deferredSetValue = null;
 512              } else {
 513                  this.setValue(0, true, true, true);
 514              }
 515          }
 516      },
 517  
 518      /**
 519       * When the thumb is available, we cache the centerpoint of the element so
 520       * we can position the element correctly when the background is clicked
 521       * @method setThumbCenterPoint
 522       */
 523      setThumbCenterPoint: function() {
 524  
 525          var el = this.thumb.getEl();
 526  
 527          if (el) {
 528              /**
 529               * The center of the slider element is stored so we can 
 530               * place it in the correct position when the background is clicked.
 531               * @property thumbCenterPoint
 532               * @type {"x": int, "y": int}
 533               */
 534              this.thumbCenterPoint = { 
 535                      x: parseInt(el.offsetWidth/2, 10), 
 536                      y: parseInt(el.offsetHeight/2, 10) 
 537              };
 538          }
 539  
 540      },
 541  
 542      /**
 543       * Locks the slider, overrides YAHOO.util.DragDrop
 544       * @method lock
 545       */
 546      lock: function() {
 547          this.thumb.lock();
 548          this.locked = true;
 549      },
 550  
 551      /**
 552       * Unlocks the slider, overrides YAHOO.util.DragDrop
 553       * @method unlock
 554       */
 555      unlock: function() {
 556          this.thumb.unlock();
 557          this.locked = false;
 558      },
 559  
 560      /**
 561       * Handles mouseup event on the thumb
 562       * @method thumbMouseUp
 563       * @private
 564       */
 565      thumbMouseUp: function() {
 566          this._mouseDown = false;
 567          if (!this.isLocked()) {
 568              this.endMove();
 569          }
 570  
 571      },
 572  
 573      onMouseUp: function() {
 574          this._mouseDown = false;
 575          if (this.backgroundEnabled && !this.isLocked()) {
 576              this.endMove();
 577          }
 578      },
 579  
 580      /**
 581       * Returns a reference to this slider's thumb
 582       * @method getThumb
 583       * @return {SliderThumb} this slider's thumb
 584       */
 585      getThumb: function() {
 586          return this.thumb;
 587      },
 588  
 589      /**
 590       * Try to focus the element when clicked so we can add
 591       * accessibility features
 592       * @method focus
 593       * @private
 594       */
 595      focus: function() {
 596          this.valueChangeSource = Slider.SOURCE_UI_EVENT;
 597  
 598          // Focus the background element if possible
 599          var el = this.getEl();
 600  
 601          if (el.focus) {
 602              try {
 603                  el.focus();
 604              } catch(e) {
 605                  // Prevent permission denied unhandled exception in FF that can
 606                  // happen when setting focus while another element is handling
 607                  // the blur.  @TODO this is still writing to the error log 
 608                  // (unhandled error) in FF1.5 with strict error checking on.
 609              }
 610          }
 611  
 612          this.verifyOffset();
 613  
 614          return !this.isLocked();
 615      },
 616  
 617      /**
 618       * Event that fires when the value of the slider has changed
 619       * @method onChange
 620       * @param {int} firstOffset the number of pixels the thumb has moved
 621       * from its start position. Normal horizontal and vertical sliders will only
 622       * have the firstOffset.  Regions will have both, the first is the horizontal
 623       * offset, the second the vertical.
 624       * @param {int} secondOffset the y offset for region sliders
 625       * @deprecated use instance.subscribe("change") instead
 626       */
 627      onChange: function (firstOffset, secondOffset) { 
 628          /* override me */ 
 629      },
 630  
 631      /**
 632       * Event that fires when the at the beginning of the slider thumb move
 633       * @method onSlideStart
 634       * @deprecated use instance.subscribe("slideStart") instead
 635       */
 636      onSlideStart: function () { 
 637          /* override me */ 
 638      },
 639  
 640      /**
 641       * Event that fires at the end of a slider thumb move
 642       * @method onSliderEnd
 643       * @deprecated use instance.subscribe("slideEnd") instead
 644       */
 645      onSlideEnd: function () { 
 646          /* override me */ 
 647      },
 648  
 649      /**
 650       * Returns the slider's thumb offset from the start position
 651       * @method getValue
 652       * @return {int} the current value
 653       */
 654      getValue: function () { 
 655          return this.thumb.getValue();
 656      },
 657  
 658      /**
 659       * Returns the slider's thumb X offset from the start position
 660       * @method getXValue
 661       * @return {int} the current horizontal offset
 662       */
 663      getXValue: function () { 
 664          return this.thumb.getXValue();
 665      },
 666  
 667      /**
 668       * Returns the slider's thumb Y offset from the start position
 669       * @method getYValue
 670       * @return {int} the current vertical offset
 671       */
 672      getYValue: function () { 
 673          return this.thumb.getYValue();
 674      },
 675  
 676      /**
 677       * Provides a way to set the value of the slider in code.
 678       *
 679       * @method setValue
 680       * @param {int} newOffset the number of pixels the thumb should be
 681       * positioned away from the initial start point 
 682       * @param {boolean} skipAnim set to true to disable the animation
 683       * for this move action (but not others).
 684       * @param {boolean} force ignore the locked setting and set value anyway
 685       * @param {boolean} silent when true, do not fire events
 686       * @return {boolean} true if the move was performed, false if it failed
 687       */
 688      setValue: function() {
 689          var args = _AS.call(arguments);
 690          args.unshift(Slider.SOURCE_SET_VALUE);
 691          return this._setValue.apply(this,args);
 692      },
 693  
 694      /**
 695       * Worker function to execute the value set operation.  Accepts type of
 696       * set operation in addition to the usual setValue params.
 697       *
 698       * @method _setValue
 699       * @param source {int} what triggered the set (e.g. Slider.SOURCE_SET_VALUE)
 700       * @param {int} newOffset the number of pixels the thumb should be
 701       * positioned away from the initial start point 
 702       * @param {boolean} skipAnim set to true to disable the animation
 703       * for this move action (but not others).
 704       * @param {boolean} force ignore the locked setting and set value anyway
 705       * @param {boolean} silent when true, do not fire events
 706       * @return {boolean} true if the move was performed, false if it failed
 707       * @protected
 708       */
 709      _setValue: function(source, newOffset, skipAnim, force, silent) {
 710          var t = this.thumb, newX, newY;
 711  
 712          if (!t.available) {
 713              this.deferredSetValue = arguments;
 714              return false;
 715          }
 716  
 717          if (this.isLocked() && !force) {
 718              return false;
 719          }
 720  
 721          if ( isNaN(newOffset) ) {
 722              return false;
 723          }
 724  
 725          if (t._isRegion) {
 726              return false;
 727          }
 728  
 729  
 730          this._silent = silent;
 731          this.valueChangeSource = source || Slider.SOURCE_SET_VALUE;
 732  
 733          t.lastOffset = [newOffset, newOffset];
 734          this.verifyOffset();
 735  
 736          this._slideStart();
 737  
 738          if (t._isHoriz) {
 739              newX = t.initPageX + newOffset + this.thumbCenterPoint.x;
 740              this.moveThumb(newX, t.initPageY, skipAnim);
 741          } else {
 742              newY = t.initPageY + newOffset + this.thumbCenterPoint.y;
 743              this.moveThumb(t.initPageX, newY, skipAnim);
 744          }
 745  
 746          return true;
 747      },
 748  
 749      /**
 750       * Provides a way to set the value of the region slider in code.
 751       * @method setRegionValue
 752       * @param {int} newOffset the number of pixels the thumb should be
 753       * positioned away from the initial start point (x axis for region)
 754       * @param {int} newOffset2 the number of pixels the thumb should be
 755       * positioned away from the initial start point (y axis for region)
 756       * @param {boolean} skipAnim set to true to disable the animation
 757       * for this move action (but not others).
 758       * @param {boolean} force ignore the locked setting and set value anyway
 759       * @param {boolean} silent when true, do not fire events
 760       * @return {boolean} true if the move was performed, false if it failed
 761       */
 762      setRegionValue : function () {
 763          var args = _AS.call(arguments);
 764          args.unshift(Slider.SOURCE_SET_VALUE);
 765          return this._setRegionValue.apply(this,args);
 766      },
 767  
 768      /**
 769       * Worker function to execute the value set operation.  Accepts type of
 770       * set operation in addition to the usual setValue params.
 771       *
 772       * @method _setRegionValue
 773       * @param source {int} what triggered the set (e.g. Slider.SOURCE_SET_VALUE)
 774       * @param {int} newOffset the number of pixels the thumb should be
 775       * positioned away from the initial start point (x axis for region)
 776       * @param {int} newOffset2 the number of pixels the thumb should be
 777       * positioned away from the initial start point (y axis for region)
 778       * @param {boolean} skipAnim set to true to disable the animation
 779       * for this move action (but not others).
 780       * @param {boolean} force ignore the locked setting and set value anyway
 781       * @param {boolean} silent when true, do not fire events
 782       * @return {boolean} true if the move was performed, false if it failed
 783       * @protected
 784       */
 785      _setRegionValue: function(source, newOffset, newOffset2, skipAnim, force, silent) {
 786          var t = this.thumb, newX, newY;
 787  
 788          if (!t.available) {
 789              this.deferredSetRegionValue = arguments;
 790              return false;
 791          }
 792  
 793          if (this.isLocked() && !force) {
 794              return false;
 795          }
 796  
 797          if ( isNaN(newOffset) ) {
 798              return false;
 799          }
 800  
 801          if (!t._isRegion) {
 802              return false;
 803          }
 804  
 805          this._silent = silent;
 806  
 807          this.valueChangeSource = source || Slider.SOURCE_SET_VALUE;
 808  
 809          t.lastOffset = [newOffset, newOffset2];
 810          this.verifyOffset();
 811  
 812          this._slideStart();
 813  
 814          newX = t.initPageX + newOffset + this.thumbCenterPoint.x;
 815          newY = t.initPageY + newOffset2 + this.thumbCenterPoint.y;
 816          this.moveThumb(newX, newY, skipAnim);
 817  
 818          return true;
 819      },
 820  
 821      /**
 822       * Checks the background position element position.  If it has moved from the
 823       * baseline position, the constraints for the thumb are reset
 824       * @method verifyOffset
 825       * @return {boolean} True if the offset is the same as the baseline.
 826       */
 827      verifyOffset: function() {
 828  
 829          var xy = getXY(this.getEl()),
 830              t  = this.thumb;
 831  
 832          if (!this.thumbCenterPoint || !this.thumbCenterPoint.x) {
 833              this.setThumbCenterPoint();
 834          }
 835  
 836          if (xy) {
 837  
 838  
 839              if (xy[0] != this.baselinePos[0] || xy[1] != this.baselinePos[1]) {
 840  
 841                  // Reset background
 842                  this.setInitPosition();
 843                  this.baselinePos = xy;
 844  
 845                  // Reset thumb
 846                  t.initPageX = this.initPageX + t.startOffset[0];
 847                  t.initPageY = this.initPageY + t.startOffset[1];
 848                  t.deltaSetXY = null;
 849                  this.resetThumbConstraints();
 850  
 851                  return false;
 852              }
 853          }
 854  
 855          return true;
 856      },
 857  
 858      /**
 859       * Move the associated slider moved to a timeout to try to get around the 
 860       * mousedown stealing moz does when I move the slider element between the 
 861       * cursor and the background during the mouseup event
 862       * @method moveThumb
 863       * @param {int} x the X coordinate of the click
 864       * @param {int} y the Y coordinate of the click
 865       * @param {boolean} skipAnim don't animate if the move happend onDrag
 866       * @param {boolean} midMove set to true if this is not terminating
 867       * the slider movement
 868       * @private
 869       */
 870      moveThumb: function(x, y, skipAnim, midMove) {
 871  
 872          var t = this.thumb,
 873              self = this,
 874              p,_p,anim;
 875  
 876          if (!t.available) {
 877              return;
 878          }
 879  
 880  
 881          t.setDelta(this.thumbCenterPoint.x, this.thumbCenterPoint.y);
 882  
 883          _p = t.getTargetCoord(x, y);
 884          p = [Math.round(_p.x), Math.round(_p.y)];
 885  
 886          if (this.animate && t._graduated && !skipAnim) {
 887              this.lock();
 888  
 889              // cache the current thumb pos
 890              this.curCoord = getXY(this.thumb.getEl());
 891              this.curCoord = [Math.round(this.curCoord[0]), Math.round(this.curCoord[1])];
 892  
 893              setTimeout( function() { self.moveOneTick(p); }, this.tickPause );
 894  
 895          } else if (this.animate && Slider.ANIM_AVAIL && !skipAnim) {
 896  
 897              this.lock();
 898  
 899              anim = new YAHOO.util.Motion( 
 900                      t.id, { points: { to: p } }, 
 901                      this.animationDuration, 
 902                      YAHOO.util.Easing.easeOut );
 903  
 904              anim.onComplete.subscribe( function() { 
 905                      self.unlock();
 906                      if (!self._mouseDown) {
 907                          self.endMove(); 
 908                      }
 909                  });
 910              anim.animate();
 911  
 912          } else {
 913              t.setDragElPos(x, y);
 914              if (!midMove && !this._mouseDown) {
 915                  this.endMove();
 916              }
 917          }
 918      },
 919  
 920      _slideStart: function() {
 921          if (!this._sliding) {
 922              if (!this._silent) {
 923                  this.onSlideStart();
 924                  this.fireEvent("slideStart");
 925              }
 926              this._sliding = true;
 927              this.moveComplete = false; // for backward compatibility. Deprecated
 928          }
 929      },
 930  
 931      _slideEnd: function() {
 932          if (this._sliding) {
 933              // Reset state before firing slideEnd
 934              var silent = this._silent;
 935              this._sliding = false;
 936              this.moveComplete = true; // for backward compatibility. Deprecated
 937              this._silent = false;
 938              if (!silent) {
 939                  this.onSlideEnd();
 940                  this.fireEvent("slideEnd");
 941              }
 942          }
 943      },
 944  
 945      /**
 946       * Move the slider one tick mark towards its final coordinate.  Used
 947       * for the animation when tick marks are defined
 948       * @method moveOneTick
 949       * @param {int[]} the destination coordinate
 950       * @private
 951       */
 952      moveOneTick: function(finalCoord) {
 953  
 954          var t = this.thumb,
 955              self = this,
 956              nextCoord = null,
 957              tmpX, tmpY;
 958  
 959          if (t._isRegion) {
 960              nextCoord = this._getNextX(this.curCoord, finalCoord);
 961              tmpX = (nextCoord !== null) ? nextCoord[0] : this.curCoord[0];
 962              nextCoord = this._getNextY(this.curCoord, finalCoord);
 963              tmpY = (nextCoord !== null) ? nextCoord[1] : this.curCoord[1];
 964  
 965              nextCoord = tmpX !== this.curCoord[0] || tmpY !== this.curCoord[1] ?
 966                  [ tmpX, tmpY ] : null;
 967          } else if (t._isHoriz) {
 968              nextCoord = this._getNextX(this.curCoord, finalCoord);
 969          } else {
 970              nextCoord = this._getNextY(this.curCoord, finalCoord);
 971          }
 972  
 973  
 974          if (nextCoord) {
 975  
 976              // cache the position
 977              this.curCoord = nextCoord;
 978  
 979              // move to the next coord
 980              this.thumb.alignElWithMouse(t.getEl(), nextCoord[0] + this.thumbCenterPoint.x, nextCoord[1] + this.thumbCenterPoint.y);
 981              
 982              // check if we are in the final position, if not make a recursive call
 983              if (!(nextCoord[0] == finalCoord[0] && nextCoord[1] == finalCoord[1])) {
 984                  setTimeout(function() { self.moveOneTick(finalCoord); }, 
 985                          this.tickPause);
 986              } else {
 987                  this.unlock();
 988                  if (!this._mouseDown) {
 989                      this.endMove();
 990                  }
 991              }
 992          } else {
 993              this.unlock();
 994              if (!this._mouseDown) {
 995                  this.endMove();
 996              }
 997          }
 998      },
 999  
1000      /**
1001       * Returns the next X tick value based on the current coord and the target coord.
1002       * @method _getNextX
1003       * @private
1004       */
1005      _getNextX: function(curCoord, finalCoord) {
1006          var t = this.thumb,
1007              thresh,
1008              tmp = [],
1009              nextCoord = null;
1010  
1011          if (curCoord[0] > finalCoord[0]) {
1012              thresh = t.tickSize - this.thumbCenterPoint.x;
1013              tmp = t.getTargetCoord( curCoord[0] - thresh, curCoord[1] );
1014              nextCoord = [tmp.x, tmp.y];
1015          } else if (curCoord[0] < finalCoord[0]) {
1016              thresh = t.tickSize + this.thumbCenterPoint.x;
1017              tmp = t.getTargetCoord( curCoord[0] + thresh, curCoord[1] );
1018              nextCoord = [tmp.x, tmp.y];
1019          } else {
1020              // equal, do nothing
1021          }
1022  
1023          return nextCoord;
1024      },
1025  
1026      /**
1027       * Returns the next Y tick value based on the current coord and the target coord.
1028       * @method _getNextY
1029       * @private
1030       */
1031      _getNextY: function(curCoord, finalCoord) {
1032          var t = this.thumb,
1033              thresh,
1034              tmp = [],
1035              nextCoord = null;
1036  
1037          if (curCoord[1] > finalCoord[1]) {
1038              thresh = t.tickSize - this.thumbCenterPoint.y;
1039              tmp = t.getTargetCoord( curCoord[0], curCoord[1] - thresh );
1040              nextCoord = [tmp.x, tmp.y];
1041          } else if (curCoord[1] < finalCoord[1]) {
1042              thresh = t.tickSize + this.thumbCenterPoint.y;
1043              tmp = t.getTargetCoord( curCoord[0], curCoord[1] + thresh );
1044              nextCoord = [tmp.x, tmp.y];
1045          } else {
1046              // equal, do nothing
1047          }
1048  
1049          return nextCoord;
1050      },
1051  
1052      /**
1053       * Resets the constraints before moving the thumb.
1054       * @method b4MouseDown
1055       * @private
1056       */
1057      b4MouseDown: function(e) {
1058          if (!this.backgroundEnabled) {
1059              return false;
1060          }
1061  
1062          this.thumb.autoOffset();
1063          this.baselinePos = [];
1064      },
1065  
1066      /**
1067       * Handles the mousedown event for the slider background
1068       * @method onMouseDown
1069       * @private
1070       */
1071      onMouseDown: function(e) {
1072          if (!this.backgroundEnabled || this.isLocked()) {
1073              return false;
1074          }
1075  
1076          this._mouseDown = true;
1077  
1078          var x = Event.getPageX(e),
1079              y = Event.getPageY(e);
1080  
1081  
1082          this.focus();
1083          this._slideStart();
1084          this.moveThumb(x, y);
1085      },
1086  
1087      /**
1088       * Handles the onDrag event for the slider background
1089       * @method onDrag
1090       * @private
1091       */
1092      onDrag: function(e) {
1093          if (this.backgroundEnabled && !this.isLocked()) {
1094              var x = Event.getPageX(e),
1095                  y = Event.getPageY(e);
1096              this.moveThumb(x, y, true, true);
1097              this.fireEvents();
1098          }
1099      },
1100  
1101      /**
1102       * Fired when the slider movement ends
1103       * @method endMove
1104       * @private
1105       */
1106      endMove: function () {
1107          this.unlock();
1108          this.fireEvents();
1109          this._slideEnd();
1110      },
1111  
1112      /**
1113       * Resets the X and Y contraints for the thumb.  Used in lieu of the thumb
1114       * instance's inherited resetConstraints because some logic was not
1115       * applicable.
1116       * @method resetThumbConstraints
1117       * @protected
1118       */
1119      resetThumbConstraints: function () {
1120          var t = this.thumb;
1121  
1122          t.setXConstraint(t.leftConstraint, t.rightConstraint, t.xTickSize);
1123          t.setYConstraint(t.topConstraint, t.bottomConstraint, t.xTickSize);
1124      },
1125  
1126      /**
1127       * Fires the change event if the value has been changed.  Ignored if we are in
1128       * the middle of an animation as the event will fire when the animation is
1129       * complete
1130       * @method fireEvents
1131       * @param {boolean} thumbEvent set to true if this event is fired from an event
1132       *                  that occurred on the thumb.  If it is, the state of the
1133       *                  thumb dd object should be correct.  Otherwise, the event
1134       *                  originated on the background, so the thumb state needs to
1135       *                  be refreshed before proceeding.
1136       * @private
1137       */
1138      fireEvents: function (thumbEvent) {
1139  
1140          var t = this.thumb, newX, newY, newVal;
1141  
1142          if (!thumbEvent) {
1143              t.cachePosition();
1144          }
1145  
1146          if (! this.isLocked()) {
1147              if (t._isRegion) {
1148                  newX = t.getXValue();
1149                  newY = t.getYValue();
1150  
1151                  if (newX != this.previousX || newY != this.previousY) {
1152                      if (!this._silent) {
1153                          this.onChange(newX, newY);
1154                          this.fireEvent("change", { x: newX, y: newY });
1155                      }
1156                  }
1157  
1158                  this.previousX = newX;
1159                  this.previousY = newY;
1160  
1161              } else {
1162                  newVal = t.getValue();
1163                  if (newVal != this.previousVal) {
1164                      if (!this._silent) {
1165                          this.onChange( newVal );
1166                          this.fireEvent("change", newVal);
1167                      }
1168                  }
1169                  this.previousVal = newVal;
1170              }
1171  
1172          }
1173      },
1174  
1175      /**
1176       * Slider toString
1177       * @method toString
1178       * @return {string} string representation of the instance
1179       */
1180      toString: function () { 
1181          return ("Slider (" + this.type +") " + this.id);
1182      }
1183  
1184  });
1185  
1186  YAHOO.lang.augmentProto(Slider, YAHOO.util.EventProvider);
1187  
1188  YAHOO.widget.Slider = Slider;
1189  })();
1190  /**
1191   * A drag and drop implementation to be used as the thumb of a slider.
1192   * @class SliderThumb
1193   * @extends YAHOO.util.DD
1194   * @constructor
1195   * @param {String} id the id of the slider html element
1196   * @param {String} sGroup the group of related DragDrop items
1197   * @param {int} iLeft the number of pixels the element can move left
1198   * @param {int} iRight the number of pixels the element can move right
1199   * @param {int} iUp the number of pixels the element can move up
1200   * @param {int} iDown the number of pixels the element can move down
1201   * @param {int} iTickSize optional parameter for specifying that the element 
1202   * should move a certain number pixels at a time.
1203   */
1204  YAHOO.widget.SliderThumb = function(id, sGroup, iLeft, iRight, iUp, iDown, iTickSize) {
1205  
1206      if (id) {
1207          YAHOO.widget.SliderThumb.superclass.constructor.call(this, id, sGroup);
1208  
1209          /**
1210           * The id of the thumbs parent HTML element (the slider background 
1211           * element).
1212           * @property parentElId
1213           * @type string
1214           */
1215          this.parentElId = sGroup;
1216      }
1217  
1218  
1219  
1220      /**
1221       * Overrides the isTarget property in YAHOO.util.DragDrop
1222       * @property isTarget
1223       * @private
1224       */
1225      this.isTarget = false;
1226  
1227      /**
1228       * The tick size for this slider
1229       * @property tickSize
1230       * @type int
1231       * @private
1232       */
1233      this.tickSize = iTickSize;
1234  
1235      /**
1236       * Informs the drag and drop util that the offsets should remain when
1237       * resetting the constraints.  This preserves the slider value when
1238       * the constraints are reset
1239       * @property maintainOffset
1240       * @type boolean
1241       * @private
1242       */
1243      this.maintainOffset = true;
1244  
1245      this.initSlider(iLeft, iRight, iUp, iDown, iTickSize);
1246  
1247      /**
1248       * Turns off the autoscroll feature in drag and drop
1249       * @property scroll
1250       * @private
1251       */
1252      this.scroll = false;
1253  
1254  }; 
1255  
1256  YAHOO.extend(YAHOO.widget.SliderThumb, YAHOO.util.DD, {
1257  
1258      /**
1259       * The (X and Y) difference between the thumb location and its parent 
1260       * (the slider background) when the control is instantiated.
1261       * @property startOffset
1262       * @type [int, int]
1263       */
1264      startOffset: null,
1265  
1266      /**
1267       * Override the default setting of dragOnly to true.
1268       * @property dragOnly
1269       * @type boolean
1270       * @default true
1271       */
1272      dragOnly : true,
1273  
1274      /**
1275       * Flag used to figure out if this is a horizontal or vertical slider
1276       * @property _isHoriz
1277       * @type boolean
1278       * @private
1279       */
1280      _isHoriz: false,
1281  
1282      /**
1283       * Cache the last value so we can check for change
1284       * @property _prevVal
1285       * @type int
1286       * @private
1287       */
1288      _prevVal: 0,
1289  
1290      /**
1291       * The slider is _graduated if there is a tick interval defined
1292       * @property _graduated
1293       * @type boolean
1294       * @private
1295       */
1296      _graduated: false,
1297  
1298  
1299      /**
1300       * Returns the difference between the location of the thumb and its parent.
1301       * @method getOffsetFromParent
1302       * @param {[int, int]} parentPos Optionally accepts the position of the parent
1303       * @type [int, int]
1304       */
1305      getOffsetFromParent0: function(parentPos) {
1306          var myPos = YAHOO.util.Dom.getXY(this.getEl()),
1307              ppos  = parentPos || YAHOO.util.Dom.getXY(this.parentElId);
1308  
1309          return [ (myPos[0] - ppos[0]), (myPos[1] - ppos[1]) ];
1310      },
1311  
1312      getOffsetFromParent: function(parentPos) {
1313  
1314          var el = this.getEl(), newOffset,
1315              myPos,ppos,l,t,deltaX,deltaY,newLeft,newTop;
1316  
1317          if (!this.deltaOffset) {
1318  
1319              myPos = YAHOO.util.Dom.getXY(el);
1320              ppos  = parentPos || YAHOO.util.Dom.getXY(this.parentElId);
1321  
1322              newOffset = [ (myPos[0] - ppos[0]), (myPos[1] - ppos[1]) ];
1323  
1324              l = parseInt( YAHOO.util.Dom.getStyle(el, "left"), 10 );
1325              t = parseInt( YAHOO.util.Dom.getStyle(el, "top" ), 10 );
1326  
1327              deltaX = l - newOffset[0];
1328              deltaY = t - newOffset[1];
1329  
1330              if (isNaN(deltaX) || isNaN(deltaY)) {
1331              } else {
1332                  this.deltaOffset = [deltaX, deltaY];
1333              }
1334  
1335          } else {
1336              newLeft = parseInt( YAHOO.util.Dom.getStyle(el, "left"), 10 );
1337              newTop  = parseInt( YAHOO.util.Dom.getStyle(el, "top" ), 10 );
1338  
1339              newOffset  = [newLeft + this.deltaOffset[0], newTop + this.deltaOffset[1]];
1340          }
1341  
1342          return newOffset;
1343      },
1344  
1345      /**
1346       * Set up the slider, must be called in the constructor of all subclasses
1347       * @method initSlider
1348       * @param {int} iLeft the number of pixels the element can move left
1349       * @param {int} iRight the number of pixels the element can move right
1350       * @param {int} iUp the number of pixels the element can move up
1351       * @param {int} iDown the number of pixels the element can move down
1352       * @param {int} iTickSize the width of the tick interval.
1353       */
1354      initSlider: function (iLeft, iRight, iUp, iDown, iTickSize) {
1355          this.initLeft = iLeft;
1356          this.initRight = iRight;
1357          this.initUp = iUp;
1358          this.initDown = iDown;
1359  
1360          this.setXConstraint(iLeft, iRight, iTickSize);
1361          this.setYConstraint(iUp, iDown, iTickSize);
1362  
1363          if (iTickSize && iTickSize > 1) {
1364              this._graduated = true;
1365          }
1366  
1367          this._isHoriz  = (iLeft || iRight); 
1368          this._isVert   = (iUp   || iDown);
1369          this._isRegion = (this._isHoriz && this._isVert); 
1370  
1371      },
1372  
1373      /**
1374       * Clear's the slider's ticks
1375       * @method clearTicks
1376       */
1377      clearTicks: function () {
1378          YAHOO.widget.SliderThumb.superclass.clearTicks.call(this);
1379          this.tickSize = 0;
1380          this._graduated = false;
1381      },
1382  
1383  
1384      /**
1385       * Gets the current offset from the element's start position in
1386       * pixels.
1387       * @method getValue
1388       * @return {int} the number of pixels (positive or negative) the
1389       * slider has moved from the start position.
1390       */
1391      getValue: function () {
1392          return (this._isHoriz) ? this.getXValue() : this.getYValue();
1393      },
1394  
1395      /**
1396       * Gets the current X offset from the element's start position in
1397       * pixels.
1398       * @method getXValue
1399       * @return {int} the number of pixels (positive or negative) the
1400       * slider has moved horizontally from the start position.
1401       */
1402      getXValue: function () {
1403          if (!this.available) { 
1404              return 0; 
1405          }
1406          var newOffset = this.getOffsetFromParent();
1407          if (YAHOO.lang.isNumber(newOffset[0])) {
1408              this.lastOffset = newOffset;
1409              return (newOffset[0] - this.startOffset[0]);
1410          } else {
1411              return (this.lastOffset[0] - this.startOffset[0]);
1412          }
1413      },
1414  
1415      /**
1416       * Gets the current Y offset from the element's start position in
1417       * pixels.
1418       * @method getYValue
1419       * @return {int} the number of pixels (positive or negative) the
1420       * slider has moved vertically from the start position.
1421       */
1422      getYValue: function () {
1423          if (!this.available) { 
1424              return 0; 
1425          }
1426          var newOffset = this.getOffsetFromParent();
1427          if (YAHOO.lang.isNumber(newOffset[1])) {
1428              this.lastOffset = newOffset;
1429              return (newOffset[1] - this.startOffset[1]);
1430          } else {
1431              return (this.lastOffset[1] - this.startOffset[1]);
1432          }
1433      },
1434  
1435      /**
1436       * Thumb toString
1437       * @method toString
1438       * @return {string} string representation of the instance
1439       */
1440      toString: function () { 
1441          return "SliderThumb " + this.id;
1442      },
1443  
1444      /**
1445       * The onchange event for the handle/thumb is delegated to the YAHOO.widget.Slider
1446       * instance it belongs to.
1447       * @method onChange
1448       * @private
1449       */
1450      onChange: function (x, y) { 
1451      }
1452  
1453  });
1454  /**
1455   * A slider with two thumbs, one that represents the min value and 
1456   * the other the max.  Actually a composition of two sliders, both with
1457   * the same background.  The constraints for each slider are adjusted
1458   * dynamically so that the min value of the max slider is equal or greater
1459   * to the current value of the min slider, and the max value of the min
1460   * slider is the current value of the max slider.
1461   * Constructor assumes both thumbs are positioned absolutely at the 0 mark on
1462   * the background.
1463   *
1464   * @namespace YAHOO.widget
1465   * @class DualSlider
1466   * @uses YAHOO.util.EventProvider
1467   * @constructor
1468   * @param {Slider} minSlider The Slider instance used for the min value thumb
1469   * @param {Slider} maxSlider The Slider instance used for the max value thumb
1470   * @param {int}    range The number of pixels the thumbs may move within
1471   * @param {Array}  initVals (optional) [min,max] Initial thumb placement
1472   */
1473  (function () {
1474  
1475  var Event = YAHOO.util.Event,
1476      YW = YAHOO.widget;
1477  
1478  function DualSlider(minSlider, maxSlider, range, initVals) {
1479  
1480      var self  = this,
1481          ready = { min : false, max : false },
1482          minThumbOnMouseDown, maxThumbOnMouseDown;
1483  
1484      /**
1485       * A slider instance that keeps track of the lower value of the range.
1486       * <strong>read only</strong>
1487       * @property minSlider
1488       * @type Slider
1489       */
1490      this.minSlider = minSlider;
1491  
1492      /**
1493       * A slider instance that keeps track of the upper value of the range.
1494       * <strong>read only</strong>
1495       * @property maxSlider
1496       * @type Slider
1497       */
1498      this.maxSlider = maxSlider;
1499  
1500      /**
1501       * The currently active slider (min or max). <strong>read only</strong>
1502       * @property activeSlider
1503       * @type Slider
1504       */
1505      this.activeSlider = minSlider;
1506  
1507      /**
1508       * Is the DualSlider oriented horizontally or vertically?
1509       * <strong>read only</strong>
1510       * @property isHoriz
1511       * @type boolean
1512       */
1513      this.isHoriz = minSlider.thumb._isHoriz;
1514  
1515      //FIXME: this is horrible
1516      minThumbOnMouseDown = this.minSlider.thumb.onMouseDown;
1517      maxThumbOnMouseDown = this.maxSlider.thumb.onMouseDown;
1518      this.minSlider.thumb.onMouseDown = function() {
1519          self.activeSlider = self.minSlider;
1520          minThumbOnMouseDown.apply(this,arguments);
1521      };
1522      this.maxSlider.thumb.onMouseDown = function () {
1523          self.activeSlider = self.maxSlider;
1524          maxThumbOnMouseDown.apply(this,arguments);
1525      };
1526  
1527      this.minSlider.thumb.onAvailable = function () {
1528          minSlider.setStartSliderState();
1529          ready.min = true;
1530          if (ready.max) {
1531              self.fireEvent('ready',self);
1532          }
1533      };
1534      this.maxSlider.thumb.onAvailable = function () {
1535          maxSlider.setStartSliderState();
1536          ready.max = true;
1537          if (ready.min) {
1538              self.fireEvent('ready',self);
1539          }
1540      };
1541  
1542      // dispatch mousedowns to the active slider
1543      minSlider.onMouseDown =
1544      maxSlider.onMouseDown = function(e) {
1545          return this.backgroundEnabled && self._handleMouseDown(e);
1546      };
1547  
1548      // Fix the drag behavior so that only the active slider
1549      // follows the drag
1550      minSlider.onDrag =
1551      maxSlider.onDrag = function(e) {
1552          self._handleDrag(e);
1553      };
1554  
1555      // Likely only the minSlider's onMouseUp will be executed, but both are
1556      // overridden just to be safe
1557      minSlider.onMouseUp =
1558      maxSlider.onMouseUp = function (e) {
1559          self._handleMouseUp(e);
1560      };
1561  
1562      // Replace the _bindKeyEvents for the minSlider and remove that for the
1563      // maxSlider since they share the same bg element.
1564      minSlider._bindKeyEvents = function () {
1565          self._bindKeyEvents(this);
1566      };
1567      maxSlider._bindKeyEvents = function () {};
1568  
1569      // The core events for each slider are handled so we can expose a single
1570      // event for when the event happens on either slider
1571      minSlider.subscribe("change", this._handleMinChange, minSlider, this);
1572      minSlider.subscribe("slideStart", this._handleSlideStart, minSlider, this);
1573      minSlider.subscribe("slideEnd", this._handleSlideEnd, minSlider, this);
1574  
1575      maxSlider.subscribe("change", this._handleMaxChange, maxSlider, this);
1576      maxSlider.subscribe("slideStart", this._handleSlideStart, maxSlider, this);
1577      maxSlider.subscribe("slideEnd", this._handleSlideEnd, maxSlider, this);
1578  
1579      /**
1580       * Event that fires when the slider is finished setting up
1581       * @event ready
1582       * @param {DualSlider} dualslider the DualSlider instance
1583       */
1584      this.createEvent("ready", this);
1585  
1586      /**
1587       * Event that fires when either the min or max value changes
1588       * @event change
1589       * @param {DualSlider} dualslider the DualSlider instance
1590       */
1591      this.createEvent("change", this);
1592  
1593      /**
1594       * Event that fires when one of the thumbs begins to move
1595       * @event slideStart
1596       * @param {Slider} activeSlider the moving slider
1597       */
1598      this.createEvent("slideStart", this);
1599  
1600      /**
1601       * Event that fires when one of the thumbs finishes moving
1602       * @event slideEnd
1603       * @param {Slider} activeSlider the moving slider
1604       */
1605      this.createEvent("slideEnd", this);
1606  
1607      // Validate initial values
1608      initVals = YAHOO.lang.isArray(initVals) ? initVals : [0,range];
1609      initVals[0] = Math.min(Math.max(parseInt(initVals[0],10)|0,0),range);
1610      initVals[1] = Math.max(Math.min(parseInt(initVals[1],10)|0,range),0);
1611      // Swap initVals if min > max
1612      if (initVals[0] > initVals[1]) {
1613          initVals.splice(0,2,initVals[1],initVals[0]);
1614      }
1615      this.minVal = initVals[0];
1616      this.maxVal = initVals[1];
1617  
1618      // Set values so initial assignment when the slider thumbs are ready will
1619      // use these values
1620      this.minSlider.setValue(this.minVal,true,true,true);
1621      this.maxSlider.setValue(this.maxVal,true,true,true);
1622  
1623  }
1624  
1625  DualSlider.prototype = {
1626  
1627      /**
1628       * The current value of the min thumb. <strong>read only</strong>.
1629       * @property minVal
1630       * @type int
1631       */
1632      minVal : -1,
1633  
1634      /**
1635       * The current value of the max thumb. <strong>read only</strong>.
1636       * @property maxVal
1637       * @type int
1638       */
1639      maxVal : -1,
1640  
1641      /**
1642       * Pixel distance to maintain between thumbs.
1643       * @property minRange
1644       * @type int
1645       * @default 0
1646       */
1647      minRange : 0,
1648  
1649      /**
1650       * Executed when one of the sliders fires the slideStart event
1651       * @method _handleSlideStart
1652       * @private
1653       */
1654      _handleSlideStart: function(data, slider) {
1655          this.fireEvent("slideStart", slider);
1656      },
1657  
1658      /**
1659       * Executed when one of the sliders fires the slideEnd event
1660       * @method _handleSlideEnd
1661       * @private
1662       */
1663      _handleSlideEnd: function(data, slider) {
1664          this.fireEvent("slideEnd", slider);
1665      },
1666  
1667      /**
1668       * Overrides the onDrag method for both sliders
1669       * @method _handleDrag
1670       * @private
1671       */
1672      _handleDrag: function(e) {
1673          YW.Slider.prototype.onDrag.call(this.activeSlider, e);
1674      },
1675  
1676      /**
1677       * Executed when the min slider fires the change event
1678       * @method _handleMinChange
1679       * @private
1680       */
1681      _handleMinChange: function() {
1682          this.activeSlider = this.minSlider;
1683          this.updateValue();
1684      },
1685  
1686      /**
1687       * Executed when the max slider fires the change event
1688       * @method _handleMaxChange
1689       * @private
1690       */
1691      _handleMaxChange: function() {
1692          this.activeSlider = this.maxSlider;
1693          this.updateValue();
1694      },
1695  
1696      /**
1697       * Set up the listeners for the keydown and keypress events.
1698       *
1699       * @method _bindKeyEvents
1700       * @protected
1701       */
1702      _bindKeyEvents : function (slider) {
1703          Event.on(slider.id,'keydown', this._handleKeyDown, this,true);
1704          Event.on(slider.id,'keypress',this._handleKeyPress,this,true);
1705      },
1706  
1707      /**
1708       * Delegate event handling to the active Slider.  See Slider.handleKeyDown.
1709       *
1710       * @method _handleKeyDown
1711       * @param e {Event} the mousedown DOM event
1712       * @protected
1713       */
1714      _handleKeyDown : function (e) {
1715          this.activeSlider.handleKeyDown.apply(this.activeSlider,arguments);
1716      },
1717  
1718      /**
1719       * Delegate event handling to the active Slider.  See Slider.handleKeyPress.
1720       *
1721       * @method _handleKeyPress
1722       * @param e {Event} the mousedown DOM event
1723       * @protected
1724       */
1725      _handleKeyPress : function (e) {
1726          this.activeSlider.handleKeyPress.apply(this.activeSlider,arguments);
1727      },
1728  
1729      /**
1730       * Sets the min and max thumbs to new values.
1731       * @method setValues
1732       * @param min {int} Pixel offset to assign to the min thumb
1733       * @param max {int} Pixel offset to assign to the max thumb
1734       * @param skipAnim {boolean} (optional) Set to true to skip thumb animation.
1735       * Default false
1736       * @param force {boolean} (optional) ignore the locked setting and set
1737       * value anyway. Default false
1738       * @param silent {boolean} (optional) Set to true to skip firing change
1739       * events.  Default false
1740       */
1741      setValues : function (min, max, skipAnim, force, silent) {
1742          var mins = this.minSlider,
1743              maxs = this.maxSlider,
1744              mint = mins.thumb,
1745              maxt = maxs.thumb,
1746              self = this,
1747              done = { min : false, max : false };
1748  
1749          // Clear constraints to prevent animated thumbs from prematurely
1750          // stopping when hitting a constraint that's moving with the other
1751          // thumb.
1752          if (mint._isHoriz) {
1753              mint.setXConstraint(mint.leftConstraint,maxt.rightConstraint,mint.tickSize);
1754              maxt.setXConstraint(mint.leftConstraint,maxt.rightConstraint,maxt.tickSize);
1755          } else {
1756              mint.setYConstraint(mint.topConstraint,maxt.bottomConstraint,mint.tickSize);
1757              maxt.setYConstraint(mint.topConstraint,maxt.bottomConstraint,maxt.tickSize);
1758          }
1759  
1760          // Set up one-time slideEnd callbacks to call updateValue when both
1761          // thumbs have been set
1762          this._oneTimeCallback(mins,'slideEnd',function () {
1763              done.min = true;
1764              if (done.max) {
1765                  self.updateValue(silent);
1766                  // Clean the slider's slideEnd events on a timeout since this
1767                  // will be executed from inside the event's fire
1768                  setTimeout(function () {
1769                      self._cleanEvent(mins,'slideEnd');
1770                      self._cleanEvent(maxs,'slideEnd');
1771                  },0);
1772              }
1773          });
1774  
1775          this._oneTimeCallback(maxs,'slideEnd',function () {
1776              done.max = true;
1777              if (done.min) {
1778                  self.updateValue(silent);
1779                  // Clean both sliders' slideEnd events on a timeout since this
1780                  // will be executed from inside one of the event's fire
1781                  setTimeout(function () {
1782                      self._cleanEvent(mins,'slideEnd');
1783                      self._cleanEvent(maxs,'slideEnd');
1784                  },0);
1785              }
1786          });
1787  
1788          // Must emit Slider slideEnd event to propagate to updateValue
1789          mins.setValue(min,skipAnim,force,false);
1790          maxs.setValue(max,skipAnim,force,false);
1791      },
1792  
1793      /**
1794       * Set the min thumb position to a new value.
1795       * @method setMinValue
1796       * @param min {int} Pixel offset for min thumb
1797       * @param skipAnim {boolean} (optional) Set to true to skip thumb animation.
1798       * Default false
1799       * @param force {boolean} (optional) ignore the locked setting and set
1800       * value anyway. Default false
1801       * @param silent {boolean} (optional) Set to true to skip firing change
1802       * events.  Default false
1803       */
1804      setMinValue : function (min, skipAnim, force, silent) {
1805          var mins = this.minSlider,
1806              self = this;
1807  
1808          this.activeSlider = mins;
1809  
1810          // Use a one-time event callback to delay the updateValue call
1811          // until after the slide operation is done
1812          self = this;
1813          this._oneTimeCallback(mins,'slideEnd',function () {
1814              self.updateValue(silent);
1815              // Clean the slideEnd event on a timeout since this
1816              // will be executed from inside the event's fire
1817              setTimeout(function () { self._cleanEvent(mins,'slideEnd'); }, 0);
1818          });
1819  
1820          mins.setValue(min, skipAnim, force);
1821      },
1822  
1823      /**
1824       * Set the max thumb position to a new value.
1825       * @method setMaxValue
1826       * @param max {int} Pixel offset for max thumb
1827       * @param skipAnim {boolean} (optional) Set to true to skip thumb animation.
1828       * Default false
1829       * @param force {boolean} (optional) ignore the locked setting and set
1830       * value anyway. Default false
1831       * @param silent {boolean} (optional) Set to true to skip firing change
1832       * events.  Default false
1833       */
1834      setMaxValue : function (max, skipAnim, force, silent) {
1835          var maxs = this.maxSlider,
1836              self = this;
1837  
1838          this.activeSlider = maxs;
1839  
1840          // Use a one-time event callback to delay the updateValue call
1841          // until after the slide operation is done
1842          this._oneTimeCallback(maxs,'slideEnd',function () {
1843              self.updateValue(silent);
1844              // Clean the slideEnd event on a timeout since this
1845              // will be executed from inside the event's fire
1846              setTimeout(function () { self._cleanEvent(maxs,'slideEnd'); }, 0);
1847          });
1848  
1849          maxs.setValue(max, skipAnim, force);
1850      },
1851  
1852      /**
1853       * Executed when one of the sliders is moved
1854       * @method updateValue
1855       * @param silent {boolean} (optional) Set to true to skip firing change
1856       * events.  Default false
1857       * @private
1858       */
1859      updateValue: function(silent) {
1860          var min     = this.minSlider.getValue(),
1861              max     = this.maxSlider.getValue(),
1862              changed = false,
1863              mint,maxt,dim,minConstraint,maxConstraint,thumbInnerWidth;
1864  
1865          if (min != this.minVal || max != this.maxVal) {
1866              changed = true;
1867  
1868              mint = this.minSlider.thumb;
1869              maxt = this.maxSlider.thumb;
1870              dim  = this.isHoriz ? 'x' : 'y';
1871  
1872              thumbInnerWidth = this.minSlider.thumbCenterPoint[dim] +
1873                                this.maxSlider.thumbCenterPoint[dim];
1874  
1875              // Establish barriers within the respective other thumb's edge, less
1876              // the minRange.  Limit to the Slider's range in the case of
1877              // negative minRanges.
1878              minConstraint = Math.max(max-thumbInnerWidth-this.minRange,0);
1879              maxConstraint = Math.min(-min-thumbInnerWidth-this.minRange,0);
1880  
1881              if (this.isHoriz) {
1882                  minConstraint = Math.min(minConstraint,maxt.rightConstraint);
1883  
1884                  mint.setXConstraint(mint.leftConstraint,minConstraint, mint.tickSize);
1885  
1886                  maxt.setXConstraint(maxConstraint,maxt.rightConstraint, maxt.tickSize);
1887              } else {
1888                  minConstraint = Math.min(minConstraint,maxt.bottomConstraint);
1889                  mint.setYConstraint(mint.leftConstraint,minConstraint, mint.tickSize);
1890  
1891                  maxt.setYConstraint(maxConstraint,maxt.bottomConstraint, maxt.tickSize);
1892              }
1893          }
1894  
1895          this.minVal = min;
1896          this.maxVal = max;
1897  
1898          if (changed && !silent) {
1899              this.fireEvent("change", this);
1900          }
1901      },
1902  
1903      /**
1904       * A background click will move the slider thumb nearest to the click.
1905       * Override if you need different behavior.
1906       * @method selectActiveSlider
1907       * @param e {Event} the mousedown event
1908       * @private
1909       */
1910      selectActiveSlider: function(e) {
1911          var min = this.minSlider,
1912              max = this.maxSlider,
1913              minLocked = min.isLocked() || !min.backgroundEnabled,
1914              maxLocked = max.isLocked() || !min.backgroundEnabled,
1915              Ev  = YAHOO.util.Event,
1916              d;
1917  
1918          if (minLocked || maxLocked) {
1919              this.activeSlider = minLocked ? max : min;
1920          } else {
1921              if (this.isHoriz) {
1922                  d = Ev.getPageX(e)-min.thumb.initPageX-min.thumbCenterPoint.x;
1923              } else {
1924                  d = Ev.getPageY(e)-min.thumb.initPageY-min.thumbCenterPoint.y;
1925              }
1926                      
1927              this.activeSlider = d*2 > max.getValue()+min.getValue() ? max : min;
1928          }
1929      },
1930  
1931      /**
1932       * Delegates the onMouseDown to the appropriate Slider
1933       *
1934       * @method _handleMouseDown
1935       * @param e {Event} mouseup event
1936       * @protected
1937       */
1938      _handleMouseDown: function(e) {
1939          if (!e._handled && !this.minSlider._sliding && !this.maxSlider._sliding) {
1940              e._handled = true;
1941              this.selectActiveSlider(e);
1942              return YW.Slider.prototype.onMouseDown.call(this.activeSlider, e);
1943          } else {
1944              return false;
1945          }
1946      },
1947  
1948      /**
1949       * Delegates the onMouseUp to the active Slider
1950       *
1951       * @method _handleMouseUp
1952       * @param e {Event} mouseup event
1953       * @protected
1954       */
1955      _handleMouseUp : function (e) {
1956          YW.Slider.prototype.onMouseUp.apply(
1957              this.activeSlider, arguments);
1958      },
1959  
1960      /**
1961       * Schedule an event callback that will execute once, then unsubscribe
1962       * itself.
1963       * @method _oneTimeCallback
1964       * @param o {EventProvider} Object to attach the event to
1965       * @param evt {string} Name of the event
1966       * @param fn {Function} function to execute once
1967       * @private
1968       */
1969      _oneTimeCallback : function (o,evt,fn) {
1970          var sub = function () {
1971              // Unsubscribe myself
1972              o.unsubscribe(evt, sub);
1973              // Pass the event handler arguments to the one time callback
1974              fn.apply({},arguments);
1975          };
1976          o.subscribe(evt,sub);
1977      },
1978  
1979      /**
1980       * Clean up the slideEnd event subscribers array, since each one-time
1981       * callback will be replaced in the event's subscribers property with
1982       * null.  This will cause memory bloat and loss of performance.
1983       * @method _cleanEvent
1984       * @param o {EventProvider} object housing the CustomEvent
1985       * @param evt {string} name of the CustomEvent
1986       * @private
1987       */
1988      _cleanEvent : function (o,evt) {
1989          var ce,i,len,j,subs,newSubs;
1990  
1991          if (o.__yui_events && o.events[evt]) {
1992              for (i = o.__yui_events.length; i >= 0; --i) {
1993                  if (o.__yui_events[i].type === evt) {
1994                      ce = o.__yui_events[i];
1995                      break;
1996                  }
1997              }
1998              if (ce) {
1999                  subs    = ce.subscribers;
2000                  newSubs = [];
2001                  j = 0;
2002                  for (i = 0, len = subs.length; i < len; ++i) {
2003                      if (subs[i]) {
2004                          newSubs[j++] = subs[i];
2005                      }
2006                  }
2007                  ce.subscribers = newSubs;
2008              }
2009          }
2010      }
2011  
2012  };
2013  
2014  YAHOO.lang.augmentProto(DualSlider, YAHOO.util.EventProvider);
2015  
2016  
2017  /**
2018   * Factory method for creating a horizontal dual-thumb slider
2019   * @for YAHOO.widget.Slider
2020   * @method YAHOO.widget.Slider.getHorizDualSlider
2021   * @static
2022   * @param {String} bg the id of the slider's background element
2023   * @param {String} minthumb the id of the min thumb
2024   * @param {String} maxthumb the id of the thumb thumb
2025   * @param {int} range the number of pixels the thumbs can move within
2026   * @param {int} iTickSize (optional) the element should move this many pixels
2027   * at a time
2028   * @param {Array}  initVals (optional) [min,max] Initial thumb placement
2029   * @return {DualSlider} a horizontal dual-thumb slider control
2030   */
2031  YW.Slider.getHorizDualSlider = 
2032      function (bg, minthumb, maxthumb, range, iTickSize, initVals) {
2033          var mint = new YW.SliderThumb(minthumb, bg, 0, range, 0, 0, iTickSize),
2034              maxt = new YW.SliderThumb(maxthumb, bg, 0, range, 0, 0, iTickSize);
2035  
2036          return new DualSlider(
2037                      new YW.Slider(bg, bg, mint, "horiz"),
2038                      new YW.Slider(bg, bg, maxt, "horiz"),
2039                      range, initVals);
2040  };
2041  
2042  /**
2043   * Factory method for creating a vertical dual-thumb slider.
2044   * @for YAHOO.widget.Slider
2045   * @method YAHOO.widget.Slider.getVertDualSlider
2046   * @static
2047   * @param {String} bg the id of the slider's background element
2048   * @param {String} minthumb the id of the min thumb
2049   * @param {String} maxthumb the id of the thumb thumb
2050   * @param {int} range the number of pixels the thumbs can move within
2051   * @param {int} iTickSize (optional) the element should move this many pixels
2052   * at a time
2053   * @param {Array}  initVals (optional) [min,max] Initial thumb placement
2054   * @return {DualSlider} a vertical dual-thumb slider control
2055   */
2056  YW.Slider.getVertDualSlider = 
2057      function (bg, minthumb, maxthumb, range, iTickSize, initVals) {
2058          var mint = new YW.SliderThumb(minthumb, bg, 0, 0, 0, range, iTickSize),
2059              maxt = new YW.SliderThumb(maxthumb, bg, 0, 0, 0, range, iTickSize);
2060  
2061          return new YW.DualSlider(
2062                      new YW.Slider(bg, bg, mint, "vert"),
2063                      new YW.Slider(bg, bg, maxt, "vert"),
2064                      range, initVals);
2065  };
2066  
2067  YAHOO.widget.DualSlider = DualSlider;
2068  
2069  })();
2070  YAHOO.register("slider", YAHOO.widget.Slider, {version: "2.9.0", build: "2800"});
2071  
2072  }, '2.9.0' ,{"requires": ["yui2-yahoo", "yui2-dom", "yui2-skin-sam-slider", "yui2-event", "yui2-dragdrop"], "optional": ["yui2-animation"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1