[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |