[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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