GPQAPP

Форк
0
/
bootstrap-slider.js 
2061 строка · 69.9 Кб
1
/*! =======================================================
2
                      VERSION  11.0.2              
3
========================================================= */
4
"use strict";
5

6
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
7

8
/*! =========================================================
9
 * bootstrap-slider.js
10
 *
11
 * Maintainers:
12
 *		Kyle Kemp
13
 *			- Twitter: @seiyria
14
 *			- Github:  seiyria
15
 *		Rohit Kalkur
16
 *			- Twitter: @Rovolutionary
17
 *			- Github:  rovolution
18
 *
19
 * =========================================================
20
 *
21
 * bootstrap-slider is released under the MIT License
22
 * Copyright (c) 2019 Kyle Kemp, Rohit Kalkur, and contributors
23
 *
24
 * Permission is hereby granted, free of charge, to any person
25
 * obtaining a copy of this software and associated documentation
26
 * files (the "Software"), to deal in the Software without
27
 * restriction, including without limitation the rights to use,
28
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
29
 * copies of the Software, and to permit persons to whom the
30
 * Software is furnished to do so, subject to the following
31
 * conditions:
32
 *
33
 * The above copyright notice and this permission notice shall be
34
 * included in all copies or substantial portions of the Software.
35
 *
36
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
37
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
38
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
39
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
40
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
41
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
42
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
43
 * OTHER DEALINGS IN THE SOFTWARE.
44
 *
45
 * ========================================================= */
46

47
/**
48
 * Bridget makes jQuery widgets
49
 * v1.0.1
50
 * MIT license
51
 */
52
var windowIsDefined = (typeof window === "undefined" ? "undefined" : _typeof(window)) === "object";
53

54
(function (factory) {
55
	if (typeof define === "function" && define.amd) {
56
		define(["jquery"], factory);
57
	} else if ((typeof module === "undefined" ? "undefined" : _typeof(module)) === "object" && module.exports) {
58
		var jQuery;
59
		try {
60
			jQuery = require("jquery");
61
		} catch (err) {
62
			jQuery = null;
63
		}
64
		module.exports = factory(jQuery);
65
	} else if (window) {
66
		window.Slider = factory(window.jQuery);
67
	}
68
})(function ($) {
69
	// Constants
70
	var NAMESPACE_MAIN = 'slider';
71
	var NAMESPACE_ALTERNATE = 'bootstrapSlider';
72

73
	// Polyfill console methods
74
	if (windowIsDefined && !window.console) {
75
		window.console = {};
76
	}
77
	if (windowIsDefined && !window.console.log) {
78
		window.console.log = function () {};
79
	}
80
	if (windowIsDefined && !window.console.warn) {
81
		window.console.warn = function () {};
82
	}
83

84
	// Reference to Slider constructor
85
	var Slider;
86

87
	(function ($) {
88

89
		'use strict';
90

91
		// -------------------------- utils -------------------------- //
92

93
		var slice = Array.prototype.slice;
94

95
		function noop() {}
96

97
		// -------------------------- definition -------------------------- //
98

99
		function defineBridget($) {
100

101
			// bail if no jQuery
102
			if (!$) {
103
				return;
104
			}
105

106
			// -------------------------- addOptionMethod -------------------------- //
107

108
			/**
109
    * adds option method -> $().plugin('option', {...})
110
    * @param {Function} PluginClass - constructor class
111
    */
112
			function addOptionMethod(PluginClass) {
113
				// don't overwrite original option method
114
				if (PluginClass.prototype.option) {
115
					return;
116
				}
117

118
				// option setter
119
				PluginClass.prototype.option = function (opts) {
120
					// bail out if not an object
121
					if (!$.isPlainObject(opts)) {
122
						return;
123
					}
124
					this.options = $.extend(true, this.options, opts);
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 : function (message) {
133
				console.error(message);
134
			};
135

136
			/**
137
    * jQuery plugin bridge, access methods like $elem.plugin('method')
138
    * @param {String} namespace - plugin name
139
    * @param {Function} PluginClass - constructor class
140
    */
141
			function bridge(namespace, PluginClass) {
142
				// add to jQuery fn namespace
143
				$.fn[namespace] = function (options) {
144
					if (typeof options === 'string') {
145
						// call plugin method when first argument is a string
146
						// get arguments for method
147
						var args = slice.call(arguments, 1);
148

149
						for (var i = 0, len = this.length; i < len; i++) {
150
							var elem = this[i];
151
							var instance = $.data(elem, namespace);
152
							if (!instance) {
153
								logError("cannot call methods on " + namespace + " prior to initialization; " + "attempted to call '" + options + "'");
154
								continue;
155
							}
156
							if (!$.isFunction(instance[options]) || options.charAt(0) === '_') {
157
								logError("no such method '" + options + "' for " + namespace + " instance");
158
								continue;
159
							}
160

161
							// trigger method with arguments
162
							var returnValue = instance[options].apply(instance, args);
163

164
							// break look and return first value if provided
165
							if (returnValue !== undefined && returnValue !== instance) {
166
								return returnValue;
167
							}
168
						}
169
						// return this if no return value
170
						return this;
171
					} else {
172
						var objects = this.map(function () {
173
							var instance = $.data(this, namespace);
174
							if (instance) {
175
								// apply options & init
176
								instance.option(options);
177
								instance._init();
178
							} else {
179
								// initialize new instance
180
								instance = new PluginClass(this, options);
181
								$.data(this, namespace, instance);
182
							}
183
							return $(this);
184
						});
185

186
						if (objects.length === 1) {
187
							return objects[0];
188
						}
189
						return objects;
190
					}
191
				};
192
			}
193

194
			// -------------------------- bridget -------------------------- //
195

196
			/**
197
    * converts a Prototypical class into a proper jQuery plugin
198
    *   the class must have a ._init method
199
    * @param {String} namespace - plugin name, used in $().pluginName
200
    * @param {Function} PluginClass - constructor class
201
    */
202
			$.bridget = function (namespace, PluginClass) {
203
				addOptionMethod(PluginClass);
204
				bridge(namespace, PluginClass);
205
			};
206

207
			return $.bridget;
208
		}
209

210
		// get jquery from browser global
211
		defineBridget($);
212
	})($);
213

214
	/*************************************************
215
 			BOOTSTRAP-SLIDER SOURCE CODE
216
 	**************************************************/
217

218
	(function ($) {
219
		var autoRegisterNamespace = void 0;
220

221
		var ErrorMsgs = {
222
			formatInvalidInputErrorMsg: function formatInvalidInputErrorMsg(input) {
223
				return "Invalid input value '" + input + "' passed in";
224
			},
225
			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"
226
		};
227

228
		var SliderScale = {
229
			linear: {
230
				getValue: function getValue(value, options) {
231
					if (value < options.min) {
232
						return options.min;
233
					} else if (value > options.max) {
234
						return options.max;
235
					} else {
236
						return value;
237
					}
238
				},
239
				toValue: function toValue(percentage) {
240
					var rawValue = percentage / 100 * (this.options.max - this.options.min);
241
					var shouldAdjustWithBase = true;
242
					if (this.options.ticks_positions.length > 0) {
243
						var minv,
244
						    maxv,
245
						    minp,
246
						    maxp = 0;
247
						for (var i = 1; i < this.options.ticks_positions.length; i++) {
248
							if (percentage <= this.options.ticks_positions[i]) {
249
								minv = this.options.ticks[i - 1];
250
								minp = this.options.ticks_positions[i - 1];
251
								maxv = this.options.ticks[i];
252
								maxp = this.options.ticks_positions[i];
253

254
								break;
255
							}
256
						}
257
						var partialPercentage = (percentage - minp) / (maxp - minp);
258
						rawValue = minv + partialPercentage * (maxv - minv);
259
						shouldAdjustWithBase = false;
260
					}
261

262
					var adjustment = shouldAdjustWithBase ? this.options.min : 0;
263
					var value = adjustment + Math.round(rawValue / this.options.step) * this.options.step;
264
					return SliderScale.linear.getValue(value, this.options);
265
				},
266
				toPercentage: function toPercentage(value) {
267
					if (this.options.max === this.options.min) {
268
						return 0;
269
					}
270

271
					if (this.options.ticks_positions.length > 0) {
272
						var minv,
273
						    maxv,
274
						    minp,
275
						    maxp = 0;
276
						for (var i = 0; i < this.options.ticks.length; i++) {
277
							if (value <= this.options.ticks[i]) {
278
								minv = i > 0 ? this.options.ticks[i - 1] : 0;
279
								minp = i > 0 ? this.options.ticks_positions[i - 1] : 0;
280
								maxv = this.options.ticks[i];
281
								maxp = this.options.ticks_positions[i];
282

283
								break;
284
							}
285
						}
286
						if (i > 0) {
287
							var partialPercentage = (value - minv) / (maxv - minv);
288
							return minp + partialPercentage * (maxp - minp);
289
						}
290
					}
291

292
					return 100 * (value - this.options.min) / (this.options.max - this.options.min);
293
				}
294
			},
295

296
			logarithmic: {
297
				/* Based on http://stackoverflow.com/questions/846221/logarithmic-slider */
298
				toValue: function toValue(percentage) {
299
					var offset = 1 - this.options.min;
300
					var min = Math.log(this.options.min + offset);
301
					var max = Math.log(this.options.max + offset);
302
					var value = Math.exp(min + (max - min) * percentage / 100) - offset;
303
					if (Math.round(value) === max) {
304
						return max;
305
					}
306
					value = this.options.min + Math.round((value - this.options.min) / this.options.step) * this.options.step;
307
					/* Rounding to the nearest step could exceed the min or
308
      * max, so clip to those values. */
309
					return SliderScale.linear.getValue(value, this.options);
310
				},
311
				toPercentage: function toPercentage(value) {
312
					if (this.options.max === this.options.min) {
313
						return 0;
314
					} else {
315
						var offset = 1 - this.options.min;
316
						var max = Math.log(this.options.max + offset);
317
						var min = Math.log(this.options.min + offset);
318
						var v = Math.log(value + offset);
319
						return 100 * (v - min) / (max - min);
320
					}
321
				}
322
			}
323
		};
324

325
		/*************************************************
326
  						CONSTRUCTOR
327
  	**************************************************/
328
		Slider = function Slider(element, options) {
329
			createNewSlider.call(this, element, options);
330
			return this;
331
		};
332

333
		function createNewSlider(element, options) {
334

335
			/*
336
   	The internal state object is used to store data about the current 'state' of slider.
337
   	This includes values such as the `value`, `enabled`, etc...
338
   */
339
			this._state = {
340
				value: null,
341
				enabled: null,
342
				offset: null,
343
				size: null,
344
				percentage: null,
345
				inDrag: false,
346
				over: false,
347
				tickIndex: null
348
			};
349

350
			// The objects used to store the reference to the tick methods if ticks_tooltip is on
351
			this.ticksCallbackMap = {};
352
			this.handleCallbackMap = {};
353

354
			if (typeof element === "string") {
355
				this.element = document.querySelector(element);
356
			} else if (element instanceof HTMLElement) {
357
				this.element = element;
358
			}
359

360
			/*************************************************
361
   					Process Options
362
   	**************************************************/
363
			options = options ? options : {};
364
			var optionTypes = Object.keys(this.defaultOptions);
365

366
			var isMinSet = options.hasOwnProperty('min');
367
			var isMaxSet = options.hasOwnProperty('max');
368

369
			for (var i = 0; i < optionTypes.length; i++) {
370
				var optName = optionTypes[i];
371

372
				// First check if an option was passed in via the constructor
373
				var val = options[optName];
374
				// If no data attrib, then check data atrributes
375
				val = typeof val !== 'undefined' ? val : getDataAttrib(this.element, optName);
376
				// Finally, if nothing was specified, use the defaults
377
				val = val !== null ? val : this.defaultOptions[optName];
378

379
				// Set all options on the instance of the Slider
380
				if (!this.options) {
381
					this.options = {};
382
				}
383
				this.options[optName] = val;
384
			}
385

386
			this.ticksAreValid = Array.isArray(this.options.ticks) && this.options.ticks.length > 0;
387

388
			// Lock to ticks only when ticks[] is defined and set
389
			if (!this.ticksAreValid) {
390
				this.options.lock_to_ticks = false;
391
			}
392

393
			// Check options.rtl
394
			if (this.options.rtl === 'auto') {
395
				var computedStyle = window.getComputedStyle(this.element);
396
				if (computedStyle != null) {
397
					this.options.rtl = computedStyle.direction === 'rtl';
398
				} else {
399
					// Fix for Firefox bug in versions less than 62:
400
					// https://bugzilla.mozilla.org/show_bug.cgi?id=548397
401
					// https://bugzilla.mozilla.org/show_bug.cgi?id=1467722
402
					this.options.rtl = this.element.style.direction === 'rtl';
403
				}
404
			}
405

406
			/*
407
   	Validate `tooltip_position` against 'orientation`
408
   	- if `tooltip_position` is incompatible with orientation, switch it to a default compatible with specified `orientation`
409
   		-- default for "vertical" -> "right", "left" if rtl
410
   		-- default for "horizontal" -> "top"
411
   */
412
			if (this.options.orientation === "vertical" && (this.options.tooltip_position === "top" || this.options.tooltip_position === "bottom")) {
413
				if (this.options.rtl) {
414
					this.options.tooltip_position = "left";
415
				} else {
416
					this.options.tooltip_position = "right";
417
				}
418
			} else if (this.options.orientation === "horizontal" && (this.options.tooltip_position === "left" || this.options.tooltip_position === "right")) {
419

420
				this.options.tooltip_position = "top";
421
			}
422

423
			function getDataAttrib(element, optName) {
424
				var dataName = "data-slider-" + optName.replace(/_/g, '-');
425
				var dataValString = element.getAttribute(dataName);
426

427
				try {
428
					return JSON.parse(dataValString);
429
				} catch (err) {
430
					return dataValString;
431
				}
432
			}
433

434
			/*************************************************
435
   					Create Markup
436
   	**************************************************/
437

438
			var origWidth = this.element.style.width;
439
			var updateSlider = false;
440
			var parent = this.element.parentNode;
441
			var sliderTrackSelection;
442
			var sliderTrackLow, sliderTrackHigh;
443
			var sliderMinHandle;
444
			var sliderMaxHandle;
445

446
			if (this.sliderElem) {
447
				updateSlider = true;
448
			} else {
449
				/* Create elements needed for slider */
450
				this.sliderElem = document.createElement("div");
451
				this.sliderElem.className = "slider";
452

453
				/* Create slider track elements */
454
				var sliderTrack = document.createElement("div");
455
				sliderTrack.className = "slider-track";
456

457
				sliderTrackLow = document.createElement("div");
458
				sliderTrackLow.className = "slider-track-low";
459

460
				sliderTrackSelection = document.createElement("div");
461
				sliderTrackSelection.className = "slider-selection";
462

463
				sliderTrackHigh = document.createElement("div");
464
				sliderTrackHigh.className = "slider-track-high";
465

466
				sliderMinHandle = document.createElement("div");
467
				sliderMinHandle.className = "slider-handle min-slider-handle";
468
				sliderMinHandle.setAttribute('role', 'slider');
469
				sliderMinHandle.setAttribute('aria-valuemin', this.options.min);
470
				sliderMinHandle.setAttribute('aria-valuemax', this.options.max);
471

472
				sliderMaxHandle = document.createElement("div");
473
				sliderMaxHandle.className = "slider-handle max-slider-handle";
474
				sliderMaxHandle.setAttribute('role', 'slider');
475
				sliderMaxHandle.setAttribute('aria-valuemin', this.options.min);
476
				sliderMaxHandle.setAttribute('aria-valuemax', this.options.max);
477

478
				sliderTrack.appendChild(sliderTrackLow);
479
				sliderTrack.appendChild(sliderTrackSelection);
480
				sliderTrack.appendChild(sliderTrackHigh);
481

482
				/* Create highlight range elements */
483
				this.rangeHighlightElements = [];
484
				var rangeHighlightsOpts = this.options.rangeHighlights;
485
				if (Array.isArray(rangeHighlightsOpts) && rangeHighlightsOpts.length > 0) {
486
					for (var j = 0; j < rangeHighlightsOpts.length; j++) {
487
						var rangeHighlightElement = document.createElement("div");
488
						var customClassString = rangeHighlightsOpts[j].class || "";
489
						rangeHighlightElement.className = "slider-rangeHighlight slider-selection " + customClassString;
490
						this.rangeHighlightElements.push(rangeHighlightElement);
491
						sliderTrack.appendChild(rangeHighlightElement);
492
					}
493
				}
494

495
				/* Add aria-labelledby to handle's */
496
				var isLabelledbyArray = Array.isArray(this.options.labelledby);
497
				if (isLabelledbyArray && this.options.labelledby[0]) {
498
					sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby[0]);
499
				}
500
				if (isLabelledbyArray && this.options.labelledby[1]) {
501
					sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby[1]);
502
				}
503
				if (!isLabelledbyArray && this.options.labelledby) {
504
					sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby);
505
					sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby);
506
				}
507

508
				/* Create ticks */
509
				this.ticks = [];
510
				if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
511
					this.ticksContainer = document.createElement('div');
512
					this.ticksContainer.className = 'slider-tick-container';
513

514
					for (i = 0; i < this.options.ticks.length; i++) {
515
						var tick = document.createElement('div');
516
						tick.className = 'slider-tick';
517
						if (this.options.ticks_tooltip) {
518
							var tickListenerReference = this._addTickListener();
519
							var enterCallback = tickListenerReference.addMouseEnter(this, tick, i);
520
							var leaveCallback = tickListenerReference.addMouseLeave(this, tick);
521

522
							this.ticksCallbackMap[i] = {
523
								mouseEnter: enterCallback,
524
								mouseLeave: leaveCallback
525
							};
526
						}
527
						this.ticks.push(tick);
528
						this.ticksContainer.appendChild(tick);
529
					}
530

531
					sliderTrackSelection.className += " tick-slider-selection";
532
				}
533

534
				this.tickLabels = [];
535
				if (Array.isArray(this.options.ticks_labels) && this.options.ticks_labels.length > 0) {
536
					this.tickLabelContainer = document.createElement('div');
537
					this.tickLabelContainer.className = 'slider-tick-label-container';
538

539
					for (i = 0; i < this.options.ticks_labels.length; i++) {
540
						var label = document.createElement('div');
541
						var noTickPositionsSpecified = this.options.ticks_positions.length === 0;
542
						var tickLabelsIndex = this.options.reversed && noTickPositionsSpecified ? this.options.ticks_labels.length - (i + 1) : i;
543
						label.className = 'slider-tick-label';
544
						label.innerHTML = this.options.ticks_labels[tickLabelsIndex];
545

546
						this.tickLabels.push(label);
547
						this.tickLabelContainer.appendChild(label);
548
					}
549
				}
550

551
				var createAndAppendTooltipSubElements = function createAndAppendTooltipSubElements(tooltipElem) {
552
					var arrow = document.createElement("div");
553
					arrow.className = "arrow";
554

555
					var inner = document.createElement("div");
556
					inner.className = "tooltip-inner";
557

558
					tooltipElem.appendChild(arrow);
559
					tooltipElem.appendChild(inner);
560
				};
561

562
				/* Create tooltip elements */
563
				var sliderTooltip = document.createElement("div");
564
				sliderTooltip.className = "tooltip tooltip-main";
565
				sliderTooltip.setAttribute('role', 'presentation');
566
				createAndAppendTooltipSubElements(sliderTooltip);
567

568
				var sliderTooltipMin = document.createElement("div");
569
				sliderTooltipMin.className = "tooltip tooltip-min";
570
				sliderTooltipMin.setAttribute('role', 'presentation');
571
				createAndAppendTooltipSubElements(sliderTooltipMin);
572

573
				var sliderTooltipMax = document.createElement("div");
574
				sliderTooltipMax.className = "tooltip tooltip-max";
575
				sliderTooltipMax.setAttribute('role', 'presentation');
576
				createAndAppendTooltipSubElements(sliderTooltipMax);
577

578
				/* Append components to sliderElem */
579
				this.sliderElem.appendChild(sliderTrack);
580
				this.sliderElem.appendChild(sliderTooltip);
581
				this.sliderElem.appendChild(sliderTooltipMin);
582
				this.sliderElem.appendChild(sliderTooltipMax);
583

584
				if (this.tickLabelContainer) {
585
					this.sliderElem.appendChild(this.tickLabelContainer);
586
				}
587
				if (this.ticksContainer) {
588
					this.sliderElem.appendChild(this.ticksContainer);
589
				}
590

591
				this.sliderElem.appendChild(sliderMinHandle);
592
				this.sliderElem.appendChild(sliderMaxHandle);
593

594
				/* Append slider element to parent container, right before the original <input> element */
595
				parent.insertBefore(this.sliderElem, this.element);
596

597
				/* Hide original <input> element */
598
				this.element.style.display = "none";
599
			}
600
			/* If JQuery exists, cache JQ references */
601
			if ($) {
602
				this.$element = $(this.element);
603
				this.$sliderElem = $(this.sliderElem);
604
			}
605

606
			/*************************************************
607
   						Setup
608
   	**************************************************/
609
			this.eventToCallbackMap = {};
610
			this.sliderElem.id = this.options.id;
611

612
			this.touchCapable = 'ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch;
613

614
			this.touchX = 0;
615
			this.touchY = 0;
616

617
			this.tooltip = this.sliderElem.querySelector('.tooltip-main');
618
			this.tooltipInner = this.tooltip.querySelector('.tooltip-inner');
619

620
			this.tooltip_min = this.sliderElem.querySelector('.tooltip-min');
621
			this.tooltipInner_min = this.tooltip_min.querySelector('.tooltip-inner');
622

623
			this.tooltip_max = this.sliderElem.querySelector('.tooltip-max');
624
			this.tooltipInner_max = this.tooltip_max.querySelector('.tooltip-inner');
625

626
			if (SliderScale[this.options.scale]) {
627
				this.options.scale = SliderScale[this.options.scale];
628
			}
629

630
			if (updateSlider === true) {
631
				// Reset classes
632
				this._removeClass(this.sliderElem, 'slider-horizontal');
633
				this._removeClass(this.sliderElem, 'slider-vertical');
634
				this._removeClass(this.sliderElem, 'slider-rtl');
635
				this._removeClass(this.tooltip, 'hide');
636
				this._removeClass(this.tooltip_min, 'hide');
637
				this._removeClass(this.tooltip_max, 'hide');
638

639
				// Undo existing inline styles for track
640
				["left", "right", "top", "width", "height"].forEach(function (prop) {
641
					this._removeProperty(this.trackLow, prop);
642
					this._removeProperty(this.trackSelection, prop);
643
					this._removeProperty(this.trackHigh, prop);
644
				}, this);
645

646
				// Undo inline styles on handles
647
				[this.handle1, this.handle2].forEach(function (handle) {
648
					this._removeProperty(handle, 'left');
649
					this._removeProperty(handle, 'right');
650
					this._removeProperty(handle, 'top');
651
				}, this);
652

653
				// Undo inline styles and classes on tooltips
654
				[this.tooltip, this.tooltip_min, this.tooltip_max].forEach(function (tooltip) {
655
					this._removeProperty(tooltip, 'bs-tooltip-left');
656
					this._removeProperty(tooltip, 'bs-tooltip-right');
657
					this._removeProperty(tooltip, 'bs-tooltip-top');
658

659
					this._removeClass(tooltip, 'bs-tooltip-right');
660
					this._removeClass(tooltip, 'bs-tooltip-left');
661
					this._removeClass(tooltip, 'bs-tooltip-top');
662
				}, this);
663
			}
664

665
			if (this.options.orientation === 'vertical') {
666
				this._addClass(this.sliderElem, 'slider-vertical');
667
				this.stylePos = 'top';
668
				this.mousePos = 'pageY';
669
				this.sizePos = 'offsetHeight';
670
			} else {
671
				this._addClass(this.sliderElem, 'slider-horizontal');
672
				this.sliderElem.style.width = origWidth;
673
				this.options.orientation = 'horizontal';
674
				if (this.options.rtl) {
675
					this.stylePos = 'right';
676
				} else {
677
					this.stylePos = 'left';
678
				}
679
				this.mousePos = 'clientX';
680
				this.sizePos = 'offsetWidth';
681
			}
682
			// specific rtl class
683
			if (this.options.rtl) {
684
				this._addClass(this.sliderElem, 'slider-rtl');
685
			}
686
			this._setTooltipPosition();
687
			/* In case ticks are specified, overwrite the min and max bounds */
688
			if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
689
				if (!isMaxSet) {
690
					this.options.max = Math.max.apply(Math, this.options.ticks);
691
				}
692
				if (!isMinSet) {
693
					this.options.min = Math.min.apply(Math, this.options.ticks);
694
				}
695
			}
696

697
			if (Array.isArray(this.options.value)) {
698
				this.options.range = true;
699
				this._state.value = this.options.value;
700
			} else if (this.options.range) {
701
				// User wants a range, but value is not an array
702
				this._state.value = [this.options.value, this.options.max];
703
			} else {
704
				this._state.value = this.options.value;
705
			}
706

707
			this.trackLow = sliderTrackLow || this.trackLow;
708
			this.trackSelection = sliderTrackSelection || this.trackSelection;
709
			this.trackHigh = sliderTrackHigh || this.trackHigh;
710

711
			if (this.options.selection === 'none') {
712
				this._addClass(this.trackLow, 'hide');
713
				this._addClass(this.trackSelection, 'hide');
714
				this._addClass(this.trackHigh, 'hide');
715
			} else if (this.options.selection === 'after' || this.options.selection === 'before') {
716
				this._removeClass(this.trackLow, 'hide');
717
				this._removeClass(this.trackSelection, 'hide');
718
				this._removeClass(this.trackHigh, 'hide');
719
			}
720

721
			this.handle1 = sliderMinHandle || this.handle1;
722
			this.handle2 = sliderMaxHandle || this.handle2;
723

724
			if (updateSlider === true) {
725
				// Reset classes
726
				this._removeClass(this.handle1, 'round triangle');
727
				this._removeClass(this.handle2, 'round triangle hide');
728

729
				for (i = 0; i < this.ticks.length; i++) {
730
					this._removeClass(this.ticks[i], 'round triangle hide');
731
				}
732
			}
733

734
			var availableHandleModifiers = ['round', 'triangle', 'custom'];
735
			var isValidHandleType = availableHandleModifiers.indexOf(this.options.handle) !== -1;
736
			if (isValidHandleType) {
737
				this._addClass(this.handle1, this.options.handle);
738
				this._addClass(this.handle2, this.options.handle);
739

740
				for (i = 0; i < this.ticks.length; i++) {
741
					this._addClass(this.ticks[i], this.options.handle);
742
				}
743
			}
744

745
			this._state.offset = this._offset(this.sliderElem);
746
			this._state.size = this.sliderElem[this.sizePos];
747
			this.setValue(this._state.value);
748

749
			/******************************************
750
   				Bind Event Listeners
751
   	******************************************/
752

753
			// Bind keyboard handlers
754
			this.handle1Keydown = this._keydown.bind(this, 0);
755
			this.handle1.addEventListener("keydown", this.handle1Keydown, false);
756

757
			this.handle2Keydown = this._keydown.bind(this, 1);
758
			this.handle2.addEventListener("keydown", this.handle2Keydown, false);
759

760
			this.mousedown = this._mousedown.bind(this);
761
			this.touchstart = this._touchstart.bind(this);
762
			this.touchmove = this._touchmove.bind(this);
763

764
			if (this.touchCapable) {
765
				this.sliderElem.addEventListener("touchstart", this.touchstart, false);
766
				this.sliderElem.addEventListener("touchmove", this.touchmove, false);
767
			}
768

769
			this.sliderElem.addEventListener("mousedown", this.mousedown, false);
770

771
			// Bind window handlers
772
			this.resize = this._resize.bind(this);
773
			window.addEventListener("resize", this.resize, false);
774

775
			// Bind tooltip-related handlers
776
			if (this.options.tooltip === 'hide') {
777
				this._addClass(this.tooltip, 'hide');
778
				this._addClass(this.tooltip_min, 'hide');
779
				this._addClass(this.tooltip_max, 'hide');
780
			} else if (this.options.tooltip === 'always') {
781
				this._showTooltip();
782
				this._alwaysShowTooltip = true;
783
			} else {
784
				this.showTooltip = this._showTooltip.bind(this);
785
				this.hideTooltip = this._hideTooltip.bind(this);
786

787
				if (this.options.ticks_tooltip) {
788
					var callbackHandle = this._addTickListener();
789
					//create handle1 listeners and store references in map
790
					var mouseEnter = callbackHandle.addMouseEnter(this, this.handle1);
791
					var mouseLeave = callbackHandle.addMouseLeave(this, this.handle1);
792
					this.handleCallbackMap.handle1 = {
793
						mouseEnter: mouseEnter,
794
						mouseLeave: mouseLeave
795
					};
796
					//create handle2 listeners and store references in map
797
					mouseEnter = callbackHandle.addMouseEnter(this, this.handle2);
798
					mouseLeave = callbackHandle.addMouseLeave(this, this.handle2);
799
					this.handleCallbackMap.handle2 = {
800
						mouseEnter: mouseEnter,
801
						mouseLeave: mouseLeave
802
					};
803
				} else {
804
					this.sliderElem.addEventListener("mouseenter", this.showTooltip, false);
805
					this.sliderElem.addEventListener("mouseleave", this.hideTooltip, false);
806

807
					if (this.touchCapable) {
808
						this.sliderElem.addEventListener("touchstart", this.showTooltip, false);
809
						this.sliderElem.addEventListener("touchmove", this.showTooltip, false);
810
						this.sliderElem.addEventListener("touchend", this.hideTooltip, false);
811
					}
812
				}
813

814
				this.handle1.addEventListener("focus", this.showTooltip, false);
815
				this.handle1.addEventListener("blur", this.hideTooltip, false);
816

817
				this.handle2.addEventListener("focus", this.showTooltip, false);
818
				this.handle2.addEventListener("blur", this.hideTooltip, false);
819

820
				if (this.touchCapable) {
821
					this.handle1.addEventListener("touchstart", this.showTooltip, false);
822
					this.handle1.addEventListener("touchmove", this.showTooltip, false);
823
					this.handle1.addEventListener("touchend", this.hideTooltip, false);
824

825
					this.handle2.addEventListener("touchstart", this.showTooltip, false);
826
					this.handle2.addEventListener("touchmove", this.showTooltip, false);
827
					this.handle2.addEventListener("touchend", this.hideTooltip, false);
828
				}
829
			}
830

831
			if (this.options.enabled) {
832
				this.enable();
833
			} else {
834
				this.disable();
835
			}
836
		}
837

838
		/*************************************************
839
  				INSTANCE PROPERTIES/METHODS
840
  	- Any methods bound to the prototype are considered
841
  part of the plugin's `public` interface
842
  	**************************************************/
843
		Slider.prototype = {
844
			_init: function _init() {}, // NOTE: Must exist to support bridget
845

846
			constructor: Slider,
847

848
			defaultOptions: {
849
				id: "",
850
				min: 0,
851
				max: 10,
852
				step: 1,
853
				precision: 0,
854
				orientation: 'horizontal',
855
				value: 5,
856
				range: false,
857
				selection: 'before',
858
				tooltip: 'show',
859
				tooltip_split: false,
860
				lock_to_ticks: false,
861
				handle: 'round',
862
				reversed: false,
863
				rtl: 'auto',
864
				enabled: true,
865
				formatter: function formatter(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 getElement() {
886
				return this.sliderElem;
887
			},
888

889
			getValue: function getValue() {
890
				if (this.options.range) {
891
					return this._state.value;
892
				} else {
893
					return this._state.value[0];
894
				}
895
			},
896

897
			setValue: function setValue(val, triggerSlideEvent, triggerChangeEvent) {
898
				if (!val) {
899
					val = 0;
900
				}
901
				var oldValue = this.getValue();
902
				this._state.value = this._validateInputValue(val);
903
				var applyPrecision = this._applyPrecision.bind(this);
904

905
				if (this.options.range) {
906
					this._state.value[0] = applyPrecision(this._state.value[0]);
907
					this._state.value[1] = applyPrecision(this._state.value[1]);
908

909
					if (this.ticksAreValid && this.options.lock_to_ticks) {
910
						this._state.value[0] = this.options.ticks[this._getClosestTickIndex(this._state.value[0])];
911
						this._state.value[1] = this.options.ticks[this._getClosestTickIndex(this._state.value[1])];
912
					}
913

914
					this._state.value[0] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[0]));
915
					this._state.value[1] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[1]));
916
				} else {
917
					this._state.value = applyPrecision(this._state.value);
918

919
					if (this.ticksAreValid && this.options.lock_to_ticks) {
920
						this._state.value = this.options.ticks[this._getClosestTickIndex(this._state.value)];
921
					}
922

923
					this._state.value = [Math.max(this.options.min, Math.min(this.options.max, this._state.value))];
924
					this._addClass(this.handle2, 'hide');
925
					if (this.options.selection === 'after') {
926
						this._state.value[1] = this.options.max;
927
					} else {
928
						this._state.value[1] = this.options.min;
929
					}
930
				}
