|
1 /* ========================================================= |
|
2 * bootstrap-slider.js v2.0.0 |
|
3 * http://www.eyecon.ro/bootstrap-slider |
|
4 * ========================================================= |
|
5 * Copyright 2012 Stefan Petre |
|
6 * |
|
7 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
8 * you may not use this file except in compliance with the License. |
|
9 * You may obtain a copy of the License at |
|
10 * |
|
11 * http://www.apache.org/licenses/LICENSE-2.0 |
|
12 * |
|
13 * Unless required by applicable law or agreed to in writing, software |
|
14 * distributed under the License is distributed on an "AS IS" BASIS, |
|
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
16 * See the License for the specific language governing permissions and |
|
17 * limitations under the License. |
|
18 * ========================================================= */ |
|
19 |
|
20 (function($) { |
|
21 |
|
22 var Slider = function(element, options) { |
|
23 this.element = $(element); |
|
24 this.picker = $('<div class="slider">'+ |
|
25 '<div class="slider-track">'+ |
|
26 '<div class="slider-selection"></div>'+ |
|
27 '<div class="slider-handle"></div>'+ |
|
28 '<div class="slider-handle"></div>'+ |
|
29 '</div>'+ |
|
30 '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'+ |
|
31 '</div>') |
|
32 .insertBefore(this.element) |
|
33 .prepend(this.element); |
|
34 this.id = this.element.data('slider-id')||options.id; |
|
35 if (this.id) { |
|
36 this.picker[0].id = this.id; |
|
37 } |
|
38 |
|
39 if (typeof Modernizr !== 'undefined' && Modernizr.touch) { |
|
40 this.touchCapable = true; |
|
41 } |
|
42 |
|
43 var tooltip = this.element.data('slider-tooltip')||options.tooltip; |
|
44 |
|
45 this.tooltip = this.picker.find('.tooltip'); |
|
46 this.tooltipInner = this.tooltip.find('div.tooltip-inner'); |
|
47 |
|
48 this.orientation = this.element.data('slider-orientation')||options.orientation; |
|
49 switch(this.orientation) { |
|
50 case 'vertical': |
|
51 this.picker.addClass('slider-vertical'); |
|
52 this.stylePos = 'top'; |
|
53 this.mousePos = 'pageY'; |
|
54 this.sizePos = 'offsetHeight'; |
|
55 this.tooltip.addClass('right')[0].style.left = '100%'; |
|
56 break; |
|
57 default: |
|
58 this.picker |
|
59 .addClass('slider-horizontal') |
|
60 .css('width', this.element.outerWidth()); |
|
61 this.orientation = 'horizontal'; |
|
62 this.stylePos = 'left'; |
|
63 this.mousePos = 'pageX'; |
|
64 this.sizePos = 'offsetWidth'; |
|
65 this.tooltip.addClass('top')[0].style.top = -this.tooltip.outerHeight() - 14 + 'px'; |
|
66 break; |
|
67 } |
|
68 |
|
69 this.min = this.element.data('slider-min')||options.min; |
|
70 this.max = this.element.data('slider-max')||options.max; |
|
71 this.step = this.element.data('slider-step')||options.step; |
|
72 this.value = this.element.data('slider-value')||options.value; |
|
73 if (this.value[1]) { |
|
74 this.range = true; |
|
75 } |
|
76 |
|
77 this.selection = this.element.data('slider-selection')||options.selection; |
|
78 this.selectionEl = this.picker.find('.slider-selection'); |
|
79 if (this.selection === 'none') { |
|
80 this.selectionEl.addClass('hide'); |
|
81 } |
|
82 this.selectionElStyle = this.selectionEl[0].style; |
|
83 |
|
84 |
|
85 this.handle1 = this.picker.find('.slider-handle:first'); |
|
86 this.handle1Stype = this.handle1[0].style; |
|
87 this.handle2 = this.picker.find('.slider-handle:last'); |
|
88 this.handle2Stype = this.handle2[0].style; |
|
89 |
|
90 var handle = this.element.data('slider-handle')||options.handle; |
|
91 switch(handle) { |
|
92 case 'round': |
|
93 this.handle1.addClass('round'); |
|
94 this.handle2.addClass('round'); |
|
95 break |
|
96 case 'triangle': |
|
97 this.handle1.addClass('triangle'); |
|
98 this.handle2.addClass('triangle'); |
|
99 break |
|
100 } |
|
101 |
|
102 if (this.range) { |
|
103 this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0])); |
|
104 this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1])); |
|
105 } else { |
|
106 this.value = [ Math.max(this.min, Math.min(this.max, this.value))]; |
|
107 this.handle2.addClass('hide'); |
|
108 if (this.selection === 'after') { |
|
109 this.value[1] = this.max; |
|
110 } else { |
|
111 this.value[1] = this.min; |
|
112 } |
|
113 } |
|
114 this.diff = this.max - this.min; |
|
115 this.percentage = [ |
|
116 (this.value[0]-this.min)*100/this.diff, |
|
117 (this.value[1]-this.min)*100/this.diff, |
|
118 this.step*100/this.diff |
|
119 ]; |
|
120 |
|
121 this.offset = this.picker.offset(); |
|
122 this.size = this.picker[0][this.sizePos]; |
|
123 |
|
124 this.formater = options.formater; |
|
125 |
|
126 this.layout(); |
|
127 |
|
128 if (this.touchCapable) { |
|
129 // Touch: Bind touch events: |
|
130 this.picker.on({ |
|
131 touchstart: $.proxy(this.mousedown, this) |
|
132 }); |
|
133 } else { |
|
134 this.picker.on({ |
|
135 mousedown: $.proxy(this.mousedown, this) |
|
136 }); |
|
137 } |
|
138 |
|
139 if (tooltip === 'show') { |
|
140 this.picker.on({ |
|
141 mouseenter: $.proxy(this.showTooltip, this), |
|
142 mouseleave: $.proxy(this.hideTooltip, this) |
|
143 }); |
|
144 } else { |
|
145 this.tooltip.addClass('hide'); |
|
146 } |
|
147 }; |
|
148 |
|
149 Slider.prototype = { |
|
150 constructor: Slider, |
|
151 |
|
152 over: false, |
|
153 inDrag: false, |
|
154 |
|
155 showTooltip: function(){ |
|
156 this.tooltip.addClass('in'); |
|
157 //var left = Math.round(this.percent*this.width); |
|
158 //this.tooltip.css('left', left - this.tooltip.outerWidth()/2); |
|
159 this.over = true; |
|
160 }, |
|
161 |
|
162 hideTooltip: function(){ |
|
163 if (this.inDrag === false) { |
|
164 this.tooltip.removeClass('in'); |
|
165 } |
|
166 this.over = false; |
|
167 }, |
|
168 |
|
169 layout: function(){ |
|
170 this.handle1Stype[this.stylePos] = this.percentage[0]+'%'; |
|
171 this.handle2Stype[this.stylePos] = this.percentage[1]+'%'; |
|
172 if (this.orientation === 'vertical') { |
|
173 this.selectionElStyle.top = Math.min(this.percentage[0], this.percentage[1]) +'%'; |
|
174 this.selectionElStyle.height = Math.abs(this.percentage[0] - this.percentage[1]) +'%'; |
|
175 } else { |
|
176 this.selectionElStyle.left = Math.min(this.percentage[0], this.percentage[1]) +'%'; |
|
177 this.selectionElStyle.width = Math.abs(this.percentage[0] - this.percentage[1]) +'%'; |
|
178 } |
|
179 if (this.range) { |
|
180 this.tooltipInner.text( |
|
181 this.formater(this.value[0]) + |
|
182 ' : ' + |
|
183 this.formater(this.value[1]) |
|
184 ); |
|
185 this.tooltip[0].style[this.stylePos] = this.size * (this.percentage[0] + (this.percentage[1] - this.percentage[0])/2)/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px'; |
|
186 } else { |
|
187 this.tooltipInner.text( |
|
188 this.formater(this.value[0]) |
|
189 ); |
|
190 this.tooltip[0].style[this.stylePos] = this.size * this.percentage[0]/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px'; |
|
191 } |
|
192 }, |
|
193 |
|
194 mousedown: function(ev) { |
|
195 |
|
196 // Touch: Get the original event: |
|
197 if (this.touchCapable && ev.type === 'touchstart') { |
|
198 ev = ev.originalEvent; |
|
199 } |
|
200 |
|
201 this.offset = this.picker.offset(); |
|
202 this.size = this.picker[0][this.sizePos]; |
|
203 |
|
204 var percentage = this.getPercentage(ev); |
|
205 |
|
206 if (this.range) { |
|
207 var diff1 = Math.abs(this.percentage[0] - percentage); |
|
208 var diff2 = Math.abs(this.percentage[1] - percentage); |
|
209 this.dragged = (diff1 < diff2) ? 0 : 1; |
|
210 } else { |
|
211 this.dragged = 0; |
|
212 } |
|
213 |
|
214 this.percentage[this.dragged] = percentage; |
|
215 this.layout(); |
|
216 |
|
217 if (this.touchCapable) { |
|
218 // Touch: Bind touch events: |
|
219 $(document).on({ |
|
220 touchmove: $.proxy(this.mousemove, this), |
|
221 touchend: $.proxy(this.mouseup, this) |
|
222 }); |
|
223 } else { |
|
224 $(document).on({ |
|
225 mousemove: $.proxy(this.mousemove, this), |
|
226 mouseup: $.proxy(this.mouseup, this) |
|
227 }); |
|
228 } |
|
229 |
|
230 this.inDrag = true; |
|
231 var val = this.calculateValue(); |
|
232 this.element.trigger({ |
|
233 type: 'slideStart', |
|
234 value: val |
|
235 }).trigger({ |
|
236 type: 'slide', |
|
237 value: val |
|
238 }); |
|
239 return false; |
|
240 }, |
|
241 |
|
242 mousemove: function(ev) { |
|
243 |
|
244 // Touch: Get the original event: |
|
245 if (this.touchCapable && ev.type === 'touchmove') { |
|
246 ev = ev.originalEvent; |
|
247 } |
|
248 |
|
249 var percentage = this.getPercentage(ev); |
|
250 if (this.range) { |
|
251 if (this.dragged === 0 && this.percentage[1] < percentage) { |
|
252 this.percentage[0] = this.percentage[1]; |
|
253 this.dragged = 1; |
|
254 } else if (this.dragged === 1 && this.percentage[0] > percentage) { |
|
255 this.percentage[1] = this.percentage[0]; |
|
256 this.dragged = 0; |
|
257 } |
|
258 } |
|
259 this.percentage[this.dragged] = percentage; |
|
260 this.layout(); |
|
261 var val = this.calculateValue(); |
|
262 this.element |
|
263 .trigger({ |
|
264 type: 'slide', |
|
265 value: val |
|
266 }) |
|
267 .data('value', val) |
|
268 .prop('value', val); |
|
269 return false; |
|
270 }, |
|
271 |
|
272 mouseup: function(ev) { |
|
273 if (this.touchCapable) { |
|
274 // Touch: Bind touch events: |
|
275 $(document).off({ |
|
276 touchmove: this.mousemove, |
|
277 touchend: this.mouseup |
|
278 }); |
|
279 } else { |
|
280 $(document).off({ |
|
281 mousemove: this.mousemove, |
|
282 mouseup: this.mouseup |
|
283 }); |
|
284 } |
|
285 |
|
286 this.inDrag = false; |
|
287 if (this.over == false) { |
|
288 this.hideTooltip(); |
|
289 } |
|
290 this.element; |
|
291 var val = this.calculateValue(); |
|
292 this.element |
|
293 .trigger({ |
|
294 type: 'slideStop', |
|
295 value: val |
|
296 }) |
|
297 .data('value', val) |
|
298 .prop('value', val); |
|
299 return false; |
|
300 }, |
|
301 |
|
302 calculateValue: function() { |
|
303 var val; |
|
304 if (this.range) { |
|
305 val = [ |
|
306 (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step), |
|
307 (this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step) |
|
308 ]; |
|
309 this.value = val; |
|
310 } else { |
|
311 val = (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step); |
|
312 this.value = [val, this.value[1]]; |
|
313 } |
|
314 return val; |
|
315 }, |
|
316 |
|
317 getPercentage: function(ev) { |
|
318 if (this.touchCapable) { |
|
319 ev = ev.touches[0]; |
|
320 } |
|
321 var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size; |
|
322 percentage = Math.round(percentage/this.percentage[2])*this.percentage[2]; |
|
323 return Math.max(0, Math.min(100, percentage)); |
|
324 }, |
|
325 |
|
326 getValue: function() { |
|
327 if (this.range) { |
|
328 return this.value; |
|
329 } |
|
330 return this.value[0]; |
|
331 }, |
|
332 |
|
333 setValue: function(val) { |
|
334 this.value = val; |
|
335 |
|
336 if (this.range) { |
|
337 this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0])); |
|
338 this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1])); |
|
339 } else { |
|
340 this.value = [ Math.max(this.min, Math.min(this.max, this.value))]; |
|
341 this.handle2.addClass('hide'); |
|
342 if (this.selection === 'after') { |
|
343 this.value[1] = this.max; |
|
344 } else { |
|
345 this.value[1] = this.min; |
|
346 } |
|
347 } |
|
348 this.diff = this.max - this.min; |
|
349 this.percentage = [ |
|
350 (this.value[0]-this.min)*100/this.diff, |
|
351 (this.value[1]-this.min)*100/this.diff, |
|
352 this.step*100/this.diff |
|
353 ]; |
|
354 this.layout(); |
|
355 } |
|
356 }; |
|
357 |
|
358 $.fn.slider = function ( option, val ) { |
|
359 return this.each(function () { |
|
360 var $this = $(this), |
|
361 data = $this.data('slider'), |
|
362 options = typeof option === 'object' && option; |
|
363 if (!data) { |
|
364 $this.data('slider', (data = new Slider(this, $.extend({}, $.fn.slider.defaults,options)))); |
|
365 } |
|
366 if (typeof option === 'string') { |
|
367 data[option](val); |
|
368 } |
|
369 }); |
|
370 }; |
|
371 |
|
372 $.fn.slider.defaults = { |
|
373 min: 0, |
|
374 max: 10, |
|
375 step: 1, |
|
376 orientation: 'horizontal', |
|
377 value: 5, |
|
378 selection: 'before', |
|
379 tooltip: 'show', |
|
380 handle: 'round', |
|
381 formater: function(value) { |
|
382 return value; |
|
383 } |
|
384 }; |
|
385 |
|
386 $.fn.slider.Constructor = Slider; |
|
387 |
|
388 // Used by MyAMS to avoid conflict with JQuery-UI slider |
|
389 $.fn.BS_slider = $.fn.slider; |
|
390 |
|
391 })(window.jQuery); |