web/wp-includes/js/scriptaculous/slider.js
changeset 136 bde1974c263b
child 194 32102edaa81b
equal deleted inserted replaced
135:53cff4b4a802 136:bde1974c263b
       
     1 // script.aculo.us slider.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
       
     2 
       
     3 // Copyright (c) 2005-2007 Marty Haught, Thomas Fuchs 
       
     4 //
       
     5 // script.aculo.us is freely distributable under the terms of an MIT-style license.
       
     6 // For details, see the script.aculo.us web site: http://script.aculo.us/
       
     7 
       
     8 if (!Control) var Control = { };
       
     9 
       
    10 // options:
       
    11 //  axis: 'vertical', or 'horizontal' (default)
       
    12 //
       
    13 // callbacks:
       
    14 //  onChange(value)
       
    15 //  onSlide(value)
       
    16 Control.Slider = Class.create({
       
    17   initialize: function(handle, track, options) {
       
    18     var slider = this;
       
    19     
       
    20     if (Object.isArray(handle)) {
       
    21       this.handles = handle.collect( function(e) { return $(e) });
       
    22     } else {
       
    23       this.handles = [$(handle)];
       
    24     }
       
    25     
       
    26     this.track   = $(track);
       
    27     this.options = options || { };
       
    28 
       
    29     this.axis      = this.options.axis || 'horizontal';
       
    30     this.increment = this.options.increment || 1;
       
    31     this.step      = parseInt(this.options.step || '1');
       
    32     this.range     = this.options.range || $R(0,1);
       
    33     
       
    34     this.value     = 0; // assure backwards compat
       
    35     this.values    = this.handles.map( function() { return 0 });
       
    36     this.spans     = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
       
    37     this.options.startSpan = $(this.options.startSpan || null);
       
    38     this.options.endSpan   = $(this.options.endSpan || null);
       
    39 
       
    40     this.restricted = this.options.restricted || false;
       
    41 
       
    42     this.maximum   = this.options.maximum || this.range.end;
       
    43     this.minimum   = this.options.minimum || this.range.start;
       
    44 
       
    45     // Will be used to align the handle onto the track, if necessary
       
    46     this.alignX = parseInt(this.options.alignX || '0');
       
    47     this.alignY = parseInt(this.options.alignY || '0');
       
    48     
       
    49     this.trackLength = this.maximumOffset() - this.minimumOffset();
       
    50 
       
    51     this.handleLength = this.isVertical() ? 
       
    52       (this.handles[0].offsetHeight != 0 ? 
       
    53         this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : 
       
    54       (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : 
       
    55         this.handles[0].style.width.replace(/px$/,""));
       
    56 
       
    57     this.active   = false;
       
    58     this.dragging = false;
       
    59     this.disabled = false;
       
    60 
       
    61     if (this.options.disabled) this.setDisabled();
       
    62 
       
    63     // Allowed values array
       
    64     this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
       
    65     if (this.allowedValues) {
       
    66       this.minimum = this.allowedValues.min();
       
    67       this.maximum = this.allowedValues.max();
       
    68     }
       
    69 
       
    70     this.eventMouseDown = this.startDrag.bindAsEventListener(this);
       
    71     this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
       
    72     this.eventMouseMove = this.update.bindAsEventListener(this);
       
    73 
       
    74     // Initialize handles in reverse (make sure first handle is active)
       
    75     this.handles.each( function(h,i) {
       
    76       i = slider.handles.length-1-i;
       
    77       slider.setValue(parseFloat(
       
    78         (Object.isArray(slider.options.sliderValue) ? 
       
    79           slider.options.sliderValue[i] : slider.options.sliderValue) || 
       
    80          slider.range.start), i);
       
    81       h.makePositioned().observe("mousedown", slider.eventMouseDown);
       
    82     });
       
    83     
       
    84     this.track.observe("mousedown", this.eventMouseDown);
       
    85     document.observe("mouseup", this.eventMouseUp);
       
    86     document.observe("mousemove", this.eventMouseMove);
       
    87     
       
    88     this.initialized = true;
       
    89   },
       
    90   dispose: function() {
       
    91     var slider = this;    
       
    92     Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
       
    93     Event.stopObserving(document, "mouseup", this.eventMouseUp);
       
    94     Event.stopObserving(document, "mousemove", this.eventMouseMove);
       
    95     this.handles.each( function(h) {
       
    96       Event.stopObserving(h, "mousedown", slider.eventMouseDown);
       
    97     });
       
    98   },
       
    99   setDisabled: function(){
       
   100     this.disabled = true;
       
   101   },
       
   102   setEnabled: function(){
       
   103     this.disabled = false;
       
   104   },  
       
   105   getNearestValue: function(value){
       
   106     if (this.allowedValues){
       
   107       if (value >= this.allowedValues.max()) return(this.allowedValues.max());
       
   108       if (value <= this.allowedValues.min()) return(this.allowedValues.min());
       
   109       
       
   110       var offset = Math.abs(this.allowedValues[0] - value);
       
   111       var newValue = this.allowedValues[0];
       
   112       this.allowedValues.each( function(v) {
       
   113         var currentOffset = Math.abs(v - value);
       
   114         if (currentOffset <= offset){
       
   115           newValue = v;
       
   116           offset = currentOffset;
       
   117         } 
       
   118       });
       
   119       return newValue;
       
   120     }
       
   121     if (value > this.range.end) return this.range.end;
       
   122     if (value < this.range.start) return this.range.start;
       
   123     return value;
       
   124   },
       
   125   setValue: function(sliderValue, handleIdx){
       
   126     if (!this.active) {
       
   127       this.activeHandleIdx = handleIdx || 0;
       
   128       this.activeHandle    = this.handles[this.activeHandleIdx];
       
   129       this.updateStyles();
       
   130     }
       
   131     handleIdx = handleIdx || this.activeHandleIdx || 0;
       
   132     if (this.initialized && this.restricted) {
       
   133       if ((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
       
   134         sliderValue = this.values[handleIdx-1];
       
   135       if ((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
       
   136         sliderValue = this.values[handleIdx+1];
       
   137     }
       
   138     sliderValue = this.getNearestValue(sliderValue);
       
   139     this.values[handleIdx] = sliderValue;
       
   140     this.value = this.values[0]; // assure backwards compat
       
   141     
       
   142     this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = 
       
   143       this.translateToPx(sliderValue);
       
   144     
       
   145     this.drawSpans();
       
   146     if (!this.dragging || !this.event) this.updateFinished();
       
   147   },
       
   148   setValueBy: function(delta, handleIdx) {
       
   149     this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, 
       
   150       handleIdx || this.activeHandleIdx || 0);
       
   151   },
       
   152   translateToPx: function(value) {
       
   153     return Math.round(
       
   154       ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * 
       
   155       (value - this.range.start)) + "px";
       
   156   },
       
   157   translateToValue: function(offset) {
       
   158     return ((offset/(this.trackLength-this.handleLength) * 
       
   159       (this.range.end-this.range.start)) + this.range.start);
       
   160   },
       
   161   getRange: function(range) {
       
   162     var v = this.values.sortBy(Prototype.K); 
       
   163     range = range || 0;
       
   164     return $R(v[range],v[range+1]);
       
   165   },
       
   166   minimumOffset: function(){
       
   167     return(this.isVertical() ? this.alignY : this.alignX);
       
   168   },
       
   169   maximumOffset: function(){
       
   170     return(this.isVertical() ? 
       
   171       (this.track.offsetHeight != 0 ? this.track.offsetHeight :
       
   172         this.track.style.height.replace(/px$/,"")) - this.alignY : 
       
   173       (this.track.offsetWidth != 0 ? this.track.offsetWidth : 
       
   174         this.track.style.width.replace(/px$/,"")) - this.alignX);
       
   175   },  
       
   176   isVertical:  function(){
       
   177     return (this.axis == 'vertical');
       
   178   },
       
   179   drawSpans: function() {
       
   180     var slider = this;
       
   181     if (this.spans)
       
   182       $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
       
   183     if (this.options.startSpan)
       
   184       this.setSpan(this.options.startSpan,
       
   185         $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
       
   186     if (this.options.endSpan)
       
   187       this.setSpan(this.options.endSpan, 
       
   188         $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
       
   189   },
       
   190   setSpan: function(span, range) {
       
   191     if (this.isVertical()) {
       
   192       span.style.top = this.translateToPx(range.start);
       
   193       span.style.height = this.translateToPx(range.end - range.start + this.range.start);
       
   194     } else {
       
   195       span.style.left = this.translateToPx(range.start);
       
   196       span.style.width = this.translateToPx(range.end - range.start + this.range.start);
       
   197     }
       
   198   },
       
   199   updateStyles: function() {
       
   200     this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
       
   201     Element.addClassName(this.activeHandle, 'selected');
       
   202   },
       
   203   startDrag: function(event) {
       
   204     if (Event.isLeftClick(event)) {
       
   205       if (!this.disabled){
       
   206         this.active = true;
       
   207         
       
   208         var handle = Event.element(event);
       
   209         var pointer  = [Event.pointerX(event), Event.pointerY(event)];
       
   210         var track = handle;
       
   211         if (track==this.track) {
       
   212           var offsets  = Position.cumulativeOffset(this.track); 
       
   213           this.event = event;
       
   214           this.setValue(this.translateToValue( 
       
   215            (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
       
   216           ));
       
   217           var offsets  = Position.cumulativeOffset(this.activeHandle);
       
   218           this.offsetX = (pointer[0] - offsets[0]);
       
   219           this.offsetY = (pointer[1] - offsets[1]);
       
   220         } else {
       
   221           // find the handle (prevents issues with Safari)
       
   222           while((this.handles.indexOf(handle) == -1) && handle.parentNode) 
       
   223             handle = handle.parentNode;
       
   224             
       
   225           if (this.handles.indexOf(handle)!=-1) {
       
   226             this.activeHandle    = handle;
       
   227             this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
       
   228             this.updateStyles();
       
   229             
       
   230             var offsets  = Position.cumulativeOffset(this.activeHandle);
       
   231             this.offsetX = (pointer[0] - offsets[0]);
       
   232             this.offsetY = (pointer[1] - offsets[1]);
       
   233           }
       
   234         }
       
   235       }
       
   236       Event.stop(event);
       
   237     }
       
   238   },
       
   239   update: function(event) {
       
   240    if (this.active) {
       
   241       if (!this.dragging) this.dragging = true;
       
   242       this.draw(event);
       
   243       if (Prototype.Browser.WebKit) window.scrollBy(0,0);
       
   244       Event.stop(event);
       
   245    }
       
   246   },
       
   247   draw: function(event) {
       
   248     var pointer = [Event.pointerX(event), Event.pointerY(event)];
       
   249     var offsets = Position.cumulativeOffset(this.track);
       
   250     pointer[0] -= this.offsetX + offsets[0];
       
   251     pointer[1] -= this.offsetY + offsets[1];
       
   252     this.event = event;
       
   253     this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
       
   254     if (this.initialized && this.options.onSlide)
       
   255       this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
       
   256   },
       
   257   endDrag: function(event) {
       
   258     if (this.active && this.dragging) {
       
   259       this.finishDrag(event, true);
       
   260       Event.stop(event);
       
   261     }
       
   262     this.active = false;
       
   263     this.dragging = false;
       
   264   },  
       
   265   finishDrag: function(event, success) {
       
   266     this.active = false;
       
   267     this.dragging = false;
       
   268     this.updateFinished();
       
   269   },
       
   270   updateFinished: function() {
       
   271     if (this.initialized && this.options.onChange) 
       
   272       this.options.onChange(this.values.length>1 ? this.values : this.value, this);
       
   273     this.event = null;
       
   274   }
       
   275 });