931

932
				// Determine which ticks the handle(s) are set at (if applicable)
933
				this._setTickIndex();
934

935
				if (this.options.max > this.options.min) {
936
					this._state.percentage = [this._toPercentage(this._state.value[0]), this._toPercentage(this._state.value[1]), this.options.step * 100 / (this.options.max - this.options.min)];
937
				} else {
938
					this._state.percentage = [0, 0, 100];
939
				}
940

941
				this._layout();
942
				var newValue = this.options.range ? this._state.value : this._state.value[0];
943

944
				this._setDataVal(newValue);
945
				if (triggerSlideEvent === true) {
946
					this._trigger('slide', newValue);
947
				}
948

949
				var hasChanged = false;
950
				if (Array.isArray(newValue)) {
951
					hasChanged = oldValue[0] !== newValue[0] || oldValue[1] !== newValue[1];
952
				} else {
953
					hasChanged = oldValue !== newValue;
954
				}
955

956
				if (hasChanged && triggerChangeEvent === true) {
957
					this._trigger('change', {
958
						oldValue: oldValue,
959
						newValue: newValue
960
					});
961
				}
962

963
				return this;
964
			},
965

966
			destroy: function destroy() {
967
				// Remove event handlers on slider elements
968
				this._removeSliderEventHandlers();
969

970
				// Remove the slider from the DOM
971
				this.sliderElem.parentNode.removeChild(this.sliderElem);
972
				/* Show original <input> element */
973
				this.element.style.display = "";
974

975
				// Clear out custom event bindings
976
				this._cleanUpEventCallbacksMap();
977

978
				// Remove data values
979
				this.element.removeAttribute("data");
980

981
				// Remove JQuery handlers/data
982
				if ($) {
983
					this._unbindJQueryEventHandlers();
984
					if (autoRegisterNamespace === NAMESPACE_MAIN) {
985
						this.$element.removeData(autoRegisterNamespace);
986
					}
987
					this.$element.removeData(NAMESPACE_ALTERNATE);
988
				}
989
			},
990

991
			disable: function disable() {
992
				this._state.enabled = false;
993
				this.handle1.removeAttribute("tabindex");
994
				this.handle2.removeAttribute("tabindex");
995
				this._addClass(this.sliderElem, 'slider-disabled');
996
				this._trigger('slideDisabled');
997

998
				return this;
999
			},
1000

1001
			enable: function enable() {
1002
				this._state.enabled = true;
1003
				this.handle1.setAttribute("tabindex", 0);
1004
				this.handle2.setAttribute("tabindex", 0);
1005
				this._removeClass(this.sliderElem, 'slider-disabled');
1006
				this._trigger('slideEnabled');
1007

1008
				return this;
1009
			},
1010

1011
			toggle: function toggle() {
1012
				if (this._state.enabled) {
1013
					this.disable();
1014
				} else {
1015
					this.enable();
1016
				}
1017
				return this;
1018
			},
1019

1020
			isEnabled: function isEnabled() {
1021
				return this._state.enabled;
1022
			},
1023

1024
			on: function on(evt, callback) {
1025
				this._bindNonQueryEventHandler(evt, callback);
1026
				return this;
1027
			},
1028

1029
			off: function off(evt, callback) {
1030
				if ($) {
1031
					this.$element.off(evt, callback);
1032
					this.$sliderElem.off(evt, callback);
1033
				} else {
1034
					this._unbindNonQueryEventHandler(evt, callback);
1035
				}
1036
			},
1037

1038
			getAttribute: function getAttribute(attribute) {
1039
				if (attribute) {
1040
					return this.options[attribute];
1041
				} else {
1042
					return this.options;
1043
				}
1044
			},
1045

1046
			setAttribute: function setAttribute(attribute, value) {
1047
				this.options[attribute] = value;
1048
				return this;
1049
			},
1050

1051
			refresh: function refresh(options) {
1052
				var currentValue = this.getValue();
1053
				this._removeSliderEventHandlers();
1054
				createNewSlider.call(this, this.element, this.options);
1055
				// Don't reset slider's value on refresh if `useCurrentValue` is true
1056
				if (options && options.useCurrentValue === true) {
1057
					this.setValue(currentValue);
1058
				}
1059
				if ($) {
1060
					// Bind new instance of slider to the element
1061
					if (autoRegisterNamespace === NAMESPACE_MAIN) {
1062
						$.data(this.element, NAMESPACE_MAIN, this);
1063
						$.data(this.element, NAMESPACE_ALTERNATE, this);
1064
					} else {
1065
						$.data(this.element, NAMESPACE_ALTERNATE, this);
1066
					}
1067
				}
1068
				return this;
1069
			},
1070

1071
			relayout: function relayout() {
1072
				this._resize();
1073
				return this;
1074
			},
1075

1076
			/******************************+
1077
   				HELPERS
1078
   	- Any method that is not part of the public interface.
1079
   - Place it underneath this comment block and write its signature like so:
1080
   		_fnName : function() {...}
1081
   	********************************/
1082
			_removeTooltipListener: function _removeTooltipListener(event, handler) {
1083
				this.handle1.removeEventListener(event, handler, false);
1084
				this.handle2.removeEventListener(event, handler, false);
1085
			},
