PageSourceSearch

https://hkshippers.org.hk/assets/vendors/bootstrap-slider-master/src/js/bootstrap-slider.js

js hkshippers.org.hk collected 2026-10-08 00:04:22 UTC 64,341 bytes, 1,942 lines download raw bytes

vendor: 7,676 bytes, lines 1-255
1/*! =========================================================
2 * bootstrap-slider.js
3 *
4 * Maintainers:
5 *		Kyle Kemp
6 *			- Twitter: @seiyria
7 *			- Github:  seiyria
8 *		Rohit Kalkur
9 *			- Twitter: @Rovolutionary
10 *			- Github:  rovolution
11 *
12 * =========================================================
13 *
14 * bootstrap-slider is released under the MIT License
15 * Copyright (c) 2017 Kyle Kemp, Rohit Kalkur, and contributors
16 *
17 * Permission is hereby granted, free of charge, to any person
18 * obtaining a copy of this software and associated documentation
19 * files (the "Software"), to deal in the Software without
20 * restriction, including without limitation the rights to use,
21 * copy, modify, merge, publish, distribute, sublicense, and/or sell
22 * copies of the Software, and to permit persons to whom the
23 * Software is furnished to do so, subject to the following
24 * conditions:
25 *
26 * The above copyright notice and this permission notice shall be
27 * included in all copies or substantial portions of the Software.
28 *
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
31 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
33 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
34 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
35 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
36 * OTHER DEALINGS IN THE SOFTWARE.
37 *
38 * ========================================================= */
39
40
41/**
42 * Bridget makes jQuery widgets
43 * v1.0.1
44 * MIT license
45 */
46const windowIsDefined = (typeof window === "object");
47
48
49(function(factory) {
50	if(typeof define === "function" && define.amd) {
51		define(["jquery"], factory);
52	}
53	else if(typeof module === "object" && module.exports) {
54		var jQuery;
55		try {
56			jQuery = require("jquery");
57		}
58		catch (err) {
59			jQuery = null;
60		}
61		module.exports = factory(jQuery);
62	}
63	else if(window) {
64		window.Slider = factory(window.jQuery);
65	}
66}(function($) {
67	// Constants
68	const NAMESPACE_MAIN = 'slider';
69	const NAMESPACE_ALTERNATE = 'bootstrapSlider';
70
71	// Polyfill console methods
72	if (windowIsDefined && !window.console) {
73		window.console = {};
74	}
75	if (windowIsDefined && !window.console.log) {
76		window.console.log = function () { };
77	}
78	if (windowIsDefined && !window.console.warn) {
79		window.console.warn = function () { };
80	}
81
82	// Reference to Slider constructor
83	var Slider;
84
85
86	(function( $ ) {
87
88		'use strict';
89
90		// -------------------------- utils -------------------------- //
91
92		var slice = Array.prototype.slice;
93
94		function noop() {}
95
96		// -------------------------- definition -------------------------- //
97
98		function defineBridget( $ ) {
99
100			// bail if no jQuery
101			if ( !$ ) {
102				return;
103			}
104
105			// -------------------------- addOptionMethod -------------------------- //
106
107			/**
108			 * adds option method -> $().plugin('option', {...})
109			 * @param {Function} PluginClass - constructor class
110			 */
111			function addOptionMethod( PluginClass ) {
112				// don't overwrite original option method
113				if ( PluginClass.prototype.option ) {
114					return;
115				}
116
117			  // option setter
118			  PluginClass.prototype.option = function( opts ) {
119			    // bail out if not an object
120			    if ( !$.isPlainObject( opts ) ){
121			      return;
122			    }
123			    this.options = $.extend( true, this.options, opts );
124			  };
125			}
126
127
128			// -------------------------- plugin bridge -------------------------- //
129
130			// helper function for logging errors
131			// $.error breaks jQuery chaining
132			var logError = typeof console === 'undefined' ? noop :
133			  function( message ) {
134			    console.error( message );
135			  };
136
137			/**
138			 * jQuery plugin bridge, access methods like $elem.plugin('method')
139			 * @param {String} namespace - plugin name
140			 * @param {Function} PluginClass - constructor class
141			 */
142			function bridge( namespace, PluginClass ) {
143			  // add to jQuery fn namespace
144			  $.fn[ namespace ] = function( options ) {
145			    if ( typeof options === 'string' ) {
146			      // call plugin method when first argument is a string
147			      // get arguments for method
148			      var args = slice.call( arguments, 1 );
149
150			      for ( var i=0, len = this.length; i < len; i++ ) {
151			        var elem = this[i];
152			        var instance = $.data( elem, namespace );
153			        if ( !instance ) {
154			          logError( "cannot call methods on " + namespace + " prior to initialization; " +
155			            "attempted to call '" + options + "'" );
156			          continue;
157			        }
158			        if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) {
159			          logError( "no such method '" + options + "' for " + namespace + " instance" );
160			          continue;
161			        }
162
163			        // trigger method with arguments
164			        var returnValue = instance[ options ].apply( instance, args);
165
166			        // break look and return first value if provided
167			        if ( returnValue !== undefined && returnValue !== instance) {
168			          return returnValue;
169			        }
170			      }
171			      // return this if no return value
172			      return this;
173			    } else {
174			      var objects = this.map( function() {
175			        var instance = $.data( this, namespace );
176			        if ( instance ) {
177			          // apply options & init
178			          instance.option( options );
179			          instance._init();
180			        } else {
181			          // initialize new instance
182			          instance = new PluginClass( this, options );
183			          $.data( this, namespace, instance );
184			        }
185			        return $(this);
186			      });
187
188			      if(!objects || objects.length > 1) {
189			      	return objects;
190			      } else {
191			      	return objects[0];
192			      }
193			    }
194			  };
195
196			}
197
198			// -------------------------- bridget -------------------------- //
199
200			/**
201			 * converts a Prototypical class into a proper jQuery plugin
202			 *   the class must have a ._init method
203			 * @param {String} namespace - plugin name, used in $().pluginName
204			 * @param {Function} PluginClass - constructor class
205			 */
206			$.bridget = function( namespace, PluginClass ) {
207			  addOptionMethod( PluginClass );
208			  bridge( namespace, PluginClass );
209			};
210
211			return $.bridget;
212
213		}
214
215	  	// get jquery from browser global
216	  	defineBridget( $ );
217
218	})( $ );
219
220
221	/*************************************************
222
223			BOOTSTRAP-SLIDER SOURCE CODE
224
225	**************************************************/
226
227	(function($) {
228
229		var ErrorMsgs = {
230			formatInvalidInputErrorMsg : function(input) {
231				return "Invalid input value '" + input + "' passed in";
232			},
233			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"
234		};
235
236		var SliderScale = {
237			linear: {
238				toValue: function(percentage) {
239					var rawValue = percentage/100 * (this.options.max - this.options.min);
240					var shouldAdjustWithBase = true;
241					if (this.options.ticks_positions.length > 0) {
242						var minv, maxv, minp, maxp = 0;
243						for (var i = 1; i < this.options.ticks_positions.length; i++) {
244							if (percentage <= this.options.ticks_positions[i]) {
245								minv = this.options.ticks[i-1];
246								minp = this.options.ticks_positions[i-1];
247								maxv = this.options.ticks[i];
248								maxp = this.options.ticks_positions[i];
249
250								break;
251							}
252						}
253						var partialPercentage = (percentage - minp) / (maxp - minp);
254						rawValue = minv + partialPercentage * (maxv - minv);
255						shouldAdjustWithBase = false;
256					}
257
258					var adjustment = shouldAdjustWithBase ? this.options.min : 0;
259					var value = adjustment + Math.round(rawValue / this.options.step) * this.options.step;
260					if (value < this.options.min) {
261						return this.options.min;
262					} else if (value > this.options.max) {
263						return this.options.max;
264					} else {
265						return value;
266					}
267				},
268				toPercentage: function(value) {
269					if (this.options.max === this.options.min) {
270						return 0;
271					}
272
273					if (this.options.ticks_positions.length > 0) {
274						var minv, maxv, minp, maxp = 0;
275						for (var i = 0; i < this.options.ticks.length; i++) {
276							if (value  <= this.options.ticks[i]) {
277								minv = (i > 0) ? this.options.ticks[i-1] : 0;
278								minp = (i > 0) ? this.options.ticks_positions[i-1] : 0;
279								maxv = this.options.ticks[i];
280								maxp = this.options.ticks_positions[i];
281
282								break;
283							}
284						}
285						if (i > 0) {
286							var partialPercentage = (value - minv) / (maxv - minv);
287							return minp + partialPercentage * (maxp - minp);
288						}
289					}
290
291					return 100 * (value - this.options.min) / (this.options.max - this.options.min);
292				}
293			},
294
295			logarithmic: {
296				/* Based on http://stackoverflow.com/questions/846221/logarithmic-slider */
297				toValue: function(percentage) {
298					var min = (this.options.min === 0) ? 0 : Math.log(this.options.min);
299					var max = Math.log(this.options.max);
300					var value = Math.exp(min + (max - min) * percentage / 100);
301					value = this.options.min + Math.round((value - this.options.min) / this.options.step) * this.options.step;
302					/* Rounding to the nearest step could exceed the min or
303					 * max, so clip to those values. */
304					if (value < this.options.min) {
305						return this.options.min;
306					} else if (value > this.options.max) {
307						return this.options.max;
308					} else {
309						return value;
310					}
311				},
312				toPercentage: function(value) {
313					if (this.options.max === this.options.min) {
314						return 0;
315					} else {
316						var max = Math.log(this.options.max);
317						var min = this.options.min === 0 ? 0 : Math.log(this.options.min);
318						var v = value === 0 ? 0 : Math.log(value);
319						return 100 * (v - min) / (max - min);
320					}
321				}
322			}
323		};
324
325
326		/*************************************************
327
328							CONSTRUCTOR
329
330		**************************************************/
331		Slider = function(element, options) {
332			createNewSlider.call(this, element, options);
333			return this;
334		};
335
336		function createNewSlider(element, options) {
337
338			/*
339				The internal state object is used to store data about the current 'state' of slider.
340				This includes values such as the `value`, `enabled`, etc...
341			*/
342			this._state = {
343				value: null,
344				enabled: null,
345				offset: null,
346				size: null,
347				percentage: null,
348				inDrag: false,
349				over: false
350			};
351
352			// The objects used to store the reference to the tick methods if ticks_tooltip is on
353			this.ticksCallbackMap = {};
354			this.handleCallbackMap = {};
355
356			if(typeof element === "string") {
357				this.element = document.querySelector(element);
358			} else if(element instanceof HTMLElement) {
359				this.element = element;
360			}
361
362			/*************************************************
363
364							Process Options
365
366			**************************************************/
367			options = options ? options : {};
368			var optionTypes = Object.keys(this.defaultOptions);
369
370			for(var i = 0; i < optionTypes.length; i++) {
371				var optName = optionTypes[i];
372
373				// First check if an option was passed in via the constructor
374				var val = options[optName];
375				// If no data attrib, then check data atrributes
376				val = (typeof val !== 'undefined') ? val : getDataAttrib(this.element, optName);
377				// Finally, if nothing was specified, use the defaults
378				val = (val !== null) ? val : this.defaultOptions[optName];
379
380				// Set all options on the instance of the Slider
381				if(!this.options) {
382					this.options = {};
383				}
384				this.options[optName] = val;
385			}
386
387			// Check options.rtl
388			if(this.options.rtl==='auto'){
389				this.options.rtl = window.getComputedStyle(this.element).direction==='rtl';
390			}
391
392			/*
393				Validate `tooltip_position` against 'orientation`
394				- if `tooltip_position` is incompatible with orientation, swith it to a default compatible with specified `orientation`
395					-- default for "vertical" -> "right", "left" if rtl
396					-- default for "horizontal" -> "top"
397			*/
398			if(this.options.orientation === "vertical" && (this.options.tooltip_position === "top" || this.options.tooltip_position === "bottom")) {
399				if(this.options.rtl) {
400					this.options.tooltip_position = "left";
401				}else{
402					this.options.tooltip_position = "right";
403				}
404			}
405			else if(this.options.orientation === "horizontal" && (this.options.tooltip_position === "left" || this.options.tooltip_position === "right")) {
406
407				this.options.tooltip_position	= "top";
408
409			}
410
411			function getDataAttrib(element, optName) {
vendor: 12,710 bytes, lines 412-764
412				var dataName = "data-slider-" + optName.replace(/_/g, '-');
413				var dataValString = element.getAttribute(dataName);
414
415				try {
416					return JSON.parse(dataValString);
417				}
418				catch(err) {
419					return dataValString;
420				}
421			}
422
423			/*************************************************
424
425							Create Markup
426
427			**************************************************/
428
429			var origWidth = this.element.style.width;
430			var updateSlider = false;
431			var parent = this.element.parentNode;
432			var sliderTrackSelection;
433			var sliderTrackLow, sliderTrackHigh;
434			var sliderMinHandle;
435			var sliderMaxHandle;
436
437			if (this.sliderElem) {
438				updateSlider = true;
439			} else {
440				/* Create elements needed for slider */
441				this.sliderElem = document.createElement("div");
442				this.sliderElem.className = "slider";
443
444				/* Create slider track elements */
445				var sliderTrack = document.createElement("div");
446				sliderTrack.className = "slider-track";
447
448				sliderTrackLow = document.createElement("div");
449				sliderTrackLow.className = "slider-track-low";
450
451				sliderTrackSelection = document.createElement("div");
452				sliderTrackSelection.className = "slider-selection";
453
454				sliderTrackHigh = document.createElement("div");
455				sliderTrackHigh.className = "slider-track-high";
456
457				sliderMinHandle = document.createElement("div");
458				sliderMinHandle.className = "slider-handle min-slider-handle";
459				sliderMinHandle.setAttribute('role', 'slider');
460				sliderMinHandle.setAttribute('aria-valuemin', this.options.min);
461				sliderMinHandle.setAttribute('aria-valuemax', this.options.max);
462
463				sliderMaxHandle = document.createElement("div");
464				sliderMaxHandle.className = "slider-handle max-slider-handle";
465				sliderMaxHandle.setAttribute('role', 'slider');
466				sliderMaxHandle.setAttribute('aria-valuemin', this.options.min);
467				sliderMaxHandle.setAttribute('aria-valuemax', this.options.max);
468
469				sliderTrack.appendChild(sliderTrackLow);
470				sliderTrack.appendChild(sliderTrackSelection);
471				sliderTrack.appendChild(sliderTrackHigh);
472
473				/* Create highlight range elements */
474				this.rangeHighlightElements = [];
475				if (Array.isArray(this.options.rangeHighlights) && this.options.rangeHighlights.length > 0) {
476					for (let j = 0; j < this.options.rangeHighlights.length; j++) {
477
478						var rangeHighlightElement = document.createElement("div");
479						rangeHighlightElement.className = "slider-rangeHighlight slider-selection";
480
481						this.rangeHighlightElements.push(rangeHighlightElement);
482						sliderTrack.appendChild(rangeHighlightElement);
483					}
484				}
485
486				/* Add aria-labelledby to handle's */
487				var isLabelledbyArray = Array.isArray(this.options.labelledby);
488				if (isLabelledbyArray && this.options.labelledby[0]) {
489					sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby[0]);
490				}
491				if (isLabelledbyArray && this.options.labelledby[1]) {
492					sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby[1]);
493				}
494				if (!isLabelledbyArray && this.options.labelledby) {
495					sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby);
496					sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby);
497				}
498
499				/* Create ticks */
500				this.ticks = [];
501				if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
502					this.ticksContainer = document.createElement('div');
503					this.ticksContainer.className = 'slider-tick-container';
504
505					for (i = 0; i < this.options.ticks.length; i++) {
506						var tick = document.createElement('div');
507						tick.className = 'slider-tick';
508						if (this.options.ticks_tooltip) {
509							var tickListenerReference = this._addTickListener();
510							var enterCallback = tickListenerReference.addMouseEnter(this, tick, i);
511							var leaveCallback = tickListenerReference.addMouseLeave(this, tick);
512
513							this.ticksCallbackMap[i] = {
514								mouseEnter: enterCallback,
515								mouseLeave: leaveCallback
516							};
517						}
518						this.ticks.push(tick);
519						this.ticksContainer.appendChild(tick);
520					}
521
522					sliderTrackSelection.className += " tick-slider-selection";
523				}
524
525				this.tickLabels = [];
526				if (Array.isArray(this.options.ticks_labels) && this.options.ticks_labels.length > 0) {
527					this.tickLabelContainer = document.createElement('div');
528					this.tickLabelContainer.className = 'slider-tick-label-container';
529
530					for (i = 0; i < this.options.ticks_labels.length; i++) {
531						var label = document.createElement('div');
532						var noTickPositionsSpecified = this.options.ticks_positions.length === 0;
533						var tickLabelsIndex = (this.options.reversed && noTickPositionsSpecified) ? (this.options.ticks_labels.length - (i + 1)) : i;
534						label.className = 'slider-tick-label';
535						label.innerHTML = this.options.ticks_labels[tickLabelsIndex];
536
537						this.tickLabels.push(label);
538						this.tickLabelContainer.appendChild(label);
539					}
540				}
541
542				const createAndAppendTooltipSubElements = function(tooltipElem) {
543					var arrow = document.createElement("div");
544					arrow.className = "tooltip-arrow";
545
546					var inner = document.createElement("div");
547					inner.className = "tooltip-inner";
548
549					tooltipElem.appendChild(arrow);
550					tooltipElem.appendChild(inner);
551				};
552
553				/* Create tooltip elements */
554				const sliderTooltip = document.createElement("div");
555				sliderTooltip.className = "tooltip tooltip-main";
556				sliderTooltip.setAttribute('role', 'presentation');
557				createAndAppendTooltipSubElements(sliderTooltip);
558
559				const sliderTooltipMin = document.createElement("div");
560				sliderTooltipMin.className = "tooltip tooltip-min";
561				sliderTooltipMin.setAttribute('role', 'presentation');
562				createAndAppendTooltipSubElements(sliderTooltipMin);
563
564				const sliderTooltipMax = document.createElement("div");
565				sliderTooltipMax.className = "tooltip tooltip-max";
566				sliderTooltipMax.setAttribute('role', 'presentation');
567				createAndAppendTooltipSubElements(sliderTooltipMax);
568
569				/* Append components to sliderElem */
570				this.sliderElem.appendChild(sliderTrack);
571				this.sliderElem.appendChild(sliderTooltip);
572				this.sliderElem.appendChild(sliderTooltipMin);
573				this.sliderElem.appendChild(sliderTooltipMax);
574
575				if (this.tickLabelContainer) {
576					this.sliderElem.appendChild(this.tickLabelContainer);
577				}
578				if (this.ticksContainer) {
579					this.sliderElem.appendChild(this.ticksContainer);
580				}
581
582				this.sliderElem.appendChild(sliderMinHandle);
583				this.sliderElem.appendChild(sliderMaxHandle);
584
585				/* Append slider element to parent container, right before the original <input> element */
586				parent.insertBefore(this.sliderElem, this.element);
587
588				/* Hide original <input> element */
589				this.element.style.display = "none";
590			}
591			/* If JQuery exists, cache JQ references */
592			if($) {
593				this.$element = $(this.element);
594				this.$sliderElem = $(this.sliderElem);
595			}
596
597			/*************************************************
598
599								Setup
600
601			**************************************************/
602			this.eventToCallbackMap = {};
603			this.sliderElem.id = this.options.id;
604
605			this.touchCapable = 'ontouchstart' in window || (window.DocumentTouch && document instanceof window.DocumentTouch);
606
607			this.touchX = 0;
608			this.touchY = 0;
609
610			this.tooltip = this.sliderElem.querySelector('.tooltip-main');
611			this.tooltipInner = this.tooltip.querySelector('.tooltip-inner');
612
613			this.tooltip_min = this.sliderElem.querySelector('.tooltip-min');
614			this.tooltipInner_min = this.tooltip_min.querySelector('.tooltip-inner');
615
616			this.tooltip_max = this.sliderElem.querySelector('.tooltip-max');
617			this.tooltipInner_max= this.tooltip_max.querySelector('.tooltip-inner');
618
619			if (SliderScale[this.options.scale]) {
620				this.options.scale = SliderScale[this.options.scale];
621			}
622
623			if (updateSlider === true) {
624				// Reset classes
625				this._removeClass(this.sliderElem, 'slider-horizontal');
626				this._removeClass(this.sliderElem, 'slider-vertical');
627				this._removeClass(this.sliderElem, 'slider-rtl');
628				this._removeClass(this.tooltip, 'hide');
629				this._removeClass(this.tooltip_min, 'hide');
630				this._removeClass(this.tooltip_max, 'hide');
631
632				// Undo existing inline styles for track
633				["left", "right", "top", "width", "height"].forEach(function(prop) {
634					this._removeProperty(this.trackLow, prop);
635					this._removeProperty(this.trackSelection, prop);
636					this._removeProperty(this.trackHigh, prop);
637				}, this);
638
639				// Undo inline styles on handles
640				[this.handle1, this.handle2].forEach(function(handle) {
641					this._removeProperty(handle, 'left');
642					this._removeProperty(handle, 'right');
643					this._removeProperty(handle, 'top');
644				}, this);
645
646				// Undo inline styles and classes on tooltips
647				[this.tooltip, this.tooltip_min, this.tooltip_max].forEach(function(tooltip) {
648					this._removeProperty(tooltip, 'left');
649					this._removeProperty(tooltip, 'right');
650					this._removeProperty(tooltip, 'top');
651					this._removeProperty(tooltip, 'margin-left');
652					this._removeProperty(tooltip, 'margin-right');
653					this._removeProperty(tooltip, 'margin-top');
654
655					this._removeClass(tooltip, 'right');
656					this._removeClass(tooltip, 'left');
657					this._removeClass(tooltip, 'top');
658				}, this);
659			}
660
661			if(this.options.orientation === 'vertical') {
662				this._addClass(this.sliderElem,'slider-vertical');
663				this.stylePos = 'top';
664				this.mousePos = 'pageY';
665				this.sizePos = 'offsetHeight';
666			} else {
667				this._addClass(this.sliderElem, 'slider-horizontal');
668				this.sliderElem.style.width = origWidth;
669				this.options.orientation = 'horizontal';
670				if(this.options.rtl) {
671					this.stylePos = 'right';
672				} else {
673					this.stylePos = 'left';
674				}
675				this.mousePos = 'pageX';
676				this.sizePos = 'offsetWidth';
677			}
678			// specific rtl class
679			if (this.options.rtl) {
680				this._addClass(this.sliderElem, 'slider-rtl');
681			}
682			this._setTooltipPosition();
683			/* In case ticks are specified, overwrite the min and max bounds */
684			if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
685					this.options.max = Math.max.apply(Math, this.options.ticks);
686					this.options.min = Math.min.apply(Math, this.options.ticks);
687			}
688
689			if (Array.isArray(this.options.value)) {
690				this.options.range = true;
691				this._state.value = this.options.value;
692			}
693			else if (this.options.range) {
694				// User wants a range, but value is not an array
695				this._state.value = [this.options.value, this.options.max];
696			}
697			else {
698				this._state.value = this.options.value;
699			}
700
701			this.trackLow = sliderTrackLow || this.trackLow;
702			this.trackSelection = sliderTrackSelection || this.trackSelection;
703			this.trackHigh = sliderTrackHigh || this.trackHigh;
704
705			if (this.options.selection === 'none') {
706				this._addClass(this.trackLow, 'hide');
707				this._addClass(this.trackSelection, 'hide');
708				this._addClass(this.trackHigh, 'hide');
709			}
710
711			else if (this.options.selection === 'after' || this.options.selection === 'before') {
712				this._removeClass(this.trackLow, 'hide');
713				this._removeClass(this.trackSelection, 'hide');
714				this._removeClass(this.trackHigh, 'hide');
715			}
716
717			this.handle1 = sliderMinHandle || this.handle1;
718			this.handle2 = sliderMaxHandle || this.handle2;
719
720			if (updateSlider === true) {
721				// Reset classes
722				this._removeClass(this.handle1, 'round triangle');
723				this._removeClass(this.handle2, 'round triangle hide');
724
725				for (i = 0; i < this.ticks.length; i++) {
726					this._removeClass(this.ticks[i], 'round triangle hide');
727				}
728			}
729
730			var availableHandleModifiers = ['round', 'triangle', 'custom'];
731			var isValidHandleType = availableHandleModifiers.indexOf(this.options.handle) !== -1;
732			if (isValidHandleType) {
733				this._addClass(this.handle1, this.options.handle);
734				this._addClass(this.handle2, this.options.handle);
735
736				for (i = 0; i < this.ticks.length; i++) {
737					this._addClass(this.ticks[i], this.options.handle);
738				}
739			}
740
741			this._state.offset = this._offset(this.sliderElem);
742			this._state.size = this.sliderElem[this.sizePos];
743			this.setValue(this._state.value);
744
745			/******************************************
746
747						Bind Event Listeners
748
749			******************************************/
750
751			// Bind keyboard handlers
752			this.handle1Keydown = this._keydown.bind(this, 0);
753			this.handle1.addEventListener("keydown", this.handle1Keydown, false);
754
755			this.handle2Keydown = this._keydown.bind(this, 1);
756			this.handle2.addEventListener("keydown", this.handle2Keydown, false);
757
758			this.mousedown = this._mousedown.bind(this);
759			this.touchstart = this._touchstart.bind(this);
760			this.touchmove = this._touchmove.bind(this);
761
762			if (this.touchCapable) {
763				// Test for passive event support
764				let supportsPassive = false;
765				try {
766					let opts = Object.defineProperty({}, 'passive', {
767						get: function() {
768							supportsPassive = true;
769						}
770					});
771					window.addEventListener("test", null, opts);
772				} catch (e) {}
773				// Use our detect's results. passive applied if supported, capture will be false either way.
774				let eventOptions = supportsPassive ? { passive: true } : false;
775				// Bind touch handlers
776				this.sliderElem.addEventListener("touchstart", this.touchstart, eventOptions);
777				this.sliderElem.addEventListener("touchmove", this.touchmove, eventOptions);
778			}
779			this.sliderElem.addEventListener("mousedown", this.mousedown, false);
780
781			// Bind window handlers
782			this.resize = this._resize.bind(this);
783			window.addEventListener("resize", this.resize, false);
784
785
786			// Bind tooltip-related handlers
787			if(this.options.tooltip === 'hide') {
788				this._addClass(this.tooltip, 'hide');
789				this._addClass(this.tooltip_min, 'hide');
790				this._addClass(this.tooltip_max, 'hide');
791			}
792			else if(this.options.tooltip === 'always') {
793				this._showTooltip();
794				this._alwaysShowTooltip = true;
795			}
796			else {
797				this.showTooltip = this._showTooltip.bind(this);
798				this.hideTooltip = this._hideTooltip.bind(this);
799
800				if (this.options.ticks_tooltip) {
801					var callbackHandle = this._addTickListener();
802					//create handle1 listeners and store references in map
803					var mouseEnter = callbackHandle.addMouseEnter(this, this.handle1);
804					var mouseLeave = callbackHandle.addMouseLeave(this, this.handle1);
805					this.handleCallbackMap.handle1 = {
806						mouseEnter: mouseEnter,
807						mouseLeave: mouseLeave
808					};
809					//create handle2 listeners and store references in map
810					mouseEnter = callbackHandle.addMouseEnter(this, this.handle2);
811					mouseLeave = callbackHandle.addMouseLeave(this, this.handle2);
812					this.handleCallbackMap.handle2 = {
813						mouseEnter: mouseEnter,
814						mouseLeave: mouseLeave
815					};
816				} else {
817					this.sliderElem.addEventListener("mouseenter", this.showTooltip, false);
818					this.sliderElem.addEventListener("mouseleave", this.hideTooltip, false);
819				}
820
821				this.handle1.addEventListener("focus", this.showTooltip, false);
822				this.handle1.addEventListener("blur", this.hideTooltip, false);
823
824				this.handle2.addEventListener("focus", this.showTooltip, false);
825				this.handle2.addEventListener("blur", this.hideTooltip, false);
826			}
827
828			if(this.options.enabled) {
829				this.enable();
830			} else {
831				this.disable();
832			}
833
834		}
835
836		/*************************************************
837
838					INSTANCE PROPERTIES/METHODS
839
840		- Any methods bound to the prototype are considered
841		part of the plugin's `public` interface
842
843		**************************************************/
844		Slider.prototype = {
845			_init: function() {}, // NOTE: Must exist to support bridget
846
847			constructor: Slider,
848
849			defaultOptions: {
850				id: "",
851				min: 0,
852				max: 10,
853				step: 1,
854				precision: 0,
855				orientation: 'horizontal',
856				value: 5,
857				range: false,
858				selection: 'before',
859				tooltip: 'show',
860				tooltip_split: false,
861				handle: 'round',
862				reversed: false,
863				rtl: 'auto',
864				enabled: true,
865				formatter: function(val) {
866					if (Array.isArray(val)) {
867						return val[0] + " : " + val[1];
868					} else {
869						return val;
870					}
871				},
872				natural_arrow_keys: false,
873				ticks: [],
874				ticks_positions: [],
875				ticks_labels: [],
876				ticks_snap_bounds: 0,
877				ticks_tooltip: false,
878				scale: 'linear',
879				focus: false,
880				tooltip_position: null,
881				labelledby: null,
882				rangeHighlights: []
883			},
884
885			getElement: function() {
886				return this.sliderElem;
887			},
888
889			getValue: function() {
890				if (this.options.range) {
891					return this._state.value;
892				}
893				else {
894					return this._state.value[0];
895				}
896			},
897
898			setValue: function(val, triggerSlideEvent, triggerChangeEvent) {
899				if (!val) {
900					val = 0;
901				}
902				var oldValue = this.getValue();
903				this._state.value = this._validateInputValue(val);
904				var applyPrecision = this._applyPrecision.bind(this);
905
906				if (this.options.range) {
907					this._state.value[0] = applyPrecision(this._state.value[0]);
908					this._state.value[1] = applyPrecision(this._state.value[1]);
909
910					this._state.value[0] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[0]));
911					this._state.value[1] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[1]));
912				}
913				else {
914					this._state.value = applyPrecision(this._state.value);
915					this._state.value = [ Math.max(this.options.min, Math.min(this.options.max, this._state.value))];
916					this._addClass(this.handle2, 'hide');
917					if (this.options.selection === 'after') {
918						this._state.value[1] = this.options.max;
919					} else {
920						this._state.value[1] = this.options.min;
921					}
922				}
923
924				if (this.options.max > this.options.min) {
925					this._state.percentage = [
926						this._toPercentage(this._state.value[0]),
927						this._toPercentage(this._state.value[1]),
928						this.options.step * 100 / (this.options.max - this.options.min)
929					];
930				} else {
931					this._state.percentage = [0, 0, 100];
932				}
933
934				this._layout();
935				var newValue = this.options.range ? this._state.value : this._state.value[0];
936
937				this._setDataVal(newValue);
938				if(triggerSlideEvent === true) {
939					this._trigger('slide', newValue);
940				}
941				if( (oldValue !== newValue) && (triggerChangeEvent === true) ) {
942					this._trigger('change', {
943						oldValue: oldValue,
944						newValue: newValue
945					});
946				}
947
948				return this;
949			},
950
951			destroy: function(){
952				// Remove event handlers on slider elements
953				this._removeSliderEventHandlers();
954
955				// Remove the slider from the DOM
956				this.sliderElem.parentNode.removeChild(this.sliderElem);
957				/* Show original <input> element */
958				this.element.style.display = "";
959
960				// Clear out custom event bindings
961				this._cleanUpEventCallbacksMap();
962
963				// Remove data values
964				this.element.removeAttribute("data");
965
966				// Remove JQuery handlers/data
967				if($) {
968					this._unbindJQueryEventHandlers();
969					this.$element.removeData('slider');
970				}
971			},
972
973			disable: function() {
974				this._state.enabled = false;
975				this.handle1.removeAttribute("tabindex");
976				this.handle2.removeAttribute("tabindex");
977				this._addClass(this.sliderElem, 'slider-disabled');
978				this._trigger('slideDisabled');
979
980				return this;
981			},
982
983			enable: function() {
984				this._state.enabled = true;
985				this.handle1.setAttribute("tabindex", 0);
986				this.handle2.setAttribute("tabindex", 0);
987				this._removeClass(this.sliderElem, 'slider-disabled');
988				this._trigger('slideEnabled');
989
990				return this;
991			},
992
993			toggle: function() {
994				if(this._state.enabled) {
995					this.disable();
996				} else {
997					this.enable();
998				}
999				return this;
1000			},
1001
1002			isEnabled: function() {
1003				return this._state.enabled;
1004			},
1005
1006			on: function(evt, callback) {
1007				this._bindNonQueryEventHandler(evt, callback);
1008				return this;
1009			},
1010
1011			off: function(evt, callback) {
1012				if($) {
1013					this.$element.off(evt, callback);
1014					this.$sliderElem.off(evt, callback);
1015				} else {
1016					this._unbindNonQueryEventHandler(evt, callback);
1017				}
1018			},
1019
1020			getAttribute: function(attribute) {
1021				if(attribute) {
1022					return this.options[attribute];
1023				} else {
1024					return this.options;
1025				}
1026			},
1027
1028			setAttribute: function(attribute, value) {
1029				this.options[attribute] = value;
1030				return this;
1031			},
1032
1033			refresh: function() {
1034				this._removeSliderEventHandlers();
1035				createNewSlider.call(this, this.element, this.options);
1036				if($) {
1037					// Bind new instance of slider to the element
1038					$.data(this.element, 'slider', this);
1039				}
1040				return this;
1041			},
1042
1043			relayout: function() {
1044				this._resize();
1045				this._layout();
1046				return this;
1047			},
1048
1049			/******************************+
1050
1051						HELPERS
1052
1053			- Any method that is not part of the public interface.
1054			- Place it underneath this comment block and write its signature like so:
1055
1056				_fnName : function() {...}
1057
1058			********************************/
1059			_removeSliderEventHandlers: function() {
1060				// Remove keydown event listeners
1061				this.handle1.removeEventListener("keydown", this.handle1Keydown, false);
1062				this.handle2.removeEventListener("keydown", this.handle2Keydown, false);
1063
1064				//remove the listeners from the ticks and handles if they had their own listeners
1065				if (this.options.ticks_tooltip) {
1066					var ticks = this.ticksContainer.getElementsByClassName('slider-tick');
1067					for(var i = 0; i < ticks.length; i++ ){
1068						ticks[i].removeEventListener('mouseenter', this.ticksCallbackMap[i].mouseEnter, false);
1069						ticks[i].removeEventListener('mouseleave', this.ticksCallbackMap[i].mouseLeave, false);
1070					}
1071					this.handle1.removeEventListener('mouseenter', this.handleCallbackMap.handle1.mouseEnter, false);
1072					this.handle2.removeEventListener('mouseenter', this.handleCallbackMap.handle2.mouseEnter, false);
1073					this.handle1.removeEventListener('mouseleave', this.handleCallbackMap.handle1.mouseLeave, false);
1074					this.handle2.removeEventListener('mouseleave', this.handleCallbackMap.handle2.mouseLeave, false);
1075				}
1076
1077				this.handleCallbackMap = null;
1078				this.ticksCallbackMap = null;
1079
1080				if (this.showTooltip) {
1081					this.handle1.removeEventListener("focus", this.showTooltip, false);
1082					this.handle2.removeEventListener("focus", this.showTooltip, false);
1083				}
1084				if (this.hideTooltip) {
1085					this.handle1.removeEventListener("blur", this.hideTooltip, false);
1086					this.handle2.removeEventListener("blur", this.hideTooltip, false);
1087				}
1088
1089				// Remove event listeners from sliderElem
1090				if (this.showTooltip) {
1091					this.sliderElem.removeEventListener("mouseenter", this.showTooltip, false);
1092				}
1093				if (this.hideTooltip) {
1094					this.sliderElem.removeEventListener("mouseleave", this.hideTooltip, false);
1095				}
1096				this.sliderElem.removeEventListener("touchstart", this.touchstart, false);
1097				this.sliderElem.removeEventListener("touchmove", this.touchmove, false);
1098				this.sliderElem.removeEventListener("mousedown", this.mousedown, false);
1099
1100				// Remove window event listener
1101				window.removeEventListener("resize", this.resize, false);
1102			},
1103			_bindNonQueryEventHandler: function(evt, callback) {
1104				if(this.eventToCallbackMap[evt] === undefined) {
1105					this.eventToCallbackMap[evt] = [];
1106				}
1107				this.eventToCallbackMap[evt].push(callback);
1108			},
1109			_unbindNonQueryEventHandler: function(evt, callback) {
1110				var callbacks = this.eventToCallbackMap[evt];
1111				if(callbacks !== undefined) {
1112					for (var i = 0; i < callbacks.length; i++) {
1113						if (callbacks[i] === callback) {
1114							callbacks.splice(i, 1);
1115							break;
1116						}
1117					}
1118				}
1119			},
1120			_cleanUpEventCallbacksMap: function() {
1121				var eventNames = Object.keys(this.eventToCallbackMap);
1122				for(var i = 0; i < eventNames.length; i++) {
1123					var eventName = eventNames[i];
1124					delete this.eventToCallbackMap[eventName];
1125				}
1126			},
1127			_showTooltip: function() {
1128				if (this.options.tooltip_split === false ){
1129					this._addClass(this.tooltip, 'in');
1130					this.tooltip_min.style.display = 'none';
1131					this.tooltip_max.style.display = 'none';
1132			    } else {
1133					this._addClass(this.tooltip_min, 'in');
1134					this._addClass(this.tooltip_max, 'in');
1135					this.tooltip.style.display = 'none';
1136				}
1137				this._state.over = true;
1138			},
1139			_hideTooltip: function() {
1140				if (this._state.inDrag === false && this.alwaysShowTooltip !== true) {
1141					this._removeClass(this.tooltip, 'in');
1142					this._removeClass(this.tooltip_min, 'in');
1143					this._removeClass(this.tooltip_max, 'in');
1144				}
1145				this._state.over = false;
1146			},
1147			_setToolTipOnMouseOver: function _setToolTipOnMouseOver(tempState){
1148				var formattedTooltipVal = this.options.formatter(!tempState ? this._state.value[0]: tempState.value[0]);
1149				var positionPercentages = !tempState ? getPositionPercentages(this._state, this.options.reversed) : getPositionPercentages(tempState, this.options.reversed);
1150				this._setText(this.tooltipInner, formattedTooltipVal);
1151
1152				this.tooltip.style[this.stylePos] = `${positionPercentages[0]}%`;
1153				if (this.options.orientation === 'vertical') {
1154					this._css(this.tooltip, `margin-${this.stylePos}`, `${-this.tooltip.offsetHeight / 2}px`);
1155				} else {
1156					this._css(this.tooltip, `margin-${this.stylePos}`, `${-this.tooltip.offsetWidth / 2}px`);
1157				}
1158
1159				function getPositionPercentages(state, reversed){
1160					if (reversed) {
1161						return [100 - state.percentage[0], this.options.range ? 100 - state.percentage[1] : state.percentage[1]];
1162					}
1163					return [state.percentage[0], state.percentage[1]];
1164				}
1165			},
1166			_addTickListener: function _addTickListener() {
1167				return {
1168					addMouseEnter: function(reference, tick, index){
1169						var enter = function(){
1170							var tempState = reference._state;
1171							var idString = index >= 0 ? index : this.attributes['aria-valuenow'].value;
1172							var hoverIndex = parseInt(idString, 10);
1173							tempState.value[0] = hoverIndex;
1174							tempState.percentage[0] = reference.options.ticks_positions[hoverIndex];
1175							reference._setToolTipOnMouseOver(tempState);
1176							reference._showTooltip();
1177						};
1178						tick.addEventListener("mouseenter", enter, false);
1179						return enter;
1180					},
1181					addMouseLeave: function(reference, tick){
1182						var leave = function(){
1183							reference._hideTooltip();
1184						};
1185						tick.addEventListener("mouseleave", leave, false);
1186						return leave;
1187					}
1188				};
1189			},
1190			_layout: function() {
1191				var positionPercentages;
1192
1193				if(this.options.reversed) {
1194					positionPercentages = [ 100 - this._state.percentage[0], this.options.range ? 100 - this._state.percentage[1] : this._state.percentage[1]];
1195				}
1196				else {
1197					positionPercentages = [ this._state.percentage[0], this._state.percentage[1] ];
1198				}
1199
1200				this.handle1.style[this.stylePos] = `${positionPercentages[0]}%`;
1201				this.handle1.setAttribute('aria-valuenow', this._state.value[0]);
1202				if (isNaN(this.options.formatter(this._state.value[0])) ) {
1203					this.handle1.setAttribute('aria-valuetext', this.options.formatter(this._state.value[0]));
1204				}
1205
1206				this.handle2.style[this.stylePos] =`${positionPercentages[1]}%`;
1207				this.handle2.setAttribute('aria-valuenow', this._state.value[1]);
1208				if (isNaN(this.options.formatter(this._state.value[1])) ) {
1209					this.handle2.setAttribute('aria-valuetext', this.options.formatter(this._state.value[1]));
1210				}
1211
1212				/* Position highlight range elements */
1213				if (this.rangeHighlightElements.length > 0 && Array.isArray(this.options.rangeHighlights) && this.options.rangeHighlights.length > 0) {
1214					for (let i = 0; i < this.options.rangeHighlights.length; i++) {
1215						var startPercent = this._toPercentage(this.options.rangeHighlights[i].start);
1216						var endPercent = this._toPercentage(this.options.rangeHighlights[i].end);
1217
1218						if (this.options.reversed) {
1219							var sp = 100-endPercent;
1220							endPercent = 100-startPercent;
1221							startPercent = sp;
1222						}
1223
1224						var currentRange = this._createHighlightRange(startPercent, endPercent);
1225
1226						if (currentRange) {
1227							if (this.options.orientation === 'vertical') {
1228								this.rangeHighlightElements[i].style.top = `${currentRange.start}%`;
1229								this.rangeHighlightElements[i].style.height = `${currentRange.size}%`;
1230							} else {
1231								if(this.options.rtl){
1232									this.rangeHighlightElements[i].style.right = `${currentRange.start}%`;
1233								} else {
1234									this.rangeHighlightElements[i].style.left = `${currentRange.start}%`;
1235								}
1236								this.rangeHighlightElements[i].style.width = `${currentRange.size}%`;
1237							}
1238						} else {
1239							this.rangeHighlightElements[i].style.display = "none";
1240						}
1241					}
1242				}
1243
1244				/* Position ticks and labels */
1245				if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
1246
1247					var styleSize = this.options.orientation === 'vertical' ? 'height' : 'width';
1248					var styleMargin;
1249					if( this.options.orientation === 'vertical' ){
1250						styleMargin='marginTop';
1251					}else {
1252						if( this.options.rtl ){
1253							styleMargin='marginRight';
1254						} else {
1255							styleMargin='marginLeft';
1256						}
1257					}
1258					var labelSize = this._state.size / (this.options.ticks.length - 1);
1259
1260					if (this.tickLabelContainer) {
1261						var extraMargin = 0;
1262						if (this.options.ticks_positions.length === 0) {
1263							if (this.options.orientation !== 'vertical') {
1264								this.tickLabelContainer.style[styleMargin] = `${ -labelSize/2 }px`;
1265							}
1266
1267							extraMargin = this.tickLabelContainer.offsetHeight;
1268						} else {
1269							/* Chidren are position absolute, calculate height by finding the max offsetHeight of a child */
1270							for (i = 0 ; i < this.tickLabelContainer.childNodes.length; i++) {
1271								if (this.tickLabelContainer.childNodes[i].offsetHeight > extraMargin) {
1272									extraMargin = this.tickLabelContainer.childNodes[i].offsetHeight;
1273								}
1274							}
1275						}
1276						if (this.options.orientation === 'horizontal') {
1277							this.sliderElem.style.marginBottom = `${ extraMargin }px`;
1278						}
1279					}
1280					for (var i = 0; i < this.options.ticks.length; i++) {
1281
1282						var percentage = this.options.ticks_positions[i] || this._toPercentage(this.options.ticks[i]);
1283
1284						if (this.options.reversed) {
1285							percentage = 100 - percentage;
1286						}
1287
1288						this.ticks[i].style[this.stylePos] = `${ percentage }%`;
1289
1290						/* Set class labels to denote whether ticks are in the selection */
1291						this._removeClass(this.ticks[i], 'in-selection');
1292						if (!this.options.range) {
1293							if (this.options.selection === 'after' && percentage >= positionPercentages[0]){
1294								this._addClass(this.ticks[i], 'in-selection');
1295							} else if (this.options.selection === 'before' && percentage <= positionPercentages[0]) {
1296								this._addClass(this.ticks[i], 'in-selection');
1297							}
1298						} else if (percentage >= positionPercentages[0] && percentage <= positionPercentages[1]) {
1299							this._addClass(this.ticks[i], 'in-selection');
1300						}
1301
1302						if (this.tickLabels[i]) {
1303							this.tickLabels[i].style[styleSize] = `${labelSize}px`;
1304
1305							if (this.options.orientation !== 'vertical' && this.options.ticks_positions[i] !== undefined) {
1306								this.tickLabels[i].style.position = 'absolute';
1307								this.tickLabels[i].style[this.stylePos] = `${percentage}%`;
1308								this.tickLabels[i].style[styleMargin] = -labelSize/2 + 'px';
1309							} else if (this.options.orientation === 'vertical') {
1310								if(this.options.rtl){
1311									this.tickLabels[i].style['marginRight'] = `${this.sliderElem.offsetWidth }px`;
1312								}else{
1313									this.tickLabels[i].style['marginLeft'] = `${this.sliderElem.offsetWidth }px`;
1314								}
1315								this.tickLabelContainer.style[styleMargin] = this.sliderElem.offsetWidth / 2 * -1 + 'px';
1316							}
1317						}
1318					}
1319				}
1320
1321				var formattedTooltipVal;
1322
1323				if (this.options.range) {
1324					formattedTooltipVal = this.options.formatter(this._state.value);
1325					this._setText(this.tooltipInner, formattedTooltipVal);
1326					this.tooltip.style[this.stylePos] = `${ (positionPercentages[1] + positionPercentages[0])/2 }%`;
1327
1328					if (this.options.orientation === 'vertical') {
1329						this._css(this.tooltip, `margin-${this.stylePos}`, `${ -this.tooltip.offsetHeight / 2 }px`);
1330					} else {
1331						this._css(this.tooltip, `margin-${this.stylePos}`, `${ -this.tooltip.offsetWidth / 2 }px`);
1332					}
1333
1334					var innerTooltipMinText = this.options.formatter(this._state.value[0]);
1335					this._setText(this.tooltipInner_min, innerTooltipMinText);
1336
1337					var innerTooltipMaxText = this.options.formatter(this._state.value[1]);
1338					this._setText(this.tooltipInner_max, innerTooltipMaxText);
1339
1340					this.tooltip_min.style[this.stylePos] = `${ positionPercentages[0] }%`;
1341
1342					if (this.options.orientation === 'vertical') {
1343						this._css(this.tooltip_min, `margin-${this.stylePos}`, `${ -this.tooltip_min.offsetHeight / 2  }px`);
1344					} else {
1345						this._css(this.tooltip_min, `margin-${this.stylePos}`, `${ -this.tooltip_min.offsetWidth / 2  }px`);
1346					}
1347
1348					this.tooltip_max.style[this.stylePos] = `${ positionPercentages[1] }%`;
1349
1350					if (this.options.orientation === 'vertical') {
1351						this._css(this.tooltip_max, `margin-${this.stylePos}`, `${ -this.tooltip_max.offsetHeight / 2 }px`);
1352					} else {
1353						this._css(this.tooltip_max, `margin-${this.stylePos}`, `${ -this.tooltip_max.offsetWidth / 2 }px`);
1354					}
1355				} else {
1356					formattedTooltipVal = this.options.formatter(this._state.value[0]);
1357					this._setText(this.tooltipInner, formattedTooltipVal);
1358
1359					this.tooltip.style[this.stylePos] = `${ positionPercentages[0] }%`;
1360					if (this.options.orientation === 'vertical') {
1361						this._css(this.tooltip, `margin-${this.stylePos}`, `${ -this.tooltip.offsetHeight / 2 }px`);
1362					} else {
1363						this._css(this.tooltip, `margin-${this.stylePos}`, `${ -this.tooltip.offsetWidth / 2 }px`);
1364					}
1365				}
1366
1367				if (this.options.orientation === 'vertical') {
1368					this.trackLow.style.top = '0';
1369					this.trackLow.style.height = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
1370
1371					this.trackSelection.style.top = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
1372					this.trackSelection.style.height = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%';
1373
1374					this.trackHigh.style.bottom = '0';
1375					this.trackHigh.style.height = (100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1])) +'%';
1376				}
1377				else {
1378					if(this.stylePos==='right') {
1379						this.trackLow.style.right = '0';
1380					} else {
1381						this.trackLow.style.left = '0';
1382					}
1383					this.trackLow.style.width = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
1384
1385					if(this.stylePos==='right') {
1386						this.trackSelection.style.right = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
1387					} else {
1388						this.trackSelection.style.left = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
1389					}
1390					this.trackSelection.style.width = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%';
1391
1392					if(this.stylePos==='right') {
1393						this.trackHigh.style.left = '0';
1394					} else {
1395						this.trackHigh.style.right = '0';
1396					}
1397					this.trackHigh.style.width = (100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1])) +'%';
1398
1399					var offset_min = this.tooltip_min.getBoundingClientRect();
1400					var offset_max = this.tooltip_max.getBoundingClientRect();
1401
1402					if (this.options.tooltip_position === 'bottom') {
1403						if (offset_min.right > offset_max.left) {
1404							this._removeClass(this.tooltip_max, 'bottom');
1405							this._addClass(this.tooltip_max, 'top');
1406							this.tooltip_max.style.top = '';
1407							this.tooltip_max.style.bottom = 22 + 'px';
1408						} else {
1409							this._removeClass(this.tooltip_max, 'top');
1410							this._addClass(this.tooltip_max, 'bottom');
1411							this.tooltip_max.style.top = this.tooltip_min.style.top;
1412							this.tooltip_max.style.bottom = '';
1413						}
1414					} else {
1415						if (offset_min.right > offset_max.left) {
1416							this._removeClass(this.tooltip_max, 'top');
1417							this._addClass(this.tooltip_max, 'bottom');
1418							this.tooltip_max.style.top = 18 + 'px';
1419						} else {
1420							this._removeClass(this.tooltip_max, 'bottom');
1421							this._addClass(this.tooltip_max, 'top');
1422							this.tooltip_max.style.top = this.tooltip_min.style.top;
1423						}
1424					}
1425				}
1426			},
1427			_createHighlightRange: function (start, end) {
1428				if (this._isHighlightRange(start, end)) {
1429					if (start > end) {
1430						return {'start': end, 'size': start - end};
1431					}
1432					return {'start': start, 'size': end - start};
1433				}
1434				return null;
1435			},
1436			_isHighlightRange: function (start, end) {
1437				if (0 <= start && start <= 100 && 0 <= end && end <= 100) {
1438					return true;
1439				}
1440				else {
1441					return false;
1442				}
1443			},
1444			_resize: function (ev) {
1445				/*jshint unused:false*/
1446				this._state.offset = this._offset(this.sliderElem);
1447				this._state.size = this.sliderElem[this.sizePos];
1448				this._layout();
1449			},
1450			_removeProperty: function(element, prop) {
1451				if (element.style.removeProperty) {
1452				    element.style.removeProperty(prop);
1453				} else {
1454				    element.style.removeAttribute(prop);
1455				}
1456			},
1457			_mousedown: function(ev) {
1458				if(!this._state.enabled) {
1459					return false;
1460				}
1461
1462				this._state.offset = this._offset(this.sliderElem);
1463				this._state.size = this.sliderElem[this.sizePos];
1464
1465				var percentage = this._getPercentage(ev);
1466
1467				if (this.options.range) {
1468					var diff1 = Math.abs(this._state.percentage[0] - percentage);
1469					var diff2 = Math.abs(this._state.percentage[1] - percentage);
1470					this._state.dragged = (diff1 < diff2) ? 0 : 1;
1471					this._adjustPercentageForRangeSliders(percentage);
1472				} else {
1473					this._state.dragged = 0;
1474				}
1475
1476				this._state.percentage[this._state.dragged] = percentage;
1477				this._layout();
1478
1479				if (this.touchCapable) {
1480					document.removeEventListener("touchmove", this.mousemove, false);
1481					document.removeEventListener("touchend", this.mouseup, false);
1482				}
1483
1484				if(this.mousemove){
1485					document.removeEventListener("mousemove", this.mousemove, false);
1486				}
1487				if(this.mouseup){
1488					document.removeEventListener("mouseup", this.mouseup, false);
1489				}
1490
1491				this.mousemove = this._mousemove.bind(this);
1492				this.mouseup = this._mouseup.bind(this);
1493
1494				if (this.touchCapable) {
1495					// Touch: Bind touch events:
1496					document.addEventListener("touchmove", this.mousemove, false);
1497					document.addEventListener("touchend", this.mouseup, false);
1498				}
1499				// Bind mouse events:
1500				document.addEventListener("mousemove", this.mousemove, false);
1501				document.addEventListener("mouseup", this.mouseup, false);
1502
1503				this._state.inDrag = true;
1504				var newValue = this._calculateValue();
1505
1506				this._trigger('slideStart', newValue);
1507
1508				this._setDataVal(newValue);
1509				this.setValue(newValue, false, true);
1510
1511				ev.returnValue = false;
1512
1513				if (this.options.focus) {
1514					this._triggerFocusOnHandle(this._state.dragged);
1515				}
1516
1517				return true;
1518			},
1519			_touchstart: function(ev) {
1520				if (ev.changedTouches === undefined) {
1521					this._mousedown(ev);
1522					return;
1523				}
1524
1525				var touch = ev.changedTouches[0];
1526				this.touchX = touch.pageX;
1527				this.touchY = touch.pageY;
1528			},
1529			_triggerFocusOnHandle: function(handleIdx) {
1530				if(handleIdx === 0) {
1531					this.handle1.focus();
1532				}
1533				if(handleIdx === 1) {
1534					this.handle2.focus();
1535				}
1536			},
1537			_keydown: function(handleIdx, ev) {
1538				if(!this._state.enabled) {
1539					return false;
1540				}
1541
1542				var dir;
1543				switch (ev.keyCode) {
1544					case 37: // left
1545					case 40: // down
1546						dir = -1;
1547						break;
1548					case 39: // right
1549					case 38: // up
1550						dir = 1;
1551						break;
1552				}
1553				if (!dir) {
1554					return;
1555				}
1556
1557				// use natural arrow keys instead of from min to max
1558				if (this.options.natural_arrow_keys) {
1559					var ifVerticalAndNotReversed = (this.options.orientation === 'vertical' && !this.options.reversed);
1560					var ifHorizontalAndReversed = (this.options.orientation === 'horizontal' && this.options.reversed); // @todo control with rtl
1561
1562					if (ifVerticalAndNotReversed || ifHorizontalAndReversed) {
1563						dir = -dir;
1564					}
1565				}
1566
1567				var val = this._state.value[handleIdx] + dir * this.options.step;
1568				const percentage = (val / this.options.max) * 100;
1569				this._state.keyCtrl = handleIdx;
1570				if (this.options.range) {
1571					this._adjustPercentageForRangeSliders(percentage);
1572					const val1 = (!this._state.keyCtrl) ? val : this._state.value[0];
1573					const val2 = (this._state.keyCtrl) ? val : this._state.value[1];
1574					val = [ val1, val2];
1575				}
1576
1577				this._trigger('slideStart', val);
1578				this._setDataVal(val);
1579				this.setValue(val, true, true);
1580
1581				this._setDataVal(val);
1582				this._trigger('slideStop', val);
1583				this._layout();
1584
1585				this._pauseEvent(ev);
1586				delete this._state.keyCtrl;
1587
1588				return false;
1589			},
1590			_pauseEvent: function(ev) {
1591				if(ev.stopPropagation) {
1592					ev.stopPropagation();
1593				}
1594				if(ev.preventDefault) {
1595					ev.preventDefault();
1596				}
1597				ev.cancelBubble=true;
1598				ev.returnValue=false;
1599			},
1600			_mousemove: function(ev) {
1601				if(!this._state.enabled) {
1602					return false;
1603				}
1604
1605				var percentage = this._getPercentage(ev);
1606				this._adjustPercentageForRangeSliders(percentage);
1607				this._state.percentage[this._state.dragged] = percentage;
1608				this._layout();
1609
1610				var val = this._calculateValue(true);
1611				this.setValue(val, true, true);
1612
1613				return false;
1614			},
1615			_touchmove: function(ev) {
1616				if (ev.changedTouches === undefined) {
1617					return;
1618				}
1619
1620				var touch = ev.changedTouches[0];
1621
1622				var xDiff = touch.pageX - this.touchX;
1623				var yDiff = touch.pageY - this.touchY;
1624
1625				if (!this._state.inDrag) {
1626					// Vertical Slider
1627					if (this.options.orientation === 'vertical' && (xDiff <= 5 && xDiff >= -5) && (yDiff >=15 || yDiff <= -15)) {
1628						this._mousedown(ev);
1629					}
1630					// Horizontal slider.
1631					else if ((yDiff <= 5 && yDiff >= -5) && (xDiff >= 15 || xDiff <= -15)) {
1632						this._mousedown(ev);
1633					}
1634				}
1635			},
1636			_adjustPercentageForRangeSliders: function(percentage) {
1637				if (this.options.range) {
1638					var precision = this._getNumDigitsAfterDecimalPlace(percentage);
1639					precision = precision ? precision - 1 : 0;
1640					var percentageWithAdjustedPrecision = this._applyToFixedAndParseFloat(percentage, precision);
1641					if (this._state.dragged === 0 && this._applyToFixedAndParseFloat(this._state.percentage[1], precision) < percentageWithAdjustedPrecision) {
1642						this._state.percentage[0] = this._state.percentage[1];
1643						this._state.dragged = 1;
1644					} else if (this._state.dragged === 1 && this._applyToFixedAndParseFloat(this._state.percentage[0], precision) > percentageWithAdjustedPrecision) {
1645						this._state.percentage[1] = this._state.percentage[0];
1646						this._state.dragged = 0;
1647					}
1648					else if (this._state.keyCtrl === 0 && (((this._state.value[1] / this.options.max) * 100) < percentage)) {
1649						this._state.percentage[0] = this._state.percentage[1];
1650						this._state.keyCtrl = 1;
1651						this.handle2.focus();
1652					}
1653					else if (this._state.keyCtrl === 1 && (((this._state.value[0] / this.options.max) * 100) > percentage)) {
1654						this._state.percentage[1] = this._state.percentage[0];
1655						this._state.keyCtrl = 0;
1656						this.handle1.focus();
1657					}
1658				}
1659			},
1660			_mouseup: function() {
1661				if(!this._state.enabled) {
1662					return false;
1663				}
1664				if (this.touchCapable) {
1665					// Touch: Unbind touch event handlers:
1666					document.removeEventListener("touchmove", this.mousemove, false);
1667					document.removeEventListener("touchend", this.mouseup, false);
1668				}
1669				// Unbind mouse event handlers:
1670				document.removeEventListener("mousemove", this.mousemove, false);
1671				document.removeEventListener("mouseup", this.mouseup, false);
1672
1673				this._state.inDrag = false;
1674				if (this._state.over === false) {
1675					this._hideTooltip();
1676				}
1677				var val = this._calculateValue(true);
1678
1679				this._layout();
1680				this._setDataVal(val);
1681				this._trigger('slideStop', val);
1682
1683				return false;
1684			},
1685			_calculateValue: function(snapToClosestTick) {
1686				var val;
1687				if (this.options.range) {
1688					val = [this.options.min,this.options.max];
1689					if (this._state.percentage[0] !== 0){
1690						val[0] = this._toValue(this._state.percentage[0]);
1691						val[0] = this._applyPrecision(val[0]);
1692					}
1693					if (this._state.percentage[1] !== 100){
1694						val[1] = this._toValue(this._state.percentage[1]);
1695						val[1] = this._applyPrecision(val[1]);
1696					}
1697				} else {
1698					val = this._toValue(this._state.percentage[0]);
1699					val = parseFloat(val);
1700					val = this._applyPrecision(val);
1701				}
1702
1703				if (snapToClosestTick) {
1704					var min = [val, Infinity];
1705					for (var i = 0; i < this.options.ticks.length; i++) {
1706						var diff = Math.abs(this.options.ticks[i] - val);
1707						if (diff <= min[1]) {
1708							min = [this.options.ticks[i], diff];
1709						}
1710					}
1711					if (min[1] <= this.options.ticks_snap_bounds) {
1712						return min[0];
1713					}
1714				}
1715
1716				return val;
1717			},
1718			_applyPrecision: function(val) {
1719				var precision = this.options.precision || this._getNumDigitsAfterDecimalPlace(this.options.step);
1720				return this._applyToFixedAndParseFloat(val, precision);
1721			},
1722			_getNumDigitsAfterDecimalPlace: function(num) {
1723				var match = (''+num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
1724				if (!match) { return 0; }
1725				return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));
1726			},
1727			_applyToFixedAndParseFloat: function(num, toFixedInput) {
1728				var truncatedNum = num.toFixed(toFixedInput);
1729				return parseFloat(truncatedNum);
1730			},
1731			/*
1732				Credits to Mike Samuel for the following method!
1733				Source: http://stackoverflow.com/questions/10454518/javascript-how-to-retrieve-the-number-of-decimals-of-a-string-number
1734			*/
1735			_getPercentage: function(ev) {
1736				if (this.touchCapable && (ev.type === 'touchstart' || ev.type === 'touchmove')) {
1737					ev = ev.touches[0];
1738				}
1739
1740				var eventPosition = ev[this.mousePos];
1741				var sliderOffset = this._state.offset[this.stylePos];
1742				var distanceToSlide = eventPosition - sliderOffset;
1743				if(this.stylePos==='right') {
1744					distanceToSlide = -distanceToSlide;
1745				}
1746				// Calculate what percent of the length the slider handle has slid
1747				var percentage = (distanceToSlide / this._state.size) * 100;
1748				percentage = Math.round(percentage / this._state.percentage[2]) * this._state.percentage[2];
1749				if (this.options.reversed) {
1750					percentage = 100 - percentage;
1751				}
1752
1753				// Make sure the percent is within the bounds of the slider.
1754				// 0% corresponds to the 'min' value of the slide
1755				// 100% corresponds to the 'max' value of the slide
1756				return Math.max(0, Math.min(100, percentage));
1757			},
1758			_validateInputValue: function(val) {
1759				if (!isNaN(+val)) {
1760					return +val;
1761				} else if (Array.isArray(val)) {
1762					this._validateArray(val);
1763					return val;
1764				} else {
1765					throw new Error(ErrorMsgs.formatInvalidInputErrorMsg(val));
1766				}
1767			},
1768			_validateArray: function(val) {
1769				for(var i = 0; i < val.length; i++) {
1770					var input =  val[i];
1771					if (typeof input !== 'number') { throw new Error( ErrorMsgs.formatInvalidInputErrorMsg(input) ); }
1772				}
1773			},
1774			_setDataVal: function(val) {
1775				this.element.setAttribute('data-value', val);
1776				this.element.setAttribute('value', val);
1777				this.element.value = val;
1778			},
1779			_trigger: function(evt, val) {
1780				val = (val || val === 0) ? val : undefined;
1781
1782				var callbackFnArray = this.eventToCallbackMap[evt];
1783				if(callbackFnArray && callbackFnArray.length) {
1784					for(var i = 0; i < callbackFnArray.length; i++) {
1785						var callbackFn = callbackFnArray[i];
1786						callbackFn(val);
1787					}
1788				}
1789
1790				/* If JQuery exists, trigger JQuery events */
1791				if($) {
1792					this._triggerJQueryEvent(evt, val);
1793				}
1794			},
1795			_triggerJQueryEvent: function(evt, val) {
1796				var eventData = {
1797					type: evt,
1798					value: val
1799				};
1800				this.$element.trigger(eventData);
1801				this.$sliderElem.trigger(eventData);
1802			},
1803			_unbindJQueryEventHandlers: function() {
1804				this.$element.off();
1805				this.$sliderElem.off();
1806			},
1807			_setText: function(element, text) {
1808				if(typeof element.textContent !== "undefined") {
1809					element.textContent = text;
1810				} else if(typeof element.innerText !== "undefined") {
1811					element.innerText = text;
1812				}
1813			},
1814			_removeClass: function(element, classString) {
1815				var classes = classString.split(" ");
1816				var newClasses = element.className;
1817
1818				for(var i = 0; i < classes.length; i++) {
1819					var classTag = classes[i];
1820					var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)");
1821					newClasses = newClasses.replace(regex, " ");
1822				}
1823
1824				element.className = newClasses.trim();
1825			},
1826			_addClass: function(element, classString) {
1827				var classes = classString.split(" ");
1828				var newClasses = element.className;
1829
1830				for(var i = 0; i < classes.length; i++) {
1831					var classTag = classes[i];
1832					var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)");
1833					var ifClassExists = regex.test(newClasses);
1834
1835					if(!ifClassExists) {
1836						newClasses += " " + classTag;
1837					}
1838				}
1839
1840				element.className = newClasses.trim();
1841			},
1842			_offsetLeft: function(obj){
1843				return obj.getBoundingClientRect().left;
1844			},
1845			_offsetRight: function(obj){
1846				return obj.getBoundingClientRect().right;
1847			},
1848			_offsetTop: function(obj){
1849				var offsetTop = obj.offsetTop;
1850				while((obj = obj.offsetParent) && !isNaN(obj.offsetTop)){
1851					offsetTop += obj.offsetTop;
1852					if( obj.tagName !== 'BODY') {
1853						offsetTop -= obj.scrollTop;
1854					}
1855				}
1856				return offsetTop;
1857			},
1858			_offset: function (obj) {
1859				return {
1860					left: this._offsetLeft(obj),
1861					right: this._offsetRight(obj),
1862					top: this._offsetTop(obj)
1863				};
1864		    },
1865			_css: function(elementRef, styleName, value) {
1866				if ($) {
1867					$.style(elementRef, styleName, value);
1868				} else {
1869					var style = styleName.replace(/^-ms-/, "ms-").replace(/-([\da-z])/gi, function (all, letter) {
1870						return letter.toUpperCase();
1871					});
1872					elementRef.style[style] = value;
1873				}
1874			},
1875			_toValue: function(percentage) {
1876				return this.options.scale.toValue.apply(this, [percentage]);
1877			},
1878			_toPercentage: function(value) {
1879				return this.options.scale.toPercentage.apply(this, [value]);
1880			},
1881			_setTooltipPosition: function(){
1882				var tooltips = [this.tooltip, this.tooltip_min, this.tooltip_max];
1883				if (this.options.orientation === 'vertical'){
1884					var tooltipPos;
1885					if(this.options.tooltip_position) {
1886						tooltipPos = this.options.tooltip_position;
1887					} else {
1888						if(this.options.rtl) {
1889							tooltipPos = 'left';
1890						} else {
1891							tooltipPos = 'right';
1892						}
1893					}
1894					var oppositeSide = (tooltipPos === 'left') ? 'right' : 'left';
1895					tooltips.forEach(function(tooltip){
1896						this._addClass(tooltip, tooltipPos);
1897						tooltip.style[oppositeSide] = '100%';
1898					}.bind(this));
1899				} else if(this.options.tooltip_position === 'bottom') {
1900					tooltips.forEach(function(tooltip){
1901						this._addClass(tooltip, 'bottom');
1902						tooltip.style.top = 22 + 'px';
1903					}.bind(this));
1904				} else {
1905					tooltips.forEach(function(tooltip){
1906						this._addClass(tooltip, 'top');
1907						tooltip.style.top = -this.tooltip.outerHeight - 14 + 'px';
1908					}.bind(this));
1909				}
1910			}
1911		};
1912
1913		/*********************************
1914
1915			Attach to global namespace
1916
1917		*********************************/
1918		if($ && $.fn) {
1919			let autoRegisterNamespace;
1920
1921			if (!$.fn.slider) {
1922				$.bridget(NAMESPACE_MAIN, Slider);
1923				autoRegisterNamespace = NAMESPACE_MAIN;
1924			}
1925			else {
1926				if (windowIsDefined) {
1927					window.console.warn("bootstrap-slider.js - WARNING: $.fn.slider namespace is already bound. Use the $.fn.bootstrapSl
1927ider namespace instead.");
1928				}
1929				autoRegisterNamespace = NAMESPACE_ALTERNATE;
1930			}
1931			$.bridget(NAMESPACE_ALTERNATE, Slider);
1932
1933			// Auto-Register data-provide="slider" Elements
1934			$(function() {
1935				$("input[data-provide=slider]")[autoRegisterNamespace]();
1936			});
1937		}
1938
1939	})( $ );
1940
1941	return Slider;
1942}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.