source: trunk/template-common/lib/ui/ui.slider.js @ 3282

Last change on this file since 3282 was 3282, checked in by plg, 15 years ago

change: according to topic:15067, svn:keywords property was removed

  • Property svn:eol-style set to LF
File size: 14.8 KB
Line 
1/*
2 * jQuery UI Slider
3 *
4 * Copyright (c) 2008 Paul Bakaus
5 * Dual licensed under the MIT (MIT-LICENSE.txt)
6 * and GPL (GPL-LICENSE.txt) licenses.
7 *
8 * http://docs.jquery.com/UI/Slider
9 *
10 * Depends:
11 *      ui.core.js
12 */
13(function($) {
14
15$.fn.unwrap = $.fn.unwrap || function(expr) {
16  return this.each(function(){
17     $(this).parents(expr).eq(0).after(this).remove();
18  });
19};
20
21$.widget("ui.slider", {
22        plugins: {},
23        ui: function(e) {
24                return {
25                        options: this.options,
26                        handle: this.currentHandle,
27                        value: this.options.axis != "both" || !this.options.axis ? Math.round(this.value(null,this.options.axis == "vertical" ? "y" : "x")) : {
28                                x: Math.round(this.value(null,"x")),
29                                y: Math.round(this.value(null,"y"))
30                        },
31                        range: this.getRange()
32                };
33        },
34        propagate: function(n,e) {
35                $.ui.plugin.call(this, n, [e, this.ui()]);
36                this.element.triggerHandler(n == "slide" ? n : "slide"+n, [e, this.ui()], this.options[n]);
37        },
38        destroy: function() {
39               
40                this.element
41                        .removeClass("ui-slider ui-slider-disabled")
42                        .removeData("slider")
43                        .unbind(".slider");
44               
45                if(this.handle && this.handle.length) {
46                        this.handle
47                                .unwrap("a");
48                        this.handle.each(function() {
49                                $(this).data("mouse").mouseDestroy();
50                        });
51                }
52               
53                this.generated && this.generated.remove();
54               
55        },
56        setData: function(key, value) {
57                $.widget.prototype.setData.apply(this, arguments);
58                if (/min|max|steps/.test(key)) {
59                        this.initBoundaries();
60                }
61               
62                if(key == "range") {
63                        value ? this.handle.length == 2 && this.createRange() : this.removeRange();
64                }
65               
66        },
67
68        init: function() {
69               
70                var self = this;
71                this.element.addClass("ui-slider");
72                this.initBoundaries();
73               
74                // Initialize mouse and key events for interaction
75                this.handle = $(this.options.handle, this.element);
76                if (!this.handle.length) {
77                        self.handle = self.generated = $(self.options.handles || [0]).map(function() {
78                                var handle = $("<div/>").addClass("ui-slider-handle").appendTo(self.element);
79                                if (this.id)
80                                        handle.attr("id", this.id);
81                                return handle[0];
82                        });
83                }
84               
85               
86                var handleclass = function(el) {
87                        this.element = $(el);
88                        this.element.data("mouse", this);
89                        this.options = self.options;
90                       
91                        this.element.bind("mousedown", function() {
92                                if(self.currentHandle) this.blur(self.currentHandle);
93                                self.focus(this,1);
94                        });
95                       
96                        this.mouseInit();
97                };
98               
99                $.extend(handleclass.prototype, $.ui.mouse, {
100                        mouseStart: function(e) { return self.start.call(self, e, this.element[0]); },
101                        mouseStop: function(e) { return self.stop.call(self, e, this.element[0]); },
102                        mouseDrag: function(e) { return self.drag.call(self, e, this.element[0]); },
103                        mouseCapture: function() { return true; },
104                        trigger: function(e) { this.mouseDown(e); }
105                });
106               
107               
108                $(this.handle)
109                        .each(function() {
110                                new handleclass(this);
111                        })
112                        .wrap('<a href="javascript:void(0)" style="outline:none;border:none;"></a>')
113                        .parent()
114                                .bind('focus', function(e) { self.focus(this.firstChild); })
115                                .bind('blur', function(e) { self.blur(this.firstChild); })
116                                .bind('keydown', function(e) { if(!self.options.noKeyboard) self.keydown(e.keyCode, this.firstChild); })
117                ;
118               
119                // Bind the click to the slider itself
120                this.element.bind('mousedown.slider', function(e) {
121                        self.click.apply(self, [e]);
122                        self.currentHandle.data("mouse").trigger(e);
123                        self.firstValue = self.firstValue + 1; //This is for always triggering the change event
124                });
125               
126                // Move the first handle to the startValue
127                $.each(this.options.handles || [], function(index, handle) {
128                        self.moveTo(handle.start, index, true);
129                });
130                if (!isNaN(this.options.startValue))
131                        this.moveTo(this.options.startValue, 0, true);
132
133                this.previousHandle = $(this.handle[0]); //set the previous handle to the first to allow clicking before selecting the handle
134                if(this.handle.length == 2 && this.options.range) this.createRange();
135        },
136        initBoundaries: function() {
137               
138                var element = this.element[0], o = this.options;
139                this.actualSize = { width: this.element.outerWidth() , height: this.element.outerHeight() };                   
140               
141                $.extend(o, {
142                        axis: o.axis || (element.offsetWidth < element.offsetHeight ? 'vertical' : 'horizontal'),
143                        max: !isNaN(parseInt(o.max,10)) ? { x: parseInt(o.max, 10), y: parseInt(o.max, 10) } : ({ x: o.max && o.max.x || 100, y: o.max && o.max.y || 100 }),
144                        min: !isNaN(parseInt(o.min,10)) ? { x: parseInt(o.min, 10), y: parseInt(o.min, 10) } : ({ x: o.min && o.min.x || 0, y: o.min && o.min.y || 0 })
145                });
146                //Prepare the real maxValue
147                o.realMax = {
148                        x: o.max.x - o.min.x,
149                        y: o.max.y - o.min.y
150                };
151                //Calculate stepping based on steps
152                o.stepping = {
153                        x: o.stepping && o.stepping.x || parseInt(o.stepping, 10) || (o.steps ? o.realMax.x/(o.steps.x || parseInt(o.steps, 10) || o.realMax.x) : 0),
154                        y: o.stepping && o.stepping.y || parseInt(o.stepping, 10) || (o.steps ? o.realMax.y/(o.steps.y || parseInt(o.steps, 10) || o.realMax.y) : 0)
155                };
156        },
157
158       
159        keydown: function(keyCode, handle) {
160                if(/(37|38|39|40)/.test(keyCode)) {
161                        this.moveTo({
162                                x: /(37|39)/.test(keyCode) ? (keyCode == 37 ? '-' : '+') + '=' + this.oneStep("x") : 0,
163                                y: /(38|40)/.test(keyCode) ? (keyCode == 38 ? '-' : '+') + '=' + this.oneStep("y") : 0
164                        }, handle);
165                }
166        },
167        focus: function(handle,hard) {
168                this.currentHandle = $(handle).addClass('ui-slider-handle-active');
169                if (hard)
170                        this.currentHandle.parent()[0].focus();
171        },
172        blur: function(handle) {
173                $(handle).removeClass('ui-slider-handle-active');
174                if(this.currentHandle && this.currentHandle[0] == handle) { this.previousHandle = this.currentHandle; this.currentHandle = null; };
175        },
176        click: function(e) {
177                // This method is only used if:
178                // - The user didn't click a handle
179                // - The Slider is not disabled
180                // - There is a current, or previous selected handle (otherwise we wouldn't know which one to move)
181               
182                var pointer = [e.pageX,e.pageY];
183               
184                var clickedHandle = false;
185                this.handle.each(function() {
186                        if(this == e.target)
187                                clickedHandle = true;
188                });
189                if (clickedHandle || this.options.disabled || !(this.currentHandle || this.previousHandle))
190                        return;
191
192                // If a previous handle was focussed, focus it again
193                if (!this.currentHandle && this.previousHandle)
194                        this.focus(this.previousHandle, true);
195               
196                // propagate only for distance > 0, otherwise propagation is done my drag
197                this.offset = this.element.offset();
198
199                this.moveTo({
200                        y: this.convertValue(e.pageY - this.offset.top - this.currentHandle[0].offsetHeight/2, "y"),
201                        x: this.convertValue(e.pageX - this.offset.left - this.currentHandle[0].offsetWidth/2, "x")
202                }, null, !this.options.distance);
203        },
204       
205
206
207        createRange: function() {
208                if(this.rangeElement) return;
209                this.rangeElement = $('<div></div>')
210                        .addClass('ui-slider-range')
211                        .css({ position: 'absolute' })
212                        .appendTo(this.element);
213                this.updateRange();
214        },
215        removeRange: function() {
216                this.rangeElement.remove();
217                this.rangeElement = null;
218        },
219        updateRange: function() {
220                        var prop = this.options.axis == "vertical" ? "top" : "left";
221                        var size = this.options.axis == "vertical" ? "height" : "width";
222                        this.rangeElement.css(prop, (parseInt($(this.handle[0]).css(prop),10) || 0) + this.handleSize(0, this.options.axis == "vertical" ? "y" : "x")/2);
223                        this.rangeElement.css(size, (parseInt($(this.handle[1]).css(prop),10) || 0) - (parseInt($(this.handle[0]).css(prop),10) || 0));
224        },
225        getRange: function() {
226                return this.rangeElement ? this.convertValue(parseInt(this.rangeElement.css(this.options.axis == "vertical" ? "height" : "width"),10), this.options.axis == "vertical" ? "y" : "x") : null;
227        },
228
229        handleIndex: function() {
230                return this.handle.index(this.currentHandle[0]);
231        },
232        value: function(handle, axis) {
233                if(this.handle.length == 1) this.currentHandle = this.handle;
234                if(!axis) axis = this.options.axis == "vertical" ? "y" : "x";
235
236                var curHandle = $(handle != undefined && handle !== null ? this.handle[handle] || handle : this.currentHandle);
237               
238                if(curHandle.data("mouse").sliderValue) {
239                        return parseInt(curHandle.data("mouse").sliderValue[axis],10);
240                } else {
241                        return parseInt(((parseInt(curHandle.css(axis == "x" ? "left" : "top"),10) / (this.actualSize[axis == "x" ? "width" : "height"] - this.handleSize(handle,axis))) * this.options.realMax[axis]) + this.options.min[axis],10);
242                }
243
244        },
245        convertValue: function(value,axis) {
246                return this.options.min[axis] + (value / (this.actualSize[axis == "x" ? "width" : "height"] - this.handleSize(null,axis))) * this.options.realMax[axis];
247        },
248       
249        translateValue: function(value,axis) {
250                return ((value - this.options.min[axis]) / this.options.realMax[axis]) * (this.actualSize[axis == "x" ? "width" : "height"] - this.handleSize(null,axis));
251        },
252        translateRange: function(value,axis) {
253                if (this.rangeElement) {
254                        if (this.currentHandle[0] == this.handle[0] && value >= this.translateValue(this.value(1),axis))
255                                value = this.translateValue(this.value(1,axis) - this.oneStep(axis), axis);
256                        if (this.currentHandle[0] == this.handle[1] && value <= this.translateValue(this.value(0),axis))
257                                value = this.translateValue(this.value(0,axis) + this.oneStep(axis), axis);
258                }
259                if (this.options.handles) {
260                        var handle = this.options.handles[this.handleIndex()];
261                        if (value < this.translateValue(handle.min,axis)) {
262                                value = this.translateValue(handle.min,axis);
263                        } else if (value > this.translateValue(handle.max,axis)) {
264                                value = this.translateValue(handle.max,axis);
265                        }
266                }
267                return value;
268        },
269        translateLimits: function(value,axis) {
270                if (value >= this.actualSize[axis == "x" ? "width" : "height"] - this.handleSize(null,axis))
271                        value = this.actualSize[axis == "x" ? "width" : "height"] - this.handleSize(null,axis);
272                if (value <= 0)
273                        value = 0;
274                return value;
275        },
276        handleSize: function(handle,axis) {
277                return $(handle != undefined && handle !== null ? this.handle[handle] : this.currentHandle)[0]["offset"+(axis == "x" ? "Width" : "Height")];   
278        },
279        oneStep: function(axis) {
280                return this.options.stepping[axis] || 1;
281        },
282
283
284        start: function(e, handle) {
285       
286                var o = this.options;
287                if(o.disabled) return false;
288
289                // Prepare the outer size
290                this.actualSize = { width: this.element.outerWidth() , height: this.element.outerHeight() };
291       
292                // This is a especially ugly fix for strange blur events happening on mousemove events
293                if (!this.currentHandle)
294                        this.focus(this.previousHandle, true); 
295
296                this.offset = this.element.offset();
297               
298                this.handleOffset = this.currentHandle.offset();
299                this.clickOffset = { top: e.pageY - this.handleOffset.top, left: e.pageX - this.handleOffset.left };
300               
301                this.firstValue = this.value();
302               
303                this.propagate('start', e);
304                this.drag(e, handle);
305                return true;
306                                       
307        },
308        stop: function(e) {
309                this.propagate('stop', e);
310                if (this.firstValue != this.value())
311                        this.propagate('change', e);
312                // This is a especially ugly fix for strange blur events happening on mousemove events
313                this.focus(this.currentHandle, true);
314                return false;
315        },
316        drag: function(e, handle) {
317
318                var o = this.options;
319                var position = { top: e.pageY - this.offset.top - this.clickOffset.top, left: e.pageX - this.offset.left - this.clickOffset.left};
320                if(!this.currentHandle) this.focus(this.previousHandle, true); //This is a especially ugly fix for strange blur events happening on mousemove events
321
322                position.left = this.translateLimits(position.left, "x");
323                position.top = this.translateLimits(position.top, "y");
324               
325                if (o.stepping.x) {
326                        var value = this.convertValue(position.left, "x");
327                        value = Math.round(value / o.stepping.x) * o.stepping.x;
328                        position.left = this.translateValue(value, "x");       
329                }
330                if (o.stepping.y) {
331                        var value = this.convertValue(position.top, "y");
332                        value = Math.round(value / o.stepping.y) * o.stepping.y;
333                        position.top = this.translateValue(value, "y"); 
334                }
335               
336                position.left = this.translateRange(position.left, "x");
337                position.top = this.translateRange(position.top, "y");
338
339                if(o.axis != "vertical") this.currentHandle.css({ left: position.left });
340                if(o.axis != "horizontal") this.currentHandle.css({ top: position.top });
341               
342                //Store the slider's value
343                this.currentHandle.data("mouse").sliderValue = {
344                        x: Math.round(this.convertValue(position.left, "x")) || 0,
345                        y: Math.round(this.convertValue(position.top, "y")) || 0
346                };
347               
348                if (this.rangeElement)
349                        this.updateRange();
350                this.propagate('slide', e);
351                return false;
352        },
353       
354        moveTo: function(value, handle, noPropagation) {
355
356                var o = this.options;
357
358                // Prepare the outer size
359                this.actualSize = { width: this.element.outerWidth() , height: this.element.outerHeight() };
360
361                //If no handle has been passed, no current handle is available and we have multiple handles, return false
362                if (handle == undefined && !this.currentHandle && this.handle.length != 1)
363                        return false; 
364               
365                //If only one handle is available, use it
366                if (handle == undefined && !this.currentHandle)
367                        handle = 0;
368               
369                if (handle != undefined)
370                        this.currentHandle = this.previousHandle = $(this.handle[handle] || handle);
371
372
373                if(value.x !== undefined && value.y !== undefined) {
374                        var x = value.x, y = value.y;
375                } else {
376                        var x = value, y = value;
377                }
378
379                if(x !== undefined && x.constructor != Number) {
380                        var me = /^\-\=/.test(x), pe = /^\+\=/.test(x);
381                        if(me || pe) {
382                                x = this.value(null, "x") + parseInt(x.replace(me ? '=' : '+=', ''), 10);
383                        } else {
384                                x = isNaN(parseInt(x, 10)) ? undefined : parseInt(x, 10);
385                        }
386                }
387               
388                if(y !== undefined && y.constructor != Number) {
389                        var me = /^\-\=/.test(y), pe = /^\+\=/.test(y);
390                        if(me || pe) {
391                                y = this.value(null, "y") + parseInt(y.replace(me ? '=' : '+=', ''), 10);
392                        } else {
393                                y = isNaN(parseInt(y, 10)) ? undefined : parseInt(y, 10);
394                        }
395                }
396
397                if(o.axis != "vertical" && x !== undefined) {
398                        if(o.stepping.x) x = Math.round(x / o.stepping.x) * o.stepping.x;
399                        x = this.translateValue(x, "x");
400                        x = this.translateLimits(x, "x");
401                        x = this.translateRange(x, "x");
402
403                        o.animate ? this.currentHandle.stop().animate({ left: x }, (Math.abs(parseInt(this.currentHandle.css("left")) - x)) * (!isNaN(parseInt(o.animate)) ? o.animate : 5)) : this.currentHandle.css({ left: x });
404                }
405
406                if(o.axis != "horizontal" && y !== undefined) {
407                        if(o.stepping.y) y = Math.round(y / o.stepping.y) * o.stepping.y;
408                        y = this.translateValue(y, "y");
409                        y = this.translateLimits(y, "y");
410                        y = this.translateRange(y, "y");
411                        o.animate ? this.currentHandle.stop().animate({ top: y }, (Math.abs(parseInt(this.currentHandle.css("top")) - y)) * (!isNaN(parseInt(o.animate)) ? o.animate : 5)) : this.currentHandle.css({ top: y });
412                }
413               
414                if (this.rangeElement)
415                        this.updateRange();
416                       
417                //Store the slider's value
418                this.currentHandle.data("mouse").sliderValue = {
419                        x: Math.round(this.convertValue(x, "x")) || 0,
420                        y: Math.round(this.convertValue(y, "y")) || 0
421                };
422       
423                if (!noPropagation) {
424                        this.propagate('start', null);
425                        this.propagate('stop', null);
426                        this.propagate('change', null);
427                        this.propagate("slide", null);
428                }
429        }
430});
431
432$.ui.slider.getter = "value";
433
434$.ui.slider.defaults = {
435        handle: ".ui-slider-handle",
436        distance: 1,
437        animate: false
438};
439
440})(jQuery);
Note: See TracBrowser for help on using the repository browser.