1086
			_removeSliderEventHandlers: function _removeSliderEventHandlers() {
1087
				// Remove keydown event listeners
1088
				this.handle1.removeEventListener("keydown", this.handle1Keydown, false);
1089
				this.handle2.removeEventListener("keydown", this.handle2Keydown, false);
1090

1091
				//remove the listeners from the ticks and handles if they had their own listeners
1092
				if (this.options.ticks_tooltip) {
1093
					var ticks = this.ticksContainer.getElementsByClassName('slider-tick');
1094
					for (var i = 0; i < ticks.length; i++) {
1095
						ticks[i].removeEventListener('mouseenter', this.ticksCallbackMap[i].mouseEnter, false);
1096
						ticks[i].removeEventListener('mouseleave', this.ticksCallbackMap[i].mouseLeave, false);
1097
					}
1098
					if (this.handleCallbackMap.handle1 && this.handleCallbackMap.handle2) {
1099
						this.handle1.removeEventListener('mouseenter', this.handleCallbackMap.handle1.mouseEnter, false);
1100
						this.handle2.removeEventListener('mouseenter', this.handleCallbackMap.handle2.mouseEnter, false);
1101
						this.handle1.removeEventListener('mouseleave', this.handleCallbackMap.handle1.mouseLeave, false);
1102
						this.handle2.removeEventListener('mouseleave', this.handleCallbackMap.handle2.mouseLeave, false);
1103
					}
1104
				}
1105

1106
				this.handleCallbackMap = null;
1107
				this.ticksCallbackMap = null;
1108

1109
				if (this.showTooltip) {
1110
					this._removeTooltipListener("focus", this.showTooltip);
1111
				}
1112
				if (this.hideTooltip) {
1113
					this._removeTooltipListener("blur", this.hideTooltip);
1114
				}
1115

1116
				// Remove event listeners from sliderElem
1117
				if (this.showTooltip) {
1118
					this.sliderElem.removeEventListener("mouseenter", this.showTooltip, false);
1119
				}
1120
				if (this.hideTooltip) {
1121
					this.sliderElem.removeEventListener("mouseleave", this.hideTooltip, false);
1122
				}
1123

1124
				this.sliderElem.removeEventListener("mousedown", this.mousedown, false);
1125

1126
				if (this.touchCapable) {
1127
					// Remove touch event listeners from handles
1128
					if (this.showTooltip) {
1129
						this.handle1.removeEventListener("touchstart", this.showTooltip, false);
1130
						this.handle1.removeEventListener("touchmove", this.showTooltip, false);
1131
						this.handle2.removeEventListener("touchstart", this.showTooltip, false);
1132
						this.handle2.removeEventListener("touchmove", this.showTooltip, false);
1133
					}
1134
					if (this.hideTooltip) {
1135
						this.handle1.removeEventListener("touchend", this.hideTooltip, false);
1136
						this.handle2.removeEventListener("touchend", this.hideTooltip, false);
1137
					}
1138

1139
					// Remove event listeners from sliderElem
1140
					if (this.showTooltip) {
1141
						this.sliderElem.removeEventListener("touchstart", this.showTooltip, false);
1142
						this.sliderElem.removeEventListener("touchmove", this.showTooltip, false);
1143
					}
1144
					if (this.hideTooltip) {
1145
						this.sliderElem.removeEventListener("touchend", this.hideTooltip, false);
1146
					}
1147

1148
					this.sliderElem.removeEventListener("touchstart", this.touchstart, false);
1149
					this.sliderElem.removeEventListener("touchmove", this.touchmove, false);
1150
				}
1151

1152
				// Remove window event listener
1153
				window.removeEventListener("resize", this.resize, false);
1154
			},
1155
			_bindNonQueryEventHandler: function _bindNonQueryEventHandler(evt, callback) {
1156
				if (this.eventToCallbackMap[evt] === undefined) {
1157
					this.eventToCallbackMap[evt] = [];
1158
				}
1159
				this.eventToCallbackMap[evt].push(callback);
1160
			},
1161
			_unbindNonQueryEventHandler: function _unbindNonQueryEventHandler(evt, callback) {
1162
				var callbacks = this.eventToCallbackMap[evt];
1163
				if (callbacks !== undefined) {
1164
					for (var i = 0; i < callbacks.length; i++) {
1165
						if (callbacks[i] === callback) {
1166
							callbacks.splice(i, 1);
1167
							break;
1168
						}
1169
					}
1170
				}
1171
			},
1172
			_cleanUpEventCallbacksMap: function _cleanUpEventCallbacksMap() {
1173
				var eventNames = Object.keys(this.eventToCallbackMap);
1174
				for (var i = 0; i < eventNames.length; i++) {
1175
					var eventName = eventNames[i];
1176
					delete this.eventToCallbackMap[eventName];
1177
				}
1178
			},
1179
			_showTooltip: function _showTooltip() {
1180
				if (this.options.tooltip_split === false) {
1181
					this._addClass(this.tooltip, 'show');
1182
					this.tooltip_min.style.display = 'none';
1183
					this.tooltip_max.style.display = 'none';
1184
				} else {
1185
					this._addClass(this.tooltip_min, 'show');
1186
					this._addClass(this.tooltip_max, 'show');
1187
					this.tooltip.style.display = 'none';
1188
				}
1189
				this._state.over = true;
1190
			},
1191
			_hideTooltip: function _hideTooltip() {
1192
				if (this._state.inDrag === false && this._alwaysShowTooltip !== true) {
1193
					this._removeClass(this.tooltip, 'show');
1194
					this._removeClass(this.tooltip_min, 'show');
1195
					this._removeClass(this.tooltip_max, 'show');
1196
				}
1197
				this._state.over = false;
1198
			},
1199
			_setToolTipOnMouseOver: function _setToolTipOnMouseOver(tempState) {
1200
				var self = this;
1201
				var formattedTooltipVal = this.options.formatter(!tempState ? this._state.value[0] : tempState.value[0]);
1202
				var positionPercentages = !tempState ? getPositionPercentages(this._state, this.options.reversed) : getPositionPercentages(tempState, this.options.reversed);
1203
				this._setText(this.tooltipInner, formattedTooltipVal);
1204

1205
				this.tooltip.style[this.stylePos] = positionPercentages[0] + "%";
1206

1207
				function getPositionPercentages(state, reversed) {
1208
					if (reversed) {
1209
						return [100 - state.percentage[0], self.options.range ? 100 - state.percentage[1] : state.percentage[1]];
1210
					}
1211
					return [state.percentage[0], state.percentage[1]];
1212
				}
1213
			},
1214
			_copyState: function _copyState() {
1215
				return {
1216
					value: [this._state.value[0], this._state.value[1]],
1217
					enabled: this._state.enabled,
1218
					offset: this._state.offset,
1219
					size: this._state.size,
1220
					percentage: [this._state.percentage[0], this._state.percentage[1], this._state.percentage[2]],
1221
					inDrag: this._state.inDrag,
1222
					over: this._state.over,
1223
					// deleted or null'd keys
1224
					dragged: this._state.dragged,
1225
					keyCtrl: this._state.keyCtrl
1226
				};
1227
			},
1228
			_addTickListener: function _addTickListener() {
1229
				return {
1230
					addMouseEnter: function addMouseEnter(reference, element, index) {
1231
						var enter = function enter() {
1232
							var tempState = reference._copyState();
1233
							// Which handle is being hovered over?
1234
							var val = element === reference.handle1 ? tempState.value[0] : tempState.value[1];
1235
							var per = void 0;
1236

1237
							// Setup value and percentage for tick's 'mouseenter'
1238
							if (index !== undefined) {
1239
								val = reference.options.ticks[index];
1240
								per = reference.options.ticks_positions.length > 0 && reference.options.ticks_positions[index] || reference._toPercentage(reference.options.ticks[index]);
1241
							} else {
1242
								per = reference._toPercentage(val);
1243
							}
1244

1245
							tempState.value[0] = val;
1246
							tempState.percentage[0] = per;
1247
							reference._setToolTipOnMouseOver(tempState);
1248
							reference._showTooltip();
1249
						};
1250
						element.addEventListener("mouseenter", enter, false);
1251
						return enter;
1252
					},
1253
					addMouseLeave: function addMouseLeave(reference, element) {
1254
						var leave = function leave() {
1255
							reference._hideTooltip();
1256
						};
1257
						element.addEventListener("mouseleave", leave, false);
1258
						return leave;
1259
					}
1260
				};
1261
			},
