1 /*! =========================================================
9 * - Twitter: @Rovolutionary
10 * - Github: rovolution
12 * =========================================================
14 * Licensed under the Apache License, Version 2.0 (the "License");
15 * you may not use this file except in compliance with the License.
16 * You may obtain a copy of the License at
18 * http://www.apache.org/licenses/LICENSE-2.0
20 * Unless required by applicable law or agreed to in writing, software
21 * distributed under the License is distributed on an "AS IS" BASIS,
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 * See the License for the specific language governing permissions and
24 * limitations under the License.
25 * ========================================================= */
29 * Bridget makes jQuery widgets
34 (function(root
, factory
) {
35 if(typeof define
=== "function" && define
.amd
) {
36 define(["jquery"], factory
);
38 else if(typeof module
=== "object" && module
.exports
) {
41 jQuery
= require("jquery");
46 module
.exports
= factory(jQuery
);
49 root
.Slider
= factory(root
.jQuery
);
52 // Reference to Slider constructor
60 // -------------------------- utils -------------------------- //
62 var slice
= Array
.prototype.slice
;
66 // -------------------------- definition -------------------------- //
68 function defineBridget( $ ) {
75 // -------------------------- addOptionMethod -------------------------- //
78 * adds option method -> $().plugin('option', {...})
79 * @param {Function} PluginClass - constructor class
81 function addOptionMethod( PluginClass
) {
82 // don't overwrite original option method
83 if ( PluginClass
.prototype.option
) {
88 PluginClass
.prototype.option = function( opts
) {
89 // bail out if not an object
90 if ( !$.isPlainObject( opts
) ){
93 this.options
= $.extend( true, this.options
, opts
);
98 // -------------------------- plugin bridge -------------------------- //
100 // helper function for logging errors
101 // $.error breaks jQuery chaining
102 var logError
= typeof console
=== 'undefined' ? noop
:
103 function( message
) {
104 console
.error( message
);
108 * jQuery plugin bridge, access methods like $elem.plugin('method')
109 * @param {String} namespace - plugin name
110 * @param {Function} PluginClass - constructor class
112 function bridge( namespace, PluginClass
) {
113 // add to jQuery fn namespace
114 $.fn
[ namespace ] = function( options
) {
115 if ( typeof options
=== 'string' ) {
116 // call plugin method when first argument is a string
117 // get arguments for method
118 var args
= slice
.call( arguments
, 1 );
120 for ( var i
=0, len
= this.length
; i
< len
; i
++ ) {
122 var instance
= $.data( elem
, namespace );
124 logError( "cannot call methods on " + namespace + " prior to initialization; " +
125 "attempted to call '" + options
+ "'" );
128 if ( !$.isFunction( instance
[options
] ) || options
.charAt(0) === '_' ) {
129 logError( "no such method '" + options
+ "' for " + namespace + " instance" );
133 // trigger method with arguments
134 var returnValue
= instance
[ options
].apply( instance
, args
);
136 // break look and return first value if provided
137 if ( returnValue
!== undefined && returnValue
!== instance
) {
141 // return this if no return value
144 var objects
= this.map( function() {
145 var instance
= $.data( this, namespace );
147 // apply options & init
148 instance
.option( options
);
151 // initialize new instance
152 instance
= new PluginClass( this, options
);
153 $.data( this, namespace, instance
);
158 if(!objects
|| objects
.length
> 1) {
168 // -------------------------- bridget -------------------------- //
171 * converts a Prototypical class into a proper jQuery plugin
172 * the class must have a ._init method
173 * @param {String} namespace - plugin name, used in $().pluginName
174 * @param {Function} PluginClass - constructor class
176 $.bridget = function( namespace, PluginClass
) {
177 addOptionMethod( PluginClass
);
178 bridge( namespace, PluginClass
);
185 // get jquery from browser global
191 /*************************************************
193 BOOTSTRAP-SLIDER SOURCE CODE
195 **************************************************/
200 formatInvalidInputErrorMsg : function(input
) {
201 return "Invalid input value '" + input
+ "' passed in";
203 callingContextNotSliderInstance
: "Calling context element does not have instance of Slider bound to it. Check your code to make sure the JQuery object returned from the call to the slider() initializer is calling the method"
208 toValue: function(percentage
) {
209 var rawValue
= percentage
/100 * (this.options
.max
- this.options
.min
);
210 if (this.options
.ticks_positions
.length
> 0) {
211 var minv
, maxv
, minp
, maxp
= 0;
212 for (var i
= 0; i
< this.options
.ticks_positions
.length
; i
++) {
213 if (percentage
<= this.options
.ticks_positions
[i
]) {
214 minv
= (i
> 0) ? this.options
.ticks
[i
-1] : 0;
215 minp
= (i
> 0) ? this.options
.ticks_positions
[i
-1] : 0;
216 maxv
= this.options
.ticks
[i
];
217 maxp
= this.options
.ticks_positions
[i
];
223 var partialPercentage
= (percentage
- minp
) / (maxp
- minp
);
224 rawValue
= minv
+ partialPercentage
* (maxv
- minv
);
228 var value
= this.options
.min
+ Math
.round(rawValue
/ this.options
.step
) * this.options
.step
;
229 if (value
< this.options
.min
) {
230 return this.options
.min
;
231 } else if (value
> this.options
.max
) {
232 return this.options
.max
;
237 toPercentage: function(value
) {
238 if (this.options
.max
=== this.options
.min
) {
242 if (this.options
.ticks_positions
.length
> 0) {
243 var minv
, maxv
, minp
, maxp
= 0;
244 for (var i
= 0; i
< this.options
.ticks
.length
; i
++) {
245 if (value
<= this.options
.ticks
[i
]) {
246 minv
= (i
> 0) ? this.options
.ticks
[i
-1] : 0;
247 minp
= (i
> 0) ? this.options
.ticks_positions
[i
-1] : 0;
248 maxv
= this.options
.ticks
[i
];
249 maxp
= this.options
.ticks_positions
[i
];
255 var partialPercentage
= (value
- minv
) / (maxv
- minv
);
256 return minp
+ partialPercentage
* (maxp
- minp
);
260 return 100 * (value
- this.options
.min
) / (this.options
.max
- this.options
.min
);
265 /* Based on http://stackoverflow.com/questions/846221/logarithmic-slider */
266 toValue: function(percentage
) {
267 var min
= (this.options
.min
=== 0) ? 0 : Math
.log(this.options
.min
);
268 var max
= Math
.log(this.options
.max
);
269 var value
= Math
.exp(min
+ (max
- min
) * percentage
/ 100);
270 value
= this.options
.min
+ Math
.round((value
- this.options
.min
) / this.options
.step
) * this.options
.step
;
271 /* Rounding to the nearest step could exceed the min or
272 * max, so clip to those values. */
273 if (value
< this.options
.min
) {
274 return this.options
.min
;
275 } else if (value
> this.options
.max
) {
276 return this.options
.max
;
281 toPercentage: function(value
) {
282 if (this.options
.max
=== this.options
.min
) {
285 var max
= Math
.log(this.options
.max
);
286 var min
= this.options
.min
=== 0 ? 0 : Math
.log(this.options
.min
);
287 var v
= value
=== 0 ? 0 : Math
.log(value
);
288 return 100 * (v
- min
) / (max
- min
);
295 /*************************************************
299 **************************************************/
300 Slider = function(element
, options
) {
301 createNewSlider
.call(this, element
, options
);
305 function createNewSlider(element
, options
) {
308 The internal state object is used to store data about the current 'state' of slider.
310 This includes values such as the `value`, `enabled`, etc...
323 if(typeof element
=== "string") {
324 this.element
= document
.querySelector(element
);
325 } else if(element
instanceof HTMLElement
) {
326 this.element
= element
;
329 /*************************************************
333 **************************************************/
334 options
= options
? options
: {};
335 var optionTypes
= Object
.keys(this.defaultOptions
);
337 for(var i
= 0; i
< optionTypes
.length
; i
++) {
338 var optName
= optionTypes
[i
];
340 // First check if an option was passed in via the constructor
341 var val
= options
[optName
];
342 // If no data attrib, then check data atrributes
343 val
= (typeof val
!== 'undefined') ? val
: getDataAttrib(this.element
, optName
);
344 // Finally, if nothing was specified, use the defaults
345 val
= (val
!== null) ? val
: this.defaultOptions
[optName
];
347 // Set all options on the instance of the Slider
351 this.options
[optName
] = val
;
355 Validate `tooltip_position` against 'orientation`
356 - if `tooltip_position` is incompatible with orientation, swith it to a default compatible with specified `orientation`
357 -- default for "vertical" -> "right"
358 -- default for "horizontal" -> "left"
360 if(this.options
.orientation
=== "vertical" && (this.options
.tooltip_position
=== "top" || this.options
.tooltip_position
=== "bottom")) {
362 this.options
.tooltip_position
= "right";
365 else if(this.options
.orientation
=== "horizontal" && (this.options
.tooltip_position
=== "left" || this.options
.tooltip_position
=== "right")) {
367 this.options
.tooltip_position
= "top";
371 function getDataAttrib(element
, optName
) {
372 var dataName
= "data-slider-" + optName
.replace(/_
/g
, '-');
373 var dataValString
= element
.getAttribute(dataName
);
376 return JSON
.parse(dataValString
);
379 return dataValString
;
383 /*************************************************
387 **************************************************/
389 var origWidth
= this.element
.style
.width
;
390 var updateSlider
= false;
391 var parent
= this.element
.parentNode
;
392 var sliderTrackSelection
;
393 var sliderTrackLow
, sliderTrackHigh
;
397 if (this.sliderElem
) {
400 /* Create elements needed for slider */
401 this.sliderElem
= document
.createElement("div");
402 this.sliderElem
.className
= "slider";
404 /* Create slider track elements */
405 var sliderTrack
= document
.createElement("div");
406 sliderTrack
.className
= "slider-track";
408 sliderTrackLow
= document
.createElement("div");
409 sliderTrackLow
.className
= "slider-track-low";
411 sliderTrackSelection
= document
.createElement("div");
412 sliderTrackSelection
.className
= "slider-selection";
414 sliderTrackHigh
= document
.createElement("div");
415 sliderTrackHigh
.className
= "slider-track-high";
417 sliderMinHandle
= document
.createElement("div");
418 sliderMinHandle
.className
= "slider-handle min-slider-handle";
419 sliderMinHandle
.setAttribute('role', 'slider');
420 sliderMinHandle
.setAttribute('aria-valuemin', this.options
.min
);
421 sliderMinHandle
.setAttribute('aria-valuemax', this.options
.max
);
423 sliderMaxHandle
= document
.createElement("div");
424 sliderMaxHandle
.className
= "slider-handle max-slider-handle";
425 sliderMaxHandle
.setAttribute('role', 'slider');
426 sliderMaxHandle
.setAttribute('aria-valuemin', this.options
.min
);
427 sliderMaxHandle
.setAttribute('aria-valuemax', this.options
.max
);
429 sliderTrack
.appendChild(sliderTrackLow
);
430 sliderTrack
.appendChild(sliderTrackSelection
);
431 sliderTrack
.appendChild(sliderTrackHigh
);
433 /* Add aria-labelledby to handle's */
434 var isLabelledbyArray
= Array
.isArray(this.options
.labelledby
);
435 if (isLabelledbyArray
&& this.options
.labelledby
[0]) {
436 sliderMinHandle
.setAttribute('aria-labelledby', this.options
.labelledby
[0]);
438 if (isLabelledbyArray
&& this.options
.labelledby
[1]) {
439 sliderMaxHandle
.setAttribute('aria-labelledby', this.options
.labelledby
[1]);
441 if (!isLabelledbyArray
&& this.options
.labelledby
) {
442 sliderMinHandle
.setAttribute('aria-labelledby', this.options
.labelledby
);
443 sliderMaxHandle
.setAttribute('aria-labelledby', this.options
.labelledby
);
448 if (Array
.isArray(this.options
.ticks
) && this.options
.ticks
.length
> 0) {
449 for (i
= 0; i
< this.options
.ticks
.length
; i
++) {
450 var tick
= document
.createElement('div');
451 tick
.className
= 'slider-tick';
453 this.ticks
.push(tick
);
454 sliderTrack
.appendChild(tick
);
457 sliderTrackSelection
.className
+= " tick-slider-selection";
460 sliderTrack
.appendChild(sliderMinHandle
);
461 sliderTrack
.appendChild(sliderMaxHandle
);
463 this.tickLabels
= [];
464 if (Array
.isArray(this.options
.ticks_labels
) && this.options
.ticks_labels
.length
> 0) {
465 this.tickLabelContainer
= document
.createElement('div');
466 this.tickLabelContainer
.className
= 'slider-tick-label-container';
468 for (i
= 0; i
< this.options
.ticks_labels
.length
; i
++) {
469 var label
= document
.createElement('div');
470 var noTickPositionsSpecified
= this.options
.ticks_positions
.length
=== 0;
471 var tickLabelsIndex
= (this.options
.reversed
&& noTickPositionsSpecified
) ? (this.options
.ticks_labels
.length
- (i
+ 1)) : i
;
472 label
.className
= 'slider-tick-label';
473 label
.innerHTML
= this.options
.ticks_labels
[tickLabelsIndex
];
475 this.tickLabels
.push(label
);
476 this.tickLabelContainer
.appendChild(label
);
481 var createAndAppendTooltipSubElements = function(tooltipElem
) {
482 var arrow
= document
.createElement("div");
483 arrow
.className
= "tooltip-arrow";
485 var inner
= document
.createElement("div");
486 inner
.className
= "tooltip-inner";
488 tooltipElem
.appendChild(arrow
);
489 tooltipElem
.appendChild(inner
);
493 /* Create tooltip elements */
494 var sliderTooltip
= document
.createElement("div");
495 sliderTooltip
.className
= "tooltip tooltip-main";
496 sliderTooltip
.setAttribute('role', 'presentation');
497 createAndAppendTooltipSubElements(sliderTooltip
);
499 var sliderTooltipMin
= document
.createElement("div");
500 sliderTooltipMin
.className
= "tooltip tooltip-min";
501 sliderTooltipMin
.setAttribute('role', 'presentation');
502 createAndAppendTooltipSubElements(sliderTooltipMin
);
504 var sliderTooltipMax
= document
.createElement("div");
505 sliderTooltipMax
.className
= "tooltip tooltip-max";
506 sliderTooltipMax
.setAttribute('role', 'presentation');
507 createAndAppendTooltipSubElements(sliderTooltipMax
);
510 /* Append components to sliderElem */
511 this.sliderElem
.appendChild(sliderTrack
);
512 this.sliderElem
.appendChild(sliderTooltip
);
513 this.sliderElem
.appendChild(sliderTooltipMin
);
514 this.sliderElem
.appendChild(sliderTooltipMax
);
516 if (this.tickLabelContainer
) {
517 this.sliderElem
.appendChild(this.tickLabelContainer
);
520 /* Append slider element to parent container, right before the original <input> element */
521 parent
.insertBefore(this.sliderElem
, this.element
);
523 /* Hide original <input> element */
524 this.element
.style
.display
= "none";
526 /* If JQuery exists, cache JQ references */
528 this.$element
= $(this.element
);
529 this.$sliderElem
= $(this.sliderElem
);
532 /*************************************************
536 **************************************************/
537 this.eventToCallbackMap
= {};
538 this.sliderElem
.id
= this.options
.id
;
540 this.touchCapable
= 'ontouchstart' in window
|| (window
.DocumentTouch
&& document
instanceof window
.DocumentTouch
);
542 this.tooltip
= this.sliderElem
.querySelector('.tooltip-main');
543 this.tooltipInner
= this.tooltip
.querySelector('.tooltip-inner');
545 this.tooltip_min
= this.sliderElem
.querySelector('.tooltip-min');
546 this.tooltipInner_min
= this.tooltip_min
.querySelector('.tooltip-inner');
548 this.tooltip_max
= this.sliderElem
.querySelector('.tooltip-max');
549 this.tooltipInner_max
= this.tooltip_max
.querySelector('.tooltip-inner');
551 if (SliderScale
[this.options
.scale
]) {
552 this.options
.scale
= SliderScale
[this.options
.scale
];
555 if (updateSlider
=== true) {
557 this._removeClass(this.sliderElem
, 'slider-horizontal');
558 this._removeClass(this.sliderElem
, 'slider-vertical');
559 this._removeClass(this.tooltip
, 'hide');
560 this._removeClass(this.tooltip_min
, 'hide');
561 this._removeClass(this.tooltip_max
, 'hide');
563 // Undo existing inline styles for track
564 ["left", "top", "width", "height"].forEach(function(prop
) {
565 this._removeProperty(this.trackLow
, prop
);
566 this._removeProperty(this.trackSelection
, prop
);
567 this._removeProperty(this.trackHigh
, prop
);
570 // Undo inline styles on handles
571 [this.handle1
, this.handle2
].forEach(function(handle
) {
572 this._removeProperty(handle
, 'left');
573 this._removeProperty(handle
, 'top');
576 // Undo inline styles and classes on tooltips
577 [this.tooltip
, this.tooltip_min
, this.tooltip_max
].forEach(function(tooltip
) {
578 this._removeProperty(tooltip
, 'left');
579 this._removeProperty(tooltip
, 'top');
580 this._removeProperty(tooltip
, 'margin-left');
581 this._removeProperty(tooltip
, 'margin-top');
583 this._removeClass(tooltip
, 'right');
584 this._removeClass(tooltip
, 'top');
588 if(this.options
.orientation
=== 'vertical') {
589 this._addClass(this.sliderElem
,'slider-vertical');
590 this.stylePos
= 'top';
591 this.mousePos
= 'pageY';
592 this.sizePos
= 'offsetHeight';
594 this._addClass(this.sliderElem
, 'slider-horizontal');
595 this.sliderElem
.style
.width
= origWidth
;
596 this.options
.orientation
= 'horizontal';
597 this.stylePos
= 'left';
598 this.mousePos
= 'pageX';
599 this.sizePos
= 'offsetWidth';
602 this._setTooltipPosition();
603 /* In case ticks are specified, overwrite the min and max bounds */
604 if (Array
.isArray(this.options
.ticks
) && this.options
.ticks
.length
> 0) {
605 this.options
.max
= Math
.max
.apply(Math
, this.options
.ticks
);
606 this.options
.min
= Math
.min
.apply(Math
, this.options
.ticks
);
609 if (Array
.isArray(this.options
.value
)) {
610 this.options
.range
= true;
611 this._state
.value
= this.options
.value
;
613 else if (this.options
.range
) {
614 // User wants a range, but value is not an array
615 this._state
.value
= [this.options
.value
, this.options
.max
];
618 this._state
.value
= this.options
.value
;
621 this.trackLow
= sliderTrackLow
|| this.trackLow
;
622 this.trackSelection
= sliderTrackSelection
|| this.trackSelection
;
623 this.trackHigh
= sliderTrackHigh
|| this.trackHigh
;
625 if (this.options
.selection
=== 'none') {
626 this._addClass(this.trackLow
, 'hide');
627 this._addClass(this.trackSelection
, 'hide');
628 this._addClass(this.trackHigh
, 'hide');
631 this.handle1
= sliderMinHandle
|| this.handle1
;
632 this.handle2
= sliderMaxHandle
|| this.handle2
;
634 if (updateSlider
=== true) {
636 this._removeClass(this.handle1
, 'round triangle');
637 this._removeClass(this.handle2
, 'round triangle hide');
639 for (i
= 0; i
< this.ticks
.length
; i
++) {
640 this._removeClass(this.ticks
[i
], 'round triangle hide');
644 var availableHandleModifiers
= ['round', 'triangle', 'custom'];
645 var isValidHandleType
= availableHandleModifiers
.indexOf(this.options
.handle
) !== -1;
646 if (isValidHandleType
) {
647 this._addClass(this.handle1
, this.options
.handle
);
648 this._addClass(this.handle2
, this.options
.handle
);
650 for (i
= 0; i
< this.ticks
.length
; i
++) {
651 this._addClass(this.ticks
[i
], this.options
.handle
);
655 this._state
.offset
= this._offset(this.sliderElem
);
656 this._state
.size
= this.sliderElem
[this.sizePos
];
657 this.setValue(this._state
.value
);
659 /******************************************
663 ******************************************/
665 // Bind keyboard handlers
666 this.handle1Keydown
= this._keydown
.bind(this, 0);
667 this.handle1
.addEventListener("keydown", this.handle1Keydown
, false);
669 this.handle2Keydown
= this._keydown
.bind(this, 1);
670 this.handle2
.addEventListener("keydown", this.handle2Keydown
, false);
672 this.mousedown
= this._mousedown
.bind(this);
673 if (this.touchCapable
) {
674 // Bind touch handlers
675 this.sliderElem
.addEventListener("touchstart", this.mousedown
, false);
677 this.sliderElem
.addEventListener("mousedown", this.mousedown
, false);
680 // Bind tooltip-related handlers
681 if(this.options
.tooltip
=== 'hide') {
682 this._addClass(this.tooltip
, 'hide');
683 this._addClass(this.tooltip_min
, 'hide');
684 this._addClass(this.tooltip_max
, 'hide');
686 else if(this.options
.tooltip
=== 'always') {
688 this._alwaysShowTooltip
= true;
691 this.showTooltip
= this._showTooltip
.bind(this);
692 this.hideTooltip
= this._hideTooltip
.bind(this);
694 this.sliderElem
.addEventListener("mouseenter", this.showTooltip
, false);
695 this.sliderElem
.addEventListener("mouseleave", this.hideTooltip
, false);
697 this.handle1
.addEventListener("focus", this.showTooltip
, false);
698 this.handle1
.addEventListener("blur", this.hideTooltip
, false);
700 this.handle2
.addEventListener("focus", this.showTooltip
, false);
701 this.handle2
.addEventListener("blur", this.hideTooltip
, false);
704 if(this.options
.enabled
) {
713 /*************************************************
715 INSTANCE PROPERTIES/METHODS
717 - Any methods bound to the prototype are considered
718 part of the plugin's `public` interface
720 **************************************************/
722 _init: function() {}, // NOTE: Must exist to support bridget
732 orientation
: 'horizontal',
737 tooltip_split
: false,
741 formatter: function(val
) {
742 if (Array
.isArray(val
)) {
743 return val
[0] + " : " + val
[1];
748 natural_arrow_keys
: false,
752 ticks_snap_bounds
: 0,
755 tooltip_position
: null,
759 getElement: function() {
760 return this.sliderElem
;
763 getValue: function() {
764 if (this.options
.range
) {
765 return this._state
.value
;
768 return this._state
.value
[0];
772 setValue: function(val
, triggerSlideEvent
, triggerChangeEvent
) {
776 var oldValue
= this.getValue();
777 this._state
.value
= this._validateInputValue(val
);
778 var applyPrecision
= this._applyPrecision
.bind(this);
780 if (this.options
.range
) {
781 this._state
.value
[0] = applyPrecision(this._state
.value
[0]);
782 this._state
.value
[1] = applyPrecision(this._state
.value
[1]);
784 this._state
.value
[0] = Math
.max(this.options
.min
, Math
.min(this.options
.max
, this._state
.value
[0]));
785 this._state
.value
[1] = Math
.max(this.options
.min
, Math
.min(this.options
.max
, this._state
.value
[1]));
788 this._state
.value
= applyPrecision(this._state
.value
);
789 this._state
.value
= [ Math
.max(this.options
.min
, Math
.min(this.options
.max
, this._state
.value
))];
790 this._addClass(this.handle2
, 'hide');
791 if (this.options
.selection
=== 'after') {
792 this._state
.value
[1] = this.options
.max
;
794 this._state
.value
[1] = this.options
.min
;
798 if (this.options
.max
> this.options
.min
) {
799 this._state
.percentage
= [
800 this._toPercentage(this._state
.value
[0]),
801 this._toPercentage(this._state
.value
[1]),
802 this.options
.step
* 100 / (this.options
.max
- this.options
.min
)
805 this._state
.percentage
= [0, 0, 100];
809 var newValue
= this.options
.range
? this._state
.value
: this._state
.value
[0];
811 if(triggerSlideEvent
=== true) {
812 this._trigger('slide', newValue
);
814 if( (oldValue
!== newValue
) && (triggerChangeEvent
=== true) ) {
815 this._trigger('change', {
820 this._setDataVal(newValue
);
826 // Remove event handlers on slider elements
827 this._removeSliderEventHandlers();
829 // Remove the slider from the DOM
830 this.sliderElem
.parentNode
.removeChild(this.sliderElem
);
831 /* Show original <input> element */
832 this.element
.style
.display
= "";
834 // Clear out custom event bindings
835 this._cleanUpEventCallbacksMap();
837 // Remove data values
838 this.element
.removeAttribute("data");
840 // Remove JQuery handlers/data
842 this._unbindJQueryEventHandlers();
843 this.$element
.removeData('slider');
847 disable: function() {
848 this._state
.enabled
= false;
849 this.handle1
.removeAttribute("tabindex");
850 this.handle2
.removeAttribute("tabindex");
851 this._addClass(this.sliderElem
, 'slider-disabled');
852 this._trigger('slideDisabled');
858 this._state
.enabled
= true;
859 this.handle1
.setAttribute("tabindex", 0);
860 this.handle2
.setAttribute("tabindex", 0);
861 this._removeClass(this.sliderElem
, 'slider-disabled');
862 this._trigger('slideEnabled');
868 if(this._state
.enabled
) {
876 isEnabled: function() {
877 return this._state
.enabled
;
880 on: function(evt
, callback
) {
881 this._bindNonQueryEventHandler(evt
, callback
);
885 off: function(evt
, callback
) {
887 this.$element
.off(evt
, callback
);
888 this.$sliderElem
.off(evt
, callback
);
890 this._unbindNonQueryEventHandler(evt
, callback
);
894 getAttribute: function(attribute
) {
896 return this.options
[attribute
];
902 setAttribute: function(attribute
, value
) {
903 this.options
[attribute
] = value
;
907 refresh: function() {
908 this._removeSliderEventHandlers();
909 createNewSlider
.call(this, this.element
, this.options
);
911 // Bind new instance of slider to the element
912 $.data(this.element
, 'slider', this);
917 relayout: function() {
922 /******************************+
926 - Any method that is not part of the public interface.
927 - Place it underneath this comment block and write its signature like so:
929 _fnName : function() {...}
931 ********************************/
932 _removeSliderEventHandlers: function() {
933 // Remove keydown event listeners
934 this.handle1
.removeEventListener("keydown", this.handle1Keydown
, false);
935 this.handle2
.removeEventListener("keydown", this.handle2Keydown
, false);
937 if (this.showTooltip
) {
938 this.handle1
.removeEventListener("focus", this.showTooltip
, false);
939 this.handle2
.removeEventListener("focus", this.showTooltip
, false);
941 if (this.hideTooltip
) {
942 this.handle1
.removeEventListener("blur", this.hideTooltip
, false);
943 this.handle2
.removeEventListener("blur", this.hideTooltip
, false);
946 // Remove event listeners from sliderElem
947 if (this.showTooltip
) {
948 this.sliderElem
.removeEventListener("mouseenter", this.showTooltip
, false);
950 if (this.hideTooltip
) {
951 this.sliderElem
.removeEventListener("mouseleave", this.hideTooltip
, false);
953 this.sliderElem
.removeEventListener("touchstart", this.mousedown
, false);
954 this.sliderElem
.removeEventListener("mousedown", this.mousedown
, false);
956 _bindNonQueryEventHandler: function(evt
, callback
) {
957 if(this.eventToCallbackMap
[evt
] === undefined) {
958 this.eventToCallbackMap
[evt
] = [];
960 this.eventToCallbackMap
[evt
].push(callback
);
962 _unbindNonQueryEventHandler: function(evt
, callback
) {
963 var callbacks
= this.eventToCallbackMap
[evt
];
964 if(callbacks
!== undefined) {
965 for (var i
= 0; i
< callbacks
.length
; i
++) {
966 if (callbacks
[i
] === callback
) {
967 callbacks
.splice(i
, 1);
973 _cleanUpEventCallbacksMap: function() {
974 var eventNames
= Object
.keys(this.eventToCallbackMap
);
975 for(var i
= 0; i
< eventNames
.length
; i
++) {
976 var eventName
= eventNames
[i
];
977 this.eventToCallbackMap
[eventName
] = null;
980 _showTooltip: function() {
981 if (this.options
.tooltip_split
=== false ){
982 this._addClass(this.tooltip
, 'in');
983 this.tooltip_min
.style
.display
= 'none';
984 this.tooltip_max
.style
.display
= 'none';
986 this._addClass(this.tooltip_min
, 'in');
987 this._addClass(this.tooltip_max
, 'in');
988 this.tooltip
.style
.display
= 'none';
990 this._state
.over
= true;
992 _hideTooltip: function() {
993 if (this._state
.inDrag
=== false && this.alwaysShowTooltip
!== true) {
994 this._removeClass(this.tooltip
, 'in');
995 this._removeClass(this.tooltip_min
, 'in');
996 this._removeClass(this.tooltip_max
, 'in');
998 this._state
.over
= false;
1000 _layout: function() {
1001 var positionPercentages
;
1003 if(this.options
.reversed
) {
1004 positionPercentages
= [ 100 - this._state
.percentage
[0], this.options
.range
? 100 - this._state
.percentage
[1] : this._state
.percentage
[1]];
1007 positionPercentages
= [ this._state
.percentage
[0], this._state
.percentage
[1] ];
1010 this.handle1
.style
[this.stylePos
] = positionPercentages
[0]+'%';
1011 this.handle1
.setAttribute('aria-valuenow', this._state
.value
[0]);
1013 this.handle2
.style
[this.stylePos
] = positionPercentages
[1]+'%';
1014 this.handle2
.setAttribute('aria-valuenow', this._state
.value
[1]);
1016 /* Position ticks and labels */
1017 if (Array
.isArray(this.options
.ticks
) && this.options
.ticks
.length
> 0) {
1019 var styleSize
= this.options
.orientation
=== 'vertical' ? 'height' : 'width';
1020 var styleMargin
= this.options
.orientation
=== 'vertical' ? 'marginTop' : 'marginLeft';
1021 var labelSize
= this._state
.size
/ (this.options
.ticks
.length
- 1);
1023 if (this.tickLabelContainer
) {
1024 var extraMargin
= 0;
1025 if (this.options
.ticks_positions
.length
=== 0) {
1026 if (this.options
.orientation
!== 'vertical') {
1027 this.tickLabelContainer
.style
[styleMargin
] = -labelSize
/2 + 'px';
1030 extraMargin
= this.tickLabelContainer
.offsetHeight
;
1032 /* Chidren are position absolute, calculate height by finding the max offsetHeight of a child */
1033 for (i
= 0 ; i
< this.tickLabelContainer
.childNodes
.length
; i
++) {
1034 if (this.tickLabelContainer
.childNodes
[i
].offsetHeight
> extraMargin
) {
1035 extraMargin
= this.tickLabelContainer
.childNodes
[i
].offsetHeight
;
1039 if (this.options
.orientation
=== 'horizontal') {
1040 this.sliderElem
.style
.marginBottom
= extraMargin
+ 'px';
1043 for (var i
= 0; i
< this.options
.ticks
.length
; i
++) {
1045 var percentage
= this.options
.ticks_positions
[i
] || this._toPercentage(this.options
.ticks
[i
]);
1047 if (this.options
.reversed
) {
1048 percentage
= 100 - percentage
;
1051 this.ticks
[i
].style
[this.stylePos
] = percentage
+ '%';
1053 /* Set class labels to denote whether ticks are in the selection */
1054 this._removeClass(this.ticks
[i
], 'in-selection');
1055 if (!this.options
.range
) {
1056 if (this.options
.selection
=== 'after' && percentage
>= positionPercentages
[0]){
1057 this._addClass(this.ticks
[i
], 'in-selection');
1058 } else if (this.options
.selection
=== 'before' && percentage
<= positionPercentages
[0]) {
1059 this._addClass(this.ticks
[i
], 'in-selection');
1061 } else if (percentage
>= positionPercentages
[0] && percentage
<= positionPercentages
[1]) {
1062 this._addClass(this.ticks
[i
], 'in-selection');
1065 if (this.tickLabels
[i
]) {
1066 this.tickLabels
[i
].style
[styleSize
] = labelSize
+ 'px';
1068 if (this.options
.orientation
!== 'vertical' && this.options
.ticks_positions
[i
] !== undefined) {
1069 this.tickLabels
[i
].style
.position
= 'absolute';
1070 this.tickLabels
[i
].style
[this.stylePos
] = percentage
+ '%';
1071 this.tickLabels
[i
].style
[styleMargin
] = -labelSize
/2 + 'px';
1072 } else if (this.options
.orientation
=== 'vertical') {
1073 this.tickLabels
[i
].style
['marginLeft'] = this.sliderElem
.offsetWidth
+ 'px';
1074 this.tickLabelContainer
.style
['marginTop'] = this.sliderElem
.offsetWidth
/ 2 * -1 + 'px';
1080 var formattedTooltipVal
;
1082 if (this.options
.range
) {
1083 formattedTooltipVal
= this.options
.formatter(this._state
.value
);
1084 this._setText(this.tooltipInner
, formattedTooltipVal
);
1085 this.tooltip
.style
[this.stylePos
] = (positionPercentages
[1] + positionPercentages
[0])/2 + '%';
1087 if (this.options
.orientation
=== 'vertical') {
1088 this._css(this.tooltip
, 'margin-top', -this.tooltip
.offsetHeight
/ 2 + 'px');
1090 this._css(this.tooltip
, 'margin-left', -this.tooltip
.offsetWidth
/ 2 + 'px');
1093 if (this.options
.orientation
=== 'vertical') {
1094 this._css(this.tooltip
, 'margin-top', -this.tooltip
.offsetHeight
/ 2 + 'px');
1096 this._css(this.tooltip
, 'margin-left', -this.tooltip
.offsetWidth
/ 2 + 'px');
1099 var innerTooltipMinText
= this.options
.formatter(this._state
.value
[0]);
1100 this._setText(this.tooltipInner_min
, innerTooltipMinText
);
1102 var innerTooltipMaxText
= this.options
.formatter(this._state
.value
[1]);
1103 this._setText(this.tooltipInner_max
, innerTooltipMaxText
);
1105 this.tooltip_min
.style
[this.stylePos
] = positionPercentages
[0] + '%';
1107 if (this.options
.orientation
=== 'vertical') {
1108 this._css(this.tooltip_min
, 'margin-top', -this.tooltip_min
.offsetHeight
/ 2 + 'px');
1110 this._css(this.tooltip_min
, 'margin-left', -this.tooltip_min
.offsetWidth
/ 2 + 'px');
1113 this.tooltip_max
.style
[this.stylePos
] = positionPercentages
[1] + '%';
1115 if (this.options
.orientation
=== 'vertical') {
1116 this._css(this.tooltip_max
, 'margin-top', -this.tooltip_max
.offsetHeight
/ 2 + 'px');
1118 this._css(this.tooltip_max
, 'margin-left', -this.tooltip_max
.offsetWidth
/ 2 + 'px');
1121 formattedTooltipVal
= this.options
.formatter(this._state
.value
[0]);
1122 this._setText(this.tooltipInner
, formattedTooltipVal
);
1124 this.tooltip
.style
[this.stylePos
] = positionPercentages
[0] + '%';
1125 if (this.options
.orientation
=== 'vertical') {
1126 this._css(this.tooltip
, 'margin-top', -this.tooltip
.offsetHeight
/ 2 + 'px');
1128 this._css(this.tooltip
, 'margin-left', -this.tooltip
.offsetWidth
/ 2 + 'px');
1132 if (this.options
.orientation
=== 'vertical') {
1133 this.trackLow
.style
.top
= '0';
1134 this.trackLow
.style
.height
= Math
.min(positionPercentages
[0], positionPercentages
[1]) +'%';
1136 this.trackSelection
.style
.top
= Math
.min(positionPercentages
[0], positionPercentages
[1]) +'%';
1137 this.trackSelection
.style
.height
= Math
.abs(positionPercentages
[0] - positionPercentages
[1]) +'%';
1139 this.trackHigh
.style
.bottom
= '0';
1140 this.trackHigh
.style
.height
= (100 - Math
.min(positionPercentages
[0], positionPercentages
[1]) - Math
.abs(positionPercentages
[0] - positionPercentages
[1])) +'%';
1143 this.trackLow
.style
.left
= '0';
1144 this.trackLow
.style
.width
= Math
.min(positionPercentages
[0], positionPercentages
[1]) +'%';
1146 this.trackSelection
.style
.left
= Math
.min(positionPercentages
[0], positionPercentages
[1]) +'%';
1147 this.trackSelection
.style
.width
= Math
.abs(positionPercentages
[0] - positionPercentages
[1]) +'%';
1149 this.trackHigh
.style
.right
= '0';
1150 this.trackHigh
.style
.width
= (100 - Math
.min(positionPercentages
[0], positionPercentages
[1]) - Math
.abs(positionPercentages
[0] - positionPercentages
[1])) +'%';
1152 var offset_min
= this.tooltip_min
.getBoundingClientRect();
1153 var offset_max
= this.tooltip_max
.getBoundingClientRect();
1155 if (offset_min
.right
> offset_max
.left
) {
1156 this._removeClass(this.tooltip_max
, 'top');
1157 this._addClass(this.tooltip_max
, 'bottom');
1158 this.tooltip_max
.style
.top
= 18 + 'px';
1160 this._removeClass(this.tooltip_max
, 'bottom');
1161 this._addClass(this.tooltip_max
, 'top');
1162 this.tooltip_max
.style
.top
= this.tooltip_min
.style
.top
;
1166 _removeProperty: function(element
, prop
) {
1167 if (element
.style
.removeProperty
) {
1168 element
.style
.removeProperty(prop
);
1170 element
.style
.removeAttribute(prop
);
1173 _mousedown: function(ev
) {
1174 if(!this._state
.enabled
) {
1178 this._state
.offset
= this._offset(this.sliderElem
);
1179 this._state
.size
= this.sliderElem
[this.sizePos
];
1181 var percentage
= this._getPercentage(ev
);
1183 if (this.options
.range
) {
1184 var diff1
= Math
.abs(this._state
.percentage
[0] - percentage
);
1185 var diff2
= Math
.abs(this._state
.percentage
[1] - percentage
);
1186 this._state
.dragged
= (diff1
< diff2
) ? 0 : 1;
1188 this._state
.dragged
= 0;
1191 this._state
.percentage
[this._state
.dragged
] = percentage
;
1194 if (this.touchCapable
) {
1195 document
.removeEventListener("touchmove", this.mousemove
, false);
1196 document
.removeEventListener("touchend", this.mouseup
, false);
1200 document
.removeEventListener("mousemove", this.mousemove
, false);
1203 document
.removeEventListener("mouseup", this.mouseup
, false);
1206 this.mousemove
= this._mousemove
.bind(this);
1207 this.mouseup
= this._mouseup
.bind(this);
1209 if (this.touchCapable
) {
1210 // Touch: Bind touch events:
1211 document
.addEventListener("touchmove", this.mousemove
, false);
1212 document
.addEventListener("touchend", this.mouseup
, false);
1214 // Bind mouse events:
1215 document
.addEventListener("mousemove", this.mousemove
, false);
1216 document
.addEventListener("mouseup", this.mouseup
, false);
1218 this._state
.inDrag
= true;
1219 var newValue
= this._calculateValue();
1221 this._trigger('slideStart', newValue
);
1223 this._setDataVal(newValue
);
1224 this.setValue(newValue
, false, true);
1226 this._pauseEvent(ev
);
1228 if (this.options
.focus
) {
1229 this._triggerFocusOnHandle(this._state
.dragged
);
1234 _triggerFocusOnHandle: function(handleIdx
) {
1235 if(handleIdx
=== 0) {
1236 this.handle1
.focus();
1238 if(handleIdx
=== 1) {
1239 this.handle2
.focus();
1242 _keydown: function(handleIdx
, ev
) {
1243 if(!this._state
.enabled
) {
1248 switch (ev
.keyCode
) {
1262 // use natural arrow keys instead of from min to max
1263 if (this.options
.natural_arrow_keys
) {
1264 var ifVerticalAndNotReversed
= (this.options
.orientation
=== 'vertical' && !this.options
.reversed
);
1265 var ifHorizontalAndReversed
= (this.options
.orientation
=== 'horizontal' && this.options
.reversed
);
1267 if (ifVerticalAndNotReversed
|| ifHorizontalAndReversed
) {
1272 var val
= this._state
.value
[handleIdx
] + dir
* this.options
.step
;
1273 if (this.options
.range
) {
1274 val
= [ (!handleIdx
) ? val
: this._state
.value
[0],
1275 ( handleIdx
) ? val
: this._state
.value
[1]];
1278 this._trigger('slideStart', val
);
1279 this._setDataVal(val
);
1280 this.setValue(val
, true, true);
1282 this._setDataVal(val
);
1283 this._trigger('slideStop', val
);
1286 this._pauseEvent(ev
);
1290 _pauseEvent: function(ev
) {
1291 if(ev
.stopPropagation
) {
1292 ev
.stopPropagation();
1294 if(ev
.preventDefault
) {
1295 ev
.preventDefault();
1297 ev
.cancelBubble
=true;
1298 ev
.returnValue
=false;
1300 _mousemove: function(ev
) {
1301 if(!this._state
.enabled
) {
1305 var percentage
= this._getPercentage(ev
);
1306 this._adjustPercentageForRangeSliders(percentage
);
1307 this._state
.percentage
[this._state
.dragged
] = percentage
;
1310 var val
= this._calculateValue(true);
1311 this.setValue(val
, true, true);
1315 _adjustPercentageForRangeSliders: function(percentage
) {
1316 if (this.options
.range
) {
1317 var precision
= this._getNumDigitsAfterDecimalPlace(percentage
);
1318 precision
= precision
? precision
- 1 : 0;
1319 var percentageWithAdjustedPrecision
= this._applyToFixedAndParseFloat(percentage
, precision
);
1320 if (this._state
.dragged
=== 0 && this._applyToFixedAndParseFloat(this._state
.percentage
[1], precision
) < percentageWithAdjustedPrecision
) {
1321 this._state
.percentage
[0] = this._state
.percentage
[1];
1322 this._state
.dragged
= 1;
1323 } else if (this._state
.dragged
=== 1 && this._applyToFixedAndParseFloat(this._state
.percentage
[0], precision
) > percentageWithAdjustedPrecision
) {
1324 this._state
.percentage
[1] = this._state
.percentage
[0];
1325 this._state
.dragged
= 0;
1329 _mouseup: function() {
1330 if(!this._state
.enabled
) {
1333 if (this.touchCapable
) {
1334 // Touch: Unbind touch event handlers:
1335 document
.removeEventListener("touchmove", this.mousemove
, false);
1336 document
.removeEventListener("touchend", this.mouseup
, false);
1338 // Unbind mouse event handlers:
1339 document
.removeEventListener("mousemove", this.mousemove
, false);
1340 document
.removeEventListener("mouseup", this.mouseup
, false);
1342 this._state
.inDrag
= false;
1343 if (this._state
.over
=== false) {
1344 this._hideTooltip();
1346 var val
= this._calculateValue(true);
1349 this._setDataVal(val
);
1350 this._trigger('slideStop', val
);
1354 _calculateValue: function(snapToClosestTick
) {
1356 if (this.options
.range
) {
1357 val
= [this.options
.min
,this.options
.max
];
1358 if (this._state
.percentage
[0] !== 0){
1359 val
[0] = this._toValue(this._state
.percentage
[0]);
1360 val
[0] = this._applyPrecision(val
[0]);
1362 if (this._state
.percentage
[1] !== 100){
1363 val
[1] = this._toValue(this._state
.percentage
[1]);
1364 val
[1] = this._applyPrecision(val
[1]);
1367 val
= this._toValue(this._state
.percentage
[0]);
1368 val
= parseFloat(val
);
1369 val
= this._applyPrecision(val
);
1372 if (snapToClosestTick
) {
1373 var min
= [val
, Infinity
];
1374 for (var i
= 0; i
< this.options
.ticks
.length
; i
++) {
1375 var diff
= Math
.abs(this.options
.ticks
[i
] - val
);
1376 if (diff
<= min
[1]) {
1377 min
= [this.options
.ticks
[i
], diff
];
1380 if (min
[1] <= this.options
.ticks_snap_bounds
) {
1387 _applyPrecision: function(val
) {
1388 var precision
= this.options
.precision
|| this._getNumDigitsAfterDecimalPlace(this.options
.step
);
1389 return this._applyToFixedAndParseFloat(val
, precision
);
1391 _getNumDigitsAfterDecimalPlace: function(num
) {
1392 var match
= (''+num
).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
1393 if (!match
) { return 0; }
1394 return Math
.max(0, (match
[1] ? match
[1].length
: 0) - (match
[2] ? +match
[2] : 0));
1396 _applyToFixedAndParseFloat: function(num
, toFixedInput
) {
1397 var truncatedNum
= num
.toFixed(toFixedInput
);
1398 return parseFloat(truncatedNum
);
1401 Credits to Mike Samuel for the following method!
1402 Source: http://stackoverflow.com/questions/10454518/javascript-how-to-retrieve-the-number-of-decimals-of-a-string-number
1404 _getPercentage: function(ev
) {
1405 if (this.touchCapable
&& (ev
.type
=== 'touchstart' || ev
.type
=== 'touchmove')) {
1409 var eventPosition
= ev
[this.mousePos
];
1410 var sliderOffset
= this._state
.offset
[this.stylePos
];
1411 var distanceToSlide
= eventPosition
- sliderOffset
;
1412 // Calculate what percent of the length the slider handle has slid
1413 var percentage
= (distanceToSlide
/ this._state
.size
) * 100;
1414 percentage
= Math
.round(percentage
/ this._state
.percentage
[2]) * this._state
.percentage
[2];
1415 if (this.options
.reversed
) {
1416 percentage
= 100 - percentage
;
1419 // Make sure the percent is within the bounds of the slider.
1420 // 0% corresponds to the 'min' value of the slide
1421 // 100% corresponds to the 'max' value of the slide
1422 return Math
.max(0, Math
.min(100, percentage
));
1424 _validateInputValue: function(val
) {
1425 if (typeof val
=== 'number') {
1427 } else if (Array
.isArray(val
)) {
1428 this._validateArray(val
);
1431 throw new Error( ErrorMsgs
.formatInvalidInputErrorMsg(val
) );
1434 _validateArray: function(val
) {
1435 for(var i
= 0; i
< val
.length
; i
++) {
1437 if (typeof input
!== 'number') { throw new Error( ErrorMsgs
.formatInvalidInputErrorMsg(input
) ); }
1440 _setDataVal: function(val
) {
1441 this.element
.setAttribute('data-value', val
);
1442 this.element
.setAttribute('value', val
);
1443 this.element
.value
= val
;
1445 _trigger: function(evt
, val
) {
1446 val
= (val
|| val
=== 0) ? val
: undefined;
1448 var callbackFnArray
= this.eventToCallbackMap
[evt
];
1449 if(callbackFnArray
&& callbackFnArray
.length
) {
1450 for(var i
= 0; i
< callbackFnArray
.length
; i
++) {
1451 var callbackFn
= callbackFnArray
[i
];
1456 /* If JQuery exists, trigger JQuery events */
1458 this._triggerJQueryEvent(evt
, val
);
1461 _triggerJQueryEvent: function(evt
, val
) {
1466 this.$element
.trigger(eventData
);
1467 this.$sliderElem
.trigger(eventData
);
1469 _unbindJQueryEventHandlers: function() {
1470 this.$element
.off();
1471 this.$sliderElem
.off();
1473 _setText: function(element
, text
) {
1474 if(typeof element
.innerText
!== "undefined") {
1475 element
.innerText
= text
;
1476 } else if(typeof element
.textContent
!== "undefined") {
1477 element
.textContent
= text
;
1480 _removeClass: function(element
, classString
) {
1481 var classes
= classString
.split(" ");
1482 var newClasses
= element
.className
;
1484 for(var i
= 0; i
< classes
.length
; i
++) {
1485 var classTag
= classes
[i
];
1486 var regex
= new RegExp("(?:\\s|^)" + classTag
+ "(?:\\s|$)");
1487 newClasses
= newClasses
.replace(regex
, " ");
1490 element
.className
= newClasses
.trim();
1492 _addClass: function(element
, classString
) {
1493 var classes
= classString
.split(" ");
1494 var newClasses
= element
.className
;
1496 for(var i
= 0; i
< classes
.length
; i
++) {
1497 var classTag
= classes
[i
];
1498 var regex
= new RegExp("(?:\\s|^)" + classTag
+ "(?:\\s|$)");
1499 var ifClassExists
= regex
.test(newClasses
);
1501 if(!ifClassExists
) {
1502 newClasses
+= " " + classTag
;
1506 element
.className
= newClasses
.trim();
1508 _offsetLeft: function(obj
){
1509 return obj
.getBoundingClientRect().left
;
1511 _offsetTop: function(obj
){
1512 var offsetTop
= obj
.offsetTop
;
1513 while((obj
= obj
.offsetParent
) && !isNaN(obj
.offsetTop
)){
1514 offsetTop
+= obj
.offsetTop
;
1518 _offset: function (obj
) {
1520 left
: this._offsetLeft(obj
),
1521 top
: this._offsetTop(obj
)
1524 _css: function(elementRef
, styleName
, value
) {
1526 $.style(elementRef
, styleName
, value
);
1528 var style
= styleName
.replace(/^-ms-/, "ms-").replace(/-([\da-z])/gi, function (all
, letter
) {
1529 return letter
.toUpperCase();
1531 elementRef
.style
[style
] = value
;
1534 _toValue: function(percentage
) {
1535 return this.options
.scale
.toValue
.apply(this, [percentage
]);
1537 _toPercentage: function(value
) {
1538 return this.options
.scale
.toPercentage
.apply(this, [value
]);
1540 _setTooltipPosition: function(){
1541 var tooltips
= [this.tooltip
, this.tooltip_min
, this.tooltip_max
];
1542 if (this.options
.orientation
=== 'vertical'){
1543 var tooltipPos
= this.options
.tooltip_position
|| 'right';
1544 var oppositeSide
= (tooltipPos
=== 'left') ? 'right' : 'left';
1545 tooltips
.forEach(function(tooltip
){
1546 this._addClass(tooltip
, tooltipPos
);
1547 tooltip
.style
[oppositeSide
] = '100%';
1549 } else if(this.options
.tooltip_position
=== 'bottom') {
1550 tooltips
.forEach(function(tooltip
){
1551 this._addClass(tooltip
, 'bottom');
1552 tooltip
.style
.top
= 22 + 'px';
1555 tooltips
.forEach(function(tooltip
){
1556 this._addClass(tooltip
, 'top');
1557 tooltip
.style
.top
= -this.tooltip
.outerHeight
- 14 + 'px';
1563 /*********************************
1565 Attach to global namespace
1567 *********************************/
1569 var namespace = $.fn
.slider
? 'bootstrapSlider' : 'slider';
1570 $.bridget(namespace, Slider
);