1262
			_layout: function _layout() {
1263
				var positionPercentages;
1264
				var formattedValue;
1265

1266
				if (this.options.reversed) {
1267
					positionPercentages = [100 - this._state.percentage[0], this.options.range ? 100 - this._state.percentage[1] : this._state.percentage[1]];
1268
				} else {
1269
					positionPercentages = [this._state.percentage[0], this._state.percentage[1]];
1270
				}
1271

1272
				this.handle1.style[this.stylePos] = positionPercentages[0] + "%";
1273
				this.handle1.setAttribute('aria-valuenow', this._state.value[0]);
1274
				formattedValue = this.options.formatter(this._state.value[0]);
1275
				if (isNaN(formattedValue)) {
1276
					this.handle1.setAttribute('aria-valuetext', formattedValue);
1277
				} else {
1278
					this.handle1.removeAttribute('aria-valuetext');
1279
				}
1280

1281
				this.handle2.style[this.stylePos] = positionPercentages[1] + "%";
1282
				this.handle2.setAttribute('aria-valuenow', this._state.value[1]);
1283
				formattedValue = this.options.formatter(this._state.value[1]);
1284
				if (isNaN(formattedValue)) {
1285
					this.handle2.setAttribute('aria-valuetext', formattedValue);
1286
				} else {
1287
					this.handle2.removeAttribute('aria-valuetext');
1288
				}
1289

1290
				/* Position highlight range elements */
1291
				if (this.rangeHighlightElements.length > 0 && Array.isArray(this.options.rangeHighlights) && this.options.rangeHighlights.length > 0) {
1292
					for (var _i = 0; _i < this.options.rangeHighlights.length; _i++) {
1293
						var startPercent = this._toPercentage(this.options.rangeHighlights[_i].start);
1294
						var endPercent = this._toPercentage(this.options.rangeHighlights[_i].end);
1295

1296
						if (this.options.reversed) {
1297
							var sp = 100 - endPercent;
1298
							endPercent = 100 - startPercent;
1299
							startPercent = sp;
1300
						}
1301

1302
						var currentRange = this._createHighlightRange(startPercent, endPercent);
1303

1304
						if (currentRange) {
1305
							if (this.options.orientation === 'vertical') {
1306
								this.rangeHighlightElements[_i].style.top = currentRange.start + "%";
1307
								this.rangeHighlightElements[_i].style.height = currentRange.size + "%";
1308
							} else {
1309
								if (this.options.rtl) {
1310
									this.rangeHighlightElements[_i].style.right = currentRange.start + "%";
1311
								} else {
1312
									this.rangeHighlightElements[_i].style.left = currentRange.start + "%";
1313
								}
1314
								this.rangeHighlightElements[_i].style.width = currentRange.size + "%";
1315
							}
1316
						} else {
1317
							this.rangeHighlightElements[_i].style.display = "none";
1318
						}
1319
					}
1320
				}
1321

1322
				/* Position ticks and labels */
1323
				if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
1324

1325
					var styleSize = this.options.orientation === 'vertical' ? 'height' : 'width';
1326
					var styleMargin;
1327
					if (this.options.orientation === 'vertical') {
1328
						styleMargin = 'marginTop';
1329
					} else {
1330
						if (this.options.rtl) {
1331
							styleMargin = 'marginRight';
1332
						} else {
1333
							styleMargin = 'marginLeft';
1334
						}
1335
					}
1336
					var labelSize = this._state.size / (this.options.ticks.length - 1);
1337

1338
					if (this.tickLabelContainer) {
1339
						var extraMargin = 0;
1340
						if (this.options.ticks_positions.length === 0) {
1341
							if (this.options.orientation !== 'vertical') {
1342
								this.tickLabelContainer.style[styleMargin] = -labelSize / 2 + "px";
1343
							}
1344

1345
							extraMargin = this.tickLabelContainer.offsetHeight;
1346
						} else {
1347
							/* Chidren are position absolute, calculate height by finding the max offsetHeight of a child */
1348
							for (i = 0; i < this.tickLabelContainer.childNodes.length; i++) {
1349
								if (this.tickLabelContainer.childNodes[i].offsetHeight > extraMargin) {
1350
									extraMargin = this.tickLabelContainer.childNodes[i].offsetHeight;
1351
								}
1352
							}
1353
						}
1354
						if (this.options.orientation === 'horizontal') {
1355
							this.sliderElem.style.marginBottom = extraMargin + "px";
1356
						}
1357
					}
1358
					for (var i = 0; i < this.options.ticks.length; i++) {
1359

1360
						var percentage = this.options.ticks_positions[i] || this._toPercentage(this.options.ticks[i]);
1361

1362
						if (this.options.reversed) {
1363
							percentage = 100 - percentage;
1364
						}
1365

1366
						this.ticks[i].style[this.stylePos] = percentage + "%";
1367

1368
						/* Set class labels to denote whether ticks are in the selection */
1369
						this._removeClass(this.ticks[i], 'in-selection');
1370
						if (!this.options.range) {
1371
							if (this.options.selection === 'after' && percentage >= positionPercentages[0]) {
1372
								this._addClass(this.ticks[i], 'in-selection');
1373
							} else if (this.options.selection === 'before' && percentage <= positionPercentages[0]) {
1374
								this._addClass(this.ticks[i], 'in-selection');
1375
							}
1376
						} else if (percentage >= positionPercentages[0] && percentage <= positionPercentages[1]) {
1377
							this._addClass(this.ticks[i], 'in-selection');
1378
						}
1379

1380
						if (this.tickLabels[i]) {
1381
							this.tickLabels[i].style[styleSize] = labelSize + "px";
1382

1383
							if (this.options.orientation !== 'vertical' && this.options.ticks_positions[i] !== undefined) {
1384
								this.tickLabels[i].style.position = 'absolute';
1385
								this.tickLabels[i].style[this.stylePos] = percentage + "%";
1386
								this.tickLabels[i].style[styleMargin] = -labelSize / 2 + 'px';
1387
							} else if (this.options.orientation === 'vertical') {
1388
								if (this.options.rtl) {
1389
									this.tickLabels[i].style['marginRight'] = this.sliderElem.offsetWidth + "px";
1390
								} else {
1391
									this.tickLabels[i].style['marginLeft'] = this.sliderElem.offsetWidth + "px";
1392
								}
1393
								this.tickLabelContainer.style[styleMargin] = this.sliderElem.offsetWidth / 2 * -1 + 'px';
1394
							}
1395

1396
							/* Set class labels to indicate tick labels are in the selection or selected */
1397
							this._removeClass(this.tickLabels[i], 'label-in-selection label-is-selection');
1398
							if (!this.options.range) {
1399
								if (this.options.selection === 'after' && percentage >= positionPercentages[0]) {
1400
									this._addClass(this.tickLabels[i], 'label-in-selection');
1401
								} else if (this.options.selection === 'before' && percentage <= positionPercentages[0]) {
1402
									this._addClass(this.tickLabels[i], 'label-in-selection');
1403
								}
1404
								if (percentage === positionPercentages[0]) {
1405
									this._addClass(this.tickLabels[i], 'label-is-selection');
1406
								}
1407
							} else if (percentage >= positionPercentages[0] && percentage <= positionPercentages[1]) {
1408
								this._addClass(this.tickLabels[i], 'label-in-selection');
1409
								if (percentage === positionPercentages[0] || positionPercentages[1]) {
1410
									this._addClass(this.tickLabels[i], 'label-is-selection');
1411
								}
1412
							}
1413
						}
1414
					}
1415
				}
1416

1417
				var formattedTooltipVal;
1418

1419
				if (this.options.range) {
1420
					formattedTooltipVal = this.options.formatter(this._state.value);
1421
					this._setText(this.tooltipInner, formattedTooltipVal);
1422
					this.tooltip.style[this.stylePos] = (positionPercentages[1] + positionPercentages[0]) / 2 + "%";
1423

1424
					var innerTooltipMinText = this.options.formatter(this._state.value[0]);
1425
					this._setText(this.tooltipInner_min, innerTooltipMinText);
1426

1427
					var innerTooltipMaxText = this.options.formatter(this._state.value[1]);
1428
					this._setText(this.tooltipInner_max, innerTooltipMaxText);
1429

1430
					this.tooltip_min.style[this.stylePos] = positionPercentages[0] + "%";
1431

1432
					this.tooltip_max.style[this.stylePos] = positionPercentages[1] + "%";
1433
				} else {
1434
					formattedTooltipVal = this.options.formatter(this._state.value[0]);
1435
					this._setText(this.tooltipInner, formattedTooltipVal);
1436

1437
					this.tooltip.style[this.stylePos] = positionPercentages[0] + "%";
1438
				}
1439

1440
				if (this.options.orientation === 'vertical') {
1441
					this.trackLow.style.top = '0';
1442
					this.trackLow.style.height = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
1443

1444
					this.trackSelection.style.top = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
1445
					this.trackSelection.style.height = Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';
1446

1447
					this.trackHigh.style.bottom = '0';
1448
					this.trackHigh.style.height = 100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';
1449
				} else {
1450
					if (this.stylePos === 'right') {
1451
						this.trackLow.style.right = '0';
1452
					} else {
1453
						this.trackLow.style.left = '0';
1454
					}
1455
					this.trackLow.style.width = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
1456

1457
					if (this.stylePos === 'right') {
1458
						this.trackSelection.style.right = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
1459
					} else {
1460
						this.trackSelection.style.left = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
1461
					}
1462
					this.trackSelection.style.width = Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';
1463

1464
					if (this.stylePos === 'right') {
1465
						this.trackHigh.style.left = '0';
1466
					} else {
1467
						this.trackHigh.style.right = '0';
1468
					}
1469
					this.trackHigh.style.width = 100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';
1470

1471
					var offset_min = this.tooltip_min.getBoundingClientRect();
1472
					var offset_max = this.tooltip_max.getBoundingClientRect();
1473

1474
					if (this.options.tooltip_position === 'bottom') {
1475
						if (offset_min.right > offset_max.left) {
1476
							this._removeClass(this.tooltip_max, 'bs-tooltip-bottom');
1477
							this._addClass(this.tooltip_max, 'bs-tooltip-top');
1478
							this.tooltip_max.style.top = '';
1479
							this.tooltip_max.style.bottom = 22 + 'px';
1480
						} else {
1481
							this._removeClass(this.tooltip_max, 'bs-tooltip-top');
1482
							this._addClass(this.tooltip_max, 'bs-tooltip-bottom');
1483
							this.tooltip_max.style.top = this.tooltip_min.style.top;
1484
							this.tooltip_max.style.bottom = '';
1485
						}
1486
					} else {
1487
						if (offset_min.right > offset_max.left) {
1488
							this._removeClass(this.tooltip_max, 'bs-tooltip-top');
1489
							this._addClass(this.tooltip_max, 'bs-tooltip-bottom');
1490
							this.tooltip_max.style.top = 18 + 'px';
1491
						} else {
1492
							this._removeClass(this.tooltip_max, 'bs-tooltip-bottom');
1493
							this._addClass(this.tooltip_max, 'bs-tooltip-top');
1494
							this.tooltip_max.style.top = this.tooltip_min.style.top;
1495
						}
1496
					}
1497
				}
1498
			},
1499
			_createHighlightRange: function _createHighlightRange(start, end) {
1500
				if (this._isHighlightRange(start, end)) {
1501
					if (start > end) {
1502
						return { 'start': end, 'size': start - end };
1503
					}
1504
					return { 'start': start, 'size': end - start };
1505
				}
1506
				return null;
1507
			},
1508
			_isHighlightRange: function _isHighlightRange(start, end) {
1509
				if (0 <= start && start <= 100 && 0 <= end && end <= 100) {
1510
					return true;
1511
				} else {
1512
					return false;
1513
				}
1514
			},
1515
			_resize: function _resize(ev) {
1516
				/*jshint unused:false*/
1517
				this._state.offset = this._offset(this.sliderElem);
1518
				this._state.size = this.sliderElem[this.sizePos];
1519
				this._layout();
1520
			},
1521
			_removeProperty: function _removeProperty(element, prop) {
1522
				if (element.style.removeProperty) {
1523
					element.style.removeProperty(prop);
1524
				} else {
1525
					element.style.removeAttribute(prop);
1526
				}
1527
			},
1528
			_mousedown: function _mousedown(ev) {
1529
				if (!this._state.enabled) {
1530
					return false;
1531
				}
1532

1533
				if (ev.preventDefault) {
1534
					ev.preventDefault();
1535
				}
1536

1537
				this._state.offset = this._offset(this.sliderElem);
1538
				this._state.size = this.sliderElem[this.sizePos];
1539

1540
				var percentage = this._getPercentage(ev);
1541

1542
				if (this.options.range) {
1543
					var diff1 = Math.abs(this._state.percentage[0] - percentage);
1544
					var diff2 = Math.abs(this._state.percentage[1] - percentage);
1545
					this._state.dragged = diff1 < diff2 ? 0 : 1;
1546
					this._adjustPercentageForRangeSliders(percentage);
1547
				} else {
1548
					this._state.dragged = 0;
1549
				}
1550

1551
				this._state.percentage[this._state.dragged] = percentage;
1552

1553
				if (this.touchCapable) {
1554
					document.removeEventListener("touchmove", this.mousemove, false);
1555
					document.removeEventListener("touchend", this.mouseup, false);
1556
				}
1557

1558
				if (this.mousemove) {
1559
					document.removeEventListener("mousemove", this.mousemove, false);
1560
				}
1561
				if (this.mouseup) {
1562
					document.removeEventListener("mouseup", this.mouseup, false);
1563
				}
1564

1565
				this.mousemove = this._mousemove.bind(this);
1566
				this.mouseup = this._mouseup.bind(this);
1567

1568
				if (this.touchCapable) {
1569
					// Touch: Bind touch events:
1570
					document.addEventListener("touchmove", this.mousemove, false);
1571
					document.addEventListener("touchend", this.mouseup, false);
1572
				}
1573
				// Bind mouse events:
1574
				document.addEventListener("mousemove", this.mousemove, false);
1575
				document.addEventListener("mouseup", this.mouseup, false);
1576

1577
				this._state.inDrag = true;
1578
				var newValue = this._calculateValue();
1579

1580
				this._trigger('slideStart', newValue);
1581

1582
				this.setValue(newValue, false, true);
1583

1584
				ev.returnValue = false;
1585

1586
				if (this.options.focus) {
1587
					this._triggerFocusOnHandle(this._state.dragged);
1588
				}
1589

1590
				return true;
1591
			},
1592
			_touchstart: function _touchstart(ev) {
1593
				this._mousedown(ev);
1594
			},
1595
			_triggerFocusOnHandle: function _triggerFocusOnHandle(handleIdx) {
1596
				if (handleIdx === 0) {
1597
					this.handle1.focus();
1598
				}
1599
				if (handleIdx === 1) {
1600
					this.handle2.focus();
1601
				}
1602
			},
1603
			_keydown: function _keydown(handleIdx, ev) {
1604
				if (!this._state.enabled) {
1605
					return false;
1606
				}
1607

1608
				var dir;
1609
				switch (ev.keyCode) {
1610
					case 37: // left
1611
					case 40:
1612
						// down
1613
						dir = -1;
1614
						break;
1615
					case 39: // right
1616
					case 38:
1617
						// up
1618
						dir = 1;
1619
						break;
1620
				}
1621
				if (!dir) {
1622
					return;
1623
				}
1624

1625
				// use natural arrow keys instead of from min to max
1626
				if (this.options.natural_arrow_keys) {
1627
					var isHorizontal = this.options.orientation === 'horizontal';
1628
					var isVertical = this.options.orientation === 'vertical';
1629
					var isRTL = this.options.rtl;
1630
					var isReversed = this.options.reversed;
1631

1632
					if (isHorizontal) {
1633
						if (isRTL) {
1634
							if (!isReversed) {
1635
								dir = -dir;
1636
							}
1637
						} else {
1638
							if (isReversed) {
1639
								dir = -dir;
1640
							}
1641
						}
1642
					} else if (isVertical) {
1643
						if (!isReversed) {
1644
							dir = -dir;
1645
						}
1646
					}
1647
				}
1648

1649
				var val;
1650
				if (this.ticksAreValid && this.options.lock_to_ticks) {
1651
					var index = void 0;
1652
					// Find tick index that handle 1/2 is currently on
1653
					index = this.options.ticks.indexOf(this._state.value[handleIdx]);
1654
					if (index === -1) {
1655
						// Set default to first tick
1656
						index = 0;
1657
						window.console.warn('(lock_to_ticks) _keydown: index should not be -1');
1658
					}
1659
					index += dir;
1660
					index = Math.max(0, Math.min(this.options.ticks.length - 1, index));
1661
					val = this.options.ticks[index];
1662
				} else {
1663
					val = this._state.value[handleIdx] + dir * this.options.step;
1664
				}
1665
				var percentage = this._toPercentage(val);
1666
				this._state.keyCtrl = handleIdx;
1667
				if (this.options.range) {
1668
					this._adjustPercentageForRangeSliders(percentage);
1669
					var val1 = !this._state.keyCtrl ? val : this._state.value[0];
1670
					var val2 = this._state.keyCtrl ? val : this._state.value[1];
1671
					// Restrict values within limits
1672
					val = [Math.max(this.options.min, Math.min(this.options.max, val1)), Math.max(this.options.min, Math.min(this.options.max, val2))];
1673
				} else {
1674
					val = Math.max(this.options.min, Math.min(this.options.max, val));
1675
				}
1676

1677
				this._trigger('slideStart', val);
1678

1679
				this.setValue(val, true, true);
1680

1681
				this._trigger('slideStop', val);
1682

1683
				this._pauseEvent(ev);
1684
				delete this._state.keyCtrl;
1685

1686
				return false;
1687
			},
1688
			_pauseEvent: function _pauseEvent(ev) {
1689
				if (ev.stopPropagation) {
1690
					ev.stopPropagation();
1691
				}
1692
				if (ev.preventDefault) {
1693
					ev.preventDefault();
1694
				}
1695
				ev.cancelBubble = true;
1696
				ev.returnValue = false;
1697
			},
1698
			_mousemove: function _mousemove(ev) {
1699
				if (!this._state.enabled) {
1700
					return false;
1701
				}
1702

1703
				var percentage = this._getPercentage(ev);
1704
				this._adjustPercentageForRangeSliders(percentage);
1705
				this._state.percentage[this._state.dragged] = percentage;
1706

1707
				var val = this._calculateValue(true);
1708
				this.setValue(val, true, true);
1709

1710
				return false;
1711
			},
1712
			_touchmove: function _touchmove(ev) {
1713
				if (ev.changedTouches === undefined) {
1714
					return;
1715
				}
1716

1717
				// Prevent page from scrolling and only drag the slider
1718
				if (ev.preventDefault) {
1719
					ev.preventDefault();
1720
				}
1721
			},
1722
			_adjustPercentageForRangeSliders: function _adjustPercentageForRangeSliders(percentage) {
1723
				if (this.options.range) {
1724
					var precision = this._getNumDigitsAfterDecimalPlace(percentage);
1725
					precision = precision ? precision - 1 : 0;
1726
					var percentageWithAdjustedPrecision = this._applyToFixedAndParseFloat(percentage, precision);
1727
					if (this._state.dragged === 0 && this._applyToFixedAndParseFloat(this._state.percentage[1], precision) < percentageWithAdjustedPrecision) {
1728
						this._state.percentage[0] = this._state.percentage[1];
1729
						this._state.dragged = 1;
1730
					} else if (this._state.dragged === 1 && this._applyToFixedAndParseFloat(this._state.percentage[0], precision) > percentageWithAdjustedPrecision) {
1731
						this._state.percentage[1] = this._state.percentage[0];
1732
						this._state.dragged = 0;
1733
					} else if (this._state.keyCtrl === 0 && this._toPercentage(this._state.value[1]) < percentage) {
1734
						this._state.percentage[0] = this._state.percentage[1];
1735
						this._state.keyCtrl = 1;
1736
						this.handle2.focus();
1737
					} else if (this._state.keyCtrl === 1 && this._toPercentage(this._state.value[0]) > percentage) {
1738
						this._state.percentage[1] = this._state.percentage[0];
1739
						this._state.keyCtrl = 0;
1740
						this.handle1.focus();
1741
					}
1742
				}
1743
			},
1744
			_mouseup: function _mouseup(ev) {
1745
				if (!this._state.enabled) {
1746
					return false;
1747
				}
1748

1749
				var percentage = this._getPercentage(ev);
1750
				this._adjustPercentageForRangeSliders(percentage);
1751
				this._state.percentage[this._state.dragged] = percentage;
1752

1753
				if (this.touchCapable) {
1754
					// Touch: Unbind touch event handlers:
1755
					document.removeEventListener("touchmove", this.mousemove, false);
1756
					document.removeEventListener("touchend", this.mouseup, false);
1757
				}
1758
				// Unbind mouse event handlers:
1759
				document.removeEventListener("mousemove", this.mousemove, false);
1760
				document.removeEventListener("mouseup", this.mouseup, false);
1761

1762
				this._state.inDrag = false;
1763
				if (this._state.over === false) {
1764
					this._hideTooltip();
1765
				}
1766
				var val = this._calculateValue(true);
1767

1768
				this.setValue(val, false, true);
1769
				this._trigger('slideStop', val);
1770

1771
				// No longer need 'dragged' after mouse up
1772
				this._state.dragged = null;
1773

1774
				return false;
1775
			},
1776
			_setValues: function _setValues(index, val) {
1777
				var comp = 0 === index ? 0 : 100;
1778
				if (this._state.percentage[index] !== comp) {
1779
					val.data[index] = this._toValue(this._state.percentage[index]);
1780
					val.data[index] = this._applyPrecision(val.data[index]);
1781
				}
1782
			},
1783
			_calculateValue: function _calculateValue(snapToClosestTick) {
1784
				var val = {};
1785
				if (this.options.range) {
1786
					val.data = [this.options.min, this.options.max];
1787
					this._setValues(0, val);
1788
					this._setValues(1, val);
1789
					if (snapToClosestTick) {
1790
						val.data[0] = this._snapToClosestTick(val.data[0]);
1791
						val.data[1] = this._snapToClosestTick(val.data[1]);
1792
					}
1793
				} else {
1794
					val.data = this._toValue(this._state.percentage[0]);
1795
					val.data = parseFloat(val.data);
1796
					val.data = this._applyPrecision(val.data);
1797
					if (snapToClosestTick) {
1798
						val.data = this._snapToClosestTick(val.data);
1799
					}
1800
				}
1801

1802
				return val.data;
1803
			},
1804
			_snapToClosestTick: function _snapToClosestTick(val) {
1805
				var min = [val, Infinity];
1806
				for (var i = 0; i < this.options.ticks.length; i++) {
1807
					var diff = Math.abs(this.options.ticks[i] - val);
1808
					if (diff <= min[1]) {
1809
						min = [this.options.ticks[i], diff];
1810
					}
1811
				}
1812
				if (min[1] <= this.options.ticks_snap_bounds) {
1813
					return min[0];
1814
				}
1815
				return val;
1816
			},
1817

1818
			_applyPrecision: function _applyPrecision(val) {
1819
				var precision = this.options.precision || this._getNumDigitsAfterDecimalPlace(this.options.step);
1820
				return this._applyToFixedAndParseFloat(val, precision);
1821
			},
1822
			_getNumDigitsAfterDecimalPlace: function _getNumDigitsAfterDecimalPlace(num) {
1823
				var match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
1824
				if (!match) {
1825
					return 0;
1826
				}
1827
				return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));
1828
			},
1829
			_applyToFixedAndParseFloat: function _applyToFixedAndParseFloat(num, toFixedInput) {
1830
				var truncatedNum = num.toFixed(toFixedInput);
1831
				return parseFloat(truncatedNum);
1832
			},
1833
			/*
1834
   	Credits to Mike Samuel for the following method!
1835
   	Source: http://stackoverflow.com/questions/10454518/javascript-how-to-retrieve-the-number-of-decimals-of-a-string-number
1836
   */
1837
			_getPercentage: function _getPercentage(ev) {
1838
				if (this.touchCapable && (ev.type === 'touchstart' || ev.type === 'touchmove' || ev.type === 'touchend')) {
1839
					ev = ev.changedTouches[0];
1840
				}
1841

1842
				var eventPosition = ev[this.mousePos];
1843
				var sliderOffset = this._state.offset[this.stylePos];
1844
				var distanceToSlide = eventPosition - sliderOffset;
1845
				if (this.stylePos === 'right') {
1846
					distanceToSlide = -distanceToSlide;
1847
				}
1848
				// Calculate what percent of the length the slider handle has slid
1849
				var percentage = distanceToSlide / this._state.size * 100;
1850
				percentage = Math.round(percentage / this._state.percentage[2]) * this._state.percentage[2];
1851
				if (this.options.reversed) {
1852
					percentage = 100 - percentage;
1853
				}
1854

1855
				// Make sure the percent is within the bounds of the slider.
1856
				// 0% corresponds to the 'min' value of the slide
1857
				// 100% corresponds to the 'max' value of the slide
1858
				return Math.max(0, Math.min(100, percentage));
1859
			},
1860
			_validateInputValue: function _validateInputValue(val) {
1861
				if (!isNaN(+val)) {
1862
					return +val;
1863
				} else if (Array.isArray(val)) {
1864
					this._validateArray(val);
1865
					return val;
1866
				} else {
1867
					throw new Error(ErrorMsgs.formatInvalidInputErrorMsg(val));
1868
				}
1869
			},
1870
			_validateArray: function _validateArray(val) {
1871
				for (var i = 0; i < val.length; i++) {
1872
					var input = val[i];
1873
					if (typeof input !== 'number') {
1874
						throw new Error(ErrorMsgs.formatInvalidInputErrorMsg(input));
1875
					}
1876
				}
1877
			},
1878
			_setDataVal: function _setDataVal(val) {
1879
				this.element.setAttribute('data-value', val);
1880
				this.element.setAttribute('value', val);
1881
				this.element.value = val;
1882
			},
1883
			_trigger: function _trigger(evt, val) {
1884
				val = val || val === 0 ? val : undefined;
1885

1886
				var callbackFnArray = this.eventToCallbackMap[evt];
1887
				if (callbackFnArray && callbackFnArray.length) {
1888
					for (var i = 0; i < callbackFnArray.length; i++) {
1889
						var callbackFn = callbackFnArray[i];
1890
						callbackFn(val);
1891
					}
1892
				}
1893

1894
				/* If JQuery exists, trigger JQuery events */
1895
				if ($) {
1896
					this._triggerJQueryEvent(evt, val);
1897
				}
1898
			},
1899
			_triggerJQueryEvent: function _triggerJQueryEvent(evt, val) {
1900
				var eventData = {
1901
					type: evt,
1902
					value: val
1903
				};
1904
				this.$element.trigger(eventData);
1905
				this.$sliderElem.trigger(eventData);
1906
			},
1907
			_unbindJQueryEventHandlers: function _unbindJQueryEventHandlers() {
1908
				this.$element.off();
1909
				this.$sliderElem.off();
1910
			},
1911
			_setText: function _setText(element, text) {
1912
				if (typeof element.textContent !== "undefined") {
1913
					element.textContent = text;
1914
				} else if (typeof element.innerText !== "undefined") {
1915
					element.innerText = text;
1916
				}
1917
			},
1918
			_removeClass: function _removeClass(element, classString) {
1919
				var classes = classString.split(" ");
1920
				var newClasses = element.className;
1921

1922
				for (var i = 0; i < classes.length; i++) {
1923
					var classTag = classes[i];
1924
					var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)");
1925
					newClasses = newClasses.replace(regex, " ");
1926
				}
1927

1928
				element.className = newClasses.trim();
1929
			},
1930
			_addClass: function _addClass(element, classString) {
1931
				var classes = classString.split(" ");
1932
				var newClasses = element.className;
1933

1934
				for (var i = 0; i < classes.length; i++) {
1935
					var classTag = classes[i];
1936
					var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)");
1937
					var ifClassExists = regex.test(newClasses);
1938

1939
					if (!ifClassExists) {
1940
						newClasses += " " + classTag;
1941
					}
1942
				}
1943

1944
				element.className = newClasses.trim();
1945
			},
1946
			_offsetLeft: function _offsetLeft(obj) {
1947
				return obj.getBoundingClientRect().left;
1948
			},
1949
			_offsetRight: function _offsetRight(obj) {
1950
				return obj.getBoundingClientRect().right;
1951
			},
1952
			_offsetTop: function _offsetTop(obj) {
1953
				var offsetTop = obj.offsetTop;
1954
				while ((obj = obj.offsetParent) && !isNaN(obj.offsetTop)) {
1955
					offsetTop += obj.offsetTop;
1956
					if (obj.tagName !== 'BODY') {
1957
						offsetTop -= obj.scrollTop;
1958
					}
1959
				}
1960
				return offsetTop;
1961
			},
1962
			_offset: function _offset(obj) {
1963
				return {
1964
					left: this._offsetLeft(obj),
1965
					right: this._offsetRight(obj),
1966
					top: this._offsetTop(obj)
1967
				};
1968
			},
1969
			_css: function _css(elementRef, styleName, value) {
1970
				if ($) {
1971
					$.style(elementRef, styleName, value);
1972
				} else {
1973
					var style = styleName.replace(/^-ms-/, "ms-").replace(/-([\da-z])/gi, function (all, letter) {
1974
						return letter.toUpperCase();
1975
					});
1976
					elementRef.style[style] = value;
1977
				}
1978
			},
1979
			_toValue: function _toValue(percentage) {
1980
				return this.options.scale.toValue.apply(this, [percentage]);
1981
			},
1982
			_toPercentage: function _toPercentage(value) {
1983
				return this.options.scale.toPercentage.apply(this, [value]);
1984
			},
1985
			_setTooltipPosition: function _setTooltipPosition() {
1986
				var tooltips = [this.tooltip, this.tooltip_min, this.tooltip_max];
1987
				if (this.options.orientation === 'vertical') {
1988
					var tooltipPos;
1989
					if (this.options.tooltip_position) {
1990
						tooltipPos = this.options.tooltip_position;
1991
					} else {
1992
						if (this.options.rtl) {
1993
							tooltipPos = 'left';
1994
						} else {
1995
							tooltipPos = 'right';
1996
						}
1997
					}
1998
					var oppositeSide = tooltipPos === 'left' ? 'right' : 'left';
1999
					tooltips.forEach(function (tooltip) {
2000
						this._addClass(tooltip, 'bs-tooltip-' + tooltipPos);
2001
						tooltip.style[oppositeSide] = '100%';
2002
					}.bind(this));
2003
				} else if (this.options.tooltip_position === 'bottom') {
2004
					tooltips.forEach(function (tooltip) {
2005
						this._addClass(tooltip, 'bs-tooltip-bottom');
2006
						tooltip.style.top = 22 + 'px';
2007
					}.bind(this));
2008
				} else {
2009
					tooltips.forEach(function (tooltip) {
2010
						this._addClass(tooltip, 'bs-tooltip-top');
2011
						tooltip.style.top = -this.tooltip.outerHeight - 14 + 'px';
2012
					}.bind(this));
2013
				}
2014
			},
2015
			_getClosestTickIndex: function _getClosestTickIndex(val) {
2016
				var difference = Math.abs(val - this.options.ticks[0]);
2017
				var index = 0;
2018
				for (var i = 0; i < this.options.ticks.length; ++i) {
2019
					var d = Math.abs(val - this.options.ticks[i]);
2020
					if (d < difference) {
2021
						difference = d;
2022
						index = i;
2023
					}
2024
				}
2025
				return index;
2026
			},
2027
			/**
2028
    * Attempts to find the index in `ticks[]` the slider values are set at.
2029
    * The indexes can be -1 to indicate the slider value is not set at a value in `ticks[]`.
2030
    */
2031
			_setTickIndex: function _setTickIndex() {
2032
				if (this.ticksAreValid) {
2033
					this._state.tickIndex = [this.options.ticks.indexOf(this._state.value[0]), this.options.ticks.indexOf(this._state.value[1])];
2034
				}
2035
			}
2036
		};
2037

2038
		/*********************************
2039
  		Attach to global namespace
2040
  	*********************************/
2041
		if ($ && $.fn) {
2042
			if (!$.fn.slider) {
2043
				$.bridget(NAMESPACE_MAIN, Slider);
2044
				autoRegisterNamespace = NAMESPACE_MAIN;
2045
			} else {
2046
				if (windowIsDefined) {
2047
					window.console.warn("bootstrap-slider.js - WARNING: $.fn.slider namespace is already bound. Use the $.fn.bootstrapSlider namespace instead.");
2048
				}
2049
				autoRegisterNamespace = NAMESPACE_ALTERNATE;
2050
			}
2051
			$.bridget(NAMESPACE_ALTERNATE, Slider);
2052

2053
			// Auto-Register data-provide="slider" Elements
2054
			$(function () {
2055
				$("input[data-provide=slider]")[autoRegisterNamespace]();
2056
			});
2057
		}
2058
	})($);
2059

2060
	return Slider;
2061
});
2062

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.